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
   1 #!/bin/sh
   2 #


   3 # CDDL HEADER START
   4 #
   5 # The contents of this file are subject to the terms of the
   6 # Common Development and Distribution License (the "License").
   7 # You may not use this file except in compliance with the License.
   8 #
   9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10 # or http://www.opensolaris.org/os/licensing.
  11 # See the License for the specific language governing permissions
  12 # and limitations under the License.
  13 #
  14 # When distributing Covered Code, include this CDDL HEADER in each
  15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16 # If applicable, add the following below this CDDL HEADER, with the
  17 # fields enclosed by brackets "[]" replaced with your own identifying
  18 # information: Portions Copyright [yyyy] [name of copyright owner]
  19 #
  20 # CDDL HEADER END
  21 #
  22 #
  23 # idsconfig -- script to setup iDS 5.x/6.x/7.x for Native LDAP II.
  24 #
  25 # Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
  26 #
  27 
  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 
  45 Hit Ctrl-C at any time before the final confirmation to exit.






  46 
  47 EOF
  48     ;;
  49     setup_complete) cat <<EOF
  50 
  51 $PROG: Setup of iDS server ${IDS_SERVER} is complete.





  52 
  53 EOF
  54     ;;
  55     display_vlv_list) cat <<EOF






  56 
  57 Note: idsconfig has created entries for VLV indexes. 



















  58 
  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.
































  62 
  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.









  66 
  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
 103 
 104   Q  Exit menu
 105 EOF
 106     ;;
 107     summary_menu)
 108 
 109         SUFFIX_INFO=
 110         DB_INFO=


 111 
 112         [ -n "${NEED_CREATE_SUFFIX}" ] &&
 113         {
 114                 SUFFIX_INFO=`cat <<EOF

 115 
 116          Suffix to create          : $LDAP_SUFFIX
 117 EOF
 118 `
 119                 [ -n "${NEED_CREATE_BACKEND}" ] &&
 120                         DB_INFO=`cat <<EOF
 121 
 122          Database to create        : $IDS_DATABASE
 123 EOF
 124 `
 125         }
 126 
 127         cat <<EOF
 128               Summary of Configuration
 129 
 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
 150 
 151 EOF
 152     ;;
 153     sfx_not_suitable) cat <<EOF
 154 
 155 Sorry, suffix ${LDAP_SUFFIX} is not suitable for Base DN ${LDAP_BASEDN}

 156 
 157 EOF
 158     ;;
 159     obj_not_found) cat <<EOF
 160 
 161 Sorry, ${PROG} can't find an objectclass for "$_ATT" attribute

 162 
 163 EOF
 164     ;;
 165     sfx_config_incons) cat <<EOF
 166 
 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

 170 
 171 EOF
 172     ;;
 173     ldbm_db_exist) cat <<EOF



 174 
 175 Database "${IDS_DATABASE}" already exists,
 176 however "${IDS_DATABASE_AVAIL}" name is available
 177 
 178 EOF
 179     ;;
 180     unable_find_db_name) cat <<EOF
 181     
 182 Unable to find any available database name close to "${IDS_DATABASE}"

 183 
 184 EOF
 185     ;;
 186     create_ldbm_db_error) cat <<EOF


 187 
 188 ERROR: unable to create suffix ${LDAP_SUFFIX}
 189        due to server error that occurred during creation of ldbm database
 190 
 191 EOF
 192     ;;
 193     create_suffix_entry_error) cat <<EOF

 194 
 195 ERROR: unable to create entry ${LDAP_SUFFIX} of ${LDAP_SUFFIX_OBJ} class

 196 
 197 EOF
 198     ;;
 199     ldap_suffix_list) cat <<EOF


















 200 
 201 No valid suffixes (naming contexts) were found for LDAP base DN:
 202 ${LDAP_BASEDN}




 203 
 204 Available suffixes are:
 205 ${LDAP_SUFFIX_LIST}



 206 
 207 EOF
 208     ;;
 209     sorry) cat <<EOF


 210 
 211 HELP - No help is available for this topic.




 212 
 213 EOF
 214     ;;
 215     create_suffix_help) cat <<EOF






 216 
 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.







 221 
 222 EOF
 223     ;;
 224     enter_ldbm_db_help) cat <<EOF
 225 
 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.












 228 
 229 EOF
















































































































































































































































































 230     ;;
 231     backup_help) cat <<EOF

























 232 
 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.
 237 
 238 EOF
 239     ;;
 240     port_help) cat <<EOF
 241 
 242 HELP - Enter the port number the directory server is configured to
 243        use for LDAP.
 244 
 245 EOF
 246     ;;
 247     domain_help) cat <<EOF
 248 





 249 HELP - This is the DNS domain name this server will be serving.  You
 250        must provide this name even if the server is not going to be populated
 251        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 
 258 HELP - This parameter defines the default location in the directory tree for
 259        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 
 267 HELP - Name of the configuration profile with which the clients will be
 268        configured. A directory server can store various profiles for multiple 
 269        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 
 276 HELP - Provide a list of directory servers to serve clients using this profile.
 277        All these servers should contain consistent data and provide similar 
 278        functionality.  This list is not ordered, and clients might change the 
 279        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 
 286 HELP - Provide a list of directory servers to serve this client profile. 
 287        Unlike the default server list, which is not ordered, the preferred 
 288        servers must be entered IN THE ORDER you wish to have them contacted. 
 289        If you do specify a preferred server list, clients will always contact 
 290        them before attempting to contact any of the servers on the default 
 291        server list. Note that you must enter the preferred server list as a 
 292        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 
 299 HELP - Default search scope to be used for all searches unless they are
 300        overwritten using serviceSearchDescriptors.  The valid options
 301        are "one", which would specify the search will only be performed 
 302        at the base DN for the given service, or "sub", which would specify 
 303        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
 322        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
 334        the default authentication method defined in the profile.  This
 335        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
 360        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 
 367 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 
 374 HELP - The server time limit value indicates the maximum amount of time the
 375        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 
 382 HELP - The server sizelimit value indicates the maximum number of entries
 383        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

 394        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 
 409 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 
 416 HELP - The time limit for the bind operation to the directory.  This
 417        value controls the responsiveness of the client in case a server
 418        becomes unavailable.  The smallest timeout value for a given
 419        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 
 426 HELP - Using Service Search Descriptors (SSD), you can override the
 427        default configuration for a given service.  The SSD can be
 428        used to override the default search base DN, the default search
 429        scope, and the default search filter to be used for directory
 430        lookups.  SSD are supported for all services (databases)
 431        defined in nsswitch.conf(4).  The default base DN is defined
 432        in ldap(1).
 433 
 434        Note: SSD are powerful tools in defining configuration profiles
 435              and provide a great deal of flexibility.  However, care
 436              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 
 443 HELP - Using this menu SSD can be added, updated, or deleted from
 444        the profile.
 445 
 446        A - This option creates a new SSD by prompting for the
 447            service name, base DN, and scope.  Service name is
 448            any valid service as defined in ldap(1).  base is
 449            either the distinguished name to the container where
 450            this service will use, or a relative DN followed
 451            by a ','.
 452        D - Delete a previously created SSD.
 453        M - Modify a previously created SSD.
 454        P - Display a list of all the previously created SSD.
 455        X - Delete all of the previously created SSD.
 456 
 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.
 473        The setup will add an administrator identity/credential
 474        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.

 478 
 479        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 
 486 HELP - Start the setup to add an administrator identity/credential
 487        and to modify access controls for the client to update
 488        shadow(4) data on the LDAP server.

 489 
 490        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
 499        access controls for allowing the client to update shadow(4) data
 500        on the LDAP server.
 501 
 502        Shadow data is used for password aging and account locking.
 503        Please refer to the shadow(4) manual page for details.
 504 
 505 EOF
 506     ;;
 507     esac
 508 }
 509 












 510 
 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 
 525     read ANS
 526     if [ -z "$ANS" ]
 527     then
 528         ANS=$2
 529     fi
 530 }
 531 
 532 
 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
 545 }
 546 













 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()









 556 {
 557     ANS=""                  # Set ANS to NULL.
 558     NUM=""








 559 
 560     get_ans "$1" "$2"
 561 
 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
 574 }
 575 
 576 
 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()
 585 {
 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
 600 }
 601 
 602 
 603 #
 604 # get_passwd(): Reads a password from the user and verify with second.
 605 #               $@  instruction/comment/description/question
 606 #
 607 get_passwd()
 608 {
 609     [ $DEBUG -eq 1 ] && ${ECHO} "In get_passwd()"








 610 
 611     # Temporary PASSWD variables
 612     _PASS1=""
 613     _PASS2=""
 614 
 615     /usr/bin/stty -echo     # Turn echo OFF
 616 
 617     # Endless loop that continues until passwd and re-entered passwd
 618     # match.
 619     while :
 620     do
 621         ANS=""                  # Set ANS to NULL.
 622 
 623         # Don't allow NULL for first try.
 624         while [ "$ANS" = "" ]
 625         do
 626             get_ans "$@"
 627             [ "$ANS" = "" ] && ${ECHO} "" && ${ECHO} "NULL passwd not allowed!"

 628         done
 629         _PASS1=$ANS         # Store first try.
 630 
 631         # Get second try.
 632         ${ECHO} ""
 633         get_ans "Re-enter passwd:"
 634         _PASS2=$ANS
 635 
 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} ""
 649 }
 650 
 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()
 657 {
 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} ""
 667 }
 668 
 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()
 682 {
 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
 688 
 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
 698                 fi




 699             fi
 700         fi
 701         ${ECHO} "Invalid choice: $MN_CH"
 702     done

 703 }
 704 
 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()
 712 {
 713     _ANSWER=












 714 
 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
 722         fi
 723 
 724         # Display prompt.
 725         ${ECHO} "$1 [$2] \c"

 726 
 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
 739 }
 740 
 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()
 747 {
 748     _ANSWER=









 749 
 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
 760 }



 761 
 762 
 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
 774 
 775     # Determine if numeric.
 776     expr "$1" + 1 > /dev/null 2>&1
 777     if [ $? -ge 2 ]; then
 778         return 1
 779     fi
 780 
 781     # Made it here, it's Numeric.
 782     return 0
 783 }
 784 
 785 
 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
 801 }


 802 
 803 
 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
 816 
 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
 826     fi
 827 }
 828 








 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





 846 }
 847 
 848 
 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`
 877 
 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
 884 
 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
 897 }
 898 










 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
 921     done
 922 }
 923 
 924 
 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





 934 }
 935 









 936 
 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`
 958 }
 959 









 960 
 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"
 983 
 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












 990 
 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













 996 
 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.











