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#
31display_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
39EOF
40    ;;
41    backup_server) cat <<EOF
42It is strongly recommended that you BACKUP the directory server
43before running $PROG.
44
45Hit Ctrl-C at any time before the final confirmation to exit.
46
47EOF
48    ;;
49    setup_complete) cat <<EOF
50
51$PROG: Setup of iDS server ${IDS_SERVER} is complete.
52
53EOF
54    ;;
55    display_vlv_list) cat <<EOF
56
57Note: idsconfig has created entries for VLV indexes. 
58
59      For DS5.x, use the directoryserver(8) 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
67EOF
68    ;;
69    cred_level_menu) cat <<EOF
70The following are the supported credential levels:
71  1  anonymous
72  2  proxy
73  3  proxy anonymous
74  4  self
75EOF
76    ;;
77    auth_method_menu) cat <<EOF
78The 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
85EOF
86    ;;
87    srvauth_method_menu) cat <<EOF
88The 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
94EOF
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
105EOF
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
117EOF
118`
119		[ -n "${NEED_CREATE_BACKEND}" ] &&
120			DB_INFO=`cat <<EOF
121
122         Database to create        : $IDS_DATABASE
123EOF
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
151EOF
152    ;;
153    sfx_not_suitable) cat <<EOF
154
155Sorry, suffix ${LDAP_SUFFIX} is not suitable for Base DN ${LDAP_BASEDN}
156
157EOF
158    ;;
159    obj_not_found) cat <<EOF
160
161Sorry, ${PROG} can't find an objectclass for "$_ATT" attribute
162
163EOF
164    ;;
165    sfx_config_incons) cat <<EOF
166
167Sorry, there is no suffix mapping for ${LDAP_SUFFIX},
168while ldbm database exists, server configuration needs to be fixed manually,
169look at cn=mapping tree,cn=config and cn=ldbm database,cn=plugins,cn=config
170
171EOF
172    ;;
173    ldbm_db_exist) cat <<EOF
174
175Database "${IDS_DATABASE}" already exists,
176however "${IDS_DATABASE_AVAIL}" name is available
177
178EOF
179    ;;
180    unable_find_db_name) cat <<EOF
181    
182Unable to find any available database name close to "${IDS_DATABASE}"
183
184EOF
185    ;;
186    create_ldbm_db_error) cat <<EOF
187
188ERROR: unable to create suffix ${LDAP_SUFFIX}
189       due to server error that occurred during creation of ldbm database
190
191EOF
192    ;;
193    create_suffix_entry_error) cat <<EOF
194
195ERROR: unable to create entry ${LDAP_SUFFIX} of ${LDAP_SUFFIX_OBJ} class
196
197EOF
198    ;;
199    ldap_suffix_list) cat <<EOF
200
201No valid suffixes (naming contexts) were found for LDAP base DN:
202${LDAP_BASEDN}
203
204Available suffixes are:
205${LDAP_SUFFIX_LIST}
206
207EOF
208    ;;
209    sorry) cat <<EOF
210
211HELP - No help is available for this topic.
212
213EOF
214    ;;
215    create_suffix_help) cat <<EOF
216
217HELP - 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
222EOF
223    ;;
224    enter_ldbm_db_help) cat <<EOF
225
226HELP - ldbm database is an internal database for storage of our suffix data.
227       Database name must be alphanumeric due to Directory Server restriction.
228
229EOF
230    ;;
231    backup_help) cat <<EOF
232
233HELP - 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
238EOF
239    ;;
240    port_help) cat <<EOF
241
242HELP - Enter the port number the directory server is configured to
243       use for LDAP.
244
245EOF
246    ;;
247    domain_help) cat <<EOF
248
249HELP - 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
254EOF
255    ;;
256    basedn_help) cat <<EOF
257
258HELP - 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
263EOF
264    ;;
265    profile_help) cat <<EOF
266
267HELP - 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(8)), assumes 
270       "default" unless another is specified.
271
272EOF
273    ;;
274    def_srvlist_help) cat <<EOF
275
276HELP - 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
282EOF
283    ;;
284    pref_srvlist_help) cat <<EOF
285
286HELP - 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
295EOF
296    ;;
297    srch_scope_help) cat <<EOF
298
299HELP - 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
306EOF
307    ;;
308    cred_lvl_help) cat <<EOF
309
310HELP - 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
317EOF
318    ;;
319    auth_help) cat <<EOF
320
321HELP - 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
327EOF
328    ;;
329    srvauth_help) cat <<EOF
330
331HELP - 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
338EOF
339    ;;
340    pam_ldap_help) cat <<EOF
341
342HELP - 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
346EOF
347    ;;
348    keyserv_help) cat <<EOF
349
350HELP - The authentication method(s) to be used by newkey(8) 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
355EOF
356    ;;
357    passwd-cmd_help) cat <<EOF
358
359HELP - 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
363EOF
364    ;;
365    referrals_help) cat <<EOF
366
367HELP - This parameter indicates whether the client should follow
368       ldap referrals if it encounters one during naming lookups.
369
370EOF
371    ;;
372    tlim_help) cat <<EOF
373
374HELP - 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
378EOF
379    ;;
380    slim_help) cat <<EOF
381
382HELP - 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
386EOF
387    ;;
388    crypt_help) cat <<EOF
389
390HELP - 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
398EOF
399    ;;
400    srchtime_help) cat <<EOF
401
402HELP - The search time limit the client will enforce for directory
403       lookups.
404
405EOF
406    ;;
407    profttl_help) cat <<EOF
408
409HELP - The time to live value for profile.  The client will refresh its
410       cached version of the configuration profile at this TTL interval.
411
412EOF
413    ;;
414    bindlim_help) cat <<EOF
415
416HELP - 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
422EOF
423    ;;
424    ssd_help) cat <<EOF
425
426HELP - 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(5).  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
439EOF
440    ;;
441    ssd_menu_help) cat <<EOF
442
443HELP - 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
459EOF
460    ;;
461    ldap_suffix_list_help) cat <<EOF
462
463HELP - 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
468EOF
469    ;;
470    enable_shadow_update_help) cat <<EOF
471
472HELP - 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(5) 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(5) manual page for details.
481
482EOF
483    ;;
484    add_admin_cred_help) cat <<EOF
485
486HELP - Start the setup to add an administrator identity/credential
487       and to modify access controls for the client to update
488       shadow(5) data on the LDAP server.
489
490       Shadow data is used for password aging and account locking.
491       Please refer to the shadow(5) manual page for details.
492
493EOF
494    ;;
495    use_host_principal_help) cat <<EOF
496
497HELP - 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(5) data
500       on the LDAP server.
501
502       Shadow data is used for password aging and account locking.
503       Please refer to the shadow(5) manual page for details.
504
505EOF
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#
516get_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#
537get_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#
555get_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.
584get_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#
607get_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#
656get_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#
681get_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#
711get_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#
746get_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#
768is_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#
793not_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#
810is_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#
835check_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#
859check_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#
904domain_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#
928is_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#
941parse_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#
964init()
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/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#
1100disp_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#
1153load_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#
1182save_password()
1183{
1184    cat > ${LDAP_ROOTPWF} <<EOF
1185${LDAP_ROOTPWD}
1186EOF
1187}
1188
1189######################################################################
1190# FUNCTIONS  FOR prompt_config_info() START HERE.
1191######################################################################
1192
1193#
1194# get_ids_server(): Prompt for iDS server name.
1195#
1196get_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#
1225get_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#
1256chk_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#
1284get_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#
1299get_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#
1338get_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#
1365get_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#
1413get_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
1424get_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
1435add_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#
1458add_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
1464dn: cn=GSSAPI,cn=identity mapping,cn=config
1465objectClass: top
1466objectClass: nsContainer
1467cn: GSSAPI
1468EOF
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
1481dn: ${_H_DN}
1482objectClass: top
1483objectClass: nsContainer
1484objectClass: dsIdentityMapping
1485objectClass: dsPatternMatching
1486cn: ${_H_CN}
1487dsMatching-pattern: \${Principal}
1488dsMatching-regexp: host\/(.*).${LDAP_DOMAIN}@${LDAP_KRB_REALM}
1489dsSearchBaseDN: ou=hosts,${LDAP_BASEDN}
1490dsSearchFilter: (&(objectClass=ipHost)(cn=\$1))
1491dsSearchScope: one
1492
1493EOF
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
1501dn: ${_U_DN}
1502objectClass: top
1503objectClass: nsContainer
1504objectClass: dsIdentityMapping
1505objectClass: dsPatternMatching
1506cn: ${_U_CN}
1507dsMatching-pattern: \${Principal}
1508dsMatching-regexp: (.*)@${LDAP_KRB_REALM}
1509dsMappedDN: uid=\$1,ou=People,${LDAP_BASEDN}
1510
1511EOF
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#
1523modify_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
1534dn: ${_P_DN}
1535ou: People
1536objectClass: top
1537objectClass: organizationalUnit
1538EOF
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
1563dn: ${_P_DN}
1564changetype: modify
1565add: aci
1566aci: (targetattr="userPassword")(version 3.0; acl self-read-pwd; allow (read,search) userdn="ldap:///self" and authmethod="sasl GSSAPI";)
1567-
1568add: aci
1569aci: (targetattr="userPassword")(version 3.0; acl host-read-pwd; allow (read,search) userdn="ldap:///cn=*+ipHostNumber=*,ou=Hosts,${LDAP_BASEDN}" and authmethod="sasl GSSAPI";)
1570EOF
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
1592search_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#
1610gssapi_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#
1639get_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
1663Profile '${ANS}' already exists, it is possible to enable
1664shadow update now. idsconfig will exit after shadow update
1665is enabled. You can also continue to overwrite the profile 
1666or create a new one and be given the chance to enable
1667shadow update later.
1668
1669EOF
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#
1703get_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#
1731get_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#
1750get_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#
1776get_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#
1808srvauth_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#
1848auth_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#
1894get_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#
1932get_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#
1946get_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#
1965get_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#
1984get_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#
2000get_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#
2049get_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#
2098get_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#
2145get_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#
2155get_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#
2165get_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#
2180add_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#
2226delete_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#
2256modify_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#
2308display_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#
2325prompt_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#
2356reset_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#
2368create_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#
2382ssd_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#
2394ssd_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#
2414get_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#
2425get_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#
2435add_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
2457dn: ${LDAP_ADMINDN}
2458cn: ${cn_tmp}
2459sn: ${cn_tmp}
2460objectclass: top
2461objectclass: person
2462userpassword: ${LDAP_ADMIN_CRED}
2463EOF
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#
2490allow_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
2523dn: ${LDAP_BASEDN}
2524changetype: modify
2525add: aci
2526aci: (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}";)
2531EOF
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#
2557allow_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
2580dn: ${LDAP_BASEDN}
2581changetype: modify
2582add: aci
2583aci: (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}";)
2584EOF
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#
2608setup_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#
2674prompt_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#
2786get_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#
2797get_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#
2807display_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#
2897create_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#
2913IDS_SERVER="$IDS_SERVER"
2914IDS_PORT=$IDS_PORT
2915IDS_TIMELIMIT=$IDS_TIMELIMIT
2916IDS_SIZELIMIT=$IDS_SIZELIMIT
2917LDAP_ROOTDN="$LDAP_ROOTDN"
2918LDAP_ROOTPWD=$LDAP_ROOTPWD
2919LDAP_DOMAIN="$LDAP_DOMAIN"
2920LDAP_SUFFIX="$LDAP_SUFFIX"
2921GSSAPI_ENABLE=$GSSAPI_ENABLE
2922LDAP_KRB_REALM="$LDAP_KRB_REALM"
2923
2924# Internal program variables that need to be set.
2925NEED_PROXY=$NEED_PROXY
2926NEED_TIME=$NEED_TIME
2927NEED_SIZE=$NEED_SIZE
2928NEED_CRYPT=$NEED_CRYPT
2929NEED_ADMIN=$NEED_ADMIN
2930NEED_HOSTACL=$NEED_HOSTACL
2931EXISTING_PROFILE=$EXISTING_PROFILE
2932
2933# LDAP PROFILE related defaults
2934LDAP_PROFILE_NAME="$LDAP_PROFILE_NAME"
2935DEL_OLD_PROFILE=1
2936LDAP_BASEDN="$LDAP_BASEDN"
2937LDAP_SERVER_LIST="$LDAP_SERVER_LIST"
2938LDAP_AUTHMETHOD="$LDAP_AUTHMETHOD"
2939LDAP_FOLLOWREF=$LDAP_FOLLOWREF
2940LDAP_SEARCH_SCOPE="$LDAP_SEARCH_SCOPE"
2941NEED_SRVAUTH_PAM=$NEED_SRVAUTH_PAM
2942NEED_SRVAUTH_KEY=$NEED_SRVAUTH_KEY
2943NEED_SRVAUTH_CMD=$NEED_SRVAUTH_CMD
2944LDAP_SRV_AUTHMETHOD_PAM="$LDAP_SRV_AUTHMETHOD_PAM"
2945LDAP_SRV_AUTHMETHOD_KEY="$LDAP_SRV_AUTHMETHOD_KEY"
2946LDAP_SRV_AUTHMETHOD_CMD="$LDAP_SRV_AUTHMETHOD_CMD"
2947LDAP_SEARCH_TIME_LIMIT=$LDAP_SEARCH_TIME_LIMIT
2948LDAP_PREF_SRVLIST="$LDAP_PREF_SRVLIST"
2949LDAP_PROFILE_TTL=$LDAP_PROFILE_TTL
2950LDAP_CRED_LEVEL="$LDAP_CRED_LEVEL"
2951LDAP_BIND_LIMIT=$LDAP_BIND_LIMIT
2952
2953# Proxy Agent
2954LDAP_PROXYAGENT="$LDAP_PROXYAGENT"
2955LDAP_PROXYAGENT_CRED=$LDAP_PROXYAGENT_CRED
2956
2957# enableShadowUpdate flag and Administrator credential
2958LDAP_ENABLE_SHADOW_UPDATE=$LDAP_ENABLE_SHADOW_UPDATE
2959LDAP_ADMINDN="$LDAP_ADMINDN"
2960LDAP_ADMIN_CRED=$LDAP_ADMIN_CRED
2961
2962# Export all the variables (just in case)
2963export IDS_HOME IDS_PORT LDAP_ROOTDN LDAP_ROOTPWD LDAP_SERVER_LIST LDAP_BASEDN
2964export LDAP_DOMAIN LDAP_SUFFIX LDAP_PROXYAGENT LDAP_PROXYAGENT_CRED
2965export NEED_PROXY
2966export LDAP_ENABLE_SHADOW_UPDATE LDAP_ADMINDN LDAP_ADMIN_CRED
2967export NEED_ADMIN NEED_HOSTACL EXISTING_PROFILE
2968export LDAP_PROFILE_NAME LDAP_BASEDN LDAP_SERVER_LIST 
2969export LDAP_AUTHMETHOD LDAP_FOLLOWREF LDAP_SEARCH_SCOPE LDAP_SEARCH_TIME_LIMIT
2970export LDAP_PREF_SRVLIST LDAP_PROFILE_TTL LDAP_CRED_LEVEL LDAP_BIND_LIMIT
2971export NEED_SRVAUTH_PAM NEED_SRVAUTH_KEY NEED_SRVAUTH_CMD
2972export LDAP_SRV_AUTHMETHOD_PAM LDAP_SRV_AUTHMETHOD_KEY LDAP_SRV_AUTHMETHOD_CMD
2973export LDAP_SERV_SRCH_DES SSD_FILE GSSAPI_ENABLE LDAP_KRB_REALM
2974
2975# Service Search Descriptors start here if present:
2976EOF
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#
2992chk_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#
3019get_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#
3072validate_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#
3138validate_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#
3179format_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#
3194prep_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
3229aci: (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 )
3237aci: (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 )
3247aci: (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 )
3254aci: (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 )
3261EOF
3262`
3263    }
3264    [ $DEBUG -eq 1 ] && cat <<EOF
3265DEBUG: ACI for ${LDAP_SUFFIX} is
3266${LDAP_SUFFIX_ACI}
3267EOF
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#
3312prep_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#
3358add_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
3367dn: cn="${LDAP_SUFFIX}",cn=mapping tree,cn=config
3368objectclass: top
3369objectclass: extensibleObject
3370objectclass: nsMappingTree
3371cn: ${LDAP_SUFFIX}
3372nsslapd-state: backend
3373nsslapd-backend: ${IDS_DATABASE}
3374
3375dn: cn=${IDS_DATABASE},cn=ldbm database,cn=plugins,cn=config
3376objectclass: top
3377objectclass: extensibleObject
3378objectclass: nsBackendInstance
3379cn: ${IDS_DATABASE}
3380nsslapd-suffix: ${LDAP_SUFFIX}
3381EOF
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
3393dn: ${LDAP_SUFFIX}
3394objectclass: ${LDAP_SUFFIX_OBJ}
3395${_ATT}: ${_VAL}
3396${LDAP_SUFFIX_ACI}
3397EOF
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#
3420get_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
3455DEBUG: backend name for suffix ${LDAP_SUFFIX} will be ${IDS_DATABASE}
3456EOF
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#
3469print_suffix_config()
3470{
3471    cat <<EOF2
3472# LDAP suffix related preferences used only if needed
3473IDS_DATABASE="${IDS_DATABASE}"
3474LDAP_SUFFIX_OBJ="$LDAP_SUFFIX_OBJ"
3475LDAP_SUFFIX_ACI=\`cat <<EOF
3476${LDAP_SUFFIX_ACI}
3477EOF
3478\`
3479export IDS_DATABASE LDAP_SUFFIX_OBJ LDAP_SUFFIX_ACI
3480EOF2
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#
3491check_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
3582discover_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#
3611modify_cn()
3612{
3613    [ $DEBUG -eq 1 ] && ${ECHO} "In modify_cn()"
3614
3615    ( cat <<EOF
3616dn: cn=schema
3617changetype: modify
3618add: objectclasses
3619objectclasses: ( 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' )
3620EOF
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.
3634modify_timelimit()
3635{
3636    [ $DEBUG -eq 1 ] && ${ECHO} "In modify_timelimit()"
3637
3638    # Here doc to modify timelimit.
3639    ( cat <<EOF
3640dn: cn=config
3641changetype: modify
3642replace: nsslapd-timelimit
3643nsslapd-timelimit: ${IDS_TIMELIMIT}
3644EOF
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.
3662modify_sizelimit()
3663{
3664    [ $DEBUG -eq 1 ] && ${ECHO} "In modify_sizelimit()"
3665
3666    # Here doc to modify sizelimit.
3667    ( cat <<EOF
3668dn: cn=config
3669changetype: modify
3670replace: nsslapd-sizelimit
3671nsslapd-sizelimit: ${IDS_SIZELIMIT}
3672EOF
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.
3690modify_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
3698dn: cn=config
3699changetype: modify
3700replace: passwordstoragescheme
3701passwordstoragescheme: crypt
3702EOF
3703	) > ${TMPDIR}/ids_crypt
3704    else
3705	( cat <<EOF
3706dn: cn=Password Policy,cn=config
3707changetype: modify
3708replace: passwordstoragescheme
3709passwordstoragescheme: crypt
3710EOF
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#
3731add_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
3764dn: cn=${i},${_EXT}
3765objectClass: top
3766objectClass: nsIndex
3767cn: ${i}
3768nsSystemIndex: false
3769nsIndexType: pres
3770nsIndexType: eq
3771EOF
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
3795dn: cn=${TASKNAME}, cn=index, cn=tasks, cn=config
3796changetype: add
3797objectclass: top
3798objectclass: extensibleObject
3799cn: ${TASKNAME}
3800nsInstance: ${IDS_DATABASE}
3801nsIndexAttribute: ${i}
3802EOF
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#
3842add_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
3872dn: cn=${i},${_EXT}
3873objectClass: top
3874objectClass: nsIndex
3875cn: ${i}
3876nsSystemIndex: false
3877nsIndexType: pres
3878nsIndexType: eq
3879nsIndexType: sub
3880EOF
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
3904dn: cn=${TASKNAME}, cn=index, cn=tasks, cn=config
3905changetype: add
3906objectclass: top
3907objectclass: extensibleObject
3908cn: ${TASKNAME}
3909nsInstance: ${IDS_DATABASE}
3910nsIndexAttribute: ${i}
3911EOF
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#
3951add_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
4038dn: ${_jEXT}
4039objectClass: top
4040objectClass: vlvSearch
4041cn: ${j}
4042vlvbase: ${k},${LDAP_BASEDN}
4043vlvscope: ${VLV_SCOPE}
4044vlvfilter: (${m})
4045aci: (target="ldap:///${_jEXT}")(targetattr="*")(version 3.0; acl "Config";allow(read,search,compare)userdn="ldap:///anyone";)
4046
4047dn: cn=${i},${_jEXT}
4048cn: ${i}
4049vlvSort: cn uid
4050objectclass: top
4051objectclass: vlvIndex
4052EOF
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#
4076display_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
4090EOF
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#
4101keep_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#
4125update_schema_attr()
4126{
4127    [ $DEBUG -eq 1 ] && ${ECHO} "In update_schema_attr()"
4128
4129    ( cat <<EOF
4130dn: cn=schema
4131changetype: modify
4132add: attributetypes
4133attributetypes: ( 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 )
4134attributetypes: ( 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 )
4135attributetypes: ( 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 )
4136attributetypes: ( 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 )
4137attributetypes: ( 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 )
4138attributetypes: ( 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 )
4139attributetypes: ( 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 )
4140attributetypes: ( 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 )
4141attributetypes: ( 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 )
4142attributetypes: ( 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 )
4143attributetypes: ( 2.16.840.1.113730.3.1.30 NAME 'mgrpRFC822MailMember' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4144attributetypes: ( 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 )
4145attributetypes: ( 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 )
4146attributetypes: ( 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 )
4147attributetypes: ( 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 )
4148attributetypes: ( 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 )
4149attributetypes: ( 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 )
4150attributetypes: ( 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 )
4151attributetypes: ( 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 )
4152attributetypes: ( 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 )
4153attributetypes: ( 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 )
4154attributetypes: ( 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 )
4155attributetypes: ( 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 )
4156attributetypes: ( 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 )
4157attributetypes: ( 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 )
4158attributetypes: ( 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 )
4159attributetypes: ( 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 )
4160attributetypes: ( 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 )
4161attributetypes: ( 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 )
4162attributetypes: ( 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 )
4163attributetypes: ( 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 )
4164attributetypes: ( 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 )
4165attributetypes: ( 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 )
4166attributetypes: ( 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 )
4167attributetypes: ( 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 )
4168attributetypes: ( 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 )
4169attributetypes: ( 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 )
4170attributetypes: ( 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 )
4171attributetypes: ( 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 )
4172attributetypes: ( 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 )
4173attributetypes: ( 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 )
4174attributetypes: ( 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 )
4175attributetypes: ( 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 )
4176attributetypes: ( 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 )
4177attributetypes: ( 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 )
4178attributetypes: ( 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 )
4179attributetypes: ( 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 )
4180attributetypes: ( 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 )
4181attributetypes: ( 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 )
4182attributetypes: ( 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 )
4183attributetypes: ( 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 )
4184attributetypes: ( 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 )
4185attributetypes: ( 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 )
4186attributetypes: ( 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 )
4187attributetypes: ( 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 )
4188attributetypes: ( 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 )
4189attributetypes: ( 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 )
4190attributetypes: ( 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 )
4191attributetypes: ( 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 )
4192attributetypes: ( 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 )
4193attributetypes: ( 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 )
4194attributetypes: ( 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 )
4195attributetypes: ( 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 )
4196attributetypes: ( 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 )
4197attributetypes: ( 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} )
4198attributetypes: ( 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 )
4199attributetypes: ( 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 )
4200attributetypes: ( 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} )
4201attributetypes: ( 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} )
4202attributetypes: ( 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} )
4203attributetypes: ( 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 )
4204attributetypes: ( 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} )
4205attributetypes: ( 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 )
4206attributetypes: ( 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 )
4207attributetypes: ( 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} )
4208attributetypes: ( 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 )
4209attributetypes: ( 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} )
4210attributetypes: ( 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} )
4211attributetypes: ( 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} )
4212attributetypes: ( 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} )
4213attributetypes: ( 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} )
4214attributetypes: ( 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 )
4215attributetypes: ( 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 )
4216attributetypes: ( 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 )
4217attributetypes: ( 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 )
4218attributetypes: ( 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 )
4219attributetypes: ( 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} )
4220attributetypes: ( 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} )
4221attributetypes: ( 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} )
4222attributetypes: ( 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} )
4223attributetypes: ( 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 )
4224attributetypes: ( 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 )
4225attributetypes: ( 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 )
4226attributetypes: ( 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 )
4227attributetypes: ( 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 )
4228EOF
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#
4250update_schema_obj()
4251{
4252    [ $DEBUG -eq 1 ] && ${ECHO} "In update_schema_obj()"
4253
4254    # Add the objectclass definitions.
4255    ( cat <<EOF
4256dn: cn=schema
4257changetype: modify
4258add: objectclasses
4259objectclasses: ( 1.3.6.1.1.1.2.14 NAME 'NisKeyObject' SUP top MUST ( cn $ nisPublickey $ nisSecretkey ) MAY ( uidNumber $ description ) )
4260
4261dn: cn=schema
4262changetype: modify
4263add: objectclasses
4264objectclasses: ( 1.3.6.1.1.1.2.15 NAME 'nisDomainObject' SUP top MUST nisDomain )
4265
4266dn: cn=schema
4267changetype: modify
4268add: objectclasses
4269objectclasses: ( 1.3.6.1.1.1.2.16 NAME 'automountMap' SUP top MUST automountMapName MAY description )
4270
4271dn: cn=schema
4272changetype: modify
4273add: objectclasses
4274objectclasses: ( 1.3.6.1.1.1.2.17 NAME 'automount' SUP top MUST ( automountKey $ automountInformation ) MAY description )
4275
4276dn: cn=schema
4277changetype: modify
4278add: objectclasses
4279objectclasses: ( 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
4281dn: cn=schema
4282changetype: modify
4283add: objectclasses
4284objectclasses: ( 2.16.840.1.113730.3.2.4 NAME 'mailGroup' SUP top MUST mail MAY ( cn $ mgrpRFC822MailMember ) )
4285
4286dn: cn=schema
4287changetype: modify
4288add: objectclasses
4289objectclasses: ( 1.3.6.1.4.1.42.2.27.1.2.5 NAME 'nisMailAlias' SUP top MUST cn MAY rfc822mailMember )
4290
4291dn: cn=schema
4292changetype: modify
4293add: objectclasses
4294objectclasses: ( 1.3.6.1.4.1.42.2.27.1.2.6 NAME 'nisNetId' SUP top MUST cn MAY ( nisNetIdUser $ nisNetIdGroup $ nisNetIdHost ) )
4295
4296dn: cn=schema
4297changetype: modify
4298add: objectclasses
4299objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.2 NAME 'SolarisAuditUser' SUP top AUXILIARY MAY ( SolarisAuditAlways $ SolarisAuditNever ) )
4300
4301dn: cn=schema
4302changetype: modify
4303add: objectclasses
4304objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.3 NAME 'SolarisUserAttr' SUP top AUXILIARY MAY ( SolarisUserQualifier $ SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrKeyValue ) )
4305
4306dn: cn=schema
4307changetype: modify
4308add: objectclasses
4309objectclasses: ( 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
4311dn: cn=schema
4312changetype: modify
4313add: objectclasses
4314objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.5 NAME 'SolarisProfAttr' SUP top MUST cn MAY ( SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrLongDesc $ SolarisAttrKeyValue ) )
4315
4316dn: cn=schema
4317changetype: modify
4318add: objectclasses
4319objectclasses: ( 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
4321dn: cn=schema
4322changetype: modify
4323add: objectclasses
4324objectclasses: ( 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
4326dn: cn=schema
4327changetype: modify
4328add: objectclasses
4329objectclasses: ( 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
4331dn: cn=schema
4332changetype: modify
4333add: objectclasses
4334objectclasses: ( 1.3.18.0.2.6.2549 NAME 'slpService' DESC 'DUMMY definition' SUP top MUST objectclass )
4335
4336dn: cn=schema
4337changetype: modify
4338add: objectclasses
4339objectclasses: ( 1.3.18.0.2.6.254 NAME 'slpServicePrinter' DESC 'Service Location Protocol (SLP) information.' SUP slpService AUXILIARY )
4340
4341dn: cn=schema
4342changetype: modify
4343add: objectclasses
4344objectclasses: ( 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
4346dn: cn=schema
4347changetype: modify
4348add: objectclasses
4349objectclasses: ( 1.3.18.0.2.6.255 NAME 'printerService' DESC 'Printer information.' SUP printerAbstract STRUCTURAL MAY ( printer-uri $ printer-xri-supported ) )
4350
4351dn: cn=schema
4352changetype: modify
4353add: objectclasses
4354objectclasses: ( 1.3.18.0.2.6.257 NAME 'printerServiceAuxClass' DESC 'Printer information.' SUP printerAbstract AUXILIARY MAY ( printer-uri $ printer-xri-supported ) )
4355
4356dn: cn=schema
4357changetype: modify
4358add: objectclasses
4359objectclasses: ( 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
4361dn: cn=schema
4362changetype: modify
4363add: objectclasses
4364objectclasses: ( 1.3.18.0.2.6.253 NAME 'printerLPR' DESC 'LPR information.' SUP top AUXILIARY MUST printer-name MAY printer-aliases )
4365
4366dn: cn=schema
4367changetype: modify
4368add: objectclasses
4369objectclasses: ( 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
4371dn: cn=schema
4372changetype: modify
4373add: objectclasses
4374objectclasses:	( 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
4376dn: cn=schema
4377changetype: modify
4378add: objectclasses
4379objectclasses:  ( 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
4381dn: cn=schema
4382changetype: modify
4383add: objectclasses
4384objectclasses:	( 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 )
4385EOF
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#
4405modify_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
4429dn: ${LDAP_BASEDN}
4430changetype: modify
4431add: aci
4432aci: (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-
4434EOF
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.
4459find_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
4470dn: ${LDAP_BASEDN}
4471changetype: modify
4472delete: aci
4473aci: ${aci_to_delete}
4474EOF
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#
4501deny_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
4536dn: ${LDAP_BASEDN}
4537changetype: modify
4538add: aci
4539aci: (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}";)
4543EOF
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#
4570deny_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
4605dn: ${LDAP_BASEDN}
4606changetype: modify
4607add: aci
4608aci: (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}";)
4613EOF
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#
4639add_vlv_aci()
4640{
4641    [ $DEBUG -eq 1 ] && ${ECHO} "In add_vlv_aci()"
4642
4643    # Add the VLV ACI.
4644    ( cat <<EOF
4645dn: oid=2.16.840.1.113730.3.4.9,cn=features,cn=config
4646changetype: modify
4647replace: aci
4648aci: (targetattr != "aci") (version 3.0; acl "VLV Request Control"; allow(read,search,compare) userdn = "ldap:///anyone";)
4649EOF
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#
4669set_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
4685dn: ${LDAP_BASEDN}
4686changetype: modify
4687objectclass: nisDomainObject
4688nisdomain: ${LDAP_DOMAIN}
4689EOF
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#
4711check_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#
4742get_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#
4766add_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
4849dn: ${dk2}=${dc2},$lastdc
4850${dk2}: $dc2
4851objectClass: top
4852objectClass: ${OBJ_Name}
4853EOF
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#
4885add_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
4901dn: ou=${ou},${LDAP_BASEDN}
4902ou: ${ou}
4903objectClass: top
4904objectClass: organizationalUnit
4905EOF
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#
4928add_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
4944dn: automountMapName=${automap},${LDAP_BASEDN}
4945automountMapName: ${automap}
4946objectClass: top
4947objectClass: automountMap
4948EOF
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#
4969add_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
4986dn: ${LDAP_PROXYAGENT}
4987cn: ${cn_tmp}
4988sn: ${cn_tmp}
4989objectclass: top
4990objectclass: person
4991userpassword: ${LDAP_PROXYAGENT_CRED}
4992EOF
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#
5011allow_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
5026dn: ${LDAP_BASEDN}
5027changetype: modify
5028add: aci
5029aci: (target="ldap:///${LDAP_BASEDN}")(targetattr="userPassword")
5030  (version 3.0; acl ${PROXY_ACI_NAME}; allow (compare,read,search)
5031  userdn = "ldap:///${LDAP_PROXYAGENT}";)
5032EOF
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.
5049delete_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
5076Proxy agent is not allowed to read user passwords when shadow
5077update is enabled. There are more than one proxy agents found.
5078Please select the currently proxy agent being used, so that
5079idsconfig can remove its read access to user passwords.
5080
5081The proxy agents are:
5082
5083EOF
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
5101dn: ${LDAP_BASEDN}
5102changetype: modify
5103delete: aci
5104aci: ${proxy_aci}
5105EOF
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#
5128add_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
5137cn=${LDAP_PROFILE_NAME},ou=profile,${LDAP_BASEDN}
5138EOF
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#
5218cleanup()
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(8)
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.
5238init
5239
5240# Parse command line arguments.
5241parse_arg $*
5242shift $?
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.
5249if [ -n "$INPUT_FILE" ]
5250then
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.
5255else
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.
5267fi
5268
5269# Modify slapd.oc.conf to ALLOW cn instead of REQUIRE.
5270modify_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.
5279if [ "$NEED_CRYPT" = "TRUE" ]; then
5280    modify_pwd_crypt
5281fi
5282
5283# Update the schema (Attributes, Objectclass Definitions)
5284if [ ${SCHEMA_UPDATED} -eq 0 ]; then
5285        update_schema_attr
5286        update_schema_obj
5287fi
5288
5289# Add suffix together with its root entry (if needed)
5290add_suffix ||
5291{
5292	cleanup
5293	exit 1
5294}
5295
5296# Add base objects (if needed)
5297add_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!
5302set_nisdomain
5303
5304# Add top level classes (new containers)
5305add_new_containers
5306
5307# Add common nismaps.
5308add_auto_maps
5309
5310# Modify top ACI.
5311modify_top_aci
5312
5313# Add Access Control Information for VLV.
5314add_vlv_aci
5315
5316# if Proxy needed, Add Proxy Agent and give read permission for password.
5317if [ $NEED_PROXY -eq 1 ]; then
5318    add_proxyagent
5319    if [ "$LDAP_ENABLE_SHADOW_UPDATE" != "TRUE" ]; then
5320	allow_proxy_read_pw
5321    fi
5322fi
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.
5327if [ $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
5332fi
5333
5334if [ $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
5342fi
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.
5346if [ $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
5350fi
5351
5352
5353# Generate client profile and add it to the server.
5354add_profile
5355
5356# Add Indexes to improve Search Performance.
5357add_eq_indexes
5358add_sub_indexes
5359add_vlv_indexes
5360
5361# Display setup complete message
5362display_msg setup_complete
5363
5364# Display VLV index commands to be executed on server.
5365display_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.
5371cleanup
5372
5373exit 0
5374# end of MAIN.
5375