xref: /titanic_51/usr/src/cmd/ldap/ns_ldap/idsconfig.sh (revision 65488c97aeb108aeffd7b61db3b2b3bcb4fc9d72)
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 for Native LDAP II.
24#
25# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
26# Use is subject to license terms.
27#
28
29#
30# display_msg(): Displays message corresponding to the tag passed in.
31#
32display_msg()
33{
34    case "$1" in
35    usage) cat <<EOF
36 $PROG: [ -v ] [ -i input file ] [ -o output file ]
37   i <input file>     Get setup info from input file.
38   o <output file>    Generate a server configuration output file.
39   v                  Verbose mode
40EOF
41    ;;
42    backup_server) cat <<EOF
43It is strongly recommended that you BACKUP the directory server
44before running $PROG.
45
46Hit Ctrl-C at any time before the final confirmation to exit.
47
48EOF
49    ;;
50    setup_complete) cat <<EOF
51
52$PROG: Setup of iDS server ${IDS_SERVER} is complete.
53
54EOF
55    ;;
56    display_vlv_list) cat <<EOF
57
58Note: idsconfig has created entries for VLV indexes. 
59
60      For DS5.x, use the directoryserver(1m) script on ${IDS_SERVER}
61      to stop the server.  Then, using directoryserver, follow the
62      directoryserver examples below to create the actual VLV indexes.
63
64      For DS6.x, use dsadm command delivered with DS6.x on ${IDS_SERVER}
65      to stop the server.  Then, using dsadm, follow the
66      dsadm examples below to create the actual VLV indexes.
67
68EOF
69    ;;
70    cred_level_menu) cat <<EOF
71The following are the supported credential levels:
72  1  anonymous
73  2  proxy
74  3  proxy anonymous
75  4  self
76  5  self proxy
77  6  self proxy anonymous
78EOF
79    ;;
80    auth_method_menu) cat <<EOF
81The following are the supported Authentication Methods:
82  1  none
83  2  simple
84  3  sasl/DIGEST-MD5
85  4  tls:simple
86  5  tls:sasl/DIGEST-MD5
87  6  sasl/GSSAPI
88EOF
89    ;;
90    srvauth_method_menu) cat <<EOF
91The following are the supported Authentication Methods:
92  1  simple
93  2  sasl/DIGEST-MD5
94  3  tls:simple
95  4  tls:sasl/DIGEST-MD5
96  5  sasl/GSSAPI
97EOF
98    ;;
99    prompt_ssd_menu) cat <<EOF
100  A  Add a Service Search Descriptor
101  D  Delete a SSD
102  M  Modify a SSD
103  P  Display all SSD's
104  H  Help
105  X  Clear all SSD's
106
107  Q  Exit menu
108EOF
109    ;;
110    summary_menu)
111
112	SUFFIX_INFO=
113	DB_INFO=
114
115	[ -n "${NEED_CREATE_SUFFIX}" ] &&
116	{
117		SUFFIX_INFO=`cat <<EOF
118
119         Suffix to create          : $LDAP_SUFFIX
120EOF
121`
122		[ -n "${NEED_CREATE_BACKEND}" ] &&
123			DB_INFO=`cat <<EOF
124
125         Database to create        : $IDS_DATABASE
126EOF
127`
128	}
129
130	cat <<EOF
131              Summary of Configuration
132
133  1  Domain to serve               : $LDAP_DOMAIN
134  2  Base DN to setup              : $LDAP_BASEDN$SUFFIX_INFO$DB_INFO
135  3  Profile name to create        : $LDAP_PROFILE_NAME
136  4  Default Server List           : $LDAP_SERVER_LIST
137  5  Preferred Server List         : $LDAP_PREF_SRVLIST
138  6  Default Search Scope          : $LDAP_SEARCH_SCOPE
139  7  Credential Level              : $LDAP_CRED_LEVEL
140  8  Authentication Method         : $LDAP_AUTHMETHOD
141  9  Enable Follow Referrals       : $LDAP_FOLLOWREF
142 10  iDS Time Limit                : $IDS_TIMELIMIT
143 11  iDS Size Limit                : $IDS_SIZELIMIT
144 12  Enable crypt password storage : $NEED_CRYPT
145 13  Service Auth Method pam_ldap  : $LDAP_SRV_AUTHMETHOD_PAM
146 14  Service Auth Method keyserv   : $LDAP_SRV_AUTHMETHOD_KEY
147 15  Service Auth Method passwd-cmd: $LDAP_SRV_AUTHMETHOD_CMD
148 16  Search Time Limit             : $LDAP_SEARCH_TIME_LIMIT
149 17  Profile Time to Live          : $LDAP_PROFILE_TTL
150 18  Bind Limit                    : $LDAP_BIND_LIMIT
151 19  Enable shadow update          : $LDAP_ENABLE_SHADOW_UPDATE
152 20  Service Search Descriptors Menu
153
154EOF
155    ;;
156    sfx_not_suitable) cat <<EOF
157
158Sorry, suffix ${LDAP_SUFFIX} is not suitable for Base DN ${LDAP_BASEDN}
159
160EOF
161    ;;
162    obj_not_found) cat <<EOF
163
164Sorry, ${PROG} can't find an objectclass for "$_ATT" attribute
165
166EOF
167    ;;
168    sfx_config_incons) cat <<EOF
169
170Sorry, there is no suffix mapping for ${LDAP_SUFFIX},
171while ldbm database exists, server configuration needs to be fixed manually,
172look at cn=mapping tree,cn=config and cn=ldbm database,cn=plugins,cn=config
173
174EOF
175    ;;
176    ldbm_db_exist) cat <<EOF
177
178Database "${IDS_DATABASE}" already exists,
179however "${IDS_DATABASE_AVAIL}" name is available
180
181EOF
182    ;;
183    unable_find_db_name) cat <<EOF
184    
185Unable to find any available database name close to "${IDS_DATABASE}"
186
187EOF
188    ;;
189    create_ldbm_db_error) cat <<EOF
190
191ERROR: unable to create suffix ${LDAP_SUFFIX}
192       due to server error that occurred during creation of ldbm database
193
194EOF
195    ;;
196    create_suffix_entry_error) cat <<EOF
197
198ERROR: unable to create entry ${LDAP_SUFFIX} of ${LDAP_SUFFIX_OBJ} class
199
200EOF
201    ;;
202    ldap_suffix_list) cat <<EOF
203
204No valid suffixes (naming contexts) were found for LDAP base DN:
205${LDAP_BASEDN}
206
207Available suffixes are:
208${LDAP_SUFFIX_LIST}
209
210EOF
211    ;;
212    sorry) cat <<EOF
213
214HELP - No help is available for this topic.
215
216EOF
217    ;;
218    create_suffix_help) cat <<EOF
219
220HELP - Our Base DN is ${LDAP_BASEDN}
221       and we need to create a Directory Suffix,
222       which can be equal to Base DN itself or be any of Base DN parents.
223       All intermediate entries up to suffix will be created on demand.
224
225EOF
226    ;;
227    enter_ldbm_db_help) cat <<EOF
228
229HELP - ldbm database is an internal database for storage of our suffix data.
230       Database name must be alphanumeric due to Directory Server restriction.
231
232EOF
233    ;;
234    backup_help) cat <<EOF
235
236HELP - Since idsconfig modifies the directory server configuration,
237       it is strongly recommended that you backup the server prior
238       to running this utility.  This is especially true if the server
239       being configured is a production server.
240
241EOF
242    ;;
243    port_help) cat <<EOF
244
245HELP - Enter the port number the directory server is configured to
246       use for LDAP.
247
248EOF
249    ;;
250    domain_help) cat <<EOF
251
252HELP - This is the DNS domain name this server will be serving.  You
253       must provide this name even if the server is not going to be populated
254       with hostnames.  Any unqualified hostname stored in the directory
255       will be fully qualified using this DNS domain name.
256
257EOF
258    ;;
259    basedn_help) cat <<EOF
260
261HELP - This parameter defines the default location in the directory tree for
262       the naming services entries.  You can override this default by using 
263       serviceSearchDescriptors (SSD). You will be given the option to set up 
264       an SSD later on in the setup.
265
266EOF
267    ;;
268    profile_help) cat <<EOF
269
270HELP - Name of the configuration profile with which the clients will be
271       configured. A directory server can store various profiles for multiple 
272       groups of clients.  The initialization tool, (ldapclient(1M)), assumes 
273       "default" unless another is specified.
274
275EOF
276    ;;
277    def_srvlist_help) cat <<EOF
278
279HELP - Provide a list of directory servers to serve clients using this profile.
280       All these servers should contain consistent data and provide similar 
281       functionality.  This list is not ordered, and clients might change the 
282       order given in this list. Note that this is a space separated list of 
283       *IP addresses* (not host names).  Providing port numbers is optional.
284
285EOF
286    ;;
287    pref_srvlist_help) cat <<EOF
288
289HELP - Provide a list of directory servers to serve this client profile. 
290       Unlike the default server list, which is not ordered, the preferred 
291       servers must be entered IN THE ORDER you wish to have them contacted. 
292       If you do specify a preferred server list, clients will always contact 
293       them before attempting to contact any of the servers on the default 
294       server list. Note that you must enter the preferred server list as a 
295       space-separated list of *IP addresses* (not host names).  Providing port 
296       numbers is optional.
297
298EOF
299    ;;
300    srch_scope_help) cat <<EOF
301
302HELP - Default search scope to be used for all searches unless they are
303       overwritten using serviceSearchDescriptors.  The valid options
304       are "one", which would specify the search will only be performed 
305       at the base DN for the given service, or "sub", which would specify 
306       the search will be performed through *all* levels below the base DN 
307       for the given service.
308
309EOF
310    ;;
311    cred_lvl_help) cat <<EOF
312
313HELP - This parameter defines what credentials the clients use to
314       authenticate to the directory server.  This list might contain
315       multiple credential levels and is ordered.  If a proxy level
316       is configured, you will also be prompted to enter a bind DN
317       for the proxy agent along with a password.  This proxy agent
318       will be created if it does not exist.
319
320EOF
321    ;;
322    auth_help) cat <<EOF
323
324HELP - The default authentication method(s) to be used by all services
325       in the client using this profile.  This is a ordered list of
326       authentication methods separated by a ';'.  The supported methods
327       are provided in a menu.  Note that sasl/DIGEST-MD5 binds require
328       passwords to be stored un-encrypted on the server.
329
330EOF
331    ;;
332    srvauth_help) cat <<EOF
333
334HELP - The authentication methods to be used by a given service.  Currently
335       3 services support this feature: pam_ldap, keyserv, and passwd-cmd.
336       The authentication method specified in this attribute overrides
337       the default authentication method defined in the profile.  This
338       feature can be used to select stronger authentication methods for
339       services which require increased security.
340
341EOF
342    ;;
343    pam_ldap_help) cat <<EOF
344
345HELP - The authentication method(s) to be used by pam_ldap when contacting
346       the directory server.  This is a ordered list, and, if provided, will
347       override the default authentication method parameter.
348
349EOF
350    ;;
351    keyserv_help) cat <<EOF
352
353HELP - The authentication method(s) to be used by newkey(1M) and chkey(1)
354       when contacting the directory server.  This is a ordered list and
355       if provided will override the default authentication method
356       parameter.
357
358EOF
359    ;;
360    passwd-cmd_help) cat <<EOF
361
362HELP - The authentication method(s) to be used by passwd(1) command when
363       contacting the directory server.  This is a ordered list and if
364       provided will override the default authentication method parameter.
365
366EOF
367    ;;
368    referrals_help) cat <<EOF
369
370HELP - This parameter indicates whether the client should follow
371       ldap referrals if it encounters one during naming lookups.
372
373EOF
374    ;;
375    tlim_help) cat <<EOF
376
377HELP - The server time limit value indicates the maximum amount of time the
378       server would spend on a query from the client before abandoning it.
379       A value of '-1' indicates no limit.
380
381EOF
382    ;;
383    slim_help) cat <<EOF
384
385HELP - The server sizelimit value indicates the maximum number of entries
386       the server would return in respond to a query from the client.  A
387       value of '-1' indicates no limit.
388
389EOF
390    ;;
391    crypt_help) cat <<EOF
392
393HELP - By default iDS does not store userPassword attribute values using
394       unix "crypt" format.  If you need to keep your passwords in the crypt
395       format for NIS/NIS+ and pam_unix compatibility, choose 'yes'.  If
396       passwords are stored using any other format than crypt, pam_ldap
397       MUST be used by clients to authenticate users to the system. Note 
398       that if you wish to use sasl/DIGEST-MD5 in conjunction with pam_ldap,
399       user passwords must be stored in the clear format.
400
401EOF
402    ;;
403    srchtime_help) cat <<EOF
404
405HELP - The search time limit the client will enforce for directory
406       lookups.
407
408EOF
409    ;;
410    profttl_help) cat <<EOF
411
412HELP - The time to live value for profile.  The client will refresh its
413       cached version of the configuration profile at this TTL interval.
414
415EOF
416    ;;
417    bindlim_help) cat <<EOF
418
419HELP - The time limit for the bind operation to the directory.  This
420       value controls the responsiveness of the client in case a server
421       becomes unavailable.  The smallest timeout value for a given
422       network architecture/conditions would work best.  This is very
423       similar to setting TCP timeout, but only for LDAP bind operation.
424
425EOF
426    ;;
427    ssd_help) cat <<EOF
428
429HELP - Using Service Search Descriptors (SSD), you can override the
430       default configuration for a given service.  The SSD can be
431       used to override the default search base DN, the default search
432       scope, and the default search filter to be used for directory
433       lookups.  SSD are supported for all services (databases)
434       defined in nsswitch.conf(4).  The default base DN is defined
435       in ldap(1).
436
437       Note: SSD are powerful tools in defining configuration profiles
438             and provide a great deal of flexibility.  However, care
439             must be taken in creating them.  If you decide to make use
440             of SSDs, consult the documentation first.
441
442EOF
443    ;;
444    ssd_menu_help) cat <<EOF
445
446HELP - Using this menu SSD can be added, updated, or deleted from
447       the profile.
448
449       A - This option creates a new SSD by prompting for the
450           service name, base DN, and scope.  Service name is
451           any valid service as defined in ldap(1).  base is
452           either the distinguished name to the container where
453           this service will use, or a relative DN followed
454           by a ','.
455       D - Delete a previously created SSD.
456       M - Modify a previously created SSD.
457       P - Display a list of all the previously created SSD.
458       X - Delete all of the previously created SSD.
459
460       Q - Exit the menu and continue with the server configuration.
461
462EOF
463    ;;
464    ldap_suffix_list_help) cat <<EOF
465
466HELP - No valid suffixes (naming contexts) are available on server 
467       ${IDS_SERVER}:${IDS_PORT}.
468       You must set an LDAP Base DN that can be contained in 
469       an existing suffix.
470
471EOF
472    ;;
473    enable_shadow_update_help) cat <<EOF
474
475HELP - Enter 'y' to set up the LDAP server for shadow update.
476       The setup will add an administrator identity/credential
477       and modify the necessary access controls for the client
478       to update shadow(4) data on the LDAP server. If sasl/GSSAPI
479       is in use, the Kerberos host principal will be used as the
480       administrator identity.
481
482       Shadow data is used for password aging and account locking.
483       Please refer to the shadow(4) manual page for details.
484
485EOF
486    ;;
487    add_admin_cred_help) cat <<EOF
488
489HELP - Start the setup to add an administrator identity/credential
490       and to modify access controls for the client to update
491       shadow(4) data on the LDAP server.
492
493       Shadow data is used for password aging and account locking.
494       Please refer to the shadow(4) manual page for details.
495
496EOF
497    ;;
498    use_host_principal_help) cat <<EOF
499
500HELP - A profile with a 'sasl/GSSAPI' authentication method and a 'self'
501       credential level is detected, enter 'y' to modify the necessary
502       access controls for allowing the client to update shadow(4) data
503       on the LDAP server.
504
505       Shadow data is used for password aging and account locking.
506       Please refer to the shadow(4) manual page for details.
507
508EOF
509    ;;
510    esac
511}
512
513
514#
515# get_ans(): gets an answer from the user.
516#		$1  instruction/comment/description/question
517#		$2  default value
518#
519get_ans()
520{
521    if [ -z "$2" ]
522    then
523	${ECHO} "$1 \c"
524    else
525	${ECHO} "$1 [$2] \c"
526    fi
527
528    read ANS
529    if [ -z "$ANS" ]
530    then
531	ANS=$2
532    fi
533}
534
535
536#
537# get_ans_req(): gets an answer (required) from the user, NULL value not allowed.
538#		$@  instruction/comment/description/question
539#
540get_ans_req()
541{
542    ANS=""                  # Set ANS to NULL.
543    while [ "$ANS" = "" ]
544    do
545	get_ans "$@"
546	[ "$ANS" = "" ] && ${ECHO} "NULL value not allowed!"
547    done
548}
549
550
551#
552# get_number(): Querys and verifies that number entered is numeric.
553#               Function will repeat prompt user for number value.
554#               $1  Message text.
555#		$2  default value.
556#               $3  Help argument.
557#
558get_number()
559{
560    ANS=""                  # Set ANS to NULL.
561    NUM=""
562
563    get_ans "$1" "$2"
564
565    # Verify that value is numeric.
566    while not_numeric $ANS
567    do
568	case "$ANS" in
569	    [Hh] | help | Help | \?) display_msg ${3:-sorry} ;;
570	    * ) ${ECHO} "Invalid value: \"${ANS}\". \c"
571	     ;;
572	esac
573	# Get a new value.
574	get_ans "Enter a numeric value:" "$2"
575    done
576    NUM=$ANS
577}
578
579
580#
581# get_negone_num(): Only allows a -1 or positive integer.
582#                   Used for values where -1 has special meaning.
583#
584#                   $1 - Prompt message.
585#                   $2 - Default value (require).
586#                   $3 - Optional help argument.
587get_negone_num()
588{
589    while :
590    do
591	get_number "$1" "$2" "$3"
592	if is_negative $ANS
593	then
594	    if [ "$ANS" = "-1" ]; then
595		break  # -1 is OK, so break.
596	    else       # Need to re-enter number.
597		${ECHO} "Invalid number: please enter -1 or positive number."
598	    fi
599	else
600	    break      # Positive number
601	fi
602    done
603}
604
605
606#
607# get_passwd(): Reads a password from the user and verify with second.
608#		$@  instruction/comment/description/question
609#
610get_passwd()
611{
612    [ $DEBUG -eq 1 ] && ${ECHO} "In get_passwd()"
613
614    # Temporary PASSWD variables
615    _PASS1=""
616    _PASS2=""
617
618    /usr/bin/stty -echo     # Turn echo OFF
619
620    # Endless loop that continues until passwd and re-entered passwd
621    # match.
622    while :
623    do
624	ANS=""                  # Set ANS to NULL.
625
626	# Don't allow NULL for first try.
627	while [ "$ANS" = "" ]
628	do
629	    get_ans "$@"
630	    [ "$ANS" = "" ] && ${ECHO} "" && ${ECHO} "NULL passwd not allowed!"
631	done
632	_PASS1=$ANS         # Store first try.
633
634	# Get second try.
635	${ECHO} ""
636	get_ans "Re-enter passwd:"
637	_PASS2=$ANS
638
639	# Test if passwords are identical.
640	if [ "$_PASS1" = "$_PASS2" ]; then
641	    break
642	fi
643
644	# Move cursor down to next line and print ERROR message.
645	${ECHO} ""
646	${ECHO} "ERROR: passwords don't match; try again."
647    done
648
649    /usr/bin/stty echo      # Turn echo ON
650
651    ${ECHO} ""
652}
653
654
655#
656# get_passwd_nochk(): Reads a password from the user w/o check.
657#		$@  instruction/comment/description/question
658#
659get_passwd_nochk()
660{
661    [ $DEBUG -eq 1 ] && ${ECHO} "In get_passwd_nochk()"
662
663    /usr/bin/stty -echo     # Turn echo OFF
664
665    get_ans "$@"
666
667    /usr/bin/stty echo      # Turn echo ON
668
669    ${ECHO} ""
670}
671
672
673#
674# get_menu_choice(): Get a menu choice from user.  Continue prompting
675#                    till the choice is in required range.
676#   $1 .. Message text.
677#   $2 .. min value
678#   $3 .. max value
679#   $4 .. OPTIONAL: default value
680#
681#   Return value:
682#     MN_CH will contain the value selected.
683#
684get_menu_choice()
685{
686    # Check for req parameter.
687    if [ $# -lt 3 ]; then
688	${ECHO} "get_menu_choice(): Did not get required parameters."
689	return 1
690    fi
691
692    while :
693    do
694	get_ans "$1" "$4"
695	MN_CH=$ANS
696	is_negative $MN_CH
697	if [ $? -eq 1 ]; then
698	    if [ $MN_CH -ge $2 ]; then
699		if [ $MN_CH -le $3 ]; then
700		    return
701		fi
702	    fi
703	fi
704	${ECHO} "Invalid choice: $MN_CH"
705    done
706}
707
708
709#
710# get_confirm(): Get confirmation from the user. (Y/Yes or N/No)
711#                $1 - Message
712#                $2 - default value.
713#
714get_confirm()
715{
716    _ANSWER=
717
718    while :
719    do
720	# Display Internal ERROR if $2 not set.
721	if [ -z "$2" ]
722	then
723	    ${ECHO} "INTERNAL ERROR: get_confirm requires 2 args, 3rd is optional."
724	    exit 2
725	fi
726
727	# Display prompt.
728	${ECHO} "$1 [$2] \c"
729
730	# Get the ANSWER.
731	read _ANSWER
732	if [ "$_ANSWER" = "" ] && [ -n "$2" ] ; then
733	    _ANSWER=$2
734	fi
735	case "$_ANSWER" in
736	    [Yy] | yes | Yes | YES) return 1 ;;
737	    [Nn] | no  | No  | NO)  return 0 ;;
738	    [Hh] | help | Help | \?) display_msg ${3:-sorry};;
739	    * ) ${ECHO} "Please enter y or n."  ;;
740	esac
741    done
742}
743
744
745#
746# get_confirm_nodef(): Get confirmation from the user. (Y/Yes or N/No)
747#                      No default value supported.
748#
749get_confirm_nodef()
750{
751    _ANSWER=
752
753    while :
754    do
755	${ECHO} "$@ \c"
756	read _ANSWER
757	case "$_ANSWER" in
758	    [Yy] | yes | Yes | YES) return 1 ;;
759	    [Nn] | no  | No  | NO)  return 0 ;;
760	    * ) ${ECHO} "Please enter y or n."  ;;
761	esac
762    done
763}
764
765
766#
767# is_numeric(): Tells is a string is numeric.
768#    0 = Numeric
769#    1 = NOT Numeric
770#
771is_numeric()
772{
773    # Check for parameter.
774    if [ $# -ne 1 ]; then
775	return 1
776    fi
777
778    # Determine if numeric.
779    expr "$1" + 1 > /dev/null 2>&1
780    if [ $? -ge 2 ]; then
781	return 1
782    fi
783
784    # Made it here, it's Numeric.
785    return 0
786}
787
788
789#
790# not_numeric(): Reverses the return values of is_numeric.  Useful
791#                 for if and while statements that want to test for
792#                 non-numeric data.
793#    0 = NOT Numeric
794#    1 = Numeric
795#
796not_numeric()
797{
798    is_numeric $1
799    if [ $? -eq 0 ]; then
800       return 1
801    else
802       return 0
803    fi
804}
805
806
807#
808# is_negative(): Tells is a Numeric value is less than zero.
809#    0 = Negative Numeric
810#    1 = Positive Numeric
811#    2 = NOT Numeric
812#
813is_negative()
814{
815    # Check for parameter.
816    if [ $# -ne 1 ]; then
817	return 1
818    fi
819
820    # Determine if numeric.  Can't use expr because -0 is
821    # considered positive??
822    if is_numeric $1; then
823	case "$1" in
824	    -*)  return 0 ;;   # Negative Numeric
825	    *)   return 1 ;;   # Positive Numeric
826	esac
827    else
828	return 2
829    fi
830}
831
832
833#
834# check_domainname(): check validity of a domain name.  Currently we check
835#                     that it has at least two components.
836#		$1  the domain name to be checked
837#
838check_domainname()
839{
840    if [ ! -z "$1" ]
841    then
842	t=`expr "$1" : '[^.]\{1,\}[.][^.]\{1,\}'`
843	if [ "$t" = 0 ]
844	then
845	    return 1
846	fi
847    fi
848    return 0
849}
850
851
852#
853# check_baseDN(): check validity of the baseDN name.
854#		$1  the baseDN name to be checked
855#
856#     NOTE: The check_baseDN function does not catch all invalid DN's.
857#           Its purpose is to reduce the number of invalid DN's to
858#           get past the input routine.  The invalid DN's will be
859#           caught by the LDAP server when they are attempted to be
860#           created.
861#
862check_baseDN()
863{
864    ck_DN=$1
865    ${ECHO} "  Checking LDAP Base DN ..."
866    if [ ! -z "$ck_DN" ]; then
867        [ $DEBUG -eq 1 ] && ${ECHO} "Checking baseDN: $ck_DN"
868        # Check for = (assignment operator)
869        ${ECHO} "$ck_DN" | ${GREP} "=" > /dev/null 2>&1
870        if [ $? -ne 0 ]; then
871            [ $DEBUG -eq 1 ] && ${ECHO} "check_baseDN: No '=' in baseDN."
872            return 1
873        fi
874
875        # Check all keys.
876        while :
877        do
878            # Get first key.
879            dkey=`${ECHO} $ck_DN | cut -d'=' -f1`
880
881            # Check that the key string is valid
882	    check_attrName $dkey
883	    if [ $? -ne 0 ]; then
884                [ $DEBUG -eq 1 ] && ${ECHO} "check_baseDN: invalid key=${dkey}"
885                return 1
886            fi
887
888            [ $DEBUG -eq 1 ] && ${ECHO} "check_baseDN: valid key=${dkey}"
889
890            # Remove first key from DN
891            ck_DN=`${ECHO} $ck_DN | cut -s -d',' -f2-`
892
893            # Break loop if nothing left.
894            if [ "$ck_DN" = "" ]; then
895                break
896            fi
897        done
898    fi
899    return 0
900}
901
902
903#
904# domain_2_dc(): Convert a domain name into dc string.
905#    $1  .. Domain name.
906#
907domain_2_dc()
908{
909    _DOM=$1           # Domain parameter.
910    _DOM_2_DC=""      # Return value from function.
911    _FIRST=1          # Flag for first time.
912
913    export _DOM_2_DC  # Make visible for others.
914
915    # Convert "."'s to spaces for "for" loop.
916    domtmp="`${ECHO} ${_DOM} | tr '.' ' '`"
917    for i in $domtmp; do
918	if [ $_FIRST -eq 1 ]; then
919	    _DOM_2_DC="dc=${i}"
920	    _FIRST=0
921	else
922	    _DOM_2_DC="${_DOM_2_DC},dc=${i}"
923	fi
924    done
925}
926
927
928#
929# is_root_user(): Check to see if logged in as root user.
930#
931is_root_user()
932{
933    case `id` in
934	uid=0\(root\)*) return 0 ;;
935	* )             return 1 ;;
936    esac
937}
938
939
940#
941# parse_arg(): Parses the command line arguments and sets the
942#              appropriate variables.
943#
944parse_arg()
945{
946    while getopts "dvhi:o:" ARG
947    do
948	case $ARG in
949	    d)      DEBUG=1;;
950	    v)      VERB="";;
951	    i)      INPUT_FILE=$OPTARG;;
952	    o)      OUTPUT_FILE=$OPTARG;;
953	    \?)	display_msg usage
954		    exit 1;;
955	    *)	${ECHO} "**ERROR: Supported option missing handler!"
956		    display_msg usage
957		    exit 1;;
958	esac
959    done
960    return `expr $OPTIND - 1`
961}
962
963
964#
965# init(): initializes variables and options
966#
967init()
968{
969    # General variables.
970    PROG=`basename $0`	# Program name
971    PID=$$              # Program ID
972    VERB='> /dev/null 2>&1'	# NULL or "> /dev/null"
973    ECHO="/bin/echo"	# print message on screen
974    EVAL="eval"		# eval or echo
975    EGREP="/usr/bin/egrep"
976    GREP="/usr/bin/grep"
977    DEBUG=0             # Set Debug OFF
978    BACKUP=no_ldap	# backup suffix
979    HOST=""		# NULL or <hostname>
980    NAWK="/usr/bin/nawk"
981    RM="/usr/bin/rm"
982    WC="/usr/bin/wc"
983    CAT="/usr/bin/cat"
984    SED="/usr/bin/sed"
985    MV="/usr/bin/mv"
986
987    DOM=""              # Set to NULL
988    # If DNS domain (resolv.conf) exists use that, otherwise use domainname.
989    if [ -f /etc/resolv.conf ]; then
990        DOM=`/usr/xpg4/bin/grep -i -E '^domain|^search' /etc/resolv.conf \
991	    | awk '{ print $2 }' | tail -1`
992    fi
993
994    # If for any reason the DOM did not get set (error'd resolv.conf) set
995    # DOM to the domainname command's output.
996    if [ "$DOM" = "" ]; then
997        DOM=`domainname`	# domain from domainname command.
998    fi
999
1000    STEP=1
1001    INTERACTIVE=1       # 0 = on, 1 = off (For input file mode)
1002    DEL_OLD_PROFILE=0   # 0 (default), 1 = delete old profile.
1003
1004    # idsconfig specific variables.
1005    INPUT_FILE=""
1006    OUTPUT_FILE=""
1007    LDAP_ENABLE_SHADOW_UPDATE="FALSE"
1008    NEED_PROXY=0        # 0 = No Proxy,    1 = Create Proxy.
1009    NEED_ADMIN=0        # 0 = No Admin,    1 = Create Admin.
1010    NEED_HOSTACL=0      # 0 = No Host ACL, 1 = Create Host ACL.
1011    EXISTING_PROFILE=0
1012    LDAP_PROXYAGENT=""
1013    LDAP_ADMINDN=""
1014    LDAP_SUFFIX=""
1015    LDAP_DOMAIN=$DOM	# domainname on Server (default value)
1016    GEN_CMD=""
1017    PROXY_ACI_NAME="LDAP_Naming_Services_proxy_password_read"
1018
1019    # LDAP COMMANDS
1020    LDAPSEARCH="/bin/ldapsearch -r"
1021    LDAPMODIFY=/bin/ldapmodify
1022    LDAPADD=/bin/ldapadd
1023    LDAPDELETE=/bin/ldapdelete
1024    LDAP_GEN_PROFILE=/usr/sbin/ldap_gen_profile
1025
1026    # iDS specific information
1027    IDS_SERVER=""
1028    IDS_PORT=389
1029    NEED_TIME=0
1030    NEED_SIZE=0
1031    NEED_SRVAUTH_PAM=0
1032    NEED_SRVAUTH_KEY=0
1033    NEED_SRVAUTH_CMD=0
1034    IDS_TIMELIMIT=""
1035    IDS_SIZELIMIT=""
1036
1037    # LDAP PROFILE related defaults
1038    LDAP_ROOTDN="cn=Directory Manager"   # Provide common default.
1039    LDAP_ROOTPWD=""                      # NULL passwd as default (i.e. invalid)
1040    LDAP_PROFILE_NAME="default"
1041    LDAP_BASEDN=""
1042    LDAP_SERVER_LIST=""
1043    LDAP_AUTHMETHOD=""
1044    LDAP_FOLLOWREF="FALSE"
1045    NEED_CRYPT=""
1046    LDAP_SEARCH_SCOPE="one"
1047    LDAP_SRV_AUTHMETHOD_PAM=""
1048    LDAP_SRV_AUTHMETHOD_KEY=""
1049    LDAP_SRV_AUTHMETHOD_CMD=""
1050    LDAP_SEARCH_TIME_LIMIT=30
1051    LDAP_PREF_SRVLIST=""
1052    LDAP_PROFILE_TTL=43200
1053    LDAP_CRED_LEVEL="proxy"
1054    LDAP_BIND_LIMIT=10
1055
1056    # Prevent new files from being read by group or others.
1057    umask 077
1058
1059    # Service Search Descriptors
1060    LDAP_SERV_SRCH_DES=""
1061
1062    # Set and create TMPDIR.
1063    TMPDIR="/tmp/idsconfig.${PID}"
1064    if mkdir -m 700 ${TMPDIR}
1065    then
1066	# Cleanup on exit.
1067	trap 'rm -rf ${TMPDIR}; /usr/bin/stty echo; exit' 1 2 3 6 15
1068    else
1069	echo "ERROR: unable to create a safe temporary directory."
1070	exit 1
1071    fi
1072    LDAP_ROOTPWF=${TMPDIR}/rootPWD
1073
1074    # Set the SSD file name after setting TMPDIR.
1075    SSD_FILE=${TMPDIR}/ssd_list
1076
1077    # GSSAPI setup
1078    LDAP_KRB_REALM=""
1079    LDAP_GSSAPI_PROFILE=""
1080    SCHEMA_UPDATED=0
1081
1082    export DEBUG VERB ECHO EVAL EGREP GREP STEP TMPDIR
1083    export IDS_SERVER IDS_PORT LDAP_ROOTDN LDAP_ROOTPWD LDAP_SERVER_LIST
1084    export LDAP_BASEDN LDAP_ROOTPWF
1085    export LDAP_DOMAIN LDAP_SUFFIX LDAP_PROXYAGENT LDAP_PROXYAGENT_CRED
1086    export NEED_PROXY
1087    export LDAP_ENABLE_SHADOW_UPDATE LDAP_ADMINDN LDAP_ADMIN_CRED
1088    export NEED_ADMIN NEED_HOSTACL EXISTING_PROFILE
1089    export LDAP_PROFILE_NAME LDAP_BASEDN LDAP_SERVER_LIST
1090    export LDAP_AUTHMETHOD LDAP_FOLLOWREF LDAP_SEARCH_SCOPE LDAP_SEARCH_TIME_LIMIT
1091    export LDAP_PREF_SRVLIST LDAP_PROFILE_TTL LDAP_CRED_LEVEL LDAP_BIND_LIMIT
1092    export NEED_SRVAUTH_PAM NEED_SRVAUTH_KEY NEED_SRVAUTH_CMD
1093    export LDAP_SRV_AUTHMETHOD_PAM LDAP_SRV_AUTHMETHOD_KEY LDAP_SRV_AUTHMETHOD_CMD
1094    export LDAP_SERV_SRCH_DES SSD_FILE
1095    export GEN_CMD LDAP_KRB_REALM LDAP_GSSAPI_PROFILE SCHEMA_UPDATED
1096}
1097
1098
1099#
1100# disp_full_debug(): List of all debug variables usually interested in.
1101#                    Grouped to avoid MASSIVE code duplication.
1102#
1103disp_full_debug()
1104{
1105    [ $DEBUG -eq 1 ] && ${ECHO} "  IDS_SERVER = $IDS_SERVER"
1106    [ $DEBUG -eq 1 ] && ${ECHO} "  IDS_PORT = $IDS_PORT"
1107    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_ROOTDN = $LDAP_ROOTDN"
1108    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_ROOTPWD = $LDAP_ROOTPWD"
1109    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_DOMAIN = $LDAP_DOMAIN"
1110    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SUFFIX = $LDAP_SUFFIX"
1111    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_BASEDN = $LDAP_BASEDN"
1112    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_PROFILE_NAME = $LDAP_PROFILE_NAME"
1113    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SERVER_LIST = $LDAP_SERVER_LIST"
1114    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_PREF_SRVLIST = $LDAP_PREF_SRVLIST"
1115    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SEARCH_SCOPE = $LDAP_SEARCH_SCOPE"
1116    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_CRED_LEVEL = $LDAP_CRED_LEVEL"
1117    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_AUTHMETHOD = $LDAP_AUTHMETHOD"
1118    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_FOLLOWREF = $LDAP_FOLLOWREF"
1119    [ $DEBUG -eq 1 ] && ${ECHO} "  IDS_TIMELIMIT = $IDS_TIMELIMIT"
1120    [ $DEBUG -eq 1 ] && ${ECHO} "  IDS_SIZELIMIT = $IDS_SIZELIMIT"
1121    [ $DEBUG -eq 1 ] && ${ECHO} "  NEED_CRYPT = $NEED_CRYPT"
1122    [ $DEBUG -eq 1 ] && ${ECHO} "  NEED_SRVAUTH_PAM = $NEED_SRVAUTH_PAM"
1123    [ $DEBUG -eq 1 ] && ${ECHO} "  NEED_SRVAUTH_KEY = $NEED_SRVAUTH_KEY"
1124    [ $DEBUG -eq 1 ] && ${ECHO} "  NEED_SRVAUTH_CMD = $NEED_SRVAUTH_CMD"
1125    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SRV_AUTHMETHOD_PAM = $LDAP_SRV_AUTHMETHOD_PAM"
1126    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SRV_AUTHMETHOD_KEY = $LDAP_SRV_AUTHMETHOD_KEY"
1127    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SRV_AUTHMETHOD_CMD = $LDAP_SRV_AUTHMETHOD_CMD"
1128    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SEARCH_TIME_LIMIT = $LDAP_SEARCH_TIME_LIMIT"
1129    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_PROFILE_TTL = $LDAP_PROFILE_TTL"
1130    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_BIND_LIMIT = $LDAP_BIND_LIMIT"
1131    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_ENABLE_SHADOW_UPDATE = $LDAP_ENABLE_SHADOW_UPDATE"
1132
1133    # Only display proxy stuff if needed.
1134    [ $DEBUG -eq 1 ] && ${ECHO} "  NEED_PROXY = $NEED_PROXY"
1135    if [ $NEED_PROXY -eq  1 ]; then
1136	[ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_PROXYAGENT = $LDAP_PROXYAGENT"
1137	[ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_PROXYAGENT_CRED = $LDAP_PROXYAGENT_CRED"
1138    fi
1139
1140    # Only display admin credential if needed.
1141    [ $DEBUG -eq 1 ] && ${ECHO} "  NEED_ADMIN = $NEED_ADMIN"
1142    [ $DEBUG -eq 1 ] && ${ECHO} "  NEED_HOSTACL = $NEED_HOSTACL"
1143    if [ $NEED_ADMIN -eq  1 ]; then
1144	[ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_ADMINDN = $LDAP_ADMINDN"
1145	[ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_ADMIN_CRED = $LDAP_ADMIN_CRED"
1146    fi
1147
1148    # Service Search Descriptors are a special case.
1149    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SERV_SRCH_DES = $LDAP_SERV_SRCH_DES"
1150}
1151
1152
1153#
1154# load_config_file(): Loads the config file.
1155#
1156load_config_file()
1157{
1158    [ $DEBUG -eq 1 ] && ${ECHO} "In load_config_file()"
1159
1160    # Remove SSD lines from input file before sourcing.
1161    # The SSD lines must be removed because some forms of the
1162    # data could cause SHELL errors.
1163    ${GREP} -v "LDAP_SERV_SRCH_DES=" ${INPUT_FILE} > ${TMPDIR}/inputfile.noSSD
1164
1165    # Source the input file.
1166    . ${TMPDIR}/inputfile.noSSD
1167
1168    # If LDAP_SUFFIX is no set, try to utilize LDAP_TREETOP since older
1169    # config files use LDAP_TREETOP
1170    LDAP_SUFFIX="${LDAP_SUFFIX:-$LDAP_TREETOP}"
1171
1172    # Save password to temporary file.
1173    save_password
1174
1175    # Create the SSD file.
1176    create_ssd_file
1177
1178    # Display FULL debugging info.
1179    disp_full_debug
1180}
1181
1182#
1183# save_password(): Save password to temporary file.
1184#
1185save_password()
1186{
1187    cat > ${LDAP_ROOTPWF} <<EOF
1188${LDAP_ROOTPWD}
1189EOF
1190}
1191
1192######################################################################
1193# FUNCTIONS  FOR prompt_config_info() START HERE.
1194######################################################################
1195
1196#
1197# get_ids_server(): Prompt for iDS server name.
1198#
1199get_ids_server()
1200{
1201    while :
1202    do
1203	# Prompt for server name.
1204	get_ans "Enter the JES Directory Server's  hostname to setup:" "$IDS_SERVER"
1205	IDS_SERVER="$ANS"
1206
1207	# Ping server to see if live.  If valid break out of loop.
1208	ping $IDS_SERVER > /dev/null 2>&1
1209	if [ $? -eq 0 ]; then
1210	    break
1211	fi
1212
1213	# Invalid server, enter a new name.
1214	${ECHO} "ERROR: Server '${IDS_SERVER}' is invalid or unreachable."
1215	IDS_SERVER=""
1216    done
1217
1218    # Set SERVER_ARGS and LDAP_ARGS since values might of changed.
1219    SERVER_ARGS="-h ${IDS_SERVER} -p ${IDS_PORT}"
1220    LDAP_ARGS="${SERVER_ARGS} ${AUTH_ARGS}"
1221    export SERVER_ARGS
1222
1223}
1224
1225#
1226# get_ids_port(): Prompt for iDS port number.
1227#
1228get_ids_port()
1229{
1230    # Get a valid iDS port number.
1231    while :
1232    do
1233	# Enter port number.
1234	get_number "Enter the port number for iDS (h=help):" "$IDS_PORT" "port_help"
1235	IDS_PORT=$ANS
1236	# Do a simple search to check hostname and port number.
1237	# If search returns SUCCESS, break out, host and port must
1238	# be valid.
1239	${LDAPSEARCH} -h ${IDS_SERVER} -p ${IDS_PORT} -b "" -s base "objectclass=*" > /dev/null 2>&1
1240	if [ $? -eq 0 ]; then
1241	    break
1242	fi
1243
1244	# Invalid host/port pair, Re-enter.
1245	${ECHO} "ERROR: Invalid host or port: ${IDS_SERVER}:${IDS_PORT}, Please re-enter!"
1246	get_ids_server
1247    done
1248
1249    # Set SERVER_ARGS and LDAP_ARGS since values might of changed.
1250    SERVER_ARGS="-h ${IDS_SERVER} -p ${IDS_PORT}"
1251    LDAP_ARGS="${SERVER_ARGS} ${AUTH_ARGS}"
1252    export SERVER_ARGS
1253}
1254
1255
1256#
1257# chk_ids_version(): Read the slapd config file and set variables
1258#
1259chk_ids_version()
1260{
1261    [ $DEBUG -eq 1 ] && ${ECHO} "In chk_ids_version()"
1262
1263    # check iDS version number.
1264    eval "${LDAPSEARCH} ${SERVER_ARGS} -b cn=monitor -s base \"objectclass=*\" version | ${GREP} \"^version=\" | cut -f2 -d'/' | cut -f1 -d' ' > ${TMPDIR}/checkDSver 2>&1"
1265    if [ $? -ne 0 ]; then
1266	${ECHO} "ERROR: Can not determine the version number of iDS!"
1267	exit 1
1268    fi
1269    IDS_VER=`cat ${TMPDIR}/checkDSver`
1270    IDS_MAJVER=`${ECHO} ${IDS_VER} | cut -f1 -d.`
1271    IDS_MINVER=`${ECHO} ${IDS_VER} | cut -f2 -d.`
1272    if [ "${IDS_MAJVER}" != "5" ] && [ "${IDS_MAJVER}" != "6" ]; then
1273	${ECHO} "ERROR: $PROG only works with JES DS version 5.x and 6.x, not ${IDS_VER}."
1274    	exit 1
1275    fi
1276    if [ $DEBUG -eq 1 ]; then
1277	${ECHO} "  IDS_MAJVER = $IDS_MAJVER"
1278	${ECHO} "  IDS_MINVER = $IDS_MINVER"
1279    fi
1280}
1281
1282
1283#
1284# get_dirmgr_dn(): Get the directory manger DN.
1285#
1286get_dirmgr_dn()
1287{
1288    get_ans "Enter the directory manager DN:" "$LDAP_ROOTDN"
1289    LDAP_ROOTDN=$ANS
1290
1291    # Update ENV variables using DN.
1292    AUTH_ARGS="-D \"${LDAP_ROOTDN}\" -j ${LDAP_ROOTPWF}"
1293    LDAP_ARGS="${SERVER_ARGS} ${AUTH_ARGS}"
1294    export AUTH_ARGS LDAP_ARGS
1295}
1296
1297
1298#
1299# get_dirmgr_pw(): Get the Root DN passwd. (Root DN found in slapd.conf)
1300#
1301get_dirmgr_pw()
1302{
1303    while :
1304    do
1305	# Get passwd.
1306	get_passwd_nochk "Enter passwd for ${LDAP_ROOTDN} :"
1307	LDAP_ROOTPWD=$ANS
1308
1309	# Store password in file.
1310	save_password
1311
1312	# Update ENV variables using DN's PW.
1313	AUTH_ARGS="-D \"${LDAP_ROOTDN}\" -j ${LDAP_ROOTPWF}"
1314	LDAP_ARGS="${SERVER_ARGS} ${AUTH_ARGS}"
1315	export AUTH_ARGS LDAP_ARGS
1316
1317	# Verify that ROOTDN and ROOTPWD are valid.
1318	eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"\" -s base \"objectclass=*\" > ${TMPDIR}/checkDN 2>&1"
1319	if [ $? -ne 0 ]; then
1320	    eval "${GREP} credential ${TMPDIR}/checkDN ${VERB}"
1321	    if [ $? -eq 0 ]; then
1322		${ECHO} "ERROR: Root DN passwd is invalid."
1323	    else
1324		${ECHO} "ERROR: Invalid Root DN <${LDAP_ROOTDN}>."
1325		get_dirmgr_dn
1326	    fi
1327	else
1328	    break         # Both are valid.
1329	fi
1330    done
1331
1332
1333}
1334
1335
1336#
1337# get_domain(): Get the Domain that will be served by the LDAP server.
1338#               $1 - Help argument.
1339#
1340get_domain()
1341{
1342    # Use LDAP_DOMAIN as default.
1343    get_ans "Enter the domainname to be served (h=help):" $LDAP_DOMAIN
1344
1345    # Check domainname, and have user re-enter if not valid.
1346    check_domainname $ANS
1347    while [ $? -ne 0 ]
1348    do
1349	case "$ANS" in
1350	    [Hh] | help | Help | \?) display_msg ${1:-sorry} ;;
1351	    * ) ${ECHO} "Invalid domainname: \"${ANS}\"."
1352	     ;;
1353	esac
1354	get_ans "Enter domainname to be served (h=help):" $DOM
1355
1356	check_domainname $ANS
1357    done
1358
1359    # Set the domainname to valid name.
1360    LDAP_DOMAIN=$ANS
1361}
1362
1363
1364#
1365# get_basedn(): Query for the Base DN.
1366#
1367get_basedn()
1368{
1369    # Set the $_DOM_2_DC and assign to LDAP_BASEDN as default.
1370    # Then call get_basedn().  This method remakes the default
1371    # each time just in case the domain changed.
1372    domain_2_dc $LDAP_DOMAIN
1373    LDAP_BASEDN=$_DOM_2_DC
1374
1375    # Get Base DN.
1376    while :
1377    do
1378	get_ans_req "Enter LDAP Base DN (h=help):" "${_DOM_2_DC}"
1379	check_baseDN "$ANS"
1380	while [ $? -ne 0 ]
1381	do
1382	    case "$ANS" in
1383		[Hh] | help | Help | \?) display_msg basedn_help ;;
1384		* ) ${ECHO} "Invalid base DN: \"${ANS}\"."
1385		;;
1386	    esac
1387
1388	    # Re-Enter the BaseDN
1389	    get_ans_req "Enter LDAP Base DN (h=help):" "${_DOM_2_DC}"
1390	    check_baseDN "$ANS"
1391	done
1392
1393	# Set base DN and check its suffix
1394	LDAP_BASEDN=${ANS}
1395	check_basedn_suffix ||
1396	{
1397		cleanup
1398		exit 1
1399	}
1400
1401	# suffix may need to be created, in that case get suffix from user
1402	[ -n "${NEED_CREATE_SUFFIX}" ] &&
1403	{
1404		get_suffix || continue
1405	}
1406
1407	# suffix is ok, break out of the base dn inquire loop
1408	break
1409    done
1410}
1411
1412#
1413# get_want_shadow_update(): Ask user if want to enable shadow update?
1414#
1415get_want_shadow_update()
1416{
1417    MSG="Do you want to enable shadow update (y/n/h)?"
1418    get_confirm "$MSG" "n" "enable_shadow_update_help"
1419    if [ $? -eq 1 ]; then
1420	LDAP_ENABLE_SHADOW_UPDATE="TRUE"
1421    else
1422	LDAP_ENABLE_SHADOW_UPDATE="FALSE"
1423    fi
1424}
1425
1426get_krb_realm() {
1427
1428    # To upper cases
1429    LDAP_KRB_REALM=`${ECHO} ${LDAP_DOMAIN} | ${NAWK} '{ print toupper($0) }'`
1430    get_ans_req "Enter Kerberos Realm:" "$LDAP_KRB_REALM"
1431    # To upper cases
1432    LDAP_KRB_REALM=`${ECHO} ${ANS} | ${NAWK} '{ print toupper($0) }'`
1433}
1434
1435# $1: DN
1436# $2: ldif file
1437add_entry_by_DN() {
1438
1439    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${1}\" -s base \"objectclass=*\" ${VERB}"
1440    if [ $? -eq 0 ]; then
1441	    ${ECHO} "  ${1} already exists"
1442	    return 0
1443    else
1444	${EVAL} "${LDAPADD} ${LDAP_ARGS} -f ${2} ${VERB}"
1445	if [ $? -eq 0 ]; then
1446		${ECHO} "  ${1} is added"
1447	    	return 0
1448	else
1449		${ECHO} "  ERROR: failed to add ${1}"
1450		return 1
1451	fi
1452    fi
1453
1454}
1455#
1456# Kerberos princiapl to DN mapping rules
1457#
1458# Add rules for host credentails and user credentials
1459#
1460add_id_mapping_rules() {
1461
1462    ${ECHO} "  Adding Kerberos principal to DN mapping rules..."
1463
1464    _C_DN="cn=GSSAPI,cn=identity mapping,cn=config"
1465    ( cat << EOF
1466dn: cn=GSSAPI,cn=identity mapping,cn=config
1467objectClass: top
1468objectClass: nsContainer
1469cn: GSSAPI
1470EOF
1471) > ${TMPDIR}/GSSAPI_container.ldif
1472
1473    add_entry_by_DN "${_C_DN}" "${TMPDIR}/GSSAPI_container.ldif"
1474    if [ $? -ne 0 ];
1475    then
1476    	${RM} ${TMPDIR}/GSSAPI_container.ldif
1477	return
1478    fi
1479
1480    _H_CN="host_auth_${LDAP_KRB_REALM}"
1481    _H_DN="cn=${_H_CN}, ${_C_DN}"
1482    ( cat << EOF
1483dn: ${_H_DN}
1484objectClass: top
1485objectClass: nsContainer
1486objectClass: dsIdentityMapping
1487objectClass: dsPatternMatching
1488cn: ${_H_CN}
1489dsMatching-pattern: \${Principal}
1490dsMatching-regexp: host\/(.*).${LDAP_DOMAIN}@${LDAP_KRB_REALM}
1491dsSearchBaseDN: ou=hosts,${LDAP_BASEDN}
1492dsSearchFilter: (&(objectClass=ipHost)(cn=\$1))
1493dsSearchScope: one
1494
1495EOF
1496) > ${TMPDIR}/${_H_CN}.ldif
1497
1498    add_entry_by_DN "${_H_DN}" "${TMPDIR}/${_H_CN}.ldif"
1499
1500    _U_CN="user_auth_${LDAP_KRB_REALM}"
1501    _U_DN="cn=${_U_CN}, ${_C_DN}"
1502    ( cat << EOF
1503dn: ${_U_DN}
1504objectClass: top
1505objectClass: nsContainer
1506objectClass: dsIdentityMapping
1507objectClass: dsPatternMatching
1508cn: ${_U_CN}
1509dsMatching-pattern: \${Principal}
1510dsMatching-regexp: (.*)@${LDAP_KRB_REALM}
1511dsMappedDN: uid=\$1,ou=People,${LDAP_BASEDN}
1512
1513EOF
1514) > ${TMPDIR}/${_U_CN}.ldif
1515
1516    add_entry_by_DN "${_U_DN}" "${TMPDIR}/${_U_CN}.ldif"
1517
1518}
1519
1520
1521#
1522# Modify ACL to allow root to read all the password and only self can read
1523# its own password when sasl/GSSAPI bind is used
1524#
1525modify_userpassword_acl_for_gssapi() {
1526
1527    _P_DN="ou=People,${LDAP_BASEDN}"
1528    _H_DN="ou=Hosts,${LDAP_BASEDN}"
1529    _P_ACI="self-read-pwd"
1530
1531    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${_P_DN}\" -s base \"objectclass=*\" > /dev/null 2>&1"
1532    if [ $? -ne 0 ]; then
1533	    ${ECHO} "  ${_P_DN} does not exist"
1534	# Not Found. Create a new entry
1535	( cat << EOF
1536dn: ${_P_DN}
1537ou: People
1538objectClass: top
1539objectClass: organizationalUnit
1540EOF
1541) > ${TMPDIR}/gssapi_people.ldif
1542
1543	add_entry_by_DN "${_P_DN}" "${TMPDIR}/gssapi_people.ldif"
1544    else
1545	${ECHO} "  ${_P_DN} already exists"
1546    fi
1547
1548    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${_P_DN}\" -s base \"objectclass=*\" aci > ${TMPDIR}/chk_gssapi_aci 2>&1"
1549
1550    if [ $? -eq 0 ]; then
1551	    ${EVAL} "${GREP} ${_P_ACI} ${TMPDIR}/chk_gssapi_aci > /dev/null 2>&1"
1552	    if [ $? -eq 0 ]; then
1553		${ECHO} "  userpassword ACL ${_P_ACI} already exists."
1554		return
1555	    else
1556		${ECHO} "  userpassword ACL ${_P_ACI} not found. Create a new one."
1557	    fi
1558    else
1559	${ECHO} "  Error searching aci for ${_P_DN}"
1560	cat ${TMPDIR}/chk_gssapi_aci
1561	cleanup
1562	exit 1
1563    fi
1564    ( cat << EOF
1565dn: ${_P_DN}
1566changetype: modify
1567add: aci
1568aci: (targetattr="userPassword")(version 3.0; acl self-read-pwd; allow (read,search) userdn="ldap:///self" and authmethod="sasl GSSAPI";)
1569-
1570add: aci
1571aci: (targetattr="userPassword")(version 3.0; acl host-read-pwd; allow (read,search) userdn="ldap:///cn=*+ipHostNumber=*,ou=Hosts,${LDAP_BASEDN}" and authmethod="sasl GSSAPI";)
1572EOF
1573) > ${TMPDIR}/user_gssapi.ldif
1574    LDAP_TYPE_OR_VALUE_EXISTS=20
1575    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/user_gssapi.ldif ${VERB}"
1576
1577    case $? in
1578    0)
1579	${ECHO} "  ${_P_DN} uaserpassword ACL is updated."
1580	;;
1581    20)
1582	${ECHO} "  ${_P_DN} uaserpassword ACL already exists."
1583	;;
1584    *)
1585	${ECHO} "  ERROR: update of userpassword ACL for ${_P_DN} failed!"
1586	cleanup
1587	exit 1
1588	;;
1589    esac
1590}
1591#
1592# $1: objectclass or attributetyp
1593# $2: name
1594search_update_schema() {
1595
1596    ATTR="${1}es"
1597
1598    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b cn=schema -s base \"objectclass=*\" ${ATTR} | ${GREP} -i \"${2}\" ${VERB}"
1599    if [ $? -ne 0 ]; then
1600	${ECHO} "${1} ${2} does not exist."
1601        update_schema_attr
1602        update_schema_obj
1603	SCHEMA_UPDATED=1
1604    else
1605	${ECHO} "${1} ${2} already exists. Schema has been updated"
1606    fi
1607}
1608
1609#
1610# $1: 1 - interactive, 0 - no
1611#
1612create_gssapi_profile() {
1613
1614
1615    if [ ${1} -eq 1 ]; then
1616        echo
1617        echo "You can create a sasl/GSSAPI enabled profile with default values now."
1618        get_confirm "Do you want to create a sasl/GSSAPI default profile ?" "n"
1619
1620        if [ $? -eq 0 ]; then
1621	    return
1622        fi
1623    fi
1624
1625    # Add profile container if it does not exist
1626    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"ou=profile,${LDAP_BASEDN}\" -s base \"objectclass=*\" > /dev/null 2>&1"
1627    if [ $? -ne 0 ]; then
1628	( cat << EOF
1629dn: ou=profile,${LDAP_BASEDN}
1630ou: profile
1631objectClass: top
1632objectClass: organizationalUnit
1633EOF
1634) > ${TMPDIR}/profile_people.ldif
1635
1636        add_entry_by_DN "ou=profile,${LDAP_BASEDN}" "${TMPDIR}/profile_people.ldif"
1637
1638    fi
1639
1640    search_update_schema "objectclass" "DUAConfigProfile"
1641
1642    _P_NAME="gssapi_${LDAP_KRB_REALM}"
1643    if [ ${1} -eq 1 ]; then
1644    	_P_TMP=${LDAP_PROFILE_NAME}
1645    	LDAP_PROFILE_NAME=${_P_NAME}
1646   	get_profile_name
1647        LDAP_GSSAPI_PROFILE=${LDAP_PROFILE_NAME}
1648    	LDAP_PROFILE_NAME=${_P_TMP}
1649    fi
1650
1651    _P_DN="cn=${LDAP_GSSAPI_PROFILE},ou=profile,${LDAP_BASEDN}"
1652    if [ ${DEL_OLD_PROFILE} -eq 1 ]; then
1653	    DEL_OLD_PROFILE=0
1654	    ${EVAL} "${LDAPDELETE} ${LDAP_ARGS} ${_P_DN} ${VERB}"
1655    fi
1656
1657    _SVR=`getent hosts ${IDS_SERVER} | ${NAWK} '{ print $1 }'`
1658    if [ ${IDS_PORT} -ne 389 ]; then
1659	    _SVR="${_SVR}:${IDS_PORT}"
1660    fi
1661
1662    (cat << EOF
1663dn: ${_P_DN}
1664objectClass: top
1665objectClass: DUAConfigProfile
1666defaultServerList: ${_SVR}
1667defaultSearchBase: ${LDAP_BASEDN}
1668authenticationMethod: sasl/GSSAPI
1669followReferrals: ${LDAP_FOLLOWREF}
1670defaultSearchScope: ${LDAP_SEARCH_SCOPE}
1671searchTimeLimit: ${LDAP_SEARCH_TIME_LIMIT}
1672profileTTL: ${LDAP_PROFILE_TTL}
1673cn: ${LDAP_GSSAPI_PROFILE}
1674credentialLevel: self
1675bindTimeLimit: ${LDAP_BIND_LIMIT}
1676EOF
1677) > ${TMPDIR}/gssapi_profile.ldif
1678
1679    add_entry_by_DN "${_P_DN}" "${TMPDIR}/gssapi_profile.ldif"
1680
1681}
1682#
1683# Set up GSSAPI if necessary
1684#
1685gssapi_setup() {
1686
1687	# assume sasl/GSSAPI is supported by the ldap server and may be used
1688	GSSAPI_AUTH_MAY_BE_USED=1
1689	${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"\" -s base \"objectclass=*\" supportedSASLMechanisms | ${GREP} GSSAPI ${VERB}"
1690	if [ $? -ne 0 ]; then
1691		GSSAPI_AUTH_MAY_BE_USED=0
1692		${ECHO} "  sasl/GSSAPI is not supported by this LDAP server"
1693		return
1694	fi
1695
1696	get_confirm "GSSAPI is supported. Do you want to set up gssapi:(y/n)" "n"
1697	if [ $? -eq 0 ]; then
1698		${ECHO}
1699		${ECHO} "GSSAPI is not set up."
1700		${ECHO} "sasl/GSSAPI bind may not work if it's not set up first."
1701	else
1702		get_krb_realm
1703		add_id_mapping_rules
1704		modify_userpassword_acl_for_gssapi
1705		create_gssapi_profile 1
1706		${ECHO}
1707		${ECHO} "GSSAPI setup is done."
1708	fi
1709
1710	cat << EOF
1711
1712You can continue to create a profile and
1713configure the LDAP server.
1714Or you can stop now.
1715
1716EOF
1717	get_confirm "Do you want to stop:(y/n)" "n"
1718	if [ $? -eq 1 ]; then
1719		cleanup
1720		exit
1721	fi
1722
1723}
1724gssapi_setup_auto() {
1725	GSSAPI_AUTH_MAY_BE_USED=0
1726	${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"\" -s base \"objectclass=*\" supportedSASLMechanisms | ${GREP} GSSAPI ${VERB}"
1727	if [ $? -ne 0 ]; then
1728		${ECHO}
1729		${ECHO} "sasl/GSSAPI is not supported by this LDAP server"
1730		${ECHO}
1731		return
1732	fi
1733	if [ -z "${LDAP_KRB_REALM}" ]; then
1734		${ECHO}
1735		${ECHO} "LDAP_KRB_REALM is not set. Skip gssapi setup."
1736		${ECHO} "sasl/GSSAPI bind won't work properly."
1737		${ECHO}
1738		return
1739	fi
1740	GSSAPI_AUTH_MAY_BE_USED=1
1741	if [ -z "${LDAP_GSSAPI_PROFILE}" ]; then
1742		${ECHO}
1743		${ECHO} "LDAP_GSSAPI_PROFILE is not set. Default is gssapi_${LDAP_KRB_REALM}"
1744		${ECHO}
1745		LDAP_GSSAPI_PROFILE="gssapi_${LDAP_KRB_REALM}"
1746	fi
1747	add_id_mapping_rules
1748	modify_userpassword_acl_for_gssapi
1749	create_gssapi_profile 0
1750}
1751# get_profile_name(): Enter the profile name.
1752#
1753get_profile_name()
1754{
1755    # Reset Delete Old Profile since getting new profile name.
1756    DEL_OLD_PROFILE=0
1757
1758    # Loop until valid profile name, or replace.
1759    while :
1760    do
1761	# Prompt for profile name.
1762	get_ans "Enter the profile name (h=help):" "$LDAP_PROFILE_NAME"
1763
1764	# Check for Help.
1765	case "$ANS" in
1766	    [Hh] | help | Help | \?) display_msg profile_help
1767				     continue ;;
1768	    * )  ;;
1769	esac
1770
1771	# Search to see if profile name already exists.
1772	eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${ANS},ou=profile,${LDAP_BASEDN}\" -s base \"objectclass=*\" ${VERB}"
1773	if [ $? -eq 0 ]; then
1774
1775	    cat << EOF
1776
1777Profile '${ANS}' already exists, it is possible to enable
1778shadow update now. idsconfig will exit after shadow update
1779is enabled. You can also continue to overwrite the profile 
1780or create a new one and be given the chance to enable
1781shadow update later.
1782
1783EOF
1784
1785	    MSG="Just enable shadow update (y/n/h)?"
1786	    get_confirm "$MSG" "n" "enable_shadow_update_help"
1787	    if [ $? -eq 1 ]; then
1788	        [ $DEBUG -eq 1 ] && ${ECHO} "set up shadow update"
1789	        LDAP_ENABLE_SHADOW_UPDATE=TRUE
1790		# display alternate messages
1791		EXISTING_PROFILE=1
1792	        # Set Profile Name.
1793	        LDAP_PROFILE_NAME=$ANS
1794	        return 0  # set up credentials for shadow update.
1795	    fi
1796
1797	    get_confirm_nodef "Are you sure you want to overwrite profile cn=${ANS}?"
1798	    if [ $? -eq 1 ]; then
1799		DEL_OLD_PROFILE=1
1800		return 0  # Replace old profile name.
1801	    else
1802		${ECHO} "Please re-enter a new profile name."
1803	    fi
1804	else
1805	    break  # Unique profile name.
1806	fi
1807    done
1808
1809    # Set Profile Name.
1810    LDAP_PROFILE_NAME=$ANS
1811}
1812
1813
1814#
1815# get_srv_list(): Get the default server list.
1816#
1817get_srv_list()
1818{
1819    # If LDAP_SERVER_LIST is NULL, then set, otherwise leave alone.
1820    if [ -z "${LDAP_SERVER_LIST}" ]; then
1821	LDAP_SERVER_LIST=`getent hosts ${IDS_SERVER} | awk '{print $1}'`
1822        if [ ${IDS_PORT} -ne 389 ]; then
1823	    LDAP_SERVER_LIST="${LDAP_SERVER_LIST}:${IDS_PORT}"
1824	fi
1825    fi
1826
1827    # Prompt for new LDAP_SERVER_LIST.
1828    while :
1829    do
1830	get_ans "Default server list (h=help):" $LDAP_SERVER_LIST
1831
1832	# If help continue, otherwise break.
1833	case "$ANS" in
1834	    [Hh] | help | Help | \?) display_msg def_srvlist_help ;;
1835	    * ) break ;;
1836	esac
1837    done
1838    LDAP_SERVER_LIST=$ANS
1839}
1840
1841
1842#
1843# get_pref_srv(): The preferred server list (Overrides the server list)
1844#
1845get_pref_srv()
1846{
1847    while :
1848    do
1849	get_ans "Preferred server list (h=help):" $LDAP_PREF_SRVLIST
1850
1851	# If help continue, otherwise break.
1852	case "$ANS" in
1853	    [Hh] | help | Help | \?) display_msg pref_srvlist_help ;;
1854	    * ) break ;;
1855	esac
1856    done
1857    LDAP_PREF_SRVLIST=$ANS
1858}
1859
1860
1861#
1862# get_search_scope(): Get the search scope from the user.
1863#
1864get_search_scope()
1865{
1866    [ $DEBUG -eq 1 ] && ${ECHO} "In get_search_scope()"
1867
1868    _MENU_CHOICE=0
1869    while :
1870    do
1871	get_ans "Choose desired search scope (one, sub, h=help): " "one"
1872	_MENU_CHOICE=$ANS
1873	case "$_MENU_CHOICE" in
1874	    one) LDAP_SEARCH_SCOPE="one"
1875	       return 1 ;;
1876	    sub) LDAP_SEARCH_SCOPE="sub"
1877	       return 2 ;;
1878	    h) display_msg srch_scope_help ;;
1879	    *) ${ECHO} "Please enter \"one\", \"sub\", or \"h\"." ;;
1880	esac
1881    done
1882
1883}
1884
1885
1886#
1887# get_cred_level(): Function to display menu to user and get the
1888#                  credential level.
1889#
1890get_cred_level()
1891{
1892    [ $DEBUG -eq 1 ] && ${ECHO} "In get_cred_level()"
1893
1894    _MENU_CHOICE=0
1895    display_msg cred_level_menu
1896    while :
1897    do
1898	get_ans "Choose Credential level [h=help]:" "1"
1899	_MENU_CHOICE=$ANS
1900	case "$_MENU_CHOICE" in
1901	    1) LDAP_CRED_LEVEL="anonymous"
1902	       return 1 ;;
1903	    2) LDAP_CRED_LEVEL="proxy"
1904	       return 2 ;;
1905	    3) LDAP_CRED_LEVEL="proxy anonymous"
1906	       return 3 ;;
1907	    4) LDAP_CRED_LEVEL="self"
1908	       SELF_GSSAPI=1
1909	       return 4 ;;
1910	    5) LDAP_CRED_LEVEL="self proxy"
1911	       SELF_GSSAPI=1
1912	       return 5 ;;
1913	    6) LDAP_CRED_LEVEL="self proxy anonymous"
1914	       SELF_GSSAPI=1
1915	       return 6 ;;
1916	    h) display_msg cred_lvl_help ;;
1917	    *) ${ECHO} "Please enter 1, 2, 3, 4, 5 or 6." ;;
1918	esac
1919    done
1920}
1921
1922
1923#
1924# srvauth_menu_handler(): Enter the Service Authentication method.
1925#
1926srvauth_menu_handler()
1927{
1928    # Display Auth menu
1929    display_msg srvauth_method_menu
1930
1931    # Get a Valid choice.
1932    while :
1933    do
1934	# Display appropriate prompt and get answer.
1935	if [ $_FIRST -eq 1 ]; then
1936	    get_ans "Choose Service Authentication Method:" "1"
1937	else
1938	    get_ans "Choose Service Authentication Method (0=reset):"
1939	fi
1940
1941	# Determine choice.
1942	_MENU_CHOICE=$ANS
1943	case "$_MENU_CHOICE" in
1944	    1) _AUTHMETHOD="simple"
1945		break ;;
1946	    2) _AUTHMETHOD="sasl/DIGEST-MD5"
1947		break ;;
1948	    3) _AUTHMETHOD="tls:simple"
1949		break ;;
1950	    4) _AUTHMETHOD="tls:sasl/DIGEST-MD5"
1951		break ;;
1952	    5) _AUTHMETHOD="sasl/GSSAPI"
1953		break ;;
1954	    0) _AUTHMETHOD=""
1955		_FIRST=1
1956		break ;;
1957	    *) ${ECHO} "Please enter 1-5 or 0 to reset." ;;
1958	esac
1959    done
1960}
1961
1962
1963#
1964# auth_menu_handler(): Enter the Authentication method.
1965#
1966auth_menu_handler()
1967{
1968    # Display Auth menu
1969    display_msg auth_method_menu
1970
1971    # Get a Valid choice.
1972    while :
1973    do
1974	# Display appropriate prompt and get answer.
1975	if [ $_FIRST -eq 1 ]; then
1976	    get_ans "Choose Authentication Method (h=help):" "1"
1977	else
1978	    get_ans "Choose Authentication Method (0=reset, h=help):"
1979	fi
1980
1981	# Determine choice.
1982	_MENU_CHOICE=$ANS
1983	case "$_MENU_CHOICE" in
1984	    1) _AUTHMETHOD="none"
1985		break ;;
1986	    2) _AUTHMETHOD="simple"
1987		break ;;
1988	    3) _AUTHMETHOD="sasl/DIGEST-MD5"
1989		break ;;
1990	    4) _AUTHMETHOD="tls:simple"
1991		break ;;
1992	    5) _AUTHMETHOD="tls:sasl/DIGEST-MD5"
1993		break ;;
1994	    6) _AUTHMETHOD="sasl/GSSAPI"
1995		break ;;
1996	    0) _AUTHMETHOD=""
1997		_FIRST=1
1998		break ;;
1999	    h) display_msg auth_help ;;
2000	    *) ${ECHO} "Please enter 1-6, 0=reset, or h=help." ;;
2001	esac
2002    done
2003}
2004
2005
2006#
2007# get_auth(): Enter the Authentication method.
2008#
2009get_auth()
2010{
2011    [ $DEBUG -eq 1 ] && ${ECHO} "In get_auth()"
2012
2013    _FIRST=1          # Flag for first time.
2014    _MENU_CHOICE=0
2015    _AUTHMETHOD=""    # Tmp method.
2016
2017    while :
2018    do
2019	# Call Menu handler
2020	auth_menu_handler
2021
2022	# Add Auth Method to list.
2023        if [ $_FIRST -eq 1 ]; then
2024	    LDAP_AUTHMETHOD="${_AUTHMETHOD}"
2025	    _FIRST=0
2026	else
2027	    LDAP_AUTHMETHOD="${LDAP_AUTHMETHOD};${_AUTHMETHOD}"
2028	fi
2029
2030	# Display current Authentication Method.
2031	${ECHO} ""
2032	${ECHO} "Current authenticationMethod: ${LDAP_AUTHMETHOD}"
2033	${ECHO} ""
2034
2035	# Prompt for another Auth Method, or break out.
2036	get_confirm_nodef "Do you want to add another Authentication Method?"
2037	if [ $? -eq 0 ]; then
2038	    break;
2039	fi
2040    done
2041}
2042
2043
2044#
2045# get_followref(): Whether or not to follow referrals.
2046#
2047get_followref()
2048{
2049    get_confirm "Do you want the clients to follow referrals (y/n/h)?" "n" "referrals_help"
2050    if [ $? -eq 1 ]; then
2051	LDAP_FOLLOWREF="TRUE"
2052    else
2053	LDAP_FOLLOWREF="FALSE"
2054    fi
2055}
2056
2057
2058#
2059# get_timelimit(): Set the time limit. -1 is max time.
2060#
2061get_timelimit()
2062{
2063    # Get current timeout value from cn=config.
2064    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=config\" -s base \"objectclass=*\" nsslapd-timelimit > ${TMPDIR}/chk_timeout 2>&1"
2065    if [ $? -ne 0 ]; then
2066	${ECHO} "  ERROR: Could not reach LDAP server to check current timeout!"
2067	cleanup
2068	exit 1
2069    fi
2070    CURR_TIMELIMIT=`${GREP} timelimit ${TMPDIR}/chk_timeout | cut -f2 -d=`
2071
2072    get_negone_num "Enter the time limit for iDS (current=${CURR_TIMELIMIT}):" "-1"
2073    IDS_TIMELIMIT=$NUM
2074}
2075
2076
2077#
2078# get_sizelimit(): Set the size limit. -1 is max size.
2079#
2080get_sizelimit()
2081{
2082    # Get current sizelimit value from cn=config.
2083    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=config\" -s base \"objectclass=*\" nsslapd-sizelimit > ${TMPDIR}/chk_sizelimit 2>&1"
2084    if [ $? -ne 0 ]; then
2085	${ECHO} "  ERROR: Could not reach LDAP server to check current sizelimit!"
2086	cleanup
2087	exit 1
2088    fi
2089    CURR_SIZELIMIT=`${GREP} sizelimit ${TMPDIR}/chk_sizelimit | cut -f2 -d=`
2090
2091    get_negone_num "Enter the size limit for iDS (current=${CURR_SIZELIMIT}):" "-1"
2092    IDS_SIZELIMIT=$NUM
2093}
2094
2095
2096#
2097# get_want_crypt(): Ask user if want to store passwords in crypt?
2098#
2099get_want_crypt()
2100{
2101    get_confirm "Do you want to store passwords in \"crypt\" format (y/n/h)?" "n" "crypt_help"
2102    if [ $? -eq 1 ]; then
2103	NEED_CRYPT="TRUE"
2104    else
2105	NEED_CRYPT="FALSE"
2106    fi
2107}
2108
2109
2110#
2111# get_srv_authMethod_pam(): Get the Service Auth Method for pam_ldap from user.
2112#
2113#  NOTE: This function is base on get_auth().
2114#
2115get_srv_authMethod_pam()
2116{
2117    [ $DEBUG -eq 1 ] && ${ECHO} "In get_srv_authMethod_pam()"
2118
2119    _FIRST=1          # Flag for first time.
2120    _MENU_CHOICE=0
2121    _AUTHMETHOD=""    # Tmp method.
2122
2123    while :
2124    do
2125	# Call Menu handler
2126	srvauth_menu_handler
2127
2128	# Add Auth Method to list.
2129        if [ $_FIRST -eq 1 ]; then
2130	    if [ "$_AUTHMETHOD" = "" ]; then
2131		LDAP_SRV_AUTHMETHOD_PAM=""
2132	    else
2133		LDAP_SRV_AUTHMETHOD_PAM="pam_ldap:${_AUTHMETHOD}"
2134	    fi
2135	    _FIRST=0
2136	else
2137	    LDAP_SRV_AUTHMETHOD_PAM="${LDAP_SRV_AUTHMETHOD_PAM};${_AUTHMETHOD}"
2138	fi
2139
2140	# Display current Authentication Method.
2141	${ECHO} ""
2142	${ECHO} "Current authenticationMethod: ${LDAP_SRV_AUTHMETHOD_PAM}"
2143	${ECHO} ""
2144
2145	# Prompt for another Auth Method, or break out.
2146	get_confirm_nodef "Do you want to add another Authentication Method?"
2147	if [ $? -eq 0 ]; then
2148	    break;
2149	fi
2150    done
2151
2152    # Check in case user reset string and exited loop.
2153    if [ "$LDAP_SRV_AUTHMETHOD_PAM" = "" ]; then
2154	NEED_SRVAUTH_PAM=0
2155    fi
2156}
2157
2158
2159#
2160# get_srv_authMethod_key(): Get the Service Auth Method for keyserv from user.
2161#
2162#  NOTE: This function is base on get_auth().
2163#
2164get_srv_authMethod_key()
2165{
2166    [ $DEBUG -eq 1 ] && ${ECHO} "In get_srv_authMethod_key()"
2167
2168    _FIRST=1          # Flag for first time.
2169    _MENU_CHOICE=0
2170    _AUTHMETHOD=""    # Tmp method.
2171
2172    while :
2173    do
2174	# Call Menu handler
2175	srvauth_menu_handler
2176
2177	# Add Auth Method to list.
2178        if [ $_FIRST -eq 1 ]; then
2179	    if [ "$_AUTHMETHOD" = "" ]; then
2180		LDAP_SRV_AUTHMETHOD_KEY=""
2181	    else
2182		LDAP_SRV_AUTHMETHOD_KEY="keyserv:${_AUTHMETHOD}"
2183	    fi
2184	    _FIRST=0
2185	else
2186	    LDAP_SRV_AUTHMETHOD_KEY="${LDAP_SRV_AUTHMETHOD_KEY};${_AUTHMETHOD}"
2187	fi
2188
2189	# Display current Authentication Method.
2190	${ECHO} ""
2191	${ECHO} "Current authenticationMethod: ${LDAP_SRV_AUTHMETHOD_KEY}"
2192	${ECHO} ""
2193
2194	# Prompt for another Auth Method, or break out.
2195	get_confirm_nodef "Do you want to add another Authentication Method?"
2196	if [ $? -eq 0 ]; then
2197	    break;
2198	fi
2199    done
2200
2201    # Check in case user reset string and exited loop.
2202    if [ "$LDAP_SRV_AUTHMETHOD_KEY" = "" ]; then
2203	NEED_SRVAUTH_KEY=0
2204    fi
2205}
2206
2207
2208#
2209# get_srv_authMethod_cmd(): Get the Service Auth Method for passwd-cmd from user.
2210#
2211#  NOTE: This function is base on get_auth().
2212#
2213get_srv_authMethod_cmd()
2214{
2215    [ $DEBUG -eq 1 ] && ${ECHO} "In get_srv_authMethod_cmd()"
2216
2217    _FIRST=1          # Flag for first time.
2218    _MENU_CHOICE=0
2219    _AUTHMETHOD=""    # Tmp method.
2220
2221    while :
2222    do
2223	# Call Menu handler
2224	srvauth_menu_handler
2225
2226	# Add Auth Method to list.
2227        if [ $_FIRST -eq 1 ]; then
2228	    if [ "$_AUTHMETHOD" = "" ]; then
2229		LDAP_SRV_AUTHMETHOD_CMD=""
2230	    else
2231		LDAP_SRV_AUTHMETHOD_CMD="passwd-cmd:${_AUTHMETHOD}"
2232	    fi
2233	    _FIRST=0
2234	else
2235	    LDAP_SRV_AUTHMETHOD_CMD="${LDAP_SRV_AUTHMETHOD_CMD};${_AUTHMETHOD}"
2236	fi
2237
2238	# Display current Authentication Method.
2239	${ECHO} ""
2240	${ECHO} "Current authenticationMethod: ${LDAP_SRV_AUTHMETHOD_CMD}"
2241	${ECHO} ""
2242
2243	# Prompt for another Auth Method, or break out.
2244	get_confirm_nodef "Do you want to add another Authentication Method?"
2245	if [ $? -eq 0 ]; then
2246	    break;
2247	fi
2248    done
2249
2250    # Check in case user reset string and exited loop.
2251    if [ "$LDAP_SRV_AUTHMETHOD_CMD" = "" ]; then
2252	NEED_SRVAUTH_CMD=0
2253    fi
2254}
2255
2256
2257#
2258# get_srch_time(): Amount of time to search.
2259#
2260get_srch_time()
2261{
2262    get_negone_num "Client search time limit in seconds (h=help):" "$LDAP_SEARCH_TIME_LIMIT" "srchtime_help"
2263    LDAP_SEARCH_TIME_LIMIT=$NUM
2264}
2265
2266
2267#
2268# get_prof_ttl(): The profile time to live (TTL)
2269#
2270get_prof_ttl()
2271{
2272    get_negone_num "Profile Time To Live in seconds (h=help):" "$LDAP_PROFILE_TTL" "profttl_help"
2273    LDAP_PROFILE_TTL=$NUM
2274}
2275
2276
2277#
2278# get_bind_limit(): Bind time limit
2279#
2280get_bind_limit()
2281{
2282    get_negone_num "Bind time limit in seconds (h=help):" "$LDAP_BIND_LIMIT" "bindlim_help"
2283    LDAP_BIND_LIMIT=$NUM
2284}
2285
2286
2287######################################################################
2288# FUNCTIONS  FOR Service Search Descriptor's START HERE.
2289######################################################################
2290
2291
2292#
2293# add_ssd(): Get SSD's from user and add to file.
2294#
2295add_ssd()
2296{
2297    [ $DEBUG -eq 1 ] && ${ECHO} "In add_ssd()"
2298
2299    # Enter the service id.  Loop til unique.
2300    while :
2301    do
2302	get_ans "Enter the service id:"
2303	_SERV_ID=$ANS
2304
2305	# Grep for name existing.
2306	${GREP} -i "^$ANS:" ${SSD_FILE} > /dev/null 2>&1
2307	if [ $? -eq 1 ]; then
2308	    break
2309	fi
2310
2311	# Name exists, print message, let user decide.
2312	${ECHO} "ERROR: Service id ${ANS} already exists."
2313    done
2314
2315    get_ans "Enter the base:"
2316    _BASE=$ANS
2317
2318    # Get the scope and verify that its one or sub.
2319    while :
2320    do
2321	get_ans "Enter the scope:"
2322	_SCOPE=$ANS
2323	case `${ECHO} ${_SCOPE} | tr '[A-Z]' '[a-z]'` in
2324	    one) break ;;
2325	    sub) break ;;
2326	    *)   ${ECHO} "${_SCOPE} is Not valid - Enter 'one' or 'sub'" ;;
2327	esac
2328    done
2329
2330    # Build SSD to add to file.
2331    _SSD="${_SERV_ID}:${_BASE}?${_SCOPE}"
2332
2333    # Add the SSD to the file.
2334    ${ECHO} "${_SSD}" >> ${SSD_FILE}
2335}
2336
2337
2338#
2339# delete_ssd(): Delete a SSD from the list.
2340#
2341delete_ssd()
2342{
2343    [ $DEBUG -eq 1 ] && ${ECHO} "In delete_ssd()"
2344
2345    # Get service id name from user for SSD to delete.
2346    get_ans_req "Enter service id to delete:"
2347
2348    # Make sure service id exists.
2349    ${GREP} "$ANS" ${SSD_FILE} > /dev/null 2>&1
2350    if [ $? -eq 1 ]; then
2351	${ECHO} "Invalid service id: $ANS not present in list."
2352	return
2353    fi
2354
2355    # Create temporary back SSD file.
2356    cp ${SSD_FILE} ${SSD_FILE}.bak
2357    if [ $? -eq 1 ]; then
2358	${ECHO} "ERROR: could not create file: ${SSD_FILE}.bak"
2359	exit 1
2360    fi
2361
2362    # Use ${GREP} to remove the SSD.  Read from temp file
2363    # and write to the orig file.
2364    ${GREP} -v "$ANS" ${SSD_FILE}.bak > ${SSD_FILE}
2365}
2366
2367
2368#
2369# modify_ssd(): Allow user to modify a SSD.
2370#
2371modify_ssd()
2372{
2373    [ $DEBUG -eq 1 ] && ${ECHO} "In modify_ssd()"
2374
2375    # Prompt user for service id.
2376    get_ans_req "Enter service id to modify:"
2377
2378    # Put into temp _LINE.
2379    _LINE=`${GREP} "^$ANS:" ${SSD_FILE}`
2380    if [ "$_LINE" = "" ]; then
2381	${ECHO} "Invalid service id: $ANS"
2382	return
2383    fi
2384
2385    # Display current filter for user to see.
2386    ${ECHO} ""
2387    ${ECHO} "Current SSD: $_LINE"
2388    ${ECHO} ""
2389
2390    # Get the defaults.
2391    _CURR_BASE=`${ECHO} $_LINE | cut -d: -f2 | cut -d'?' -f 1`
2392    _CURR_SCOPE=`${ECHO} $_LINE | cut -d: -f2 | cut -d'?' -f 2`
2393
2394    # Create temporary back SSD file.
2395    cp ${SSD_FILE} ${SSD_FILE}.bak
2396    if [ $? -eq 1 ]; then
2397	${ECHO} "ERROR: could not create file: ${SSD_FILE}.bak"
2398	cleanup
2399	exit 1
2400    fi
2401
2402    # Removed the old line.
2403    ${GREP} -v "^$ANS:" ${SSD_FILE}.bak > ${SSD_FILE} 2>&1
2404
2405    # New Entry
2406    _SERV_ID=$ANS
2407    get_ans_req "Enter the base:" "$_CURR_BASE"
2408    _BASE=$ANS
2409    get_ans_req "Enter the scope:" "$_CURR_SCOPE"
2410    _SCOPE=$ANS
2411
2412    # Build the new SSD.
2413    _SSD="${_SERV_ID}:${_BASE}?${_SCOPE}"
2414
2415    # Add the SSD to the file.
2416    ${ECHO} "${_SSD}" >> ${SSD_FILE}
2417}
2418
2419
2420#
2421# display_ssd(): Display the current SSD list.
2422#
2423display_ssd()
2424{
2425    [ $DEBUG -eq 1 ] && ${ECHO} "In display_ssd()"
2426
2427    ${ECHO} ""
2428    ${ECHO} "Current Service Search Descriptors:"
2429    ${ECHO} "=================================="
2430    cat ${SSD_FILE}
2431    ${ECHO} ""
2432    ${ECHO} "Hit return to continue."
2433    read __A
2434}
2435
2436
2437#
2438# prompt_ssd(): Get SSD's from user.
2439#
2440prompt_ssd()
2441{
2442    [ $DEBUG -eq 1 ] && ${ECHO} "In prompt_ssd()"
2443    # See if user wants SSD's?
2444    get_confirm "Do you wish to setup Service Search Descriptors (y/n/h)?" "n" "ssd_help"
2445    [ "$?" -eq 0 ] && return
2446
2447    # Display menu for SSD choices.
2448    while :
2449    do
2450	display_msg prompt_ssd_menu
2451	get_ans "Enter menu choice:" "Quit"
2452	case "$ANS" in
2453	    [Aa] | add) add_ssd ;;
2454	    [Dd] | delete) delete_ssd ;;
2455	    [Mm] | modify) modify_ssd ;;
2456	    [Pp] | print | display) display_ssd ;;
2457	    [Xx] | reset | clear) reset_ssd_file ;;
2458	    [Hh] | Help | help)	display_msg ssd_menu_help
2459				${ECHO} " Press return to continue."
2460				read __A ;;
2461	    [Qq] | Quit | quit)	return ;;
2462	    *)    ${ECHO} "Invalid choice: $ANS please re-enter from menu." ;;
2463	esac
2464    done
2465}
2466
2467
2468#
2469# reset_ssd_file(): Blank out current SSD file.
2470#
2471reset_ssd_file()
2472{
2473    [ $DEBUG -eq 1 ] && ${ECHO} "In reset_ssd_file()"
2474
2475    rm -f ${SSD_FILE}
2476    touch ${SSD_FILE}
2477}
2478
2479
2480#
2481# create_ssd_file(): Create a temporary file for SSD's.
2482#
2483create_ssd_file()
2484{
2485    [ $DEBUG -eq 1 ] && ${ECHO} "In create_ssd_file()"
2486
2487    # Build a list of SSD's and store in temp file.
2488    ${GREP} "LDAP_SERV_SRCH_DES=" ${INPUT_FILE} | \
2489	sed 's/LDAP_SERV_SRCH_DES=//' \
2490	> ${SSD_FILE}
2491}
2492
2493
2494#
2495# ssd_2_config(): Append the SSD file to the output file.
2496#
2497ssd_2_config()
2498{
2499    [ $DEBUG -eq 1 ] && ${ECHO} "In ssd_2_config()"
2500
2501    # Convert to config file format using sed.
2502    sed -e "s/^/LDAP_SERV_SRCH_DES=/" ${SSD_FILE} >> ${OUTPUT_FILE}
2503}
2504
2505
2506#
2507# ssd_2_profile(): Add SSD's to the GEN_CMD string.
2508#
2509ssd_2_profile()
2510{
2511    [ $DEBUG -eq 1 ] && ${ECHO} "In ssd_2_profile()"
2512
2513    GEN_TMPFILE=${TMPDIR}/ssd_tmpfile
2514    touch ${GEN_TMPFILE}
2515
2516    # Add and convert each SSD to string.
2517    while read SSD_LINE
2518    do
2519	${ECHO} " -a \"serviceSearchDescriptor=${SSD_LINE}\"\c" >> ${GEN_TMPFILE}
2520    done <${SSD_FILE}
2521
2522    # Add SSD's to GEN_CMD.
2523    GEN_CMD="${GEN_CMD} `cat ${GEN_TMPFILE}`"
2524}
2525
2526#
2527# get_adminDN(): Get the admin DN.
2528#
2529get_adminDN()
2530{
2531    LDAP_ADMINDN="cn=admin,ou=profile,${LDAP_BASEDN}"  # default
2532    get_ans "Enter DN for the administrator:" "$LDAP_ADMINDN"
2533    LDAP_ADMINDN=$ANS
2534    [ $DEBUG -eq 1 ] && ${ECHO} "LDAP_ADMINDN = $LDAP_ADMINDN"
2535}
2536
2537#
2538# get_admin_pw(): Get the admin passwd.
2539#
2540get_admin_pw()
2541{
2542    get_passwd "Enter passwd for the administrator:"
2543    LDAP_ADMIN_CRED=$ANS
2544    [ $DEBUG -eq 1 ] && ${ECHO} "LDAP_ADMIN_CRED = $LDAP_ADMIN_CRED"
2545}
2546
2547#
2548# add_admin(): Add an admin entry for nameservice for updating shadow data.
2549#
2550add_admin()
2551{
2552    [ $DEBUG -eq 1 ] && ${ECHO} "In add_admin()"
2553
2554    # Check if the admin user already exists.
2555    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_ADMINDN}\" -s base \"objectclass=*\" ${VERB}"
2556    if [ $? -eq 0 ]; then
2557	MSG="Administrator ${LDAP_ADMINDN} already exists."
2558	if [ $EXISTING_PROFILE -eq 1 ]; then
2559	    ${ECHO} "  NOT ADDED: $MSG"
2560	else
2561	    ${ECHO} "  ${STEP}. $MSG"
2562	    STEP=`expr $STEP + 1`
2563	fi
2564	return 0
2565    fi
2566
2567    # Get cn and sn names from LDAP_ADMINDN.
2568    cn_tmp=`${ECHO} ${LDAP_ADMINDN} | cut -f1 -d, | cut -f2 -d=`
2569
2570    # Create the tmp file to add.
2571    ( cat <<EOF
2572dn: ${LDAP_ADMINDN}
2573cn: ${cn_tmp}
2574sn: ${cn_tmp}
2575objectclass: top
2576objectclass: person
2577userpassword: ${LDAP_ADMIN_CRED}
2578EOF
2579) > ${TMPDIR}/admin
2580
2581    # Add the entry.
2582    ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/admin ${VERB}"
2583    if [ $? -ne 0 ]; then
2584	${ECHO} "  ERROR: Adding administrator identity failed!"
2585	cleanup
2586	exit 1
2587    fi
2588
2589    ${RM} -f ${TMPDIR}/admin
2590
2591    # Display message that the administrator identity is added.
2592    MSG="Administrator identity ${LDAP_ADMINDN}"
2593    if [ $EXISTING_PROFILE -eq 1 ]; then
2594	${ECHO} "  ADDED: $MSG."
2595    else
2596	${ECHO} "  ${STEP}. $MSG added."
2597	STEP=`expr $STEP + 1`
2598    fi
2599}
2600
2601#
2602# allow_admin_read_write_shadow(): Give Admin read/write permission
2603# to shadow data.
2604#
2605allow_admin_read_write_shadow()
2606{
2607    [ $DEBUG -eq 1 ] && ${ECHO} "In allow_admin_read_write_shadow()"
2608
2609    # Set ACI Name
2610    ADMIN_ACI_NAME="LDAP_Naming_Services_admin_shadow_write"
2611
2612    # Search for ACI_NAME
2613    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" \
2614    -s base objectclass=* aci > ${TMPDIR}/chk_adminwrite_aci 2>&1"
2615
2616    # if an ACI with ${ADMIN_ACI_NAME} and "write,compare,read,search"
2617    # and ${LDAP_ADMINDN} already exists, we are done
2618    ${EGREP} ".*${ADMIN_ACI_NAME}.*write,compare,read,search.*${LDAP_ADMINDN}.*" \
2619    	${TMPDIR}/chk_adminwrite_aci 2>&1 > /dev/null
2620    if [ $? -eq 0 ]; then
2621	MSG="Admin ACI ${ADMIN_ACI_NAME} already exists for ${LDAP_BASEDN}."
2622	if [ $EXISTING_PROFILE -eq 1 ]; then
2623	    ${ECHO} "  NOT SET: $MSG"
2624	else
2625	    ${ECHO} "  ${STEP}. $MSG"
2626	    STEP=`expr $STEP + 1`
2627	fi
2628	return 0
2629    fi
2630
2631    # If an ACI with ${ADMIN_ACI_NAME} and "(write)" and ${LDAP_ADMINDN}
2632    # already exists, delete it first.
2633    find_and_delete_ACI ".*${ADMIN_ACI_NAME}.*(write).*${LDAP_ADMINDN}.*" \
2634	${TMPDIR}/chk_adminwrite_aci ${ADMIN_ACI_NAME}
2635
2636    # Create the tmp file to add.
2637    ( cat <<EOF
2638dn: ${LDAP_BASEDN}
2639changetype: modify
2640add: aci
2641aci: (target="ldap:///${LDAP_BASEDN}")(targetattr="shadowLastChange
2642 ||shadowMin||shadowMax||shadowWarning||shadowInactive||shadowExpire
2643 ||shadowFlag||userPassword||loginShell||homeDirectory||gecos")
2644  (version 3.0; acl ${ADMIN_ACI_NAME}; allow (write,compare,read,search)
2645  userdn = "ldap:///${LDAP_ADMINDN}";)
2646EOF
2647) > ${TMPDIR}/admin_write
2648
2649    # Add the entry.
2650    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/admin_write ${VERB}"
2651    if [ $? -ne 0 ]; then
2652	${ECHO} "  ERROR: Allow ${LDAP_ADMINDN} read/write access to shadow data failed!"
2653	cleanup
2654	exit 1
2655    fi
2656
2657    ${RM} -f ${TMPDIR}/admin_write
2658    # Display message that the administrator ACL is set.
2659    MSG="Give ${LDAP_ADMINDN} read/write access to shadow data."
2660    if [ $EXISTING_PROFILE -eq 1 ]; then
2661	${ECHO} "  ACI SET: $MSG"
2662    else
2663	${ECHO} "  ${STEP}. $MSG"
2664	STEP=`expr $STEP + 1`
2665    fi
2666}
2667
2668#
2669# allow_host_read_write_shadow(): Give host principal read/write permission
2670# for shadow data.
2671#
2672allow_host_read_write_shadow()
2673{
2674    [ $DEBUG -eq 1 ] && ${ECHO} "In allow_host_read_write_shadow()"
2675
2676    # Set ACI Name
2677    HOST_ACI_NAME="LDAP_Naming_Services_host_shadow_write"
2678
2679    # Search for ACI_NAME
2680    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_hostwrite_aci 2>&1"
2681    ${GREP} "${HOST_ACI_NAME}" ${TMPDIR}/chk_hostwrite_aci > /dev/null 2>&1
2682    if [ $? -eq 0 ]; then
2683	MSG="Host ACI ${HOST_ACI_NAME} already exists for ${LDAP_BASEDN}."
2684	if [ $EXISTING_PROFILE -eq 1 ]; then
2685	    ${ECHO} "  NOT ADDED: $MSG"
2686	else
2687	    ${ECHO} "  ${STEP}. $MSG"
2688	    STEP=`expr $STEP + 1`
2689	fi
2690	return 0
2691    fi
2692
2693    # Create the tmp file to add.
2694    ( cat <<EOF
2695dn: ${LDAP_BASEDN}
2696changetype: modify
2697add: aci
2698aci: (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}";)
2699EOF
2700) > ${TMPDIR}/host_read_write
2701
2702    # Add the entry.
2703    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/host_read_write ${VERB}"
2704    if [ $? -ne 0 ]; then
2705	${ECHO} "  ERROR: Allow Host Principal to write shadow data failed!"
2706	cleanup
2707	exit 1
2708    fi
2709
2710    ${RM} -f ${TMPDIR}/host_read_write
2711    MSG="Give host principal read/write permission for shadow."
2712    if [ $EXISTING_PROFILE -eq 1 ]; then
2713	${ECHO} "  ACI SET: $MSG"
2714    else
2715	${ECHO} "  ${STEP}. $MSG"
2716	STEP=`expr $STEP + 1`
2717    fi
2718}
2719
2720#
2721# Set up shadow update
2722#
2723setup_shadow_update() {
2724    [ $DEBUG -eq 1 ] && ${ECHO} "In setup_shadow_update()"
2725
2726    # get content of the profile
2727    PROFILE_OUT=${TMPDIR}/prof_tmpfile
2728    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${LDAP_PROFILE_NAME},ou=profile,${LDAP_BASEDN}\" -s base \"objectclass=*\" > $PROFILE_OUT 2>&1"
2729    ${GREP} -i cn $PROFILE_OUT >/dev/null 2>&1
2730    if [ $? -ne 0 ]; then
2731	[ $DEBUG -eq 1 ] && ${ECHO} "Profile ${LDAP_PROFILE_NAME} does not exist"
2732	${RM} ${PROFILE_OUT}
2733	return
2734    fi
2735
2736    # Search to see if authenticationMethod has 'GSSAPI' and
2737    # credentialLevel has 'self'. If so, ask to use the
2738    # host principal for shadow update
2739    if [ $GSSAPI_AUTH_MAY_BE_USED -eq 1 ]; then
2740	if ${GREP} authenticationMethod $PROFILE_OUT | ${GREP} GSSAPI >/dev/null 2>&1
2741	then
2742	    if ${GREP} credentialLevel $PROFILE_OUT | ${GREP} self >/dev/null 2>&1
2743	    then
2744		NEED_HOSTACL=1
2745	    fi
2746	fi
2747	${RM} ${PROFILE_OUT}
2748	[ $DEBUG -eq 1 ] && ${ECHO} "NEED_HOSTACL = $NEED_HOSTACL"
2749
2750	if [ $NEED_HOSTACL -eq 1 ]; then
2751	    MSG="Use host principal for shadow data update (y/n/h)?"
2752	    get_confirm "$MSG" "y" "use_host_principal_help"
2753	    if [ $? -eq 1 ]; then
2754		delete_proxy_read_pw
2755		allow_host_read_write_shadow
2756		deny_non_host_shadow_access
2757	        ${ECHO} ""
2758		${ECHO} "  Shadow update has been enabled."
2759	    else
2760	        ${ECHO} ""
2761    		${ECHO} "  Shadow update may not work."
2762	    fi
2763	    return
2764	fi
2765    fi
2766
2767    MSG="Add the administrator identity (y/n/h)?"
2768    get_confirm "$MSG" "y" "add_admin_cred_help"
2769    if [ $? -eq 1 ]; then
2770	get_adminDN
2771	get_admin_pw
2772	add_admin
2773	delete_proxy_read_pw
2774	allow_admin_read_write_shadow
2775	deny_non_admin_shadow_access
2776        ${ECHO} ""
2777	${ECHO} "  Shadow update has been enabled."
2778	return
2779    fi
2780
2781    ${ECHO} "  No administrator identity specified, shadow update may not work."
2782}
2783
2784
2785#
2786# prompt_config_info(): This function prompts the user for the config
2787# info that is not specified in the input file.
2788#
2789prompt_config_info()
2790{
2791    [ $DEBUG -eq 1 ] && ${ECHO} "In prompt_config_info()"
2792
2793    # Prompt for iDS server name.
2794    get_ids_server
2795
2796    # Prompt for iDS port number.
2797    get_ids_port
2798
2799    # Check iDS version for compatibility.
2800    chk_ids_version
2801
2802    # Check if the server supports the VLV.
2803    chk_vlv_indexes
2804
2805    # Get the Directory manager DN and passwd.
2806    get_dirmgr_dn
2807    get_dirmgr_pw
2808
2809    #
2810    # LDAP CLIENT PROFILE SPECIFIC INFORMATION.
2811    #   (i.e. The fields that show up in the profile.)
2812    #
2813    get_domain "domain_help"
2814
2815    get_basedn
2816
2817    gssapi_setup
2818
2819    get_profile_name
2820
2821    if [ "$LDAP_ENABLE_SHADOW_UPDATE" = "TRUE" ];then
2822	setup_shadow_update
2823	cleanup
2824	exit 0
2825    fi
2826
2827    get_srv_list
2828    get_pref_srv
2829    get_search_scope
2830
2831    # If cred is "anonymous", make auth == "none"
2832    get_cred_level
2833    if [ "$LDAP_CRED_LEVEL" != "anonymous" ]; then
2834	get_auth
2835    fi
2836
2837    get_followref
2838
2839    # Query user about timelimt.
2840    get_confirm "Do you want to modify the server timelimit value (y/n/h)?" "n" "tlim_help"
2841    NEED_TIME=$?
2842    [ $NEED_TIME -eq 1 ] && get_timelimit
2843
2844    # Query user about sizelimit.
2845    get_confirm "Do you want to modify the server sizelimit value (y/n/h)?" "n" "slim_help"
2846    NEED_SIZE=$?
2847    [ $NEED_SIZE -eq 1 ] && get_sizelimit
2848
2849    # Does the user want to store passwords in crypt format?
2850    get_want_crypt
2851
2852    # Prompt for any Service Authentication Methods?
2853    get_confirm "Do you want to setup a Service Authentication Methods (y/n/h)?" "n" "srvauth_help"
2854    if [ $? -eq 1 ]; then
2855	# Does the user want to set Service Authentication Method for pam_ldap?
2856	get_confirm "Do you want to setup a Service Auth. Method for \"pam_ldap\" (y/n/h)?" "n" "pam_ldap_help"
2857	NEED_SRVAUTH_PAM=$?
2858	[ $NEED_SRVAUTH_PAM -eq 1 ] && get_srv_authMethod_pam
2859
2860	# Does the user want to set Service Authentication Method for keyserv?
2861	get_confirm "Do you want to setup a Service Auth. Method for \"keyserv\" (y/n/h)?" "n" "keyserv_help"
2862	NEED_SRVAUTH_KEY=$?
2863	[ $NEED_SRVAUTH_KEY -eq 1 ] && get_srv_authMethod_key
2864
2865	# Does the user want to set Service Authentication Method for passwd-cmd?
2866	get_confirm "Do you want to setup a Service Auth. Method for \"passwd-cmd\" (y/n/h)?" "n" "passwd-cmd_help"
2867	NEED_SRVAUTH_CMD=$?
2868	[ $NEED_SRVAUTH_CMD -eq 1 ] && get_srv_authMethod_cmd
2869    fi
2870
2871
2872    # Get Timeouts
2873    get_srch_time
2874    get_prof_ttl
2875    get_bind_limit
2876
2877    # Ask whether to enable shadow update
2878    get_want_shadow_update
2879
2880    # Reset the sdd_file and prompt user for SSD.  Will use menus
2881    # to build an SSD File.
2882    reset_ssd_file
2883    prompt_ssd
2884
2885    # Display FULL debugging info.
2886    disp_full_debug
2887
2888    # Extra blank line to separate prompt lines from steps.
2889    ${ECHO} " "
2890}
2891
2892
2893######################################################################
2894# FUNCTIONS  FOR display_summary() START HERE.
2895######################################################################
2896
2897
2898#
2899# get_proxyagent(): Get the proxyagent DN.
2900#
2901get_proxyagent()
2902{
2903    LDAP_PROXYAGENT="cn=proxyagent,ou=profile,${LDAP_BASEDN}"  # default
2904    get_ans "Enter DN for proxy agent:" "$LDAP_PROXYAGENT"
2905    LDAP_PROXYAGENT=$ANS
2906}
2907
2908
2909#
2910# get_proxy_pw(): Get the proxyagent passwd.
2911#
2912get_proxy_pw()
2913{
2914    get_passwd "Enter passwd for proxyagent:"
2915    LDAP_PROXYAGENT_CRED=$ANS
2916}
2917
2918#
2919# display_summary(): Display a summary of values entered and let the
2920#                    user modify values at will.
2921#
2922display_summary()
2923{
2924    [ $DEBUG -eq 1 ] && ${ECHO} "In display_summary()"
2925
2926    # Create lookup table for function names.  First entry is dummy for
2927    # shift.
2928    TBL1="dummy"
2929    TBL2="get_domain get_basedn get_profile_name"
2930    TBL3="get_srv_list get_pref_srv get_search_scope get_cred_level"
2931    TBL4="get_auth get_followref"
2932    TBL5="get_timelimit get_sizelimit get_want_crypt"
2933    TBL6="get_srv_authMethod_pam get_srv_authMethod_key get_srv_authMethod_cmd"
2934    TBL7="get_srch_time get_prof_ttl get_bind_limit"
2935    TBL8="get_want_shadow_update"
2936    TBL9="prompt_ssd"
2937    FUNC_TBL="$TBL1 $TBL2 $TBL3 $TBL4 $TBL5 $TBL6 $TBL7 $TBL8 $TBL9"
2938
2939    # Since menu prompt string is long, set here.
2940    _MENU_PROMPT="Enter config value to change: (1-20 0=commit changes)"
2941
2942    # Infinite loop.  Test for 0, and break in loop.
2943    while :
2944    do
2945	# Display menu and get value in range.
2946	display_msg summary_menu
2947	get_menu_choice "${_MENU_PROMPT}" "0" "20" "0"
2948	_CH=$MN_CH
2949
2950	# Make sure where not exiting.
2951	if [ $_CH -eq 0 ]; then
2952	    break       # Break out of loop if 0 selected.
2953	fi
2954
2955	# Call appropriate function from function table.
2956	set $FUNC_TBL
2957	shift $_CH
2958	$1          # Call the appropriate function.
2959    done
2960
2961    # If cred level is still see if user wants a change?
2962    if ${ECHO} "$LDAP_CRED_LEVEL" | ${GREP} "proxy" > /dev/null 2>&1
2963    then
2964	if [ "$LDAP_AUTHMETHOD" != "none" ]; then
2965	    NEED_PROXY=1    # I assume integer test is faster?
2966	    get_proxyagent
2967	    get_proxy_pw
2968	else
2969	    ${ECHO} "WARNING: Since Authentication method is 'none'."
2970	    ${ECHO} "         Credential level will be set to 'anonymous'."
2971	    LDAP_CRED_LEVEL="anonymous"
2972	fi
2973    fi
2974
2975    # If shadow update is enabled, set up administrator credential
2976    if [ "$LDAP_ENABLE_SHADOW_UPDATE" = "TRUE" ]; then
2977	NEED_ADMIN=1
2978	if ${ECHO} "$LDAP_CRED_LEVEL" | ${GREP} "self" > /dev/null 2>&1; then
2979	    if ${ECHO} "$LDAP_AUTHMETHOD" | ${GREP} "GSSAPI" > /dev/null 2>&1; then
2980		NEED_HOSTACL=1
2981		NEED_ADMIN=0
2982	    fi
2983	fi
2984        [ $DEBUG -eq 1 ] && ${ECHO} "NEED_HOSTACL = $NEED_HOSTACL"
2985        [ $DEBUG -eq 1 ] && ${ECHO} "NEED_ADMIN   = $NEED_ADMIN"
2986	if [ $NEED_ADMIN -eq 1 ]; then
2987	    get_adminDN
2988	    get_admin_pw
2989	fi
2990    fi
2991
2992    # Display FULL debugging info.
2993    disp_full_debug
2994
2995    # Final confirmation message. (ARE YOU SURE!)
2996    ${ECHO} " "
2997    get_confirm_nodef "WARNING: About to start committing changes. (y=continue, n=EXIT)"
2998    if [ $? -eq 0 ]; then
2999	${ECHO} "Terminating setup without making changes at users request."
3000	cleanup
3001	exit 1
3002    fi
3003
3004    # Print newline
3005    ${ECHO} " "
3006}
3007
3008
3009#
3010# create_config_file(): Write config data to config file specified.
3011#
3012create_config_file()
3013{
3014    [ $DEBUG -eq 1 ] && ${ECHO} "In create_config_file()"
3015
3016    # If output file exists, delete it.
3017    [ -f $OUTPUT_FILE ] && rm $OUTPUT_FILE
3018
3019    # Create output file.
3020    cat > $OUTPUT_FILE <<EOF
3021#!/bin/sh
3022# $OUTPUT_FILE - This file contains configuration information for
3023#                Native LDAP.  Use the idsconfig tool to load it.
3024#
3025# WARNING: This file was generated by idsconfig, and is intended to
3026#          be loaded by idsconfig as is.  DO NOT EDIT THIS FILE!
3027#
3028IDS_SERVER="$IDS_SERVER"
3029IDS_PORT=$IDS_PORT
3030IDS_TIMELIMIT=$IDS_TIMELIMIT
3031IDS_SIZELIMIT=$IDS_SIZELIMIT
3032LDAP_ROOTDN="$LDAP_ROOTDN"
3033LDAP_ROOTPWD=$LDAP_ROOTPWD
3034LDAP_DOMAIN="$LDAP_DOMAIN"
3035LDAP_SUFFIX="$LDAP_SUFFIX"
3036LDAP_KRB_REALM="$LDAP_KRB_REALM"
3037LDAP_GSSAPI_PROFILE="$LDAP_GSSAPI_PROFILE"
3038
3039# Internal program variables that need to be set.
3040NEED_PROXY=$NEED_PROXY
3041NEED_TIME=$NEED_TIME
3042NEED_SIZE=$NEED_SIZE
3043NEED_CRYPT=$NEED_CRYPT
3044NEED_ADMIN=$NEED_ADMIN
3045NEED_HOSTACL=$NEED_HOSTACL
3046EXISTING_PROFILE=$EXISTING_PROFILE
3047
3048# LDAP PROFILE related defaults
3049LDAP_PROFILE_NAME="$LDAP_PROFILE_NAME"
3050DEL_OLD_PROFILE=1
3051LDAP_BASEDN="$LDAP_BASEDN"
3052LDAP_SERVER_LIST="$LDAP_SERVER_LIST"
3053LDAP_AUTHMETHOD="$LDAP_AUTHMETHOD"
3054LDAP_FOLLOWREF=$LDAP_FOLLOWREF
3055LDAP_SEARCH_SCOPE="$LDAP_SEARCH_SCOPE"
3056NEED_SRVAUTH_PAM=$NEED_SRVAUTH_PAM
3057NEED_SRVAUTH_KEY=$NEED_SRVAUTH_KEY
3058NEED_SRVAUTH_CMD=$NEED_SRVAUTH_CMD
3059LDAP_SRV_AUTHMETHOD_PAM="$LDAP_SRV_AUTHMETHOD_PAM"
3060LDAP_SRV_AUTHMETHOD_KEY="$LDAP_SRV_AUTHMETHOD_KEY"
3061LDAP_SRV_AUTHMETHOD_CMD="$LDAP_SRV_AUTHMETHOD_CMD"
3062LDAP_SEARCH_TIME_LIMIT=$LDAP_SEARCH_TIME_LIMIT
3063LDAP_PREF_SRVLIST="$LDAP_PREF_SRVLIST"
3064LDAP_PROFILE_TTL=$LDAP_PROFILE_TTL
3065LDAP_CRED_LEVEL="$LDAP_CRED_LEVEL"
3066LDAP_BIND_LIMIT=$LDAP_BIND_LIMIT
3067
3068# Proxy Agent
3069LDAP_PROXYAGENT="$LDAP_PROXYAGENT"
3070LDAP_PROXYAGENT_CRED=$LDAP_PROXYAGENT_CRED
3071
3072# enableShadowUpdate flag and Administrator credential
3073LDAP_ENABLE_SHADOW_UPDATE=$LDAP_ENABLE_SHADOW_UPDATE
3074LDAP_ADMINDN="$LDAP_ADMINDN"
3075LDAP_ADMIN_CRED=$LDAP_ADMIN_CRED
3076
3077# Export all the variables (just in case)
3078export IDS_HOME IDS_PORT LDAP_ROOTDN LDAP_ROOTPWD LDAP_SERVER_LIST LDAP_BASEDN
3079export LDAP_DOMAIN LDAP_SUFFIX LDAP_PROXYAGENT LDAP_PROXYAGENT_CRED
3080export NEED_PROXY
3081export LDAP_ENABLE_SHADOW_UPDATE LDAP_ADMINDN LDAP_ADMIN_CRED
3082export NEED_ADMIN NEED_HOSTACL EXISTING_PROFILE
3083export LDAP_PROFILE_NAME LDAP_BASEDN LDAP_SERVER_LIST 
3084export LDAP_AUTHMETHOD LDAP_FOLLOWREF LDAP_SEARCH_SCOPE LDAP_SEARCH_TIME_LIMIT
3085export LDAP_PREF_SRVLIST LDAP_PROFILE_TTL LDAP_CRED_LEVEL LDAP_BIND_LIMIT
3086export NEED_SRVAUTH_PAM NEED_SRVAUTH_KEY NEED_SRVAUTH_CMD
3087export LDAP_SRV_AUTHMETHOD_PAM LDAP_SRV_AUTHMETHOD_KEY LDAP_SRV_AUTHMETHOD_CMD
3088export LDAP_SERV_SRCH_DES SSD_FILE LDAP_KRB_REALM LDAP_GSSAPI_PROFILE
3089
3090# Service Search Descriptors start here if present:
3091EOF
3092    # Add service search descriptors.
3093    ssd_2_config "${OUTPUT_FILE}"
3094
3095    # Add LDAP suffix preferences
3096    print_suffix_config >> "${OUTPUT_FILE}"
3097
3098    # Add the end of FILE tag.
3099    ${ECHO} "" >> ${OUTPUT_FILE}
3100    ${ECHO} "# End of $OUTPUT_FILE" >> ${OUTPUT_FILE}
3101}
3102
3103
3104#
3105# chk_vlv_indexes(): Do ldapsearch to see if server supports VLV.
3106#
3107chk_vlv_indexes()
3108{
3109    # Do ldapsearch to see if server supports VLV.
3110    ${LDAPSEARCH} ${SERVER_ARGS} -b "" -s base "objectclass=*" > ${TMPDIR}/checkVLV 2>&1
3111    eval "${GREP} 2.16.840.1.113730.3.4.9 ${TMPDIR}/checkVLV ${VERB}"
3112    if [ $? -ne 0 ]; then
3113	${ECHO} "ERROR: VLV is not supported on LDAP server!"
3114	cleanup
3115	exit 1
3116    fi
3117    [ $DEBUG -eq 1 ] && ${ECHO} "  VLV controls found on LDAP server."
3118}
3119
3120#
3121# get_backend(): this function gets the relevant backend
3122#                (database) for LDAP_BASED.
3123#                Description: set IDS_DATABASE; exit on failure.
3124#                Prerequisite: LDAP_BASEDN and LDAP_SUFFIX are
3125#                valid.
3126#
3127#                backend is retrieved from suffixes and subsuffixes
3128#                defined under "cn=mapping tree,cn=config". The
3129#                nsslapd-state attribute of these suffixes entries
3130#                is filled with either Backend, Disabled or referrals
3131#                related values. We only want those that have a true
3132#                backend database to select the relevant backend.
3133#
3134get_backend()
3135{
3136    [ $DEBUG -eq 1 ] && ${ECHO} "In get_backend()"
3137
3138    cur_suffix=${LDAP_BASEDN}
3139    prev_suffix=
3140    IDS_DATABASE=
3141    while [ "${cur_suffix}" != "${prev_suffix}" ]
3142    do
3143	[ $DEBUG -eq 1 ] && ${ECHO} "testing LDAP suffix: ${cur_suffix}"
3144	eval "${LDAPSEARCH} ${LDAP_ARGS} " \
3145		"-b \"cn=\\\"${cur_suffix}\\\",cn=mapping tree,cn=config\" " \
3146		"-s base nsslapd-state=Backend nsslapd-backend 2>&1 " \
3147		"| ${GREP} 'nsslapd-backend=' " \
3148		"> ${TMPDIR}/ids_database_name 2>&1"
3149	NUM_DBS=`wc -l ${TMPDIR}/ids_database_name | awk '{print $1}'`
3150	case ${NUM_DBS} in
3151	0) # not a suffix, or suffix not activated; try next
3152	    prev_suffix=${cur_suffix}
3153	    cur_suffix=`${ECHO} ${cur_suffix} | cut -f2- -d','`
3154	    ;;
3155	1) # suffix found; get database name
3156	    IDS_DATABASE=`cat ${TMPDIR}/ids_database_name | cut -d= -f2`
3157	    ;;
3158	*) # can not handle more than one database per suffix
3159	    ${ECHO} "ERROR: More than one database is configured "
3160	    ${ECHO} "       for $LDAP_SUFFIX!"
3161	    ${ECHO} "       $PROG can not configure suffixes where "
3162	    ${ECHO} "       more than one database is used for one suffix."
3163	    cleanup
3164	    exit 1
3165	    ;;
3166	esac
3167	if [ -n "${IDS_DATABASE}" ]; then
3168	    break
3169	fi
3170    done
3171
3172    if [ -z "${IDS_DATABASE}" ]; then
3173	# should not happen, since LDAP_BASEDN is supposed to be valid
3174	${ECHO} "Could not find a valid backend for ${LDAP_BASEDN}."
3175	${ECHO} "Exiting."
3176	cleanup
3177	exit 1
3178    fi
3179
3180    [ $DEBUG -eq 1 ] && ${ECHO} "IDS_DATABASE: ${IDS_DATABASE}"
3181}
3182
3183#
3184# validate_suffix(): This function validates ${LDAP_SUFFIX}
3185#                  THIS FUNCTION IS FOR THE LOAD CONFIG FILE OPTION.
3186#
3187validate_suffix()
3188{
3189    [ $DEBUG -eq 1 ] && ${ECHO} "In validate_suffix()"
3190
3191    # Check LDAP_SUFFIX is not null
3192    if [ -z "${LDAP_SUFFIX}" ]; then
3193	${ECHO} "Invalid suffix (null suffix)"
3194	cleanup
3195	exit 1
3196    fi
3197
3198    # Check LDAP_SUFFIX and LDAP_BASEDN are consistent
3199    # Convert to lower case for basename.
3200    format_string "${LDAP_BASEDN}"
3201    LOWER_BASEDN="${FMT_STR}"
3202    format_string "${LDAP_SUFFIX}"
3203    LOWER_SUFFIX="${FMT_STR}"
3204
3205    [ $DEBUG -eq 1 ] && ${ECHO} "LOWER_BASEDN: ${LOWER_BASEDN}"
3206    [ $DEBUG -eq 1 ] && ${ECHO} "LOWER_SUFFIX: ${LOWER_SUFFIX}"
3207
3208    if [ "${LOWER_BASEDN}" != "${LOWER_SUFFIX}" ]; then
3209    	sub_basedn=`basename "${LOWER_BASEDN}" "${LOWER_SUFFIX}"`
3210    	if [ "$sub_basedn" = "${LOWER_BASEDN}" ]; then
3211	    ${ECHO} "Invalid suffix ${LOWER_SUFFIX}"
3212	    ${ECHO} "for Base DN ${LOWER_BASEDN}"
3213	    cleanup
3214	    exit 1
3215	fi
3216    fi
3217
3218    # Check LDAP_SUFFIX does exist
3219    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_SUFFIX}\" -s base \"objectclass=*\" > ${TMPDIR}/checkSuffix 2>&1" && return 0
3220
3221    # Well, suffix does not exist, try to prepare create it ...
3222    NEED_CREATE_SUFFIX=1
3223    prep_create_sfx_entry ||
3224    {
3225	cleanup
3226	exit 1
3227    }
3228    [ -n "${NEED_CREATE_BACKEND}" ] &&
3229    {
3230	# try to use id attr value of the suffix as a database name
3231	IDS_DATABASE=${_VAL}
3232	prep_create_sfx_backend
3233	case $? in
3234	1)	# cann't use the name we want, so we can either exit or use
3235		# some another available name - doing the last ...
3236		IDS_DATABASE=${IDS_DATABASE_AVAIL}
3237		;;
3238	2)	# unable to determine database name
3239		cleanup
3240		exit 1
3241		;;
3242	esac
3243    }
3244
3245    [ $DEBUG -eq 1 ] && ${ECHO} "Suffix $LDAP_SUFFIX, Database $IDS_DATABASE"
3246}
3247
3248#
3249# validate_info(): This function validates the basic info collected
3250#                  So that some problems are caught right away.
3251#                  THIS FUNCTION IS FOR THE LOAD CONFIG FILE OPTION.
3252#
3253validate_info()
3254{
3255    [ $DEBUG -eq 1 ] && ${ECHO} "In validate_info()"
3256
3257    # Set SERVER_ARGS, AUTH_ARGS, and LDAP_ARGS for the config file.
3258    SERVER_ARGS="-h ${IDS_SERVER} -p ${IDS_PORT}"
3259    AUTH_ARGS="-D \"${LDAP_ROOTDN}\" -j ${LDAP_ROOTPWF}"
3260    LDAP_ARGS="${SERVER_ARGS} ${AUTH_ARGS}"
3261    export SERVER_ARGS
3262
3263    # Check the Root DN and Root DN passwd.
3264    # Use eval instead of $EVAL because not part of setup. (validate)
3265    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"\" -s base \"objectclass=*\" > ${TMPDIR}/checkDN 2>&1"
3266    if [ $? -ne 0 ]; then
3267	eval "${GREP} credential ${TMPDIR}/checkDN ${VERB}"
3268	if [ $? -eq 0 ]; then
3269	    ${ECHO} "ERROR: Root DN passwd is invalid."
3270	else
3271	    ${ECHO} "ERROR2: Invalid Root DN <${LDAP_ROOTDN}>."
3272	fi
3273	cleanup
3274	exit 1
3275    fi
3276    [ $DEBUG -eq 1 ] && ${ECHO} "  RootDN ... OK"
3277    [ $DEBUG -eq 1 ] && ${ECHO} "  RootDN passwd ... OK"
3278
3279    # Check if the server supports the VLV.
3280    chk_vlv_indexes
3281    [ $DEBUG -eq 1 ] && ${ECHO} "  VLV indexes ... OK"
3282
3283    # Check LDAP suffix
3284    validate_suffix
3285    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP suffix ... OK"
3286}
3287
3288#
3289# format_string(): take a string as argument and set FMT_STR
3290# to be the same string formatted as follow:
3291# - only lower case characters
3292# - no unnecessary spaces around , and =
3293#
3294format_string()
3295{
3296    FMT_STR=`${ECHO} "$1" | tr '[A-Z]' '[a-z]' |
3297	sed -e 's/[ ]*,[ ]*/,/g' -e 's/[ ]*=[ ]*/=/g'`
3298}
3299
3300#
3301# prepare for the suffix entry creation
3302#
3303# input  : LDAP_BASEDN, LDAP_SUFFIX - base dn and suffix;
3304# in/out : LDAP_SUFFIX_OBJ, LDAP_SUFFIX_ACI - initially may come from config.
3305# output : NEED_CREATE_BACKEND - backend for this suffix needs to be created;
3306#          _RDN, _ATT, _VAL - suffix's RDN, id attribute name and its value.
3307# return : 0 - success, otherwise error.
3308#
3309prep_create_sfx_entry()
3310{
3311    [ $DEBUG -eq 1 ] && ${ECHO} "In prep_create_sfx_entry()"
3312
3313    # check whether suffix corresponds to base dn
3314    format_string "${LDAP_BASEDN}"
3315    ${ECHO} ",${FMT_STR}" | ${GREP} ",${LDAP_SUFFIX}$" >/dev/null 2>&1 ||
3316    {
3317	display_msg sfx_not_suitable
3318	return 1
3319    }
3320
3321    # parse LDAP_SUFFIX
3322    _RDN=`${ECHO} "${LDAP_SUFFIX}" | cut -d, -f1`
3323    _ATT=`${ECHO} "${_RDN}" | cut -d= -f1`
3324    _VAL=`${ECHO} "${_RDN}" | cut -d= -f2-`
3325
3326    # find out an objectclass for suffix entry if it is not defined yet
3327    [ -z "${LDAP_SUFFIX_OBJ}" ] &&
3328    {
3329	get_objectclass ${_ATT}
3330	[ -z "${_ATTR_NAME}" ] &&
3331	{
3332		display_msg obj_not_found
3333		return 1
3334	}
3335	LDAP_SUFFIX_OBJ=${_ATTR_NAME}
3336    }
3337    [ $DEBUG -eq 1 ] && ${ECHO} "Suffix entry object is ${LDAP_SUFFIX_OBJ}"
3338
3339    # find out an aci for suffix entry if it is not defined yet
3340    [ -z "${LDAP_SUFFIX_ACI}" ] &&
3341    {
3342	# set Directory Server default aci
3343	LDAP_SUFFIX_ACI=`cat <<EOF
3344aci: (targetattr != "userPassword || passwordHistory || passwordExpirationTime
3345 || passwordExpWarned || passwordRetryCount || retryCountResetTime ||
3346 accountUnlockTime || passwordAllowChangeTime")
3347 (
3348   version 3.0;
3349   acl "Anonymous access";
3350   allow (read, search, compare) userdn = "ldap:///anyone";
3351 )
3352aci: (targetattr != "nsroledn || aci || nsLookThroughLimit || nsSizeLimit ||
3353 nsTimeLimit || nsIdleTimeout || passwordPolicySubentry ||
3354 passwordExpirationTime || passwordExpWarned || passwordRetryCount ||
3355 retryCountResetTime || accountUnlockTime || passwordHistory ||
3356 passwordAllowChangeTime")
3357 (
3358   version 3.0;
3359   acl "Allow self entry modification except for some attributes";
3360   allow (write) userdn = "ldap:///self";
3361 )
3362aci: (targetattr = "*")
3363 (
3364   version 3.0;
3365   acl "Configuration Administrator";
3366   allow (all) userdn = "ldap:///uid=admin,ou=Administrators,
3367                         ou=TopologyManagement,o=NetscapeRoot";
3368 )
3369aci: (targetattr ="*")
3370 (
3371   version 3.0;
3372   acl "Configuration Administrators Group";
3373   allow (all) groupdn = "ldap:///cn=Configuration Administrators,
3374                          ou=Groups,ou=TopologyManagement,o=NetscapeRoot";
3375 )
3376EOF
3377`
3378    }
3379    [ $DEBUG -eq 1 ] && cat <<EOF
3380DEBUG: ACI for ${LDAP_SUFFIX} is
3381${LDAP_SUFFIX_ACI}
3382EOF
3383
3384    NEED_CREATE_BACKEND=
3385
3386    # check the suffix mapping tree ...
3387    # if mapping exists, suffix should work, otherwise DS inconsistent
3388    # NOTE: -b 'cn=mapping tree,cn=config' -s one 'cn=\"$1\"' won't work
3389    #       in case of 'cn' value in LDAP is not quoted by '"',
3390    #       -b 'cn=\"$1\",cn=mapping tree,cn=config' works in all cases
3391    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} \
3392	-b 'cn=\"${LDAP_SUFFIX}\",cn=mapping tree,cn=config' \
3393	-s base 'objectclass=*' dn ${VERB}" &&
3394    {
3395	[ $DEBUG -eq 1 ] && ${ECHO} "Suffix mapping already exists"
3396	# get_backend() either gets IDS_DATABASE or exits
3397	get_backend
3398	return 0
3399    }
3400
3401    # no suffix mapping, just in case check ldbm backends consistency -
3402    # there are must be NO any databases pointing to LDAP_SUFFIX
3403    [ -n "`${EVAL} \"${LDAPSEARCH} ${LDAP_ARGS} \
3404	-b 'cn=ldbm database,cn=plugins,cn=config' \
3405	-s one 'nsslapd-suffix=${LDAP_SUFFIX}' dn\" 2>/dev/null`" ] &&
3406    {
3407	display_msg sfx_config_incons
3408	return 1
3409    }
3410
3411    # ok, no suffix mapping, no ldbm database
3412    [ $DEBUG -eq 1 ] && ${ECHO} "DEBUG: backend needs to be created ..."
3413    NEED_CREATE_BACKEND=1
3414    return 0
3415}
3416
3417#
3418# prepare for the suffix backend creation
3419#
3420# input  : IDS_DATABASE - requested ldbm db name (must be not null)
3421# in/out : IDS_DATABASE_AVAIL - available ldbm db name
3422# return : 0 - ldbm db name ok
3423#          1 - IDS_DATABASE exists,
3424#              so IDS_DATABASE_AVAIL contains available name
3425#          2 - unable to find any available name
3426#
3427prep_create_sfx_backend()
3428{
3429    [ $DEBUG -eq 1 ] && ${ECHO} "In prep_create_sfx_backend()"
3430
3431    # check if requested name available
3432    [ "${IDS_DATABASE}" = "${IDS_DATABASE_AVAIL}" ] && return 0
3433
3434    # get the list of database names start with a requested name
3435    _LDBM_DBS=`${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} \
3436	-b 'cn=ldbm database,cn=plugins,cn=config' \
3437	-s one 'cn=${IDS_DATABASE}*' cn"` 2>/dev/null
3438
3439    # find available db name based on a requested name
3440    _i=""; _i_MAX=10
3441    while [ ${_i:-0} -lt ${_i_MAX} ]
3442    do
3443	_name="${IDS_DATABASE}${_i}"
3444	${ECHO} "${_LDBM_DBS}" | ${GREP} -i "^cn=${_name}$" >/dev/null 2>&1 ||
3445	{
3446		IDS_DATABASE_AVAIL="${_name}"
3447		break
3448	}
3449	_i=`expr ${_i:-0} + 1`
3450    done
3451
3452    [ "${IDS_DATABASE}" = "${IDS_DATABASE_AVAIL}" ] && return 0
3453
3454    [ -n "${IDS_DATABASE_AVAIL}" ] &&
3455    {
3456	display_msg ldbm_db_exist
3457	return 1
3458    }
3459
3460    display_msg unable_find_db_name
3461    return 2
3462}
3463
3464#
3465# add suffix if needed,
3466#     suffix entry and backend MUST be prepared by
3467#     prep_create_sfx_entry and prep_create_sfx_backend correspondingly
3468#
3469# input  : NEED_CREATE_SUFFIX, LDAP_SUFFIX, LDAP_SUFFIX_OBJ, _ATT, _VAL
3470#          LDAP_SUFFIX_ACI, NEED_CREATE_BACKEND, IDS_DATABASE
3471# return : 0 - suffix successfully created, otherwise error occured
3472#
3473add_suffix()
3474{
3475    [ $DEBUG -eq 1 ] && ${ECHO} "In add_suffix()"
3476
3477    [ -n "${NEED_CREATE_SUFFIX}" ] || return 0
3478
3479    [ -n "${NEED_CREATE_BACKEND}" ] &&
3480    {
3481	${EVAL} "${LDAPADD} ${LDAP_ARGS} ${VERB}" <<EOF
3482dn: cn="${LDAP_SUFFIX}",cn=mapping tree,cn=config
3483objectclass: top
3484objectclass: extensibleObject
3485objectclass: nsMappingTree
3486cn: ${LDAP_SUFFIX}
3487nsslapd-state: backend
3488nsslapd-backend: ${IDS_DATABASE}
3489
3490dn: cn=${IDS_DATABASE},cn=ldbm database,cn=plugins,cn=config
3491objectclass: top
3492objectclass: extensibleObject
3493objectclass: nsBackendInstance
3494cn: ${IDS_DATABASE}
3495nsslapd-suffix: ${LDAP_SUFFIX}
3496EOF
3497	[ $? -ne 0 ] &&
3498	{
3499		display_msg create_ldbm_db_error
3500		return 1
3501	}
3502
3503	${ECHO} "  ${STEP}. Database ${IDS_DATABASE} successfully created"
3504	STEP=`expr $STEP + 1`
3505    }
3506
3507    ${EVAL} "${LDAPADD} ${LDAP_ARGS} ${VERB}" <<EOF
3508dn: ${LDAP_SUFFIX}
3509objectclass: ${LDAP_SUFFIX_OBJ}
3510${_ATT}: ${_VAL}
3511${LDAP_SUFFIX_ACI}
3512EOF
3513    [ $? -ne 0 ] &&
3514    {
3515	display_msg create_suffix_entry_error
3516	return 1
3517    }
3518
3519    ${ECHO} "  ${STEP}. Suffix ${LDAP_SUFFIX} successfully created"
3520    STEP=`expr $STEP + 1`
3521    return 0
3522}
3523
3524#
3525# interactively get suffix and related info from a user
3526#
3527# input  : LDAP_BASEDN - Base DN
3528# output : LDAP_SUFFIX - Suffix, _ATT, _VAL - id attribute and its value;
3529#          LDAP_SUFFIX_OBJ, LDAP_SUFFIX_ACI - objectclass and aci;
3530#          NEED_CREATE_BACKEND - tells whether backend needs to be created;
3531#          IDS_DATABASE - prepared ldbm db name
3532# return : 0 - user gave a correct suffix
3533#          1 - suffix given by user cann't be created
3534#
3535get_suffix()
3536{
3537    [ $DEBUG -eq 1 ] && ${ECHO} "In get_suffix()"
3538
3539    while :
3540    do
3541	get_ans "Enter suffix to be created (b=back/h=help):" ${LDAP_BASEDN}
3542	case "${ANS}" in
3543	[Hh] | Help | help | \? ) display_msg create_suffix_help ;;
3544	[Bb] | Back | back | \< ) return 1 ;;
3545	* )
3546		format_string "${ANS}"
3547		LDAP_SUFFIX=${FMT_STR}
3548		prep_create_sfx_entry || continue
3549
3550		[ -n "${NEED_CREATE_BACKEND}" ] &&
3551		{
3552		    IDS_DATABASE_AVAIL= # reset the available db name
3553
3554		    reenter_suffix=
3555		    while :
3556		    do
3557			get_ans "Enter ldbm database name (b=back/h=help):" \
3558				${IDS_DATABASE_AVAIL:-${_VAL}}
3559			case "${ANS}" in
3560			[Hh] | \? ) display_msg enter_ldbm_db_help ;;
3561			[Bb] | \< ) reenter_suffix=1; break ;;
3562			* )
3563				IDS_DATABASE="${ANS}"
3564				prep_create_sfx_backend && break
3565			esac
3566		    done
3567		    [ -n "${reenter_suffix}" ] && continue
3568
3569		    [ $DEBUG -eq 1 ] && cat <<EOF
3570DEBUG: backend name for suffix ${LDAP_SUFFIX} will be ${IDS_DATABASE}
3571EOF
3572		}
3573
3574		# eventually everything is prepared
3575		return 0
3576		;;
3577	esac
3578    done
3579}
3580
3581#
3582# print out a script which sets LDAP suffix related preferences
3583#
3584print_suffix_config()
3585{
3586    cat <<EOF2
3587# LDAP suffix related preferences used only if needed
3588IDS_DATABASE="${IDS_DATABASE}"
3589LDAP_SUFFIX_OBJ="$LDAP_SUFFIX_OBJ"
3590LDAP_SUFFIX_ACI=\`cat <<EOF
3591${LDAP_SUFFIX_ACI}
3592EOF
3593\`
3594export IDS_DATABASE LDAP_SUFFIX_OBJ LDAP_SUFFIX_ACI
3595EOF2
3596}
3597
3598#
3599# check_basedn_suffix(): check that there is an existing
3600# valid suffix to hold current base DN
3601# return:
3602#   0: valid suffix found or new one should be created,
3603#      NEED_CREATE_SUFFIX flag actually indicates that
3604#   1: some error occures
3605#
3606check_basedn_suffix()
3607{
3608    [ $DEBUG -eq 1 ] && ${ECHO} "In check_basedn_suffix()"
3609
3610    NEED_CREATE_SUFFIX=
3611
3612    # find out existing suffixes
3613    discover_serv_suffix
3614
3615    ${ECHO} "  Validating LDAP Base DN and Suffix ..."
3616
3617    # check that LDAP Base DN might be added
3618    cur_ldap_entry=${LDAP_BASEDN}
3619    prev_ldap_entry=
3620    while [ "${cur_ldap_entry}" != "${prev_ldap_entry}" ]
3621    do
3622	[ $DEBUG -eq 1 ] && ${ECHO} "testing LDAP entry: ${cur_ldap_entry}"
3623	${LDAPSEARCH} ${SERVER_ARGS} -b "${cur_ldap_entry}" \
3624		-s one "objectclass=*" > /dev/null 2>&1
3625	if [ $? -eq 0 ]; then
3626	    break
3627	else
3628	    prev_ldap_entry=${cur_ldap_entry}
3629	    cur_ldap_entry=`${ECHO} ${cur_ldap_entry} | cut -f2- -d','`
3630	fi
3631    done
3632
3633    if [ "${cur_ldap_entry}" = "${prev_ldap_entry}" ]; then
3634	${ECHO} "  No valid suffixes were found for Base DN ${LDAP_BASEDN}"
3635
3636	NEED_CREATE_SUFFIX=1
3637	return 0
3638
3639    else
3640	[ $DEBUG -eq 1 ] && ${ECHO} "found valid LDAP entry: ${cur_ldap_entry}"
3641
3642	# Now looking for relevant suffix for this entry.
3643	# LDAP_SUFFIX will then be used to add necessary
3644	# base objects. See add_base_objects().
3645	format_string "${cur_ldap_entry}"
3646	lower_entry="${FMT_STR}"
3647	[ $DEBUG -eq 1 ] && ${ECHO} "final suffix list: ${LDAP_SUFFIX_LIST}"
3648	oIFS=$IFS
3649	[ $DEBUG -eq 1 ] && ${ECHO} "setting IFS to new line"
3650	IFS='
3651'
3652	for suff in ${LDAP_SUFFIX_LIST}
3653	do
3654	    [ $DEBUG -eq 1 ] && ${ECHO} "testing suffix: ${suff}"
3655	    format_string "${suff}"
3656	    lower_suff="${FMT_STR}"
3657	    if [ "${lower_entry}" = "${lower_suff}" ]; then
3658		LDAP_SUFFIX="${suff}"
3659		break
3660	    else
3661		dcstmp=`basename "${lower_entry}" "${lower_suff}"`
3662		if [ "${dcstmp}" = "${lower_entry}" ]; then
3663		    # invalid suffix, try next one
3664		    continue
3665		else
3666		    # valid suffix found
3667		    LDAP_SUFFIX="${suff}"
3668		    break
3669		fi
3670	    fi
3671	done
3672	[ $DEBUG -eq 1 ] && ${ECHO} "setting IFS to original value"
3673	IFS=$oIFS
3674
3675	[ $DEBUG -eq 1 ] && ${ECHO} "LDAP_SUFFIX: ${LDAP_SUFFIX}"
3676
3677	if [ -z "${LDAP_SUFFIX}" ]; then
3678	    # should not happen, since we found the entry
3679	    ${ECHO} "Could not find a valid suffix for ${LDAP_BASEDN}."
3680	    ${ECHO} "Exiting."
3681	    return 1
3682	fi
3683
3684	# Getting relevant database (backend)
3685	# IDS_DATABASE will then be used to create indexes.
3686	get_backend
3687
3688	return 0
3689    fi
3690}
3691
3692#
3693# discover_serv_suffix(): This function queries the server to find
3694#    suffixes available
3695#  return: 0: OK, suffix found
3696#          1: suffix not determined
3697discover_serv_suffix()
3698{
3699    [ $DEBUG -eq 1 ] && ${ECHO} "In discover_serv_suffix()"
3700
3701    # Search the server for the TOP of the TREE.
3702    ${LDAPSEARCH} ${SERVER_ARGS} -b "" -s base "objectclass=*" > ${TMPDIR}/checkTOP 2>&1
3703    ${GREP} -i namingcontexts ${TMPDIR}/checkTOP | \
3704	${GREP} -i -v NetscapeRoot > ${TMPDIR}/treeTOP
3705    NUM_TOP=`wc -l ${TMPDIR}/treeTOP | awk '{print $1}'`
3706    case $NUM_TOP in
3707	0)
3708	    [ $DEBUG -eq 1 ] && ${ECHO} "DEBUG: No suffix found in LDAP tree"
3709	    return 1
3710	    ;;
3711	*)  # build the list of suffixes; take out 'namingContexts=' in
3712	    # each line of ${TMPDIR}/treeTOP
3713	    LDAP_SUFFIX_LIST=`cat ${TMPDIR}/treeTOP |
3714		awk '{ printf("%s\n",substr($0,16,length-15)) }'`
3715	    ;;
3716    esac
3717
3718    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SUFFIX_LIST = $LDAP_SUFFIX_LIST"
3719    return 0
3720}
3721
3722
3723#
3724# modify_cn(): Change the cn from MUST to MAY in ipNetwork.
3725#
3726modify_cn()
3727{
3728    [ $DEBUG -eq 1 ] && ${ECHO} "In modify_cn()"
3729
3730    ( cat <<EOF
3731dn: cn=schema
3732changetype: modify
3733add: objectclasses
3734objectclasses: ( 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' )
3735EOF
3736) > ${TMPDIR}/ipNetwork_cn
3737
3738    # Modify the cn for ipNetwork.
3739    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/ipNetwork_cn ${VERB}"
3740    if [ $? -ne 0 ]; then
3741	${ECHO} "  ERROR: update of cn for ipNetwork failed!"
3742	cleanup
3743	exit 1
3744    fi
3745}
3746
3747
3748# modify_timelimit(): Modify timelimit to user value.
3749modify_timelimit()
3750{
3751    [ $DEBUG -eq 1 ] && ${ECHO} "In modify_timelimit()"
3752
3753    # Here doc to modify timelimit.
3754    ( cat <<EOF
3755dn: cn=config
3756changetype: modify
3757replace: nsslapd-timelimit
3758nsslapd-timelimit: ${IDS_TIMELIMIT}
3759EOF
3760) > ${TMPDIR}/ids_timelimit
3761
3762    # Add the entry.
3763    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/ids_timelimit ${VERB}"
3764    if [ $? -ne 0 ]; then
3765	${ECHO} "  ERROR: update of nsslapd-timelimit failed!"
3766	cleanup
3767	exit 1
3768    fi
3769
3770    # Display messages for modifications made in patch.
3771    ${ECHO} "  ${STEP}. Changed timelimit to ${IDS_TIMELIMIT} in cn=config."
3772    STEP=`expr $STEP + 1`
3773}
3774
3775
3776# modify_sizelimit(): Modify sizelimit to user value.
3777modify_sizelimit()
3778{
3779    [ $DEBUG -eq 1 ] && ${ECHO} "In modify_sizelimit()"
3780
3781    # Here doc to modify sizelimit.
3782    ( cat <<EOF
3783dn: cn=config
3784changetype: modify
3785replace: nsslapd-sizelimit
3786nsslapd-sizelimit: ${IDS_SIZELIMIT}
3787EOF
3788) > ${TMPDIR}/ids_sizelimit
3789
3790    # Add the entry.
3791    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/ids_sizelimit ${VERB}"
3792    if [ $? -ne 0 ]; then
3793	${ECHO} "  ERROR: update of nsslapd-sizelimit failed!"
3794	cleanup
3795	exit 1
3796    fi
3797
3798    # Display messages for modifications made in patch.
3799    ${ECHO} "  ${STEP}. Changed sizelimit to ${IDS_SIZELIMIT} in cn=config."
3800    STEP=`expr $STEP + 1`
3801}
3802
3803
3804# modify_pwd_crypt(): Modify the passwd storage scheme to support CRYPT.
3805modify_pwd_crypt()
3806{
3807    [ $DEBUG -eq 1 ] && ${ECHO} "In modify_pwd_crypt()"
3808
3809    # Here doc to modify passwordstoragescheme.
3810    # IDS 5.2 moved passwordchangesceme off to a new data structure.
3811    if [ $IDS_MAJVER -le 5 ] && [ $IDS_MINVER -le 1 ]; then
3812	( cat <<EOF
3813dn: cn=config
3814changetype: modify
3815replace: passwordstoragescheme
3816passwordstoragescheme: crypt
3817EOF
3818	) > ${TMPDIR}/ids_crypt
3819    else
3820	( cat <<EOF
3821dn: cn=Password Policy,cn=config
3822changetype: modify
3823replace: passwordstoragescheme
3824passwordstoragescheme: crypt
3825EOF
3826	) > ${TMPDIR}/ids_crypt
3827    fi
3828
3829    # Add the entry.
3830    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/ids_crypt ${VERB}"
3831    if [ $? -ne 0 ]; then
3832	${ECHO} "  ERROR: update of passwordstoragescheme failed!"
3833	cleanup
3834	exit 1
3835    fi
3836
3837    # Display messages for modifications made in patch.
3838    ${ECHO} "  ${STEP}. Changed passwordstoragescheme to \"crypt\" in cn=config."
3839    STEP=`expr $STEP + 1`
3840}
3841
3842
3843#
3844# add_eq_indexes(): Add indexes to improve search performance.
3845#
3846add_eq_indexes()
3847{
3848    [ $DEBUG -eq 1 ] && ${ECHO} "In add_eq_indexes()"
3849
3850    # Set eq indexes to add.
3851    _INDEXES="uidNumber ipNetworkNumber gidnumber oncrpcnumber automountKey"
3852
3853    if [ -z "${IDS_DATABASE}" ]; then
3854	get_backend
3855    fi
3856
3857    # Set _EXT to use as shortcut.
3858    _EXT="cn=index,cn=${IDS_DATABASE},cn=ldbm database,cn=plugins,cn=config"
3859
3860    # Display message to id current step.
3861    ${ECHO} "  ${STEP}. Processing eq,pres indexes:"
3862    STEP=`expr $STEP + 1`
3863
3864    # For loop to create indexes.
3865    for i in ${_INDEXES}; do
3866	[ $DEBUG -eq 1 ] && ${ECHO} "  Adding index for ${i}"
3867
3868	# Check if entry exists first, if so, skip to next.
3869	${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${i},${_EXT}\" -s base \
3870	    \"objectclass=*\" > /dev/null 2>&1"
3871	if [ $? -eq 0 ]; then
3872	    # Display index skipped.
3873	    ${ECHO} "      ${i} (eq,pres) skipped already exists"
3874	    continue
3875	fi
3876
3877	# Here doc to create LDIF.
3878	( cat <<EOF
3879dn: cn=${i},${_EXT}
3880objectClass: top
3881objectClass: nsIndex
3882cn: ${i}
3883nsSystemIndex: false
3884nsIndexType: pres
3885nsIndexType: eq
3886EOF
3887) > ${TMPDIR}/index_${i}
3888
3889	# Add the index.
3890	${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/index_${i} ${VERB}"
3891	if [ $? -ne 0 ]; then
3892	    ${ECHO} "  ERROR: Adding EQ,PRES index for ${i} failed!"
3893	    cleanup
3894	    exit 1
3895	fi
3896
3897	# Build date for task name.
3898	_YR=`date '+%y'`
3899	_MN=`date '+%m'`
3900	_DY=`date '+%d'`
3901	_H=`date '+%H'`
3902	_M=`date '+%M'`
3903	_S=`date '+%S'`
3904
3905	# Build task name
3906	TASKNAME="${i}_${_YR}_${_MN}_${_DY}_${_H}_${_M}_${_S}"
3907
3908	# Build the task entry to add.
3909	( cat <<EOF
3910dn: cn=${TASKNAME}, cn=index, cn=tasks, cn=config
3911changetype: add
3912objectclass: top
3913objectclass: extensibleObject
3914cn: ${TASKNAME}
3915nsInstance: ${IDS_DATABASE}
3916nsIndexAttribute: ${i}
3917EOF
3918) > ${TMPDIR}/task_${i}
3919
3920	# Add the task.
3921	${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/task_${i} ${VERB}"
3922	if [ $? -ne 0 ]; then
3923	    ${ECHO} "  ERROR: Adding task for ${i} failed!"
3924	    cleanup
3925	    exit 1
3926	fi
3927
3928	# Wait for task to finish, display current status.
3929	while :
3930	do
3931	    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} \
3932	        -b \"cn=${TASKNAME}, cn=index, cn=tasks, cn=config\" -s base \
3933	        \"objectclass=*\" nstaskstatus > \"${TMPDIR}/istask_${i}\" 2>&1"
3934	    ${GREP} "${TASKNAME}" "${TMPDIR}/istask_${i}" > /dev/null 2>&1
3935	    if [ $? -ne 0 ]; then
3936		break
3937	    fi
3938	    TASK_STATUS=`${GREP} -i nstaskstatus "${TMPDIR}/istask_${i}" |
3939	        head -1 | cut -d: -f2`
3940	    ${ECHO} "      ${i} (eq,pres)  $TASK_STATUS                  \r\c"
3941	    ${ECHO} "$TASK_STATUS" | ${GREP} "Finished" > /dev/null 2>&1
3942	    if [ $? -eq 0 ]; then
3943		break
3944	    fi
3945	    sleep 2
3946	done
3947
3948	# Print newline because of \c.
3949	${ECHO} " "
3950    done
3951}
3952
3953
3954#
3955# add_sub_indexes(): Add indexes to improve search performance.
3956#
3957add_sub_indexes()
3958{
3959    [ $DEBUG -eq 1 ] && ${ECHO} "In add_sub_indexes()"
3960
3961    # Set eq indexes to add.
3962    _INDEXES="ipHostNumber membernisnetgroup nisnetgrouptriple"
3963
3964    # Set _EXT to use as shortcut.
3965    _EXT="cn=index,cn=${IDS_DATABASE},cn=ldbm database,cn=plugins,cn=config"
3966
3967
3968    # Display message to id current step.
3969    ${ECHO} "  ${STEP}. Processing eq,pres,sub indexes:"
3970    STEP=`expr $STEP + 1`
3971
3972    # For loop to create indexes.
3973    for i in ${_INDEXES}; do
3974	[ $DEBUG -eq 1 ] && ${ECHO} "  Adding index for ${i}"
3975
3976	# Check if entry exists first, if so, skip to next.
3977	${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${i},${_EXT}\" \
3978	    -s base \"objectclass=*\" > /dev/null 2>&1"
3979	if [ $? -eq 0 ]; then
3980	    # Display index skipped.
3981	    ${ECHO} "      ${i} (eq,pres,sub) skipped already exists"
3982	    continue
3983	fi
3984
3985	# Here doc to create LDIF.
3986	( cat <<EOF
3987dn: cn=${i},${_EXT}
3988objectClass: top
3989objectClass: nsIndex
3990cn: ${i}
3991nsSystemIndex: false
3992nsIndexType: pres
3993nsIndexType: eq
3994nsIndexType: sub
3995EOF
3996) > ${TMPDIR}/index_${i}
3997
3998	# Add the index.
3999	${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/index_${i} ${VERB}"
4000	if [ $? -ne 0 ]; then
4001	    ${ECHO} "  ERROR: Adding EQ,PRES,SUB index for ${i} failed!"
4002	    cleanup
4003	    exit 1
4004	fi
4005
4006	# Build date for task name.
4007	_YR=`date '+%y'`
4008	_MN=`date '+%m'`
4009	_DY=`date '+%d'`
4010	_H=`date '+%H'`
4011	_M=`date '+%M'`
4012	_S=`date '+%S'`
4013
4014	# Build task name
4015	TASKNAME="${i}_${_YR}_${_MN}_${_DY}_${_H}_${_M}_${_S}"
4016
4017	# Build the task entry to add.
4018	( cat <<EOF
4019dn: cn=${TASKNAME}, cn=index, cn=tasks, cn=config
4020changetype: add
4021objectclass: top
4022objectclass: extensibleObject
4023cn: ${TASKNAME}
4024nsInstance: ${IDS_DATABASE}
4025nsIndexAttribute: ${i}
4026EOF
4027) > ${TMPDIR}/task_${i}
4028
4029	# Add the task.
4030	${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/task_${i} ${VERB}"
4031	if [ $? -ne 0 ]; then
4032	    ${ECHO} "  ERROR: Adding task for ${i} failed!"
4033	    cleanup
4034	    exit 1
4035	fi
4036
4037	# Wait for task to finish, display current status.
4038	while :
4039	do
4040	    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} \
4041	        -b \"cn=${TASKNAME}, cn=index, cn=tasks, cn=config\" -s base \
4042	        \"objectclass=*\" nstaskstatus > \"${TMPDIR}/istask_${i}\" 2>&1"
4043	    ${GREP} "${TASKNAME}" "${TMPDIR}/istask_${i}" > /dev/null 2>&1
4044	    if [ $? -ne 0 ]; then
4045		break
4046	    fi
4047	    TASK_STATUS=`${GREP} -i nstaskstatus "${TMPDIR}/istask_${i}" |
4048	        head -1 | cut -d: -f2`
4049	    ${ECHO} "      ${i} (eq,pres,sub)  $TASK_STATUS                  \r\c"
4050	    ${ECHO} "$TASK_STATUS" | ${GREP} "Finished" > /dev/null 2>&1
4051	    if [ $? -eq 0 ]; then
4052		break
4053	    fi
4054	    sleep 2
4055	done
4056
4057	# Print newline because of \c.
4058	${ECHO} " "
4059    done
4060}
4061
4062
4063#
4064# add_vlv_indexes(): Add VLV indexes to improve search performance.
4065#
4066add_vlv_indexes()
4067{
4068    [ $DEBUG -eq 1 ] && ${ECHO} "In add_vlv_indexes()"
4069
4070    # Set eq indexes to add.
4071    # Note semi colon separators because some filters contain colons
4072    _INDEX1="${LDAP_DOMAIN}.getgrent;${LDAP_DOMAIN}_group_vlv_index;ou=group;objectClass=posixGroup"
4073    _INDEX2="${LDAP_DOMAIN}.gethostent;${LDAP_DOMAIN}_hosts_vlv_index;ou=hosts;objectClass=ipHost"
4074    _INDEX3="${LDAP_DOMAIN}.getnetent;${LDAP_DOMAIN}_networks_vlv_index;ou=networks;objectClass=ipNetwork"
4075    _INDEX4="${LDAP_DOMAIN}.getpwent;${LDAP_DOMAIN}_passwd_vlv_index;ou=people;objectClass=posixAccount"
4076    _INDEX5="${LDAP_DOMAIN}.getrpcent;${LDAP_DOMAIN}_rpc_vlv_index;ou=rpc;objectClass=oncRpc"
4077    _INDEX6="${LDAP_DOMAIN}.getspent;${LDAP_DOMAIN}_shadow_vlv_index;ou=people;objectClass=shadowAccount"
4078
4079    # Indexes added during NIS to LDAP transition
4080    _INDEX7="${LDAP_DOMAIN}.getauhoent;${LDAP_DOMAIN}_auho_vlv_index;automountmapname=auto_home;objectClass=automount"
4081    _INDEX8="${LDAP_DOMAIN}.getsoluent;${LDAP_DOMAIN}_solu_vlv_index;ou=people;objectClass=SolarisUserAttr"
4082    _INDEX9="${LDAP_DOMAIN}.getauduent;${LDAP_DOMAIN}_audu_vlv_index;ou=people;objectClass=SolarisAuditUser"
4083    _INDEX10="${LDAP_DOMAIN}.getauthent;${LDAP_DOMAIN}_auth_vlv_index;ou=SolarisAuthAttr;objectClass=SolarisAuthAttr"
4084    _INDEX11="${LDAP_DOMAIN}.getexecent;${LDAP_DOMAIN}_exec_vlv_index;ou=SolarisProfAttr;&(objectClass=SolarisExecAttr)(SolarisKernelSecurityPolicy=*)"
4085    _INDEX12="${LDAP_DOMAIN}.getprofent;${LDAP_DOMAIN}_prof_vlv_index;ou=SolarisProfAttr;&(objectClass=SolarisProfAttr)(SolarisAttrLongDesc=*)"
4086    _INDEX13="${LDAP_DOMAIN}.getmailent;${LDAP_DOMAIN}_mail_vlv_index;ou=aliases;objectClass=mailGroup"
4087    _INDEX14="${LDAP_DOMAIN}.getbootent;${LDAP_DOMAIN}__boot_vlv_index;ou=ethers;&(objectClass=bootableDevice)(bootParameter=*)"
4088    _INDEX15="${LDAP_DOMAIN}.getethent;${LDAP_DOMAIN}_ethers_vlv_index;ou=ethers;&(objectClass=ieee802Device)(macAddress=*)"
4089    _INDEX16="${LDAP_DOMAIN}.getngrpent;${LDAP_DOMAIN}_netgroup_vlv_index;ou=netgroup;objectClass=nisNetgroup"
4090    _INDEX17="${LDAP_DOMAIN}.getipnent;${LDAP_DOMAIN}_ipn_vlv_index;ou=networks;&(objectClass=ipNetwork)(cn=*)"
4091    _INDEX18="${LDAP_DOMAIN}.getmaskent;${LDAP_DOMAIN}_mask_vlv_index;ou=networks;&(objectClass=ipNetwork)(ipNetmaskNumber=*)"
4092    _INDEX19="${LDAP_DOMAIN}.getprent;${LDAP_DOMAIN}_pr_vlv_index;ou=printers;objectClass=printerService"
4093    _INDEX20="${LDAP_DOMAIN}.getip4ent;${LDAP_DOMAIN}_ip4_vlv_index;ou=hosts;&(objectClass=ipHost)(ipHostNumber=*.*)"
4094    _INDEX21="${LDAP_DOMAIN}.getip6ent;${LDAP_DOMAIN}_ip6_vlv_index;ou=hosts;&(objectClass=ipHost)(ipHostNumber=*:*)"
4095
4096    _INDEXES="$_INDEX1 $_INDEX2 $_INDEX3 $_INDEX4 $_INDEX5 $_INDEX6 $_INDEX7 $_INDEX8 $_INDEX9 $_INDEX10 $_INDEX11 $_INDEX12 $_INDEX13 $_INDEX14 $_INDEX15 $_INDEX16 $_INDEX17 $_INDEX18 $_INDEX19 $_INDEX20 $_INDEX21 "
4097
4098
4099    # Set _EXT to use as shortcut.
4100    _EXT="cn=${IDS_DATABASE},cn=ldbm database,cn=plugins,cn=config"
4101
4102
4103    # Display message to id current step.
4104    ${ECHO} "  ${STEP}. Processing VLV indexes:"
4105    STEP=`expr $STEP + 1`
4106
4107    # Reset temp file for vlvindex commands.
4108    [ -f ${TMPDIR}/ds5_vlvindex_list ] &&  rm ${TMPDIR}/ds5_vlvindex_list
4109    touch ${TMPDIR}/ds5_vlvindex_list
4110    [ -f ${TMPDIR}/ds6_vlvindex_list ] &&  rm ${TMPDIR}/ds6_vlvindex_list
4111    touch ${TMPDIR}/ds6_vlvindex_list
4112
4113    # Get the instance name from iDS server.
4114    _INSTANCE="<server-instance>"    # Default to old output.
4115
4116    eval "${LDAPSEARCH} -v ${LDAP_ARGS} -b \"cn=config\" -s base \"objectclass=*\" nsslapd-instancedir | ${GREP} 'nsslapd-instancedir=' | cut -d'=' -f2- > ${TMPDIR}/instance_name 2>&1"
4117
4118    ${GREP} "slapd-" ${TMPDIR}/instance_name > /dev/null 2>&1 # Check if seems right?
4119    if [ $? -eq 0 ]; then # If success, grab name after "slapd-".
4120	_INST_DIR=`cat ${TMPDIR}/instance_name`
4121	_INSTANCE=`basename "${_INST_DIR}" | cut -d'-' -f2-`
4122    fi
4123
4124    # For loop to create indexes.
4125    for p in ${_INDEXES}; do
4126	[ $DEBUG -eq 1 ] && ${ECHO} "  Adding index for ${i}"
4127
4128	# Break p (pair) into i and j parts.
4129        i=`${ECHO} $p | cut -d';' -f1`
4130        j=`${ECHO} $p | cut -d';' -f2`
4131        k=`${ECHO} $p | cut -d';' -f3`
4132        m=`${ECHO} $p | cut -d';' -f4`
4133
4134	# Set _jEXT to use as shortcut.
4135	_jEXT="cn=${j},${_EXT}"
4136
4137	# Check if entry exists first, if so, skip to next.
4138	${LDAPSEARCH} ${SERVER_ARGS} -b "cn=${i},${_jEXT}" -s base "objectclass=*" > /dev/null 2>&1
4139	if [ $? -eq 0 ]; then
4140	    # Display index skipped.
4141	    ${ECHO} "      ${i} vlv_index skipped already exists"
4142	    continue
4143	fi
4144
4145	# Compute the VLV Scope from the LDAP_SEARCH_SCOPE.
4146	# NOTE: A value of "base (0)" does not make sense.
4147        case "$LDAP_SEARCH_SCOPE" in
4148            sub) VLV_SCOPE="2" ;;
4149            *)   VLV_SCOPE="1" ;;
4150        esac
4151
4152	# Here doc to create LDIF.
4153	( cat <<EOF
4154dn: ${_jEXT}
4155objectClass: top
4156objectClass: vlvSearch
4157cn: ${j}
4158vlvbase: ${k},${LDAP_BASEDN}
4159vlvscope: ${VLV_SCOPE}
4160vlvfilter: (${m})
4161aci: (target="ldap:///${_jEXT}")(targetattr="*")(version 3.0; acl "Config";allow(read,search,compare)userdn="ldap:///anyone";)
4162
4163dn: cn=${i},${_jEXT}
4164cn: ${i}
4165vlvSort: cn uid
4166objectclass: top
4167objectclass: vlvIndex
4168EOF
4169) > ${TMPDIR}/vlv_index_${i}
4170
4171	# Add the index.
4172	${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/vlv_index_${i} ${VERB}"
4173	if [ $? -ne 0 ]; then
4174	    ${ECHO} "  ERROR: Adding VLV index for ${i} failed!"
4175	    cleanup
4176	    exit 1
4177	fi
4178
4179	# Print message that index was created.
4180	${ECHO} "      ${i} vlv_index   Entry created"
4181
4182	# Add command to list of vlvindex commands to run.
4183	${ECHO} "  directoryserver -s ${_INSTANCE} vlvindex -n ${IDS_DATABASE} -T ${i}" >> ${TMPDIR}/ds5_vlvindex_list
4184	${ECHO} "  <install-path>/bin/dsadm reindex -l -t ${i} <directory-instance-path> ${LDAP_SUFFIX}" >> ${TMPDIR}/ds6_vlvindex_list
4185    done
4186}
4187
4188
4189#
4190# display_vlv_cmds(): Display VLV index commands to run on server.
4191#
4192display_vlv_cmds()
4193{
4194    if [ -s "${TMPDIR}/ds5_vlvindex_list" -o \
4195	 -s "${TMPDIR}/ds6_vlvindex_list" ]; then
4196	display_msg display_vlv_list
4197    fi
4198
4199    if [ -s "${TMPDIR}/ds5_vlvindex_list" ]; then
4200	cat ${TMPDIR}/ds5_vlvindex_list
4201    fi
4202
4203    cat << EOF
4204
4205
4206EOF
4207
4208    if [ -s "${TMPDIR}/ds6_vlvindex_list" ]; then
4209	cat ${TMPDIR}/ds6_vlvindex_list
4210    fi
4211}
4212
4213#
4214# keep_backward_compatibility(): Modify schema for the backward compatibility if
4215# there are the incompatible attributes already
4216#
4217keep_backward_compatibility()
4218{
4219    ${EVAL} "${LDAPSEARCH} ${SERVER_ARGS} -b cn=schema -s base \
4220        \"objectclass=*\" attributeTypes | ${GREP} -i memberGid-oid ${VERB}"
4221    if [ $? -eq 0 ]; then
4222        ${SED} -e 's/1\.3\.6\.1\.4\.1\.42\.2\.27\.5\.1\.30\ /memberGid-oid\ /' \
4223            ${TMPDIR}/schema_attr > ${TMPDIR}/schema_attr.new
4224        ${MV} ${TMPDIR}/schema_attr.new ${TMPDIR}/schema_attr
4225    fi
4226
4227    ${EVAL} "${LDAPSEARCH} ${SERVER_ARGS} -b cn=schema -s base \
4228        \"objectclass=*\" attributeTypes | ${GREP} -i rfc822mailMember-oid \
4229        ${VERB}"
4230    if [ $? -eq 0 ]; then
4231        ${SED} -e \
4232            's/1\.3\.6\.1\.4\.1\.42\.2\.27\.2\.1\.15\ /rfc822mailMember-oid\ /' \
4233            ${TMPDIR}/schema_attr > ${TMPDIR}/schema_attr.new
4234        ${MV} ${TMPDIR}/schema_attr.new ${TMPDIR}/schema_attr
4235    fi
4236}
4237
4238#
4239# update_schema_attr(): Update Schema to support Naming.
4240#
4241update_schema_attr()
4242{
4243    [ $DEBUG -eq 1 ] && ${ECHO} "In update_schema_attr()"
4244
4245    ( cat <<EOF
4246dn: cn=schema
4247changetype: modify
4248add: attributetypes
4249attributetypes: ( 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 )
4250attributetypes: ( 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 )
4251attributetypes: ( 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 )
4252attributetypes: ( 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 )
4253attributetypes: ( 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 )
4254attributetypes: ( 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 )
4255attributetypes: ( 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 )
4256attributetypes: ( 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 )
4257attributetypes: ( 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 )
4258attributetypes: ( 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 )
4259attributetypes: ( 2.16.840.1.113730.3.1.30 NAME 'mgrpRFC822MailMember' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4260attributetypes: ( 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 )
4261attributetypes: ( 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 )
4262attributetypes: ( 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 )
4263attributetypes: ( 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 )
4264attributetypes: ( 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 )
4265attributetypes: ( 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 )
4266attributetypes: ( 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 )
4267attributetypes: ( 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 )
4268attributetypes: ( 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 )
4269attributetypes: ( 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 )
4270attributetypes: ( 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 )
4271attributetypes: ( 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 )
4272attributetypes: ( 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 )
4273attributetypes: ( 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 )
4274attributetypes: ( 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 )
4275attributetypes: ( 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 )
4276attributetypes: ( 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 )
4277attributetypes: ( 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 )
4278attributetypes: ( 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 )
4279attributetypes: ( 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 )
4280attributetypes: ( 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 )
4281attributetypes: ( 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 )
4282attributetypes: ( 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 )
4283attributetypes: ( 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 )
4284attributetypes: ( 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 )
4285attributetypes: ( 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 )
4286attributetypes: ( 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 )
4287attributetypes: ( 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 )
4288attributetypes: ( 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 )
4289attributetypes: ( 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 )
4290attributetypes: ( 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 )
4291attributetypes: ( 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 )
4292attributetypes: ( 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 )
4293attributetypes: ( 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 )
4294attributetypes: ( 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 )
4295attributetypes: ( 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 )
4296attributetypes: ( 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 )
4297attributetypes: ( 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 )
4298attributetypes: ( 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 )
4299attributetypes: ( 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 )
4300attributetypes: ( 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 )
4301attributetypes: ( 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 )
4302attributetypes: ( 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 )
4303attributetypes: ( 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 )
4304attributetypes: ( 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 )
4305attributetypes: ( 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 )
4306attributetypes: ( 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 )
4307attributetypes: ( 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 )
4308attributetypes: ( 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 )
4309attributetypes: ( 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 )
4310attributetypes: ( 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 )
4311attributetypes: ( 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 )
4312attributetypes: ( 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 )
4313attributetypes: ( 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} )
4314attributetypes: ( 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 )
4315attributetypes: ( 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 )
4316attributetypes: ( 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} )
4317attributetypes: ( 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} )
4318attributetypes: ( 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} )
4319attributetypes: ( 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 )
4320attributetypes: ( 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} )
4321attributetypes: ( 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 )
4322attributetypes: ( 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 )
4323attributetypes: ( 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} )
4324attributetypes: ( 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 )
4325attributetypes: ( 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} )
4326attributetypes: ( 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} )
4327attributetypes: ( 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} )
4328attributetypes: ( 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} )
4329attributetypes: ( 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} )
4330attributetypes: ( 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 )
4331attributetypes: ( 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 )
4332attributetypes: ( 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 )
4333attributetypes: ( 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 )
4334attributetypes: ( 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 )
4335attributetypes: ( 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} )
4336attributetypes: ( 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} )
4337attributetypes: ( 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} )
4338attributetypes: ( 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} )
4339attributetypes: ( 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 )
4340attributetypes: ( 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 )
4341attributetypes: ( 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 )
4342attributetypes: ( 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 )
4343attributetypes: ( 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 )
4344EOF
4345) > ${TMPDIR}/schema_attr
4346
4347    keep_backward_compatibility
4348
4349    # Add the entry.
4350    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/schema_attr ${VERB}"
4351    if [ $? -ne 0 ]; then
4352	${ECHO} "  ERROR: update of schema attributes failed!"
4353	cleanup
4354	exit 1
4355    fi
4356
4357    # Display message that schema is updated.
4358    ${ECHO} "  ${STEP}. Schema attributes have been updated."
4359    STEP=`expr $STEP + 1`
4360}
4361
4362
4363#
4364# update_schema_obj(): Update the schema objectclass definitions.
4365#
4366update_schema_obj()
4367{
4368    [ $DEBUG -eq 1 ] && ${ECHO} "In update_schema_obj()"
4369
4370    # Add the objectclass definitions.
4371    ( cat <<EOF
4372dn: cn=schema
4373changetype: modify
4374add: objectclasses
4375objectclasses: ( 1.3.6.1.1.1.2.14 NAME 'NisKeyObject' SUP top MUST ( cn $ nisPublickey $ nisSecretkey ) MAY ( uidNumber $ description ) )
4376
4377dn: cn=schema
4378changetype: modify
4379add: objectclasses
4380objectclasses: ( 1.3.6.1.1.1.2.15 NAME 'nisDomainObject' SUP top MUST nisDomain )
4381
4382dn: cn=schema
4383changetype: modify
4384add: objectclasses
4385objectclasses: ( 1.3.6.1.1.1.2.16 NAME 'automountMap' SUP top MUST automountMapName MAY description )
4386
4387dn: cn=schema
4388changetype: modify
4389add: objectclasses
4390objectclasses: ( 1.3.6.1.1.1.2.17 NAME 'automount' SUP top MUST ( automountKey $ automountInformation ) MAY description )
4391
4392dn: cn=schema
4393changetype: modify
4394add: objectclasses
4395objectclasses: ( 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 ) )
4396
4397dn: cn=schema
4398changetype: modify
4399add: objectclasses
4400objectclasses: ( 2.16.840.1.113730.3.2.4 NAME 'mailGroup' SUP top MUST mail MAY ( cn $ mgrpRFC822MailMember ) )
4401
4402dn: cn=schema
4403changetype: modify
4404add: objectclasses
4405objectclasses: ( 1.3.6.1.4.1.42.2.27.1.2.5 NAME 'nisMailAlias' SUP top MUST cn MAY rfc822mailMember )
4406
4407dn: cn=schema
4408changetype: modify
4409add: objectclasses
4410objectclasses: ( 1.3.6.1.4.1.42.2.27.1.2.6 NAME 'nisNetId' SUP top MUST cn MAY ( nisNetIdUser $ nisNetIdGroup $ nisNetIdHost ) )
4411
4412dn: cn=schema
4413changetype: modify
4414add: objectclasses
4415objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.2 NAME 'SolarisAuditUser' SUP top AUXILIARY MAY ( SolarisAuditAlways $ SolarisAuditNever ) )
4416
4417dn: cn=schema
4418changetype: modify
4419add: objectclasses
4420objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.3 NAME 'SolarisUserAttr' SUP top AUXILIARY MAY ( SolarisUserQualifier $ SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrKeyValue ) )
4421
4422dn: cn=schema
4423changetype: modify
4424add: objectclasses
4425objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.4 NAME 'SolarisAuthAttr' SUP top MUST cn MAY ( SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrShortDesc $ SolarisAttrLongDesc $ SolarisAttrKeyValue ) )
4426
4427dn: cn=schema
4428changetype: modify
4429add: objectclasses
4430objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.5 NAME 'SolarisProfAttr' SUP top MUST cn MAY ( SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrLongDesc $ SolarisAttrKeyValue ) )
4431
4432dn: cn=schema
4433changetype: modify
4434add: objectclasses
4435objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.6 NAME 'SolarisExecAttr' SUP top AUXILIARY MAY ( SolarisKernelSecurityPolicy $ SolarisProfileType $ SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisProfileID $ SolarisAttrKeyValue ) )
4436
4437dn: cn=schema
4438changetype: modify
4439add: objectclasses
4440objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.1 NAME 'SolarisProject' SUP top MUST ( SolarisProjectID $ SolarisProjectName ) MAY ( memberUid $ memberGid $ description $ SolarisProjectAttr ) )
4441
4442dn: cn=schema
4443changetype: modify
4444add: objectclasses
4445objectclasses: ( 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 ) )
4446
4447dn: cn=schema
4448changetype: modify
4449add: objectclasses
4450objectclasses: ( 1.3.18.0.2.6.2549 NAME 'slpService' DESC 'DUMMY definition' SUP top MUST objectclass )
4451
4452dn: cn=schema
4453changetype: modify
4454add: objectclasses
4455objectclasses: ( 1.3.18.0.2.6.254 NAME 'slpServicePrinter' DESC 'Service Location Protocol (SLP) information.' SUP slpService AUXILIARY )
4456
4457dn: cn=schema
4458changetype: modify
4459add: objectclasses
4460objectclasses: ( 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 ) )
4461
4462dn: cn=schema
4463changetype: modify
4464add: objectclasses
4465objectclasses: ( 1.3.18.0.2.6.255 NAME 'printerService' DESC 'Printer information.' SUP printerAbstract STRUCTURAL MAY ( printer-uri $ printer-xri-supported ) )
4466
4467dn: cn=schema
4468changetype: modify
4469add: objectclasses
4470objectclasses: ( 1.3.18.0.2.6.257 NAME 'printerServiceAuxClass' DESC 'Printer information.' SUP printerAbstract AUXILIARY MAY ( printer-uri $ printer-xri-supported ) )
4471
4472dn: cn=schema
4473changetype: modify
4474add: objectclasses
4475objectclasses: ( 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 ) )
4476
4477dn: cn=schema
4478changetype: modify
4479add: objectclasses
4480objectclasses: ( 1.3.18.0.2.6.253 NAME 'printerLPR' DESC 'LPR information.' SUP top AUXILIARY MUST printer-name MAY printer-aliases )
4481
4482dn: cn=schema
4483changetype: modify
4484add: objectclasses
4485objectclasses: ( 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 ) )
4486
4487dn: cn=schema
4488changetype: modify
4489add: objectclasses
4490objectclasses:	( 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 ) )
4491
4492dn: cn=schema
4493changetype: modify
4494add: objectclasses
4495objectclasses:  ( 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 )
4496
4497dn: cn=schema
4498changetype: modify
4499add: objectclasses
4500objectclasses:	( 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 )
4501EOF
4502) > ${TMPDIR}/schema_obj
4503
4504    # Add the entry.
4505    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/schema_obj ${VERB}"
4506    if [ $? -ne 0 ]; then
4507	${ECHO} "  ERROR: update of schema objectclass definitions failed!"
4508	cleanup
4509	exit 1
4510    fi
4511
4512    # Display message that schema is updated.
4513    ${ECHO} "  ${STEP}. Schema objectclass definitions have been added."
4514    STEP=`expr $STEP + 1`
4515}
4516
4517#
4518# modify_top_aci(): Modify the ACI for the top entry to disable self modify
4519#                   of user attributes.
4520#
4521modify_top_aci()
4522{
4523    [ $DEBUG -eq 1 ] && ${ECHO} "In modify_top_aci()"
4524
4525    # Set ACI Name
4526    ACI_NAME="LDAP_Naming_Services_deny_write_access"
4527
4528    # Search for ACI_NAME
4529    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_top_aci 2>&1"
4530    if [ $? -ne 0 ]; then
4531	${ECHO} "Error searching aci for ${LDAP_BASEDN}"
4532	cat ${TMPDIR}/chk_top_aci
4533	cleanup
4534	exit 1
4535    fi
4536    ${GREP} "${ACI_NAME}" ${TMPDIR}/chk_top_aci > /dev/null 2>&1
4537    if [ $? -eq 0 ]; then
4538	${ECHO} "  ${STEP}. Top level ACI ${ACI_NAME} already exists for ${LDAP_BASEDN}."
4539	STEP=`expr $STEP + 1`
4540	return 0
4541    fi
4542
4543    # Crate LDIF for top level ACI.
4544    ( cat <<EOF
4545dn: ${LDAP_BASEDN}
4546changetype: modify
4547add: aci
4548aci: (targetattr = "cn||uid||uidNumber||gidNumber||homeDirectory||shadowLastChange||shadowMin||shadowMax||shadowWarning||shadowInactive||shadowExpire||shadowFlag||memberUid||SolarisAuditAlways||SolarisAuditNever||SolarisAttrKeyValue||SolarisAttrReserved1||SolarisAttrReserved2||SolarisUserQualifier")(version 3.0; acl ${ACI_NAME}; deny (write) userdn = "ldap:///self";)
4549-
4550EOF
4551) > ${TMPDIR}/top_aci
4552
4553    # Add the entry.
4554    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/top_aci ${VERB}"
4555    if [ $? -ne 0 ]; then
4556	${ECHO} "  ERROR: Modify of top level ACI failed! (restricts self modify)"
4557	cleanup
4558	exit 1
4559    fi
4560
4561    # Display message that ACI is updated.
4562    MSG="ACI for ${LDAP_BASEDN} modified to disable self modify."
4563    if [ $EXISTING_PROFILE -eq 1 ];then
4564	${ECHO} "  ACI SET: $MSG"
4565    else
4566	${ECHO} "  ${STEP}. $MSG"
4567	STEP=`expr $STEP + 1`
4568    fi
4569}
4570
4571#
4572# find_and_delete_ACI(): Find an ACI in file $2 with a matching pattern $1.
4573# Delete the ACI and print a message using $3 as the ACI name. $3 is needed
4574# because it could have a different value than that of $1.
4575find_and_delete_ACI()
4576{
4577    [ $DEBUG -eq 1 ] && ${ECHO} "In find_and_delete_ACI"
4578
4579    # if an ACI with pattern $1 exists in file $2, delete it from ${LDAP_BASEDN}
4580    ${EGREP} $1 $2 | ${SED} -e 's/aci=//' > ${TMPDIR}/grep_find_delete_aci 2>&1
4581    if [ -s ${TMPDIR}/grep_find_delete_aci ]; then
4582	aci_to_delete=`${CAT} ${TMPDIR}/grep_find_delete_aci`
4583
4584	# Create the tmp file to delete the ACI.
4585	( cat <<EOF
4586dn: ${LDAP_BASEDN}
4587changetype: modify
4588delete: aci
4589aci: ${aci_to_delete}
4590EOF
4591	) > ${TMPDIR}/find_delete_aci
4592
4593	# Delete the ACI
4594	${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/find_delete_aci ${VERB}"
4595	if [ $? -ne 0 ]; then
4596	    ${ECHO} "  ERROR: Remove of $3 ACI failed!"
4597	    cleanup
4598	    exit 1
4599	fi
4600
4601	${RM} -f ${TMPDIR}/find_delete_aci
4602	# Display message that an ACL is deleted.
4603	MSG="ACI $3 deleted."
4604	if [ $EXISTING_PROFILE -eq 1 ]; then
4605	    ${ECHO} "  ACI DELETED: $MSG"
4606	else
4607	    ${ECHO} "  ${STEP}. $MSG"
4608	    STEP=`expr $STEP + 1`
4609	fi
4610    fi
4611}
4612
4613#
4614# Add an ACI to deny non-admin access to shadow data when
4615# shadow update is enabled.
4616#
4617deny_non_admin_shadow_access()
4618{
4619    [ $DEBUG -eq 1 ] && ${ECHO} "In deny_non_admin_shadow_access()"
4620
4621    # Set ACI Names
4622    ACI_TO_ADD="LDAP_Naming_Services_deny_non_admin_shadow_access"
4623    ACI_TO_DEL="LDAP_Naming_Services_deny_non_host_shadow_access"
4624
4625    # Search for ACI_TO_ADD
4626    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_aci_non_admin 2>&1"
4627    if [ $? -ne 0 ]; then
4628	${ECHO} "Error searching aci for ${LDAP_BASEDN}"
4629	cleanup
4630	exit 1
4631    fi
4632
4633    # If an ACI with ${ACI_TO_ADD} already exists, we are done.
4634    ${EGREP} ${ACI_TO_ADD} ${TMPDIR}/chk_aci_non_admin 2>&1 > /dev/null
4635    if [ $? -eq 0 ]; then
4636	MSG="ACI ${ACI_TO_ADD} already set for ${LDAP_BASEDN}."
4637	if [ $EXISTING_PROFILE -eq 1 ]; then
4638	    ${ECHO} "  NOT SET: $MSG"
4639	else
4640	    ${ECHO} "  ${STEP}. $MSG"
4641	    STEP=`expr $STEP + 1`
4642	fi
4643	return 0
4644    fi
4645
4646    # The deny_non_admin_shadow_access and deny_non_host_shadow_access ACIs
4647    # should be mutually exclusive, so if the latter exists, delete it.
4648    find_and_delete_ACI ${ACI_TO_DEL} ${TMPDIR}/chk_aci_non_admin ${ACI_TO_DEL}
4649
4650    # Create the tmp file to add.
4651    ( cat <<EOF
4652dn: ${LDAP_BASEDN}
4653changetype: modify
4654add: aci
4655aci: (target="ldap:///${LDAP_BASEDN}")(targetattr = "shadowLastChange||
4656 shadowMin|| shadowMax||shadowWarning||shadowInactive||shadowExpire||
4657 shadowFlag||userPassword") (version 3.0; acl ${ACI_TO_ADD};
4658 deny (write,read,search,compare) userdn != "ldap:///${LDAP_ADMINDN}";)
4659EOF
4660) > ${TMPDIR}/non_admin_aci_write
4661
4662    # Add the entry.
4663    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/non_admin_aci_write ${VERB}"
4664    if [ $? -ne 0 ]; then
4665	${ECHO} "  ERROR: Adding ACI ${ACI_TO_ADD} failed!"
4666	${CAT} ${TMPDIR}/non_admin_aci_write
4667	cleanup
4668	exit 1
4669    fi
4670
4671    ${RM} -f ${TMPDIR}/non_admin_aci_write
4672    # Display message that the non-admin access to shadow data is denied.
4673    MSG="Non-Admin access to shadow data denied."
4674    if [ $EXISTING_PROFILE -eq 1 ]; then
4675	${ECHO} "  ACI SET: $MSG"
4676    else
4677	${ECHO} "  ${STEP}. $MSG"
4678	STEP=`expr $STEP + 1`
4679    fi
4680}
4681
4682#
4683# Add an ACI to deny non-host access to shadow data when
4684# shadow update is enabled and auth Method if gssapi.
4685#
4686deny_non_host_shadow_access()
4687{
4688    [ $DEBUG -eq 1 ] && ${ECHO} "In deny_non_host_shadow_access()"
4689
4690    # Set ACI Names
4691    ACI_TO_ADD="LDAP_Naming_Services_deny_non_host_shadow_access"
4692    ACI_TO_DEL="LDAP_Naming_Services_deny_non_admin_shadow_access"
4693
4694    # Search for ACI_TO_ADD
4695    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_aci_non_host 2>&1"
4696    if [ $? -ne 0 ]; then
4697	${ECHO} "Error searching aci for ${LDAP_BASEDN}"
4698	cleanup
4699	exit 1
4700    fi
4701
4702    # If an ACI with ${ACI_TO_ADD} already exists, we are done.
4703    ${EGREP} ${ACI_TO_ADD} ${TMPDIR}/chk_aci_non_host 2>&1 > /dev/null
4704    if [ $? -eq 0 ]; then
4705	MSG="ACI ${ACI_TO_ADD} already set for ${LDAP_BASEDN}."
4706	if [ $EXISTING_PROFILE -eq 1 ]; then
4707	    ${ECHO} "  NOT SET: $MSG"
4708	else
4709	    ${ECHO} "  ${STEP}. $MSG"
4710	    STEP=`expr $STEP + 1`
4711	fi
4712	return 0
4713    fi
4714
4715    # The deny_non_admin_shadow_access and deny_non_host_shadow_access ACIs
4716    # should be mutually exclusive, so if the former exists, delete it.
4717    find_and_delete_ACI ${ACI_TO_DEL} ${TMPDIR}/chk_aci_non_host ${ACI_TO_DEL}
4718
4719    # Create the tmp file to add.
4720    ( cat <<EOF
4721dn: ${LDAP_BASEDN}
4722changetype: modify
4723add: aci
4724aci: (target="ldap:///${LDAP_BASEDN}")(targetattr = "shadowLastChange||
4725 shadowMin|| shadowMax||shadowWarning||shadowInactive||shadowExpire||
4726 shadowFlag||userPassword") (version 3.0; acl ${ACI_TO_ADD};
4727  deny (write,read,search,compare)
4728  userdn != "ldap:///cn=*+ipHostNumber=*,ou=Hosts,${LDAP_BASEDN}";)
4729EOF
4730) > ${TMPDIR}/non_host_aci_write
4731
4732    # Add the entry.
4733    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/non_host_aci_write ${VERB}"
4734    if [ $? -ne 0 ]; then
4735	${ECHO} "  ERROR: Adding ACI ${ACI_TO_ADD} failed!"
4736	${CAT} ${TMPDIR}/non_host_aci_write
4737	cleanup
4738	exit 1
4739    fi
4740
4741    ${RM} -f ${TMPDIR}/non_host_aci_write
4742    # Display message that the non-host access to shadow data is denied.
4743    MSG="Non-host access to shadow data is denied."
4744    if [ $EXISTING_PROFILE -eq 1 ]; then
4745	${ECHO} "  ACI SET: $MSG"
4746    else
4747	${ECHO} "  ${STEP}. $MSG"
4748	STEP=`expr $STEP + 1`
4749    fi
4750}
4751
4752#
4753# add_vlv_aci(): Add access control information (aci) for VLV.
4754#
4755add_vlv_aci()
4756{
4757    [ $DEBUG -eq 1 ] && ${ECHO} "In add_vlv_aci()"
4758
4759    # Add the VLV ACI.
4760    ( cat <<EOF
4761dn: oid=2.16.840.1.113730.3.4.9,cn=features,cn=config
4762changetype: modify
4763replace: aci
4764aci: (targetattr != "aci") (version 3.0; acl "VLV Request Control"; allow(read,search,compare) userdn = "ldap:///anyone";)
4765EOF
4766) > ${TMPDIR}/vlv_aci
4767
4768    # Add the entry.
4769    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/vlv_aci ${VERB}"
4770    if [ $? -ne 0 ]; then
4771	${ECHO} "  ERROR: Add of VLV ACI failed!"
4772	cleanup
4773	exit 1
4774    fi
4775
4776    # Display message that schema is updated.
4777    ${ECHO} "  ${STEP}. Add of VLV Access Control Information (ACI)."
4778    STEP=`expr $STEP + 1`
4779}
4780
4781
4782#
4783# set_nisdomain(): Add the NisDomainObject to the Base DN.
4784#
4785set_nisdomain()
4786{
4787    [ $DEBUG -eq 1 ] && ${ECHO} "In set_nisdomain()"
4788
4789    # Check if nisDomain is already set.
4790    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base \
4791	\"objectclass=*\"" > ${TMPDIR}/chk_nisdomain 2>&1
4792    ${EVAL} "${GREP} -i nisDomain ${TMPDIR}/chk_nisdomain ${VERB}"
4793    if [ $? -eq 0 ]; then
4794	${ECHO} "  ${STEP}. NisDomainObject for ${LDAP_BASEDN} was already set."
4795	STEP=`expr $STEP + 1`
4796	return 0
4797    fi
4798
4799    # Add the new top level containers.
4800    ( cat <<EOF
4801dn: ${LDAP_BASEDN}
4802changetype: modify
4803objectclass: nisDomainObject
4804nisdomain: ${LDAP_DOMAIN}
4805EOF
4806) > ${TMPDIR}/nis_domain
4807
4808    # Add the entry.
4809    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/nis_domain ${VERB}"
4810    if [ $? -ne 0 ]; then
4811	${ECHO} "  ERROR: update of NisDomainObject in ${LDAP_BASEDN} failed."
4812	cleanup
4813	exit 1
4814    fi
4815
4816    # Display message that schema is updated.
4817    ${ECHO} "  ${STEP}. NisDomainObject added to ${LDAP_BASEDN}."
4818    STEP=`expr $STEP + 1`
4819}
4820
4821
4822#
4823# check_attrName(): Check that the attribute name is valid.
4824#              $1   Key to check.
4825#         Returns   0 : valid name	1 : invalid name
4826#
4827check_attrName()
4828{
4829    [ $DEBUG -eq 1 ] && ${ECHO} "In check_attrName()"
4830    [ $DEBUG -eq 1 ] && ${ECHO} "check_attrName: Input Param = $1"
4831
4832    ${ECHO} $1 | ${EGREP} '^[0-9]+(\.[0-9]+)*$' > /dev/null 2>&1
4833    if [ $? -eq 0 ]; then
4834	${EVAL} "${LDAPSEARCH} ${SERVER_ARGS} -b cn=schema -s base \"objectclass=*\" \
4835			attributeTypes | ${EGREP} -i '^attributetypes[ ]*=[ ]*\([ ]*$1 ' ${VERB}"
4836    else
4837	${EVAL} "${LDAPSEARCH} ${SERVER_ARGS} -b cn=schema -s base \"objectclass=*\" \
4838			attributeTypes | ${EGREP} -i \"'$1'\" ${VERB}"
4839    fi
4840
4841    if [ $? -ne 0 ]; then
4842	return 1
4843    else
4844	return 0
4845    fi
4846}
4847
4848
4849#
4850# get_objectclass():   Determine the objectclass for the given attribute name
4851#              $1   Attribute name to check.
4852#      _ATTR_NAME   Return value, Object Name or NULL if unknown to idsconfig.
4853#
4854#      NOTE: An attribute name can be valid but still we might not be able
4855#            to determine the objectclass from the table.
4856#            In such cases, the user needs to create the necessary object(s).
4857#
4858get_objectclass()
4859{
4860    [ $DEBUG -eq 1 ] && ${ECHO} "In get_objectclass()"
4861    [ $DEBUG -eq 1 ] && ${ECHO} "get_objectclass: Input Param = $1"
4862
4863    # Set return value to NULL string.
4864    _ATTR_NAME=""
4865
4866    # Test key for type:
4867    case `${ECHO} ${1} | tr '[A-Z]' '[a-z]'` in
4868	ou | organizationalunitname | 2.5.4.11) _ATTR_NAME="organizationalUnit" ;;
4869	dc | domaincomponent | 0.9.2342.19200300.100.1.25) _ATTR_NAME="domain" ;;
4870	 o | organizationname | 2.5.4.10) _ATTR_NAME="organization" ;;
4871	 c | countryname | 2.5.4.6) _ATTR_NAME="country" ;;
4872	 *)  _ATTR_NAME="" ;;
4873    esac
4874
4875    [ $DEBUG -eq 1 ] && ${ECHO} "get_objectclass: _ATTR_NAME = $_ATTR_NAME"
4876}
4877
4878
4879#
4880# add_base_objects(): Add any necessary base objects.
4881#
4882add_base_objects()
4883{
4884    [ $DEBUG -eq 1 ] && ${ECHO} "In add_base_objects()"
4885
4886    # Convert to lower case for basename.
4887    format_string "${LDAP_BASEDN}"
4888    LOWER_BASEDN="${FMT_STR}"
4889    format_string "${LDAP_SUFFIX}"
4890    LOWER_SUFFIX="${FMT_STR}"
4891
4892    [ $DEBUG -eq 1 ] && ${ECHO} "LOWER_BASEDN: ${LOWER_BASEDN}"
4893    [ $DEBUG -eq 1 ] && ${ECHO} "LOWER_SUFFIX: ${LOWER_SUFFIX}"
4894
4895    # Create additional components.
4896    if [ "${LOWER_BASEDN}" = "${LOWER_SUFFIX}" ]; then
4897	[ $DEBUG -eq 1 ] && ${ECHO} "Base DN and Suffix equivalent"
4898    else
4899	# first, test that the suffix is valid
4900	dcstmp=`basename "${LOWER_BASEDN}" "${LOWER_SUFFIX}"`
4901	if [ "$dcstmp" = "${LOWER_BASEDN}" ]; then
4902	    # should not happen since check_basedn_suffix() succeeded
4903	    ${ECHO} "Invalid suffix ${LOWER_SUFFIX}"
4904	    ${ECHO} "for Base DN ${LOWER_BASEDN}"
4905	    cleanup
4906	    exit 1
4907	fi
4908	# OK, suffix is valid, start working with LDAP_BASEDN
4909	# field separator is ',' (i.e., space is a valid character)
4910	dcstmp2="`${ECHO} ${LDAP_BASEDN} |
4911		sed -e 's/[ ]*,[ ]*/,/g' -e 's/[ ]*=[ ]*/=/g'`"
4912	dcs=""
4913	# use dcstmp to count the loop, and dcstmp2 to get the correct
4914	# string case
4915	# dcs should be in reverse order, only for these components
4916	# that need to be added
4917	while [ -n "${dcstmp}" ]
4918	do
4919	    i2=`${ECHO} "$dcstmp2" | cut -f1 -d','`
4920	    dk=`${ECHO} $i2 | awk -F= '{print $1}'`
4921	    dc=`${ECHO} $i2 | awk -F= '{print $2}'`
4922	    dcs="$dk=$dc,$dcs";
4923	    dcstmp2=`${ECHO} "$dcstmp2" | cut -f2- -d','`
4924	    dcstmp=`${ECHO} "$dcstmp" | cut -f2- -d','`
4925	    [ $DEBUG -eq 1 ] && \
4926		${ECHO} "dcs: ${dcs}\ndcstmp: ${dcstmp}\ndcstmp2: ${dcstmp2}\n"
4927	done
4928
4929
4930
4931	lastdc=${LDAP_SUFFIX}
4932	dc=`${ECHO} "${dcs}" | cut -f1 -d','`
4933	dcstmp=`${ECHO} "${dcs}" | cut -f2- -d','`
4934	while [ -n "${dc}" ]; do
4935	    # Get Key and component from $dc.
4936	    dk2=`${ECHO} $dc | awk -F= '{print $1}'`
4937	    dc2=`${ECHO} $dc | awk -F= '{print $2}'`
4938
4939	    # At this point, ${dk2} is a valid attribute name
4940
4941	    # Check if entry exists first, if so, skip to next.
4942	    ${LDAPSEARCH} ${SERVER_ARGS} -b "${dk2}=${dc2},$lastdc" -s base "objectclass=*" > /dev/null 2>&1
4943	    if [ $? -eq 0 ]; then
4944	        # Set the $lastdc to new dc.
4945	        lastdc="${dk2}=${dc2},$lastdc"
4946
4947		# Process next component.
4948		dc=`${ECHO} "${dcstmp}" | cut -f1 -d','`
4949		dcstmp=`${ECHO} "${dcstmp}" | cut -f2- -d','`
4950		continue
4951
4952	    fi
4953
4954	    # Determine the objectclass for the entry.
4955            get_objectclass $dk2
4956	    OBJ_Name=${_ATTR_NAME}
4957	    if [ "${OBJ_Name}" = "" ]; then
4958	        ${ECHO} "Cannot determine objectclass for $dk2"
4959	        ${ECHO} "Please create ${dk2}=${dc2},$lastdc entry and rerun idsconfig"
4960	        exit 1
4961	    fi
4962
4963	    # Add the new container.
4964	    ( cat <<EOF
4965dn: ${dk2}=${dc2},$lastdc
4966${dk2}: $dc2
4967objectClass: top
4968objectClass: ${OBJ_Name}
4969EOF
4970) > ${TMPDIR}/base_objects
4971
4972
4973	    # Set the $lastdc to new dc.
4974	    lastdc="${dk2}=${dc2},$lastdc"
4975
4976	    # Add the entry.
4977	    ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/base_objects ${VERB}"
4978	    if [ $? -ne 0 ]; then
4979		${ECHO} "  ERROR: update of base objects ${dc} failed."
4980		cleanup
4981		exit 1
4982	    fi
4983
4984	    # Display message that schema is updated.
4985	    ${ECHO} "  ${STEP}. Created DN component ${dc}."
4986	    STEP=`expr $STEP + 1`
4987
4988	    # Process next component.
4989	    dc=`${ECHO} "${dcstmp}" | cut -f1 -d','`
4990	    dcstmp=`${ECHO} "${dcstmp}" | cut -f2- -d','`
4991	done
4992    fi
4993}
4994
4995
4996#
4997# add_new_containers(): Add the top level classes.
4998#
4999#    $1 = Base DN
5000#
5001add_new_containers()
5002{
5003    [ $DEBUG -eq 1 ] && ${ECHO} "In add_new_containers()"
5004
5005    for ou in people group rpc protocols networks netgroup \
5006	aliases hosts services ethers profile printers projects \
5007	SolarisAuthAttr SolarisProfAttr Timezone ipTnet ; do
5008
5009	# Check if nismaps already exist.
5010	eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"ou=${ou},${LDAP_BASEDN}\" -s base \"objectclass=*\" ${VERB}"
5011	if [ $? -eq 0 ]; then
5012	    continue
5013	fi
5014
5015	# Create TMP file to add.
5016	( cat <<EOF
5017dn: ou=${ou},${LDAP_BASEDN}
5018ou: ${ou}
5019objectClass: top
5020objectClass: organizationalUnit
5021EOF
5022) > ${TMPDIR}/toplevel.${ou}
5023
5024	# Add the entry.
5025	${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/toplevel.${ou} ${VERB}"
5026	if [ $? -ne 0 ]; then
5027	    ${ECHO} "  ERROR: Add of ou=${ou} container failed!"
5028	    cleanup
5029	    exit 1
5030	fi
5031    done
5032
5033    # Display message that top level OU containers complete.
5034    ${ECHO} "  ${STEP}. Top level \"ou\" containers complete."
5035    STEP=`expr $STEP + 1`
5036}
5037
5038
5039#
5040# add_auto_maps(): Add the automount map entries.
5041#
5042# auto_home, auto_direct, auto_master, auto_shared
5043#
5044add_auto_maps()
5045{
5046    [ $DEBUG -eq 1 ] && ${ECHO} "In add_auto_maps()"
5047
5048    # Set AUTO_MAPS for maps to create.
5049    AUTO_MAPS="auto_home auto_direct auto_master auto_shared"
5050
5051    for automap in $AUTO_MAPS; do
5052	# Check if automaps already exist.
5053	eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"automountMapName=${automap},${LDAP_BASEDN}\" -s base \"objectclass=*\" ${VERB}"
5054	if [ $? -eq 0 ]; then
5055	    continue
5056	fi
5057
5058	# Create the tmp file to add.
5059	( cat <<EOF
5060dn: automountMapName=${automap},${LDAP_BASEDN}
5061automountMapName: ${automap}
5062objectClass: top
5063objectClass: automountMap
5064EOF
5065) > ${TMPDIR}/automap.${automap}
5066
5067	# Add the entry.
5068	${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/automap.${automap} ${VERB}"
5069	if [ $? -ne 0 ]; then
5070	    ${ECHO} "  ERROR: Add of automap ${automap} failed!"
5071	    cleanup
5072	    exit 1
5073	fi
5074    done
5075
5076    # Display message that automount entries are updated.
5077    ${ECHO} "  ${STEP}. automount maps: $AUTO_MAPS processed."
5078    STEP=`expr $STEP + 1`
5079}
5080
5081
5082#
5083# add_proxyagent(): Add entry for nameservice to use to access server.
5084#
5085add_proxyagent()
5086{
5087    [ $DEBUG -eq 1 ] && ${ECHO} "In add_proxyagent()"
5088
5089    # Check if proxy agent already exists.
5090    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_PROXYAGENT}\" -s base \"objectclass=*\" ${VERB}"
5091    if [ $? -eq 0 ]; then
5092	${ECHO} "  ${STEP}. Proxy Agent ${LDAP_PROXYAGENT} already exists."
5093	STEP=`expr $STEP + 1`
5094	return 0
5095    fi
5096
5097    # Get cn and sn names from LDAP_PROXYAGENT.
5098    cn_tmp=`${ECHO} ${LDAP_PROXYAGENT} | cut -f1 -d, | cut -f2 -d=`
5099
5100    # Create the tmp file to add.
5101    ( cat <<EOF
5102dn: ${LDAP_PROXYAGENT}
5103cn: ${cn_tmp}
5104sn: ${cn_tmp}
5105objectclass: top
5106objectclass: person
5107userpassword: ${LDAP_PROXYAGENT_CRED}
5108EOF
5109) > ${TMPDIR}/proxyagent
5110
5111    # Add the entry.
5112    ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/proxyagent ${VERB}"
5113    if [ $? -ne 0 ]; then
5114	${ECHO} "  ERROR: Adding proxyagent failed!"
5115	cleanup
5116	exit 1
5117    fi
5118
5119    # Display message that schema is updated.
5120    ${ECHO} "  ${STEP}. Proxy Agent ${LDAP_PROXYAGENT} added."
5121    STEP=`expr $STEP + 1`
5122}
5123
5124#
5125# allow_proxy_read_pw(): Give Proxy Agent read permission for password.
5126#
5127allow_proxy_read_pw()
5128{
5129    [ $DEBUG -eq 1 ] && ${ECHO} "In allow_proxy_read_pw()"
5130
5131    # Search for ACI_NAME
5132    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_proxyread_aci 2>&1"
5133    ${GREP} "${PROXY_ACI_NAME}" ${TMPDIR}/chk_proxyread_aci > /dev/null 2>&1
5134    if [ $? -eq 0 ]; then
5135	${ECHO} "  ${STEP}. Proxy ACI ${PROXY_ACI_NAME=} already exists for ${LDAP_BASEDN}."
5136	STEP=`expr $STEP + 1`
5137	return 0
5138    fi
5139
5140    # Create the tmp file to add.
5141    ( cat <<EOF
5142dn: ${LDAP_BASEDN}
5143changetype: modify
5144add: aci
5145aci: (target="ldap:///${LDAP_BASEDN}")(targetattr="userPassword")
5146  (version 3.0; acl ${PROXY_ACI_NAME}; allow (compare,read,search)
5147  userdn = "ldap:///${LDAP_PROXYAGENT}";)
5148EOF
5149) > ${TMPDIR}/proxy_read
5150
5151    # Add the entry.
5152    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/proxy_read ${VERB}"
5153    if [ $? -ne 0 ]; then
5154	${ECHO} "  ERROR: Allow ${LDAP_PROXYAGENT} to read password failed!"
5155	cleanup
5156	exit 1
5157    fi
5158
5159    # Display message that schema is updated.
5160    ${ECHO} "  ${STEP}. Give ${LDAP_PROXYAGENT} read permission for password."
5161    STEP=`expr $STEP + 1`
5162}
5163
5164#  Delete Proxy Agent read permission for password.
5165delete_proxy_read_pw()
5166{
5167    [ $DEBUG -eq 1 ] && ${ECHO} "In delete_proxy_read_pw()"
5168
5169    # Search for ACI_NAME
5170    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_proxyread_aci 2>&1"
5171    ${GREP} "${PROXY_ACI_NAME}" ${TMPDIR}/chk_proxyread_aci | \
5172	${SED} -e 's/aci=//' > ${TMPDIR}/grep_proxyread_aci 2>&1
5173    if [ $? -ne 0 ]; then
5174	${ECHO} "Proxy ACI ${PROXY_ACI_NAME} does not exist for ${LDAP_BASEDN}."
5175	return 0
5176    fi
5177
5178    # We need to remove proxy agent's read access to user passwords,
5179    # but We do not know the value of the ${LDAP_PROXYAGENT} here, so
5180    # 1. if only one match found, delete it
5181    # 2. if more than one matches found, ask the user which one to delete
5182    HOWMANY=`${WC} -l ${TMPDIR}/grep_proxyread_aci | ${NAWK} '{print $1}'`
5183    if [ $HOWMANY -eq 0 ]; then
5184	${ECHO} "Proxy ACI ${PROXY_ACI_NAME} does not exist for ${LDAP_BASEDN}."
5185	return 0
5186    fi
5187    if [ $HOWMANY -eq 1 ];then
5188	proxy_aci=`${CAT} ${TMPDIR}/grep_proxyread_aci`
5189    else
5190	    ${CAT} << EOF
5191
5192Proxy agent is not allowed to read user passwords when shadow
5193update is enabled. There are more than one proxy agents found.
5194Please select the currently proxy agent being used, so that
5195idsconfig can remove its read access to user passwords.
5196
5197The proxy agents are:
5198
5199EOF
5200	    # generate the proxy agent list
5201    	    ${SED} -e "s/.*ldap:\/\/\/.*ldap:\/\/\///" \
5202	    ${TMPDIR}/grep_proxyread_aci | ${SED} -e "s/\";)//" > \
5203	    	${TMPDIR}/proxy_agent_list
5204
5205	    # print the proxy agent list
5206	    ${NAWK} '{print NR ": " $0}' ${TMPDIR}/proxy_agent_list
5207
5208	    # ask the user to pick one
5209	    _MENU_PROMPT="Select the proxy agent (1-$HOWMANY): "
5210	    get_menu_choice "${_MENU_PROMPT}" "0" "$HOWMANY"
5211	    _CH=$MN_CH
5212	    proxy_aci=`${SED} -n "$_CH p" ${TMPDIR}/grep_proxyread_aci`
5213    fi
5214
5215    # Create the tmp file to delete the ACI.
5216    ( cat <<EOF
5217dn: ${LDAP_BASEDN}
5218changetype: modify
5219delete: aci
5220aci: ${proxy_aci}
5221EOF
5222    ) > ${TMPDIR}/proxy_delete
5223
5224    # Delete the ACI
5225    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/proxy_delete ${VERB}"
5226    if [ $? -ne 0 ]; then
5227	${ECHO} "  ERROR: Remove of ${PROXY_ACI_NAME} ACI failed!"
5228	cat ${TMPDIR}/proxy_delete
5229	cleanup
5230	exit 1
5231    fi
5232
5233    # Display message that ACI is updated.
5234    MSG="Removed ${PROXY_ACI_NAME} ACI for proxyagent read permission for password."
5235    ${ECHO} " "
5236    ${ECHO} "  ACI REMOVED: $MSG"
5237    ${ECHO} "  The ACI removed is $proxy_aci"
5238    ${ECHO} " "
5239}
5240
5241#
5242# add_profile(): Add client profile to server.
5243#
5244add_profile()
5245{
5246    [ $DEBUG -eq 1 ] && ${ECHO} "In add_profile()"
5247
5248    # If profile name already exists, DELETE it, and add new one.
5249    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${LDAP_PROFILE_NAME},ou=profile,${LDAP_BASEDN}\" -s base \"objectclass=*\" ${VERB}"
5250    if [ $? -eq 0 ]; then
5251	# Create Delete file.
5252	( cat <<EOF
5253cn=${LDAP_PROFILE_NAME},ou=profile,${LDAP_BASEDN}
5254EOF
5255) > ${TMPDIR}/del_profile
5256
5257	# Check if DEL_OLD_PROFILE is set.  (If not ERROR)
5258	if [ $DEL_OLD_PROFILE -eq 0 ]; then
5259	    ${ECHO} "ERROR: Profile name ${LDAP_PROFILE_NAME} exists! Add failed!"
5260	    exit 1
5261	fi
5262
5263	# Delete the OLD profile.
5264	${EVAL} "${LDAPDELETE} ${LDAP_ARGS} -f ${TMPDIR}/del_profile ${VERB}"
5265	if [ $? -ne 0 ]; then
5266	    ${ECHO} "  ERROR: Attempt to DELETE profile failed!"
5267	    cleanup
5268	    exit 1
5269	fi
5270    fi
5271
5272    # Build the "ldapclient genprofile" command string to execute.
5273    GEN_CMD="ldapclient genprofile -a \"profileName=${LDAP_PROFILE_NAME}\""
5274
5275    # Add required argument defaultSearchBase.
5276    GEN_CMD="${GEN_CMD} -a \"defaultSearchBase=${LDAP_BASEDN}\""
5277
5278    # Add optional parameters.
5279    [ -n "$LDAP_SERVER_LIST" ] && \
5280	GEN_CMD="${GEN_CMD} -a \"defaultServerList=${LDAP_SERVER_LIST}\""
5281    [ -n "$LDAP_SEARCH_SCOPE" ] && \
5282	GEN_CMD="${GEN_CMD} -a \"defaultSearchScope=${LDAP_SEARCH_SCOPE}\""
5283    [ -n "$LDAP_CRED_LEVEL" ] && \
5284	GEN_CMD="${GEN_CMD} -a \"credentialLevel=${LDAP_CRED_LEVEL}\""
5285    [ -n "$LDAP_AUTHMETHOD" ] && \
5286	GEN_CMD="${GEN_CMD} -a \"authenticationMethod=${LDAP_AUTHMETHOD}\""
5287    [ -n "$LDAP_FOLLOWREF" ] && \
5288	GEN_CMD="${GEN_CMD} -a \"followReferrals=${LDAP_FOLLOWREF}\""
5289    [ -n "$LDAP_SEARCH_TIME_LIMIT" ] && \
5290	GEN_CMD="${GEN_CMD} -a \"searchTimeLimit=${LDAP_SEARCH_TIME_LIMIT}\""
5291    [ -n "$LDAP_PROFILE_TTL" ] && \
5292	GEN_CMD="${GEN_CMD} -a \"profileTTL=${LDAP_PROFILE_TTL}\""
5293    [ -n "$LDAP_BIND_LIMIT" ] && \
5294	GEN_CMD="${GEN_CMD} -a \"bindTimeLimit=${LDAP_BIND_LIMIT}\""
5295    [ -n "$LDAP_PREF_SRVLIST" ] && \
5296	GEN_CMD="${GEN_CMD} -a \"preferredServerList=${LDAP_PREF_SRVLIST}\""
5297    [ -n "$LDAP_SRV_AUTHMETHOD_PAM" ] && \
5298	GEN_CMD="${GEN_CMD} -a \"serviceAuthenticationMethod=${LDAP_SRV_AUTHMETHOD_PAM}\""
5299    [ -n "$LDAP_SRV_AUTHMETHOD_KEY" ] && \
5300	GEN_CMD="${GEN_CMD} -a \"serviceAuthenticationMethod=${LDAP_SRV_AUTHMETHOD_KEY}\""
5301    [ -n "$LDAP_SRV_AUTHMETHOD_CMD" ] && \
5302	GEN_CMD="${GEN_CMD} -a \"serviceAuthenticationMethod=${LDAP_SRV_AUTHMETHOD_CMD}\""
5303
5304    # Check if there are any service search descriptors to ad.
5305    if [ -s "${SSD_FILE}" ]; then
5306	ssd_2_profile
5307    fi
5308
5309    # Execute "ldapclient genprofile" to create profile.
5310    eval ${GEN_CMD} > ${TMPDIR}/gen_profile 2> ${TMPDIR}/gen_profile_ERR
5311    if [ $? -ne 0 ]; then
5312	${ECHO} "  ERROR: ldapclient genprofile failed!"
5313	cleanup
5314	exit 1
5315    fi
5316
5317    # Add the generated profile..
5318    ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/gen_profile ${VERB}"
5319    if [ $? -ne 0 ]; then
5320	${ECHO} "  ERROR: Attempt to add profile failed!"
5321	cleanup
5322	exit 1
5323    fi
5324
5325    # Display message that schema is updated.
5326    ${ECHO} "  ${STEP}. Generated client profile and loaded on server."
5327    STEP=`expr $STEP + 1`
5328}
5329
5330
5331#
5332# cleanup(): Remove the TMPDIR and all files in it.
5333#
5334cleanup()
5335{
5336    [ $DEBUG -eq 1 ] && ${ECHO} "In cleanup()"
5337
5338    rm -fr ${TMPDIR}
5339}
5340
5341
5342#
5343# 			* * * MAIN * * *
5344#
5345# Description:
5346# This script assumes that the iPlanet Directory Server (iDS) is
5347# installed and that setup has been run.  This script takes the
5348# iDS server from that point and sets up the infrastructure for
5349# LDAP Naming Services.  After running this script, ldapaddent(1M)
5350# or some other tools can be used to populate data.
5351
5352# Initialize the variables that need to be set to NULL, or some
5353# other initial value before the rest of the functions can be called.
5354init
5355
5356# Parse command line arguments.
5357parse_arg $*
5358shift $?
5359
5360# Print extra line to separate from prompt.
5361${ECHO} " "
5362
5363# Either Load the user specified config file
5364# or prompt user for config info.
5365if [ -n "$INPUT_FILE" ]
5366then
5367    load_config_file
5368    INTERACTIVE=0      # Turns off prompts that occur later.
5369    validate_info      # Validate basic info in file.
5370    chk_ids_version    # Check iDS version for compatibility.
5371    gssapi_setup_auto
5372else
5373    # Display BACKUP warning to user.
5374    display_msg backup_server
5375    get_confirm "Do you wish to continue with server setup (y/n/h)?" "n" "backup_help"
5376    if [ $? -eq 0 ]; then    # if No, cleanup and exit.
5377	cleanup ; exit 1
5378    fi
5379
5380    # Prompt for values.
5381    prompt_config_info
5382    display_summary    # Allow user to modify results.
5383    INTERACTIVE=1      # Insures future prompting.
5384fi
5385
5386# Modify slapd.oc.conf to ALLOW cn instead of REQUIRE.
5387modify_cn
5388
5389# Modify timelimit to user value.
5390[ $NEED_TIME -eq 1 ] && modify_timelimit
5391
5392# Modify sizelimit to user value.
5393[ $NEED_SIZE -eq 1 ] && modify_sizelimit
5394
5395# Modify the password storage scheme to support CRYPT.
5396if [ "$NEED_CRYPT" = "TRUE" ]; then
5397    modify_pwd_crypt
5398fi
5399
5400# Update the schema (Attributes, Objectclass Definitions)
5401if [ ${SCHEMA_UPDATED} -eq 0 ]; then
5402        update_schema_attr
5403        update_schema_obj
5404fi
5405
5406# Add suffix together with its root entry (if needed)
5407add_suffix ||
5408{
5409	cleanup
5410	exit 1
5411}
5412
5413# Add base objects (if needed)
5414add_base_objects
5415
5416# Update the NisDomainObject.
5417#   The Base DN might of just been created, so this MUST happen after
5418#   the base objects have been added!
5419set_nisdomain
5420
5421# Add top level classes (new containers)
5422add_new_containers
5423
5424# Add common nismaps.
5425add_auto_maps
5426
5427# Modify top ACI.
5428modify_top_aci
5429
5430# Add Access Control Information for VLV.
5431add_vlv_aci
5432
5433# if Proxy needed, Add Proxy Agent and give read permission for password.
5434if [ $NEED_PROXY -eq 1 ]; then
5435    add_proxyagent
5436    if [ "$LDAP_ENABLE_SHADOW_UPDATE" != "TRUE" ]; then
5437	allow_proxy_read_pw
5438    fi
5439fi
5440
5441# If admin needed for shadow update, Add the administrator identity and
5442# give read/write permission for shadow, and deny all others read/write
5443# access to it.
5444if [ $NEED_ADMIN -eq 1 ]; then
5445    add_admin
5446    allow_admin_read_write_shadow
5447    # deny non-admin access to shadow data
5448    deny_non_admin_shadow_access
5449fi
5450
5451# If use host principal for shadow update, give read/write permission for
5452# shadow, and deny all others' read/write access to it.
5453if [ $NEED_HOSTACL -eq 1 ]; then
5454    allow_host_read_write_shadow
5455    # deny non-host access to shadow data
5456    deny_non_host_shadow_access
5457fi
5458
5459
5460# Generate client profile and add it to the server.
5461add_profile
5462
5463# Add Indexes to improve Search Performance.
5464add_eq_indexes
5465add_sub_indexes
5466add_vlv_indexes
5467
5468# Display setup complete message
5469display_msg setup_complete
5470
5471# Display VLV index commands to be executed on server.
5472display_vlv_cmds
5473
5474# Create config file if requested.
5475[ -n "$OUTPUT_FILE" ] && create_config_file
5476
5477# Removed the TMPDIR and all files in it.
5478cleanup
5479
5480exit 0
5481# end of MAIN.
5482