1000 
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"
1015 
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









1022 
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=""
1033 
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
1052 
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
1093 }








1094 
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"
1147 }
1148 












1149 
1150 #
1151 # load_config_file(): Loads the config file.
1152 #
1153 load_config_file()
1154 {
1155     [ $DEBUG -eq 1 ] && ${ECHO} "In load_config_file()"
1156 
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






1161 
1162     # Source the input file. 
1163     . ${TMPDIR}/inputfile.noSSD





1164 
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}"










1168 
1169     # Save password to temporary file.
1170     save_password







1171 
1172     # Create the SSD file.
1173     create_ssd_file
1174 
1175     # Display FULL debugging info.
1176     disp_full_debug
1177 }
1178 
1179 #
1180 # save_password(): Save password to temporary file.
1181 #
1182 save_password()
1183 {
1184     cat > ${LDAP_ROOTPWF} <<EOF
1185 ${LDAP_ROOTPWD}
1186 EOF









1187 }
1188 
1189 ######################################################################
1190 # FUNCTIONS  FOR prompt_config_info() START HERE.
1191 ######################################################################








1192 
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"
1203 
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
1208         fi
1209 
1210         # Invalid server, enter a new name.
1211         ${ECHO} "ERROR: Server '${IDS_SERVER}' is invalid or unreachable."
1212         IDS_SERVER=""
1213     done
1214 
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

1219 
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
1239         fi
1240         
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
1245 
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
1250 }
1251 



1252 
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()"
1259 
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

1278 }
1279 






















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
1293 }
1294 


























1295 
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



1306 
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
1325         else
1326             break         # Both are valid.


1327         fi









1328     done









1329 





1330 



1331 }
1332 



























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









1359 }
1360 











1361 
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"
1389         done
1390 
1391         # Set base DN and check its suffix
1392         LDAP_BASEDN=${ANS}
1393         check_basedn_suffix ||
1394         {
1395                 cleanup
1396                 exit 1
1397         }
1398 
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

1408 }
1409 
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






1422 }
1423 
1424 get_krb_realm() {
1425 
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) }'`
1431 }








1432 
1433 # $1: DN
1434 # $2: ldif file
1435 add_entry_by_DN() {
1436 
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 
1452 }
1453 #
1454 # Kerberos princiapl to DN mapping rules
1455 #
1456 # Add rules for host credentails and user credentials
1457 #
1458 add_id_mapping_rules() {
1459 
1460     ${ECHO} "  Adding Kerberos principal to DN mapping rules..."
1461 
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
1470 
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
1477 
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
1492 
1493 EOF
1494 ) > ${TMPDIR}/${_H_CN}.ldif

1495 
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 
1516 }







1517 
1518 
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() {
1524 
1525     _P_DN="ou=People,${LDAP_BASEDN}"
1526     _H_DN="ou=Hosts,${LDAP_BASEDN}"
1527     _P_ACI="self-read-pwd"
1528 
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
1588 }
1589 #
1590 # $1: objectclass or attributetyp
1591 # $2: name
1592 search_update_schema() {
1593 
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
1605 }
1606 
1607 #
1608 # Set up GSSAPI if necessary
1609 #
1610 gssapi_setup() {



1611 
1612         GSSAPI_ENABLE=0
1613 
1614         # assume sasl/GSSAPI is supported by the ldap server and may be used
1615         GSSAPI_AUTH_MAY_BE_USED=1
1616 
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"



1621                 return
1622         fi
1623 
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."


1630         else
1631                 GSSAPI_ENABLE=1
1632                 get_krb_realm
1633         fi
1634 
1635 }
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 
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"

1649 
1650         # Check for Help.
1651         case "$ANS" in
1652             [Hh] | help | Help | \?) display_msg profile_help
1653                                      continue ;; 
1654             * )  ;;

1655         esac
1656 
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




1660 
1661             cat << EOF




1662 
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.
1668 
1669 EOF
1670 
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
1682 
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
1697 }
1698 


















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}"
1710         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




1725 }
1726 
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
1744 }
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 
1769 }




1770 


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
1802 }
1803 











1804 
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     
1812 
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"
1819         else
1820             get_ans "Choose Service Authentication Method (0=reset):"
1821         fi
1822 
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
1842 }
1843 











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
1888 }
1889 
1890 
1891 #
1892 # get_auth(): Enter the Authentication method.
1893 #
1894 get_auth()
1895 {
1896     [ $DEBUG -eq 1 ] && ${ECHO} "In get_auth()"
1897 
1898     _FIRST=1          # Flag for first time.
1899     _MENU_CHOICE=0
1900     _AUTHMETHOD=""    # Tmp method.
1901 
1902     while :
1903     do
1904         # Call Menu handler
1905         auth_menu_handler
1906 
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}"
1913         fi
1914 
1915         # Display current Authentication Method.
1916         ${ECHO} ""
1917         ${ECHO} "Current authenticationMethod: ${LDAP_AUTHMETHOD}"
1918         ${ECHO} ""



1919 
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;


1924         fi
1925     done


1926 }
1927 
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
1940 }




1941 


1942 
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 }
1960 











1961 
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=`
1975 
1976     get_negone_num "Enter the size limit for iDS (current=${CURR_SIZELIMIT}):" "-1"
1977     IDS_SIZELIMIT=$NUM
1978 }
1979 
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
1992 }






1993 




1994 
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()"
2003 
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}"
2023         fi
2024 
2025         # Display current Authentication Method.
2026         ${ECHO} ""
2027         ${ECHO} "Current authenticationMethod: ${LDAP_SRV_AUTHMETHOD_PAM}"
2028         ${ECHO} ""
2029 
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
2041 }




2042 


2043 
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()"
2052 
2053     _FIRST=1          # Flag for first time.
2054     _MENU_CHOICE=0
2055     _AUTHMETHOD=""    # Tmp method.

2056 
2057     while :
2058     do
2059         # Call Menu handler
2060         srvauth_menu_handler
2061 
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}"
2072         fi
2073 
2074         # Display current Authentication Method.
2075         ${ECHO} ""
2076         ${ECHO} "Current authenticationMethod: ${LDAP_SRV_AUTHMETHOD_KEY}"
2077         ${ECHO} ""
2078 
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
2085 
2086     # Check in case user reset string and exited loop.
2087     if [ "$LDAP_SRV_AUTHMETHOD_KEY" = "" ]; then
2088         NEED_SRVAUTH_KEY=0
2089     fi
2090 }
2091 









2092 
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()"
2101 
2102     _FIRST=1          # Flag for first time.
2103     _MENU_CHOICE=0
2104     _AUTHMETHOD=""    # Tmp method.
2105 
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}"
2121         fi
2122 
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
2139 }
2140 
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
2149 }
2150 
2151 
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 }





2160 


2161 
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 }
2170 





2171 
2172 ######################################################################
2173 # FUNCTIONS  FOR Service Search Descriptor's START HERE.
2174 ######################################################################
2175 










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

2194         fi
2195 
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
2202 
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}
2220 }






2221 



2222 
2223 #
2224 # delete_ssd(): Delete a SSD from the list.
2225 #
2226 delete_ssd()
2227 {
2228     [ $DEBUG -eq 1 ] && ${ECHO} "In delete_ssd()"
2229 
2230     # Get service id name from user for SSD to delete.
2231     get_ans_req "Enter service id to delete:"
2232 
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





2239 
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
2246 
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} 
2250 }
2251 












2252 
2253 #
2254 # modify_ssd(): Allow user to modify a SSD.
2255 #
2256 modify_ssd()
2257 {
2258     [ $DEBUG -eq 1 ] && ${ECHO} "In modify_ssd()"








2259 
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


2269 
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`
2278 
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

2286 
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








2296 
2297     # Build the new SSD.
2298     _SSD="${_SERV_ID}:${_BASE}?${_SCOPE}"
2299 
2300     # Add the SSD to the file.
2301     ${ECHO} "${_SSD}" >> ${SSD_FILE}
2302 }










2303 











2304 
2305 #
2306 # display_ssd(): Display the current SSD list.
2307 #
2308 display_ssd()
2309 {
2310     [ $DEBUG -eq 1 ] && ${ECHO} "In display_ssd()"
2311 
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
2319 }








2320 







2321 
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





2331 
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














2350 }
2351 









2352 
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}
2362 }





2363 















2364 
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()"
2371 
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}
2376 }
2377 











2378 
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}


2388 }
2389 









2390 
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()"



