Print this page
- adds support for ForgeRock OpenDJ Directory Server (DS)
- does some jobs a little bit more intelligent (fixes all missing parts in a DS)
- improved readability/output (demystify, show what it does)
- optional recording of all commands used to initialize/fix the DS (option -k)
- creates backend and VLV indexes for OpenDJ on the fly (no need to exec a list
  of DS specific commands after running the script)
- almost complete rewrite in ksh93 to reduce maintenance burden, support
  much easier debugging/tracing (just in case), integrated documentation
  and much much less forking of/dependencies on external tools

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/ldap/ns_ldap/idsconfig.sh
          +++ new/usr/src/cmd/ldap/ns_ldap/idsconfig.sh
   1      -#!/bin/sh
        1 +#!/bin/ksh93
   2    2  #
        3 +# $Id: idsconfig.sh,v 66c6ff17d001 2013-09-24 00:35:53Z jel+illumos $
        4 +#
   3    5  # CDDL HEADER START
   4    6  #
   5    7  # The contents of this file are subject to the terms of the
   6    8  # Common Development and Distribution License (the "License").
   7    9  # You may not use this file except in compliance with the License.
   8   10  #
   9   11  # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10   12  # or http://www.opensolaris.org/os/licensing.
  11   13  # See the License for the specific language governing permissions
  12   14  # and limitations under the License.
  13   15  #
  14   16  # When distributing Covered Code, include this CDDL HEADER in each
  15   17  # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16   18  # If applicable, add the following below this CDDL HEADER, with the
  17   19  # fields enclosed by brackets "[]" replaced with your own identifying
  18   20  # information: Portions Copyright [yyyy] [name of copyright owner]
  19   21  #
  20   22  # CDDL HEADER END
  21   23  #
  22      -#
  23      -# idsconfig -- script to setup iDS 5.x/6.x/7.x for Native LDAP II.
  24      -#
  25   24  # Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
  26      -#
       25 +# Portions Copyright 2013  Jens Elkner.
  27   26  
  28      -#
  29      -# display_msg(): Displays message corresponding to the tag passed in.
  30      -#
  31      -display_msg()
  32      -{
  33      -    case "$1" in
  34      -    usage) cat <<EOF
  35      - $PROG: [ -v ] [ -i input file ] [ -o output file ]
  36      -   i <input file>     Get setup info from input file.
  37      -   o <output file>    Generate a server configuration output file.
  38      -   v                  Verbose mode
  39      -EOF
  40      -    ;;
  41      -    backup_server) cat <<EOF
  42      -It is strongly recommended that you BACKUP the directory server
  43      -before running $PROG.
  44   27  
  45      -Hit Ctrl-C at any time before the final confirmation to exit.
       28 +#############################################################################
       29 +# Main global vars
       30 +#############################################################################
       31 +LIC='[-?$Id: idsconfig.sh,v 66c6ff17d001 2013-09-24 00:35:53Z jel+illumos $ ]
       32 +[-copyright?Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.]
       33 +[-copyright?Portions Copyright (c) 2013  Jens Elkner.]
       34 +[-license?CDDL 1.0]'
  46   35  
  47      -EOF
  48      -    ;;
  49      -    setup_complete) cat <<EOF
       36 +SDIR=${.sh.file%/*}
       37 +typeset -r FPROG=${.sh.file}
       38 +typeset -r PROG=${FPROG##*/}
  50   39  
  51      -$PROG: Setup of iDS server ${IDS_SERVER} is complete.
       40 +typeset -T LogObj_t=(
       41 +        typeset -Sh 'Color for info messages' GREEN='38;5;232;48;5;118' #'1;30;102';
       42 +        typeset -Sh 'Color for warning messages' BLUE='38;5;21;48;5;118' #'1;34;102';
       43 +        typeset -Sh 'Color for fatal messages' RED='38;5;9;48;5;118' #'1;31;102';
       44 +        typeset -Sih 'Flag, whether to use colored labels' COLORED=1
       45 +        typeset -Sih  'Flag, whether to print verbose infos' VERBOSE=0
  52   46  
  53      -EOF
  54      -    ;;
  55      -    display_vlv_list) cat <<EOF
       47 +        function log {
       48 +                (( _.COLORED )) && print -u2 "\E[1;$2m${ date +%T; } $1:\E[0m $3" || \
       49 +                        print -u2 "${ date +%T; } ${1}: $3"
       50 +        }
       51 +        typeset -Sfh ' log a message to stderr' log
       52 +        function verbose {
       53 +                (( _.VERBOSE )) && _.log "VERB" ${_.GREEN} "      $*"
       54 +        }
       55 +        typeset -Sfh ' log a info message to stderr if verbose messages are enabled' info
  56   56  
  57      -Note: idsconfig has created entries for VLV indexes. 
       57 +        function info {
       58 +                _.log "INFO" ${_.GREEN} "$*"
       59 +        }
       60 +        typeset -Sfh ' log a info message to stderr' info
       61 +        function warn {
       62 +                _.log "WARN" ${_.BLUE} "$*"
       63 +        }
       64 +        typeset -Sfh ' log a warning message to stderr' warn
       65 +        function fatal {
       66 +                _.log "FATAL" ${_.RED} "$*"
       67 +        }
       68 +        typeset -Sfh ' log a fatal error message to stderr' fatal
       69 +        function printMarker {
       70 +                typeset COLOR="$1" L='----------------------------------------------------------------------------'
       71 +                (( _.COLORED )) && print "\E[1;${COLOR:-${_.GREEN}}m${L}\E[0m" || \
       72 +                        print "${L}"
       73 +        }
       74 +        typeset -Sfh ' print a marker line to stdout' printMarker
       75 +)
       76 +LogObj_t Log
  58   77  
  59      -      For DS5.x, use the directoryserver(1m) script on ${IDS_SERVER}
  60      -      to stop the server.  Then, using directoryserver, follow the
  61      -      directoryserver examples below to create the actual VLV indexes.
       78 +typeset -T ManObj_t=(
       79 +    typeset -Ah 'Variable descriptions. Key: variable name' VAR
       80 +    typeset -Ah 'Function usages. Key: function name' FUNC
       81 +    function addVar {
       82 +                [[ -n ${_.VAR[$1]} ]] && Log.warn "Overwriting previous description for $1"
       83 +        _.VAR[$1]="[+$1?$2]"
       84 +    }
       85 +    typeset -fh 'Add a description (arg2) for the given variable name (arg1)' addVar
       86 +    function addFunc {
       87 +        typeset fname=$1
       88 +        typeset X="$2"
       89 +                [[ -n ${_.FUNC[$fname]} ]] && Log.warn "Overwriting previous usage info for $1()"
       90 +        [[ -z $X ]] && X="$LIC"
       91 +        shift 2
       92 +        while [[ -n $1 ]]; do
       93 +            X+="$1"
       94 +            shift
       95 +        done
       96 +        _.FUNC[$fname]+="$X"
       97 +    }
       98 +    typeset -fh $'Add usage info (arg3 ...) for the given function name (arg1). If implementation details (arg2) is empty, the value of \a$LIC\a gets used instead' addFunc
       99 +    function varUsage {
      100 +        typeset X=""
      101 +                [[ "$1" == '@' || "$1" == '*' ]] && set -- ${!_.VAR[@]}
      102 +        while [[ -n $1 ]]; do
      103 +            X+="${_.VAR[$1]}"
      104 +            shift
      105 +        done
      106 +        print "$X"
      107 +    }
      108 +    typeset -fh $'Get the variable usage info for the named variables (arg2 ...) if available as a concatenated string. See \baddVar()\b' varUsage
      109 +        function funcUsage {
      110 +                printf "${_.FUNC[$1]}"
      111 +        }
      112 +        typeset -fh 'Get the function usage info for the named function (arg1)' funcUsage
  62  113  
  63      -      For DS6.x or later, use dsadm command delivered with DS on ${IDS_SERVER}
  64      -      to stop the server.  Then, using dsadm, follow the
  65      -      dsadm examples below to create the actual VLV indexes.
      114 +        function listVars {
      115 +                typeset ALL="${ print ${!_.VAR[*]} | tr ' ' '\n' | sort -u; }" VNAME
      116 +                for VNAME in $ALL; do
      117 +                        [[ $VNAME == OLDENV || $VNAME == LASTENV ]] && continue
      118 +                        typeset -n X=$VNAME
      119 +                        print "$VNAME=$X"
      120 +                done
      121 +                unset -n X
      122 +        }
      123 +        typeset -fh 'List all registered environment variables and its current value, except for OLDENV and LASTENV.' listVars
      124 +)
      125 +ManObj_t Man
  66  126  
  67      -EOF
  68      -    ;;
  69      -    cred_level_menu) cat <<EOF
  70      -The following are the supported credential levels:
  71      -  1  anonymous
  72      -  2  proxy
  73      -  3  proxy anonymous
  74      -  4  self
  75      -EOF
  76      -    ;;
  77      -    auth_method_menu) cat <<EOF
  78      -The following are the supported Authentication Methods:
  79      -  1  none
  80      -  2  simple
  81      -  3  sasl/DIGEST-MD5
  82      -  4  tls:simple
  83      -  5  tls:sasl/DIGEST-MD5
  84      -  6  sasl/GSSAPI
  85      -EOF
  86      -    ;;
  87      -    srvauth_method_menu) cat <<EOF
  88      -The following are the supported Authentication Methods:
  89      -  1  simple
  90      -  2  sasl/DIGEST-MD5
  91      -  3  tls:simple
  92      -  4  tls:sasl/DIGEST-MD5
  93      -  5  sasl/GSSAPI
  94      -EOF
  95      -    ;;
  96      -    prompt_ssd_menu) cat <<EOF
  97      -  A  Add a Service Search Descriptor
  98      -  D  Delete a SSD
  99      -  M  Modify a SSD
 100      -  P  Display all SSD's
 101      -  H  Help
 102      -  X  Clear all SSD's
      127 +Man.addFunc showUsage '' '[+NAME?showUsage - show usage info.]
      128 +[+DESCRIPTION?Shows usage info for the given \afname\a if available.]
      129 +\n\n\afname\a
      130 +'
      131 +function showUsage {
      132 +        typeset WHAT="$2"
      133 +        if (( Log.VERBOSE )) && [[ ${WHAT} == 'MAIN' ]]; then
      134 +                typeset PRE=${Man.FUNC[$WHAT]%%\[+NOTES*}
      135 +                typeset POST=${.sh.match}
      136 +                typeset E='[+ENVIRONMENT VARIABLES]{'"${ Man.varUsage '*' ; }"'}'
      137 +                getopts -a "${PROG}" "${ print ${PRE}${E}${POST} ; }" OPT --man
      138 +        else
      139 +                getopts -a "${PROG}" "${ print ${Man.FUNC[$WHAT]}; }" OPT --man
      140 +        fi
      141 +}
 103  142  
 104      -  Q  Exit menu
 105      -EOF
 106      -    ;;
 107      -    summary_menu)
      143 +Man.addVar PROG 'String. The basename of this script.'
 108  144  
 109      -        SUFFIX_INFO=
 110      -        DB_INFO=
      145 +Man.addVar INT 'Associative array of Integers. Config relevant int values and flags.' 
      146 +typeset -A -i INT=( )
      147 +Man.addVar STR 'Associative array of Strings. Config relevant string values.'
      148 +typeset -A STR=( )
 111  149  
 112      -        [ -n "${NEED_CREATE_SUFFIX}" ] &&
 113      -        {
 114      -                SUFFIX_INFO=`cat <<EOF
      150 +Man.addVar TMPF 'Associative array of Integers. Int values with a more or less a global character in this script.' 
      151 +typeset -A -i TMPF=( )
      152 +Man.addVar TMP 'Associative array of Strings. String values whith a more or less a global character in this script.' 
      153 +typeset -A TMP=( )
 115  154  
 116      -         Suffix to create          : $LDAP_SUFFIX
 117      -EOF
 118      -`
 119      -                [ -n "${NEED_CREATE_BACKEND}" ] &&
 120      -                        DB_INFO=`cat <<EOF
      155 +Man.addVar CON_ARGS 'String. Contains connection related options for ldap commands.'
      156 +typeset CON_ARGS=''
 121  157  
 122      -         Database to create        : $IDS_DATABASE
 123      -EOF
 124      -`
 125      -        }
      158 +Man.addVar AUTH_ARGS 'Indexed array of Strings. Contains authentification related options for ldap commands.'
      159 +typeset -a AUTH_ARGS=( )
 126  160  
 127      -        cat <<EOF
 128      -              Summary of Configuration
      161 +Man.addVar SSD 'Indexed array of Strings. Contains the Service Search Decsriptors to use.'
      162 +typeset -a SSD=( )
 129  163  
 130      -  1  Domain to serve               : $LDAP_DOMAIN
 131      -  2  Base DN to setup              : $LDAP_BASEDN$SUFFIX_INFO$DB_INFO
 132      -  3  Profile name to create        : $LDAP_PROFILE_NAME
 133      -  4  Default Server List           : $LDAP_SERVER_LIST
 134      -  5  Preferred Server List         : $LDAP_PREF_SRVLIST
 135      -  6  Default Search Scope          : $LDAP_SEARCH_SCOPE
 136      -  7  Credential Level              : $LDAP_CRED_LEVEL
 137      -  8  Authentication Method         : $LDAP_AUTHMETHOD
 138      -  9  Enable Follow Referrals       : $LDAP_FOLLOWREF
 139      - 10  iDS Time Limit                : $IDS_TIMELIMIT
 140      - 11  iDS Size Limit                : $IDS_SIZELIMIT
 141      - 12  Enable crypt password storage : $NEED_CRYPT
 142      - 13  Service Auth Method pam_ldap  : $LDAP_SRV_AUTHMETHOD_PAM
 143      - 14  Service Auth Method keyserv   : $LDAP_SRV_AUTHMETHOD_KEY
 144      - 15  Service Auth Method passwd-cmd: $LDAP_SRV_AUTHMETHOD_CMD
 145      - 16  Search Time Limit             : $LDAP_SEARCH_TIME_LIMIT
 146      - 17  Profile Time to Live          : $LDAP_PROFILE_TTL
 147      - 18  Bind Limit                    : $LDAP_BIND_LIMIT
 148      - 19  Enable shadow update          : $LDAP_ENABLE_SHADOW_UPDATE
 149      - 20  Service Search Descriptors Menu
      164 +# NOTE: The ACI names are retained to be compatible to previous releases. If one
      165 +#       installs a completely new LDAP infrastructure changing the names should
      166 +#       not be a problem as long as they do not collide with existing aci names!
 150  167  
 151      -EOF
 152      -    ;;
 153      -    sfx_not_suitable) cat <<EOF
      168 +Man.addVar SFX_ANYONE_ACI_NAME 'String constant. The name of the suffix ACI rule, which allows anyone to read, search, compare.'
      169 +typeset -r SFX_ANYONE_ACI_NAME='Anonymous access'
 154  170  
 155      -Sorry, suffix ${LDAP_SUFFIX} is not suitable for Base DN ${LDAP_BASEDN}
      171 +Man.addVar SFX_SELF_ACI_NAME 'String constant. The name of the suffix ACI rule, which allows a principal to modify its own attributes except those related to password state information and policy.'
      172 +typeset -r SFX_SELF_ACI_NAME='Limited self entry modification'
 156  173  
 157      -EOF
 158      -    ;;
 159      -    obj_not_found) cat <<EOF
      174 +Man.addVar SFX_ADMIN_ACI_NAME 'String constant. The name of the suffix ACI rule, which allows the directory configuration administrator all operations on any entry.'
      175 +typeset -r SFX_ADMINGRP_ACI_NAME='Configuration Administrator access'
 160  176  
 161      -Sorry, ${PROG} can't find an objectclass for "$_ATT" attribute
      177 +Man.addVar SFX_ADMINGRP_ACI_NAME 'String constant. The name of the suffix ACI rule, which allows the directory configuration administrator group all operations on any entry.'
      178 +typeset -r SFX_ADMIN_ACI_NAME='Configuration Administrator Group access'
 162  179  
 163      -EOF
 164      -    ;;
 165      -    sfx_config_incons) cat <<EOF
      180 +Man.addVar PROXY_ACI_NAME 'String constant. The name of the ACI rule, which allows proxies to read passwords.'
      181 +typeset -r PROXY_ACI_NAME='LDAP Naming Services proxy_password_read'
 166  182  
 167      -Sorry, there is no suffix mapping for ${LDAP_SUFFIX},
 168      -while ldbm database exists, server configuration needs to be fixed manually,
 169      -look at cn=mapping tree,cn=config and cn=ldbm database,cn=plugins,cn=config
      183 +Man.addVar HOST_ACI_NAME 'String constant. The name of the ACI rule, which allows host principals to write passwords.'
      184 +typeset  -r HOST_ACI_NAME='LDAP Naming Services host_shadow_write'
      185 +Man.addVar NON_HOST_ACI_NAME 'String constant. The name of the ACI rule, which denies non-host principals access to shadow data.'
      186 +typeset -r NON_HOST_ACI_NAME='LDAP Naming Services deny_non_host_shadow_access'
 170  187  
 171      -EOF
 172      -    ;;
 173      -    ldbm_db_exist) cat <<EOF
      188 +Man.addVar ADMIN_ACI_NAME 'String constant. The name of the ACI rule, which allows Admin principals access to shadow, rbac and mount data.'
      189 +typeset -r ADMIN_ACI_NAME='LDAP Naming Services admin_shadow_write'
      190 +Man.addVar NON_ADMIN_ACI_NAME 'String constant. The name of the ACI rule, which denies non-Admin principals access to shadow data.'
      191 +typeset -r NON_ADMIN_ACI_NAME='LDAP Naming Services deny_non_admin_shadow_access'
      192 +Man.addVar USER_ACI_NAME 'String constant. The name of the ACI rule, which prevents a user from changing administrative fields like uidNumber, homeDirectory, shadowExpire, etc..'
      193 +typeset -r USER_ACI_NAME='LDAP Naming Services deny_write_access'
 174  194  
 175      -Database "${IDS_DATABASE}" already exists,
 176      -however "${IDS_DATABASE_AVAIL}" name is available
      195 +Man.addVar VLV_ACI_NAME 'String constant. The name of the global ACI rule, which allows any user to use VLVs for read, search and compare.'
      196 +typeset -r VLV_ACI_NAME='VLV Request Control'
 177  197  
 178      -EOF
 179      -    ;;
 180      -    unable_find_db_name) cat <<EOF
 181      -    
 182      -Unable to find any available database name close to "${IDS_DATABASE}"
      198 +Man.addVar SELF_GSS_ACI_NAME 'String constant. The name of the ou=people ACI rule, which allows a via SASL/GSSAPI authenticated user read and search on passwords.'
      199 +typeset -r SELF_GSS_ACI_NAME='self-read-pwd'
 183  200  
 184      -EOF
 185      -    ;;
 186      -    create_ldbm_db_error) cat <<EOF
      201 +Man.addVar HOST_GSS_ACI_NAME 'String constant. The name of the ou=people ACI rule, which allows a via SASL/GSSAPI authenticated hosts read and search on passwords.'
      202 +typeset -r HOST_GSS_ACI_NAME='host-read-pwd'
 187  203  
 188      -ERROR: unable to create suffix ${LDAP_SUFFIX}
 189      -       due to server error that occurred during creation of ldbm database
      204 +Man.addVar AUTH_METHODS 'Indexed array of Strings. A list of currently supported authentication methods.'
      205 +typeset -a -r AUTH_METHODS=(
      206 +        'none'                  'simple'                                'sasl/DIGEST-MD5'
      207 +        'tls:simple'    'tls:sasl/DIGEST-MD5'   'sasl/GSSAPI'
      208 +) # order is important
 190  209  
 191      -EOF
 192      -    ;;
 193      -    create_suffix_entry_error) cat <<EOF
      210 +Man.addVar CRED_LEVELS 'Indexed array of Strings. A list of currently supported client credential levels.'
      211 +typeset -a -r CRED_LEVELS=( 'anonymous' 'proxy' 'proxy anonymous' 'self' )
 194  212  
 195      -ERROR: unable to create entry ${LDAP_SUFFIX} of ${LDAP_SUFFIX_OBJ} class
      213 +Man.addVar OID2ADEF 'Associative array of Strings. Key: OID, Value: attribute definition. Used to cache attribute definitions of schemas currently installed on the DS. Gets lazy initialized, i.e. populated when needed.' 
      214 +typeset -A OID2ADEF=( )
      215 +Man.addVar ANAME2OID 'Associative array of Strings. Key: attribute name (lowercase), Value: OID. Used to cache name to OID mappings. Gets initialized, when \bOID2ADEF\b gets populated.'
      216 +typeset -A ANAME2OID=( )
 196  217  
 197      -EOF
 198      -    ;;
 199      -    ldap_suffix_list) cat <<EOF
      218 +Man.addVar OID2ODEF 'Associative array of Strings. Key: OID, Value: objectclass definition. Used to cache objectclass definitions of schemas currently installed on the DS. Gets lazy initialized, i.e. populated when needed.' 
      219 +typeset -A OID2ODEF=( )
 200  220  
 201      -No valid suffixes (naming contexts) were found for LDAP base DN:
 202      -${LDAP_BASEDN}
      221 +Man.addFunc checkBinary '' '[+NAME?checkBinary - lookup a command.]
      222 +[+DESCRIPTION?Check the standard path, whether it contains \acmd\a and if not, use \aPATH\a to lookup the command. If found the full path of the command gets printed to stdout, otherwise an error message to stderr.]
      223 +[+RETURN VALUES]{
      224 +        [+0?\acmd\a found.]
      225 +        [+1?\acmd\a not found.]
      226 +}
      227 +[+SEE ALSO?\bwhence\b(1).]
      228 +\n\n\acmd\a
      229 +'
      230 +function checkBinary {
      231 +        typeset CMD=$1 X=''
      232 +        for DIR in /usr/bin /usr/sbin ; do
      233 +                [[ -x ${DIR}/${CMD} ]] && print ${DIR}/${CMD} && return 0
      234 +        done
      235 +        X=${ whence -fp ${CMD} ; }
      236 +        [[ -n $X ]] && print "${X}" && return 0
      237 +        X="${.sh.file%/*}/${CMD}"
      238 +        [[ -x ${X} ]] && print "$X" && return 0
      239 +        print -u2 "Missing command '${CMD}'."
      240 +        return 1
      241 +}
 203  242  
 204      -Available suffixes are:
 205      -${LDAP_SUFFIX_LIST}
      243 +Man.addFunc init '' '[+NAME?init - initializes variables and options.]
      244 +[+DESCRIPTION?Does some basic binary-avail checks and initializes certain values of \bSTR[]]\b, \bINT[]]\b and \bTMP[]]\b.]
      245 +'
      246 +function init {
      247 +        typeset X='' KEY VAL TAIL
      248 +        integer ERR=0
 206  249  
 207      -EOF
 208      -    ;;
 209      -    sorry) cat <<EOF
      250 +        # General commands
      251 +        HOST=${ hostname ; }
      252 +        PING=${ checkBinary ping || (( ERR++ )) ; }
      253 +        STTY=${ checkBinary stty || (( ERR++ )) ; }
      254 +        GETENT=${ checkBinary getent || (( ERR++ )) ; }
 210  255  
 211      -HELP - No help is available for this topic.
      256 +        # LDAP COMMANDS
      257 +        LDAPSEARCH=${ checkBinary ldapsearch || (( ERR++ )) ; }
      258 +        LDAPMODIFY=${ checkBinary ldapmodify || (( ERR++ )) ; }
      259 +        LDAPDELETE=${ checkBinary ldapdelete || (( ERR++ )) ; }
      260 +        LDAPCLIENT=${ checkBinary ldapclient || (( ERR++ )) ; }
 212  261  
 213      -EOF
 214      -    ;;
 215      -    create_suffix_help) cat <<EOF
      262 +        if (( ERR )); then
      263 +                Log.fatal 'Please adjust your PATH and try again'
      264 +                return 66
      265 +        fi
      266 +        LDAPSEARCH+=' -r'
 216  267  
 217      -HELP - Our Base DN is ${LDAP_BASEDN}
 218      -       and we need to create a Directory Suffix,
 219      -       which can be equal to Base DN itself or be any of Base DN parents.
 220      -       All intermediate entries up to suffix will be created on demand.
      268 +        # If DNS domain (resolv.conf) exists use that, otherwise use domainname.
      269 +        if [[ -f /etc/resolv.conf ]]; then
      270 +                while read KEY VAL TAIL ; do
      271 +                        if [[ ${KEY} == 'domain' || ${KEY} == 'search' ]]; then
      272 +                                X=${VAL}
      273 +                                break;
      274 +                        fi
      275 +                done < /etc/resolv.conf
      276 +        fi
 221  277  
 222      -EOF
 223      -    ;;
 224      -    enter_ldbm_db_help) cat <<EOF
      278 +        # If for any reason the DOMAIN did not get set (error'd resolv.conf) set
      279 +        # X to the domainname or getent command's output.
      280 +        [[ -z $X ]] && X=${ domainname ; }
      281 +        if [[ -z $X ]]; then
      282 +                typeset -a AX=( ${ ${GETENT} hosts ${HOST} 2>/dev/null ; } )
      283 +                integer I
      284 +                for (( I=${#AX[@]}-1; I > 0; I++ )); do
      285 +                        X=${AX[$I]#*.}
      286 +                        [[ -n $X ]] && break
      287 +                done
      288 +        fi
 225  289  
 226      -HELP - ldbm database is an internal database for storage of our suffix data.
 227      -       Database name must be alphanumeric due to Directory Server restriction.
      290 +        # Actually one needs to init non-null/zero values, only. However, we want
      291 +        # to have the keys registered ...
 228  292  
 229      -EOF
 230      -    ;;
 231      -    backup_help) cat <<EOF
      293 +        # idsconfig specific variables.
      294 +        INT[LDAP_ENABLE_SHADOW_UPDATE]=0
      295 +        INT[NEED_PROXY]=0                       # 0 = No Proxy,    1 = Create Proxy.
      296 +        INT[NEED_ADMIN]=0                       # 0 = No Admin,    1 = Create Admin.
      297 +        INT[NEED_HOSTACL]=0                     # 0 = No Host ACL, 1 = Create Host ACL.
      298 +        INT[EXISTING_PROFILE]=0
      299 +        (( INT[TASK_TIMEOUT] < 10 )) && INT[TASK_TIMEOUT]=60
      300 +        STR[LDAP_PROXYAGENT]=''
      301 +        STR[LDAP_PROXYAGENT_CRED]=''
      302 +        STR[LDAP_ADMINDN]=''
      303 +        STR[LDAP_ADMIN_CRED]=''         # enableShadowUpdate flag and Admin credential
      304 +        STR[DS_DB]=''                           # storage backend name
      305 +        STR[LDAP_SUFFIX]=''                     # suffix within the backend
      306 +        STR[LDAP_DOMAIN]=${X%%.}        # domainname on Server (default value)
      307 +        
      308 +        # DS specific information
      309 +        STR[DS_HOST]=''
      310 +        INT[DS_PORT]=389
      311 +        INT[NEED_TIME]=0
      312 +        INT[NEED_SIZE]=0
      313 +        INT[DS_TIMELIMIT]=0
      314 +        INT[DS_SIZELIMIT]=0
 232  315  
 233      -HELP - Since idsconfig modifies the directory server configuration,
 234      -       it is strongly recommended that you backup the server prior
 235      -       to running this utility.  This is especially true if the server
 236      -       being configured is a production server.
      316 +        # LDAP PROFILE related defaults
      317 +        STR[LDAP_ROOTDN]='cn=Directory Manager' # Provide common default.
      318 +        STR[LDAP_ROOTPWD]=''                                    # NULL passwd (is invalid)
      319 +        STR[LDAP_PROFILE_NAME]='default'
      320 +        STR[LDAP_BASEDN]=''
      321 +        STR[LDAP_SERVER_LIST]=''
      322 +        STR[LDAP_AUTHMETHOD]=''
      323 +        INT[LDAP_FOLLOWREF]=0
      324 +        INT[NEED_CRYPT]=0
      325 +        INT[NEED_SRVAUTH_PAM]=0
      326 +        INT[NEED_SRVAUTH_KEY]=0
      327 +        INT[NEED_SRVAUTH_CMD]=0
      328 +        (( ! INT[NEED_CRYPT_IMPORT] )) && INT[NEED_CRYPT_IMPORT]=0
      329 +        STR[LDAP_SEARCH_SCOPE]='one'
      330 +        STR[LDAP_SRV_AUTHMETHOD_PAM]=''
      331 +        STR[LDAP_SRV_AUTHMETHOD_KEY]=''
      332 +        STR[LDAP_SRV_AUTHMETHOD_CMD]=''
      333 +        INT[LDAP_SEARCH_TIME_LIMIT]=30
      334 +        STR[LDAP_PREF_SRVLIST]=''
      335 +        INT[LDAP_PROFILE_TTL]=43200
      336 +        STR[LDAP_CRED_LEVEL]='proxy'
      337 +        INT[LDAP_BIND_LIMIT]=10
 237  338  
 238      -EOF
 239      -    ;;
 240      -    port_help) cat <<EOF
      339 +        # Service Search Descriptors (just make sure it is empty)
      340 +        SSD=( ); unset SSD[0]                           # unset is required!
 241  341  
 242      -HELP - Enter the port number the directory server is configured to
 243      -       use for LDAP.
      342 +    # GSSAPI setup
      343 +    INT[GSSAPI_ENABLE]=0
      344 +    STR[LDAP_KRB_REALM]=''
 244  345  
 245      -EOF
 246      -    ;;
 247      -    domain_help) cat <<EOF
      346 +        # temp settings
      347 +        TMPF[STEP]=0                                            # internal file counter - see nextFile()
      348 +        TMPF[IS_OPENDJ]=0                                       # set if detected DS is OpenDS/OpenDJ
      349 +        TMPF[DEL_OLD_PROFILE]=0                         # 0 = don't, 1 = delete old profile
      350 +        TMPF[STEP]=1                                            # simple progress indicator
      351 +        TMPF[GSSAPI_AUTH_MAY_BE_USED]=0         # DS GSSAPI SASL support
      352 +        TMPF[NEED_CREATE_SUFFIX]=0                      # see add_suffix()
      353 +        TMPF[NEED_CREATE_BACKEND]=0                     # see add_suffix()
      354 +        # schema completion syntax to use:
      355 +        # 0 .. detect, 1 .. force OpenDJ, 2 .. force DSEE
      356 +        (( TMPF[SYNTAX] < 0 || TMPF[SYNTAX] > 2 )) && TMPF[SYNTAX]=0
 248  357  
      358 +        TMP[FILE]=''                                            # tmp output filename - see nextFile()
      359 +    TMP[LDAP_ROOTPWF]=${TMP[DIR]}/rootPWD       # filename containing the root PW
      360 +        TMP[WARN]=''                                            # set if possibly incompatible DS
      361 +        TMP[SUFFIX_OBJ]=''                                      # suffix objectclass (long name)
      362 +        TMP[SUFFIX_ATT]=''                                      # suffix RDN attr name
      363 +    TMP[SUFFIX_VAL]=''                                  # suffix RDN attr value
      364 +        TMP[DS_DBS_AVAIL]=''                            # next available suffix DBs
      365 +        TMP[VLV_CMDS]=''                                        # where VLV commands to exec are stored
      366 +        #       Set via getopts - just make sure, they are registered
      367 +        [[ -z ${TMP[IN]} ]] && TMP[IN]=''               # the config file to read
      368 +        [[ -z ${TMP[OUT]} ]] && TMP[OUT]=''     # the config file to write
      369 +        # redirect ldap output to file instead of stdout
      370 +        if (( TMPF[FD] > 2 )); then
      371 +                exec 4>${TMP[DIR]}/ldap.out
      372 +        fi
      373 +        return 0
      374 +}
      375 +
      376 +# internal
      377 +function showProgress {
      378 +        typeset NUM=${ printf "%3d" TMPF[STEP] ; }
      379 +        Log.info "${NUM}. " "$*"
      380 +        (( TMPF[STEP]++ ))
      381 +}
      382 +
      383 +# internal
      384 +function nextFile {
      385 +        typeset CMD="$1" FN="${2// /_}" EXT='cmd'
      386 +        (( TMPF[STEP]++ ))
      387 +        case "$1" in
      388 +                add|modify|delete) CMD="ldap$1" EXT='ldif' ;;
      389 +                sh) EXT='sh'
      390 +        esac
      391 +        TMP[FILE]=${ printf "${TMP[DIR]}/%03d_${CMD}_${FN}.${EXT}" ${TMPF[STEP]} ; }
      392 +        [[ -e ${TMP[FILE]} ]] && Log.warn "Overwriting ${TMP[FILE]} ..."
      393 +}
      394 +
      395 +Man.addFunc show_vars '' '[+NAME?show_vars - List of all config variables and their values.]
      396 +[+DESCRIPTION?Lists all config variables and their current values in a more or less human readable manner.]
      397 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage INT STR SSD ; }" '}
      398 +'
      399 +function show_vars {
      400 +        (( ! VERBOSE )) && return
      401 +
      402 +        typeset S=${!STR[@]} OUT='Current non-NULL values:\n'
      403 +        S=${ print ${S// /$'\n'} | sort ; }
      404 +        for KEY in $S ; do
      405 +                [[ -n ${STR[$KEY]} ]] && \
      406 +                        OUT+=${ printf "%32s = '%s'" ${KEY} "${STR[$KEY]}" ; }'\n'
      407 +        done
      408 +        S=${!INT[@]}
      409 +        S=${ print ${S// /$'\n'} | sort ; }
      410 +        for KEY in $S ; do
      411 +                (( INT[$KEY] )) && \
      412 +                        OUT+=${ printf "%32s = %d" ${KEY} "${INT[$KEY]}" ; }'\n'
      413 +        done
      414 +        if (( ${#SSD[@]} )); then
      415 +                OUT+=${ printf "%32s = (" 'SSD' ; }
      416 +                for S in "${SSD[@]}" ; do
      417 +                        OUT+="\t\t${S}\n"
      418 +                done
      419 +                OUT+='\t)\n'
      420 +        fi
      421 +        print -u2 "${OUT}"
      422 +}
      423 +
      424 +Man.addFunc save_password '' '[+NAME?save_password - Save password to temporary file.]
      425 +[+DESCRIPTION?Save the current password from \bSTR[LDAP_ROOTPWD]]\b to the file \bTMP[LDAP_ROOTPWF]]\b.]
      426 +'
      427 +function save_password {
      428 +        print "${STR[LDAP_ROOTPWD]}" >"${TMP[LDAP_ROOTPWF]}"
      429 +}
      430 +#############################################################################
      431 +# EOG
      432 +#############################################################################
      433 +
      434 +
      435 +#############################################################################
      436 +# config file stuff
      437 +#############################################################################
      438 +Man.addFunc create_config_file '' '[+NAME?create_config_file - Write config data to the specified file.]
      439 +[+DESCRIPTION?Write config data to \afile\a.]
      440 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage INT STR SSD ; }" '}
      441 +[+RETURN VALUES]{
      442 +        [+0?file was written successfully.]
      443 +        [+>= 1?otherwise.]
      444 +}
      445 +[+SEE ALSO?\bload_config_file()\b.]
      446 +\n\n\afile\a
      447 +'
      448 +function create_config_file {
      449 +        typeset OUT="$1" KEY
      450 +        [[ -z ${OUT} ]] && return 1
      451 +
      452 +        # Create output file.
      453 +        (
      454 +        print '
      455 +# '"${OUT}"' - This file contains configuration information for
      456 +# LDAP naming services.  Use the '"${PROG}"' tool to load it.
      457 +#
      458 +# WARNING: This file was generated by '"${PROG}"', and is intended to
      459 +#          be loaded by '"${PROG}"' as is.  DO NOT EDIT THIS FILE!
      460 +'
      461 +                print 'typeset -A -i IIN=( )'
      462 +                for KEY in "${!INT[@]}" ; do
      463 +                        print "IIN[${KEY}]=${INT[${KEY}]}"
      464 +                done
      465 +                print '\ntypeset -A SIN=( )'
      466 +                for KEY in "${!STR[@]}" ; do
      467 +                        printf "SIN[${KEY}]=%q\n" "${STR[${KEY}]}"
      468 +                done
      469 +                print '\ntypeset -a SIN_SSD=( )'
      470 +                for KEY in "${SSD[@]}" ; do
      471 +                        [[ -n ${KEY} ]] && printf "SIN_SSD+=( %q )\n" "${KEY}"
      472 +                done
      473 +                print "\n# End of ${OUT}"
      474 +        ) >"${OUT}"
      475 +}
      476 +
      477 +# for backward compatibilty, but not documented: old format is bogus and should
      478 +# not be used anymore.
      479 +function source_old_config {
      480 +        typeset IN="$1" TODO='' VNAME KEY VAL LINE
      481 +        typeset -A OLDMAP=(
      482 +                [DS_HOST]=IDS_SERVER
      483 +                [DS_PORT]=IDS_PORT
      484 +                [DS_DB]=IDS_DATABASE
      485 +                [DS_TIMELIMIT]=IDS_TIMELIMIT
      486 +                [DS_SIZELIMIT]=IDS_SIZELIMIT
      487 +                [SSD]=LDAP_SERV_SRCH_DES
      488 +        )
      489 +
      490 +        for KEY in "${!INT[@]}" ; do
      491 +                VNAME=${OLDMAP[${KEY}]}
      492 +                [[ -z ${VNAME} ]] && VNAME=${KEY}
      493 +                typeset -n VAR=${VNAME}
      494 +                INT[${KEY}]=${VAR}
      495 +                TODO+="${VNAME} "
      496 +        done
      497 +        for KEY in "${!STR[@]}" ; do
      498 +                VNAME=${OLDMAP[${KEY}]}
      499 +                [[ -z ${VNAME} ]] && VNAME=${KEY}
      500 +                typeset -n VAR=${VNAME}
      501 +                STR[${KEY}]="${VAR}"
      502 +                TODO+="${VNAME} "
      503 +        done
      504 +        while read LINE; do
      505 +                if [[ ${LINE:0:19} == 'LDAP_SERV_SRCH_DES=' ]]; then
      506 +                        VAL="${LINE:19}"
      507 +                        [[ -n ${VAL} ]] && SSD+=( "${VAL}" )
      508 +                fi
      509 +        done < "${IN}"
      510 +
      511 +        # cleanup "global" namespace
      512 +        [[ -n ${TODO} ]] && eval "unset ${TODO}"
      513 +}
      514 +
      515 +Man.addFunc load_config_file '' '[+NAME?load_config_file - load an '"${PROG}"' config file.]
      516 +[+DESCRIPTION?Loads the initial config from \afile\a, which has been generated in a previous run by '"${PROG}"'. Sets \bTMPF[DEL_OLD_PROFILE]]\b to 1 on success.]
      517 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage INT STR SSD ; }" '}
      518 +[+RETURN VALUES]{
      519 +        [+0?on success.]
      520 +        [+>= 66? \afile\a is not a file or unreadable.]
      521 +}
      522 +[+SEE ALSO?\bsave_password()\b, \bshow_vars()\b.]
      523 +\n\n\afile\a
      524 +'
      525 +function load_config_file {
      526 +        typeset IN="$1" KEY VAL
      527 +        integer I
      528 +        [[ ! -f ${IN} ]] && Log.fatal "${IN} is not a file" && return 66
      529 +        [[ ! -r ${IN} ]] && Log.fatal "${IN} is not readable" && return  67
      530 +
      531 +        # source in the stuff - not nice but less work ;-)
      532 +        . "${IN}"
      533 +
      534 +        KEY=${ typeset -p IIN ; }
      535 +        if [[ -z ${KEY} ]]; then
      536 +                source_old_config "${IN}" || return 68
      537 +        else
      538 +                for KEY in "${!INT[@]}" ; do
      539 +                        INT[${KEY}]=${IIN[${KEY}]}
      540 +                done
      541 +                for KEY in "${!STR[@]}" ; do
      542 +                        STR[${KEY}]="${SIN[${KEY}]}"
      543 +                done
      544 +                for KEY in "${SIN_SSD[@]}" ; do
      545 +                        [[ -n ${KEY} ]] && SSD+=( "${KEY}" )
      546 +                done
      547 +                # cleanup "global" namespace
      548 +                unset IIN SIN SIN_SSD
      549 +        fi
      550 +
      551 +        TMPF[DEL_OLD_PROFILE]=1
      552 +        save_password
      553 +        show_vars
      554 +
      555 +        return 0
      556 +}
      557 +#############################################################################
      558 +# End Of  config file stuff
      559 +#############################################################################
      560 +
      561 +
      562 +############################################################################
      563 +# Basic [menu] stuff
      564 +############################################################################
      565 +Man.addFunc display_msg '' '[+NAME?display_msg - display a message]
      566 +[+DESCRIPTION?Display a message corresponding to the \atag\a passed in.]
      567 +[+ENVIRONMENT VARIABLES]{'"${ Man.varUsage INT STR TMP ; }" '}
      568 +\n\n\atag\a
      569 +'
      570 +function display_msg {
      571 +        typeset X
      572 +        integer I
      573 +
      574 +        case "$1" in
      575 +                backup_server)
      576 +                        print '
      577 +It is strongly recommended that you BACKUP the directory server
      578 +before running '"${PROG}"'.
      579 +
      580 +Hit Ctrl-C at any time before the final confirmation to exit.\n'
      581 +                        ;;
      582 +                cred_level_menu)
      583 +                        print 'The following are the supported credential levels:'
      584 +                        for (( I=0; I < ${#CRED_LEVELS[@]}; I++ )); do
      585 +                                printf ' %2d %s\n' $((I+1)) "${CRED_LEVELS[I]}"
      586 +                        done
      587 +                        ;;
      588 +                auth_method_menu)
      589 +                        print 'The following are the supported Client Authentication Methods:'
      590 +                        for (( I=0; I < ${#AUTH_METHODS[@]}; I++ )); do
      591 +                                printf ' %-2d  %s\n' $((I+1)) "${AUTH_METHODS[I]}"
      592 +                        done
      593 +                        ;;
      594 +                srvauth_method_menu)
      595 +                        print 'The following are the supported Service Authentication Methods:'
      596 +                        # skip 'none'
      597 +                        for (( I=1; I < ${#AUTH_METHODS[@]}; I++ )); do
      598 +                                printf ' %-2d  %s\n' $((I)) "${AUTH_METHODS[I]}"
      599 +                        done
      600 +                        ;;
      601 +                prompt_ssd_menu)
      602 +                        print '  A  Add a Service Search Descriptor (SSD)
      603 +  D  Delete a SSD
      604 +  M  Modify a SSD
      605 +  P  Display all SSDs
      606 +  H  Help
      607 +  X  Clear all SSDs
      608 +
      609 +  Q  Exit menu'
      610 +                        ;;
      611 +                summary_menu)
      612 +                        typeset SUFFIX_INFO=''
      613 +                        typeset DB_INFO=''
      614 +
      615 +                        if (( TMPF[NEED_CREATE_SUFFIX] )); then
      616 +                                SUFFIX_INFO='
      617 +         Suffix to create          : '"${STR[LDAP_SUFFIX]}"'\n'
      618 +                                (( TMPF[NEED_CREATE_BACKEND] )) && DB_INFO='
      619 +         Database to create        : '"${STR[DS_DB]}"'\n'
      620 +                        fi
      621 +                        typeset BASEDN
      622 +                        BASEDN="${STR[LDAP_BASEDN]}${STR[SUFFIX_INFO]}${STR[DB_INFO]}"
      623 +
      624 +                        print '              Summary of Configuration
      625 +
      626 +  1  Domain to serve               : '"${STR[LDAP_DOMAIN]}"'
      627 +  2  Base DN to setup              : '"${BASEDN}"'
      628 +  3  Profile name to create        : '"${STR[LDAP_PROFILE_NAME]}"'
      629 +  4  Default Server List           : '"${STR[LDAP_SERVER_LIST]}"'
      630 +  5  Preferred Server List         : '"${STR[LDAP_PREF_SRVLIST]}"'
      631 +  6  Default Search Scope          : '"${STR[LDAP_SEARCH_SCOPE]}"'
      632 +  7  Credential Level              : '"${STR[LDAP_CRED_LEVEL]}"'
      633 +  8  Authentication Method         : '"${STR[LDAP_AUTHMETHOD]}"'
      634 +  9  Enable Follow Referrals       : '"${INT[LDAP_FOLLOWREF]}"'
      635 + 10  DS Time Limit                 : '"${INT[DS_TIMELIMIT]}"'
      636 + 11  DS Size Limit                 : '"${INT[DS_SIZELIMIT]}"'
      637 + 12  Enable crypt password storage : '"${INT[NEED_CRYPT]}"'
      638 + 13  Service Auth Method pam_ldap  : '"${STR[LDAP_SRV_AUTHMETHOD_PAM]}"'
      639 + 14  Service Auth Method keyserv   : '"${STR[LDAP_SRV_AUTHMETHOD_KEY]}"'
      640 + 15  Service Auth Method passwd-cmd: '"${STR[LDAP_SRV_AUTHMETHOD_CMD]}"'
      641 + 16  Search Time Limit             : '"${INT[LDAP_SEARCH_TIME_LIMIT]}"'
      642 + 17  Profile Time to Live          : '"${INT[LDAP_PROFILE_TTL]}"'
      643 + 18  Bind Limit                    : '"${INT[LDAP_BIND_LIMIT]}"'
      644 + 19  Enable shadow update          : '"${INT[LDAP_ENABLE_SHADOW_UPDATE]}"'
      645 + 20  Service Search Descriptors Menu\n'
      646 +                        ;;
      647 +                sorry)
      648 +                        print '
      649 +HELP - No help is available for this topic.\n'
      650 +                        ;;
      651 +                create_suffix_help)
      652 +                        print '
      653 +HELP - Our Base DN is "'"${STR[LDAP_BASEDN]}"'"
      654 +       and we need to create a Directory Suffix,
      655 +       which can be equal to Base DN itself or be any of Base DN parents.
      656 +       All intermediate entries up to suffix will be created on demand.\n'
      657 +                        ;;
      658 +                enter_ldbm_db_help)
      659 +                        print '
      660 +HELP - database backend is an internal database for storage of our suffix data.
      661 +       Backend name must be alphanumeric due to Directory Server restriction.
      662 +'
      663 +                        ;;
      664 +                backup_help)
      665 +                        print '
      666 +HELP - Since '"${PROG}"' modifies the directory server configuration,
      667 +       it is strongly recommended that you backup the server prior
      668 +       to running this utility.  This is especially true if the server
      669 +       being configured is a production server.\n'
      670 +                        ;;
      671 +                port_help)
      672 +                        print '
      673 +HELP - Enter the port number the directory server is configured to
      674 +       use for LDAP.\n'
      675 +                        ;;
      676 +                adminport_help)
      677 +                        print '
      678 +HELP - Enter the Admin port number the directory server is configured to
      679 +       use for for DS administration commands.\n'
      680 +                        ;;
      681 +                domain_help)
      682 +                        print '
 249  683  HELP - This is the DNS domain name this server will be serving.  You
 250  684         must provide this name even if the server is not going to be populated
 251  685         with hostnames.  Any unqualified hostname stored in the directory
 252      -       will be fully qualified using this DNS domain name.
 253      -
 254      -EOF
 255      -    ;;
 256      -    basedn_help) cat <<EOF
 257      -
      686 +       will be fully qualified using this DNS domain name.\n'
      687 +                        ;;
      688 +                basedn_help)
      689 +                        print '
 258  690  HELP - This parameter defines the default location in the directory tree for
 259  691         the naming services entries.  You can override this default by using 
 260      -       serviceSearchDescriptors (SSD). You will be given the option to set up 
 261      -       an SSD later on in the setup.
 262      -
 263      -EOF
 264      -    ;;
 265      -    profile_help) cat <<EOF
 266      -
      692 +       Service Search Descriptors (SSD). You will be given the option to set up 
      693 +       an SSD later on in the setup.\n'
      694 +                        ;;
      695 +                profile_help)
      696 +                        print '
 267  697  HELP - Name of the configuration profile with which the clients will be
 268  698         configured. A directory server can store various profiles for multiple 
 269  699         groups of clients.  The initialization tool, (ldapclient(1M)), assumes 
 270      -       "default" unless another is specified.
 271      -
 272      -EOF
 273      -    ;;
 274      -    def_srvlist_help) cat <<EOF
 275      -
      700 +       "default" unless another is specified.\n'
      701 +                        ;;
      702 +                def_srvlist_help)
      703 +                        print '
 276  704  HELP - Provide a list of directory servers to serve clients using this profile.
 277  705         All these servers should contain consistent data and provide similar 
 278  706         functionality.  This list is not ordered, and clients might change the 
 279  707         order given in this list. Note that this is a space separated list of 
 280      -       *IP addresses* (not host names).  Providing port numbers is optional.
 281      -
 282      -EOF
 283      -    ;;
 284      -    pref_srvlist_help) cat <<EOF
 285      -
      708 +       *IP addresses* (not host names).  Providing port numbers is optional.\n'
      709 +                        ;;
      710 +                pref_srvlist_help)
      711 +                        print '
 286  712  HELP - Provide a list of directory servers to serve this client profile. 
 287  713         Unlike the default server list, which is not ordered, the preferred 
 288  714         servers must be entered IN THE ORDER you wish to have them contacted. 
 289  715         If you do specify a preferred server list, clients will always contact 
 290  716         them before attempting to contact any of the servers on the default 
 291  717         server list. Note that you must enter the preferred server list as a 
 292  718         space-separated list of *IP addresses* (not host names).  Providing port 
 293      -       numbers is optional.
 294      -
 295      -EOF
 296      -    ;;
 297      -    srch_scope_help) cat <<EOF
 298      -
      719 +       numbers is optional.\n'
      720 +                        ;;
      721 +                srch_scope_help)
      722 +                        print '
 299  723  HELP - Default search scope to be used for all searches unless they are
 300  724         overwritten using serviceSearchDescriptors.  The valid options
 301  725         are "one", which would specify the search will only be performed 
 302  726         at the base DN for the given service, or "sub", which would specify 
 303  727         the search will be performed through *all* levels below the base DN 
 304      -       for the given service.
 305      -
 306      -EOF
 307      -    ;;
 308      -    cred_lvl_help) cat <<EOF
 309      -
 310      -HELP - This parameter defines what credentials the clients use to
 311      -       authenticate to the directory server.  This list might contain
 312      -       multiple credential levels and is ordered.  If a proxy level
 313      -       is configured, you will also be prompted to enter a bind DN
 314      -       for the proxy agent along with a password.  This proxy agent
 315      -       will be created if it does not exist.
 316      -
 317      -EOF
 318      -    ;;
 319      -    auth_help) cat <<EOF
 320      -
 321      -HELP - The default authentication method(s) to be used by all services
      728 +       for the given service. If you use the default DIT layout, "one" should
      729 +       be ok and probably a little bit faster.\n'
      730 +                        ;;
      731 +                cred_lvl_help)
      732 +                        print '
      733 +HELP - This parameter defines what credentials (identity) the clients use to
      734 +       authenticate (bind) to the directory server.  This list might contain
      735 +       multiple credential levels and is ordered.  If a proxy level is
      736 +       configured, you will also be prompted to enter a bind DN for the
      737 +       proxy agent along with a password.  This proxy agent will be created
      738 +       if it does not exist. See also ldapclient(1M).\n'
      739 +                        ;;
      740 +                auth_help)
      741 +                        print '
      742 +HELP - The default authentication (bind) method(s) to be used by all services
 322  743         in the client using this profile.  This is a ordered list of
 323      -       authentication methods separated by a ';'.  The supported methods
 324      -       are provided in a menu.  Note that sasl/DIGEST-MD5 binds require
 325      -       passwords to be stored un-encrypted on the server.
 326      -
 327      -EOF
 328      -    ;;
 329      -    srvauth_help) cat <<EOF
 330      -
 331      -HELP - The authentication methods to be used by a given service.  Currently
 332      -       3 services support this feature: pam_ldap, keyserv, and passwd-cmd.
 333      -       The authentication method specified in this attribute overrides
      744 +       authentication methods separated by a ";".  The supported methods are
      745 +       provided in a menu.  Note that sasl/DIGEST-MD5 binds require passwords
      746 +       to be stored un-encrypted on the server. See also ldapclient(1M).\n'
      747 +                        ;;
      748 +                srvauth_help)
      749 +                        print '
      750 +HELP - The non-default authentication (bind) methods to be used by certain
      751 +       services (for now pam_ldap, keyserv, and passwd-cmd are supported).
      752 +       The authentication methods specified in this attribute overrides
 334  753         the default authentication method defined in the profile.  This
 335  754         feature can be used to select stronger authentication methods for
 336      -       services which require increased security.
 337      -
 338      -EOF
 339      -    ;;
 340      -    pam_ldap_help) cat <<EOF
 341      -
 342      -HELP - The authentication method(s) to be used by pam_ldap when contacting
 343      -       the directory server.  This is a ordered list, and, if provided, will
 344      -       override the default authentication method parameter.
 345      -
 346      -EOF
 347      -    ;;
 348      -    keyserv_help) cat <<EOF
 349      -
 350      -HELP - The authentication method(s) to be used by newkey(1M) and chkey(1)
 351      -       when contacting the directory server.  This is a ordered list and
 352      -       if provided will override the default authentication method
 353      -       parameter.
 354      -
 355      -EOF
 356      -    ;;
 357      -    passwd-cmd_help) cat <<EOF
 358      -
 359      -HELP - The authentication method(s) to be used by passwd(1) command when
      755 +       services which require increased security.\n'
      756 +                        ;;
      757 +                pam_ldap_help)
      758 +                        print '
      759 +HELP - The authentication (bind) method(s) to be used by pam_ldap when
      760 +       contacting the directory server.  This is a ordered list, and, if
      761 +       provided, will override the default authentication method parameter.\n'
      762 +                        ;;
      763 +                keyserv_help)
      764 +                        print '
      765 +HELP - The authentication (bind) method(s) to be used by newkey(1M) and chkey(1)
      766 +       when contacting the directory server.  This is a ordered list and if
      767 +       provided will override the default authentication method parameter.\n'
      768 +                        ;;
      769 +                passwd-cmd_help)
      770 +                        print '
      771 +HELP - The authentication (bind) method(s) to be used by passwd(1) command when
 360  772         contacting the directory server.  This is a ordered list and if
 361      -       provided will override the default authentication method parameter.
 362      -
 363      -EOF
 364      -    ;;
 365      -    referrals_help) cat <<EOF
 366      -
      773 +       provided will override the default authentication method parameter.\n'
      774 +                        ;;
      775 +                referrals_help)
      776 +                        print '
 367  777  HELP - This parameter indicates whether the client should follow
 368      -       ldap referrals if it encounters one during naming lookups.
 369      -
 370      -EOF
 371      -    ;;
 372      -    tlim_help) cat <<EOF
 373      -
      778 +       ldap referrals if it encounters one during naming lookups.\n'
      779 +                        ;;
      780 +                tlim_help)
      781 +                        print '
 374  782  HELP - The server time limit value indicates the maximum amount of time the
 375  783         server would spend on a query from the client before abandoning it.
 376      -       A value of '-1' indicates no limit.
 377      -
 378      -EOF
 379      -    ;;
 380      -    slim_help) cat <<EOF
 381      -
      784 +       A value of "-1" indicates no limit.\n'
      785 +                        ;;
      786 +                slim_help)
      787 +                        print '
 382  788  HELP - The server sizelimit value indicates the maximum number of entries
 383  789         the server would return in respond to a query from the client.  A
 384      -       value of '-1' indicates no limit.
 385      -
 386      -EOF
 387      -    ;;
 388      -    crypt_help) cat <<EOF
 389      -
 390      -HELP - By default iDS does not store userPassword attribute values using
 391      -       unix "crypt" format.  If you need to keep your passwords in the crypt
 392      -       format for NIS/NIS+ and pam_unix compatibility, choose 'yes'.  If
 393      -       passwords are stored using any other format than crypt, pam_ldap
      790 +       value of "-1" indicates no limit.\n'
      791 +                        ;;
      792 +                crypt_help)
      793 +                        print '
      794 +HELP - By default a DS does not store userPassword attribute values using
      795 +       unix "crypt" formats (like bsdmd5, sunmd5, sha256, sha512, old crypt,
      796 +       etc. - see crypt.conf(4)).  If you need to keep your passwords in the
      797 +       crypt formats for backward or pam_unix compatibility, choose "yes".
      798 +       If any other password storage scheme than crypt is used, pam_ldap
 394  799         MUST be used by clients to authenticate users to the system. Note 
 395      -       that if you wish to use sasl/DIGEST-MD5 in conjunction with pam_ldap,
 396      -       user passwords must be stored in the clear format.
 397      -
 398      -EOF
 399      -    ;;
 400      -    srchtime_help) cat <<EOF
 401      -
 402      -HELP - The search time limit the client will enforce for directory
 403      -       lookups.
 404      -
 405      -EOF
 406      -    ;;
 407      -    profttl_help) cat <<EOF
 408      -
      800 +       that if you wish to use sasl/*-MD5 in conjunction with pam_ldap,
      801 +       user passwords are/must be stored in the clear text.\n'
      802 +                        ;;
      803 +                srchtime_help)
      804 +                        print '
      805 +HELP - The search time limit the client will enforce for directory lookups.\n'
      806 +                        ;;
      807 +                profttl_help)
      808 +                        print '
 409  809  HELP - The time to live value for profile.  The client will refresh its
 410      -       cached version of the configuration profile at this TTL interval.
 411      -
 412      -EOF
 413      -    ;;
 414      -    bindlim_help) cat <<EOF
 415      -
      810 +       cached version of the configuration profile at this TTL interval.\n'
      811 +                        ;;
      812 +                bindlim_help)
      813 +                        print '
 416  814  HELP - The time limit for the bind operation to the directory.  This
 417  815         value controls the responsiveness of the client in case a server
 418  816         becomes unavailable.  The smallest timeout value for a given
 419  817         network architecture/conditions would work best.  This is very
 420      -       similar to setting TCP timeout, but only for LDAP bind operation.
 421      -
 422      -EOF
 423      -    ;;
 424      -    ssd_help) cat <<EOF
 425      -
      818 +       similar to setting TCP timeout, but only for LDAP bind operation.\n'
      819 +                        ;;
      820 +                ssd_help)
      821 +                        print '
 426  822  HELP - Using Service Search Descriptors (SSD), you can override the
 427  823         default configuration for a given service.  The SSD can be
 428  824         used to override the default search base DN, the default search
 429  825         scope, and the default search filter to be used for directory
 430  826         lookups.  SSD are supported for all services (databases)
 431      -       defined in nsswitch.conf(4).  The default base DN is defined
 432      -       in ldap(1).
      827 +       defined in nsswitch.conf(4). See also ldapclient(1M).
 433  828  
 434  829         Note: SSD are powerful tools in defining configuration profiles
 435  830               and provide a great deal of flexibility.  However, care
 436  831               must be taken in creating them.  If you decide to make use
 437      -             of SSDs, consult the documentation first.
 438      -
 439      -EOF
 440      -    ;;
 441      -    ssd_menu_help) cat <<EOF
 442      -
      832 +             of SSDs, consult the documentation first.\n'
      833 +                        ;;
      834 +                ssd_menu_help)
      835 +                        print '
 443  836  HELP - Using this menu SSD can be added, updated, or deleted from
 444  837         the profile.
 445  838  
 446  839         A - This option creates a new SSD by prompting for the
 447  840             service name, base DN, and scope.  Service name is
 448  841             any valid service as defined in ldap(1).  base is
 449  842             either the distinguished name to the container where
 450  843             this service will use, or a relative DN followed
 451      -           by a ','.
      844 +           by a ",". For more information see ldapclient(1M).
 452  845         D - Delete a previously created SSD.
 453  846         M - Modify a previously created SSD.
 454  847         P - Display a list of all the previously created SSD.
 455  848         X - Delete all of the previously created SSD.
 456  849  
 457      -       Q - Exit the menu and continue with the server configuration.
 458      -
 459      -EOF
 460      -    ;;
 461      -    ldap_suffix_list_help) cat <<EOF
 462      -
 463      -HELP - No valid suffixes (naming contexts) are available on server 
 464      -       ${IDS_SERVER}:${IDS_PORT}.
 465      -       You must set an LDAP Base DN that can be contained in 
 466      -       an existing suffix.
 467      -
 468      -EOF
 469      -    ;;
 470      -    enable_shadow_update_help) cat <<EOF
 471      -
 472      -HELP - Enter 'y' to set up the LDAP server for shadow update.
      850 +       Q - Exit the menu and continue with the server configuration.\n'
      851 +                        ;;
      852 +                enable_shadow_update_help)
      853 +                        print '
      854 +HELP - Enter "y" to set up the LDAP server for shadow update.
 473  855         The setup will add an administrator identity/credential
 474  856         and modify the necessary access controls for the client
 475      -       to update shadow(4) data on the LDAP server. If sasl/GSSAPI
 476      -       is in use, the Kerberos host principal will be used as the
 477      -       administrator identity.
      857 +       to update shadow(4), auth_attr(4), exec_attr(4), prof_attr(4),
      858 +       user_attr(4), and project(4) data on the LDAP server. If
      859 +       sasl/GSSAPI is in use, the Kerberos host principal will be used
      860 +       as the administrator identity.
 478  861  
 479  862         Shadow data is used for password aging and account locking.
 480      -       Please refer to the shadow(4) manual page for details.
 481      -
 482      -EOF
 483      -    ;;
 484      -    add_admin_cred_help) cat <<EOF
 485      -
      863 +       Please refer to the shadow(4) manual page for details.\n'
      864 +                        ;;
      865 +                add_admin_cred_help)
      866 +                        print '
 486  867  HELP - Start the setup to add an administrator identity/credential
 487  868         and to modify access controls for the client to update
 488      -       shadow(4) data on the LDAP server.
      869 +       shadow(4), auth_attr(4), exec_attr(4), prof_attr(4),
      870 +       user_attr(4), and project(4) data on the LDAP server.
 489  871  
 490  872         Shadow data is used for password aging and account locking.
 491      -       Please refer to the shadow(4) manual page for details.
 492      -
 493      -EOF
 494      -    ;;
 495      -    use_host_principal_help) cat <<EOF
 496      -
 497      -HELP - A profile with a 'sasl/GSSAPI' authentication method and a 'self'
 498      -       credential level is detected, enter 'y' to modify the necessary
      873 +       Please refer to the shadow(4) manual page for details.\n'
      874 +                        ;;
      875 +                use_host_principal_help)
      876 +                        print '
      877 +HELP - A profile with a "sasl/GSSAPI" authentication method and a "self"
      878 +       credential level is detected, enter "y" to modify the necessary
 499  879         access controls for allowing the client to update shadow(4) data
 500  880         on the LDAP server.
 501  881  
 502  882         Shadow data is used for password aging and account locking.
 503      -       Please refer to the shadow(4) manual page for details.
      883 +       Please refer to the shadow(4) manual page for details.\n'
      884 +                        ;;
      885 +        esac
      886 +}
 504  887  
 505      -EOF
 506      -    ;;
 507      -    esac
      888 +Man.addVar ANS 'Variable used to return the user input.'
      889 +Man.addFunc get_ans '' '[+NAME?get_ans - gets an answer from the user.]
      890 +[+DESCRIPTION?Read a string from stdin. Arguments:]{
      891 +        [+prompt?instruction/comment/description/question to show.]
      892 +        [+default?Default value to use if no answer/empty string was read.]
 508  893  }
      894 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage ANS ; }" '}
      895 +\n\n\aprompt\a [\adefault\a]
      896 +'
      897 +function get_ans {
      898 +        typeset PROMPT="$1 "
      899 +    [[ -n $2 ]] && PROMPT+="[$2] "
 509  900  
      901 +        read ANS?"${PROMPT}"
      902 +        [[ -z ${ANS} ]] && ANS="$2"
      903 +}
 510  904  
 511      -#
 512      -# get_ans(): gets an answer from the user.
 513      -#               $1  instruction/comment/description/question
 514      -#               $2  default value
 515      -#
 516      -get_ans()
 517      -{
 518      -    if [ -z "$2" ]
 519      -    then
 520      -        ${ECHO} "$1 \c"
 521      -    else
 522      -        ${ECHO} "$1 [$2] \c"
 523      -    fi
 524  905  
 525      -    read ANS
 526      -    if [ -z "$ANS" ]
 527      -    then
 528      -        ANS=$2
 529      -    fi
      906 +Man.addFunc get_ans_req '' '[+NAME?get_ans_req - get a non-empty answer from the user.]
      907 +[+DESCRIPTION?Read a string from stdin. Does not return until the string is a non-empty string or a \adefault\a value is given. Arguments:]{
      908 +        [+prompt?instruction/comment/description/question to show.]
      909 +        [+default?Default value to use if no answer/empty string was read.]
 530  910  }
      911 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage ANS ; }" '}
      912 +[+SEE ALSO?\bget_ans()\b]
      913 +\n\n\aprompt\a [\adefault\a]
      914 +'
      915 +function get_ans_req {
      916 +        ANS=''
      917 +        while [[ -z ${ANS} ]]; do
      918 +                get_ans "$@"
      919 +                [[ -z ${ANS} ]] && Log.warn 'NULL value not allowed'
      920 +        done
      921 +}
 531  922  
      923 +Man.addFunc is_numeric '' '[+NAME?is_numeric - check whether arg is a numeric string]
      924 +[+DESCRIPTION?Check whether the given \astring\a is a numeric string.]
      925 +[+RETURN VALUES]{
      926 +        [+0?If the string is a numeric string.]
      927 +        [+1?Otherwise.]
      928 +}
      929 +[+SEE ALSO?\bnot_numeric()\b]
      930 +\n\n\astring\a
      931 +'
      932 +function is_numeric {
      933 +        (( $# != 1 )) && return 1
      934 +    [[ $1 =~ ^[0-9]+$ ]] && return 0 || return 1
      935 +}
 532  936  
 533      -#
 534      -# get_ans_req(): gets an answer (required) from the user, NULL value not allowed.
 535      -#               $@  instruction/comment/description/question
 536      -#
 537      -get_ans_req()
 538      -{
 539      -    ANS=""                  # Set ANS to NULL.
 540      -    while [ "$ANS" = "" ]
 541      -    do 
 542      -        get_ans "$@"
 543      -        [ "$ANS" = "" ] && ${ECHO} "NULL value not allowed!"
 544      -    done
      937 +Man.addFunc not_numeric '' '[+NAME?not_numeric - check whether arg is NOT a numeric string]
      938 +[+DESCRIPTION?Check whether the given \astring\a is NOT a numeric string. Useful for if and while statements that want to test for non-numeric data.]
      939 +[+RETURN VALUES]{
      940 +        [+0?If the string is NOT a numeric string.]
      941 +        [+1?Otherwise.]
 545  942  }
      943 +[+SEE ALSO?\bis_numeric()\b]
      944 +\n\n\astring\a
      945 +'
      946 +function not_numeric {
      947 +        is_numeric $1 && return 1 || return 0
      948 +}
 546  949  
 547      -
 548      -#
 549      -# get_number(): Querys and verifies that number entered is numeric.
 550      -#               Function will repeat prompt user for number value.
 551      -#               $1  Message text.
 552      -#               $2  default value.
 553      -#               $3  Help argument.
 554      -#
 555      -get_number()
      950 +Man.addVar NUM 'Variable used to return the user input as a number.'
      951 +integer NUM
      952 +Man.addFunc get_number '' '[+NAME?get_number - get a number from the user.]
      953 +[+DESCRIPTION?Read a string from stdin until it represents a number. Arguments:]
 556  954  {
 557      -    ANS=""                  # Set ANS to NULL.
 558      -    NUM=""
      955 +        [+prompt?instruction/comment/description/question to show.]
      956 +        [+default?Default value to use if no answer/empty string was read.]
      957 +        [+helpTag?Tag of the help message to show, when the string read is h|H|?|help|Help.]
      958 +}
      959 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage NUM ANS ; }" '}
      960 +[+SEE ALSO?\bget_ans()\b, \bis_numeric()\b, \bdisplay_msg()\b]
      961 +\n\n\aprompt\a \adefault\a [\ahelpTag\a]
      962 +'
      963 +function get_number {
      964 +        ANS=''
 559  965  
 560      -    get_ans "$1" "$2"
      966 +        get_ans "$1" "$2"
 561  967  
 562      -    # Verify that value is numeric.
 563      -    while not_numeric $ANS
 564      -    do
 565      -        case "$ANS" in
 566      -            [Hh] | help | Help | \?) display_msg ${3:-sorry} ;;
 567      -            * ) ${ECHO} "Invalid value: \"${ANS}\". \c"
 568      -             ;;
 569      -        esac
 570      -        # Get a new value.
 571      -        get_ans "Enter a numeric value:" "$2"
 572      -    done
 573      -    NUM=$ANS
      968 +        while not_numeric $ANS ; do
      969 +                case "${ANS}" in
      970 +                        [Hh?] | help | Help) display_msg ${3:-sorry} ;;
      971 +                        * ) Log.warn "Invalid value: '${ANS}'" ;;
      972 +                esac
      973 +                get_ans 'Enter a numeric value:' "$2"
      974 +        done
      975 +        NUM=${ANS}
 574  976  }
 575  977  
 576  978  
 577      -#
 578      -# get_negone_num(): Only allows a -1 or positive integer.
 579      -#                   Used for values where -1 has special meaning.
 580      -#
 581      -#                   $1 - Prompt message.
 582      -#                   $2 - Default value (require).
 583      -#                   $3 - Optional help argument.
 584      -get_negone_num()
      979 +Man.addFunc get_negone_num '' '[+NAME?get_negone_num - get a number >= -1 from the user.]
      980 +[+DESCRIPTION?Read a string from stdin until it represents a number >= -1. Arguments:]
 585  981  {
 586      -    while :
 587      -    do
 588      -        get_number "$1" "$2" "$3"
 589      -        if is_negative $ANS
 590      -        then
 591      -            if [ "$ANS" = "-1" ]; then
 592      -                break  # -1 is OK, so break.
 593      -            else       # Need to re-enter number.
 594      -                ${ECHO} "Invalid number: please enter -1 or positive number."
 595      -            fi
 596      -        else
 597      -            break      # Positive number
 598      -        fi
 599      -    done
      982 +        [+prompt?instruction/comment/description/question to show.]
      983 +        [+default?Default value to use if no answer/empty string was read.]
      984 +        [+helpTag?Tag of the help message to show, when the string read is h|H|?|help|Help.]
 600  985  }
      986 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage NUM ANS ; }" '}
      987 +[+SEE ALSO?\bget_number()\b]
      988 +\n\n\aprompt\a \adefault\a [\ahelpTag\a]
      989 +'
      990 +function get_negone_num {
      991 +        while : ; do
      992 +                get_number "$1" "$2" "$3"
      993 +                (( NUM >= -1 )) && break
      994 +                Log.warn 'Invalid number! Enter a number >= -1'
      995 +        done
      996 +}
 601  997  
 602      -
 603      -#
 604      -# get_passwd(): Reads a password from the user and verify with second.
 605      -#               $@  instruction/comment/description/question
 606      -#
 607      -get_passwd()
      998 +Man.addFunc get_passwd '' '[+NAME?get_passwd - get a password from the user.]
      999 +[+DESCRIPTION?Read a password from stdin and verify with second until both match. Password gets not echoed to stdout. Arguments:]
 608 1000  {
 609      -    [ $DEBUG -eq 1 ] && ${ECHO} "In get_passwd()"
     1001 +    [+prompt?instruction/comment/description/question to show.]
     1002 +    [+default?Default value to use if no answer/empty string was read.]
     1003 +}
     1004 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage ANS ; }" '}
     1005 +[+SEE ALSO?\bget_ans()\b]
     1006 +\n\n\aprompt\a [\adefault\a]
     1007 +'
     1008 +function get_passwd {
     1009 +        typeset _PASS1='' _PASS2=''
 610 1010  
 611      -    # Temporary PASSWD variables
 612      -    _PASS1=""
 613      -    _PASS2=""
     1011 +        ${STTY} -echo                   # Turn echo OFF
 614 1012  
 615      -    /usr/bin/stty -echo     # Turn echo OFF
     1013 +        # continue until passwd and re-entered passwd match
     1014 +        while : ; do
     1015 +                ANS=''
     1016 +                # Don't allow NULL for first try.
     1017 +                while [[ -z ${ANS}  ]]; do
     1018 +                        get_ans "$@"
     1019 +                        [[ -z ${ANS} ]] && \
     1020 +                                print -u2 && Log.warn 'Empty password not allowed'
     1021 +                done
     1022 +                _PASS1="${ANS}"                 # Store first try.
 616 1023  
 617      -    # Endless loop that continues until passwd and re-entered passwd
 618      -    # match.
 619      -    while :
 620      -    do
 621      -        ANS=""                  # Set ANS to NULL.
     1024 +                print
     1025 +                get_ans 'Re-enter password:'
     1026 +                _PASS2="${ANS}"
 622 1027  
 623      -        # Don't allow NULL for first try.
 624      -        while [ "$ANS" = "" ]
 625      -        do
 626      -            get_ans "$@"
 627      -            [ "$ANS" = "" ] && ${ECHO} "" && ${ECHO} "NULL passwd not allowed!"
     1028 +                [[ ${_PASS1} == ${_PASS2} ]] && break
     1029 +                print -u2 && Log.warn "passwords don't match - try again"
 628 1030          done
 629      -        _PASS1=$ANS         # Store first try.
 630 1031  
 631      -        # Get second try.
 632      -        ${ECHO} ""
 633      -        get_ans "Re-enter passwd:"
 634      -        _PASS2=$ANS
     1032 +        ${STTY} echo                    # Turn echo ON
 635 1033  
 636      -        # Test if passwords are identical.
 637      -        if [ "$_PASS1" = "$_PASS2" ]; then
 638      -            break
 639      -        fi
 640      -        
 641      -        # Move cursor down to next line and print ERROR message.
 642      -        ${ECHO} ""
 643      -        ${ECHO} "ERROR: passwords don't match; try again."
 644      -    done
 645      -
 646      -    /usr/bin/stty echo      # Turn echo ON
 647      -
 648      -    ${ECHO} ""
     1034 +        print
 649 1035  }
 650 1036  
 651      -
 652      -#
 653      -# get_passwd_nochk(): Reads a password from the user w/o check.
 654      -#               $@  instruction/comment/description/question
 655      -#
 656      -get_passwd_nochk()
     1037 +Man.addFunc get_passwd_nochk '' '[+NAME?get_passwd_nochk - get a password from the user w/o check.]
     1038 +[+DESCRIPTION?Read a password from stdin. Actually the same as \bget_ans()\b but echoing characters read to stdout is switched off. Arguments:]
 657 1039  {
 658      -    [ $DEBUG -eq 1 ] && ${ECHO} "In get_passwd_nochk()"
 659      -
 660      -    /usr/bin/stty -echo     # Turn echo OFF
 661      -
 662      -    get_ans "$@"
 663      -
 664      -    /usr/bin/stty echo      # Turn echo ON
 665      -
 666      -    ${ECHO} ""
     1040 +    [+prompt?instruction/comment/description/question to show.]
     1041 +    [+default?Default value to use if no answer/empty string was read.]
 667 1042  }
     1043 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage ANS ; }" '}
     1044 +[+SEE ALSO?\bget_ans()\b]
     1045 +\n\n\aprompt\a [\adefault\a]
     1046 +'
     1047 +function get_passwd_nochk {
     1048 +        ${STTY} -echo                   # Turn echo OFF
     1049 +        get_ans "$@"
     1050 +        ${STTY} echo                    # Turn echo ON
     1051 +        print
     1052 +}
 668 1053  
 669      -
 670      -#
 671      -# get_menu_choice(): Get a menu choice from user.  Continue prompting
 672      -#                    till the choice is in required range.
 673      -#   $1 .. Message text.
 674      -#   $2 .. min value
 675      -#   $3 .. max value
 676      -#   $4 .. OPTIONAL: default value
 677      -#
 678      -#   Return value: 
 679      -#     MN_CH will contain the value selected.
 680      -#
 681      -get_menu_choice()
     1054 +Man.addFunc get_menu_choice '' '[+NAME?get_menu_choice - get a valid menu choice number.]
     1055 +[+DESCRIPTION?Get a menu choice from user. Continue prompting until the choice is in required range. Arguments:]
 682 1056  {
 683      -    # Check for req parameter.
 684      -    if [ $# -lt 3 ]; then
 685      -        ${ECHO} "get_menu_choice(): Did not get required parameters."
 686      -        return 1
 687      -    fi
     1057 +        [+prompt?Message text.]
     1058 +        [+min?Min value.]
     1059 +        [+max?Max value.]
     1060 +        [+default?Default value to use if no answer/empty string was read.]
     1061 +        [+helpTag?If given, "h" is allowed as well and the help message for this tag gets shown, when it got typed and before the prompt is shown the first time. The prompt should contain a hint in this case.]
     1062 +        [+menuTag?If given the menu choices for the given menu gest displayed at start and after each help text.]
     1063 +}
     1064 +[+RETURN VALUES]{
     1065 +        [+-1?on error (invalid parameters).]
     1066 +        [+>= \amin\a?the selected value.]
     1067 +}
     1068 +[+SEE ALSO?\bis_numeric()\b, \bget_ans()\b, \bdisplay_msg()\b.]
     1069 +\n\n\aprompt\a \amin\a \amax\a [\adefault\a [\ahelpTag\a]] 
     1070 +'
     1071 +function get_menu_choice {
     1072 +        if (( $# < 3 )); then
     1073 +                Log.warn "${.sh.fun}(): Did not get required parameters"
     1074 +                return -1
     1075 +        fi
 688 1076  
 689      -    while :
 690      -    do
 691      -        get_ans "$1" "$4"
 692      -        MN_CH=$ANS
 693      -        is_negative $MN_CH
 694      -        if [ $? -eq 1 ]; then
 695      -            if [ $MN_CH -ge $2 ]; then
 696      -                if [ $MN_CH -le $3 ]; then
 697      -                    return
     1077 +        [[ -n $6 ]] && display_msg "$6"
     1078 +        while : ; do
     1079 +                get_ans "$1" "$4"
     1080 +                if is_numeric ${ANS} && NUM=${ANS} && (( NUM >= $2 )) && (( NUM <= $3 ))
     1081 +                then
     1082 +                        return ${NUM}
 698 1083                  fi
 699      -            fi
 700      -        fi
 701      -        ${ECHO} "Invalid choice: $MN_CH"
 702      -    done
     1084 +                if [[ -n $5 && ${ANS} == 'h' ]]; then
     1085 +                        display_msg "$5"
     1086 +                        [[ -n $6 ]] && display_msg "$6"
     1087 +                        continue
     1088 +                fi
     1089 +                Log.warn "Invalid choice! Enter a number in the range $2 .. $3"
     1090 +        done
     1091 +        return -1
 703 1092  }
 704 1093  
 705      -
 706      -#
 707      -# get_confirm(): Get confirmation from the user. (Y/Yes or N/No)
 708      -#                $1 - Message
 709      -#                $2 - default value.
 710      -#
 711      -get_confirm()
     1094 +Man.addFunc get_confirm '' '[+NAME?get_confirm - Get confirmation from the user.]
     1095 +[+DESCRIPTION?Read a string from stdin until it matches Y|y|Yes|yes|YES|N|n|No|no|NO or an empty string. Arguments:]
 712 1096  {
 713      -    _ANSWER=
     1097 +    [+prompt?instruction/comment/description/question to show.]
     1098 +    [+default?Default value to use if no answer/empty string was read.]
     1099 +    [+helpTag?Tag of the help message to show, when the string read is h|H|?|help|Help.]
     1100 +}
     1101 +[+RETURN VALUES]{
     1102 +        [+0?for NO]
     1103 +        [+1?for YES]
     1104 +}
     1105 +[+SEE ALSO?\bdisplay_msg()\b]
     1106 +\n\n\aprompt\a \adefault\a [\ahelpTag\a]
     1107 +'
     1108 +function get_confirm {
     1109 +        typeset _ANSWER=''
 714 1110  
 715      -    while :
 716      -    do
 717      -        # Display Internal ERROR if $2 not set.
 718      -        if [ -z "$2" ]
 719      -        then
 720      -            ${ECHO} "INTERNAL ERROR: get_confirm requires 2 args, 3rd is optional."
 721      -            exit 2
     1111 +        if [[ -z $2 ]]; then
     1112 +                Log.fatal "INTERNAL ERROR: ${.sh.fun} requires 2 args, 3rd is optional"
     1113 +                exit 2
 722 1114          fi
 723 1115  
 724      -        # Display prompt.
 725      -        ${ECHO} "$1 [$2] \c"
     1116 +        while : ; do
     1117 +                read _ANSWER?"$1 [$2] "
     1118 +                [[ -z ${_ANSWER} ]] && _ANSWER="$2"
 726 1119  
 727      -        # Get the ANSWER.
 728      -        read _ANSWER
 729      -        if [ "$_ANSWER" = "" ] && [ -n "$2" ] ; then
 730      -            _ANSWER=$2
 731      -        fi
 732      -        case "$_ANSWER" in
 733      -            [Yy] | yes | Yes | YES) return 1 ;;
 734      -            [Nn] | no  | No  | NO)  return 0 ;;
 735      -            [Hh] | help | Help | \?) display_msg ${3:-sorry};;
 736      -            * ) ${ECHO} "Please enter y or n."  ;;
 737      -        esac
 738      -    done
     1120 +                case "${_ANSWER}" in
     1121 +                    [Yy] | yes | Yes | YES) return 1 ;;
     1122 +                        [Nn] | no  | No  | NO)  return 0 ;;
     1123 +                        [Hh?] | help | Help) display_msg ${3:-sorry} ;;
     1124 +                        * ) Log.warn 'Please enter y or n'  ;;
     1125 +                esac
     1126 +        done
 739 1127  }
 740 1128  
 741      -
 742      -#
 743      -# get_confirm_nodef(): Get confirmation from the user. (Y/Yes or N/No)
 744      -#                      No default value supported.
 745      -#
 746      -get_confirm_nodef()
     1129 +Man.addFunc get_confirm_nodef '' '[+NAME?get_confirm_nodef - Get confirmation from the user.]
     1130 +[+DESCRIPTION?Read a string from stdin until it matches Y|y|Yes|yes|YES|N|n|No|no|NO. No default value and help tag supported. Arguments:]
 747 1131  {
 748      -    _ANSWER=
     1132 +        [+prompt?instruction/comment/description/question to show.]
     1133 +}
     1134 +[+RETURN VALUES]{
     1135 +        [+0?for NO]
     1136 +        [+1?for YES]
     1137 +}
     1138 +\n\n[\aprompt\a]...
     1139 +'
     1140 +function get_confirm_nodef {
     1141 +        typeset _ANSWER=''
 749 1142  
 750      -    while :
 751      -    do
 752      -        ${ECHO} "$@ \c"
 753      -        read _ANSWER
 754      -        case "$_ANSWER" in
 755      -            [Yy] | yes | Yes | YES) return 1 ;;
 756      -            [Nn] | no  | No  | NO)  return 0 ;;
 757      -            * ) ${ECHO} "Please enter y or n."  ;;
 758      -        esac
 759      -    done
     1143 +        while : ; do
     1144 +                read _ANSWER?"$@ "
     1145 +                case "${_ANSWER}" in
     1146 +                        [Yy] | yes | Yes | YES) return 1 ;;
     1147 +                        [Nn] | no  | No  | NO)  return 0 ;;
     1148 +                        * ) Log.warn 'Please enter y or n'  ;;
     1149 +                esac
     1150 +        done
 760 1151  }
     1152 +############################################################################
     1153 +# End of basic [menu] stuff
     1154 +############################################################################
 761 1155  
 762 1156  
 763      -#
 764      -# is_numeric(): Tells is a string is numeric.
 765      -#    0 = Numeric
 766      -#    1 = NOT Numeric
 767      -#
 768      -is_numeric()
 769      -{
 770      -    # Check for parameter.
 771      -    if [ $# -ne 1 ]; then
 772      -        return 1
 773      -    fi
     1157 +######################################################################
     1158 +# FUNCTIONS FOR prompt_config_info() START HERE.
     1159 +######################################################################
     1160 +Man.addFunc get_ids_server '' '[+NAME?get_ids_server - Prompt for DS server name.]
     1161 +[+DESCRIPTION?Ask the user for the DS hostname, store it into \bSTR[DS_HOST]]\b and adjusts \bCON_ARGS\b.]
     1162 +[+ENVIRONMENT VARIABLES]{'"${ Man.varUsage CON_ARGS ; }"'}
     1163 +[+SEE ALSO?\bget_ans()\b, \bget_ids_port()\b, \bping\b(1M).]
     1164 +'
     1165 +function get_ids_server {
     1166 +        typeset SRV="${STR[DS_HOST]}"
     1167 +        typeset OS=${ uname -s ; }
 774 1168  
 775      -    # Determine if numeric.
 776      -    expr "$1" + 1 > /dev/null 2>&1
 777      -    if [ $? -ge 2 ]; then
 778      -        return 1
 779      -    fi
     1169 +        while : ; do
     1170 +                get_ans "Enter the Directory Server's hostname to setup:" \
     1171 +                        "${STR[DS_HOST]}" 
     1172 +                SRV="${ANS}"
 780 1173  
 781      -    # Made it here, it's Numeric.
 782      -    return 0
     1174 +                # Ping server to see if alive.  If reachable break out of loop
     1175 +                if [[ ${OS} == 'SunOS' ]]; then
     1176 +                        ${PING} "${SRV}" 3 >/dev/null 2>&1 && break
     1177 +                else
     1178 +                        # assume Linux
     1179 +                        ${PING} -W 3 "${SRV}" >/dev/null 2>&1 && break
     1180 +                fi
     1181 +                Log.warn "Server '${SRV}' is invalid or unreachable"
     1182 +        done
     1183 +        STR[DS_HOST]="${SRV}"
     1184 +
     1185 +        # Set CON_ARGS since values might have changed
     1186 +        CON_ARGS="-h ${SRV} -p ${INT[DS_PORT]}"
 783 1187  }
 784 1188  
     1189 +Man.addFunc get_ids_port '' '[+NAME?get_ids_port - Prompt for DS port number.]
     1190 +[+DESCRIPTION?Ask the user for the DS port number and host, store it into \bINT[DS_PORT]]\b, \bSTR[DS_HOST]]\b and adjust \bCON_ARGS\b.]
     1191 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage CON_ARGS ; }" '}
     1192 +[+SEE ALSO?\bget_number()\b, \bget_ids_server()\b, \bldapsearch\b(1).]
     1193 +\n\n\aarg\a'
     1194 +function get_ids_port {
     1195 +        typeset ASK='Enter the port number for the directory server (h=help):'
     1196 +        typeset HELP='port_help' KEY='DS_PORT'
 785 1197  
 786      -#
 787      -# not_numeric(): Reverses the return values of is_numeric.  Useful
 788      -#                 for if and while statements that want to test for
 789      -#                 non-numeric data.
 790      -#    0 = NOT Numeric
 791      -#    1 = Numeric
 792      -#
 793      -not_numeric()
 794      -{
 795      -    is_numeric $1
 796      -    if [ $? -eq 0 ]; then
 797      -       return 1
 798      -    else
 799      -       return 0
 800      -    fi
     1198 +        integer PORT
     1199 +        while : ; do
     1200 +                # Enter port number
     1201 +                get_number "${ASK}" ${INT[${KEY}]} "${HELP}"
     1202 +                PORT=${ANS}
     1203 +                # Do a simple search to check hostname and LDAP port number
     1204 +                if [[ -z $1 ]]; then
     1205 +                        if ${LDAPSEARCH} -h ${STR[DS_HOST]} -p ${PORT} -b '' \
     1206 +                                -s base 'objectclass=*' > /dev/null 2>&1
     1207 +                        then
     1208 +                                break
     1209 +                        fi
     1210 +                        Log.warn "Invalid host or port '${STR[DS_HOST]}:${PORT}'"
     1211 +                        get_ids_server
     1212 +                else
     1213 +                        break
     1214 +                fi
     1215 +        done
     1216 +        INT[${KEY}]=${PORT}
     1217 +        [[ -n $1 ]] && return
     1218 +
     1219 +        # Set CON_ARGS since values might have changed
     1220 +        CON_ARGS="-h ${STR[DS_HOST]} -p ${PORT}"
 801 1221  }
 802 1222  
     1223 +Man.addFunc chk_ids_version '' '[+NAME?chk_ids_version - Read the DS version info.]
     1224 +[+DESCRIPTION?Query the DS for version info and store it into \bTMP[DS_INFO]]\b as "ProductName MajorVersionNum MinorVersionNum". If the DS is OpenDS or OpenDJ \bTMPF[IS_OPENDJ]]\b gets set to 1, 0 otherwise. If the DS seems to be unsupported by this script, an appropriate message gets stored into \bTMP[WARN]]\b.]
     1225 +[+RETURN VALUES]{
     1226 +        [+0?on success.]
     1227 +        [+>= 66?on fatal error (got no info).]
     1228 +}
     1229 +[+SEE ALSO?\bldapsearch\b(1).]
     1230 +'
     1231 +function chk_ids_version {
     1232 +        typeset PROD='' X LINE
     1233 +        typeset  -a SPLIT=( )
     1234 +        integer MAJOR=0 MINOR=0
     1235 +    ${LDAPSEARCH} ${CON_ARGS} -b cn=monitor -s base 'objectclass=*' \
     1236 +                2>/dev/null | \
     1237 +        while read LINE ; do
     1238 +                if [[ ${LINE:0:14} == 'vendorVersion=' ]]; then
     1239 +                        # OpenD*
     1240 +                        X=${LINE:14}
     1241 +                        X=${X//Directory Server }               # usually <= 2.3.x
     1242 +                        PROD=${X%% *}
     1243 +                        SPLIT=( ${.sh.match//./ } )
     1244 +                        MAJOR=${SPLIT[0]}
     1245 +                        MINOR=${SPLIT[1]}
     1246 +                        break
     1247 +                elif [[ ${LINE:0:8} == 'version=' ]]; then
     1248 +                        # *DSEE
     1249 +                        X=${LINE:8}
     1250 +                        PROD=${X%%/*}
     1251 +                        X=${.sh.match#/}
     1252 +                        SPLIT=( ${X//./ } )
     1253 +                        MAJOR=${SPLIT[0]}
     1254 +                        MINOR=${SPLIT[1]}
     1255 +                        break
     1256 +                fi
     1257 +        done
     1258 +        if [[ -z ${PROD} ]] || (( MAJOR == 0 )); then
     1259 +                Log.fatal 'Can not determine the version number of the DS'
     1260 +                return 66
     1261 +        fi
 803 1262  
 804      -#
 805      -# is_negative(): Tells is a Numeric value is less than zero.
 806      -#    0 = Negative Numeric
 807      -#    1 = Positive Numeric
 808      -#    2 = NOT Numeric
 809      -#
 810      -is_negative()
 811      -{
 812      -    # Check for parameter.
 813      -    if [ $# -ne 1 ]; then
 814      -        return 1
 815      -    fi
     1263 +        TMP[DS_INFO]="${PROD} ${MAJOR} ${MINOR}"
 816 1264  
 817      -    # Determine if numeric.  Can't use expr because -0 is 
 818      -    # considered positive??
 819      -    if is_numeric $1; then
 820      -        case "$1" in 
 821      -            -*)  return 0 ;;   # Negative Numeric
 822      -            *)   return 1 ;;   # Positive Numeric
 823      -        esac
 824      -    else
 825      -        return 2
     1265 +        # for easier maintainance we don't put it into a single expr
     1266 +        X=''
     1267 +        if [[ ${PROD} == 'OpenDS' || ${PROD} == 'OpenDJ' ]]; then
     1268 +                TMPF[IS_OPENDJ]=1
     1269 +                (( MAJOR < 2 )) && X='1'
     1270 +        elif (( MAJOR < 5 || (7 < MAJOR && MAJOR < 11) )); then
     1271 +                # not a supported DSEE version
     1272 +                TMPF[IS_OPENDJ]=0
     1273 +                X='1'
 826 1274      fi
     1275 +        if [[ -n ${X} ]]; then
     1276 +                TMP[WARN]="$PROG only works with DSEE version 5.x, 6.x, 7.x, "
     1277 +                TMP[WARN]+='ODSEE 11g and OpenDS/OpenDJ 2.x'
     1278 +                Log.warn "${TMP[WARN]}"
     1279 +        fi
     1280 +        Log.printMarker
     1281 +    Log.info "Detected DS:  ${PROD} ${MAJOR}.${MINOR}"
     1282 +        Log.printMarker
     1283 +        return 0
 827 1284  }
 828 1285  
 829      -
 830      -#
 831      -# check_domainname(): check validity of a domain name.  Currently we check
 832      -#                     that it has at least two components.
 833      -#               $1  the domain name to be checked
 834      -#
 835      -check_domainname()
 836      -{
 837      -    if [ ! -z "$1" ]
 838      -    then
 839      -        t=`expr "$1" : '[^.]\{1,\}[.][^.]\{1,\}'`
 840      -        if [ "$t" = 0 ]
 841      -        then
 842      -            return 1
 843      -        fi
 844      -    fi
 845      -    return 0
     1286 +Man.addFunc get_dirmgr_dn '' '[+NAME?get_dirmgr_dn - get the directory manger DN.]
     1287 +[+DESCRIPTION?Ask the user for the directory manger DN and store it into \bSTR[LDAP_ROOTDN]]\b and adjust \bAUTH_ARGS\b.]
     1288 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage AUTH_ARGS ; }" '}
     1289 +[+SEE ALSO?\bget_ans()\b.]
     1290 +'
     1291 +function get_dirmgr_dn {
     1292 +        get_ans 'Enter the directory manager DN:' "${STR[LDAP_ROOTDN]}"
     1293 +    STR[LDAP_ROOTDN]="${ANS}"
     1294 +        AUTH_ARGS=( '-D' "${STR[LDAP_ROOTDN]}" '-j' "${TMP[LDAP_ROOTPWF]}" )
 846 1295  }
 847 1296  
     1297 +Man.addFunc get_dirmgr_pw '' '[+NAME?get_dirmgr_pw - get the Root DN password.]
     1298 +[+DESCRIPTION?Ask the user for the Root DN (\bSTR[LDAP_ROOTDN]]\b), store it into \bSTR[LDAP_ROOTPWD]]\b as well as a temp file for later use. Finally adjust \bAUTH_ARGS\b and check, whether the changes work.]
     1299 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage AUTH_ARGS ; }" '}
     1300 +[+SEE ALSO?\bget_passwd_nochk()\b, \bsave_password()\b, \bldapsearch\b(1).]
     1301 +'
     1302 +function get_dirmgr_pw {
     1303 +        typeset RES
 848 1304  
 849      -#
 850      -# check_baseDN(): check validity of the baseDN name.
 851      -#               $1  the baseDN name to be checked
 852      -#
 853      -#     NOTE: The check_baseDN function does not catch all invalid DN's.
 854      -#           Its purpose is to reduce the number of invalid DN's to 
 855      -#           get past the input routine.  The invalid DN's will be 
 856      -#           caught by the LDAP server when they are attempted to be 
 857      -#           created.
 858      -#
 859      -check_baseDN()
 860      -{
 861      -    ck_DN=$1
 862      -    ${ECHO} "  Checking LDAP Base DN ..."
 863      -    if [ ! -z "$ck_DN" ]; then
 864      -        [ $DEBUG -eq 1 ] && ${ECHO} "Checking baseDN: $ck_DN"
 865      -        # Check for = (assignment operator)
 866      -        ${ECHO} "$ck_DN" | ${GREP} "=" > /dev/null 2>&1
 867      -        if [ $? -ne 0 ]; then
 868      -            [ $DEBUG -eq 1 ] && ${ECHO} "check_baseDN: No '=' in baseDN."
 869      -            return 1
 870      -        fi
 871      -   
 872      -        # Check all keys.
 873      -        while :
 874      -        do
 875      -            # Get first key.
 876      -            dkey=`${ECHO} $ck_DN | cut -d'=' -f1`
     1305 +        while : ; do
     1306 +                get_passwd_nochk "Enter passwd for ${STR[LDAP_ROOTDN]} :"
     1307 +                STR[LDAP_ROOTPWD]="${ANS}"      # stored for create_config_file(), only
     1308 +                save_password
     1309 +                AUTH_ARGS=( '-D' "${STR[LDAP_ROOTDN]}" '-j' "${TMP[LDAP_ROOTPWF]}" )
 877 1310  
 878      -            # Check that the key string is valid
 879      -            check_attrName $dkey
 880      -            if [ $? -ne 0 ]; then 
 881      -                [ $DEBUG -eq 1 ] && ${ECHO} "check_baseDN: invalid key=${dkey}" 
 882      -                return 1 
 883      -            fi
     1311 +                # Verify that ROOTDN and ROOTPWD are valid
     1312 +                RES=${ ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
     1313 +                        -b '' -s base 'objectclass=*' supportedLDAPVersion 2>&1 ; }
     1314 +                (( $? == 0 )) && break  # Both are valid.
 884 1315  
 885      -            [ $DEBUG -eq 1 ] && ${ECHO} "check_baseDN: valid key=${dkey}" 
 886      -
 887      -            # Remove first key from DN
 888      -            ck_DN=`${ECHO} $ck_DN | cut -s -d',' -f2-`
 889      -
 890      -            # Break loop if nothing left.
 891      -            if [ "$ck_DN" = "" ]; then
 892      -                break
 893      -            fi
 894      -        done
 895      -    fi
 896      -    return 0
     1316 +                if [[ ${RES} =~ (credential|no password) ]]; then
     1317 +                        Log.warn 'Password for Root DN is invalid'
     1318 +                else
     1319 +                        Log.warn "Root DN '${STR[LDAP_ROOTDN]}' is invalid"
     1320 +                        get_dirmgr_dn
     1321 +                fi
     1322 +    done
 897 1323  }
 898 1324  
 899      -
 900      -#
 901      -# domain_2_dc(): Convert a domain name into dc string.
 902      -#    $1  .. Domain name.
 903      -#
 904      -domain_2_dc()
 905      -{
 906      -    _DOM=$1           # Domain parameter.
 907      -    _DOM_2_DC=""      # Return value from function.
 908      -    _FIRST=1          # Flag for first time.
 909      -    
 910      -    export _DOM_2_DC  # Make visible for others.
 911      -
 912      -    # Convert "."'s to spaces for "for" loop.
 913      -    domtmp="`${ECHO} ${_DOM} | tr '.' ' '`"
 914      -    for i in $domtmp; do
 915      -        if [ $_FIRST -eq 1 ]; then 
 916      -            _DOM_2_DC="dc=${i}"
 917      -            _FIRST=0
 918      -        else
 919      -            _DOM_2_DC="${_DOM_2_DC},dc=${i}"
 920      -        fi
     1325 +Man.addFunc get_domain '' '[+NAME?get_domain - Ask user for domain to be served.]
     1326 +[+DESCRIPTION?Ask the user for the Domain that will be served by the LDAP server and store it into \bSTR[LDAP_DOMAIN]]\b.]
     1327 +[+SEE ALSO?\bget_ans()\b.]
     1328 +'
     1329 +function get_domain {
     1330 +        while : ; do
     1331 +                get_ans 'Enter the domainname to be served (h=help):' \
     1332 +                        "${STR[LDAP_DOMAIN]}"
     1333 +                case "${ANS}" in
     1334 +                        [Hh?] | help | Help) display_msg 'domain_help' ; continue ;;
     1335 +                esac
     1336 +                # check, whether it has at least 2 dot separated components
     1337 +                [[ ${ANS} =~ [^.]+\.[^.]+ ]] && break
     1338 +                Log.warn "Invalid domainname '${ANS}'"
 921 1339      done
     1340 +        STR[LDAP_DOMAIN]="${ANS}"
 922 1341  }
 923 1342  
     1343 +Man.addFunc getDSobjectclasses '' '[+NAME?getDSobjectclasses - get all DS schema objectclasses.]
     1344 +[+DESCRIPTION?Fetch all objectclasses definitions of the DS via \bcn=schema\b and cache them into \bOID2ODEF\b. Once successfully fetched, this function does nothing but return 0.]
     1345 +[+RETURN VALUES]{
     1346 +        [+0?on success.]
     1347 +        [+>0?failed to retrieve attribute definitions.]
     1348 +}
     1349 +'
     1350 +function getDSobjectclasses {
     1351 +        (( ${#OID2ODEF[@]} )) && return 0
 924 1352  
 925      -#
 926      -# is_root_user(): Check to see if logged in as root user.
 927      -#
 928      -is_root_user()
 929      -{
 930      -    case `id` in
 931      -        uid=0\(root\)*) return 0 ;;
 932      -        * )             return 1 ;;
 933      -    esac
     1353 +        typeset AT OID NAME TAIL
     1354 +        set -o pipefail
     1355 +        ${LDAPSEARCH} ${CON_ARGS} -b cn=schema -s base 'objectclass=*' \
     1356 +                objectclasses 2>/dev/null | \
     1357 +        while read AT OID NAME TAIL ; do
     1358 +                [[ ${AT} != 'objectclasses=(' ]] && continue
     1359 +                TAIL=${TAIL%%+( )$')'};
     1360 +                OID2ODEF["${OID}"]="${TAIL}"
     1361 +                :                       # always return 0
     1362 +        done
 934 1363  }
 935 1364  
     1365 +Man.addFunc getDSattributes '' '[+NAME?getDSattributes - get all DS schema attributes.]
     1366 +[+DESCRIPTION?Fetch all attribute definitions of the DS via \bcn=schema\b and cache them into \bOID2ADEF\b. Also populate the hash map \bANAME2OID\b for all the attributes definied. Once successfully fetched, this function does nothing but return 0.]
     1367 +[+RETURN VALUES]{
     1368 +        [+0?on success.]
     1369 +        [+>0?failed to retrieve attribute definitions.]
     1370 +}
     1371 +'
     1372 +function getDSattributes {
     1373 +        (( ${#ANAME2OID[@]} )) && return 0
 936 1374  
 937      -#
 938      -# parse_arg(): Parses the command line arguments and sets the 
 939      -#              appropriate variables.
 940      -#
 941      -parse_arg()
 942      -{
 943      -    while getopts "dvhi:o:" ARG
 944      -    do
 945      -        case $ARG in
 946      -            d)      DEBUG=1;;
 947      -            v)      VERB="";;
 948      -            i)      INPUT_FILE=$OPTARG;;
 949      -            o)      OUTPUT_FILE=$OPTARG;;
 950      -            \?) display_msg usage
 951      -                    exit 1;;
 952      -            *)  ${ECHO} "**ERROR: Supported option missing handler!"
 953      -                    display_msg usage
 954      -                    exit 1;;
 955      -        esac
 956      -    done
 957      -    return `expr $OPTIND - 1`
     1375 +        typeset AT OID NAME TAIL
     1376 +        typeset -l ALIAS
     1377 +        set -o pipefail
     1378 +        ${LDAPSEARCH} ${CON_ARGS} -b cn=schema -s base 'objectclass=*' \
     1379 +                attributeTypes 2>/dev/null | \
     1380 +        while read AT OID NAME TAIL ; do
     1381 +                [[ ${AT} != 'attributeTypes=(' ]] && continue
     1382 +                TAIL=${TAIL%%+( )$')'};
     1383 +                OID2ADEF["${OID}"]="${TAIL}"
     1384 +                # 'name'
     1385 +                if [[ ${TAIL:0:1} == "'" ]]; then
     1386 +                        NAME=${TAIL:1}
     1387 +                        ALIAS=${NAME%%"'"*}
     1388 +                        ANAME2OID["${ALIAS}"]="${OID}"
     1389 +                        continue
     1390 +                fi
     1391 +                # ( 'name' 'name 1' ... )
     1392 +                NAME=${TAIL%%$')'*}
     1393 +                NAME=${NAME##$'('*([[:space:]])}
     1394 +                while [[ ${NAME} == ~(E)"'"([^"'"]+)"'" ]]; do
     1395 +                        ALIAS=${.sh.match[1]}
     1396 +                        ANAME2OID["${ALIAS}"]="${OID}"
     1397 +                        NAME=${NAME:${#ALIAS}+2}
     1398 +                        NAME=${NAME#*([[:space:]])}
     1399 +                done
     1400 +                :                       # always return 0
     1401 +        done
 958 1402  }
 959 1403  
     1404 +Man.addFunc check_attrName '' '[+NAME?check_attrName - validate an attribute name.]
     1405 +[+DESCRIPTION?Check that \akey\a is a valid attribute name.]
     1406 +[+RETURN VALUES]{
     1407 +        [0?key is a valid name.]
     1408 +        [1?key is a invalid name.]
     1409 +        [66?failed to fetch attribute definitions from server.]
     1410 +}
     1411 +[+SEE ALSO?\bldapsearch\b(1).]
     1412 +\n\n\akey\a
     1413 +'
     1414 +function check_attrName {
     1415 +        typeset KEY=$1
 960 1416  
 961      -#
 962      -# init(): initializes variables and options
 963      -#
 964      -init()
 965      -{
 966      -    # General variables.
 967      -    PROG=`basename $0`  # Program name
 968      -    PID=$$              # Program ID
 969      -    VERB='> /dev/null 2>&1'     # NULL or "> /dev/null"
 970      -    ECHO="/bin/echo"    # print message on screen
 971      -    EVAL="eval"         # eval or echo
 972      -    EGREP="/usr/bin/egrep"
 973      -    GREP="/usr/bin/grep"
 974      -    DEBUG=0             # Set Debug OFF
 975      -    BACKUP=no_ldap      # backup suffix
 976      -    HOST=""             # NULL or <hostname>
 977      -    NAWK="/usr/bin/nawk"
 978      -    RM="/usr/bin/rm"
 979      -    WC="/usr/bin/wc"
 980      -    CAT="/usr/bin/cat"
 981      -    SED="/usr/bin/sed"
 982      -    MV="/usr/bin/mv"
     1417 +        if ! getDSattributes ; then
     1418 +                Log.fatal 'Unable to fetch attribute definitions from server'
     1419 +                return 66
     1420 +        fi
     1421 +        [[ -z ${KEY} ]] && return 1
     1422 +        if [[ ${KEY} =~ ^[0-9]+(\.[0-9]+)*$ ]]; then    
     1423 +                # OID value
     1424 +                [[ -n ${OID2ADEF[${KEY}]} ]] && return 0
     1425 +        else
     1426 +                # symbol. name
     1427 +                KEY=${ANAME2OID[${KEY}]}
     1428 +                # if have a mapping, than we also have a definition for it - no need
     1429 +                # to double check
     1430 +                [[ -n  ${KEY} ]] && return 0
     1431 +        fi
     1432 +        return 1
     1433 +}
 983 1434  
 984      -    DOM=""              # Set to NULL
 985      -    # If DNS domain (resolv.conf) exists use that, otherwise use domainname.
 986      -    if [ -f /etc/resolv.conf ]; then
 987      -        DOM=`/usr/xpg4/bin/grep -i -E '^domain|^search' /etc/resolv.conf \
 988      -            | awk '{ print $2 }' | tail -1`
 989      -    fi
     1435 +Man.addFunc check_baseDN '' '[+NAME?check_baseDN - check validity of the baseDN name.]
     1436 +[+DESCRIPTION?Check that \abaseDN\a is a valid base DN.]
     1437 +[+RETURN VALUES]{
     1438 +    [+0?baseDN is a valid.]
     1439 +    [+>= 1?baseDN is a invalid.]
     1440 +}
     1441 +[+SEE ALSO?\bcheck_attrName()\b.]
     1442 +[+NOTES?This function does not catch all invalid DNs. Its purpose is to reduce the number of invalid DNs to get past the input routine.  The invalid DNs will be caught by the LDAP server when they are attempted to be created.]
     1443 +\n\n\abaseDN\a
     1444 +'
     1445 +function check_baseDN {
     1446 +        # NOTE: we preserve spaces! And try to report all errors instead of just one
     1447 +    Log.info 'Checking LDAP Base DN ...'
     1448 +        [[ -z $1 ]] && return 0
 990 1449  
 991      -    # If for any reason the DOM did not get set (error'd resolv.conf) set
 992      -    # DOM to the domainname command's output.
 993      -    if [ "$DOM" = "" ]; then
 994      -        DOM=`domainname`        # domain from domainname command.
 995      -    fi
     1450 +        # NOTE: when fancy debug via trap is enabled, splitting via IFS does not
     1451 +        # work: IFS=',' PAIRS=( $1 ) - so we do it manually
 996 1452  
 997      -    STEP=1
 998      -    INTERACTIVE=1       # 0 = on, 1 = off (For input file mode)
 999      -    DEL_OLD_PROFILE=0   # 0 (default), 1 = delete old profile.
     1453 +        typeset PAIR KEY VAL TAIL="${1},"
     1454 +        typeset -A UNIQ_KEYS=( )        # avoid repeated lookup of the same attrName
     1455 +        integer ERR=0
     1456 +        while [[ -n ${TAIL} ]]; do
     1457 +                TAIL=${TAIL#*,}
     1458 +                PAIR=${.sh.match%,}
     1459 +                VAL=${PAIR#*=}
     1460 +                KEY=${.sh.match%=}
     1461 +                if [[ -z ${KEY} || -z ${VAL} ]]; then
     1462 +                        Log.warn "Invalid key=value pair '${PAIR}'"
     1463 +                        (( ERR++ ))
     1464 +                        continue
     1465 +                fi
     1466 +                UNIQ_KEYS[${KEY}]=1
     1467 +        done
1000 1468  
1001      -    # idsconfig specific variables.
1002      -    INPUT_FILE=""
1003      -    OUTPUT_FILE=""
1004      -    LDAP_ENABLE_SHADOW_UPDATE="FALSE"
1005      -    NEED_PROXY=0        # 0 = No Proxy,    1 = Create Proxy.
1006      -    NEED_ADMIN=0        # 0 = No Admin,    1 = Create Admin.
1007      -    NEED_HOSTACL=0      # 0 = No Host ACL, 1 = Create Host ACL.
1008      -    EXISTING_PROFILE=0
1009      -    LDAP_PROXYAGENT=""
1010      -    LDAP_ADMINDN=""
1011      -    LDAP_SUFFIX=""
1012      -    LDAP_DOMAIN=$DOM    # domainname on Server (default value)
1013      -    GEN_CMD=""
1014      -    PROXY_ACI_NAME="LDAP_Naming_Services_proxy_password_read"
     1469 +        for KEY in "${!UNIQ_KEYS[@]}" ; do
     1470 +                if ! check_attrName "${KEY}" ; then
     1471 +                        Log.warn "Unknown attribute name '${KEY}'"
     1472 +                fi
     1473 +        done
     1474 +        return ${ERR}
     1475 +}
1015 1476  
1016      -    # LDAP COMMANDS
1017      -    LDAPSEARCH="/bin/ldapsearch -r"
1018      -    LDAPMODIFY=/bin/ldapmodify
1019      -    LDAPADD=/bin/ldapadd
1020      -    LDAPDELETE=/bin/ldapdelete
1021      -    LDAP_GEN_PROFILE=/usr/sbin/ldap_gen_profile
     1477 +Man.addFunc discover_serv_suffix '' '[+NAME?discover_serv_suffix - query the DS to find suffixes available.]
     1478 +[+DESCRIPTION?Query the DS to find suffixes available. All suffixes found are stored into the variable \avname\a which must be an indexed array.]
     1479 +[+RETURN VALUES]{
     1480 +        [+0?at least one suffix was found.]
     1481 +        [+1?no suffix found.]
     1482 +}
     1483 +[+SEE ALSO?\bldapsearch\b(1).]
     1484 +\n\n\avname\a
     1485 +'
     1486 +function discover_serv_suffix {
     1487 +        typeset LINE
     1488 +        integer NUM_TOP=0
     1489 +        typeset -n DST=$1
     1490 +        DST=( ); unset DST[0]
1022 1491  
1023      -    # iDS specific information
1024      -    IDS_SERVER=""
1025      -    IDS_PORT=389
1026      -    NEED_TIME=0
1027      -    NEED_SIZE=0
1028      -    NEED_SRVAUTH_PAM=0
1029      -    NEED_SRVAUTH_KEY=0
1030      -    NEED_SRVAUTH_CMD=0
1031      -    IDS_TIMELIMIT=""
1032      -    IDS_SIZELIMIT=""
     1492 +        # Search the server for the TOP of the TREE. Usually none for virgin DS
     1493 +        ${LDAPSEARCH} ${CON_ARGS} -b '' -s base 'objectclass=*' namingContexts \
     1494 +                2>/dev/null | \
     1495 +        while read LINE ; do
     1496 +                if [[ -n ${LINE} && ${LINE} != ~(Ei)NetscapeRoot ]]; then
     1497 +                        (( NUM_TOP++ ))
     1498 +                        DST+=( "${LINE#*=}\n" )         # strip off '^namingContexts='
     1499 +                fi
     1500 +        done
1033 1501  
1034      -    # LDAP PROFILE related defaults
1035      -    LDAP_ROOTDN="cn=Directory Manager"   # Provide common default.
1036      -    LDAP_ROOTPWD=""                      # NULL passwd as default (i.e. invalid)
1037      -    LDAP_PROFILE_NAME="default"
1038      -    LDAP_BASEDN=""
1039      -    LDAP_SERVER_LIST=""
1040      -    LDAP_AUTHMETHOD=""
1041      -    LDAP_FOLLOWREF="FALSE"
1042      -    NEED_CRYPT=""
1043      -    LDAP_SEARCH_SCOPE="one"
1044      -    LDAP_SRV_AUTHMETHOD_PAM=""
1045      -    LDAP_SRV_AUTHMETHOD_KEY=""
1046      -    LDAP_SRV_AUTHMETHOD_CMD=""
1047      -    LDAP_SEARCH_TIME_LIMIT=30
1048      -    LDAP_PREF_SRVLIST=""
1049      -    LDAP_PROFILE_TTL=43200
1050      -    LDAP_CRED_LEVEL="proxy"
1051      -    LDAP_BIND_LIMIT=10
     1502 +        if (( NUM_TOP == 0 )); then
     1503 +                Log.verbose 'No suffix found in LDAP tree'
     1504 +                return 1
     1505 +        fi
1052 1506  
1053      -    # Prevent new files from being read by group or others.
1054      -    umask 077
1055      -
1056      -    # Service Search Descriptors
1057      -    LDAP_SERV_SRCH_DES=""
1058      -
1059      -    # Set and create TMPDIR.
1060      -    TMPDIR="/tmp/idsconfig.${PID}"
1061      -    if mkdir -m 700 ${TMPDIR}
1062      -    then
1063      -        # Cleanup on exit.
1064      -        trap 'rm -rf ${TMPDIR}; /usr/bin/stty echo; exit' 1 2 3 6 15
1065      -    else
1066      -        echo "ERROR: unable to create a safe temporary directory."
1067      -        exit 1
1068      -    fi
1069      -    LDAP_ROOTPWF=${TMPDIR}/rootPWD
1070      -
1071      -    # Set the SSD file name after setting TMPDIR.
1072      -    SSD_FILE=${TMPDIR}/ssd_list
1073      -
1074      -    # GSSAPI setup
1075      -    GSSAPI_ENABLE=0
1076      -    LDAP_KRB_REALM=""
1077      -    SCHEMA_UPDATED=0
1078      -    
1079      -    export DEBUG VERB ECHO EVAL EGREP GREP STEP TMPDIR
1080      -    export IDS_SERVER IDS_PORT LDAP_ROOTDN LDAP_ROOTPWD LDAP_SERVER_LIST 
1081      -    export LDAP_BASEDN LDAP_ROOTPWF
1082      -    export LDAP_DOMAIN LDAP_SUFFIX LDAP_PROXYAGENT LDAP_PROXYAGENT_CRED
1083      -    export NEED_PROXY
1084      -    export LDAP_ENABLE_SHADOW_UPDATE LDAP_ADMINDN LDAP_ADMIN_CRED
1085      -    export NEED_ADMIN NEED_HOSTACL EXISTING_PROFILE
1086      -    export LDAP_PROFILE_NAME LDAP_BASEDN LDAP_SERVER_LIST 
1087      -    export LDAP_AUTHMETHOD LDAP_FOLLOWREF LDAP_SEARCH_SCOPE LDAP_SEARCH_TIME_LIMIT
1088      -    export LDAP_PREF_SRVLIST LDAP_PROFILE_TTL LDAP_CRED_LEVEL LDAP_BIND_LIMIT
1089      -    export NEED_SRVAUTH_PAM NEED_SRVAUTH_KEY NEED_SRVAUTH_CMD
1090      -    export LDAP_SRV_AUTHMETHOD_PAM LDAP_SRV_AUTHMETHOD_KEY LDAP_SRV_AUTHMETHOD_CMD
1091      -    export LDAP_SERV_SRCH_DES SSD_FILE
1092      -    export GEN_CMD GSSAPI_ENABLE LDAP_KRB_REALM SCHEMA_UPDATED
     1507 +        Log.verbose "LDAP_SUFFIX_LIST = ${DST[@]}"
     1508 +        return 0
1093 1509  }
1094 1510  
1095      -
1096      -#
1097      -# disp_full_debug(): List of all debug variables usually interested in.
1098      -#                    Grouped to avoid MASSIVE code duplication.
1099      -#
1100      -disp_full_debug()
1101      -{
1102      -    [ $DEBUG -eq 1 ] && ${ECHO} "  IDS_SERVER = $IDS_SERVER"
1103      -    [ $DEBUG -eq 1 ] && ${ECHO} "  IDS_PORT = $IDS_PORT"
1104      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_ROOTDN = $LDAP_ROOTDN"
1105      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_ROOTPWD = $LDAP_ROOTPWD"
1106      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_DOMAIN = $LDAP_DOMAIN"
1107      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SUFFIX = $LDAP_SUFFIX"
1108      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_BASEDN = $LDAP_BASEDN"
1109      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_PROFILE_NAME = $LDAP_PROFILE_NAME"
1110      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SERVER_LIST = $LDAP_SERVER_LIST"
1111      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_PREF_SRVLIST = $LDAP_PREF_SRVLIST"
1112      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SEARCH_SCOPE = $LDAP_SEARCH_SCOPE"
1113      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_CRED_LEVEL = $LDAP_CRED_LEVEL"
1114      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_AUTHMETHOD = $LDAP_AUTHMETHOD"
1115      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_FOLLOWREF = $LDAP_FOLLOWREF"
1116      -    [ $DEBUG -eq 1 ] && ${ECHO} "  IDS_TIMELIMIT = $IDS_TIMELIMIT"
1117      -    [ $DEBUG -eq 1 ] && ${ECHO} "  IDS_SIZELIMIT = $IDS_SIZELIMIT"
1118      -    [ $DEBUG -eq 1 ] && ${ECHO} "  NEED_CRYPT = $NEED_CRYPT"
1119      -    [ $DEBUG -eq 1 ] && ${ECHO} "  NEED_SRVAUTH_PAM = $NEED_SRVAUTH_PAM"
1120      -    [ $DEBUG -eq 1 ] && ${ECHO} "  NEED_SRVAUTH_KEY = $NEED_SRVAUTH_KEY"
1121      -    [ $DEBUG -eq 1 ] && ${ECHO} "  NEED_SRVAUTH_CMD = $NEED_SRVAUTH_CMD"
1122      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SRV_AUTHMETHOD_PAM = $LDAP_SRV_AUTHMETHOD_PAM"
1123      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SRV_AUTHMETHOD_KEY = $LDAP_SRV_AUTHMETHOD_KEY"
1124      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SRV_AUTHMETHOD_CMD = $LDAP_SRV_AUTHMETHOD_CMD"
1125      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SEARCH_TIME_LIMIT = $LDAP_SEARCH_TIME_LIMIT"
1126      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_PROFILE_TTL = $LDAP_PROFILE_TTL"
1127      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_BIND_LIMIT = $LDAP_BIND_LIMIT"
1128      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_ENABLE_SHADOW_UPDATE = $LDAP_ENABLE_SHADOW_UPDATE"
1129      -
1130      -    # Only display proxy stuff if needed.
1131      -    [ $DEBUG -eq 1 ] && ${ECHO} "  NEED_PROXY = $NEED_PROXY"
1132      -    if [ $NEED_PROXY -eq  1 ]; then
1133      -        [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_PROXYAGENT = $LDAP_PROXYAGENT"
1134      -        [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_PROXYAGENT_CRED = $LDAP_PROXYAGENT_CRED"
1135      -    fi
1136      -
1137      -    # Only display admin credential if needed.
1138      -    [ $DEBUG -eq 1 ] && ${ECHO} "  NEED_ADMIN = $NEED_ADMIN"
1139      -    [ $DEBUG -eq 1 ] && ${ECHO} "  NEED_HOSTACL = $NEED_HOSTACL"
1140      -    if [ $NEED_ADMIN -eq  1 ]; then
1141      -        [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_ADMINDN = $LDAP_ADMINDN"
1142      -        [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_ADMIN_CRED = $LDAP_ADMIN_CRED"
1143      -    fi
1144      -
1145      -    # Service Search Descriptors are a special case.
1146      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SERV_SRCH_DES = $LDAP_SERV_SRCH_DES"
     1511 +Man.addFunc get_backend '' '[+NAME?get_backend - get the relevant database backend for the Base DN.]
     1512 +[+DESCRIPTION?Get the relevant database backend name for the Base DN and store it into \bSTR[DS_DB]]\b.]
     1513 +[+?Prerequisite: \bSTR[LDAP_BASEDN]]\b must be set and valid.]
     1514 +[+?backend is retrieved from suffixes and subsuffixes defined under "cn=mapping tree,cn=config". The nsslapd-state attribute of these suffixes entries is filled with either Backend, Disabled or referrals related values. We only want those that have a true backend database to select the relevant backend.]
     1515 +[+RETURN VALUES]{
     1516 +        [+0?on success.]
     1517 +        [+>= 66?an fatal error occured.]
1147 1518  }
     1519 +[+SEE ALSO?\bldapsearch\b(1).]
     1520 +'
     1521 +function get_backend {
     1522 +        typeset CUR_DN=${STR[LDAP_BASEDN]} PREV_DN='' FILTER
1148 1523  
     1524 +        while [[ ${CUR_DN} != ${PREV_DN} ]]; do
     1525 +                typeset -a DB=( )
     1526 +                Log.verbose "Testing LDAP suffix: ${CUR_DN} ..."
1149 1527  
1150      -#
1151      -# load_config_file(): Loads the config file.
1152      -#
1153      -load_config_file()
1154      -{
1155      -    [ $DEBUG -eq 1 ] && ${ECHO} "In load_config_file()"
     1528 +                if (( TMPF[IS_OPENDJ] )); then
     1529 +                        FILTER='(&(&(objectclass=ds-cfg-backend)(ds-cfg-base-dn='"${CUR_DN}"
     1530 +                        FILTER+='))(objectClass=ds-cfg-local-db-backend))'
     1531 +                        ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
     1532 +                                -b 'cn=Backends,cn=config' -s one "${FILTER}" 2>/dev/null | \
     1533 +                        while read LINE ; do
     1534 +                                [[ ${LINE:0:18} == 'ds-cfg-backend-id=' && \
     1535 +                                        ${LINE: -10} != ',cn=config' ]] && DB+=( "${LINE:18}" )
     1536 +                        done
     1537 +                else
1156 1538  
1157      -    # Remove SSD lines from input file before sourcing.
1158      -    # The SSD lines must be removed because some forms of the 
1159      -    # data could cause SHELL errors.
1160      -    ${GREP} -v "LDAP_SERV_SRCH_DES=" ${INPUT_FILE} > ${TMPDIR}/inputfile.noSSD
     1539 +                        ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
     1540 +                                -b "cn=${CUR_DN},cn=mapping tree,cn=config" \
     1541 +                                -s base 'nsslapd-state=Backend' 'nsslapd-backend' 2>/dev/null |\
     1542 +                        while read LINE ; do
     1543 +                                [[ ${LINE:0:16} == 'nsslapd-backend=' ]] && DB+=( "${LINE:16}" )
     1544 +                        done
     1545 +                fi
1161 1546  
1162      -    # Source the input file. 
1163      -    . ${TMPDIR}/inputfile.noSSD
     1547 +                if (( ${#DB[@]} == 0 )); then
     1548 +                        # not a suffix, or suffix not activated; try next
     1549 +                        PREV_DN=${CUR_DN}
     1550 +                        CUR_DN="${CUR_DN#*,}"
     1551 +                elif (( ${#DB[@]} == 1 )); then
     1552 +                        break
     1553 +                else
     1554 +                        Log.fatal "More than one database is configured for '${CUR_DN}'!" \
     1555 +                                "$PROG can not configure suffixes where" \
     1556 +                                'more than one database is used for one suffix'
     1557 +                        return 66
     1558 +                fi
     1559 +        done
1164 1560  
1165      -    # If LDAP_SUFFIX is no set, try to utilize LDAP_TREETOP since older 
1166      -    # config files use LDAP_TREETOP
1167      -    LDAP_SUFFIX="${LDAP_SUFFIX:-$LDAP_TREETOP}"
     1561 +        if (( ${#DB[@]} == 0 )); then
     1562 +                # should not happen, since STR[LDAP_BASEDN] is supposed to be valid
     1563 +                Log.fatal "Could not find a valid backend for '${STR[LDAP_BASEDN]}'"
     1564 +                if (( TMPF[IS_OPENDJ] )); then
     1565 +                        Log.fatal 'Check the "Creating a New Database Backend" section in the Administration Guide'
     1566 +                fi
     1567 +                return 67
     1568 +        fi
     1569 +        STR[DS_DB]="${DB[0]}"
1168 1570  
1169      -    # Save password to temporary file.
1170      -    save_password
     1571 +        Log.verbose "DB backend '${STR[DS_DB]}' selected"
1171 1572  
1172      -    # Create the SSD file.
1173      -    create_ssd_file
     1573 +        return 0
     1574 +}
1174 1575  
1175      -    # Display FULL debugging info.
1176      -    disp_full_debug
     1576 +Man.addFunc normalizeDN '' '[+NAME?normalizeDN - normalize a [relative]] distinguished name.]
     1577 +[+DESCRIPTION?Strip off unnecessary spaces around \b,\b and \b=\b as well as at the beginning and end of the given \adn\a, optionally convert it to lower or upper case (if either \bl\b or \bu\b is given) and print it to stdout.]
     1578 +\n\n\adn\a [\bl\b|\bu\b]
     1579 +'
     1580 +function normalizeDN {
     1581 +        [[ -z $1 ]] && return
     1582 +        typeset VAL=",${1},"
     1583 +        VAL="${VAL//*( ),*( )/,}"
     1584 +        VAL="${VAL//*( )=*( )/=}"
     1585 +        if [[ $2 == 'l' ]]; then
     1586 +                typeset -l LC="${VAL}"
     1587 +                VAL="${LC}"
     1588 +        elif [[ $2 == 'u' ]]; then
     1589 +                typeset -u UC="${VAL}"
     1590 +                VAL="${UC}"
     1591 +        fi
     1592 +        print -- "${VAL:1:${#VAL}-2}"
1177 1593  }
1178 1594  
1179      -#
1180      -# save_password(): Save password to temporary file.
1181      -#
1182      -save_password()
1183      -{
1184      -    cat > ${LDAP_ROOTPWF} <<EOF
1185      -${LDAP_ROOTPWD}
1186      -EOF
     1595 +Man.addFunc check_basedn_suffix '' '[+NAME?check_basedn_suffix - check that there is an existing valid suffix to hold current base DN.]
     1596 +[+DESCRIPTION?Check that there is an existing valid suffix for \bSTR[LDAP_BASEDN]]\b. If one is found, store it into \bSTR[LDAP_SUFFIX]]\b and make a corresponding backend check.]
     1597 +[+RETURN VALUES]{
     1598 +        [+0?valid suffix found or new one should be created (\bTMPF[NEED_CREATE_SUFFIX]]\b flag actually indicates that).]
     1599 +        [+>= 66?a fatal error occured.]
1187 1600  }
     1601 +[+SEE ALSO?\bdiscover_serv_suffix()\b, \bldapsearch\b(1), \bnormalizeDN()\b, \bget_backend()\b.]
     1602 +'
     1603 +function check_basedn_suffix {
     1604 +        Log.info 'Validating LDAP Base DN and Suffix ...'
     1605 +        TMPF[NEED_CREATE_SUFFIX]=0
1188 1606  
1189      -######################################################################
1190      -# FUNCTIONS  FOR prompt_config_info() START HERE.
1191      -######################################################################
     1607 +        # check that LDAP Base DN might be added
     1608 +        typeset CUR_DN="${STR[LDAP_BASEDN]}" PREV_DN=''
1192 1609  
1193      -#
1194      -# get_ids_server(): Prompt for iDS server name.
1195      -#
1196      -get_ids_server()
1197      -{
1198      -    while :
1199      -    do
1200      -        # Prompt for server name.
1201      -        get_ans "Enter the JES Directory Server's  hostname to setup:" "$IDS_SERVER" 
1202      -        IDS_SERVER="$ANS"
     1610 +        while [[ ${CUR_DN} != ${PREV_DN} ]]; do
     1611 +                ${LDAPSEARCH} ${CON_ARGS} -b "${CUR_DN}" -s one 'objectclass=*' \
     1612 +                        >/dev/null 2>&1 && break
     1613 +                PREV_DN=${CUR_DN}
     1614 +                CUR_DN="${CUR_DN#*,}"   # remove leading component
     1615 +        done
1203 1616  
1204      -        # Ping server to see if live.  If valid break out of loop.
1205      -        ping $IDS_SERVER > /dev/null 2>&1
1206      -        if [ $? -eq 0 ]; then
1207      -            break
     1617 +        if [[ ${CUR_DN} == ${PREV_DN} ]]; then
     1618 +                Log.info "No valid suffixes were found for Base DN '${STR[LDAP_BASEDN]}'"
     1619 +                TMPF[NEED_CREATE_SUFFIX]=1
     1620 +                return 0
1208 1621          fi
1209 1622  
1210      -        # Invalid server, enter a new name.
1211      -        ${ECHO} "ERROR: Server '${IDS_SERVER}' is invalid or unreachable."
1212      -        IDS_SERVER=""
1213      -    done
     1623 +        # find out existing suffixes
     1624 +        typeset -a SUFFIXES=( )
     1625 +        discover_serv_suffix SUFFIXES
1214 1626  
1215      -    # Set SERVER_ARGS and LDAP_ARGS since values might of changed.
1216      -    SERVER_ARGS="-h ${IDS_SERVER} -p ${IDS_PORT}"
1217      -    LDAP_ARGS="${SERVER_ARGS} ${AUTH_ARGS}"
1218      -    export SERVER_ARGS
     1627 +        # Now looking for relevant suffix for this entry (using lower case - LC).
     1628 +        # STR[LDAP_SUFFIX] will then be used to add necessary base objects via
     1629 +        # add_base_objects().
     1630 +        typeset LC_DN=,${ normalizeDN "${CUR_DN}" l ; }
     1631 +        typeset SFX LC_SFX
     1632 +        for SFX in "${SUFFIXES[@]}" ; do
     1633 +                Log.verbose "Testing suffix: ${SFX} ..."
     1634 +                # LC_DN ends with ,SFX ?
     1635 +            LC_SFX=,${ normalizeDN "${SFX}" l ; }
     1636 +                if [[ ${LC_DN: -${#LC_SFX}} == ${LC_SFX} ]]; then
     1637 +                        STR[LDAP_SUFFIX]="${SFX}"
     1638 +                        break
     1639 +                fi
     1640 +        done
1219 1641  
1220      -}
1221      -
1222      -#
1223      -# get_ids_port(): Prompt for iDS port number.
1224      -#
1225      -get_ids_port()
1226      -{
1227      -    # Get a valid iDS port number.
1228      -    while :
1229      -    do
1230      -        # Enter port number.
1231      -        get_number "Enter the port number for iDS (h=help):" "$IDS_PORT" "port_help"
1232      -        IDS_PORT=$ANS
1233      -        # Do a simple search to check hostname and port number.
1234      -        # If search returns SUCCESS, break out, host and port must
1235      -        # be valid.
1236      -        ${LDAPSEARCH} -h ${IDS_SERVER} -p ${IDS_PORT} -b "" -s base "objectclass=*" > /dev/null 2>&1
1237      -        if [ $? -eq 0 ]; then
1238      -            break
     1642 +        if [[ -z ${STR[LDAP_SUFFIX]} ]]; then
     1643 +                # should not happen, since we found the entry
     1644 +                Log.fatal "Could not find a valid suffix for '${STR[LDAP_BASEDN]}'"
     1645 +            return 66
1239 1646          fi
1240 1647          
1241      -        # Invalid host/port pair, Re-enter.
1242      -        ${ECHO} "ERROR: Invalid host or port: ${IDS_SERVER}:${IDS_PORT}, Please re-enter!"
1243      -        get_ids_server
1244      -    done
     1648 +        # Getting relevant database (backend)
     1649 +        # DS_DB will then be used to create indexes.
     1650 +        get_backend || return 67
1245 1651  
1246      -    # Set SERVER_ARGS and LDAP_ARGS since values might of changed.
1247      -    SERVER_ARGS="-h ${IDS_SERVER} -p ${IDS_PORT}"
1248      -    LDAP_ARGS="${SERVER_ARGS} ${AUTH_ARGS}"
1249      -    export SERVER_ARGS
     1652 +        return 0
1250 1653  }
1251 1654  
     1655 +Man.addFunc get_objectclass '' '[+NAME?get_objectclass - get the objectclass for the given attribute name.]
     1656 +[+DESCRIPTION?Get the objectclass for the given attribute name \aattrName\a and print it to stdout. Right now ou, dc, o, and c and related aliases/OIDs are supported, only. For all others nothing will be printed.]
     1657 +[+NOTES?An attribute name can be valid but still we might not be able to determine the objectclass from the table. In such cases, the user needs to create the necessary object(s).]
     1658 +\n\n\aattrName\a
     1659 +'
     1660 +function get_objectclass {
     1661 +    typeset -l ANAME="$1"
1252 1662  
1253      -#
1254      -# chk_ids_version(): Read the slapd config file and set variables
1255      -#
1256      -chk_ids_version() 
1257      -{
1258      -    [ $DEBUG -eq 1 ] && ${ECHO} "In chk_ids_version()"
     1663 +        case "${ANAME}" in
     1664 +                ou | organizationalunitname | 2.5.4.11)
     1665 +                        print 'organizationalUnit'
     1666 +                        ;;
     1667 +                dc | domaincomponent | 0.9.2342.19200300.100.1.25)
     1668 +                        print 'domain'
     1669 +                        ;;
     1670 +                o | organizationname | 2.5.4.10)
     1671 +                        print 'organization'
     1672 +                        ;;
     1673 +                c | countryname | 2.5.4.6)
     1674 +                        print 'country'
     1675 +                        ;;
     1676 +        esac
     1677 +}
1259 1678  
1260      -    # check iDS version number.
1261      -    eval "${LDAPSEARCH} ${SERVER_ARGS} -b cn=monitor -s base \"objectclass=*\" version | ${GREP} \"^version=\" | cut -f2 -d'/' | cut -f1 -d' ' > ${TMPDIR}/checkDSver 2>&1"
1262      -    if [ $? -ne 0 ]; then
1263      -        ${ECHO} "ERROR: Can not determine the version number of iDS!"
1264      -        exit 1
1265      -    fi
1266      -    IDS_VER=`cat ${TMPDIR}/checkDSver`
1267      -    IDS_MAJVER=`${ECHO} ${IDS_VER} | cut -f1 -d.`
1268      -    IDS_MINVER=`${ECHO} ${IDS_VER} | cut -f2 -d.`
1269      -    case "${IDS_MAJVER}" in
1270      -        5|6|7)  : ;;
1271      -        *)   ${ECHO} "ERROR: $PROG only works with JES DS version 5.x, 6.x or 7.x, not ${IDS_VER}."; exit 1;;
1272      -    esac
1273      -
1274      -    if [ $DEBUG -eq 1 ]; then
1275      -        ${ECHO} "  IDS_MAJVER = $IDS_MAJVER"
1276      -        ${ECHO} "  IDS_MINVER = $IDS_MINVER"
1277      -    fi
     1679 +function checkSuffixRDN {
     1680 +        typeset RDN="${STR[LDAP_SUFFIX]%%,*}"
     1681 +        TMP[SUFFIX_VAL]="${RDN#*=}"
     1682 +        TMP[SUFFIX_ATT]="${.sh.match%=}"
     1683 +        
     1684 +        # find out an objectclass for suffix entry if it is not defined yet
     1685 +        TMP[SUFFIX_OBJ]=${ get_objectclass "${TMP[SUFFIX_ATT]}" ; }
     1686 +        if [[ -z ${TMP[SUFFIX_OBJ]} ]]; then
     1687 +                Log.fatal 'Unable to find an objectclass for' "'${TMP[SUFFIX_ATT]}'" \
     1688 +                        'attribute'
     1689 +                return 1
     1690 +        fi
     1691 +        return 0
1278 1692  }
1279 1693  
1280      -
1281      -#
1282      -# get_dirmgr_dn(): Get the directory manger DN.
1283      -#
1284      -get_dirmgr_dn()
1285      -{
1286      -    get_ans "Enter the directory manager DN:" "$LDAP_ROOTDN"
1287      -    LDAP_ROOTDN=$ANS
1288      -
1289      -    # Update ENV variables using DN.
1290      -    AUTH_ARGS="-D \"${LDAP_ROOTDN}\" -j ${LDAP_ROOTPWF}"
1291      -    LDAP_ARGS="${SERVER_ARGS} ${AUTH_ARGS}"
1292      -    export AUTH_ARGS LDAP_ARGS
     1694 +Man.addFunc prep_create_sfx_entry '' '[+NAME?prep_create_sfx_entry - prepare for the suffix entry creation.]
     1695 +[+DESCRIPTION?Prepare suffix entry creation based on \bSTR[LDAP_BASEDN|LDAP_SUFFIX]]\b and \bTMP[SUFFIX_OBJ]]\b. If the latter are unset (no config file read), set them to defaults depending on the baseDN. Finally check, whether the suffix entry already exists and if so check for consistency with the current config. This function sets:]{
     1696 +        [+TMPF[NEED_CREATE_BACKEND]]?0 .. backend already exists. 1 .. create a backend.]
     1697 +        [+TMP[SUFFIX_ATT]]?The attribute name of the leading RDN of the suffix (ID).]
     1698 +        [+TMP[SUFFIX_VAL]]?The attribute value of the leading RDN of the suffix (ID).]
1293 1699  }
     1700 +[+RETURN VALUES]{
     1701 +        [+0?on success.]
     1702 +        [+1?an attribute/consistence related error occured.]
     1703 +        [+>= 66?a fatal error occured.]
     1704 +}
     1705 +[+SEE ALSO?\bnormalizeDN()\b, \bdisplay_msg()\b, \badd_suffix()\b, \bldapsearch\b(1)]
     1706 +' 
     1707 +function prep_create_sfx_entry {
     1708 +        # check whether suffix corresponds to base dn (i.e. baseDN ends with suffix)
     1709 +        typeset X=,${ normalizeDN "${STR[LDAP_BASEDN]}" l ; }
     1710 +        typeset SFX=,${STR[LDAP_SUFFIX]}
     1711 +        if [[ ${X: -${#SFX}} != ${SFX} ]]; then
     1712 +                Log.warn "Sorry, suffix '${STR[LDAP_SUFFIX]}' is not suitable for" \
     1713 +                        "Base DN '${STR[LDAP_BASEDN]}'"
     1714 +                return 1
     1715 +        fi
1294 1716  
     1717 +        checkSuffixRDN || return 66
     1718 +        Log.verbose "Suffix entry object: '${TMP[SUFFIX_OBJ]}'"
1295 1719  
1296      -#
1297      -# get_dirmgr_pw(): Get the Root DN passwd. (Root DN found in slapd.conf)
1298      -#
1299      -get_dirmgr_pw()
1300      -{
1301      -    while :
1302      -    do
1303      -        # Get passwd.
1304      -        get_passwd_nochk "Enter passwd for ${LDAP_ROOTDN} :" 
1305      -        LDAP_ROOTPWD=$ANS
     1720 +        TMPF[NEED_CREATE_BACKEND]=0
1306 1721  
1307      -        # Store password in file.
1308      -        save_password
1309      -
1310      -        # Update ENV variables using DN's PW.
1311      -        AUTH_ARGS="-D \"${LDAP_ROOTDN}\" -j ${LDAP_ROOTPWF}"
1312      -        LDAP_ARGS="${SERVER_ARGS} ${AUTH_ARGS}"
1313      -        export AUTH_ARGS LDAP_ARGS
1314      -
1315      -        # Verify that ROOTDN and ROOTPWD are valid.
1316      -        eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"\" -s base \"objectclass=*\" > ${TMPDIR}/checkDN 2>&1"
1317      -        if [ $? -ne 0 ]; then
1318      -            eval "${GREP} credential ${TMPDIR}/checkDN ${VERB}"
1319      -            if [ $? -eq 0 ]; then
1320      -                ${ECHO} "ERROR: Root DN passwd is invalid."
1321      -            else
1322      -                ${ECHO} "ERROR: Invalid Root DN <${LDAP_ROOTDN}>."
1323      -                get_dirmgr_dn
1324      -            fi
     1722 +        if (( TMPF[IS_OPENDJ] )); then
     1723 +                # 1st just check, whether any backend matches the suffix
     1724 +                typeset FILTER='(&(objectClass=ds-cfg-local-db-backend)'
     1725 +                FILTER+="(|(ds-cfg-base-dn=${STR[LDAP_SUFFIX]})"
     1726 +                FILTER+="(ds-cfg-base-dn=*,${STR[LDAP_SUFFIX]})))"
     1727 +                X=${ ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
     1728 +                        -b 'cn=Backends,cn=config' -s one "${FILTER}" 2>/dev/null ; }
     1729 +                if [[ -n ${X} ]]; then
     1730 +                        Log.verbose 'Suffix backend already exists'
     1731 +                        get_backend || return 66 
     1732 +                        return 0
     1733 +                fi
1325 1734          else
1326      -            break         # Both are valid.
     1735 +                # DSEE: check the suffix mapping tree ...
     1736 +                # If mapping exists, suffix should work, otherwise DSEE inconsistent
     1737 +                # NOTE: -b 'cn=mapping tree,cn=config' -s one 'cn=\"$1\"' won't work
     1738 +                #       in case of 'cn' value in LDAP is not quoted by '"',
     1739 +                #       -b 'cn=\"$1\",cn=mapping tree,cn=config' works in all cases
     1740 +                if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
     1741 +                        -b "cn=\"${STR[LDAP_SUFFIX]}\",cn=mapping tree,cn=config" \
     1742 +                        -s base 'objectclass=*' dn 2>/dev/null
     1743 +                then
     1744 +                        Log.verbose 'Suffix mapping already exists'
     1745 +                        get_backend || return 66 
     1746 +                        return 0
     1747 +                fi
     1748 +
     1749 +                # no suffix mapping, just in case check ldbm backends consistency -
     1750 +                # there are must be NO any databases pointing to STR[LDAP_SUFFIX] 
     1751 +                X=${ ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
     1752 +                        -b 'cn=ldbm database,cn=plugins,cn=config' \
     1753 +                        -s one "nsslapd-suffix=${STR[LDAP_SUFFIX]}" dn 2>/dev/null ; }
     1754 +                if [[ -n ${X} ]]; then
     1755 +                        Log.warn 'Sorry, there is no suffix mapping for' \
     1756 +                                "'${STR[LDAP_SUFFIX]}', while ldbm database exists, server" \
     1757 +                                'configuration needs to be fixed manually, look at cn=mapping' \
     1758 +                                'tree,cn=config and cn=ldbm database,cn=plugins,cn=config'
     1759 +                        return 1
     1760 +                fi
1327 1761          fi
1328      -    done
1329 1762  
1330      -
     1763 +        Log.verbose 'Backend needs to be created ...'
     1764 +        TMPF[NEED_CREATE_BACKEND]=1
     1765 +        return 0
1331 1766  }
1332 1767  
1333      -
1334      -#
1335      -# get_domain(): Get the Domain that will be served by the LDAP server.
1336      -#               $1 - Help argument.
1337      -#
1338      -get_domain()
1339      -{
1340      -    # Use LDAP_DOMAIN as default.
1341      -    get_ans "Enter the domainname to be served (h=help):" $LDAP_DOMAIN
1342      -
1343      -    # Check domainname, and have user re-enter if not valid.
1344      -    check_domainname $ANS
1345      -    while [ $? -ne 0 ]
1346      -    do
1347      -        case "$ANS" in
1348      -            [Hh] | help | Help | \?) display_msg ${1:-sorry} ;;
1349      -            * ) ${ECHO} "Invalid domainname: \"${ANS}\"."
1350      -             ;;
1351      -        esac
1352      -        get_ans "Enter domainname to be served (h=help):" $DOM
1353      -        
1354      -        check_domainname $ANS
1355      -    done
1356      -    
1357      -    # Set the domainname to valid name.
1358      -    LDAP_DOMAIN=$ANS
     1768 +Man.addFunc prep_create_sfx_backend '' '[+NAME?prep_create_sfx_backend - prepare for the suffix backend creation.]
     1769 +[+DESCRIPTION?Prepare for the suffix backend creation by checking available DBs starting with \bSTR[DS_DB]]\b. Sets \bTMP[DS_DB_AVAIL]]\b if not yet set or != \bSTR[DS_DB]]\b.]
     1770 +[+RETURN VALUES]{
     1771 +        [+0?backend db name is ok.]
     1772 +        [+1?\bSTR[DS_DB]]\b exists, so \bTMP[DS_DB_AVAIL]]\b contains available name.]
     1773 +        [+2?unable to find any available name.]
1359 1774  }
     1775 +[+SEE ALSO?\bldapsearch\b(1).]
     1776 +'
     1777 +function prep_create_sfx_backend {
     1778 +        # check if requested name available
     1779 +        [[ ${STR[DS_DB]} == ${TMP[DS_DBS_AVAIL]} ]] && return 0
1360 1780  
     1781 +        # get the list of database names start with a requested name
     1782 +        typeset -a DBS=( )
     1783 +        if (( TMPF[IS_OPENDJ] )); then
     1784 +                typeset FILTER='(&(objectclass=ds-cfg-local-db-backend)'
     1785 +                FILTER+="(ds-cfg-backend-id=${STR[DS_DB]}*))"
     1786 +                ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
     1787 +                        -b 'cn=Backends,cn=config' -s one "${FILTER}" ds-cfg-backend-id \
     1788 +                        2>/dev/null | \
     1789 +                while read LINE ; do
     1790 +                        [[ -n ${LINE} && ${LINE: -10} != ',cn=config' ]] && \
     1791 +                                DBS+=( "${LINE#ds-cfg-backend-id=}" )
     1792 +                done
     1793 +        else
     1794 +                ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
     1795 +                        -b 'cn=ldbm database,cn=plugins,cn=config' \
     1796 +                        -s one "cn=${STR[DS_DB]}*" cn 2>/dev/null | \
     1797 +                while read LINE ; do
     1798 +                        [[ -n ${LINE} && ${LINE: -10} != ',cn=config' ]] && \
     1799 +                                DBS+=( "${LINE#cn=}" )
     1800 +                done
     1801 +        fi
     1802 +        if (( ${#DBS[@]} == 0 )); then
     1803 +                # no backend name starts with STR[DS_DB]
     1804 +                TMP[DS_DBS_AVAIL]="${STR[DS_DB]}"
     1805 +                return 0
     1806 +        fi
1361 1807  
1362      -#
1363      -# get_basedn(): Query for the Base DN.
1364      -#
1365      -get_basedn()
1366      -{
1367      -    # Set the $_DOM_2_DC and assign to LDAP_BASEDN as default.
1368      -    # Then call get_basedn().  This method remakes the default
1369      -    # each time just in case the domain changed.
1370      -    domain_2_dc $LDAP_DOMAIN
1371      -    LDAP_BASEDN=$_DOM_2_DC
1372      -
1373      -    # Get Base DN.
1374      -    while :
1375      -    do
1376      -        get_ans_req "Enter LDAP Base DN (h=help):" "${_DOM_2_DC}"
1377      -        check_baseDN "$ANS"
1378      -        while [ $? -ne 0 ]
1379      -        do
1380      -            case "$ANS" in
1381      -                [Hh] | help | Help | \?) display_msg basedn_help ;;
1382      -                * ) ${ECHO} "Invalid base DN: \"${ANS}\"."
1383      -                ;;
1384      -            esac
1385      -
1386      -            # Re-Enter the BaseDN
1387      -            get_ans_req "Enter LDAP Base DN (h=help):" "${_DOM_2_DC}"
1388      -            check_baseDN "$ANS"
     1808 +        # find a non-existing db name based on a requested name
     1809 +        integer I FOUND
     1810 +        typeset -l NAME DB
     1811 +        for (( I=0 ; I < 10; I++ )); do
     1812 +                (( I )) && NAME="${STR[DS_DB]}${I}" || NAME="${STR[DS_DB]}"
     1813 +                FOUND=0
     1814 +                for DB in "${DBS[@]}" ; do
     1815 +                        [[ ${DB} == ${NAME} ]] && FOUND=1 && break
     1816 +                done
     1817 +                if (( ! FOUND )); then
     1818 +                        if (( I == 0 )); then
     1819 +                                TMP[DS_DBS_AVAIL]="${STR[DS_DB]}"
     1820 +                                return 0        # requested name is available
     1821 +                        fi
     1822 +                        TMP[DS_DBS_AVAIL]="${STR[DS_DB]}${I}"
     1823 +                        break
     1824 +                fi
1389 1825          done
1390 1826  
1391      -        # Set base DN and check its suffix
1392      -        LDAP_BASEDN=${ANS}
1393      -        check_basedn_suffix ||
1394      -        {
1395      -                cleanup
1396      -                exit 1
1397      -        }
     1827 +    if [[ -n ${TMP[DS_DBS_AVAIL]} ]]; then
     1828 +                Log.warn "Database backend '${STR[DS_DB]}' already exists," \
     1829 +                        "however '${TMP[DS_DBS_AVAIL]}' is available"
     1830 +                return 1
     1831 +        fi
1398 1832  
1399      -        # suffix may need to be created, in that case get suffix from user
1400      -        [ -n "${NEED_CREATE_SUFFIX}" ] &&
1401      -        {
1402      -                get_suffix || continue
1403      -        }
1404      -
1405      -        # suffix is ok, break out of the base dn inquire loop
1406      -        break
1407      -    done
     1833 +        Log.warn 'Unable to find any available database backend close to' \
     1834 +                "'${STR[DS_DB]}'"
     1835 +    return 2
1408 1836  }
1409 1837  
1410      -#
1411      -# get_want_shadow_update(): Ask user if want to enable shadow update?
1412      -#
1413      -get_want_shadow_update()
1414      -{
1415      -    MSG="Do you want to enable shadow update (y/n/h)?"
1416      -    get_confirm "$MSG" "n" "enable_shadow_update_help"
1417      -    if [ $? -eq 1 ]; then
1418      -        LDAP_ENABLE_SHADOW_UPDATE="TRUE"
1419      -    else
1420      -        LDAP_ENABLE_SHADOW_UPDATE="FALSE"
1421      -    fi
     1838 +Man.addFunc get_suffix '' '[+NAME?get_suffix - Ask user for suffix and related backend.]
     1839 +[+DESCRIPTION?Ask the user for the suffix (default: \bSTR[LDAP_BASEDN]]\b) to create and the db name if it does not yet exist. \bTMP[DS_DBS_AVAIL]]\b gets set to the given db name (if any), \bSTR[DS_DB]]\b to the prepared db name and \bSTR[LDAP_SUFFIX]]\b to the given suffix.]
     1840 +[+RETURN VALUES]{
     1841 +        [+0?on success (user gave a correct suffix).]
     1842 +        [+1?unable to create suffix given by user.]
     1843 +        [+>= 66?a fatal error occured.]
1422 1844  }
     1845 +[+SEE ALSO?\bget_ans()\b, \bdisplay_msg()\b, \bnormalizeDN()\b, \bprep_create_sfx_entry()\b, \bprep_create_sfx_backend()\b.]
     1846 +'
     1847 +function get_suffix {
     1848 +        while : ; do
     1849 +                get_ans 'Enter suffix to be created (b=back/h=help):' \
     1850 +                        "${STR[LDAP_BASEDN]}"
     1851 +                case "${ANS}" in
     1852 +                        [Hh?] | Help | help)
     1853 +                                display_msg 'create_suffix_help'
     1854 +                                continue
     1855 +                                ;;
     1856 +                        [Bb] | '<' | Back | back)
     1857 +                                return 1
     1858 +                                ;;
     1859 +                esac
     1860 +                STR[LDAP_SUFFIX]=${ normalizeDN "${ANS}" l ; }
     1861 +                prep_create_sfx_entry
     1862 +                integer REDO=$?
     1863 +                (( REDO >= 66 )) && return 66
     1864 +                (( REDO )) && continue
1423 1865  
1424      -get_krb_realm() {
     1866 +                if (( TMPF[NEED_CREATE_BACKEND] )); then
     1867 +                        TMP[DS_DBS_AVAIL]=''            # reset the available db name
     1868 +                        REDO=0
     1869 +                        while : ; do
     1870 +                                X=${TMP[DS_DBS_AVAIL]}
     1871 +                                # Basically for OpenDJ we could use 'userRoot' as default aka
     1872 +                                # TMP[SUFFIX_VAL], however, users may use it for trying out
     1873 +                                # examples from the docs
     1874 +                                get_ans 'Enter local database backend name (b=back/h=help):' \
     1875 +                                        "${X:-${TMP[SUFFIX_VAL]}}"
     1876 +                                case "${ANS}" in
     1877 +                                        [Hh?])
     1878 +                                                display_msg 'enter_ldbm_db_help'
     1879 +                                                continue
     1880 +                                                ;;
     1881 +                                        [Bb] | '<')
     1882 +                                                REDO=1
     1883 +                                                break
     1884 +                                                ;;
     1885 +                                esac
     1886 +                                STR[DS_DB]="${ANS}"
     1887 +                                prep_create_sfx_backend && break
     1888 +                        done
1425 1889  
1426      -    # To upper cases
1427      -    LDAP_KRB_REALM=`${ECHO} ${LDAP_DOMAIN} | ${NAWK} '{ print toupper($0) }'`
1428      -    get_ans_req "Enter Kerberos Realm:" "$LDAP_KRB_REALM"
1429      -    # To upper cases
1430      -    LDAP_KRB_REALM=`${ECHO} ${ANS} | ${NAWK} '{ print toupper($0) }'`
     1890 +                        (( REDO )) && continue
     1891 +
     1892 +                        Log.verbose 'Databse backend name for suffix ${STR[LDAP_SUFFIX]}:' \
     1893 +                                "${DS_DB}"
     1894 +                fi
     1895 +                # eventually everything is prepared
     1896 +                break
     1897 +        done
     1898 +        return 0
1431 1899  }
1432 1900  
1433      -# $1: DN
1434      -# $2: ldif file
1435      -add_entry_by_DN() {
     1901 +Man.addFunc domain_2_dc '' '[+NAME?domain_2_dc - Convert a domain name into dc string.]
     1902 +[+DESCRIPTION?Convert a domain name \adomain\a into a dc=...,dc=... string and print it to stdout.]
     1903 +\n\n\adomain\a
     1904 +'
     1905 +function domain_2_dc {
     1906 +        [[ -z $1 ]] && return
     1907 +        typeset DC='' SD
     1908 +        for SD in ${1//./ } ; do        # removes leading && trailing && double dots
     1909 +                DC+=",dc=${SD}"
     1910 +        done
     1911 +        print -- "${DC:1}"
     1912 +}
1436 1913  
1437      -    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${1}\" -s base \"objectclass=*\" ${VERB}"
1438      -    if [ $? -eq 0 ]; then
1439      -            ${ECHO} "  ${1} already exists"
1440      -            return 0
1441      -    else
1442      -        ${EVAL} "${LDAPADD} ${LDAP_ARGS} -f ${2} ${VERB}"
1443      -        if [ $? -eq 0 ]; then
1444      -                ${ECHO} "  ${1} is added"
1445      -                return 0
1446      -        else
1447      -                ${ECHO} "  ERROR: failed to add ${1}"
1448      -                return 1
1449      -        fi
1450      -    fi
1451      -
     1914 +Man.addFunc get_basedn  '' '[+NAME?get_basedn - Ask user for Base DN.]
     1915 +[+DESCRIPTION?Ask the user for the BaseDN to use, check whether to create a suffix and store the value into \bSTR[LDAP_BASEDN]]\b.]
     1916 +[+RETURN VALUES]{
     1917 +        [+0?on success.]
     1918 +        [+>= 66?a fatal error occured.]
1452 1919  }
1453      -#
1454      -# Kerberos princiapl to DN mapping rules
1455      -#
1456      -# Add rules for host credentails and user credentials
1457      -#
1458      -add_id_mapping_rules() {
     1920 +[+SEE ALSO?\bget_ans_req()\b, \bdisplay_msg()\b, \bcheck_baseDN()\b, \bcheck_basedn_suffix()\b, \bget_suffix()\b.]
     1921 +'
     1922 +function get_basedn {
     1923 +        typeset BASEDN=${ domain_2_dc ${STR[LDAP_DOMAIN]} ; }
     1924 +        integer RES
1459 1925  
1460      -    ${ECHO} "  Adding Kerberos principal to DN mapping rules..."
     1926 +        while : ; do
     1927 +                # Get Base DN.
     1928 +                while : ; do
     1929 +                        get_ans_req 'Enter LDAP Base DN (h=help):' "${BASEDN}"
     1930 +                        case "${ANS}" in
     1931 +                                [Hh?] | help | Help) display_msg 'basedn_help' ; continue ;;
     1932 +                        esac
     1933 +                        check_baseDN "${ANS}" && break
     1934 +                        Log.warn "Invalid base DN: '${ANS}'"
     1935 +                done
1461 1936  
1462      -    _C_DN="cn=GSSAPI,cn=identity mapping,cn=config"
1463      -    ( cat << EOF
1464      -dn: cn=GSSAPI,cn=identity mapping,cn=config
1465      -objectClass: top
1466      -objectClass: nsContainer
1467      -cn: GSSAPI
1468      -EOF
1469      -) > ${TMPDIR}/GSSAPI_container.ldif
     1937 +                # Set base DN and check its suffix
     1938 +                STR[LDAP_BASEDN]="${ANS}"
     1939 +                check_basedn_suffix || return 66
1470 1940  
1471      -    add_entry_by_DN "${_C_DN}" "${TMPDIR}/GSSAPI_container.ldif"
1472      -    if [ $? -ne 0 ];
1473      -    then
1474      -        ${RM} ${TMPDIR}/GSSAPI_container.ldif
1475      -        return
1476      -    fi
     1941 +                # suffix may need to be created, in that case get suffix from user
     1942 +                if (( TMPF[NEED_CREATE_SUFFIX] )); then
     1943 +                        get_suffix
     1944 +                        RES=$?
     1945 +                        (( RES >= 66 )) && return 67 
     1946 +                        (( RES )) && continue
     1947 +                fi
1477 1948  
1478      -    _H_CN="host_auth_${LDAP_KRB_REALM}"
1479      -    _H_DN="cn=${_H_CN}, ${_C_DN}"
1480      -    ( cat << EOF
1481      -dn: ${_H_DN}
1482      -objectClass: top
1483      -objectClass: nsContainer
1484      -objectClass: dsIdentityMapping
1485      -objectClass: dsPatternMatching
1486      -cn: ${_H_CN}
1487      -dsMatching-pattern: \${Principal}
1488      -dsMatching-regexp: host\/(.*).${LDAP_DOMAIN}@${LDAP_KRB_REALM}
1489      -dsSearchBaseDN: ou=hosts,${LDAP_BASEDN}
1490      -dsSearchFilter: (&(objectClass=ipHost)(cn=\$1))
1491      -dsSearchScope: one
     1949 +                # suffix is ok, break out of the base dn inquire loop
     1950 +                break
     1951 +        done
     1952 +        return 0
     1953 +}
1492 1954  
1493      -EOF
1494      -) > ${TMPDIR}/${_H_CN}.ldif
     1955 +Man.addFunc chk_vlv_indexes '' '[+NAME?chk_vlv_indexes - check if server supports VLV.]
     1956 +[+DESCRIPTION?Checks, whether the DS supports Virtual List Views (VLV).]
     1957 +[+RETURN VALUES]{
     1958 +        [+0?if VLVs are supported.]
     1959 +        [+>= 66?if VLVs are not supported.]
     1960 +}
     1961 +[+SEE ALSO?\bldapsearch\b(1).]
     1962 +'
     1963 +function chk_vlv_indexes {
     1964 +        typeset ATTR=''
     1965 +        ${LDAPSEARCH} ${CON_ARGS} -b '' -s base 'objectclass=*' \
     1966 +                supportedControl 2>/dev/null | \
     1967 +        while read LINE ; do
     1968 +                if [[ ${LINE#*=} == '2.16.840.1.113730.3.4.9' ]]; then
     1969 +                        ATTR=${.sh.match%=}
     1970 +                        break
     1971 +                fi
     1972 +        done
     1973 +        if [[ -z ${ATTR} ]]; then
     1974 +                Log.fatal 'VLV is not supported on LDAP server'
     1975 +                return 66
     1976 +        fi
     1977 +        return 0
     1978 +}
1495 1979  
1496      -    add_entry_by_DN "${_H_DN}" "${TMPDIR}/${_H_CN}.ldif"
1497      -
1498      -    _U_CN="user_auth_${LDAP_KRB_REALM}"
1499      -    _U_DN="cn=${_U_CN}, ${_C_DN}"
1500      -    ( cat << EOF
1501      -dn: ${_U_DN}
1502      -objectClass: top
1503      -objectClass: nsContainer
1504      -objectClass: dsIdentityMapping
1505      -objectClass: dsPatternMatching
1506      -cn: ${_U_CN}
1507      -dsMatching-pattern: \${Principal}
1508      -dsMatching-regexp: (.*)@${LDAP_KRB_REALM}
1509      -dsMappedDN: uid=\$1,ou=People,${LDAP_BASEDN}
1510      -
1511      -EOF
1512      -) > ${TMPDIR}/${_U_CN}.ldif
1513      -
1514      -    add_entry_by_DN "${_U_DN}" "${TMPDIR}/${_U_CN}.ldif"
1515      -
     1980 +Man.addFunc validate_suffix '' '[+NAME?validate_suffix - validate suffix obtained via config file.]
     1981 +[+DESCRIPTION?This function validates STR[LDAP_SUFFIX]] AFTER THE LOAD OF A CONFIG FILE (should not be used for interactive use). Also does a consistency check wrt. \bSTR[LDAP_BASEDN]]\b.]
     1982 +[+RETURN VALUES]{
     1983 +        [+0?on success.]
     1984 +        [+>= 66?a fatal error occured.]
1516 1985  }
     1986 +[+SEE ALSO?\bnormalizeDN()\b, \bldapsearch\b(1), \bprep_create_sfx_entry()\b, \bprep_create_sfx_backend()\b.]
     1987 +'
     1988 +function validate_suffix {
     1989 +        # Check STR[LDAP_SUFFIX] is not null
     1990 +        if [[ -z ${STR[LDAP_SUFFIX]} ]]; then
     1991 +                Log.fatal 'Invalid suffix (null suffix)'
     1992 +                return 66
     1993 +        fi
1517 1994  
     1995 +        # STR[LDAP_SUFFIX] and STR[LDAP_BASEDN] are consistent ?
     1996 +        typeset X=,${ normalizeDN "${STR[LDAP_BASEDN]}" l ; }
     1997 +        typeset SFX=,${ normalizeDN "${STR[LDAP_SUFFIX]}" l ; }
     1998 +        if [[ ${X: -${#SFX}} != ${SFX} ]]; then
     1999 +                Log.fatal "Invalid suffix '${SFX}' for Base DN '${X}'"
     2000 +                return 67
     2001 +        fi
1518 2002  
1519      -#
1520      -# Modify ACL to allow root to read all the password and only self can read
1521      -# its own password when sasl/GSSAPI bind is used
1522      -#
1523      -modify_userpassword_acl_for_gssapi() {
     2003 +        # STR[LDAP_SUFFIX] does exist ?
     2004 +        if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b "${STR[LDAP_SUFFIX]}" \
     2005 +                -s base 'objectclass=*' >/dev/null 2>&1
     2006 +        then
     2007 +                checkSuffixRDN && return 0 || return 68
     2008 +        fi
1524 2009  
1525      -    _P_DN="ou=People,${LDAP_BASEDN}"
1526      -    _H_DN="ou=Hosts,${LDAP_BASEDN}"
1527      -    _P_ACI="self-read-pwd"
     2010 +        # Well, suffix does not exist, try to prepare create it ...
     2011 +        TMPF[NEED_CREATE_SUFFIX]=1
     2012 +        prep_create_sfx_entry || return 69
     2013 +        if (( TMPF[NEED_CREATE_BACKEND] )); then
     2014 +                if [[ -z ${STR[DS_DB]} ]]; then
     2015 +                        Log.fatal 'Database backend name is not set. Either set SIN[DS_DB]'\
     2016 +                                'in the input file to a valid, i.e. non-existing DB name, or' \
     2017 +                                'create the backend with the default DS tools'
     2018 +                        return 70
     2019 +                fi
     2020 +                # too risky, even if a available backend name could be found
     2021 +                prep_create_sfx_backend || return 71
     2022 +        fi
1528 2023  
1529      -    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${_P_DN}\" -s base \"objectclass=*\" > /dev/null 2>&1" 
1530      -    if [ $? -ne 0 ]; then
1531      -            ${ECHO} "  ${_P_DN} does not exist"
1532      -        # Not Found. Create a new entry
1533      -        ( cat << EOF
1534      -dn: ${_P_DN}
1535      -ou: People
1536      -objectClass: top
1537      -objectClass: organizationalUnit
1538      -EOF
1539      -) > ${TMPDIR}/gssapi_people.ldif
1540      -
1541      -        add_entry_by_DN "${_P_DN}" "${TMPDIR}/gssapi_people.ldif"
1542      -    else 
1543      -        ${ECHO} "  ${_P_DN} already exists"
1544      -    fi
1545      -
1546      -    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${_P_DN}\" -s base \"objectclass=*\" aci > ${TMPDIR}/chk_gssapi_aci 2>&1"
1547      -
1548      -    if [ $? -eq 0 ]; then
1549      -            ${EVAL} "${GREP} ${_P_ACI} ${TMPDIR}/chk_gssapi_aci > /dev/null 2>&1"
1550      -            if [ $? -eq 0 ]; then
1551      -                ${ECHO} "  userpassword ACL ${_P_ACI} already exists."
1552      -                return
1553      -            else
1554      -                ${ECHO} "  userpassword ACL ${_P_ACI} not found. Create a new one."
1555      -            fi
1556      -    else
1557      -        ${ECHO} "  Error searching aci for ${_P_DN}"
1558      -        cat ${TMPDIR}/chk_gssapi_aci
1559      -        cleanup
1560      -        exit 1
1561      -    fi
1562      -    ( cat << EOF
1563      -dn: ${_P_DN}
1564      -changetype: modify
1565      -add: aci
1566      -aci: (targetattr="userPassword")(version 3.0; acl self-read-pwd; allow (read,search) userdn="ldap:///self" and authmethod="sasl GSSAPI";)
1567      --
1568      -add: aci
1569      -aci: (targetattr="userPassword")(version 3.0; acl host-read-pwd; allow (read,search) userdn="ldap:///cn=*+ipHostNumber=*,ou=Hosts,${LDAP_BASEDN}" and authmethod="sasl GSSAPI";)
1570      -EOF
1571      -) > ${TMPDIR}/user_gssapi.ldif
1572      -    LDAP_TYPE_OR_VALUE_EXISTS=20
1573      -    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/user_gssapi.ldif ${VERB}"
1574      -
1575      -    case $? in
1576      -    0)
1577      -        ${ECHO} "  ${_P_DN} uaserpassword ACL is updated."
1578      -        ;;
1579      -    20)
1580      -        ${ECHO} "  ${_P_DN} uaserpassword ACL already exists."
1581      -        ;;
1582      -    *)
1583      -        ${ECHO} "  ERROR: update of userpassword ACL for ${_P_DN} failed!"
1584      -        cleanup
1585      -        exit 1
1586      -        ;;
1587      -    esac
     2024 +    Log.verbose "Suffix: '${STR[LDAP_SUFFIX]}'   Database: '${STR[DS_DB]}'"
     2025 +        return 0
1588 2026  }
1589      -#
1590      -# $1: objectclass or attributetyp
1591      -# $2: name
1592      -search_update_schema() {
1593 2027  
1594      -    ATTR="${1}es"
1595      -
1596      -    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b cn=schema -s base \"objectclass=*\" ${ATTR} | ${GREP} -i \"${2}\" ${VERB}"
1597      -    if [ $? -ne 0 ]; then
1598      -        ${ECHO} "${1} ${2} does not exist."
1599      -        update_schema_attr
1600      -        update_schema_obj
1601      -        SCHEMA_UPDATED=1
1602      -    else
1603      -        ${ECHO} "${1} ${2} already exists. Schema has been updated"
1604      -    fi
     2028 +Man.addFunc validate_info '' '[+NAME?validate_info - validate basic info obtained via config file.]
     2029 +[+DESCRIPTION?This function updates \bCON_ARGS\b as well as \bAUTH_ARGS\b, checks, whether they work so that some problems are caught right away AFTER THE LOAD OF A CONFIG FILE (should not be used for interactive use). It also validates the obtained suffix and whether the DS supports VLVs.]
     2030 +[+RETURN VALUES]{
     2031 +        [+0?on success.]
     2032 +        [+>= 66?a fatal error occured.]
1605 2033  }
     2034 +[+SEE ALSO?\bldapsearch\b(1), \bchk_vlv_indexes()\b, \bvalidate_suffix()\b.]
     2035 +'
     2036 +function validate_info {
     2037 +        # Set CON_ARGS and AUTH_ARGS for the config file.
     2038 +        CON_ARGS="-h ${STR[DS_HOST]} -p ${INT[DS_PORT]}"
     2039 +        AUTH_ARGS=( '-D' "${STR[LDAP_ROOTDN]}" '-j' "${TMP[LDAP_ROOTPWF]}" )
     2040 +        chk_ids_version || return 1     # Check DSEE version for compatibility
1606 2041  
1607      -#
1608      -# Set up GSSAPI if necessary
1609      -#
1610      -gssapi_setup() {
     2042 +        # Check the Root DN and Root DN passwd.o Same as for get_dirmgr_pw()
     2043 +        RES=${ ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b '' -s base \
     2044 +                'objectclass=*' supportedLDAPVersion 2>&1 ; }
     2045 +        if (( $? )); then
     2046 +                if [[ ${RES} =~ credential ]]; then
     2047 +                        Log.fatal 'Root DN passwd is invalid'
     2048 +                else
     2049 +                        Log.fatal "Invalid Root DN '${STR[LDAP_ROOTDN]}'"
     2050 +                fi
     2051 +                return 66
     2052 +        fi
     2053 +    Log.verbose 'RootDN: ok   RootDN passwd: ok'
1611 2054  
1612      -        GSSAPI_ENABLE=0
     2055 +        # Check if the server supports the VLV
     2056 +        chk_vlv_indexes || return 67
     2057 +        Log.verbose 'VLV indexes ... ok'
1613 2058  
1614      -        # assume sasl/GSSAPI is supported by the ldap server and may be used
1615      -        GSSAPI_AUTH_MAY_BE_USED=1
     2059 +        # Check LDAP suffix
     2060 +        validate_suffix || return 66
     2061 +        Log.verbose 'LDAP suffix ... ok'
     2062 +        return 0
     2063 +}
1616 2064  
1617      -        ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"\" -s base \"objectclass=*\" supportedSASLMechanisms | ${GREP} GSSAPI ${VERB}"
1618      -        if [ $? -ne 0 ]; then
1619      -                GSSAPI_AUTH_MAY_BE_USED=0
1620      -                ${ECHO} "  sasl/GSSAPI is not supported by this LDAP server"
     2065 +Man.addFunc gssapi_setup '' '[+NAME?gssapi_setup - set up GSSAPI if necessary.]
     2066 +[+DESCRIPTION?Check, whether the DS supports the SASL mechanism \bGSSAPI\b. If so, ask the user whether it should be enabled and depending on the answer ask for related Kerberos realm info. \bINT[GSSAPI_ENABLE]]\b and \bTMPF[GSSAPI_AUTH_MAY_BE_USED]]\b and optionally \bSTR[LDAP_KRB_REALM]]\b are set accordingly.]
     2067 +[+SEE ALSO?\bldapsearch\b(1), \bget_ans_req()\b.]
     2068 +'
     2069 +function gssapi_setup {
     2070 +        INT[GSSAPI_ENABLE]=0
     2071 +        TMPF[GSSAPI_AUTH_MAY_BE_USED]=0
     2072 +
     2073 +        ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b '' -s base 'objectclass=*' \
     2074 +                supportedSASLMechanisms 2>/dev/null | \
     2075 +        while read LINE ; do
     2076 +                if [[ ${LINE:0:24} == 'supportedSASLMechanisms=' && \
     2077 +                        ${LINE:24} == 'GSSAPI' ]]
     2078 +                then
     2079 +                        TMPF[GSSAPI_AUTH_MAY_BE_USED]=1
     2080 +                        break
     2081 +                fi
     2082 +        done
     2083 +        if (( ! TMPF[GSSAPI_AUTH_MAY_BE_USED] )); then
     2084 +                Log.info 'sasl/GSSAPI is not supported by this LDAP server'
1621 2085                  return
1622 2086          fi
1623 2087  
1624      -        get_confirm "GSSAPI is supported. Do you want to set up gssapi:(y/n)" "n"
1625      -        if [ $? -eq 0 ]; then
1626      -                GSSAPI_ENABLE=0
1627      -                ${ECHO}
1628      -                ${ECHO} "GSSAPI is not set up."
1629      -                ${ECHO} "sasl/GSSAPI bind may not work if it's not set up first."
     2088 +        get_confirm 'GSSAPI is supported. Do you want to set up GSSAPI:(y/n)' 'n'
     2089 +        if (( $? )); then
     2090 +                INT[GSSAPI_ENABLE]=1
     2091 +                # get kerberos realm
     2092 +                typeset -u REALM=${STR[LDAP_DOMAIN]}
     2093 +                get_ans_req "Enter Kerberos Realm:" "${REALM}"
     2094 +                REALM="${ANS}"          # make sure, it is upper case
     2095 +                STR[LDAP_KRB_REALM]="${REALM}"
1630 2096          else
1631      -                GSSAPI_ENABLE=1
1632      -                get_krb_realm
     2097 +                Log.info 'GSSAPI is not set up - ' \
     2098 +                        'sasl/GSSAPI bind may not work if it is not set up first'
1633 2099          fi
1634      -
1635 2100  }
1636      -#
1637      -# get_profile_name(): Enter the profile name.
1638      -#
1639      -get_profile_name()
1640      -{
1641      -    # Reset Delete Old Profile since getting new profile name.
1642      -    DEL_OLD_PROFILE=0
1643 2101  
1644      -    # Loop until valid profile name, or replace.
1645      -    while :
1646      -    do
1647      -        # Prompt for profile name.
1648      -        get_ans "Enter the profile name (h=help):" "$LDAP_PROFILE_NAME"
     2102 +Man.addFunc get_profile_name '' '[+NAME?get_profile_name - Ask user for client profile name.]
     2103 +[+DESCRIPTION?Ask the user for the name of the client profile to create, check whether it already exists, and if so ask whether it should be overwritten. Sets \bSTR[LDAP_PROFILE_NAME]]\b, \bTMPF[DEL_OLD_PROFILE]]\b and if the user wants to just enable shadow update \bINT[LDAP_ENABLE_SHADOW_UPDATE]]\b and \bINT[EXISTING_PROFILE]]\b.]
     2104 +[+SEE ALSO?\bget_ans()\b, \bldapsearch\b(1), \bget_confirm()\b, \bget_confirm_nodef()\b, \bdisplay_msg()\b.]
     2105 +'
     2106 +function get_profile_name {
     2107 +        TMPF[DEL_OLD_PROFILE]=0         # Reset since getting new profile name
1649 2108  
1650      -        # Check for Help.
1651      -        case "$ANS" in
1652      -            [Hh] | help | Help | \?) display_msg profile_help
1653      -                                     continue ;; 
1654      -            * )  ;;
1655      -        esac
     2109 +        typeset PNAME="${STR[LDAP_PROFILE_NAME]}"
     2110 +        # Loop until valid profile name, or replace.
     2111 +        while : ; do
     2112 +                get_ans 'Enter the client profile name (h=help):' "${PNAME}"
     2113 +                case "${ANS}" in
     2114 +                        [Hh] | help | Help | '?') display_msg 'profile_help' ; continue ;; 
     2115 +                esac
1656 2116  
1657      -        # Search to see if profile name already exists.
1658      -        eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${ANS},ou=profile,${LDAP_BASEDN}\" -s base \"objectclass=*\" ${VERB}"
1659      -        if [ $? -eq 0 ]; then
     2117 +                # Search to see if profile name already exists.
     2118 +                if ! ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
     2119 +                        -b "cn=${ANS},ou=profile,${STR[LDAP_BASEDN]}" -s base \
     2120 +                        'objectclass=*' >/dev/null 2>&1
     2121 +                then
     2122 +                        break  # Unique profile name (does not yet exist)
     2123 +                fi
1660 2124  
1661      -            cat << EOF
     2125 +                Log.info 'Profile "'"${ANS}"'" already exists, it is possible to' \
     2126 +                        'enable shadow update now.' "${PROG}" 'will exit after shadow' \
     2127 +                        'update is enabled. You can also continue to overwrite the' \
     2128 +                        'profile or create a new one and be given the chance to enable' \
     2129 +                        'shadow update later.'
1662 2130  
1663      -Profile '${ANS}' already exists, it is possible to enable
1664      -shadow update now. idsconfig will exit after shadow update
1665      -is enabled. You can also continue to overwrite the profile 
1666      -or create a new one and be given the chance to enable
1667      -shadow update later.
     2131 +            get_confirm 'Just enable shadow update (y/n/h)?' 'n' \
     2132 +                        'enable_shadow_update_help'
     2133 +            if (( $? )); then
     2134 +                        # set up credentials for shadow update
     2135 +                        INT[LDAP_ENABLE_SHADOW_UPDATE]=1
     2136 +                        # display alternate messages
     2137 +                        INT[EXISTING_PROFILE]=1
     2138 +                        break
     2139 +                fi
1668 2140  
1669      -EOF
     2141 +                get_confirm_nodef \
     2142 +                        "Are you sure you want to overwrite profile 'cn=${ANS}'?"
     2143 +                if (( $? )); then
     2144 +                        TMPF[DEL_OLD_PROFILE]=1         # Replace old profile name
     2145 +                        break
     2146 +                fi
     2147 +        done
1670 2148  
1671      -            MSG="Just enable shadow update (y/n/h)?"
1672      -            get_confirm "$MSG" "n" "enable_shadow_update_help"
1673      -            if [ $? -eq 1 ]; then
1674      -                [ $DEBUG -eq 1 ] && ${ECHO} "set up shadow update"
1675      -                LDAP_ENABLE_SHADOW_UPDATE=TRUE
1676      -                # display alternate messages
1677      -                EXISTING_PROFILE=1
1678      -                # Set Profile Name.
1679      -                LDAP_PROFILE_NAME=$ANS
1680      -                return 0  # set up credentials for shadow update.
1681      -            fi
     2149 +        STR[LDAP_PROFILE_NAME]="${ANS}"
     2150 +}
1682 2151  
1683      -            get_confirm_nodef "Are you sure you want to overwrite profile cn=${ANS}?"
1684      -            if [ $? -eq 1 ]; then
1685      -                DEL_OLD_PROFILE=1
1686      -                return 0  # Replace old profile name.
1687      -            else
1688      -                ${ECHO} "Please re-enter a new profile name."
1689      -            fi
1690      -        else
1691      -            break  # Unique profile name.
1692      -        fi
1693      -    done
1694      -
1695      -    # Set Profile Name.
1696      -    LDAP_PROFILE_NAME=$ANS
     2152 +Man.addFunc getACIs '' '[+NAME?getACIs - get ACIs for the current base DN.]
     2153 +[+DESCRIPTION?Get all ACIs for \abaseDN\a and append them to the indexed array of strings \avname\a. If \abaseDN\a is not given, \bSTR[LDAP_BASEDN]]\b will be used instead. If \ascope\a is set to \bGlobal\b this method queries for "ds-cfg-global-aci" instead of "aci" unless \bTMPF[IS_OPENDJ]]\b is \b0\b.]
     2154 +[+RETURN VALUES]{
     2155 +        [+-1?invalid function usage.]
     2156 +        [+0?on success.]
     2157 +        [+1?an error occured when executing the ldapsearch operation.]
1697 2158  }
     2159 +\n\n\avname\a [\abaseDN\a] [\ascope\a]
     2160 +'
     2161 +function getACIs {
     2162 +        set -o pipefail         # wanna have the exit code of ldapsearch
     2163 +        [[ -z $1 ]] && Log.warn "${.sh.fun}(): invalid function usage" && \
     2164 +                return -1
     2165 +        typeset -n ACILIST=$1
     2166 +        typeset LINE
     2167 +        typeset DN="$2" ACI='aci'
     2168 +        [[ -z ${DN} ]] && DN="${STR[LDAP_BASEDN]}"
     2169 +        [[ $3 == 'Global' ]] && (( TMPF[IS_OPENDJ] )) && ACI='ds-cfg-global-aci'
1698 2170  
1699      -
1700      -#
1701      -# get_srv_list(): Get the default server list.
1702      -#
1703      -get_srv_list()
1704      -{
1705      -    # If LDAP_SERVER_LIST is NULL, then set, otherwise leave alone.
1706      -    if [ -z "${LDAP_SERVER_LIST}" ]; then
1707      -        LDAP_SERVER_LIST=`getent hosts ${IDS_SERVER} | awk '{print $1}'`
1708      -        if [ ${IDS_PORT} -ne 389 ]; then
1709      -            LDAP_SERVER_LIST="${LDAP_SERVER_LIST}:${IDS_PORT}"
     2171 +    ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b "${DN}" -s base \
     2172 +                'objectclass=*' ${ACI} 2>/dev/null | \
     2173 +        while read LINE ; do
     2174 +                # NOTE: the || : is required to always get success (pipe doesn't break)
     2175 +                [[ ${LINE:0:${#ACI}+1} == "${ACI}=" ]] && \
     2176 +                        ACILIST+=( "${LINE:${#ACI}+1}" ) || :
     2177 +        done
     2178 +        if (( $? )); then
     2179 +                Log.fatal "Unable to get aci list for '${STR[LDAP_BASEDN]}'"
     2180 +                return 1
1710 2181          fi
1711      -    fi
1712      -
1713      -    # Prompt for new LDAP_SERVER_LIST.
1714      -    while :
1715      -    do
1716      -        get_ans "Default server list (h=help):" $LDAP_SERVER_LIST
1717      -
1718      -        # If help continue, otherwise break.
1719      -        case "$ANS" in
1720      -            [Hh] | help | Help | \?) display_msg def_srvlist_help ;;
1721      -            * ) break ;;
1722      -        esac
1723      -    done
1724      -    LDAP_SERVER_LIST=$ANS
     2182 +        return 0
1725 2183  }
1726 2184  
1727      -
1728      -#
1729      -# get_pref_srv(): The preferred server list (Overrides the server list)
1730      -#
1731      -get_pref_srv()
1732      -{
1733      -    while :
1734      -    do
1735      -        get_ans "Preferred server list (h=help):" $LDAP_PREF_SRVLIST
1736      -
1737      -        # If help continue, otherwise break.
1738      -        case "$ANS" in
1739      -            [Hh] | help | Help | \?) display_msg pref_srvlist_help ;;
1740      -            * ) break ;;
1741      -        esac
1742      -    done
1743      -    LDAP_PREF_SRVLIST=$ANS
     2185 +Man.addFunc findACI '' '[+NAME?findACI - find an ACI in the given list.]
     2186 +[+DESCRIPTION?Find the first ACI which matches \aregex\a in the indexed array of ACIs \avname\a. If a match occurs, print out a message using the given \aaciName\a prefixed with \ascope\a. If \ascope\a is not given or empty, \bBaseDN\b will be used instead.]
     2187 +[+RETURN VALUES]{
     2188 +        [+0?no ACI matched.]
     2189 +        [+>=1?the index+1 of the ACI matched.]
1744 2190  }
1745      -
1746      -
1747      -#
1748      -# get_search_scope(): Get the search scope from the user.
1749      -#
1750      -get_search_scope()
1751      -{
1752      -    [ $DEBUG -eq 1 ] && ${ECHO} "In get_search_scope()"
1753      -
1754      -    _MENU_CHOICE=0
1755      -    while :
1756      -    do
1757      -        get_ans "Choose desired search scope (one, sub, h=help): " "one"
1758      -        _MENU_CHOICE=$ANS
1759      -        case "$_MENU_CHOICE" in
1760      -            one) LDAP_SEARCH_SCOPE="one"
1761      -               return 1 ;;
1762      -            sub) LDAP_SEARCH_SCOPE="sub"
1763      -               return 2 ;;
1764      -            h) display_msg srch_scope_help ;;
1765      -            *) ${ECHO} "Please enter \"one\", \"sub\", or \"h\"." ;;
1766      -        esac
1767      -    done
1768      -
     2191 +[+SEE ALSO?\bgetACIs()\b, \bfindACI()\b, \bfind_and_delete_ACI\b()]
     2192 +\n\n\avname\a \aaciName\a \aregex\a [\ascope\a]
     2193 +'
     2194 +function findACI {
     2195 +        typeset -n LIST=$1
     2196 +        typeset NAME="$2" REGEX="$3" SCOPE="$4"
     2197 +        integer MAX=${#LIST[@]} I
     2198 +        [[ -z ${SCOPE} ]] && SCOPE='BaseDN'
     2199 +        for (( I=0; I < MAX; I++ )); do
     2200 +                if [[ ${LIST[${I}]} =~ ${REGEX} ]]; then
     2201 +                        showProgress "${SCOPE} ACI '${NAME}' exists."
     2202 +                        return $((I+1))
     2203 +                fi
     2204 +        done
     2205 +        return 0
1769 2206  }
1770 2207  
1771      -
1772      -#
1773      -# get_cred_level(): Function to display menu to user and get the 
1774      -#                  credential level.
1775      -#
1776      -get_cred_level()
1777      -{
1778      -    [ $DEBUG -eq 1 ] && ${ECHO} "In get_cred_level()"
1779      -
1780      -    _MENU_CHOICE=0
1781      -    display_msg cred_level_menu
1782      -    while :
1783      -    do
1784      -        if [ $GSSAPI_ENABLE -eq 1 ]; then
1785      -            ${ECHO} '"self" is needed for GSSAPI profile'
1786      -        fi
1787      -        get_ans "Choose Credential level [h=help]:" "1"
1788      -        _MENU_CHOICE=$ANS
1789      -        case "$_MENU_CHOICE" in
1790      -            1) LDAP_CRED_LEVEL="anonymous"
1791      -               return 1 ;;
1792      -            2) LDAP_CRED_LEVEL="proxy"
1793      -               return 2 ;;
1794      -            3) LDAP_CRED_LEVEL="proxy anonymous"
1795      -               return 3 ;;
1796      -            4) LDAP_CRED_LEVEL="self"
1797      -               return 4 ;;
1798      -            h) display_msg cred_lvl_help ;;
1799      -            *) ${ECHO} "Please enter 1, 2, 3 or 4." ;;
1800      -        esac
1801      -    done
     2208 +Man.addFunc allow_proxy_read_pw '' '[+NAME?allow_proxy_read_pw - add Proxy Agent read permission for password.]
     2209 +[+DESCRIPTION?Add the ACI \bPROXY_ACI_NAME\b for \bSTR[LDAP_PROXYAGENT]]\b to \bSTR[LDAP_BASEDN]]\b if it not already exists.]
     2210 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage PROXY_ACI_NAME ; }" '}
     2211 +[+RETURN VALUES]{
     2212 +        [+0?on success (ACI already exists or added successfully).]
     2213 +        [+>= 66?a fatal error occured.]
1802 2214  }
     2215 +[+SEE ALSO?\bgetACIs()\b, \bldapmodify\b(1).]
     2216 +'
     2217 +function allow_proxy_read_pw {
     2218 +        typeset ACI PATTERN TARGET
1803 2219  
     2220 +        typeset -a LIST=( )
     2221 +        getACIs LIST || return 66
1804 2222  
1805      -#
1806      -# srvauth_menu_handler(): Enter the Service Authentication method.
1807      -#
1808      -srvauth_menu_handler()
1809      -{
1810      -    # Display Auth menu
1811      -    display_msg srvauth_method_menu     
     2223 +        PATTERN='acl[ ]+"?('"${PROXY_ACI_NAME}|${PROXY_ACI_NAME// /_}"')"?'
     2224 +        findACI LIST "${PROXY_ACI_NAME}" "${PATTERN}" || return 0
1812 2225  
1813      -    # Get a Valid choice.
1814      -    while :
1815      -    do
1816      -        # Display appropriate prompt and get answer.
1817      -        if [ $_FIRST -eq 1 ]; then
1818      -            get_ans "Choose Service Authentication Method:" "1"
     2226 +        PATTERN='userPassword'
     2227 +        if (( TMPF[IS_OPENDJ] )); then
     2228 +                PATTERN+=' || authPassword'
     2229 +                # At least in OpenDJ specifying the same target as where the ACI gets 
     2230 +                # attached is redundant wrt. the result and causes minimal overhead
     2231 +                TARGET=''
1819 2232          else
1820      -            get_ans "Choose Service Authentication Method (0=reset):"
     2233 +                TARGET='(target = "ldap:///'"${STR[LDAP_BASEDN]}"'")'
1821 2234          fi
     2235 +        
     2236 +        nextFile modify $0
     2237 +        print '
     2238 +dn: '"${STR[LDAP_BASEDN]}"'
     2239 +changetype: modify
     2240 +add: aci
     2241 +aci: '"${TARGET}"'(targetattr = "'"${PATTERN}"'")
     2242 + (
     2243 +        version 3.0;  acl "'"${PROXY_ACI_NAME}"'";
     2244 +        allow (compare,read,search) userdn = "ldap:///'"${STR[LDAP_PROXYAGENT]}"'";
     2245 + )
     2246 +'               > ${TMP[FILE]}
     2247 +    
     2248 +        if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     2249 +                >&${TMPF[FD]} 2>&1
     2250 +        then
     2251 +                Log.fatal "Adding '${PROXY_ACI_NAME}' ACI failed"
     2252 +                return 66
     2253 +        fi
1822 2254  
1823      -        # Determine choice.
1824      -        _MENU_CHOICE=$ANS
1825      -        case "$_MENU_CHOICE" in
1826      -            1) _AUTHMETHOD="simple"
1827      -                break ;;
1828      -            2) _AUTHMETHOD="sasl/DIGEST-MD5"
1829      -                break ;;
1830      -            3) _AUTHMETHOD="tls:simple"
1831      -                break ;;
1832      -            4) _AUTHMETHOD="tls:sasl/DIGEST-MD5"
1833      -                break ;;
1834      -            5) _AUTHMETHOD="sasl/GSSAPI"
1835      -                break ;;
1836      -            0) _AUTHMETHOD=""
1837      -                _FIRST=1
1838      -                break ;;
1839      -            *) ${ECHO} "Please enter 1-5 or 0 to reset." ;;
1840      -        esac
1841      -    done
     2255 +        showProgress "ACI '${PROXY_ACI_NAME}' added."
     2256 +        return 0
1842 2257  }
1843 2258  
1844      -
1845      -#
1846      -# auth_menu_handler(): Enter the Authentication method.
1847      -#
1848      -auth_menu_handler()
1849      -{
1850      -    # Display Auth menu
1851      -    display_msg auth_method_menu        
1852      -
1853      -    # Get a Valid choice.
1854      -    while :
1855      -    do
1856      -        if [ $GSSAPI_ENABLE -eq 1 ]; then
1857      -            ${ECHO} '"sasl/GSSAPI" is needed for GSSAPI profile'
1858      -        fi
1859      -        # Display appropriate prompt and get answer.
1860      -        if [ $_FIRST -eq 1 ]; then
1861      -            get_ans "Choose Authentication Method (h=help):" "1"
1862      -        else
1863      -            get_ans "Choose Authentication Method (0=reset, h=help):"
1864      -        fi
1865      -
1866      -        # Determine choice.
1867      -        _MENU_CHOICE=$ANS
1868      -        case "$_MENU_CHOICE" in
1869      -            1) _AUTHMETHOD="none"
1870      -                break ;;
1871      -            2) _AUTHMETHOD="simple"
1872      -                break ;;
1873      -            3) _AUTHMETHOD="sasl/DIGEST-MD5"
1874      -                break ;;
1875      -            4) _AUTHMETHOD="tls:simple"
1876      -                break ;;
1877      -            5) _AUTHMETHOD="tls:sasl/DIGEST-MD5"
1878      -                break ;;
1879      -            6) _AUTHMETHOD="sasl/GSSAPI"
1880      -                break ;;
1881      -            0) _AUTHMETHOD=""
1882      -                _FIRST=1
1883      -                break ;;
1884      -            h) display_msg auth_help ;;
1885      -            *) ${ECHO} "Please enter 1-6, 0=reset, or h=help." ;;
1886      -        esac
1887      -    done
     2259 +Man.addFunc delete_proxy_read_pw '' '[+NAME?delete_proxy_read_pw - delete Proxy Agent read permission for password.]
     2260 +[+DESCRIPTION?Remove the ACI \bPROXY_ACI_NAME\b from \bSTR[LDAP_BASEDN]]\b if such an ACI exists.]
     2261 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage PROXY_ACI_NAME ; }" '}
     2262 +[+RETURN VALUES]{
     2263 +        [+0?on success (no delete required or ACI deleted).]
     2264 +        [+>= 66?a fatal error occured.]
1888 2265  }
     2266 +[+SEE ALSO?\bgetACIs()\b, \bget_menu_choice()\b, \bldapmodify\b(1).]
     2267 +'
     2268 +function delete_proxy_read_pw {
     2269 +        typeset PROXY_ACI='' ACI PATTERN X
1889 2270  
     2271 +        typeset -a LIST=( )
     2272 +        getACIs LIST || return 66
1890 2273  
1891      -#
1892      -# get_auth(): Enter the Authentication method.
1893      -#
1894      -get_auth()
1895      -{
1896      -    [ $DEBUG -eq 1 ] && ${ECHO} "In get_auth()"
     2274 +        # Search for ACI_NAME - no findACI() because we need ALL matching ACIs
     2275 +        typeset -a ACILIST=( )
     2276 +        PATTERN='acl[ ]+"?('"${PROXY_ACI_NAME}|${PROXY_ACI_NAME// /_}"')"?'
     2277 +        for ACI in "${LIST[@]}" ; do
     2278 +                [[ ${ACI} =~ ${PATTERN} ]] && ACILIST+=( "${ACI#*=}" )
     2279 +        done
1897 2280  
1898      -    _FIRST=1          # Flag for first time.
1899      -    _MENU_CHOICE=0
1900      -    _AUTHMETHOD=""    # Tmp method.
     2281 +        # We need to remove proxy agent's read access to user passwords,
     2282 +        # but We do not know the value of the ${LDAP_PROXYAGENT} here, so
     2283 +        # 1. if only one match found, delete it
     2284 +        # 2. if more than one matches found, ask the user which one to delete
     2285 +        if (( ${#ACILIST[@]} == 0 )); then
     2286 +                Log.warn "ACI '${PROXY_ACI_NAME}' does not exist for" \
     2287 +                        "'${STR[LDAP_BASEDN]}'"
     2288 +                return 0
     2289 +    fi
     2290 +        if (( ${#ACILIST[@]} == 1 ));then
     2291 +                PROXY_ACI="${ACI[0]}"
     2292 +    else
     2293 +                X='
     2294 +Proxy agent is not allowed to read user passwords when shadow
     2295 +update is enabled. There are more than one proxy agents found.
     2296 +Please select the proxy agent currently being used, so that
     2297 +'"${PROG}"' can remove its read access to user passwords.
1901 2298  
1902      -    while :
1903      -    do
1904      -        # Call Menu handler
1905      -        auth_menu_handler
     2299 +The proxy agents are:
     2300 +'
     2301 +                # print the list of ACIs for selection
     2302 +                integer I MAX
     2303 +                MAX=${#ACILIST[@]}
     2304 +                for (( I=0; I < MAX; I++ )) ; do
     2305 +                        ACI="${ACILIST[${I}]}"
     2306 +                        if (( ! Log.VERBOSE )); then
     2307 +                        # older versions used
     2308 +                                # sed -e 's|.*ldap:///.*ldap:///||' -e 's|";)||'
     2309 +                                ACI=${ACI##*ldap:///}
     2310 +                                ACI=${ACI%\"*}
     2311 +                        fi
     2312 +                        X+=${ printf '%2d: %s\n' $((I+1)) "${ACI}" ; }
     2313 +                done
     2314 +                Log.warn "${X}"
1906 2315  
1907      -        # Add Auth Method to list.
1908      -        if [ $_FIRST -eq 1 ]; then 
1909      -            LDAP_AUTHMETHOD="${_AUTHMETHOD}"
1910      -            _FIRST=0
1911      -        else
1912      -            LDAP_AUTHMETHOD="${LDAP_AUTHMETHOD};${_AUTHMETHOD}"
     2316 +            # ask the user to pick one
     2317 +                get_menu_choice "Select the proxy agent (1-${MAX}): " 1 ${MAX}
     2318 +                I=$(( $? - 1 ))
     2319 +                PROXY_ACI="${ACILIST[$I]}"
1913 2320          fi
1914 2321  
1915      -        # Display current Authentication Method.
1916      -        ${ECHO} ""
1917      -        ${ECHO} "Current authenticationMethod: ${LDAP_AUTHMETHOD}"
1918      -        ${ECHO} ""
     2322 +        nextFile modify $0
     2323 +        print '
     2324 +dn: '"${STR[LDAP_BASEDN]}"'
     2325 +changetype: modify
     2326 +delete: aci
     2327 +aci: '"${PROXY_ACI}"'
     2328 +'               >${TMP[FILE]}
1919 2329  
1920      -        # Prompt for another Auth Method, or break out.
1921      -        get_confirm_nodef "Do you want to add another Authentication Method?"
1922      -        if [ $? -eq 0 ]; then
1923      -            break;
     2330 +        if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     2331 +                >&${TMPF[FD]} 2>&1
     2332 +        then
     2333 +                Log.fatal "Remove of '${PROXY_ACI_NAME}' ACI failed"
     2334 +                cat ${TMP[FILE]}
     2335 +                return 66
1924 2336          fi
1925      -    done
     2337 +
     2338 +    Log.info "Removed '${PROXY_ACI_NAME}' ACI"
     2339 +        return 0
1926 2340  }
1927 2341  
1928      -
1929      -#
1930      -# get_followref(): Whether or not to follow referrals.
1931      -#
1932      -get_followref()
1933      -{
1934      -    get_confirm "Do you want the clients to follow referrals (y/n/h)?" "n" "referrals_help"
1935      -    if [ $? -eq 1 ]; then
1936      -        LDAP_FOLLOWREF="TRUE"
1937      -    else
1938      -        LDAP_FOLLOWREF="FALSE"
1939      -    fi
     2342 +Man.addFunc allow_host_read_write_shadow '' '[+NAME?allow_host_read_write_shadow - add host principal read/write permission for shadow data.]
     2343 +[+DESCRIPTION?Add the ACI \bHOST_ACI_NAME\b to \bSTR[LDAP_BASEDN]]\b  unless it already exists.]
     2344 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage HOST_ACI_NAME ; }" '}
     2345 +[+RETURN VALUES]{
     2346 +        [+0?on success (ACI already exists or added successfully).]
     2347 +        [+>= 66?a fatal error occured.]
1940 2348  }
     2349 +[+SEE ALSO?\bgetACIs()\b, \bldapmodify\b(1).]
     2350 +'
     2351 +function allow_host_read_write_shadow {
     2352 +        typeset ACI PATTERN TARGET=''
1941 2353  
     2354 +        typeset -a LIST=( )
     2355 +        getACIs LIST || return 66
1942 2356  
1943      -#
1944      -# get_timelimit(): Set the time limit. -1 is max time.
1945      -#
1946      -get_timelimit()
1947      -{
1948      -    # Get current timeout value from cn=config.
1949      -    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=config\" -s base \"objectclass=*\" nsslapd-timelimit > ${TMPDIR}/chk_timeout 2>&1"
1950      -    if [ $? -ne 0 ]; then
1951      -        ${ECHO} "  ERROR: Could not reach LDAP server to check current timeout!"
1952      -        cleanup
1953      -        exit 1
1954      -    fi
1955      -    CURR_TIMELIMIT=`${GREP} timelimit ${TMPDIR}/chk_timeout | cut -f2 -d=`
1956      -    
1957      -    get_negone_num "Enter the time limit for iDS (current=${CURR_TIMELIMIT}):" "-1"
1958      -    IDS_TIMELIMIT=$NUM
1959      -}
     2357 +        PATTERN='acl[ ]+"?('"${HOST_ACI_NAME}|${HOST_ACI_NAME// /_}"')"?'
     2358 +        findACI LIST "${HOST_ACI_NAME}" "${PATTERN}" || return 0
1960 2359  
     2360 +        (( ! TMPF[IS_OPENDJ] )) && \
     2361 +                TARGET='(target = "ldap:///'"${STR[LDAP_BASEDN]}"'")'   # OD: redundant
1961 2362  
1962      -#
1963      -# get_sizelimit(): Set the size limit. -1 is max size.
1964      -#
1965      -get_sizelimit()
1966      -{
1967      -    # Get current sizelimit value from cn=config.
1968      -    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=config\" -s base \"objectclass=*\" nsslapd-sizelimit > ${TMPDIR}/chk_sizelimit 2>&1"
1969      -    if [ $? -ne 0 ]; then
1970      -        ${ECHO} "  ERROR: Could not reach LDAP server to check current sizelimit!"
1971      -        cleanup
1972      -        exit 1
1973      -    fi
1974      -    CURR_SIZELIMIT=`${GREP} sizelimit ${TMPDIR}/chk_sizelimit | cut -f2 -d=`
     2363 +        nextFile modify $0
     2364 +        print '
     2365 +dn: '"${STR[LDAP_BASEDN]}"'
     2366 +changetype: modify
     2367 +add: aci
     2368 +aci: '"${TARGET}"'(targetattr = "shadowLastChange || shadowMin || shadowMax || shadowWarning || shadowInactive || shadowExpire || shadowFlag || userPassword || loginShell || homeDirectory || gecos")
     2369 + (
     2370 +        version 3.0;  acl '"${HOST_ACI_NAME}"';
     2371 +        allow (write,compare,read,search) authmethod = "sasl GSSAPI" and userdn = "ldap:///cn=*+ipHostNumber=*,ou=Hosts,'"${STR[LDAP_BASEDN]}"';
     2372 + )
     2373 +'               > ${TMP[FILE]}
     2374 +    
     2375 +        if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     2376 +                >&${TMPF[FD]} 2>&1
     2377 +        then
     2378 +                Log.fatal 'Remove of '${ACI_NAME}' ACI failed'
     2379 +                return 66
     2380 +        fi
1975 2381  
1976      -    get_negone_num "Enter the size limit for iDS (current=${CURR_SIZELIMIT}):" "-1"
1977      -    IDS_SIZELIMIT=$NUM
     2382 +        showProgress "ACI '${ACI_NAME}' added."
     2383 +        return 0
1978 2384  }
1979 2385  
1980      -
1981      -#
1982      -# get_want_crypt(): Ask user if want to store passwords in crypt?
1983      -#
1984      -get_want_crypt()
1985      -{
1986      -    get_confirm "Do you want to store passwords in \"crypt\" format (y/n/h)?" "n" "crypt_help"
1987      -    if [ $? -eq 1 ]; then
1988      -        NEED_CRYPT="TRUE"
1989      -    else
1990      -        NEED_CRYPT="FALSE"
1991      -    fi
     2386 +Man.addFunc find_and_delete_ACI '' '[+NAME?find_and_delete_ACI - find and delete an ACI in the given list.]
     2387 +[+DESCRIPTION?Find the first ACI which matches \aregex\a in the indexed array of ACIs \avname\a and delete it. If no ACI matches, the function does nothing and returns. Otherwise it tries to delete it from \bSTR[LDAP_BASEDN]]\b and prints out a message using \aaciName\a.]
     2388 +[+RETURN VALUES]{
     2389 +        [+0?on success (no ACI matched or ACI removed successfully).]
     2390 +        [+66?an error occured when removing the matched ACI.]
1992 2391  }
     2392 +[+SEE ALSO?\bgetACIs()\b, \bldapmodify\b(1)]
     2393 +\n\n\avname\a \aaciName\a \aregex\a
     2394 +'
     2395 +function find_and_delete_ACI {
     2396 +        typeset -n LIST=$1
     2397 +        typeset ACI_NAME="$2" REGEX="$3" DEL='' ACI
1993 2398  
     2399 +        for ACI in "${LIST[@]}" ; do
     2400 +                [[ ${ACI} =~ ${REGEX} ]] && DEL="${ACI}" && break
     2401 +        done
     2402 +        [[ -z ${DEL} ]] && return 0
1994 2403  
1995      -#
1996      -# get_srv_authMethod_pam(): Get the Service Auth Method for pam_ldap from user.
1997      -#
1998      -#  NOTE: This function is base on get_auth().
1999      -#
2000      -get_srv_authMethod_pam()
2001      -{
2002      -    [ $DEBUG -eq 1 ] && ${ECHO} "In get_srv_authMethod_pam()"
     2404 +        nextFile modify "${0}-${ACI_NAME}"
     2405 +        print '
     2406 +dn: '"${STR[LDAP_BASEDN]}"'
     2407 +changetype: modify
     2408 +delete: aci
     2409 +aci: '"${DEL}"'
     2410 +'               > ${TMP[FILE]}
2003 2411  
2004      -    _FIRST=1          # Flag for first time.
2005      -    _MENU_CHOICE=0
2006      -    _AUTHMETHOD=""    # Tmp method.
2007      -
2008      -    while :
2009      -    do
2010      -        # Call Menu handler
2011      -        srvauth_menu_handler
2012      -
2013      -        # Add Auth Method to list.
2014      -        if [ $_FIRST -eq 1 ]; then 
2015      -            if [ "$_AUTHMETHOD" = "" ]; then
2016      -                LDAP_SRV_AUTHMETHOD_PAM=""
2017      -            else
2018      -                LDAP_SRV_AUTHMETHOD_PAM="pam_ldap:${_AUTHMETHOD}"
2019      -            fi
2020      -            _FIRST=0
2021      -        else
2022      -            LDAP_SRV_AUTHMETHOD_PAM="${LDAP_SRV_AUTHMETHOD_PAM};${_AUTHMETHOD}"
     2412 +        if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     2413 +                >&${TMPF[FD]} 2>&1
     2414 +        then
     2415 +                Log.fatal "Remove of '${ACI_NAME}' ACI failed"
     2416 +                return 66
2023 2417          fi
2024 2418  
2025      -        # Display current Authentication Method.
2026      -        ${ECHO} ""
2027      -        ${ECHO} "Current authenticationMethod: ${LDAP_SRV_AUTHMETHOD_PAM}"
2028      -        ${ECHO} ""
     2419 +        showProgress "ACI '${ACI_NAME}' deleted."
     2420 +        return 0
     2421 +}
2029 2422  
2030      -        # Prompt for another Auth Method, or break out.
2031      -        get_confirm_nodef "Do you want to add another Authentication Method?"
2032      -        if [ $? -eq 0 ]; then
2033      -            break;
2034      -        fi
2035      -    done
2036      -
2037      -    # Check in case user reset string and exited loop.
2038      -    if [ "$LDAP_SRV_AUTHMETHOD_PAM" = "" ]; then
2039      -        NEED_SRVAUTH_PAM=0
2040      -    fi
     2423 +Man.addFunc deny_non_host_shadow_access '' '[+NAME?deny_non_host_shadow_access - add a deny non-host access to shadow data.]
     2424 +[+DESCRIPTION?Add the ACI \bNON_HOST_ACI_NAME\b to \bSTR[LDAP_BASEDN]]\b  unless it already exists. If it does not exists the ACI \bNON_ADMIN_ACI_NAME\b gets deleted first if available.]
     2425 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage NON_HOST_ACI_NAME NON_ADMIN_ACI_NAME ; }" '}
     2426 +[+RETURN VALUES]{
     2427 +        [+0?on success (ACI already exists or added successfully).]
     2428 +        [+>= 66?a fatal error occured.]
2041 2429  }
     2430 +[+SEE ALSO?\bgetACIs()\b, \bfind_and_delete_ACI()\b, \bldapmodify\b(1).]
     2431 +'
     2432 +function deny_non_host_shadow_access {
     2433 +        typeset ACI PATTERN TARGET=''
2042 2434  
     2435 +        typeset -a LIST=( )
     2436 +        getACIs LIST || return 66
2043 2437  
2044      -#
2045      -# get_srv_authMethod_key(): Get the Service Auth Method for keyserv from user.
2046      -#
2047      -#  NOTE: This function is base on get_auth().
2048      -#
2049      -get_srv_authMethod_key()
2050      -{
2051      -    [ $DEBUG -eq 1 ] && ${ECHO} "In get_srv_authMethod_key()"
     2438 +    # If an ACI with ${NON_HOST_ACI_NAME} already exists, we are done
     2439 +        PATTERN='acl[ ]+"?('"${NON_HOST_ACI_NAME}|${NON_HOST_ACI_NAME// /_}"')"?'
     2440 +        findACI LIST "${NON_HOST_ACI_NAME}" "${PATTERN}" || return 0
2052 2441  
2053      -    _FIRST=1          # Flag for first time.
2054      -    _MENU_CHOICE=0
2055      -    _AUTHMETHOD=""    # Tmp method.
     2442 +        # The deny_non_admin_shadow_access and deny_non_host_shadow_access ACIs
     2443 +        # should be mutually exclusive, so if the former exists, delete it
     2444 +        PATTERN='acl[ ]+"?('"${NON_ADMIN_ACI_NAME}|${NON_ADMIN_ACI_NAME// /_}"')"?'
     2445 +        find_and_delete_ACI LIST "${NON_ADMIN_ACI_NAME}" "${PATTERN}" || return 67
2056 2446  
2057      -    while :
2058      -    do
2059      -        # Call Menu handler
2060      -        srvauth_menu_handler
     2447 +        (( ! TMPF[IS_OPENDJ] )) && \
     2448 +                TARGET='(target = "ldap:///'"${STR[LDAP_BASEDN]}"'")'   # OD: redundant
2061 2449  
2062      -        # Add Auth Method to list.
2063      -        if [ $_FIRST -eq 1 ]; then 
2064      -            if [ "$_AUTHMETHOD" = "" ]; then
2065      -                LDAP_SRV_AUTHMETHOD_KEY=""
2066      -            else
2067      -                LDAP_SRV_AUTHMETHOD_KEY="keyserv:${_AUTHMETHOD}"
2068      -            fi
2069      -            _FIRST=0
2070      -        else
2071      -            LDAP_SRV_AUTHMETHOD_KEY="${LDAP_SRV_AUTHMETHOD_KEY};${_AUTHMETHOD}"
     2450 +        nextFile modify $0
     2451 +        print '
     2452 +dn: '"${STR[LDAP_BASEDN]}"'
     2453 +changetype: modify
     2454 +add: aci
     2455 +aci: '"${TARGET}"'(targetattr = "shadowLastChange || shadowMin || shadowMax ||shadowWarning || shadowInactive || shadowExpire || shadowFlag || userPassword")
     2456 + (
     2457 +        version 3.0;  acl "'"${NON_HOST_ACI_NAME}"'";
     2458 +        deny (write,read,search,compare) userdn != "ldap:///cn=*+ipHostNumber=*,ou=Hosts,'"${STR[LDAP_BASEDN]}"'";
     2459 + )
     2460 +'               > ${TMP[FILE]}
     2461 +    
     2462 +        if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     2463 +                >&${TMPF[FD]} 2>&1
     2464 +        then
     2465 +                Log.fatal "Adding ACI '${NON_HOST_ACI_NAME}' failed"
     2466 +                return 67
2072 2467          fi
2073 2468  
2074      -        # Display current Authentication Method.
2075      -        ${ECHO} ""
2076      -        ${ECHO} "Current authenticationMethod: ${LDAP_SRV_AUTHMETHOD_KEY}"
2077      -        ${ECHO} ""
     2469 +        showProgress "ACI '${NON_HOST_ACI_NAME}' added."
     2470 +        return 0
     2471 +}
2078 2472  
2079      -        # Prompt for another Auth Method, or break out.
2080      -        get_confirm_nodef "Do you want to add another Authentication Method?"
2081      -        if [ $? -eq 0 ]; then
2082      -            break;
2083      -        fi
2084      -    done
     2473 +Man.addFunc get_adminDN '' '[+NAME?get_adminDN - ask user for Admin DN.]
     2474 +[+DESCRIPTION?Ask the user for the Admin DN and store it into \bSTR[LDAP_BASEDN]]\b.]
     2475 +[+SEE ALSO?\bget_ans()\b.]
     2476 +'
     2477 +function get_adminDN {
     2478 +    get_ans 'Enter DN for the administrator:' \
     2479 +                "cn=admin,ou=profile,${STR[LDAP_BASEDN]}"
     2480 +        STR[LDAP_ADMINDN]="${ANS}"
     2481 +}
2085 2482  
2086      -    # Check in case user reset string and exited loop.
2087      -    if [ "$LDAP_SRV_AUTHMETHOD_KEY" = "" ]; then
2088      -        NEED_SRVAUTH_KEY=0
2089      -    fi
     2483 +Man.addFunc get_admin_pw '' '[+NAME?get_admin_pw - ask user for Admin password]
     2484 +[+DESCRIPTION?Ask the user for the Admin password and store it into \bSTR[LDAP_ADMIN_CRED]]\b.]
     2485 +[+SEE ALSO?\bget_passwd()\b.]
     2486 +'
     2487 +function get_admin_pw {
     2488 +        get_passwd 'Enter passwd for the administrator:'
     2489 +        STR[LDAP_ADMIN_CRED]="${ANS}"
2090 2490  }
2091 2491  
     2492 +Man.addFunc add_admin '' '[+NAME?add_admin - Add administrator identity.]
     2493 +[+DESCRIPTION?Add the \bSTR[LDAP_ADMINDN]]\b entry with the password \bSTR[LDAP_ADMIN_CRED]]\b unless it already exists.]
     2494 +[+RETURN VALUES]{
     2495 +        [+0?on success (entry already exists or added successfully).]
     2496 +        [+>= 66?a fatal error occured.]
     2497 +}
     2498 +[+SEE ALSO?\bldapsearch\b(1), \bldapmodify\b(1).]
     2499 +'
     2500 +function add_admin {
     2501 +        if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b "${STR[LDAP_ADMINDN]}" \
     2502 +                -s base 'objectclass=*' >/dev/null 2>&1
     2503 +        then
     2504 +                showProgress "Administrator identity exists."
     2505 +                return 0
     2506 +        fi
2092 2507  
2093      -#
2094      -# get_srv_authMethod_cmd(): Get the Service Auth Method for passwd-cmd from user.
2095      -#
2096      -#  NOTE: This function is base on get_auth().
2097      -#
2098      -get_srv_authMethod_cmd()
2099      -{
2100      -    [ $DEBUG -eq 1 ] && ${ECHO} "In get_srv_authMethod_cmd()"
     2508 +        typeset CN="${STR[LDAP_ADMINDN]%%,*}"
     2509 +        CN="${CN#*=}"
2101 2510  
2102      -    _FIRST=1          # Flag for first time.
2103      -    _MENU_CHOICE=0
2104      -    _AUTHMETHOD=""    # Tmp method.
     2511 +        nextFile add $0
     2512 +        print '
     2513 +dn: '"${STR[LDAP_ADMINDN]}"'
     2514 +cn: '"${CN}"'
     2515 +sn: '"${CN}"'
     2516 +objectclass: top
     2517 +objectclass: person
     2518 +userpassword: '"${STR[LDAP_ADMIN_CRED]}"'
     2519 +'               > ${TMP[FILE]}
2105 2520  
2106      -    while :
2107      -    do
2108      -        # Call Menu handler
2109      -        srvauth_menu_handler
2110      -
2111      -        # Add Auth Method to list.
2112      -        if [ $_FIRST -eq 1 ]; then 
2113      -            if [ "$_AUTHMETHOD" = "" ]; then
2114      -                LDAP_SRV_AUTHMETHOD_CMD=""
2115      -            else
2116      -                LDAP_SRV_AUTHMETHOD_CMD="passwd-cmd:${_AUTHMETHOD}"
2117      -            fi
2118      -            _FIRST=0
2119      -        else
2120      -            LDAP_SRV_AUTHMETHOD_CMD="${LDAP_SRV_AUTHMETHOD_CMD};${_AUTHMETHOD}"
     2521 +        if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     2522 +                >&${TMPF[FD]} 2>&1
     2523 +        then
     2524 +                Log.fatal 'Adding administrator identity failed'
     2525 +                return 66
2121 2526          fi
2122 2527  
2123      -        # Display current Authentication Method.
2124      -        ${ECHO} ""
2125      -        ${ECHO} "Current authenticationMethod: ${LDAP_SRV_AUTHMETHOD_CMD}"
2126      -        ${ECHO} ""
2127      -
2128      -        # Prompt for another Auth Method, or break out.
2129      -        get_confirm_nodef "Do you want to add another Authentication Method?"
2130      -        if [ $? -eq 0 ]; then
2131      -            break;
2132      -        fi
2133      -    done
2134      -
2135      -    # Check in case user reset string and exited loop.
2136      -    if [ "$LDAP_SRV_AUTHMETHOD_CMD" = "" ]; then
2137      -        NEED_SRVAUTH_CMD=0
2138      -    fi
     2528 +        showProgress 'Administrator identity added.'
     2529 +        return 0
2139 2530  }
2140 2531  
2141      -
2142      -#
2143      -# get_srch_time(): Amount of time to search.
2144      -#
2145      -get_srch_time()
2146      -{
2147      -    get_negone_num "Client search time limit in seconds (h=help):" "$LDAP_SEARCH_TIME_LIMIT" "srchtime_help"
2148      -    LDAP_SEARCH_TIME_LIMIT=$NUM
     2532 +Man.addFunc allow_admin_read_write_shadow '' '[+NAME?allow_admin_read_write_shadow - add Admin read/write permission for shadow, rbac and mount data.]
     2533 +[+DESCRIPTION?Add the ACI \bADMIN_ACI_NAME\b to \bSTR[LDAP_BASEDN]]\b  unless it already exists. Also tries to remove old similar ACIs if they exist.]
     2534 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage ADMIN_ACI_NAME ; }" '}
     2535 +[+RETURN VALUES]{
     2536 +        [+0?on success (aci already exists or addition was successfull).]
     2537 +        [+>= 66?a fatal error occured.]
2149 2538  }
     2539 +[+SEE ALSO?\bgetACIs()\b, \bfind_and_delete_ACI()\b, \bldapmodify\b(1).]
     2540 +'
     2541 +function allow_admin_read_write_shadow {
     2542 +        typeset PERMS='write,compare,read,search,add,delete' \
     2543 +                ACI RBAC PATTERN TARGET=''
2150 2544  
     2545 +        typeset -a LIST=( )
     2546 +        getACIs LIST || return 66
2151 2547  
2152      -#
2153      -# get_prof_ttl(): The profile time to live (TTL)
2154      -#
2155      -get_prof_ttl()
2156      -{
2157      -    get_negone_num "Profile Time To Live in seconds (h=help):" "$LDAP_PROFILE_TTL" "profttl_help"
2158      -    LDAP_PROFILE_TTL=$NUM
2159      -}
     2548 +    # If the ACI already exists, we are done
     2549 +        PATTERN='acl[ ]+"?('"${ADMIN_ACI_NAME}|${ADMIN_ACI_NAME// /_}"')"?'
     2550 +        PATTERN+='.*\('"${PERMS}"'\).*'"${STR[LDAP_ADMINDN]}"
     2551 +        findACI LIST "${ADMIN_ACI_NAME}" "${PATTERN}" || return 0
2160 2552  
     2553 +    # If an ACI with ${ADMIN_ACI_NAME} and "(write|write,compare,read,search)"
     2554 +        # and ${LDAP_ADMINDN} exists, delete it
     2555 +        PATTERN='acl[ ]+"?('"${ADMIN_ACI_NAME}|${ADMIN_ACI_NAME// /_}"')"?'
     2556 +        PATTERN+='.*\(write\).*'"${STR[LDAP_ADMINDN]}"
     2557 +    find_and_delete_ACI LIST "${ADMIN_ACI_NAME}" "${PATTERN}" || return 67
2161 2558  
2162      -#
2163      -# get_bind_limit(): Bind time limit
2164      -#
2165      -get_bind_limit()
2166      -{
2167      -    get_negone_num "Bind time limit in seconds (h=help):" "$LDAP_BIND_LIMIT" "bindlim_help"
2168      -    LDAP_BIND_LIMIT=$NUM
2169      -}
     2559 +        PATTERN='acl[ ]+"?('"${ADMIN_ACI_NAME}|${ADMIN_ACI_NAME// /_}"')"?'
     2560 +        PATTERN+='.*\(write,compare,read,search\).*'"${STR[LDAP_ADMINDN]}"
     2561 +    find_and_delete_ACI LIST "${ADMIN_ACI_NAME}" "${PATTERN}" || return 68
2170 2562  
     2563 +    RBAC='objectClass || uid || uidNumber || gidNumber || cn'
     2564 +    RBAC+=' || SolarisAttrKeyValue || SolarisAttrShortDesc'
     2565 +        RBAC+=' || SolarisAttrLongDesc || SolarisKernelSecurityPolicy'
     2566 +        RBAC+=' || SolarisProfileType || SolarisProfileId || SolarisUserQualifier'
     2567 +    RBAC+=' || SolarisReserved1 || SolarisReserved2'
     2568 +    RBAC+=' || SolarisAttrReserved1 || SolarisAttrReserved2'
     2569 +    RBAC+=' || SolarisProjectID || SolarisProjectName'
     2570 +    RBAC+=' || SolarisProjectAttr || memberUid || memberGid || description'
     2571 +    RBAC+=' || automountKey || automountMapName || automountInformation'
     2572 +    RBAC+=' || ipTnetTemplateName || ipTnetNumber'
2171 2573  
2172      -######################################################################
2173      -# FUNCTIONS  FOR Service Search Descriptor's START HERE.
2174      -######################################################################
     2574 +        (( ! TMPF[IS_OPENDJ] )) && \
     2575 +                TARGET='(target = "ldap:///'"${STR[LDAP_BASEDN]}"'")'   # OD: redundant
2175 2576  
2176      -
2177      -#
2178      -# add_ssd(): Get SSD's from user and add to file.
2179      -#
2180      -add_ssd()
2181      -{
2182      -    [ $DEBUG -eq 1 ] && ${ECHO} "In add_ssd()"
2183      -
2184      -    # Enter the service id.  Loop til unique.
2185      -    while :
2186      -    do
2187      -        get_ans "Enter the service id:"
2188      -        _SERV_ID=$ANS
2189      -
2190      -        # Grep for name existing.
2191      -        ${GREP} -i "^$ANS:" ${SSD_FILE} > /dev/null 2>&1
2192      -        if [ $? -eq 1 ]; then
2193      -            break
     2577 +        nextFile modify $0
     2578 +        print '
     2579 +dn: '"${STR[LDAP_BASEDN]}"'
     2580 +changetype: modify
     2581 +add: aci
     2582 +aci: '"${TARGET}"'(targetattr = "shadowLastChange || shadowMin || shadowMax || shadowWarning || shadowInactive || shadowExpire || shadowFlag || userPassword || loginShell || homeDirectory || gecos || '"${RBAC}"'")
     2583 + (
     2584 +        version 3.0;  acl "'${ADMIN_ACI_NAME}'";
     2585 +        allow ('"${PERMS}"') userdn = "ldap:///'"${STR[LDAP_ADMINDN]}"'";
     2586 + )
     2587 +'               > ${TMP[FILE]}
     2588 +    
     2589 +        if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     2590 +                >&${TMPF[FD]} 2>&1
     2591 +        then
     2592 +                Log.fatal "Adding '${ADMIN_ACI_NAME}' ACI failed"
     2593 +                return 69
2194 2594          fi
2195 2595  
2196      -        # Name exists, print message, let user decide.
2197      -        ${ECHO} "ERROR: Service id ${ANS} already exists."
2198      -    done
2199      -    
2200      -    get_ans "Enter the base:"
2201      -    _BASE=$ANS
     2596 +        showProgress "ACI '${ADMIN_ACI_NAME}' added."
     2597 +        return 0
     2598 +}
2202 2599  
2203      -    # Get the scope and verify that its one or sub.
2204      -    while :
2205      -    do
2206      -        get_ans "Enter the scope:"
2207      -        _SCOPE=$ANS
2208      -        case `${ECHO} ${_SCOPE} | tr '[A-Z]' '[a-z]'` in
2209      -            one) break ;;
2210      -            sub) break ;;
2211      -            *)   ${ECHO} "${_SCOPE} is Not valid - Enter 'one' or 'sub'" ;;
2212      -        esac
2213      -    done
2214      -
2215      -    # Build SSD to add to file.
2216      -    _SSD="${_SERV_ID}:${_BASE}?${_SCOPE}"
2217      -    
2218      -    # Add the SSD to the file.
2219      -    ${ECHO} "${_SSD}" >> ${SSD_FILE}
     2600 +Man.addFunc deny_non_admin_shadow_access '' '[+NAME?deny_non_admin_shadow_access - add a deny Admin access to shadow data.]
     2601 +[+DESCRIPTION?Add the ACI \bNON_ADMIN_ACI_NAME\b to \bSTR[LDAP_BASEDN]]\b  unless it already exists. If it does not exists the ACI \bNON_HOST_ACI_NAME\b gets deleted first if available.]
     2602 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage NON_ADMIN_ACI_NAME NON_HOST_ACI_NAME ; }" '}
     2603 +[+RETURN VALUES]{
     2604 +        [+0?on success (ACI already exists or added successfully).]
     2605 +        [+>= 66?a fatal error occured.]
2220 2606  }
     2607 +[+SEE ALSO?\bgetACIs()\b, \bfind_and_delete_ACI()\b, \bldapmodify\b(1).]
     2608 +'
     2609 +function deny_non_admin_shadow_access {
     2610 +        typeset TARGET=''
     2611 +        typeset -a LIST=( )
     2612 +        getACIs LIST || return 66
2221 2613  
     2614 +    # If the ACI already exists, we are done
     2615 +        PATTERN='acl[ ]+"?('"${NON_ADMIN_ACI_NAME}|${NON_ADMIN_ACI_NAME// /_}"')"?'
     2616 +        findACI LIST "${NON_ADMIN_ACI_NAME}" "${PATTERN}" || return 0
2222 2617  
2223      -#
2224      -# delete_ssd(): Delete a SSD from the list.
2225      -#
2226      -delete_ssd()
2227      -{
2228      -    [ $DEBUG -eq 1 ] && ${ECHO} "In delete_ssd()"
     2618 +        # The deny_non_admin_shadow_access and deny_non_host_shadow_access ACIs
     2619 +        # should be mutually exclusive, so if the latter exists, delete it
     2620 +        PATTERN='acl[ ]+"?('"${NON_HOST_ACI_NAME}|${NON_HOST_ACI_NAME// /_}"')"?'
     2621 +        find_and_delete_ACI LIST "${NON_HOST_ACI_NAME}" "${PATTERN}" || return 67
2229 2622  
2230      -    # Get service id name from user for SSD to delete.
2231      -    get_ans_req "Enter service id to delete:"
     2623 +        (( ! TMPF[IS_OPENDJ] )) && \
     2624 +                TARGET='(target = "ldap:///'"${STR[LDAP_BASEDN]}"'")'   # OD: redundant
2232 2625  
2233      -    # Make sure service id exists.
2234      -    ${GREP} "$ANS" ${SSD_FILE} > /dev/null 2>&1
2235      -    if [ $? -eq 1 ]; then
2236      -        ${ECHO} "Invalid service id: $ANS not present in list."
2237      -        return
2238      -    fi
     2626 +        nextFile modify $0
     2627 +        print '
     2628 +dn: '"${STR[LDAP_BASEDN]}"'
     2629 +changetype: modify
     2630 +add: aci
     2631 +aci: '"${TARGET}"'(targetattr = "shadowLastChange || shadowMin ||  shadowMax || shadowWarning || shadowInactive || shadowExpire || shadowFlag || userPassword")
     2632 + (
     2633 +        version 3.0;  acl "'"${NON_ADMIN_ACI_NAME}"'";
     2634 +        deny (write,read,search,compare,add,delete) userdn != "ldap:///'"${STR[LDAP_ADMINDN]}"'";
     2635 + )
     2636 +'               > ${TMP[FILE]}
     2637 +    
     2638 +        if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     2639 +                >&${TMPF[FD]} 2>&1
     2640 +        then
     2641 +                Log.fatal "Adding '${NON_ADMIN_ACI_NAME}' ACI failed"
     2642 +                ${CAT} ${TMP[FILE]}
     2643 +                return 68
     2644 +        fi
2239 2645  
2240      -    # Create temporary back SSD file.
2241      -    cp ${SSD_FILE} ${SSD_FILE}.bak
2242      -    if [ $? -eq 1 ]; then
2243      -        ${ECHO} "ERROR: could not create file: ${SSD_FILE}.bak"
2244      -        exit 1
2245      -    fi
     2646 +        showProgress "ACI '${NON_ADMIN_ACI_NAME}' added."
     2647 +        return 0
     2648 +}
2246 2649  
2247      -    # Use ${GREP} to remove the SSD.  Read from temp file
2248      -    # and write to the orig file.
2249      -    ${GREP} -v "$ANS" ${SSD_FILE}.bak > ${SSD_FILE} 
     2650 +Man.addFunc setup_shadow_update '' '[+NAME?setup_shadow_update - set up shadow update.]
     2651 +[+DESCRIPTION?Check whether the profile \bSTR[LDAP_PROFILE_NAME]]\b for \bSTR[LDAP_BASEDN]]\b exists. If not simply notify the user and return. Otherwise check whether the profile uses authenticationMethod "GSSAPI" and credentialLevel "self". If so ask the user whether to use host or "Admin" user principal for shadow updates and collect the related info. Sets \bINT[NEED_HOSTACL]]\b if the host principal should be used for shadow update (requires that \bTMPF[GSSAPI_AUTH_MAY_BE_USED]]\b is already set).]
     2652 +[+RETURN VALUES]{
     2653 +        [+0?on success.]
     2654 +        [+>= 66? a fatal error occured.]
2250 2655  }
     2656 +[+SEE ALSO?\bldapsearch\b(1), \bget_confirm()\b, \bdelete_proxy_read_pw()\b, \ballow_host_read_write_shadow()\b, \bdeny_non_host_shadow_access()\b, \bget_adminDN()\b, \bget_admin_pw()\b, \badd_admin()\b, \ballow_admin_read_write_shadow()\b, \bdeny_non_admin_shadow_access()\b.]
     2657 +'
     2658 +function setup_shadow_update {
     2659 +        # get content of the profile
     2660 +        integer CN=0 GSSAPI=0 SELF=0
     2661 +        typeset -l LINE
2251 2662  
     2663 +        ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
     2664 +                -b "cn=${STR[LDAP_PROFILE_NAME]},ou=profile,${STR[LDAP_BASEDN]}" \
     2665 +                -s base 'objectclass=*' 2>/dev/null | \
     2666 +        while read LINE ; do
     2667 +                [[ ${LINE:0:3} == 'cn=' ]] && CN=1
     2668 +                [[ ${LINE:0:21} == 'authenticationmethod=' && ${LINE:21} == 'GSSAPI' ]]\
     2669 +                        && GSSAPI=1
     2670 +                [[ ${LINE:0:16} == 'credentiallevel=' && ${LINE:16} == 'self' ]] \
     2671 +                        && SELF=1
     2672 +        done
     2673 +        if (( ! CN )); then
     2674 +                Log.verbose "Profile '${STR[LDAP_PROFILE_NAME]}' does not exist"
     2675 +                return 0
     2676 +        fi
2252 2677  
2253      -#
2254      -# modify_ssd(): Allow user to modify a SSD.
2255      -#
2256      -modify_ssd()
2257      -{
2258      -    [ $DEBUG -eq 1 ] && ${ECHO} "In modify_ssd()"
     2678 +        # If authenticationMethod has 'GSSAPI' and credentialLevel
     2679 +        # has 'self', ask to use the host principal for shadow update
     2680 +        if (( TMPF[GSSAPI_AUTH_MAY_BE_USED] && GSSAPI && SELF )); then
     2681 +                INT[NEED_HOSTACL]=1
     2682 +        fi
     2683 +        Log.verbose "NEED_HOSTACL = ${INT[NEED_HOSTACL]}"
2259 2684  
2260      -    # Prompt user for service id.
2261      -    get_ans_req "Enter service id to modify:"
2262      -    
2263      -    # Put into temp _LINE.
2264      -    _LINE=`${GREP} "^$ANS:" ${SSD_FILE}`
2265      -    if [ "$_LINE" = "" ]; then
2266      -        ${ECHO} "Invalid service id: $ANS"
2267      -        return
2268      -    fi
     2685 +        if (( INT[NEED_HOSTACL] )); then
     2686 +                get_confirm 'Use host principal for shadow data update (y/n/h)?' 'y' \
     2687 +                        'use_host_principal_help'
     2688 +                if (( $? )); then
     2689 +                        delete_proxy_read_pw || return 66
     2690 +                        allow_host_read_write_shadow || return 67
     2691 +                        deny_non_host_shadow_access || return 68
     2692 +                        Log.info 'Shadow update has been enabled'
     2693 +                else
     2694 +                        Log.warn 'Shadow update may not work'
     2695 +                fi
     2696 +                return 0
     2697 +        fi
2269 2698  
2270      -    # Display current filter for user to see.
2271      -    ${ECHO} ""
2272      -    ${ECHO} "Current SSD: $_LINE"
2273      -    ${ECHO} ""
2274      -    
2275      -    # Get the defaults.
2276      -    _CURR_BASE=`${ECHO} $_LINE | cut -d: -f2 | cut -d'?' -f 1`
2277      -    _CURR_SCOPE=`${ECHO} $_LINE | cut -d: -f2 | cut -d'?' -f 2`
     2699 +        get_confirm 'Add the administrator identity (y/n/h)?' 'y' \
     2700 +                'add_admin_cred_help'
     2701 +        if (( $? )); then
     2702 +                get_adminDN
     2703 +                get_admin_pw
     2704 +                add_admin || return 69
     2705 +                delete_proxy_read_pw || return 66
     2706 +                allow_admin_read_write_shadow || return 70
     2707 +                deny_non_admin_shadow_access || return 71
     2708 +                Log.info 'Shadow update has been enabled'
     2709 +        else
     2710 +                Log.warn 'No administrator identity specified, shadow update may not' \
     2711 +                        'work'
     2712 +        fi
     2713 +        return 0
     2714 +}
2278 2715  
2279      -    # Create temporary back SSD file.
2280      -    cp ${SSD_FILE} ${SSD_FILE}.bak
2281      -    if [ $? -eq 1 ]; then
2282      -        ${ECHO} "ERROR: could not create file: ${SSD_FILE}.bak"
2283      -        cleanup
2284      -        exit 1
2285      -    fi
     2716 +Man.addFunc get_srv_list '' '[+NAME?get_srv_list - Ask user for default server list.]
     2717 +[+DESCRIPTION?Ask the user for the default server list and store it into \bSTR[LDAP_SERVER_LIST]]\b.]
     2718 +[+SEE ALSO?\bget_ans()\b, \bdisplay_msg()\b.]
     2719 +'
     2720 +function get_srv_list {
     2721 +        # If LDAP_SERVER_LIST is NULL, then set, otherwise leave alone
     2722 +        if [[ -z ${STR[LDAP_SERVER_LIST]} ]]; then
     2723 +                ANS=${ ${GETENT} hosts ${STR[DS_HOST]} ; }
     2724 +                STR[LDAP_SERVER_LIST]=${ANS%%[[:space:]]*}
     2725 +                if (( INT[DS_PORT] != 389 )); then
     2726 +                        STR[LDAP_SERVER_LIST]="${STR[LDAP_SERVER_LIST]}:${INT[DS_PORT]}"
     2727 +                fi
     2728 +        fi
2286 2729  
2287      -    # Removed the old line.
2288      -    ${GREP} -v "^$ANS:" ${SSD_FILE}.bak > ${SSD_FILE} 2>&1
2289      - 
2290      -    # New Entry
2291      -    _SERV_ID=$ANS
2292      -    get_ans_req "Enter the base:" "$_CURR_BASE"
2293      -    _BASE=$ANS
2294      -    get_ans_req "Enter the scope:" "$_CURR_SCOPE"
2295      -    _SCOPE=$ANS
     2730 +        while : ; do
     2731 +                get_ans 'Default server list (h=help):' "${STR[LDAP_SERVER_LIST]}"
     2732 +                case "${ANS}" in
     2733 +                        [Hh] | help | Help | '?') display_msg 'def_srvlist_help' ;;
     2734 +                        * ) break ;;
     2735 +                esac
     2736 +        done
     2737 +        STR[LDAP_SERVER_LIST]="${ANS}"
     2738 +}
2296 2739  
2297      -    # Build the new SSD.
2298      -    _SSD="${_SERV_ID}:${_BASE}?${_SCOPE}"
     2740 +Man.addFunc get_pref_srv '' '[+NAME?get_pref_srv - Ask user for preferred server list.]
     2741 +[+DESCRIPTION?Ask the user for the preferred server list and store it into \bSTR[LDAP_PREF_SRVLIST]]\b (overrides the server list).]
     2742 +[+SEE ALSO?\bget_ans()\b, \bdisplay_msg()\b.]
     2743 +'
     2744 +function get_pref_srv {
     2745 +        while : ; do
     2746 +                get_ans 'Preferred server list (h=help):' "${STR[LDAP_PREF_SRVLIST]}"
     2747 +                case "${ANS}" in
     2748 +                        [Hh] | help | Help | '?') display_msg 'pref_srvlist_help' ;;
     2749 +                        * ) break ;;
     2750 +                esac
     2751 +        done
     2752 +        STR[LDAP_PREF_SRVLIST]="${ANS}"
     2753 +}
2299 2754  
2300      -    # Add the SSD to the file.
2301      -    ${ECHO} "${_SSD}" >> ${SSD_FILE}
     2755 +Man.addFunc get_search_scope '' '[+NAME?get_search_scope - Ask user for search scope.]
     2756 +[+DESCRIPTION?Ask the user for the search scope and store it into \bSTR[LDAP_SEARCH_SCOPE]]\b.]
     2757 +[+RETURN VALUES]{
     2758 +        [+1?search scope "one" selected.]
     2759 +        [+2?search scope "sub" selected.]
2302 2760  }
     2761 +[+SEE ALSO?\bget_ans()\b, \bdisplay_msg()\b.]
     2762 +'
     2763 +function get_search_scope {
     2764 +        integer RES
     2765 +        get_menu_choice 'Choose desired search scope (1=one, 2=sub, h=help): ' \
     2766 +                1 2 1 srch_scope_help
     2767 +        (( $? == 2 )) && { STR[LDAP_SEARCH_SCOPE]='sub' ; return 2 ; }
     2768 +        STR[LDAP_SEARCH_SCOPE]='one'
     2769 +        return 1
     2770 +}
2303 2771  
     2772 +Man.addFunc get_cred_level '' '[+NAME?get_cred_level - Ask user for credential level.]
     2773 +[+DESCRIPTION?Ask the user for the client credential level to use and store it into \bSTR[LDAP_CRED_LEVEL]]\b.]
     2774 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage CRED_LEVELS STR ; }" '}
     2775 +[+RETURN VALUES?The index wrt. \bCRED_LEVELS\b of the selected credential level \b+1\b.]
     2776 +[+SEE ALSO?\bget_ans()\b, \bdisplay_msg()\b.]
     2777 +'
     2778 +function get_cred_level {
     2779 +        integer RES
     2780 +        typeset PROMPT=''
     2781 +        (( INT[GSSAPI_ENABLE] )) && PROMPT='"self" is needed for GSSAPI profile.\n'
     2782 +        PROMPT+='Choose Credential level (identity) [h=help]:'
2304 2783  
2305      -#
2306      -# display_ssd(): Display the current SSD list.
2307      -#
2308      -display_ssd()
2309      -{
2310      -    [ $DEBUG -eq 1 ] && ${ECHO} "In display_ssd()"
     2784 +        get_menu_choice "${PROMPT}" 1 4 1 'cred_lvl_help' 'cred_level_menu'
     2785 +        RES=$?
     2786 +        STR[LDAP_CRED_LEVEL]="${CRED_LEVELS[RES-1]}"
     2787 +        return ${RES}
     2788 +}
2311 2789  
2312      -    ${ECHO} ""
2313      -    ${ECHO} "Current Service Search Descriptors:"
2314      -    ${ECHO} "=================================="
2315      -    cat ${SSD_FILE}
2316      -    ${ECHO} ""
2317      -    ${ECHO} "Hit return to continue."
2318      -    read __A
     2790 +Man.addFunc get_auth '' '[+NAME?get_auth - ask user for authentication methods.]
     2791 +[+DESCRIPTION?Ask the user for authentication methods to enable and store them  as a semicolon separated list into \bSTR[LDAP_AUTHMETHOD | LDAP_SRV_AUTHMETHOD_{PAM|KEY|CMD}}]]\b and set \bINT[NEED_SRVAUTH_{PAM|KEY|CMD}]]\b to 0 depending on the given \atype\a (either "client", "pam_ldap", "keyserv", or "passwd-cmd") and selected methods.]
     2792 +[+ENVIRONMENT VARIABLES]{' "${  Man.varUsage AUTH_METHODS STR ; }" '}
     2793 +[+RETURN VALUES]{
     2794 +        [+0?on success.]
     2795 +        [+-1?if an invalid \atype\a was given.]
2319 2796  }
     2797 +[+SEE ALSO?\bget_menu_choice()\b, \bget_confirm_nodef()\b.]
     2798 +\n\n\atype\a
     2799 +'
     2800 +function get_auth {
     2801 +        typeset TYPE=$1 VNAME HELPTAG MENU
     2802 +        integer RES MAX=${#AUTH_METHODS[@]} OFFSET=0
     2803 +        typeset -a SELECTED=( )
     2804 +        typeset -u UTYPE=${TYPE}
2320 2805  
     2806 +        case "${TYPE}" in
     2807 +                client) VNAME=LDAP_AUTHMETHOD ; OFFSET=1 ; UTYPE='DEFAULT' ;;
     2808 +                pam_ldap) VNAME=LDAP_SRV_AUTHMETHOD_PAM ;;
     2809 +                keyserv) VNAME=LDAP_SRV_AUTHMETHOD_KEY ;;
     2810 +                passwd-cmd) VNAME=LDAP_SRV_AUTHMETHOD_CMD ;;
     2811 +                *) print -u2 "${.sh.fun}() bug: invalid type argument" && return -1 ;;
     2812 +        esac
     2813 +                
     2814 +        typeset ASK='' VAL='' M=''
     2815 +        if (( OFFSET )); then
     2816 +                # client
     2817 +                (( INT[GSSAPI_ENABLE] )) && \
     2818 +                        ASK='"sasl/GSSAPI" is needed for GSSAPI profile.\n'
     2819 +                ASK+='Choose DEFAULT authentication (bind) method (0=reset, h=help):'
     2820 +                MENU='auth_method_menu'
     2821 +                HELPTAG='auth_help'
     2822 +        else
     2823 +                ASK="Choose ${UTYPE} authentication (bind) method (0=reset, h=help):"
     2824 +                (( MAX-- ))
     2825 +                MENU='srvauth_method_menu'
     2826 +                HELPTAG='srvauth_help'
     2827 +        fi
2321 2828  
2322      -#
2323      -# prompt_ssd(): Get SSD's from user.
2324      -#
2325      -prompt_ssd()
2326      -{
2327      -    [ $DEBUG -eq 1 ] && ${ECHO} "In prompt_ssd()"    
2328      -    # See if user wants SSD's?
2329      -    get_confirm "Do you wish to setup Service Search Descriptors (y/n/h)?" "n" "ssd_help"
2330      -    [ "$?" -eq 0 ] && return
     2829 +        while : ; do
     2830 +                get_menu_choice "${ASK}" 0 ${MAX} 1 ${HELPTAG} ${MENU}
     2831 +                RES=$?
     2832 +                if (( RES )); then
     2833 +                        M=${AUTH_METHODS[RES - OFFSET]}
     2834 +                        # avoid doubles
     2835 +                        [[ ${VAL} != ~(E)[ ]${M}[ ] ]] && SELECTED+=( ${M} )
     2836 +                        VAL=" ${SELECTED[@]} "
     2837 +                        M=${VAL// /\;}
     2838 +                        M=${M#\;}
     2839 +                else
     2840 +                        typeset -a SELECTED=( )         # reset
     2841 +                        VAL=''
     2842 +                        M=''
     2843 +                fi
     2844 +                print && Log.info "Current authentication method(s): ${M%\;}\n"
2331 2845  
2332      -    # Display menu for SSD choices.
2333      -    while :
2334      -    do
2335      -        display_msg prompt_ssd_menu
2336      -        get_ans "Enter menu choice:" "Quit"
2337      -        case "$ANS" in
2338      -            [Aa] | add) add_ssd ;;
2339      -            [Dd] | delete) delete_ssd ;;
2340      -            [Mm] | modify) modify_ssd ;;
2341      -            [Pp] | print | display) display_ssd ;;
2342      -            [Xx] | reset | clear) reset_ssd_file ;;
2343      -            [Hh] | Help | help) display_msg ssd_menu_help 
2344      -                                ${ECHO} " Press return to continue."
2345      -                                read __A ;;
2346      -            [Qq] | Quit | quit) return ;;
2347      -            *)    ${ECHO} "Invalid choice: $ANS please re-enter from menu." ;;
2348      -        esac
2349      -    done
     2846 +                get_confirm_nodef "Do you want to add another ${UTYPE} authentication method (y/n)?" \
     2847 +                        && break
     2848 +        done
     2849 +        M=${M%\;}
     2850 +        if (( ! OFFSET )); then
     2851 +                M=${M//\;/\;${TYPE}:}
     2852 +                if [[ -n ${M} ]]; then
     2853 +                        STR[${VNAME}]="${TYPE}:${M}"
     2854 +                else
     2855 +                        STR[${VNAME}]=''
     2856 +                        INT[NEED_SRVAUTH_${TYPE##*_}]=0
     2857 +                fi
     2858 +        else
     2859 +                STR[${VNAME}]="${M}"
     2860 +        fi
     2861 +        Log.verbose "Selected ${UTYPE} authentication methods: '${STR[${VNAME}]}'"
     2862 +        return 0
2350 2863  }
2351 2864  
     2865 +Man.addFunc get_followref '' '[+NAME?get_followref - Ask user whether or not to follow referrals.]
     2866 +[+DESCRIPTION?Ask the user whether the client should follow referrals. Result gets stored into \bINT[LDAP_FOLLOWREF]]\b.]
     2867 +[+SEE ALSO?\bget_confirm()\b, \bldapclient\b(1M).]
     2868 +'
     2869 +function get_followref {
     2870 +        get_confirm 'Do you want the clients to follow referrals (y/n/h)?' 'n' \
     2871 +                'referrals_help'
     2872 +        INT[LDAP_FOLLOWREF]=$?
     2873 +}
2352 2874  
2353      -#
2354      -# reset_ssd_file(): Blank out current SSD file.
2355      -#
2356      -reset_ssd_file()
2357      -{
2358      -    [ $DEBUG -eq 1 ] && ${ECHO} "In reset_ssd_file()"
2359      -    
2360      -    rm -f ${SSD_FILE}
2361      -    touch ${SSD_FILE}
     2875 +Man.addFunc get_timelimit '' '[+NAME?get_timelimit - Ask user for search time limit.]
     2876 +[+DESCRIPTION?Ask the user for the max. time allowed to process a search operation and store it into \bINT[DS_TIMELIMIT]]\b.]
     2877 +[+RETURN VALUES]{
     2878 +        [+0?on success.]
     2879 +        [+>= 66?a fatal error occured.]
2362 2880  }
     2881 +[+SEE ALSO?\bis_numeric()\b, \bget_negone_num()\b.]
     2882 +'
     2883 +function get_timelimit {
     2884 +        typeset NAME='nsslapd-timelimit' VAL=''
     2885 +        (( TMPF[IS_OPENDJ] )) && NAME='ds-cfg-time-limit'       # min val = 0
2363 2886  
     2887 +        # Get current timeout value from cn=config
     2888 +        ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b 'cn=config' -s base \
     2889 +                'objectclass=*' "${NAME}" 2>/dev/null | \
     2890 +        while read LINE; do
     2891 +                if [[ ${LINE%%=*} == ${NAME} ]]; then
     2892 +                        VAL=${LINE#*=}
     2893 +                        break
     2894 +                fi
     2895 +        done
     2896 +        if [[ -z ${VAL} ]]; then
     2897 +                Log.fatal 'Unable to check current search processing timeout of the DS'
     2898 +                return 66
     2899 +        fi
     2900 +        VAL=${VAL%%[[:space:]]*}
     2901 +        is_numeric ${VAL} && NUM=${VAL} || NUM=INT[DS_TIMELIMIT]
     2902 +    
     2903 +        get_negone_num "Enter the DS search processing time limit in seconds (current=${NUM})" \
     2904 +                '30'
     2905 +        (( TMPF[IS_OPENDJ] && NUM < 0 )) && NUM=0       # unlimited
2364 2906  
2365      -#
2366      -# create_ssd_file(): Create a temporary file for SSD's.
2367      -#
2368      -create_ssd_file()
2369      -{
2370      -    [ $DEBUG -eq 1 ] && ${ECHO} "In create_ssd_file()"
     2907 +        INT[DS_TIMELIMIT]=${NUM}
     2908 +        return 0
     2909 +}
2371 2910  
2372      -    # Build a list of SSD's and store in temp file.
2373      -    ${GREP} "LDAP_SERV_SRCH_DES=" ${INPUT_FILE} | \
2374      -        sed 's/LDAP_SERV_SRCH_DES=//' \
2375      -        > ${SSD_FILE}
     2911 +Man.addFunc get_sizelimit '' '[+NAME?get_sizelimit - Ask user for search size limit.]
     2912 +[+DESCRIPTION?Ask the user for the max. number of entries to return for a single search operation and store it into \bINT[DS_SIZELIMIT]]\b.]
     2913 +[+RETURN VALUES]{
     2914 +        [+0?on success.]
     2915 +        [+>= 66?a fatal error occured.]
2376 2916  }
     2917 +[+SEE ALSO?\bis_numeric()\b, \bget_negone_num()\b.]
     2918 +'
     2919 +function get_sizelimit {
     2920 +        typeset NAME='nsslapd-sizelimit' VAL=''
     2921 +        (( TMPF[IS_OPENDJ] )) && NAME='ds-cfg-size-limit'       # min val = 0
2377 2922  
     2923 +        # Get current search sizelimit
     2924 +        ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b 'cn=config' -s base \
     2925 +                'objectclass=*' "${NAME}" 2>/dev/null | \
     2926 +        while read LINE; do
     2927 +                if [[ ${LINE%%=*} == ${NAME} ]]; then
     2928 +                        VAL=${LINE#*=}
     2929 +                        break
     2930 +                fi
     2931 +        done
     2932 +        if [[ -z ${VAL} ]]; then
     2933 +                Log.fatal 'Unable to check current search entry result limit of the DS'
     2934 +                return 66
     2935 +        fi
     2936 +        is_numeric ${VAL} && NUM=${VAL} || NUM=INT[DS_SIZELIMIT]
2378 2937  
2379      -#
2380      -# ssd_2_config(): Append the SSD file to the output file.
2381      -#
2382      -ssd_2_config()
2383      -{
2384      -    [ $DEBUG -eq 1 ] && ${ECHO} "In ssd_2_config()"
2385      -    
2386      -    # Convert to config file format using sed.
2387      -    sed -e "s/^/LDAP_SERV_SRCH_DES=/" ${SSD_FILE} >> ${OUTPUT_FILE}
     2938 +        get_negone_num "Enter max. entries per search the DS returns (current=${NUM})" '1000'
     2939 +        (( TMPF[IS_OPENDJ] && NUM < 0 )) && NUM=0       # unlimited
     2940 +        INT[DS_SIZELIMIT]=${NUM}
     2941 +        return 0
2388 2942  }
2389 2943  
     2944 +Man.addFunc get_want_crypt '' '[+NAME?get_want_crypt - Ask user whether to store passwords in crypt.]
     2945 +[+DESCRIPTION?Ask the user whether the default password storage scheme should be set to "CRYPT" and stores the result into \bINT[NEED_CRYPT]]\b.]
     2946 +[+SEE ALSO?\bget_confirm()\b.]
     2947 +'
     2948 +function get_want_crypt {
     2949 +        get_confirm 'Do you want to store passwords in "CRYPT" formats (y/n/h)?' \
     2950 +                'n' 'crypt_help'
     2951 +        INT[NEED_CRYPT]=$?
     2952 +}
2390 2953  
2391      -#
2392      -# ssd_2_profile(): Add SSD's to the GEN_CMD string.
2393      -#
2394      -ssd_2_profile()
2395      -{
2396      -    [ $DEBUG -eq 1 ] && ${ECHO} "In ssd_2_profile()"
     2954 +Man.addFunc get_srch_time '' '[+NAME?get_srch_time - Ask user for client search time limit.]
     2955 +[+DESCRIPTION?Ask the user for the max. time in seconds a client waits for a search result and store it into \bINT[LDAP_SEARCH_TIME_LIMIT]]\b.]
     2956 +[+SEE ALSO?\bget_negone_num()\b, \bldapclient\b(1M).]
     2957 +'
     2958 +function get_srch_time {
     2959 +        get_negone_num 'Client search time limit in seconds (h=help):' \
     2960 +                ${INT[LDAP_SEARCH_TIME_LIMIT]} 'srchtime_help'
     2961 +        INT[LDAP_SEARCH_TIME_LIMIT]=${NUM}
     2962 +}
2397 2963  
2398      -    GEN_TMPFILE=${TMPDIR}/ssd_tmpfile
2399      -    touch ${GEN_TMPFILE}
2400      -
2401      -    # Add and convert each SSD to string.
2402      -    while read SSD_LINE
2403      -    do
2404      -        ${ECHO} " -a \"serviceSearchDescriptor=${SSD_LINE}\"\c" >> ${GEN_TMPFILE}
2405      -    done <${SSD_FILE}
2406      -
2407      -    # Add SSD's to GEN_CMD.
2408      -    GEN_CMD="${GEN_CMD} `cat ${GEN_TMPFILE}`"
     2964 +Man.addFunc get_prof_ttl '' '[+NAME?get_prof_ttl - Ask user for client profile time to live (TTL).]
     2965 +[+DESCRIPTION?Ask the user for the max. time in seconds a client may cache its profile before refreshing again and store it into \bINT[LDAP_PROFILE_TTL]]\b.]
     2966 +[+SEE ALSO?\bget_negone_num()\b, \bldapclient\b(1M).]
     2967 +'
     2968 +function get_prof_ttl {
     2969 +        get_negone_num 'Client Profile Time To Live in seconds (h=help):' \
     2970 +                ${INT[LDAP_PROFILE_TTL]} 'profttl_help'
     2971 +        INT[LDAP_PROFILE_TTL]=${NUM}
2409 2972  }
2410 2973  
2411      -#
2412      -# get_adminDN(): Get the admin DN.
2413      -#
2414      -get_adminDN()
2415      -{
2416      -    LDAP_ADMINDN="cn=admin,ou=profile,${LDAP_BASEDN}"  # default
2417      -    get_ans "Enter DN for the administrator:" "$LDAP_ADMINDN"
2418      -    LDAP_ADMINDN=$ANS
2419      -    [ $DEBUG -eq 1 ] && ${ECHO} "LDAP_ADMINDN = $LDAP_ADMINDN"
     2974 +Man.addFunc get_bind_limit '' '[+NAME?get_bind_limit - Ask user for client bind time limit.]
     2975 +[+DESCRIPTION?Ask the user for the max. time in seconds a client may try to bind to the server and store it into \bINT[LDAP_BIND_LIMIT]]\b.]
     2976 +[+SEE ALSO?\bget_negone_num()\b, \bldapclient\b(1M).]
     2977 +'
     2978 +function get_bind_limit {
     2979 +        get_negone_num 'Client bind time limit in seconds (h=help):' \
     2980 +                ${INT[LDAP_BIND_LIMIT]} 'bindlim_help'
     2981 +        INT[LDAP_BIND_LIMIT]=${NUM}
2420 2982  }
2421 2983  
2422      -#
2423      -# get_admin_pw(): Get the admin passwd.
2424      -#
2425      -get_admin_pw()
2426      -{
2427      -    get_passwd "Enter passwd for the administrator:"
2428      -    LDAP_ADMIN_CRED=$ANS
2429      -    [ $DEBUG -eq 1 ] && ${ECHO} "LDAP_ADMIN_CRED = $LDAP_ADMIN_CRED"
     2984 +Man.addFunc get_want_shadow_update '' '[+NAME?get_want_shadow_update - Ask user whether to enable shadow update.]
     2985 +[+DESCRIPTION?Ask the user whether to enable shadow update. Set \bINT[LDAP_ENABLE_SHADOW_UPDATE]]\b to 0 if not desired, to 1 otherwise.]
     2986 +[+SEE ALSO?\bget_confirm()\b.]
     2987 +'
     2988 +function get_want_shadow_update {
     2989 +        get_confirm 'Do you want to enable shadow update (y/n/h)?' 'n' \
     2990 +                'enable_shadow_update_help'
     2991 +        INT[LDAP_ENABLE_SHADOW_UPDATE]=$?
2430 2992  }
2431 2993  
2432      -#
2433      -# add_admin(): Add an admin entry for nameservice for updating shadow data.
2434      -#
2435      -add_admin()
2436      -{
2437      -    [ $DEBUG -eq 1 ] && ${ECHO} "In add_admin()"
     2994 +        ######################################################################
     2995 +        # FUNCTIONS  FOR Service Search Descriptor's START HERE.
     2996 +        ######################################################################
     2997 +Man.addFunc add_ssd '' '[+NAME?add_ssd - Ask user for SSD to add.]
     2998 +[+DESCRIPTION?Ask the user for the ID:BASE:SCOPE and add it to \bSSD\b list.]
     2999 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage SSD ; }" '}
     3000 +[+SEE ALSO?\bget_ans\b, \bget_ans_req()\b.]
     3001 +'
     3002 +function add_ssd {
     3003 +        typeset ID='' BASE='' X
     3004 +        typeset -l SCOPE=''
     3005 +        integer FOUND
2438 3006  
2439      -    # Check if the admin user already exists.
2440      -    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_ADMINDN}\" -s base \"objectclass=*\" ${VERB}"
2441      -    if [ $? -eq 0 ]; then
2442      -        MSG="Administrator ${LDAP_ADMINDN} already exists."
2443      -        if [ $EXISTING_PROFILE -eq 1 ]; then
2444      -            ${ECHO} "  NOT ADDED: $MSG"
2445      -        else
2446      -            ${ECHO} "  ${STEP}. $MSG"
2447      -            STEP=`expr $STEP + 1`       
2448      -        fi
2449      -        return 0
2450      -    fi
     3007 +        while : ; do
     3008 +                get_ans 'Enter the service name (e.g. passwd):'
     3009 +                [[ -z ${ANS} ]] && return
     3010 +                [[ ${ANS} =~ [:] ]] && print 'Invalid service name' && continue
2451 3011  
2452      -    # Get cn and sn names from LDAP_ADMINDN.
2453      -    cn_tmp=`${ECHO} ${LDAP_ADMINDN} | cut -f1 -d, | cut -f2 -d=`
2454      -
2455      -    # Create the tmp file to add.
2456      -    ( cat <<EOF
2457      -dn: ${LDAP_ADMINDN}
2458      -cn: ${cn_tmp}
2459      -sn: ${cn_tmp}
2460      -objectclass: top
2461      -objectclass: person
2462      -userpassword: ${LDAP_ADMIN_CRED}
2463      -EOF
2464      -) > ${TMPDIR}/admin
     3012 +                FOUND=0
     3013 +                for X  in "${SSD[@]}" ; do
     3014 +                        [[ ${X%%:*} == ${ANS} ]] && FOUND=1 && break
     3015 +                done
     3016 +                (( ! FOUND )) && break
     3017 +                Log.warn "An SSD for '${ANS}' already exists:\n${X}\n"
     3018 +        done
     3019 +        ID="${ANS}"
2465 3020      
2466      -    # Add the entry.
2467      -    ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/admin ${VERB}"
2468      -    if [ $? -ne 0 ]; then
2469      -        ${ECHO} "  ERROR: Adding administrator identity failed!"
2470      -        cleanup
2471      -        exit 1
2472      -    fi
     3021 +        while : ; do
     3022 +                get_ans_req 'Enter the search base (e.g. ou=people,o=inet):'
     3023 +                [[ ${ANS} != ~(E)[:] ]] && break
     3024 +                Log.warn 'Invalid search base' && continue
     3025 +        done
     3026 +        BASE="${ANS}"
2473 3027  
2474      -    ${RM} -f ${TMPDIR}/admin
     3028 +        while : ; do
     3029 +                get_ans_req "Enter the search scope (one|sub):"
     3030 +                SCOPE=${ANS}
     3031 +                [[ ${SCOPE} == 'one' || ${SCOPE} == 'sub' ]] && break
     3032 +                Log.warn "'${ANS}' is NOT valid - Enter 'one' or 'sub'"
     3033 +        done
2475 3034  
2476      -    # Display message that the administrator identity is added.
2477      -    MSG="Administrator identity ${LDAP_ADMINDN}"
2478      -    if [ $EXISTING_PROFILE -eq 1 ]; then
2479      -        ${ECHO} "  ADDED: $MSG."
2480      -    else
2481      -        ${ECHO} "  ${STEP}. $MSG added."
2482      -        STEP=`expr $STEP + 1`
2483      -    fi
     3035 +        SSD+=( "${ID}:${BASE}?${SCOPE}" )
2484 3036  }
2485 3037  
2486      -#
2487      -# allow_admin_read_write_shadow(): Give Admin read/write permission
2488      -# to shadow data.
2489      -#
2490      -allow_admin_read_write_shadow()
2491      -{
2492      -    [ $DEBUG -eq 1 ] && ${ECHO} "In allow_admin_read_write_shadow()"
     3038 +Man.addFunc delete_ssd '' '[+NAME?delete_ssd - Ask user which SSD to delete.]
     3039 +[+DESCRIPTION?Ask the user for the ID of the SSD to delete and remove it from \bSSD\b list.]
     3040 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage SSD ; }" '}
     3041 +[+SEE ALSO?\bget_ans()\b.]
     3042 +'
     3043 +function delete_ssd {
     3044 +        get_ans 'Enter the service name of the SSD to delete (e.g. passwd):'
     3045 +        [[ -z ${ANS} ]] && return
2493 3046  
2494      -    # Set ACI Name
2495      -    ADMIN_ACI_NAME="LDAP_Naming_Services_admin_shadow_write"
     3047 +        typeset X
     3048 +        integer I FOUND=-1 MAX=${#SSD[@]}
2496 3049  
2497      -    # Search for ACI_NAME
2498      -    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" \
2499      -    -s base objectclass=* aci > ${TMPDIR}/chk_adminwrite_aci 2>&1"
2500      -
2501      -    # if an ACI with ${ADMIN_ACI_NAME} and "write,compare,read,search"
2502      -    # and ${LDAP_ADMINDN} already exists, we are done
2503      -    ${EGREP} ".*${ADMIN_ACI_NAME}.*write,compare,read,search.*${LDAP_ADMINDN}.*" \
2504      -        ${TMPDIR}/chk_adminwrite_aci 2>&1 > /dev/null
2505      -    if [ $? -eq 0 ]; then
2506      -        MSG="Admin ACI ${ADMIN_ACI_NAME} already exists for ${LDAP_BASEDN}."
2507      -        if [ $EXISTING_PROFILE -eq 1 ]; then
2508      -            ${ECHO} "  NOT SET: $MSG"
2509      -        else
2510      -            ${ECHO} "  ${STEP}. $MSG"
2511      -            STEP=`expr $STEP + 1`       
     3050 +        for (( I=0; I < MAX ; I++ )); do
     3051 +                X=${SSD[I]}
     3052 +                [[ ${X%%:*} == ${ANS} ]] && FOUND=$I && break
     3053 +        done
     3054 +        if (( FOUND == -1 )); then
     3055 +                Log.warn "Invalid service name: '${ANS}' not present in list"
     3056 +                return
2512 3057          fi
2513      -        return 0
2514      -    fi
     3058 +        (( FOUND == 0 )) && unset SSD[0] && return
2515 3059  
2516      -    # If an ACI with ${ADMIN_ACI_NAME} and "(write)" and ${LDAP_ADMINDN}
2517      -    # already exists, delete it first.
2518      -    find_and_delete_ACI ".*${ADMIN_ACI_NAME}.*(write).*${LDAP_ADMINDN}.*" \
2519      -        ${TMPDIR}/chk_adminwrite_aci ${ADMIN_ACI_NAME}
     3060 +        # need to do a little bit more, since ksh allows to remove the 1st entry,
     3061 +        # only (i.e. like "shift 1" for positional params)
     3062 +        for (( I=FOUND; I > 0; I-- )); do
     3063 +                SSD[${I}]="${SSD[I-1]}"
     3064 +        done
     3065 +        unset SSD[0]
     3066 +}
2520 3067  
2521      -    # Create the tmp file to add.
2522      -    ( cat <<EOF
2523      -dn: ${LDAP_BASEDN}
2524      -changetype: modify
2525      -add: aci
2526      -aci: (target="ldap:///${LDAP_BASEDN}")(targetattr="shadowLastChange
2527      - ||shadowMin||shadowMax||shadowWarning||shadowInactive||shadowExpire
2528      - ||shadowFlag||userPassword||loginShell||homeDirectory||gecos")
2529      -  (version 3.0; acl ${ADMIN_ACI_NAME}; allow (write,compare,read,search)
2530      -  userdn = "ldap:///${LDAP_ADMINDN}";)
2531      -EOF
2532      -) > ${TMPDIR}/admin_write
     3068 +Man.addFunc modify_ssd '' '[+NAME?modify_ssd - Allow user to modify an SSD.]
     3069 +[+DESCRIPTION?Ask the user for the ID of the SSD to modify, let the user modify it and finally save changes back to the \bSSD\b list.]
     3070 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage SSD ; }" '}
     3071 +[+SEE ALSO?\bget_ans()\b, \bread\b(1).]
     3072 +'
     3073 +function modify_ssd {
     3074 +        get_ans 'Enter the service name of the SSD to modify:'
     3075 +        [[ -z ${ANS} ]] && return
2533 3076      
2534      -    # Add the entry.
2535      -    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/admin_write ${VERB}"
2536      -    if [ $? -ne 0 ]; then
2537      -        ${ECHO} "  ERROR: Allow ${LDAP_ADMINDN} read/write access to shadow data failed!"
2538      -        cleanup
2539      -        exit 1
2540      -    fi
     3077 +        typeset ID BASE
     3078 +        typeset -l SCOPE
     3079 +        integer I FOUND=-1 MAX=${#SSD[@]}
     3080 +        for (( I=0; I < MAX ; I++ )); do
     3081 +                X=${SSD[I]}
     3082 +                [[ ${X%%:*} == ${ANS} ]] && FOUND=$I && break
     3083 +        done
     3084 +        if (( FOUND == -1 )); then
     3085 +                Log.warn "Invalid service name: '${ANS}'"
     3086 +                return 0
     3087 +        fi
2541 3088  
2542      -    ${RM} -f ${TMPDIR}/admin_write
2543      -    # Display message that the administrator ACL is set.
2544      -    MSG="Give ${LDAP_ADMINDN} read/write access to shadow data."
2545      -    if [ $EXISTING_PROFILE -eq 1 ]; then
2546      -        ${ECHO} "  ACI SET: $MSG"
2547      -    else
2548      -        ${ECHO} "  ${STEP}. $MSG"
2549      -        STEP=`expr $STEP + 1`
2550      -    fi
2551      -}
     3089 +        # most users expect emacs edit behavior (don't have a proper profile)
     3090 +        set -o emacs
     3091 +        read -v X?'Current SSD: '
2552 3092  
2553      -#
2554      -# allow_host_read_write_shadow(): Give host principal read/write permission
2555      -# for shadow data.
2556      -#
2557      -allow_host_read_write_shadow()
2558      -{
2559      -    [ $DEBUG -eq 1 ] && ${ECHO} "In allow_host_read_write_shadow()"
2560      -
2561      -    # Set ACI Name
2562      -    HOST_ACI_NAME="LDAP_Naming_Services_host_shadow_write"
2563      -
2564      -    # Search for ACI_NAME
2565      -    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_hostwrite_aci 2>&1"
2566      -    ${GREP} "${HOST_ACI_NAME}" ${TMPDIR}/chk_hostwrite_aci > /dev/null 2>&1
2567      -    if [ $? -eq 0 ]; then
2568      -        MSG="Host ACI ${HOST_ACI_NAME} already exists for ${LDAP_BASEDN}."
2569      -        if [ $EXISTING_PROFILE -eq 1 ]; then
2570      -            ${ECHO} "  NOT ADDED: $MSG"
2571      -        else
2572      -            ${ECHO} "  ${STEP}. $MSG"
2573      -            STEP=`expr $STEP + 1`
     3093 +        # now verify
     3094 +        ID=${X%%:*}
     3095 +        BASE=${.sh.match#:}
     3096 +        SCOPE=${BASE#*$'?'}
     3097 +        BASE=${.sh.match%$'?'}
     3098 +        if [[ -z ${ID} || -z ${BASE} || -z ${SCOPE} ]] || \
     3099 +                [[ ${SCOPE} != 'one' && ${SCOPE} != 'sub' ]]
     3100 +        then
     3101 +                Log.warn 'SSD is invalid. Change skipped'
     3102 +                return
2574 3103          fi
2575      -        return 0
2576      -    fi
     3104 +        SSD[${FOUND}]="${ID}:${BASE}?${SCOPE}"
     3105 +}
2577 3106  
2578      -    # Create the tmp file to add.
2579      -    ( cat <<EOF
2580      -dn: ${LDAP_BASEDN}
2581      -changetype: modify
2582      -add: aci
2583      -aci: (target="ldap:///${LDAP_BASEDN}")(targetattr="shadowLastChange||shadowMin||shadowMax||shadowWarning||shadowInactive||shadowExpire||shadowFlag||userPassword||loginShell||homeDirectory||gecos")(version 3.0; acl ${HOST_ACI_NAME}; allow (write,compare,read,search) authmethod="sasl GSSAPI" and userdn = "ldap:///cn=*+ipHostNumber=*,ou=Hosts,${LDAP_BASEDN}";)
2584      -EOF
2585      -) > ${TMPDIR}/host_read_write
2586      -    
2587      -    # Add the entry.
2588      -    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/host_read_write ${VERB}"
2589      -    if [ $? -ne 0 ]; then
2590      -        ${ECHO} "  ERROR: Allow Host Principal to write shadow data failed!"
2591      -        cleanup
2592      -        exit 1
2593      -    fi
     3107 +Man.addFunc reset_ssd '' '[+NAME?reset_ssd - Blank out current list of SSDs.]
     3108 +[+DESCRIPTION?Clear the \bSSD\b array.]
     3109 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage SSD ; }" '}
     3110 +'
     3111 +function reset_ssd {
     3112 +    SSD=( )
     3113 +        unset SSD[0]    # required otherwise it would contain a single '\n'. Bug?
     3114 +}
2594 3115  
2595      -    ${RM} -f ${TMPDIR}/host_read_write
2596      -    MSG="Give host principal read/write permission for shadow."
2597      -    if [ $EXISTING_PROFILE -eq 1 ]; then
2598      -        ${ECHO} "  ACI SET: $MSG"
2599      -    else
2600      -        ${ECHO} "  ${STEP}. $MSG"
2601      -        STEP=`expr $STEP + 1`
2602      -    fi
     3116 +Man.addFunc display_ssd '' '[+NAME?display_ssd -  Display current SSD list.]
     3117 +[+DESCRIPTION?Display the current \bSSD\b list and return, when the user hit the enter key.]
     3118 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage SSD ; }" '}
     3119 +'
     3120 +function display_ssd {
     3121 +        typeset X
     3122 +        print '
     3123 +Current Service Search Descriptors:
     3124 +=================================='
     3125 +        for X in "${SSD[@]}" ; do
     3126 +                print "  ${X}"
     3127 +        done
     3128 +    print '\nHit return to continue.'
     3129 +        read
2603 3130  }
2604 3131  
2605      -#
2606      -# Set up shadow update
2607      -#
2608      -setup_shadow_update() {
2609      -    [ $DEBUG -eq 1 ] && ${ECHO} "In setup_shadow_update()"
2610      -
2611      -    # get content of the profile
2612      -    PROFILE_OUT=${TMPDIR}/prof_tmpfile
2613      -    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${LDAP_PROFILE_NAME},ou=profile,${LDAP_BASEDN}\" -s base \"objectclass=*\" > $PROFILE_OUT 2>&1"
2614      -    ${GREP} -i cn $PROFILE_OUT >/dev/null 2>&1
2615      -    if [ $? -ne 0 ]; then
2616      -        [ $DEBUG -eq 1 ] && ${ECHO} "Profile ${LDAP_PROFILE_NAME} does not exist"
2617      -        ${RM} ${PROFILE_OUT}
2618      -        return
2619      -    fi
2620      -
2621      -    # Search to see if authenticationMethod has 'GSSAPI' and
2622      -    # credentialLevel has 'self'. If so, ask to use the
2623      -    # host principal for shadow update
2624      -    if [ $GSSAPI_AUTH_MAY_BE_USED -eq 1 ]; then
2625      -        if ${GREP} authenticationMethod $PROFILE_OUT | ${GREP} GSSAPI >/dev/null 2>&1
     3132 +Man.addFunc prompt_ssd '' '[+NAME?prompt_ssd - Get SSDs from user.]
     3133 +[+DESCRIPTION?Ask the user whether to add/delete/modify/display one or more SSDs currently set and execute the corresponding action.]
     3134 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage ANS ; }" '}
     3135 +[+SEE ALSO?\bdisplay_msg()\b, \bget_ans()\b, \badd_ssd()\b, \bdelete_ssd()\b, \bmodify_ssd()\b, \bdisplay_ssd()\b, \breset_ssd()\b.]
     3136 +'
     3137 +function prompt_ssd {
     3138 +        if get_confirm 'Do you wish to setup Service Search Descriptors (y/n/h)?' \
     3139 +                'n' 'ssd_help'
2626 3140          then
2627      -            if ${GREP} credentialLevel $PROFILE_OUT | ${GREP} self >/dev/null 2>&1
2628      -            then
2629      -                NEED_HOSTACL=1
2630      -            fi
     3141 +                return
2631 3142          fi
2632      -        ${RM} ${PROFILE_OUT}
2633      -        [ $DEBUG -eq 1 ] && ${ECHO} "NEED_HOSTACL = $NEED_HOSTACL"
2634 3143  
2635      -        if [ $NEED_HOSTACL -eq 1 ]; then
2636      -            MSG="Use host principal for shadow data update (y/n/h)?"
2637      -            get_confirm "$MSG" "y" "use_host_principal_help"
2638      -            if [ $? -eq 1 ]; then
2639      -                delete_proxy_read_pw
2640      -                allow_host_read_write_shadow
2641      -                deny_non_host_shadow_access
2642      -                ${ECHO} ""
2643      -                ${ECHO} "  Shadow update has been enabled."
2644      -            else
2645      -                ${ECHO} ""
2646      -                ${ECHO} "  Shadow update may not work."
2647      -            fi
2648      -            return
2649      -        fi
2650      -    fi
     3144 +        # Display menu for SSD choices
     3145 +        while : ; do
     3146 +                display_msg prompt_ssd_menu
     3147 +                get_ans 'Enter menu choice:' 'Quit'
     3148 +                case "${ANS}" in
     3149 +                        [Qq] | Quit | quit)             return ;;
     3150 +                        [Aa] | add)                             add_ssd ;;
     3151 +                        [Dd] | delete)                  delete_ssd ;;
     3152 +                        [Mm] | modify)                  modify_ssd ;;
     3153 +                        [Pp] | print | display) display_ssd ;;
     3154 +                        [Xx] | reset | clear)   reset_ssd ;;
     3155 +                        [Hh] | Help | help)
     3156 +                                display_msg 'ssd_menu_help '
     3157 +                                print ' Press return to continue.'
     3158 +                                read
     3159 +                                ;;
     3160 +                        *) Log.warn "Invalid choice: '${ANS}' please re-enter from menu!" ;;
     3161 +                esac
     3162 +        done
     3163 +}
2651 3164  
2652      -    MSG="Add the administrator identity (y/n/h)?"
2653      -    get_confirm "$MSG" "y" "add_admin_cred_help"
2654      -    if [ $? -eq 1 ]; then
2655      -        get_adminDN
2656      -        get_admin_pw
2657      -        add_admin
2658      -        delete_proxy_read_pw
2659      -        allow_admin_read_write_shadow
2660      -        deny_non_admin_shadow_access
2661      -        ${ECHO} ""
2662      -        ${ECHO} "  Shadow update has been enabled."
2663      -        return
2664      -    fi
2665      -
2666      -    ${ECHO} "  No administrator identity specified, shadow update may not work."
     3165 +        ######################################################################
     3166 +        # End Of FUNCTIONS FOR Service Search Descriptor's
     3167 +        ######################################################################
     3168 +Man.addFunc prompt_config_info '' '[+NAME?prompt_config_info - Ask user for missing config info.]
     3169 +[+DESCRIPTION?Ask the user for the config info not yet available/read from an '"${PROG}"' config file.]
     3170 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage INT STR SSD ; }" '}
     3171 +[+RETURN VALUES]{
     3172 +        [+0?on success (all info aquired).]
     3173 +        [+>= 66?a fatal error occured.]
2667 3174  }
     3175 +'
     3176 +function prompt_config_info {
     3177 +        # Prompt for DS server name
     3178 +        get_ids_server
2668 3179  
     3180 +        # Prompt for DS port number
     3181 +        get_ids_port
2669 3182  
2670      -#
2671      -# prompt_config_info(): This function prompts the user for the config
2672      -# info that is not specified in the input file.  
2673      -#
2674      -prompt_config_info()
2675      -{
2676      -    [ $DEBUG -eq 1 ] && ${ECHO} "In prompt_config_info()"
     3183 +        # Check DS version for compatibility
     3184 +        chk_ids_version || return 66
2677 3185  
2678      -    # Prompt for iDS server name.
2679      -    get_ids_server
     3186 +        # Check if the DS supports the VLV
     3187 +        chk_vlv_indexes || return 67
2680 3188  
2681      -    # Prompt for iDS port number.
2682      -    get_ids_port
     3189 +        # Get the Directory manager DN and passwd
     3190 +        get_dirmgr_dn
     3191 +        get_dirmgr_pw
2683 3192  
2684      -    # Check iDS version for compatibility.
2685      -    chk_ids_version
     3193 +        get_confirm 'Do you want to modify the DS timelimit for processing searches (y/n/h)?' 'n' 'tlim_help'
     3194 +        INT[NEED_TIME]=$?
     3195 +        if (( INT[NEED_TIME] )); then
     3196 +                get_timelimit || return 70
     3197 +        fi
2686 3198  
2687      -    # Check if the server supports the VLV.
2688      -    chk_vlv_indexes
     3199 +        get_confirm 'Do you want to modify the DS sizelimit - max. entries to return (y/n/h)?' 'n' 'slim_help'
     3200 +        INT[NEED_SIZE]=$?
     3201 +        if (( INT[NEED_SIZE] )); then
     3202 +                get_sizelimit || return 71
     3203 +        fi
2689 3204  
2690      -    # Get the Directory manager DN and passwd.
2691      -    get_dirmgr_dn
2692      -    get_dirmgr_pw
2693 3205  
2694      -    #
2695      -    # LDAP CLIENT PROFILE SPECIFIC INFORMATION.
2696      -    #   (i.e. The fields that show up in the profile.)
2697      -    #
2698      -    get_domain "domain_help"
     3206 +        # LDAP CLIENT PROFILE SPECIFIC INFORMATION
     3207 +        #   (i.e. the fields that show up in the profile)
     3208 +        get_domain
     3209 +        get_basedn || return 68
2699 3210  
2700      -    get_basedn
2701      -
     3211 +        # Check/Get Kerberos infos
2702 3212      gssapi_setup
2703 3213  
2704 3214      get_profile_name
2705 3215  
2706      -    if [ "$LDAP_ENABLE_SHADOW_UPDATE" = "TRUE" ];then
2707      -        setup_shadow_update
2708      -        cleanup
2709      -        exit 0
2710      -    fi
     3216 +        if (( INT[LDAP_ENABLE_SHADOW_UPDATE] ));then
     3217 +                setup_shadow_update || return 69
     3218 +                return 0
     3219 +        fi
2711 3220  
2712      -    get_srv_list
2713      -    get_pref_srv
2714      -    get_search_scope
2715      -
2716      -    # If cred is "anonymous", make auth == "none"
2717      -    get_cred_level
2718      -    if [ "$LDAP_CRED_LEVEL" != "anonymous" ]; then
2719      -        get_auth
2720      -    fi
2721      -
     3221 +        get_srv_list
     3222 +        get_pref_srv
     3223 +        get_search_scope
2722 3224      get_followref
2723 3225  
2724      -    # Query user about timelimt.
2725      -    get_confirm "Do you want to modify the server timelimit value (y/n/h)?" "n" "tlim_help"
2726      -    NEED_TIME=$?
2727      -    [ $NEED_TIME -eq 1 ] && get_timelimit
     3226 +        # Store passwords in crypt format?
     3227 +        get_want_crypt
2728 3228  
2729      -    # Query user about sizelimit.
2730      -    get_confirm "Do you want to modify the server sizelimit value (y/n/h)?" "n" "slim_help"
2731      -    NEED_SIZE=$?
2732      -    [ $NEED_SIZE -eq 1 ] && get_sizelimit
     3229 +        # If cred is "anonymous", make auth == "none"
     3230 +        get_cred_level
     3231 +        [[ ${STR[LDAP_CRED_LEVEL]} != anonymous ]] && get_auth 'client'
2733 3232  
2734      -    # Does the user want to store passwords in crypt format?
2735      -    get_want_crypt
     3233 +        get_confirm 'Do you want to setup any non-default Authentication Methods (y/n/h)?' 'n' 'srvauth_help'
     3234 +        if (( $? )); then
     3235 +                get_confirm 'Do you want to setup Authentication Methods for "pam_ldap" (y/n/h)?' 'n' 'pam_ldap_help'
     3236 +                INT[NEED_SRVAUTH_PAM]=$?
     3237 +                (( INT[NEED_SRVAUTH_PAM] )) && get_auth 'pam_ldap'
2736 3238  
2737      -    # Prompt for any Service Authentication Methods?
2738      -    get_confirm "Do you want to setup a Service Authentication Methods (y/n/h)?" "n" "srvauth_help"
2739      -    if [ $? -eq 1 ]; then
2740      -        # Does the user want to set Service Authentication Method for pam_ldap?
2741      -        get_confirm "Do you want to setup a Service Auth. Method for \"pam_ldap\" (y/n/h)?" "n" "pam_ldap_help"
2742      -        NEED_SRVAUTH_PAM=$?
2743      -        [ $NEED_SRVAUTH_PAM -eq 1 ] && get_srv_authMethod_pam
     3239 +                get_confirm 'Do you want to setup Authentication Methods for "keyserv" (y/n/h)?' 'n' 'keyserv_help'
     3240 +                INT[NEED_SRVAUTH_KEY]=$?
     3241 +                (( INT[NEED_SRVAUTH_KEY] )) && get_auth 'keyserv'
2744 3242  
2745      -        # Does the user want to set Service Authentication Method for keyserv?
2746      -        get_confirm "Do you want to setup a Service Auth. Method for \"keyserv\" (y/n/h)?" "n" "keyserv_help"
2747      -        NEED_SRVAUTH_KEY=$?
2748      -        [ $NEED_SRVAUTH_KEY -eq 1 ] && get_srv_authMethod_key
     3243 +                get_confirm 'Do you want to setup Authentication Methods for "passwd-cmd (y/n/h)?' 'n' 'passwd-cmd_help'
     3244 +                INT[NEED_SRVAUTH_CMD]=$?
     3245 +                (( INT[NEED_SRVAUTH_CMD] )) && get_auth 'passwd-cmd'
     3246 +        fi
2749 3247  
2750      -        # Does the user want to set Service Authentication Method for passwd-cmd?
2751      -        get_confirm "Do you want to setup a Service Auth. Method for \"passwd-cmd\" (y/n/h)?" "n" "passwd-cmd_help"
2752      -        NEED_SRVAUTH_CMD=$?
2753      -        [ $NEED_SRVAUTH_CMD -eq 1 ] && get_srv_authMethod_cmd
2754      -    fi
2755      - 
     3248 +        # Get client timeouts
     3249 +        get_srch_time
     3250 +        get_prof_ttl
     3251 +        get_bind_limit
2756 3252  
2757      -    # Get Timeouts
2758      -    get_srch_time
2759      -    get_prof_ttl
2760      -    get_bind_limit
     3253 +        get_want_shadow_update
2761 3254  
2762      -    # Ask whether to enable shadow update
2763      -    get_want_shadow_update
     3255 +        reset_ssd
     3256 +        prompt_ssd
2764 3257  
2765      -    # Reset the sdd_file and prompt user for SSD.  Will use menus
2766      -    # to build an SSD File.
2767      -    reset_ssd_file
2768      -    prompt_ssd
     3258 +        show_vars
2769 3259  
2770      -    # Display FULL debugging info.
2771      -    disp_full_debug
2772      -
2773      -    # Extra blank line to separate prompt lines from steps.
2774      -    ${ECHO} " "
     3260 +        Log.printMarker
     3261 +        return 0
2775 3262  }
     3263 +######################################################################
     3264 +# End Of FUNCTIONS FOR prompt_config_info()
     3265 +######################################################################
2776 3266  
2777 3267  
2778 3268  ######################################################################
2779 3269  # FUNCTIONS  FOR display_summary() START HERE.
2780 3270  ######################################################################
2781      -
2782      -
2783      -#
2784      -# get_proxyagent(): Get the proxyagent DN.
2785      -#
2786      -get_proxyagent()
2787      -{
2788      -    LDAP_PROXYAGENT="cn=proxyagent,ou=profile,${LDAP_BASEDN}"  # default
2789      -    get_ans "Enter DN for proxy agent:" "$LDAP_PROXYAGENT"
2790      -    LDAP_PROXYAGENT=$ANS
     3271 +Man.addFunc get_proxyagent '' '[+NAME?get_proxyagent - Ask user for the proxy agent DN and password.]
     3272 +[+DESCRIPTION?Ask the user for the proxy agent DN and password to use and store it into \bSTR[LDAP_PROXYAGENT]]\b, \bSTR[LDAP_PROXYAGENT_CRED]]\b.]
     3273 +[+SEE ALSO?\bget_ans()\b.]
     3274 +'
     3275 +function get_proxyagent {
     3276 +        STR[LDAP_PROXYAGENT]="cn=proxyagent,ou=profile,${STR[LDAP_BASEDN]}"
     3277 +        get_ans 'Enter DN for proxy agent:' "${STR[LDAP_PROXYAGENT]}"
     3278 +        STR[LDAP_PROXYAGENT]="${ANS}"
     3279 +        get_passwd 'Enter passwd for proxyagent:'
     3280 +        STR[LDAP_PROXYAGENT_CRED]="${ANS}"
2791 3281  }
2792 3282  
     3283 +Man.addFunc display_summary '' '[+NAME?display_summary - Display a summary of values entered and let the user modify values at will.]
     3284 +[+DESCRIPTION?Display a summary of all configuration relevant info and let the user re-enter data if needed.]
     3285 +'
     3286 +function display_summary {
     3287 +        # Create lookup table for function names. Needs to be in sync with 
     3288 +        # helpTag 'summary_menu' in display_msg()!
     3289 +        typeset -a FN=( 'dummy' )                                       # dummy for commit and quit
     3290 +        FN+=( 'get_domain' 'get_basedn' 'get_profile_name' )
     3291 +        FN+=( 'get_srv_list' 'get_pref_srv' 'get_search_scope' 'get_cred_level' )
     3292 +        FN+=( 'get_auth client' 'get_followref' )
     3293 +    FN+=( 'get_timelimit' 'get_sizelimit' 'get_want_crypt' )
     3294 +    FN+=( 'get_auth pam_ldap' 'get_auth keyserv' 'get_auth passwd-cmd' )
     3295 +    FN+=( 'get_srch_time' 'get_prof_ttl' 'get_bind_limit' )
     3296 +    FN+=( 'get_want_shadow_update' )
     3297 +    FN+=( 'prompt_ssd' )
2793 3298  
2794      -#
2795      -# get_proxy_pw(): Get the proxyagent passwd.
2796      -#
2797      -get_proxy_pw()
2798      -{
2799      -    get_passwd "Enter passwd for proxyagent:"
2800      -    LDAP_PROXYAGENT_CRED=$ANS
2801      -}
     3299 +    # Since menu prompt string is long, set here
     3300 +    typeset PROMPT='Enter config value to change: (1-20 0=commit changes)'
     3301 +        integer RES MAX=${#FN[@]}
     3302 +        (( MAX-- ))
2802 3303  
2803      -#
2804      -# display_summary(): Display a summary of values entered and let the 
2805      -#                    user modify values at will.
2806      -#
2807      -display_summary()
2808      -{
2809      -    [ $DEBUG -eq 1 ] && ${ECHO} "In display_summary()"
     3304 +        while : ; do
     3305 +                # Display menu and get value in range
     3306 +                get_menu_choice "${PROMPT}" '0' ${MAX} '0' '' 'summary_menu'
     3307 +                RES=$?
     3308 +        
     3309 +                # Make sure where not exiting
     3310 +                (( RES == 0 )) && break                 # quit selected
2810 3311  
2811      -    # Create lookup table for function names.  First entry is dummy for
2812      -    # shift.
2813      -    TBL1="dummy"
2814      -    TBL2="get_domain get_basedn get_profile_name"
2815      -    TBL3="get_srv_list get_pref_srv get_search_scope get_cred_level"
2816      -    TBL4="get_auth get_followref"
2817      -    TBL5="get_timelimit get_sizelimit get_want_crypt"
2818      -    TBL6="get_srv_authMethod_pam get_srv_authMethod_key get_srv_authMethod_cmd"
2819      -    TBL7="get_srch_time get_prof_ttl get_bind_limit"
2820      -    TBL8="get_want_shadow_update"
2821      -    TBL9="prompt_ssd"
2822      -    FUNC_TBL="$TBL1 $TBL2 $TBL3 $TBL4 $TBL5 $TBL6 $TBL7 $TBL8 $TBL9"
     3312 +                # Call appropriate function from function table
     3313 +                ${FN[RES]}
     3314 +        done
2823 3315  
2824      -    # Since menu prompt string is long, set here.
2825      -    _MENU_PROMPT="Enter config value to change: (1-20 0=commit changes)"
     3316 +    # If credlevel is still proxy see if user wants a change?
     3317 +        if [[ ${STR[LDAP_CRED_LEVEL]:0:5} == 'proxy' ]]; then
     3318 +                if [[ ${STR[LDAP_AUTHMETHOD]} != none ]]; then
     3319 +                        INT[NEED_PROXY]=1
     3320 +                        get_proxyagent
     3321 +                else
     3322 +                        Log.warn 'Since Authentication method is "none",' \
     3323 +                                'credential level will be set to "anonymous"'
     3324 +                        STR[LDAP_CRED_LEVEL]='anonymous'
     3325 +                fi
     3326 +        fi
2826 3327  
2827      -    # Infinite loop.  Test for 0, and break in loop.
2828      -    while :
2829      -    do
2830      -        # Display menu and get value in range.
2831      -        display_msg summary_menu
2832      -        get_menu_choice "${_MENU_PROMPT}" "0" "20" "0"
2833      -        _CH=$MN_CH
2834      -        
2835      -        # Make sure where not exiting.
2836      -        if [ $_CH -eq 0 ]; then
2837      -            break       # Break out of loop if 0 selected.
     3328 +        # If shadow update is enabled, set up administrator credential
     3329 +        if (( INT[LDAP_ENABLE_SHADOW_UPDATE] )); then
     3330 +                INT[NEED_ADMIN]=1
     3331 +                if [[ ${STR[LDAP_CRED_LEVEL]} == 'self' && \
     3332 +                        ${STR[LDAP_AUTHMETHOD]} == 'sasl/GSSAPI' ]];
     3333 +                then
     3334 +                                INT[NEED_HOSTACL]=1
     3335 +                                INT[NEED_ADMIN]=0
     3336 +                fi
     3337 +                if (( INT[NEED_ADMIN] )); then
     3338 +                        get_adminDN
     3339 +                        get_admin_pw
     3340 +                fi
2838 3341          fi
2839 3342  
2840      -        # Call appropriate function from function table.
2841      -        set $FUNC_TBL
2842      -        shift $_CH
2843      -        $1          # Call the appropriate function.
2844      -    done
     3343 +        show_vars
2845 3344  
2846      -    # If cred level is still see if user wants a change?
2847      -    if ${ECHO} "$LDAP_CRED_LEVEL" | ${GREP} "proxy" > /dev/null 2>&1
2848      -    then
2849      -        if [ "$LDAP_AUTHMETHOD" != "none" ]; then
2850      -            NEED_PROXY=1    # I assume integer test is faster?
2851      -            get_proxyagent
2852      -            get_proxy_pw
2853      -        else
2854      -            ${ECHO} "WARNING: Since Authentication method is 'none'."
2855      -            ${ECHO} "         Credential level will be set to 'anonymous'."
2856      -            LDAP_CRED_LEVEL="anonymous"
     3345 +        get_confirm_nodef '
     3346 +WARNING: About to start committing changes. (y=continue, n=EXIT)'
     3347 +        if (( ! $? )); then
     3348 +                Log.info 'Terminating setup without making changes at users request'
     3349 +                return 1
2857 3350          fi
2858      -    fi
2859 3351  
2860      -    # If shadow update is enabled, set up administrator credential
2861      -    if [ "$LDAP_ENABLE_SHADOW_UPDATE" = "TRUE" ]; then
2862      -        NEED_ADMIN=1
2863      -        if ${ECHO} "$LDAP_CRED_LEVEL" | ${GREP} "self" > /dev/null 2>&1; then
2864      -            if ${ECHO} "$LDAP_AUTHMETHOD" | ${GREP} "GSSAPI" > /dev/null 2>&1; then
2865      -                NEED_HOSTACL=1
2866      -                NEED_ADMIN=0
2867      -            fi
     3352 +        Log.printMarker
     3353 +        return 0
     3354 +}
     3355 +######################################################################
     3356 +# End Of FUNCTIONS  FOR display_summary()
     3357 +######################################################################
     3358 +
     3359 +Man.addFunc modify_cn '' '[+NAME?modify_cn - modify objectclass "ipNetwork" to RFC 2307bis.]
     3360 +[+DESCRIPTION?Change the cn from MUST to MAY in ipNetwork objectclass.]
     3361 +[+RETURN VALUES]{
     3362 +        [+0?on success.]
     3363 +        [+>= 66?a fatal error occurred.]
     3364 +}
     3365 +[+SEE ALSO?\bldapmodify\b(1).]
     3366 +'
     3367 +function modify_cn {
     3368 +        getDSobjectclasses || return 66
     3369 +        typeset NEWDEF="'ipNetwork' SUP top STRUCTURAL DESC 'Abstraction of a network. The distinguished value of the cn attribute denotes the canonical name of the network' MUST ipNetworkNumber MAY "'( cn $ ipNetmaskNumber $ l $ description $ manager )'" X-ORIGIN 'draft-howard-rfc2307bis'"
     3370 +
     3371 +        # bis-delta: MUST ( -cn )  MAY ( +cn )
     3372 +        typeset DEF=${OID2ODEF['1.3.6.1.1.1.2.7']}
     3373 +        if [[ -n ${DEF} ]]; then
     3374 +                DEF=${DEF##*MUST*([[:space:]])}
     3375 +                if [[ ${DEF:0:9} == 'ipNetwork' ]]; then
     3376 +                        # assume no need to fix, old definition would start with a '(' 
     3377 +                        showProgress 'Schema definition of ipNetwork ok (RFC2307bis).'
     3378 +                        return 0
     3379 +                fi
2868 3380          fi
2869      -        [ $DEBUG -eq 1 ] && ${ECHO} "NEED_HOSTACL = $NEED_HOSTACL"
2870      -        [ $DEBUG -eq 1 ] && ${ECHO} "NEED_ADMIN   = $NEED_ADMIN"
2871      -        if [ $NEED_ADMIN -eq 1 ]; then
2872      -            get_adminDN
2873      -            get_admin_pw
2874      -        fi
2875      -    fi
2876 3381  
2877      -    # Display FULL debugging info.
2878      -    disp_full_debug
     3382 +        nextFile modify $0
     3383 +        print '
     3384 +dn: cn=schema
     3385 +changetype: modify
     3386 +add: objectclasses
     3387 +objectclasses: ( 1.3.6.1.1.1.2.7 NAME '"${NEWDEF}"')
     3388 +'       > ${TMP[FILE]}
2879 3389  
2880      -    # Final confirmation message. (ARE YOU SURE!)
2881      -    ${ECHO} " "
2882      -    get_confirm_nodef "WARNING: About to start committing changes. (y=continue, n=EXIT)" 
2883      -    if [ $? -eq 0 ]; then
2884      -        ${ECHO} "Terminating setup without making changes at users request."
2885      -        cleanup
2886      -        exit 1
2887      -    fi
     3390 +        if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     3391 +                >&${TMPF[FD]} 2>&1
     3392 +        then
     3393 +                Log.fatal 'Schema update of ipNetwork to RFC2307bis failed'
     3394 +                return 67
     3395 +        fi
     3396 +        showProgress 'Schema update of ipNetwork to RFC2307bis done.'
     3397 +        OID2ODEF['1.3.6.1.1.1.2.7']="${NEWDEF}"
     3398 +        return 0
     3399 +}
2888 3400  
2889      -    # Print newline 
2890      -    ${ECHO} " "
     3401 +Man.addFunc modify_timelimit '' '[+NAME?modify_timelimit - Set the DS timelimit.]
     3402 +[+DESCRIPTION?Set the DS timelimit to \bINT[DS_TIMELIMIT]]\b.]
     3403 +[+RETURN VALUES]{
     3404 +        [+0?on success.]
     3405 +        [+>= 66?a fatal error occurred.]
2891 3406  }
     3407 +[+SEE ALSO?\bldapmodify\b(1).]
     3408 +'
     3409 +function modify_timelimit {
     3410 +        typeset NAME='nsslapd-timelimit'
     3411 +        (( TMPF[IS_OPENDJ] )) && NAME='ds-cfg-time-limit'
2892 3412  
     3413 +        nextFile modify $0
     3414 +        print '
     3415 +dn: cn=config
     3416 +changetype: modify
     3417 +replace: '"${NAME}"'
     3418 +'"${NAME}"': '"${INT[DS_TIMELIMIT]}"' s
     3419 +'               > ${TMP[FILE]}
2893 3420  
2894      -#
2895      -# create_config_file(): Write config data to config file specified.
2896      -#
2897      -create_config_file()
2898      -{
2899      -    [ $DEBUG -eq 1 ] && ${ECHO} "In create_config_file()"
     3421 +        if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     3422 +                >&${TMPF[FD]} 2>&1
     3423 +        then
     3424 +                Log.fatal 'Update of ${NAME} failed'
     3425 +                return 66
     3426 +        fi
2900 3427  
2901      -    # If output file exists, delete it.
2902      -    [ -f $OUTPUT_FILE ] && rm $OUTPUT_FILE
     3428 +        showProgress "Changed ${NAME} to ${INT[DS_TIMELIMIT]} in 'cn=config'."
     3429 +        return 0
     3430 +}
2903 3431  
2904      -    # Create output file.
2905      -    cat > $OUTPUT_FILE <<EOF
2906      -#!/bin/sh
2907      -# $OUTPUT_FILE - This file contains configuration information for
2908      -#                Native LDAP.  Use the idsconfig tool to load it.
2909      -#
2910      -# WARNING: This file was generated by idsconfig, and is intended to
2911      -#          be loaded by idsconfig as is.  DO NOT EDIT THIS FILE!
2912      -#
2913      -IDS_SERVER="$IDS_SERVER"
2914      -IDS_PORT=$IDS_PORT
2915      -IDS_TIMELIMIT=$IDS_TIMELIMIT
2916      -IDS_SIZELIMIT=$IDS_SIZELIMIT
2917      -LDAP_ROOTDN="$LDAP_ROOTDN"
2918      -LDAP_ROOTPWD=$LDAP_ROOTPWD
2919      -LDAP_DOMAIN="$LDAP_DOMAIN"
2920      -LDAP_SUFFIX="$LDAP_SUFFIX"
2921      -GSSAPI_ENABLE=$GSSAPI_ENABLE
2922      -LDAP_KRB_REALM="$LDAP_KRB_REALM"
     3432 +Man.addFunc modify_sizelimit '' '[+NAME?modify_sizelimit - Set the DS sizelimit.]
     3433 +[+DESCRIPTION?Set the DS sizelimit to \bINT[DS_SIZELIMIT]]\b.]
     3434 +[+RETURN VALUES]{
     3435 +        [+0?on success.]
     3436 +        [+>= 66?a fatal error occurred.]
     3437 +}
     3438 +[+SEE ALSO?\bldapmodify\b(1).]
     3439 +'
     3440 +function modify_sizelimit {
     3441 +        typeset NAME='nsslapd-sizelimit'
     3442 +        (( TMPF[IS_OPENDJ] )) && NAME='ds-cfg-size-limit'
2923 3443  
2924      -# Internal program variables that need to be set.
2925      -NEED_PROXY=$NEED_PROXY
2926      -NEED_TIME=$NEED_TIME
2927      -NEED_SIZE=$NEED_SIZE
2928      -NEED_CRYPT=$NEED_CRYPT
2929      -NEED_ADMIN=$NEED_ADMIN
2930      -NEED_HOSTACL=$NEED_HOSTACL
2931      -EXISTING_PROFILE=$EXISTING_PROFILE
     3444 +        nextFile modify $0
     3445 +        print '
     3446 +dn: cn=config
     3447 +changetype: modify
     3448 +replace: '"${NAME}"'
     3449 +'"${NAME}"': '"${INT[DS_SIZELIMIT]}"'
     3450 +'               > ${TMP[FILE]}
2932 3451  
2933      -# LDAP PROFILE related defaults
2934      -LDAP_PROFILE_NAME="$LDAP_PROFILE_NAME"
2935      -DEL_OLD_PROFILE=1
2936      -LDAP_BASEDN="$LDAP_BASEDN"
2937      -LDAP_SERVER_LIST="$LDAP_SERVER_LIST"
2938      -LDAP_AUTHMETHOD="$LDAP_AUTHMETHOD"
2939      -LDAP_FOLLOWREF=$LDAP_FOLLOWREF
2940      -LDAP_SEARCH_SCOPE="$LDAP_SEARCH_SCOPE"
2941      -NEED_SRVAUTH_PAM=$NEED_SRVAUTH_PAM
2942      -NEED_SRVAUTH_KEY=$NEED_SRVAUTH_KEY
2943      -NEED_SRVAUTH_CMD=$NEED_SRVAUTH_CMD
2944      -LDAP_SRV_AUTHMETHOD_PAM="$LDAP_SRV_AUTHMETHOD_PAM"
2945      -LDAP_SRV_AUTHMETHOD_KEY="$LDAP_SRV_AUTHMETHOD_KEY"
2946      -LDAP_SRV_AUTHMETHOD_CMD="$LDAP_SRV_AUTHMETHOD_CMD"
2947      -LDAP_SEARCH_TIME_LIMIT=$LDAP_SEARCH_TIME_LIMIT
2948      -LDAP_PREF_SRVLIST="$LDAP_PREF_SRVLIST"
2949      -LDAP_PROFILE_TTL=$LDAP_PROFILE_TTL
2950      -LDAP_CRED_LEVEL="$LDAP_CRED_LEVEL"
2951      -LDAP_BIND_LIMIT=$LDAP_BIND_LIMIT
     3452 +        if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     3453 +                >&${TMPF[FD]} 2>&1
     3454 +        then
     3455 +                Log.fatal "Update of ${NAME} failed"
     3456 +                return 66
     3457 +        fi
2952 3458  
2953      -# Proxy Agent
2954      -LDAP_PROXYAGENT="$LDAP_PROXYAGENT"
2955      -LDAP_PROXYAGENT_CRED=$LDAP_PROXYAGENT_CRED
     3459 +        showProgress "Changed ${NAME} to ${INT[DS_SIZELIMIT]} in 'cn=config'."
     3460 +        return 0
     3461 +}
2956 3462  
2957      -# enableShadowUpdate flag and Administrator credential
2958      -LDAP_ENABLE_SHADOW_UPDATE=$LDAP_ENABLE_SHADOW_UPDATE
2959      -LDAP_ADMINDN="$LDAP_ADMINDN"
2960      -LDAP_ADMIN_CRED=$LDAP_ADMIN_CRED
     3463 +Man.addFunc modify_pwd_crypt '' '[+NAME?modify_pwd_crypt - modify the passwd storage scheme to use CRYPT.]
     3464 +[+DESCRIPTION?Set the default password policy of the DS to CRYPT.]
     3465 +[+RETURN VALUES]{
     3466 +        [+0?on success.]
     3467 +        [+>= 66?a fatal error occurred.]
     3468 +}
     3469 +[+SEE ALSO?\bldapmodify\b(1).]
     3470 +'
     3471 +function modify_pwd_crypt {
     3472 +    # DS 5.2 moved passwordchangescheme off to a new data structure
     3473 +        typeset -a INFO=( ${TMP[DS_INFO]} )
     3474 +        typeset DN='cn=config' TARGET='passwordStorageScheme' VALUE='CRYPT' MSG=''
     3475 +        typeset FMT='dn: %s\nchangetype: modify\nreplace: %s\n%s: %s\n\n'
     3476 +        nextFile modify $0
2961 3477  
2962      -# Export all the variables (just in case)
2963      -export IDS_HOME IDS_PORT LDAP_ROOTDN LDAP_ROOTPWD LDAP_SERVER_LIST LDAP_BASEDN
2964      -export LDAP_DOMAIN LDAP_SUFFIX LDAP_PROXYAGENT LDAP_PROXYAGENT_CRED
2965      -export NEED_PROXY
2966      -export LDAP_ENABLE_SHADOW_UPDATE LDAP_ADMINDN LDAP_ADMIN_CRED
2967      -export NEED_ADMIN NEED_HOSTACL EXISTING_PROFILE
2968      -export LDAP_PROFILE_NAME LDAP_BASEDN LDAP_SERVER_LIST 
2969      -export LDAP_AUTHMETHOD LDAP_FOLLOWREF LDAP_SEARCH_SCOPE LDAP_SEARCH_TIME_LIMIT
2970      -export LDAP_PREF_SRVLIST LDAP_PROFILE_TTL LDAP_CRED_LEVEL LDAP_BIND_LIMIT
2971      -export NEED_SRVAUTH_PAM NEED_SRVAUTH_KEY NEED_SRVAUTH_CMD
2972      -export LDAP_SRV_AUTHMETHOD_PAM LDAP_SRV_AUTHMETHOD_KEY LDAP_SRV_AUTHMETHOD_CMD
2973      -export LDAP_SERV_SRCH_DES SSD_FILE GSSAPI_ENABLE LDAP_KRB_REALM
     3478 +        if (( TMPF[IS_OPENDJ] )); then
     3479 +                DN='cn=Default Password Policy,cn=Password Policies,cn=config'
     3480 +                TARGET='ds-cfg-default-password-storage-scheme'
     3481 +                VALUE='cn=CRYPT,cn=Password Storage Schemes,cn=config'
     3482 +        else
     3483 +                # DSEE
     3484 +                integer VER=$(( ${INFO[1]} * 1000 + ${INFO[2]} ))
     3485 +                (( VER >= 5002 )) && DN='cn=Password Policy,cn=config'
     3486 +        fi
     3487 +        printf "${FMT}" "${DN}" "${TARGET}" "${TARGET}" "${VALUE}" >${TMP[FILE]}
     3488 +        MSG="Changed '${TARGET}' to 'CRYPT'"
2974 3489  
2975      -# Service Search Descriptors start here if present:
2976      -EOF
2977      -    # Add service search descriptors.
2978      -    ssd_2_config "${OUTPUT_FILE}"
     3490 +        if (( TMPF[IS_OPENDJ] )); then
     3491 +                if (( INT[NEED_CRYPT_IMPORT] )); then 
     3492 +                        TARGET='ds-cfg-allow-pre-encoded-passwords'
     3493 +                        printf "${FMT}" "${DN}" "${TARGET}" "${TARGET}" 'true'>>${TMP[FILE]}
     3494 +                        MSG+="and '${TARGET}' to 'true'"
     3495 +                fi
     3496 +                DN='cn=Password Policy Import,cn=Plugins,cn=config'
     3497 +                TARGET='ds-cfg-default-user-password-storage-scheme'
     3498 +                printf "${FMT}" "${DN}" "${TARGET}" "${TARGET}" "${VALUE}">>${TMP[FILE]}
     3499 +        fi
2979 3500  
2980      -    # Add LDAP suffix preferences
2981      -    print_suffix_config >> "${OUTPUT_FILE}"
     3501 +        if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     3502 +                >&${TMPF[FD]} 2>&1
     3503 +        then
     3504 +                Log.fatal 'Update of passwordStorageScheme failed'
     3505 +                return 66
     3506 +        fi
2982 3507  
2983      -    # Add the end of FILE tag.
2984      -    ${ECHO} "" >> ${OUTPUT_FILE}
2985      -    ${ECHO} "# End of $OUTPUT_FILE" >> ${OUTPUT_FILE}
     3508 +        showProgress "${MSG}."
     3509 +        return 0
2986 3510  }
2987 3511  
2988      -
2989      -#
2990      -# chk_vlv_indexes(): Do ldapsearch to see if server supports VLV.
2991      -#
2992      -chk_vlv_indexes()
2993      -{
2994      -    # Do ldapsearch to see if server supports VLV.
2995      -    ${LDAPSEARCH} ${SERVER_ARGS} -b "" -s base "objectclass=*" > ${TMPDIR}/checkVLV 2>&1
2996      -    eval "${GREP} 2.16.840.1.113730.3.4.9 ${TMPDIR}/checkVLV ${VERB}"
2997      -    if [ $? -ne 0 ]; then
2998      -        ${ECHO} "ERROR: VLV is not supported on LDAP server!"
2999      -        cleanup
3000      -        exit 1
3001      -    fi
3002      -    [ $DEBUG -eq 1 ] && ${ECHO} "  VLV controls found on LDAP server."
     3512 +Man.addFunc update_schema_attr '' '[+NAME?update_schema_attr -  Update DS schema to support Naming Services.]
     3513 +[+DESCRIPTION?Update the schema of the DS with the attribute types required for the Solaris Naming Services. It just checks, whether the OID is defined in the server schema. If already defined, it is left as is, otherwise added.]
     3514 +[+RETURN VALUES]{
     3515 +        [+0?on success.]
     3516 +        [+>= 66?a fatal error occurred.]
3003 3517  }
     3518 +[+SEE ALSO?\bldapmodify\b(1), \bgetDSattributes()\b.]
     3519 +'
     3520 +function update_schema_attr {
3004 3521  
3005      -#
3006      -# get_backend(): this function gets the relevant backend
3007      -#                (database) for LDAP_BASED.
3008      -#                Description: set IDS_DATABASE; exit on failure.
3009      -#                Prerequisite: LDAP_BASEDN and LDAP_SUFFIX are
3010      -#                valid.
3011      -#
3012      -#                backend is retrieved from suffixes and subsuffixes
3013      -#                defined under "cn=mapping tree,cn=config". The 
3014      -#                nsslapd-state attribute of these suffixes entries
3015      -#                is filled with either Backend, Disabled or referrals
3016      -#                related values. We only want those that have a true
3017      -#                backend database to select the relevant backend.
3018      -#                
3019      -get_backend()
3020      -{
3021      -    [ $DEBUG -eq 1 ] && ${ECHO} "In get_backend()"
     3522 +        # incorporate former 'keep_backward_compatibility()'
     3523 +        getDSattributes || return 66
     3524 +        typeset MEMBERGID_OID='1.3.6.1.4.1.42.2.27.5.1.30'
     3525 +        typeset DEF=${ANAME2OID['membergid-oid']}
     3526 +        [[ -n ${DEF} ]] && MEMBERGID_OID='memberGid-oid'
     3527 +        typeset RFC822MAILMEMBER_OID='1.3.6.1.4.1.42.2.27.2.1.15'
     3528 +        DEF=${ANAME2OID['rfc822mailmember-oid']}
     3529 +        [[ -n ${DEF} ]] && RFC822MAILMEMBER_OID='rfc822mailMember-oid'
3022 3530  
3023      -    cur_suffix=${LDAP_BASEDN}
3024      -    prev_suffix=
3025      -    IDS_DATABASE=
3026      -    while [ "${cur_suffix}" != "${prev_suffix}" ]
3027      -    do
3028      -        [ $DEBUG -eq 1 ] && ${ECHO} "testing LDAP suffix: ${cur_suffix}"
3029      -        eval "${LDAPSEARCH} ${LDAP_ARGS} " \
3030      -                "-b \"cn=\\\"${cur_suffix}\\\",cn=mapping tree,cn=config\" " \
3031      -                "-s base nsslapd-state=Backend nsslapd-backend 2>&1 " \
3032      -                "| ${GREP} 'nsslapd-backend=' " \
3033      -                "> ${TMPDIR}/ids_database_name 2>&1"
3034      -        NUM_DBS=`wc -l ${TMPDIR}/ids_database_name | awk '{print $1}'`
3035      -        case ${NUM_DBS} in
3036      -        0) # not a suffix, or suffix not activated; try next
3037      -            prev_suffix=${cur_suffix}
3038      -            cur_suffix=`${ECHO} ${cur_suffix} | cut -f2- -d','`
3039      -            ;;
3040      -        1) # suffix found; get database name
3041      -            IDS_DATABASE=`cat ${TMPDIR}/ids_database_name | cut -d= -f2`
3042      -            ;;
3043      -        *) # can not handle more than one database per suffix
3044      -            ${ECHO} "ERROR: More than one database is configured "
3045      -            ${ECHO} "       for $LDAP_SUFFIX!"
3046      -            ${ECHO} "       $PROG can not configure suffixes where "
3047      -            ${ECHO} "       more than one database is used for one suffix."
3048      -            cleanup
3049      -            exit 1
3050      -            ;;
3051      -        esac
3052      -        if [ -n "${IDS_DATABASE}" ]; then
3053      -            break
3054      -        fi
3055      -    done
     3531 +        # EE and OD definitions seem to be compatible wrt. to Solaris. However, the
     3532 +        # OD defs usually specifies explicitly the server behavior (what happens, if
     3533 +        # EQUALITY|SUBSTR is not specified => caseIgnore[Substring]Match)) and 
     3534 +        # sometimes a different kind of String to use (see RFC 4517):
     3535 +        # IA5 String: ASCII character in the range of 0..127
     3536 +        # Octet String: byte collection (0..255), usually not human readable,
     3537 +        #               bytewise comparision
     3538 +        # Directory String: an UTF-8 string
     3539 +        # DN: basically an UTF-8 string, but with some constraints wrt. backslash
     3540 +        #     escaping '\0', '"', '+', ',', ';', '<', '>',  and '\'
     3541 +        # Boolean String: TRUE|FALSE
     3542 +        typeset -A EE=( )
     3543 +        typeset -A OD=( )
     3544 +        EE['1.3.6.1.1.1.1.28']="'nisPublickey' DESC 'NIS public key' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
     3545 +        OD['1.3.6.1.1.1.1.28']="'nisPublicKey' DESC 'NIS public key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE X-ORIGIN 'draft-howard-rfc2307bis'" # Directory vs. Octet String
3056 3546  
3057      -    if [ -z "${IDS_DATABASE}" ]; then
3058      -        # should not happen, since LDAP_BASEDN is supposed to be valid
3059      -        ${ECHO} "Could not find a valid backend for ${LDAP_BASEDN}."
3060      -        ${ECHO} "Exiting."
3061      -        cleanup
3062      -        exit 1
3063      -    fi
     3547 +        EE['1.3.6.1.1.1.1.29']="'nisSecretkey' DESC 'NIS secret key' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
     3548 +        OD['1.3.6.1.1.1.1.29']="'nisSecretKey' DESC 'NIS secret key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE X-ORIGIN 'draft-howard-rfc2307bis'"    # Directory vs. Octet String
3064 3549  
3065      -    [ $DEBUG -eq 1 ] && ${ECHO} "IDS_DATABASE: ${IDS_DATABASE}"
3066      -}
     3550 +        EE['1.3.6.1.1.1.1.30']="'nisDomain' DESC 'NIS domain' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
     3551 +        OD['1.3.6.1.1.1.1.30']="'nisDomain' DESC 'NIS domain' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'draft-howard-rfc2307bis'"      # Directory vs. IA5 String
3067 3552  
3068      -#
3069      -# validate_suffix(): This function validates ${LDAP_SUFFIX}
3070      -#                  THIS FUNCTION IS FOR THE LOAD CONFIG FILE OPTION.
3071      -#
3072      -validate_suffix()
3073      -{
3074      -    [ $DEBUG -eq 1 ] && ${ECHO} "In validate_suffix()"
     3553 +        EE['1.3.6.1.1.1.1.31']="'automountMapName' DESC 'automount Map Name' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
     3554 +        OD['1.3.6.1.1.1.1.31']="'automountMapName' DESC 'automount Map Name' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'draft-howard-rfc2307bis'"
3075 3555  
3076      -    # Check LDAP_SUFFIX is not null
3077      -    if [ -z "${LDAP_SUFFIX}" ]; then
3078      -        ${ECHO} "Invalid suffix (null suffix)"
3079      -        cleanup
3080      -        exit 1
3081      -    fi
     3556 +        EE['1.3.6.1.1.1.1.32']="'automountKey' DESC 'automount Key Value' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
     3557 +        OD['1.3.6.1.1.1.1.32']="'automountKey' DESC 'Automount Key value' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'draft-howard-rfc2307bis'"
3082 3558  
3083      -    # Check LDAP_SUFFIX and LDAP_BASEDN are consistent
3084      -    # Convert to lower case for basename.
3085      -    format_string "${LDAP_BASEDN}"
3086      -    LOWER_BASEDN="${FMT_STR}"
3087      -    format_string "${LDAP_SUFFIX}"
3088      -    LOWER_SUFFIX="${FMT_STR}"
     3559 +        EE['1.3.6.1.1.1.1.33']="'automountInformation' DESC 'automount information' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
     3560 +        OD['1.3.6.1.1.1.1.33']="'automountInformation' DESC 'Automount information' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'draft-howard-rfc2307bis'"
3089 3561  
3090      -    [ $DEBUG -eq 1 ] && ${ECHO} "LOWER_BASEDN: ${LOWER_BASEDN}"
3091      -    [ $DEBUG -eq 1 ] && ${ECHO} "LOWER_SUFFIX: ${LOWER_SUFFIX}"
     3562 +        EE['1.3.6.1.4.1.42.2.27.1.1.12']="'nisNetIdUser' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26"
     3563 +        OD['1.3.6.1.4.1.42.2.27.1.1.12']="'nisNetIdUser' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Solaris Specific'"
3092 3564  
3093      -    if [ "${LOWER_BASEDN}" != "${LOWER_SUFFIX}" ]; then
3094      -        sub_basedn=`basename "${LOWER_BASEDN}" "${LOWER_SUFFIX}"`
3095      -        if [ "$sub_basedn" = "${LOWER_BASEDN}" ]; then
3096      -            ${ECHO} "Invalid suffix ${LOWER_SUFFIX}"
3097      -            ${ECHO} "for Base DN ${LOWER_BASEDN}"
3098      -            cleanup
3099      -            exit 1
3100      -        fi
3101      -    fi
     3565 +        EE['1.3.6.1.4.1.42.2.27.1.1.13']="'nisNetIdGroup' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26"
     3566 +        OD['1.3.6.1.4.1.42.2.27.1.1.13']="'nisNetIdGroup' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Solaris Specific'"
3102 3567  
3103      -    # Check LDAP_SUFFIX does exist
3104      -    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_SUFFIX}\" -s base \"objectclass=*\" > ${TMPDIR}/checkSuffix 2>&1" && return 0
     3568 +        EE['1.3.6.1.4.1.42.2.27.1.1.14']="'nisNetIdHost' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26"
     3569 +        OD['1.3.6.1.4.1.42.2.27.1.1.14']="'nisNetIdHost' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Solaris Specific'"
3105 3570  
3106      -    # Well, suffix does not exist, try to prepare create it ...
3107      -    NEED_CREATE_SUFFIX=1
3108      -    prep_create_sfx_entry ||
3109      -    {
3110      -        cleanup
3111      -        exit 1
3112      -    }
3113      -    [ -n "${NEED_CREATE_BACKEND}" ] &&
3114      -    {
3115      -        # try to use id attr value of the suffix as a database name
3116      -        IDS_DATABASE=${_VAL}
3117      -        prep_create_sfx_backend
3118      -        case $? in
3119      -        1)      # cann't use the name we want, so we can either exit or use
3120      -                # some another available name - doing the last ...
3121      -                IDS_DATABASE=${IDS_DATABASE_AVAIL}
3122      -                ;;
3123      -        2)      # unable to determine database name
3124      -                cleanup
3125      -                exit 1
3126      -                ;;
3127      -        esac
3128      -    }
     3571 +        EE[${RFC822MAILMEMBER_OID}]="'rfc822mailMember' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26"
     3572 +        OD[${RFC822MAILMEMBER_OID}]="'rfc822mailMember' DESC 'rfc822 mail addresss of group member' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Solaris Specific'"
3129 3573  
3130      -    [ $DEBUG -eq 1 ] && ${ECHO} "Suffix $LDAP_SUFFIX, Database $IDS_DATABASE"
3131      -}
     3574 +        EE['2.16.840.1.113730.3.1.30']="'mgrpRFC822MailMember' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
     3575 +        OD['2.16.840.1.113730.3.1.30']="'mgrpRFC822MailMember' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Solaris Specific'"
3132 3576  
3133      -#
3134      -# validate_info(): This function validates the basic info collected
3135      -#                  So that some problems are caught right away.
3136      -#                  THIS FUNCTION IS FOR THE LOAD CONFIG FILE OPTION.
3137      -#
3138      -validate_info()
3139      -{
3140      -    [ $DEBUG -eq 1 ] && ${ECHO} "In validate_info()"
     3577 +        EE['1.3.6.1.4.1.42.2.27.5.1.15']="'SolarisLDAPServers' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
     3578 +        OD['1.3.6.1.4.1.42.2.27.5.1.15']="'SolarisLDAPServers' DESC 'LDAP Server address eg. 76.234.3.1:389' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Solaris Specific'"      # Directory vs. IA5 String
3141 3579  
3142      -    # Set SERVER_ARGS, AUTH_ARGS, and LDAP_ARGS for the config file.
3143      -    SERVER_ARGS="-h ${IDS_SERVER} -p ${IDS_PORT}"
3144      -    AUTH_ARGS="-D \"${LDAP_ROOTDN}\" -j ${LDAP_ROOTPWF}"
3145      -    LDAP_ARGS="${SERVER_ARGS} ${AUTH_ARGS}"
3146      -    export SERVER_ARGS
     3580 +        EE['1.3.6.1.4.1.42.2.27.5.1.16']="'SolarisSearchBaseDN' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE"
     3581 +        OD['1.3.6.1.4.1.42.2.27.5.1.16']="'SolarisSearchBaseDN' DESC 'Search Base Distinguished Name' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"   # DN vs. Directory String
3147 3582  
3148      -    # Check the Root DN and Root DN passwd.
3149      -    # Use eval instead of $EVAL because not part of setup. (validate)
3150      -    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"\" -s base \"objectclass=*\" > ${TMPDIR}/checkDN 2>&1"
3151      -    if [ $? -ne 0 ]; then
3152      -        eval "${GREP} credential ${TMPDIR}/checkDN ${VERB}"
3153      -        if [ $? -eq 0 ]; then
3154      -            ${ECHO} "ERROR: Root DN passwd is invalid."
3155      -        else
3156      -            ${ECHO} "ERROR2: Invalid Root DN <${LDAP_ROOTDN}>."
3157      -        fi
3158      -        cleanup
3159      -        exit 1
3160      -    fi
3161      -    [ $DEBUG -eq 1 ] && ${ECHO} "  RootDN ... OK"
3162      -    [ $DEBUG -eq 1 ] && ${ECHO} "  RootDN passwd ... OK"
     3583 +        EE['1.3.6.1.4.1.42.2.27.5.1.17']="'SolarisCacheTTL' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3584 +        OD['1.3.6.1.4.1.42.2.27.5.1.17']="'SolarisCacheTTL' DESC 'TTL value for the Domain information eg. 1w, 2d, 3h, 10m, or 5s' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"   # Directory vs. IA5 String
3163 3585  
3164      -    # Check if the server supports the VLV.
3165      -    chk_vlv_indexes
3166      -    [ $DEBUG -eq 1 ] && ${ECHO} "  VLV indexes ... OK"
     3586 +        EE['1.3.6.1.4.1.42.2.27.5.1.18']="'SolarisBindDN' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE"
     3587 +        OD['1.3.6.1.4.1.42.2.27.5.1.18']="'SolarisBindDN' DESC 'DN to be used to bind to the directory as proxy' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"        # DN vs. Directory String
3167 3588  
3168      -    # Check LDAP suffix
3169      -    validate_suffix
3170      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP suffix ... OK"
3171      -}
     3589 +        EE['1.3.6.1.4.1.42.2.27.5.1.19']="'SolarisBindPassword' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
     3590 +        OD['1.3.6.1.4.1.42.2.27.5.1.19']="'SolarisBindPassword' DESC 'Password for bindDN to authenticate to the directory' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"    # IA5 vs. Octet String
3172 3591  
3173      -#
3174      -# format_string(): take a string as argument and set FMT_STR
3175      -# to be the same string formatted as follow:
3176      -# - only lower case characters
3177      -# - no unnecessary spaces around , and =
3178      -#
3179      -format_string()
3180      -{
3181      -    FMT_STR=`${ECHO} "$1" | tr '[A-Z]' '[a-z]' |
3182      -        sed -e 's/[ ]*,[ ]*/,/g' -e 's/[ ]*=[ ]*/=/g'`
3183      -}
     3592 +        EE['1.3.6.1.4.1.42.2.27.5.1.20']="'SolarisAuthMethod' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
     3593 +        OD['1.3.6.1.4.1.42.2.27.5.1.20']="'SolarisAuthMethod' DESC 'Authentication method to be used eg. \"NS_LDAP_AUTH_NONE\", \"NS_LDAP_AUTH_SIMPLE\" or \"NS_LDAP_AUTH_SASL_CRAM_MD5\"' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Solaris Specific'"        # Directory vs. IA5 String
3184 3594  
3185      -#
3186      -# prepare for the suffix entry creation
3187      -#
3188      -# input  : LDAP_BASEDN, LDAP_SUFFIX - base dn and suffix;
3189      -# in/out : LDAP_SUFFIX_OBJ, LDAP_SUFFIX_ACI - initially may come from config.
3190      -# output : NEED_CREATE_BACKEND - backend for this suffix needs to be created;
3191      -#          _RDN, _ATT, _VAL - suffix's RDN, id attribute name and its value.
3192      -# return : 0 - success, otherwise error.
3193      -#
3194      -prep_create_sfx_entry()
3195      -{
3196      -    [ $DEBUG -eq 1 ] && ${ECHO} "In prep_create_sfx_entry()"
     3595 +        EE['1.3.6.1.4.1.42.2.27.5.1.21']="'SolarisTransportSecurity' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
     3596 +        OD['1.3.6.1.4.1.42.2.27.5.1.21']="'SolarisTransportSecurity' DESC 'Transport Level Security method to be used eg. \"NS_LDAP_SEC_NONE\" or \"NS_LDAP_SEC_SASL_TLS\"' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"  # Directory vs. IA5 String
3197 3597  
3198      -    # check whether suffix corresponds to base dn
3199      -    format_string "${LDAP_BASEDN}"
3200      -    ${ECHO} ",${FMT_STR}" | ${GREP} ",${LDAP_SUFFIX}$" >/dev/null 2>&1 ||
3201      -    {
3202      -        display_msg sfx_not_suitable
3203      -        return 1
3204      -    }
     3598 +        EE['1.3.6.1.4.1.42.2.27.5.1.22']="'SolarisCertificatePath' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
     3599 +        OD['1.3.6.1.4.1.42.2.27.5.1.22']="'SolarisCertificatePath' DESC 'Path to certificate file/device' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"
3205 3600  
3206      -    # parse LDAP_SUFFIX
3207      -    _RDN=`${ECHO} "${LDAP_SUFFIX}" | cut -d, -f1`
3208      -    _ATT=`${ECHO} "${_RDN}" | cut -d= -f1`
3209      -    _VAL=`${ECHO} "${_RDN}" | cut -d= -f2-`
     3601 +        EE['1.3.6.1.4.1.42.2.27.5.1.23']="'SolarisCertificatePassword' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
     3602 +        OD['1.3.6.1.4.1.42.2.27.5.1.23']="'SolarisCertificatePassword' DESC 'Password or PIN that grants access to certificate.' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"       # IA5 vs. Octet String
3210 3603  
3211      -    # find out an objectclass for suffix entry if it is not defined yet
3212      -    [ -z "${LDAP_SUFFIX_OBJ}" ] &&
3213      -    {
3214      -        get_objectclass ${_ATT}
3215      -        [ -z "${_ATTR_NAME}" ] &&
3216      -        {
3217      -                display_msg obj_not_found
3218      -                return 1
3219      -        }
3220      -        LDAP_SUFFIX_OBJ=${_ATTR_NAME}
3221      -    }
3222      -    [ $DEBUG -eq 1 ] && ${ECHO} "Suffix entry object is ${LDAP_SUFFIX_OBJ}"
     3604 +        EE['1.3.6.1.4.1.42.2.27.5.1.24']="'SolarisDataSearchDN' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
     3605 +        OD['1.3.6.1.4.1.42.2.27.5.1.24']="'SolarisDataSearchDN' DESC 'Search DN for data lookup in \":(DN0),(DN1),...\" format' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Solaris Specific'"
3223 3606  
3224      -    # find out an aci for suffix entry if it is not defined yet
3225      -    [ -z "${LDAP_SUFFIX_ACI}" ] &&
3226      -    {
3227      -        # set Directory Server default aci
3228      -        LDAP_SUFFIX_ACI=`cat <<EOF
3229      -aci: (targetattr != "userPassword || passwordHistory || passwordExpirationTime
3230      - || passwordExpWarned || passwordRetryCount || retryCountResetTime ||
3231      - accountUnlockTime || passwordAllowChangeTime")
3232      - (
3233      -   version 3.0;
3234      -   acl "Anonymous access";
3235      -   allow (read, search, compare) userdn = "ldap:///anyone";
3236      - )
3237      -aci: (targetattr != "nsroledn || aci || nsLookThroughLimit || nsSizeLimit ||
3238      - nsTimeLimit || nsIdleTimeout || passwordPolicySubentry ||
3239      - passwordExpirationTime || passwordExpWarned || passwordRetryCount ||
3240      - retryCountResetTime || accountUnlockTime || passwordHistory ||
3241      - passwordAllowChangeTime")
3242      - (
3243      -   version 3.0;
3244      -   acl "Allow self entry modification except for some attributes";
3245      -   allow (write) userdn = "ldap:///self";
3246      - )
3247      -aci: (targetattr = "*")
3248      - (
3249      -   version 3.0;
3250      -   acl "Configuration Administrator";
3251      -   allow (all) userdn = "ldap:///uid=admin,ou=Administrators,
3252      -                         ou=TopologyManagement,o=NetscapeRoot";
3253      - )
3254      -aci: (targetattr ="*")
3255      - (
3256      -   version 3.0;
3257      -   acl "Configuration Administrators Group";
3258      -   allow (all) groupdn = "ldap:///cn=Configuration Administrators,
3259      -                          ou=Groups,ou=TopologyManagement,o=NetscapeRoot";
3260      - )
3261      -EOF
3262      -`
3263      -    }
3264      -    [ $DEBUG -eq 1 ] && cat <<EOF
3265      -DEBUG: ACI for ${LDAP_SUFFIX} is
3266      -${LDAP_SUFFIX_ACI}
3267      -EOF
     3607 +        EE['1.3.6.1.4.1.42.2.27.5.1.25']="'SolarisSearchScope' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3608 +        OD['1.3.6.1.4.1.42.2.27.5.1.25']="'SolarisSearchScope' DESC 'Scope to be used for search operations eg. \"NS_LDAP_SCOPE_BASE\", \"NS_LDAP_SCOPE_ONELEVEL\" or \"NS_LDAP_SCOPE_SUBTREE\"' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"     # Directory vs. IA5 String
3268 3609  
3269      -    NEED_CREATE_BACKEND=
     3610 +        EE['1.3.6.1.4.1.42.2.27.5.1.26']="'SolarisSearchTimeLimit' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE"
     3611 +        OD['1.3.6.1.4.1.42.2.27.5.1.26']="'SolarisSearchTimeLimit' DESC 'Time Limit in seconds for search operations' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"
3270 3612  
3271      -    # check the suffix mapping tree ...
3272      -    # if mapping exists, suffix should work, otherwise DS inconsistent
3273      -    # NOTE: -b 'cn=mapping tree,cn=config' -s one 'cn=\"$1\"' won't work
3274      -    #       in case of 'cn' value in LDAP is not quoted by '"',
3275      -    #       -b 'cn=\"$1\",cn=mapping tree,cn=config' works in all cases
3276      -    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} \
3277      -        -b 'cn=\"${LDAP_SUFFIX}\",cn=mapping tree,cn=config' \
3278      -        -s base 'objectclass=*' dn ${VERB}" &&
3279      -    {
3280      -        [ $DEBUG -eq 1 ] && ${ECHO} "Suffix mapping already exists"
3281      -        # get_backend() either gets IDS_DATABASE or exits
3282      -        get_backend
3283      -        return 0
3284      -    }
     3613 +        EE['1.3.6.1.4.1.42.2.27.5.1.27']="'SolarisPreferredServer' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
     3614 +        OD['1.3.6.1.4.1.42.2.27.5.1.27']="'SolarisPreferredServer' DESC 'Preferred LDAP Server address or network number' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Solaris Specific'" # Directory vs. IA5 String
3285 3615  
3286      -    # no suffix mapping, just in case check ldbm backends consistency -
3287      -    # there are must be NO any databases pointing to LDAP_SUFFIX 
3288      -    [ -n "`${EVAL} \"${LDAPSEARCH} ${LDAP_ARGS} \
3289      -        -b 'cn=ldbm database,cn=plugins,cn=config' \
3290      -        -s one 'nsslapd-suffix=${LDAP_SUFFIX}' dn\" 2>/dev/null`" ] &&
3291      -    {
3292      -        display_msg sfx_config_incons
3293      -        return 1
3294      -    }
     3616 +        EE['1.3.6.1.4.1.42.2.27.5.1.28']="'SolarisPreferredServerOnly' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3617 +        OD['1.3.6.1.4.1.42.2.27.5.1.28']="'SolarisPreferredServerOnly' DESC 'Boolean flag for use of preferredServer or not' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"        # Directory vs. Boolean String
3295 3618  
3296      -    # ok, no suffix mapping, no ldbm database
3297      -    [ $DEBUG -eq 1 ] && ${ECHO} "DEBUG: backend needs to be created ..."
3298      -    NEED_CREATE_BACKEND=1
3299      -    return 0
3300      -}
     3619 +        EE['1.3.6.1.4.1.42.2.27.5.1.29']="'SolarisSearchReferral' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3620 +        OD['1.3.6.1.4.1.42.2.27.5.1.29']="'SolarisSearchReferral' DESC 'referral chasing option eg. \"NS_LDAP_NOREF\" or \"NS_LDAP_FOLLOWREF\"' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"      # Directory vs. IA5 String
3301 3621  
3302      -#
3303      -# prepare for the suffix backend creation
3304      -#
3305      -# input  : IDS_DATABASE - requested ldbm db name (must be not null)
3306      -# in/out : IDS_DATABASE_AVAIL - available ldbm db name
3307      -# return : 0 - ldbm db name ok
3308      -#          1 - IDS_DATABASE exists,
3309      -#              so IDS_DATABASE_AVAIL contains available name
3310      -#          2 - unable to find any available name
3311      -#
3312      -prep_create_sfx_backend()
3313      -{
3314      -    [ $DEBUG -eq 1 ] && ${ECHO} "In prep_create_sfx_backend()"
     3622 +        EE['1.3.6.1.4.1.42.2.27.5.1.4']="'SolarisAttrKeyValue' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3623 +        OD['1.3.6.1.4.1.42.2.27.5.1.4']="'SolarisAttrKeyValue' DESC 'Semi-colon separated key=value pairs of attributes' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'" # Directory vs. IA5 String
3315 3624  
3316      -    # check if requested name available
3317      -    [ "${IDS_DATABASE}" = "${IDS_DATABASE_AVAIL}" ] && return 0
     3625 +        EE['1.3.6.1.4.1.42.2.27.5.1.5']="'SolarisAuditAlways' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3626 +        OD['1.3.6.1.4.1.42.2.27.5.1.5']="'SolarisAuditAlways' DESC 'Always audited attributes per-user' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"      # Directory vs. IA5 String
3318 3627  
3319      -    # get the list of database names start with a requested name
3320      -    _LDBM_DBS=`${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} \
3321      -        -b 'cn=ldbm database,cn=plugins,cn=config' \
3322      -        -s one 'cn=${IDS_DATABASE}*' cn"` 2>/dev/null
     3628 +        EE['1.3.6.1.4.1.42.2.27.5.1.6']="'SolarisAuditNever' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3629 +        OD['1.3.6.1.4.1.42.2.27.5.1.6']="'SolarisAuditNever' DESC 'Never audited attributes per-user' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"        # Directory vs. IA5 String
3323 3630  
3324      -    # find available db name based on a requested name
3325      -    _i=""; _i_MAX=10
3326      -    while [ ${_i:-0} -lt ${_i_MAX} ]
3327      -    do
3328      -        _name="${IDS_DATABASE}${_i}"
3329      -        ${ECHO} "${_LDBM_DBS}" | ${GREP} -i "^cn=${_name}$" >/dev/null 2>&1 ||
3330      -        {
3331      -                IDS_DATABASE_AVAIL="${_name}"
3332      -                break
3333      -        }
3334      -        _i=`expr ${_i:-0} + 1`
3335      -    done
     3631 +        EE['1.3.6.1.4.1.42.2.27.5.1.7']="'SolarisAttrShortDesc' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3632 +        OD['1.3.6.1.4.1.42.2.27.5.1.7']="'SolarisAttrShortDesc' DESC 'Short description about an entry, used by GUIs' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"        # Directory vs. IA5 String
3336 3633  
3337      -    [ "${IDS_DATABASE}" = "${IDS_DATABASE_AVAIL}" ] && return 0
     3634 +        EE['1.3.6.1.4.1.42.2.27.5.1.8']="'SolarisAttrLongDesc' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3635 +        OD['1.3.6.1.4.1.42.2.27.5.1.8']="'SolarisAttrLongDesc' DESC 'Detail description about an entry' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"      # Directory vs. IA5 String
3338 3636  
3339      -    [ -n "${IDS_DATABASE_AVAIL}" ] &&
3340      -    {
3341      -        display_msg ldbm_db_exist
3342      -        return 1
3343      -    }
     3637 +        EE['1.3.6.1.4.1.42.2.27.5.1.9']="'SolarisKernelSecurityPolicy' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3638 +        OD['1.3.6.1.4.1.42.2.27.5.1.9']="'SolarisKernelSecurityPolicy' DESC 'Solaris kernel security policy' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'" # Directory vs. IA5 String
3344 3639  
3345      -    display_msg unable_find_db_name
3346      -    return 2
3347      -}
     3640 +        EE['1.3.6.1.4.1.42.2.27.5.1.10']="'SolarisProfileType' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3641 +        OD['1.3.6.1.4.1.42.2.27.5.1.10']="'SolarisProfileType' DESC 'Type of object defined in profile'EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"       # Directory vs. IA5 String
3348 3642  
3349      -#
3350      -# add suffix if needed,
3351      -#     suffix entry and backend MUST be prepared by
3352      -#     prep_create_sfx_entry and prep_create_sfx_backend correspondingly
3353      -#
3354      -# input  : NEED_CREATE_SUFFIX, LDAP_SUFFIX, LDAP_SUFFIX_OBJ, _ATT, _VAL
3355      -#          LDAP_SUFFIX_ACI, NEED_CREATE_BACKEND, IDS_DATABASE
3356      -# return : 0 - suffix successfully created, otherwise error occured
3357      -#
3358      -add_suffix()
3359      -{
3360      -    [ $DEBUG -eq 1 ] && ${ECHO} "In add_suffix()"
     3643 +        EE['1.3.6.1.4.1.42.2.27.5.1.11']="'SolarisProfileId' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
     3644 +        OD['1.3.6.1.4.1.42.2.27.5.1.11']="'SolarisProfileId' DESC 'Identifier of object defined in profile' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"
3361 3645  
3362      -    [ -n "${NEED_CREATE_SUFFIX}" ] || return 0
     3646 +        EE['1.3.6.1.4.1.42.2.27.5.1.12']="'SolarisUserQualifier' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3647 +        OD['1.3.6.1.4.1.42.2.27.5.1.12']="'SolarisUserQualifier' DESC 'Per-user login attributes' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"    # Directory vs. IA5 String
3363 3648  
3364      -    [ -n "${NEED_CREATE_BACKEND}" ] &&
3365      -    {
3366      -        ${EVAL} "${LDAPADD} ${LDAP_ARGS} ${VERB}" <<EOF
3367      -dn: cn="${LDAP_SUFFIX}",cn=mapping tree,cn=config
3368      -objectclass: top
3369      -objectclass: extensibleObject
3370      -objectclass: nsMappingTree
3371      -cn: ${LDAP_SUFFIX}
3372      -nsslapd-state: backend
3373      -nsslapd-backend: ${IDS_DATABASE}
     3649 +        EE['1.3.6.1.4.1.42.2.27.5.1.13']="'SolarisAttrReserved1' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3650 +        OD['1.3.6.1.4.1.42.2.27.5.1.13']="'SolarisAttrReserved1' DESC 'Reserved for future use' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"      # Directory vs. IA5 String
3374 3651  
3375      -dn: cn=${IDS_DATABASE},cn=ldbm database,cn=plugins,cn=config
3376      -objectclass: top
3377      -objectclass: extensibleObject
3378      -objectclass: nsBackendInstance
3379      -cn: ${IDS_DATABASE}
3380      -nsslapd-suffix: ${LDAP_SUFFIX}
3381      -EOF
3382      -        [ $? -ne 0 ] &&
3383      -        {
3384      -                display_msg create_ldbm_db_error
3385      -                return 1
3386      -        }
     3652 +        EE['1.3.6.1.4.1.42.2.27.5.1.14']="'SolarisAttrReserved2' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3653 +        OD['1.3.6.1.4.1.42.2.27.5.1.14']="'SolarisAttrReserved2' DESC 'Reserved for future use' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"      # Directory vs. IA5 String
3387 3654  
3388      -        ${ECHO} "  ${STEP}. Database ${IDS_DATABASE} successfully created"
3389      -        STEP=`expr $STEP + 1`
3390      -    }
     3655 +        EE['1.3.6.1.4.1.42.2.27.5.1.1']="'SolarisProjectID' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE"
     3656 +        OD['1.3.6.1.4.1.42.2.27.5.1.1']="'SolarisProjectID' DESC 'Unique ID for a Solaris Project entry' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"
3391 3657  
3392      -    ${EVAL} "${LDAPADD} ${LDAP_ARGS} ${VERB}" <<EOF
3393      -dn: ${LDAP_SUFFIX}
3394      -objectclass: ${LDAP_SUFFIX_OBJ}
3395      -${_ATT}: ${_VAL}
3396      -${LDAP_SUFFIX_ACI}
3397      -EOF
3398      -    [ $? -ne 0 ] &&
3399      -    {
3400      -        display_msg create_suffix_entry_error
3401      -        return 1
3402      -    }
     3658 +        EE['1.3.6.1.4.1.42.2.27.5.1.2']="'SolarisProjectName' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
     3659 +        OD['1.3.6.1.4.1.42.2.27.5.1.2']="'SolarisProjectName' DESC 'Name of a Solaris Project Entry' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"
3403 3660  
3404      -    ${ECHO} "  ${STEP}. Suffix ${LDAP_SUFFIX} successfully created"
3405      -    STEP=`expr $STEP + 1`
3406      -    return 0
3407      -}
     3661 +        EE['1.3.6.1.4.1.42.2.27.5.1.3']="'SolarisProjectAttr' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26"
     3662 +        OD['1.3.6.1.4.1.42.2.27.5.1.3']="'SolarisProjectAttr' DESC 'Attributes of a Solaris Project entry' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"
3408 3663  
3409      -#
3410      -# interactively get suffix and related info from a user
3411      -#
3412      -# input  : LDAP_BASEDN - Base DN
3413      -# output : LDAP_SUFFIX - Suffix, _ATT, _VAL - id attribute and its value;
3414      -#          LDAP_SUFFIX_OBJ, LDAP_SUFFIX_ACI - objectclass and aci;
3415      -#          NEED_CREATE_BACKEND - tells whether backend needs to be created;
3416      -#          IDS_DATABASE - prepared ldbm db name
3417      -# return : 0 - user gave a correct suffix 
3418      -#          1 - suffix given by user cann't be created
3419      -#
3420      -get_suffix()
3421      -{
3422      -    [ $DEBUG -eq 1 ] && ${ECHO} "In get_suffix()"
     3664 +        EE[${MEMBERGID_OID}]="'memberGid' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26"
     3665 +        OD[${MEMBERGID_OID}]="'memberGid' DESC 'Posix Group Name' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Solaris Specific'"
3423 3666  
3424      -    while :
3425      -    do
3426      -        get_ans "Enter suffix to be created (b=back/h=help):" ${LDAP_BASEDN}
3427      -        case "${ANS}" in
3428      -        [Hh] | Help | help | \? ) display_msg create_suffix_help ;;
3429      -        [Bb] | Back | back | \< ) return 1 ;;
3430      -        * )
3431      -                format_string "${ANS}"
3432      -                LDAP_SUFFIX=${FMT_STR}
3433      -                prep_create_sfx_entry || continue
     3667 +        EE['1.3.6.1.4.1.11.1.3.1.1.0']="'defaultServerList' DESC 'Default LDAP server host address used by a DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3668 +        OD['1.3.6.1.4.1.11.1.3.1.1.0']="'defaultServerList' DESC 'List of default servers' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 4876'"
3434 3669  
3435      -                [ -n "${NEED_CREATE_BACKEND}" ] &&
3436      -                {
3437      -                    IDS_DATABASE_AVAIL= # reset the available db name
     3670 +        EE['1.3.6.1.4.1.11.1.3.1.1.1']="'defaultSearchBase' DESC 'Default LDAP base DN used by a DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE"
     3671 +        OD['1.3.6.1.4.1.11.1.3.1.1.1']="'defaultSearchBase' DESC 'Default base for searches' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'RFC 4876'"
3438 3672  
3439      -                    reenter_suffix=
3440      -                    while :
3441      -                    do
3442      -                        get_ans "Enter ldbm database name (b=back/h=help):" \
3443      -                                ${IDS_DATABASE_AVAIL:-${_VAL}}
3444      -                        case "${ANS}" in
3445      -                        [Hh] | \? ) display_msg enter_ldbm_db_help ;;
3446      -                        [Bb] | \< ) reenter_suffix=1; break ;;
3447      -                        * )
3448      -                                IDS_DATABASE="${ANS}"
3449      -                                prep_create_sfx_backend && break
3450      -                        esac
3451      -                    done
3452      -                    [ -n "${reenter_suffix}" ] && continue
     3673 +        EE['1.3.6.1.4.1.11.1.3.1.1.2']="'preferredServerList' DESC 'Preferred LDAP server host addresses to be used by a DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3674 +        OD['1.3.6.1.4.1.11.1.3.1.1.2']="'preferredServerList' DESC 'List of preferred servers' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 4876'"
3453 3675  
3454      -                    [ $DEBUG -eq 1 ] && cat <<EOF
3455      -DEBUG: backend name for suffix ${LDAP_SUFFIX} will be ${IDS_DATABASE}
3456      -EOF
3457      -                }
     3676 +        EE['1.3.6.1.4.1.11.1.3.1.1.3']="'searchTimeLimit' DESC 'Maximum time in seconds a DUA should allow for a search to complete' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE"
     3677 +        OD['1.3.6.1.4.1.11.1.3.1.1.3']="'searchTimeLimit' DESC 'Maximum time an agent or service allows for a search to complete' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 4876'"
3458 3678  
3459      -                # eventually everything is prepared
3460      -                return 0
3461      -                ;;
3462      -        esac
3463      -    done
3464      -}
     3679 +        EE['1.3.6.1.4.1.11.1.3.1.1.4']="'bindTimeLimit' DESC 'Maximum time in seconds a DUA should allow for the bind operation to complete' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE"
     3680 +        OD['1.3.6.1.4.1.11.1.3.1.1.4']="'bindTimeLimit' DESC 'Maximum time an agent or service allows for a bind operation to complete' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 4876'"
3465 3681  
3466      -#
3467      -# print out a script which sets LDAP suffix related preferences
3468      -#
3469      -print_suffix_config()
3470      -{
3471      -    cat <<EOF2
3472      -# LDAP suffix related preferences used only if needed
3473      -IDS_DATABASE="${IDS_DATABASE}"
3474      -LDAP_SUFFIX_OBJ="$LDAP_SUFFIX_OBJ"
3475      -LDAP_SUFFIX_ACI=\`cat <<EOF
3476      -${LDAP_SUFFIX_ACI}
3477      -EOF
3478      -\`
3479      -export IDS_DATABASE LDAP_SUFFIX_OBJ LDAP_SUFFIX_ACI
3480      -EOF2
3481      -}
     3682 +        EE['1.3.6.1.4.1.11.1.3.1.1.5']="'followReferrals' DESC 'Tells DUA if it should follow referrals returned by a DSA search result' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3683 +        OD['1.3.6.1.4.1.11.1.3.1.1.5']="'followReferrals' DESC 'An agent or service does or should follow referrals' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'RFC 4876'"        # Directory vs. Boolean String
3482 3684  
3483      -# 
3484      -# check_basedn_suffix(): check that there is an existing 
3485      -# valid suffix to hold current base DN
3486      -# return:
3487      -#   0: valid suffix found or new one should be created,
3488      -#      NEED_CREATE_SUFFIX flag actually indicates that
3489      -#   1: some error occures
3490      -#
3491      -check_basedn_suffix()
3492      -{
3493      -    [ $DEBUG -eq 1 ] && ${ECHO} "In check_basedn_suffix()"
     3685 +        EE['1.3.6.1.4.1.11.1.3.1.1.6']="'authenticationMethod' DESC 'A keystring which identifies the type of authentication method used to contact the DSA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3686 +        OD['1.3.6.1.4.1.11.1.3.1.1.6']="'authenticationMethod' DESC 'Identifies the types of authentication methods either used, required, or provided by a service or peer' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 4876'"
3494 3687  
3495      -    NEED_CREATE_SUFFIX=
     3688 +        EE['1.3.6.1.4.1.11.1.3.1.1.7']="'profileTTL' DESC 'Time to live before a client DUA should re-read this configuration profile' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE"
     3689 +        OD['1.3.6.1.4.1.11.1.3.1.1.7']="'profileTTL' DESC 'Time to live, in seconds, before a profile is considered stale' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 4876'"
3496 3690  
3497      -    # find out existing suffixes
3498      -    discover_serv_suffix
     3691 +        EE['1.3.6.1.4.1.11.1.3.1.1.14']="'serviceSearchDescriptor' DESC 'LDAP search descriptor list used by Naming-DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26"
     3692 +        OD['1.3.6.1.4.1.11.1.3.1.1.14']="'serviceSearchDescriptor' DESC 'Specifies search descriptors required, used, or supported by a particular service or agent' EQUALITY caseExactMatch SUBSTR caseExactSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 4876'"  # IA5 vs. Directory String
3499 3693  
3500      -    ${ECHO} "  Validating LDAP Base DN and Suffix ..."
     3694 +        EE['1.3.6.1.4.1.11.1.3.1.1.9']="'attributeMap' DESC 'Attribute mappings used by a Naming-DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
     3695 +        OD['1.3.6.1.4.1.11.1.3.1.1.9']="'attributeMap' DESC 'Attribute mappings used, required, or supported by an agent or service' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC 4876'"      # Directory vs. IA5 String
3501 3696  
3502      -    # check that LDAP Base DN might be added
3503      -    cur_ldap_entry=${LDAP_BASEDN}
3504      -    prev_ldap_entry=
3505      -    while [ "${cur_ldap_entry}" != "${prev_ldap_entry}" ]
3506      -    do
3507      -        [ $DEBUG -eq 1 ] && ${ECHO} "testing LDAP entry: ${cur_ldap_entry}"
3508      -        ${LDAPSEARCH} ${SERVER_ARGS} -b "${cur_ldap_entry}" \
3509      -                -s one "objectclass=*" > /dev/null 2>&1
3510      -        if [ $? -eq 0 ]; then 
3511      -            break
3512      -        else
3513      -            prev_ldap_entry=${cur_ldap_entry}
3514      -            cur_ldap_entry=`${ECHO} ${cur_ldap_entry} | cut -f2- -d','`
3515      -        fi      
3516      -    done
     3697 +        EE['1.3.6.1.4.1.11.1.3.1.1.10']="'credentialLevel' DESC 'Identifies type of credentials a DUA should use when binding to the LDAP server' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3698 +        OD['1.3.6.1.4.1.11.1.3.1.1.10']="'credentialLevel' DESC 'Identifies type of credentials either used, required, or supported by an agent or service' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'RFC 4876'"  # Directory vs. IA5 String
3517 3699  
3518      -    if [ "${cur_ldap_entry}" = "${prev_ldap_entry}" ]; then
3519      -        ${ECHO} "  No valid suffixes were found for Base DN ${LDAP_BASEDN}"
     3700 +        EE['1.3.6.1.4.1.11.1.3.1.1.11']="'objectclassMap' DESC 'Objectclass mappings used by a Naming-DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
     3701 +        OD['1.3.6.1.4.1.11.1.3.1.1.11']="'objectclassMap' DESC 'Object class mappings used, required, or supported by an agent or service' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC 4876'"        # Directory vs. IA5 String
3520 3702  
3521      -        NEED_CREATE_SUFFIX=1
3522      -        return 0
     3703 +        EE['1.3.6.1.4.1.11.1.3.1.1.12']="'defaultSearchScope' DESC 'Default search scope used by a DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3704 +        OD['1.3.6.1.4.1.11.1.3.1.1.12']="'defaultSearchScope' DESC 'Default scope used when performing a search' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'RFC 4876'"     # Directory vs. IA5 String
3523 3705  
3524      -    else
3525      -        [ $DEBUG -eq 1 ] && ${ECHO} "found valid LDAP entry: ${cur_ldap_entry}"
     3706 +        EE['1.3.6.1.4.1.11.1.3.1.1.13']="'serviceCredentialLevel' DESC 'Search scope used by a service of the DUA' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26"
     3707 +        OD['1.3.6.1.4.1.11.1.3.1.1.13']="'serviceCredentialLevel' DESC 'Specifies the type of credentials either used, required, or supported by a specific service' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC 4876'"
3526 3708  
3527      -        # Now looking for relevant suffix for this entry.
3528      -        # LDAP_SUFFIX will then be used to add necessary
3529      -        # base objects. See add_base_objects().
3530      -        format_string "${cur_ldap_entry}"
3531      -        lower_entry="${FMT_STR}"
3532      -        [ $DEBUG -eq 1 ] && ${ECHO} "final suffix list: ${LDAP_SUFFIX_LIST}"
3533      -        oIFS=$IFS
3534      -        [ $DEBUG -eq 1 ] && ${ECHO} "setting IFS to new line"
3535      -        IFS='
3536      -'
3537      -        for suff in ${LDAP_SUFFIX_LIST}
3538      -        do
3539      -            [ $DEBUG -eq 1 ] && ${ECHO} "testing suffix: ${suff}"
3540      -            format_string "${suff}"
3541      -            lower_suff="${FMT_STR}"
3542      -            if [ "${lower_entry}" = "${lower_suff}" ]; then
3543      -                LDAP_SUFFIX="${suff}"
3544      -                break
3545      -            else
3546      -                dcstmp=`basename "${lower_entry}" "${lower_suff}"`
3547      -                if [ "${dcstmp}" = "${lower_entry}" ]; then
3548      -                    # invalid suffix, try next one
3549      -                    continue
3550      -                else
3551      -                    # valid suffix found
3552      -                    LDAP_SUFFIX="${suff}"
3553      -                    break
3554      -                fi
3555      -            fi
3556      -        done
3557      -        [ $DEBUG -eq 1 ] && ${ECHO} "setting IFS to original value"
3558      -        IFS=$oIFS
     3709 +        EE['1.3.6.1.4.1.11.1.3.1.1.15']="'serviceAuthenticationMethod' DESC 'Authentication Method used by a service of the DUA' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
     3710 +        OD['1.3.6.1.4.1.11.1.3.1.1.15']="'serviceAuthenticationMethod' DESC 'Specifies types authentication methods either used, required, or supported by a particular service' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 4876'"
3559 3711  
3560      -        [ $DEBUG -eq 1 ] && ${ECHO} "LDAP_SUFFIX: ${LDAP_SUFFIX}"
     3712 +        EE['1.3.18.0.2.4.1140']="'printer-uri' DESC 'A URI supported by this printer.  This URI SHOULD be used as a relative distinguished name (RDN).  If printer-xri-supported is implemented, then this URI value MUST be listed in a member value of printer-xri-supported.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3713 +        OD['1.3.18.0.2.4.1140']="'printer-uri' DESC 'A URI supported by this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3561 3714  
3562      -        if [ -z "${LDAP_SUFFIX}" ]; then
3563      -            # should not happen, since we found the entry
3564      -            ${ECHO} "Could not find a valid suffix for ${LDAP_BASEDN}."
3565      -            ${ECHO} "Exiting."
3566      -            return 1
3567      -        fi
3568      -        
3569      -        # Getting relevant database (backend)
3570      -        # IDS_DATABASE will then be used to create indexes.
3571      -        get_backend
     3715 +        EE['1.3.18.0.2.4.1107']="'printer-xri-supported' DESC 'The unordered list of XRI (extended resource identifiers) supported by this printer.  Each member of the list consists of a URI (uniform resource identifier) followed by optional authentication and security metaparameters.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
     3716 +        OD['1.3.18.0.2.4.1107']="'printer-xri-supported' DESC 'The unordered list of XRI (extended resource identifiers) supported by this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 3712'"
3572 3717  
3573      -        return 0
3574      -    fi
3575      -}
     3718 +        EE['1.3.18.0.2.4.1135']="'printer-name' DESC 'The site-specific administrative name of this printer, more end-user friendly than a URI.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}  SINGLE-VALUE"
     3719 +        OD['1.3.18.0.2.4.1135']="'printer-name' DESC 'The site-specific administrative name of this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3576 3720  
3577      -#
3578      -# discover_serv_suffix(): This function queries the server to find 
3579      -#    suffixes available
3580      -#  return: 0: OK, suffix found
3581      -#          1: suffix not determined
3582      -discover_serv_suffix()
3583      -{
3584      -    [ $DEBUG -eq 1 ] && ${ECHO} "In discover_serv_suffix()"
     3721 +        EE['1.3.18.0.2.4.1119']="'printer-natural-language-configured' DESC 'The configured language in which error and status messages will be generated (by default) by this printer.  Also, a possible language for printer string attributes set by operator, system administrator, or manufacturer.  Also, the (declared) language of the \"printer-name\", \"printer-location\", \"printer-info\", and \"printer-make-and-model\" attributes of this printer. For example: \"en-us\" (US English) or \"fr-fr\" (French in France) Legal values of language tags conform to [RFC3066] \"Tags for the Identification of Languages\".' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}  SINGLE-VALUE"
     3722 +        OD['1.3.18.0.2.4.1119']="'printer-natural-language-configured' DESC 'The configured natural language in which error and status messages will be generated (by default) by this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3585 3723  
3586      -    # Search the server for the TOP of the TREE.
3587      -    ${LDAPSEARCH} ${SERVER_ARGS} -b "" -s base "objectclass=*" > ${TMPDIR}/checkTOP 2>&1
3588      -    ${GREP} -i namingcontexts ${TMPDIR}/checkTOP | \
3589      -        ${GREP} -i -v NetscapeRoot > ${TMPDIR}/treeTOP
3590      -    NUM_TOP=`wc -l ${TMPDIR}/treeTOP | awk '{print $1}'`
3591      -    case $NUM_TOP in
3592      -        0)
3593      -            [ $DEBUG -eq 1 ] && ${ECHO} "DEBUG: No suffix found in LDAP tree"
3594      -            return 1
3595      -            ;;
3596      -        *)  # build the list of suffixes; take out 'namingContexts=' in
3597      -            # each line of ${TMPDIR}/treeTOP
3598      -            LDAP_SUFFIX_LIST=`cat ${TMPDIR}/treeTOP | 
3599      -                awk '{ printf("%s\n",substr($0,16,length-15)) }'`
3600      -            ;;
3601      -    esac
     3724 +        EE['1.3.18.0.2.4.1136']="'printer-location' DESC 'Identifies the location of the printer. This could include things like: \"in Room 123A\", \"second floor of building XYZ\".' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE"
     3725 +        OD['1.3.18.0.2.4.1136']="'printer-location' DESC 'The physical location of this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3602 3726  
3603      -    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SUFFIX_LIST = $LDAP_SUFFIX_LIST"
3604      -    return 0
3605      -}
     3727 +        EE['1.3.18.0.2.4.1139']="'printer-info' DESC 'Identifies the descriptive information about this printer.  This could include things like: \"This printer can be used for printing color transparencies for HR presentations\", or \"Out of courtesy for others, please print only small (1-5 page) jobs at this printer\", or even \"This printer is going away on July 1, 1997, please find a new printer\".' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE"
     3728 +        OD['1.3.18.0.2.4.1139']="'printer-info' DESC 'Descriptive information about this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3606 3729  
     3730 +        EE['1.3.18.0.2.4.1134']="'printer-more-info' DESC 'A URI used to obtain more information about this specific printer.  For example, this could be an HTTP type URI referencing an HTML page accessible to a Web Browser.  The information obtained from this URI is intended for end user consumption.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3731 +        OD['1.3.18.0.2.4.1134']="'printer-more-info' DESC 'A URI for more information about this specific printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3607 3732  
3608      -#
3609      -# modify_cn(): Change the cn from MUST to MAY in ipNetwork.
3610      -#
3611      -modify_cn()
3612      -{
3613      -    [ $DEBUG -eq 1 ] && ${ECHO} "In modify_cn()"
     3733 +        EE['1.3.18.0.2.4.1138']="'printer-make-and-model' DESC 'Identifies the make and model of the device.  The device manufacturer MAY initially populate this attribute.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}  SINGLE-VALUE"
     3734 +        OD['1.3.18.0.2.4.1138']="'printer-make-and-model' DESC 'Make and model of this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3614 3735  
3615      -    ( cat <<EOF
3616      -dn: cn=schema
3617      -changetype: modify
3618      -add: objectclasses
3619      -objectclasses: ( 1.3.6.1.1.1.2.7 NAME 'ipNetwork' DESC 'Standard LDAP objectclass' SUP top STRUCTURAL MUST ipNetworkNumber MAY ( ipNetmaskNumber $ manager $ cn $ l $ description ) X-ORIGIN 'RFC 2307' )
3620      -EOF
3621      -) > ${TMPDIR}/ipNetwork_cn
     3736 +        EE['1.3.18.0.2.4.1133']="'printer-ipp-versions-supported' DESC 'Identifies the IPP protocol version(s) that this printer supports, including major and minor versions, i.e., the version numbers for which this Printer implementation meets the conformance requirements.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}"
     3737 +        OD['1.3.18.0.2.4.1133']="'printer-ipp-versions-supported' DESC 'IPP protocol version(s) that this printer supports.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} X-ORIGIN 'RFC 3712'"
3622 3738  
3623      -    # Modify the cn for ipNetwork.
3624      -    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/ipNetwork_cn ${VERB}"
3625      -    if [ $? -ne 0 ]; then
3626      -        ${ECHO} "  ERROR: update of cn for ipNetwork failed!"
3627      -        cleanup
3628      -        exit 1
3629      -    fi
3630      -}
     3739 +        EE['1.3.18.0.2.4.1132']="'printer-multiple-document-jobs-supported' DESC 'Indicates whether or not the printer supports more than one document per job, i.e., more than one Send-Document or Send-Data operation with document data.' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE"
     3740 +        OD['1.3.18.0.2.4.1132']="'printer-multiple-document-jobs-supported' DESC 'Indicates whether or not this printer supports more than one document per job.' EQUALITY booleanMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3631 3741  
     3742 +        EE['1.3.18.0.2.4.1109']="'printer-charset-configured' DESC 'The configured charset in which error and status messages will be generated (by default) by this printer.  Also, a possible charset for printer string attributes set by operator, system administrator, or manufacturer.  For example: \"utf-8\" (ISO 10646/Unicode) or \"iso-8859-1\" (Latin1).  Legal values are defined by the IANA Registry of Coded Character Sets and the \"(preferred MIME name)\" SHALL be used as the tag.  For coherence with IPP Model, charset tags in this attribute SHALL be lowercase normalized.  This attribute SHOULD be static (time of registration) and SHOULD NOT be dynamically refreshed attributetypes: (subsequently).' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{63} SINGLE-VALUE"
     3743 +        OD['1.3.18.0.2.4.1109']="'printer-charset-configured' DESC 'The configured charset in which error and status messages will be generated (by default) by this printer.' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{63} SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3632 3744  
3633      -# modify_timelimit(): Modify timelimit to user value.
3634      -modify_timelimit()
3635      -{
3636      -    [ $DEBUG -eq 1 ] && ${ECHO} "In modify_timelimit()"
     3745 +        EE['1.3.18.0.2.4.1131']="'printer-charset-supported' DESC 'Identifies the set of charsets supported for attribute type values of type Directory String for this directory entry.  For example: \"utf-8\" (ISO 10646/Unicode) or \"iso-8859-1\" (Latin1).  Legal values are defined by the IANA Registry of Coded Character Sets and the preferred MIME name.' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{63}"
     3746 +        OD['1.3.18.0.2.4.1131']="'printer-charset-supported' DESC 'Set of charsets supported for the attribute values of syntax DirectoryString for this directory entry.' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{63} X-ORIGIN 'RFC 3712'"
3637 3747  
3638      -    # Here doc to modify timelimit.
3639      -    ( cat <<EOF
3640      -dn: cn=config
3641      -changetype: modify
3642      -replace: nsslapd-timelimit
3643      -nsslapd-timelimit: ${IDS_TIMELIMIT}
3644      -EOF
3645      -) > ${TMPDIR}/ids_timelimit
     3748 +        EE['1.3.18.0.2.4.1137']="'printer-generated-natural-language-supported' DESC 'Identifies the natural language(s) supported for this directory entry.  For example: \"en-us\" (US English) or \"fr-fr\" (French in France).  Legal values conform to [RFC3066], Tags for the Identification of Languages.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{63}"
     3749 +        OD['1.3.18.0.2.4.1137']="'printer-generated-natural-language-supported' DESC 'Natural language(s) supported for this directory entry.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{63} X-ORIGIN 'RFC 3712'"
3646 3750  
3647      -    # Add the entry.
3648      -    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/ids_timelimit ${VERB}"
3649      -    if [ $? -ne 0 ]; then
3650      -        ${ECHO} "  ERROR: update of nsslapd-timelimit failed!"
3651      -        cleanup
3652      -        exit 1
3653      -    fi
     3751 +        EE['1.3.18.0.2.4.1130']="'printer-document-format-supported' DESC 'The possible document formats in which data may be interpreted and printed by this printer.  Legal values are MIME types come from the IANA Registry of Internet Media Types.' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}"
     3752 +        OD['1.3.18.0.2.4.1130']="'printer-document-format-supported' DESC 'The possible source document formats which may be interpreted and printed by this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} X-ORIGIN 'RFC 3712'"
3654 3753  
3655      -    # Display messages for modifications made in patch.
3656      -    ${ECHO} "  ${STEP}. Changed timelimit to ${IDS_TIMELIMIT} in cn=config."
3657      -    STEP=`expr $STEP + 1`
3658      -}
     3754 +        EE['1.3.18.0.2.4.1129']="'printer-color-supported' DESC 'Indicates whether this printer is capable of any type of color printing at all, including highlight color.' EQUALITY booleanMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE"
     3755 +        OD['1.3.18.0.2.4.1129']="'printer-color-supported' DESC 'Indicates whether this printer is capable of any type of color printing at all, including highlight color.' EQUALITY booleanMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3659 3756  
     3757 +        EE['1.3.18.0.2.4.1128']="'printer-compression-supported' DESC 'Compression algorithms supported by this printer.  For example: \"deflate, gzip\".  Legal values include; \"none\", \"deflate\" attributetypes: (public domain ZIP), \"gzip\" (GNU ZIP), \"compress\" (UNIX).' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{255}"
     3758 +        OD['1.3.18.0.2.4.1128']="'printer-compression-supported' DESC 'Compression algorithms supported by this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{255} X-ORIGIN 'RFC 3712'"
3660 3759  
3661      -# modify_sizelimit(): Modify sizelimit to user value.
3662      -modify_sizelimit()
3663      -{
3664      -    [ $DEBUG -eq 1 ] && ${ECHO} "In modify_sizelimit()"
     3760 +        EE['1.3.18.0.2.4.1127']="'printer-pages-per-minute' DESC 'The nominal number of pages per minute which may be output by this printer (e.g., a simplex or black-and-white printer).  This attribute is informative, NOT a service guarantee.  Typically, it is the value used in marketing literature to describe this printer.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE"
     3761 +        OD['1.3.18.0.2.4.1127']="'printer-pages-per-minute' DESC 'The nominal number of pages per minute which may be output by this printer.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3665 3762  
3666      -    # Here doc to modify sizelimit.
3667      -    ( cat <<EOF
3668      -dn: cn=config
3669      -changetype: modify
3670      -replace: nsslapd-sizelimit
3671      -nsslapd-sizelimit: ${IDS_SIZELIMIT}
3672      -EOF
3673      -) > ${TMPDIR}/ids_sizelimit
     3763 +        EE['1.3.18.0.2.4.1126']="'printer-pages-per-minute-color' DESC 'The nominal number of color pages per minute which may be output by this printer (e.g., a simplex or color printer).  This attribute is informative, NOT a service guarantee.  Typically, it is the value used in marketing literature to describe this printer.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE"
     3764 +        OD['1.3.18.0.2.4.1126']="'printer-pages-per-minute-color' DESC 'The nominal number of color pages per minute which may be output by this printer.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3674 3765  
3675      -    # Add the entry.
3676      -    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/ids_sizelimit ${VERB}"
3677      -    if [ $? -ne 0 ]; then
3678      -        ${ECHO} "  ERROR: update of nsslapd-sizelimit failed!"
3679      -        cleanup
3680      -        exit 1
3681      -    fi
     3766 +        EE['1.3.18.0.2.4.1125']="'printer-finishings-supported' DESC 'The possible finishing operations supported by this printer. Legal values include; \"none\", \"staple\", \"punch\", \"cover\", \"bind\", \"saddle-stitch\", \"edge-stitch\", \"staple-top-left\", \"staple-bottom-left\", \"staple-top-right\", \"staple-bottom-right\", \"edge-stitch-left\", \"edge-stitch-top\", \"edge-stitch-right\", \"edge-stitch-bottom\", \"staple-dual-left\", \"staple-dual-top\", \"staple-dual-right\", \"staple-dual-bottom\".' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{255}"
     3767 +        OD['1.3.18.0.2.4.1125']="'printer-finishings-supported' DESC 'The possible finishing operations supported by this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{255} X-ORIGIN 'RFC 3712'"
3682 3768  
3683      -    # Display messages for modifications made in patch.
3684      -    ${ECHO} "  ${STEP}. Changed sizelimit to ${IDS_SIZELIMIT} in cn=config."
3685      -    STEP=`expr $STEP + 1`
3686      -}
     3769 +        EE['1.3.18.0.2.4.1124']="'printer-number-up-supported' DESC 'The possible numbers of print-stream pages to impose upon a single side of an instance of a selected medium. Legal values include; 1, 2, and 4.  Implementations may support other values.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.27"
     3770 +        OD['1.3.18.0.2.4.1124']="'printer-number-up-supported' DESC 'The possible numbers of print-stream pages to impose upon a single side of an instance of a selected medium.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.27 X-ORIGIN 'RFC 3712'"
3687 3771  
     3772 +        EE['1.3.18.0.2.4.1123']="'printer-sides-supported' DESC 'The number of impression sides (one or two) and the two-sided impression rotations supported by this printer.  Legal values include; \"one-sided\", \"two-sided-long-edge\", \"two-sided-short-edge\".' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}"
     3773 +        OD['1.3.18.0.2.4.1123']="'printer-sides-supported' DESC 'The number of impression sides (one or two) and the two-sided impression rotations supported by this printer.' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} X-ORIGIN 'RFC 3712'"
3688 3774  
3689      -# modify_pwd_crypt(): Modify the passwd storage scheme to support CRYPT.
3690      -modify_pwd_crypt()
3691      -{
3692      -    [ $DEBUG -eq 1 ] && ${ECHO} "In modify_pwd_crypt()"
     3775 +        EE['1.3.18.0.2.4.1122']="'printer-media-supported' DESC 'The standard names/types/sizes (and optional color suffixes) of the media supported by this printer.  For example: \"iso-a4\",  \"envelope\", or \"na-letter-white\".  Legal values  conform to ISO 10175, Document Printing Application (DPA), and any IANA registered extensions.' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{255}"
     3776 +        OD['1.3.18.0.2.4.1122']="'printer-media-supported' DESC 'The standard names/types/sizes (and optional color suffixes) of the media supported by this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{255} X-ORIGIN 'RFC 3712'"
3693 3777  
3694      -    # Here doc to modify passwordstoragescheme.
3695      -    # IDS 5.2 moved passwordchangesceme off to a new data structure.
3696      -    if [ $IDS_MAJVER -le 5 ] && [ $IDS_MINVER -le 1 ]; then 
3697      -        ( cat <<EOF
3698      -dn: cn=config
3699      -changetype: modify
3700      -replace: passwordstoragescheme
3701      -passwordstoragescheme: crypt
3702      -EOF
3703      -        ) > ${TMPDIR}/ids_crypt
3704      -    else
3705      -        ( cat <<EOF
3706      -dn: cn=Password Policy,cn=config
3707      -changetype: modify
3708      -replace: passwordstoragescheme
3709      -passwordstoragescheme: crypt
3710      -EOF
3711      -        ) > ${TMPDIR}/ids_crypt
3712      -    fi
     3778 +        EE['1.3.18.0.2.4.1117']="'printer-media-local-supported' DESC 'Site-specific names of media supported by this printer, in the language in \"printer-natural-language-configured\".  For example: \"purchasing-form\" (site-specific name) as opposed to (in \"printer-media-supported\"): \"na-letter\" (standard keyword from ISO 10175).' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{255}"
     3779 +        OD['1.3.18.0.2.4.1117']="'printer-media-local-supported' DESC 'Site-specific names of media supported by this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{255} X-ORIGIN 'RFC 3712'"
3713 3780  
3714      -    # Add the entry.
3715      -    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/ids_crypt ${VERB}"
3716      -    if [ $? -ne 0 ]; then
3717      -        ${ECHO} "  ERROR: update of passwordstoragescheme failed!"
3718      -        cleanup
3719      -        exit 1
3720      -    fi
     3781 +        EE['1.3.18.0.2.4.1121']="'printer-resolution-supported' DESC 'List of resolutions supported for printing documents by this printer.  Each resolution value is a string with 3 fields:  1) Cross feed direction resolution (positive integer), 2) Feed direction resolution (positive integer), 3) Resolution unit.  Legal values are \"dpi\" (dots per inch) and \"dpcm\" (dots per centimeter).  Each resolution field is delimited by \">\".  For example:  \"300> 300> dpi>\".' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{255}"
     3782 +        OD['1.3.18.0.2.4.1121']="'printer-resolution-supported' DESC 'List of resolutions supported for printing documents by this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{255} X-ORIGIN 'RFC 3712'"
3721 3783  
3722      -    # Display messages for modifications made in patch.
3723      -    ${ECHO} "  ${STEP}. Changed passwordstoragescheme to \"crypt\" in cn=config."
3724      -    STEP=`expr $STEP + 1`
3725      -}
     3784 +        EE['1.3.18.0.2.4.1120']="'printer-print-quality-supported' DESC 'List of print qualities supported for printing documents on this printer.  For example: \"draft, normal\".  Legal values include; \"unknown\", \"draft\", \"normal\", \"high\".' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}"
     3785 +        OD['1.3.18.0.2.4.1120']="'printer-print-quality-supported' DESC 'List of print qualities supported for printing documents on this printer.' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} X-ORIGIN 'RFC 3712'"
3726 3786  
     3787 +        EE['1.3.18.0.2.4.1110']="'printer-job-priority-supported' DESC 'Indicates the number of job priority levels supported.  An IPP conformant printer which supports job priority must always support a full range of priorities from \"1\" to \"100\" (to ensure consistent behavior), therefore this attribute describes the \"granularity\".  Legal values of this attribute are from \"1\" to \"100\".' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE"
     3788 +        OD['1.3.18.0.2.4.1110']="'printer-job-priority-supported' DESC 'Indicates the number of job priority levels supported by this printer.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3727 3789  
3728      -#
3729      -# add_eq_indexes(): Add indexes to improve search performance.
3730      -#
3731      -add_eq_indexes()
3732      -{
3733      -    [ $DEBUG -eq 1 ] && ${ECHO} "In add_eq_indexes()"
     3790 +        EE['1.3.18.0.2.4.1118']="'printer-copies-supported' DESC 'The maximum number of copies of a document that may be printed as a single job.  A value of \"0\" indicates no maximum limit.  A value of \"-1\" indicates unknown.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE"
     3791 +        OD['1.3.18.0.2.4.1118']="'printer-copies-supported' DESC 'The maximum number of copies of a document that may be printed as a single job on this printer.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3734 3792  
3735      -    # Set eq indexes to add.
3736      -    _INDEXES="uidNumber ipNetworkNumber gidnumber oncrpcnumber automountKey"
     3793 +        EE['1.3.18.0.2.4.1111']="'printer-job-k-octets-supported' DESC 'The maximum size in kilobytes (1,024 octets actually) incoming print job that this printer will accept.  A value of \"0\" indicates no maximum limit.  A value of \"-1\" indicates unknown.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE"
     3794 +        OD['1.3.18.0.2.4.1111']="'printer-job-k-octets-supported' DESC 'The maximum size in kilobytes (1,024 octets actually) incoming print job that this printer will accept.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3737 3795  
3738      -    if [ -z "${IDS_DATABASE}" ]; then
3739      -        get_backend
3740      -    fi
     3796 +        EE['1.3.18.0.2.4.1112']="'printer-current-operator' DESC 'The name of the current human operator responsible for operating this printer.  It is suggested that this string include information that would enable other humans to reach the operator, such as a phone number.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE"
     3797 +        OD['1.3.18.0.2.4.1112']="'printer-current-operator' DESC 'The identity of the current human operator responsible for operating this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3741 3798  
3742      -    # Set _EXT to use as shortcut.
3743      -    _EXT="cn=index,cn=${IDS_DATABASE},cn=ldbm database,cn=plugins,cn=config"
     3799 +        EE['1.3.18.0.2.4.1113']="'printer-service-person' DESC 'The name of the current human service person responsible for servicing this printer.  It is suggested that this string include information that would enable other humans to reach the service person, such as a phone number.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}  SINGLE-VALUE"
     3800 +        OD['1.3.18.0.2.4.1113']="'printer-service-person' DESC 'The identity of the current human service person responsible for servicing this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3744 3801  
3745      -    # Display message to id current step.
3746      -    ${ECHO} "  ${STEP}. Processing eq,pres indexes:"
3747      -    STEP=`expr $STEP + 1`
     3802 +        EE['1.3.18.0.2.4.1114']="'printer-delivery-orientation-supported' DESC 'The possible delivery orientations of pages as they are printed and ejected from this printer.  Legal values include; \"unknown\", \"face-up\", and \"face-down\".' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}"
     3803 +        OD['1.3.18.0.2.4.1114']="'printer-delivery-orientation-supported' DESC 'The possible delivery orientations of pages as they are printed and ejected from this printer.' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} X-ORIGIN 'RFC 3712'"
3748 3804  
3749      -    # For loop to create indexes.
3750      -    for i in ${_INDEXES}; do
3751      -        [ $DEBUG -eq 1 ] && ${ECHO} "  Adding index for ${i}"
     3805 +        EE['1.3.18.0.2.4.1115']="'printer-stacking-order-supported' DESC 'The possible stacking order of pages as they are printed and ejected from this printer. Legal values include; \"unknown\", \"first-to-last\", \"last-to-first\".' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}"
     3806 +        OD['1.3.18.0.2.4.1115']="'printer-stacking-order-supported' DESC 'The possible stacking order of pages as they are printed and ejected from this printer.' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} X-ORIGIN 'RFC 3712'"
3752 3807  
3753      -        # Check if entry exists first, if so, skip to next.
3754      -        ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${i},${_EXT}\" -s base \
3755      -            \"objectclass=*\" > /dev/null 2>&1"
3756      -        if [ $? -eq 0 ]; then
3757      -            # Display index skipped.
3758      -            ${ECHO} "      ${i} (eq,pres) skipped already exists"       
3759      -            continue
3760      -        fi
     3808 +        EE['1.3.18.0.2.4.1116']="'printer-output-features-supported' DESC 'The possible output features supported by this printer. Legal values include; \"unknown\", \"bursting\", \"decollating\", \"page-collating\", \"offset-stacking\".' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}"
     3809 +        OD['1.3.18.0.2.4.1116']="'printer-output-features-supported' DESC 'The possible output features supported by this printer.' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} X-ORIGIN 'RFC 3712'"
3761 3810  
3762      -        # Here doc to create LDIF.
3763      -        ( cat <<EOF
3764      -dn: cn=${i},${_EXT}
3765      -objectClass: top
3766      -objectClass: nsIndex
3767      -cn: ${i}
3768      -nsSystemIndex: false
3769      -nsIndexType: pres
3770      -nsIndexType: eq
3771      -EOF
3772      -) > ${TMPDIR}/index_${i}
     3811 +        EE['1.3.18.0.2.4.1108']="'printer-aliases' DESC 'Site-specific administrative names of this printer in addition the printer name specified for printer-name.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}"
     3812 +        OD['1.3.18.0.2.4.1108']="'printer-aliases' DESC 'List of site-specific administrative names of this printer in addition to the value specified for printer-name.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} X-ORIGIN 'RFC 3712'"
3773 3813  
3774      -        # Add the index.
3775      -        ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/index_${i} ${VERB}"
3776      -        if [ $? -ne 0 ]; then
3777      -            ${ECHO} "  ERROR: Adding EQ,PRES index for ${i} failed!"
3778      -            cleanup
3779      -            exit 1
3780      -        fi
     3814 +        EE['1.3.6.1.4.1.42.2.27.5.1.63']="'sun-printer-bsdaddr' DESC 'Sets the server, print queue destination name and whether the client generates protocol extensions. \"Solaris\" specifies a Solaris print server extension. The value is represented by the following value: server \",\" destination \", Solaris\".' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
     3815 +        OD['1.3.6.1.4.1.42.2.27.5.1.63']="'sun-printer-bsdaddr' DESC 'Sets the server, print queue destination name and whether the client generates protocol extensions. \"Solaris\" specifies a Solaris print server extension. The value is represented by the following value: server \",\" destination \", Solaris\".' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"
3781 3816  
3782      -        # Build date for task name.
3783      -        _YR=`date '+%y'`
3784      -        _MN=`date '+%m'`
3785      -        _DY=`date '+%d'`
3786      -        _H=`date '+%H'`
3787      -        _M=`date '+%M'`
3788      -        _S=`date '+%S'`
     3817 +        EE['1.3.6.1.4.1.42.2.27.5.1.64']="'sun-printer-kvp' DESC 'This attribute contains a set of key value pairs which may have meaning to the print subsystem or may be user defined. Each value is represented by the following: key \"=\" value.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
     3818 +        OD['1.3.6.1.4.1.42.2.27.5.1.64']="'sun-printer-kvp' DESC 'This attribute contains a set of key value pairs which may have meaning to the print subsystem or may be user defined. Each value is represented by the following: key \"=\" value.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Solaris Specific'"
3789 3819  
3790      -        # Build task name
3791      -        TASKNAME="${i}_${_YR}_${_MN}_${_DY}_${_H}_${_M}_${_S}"
     3820 +        EE['1.3.6.1.4.1.42.2.27.5.1.57']="'nisplusTimeZone' DESC 'tzone column from NIS+ timezone table' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
     3821 +        OD['1.3.6.1.4.1.42.2.27.5.1.57']="'nisplusTimeZone' DESC 'tzone column from NIS+ timezone table' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"
3792 3822  
3793      -        # Build the task entry to add.
3794      -        ( cat <<EOF
3795      -dn: cn=${TASKNAME}, cn=index, cn=tasks, cn=config
3796      -changetype: add
3797      -objectclass: top
3798      -objectclass: extensibleObject
3799      -cn: ${TASKNAME}
3800      -nsInstance: ${IDS_DATABASE}
3801      -nsIndexAttribute: ${i}
3802      -EOF
3803      -) > ${TMPDIR}/task_${i}
     3823 +        EE['1.3.6.1.4.1.42.2.27.5.1.67']="'ipTnetTemplateName' DESC 'Trusted Solaris network template template_name' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
     3824 +        OD['1.3.6.1.4.1.42.2.27.5.1.67']="'ipTnetTemplateName' DESC 'Trusted Solaris network template template_name' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"
3804 3825  
3805      -        # Add the task.
3806      -        ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/task_${i} ${VERB}"
3807      -        if [ $? -ne 0 ]; then
3808      -            ${ECHO} "  ERROR: Adding task for ${i} failed!"
3809      -            cleanup
3810      -            exit 1
     3826 +        EE['1.3.6.1.4.1.42.2.27.5.1.68']="'ipTnetNumber' DESC 'Trusted Solaris network template ip_address' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
     3827 +        OD['1.3.6.1.4.1.42.2.27.5.1.68']="'ipTnetNumber' DESC 'Trusted Solaris network template ip_address' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"
     3828 +
     3829 +        # obey CLI syntax force option (if any)
     3830 +        if (( TMPF[SYNTAX] == 1 )); then
     3831 +                typeset -n MAP=OD
     3832 +        elif (( TMPF[SYNTAX] == 2 )); then
     3833 +                typeset -n MAP=EE
     3834 +        elif (( TMPF[IS_OPENDJ] )); then
     3835 +                typeset -n MAP=OD
     3836 +        else
     3837 +                typeset -n MAP=EE
3811 3838          fi
3812 3839  
3813      -        # Wait for task to finish, display current status.
3814      -        while :
3815      -        do
3816      -            ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} \
3817      -                -b \"cn=${TASKNAME}, cn=index, cn=tasks, cn=config\" -s base \
3818      -                \"objectclass=*\" nstaskstatus > \"${TMPDIR}/istask_${i}\" 2>&1"
3819      -            ${GREP} "${TASKNAME}" "${TMPDIR}/istask_${i}" > /dev/null 2>&1
3820      -            if [ $? -ne 0 ]; then
3821      -                break
3822      -            fi
3823      -            TASK_STATUS=`${GREP} -i nstaskstatus "${TMPDIR}/istask_${i}" |
3824      -                head -1 | cut -d: -f2`
3825      -            ${ECHO} "      ${i} (eq,pres)  $TASK_STATUS                  \r\c"
3826      -            ${ECHO} "$TASK_STATUS" | ${GREP} "Finished" > /dev/null 2>&1
3827      -            if [ $? -eq 0 ]; then
3828      -                break
3829      -            fi
3830      -            sleep 2
     3840 +        typeset TODO='' OID X
     3841 +        for OID in ${!MAP[@]}; do
     3842 +                [[ -n ${OID2ADEF[${OID}]} ]] && continue
     3843 +                X="${MAP[${OID}]}"
     3844 +                TODO+='attributetypes: ( '"${OID} NAME ${X}"' )\n'
     3845 +                OID2ADEF["${OID}"]="${X}"
     3846 +                X=${X:1}
     3847 +                X=${X%%"'"*}    # we have no aliases above
     3848 +                ANAME2OID["${X}"]="${OID}"
3831 3849          done
3832 3850  
3833      -        # Print newline because of \c.
3834      -        ${ECHO} " "
3835      -    done
     3851 +        if [[ -z ${TODO} ]]; then
     3852 +                X='Schema contains all required attribute definitions'
     3853 +        else
     3854 +                nextFile add $0
     3855 +                print 'dn: cn=schema\nchangetype: modify\nadd: attributetypes' \
     3856 +                        "\n${TODO}" >${TMP[FILE]}
     3857 +                if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     3858 +                        >&${TMPF[FD]} 2>&1
     3859 +                then
     3860 +                        Log.fatal 'Adding attribute definitions to schema failed'
     3861 +                        return 67
     3862 +                fi
     3863 +                X='Schema attribute definitions added'
     3864 +        fi
     3865 +        showProgress "${X}."
     3866 +        return 0
3836 3867  }
3837 3868  
     3869 +Man.addFunc update_schema_obj '' '[+NAME?update_schema_obj -  Update DS schema to support Naming Services.]
     3870 +[+DESCRIPTION?Update the schema of the DS with the objectclasses required for the Solaris Naming Services. It just checks, whether the OID is already defined on the server. If already defined, it is left as is, otherwise added.]
     3871 +[+RETURN VALUES]{
     3872 +        [+0?on success.]
     3873 +        [+>= 66?a fatal error occurred.]
     3874 +}
     3875 +[+SEE ALSO?\bupdate_schema_attr()\b, \bldapmodify\b(1).]
     3876 +'
     3877 +function update_schema_obj {
     3878 +        getDSobjectclasses || return 66
3838 3879  
3839      -#
3840      -# add_sub_indexes(): Add indexes to improve search performance.
3841      -#
3842      -add_sub_indexes()
3843      -{
3844      -    [ $DEBUG -eq 1 ] && ${ECHO} "In add_sub_indexes()"
     3880 +        typeset -A EE=( )
     3881 +        typeset -A OD=( )
     3882 +        EE['1.3.6.1.1.1.2.14']="'NisKeyObject' SUP top MUST "'( cn $ nisPublickey $ nisSecretkey ) MAY ( uidNumber $ description )'
     3883 +        OD['1.3.6.1.1.1.2.14']="'nisKeyObject' SUP top AUXILIARY DESC 'An object with a public and secret key' MUST "'( cn $ nisPublicKey $ nisSecretKey ) MAY ( uidNumber $ description )'" X-ORIGIN 'draft-howard-rfc2307bis'"
3845 3884  
3846      -    # Set eq indexes to add.
3847      -    _INDEXES="ipHostNumber membernisnetgroup nisnetgrouptriple"
     3885 +        EE['1.3.6.1.1.1.2.15']="'nisDomainObject' SUP top MUST nisDomain"
     3886 +        OD['1.3.6.1.1.1.2.15']="'nisDomainObject' SUP top AUXILIARY DESC 'Associates a NIS domain with a naming context' MUST nisDomain X-ORIGIN 'draft-howard-rfc2307bis'"
3848 3887  
3849      -    # Set _EXT to use as shortcut.
3850      -    _EXT="cn=index,cn=${IDS_DATABASE},cn=ldbm database,cn=plugins,cn=config"
     3888 +        EE['1.3.6.1.1.1.2.16']="'automountMap' SUP top MUST automountMapName MAY description"
     3889 +        OD['1.3.6.1.1.1.2.16']="'automountMap' SUP top STRUCTURAL MUST ( automountMapName ) MAY description X-ORIGIN 'draft-howard-rfc2307bis'"
3851 3890  
     3891 +        EE['1.3.6.1.1.1.2.17']="'automount' SUP top MUST "'( automountKey $ automountInformation ) MAY description'
     3892 +        OD['1.3.6.1.1.1.2.17']="'automount' SUP top STRUCTURAL DESC 'Automount information' MUST "'( automountKey $ automountInformation )'" MAY description X-ORIGIN 'draft-howard-rfc2307bis'"
3852 3893  
3853      -    # Display message to id current step.
3854      -    ${ECHO} "  ${STEP}. Processing eq,pres,sub indexes:"
3855      -    STEP=`expr $STEP + 1`
     3894 +        EE['1.3.6.1.4.1.42.2.27.5.2.7']="'SolarisNamingProfile' SUP top MUST "'( cn $ SolarisLDAPservers $ SolarisSearchBaseDN ) MAY ( SolarisBindDN $ SolarisBindPassword $ SolarisAuthMethod $ SolarisTransportSecurity $ SolarisCertificatePath $ SolarisCertificatePassword $ SolarisDataSearchDN $ SolarisSearchScope $ SolarisSearchTimeLimit $ SolarisPreferredServer $ SolarisPreferredServerOnly $ SolarisCacheTTL $ SolarisSearchReferral )'
     3895 +        OD['1.3.6.1.4.1.42.2.27.5.2.7']="'SolarisNamingProfile' SUP top STRUCTURAL DESC 'Solaris LDAP Naming client profile objectClass' MUST "'( cn $ SolarisLDAPServers $ SolarisSearchBaseDN ) MAY ( SolarisBindDN $ SolarisBindPassword $ SolarisAuthMethod $ SolarisTransportSecurity $ SolarisCertificatePath $ SolarisCertificatePassword $ SolarisDataSearchDN $ SolarisSearchScope $ SolarisSearchTimeLimit $ SolarisPreferredServer $ SolarisPreferredServerOnly $ SolarisCacheTTL $ SolarisSearchReferral $ SolarisBindTimeLimit )'" X-ORIGIN 'Solaris Specific'"
3856 3896  
3857      -    # For loop to create indexes.
3858      -    for i in ${_INDEXES}; do
3859      -        [ $DEBUG -eq 1 ] && ${ECHO} "  Adding index for ${i}"
     3897 +        EE['2.16.840.1.113730.3.2.4']="'mailGroup' SUP top MUST mail MAY "'( cn $ mgrpRFC822MailMember )'
     3898 +        OD['2.16.840.1.113730.3.2.4']="'mailGroup' SUP top STRUCTURAL MUST mail MAY "'( cn $ mgrpRFC822MailMember )'" X-ORIGIN 'Solaris Specific'"
3860 3899  
3861      -        # Check if entry exists first, if so, skip to next.
3862      -        ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${i},${_EXT}\" \
3863      -            -s base \"objectclass=*\" > /dev/null 2>&1"
3864      -        if [ $? -eq 0 ]; then
3865      -            # Display index skipped.
3866      -            ${ECHO} "      ${i} (eq,pres,sub) skipped already exists"   
3867      -            continue
3868      -        fi
     3900 +        EE['1.3.6.1.4.1.42.2.27.1.2.5']="'nisMailAlias' SUP top MUST cn MAY rfc822mailMember"
     3901 +        OD['1.3.6.1.4.1.42.2.27.1.2.5']="'nisMailAlias' SUP top MUST cn MAY rfc822mailMember X-ORIGIN 'Solaris Specific'"
3869 3902  
3870      -        # Here doc to create LDIF.
3871      -        ( cat <<EOF
3872      -dn: cn=${i},${_EXT}
3873      -objectClass: top
3874      -objectClass: nsIndex
3875      -cn: ${i}
3876      -nsSystemIndex: false
3877      -nsIndexType: pres
3878      -nsIndexType: eq
3879      -nsIndexType: sub
3880      -EOF
3881      -) > ${TMPDIR}/index_${i}
     3903 +        EE['1.3.6.1.4.1.42.2.27.1.2.6']="'nisNetId' SUP top MUST cn MAY "'( nisNetIdUser $ nisNetIdGroup $ nisNetIdHost )'
     3904 +        OD['1.3.6.1.4.1.42.2.27.1.2.6']="'nisNetId' SUP top MUST cn MAY "'( nisNetIdUser $ nisNetIdGroup $ nisNetIdHost )'" X-ORIGIN 'Solaris Specific'"
3882 3905  
3883      -        # Add the index.
3884      -        ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/index_${i} ${VERB}"
3885      -        if [ $? -ne 0 ]; then
3886      -            ${ECHO} "  ERROR: Adding EQ,PRES,SUB index for ${i} failed!"
3887      -            cleanup
3888      -            exit 1
3889      -        fi
     3906 +        EE['1.3.6.1.4.1.42.2.27.5.2.2']="'SolarisAuditUser' SUP top AUXILIARY MAY "'( SolarisAuditAlways $ SolarisAuditNever )'
     3907 +        OD['1.3.6.1.4.1.42.2.27.5.2.2']="'SolarisAuditUser' SUP top AUXILIARY MAY "'( SolarisAuditAlways $ SolarisAuditNever )'" X-ORIGIN 'Solaris Specific'"
3890 3908  
3891      -        # Build date for task name.
3892      -        _YR=`date '+%y'`
3893      -        _MN=`date '+%m'`
3894      -        _DY=`date '+%d'`
3895      -        _H=`date '+%H'`
3896      -        _M=`date '+%M'`
3897      -        _S=`date '+%S'`
     3909 +        EE['1.3.6.1.4.1.42.2.27.5.2.3']="'SolarisUserAttr' SUP top AUXILIARY MAY "'( SolarisUserQualifier $ SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrKeyValue )'
     3910 +        OD['1.3.6.1.4.1.42.2.27.5.2.3']="'SolarisUserAttr' SUP top AUXILIARY DESC 'User attributes' MAY "'( SolarisUserQualifier $ SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrKeyValue )'" X-ORIGIN 'Solaris Specific'"
3898 3911  
3899      -        # Build task name
3900      -        TASKNAME="${i}_${_YR}_${_MN}_${_DY}_${_H}_${_M}_${_S}"
     3912 +        EE['1.3.6.1.4.1.42.2.27.5.2.4']="'SolarisAuthAttr' SUP top MUST cn MAY "'( SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrShortDesc $ SolarisAttrLongDesc $ SolarisAttrKeyValue )'
     3913 +        OD['1.3.6.1.4.1.42.2.27.5.2.4']="'SolarisAuthAttr' SUP top STRUCTURAL DESC 'Authorizations data' MUST cn MAY "'( SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrShortDesc $ SolarisAttrLongDesc $ SolarisAttrKeyValue )'" X-ORIGIN 'Solaris Specific'"
3901 3914  
3902      -        # Build the task entry to add.
3903      -        ( cat <<EOF
3904      -dn: cn=${TASKNAME}, cn=index, cn=tasks, cn=config
3905      -changetype: add
3906      -objectclass: top
3907      -objectclass: extensibleObject
3908      -cn: ${TASKNAME}
3909      -nsInstance: ${IDS_DATABASE}
3910      -nsIndexAttribute: ${i}
3911      -EOF
3912      -) > ${TMPDIR}/task_${i}
     3915 +        EE['1.3.6.1.4.1.42.2.27.5.2.5']="'SolarisProfAttr' SUP top MUST cn MAY "'( SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrLongDesc $ SolarisAttrKeyValue )'
     3916 +        OD['1.3.6.1.4.1.42.2.27.5.2.5']="'SolarisProfAttr' SUP top STRUCTURAL DESC 'Profiles data' MUST cn MAY "'( SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrLongDesc $ SolarisAttrKeyValue )'" X-ORIGIN 'Solaris Specific'"
3913 3917  
3914      -        # Add the task.
3915      -        ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/task_${i} ${VERB}"
3916      -        if [ $? -ne 0 ]; then
3917      -            ${ECHO} "  ERROR: Adding task for ${i} failed!"
3918      -            cleanup
3919      -            exit 1
3920      -        fi
     3918 +        EE['1.3.6.1.4.1.42.2.27.5.2.6']="'SolarisExecAttr' SUP top AUXILIARY MAY "'( SolarisKernelSecurityPolicy $ SolarisProfileType $ SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisProfileID $ SolarisAttrKeyValue )'
     3919 +        OD['1.3.6.1.4.1.42.2.27.5.2.6']="'SolarisExecAttr' SUP top AUXILIARY DESC 'Profiles execution attributes' MAY "'( SolarisKernelSecurityPolicy $ SolarisProfileType $ SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisProfileId $ SolarisAttrKeyValue )'" X-ORIGIN 'Solaris Specific'"
3921 3920  
3922      -        # Wait for task to finish, display current status.
3923      -        while :
3924      -        do
3925      -            ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} \
3926      -                -b \"cn=${TASKNAME}, cn=index, cn=tasks, cn=config\" -s base \
3927      -                \"objectclass=*\" nstaskstatus > \"${TMPDIR}/istask_${i}\" 2>&1"
3928      -            ${GREP} "${TASKNAME}" "${TMPDIR}/istask_${i}" > /dev/null 2>&1
3929      -            if [ $? -ne 0 ]; then
3930      -                break
3931      -            fi
3932      -            TASK_STATUS=`${GREP} -i nstaskstatus "${TMPDIR}/istask_${i}" |
3933      -                head -1 | cut -d: -f2`
3934      -            ${ECHO} "      ${i} (eq,pres,sub)  $TASK_STATUS                  \r\c"
3935      -            ${ECHO} "$TASK_STATUS" | ${GREP} "Finished" > /dev/null 2>&1
3936      -            if [ $? -eq 0 ]; then
3937      -                break
3938      -            fi
3939      -            sleep 2
3940      -        done
     3921 +        EE['1.3.6.1.4.1.42.2.27.5.2.1']="'SolarisProject' SUP top MUST "'( SolarisProjectID $ SolarisProjectName ) MAY ( memberUid $ memberGid $ description $ SolarisProjectAttr )'
     3922 +        OD['1.3.6.1.4.1.42.2.27.5.2.1']="'SolarisProject' SUP top STRUCTURAL MUST "'( SolarisProjectID $ SolarisProjectName ) MAY ( memberUid $ memberGid $ description $ SolarisProjectAttr )'" X-ORIGIN 'Solaris Specific'"
3941 3923  
3942      -        # Print newline because of \c.
3943      -        ${ECHO} " "
3944      -    done
3945      -}
     3924 +        EE['1.3.6.1.4.1.11.1.3.1.2.4']="'DUAConfigProfile' SUP top DESC 'Abstraction of a base configuration for a DUA' MUST cn MAY "'( defaultServerList $ preferredServerList $ defaultSearchBase $ defaultSearchScope $ searchTimeLimit $ bindTimeLimit $ credentialLevel $ authenticationMethod $ followReferrals $ serviceSearchDescriptor $ serviceCredentialLevel $ serviceAuthenticationMethod $ objectclassMap $ attributeMap $ profileTTL )'
     3925 +        OD['1.3.6.1.4.1.11.1.3.1.2.4']="'DUAConfigProfile' SUP top STRUCTURAL DESC 'Abstraction of a base configuration for a DUA' MUST "'( cn ) MAY ( defaultServerList $ preferredServerList $ defaultSearchBase $ defaultSearchScope $ searchTimeLimit $ bindTimeLimit $ credentialLevel $ authenticationMethod $ followReferrals $ dereferenceAliases $ serviceSearchDescriptor $ serviceCredentialLevel $ serviceAuthenticationMethod $ objectclassMap $ attributeMap $ profileTTL )'" X-ORIGIN 'RFC 4876'"
3946 3926  
     3927 +        EE['1.3.18.0.2.6.2549']="'slpService' DESC 'DUMMY definition' SUP top MUST objectclass"
     3928 +        OD['1.3.18.0.2.6.2549']="'slpService' DESC 'parent superclass for SLP services' SUP top ABSTRACT MUST  "'( template-major-version-number $ template-minor-version-number $ description $ template-url-syntax $ service-advert-service-type $ service-advert-scopes ) MAY ( service-advert-url-authenticator $ service-advert-attribute-authenticator )'" X-ORIGIN 'RFC 2926'"
3947 3929  
3948      -#
3949      -# add_vlv_indexes(): Add VLV indexes to improve search performance.
3950      -#
3951      -add_vlv_indexes()
3952      -{
3953      -    [ $DEBUG -eq 1 ] && ${ECHO} "In add_vlv_indexes()"
     3930 +        EE['1.3.18.0.2.6.254']="'slpServicePrinter' DESC 'Service Location Protocol (SLP) information.' SUP slpService AUXILIARY"
     3931 +        OD['1.3.18.0.2.6.254']="'slpServicePrinter' DESC 'Service Location Protocol (SLP) information.' SUP slpService AUXILIARY X-ORIGIN 'RFC 3712'"
3954 3932  
3955      -    # Set eq indexes to add.
3956      -    # Note semi colon separators because some filters contain colons
3957      -    _INDEX1="${LDAP_DOMAIN}.getgrent;${LDAP_DOMAIN}_group_vlv_index;ou=group;objectClass=posixGroup"
3958      -    _INDEX2="${LDAP_DOMAIN}.gethostent;${LDAP_DOMAIN}_hosts_vlv_index;ou=hosts;objectClass=ipHost"
3959      -    _INDEX3="${LDAP_DOMAIN}.getnetent;${LDAP_DOMAIN}_networks_vlv_index;ou=networks;objectClass=ipNetwork"
3960      -    _INDEX4="${LDAP_DOMAIN}.getpwent;${LDAP_DOMAIN}_passwd_vlv_index;ou=people;objectClass=posixAccount"
3961      -    _INDEX5="${LDAP_DOMAIN}.getrpcent;${LDAP_DOMAIN}_rpc_vlv_index;ou=rpc;objectClass=oncRpc"
3962      -    _INDEX6="${LDAP_DOMAIN}.getspent;${LDAP_DOMAIN}_shadow_vlv_index;ou=people;objectClass=shadowAccount"
     3933 +        EE['1.3.18.0.2.6.258']="'printerAbstract' DESC 'Printer related information.' SUP top ABSTRACT MAY "'( printer-name $ printer-natural-language-configured $ printer-location $ printer-info $ printer-more-info $ printer-make-and-model $ printer-multiple-document-jobs-supported $ printer-charset-configured $ printer-charset-supported $ printer-generated-natural-language-supported $ printer-document-format-supported $ printer-color-supported $ printer-compression-supported $ printer-pages-per-minute $ printer-pages-per-minute-color $ printer-finishings-supported $ printer-number-up-supported $ printer-sides-supported $ printer-media-supported $ printer-media-local-supported $ printer-resolution-supported $ printer-print-quality-supported $ printer-job-priority-supported $ printer-copies-supported $ printer-job-k-octets-supported $ printer-current-operator $ printer-service-person $ printer-delivery-orientation-supported $ printer-stacking-order-supported $ printer-output-features-supported )'
     3934 +        OD['1.3.18.0.2.6.258']="'printerAbstract' DESC 'Printer related information.' SUP top ABSTRACT MAY "'( printer-name $ printer-natural-language-configured $ printer-location $ printer-info $ printer-more-info $ printer-make-and-model $ printer-multiple-document-jobs-supported $ printer-charset-configured $ printer-charset-supported $ printer-generated-natural-language-supported $ printer-document-format-supported $ printer-color-supported $ printer-compression-supported $ printer-pages-per-minute $ printer-pages-per-minute-color $ printer-finishings-supported $ printer-number-up-supported $ printer-sides-supported $ printer-media-supported $ printer-media-local-supported $ printer-resolution-supported $ printer-print-quality-supported $ printer-job-priority-supported $ printer-copies-supported $ printer-job-k-octets-supported $ printer-current-operator $ printer-service-person $ printer-delivery-orientation-supported $ printer-stacking-order-supported $ printer-output-features-supported )'" X-ORIGIN 'RFC 3712' )"
3963 3935  
3964      -    # Indexes added during NIS to LDAP transition
3965      -    _INDEX7="${LDAP_DOMAIN}.getauhoent;${LDAP_DOMAIN}_auho_vlv_index;automountmapname=auto_home;objectClass=automount"
3966      -    _INDEX8="${LDAP_DOMAIN}.getsoluent;${LDAP_DOMAIN}_solu_vlv_index;ou=people;objectClass=SolarisUserAttr"
3967      -    _INDEX10="${LDAP_DOMAIN}.getauthent;${LDAP_DOMAIN}_auth_vlv_index;ou=SolarisAuthAttr;objectClass=SolarisAuthAttr"
3968      -    _INDEX11="${LDAP_DOMAIN}.getexecent;${LDAP_DOMAIN}_exec_vlv_index;ou=SolarisProfAttr;&(objectClass=SolarisExecAttr)(SolarisKernelSecurityPolicy=*)"
3969      -    _INDEX12="${LDAP_DOMAIN}.getprofent;${LDAP_DOMAIN}_prof_vlv_index;ou=SolarisProfAttr;&(objectClass=SolarisProfAttr)(SolarisAttrLongDesc=*)"
3970      -    _INDEX13="${LDAP_DOMAIN}.getmailent;${LDAP_DOMAIN}_mail_vlv_index;ou=aliases;objectClass=mailGroup"
3971      -    _INDEX14="${LDAP_DOMAIN}.getbootent;${LDAP_DOMAIN}__boot_vlv_index;ou=ethers;&(objectClass=bootableDevice)(bootParameter=*)"
3972      -    _INDEX15="${LDAP_DOMAIN}.getethent;${LDAP_DOMAIN}_ethers_vlv_index;ou=ethers;&(objectClass=ieee802Device)(macAddress=*)"
3973      -    _INDEX16="${LDAP_DOMAIN}.getngrpent;${LDAP_DOMAIN}_netgroup_vlv_index;ou=netgroup;objectClass=nisNetgroup"
3974      -    _INDEX17="${LDAP_DOMAIN}.getipnent;${LDAP_DOMAIN}_ipn_vlv_index;ou=networks;&(objectClass=ipNetwork)(cn=*)"
3975      -    _INDEX18="${LDAP_DOMAIN}.getmaskent;${LDAP_DOMAIN}_mask_vlv_index;ou=networks;&(objectClass=ipNetwork)(ipNetmaskNumber=*)"
3976      -    _INDEX19="${LDAP_DOMAIN}.getprent;${LDAP_DOMAIN}_pr_vlv_index;ou=printers;objectClass=printerService"
3977      -    _INDEX20="${LDAP_DOMAIN}.getip4ent;${LDAP_DOMAIN}_ip4_vlv_index;ou=hosts;&(objectClass=ipHost)(ipHostNumber=*.*)"
3978      -    _INDEX21="${LDAP_DOMAIN}.getip6ent;${LDAP_DOMAIN}_ip6_vlv_index;ou=hosts;&(objectClass=ipHost)(ipHostNumber=*:*)"
     3936 +        EE['1.3.18.0.2.6.255']="'printerService' DESC 'Printer information.' SUP printerAbstract STRUCTURAL MAY "'( printer-uri $ printer-xri-supported )'
     3937 +        OD['1.3.18.0.2.6.255']="'printerService' DESC 'Printer information.' SUP printerAbstract STRUCTURAL MAY "'( printer-uri $ printer-xri-supported )'" X-ORIGIN 'RFC 3712'"
3979 3938  
3980      -    _INDEXES="$_INDEX1 $_INDEX2 $_INDEX3 $_INDEX4 $_INDEX5 $_INDEX6 $_INDEX7 $_INDEX8 $_INDEX9 $_INDEX10 $_INDEX11 $_INDEX12 $_INDEX13 $_INDEX14 $_INDEX15 $_INDEX16 $_INDEX17 $_INDEX18 $_INDEX19 $_INDEX20 $_INDEX21 "
     3939 +        EE['1.3.18.0.2.6.257']="'printerServiceAuxClass' DESC 'Printer information.' SUP printerAbstract AUXILIARY MAY "'( printer-uri $ printer-xri-supported )'
     3940 +        OD['1.3.18.0.2.6.257']="'printerServiceAuxClass' DESC 'Printer information.' SUP printerAbstract AUXILIARY MAY "'( printer-uri $ printer-xri-supported )'" X-ORIGIN 'RFC 3712'"
3981 3941  
     3942 +        EE['1.3.18.0.2.6.256']="'printerIPP' DESC 'Internet Printing Protocol (IPP) information.' SUP top AUXILIARY MAY "'( printer-ipp-versions-supported $ printer-multiple-document-jobs-supported )'
     3943 +        OD['1.3.18.0.2.6.256']="'printerIPP' DESC 'Internet Printing Protocol (IPP) information.' SUP top AUXILIARY MAY "'( printer-ipp-versions-supported $ printer-multiple-document-jobs-supported )'" X-ORIGIN 'RFC 3712'"
3982 3944  
3983      -    # Set _EXT to use as shortcut.
3984      -    _EXT="cn=${IDS_DATABASE},cn=ldbm database,cn=plugins,cn=config"
     3945 +        EE['1.3.18.0.2.6.253']="'printerLPR' DESC 'LPR information.' SUP top AUXILIARY MUST printer-name MAY printer-aliases"
     3946 +        OD['1.3.18.0.2.6.253']="'printerLPR' DESC 'LPR information.' SUP top AUXILIARY MUST ( printer-name ) MAY ( printer-aliases ) X-ORIGIN 'RFC 3712'"
3985 3947  
     3948 +        EE['1.3.6.1.4.1.42.2.27.5.2.14']="'sunPrinter' DESC 'Sun printer information' SUP top AUXILIARY MUST printer-name MAY "'( sun-printer-bsdaddr $ sun-printer-kvp )'
     3949 +        OD['1.3.6.1.4.1.42.2.27.5.2.14']="'sunPrinter' DESC 'Sun printer information' SUP top AUXILIARY MUST printer-name MAY "'(sun-printer-bsdaddr $ sun-printer-kvp)'" X-ORIGIN 'Solaris Specific'"
3986 3950  
3987      -    # Display message to id current step.
3988      -    ${ECHO} "  ${STEP}. Processing VLV indexes:"
3989      -    STEP=`expr $STEP + 1`
     3951 +        EE['1.3.6.1.4.1.42.2.27.5.2.12']="'nisplusTimeZoneData' DESC 'NIS+ timezone table data' SUP top STRUCTURAL MUST cn MAY "'( nisplusTimeZone $ description )'
     3952 +        OD['1.3.6.1.4.1.42.2.27.5.2.12']="'nisplusTimeZoneData' DESC 'NIS+ timezone table data' SUP top STRUCTURAL MUST cn MAY "'( nisplusTimeZone $ description )'" X-ORIGIN 'Solaris Specific'"
3990 3953  
3991      -    # Reset temp file for vlvindex commands.
3992      -    [ -f ${TMPDIR}/ds5_vlvindex_list ] &&  rm ${TMPDIR}/ds5_vlvindex_list
3993      -    touch ${TMPDIR}/ds5_vlvindex_list
3994      -    [ -f ${TMPDIR}/ds6_vlvindex_list ] &&  rm ${TMPDIR}/ds6_vlvindex_list
3995      -    touch ${TMPDIR}/ds6_vlvindex_list
     3954 +        EE['1.3.6.1.4.1.42.2.27.5.2.8']="'ipTnetTemplate' DESC 'Object class for TSOL network templates' SUP top MUST ipTnetTemplateName MAY SolarisAttrKeyValue"
     3955 +        OD['1.3.6.1.4.1.42.2.27.5.2.8']="'ipTnetTemplate' DESC 'Object class for TSOL network templates' SUP top STRUCTURAL MUST ipTnetTemplateName MAY SolarisAttrKeyValue X-ORIGIN 'Solaris Specific'"
3996 3956  
3997      -    # Get the instance name from iDS server.
3998      -    _INSTANCE="<server-instance>"    # Default to old output.
     3957 +        EE['1.3.6.1.4.1.42.2.27.5.2.9']="'ipTnetHost' DESC 'Associates an IP address or wildcard with a TSOL template_name' SUP top AUXILIARY MUST ipTnetNumber"
     3958 +        OD['1.3.6.1.4.1.42.2.27.5.2.9']="'ipTnetHost' DESC 'Associates an IP address or wildcard with a TSOL template_name' SUP top AUXILIARY MUST ipTnetNumber X-ORIGIN 'Solaris Specific'"
3999 3959  
4000      -    eval "${LDAPSEARCH} -v ${LDAP_ARGS} -b \"cn=config\" -s base \"objectclass=*\" nsslapd-instancedir | ${GREP} 'nsslapd-instancedir=' | cut -d'=' -f2- > ${TMPDIR}/instance_name 2>&1"
     3960 +        # obey CLI syntax force option (if any)
     3961 +        if (( TMPF[SYNTAX] == 1 )); then
     3962 +                typeset -n MAP=OD
     3963 +        elif (( TMPF[SYNTAX] == 2 )); then
     3964 +                typeset -n MAP=EE
     3965 +        elif (( TMPF[IS_OPENDJ] )); then
     3966 +                typeset -n MAP=OD
     3967 +        else
     3968 +                typeset -n MAP=EE
     3969 +        fi
4001 3970  
4002      -    ${GREP} "slapd-" ${TMPDIR}/instance_name > /dev/null 2>&1 # Check if seems right?
4003      -    if [ $? -eq 0 ]; then # If success, grab name after "slapd-".
4004      -        _INST_DIR=`cat ${TMPDIR}/instance_name`
4005      -        _INSTANCE=`basename "${_INST_DIR}" | cut -d'-' -f2-`
4006      -    fi
     3971 +        # we need to preserve order, so 2 passes
     3972 +        typeset TODO='' OID
     3973 +        for OID in ${!MAP[@]}; do
     3974 +                [[ -n ${OID2ODEF[${OID}]} ]] && continue
     3975 +                TODO+="${OID} "
     3976 +        done
4007 3977  
4008      -    # For loop to create indexes.
4009      -    for p in ${_INDEXES}; do
4010      -        [ $DEBUG -eq 1 ] && ${ECHO} "  Adding index for ${i}"
     3978 +        if [[ -z ${TODO} ]]; then
     3979 +                X='Schema contains all required objectclass defintions'
     3980 +        else
     3981 +                # 2nd pass
     3982 +                typeset X SORTED
     3983 +                SORTED=${ print ${TODO// /$'\n'} | sort -n -t. ; }
     3984 +                TODO='' TODO2=''
     3985 +                for OID in ${SORTED} ; do
     3986 +                        X="${MAP[${OID}]}"
     3987 +                        OID2ODEF["${OID}"]="${X}"
     3988 +                        # 1.3.18.0.2.6.254 requires 1.3.18.0.2.6.2549
     3989 +                        # 1.3.18.0.2.6.255,1.3.18.0.2.6.257 require 1.3.18.0.2.6.258
     3990 +                        [[ ${OID} == '1.3.18.0.2.6.254' \
     3991 +                                || ${OID} == '1.3.18.0.2.6.255' \
     3992 +                                || ${OID} == '1.3.18.0.2.6.257' ]] \
     3993 +                                && TODO2+='objectclasses: ( '"${OID} NAME ${X}"' )\n' \
     3994 +                                || TODO+='objectclasses: ( '"${OID} NAME ${X}"' )\n'
     3995 +                done
4011 3996  
4012      -        # Break p (pair) into i and j parts.
4013      -        i=`${ECHO} $p | cut -d';' -f1`
4014      -        j=`${ECHO} $p | cut -d';' -f2`
4015      -        k=`${ECHO} $p | cut -d';' -f3`
4016      -        m=`${ECHO} $p | cut -d';' -f4`
4017      -
4018      -        # Set _jEXT to use as shortcut.
4019      -        _jEXT="cn=${j},${_EXT}"
4020      -
4021      -        # Check if entry exists first, if so, skip to next.
4022      -        ${LDAPSEARCH} ${SERVER_ARGS} -b "cn=${i},${_jEXT}" -s base "objectclass=*" > /dev/null 2>&1
4023      -        if [ $? -eq 0 ]; then
4024      -            # Display index skipped.
4025      -            ${ECHO} "      ${i} vlv_index skipped already exists"       
4026      -            continue
     3997 +                nextFile modify $0
     3998 +                print 'dn: cn=schema\nchangetype: modify\nadd: objectclasses' \
     3999 +                        "\n${TODO}${TODO2}" >${TMP[FILE]}
     4000 +                if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     4001 +                        >&${TMPF[FD]} 2>&1
     4002 +                then
     4003 +                        Log.fatal 'Adding objectclass definitions to schema failed'
     4004 +                        return 67
     4005 +                fi
     4006 +                X='Schema objectclass definitions added'
4027 4007          fi
4028 4008  
4029      -        # Compute the VLV Scope from the LDAP_SEARCH_SCOPE. 
4030      -        # NOTE: A value of "base (0)" does not make sense.
4031      -        case "$LDAP_SEARCH_SCOPE" in
4032      -            sub) VLV_SCOPE="2" ;;
4033      -            *)   VLV_SCOPE="1" ;; 
4034      -        esac
     4009 +        showProgress "${X}."
     4010 +        return 0
     4011 +}
4035 4012  
4036      -        # Here doc to create LDIF.
4037      -        ( cat <<EOF
4038      -dn: ${_jEXT}
4039      -objectClass: top
4040      -objectClass: vlvSearch
4041      -cn: ${j}
4042      -vlvbase: ${k},${LDAP_BASEDN}
4043      -vlvscope: ${VLV_SCOPE}
4044      -vlvfilter: (${m})
4045      -aci: (target="ldap:///${_jEXT}")(targetattr="*")(version 3.0; acl "Config";allow(read,search,compare)userdn="ldap:///anyone";)
     4013 +Man.addFunc add_suffix '' '[+NAME?add_suffix - add suffix to DS if needed.]
     4014 +[+DESCRIPTION?Add a suffix to the DS if needed (\bTMPF[NEED_CREATE_SUFFIX]]\b is set) and optionally create the backend for it (\bTMPF[NEED_CREATE_BACKEND]]\b is set). Suffix entry and backend MUST be prepared by \bprep_create_sfx_entry()\b and \bprep_create_sfx_backend()\b correspondingly to have the following vars set:]{
     4015 +        [+STR[LDAP_SUFFIX]] ]
     4016 +        [+STR[DS_DB]] ]
     4017 +        [+TMP[SUFFIX_OBJ]] ]
     4018 +        [+TMP[SUFFIX_ATT]] ]
     4019 +        [+TMP[SUFFIX_VAL]] ]
     4020 +}
     4021 +[+RETURN VALUES]{
     4022 +        [+0?on success (suffix not needed or created successfully).]
     4023 +        [+1?otherwise (unable to create suffix).]
     4024 +}
     4025 +[+SEE ALSO?\bldapadd\b(1), \bdisplay_msg()\b.]
     4026 +'
     4027 +function add_suffix {
     4028 +        if (( ! TMPF[NEED_CREATE_BACKEND] )); then
     4029 +                showProgress "Database backend exists."
     4030 +        else
     4031 +                nextFile add "${0}-backend"
     4032 +                if (( TMPF[IS_OPENDJ] )); then
     4033 +                        print '
     4034 +dn: ds-cfg-backend-id='"${STR[DS_DB]}"',cn=Backends,cn=config
     4035 +ds-cfg-backend-id: '"${STR[DS_DB]}"'
     4036 +ds-cfg-base-dn: '"${STR[LDAP_SUFFIX]}"'
     4037 +objectclass: top
     4038 +objectclass: ds-cfg-backend
     4039 +objectclass: ds-cfg-local-db-backend
     4040 +ds-cfg-java-class: org.opends.server.backends.jeb.BackendImpl
     4041 +ds-cfg-enabled: true
     4042 +ds-cfg-writability-mode: enabled
     4043 +ds-cfg-preload-time-limit: 0 ms
     4044 +ds-cfg-compact-encoding: true
     4045 +ds-cfg-entries-compressed: false
     4046 +ds-cfg-index-entry-limit: 4000
     4047 +ds-cfg-db-directory: db
     4048 +ds-cfg-db-directory-permissions: 700
     4049 +ds-cfg-disk-low-threshold: 100 mb
     4050 +ds-cfg-disk-full-threshold: 20 mb
     4051 +ds-cfg-db-run-cleaner: true
     4052 +ds-cfg-db-cleaner-min-utilization: 50
     4053 +ds-cfg-db-logging-file-handler-on: true
     4054 +ds-cfg-db-logging-level: CONFIG
     4055 +ds-cfg-db-log-filecache-size: 100
     4056 +ds-cfg-db-log-file-max: 10 mb
     4057 +ds-cfg-db-cache-size: 0 b
     4058 +ds-cfg-db-cache-percent: 50
     4059 +ds-cfg-db-evictor-core-threads: 1
     4060 +ds-cfg-db-evictor-max-threads: 10
     4061 +ds-cfg-db-evictor-nodes-per-scan: 10
     4062 +ds-cfg-db-evictor-lru-only: true
     4063 +ds-cfg-db-evictor-keep-alive: 600 s
     4064 +ds-cfg-db-txn-no-sync: false
     4065 +ds-cfg-db-txn-write-no-sync: true
     4066 +ds-cfg-db-checkpointer-wakeup-interval: 30 s
     4067 +ds-cfg-db-checkpointer-bytes-interval: 20 mb
     4068 +'                       >${TMP[FILE]}
     4069 +        else
     4070 +                        print '
     4071 +dn: cn="'"${STR[LDAP_SUFFIX]}"'",cn=mapping tree,cn=config
     4072 +objectclass: top
     4073 +objectclass: extensibleObject
     4074 +objectclass: nsMappingTree
     4075 +cn: '"${STR[LDAP_SUFFIX]}"'
     4076 +nsslapd-state: backend
     4077 +nsslapd-backend: '"${STR[DS_DB]}"'
4046 4078  
4047      -dn: cn=${i},${_jEXT}
4048      -cn: ${i}
4049      -vlvSort: cn uid
     4079 +dn: cn='"${STR[DS_DB]}"',cn=ldbm database,cn=plugins,cn=config
4050 4080  objectclass: top
4051      -objectclass: vlvIndex
4052      -EOF
4053      -) > ${TMPDIR}/vlv_index_${i}
     4081 +objectclass: extensibleObject
     4082 +objectclass: nsBackendInstance
     4083 +cn: '"${STR[DS_DB]}"'
     4084 +nsslapd-suffix: '"${STR[LDAP_SUFFIX]}"'
     4085 +'                               >${TMP[FILE]}
     4086 +                fi
4054 4087  
4055      -        # Add the index.
4056      -        ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/vlv_index_${i} ${VERB}"
4057      -        if [ $? -ne 0 ]; then
4058      -            ${ECHO} "  ERROR: Adding VLV index for ${i} failed!"
4059      -            cleanup
4060      -            exit 1
     4088 +                if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     4089 +                        >&${TMPF[FD]} 2>&1
     4090 +                then
     4091 +                        Log.fatal 'Unable to create backend' "'${STR[DS_DB]}'" \
     4092 +                                'with suffix' "'${STR[LDAP_SUFFIX]}'" 'due to server error.'
     4093 +                        return 1
     4094 +                fi
     4095 +                showProgress "Database backend created."
4061 4096          fi
4062 4097  
4063      -        # Print message that index was created.
4064      -        ${ECHO} "      ${i} vlv_index   Entry created"
4065      -
4066      -        # Add command to list of vlvindex commands to run.
4067      -        ${ECHO} "  directoryserver -s ${_INSTANCE} vlvindex -n ${IDS_DATABASE} -T ${i}" >> ${TMPDIR}/ds5_vlvindex_list
4068      -        ${ECHO} "  <install-path>/bin/dsadm reindex -l -t ${i} <directory-instance-path> ${LDAP_SUFFIX}" >> ${TMPDIR}/ds6_vlvindex_list
4069      -    done
     4098 +        if (( ! TMPF[NEED_CREATE_SUFFIX] )); then
     4099 +                showProgress "Suffix exists."
     4100 +        else
     4101 +                nextFile add $0
     4102 +                print '
     4103 +dn: '"${STR[LDAP_SUFFIX]}"'
     4104 +objectclass: top
     4105 +objectclass: '"${TMP[SUFFIX_OBJ]}"'
     4106 +'"${TMP[SUFFIX_ATT]}: ${TMP[SUFFIX_VAL]}"'
     4107 +'               >${TMP[FILE]}
     4108 +                if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     4109 +                        >&${TMPF[FD]} 2>&1
     4110 +                then
     4111 +                        Log.warn 'Unable to create entry' "'${STR[LDAP_SUFFIX]}'" 'of' \
     4112 +                                "'${TMP[SUFFIX_OBJ]}'" 'class'
     4113 +                        return 1
     4114 +                fi
     4115 +                showProgress "Suffix added."
     4116 +        fi
     4117 +        return 0
4070 4118  }
4071 4119  
     4120 +function add_suffix_aci {
     4121 +        typeset PW_STATE PW_STATE_RO ANY_NO_READ SELF_NO_WRITE
     4122 +        typeset ADMIN_DN ADMIN_GROUP_DN
     4123 +        if (( TMPF[IS_OPENDJ] )); then
     4124 +                # TBD: include Password Policy State extended ops ?
4072 4125  
4073      -#
4074      -# display_vlv_cmds(): Display VLV index commands to run on server.
4075      -#
4076      -display_vlv_cmds()
4077      -{
4078      -    if [ -s "${TMPDIR}/ds5_vlvindex_list" -o \
4079      -         -s "${TMPDIR}/ds6_vlvindex_list" ]; then
4080      -        display_msg display_vlv_list
4081      -    fi
     4126 +                # password state information aka ds-pwp-*, pwd* and ds-pta-* WITHOUT
     4127 +                # attrs, which are schema flagged with NO-USER-MODIFICATION
     4128 +                PW_STATE=' ds-pwp-account-disabled || ds-pwp-account-expiration-time
     4129 + || ds-pwp-last-login-time || ds-pwp-password-changed-by-required-time
     4130 + || ds-pwp-password-policy-dn || ds-pwp-reset-time || ds-pwp-warned-time
     4131 + || ds-privilege-name || pwdReset'
     4132 +                # password state information flagged with NO-USER-MODIFICATION
     4133 +                # ds-pwp-password-expiration-time is the same as pwdExpirationTime
     4134 +                # so save some parse time ;-)
     4135 +                PW_STATE_RO=' pwdExpirationTime || pwdChangedTime || pwdGraceUseTime
     4136 + || pwdFailureTime || pwdHistory || pwdAccountLockedTime'
     4137 +                # People using PassThroughAuthentication probably wish that too:
     4138 +                #PW_STATE_RO+='|| ds-pta-cached-password || ds-pta-cached-password-time'
4082 4139  
4083      -    if [ -s "${TMPDIR}/ds5_vlvindex_list" ]; then
4084      -        cat ${TMPDIR}/ds5_vlvindex_list
4085      -    fi
     4140 +                # passwords + password state
     4141 +                ANY_NO_READ="userPassword || authPassword ||${PW_STATE}||${PW_STATE_RO}"
     4142 +                # aci + search limits aka ds-rlim-*  + RW password state/policy
     4143 +                SELF_NO_WRITE='aci || ds-rlim-idle-time-limit
     4144 + || ds-rlim-lookthrough-limit || ds-rlim-size-limit || ds-rlim-time-limit
     4145 + || pwdPolicySubentry ||'"${PW_STATE}"
     4146 +                ADMIN_DN='uid=admin,cn=Administrators'
     4147 +                ADMIN_GROUP_DN='cn=Administrators'
     4148 +                ADMIN_DN+=',cn=admin data'
     4149 +                ADMIN_GROUP_DN+=',cn=admin data'
     4150 +        else
     4151 +                # DSEE
     4152 +                # password state information aka passwordObject
     4153 +                PW_STATE=' accountUnlockTime || passwordAllowChangeTime
     4154 + || passwordExpWarned || passwordExpirationTime || passwordHistory
     4155 + || passwordRetryCount || retryCountResetTime'
4086 4156  
4087      -    cat << EOF
     4157 +                # passwords + password state
     4158 +                ANY_NO_READ="userPassword ||${PW_STATE}"
     4159 +                # aci + search limits + password state/policy
     4160 +                SELF_NO_WRITE='aci || nsIdleTimeout || nsLookThroughLimit
     4161 + || nsSizeLimit || nsTimeLimit || nsroledn || passwordPolicySubentry
     4162 + ||'"${PW_STATE}"
     4163 +                ADMIN_DN='uid=admin,ou=Administrators'
     4164 +                ADMIN_GROUP_DN='cn=Configuration Administrators,ou=Groups'
     4165 +                ADMIN_DN+=',ou=TopologyManagement,o=NetscapeRoot'
     4166 +                ADMIN_GROUP_DN+=',ou=TopologyManagement,o=NetscapeRoot"'
     4167 +        fi
4088 4168  
     4169 +        typeset -A RULES=(
     4170 +                [SFX_ANYONE_ACI_NAME]='aci: (targetattr != "'"${ANY_NO_READ//$'\n'}"'")
     4171 + (
     4172 +        version 3.0;  acl "'"${SFX_ANYONE_ACI_NAME}"'";
     4173 +        allow (read, search, compare) userdn = "ldap:///anyone";
     4174 + )'
     4175 +                [SFX_SELF_ACI_NAME]='aci: (targetattr != "'"${SELF_NO_WRITE//$'\n'}"'")
     4176 + (
     4177 +        version 3.0;  acl "'"${SFX_SELF_ACI_NAME}"'";
     4178 +        allow (write) userdn = "ldap:///self";
     4179 + )'
     4180 +                [SFX_ADMIN_ACI_NAME]='aci: (targetattr = "*")
     4181 + (
     4182 +        version 3.0;  acl "'"${SFX_ADMIN_ACI_NAME}"'";
     4183 +        allow (all) userdn = "ldap:///'"${ADMIN_DN}"'";
     4184 + )'
     4185 +                [SFX_ADMINGRP_ACI_NAME]='aci: (targetattr ="*")
     4186 + (
     4187 +        version 3.0;  acl "'"${SFX_ADMINGRP_ACI_NAME}"'";
     4188 +        allow (all) groupdn = "ldap:///'"${ADMIN_GROUP_DN}"'";
     4189 + )'
     4190 +        )
4089 4191  
4090      -EOF
     4192 +        # Check and set if doesn't already exist
     4193 +        typeset -a LIST=( )
     4194 +        getACIs LIST "${STR[LDAP_SUFFIX]}"
4091 4195  
4092      -    if [ -s "${TMPDIR}/ds6_vlvindex_list" ]; then
4093      -        cat ${TMPDIR}/ds6_vlvindex_list
4094      -    fi
     4196 +        for ACI in "${!RULES[@]}" ; do
     4197 +                typeset -n NAME=${ACI}
     4198 +                [[ -z ${NAME} ]] && continue    # if it has no name, ignore it
     4199 +                PATTERN='acl[ ]+"?'"${NAME}"'"?'
     4200 +                findACI LIST "${NAME}" "${PATTERN}" 'Suffix' || continue        # exists
     4201 +                nextFile add "${0}-${NAME}"
     4202 +                print '
     4203 +dn: '"${STR[LDAP_SUFFIX]}"'
     4204 +changetype: modify
     4205 +add: aci
     4206 +'"${RULES[${ACI}]}"'
     4207 +'                       >${TMP[FILE]}
     4208 +                if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     4209 +                        >&${TMPF[FD]} 2>&1
     4210 +                then
     4211 +                        Log.warn "Adding '${NAME}' suffix ACI failed"
     4212 +                        return 1
     4213 +                fi
     4214 +                showProgress "Suffix ACI '${NAME}' added."
     4215 +        done
     4216 +        return 0
4095 4217  }
4096 4218  
4097      -#
4098      -# keep_backward_compatibility(): Modify schema for the backward compatibility if
4099      -# there are the incompatible attributes already
4100      -#
4101      -keep_backward_compatibility()
4102      -{
4103      -    ${EVAL} "${LDAPSEARCH} ${SERVER_ARGS} -b cn=schema -s base \
4104      -        \"objectclass=*\" attributeTypes | ${GREP} -i memberGid-oid ${VERB}"
4105      -    if [ $? -eq 0 ]; then
4106      -        ${SED} -e 's/1\.3\.6\.1\.4\.1\.42\.2\.27\.5\.1\.30\ /memberGid-oid\ /' \
4107      -            ${TMPDIR}/schema_attr > ${TMPDIR}/schema_attr.new
4108      -        ${MV} ${TMPDIR}/schema_attr.new ${TMPDIR}/schema_attr
4109      -    fi
4110      -
4111      -    ${EVAL} "${LDAPSEARCH} ${SERVER_ARGS} -b cn=schema -s base \
4112      -        \"objectclass=*\" attributeTypes | ${GREP} -i rfc822mailMember-oid \
4113      -        ${VERB}"
4114      -    if [ $? -eq 0 ]; then
4115      -        ${SED} -e \
4116      -            's/1\.3\.6\.1\.4\.1\.42\.2\.27\.2\.1\.15\ /rfc822mailMember-oid\ /' \
4117      -            ${TMPDIR}/schema_attr > ${TMPDIR}/schema_attr.new
4118      -        ${MV} ${TMPDIR}/schema_attr.new ${TMPDIR}/schema_attr
4119      -    fi
     4219 +Man.addFunc add_base_objects '' '[+NAME?add_base_objects - add possibly missing, necessary base objects.]
     4220 +[+DESCRIPTION?Determine all RDNs required to form the \bSTR[LDAP_BASEDN]]\b using the suffix \bSTR[LDAP_SUFFIX]]\b (RDN1,RDN2,...,suffix == baseDN) and create the missing entries.]
     4221 +[+RETURN VALUES]{
     4222 +        [+0?on success (all entries available or created successfully).]
     4223 +        [+>= 66?a fatal error occured.]
4120 4224  }
     4225 +[+SEE ALSO?\bnormalizeDN()\b, \bldapsearch\b(1), \bldapmodify\b(1).]
     4226 +'
     4227 +function add_base_objects {
     4228 +        # typeset -A STR
     4229 +        # STR[LDAP_BASEDN]=dc=x,dc=my,dc=do,dc=main,dc=de
     4230 +        # STR[LDAP_SUFFIX]=dc=do,dc=main,dc=de
4121 4231  
4122      -#
4123      -# update_schema_attr(): Update Schema to support Naming.
4124      -#
4125      -update_schema_attr()
4126      -{
4127      -    [ $DEBUG -eq 1 ] && ${ECHO} "In update_schema_attr()"
     4232 +        # Convert to lower case for basename.
     4233 +        typeset LC_DN=','${ normalizeDN "${STR[LDAP_BASEDN]}" l ; }
     4234 +        typeset LC_SFX=','${ normalizeDN "${STR[LDAP_SUFFIX]}" l ; }
4128 4235  
4129      -    ( cat <<EOF
4130      -dn: cn=schema
4131      -changetype: modify
4132      -add: attributetypes
4133      -attributetypes: ( 1.3.6.1.1.1.1.28 NAME 'nisPublickey' DESC 'NIS public key' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4134      -attributetypes: ( 1.3.6.1.1.1.1.29 NAME 'nisSecretkey' DESC 'NIS secret key' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4135      -attributetypes: ( 1.3.6.1.1.1.1.30 NAME 'nisDomain' DESC 'NIS domain' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4136      -attributetypes: ( 1.3.6.1.1.1.1.31 NAME 'automountMapName' DESC 'automount Map Name' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4137      -attributetypes: ( 1.3.6.1.1.1.1.32 NAME 'automountKey' DESC 'automount Key Value' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4138      -attributetypes: ( 1.3.6.1.1.1.1.33 NAME 'automountInformation' DESC 'automount information' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4139      -attributetypes: ( 1.3.6.1.4.1.42.2.27.1.1.12 NAME 'nisNetIdUser' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
4140      -attributetypes: ( 1.3.6.1.4.1.42.2.27.1.1.13 NAME 'nisNetIdGroup' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
4141      -attributetypes: ( 1.3.6.1.4.1.42.2.27.1.1.14 NAME 'nisNetIdHost' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
4142      -attributetypes: ( 1.3.6.1.4.1.42.2.27.2.1.15 NAME 'rfc822mailMember' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
4143      -attributetypes: ( 2.16.840.1.113730.3.1.30 NAME 'mgrpRFC822MailMember' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4144      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.15 NAME 'SolarisLDAPServers' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4145      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.16 NAME 'SolarisSearchBaseDN' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE )
4146      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.17 NAME 'SolarisCacheTTL' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4147      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.18 NAME 'SolarisBindDN' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE )
4148      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.19 NAME 'SolarisBindPassword' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4149      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.20 NAME 'SolarisAuthMethod' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4150      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.21 NAME 'SolarisTransportSecurity' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4151      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.22 NAME 'SolarisCertificatePath' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4152      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.23 NAME 'SolarisCertificatePassword' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4153      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.24 NAME 'SolarisDataSearchDN' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4154      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.25 NAME 'SolarisSearchScope' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4155      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.26 NAME 'SolarisSearchTimeLimit' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
4156      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.27 NAME 'SolarisPreferredServer' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4157      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.28 NAME 'SolarisPreferredServerOnly' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4158      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.29 NAME 'SolarisSearchReferral' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4159      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.4 NAME 'SolarisAttrKeyValue' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4160      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.5 NAME 'SolarisAuditAlways' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4161      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.6 NAME 'SolarisAuditNever' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4162      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.7 NAME 'SolarisAttrShortDesc' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4163      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.8 NAME 'SolarisAttrLongDesc' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4164      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.9 NAME 'SolarisKernelSecurityPolicy' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4165      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.10 NAME 'SolarisProfileType' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4166      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.11 NAME 'SolarisProfileId' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4167      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.12 NAME 'SolarisUserQualifier' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4168      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.13 NAME 'SolarisAttrReserved1' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4169      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.14 NAME 'SolarisAttrReserved2' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4170      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.1 NAME 'SolarisProjectID' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
4171      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.2 NAME 'SolarisProjectName' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4172      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.3 NAME 'SolarisProjectAttr' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
4173      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.30 NAME 'memberGid' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
4174      -attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.0 NAME 'defaultServerList' DESC 'Default LDAP server host address used by a DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4175      -attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.1 NAME 'defaultSearchBase' DESC 'Default LDAP base DN used by a DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE )
4176      -attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.2 NAME 'preferredServerList' DESC 'Preferred LDAP server host addresses to be used by a DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4177      -attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.3 NAME 'searchTimeLimit' DESC 'Maximum time in seconds a DUA should allow for a search to complete' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
4178      -attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.4 NAME 'bindTimeLimit' DESC 'Maximum time in seconds a DUA should allow for the bind operation to complete' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
4179      -attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.5 NAME 'followReferrals' DESC 'Tells DUA if it should follow referrals returned by a DSA search result' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4180      -attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.6 NAME 'authenticationMethod' DESC 'A keystring which identifies the type of authentication method used to contact the DSA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4181      -attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.7 NAME 'profileTTL' DESC 'Time to live before a client DUA should re-read this configuration profile' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
4182      -attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.14 NAME 'serviceSearchDescriptor' DESC 'LDAP search descriptor list used by Naming-DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
4183      -attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.9 NAME 'attributeMap' DESC 'Attribute mappings used by a Naming-DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4184      -attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.10 NAME 'credentialLevel' DESC 'Identifies type of credentials a DUA should use when binding to the LDAP server' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4185      -attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.11 NAME 'objectclassMap' DESC 'Objectclass mappings used by a Naming-DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4186      -attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.12 NAME 'defaultSearchScope' DESC 'Default search scope used by a DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4187      -attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.13 NAME 'serviceCredentialLevel' DESC 'Search scope used by a service of the DUA' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
4188      -attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.15 NAME 'serviceAuthenticationMethod' DESC 'Authentication Method used by a service of the DUA' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4189      -attributetypes: ( 1.3.18.0.2.4.1140 NAME 'printer-uri' DESC 'A URI supported by this printer.  This URI SHOULD be used as a relative distinguished name (RDN).  If printer-xri-supported is implemented, then this URI value MUST be listed in a member value of printer-xri-supported.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4190      -attributetypes: ( 1.3.18.0.2.4.1107 NAME 'printer-xri-supported' DESC 'The unordered list of XRI (extended resource identifiers) supported by this printer.  Each member of the list consists of a URI (uniform resource identifier) followed by optional authentication and security metaparameters.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4191      -attributetypes: ( 1.3.18.0.2.4.1135 NAME 'printer-name' DESC 'The site-specific administrative name of this printer, more end-user friendly than a URI.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}  SINGLE-VALUE )
4192      -attributetypes: ( 1.3.18.0.2.4.1119 NAME 'printer-natural-language-configured' DESC 'The configured language in which error and status messages will be generated (by default) by this printer.  Also, a possible language for printer string attributes set by operator, system administrator, or manufacturer.  Also, the (declared) language of the "printer-name", "printer-location", "printer-info", and "printer-make-and-model" attributes of this printer. For example: "en-us" (US English) or "fr-fr" (French in France) Legal values of language tags conform to [RFC3066] "Tags for the Identification of Languages".' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}  SINGLE-VALUE )
4193      -attributetypes: ( 1.3.18.0.2.4.1136 NAME 'printer-location' DESC 'Identifies the location of the printer. This could include things like: "in Room 123A", "second floor of building XYZ".' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE )
4194      -attributetypes: ( 1.3.18.0.2.4.1139 NAME 'printer-info' DESC 'Identifies the descriptive information about this printer.  This could include things like: "This printer can be used for printing color transparencies for HR presentations", or "Out of courtesy for others, please print only small (1-5 page) jobs at this printer", or even "This printer is going away on July 1, 1997, please find a new printer".' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE )
4195      -attributetypes: ( 1.3.18.0.2.4.1134 NAME 'printer-more-info' DESC 'A URI used to obtain more information about this specific printer.  For example, this could be an HTTP type URI referencing an HTML page accessible to a Web Browser.  The information obtained from this URI is intended for end user consumption.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4196      -attributetypes: ( 1.3.18.0.2.4.1138 NAME 'printer-make-and-model' DESC 'Identifies the make and model of the device.  The device manufacturer MAY initially populate this attribute.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}  SINGLE-VALUE )
4197      -attributetypes: ( 1.3.18.0.2.4.1133 NAME 'printer-ipp-versions-supported' DESC 'Identifies the IPP protocol version(s) that this printer supports, including major and minor versions, i.e., the version numbers for which this Printer implementation meets the conformance requirements.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} )
4198      -attributetypes: ( 1.3.18.0.2.4.1132 NAME 'printer-multiple-document-jobs-supported' DESC 'Indicates whether or not the printer supports more than one document per job, i.e., more than one Send-Document or Send-Data operation with document data.' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
4199      -attributetypes: ( 1.3.18.0.2.4.1109 NAME 'printer-charset-configured' DESC 'The configured charset in which error and status messages will be generated (by default) by this printer.  Also, a possible charset for printer string attributes set by operator, system administrator, or manufacturer.  For example: "utf-8" (ISO 10646/Unicode) or "iso-8859-1" (Latin1).  Legal values are defined by the IANA Registry of Coded Character Sets and the "(preferred MIME name)" SHALL be used as the tag.  For coherence with IPP Model, charset tags in this attribute SHALL be lowercase normalized.  This attribute SHOULD be static (time of registration) and SHOULD NOT be dynamically refreshed attributetypes: (subsequently).' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{63} SINGLE-VALUE )
4200      -attributetypes: ( 1.3.18.0.2.4.1131 NAME 'printer-charset-supported' DESC 'Identifies the set of charsets supported for attribute type values of type Directory String for this directory entry.  For example: "utf-8" (ISO 10646/Unicode) or "iso-8859-1" (Latin1).  Legal values are defined by the IANA Registry of Coded Character Sets and the preferred MIME name.' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{63} )
4201      -attributetypes: ( 1.3.18.0.2.4.1137 NAME 'printer-generated-natural-language-supported' DESC 'Identifies the natural language(s) supported for this directory entry.  For example: "en-us" (US English) or "fr-fr" (French in France).  Legal values conform to [RFC3066], Tags for the Identification of Languages.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{63} )
4202      -attributetypes: ( 1.3.18.0.2.4.1130 NAME 'printer-document-format-supported' DESC 'The possible document formats in which data may be interpreted and printed by this printer.  Legal values are MIME types come from the IANA Registry of Internet Media Types.' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} )
4203      -attributetypes: ( 1.3.18.0.2.4.1129 NAME 'printer-color-supported' DESC 'Indicates whether this printer is capable of any type of color printing at all, including highlight color.' EQUALITY booleanMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
4204      -attributetypes: ( 1.3.18.0.2.4.1128 NAME 'printer-compression-supported' DESC 'Compression algorithms supported by this printer.  For example: "deflate, gzip".  Legal values include; "none", "deflate" attributetypes: (public domain ZIP), "gzip" (GNU ZIP), "compress" (UNIX).' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{255} )
4205      -attributetypes: ( 1.3.18.0.2.4.1127 NAME 'printer-pages-per-minute' DESC 'The nominal number of pages per minute which may be output by this printer (e.g., a simplex or black-and-white printer).  This attribute is informative, NOT a service guarantee.  Typically, it is the value used in marketing literature to describe this printer.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
4206      -attributetypes: ( 1.3.18.0.2.4.1126 NAME 'printer-pages-per-minute-color' DESC 'The nominal number of color pages per minute which may be output by this printer (e.g., a simplex or color printer).  This attribute is informative, NOT a service guarantee.  Typically, it is the value used in marketing literature to describe this printer.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
4207      -attributetypes: ( 1.3.18.0.2.4.1125 NAME 'printer-finishings-supported' DESC 'The possible finishing operations supported by this printer. Legal values include; "none", "staple", "punch", "cover", "bind", "saddle-stitch", "edge-stitch", "staple-top-left", "staple-bottom-left", "staple-top-right", "staple-bottom-right", "edge-stitch-left", "edge-stitch-top", "edge-stitch-right", "edge-stitch-bottom", "staple-dual-left", "staple-dual-top", "staple-dual-right", "staple-dual-bottom".' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{255} )
4208      -attributetypes: ( 1.3.18.0.2.4.1124 NAME 'printer-number-up-supported' DESC 'The possible numbers of print-stream pages to impose upon a single side of an instance of a selected medium. Legal values include; 1, 2, and 4.  Implementations may support other values.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.27 )
4209      -attributetypes: ( 1.3.18.0.2.4.1123 NAME 'printer-sides-supported' DESC 'The number of impression sides (one or two) and the two-sided impression rotations supported by this printer.  Legal values include; "one-sided", "two-sided-long-edge", "two-sided-short-edge".' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} )
4210      -attributetypes: ( 1.3.18.0.2.4.1122 NAME 'printer-media-supported' DESC 'The standard names/types/sizes (and optional color suffixes) of the media supported by this printer.  For example: "iso-a4",  "envelope", or "na-letter-white".  Legal values  conform to ISO 10175, Document Printing Application (DPA), and any IANA registered extensions.' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{255} )
4211      -attributetypes: ( 1.3.18.0.2.4.1117 NAME 'printer-media-local-supported' DESC 'Site-specific names of media supported by this printer, in the language in "printer-natural-language-configured".  For example: "purchasing-form" (site-specific name) as opposed to (in "printer-media-supported"): "na-letter" (standard keyword from ISO 10175).' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{255} )
4212      -attributetypes: ( 1.3.18.0.2.4.1121 NAME 'printer-resolution-supported' DESC 'List of resolutions supported for printing documents by this printer.  Each resolution value is a string with 3 fields:  1) Cross feed direction resolution (positive integer), 2) Feed direction resolution (positive integer), 3) Resolution unit.  Legal values are "dpi" (dots per inch) and "dpcm" (dots per centimeter).  Each resolution field is delimited by ">".  For example:  "300> 300> dpi>".' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{255} )
4213      -attributetypes: ( 1.3.18.0.2.4.1120 NAME 'printer-print-quality-supported' DESC 'List of print qualities supported for printing documents on this printer.  For example: "draft, normal".  Legal values include; "unknown", "draft", "normal", "high".' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} )
4214      -attributetypes: ( 1.3.18.0.2.4.1110 NAME 'printer-job-priority-supported' DESC 'Indicates the number of job priority levels supported.  An IPP conformant printer which supports job priority must always support a full range of priorities from "1" to "100" (to ensure consistent behavior), therefore this attribute describes the "granularity".  Legal values of this attribute are from "1" to "100".' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
4215      -attributetypes: ( 1.3.18.0.2.4.1118 NAME 'printer-copies-supported' DESC 'The maximum number of copies of a document that may be printed as a single job.  A value of "0" indicates no maximum limit.  A value of "-1" indicates unknown.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
4216      -attributetypes: ( 1.3.18.0.2.4.1111 NAME 'printer-job-k-octets-supported' DESC 'The maximum size in kilobytes (1,024 octets actually) incoming print job that this printer will accept.  A value of "0" indicates no maximum limit.  A value of "-1" indicates unknown.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
4217      -attributetypes: ( 1.3.18.0.2.4.1112 NAME 'printer-current-operator' DESC 'The name of the current human operator responsible for operating this printer.  It is suggested that this string include information that would enable other humans to reach the operator, such as a phone number.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE )
4218      -attributetypes: ( 1.3.18.0.2.4.1113 NAME 'printer-service-person' DESC 'The name of the current human service person responsible for servicing this printer.  It is suggested that this string include information that would enable other humans to reach the service person, such as a phone number.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127}  SINGLE-VALUE )
4219      -attributetypes: ( 1.3.18.0.2.4.1114 NAME 'printer-delivery-orientation-supported' DESC 'The possible delivery orientations of pages as they are printed and ejected from this printer.  Legal values include; "unknown", "face-up", and "face-down".' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} )
4220      -attributetypes: ( 1.3.18.0.2.4.1115 NAME 'printer-stacking-order-supported' DESC 'The possible stacking order of pages as they are printed and ejected from this printer. Legal values include; "unknown", "first-to-last", "last-to-first".' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} )
4221      -attributetypes: ( 1.3.18.0.2.4.1116 NAME 'printer-output-features-supported' DESC 'The possible output features supported by this printer. Legal values include; "unknown", "bursting", "decollating", "page-collating", "offset-stacking".' EQUALITY caseIgnoreMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} )
4222      -attributetypes: ( 1.3.18.0.2.4.1108 NAME 'printer-aliases' DESC 'Site-specific administrative names of this printer in addition the printer name specified for printer-name.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX  1.3.6.1.4.1.1466.115.121.1.15{127} )
4223      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.63 NAME 'sun-printer-bsdaddr' DESC 'Sets the server, print queue destination name and whether the client generates protocol extensions. "Solaris" specifies a Solaris print server extension. The value is represented by the following value: server "," destination ", Solaris".' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4224      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.64 NAME 'sun-printer-kvp' DESC 'This attribute contains a set of key value pairs which may have meaning to the print subsystem or may be user defined. Each value is represented by the following: key "=" value.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4225      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.57 NAME 'nisplusTimeZone' DESC 'tzone column from NIS+ timezone table' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4226      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.67 NAME 'ipTnetTemplateName' DESC 'Trusted Solaris network template template_name' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4227      -attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.68 NAME 'ipTnetNumber' DESC 'Trusted Solaris network template ip_address' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4228      -EOF
4229      -) > ${TMPDIR}/schema_attr
     4236 +        # first, test that baseDN ends with suffix
     4237 +        if [[ ${LC_DN: -${#LC_SFX}} != ${LC_SFX} ]]; then
     4238 +                # should not happen since check_basedn_suffix() succeeded
     4239 +                Log.fatal "Invalid suffix '${LC_SFX}' for Base DN '${LC_DN}'"
     4240 +                return 66
     4241 +        fi
     4242 +        # Save the stuff before LC_SFX w/o leading ',' -> further called prefix
     4243 +        LC_DN=${LC_DN:1:${#LC_DN}-${#LC_SFX}-1}
4230 4244  
4231      -    keep_backward_compatibility
     4245 +        # Remove redundant spaces around ',' and '=' first from LDAP_BASEDN
     4246 +        typeset DN=${ normalizeDN ${STR[LDAP_BASEDN]} ; }
4232 4247  
4233      -    # Add the entry.
4234      -    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/schema_attr ${VERB}"
4235      -    if [ $? -ne 0 ]; then
4236      -        ${ECHO} "  ERROR: update of schema attributes failed!"
4237      -        cleanup
4238      -        exit 1
4239      -    fi
     4248 +        # Now LC_DN and DN differ at most in lower vs. uppercase character and
     4249 +        # we can get the prefix of the baseDN by just copying corresponding chars
     4250 +        DN=",${DN:0:${#LC_DN}}"
4240 4251  
4241      -    # Display message that schema is updated.
4242      -    ${ECHO} "  ${STEP}. Schema attributes have been updated."
4243      -    STEP=`expr $STEP + 1`
4244      -}
     4252 +        if [[ ${DN} == ',' ]]; then
     4253 +                X='No need to create a DN component (baseDN equals suffix)'
     4254 +        else
     4255 +                typeset LAST=${ normalizeDN ${STR[LDAP_SUFFIX]} ; } DC KEY VAL CLASS
     4256 +                X="Created DN components for ${DN#,}"
     4257 +                while [[ -n ${DN} ]]; do
     4258 +                    # Get trailing key=val (DC) from DN and strip it off
     4259 +                        DN=${DN%,*}
     4260 +                        DC="${.sh.match#,}"
     4261 +                        LAST="${DC},${LAST}"
     4262 +        
     4263 +                        # Check if entry exists first, if so, skip to next.
     4264 +                    ${LDAPSEARCH} ${CON_ARGS} -b "${LAST}" -s base \
     4265 +                                'objectclass=*' >/dev/null 2>&1  &&  continue
     4266 +        
     4267 +                        VAL=${DC#*=}
     4268 +                        KEY=${.sh.match%=}
     4269 +                        # Determine the objectclass for the entry.
     4270 +                        CLASS=${ get_objectclass ${KEY} ; }
     4271 +                        if [[ -z ${CLASS} ]]; then
     4272 +                                Log.fatal "Unable to determine objectClass for '${KEY}'." \
     4273 +                                        "Please create the following entry and re-run ${PROG}:" \
     4274 +                                        "${KEY}=${VAL},${LAST}"
     4275 +                                return 66
     4276 +                        fi
4245 4277  
     4278 +                        nextFile add "${0}-${LAST}"
     4279 +                    print '
     4280 +dn: '"${LAST}"'
     4281 +'"${KEY}: ${VAL}"'
     4282 +objectClass: top
     4283 +objectClass: '"${CLASS}"'
     4284 +'                               > ${TMP[FILE]}
4246 4285  
4247      -#
4248      -# update_schema_obj(): Update the schema objectclass definitions.
4249      -#
4250      -update_schema_obj()
4251      -{
4252      -    [ $DEBUG -eq 1 ] && ${ECHO} "In update_schema_obj()"
     4286 +                    if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]}\
     4287 +                                >&${TMPF[FD]} 2>&1
     4288 +                        then
     4289 +                                Log.fatal "Update of base objects '${DC}' failed"
     4290 +                                return 66
     4291 +                        fi
     4292 +                done
     4293 +        fi
     4294 +        showProgress "${X}."
     4295 +        return 0
     4296 +}
4253 4297  
4254      -    # Add the objectclass definitions.
4255      -    ( cat <<EOF
4256      -dn: cn=schema
4257      -changetype: modify
4258      -add: objectclasses
4259      -objectclasses: ( 1.3.6.1.1.1.2.14 NAME 'NisKeyObject' SUP top MUST ( cn $ nisPublickey $ nisSecretkey ) MAY ( uidNumber $ description ) )
     4298 +Man.addFunc set_nisdomain '' '[+NAME?set_nisdomain - Add the NisDomainObject to the Base DN.]
     4299 +[+DESCRIPTION?Add a NisDomainObject with nisdomain \bSTR[LDAP_DOMAIN]]\b to the \bSTR[LDAP_BASEDN]]\b unless there is already one.]
     4300 +[+RETURN VALUES]{
     4301 +        [+0?on success.]
     4302 +        [+>= 66?a fatal error occured.]
     4303 +}
     4304 +[+SEE ALSO?\bldapsearch\b(1), \bldapmodify\b(1).]
     4305 +'
     4306 +function set_nisdomain {
     4307 +        # Check if nisDomain is already set
     4308 +        ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b "${STR[LDAP_BASEDN]}" \
     4309 +                -s base 'objectclass=*' 2>/dev/null | \
     4310 +        while read LINE ; do
     4311 +                if [[ ${LINE} == ~(Ei)^nisDomain= ]]; then
     4312 +                        showProgress 'NisDomainObject was already set for' \
     4313 +                                "'${STR[LDAP_BASEDN]}'."
     4314 +                        return 0
     4315 +                fi
     4316 +        done
4260 4317  
4261      -dn: cn=schema
     4318 +        nextFile modify $0
     4319 +        print '
     4320 +dn: '"${STR[LDAP_BASEDN]}"'
4262 4321  changetype: modify
4263      -add: objectclasses
4264      -objectclasses: ( 1.3.6.1.1.1.2.15 NAME 'nisDomainObject' SUP top MUST nisDomain )
     4322 +objectclass: nisDomainObject
     4323 +nisdomain: '"${STR[LDAP_DOMAIN]}"'
     4324 +'               >${TMP[FILE]}
4265 4325  
4266      -dn: cn=schema
4267      -changetype: modify
4268      -add: objectclasses
4269      -objectclasses: ( 1.3.6.1.1.1.2.16 NAME 'automountMap' SUP top MUST automountMapName MAY description )
     4326 +        if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     4327 +                >&${TMPF[FD]} 2>&1
     4328 +        then
     4329 +                Log.fatal "Update of NisDomainObject in '${STR[LDAP_BASEDN]}' failed"
     4330 +                return 66
     4331 +        fi
4270 4332  
4271      -dn: cn=schema
4272      -changetype: modify
4273      -add: objectclasses
4274      -objectclasses: ( 1.3.6.1.1.1.2.17 NAME 'automount' SUP top MUST ( automountKey $ automountInformation ) MAY description )
     4333 +        showProgress "NisDomainObject added to '${STR[LDAP_BASEDN]}'."
     4334 +        return 0
     4335 +}
4275 4336  
4276      -dn: cn=schema
4277      -changetype: modify
4278      -add: objectclasses
4279      -objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.7 NAME 'SolarisNamingProfile' SUP top MUST ( cn $ SolarisLDAPservers $ SolarisSearchBaseDN ) MAY ( SolarisBindDN $ SolarisBindPassword $ SolarisAuthMethod $ SolarisTransportSecurity $ SolarisCertificatePath $ SolarisCertificatePassword $ SolarisDataSearchDN $ SolarisSearchScope $ SolarisSearchTimeLimit $ SolarisPreferredServer $ SolarisPreferredServerOnly $ SolarisCacheTTL $ SolarisSearchReferral ) )
     4337 +Man.addFunc add_new_containers '' '[+NAME?add_new_containers - Add top level containers to the base DN.]
     4338 +[+DESCRIPTION?Add the Name Service Switch top level containers to the \bSTR[LDAP_BASEDN]]\b unless they already exist.]
     4339 +[+RETURN VALUES]{
     4340 +        [+0?on success.]
     4341 +        [+>= 66?a fatal error occured.]
     4342 +}
     4343 +[+SEE ALSO?\b/etc/nsswitch.ldap\b, \bldapsearch\b(1), \bldapmodify\b(1).]
     4344 +'
     4345 +function add_new_containers {
     4346 +        typeset OU
4280 4347  
4281      -dn: cn=schema
4282      -changetype: modify
4283      -add: objectclasses
4284      -objectclasses: ( 2.16.840.1.113730.3.2.4 NAME 'mailGroup' SUP top MUST mail MAY ( cn $ mgrpRFC822MailMember ) )
     4348 +        for OU in people group rpc protocols networks netgroup \
     4349 +                aliases hosts services ethers profile printers projects \
     4350 +                SolarisAuthAttr SolarisProfAttr Timezone ipTnet
     4351 +        do
     4352 +                if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
     4353 +                        -b "ou=${OU},${STR[LDAP_BASEDN]}" -s base 'objectclass=*' \
     4354 +                        >/dev/null 2>&1
     4355 +                then
     4356 +                        showProgress "'ou=${OU}' exists."
     4357 +                        continue
     4358 +                fi
4285 4359  
4286      -dn: cn=schema
4287      -changetype: modify
4288      -add: objectclasses
4289      -objectclasses: ( 1.3.6.1.4.1.42.2.27.1.2.5 NAME 'nisMailAlias' SUP top MUST cn MAY rfc822mailMember )
     4360 +                nextFile add "${0}-${OU}"
     4361 +                print '
     4362 +dn: ou='"${OU},${STR[LDAP_BASEDN]}"'
     4363 +ou: '"${OU}"'
     4364 +objectClass: top
     4365 +objectClass: organizationalUnit
     4366 +'                       > ${TMP[FILE]}
4290 4367  
4291      -dn: cn=schema
4292      -changetype: modify
4293      -add: objectclasses
4294      -objectclasses: ( 1.3.6.1.4.1.42.2.27.1.2.6 NAME 'nisNetId' SUP top MUST cn MAY ( nisNetIdUser $ nisNetIdGroup $ nisNetIdHost ) )
     4368 +                if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     4369 +                        >&${TMPF[FD]} 2>&1
     4370 +                then
     4371 +                        Log.fatal "Adding 'ou=${OU}' failed"
     4372 +                        return 66
     4373 +                fi
     4374 +                showProgress "'ou=${OU}' added."
     4375 +        done
4295 4376  
4296      -dn: cn=schema
4297      -changetype: modify
4298      -add: objectclasses
4299      -objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.2 NAME 'SolarisAuditUser' SUP top AUXILIARY MAY ( SolarisAuditAlways $ SolarisAuditNever ) )
     4377 +        return 0
     4378 +}
4300 4379  
4301      -dn: cn=schema
4302      -changetype: modify
4303      -add: objectclasses
4304      -objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.3 NAME 'SolarisUserAttr' SUP top AUXILIARY MAY ( SolarisUserQualifier $ SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrKeyValue ) )
     4380 +Man.addFunc add_auto_maps '' '[+NAME?add_auto_maps - Add the automount map entries.]
     4381 +[+DESCRIPTION?Add the automount maps \bauto_home\b, \bauto_direct\b, \bauto_master\b, \bauto_shared\b to \bSTR[LDAP_BASEDN]]\b unless they already exist.]
     4382 +[+RETURN VALUES]{
     4383 +        [+0?on success.]
     4384 +        [+>= 66?a fatal error occured.]
     4385 +}
     4386 +[+SEE ALSO?\bldapsearch\b(1), \bldapmodify\b(1).]
     4387 +'
     4388 +function add_auto_maps {
     4389 +        # AUTO_MAPS for maps to create
     4390 +        typeset AUTO_MAPS="auto_home auto_direct auto_master auto_shared" MAP
4305 4391  
4306      -dn: cn=schema
4307      -changetype: modify
4308      -add: objectclasses
4309      -objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.4 NAME 'SolarisAuthAttr' SUP top MUST cn MAY ( SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrShortDesc $ SolarisAttrLongDesc $ SolarisAttrKeyValue ) )
     4392 +        for MAP in ${AUTO_MAPS}; do
     4393 +                # Check if automap already exist
     4394 +                if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
     4395 +                        -b "automountMapName=${MAP},${STR[LDAP_BASEDN]}" -s base \
     4396 +                        'objectclass=*' >/dev/null 2>&1
     4397 +                then
     4398 +                        showProgress "'${MAP}' automount exists."
     4399 +                        continue
     4400 +                fi
4310 4401  
4311      -dn: cn=schema
4312      -changetype: modify
4313      -add: objectclasses
4314      -objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.5 NAME 'SolarisProfAttr' SUP top MUST cn MAY ( SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrLongDesc $ SolarisAttrKeyValue ) )
     4402 +                nextFile add "${0}-${MAP}"
     4403 +                print '
     4404 +dn: automountMapName='"${MAP},${STR[LDAP_BASEDN]}"'
     4405 +automountMapName: '"${MAP}"'
     4406 +objectClass: top
     4407 +objectClass: automountMap
     4408 +'                       > ${TMP[FILE]}
     4409 +    
     4410 +                if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     4411 +                        >&${TMPF[FD]} 2>&1
     4412 +                then
     4413 +                        Log.fatal "Adding '${MAP}' automount map failed"
     4414 +                        return 66
     4415 +                fi
     4416 +                showProgress "'${MAP}' automount added."
     4417 +        done
4315 4418  
4316      -dn: cn=schema
4317      -changetype: modify
4318      -add: objectclasses
4319      -objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.6 NAME 'SolarisExecAttr' SUP top AUXILIARY MAY ( SolarisKernelSecurityPolicy $ SolarisProfileType $ SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisProfileID $ SolarisAttrKeyValue ) )
     4419 +        return 0
     4420 +}
4320 4421  
4321      -dn: cn=schema
4322      -changetype: modify
4323      -add: objectclasses
4324      -objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.1 NAME 'SolarisProject' SUP top MUST ( SolarisProjectID $ SolarisProjectName ) MAY ( memberUid $ memberGid $ description $ SolarisProjectAttr ) )
     4422 +Man.addFunc modify_top_aci '' '[+NAME?modify_top_aci - add a deny self modify ACI.]
     4423 +[+DESCRIPTION?Add the ACI \bUSER_ACI_NAME\b to \bSTR[LDAP_BASEDN]]\b to disable self modify of user attributes like uid, uidNumber, gidNumber, shadowExpire, etc. This does nothing if an ACI with the same name already exists for this entry.]
     4424 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage USER_ACI_NAME ; }" '}
     4425 +[+RETURN VALUES]{
     4426 +        [+0?on success (ACI already exists or added successfully).]
     4427 +        [+>= 66?a fatal error occured.]
     4428 +}
     4429 +[+SEE ALSO?\bgetACIs()\b, \bfindACI()\b, \bldapmodify\b(1).]
     4430 +'
     4431 +function modify_top_aci {
     4432 +        typeset PATTERN
4325 4433  
4326      -dn: cn=schema
4327      -changetype: modify
4328      -add: objectclasses
4329      -objectclasses: ( 1.3.6.1.4.1.11.1.3.1.2.4 NAME 'DUAConfigProfile' SUP top DESC 'Abstraction of a base configuration for a DUA' MUST cn MAY ( defaultServerList $ preferredServerList $ defaultSearchBase $ defaultSearchScope $ searchTimeLimit $ bindTimeLimit $ credentialLevel $ authenticationMethod $ followReferrals $ serviceSearchDescriptor $ serviceCredentialLevel $ serviceAuthenticationMethod $ objectclassMap $ attributeMap $ profileTTL ) )
     4434 +        typeset -a LIST=( )
     4435 +        getACIs LIST || return 66
4330 4436  
4331      -dn: cn=schema
4332      -changetype: modify
4333      -add: objectclasses
4334      -objectclasses: ( 1.3.18.0.2.6.2549 NAME 'slpService' DESC 'DUMMY definition' SUP top MUST objectclass )
     4437 +    # check, whether ACI already exists
     4438 +        PATTERN='acl[ ]+"?('"${USER_ACI_NAME}|${USER_ACI_NAME// /_}"')"?'
     4439 +        findACI LIST "${USER_ACI_NAME}" "${PATTERN}" || return 0        # exists
4335 4440  
4336      -dn: cn=schema
     4441 +        # Create LDIF for top level ACI
     4442 +        nextFile modify $0
     4443 +        print '
     4444 +dn: '"${STR[LDAP_BASEDN]}"'
4337 4445  changetype: modify
4338      -add: objectclasses
4339      -objectclasses: ( 1.3.18.0.2.6.254 NAME 'slpServicePrinter' DESC 'Service Location Protocol (SLP) information.' SUP slpService AUXILIARY )
     4446 +add: aci
     4447 +aci: (targetattr = "cn || uid || uidNumber || gidNumber || homeDirectory || shadowLastChange || shadowMin || shadowMax || shadowWarning || shadowInactive || shadowExpire || shadowFlag || memberUid || SolarisAttrKeyValue || SolarisAttrReserved1 || SolarisAttrReserved2 || SolarisUserQualifier")
     4448 + (
     4449 +        version 3.0;  acl "'"${USER_ACI_NAME}"'";
     4450 +        deny (write) userdn = "ldap:///self";
     4451 + )
     4452 +'               > ${TMP[FILE]}
4340 4453  
4341      -dn: cn=schema
4342      -changetype: modify
4343      -add: objectclasses
4344      -objectclasses: ( 1.3.18.0.2.6.258 NAME 'printerAbstract' DESC 'Printer related information.' SUP top ABSTRACT MAY ( printer-name $ printer-natural-language-configured $ printer-location $ printer-info $ printer-more-info $ printer-make-and-model $ printer-multiple-document-jobs-supported $ printer-charset-configured $ printer-charset-supported $ printer-generated-natural-language-supported $ printer-document-format-supported $ printer-color-supported $ printer-compression-supported $ printer-pages-per-minute $ printer-pages-per-minute-color $ printer-finishings-supported $ printer-number-up-supported $ printer-sides-supported $ printer-media-supported $ printer-media-local-supported $ printer-resolution-supported $ printer-print-quality-supported $ printer-job-priority-supported $ printer-copies-supported $ printer-job-k-octets-supported $ printer-current-operator $ printer-service-person $ printer-delivery-orientation-supported $ printer-stacking-order-supported $ printer-output-features-supported ) )
     4454 +        if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     4455 +                >&${TMPF[FD]} 2>&1
     4456 +        then
     4457 +                Log.fatal 'Deny user to change non-password attributes failed'
     4458 +                return 66
     4459 +        fi
4345 4460  
4346      -dn: cn=schema
4347      -changetype: modify
4348      -add: objectclasses
4349      -objectclasses: ( 1.3.18.0.2.6.255 NAME 'printerService' DESC 'Printer information.' SUP printerAbstract STRUCTURAL MAY ( printer-uri $ printer-xri-supported ) )
     4461 +        showProgress "Self modify for non-password attributes disabled."
     4462 +        return 0
     4463 +}
4350 4464  
4351      -dn: cn=schema
4352      -changetype: modify
4353      -add: objectclasses
4354      -objectclasses: ( 1.3.18.0.2.6.257 NAME 'printerServiceAuxClass' DESC 'Printer information.' SUP printerAbstract AUXILIARY MAY ( printer-uri $ printer-xri-supported ) )
     4465 +Man.addFunc add_vlv_aci '' '[+NAME?add_vlv_aci - Add ACI for VLV.]
     4466 +[+DESCRIPTION?Add the global ACI to allow everyone read-only access to VLVs.]
     4467 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage VLV_ACI_NAME ; }" '}
     4468 +[+RETURN VALUES]{
     4469 +        [+0?on success (ACI added successfully).]
     4470 +        [+>= 66?a fatal error occured.]
     4471 +}
     4472 +[+SEE ALSO?\bldapmodify\b(1).]
     4473 +'
     4474 +function add_vlv_aci {
     4475 +        # VLV Request = 2.16.840.1.113730.3.4.9
     4476 +        typeset RULE='version 3.0;  acl "'"${VLV_ACI_NAME}"'";\n\t'
     4477 +        RULE+='allow (read,search,compare) userdn = "ldap:///anyone";'
     4478 +        typeset DN='oid=2.16.840.1.113730.3.4.9,cn=features,cn=config'
     4479 +        (( TMPF[IS_OPENDJ] )) && DN='cn=Access Control Handler,cn=config'
4355 4480  
4356      -dn: cn=schema
4357      -changetype: modify
4358      -add: objectclasses
4359      -objectclasses: ( 1.3.18.0.2.6.256 NAME 'printerIPP' DESC 'Internet Printing Protocol (IPP) information.' SUP top AUXILIARY MAY ( printer-ipp-versions-supported $ printer-multiple-document-jobs-supported ) )
     4481 +        typeset -a LIST=( )
     4482 +        getACIs LIST "${DN}" 'Global' || return 66
4360 4483  
4361      -dn: cn=schema
4362      -changetype: modify
4363      -add: objectclasses
4364      -objectclasses: ( 1.3.18.0.2.6.253 NAME 'printerLPR' DESC 'LPR information.' SUP top AUXILIARY MUST printer-name MAY printer-aliases )
     4484 +        PATTERN='acl[ ]+"?('"${VLV_ACI_NAME}|${VLV_ACI_NAME// /_}"')"?'
     4485 +        findACI LIST "${VLV_ACI_NAME}" "${PATTERN}" 'Global' || return 0
4365 4486  
4366      -dn: cn=schema
     4487 +        nextFile modify $0
     4488 +        if (( TMPF[IS_OPENDJ] )); then
     4489 +                print '
     4490 +dn: '"${DN}"'
4367 4491  changetype: modify
4368      -add: objectclasses
4369      -objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.14 NAME 'sunPrinter' DESC 'Sun printer information' SUP top AUXILIARY MUST printer-name MAY ( sun-printer-bsdaddr $ sun-printer-kvp ) )
4370      -
4371      -dn: cn=schema
     4492 +add: ds-cfg-global-aci
     4493 +ds-cfg-global-aci: (targetcontrol = "2.16.840.1.113730.3.4.9")(targetattr != "aci")
     4494 + (
     4495 +        '"${RULE}"'
     4496 + )
     4497 +'               > ${TMP[FILE]}
     4498 +        else
     4499 +                print '
     4500 +dn: '"${DN}"'
4372 4501  changetype: modify
4373      -add: objectclasses
4374      -objectclasses:  ( 1.3.6.1.4.1.42.2.27.5.2.12 NAME 'nisplusTimeZoneData' DESC 'NIS+ timezone table data' SUP top STRUCTURAL MUST cn MAY ( nisplusTimeZone $ description ) )
     4502 +replace: aci
     4503 +aci: (targetattr != "aci")
     4504 + (
     4505 +        '"${RULE}"'
     4506 + )
     4507 +'               > ${TMP[FILE]}
     4508 +        fi
4375 4509  
4376      -dn: cn=schema
4377      -changetype: modify
4378      -add: objectclasses
4379      -objectclasses:  ( 1.3.6.1.4.1.42.2.27.5.2.8 NAME 'ipTnetTemplate' DESC 'Object class for TSOL network templates' SUP top MUST ipTnetTemplateName MAY SolarisAttrKeyValue )
     4510 +        if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     4511 +                >&${TMPF[FD]} 2>&1
     4512 +        then
     4513 +                Log.fatal "Adding '${VLV_ACI_NAME}' global ACI failed"
     4514 +                return 66
     4515 +        fi
4380 4516  
4381      -dn: cn=schema
4382      -changetype: modify
4383      -add: objectclasses
4384      -objectclasses:  ( 1.3.6.1.4.1.42.2.27.5.2.9 NAME 'ipTnetHost' DESC 'Associates an IP address or wildcard with a TSOL template_name' SUP top AUXILIARY MUST ipTnetNumber )
4385      -EOF
4386      -) > ${TMPDIR}/schema_obj
     4517 +        showProgress "Global ACI '${VLV_ACI_NAME}' added."
     4518 +        return 0
     4519 +}
4387 4520  
4388      -    # Add the entry.
4389      -    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/schema_obj ${VERB}"
4390      -    if [ $? -ne 0 ]; then
4391      -        ${ECHO} "  ERROR: update of schema objectclass definitions failed!"
4392      -        cleanup
4393      -        exit 1
4394      -    fi
4395      -
4396      -    # Display message that schema is updated.
4397      -    ${ECHO} "  ${STEP}. Schema objectclass definitions have been added."
4398      -    STEP=`expr $STEP + 1`
     4521 +Man.addFunc add_proxyagent '' '[+NAME?add_proxyagent - Add proxy agent user to DS.]
     4522 +[+DESCRIPTION?Add the proxy agent user \bSTR[LDAP_PROXYAGENT]]\b to the DS unless it already exists to allow nameservice access to the server.]
     4523 +[+RETURN VALUES]{
     4524 +        [+0?on success (entry already exists or added successfully).]
     4525 +        [+>= 66?a fatal error occured.]
4399 4526  }
     4527 +[+SEE ALSO?\bldapmodify\b(1).]
     4528 +'
     4529 +function add_proxyagent {
     4530 +        # Check if proxy agent already exists
     4531 +        if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
     4532 +                -b "${STR[LDAP_PROXYAGENT]}" -s base 'objectclass=*' >/dev/null 2>&1
     4533 +        then
     4534 +                showProgress "Proxyagent identity exists."
     4535 +                return 0
     4536 +        fi
4400 4537  
4401      -#
4402      -# modify_top_aci(): Modify the ACI for the top entry to disable self modify
4403      -#                   of user attributes.
4404      -#
4405      -modify_top_aci()
4406      -{
4407      -    [ $DEBUG -eq 1 ] && ${ECHO} "In modify_top_aci()"
     4538 +        # Get cn and sn names from LDAP_PROXYAGENT.
     4539 +        typeset NAME="${STR[LDAP_PROXYAGENT]%%,*}"
     4540 +        NAME=${NAME#*=}
4408 4541  
4409      -    # Set ACI Name
4410      -    ACI_NAME="LDAP_Naming_Services_deny_write_access"
     4542 +        # Add the entry
     4543 +        nextFile add $0
     4544 +        print '
     4545 +dn: '"${STR[LDAP_PROXYAGENT]}"'
     4546 +cn: '"${NAME}"'
     4547 +sn: '"${NAME}"'
     4548 +objectclass: top
     4549 +objectclass: person
     4550 +userpassword: '"${STR[LDAP_PROXYAGENT_CRED]}"'
     4551 +'               > ${TMP[FILE]}
     4552 +    
     4553 +        if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     4554 +                >&${TMPF[FD]} 2>&1
     4555 +        then
     4556 +                Log.fatal 'Adding proxyagent identity failed'
     4557 +                return 66
     4558 +        fi
4411 4559  
4412      -    # Search for ACI_NAME
4413      -    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_top_aci 2>&1"
4414      -    if [ $? -ne 0 ]; then
4415      -        ${ECHO} "Error searching aci for ${LDAP_BASEDN}"
4416      -        cat ${TMPDIR}/chk_top_aci
4417      -        cleanup
4418      -        exit 1
4419      -    fi
4420      -    ${GREP} "${ACI_NAME}" ${TMPDIR}/chk_top_aci > /dev/null 2>&1
4421      -    if [ $? -eq 0 ]; then
4422      -        ${ECHO} "  ${STEP}. Top level ACI ${ACI_NAME} already exists for ${LDAP_BASEDN}."
4423      -        STEP=`expr $STEP + 1`
     4560 +        showProgress 'Proxyagent identity added.'
4424 4561          return 0
4425      -    fi
     4562 +}
4426 4563  
4427      -    # Crate LDIF for top level ACI.
4428      -    ( cat <<EOF
4429      -dn: ${LDAP_BASEDN}
4430      -changetype: modify
4431      -add: aci
4432      -aci: (targetattr = "cn||uid||uidNumber||gidNumber||homeDirectory||shadowLastChange||shadowMin||shadowMax||shadowWarning||shadowInactive||shadowExpire||shadowFlag||memberUid||SolarisAttrKeyValue||SolarisAttrReserved1||SolarisAttrReserved2||SolarisUserQualifier")(version 3.0; acl ${ACI_NAME}; deny (write) userdn = "ldap:///self";)
4433      --
4434      -EOF
4435      -) > ${TMPDIR}/top_aci
4436      -
4437      -    # Add the entry.
4438      -    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/top_aci ${VERB}"
4439      -    if [ $? -ne 0 ]; then
4440      -        ${ECHO} "  ERROR: Modify of top level ACI failed! (restricts self modify)"
4441      -        cleanup
4442      -        exit 1
     4564 +Man.addFunc add_entry_by_DN '' '[+NAME?add_entry_by_DN - Add an ldif file by DN.]
     4565 +[+DESCRIPTION?Add the entries in the given LDIF \afile\a to the DS unless a base entry for \aDN\a already exists.]
     4566 +[+RETURN VALUES]{
     4567 +        [+0?on success (\aDN\a already exists or added successfully).]
     4568 +        [+1?on error (failed to add entries).]
     4569 +}
     4570 +[+SEE ALSO?\bldapsearch\b(1), \bldapadd\b(1).]
     4571 +\n\n\aDN\a \afile\a
     4572 +'
     4573 +function add_entry_by_DN {
     4574 +        if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b "$1" -s base \
     4575 +                'objectclass=*' >/dev/null 2>&1
     4576 +        then
     4577 +                showProgress "'${1}' exists."
     4578 +                return 0
4443 4579      fi
4444      -
4445      -    # Display message that ACI is updated.
4446      -    MSG="ACI for ${LDAP_BASEDN} modified to disable self modify."
4447      -    if [ $EXISTING_PROFILE -eq 1 ];then
4448      -        ${ECHO} "  ACI SET: $MSG"
4449      -    else
4450      -        ${ECHO} "  ${STEP}. $MSG"
4451      -        STEP=`expr $STEP + 1`
4452      -    fi
     4580 +        if ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f "$2" >&${TMPF[FD]} 2>&1
     4581 +        then
     4582 +                showProgress "'${1}' added."
     4583 +                return 0
     4584 +        fi
     4585 +        Log.fatal "Adding '${1}' failed"
     4586 +        return 1
4453 4587  }
4454 4588  
4455      -#
4456      -# find_and_delete_ACI(): Find an ACI in file $2 with a matching pattern $1.
4457      -# Delete the ACI and print a message using $3 as the ACI name. $3 is needed
4458      -# because it could have a different value than that of $1.
4459      -find_and_delete_ACI()
4460      -{
4461      -    [ $DEBUG -eq 1 ] && ${ECHO} "In find_and_delete_ACI"
     4589 +Man.addFunc add_id_mapping_rules '' '[+NAME?add_id_mapping_rules - Add Kerberos principal to DN mapping rules to the DS.]
     4590 +[+DESCRIPTION?Add GSSAPI identity mapping rules for host credentails and user credentials to the DS config unless they already exists. Hosts are matched against \b*.STR[LDAP_DOMAIN]]@STR[LDAP_KRB_REALM]]\b and ou=hosts in \bSTR[LDAP_BASEDN]]\b, users against \b*.@STR[LDAP_KRB_REALM]]\b and uid=$1,ou=People in \bSTR[LDAP_BASEDN]]\b.]
     4591 +[+SEE ALSO?\badd_entry_by_DN()\b.]
     4592 +'
     4593 +function add_id_mapping_rules {
     4594 +        Log.info 'Adding Kerberos principal to DN mapping rules ...'
     4595 +        typeset C_DN='cn=GSSAPI,cn=identity mapping,cn=config' OC='nsContainer'
     4596 +        if (( TMPF[IS_OPENDJ] )); then
     4597 +                # we create a new branch instead of reusing the default, possibly unused
     4598 +                # 'cn=Regular Expression,cn=Identity Mappers,cn=config' GSSAPI ID mapper
     4599 +                C_DN='cn=GSSAPI,cn=Identity Mappers,cn=config'
     4600 +                OC='ds-cfg-branch'
     4601 +        fi
4462 4602  
4463      -    # if an ACI with pattern $1 exists in file $2, delete it from ${LDAP_BASEDN}
4464      -    ${EGREP} $1 $2 | ${SED} -e 's/aci=//' > ${TMPDIR}/grep_find_delete_aci 2>&1
4465      -    if [ -s ${TMPDIR}/grep_find_delete_aci ]; then
4466      -        aci_to_delete=`${CAT} ${TMPDIR}/grep_find_delete_aci`
     4603 +        nextFile add "${0}-krbPrincipal"
     4604 +        print '
     4605 +dn: cn='"${C_DN}"'
     4606 +objectClass: top
     4607 +objectClass: '"${OC}"'
     4608 +cn: GSSAPI
     4609 +'               > ${TMP[FILE]}
     4610 +        add_entry_by_DN "${C_DN}" ${TMP[FILE]} || return
4467 4611  
4468      -        # Create the tmp file to delete the ACI.
4469      -        ( cat <<EOF
4470      -dn: ${LDAP_BASEDN}
4471      -changetype: modify
4472      -delete: aci
4473      -aci: ${aci_to_delete}
4474      -EOF
4475      -        ) > ${TMPDIR}/find_delete_aci
4476      -
4477      -        # Delete the ACI
4478      -        ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/find_delete_aci ${VERB}"
4479      -        if [ $? -ne 0 ]; then
4480      -            ${ECHO} "  ERROR: Remove of $3 ACI failed!"
4481      -            cleanup
4482      -            exit 1
     4612 +        typeset H_CN="host_auth_${STR[LDAP_KRB_REALM]}"
     4613 +        typeset H_DN="cn=${H_CN}, ${C_DN}"
     4614 +        nextFile add "${0}-krbHostAuth"
     4615 +        if (( TMPF[IS_OPENDJ] )); then
     4616 +                print '
     4617 +# For now (2.6.0) OpenDJ supports a single-valued ds-cfg-identity-mapper, only.
     4618 +# So either you merge this and the next Identity Mapper to something more useful
     4619 +# together or just enable one of them until it gets fixed. For more information
     4620 +# see https://bugster.forgerock.org/jira/browse/OPENDJ-521
     4621 +dn: '"${H_DN}"'
     4622 +cn: '"${H_CN}"'
     4623 +objectClass: top
     4624 +objectClass=ds-cfg-identity-mapper
     4625 +objectClass=ds-cfg-regular-expression-identity-mapper
     4626 +ds-cfg-java-class=org.opends.server.extensions.RegularExpressionIdentityMapper
     4627 +ds-cfg-enabled=false
     4628 +ds-cfg-match-base-dn=ou=hosts,'"${STR[LDAP_BASEDN]}"'
     4629 +ds-cfg-match-pattern=host\/(.*).'"${STR[LDAP_DOMAIN]}@${STR[LDAP_KRB_REALM]}"'
     4630 +ds-cfg-replace-pattern=$1
     4631 +ds-cfg-match-attribute=cn
     4632 +'               > ${TMP[FILE]}
     4633 +        else
     4634 +                print '
     4635 +dn: '"${H_DN}"'
     4636 +objectClass: top
     4637 +objectClass: nsContainer
     4638 +objectClass: dsIdentityMapping
     4639 +objectClass: dsPatternMatching
     4640 +cn: '"${H_CN}"'
     4641 +dsMatching-pattern: ${Principal}
     4642 +dsMatching-regexp: host\/(.*).'"${STR[LDAP_DOMAIN]}@${STR[LDAP_KRB_REALM]}"'
     4643 +dsSearchBaseDN: ou=hosts,'"${STR[LDAP_BASEDN]}"'
     4644 +dsSearchFilter: (&(objectClass=ipHost)(cn=$1))
     4645 +dsSearchScope: one
     4646 +'               > ${TMP[FILE]}
4483 4647          fi
     4648 +        add_entry_by_DN "${H_DN}" ${TMP[FILE]}
4484 4649  
4485      -        ${RM} -f ${TMPDIR}/find_delete_aci
4486      -        # Display message that an ACL is deleted.
4487      -        MSG="ACI $3 deleted."
4488      -        if [ $EXISTING_PROFILE -eq 1 ]; then
4489      -            ${ECHO} "  ACI DELETED: $MSG"
     4650 +        typeset U_CN="user_auth_${STR[LDAP_KRB_REALM]}"
     4651 +        typeset U_DN="cn=${U_CN}, ${C_DN}"
     4652 +        nextFile add "${0}-krbUserAuth"
     4653 +        if (( TMPF[IS_OPENDJ] )); then
     4654 +                print '
     4655 +dn: '"${U_DN}"'
     4656 +cn: '"${U_CN}"'
     4657 +objectClass: top
     4658 +objectClass=ds-cfg-identity-mapper
     4659 +objectClass=ds-cfg-regular-expression-identity-mapper
     4660 +ds-cfg-java-class=org.opends.server.extensions.RegularExpressionIdentityMapper
     4661 +ds-cfg-enabled=true
     4662 +ds-cfg-match-base-dn=ou=People,'"${STR[LDAP_BASEDN]}"'
     4663 +ds-cfg-match-pattern=(.*)@'"${STR[LDAP_KRB_REALM]}"'
     4664 +ds-cfg-replace-pattern=$1
     4665 +ds-cfg-match-attribute=uid
     4666 +'               > ${TMP[FILE]}
4490 4667          else
4491      -            ${ECHO} "  ${STEP}. $MSG"
4492      -            STEP=`expr $STEP + 1`
     4668 +                print '
     4669 +dn: '"${U_DN}"'
     4670 +objectClass: top
     4671 +objectClass: nsContainer
     4672 +objectClass: dsIdentityMapping
     4673 +objectClass: dsPatternMatching
     4674 +cn: '"${U_CN}"'
     4675 +dsMatching-pattern: ${Principal}
     4676 +dsMatching-regexp: (.*)@'"${STR[LDAP_KRB_REALM]}"'
     4677 +dsMappedDN: uid=$1,ou=People,'"${STR[LDAP_BASEDN]}"'
     4678 +'               > ${TMP[FILE]}
4493 4679          fi
4494      -    fi
     4680 +        add_entry_by_DN "${U_DN}" ${TMP[FILE]}
4495 4681  }
4496 4682  
4497      -#
4498      -# Add an ACI to deny non-admin access to shadow data when
4499      -# shadow update is enabled.
4500      -#
4501      -deny_non_admin_shadow_access()
4502      -{
4503      -    [ $DEBUG -eq 1 ] && ${ECHO} "In deny_non_admin_shadow_access()"
     4683 +Man.addFunc modify_userpassword_acl_for_gssapi '' '[+NAME?modify_userpassword_acl_for_gssapi - Allow hosts and user to read password(s).]
     4684 +[+DESCRIPTION?Modify ACL to allow hosts to read all and a user to read its own password only, when sasl/GSSAPI bind is used.]
     4685 +[+RETURN VALUES]{
     4686 +        [+0?on success (entries already exist or added successfully).]
     4687 +        [+>= 66?a fatal error occured.]
     4688 +}
     4689 +[+SEE ALSO?\badd_entry_by_DN()\b.]
     4690 +'
     4691 +function modify_userpassword_acl_for_gssapi {
     4692 +        typeset P_DN="ou=People,${STR[LDAP_BASEDN]}"
     4693 +        typeset H_DN="ou=Hosts,${STR[LDAP_BASEDN]}"
4504 4694  
4505      -    # Set ACI Names
4506      -    ACI_TO_ADD="LDAP_Naming_Services_deny_non_admin_shadow_access"
4507      -    ACI_TO_DEL="LDAP_Naming_Services_deny_non_host_shadow_access"
     4695 +        if ! ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b "${P_DN}" -s base \
     4696 +                'objectclass=*' > /dev/null 2>&1
     4697 +        then
     4698 +                Log.verbose "'${P_DN}' does not exist"
4508 4699  
4509      -    # Search for ACI_TO_ADD
4510      -    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_aci_non_admin 2>&1"
4511      -    if [ $? -ne 0 ]; then
4512      -        ${ECHO} "Error searching aci for ${LDAP_BASEDN}"
4513      -        cleanup
4514      -        exit 1
4515      -    fi
     4700 +                nextFile add $0
     4701 +                print '
     4702 +dn: '"${P_DN}"'
     4703 +ou: People
     4704 +objectClass: top
     4705 +objectClass: organizationalUnit
     4706 +'                       > ${TMP[FILE]}
4516 4707  
4517      -    # If an ACI with ${ACI_TO_ADD} already exists, we are done.
4518      -    ${EGREP} ${ACI_TO_ADD} ${TMPDIR}/chk_aci_non_admin 2>&1 > /dev/null
4519      -    if [ $? -eq 0 ]; then
4520      -        MSG="ACI ${ACI_TO_ADD} already set for ${LDAP_BASEDN}."
4521      -        if [ $EXISTING_PROFILE -eq 1 ]; then
4522      -            ${ECHO} "  NOT SET: $MSG"
4523      -        else
4524      -            ${ECHO} "  ${STEP}. $MSG"
4525      -            STEP=`expr $STEP + 1`       
     4708 +                add_entry_by_DN "${P_DN}" ${TMP[FILE]}
     4709 +        else 
     4710 +                Log.verbose "'${P_DN}' already exists"
4526 4711          fi
4527      -        return 0
4528      -    fi
     4712 +        typeset TARGET='userPassword' PATTERN
     4713 +        (( TMPF[IS_OPENDJ] )) && TARGET+=' || authPassword'
4529 4714  
4530      -    # The deny_non_admin_shadow_access and deny_non_host_shadow_access ACIs
4531      -    # should be mutually exclusive, so if the latter exists, delete it.
4532      -    find_and_delete_ACI ${ACI_TO_DEL} ${TMPDIR}/chk_aci_non_admin ${ACI_TO_DEL}
     4715 +        typeset -A RULES=(
     4716 +                [SELF_GSS_ACI_NAME]='aci: (targetattr = "'"${TARGET}"'")
     4717 + (
     4718 +        version 3.0;  acl self-read-pwd;
     4719 +        allow (read,search) userdn="ldap:///self" and authmethod="sasl GSSAPI";
     4720 + )'
     4721 +                [HOST_GSS_ACI_NAME]='aci: (targetattr = "'"${TARGET}"'")
     4722 + (
     4723 +        version 3.0;  acl host-read-pwd;
     4724 +        allow (read,search) userdn="ldap:///cn=*+ipHostNumber=*,ou=Hosts,'"${STR[LDAP_BASEDN]}"'" and authmethod="sasl GSSAPI";
     4725 + )'
     4726 +        )
4533 4727  
4534      -    # Create the tmp file to add.
4535      -    ( cat <<EOF
4536      -dn: ${LDAP_BASEDN}
     4728 +        typeset -a LIST=( )
     4729 +        getACIs LIST "${P_DN}" || return 66
     4730 +
     4731 +        for ACI in "${!RULES[@]}" ; do
     4732 +                typeset -n NAME=${ACI}
     4733 +                [[ -z ${NAME} ]] && continue    # if it has no name, ignore it
     4734 +                PATTERN='acl[ ]+"?'"${NAME}"'"?'
     4735 +                findACI LIST "${NAME}" "${PATTERN}" 'ou=people' || continue     # exists
     4736 +                nextFile add "${0}-${NAME}"
     4737 +                print '
     4738 +dn: '"${P_DN}"'
4537 4739  changetype: modify
4538 4740  add: aci
4539      -aci: (target="ldap:///${LDAP_BASEDN}")(targetattr = "shadowLastChange||
4540      - shadowMin|| shadowMax||shadowWarning||shadowInactive||shadowExpire||
4541      - shadowFlag||userPassword") (version 3.0; acl ${ACI_TO_ADD};
4542      - deny (write,read,search,compare) userdn != "ldap:///${LDAP_ADMINDN}";)
4543      -EOF
4544      -) > ${TMPDIR}/non_admin_aci_write
4545      -    
4546      -    # Add the entry.
4547      -    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/non_admin_aci_write ${VERB}"
4548      -    if [ $? -ne 0 ]; then
4549      -        ${ECHO} "  ERROR: Adding ACI ${ACI_TO_ADD} failed!"
4550      -        ${CAT} ${TMPDIR}/non_admin_aci_write
4551      -        cleanup
4552      -        exit 1
4553      -    fi
     4741 +'"${RULES[${ACI}]}"'
     4742 +'                       > ${TMP[FILE]}
4554 4743  
4555      -    ${RM} -f ${TMPDIR}/non_admin_aci_write
4556      -    # Display message that the non-admin access to shadow data is denied.
4557      -    MSG="Non-Admin access to shadow data denied."
4558      -    if [ $EXISTING_PROFILE -eq 1 ]; then
4559      -        ${ECHO} "  ACI SET: $MSG"
4560      -    else
4561      -        ${ECHO} "  ${STEP}. $MSG"
4562      -        STEP=`expr $STEP + 1`
4563      -    fi
     4744 +                if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     4745 +                        >&${TMPF[FD]} 2>&1
     4746 +                then
     4747 +                        Log.warn "Adding '${NAME}' ou=people ACI failed."
     4748 +                        return 67
     4749 +                fi
     4750 +                showProgress "ou=people ACI '${NAME}' added."
     4751 +        done
     4752 +        return 0
4564 4753  }
4565 4754  
4566      -#
4567      -# Add an ACI to deny non-host access to shadow data when
4568      -# shadow update is enabled and auth Method if gssapi.
4569      -#
4570      -deny_non_host_shadow_access()
4571      -{
4572      -    [ $DEBUG -eq 1 ] && ${ECHO} "In deny_non_host_shadow_access()"
     4755 +Man.addFunc add_profile '' '[+NAME?add_profile - Add client profile to server.]
     4756 +[+DESCRIPTION?Generates a client profile and adds it to the DS as "\bcn=STR[LDAP_PROFILE_NAME]],ou=profile,STR[LDAP_BASEDN]]\b" unless it already exists and \bTMPF[DEL_OLD_PROFILE]]\b is not set. Other profile related variables are:]{
     4757 +        [+?STR[LDAP_SERVER_LIST]] ]
     4758 +        [+?STR[LDAP_SEARCH_SCOPE]] ]
     4759 +        [+?STR[LDAP_CRED_LEVEL]] ]
     4760 +        [+?STR[LDAP_AUTHMETHOD]] ]
     4761 +        [+?INT[LDAP_FOLLOWREF]] ]
     4762 +        [+?INT[LDAP_SEARCH_TIME_LIMIT]] ]
     4763 +        [+?INT[LDAP_PROFILE_TTL]] ]
     4764 +        [+?INT[LDAP_BIND_LIMIT]] ]
     4765 +        [+?STR[LDAP_PREF_SRVLIST]] ]
     4766 +        [+?STR[LDAP_SRV_AUTHMETHOD_PAM]] ]
     4767 +        [+?STR[LDAP_SRV_AUTHMETHOD_KEY]] ]
     4768 +        [+?STR[LDAP_SRV_AUTHMETHOD_CMD]] ]
     4769 +        [+?SSD]
     4770 +}
     4771 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage INT STR SSD ; }" '}
     4772 +[+RETURN VALUES]{
     4773 +        [+0?on success.]
     4774 +        [+>= 66?fatal error.]
     4775 +}
     4776 +[+SEE ALSO?\bldapclient\b(1M), \bldapdelete\b(1), \bldapmodify\b(1).]
     4777 +'
     4778 +function add_profile {
     4779 +        # If profile name already exists, DELETE it, and add new one
     4780 +        if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
     4781 +                -b "cn=${STR[LDAP_PROFILE_NAME]},ou=profile,${STR[LDAP_BASEDN]}" \
     4782 +                -s base 'objectclass=*' >/dev/null 2>&1
     4783 +        then
     4784 +                if (( ! TMPF[DEL_OLD_PROFILE] )); then
     4785 +                        Log.fatal "Adding client profile name '${STR[LDAP_PROFILE_NAME]}'" \
     4786 +                                'failed (entry already exists)'
     4787 +                        return 66
     4788 +                fi
4573 4789  
4574      -    # Set ACI Names
4575      -    ACI_TO_ADD="LDAP_Naming_Services_deny_non_host_shadow_access"
4576      -    ACI_TO_DEL="LDAP_Naming_Services_deny_non_admin_shadow_access"
4577      -
4578      -    # Search for ACI_TO_ADD
4579      -    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_aci_non_host 2>&1"
4580      -    if [ $? -ne 0 ]; then
4581      -        ${ECHO} "Error searching aci for ${LDAP_BASEDN}"
4582      -        cleanup
4583      -        exit 1
4584      -    fi
4585      -
4586      -    # If an ACI with ${ACI_TO_ADD} already exists, we are done.
4587      -    ${EGREP} ${ACI_TO_ADD} ${TMPDIR}/chk_aci_non_host 2>&1 > /dev/null
4588      -    if [ $? -eq 0 ]; then
4589      -        MSG="ACI ${ACI_TO_ADD} already set for ${LDAP_BASEDN}."
4590      -        if [ $EXISTING_PROFILE -eq 1 ]; then
4591      -            ${ECHO} "  NOT SET: $MSG"
4592      -        else
4593      -            ${ECHO} "  ${STEP}. $MSG"
4594      -            STEP=`expr $STEP + 1`       
     4790 +                nextFile delete $0
     4791 +                print "cn=${STR[LDAP_PROFILE_NAME]},ou=profile,${STR[LDAP_BASEDN]}" \
     4792 +                        >${TMP[FILE]}
     4793 +                if ! ${LDAPDELETE} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     4794 +                        >&${TMPF[FD]} 2>&1
     4795 +                then
     4796 +                        Log.fatal 'Attempt to DELETE old client profile' \
     4797 +                                "'${STR[LDAP_PROFILE_NAME]}' failed"
     4798 +                        return 67
     4799 +                fi
4595 4800          fi
4596      -        return 0
4597      -    fi
4598 4801  
4599      -    # The deny_non_admin_shadow_access and deny_non_host_shadow_access ACIs
4600      -    # should be mutually exclusive, so if the former exists, delete it.
4601      -    find_and_delete_ACI ${ACI_TO_DEL} ${TMPDIR}/chk_aci_non_host ${ACI_TO_DEL}
     4802 +        # Build the "ldapclient genprofile" command string to execute
     4803 +        typeset -a ARG=( )
     4804 +        ARG+=( genprofile '-a' "profileName=${STR[LDAP_PROFILE_NAME]}" )
4602 4805  
4603      -    # Create the tmp file to add.
4604      -    ( cat <<EOF
4605      -dn: ${LDAP_BASEDN}
4606      -changetype: modify
4607      -add: aci
4608      -aci: (target="ldap:///${LDAP_BASEDN}")(targetattr = "shadowLastChange||
4609      - shadowMin|| shadowMax||shadowWarning||shadowInactive||shadowExpire||
4610      - shadowFlag||userPassword") (version 3.0; acl ${ACI_TO_ADD};
4611      -  deny (write,read,search,compare)
4612      -  userdn != "ldap:///cn=*+ipHostNumber=*,ou=Hosts,${LDAP_BASEDN}";)
4613      -EOF
4614      -) > ${TMPDIR}/non_host_aci_write
4615      -    
4616      -    # Add the entry.
4617      -    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/non_host_aci_write ${VERB}"
4618      -    if [ $? -ne 0 ]; then
4619      -        ${ECHO} "  ERROR: Adding ACI ${ACI_TO_ADD} failed!"
4620      -        ${CAT} ${TMPDIR}/non_host_aci_write
4621      -        cleanup
4622      -        exit 1
4623      -    fi
     4806 +        # Add required argument defaultSearchBase
     4807 +        ARG+=( -a "defaultSearchBase=${STR[LDAP_BASEDN]}" )
4624 4808  
4625      -    ${RM} -f ${TMPDIR}/non_host_aci_write
4626      -    # Display message that the non-host access to shadow data is denied.
4627      -    MSG="Non-host access to shadow data is denied."
4628      -    if [ $EXISTING_PROFILE -eq 1 ]; then
4629      -        ${ECHO} "  ACI SET: $MSG"
4630      -    else
4631      -        ${ECHO} "  ${STEP}. $MSG"
4632      -        STEP=`expr $STEP + 1`
4633      -    fi
4634      -}
     4809 +        # Add optional parameters
     4810 +        [[ -n ${STR[LDAP_SERVER_LIST]} ]] && \
     4811 +                ARG+=( -a "defaultServerList=${STR[LDAP_SERVER_LIST]}" )
     4812 +        [[ -n ${STR[LDAP_SEARCH_SCOPE]} ]] && \
     4813 +                ARG+=( -a "defaultSearchScope=${STR[LDAP_SEARCH_SCOPE]}" )
     4814 +        [[ -n ${STR[LDAP_CRED_LEVEL]} ]] && \
     4815 +                ARG+=( -a "credentialLevel=${STR[LDAP_CRED_LEVEL]}" )
     4816 +        [[ -n ${STR[LDAP_AUTHMETHOD]} ]] && \
     4817 +                ARG+=( -a "authenticationMethod=${STR[LDAP_AUTHMETHOD]}" )
     4818 +    (( INT[LDAP_FOLLOWREF] )) && X='TRUE"' || X='FALSE"'
     4819 +        ARG+=( -a "followReferrals=${X}" )
     4820 +        (( INT[LDAP_SEARCH_TIME_LIMIT] )) && \
     4821 +                ARG+=( -a "searchTimeLimit=${INT[LDAP_SEARCH_TIME_LIMIT]}" )
     4822 +        (( INT[LDAP_PROFILE_TTL] )) && \
     4823 +                ARG+=( -a "profileTTL=${INT[LDAP_PROFILE_TTL]}" )
     4824 +        [[ -n ${INT[LDAP_BIND_LIMIT]} ]] && \
     4825 +                ARG+=( -a "bindTimeLimit=${INT[LDAP_BIND_LIMIT]}" )
     4826 +        [[ -n ${STR[LDAP_PREF_SRVLIST]} ]] && \
     4827 +                ARG+=( -a "preferredServerList=${STR[LDAP_PREF_SRVLIST]}" )
     4828 +        [[ -n ${STR[LDAP_SRV_AUTHMETHOD_PAM]} ]] && \
     4829 +                ARG+=(-a "serviceAuthenticationMethod=${STR[LDAP_SRV_AUTHMETHOD_PAM]}")
     4830 +        [[ -n ${STR[LDAP_SRV_AUTHMETHOD_KEY]} ]] && \
     4831 +                ARG+=(-a "serviceAuthenticationMethod=${STR[LDAP_SRV_AUTHMETHOD_KEY]}")
     4832 +        [[ -n ${STR[LDAP_SRV_AUTHMETHOD_CMD]} ]] && \
     4833 +                ARG+=(-a "serviceAuthenticationMethod=${STR[LDAP_SRV_AUTHMETHOD_CMD]}")
4635 4834  
4636      -#
4637      -# add_vlv_aci(): Add access control information (aci) for VLV.
4638      -#
4639      -add_vlv_aci()
4640      -{
4641      -    [ $DEBUG -eq 1 ] && ${ECHO} "In add_vlv_aci()"
     4835 +        # Add SSDs
     4836 +        typeset X
     4837 +        for X in "${SSD[@]}" ; do
     4838 +                ARG+=( -a "serviceSearchDescriptor=${X}" )
     4839 +        done
4642 4840  
4643      -    # Add the VLV ACI.
4644      -    ( cat <<EOF
4645      -dn: oid=2.16.840.1.113730.3.4.9,cn=features,cn=config
4646      -changetype: modify
4647      -replace: aci
4648      -aci: (targetattr != "aci") (version 3.0; acl "VLV Request Control"; allow(read,search,compare) userdn = "ldap:///anyone";)
4649      -EOF
4650      -) > ${TMPDIR}/vlv_aci
     4841 +    # Execute "ldapclient genprofile" to create profile
     4842 +        nextFile add $0
     4843 +        if ! ${LDAPCLIENT} "${ARG[@]}" >${TMP[FILE]} 2>${TMP[DIR]}/gen_profile.err
     4844 +        then
     4845 +                Log.fatal 'ldapclient genprofile failed'
     4846 +                return 68
     4847 +        fi
4651 4848  
4652      -    # Add the entry.
4653      -    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/vlv_aci ${VERB}"
4654      -    if [ $? -ne 0 ]; then
4655      -        ${ECHO} "  ERROR: Add of VLV ACI failed!"
4656      -        cleanup
4657      -        exit 1
4658      -    fi
     4849 +        # Add the generated profile
     4850 +        if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     4851 +                >&${TMPF[FD]} 2>&1
     4852 +        then
     4853 +                log.fatal 'Attempt to add profile failed!'
     4854 +                return 69
     4855 +        fi
4659 4856  
4660      -    # Display message that schema is updated.
4661      -    ${ECHO} "  ${STEP}. Add of VLV Access Control Information (ACI)."
4662      -    STEP=`expr $STEP + 1`
     4857 +        showProgress 'Client profile generated and pushed to the DS.'
     4858 +        return 0
4663 4859  }
4664 4860  
4665      -
4666      -#
4667      -# set_nisdomain(): Add the NisDomainObject to the Base DN.
4668      -#
4669      -set_nisdomain()
4670      -{
4671      -    [ $DEBUG -eq 1 ] && ${ECHO} "In set_nisdomain()"
4672      -
4673      -    # Check if nisDomain is already set.
4674      -    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base \
4675      -        \"objectclass=*\"" > ${TMPDIR}/chk_nisdomain 2>&1
4676      -    ${EVAL} "${GREP} -i nisDomain ${TMPDIR}/chk_nisdomain ${VERB}"
4677      -    if [ $? -eq 0 ]; then
4678      -        ${ECHO} "  ${STEP}. NisDomainObject for ${LDAP_BASEDN} was already set."
4679      -        STEP=`expr $STEP + 1`
4680      -        return 0
4681      -    fi
4682      -
4683      -    # Add the new top level containers.
4684      -    ( cat <<EOF
4685      -dn: ${LDAP_BASEDN}
4686      -changetype: modify
4687      -objectclass: nisDomainObject
4688      -nisdomain: ${LDAP_DOMAIN}
4689      -EOF
4690      -) > ${TMPDIR}/nis_domain
4691      -
4692      -    # Add the entry.
4693      -    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/nis_domain ${VERB}"
4694      -    if [ $? -ne 0 ]; then
4695      -        ${ECHO} "  ERROR: update of NisDomainObject in ${LDAP_BASEDN} failed."
4696      -        cleanup
4697      -        exit 1
4698      -    fi
4699      -
4700      -    # Display message that schema is updated.
4701      -    ${ECHO} "  ${STEP}. NisDomainObject added to ${LDAP_BASEDN}."
4702      -    STEP=`expr $STEP + 1`
     4861 +Man.addFunc checkTaskCompletion '' '[+NAME?checkTaskCompletion - Wait and check completion of a DS task.]
     4862 +[+DESCRIPTION?Checks the state of the DS task with the given \adn\a periodically until it got stopped due to an error or has been finished successfully, or the timeout has been hit. Timeout is an integer and specifies the number of seconds to max. wait for completion. If not given or invalid 60 will be used instead.]
     4863 +[+RETURN VALUES]{
     4864 +        [+0?on success.]
     4865 +        [+1?task failed.]
     4866 +        [+2?timeout has been hit, task not yet finished or has an unknown state.]
4703 4867  }
     4868 +[+See Also?\bldapsearch\b(1)]
     4869 +\n\n\adn\a [\atimeout\a]
     4870 +'
     4871 +function checkTaskCompletion {
     4872 +        typeset DN="$1" STATUS='nstaskstatus=' TASKID X
     4873 +        integer TIMEOUT=${2:-${INT[TASK_TIMEOUT]}} RESULT=2 SEEN
     4874 +        (( TIMEOUT < 10 )) && TIMEOUT=60
     4875 +        (( TMPF[IS_OPENDJ] )) && STATUS='ds-task-state='
     4876 +        TASKID=${DN%%,*}
     4877 +        # Wait for task to finish, display current status.
     4878 +        while (( TIMEOUT > 0 )) ; do
     4879 +                SEEN=0 X=''
     4880 +                ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
     4881 +                        -b "${DN}" -s base 'objectclass=*' ${STATUS%=} 2>/dev/null | \
     4882 +                while read LINE ; do
     4883 +                        [[ ${LINE%%,*} == ${TASKID} ]] && SEEN=1 && continue
     4884 +                        [[ -z ${X} && ${LINE:0:${#STATUS}} == ${STATUS} ]] && \
     4885 +                                X=${LINE:${#STATUS}}
     4886 +                done
     4887 +                (( ! SEEN )) && break   # an error occured
     4888 +                print -n '.'
     4889 +                [[ ${X} =~ Finished || ${X} == 'COMPLETED_SUCCESSFULLY' ]] && \
     4890 +                        RESULT=0 && break
     4891 +                [[ ${X:0:12} == 'Index failed' || ${X:016} == 'STOPPED_BY_ERROR' ]] && \
     4892 +                        RESULT=1 && break
     4893 +                sleep 1
     4894 +                (( TIMEOUT-=1 ))
     4895 +        done
     4896 +        # DSEE removes non-recurring tasks automagically, OpenDJ not
     4897 +        (( RESULT < 2 && TMPF[IS_OPENDJ] )) && \
     4898 +                ${LDAPDELETE} ${CON_ARGS} "${AUTH_ARGS[@]}" "${DN}" >&${TMPF[FD]} 2>&1
     4899 +        return ${RESULT}
     4900 +}
4704 4901  
4705      -
4706      -#
4707      -# check_attrName(): Check that the attribute name is valid.
4708      -#              $1   Key to check.
4709      -#         Returns   0 : valid name      1 : invalid name
4710      -#
4711      -check_attrName()
4712      -{
4713      -    [ $DEBUG -eq 1 ] && ${ECHO} "In check_attrName()"
4714      -    [ $DEBUG -eq 1 ] && ${ECHO} "check_attrName: Input Param = $1"
4715      -
4716      -    ${ECHO} $1 | ${EGREP} '^[0-9]+(\.[0-9]+)*$' > /dev/null 2>&1
4717      -    if [ $? -eq 0 ]; then       
4718      -        ${EVAL} "${LDAPSEARCH} ${SERVER_ARGS} -b cn=schema -s base \"objectclass=*\" \
4719      -                        attributeTypes | ${EGREP} -i '^attributetypes[ ]*=[ ]*\([ ]*$1 ' ${VERB}"
4720      -    else        
4721      -        ${EVAL} "${LDAPSEARCH} ${SERVER_ARGS} -b cn=schema -s base \"objectclass=*\" \
4722      -                        attributeTypes | ${EGREP} -i \"'$1'\" ${VERB}"
4723      -    fi
4724      -
4725      -    if [ $? -ne 0 ]; then
4726      -        return 1 
4727      -    else
4728      -        return 0        
4729      -    fi  
     4902 +Man.addFunc rebuildIndex '' '[+NAME?rebuildIndex - Rebuild a single index.]
     4903 +[+DESCRIPTION?Instruct the DS to rebuild the index with the name \aname\a. If the \aname\a starts with "vlv." it indicates a Virtual List View, which is supported for OpenDJ, only. Wrt. to OpenDJ and VLVs a return code of \b0\b does not necessaryly mean, that the index is finally in a non-degraded state. It just means, the task has been executed successfully.]
     4904 +[+RETURN VALUES]{
     4905 +        [+0?on success.]
     4906 +        [+1?if a VLV index was specified, but the current DS is != OpenDJ/OpenDS.]
     4907 +        [+2?if the task failed or did not complete within 60 seconds.]
     4908 +        [+66?if scheduling a rebuild task on the DS failed.]
4730 4909  }
     4910 +[+SEE ALSO?\bcheckTaskCompletion()\b, \bldapsearch\b(1), \bldapmodify\b(1).]
     4911 +\n\n\aname\a
     4912 +'
     4913 +function rebuildIndex {
     4914 +        typeset IDX=$1
     4915 +        TASKNAME=${IDX}_${ date "+%Y_%m_%d_%H_%M_%S" ; }
4731 4916  
     4917 +        if [[ ${IDX:0:4} == 'vlv.' ]] && (( ! TMPF[IS_OPENDJ] )) ; then
     4918 +                Log.warn 'Non-OpenDJ/OpenDS servers do not support VLV rebuildTasks'
     4919 +                return 1
     4920 +        fi
4732 4921  
4733      -#
4734      -# get_objectclass():   Determine the objectclass for the given attribute name 
4735      -#              $1   Attribute name to check.
4736      -#      _ATTR_NAME   Return value, Object Name or NULL if unknown to idsconfig.
4737      -#
4738      -#      NOTE: An attribute name can be valid but still we might not be able
4739      -#            to determine the objectclass from the table.
4740      -#            In such cases, the user needs to create the necessary object(s).
4741      -#
4742      -get_objectclass()
4743      -{
4744      -    [ $DEBUG -eq 1 ] && ${ECHO} "In get_objectclass()"
4745      -    [ $DEBUG -eq 1 ] && ${ECHO} "get_objectclass: Input Param = $1"
     4922 +        nextFile add "${0}-task-${TASKNAME}"
     4923 +        if (( TMPF[IS_OPENDJ] )); then
     4924 +                # NOTE: rebuildTask requires ldif-import LDAP privilege.
     4925 +                # It's a little bit inefficient: one could schedule a single task at
     4926 +                # the end of the function and use 'rebuildall' or a space separated
     4927 +                # list of all attributes in ds-task-rebuild-index to do it at once.
     4928 +                DN='ds-task-id='"${TASKNAME}"',cn=Scheduled Tasks,cn=Tasks'
     4929 +                print '
     4930 +# rebuild-index --index '"${IDX}"' --baseDN '"${STR[LDAP_BASEDN]}"' \
     4931 +#        '"${CON_ARGS} ${AUTH_ARGS[@]}"' -X
4746 4932  
4747      -    # Set return value to NULL string.
4748      -    _ATTR_NAME=""
     4933 +dn: '"${DN}"'
     4934 +ds-task-id: '"${TASKNAME}"'
     4935 +objectClass: top
     4936 +objectClass: ds-task
     4937 +objectClass: ds-task-rebuild
     4938 +ds-task-class-name: org.opends.server.tasks.RebuildTask
     4939 +ds-task-rebuild-base-dn: '"${STR[LDAP_SUFFIX]}"'
     4940 +ds-task-rebuild-index: '"${IDX}"'
     4941 +#ds-task-rebuild-tmp-directory:
     4942 +'               > ${TMP[FILE]}
     4943 +        else
     4944 +                DN='cn='"${TASKNAME}"',cn=index,cn=tasks,cn=config'
     4945 +                print '
     4946 +dn: '"${DN}"'
     4947 +cn: '"${TASKNAME}"'
     4948 +objectclass: top
     4949 +objectclass: extensibleObject
     4950 +nsInstance: '"${STR[DS_DB]}"'
     4951 +nsIndexAttribute: '"${IDX}"'
     4952 +'               > ${TMP[FILE]}
     4953 +        fi
4749 4954  
4750      -    # Test key for type:
4751      -    case `${ECHO} ${1} | tr '[A-Z]' '[a-z]'` in
4752      -        ou | organizationalunitname | 2.5.4.11) _ATTR_NAME="organizationalUnit" ;;
4753      -        dc | domaincomponent | 0.9.2342.19200300.100.1.25) _ATTR_NAME="domain" ;;
4754      -         o | organizationname | 2.5.4.10) _ATTR_NAME="organization" ;;
4755      -         c | countryname | 2.5.4.6) _ATTR_NAME="country" ;;
4756      -         *)  _ATTR_NAME="" ;;
4757      -    esac
     4955 +        if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     4956 +                >&${TMPF[FD]} 2>&1
     4957 +        then
     4958 +                Log.fatal "Adding task for '${IDX}' failed"
     4959 +                return 66
     4960 +        fi
4758 4961  
4759      -    [ $DEBUG -eq 1 ] && ${ECHO} "get_objectclass: _ATTR_NAME = $_ATTR_NAME"
     4962 +        checkTaskCompletion "${DN}" && print "" || { Log.warn 'FAILED'; return 2; }
     4963 +        return 0
4760 4964  }
4761 4965  
     4966 +Man.addFunc add_indexes '' '[+NAME?add_indexes - Add indexes.]
     4967 +[+DESCRIPTION?Add indexes of the given \atypes\a (e.g. "pres eq") for the given \aattributes\a (e.g. "uidNumber gidnumber") and schedule corresponding tasks to actually create the indexes unless they already exist. Both arguments are handle as a whitespace separated list.]
     4968 +[+RETURN VALUES]{
     4969 +        [+-1?syntax error (insufficient parameters).]
     4970 +        [+0?on success.]
     4971 +        [+>= 66?fatal error.]
     4972 +}
     4973 +[+SEE ALSO?\bldapsearch\b(1), \bldapmodify\b(1).]
     4974 +\n\n\atypes\a \aattributes\a
     4975 +'
     4976 +function add_indexes {
     4977 +        if [[ -z ${STR[DS_DB]} ]]; then
     4978 +                get_backend || return 66
     4979 +        fi
     4980 +        [[ -z $1 || -z $2 ]] && Log.warn "${.sh.fun}(): syntax error" && return -1
4762 4981  
4763      -#
4764      -# add_base_objects(): Add any necessary base objects.
4765      -#
4766      -add_base_objects()
4767      -{
4768      -    [ $DEBUG -eq 1 ] && ${ECHO} "In add_base_objects()"
     4982 +        typeset -l TYPES=${1//,/ }              # we allow comma separated lists as well
     4983 +        typeset IDX=${2//,/ }
4769 4984  
4770      -    # Convert to lower case for basename.
4771      -    format_string "${LDAP_BASEDN}"
4772      -    LOWER_BASEDN="${FMT_STR}"
4773      -    format_string "${LDAP_SUFFIX}"
4774      -    LOWER_SUFFIX="${FMT_STR}"
     4985 +    Log.verbose "Processing '${TYPES// /,}' indexes ..."
4775 4986  
4776      -    [ $DEBUG -eq 1 ] && ${ECHO} "LOWER_BASEDN: ${LOWER_BASEDN}"
4777      -    [ $DEBUG -eq 1 ] && ${ECHO} "LOWER_SUFFIX: ${LOWER_SUFFIX}"
     4987 +        typeset DN="cn=index,cn=${STR[DS_DB]},cn=ldbm database,cn=plugins,cn=config"
     4988 +        typeset LTYPE="nsIndexType: ${TYPES// /$'\n'nsIndexType: }"
     4989 +        typeset ATTR='cn' OC='extensibleObject' DST TASKNAME LINE X
     4990 +        integer SEEN
     4991 +        if (( TMPF[IS_OPENDJ] )); then
     4992 +                OC='ds-cfg-branch'
     4993 +                DN="cn=Index,ds-cfg-backend-id=${STR[DS_DB]},cn=Backends,cn=config"
     4994 +                ATTR='ds-cfg-attribute'
     4995 +                LTYPE=''
     4996 +                for X in ${TYPES}; do
     4997 +                        [[ $X == 'eq' ]] && LTYPE+='ds-cfg-index-type: equality\n'
     4998 +                        [[ $X == 'pres' ]] && LTYPE+='ds-cfg-index-type: presence\n'
     4999 +                        [[ $X == 'sub' ]] && LTYPE+='ds-cfg-index-type: substring\n'
     5000 +                done
     5001 +        fi
4778 5002  
4779      -    # Create additional components.
4780      -    if [ "${LOWER_BASEDN}" = "${LOWER_SUFFIX}" ]; then
4781      -        [ $DEBUG -eq 1 ] && ${ECHO} "Base DN and Suffix equivalent"
4782      -    else
4783      -        # first, test that the suffix is valid
4784      -        dcstmp=`basename "${LOWER_BASEDN}" "${LOWER_SUFFIX}"`
4785      -        if [ "$dcstmp" = "${LOWER_BASEDN}" ]; then
4786      -            # should not happen since check_basedn_suffix() succeeded
4787      -            ${ECHO} "Invalid suffix ${LOWER_SUFFIX}"
4788      -            ${ECHO} "for Base DN ${LOWER_BASEDN}"
4789      -            cleanup
4790      -            exit 1
     5003 +        # check, whether Index container exists - if not, create it
     5004 +        if ! ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b "${DN}" \
     5005 +                -s base 'objectclass=*' > /dev/null 2>&1
     5006 +        then
     5007 +                nextFile add $0
     5008 +                X=${DN%%,*}
     5009 +                print '
     5010 +dn: '"${DN}"'
     5011 +objectClass: top
     5012 +objectClass: '"${OC}"'
     5013 +cn: '"${X#*=}"'
     5014 +'               >${TMP[FILE]}
     5015 +                if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     5016 +                        >&${TMPF[FD]} 2>&1
     5017 +                then
     5018 +                        Log.fatal 'Failed to add backend Index base'
     5019 +                        return 66
     5020 +                fi
4791 5021          fi
4792      -        # OK, suffix is valid, start working with LDAP_BASEDN
4793      -        # field separator is ',' (i.e., space is a valid character)
4794      -        dcstmp2="`${ECHO} ${LDAP_BASEDN} |
4795      -                sed -e 's/[ ]*,[ ]*/,/g' -e 's/[ ]*=[ ]*/=/g'`"
4796      -        dcs=""
4797      -        # use dcstmp to count the loop, and dcstmp2 to get the correct
4798      -        # string case
4799      -        # dcs should be in reverse order, only for these components
4800      -        # that need to be added
4801      -        while [ -n "${dcstmp}" ]
4802      -        do
4803      -            i2=`${ECHO} "$dcstmp2" | cut -f1 -d','`
4804      -            dk=`${ECHO} $i2 | awk -F= '{print $1}'`
4805      -            dc=`${ECHO} $i2 | awk -F= '{print $2}'`
4806      -            dcs="$dk=$dc,$dcs";
4807      -            dcstmp2=`${ECHO} "$dcstmp2" | cut -f2- -d','`
4808      -            dcstmp=`${ECHO} "$dcstmp" | cut -f2- -d','`
4809      -            [ $DEBUG -eq 1 ] && \
4810      -                ${ECHO} "dcs: ${dcs}\ndcstmp: ${dcstmp}\ndcstmp2: ${dcstmp2}\n"
4811      -        done
4812 5022  
     5023 +        for DST in ${IDX} ; do
     5024 +                # Check if entry exists first. If so, skip to next
     5025 +                if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
     5026 +                        -b "${ATTR}=${DST},${DN}" -s base 'objectclass=*' > /dev/null 2>&1
     5027 +                then
     5028 +                        showProgress "'${DST}' index exists."   
     5029 +                        continue
     5030 +                fi
4813 5031  
     5032 +                nextFile add "${0}-${DST}"
     5033 +                if (( TMPF[IS_OPENDJ] )); then
     5034 +                        X=${LTYPE//'\n'/ }
     5035 +                        X=${X//: /:}
     5036 +                        print '
     5037 +# dsconfig create-local-db-index '"${CON_ARGS} ${AUTH_ARGS[@]}"' -X \
     5038 +#       '"${X//ds-cfg-/--set }"' \
     5039 +#       --backend-name '"${STR[DS_DB]}"' --index-name '"${DST}"'
4814 5040  
4815      -        lastdc=${LDAP_SUFFIX}
4816      -        dc=`${ECHO} "${dcs}" | cut -f1 -d','`
4817      -        dcstmp=`${ECHO} "${dcs}" | cut -f2- -d','`
4818      -        while [ -n "${dc}" ]; do
4819      -            # Get Key and component from $dc.
4820      -            dk2=`${ECHO} $dc | awk -F= '{print $1}'`
4821      -            dc2=`${ECHO} $dc | awk -F= '{print $2}'`
     5041 +dn: ds-cfg-attribute='"${DST},${DN}"'
     5042 +ds-cfg-attribute: '"${DST}"'
     5043 +objectClass: top
     5044 +objectClass: ds-cfg-local-db-index
     5045 +'"${LTYPE}"'
     5046 +'                       > ${TMP[FILE]}
     5047 +                else
     5048 +                        print '
     5049 +dn: cn='"${DST},${DN}"'
     5050 +objectClass: top
     5051 +objectClass: nsIndex
     5052 +cn: '"${DST}"'
     5053 +nsSystemIndex: false
     5054 +'"${LTYPE}"'
     5055 +'                       > ${TMP[FILE]}
     5056 +                fi
     5057 +                if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     5058 +                        >&${TMPF[FD]} 2>&1
     5059 +                then
     5060 +                        Log.fatal "Adding '${DST}' backend index failed"
     5061 +                        return 67
     5062 +                fi
     5063 +                showProgress "'${DST}' backend index added."
     5064 +                rebuildIndex ${DST}
     5065 +        done
     5066 +        return 0
     5067 +}
4822 5068  
4823      -            # At this point, ${dk2} is a valid attribute name
     5069 +Man.addFunc add_eq_indexes '' '[+NAME?add_eq_indexes - Add indexes of type pres and eq.]
     5070 +[+DESCRIPTION?Add eq,pres indexes and schedule corresponding tasks to actually create the indexes unless they already exist.]
     5071 +[+RETURN VALUES]{
     5072 +        [+0?on success.]
     5073 +        [+>= 66?fatal error.]
     5074 +}
     5075 +[+SEE ALSO?\badd_indexes()\b.]
     5076 +'
     5077 +function add_eq_indexes {
     5078 +        add_indexes "pres eq" \
     5079 +                "uidNumber ipNetworkNumber gidnumber oncrpcnumber automountKey"
     5080 +}
4824 5081  
4825      -            # Check if entry exists first, if so, skip to next.
4826      -            ${LDAPSEARCH} ${SERVER_ARGS} -b "${dk2}=${dc2},$lastdc" -s base "objectclass=*" > /dev/null 2>&1
4827      -            if [ $? -eq 0 ]; then
4828      -                # Set the $lastdc to new dc.
4829      -                lastdc="${dk2}=${dc2},$lastdc"
     5082 +Man.addFunc add_sub_indexes '' '[+NAME?add_sub_indexes - Add indexes of type pres, eq and sub.]
     5083 +[+DESCRIPTION?Add eq,pres,sub indexes and schedule corresponding tasks to actually create the indexes unless they already exist.]
     5084 +[+RETURN VALUES]{
     5085 +        [+0?on success.]
     5086 +        [+>= 66?fatal error.]
     5087 +}
     5088 +[+SEE ALSO?\badd_indexes()\b.]
     5089 +'
     5090 +function add_sub_indexes {
     5091 +        add_indexes "pres eq sub" \
     5092 +                "ipHostNumber membernisnetgroup nisnetgrouptriple"
     5093 +}
4830 5094  
4831      -                # Process next component.
4832      -                dc=`${ECHO} "${dcstmp}" | cut -f1 -d','`
4833      -                dcstmp=`${ECHO} "${dcstmp}" | cut -f2- -d','`
4834      -                continue
     5095 +Man.addFunc add_vlv_indexes_OpenDJ '' '[+NAME?add_vlv_indexes_OpenDJ - Add VLV indexes to OpenDS/OpenDJ.]
     5096 +[+DESCRIPTION?OpenDS/OpenDJ specialized part of \badd_vlv_indexes()\b (pulled out for easier maintenance).]
     5097 +[+SEE ALSO?\badd_vlv_indexes()\b, https://blogs.oracle.com/kanthi/entry/ldap_paged_results_more]
     5098 +[+NOTES?\bpagedResultsControl\b and \bVLV\b is per default allowed for authenticated users, only. To check, try something like this:]{
     5099 +        [+?ldapsearch -r -j /tmp/pw -D "cn=Directory Manager" -h ldaphost \]
     5100 +        [+?     -b "cn=Access Control Handler,cn=config" "objectclass=*" | \]
     5101 +        [+?     egrep "1.2.840.113556.1.4.319|2.16.840.1.113730.3.4.9"]
     5102 +}
     5103 +\n\n\avname\a \afile\a
     5104 +'
     5105 +function add_vlv_indexes_OpenDJ {
     5106 +        typeset -n INDEX_TABLE=$1
     5107 +        typeset OUT="$2" ENTRY IDX_NAME CN SCOPE='single-level' BASE FILTER
4835 5108  
4836      -            fi
     5109 +        [[ ${STR[LDAP_SEARCH_SCOPE]} == sub ]] && SCOPE='subordinate-subtree'
     5110 +        BACKEND="cn=VLV Index,ds-cfg-backend-id=${STR[DS_DB]},cn=Backends,cn=config"
4837 5111  
4838      -            # Determine the objectclass for the entry.
4839      -            get_objectclass $dk2
4840      -            OBJ_Name=${_ATTR_NAME}
4841      -            if [ "${OBJ_Name}" = "" ]; then
4842      -                ${ECHO} "Cannot determine objectclass for $dk2"
4843      -                ${ECHO} "Please create ${dk2}=${dc2},$lastdc entry and rerun idsconfig"
4844      -                exit 1 
4845      -            fi
4846      -
4847      -            # Add the new container.
4848      -            ( cat <<EOF
4849      -dn: ${dk2}=${dc2},$lastdc
4850      -${dk2}: $dc2
     5112 +        # check, whether VLV Index container exists - if not, create it
     5113 +        if ! ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b "${BACKEND}" \
     5114 +                -s base 'objectclass=*' > /dev/null 2>&1
     5115 +        then
     5116 +                nextFile add $0
     5117 +                print '
     5118 +dn: '"${BACKEND}"'
4851 5119  objectClass: top
4852      -objectClass: ${OBJ_Name}
4853      -EOF
4854      -) > ${TMPDIR}/base_objects
     5120 +objectClass: ds-cfg-branch
     5121 +cn: VLV Index
     5122 +'                       >${TMP[FILE]}
     5123 +                if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     5124 +                        >&${TMPF[FD]} 2>&1
     5125 +                then
     5126 +                        Log.fatal 'Adding VLV Index base'
     5127 +                        return 66
     5128 +                fi
     5129 +        fi
4855 5130  
     5131 +        integer COUNT=0
     5132 +    # create index entries
     5133 +    for ENTRY in "${INDEX_TABLE[@]}" ; do
     5134 +                typeset -a F=( ${ENTRY} )                                       # split columns
     5135 +                
     5136 +                IDX_NAME="${STR[LDAP_DOMAIN]}.get${F[0]}"
     5137 +                BASE="ou=${F[2]},${STR[LDAP_BASEDN]}"
     5138 +                [[ ${F[2]} =~ = ]] && BASE="${BASE:3}"          # cut out ou=
     5139 +                FILTER="objectClass=${F[3]}"
     5140 +                [[ ${F[3]:0:1} == '&' ]] && FILTER="&(objectClass=${F[3]:2}"
4856 5141  
4857      -            # Set the $lastdc to new dc.
4858      -            lastdc="${dk2}=${dc2},$lastdc"
     5142 +                if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -s base \
     5143 +                        -b "ds-cfg-name=${IDX_NAME},${BACKEND}" 'objectclass=*' \
     5144 +                        > /dev/null 2>&1
     5145 +                then
     5146 +                        showProgress "'${IDX_NAME}' VLV index exists."
     5147 +                        continue
     5148 +                fi
4859 5149  
4860      -            # Add the entry.
4861      -            ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/base_objects ${VERB}"
4862      -            if [ $? -ne 0 ]; then
4863      -                ${ECHO} "  ERROR: update of base objects ${dc} failed."
4864      -                cleanup
4865      -                exit 1
4866      -            fi
     5150 +                nextFile add "${0}-${IDX_NAME}"
     5151 +                print '
     5152 +# dsconfig create-local-db-vlv-index '"${CON_ARGS} ${AUTH_ARGS[@]}"' -X \
     5153 +#       --backend-name "'"${STR[DS_DB]}"'" \
     5154 +#       --set "base-dn:'"${BASE}"'" \
     5155 +#       --index-name '"${IDX_NAME}"' --set "sort-order:cn uid" \
     5156 +#       --set "scope:'"${SCOPE}"'" --set "filter:'"${FILTER}"'"
4867 5157  
4868      -            # Display message that schema is updated.
4869      -            ${ECHO} "  ${STEP}. Created DN component ${dc}."
4870      -            STEP=`expr $STEP + 1`
     5158 +dn: ds-cfg-name='"${IDX_NAME},${BACKEND}"'
     5159 +objectClass: top
     5160 +objectClass: ds-cfg-local-db-vlv-index
     5161 +ds-cfg-name: '"${IDX_NAME}"'
     5162 +ds-cfg-base-dn: '"${BASE}"'
     5163 +ds-cfg-scope: '"${SCOPE}"'
     5164 +ds-cfg-filter: '"${FILTER}"'
     5165 +ds-cfg-sort-order: cn uid
     5166 +aci: (targetattr = "*")
     5167 + (
     5168 +    version 3.0;  acl "Config";
     5169 +    allow (read,search,compare) userdn="ldap:///anyone";
     5170 + )
     5171 +'               > ${TMP[FILE]}
4871 5172  
4872      -            # Process next component.
4873      -            dc=`${ECHO} "${dcstmp}" | cut -f1 -d','`
4874      -            dcstmp=`${ECHO} "${dcstmp}" | cut -f2- -d','`
     5173 +                if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     5174 +                        >&${TMPF[FD]} 2>&1
     5175 +                then
     5176 +                        Log.fatal "Adding '${IDX_NAME}' VLV index failed"
     5177 +                        return 67
     5178 +                fi
     5179 +                showProgress "'${IDX_NAME}' VLV index added."
     5180 +
     5181 +                if rebuildIndex "vlv.${IDX_NAME}" ; then
     5182 +                        (( COUNT++ ))
     5183 +                else
     5184 +                        print "rebuild-index -b '${STR[LDAP_SUFFIX]}' " \
     5185 +                                "--index 'vlv.${IDX_NAME}'" >>${OUT}
     5186 +                fi
4875 5187          done
4876      -    fi
     5188 +        if (( COUNT )); then
     5189 +                # Bug or feature: Even if scheduled as task, VLV idx rebuild leaves
     5190 +                # the index in degraded state. So:
     5191 +                showProgress 'Rebuilding degraded indexes.'
     5192 +                if ! rebuildIndex rebuilddegraded ; then
     5193 +                        print "svcadm disable opendj@VERS@\n" \
     5194 +                                "rebuild-index -b '${STR[LDAP_SUFFIX]}' --rebuildDegraded\n" \
     5195 +                                "svcadm enable opendj@VERS@"
     5196 +                                >>${OUT}
     5197 +                fi
     5198 +        fi
4877 5199  }
4878 5200  
     5201 +Man.addFunc add_vlv_indexes_DSEE '' '[+NAME?add_vlv_indexes_DSEE - Add VLV indexes to DSEE.]
     5202 +[+DESCRIPTION?DSEE specialized part of \badd_vlv_indexes()\b (pulled out for easier maintenance).]
     5203 +[+SEE ALSO?\b\badd_vlv_indexes()\b.]
     5204 +\n\n\avname\a \afile\a
     5205 +'
     5206 +function add_vlv_indexes_DSEE {
     5207 +        typeset -n INDEX_TABLE=$1
     5208 +        typeset OUT="$2" ENTRY IDX_NAME CN SCOPE=1 BASE FILTER
4879 5209  
4880      -#
4881      -# add_new_containers(): Add the top level classes.
4882      -#
4883      -#    $1 = Base DN
4884      -#
4885      -add_new_containers()
4886      -{
4887      -    [ $DEBUG -eq 1 ] && ${ECHO} "In add_new_containers()"
     5210 +        typeset INFO=( ${TMP[DS_INFO]} )
     5211 +        integer MAJOR=${INFO[${#INFO[@]}-2]}
     5212 +        typeset INSTANCE="@serverInstance@" LINE
     5213 +        ${LDAPSEARCH} -v ${CON_ARGS} "${AUTH_ARGS[@]}" -b 'cn=config' \
     5214 +                -s base 'objectclass=*' nsslapd-instancedir 2>/dev/null | \
     5215 +        while read LINE ; do
     5216 +                [[ ${LINE:0:20} == 'nsslapd-instancedir=' ]] && LINE=${LINE:20} && break
     5217 +        done
     5218 +        if (( MAJOR < 6 )); then
     5219 +                # DSEE 5.x only. 
     5220 +                [[ ${LINE} =~ slapd- ]] && LINE=${LINE#*/} && INSTANCE=${LINE#*-}
     5221 +        else
     5222 +                # 6+ - the instance path
     5223 +                INSTANCE="${LINE}"
     5224 +        fi
     5225 +        [[ ${STR[LDAP_SEARCH_SCOPE]} == sub ]] && SCOPE=2
     5226 +        BACKEND="cn=${STR[DS_DB]},cn=ldbm database,cn=plugins,cn=config"
4888 5227  
4889      -    for ou in people group rpc protocols networks netgroup \
4890      -        aliases hosts services ethers profile printers projects \
4891      -        SolarisAuthAttr SolarisProfAttr Timezone ipTnet ; do
     5228 +    # create index entries
     5229 +    for ENTRY in "${INDEX_TABLE[@]}" ; do
     5230 +                typeset -a F=( ${ENTRY} )                                       # split columns
     5231 +                
     5232 +                IDX_NAME="${STR[LDAP_DOMAIN]}.get${F[0]}"
     5233 +                CN="${STR[LDAP_DOMAIN]}_${F[1]}_vlv_index"
     5234 +                BASE="ou=${F[2]},${STR[LDAP_BASEDN]}"
     5235 +                [[ ${F[2]} =~ = ]] && BASE="${BASE:3}"          # cut out ou=
     5236 +                FILTER="objectClass=${F[3]}"
     5237 +                [[ ${F[3]:0:1} == '&' ]] && FILTER="&(objectClass=${F[3]:2}"
4892 5238  
4893      -        # Check if nismaps already exist.
4894      -        eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"ou=${ou},${LDAP_BASEDN}\" -s base \"objectclass=*\" ${VERB}"
4895      -        if [ $? -eq 0 ]; then
4896      -            continue
4897      -        fi
     5239 +                if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -s base \
     5240 +                        -b "cn=${IDX_NAME},cn=${CN},${BACKEND}" 'objectclass=*' \
     5241 +                        > /dev/null 2>&1
     5242 +                then
     5243 +                        showProgress "'${IDX_NAME}' VLV index exists."
     5244 +                        continue
     5245 +                fi
4898 5246  
4899      -        # Create TMP file to add.
4900      -        ( cat <<EOF
4901      -dn: ou=${ou},${LDAP_BASEDN}
4902      -ou: ${ou}
     5247 +                nextFile add "${0}-${IDX_NAME}"
     5248 +                print '
     5249 +dn: '"cn=${CN},${BACKEND}"'
4903 5250  objectClass: top
4904      -objectClass: organizationalUnit
4905      -EOF
4906      -) > ${TMPDIR}/toplevel.${ou}
     5251 +objectClass: vlvSearch
     5252 +cn: '"${CN}"'
     5253 +vlvbase: '"${BASE}"'
     5254 +vlvscope: '${SCOPE}'
     5255 +vlvfilter: ('"${FILTER}"')
     5256 +aci: (target = "ldap:///'"cn=${CN},${BACKEND}"'") (targetattr = "*")
     5257 + (
     5258 +        version 3.0;  acl "Config";
     5259 +        allow (read,search,compare) userdn="ldap:///anyone";
     5260 + )
4907 5261  
4908      -        # Add the entry.
4909      -        ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/toplevel.${ou} ${VERB}"
4910      -        if [ $? -ne 0 ]; then
4911      -            ${ECHO} "  ERROR: Add of ou=${ou} container failed!"
4912      -            cleanup
4913      -            exit 1
4914      -        fi
4915      -    done
     5262 +dn: cn='"${IDX_NAME},cn=${CN},${BACKEND}"'
     5263 +cn: '"${IDX_NAME}"'
     5264 +vlvSort: cn uid
     5265 +objectclass: top
     5266 +objectclass: vlvIndex
     5267 +'               > ${TMP[FILE]}
4916 5268  
4917      -    # Display message that top level OU containers complete.
4918      -    ${ECHO} "  ${STEP}. Top level \"ou\" containers complete."
4919      -    STEP=`expr $STEP + 1`
     5269 +                if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
     5270 +                        >&${TMPF[FD]} 2>&1
     5271 +                then
     5272 +                        Log.fatal "Adding '${IDX_NAME}' VLV index failed"
     5273 +                        return 66
     5274 +                fi
     5275 +                showProgress "'${IDX_NAME}' VLV index added."
     5276 +
     5277 +                if (( MAJOR < 6 )); then
     5278 +                        # DSEE 5.x
     5279 +                        print "directoryserver -s '${INSTANCE}' vlvindex" \
     5280 +                                "-n '${STR[DS_DB]}' -T '${IDX_NAME}'" >> ${OUT}
     5281 +                else
     5282 +                        # assume DSEE 6+
     5283 +                        print "dsadm reindex -l -t '${IDX_NAME}'" \
     5284 +                                "'${INSTANCE}' '${STR[LDAP_SUFFIX]}'" >> ${OUT}
     5285 +                fi
     5286 +        done
4920 5287  }
4921 5288  
     5289 +Man.addFunc add_vlv_indexes '' '[+NAME?add_vlv_indexes - Add VLV indexes.]
     5290 +[+DESCRIPTION?Create VLV indexes entries on the \bSTR[DS_DB]]\b for \bSTR[LDAP_DOMAIN]]\b with \bSTR[LDAP_SEARCH_SCOPE]]\b and create the script \bTMP[DIR]]/do_vlv_index\b to be started on the DS to actually re-index the DB.]
     5291 +[+RETURN VALUES]{
     5292 +        [+0?on success.]
     5293 +        [+>= 66?fatal error.]
     5294 +}
     5295 +[+SEE ALSO?\bldapsearch\b(1), \bldapmodify\b(1).]
     5296 +'
     5297 +function add_vlv_indexes {
     5298 +    Log.verbose 'Processing VLV indexes ...'
4922 5299  
4923      -#
4924      -# add_auto_maps(): Add the automount map entries.
4925      -#
4926      -# auto_home, auto_direct, auto_master, auto_shared
4927      -#
4928      -add_auto_maps()
4929      -{
4930      -    [ $DEBUG -eq 1 ] && ${ECHO} "In add_auto_maps()"
     5300 +        #         F[0]                   F[1]             F[2]           F[3]
     5301 +        # ${LDAP_DOMAIN}.get ${LDAP_DOMAIN}_%s_vlv_index ou=%s objectClass=$1||&(%s)
     5302 +        typeset -a INDEXES=( 
     5303 +                'grent          group           group                   posixGroup'
     5304 +                'hostent        hosts           hosts                   ipHost'
     5305 +                'netent         networks        networks                ipNetwork'
     5306 +                'pwent          passwd          people                  posixAccount'
     5307 +                'rpcent         rpc                     rpc                             oncRpc'
     5308 +                'spent          shadow          people                  shadowAccount'
     5309 +                # Indexes added during NIS to LDAP transition
     5310 +                'auhoent        auho            automountMapName=auto_home      automount'
     5311 +                'soluent        solu            people                  SolarisUserAttr'
     5312 +                'authent        auth            SolarisAuthAttr SolarisAuthAttr'
     5313 +                'execent        exec            SolarisProfAttr &(SolarisExecAttr)(SolarisKernelSecurityPolicy=*)'
     5314 +                'profent        prof            SolarisProfAttr &(SolarisProfAttr)(SolarisAttrLongDesc=*)'
     5315 +                'mailent        mail            aliases                 mailGroup'
     5316 +                'bootent        _boot           ethers                  &(bootableDevice)(bootParameter=*)'
     5317 +                'ethent         ethers          ethers                  &(ieee802Device)(macAddress=*)'
     5318 +                'ngrpent        netgroup        netgroup                nisNetgroup'
     5319 +                'ipnent         ipn                     networks                &(ipNetwork)(cn=*)'
     5320 +                'maskent        mask            networks                &(ipNetwork)(ipNetmaskNumber=*)'
     5321 +                'prent          pr                      printers                printerService'
     5322 +                'ip4ent         ip4                     hosts                   &(ipHost)(ipHostNumber=*.*)'
     5323 +                'ip6ent         ip6                     hosts                   &(ipHost)(ipHostNumber=*:*)'
     5324 +        )
4931 5325  
4932      -    # Set AUTO_MAPS for maps to create.
4933      -    AUTO_MAPS="auto_home auto_direct auto_master auto_shared"
     5326 +    # temp file for vlvindex commands
     5327 +        typeset OUT=${TMP[DIR]}/tmp
     5328 +        rm -f ${OUT} && touch ${OUT}
4934 5329  
4935      -    for automap in $AUTO_MAPS; do
4936      -        # Check if automaps already exist.
4937      -        eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"automountMapName=${automap},${LDAP_BASEDN}\" -s base \"objectclass=*\" ${VERB}"
4938      -        if [ $? -eq 0 ]; then
4939      -            continue
     5330 +        if (( TMPF[IS_OPENDJ] )); then
     5331 +                add_vlv_indexes_OpenDJ INDEXES ${OUT}
     5332 +        else
     5333 +                add_vlv_indexes_DSEE INDEXES ${OUT}
4940 5334          fi
4941      -
4942      -        # Create the tmp file to add.
4943      -        ( cat <<EOF
4944      -dn: automountMapName=${automap},${LDAP_BASEDN}
4945      -automountMapName: ${automap}
4946      -objectClass: top
4947      -objectClass: automountMap
4948      -EOF
4949      -) > ${TMPDIR}/automap.${automap}
4950      -    
4951      -        # Add the entry.
4952      -        ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/automap.${automap} ${VERB}"
4953      -        if [ $? -ne 0 ]; then
4954      -            ${ECHO} "  ERROR: Add of automap ${automap} failed!"
4955      -            cleanup
4956      -            exit 1
4957      -        fi
4958      -    done
4959      -
4960      -    # Display message that automount entries are updated.
4961      -    ${ECHO} "  ${STEP}. automount maps: $AUTO_MAPS processed."
4962      -    STEP=`expr $STEP + 1`
     5335 +        nextFile sh
     5336 +        mv ${OUT} ${TMP[FILE]}
     5337 +        TMP[VLV_CMDS]=${TMP[FILE]}
4963 5338  }
4964 5339  
     5340 +Man.addFunc display_vlv_cmds '' '[+NAME?display_vlv_cmds - Display VLV index commands to run on server.]
     5341 +[+DESCRIPTION?Display VLV index commands to run on server and save the file to /var/tmp/doIndexVLV-\bSTR[DS_HOST]].sh\b.]
     5342 +'
     5343 +function display_vlv_cmds {
     5344 +        typeset SAV="/var/tmp/doIndexVLV-${STR[DS_HOST]}.sh"
4965 5345  
4966      -#
4967      -# add_proxyagent(): Add entry for nameservice to use to access server.
4968      -#
4969      -add_proxyagent()
4970      -{
4971      -    [ $DEBUG -eq 1 ] && ${ECHO} "In add_proxyagent()"
     5346 +        [[ -s ${TMP[VLV_CMDS]} ]] || return
     5347 +        # some problems occured, so the file is not empty
     5348 +        [[ -e ${SAV} ]] && SAV="${SAV%.sh}-$$.sh"
     5349 +        cp -p ${TMP[VLV_CMDS]} "${SAV}"
4972 5350  
4973      -    # Check if proxy agent already exists.
4974      -    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_PROXYAGENT}\" -s base \"objectclass=*\" ${VERB}"
4975      -    if [ $? -eq 0 ]; then
4976      -        ${ECHO} "  ${STEP}. Proxy Agent ${LDAP_PROXYAGENT} already exists."
4977      -        STEP=`expr $STEP + 1`   
4978      -        return 0
     5351 +        typeset MSG='NOTE: '"${PROG}"'configured the entries for VLV indexes.'
     5352 +        if (( TMPF[IS_OPENDJ] )); then
     5353 +                MSG+='
     5354 +To create the actual VLV indexes, you need to stop the DS on the host
     5355 +'"'${STR[DS_HOST]}'"', e.g. using "svcadm disable -t opendj@VERS@"
     5356 +or, if manually started, "ds-stop" and than run the commands shown in the file
     5357 +'"'${SAV}'"'.  Than restart the DS e.g. using
     5358 +"svcadm enable opendj@VERS@" or "ds-start".
     5359 +'
     5360 +        else
     5361 +                typeset INFO=( ${DS_INFO[@]} )
     5362 +                if (( INFO[1] >= 6 )); then
     5363 +                        MSG+='
     5364 +Use the dsadm command delivered with the DS on the host '"'${STR[DS_HOST]}'"'
     5365 +to stop the server.  Then, using dsadm, follow the dsadm examples shown in the
     5366 +file '"'${SAV}'"' to create the actual VLV indexes.
     5367 +'
     5368 +                else
     5369 +                        MSG+='
     5370 +Use the directoryserver(1m) script on the host '"'${STR[DS_HOST]}'"'
     5371 +to stop the server.  Then, using directoryserver, follow the directoryserver
     5372 +examples shown in the file '"'${SAV}'"' to create the
     5373 +actual VLV indexes.
     5374 +'
     5375 +                fi
4979 5376      fi
4980      -
4981      -    # Get cn and sn names from LDAP_PROXYAGENT.
4982      -    cn_tmp=`${ECHO} ${LDAP_PROXYAGENT} | cut -f1 -d, | cut -f2 -d=`
4983      -
4984      -    # Create the tmp file to add.
4985      -    ( cat <<EOF
4986      -dn: ${LDAP_PROXYAGENT}
4987      -cn: ${cn_tmp}
4988      -sn: ${cn_tmp}
4989      -objectclass: top
4990      -objectclass: person
4991      -userpassword: ${LDAP_PROXYAGENT_CRED}
4992      -EOF
4993      -) > ${TMPDIR}/proxyagent
4994      -    
4995      -    # Add the entry.
4996      -    ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/proxyagent ${VERB}"
4997      -    if [ $? -ne 0 ]; then
4998      -        ${ECHO} "  ERROR: Adding proxyagent failed!"
4999      -        cleanup
5000      -        exit 1
5001      -    fi
5002      -
5003      -    # Display message that schema is updated.
5004      -    ${ECHO} "  ${STEP}. Proxy Agent ${LDAP_PROXYAGENT} added."
5005      -    STEP=`expr $STEP + 1`
     5377 +        Log.info "\n\n${MSG}"
5006 5378  }
5007 5379  
5008      -#
5009      -# allow_proxy_read_pw(): Give Proxy Agent read permission for password.
5010      -#
5011      -allow_proxy_read_pw()
5012      -{
5013      -    [ $DEBUG -eq 1 ] && ${ECHO} "In allow_proxy_read_pw()"
     5380 +Man.addFunc doMain '' '[+NAME?doMain - the main entry point.]
     5381 +[+DESCRIPTION?The entry point, where the real work starts.]
     5382 +'
     5383 +function doMain {
     5384 +        # Initialize the variables that need to be set to NULL, or some 
     5385 +        # other initial value before the rest of the functions can be called
     5386 +        init || return 1
     5387 +        show_vars
5014 5388  
5015      -    # Search for ACI_NAME
5016      -    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_proxyread_aci 2>&1"
5017      -    ${GREP} "${PROXY_ACI_NAME}" ${TMPDIR}/chk_proxyread_aci > /dev/null 2>&1
5018      -    if [ $? -eq 0 ]; then
5019      -        ${ECHO} "  ${STEP}. Proxy ACI ${PROXY_ACI_NAME=} already exists for ${LDAP_BASEDN}."
5020      -        STEP=`expr $STEP + 1`
5021      -        return 0
5022      -    fi
     5389 +        # Print extra line to separate from prompt
     5390 +        print
5023 5391  
5024      -    # Create the tmp file to add.
5025      -    ( cat <<EOF
5026      -dn: ${LDAP_BASEDN}
5027      -changetype: modify
5028      -add: aci
5029      -aci: (target="ldap:///${LDAP_BASEDN}")(targetattr="userPassword")
5030      -  (version 3.0; acl ${PROXY_ACI_NAME}; allow (compare,read,search)
5031      -  userdn = "ldap:///${LDAP_PROXYAGENT}";)
5032      -EOF
5033      -) > ${TMPDIR}/proxy_read
5034      -    
5035      -    # Add the entry.
5036      -    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/proxy_read ${VERB}"
5037      -    if [ $? -ne 0 ]; then
5038      -        ${ECHO} "  ERROR: Allow ${LDAP_PROXYAGENT} to read password failed!"
5039      -        cleanup
5040      -        exit 1
5041      -    fi
     5392 +        # Either load the user specified config file or prompt user for config info
     5393 +        if [[ -n ${TMP[IN]} ]]; then 
     5394 +                load_config_file "${TMP[IN]}"
     5395 +                validate_info || return 1       # Validate basic info in file
     5396 +        else
     5397 +                display_msg 'backup_server'
     5398 +                get_confirm 'Do you wish to continue with server setup (y/n/h)?' \
     5399 +                        'n' 'backup_help' && return 1
5042 5400  
5043      -    # Display message that schema is updated.
5044      -    ${ECHO} "  ${STEP}. Give ${LDAP_PROXYAGENT} read permission for password."
5045      -    STEP=`expr $STEP + 1`
5046      -}
     5401 +                # Ask for all required infos
     5402 +                prompt_config_info || return 1
     5403 +                (( INT[LDAP_ENABLE_SHADOW_UPDATE] && INT[EXISTING_PROFILE] )) && \
     5404 +                        return 0        # just enabled shadow update in an existing profile
     5405 +                # Allow user to modify results
     5406 +                integer RES
     5407 +                display_summary
     5408 +                RES=$?
     5409 +                # save the work for now, so that even on exit/errors it can be re-used
     5410 +                [[ -n ${TMP[OUT]} ]] && create_config_file "${TMP[OUT]}"
     5411 +                (( RES )) && return 1
     5412 +        fi
5047 5413  
5048      -#  Delete Proxy Agent read permission for password.
5049      -delete_proxy_read_pw()
5050      -{
5051      -    [ $DEBUG -eq 1 ] && ${ECHO} "In delete_proxy_read_pw()"
     5414 +        if (( INT[NEED_TIME] )); then
     5415 +                modify_timelimit || return 1
     5416 +        fi
5052 5417  
5053      -    # Search for ACI_NAME
5054      -    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_proxyread_aci 2>&1"
5055      -    ${GREP} "${PROXY_ACI_NAME}" ${TMPDIR}/chk_proxyread_aci | \
5056      -        ${SED} -e 's/aci=//' > ${TMPDIR}/grep_proxyread_aci 2>&1
5057      -    if [ $? -ne 0 ]; then
5058      -        ${ECHO} "Proxy ACI ${PROXY_ACI_NAME} does not exist for ${LDAP_BASEDN}."
5059      -        return 0
5060      -    fi
     5418 +        if (( INT[NEED_SIZE] )); then
     5419 +                modify_sizelimit || return 1
     5420 +        fi
5061 5421  
5062      -    # We need to remove proxy agent's read access to user passwords,
5063      -    # but We do not know the value of the ${LDAP_PROXYAGENT} here, so
5064      -    # 1. if only one match found, delete it
5065      -    # 2. if more than one matches found, ask the user which one to delete
5066      -    HOWMANY=`${WC} -l ${TMPDIR}/grep_proxyread_aci | ${NAWK} '{print $1}'`
5067      -    if [ $HOWMANY -eq 0 ]; then
5068      -        ${ECHO} "Proxy ACI ${PROXY_ACI_NAME} does not exist for ${LDAP_BASEDN}."
5069      -        return 0
5070      -    fi
5071      -    if [ $HOWMANY -eq 1 ];then
5072      -        proxy_aci=`${CAT} ${TMPDIR}/grep_proxyread_aci`
5073      -    else
5074      -            ${CAT} << EOF
     5422 +        # Modify the password storage scheme to support CRYPT
     5423 +        if (( INT[NEED_CRYPT] )); then
     5424 +                modify_pwd_crypt || return 1
     5425 +        fi
5075 5426  
5076      -Proxy agent is not allowed to read user passwords when shadow
5077      -update is enabled. There are more than one proxy agents found.
5078      -Please select the currently proxy agent being used, so that
5079      -idsconfig can remove its read access to user passwords.
     5427 +        # schema modifications
     5428 +        modify_cn || return 1
     5429 +        update_schema_attr || return 1
     5430 +        update_schema_obj || return 1
5080 5431  
5081      -The proxy agents are:
     5432 +        add_suffix || return 1
5082 5433  
5083      -EOF
5084      -            # generate the proxy agent list
5085      -            ${SED} -e "s/.*ldap:\/\/\/.*ldap:\/\/\///" \
5086      -            ${TMPDIR}/grep_proxyread_aci | ${SED} -e "s/\";)//" > \
5087      -                ${TMPDIR}/proxy_agent_list
     5434 +        # Add missing suffix ACIs
     5435 +        add_suffix_aci || return 1
5088 5436  
5089      -            # print the proxy agent list
5090      -            ${NAWK} '{print NR ": " $0}' ${TMPDIR}/proxy_agent_list
     5437 +        # Add base objects (if needed)
     5438 +        add_base_objects || return 1
5091 5439  
5092      -            # ask the user to pick one
5093      -            _MENU_PROMPT="Select the proxy agent (1-$HOWMANY): "
5094      -            get_menu_choice "${_MENU_PROMPT}" "0" "$HOWMANY"
5095      -            _CH=$MN_CH
5096      -            proxy_aci=`${SED} -n "$_CH p" ${TMPDIR}/grep_proxyread_aci`
5097      -    fi
     5440 +        # Update the NisDomainObject.  
     5441 +        #   The Base DN might of just been created, so this MUST happen after
     5442 +        #   the base objects have been added!
     5443 +        set_nisdomain || return 1
5098 5444  
5099      -    # Create the tmp file to delete the ACI.
5100      -    ( cat <<EOF
5101      -dn: ${LDAP_BASEDN}
5102      -changetype: modify
5103      -delete: aci
5104      -aci: ${proxy_aci}
5105      -EOF
5106      -    ) > ${TMPDIR}/proxy_delete
     5445 +        # Add top level classes (new containers)
     5446 +        add_new_containers || return 1
5107 5447  
5108      -    # Delete the ACI
5109      -    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/proxy_delete ${VERB}"
5110      -    if [ $? -ne 0 ]; then
5111      -        ${ECHO} "  ERROR: Remove of ${PROXY_ACI_NAME} ACI failed!"
5112      -        cat ${TMPDIR}/proxy_delete
5113      -        cleanup
5114      -        exit 1
5115      -    fi
     5448 +        add_auto_maps || return 1
5116 5449  
5117      -    # Display message that ACI is updated.
5118      -    MSG="Removed ${PROXY_ACI_NAME} ACI for proxyagent read permission for password."
5119      -    ${ECHO} " "
5120      -    ${ECHO} "  ACI REMOVED: $MSG"
5121      -    ${ECHO} "  The ACI removed is $proxy_aci"
5122      -    ${ECHO} " "
5123      -}
     5450 +        modify_top_aci || return 1
5124 5451  
5125      -#
5126      -# add_profile(): Add client profile to server.
5127      -#
5128      -add_profile()
5129      -{
5130      -    [ $DEBUG -eq 1 ] && ${ECHO} "In add_profile()"
     5452 +        add_vlv_aci || return 1
5131 5453  
5132      -    # If profile name already exists, DELETE it, and add new one.
5133      -    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${LDAP_PROFILE_NAME},ou=profile,${LDAP_BASEDN}\" -s base \"objectclass=*\" ${VERB}"
5134      -    if [ $? -eq 0 ]; then
5135      -        # Create Delete file.
5136      -        ( cat <<EOF
5137      -cn=${LDAP_PROFILE_NAME},ou=profile,${LDAP_BASEDN}
5138      -EOF
5139      -) > ${TMPDIR}/del_profile
     5454 +        if (( INT[NEED_PROXY] )); then
     5455 +                add_proxyagent || return 1
     5456 +                if (( ! INT[LDAP_ENABLE_SHADOW_UPDATE] )); then
     5457 +                        allow_proxy_read_pw || return 1
     5458 +                fi
     5459 +        fi
5140 5460  
5141      -        # Check if DEL_OLD_PROFILE is set.  (If not ERROR)
5142      -        if [ $DEL_OLD_PROFILE -eq 0 ]; then
5143      -            ${ECHO} "ERROR: Profile name ${LDAP_PROFILE_NAME} exists! Add failed!"
5144      -            exit 1
     5461 +        if (( INT[NEED_ADMIN] )); then
     5462 +                add_admin || return 1
     5463 +                allow_admin_read_write_shadow || return 1
     5464 +                deny_non_admin_shadow_access || return 1
5145 5465          fi
5146 5466  
5147      -        # Delete the OLD profile.
5148      -        ${EVAL} "${LDAPDELETE} ${LDAP_ARGS} -f ${TMPDIR}/del_profile ${VERB}"
5149      -        if [ $? -ne 0 ]; then
5150      -            ${ECHO} "  ERROR: Attempt to DELETE profile failed!"
5151      -            cleanup
5152      -            exit 1
     5467 +        if (( INT[GSSAPI_ENABLE] )); then
     5468 +                add_id_mapping_rules
     5469 +                # do not modify ACI if "sasl/GSSAPI" and "self" are not selected
     5470 +                if [[ ${STR[LDAP_CRED_LEVEL]} == 'self' && \
     5471 +                        ${STR[LDAP_AUTHMETHOD]} == 'sasl/GSSAPI' ]]
     5472 +                then
     5473 +                        modify_userpassword_acl_for_gssapi || return 1
     5474 +                else
     5475 +                        Log.warn 'ACL for GSSAPI was not set because of  incompatibility' \
     5476 +                                'in profile'
     5477 +                fi
5153 5478          fi
5154      -    fi
5155 5479  
5156      -    # Build the "ldapclient genprofile" command string to execute.
5157      -    GEN_CMD="ldapclient genprofile -a \"profileName=${LDAP_PROFILE_NAME}\""
     5480 +        if (( INT[NEED_HOSTACL] )); then
     5481 +                allow_host_read_write_shadow || return 66
     5482 +                deny_non_host_shadow_access || return 67
     5483 +        fi
5158 5484  
5159      -    # Add required argument defaultSearchBase.
5160      -    GEN_CMD="${GEN_CMD} -a \"defaultSearchBase=${LDAP_BASEDN}\""
5161 5485  
5162      -    # Add optional parameters.
5163      -    [ -n "$LDAP_SERVER_LIST" ] && \
5164      -        GEN_CMD="${GEN_CMD} -a \"defaultServerList=${LDAP_SERVER_LIST}\""
5165      -    [ -n "$LDAP_SEARCH_SCOPE" ] && \
5166      -        GEN_CMD="${GEN_CMD} -a \"defaultSearchScope=${LDAP_SEARCH_SCOPE}\""
5167      -    [ -n "$LDAP_CRED_LEVEL" ] && \
5168      -        GEN_CMD="${GEN_CMD} -a \"credentialLevel=${LDAP_CRED_LEVEL}\""
5169      -    [ -n "$LDAP_AUTHMETHOD" ] && \
5170      -        GEN_CMD="${GEN_CMD} -a \"authenticationMethod=${LDAP_AUTHMETHOD}\""
5171      -    [ -n "$LDAP_FOLLOWREF" ] && \
5172      -        GEN_CMD="${GEN_CMD} -a \"followReferrals=${LDAP_FOLLOWREF}\""
5173      -    [ -n "$LDAP_SEARCH_TIME_LIMIT" ] && \
5174      -        GEN_CMD="${GEN_CMD} -a \"searchTimeLimit=${LDAP_SEARCH_TIME_LIMIT}\""
5175      -    [ -n "$LDAP_PROFILE_TTL" ] && \
5176      -        GEN_CMD="${GEN_CMD} -a \"profileTTL=${LDAP_PROFILE_TTL}\""
5177      -    [ -n "$LDAP_BIND_LIMIT" ] && \
5178      -        GEN_CMD="${GEN_CMD} -a \"bindTimeLimit=${LDAP_BIND_LIMIT}\""
5179      -    [ -n "$LDAP_PREF_SRVLIST" ] && \
5180      -        GEN_CMD="${GEN_CMD} -a \"preferredServerList=${LDAP_PREF_SRVLIST}\""
5181      -    [ -n "$LDAP_SRV_AUTHMETHOD_PAM" ] && \
5182      -        GEN_CMD="${GEN_CMD} -a \"serviceAuthenticationMethod=${LDAP_SRV_AUTHMETHOD_PAM}\""
5183      -    [ -n "$LDAP_SRV_AUTHMETHOD_KEY" ] && \
5184      -        GEN_CMD="${GEN_CMD} -a \"serviceAuthenticationMethod=${LDAP_SRV_AUTHMETHOD_KEY}\""
5185      -    [ -n "$LDAP_SRV_AUTHMETHOD_CMD" ] && \
5186      -        GEN_CMD="${GEN_CMD} -a \"serviceAuthenticationMethod=${LDAP_SRV_AUTHMETHOD_CMD}\""
     5486 +        # Generate client profile and add it to the server
     5487 +        add_profile || return 1
5187 5488  
5188      -    # Check if there are any service search descriptors to ad.
5189      -    if [ -s "${SSD_FILE}" ]; then
5190      -        ssd_2_profile
5191      -    fi
     5489 +        # Add Indexes to improve search performance
     5490 +        add_eq_indexes || return 1
     5491 +        add_sub_indexes || return 1
     5492 +        add_vlv_indexes || return 1
5192 5493  
5193      -    # Execute "ldapclient genprofile" to create profile.
5194      -    eval ${GEN_CMD} > ${TMPDIR}/gen_profile 2> ${TMPDIR}/gen_profile_ERR
5195      -    if [ $? -ne 0 ]; then
5196      -        ${ECHO} "  ERROR: ldapclient genprofile failed!"
5197      -        cleanup
5198      -        exit 1
5199      -    fi
     5494 +        # Display setup complete message
     5495 +        Log.printMarker
     5496 +        Log.info 'Setup of DS server' "'${STR[DS_HOST]}'" 'is complete.'
     5497 +        Log.printMarker
5200 5498  
5201      -    # Add the generated profile..
5202      -    ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/gen_profile ${VERB}"
5203      -    if [ $? -ne 0 ]; then
5204      -        ${ECHO} "  ERROR: Attempt to add profile failed!"
5205      -        cleanup
5206      -        exit 1
5207      -    fi
     5499 +        # Display VLV index commands to be executed on server (if any)
     5500 +        display_vlv_cmds
5208 5501  
5209      -    # Display message that schema is updated.
5210      -    ${ECHO} "  ${STEP}. Generated client profile and loaded on server."
5211      -    STEP=`expr $STEP + 1`
     5502 +        # Create final config file if requested
     5503 +        [[ -n ${TMP[OUT]} ]] && create_config_file "${TMP[OUT]}"
     5504 +        return 0
5212 5505  }
5213 5506  
     5507 +Man.addFunc cleanup '' '[+NAME?cleanup - cleanup tempfiles, tty and exit.]
     5508 +[+DESCRIPTION?Removes \aTMP[DIR]]\a unless \aTMPF[DEBUG]]\a is set and restores the echo for the tty.]
     5509 +[+ENVIRONMENT VARIABLES]{' "${ Man.varUsage TMP TMPF ; }" '}
     5510 +'
     5511 +function cleanup {
     5512 +        (( TMPF[CLEANUP_DONE] )) && return
     5513 +        if (( TMPF[DEBUG] )); then
     5514 +                typeset X=${ ls -1 ${TMP[DIR]} 2>/dev/null ; }
     5515 +                if [[ -z $X || $X == 'rootPWD' ]]; then
     5516 +                        rm -rf ${TMP[DIR]}
     5517 +                else
     5518 +                        Log.info "Leaving temp dir ${TMP[DIR]} as is. Remove it manually"
     5519 +                fi
     5520 +        elif (( TMPF[KEEP] )); then
     5521 +                typeset X=${ ls -1 ${TMP[DIR]} 2>/dev/null ; }
     5522 +                if [[ -z $X || $X == 'rootPWD' ]]; then
     5523 +                        rm -rf ${TMP[DIR]}
     5524 +                else
     5525 +                        Log.info "Keeping setup scripts and files in ${TMP[DIR]}"
     5526 +                fi
     5527 +        elif [[ -d ${TMP[DIR]} ]]; then
     5528 +                rm -rf ${TMP[DIR]}
     5529 +        fi
     5530 +        ${STTY:-/usr/bin/stty} echo
     5531 +        trap - EXIT 1 2 3 6 15
     5532 +        # Might be trapped in the scope of a function which will stop executing
     5533 +        # the function itself but not the script. So:
     5534 +        [[ -z $1 ]] && kill $$
     5535 +        TMPF[CLEANUP_DONE]=1
     5536 +}
5214 5537  
5215      -#
5216      -# cleanup(): Remove the TMPDIR and all files in it.
5217      -#
5218      -cleanup()
5219      -{
5220      -    [ $DEBUG -eq 1 ] && ${ECHO} "In cleanup()"
5221      -
5222      -    rm -fr ${TMPDIR}
     5538 +# debug helper function. Required to be not a 'function'!
     5539 +showCommand() {
     5540 +        typeset CMD="${.sh.command}"
     5541 +        [[ -z ${CMD} ]] && return
     5542 +        print -n -u2 '\E[0;30;47m'
     5543 +        print -u2 -r -n "DEBUG: ${.sh.fun} '${CMD}'"
     5544 +        print '\E[0m'
5223 5545  }
5224 5546  
5225      -
5226      -#
5227      -#                       * * * MAIN * * *
5228      -#
5229      -# Description:
5230      -# This script assumes that the iPlanet Directory Server (iDS) is 
5231      -# installed and that setup has been run.  This script takes the 
5232      -# iDS server from that point and sets up the infrastructure for
5233      -# LDAP Naming Services.  After running this script, ldapaddent(1M)
5234      -# or some other tools can be used to populate data.
5235      -
5236      -# Initialize the variables that need to be set to NULL, or some 
5237      -# other initial value before the rest of the functions can be called.
5238      -init
5239      -
5240      -# Parse command line arguments.  
5241      -parse_arg $*
5242      -shift $?
5243      -
5244      -# Print extra line to separate from prompt.
5245      -${ECHO} " "
5246      -
5247      -# Either Load the user specified config file 
5248      -# or prompt user for config info.
5249      -if [ -n "$INPUT_FILE" ]
5250      -then 
5251      -    load_config_file
5252      -    INTERACTIVE=0      # Turns off prompts that occur later.
5253      -    validate_info      # Validate basic info in file.
5254      -    chk_ids_version    # Check iDS version for compatibility.
5255      -else
5256      -    # Display BACKUP warning to user.
5257      -    display_msg backup_server
5258      -    get_confirm "Do you wish to continue with server setup (y/n/h)?" "n" "backup_help"
5259      -    if [ $? -eq 0 ]; then    # if No, cleanup and exit.
5260      -        cleanup ; exit 1
5261      -    fi
5262      -
5263      -    # Prompt for values.
5264      -    prompt_config_info
5265      -    display_summary    # Allow user to modify results.
5266      -    INTERACTIVE=1      # Insures future prompting.
5267      -fi
5268      -
5269      -# Modify slapd.oc.conf to ALLOW cn instead of REQUIRE.
5270      -modify_cn
5271      -
5272      -# Modify timelimit to user value.
5273      -[ $NEED_TIME -eq 1 ] && modify_timelimit
5274      -
5275      -# Modify sizelimit to user value.
5276      -[ $NEED_SIZE -eq 1 ] && modify_sizelimit
5277      -
5278      -# Modify the password storage scheme to support CRYPT.
5279      -if [ "$NEED_CRYPT" = "TRUE" ]; then
5280      -    modify_pwd_crypt
5281      -fi
5282      -
5283      -# Update the schema (Attributes, Objectclass Definitions)
5284      -if [ ${SCHEMA_UPDATED} -eq 0 ]; then
5285      -        update_schema_attr
5286      -        update_schema_obj
5287      -fi
5288      -
5289      -# Add suffix together with its root entry (if needed)
5290      -add_suffix ||
5291      -{
5292      -        cleanup
5293      -        exit 1
     5547 +Man.addFunc MAIN '' '[+NAME?'"${PROG}"' - setup the infrastructure of a directory server to provide data and security required by the Solaris (or similar OS) LDAP Naming Services.]
     5548 +[+DESCRIPTION?This script assumes that the Sun/Oracle Directory Server Enterprise Edition (DSEE), or Sun OpenDS or Forgerock OpenDJ is installed and that its setup has been run.  This script takes the directory server from that point and sets up the infrastructure for LDAP Naming Services.  After running this script, \bldapaddent\b(1M) or some other tools can be used to populate data.]
     5549 +[h:help?Print this help and exit.]
     5550 +[F:functions?Print out a list of names of all currently defined script functions and exit (see \btypeset +f\b).]
     5551 +[H:usage]:[function?Show the usage info for the function with the given name if available and exit. (see also option \b-F\b).]
     5552 +[T:trace]:[fname_list?A comma or whitespace separated list of function names, which should be traced when running this script. If the list consist of the single word "ALL" or "*" all known functions get traced. "MAIN" is the special word to enable the trace of the main script. Gets activated as soon as this option gets processed, so option order might be important.]
     5553 +[d:debug?Enable really verbose debug info.]
     5554 +[C:no-color?Do not use ANSI escape codes to color the output.]
     5555 +[k:keep?Keep the files used to modify the DS. Files are enumerated and prefixed with the command to use for executing it so that one is able to do the same manually what this script did and thus may help to fine tune the setup of your DS. Actually it is recommended to run this script against a virgin DS and than re-use/adjust everything you need on your production system.]
     5556 +[I:importpwp?If specified, the storage scheme for Password Policy Import will be changed in the same way as the storage scheme for the Default Password Policy. If not specified, the storage scheme for Password Policy Import stays untouched. This option gets ignored for non-OpenDS/OpenDJ directory servers.]
     5557 +[i:in]:[file?Get setup info from the given file.]
     5558 +[o:out]:[file?Generate a server configuration output file.]
     5559 +[s:djSyntax?If given, the OpenDJ schema defintions will be used to complement the servers schema if needed, no matter which kind of server has been detected.]
     5560 +[S:eeSyntax?If given, the Sun DSEE schema defintions will be used to complement the servers schema if needed, no matter which kind of server has been detected. 
     5561 +Wrt. Solaris it should not make a difference, whether OpenDJ or DSEE syntax is used. OpenDJ syntax is usually a little bit more precise.]
     5562 +[t:timeout]:[seconds:=60?When this script creates an index, it also schedules a task to rebuild the index immediately. The \atimeout\a specifies, how long to wait for task completion. If the task gets not finished within the given time, the script treats that as an error and continues its work.]
     5563 +[v:verbose?Verbose mode - makes the script a little bit more chatty.]
     5564 +[+NOTES?This script should work for the following DS:]{
     5565 +        [+?Sun DS 5.x]
     5566 +        [+?Sun DSEE 6.x/7.x]
     5567 +        [+?Oracle ODSEE 11g]
     5568 +        [+?Sun OpenDS 2.x]
     5569 +        [+?Forgerock OpenDJ 2.x]
5294 5570  }
     5571 +'
5295 5572  
5296      -# Add base objects (if needed)
5297      -add_base_objects
     5573 +TMPF[DEBUG]=0 TMPF[KEEP]=0 TMPF[FD]=4
5298 5574  
5299      -# Update the NisDomainObject.  
5300      -#   The Base DN might of just been created, so this MUST happen after
5301      -#   the base objects have been added!
5302      -set_nisdomain
     5575 +X="${ print ${Man.FUNC[MAIN]} ; }"
     5576 +while getopts "${X}" option ; do
     5577 +        case "${option}" in
     5578 +                '?'|h)  showUsage ${PROG} MAIN ; exit 0 ;;
     5579 +                F) typeset +f ; exit 0 ;;
     5580 +                T)      if [[ ${OPTARG} == '*' || ${OPTARG} == 'ALL' ]]; then
     5581 +                                typeset -ft ${ typeset +f ; }
     5582 +                        elif [[ ${OPTARG} == 'MAIN' ]]; then
     5583 +                                set -x
     5584 +                        else
     5585 +                                typeset -ft ${OPTARG//,/ }
     5586 +                        fi
     5587 +                        ;;
     5588 +                H)  if [[ ${OPTARG%_t} != $OPTARG ]]; then
     5589 +                                $OPTARG --man   # self-defined types
     5590 +                        else
     5591 +                                showUsage "$OPTARG" "$OPTARG"   # functions
     5592 +                        fi
     5593 +                        exit 0
     5594 +                        ;;
     5595 +                C)      Log.COLORED=0 ;;
     5596 +                d)      TMPF[DEBUG]=1 ;;
     5597 +                k)      TMPF[KEEP]=1 ;;
     5598 +                I)      INT[NEED_CRYPT_IMPORT]=1 ;;
     5599 +                i)      TMP[IN]="${OPTARG}" ;;
     5600 +                o)      TMP[OUT]="${OPTARG}" ;;
     5601 +                S)      TMPF[SYNTAX]=2 ; print DSEE ;;
     5602 +                s)      TMPF[SYNTAX]=1 ; print DJ ;;
     5603 +                t)      is_numeric "${OPTARG}" && INT[TASK_TIMEOUT]=${OPTARG} ;;
     5604 +                v)      Log.VERBOSE=1 ; TMPF[FD]=1 ;;
     5605 +            *)  Log.fatal '**Internal ERROR: Supported option missing handler'
     5606 +                        exit 1
     5607 +                        ;;
     5608 +        esac
     5609 +done
     5610 +X=$(( OPTIND - 1 ))
     5611 +shift $X
     5612 +(( TMPF[DEBUG] )) && Man.listVars
5303 5613  
5304      -# Add top level classes (new containers)
5305      -add_new_containers
     5614 +unset LC_ALL LC_LANG
     5615 +export LC_CTYPE=C       # avoid any surprises
5306 5616  
5307      -# Add common nismaps.
5308      -add_auto_maps
5309      -
5310      -# Modify top ACI.
5311      -modify_top_aci
5312      -
5313      -# Add Access Control Information for VLV.
5314      -add_vlv_aci
5315      -
5316      -# if Proxy needed, Add Proxy Agent and give read permission for password.
5317      -if [ $NEED_PROXY -eq 1 ]; then
5318      -    add_proxyagent
5319      -    if [ "$LDAP_ENABLE_SHADOW_UPDATE" != "TRUE" ]; then
5320      -        allow_proxy_read_pw
5321      -    fi
     5617 +# Create TMP[DIR]
     5618 +TMP[DIR]=${ mktemp -d /tmp/${PROG}.XXXXX ; }
     5619 +if [[ -z ${TMP[DIR]} ]]; then
     5620 +        Log.fatal 'Unable to create a safe temporary directory'
     5621 +        exit 1
5322 5622  fi
5323      -
5324      -# If admin needed for shadow update, Add the administrator identity and
5325      -# give read/write permission for shadow, and deny all others read/write
5326      -# access to it.
5327      -if [ $NEED_ADMIN -eq 1 ]; then
5328      -    add_admin
5329      -    allow_admin_read_write_shadow
5330      -    # deny non-admin access to shadow data
5331      -    deny_non_admin_shadow_access
     5623 +trap cleanup EXIT 1 2 3 6 15            # and register to cleanup on exit/signal
     5624 +if (( TMPF[DEBUG] )); then
     5625 +        trap 'typeset _CMD_="${.sh.command}"
     5626 +        print -u2 -n "\E[0;30;47m"
     5627 +        print -u2 -n -r "${.sh.fun:-MAIN}(): ${_CMD_}"
     5628 +        print -u2 "\E[0m"
     5629 +        ' TMPF[DEBUG]
5332 5630  fi
5333 5631  
5334      -if [ $GSSAPI_ENABLE -eq 1 ]; then
5335      -    add_id_mapping_rules
5336      -    # do not modify ACI if "sasl/GSSAPI" and "self" are not selected
5337      -    if [ "$LDAP_CRED_LEVEL" = "self" -a "$LDAP_AUTHMETHOD" = "sasl/GSSAPI" ]; then
5338      -        modify_userpassword_acl_for_gssapi
5339      -    else
5340      -        ${ECHO} "  ACL for GSSAPI was not set because of incompatibility in profile."
5341      -    fi
5342      -fi
     5632 +# Prevent new files from being read by group or others
     5633 +umask 077
5343 5634  
5344      -# If use host principal for shadow update, give read/write permission for
5345      -# shadow, and deny all others' read/write access to it.
5346      -if [ $NEED_HOSTACL -eq 1 ]; then
5347      -    allow_host_read_write_shadow
5348      -    # deny non-host access to shadow data
5349      -    deny_non_host_shadow_access
5350      -fi
     5635 +doMain
     5636 +X=$?
5351 5637  
     5638 +cleanup NOKILL
5352 5639  
5353      -# Generate client profile and add it to the server.
5354      -add_profile
     5640 +exit ${X}
5355 5641  
5356      -# Add Indexes to improve Search Performance.
5357      -add_eq_indexes
5358      -add_sub_indexes
5359      -add_vlv_indexes
5360      -
5361      -# Display setup complete message
5362      -display_msg setup_complete
5363      -
5364      -# Display VLV index commands to be executed on server.
5365      -display_vlv_cmds
5366      -
5367      -# Create config file if requested.
5368      -[ -n "$OUTPUT_FILE" ] && create_config_file
5369      -
5370      -# Removed the TMPDIR and all files in it.
5371      -cleanup
5372      -
5373      -exit 0
5374      -# end of MAIN.
     5642 +# vim:ts=4 filetype=sh
     5643 +# :syntax sync fromstart
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX