xref: /illumos-gate/usr/src/cmd/ldap/ns_ldap/idsconfig.sh (revision b31b5de1357c915fe7dab4d9646d9d84f9fe69bc)
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
983    DOM=""              # Set to NULL
984    # If DNS domain (resolv.conf) exists use that, otherwise use domainname.
985    if [ -f /etc/resolv.conf ]; then
986        DOM=`/usr/xpg4/bin/grep -i -E '^domain|^search' /etc/resolv.conf \
987	    | awk '{ print $2 }' | tail -1`
988    fi
989
990    # If for any reason the DOM did not get set (error'd resolv.conf) set
991    # DOM to the domainname command's output.
992    if [ "$DOM" = "" ]; then
993        DOM=`domainname`	# domain from domainname command.
994    fi
995
996    STEP=1
997    INTERACTIVE=1       # 0 = on, 1 = off (For input file mode)
998    DEL_OLD_PROFILE=0   # 0 (default), 1 = delete old profile.
999
1000    # idsconfig specific variables.
1001    INPUT_FILE=""
1002    OUTPUT_FILE=""
1003    LDAP_ENABLE_SHADOW_UPDATE="FALSE"
1004    NEED_PROXY=0        # 0 = No Proxy,    1 = Create Proxy.
1005    NEED_ADMIN=0        # 0 = No Admin,    1 = Create Admin.
1006    NEED_HOSTACL=0      # 0 = No Host ACL, 1 = Create Host ACL.
1007    EXISTING_PROFILE=0
1008    LDAP_PROXYAGENT=""
1009    LDAP_ADMINDN=""
1010    LDAP_SUFFIX=""
1011    LDAP_DOMAIN=$DOM	# domainname on Server (default value)
1012    GEN_CMD=""
1013
1014    # LDAP COMMANDS
1015    LDAPSEARCH="/bin/ldapsearch -r"
1016    LDAPMODIFY=/bin/ldapmodify
1017    LDAPADD=/bin/ldapadd
1018    LDAPDELETE=/bin/ldapdelete
1019    LDAP_GEN_PROFILE=/usr/sbin/ldap_gen_profile
1020
1021    # iDS specific information
1022    IDS_SERVER=""
1023    IDS_PORT=389
1024    NEED_TIME=0
1025    NEED_SIZE=0
1026    NEED_SRVAUTH_PAM=0
1027    NEED_SRVAUTH_KEY=0
1028    NEED_SRVAUTH_CMD=0
1029    IDS_TIMELIMIT=""
1030    IDS_SIZELIMIT=""
1031
1032    # LDAP PROFILE related defaults
1033    LDAP_ROOTDN="cn=Directory Manager"   # Provide common default.
1034    LDAP_ROOTPWD=""                      # NULL passwd as default (i.e. invalid)
1035    LDAP_PROFILE_NAME="default"
1036    LDAP_BASEDN=""
1037    LDAP_SERVER_LIST=""
1038    LDAP_AUTHMETHOD=""
1039    LDAP_FOLLOWREF="FALSE"
1040    NEED_CRYPT=""
1041    LDAP_SEARCH_SCOPE="one"
1042    LDAP_SRV_AUTHMETHOD_PAM=""
1043    LDAP_SRV_AUTHMETHOD_KEY=""
1044    LDAP_SRV_AUTHMETHOD_CMD=""
1045    LDAP_SEARCH_TIME_LIMIT=30
1046    LDAP_PREF_SRVLIST=""
1047    LDAP_PROFILE_TTL=43200
1048    LDAP_CRED_LEVEL="proxy"
1049    LDAP_BIND_LIMIT=10
1050
1051    # Prevent new files from being read by group or others.
1052    umask 077
1053
1054    # Service Search Descriptors
1055    LDAP_SERV_SRCH_DES=""
1056
1057    # Set and create TMPDIR.
1058    TMPDIR="/tmp/idsconfig.${PID}"
1059    if mkdir -m 700 ${TMPDIR}
1060    then
1061	# Cleanup on exit.
1062	trap 'rm -rf ${TMPDIR}; /usr/bin/stty echo; exit' 1 2 3 6 15
1063    else
1064	echo "ERROR: unable to create a safe temporary directory."
1065	exit 1
1066    fi
1067    LDAP_ROOTPWF=${TMPDIR}/rootPWD
1068
1069    # Set the SSD file name after setting TMPDIR.
1070    SSD_FILE=${TMPDIR}/ssd_list
1071
1072    # GSSAPI setup
1073    LDAP_KRB_REALM=""
1074    LDAP_GSSAPI_PROFILE=""
1075    SCHEMA_UPDATED=0
1076
1077    export DEBUG VERB ECHO EVAL EGREP GREP STEP TMPDIR
1078    export IDS_SERVER IDS_PORT LDAP_ROOTDN LDAP_ROOTPWD LDAP_SERVER_LIST
1079    export LDAP_BASEDN LDAP_ROOTPWF
1080    export LDAP_DOMAIN LDAP_SUFFIX LDAP_PROXYAGENT LDAP_PROXYAGENT_CRED
1081    export NEED_PROXY
1082    export LDAP_ENABLE_SHADOW_UPDATE LDAP_ADMINDN LDAP_ADMIN_CRED
1083    export NEED_ADMIN NEED_HOSTACL EXISTING_PROFILE
1084    export LDAP_PROFILE_NAME LDAP_BASEDN LDAP_SERVER_LIST
1085    export LDAP_AUTHMETHOD LDAP_FOLLOWREF LDAP_SEARCH_SCOPE LDAP_SEARCH_TIME_LIMIT
1086    export LDAP_PREF_SRVLIST LDAP_PROFILE_TTL LDAP_CRED_LEVEL LDAP_BIND_LIMIT
1087    export NEED_SRVAUTH_PAM NEED_SRVAUTH_KEY NEED_SRVAUTH_CMD
1088    export LDAP_SRV_AUTHMETHOD_PAM LDAP_SRV_AUTHMETHOD_KEY LDAP_SRV_AUTHMETHOD_CMD
1089    export LDAP_SERV_SRCH_DES SSD_FILE
1090    export GEN_CMD LDAP_KRB_REALM LDAP_GSSAPI_PROFILE SCHEMA_UPDATED
1091}
1092
1093
1094#
1095# disp_full_debug(): List of all debug variables usually interested in.
1096#                    Grouped to avoid MASSIVE code duplication.
1097#
1098disp_full_debug()
1099{
1100    [ $DEBUG -eq 1 ] && ${ECHO} "  IDS_SERVER = $IDS_SERVER"
1101    [ $DEBUG -eq 1 ] && ${ECHO} "  IDS_PORT = $IDS_PORT"
1102    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_ROOTDN = $LDAP_ROOTDN"
1103    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_ROOTPWD = $LDAP_ROOTPWD"
1104    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_DOMAIN = $LDAP_DOMAIN"
1105    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SUFFIX = $LDAP_SUFFIX"
1106    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_BASEDN = $LDAP_BASEDN"
1107    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_PROFILE_NAME = $LDAP_PROFILE_NAME"
1108    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SERVER_LIST = $LDAP_SERVER_LIST"
1109    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_PREF_SRVLIST = $LDAP_PREF_SRVLIST"
1110    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SEARCH_SCOPE = $LDAP_SEARCH_SCOPE"
1111    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_CRED_LEVEL = $LDAP_CRED_LEVEL"
1112    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_AUTHMETHOD = $LDAP_AUTHMETHOD"
1113    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_FOLLOWREF = $LDAP_FOLLOWREF"
1114    [ $DEBUG -eq 1 ] && ${ECHO} "  IDS_TIMELIMIT = $IDS_TIMELIMIT"
1115    [ $DEBUG -eq 1 ] && ${ECHO} "  IDS_SIZELIMIT = $IDS_SIZELIMIT"
1116    [ $DEBUG -eq 1 ] && ${ECHO} "  NEED_CRYPT = $NEED_CRYPT"
1117    [ $DEBUG -eq 1 ] && ${ECHO} "  NEED_SRVAUTH_PAM = $NEED_SRVAUTH_PAM"
1118    [ $DEBUG -eq 1 ] && ${ECHO} "  NEED_SRVAUTH_KEY = $NEED_SRVAUTH_KEY"
1119    [ $DEBUG -eq 1 ] && ${ECHO} "  NEED_SRVAUTH_CMD = $NEED_SRVAUTH_CMD"
1120    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SRV_AUTHMETHOD_PAM = $LDAP_SRV_AUTHMETHOD_PAM"
1121    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SRV_AUTHMETHOD_KEY = $LDAP_SRV_AUTHMETHOD_KEY"
1122    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SRV_AUTHMETHOD_CMD = $LDAP_SRV_AUTHMETHOD_CMD"
1123    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SEARCH_TIME_LIMIT = $LDAP_SEARCH_TIME_LIMIT"
1124    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_PROFILE_TTL = $LDAP_PROFILE_TTL"
1125    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_BIND_LIMIT = $LDAP_BIND_LIMIT"
1126    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_ENABLE_SHADOW_UPDATE = $LDAP_ENABLE_SHADOW_UPDATE"
1127
1128    # Only display proxy stuff if needed.
1129    [ $DEBUG -eq 1 ] && ${ECHO} "  NEED_PROXY = $NEED_PROXY"
1130    if [ $NEED_PROXY -eq  1 ]; then
1131	[ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_PROXYAGENT = $LDAP_PROXYAGENT"
1132	[ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_PROXYAGENT_CRED = $LDAP_PROXYAGENT_CRED"
1133    fi
1134
1135    # Only display admin credential if needed.
1136    [ $DEBUG -eq 1 ] && ${ECHO} "  NEED_ADMIN = $NEED_ADMIN"
1137    [ $DEBUG -eq 1 ] && ${ECHO} "  NEED_HOSTACL = $NEED_HOSTACL"
1138    if [ $NEED_ADMIN -eq  1 ]; then
1139	[ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_ADMINDN = $LDAP_ADMINDN"
1140	[ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_ADMIN_CRED = $LDAP_ADMIN_CRED"
1141    fi
1142
1143    # Service Search Descriptors are a special case.
1144    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SERV_SRCH_DES = $LDAP_SERV_SRCH_DES"
1145}
1146
1147
1148#
1149# load_config_file(): Loads the config file.
1150#
1151load_config_file()
1152{
1153    [ $DEBUG -eq 1 ] && ${ECHO} "In load_config_file()"
1154
1155    # Remove SSD lines from input file before sourcing.
1156    # The SSD lines must be removed because some forms of the
1157    # data could cause SHELL errors.
1158    ${GREP} -v "LDAP_SERV_SRCH_DES=" ${INPUT_FILE} > ${TMPDIR}/inputfile.noSSD
1159
1160    # Source the input file.
1161    . ${TMPDIR}/inputfile.noSSD
1162
1163    # If LDAP_SUFFIX is no set, try to utilize LDAP_TREETOP since older
1164    # config files use LDAP_TREETOP
1165    LDAP_SUFFIX="${LDAP_SUFFIX:-$LDAP_TREETOP}"
1166
1167    # Save password to temporary file.
1168    save_password
1169
1170    # Create the SSD file.
1171    create_ssd_file
1172
1173    # Display FULL debugging info.
1174    disp_full_debug
1175}
1176
1177#
1178# save_password(): Save password to temporary file.
1179#
1180save_password()
1181{
1182    cat > ${LDAP_ROOTPWF} <<EOF
1183${LDAP_ROOTPWD}
1184EOF
1185}
1186
1187######################################################################
1188# FUNCTIONS  FOR prompt_config_info() START HERE.
1189######################################################################
1190
1191#
1192# get_ids_server(): Prompt for iDS server name.
1193#
1194get_ids_server()
1195{
1196    while :
1197    do
1198	# Prompt for server name.
1199	get_ans "Enter the JES Directory Server's  hostname to setup:" "$IDS_SERVER"
1200	IDS_SERVER="$ANS"
1201
1202	# Ping server to see if live.  If valid break out of loop.
1203	ping $IDS_SERVER > /dev/null 2>&1
1204	if [ $? -eq 0 ]; then
1205	    break
1206	fi
1207
1208	# Invalid server, enter a new name.
1209	${ECHO} "ERROR: Server '${IDS_SERVER}' is invalid or unreachable."
1210	IDS_SERVER=""
1211    done
1212
1213    # Set SERVER_ARGS and LDAP_ARGS since values might of changed.
1214    SERVER_ARGS="-h ${IDS_SERVER} -p ${IDS_PORT}"
1215    LDAP_ARGS="${SERVER_ARGS} ${AUTH_ARGS}"
1216    export SERVER_ARGS
1217
1218}
1219
1220#
1221# get_ids_port(): Prompt for iDS port number.
1222#
1223get_ids_port()
1224{
1225    # Get a valid iDS port number.
1226    while :
1227    do
1228	# Enter port number.
1229	get_number "Enter the port number for iDS (h=help):" "$IDS_PORT" "port_help"
1230	IDS_PORT=$ANS
1231	# Do a simple search to check hostname and port number.
1232	# If search returns SUCCESS, break out, host and port must
1233	# be valid.
1234	${LDAPSEARCH} -h ${IDS_SERVER} -p ${IDS_PORT} -b "" -s base "objectclass=*" > /dev/null 2>&1
1235	if [ $? -eq 0 ]; then
1236	    break
1237	fi
1238
1239	# Invalid host/port pair, Re-enter.
1240	${ECHO} "ERROR: Invalid host or port: ${IDS_SERVER}:${IDS_PORT}, Please re-enter!"
1241	get_ids_server
1242    done
1243
1244    # Set SERVER_ARGS and LDAP_ARGS since values might of changed.
1245    SERVER_ARGS="-h ${IDS_SERVER} -p ${IDS_PORT}"
1246    LDAP_ARGS="${SERVER_ARGS} ${AUTH_ARGS}"
1247    export SERVER_ARGS
1248}
1249
1250
1251#
1252# chk_ids_version(): Read the slapd config file and set variables
1253#
1254chk_ids_version()
1255{
1256    [ $DEBUG -eq 1 ] && ${ECHO} "In chk_ids_version()"
1257
1258    # check iDS version number.
1259    eval "${LDAPSEARCH} ${SERVER_ARGS} -b cn=monitor -s base \"objectclass=*\" version | ${GREP} \"^version=\" | cut -f2 -d'/' | cut -f1 -d' ' > ${TMPDIR}/checkDSver 2>&1"
1260    if [ $? -ne 0 ]; then
1261	${ECHO} "ERROR: Can not determine the version number of iDS!"
1262	exit 1
1263    fi
1264    IDS_VER=`cat ${TMPDIR}/checkDSver`
1265    IDS_MAJVER=`${ECHO} ${IDS_VER} | cut -f1 -d.`
1266    IDS_MINVER=`${ECHO} ${IDS_VER} | cut -f2 -d.`
1267    if [ "${IDS_MAJVER}" != "5" ] && [ "${IDS_MAJVER}" != "6" ]; then
1268	${ECHO} "ERROR: $PROG only works with JES DS version 5.x and 6.x, not ${IDS_VER}."
1269    	exit 1
1270    fi
1271    if [ $DEBUG -eq 1 ]; then
1272	${ECHO} "  IDS_MAJVER = $IDS_MAJVER"
1273	${ECHO} "  IDS_MINVER = $IDS_MINVER"
1274    fi
1275}
1276
1277
1278#
1279# get_dirmgr_dn(): Get the directory manger DN.
1280#
1281get_dirmgr_dn()
1282{
1283    get_ans "Enter the directory manager DN:" "$LDAP_ROOTDN"
1284    LDAP_ROOTDN=$ANS
1285
1286    # Update ENV variables using DN.
1287    AUTH_ARGS="-D \"${LDAP_ROOTDN}\" -j ${LDAP_ROOTPWF}"
1288    LDAP_ARGS="${SERVER_ARGS} ${AUTH_ARGS}"
1289    export AUTH_ARGS LDAP_ARGS
1290}
1291
1292
1293#
1294# get_dirmgr_pw(): Get the Root DN passwd. (Root DN found in slapd.conf)
1295#
1296get_dirmgr_pw()
1297{
1298    while :
1299    do
1300	# Get passwd.
1301	get_passwd_nochk "Enter passwd for ${LDAP_ROOTDN} :"
1302	LDAP_ROOTPWD=$ANS
1303
1304	# Store password in file.
1305	save_password
1306
1307	# Update ENV variables using DN's PW.
1308	AUTH_ARGS="-D \"${LDAP_ROOTDN}\" -j ${LDAP_ROOTPWF}"
1309	LDAP_ARGS="${SERVER_ARGS} ${AUTH_ARGS}"
1310	export AUTH_ARGS LDAP_ARGS
1311
1312	# Verify that ROOTDN and ROOTPWD are valid.
1313	eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"\" -s base \"objectclass=*\" > ${TMPDIR}/checkDN 2>&1"
1314	if [ $? -ne 0 ]; then
1315	    eval "${GREP} credential ${TMPDIR}/checkDN ${VERB}"
1316	    if [ $? -eq 0 ]; then
1317		${ECHO} "ERROR: Root DN passwd is invalid."
1318	    else
1319		${ECHO} "ERROR: Invalid Root DN <${LDAP_ROOTDN}>."
1320		get_dirmgr_dn
1321	    fi
1322	else
1323	    break         # Both are valid.
1324	fi
1325    done
1326
1327
1328}
1329
1330
1331#
1332# get_domain(): Get the Domain that will be served by the LDAP server.
1333#               $1 - Help argument.
1334#
1335get_domain()
1336{
1337    # Use LDAP_DOMAIN as default.
1338    get_ans "Enter the domainname to be served (h=help):" $LDAP_DOMAIN
1339
1340    # Check domainname, and have user re-enter if not valid.
1341    check_domainname $ANS
1342    while [ $? -ne 0 ]
1343    do
1344	case "$ANS" in
1345	    [Hh] | help | Help | \?) display_msg ${1:-sorry} ;;
1346	    * ) ${ECHO} "Invalid domainname: \"${ANS}\"."
1347	     ;;
1348	esac
1349	get_ans "Enter domainname to be served (h=help):" $DOM
1350
1351	check_domainname $ANS
1352    done
1353
1354    # Set the domainname to valid name.
1355    LDAP_DOMAIN=$ANS
1356}
1357
1358
1359#
1360# get_basedn(): Query for the Base DN.
1361#
1362get_basedn()
1363{
1364    # Set the $_DOM_2_DC and assign to LDAP_BASEDN as default.
1365    # Then call get_basedn().  This method remakes the default
1366    # each time just in case the domain changed.
1367    domain_2_dc $LDAP_DOMAIN
1368    LDAP_BASEDN=$_DOM_2_DC
1369
1370    # Get Base DN.
1371    while :
1372    do
1373	get_ans_req "Enter LDAP Base DN (h=help):" "${_DOM_2_DC}"
1374	check_baseDN "$ANS"
1375	while [ $? -ne 0 ]
1376	do
1377	    case "$ANS" in
1378		[Hh] | help | Help | \?) display_msg basedn_help ;;
1379		* ) ${ECHO} "Invalid base DN: \"${ANS}\"."
1380		;;
1381	    esac
1382
1383	    # Re-Enter the BaseDN
1384	    get_ans_req "Enter LDAP Base DN (h=help):" "${_DOM_2_DC}"
1385	    check_baseDN "$ANS"
1386	done
1387
1388	# Set base DN and check its suffix
1389	LDAP_BASEDN=${ANS}
1390	check_basedn_suffix ||
1391	{
1392		cleanup
1393		exit 1
1394	}
1395
1396	# suffix may need to be created, in that case get suffix from user
1397	[ -n "${NEED_CREATE_SUFFIX}" ] &&
1398	{
1399		get_suffix || continue
1400	}
1401
1402	# suffix is ok, break out of the base dn inquire loop
1403	break
1404    done
1405}
1406
1407#
1408# get_want_shadow_update(): Ask user if want to enable shadow update?
1409#
1410get_want_shadow_update()
1411{
1412    MSG="Do you want to enable shadow update (y/n/h)?"
1413    get_confirm "$MSG" "n" "enable_shadow_update_help"
1414    if [ $? -eq 1 ]; then
1415	LDAP_ENABLE_SHADOW_UPDATE="TRUE"
1416    else
1417	LDAP_ENABLE_SHADOW_UPDATE="FALSE"
1418    fi
1419}
1420
1421get_krb_realm() {
1422
1423    # To upper cases
1424    LDAP_KRB_REALM=`${ECHO} ${LDAP_DOMAIN} | ${NAWK} '{ print toupper($0) }'`
1425    get_ans_req "Enter Kerberos Realm:" "$LDAP_KRB_REALM"
1426    # To upper cases
1427    LDAP_KRB_REALM=`${ECHO} ${ANS} | ${NAWK} '{ print toupper($0) }'`
1428}
1429
1430# $1: DN
1431# $2: ldif file
1432add_entry_by_DN() {
1433
1434    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${1}\" -s base \"objectclass=*\" ${VERB}"
1435    if [ $? -eq 0 ]; then
1436	    ${ECHO} "  ${1} already exists"
1437	    return 0
1438    else
1439	${EVAL} "${LDAPADD} ${LDAP_ARGS} -f ${2} ${VERB}"
1440	if [ $? -eq 0 ]; then
1441		${ECHO} "  ${1} is added"
1442	    	return 0
1443	else
1444		${ECHO} "  ERROR: failed to add ${1}"
1445		return 1
1446	fi
1447    fi
1448
1449}
1450#
1451# Kerberos princiapl to DN mapping rules
1452#
1453# Add rules for host credentails and user credentials
1454#
1455add_id_mapping_rules() {
1456
1457    ${ECHO} "  Adding Kerberos principal to DN mapping rules..."
1458
1459    _C_DN="cn=GSSAPI,cn=identity mapping,cn=config"
1460    ( cat << EOF
1461dn: cn=GSSAPI,cn=identity mapping,cn=config
1462objectClass: top
1463objectClass: nsContainer
1464cn: GSSAPI
1465EOF
1466) > ${TMPDIR}/GSSAPI_container.ldif
1467
1468    add_entry_by_DN "${_C_DN}" "${TMPDIR}/GSSAPI_container.ldif"
1469    if [ $? -ne 0 ];
1470    then
1471    	${RM} ${TMPDIR}/GSSAPI_container.ldif
1472	return
1473    fi
1474
1475    _H_CN="host_auth_${LDAP_KRB_REALM}"
1476    _H_DN="cn=${_H_CN}, ${_C_DN}"
1477    ( cat << EOF
1478dn: ${_H_DN}
1479objectClass: top
1480objectClass: nsContainer
1481objectClass: dsIdentityMapping
1482objectClass: dsPatternMatching
1483cn: ${_H_CN}
1484dsMatching-pattern: \${Principal}
1485dsMatching-regexp: host\/(.*).${LDAP_DOMAIN}@${LDAP_KRB_REALM}
1486dsSearchBaseDN: ou=hosts,${LDAP_BASEDN}
1487dsSearchFilter: (&(objectClass=ipHost)(cn=\$1))
1488dsSearchScope: one
1489
1490EOF
1491) > ${TMPDIR}/${_H_CN}.ldif
1492
1493    add_entry_by_DN "${_H_DN}" "${TMPDIR}/${_H_CN}.ldif"
1494
1495    _U_CN="user_auth_${LDAP_KRB_REALM}"
1496    _U_DN="cn=${_U_CN}, ${_C_DN}"
1497    ( cat << EOF
1498dn: ${_U_DN}
1499objectClass: top
1500objectClass: nsContainer
1501objectClass: dsIdentityMapping
1502objectClass: dsPatternMatching
1503cn: ${_U_CN}
1504dsMatching-pattern: \${Principal}
1505dsMatching-regexp: (.*)@${LDAP_KRB_REALM}
1506dsMappedDN: uid=\$1,ou=People,${LDAP_BASEDN}
1507
1508EOF
1509) > ${TMPDIR}/${_U_CN}.ldif
1510
1511    add_entry_by_DN "${_U_DN}" "${TMPDIR}/${_U_CN}.ldif"
1512
1513}
1514
1515
1516#
1517# Modify ACL to allow root to read all the password and only self can read
1518# its own password when sasl/GSSAPI bind is used
1519#
1520modify_userpassword_acl_for_gssapi() {
1521
1522    _P_DN="ou=People,${LDAP_BASEDN}"
1523    _H_DN="ou=Hosts,${LDAP_BASEDN}"
1524    _P_ACI="self-read-pwd"
1525
1526    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${_P_DN}\" -s base \"objectclass=*\" > /dev/null 2>&1"
1527    if [ $? -ne 0 ]; then
1528	    ${ECHO} "  ${_P_DN} does not exist"
1529	# Not Found. Create a new entry
1530	( cat << EOF
1531dn: ${_P_DN}
1532ou: People
1533objectClass: top
1534objectClass: organizationalUnit
1535EOF
1536) > ${TMPDIR}/gssapi_people.ldif
1537
1538	add_entry_by_DN "${_P_DN}" "${TMPDIR}/gssapi_people.ldif"
1539    else
1540	${ECHO} "  ${_P_DN} already exists"
1541    fi
1542
1543    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${_P_DN}\" -s base \"objectclass=*\" aci > ${TMPDIR}/chk_gssapi_aci 2>&1"
1544
1545    if [ $? -eq 0 ]; then
1546	    ${EVAL} "${GREP} ${_P_ACI} ${TMPDIR}/chk_gssapi_aci > /dev/null 2>&1"
1547	    if [ $? -eq 0 ]; then
1548		${ECHO} "  userpassword ACL ${_P_ACI} already exists."
1549		return
1550	    else
1551		${ECHO} "  userpassword ACL ${_P_ACI} not found. Create a new one."
1552	    fi
1553    else
1554	${ECHO} "  Error searching aci for ${_P_DN}"
1555	cat ${TMPDIR}/chk_gssapi_aci
1556	cleanup
1557	exit 1
1558    fi
1559    ( cat << EOF
1560dn: ${_P_DN}
1561changetype: modify
1562add: aci
1563aci: (targetattr="userPassword")(version 3.0; acl self-read-pwd; allow (read,search) userdn="ldap:///self" and authmethod="sasl GSSAPI";)
1564-
1565add: aci
1566aci: (targetattr="userPassword")(version 3.0; acl host-read-pwd; allow (read,search) userdn="ldap:///cn=*+ipHostNumber=*,ou=Hosts,${LDAP_BASEDN}" and authmethod="sasl GSSAPI";)
1567EOF
1568) > ${TMPDIR}/user_gssapi.ldif
1569    LDAP_TYPE_OR_VALUE_EXISTS=20
1570    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/user_gssapi.ldif ${VERB}"
1571
1572    case $? in
1573    0)
1574	${ECHO} "  ${_P_DN} uaserpassword ACL is updated."
1575	;;
1576    20)
1577	${ECHO} "  ${_P_DN} uaserpassword ACL already exists."
1578	;;
1579    *)
1580	${ECHO} "  ERROR: update of userpassword ACL for ${_P_DN} failed!"
1581	cleanup
1582	exit 1
1583	;;
1584    esac
1585}
1586#
1587# $1: objectclass or attributetyp
1588# $2: name
1589search_update_schema() {
1590
1591    ATTR="${1}es"
1592
1593    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b cn=schema -s base \"objectclass=*\" ${ATTR} | ${GREP} -i \"${2}\" ${VERB}"
1594    if [ $? -ne 0 ]; then
1595	${ECHO} "${1} ${2} does not exist."
1596        update_schema_attr
1597        update_schema_obj
1598	SCHEMA_UPDATED=1
1599    else
1600	${ECHO} "${1} ${2} already exists. Schema has been updated"
1601    fi
1602}
1603
1604#
1605# $1: 1 - interactive, 0 - no
1606#
1607create_gssapi_profile() {
1608
1609
1610    if [ ${1} -eq 1 ]; then
1611        echo
1612        echo "You can create a sasl/GSSAPI enabled profile with default values now."
1613        get_confirm "Do you want to create a sasl/GSSAPI default profile ?" "n"
1614
1615        if [ $? -eq 0 ]; then
1616	    return
1617        fi
1618    fi
1619
1620    # Add profile container if it does not exist
1621    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"ou=profile,${LDAP_BASEDN}\" -s base \"objectclass=*\" > /dev/null 2>&1"
1622    if [ $? -ne 0 ]; then
1623	( cat << EOF
1624dn: ou=profile,${LDAP_BASEDN}
1625ou: profile
1626objectClass: top
1627objectClass: organizationalUnit
1628EOF
1629) > ${TMPDIR}/profile_people.ldif
1630
1631        add_entry_by_DN "ou=profile,${LDAP_BASEDN}" "${TMPDIR}/profile_people.ldif"
1632
1633    fi
1634
1635    search_update_schema "objectclass" "DUAConfigProfile"
1636
1637    _P_NAME="gssapi_${LDAP_KRB_REALM}"
1638    if [ ${1} -eq 1 ]; then
1639    	_P_TMP=${LDAP_PROFILE_NAME}
1640    	LDAP_PROFILE_NAME=${_P_NAME}
1641   	get_profile_name
1642        LDAP_GSSAPI_PROFILE=${LDAP_PROFILE_NAME}
1643    	LDAP_PROFILE_NAME=${_P_TMP}
1644    fi
1645
1646    _P_DN="cn=${LDAP_GSSAPI_PROFILE},ou=profile,${LDAP_BASEDN}"
1647    if [ ${DEL_OLD_PROFILE} -eq 1 ]; then
1648	    DEL_OLD_PROFILE=0
1649	    ${EVAL} "${LDAPDELETE} ${LDAP_ARGS} ${_P_DN} ${VERB}"
1650    fi
1651
1652    _SVR=`getent hosts ${IDS_SERVER} | ${NAWK} '{ print $1 }'`
1653    if [ ${IDS_PORT} -ne 389 ]; then
1654	    _SVR="${_SVR}:${IDS_PORT}"
1655    fi
1656
1657    (cat << EOF
1658dn: ${_P_DN}
1659objectClass: top
1660objectClass: DUAConfigProfile
1661defaultServerList: ${_SVR}
1662defaultSearchBase: ${LDAP_BASEDN}
1663authenticationMethod: sasl/GSSAPI
1664followReferrals: ${LDAP_FOLLOWREF}
1665defaultSearchScope: ${LDAP_SEARCH_SCOPE}
1666searchTimeLimit: ${LDAP_SEARCH_TIME_LIMIT}
1667profileTTL: ${LDAP_PROFILE_TTL}
1668cn: ${LDAP_GSSAPI_PROFILE}
1669credentialLevel: self
1670bindTimeLimit: ${LDAP_BIND_LIMIT}
1671EOF
1672) > ${TMPDIR}/gssapi_profile.ldif
1673
1674    add_entry_by_DN "${_P_DN}" "${TMPDIR}/gssapi_profile.ldif"
1675
1676}
1677#
1678# Set up GSSAPI if necessary
1679#
1680gssapi_setup() {
1681
1682	# assume sasl/GSSAPI is supported by the ldap server and may be used
1683	GSSAPI_AUTH_MAY_BE_USED=1
1684	${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"\" -s base \"objectclass=*\" supportedSASLMechanisms | ${GREP} GSSAPI ${VERB}"
1685	if [ $? -ne 0 ]; then
1686		GSSAPI_AUTH_MAY_BE_USED=0
1687		${ECHO} "  sasl/GSSAPI is not supported by this LDAP server"
1688		return
1689	fi
1690
1691	get_confirm "GSSAPI is supported. Do you want to set up gssapi:(y/n)" "n"
1692	if [ $? -eq 0 ]; then
1693		${ECHO}
1694		${ECHO} "GSSAPI is not set up."
1695		${ECHO} "sasl/GSSAPI bind may not work if it's not set up first."
1696	else
1697		get_krb_realm
1698		add_id_mapping_rules
1699		modify_userpassword_acl_for_gssapi
1700		create_gssapi_profile 1
1701		${ECHO}
1702		${ECHO} "GSSAPI setup is done."
1703	fi
1704
1705	cat << EOF
1706
1707You can continue to create a profile and
1708configure the LDAP server.
1709Or you can stop now.
1710
1711EOF
1712	get_confirm "Do you want to stop:(y/n)" "n"
1713	if [ $? -eq 1 ]; then
1714		cleanup
1715		exit
1716	fi
1717
1718}
1719gssapi_setup_auto() {
1720	GSSAPI_AUTH_MAY_BE_USED=0
1721	${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"\" -s base \"objectclass=*\" supportedSASLMechanisms | ${GREP} GSSAPI ${VERB}"
1722	if [ $? -ne 0 ]; then
1723		${ECHO}
1724		${ECHO} "sasl/GSSAPI is not supported by this LDAP server"
1725		${ECHO}
1726		return
1727	fi
1728	if [ -z "${LDAP_KRB_REALM}" ]; then
1729		${ECHO}
1730		${ECHO} "LDAP_KRB_REALM is not set. Skip gssapi setup."
1731		${ECHO} "sasl/GSSAPI bind won't work properly."
1732		${ECHO}
1733		return
1734	fi
1735	GSSAPI_AUTH_MAY_BE_USED=1
1736	if [ -z "${LDAP_GSSAPI_PROFILE}" ]; then
1737		${ECHO}
1738		${ECHO} "LDAP_GSSAPI_PROFILE is not set. Default is gssapi_${LDAP_KRB_REALM}"
1739		${ECHO}
1740		LDAP_GSSAPI_PROFILE="gssapi_${LDAP_KRB_REALM}"
1741	fi
1742	add_id_mapping_rules
1743	modify_userpassword_acl_for_gssapi
1744	create_gssapi_profile 0
1745}
1746# get_profile_name(): Enter the profile name.
1747#
1748get_profile_name()
1749{
1750    # Reset Delete Old Profile since getting new profile name.
1751    DEL_OLD_PROFILE=0
1752
1753    # Loop until valid profile name, or replace.
1754    while :
1755    do
1756	# Prompt for profile name.
1757	get_ans "Enter the profile name (h=help):" "$LDAP_PROFILE_NAME"
1758
1759	# Check for Help.
1760	case "$ANS" in
1761	    [Hh] | help | Help | \?) display_msg profile_help
1762				     continue ;;
1763	    * )  ;;
1764	esac
1765
1766	# Search to see if profile name already exists.
1767	eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${ANS},ou=profile,${LDAP_BASEDN}\" -s base \"objectclass=*\" ${VERB}"
1768	if [ $? -eq 0 ]; then
1769
1770	    cat << EOF
1771
1772Profile '${ANS}' already exists, it is possible to enable
1773shadow update now. idsconfig will exit after shadow update
1774is enabled. You can also continue to overwrite the profile 
1775or create a new one and be given the chance to enable
1776shadow update later.
1777
1778EOF
1779
1780	    MSG="Just enable shadow update (y/n/h)?"
1781	    get_confirm "$MSG" "n" "enable_shadow_update_help"
1782	    if [ $? -eq 1 ]; then
1783	        [ $DEBUG -eq 1 ] && ${ECHO} "set up shadow update"
1784	        LDAP_ENABLE_SHADOW_UPDATE=TRUE
1785		# display alternate messages
1786		EXISTING_PROFILE=1
1787	        # Set Profile Name.
1788	        LDAP_PROFILE_NAME=$ANS
1789	        return 0  # set up credentials for shadow update.
1790	    fi
1791
1792	    get_confirm_nodef "Are you sure you want to overwrite profile cn=${ANS}?"
1793	    if [ $? -eq 1 ]; then
1794		DEL_OLD_PROFILE=1
1795		return 0  # Replace old profile name.
1796	    else
1797		${ECHO} "Please re-enter a new profile name."
1798	    fi
1799	else
1800	    break  # Unique profile name.
1801	fi
1802    done
1803
1804    # Set Profile Name.
1805    LDAP_PROFILE_NAME=$ANS
1806}
1807
1808
1809#
1810# get_srv_list(): Get the default server list.
1811#
1812get_srv_list()
1813{
1814    # If LDAP_SERVER_LIST is NULL, then set, otherwise leave alone.
1815    if [ -z "${LDAP_SERVER_LIST}" ]; then
1816	LDAP_SERVER_LIST=`getent hosts ${IDS_SERVER} | awk '{print $1}'`
1817        if [ ${IDS_PORT} -ne 389 ]; then
1818	    LDAP_SERVER_LIST="${LDAP_SERVER_LIST}:${IDS_PORT}"
1819	fi
1820    fi
1821
1822    # Prompt for new LDAP_SERVER_LIST.
1823    while :
1824    do
1825	get_ans "Default server list (h=help):" $LDAP_SERVER_LIST
1826
1827	# If help continue, otherwise break.
1828	case "$ANS" in
1829	    [Hh] | help | Help | \?) display_msg def_srvlist_help ;;
1830	    * ) break ;;
1831	esac
1832    done
1833    LDAP_SERVER_LIST=$ANS
1834}
1835
1836
1837#
1838# get_pref_srv(): The preferred server list (Overrides the server list)
1839#
1840get_pref_srv()
1841{
1842    while :
1843    do
1844	get_ans "Preferred server list (h=help):" $LDAP_PREF_SRVLIST
1845
1846	# If help continue, otherwise break.
1847	case "$ANS" in
1848	    [Hh] | help | Help | \?) display_msg pref_srvlist_help ;;
1849	    * ) break ;;
1850	esac
1851    done
1852    LDAP_PREF_SRVLIST=$ANS
1853}
1854
1855
1856#
1857# get_search_scope(): Get the search scope from the user.
1858#
1859get_search_scope()
1860{
1861    [ $DEBUG -eq 1 ] && ${ECHO} "In get_search_scope()"
1862
1863    _MENU_CHOICE=0
1864    while :
1865    do
1866	get_ans "Choose desired search scope (one, sub, h=help): " "one"
1867	_MENU_CHOICE=$ANS
1868	case "$_MENU_CHOICE" in
1869	    one) LDAP_SEARCH_SCOPE="one"
1870	       return 1 ;;
1871	    sub) LDAP_SEARCH_SCOPE="sub"
1872	       return 2 ;;
1873	    h) display_msg srch_scope_help ;;
1874	    *) ${ECHO} "Please enter \"one\", \"sub\", or \"h\"." ;;
1875	esac
1876    done
1877
1878}
1879
1880
1881#
1882# get_cred_level(): Function to display menu to user and get the
1883#                  credential level.
1884#
1885get_cred_level()
1886{
1887    [ $DEBUG -eq 1 ] && ${ECHO} "In get_cred_level()"
1888
1889    _MENU_CHOICE=0
1890    display_msg cred_level_menu
1891    while :
1892    do
1893	get_ans "Choose Credential level [h=help]:" "1"
1894	_MENU_CHOICE=$ANS
1895	case "$_MENU_CHOICE" in
1896	    1) LDAP_CRED_LEVEL="anonymous"
1897	       return 1 ;;
1898	    2) LDAP_CRED_LEVEL="proxy"
1899	       return 2 ;;
1900	    3) LDAP_CRED_LEVEL="proxy anonymous"
1901	       return 3 ;;
1902	    4) LDAP_CRED_LEVEL="self"
1903	       SELF_GSSAPI=1
1904	       return 4 ;;
1905	    5) LDAP_CRED_LEVEL="self proxy"
1906	       SELF_GSSAPI=1
1907	       return 5 ;;
1908	    6) LDAP_CRED_LEVEL="self proxy anonymous"
1909	       SELF_GSSAPI=1
1910	       return 6 ;;
1911	    h) display_msg cred_lvl_help ;;
1912	    *) ${ECHO} "Please enter 1, 2, 3, 4, 5 or 6." ;;
1913	esac
1914    done
1915}
1916
1917
1918#
1919# srvauth_menu_handler(): Enter the Service Authentication method.
1920#
1921srvauth_menu_handler()
1922{
1923    # Display Auth menu
1924    display_msg srvauth_method_menu
1925
1926    # Get a Valid choice.
1927    while :
1928    do
1929	# Display appropriate prompt and get answer.
1930	if [ $_FIRST -eq 1 ]; then
1931	    get_ans "Choose Service Authentication Method:" "1"
1932	else
1933	    get_ans "Choose Service Authentication Method (0=reset):"
1934	fi
1935
1936	# Determine choice.
1937	_MENU_CHOICE=$ANS
1938	case "$_MENU_CHOICE" in
1939	    1) _AUTHMETHOD="simple"
1940		break ;;
1941	    2) _AUTHMETHOD="sasl/DIGEST-MD5"
1942		break ;;
1943	    3) _AUTHMETHOD="tls:simple"
1944		break ;;
1945	    4) _AUTHMETHOD="tls:sasl/DIGEST-MD5"
1946		break ;;
1947	    5) _AUTHMETHOD="sasl/GSSAPI"
1948		break ;;
1949	    0) _AUTHMETHOD=""
1950		_FIRST=1
1951		break ;;
1952	    *) ${ECHO} "Please enter 1-5 or 0 to reset." ;;
1953	esac
1954    done
1955}
1956
1957
1958#
1959# auth_menu_handler(): Enter the Authentication method.
1960#
1961auth_menu_handler()
1962{
1963    # Display Auth menu
1964    display_msg auth_method_menu
1965
1966    # Get a Valid choice.
1967    while :
1968    do
1969	# Display appropriate prompt and get answer.
1970	if [ $_FIRST -eq 1 ]; then
1971	    get_ans "Choose Authentication Method (h=help):" "1"
1972	else
1973	    get_ans "Choose Authentication Method (0=reset, h=help):"
1974	fi
1975
1976	# Determine choice.
1977	_MENU_CHOICE=$ANS
1978	case "$_MENU_CHOICE" in
1979	    1) _AUTHMETHOD="none"
1980		break ;;
1981	    2) _AUTHMETHOD="simple"
1982		break ;;
1983	    3) _AUTHMETHOD="sasl/DIGEST-MD5"
1984		break ;;
1985	    4) _AUTHMETHOD="tls:simple"
1986		break ;;
1987	    5) _AUTHMETHOD="tls:sasl/DIGEST-MD5"
1988		break ;;
1989	    6) _AUTHMETHOD="sasl/GSSAPI"
1990		break ;;
1991	    0) _AUTHMETHOD=""
1992		_FIRST=1
1993		break ;;
1994	    h) display_msg auth_help ;;
1995	    *) ${ECHO} "Please enter 1-6, 0=reset, or h=help." ;;
1996	esac
1997    done
1998}
1999
2000
2001#
2002# get_auth(): Enter the Authentication method.
2003#
2004get_auth()
2005{
2006    [ $DEBUG -eq 1 ] && ${ECHO} "In get_auth()"
2007
2008    _FIRST=1          # Flag for first time.
2009    _MENU_CHOICE=0
2010    _AUTHMETHOD=""    # Tmp method.
2011
2012    while :
2013    do
2014	# Call Menu handler
2015	auth_menu_handler
2016
2017	# Add Auth Method to list.
2018        if [ $_FIRST -eq 1 ]; then
2019	    LDAP_AUTHMETHOD="${_AUTHMETHOD}"
2020	    _FIRST=0
2021	else
2022	    LDAP_AUTHMETHOD="${LDAP_AUTHMETHOD};${_AUTHMETHOD}"
2023	fi
2024
2025	# Display current Authentication Method.
2026	${ECHO} ""
2027	${ECHO} "Current authenticationMethod: ${LDAP_AUTHMETHOD}"
2028	${ECHO} ""
2029
2030	# Prompt for another Auth Method, or break out.
2031	get_confirm_nodef "Do you want to add another Authentication Method?"
2032	if [ $? -eq 0 ]; then
2033	    break;
2034	fi
2035    done
2036}
2037
2038
2039#
2040# get_followref(): Whether or not to follow referrals.
2041#
2042get_followref()
2043{
2044    get_confirm "Do you want the clients to follow referrals (y/n/h)?" "n" "referrals_help"
2045    if [ $? -eq 1 ]; then
2046	LDAP_FOLLOWREF="TRUE"
2047    else
2048	LDAP_FOLLOWREF="FALSE"
2049    fi
2050}
2051
2052
2053#
2054# get_timelimit(): Set the time limit. -1 is max time.
2055#
2056get_timelimit()
2057{
2058    # Get current timeout value from cn=config.
2059    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=config\" -s base \"objectclass=*\" nsslapd-timelimit > ${TMPDIR}/chk_timeout 2>&1"
2060    if [ $? -ne 0 ]; then
2061	${ECHO} "  ERROR: Could not reach LDAP server to check current timeout!"
2062	cleanup
2063	exit 1
2064    fi
2065    CURR_TIMELIMIT=`${GREP} timelimit ${TMPDIR}/chk_timeout | cut -f2 -d=`
2066
2067    get_negone_num "Enter the time limit for iDS (current=${CURR_TIMELIMIT}):" "-1"
2068    IDS_TIMELIMIT=$NUM
2069}
2070
2071
2072#
2073# get_sizelimit(): Set the size limit. -1 is max size.
2074#
2075get_sizelimit()
2076{
2077    # Get current sizelimit value from cn=config.
2078    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=config\" -s base \"objectclass=*\" nsslapd-sizelimit > ${TMPDIR}/chk_sizelimit 2>&1"
2079    if [ $? -ne 0 ]; then
2080	${ECHO} "  ERROR: Could not reach LDAP server to check current sizelimit!"
2081	cleanup
2082	exit 1
2083    fi
2084    CURR_SIZELIMIT=`${GREP} sizelimit ${TMPDIR}/chk_sizelimit | cut -f2 -d=`
2085
2086    get_negone_num "Enter the size limit for iDS (current=${CURR_SIZELIMIT}):" "-1"
2087    IDS_SIZELIMIT=$NUM
2088}
2089
2090
2091#
2092# get_want_crypt(): Ask user if want to store passwords in crypt?
2093#
2094get_want_crypt()
2095{
2096    get_confirm "Do you want to store passwords in \"crypt\" format (y/n/h)?" "n" "crypt_help"
2097    if [ $? -eq 1 ]; then
2098	NEED_CRYPT="TRUE"
2099    else
2100	NEED_CRYPT="FALSE"
2101    fi
2102}
2103
2104
2105#
2106# get_srv_authMethod_pam(): Get the Service Auth Method for pam_ldap from user.
2107#
2108#  NOTE: This function is base on get_auth().
2109#
2110get_srv_authMethod_pam()
2111{
2112    [ $DEBUG -eq 1 ] && ${ECHO} "In get_srv_authMethod_pam()"
2113
2114    _FIRST=1          # Flag for first time.
2115    _MENU_CHOICE=0
2116    _AUTHMETHOD=""    # Tmp method.
2117
2118    while :
2119    do
2120	# Call Menu handler
2121	srvauth_menu_handler
2122
2123	# Add Auth Method to list.
2124        if [ $_FIRST -eq 1 ]; then
2125	    if [ "$_AUTHMETHOD" = "" ]; then
2126		LDAP_SRV_AUTHMETHOD_PAM=""
2127	    else
2128		LDAP_SRV_AUTHMETHOD_PAM="pam_ldap:${_AUTHMETHOD}"
2129	    fi
2130	    _FIRST=0
2131	else
2132	    LDAP_SRV_AUTHMETHOD_PAM="${LDAP_SRV_AUTHMETHOD_PAM};${_AUTHMETHOD}"
2133	fi
2134
2135	# Display current Authentication Method.
2136	${ECHO} ""
2137	${ECHO} "Current authenticationMethod: ${LDAP_SRV_AUTHMETHOD_PAM}"
2138	${ECHO} ""
2139
2140	# Prompt for another Auth Method, or break out.
2141	get_confirm_nodef "Do you want to add another Authentication Method?"
2142	if [ $? -eq 0 ]; then
2143	    break;
2144	fi
2145    done
2146
2147    # Check in case user reset string and exited loop.
2148    if [ "$LDAP_SRV_AUTHMETHOD_PAM" = "" ]; then
2149	NEED_SRVAUTH_PAM=0
2150    fi
2151}
2152
2153
2154#
2155# get_srv_authMethod_key(): Get the Service Auth Method for keyserv from user.
2156#
2157#  NOTE: This function is base on get_auth().
2158#
2159get_srv_authMethod_key()
2160{
2161    [ $DEBUG -eq 1 ] && ${ECHO} "In get_srv_authMethod_key()"
2162
2163    _FIRST=1          # Flag for first time.
2164    _MENU_CHOICE=0
2165    _AUTHMETHOD=""    # Tmp method.
2166
2167    while :
2168    do
2169	# Call Menu handler
2170	srvauth_menu_handler
2171
2172	# Add Auth Method to list.
2173        if [ $_FIRST -eq 1 ]; then
2174	    if [ "$_AUTHMETHOD" = "" ]; then
2175		LDAP_SRV_AUTHMETHOD_KEY=""
2176	    else
2177		LDAP_SRV_AUTHMETHOD_KEY="keyserv:${_AUTHMETHOD}"
2178	    fi
2179	    _FIRST=0
2180	else
2181	    LDAP_SRV_AUTHMETHOD_KEY="${LDAP_SRV_AUTHMETHOD_KEY};${_AUTHMETHOD}"
2182	fi
2183
2184	# Display current Authentication Method.
2185	${ECHO} ""
2186	${ECHO} "Current authenticationMethod: ${LDAP_SRV_AUTHMETHOD_KEY}"
2187	${ECHO} ""
2188
2189	# Prompt for another Auth Method, or break out.
2190	get_confirm_nodef "Do you want to add another Authentication Method?"
2191	if [ $? -eq 0 ]; then
2192	    break;
2193	fi
2194    done
2195
2196    # Check in case user reset string and exited loop.
2197    if [ "$LDAP_SRV_AUTHMETHOD_KEY" = "" ]; then
2198	NEED_SRVAUTH_KEY=0
2199    fi
2200}
2201
2202
2203#
2204# get_srv_authMethod_cmd(): Get the Service Auth Method for passwd-cmd from user.
2205#
2206#  NOTE: This function is base on get_auth().
2207#
2208get_srv_authMethod_cmd()
2209{
2210    [ $DEBUG -eq 1 ] && ${ECHO} "In get_srv_authMethod_cmd()"
2211
2212    _FIRST=1          # Flag for first time.
2213    _MENU_CHOICE=0
2214    _AUTHMETHOD=""    # Tmp method.
2215
2216    while :
2217    do
2218	# Call Menu handler
2219	srvauth_menu_handler
2220
2221	# Add Auth Method to list.
2222        if [ $_FIRST -eq 1 ]; then
2223	    if [ "$_AUTHMETHOD" = "" ]; then
2224		LDAP_SRV_AUTHMETHOD_CMD=""
2225	    else
2226		LDAP_SRV_AUTHMETHOD_CMD="passwd-cmd:${_AUTHMETHOD}"
2227	    fi
2228	    _FIRST=0
2229	else
2230	    LDAP_SRV_AUTHMETHOD_CMD="${LDAP_SRV_AUTHMETHOD_CMD};${_AUTHMETHOD}"
2231	fi
2232
2233	# Display current Authentication Method.
2234	${ECHO} ""
2235	${ECHO} "Current authenticationMethod: ${LDAP_SRV_AUTHMETHOD_CMD}"
2236	${ECHO} ""
2237
2238	# Prompt for another Auth Method, or break out.
2239	get_confirm_nodef "Do you want to add another Authentication Method?"
2240	if [ $? -eq 0 ]; then
2241	    break;
2242	fi
2243    done
2244
2245    # Check in case user reset string and exited loop.
2246    if [ "$LDAP_SRV_AUTHMETHOD_CMD" = "" ]; then
2247	NEED_SRVAUTH_CMD=0
2248    fi
2249}
2250
2251
2252#
2253# get_srch_time(): Amount of time to search.
2254#
2255get_srch_time()
2256{
2257    get_negone_num "Client search time limit in seconds (h=help):" "$LDAP_SEARCH_TIME_LIMIT" "srchtime_help"
2258    LDAP_SEARCH_TIME_LIMIT=$NUM
2259}
2260
2261
2262#
2263# get_prof_ttl(): The profile time to live (TTL)
2264#
2265get_prof_ttl()
2266{
2267    get_negone_num "Profile Time To Live in seconds (h=help):" "$LDAP_PROFILE_TTL" "profttl_help"
2268    LDAP_PROFILE_TTL=$NUM
2269}
2270
2271
2272#
2273# get_bind_limit(): Bind time limit
2274#
2275get_bind_limit()
2276{
2277    get_negone_num "Bind time limit in seconds (h=help):" "$LDAP_BIND_LIMIT" "bindlim_help"
2278    LDAP_BIND_LIMIT=$NUM
2279}
2280
2281
2282######################################################################
2283# FUNCTIONS  FOR Service Search Descriptor's START HERE.
2284######################################################################
2285
2286
2287#
2288# add_ssd(): Get SSD's from user and add to file.
2289#
2290add_ssd()
2291{
2292    [ $DEBUG -eq 1 ] && ${ECHO} "In add_ssd()"
2293
2294    # Enter the service id.  Loop til unique.
2295    while :
2296    do
2297	get_ans "Enter the service id:"
2298	_SERV_ID=$ANS
2299
2300	# Grep for name existing.
2301	${GREP} -i "^$ANS:" ${SSD_FILE} > /dev/null 2>&1
2302	if [ $? -eq 1 ]; then
2303	    break
2304	fi
2305
2306	# Name exists, print message, let user decide.
2307	${ECHO} "ERROR: Service id ${ANS} already exists."
2308    done
2309
2310    get_ans "Enter the base:"
2311    _BASE=$ANS
2312
2313    # Get the scope and verify that its one or sub.
2314    while :
2315    do
2316	get_ans "Enter the scope:"
2317	_SCOPE=$ANS
2318	case `${ECHO} ${_SCOPE} | tr '[A-Z]' '[a-z]'` in
2319	    one) break ;;
2320	    sub) break ;;
2321	    *)   ${ECHO} "${_SCOPE} is Not valid - Enter 'one' or 'sub'" ;;
2322	esac
2323    done
2324
2325    # Build SSD to add to file.
2326    _SSD="${_SERV_ID}:${_BASE}?${_SCOPE}"
2327
2328    # Add the SSD to the file.
2329    ${ECHO} "${_SSD}" >> ${SSD_FILE}
2330}
2331
2332
2333#
2334# delete_ssd(): Delete a SSD from the list.
2335#
2336delete_ssd()
2337{
2338    [ $DEBUG -eq 1 ] && ${ECHO} "In delete_ssd()"
2339
2340    # Get service id name from user for SSD to delete.
2341    get_ans_req "Enter service id to delete:"
2342
2343    # Make sure service id exists.
2344    ${GREP} "$ANS" ${SSD_FILE} > /dev/null 2>&1
2345    if [ $? -eq 1 ]; then
2346	${ECHO} "Invalid service id: $ANS not present in list."
2347	return
2348    fi
2349
2350    # Create temporary back SSD file.
2351    cp ${SSD_FILE} ${SSD_FILE}.bak
2352    if [ $? -eq 1 ]; then
2353	${ECHO} "ERROR: could not create file: ${SSD_FILE}.bak"
2354	exit 1
2355    fi
2356
2357    # Use ${GREP} to remove the SSD.  Read from temp file
2358    # and write to the orig file.
2359    ${GREP} -v "$ANS" ${SSD_FILE}.bak > ${SSD_FILE}
2360}
2361
2362
2363#
2364# modify_ssd(): Allow user to modify a SSD.
2365#
2366modify_ssd()
2367{
2368    [ $DEBUG -eq 1 ] && ${ECHO} "In modify_ssd()"
2369
2370    # Prompt user for service id.
2371    get_ans_req "Enter service id to modify:"
2372
2373    # Put into temp _LINE.
2374    _LINE=`${GREP} "^$ANS:" ${SSD_FILE}`
2375    if [ "$_LINE" = "" ]; then
2376	${ECHO} "Invalid service id: $ANS"
2377	return
2378    fi
2379
2380    # Display current filter for user to see.
2381    ${ECHO} ""
2382    ${ECHO} "Current SSD: $_LINE"
2383    ${ECHO} ""
2384
2385    # Get the defaults.
2386    _CURR_BASE=`${ECHO} $_LINE | cut -d: -f2 | cut -d'?' -f 1`
2387    _CURR_SCOPE=`${ECHO} $_LINE | cut -d: -f2 | cut -d'?' -f 2`
2388
2389    # Create temporary back SSD file.
2390    cp ${SSD_FILE} ${SSD_FILE}.bak
2391    if [ $? -eq 1 ]; then
2392	${ECHO} "ERROR: could not create file: ${SSD_FILE}.bak"
2393	cleanup
2394	exit 1
2395    fi
2396
2397    # Removed the old line.
2398    ${GREP} -v "^$ANS:" ${SSD_FILE}.bak > ${SSD_FILE} 2>&1
2399
2400    # New Entry
2401    _SERV_ID=$ANS
2402    get_ans_req "Enter the base:" "$_CURR_BASE"
2403    _BASE=$ANS
2404    get_ans_req "Enter the scope:" "$_CURR_SCOPE"
2405    _SCOPE=$ANS
2406
2407    # Build the new SSD.
2408    _SSD="${_SERV_ID}:${_BASE}?${_SCOPE}"
2409
2410    # Add the SSD to the file.
2411    ${ECHO} "${_SSD}" >> ${SSD_FILE}
2412}
2413
2414
2415#
2416# display_ssd(): Display the current SSD list.
2417#
2418display_ssd()
2419{
2420    [ $DEBUG -eq 1 ] && ${ECHO} "In display_ssd()"
2421
2422    ${ECHO} ""
2423    ${ECHO} "Current Service Search Descriptors:"
2424    ${ECHO} "=================================="
2425    cat ${SSD_FILE}
2426    ${ECHO} ""
2427    ${ECHO} "Hit return to continue."
2428    read __A
2429}
2430
2431
2432#
2433# prompt_ssd(): Get SSD's from user.
2434#
2435prompt_ssd()
2436{
2437    [ $DEBUG -eq 1 ] && ${ECHO} "In prompt_ssd()"
2438    # See if user wants SSD's?
2439    get_confirm "Do you wish to setup Service Search Descriptors (y/n/h)?" "n" "ssd_help"
2440    [ "$?" -eq 0 ] && return
2441
2442    # Display menu for SSD choices.
2443    while :
2444    do
2445	display_msg prompt_ssd_menu
2446	get_ans "Enter menu choice:" "Quit"
2447	case "$ANS" in
2448	    [Aa] | add) add_ssd ;;
2449	    [Dd] | delete) delete_ssd ;;
2450	    [Mm] | modify) modify_ssd ;;
2451	    [Pp] | print | display) display_ssd ;;
2452	    [Xx] | reset | clear) reset_ssd_file ;;
2453	    [Hh] | Help | help)	display_msg ssd_menu_help
2454				${ECHO} " Press return to continue."
2455				read __A ;;
2456	    [Qq] | Quit | quit)	return ;;
2457	    *)    ${ECHO} "Invalid choice: $ANS please re-enter from menu." ;;
2458	esac
2459    done
2460}
2461
2462
2463#
2464# reset_ssd_file(): Blank out current SSD file.
2465#
2466reset_ssd_file()
2467{
2468    [ $DEBUG -eq 1 ] && ${ECHO} "In reset_ssd_file()"
2469
2470    rm -f ${SSD_FILE}
2471    touch ${SSD_FILE}
2472}
2473
2474
2475#
2476# create_ssd_file(): Create a temporary file for SSD's.
2477#
2478create_ssd_file()
2479{
2480    [ $DEBUG -eq 1 ] && ${ECHO} "In create_ssd_file()"
2481
2482    # Build a list of SSD's and store in temp file.
2483    ${GREP} "LDAP_SERV_SRCH_DES=" ${INPUT_FILE} | \
2484	sed 's/LDAP_SERV_SRCH_DES=//' \
2485	> ${SSD_FILE}
2486}
2487
2488
2489#
2490# ssd_2_config(): Append the SSD file to the output file.
2491#
2492ssd_2_config()
2493{
2494    [ $DEBUG -eq 1 ] && ${ECHO} "In ssd_2_config()"
2495
2496    # Convert to config file format using sed.
2497    sed -e "s/^/LDAP_SERV_SRCH_DES=/" ${SSD_FILE} >> ${OUTPUT_FILE}
2498}
2499
2500
2501#
2502# ssd_2_profile(): Add SSD's to the GEN_CMD string.
2503#
2504ssd_2_profile()
2505{
2506    [ $DEBUG -eq 1 ] && ${ECHO} "In ssd_2_profile()"
2507
2508    GEN_TMPFILE=${TMPDIR}/ssd_tmpfile
2509    touch ${GEN_TMPFILE}
2510
2511    # Add and convert each SSD to string.
2512    while read SSD_LINE
2513    do
2514	${ECHO} " -a \"serviceSearchDescriptor=${SSD_LINE}\"\c" >> ${GEN_TMPFILE}
2515    done <${SSD_FILE}
2516
2517    # Add SSD's to GEN_CMD.
2518    GEN_CMD="${GEN_CMD} `cat ${GEN_TMPFILE}`"
2519}
2520
2521#
2522# get_adminDN(): Get the admin DN.
2523#
2524get_adminDN()
2525{
2526    LDAP_ADMINDN="cn=admin,ou=profile,${LDAP_BASEDN}"  # default
2527    get_ans "Enter DN for the administrator:" "$LDAP_ADMINDN"
2528    LDAP_ADMINDN=$ANS
2529    [ $DEBUG -eq 1 ] && ${ECHO} "LDAP_ADMINDN = $LDAP_ADMINDN"
2530}
2531
2532#
2533# get_admin_pw(): Get the admin passwd.
2534#
2535get_admin_pw()
2536{
2537    get_passwd "Enter passwd for the administrator:"
2538    LDAP_ADMIN_CRED=$ANS
2539    [ $DEBUG -eq 1 ] && ${ECHO} "LDAP_ADMIN_CRED = $LDAP_ADMIN_CRED"
2540}
2541
2542#
2543# add_admin(): Add an admin entry for nameservice for updating shadow data.
2544#
2545add_admin()
2546{
2547    [ $DEBUG -eq 1 ] && ${ECHO} "In add_admin()"
2548
2549    # Check if the admin user already exists.
2550    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_ADMINDN}\" -s base \"objectclass=*\" ${VERB}"
2551    if [ $? -eq 0 ]; then
2552	MSG="Administrator ${LDAP_ADMINDN} already exists."
2553	if [ $EXISTING_PROFILE -eq 1 ]; then
2554	    ${ECHO} "  NOT ADDED: $MSG"
2555	else
2556	    ${ECHO} "  ${STEP}. $MSG"
2557	    STEP=`expr $STEP + 1`
2558	fi
2559	return 0
2560    fi
2561
2562    # Get cn and sn names from LDAP_ADMINDN.
2563    cn_tmp=`${ECHO} ${LDAP_ADMINDN} | cut -f1 -d, | cut -f2 -d=`
2564
2565    # Create the tmp file to add.
2566    ( cat <<EOF
2567dn: ${LDAP_ADMINDN}
2568cn: ${cn_tmp}
2569sn: ${cn_tmp}
2570objectclass: top
2571objectclass: person
2572userpassword: ${LDAP_ADMIN_CRED}
2573EOF
2574) > ${TMPDIR}/admin
2575
2576    # Add the entry.
2577    ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/admin ${VERB}"
2578    if [ $? -ne 0 ]; then
2579	${ECHO} "  ERROR: Adding administrator identity failed!"
2580	cleanup
2581	exit 1
2582    fi
2583
2584    ${RM} -f ${TMPDIR}/admin
2585
2586    # Display message that the administrator identity is added.
2587    MSG="Administrator identity ${LDAP_ADMINDN}"
2588    if [ $EXISTING_PROFILE -eq 1 ]; then
2589	${ECHO} "  ADDED: $MSG."
2590    else
2591	${ECHO} "  ${STEP}. $MSG added."
2592	STEP=`expr $STEP + 1`
2593    fi
2594}
2595
2596#
2597# allow_admin_write_shadow(): Give Admin write permission for shadow data.
2598#
2599allow_admin_write_shadow()
2600{
2601    [ $DEBUG -eq 1 ] && ${ECHO} "In allow_admin_write_shadow()"
2602
2603    # Set ACI Name
2604    ADMIN_ACI_NAME="LDAP_Naming_Services_admin_shadow_write"
2605
2606    # Search for ACI_NAME
2607    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" \
2608    -s base objectclass=* aci > ${TMPDIR}/chk_adminwrite_aci 2>&1"
2609    ${GREP} "${ADMIN_ACI_NAME}" ${TMPDIR}/chk_adminwrite_aci > /dev/null 2>&1
2610    if [ $? -eq 0 ]; then
2611	MSG="Admin ACI ${ADMIN_ACI_NAME} already exists for ${LDAP_BASEDN}."
2612	if [ $EXISTING_PROFILE -eq 1 ]; then
2613	    ${ECHO} "  NOT SET: $MSG"
2614	else
2615	    ${ECHO} "  ${STEP}. $MSG"
2616	    STEP=`expr $STEP + 1`
2617	fi
2618	return 0
2619    fi
2620
2621    # Create the tmp file to add.
2622    ( cat <<EOF
2623dn: ${LDAP_BASEDN}
2624changetype: modify
2625add: aci
2626aci: (target="ldap:///${LDAP_BASEDN}")(targetattr="shadowLastChange||shadowMin||shadowMax||shadowWarning||shadowInactive||shadowExpire||shadowFlag||userPassword||loginShell||homeDirectory||gecos")(version 3.0; acl ${ADMIN_ACI_NAME}; allow (write) userdn = "ldap:///${LDAP_ADMINDN}";)
2627EOF
2628) > ${TMPDIR}/admin_write
2629
2630    # Add the entry.
2631    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/admin_write ${VERB}"
2632    if [ $? -ne 0 ]; then
2633	${ECHO} "  ERROR: Allow ${LDAP_ADMINDN} to write shadow data failed!"
2634	cleanup
2635	exit 1
2636    fi
2637
2638    ${RM} -f ${TMPDIR}/admin_write
2639    # Display message that the administrator ACL is set.
2640    MSG="Give ${LDAP_ADMINDN} write permission for shadow."
2641    if [ $EXISTING_PROFILE -eq 1 ]; then
2642	${ECHO} "  ACI SET: $MSG"
2643    else
2644	${ECHO} "  ${STEP}. $MSG"
2645	STEP=`expr $STEP + 1`
2646    fi
2647}
2648
2649#
2650# allow_host_write_shadow(): Give host principal write permission
2651# for shadow data.
2652#
2653allow_host_write_shadow()
2654{
2655    [ $DEBUG -eq 1 ] && ${ECHO} "In allow_host_write_shadow()"
2656
2657    # Set ACI Name
2658    HOST_ACI_NAME="LDAP_Naming_Services_host_shadow_write"
2659
2660    # Search for ACI_NAME
2661    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_hostwrite_aci 2>&1"
2662    ${GREP} "${HOST_ACI_NAME}" ${TMPDIR}/chk_hostwrite_aci > /dev/null 2>&1
2663    if [ $? -eq 0 ]; then
2664	MSG="Host ACI ${HOST_ACI_NAME} already exists for ${LDAP_BASEDN}."
2665	if [ $EXISTING_PROFILE -eq 1 ]; then
2666	    ${ECHO} "  NOT ADDED: $MSG"
2667	else
2668	    ${ECHO} "  ${STEP}. $MSG"
2669	    STEP=`expr $STEP + 1`
2670	fi
2671	return 0
2672    fi
2673
2674    # Create the tmp file to add.
2675    ( cat <<EOF
2676dn: ${LDAP_BASEDN}
2677changetype: modify
2678add: aci
2679aci: (target="ldap:///${LDAP_BASEDN}")(targetattr="shadowLastChange||shadowMin||shadowMax||shadowWarning||shadowInactive||shadowExpire||shadowFlag||userPassword||loginShell||homeDirectory||gecos")(version 3.0; acl ${HOST_ACI_NAME}; allow (read, write) authmethod="sasl GSSAPI" and userdn = "ldap:///cn=*+ipHostNumber=*,ou=Hosts,${LDAP_BASEDN}";)
2680EOF
2681) > ${TMPDIR}/host_write
2682
2683    # Add the entry.
2684    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/host_write ${VERB}"
2685    if [ $? -ne 0 ]; then
2686	${ECHO} "  ERROR: Allow Host Principal to write shadow data failed!"
2687	cleanup
2688	exit 1
2689    fi
2690
2691    ${RM} -f ${TMPDIR}/host_write
2692    MSG="Give host principal write permission for shadow."
2693    if [ $EXISTING_PROFILE -eq 1 ]; then
2694	${ECHO} "  ACI SET: $MSG"
2695    else
2696	${ECHO} "  ${STEP}. $MSG"
2697	STEP=`expr $STEP + 1`
2698    fi
2699}
2700
2701#
2702# Set up shadow update
2703#
2704setup_shadow_update() {
2705    [ $DEBUG -eq 1 ] && ${ECHO} "In setup_shadow_update()"
2706
2707    # get content of the profile
2708    PROFILE_OUT=${TMPDIR}/prof_tmpfile
2709    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${LDAP_PROFILE_NAME},ou=profile,${LDAP_BASEDN}\" -s base \"objectclass=*\" > $PROFILE_OUT 2>&1"
2710    ${GREP} -i cn $PROFILE_OUT >/dev/null 2>&1
2711    if [ $? -ne 0 ]; then
2712	[ $DEBUG -eq 1 ] && ${ECHO} "Profile ${LDAP_PROFILE_NAME} does not exist"
2713	${RM} ${PROFILE_OUT}
2714	return
2715    fi
2716
2717    # Search to see if authenticationMethod has 'GSSAPI' and
2718    # credentialLevel has 'self'. If so, ask to use the
2719    # host principal for shadow update
2720    if [ $GSSAPI_AUTH_MAY_BE_USED -eq 1 ]; then
2721	if ${GREP} authenticationMethod $PROFILE_OUT | ${GREP} GSSAPI >/dev/null 2>&1
2722	then
2723	    if ${GREP} credentialLevel $PROFILE_OUT | ${GREP} self >/dev/null 2>&1
2724	    then
2725		NEED_HOSTACL=1
2726	    fi
2727	fi
2728	${RM} ${PROFILE_OUT}
2729	[ $DEBUG -eq 1 ] && ${ECHO} "NEED_HOSTACL = $NEED_HOSTACL"
2730
2731	if [ $NEED_HOSTACL -eq 1 ]; then
2732	    MSG="Use host principal for shadow data update (y/n/h)?"
2733	    get_confirm "$MSG" "y" "use_host_principal_help"
2734	    if [ $? -eq 1 ]; then
2735		allow_host_write_shadow
2736		modify_top_aci
2737	        ${ECHO} ""
2738		${ECHO} "  Shadow update has been enabled."
2739	    else
2740	        ${ECHO} ""
2741    		${ECHO} "  Shadow update may not work."
2742	    fi
2743	    return
2744	fi
2745    fi
2746
2747    MSG="Add the administrator identity (y/n/h)?"
2748    get_confirm "$MSG" "y" "add_admin_cred_help"
2749    if [ $? -eq 1 ]; then
2750	get_adminDN
2751	get_admin_pw
2752	add_admin
2753	allow_admin_write_shadow
2754	modify_top_aci
2755        ${ECHO} ""
2756	${ECHO} "  Shadow update has been enabled."
2757	return
2758    fi
2759
2760    ${ECHO} "  No administrator identity specified, shadow update may not work."
2761}
2762
2763
2764#
2765# prompt_config_info(): This function prompts the user for the config
2766# info that is not specified in the input file.
2767#
2768prompt_config_info()
2769{
2770    [ $DEBUG -eq 1 ] && ${ECHO} "In prompt_config_info()"
2771
2772    # Prompt for iDS server name.
2773    get_ids_server
2774
2775    # Prompt for iDS port number.
2776    get_ids_port
2777
2778    # Check iDS version for compatibility.
2779    chk_ids_version
2780
2781    # Check if the server supports the VLV.
2782    chk_vlv_indexes
2783
2784    # Get the Directory manager DN and passwd.
2785    get_dirmgr_dn
2786    get_dirmgr_pw
2787
2788    #
2789    # LDAP CLIENT PROFILE SPECIFIC INFORMATION.
2790    #   (i.e. The fields that show up in the profile.)
2791    #
2792    get_domain "domain_help"
2793
2794    get_basedn
2795
2796    gssapi_setup
2797
2798    get_profile_name
2799
2800    if [ "$LDAP_ENABLE_SHADOW_UPDATE" = "TRUE" ];then
2801	setup_shadow_update
2802	exit 0
2803    fi
2804
2805    get_srv_list
2806    get_pref_srv
2807    get_search_scope
2808
2809    # If cred is "anonymous", make auth == "none"
2810    get_cred_level
2811    if [ "$LDAP_CRED_LEVEL" != "anonymous" ]; then
2812	get_auth
2813    fi
2814
2815    get_followref
2816
2817    # Query user about timelimt.
2818    get_confirm "Do you want to modify the server timelimit value (y/n/h)?" "n" "tlim_help"
2819    NEED_TIME=$?
2820    [ $NEED_TIME -eq 1 ] && get_timelimit
2821
2822    # Query user about sizelimit.
2823    get_confirm "Do you want to modify the server sizelimit value (y/n/h)?" "n" "slim_help"
2824    NEED_SIZE=$?
2825    [ $NEED_SIZE -eq 1 ] && get_sizelimit
2826
2827    # Does the user want to store passwords in crypt format?
2828    get_want_crypt
2829
2830    # Prompt for any Service Authentication Methods?
2831    get_confirm "Do you want to setup a Service Authentication Methods (y/n/h)?" "n" "srvauth_help"
2832    if [ $? -eq 1 ]; then
2833	# Does the user want to set Service Authentication Method for pam_ldap?
2834	get_confirm "Do you want to setup a Service Auth. Method for \"pam_ldap\" (y/n/h)?" "n" "pam_ldap_help"
2835	NEED_SRVAUTH_PAM=$?
2836	[ $NEED_SRVAUTH_PAM -eq 1 ] && get_srv_authMethod_pam
2837
2838	# Does the user want to set Service Authentication Method for keyserv?
2839	get_confirm "Do you want to setup a Service Auth. Method for \"keyserv\" (y/n/h)?" "n" "keyserv_help"
2840	NEED_SRVAUTH_KEY=$?
2841	[ $NEED_SRVAUTH_KEY -eq 1 ] && get_srv_authMethod_key
2842
2843	# Does the user want to set Service Authentication Method for passwd-cmd?
2844	get_confirm "Do you want to setup a Service Auth. Method for \"passwd-cmd\" (y/n/h)?" "n" "passwd-cmd_help"
2845	NEED_SRVAUTH_CMD=$?
2846	[ $NEED_SRVAUTH_CMD -eq 1 ] && get_srv_authMethod_cmd
2847    fi
2848
2849
2850    # Get Timeouts
2851    get_srch_time
2852    get_prof_ttl
2853    get_bind_limit
2854
2855    # Ask whether to enable shadow update
2856    get_want_shadow_update
2857
2858    # Reset the sdd_file and prompt user for SSD.  Will use menus
2859    # to build an SSD File.
2860    reset_ssd_file
2861    prompt_ssd
2862
2863    # Display FULL debugging info.
2864    disp_full_debug
2865
2866    # Extra blank line to separate prompt lines from steps.
2867    ${ECHO} " "
2868}
2869
2870
2871######################################################################
2872# FUNCTIONS  FOR display_summary() START HERE.
2873######################################################################
2874
2875
2876#
2877# get_proxyagent(): Get the proxyagent DN.
2878#
2879get_proxyagent()
2880{
2881    LDAP_PROXYAGENT="cn=proxyagent,ou=profile,${LDAP_BASEDN}"  # default
2882    get_ans "Enter DN for proxy agent:" "$LDAP_PROXYAGENT"
2883    LDAP_PROXYAGENT=$ANS
2884}
2885
2886
2887#
2888# get_proxy_pw(): Get the proxyagent passwd.
2889#
2890get_proxy_pw()
2891{
2892    get_passwd "Enter passwd for proxyagent:"
2893    LDAP_PROXYAGENT_CRED=$ANS
2894}
2895
2896#
2897# display_summary(): Display a summary of values entered and let the
2898#                    user modify values at will.
2899#
2900display_summary()
2901{
2902    [ $DEBUG -eq 1 ] && ${ECHO} "In display_summary()"
2903
2904    # Create lookup table for function names.  First entry is dummy for
2905    # shift.
2906    TBL1="dummy"
2907    TBL2="get_domain get_basedn get_profile_name"
2908    TBL3="get_srv_list get_pref_srv get_search_scope get_cred_level"
2909    TBL4="get_auth get_followref"
2910    TBL5="get_timelimit get_sizelimit get_want_crypt"
2911    TBL6="get_srv_authMethod_pam get_srv_authMethod_key get_srv_authMethod_cmd"
2912    TBL7="get_srch_time get_prof_ttl get_bind_limit"
2913    TBL8="get_want_shadow_update"
2914    TBL9="prompt_ssd"
2915    FUNC_TBL="$TBL1 $TBL2 $TBL3 $TBL4 $TBL5 $TBL6 $TBL7 $TBL8 $TBL9"
2916
2917    # Since menu prompt string is long, set here.
2918    _MENU_PROMPT="Enter config value to change: (1-20 0=commit changes)"
2919
2920    # Infinite loop.  Test for 0, and break in loop.
2921    while :
2922    do
2923	# Display menu and get value in range.
2924	display_msg summary_menu
2925	get_menu_choice "${_MENU_PROMPT}" "0" "20" "0"
2926	_CH=$MN_CH
2927
2928	# Make sure where not exiting.
2929	if [ $_CH -eq 0 ]; then
2930	    break       # Break out of loop if 0 selected.
2931	fi
2932
2933	# Call appropriate function from function table.
2934	set $FUNC_TBL
2935	shift $_CH
2936	$1          # Call the appropriate function.
2937    done
2938
2939    # If cred level is still see if user wants a change?
2940    if ${ECHO} "$LDAP_CRED_LEVEL" | ${GREP} "proxy" > /dev/null 2>&1
2941    then
2942	if [ "$LDAP_AUTHMETHOD" != "none" ]; then
2943	    NEED_PROXY=1    # I assume integer test is faster?
2944	    get_proxyagent
2945	    get_proxy_pw
2946	else
2947	    ${ECHO} "WARNING: Since Authentication method is 'none'."
2948	    ${ECHO} "         Credential level will be set to 'anonymous'."
2949	    LDAP_CRED_LEVEL="anonymous"
2950	fi
2951    fi
2952
2953    # If shadow update is enabled, set up administrator credential
2954    if [ "$LDAP_ENABLE_SHADOW_UPDATE" = "TRUE" ]; then
2955	NEED_ADMIN=1
2956	if ${ECHO} "$LDAP_CRED_LEVEL" | ${GREP} "self" > /dev/null 2>&1; then
2957	    if ${ECHO} "$LDAP_AUTHMETHOD" | ${GREP} "GSSAPI" > /dev/null 2>&1; then
2958		NEED_HOSTACL=1
2959		NEED_ADMIN=0
2960	    fi
2961	fi
2962        [ $DEBUG -eq 1 ] && ${ECHO} "NEED_HOSTACL = $NEED_HOSTACL"
2963        [ $DEBUG -eq 1 ] && ${ECHO} "NEED_ADMIN   = $NEED_ADMIN"
2964	if [ $NEED_ADMIN -eq 1 ]; then
2965	    get_adminDN
2966	    get_admin_pw
2967	fi
2968    fi
2969
2970    # Display FULL debugging info.
2971    disp_full_debug
2972
2973    # Final confirmation message. (ARE YOU SURE!)
2974    ${ECHO} " "
2975    get_confirm_nodef "WARNING: About to start committing changes. (y=continue, n=EXIT)"
2976    if [ $? -eq 0 ]; then
2977	${ECHO} "Terminating setup without making changes at users request."
2978	cleanup
2979	exit 1
2980    fi
2981
2982    # Print newline
2983    ${ECHO} " "
2984}
2985
2986
2987#
2988# create_config_file(): Write config data to config file specified.
2989#
2990create_config_file()
2991{
2992    [ $DEBUG -eq 1 ] && ${ECHO} "In create_config_file()"
2993
2994    # If output file exists, delete it.
2995    [ -f $OUTPUT_FILE ] && rm $OUTPUT_FILE
2996
2997    # Create output file.
2998    cat > $OUTPUT_FILE <<EOF
2999#!/bin/sh
3000# $OUTPUT_FILE - This file contains configuration information for
3001#                Native LDAP.  Use the idsconfig tool to load it.
3002#
3003# WARNING: This file was generated by idsconfig, and is intended to
3004#          be loaded by idsconfig as is.  DO NOT EDIT THIS FILE!
3005#
3006IDS_SERVER="$IDS_SERVER"
3007IDS_PORT=$IDS_PORT
3008IDS_TIMELIMIT=$IDS_TIMELIMIT
3009IDS_SIZELIMIT=$IDS_SIZELIMIT
3010LDAP_ROOTDN="$LDAP_ROOTDN"
3011LDAP_ROOTPWD=$LDAP_ROOTPWD
3012LDAP_DOMAIN="$LDAP_DOMAIN"
3013LDAP_SUFFIX="$LDAP_SUFFIX"
3014LDAP_KRB_REALM="$LDAP_KRB_REALM"
3015LDAP_GSSAPI_PROFILE="$LDAP_GSSAPI_PROFILE"
3016
3017# Internal program variables that need to be set.
3018NEED_PROXY=$NEED_PROXY
3019NEED_TIME=$NEED_TIME
3020NEED_SIZE=$NEED_SIZE
3021NEED_CRYPT=$NEED_CRYPT
3022NEED_ADMIN=$NEED_ADMIN
3023NEED_HOSTACL=$NEED_HOSTACL
3024EXISTING_PROFILE=$EXISTING_PROFILE
3025
3026# LDAP PROFILE related defaults
3027LDAP_PROFILE_NAME="$LDAP_PROFILE_NAME"
3028DEL_OLD_PROFILE=1
3029LDAP_BASEDN="$LDAP_BASEDN"
3030LDAP_SERVER_LIST="$LDAP_SERVER_LIST"
3031LDAP_AUTHMETHOD="$LDAP_AUTHMETHOD"
3032LDAP_FOLLOWREF=$LDAP_FOLLOWREF
3033LDAP_SEARCH_SCOPE="$LDAP_SEARCH_SCOPE"
3034NEED_SRVAUTH_PAM=$NEED_SRVAUTH_PAM
3035NEED_SRVAUTH_KEY=$NEED_SRVAUTH_KEY
3036NEED_SRVAUTH_CMD=$NEED_SRVAUTH_CMD
3037LDAP_SRV_AUTHMETHOD_PAM="$LDAP_SRV_AUTHMETHOD_PAM"
3038LDAP_SRV_AUTHMETHOD_KEY="$LDAP_SRV_AUTHMETHOD_KEY"
3039LDAP_SRV_AUTHMETHOD_CMD="$LDAP_SRV_AUTHMETHOD_CMD"
3040LDAP_SEARCH_TIME_LIMIT=$LDAP_SEARCH_TIME_LIMIT
3041LDAP_PREF_SRVLIST="$LDAP_PREF_SRVLIST"
3042LDAP_PROFILE_TTL=$LDAP_PROFILE_TTL
3043LDAP_CRED_LEVEL="$LDAP_CRED_LEVEL"
3044LDAP_BIND_LIMIT=$LDAP_BIND_LIMIT
3045
3046# Proxy Agent
3047LDAP_PROXYAGENT="$LDAP_PROXYAGENT"
3048LDAP_PROXYAGENT_CRED=$LDAP_PROXYAGENT_CRED
3049
3050# enableShadowUpdate flag and Administrator credential
3051LDAP_ENABLE_SHADOW_UPDATE=$LDAP_ENABLE_SHADOW_UPDATE
3052LDAP_ADMINDN="$LDAP_ADMINDN"
3053LDAP_ADMIN_CRED=$LDAP_ADMIN_CRED
3054
3055# Export all the variables (just in case)
3056export IDS_HOME IDS_PORT LDAP_ROOTDN LDAP_ROOTPWD LDAP_SERVER_LIST LDAP_BASEDN
3057export LDAP_DOMAIN LDAP_SUFFIX LDAP_PROXYAGENT LDAP_PROXYAGENT_CRED
3058export NEED_PROXY
3059export LDAP_ENABLE_SHADOW_UPDATE LDAP_ADMINDN LDAP_ADMIN_CRED
3060export NEED_ADMIN NEED_HOSTACL EXISTING_PROFILE
3061export LDAP_PROFILE_NAME LDAP_BASEDN LDAP_SERVER_LIST 
3062export LDAP_AUTHMETHOD LDAP_FOLLOWREF LDAP_SEARCH_SCOPE LDAP_SEARCH_TIME_LIMIT
3063export LDAP_PREF_SRVLIST LDAP_PROFILE_TTL LDAP_CRED_LEVEL LDAP_BIND_LIMIT
3064export NEED_SRVAUTH_PAM NEED_SRVAUTH_KEY NEED_SRVAUTH_CMD
3065export LDAP_SRV_AUTHMETHOD_PAM LDAP_SRV_AUTHMETHOD_KEY LDAP_SRV_AUTHMETHOD_CMD
3066export LDAP_SERV_SRCH_DES SSD_FILE LDAP_KRB_REALM LDAP_GSSAPI_PROFILE
3067
3068# Service Search Descriptors start here if present:
3069EOF
3070    # Add service search descriptors.
3071    ssd_2_config "${OUTPUT_FILE}"
3072
3073    # Add LDAP suffix preferences
3074    print_suffix_config >> "${OUTPUT_FILE}"
3075
3076    # Add the end of FILE tag.
3077    ${ECHO} "" >> ${OUTPUT_FILE}
3078    ${ECHO} "# End of $OUTPUT_FILE" >> ${OUTPUT_FILE}
3079}
3080
3081
3082#
3083# chk_vlv_indexes(): Do ldapsearch to see if server supports VLV.
3084#
3085chk_vlv_indexes()
3086{
3087    # Do ldapsearch to see if server supports VLV.
3088    ${LDAPSEARCH} ${SERVER_ARGS} -b "" -s base "objectclass=*" > ${TMPDIR}/checkVLV 2>&1
3089    eval "${GREP} 2.16.840.1.113730.3.4.9 ${TMPDIR}/checkVLV ${VERB}"
3090    if [ $? -ne 0 ]; then
3091	${ECHO} "ERROR: VLV is not supported on LDAP server!"
3092	cleanup
3093	exit 1
3094    fi
3095    [ $DEBUG -eq 1 ] && ${ECHO} "  VLV controls found on LDAP server."
3096}
3097
3098#
3099# get_backend(): this function gets the relevant backend
3100#                (database) for LDAP_BASED.
3101#                Description: set IDS_DATABASE; exit on failure.
3102#                Prerequisite: LDAP_BASEDN and LDAP_SUFFIX are
3103#                valid.
3104#
3105#                backend is retrieved from suffixes and subsuffixes
3106#                defined under "cn=mapping tree,cn=config". The
3107#                nsslapd-state attribute of these suffixes entries
3108#                is filled with either Backend, Disabled or referrals
3109#                related values. We only want those that have a true
3110#                backend database to select the relevant backend.
3111#
3112get_backend()
3113{
3114    [ $DEBUG -eq 1 ] && ${ECHO} "In get_backend()"
3115
3116    cur_suffix=${LDAP_BASEDN}
3117    prev_suffix=
3118    IDS_DATABASE=
3119    while [ "${cur_suffix}" != "${prev_suffix}" ]
3120    do
3121	[ $DEBUG -eq 1 ] && ${ECHO} "testing LDAP suffix: ${cur_suffix}"
3122	eval "${LDAPSEARCH} ${LDAP_ARGS} " \
3123		"-b \"cn=\\\"${cur_suffix}\\\",cn=mapping tree,cn=config\" " \
3124		"-s base nsslapd-state=Backend nsslapd-backend 2>&1 " \
3125		"| ${GREP} 'nsslapd-backend=' " \
3126		"> ${TMPDIR}/ids_database_name 2>&1"
3127	NUM_DBS=`wc -l ${TMPDIR}/ids_database_name | awk '{print $1}'`
3128	case ${NUM_DBS} in
3129	0) # not a suffix, or suffix not activated; try next
3130	    prev_suffix=${cur_suffix}
3131	    cur_suffix=`${ECHO} ${cur_suffix} | cut -f2- -d','`
3132	    ;;
3133	1) # suffix found; get database name
3134	    IDS_DATABASE=`cat ${TMPDIR}/ids_database_name | cut -d= -f2`
3135	    ;;
3136	*) # can not handle more than one database per suffix
3137	    ${ECHO} "ERROR: More than one database is configured "
3138	    ${ECHO} "       for $LDAP_SUFFIX!"
3139	    ${ECHO} "       $PROG can not configure suffixes where "
3140	    ${ECHO} "       more than one database is used for one suffix."
3141	    cleanup
3142	    exit 1
3143	    ;;
3144	esac
3145	if [ -n "${IDS_DATABASE}" ]; then
3146	    break
3147	fi
3148    done
3149
3150    if [ -z "${IDS_DATABASE}" ]; then
3151	# should not happen, since LDAP_BASEDN is supposed to be valid
3152	${ECHO} "Could not find a valid backend for ${LDAP_BASEDN}."
3153	${ECHO} "Exiting."
3154	cleanup
3155	exit 1
3156    fi
3157
3158    [ $DEBUG -eq 1 ] && ${ECHO} "IDS_DATABASE: ${IDS_DATABASE}"
3159}
3160
3161#
3162# validate_suffix(): This function validates ${LDAP_SUFFIX}
3163#                  THIS FUNCTION IS FOR THE LOAD CONFIG FILE OPTION.
3164#
3165validate_suffix()
3166{
3167    [ $DEBUG -eq 1 ] && ${ECHO} "In validate_suffix()"
3168
3169    # Check LDAP_SUFFIX is not null
3170    if [ -z "${LDAP_SUFFIX}" ]; then
3171	${ECHO} "Invalid suffix (null suffix)"
3172	cleanup
3173	exit 1
3174    fi
3175
3176    # Check LDAP_SUFFIX and LDAP_BASEDN are consistent
3177    # Convert to lower case for basename.
3178    format_string "${LDAP_BASEDN}"
3179    LOWER_BASEDN="${FMT_STR}"
3180    format_string "${LDAP_SUFFIX}"
3181    LOWER_SUFFIX="${FMT_STR}"
3182
3183    [ $DEBUG -eq 1 ] && ${ECHO} "LOWER_BASEDN: ${LOWER_BASEDN}"
3184    [ $DEBUG -eq 1 ] && ${ECHO} "LOWER_SUFFIX: ${LOWER_SUFFIX}"
3185
3186    if [ "${LOWER_BASEDN}" != "${LOWER_SUFFIX}" ]; then
3187    	sub_basedn=`basename "${LOWER_BASEDN}" "${LOWER_SUFFIX}"`
3188    	if [ "$sub_basedn" = "${LOWER_BASEDN}" ]; then
3189	    ${ECHO} "Invalid suffix ${LOWER_SUFFIX}"
3190	    ${ECHO} "for Base DN ${LOWER_BASEDN}"
3191	    cleanup
3192	    exit 1
3193	fi
3194    fi
3195
3196    # Check LDAP_SUFFIX does exist
3197    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_SUFFIX}\" -s base \"objectclass=*\" > ${TMPDIR}/checkSuffix 2>&1" && return 0
3198
3199    # Well, suffix does not exist, try to prepare create it ...
3200    NEED_CREATE_SUFFIX=1
3201    prep_create_sfx_entry ||
3202    {
3203	cleanup
3204	exit 1
3205    }
3206    [ -n "${NEED_CREATE_BACKEND}" ] &&
3207    {
3208	# try to use id attr value of the suffix as a database name
3209	IDS_DATABASE=${_VAL}
3210	prep_create_sfx_backend
3211	case $? in
3212	1)	# cann't use the name we want, so we can either exit or use
3213		# some another available name - doing the last ...
3214		IDS_DATABASE=${IDS_DATABASE_AVAIL}
3215		;;
3216	2)	# unable to determine database name
3217		cleanup
3218		exit 1
3219		;;
3220	esac
3221    }
3222
3223    [ $DEBUG -eq 1 ] && ${ECHO} "Suffix $LDAP_SUFFIX, Database $IDS_DATABASE"
3224}
3225
3226#
3227# validate_info(): This function validates the basic info collected
3228#                  So that some problems are caught right away.
3229#                  THIS FUNCTION IS FOR THE LOAD CONFIG FILE OPTION.
3230#
3231validate_info()
3232{
3233    [ $DEBUG -eq 1 ] && ${ECHO} "In validate_info()"
3234
3235    # Set SERVER_ARGS, AUTH_ARGS, and LDAP_ARGS for the config file.
3236    SERVER_ARGS="-h ${IDS_SERVER} -p ${IDS_PORT}"
3237    AUTH_ARGS="-D \"${LDAP_ROOTDN}\" -j ${LDAP_ROOTPWF}"
3238    LDAP_ARGS="${SERVER_ARGS} ${AUTH_ARGS}"
3239    export SERVER_ARGS
3240
3241    # Check the Root DN and Root DN passwd.
3242    # Use eval instead of $EVAL because not part of setup. (validate)
3243    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"\" -s base \"objectclass=*\" > ${TMPDIR}/checkDN 2>&1"
3244    if [ $? -ne 0 ]; then
3245	eval "${GREP} credential ${TMPDIR}/checkDN ${VERB}"
3246	if [ $? -eq 0 ]; then
3247	    ${ECHO} "ERROR: Root DN passwd is invalid."
3248	else
3249	    ${ECHO} "ERROR2: Invalid Root DN <${LDAP_ROOTDN}>."
3250	fi
3251	cleanup
3252	exit 1
3253    fi
3254    [ $DEBUG -eq 1 ] && ${ECHO} "  RootDN ... OK"
3255    [ $DEBUG -eq 1 ] && ${ECHO} "  RootDN passwd ... OK"
3256
3257    # Check if the server supports the VLV.
3258    chk_vlv_indexes
3259    [ $DEBUG -eq 1 ] && ${ECHO} "  VLV indexes ... OK"
3260
3261    # Check LDAP suffix
3262    validate_suffix
3263    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP suffix ... OK"
3264}
3265
3266#
3267# format_string(): take a string as argument and set FMT_STR
3268# to be the same string formatted as follow:
3269# - only lower case characters
3270# - no unnecessary spaces around , and =
3271#
3272format_string()
3273{
3274    FMT_STR=`${ECHO} "$1" | tr '[A-Z]' '[a-z]' |
3275	sed -e 's/[ ]*,[ ]*/,/g' -e 's/[ ]*=[ ]*/=/g'`
3276}
3277
3278#
3279# prepare for the suffix entry creation
3280#
3281# input  : LDAP_BASEDN, LDAP_SUFFIX - base dn and suffix;
3282# in/out : LDAP_SUFFIX_OBJ, LDAP_SUFFIX_ACI - initially may come from config.
3283# output : NEED_CREATE_BACKEND - backend for this suffix needs to be created;
3284#          _RDN, _ATT, _VAL - suffix's RDN, id attribute name and its value.
3285# return : 0 - success, otherwise error.
3286#
3287prep_create_sfx_entry()
3288{
3289    [ $DEBUG -eq 1 ] && ${ECHO} "In prep_create_sfx_entry()"
3290
3291    # check whether suffix corresponds to base dn
3292    format_string "${LDAP_BASEDN}"
3293    ${ECHO} ",${FMT_STR}" | ${GREP} ",${LDAP_SUFFIX}$" >/dev/null 2>&1 ||
3294    {
3295	display_msg sfx_not_suitable
3296	return 1
3297    }
3298
3299    # parse LDAP_SUFFIX
3300    _RDN=`${ECHO} "${LDAP_SUFFIX}" | cut -d, -f1`
3301    _ATT=`${ECHO} "${_RDN}" | cut -d= -f1`
3302    _VAL=`${ECHO} "${_RDN}" | cut -d= -f2-`
3303
3304    # find out an objectclass for suffix entry if it is not defined yet
3305    [ -z "${LDAP_SUFFIX_OBJ}" ] &&
3306    {
3307	get_objectclass ${_ATT}
3308	[ -z "${_ATTR_NAME}" ] &&
3309	{
3310		display_msg obj_not_found
3311		return 1
3312	}
3313	LDAP_SUFFIX_OBJ=${_ATTR_NAME}
3314    }
3315    [ $DEBUG -eq 1 ] && ${ECHO} "Suffix entry object is ${LDAP_SUFFIX_OBJ}"
3316
3317    # find out an aci for suffix entry if it is not defined yet
3318    [ -z "${LDAP_SUFFIX_ACI}" ] &&
3319    {
3320	# set Directory Server default aci
3321	LDAP_SUFFIX_ACI=`cat <<EOF
3322aci: (targetattr != "userPassword || passwordHistory || passwordExpirationTime
3323 || passwordExpWarned || passwordRetryCount || retryCountResetTime ||
3324 accountUnlockTime || passwordAllowChangeTime")
3325 (
3326   version 3.0;
3327   acl "Anonymous access";
3328   allow (read, search, compare) userdn = "ldap:///anyone";
3329 )
3330aci: (targetattr != "nsroledn || aci || nsLookThroughLimit || nsSizeLimit ||
3331 nsTimeLimit || nsIdleTimeout || passwordPolicySubentry ||
3332 passwordExpirationTime || passwordExpWarned || passwordRetryCount ||
3333 retryCountResetTime || accountUnlockTime || passwordHistory ||
3334 passwordAllowChangeTime")
3335 (
3336   version 3.0;
3337   acl "Allow self entry modification except for some attributes";
3338   allow (write) userdn = "ldap:///self";
3339 )
3340aci: (targetattr = "*")
3341 (
3342   version 3.0;
3343   acl "Configuration Administrator";
3344   allow (all) userdn = "ldap:///uid=admin,ou=Administrators,
3345                         ou=TopologyManagement,o=NetscapeRoot";
3346 )
3347aci: (targetattr ="*")
3348 (
3349   version 3.0;
3350   acl "Configuration Administrators Group";
3351   allow (all) groupdn = "ldap:///cn=Configuration Administrators,
3352                          ou=Groups,ou=TopologyManagement,o=NetscapeRoot";
3353 )
3354EOF
3355`
3356    }
3357    [ $DEBUG -eq 1 ] && cat <<EOF
3358DEBUG: ACI for ${LDAP_SUFFIX} is
3359${LDAP_SUFFIX_ACI}
3360EOF
3361
3362    NEED_CREATE_BACKEND=
3363
3364    # check the suffix mapping tree ...
3365    # if mapping exists, suffix should work, otherwise DS inconsistent
3366    # NOTE: -b 'cn=mapping tree,cn=config' -s one 'cn=\"$1\"' won't work
3367    #       in case of 'cn' value in LDAP is not quoted by '"',
3368    #       -b 'cn=\"$1\",cn=mapping tree,cn=config' works in all cases
3369    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} \
3370	-b 'cn=\"${LDAP_SUFFIX}\",cn=mapping tree,cn=config' \
3371	-s base 'objectclass=*' dn ${VERB}" &&
3372    {
3373	[ $DEBUG -eq 1 ] && ${ECHO} "Suffix mapping already exists"
3374	# get_backend() either gets IDS_DATABASE or exits
3375	get_backend
3376	return 0
3377    }
3378
3379    # no suffix mapping, just in case check ldbm backends consistency -
3380    # there are must be NO any databases pointing to LDAP_SUFFIX
3381    [ -n "`${EVAL} \"${LDAPSEARCH} ${LDAP_ARGS} \
3382	-b 'cn=ldbm database,cn=plugins,cn=config' \
3383	-s one 'nsslapd-suffix=${LDAP_SUFFIX}' dn\" 2>/dev/null`" ] &&
3384    {
3385	display_msg sfx_config_incons
3386	return 1
3387    }
3388
3389    # ok, no suffix mapping, no ldbm database
3390    [ $DEBUG -eq 1 ] && ${ECHO} "DEBUG: backend needs to be created ..."
3391    NEED_CREATE_BACKEND=1
3392    return 0
3393}
3394
3395#
3396# prepare for the suffix backend creation
3397#
3398# input  : IDS_DATABASE - requested ldbm db name (must be not null)
3399# in/out : IDS_DATABASE_AVAIL - available ldbm db name
3400# return : 0 - ldbm db name ok
3401#          1 - IDS_DATABASE exists,
3402#              so IDS_DATABASE_AVAIL contains available name
3403#          2 - unable to find any available name
3404#
3405prep_create_sfx_backend()
3406{
3407    [ $DEBUG -eq 1 ] && ${ECHO} "In prep_create_sfx_backend()"
3408
3409    # check if requested name available
3410    [ "${IDS_DATABASE}" = "${IDS_DATABASE_AVAIL}" ] && return 0
3411
3412    # get the list of database names start with a requested name
3413    _LDBM_DBS=`${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} \
3414	-b 'cn=ldbm database,cn=plugins,cn=config' \
3415	-s one 'cn=${IDS_DATABASE}*' cn"` 2>/dev/null
3416
3417    # find available db name based on a requested name
3418    _i=""; _i_MAX=10
3419    while [ ${_i:-0} -lt ${_i_MAX} ]
3420    do
3421	_name="${IDS_DATABASE}${_i}"
3422	${ECHO} "${_LDBM_DBS}" | ${GREP} -i "^cn=${_name}$" >/dev/null 2>&1 ||
3423	{
3424		IDS_DATABASE_AVAIL="${_name}"
3425		break
3426	}
3427	_i=`expr ${_i:-0} + 1`
3428    done
3429
3430    [ "${IDS_DATABASE}" = "${IDS_DATABASE_AVAIL}" ] && return 0
3431
3432    [ -n "${IDS_DATABASE_AVAIL}" ] &&
3433    {
3434	display_msg ldbm_db_exist
3435	return 1
3436    }
3437
3438    display_msg unable_find_db_name
3439    return 2
3440}
3441
3442#
3443# add suffix if needed,
3444#     suffix entry and backend MUST be prepared by
3445#     prep_create_sfx_entry and prep_create_sfx_backend correspondingly
3446#
3447# input  : NEED_CREATE_SUFFIX, LDAP_SUFFIX, LDAP_SUFFIX_OBJ, _ATT, _VAL
3448#          LDAP_SUFFIX_ACI, NEED_CREATE_BACKEND, IDS_DATABASE
3449# return : 0 - suffix successfully created, otherwise error occured
3450#
3451add_suffix()
3452{
3453    [ $DEBUG -eq 1 ] && ${ECHO} "In add_suffix()"
3454
3455    [ -n "${NEED_CREATE_SUFFIX}" ] || return 0
3456
3457    [ -n "${NEED_CREATE_BACKEND}" ] &&
3458    {
3459	${EVAL} "${LDAPADD} ${LDAP_ARGS} ${VERB}" <<EOF
3460dn: cn="${LDAP_SUFFIX}",cn=mapping tree,cn=config
3461objectclass: top
3462objectclass: extensibleObject
3463objectclass: nsMappingTree
3464cn: ${LDAP_SUFFIX}
3465nsslapd-state: backend
3466nsslapd-backend: ${IDS_DATABASE}
3467
3468dn: cn=${IDS_DATABASE},cn=ldbm database,cn=plugins,cn=config
3469objectclass: top
3470objectclass: extensibleObject
3471objectclass: nsBackendInstance
3472cn: ${IDS_DATABASE}
3473nsslapd-suffix: ${LDAP_SUFFIX}
3474EOF
3475	[ $? -ne 0 ] &&
3476	{
3477		display_msg create_ldbm_db_error
3478		return 1
3479	}
3480
3481	${ECHO} "  ${STEP}. Database ${IDS_DATABASE} successfully created"
3482	STEP=`expr $STEP + 1`
3483    }
3484
3485    ${EVAL} "${LDAPADD} ${LDAP_ARGS} ${VERB}" <<EOF
3486dn: ${LDAP_SUFFIX}
3487objectclass: ${LDAP_SUFFIX_OBJ}
3488${_ATT}: ${_VAL}
3489${LDAP_SUFFIX_ACI}
3490EOF
3491    [ $? -ne 0 ] &&
3492    {
3493	display_msg create_suffix_entry_error
3494	return 1
3495    }
3496
3497    ${ECHO} "  ${STEP}. Suffix ${LDAP_SUFFIX} successfully created"
3498    STEP=`expr $STEP + 1`
3499    return 0
3500}
3501
3502#
3503# interactively get suffix and related info from a user
3504#
3505# input  : LDAP_BASEDN - Base DN
3506# output : LDAP_SUFFIX - Suffix, _ATT, _VAL - id attribute and its value;
3507#          LDAP_SUFFIX_OBJ, LDAP_SUFFIX_ACI - objectclass and aci;
3508#          NEED_CREATE_BACKEND - tells whether backend needs to be created;
3509#          IDS_DATABASE - prepared ldbm db name
3510# return : 0 - user gave a correct suffix
3511#          1 - suffix given by user cann't be created
3512#
3513get_suffix()
3514{
3515    [ $DEBUG -eq 1 ] && ${ECHO} "In get_suffix()"
3516
3517    while :
3518    do
3519	get_ans "Enter suffix to be created (b=back/h=help):" ${LDAP_BASEDN}
3520	case "${ANS}" in
3521	[Hh] | Help | help | \? ) display_msg create_suffix_help ;;
3522	[Bb] | Back | back | \< ) return 1 ;;
3523	* )
3524		format_string "${ANS}"
3525		LDAP_SUFFIX=${FMT_STR}
3526		prep_create_sfx_entry || continue
3527
3528		[ -n "${NEED_CREATE_BACKEND}" ] &&
3529		{
3530		    IDS_DATABASE_AVAIL= # reset the available db name
3531
3532		    reenter_suffix=
3533		    while :
3534		    do
3535			get_ans "Enter ldbm database name (b=back/h=help):" \
3536				${IDS_DATABASE_AVAIL:-${_VAL}}
3537			case "${ANS}" in
3538			[Hh] | \? ) display_msg enter_ldbm_db_help ;;
3539			[Bb] | \< ) reenter_suffix=1; break ;;
3540			* )
3541				IDS_DATABASE="${ANS}"
3542				prep_create_sfx_backend && break
3543			esac
3544		    done
3545		    [ -n "${reenter_suffix}" ] && continue
3546
3547		    [ $DEBUG -eq 1 ] && cat <<EOF
3548DEBUG: backend name for suffix ${LDAP_SUFFIX} will be ${IDS_DATABASE}
3549EOF
3550		}
3551
3552		# eventually everything is prepared
3553		return 0
3554		;;
3555	esac
3556    done
3557}
3558
3559#
3560# print out a script which sets LDAP suffix related preferences
3561#
3562print_suffix_config()
3563{
3564    cat <<EOF2
3565# LDAP suffix related preferences used only if needed
3566IDS_DATABASE="${IDS_DATABASE}"
3567LDAP_SUFFIX_OBJ="$LDAP_SUFFIX_OBJ"
3568LDAP_SUFFIX_ACI=\`cat <<EOF
3569${LDAP_SUFFIX_ACI}
3570EOF
3571\`
3572export IDS_DATABASE LDAP_SUFFIX_OBJ LDAP_SUFFIX_ACI
3573EOF2
3574}
3575
3576#
3577# check_basedn_suffix(): check that there is an existing
3578# valid suffix to hold current base DN
3579# return:
3580#   0: valid suffix found or new one should be created,
3581#      NEED_CREATE_SUFFIX flag actually indicates that
3582#   1: some error occures
3583#
3584check_basedn_suffix()
3585{
3586    [ $DEBUG -eq 1 ] && ${ECHO} "In check_basedn_suffix()"
3587
3588    NEED_CREATE_SUFFIX=
3589
3590    # find out existing suffixes
3591    discover_serv_suffix
3592
3593    ${ECHO} "  Validating LDAP Base DN and Suffix ..."
3594
3595    # check that LDAP Base DN might be added
3596    cur_ldap_entry=${LDAP_BASEDN}
3597    prev_ldap_entry=
3598    while [ "${cur_ldap_entry}" != "${prev_ldap_entry}" ]
3599    do
3600	[ $DEBUG -eq 1 ] && ${ECHO} "testing LDAP entry: ${cur_ldap_entry}"
3601	${LDAPSEARCH} ${SERVER_ARGS} -b "${cur_ldap_entry}" \
3602		-s one "objectclass=*" > /dev/null 2>&1
3603	if [ $? -eq 0 ]; then
3604	    break
3605	else
3606	    prev_ldap_entry=${cur_ldap_entry}
3607	    cur_ldap_entry=`${ECHO} ${cur_ldap_entry} | cut -f2- -d','`
3608	fi
3609    done
3610
3611    if [ "${cur_ldap_entry}" = "${prev_ldap_entry}" ]; then
3612	${ECHO} "  No valid suffixes were found for Base DN ${LDAP_BASEDN}"
3613
3614	NEED_CREATE_SUFFIX=1
3615	return 0
3616
3617    else
3618	[ $DEBUG -eq 1 ] && ${ECHO} "found valid LDAP entry: ${cur_ldap_entry}"
3619
3620	# Now looking for relevant suffix for this entry.
3621	# LDAP_SUFFIX will then be used to add necessary
3622	# base objects. See add_base_objects().
3623	format_string "${cur_ldap_entry}"
3624	lower_entry="${FMT_STR}"
3625	[ $DEBUG -eq 1 ] && ${ECHO} "final suffix list: ${LDAP_SUFFIX_LIST}"
3626	oIFS=$IFS
3627	[ $DEBUG -eq 1 ] && ${ECHO} "setting IFS to new line"
3628	IFS='
3629'
3630	for suff in ${LDAP_SUFFIX_LIST}
3631	do
3632	    [ $DEBUG -eq 1 ] && ${ECHO} "testing suffix: ${suff}"
3633	    format_string "${suff}"
3634	    lower_suff="${FMT_STR}"
3635	    if [ "${lower_entry}" = "${lower_suff}" ]; then
3636		LDAP_SUFFIX="${suff}"
3637		break
3638	    else
3639		dcstmp=`basename "${lower_entry}" "${lower_suff}"`
3640		if [ "${dcstmp}" = "${lower_entry}" ]; then
3641		    # invalid suffix, try next one
3642		    continue
3643		else
3644		    # valid suffix found
3645		    LDAP_SUFFIX="${suff}"
3646		    break
3647		fi
3648	    fi
3649	done
3650	[ $DEBUG -eq 1 ] && ${ECHO} "setting IFS to original value"
3651	IFS=$oIFS
3652
3653	[ $DEBUG -eq 1 ] && ${ECHO} "LDAP_SUFFIX: ${LDAP_SUFFIX}"
3654
3655	if [ -z "${LDAP_SUFFIX}" ]; then
3656	    # should not happen, since we found the entry
3657	    ${ECHO} "Could not find a valid suffix for ${LDAP_BASEDN}."
3658	    ${ECHO} "Exiting."
3659	    return 1
3660	fi
3661
3662	# Getting relevant database (backend)
3663	# IDS_DATABASE will then be used to create indexes.
3664	get_backend
3665
3666	return 0
3667    fi
3668}
3669
3670#
3671# discover_serv_suffix(): This function queries the server to find
3672#    suffixes available
3673#  return: 0: OK, suffix found
3674#          1: suffix not determined
3675discover_serv_suffix()
3676{
3677    [ $DEBUG -eq 1 ] && ${ECHO} "In discover_serv_suffix()"
3678
3679    # Search the server for the TOP of the TREE.
3680    ${LDAPSEARCH} ${SERVER_ARGS} -b "" -s base "objectclass=*" > ${TMPDIR}/checkTOP 2>&1
3681    ${GREP} -i namingcontexts ${TMPDIR}/checkTOP | \
3682	${GREP} -i -v NetscapeRoot > ${TMPDIR}/treeTOP
3683    NUM_TOP=`wc -l ${TMPDIR}/treeTOP | awk '{print $1}'`
3684    case $NUM_TOP in
3685	0)
3686	    [ $DEBUG -eq 1 ] && ${ECHO} "DEBUG: No suffix found in LDAP tree"
3687	    return 1
3688	    ;;
3689	*)  # build the list of suffixes; take out 'namingContexts=' in
3690	    # each line of ${TMPDIR}/treeTOP
3691	    LDAP_SUFFIX_LIST=`cat ${TMPDIR}/treeTOP |
3692		awk '{ printf("%s\n",substr($0,16,length-15)) }'`
3693	    ;;
3694    esac
3695
3696    [ $DEBUG -eq 1 ] && ${ECHO} "  LDAP_SUFFIX_LIST = $LDAP_SUFFIX_LIST"
3697    return 0
3698}
3699
3700
3701#
3702# modify_cn(): Change the cn from MUST to MAY in ipNetwork.
3703#
3704modify_cn()
3705{
3706    [ $DEBUG -eq 1 ] && ${ECHO} "In modify_cn()"
3707
3708    ( cat <<EOF
3709dn: cn=schema
3710changetype: modify
3711add: objectclasses
3712objectclasses: ( 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' )
3713EOF
3714) > ${TMPDIR}/ipNetwork_cn
3715
3716    # Modify the cn for ipNetwork.
3717    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/ipNetwork_cn ${VERB}"
3718    if [ $? -ne 0 ]; then
3719	${ECHO} "  ERROR: update of cn for ipNetwork failed!"
3720	cleanup
3721	exit 1
3722    fi
3723}
3724
3725
3726# modify_timelimit(): Modify timelimit to user value.
3727modify_timelimit()
3728{
3729    [ $DEBUG -eq 1 ] && ${ECHO} "In modify_timelimit()"
3730
3731    # Here doc to modify timelimit.
3732    ( cat <<EOF
3733dn: cn=config
3734changetype: modify
3735replace: nsslapd-timelimit
3736nsslapd-timelimit: ${IDS_TIMELIMIT}
3737EOF
3738) > ${TMPDIR}/ids_timelimit
3739
3740    # Add the entry.
3741    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/ids_timelimit ${VERB}"
3742    if [ $? -ne 0 ]; then
3743	${ECHO} "  ERROR: update of nsslapd-timelimit failed!"
3744	cleanup
3745	exit 1
3746    fi
3747
3748    # Display messages for modifications made in patch.
3749    ${ECHO} "  ${STEP}. Changed timelimit to ${IDS_TIMELIMIT} in cn=config."
3750    STEP=`expr $STEP + 1`
3751}
3752
3753
3754# modify_sizelimit(): Modify sizelimit to user value.
3755modify_sizelimit()
3756{
3757    [ $DEBUG -eq 1 ] && ${ECHO} "In modify_sizelimit()"
3758
3759    # Here doc to modify sizelimit.
3760    ( cat <<EOF
3761dn: cn=config
3762changetype: modify
3763replace: nsslapd-sizelimit
3764nsslapd-sizelimit: ${IDS_SIZELIMIT}
3765EOF
3766) > ${TMPDIR}/ids_sizelimit
3767
3768    # Add the entry.
3769    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/ids_sizelimit ${VERB}"
3770    if [ $? -ne 0 ]; then
3771	${ECHO} "  ERROR: update of nsslapd-sizelimit failed!"
3772	cleanup
3773	exit 1
3774    fi
3775
3776    # Display messages for modifications made in patch.
3777    ${ECHO} "  ${STEP}. Changed sizelimit to ${IDS_SIZELIMIT} in cn=config."
3778    STEP=`expr $STEP + 1`
3779}
3780
3781
3782# modify_pwd_crypt(): Modify the passwd storage scheme to support CRYPT.
3783modify_pwd_crypt()
3784{
3785    [ $DEBUG -eq 1 ] && ${ECHO} "In modify_pwd_crypt()"
3786
3787    # Here doc to modify passwordstoragescheme.
3788    # IDS 5.2 moved passwordchangesceme off to a new data structure.
3789    if [ $IDS_MAJVER -le 5 ] && [ $IDS_MINVER -le 1 ]; then
3790	( cat <<EOF
3791dn: cn=config
3792changetype: modify
3793replace: passwordstoragescheme
3794passwordstoragescheme: crypt
3795EOF
3796	) > ${TMPDIR}/ids_crypt
3797    else
3798	( cat <<EOF
3799dn: cn=Password Policy,cn=config
3800changetype: modify
3801replace: passwordstoragescheme
3802passwordstoragescheme: crypt
3803EOF
3804	) > ${TMPDIR}/ids_crypt
3805    fi
3806
3807    # Add the entry.
3808    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/ids_crypt ${VERB}"
3809    if [ $? -ne 0 ]; then
3810	${ECHO} "  ERROR: update of passwordstoragescheme failed!"
3811	cleanup
3812	exit 1
3813    fi
3814
3815    # Display messages for modifications made in patch.
3816    ${ECHO} "  ${STEP}. Changed passwordstoragescheme to \"crypt\" in cn=config."
3817    STEP=`expr $STEP + 1`
3818}
3819
3820
3821#
3822# add_eq_indexes(): Add indexes to improve search performance.
3823#
3824add_eq_indexes()
3825{
3826    [ $DEBUG -eq 1 ] && ${ECHO} "In add_eq_indexes()"
3827
3828    # Set eq indexes to add.
3829    _INDEXES="uidNumber ipNetworkNumber gidnumber oncrpcnumber automountKey"
3830
3831    if [ -z "${IDS_DATABASE}" ]; then
3832	get_backend
3833    fi
3834
3835    # Set _EXT to use as shortcut.
3836    _EXT="cn=index,cn=${IDS_DATABASE},cn=ldbm database,cn=plugins,cn=config"
3837
3838    # Display message to id current step.
3839    ${ECHO} "  ${STEP}. Processing eq,pres indexes:"
3840    STEP=`expr $STEP + 1`
3841
3842    # For loop to create indexes.
3843    for i in ${_INDEXES}; do
3844	[ $DEBUG -eq 1 ] && ${ECHO} "  Adding index for ${i}"
3845
3846	# Check if entry exists first, if so, skip to next.
3847	${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${i},${_EXT}\" -s base \
3848	    \"objectclass=*\" > /dev/null 2>&1"
3849	if [ $? -eq 0 ]; then
3850	    # Display index skipped.
3851	    ${ECHO} "      ${i} (eq,pres) skipped already exists"
3852	    continue
3853	fi
3854
3855	# Here doc to create LDIF.
3856	( cat <<EOF
3857dn: cn=${i},${_EXT}
3858objectClass: top
3859objectClass: nsIndex
3860cn: ${i}
3861nsSystemIndex: false
3862nsIndexType: pres
3863nsIndexType: eq
3864EOF
3865) > ${TMPDIR}/index_${i}
3866
3867	# Add the index.
3868	${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/index_${i} ${VERB}"
3869	if [ $? -ne 0 ]; then
3870	    ${ECHO} "  ERROR: Adding EQ,PRES index for ${i} failed!"
3871	    cleanup
3872	    exit 1
3873	fi
3874
3875	# Build date for task name.
3876	_YR=`date '+%y'`
3877	_MN=`date '+%m'`
3878	_DY=`date '+%d'`
3879	_H=`date '+%H'`
3880	_M=`date '+%M'`
3881	_S=`date '+%S'`
3882
3883	# Build task name
3884	TASKNAME="${i}_${_YR}_${_MN}_${_DY}_${_H}_${_M}_${_S}"
3885
3886	# Build the task entry to add.
3887	( cat <<EOF
3888dn: cn=${TASKNAME}, cn=index, cn=tasks, cn=config
3889changetype: add
3890objectclass: top
3891objectclass: extensibleObject
3892cn: ${TASKNAME}
3893nsInstance: ${IDS_DATABASE}
3894nsIndexAttribute: ${i}
3895EOF
3896) > ${TMPDIR}/task_${i}
3897
3898	# Add the task.
3899	${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/task_${i} ${VERB}"
3900	if [ $? -ne 0 ]; then
3901	    ${ECHO} "  ERROR: Adding task for ${i} failed!"
3902	    cleanup
3903	    exit 1
3904	fi
3905
3906	# Wait for task to finish, display current status.
3907	while :
3908	do
3909	    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} \
3910	        -b \"cn=${TASKNAME}, cn=index, cn=tasks, cn=config\" -s base \
3911	        \"objectclass=*\" nstaskstatus > \"${TMPDIR}/istask_${i}\" 2>&1"
3912	    ${GREP} "${TASKNAME}" "${TMPDIR}/istask_${i}" > /dev/null 2>&1
3913	    if [ $? -ne 0 ]; then
3914		break
3915	    fi
3916	    TASK_STATUS=`${GREP} -i nstaskstatus "${TMPDIR}/istask_${i}" |
3917	        head -1 | cut -d: -f2`
3918	    ${ECHO} "      ${i} (eq,pres)  $TASK_STATUS                  \r\c"
3919	    ${ECHO} "$TASK_STATUS" | ${GREP} "Finished" > /dev/null 2>&1
3920	    if [ $? -eq 0 ]; then
3921		break
3922	    fi
3923	    sleep 2
3924	done
3925
3926	# Print newline because of \c.
3927	${ECHO} " "
3928    done
3929}
3930
3931
3932#
3933# add_sub_indexes(): Add indexes to improve search performance.
3934#
3935add_sub_indexes()
3936{
3937    [ $DEBUG -eq 1 ] && ${ECHO} "In add_sub_indexes()"
3938
3939    # Set eq indexes to add.
3940    _INDEXES="ipHostNumber membernisnetgroup nisnetgrouptriple"
3941
3942    # Set _EXT to use as shortcut.
3943    _EXT="cn=index,cn=${IDS_DATABASE},cn=ldbm database,cn=plugins,cn=config"
3944
3945
3946    # Display message to id current step.
3947    ${ECHO} "  ${STEP}. Processing eq,pres,sub indexes:"
3948    STEP=`expr $STEP + 1`
3949
3950    # For loop to create indexes.
3951    for i in ${_INDEXES}; do
3952	[ $DEBUG -eq 1 ] && ${ECHO} "  Adding index for ${i}"
3953
3954	# Check if entry exists first, if so, skip to next.
3955	${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${i},${_EXT}\" \
3956	    -s base \"objectclass=*\" > /dev/null 2>&1"
3957	if [ $? -eq 0 ]; then
3958	    # Display index skipped.
3959	    ${ECHO} "      ${i} (eq,pres,sub) skipped already exists"
3960	    continue
3961	fi
3962
3963	# Here doc to create LDIF.
3964	( cat <<EOF
3965dn: cn=${i},${_EXT}
3966objectClass: top
3967objectClass: nsIndex
3968cn: ${i}
3969nsSystemIndex: false
3970nsIndexType: pres
3971nsIndexType: eq
3972nsIndexType: sub
3973EOF
3974) > ${TMPDIR}/index_${i}
3975
3976	# Add the index.
3977	${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/index_${i} ${VERB}"
3978	if [ $? -ne 0 ]; then
3979	    ${ECHO} "  ERROR: Adding EQ,PRES,SUB index for ${i} failed!"
3980	    cleanup
3981	    exit 1
3982	fi
3983
3984	# Build date for task name.
3985	_YR=`date '+%y'`
3986	_MN=`date '+%m'`
3987	_DY=`date '+%d'`
3988	_H=`date '+%H'`
3989	_M=`date '+%M'`
3990	_S=`date '+%S'`
3991
3992	# Build task name
3993	TASKNAME="${i}_${_YR}_${_MN}_${_DY}_${_H}_${_M}_${_S}"
3994
3995	# Build the task entry to add.
3996	( cat <<EOF
3997dn: cn=${TASKNAME}, cn=index, cn=tasks, cn=config
3998changetype: add
3999objectclass: top
4000objectclass: extensibleObject
4001cn: ${TASKNAME}
4002nsInstance: ${IDS_DATABASE}
4003nsIndexAttribute: ${i}
4004EOF
4005) > ${TMPDIR}/task_${i}
4006
4007	# Add the task.
4008	${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/task_${i} ${VERB}"
4009	if [ $? -ne 0 ]; then
4010	    ${ECHO} "  ERROR: Adding task for ${i} failed!"
4011	    cleanup
4012	    exit 1
4013	fi
4014
4015	# Wait for task to finish, display current status.
4016	while :
4017	do
4018	    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} \
4019	        -b \"cn=${TASKNAME}, cn=index, cn=tasks, cn=config\" -s base \
4020	        \"objectclass=*\" nstaskstatus > \"${TMPDIR}/istask_${i}\" 2>&1"
4021	    ${GREP} "${TASKNAME}" "${TMPDIR}/istask_${i}" > /dev/null 2>&1
4022	    if [ $? -ne 0 ]; then
4023		break
4024	    fi
4025	    TASK_STATUS=`${GREP} -i nstaskstatus "${TMPDIR}/istask_${i}" |
4026	        head -1 | cut -d: -f2`
4027	    ${ECHO} "      ${i} (eq,pres,sub)  $TASK_STATUS                  \r\c"
4028	    ${ECHO} "$TASK_STATUS" | ${GREP} "Finished" > /dev/null 2>&1
4029	    if [ $? -eq 0 ]; then
4030		break
4031	    fi
4032	    sleep 2
4033	done
4034
4035	# Print newline because of \c.
4036	${ECHO} " "
4037    done
4038}
4039
4040
4041#
4042# add_vlv_indexes(): Add VLV indexes to improve search performance.
4043#
4044add_vlv_indexes()
4045{
4046    [ $DEBUG -eq 1 ] && ${ECHO} "In add_vlv_indexes()"
4047
4048    # Set eq indexes to add.
4049    # Note semi colon separators because some filters contain colons
4050    _INDEX1="${LDAP_DOMAIN}.getgrent;${LDAP_DOMAIN}_group_vlv_index;ou=group;objectClass=posixGroup"
4051    _INDEX2="${LDAP_DOMAIN}.gethostent;${LDAP_DOMAIN}_hosts_vlv_index;ou=hosts;objectClass=ipHost"
4052    _INDEX3="${LDAP_DOMAIN}.getnetent;${LDAP_DOMAIN}_networks_vlv_index;ou=networks;objectClass=ipNetwork"
4053    _INDEX4="${LDAP_DOMAIN}.getpwent;${LDAP_DOMAIN}_passwd_vlv_index;ou=people;objectClass=posixAccount"
4054    _INDEX5="${LDAP_DOMAIN}.getrpcent;${LDAP_DOMAIN}_rpc_vlv_index;ou=rpc;objectClass=oncRpc"
4055    _INDEX6="${LDAP_DOMAIN}.getspent;${LDAP_DOMAIN}_shadow_vlv_index;ou=people;objectClass=shadowAccount"
4056
4057    # Indexes added during NIS to LDAP transition
4058    _INDEX7="${LDAP_DOMAIN}.getauhoent;${LDAP_DOMAIN}_auho_vlv_index;automountmapname=auto_home;objectClass=automount"
4059    _INDEX8="${LDAP_DOMAIN}.getsoluent;${LDAP_DOMAIN}_solu_vlv_index;ou=people;objectClass=SolarisUserAttr"
4060    _INDEX9="${LDAP_DOMAIN}.getauduent;${LDAP_DOMAIN}_audu_vlv_index;ou=people;objectClass=SolarisAuditUser"
4061    _INDEX10="${LDAP_DOMAIN}.getauthent;${LDAP_DOMAIN}_auth_vlv_index;ou=SolarisAuthAttr;objectClass=SolarisAuthAttr"
4062    _INDEX11="${LDAP_DOMAIN}.getexecent;${LDAP_DOMAIN}_exec_vlv_index;ou=SolarisProfAttr;&(objectClass=SolarisExecAttr)(SolarisKernelSecurityPolicy=*)"
4063    _INDEX12="${LDAP_DOMAIN}.getprofent;${LDAP_DOMAIN}_prof_vlv_index;ou=SolarisProfAttr;&(objectClass=SolarisProfAttr)(SolarisAttrLongDesc=*)"
4064    _INDEX13="${LDAP_DOMAIN}.getmailent;${LDAP_DOMAIN}_mail_vlv_index;ou=aliases;objectClass=mailGroup"
4065    _INDEX14="${LDAP_DOMAIN}.getbootent;${LDAP_DOMAIN}__boot_vlv_index;ou=ethers;&(objectClass=bootableDevice)(bootParameter=*)"
4066    _INDEX15="${LDAP_DOMAIN}.getethent;${LDAP_DOMAIN}_ethers_vlv_index;ou=ethers;&(objectClass=ieee802Device)(macAddress=*)"
4067    _INDEX16="${LDAP_DOMAIN}.getngrpent;${LDAP_DOMAIN}_netgroup_vlv_index;ou=netgroup;objectClass=nisNetgroup"
4068    _INDEX17="${LDAP_DOMAIN}.getipnent;${LDAP_DOMAIN}_ipn_vlv_index;ou=networks;&(objectClass=ipNetwork)(cn=*)"
4069    _INDEX18="${LDAP_DOMAIN}.getmaskent;${LDAP_DOMAIN}_mask_vlv_index;ou=networks;&(objectClass=ipNetwork)(ipNetmaskNumber=*)"
4070    _INDEX19="${LDAP_DOMAIN}.getprent;${LDAP_DOMAIN}_pr_vlv_index;ou=printers;objectClass=printerService"
4071    _INDEX20="${LDAP_DOMAIN}.getip4ent;${LDAP_DOMAIN}_ip4_vlv_index;ou=hosts;&(objectClass=ipHost)(ipHostNumber=*.*)"
4072    _INDEX21="${LDAP_DOMAIN}.getip6ent;${LDAP_DOMAIN}_ip6_vlv_index;ou=hosts;&(objectClass=ipHost)(ipHostNumber=*:*)"
4073
4074    _INDEXES="$_INDEX1 $_INDEX2 $_INDEX3 $_INDEX4 $_INDEX5 $_INDEX6 $_INDEX7 $_INDEX8 $_INDEX9 $_INDEX10 $_INDEX11 $_INDEX12 $_INDEX13 $_INDEX14 $_INDEX15 $_INDEX16 $_INDEX17 $_INDEX18 $_INDEX19 $_INDEX20 $_INDEX21 "
4075
4076
4077    # Set _EXT to use as shortcut.
4078    _EXT="cn=${IDS_DATABASE},cn=ldbm database,cn=plugins,cn=config"
4079
4080
4081    # Display message to id current step.
4082    ${ECHO} "  ${STEP}. Processing VLV indexes:"
4083    STEP=`expr $STEP + 1`
4084
4085    # Reset temp file for vlvindex commands.
4086    [ -f ${TMPDIR}/ds5_vlvindex_list ] &&  rm ${TMPDIR}/ds5_vlvindex_list
4087    touch ${TMPDIR}/ds5_vlvindex_list
4088    [ -f ${TMPDIR}/ds6_vlvindex_list ] &&  rm ${TMPDIR}/ds6_vlvindex_list
4089    touch ${TMPDIR}/ds6_vlvindex_list
4090
4091    # Get the instance name from iDS server.
4092    _INSTANCE="<server-instance>"    # Default to old output.
4093
4094    eval "${LDAPSEARCH} -v ${LDAP_ARGS} -b \"cn=config\" -s base \"objectclass=*\" nsslapd-instancedir | ${GREP} 'nsslapd-instancedir=' | cut -d'=' -f2- > ${TMPDIR}/instance_name 2>&1"
4095
4096    ${GREP} "slapd-" ${TMPDIR}/instance_name > /dev/null 2>&1 # Check if seems right?
4097    if [ $? -eq 0 ]; then # If success, grab name after "slapd-".
4098	_INST_DIR=`cat ${TMPDIR}/instance_name`
4099	_INSTANCE=`basename "${_INST_DIR}" | cut -d'-' -f2-`
4100    fi
4101
4102    # For loop to create indexes.
4103    for p in ${_INDEXES}; do
4104	[ $DEBUG -eq 1 ] && ${ECHO} "  Adding index for ${i}"
4105
4106	# Break p (pair) into i and j parts.
4107        i=`${ECHO} $p | cut -d';' -f1`
4108        j=`${ECHO} $p | cut -d';' -f2`
4109        k=`${ECHO} $p | cut -d';' -f3`
4110        m=`${ECHO} $p | cut -d';' -f4`
4111
4112	# Set _jEXT to use as shortcut.
4113	_jEXT="cn=${j},${_EXT}"
4114
4115	# Check if entry exists first, if so, skip to next.
4116	${LDAPSEARCH} ${SERVER_ARGS} -b "cn=${i},${_jEXT}" -s base "objectclass=*" > /dev/null 2>&1
4117	if [ $? -eq 0 ]; then
4118	    # Display index skipped.
4119	    ${ECHO} "      ${i} vlv_index skipped already exists"
4120	    continue
4121	fi
4122
4123	# Compute the VLV Scope from the LDAP_SEARCH_SCOPE.
4124	# NOTE: A value of "base (0)" does not make sense.
4125        case "$LDAP_SEARCH_SCOPE" in
4126            sub) VLV_SCOPE="2" ;;
4127            *)   VLV_SCOPE="1" ;;
4128        esac
4129
4130	# Here doc to create LDIF.
4131	( cat <<EOF
4132dn: ${_jEXT}
4133objectClass: top
4134objectClass: vlvSearch
4135cn: ${j}
4136vlvbase: ${k},${LDAP_BASEDN}
4137vlvscope: ${VLV_SCOPE}
4138vlvfilter: (${m})
4139aci: (target="ldap:///${_jEXT}")(targetattr="*")(version 3.0; acl "Config";allow(read,search,compare)userdn="ldap:///anyone";)
4140
4141dn: cn=${i},${_jEXT}
4142cn: ${i}
4143vlvSort: cn uid
4144objectclass: top
4145objectclass: vlvIndex
4146EOF
4147) > ${TMPDIR}/vlv_index_${i}
4148
4149	# Add the index.
4150	${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/vlv_index_${i} ${VERB}"
4151	if [ $? -ne 0 ]; then
4152	    ${ECHO} "  ERROR: Adding VLV index for ${i} failed!"
4153	    cleanup
4154	    exit 1
4155	fi
4156
4157	# Print message that index was created.
4158	${ECHO} "      ${i} vlv_index   Entry created"
4159
4160	# Add command to list of vlvindex commands to run.
4161	${ECHO} "  directoryserver -s ${_INSTANCE} vlvindex -n ${IDS_DATABASE} -T ${i}" >> ${TMPDIR}/ds5_vlvindex_list
4162	${ECHO} "  <install-path>/bin/dsadm reindex -l -t ${i} <directory-instance-path> ${LDAP_SUFFIX}" >> ${TMPDIR}/ds6_vlvindex_list
4163    done
4164}
4165
4166
4167#
4168# display_vlv_cmds(): Display VLV index commands to run on server.
4169#
4170display_vlv_cmds()
4171{
4172    if [ -s "${TMPDIR}/ds5_vlvindex_list" -o \
4173	 -s "${TMPDIR}/ds6_vlvindex_list" ]; then
4174	display_msg display_vlv_list
4175    fi
4176
4177    if [ -s "${TMPDIR}/ds5_vlvindex_list" ]; then
4178	cat ${TMPDIR}/ds5_vlvindex_list
4179    fi
4180
4181    cat << EOF
4182
4183
4184EOF
4185
4186    if [ -s "${TMPDIR}/ds6_vlvindex_list" ]; then
4187	cat ${TMPDIR}/ds6_vlvindex_list
4188    fi
4189}
4190
4191
4192#
4193# update_schema_attr(): Update Schema to support Naming.
4194#
4195update_schema_attr()
4196{
4197    [ $DEBUG -eq 1 ] && ${ECHO} "In update_schema_attr()"
4198
4199    ( cat <<EOF
4200dn: cn=schema
4201changetype: modify
4202add: attributetypes
4203attributetypes: ( 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 )
4204attributetypes: ( 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 )
4205attributetypes: ( 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 )
4206attributetypes: ( 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 )
4207attributetypes: ( 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 )
4208attributetypes: ( 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 )
4209attributetypes: ( 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 )
4210attributetypes: ( 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 )
4211attributetypes: ( 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 )
4212attributetypes: ( 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 )
4213attributetypes: ( 2.16.840.1.113730.3.1.30 NAME 'mgrpRFC822MailMember' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4214attributetypes: ( 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 )
4215attributetypes: ( 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 )
4216attributetypes: ( 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 )
4217attributetypes: ( 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 )
4218attributetypes: ( 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 )
4219attributetypes: ( 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 )
4220attributetypes: ( 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 )
4221attributetypes: ( 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 )
4222attributetypes: ( 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 )
4223attributetypes: ( 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 )
4224attributetypes: ( 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 )
4225attributetypes: ( 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 )
4226attributetypes: ( 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 )
4227attributetypes: ( 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 )
4228attributetypes: ( 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 )
4229attributetypes: ( 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 )
4230attributetypes: ( 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 )
4231attributetypes: ( 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 )
4232attributetypes: ( 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 )
4233attributetypes: ( 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 )
4234attributetypes: ( 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 )
4235attributetypes: ( 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 )
4236attributetypes: ( 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 )
4237attributetypes: ( 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 )
4238attributetypes: ( 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 )
4239attributetypes: ( 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 )
4240attributetypes: ( 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 )
4241attributetypes: ( 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 )
4242attributetypes: ( 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 )
4243attributetypes: ( 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 )
4244attributetypes: ( 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 )
4245attributetypes: ( 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 )
4246attributetypes: ( 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 )
4247attributetypes: ( 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 )
4248attributetypes: ( 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 )
4249attributetypes: ( 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 )
4250attributetypes: ( 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 )
4251attributetypes: ( 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 )
4252attributetypes: ( 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 )
4253attributetypes: ( 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 )
4254attributetypes: ( 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 )
4255attributetypes: ( 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 )
4256attributetypes: ( 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 )
4257attributetypes: ( 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 )
4258attributetypes: ( 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 )
4259attributetypes: ( 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 )
4260attributetypes: ( 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 )
4261attributetypes: ( 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 )
4262attributetypes: ( 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 )
4263attributetypes: ( 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 )
4264attributetypes: ( 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 )
4265attributetypes: ( 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 )
4266attributetypes: ( 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 )
4267attributetypes: ( 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} )
4268attributetypes: ( 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 )
4269attributetypes: ( 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 )
4270attributetypes: ( 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} )
4271attributetypes: ( 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} )
4272attributetypes: ( 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} )
4273attributetypes: ( 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 )
4274attributetypes: ( 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} )
4275attributetypes: ( 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 )
4276attributetypes: ( 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 )
4277attributetypes: ( 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} )
4278attributetypes: ( 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 )
4279attributetypes: ( 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} )
4280attributetypes: ( 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} )
4281attributetypes: ( 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} )
4282attributetypes: ( 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} )
4283attributetypes: ( 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} )
4284attributetypes: ( 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 )
4285attributetypes: ( 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 )
4286attributetypes: ( 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 )
4287attributetypes: ( 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 )
4288attributetypes: ( 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 )
4289attributetypes: ( 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} )
4290attributetypes: ( 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} )
4291attributetypes: ( 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} )
4292attributetypes: ( 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} )
4293attributetypes: ( 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 )
4294attributetypes: ( 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 )
4295attributetypes: ( 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 )
4296attributetypes: ( 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 )
4297attributetypes: ( 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 )
4298EOF
4299) > ${TMPDIR}/schema_attr
4300
4301    # Add the entry.
4302    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/schema_attr ${VERB}"
4303    if [ $? -ne 0 ]; then
4304	${ECHO} "  ERROR: update of schema attributes failed!"
4305	cleanup
4306	exit 1
4307    fi
4308
4309    # Display message that schema is updated.
4310    ${ECHO} "  ${STEP}. Schema attributes have been updated."
4311    STEP=`expr $STEP + 1`
4312}
4313
4314
4315#
4316# update_schema_obj(): Update the schema objectclass definitions.
4317#
4318update_schema_obj()
4319{
4320    [ $DEBUG -eq 1 ] && ${ECHO} "In update_schema_obj()"
4321
4322    # Add the objectclass definitions.
4323    ( cat <<EOF
4324dn: cn=schema
4325changetype: modify
4326add: objectclasses
4327objectclasses: ( 1.3.6.1.1.1.2.14 NAME 'NisKeyObject' SUP top MUST ( cn $ nisPublickey $ nisSecretkey ) MAY ( uidNumber $ description ) )
4328
4329dn: cn=schema
4330changetype: modify
4331add: objectclasses
4332objectclasses: ( 1.3.6.1.1.1.2.15 NAME 'nisDomainObject' SUP top MUST nisDomain )
4333
4334dn: cn=schema
4335changetype: modify
4336add: objectclasses
4337objectclasses: ( 1.3.6.1.1.1.2.16 NAME 'automountMap' SUP top MUST automountMapName MAY description )
4338
4339dn: cn=schema
4340changetype: modify
4341add: objectclasses
4342objectclasses: ( 1.3.6.1.1.1.2.17 NAME 'automount' SUP top MUST ( automountKey $ automountInformation ) MAY description )
4343
4344dn: cn=schema
4345changetype: modify
4346add: objectclasses
4347objectclasses: ( 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 ) )
4348
4349dn: cn=schema
4350changetype: modify
4351add: objectclasses
4352objectclasses: ( 2.16.840.1.113730.3.2.4 NAME 'mailGroup' SUP top MUST mail MAY ( cn $ mgrpRFC822MailMember ) )
4353
4354dn: cn=schema
4355changetype: modify
4356add: objectclasses
4357objectclasses: ( 1.3.6.1.4.1.42.2.27.1.2.5 NAME 'nisMailAlias' SUP top MUST cn MAY rfc822mailMember )
4358
4359dn: cn=schema
4360changetype: modify
4361add: objectclasses
4362objectclasses: ( 1.3.6.1.4.1.42.2.27.1.2.6 NAME 'nisNetId' SUP top MUST cn MAY ( nisNetIdUser $ nisNetIdGroup $ nisNetIdHost ) )
4363
4364dn: cn=schema
4365changetype: modify
4366add: objectclasses
4367objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.2 NAME 'SolarisAuditUser' SUP top AUXILIARY MAY ( SolarisAuditAlways $ SolarisAuditNever ) )
4368
4369dn: cn=schema
4370changetype: modify
4371add: objectclasses
4372objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.3 NAME 'SolarisUserAttr' SUP top AUXILIARY MAY ( SolarisUserQualifier $ SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrKeyValue ) )
4373
4374dn: cn=schema
4375changetype: modify
4376add: objectclasses
4377objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.4 NAME 'SolarisAuthAttr' SUP top MUST cn MAY ( SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrShortDesc $ SolarisAttrLongDesc $ SolarisAttrKeyValue ) )
4378
4379dn: cn=schema
4380changetype: modify
4381add: objectclasses
4382objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.5 NAME 'SolarisProfAttr' SUP top MUST cn MAY ( SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrLongDesc $ SolarisAttrKeyValue ) )
4383
4384dn: cn=schema
4385changetype: modify
4386add: objectclasses
4387objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.6 NAME 'SolarisExecAttr' SUP top AUXILIARY MAY ( SolarisKernelSecurityPolicy $ SolarisProfileType $ SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisProfileID $ SolarisAttrKeyValue ) )
4388
4389dn: cn=schema
4390changetype: modify
4391add: objectclasses
4392objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.1 NAME 'SolarisProject' SUP top MUST ( SolarisProjectID $ SolarisProjectName ) MAY ( memberUid $ memberGid $ description $ SolarisProjectAttr ) )
4393
4394dn: cn=schema
4395changetype: modify
4396add: objectclasses
4397objectclasses: ( 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 ) )
4398
4399dn: cn=schema
4400changetype: modify
4401add: objectclasses
4402objectclasses: ( 1.3.18.0.2.6.2549 NAME 'slpService' DESC 'DUMMY definition' SUP top MUST objectclass )
4403
4404dn: cn=schema
4405changetype: modify
4406add: objectclasses
4407objectclasses: ( 1.3.18.0.2.6.254 NAME 'slpServicePrinter' DESC 'Service Location Protocol (SLP) information.' SUP slpService AUXILIARY )
4408
4409dn: cn=schema
4410changetype: modify
4411add: objectclasses
4412objectclasses: ( 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 ) )
4413
4414dn: cn=schema
4415changetype: modify
4416add: objectclasses
4417objectclasses: ( 1.3.18.0.2.6.255 NAME 'printerService' DESC 'Printer information.' SUP printerAbstract STRUCTURAL MAY ( printer-uri $ printer-xri-supported ) )
4418
4419dn: cn=schema
4420changetype: modify
4421add: objectclasses
4422objectclasses: ( 1.3.18.0.2.6.257 NAME 'printerServiceAuxClass' DESC 'Printer information.' SUP printerAbstract AUXILIARY MAY ( printer-uri $ printer-xri-supported ) )
4423
4424dn: cn=schema
4425changetype: modify
4426add: objectclasses
4427objectclasses: ( 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 ) )
4428
4429dn: cn=schema
4430changetype: modify
4431add: objectclasses
4432objectclasses: ( 1.3.18.0.2.6.253 NAME 'printerLPR' DESC 'LPR information.' SUP top AUXILIARY MUST printer-name MAY printer-aliases )
4433
4434dn: cn=schema
4435changetype: modify
4436add: objectclasses
4437objectclasses: ( 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 ) )
4438
4439dn: cn=schema
4440changetype: modify
4441add: objectclasses
4442objectclasses:	( 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 ) )
4443
4444dn: cn=schema
4445changetype: modify
4446add: objectclasses
4447objectclasses:  ( 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 )
4448
4449dn: cn=schema
4450changetype: modify
4451add: objectclasses
4452objectclasses:	( 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 )
4453EOF
4454) > ${TMPDIR}/schema_obj
4455
4456    # Add the entry.
4457    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/schema_obj ${VERB}"
4458    if [ $? -ne 0 ]; then
4459	${ECHO} "  ERROR: update of schema objectclass definitions failed!"
4460	cleanup
4461	exit 1
4462    fi
4463
4464    # Display message that schema is updated.
4465    ${ECHO} "  ${STEP}. Schema objectclass definitions have been added."
4466    STEP=`expr $STEP + 1`
4467}
4468
4469
4470#
4471# modify_top_aci(): Modify the ACI for the top entry to disable self modify
4472#                   of user attributes.
4473#
4474modify_top_aci()
4475{
4476    [ $DEBUG -eq 1 ] && ${ECHO} "In modify_top_aci()"
4477
4478    # Set ACI Name
4479    ACI_NAME="LDAP_Naming_Services_deny_write_access"
4480
4481    # Search for ACI_NAME
4482    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_top_aci 2>&1"
4483    if [ $? -ne 0 ]; then
4484	${ECHO} "Error searching aci for ${LDAP_BASEDN}"
4485	cat ${TMPDIR}/chk_top_aci
4486	cleanup
4487	exit 1
4488    fi
4489
4490    # Display "already exists" message if necessary. For shadow update,
4491    # check also if the deny self-write to userPassword has been done.
4492    # If not, more to do, don't display the message.
4493    MSG="Top level ACI ${ACI_NAME} already exists for ${LDAP_BASEDN}."
4494    ${GREP} "${ACI_NAME}" ${TMPDIR}/chk_top_aci > /dev/null 2>&1
4495    if [ $? -eq 0 ]; then
4496	if [ "$LDAP_ENABLE_SHADOW_UPDATE" != "TRUE" ];then
4497	    ${ECHO} "  ${STEP}. $MSG"
4498	    STEP=`expr $STEP + 1`
4499	    return 0
4500	else
4501	    ${GREP} "${ACI_NAME}" ${TMPDIR}/chk_top_aci | ${GREP} -i  \
4502	    userPassword > /dev/null 2>&1
4503	    if [ $? -eq 0 ]; then
4504		# userPassword is already on the deny list, no more to do
4505		if [ $EXISTING_PROFILE -eq 1 ];then
4506		    ${ECHO} "  NOT SET: $MSG"
4507		else
4508		    ${ECHO} "  ${STEP}. $MSG"
4509		    STEP=`expr $STEP + 1`
4510		fi
4511	        return 0
4512	    fi
4513	fi
4514    fi
4515
4516    # if shadow update is enabled, also deny self-write to userPassword
4517    if [ "$LDAP_ENABLE_SHADOW_UPDATE" = "TRUE" ];then
4518	PWD_SELF_CHANGE="userPassword||"
4519    else
4520	PWD_SELF_CHANGE=""
4521    fi
4522
4523    # Crate LDIF for top level ACI.
4524    ( cat <<EOF
4525dn: ${LDAP_BASEDN}
4526changetype: modify
4527add: aci
4528aci: (targetattr = "${PWD_SELF_CHANGE}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";)
4529-
4530EOF
4531) > ${TMPDIR}/top_aci
4532
4533    # Add the entry.
4534    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/top_aci ${VERB}"
4535    if [ $? -ne 0 ]; then
4536	${ECHO} "  ERROR: Modify of top level ACI failed! (restricts self modify)"
4537	cleanup
4538	exit 1
4539    fi
4540
4541    # Display message that schema is updated.
4542    MSG="ACI for ${LDAP_BASEDN} modified to disable self modify."
4543    if [ $EXISTING_PROFILE -eq 1 ];then
4544	${ECHO} "  ACI SET: $MSG"
4545    else
4546	${ECHO} "  ${STEP}. $MSG"
4547	STEP=`expr $STEP + 1`
4548    fi
4549}
4550
4551#
4552# add_vlv_aci(): Add access control information (aci) for VLV.
4553#
4554add_vlv_aci()
4555{
4556    [ $DEBUG -eq 1 ] && ${ECHO} "In add_vlv_aci()"
4557
4558    # Add the VLV ACI.
4559    ( cat <<EOF
4560dn: oid=2.16.840.1.113730.3.4.9,cn=features,cn=config
4561changetype: modify
4562replace: aci
4563aci: (targetattr != "aci") (version 3.0; acl "VLV Request Control"; allow(read,search,compare) userdn = "ldap:///anyone";)
4564EOF
4565) > ${TMPDIR}/vlv_aci
4566
4567    # Add the entry.
4568    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/vlv_aci ${VERB}"
4569    if [ $? -ne 0 ]; then
4570	${ECHO} "  ERROR: Add of VLV ACI failed!"
4571	cleanup
4572	exit 1
4573    fi
4574
4575    # Display message that schema is updated.
4576    ${ECHO} "  ${STEP}. Add of VLV Access Control Information (ACI)."
4577    STEP=`expr $STEP + 1`
4578}
4579
4580
4581#
4582# set_nisdomain(): Add the NisDomainObject to the Base DN.
4583#
4584set_nisdomain()
4585{
4586    [ $DEBUG -eq 1 ] && ${ECHO} "In set_nisdomain()"
4587
4588    # Check if nisDomain is already set.
4589    ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base \
4590	\"objectclass=*\"" > ${TMPDIR}/chk_nisdomain 2>&1
4591    ${EVAL} "${GREP} -i nisDomain ${TMPDIR}/chk_nisdomain ${VERB}"
4592    if [ $? -eq 0 ]; then
4593	${ECHO} "  ${STEP}. NisDomainObject for ${LDAP_BASEDN} was already set."
4594	STEP=`expr $STEP + 1`
4595	return 0
4596    fi
4597
4598    # Add the new top level containers.
4599    ( cat <<EOF
4600dn: ${LDAP_BASEDN}
4601changetype: modify
4602objectclass: nisDomainObject
4603nisdomain: ${LDAP_DOMAIN}
4604EOF
4605) > ${TMPDIR}/nis_domain
4606
4607    # Add the entry.
4608    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/nis_domain ${VERB}"
4609    if [ $? -ne 0 ]; then
4610	${ECHO} "  ERROR: update of NisDomainObject in ${LDAP_BASEDN} failed."
4611	cleanup
4612	exit 1
4613    fi
4614
4615    # Display message that schema is updated.
4616    ${ECHO} "  ${STEP}. NisDomainObject added to ${LDAP_BASEDN}."
4617    STEP=`expr $STEP + 1`
4618}
4619
4620
4621#
4622# check_attrName(): Check that the attribute name is valid.
4623#              $1   Key to check.
4624#         Returns   0 : valid name	1 : invalid name
4625#
4626check_attrName()
4627{
4628    [ $DEBUG -eq 1 ] && ${ECHO} "In check_attrName()"
4629    [ $DEBUG -eq 1 ] && ${ECHO} "check_attrName: Input Param = $1"
4630
4631    ${ECHO} $1 | ${EGREP} '^[0-9]+(\.[0-9]+)*$' > /dev/null 2>&1
4632    if [ $? -eq 0 ]; then
4633	${EVAL} "${LDAPSEARCH} ${SERVER_ARGS} -b cn=schema -s base \"objectclass=*\" \
4634			attributeTypes | ${EGREP} -i '^attributetypes[ ]*=[ ]*\([ ]*$1 ' ${VERB}"
4635    else
4636	${EVAL} "${LDAPSEARCH} ${SERVER_ARGS} -b cn=schema -s base \"objectclass=*\" \
4637			attributeTypes | ${EGREP} -i \"'$1'\" ${VERB}"
4638    fi
4639
4640    if [ $? -ne 0 ]; then
4641	return 1
4642    else
4643	return 0
4644    fi
4645}
4646
4647
4648#
4649# get_objectclass():   Determine the objectclass for the given attribute name
4650#              $1   Attribute name to check.
4651#      _ATTR_NAME   Return value, Object Name or NULL if unknown to idsconfig.
4652#
4653#      NOTE: An attribute name can be valid but still we might not be able
4654#            to determine the objectclass from the table.
4655#            In such cases, the user needs to create the necessary object(s).
4656#
4657get_objectclass()
4658{
4659    [ $DEBUG -eq 1 ] && ${ECHO} "In get_objectclass()"
4660    [ $DEBUG -eq 1 ] && ${ECHO} "get_objectclass: Input Param = $1"
4661
4662    # Set return value to NULL string.
4663    _ATTR_NAME=""
4664
4665    # Test key for type:
4666    case `${ECHO} ${1} | tr '[A-Z]' '[a-z]'` in
4667	ou | organizationalunitname | 2.5.4.11) _ATTR_NAME="organizationalUnit" ;;
4668	dc | domaincomponent | 0.9.2342.19200300.100.1.25) _ATTR_NAME="domain" ;;
4669	 o | organizationname | 2.5.4.10) _ATTR_NAME="organization" ;;
4670	 c | countryname | 2.5.4.6) _ATTR_NAME="country" ;;
4671	 *)  _ATTR_NAME="" ;;
4672    esac
4673
4674    [ $DEBUG -eq 1 ] && ${ECHO} "get_objectclass: _ATTR_NAME = $_ATTR_NAME"
4675}
4676
4677
4678#
4679# add_base_objects(): Add any necessary base objects.
4680#
4681add_base_objects()
4682{
4683    [ $DEBUG -eq 1 ] && ${ECHO} "In add_base_objects()"
4684
4685    # Convert to lower case for basename.
4686    format_string "${LDAP_BASEDN}"
4687    LOWER_BASEDN="${FMT_STR}"
4688    format_string "${LDAP_SUFFIX}"
4689    LOWER_SUFFIX="${FMT_STR}"
4690
4691    [ $DEBUG -eq 1 ] && ${ECHO} "LOWER_BASEDN: ${LOWER_BASEDN}"
4692    [ $DEBUG -eq 1 ] && ${ECHO} "LOWER_SUFFIX: ${LOWER_SUFFIX}"
4693
4694    # Create additional components.
4695    if [ "${LOWER_BASEDN}" = "${LOWER_SUFFIX}" ]; then
4696	[ $DEBUG -eq 1 ] && ${ECHO} "Base DN and Suffix equivalent"
4697    else
4698	# first, test that the suffix is valid
4699	dcstmp=`basename "${LOWER_BASEDN}" "${LOWER_SUFFIX}"`
4700	if [ "$dcstmp" = "${LOWER_BASEDN}" ]; then
4701	    # should not happen since check_basedn_suffix() succeeded
4702	    ${ECHO} "Invalid suffix ${LOWER_SUFFIX}"
4703	    ${ECHO} "for Base DN ${LOWER_BASEDN}"
4704	    cleanup
4705	    exit 1
4706	fi
4707	# OK, suffix is valid, start working with LDAP_BASEDN
4708	# field separator is ',' (i.e., space is a valid character)
4709	dcstmp2="`${ECHO} ${LDAP_BASEDN} |
4710		sed -e 's/[ ]*,[ ]*/,/g' -e 's/[ ]*=[ ]*/=/g'`"
4711	dcs=""
4712	# use dcstmp to count the loop, and dcstmp2 to get the correct
4713	# string case
4714	# dcs should be in reverse order, only for these components
4715	# that need to be added
4716	while [ -n "${dcstmp}" ]
4717	do
4718	    i2=`${ECHO} "$dcstmp2" | cut -f1 -d','`
4719	    dk=`${ECHO} $i2 | awk -F= '{print $1}'`
4720	    dc=`${ECHO} $i2 | awk -F= '{print $2}'`
4721	    dcs="$dk=$dc,$dcs";
4722	    dcstmp2=`${ECHO} "$dcstmp2" | cut -f2- -d','`
4723	    dcstmp=`${ECHO} "$dcstmp" | cut -f2- -d','`
4724	    [ $DEBUG -eq 1 ] && \
4725		${ECHO} "dcs: ${dcs}\ndcstmp: ${dcstmp}\ndcstmp2: ${dcstmp2}\n"
4726	done
4727
4728
4729
4730	lastdc=${LDAP_SUFFIX}
4731	dc=`${ECHO} "${dcs}" | cut -f1 -d','`
4732	dcstmp=`${ECHO} "${dcs}" | cut -f2- -d','`
4733	while [ -n "${dc}" ]; do
4734	    # Get Key and component from $dc.
4735	    dk2=`${ECHO} $dc | awk -F= '{print $1}'`
4736	    dc2=`${ECHO} $dc | awk -F= '{print $2}'`
4737
4738	    # At this point, ${dk2} is a valid attribute name
4739
4740	    # Check if entry exists first, if so, skip to next.
4741	    ${LDAPSEARCH} ${SERVER_ARGS} -b "${dk2}=${dc2},$lastdc" -s base "objectclass=*" > /dev/null 2>&1
4742	    if [ $? -eq 0 ]; then
4743	        # Set the $lastdc to new dc.
4744	        lastdc="${dk2}=${dc2},$lastdc"
4745
4746		# Process next component.
4747		dc=`${ECHO} "${dcstmp}" | cut -f1 -d','`
4748		dcstmp=`${ECHO} "${dcstmp}" | cut -f2- -d','`
4749		continue
4750
4751	    fi
4752
4753	    # Determine the objectclass for the entry.
4754            get_objectclass $dk2
4755	    OBJ_Name=${_ATTR_NAME}
4756	    if [ "${OBJ_Name}" = "" ]; then
4757	        ${ECHO} "Cannot determine objectclass for $dk2"
4758	        ${ECHO} "Please create ${dk2}=${dc2},$lastdc entry and rerun idsconfig"
4759	        exit 1
4760	    fi
4761
4762	    # Add the new container.
4763	    ( cat <<EOF
4764dn: ${dk2}=${dc2},$lastdc
4765${dk2}: $dc2
4766objectClass: top
4767objectClass: ${OBJ_Name}
4768EOF
4769) > ${TMPDIR}/base_objects
4770
4771
4772	    # Set the $lastdc to new dc.
4773	    lastdc="${dk2}=${dc2},$lastdc"
4774
4775	    # Add the entry.
4776	    ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/base_objects ${VERB}"
4777	    if [ $? -ne 0 ]; then
4778		${ECHO} "  ERROR: update of base objects ${dc} failed."
4779		cleanup
4780		exit 1
4781	    fi
4782
4783	    # Display message that schema is updated.
4784	    ${ECHO} "  ${STEP}. Created DN component ${dc}."
4785	    STEP=`expr $STEP + 1`
4786
4787	    # Process next component.
4788	    dc=`${ECHO} "${dcstmp}" | cut -f1 -d','`
4789	    dcstmp=`${ECHO} "${dcstmp}" | cut -f2- -d','`
4790	done
4791    fi
4792}
4793
4794
4795#
4796# add_new_containers(): Add the top level classes.
4797#
4798#    $1 = Base DN
4799#
4800add_new_containers()
4801{
4802    [ $DEBUG -eq 1 ] && ${ECHO} "In add_new_containers()"
4803
4804    for ou in people group rpc protocols networks netgroup \
4805	aliases hosts services ethers profile printers projects \
4806	SolarisAuthAttr SolarisProfAttr Timezone ipTnet ; do
4807
4808	# Check if nismaps already exist.
4809	eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"ou=${ou},${LDAP_BASEDN}\" -s base \"objectclass=*\" ${VERB}"
4810	if [ $? -eq 0 ]; then
4811	    continue
4812	fi
4813
4814	# Create TMP file to add.
4815	( cat <<EOF
4816dn: ou=${ou},${LDAP_BASEDN}
4817ou: ${ou}
4818objectClass: top
4819objectClass: organizationalUnit
4820EOF
4821) > ${TMPDIR}/toplevel.${ou}
4822
4823	# Add the entry.
4824	${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/toplevel.${ou} ${VERB}"
4825	if [ $? -ne 0 ]; then
4826	    ${ECHO} "  ERROR: Add of ou=${ou} container failed!"
4827	    cleanup
4828	    exit 1
4829	fi
4830    done
4831
4832    # Display message that top level OU containers complete.
4833    ${ECHO} "  ${STEP}. Top level \"ou\" containers complete."
4834    STEP=`expr $STEP + 1`
4835}
4836
4837
4838#
4839# add_auto_maps(): Add the automount map entries.
4840#
4841# auto_home, auto_direct, auto_master, auto_shared
4842#
4843add_auto_maps()
4844{
4845    [ $DEBUG -eq 1 ] && ${ECHO} "In add_auto_maps()"
4846
4847    # Set AUTO_MAPS for maps to create.
4848    AUTO_MAPS="auto_home auto_direct auto_master auto_shared"
4849
4850    for automap in $AUTO_MAPS; do
4851	# Check if automaps already exist.
4852	eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"automountMapName=${automap},${LDAP_BASEDN}\" -s base \"objectclass=*\" ${VERB}"
4853	if [ $? -eq 0 ]; then
4854	    continue
4855	fi
4856
4857	# Create the tmp file to add.
4858	( cat <<EOF
4859dn: automountMapName=${automap},${LDAP_BASEDN}
4860automountMapName: ${automap}
4861objectClass: top
4862objectClass: automountMap
4863EOF
4864) > ${TMPDIR}/automap.${automap}
4865
4866	# Add the entry.
4867	${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/automap.${automap} ${VERB}"
4868	if [ $? -ne 0 ]; then
4869	    ${ECHO} "  ERROR: Add of automap ${automap} failed!"
4870	    cleanup
4871	    exit 1
4872	fi
4873    done
4874
4875    # Display message that automount entries are updated.
4876    ${ECHO} "  ${STEP}. automount maps: $AUTO_MAPS processed."
4877    STEP=`expr $STEP + 1`
4878}
4879
4880
4881#
4882# add_proxyagent(): Add entry for nameservice to use to access server.
4883#
4884add_proxyagent()
4885{
4886    [ $DEBUG -eq 1 ] && ${ECHO} "In add_proxyagent()"
4887
4888    # Check if proxy agent already exists.
4889    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_PROXYAGENT}\" -s base \"objectclass=*\" ${VERB}"
4890    if [ $? -eq 0 ]; then
4891	${ECHO} "  ${STEP}. Proxy Agent ${LDAP_PROXYAGENT} already exists."
4892	STEP=`expr $STEP + 1`
4893	return 0
4894    fi
4895
4896    # Get cn and sn names from LDAP_PROXYAGENT.
4897    cn_tmp=`${ECHO} ${LDAP_PROXYAGENT} | cut -f1 -d, | cut -f2 -d=`
4898
4899    # Create the tmp file to add.
4900    ( cat <<EOF
4901dn: ${LDAP_PROXYAGENT}
4902cn: ${cn_tmp}
4903sn: ${cn_tmp}
4904objectclass: top
4905objectclass: person
4906userpassword: ${LDAP_PROXYAGENT_CRED}
4907EOF
4908) > ${TMPDIR}/proxyagent
4909
4910    # Add the entry.
4911    ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/proxyagent ${VERB}"
4912    if [ $? -ne 0 ]; then
4913	${ECHO} "  ERROR: Adding proxyagent failed!"
4914	cleanup
4915	exit 1
4916    fi
4917
4918    # Display message that schema is updated.
4919    ${ECHO} "  ${STEP}. Proxy Agent ${LDAP_PROXYAGENT} added."
4920    STEP=`expr $STEP + 1`
4921}
4922
4923#
4924# allow_proxy_read_pw(): Give Proxy Agent read permission for password.
4925#
4926allow_proxy_read_pw()
4927{
4928    [ $DEBUG -eq 1 ] && ${ECHO} "In allow_proxy_read_pw()"
4929
4930    # Set ACI Name
4931    PROXY_ACI_NAME="LDAP_Naming_Services_proxy_password_read"
4932
4933    # Search for ACI_NAME
4934    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_proxyread_aci 2>&1"
4935    ${GREP} "${PROXY_ACI_NAME}" ${TMPDIR}/chk_proxyread_aci > /dev/null 2>&1
4936    if [ $? -eq 0 ]; then
4937	${ECHO} "  ${STEP}. Proxy ACI ${PROXY_ACI_NAME=} already exists for ${LDAP_BASEDN}."
4938	STEP=`expr $STEP + 1`
4939	return 0
4940    fi
4941
4942    # Create the tmp file to add.
4943    ( cat <<EOF
4944dn: ${LDAP_BASEDN}
4945changetype: modify
4946add: aci
4947aci: (target="ldap:///${LDAP_BASEDN}")(targetattr="userPassword")(version 3.0; acl ${PROXY_ACI_NAME}; allow (compare,read,search) userdn = "ldap:///${LDAP_PROXYAGENT}";)
4948EOF
4949) > ${TMPDIR}/proxy_read
4950
4951    # Add the entry.
4952    ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/proxy_read ${VERB}"
4953    if [ $? -ne 0 ]; then
4954	${ECHO} "  ERROR: Allow ${LDAP_PROXYAGENT} to read password failed!"
4955	cleanup
4956	exit 1
4957    fi
4958
4959    # Display message that schema is updated.
4960    ${ECHO} "  ${STEP}. Give ${LDAP_PROXYAGENT} read permission for password."
4961    STEP=`expr $STEP + 1`
4962}
4963
4964#
4965# add_profile(): Add client profile to server.
4966#
4967add_profile()
4968{
4969    [ $DEBUG -eq 1 ] && ${ECHO} "In add_profile()"
4970
4971    # If profile name already exists, DELETE it, and add new one.
4972    eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${LDAP_PROFILE_NAME},ou=profile,${LDAP_BASEDN}\" -s base \"objectclass=*\" ${VERB}"
4973    if [ $? -eq 0 ]; then
4974	# Create Delete file.
4975	( cat <<EOF
4976cn=${LDAP_PROFILE_NAME},ou=profile,${LDAP_BASEDN}
4977EOF
4978) > ${TMPDIR}/del_profile
4979
4980	# Check if DEL_OLD_PROFILE is set.  (If not ERROR)
4981	if [ $DEL_OLD_PROFILE -eq 0 ]; then
4982	    ${ECHO} "ERROR: Profile name ${LDAP_PROFILE_NAME} exists! Add failed!"
4983	    exit 1
4984	fi
4985
4986	# Delete the OLD profile.
4987	${EVAL} "${LDAPDELETE} ${LDAP_ARGS} -f ${TMPDIR}/del_profile ${VERB}"
4988	if [ $? -ne 0 ]; then
4989	    ${ECHO} "  ERROR: Attempt to DELETE profile failed!"
4990	    cleanup
4991	    exit 1
4992	fi
4993    fi
4994
4995    # Build the "ldapclient genprofile" command string to execute.
4996    GEN_CMD="ldapclient genprofile -a \"profileName=${LDAP_PROFILE_NAME}\""
4997
4998    # Add required argument defaultSearchBase.
4999    GEN_CMD="${GEN_CMD} -a \"defaultSearchBase=${LDAP_BASEDN}\""
5000
5001    # Add optional parameters.
5002    [ -n "$LDAP_SERVER_LIST" ] && \
5003	GEN_CMD="${GEN_CMD} -a \"defaultServerList=${LDAP_SERVER_LIST}\""
5004    [ -n "$LDAP_SEARCH_SCOPE" ] && \
5005	GEN_CMD="${GEN_CMD} -a \"defaultSearchScope=${LDAP_SEARCH_SCOPE}\""
5006    [ -n "$LDAP_CRED_LEVEL" ] && \
5007	GEN_CMD="${GEN_CMD} -a \"credentialLevel=${LDAP_CRED_LEVEL}\""
5008    [ -n "$LDAP_AUTHMETHOD" ] && \
5009	GEN_CMD="${GEN_CMD} -a \"authenticationMethod=${LDAP_AUTHMETHOD}\""
5010    [ -n "$LDAP_FOLLOWREF" ] && \
5011	GEN_CMD="${GEN_CMD} -a \"followReferrals=${LDAP_FOLLOWREF}\""
5012    [ -n "$LDAP_SEARCH_TIME_LIMIT" ] && \
5013	GEN_CMD="${GEN_CMD} -a \"searchTimeLimit=${LDAP_SEARCH_TIME_LIMIT}\""
5014    [ -n "$LDAP_PROFILE_TTL" ] && \
5015	GEN_CMD="${GEN_CMD} -a \"profileTTL=${LDAP_PROFILE_TTL}\""
5016    [ -n "$LDAP_BIND_LIMIT" ] && \
5017	GEN_CMD="${GEN_CMD} -a \"bindTimeLimit=${LDAP_BIND_LIMIT}\""
5018    [ -n "$LDAP_PREF_SRVLIST" ] && \
5019	GEN_CMD="${GEN_CMD} -a \"preferredServerList=${LDAP_PREF_SRVLIST}\""
5020    [ -n "$LDAP_SRV_AUTHMETHOD_PAM" ] && \
5021	GEN_CMD="${GEN_CMD} -a \"serviceAuthenticationMethod=${LDAP_SRV_AUTHMETHOD_PAM}\""
5022    [ -n "$LDAP_SRV_AUTHMETHOD_KEY" ] && \
5023	GEN_CMD="${GEN_CMD} -a \"serviceAuthenticationMethod=${LDAP_SRV_AUTHMETHOD_KEY}\""
5024    [ -n "$LDAP_SRV_AUTHMETHOD_CMD" ] && \
5025	GEN_CMD="${GEN_CMD} -a \"serviceAuthenticationMethod=${LDAP_SRV_AUTHMETHOD_CMD}\""
5026
5027    # Check if there are any service search descriptors to ad.
5028    if [ -s "${SSD_FILE}" ]; then
5029	ssd_2_profile
5030    fi
5031
5032    # Execute "ldapclient genprofile" to create profile.
5033    eval ${GEN_CMD} > ${TMPDIR}/gen_profile 2> ${TMPDIR}/gen_profile_ERR
5034    if [ $? -ne 0 ]; then
5035	${ECHO} "  ERROR: ldapclient genprofile failed!"
5036	cleanup
5037	exit 1
5038    fi
5039
5040    # Add the generated profile..
5041    ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/gen_profile ${VERB}"
5042    if [ $? -ne 0 ]; then
5043	${ECHO} "  ERROR: Attempt to add profile failed!"
5044	cleanup
5045	exit 1
5046    fi
5047
5048    # Display message that schema is updated.
5049    ${ECHO} "  ${STEP}. Generated client profile and loaded on server."
5050    STEP=`expr $STEP + 1`
5051}
5052
5053
5054#
5055# cleanup(): Remove the TMPDIR and all files in it.
5056#
5057cleanup()
5058{
5059    [ $DEBUG -eq 1 ] && ${ECHO} "In cleanup()"
5060
5061    rm -fr ${TMPDIR}
5062}
5063
5064
5065#
5066# 			* * * MAIN * * *
5067#
5068# Description:
5069# This script assumes that the iPlanet Directory Server (iDS) is
5070# installed and that setup has been run.  This script takes the
5071# iDS server from that point and sets up the infrastructure for
5072# LDAP Naming Services.  After running this script, ldapaddent(1M)
5073# or some other tools can be used to populate data.
5074
5075# Initialize the variables that need to be set to NULL, or some
5076# other initial value before the rest of the functions can be called.
5077init
5078
5079# Parse command line arguments.
5080parse_arg $*
5081shift $?
5082
5083# Print extra line to separate from prompt.
5084${ECHO} " "
5085
5086# Either Load the user specified config file
5087# or prompt user for config info.
5088if [ -n "$INPUT_FILE" ]
5089then
5090    load_config_file
5091    INTERACTIVE=0      # Turns off prompts that occur later.
5092    validate_info      # Validate basic info in file.
5093    chk_ids_version    # Check iDS version for compatibility.
5094    gssapi_setup_auto
5095else
5096    # Display BACKUP warning to user.
5097    display_msg backup_server
5098    get_confirm "Do you wish to continue with server setup (y/n/h)?" "n" "backup_help"
5099    if [ $? -eq 0 ]; then    # if No, cleanup and exit.
5100	cleanup ; exit 1
5101    fi
5102
5103    # Prompt for values.
5104    prompt_config_info
5105    display_summary    # Allow user to modify results.
5106    INTERACTIVE=1      # Insures future prompting.
5107fi
5108
5109# Modify slapd.oc.conf to ALLOW cn instead of REQUIRE.
5110modify_cn
5111
5112# Modify timelimit to user value.
5113[ $NEED_TIME -eq 1 ] && modify_timelimit
5114
5115# Modify sizelimit to user value.
5116[ $NEED_SIZE -eq 1 ] && modify_sizelimit
5117
5118# Modify the password storage scheme to support CRYPT.
5119if [ "$NEED_CRYPT" = "TRUE" ]; then
5120    modify_pwd_crypt
5121fi
5122
5123# Update the schema (Attributes, Objectclass Definitions)
5124if [ ${SCHEMA_UPDATED} -eq 0 ]; then
5125        update_schema_attr
5126        update_schema_obj
5127fi
5128
5129# Add suffix together with its root entry (if needed)
5130add_suffix ||
5131{
5132	cleanup
5133	exit 1
5134}
5135
5136# Add base objects (if needed)
5137add_base_objects
5138
5139# Update the NisDomainObject.
5140#   The Base DN might of just been created, so this MUST happen after
5141#   the base objects have been added!
5142set_nisdomain
5143
5144# Add top level classes (new containers)
5145add_new_containers
5146
5147# Add common nismaps.
5148add_auto_maps
5149
5150# Modify top ACI.
5151modify_top_aci
5152
5153# Add Access Control Information for VLV.
5154add_vlv_aci
5155
5156# if Proxy needed, Add Proxy Agent and give read permission for password.
5157if [ $NEED_PROXY -eq 1 ]; then
5158    add_proxyagent
5159    allow_proxy_read_pw
5160fi
5161
5162# If admin needed for shadow update, Add the administrator identity and
5163# give write permission for shadow.
5164if [ $NEED_ADMIN -eq 1 ]; then
5165    add_admin
5166    allow_admin_write_shadow
5167fi
5168
5169# if use host principal for shadow update, give write permission for shadow.
5170if [ $NEED_HOSTACL -eq 1 ]; then
5171    allow_host_write_shadow
5172fi
5173
5174# Generate client profile and add it to the server.
5175add_profile
5176
5177# Add Indexes to improve Search Performance.
5178add_eq_indexes
5179add_sub_indexes
5180add_vlv_indexes
5181
5182# Display setup complete message
5183display_msg setup_complete
5184
5185# Display VLV index commands to be executed on server.
5186display_vlv_cmds
5187
5188# Create config file if requested.
5189[ -n "$OUTPUT_FILE" ] && create_config_file
5190
5191# Removed the TMPDIR and all files in it.
5192cleanup
5193
5194exit 0
5195# end of MAIN.
5196