2397 
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}`"
2409 }
2410 
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"
2420 }
2421 
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"
2430 }
2431 
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()"






2438 
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
2451 
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
2465     
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
2473 
2474     ${RM} -f ${TMPDIR}/admin
2475 
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
2484 }
2485 
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()"

2493 
2494     # Set ACI Name
2495     ADMIN_ACI_NAME="LDAP_Naming_Services_admin_shadow_write"
2496 
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`       
2512         fi
2513         return 0
2514     fi
2515 
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}
2520 
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
2533     
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
2541 
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 }
2552 
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`
2574         fi
2575         return 0
2576     fi
2577 
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


2594 
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
2603 }
2604 
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
2626         then
2627             if ${GREP} credentialLevel $PROFILE_OUT | ${GREP} self >/dev/null 2>&1
2628             then
2629                 NEED_HOSTACL=1
2630             fi
2631         fi
2632         ${RM} ${PROFILE_OUT}
2633         [ $DEBUG -eq 1 ] && ${ECHO} "NEED_HOSTACL = $NEED_HOSTACL"
2634 
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
2651 
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."




2667 }
2668 
2669 
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()"
2677 
2678     # Prompt for iDS server name.



2679     get_ids_server
2680 
2681     # Prompt for iDS port number.
2682     get_ids_port
2683 
2684     # Check iDS version for compatibility.
2685     chk_ids_version
2686 
2687     # Check if the server supports the VLV.
2688     chk_vlv_indexes
2689 
2690     # Get the Directory manager DN and passwd.
2691     get_dirmgr_dn
2692     get_dirmgr_pw
2693 
2694     #
2695     # LDAP CLIENT PROFILE SPECIFIC INFORMATION.
2696     #   (i.e. The fields that show up in the profile.)
2697     #
2698     get_domain "domain_help"
2699 
2700     get_basedn




2701 







2702     gssapi_setup
2703 
2704     get_profile_name
2705 
2706     if [ "$LDAP_ENABLE_SHADOW_UPDATE" = "TRUE" ];then
2707         setup_shadow_update
2708         cleanup
2709         exit 0
2710     fi
2711 
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 
2722     get_followref
2723 
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
2728 
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
2733 
2734     # Does the user want to store passwords in crypt format?
2735     get_want_crypt
2736 
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
2744 
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

2749 
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  
2756 
2757     # Get Timeouts
2758     get_srch_time
2759     get_prof_ttl
2760     get_bind_limit
2761 
2762     # Ask whether to enable shadow update
2763     get_want_shadow_update
2764 
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
2769 
2770     # Display FULL debugging info.
2771     disp_full_debug
2772 
2773     # Extra blank line to separate prompt lines from steps.
2774     ${ECHO} " "
2775 }



2776 
2777 
2778 ######################################################################
2779 # FUNCTIONS  FOR display_summary() START HERE.
2780 ######################################################################
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
2791 }
2792 















2793 
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 }
2802 
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()"
2810 
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"
2823 
2824     # Since menu prompt string is long, set here.
2825     _MENU_PROMPT="Enter config value to change: (1-20 0=commit changes)"
2826 
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.
2838         fi
2839 
2840         # Call appropriate function from function table.
2841         set $FUNC_TBL
2842         shift $_CH
2843         $1          # Call the appropriate function.
2844     done
2845 
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"
2857         fi
2858     fi
2859 
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
2868         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 
2877     # Display FULL debugging info.
2878     disp_full_debug
2879 
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
2888 
2889     # Print newline 
2890     ${ECHO} " "
2891 }



2892 











2893 
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()"




2900 
2901     # If output file exists, delete it.
2902     [ -f $OUTPUT_FILE ] && rm $OUTPUT_FILE





2903 
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"
2923 
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



2932 
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
2952 
2953 # Proxy Agent
2954 LDAP_PROXYAGENT="$LDAP_PROXYAGENT"
2955 LDAP_PROXYAGENT_CRED=$LDAP_PROXYAGENT_CRED



2956 
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
2961 
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
2974 
2975 # Service Search Descriptors start here if present:
2976 EOF
2977     # Add service search descriptors.
2978     ssd_2_config "${OUTPUT_FILE}"
2979 
2980     # Add LDAP suffix preferences
2981     print_suffix_config >> "${OUTPUT_FILE}"
2982 
2983     # Add the end of FILE tag.
2984     ${ECHO} "" >> ${OUTPUT_FILE}
2985     ${ECHO} "# End of $OUTPUT_FILE" >> ${OUTPUT_FILE}
2986 }
2987 
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."
3003 }





3004 
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()"
3022 
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
3056 
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
3064 
3065     [ $DEBUG -eq 1 ] && ${ECHO} "IDS_DATABASE: ${IDS_DATABASE}"




3066 }








3067 
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()"
3075 
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


3082 
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}"
3089 
3090     [ $DEBUG -eq 1 ] && ${ECHO} "LOWER_BASEDN: ${LOWER_BASEDN}"
3091     [ $DEBUG -eq 1 ] && ${ECHO} "LOWER_SUFFIX: ${LOWER_SUFFIX}"
3092 
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
3102 
3103     # Check LDAP_SUFFIX does exist
3104     ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_SUFFIX}\" -s base \"objectclass=*\" > ${TMPDIR}/checkSuffix 2>&1" && return 0




3105 
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     }
3129 
3130     [ $DEBUG -eq 1 ] && ${ECHO} "Suffix $LDAP_SUFFIX, Database $IDS_DATABASE"




3131 }



3132 
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()"
3141 
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










3147 
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"
3163 
3164     # Check if the server supports the VLV.
3165     chk_vlv_indexes
3166     [ $DEBUG -eq 1 ] && ${ECHO} "  VLV indexes ... OK"
3167 
3168     # Check LDAP suffix
3169     validate_suffix
3170     [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP suffix ... OK"
3171 }
3172 
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 }
3184 
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()"
3197 
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     }
3205 
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-`
3210 
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}"
3223 
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
3268 
3269     NEED_CREATE_BACKEND=

3270 
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     }
3285 
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     }
3295 
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 }
3301 
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()"
3315 
3316     # check if requested name available
3317     [ "${IDS_DATABASE}" = "${IDS_DATABASE_AVAIL}" ] && return 0
3318 
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
3323 
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
3336 
3337     [ "${IDS_DATABASE}" = "${IDS_DATABASE_AVAIL}" ] && return 0

3338 
3339     [ -n "${IDS_DATABASE_AVAIL}" ] &&
3340     {
3341         display_msg ldbm_db_exist
3342         return 1
3343     }
3344 
3345     display_msg unable_find_db_name
3346     return 2
3347 }
3348 
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()"
3361 
3362     [ -n "${NEED_CREATE_SUFFIX}" ] || return 0

3363 
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}
3374 
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         }
3387 
3388         ${ECHO} "  ${STEP}. Database ${IDS_DATABASE} successfully created"
3389         STEP=`expr $STEP + 1`
3390     }
3391 
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     }
3403 
3404     ${ECHO} "  ${STEP}. Suffix ${LDAP_SUFFIX} successfully created"
3405     STEP=`expr $STEP + 1`
3406     return 0
3407 }
3408 
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()"
3423 
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
3434 
3435                 [ -n "${NEED_CREATE_BACKEND}" ] &&
3436                 {
3437                     IDS_DATABASE_AVAIL= # reset the available db name
3438 
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
3453 
3454                     [ $DEBUG -eq 1 ] && cat <<EOF
3455 DEBUG: backend name for suffix ${LDAP_SUFFIX} will be ${IDS_DATABASE}
3456 EOF
3457                 }
3458 
3459                 # eventually everything is prepared
3460                 return 0
3461                 ;;
3462         esac
3463     done
3464 }
3465 
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 }
3482 
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()"
3494 
3495     NEED_CREATE_SUFFIX=

3496 
3497     # find out existing suffixes
3498     discover_serv_suffix
3499 
3500     ${ECHO} "  Validating LDAP Base DN and Suffix ..."

3501 
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
3517 
3518     if [ "${cur_ldap_entry}" = "${prev_ldap_entry}" ]; then
3519         ${ECHO} "  No valid suffixes were found for Base DN ${LDAP_BASEDN}"
3520 
3521         NEED_CREATE_SUFFIX=1
3522         return 0
3523 
3524     else
3525         [ $DEBUG -eq 1 ] && ${ECHO} "found valid LDAP entry: ${cur_ldap_entry}"
3526 
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
3559 
3560         [ $DEBUG -eq 1 ] && ${ECHO} "LDAP_SUFFIX: ${LDAP_SUFFIX}"

3561 
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
3572 
3573         return 0
3574     fi
3575 }
3576 
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()"
3585 
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
3602 
3603     [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SUFFIX_LIST = $LDAP_SUFFIX_LIST"
3604     return 0
3605 }
3606 


3607 
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()"
3614 
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
3622 
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 }
3631 


3632 
3633 # modify_timelimit(): Modify timelimit to user value.
3634 modify_timelimit()
3635 {
3636     [ $DEBUG -eq 1 ] && ${ECHO} "In modify_timelimit()"
3637 
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
3646 
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
3654 
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 }
3659 


3660 
3661 # modify_sizelimit(): Modify sizelimit to user value.
3662 modify_sizelimit()
3663 {
3664     [ $DEBUG -eq 1 ] && ${ECHO} "In modify_sizelimit()"
3665 
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
3674 
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
3682 
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 }
3687 


3688 
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()"
3693 
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
3713 
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
3721 
3722     # Display messages for modifications made in patch.
3723     ${ECHO} "  ${STEP}. Changed passwordstoragescheme to \"crypt\" in cn=config."
3724     STEP=`expr $STEP + 1`
3725 }
3726 


3727 
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()"
3734 
3735     # Set eq indexes to add.
3736     _INDEXES="uidNumber ipNetworkNumber gidnumber oncrpcnumber automountKey"
3737 
3738     if [ -z "${IDS_DATABASE}" ]; then
3739         get_backend
3740     fi
3741 
3742     # Set _EXT to use as shortcut.
3743     _EXT="cn=index,cn=${IDS_DATABASE},cn=ldbm database,cn=plugins,cn=config"
3744 
3745     # Display message to id current step.
3746     ${ECHO} "  ${STEP}. Processing eq,pres indexes:"
3747     STEP=`expr $STEP + 1`
3748 
3749     # For loop to create indexes.
3750     for i in ${_INDEXES}; do
3751         [ $DEBUG -eq 1 ] && ${ECHO} "  Adding index for ${i}"
3752 
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
3761 
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}
3773 
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
3781 
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'`
3789 
3790         # Build task name
3791         TASKNAME="${i}_${_YR}_${_MN}_${_DY}_${_H}_${_M}_${_S}"
3792 
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}
3804 
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
3811         fi
3812 
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
3831         done
3832 
3833         # Print newline because of \c.
3834         ${ECHO} " "
3835     done
3836 }
3837 


3838 
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()"
3845 
3846     # Set eq indexes to add.
3847     _INDEXES="ipHostNumber membernisnetgroup nisnetgrouptriple"
3848 
3849     # Set _EXT to use as shortcut.
3850     _EXT="cn=index,cn=${IDS_DATABASE},cn=ldbm database,cn=plugins,cn=config"
3851 


3852 
3853     # Display message to id current step.
3854     ${ECHO} "  ${STEP}. Processing eq,pres,sub indexes:"
3855     STEP=`expr $STEP + 1`
3856 
3857     # For loop to create indexes.
3858     for i in ${_INDEXES}; do
3859         [ $DEBUG -eq 1 ] && ${ECHO} "  Adding index for ${i}"
3860 
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
3869 
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}
3882 
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
3890 
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'`



3898 
3899         # Build task name
3900         TASKNAME="${i}_${_YR}_${_MN}_${_DY}_${_H}_${_M}_${_S}"
3901 
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}
3913 
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
3921 
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
3941 
3942         # Print newline because of \c.
3943         ${ECHO} " "
3944     done


3945 }




3946 




3947 
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()"
3954 
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"
3963 
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=*:*)"
3979 
3980     _INDEXES="$_INDEX1 $_INDEX2 $_INDEX3 $_INDEX4 $_INDEX5 $_INDEX6 $_INDEX7 $_INDEX8 $_INDEX9 $_INDEX10 $_INDEX11 $_INDEX12 $_INDEX13 $_INDEX14 $_INDEX15 $_INDEX16 $_INDEX17 $_INDEX18 $_INDEX19 $_INDEX20 $_INDEX21 "

3981 


3982 
3983     # Set _EXT to use as shortcut.
3984     _EXT="cn=${IDS_DATABASE},cn=ldbm database,cn=plugins,cn=config"
3985 


3986 
3987     # Display message to id current step.
3988     ${ECHO} "  ${STEP}. Processing VLV indexes:"
3989     STEP=`expr $STEP + 1`
3990 
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
3996 
3997     # Get the instance name from iDS server.
3998     _INSTANCE="<server-instance>"    # Default to old output.
3999 
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"

4001 
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
4007 
4008     # For loop to create indexes.
4009     for p in ${_INDEXES}; do
4010         [ $DEBUG -eq 1 ] && ${ECHO} "  Adding index for ${i}"
4011 
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
4027         fi
4028 
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
4035 
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";)
4046 
4047 dn: cn=${i},${_jEXT}
4048 cn: ${i}
4049 vlvSort: cn uid
4050 objectclass: top
4051 objectclass: vlvIndex
4052 EOF
4053 ) > ${TMPDIR}/vlv_index_${i}
4054 
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
4061         fi
4062 
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
4070 }
4071 


4072 
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
4082 
4083     if [ -s "${TMPDIR}/ds5_vlvindex_list" ]; then
4084         cat ${TMPDIR}/ds5_vlvindex_list










4085     fi
4086 
4087     cat << EOF





4088 


















4089 
4090 EOF
4091 
4092     if [ -s "${TMPDIR}/ds6_vlvindex_list" ]; then
4093         cat ${TMPDIR}/ds6_vlvindex_list




4094     fi
4095 }
4096 
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
4120 }
4121 
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()"



























































4128 
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
4230 
4231     keep_backward_compatibility
4232 
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


4240 
4241     # Display message that schema is updated.
4242     ${ECHO} "  ${STEP}. Schema attributes have been updated."
4243     STEP=`expr $STEP + 1`

















4244 }
4245 





4246 
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()"







4253 
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 ) )










4260 
4261 dn: cn=schema
4262 changetype: modify
4263 add: objectclasses
4264 objectclasses: ( 1.3.6.1.1.1.2.15 NAME 'nisDomainObject' SUP top MUST nisDomain )







4265 
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 )


















4270 
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 )
4275 
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 ) )











4280 
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 ) )








4285 
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 )
4290 
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 ) )




4295 
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 ) )
4300 
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 ) )
4305 
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 ) )






4310 
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 ) )
4315 
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 ) )






4320 
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 ) )



4325 
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 ) )







4330 
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 )















4335 
4336 dn: cn=schema


4337 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 )

4340 
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 ) )


4345 
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 ) )
4350 
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 ) )






4355 
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 ) )







4360 
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 )



4365 
4366 dn: cn=schema
4367 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
4372 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 ) )
4375 
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 )







4380 
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



4387 
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`
4399 }
4400 
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()"




4408 
4409     # Set ACI Name
4410     ACI_NAME="LDAP_Naming_Services_deny_write_access"
4411 
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`
4424         return 0
4425     fi
4426 
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
4443     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
4453 }
4454 
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"








4462 
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`
4467 
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















4483         fi
4484 
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"
4490         else
4491             ${ECHO} "  ${STEP}. $MSG"
4492             STEP=`expr $STEP + 1`
4493         fi
4494     fi


4495 }
4496 
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()"









4504 
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"
4508 
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
4516 
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`       










4526         fi



4527         return 0
4528     fi



4529 
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}










4533 
4534     # Create the tmp file to add.
4535     ( cat <<EOF
4536 dn: ${LDAP_BASEDN}
4537 changetype: modify
4538 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

4554 
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

4564 }
4565 
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()"




4573 
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`       
4595         fi
4596         return 0
4597     fi
4598 
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}









4602 
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




4624 
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 }


















4635 
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()"
4642 
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
4651 
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

4659 
4660     # Display message that schema is updated.
4661     ${ECHO} "  ${STEP}. Add of VLV Access Control Information (ACI)."
4662     STEP=`expr $STEP + 1`
4663 }
4664 


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`
4703 }
4704 
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  
4730 }
4731 








































4732 
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"
4746 
4747     # Set return value to NULL string.
4748     _ATTR_NAME=""
4749 
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
4758 
4759     [ $DEBUG -eq 1 ] && ${ECHO} "get_objectclass: _ATTR_NAME = $_ATTR_NAME"
4760 }






4761 




4762 
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()"




4769 
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}"
4775 
4776     [ $DEBUG -eq 1 ] && ${ECHO} "LOWER_BASEDN: ${LOWER_BASEDN}"
4777     [ $DEBUG -eq 1 ] && ${ECHO} "LOWER_SUFFIX: ${LOWER_SUFFIX}"
4778 
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

4791         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 






4813 



4814 
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}'`








4822 
4823             # At this point, ${dk2} is a valid attribute name

4824 
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"
4830 
4831                 # Process next component.
4832                 dc=`${ECHO} "${dcstmp}" | cut -f1 -d','`
4833                 dcstmp=`${ECHO} "${dcstmp}" | cut -f2- -d','`
4834                 continue
4835 









4836             fi
4837 
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
4851 objectClass: top
4852 objectClass: ${OBJ_Name}
4853 EOF
4854 ) > ${TMPDIR}/base_objects
4855 
4856 
4857             # Set the $lastdc to new dc.
4858             lastdc="${dk2}=${dc2},$lastdc"
4859 
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
4867 
4868             # Display message that schema is updated.
4869             ${ECHO} "  ${STEP}. Created DN component ${dc}."
4870             STEP=`expr $STEP + 1`





4871 
4872             # Process next component.
4873             dc=`${ECHO} "${dcstmp}" | cut -f1 -d','`
4874             dcstmp=`${ECHO} "${dcstmp}" | cut -f2- -d','`
4875         done











4876     fi










4877 }
4878 












4879 
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()"




4888 
4889     for ou in people group rpc protocols networks netgroup \
4890         aliases hosts services ethers profile printers projects \
4891         SolarisAuthAttr SolarisProfAttr Timezone ipTnet ; do










4892 
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
4898 
4899         # Create TMP file to add.
4900         ( cat <<EOF
4901 dn: ou=${ou},${LDAP_BASEDN}
4902 ou: ${ou}



4903 objectClass: top
4904 objectClass: organizationalUnit
4905 EOF
4906 ) > ${TMPDIR}/toplevel.${ou}
4907 
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
4916 
4917     # Display message that top level OU containers complete.
4918     ${ECHO} "  ${STEP}. Top level \"ou\" containers complete."
4919     STEP=`expr $STEP + 1`
4920 }
4921 





4922 
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()"
4931 
4932     # Set AUTO_MAPS for maps to create.
4933     AUTO_MAPS="auto_home auto_direct auto_master auto_shared"
4934 
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
4940         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`















4963 }
4964 








4965 
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()"
4972 
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

4979     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`
5006 }










5007 
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()"
5014 
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

5023 
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


5042 
5043     # Display message that schema is updated.
5044     ${ECHO} "  ${STEP}. Give ${LDAP_PROXYAGENT} read permission for password."
5045     STEP=`expr $STEP + 1`


5046 }




5047 
5048 #  Delete Proxy Agent read permission for password.
5049 delete_proxy_read_pw()
5050 {
5051     [ $DEBUG -eq 1 ] && ${ECHO} "In delete_proxy_read_pw()"





















5052 
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
5061 
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





5075 
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.

5080 
5081 The proxy agents are:



5082 
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
5088 
5089             # print the proxy agent list
5090             ${NAWK} '{print NR ": " $0}' ${TMPDIR}/proxy_agent_list
5091 
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
5098 
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
5107 
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
5116 
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 }
5124 
5125 #
5126 # add_profile(): Add client profile to server.
5127 #
5128 add_profile()
5129 {
5130     [ $DEBUG -eq 1 ] && ${ECHO} "In add_profile()"


5131 
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
5140 
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
5145         fi



5146 
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





5153         fi
5154     fi
5155 
5156     # Build the "ldapclient genprofile" command string to execute.
5157     GEN_CMD="ldapclient genprofile -a \"profileName=${LDAP_PROFILE_NAME}\""
5158 
5159     # Add required argument defaultSearchBase.
5160     GEN_CMD="${GEN_CMD} -a \"defaultSearchBase=${LDAP_BASEDN}\""
5161 
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}\""
5187 
5188     # Check if there are any service search descriptors to ad.
5189     if [ -s "${SSD_FILE}" ]; then
5190         ssd_2_profile
5191     fi
5192 
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
5200 
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
5208 
5209     # Display message that schema is updated.
5210     ${ECHO} "  ${STEP}. Generated client profile and loaded on server."
5211     STEP=`expr $STEP + 1`
5212 }
5213 

5214 
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}
5223 }
5224 




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
5294 }
5295 
5296 # Add base objects (if needed)
5297 add_base_objects
5298 
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
5303 
5304 # Add top level classes (new containers)
5305 add_new_containers




























5306 
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
5322 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
5332 fi
5333 
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



















5343 
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








5351 


5352 
5353 # Generate client profile and add it to the server.
5354 add_profile
5355 
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.
   1 #!/bin/ksh93
   2 #
   3 # $Id: idsconfig.sh,v 66c6ff17d001 2013-09-24 00:35:53Z jel+illumos $
   4 #
   5 # CDDL HEADER START
   6 #
   7 # The contents of this file are subject to the terms of the
   8 # Common Development and Distribution License (the "License").
   9 # You may not use this file except in compliance with the License.
  10 #
  11 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  12 # or http://www.opensolaris.org/os/licensing.
  13 # See the License for the specific language governing permissions
  14 # and limitations under the License.
  15 #
  16 # When distributing Covered Code, include this CDDL HEADER in each
  17 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  18 # If applicable, add the following below this CDDL HEADER, with the
  19 # fields enclosed by brackets "[]" replaced with your own identifying
  20 # information: Portions Copyright [yyyy] [name of copyright owner]
  21 #
  22 # CDDL HEADER END
  23 #



  24 # Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
  25 # Portions Copyright 2013  Jens Elkner.
  26 
















  27 
  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]'
  35 
  36 SDIR=${.sh.file%/*}
  37 typeset -r FPROG=${.sh.file}
  38 typeset -r PROG=${FPROG##*/}
  39 
  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
  46 
  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 
  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
  77 
  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
 113 
 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
 126 
 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 }





















 142 
 143 Man.addVar PROG 'String. The basename of this script.'



 144 
 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=( )
 149 
 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=( )
 154 
 155 Man.addVar CON_ARGS 'String. Contains connection related options for ldap commands.'
 156 typeset CON_ARGS=''



 157 
 158 Man.addVar AUTH_ARGS 'Indexed array of Strings. Contains authentification related options for ldap commands.'
 159 typeset -a AUTH_ARGS=( )


 160 
 161 Man.addVar SSD 'Indexed array of Strings. Contains the Service Search Decsriptors to use.'
 162 typeset -a SSD=( )
 163 
 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!

















 167 
 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'

 170 
 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'
 173 
 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'

 176 
 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'
 179 
 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'

 182 
 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'
 187 
 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'
 194 
 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'
 197 
 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'

 200 
 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'
 203 
 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
 209 
 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' )
 212 
 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=( )
 217 
 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=( )
 220 
 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 }
 242 
 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
 249 
 250         # General commands
 251         HOST=${ hostname ; }
 252         PING=${ checkBinary ping || (( ERR++ )) ; }
 253         STTY=${ checkBinary stty || (( ERR++ )) ; }
 254         GETENT=${ checkBinary getent || (( ERR++ )) ; }
 255 
 256         # LDAP COMMANDS
 257         LDAPSEARCH=${ checkBinary ldapsearch || (( ERR++ )) ; }
 258         LDAPMODIFY=${ checkBinary ldapmodify || (( ERR++ )) ; }
 259         LDAPDELETE=${ checkBinary ldapdelete || (( ERR++ )) ; }
 260         LDAPCLIENT=${ checkBinary ldapclient || (( ERR++ )) ; }
 261 
 262         if (( ERR )); then
 263                 Log.fatal 'Please adjust your PATH and try again'
 264                 return 66
 265         fi
 266         LDAPSEARCH+=' -r'
 267 
 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
 277 
 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
 289 
 290         # Actually one needs to init non-null/zero values, only. However, we want
 291         # to have the keys registered ...

 292 
 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
 315 
 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
 338 
 339         # Service Search Descriptors (just make sure it is empty)
 340         SSD=( ); unset SSD[0]                           # unset is required!
 341 
 342     # GSSAPI setup
 343     INT[GSSAPI_ENABLE]=0
 344     STR[LDAP_KRB_REALM]=''
 345 
 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
 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 '
 683 HELP - This is the DNS domain name this server will be serving.  You
 684        must provide this name even if the server is not going to be populated
 685        with hostnames.  Any unqualified hostname stored in the directory
 686        will be fully qualified using this DNS domain name.\n'


 687                         ;;
 688                 basedn_help)
 689                         print '
 690 HELP - This parameter defines the default location in the directory tree for
 691        the naming services entries.  You can override this default by using 
 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 '
 697 HELP - Name of the configuration profile with which the clients will be
 698        configured. A directory server can store various profiles for multiple 
 699        groups of clients.  The initialization tool, (ldapclient(1M)), assumes 
 700        "default" unless another is specified.\n'


 701                         ;;
 702                 def_srvlist_help)
 703                         print '
 704 HELP - Provide a list of directory servers to serve clients using this profile.
 705        All these servers should contain consistent data and provide similar 
 706        functionality.  This list is not ordered, and clients might change the 
 707        order given in this list. Note that this is a space separated list of 
 708        *IP addresses* (not host names).  Providing port numbers is optional.\n'


 709                         ;;
 710                 pref_srvlist_help)
 711                         print '
 712 HELP - Provide a list of directory servers to serve this client profile. 
 713        Unlike the default server list, which is not ordered, the preferred 
 714        servers must be entered IN THE ORDER you wish to have them contacted. 
 715        If you do specify a preferred server list, clients will always contact 
 716        them before attempting to contact any of the servers on the default 
 717        server list. Note that you must enter the preferred server list as a 
 718        space-separated list of *IP addresses* (not host names).  Providing port 
 719        numbers is optional.\n'


 720                         ;;
 721                 srch_scope_help)
 722                         print '
 723 HELP - Default search scope to be used for all searches unless they are
 724        overwritten using serviceSearchDescriptors.  The valid options
 725        are "one", which would specify the search will only be performed 
 726        at the base DN for the given service, or "sub", which would specify 
 727        the search will be performed through *all* levels below the base DN 
 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
 743        in the client using this profile.  This is a ordered list of
 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
 753        the default authentication method defined in the profile.  This
 754        feature can be used to select stronger authentication methods for
 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
 772        contacting the directory server.  This is a ordered list and if
 773        provided will override the default authentication method parameter.\n'


 774                         ;;
 775                 referrals_help)
 776                         print '
 777 HELP - This parameter indicates whether the client should follow
 778        ldap referrals if it encounters one during naming lookups.\n'


 779                         ;;
 780                 tlim_help)
 781                         print '
 782 HELP - The server time limit value indicates the maximum amount of time the
 783        server would spend on a query from the client before abandoning it.
 784        A value of "-1" indicates no limit.\n'


 785                         ;;
 786                 slim_help)
 787                         print '
 788 HELP - The server sizelimit value indicates the maximum number of entries
 789        the server would return in respond to a query from the client.  A
 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
 799        MUST be used by clients to authenticate users to the system. Note 
 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 '
 809 HELP - The time to live value for profile.  The client will refresh its
 810        cached version of the configuration profile at this TTL interval.\n'


 811                         ;;
 812                 bindlim_help)
 813                         print '
 814 HELP - The time limit for the bind operation to the directory.  This
 815        value controls the responsiveness of the client in case a server
 816        becomes unavailable.  The smallest timeout value for a given
 817        network architecture/conditions would work best.  This is very
 818        similar to setting TCP timeout, but only for LDAP bind operation.\n'


 819                         ;;
 820                 ssd_help)
 821                         print '
 822 HELP - Using Service Search Descriptors (SSD), you can override the
 823        default configuration for a given service.  The SSD can be
 824        used to override the default search base DN, the default search
 825        scope, and the default search filter to be used for directory
 826        lookups.  SSD are supported for all services (databases)
 827        defined in nsswitch.conf(4). See also ldapclient(1M).

 828 
 829        Note: SSD are powerful tools in defining configuration profiles
 830              and provide a great deal of flexibility.  However, care
 831              must be taken in creating them.  If you decide to make use
 832              of SSDs, consult the documentation first.\n'


 833                         ;;
 834                 ssd_menu_help)
 835                         print '
 836 HELP - Using this menu SSD can be added, updated, or deleted from
 837        the profile.
 838 
 839        A - This option creates a new SSD by prompting for the
 840            service name, base DN, and scope.  Service name is
 841            any valid service as defined in ldap(1).  base is
 842            either the distinguished name to the container where
 843            this service will use, or a relative DN followed
 844            by a ",". For more information see ldapclient(1M).
 845        D - Delete a previously created SSD.
 846        M - Modify a previously created SSD.
 847        P - Display a list of all the previously created SSD.
 848        X - Delete all of the previously created SSD.
 849 
 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.









 855        The setup will add an administrator identity/credential
 856        and modify the necessary access controls for the client
 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.
 861 
 862        Shadow data is used for password aging and account locking.
 863        Please refer to the shadow(4) manual page for details.\n'


 864                         ;;
 865                 add_admin_cred_help)
 866                         print '
 867 HELP - Start the setup to add an administrator identity/credential
 868        and to modify access controls for the client to update
 869        shadow(4), auth_attr(4), exec_attr(4), prof_attr(4),
 870        user_attr(4), and project(4) data on the LDAP server.
 871 
 872        Shadow data is used for password aging and account locking.
 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
 879        access controls for allowing the client to update shadow(4) data
 880        on the LDAP server.
 881 
 882        Shadow data is used for password aging and account locking.
 883        Please refer to the shadow(4) manual page for details.\n'


 884                         ;;
 885         esac
 886 }
 887 
 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.]
 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] "
 900 
 901         read ANS?"${PROMPT}"
 902         [[ -z ${ANS} ]] && ANS="$2"

















 903 }
 904 
 905 
 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.]
 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 }
 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 }
 936 
 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.]
 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 }
 949 
 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:]
 954 {
 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=''
 965 
 966         get_ans "$1" "$2"
 967 
 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}
 976 }
 977 
 978 
 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:]






 981 {
 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.]
 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 }
 997 
 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:]




1000 {
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=''
1010 
1011         ${STTY} -echo                   # Turn echo OFF


1012 
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.
1023 
1024                 print
1025                 get_ans 'Re-enter password:'
1026                 _PASS2="${ANS}"

1027 
1028                 [[ ${_PASS1} == ${_PASS2} ]] && break
1029                 print -u2 && Log.warn "passwords don't match - try again"






1030         done
1031 
1032         ${STTY} echo                    # Turn echo ON
1033 
1034         print
1035 }
1036 
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:]




1039 {
1040     [+prompt?instruction/comment/description/question to show.]
1041     [+default?Default value to use if no answer/empty string was read.]
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 }
1053 
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:]











1056 {
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
1076 
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}



1083                 fi
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
1092 }
1093 
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:]





1096 {
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=''
1110 
1111         if [[ -z $2 ]]; then
1112                 Log.fatal "INTERNAL ERROR: ${.sh.fun} requires 2 args, 3rd is optional"




1113                 exit 2
1114         fi
1115 
1116         while : ; do
1117                 read _ANSWER?"$1 [$2] "
1118                 [[ -z ${_ANSWER} ]] && _ANSWER="$2"
1119 
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
1127 }
1128 
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:]




1131 {
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=''
1142 
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
1151 }
1152 ############################################################################
1153 # End of basic [menu] stuff
1154 ############################################################################
1155 
1156 
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 ; }
1168 
1169         while : ; do
1170                 get_ans "Enter the Directory Server's hostname to setup:" \
1171                         "${STR[DS_HOST]}" 
1172                 SRV="${ANS}"

1173 
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]}"






















1187 }
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'
1197 
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}"
1221 }
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
1262 
1263         TMP[DS_INFO]="${PROD} ${MAJOR} ${MINOR}"
1264 
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'
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
1284 }
1285 
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]}" )
1295 }
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


1304 
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]}" )
1310 
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.
1315 
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
1323 }
1324 
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}'"
1339     done
1340         STR[LDAP_DOMAIN]="${ANS}"
1341 }
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
1352 
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

1363 }
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
1374 
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
1402 }
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
1416 
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 }
1434 
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
1449 
1450         # NOTE: when fancy debug via trap is enabled, splitting via IFS does not
1451         # work: IFS=',' PAIRS=( $1 ) - so we do it manually












1452 
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
1468 
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 }
1476 
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]
1491 
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
1501 
1502         if (( NUM_TOP == 0 )); then
1503                 Log.verbose 'No suffix found in LDAP tree'
1504                 return 1



1505         fi
1506 
1507         Log.verbose "LDAP_SUFFIX_LIST = ${DST[@]}"
1508         return 0
1509 }
1510 
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.]
1518 }
1519 [+SEE ALSO?\bldapsearch\b(1).]
1520 '
1521 function get_backend {
1522         typeset CUR_DN=${STR[LDAP_BASEDN]} PREV_DN='' FILTER
1523 
1524         while [[ ${CUR_DN} != ${PREV_DN} ]]; do
1525                 typeset -a DB=( )
1526                 Log.verbose "Testing LDAP suffix: ${CUR_DN} ..."



1527 
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
1538 
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
1546 
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
1560 
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]}"
1570 
1571         Log.verbose "DB backend '${STR[DS_DB]}' selected"

1572 
1573         return 0

1574 }
1575 
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}"
1593 }
1594 
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.]
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
1606 
1607         # check that LDAP Base DN might be added
1608         typeset CUR_DN="${STR[LDAP_BASEDN]}" PREV_DN=''








1609 
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
1616 
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
1621         fi
1622 
1623         # find out existing suffixes
1624         typeset -a SUFFIXES=( )
1625         discover_serv_suffix SUFFIXES
1626 
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
1641 
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
1646         fi
1647         
1648         # Getting relevant database (backend)
1649         # DS_DB will then be used to create indexes.
1650         get_backend || return 67
1651 
1652         return 0
1653 }




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"
1662 
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 }
1678 
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
1692 }
1693 
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).]
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
1716 
1717         checkSuffixRDN || return 66
1718         Log.verbose "Suffix entry object: '${TMP[SUFFIX_OBJ]}'"





1719 
1720         TMPF[NEED_CREATE_BACKEND]=0




1721 
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
1734         else
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
1761         fi
1762 
1763         Log.verbose 'Backend needs to be created ...'
1764         TMPF[NEED_CREATE_BACKEND]=1
1765         return 0
1766 }
1767 
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.]
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
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
1807 
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
1825         done
1826 
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
1832 
1833         Log.warn 'Unable to find any available database backend close to' \
1834                 "'${STR[DS_DB]}'"
1835     return 2
1836 }
1837 
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.]
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
1865 
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
1889 
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
1899 }
1900 
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 }
1913 
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.]
1919 }
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
1925 
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
1936 
1937                 # Set base DN and check its suffix
1938                 STR[LDAP_BASEDN]="${ANS}"
1939                 check_basedn_suffix || return 66




1940 
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
1948 
1949                 # suffix is ok, break out of the base dn inquire loop
1950                 break
1951         done
1952         return 0
1953 }
1954 
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 }
1979 
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.]


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
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

2002 
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
2009 
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

2023 
2024     Log.verbose "Suffix: '${STR[LDAP_SUFFIX]}'   Database: '${STR[DS_DB]}'"
2025         return 0
2026 }
2027 
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.]















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
2041 
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'

















2054 
2055         # Check if the server supports the VLV
2056         chk_vlv_indexes || return 67
2057         Log.verbose 'VLV indexes ... ok'















2058 
2059         # Check LDAP suffix
2060         validate_suffix || return 66
2061         Log.verbose 'LDAP suffix ... ok'
2062         return 0







2063 }
2064 
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'
2085                 return
2086         fi
2087 
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}"
2096         else
2097                 Log.info 'GSSAPI is not set up - ' \
2098                         'sasl/GSSAPI bind may not work if it is not set up first'
2099         fi

2100 }







2101 
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
2108 
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
2116 
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
2124 
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.'
2130 
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
2140 
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
2148 
2149         STR[LDAP_PROFILE_NAME]="${ANS}"

2150 }
2151 
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.]
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'
2170 
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
2181         fi
2182         return 0
2183 }
2184 
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.]
2190 }
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
2206 }
2207 
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.]

















2214 }
2215 [+SEE ALSO?\bgetACIs()\b, \bldapmodify\b(1).]
2216 '
2217 function allow_proxy_read_pw {
2218         typeset ACI PATTERN TARGET
2219 
2220         typeset -a LIST=( )
2221         getACIs LIST || return 66
2222 
2223         PATTERN='acl[ ]+"?('"${PROXY_ACI_NAME}|${PROXY_ACI_NAME// /_}"')"?'
2224         findACI LIST "${PROXY_ACI_NAME}" "${PATTERN}" || return 0





2225 
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=''
2232         else
2233                 TARGET='(target = "ldap:///'"${STR[LDAP_BASEDN]}"'")'
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
2254 
2255         showProgress "ACI '${PROXY_ACI_NAME}' added."
2256         return 0

















2257 }
2258 
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.]
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
2270 
2271         typeset -a LIST=( )
2272         getACIs LIST || return 66





2273 
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
2280 
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.
2298 
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}"
2315 
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]}"



















2320         fi
2321 
2322         nextFile modify $0
2323         print '
2324 dn: '"${STR[LDAP_BASEDN]}"'
2325 changetype: modify
2326 delete: aci
2327 aci: '"${PROXY_ACI}"'
2328 '               >${TMP[FILE]}
2329 
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
2336         fi
2337 
2338     Log.info "Removed '${PROXY_ACI_NAME}' ACI"
2339         return 0
2340 }
2341 
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.]






2348 }
2349 [+SEE ALSO?\bgetACIs()\b, \bldapmodify\b(1).]
2350 '
2351 function allow_host_read_write_shadow {
2352         typeset ACI PATTERN TARGET=''
2353 
2354         typeset -a LIST=( )
2355         getACIs LIST || return 66
2356 
2357         PATTERN='acl[ ]+"?('"${HOST_ACI_NAME}|${HOST_ACI_NAME// /_}"')"?'
2358         findACI LIST "${HOST_ACI_NAME}" "${PATTERN}" || return 0











2359 
2360         (( ! TMPF[IS_OPENDJ] )) && \
2361                 TARGET='(target = "ldap:///'"${STR[LDAP_BASEDN]}"'")'   # OD: redundant

2362 
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

2381 
2382         showProgress "ACI '${ACI_NAME}' added."
2383         return 0
2384 }
2385 
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.]







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
2398 
2399         for ACI in "${LIST[@]}" ; do
2400                 [[ ${ACI} =~ ${REGEX} ]] && DEL="${ACI}" && break
2401         done
2402         [[ -z ${DEL} ]] && return 0
2403 
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]}

2411 
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










2417         fi




2418 
2419         showProgress "ACI '${ACI_NAME}' deleted."
2420         return 0
2421 }

2422 
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.]





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=''
2434 
2435         typeset -a LIST=( )
2436         getACIs LIST || return 66
2437 
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





2441 
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
2446 
2447         (( ! TMPF[IS_OPENDJ] )) && \
2448                 TARGET='(target = "ldap:///'"${STR[LDAP_BASEDN]}"'")'   # OD: redundant


2449 
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




2467         fi

2468 
2469         showProgress "ACI '${NON_HOST_ACI_NAME}' added."
2470         return 0


2471 }
2472 
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 }
2482 
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}"
2490 }
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




2507 
2508         typeset CN="${STR[LDAP_ADMINDN]%%,*}"
2509         CN="${CN#*=}"


2510 
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]}
2520 
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
2526         fi

2527 
2528         showProgress 'Administrator identity added.'
2529         return 0






2530 }
2531 
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.]


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=''
2544 
2545         typeset -a LIST=( )
2546         getACIs LIST || return 66
2547 
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




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
2558 
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
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'
2573 
2574         (( ! TMPF[IS_OPENDJ] )) && \
2575                 TARGET='(target = "ldap:///'"${STR[LDAP_BASEDN]}"'")'   # OD: redundant




2576 
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
2594         fi
2595 
2596         showProgress "ACI '${ADMIN_ACI_NAME}' added."
2597         return 0
2598 }
2599 
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.]














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
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
2617 
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


2622 
2623         (( ! TMPF[IS_OPENDJ] )) && \
2624                 TARGET='(target = "ldap:///'"${STR[LDAP_BASEDN]}"'")'   # OD: redundant
2625 
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
2645 
2646         showProgress "ACI '${NON_ADMIN_ACI_NAME}' added."
2647         return 0

2648 }
2649 
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.]
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
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
2677 
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]}"
2684 
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
2698 
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 }
2715 
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
2729 
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 }
2739 
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 }
2754 
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.]
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 }
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]:'
2783 
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 }

2789 
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.]

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}
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
2828 
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"
2845 
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
2863 }
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 }
2874 
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.]




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
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



2906 
2907         INT[DS_TIMELIMIT]=${NUM}
2908         return 0


2909 }
2910 
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.]
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
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]
2937 
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
2942 }
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 }
2953 
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 }
2963 
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}



2972 }
2973 
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}

2982 }
2983 
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]=$?
2992 }
2993 
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
3006 
3007         while : ; do
3008                 get_ans 'Enter the service name (e.g. passwd):'
3009                 [[ -z ${ANS} ]] && return
3010                 [[ ${ANS} =~ [:] ]] && print 'Invalid service name' && continue








3011 
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}"
3020     
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}"




3027 
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

3034 
3035         SSD+=( "${ID}:${BASE}?${SCOPE}" )









3036 }
3037 
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
3046 
3047         typeset X
3048         integer I FOUND=-1 MAX=${#SSD[@]}
3049 
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








3057         fi
3058         (( FOUND == 0 )) && unset SSD[0] && return

3059 
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 }
3067 
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
3076     
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
3088 
3089         # most users expect emacs edit behavior (don't have a proper profile)
3090         set -o emacs
3091         read -v X?'Current SSD: '





3092 
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
3103         fi
3104         SSD[${FOUND}]="${ID}:${BASE}?${SCOPE}"
3105 }
3106 
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 }
3115 
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
3130 }
3131 
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'







3140         then





















3141                 return
3142         fi

3143 
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 }
3164 
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.]
3174 }
3175 '
3176 function prompt_config_info {
3177         # Prompt for DS server name
3178         get_ids_server
3179 
3180         # Prompt for DS port number
3181         get_ids_port
3182 
3183         # Check DS version for compatibility
3184         chk_ids_version || return 66
3185 
3186         # Check if the DS supports the VLV
3187         chk_vlv_indexes || return 67
3188 
3189         # Get the Directory manager DN and passwd
3190         get_dirmgr_dn
3191         get_dirmgr_pw
3192 
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
3198 
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
3204 
3205 
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
3210 
3211         # Check/Get Kerberos infos
3212     gssapi_setup
3213 
3214     get_profile_name
3215 
3216         if (( INT[LDAP_ENABLE_SHADOW_UPDATE] ));then
3217                 setup_shadow_update || return 69
3218                 return 0

3219         fi
3220 
3221         get_srv_list
3222         get_pref_srv
3223         get_search_scope







3224     get_followref
3225 
3226         # Store passwords in crypt format?










3227         get_want_crypt
3228 
3229         # If cred is "anonymous", make auth == "none"
3230         get_cred_level
3231         [[ ${STR[LDAP_CRED_LEVEL]} != anonymous ]] && get_auth 'client'




3232 
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'
3238 
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'
3242 
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
3247 
3248         # Get client timeouts

3249         get_srch_time
3250         get_prof_ttl
3251         get_bind_limit
3252 

3253         get_want_shadow_update
3254 
3255         reset_ssd


3256         prompt_ssd
3257 
3258         show_vars

3259 
3260         Log.printMarker
3261         return 0
3262 }
3263 ######################################################################
3264 # End Of FUNCTIONS FOR prompt_config_info()
3265 ######################################################################
3266 
3267 
3268 ######################################################################
3269 # FUNCTIONS  FOR display_summary() START HERE.
3270 ######################################################################
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}"
3281 }
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' )
3298 
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-- ))




3303 
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










3311 
3312                 # Call appropriate function from function table
3313                 ${FN[RES]}


















3314         done
3315 
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
3327 
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
3341         fi
3342 
3343         show_vars

3344 
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


3350         fi
3351 
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
3380         fi
3381 
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]}
3389 
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 }









3400 
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.]
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'
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]}












3420 
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
3427 
3428         showProgress "Changed ${NAME} to ${INT[DS_TIMELIMIT]} in 'cn=config'."
3429         return 0



























3430 }
3431 
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'
3443 
3444         nextFile modify $0
3445         print '
3446 dn: cn=config
3447 changetype: modify
3448 replace: '"${NAME}"'
3449 '"${NAME}"': '"${INT[DS_SIZELIMIT]}"'
3450 '               > ${TMP[FILE]}










3451 
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

3458 
3459         showProgress "Changed ${NAME} to ${INT[DS_SIZELIMIT]} in 'cn=config'."
3460         return 0
3461 }




3462 
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
3477 
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'"
3489 
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
3500 
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
3507 
3508         showProgress "${MSG}."
3509         return 0
3510 }




















3511 
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.]
3517 }
3518 [+SEE ALSO?\bldapmodify\b(1), \bgetDSattributes()\b.]
3519 '
3520 function update_schema_attr {
3521 
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'
3530 
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
3546 
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













3549 
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

3552 
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'"


3555 
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'"









3558 
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'"










3561 
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'"





3564 
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'"


3567 
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'"










3570 
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'"










































3573 
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'"
3576 
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












3579 
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







3582 
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



3585 
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











3588 
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
3591 
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


3594 
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










3597 
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'"
3600 
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



3603 
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'"

3606 
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










3609 
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'"
3612 
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








3615 
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










3618 
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

3621 
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









3624 
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


3627 
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












3630 
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








3633 
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

3636 
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












3639 
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


3642 
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'"




3645 
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














3648 
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









3651 
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
3654 
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'"
3657 
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'"
3660 
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'"













3663 
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'"
3666 
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'"
3669 
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'"
3672 
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'"






























3675 
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'"
3678 
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'"




3681 
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

3684 
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'"

3687 
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'"






3690 
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














3693 
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

3696 
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
3699 
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




3702 
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





3705 
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'"






3708 
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'"
3711 
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'"


3714 
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'"






3717 
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'"





3720 
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'"


3723 
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'"
3726 
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'"


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'"






3732 
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'"





3735 
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'"


3738 
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'"
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'"


3744 
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'"

















3747 
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'"





3750 
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'"


3753 
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'"
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'"




3759 
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'"
3762 
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'"

3765 
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'"
3768 
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'"

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'"

3774 
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'"






3777 
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'"









3780 
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'"





3783 
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'"





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'"
3789 
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'"









3792 
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'"





3795 
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'"

















3798 
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'"


3801 
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'"
3804 
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'"




3807 
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'"
3810 
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'"
3813 
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'"
3816 
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'"

3819 
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'"

3822 
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'"






3825 
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
3838         fi
3839 
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}"
3849         done
3850 
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
3867 }






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
3879 
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'"
3884 
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'"




3887 
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'"






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'"













3893 
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'"
3896 
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'"
3899 
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'"
3902 
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'"
3905 
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'"

3908 
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'"



3911 
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'"
3914 
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'"
3917 
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'"



3920 
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'"

3923 
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'"



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'"
3929 
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'"





3932 
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' )"




3935 
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'"








3938 
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'"





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'"





3944 
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'"
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'"



3950 
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'"
3953 
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'"







3956 
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'"
3959 
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
3970 
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
3977 
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
3996 
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'













4007         fi
4008 
4009         showProgress "${X}."
4010         return 0







4011 }
4012 
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]}"'
4078 
4079 dn: cn='"${STR[DS_DB]}"',cn=ldbm database,cn=plugins,cn=config
4080 objectclass: top
4081 objectclass: extensibleObject
4082 objectclass: nsBackendInstance
4083 cn: '"${STR[DS_DB]}"'
4084 nsslapd-suffix: '"${STR[LDAP_SUFFIX]}"'
4085 '                               >${TMP[FILE]}
4086                 fi





























































































4087 
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."
4096         fi
4097 
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
4118 }
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 ?
4125 
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'
4139 
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'
4156 
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
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         )
4191 
4192         # Check and set if doesn't already exist
4193         typeset -a LIST=( )
4194         getACIs LIST "${STR[LDAP_SUFFIX]}"

4195 
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
4217 }
4218 
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.]
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
4231 
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 ; }

4235 
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}
4244 
4245         # Remove redundant spaces around ',' and '=' first from LDAP_BASEDN
4246         typeset DN=${ normalizeDN ${STR[LDAP_BASEDN]} ; }


4247 
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}}"

4251 
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
4277 
4278                         nextFile add "${0}-${LAST}"
4279                     print '
4280 dn: '"${LAST}"'
4281 '"${KEY}: ${VAL}"'
4282 objectClass: top
4283 objectClass: '"${CLASS}"'
4284 '                               > ${TMP[FILE]}
4285 
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 }
4297 
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
4317 
4318         nextFile modify $0
4319         print '
4320 dn: '"${STR[LDAP_BASEDN]}"'
4321 changetype: modify
4322 objectclass: nisDomainObject
4323 nisdomain: '"${STR[LDAP_DOMAIN]}"'
4324 '               >${TMP[FILE]}
4325 
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
4332 
4333         showProgress "NisDomainObject added to '${STR[LDAP_BASEDN]}'."
4334         return 0
4335 }

4336 
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
4347 
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
4359 
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]}
4367 
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
4376 
4377         return 0
4378 }


4379 
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
4391 
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
4401 
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
4418 
4419         return 0


4420 }
4421 
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
4433 
4434         typeset -a LIST=( )
4435         getACIs LIST || return 66
4436 
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











4440 
4441         # Create LDIF for top level ACI
4442         nextFile modify $0
4443         print '
4444 dn: '"${STR[LDAP_BASEDN]}"'
4445 changetype: modify
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]}
4453 
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
4460 
4461         showProgress "Self modify for non-password attributes disabled."
4462         return 0






4463 }
4464 
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'
4480 
4481         typeset -a LIST=( )
4482         getACIs LIST "${DN}" 'Global' || return 66


4483 
4484         PATTERN='acl[ ]+"?('"${VLV_ACI_NAME}|${VLV_ACI_NAME// /_}"')"?'
4485         findACI LIST "${VLV_ACI_NAME}" "${PATTERN}" 'Global' || return 0






4486 
4487         nextFile modify $0
4488         if (( TMPF[IS_OPENDJ] )); then
4489                 print '
4490 dn: '"${DN}"'
4491 changetype: modify
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}"'
4501 changetype: modify
4502 replace: aci
4503 aci: (targetattr != "aci")
4504  (
4505         '"${RULE}"'
4506  )
4507 '               > ${TMP[FILE]}
4508         fi
4509 
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
4516 
4517         showProgress "Global ACI '${VLV_ACI_NAME}' added."
4518         return 0
4519 }
4520 
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.]
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
4537 
4538         # Get cn and sn names from LDAP_PROXYAGENT.
4539         typeset NAME="${STR[LDAP_PROXYAGENT]%%,*}"
4540         NAME=${NAME#*=}
4541 
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
4559 
4560         showProgress 'Proxyagent identity added.'
4561         return 0
4562 }
4563 
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
4579     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
4587 }
4588 
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
4602 
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



4611 
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]}
4647         fi
4648         add_entry_by_DN "${H_DN}" ${TMP[FILE]}
4649 
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]}
4667         else
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]}
4679         fi
4680         add_entry_by_DN "${U_DN}" ${TMP[FILE]}
4681 }
4682 
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]}"
4694 
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"
4699 
4700                 nextFile add $0
4701                 print '
4702 dn: '"${P_DN}"'
4703 ou: People
4704 objectClass: top
4705 objectClass: organizationalUnit
4706 '                       > ${TMP[FILE]}
4707 
4708                 add_entry_by_DN "${P_DN}" ${TMP[FILE]}





4709         else 
4710                 Log.verbose "'${P_DN}' already exists"

4711         fi
4712         typeset TARGET='userPassword' PATTERN
4713         (( TMPF[IS_OPENDJ] )) && TARGET+=' || authPassword'
4714 
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         )
4727 
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}"'
4739 changetype: modify
4740 add: aci
4741 '"${RULES[${ACI}]}"'
4742 '                       > ${TMP[FILE]}





4743 
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
4753 }
4754 
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
4789 
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
4800         fi
4801 
4802         # Build the "ldapclient genprofile" command string to execute
4803         typeset -a ARG=( )
4804         ARG+=( genprofile '-a' "profileName=${STR[LDAP_PROFILE_NAME]}" )

4805 
4806         # Add required argument defaultSearchBase
4807         ARG+=( -a "defaultSearchBase=${STR[LDAP_BASEDN]}" )
4808 
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]}")
4834 
4835         # Add SSDs
4836         typeset X
4837         for X in "${SSD[@]}" ; do
4838                 ARG+=( -a "serviceSearchDescriptor=${X}" )
4839         done




4840 
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
4848 
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
4856 
4857         showProgress 'Client profile generated and pushed to the DS.'


4858         return 0

4859 }
4860 
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.]
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 }
4901 
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.]




















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" ; }
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
4921 
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
4932 
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




















4954 
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
4961 
4962         checkTaskCompletion "${DN}" && print "" || { Log.warn 'FAILED'; return 2; }
4963         return 0
4964 }
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
4981 
4982         typeset -l TYPES=${1//,/ }              # we allow comma separated lists as well
4983         typeset IDX=${2//,/ }
4984 
4985     Log.verbose "Processing '${TYPES// /,}' indexes ..."




4986 
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
5002 
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
5021         fi
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
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}"'
5040 
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 }
5068 
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 }
5081 
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 }
5094 
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
5108 
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"



5111 
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}"'
5119 objectClass: top
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
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}"
5141 
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
5149 
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}"'"
5157 
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]}
5172 
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
5187         done
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
5199 }
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
5209 
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"
5227 
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}"




5238 
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
5246 
5247                 nextFile add "${0}-${IDX_NAME}"
5248                 print '
5249 dn: '"cn=${CN},${BACKEND}"'
5250 objectClass: top
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  )
5261 
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]}
5268 
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
5287 }
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 ...'
5299 
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         )
5325 
5326     # temp file for vlvindex commands
5327         typeset OUT=${TMP[DIR]}/tmp
5328         rm -f ${OUT} && touch ${OUT}





5329 
5330         if (( TMPF[IS_OPENDJ] )); then
5331                 add_vlv_indexes_OpenDJ INDEXES ${OUT}









5332         else
5333                 add_vlv_indexes_DSEE INDEXES ${OUT}
5334         fi
5335         nextFile sh
5336         mv ${OUT} ${TMP[FILE]}
5337         TMP[VLV_CMDS]=${TMP[FILE]}
5338 }
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"
5345 
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}"
5350 
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

















5376     fi
5377         Log.info "\n\n${MSG}"






5378 }
5379 
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
5388 
5389         # Print extra line to separate from prompt
5390         print






5391 
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
5400 
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

5413 
5414         if (( INT[NEED_TIME] )); then
5415                 modify_timelimit || return 1

































5416         fi
5417 
5418         if (( INT[NEED_SIZE] )); then
5419                 modify_sizelimit || return 1




5420         fi
5421 
5422         # Modify the password storage scheme to support CRYPT
5423         if (( INT[NEED_CRYPT] )); then
5424                 modify_pwd_crypt || return 1



5425         fi
5426 
5427         # schema modifications
5428         modify_cn || return 1
5429         update_schema_attr || return 1
5430         update_schema_obj || return 1
5431 
5432         add_suffix || return 1
5433 
5434         # Add missing suffix ACIs
5435         add_suffix_aci || return 1




5436 
5437         # Add base objects (if needed)
5438         add_base_objects || return 1
5439 
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
5444 
5445         # Add top level classes (new containers)
5446         add_new_containers || return 1







5447 
5448         add_auto_maps || return 1


5449 
5450         modify_top_aci || return 1


5451 
5452         add_vlv_aci || return 1

5453 
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
5460 
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
5465         fi
5466 
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
5478         fi
5479 
5480         if (( INT[NEED_HOSTACL] )); then
5481                 allow_host_read_write_shadow || return 66
5482                 deny_non_host_shadow_access || return 67
5483         fi
5484 


5485 
5486         # Generate client profile and add it to the server
5487         add_profile || return 1


5488 
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

5493 
5494         # Display setup complete message
5495         Log.printMarker
5496         Log.info 'Setup of DS server' "'${STR[DS_HOST]}'" 'is complete.'
5497         Log.printMarker


5498 
5499         # Display VLV index commands to be executed on server (if any)
5500         display_vlv_cmds
5501 
5502         # Create final config file if requested
5503         [[ -n ${TMP[OUT]} ]] && create_config_file "${TMP[OUT]}"
5504         return 0
5505 }
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 }
5537 
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'
5545 }
5546 
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]
5570 }
5571 '
5572 
5573 TMPF[DEBUG]=0 TMPF[KEEP]=0 TMPF[FD]=4

5574 
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
5613 
5614 unset LC_ALL LC_LANG
5615 export LC_CTYPE=C       # avoid any surprises
5616 
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
5622 fi
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]
5630 fi
5631 
5632 # Prevent new files from being read by group or others
5633 umask 077
5634 
5635 doMain
5636 X=$?
5637 
5638 cleanup NOKILL



5639 
5640 exit ${X}

5641 
5642 # vim:ts=4 filetype=sh
5643 # :syntax sync fromstart