1 #!/bin/sh
2 #
3 # CDDL HEADER START
4 #
5 # The contents of this file are subject to the terms of the
6 # Common Development and Distribution License (the "License").
7 # You may not use this file except in compliance with the License.
8 #
9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 # or http://www.opensolaris.org/os/licensing.
11 # See the License for the specific language governing permissions
12 # and limitations under the License.
13 #
14 # When distributing Covered Code, include this CDDL HEADER in each
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 # If applicable, add the following below this CDDL HEADER, with the
17 # fields enclosed by brackets "[]" replaced with your own identifying
18 # information: Portions Copyright [yyyy] [name of copyright owner]
19 #
20 # CDDL HEADER END
21 #
22 #
23 # idsconfig -- script to setup iDS 5.x/6.x/7.x for Native LDAP II.
24 #
25 # Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
26 #
27
28 #
29 # display_msg(): Displays message corresponding to the tag passed in.
30 #
31 display_msg()
32 {
33 case "$1" in
34 usage) cat <<EOF
35 $PROG: [ -v ] [ -i input file ] [ -o output file ]
36 i <input file> Get setup info from input file.
37 o <output file> Generate a server configuration output file.
38 v Verbose mode
39 EOF
40 ;;
41 backup_server) cat <<EOF
42 It is strongly recommended that you BACKUP the directory server
43 before running $PROG.
44
45 Hit Ctrl-C at any time before the final confirmation to exit.
46
47 EOF
48 ;;
49 setup_complete) cat <<EOF
50
51 $PROG: Setup of iDS server ${IDS_SERVER} is complete.
52
53 EOF
54 ;;
55 display_vlv_list) cat <<EOF
56
57 Note: idsconfig has created entries for VLV indexes.
58
59 For DS5.x, use the directoryserver(1m) script on ${IDS_SERVER}
60 to stop the server. Then, using directoryserver, follow the
61 directoryserver examples below to create the actual VLV indexes.
62
63 For DS6.x or later, use dsadm command delivered with DS on ${IDS_SERVER}
64 to stop the server. Then, using dsadm, follow the
65 dsadm examples below to create the actual VLV indexes.
66
67 EOF
68 ;;
69 cred_level_menu) cat <<EOF
70 The following are the supported credential levels:
71 1 anonymous
72 2 proxy
73 3 proxy anonymous
74 4 self
75 EOF
76 ;;
77 auth_method_menu) cat <<EOF
78 The following are the supported Authentication Methods:
79 1 none
80 2 simple
81 3 sasl/DIGEST-MD5
82 4 tls:simple
83 5 tls:sasl/DIGEST-MD5
84 6 sasl/GSSAPI
85 EOF
86 ;;
87 srvauth_method_menu) cat <<EOF
88 The following are the supported Authentication Methods:
89 1 simple
90 2 sasl/DIGEST-MD5
91 3 tls:simple
92 4 tls:sasl/DIGEST-MD5
93 5 sasl/GSSAPI
94 EOF
95 ;;
96 prompt_ssd_menu) cat <<EOF
97 A Add a Service Search Descriptor
98 D Delete a SSD
99 M Modify a SSD
100 P Display all SSD's
101 H Help
102 X Clear all SSD's
103
104 Q Exit menu
105 EOF
106 ;;
107 summary_menu)
108
109 SUFFIX_INFO=
110 DB_INFO=
111
112 [ -n "${NEED_CREATE_SUFFIX}" ] &&
113 {
114 SUFFIX_INFO=`cat <<EOF
115
116 Suffix to create : $LDAP_SUFFIX
117 EOF
118 `
119 [ -n "${NEED_CREATE_BACKEND}" ] &&
120 DB_INFO=`cat <<EOF
121
122 Database to create : $IDS_DATABASE
123 EOF
124 `
125 }
126
127 cat <<EOF
128 Summary of Configuration
129
130 1 Domain to serve : $LDAP_DOMAIN
131 2 Base DN to setup : $LDAP_BASEDN$SUFFIX_INFO$DB_INFO
132 3 Profile name to create : $LDAP_PROFILE_NAME
133 4 Default Server List : $LDAP_SERVER_LIST
134 5 Preferred Server List : $LDAP_PREF_SRVLIST
135 6 Default Search Scope : $LDAP_SEARCH_SCOPE
136 7 Credential Level : $LDAP_CRED_LEVEL
137 8 Authentication Method : $LDAP_AUTHMETHOD
138 9 Enable Follow Referrals : $LDAP_FOLLOWREF
139 10 iDS Time Limit : $IDS_TIMELIMIT
140 11 iDS Size Limit : $IDS_SIZELIMIT
141 12 Enable crypt password storage : $NEED_CRYPT
142 13 Service Auth Method pam_ldap : $LDAP_SRV_AUTHMETHOD_PAM
143 14 Service Auth Method keyserv : $LDAP_SRV_AUTHMETHOD_KEY
144 15 Service Auth Method passwd-cmd: $LDAP_SRV_AUTHMETHOD_CMD
145 16 Search Time Limit : $LDAP_SEARCH_TIME_LIMIT
146 17 Profile Time to Live : $LDAP_PROFILE_TTL
147 18 Bind Limit : $LDAP_BIND_LIMIT
148 19 Enable shadow update : $LDAP_ENABLE_SHADOW_UPDATE
149 20 Service Search Descriptors Menu
150
151 EOF
152 ;;
153 sfx_not_suitable) cat <<EOF
154
155 Sorry, suffix ${LDAP_SUFFIX} is not suitable for Base DN ${LDAP_BASEDN}
156
157 EOF
158 ;;
159 obj_not_found) cat <<EOF
160
161 Sorry, ${PROG} can't find an objectclass for "$_ATT" attribute
162
163 EOF
164 ;;
165 sfx_config_incons) cat <<EOF
166
167 Sorry, there is no suffix mapping for ${LDAP_SUFFIX},
168 while ldbm database exists, server configuration needs to be fixed manually,
169 look at cn=mapping tree,cn=config and cn=ldbm database,cn=plugins,cn=config
170
171 EOF
172 ;;
173 ldbm_db_exist) cat <<EOF
174
175 Database "${IDS_DATABASE}" already exists,
176 however "${IDS_DATABASE_AVAIL}" name is available
177
178 EOF
179 ;;
180 unable_find_db_name) cat <<EOF
181
182 Unable to find any available database name close to "${IDS_DATABASE}"
183
184 EOF
185 ;;
186 create_ldbm_db_error) cat <<EOF
187
188 ERROR: unable to create suffix ${LDAP_SUFFIX}
189 due to server error that occurred during creation of ldbm database
190
191 EOF
192 ;;
193 create_suffix_entry_error) cat <<EOF
194
195 ERROR: unable to create entry ${LDAP_SUFFIX} of ${LDAP_SUFFIX_OBJ} class
196
197 EOF
198 ;;
199 ldap_suffix_list) cat <<EOF
200
201 No valid suffixes (naming contexts) were found for LDAP base DN:
202 ${LDAP_BASEDN}
203
204 Available suffixes are:
205 ${LDAP_SUFFIX_LIST}
206
207 EOF
208 ;;
209 sorry) cat <<EOF
210
211 HELP - No help is available for this topic.
212
213 EOF
214 ;;
215 create_suffix_help) cat <<EOF
216
217 HELP - Our Base DN is ${LDAP_BASEDN}
218 and we need to create a Directory Suffix,
219 which can be equal to Base DN itself or be any of Base DN parents.
220 All intermediate entries up to suffix will be created on demand.
221
222 EOF
223 ;;
224 enter_ldbm_db_help) cat <<EOF
225
226 HELP - ldbm database is an internal database for storage of our suffix data.
227 Database name must be alphanumeric due to Directory Server restriction.
228
229 EOF
230 ;;
231 backup_help) cat <<EOF
232
233 HELP - Since idsconfig modifies the directory server configuration,
234 it is strongly recommended that you backup the server prior
235 to running this utility. This is especially true if the server
236 being configured is a production server.
237
238 EOF
239 ;;
240 port_help) cat <<EOF
241
242 HELP - Enter the port number the directory server is configured to
243 use for LDAP.
244
245 EOF
246 ;;
247 domain_help) cat <<EOF
248
249 HELP - This is the DNS domain name this server will be serving. You
250 must provide this name even if the server is not going to be populated
251 with hostnames. Any unqualified hostname stored in the directory
252 will be fully qualified using this DNS domain name.
253
254 EOF
255 ;;
256 basedn_help) cat <<EOF
257
258 HELP - This parameter defines the default location in the directory tree for
259 the naming services entries. You can override this default by using
260 serviceSearchDescriptors (SSD). You will be given the option to set up
261 an SSD later on in the setup.
262
263 EOF
264 ;;
265 profile_help) cat <<EOF
266
267 HELP - Name of the configuration profile with which the clients will be
268 configured. A directory server can store various profiles for multiple
269 groups of clients. The initialization tool, (ldapclient(1M)), assumes
270 "default" unless another is specified.
271
272 EOF
273 ;;
274 def_srvlist_help) cat <<EOF
275
276 HELP - Provide a list of directory servers to serve clients using this profile.
277 All these servers should contain consistent data and provide similar
278 functionality. This list is not ordered, and clients might change the
279 order given in this list. Note that this is a space separated list of
280 *IP addresses* (not host names). Providing port numbers is optional.
281
282 EOF
283 ;;
284 pref_srvlist_help) cat <<EOF
285
286 HELP - Provide a list of directory servers to serve this client profile.
287 Unlike the default server list, which is not ordered, the preferred
288 servers must be entered IN THE ORDER you wish to have them contacted.
289 If you do specify a preferred server list, clients will always contact
290 them before attempting to contact any of the servers on the default
291 server list. Note that you must enter the preferred server list as a
292 space-separated list of *IP addresses* (not host names). Providing port
293 numbers is optional.
294
295 EOF
296 ;;
297 srch_scope_help) cat <<EOF
298
299 HELP - Default search scope to be used for all searches unless they are
300 overwritten using serviceSearchDescriptors. The valid options
301 are "one", which would specify the search will only be performed
302 at the base DN for the given service, or "sub", which would specify
303 the search will be performed through *all* levels below the base DN
304 for the given service.
305
306 EOF
307 ;;
308 cred_lvl_help) cat <<EOF
309
310 HELP - This parameter defines what credentials the clients use to
311 authenticate to the directory server. This list might contain
312 multiple credential levels and is ordered. If a proxy level
313 is configured, you will also be prompted to enter a bind DN
314 for the proxy agent along with a password. This proxy agent
315 will be created if it does not exist.
316
317 EOF
318 ;;
319 auth_help) cat <<EOF
320
321 HELP - The default authentication method(s) to be used by all services
322 in the client using this profile. This is a ordered list of
323 authentication methods separated by a ';'. The supported methods
324 are provided in a menu. Note that sasl/DIGEST-MD5 binds require
325 passwords to be stored un-encrypted on the server.
326
327 EOF
328 ;;
329 srvauth_help) cat <<EOF
330
331 HELP - The authentication methods to be used by a given service. Currently
332 3 services support this feature: pam_ldap, keyserv, and passwd-cmd.
333 The authentication method specified in this attribute overrides
334 the default authentication method defined in the profile. This
335 feature can be used to select stronger authentication methods for
336 services which require increased security.
337
338 EOF
339 ;;
340 pam_ldap_help) cat <<EOF
341
342 HELP - The authentication method(s) to be used by pam_ldap when contacting
343 the directory server. This is a ordered list, and, if provided, will
344 override the default authentication method parameter.
345
346 EOF
347 ;;
348 keyserv_help) cat <<EOF
349
350 HELP - The authentication method(s) to be used by newkey(1M) and chkey(1)
351 when contacting the directory server. This is a ordered list and
352 if provided will override the default authentication method
353 parameter.
354
355 EOF
356 ;;
357 passwd-cmd_help) cat <<EOF
358
359 HELP - The authentication method(s) to be used by passwd(1) command when
360 contacting the directory server. This is a ordered list and if
361 provided will override the default authentication method parameter.
362
363 EOF
364 ;;
365 referrals_help) cat <<EOF
366
367 HELP - This parameter indicates whether the client should follow
368 ldap referrals if it encounters one during naming lookups.
369
370 EOF
371 ;;
372 tlim_help) cat <<EOF
373
374 HELP - The server time limit value indicates the maximum amount of time the
375 server would spend on a query from the client before abandoning it.
376 A value of '-1' indicates no limit.
377
378 EOF
379 ;;
380 slim_help) cat <<EOF
381
382 HELP - The server sizelimit value indicates the maximum number of entries
383 the server would return in respond to a query from the client. A
384 value of '-1' indicates no limit.
385
386 EOF
387 ;;
388 crypt_help) cat <<EOF
389
390 HELP - By default iDS does not store userPassword attribute values using
391 unix "crypt" format. If you need to keep your passwords in the crypt
392 format for NIS/NIS+ and pam_unix compatibility, choose 'yes'. If
393 passwords are stored using any other format than crypt, pam_ldap
394 MUST be used by clients to authenticate users to the system. Note
395 that if you wish to use sasl/DIGEST-MD5 in conjunction with pam_ldap,
396 user passwords must be stored in the clear format.
397
398 EOF
399 ;;
400 srchtime_help) cat <<EOF
401
402 HELP - The search time limit the client will enforce for directory
403 lookups.
404
405 EOF
406 ;;
407 profttl_help) cat <<EOF
408
409 HELP - The time to live value for profile. The client will refresh its
410 cached version of the configuration profile at this TTL interval.
411
412 EOF
413 ;;
414 bindlim_help) cat <<EOF
415
416 HELP - The time limit for the bind operation to the directory. This
417 value controls the responsiveness of the client in case a server
418 becomes unavailable. The smallest timeout value for a given
419 network architecture/conditions would work best. This is very
420 similar to setting TCP timeout, but only for LDAP bind operation.
421
422 EOF
423 ;;
424 ssd_help) cat <<EOF
425
426 HELP - Using Service Search Descriptors (SSD), you can override the
427 default configuration for a given service. The SSD can be
428 used to override the default search base DN, the default search
429 scope, and the default search filter to be used for directory
430 lookups. SSD are supported for all services (databases)
431 defined in nsswitch.conf(4). The default base DN is defined
432 in ldap(1).
433
434 Note: SSD are powerful tools in defining configuration profiles
435 and provide a great deal of flexibility. However, care
436 must be taken in creating them. If you decide to make use
437 of SSDs, consult the documentation first.
438
439 EOF
440 ;;
441 ssd_menu_help) cat <<EOF
442
443 HELP - Using this menu SSD can be added, updated, or deleted from
444 the profile.
445
446 A - This option creates a new SSD by prompting for the
447 service name, base DN, and scope. Service name is
448 any valid service as defined in ldap(1). base is
449 either the distinguished name to the container where
450 this service will use, or a relative DN followed
451 by a ','.
452 D - Delete a previously created SSD.
453 M - Modify a previously created SSD.
454 P - Display a list of all the previously created SSD.
455 X - Delete all of the previously created SSD.
456
457 Q - Exit the menu and continue with the server configuration.
458
459 EOF
460 ;;
461 ldap_suffix_list_help) cat <<EOF
462
463 HELP - No valid suffixes (naming contexts) are available on server
464 ${IDS_SERVER}:${IDS_PORT}.
465 You must set an LDAP Base DN that can be contained in
466 an existing suffix.
467
468 EOF
469 ;;
470 enable_shadow_update_help) cat <<EOF
471
472 HELP - Enter 'y' to set up the LDAP server for shadow update.
473 The setup will add an administrator identity/credential
474 and modify the necessary access controls for the client
475 to update shadow(4) data on the LDAP server. If sasl/GSSAPI
476 is in use, the Kerberos host principal will be used as the
477 administrator identity.
478
479 Shadow data is used for password aging and account locking.
480 Please refer to the shadow(4) manual page for details.
481
482 EOF
483 ;;
484 add_admin_cred_help) cat <<EOF
485
486 HELP - Start the setup to add an administrator identity/credential
487 and to modify access controls for the client to update
488 shadow(4) data on the LDAP server.
489
490 Shadow data is used for password aging and account locking.
491 Please refer to the shadow(4) manual page for details.
492
493 EOF
494 ;;
495 use_host_principal_help) cat <<EOF
496
497 HELP - A profile with a 'sasl/GSSAPI' authentication method and a 'self'
498 credential level is detected, enter 'y' to modify the necessary
499 access controls for allowing the client to update shadow(4) data
500 on the LDAP server.
501
502 Shadow data is used for password aging and account locking.
503 Please refer to the shadow(4) manual page for details.
504
505 EOF
506 ;;
507 esac
508 }
509
510
511 #
512 # get_ans(): gets an answer from the user.
513 # $1 instruction/comment/description/question
514 # $2 default value
515 #
516 get_ans()
517 {
518 if [ -z "$2" ]
519 then
520 ${ECHO} "$1 \c"
521 else
522 ${ECHO} "$1 [$2] \c"
523 fi
524
525 read ANS
526 if [ -z "$ANS" ]
527 then
528 ANS=$2
529 fi
530 }
531
532
533 #
534 # get_ans_req(): gets an answer (required) from the user, NULL value not allowed.
535 # $@ instruction/comment/description/question
536 #
537 get_ans_req()
538 {
539 ANS="" # Set ANS to NULL.
540 while [ "$ANS" = "" ]
541 do
542 get_ans "$@"
543 [ "$ANS" = "" ] && ${ECHO} "NULL value not allowed!"
544 done
545 }
546
547
548 #
549 # get_number(): Querys and verifies that number entered is numeric.
550 # Function will repeat prompt user for number value.
551 # $1 Message text.
552 # $2 default value.
553 # $3 Help argument.
554 #
555 get_number()
556 {
557 ANS="" # Set ANS to NULL.
558 NUM=""
559
560 get_ans "$1" "$2"
561
562 # Verify that value is numeric.
563 while not_numeric $ANS
564 do
565 case "$ANS" in
566 [Hh] | help | Help | \?) display_msg ${3:-sorry} ;;
567 * ) ${ECHO} "Invalid value: \"${ANS}\". \c"
568 ;;
569 esac
570 # Get a new value.
571 get_ans "Enter a numeric value:" "$2"
572 done
573 NUM=$ANS
574 }
575
576
577 #
578 # get_negone_num(): Only allows a -1 or positive integer.
579 # Used for values where -1 has special meaning.
580 #
581 # $1 - Prompt message.
582 # $2 - Default value (require).
583 # $3 - Optional help argument.
584 get_negone_num()
585 {
586 while :
587 do
588 get_number "$1" "$2" "$3"
589 if is_negative $ANS
590 then
591 if [ "$ANS" = "-1" ]; then
592 break # -1 is OK, so break.
593 else # Need to re-enter number.
594 ${ECHO} "Invalid number: please enter -1 or positive number."
595 fi
596 else
597 break # Positive number
598 fi
599 done
600 }
601
602
603 #
604 # get_passwd(): Reads a password from the user and verify with second.
605 # $@ instruction/comment/description/question
606 #
607 get_passwd()
608 {
609 [ $DEBUG -eq 1 ] && ${ECHO} "In get_passwd()"
610
611 # Temporary PASSWD variables
612 _PASS1=""
613 _PASS2=""
614
615 /usr/bin/stty -echo # Turn echo OFF
616
617 # Endless loop that continues until passwd and re-entered passwd
618 # match.
619 while :
620 do
621 ANS="" # Set ANS to NULL.
622
623 # Don't allow NULL for first try.
624 while [ "$ANS" = "" ]
625 do
626 get_ans "$@"
627 [ "$ANS" = "" ] && ${ECHO} "" && ${ECHO} "NULL passwd not allowed!"
628 done
629 _PASS1=$ANS # Store first try.
630
631 # Get second try.
632 ${ECHO} ""
633 get_ans "Re-enter passwd:"
634 _PASS2=$ANS
635
636 # Test if passwords are identical.
637 if [ "$_PASS1" = "$_PASS2" ]; then
638 break
639 fi
640
641 # Move cursor down to next line and print ERROR message.
642 ${ECHO} ""
643 ${ECHO} "ERROR: passwords don't match; try again."
644 done
645
646 /usr/bin/stty echo # Turn echo ON
647
648 ${ECHO} ""
649 }
650
651
652 #
653 # get_passwd_nochk(): Reads a password from the user w/o check.
654 # $@ instruction/comment/description/question
655 #
656 get_passwd_nochk()
657 {
658 [ $DEBUG -eq 1 ] && ${ECHO} "In get_passwd_nochk()"
659
660 /usr/bin/stty -echo # Turn echo OFF
661
662 get_ans "$@"
663
664 /usr/bin/stty echo # Turn echo ON
665
666 ${ECHO} ""
667 }
668
669
670 #
671 # get_menu_choice(): Get a menu choice from user. Continue prompting
672 # till the choice is in required range.
673 # $1 .. Message text.
674 # $2 .. min value
675 # $3 .. max value
676 # $4 .. OPTIONAL: default value
677 #
678 # Return value:
679 # MN_CH will contain the value selected.
680 #
681 get_menu_choice()
682 {
683 # Check for req parameter.
684 if [ $# -lt 3 ]; then
685 ${ECHO} "get_menu_choice(): Did not get required parameters."
686 return 1
687 fi
688
689 while :
690 do
691 get_ans "$1" "$4"
692 MN_CH=$ANS
693 is_negative $MN_CH
694 if [ $? -eq 1 ]; then
695 if [ $MN_CH -ge $2 ]; then
696 if [ $MN_CH -le $3 ]; then
697 return
698 fi
699 fi
700 fi
701 ${ECHO} "Invalid choice: $MN_CH"
702 done
703 }
704
705
706 #
707 # get_confirm(): Get confirmation from the user. (Y/Yes or N/No)
708 # $1 - Message
709 # $2 - default value.
710 #
711 get_confirm()
712 {
713 _ANSWER=
714
715 while :
716 do
717 # Display Internal ERROR if $2 not set.
718 if [ -z "$2" ]
719 then
720 ${ECHO} "INTERNAL ERROR: get_confirm requires 2 args, 3rd is optional."
721 exit 2
722 fi
723
724 # Display prompt.
725 ${ECHO} "$1 [$2] \c"
726
727 # Get the ANSWER.
728 read _ANSWER
729 if [ "$_ANSWER" = "" ] && [ -n "$2" ] ; then
730 _ANSWER=$2
731 fi
732 case "$_ANSWER" in
733 [Yy] | yes | Yes | YES) return 1 ;;
734 [Nn] | no | No | NO) return 0 ;;
735 [Hh] | help | Help | \?) display_msg ${3:-sorry};;
736 * ) ${ECHO} "Please enter y or n." ;;
737 esac
738 done
739 }
740
741
742 #
743 # get_confirm_nodef(): Get confirmation from the user. (Y/Yes or N/No)
744 # No default value supported.
745 #
746 get_confirm_nodef()
747 {
748 _ANSWER=
749
750 while :
751 do
752 ${ECHO} "$@ \c"
753 read _ANSWER
754 case "$_ANSWER" in
755 [Yy] | yes | Yes | YES) return 1 ;;
756 [Nn] | no | No | NO) return 0 ;;
757 * ) ${ECHO} "Please enter y or n." ;;
758 esac
759 done
760 }
761
762
763 #
764 # is_numeric(): Tells is a string is numeric.
765 # 0 = Numeric
766 # 1 = NOT Numeric
767 #
768 is_numeric()
769 {
770 # Check for parameter.
771 if [ $# -ne 1 ]; then
772 return 1
773 fi
774
775 # Determine if numeric.
776 expr "$1" + 1 > /dev/null 2>&1
777 if [ $? -ge 2 ]; then
778 return 1
779 fi
780
781 # Made it here, it's Numeric.
782 return 0
783 }
784
785
786 #
787 # not_numeric(): Reverses the return values of is_numeric. Useful
788 # for if and while statements that want to test for
789 # non-numeric data.
790 # 0 = NOT Numeric
791 # 1 = Numeric
792 #
793 not_numeric()
794 {
795 is_numeric $1
796 if [ $? -eq 0 ]; then
797 return 1
798 else
799 return 0
800 fi
801 }
802
803
804 #
805 # is_negative(): Tells is a Numeric value is less than zero.
806 # 0 = Negative Numeric
807 # 1 = Positive Numeric
808 # 2 = NOT Numeric
809 #
810 is_negative()
811 {
812 # Check for parameter.
813 if [ $# -ne 1 ]; then
814 return 1
815 fi
816
817 # Determine if numeric. Can't use expr because -0 is
818 # considered positive??
819 if is_numeric $1; then
820 case "$1" in
821 -*) return 0 ;; # Negative Numeric
822 *) return 1 ;; # Positive Numeric
823 esac
824 else
825 return 2
826 fi
827 }
828
829
830 #
831 # check_domainname(): check validity of a domain name. Currently we check
832 # that it has at least two components.
833 # $1 the domain name to be checked
834 #
835 check_domainname()
836 {
837 if [ ! -z "$1" ]
838 then
839 t=`expr "$1" : '[^.]\{1,\}[.][^.]\{1,\}'`
840 if [ "$t" = 0 ]
841 then
842 return 1
843 fi
844 fi
845 return 0
846 }
847
848
849 #
850 # check_baseDN(): check validity of the baseDN name.
851 # $1 the baseDN name to be checked
852 #
853 # NOTE: The check_baseDN function does not catch all invalid DN's.
854 # Its purpose is to reduce the number of invalid DN's to
855 # get past the input routine. The invalid DN's will be
856 # caught by the LDAP server when they are attempted to be
857 # created.
858 #
859 check_baseDN()
860 {
861 ck_DN=$1
862 ${ECHO} " Checking LDAP Base DN ..."
863 if [ ! -z "$ck_DN" ]; then
864 [ $DEBUG -eq 1 ] && ${ECHO} "Checking baseDN: $ck_DN"
865 # Check for = (assignment operator)
866 ${ECHO} "$ck_DN" | ${GREP} "=" > /dev/null 2>&1
867 if [ $? -ne 0 ]; then
868 [ $DEBUG -eq 1 ] && ${ECHO} "check_baseDN: No '=' in baseDN."
869 return 1
870 fi
871
872 # Check all keys.
873 while :
874 do
875 # Get first key.
876 dkey=`${ECHO} $ck_DN | cut -d'=' -f1`
877
878 # Check that the key string is valid
879 check_attrName $dkey
880 if [ $? -ne 0 ]; then
881 [ $DEBUG -eq 1 ] && ${ECHO} "check_baseDN: invalid key=${dkey}"
882 return 1
883 fi
884
885 [ $DEBUG -eq 1 ] && ${ECHO} "check_baseDN: valid key=${dkey}"
886
887 # Remove first key from DN
888 ck_DN=`${ECHO} $ck_DN | cut -s -d',' -f2-`
889
890 # Break loop if nothing left.
891 if [ "$ck_DN" = "" ]; then
892 break
893 fi
894 done
895 fi
896 return 0
897 }
898
899
900 #
901 # domain_2_dc(): Convert a domain name into dc string.
902 # $1 .. Domain name.
903 #
904 domain_2_dc()
905 {
906 _DOM=$1 # Domain parameter.
907 _DOM_2_DC="" # Return value from function.
908 _FIRST=1 # Flag for first time.
909
910 export _DOM_2_DC # Make visible for others.
911
912 # Convert "."'s to spaces for "for" loop.
913 domtmp="`${ECHO} ${_DOM} | tr '.' ' '`"
914 for i in $domtmp; do
915 if [ $_FIRST -eq 1 ]; then
916 _DOM_2_DC="dc=${i}"
917 _FIRST=0
918 else
919 _DOM_2_DC="${_DOM_2_DC},dc=${i}"
920 fi
921 done
922 }
923
924
925 #
926 # is_root_user(): Check to see if logged in as root user.
927 #
928 is_root_user()
929 {
930 case `id` in
931 uid=0\(root\)*) return 0 ;;
932 * ) return 1 ;;
933 esac
934 }
935
936
937 #
938 # parse_arg(): Parses the command line arguments and sets the
939 # appropriate variables.
940 #
941 parse_arg()
942 {
943 while getopts "dvhi:o:" ARG
944 do
945 case $ARG in
946 d) DEBUG=1;;
947 v) VERB="";;
948 i) INPUT_FILE=$OPTARG;;
949 o) OUTPUT_FILE=$OPTARG;;
950 \?) display_msg usage
951 exit 1;;
952 *) ${ECHO} "**ERROR: Supported option missing handler!"
953 display_msg usage
954 exit 1;;
955 esac
956 done
957 return `expr $OPTIND - 1`
958 }
959
960
961 #
962 # init(): initializes variables and options
963 #
964 init()
965 {
966 # General variables.
967 PROG=`basename $0` # Program name
968 PID=$$ # Program ID
969 VERB='> /dev/null 2>&1' # NULL or "> /dev/null"
970 ECHO="/bin/echo" # print message on screen
971 EVAL="eval" # eval or echo
972 EGREP="/usr/bin/egrep"
973 GREP="/usr/bin/grep"
974 DEBUG=0 # Set Debug OFF
975 BACKUP=no_ldap # backup suffix
976 HOST="" # NULL or <hostname>
977 NAWK="/usr/bin/nawk"
978 RM="/usr/bin/rm"
979 WC="/usr/bin/wc"
980 CAT="/usr/bin/cat"
981 SED="/usr/bin/sed"
982 MV="/usr/bin/mv"
983
984 DOM="" # Set to NULL
985 # If DNS domain (resolv.conf) exists use that, otherwise use domainname.
986 if [ -f /etc/resolv.conf ]; then
987 DOM=`/usr/xpg4/bin/grep -i -E '^domain|^search' /etc/resolv.conf \
988 | awk '{ print $2 }' | tail -1`
989 fi
990
991 # If for any reason the DOM did not get set (error'd resolv.conf) set
992 # DOM to the domainname command's output.
993 if [ "$DOM" = "" ]; then
994 DOM=`domainname` # domain from domainname command.
995 fi
996
997 STEP=1
998 INTERACTIVE=1 # 0 = on, 1 = off (For input file mode)
999 DEL_OLD_PROFILE=0 # 0 (default), 1 = delete old profile.
1000
1001 # idsconfig specific variables.
1002 INPUT_FILE=""
1003 OUTPUT_FILE=""
1004 LDAP_ENABLE_SHADOW_UPDATE="FALSE"
1005 NEED_PROXY=0 # 0 = No Proxy, 1 = Create Proxy.
1006 NEED_ADMIN=0 # 0 = No Admin, 1 = Create Admin.
1007 NEED_HOSTACL=0 # 0 = No Host ACL, 1 = Create Host ACL.
1008 EXISTING_PROFILE=0
1009 LDAP_PROXYAGENT=""
1010 LDAP_ADMINDN=""
1011 LDAP_SUFFIX=""
1012 LDAP_DOMAIN=$DOM # domainname on Server (default value)
1013 GEN_CMD=""
1014 PROXY_ACI_NAME="LDAP_Naming_Services_proxy_password_read"
1015
1016 # LDAP COMMANDS
1017 LDAPSEARCH="/bin/ldapsearch -r"
1018 LDAPMODIFY=/bin/ldapmodify
1019 LDAPADD=/bin/ldapadd
1020 LDAPDELETE=/bin/ldapdelete
1021 LDAP_GEN_PROFILE=/usr/sbin/ldap_gen_profile
1022
1023 # iDS specific information
1024 IDS_SERVER=""
1025 IDS_PORT=389
1026 NEED_TIME=0
1027 NEED_SIZE=0
1028 NEED_SRVAUTH_PAM=0
1029 NEED_SRVAUTH_KEY=0
1030 NEED_SRVAUTH_CMD=0
1031 IDS_TIMELIMIT=""
1032 IDS_SIZELIMIT=""
1033
1034 # LDAP PROFILE related defaults
1035 LDAP_ROOTDN="cn=Directory Manager" # Provide common default.
1036 LDAP_ROOTPWD="" # NULL passwd as default (i.e. invalid)
1037 LDAP_PROFILE_NAME="default"
1038 LDAP_BASEDN=""
1039 LDAP_SERVER_LIST=""
1040 LDAP_AUTHMETHOD=""
1041 LDAP_FOLLOWREF="FALSE"
1042 NEED_CRYPT=""
1043 LDAP_SEARCH_SCOPE="one"
1044 LDAP_SRV_AUTHMETHOD_PAM=""
1045 LDAP_SRV_AUTHMETHOD_KEY=""
1046 LDAP_SRV_AUTHMETHOD_CMD=""
1047 LDAP_SEARCH_TIME_LIMIT=30
1048 LDAP_PREF_SRVLIST=""
1049 LDAP_PROFILE_TTL=43200
1050 LDAP_CRED_LEVEL="proxy"
1051 LDAP_BIND_LIMIT=10
1052
1053 # Prevent new files from being read by group or others.
1054 umask 077
1055
1056 # Service Search Descriptors
1057 LDAP_SERV_SRCH_DES=""
1058
1059 # Set and create TMPDIR.
1060 TMPDIR="/tmp/idsconfig.${PID}"
1061 if mkdir -m 700 ${TMPDIR}
1062 then
1063 # Cleanup on exit.
1064 trap 'rm -rf ${TMPDIR}; /usr/bin/stty echo; exit' 1 2 3 6 15
1065 else
1066 echo "ERROR: unable to create a safe temporary directory."
1067 exit 1
1068 fi
1069 LDAP_ROOTPWF=${TMPDIR}/rootPWD
1070
1071 # Set the SSD file name after setting TMPDIR.
1072 SSD_FILE=${TMPDIR}/ssd_list
1073
1074 # GSSAPI setup
1075 GSSAPI_ENABLE=0
1076 LDAP_KRB_REALM=""
1077 SCHEMA_UPDATED=0
1078
1079 export DEBUG VERB ECHO EVAL EGREP GREP STEP TMPDIR
1080 export IDS_SERVER IDS_PORT LDAP_ROOTDN LDAP_ROOTPWD LDAP_SERVER_LIST
1081 export LDAP_BASEDN LDAP_ROOTPWF
1082 export LDAP_DOMAIN LDAP_SUFFIX LDAP_PROXYAGENT LDAP_PROXYAGENT_CRED
1083 export NEED_PROXY
1084 export LDAP_ENABLE_SHADOW_UPDATE LDAP_ADMINDN LDAP_ADMIN_CRED
1085 export NEED_ADMIN NEED_HOSTACL EXISTING_PROFILE
1086 export LDAP_PROFILE_NAME LDAP_BASEDN LDAP_SERVER_LIST
1087 export LDAP_AUTHMETHOD LDAP_FOLLOWREF LDAP_SEARCH_SCOPE LDAP_SEARCH_TIME_LIMIT
1088 export LDAP_PREF_SRVLIST LDAP_PROFILE_TTL LDAP_CRED_LEVEL LDAP_BIND_LIMIT
1089 export NEED_SRVAUTH_PAM NEED_SRVAUTH_KEY NEED_SRVAUTH_CMD
1090 export LDAP_SRV_AUTHMETHOD_PAM LDAP_SRV_AUTHMETHOD_KEY LDAP_SRV_AUTHMETHOD_CMD
1091 export LDAP_SERV_SRCH_DES SSD_FILE
1092 export GEN_CMD GSSAPI_ENABLE LDAP_KRB_REALM SCHEMA_UPDATED
1093 }
1094
1095
1096 #
1097 # disp_full_debug(): List of all debug variables usually interested in.
1098 # Grouped to avoid MASSIVE code duplication.
1099 #
1100 disp_full_debug()
1101 {
1102 [ $DEBUG -eq 1 ] && ${ECHO} " IDS_SERVER = $IDS_SERVER"
1103 [ $DEBUG -eq 1 ] && ${ECHO} " IDS_PORT = $IDS_PORT"
1104 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_ROOTDN = $LDAP_ROOTDN"
1105 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_ROOTPWD = $LDAP_ROOTPWD"
1106 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_DOMAIN = $LDAP_DOMAIN"
1107 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_SUFFIX = $LDAP_SUFFIX"
1108 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_BASEDN = $LDAP_BASEDN"
1109 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_PROFILE_NAME = $LDAP_PROFILE_NAME"
1110 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_SERVER_LIST = $LDAP_SERVER_LIST"
1111 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_PREF_SRVLIST = $LDAP_PREF_SRVLIST"
1112 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_SEARCH_SCOPE = $LDAP_SEARCH_SCOPE"
1113 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_CRED_LEVEL = $LDAP_CRED_LEVEL"
1114 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_AUTHMETHOD = $LDAP_AUTHMETHOD"
1115 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_FOLLOWREF = $LDAP_FOLLOWREF"
1116 [ $DEBUG -eq 1 ] && ${ECHO} " IDS_TIMELIMIT = $IDS_TIMELIMIT"
1117 [ $DEBUG -eq 1 ] && ${ECHO} " IDS_SIZELIMIT = $IDS_SIZELIMIT"
1118 [ $DEBUG -eq 1 ] && ${ECHO} " NEED_CRYPT = $NEED_CRYPT"
1119 [ $DEBUG -eq 1 ] && ${ECHO} " NEED_SRVAUTH_PAM = $NEED_SRVAUTH_PAM"
1120 [ $DEBUG -eq 1 ] && ${ECHO} " NEED_SRVAUTH_KEY = $NEED_SRVAUTH_KEY"
1121 [ $DEBUG -eq 1 ] && ${ECHO} " NEED_SRVAUTH_CMD = $NEED_SRVAUTH_CMD"
1122 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_SRV_AUTHMETHOD_PAM = $LDAP_SRV_AUTHMETHOD_PAM"
1123 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_SRV_AUTHMETHOD_KEY = $LDAP_SRV_AUTHMETHOD_KEY"
1124 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_SRV_AUTHMETHOD_CMD = $LDAP_SRV_AUTHMETHOD_CMD"
1125 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_SEARCH_TIME_LIMIT = $LDAP_SEARCH_TIME_LIMIT"
1126 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_PROFILE_TTL = $LDAP_PROFILE_TTL"
1127 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_BIND_LIMIT = $LDAP_BIND_LIMIT"
1128 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_ENABLE_SHADOW_UPDATE = $LDAP_ENABLE_SHADOW_UPDATE"
1129
1130 # Only display proxy stuff if needed.
1131 [ $DEBUG -eq 1 ] && ${ECHO} " NEED_PROXY = $NEED_PROXY"
1132 if [ $NEED_PROXY -eq 1 ]; then
1133 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_PROXYAGENT = $LDAP_PROXYAGENT"
1134 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_PROXYAGENT_CRED = $LDAP_PROXYAGENT_CRED"
1135 fi
1136
1137 # Only display admin credential if needed.
1138 [ $DEBUG -eq 1 ] && ${ECHO} " NEED_ADMIN = $NEED_ADMIN"
1139 [ $DEBUG -eq 1 ] && ${ECHO} " NEED_HOSTACL = $NEED_HOSTACL"
1140 if [ $NEED_ADMIN -eq 1 ]; then
1141 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_ADMINDN = $LDAP_ADMINDN"
1142 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_ADMIN_CRED = $LDAP_ADMIN_CRED"
1143 fi
1144
1145 # Service Search Descriptors are a special case.
1146 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_SERV_SRCH_DES = $LDAP_SERV_SRCH_DES"
1147 }
1148
1149
1150 #
1151 # load_config_file(): Loads the config file.
1152 #
1153 load_config_file()
1154 {
1155 [ $DEBUG -eq 1 ] && ${ECHO} "In load_config_file()"
1156
1157 # Remove SSD lines from input file before sourcing.
1158 # The SSD lines must be removed because some forms of the
1159 # data could cause SHELL errors.
1160 ${GREP} -v "LDAP_SERV_SRCH_DES=" ${INPUT_FILE} > ${TMPDIR}/inputfile.noSSD
1161
1162 # Source the input file.
1163 . ${TMPDIR}/inputfile.noSSD
1164
1165 # If LDAP_SUFFIX is no set, try to utilize LDAP_TREETOP since older
1166 # config files use LDAP_TREETOP
1167 LDAP_SUFFIX="${LDAP_SUFFIX:-$LDAP_TREETOP}"
1168
1169 # Save password to temporary file.
1170 save_password
1171
1172 # Create the SSD file.
1173 create_ssd_file
1174
1175 # Display FULL debugging info.
1176 disp_full_debug
1177 }
1178
1179 #
1180 # save_password(): Save password to temporary file.
1181 #
1182 save_password()
1183 {
1184 cat > ${LDAP_ROOTPWF} <<EOF
1185 ${LDAP_ROOTPWD}
1186 EOF
1187 }
1188
1189 ######################################################################
1190 # FUNCTIONS FOR prompt_config_info() START HERE.
1191 ######################################################################
1192
1193 #
1194 # get_ids_server(): Prompt for iDS server name.
1195 #
1196 get_ids_server()
1197 {
1198 while :
1199 do
1200 # Prompt for server name.
1201 get_ans "Enter the JES Directory Server's hostname to setup:" "$IDS_SERVER"
1202 IDS_SERVER="$ANS"
1203
1204 # Ping server to see if live. If valid break out of loop.
1205 ping $IDS_SERVER > /dev/null 2>&1
1206 if [ $? -eq 0 ]; then
1207 break
1208 fi
1209
1210 # Invalid server, enter a new name.
1211 ${ECHO} "ERROR: Server '${IDS_SERVER}' is invalid or unreachable."
1212 IDS_SERVER=""
1213 done
1214
1215 # Set SERVER_ARGS and LDAP_ARGS since values might of changed.
1216 SERVER_ARGS="-h ${IDS_SERVER} -p ${IDS_PORT}"
1217 LDAP_ARGS="${SERVER_ARGS} ${AUTH_ARGS}"
1218 export SERVER_ARGS
1219
1220 }
1221
1222 #
1223 # get_ids_port(): Prompt for iDS port number.
1224 #
1225 get_ids_port()
1226 {
1227 # Get a valid iDS port number.
1228 while :
1229 do
1230 # Enter port number.
1231 get_number "Enter the port number for iDS (h=help):" "$IDS_PORT" "port_help"
1232 IDS_PORT=$ANS
1233 # Do a simple search to check hostname and port number.
1234 # If search returns SUCCESS, break out, host and port must
1235 # be valid.
1236 ${LDAPSEARCH} -h ${IDS_SERVER} -p ${IDS_PORT} -b "" -s base "objectclass=*" > /dev/null 2>&1
1237 if [ $? -eq 0 ]; then
1238 break
1239 fi
1240
1241 # Invalid host/port pair, Re-enter.
1242 ${ECHO} "ERROR: Invalid host or port: ${IDS_SERVER}:${IDS_PORT}, Please re-enter!"
1243 get_ids_server
1244 done
1245
1246 # Set SERVER_ARGS and LDAP_ARGS since values might of changed.
1247 SERVER_ARGS="-h ${IDS_SERVER} -p ${IDS_PORT}"
1248 LDAP_ARGS="${SERVER_ARGS} ${AUTH_ARGS}"
1249 export SERVER_ARGS
1250 }
1251
1252
1253 #
1254 # chk_ids_version(): Read the slapd config file and set variables
1255 #
1256 chk_ids_version()
1257 {
1258 [ $DEBUG -eq 1 ] && ${ECHO} "In chk_ids_version()"
1259
1260 # check iDS version number.
1261 eval "${LDAPSEARCH} ${SERVER_ARGS} -b cn=monitor -s base \"objectclass=*\" version | ${GREP} \"^version=\" | cut -f2 -d'/' | cut -f1 -d' ' > ${TMPDIR}/checkDSver 2>&1"
1262 if [ $? -ne 0 ]; then
1263 ${ECHO} "ERROR: Can not determine the version number of iDS!"
1264 exit 1
1265 fi
1266 IDS_VER=`cat ${TMPDIR}/checkDSver`
1267 IDS_MAJVER=`${ECHO} ${IDS_VER} | cut -f1 -d.`
1268 IDS_MINVER=`${ECHO} ${IDS_VER} | cut -f2 -d.`
1269 case "${IDS_MAJVER}" in
1270 5|6|7) : ;;
1271 *) ${ECHO} "ERROR: $PROG only works with JES DS version 5.x, 6.x or 7.x, not ${IDS_VER}."; exit 1;;
1272 esac
1273
1274 if [ $DEBUG -eq 1 ]; then
1275 ${ECHO} " IDS_MAJVER = $IDS_MAJVER"
1276 ${ECHO} " IDS_MINVER = $IDS_MINVER"
1277 fi
1278 }
1279
1280
1281 #
1282 # get_dirmgr_dn(): Get the directory manger DN.
1283 #
1284 get_dirmgr_dn()
1285 {
1286 get_ans "Enter the directory manager DN:" "$LDAP_ROOTDN"
1287 LDAP_ROOTDN=$ANS
1288
1289 # Update ENV variables using DN.
1290 AUTH_ARGS="-D \"${LDAP_ROOTDN}\" -j ${LDAP_ROOTPWF}"
1291 LDAP_ARGS="${SERVER_ARGS} ${AUTH_ARGS}"
1292 export AUTH_ARGS LDAP_ARGS
1293 }
1294
1295
1296 #
1297 # get_dirmgr_pw(): Get the Root DN passwd. (Root DN found in slapd.conf)
1298 #
1299 get_dirmgr_pw()
1300 {
1301 while :
1302 do
1303 # Get passwd.
1304 get_passwd_nochk "Enter passwd for ${LDAP_ROOTDN} :"
1305 LDAP_ROOTPWD=$ANS
1306
1307 # Store password in file.
1308 save_password
1309
1310 # Update ENV variables using DN's PW.
1311 AUTH_ARGS="-D \"${LDAP_ROOTDN}\" -j ${LDAP_ROOTPWF}"
1312 LDAP_ARGS="${SERVER_ARGS} ${AUTH_ARGS}"
1313 export AUTH_ARGS LDAP_ARGS
1314
1315 # Verify that ROOTDN and ROOTPWD are valid.
1316 eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"\" -s base \"objectclass=*\" > ${TMPDIR}/checkDN 2>&1"
1317 if [ $? -ne 0 ]; then
1318 eval "${GREP} credential ${TMPDIR}/checkDN ${VERB}"
1319 if [ $? -eq 0 ]; then
1320 ${ECHO} "ERROR: Root DN passwd is invalid."
1321 else
1322 ${ECHO} "ERROR: Invalid Root DN <${LDAP_ROOTDN}>."
1323 get_dirmgr_dn
1324 fi
1325 else
1326 break # Both are valid.
1327 fi
1328 done
1329
1330
1331 }
1332
1333
1334 #
1335 # get_domain(): Get the Domain that will be served by the LDAP server.
1336 # $1 - Help argument.
1337 #
1338 get_domain()
1339 {
1340 # Use LDAP_DOMAIN as default.
1341 get_ans "Enter the domainname to be served (h=help):" $LDAP_DOMAIN
1342
1343 # Check domainname, and have user re-enter if not valid.
1344 check_domainname $ANS
1345 while [ $? -ne 0 ]
1346 do
1347 case "$ANS" in
1348 [Hh] | help | Help | \?) display_msg ${1:-sorry} ;;
1349 * ) ${ECHO} "Invalid domainname: \"${ANS}\"."
1350 ;;
1351 esac
1352 get_ans "Enter domainname to be served (h=help):" $DOM
1353
1354 check_domainname $ANS
1355 done
1356
1357 # Set the domainname to valid name.
1358 LDAP_DOMAIN=$ANS
1359 }
1360
1361
1362 #
1363 # get_basedn(): Query for the Base DN.
1364 #
1365 get_basedn()
1366 {
1367 # Set the $_DOM_2_DC and assign to LDAP_BASEDN as default.
1368 # Then call get_basedn(). This method remakes the default
1369 # each time just in case the domain changed.
1370 domain_2_dc $LDAP_DOMAIN
1371 LDAP_BASEDN=$_DOM_2_DC
1372
1373 # Get Base DN.
1374 while :
1375 do
1376 get_ans_req "Enter LDAP Base DN (h=help):" "${_DOM_2_DC}"
1377 check_baseDN "$ANS"
1378 while [ $? -ne 0 ]
1379 do
1380 case "$ANS" in
1381 [Hh] | help | Help | \?) display_msg basedn_help ;;
1382 * ) ${ECHO} "Invalid base DN: \"${ANS}\"."
1383 ;;
1384 esac
1385
1386 # Re-Enter the BaseDN
1387 get_ans_req "Enter LDAP Base DN (h=help):" "${_DOM_2_DC}"
1388 check_baseDN "$ANS"
1389 done
1390
1391 # Set base DN and check its suffix
1392 LDAP_BASEDN=${ANS}
1393 check_basedn_suffix ||
1394 {
1395 cleanup
1396 exit 1
1397 }
1398
1399 # suffix may need to be created, in that case get suffix from user
1400 [ -n "${NEED_CREATE_SUFFIX}" ] &&
1401 {
1402 get_suffix || continue
1403 }
1404
1405 # suffix is ok, break out of the base dn inquire loop
1406 break
1407 done
1408 }
1409
1410 #
1411 # get_want_shadow_update(): Ask user if want to enable shadow update?
1412 #
1413 get_want_shadow_update()
1414 {
1415 MSG="Do you want to enable shadow update (y/n/h)?"
1416 get_confirm "$MSG" "n" "enable_shadow_update_help"
1417 if [ $? -eq 1 ]; then
1418 LDAP_ENABLE_SHADOW_UPDATE="TRUE"
1419 else
1420 LDAP_ENABLE_SHADOW_UPDATE="FALSE"
1421 fi
1422 }
1423
1424 get_krb_realm() {
1425
1426 # To upper cases
1427 LDAP_KRB_REALM=`${ECHO} ${LDAP_DOMAIN} | ${NAWK} '{ print toupper($0) }'`
1428 get_ans_req "Enter Kerberos Realm:" "$LDAP_KRB_REALM"
1429 # To upper cases
1430 LDAP_KRB_REALM=`${ECHO} ${ANS} | ${NAWK} '{ print toupper($0) }'`
1431 }
1432
1433 # $1: DN
1434 # $2: ldif file
1435 add_entry_by_DN() {
1436
1437 ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${1}\" -s base \"objectclass=*\" ${VERB}"
1438 if [ $? -eq 0 ]; then
1439 ${ECHO} " ${1} already exists"
1440 return 0
1441 else
1442 ${EVAL} "${LDAPADD} ${LDAP_ARGS} -f ${2} ${VERB}"
1443 if [ $? -eq 0 ]; then
1444 ${ECHO} " ${1} is added"
1445 return 0
1446 else
1447 ${ECHO} " ERROR: failed to add ${1}"
1448 return 1
1449 fi
1450 fi
1451
1452 }
1453 #
1454 # Kerberos princiapl to DN mapping rules
1455 #
1456 # Add rules for host credentails and user credentials
1457 #
1458 add_id_mapping_rules() {
1459
1460 ${ECHO} " Adding Kerberos principal to DN mapping rules..."
1461
1462 _C_DN="cn=GSSAPI,cn=identity mapping,cn=config"
1463 ( cat << EOF
1464 dn: cn=GSSAPI,cn=identity mapping,cn=config
1465 objectClass: top
1466 objectClass: nsContainer
1467 cn: GSSAPI
1468 EOF
1469 ) > ${TMPDIR}/GSSAPI_container.ldif
1470
1471 add_entry_by_DN "${_C_DN}" "${TMPDIR}/GSSAPI_container.ldif"
1472 if [ $? -ne 0 ];
1473 then
1474 ${RM} ${TMPDIR}/GSSAPI_container.ldif
1475 return
1476 fi
1477
1478 _H_CN="host_auth_${LDAP_KRB_REALM}"
1479 _H_DN="cn=${_H_CN}, ${_C_DN}"
1480 ( cat << EOF
1481 dn: ${_H_DN}
1482 objectClass: top
1483 objectClass: nsContainer
1484 objectClass: dsIdentityMapping
1485 objectClass: dsPatternMatching
1486 cn: ${_H_CN}
1487 dsMatching-pattern: \${Principal}
1488 dsMatching-regexp: host\/(.*).${LDAP_DOMAIN}@${LDAP_KRB_REALM}
1489 dsSearchBaseDN: ou=hosts,${LDAP_BASEDN}
1490 dsSearchFilter: (&(objectClass=ipHost)(cn=\$1))
1491 dsSearchScope: one
1492
1493 EOF
1494 ) > ${TMPDIR}/${_H_CN}.ldif
1495
1496 add_entry_by_DN "${_H_DN}" "${TMPDIR}/${_H_CN}.ldif"
1497
1498 _U_CN="user_auth_${LDAP_KRB_REALM}"
1499 _U_DN="cn=${_U_CN}, ${_C_DN}"
1500 ( cat << EOF
1501 dn: ${_U_DN}
1502 objectClass: top
1503 objectClass: nsContainer
1504 objectClass: dsIdentityMapping
1505 objectClass: dsPatternMatching
1506 cn: ${_U_CN}
1507 dsMatching-pattern: \${Principal}
1508 dsMatching-regexp: (.*)@${LDAP_KRB_REALM}
1509 dsMappedDN: uid=\$1,ou=People,${LDAP_BASEDN}
1510
1511 EOF
1512 ) > ${TMPDIR}/${_U_CN}.ldif
1513
1514 add_entry_by_DN "${_U_DN}" "${TMPDIR}/${_U_CN}.ldif"
1515
1516 }
1517
1518
1519 #
1520 # Modify ACL to allow root to read all the password and only self can read
1521 # its own password when sasl/GSSAPI bind is used
1522 #
1523 modify_userpassword_acl_for_gssapi() {
1524
1525 _P_DN="ou=People,${LDAP_BASEDN}"
1526 _H_DN="ou=Hosts,${LDAP_BASEDN}"
1527 _P_ACI="self-read-pwd"
1528
1529 ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${_P_DN}\" -s base \"objectclass=*\" > /dev/null 2>&1"
1530 if [ $? -ne 0 ]; then
1531 ${ECHO} " ${_P_DN} does not exist"
1532 # Not Found. Create a new entry
1533 ( cat << EOF
1534 dn: ${_P_DN}
1535 ou: People
1536 objectClass: top
1537 objectClass: organizationalUnit
1538 EOF
1539 ) > ${TMPDIR}/gssapi_people.ldif
1540
1541 add_entry_by_DN "${_P_DN}" "${TMPDIR}/gssapi_people.ldif"
1542 else
1543 ${ECHO} " ${_P_DN} already exists"
1544 fi
1545
1546 ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${_P_DN}\" -s base \"objectclass=*\" aci > ${TMPDIR}/chk_gssapi_aci 2>&1"
1547
1548 if [ $? -eq 0 ]; then
1549 ${EVAL} "${GREP} ${_P_ACI} ${TMPDIR}/chk_gssapi_aci > /dev/null 2>&1"
1550 if [ $? -eq 0 ]; then
1551 ${ECHO} " userpassword ACL ${_P_ACI} already exists."
1552 return
1553 else
1554 ${ECHO} " userpassword ACL ${_P_ACI} not found. Create a new one."
1555 fi
1556 else
1557 ${ECHO} " Error searching aci for ${_P_DN}"
1558 cat ${TMPDIR}/chk_gssapi_aci
1559 cleanup
1560 exit 1
1561 fi
1562 ( cat << EOF
1563 dn: ${_P_DN}
1564 changetype: modify
1565 add: aci
1566 aci: (targetattr="userPassword")(version 3.0; acl self-read-pwd; allow (read,search) userdn="ldap:///self" and authmethod="sasl GSSAPI";)
1567 -
1568 add: aci
1569 aci: (targetattr="userPassword")(version 3.0; acl host-read-pwd; allow (read,search) userdn="ldap:///cn=*+ipHostNumber=*,ou=Hosts,${LDAP_BASEDN}" and authmethod="sasl GSSAPI";)
1570 EOF
1571 ) > ${TMPDIR}/user_gssapi.ldif
1572 LDAP_TYPE_OR_VALUE_EXISTS=20
1573 ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/user_gssapi.ldif ${VERB}"
1574
1575 case $? in
1576 0)
1577 ${ECHO} " ${_P_DN} uaserpassword ACL is updated."
1578 ;;
1579 20)
1580 ${ECHO} " ${_P_DN} uaserpassword ACL already exists."
1581 ;;
1582 *)
1583 ${ECHO} " ERROR: update of userpassword ACL for ${_P_DN} failed!"
1584 cleanup
1585 exit 1
1586 ;;
1587 esac
1588 }
1589 #
1590 # $1: objectclass or attributetyp
1591 # $2: name
1592 search_update_schema() {
1593
1594 ATTR="${1}es"
1595
1596 ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b cn=schema -s base \"objectclass=*\" ${ATTR} | ${GREP} -i \"${2}\" ${VERB}"
1597 if [ $? -ne 0 ]; then
1598 ${ECHO} "${1} ${2} does not exist."
1599 update_schema_attr
1600 update_schema_obj
1601 SCHEMA_UPDATED=1
1602 else
1603 ${ECHO} "${1} ${2} already exists. Schema has been updated"
1604 fi
1605 }
1606
1607 #
1608 # Set up GSSAPI if necessary
1609 #
1610 gssapi_setup() {
1611
1612 GSSAPI_ENABLE=0
1613
1614 # assume sasl/GSSAPI is supported by the ldap server and may be used
1615 GSSAPI_AUTH_MAY_BE_USED=1
1616
1617 ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"\" -s base \"objectclass=*\" supportedSASLMechanisms | ${GREP} GSSAPI ${VERB}"
1618 if [ $? -ne 0 ]; then
1619 GSSAPI_AUTH_MAY_BE_USED=0
1620 ${ECHO} " sasl/GSSAPI is not supported by this LDAP server"
1621 return
1622 fi
1623
1624 get_confirm "GSSAPI is supported. Do you want to set up gssapi:(y/n)" "n"
1625 if [ $? -eq 0 ]; then
1626 GSSAPI_ENABLE=0
1627 ${ECHO}
1628 ${ECHO} "GSSAPI is not set up."
1629 ${ECHO} "sasl/GSSAPI bind may not work if it's not set up first."
1630 else
1631 GSSAPI_ENABLE=1
1632 get_krb_realm
1633 fi
1634
1635 }
1636 #
1637 # get_profile_name(): Enter the profile name.
1638 #
1639 get_profile_name()
1640 {
1641 # Reset Delete Old Profile since getting new profile name.
1642 DEL_OLD_PROFILE=0
1643
1644 # Loop until valid profile name, or replace.
1645 while :
1646 do
1647 # Prompt for profile name.
1648 get_ans "Enter the profile name (h=help):" "$LDAP_PROFILE_NAME"
1649
1650 # Check for Help.
1651 case "$ANS" in
1652 [Hh] | help | Help | \?) display_msg profile_help
1653 continue ;;
1654 * ) ;;
1655 esac
1656
1657 # Search to see if profile name already exists.
1658 eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${ANS},ou=profile,${LDAP_BASEDN}\" -s base \"objectclass=*\" ${VERB}"
1659 if [ $? -eq 0 ]; then
1660
1661 cat << EOF
1662
1663 Profile '${ANS}' already exists, it is possible to enable
1664 shadow update now. idsconfig will exit after shadow update
1665 is enabled. You can also continue to overwrite the profile
1666 or create a new one and be given the chance to enable
1667 shadow update later.
1668
1669 EOF
1670
1671 MSG="Just enable shadow update (y/n/h)?"
1672 get_confirm "$MSG" "n" "enable_shadow_update_help"
1673 if [ $? -eq 1 ]; then
1674 [ $DEBUG -eq 1 ] && ${ECHO} "set up shadow update"
1675 LDAP_ENABLE_SHADOW_UPDATE=TRUE
1676 # display alternate messages
1677 EXISTING_PROFILE=1
1678 # Set Profile Name.
1679 LDAP_PROFILE_NAME=$ANS
1680 return 0 # set up credentials for shadow update.
1681 fi
1682
1683 get_confirm_nodef "Are you sure you want to overwrite profile cn=${ANS}?"
1684 if [ $? -eq 1 ]; then
1685 DEL_OLD_PROFILE=1
1686 return 0 # Replace old profile name.
1687 else
1688 ${ECHO} "Please re-enter a new profile name."
1689 fi
1690 else
1691 break # Unique profile name.
1692 fi
1693 done
1694
1695 # Set Profile Name.
1696 LDAP_PROFILE_NAME=$ANS
1697 }
1698
1699
1700 #
1701 # get_srv_list(): Get the default server list.
1702 #
1703 get_srv_list()
1704 {
1705 # If LDAP_SERVER_LIST is NULL, then set, otherwise leave alone.
1706 if [ -z "${LDAP_SERVER_LIST}" ]; then
1707 LDAP_SERVER_LIST=`getent hosts ${IDS_SERVER} | awk '{print $1}'`
1708 if [ ${IDS_PORT} -ne 389 ]; then
1709 LDAP_SERVER_LIST="${LDAP_SERVER_LIST}:${IDS_PORT}"
1710 fi
1711 fi
1712
1713 # Prompt for new LDAP_SERVER_LIST.
1714 while :
1715 do
1716 get_ans "Default server list (h=help):" $LDAP_SERVER_LIST
1717
1718 # If help continue, otherwise break.
1719 case "$ANS" in
1720 [Hh] | help | Help | \?) display_msg def_srvlist_help ;;
1721 * ) break ;;
1722 esac
1723 done
1724 LDAP_SERVER_LIST=$ANS
1725 }
1726
1727
1728 #
1729 # get_pref_srv(): The preferred server list (Overrides the server list)
1730 #
1731 get_pref_srv()
1732 {
1733 while :
1734 do
1735 get_ans "Preferred server list (h=help):" $LDAP_PREF_SRVLIST
1736
1737 # If help continue, otherwise break.
1738 case "$ANS" in
1739 [Hh] | help | Help | \?) display_msg pref_srvlist_help ;;
1740 * ) break ;;
1741 esac
1742 done
1743 LDAP_PREF_SRVLIST=$ANS
1744 }
1745
1746
1747 #
1748 # get_search_scope(): Get the search scope from the user.
1749 #
1750 get_search_scope()
1751 {
1752 [ $DEBUG -eq 1 ] && ${ECHO} "In get_search_scope()"
1753
1754 _MENU_CHOICE=0
1755 while :
1756 do
1757 get_ans "Choose desired search scope (one, sub, h=help): " "one"
1758 _MENU_CHOICE=$ANS
1759 case "$_MENU_CHOICE" in
1760 one) LDAP_SEARCH_SCOPE="one"
1761 return 1 ;;
1762 sub) LDAP_SEARCH_SCOPE="sub"
1763 return 2 ;;
1764 h) display_msg srch_scope_help ;;
1765 *) ${ECHO} "Please enter \"one\", \"sub\", or \"h\"." ;;
1766 esac
1767 done
1768
1769 }
1770
1771
1772 #
1773 # get_cred_level(): Function to display menu to user and get the
1774 # credential level.
1775 #
1776 get_cred_level()
1777 {
1778 [ $DEBUG -eq 1 ] && ${ECHO} "In get_cred_level()"
1779
1780 _MENU_CHOICE=0
1781 display_msg cred_level_menu
1782 while :
1783 do
1784 if [ $GSSAPI_ENABLE -eq 1 ]; then
1785 ${ECHO} '"self" is needed for GSSAPI profile'
1786 fi
1787 get_ans "Choose Credential level [h=help]:" "1"
1788 _MENU_CHOICE=$ANS
1789 case "$_MENU_CHOICE" in
1790 1) LDAP_CRED_LEVEL="anonymous"
1791 return 1 ;;
1792 2) LDAP_CRED_LEVEL="proxy"
1793 return 2 ;;
1794 3) LDAP_CRED_LEVEL="proxy anonymous"
1795 return 3 ;;
1796 4) LDAP_CRED_LEVEL="self"
1797 return 4 ;;
1798 h) display_msg cred_lvl_help ;;
1799 *) ${ECHO} "Please enter 1, 2, 3 or 4." ;;
1800 esac
1801 done
1802 }
1803
1804
1805 #
1806 # srvauth_menu_handler(): Enter the Service Authentication method.
1807 #
1808 srvauth_menu_handler()
1809 {
1810 # Display Auth menu
1811 display_msg srvauth_method_menu
1812
1813 # Get a Valid choice.
1814 while :
1815 do
1816 # Display appropriate prompt and get answer.
1817 if [ $_FIRST -eq 1 ]; then
1818 get_ans "Choose Service Authentication Method:" "1"
1819 else
1820 get_ans "Choose Service Authentication Method (0=reset):"
1821 fi
1822
1823 # Determine choice.
1824 _MENU_CHOICE=$ANS
1825 case "$_MENU_CHOICE" in
1826 1) _AUTHMETHOD="simple"
1827 break ;;
1828 2) _AUTHMETHOD="sasl/DIGEST-MD5"
1829 break ;;
1830 3) _AUTHMETHOD="tls:simple"
1831 break ;;
1832 4) _AUTHMETHOD="tls:sasl/DIGEST-MD5"
1833 break ;;
1834 5) _AUTHMETHOD="sasl/GSSAPI"
1835 break ;;
1836 0) _AUTHMETHOD=""
1837 _FIRST=1
1838 break ;;
1839 *) ${ECHO} "Please enter 1-5 or 0 to reset." ;;
1840 esac
1841 done
1842 }
1843
1844
1845 #
1846 # auth_menu_handler(): Enter the Authentication method.
1847 #
1848 auth_menu_handler()
1849 {
1850 # Display Auth menu
1851 display_msg auth_method_menu
1852
1853 # Get a Valid choice.
1854 while :
1855 do
1856 if [ $GSSAPI_ENABLE -eq 1 ]; then
1857 ${ECHO} '"sasl/GSSAPI" is needed for GSSAPI profile'
1858 fi
1859 # Display appropriate prompt and get answer.
1860 if [ $_FIRST -eq 1 ]; then
1861 get_ans "Choose Authentication Method (h=help):" "1"
1862 else
1863 get_ans "Choose Authentication Method (0=reset, h=help):"
1864 fi
1865
1866 # Determine choice.
1867 _MENU_CHOICE=$ANS
1868 case "$_MENU_CHOICE" in
1869 1) _AUTHMETHOD="none"
1870 break ;;
1871 2) _AUTHMETHOD="simple"
1872 break ;;
1873 3) _AUTHMETHOD="sasl/DIGEST-MD5"
1874 break ;;
1875 4) _AUTHMETHOD="tls:simple"
1876 break ;;
1877 5) _AUTHMETHOD="tls:sasl/DIGEST-MD5"
1878 break ;;
1879 6) _AUTHMETHOD="sasl/GSSAPI"
1880 break ;;
1881 0) _AUTHMETHOD=""
1882 _FIRST=1
1883 break ;;
1884 h) display_msg auth_help ;;
1885 *) ${ECHO} "Please enter 1-6, 0=reset, or h=help." ;;
1886 esac
1887 done
1888 }
1889
1890
1891 #
1892 # get_auth(): Enter the Authentication method.
1893 #
1894 get_auth()
1895 {
1896 [ $DEBUG -eq 1 ] && ${ECHO} "In get_auth()"
1897
1898 _FIRST=1 # Flag for first time.
1899 _MENU_CHOICE=0
1900 _AUTHMETHOD="" # Tmp method.
1901
1902 while :
1903 do
1904 # Call Menu handler
1905 auth_menu_handler
1906
1907 # Add Auth Method to list.
1908 if [ $_FIRST -eq 1 ]; then
1909 LDAP_AUTHMETHOD="${_AUTHMETHOD}"
1910 _FIRST=0
1911 else
1912 LDAP_AUTHMETHOD="${LDAP_AUTHMETHOD};${_AUTHMETHOD}"
1913 fi
1914
1915 # Display current Authentication Method.
1916 ${ECHO} ""
1917 ${ECHO} "Current authenticationMethod: ${LDAP_AUTHMETHOD}"
1918 ${ECHO} ""
1919
1920 # Prompt for another Auth Method, or break out.
1921 get_confirm_nodef "Do you want to add another Authentication Method?"
1922 if [ $? -eq 0 ]; then
1923 break;
1924 fi
1925 done
1926 }
1927
1928
1929 #
1930 # get_followref(): Whether or not to follow referrals.
1931 #
1932 get_followref()
1933 {
1934 get_confirm "Do you want the clients to follow referrals (y/n/h)?" "n" "referrals_help"
1935 if [ $? -eq 1 ]; then
1936 LDAP_FOLLOWREF="TRUE"
1937 else
1938 LDAP_FOLLOWREF="FALSE"
1939 fi
1940 }
1941
1942
1943 #
1944 # get_timelimit(): Set the time limit. -1 is max time.
1945 #
1946 get_timelimit()
1947 {
1948 # Get current timeout value from cn=config.
1949 eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=config\" -s base \"objectclass=*\" nsslapd-timelimit > ${TMPDIR}/chk_timeout 2>&1"
1950 if [ $? -ne 0 ]; then
1951 ${ECHO} " ERROR: Could not reach LDAP server to check current timeout!"
1952 cleanup
1953 exit 1
1954 fi
1955 CURR_TIMELIMIT=`${GREP} timelimit ${TMPDIR}/chk_timeout | cut -f2 -d=`
1956
1957 get_negone_num "Enter the time limit for iDS (current=${CURR_TIMELIMIT}):" "-1"
1958 IDS_TIMELIMIT=$NUM
1959 }
1960
1961
1962 #
1963 # get_sizelimit(): Set the size limit. -1 is max size.
1964 #
1965 get_sizelimit()
1966 {
1967 # Get current sizelimit value from cn=config.
1968 eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=config\" -s base \"objectclass=*\" nsslapd-sizelimit > ${TMPDIR}/chk_sizelimit 2>&1"
1969 if [ $? -ne 0 ]; then
1970 ${ECHO} " ERROR: Could not reach LDAP server to check current sizelimit!"
1971 cleanup
1972 exit 1
1973 fi
1974 CURR_SIZELIMIT=`${GREP} sizelimit ${TMPDIR}/chk_sizelimit | cut -f2 -d=`
1975
1976 get_negone_num "Enter the size limit for iDS (current=${CURR_SIZELIMIT}):" "-1"
1977 IDS_SIZELIMIT=$NUM
1978 }
1979
1980
1981 #
1982 # get_want_crypt(): Ask user if want to store passwords in crypt?
1983 #
1984 get_want_crypt()
1985 {
1986 get_confirm "Do you want to store passwords in \"crypt\" format (y/n/h)?" "n" "crypt_help"
1987 if [ $? -eq 1 ]; then
1988 NEED_CRYPT="TRUE"
1989 else
1990 NEED_CRYPT="FALSE"
1991 fi
1992 }
1993
1994
1995 #
1996 # get_srv_authMethod_pam(): Get the Service Auth Method for pam_ldap from user.
1997 #
1998 # NOTE: This function is base on get_auth().
1999 #
2000 get_srv_authMethod_pam()
2001 {
2002 [ $DEBUG -eq 1 ] && ${ECHO} "In get_srv_authMethod_pam()"
2003
2004 _FIRST=1 # Flag for first time.
2005 _MENU_CHOICE=0
2006 _AUTHMETHOD="" # Tmp method.
2007
2008 while :
2009 do
2010 # Call Menu handler
2011 srvauth_menu_handler
2012
2013 # Add Auth Method to list.
2014 if [ $_FIRST -eq 1 ]; then
2015 if [ "$_AUTHMETHOD" = "" ]; then
2016 LDAP_SRV_AUTHMETHOD_PAM=""
2017 else
2018 LDAP_SRV_AUTHMETHOD_PAM="pam_ldap:${_AUTHMETHOD}"
2019 fi
2020 _FIRST=0
2021 else
2022 LDAP_SRV_AUTHMETHOD_PAM="${LDAP_SRV_AUTHMETHOD_PAM};${_AUTHMETHOD}"
2023 fi
2024
2025 # Display current Authentication Method.
2026 ${ECHO} ""
2027 ${ECHO} "Current authenticationMethod: ${LDAP_SRV_AUTHMETHOD_PAM}"
2028 ${ECHO} ""
2029
2030 # Prompt for another Auth Method, or break out.
2031 get_confirm_nodef "Do you want to add another Authentication Method?"
2032 if [ $? -eq 0 ]; then
2033 break;
2034 fi
2035 done
2036
2037 # Check in case user reset string and exited loop.
2038 if [ "$LDAP_SRV_AUTHMETHOD_PAM" = "" ]; then
2039 NEED_SRVAUTH_PAM=0
2040 fi
2041 }
2042
2043
2044 #
2045 # get_srv_authMethod_key(): Get the Service Auth Method for keyserv from user.
2046 #
2047 # NOTE: This function is base on get_auth().
2048 #
2049 get_srv_authMethod_key()
2050 {
2051 [ $DEBUG -eq 1 ] && ${ECHO} "In get_srv_authMethod_key()"
2052
2053 _FIRST=1 # Flag for first time.
2054 _MENU_CHOICE=0
2055 _AUTHMETHOD="" # Tmp method.
2056
2057 while :
2058 do
2059 # Call Menu handler
2060 srvauth_menu_handler
2061
2062 # Add Auth Method to list.
2063 if [ $_FIRST -eq 1 ]; then
2064 if [ "$_AUTHMETHOD" = "" ]; then
2065 LDAP_SRV_AUTHMETHOD_KEY=""
2066 else
2067 LDAP_SRV_AUTHMETHOD_KEY="keyserv:${_AUTHMETHOD}"
2068 fi
2069 _FIRST=0
2070 else
2071 LDAP_SRV_AUTHMETHOD_KEY="${LDAP_SRV_AUTHMETHOD_KEY};${_AUTHMETHOD}"
2072 fi
2073
2074 # Display current Authentication Method.
2075 ${ECHO} ""
2076 ${ECHO} "Current authenticationMethod: ${LDAP_SRV_AUTHMETHOD_KEY}"
2077 ${ECHO} ""
2078
2079 # Prompt for another Auth Method, or break out.
2080 get_confirm_nodef "Do you want to add another Authentication Method?"
2081 if [ $? -eq 0 ]; then
2082 break;
2083 fi
2084 done
2085
2086 # Check in case user reset string and exited loop.
2087 if [ "$LDAP_SRV_AUTHMETHOD_KEY" = "" ]; then
2088 NEED_SRVAUTH_KEY=0
2089 fi
2090 }
2091
2092
2093 #
2094 # get_srv_authMethod_cmd(): Get the Service Auth Method for passwd-cmd from user.
2095 #
2096 # NOTE: This function is base on get_auth().
2097 #
2098 get_srv_authMethod_cmd()
2099 {
2100 [ $DEBUG -eq 1 ] && ${ECHO} "In get_srv_authMethod_cmd()"
2101
2102 _FIRST=1 # Flag for first time.
2103 _MENU_CHOICE=0
2104 _AUTHMETHOD="" # Tmp method.
2105
2106 while :
2107 do
2108 # Call Menu handler
2109 srvauth_menu_handler
2110
2111 # Add Auth Method to list.
2112 if [ $_FIRST -eq 1 ]; then
2113 if [ "$_AUTHMETHOD" = "" ]; then
2114 LDAP_SRV_AUTHMETHOD_CMD=""
2115 else
2116 LDAP_SRV_AUTHMETHOD_CMD="passwd-cmd:${_AUTHMETHOD}"
2117 fi
2118 _FIRST=0
2119 else
2120 LDAP_SRV_AUTHMETHOD_CMD="${LDAP_SRV_AUTHMETHOD_CMD};${_AUTHMETHOD}"
2121 fi
2122
2123 # Display current Authentication Method.
2124 ${ECHO} ""
2125 ${ECHO} "Current authenticationMethod: ${LDAP_SRV_AUTHMETHOD_CMD}"
2126 ${ECHO} ""
2127
2128 # Prompt for another Auth Method, or break out.
2129 get_confirm_nodef "Do you want to add another Authentication Method?"
2130 if [ $? -eq 0 ]; then
2131 break;
2132 fi
2133 done
2134
2135 # Check in case user reset string and exited loop.
2136 if [ "$LDAP_SRV_AUTHMETHOD_CMD" = "" ]; then
2137 NEED_SRVAUTH_CMD=0
2138 fi
2139 }
2140
2141
2142 #
2143 # get_srch_time(): Amount of time to search.
2144 #
2145 get_srch_time()
2146 {
2147 get_negone_num "Client search time limit in seconds (h=help):" "$LDAP_SEARCH_TIME_LIMIT" "srchtime_help"
2148 LDAP_SEARCH_TIME_LIMIT=$NUM
2149 }
2150
2151
2152 #
2153 # get_prof_ttl(): The profile time to live (TTL)
2154 #
2155 get_prof_ttl()
2156 {
2157 get_negone_num "Profile Time To Live in seconds (h=help):" "$LDAP_PROFILE_TTL" "profttl_help"
2158 LDAP_PROFILE_TTL=$NUM
2159 }
2160
2161
2162 #
2163 # get_bind_limit(): Bind time limit
2164 #
2165 get_bind_limit()
2166 {
2167 get_negone_num "Bind time limit in seconds (h=help):" "$LDAP_BIND_LIMIT" "bindlim_help"
2168 LDAP_BIND_LIMIT=$NUM
2169 }
2170
2171
2172 ######################################################################
2173 # FUNCTIONS FOR Service Search Descriptor's START HERE.
2174 ######################################################################
2175
2176
2177 #
2178 # add_ssd(): Get SSD's from user and add to file.
2179 #
2180 add_ssd()
2181 {
2182 [ $DEBUG -eq 1 ] && ${ECHO} "In add_ssd()"
2183
2184 # Enter the service id. Loop til unique.
2185 while :
2186 do
2187 get_ans "Enter the service id:"
2188 _SERV_ID=$ANS
2189
2190 # Grep for name existing.
2191 ${GREP} -i "^$ANS:" ${SSD_FILE} > /dev/null 2>&1
2192 if [ $? -eq 1 ]; then
2193 break
2194 fi
2195
2196 # Name exists, print message, let user decide.
2197 ${ECHO} "ERROR: Service id ${ANS} already exists."
2198 done
2199
2200 get_ans "Enter the base:"
2201 _BASE=$ANS
2202
2203 # Get the scope and verify that its one or sub.
2204 while :
2205 do
2206 get_ans "Enter the scope:"
2207 _SCOPE=$ANS
2208 case `${ECHO} ${_SCOPE} | tr '[A-Z]' '[a-z]'` in
2209 one) break ;;
2210 sub) break ;;
2211 *) ${ECHO} "${_SCOPE} is Not valid - Enter 'one' or 'sub'" ;;
2212 esac
2213 done
2214
2215 # Build SSD to add to file.
2216 _SSD="${_SERV_ID}:${_BASE}?${_SCOPE}"
2217
2218 # Add the SSD to the file.
2219 ${ECHO} "${_SSD}" >> ${SSD_FILE}
2220 }
2221
2222
2223 #
2224 # delete_ssd(): Delete a SSD from the list.
2225 #
2226 delete_ssd()
2227 {
2228 [ $DEBUG -eq 1 ] && ${ECHO} "In delete_ssd()"
2229
2230 # Get service id name from user for SSD to delete.
2231 get_ans_req "Enter service id to delete:"
2232
2233 # Make sure service id exists.
2234 ${GREP} "$ANS" ${SSD_FILE} > /dev/null 2>&1
2235 if [ $? -eq 1 ]; then
2236 ${ECHO} "Invalid service id: $ANS not present in list."
2237 return
2238 fi
2239
2240 # Create temporary back SSD file.
2241 cp ${SSD_FILE} ${SSD_FILE}.bak
2242 if [ $? -eq 1 ]; then
2243 ${ECHO} "ERROR: could not create file: ${SSD_FILE}.bak"
2244 exit 1
2245 fi
2246
2247 # Use ${GREP} to remove the SSD. Read from temp file
2248 # and write to the orig file.
2249 ${GREP} -v "$ANS" ${SSD_FILE}.bak > ${SSD_FILE}
2250 }
2251
2252
2253 #
2254 # modify_ssd(): Allow user to modify a SSD.
2255 #
2256 modify_ssd()
2257 {
2258 [ $DEBUG -eq 1 ] && ${ECHO} "In modify_ssd()"
2259
2260 # Prompt user for service id.
2261 get_ans_req "Enter service id to modify:"
2262
2263 # Put into temp _LINE.
2264 _LINE=`${GREP} "^$ANS:" ${SSD_FILE}`
2265 if [ "$_LINE" = "" ]; then
2266 ${ECHO} "Invalid service id: $ANS"
2267 return
2268 fi
2269
2270 # Display current filter for user to see.
2271 ${ECHO} ""
2272 ${ECHO} "Current SSD: $_LINE"
2273 ${ECHO} ""
2274
2275 # Get the defaults.
2276 _CURR_BASE=`${ECHO} $_LINE | cut -d: -f2 | cut -d'?' -f 1`
2277 _CURR_SCOPE=`${ECHO} $_LINE | cut -d: -f2 | cut -d'?' -f 2`
2278
2279 # Create temporary back SSD file.
2280 cp ${SSD_FILE} ${SSD_FILE}.bak
2281 if [ $? -eq 1 ]; then
2282 ${ECHO} "ERROR: could not create file: ${SSD_FILE}.bak"
2283 cleanup
2284 exit 1
2285 fi
2286
2287 # Removed the old line.
2288 ${GREP} -v "^$ANS:" ${SSD_FILE}.bak > ${SSD_FILE} 2>&1
2289
2290 # New Entry
2291 _SERV_ID=$ANS
2292 get_ans_req "Enter the base:" "$_CURR_BASE"
2293 _BASE=$ANS
2294 get_ans_req "Enter the scope:" "$_CURR_SCOPE"
2295 _SCOPE=$ANS
2296
2297 # Build the new SSD.
2298 _SSD="${_SERV_ID}:${_BASE}?${_SCOPE}"
2299
2300 # Add the SSD to the file.
2301 ${ECHO} "${_SSD}" >> ${SSD_FILE}
2302 }
2303
2304
2305 #
2306 # display_ssd(): Display the current SSD list.
2307 #
2308 display_ssd()
2309 {
2310 [ $DEBUG -eq 1 ] && ${ECHO} "In display_ssd()"
2311
2312 ${ECHO} ""
2313 ${ECHO} "Current Service Search Descriptors:"
2314 ${ECHO} "=================================="
2315 cat ${SSD_FILE}
2316 ${ECHO} ""
2317 ${ECHO} "Hit return to continue."
2318 read __A
2319 }
2320
2321
2322 #
2323 # prompt_ssd(): Get SSD's from user.
2324 #
2325 prompt_ssd()
2326 {
2327 [ $DEBUG -eq 1 ] && ${ECHO} "In prompt_ssd()"
2328 # See if user wants SSD's?
2329 get_confirm "Do you wish to setup Service Search Descriptors (y/n/h)?" "n" "ssd_help"
2330 [ "$?" -eq 0 ] && return
2331
2332 # Display menu for SSD choices.
2333 while :
2334 do
2335 display_msg prompt_ssd_menu
2336 get_ans "Enter menu choice:" "Quit"
2337 case "$ANS" in
2338 [Aa] | add) add_ssd ;;
2339 [Dd] | delete) delete_ssd ;;
2340 [Mm] | modify) modify_ssd ;;
2341 [Pp] | print | display) display_ssd ;;
2342 [Xx] | reset | clear) reset_ssd_file ;;
2343 [Hh] | Help | help) display_msg ssd_menu_help
2344 ${ECHO} " Press return to continue."
2345 read __A ;;
2346 [Qq] | Quit | quit) return ;;
2347 *) ${ECHO} "Invalid choice: $ANS please re-enter from menu." ;;
2348 esac
2349 done
2350 }
2351
2352
2353 #
2354 # reset_ssd_file(): Blank out current SSD file.
2355 #
2356 reset_ssd_file()
2357 {
2358 [ $DEBUG -eq 1 ] && ${ECHO} "In reset_ssd_file()"
2359
2360 rm -f ${SSD_FILE}
2361 touch ${SSD_FILE}
2362 }
2363
2364
2365 #
2366 # create_ssd_file(): Create a temporary file for SSD's.
2367 #
2368 create_ssd_file()
2369 {
2370 [ $DEBUG -eq 1 ] && ${ECHO} "In create_ssd_file()"
2371
2372 # Build a list of SSD's and store in temp file.
2373 ${GREP} "LDAP_SERV_SRCH_DES=" ${INPUT_FILE} | \
2374 sed 's/LDAP_SERV_SRCH_DES=//' \
2375 > ${SSD_FILE}
2376 }
2377
2378
2379 #
2380 # ssd_2_config(): Append the SSD file to the output file.
2381 #
2382 ssd_2_config()
2383 {
2384 [ $DEBUG -eq 1 ] && ${ECHO} "In ssd_2_config()"
2385
2386 # Convert to config file format using sed.
2387 sed -e "s/^/LDAP_SERV_SRCH_DES=/" ${SSD_FILE} >> ${OUTPUT_FILE}
2388 }
2389
2390
2391 #
2392 # ssd_2_profile(): Add SSD's to the GEN_CMD string.
2393 #
2394 ssd_2_profile()
2395 {
2396 [ $DEBUG -eq 1 ] && ${ECHO} "In ssd_2_profile()"
2397
2398 GEN_TMPFILE=${TMPDIR}/ssd_tmpfile
2399 touch ${GEN_TMPFILE}
2400
2401 # Add and convert each SSD to string.
2402 while read SSD_LINE
2403 do
2404 ${ECHO} " -a \"serviceSearchDescriptor=${SSD_LINE}\"\c" >> ${GEN_TMPFILE}
2405 done <${SSD_FILE}
2406
2407 # Add SSD's to GEN_CMD.
2408 GEN_CMD="${GEN_CMD} `cat ${GEN_TMPFILE}`"
2409 }
2410
2411 #
2412 # get_adminDN(): Get the admin DN.
2413 #
2414 get_adminDN()
2415 {
2416 LDAP_ADMINDN="cn=admin,ou=profile,${LDAP_BASEDN}" # default
2417 get_ans "Enter DN for the administrator:" "$LDAP_ADMINDN"
2418 LDAP_ADMINDN=$ANS
2419 [ $DEBUG -eq 1 ] && ${ECHO} "LDAP_ADMINDN = $LDAP_ADMINDN"
2420 }
2421
2422 #
2423 # get_admin_pw(): Get the admin passwd.
2424 #
2425 get_admin_pw()
2426 {
2427 get_passwd "Enter passwd for the administrator:"
2428 LDAP_ADMIN_CRED=$ANS
2429 [ $DEBUG -eq 1 ] && ${ECHO} "LDAP_ADMIN_CRED = $LDAP_ADMIN_CRED"
2430 }
2431
2432 #
2433 # add_admin(): Add an admin entry for nameservice for updating shadow data.
2434 #
2435 add_admin()
2436 {
2437 [ $DEBUG -eq 1 ] && ${ECHO} "In add_admin()"
2438
2439 # Check if the admin user already exists.
2440 eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_ADMINDN}\" -s base \"objectclass=*\" ${VERB}"
2441 if [ $? -eq 0 ]; then
2442 MSG="Administrator ${LDAP_ADMINDN} already exists."
2443 if [ $EXISTING_PROFILE -eq 1 ]; then
2444 ${ECHO} " NOT ADDED: $MSG"
2445 else
2446 ${ECHO} " ${STEP}. $MSG"
2447 STEP=`expr $STEP + 1`
2448 fi
2449 return 0
2450 fi
2451
2452 # Get cn and sn names from LDAP_ADMINDN.
2453 cn_tmp=`${ECHO} ${LDAP_ADMINDN} | cut -f1 -d, | cut -f2 -d=`
2454
2455 # Create the tmp file to add.
2456 ( cat <<EOF
2457 dn: ${LDAP_ADMINDN}
2458 cn: ${cn_tmp}
2459 sn: ${cn_tmp}
2460 objectclass: top
2461 objectclass: person
2462 userpassword: ${LDAP_ADMIN_CRED}
2463 EOF
2464 ) > ${TMPDIR}/admin
2465
2466 # Add the entry.
2467 ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/admin ${VERB}"
2468 if [ $? -ne 0 ]; then
2469 ${ECHO} " ERROR: Adding administrator identity failed!"
2470 cleanup
2471 exit 1
2472 fi
2473
2474 ${RM} -f ${TMPDIR}/admin
2475
2476 # Display message that the administrator identity is added.
2477 MSG="Administrator identity ${LDAP_ADMINDN}"
2478 if [ $EXISTING_PROFILE -eq 1 ]; then
2479 ${ECHO} " ADDED: $MSG."
2480 else
2481 ${ECHO} " ${STEP}. $MSG added."
2482 STEP=`expr $STEP + 1`
2483 fi
2484 }
2485
2486 #
2487 # allow_admin_read_write_shadow(): Give Admin read/write permission
2488 # to shadow data.
2489 #
2490 allow_admin_read_write_shadow()
2491 {
2492 [ $DEBUG -eq 1 ] && ${ECHO} "In allow_admin_read_write_shadow()"
2493
2494 # Set ACI Name
2495 ADMIN_ACI_NAME="LDAP_Naming_Services_admin_shadow_write"
2496
2497 # Search for ACI_NAME
2498 eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" \
2499 -s base objectclass=* aci > ${TMPDIR}/chk_adminwrite_aci 2>&1"
2500
2501 # if an ACI with ${ADMIN_ACI_NAME} and "write,compare,read,search"
2502 # and ${LDAP_ADMINDN} already exists, we are done
2503 ${EGREP} ".*${ADMIN_ACI_NAME}.*write,compare,read,search.*${LDAP_ADMINDN}.*" \
2504 ${TMPDIR}/chk_adminwrite_aci 2>&1 > /dev/null
2505 if [ $? -eq 0 ]; then
2506 MSG="Admin ACI ${ADMIN_ACI_NAME} already exists for ${LDAP_BASEDN}."
2507 if [ $EXISTING_PROFILE -eq 1 ]; then
2508 ${ECHO} " NOT SET: $MSG"
2509 else
2510 ${ECHO} " ${STEP}. $MSG"
2511 STEP=`expr $STEP + 1`
2512 fi
2513 return 0
2514 fi
2515
2516 # If an ACI with ${ADMIN_ACI_NAME} and "(write)" and ${LDAP_ADMINDN}
2517 # already exists, delete it first.
2518 find_and_delete_ACI ".*${ADMIN_ACI_NAME}.*(write).*${LDAP_ADMINDN}.*" \
2519 ${TMPDIR}/chk_adminwrite_aci ${ADMIN_ACI_NAME}
2520
2521 # Create the tmp file to add.
2522 ( cat <<EOF
2523 dn: ${LDAP_BASEDN}
2524 changetype: modify
2525 add: aci
2526 aci: (target="ldap:///${LDAP_BASEDN}")(targetattr="shadowLastChange
2527 ||shadowMin||shadowMax||shadowWarning||shadowInactive||shadowExpire
2528 ||shadowFlag||userPassword||loginShell||homeDirectory||gecos")
2529 (version 3.0; acl ${ADMIN_ACI_NAME}; allow (write,compare,read,search)
2530 userdn = "ldap:///${LDAP_ADMINDN}";)
2531 EOF
2532 ) > ${TMPDIR}/admin_write
2533
2534 # Add the entry.
2535 ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/admin_write ${VERB}"
2536 if [ $? -ne 0 ]; then
2537 ${ECHO} " ERROR: Allow ${LDAP_ADMINDN} read/write access to shadow data failed!"
2538 cleanup
2539 exit 1
2540 fi
2541
2542 ${RM} -f ${TMPDIR}/admin_write
2543 # Display message that the administrator ACL is set.
2544 MSG="Give ${LDAP_ADMINDN} read/write access to shadow data."
2545 if [ $EXISTING_PROFILE -eq 1 ]; then
2546 ${ECHO} " ACI SET: $MSG"
2547 else
2548 ${ECHO} " ${STEP}. $MSG"
2549 STEP=`expr $STEP + 1`
2550 fi
2551 }
2552
2553 #
2554 # allow_host_read_write_shadow(): Give host principal read/write permission
2555 # for shadow data.
2556 #
2557 allow_host_read_write_shadow()
2558 {
2559 [ $DEBUG -eq 1 ] && ${ECHO} "In allow_host_read_write_shadow()"
2560
2561 # Set ACI Name
2562 HOST_ACI_NAME="LDAP_Naming_Services_host_shadow_write"
2563
2564 # Search for ACI_NAME
2565 eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_hostwrite_aci 2>&1"
2566 ${GREP} "${HOST_ACI_NAME}" ${TMPDIR}/chk_hostwrite_aci > /dev/null 2>&1
2567 if [ $? -eq 0 ]; then
2568 MSG="Host ACI ${HOST_ACI_NAME} already exists for ${LDAP_BASEDN}."
2569 if [ $EXISTING_PROFILE -eq 1 ]; then
2570 ${ECHO} " NOT ADDED: $MSG"
2571 else
2572 ${ECHO} " ${STEP}. $MSG"
2573 STEP=`expr $STEP + 1`
2574 fi
2575 return 0
2576 fi
2577
2578 # Create the tmp file to add.
2579 ( cat <<EOF
2580 dn: ${LDAP_BASEDN}
2581 changetype: modify
2582 add: aci
2583 aci: (target="ldap:///${LDAP_BASEDN}")(targetattr="shadowLastChange||shadowMin||shadowMax||shadowWarning||shadowInactive||shadowExpire||shadowFlag||userPassword||loginShell||homeDirectory||gecos")(version 3.0; acl ${HOST_ACI_NAME}; allow (write,compare,read,search) authmethod="sasl GSSAPI" and userdn = "ldap:///cn=*+ipHostNumber=*,ou=Hosts,${LDAP_BASEDN}";)
2584 EOF
2585 ) > ${TMPDIR}/host_read_write
2586
2587 # Add the entry.
2588 ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/host_read_write ${VERB}"
2589 if [ $? -ne 0 ]; then
2590 ${ECHO} " ERROR: Allow Host Principal to write shadow data failed!"
2591 cleanup
2592 exit 1
2593 fi
2594
2595 ${RM} -f ${TMPDIR}/host_read_write
2596 MSG="Give host principal read/write permission for shadow."
2597 if [ $EXISTING_PROFILE -eq 1 ]; then
2598 ${ECHO} " ACI SET: $MSG"
2599 else
2600 ${ECHO} " ${STEP}. $MSG"
2601 STEP=`expr $STEP + 1`
2602 fi
2603 }
2604
2605 #
2606 # Set up shadow update
2607 #
2608 setup_shadow_update() {
2609 [ $DEBUG -eq 1 ] && ${ECHO} "In setup_shadow_update()"
2610
2611 # get content of the profile
2612 PROFILE_OUT=${TMPDIR}/prof_tmpfile
2613 ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${LDAP_PROFILE_NAME},ou=profile,${LDAP_BASEDN}\" -s base \"objectclass=*\" > $PROFILE_OUT 2>&1"
2614 ${GREP} -i cn $PROFILE_OUT >/dev/null 2>&1
2615 if [ $? -ne 0 ]; then
2616 [ $DEBUG -eq 1 ] && ${ECHO} "Profile ${LDAP_PROFILE_NAME} does not exist"
2617 ${RM} ${PROFILE_OUT}
2618 return
2619 fi
2620
2621 # Search to see if authenticationMethod has 'GSSAPI' and
2622 # credentialLevel has 'self'. If so, ask to use the
2623 # host principal for shadow update
2624 if [ $GSSAPI_AUTH_MAY_BE_USED -eq 1 ]; then
2625 if ${GREP} authenticationMethod $PROFILE_OUT | ${GREP} GSSAPI >/dev/null 2>&1
2626 then
2627 if ${GREP} credentialLevel $PROFILE_OUT | ${GREP} self >/dev/null 2>&1
2628 then
2629 NEED_HOSTACL=1
2630 fi
2631 fi
2632 ${RM} ${PROFILE_OUT}
2633 [ $DEBUG -eq 1 ] && ${ECHO} "NEED_HOSTACL = $NEED_HOSTACL"
2634
2635 if [ $NEED_HOSTACL -eq 1 ]; then
2636 MSG="Use host principal for shadow data update (y/n/h)?"
2637 get_confirm "$MSG" "y" "use_host_principal_help"
2638 if [ $? -eq 1 ]; then
2639 delete_proxy_read_pw
2640 allow_host_read_write_shadow
2641 deny_non_host_shadow_access
2642 ${ECHO} ""
2643 ${ECHO} " Shadow update has been enabled."
2644 else
2645 ${ECHO} ""
2646 ${ECHO} " Shadow update may not work."
2647 fi
2648 return
2649 fi
2650 fi
2651
2652 MSG="Add the administrator identity (y/n/h)?"
2653 get_confirm "$MSG" "y" "add_admin_cred_help"
2654 if [ $? -eq 1 ]; then
2655 get_adminDN
2656 get_admin_pw
2657 add_admin
2658 delete_proxy_read_pw
2659 allow_admin_read_write_shadow
2660 deny_non_admin_shadow_access
2661 ${ECHO} ""
2662 ${ECHO} " Shadow update has been enabled."
2663 return
2664 fi
2665
2666 ${ECHO} " No administrator identity specified, shadow update may not work."
2667 }
2668
2669
2670 #
2671 # prompt_config_info(): This function prompts the user for the config
2672 # info that is not specified in the input file.
2673 #
2674 prompt_config_info()
2675 {
2676 [ $DEBUG -eq 1 ] && ${ECHO} "In prompt_config_info()"
2677
2678 # Prompt for iDS server name.
2679 get_ids_server
2680
2681 # Prompt for iDS port number.
2682 get_ids_port
2683
2684 # Check iDS version for compatibility.
2685 chk_ids_version
2686
2687 # Check if the server supports the VLV.
2688 chk_vlv_indexes
2689
2690 # Get the Directory manager DN and passwd.
2691 get_dirmgr_dn
2692 get_dirmgr_pw
2693
2694 #
2695 # LDAP CLIENT PROFILE SPECIFIC INFORMATION.
2696 # (i.e. The fields that show up in the profile.)
2697 #
2698 get_domain "domain_help"
2699
2700 get_basedn
2701
2702 gssapi_setup
2703
2704 get_profile_name
2705
2706 if [ "$LDAP_ENABLE_SHADOW_UPDATE" = "TRUE" ];then
2707 setup_shadow_update
2708 cleanup
2709 exit 0
2710 fi
2711
2712 get_srv_list
2713 get_pref_srv
2714 get_search_scope
2715
2716 # If cred is "anonymous", make auth == "none"
2717 get_cred_level
2718 if [ "$LDAP_CRED_LEVEL" != "anonymous" ]; then
2719 get_auth
2720 fi
2721
2722 get_followref
2723
2724 # Query user about timelimt.
2725 get_confirm "Do you want to modify the server timelimit value (y/n/h)?" "n" "tlim_help"
2726 NEED_TIME=$?
2727 [ $NEED_TIME -eq 1 ] && get_timelimit
2728
2729 # Query user about sizelimit.
2730 get_confirm "Do you want to modify the server sizelimit value (y/n/h)?" "n" "slim_help"
2731 NEED_SIZE=$?
2732 [ $NEED_SIZE -eq 1 ] && get_sizelimit
2733
2734 # Does the user want to store passwords in crypt format?
2735 get_want_crypt
2736
2737 # Prompt for any Service Authentication Methods?
2738 get_confirm "Do you want to setup a Service Authentication Methods (y/n/h)?" "n" "srvauth_help"
2739 if [ $? -eq 1 ]; then
2740 # Does the user want to set Service Authentication Method for pam_ldap?
2741 get_confirm "Do you want to setup a Service Auth. Method for \"pam_ldap\" (y/n/h)?" "n" "pam_ldap_help"
2742 NEED_SRVAUTH_PAM=$?
2743 [ $NEED_SRVAUTH_PAM -eq 1 ] && get_srv_authMethod_pam
2744
2745 # Does the user want to set Service Authentication Method for keyserv?
2746 get_confirm "Do you want to setup a Service Auth. Method for \"keyserv\" (y/n/h)?" "n" "keyserv_help"
2747 NEED_SRVAUTH_KEY=$?
2748 [ $NEED_SRVAUTH_KEY -eq 1 ] && get_srv_authMethod_key
2749
2750 # Does the user want to set Service Authentication Method for passwd-cmd?
2751 get_confirm "Do you want to setup a Service Auth. Method for \"passwd-cmd\" (y/n/h)?" "n" "passwd-cmd_help"
2752 NEED_SRVAUTH_CMD=$?
2753 [ $NEED_SRVAUTH_CMD -eq 1 ] && get_srv_authMethod_cmd
2754 fi
2755
2756
2757 # Get Timeouts
2758 get_srch_time
2759 get_prof_ttl
2760 get_bind_limit
2761
2762 # Ask whether to enable shadow update
2763 get_want_shadow_update
2764
2765 # Reset the sdd_file and prompt user for SSD. Will use menus
2766 # to build an SSD File.
2767 reset_ssd_file
2768 prompt_ssd
2769
2770 # Display FULL debugging info.
2771 disp_full_debug
2772
2773 # Extra blank line to separate prompt lines from steps.
2774 ${ECHO} " "
2775 }
2776
2777
2778 ######################################################################
2779 # FUNCTIONS FOR display_summary() START HERE.
2780 ######################################################################
2781
2782
2783 #
2784 # get_proxyagent(): Get the proxyagent DN.
2785 #
2786 get_proxyagent()
2787 {
2788 LDAP_PROXYAGENT="cn=proxyagent,ou=profile,${LDAP_BASEDN}" # default
2789 get_ans "Enter DN for proxy agent:" "$LDAP_PROXYAGENT"
2790 LDAP_PROXYAGENT=$ANS
2791 }
2792
2793
2794 #
2795 # get_proxy_pw(): Get the proxyagent passwd.
2796 #
2797 get_proxy_pw()
2798 {
2799 get_passwd "Enter passwd for proxyagent:"
2800 LDAP_PROXYAGENT_CRED=$ANS
2801 }
2802
2803 #
2804 # display_summary(): Display a summary of values entered and let the
2805 # user modify values at will.
2806 #
2807 display_summary()
2808 {
2809 [ $DEBUG -eq 1 ] && ${ECHO} "In display_summary()"
2810
2811 # Create lookup table for function names. First entry is dummy for
2812 # shift.
2813 TBL1="dummy"
2814 TBL2="get_domain get_basedn get_profile_name"
2815 TBL3="get_srv_list get_pref_srv get_search_scope get_cred_level"
2816 TBL4="get_auth get_followref"
2817 TBL5="get_timelimit get_sizelimit get_want_crypt"
2818 TBL6="get_srv_authMethod_pam get_srv_authMethod_key get_srv_authMethod_cmd"
2819 TBL7="get_srch_time get_prof_ttl get_bind_limit"
2820 TBL8="get_want_shadow_update"
2821 TBL9="prompt_ssd"
2822 FUNC_TBL="$TBL1 $TBL2 $TBL3 $TBL4 $TBL5 $TBL6 $TBL7 $TBL8 $TBL9"
2823
2824 # Since menu prompt string is long, set here.
2825 _MENU_PROMPT="Enter config value to change: (1-20 0=commit changes)"
2826
2827 # Infinite loop. Test for 0, and break in loop.
2828 while :
2829 do
2830 # Display menu and get value in range.
2831 display_msg summary_menu
2832 get_menu_choice "${_MENU_PROMPT}" "0" "20" "0"
2833 _CH=$MN_CH
2834
2835 # Make sure where not exiting.
2836 if [ $_CH -eq 0 ]; then
2837 break # Break out of loop if 0 selected.
2838 fi
2839
2840 # Call appropriate function from function table.
2841 set $FUNC_TBL
2842 shift $_CH
2843 $1 # Call the appropriate function.
2844 done
2845
2846 # If cred level is still see if user wants a change?
2847 if ${ECHO} "$LDAP_CRED_LEVEL" | ${GREP} "proxy" > /dev/null 2>&1
2848 then
2849 if [ "$LDAP_AUTHMETHOD" != "none" ]; then
2850 NEED_PROXY=1 # I assume integer test is faster?
2851 get_proxyagent
2852 get_proxy_pw
2853 else
2854 ${ECHO} "WARNING: Since Authentication method is 'none'."
2855 ${ECHO} " Credential level will be set to 'anonymous'."
2856 LDAP_CRED_LEVEL="anonymous"
2857 fi
2858 fi
2859
2860 # If shadow update is enabled, set up administrator credential
2861 if [ "$LDAP_ENABLE_SHADOW_UPDATE" = "TRUE" ]; then
2862 NEED_ADMIN=1
2863 if ${ECHO} "$LDAP_CRED_LEVEL" | ${GREP} "self" > /dev/null 2>&1; then
2864 if ${ECHO} "$LDAP_AUTHMETHOD" | ${GREP} "GSSAPI" > /dev/null 2>&1; then
2865 NEED_HOSTACL=1
2866 NEED_ADMIN=0
2867 fi
2868 fi
2869 [ $DEBUG -eq 1 ] && ${ECHO} "NEED_HOSTACL = $NEED_HOSTACL"
2870 [ $DEBUG -eq 1 ] && ${ECHO} "NEED_ADMIN = $NEED_ADMIN"
2871 if [ $NEED_ADMIN -eq 1 ]; then
2872 get_adminDN
2873 get_admin_pw
2874 fi
2875 fi
2876
2877 # Display FULL debugging info.
2878 disp_full_debug
2879
2880 # Final confirmation message. (ARE YOU SURE!)
2881 ${ECHO} " "
2882 get_confirm_nodef "WARNING: About to start committing changes. (y=continue, n=EXIT)"
2883 if [ $? -eq 0 ]; then
2884 ${ECHO} "Terminating setup without making changes at users request."
2885 cleanup
2886 exit 1
2887 fi
2888
2889 # Print newline
2890 ${ECHO} " "
2891 }
2892
2893
2894 #
2895 # create_config_file(): Write config data to config file specified.
2896 #
2897 create_config_file()
2898 {
2899 [ $DEBUG -eq 1 ] && ${ECHO} "In create_config_file()"
2900
2901 # If output file exists, delete it.
2902 [ -f $OUTPUT_FILE ] && rm $OUTPUT_FILE
2903
2904 # Create output file.
2905 cat > $OUTPUT_FILE <<EOF
2906 #!/bin/sh
2907 # $OUTPUT_FILE - This file contains configuration information for
2908 # Native LDAP. Use the idsconfig tool to load it.
2909 #
2910 # WARNING: This file was generated by idsconfig, and is intended to
2911 # be loaded by idsconfig as is. DO NOT EDIT THIS FILE!
2912 #
2913 IDS_SERVER="$IDS_SERVER"
2914 IDS_PORT=$IDS_PORT
2915 IDS_TIMELIMIT=$IDS_TIMELIMIT
2916 IDS_SIZELIMIT=$IDS_SIZELIMIT
2917 LDAP_ROOTDN="$LDAP_ROOTDN"
2918 LDAP_ROOTPWD=$LDAP_ROOTPWD
2919 LDAP_DOMAIN="$LDAP_DOMAIN"
2920 LDAP_SUFFIX="$LDAP_SUFFIX"
2921 GSSAPI_ENABLE=$GSSAPI_ENABLE
2922 LDAP_KRB_REALM="$LDAP_KRB_REALM"
2923
2924 # Internal program variables that need to be set.
2925 NEED_PROXY=$NEED_PROXY
2926 NEED_TIME=$NEED_TIME
2927 NEED_SIZE=$NEED_SIZE
2928 NEED_CRYPT=$NEED_CRYPT
2929 NEED_ADMIN=$NEED_ADMIN
2930 NEED_HOSTACL=$NEED_HOSTACL
2931 EXISTING_PROFILE=$EXISTING_PROFILE
2932
2933 # LDAP PROFILE related defaults
2934 LDAP_PROFILE_NAME="$LDAP_PROFILE_NAME"
2935 DEL_OLD_PROFILE=1
2936 LDAP_BASEDN="$LDAP_BASEDN"
2937 LDAP_SERVER_LIST="$LDAP_SERVER_LIST"
2938 LDAP_AUTHMETHOD="$LDAP_AUTHMETHOD"
2939 LDAP_FOLLOWREF=$LDAP_FOLLOWREF
2940 LDAP_SEARCH_SCOPE="$LDAP_SEARCH_SCOPE"
2941 NEED_SRVAUTH_PAM=$NEED_SRVAUTH_PAM
2942 NEED_SRVAUTH_KEY=$NEED_SRVAUTH_KEY
2943 NEED_SRVAUTH_CMD=$NEED_SRVAUTH_CMD
2944 LDAP_SRV_AUTHMETHOD_PAM="$LDAP_SRV_AUTHMETHOD_PAM"
2945 LDAP_SRV_AUTHMETHOD_KEY="$LDAP_SRV_AUTHMETHOD_KEY"
2946 LDAP_SRV_AUTHMETHOD_CMD="$LDAP_SRV_AUTHMETHOD_CMD"
2947 LDAP_SEARCH_TIME_LIMIT=$LDAP_SEARCH_TIME_LIMIT
2948 LDAP_PREF_SRVLIST="$LDAP_PREF_SRVLIST"
2949 LDAP_PROFILE_TTL=$LDAP_PROFILE_TTL
2950 LDAP_CRED_LEVEL="$LDAP_CRED_LEVEL"
2951 LDAP_BIND_LIMIT=$LDAP_BIND_LIMIT
2952
2953 # Proxy Agent
2954 LDAP_PROXYAGENT="$LDAP_PROXYAGENT"
2955 LDAP_PROXYAGENT_CRED=$LDAP_PROXYAGENT_CRED
2956
2957 # enableShadowUpdate flag and Administrator credential
2958 LDAP_ENABLE_SHADOW_UPDATE=$LDAP_ENABLE_SHADOW_UPDATE
2959 LDAP_ADMINDN="$LDAP_ADMINDN"
2960 LDAP_ADMIN_CRED=$LDAP_ADMIN_CRED
2961
2962 # Export all the variables (just in case)
2963 export IDS_HOME IDS_PORT LDAP_ROOTDN LDAP_ROOTPWD LDAP_SERVER_LIST LDAP_BASEDN
2964 export LDAP_DOMAIN LDAP_SUFFIX LDAP_PROXYAGENT LDAP_PROXYAGENT_CRED
2965 export NEED_PROXY
2966 export LDAP_ENABLE_SHADOW_UPDATE LDAP_ADMINDN LDAP_ADMIN_CRED
2967 export NEED_ADMIN NEED_HOSTACL EXISTING_PROFILE
2968 export LDAP_PROFILE_NAME LDAP_BASEDN LDAP_SERVER_LIST
2969 export LDAP_AUTHMETHOD LDAP_FOLLOWREF LDAP_SEARCH_SCOPE LDAP_SEARCH_TIME_LIMIT
2970 export LDAP_PREF_SRVLIST LDAP_PROFILE_TTL LDAP_CRED_LEVEL LDAP_BIND_LIMIT
2971 export NEED_SRVAUTH_PAM NEED_SRVAUTH_KEY NEED_SRVAUTH_CMD
2972 export LDAP_SRV_AUTHMETHOD_PAM LDAP_SRV_AUTHMETHOD_KEY LDAP_SRV_AUTHMETHOD_CMD
2973 export LDAP_SERV_SRCH_DES SSD_FILE GSSAPI_ENABLE LDAP_KRB_REALM
2974
2975 # Service Search Descriptors start here if present:
2976 EOF
2977 # Add service search descriptors.
2978 ssd_2_config "${OUTPUT_FILE}"
2979
2980 # Add LDAP suffix preferences
2981 print_suffix_config >> "${OUTPUT_FILE}"
2982
2983 # Add the end of FILE tag.
2984 ${ECHO} "" >> ${OUTPUT_FILE}
2985 ${ECHO} "# End of $OUTPUT_FILE" >> ${OUTPUT_FILE}
2986 }
2987
2988
2989 #
2990 # chk_vlv_indexes(): Do ldapsearch to see if server supports VLV.
2991 #
2992 chk_vlv_indexes()
2993 {
2994 # Do ldapsearch to see if server supports VLV.
2995 ${LDAPSEARCH} ${SERVER_ARGS} -b "" -s base "objectclass=*" > ${TMPDIR}/checkVLV 2>&1
2996 eval "${GREP} 2.16.840.1.113730.3.4.9 ${TMPDIR}/checkVLV ${VERB}"
2997 if [ $? -ne 0 ]; then
2998 ${ECHO} "ERROR: VLV is not supported on LDAP server!"
2999 cleanup
3000 exit 1
3001 fi
3002 [ $DEBUG -eq 1 ] && ${ECHO} " VLV controls found on LDAP server."
3003 }
3004
3005 #
3006 # get_backend(): this function gets the relevant backend
3007 # (database) for LDAP_BASED.
3008 # Description: set IDS_DATABASE; exit on failure.
3009 # Prerequisite: LDAP_BASEDN and LDAP_SUFFIX are
3010 # valid.
3011 #
3012 # backend is retrieved from suffixes and subsuffixes
3013 # defined under "cn=mapping tree,cn=config". The
3014 # nsslapd-state attribute of these suffixes entries
3015 # is filled with either Backend, Disabled or referrals
3016 # related values. We only want those that have a true
3017 # backend database to select the relevant backend.
3018 #
3019 get_backend()
3020 {
3021 [ $DEBUG -eq 1 ] && ${ECHO} "In get_backend()"
3022
3023 cur_suffix=${LDAP_BASEDN}
3024 prev_suffix=
3025 IDS_DATABASE=
3026 while [ "${cur_suffix}" != "${prev_suffix}" ]
3027 do
3028 [ $DEBUG -eq 1 ] && ${ECHO} "testing LDAP suffix: ${cur_suffix}"
3029 eval "${LDAPSEARCH} ${LDAP_ARGS} " \
3030 "-b \"cn=\\\"${cur_suffix}\\\",cn=mapping tree,cn=config\" " \
3031 "-s base nsslapd-state=Backend nsslapd-backend 2>&1 " \
3032 "| ${GREP} 'nsslapd-backend=' " \
3033 "> ${TMPDIR}/ids_database_name 2>&1"
3034 NUM_DBS=`wc -l ${TMPDIR}/ids_database_name | awk '{print $1}'`
3035 case ${NUM_DBS} in
3036 0) # not a suffix, or suffix not activated; try next
3037 prev_suffix=${cur_suffix}
3038 cur_suffix=`${ECHO} ${cur_suffix} | cut -f2- -d','`
3039 ;;
3040 1) # suffix found; get database name
3041 IDS_DATABASE=`cat ${TMPDIR}/ids_database_name | cut -d= -f2`
3042 ;;
3043 *) # can not handle more than one database per suffix
3044 ${ECHO} "ERROR: More than one database is configured "
3045 ${ECHO} " for $LDAP_SUFFIX!"
3046 ${ECHO} " $PROG can not configure suffixes where "
3047 ${ECHO} " more than one database is used for one suffix."
3048 cleanup
3049 exit 1
3050 ;;
3051 esac
3052 if [ -n "${IDS_DATABASE}" ]; then
3053 break
3054 fi
3055 done
3056
3057 if [ -z "${IDS_DATABASE}" ]; then
3058 # should not happen, since LDAP_BASEDN is supposed to be valid
3059 ${ECHO} "Could not find a valid backend for ${LDAP_BASEDN}."
3060 ${ECHO} "Exiting."
3061 cleanup
3062 exit 1
3063 fi
3064
3065 [ $DEBUG -eq 1 ] && ${ECHO} "IDS_DATABASE: ${IDS_DATABASE}"
3066 }
3067
3068 #
3069 # validate_suffix(): This function validates ${LDAP_SUFFIX}
3070 # THIS FUNCTION IS FOR THE LOAD CONFIG FILE OPTION.
3071 #
3072 validate_suffix()
3073 {
3074 [ $DEBUG -eq 1 ] && ${ECHO} "In validate_suffix()"
3075
3076 # Check LDAP_SUFFIX is not null
3077 if [ -z "${LDAP_SUFFIX}" ]; then
3078 ${ECHO} "Invalid suffix (null suffix)"
3079 cleanup
3080 exit 1
3081 fi
3082
3083 # Check LDAP_SUFFIX and LDAP_BASEDN are consistent
3084 # Convert to lower case for basename.
3085 format_string "${LDAP_BASEDN}"
3086 LOWER_BASEDN="${FMT_STR}"
3087 format_string "${LDAP_SUFFIX}"
3088 LOWER_SUFFIX="${FMT_STR}"
3089
3090 [ $DEBUG -eq 1 ] && ${ECHO} "LOWER_BASEDN: ${LOWER_BASEDN}"
3091 [ $DEBUG -eq 1 ] && ${ECHO} "LOWER_SUFFIX: ${LOWER_SUFFIX}"
3092
3093 if [ "${LOWER_BASEDN}" != "${LOWER_SUFFIX}" ]; then
3094 sub_basedn=`basename "${LOWER_BASEDN}" "${LOWER_SUFFIX}"`
3095 if [ "$sub_basedn" = "${LOWER_BASEDN}" ]; then
3096 ${ECHO} "Invalid suffix ${LOWER_SUFFIX}"
3097 ${ECHO} "for Base DN ${LOWER_BASEDN}"
3098 cleanup
3099 exit 1
3100 fi
3101 fi
3102
3103 # Check LDAP_SUFFIX does exist
3104 ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_SUFFIX}\" -s base \"objectclass=*\" > ${TMPDIR}/checkSuffix 2>&1" && return 0
3105
3106 # Well, suffix does not exist, try to prepare create it ...
3107 NEED_CREATE_SUFFIX=1
3108 prep_create_sfx_entry ||
3109 {
3110 cleanup
3111 exit 1
3112 }
3113 [ -n "${NEED_CREATE_BACKEND}" ] &&
3114 {
3115 # try to use id attr value of the suffix as a database name
3116 IDS_DATABASE=${_VAL}
3117 prep_create_sfx_backend
3118 case $? in
3119 1) # cann't use the name we want, so we can either exit or use
3120 # some another available name - doing the last ...
3121 IDS_DATABASE=${IDS_DATABASE_AVAIL}
3122 ;;
3123 2) # unable to determine database name
3124 cleanup
3125 exit 1
3126 ;;
3127 esac
3128 }
3129
3130 [ $DEBUG -eq 1 ] && ${ECHO} "Suffix $LDAP_SUFFIX, Database $IDS_DATABASE"
3131 }
3132
3133 #
3134 # validate_info(): This function validates the basic info collected
3135 # So that some problems are caught right away.
3136 # THIS FUNCTION IS FOR THE LOAD CONFIG FILE OPTION.
3137 #
3138 validate_info()
3139 {
3140 [ $DEBUG -eq 1 ] && ${ECHO} "In validate_info()"
3141
3142 # Set SERVER_ARGS, AUTH_ARGS, and LDAP_ARGS for the config file.
3143 SERVER_ARGS="-h ${IDS_SERVER} -p ${IDS_PORT}"
3144 AUTH_ARGS="-D \"${LDAP_ROOTDN}\" -j ${LDAP_ROOTPWF}"
3145 LDAP_ARGS="${SERVER_ARGS} ${AUTH_ARGS}"
3146 export SERVER_ARGS
3147
3148 # Check the Root DN and Root DN passwd.
3149 # Use eval instead of $EVAL because not part of setup. (validate)
3150 eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"\" -s base \"objectclass=*\" > ${TMPDIR}/checkDN 2>&1"
3151 if [ $? -ne 0 ]; then
3152 eval "${GREP} credential ${TMPDIR}/checkDN ${VERB}"
3153 if [ $? -eq 0 ]; then
3154 ${ECHO} "ERROR: Root DN passwd is invalid."
3155 else
3156 ${ECHO} "ERROR2: Invalid Root DN <${LDAP_ROOTDN}>."
3157 fi
3158 cleanup
3159 exit 1
3160 fi
3161 [ $DEBUG -eq 1 ] && ${ECHO} " RootDN ... OK"
3162 [ $DEBUG -eq 1 ] && ${ECHO} " RootDN passwd ... OK"
3163
3164 # Check if the server supports the VLV.
3165 chk_vlv_indexes
3166 [ $DEBUG -eq 1 ] && ${ECHO} " VLV indexes ... OK"
3167
3168 # Check LDAP suffix
3169 validate_suffix
3170 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP suffix ... OK"
3171 }
3172
3173 #
3174 # format_string(): take a string as argument and set FMT_STR
3175 # to be the same string formatted as follow:
3176 # - only lower case characters
3177 # - no unnecessary spaces around , and =
3178 #
3179 format_string()
3180 {
3181 FMT_STR=`${ECHO} "$1" | tr '[A-Z]' '[a-z]' |
3182 sed -e 's/[ ]*,[ ]*/,/g' -e 's/[ ]*=[ ]*/=/g'`
3183 }
3184
3185 #
3186 # prepare for the suffix entry creation
3187 #
3188 # input : LDAP_BASEDN, LDAP_SUFFIX - base dn and suffix;
3189 # in/out : LDAP_SUFFIX_OBJ, LDAP_SUFFIX_ACI - initially may come from config.
3190 # output : NEED_CREATE_BACKEND - backend for this suffix needs to be created;
3191 # _RDN, _ATT, _VAL - suffix's RDN, id attribute name and its value.
3192 # return : 0 - success, otherwise error.
3193 #
3194 prep_create_sfx_entry()
3195 {
3196 [ $DEBUG -eq 1 ] && ${ECHO} "In prep_create_sfx_entry()"
3197
3198 # check whether suffix corresponds to base dn
3199 format_string "${LDAP_BASEDN}"
3200 ${ECHO} ",${FMT_STR}" | ${GREP} ",${LDAP_SUFFIX}$" >/dev/null 2>&1 ||
3201 {
3202 display_msg sfx_not_suitable
3203 return 1
3204 }
3205
3206 # parse LDAP_SUFFIX
3207 _RDN=`${ECHO} "${LDAP_SUFFIX}" | cut -d, -f1`
3208 _ATT=`${ECHO} "${_RDN}" | cut -d= -f1`
3209 _VAL=`${ECHO} "${_RDN}" | cut -d= -f2-`
3210
3211 # find out an objectclass for suffix entry if it is not defined yet
3212 [ -z "${LDAP_SUFFIX_OBJ}" ] &&
3213 {
3214 get_objectclass ${_ATT}
3215 [ -z "${_ATTR_NAME}" ] &&
3216 {
3217 display_msg obj_not_found
3218 return 1
3219 }
3220 LDAP_SUFFIX_OBJ=${_ATTR_NAME}
3221 }
3222 [ $DEBUG -eq 1 ] && ${ECHO} "Suffix entry object is ${LDAP_SUFFIX_OBJ}"
3223
3224 # find out an aci for suffix entry if it is not defined yet
3225 [ -z "${LDAP_SUFFIX_ACI}" ] &&
3226 {
3227 # set Directory Server default aci
3228 LDAP_SUFFIX_ACI=`cat <<EOF
3229 aci: (targetattr != "userPassword || passwordHistory || passwordExpirationTime
3230 || passwordExpWarned || passwordRetryCount || retryCountResetTime ||
3231 accountUnlockTime || passwordAllowChangeTime")
3232 (
3233 version 3.0;
3234 acl "Anonymous access";
3235 allow (read, search, compare) userdn = "ldap:///anyone";
3236 )
3237 aci: (targetattr != "nsroledn || aci || nsLookThroughLimit || nsSizeLimit ||
3238 nsTimeLimit || nsIdleTimeout || passwordPolicySubentry ||
3239 passwordExpirationTime || passwordExpWarned || passwordRetryCount ||
3240 retryCountResetTime || accountUnlockTime || passwordHistory ||
3241 passwordAllowChangeTime")
3242 (
3243 version 3.0;
3244 acl "Allow self entry modification except for some attributes";
3245 allow (write) userdn = "ldap:///self";
3246 )
3247 aci: (targetattr = "*")
3248 (
3249 version 3.0;
3250 acl "Configuration Administrator";
3251 allow (all) userdn = "ldap:///uid=admin,ou=Administrators,
3252 ou=TopologyManagement,o=NetscapeRoot";
3253 )
3254 aci: (targetattr ="*")
3255 (
3256 version 3.0;
3257 acl "Configuration Administrators Group";
3258 allow (all) groupdn = "ldap:///cn=Configuration Administrators,
3259 ou=Groups,ou=TopologyManagement,o=NetscapeRoot";
3260 )
3261 EOF
3262 `
3263 }
3264 [ $DEBUG -eq 1 ] && cat <<EOF
3265 DEBUG: ACI for ${LDAP_SUFFIX} is
3266 ${LDAP_SUFFIX_ACI}
3267 EOF
3268
3269 NEED_CREATE_BACKEND=
3270
3271 # check the suffix mapping tree ...
3272 # if mapping exists, suffix should work, otherwise DS inconsistent
3273 # NOTE: -b 'cn=mapping tree,cn=config' -s one 'cn=\"$1\"' won't work
3274 # in case of 'cn' value in LDAP is not quoted by '"',
3275 # -b 'cn=\"$1\",cn=mapping tree,cn=config' works in all cases
3276 ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} \
3277 -b 'cn=\"${LDAP_SUFFIX}\",cn=mapping tree,cn=config' \
3278 -s base 'objectclass=*' dn ${VERB}" &&
3279 {
3280 [ $DEBUG -eq 1 ] && ${ECHO} "Suffix mapping already exists"
3281 # get_backend() either gets IDS_DATABASE or exits
3282 get_backend
3283 return 0
3284 }
3285
3286 # no suffix mapping, just in case check ldbm backends consistency -
3287 # there are must be NO any databases pointing to LDAP_SUFFIX
3288 [ -n "`${EVAL} \"${LDAPSEARCH} ${LDAP_ARGS} \
3289 -b 'cn=ldbm database,cn=plugins,cn=config' \
3290 -s one 'nsslapd-suffix=${LDAP_SUFFIX}' dn\" 2>/dev/null`" ] &&
3291 {
3292 display_msg sfx_config_incons
3293 return 1
3294 }
3295
3296 # ok, no suffix mapping, no ldbm database
3297 [ $DEBUG -eq 1 ] && ${ECHO} "DEBUG: backend needs to be created ..."
3298 NEED_CREATE_BACKEND=1
3299 return 0
3300 }
3301
3302 #
3303 # prepare for the suffix backend creation
3304 #
3305 # input : IDS_DATABASE - requested ldbm db name (must be not null)
3306 # in/out : IDS_DATABASE_AVAIL - available ldbm db name
3307 # return : 0 - ldbm db name ok
3308 # 1 - IDS_DATABASE exists,
3309 # so IDS_DATABASE_AVAIL contains available name
3310 # 2 - unable to find any available name
3311 #
3312 prep_create_sfx_backend()
3313 {
3314 [ $DEBUG -eq 1 ] && ${ECHO} "In prep_create_sfx_backend()"
3315
3316 # check if requested name available
3317 [ "${IDS_DATABASE}" = "${IDS_DATABASE_AVAIL}" ] && return 0
3318
3319 # get the list of database names start with a requested name
3320 _LDBM_DBS=`${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} \
3321 -b 'cn=ldbm database,cn=plugins,cn=config' \
3322 -s one 'cn=${IDS_DATABASE}*' cn"` 2>/dev/null
3323
3324 # find available db name based on a requested name
3325 _i=""; _i_MAX=10
3326 while [ ${_i:-0} -lt ${_i_MAX} ]
3327 do
3328 _name="${IDS_DATABASE}${_i}"
3329 ${ECHO} "${_LDBM_DBS}" | ${GREP} -i "^cn=${_name}$" >/dev/null 2>&1 ||
3330 {
3331 IDS_DATABASE_AVAIL="${_name}"
3332 break
3333 }
3334 _i=`expr ${_i:-0} + 1`
3335 done
3336
3337 [ "${IDS_DATABASE}" = "${IDS_DATABASE_AVAIL}" ] && return 0
3338
3339 [ -n "${IDS_DATABASE_AVAIL}" ] &&
3340 {
3341 display_msg ldbm_db_exist
3342 return 1
3343 }
3344
3345 display_msg unable_find_db_name
3346 return 2
3347 }
3348
3349 #
3350 # add suffix if needed,
3351 # suffix entry and backend MUST be prepared by
3352 # prep_create_sfx_entry and prep_create_sfx_backend correspondingly
3353 #
3354 # input : NEED_CREATE_SUFFIX, LDAP_SUFFIX, LDAP_SUFFIX_OBJ, _ATT, _VAL
3355 # LDAP_SUFFIX_ACI, NEED_CREATE_BACKEND, IDS_DATABASE
3356 # return : 0 - suffix successfully created, otherwise error occured
3357 #
3358 add_suffix()
3359 {
3360 [ $DEBUG -eq 1 ] && ${ECHO} "In add_suffix()"
3361
3362 [ -n "${NEED_CREATE_SUFFIX}" ] || return 0
3363
3364 [ -n "${NEED_CREATE_BACKEND}" ] &&
3365 {
3366 ${EVAL} "${LDAPADD} ${LDAP_ARGS} ${VERB}" <<EOF
3367 dn: cn="${LDAP_SUFFIX}",cn=mapping tree,cn=config
3368 objectclass: top
3369 objectclass: extensibleObject
3370 objectclass: nsMappingTree
3371 cn: ${LDAP_SUFFIX}
3372 nsslapd-state: backend
3373 nsslapd-backend: ${IDS_DATABASE}
3374
3375 dn: cn=${IDS_DATABASE},cn=ldbm database,cn=plugins,cn=config
3376 objectclass: top
3377 objectclass: extensibleObject
3378 objectclass: nsBackendInstance
3379 cn: ${IDS_DATABASE}
3380 nsslapd-suffix: ${LDAP_SUFFIX}
3381 EOF
3382 [ $? -ne 0 ] &&
3383 {
3384 display_msg create_ldbm_db_error
3385 return 1
3386 }
3387
3388 ${ECHO} " ${STEP}. Database ${IDS_DATABASE} successfully created"
3389 STEP=`expr $STEP + 1`
3390 }
3391
3392 ${EVAL} "${LDAPADD} ${LDAP_ARGS} ${VERB}" <<EOF
3393 dn: ${LDAP_SUFFIX}
3394 objectclass: ${LDAP_SUFFIX_OBJ}
3395 ${_ATT}: ${_VAL}
3396 ${LDAP_SUFFIX_ACI}
3397 EOF
3398 [ $? -ne 0 ] &&
3399 {
3400 display_msg create_suffix_entry_error
3401 return 1
3402 }
3403
3404 ${ECHO} " ${STEP}. Suffix ${LDAP_SUFFIX} successfully created"
3405 STEP=`expr $STEP + 1`
3406 return 0
3407 }
3408
3409 #
3410 # interactively get suffix and related info from a user
3411 #
3412 # input : LDAP_BASEDN - Base DN
3413 # output : LDAP_SUFFIX - Suffix, _ATT, _VAL - id attribute and its value;
3414 # LDAP_SUFFIX_OBJ, LDAP_SUFFIX_ACI - objectclass and aci;
3415 # NEED_CREATE_BACKEND - tells whether backend needs to be created;
3416 # IDS_DATABASE - prepared ldbm db name
3417 # return : 0 - user gave a correct suffix
3418 # 1 - suffix given by user cann't be created
3419 #
3420 get_suffix()
3421 {
3422 [ $DEBUG -eq 1 ] && ${ECHO} "In get_suffix()"
3423
3424 while :
3425 do
3426 get_ans "Enter suffix to be created (b=back/h=help):" ${LDAP_BASEDN}
3427 case "${ANS}" in
3428 [Hh] | Help | help | \? ) display_msg create_suffix_help ;;
3429 [Bb] | Back | back | \< ) return 1 ;;
3430 * )
3431 format_string "${ANS}"
3432 LDAP_SUFFIX=${FMT_STR}
3433 prep_create_sfx_entry || continue
3434
3435 [ -n "${NEED_CREATE_BACKEND}" ] &&
3436 {
3437 IDS_DATABASE_AVAIL= # reset the available db name
3438
3439 reenter_suffix=
3440 while :
3441 do
3442 get_ans "Enter ldbm database name (b=back/h=help):" \
3443 ${IDS_DATABASE_AVAIL:-${_VAL}}
3444 case "${ANS}" in
3445 [Hh] | \? ) display_msg enter_ldbm_db_help ;;
3446 [Bb] | \< ) reenter_suffix=1; break ;;
3447 * )
3448 IDS_DATABASE="${ANS}"
3449 prep_create_sfx_backend && break
3450 esac
3451 done
3452 [ -n "${reenter_suffix}" ] && continue
3453
3454 [ $DEBUG -eq 1 ] && cat <<EOF
3455 DEBUG: backend name for suffix ${LDAP_SUFFIX} will be ${IDS_DATABASE}
3456 EOF
3457 }
3458
3459 # eventually everything is prepared
3460 return 0
3461 ;;
3462 esac
3463 done
3464 }
3465
3466 #
3467 # print out a script which sets LDAP suffix related preferences
3468 #
3469 print_suffix_config()
3470 {
3471 cat <<EOF2
3472 # LDAP suffix related preferences used only if needed
3473 IDS_DATABASE="${IDS_DATABASE}"
3474 LDAP_SUFFIX_OBJ="$LDAP_SUFFIX_OBJ"
3475 LDAP_SUFFIX_ACI=\`cat <<EOF
3476 ${LDAP_SUFFIX_ACI}
3477 EOF
3478 \`
3479 export IDS_DATABASE LDAP_SUFFIX_OBJ LDAP_SUFFIX_ACI
3480 EOF2
3481 }
3482
3483 #
3484 # check_basedn_suffix(): check that there is an existing
3485 # valid suffix to hold current base DN
3486 # return:
3487 # 0: valid suffix found or new one should be created,
3488 # NEED_CREATE_SUFFIX flag actually indicates that
3489 # 1: some error occures
3490 #
3491 check_basedn_suffix()
3492 {
3493 [ $DEBUG -eq 1 ] && ${ECHO} "In check_basedn_suffix()"
3494
3495 NEED_CREATE_SUFFIX=
3496
3497 # find out existing suffixes
3498 discover_serv_suffix
3499
3500 ${ECHO} " Validating LDAP Base DN and Suffix ..."
3501
3502 # check that LDAP Base DN might be added
3503 cur_ldap_entry=${LDAP_BASEDN}
3504 prev_ldap_entry=
3505 while [ "${cur_ldap_entry}" != "${prev_ldap_entry}" ]
3506 do
3507 [ $DEBUG -eq 1 ] && ${ECHO} "testing LDAP entry: ${cur_ldap_entry}"
3508 ${LDAPSEARCH} ${SERVER_ARGS} -b "${cur_ldap_entry}" \
3509 -s one "objectclass=*" > /dev/null 2>&1
3510 if [ $? -eq 0 ]; then
3511 break
3512 else
3513 prev_ldap_entry=${cur_ldap_entry}
3514 cur_ldap_entry=`${ECHO} ${cur_ldap_entry} | cut -f2- -d','`
3515 fi
3516 done
3517
3518 if [ "${cur_ldap_entry}" = "${prev_ldap_entry}" ]; then
3519 ${ECHO} " No valid suffixes were found for Base DN ${LDAP_BASEDN}"
3520
3521 NEED_CREATE_SUFFIX=1
3522 return 0
3523
3524 else
3525 [ $DEBUG -eq 1 ] && ${ECHO} "found valid LDAP entry: ${cur_ldap_entry}"
3526
3527 # Now looking for relevant suffix for this entry.
3528 # LDAP_SUFFIX will then be used to add necessary
3529 # base objects. See add_base_objects().
3530 format_string "${cur_ldap_entry}"
3531 lower_entry="${FMT_STR}"
3532 [ $DEBUG -eq 1 ] && ${ECHO} "final suffix list: ${LDAP_SUFFIX_LIST}"
3533 oIFS=$IFS
3534 [ $DEBUG -eq 1 ] && ${ECHO} "setting IFS to new line"
3535 IFS='
3536 '
3537 for suff in ${LDAP_SUFFIX_LIST}
3538 do
3539 [ $DEBUG -eq 1 ] && ${ECHO} "testing suffix: ${suff}"
3540 format_string "${suff}"
3541 lower_suff="${FMT_STR}"
3542 if [ "${lower_entry}" = "${lower_suff}" ]; then
3543 LDAP_SUFFIX="${suff}"
3544 break
3545 else
3546 dcstmp=`basename "${lower_entry}" "${lower_suff}"`
3547 if [ "${dcstmp}" = "${lower_entry}" ]; then
3548 # invalid suffix, try next one
3549 continue
3550 else
3551 # valid suffix found
3552 LDAP_SUFFIX="${suff}"
3553 break
3554 fi
3555 fi
3556 done
3557 [ $DEBUG -eq 1 ] && ${ECHO} "setting IFS to original value"
3558 IFS=$oIFS
3559
3560 [ $DEBUG -eq 1 ] && ${ECHO} "LDAP_SUFFIX: ${LDAP_SUFFIX}"
3561
3562 if [ -z "${LDAP_SUFFIX}" ]; then
3563 # should not happen, since we found the entry
3564 ${ECHO} "Could not find a valid suffix for ${LDAP_BASEDN}."
3565 ${ECHO} "Exiting."
3566 return 1
3567 fi
3568
3569 # Getting relevant database (backend)
3570 # IDS_DATABASE will then be used to create indexes.
3571 get_backend
3572
3573 return 0
3574 fi
3575 }
3576
3577 #
3578 # discover_serv_suffix(): This function queries the server to find
3579 # suffixes available
3580 # return: 0: OK, suffix found
3581 # 1: suffix not determined
3582 discover_serv_suffix()
3583 {
3584 [ $DEBUG -eq 1 ] && ${ECHO} "In discover_serv_suffix()"
3585
3586 # Search the server for the TOP of the TREE.
3587 ${LDAPSEARCH} ${SERVER_ARGS} -b "" -s base "objectclass=*" > ${TMPDIR}/checkTOP 2>&1
3588 ${GREP} -i namingcontexts ${TMPDIR}/checkTOP | \
3589 ${GREP} -i -v NetscapeRoot > ${TMPDIR}/treeTOP
3590 NUM_TOP=`wc -l ${TMPDIR}/treeTOP | awk '{print $1}'`
3591 case $NUM_TOP in
3592 0)
3593 [ $DEBUG -eq 1 ] && ${ECHO} "DEBUG: No suffix found in LDAP tree"
3594 return 1
3595 ;;
3596 *) # build the list of suffixes; take out 'namingContexts=' in
3597 # each line of ${TMPDIR}/treeTOP
3598 LDAP_SUFFIX_LIST=`cat ${TMPDIR}/treeTOP |
3599 awk '{ printf("%s\n",substr($0,16,length-15)) }'`
3600 ;;
3601 esac
3602
3603 [ $DEBUG -eq 1 ] && ${ECHO} " LDAP_SUFFIX_LIST = $LDAP_SUFFIX_LIST"
3604 return 0
3605 }
3606
3607
3608 #
3609 # modify_cn(): Change the cn from MUST to MAY in ipNetwork.
3610 #
3611 modify_cn()
3612 {
3613 [ $DEBUG -eq 1 ] && ${ECHO} "In modify_cn()"
3614
3615 ( cat <<EOF
3616 dn: cn=schema
3617 changetype: modify
3618 add: objectclasses
3619 objectclasses: ( 1.3.6.1.1.1.2.7 NAME 'ipNetwork' DESC 'Standard LDAP objectclass' SUP top STRUCTURAL MUST ipNetworkNumber MAY ( ipNetmaskNumber $ manager $ cn $ l $ description ) X-ORIGIN 'RFC 2307' )
3620 EOF
3621 ) > ${TMPDIR}/ipNetwork_cn
3622
3623 # Modify the cn for ipNetwork.
3624 ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/ipNetwork_cn ${VERB}"
3625 if [ $? -ne 0 ]; then
3626 ${ECHO} " ERROR: update of cn for ipNetwork failed!"
3627 cleanup
3628 exit 1
3629 fi
3630 }
3631
3632
3633 # modify_timelimit(): Modify timelimit to user value.
3634 modify_timelimit()
3635 {
3636 [ $DEBUG -eq 1 ] && ${ECHO} "In modify_timelimit()"
3637
3638 # Here doc to modify timelimit.
3639 ( cat <<EOF
3640 dn: cn=config
3641 changetype: modify
3642 replace: nsslapd-timelimit
3643 nsslapd-timelimit: ${IDS_TIMELIMIT}
3644 EOF
3645 ) > ${TMPDIR}/ids_timelimit
3646
3647 # Add the entry.
3648 ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/ids_timelimit ${VERB}"
3649 if [ $? -ne 0 ]; then
3650 ${ECHO} " ERROR: update of nsslapd-timelimit failed!"
3651 cleanup
3652 exit 1
3653 fi
3654
3655 # Display messages for modifications made in patch.
3656 ${ECHO} " ${STEP}. Changed timelimit to ${IDS_TIMELIMIT} in cn=config."
3657 STEP=`expr $STEP + 1`
3658 }
3659
3660
3661 # modify_sizelimit(): Modify sizelimit to user value.
3662 modify_sizelimit()
3663 {
3664 [ $DEBUG -eq 1 ] && ${ECHO} "In modify_sizelimit()"
3665
3666 # Here doc to modify sizelimit.
3667 ( cat <<EOF
3668 dn: cn=config
3669 changetype: modify
3670 replace: nsslapd-sizelimit
3671 nsslapd-sizelimit: ${IDS_SIZELIMIT}
3672 EOF
3673 ) > ${TMPDIR}/ids_sizelimit
3674
3675 # Add the entry.
3676 ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/ids_sizelimit ${VERB}"
3677 if [ $? -ne 0 ]; then
3678 ${ECHO} " ERROR: update of nsslapd-sizelimit failed!"
3679 cleanup
3680 exit 1
3681 fi
3682
3683 # Display messages for modifications made in patch.
3684 ${ECHO} " ${STEP}. Changed sizelimit to ${IDS_SIZELIMIT} in cn=config."
3685 STEP=`expr $STEP + 1`
3686 }
3687
3688
3689 # modify_pwd_crypt(): Modify the passwd storage scheme to support CRYPT.
3690 modify_pwd_crypt()
3691 {
3692 [ $DEBUG -eq 1 ] && ${ECHO} "In modify_pwd_crypt()"
3693
3694 # Here doc to modify passwordstoragescheme.
3695 # IDS 5.2 moved passwordchangesceme off to a new data structure.
3696 if [ $IDS_MAJVER -le 5 ] && [ $IDS_MINVER -le 1 ]; then
3697 ( cat <<EOF
3698 dn: cn=config
3699 changetype: modify
3700 replace: passwordstoragescheme
3701 passwordstoragescheme: crypt
3702 EOF
3703 ) > ${TMPDIR}/ids_crypt
3704 else
3705 ( cat <<EOF
3706 dn: cn=Password Policy,cn=config
3707 changetype: modify
3708 replace: passwordstoragescheme
3709 passwordstoragescheme: crypt
3710 EOF
3711 ) > ${TMPDIR}/ids_crypt
3712 fi
3713
3714 # Add the entry.
3715 ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/ids_crypt ${VERB}"
3716 if [ $? -ne 0 ]; then
3717 ${ECHO} " ERROR: update of passwordstoragescheme failed!"
3718 cleanup
3719 exit 1
3720 fi
3721
3722 # Display messages for modifications made in patch.
3723 ${ECHO} " ${STEP}. Changed passwordstoragescheme to \"crypt\" in cn=config."
3724 STEP=`expr $STEP + 1`
3725 }
3726
3727
3728 #
3729 # add_eq_indexes(): Add indexes to improve search performance.
3730 #
3731 add_eq_indexes()
3732 {
3733 [ $DEBUG -eq 1 ] && ${ECHO} "In add_eq_indexes()"
3734
3735 # Set eq indexes to add.
3736 _INDEXES="uidNumber ipNetworkNumber gidnumber oncrpcnumber automountKey"
3737
3738 if [ -z "${IDS_DATABASE}" ]; then
3739 get_backend
3740 fi
3741
3742 # Set _EXT to use as shortcut.
3743 _EXT="cn=index,cn=${IDS_DATABASE},cn=ldbm database,cn=plugins,cn=config"
3744
3745 # Display message to id current step.
3746 ${ECHO} " ${STEP}. Processing eq,pres indexes:"
3747 STEP=`expr $STEP + 1`
3748
3749 # For loop to create indexes.
3750 for i in ${_INDEXES}; do
3751 [ $DEBUG -eq 1 ] && ${ECHO} " Adding index for ${i}"
3752
3753 # Check if entry exists first, if so, skip to next.
3754 ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${i},${_EXT}\" -s base \
3755 \"objectclass=*\" > /dev/null 2>&1"
3756 if [ $? -eq 0 ]; then
3757 # Display index skipped.
3758 ${ECHO} " ${i} (eq,pres) skipped already exists"
3759 continue
3760 fi
3761
3762 # Here doc to create LDIF.
3763 ( cat <<EOF
3764 dn: cn=${i},${_EXT}
3765 objectClass: top
3766 objectClass: nsIndex
3767 cn: ${i}
3768 nsSystemIndex: false
3769 nsIndexType: pres
3770 nsIndexType: eq
3771 EOF
3772 ) > ${TMPDIR}/index_${i}
3773
3774 # Add the index.
3775 ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/index_${i} ${VERB}"
3776 if [ $? -ne 0 ]; then
3777 ${ECHO} " ERROR: Adding EQ,PRES index for ${i} failed!"
3778 cleanup
3779 exit 1
3780 fi
3781
3782 # Build date for task name.
3783 _YR=`date '+%y'`
3784 _MN=`date '+%m'`
3785 _DY=`date '+%d'`
3786 _H=`date '+%H'`
3787 _M=`date '+%M'`
3788 _S=`date '+%S'`
3789
3790 # Build task name
3791 TASKNAME="${i}_${_YR}_${_MN}_${_DY}_${_H}_${_M}_${_S}"
3792
3793 # Build the task entry to add.
3794 ( cat <<EOF
3795 dn: cn=${TASKNAME}, cn=index, cn=tasks, cn=config
3796 changetype: add
3797 objectclass: top
3798 objectclass: extensibleObject
3799 cn: ${TASKNAME}
3800 nsInstance: ${IDS_DATABASE}
3801 nsIndexAttribute: ${i}
3802 EOF
3803 ) > ${TMPDIR}/task_${i}
3804
3805 # Add the task.
3806 ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/task_${i} ${VERB}"
3807 if [ $? -ne 0 ]; then
3808 ${ECHO} " ERROR: Adding task for ${i} failed!"
3809 cleanup
3810 exit 1
3811 fi
3812
3813 # Wait for task to finish, display current status.
3814 while :
3815 do
3816 ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} \
3817 -b \"cn=${TASKNAME}, cn=index, cn=tasks, cn=config\" -s base \
3818 \"objectclass=*\" nstaskstatus > \"${TMPDIR}/istask_${i}\" 2>&1"
3819 ${GREP} "${TASKNAME}" "${TMPDIR}/istask_${i}" > /dev/null 2>&1
3820 if [ $? -ne 0 ]; then
3821 break
3822 fi
3823 TASK_STATUS=`${GREP} -i nstaskstatus "${TMPDIR}/istask_${i}" |
3824 head -1 | cut -d: -f2`
3825 ${ECHO} " ${i} (eq,pres) $TASK_STATUS \r\c"
3826 ${ECHO} "$TASK_STATUS" | ${GREP} "Finished" > /dev/null 2>&1
3827 if [ $? -eq 0 ]; then
3828 break
3829 fi
3830 sleep 2
3831 done
3832
3833 # Print newline because of \c.
3834 ${ECHO} " "
3835 done
3836 }
3837
3838
3839 #
3840 # add_sub_indexes(): Add indexes to improve search performance.
3841 #
3842 add_sub_indexes()
3843 {
3844 [ $DEBUG -eq 1 ] && ${ECHO} "In add_sub_indexes()"
3845
3846 # Set eq indexes to add.
3847 _INDEXES="ipHostNumber membernisnetgroup nisnetgrouptriple"
3848
3849 # Set _EXT to use as shortcut.
3850 _EXT="cn=index,cn=${IDS_DATABASE},cn=ldbm database,cn=plugins,cn=config"
3851
3852
3853 # Display message to id current step.
3854 ${ECHO} " ${STEP}. Processing eq,pres,sub indexes:"
3855 STEP=`expr $STEP + 1`
3856
3857 # For loop to create indexes.
3858 for i in ${_INDEXES}; do
3859 [ $DEBUG -eq 1 ] && ${ECHO} " Adding index for ${i}"
3860
3861 # Check if entry exists first, if so, skip to next.
3862 ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${i},${_EXT}\" \
3863 -s base \"objectclass=*\" > /dev/null 2>&1"
3864 if [ $? -eq 0 ]; then
3865 # Display index skipped.
3866 ${ECHO} " ${i} (eq,pres,sub) skipped already exists"
3867 continue
3868 fi
3869
3870 # Here doc to create LDIF.
3871 ( cat <<EOF
3872 dn: cn=${i},${_EXT}
3873 objectClass: top
3874 objectClass: nsIndex
3875 cn: ${i}
3876 nsSystemIndex: false
3877 nsIndexType: pres
3878 nsIndexType: eq
3879 nsIndexType: sub
3880 EOF
3881 ) > ${TMPDIR}/index_${i}
3882
3883 # Add the index.
3884 ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/index_${i} ${VERB}"
3885 if [ $? -ne 0 ]; then
3886 ${ECHO} " ERROR: Adding EQ,PRES,SUB index for ${i} failed!"
3887 cleanup
3888 exit 1
3889 fi
3890
3891 # Build date for task name.
3892 _YR=`date '+%y'`
3893 _MN=`date '+%m'`
3894 _DY=`date '+%d'`
3895 _H=`date '+%H'`
3896 _M=`date '+%M'`
3897 _S=`date '+%S'`
3898
3899 # Build task name
3900 TASKNAME="${i}_${_YR}_${_MN}_${_DY}_${_H}_${_M}_${_S}"
3901
3902 # Build the task entry to add.
3903 ( cat <<EOF
3904 dn: cn=${TASKNAME}, cn=index, cn=tasks, cn=config
3905 changetype: add
3906 objectclass: top
3907 objectclass: extensibleObject
3908 cn: ${TASKNAME}
3909 nsInstance: ${IDS_DATABASE}
3910 nsIndexAttribute: ${i}
3911 EOF
3912 ) > ${TMPDIR}/task_${i}
3913
3914 # Add the task.
3915 ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/task_${i} ${VERB}"
3916 if [ $? -ne 0 ]; then
3917 ${ECHO} " ERROR: Adding task for ${i} failed!"
3918 cleanup
3919 exit 1
3920 fi
3921
3922 # Wait for task to finish, display current status.
3923 while :
3924 do
3925 ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} \
3926 -b \"cn=${TASKNAME}, cn=index, cn=tasks, cn=config\" -s base \
3927 \"objectclass=*\" nstaskstatus > \"${TMPDIR}/istask_${i}\" 2>&1"
3928 ${GREP} "${TASKNAME}" "${TMPDIR}/istask_${i}" > /dev/null 2>&1
3929 if [ $? -ne 0 ]; then
3930 break
3931 fi
3932 TASK_STATUS=`${GREP} -i nstaskstatus "${TMPDIR}/istask_${i}" |
3933 head -1 | cut -d: -f2`
3934 ${ECHO} " ${i} (eq,pres,sub) $TASK_STATUS \r\c"
3935 ${ECHO} "$TASK_STATUS" | ${GREP} "Finished" > /dev/null 2>&1
3936 if [ $? -eq 0 ]; then
3937 break
3938 fi
3939 sleep 2
3940 done
3941
3942 # Print newline because of \c.
3943 ${ECHO} " "
3944 done
3945 }
3946
3947
3948 #
3949 # add_vlv_indexes(): Add VLV indexes to improve search performance.
3950 #
3951 add_vlv_indexes()
3952 {
3953 [ $DEBUG -eq 1 ] && ${ECHO} "In add_vlv_indexes()"
3954
3955 # Set eq indexes to add.
3956 # Note semi colon separators because some filters contain colons
3957 _INDEX1="${LDAP_DOMAIN}.getgrent;${LDAP_DOMAIN}_group_vlv_index;ou=group;objectClass=posixGroup"
3958 _INDEX2="${LDAP_DOMAIN}.gethostent;${LDAP_DOMAIN}_hosts_vlv_index;ou=hosts;objectClass=ipHost"
3959 _INDEX3="${LDAP_DOMAIN}.getnetent;${LDAP_DOMAIN}_networks_vlv_index;ou=networks;objectClass=ipNetwork"
3960 _INDEX4="${LDAP_DOMAIN}.getpwent;${LDAP_DOMAIN}_passwd_vlv_index;ou=people;objectClass=posixAccount"
3961 _INDEX5="${LDAP_DOMAIN}.getrpcent;${LDAP_DOMAIN}_rpc_vlv_index;ou=rpc;objectClass=oncRpc"
3962 _INDEX6="${LDAP_DOMAIN}.getspent;${LDAP_DOMAIN}_shadow_vlv_index;ou=people;objectClass=shadowAccount"
3963
3964 # Indexes added during NIS to LDAP transition
3965 _INDEX7="${LDAP_DOMAIN}.getauhoent;${LDAP_DOMAIN}_auho_vlv_index;automountmapname=auto_home;objectClass=automount"
3966 _INDEX8="${LDAP_DOMAIN}.getsoluent;${LDAP_DOMAIN}_solu_vlv_index;ou=people;objectClass=SolarisUserAttr"
3967 _INDEX10="${LDAP_DOMAIN}.getauthent;${LDAP_DOMAIN}_auth_vlv_index;ou=SolarisAuthAttr;objectClass=SolarisAuthAttr"
3968 _INDEX11="${LDAP_DOMAIN}.getexecent;${LDAP_DOMAIN}_exec_vlv_index;ou=SolarisProfAttr;&(objectClass=SolarisExecAttr)(SolarisKernelSecurityPolicy=*)"
3969 _INDEX12="${LDAP_DOMAIN}.getprofent;${LDAP_DOMAIN}_prof_vlv_index;ou=SolarisProfAttr;&(objectClass=SolarisProfAttr)(SolarisAttrLongDesc=*)"
3970 _INDEX13="${LDAP_DOMAIN}.getmailent;${LDAP_DOMAIN}_mail_vlv_index;ou=aliases;objectClass=mailGroup"
3971 _INDEX14="${LDAP_DOMAIN}.getbootent;${LDAP_DOMAIN}__boot_vlv_index;ou=ethers;&(objectClass=bootableDevice)(bootParameter=*)"
3972 _INDEX15="${LDAP_DOMAIN}.getethent;${LDAP_DOMAIN}_ethers_vlv_index;ou=ethers;&(objectClass=ieee802Device)(macAddress=*)"
3973 _INDEX16="${LDAP_DOMAIN}.getngrpent;${LDAP_DOMAIN}_netgroup_vlv_index;ou=netgroup;objectClass=nisNetgroup"
3974 _INDEX17="${LDAP_DOMAIN}.getipnent;${LDAP_DOMAIN}_ipn_vlv_index;ou=networks;&(objectClass=ipNetwork)(cn=*)"
3975 _INDEX18="${LDAP_DOMAIN}.getmaskent;${LDAP_DOMAIN}_mask_vlv_index;ou=networks;&(objectClass=ipNetwork)(ipNetmaskNumber=*)"
3976 _INDEX19="${LDAP_DOMAIN}.getprent;${LDAP_DOMAIN}_pr_vlv_index;ou=printers;objectClass=printerService"
3977 _INDEX20="${LDAP_DOMAIN}.getip4ent;${LDAP_DOMAIN}_ip4_vlv_index;ou=hosts;&(objectClass=ipHost)(ipHostNumber=*.*)"
3978 _INDEX21="${LDAP_DOMAIN}.getip6ent;${LDAP_DOMAIN}_ip6_vlv_index;ou=hosts;&(objectClass=ipHost)(ipHostNumber=*:*)"
3979
3980 _INDEXES="$_INDEX1 $_INDEX2 $_INDEX3 $_INDEX4 $_INDEX5 $_INDEX6 $_INDEX7 $_INDEX8 $_INDEX9 $_INDEX10 $_INDEX11 $_INDEX12 $_INDEX13 $_INDEX14 $_INDEX15 $_INDEX16 $_INDEX17 $_INDEX18 $_INDEX19 $_INDEX20 $_INDEX21 "
3981
3982
3983 # Set _EXT to use as shortcut.
3984 _EXT="cn=${IDS_DATABASE},cn=ldbm database,cn=plugins,cn=config"
3985
3986
3987 # Display message to id current step.
3988 ${ECHO} " ${STEP}. Processing VLV indexes:"
3989 STEP=`expr $STEP + 1`
3990
3991 # Reset temp file for vlvindex commands.
3992 [ -f ${TMPDIR}/ds5_vlvindex_list ] && rm ${TMPDIR}/ds5_vlvindex_list
3993 touch ${TMPDIR}/ds5_vlvindex_list
3994 [ -f ${TMPDIR}/ds6_vlvindex_list ] && rm ${TMPDIR}/ds6_vlvindex_list
3995 touch ${TMPDIR}/ds6_vlvindex_list
3996
3997 # Get the instance name from iDS server.
3998 _INSTANCE="<server-instance>" # Default to old output.
3999
4000 eval "${LDAPSEARCH} -v ${LDAP_ARGS} -b \"cn=config\" -s base \"objectclass=*\" nsslapd-instancedir | ${GREP} 'nsslapd-instancedir=' | cut -d'=' -f2- > ${TMPDIR}/instance_name 2>&1"
4001
4002 ${GREP} "slapd-" ${TMPDIR}/instance_name > /dev/null 2>&1 # Check if seems right?
4003 if [ $? -eq 0 ]; then # If success, grab name after "slapd-".
4004 _INST_DIR=`cat ${TMPDIR}/instance_name`
4005 _INSTANCE=`basename "${_INST_DIR}" | cut -d'-' -f2-`
4006 fi
4007
4008 # For loop to create indexes.
4009 for p in ${_INDEXES}; do
4010 [ $DEBUG -eq 1 ] && ${ECHO} " Adding index for ${i}"
4011
4012 # Break p (pair) into i and j parts.
4013 i=`${ECHO} $p | cut -d';' -f1`
4014 j=`${ECHO} $p | cut -d';' -f2`
4015 k=`${ECHO} $p | cut -d';' -f3`
4016 m=`${ECHO} $p | cut -d';' -f4`
4017
4018 # Set _jEXT to use as shortcut.
4019 _jEXT="cn=${j},${_EXT}"
4020
4021 # Check if entry exists first, if so, skip to next.
4022 ${LDAPSEARCH} ${SERVER_ARGS} -b "cn=${i},${_jEXT}" -s base "objectclass=*" > /dev/null 2>&1
4023 if [ $? -eq 0 ]; then
4024 # Display index skipped.
4025 ${ECHO} " ${i} vlv_index skipped already exists"
4026 continue
4027 fi
4028
4029 # Compute the VLV Scope from the LDAP_SEARCH_SCOPE.
4030 # NOTE: A value of "base (0)" does not make sense.
4031 case "$LDAP_SEARCH_SCOPE" in
4032 sub) VLV_SCOPE="2" ;;
4033 *) VLV_SCOPE="1" ;;
4034 esac
4035
4036 # Here doc to create LDIF.
4037 ( cat <<EOF
4038 dn: ${_jEXT}
4039 objectClass: top
4040 objectClass: vlvSearch
4041 cn: ${j}
4042 vlvbase: ${k},${LDAP_BASEDN}
4043 vlvscope: ${VLV_SCOPE}
4044 vlvfilter: (${m})
4045 aci: (target="ldap:///${_jEXT}")(targetattr="*")(version 3.0; acl "Config";allow(read,search,compare)userdn="ldap:///anyone";)
4046
4047 dn: cn=${i},${_jEXT}
4048 cn: ${i}
4049 vlvSort: cn uid
4050 objectclass: top
4051 objectclass: vlvIndex
4052 EOF
4053 ) > ${TMPDIR}/vlv_index_${i}
4054
4055 # Add the index.
4056 ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/vlv_index_${i} ${VERB}"
4057 if [ $? -ne 0 ]; then
4058 ${ECHO} " ERROR: Adding VLV index for ${i} failed!"
4059 cleanup
4060 exit 1
4061 fi
4062
4063 # Print message that index was created.
4064 ${ECHO} " ${i} vlv_index Entry created"
4065
4066 # Add command to list of vlvindex commands to run.
4067 ${ECHO} " directoryserver -s ${_INSTANCE} vlvindex -n ${IDS_DATABASE} -T ${i}" >> ${TMPDIR}/ds5_vlvindex_list
4068 ${ECHO} " <install-path>/bin/dsadm reindex -l -t ${i} <directory-instance-path> ${LDAP_SUFFIX}" >> ${TMPDIR}/ds6_vlvindex_list
4069 done
4070 }
4071
4072
4073 #
4074 # display_vlv_cmds(): Display VLV index commands to run on server.
4075 #
4076 display_vlv_cmds()
4077 {
4078 if [ -s "${TMPDIR}/ds5_vlvindex_list" -o \
4079 -s "${TMPDIR}/ds6_vlvindex_list" ]; then
4080 display_msg display_vlv_list
4081 fi
4082
4083 if [ -s "${TMPDIR}/ds5_vlvindex_list" ]; then
4084 cat ${TMPDIR}/ds5_vlvindex_list
4085 fi
4086
4087 cat << EOF
4088
4089
4090 EOF
4091
4092 if [ -s "${TMPDIR}/ds6_vlvindex_list" ]; then
4093 cat ${TMPDIR}/ds6_vlvindex_list
4094 fi
4095 }
4096
4097 #
4098 # keep_backward_compatibility(): Modify schema for the backward compatibility if
4099 # there are the incompatible attributes already
4100 #
4101 keep_backward_compatibility()
4102 {
4103 ${EVAL} "${LDAPSEARCH} ${SERVER_ARGS} -b cn=schema -s base \
4104 \"objectclass=*\" attributeTypes | ${GREP} -i memberGid-oid ${VERB}"
4105 if [ $? -eq 0 ]; then
4106 ${SED} -e 's/1\.3\.6\.1\.4\.1\.42\.2\.27\.5\.1\.30\ /memberGid-oid\ /' \
4107 ${TMPDIR}/schema_attr > ${TMPDIR}/schema_attr.new
4108 ${MV} ${TMPDIR}/schema_attr.new ${TMPDIR}/schema_attr
4109 fi
4110
4111 ${EVAL} "${LDAPSEARCH} ${SERVER_ARGS} -b cn=schema -s base \
4112 \"objectclass=*\" attributeTypes | ${GREP} -i rfc822mailMember-oid \
4113 ${VERB}"
4114 if [ $? -eq 0 ]; then
4115 ${SED} -e \
4116 's/1\.3\.6\.1\.4\.1\.42\.2\.27\.2\.1\.15\ /rfc822mailMember-oid\ /' \
4117 ${TMPDIR}/schema_attr > ${TMPDIR}/schema_attr.new
4118 ${MV} ${TMPDIR}/schema_attr.new ${TMPDIR}/schema_attr
4119 fi
4120 }
4121
4122 #
4123 # update_schema_attr(): Update Schema to support Naming.
4124 #
4125 update_schema_attr()
4126 {
4127 [ $DEBUG -eq 1 ] && ${ECHO} "In update_schema_attr()"
4128
4129 ( cat <<EOF
4130 dn: cn=schema
4131 changetype: modify
4132 add: attributetypes
4133 attributetypes: ( 1.3.6.1.1.1.1.28 NAME 'nisPublickey' DESC 'NIS public key' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4134 attributetypes: ( 1.3.6.1.1.1.1.29 NAME 'nisSecretkey' DESC 'NIS secret key' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4135 attributetypes: ( 1.3.6.1.1.1.1.30 NAME 'nisDomain' DESC 'NIS domain' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4136 attributetypes: ( 1.3.6.1.1.1.1.31 NAME 'automountMapName' DESC 'automount Map Name' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4137 attributetypes: ( 1.3.6.1.1.1.1.32 NAME 'automountKey' DESC 'automount Key Value' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4138 attributetypes: ( 1.3.6.1.1.1.1.33 NAME 'automountInformation' DESC 'automount information' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4139 attributetypes: ( 1.3.6.1.4.1.42.2.27.1.1.12 NAME 'nisNetIdUser' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
4140 attributetypes: ( 1.3.6.1.4.1.42.2.27.1.1.13 NAME 'nisNetIdGroup' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
4141 attributetypes: ( 1.3.6.1.4.1.42.2.27.1.1.14 NAME 'nisNetIdHost' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
4142 attributetypes: ( 1.3.6.1.4.1.42.2.27.2.1.15 NAME 'rfc822mailMember' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
4143 attributetypes: ( 2.16.840.1.113730.3.1.30 NAME 'mgrpRFC822MailMember' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4144 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.15 NAME 'SolarisLDAPServers' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4145 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.16 NAME 'SolarisSearchBaseDN' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE )
4146 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.17 NAME 'SolarisCacheTTL' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4147 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.18 NAME 'SolarisBindDN' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE )
4148 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.19 NAME 'SolarisBindPassword' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4149 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.20 NAME 'SolarisAuthMethod' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4150 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.21 NAME 'SolarisTransportSecurity' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4151 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.22 NAME 'SolarisCertificatePath' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4152 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.23 NAME 'SolarisCertificatePassword' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4153 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.24 NAME 'SolarisDataSearchDN' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4154 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.25 NAME 'SolarisSearchScope' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4155 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.26 NAME 'SolarisSearchTimeLimit' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
4156 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.27 NAME 'SolarisPreferredServer' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4157 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.28 NAME 'SolarisPreferredServerOnly' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4158 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.29 NAME 'SolarisSearchReferral' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4159 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.4 NAME 'SolarisAttrKeyValue' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4160 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.5 NAME 'SolarisAuditAlways' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4161 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.6 NAME 'SolarisAuditNever' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4162 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.7 NAME 'SolarisAttrShortDesc' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4163 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.8 NAME 'SolarisAttrLongDesc' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4164 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.9 NAME 'SolarisKernelSecurityPolicy' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4165 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.10 NAME 'SolarisProfileType' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4166 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.11 NAME 'SolarisProfileId' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4167 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.12 NAME 'SolarisUserQualifier' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4168 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.13 NAME 'SolarisAttrReserved1' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4169 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.14 NAME 'SolarisAttrReserved2' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4170 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.1 NAME 'SolarisProjectID' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
4171 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.2 NAME 'SolarisProjectName' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4172 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.3 NAME 'SolarisProjectAttr' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
4173 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.30 NAME 'memberGid' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
4174 attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.0 NAME 'defaultServerList' DESC 'Default LDAP server host address used by a DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4175 attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.1 NAME 'defaultSearchBase' DESC 'Default LDAP base DN used by a DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE )
4176 attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.2 NAME 'preferredServerList' DESC 'Preferred LDAP server host addresses to be used by a DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4177 attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.3 NAME 'searchTimeLimit' DESC 'Maximum time in seconds a DUA should allow for a search to complete' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
4178 attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.4 NAME 'bindTimeLimit' DESC 'Maximum time in seconds a DUA should allow for the bind operation to complete' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
4179 attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.5 NAME 'followReferrals' DESC 'Tells DUA if it should follow referrals returned by a DSA search result' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4180 attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.6 NAME 'authenticationMethod' DESC 'A keystring which identifies the type of authentication method used to contact the DSA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4181 attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.7 NAME 'profileTTL' DESC 'Time to live before a client DUA should re-read this configuration profile' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
4182 attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.14 NAME 'serviceSearchDescriptor' DESC 'LDAP search descriptor list used by Naming-DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
4183 attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.9 NAME 'attributeMap' DESC 'Attribute mappings used by a Naming-DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4184 attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.10 NAME 'credentialLevel' DESC 'Identifies type of credentials a DUA should use when binding to the LDAP server' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4185 attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.11 NAME 'objectclassMap' DESC 'Objectclass mappings used by a Naming-DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4186 attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.12 NAME 'defaultSearchScope' DESC 'Default search scope used by a DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4187 attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.13 NAME 'serviceCredentialLevel' DESC 'Search scope used by a service of the DUA' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
4188 attributetypes: ( 1.3.6.1.4.1.11.1.3.1.1.15 NAME 'serviceAuthenticationMethod' DESC 'Authentication Method used by a service of the DUA' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4189 attributetypes: ( 1.3.18.0.2.4.1140 NAME 'printer-uri' DESC 'A URI supported by this printer. This URI SHOULD be used as a relative distinguished name (RDN). If printer-xri-supported is implemented, then this URI value MUST be listed in a member value of printer-xri-supported.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4190 attributetypes: ( 1.3.18.0.2.4.1107 NAME 'printer-xri-supported' DESC 'The unordered list of XRI (extended resource identifiers) supported by this printer. Each member of the list consists of a URI (uniform resource identifier) followed by optional authentication and security metaparameters.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4191 attributetypes: ( 1.3.18.0.2.4.1135 NAME 'printer-name' DESC 'The site-specific administrative name of this printer, more end-user friendly than a URI.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE )
4192 attributetypes: ( 1.3.18.0.2.4.1119 NAME 'printer-natural-language-configured' DESC 'The configured language in which error and status messages will be generated (by default) by this printer. Also, a possible language for printer string attributes set by operator, system administrator, or manufacturer. Also, the (declared) language of the "printer-name", "printer-location", "printer-info", and "printer-make-and-model" attributes of this printer. For example: "en-us" (US English) or "fr-fr" (French in France) Legal values of language tags conform to [RFC3066] "Tags for the Identification of Languages".' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE )
4193 attributetypes: ( 1.3.18.0.2.4.1136 NAME 'printer-location' DESC 'Identifies the location of the printer. This could include things like: "in Room 123A", "second floor of building XYZ".' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE )
4194 attributetypes: ( 1.3.18.0.2.4.1139 NAME 'printer-info' DESC 'Identifies the descriptive information about this printer. This could include things like: "This printer can be used for printing color transparencies for HR presentations", or "Out of courtesy for others, please print only small (1-5 page) jobs at this printer", or even "This printer is going away on July 1, 1997, please find a new printer".' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE )
4195 attributetypes: ( 1.3.18.0.2.4.1134 NAME 'printer-more-info' DESC 'A URI used to obtain more information about this specific printer. For example, this could be an HTTP type URI referencing an HTML page accessible to a Web Browser. The information obtained from this URI is intended for end user consumption.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4196 attributetypes: ( 1.3.18.0.2.4.1138 NAME 'printer-make-and-model' DESC 'Identifies the make and model of the device. The device manufacturer MAY initially populate this attribute.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE )
4197 attributetypes: ( 1.3.18.0.2.4.1133 NAME 'printer-ipp-versions-supported' DESC 'Identifies the IPP protocol version(s) that this printer supports, including major and minor versions, i.e., the version numbers for which this Printer implementation meets the conformance requirements.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} )
4198 attributetypes: ( 1.3.18.0.2.4.1132 NAME 'printer-multiple-document-jobs-supported' DESC 'Indicates whether or not the printer supports more than one document per job, i.e., more than one Send-Document or Send-Data operation with document data.' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
4199 attributetypes: ( 1.3.18.0.2.4.1109 NAME 'printer-charset-configured' DESC 'The configured charset in which error and status messages will be generated (by default) by this printer. Also, a possible charset for printer string attributes set by operator, system administrator, or manufacturer. For example: "utf-8" (ISO 10646/Unicode) or "iso-8859-1" (Latin1). Legal values are defined by the IANA Registry of Coded Character Sets and the "(preferred MIME name)" SHALL be used as the tag. For coherence with IPP Model, charset tags in this attribute SHALL be lowercase normalized. This attribute SHOULD be static (time of registration) and SHOULD NOT be dynamically refreshed attributetypes: (subsequently).' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{63} SINGLE-VALUE )
4200 attributetypes: ( 1.3.18.0.2.4.1131 NAME 'printer-charset-supported' DESC 'Identifies the set of charsets supported for attribute type values of type Directory String for this directory entry. For example: "utf-8" (ISO 10646/Unicode) or "iso-8859-1" (Latin1). Legal values are defined by the IANA Registry of Coded Character Sets and the preferred MIME name.' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{63} )
4201 attributetypes: ( 1.3.18.0.2.4.1137 NAME 'printer-generated-natural-language-supported' DESC 'Identifies the natural language(s) supported for this directory entry. For example: "en-us" (US English) or "fr-fr" (French in France). Legal values conform to [RFC3066], Tags for the Identification of Languages.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{63} )
4202 attributetypes: ( 1.3.18.0.2.4.1130 NAME 'printer-document-format-supported' DESC 'The possible document formats in which data may be interpreted and printed by this printer. Legal values are MIME types come from the IANA Registry of Internet Media Types.' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} )
4203 attributetypes: ( 1.3.18.0.2.4.1129 NAME 'printer-color-supported' DESC 'Indicates whether this printer is capable of any type of color printing at all, including highlight color.' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
4204 attributetypes: ( 1.3.18.0.2.4.1128 NAME 'printer-compression-supported' DESC 'Compression algorithms supported by this printer. For example: "deflate, gzip". Legal values include; "none", "deflate" attributetypes: (public domain ZIP), "gzip" (GNU ZIP), "compress" (UNIX).' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} )
4205 attributetypes: ( 1.3.18.0.2.4.1127 NAME 'printer-pages-per-minute' DESC 'The nominal number of pages per minute which may be output by this printer (e.g., a simplex or black-and-white printer). This attribute is informative, NOT a service guarantee. Typically, it is the value used in marketing literature to describe this printer.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
4206 attributetypes: ( 1.3.18.0.2.4.1126 NAME 'printer-pages-per-minute-color' DESC 'The nominal number of color pages per minute which may be output by this printer (e.g., a simplex or color printer). This attribute is informative, NOT a service guarantee. Typically, it is the value used in marketing literature to describe this printer.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
4207 attributetypes: ( 1.3.18.0.2.4.1125 NAME 'printer-finishings-supported' DESC 'The possible finishing operations supported by this printer. Legal values include; "none", "staple", "punch", "cover", "bind", "saddle-stitch", "edge-stitch", "staple-top-left", "staple-bottom-left", "staple-top-right", "staple-bottom-right", "edge-stitch-left", "edge-stitch-top", "edge-stitch-right", "edge-stitch-bottom", "staple-dual-left", "staple-dual-top", "staple-dual-right", "staple-dual-bottom".' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} )
4208 attributetypes: ( 1.3.18.0.2.4.1124 NAME 'printer-number-up-supported' DESC 'The possible numbers of print-stream pages to impose upon a single side of an instance of a selected medium. Legal values include; 1, 2, and 4. Implementations may support other values.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
4209 attributetypes: ( 1.3.18.0.2.4.1123 NAME 'printer-sides-supported' DESC 'The number of impression sides (one or two) and the two-sided impression rotations supported by this printer. Legal values include; "one-sided", "two-sided-long-edge", "two-sided-short-edge".' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} )
4210 attributetypes: ( 1.3.18.0.2.4.1122 NAME 'printer-media-supported' DESC 'The standard names/types/sizes (and optional color suffixes) of the media supported by this printer. For example: "iso-a4", "envelope", or "na-letter-white". Legal values conform to ISO 10175, Document Printing Application (DPA), and any IANA registered extensions.' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} )
4211 attributetypes: ( 1.3.18.0.2.4.1117 NAME 'printer-media-local-supported' DESC 'Site-specific names of media supported by this printer, in the language in "printer-natural-language-configured". For example: "purchasing-form" (site-specific name) as opposed to (in "printer-media-supported"): "na-letter" (standard keyword from ISO 10175).' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} )
4212 attributetypes: ( 1.3.18.0.2.4.1121 NAME 'printer-resolution-supported' DESC 'List of resolutions supported for printing documents by this printer. Each resolution value is a string with 3 fields: 1) Cross feed direction resolution (positive integer), 2) Feed direction resolution (positive integer), 3) Resolution unit. Legal values are "dpi" (dots per inch) and "dpcm" (dots per centimeter). Each resolution field is delimited by ">". For example: "300> 300> dpi>".' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} )
4213 attributetypes: ( 1.3.18.0.2.4.1120 NAME 'printer-print-quality-supported' DESC 'List of print qualities supported for printing documents on this printer. For example: "draft, normal". Legal values include; "unknown", "draft", "normal", "high".' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} )
4214 attributetypes: ( 1.3.18.0.2.4.1110 NAME 'printer-job-priority-supported' DESC 'Indicates the number of job priority levels supported. An IPP conformant printer which supports job priority must always support a full range of priorities from "1" to "100" (to ensure consistent behavior), therefore this attribute describes the "granularity". Legal values of this attribute are from "1" to "100".' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
4215 attributetypes: ( 1.3.18.0.2.4.1118 NAME 'printer-copies-supported' DESC 'The maximum number of copies of a document that may be printed as a single job. A value of "0" indicates no maximum limit. A value of "-1" indicates unknown.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
4216 attributetypes: ( 1.3.18.0.2.4.1111 NAME 'printer-job-k-octets-supported' DESC 'The maximum size in kilobytes (1,024 octets actually) incoming print job that this printer will accept. A value of "0" indicates no maximum limit. A value of "-1" indicates unknown.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
4217 attributetypes: ( 1.3.18.0.2.4.1112 NAME 'printer-current-operator' DESC 'The name of the current human operator responsible for operating this printer. It is suggested that this string include information that would enable other humans to reach the operator, such as a phone number.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE )
4218 attributetypes: ( 1.3.18.0.2.4.1113 NAME 'printer-service-person' DESC 'The name of the current human service person responsible for servicing this printer. It is suggested that this string include information that would enable other humans to reach the service person, such as a phone number.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE )
4219 attributetypes: ( 1.3.18.0.2.4.1114 NAME 'printer-delivery-orientation-supported' DESC 'The possible delivery orientations of pages as they are printed and ejected from this printer. Legal values include; "unknown", "face-up", and "face-down".' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} )
4220 attributetypes: ( 1.3.18.0.2.4.1115 NAME 'printer-stacking-order-supported' DESC 'The possible stacking order of pages as they are printed and ejected from this printer. Legal values include; "unknown", "first-to-last", "last-to-first".' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} )
4221 attributetypes: ( 1.3.18.0.2.4.1116 NAME 'printer-output-features-supported' DESC 'The possible output features supported by this printer. Legal values include; "unknown", "bursting", "decollating", "page-collating", "offset-stacking".' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} )
4222 attributetypes: ( 1.3.18.0.2.4.1108 NAME 'printer-aliases' DESC 'Site-specific administrative names of this printer in addition the printer name specified for printer-name.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} )
4223 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.63 NAME 'sun-printer-bsdaddr' DESC 'Sets the server, print queue destination name and whether the client generates protocol extensions. "Solaris" specifies a Solaris print server extension. The value is represented by the following value: server "," destination ", Solaris".' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
4224 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.64 NAME 'sun-printer-kvp' DESC 'This attribute contains a set of key value pairs which may have meaning to the print subsystem or may be user defined. Each value is represented by the following: key "=" value.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
4225 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.57 NAME 'nisplusTimeZone' DESC 'tzone column from NIS+ timezone table' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4226 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.67 NAME 'ipTnetTemplateName' DESC 'Trusted Solaris network template template_name' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4227 attributetypes: ( 1.3.6.1.4.1.42.2.27.5.1.68 NAME 'ipTnetNumber' DESC 'Trusted Solaris network template ip_address' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
4228 EOF
4229 ) > ${TMPDIR}/schema_attr
4230
4231 keep_backward_compatibility
4232
4233 # Add the entry.
4234 ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/schema_attr ${VERB}"
4235 if [ $? -ne 0 ]; then
4236 ${ECHO} " ERROR: update of schema attributes failed!"
4237 cleanup
4238 exit 1
4239 fi
4240
4241 # Display message that schema is updated.
4242 ${ECHO} " ${STEP}. Schema attributes have been updated."
4243 STEP=`expr $STEP + 1`
4244 }
4245
4246
4247 #
4248 # update_schema_obj(): Update the schema objectclass definitions.
4249 #
4250 update_schema_obj()
4251 {
4252 [ $DEBUG -eq 1 ] && ${ECHO} "In update_schema_obj()"
4253
4254 # Add the objectclass definitions.
4255 ( cat <<EOF
4256 dn: cn=schema
4257 changetype: modify
4258 add: objectclasses
4259 objectclasses: ( 1.3.6.1.1.1.2.14 NAME 'NisKeyObject' SUP top MUST ( cn $ nisPublickey $ nisSecretkey ) MAY ( uidNumber $ description ) )
4260
4261 dn: cn=schema
4262 changetype: modify
4263 add: objectclasses
4264 objectclasses: ( 1.3.6.1.1.1.2.15 NAME 'nisDomainObject' SUP top MUST nisDomain )
4265
4266 dn: cn=schema
4267 changetype: modify
4268 add: objectclasses
4269 objectclasses: ( 1.3.6.1.1.1.2.16 NAME 'automountMap' SUP top MUST automountMapName MAY description )
4270
4271 dn: cn=schema
4272 changetype: modify
4273 add: objectclasses
4274 objectclasses: ( 1.3.6.1.1.1.2.17 NAME 'automount' SUP top MUST ( automountKey $ automountInformation ) MAY description )
4275
4276 dn: cn=schema
4277 changetype: modify
4278 add: objectclasses
4279 objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.7 NAME 'SolarisNamingProfile' SUP top MUST ( cn $ SolarisLDAPservers $ SolarisSearchBaseDN ) MAY ( SolarisBindDN $ SolarisBindPassword $ SolarisAuthMethod $ SolarisTransportSecurity $ SolarisCertificatePath $ SolarisCertificatePassword $ SolarisDataSearchDN $ SolarisSearchScope $ SolarisSearchTimeLimit $ SolarisPreferredServer $ SolarisPreferredServerOnly $ SolarisCacheTTL $ SolarisSearchReferral ) )
4280
4281 dn: cn=schema
4282 changetype: modify
4283 add: objectclasses
4284 objectclasses: ( 2.16.840.1.113730.3.2.4 NAME 'mailGroup' SUP top MUST mail MAY ( cn $ mgrpRFC822MailMember ) )
4285
4286 dn: cn=schema
4287 changetype: modify
4288 add: objectclasses
4289 objectclasses: ( 1.3.6.1.4.1.42.2.27.1.2.5 NAME 'nisMailAlias' SUP top MUST cn MAY rfc822mailMember )
4290
4291 dn: cn=schema
4292 changetype: modify
4293 add: objectclasses
4294 objectclasses: ( 1.3.6.1.4.1.42.2.27.1.2.6 NAME 'nisNetId' SUP top MUST cn MAY ( nisNetIdUser $ nisNetIdGroup $ nisNetIdHost ) )
4295
4296 dn: cn=schema
4297 changetype: modify
4298 add: objectclasses
4299 objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.2 NAME 'SolarisAuditUser' SUP top AUXILIARY MAY ( SolarisAuditAlways $ SolarisAuditNever ) )
4300
4301 dn: cn=schema
4302 changetype: modify
4303 add: objectclasses
4304 objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.3 NAME 'SolarisUserAttr' SUP top AUXILIARY MAY ( SolarisUserQualifier $ SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrKeyValue ) )
4305
4306 dn: cn=schema
4307 changetype: modify
4308 add: objectclasses
4309 objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.4 NAME 'SolarisAuthAttr' SUP top MUST cn MAY ( SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrShortDesc $ SolarisAttrLongDesc $ SolarisAttrKeyValue ) )
4310
4311 dn: cn=schema
4312 changetype: modify
4313 add: objectclasses
4314 objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.5 NAME 'SolarisProfAttr' SUP top MUST cn MAY ( SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrLongDesc $ SolarisAttrKeyValue ) )
4315
4316 dn: cn=schema
4317 changetype: modify
4318 add: objectclasses
4319 objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.6 NAME 'SolarisExecAttr' SUP top AUXILIARY MAY ( SolarisKernelSecurityPolicy $ SolarisProfileType $ SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisProfileID $ SolarisAttrKeyValue ) )
4320
4321 dn: cn=schema
4322 changetype: modify
4323 add: objectclasses
4324 objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.1 NAME 'SolarisProject' SUP top MUST ( SolarisProjectID $ SolarisProjectName ) MAY ( memberUid $ memberGid $ description $ SolarisProjectAttr ) )
4325
4326 dn: cn=schema
4327 changetype: modify
4328 add: objectclasses
4329 objectclasses: ( 1.3.6.1.4.1.11.1.3.1.2.4 NAME 'DUAConfigProfile' SUP top DESC 'Abstraction of a base configuration for a DUA' MUST cn MAY ( defaultServerList $ preferredServerList $ defaultSearchBase $ defaultSearchScope $ searchTimeLimit $ bindTimeLimit $ credentialLevel $ authenticationMethod $ followReferrals $ serviceSearchDescriptor $ serviceCredentialLevel $ serviceAuthenticationMethod $ objectclassMap $ attributeMap $ profileTTL ) )
4330
4331 dn: cn=schema
4332 changetype: modify
4333 add: objectclasses
4334 objectclasses: ( 1.3.18.0.2.6.2549 NAME 'slpService' DESC 'DUMMY definition' SUP top MUST objectclass )
4335
4336 dn: cn=schema
4337 changetype: modify
4338 add: objectclasses
4339 objectclasses: ( 1.3.18.0.2.6.254 NAME 'slpServicePrinter' DESC 'Service Location Protocol (SLP) information.' SUP slpService AUXILIARY )
4340
4341 dn: cn=schema
4342 changetype: modify
4343 add: objectclasses
4344 objectclasses: ( 1.3.18.0.2.6.258 NAME 'printerAbstract' DESC 'Printer related information.' SUP top ABSTRACT MAY ( printer-name $ printer-natural-language-configured $ printer-location $ printer-info $ printer-more-info $ printer-make-and-model $ printer-multiple-document-jobs-supported $ printer-charset-configured $ printer-charset-supported $ printer-generated-natural-language-supported $ printer-document-format-supported $ printer-color-supported $ printer-compression-supported $ printer-pages-per-minute $ printer-pages-per-minute-color $ printer-finishings-supported $ printer-number-up-supported $ printer-sides-supported $ printer-media-supported $ printer-media-local-supported $ printer-resolution-supported $ printer-print-quality-supported $ printer-job-priority-supported $ printer-copies-supported $ printer-job-k-octets-supported $ printer-current-operator $ printer-service-person $ printer-delivery-orientation-supported $ printer-stacking-order-supported $ printer-output-features-supported ) )
4345
4346 dn: cn=schema
4347 changetype: modify
4348 add: objectclasses
4349 objectclasses: ( 1.3.18.0.2.6.255 NAME 'printerService' DESC 'Printer information.' SUP printerAbstract STRUCTURAL MAY ( printer-uri $ printer-xri-supported ) )
4350
4351 dn: cn=schema
4352 changetype: modify
4353 add: objectclasses
4354 objectclasses: ( 1.3.18.0.2.6.257 NAME 'printerServiceAuxClass' DESC 'Printer information.' SUP printerAbstract AUXILIARY MAY ( printer-uri $ printer-xri-supported ) )
4355
4356 dn: cn=schema
4357 changetype: modify
4358 add: objectclasses
4359 objectclasses: ( 1.3.18.0.2.6.256 NAME 'printerIPP' DESC 'Internet Printing Protocol (IPP) information.' SUP top AUXILIARY MAY ( printer-ipp-versions-supported $ printer-multiple-document-jobs-supported ) )
4360
4361 dn: cn=schema
4362 changetype: modify
4363 add: objectclasses
4364 objectclasses: ( 1.3.18.0.2.6.253 NAME 'printerLPR' DESC 'LPR information.' SUP top AUXILIARY MUST printer-name MAY printer-aliases )
4365
4366 dn: cn=schema
4367 changetype: modify
4368 add: objectclasses
4369 objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.14 NAME 'sunPrinter' DESC 'Sun printer information' SUP top AUXILIARY MUST printer-name MAY ( sun-printer-bsdaddr $ sun-printer-kvp ) )
4370
4371 dn: cn=schema
4372 changetype: modify
4373 add: objectclasses
4374 objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.12 NAME 'nisplusTimeZoneData' DESC 'NIS+ timezone table data' SUP top STRUCTURAL MUST cn MAY ( nisplusTimeZone $ description ) )
4375
4376 dn: cn=schema
4377 changetype: modify
4378 add: objectclasses
4379 objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.8 NAME 'ipTnetTemplate' DESC 'Object class for TSOL network templates' SUP top MUST ipTnetTemplateName MAY SolarisAttrKeyValue )
4380
4381 dn: cn=schema
4382 changetype: modify
4383 add: objectclasses
4384 objectclasses: ( 1.3.6.1.4.1.42.2.27.5.2.9 NAME 'ipTnetHost' DESC 'Associates an IP address or wildcard with a TSOL template_name' SUP top AUXILIARY MUST ipTnetNumber )
4385 EOF
4386 ) > ${TMPDIR}/schema_obj
4387
4388 # Add the entry.
4389 ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/schema_obj ${VERB}"
4390 if [ $? -ne 0 ]; then
4391 ${ECHO} " ERROR: update of schema objectclass definitions failed!"
4392 cleanup
4393 exit 1
4394 fi
4395
4396 # Display message that schema is updated.
4397 ${ECHO} " ${STEP}. Schema objectclass definitions have been added."
4398 STEP=`expr $STEP + 1`
4399 }
4400
4401 #
4402 # modify_top_aci(): Modify the ACI for the top entry to disable self modify
4403 # of user attributes.
4404 #
4405 modify_top_aci()
4406 {
4407 [ $DEBUG -eq 1 ] && ${ECHO} "In modify_top_aci()"
4408
4409 # Set ACI Name
4410 ACI_NAME="LDAP_Naming_Services_deny_write_access"
4411
4412 # Search for ACI_NAME
4413 eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_top_aci 2>&1"
4414 if [ $? -ne 0 ]; then
4415 ${ECHO} "Error searching aci for ${LDAP_BASEDN}"
4416 cat ${TMPDIR}/chk_top_aci
4417 cleanup
4418 exit 1
4419 fi
4420 ${GREP} "${ACI_NAME}" ${TMPDIR}/chk_top_aci > /dev/null 2>&1
4421 if [ $? -eq 0 ]; then
4422 ${ECHO} " ${STEP}. Top level ACI ${ACI_NAME} already exists for ${LDAP_BASEDN}."
4423 STEP=`expr $STEP + 1`
4424 return 0
4425 fi
4426
4427 # Crate LDIF for top level ACI.
4428 ( cat <<EOF
4429 dn: ${LDAP_BASEDN}
4430 changetype: modify
4431 add: aci
4432 aci: (targetattr = "cn||uid||uidNumber||gidNumber||homeDirectory||shadowLastChange||shadowMin||shadowMax||shadowWarning||shadowInactive||shadowExpire||shadowFlag||memberUid||SolarisAttrKeyValue||SolarisAttrReserved1||SolarisAttrReserved2||SolarisUserQualifier")(version 3.0; acl ${ACI_NAME}; deny (write) userdn = "ldap:///self";)
4433 -
4434 EOF
4435 ) > ${TMPDIR}/top_aci
4436
4437 # Add the entry.
4438 ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/top_aci ${VERB}"
4439 if [ $? -ne 0 ]; then
4440 ${ECHO} " ERROR: Modify of top level ACI failed! (restricts self modify)"
4441 cleanup
4442 exit 1
4443 fi
4444
4445 # Display message that ACI is updated.
4446 MSG="ACI for ${LDAP_BASEDN} modified to disable self modify."
4447 if [ $EXISTING_PROFILE -eq 1 ];then
4448 ${ECHO} " ACI SET: $MSG"
4449 else
4450 ${ECHO} " ${STEP}. $MSG"
4451 STEP=`expr $STEP + 1`
4452 fi
4453 }
4454
4455 #
4456 # find_and_delete_ACI(): Find an ACI in file $2 with a matching pattern $1.
4457 # Delete the ACI and print a message using $3 as the ACI name. $3 is needed
4458 # because it could have a different value than that of $1.
4459 find_and_delete_ACI()
4460 {
4461 [ $DEBUG -eq 1 ] && ${ECHO} "In find_and_delete_ACI"
4462
4463 # if an ACI with pattern $1 exists in file $2, delete it from ${LDAP_BASEDN}
4464 ${EGREP} $1 $2 | ${SED} -e 's/aci=//' > ${TMPDIR}/grep_find_delete_aci 2>&1
4465 if [ -s ${TMPDIR}/grep_find_delete_aci ]; then
4466 aci_to_delete=`${CAT} ${TMPDIR}/grep_find_delete_aci`
4467
4468 # Create the tmp file to delete the ACI.
4469 ( cat <<EOF
4470 dn: ${LDAP_BASEDN}
4471 changetype: modify
4472 delete: aci
4473 aci: ${aci_to_delete}
4474 EOF
4475 ) > ${TMPDIR}/find_delete_aci
4476
4477 # Delete the ACI
4478 ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/find_delete_aci ${VERB}"
4479 if [ $? -ne 0 ]; then
4480 ${ECHO} " ERROR: Remove of $3 ACI failed!"
4481 cleanup
4482 exit 1
4483 fi
4484
4485 ${RM} -f ${TMPDIR}/find_delete_aci
4486 # Display message that an ACL is deleted.
4487 MSG="ACI $3 deleted."
4488 if [ $EXISTING_PROFILE -eq 1 ]; then
4489 ${ECHO} " ACI DELETED: $MSG"
4490 else
4491 ${ECHO} " ${STEP}. $MSG"
4492 STEP=`expr $STEP + 1`
4493 fi
4494 fi
4495 }
4496
4497 #
4498 # Add an ACI to deny non-admin access to shadow data when
4499 # shadow update is enabled.
4500 #
4501 deny_non_admin_shadow_access()
4502 {
4503 [ $DEBUG -eq 1 ] && ${ECHO} "In deny_non_admin_shadow_access()"
4504
4505 # Set ACI Names
4506 ACI_TO_ADD="LDAP_Naming_Services_deny_non_admin_shadow_access"
4507 ACI_TO_DEL="LDAP_Naming_Services_deny_non_host_shadow_access"
4508
4509 # Search for ACI_TO_ADD
4510 eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_aci_non_admin 2>&1"
4511 if [ $? -ne 0 ]; then
4512 ${ECHO} "Error searching aci for ${LDAP_BASEDN}"
4513 cleanup
4514 exit 1
4515 fi
4516
4517 # If an ACI with ${ACI_TO_ADD} already exists, we are done.
4518 ${EGREP} ${ACI_TO_ADD} ${TMPDIR}/chk_aci_non_admin 2>&1 > /dev/null
4519 if [ $? -eq 0 ]; then
4520 MSG="ACI ${ACI_TO_ADD} already set for ${LDAP_BASEDN}."
4521 if [ $EXISTING_PROFILE -eq 1 ]; then
4522 ${ECHO} " NOT SET: $MSG"
4523 else
4524 ${ECHO} " ${STEP}. $MSG"
4525 STEP=`expr $STEP + 1`
4526 fi
4527 return 0
4528 fi
4529
4530 # The deny_non_admin_shadow_access and deny_non_host_shadow_access ACIs
4531 # should be mutually exclusive, so if the latter exists, delete it.
4532 find_and_delete_ACI ${ACI_TO_DEL} ${TMPDIR}/chk_aci_non_admin ${ACI_TO_DEL}
4533
4534 # Create the tmp file to add.
4535 ( cat <<EOF
4536 dn: ${LDAP_BASEDN}
4537 changetype: modify
4538 add: aci
4539 aci: (target="ldap:///${LDAP_BASEDN}")(targetattr = "shadowLastChange||
4540 shadowMin|| shadowMax||shadowWarning||shadowInactive||shadowExpire||
4541 shadowFlag||userPassword") (version 3.0; acl ${ACI_TO_ADD};
4542 deny (write,read,search,compare) userdn != "ldap:///${LDAP_ADMINDN}";)
4543 EOF
4544 ) > ${TMPDIR}/non_admin_aci_write
4545
4546 # Add the entry.
4547 ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/non_admin_aci_write ${VERB}"
4548 if [ $? -ne 0 ]; then
4549 ${ECHO} " ERROR: Adding ACI ${ACI_TO_ADD} failed!"
4550 ${CAT} ${TMPDIR}/non_admin_aci_write
4551 cleanup
4552 exit 1
4553 fi
4554
4555 ${RM} -f ${TMPDIR}/non_admin_aci_write
4556 # Display message that the non-admin access to shadow data is denied.
4557 MSG="Non-Admin access to shadow data denied."
4558 if [ $EXISTING_PROFILE -eq 1 ]; then
4559 ${ECHO} " ACI SET: $MSG"
4560 else
4561 ${ECHO} " ${STEP}. $MSG"
4562 STEP=`expr $STEP + 1`
4563 fi
4564 }
4565
4566 #
4567 # Add an ACI to deny non-host access to shadow data when
4568 # shadow update is enabled and auth Method if gssapi.
4569 #
4570 deny_non_host_shadow_access()
4571 {
4572 [ $DEBUG -eq 1 ] && ${ECHO} "In deny_non_host_shadow_access()"
4573
4574 # Set ACI Names
4575 ACI_TO_ADD="LDAP_Naming_Services_deny_non_host_shadow_access"
4576 ACI_TO_DEL="LDAP_Naming_Services_deny_non_admin_shadow_access"
4577
4578 # Search for ACI_TO_ADD
4579 eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_aci_non_host 2>&1"
4580 if [ $? -ne 0 ]; then
4581 ${ECHO} "Error searching aci for ${LDAP_BASEDN}"
4582 cleanup
4583 exit 1
4584 fi
4585
4586 # If an ACI with ${ACI_TO_ADD} already exists, we are done.
4587 ${EGREP} ${ACI_TO_ADD} ${TMPDIR}/chk_aci_non_host 2>&1 > /dev/null
4588 if [ $? -eq 0 ]; then
4589 MSG="ACI ${ACI_TO_ADD} already set for ${LDAP_BASEDN}."
4590 if [ $EXISTING_PROFILE -eq 1 ]; then
4591 ${ECHO} " NOT SET: $MSG"
4592 else
4593 ${ECHO} " ${STEP}. $MSG"
4594 STEP=`expr $STEP + 1`
4595 fi
4596 return 0
4597 fi
4598
4599 # The deny_non_admin_shadow_access and deny_non_host_shadow_access ACIs
4600 # should be mutually exclusive, so if the former exists, delete it.
4601 find_and_delete_ACI ${ACI_TO_DEL} ${TMPDIR}/chk_aci_non_host ${ACI_TO_DEL}
4602
4603 # Create the tmp file to add.
4604 ( cat <<EOF
4605 dn: ${LDAP_BASEDN}
4606 changetype: modify
4607 add: aci
4608 aci: (target="ldap:///${LDAP_BASEDN}")(targetattr = "shadowLastChange||
4609 shadowMin|| shadowMax||shadowWarning||shadowInactive||shadowExpire||
4610 shadowFlag||userPassword") (version 3.0; acl ${ACI_TO_ADD};
4611 deny (write,read,search,compare)
4612 userdn != "ldap:///cn=*+ipHostNumber=*,ou=Hosts,${LDAP_BASEDN}";)
4613 EOF
4614 ) > ${TMPDIR}/non_host_aci_write
4615
4616 # Add the entry.
4617 ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/non_host_aci_write ${VERB}"
4618 if [ $? -ne 0 ]; then
4619 ${ECHO} " ERROR: Adding ACI ${ACI_TO_ADD} failed!"
4620 ${CAT} ${TMPDIR}/non_host_aci_write
4621 cleanup
4622 exit 1
4623 fi
4624
4625 ${RM} -f ${TMPDIR}/non_host_aci_write
4626 # Display message that the non-host access to shadow data is denied.
4627 MSG="Non-host access to shadow data is denied."
4628 if [ $EXISTING_PROFILE -eq 1 ]; then
4629 ${ECHO} " ACI SET: $MSG"
4630 else
4631 ${ECHO} " ${STEP}. $MSG"
4632 STEP=`expr $STEP + 1`
4633 fi
4634 }
4635
4636 #
4637 # add_vlv_aci(): Add access control information (aci) for VLV.
4638 #
4639 add_vlv_aci()
4640 {
4641 [ $DEBUG -eq 1 ] && ${ECHO} "In add_vlv_aci()"
4642
4643 # Add the VLV ACI.
4644 ( cat <<EOF
4645 dn: oid=2.16.840.1.113730.3.4.9,cn=features,cn=config
4646 changetype: modify
4647 replace: aci
4648 aci: (targetattr != "aci") (version 3.0; acl "VLV Request Control"; allow(read,search,compare) userdn = "ldap:///anyone";)
4649 EOF
4650 ) > ${TMPDIR}/vlv_aci
4651
4652 # Add the entry.
4653 ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/vlv_aci ${VERB}"
4654 if [ $? -ne 0 ]; then
4655 ${ECHO} " ERROR: Add of VLV ACI failed!"
4656 cleanup
4657 exit 1
4658 fi
4659
4660 # Display message that schema is updated.
4661 ${ECHO} " ${STEP}. Add of VLV Access Control Information (ACI)."
4662 STEP=`expr $STEP + 1`
4663 }
4664
4665
4666 #
4667 # set_nisdomain(): Add the NisDomainObject to the Base DN.
4668 #
4669 set_nisdomain()
4670 {
4671 [ $DEBUG -eq 1 ] && ${ECHO} "In set_nisdomain()"
4672
4673 # Check if nisDomain is already set.
4674 ${EVAL} "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base \
4675 \"objectclass=*\"" > ${TMPDIR}/chk_nisdomain 2>&1
4676 ${EVAL} "${GREP} -i nisDomain ${TMPDIR}/chk_nisdomain ${VERB}"
4677 if [ $? -eq 0 ]; then
4678 ${ECHO} " ${STEP}. NisDomainObject for ${LDAP_BASEDN} was already set."
4679 STEP=`expr $STEP + 1`
4680 return 0
4681 fi
4682
4683 # Add the new top level containers.
4684 ( cat <<EOF
4685 dn: ${LDAP_BASEDN}
4686 changetype: modify
4687 objectclass: nisDomainObject
4688 nisdomain: ${LDAP_DOMAIN}
4689 EOF
4690 ) > ${TMPDIR}/nis_domain
4691
4692 # Add the entry.
4693 ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/nis_domain ${VERB}"
4694 if [ $? -ne 0 ]; then
4695 ${ECHO} " ERROR: update of NisDomainObject in ${LDAP_BASEDN} failed."
4696 cleanup
4697 exit 1
4698 fi
4699
4700 # Display message that schema is updated.
4701 ${ECHO} " ${STEP}. NisDomainObject added to ${LDAP_BASEDN}."
4702 STEP=`expr $STEP + 1`
4703 }
4704
4705
4706 #
4707 # check_attrName(): Check that the attribute name is valid.
4708 # $1 Key to check.
4709 # Returns 0 : valid name 1 : invalid name
4710 #
4711 check_attrName()
4712 {
4713 [ $DEBUG -eq 1 ] && ${ECHO} "In check_attrName()"
4714 [ $DEBUG -eq 1 ] && ${ECHO} "check_attrName: Input Param = $1"
4715
4716 ${ECHO} $1 | ${EGREP} '^[0-9]+(\.[0-9]+)*$' > /dev/null 2>&1
4717 if [ $? -eq 0 ]; then
4718 ${EVAL} "${LDAPSEARCH} ${SERVER_ARGS} -b cn=schema -s base \"objectclass=*\" \
4719 attributeTypes | ${EGREP} -i '^attributetypes[ ]*=[ ]*\([ ]*$1 ' ${VERB}"
4720 else
4721 ${EVAL} "${LDAPSEARCH} ${SERVER_ARGS} -b cn=schema -s base \"objectclass=*\" \
4722 attributeTypes | ${EGREP} -i \"'$1'\" ${VERB}"
4723 fi
4724
4725 if [ $? -ne 0 ]; then
4726 return 1
4727 else
4728 return 0
4729 fi
4730 }
4731
4732
4733 #
4734 # get_objectclass(): Determine the objectclass for the given attribute name
4735 # $1 Attribute name to check.
4736 # _ATTR_NAME Return value, Object Name or NULL if unknown to idsconfig.
4737 #
4738 # NOTE: An attribute name can be valid but still we might not be able
4739 # to determine the objectclass from the table.
4740 # In such cases, the user needs to create the necessary object(s).
4741 #
4742 get_objectclass()
4743 {
4744 [ $DEBUG -eq 1 ] && ${ECHO} "In get_objectclass()"
4745 [ $DEBUG -eq 1 ] && ${ECHO} "get_objectclass: Input Param = $1"
4746
4747 # Set return value to NULL string.
4748 _ATTR_NAME=""
4749
4750 # Test key for type:
4751 case `${ECHO} ${1} | tr '[A-Z]' '[a-z]'` in
4752 ou | organizationalunitname | 2.5.4.11) _ATTR_NAME="organizationalUnit" ;;
4753 dc | domaincomponent | 0.9.2342.19200300.100.1.25) _ATTR_NAME="domain" ;;
4754 o | organizationname | 2.5.4.10) _ATTR_NAME="organization" ;;
4755 c | countryname | 2.5.4.6) _ATTR_NAME="country" ;;
4756 *) _ATTR_NAME="" ;;
4757 esac
4758
4759 [ $DEBUG -eq 1 ] && ${ECHO} "get_objectclass: _ATTR_NAME = $_ATTR_NAME"
4760 }
4761
4762
4763 #
4764 # add_base_objects(): Add any necessary base objects.
4765 #
4766 add_base_objects()
4767 {
4768 [ $DEBUG -eq 1 ] && ${ECHO} "In add_base_objects()"
4769
4770 # Convert to lower case for basename.
4771 format_string "${LDAP_BASEDN}"
4772 LOWER_BASEDN="${FMT_STR}"
4773 format_string "${LDAP_SUFFIX}"
4774 LOWER_SUFFIX="${FMT_STR}"
4775
4776 [ $DEBUG -eq 1 ] && ${ECHO} "LOWER_BASEDN: ${LOWER_BASEDN}"
4777 [ $DEBUG -eq 1 ] && ${ECHO} "LOWER_SUFFIX: ${LOWER_SUFFIX}"
4778
4779 # Create additional components.
4780 if [ "${LOWER_BASEDN}" = "${LOWER_SUFFIX}" ]; then
4781 [ $DEBUG -eq 1 ] && ${ECHO} "Base DN and Suffix equivalent"
4782 else
4783 # first, test that the suffix is valid
4784 dcstmp=`basename "${LOWER_BASEDN}" "${LOWER_SUFFIX}"`
4785 if [ "$dcstmp" = "${LOWER_BASEDN}" ]; then
4786 # should not happen since check_basedn_suffix() succeeded
4787 ${ECHO} "Invalid suffix ${LOWER_SUFFIX}"
4788 ${ECHO} "for Base DN ${LOWER_BASEDN}"
4789 cleanup
4790 exit 1
4791 fi
4792 # OK, suffix is valid, start working with LDAP_BASEDN
4793 # field separator is ',' (i.e., space is a valid character)
4794 dcstmp2="`${ECHO} ${LDAP_BASEDN} |
4795 sed -e 's/[ ]*,[ ]*/,/g' -e 's/[ ]*=[ ]*/=/g'`"
4796 dcs=""
4797 # use dcstmp to count the loop, and dcstmp2 to get the correct
4798 # string case
4799 # dcs should be in reverse order, only for these components
4800 # that need to be added
4801 while [ -n "${dcstmp}" ]
4802 do
4803 i2=`${ECHO} "$dcstmp2" | cut -f1 -d','`
4804 dk=`${ECHO} $i2 | awk -F= '{print $1}'`
4805 dc=`${ECHO} $i2 | awk -F= '{print $2}'`
4806 dcs="$dk=$dc,$dcs";
4807 dcstmp2=`${ECHO} "$dcstmp2" | cut -f2- -d','`
4808 dcstmp=`${ECHO} "$dcstmp" | cut -f2- -d','`
4809 [ $DEBUG -eq 1 ] && \
4810 ${ECHO} "dcs: ${dcs}\ndcstmp: ${dcstmp}\ndcstmp2: ${dcstmp2}\n"
4811 done
4812
4813
4814
4815 lastdc=${LDAP_SUFFIX}
4816 dc=`${ECHO} "${dcs}" | cut -f1 -d','`
4817 dcstmp=`${ECHO} "${dcs}" | cut -f2- -d','`
4818 while [ -n "${dc}" ]; do
4819 # Get Key and component from $dc.
4820 dk2=`${ECHO} $dc | awk -F= '{print $1}'`
4821 dc2=`${ECHO} $dc | awk -F= '{print $2}'`
4822
4823 # At this point, ${dk2} is a valid attribute name
4824
4825 # Check if entry exists first, if so, skip to next.
4826 ${LDAPSEARCH} ${SERVER_ARGS} -b "${dk2}=${dc2},$lastdc" -s base "objectclass=*" > /dev/null 2>&1
4827 if [ $? -eq 0 ]; then
4828 # Set the $lastdc to new dc.
4829 lastdc="${dk2}=${dc2},$lastdc"
4830
4831 # Process next component.
4832 dc=`${ECHO} "${dcstmp}" | cut -f1 -d','`
4833 dcstmp=`${ECHO} "${dcstmp}" | cut -f2- -d','`
4834 continue
4835
4836 fi
4837
4838 # Determine the objectclass for the entry.
4839 get_objectclass $dk2
4840 OBJ_Name=${_ATTR_NAME}
4841 if [ "${OBJ_Name}" = "" ]; then
4842 ${ECHO} "Cannot determine objectclass for $dk2"
4843 ${ECHO} "Please create ${dk2}=${dc2},$lastdc entry and rerun idsconfig"
4844 exit 1
4845 fi
4846
4847 # Add the new container.
4848 ( cat <<EOF
4849 dn: ${dk2}=${dc2},$lastdc
4850 ${dk2}: $dc2
4851 objectClass: top
4852 objectClass: ${OBJ_Name}
4853 EOF
4854 ) > ${TMPDIR}/base_objects
4855
4856
4857 # Set the $lastdc to new dc.
4858 lastdc="${dk2}=${dc2},$lastdc"
4859
4860 # Add the entry.
4861 ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/base_objects ${VERB}"
4862 if [ $? -ne 0 ]; then
4863 ${ECHO} " ERROR: update of base objects ${dc} failed."
4864 cleanup
4865 exit 1
4866 fi
4867
4868 # Display message that schema is updated.
4869 ${ECHO} " ${STEP}. Created DN component ${dc}."
4870 STEP=`expr $STEP + 1`
4871
4872 # Process next component.
4873 dc=`${ECHO} "${dcstmp}" | cut -f1 -d','`
4874 dcstmp=`${ECHO} "${dcstmp}" | cut -f2- -d','`
4875 done
4876 fi
4877 }
4878
4879
4880 #
4881 # add_new_containers(): Add the top level classes.
4882 #
4883 # $1 = Base DN
4884 #
4885 add_new_containers()
4886 {
4887 [ $DEBUG -eq 1 ] && ${ECHO} "In add_new_containers()"
4888
4889 for ou in people group rpc protocols networks netgroup \
4890 aliases hosts services ethers profile printers projects \
4891 SolarisAuthAttr SolarisProfAttr Timezone ipTnet ; do
4892
4893 # Check if nismaps already exist.
4894 eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"ou=${ou},${LDAP_BASEDN}\" -s base \"objectclass=*\" ${VERB}"
4895 if [ $? -eq 0 ]; then
4896 continue
4897 fi
4898
4899 # Create TMP file to add.
4900 ( cat <<EOF
4901 dn: ou=${ou},${LDAP_BASEDN}
4902 ou: ${ou}
4903 objectClass: top
4904 objectClass: organizationalUnit
4905 EOF
4906 ) > ${TMPDIR}/toplevel.${ou}
4907
4908 # Add the entry.
4909 ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/toplevel.${ou} ${VERB}"
4910 if [ $? -ne 0 ]; then
4911 ${ECHO} " ERROR: Add of ou=${ou} container failed!"
4912 cleanup
4913 exit 1
4914 fi
4915 done
4916
4917 # Display message that top level OU containers complete.
4918 ${ECHO} " ${STEP}. Top level \"ou\" containers complete."
4919 STEP=`expr $STEP + 1`
4920 }
4921
4922
4923 #
4924 # add_auto_maps(): Add the automount map entries.
4925 #
4926 # auto_home, auto_direct, auto_master, auto_shared
4927 #
4928 add_auto_maps()
4929 {
4930 [ $DEBUG -eq 1 ] && ${ECHO} "In add_auto_maps()"
4931
4932 # Set AUTO_MAPS for maps to create.
4933 AUTO_MAPS="auto_home auto_direct auto_master auto_shared"
4934
4935 for automap in $AUTO_MAPS; do
4936 # Check if automaps already exist.
4937 eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"automountMapName=${automap},${LDAP_BASEDN}\" -s base \"objectclass=*\" ${VERB}"
4938 if [ $? -eq 0 ]; then
4939 continue
4940 fi
4941
4942 # Create the tmp file to add.
4943 ( cat <<EOF
4944 dn: automountMapName=${automap},${LDAP_BASEDN}
4945 automountMapName: ${automap}
4946 objectClass: top
4947 objectClass: automountMap
4948 EOF
4949 ) > ${TMPDIR}/automap.${automap}
4950
4951 # Add the entry.
4952 ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/automap.${automap} ${VERB}"
4953 if [ $? -ne 0 ]; then
4954 ${ECHO} " ERROR: Add of automap ${automap} failed!"
4955 cleanup
4956 exit 1
4957 fi
4958 done
4959
4960 # Display message that automount entries are updated.
4961 ${ECHO} " ${STEP}. automount maps: $AUTO_MAPS processed."
4962 STEP=`expr $STEP + 1`
4963 }
4964
4965
4966 #
4967 # add_proxyagent(): Add entry for nameservice to use to access server.
4968 #
4969 add_proxyagent()
4970 {
4971 [ $DEBUG -eq 1 ] && ${ECHO} "In add_proxyagent()"
4972
4973 # Check if proxy agent already exists.
4974 eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_PROXYAGENT}\" -s base \"objectclass=*\" ${VERB}"
4975 if [ $? -eq 0 ]; then
4976 ${ECHO} " ${STEP}. Proxy Agent ${LDAP_PROXYAGENT} already exists."
4977 STEP=`expr $STEP + 1`
4978 return 0
4979 fi
4980
4981 # Get cn and sn names from LDAP_PROXYAGENT.
4982 cn_tmp=`${ECHO} ${LDAP_PROXYAGENT} | cut -f1 -d, | cut -f2 -d=`
4983
4984 # Create the tmp file to add.
4985 ( cat <<EOF
4986 dn: ${LDAP_PROXYAGENT}
4987 cn: ${cn_tmp}
4988 sn: ${cn_tmp}
4989 objectclass: top
4990 objectclass: person
4991 userpassword: ${LDAP_PROXYAGENT_CRED}
4992 EOF
4993 ) > ${TMPDIR}/proxyagent
4994
4995 # Add the entry.
4996 ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/proxyagent ${VERB}"
4997 if [ $? -ne 0 ]; then
4998 ${ECHO} " ERROR: Adding proxyagent failed!"
4999 cleanup
5000 exit 1
5001 fi
5002
5003 # Display message that schema is updated.
5004 ${ECHO} " ${STEP}. Proxy Agent ${LDAP_PROXYAGENT} added."
5005 STEP=`expr $STEP + 1`
5006 }
5007
5008 #
5009 # allow_proxy_read_pw(): Give Proxy Agent read permission for password.
5010 #
5011 allow_proxy_read_pw()
5012 {
5013 [ $DEBUG -eq 1 ] && ${ECHO} "In allow_proxy_read_pw()"
5014
5015 # Search for ACI_NAME
5016 eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_proxyread_aci 2>&1"
5017 ${GREP} "${PROXY_ACI_NAME}" ${TMPDIR}/chk_proxyread_aci > /dev/null 2>&1
5018 if [ $? -eq 0 ]; then
5019 ${ECHO} " ${STEP}. Proxy ACI ${PROXY_ACI_NAME=} already exists for ${LDAP_BASEDN}."
5020 STEP=`expr $STEP + 1`
5021 return 0
5022 fi
5023
5024 # Create the tmp file to add.
5025 ( cat <<EOF
5026 dn: ${LDAP_BASEDN}
5027 changetype: modify
5028 add: aci
5029 aci: (target="ldap:///${LDAP_BASEDN}")(targetattr="userPassword")
5030 (version 3.0; acl ${PROXY_ACI_NAME}; allow (compare,read,search)
5031 userdn = "ldap:///${LDAP_PROXYAGENT}";)
5032 EOF
5033 ) > ${TMPDIR}/proxy_read
5034
5035 # Add the entry.
5036 ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/proxy_read ${VERB}"
5037 if [ $? -ne 0 ]; then
5038 ${ECHO} " ERROR: Allow ${LDAP_PROXYAGENT} to read password failed!"
5039 cleanup
5040 exit 1
5041 fi
5042
5043 # Display message that schema is updated.
5044 ${ECHO} " ${STEP}. Give ${LDAP_PROXYAGENT} read permission for password."
5045 STEP=`expr $STEP + 1`
5046 }
5047
5048 # Delete Proxy Agent read permission for password.
5049 delete_proxy_read_pw()
5050 {
5051 [ $DEBUG -eq 1 ] && ${ECHO} "In delete_proxy_read_pw()"
5052
5053 # Search for ACI_NAME
5054 eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"${LDAP_BASEDN}\" -s base objectclass=* aci > ${TMPDIR}/chk_proxyread_aci 2>&1"
5055 ${GREP} "${PROXY_ACI_NAME}" ${TMPDIR}/chk_proxyread_aci | \
5056 ${SED} -e 's/aci=//' > ${TMPDIR}/grep_proxyread_aci 2>&1
5057 if [ $? -ne 0 ]; then
5058 ${ECHO} "Proxy ACI ${PROXY_ACI_NAME} does not exist for ${LDAP_BASEDN}."
5059 return 0
5060 fi
5061
5062 # We need to remove proxy agent's read access to user passwords,
5063 # but We do not know the value of the ${LDAP_PROXYAGENT} here, so
5064 # 1. if only one match found, delete it
5065 # 2. if more than one matches found, ask the user which one to delete
5066 HOWMANY=`${WC} -l ${TMPDIR}/grep_proxyread_aci | ${NAWK} '{print $1}'`
5067 if [ $HOWMANY -eq 0 ]; then
5068 ${ECHO} "Proxy ACI ${PROXY_ACI_NAME} does not exist for ${LDAP_BASEDN}."
5069 return 0
5070 fi
5071 if [ $HOWMANY -eq 1 ];then
5072 proxy_aci=`${CAT} ${TMPDIR}/grep_proxyread_aci`
5073 else
5074 ${CAT} << EOF
5075
5076 Proxy agent is not allowed to read user passwords when shadow
5077 update is enabled. There are more than one proxy agents found.
5078 Please select the currently proxy agent being used, so that
5079 idsconfig can remove its read access to user passwords.
5080
5081 The proxy agents are:
5082
5083 EOF
5084 # generate the proxy agent list
5085 ${SED} -e "s/.*ldap:\/\/\/.*ldap:\/\/\///" \
5086 ${TMPDIR}/grep_proxyread_aci | ${SED} -e "s/\";)//" > \
5087 ${TMPDIR}/proxy_agent_list
5088
5089 # print the proxy agent list
5090 ${NAWK} '{print NR ": " $0}' ${TMPDIR}/proxy_agent_list
5091
5092 # ask the user to pick one
5093 _MENU_PROMPT="Select the proxy agent (1-$HOWMANY): "
5094 get_menu_choice "${_MENU_PROMPT}" "0" "$HOWMANY"
5095 _CH=$MN_CH
5096 proxy_aci=`${SED} -n "$_CH p" ${TMPDIR}/grep_proxyread_aci`
5097 fi
5098
5099 # Create the tmp file to delete the ACI.
5100 ( cat <<EOF
5101 dn: ${LDAP_BASEDN}
5102 changetype: modify
5103 delete: aci
5104 aci: ${proxy_aci}
5105 EOF
5106 ) > ${TMPDIR}/proxy_delete
5107
5108 # Delete the ACI
5109 ${EVAL} "${LDAPMODIFY} ${LDAP_ARGS} -f ${TMPDIR}/proxy_delete ${VERB}"
5110 if [ $? -ne 0 ]; then
5111 ${ECHO} " ERROR: Remove of ${PROXY_ACI_NAME} ACI failed!"
5112 cat ${TMPDIR}/proxy_delete
5113 cleanup
5114 exit 1
5115 fi
5116
5117 # Display message that ACI is updated.
5118 MSG="Removed ${PROXY_ACI_NAME} ACI for proxyagent read permission for password."
5119 ${ECHO} " "
5120 ${ECHO} " ACI REMOVED: $MSG"
5121 ${ECHO} " The ACI removed is $proxy_aci"
5122 ${ECHO} " "
5123 }
5124
5125 #
5126 # add_profile(): Add client profile to server.
5127 #
5128 add_profile()
5129 {
5130 [ $DEBUG -eq 1 ] && ${ECHO} "In add_profile()"
5131
5132 # If profile name already exists, DELETE it, and add new one.
5133 eval "${LDAPSEARCH} ${LDAP_ARGS} -b \"cn=${LDAP_PROFILE_NAME},ou=profile,${LDAP_BASEDN}\" -s base \"objectclass=*\" ${VERB}"
5134 if [ $? -eq 0 ]; then
5135 # Create Delete file.
5136 ( cat <<EOF
5137 cn=${LDAP_PROFILE_NAME},ou=profile,${LDAP_BASEDN}
5138 EOF
5139 ) > ${TMPDIR}/del_profile
5140
5141 # Check if DEL_OLD_PROFILE is set. (If not ERROR)
5142 if [ $DEL_OLD_PROFILE -eq 0 ]; then
5143 ${ECHO} "ERROR: Profile name ${LDAP_PROFILE_NAME} exists! Add failed!"
5144 exit 1
5145 fi
5146
5147 # Delete the OLD profile.
5148 ${EVAL} "${LDAPDELETE} ${LDAP_ARGS} -f ${TMPDIR}/del_profile ${VERB}"
5149 if [ $? -ne 0 ]; then
5150 ${ECHO} " ERROR: Attempt to DELETE profile failed!"
5151 cleanup
5152 exit 1
5153 fi
5154 fi
5155
5156 # Build the "ldapclient genprofile" command string to execute.
5157 GEN_CMD="ldapclient genprofile -a \"profileName=${LDAP_PROFILE_NAME}\""
5158
5159 # Add required argument defaultSearchBase.
5160 GEN_CMD="${GEN_CMD} -a \"defaultSearchBase=${LDAP_BASEDN}\""
5161
5162 # Add optional parameters.
5163 [ -n "$LDAP_SERVER_LIST" ] && \
5164 GEN_CMD="${GEN_CMD} -a \"defaultServerList=${LDAP_SERVER_LIST}\""
5165 [ -n "$LDAP_SEARCH_SCOPE" ] && \
5166 GEN_CMD="${GEN_CMD} -a \"defaultSearchScope=${LDAP_SEARCH_SCOPE}\""
5167 [ -n "$LDAP_CRED_LEVEL" ] && \
5168 GEN_CMD="${GEN_CMD} -a \"credentialLevel=${LDAP_CRED_LEVEL}\""
5169 [ -n "$LDAP_AUTHMETHOD" ] && \
5170 GEN_CMD="${GEN_CMD} -a \"authenticationMethod=${LDAP_AUTHMETHOD}\""
5171 [ -n "$LDAP_FOLLOWREF" ] && \
5172 GEN_CMD="${GEN_CMD} -a \"followReferrals=${LDAP_FOLLOWREF}\""
5173 [ -n "$LDAP_SEARCH_TIME_LIMIT" ] && \
5174 GEN_CMD="${GEN_CMD} -a \"searchTimeLimit=${LDAP_SEARCH_TIME_LIMIT}\""
5175 [ -n "$LDAP_PROFILE_TTL" ] && \
5176 GEN_CMD="${GEN_CMD} -a \"profileTTL=${LDAP_PROFILE_TTL}\""
5177 [ -n "$LDAP_BIND_LIMIT" ] && \
5178 GEN_CMD="${GEN_CMD} -a \"bindTimeLimit=${LDAP_BIND_LIMIT}\""
5179 [ -n "$LDAP_PREF_SRVLIST" ] && \
5180 GEN_CMD="${GEN_CMD} -a \"preferredServerList=${LDAP_PREF_SRVLIST}\""
5181 [ -n "$LDAP_SRV_AUTHMETHOD_PAM" ] && \
5182 GEN_CMD="${GEN_CMD} -a \"serviceAuthenticationMethod=${LDAP_SRV_AUTHMETHOD_PAM}\""
5183 [ -n "$LDAP_SRV_AUTHMETHOD_KEY" ] && \
5184 GEN_CMD="${GEN_CMD} -a \"serviceAuthenticationMethod=${LDAP_SRV_AUTHMETHOD_KEY}\""
5185 [ -n "$LDAP_SRV_AUTHMETHOD_CMD" ] && \
5186 GEN_CMD="${GEN_CMD} -a \"serviceAuthenticationMethod=${LDAP_SRV_AUTHMETHOD_CMD}\""
5187
5188 # Check if there are any service search descriptors to ad.
5189 if [ -s "${SSD_FILE}" ]; then
5190 ssd_2_profile
5191 fi
5192
5193 # Execute "ldapclient genprofile" to create profile.
5194 eval ${GEN_CMD} > ${TMPDIR}/gen_profile 2> ${TMPDIR}/gen_profile_ERR
5195 if [ $? -ne 0 ]; then
5196 ${ECHO} " ERROR: ldapclient genprofile failed!"
5197 cleanup
5198 exit 1
5199 fi
5200
5201 # Add the generated profile..
5202 ${EVAL} "${LDAPMODIFY} -a ${LDAP_ARGS} -f ${TMPDIR}/gen_profile ${VERB}"
5203 if [ $? -ne 0 ]; then
5204 ${ECHO} " ERROR: Attempt to add profile failed!"
5205 cleanup
5206 exit 1
5207 fi
5208
5209 # Display message that schema is updated.
5210 ${ECHO} " ${STEP}. Generated client profile and loaded on server."
5211 STEP=`expr $STEP + 1`
5212 }
5213
5214
5215 #
5216 # cleanup(): Remove the TMPDIR and all files in it.
5217 #
5218 cleanup()
5219 {
5220 [ $DEBUG -eq 1 ] && ${ECHO} "In cleanup()"
5221
5222 rm -fr ${TMPDIR}
5223 }
5224
5225
5226 #
5227 # * * * MAIN * * *
5228 #
5229 # Description:
5230 # This script assumes that the iPlanet Directory Server (iDS) is
5231 # installed and that setup has been run. This script takes the
5232 # iDS server from that point and sets up the infrastructure for
5233 # LDAP Naming Services. After running this script, ldapaddent(1M)
5234 # or some other tools can be used to populate data.
5235
5236 # Initialize the variables that need to be set to NULL, or some
5237 # other initial value before the rest of the functions can be called.
5238 init
5239
5240 # Parse command line arguments.
5241 parse_arg $*
5242 shift $?
5243
5244 # Print extra line to separate from prompt.
5245 ${ECHO} " "
5246
5247 # Either Load the user specified config file
5248 # or prompt user for config info.
5249 if [ -n "$INPUT_FILE" ]
5250 then
5251 load_config_file
5252 INTERACTIVE=0 # Turns off prompts that occur later.
5253 validate_info # Validate basic info in file.
5254 chk_ids_version # Check iDS version for compatibility.
5255 else
5256 # Display BACKUP warning to user.
5257 display_msg backup_server
5258 get_confirm "Do you wish to continue with server setup (y/n/h)?" "n" "backup_help"
5259 if [ $? -eq 0 ]; then # if No, cleanup and exit.
5260 cleanup ; exit 1
5261 fi
5262
5263 # Prompt for values.
5264 prompt_config_info
5265 display_summary # Allow user to modify results.
5266 INTERACTIVE=1 # Insures future prompting.
5267 fi
5268
5269 # Modify slapd.oc.conf to ALLOW cn instead of REQUIRE.
5270 modify_cn
5271
5272 # Modify timelimit to user value.
5273 [ $NEED_TIME -eq 1 ] && modify_timelimit
5274
5275 # Modify sizelimit to user value.
5276 [ $NEED_SIZE -eq 1 ] && modify_sizelimit
5277
5278 # Modify the password storage scheme to support CRYPT.
5279 if [ "$NEED_CRYPT" = "TRUE" ]; then
5280 modify_pwd_crypt
5281 fi
5282
5283 # Update the schema (Attributes, Objectclass Definitions)
5284 if [ ${SCHEMA_UPDATED} -eq 0 ]; then
5285 update_schema_attr
5286 update_schema_obj
5287 fi
5288
5289 # Add suffix together with its root entry (if needed)
5290 add_suffix ||
5291 {
5292 cleanup
5293 exit 1
5294 }
5295
5296 # Add base objects (if needed)
5297 add_base_objects
5298
5299 # Update the NisDomainObject.
5300 # The Base DN might of just been created, so this MUST happen after
5301 # the base objects have been added!
5302 set_nisdomain
5303
5304 # Add top level classes (new containers)
5305 add_new_containers
5306
5307 # Add common nismaps.
5308 add_auto_maps
5309
5310 # Modify top ACI.
5311 modify_top_aci
5312
5313 # Add Access Control Information for VLV.
5314 add_vlv_aci
5315
5316 # if Proxy needed, Add Proxy Agent and give read permission for password.
5317 if [ $NEED_PROXY -eq 1 ]; then
5318 add_proxyagent
5319 if [ "$LDAP_ENABLE_SHADOW_UPDATE" != "TRUE" ]; then
5320 allow_proxy_read_pw
5321 fi
5322 fi
5323
5324 # If admin needed for shadow update, Add the administrator identity and
5325 # give read/write permission for shadow, and deny all others read/write
5326 # access to it.
5327 if [ $NEED_ADMIN -eq 1 ]; then
5328 add_admin
5329 allow_admin_read_write_shadow
5330 # deny non-admin access to shadow data
5331 deny_non_admin_shadow_access
5332 fi
5333
5334 if [ $GSSAPI_ENABLE -eq 1 ]; then
5335 add_id_mapping_rules
5336 # do not modify ACI if "sasl/GSSAPI" and "self" are not selected
5337 if [ "$LDAP_CRED_LEVEL" = "self" -a "$LDAP_AUTHMETHOD" = "sasl/GSSAPI" ]; then
5338 modify_userpassword_acl_for_gssapi
5339 else
5340 ${ECHO} " ACL for GSSAPI was not set because of incompatibility in profile."
5341 fi
5342 fi
5343
5344 # If use host principal for shadow update, give read/write permission for
5345 # shadow, and deny all others' read/write access to it.
5346 if [ $NEED_HOSTACL -eq 1 ]; then
5347 allow_host_read_write_shadow
5348 # deny non-host access to shadow data
5349 deny_non_host_shadow_access
5350 fi
5351
5352
5353 # Generate client profile and add it to the server.
5354 add_profile
5355
5356 # Add Indexes to improve Search Performance.
5357 add_eq_indexes
5358 add_sub_indexes
5359 add_vlv_indexes
5360
5361 # Display setup complete message
5362 display_msg setup_complete
5363
5364 # Display VLV index commands to be executed on server.
5365 display_vlv_cmds
5366
5367 # Create config file if requested.
5368 [ -n "$OUTPUT_FILE" ] && create_config_file
5369
5370 # Removed the TMPDIR and all files in it.
5371 cleanup
5372
5373 exit 0
5374 # end of MAIN.
|
1 #!/bin/ksh93
2 #
3 # $Id: idsconfig.sh,v 66c6ff17d001 2013-09-24 00:35:53Z jel+illumos $
4 #
5 # CDDL HEADER START
6 #
7 # The contents of this file are subject to the terms of the
8 # Common Development and Distribution License (the "License").
9 # You may not use this file except in compliance with the License.
10 #
11 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
12 # or http://www.opensolaris.org/os/licensing.
13 # See the License for the specific language governing permissions
14 # and limitations under the License.
15 #
16 # When distributing Covered Code, include this CDDL HEADER in each
17 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
18 # If applicable, add the following below this CDDL HEADER, with the
19 # fields enclosed by brackets "[]" replaced with your own identifying
20 # information: Portions Copyright [yyyy] [name of copyright owner]
21 #
22 # CDDL HEADER END
23 #
24 # Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
25 # Portions Copyright 2013 Jens Elkner.
26
27
28 #############################################################################
29 # Main global vars
30 #############################################################################
31 LIC='[-?$Id: idsconfig.sh,v 66c6ff17d001 2013-09-24 00:35:53Z jel+illumos $ ]
32 [-copyright?Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.]
33 [-copyright?Portions Copyright (c) 2013 Jens Elkner.]
34 [-license?CDDL 1.0]'
35
36 SDIR=${.sh.file%/*}
37 typeset -r FPROG=${.sh.file}
38 typeset -r PROG=${FPROG##*/}
39
40 typeset -T LogObj_t=(
41 typeset -Sh 'Color for info messages' GREEN='38;5;232;48;5;118' #'1;30;102';
42 typeset -Sh 'Color for warning messages' BLUE='38;5;21;48;5;118' #'1;34;102';
43 typeset -Sh 'Color for fatal messages' RED='38;5;9;48;5;118' #'1;31;102';
44 typeset -Sih 'Flag, whether to use colored labels' COLORED=1
45 typeset -Sih 'Flag, whether to print verbose infos' VERBOSE=0
46
47 function log {
48 (( _.COLORED )) && print -u2 "\E[1;$2m${ date +%T; } $1:\E[0m $3" || \
49 print -u2 "${ date +%T; } ${1}: $3"
50 }
51 typeset -Sfh ' log a message to stderr' log
52 function verbose {
53 (( _.VERBOSE )) && _.log "VERB" ${_.GREEN} " $*"
54 }
55 typeset -Sfh ' log a info message to stderr if verbose messages are enabled' info
56
57 function info {
58 _.log "INFO" ${_.GREEN} "$*"
59 }
60 typeset -Sfh ' log a info message to stderr' info
61 function warn {
62 _.log "WARN" ${_.BLUE} "$*"
63 }
64 typeset -Sfh ' log a warning message to stderr' warn
65 function fatal {
66 _.log "FATAL" ${_.RED} "$*"
67 }
68 typeset -Sfh ' log a fatal error message to stderr' fatal
69 function printMarker {
70 typeset COLOR="$1" L='----------------------------------------------------------------------------'
71 (( _.COLORED )) && print "\E[1;${COLOR:-${_.GREEN}}m${L}\E[0m" || \
72 print "${L}"
73 }
74 typeset -Sfh ' print a marker line to stdout' printMarker
75 )
76 LogObj_t Log
77
78 typeset -T ManObj_t=(
79 typeset -Ah 'Variable descriptions. Key: variable name' VAR
80 typeset -Ah 'Function usages. Key: function name' FUNC
81 function addVar {
82 [[ -n ${_.VAR[$1]} ]] && Log.warn "Overwriting previous description for $1"
83 _.VAR[$1]="[+$1?$2]"
84 }
85 typeset -fh 'Add a description (arg2) for the given variable name (arg1)' addVar
86 function addFunc {
87 typeset fname=$1
88 typeset X="$2"
89 [[ -n ${_.FUNC[$fname]} ]] && Log.warn "Overwriting previous usage info for $1()"
90 [[ -z $X ]] && X="$LIC"
91 shift 2
92 while [[ -n $1 ]]; do
93 X+="$1"
94 shift
95 done
96 _.FUNC[$fname]+="$X"
97 }
98 typeset -fh $'Add usage info (arg3 ...) for the given function name (arg1). If implementation details (arg2) is empty, the value of \a$LIC\a gets used instead' addFunc
99 function varUsage {
100 typeset X=""
101 [[ "$1" == '@' || "$1" == '*' ]] && set -- ${!_.VAR[@]}
102 while [[ -n $1 ]]; do
103 X+="${_.VAR[$1]}"
104 shift
105 done
106 print "$X"
107 }
108 typeset -fh $'Get the variable usage info for the named variables (arg2 ...) if available as a concatenated string. See \baddVar()\b' varUsage
109 function funcUsage {
110 printf "${_.FUNC[$1]}"
111 }
112 typeset -fh 'Get the function usage info for the named function (arg1)' funcUsage
113
114 function listVars {
115 typeset ALL="${ print ${!_.VAR[*]} | tr ' ' '\n' | sort -u; }" VNAME
116 for VNAME in $ALL; do
117 [[ $VNAME == OLDENV || $VNAME == LASTENV ]] && continue
118 typeset -n X=$VNAME
119 print "$VNAME=$X"
120 done
121 unset -n X
122 }
123 typeset -fh 'List all registered environment variables and its current value, except for OLDENV and LASTENV.' listVars
124 )
125 ManObj_t Man
126
127 Man.addFunc showUsage '' '[+NAME?showUsage - show usage info.]
128 [+DESCRIPTION?Shows usage info for the given \afname\a if available.]
129 \n\n\afname\a
130 '
131 function showUsage {
132 typeset WHAT="$2"
133 if (( Log.VERBOSE )) && [[ ${WHAT} == 'MAIN' ]]; then
134 typeset PRE=${Man.FUNC[$WHAT]%%\[+NOTES*}
135 typeset POST=${.sh.match}
136 typeset E='[+ENVIRONMENT VARIABLES]{'"${ Man.varUsage '*' ; }"'}'
137 getopts -a "${PROG}" "${ print ${PRE}${E}${POST} ; }" OPT --man
138 else
139 getopts -a "${PROG}" "${ print ${Man.FUNC[$WHAT]}; }" OPT --man
140 fi
141 }
142
143 Man.addVar PROG 'String. The basename of this script.'
144
145 Man.addVar INT 'Associative array of Integers. Config relevant int values and flags.'
146 typeset -A -i INT=( )
147 Man.addVar STR 'Associative array of Strings. Config relevant string values.'
148 typeset -A STR=( )
149
150 Man.addVar TMPF 'Associative array of Integers. Int values with a more or less a global character in this script.'
151 typeset -A -i TMPF=( )
152 Man.addVar TMP 'Associative array of Strings. String values whith a more or less a global character in this script.'
153 typeset -A TMP=( )
154
155 Man.addVar CON_ARGS 'String. Contains connection related options for ldap commands.'
156 typeset CON_ARGS=''
157
158 Man.addVar AUTH_ARGS 'Indexed array of Strings. Contains authentification related options for ldap commands.'
159 typeset -a AUTH_ARGS=( )
160
161 Man.addVar SSD 'Indexed array of Strings. Contains the Service Search Decsriptors to use.'
162 typeset -a SSD=( )
163
164 # NOTE: The ACI names are retained to be compatible to previous releases. If one
165 # installs a completely new LDAP infrastructure changing the names should
166 # not be a problem as long as they do not collide with existing aci names!
167
168 Man.addVar SFX_ANYONE_ACI_NAME 'String constant. The name of the suffix ACI rule, which allows anyone to read, search, compare.'
169 typeset -r SFX_ANYONE_ACI_NAME='Anonymous access'
170
171 Man.addVar SFX_SELF_ACI_NAME 'String constant. The name of the suffix ACI rule, which allows a principal to modify its own attributes except those related to password state information and policy.'
172 typeset -r SFX_SELF_ACI_NAME='Limited self entry modification'
173
174 Man.addVar SFX_ADMIN_ACI_NAME 'String constant. The name of the suffix ACI rule, which allows the directory configuration administrator all operations on any entry.'
175 typeset -r SFX_ADMINGRP_ACI_NAME='Configuration Administrator access'
176
177 Man.addVar SFX_ADMINGRP_ACI_NAME 'String constant. The name of the suffix ACI rule, which allows the directory configuration administrator group all operations on any entry.'
178 typeset -r SFX_ADMIN_ACI_NAME='Configuration Administrator Group access'
179
180 Man.addVar PROXY_ACI_NAME 'String constant. The name of the ACI rule, which allows proxies to read passwords.'
181 typeset -r PROXY_ACI_NAME='LDAP Naming Services proxy_password_read'
182
183 Man.addVar HOST_ACI_NAME 'String constant. The name of the ACI rule, which allows host principals to write passwords.'
184 typeset -r HOST_ACI_NAME='LDAP Naming Services host_shadow_write'
185 Man.addVar NON_HOST_ACI_NAME 'String constant. The name of the ACI rule, which denies non-host principals access to shadow data.'
186 typeset -r NON_HOST_ACI_NAME='LDAP Naming Services deny_non_host_shadow_access'
187
188 Man.addVar ADMIN_ACI_NAME 'String constant. The name of the ACI rule, which allows Admin principals access to shadow, rbac and mount data.'
189 typeset -r ADMIN_ACI_NAME='LDAP Naming Services admin_shadow_write'
190 Man.addVar NON_ADMIN_ACI_NAME 'String constant. The name of the ACI rule, which denies non-Admin principals access to shadow data.'
191 typeset -r NON_ADMIN_ACI_NAME='LDAP Naming Services deny_non_admin_shadow_access'
192 Man.addVar USER_ACI_NAME 'String constant. The name of the ACI rule, which prevents a user from changing administrative fields like uidNumber, homeDirectory, shadowExpire, etc..'
193 typeset -r USER_ACI_NAME='LDAP Naming Services deny_write_access'
194
195 Man.addVar VLV_ACI_NAME 'String constant. The name of the global ACI rule, which allows any user to use VLVs for read, search and compare.'
196 typeset -r VLV_ACI_NAME='VLV Request Control'
197
198 Man.addVar SELF_GSS_ACI_NAME 'String constant. The name of the ou=people ACI rule, which allows a via SASL/GSSAPI authenticated user read and search on passwords.'
199 typeset -r SELF_GSS_ACI_NAME='self-read-pwd'
200
201 Man.addVar HOST_GSS_ACI_NAME 'String constant. The name of the ou=people ACI rule, which allows a via SASL/GSSAPI authenticated hosts read and search on passwords.'
202 typeset -r HOST_GSS_ACI_NAME='host-read-pwd'
203
204 Man.addVar AUTH_METHODS 'Indexed array of Strings. A list of currently supported authentication methods.'
205 typeset -a -r AUTH_METHODS=(
206 'none' 'simple' 'sasl/DIGEST-MD5'
207 'tls:simple' 'tls:sasl/DIGEST-MD5' 'sasl/GSSAPI'
208 ) # order is important
209
210 Man.addVar CRED_LEVELS 'Indexed array of Strings. A list of currently supported client credential levels.'
211 typeset -a -r CRED_LEVELS=( 'anonymous' 'proxy' 'proxy anonymous' 'self' )
212
213 Man.addVar OID2ADEF 'Associative array of Strings. Key: OID, Value: attribute definition. Used to cache attribute definitions of schemas currently installed on the DS. Gets lazy initialized, i.e. populated when needed.'
214 typeset -A OID2ADEF=( )
215 Man.addVar ANAME2OID 'Associative array of Strings. Key: attribute name (lowercase), Value: OID. Used to cache name to OID mappings. Gets initialized, when \bOID2ADEF\b gets populated.'
216 typeset -A ANAME2OID=( )
217
218 Man.addVar OID2ODEF 'Associative array of Strings. Key: OID, Value: objectclass definition. Used to cache objectclass definitions of schemas currently installed on the DS. Gets lazy initialized, i.e. populated when needed.'
219 typeset -A OID2ODEF=( )
220
221 Man.addFunc checkBinary '' '[+NAME?checkBinary - lookup a command.]
222 [+DESCRIPTION?Check the standard path, whether it contains \acmd\a and if not, use \aPATH\a to lookup the command. If found the full path of the command gets printed to stdout, otherwise an error message to stderr.]
223 [+RETURN VALUES]{
224 [+0?\acmd\a found.]
225 [+1?\acmd\a not found.]
226 }
227 [+SEE ALSO?\bwhence\b(1).]
228 \n\n\acmd\a
229 '
230 function checkBinary {
231 typeset CMD=$1 X=''
232 for DIR in /usr/bin /usr/sbin ; do
233 [[ -x ${DIR}/${CMD} ]] && print ${DIR}/${CMD} && return 0
234 done
235 X=${ whence -fp ${CMD} ; }
236 [[ -n $X ]] && print "${X}" && return 0
237 X="${.sh.file%/*}/${CMD}"
238 [[ -x ${X} ]] && print "$X" && return 0
239 print -u2 "Missing command '${CMD}'."
240 return 1
241 }
242
243 Man.addFunc init '' '[+NAME?init - initializes variables and options.]
244 [+DESCRIPTION?Does some basic binary-avail checks and initializes certain values of \bSTR[]]\b, \bINT[]]\b and \bTMP[]]\b.]
245 '
246 function init {
247 typeset X='' KEY VAL TAIL
248 integer ERR=0
249
250 # General commands
251 HOST=${ hostname ; }
252 PING=${ checkBinary ping || (( ERR++ )) ; }
253 STTY=${ checkBinary stty || (( ERR++ )) ; }
254 GETENT=${ checkBinary getent || (( ERR++ )) ; }
255
256 # LDAP COMMANDS
257 LDAPSEARCH=${ checkBinary ldapsearch || (( ERR++ )) ; }
258 LDAPMODIFY=${ checkBinary ldapmodify || (( ERR++ )) ; }
259 LDAPDELETE=${ checkBinary ldapdelete || (( ERR++ )) ; }
260 LDAPCLIENT=${ checkBinary ldapclient || (( ERR++ )) ; }
261
262 if (( ERR )); then
263 Log.fatal 'Please adjust your PATH and try again'
264 return 66
265 fi
266 LDAPSEARCH+=' -r'
267
268 # If DNS domain (resolv.conf) exists use that, otherwise use domainname.
269 if [[ -f /etc/resolv.conf ]]; then
270 while read KEY VAL TAIL ; do
271 if [[ ${KEY} == 'domain' || ${KEY} == 'search' ]]; then
272 X=${VAL}
273 break;
274 fi
275 done < /etc/resolv.conf
276 fi
277
278 # If for any reason the DOMAIN did not get set (error'd resolv.conf) set
279 # X to the domainname or getent command's output.
280 [[ -z $X ]] && X=${ domainname ; }
281 if [[ -z $X ]]; then
282 typeset -a AX=( ${ ${GETENT} hosts ${HOST} 2>/dev/null ; } )
283 integer I
284 for (( I=${#AX[@]}-1; I > 0; I++ )); do
285 X=${AX[$I]#*.}
286 [[ -n $X ]] && break
287 done
288 fi
289
290 # Actually one needs to init non-null/zero values, only. However, we want
291 # to have the keys registered ...
292
293 # idsconfig specific variables.
294 INT[LDAP_ENABLE_SHADOW_UPDATE]=0
295 INT[NEED_PROXY]=0 # 0 = No Proxy, 1 = Create Proxy.
296 INT[NEED_ADMIN]=0 # 0 = No Admin, 1 = Create Admin.
297 INT[NEED_HOSTACL]=0 # 0 = No Host ACL, 1 = Create Host ACL.
298 INT[EXISTING_PROFILE]=0
299 (( INT[TASK_TIMEOUT] < 10 )) && INT[TASK_TIMEOUT]=60
300 STR[LDAP_PROXYAGENT]=''
301 STR[LDAP_PROXYAGENT_CRED]=''
302 STR[LDAP_ADMINDN]=''
303 STR[LDAP_ADMIN_CRED]='' # enableShadowUpdate flag and Admin credential
304 STR[DS_DB]='' # storage backend name
305 STR[LDAP_SUFFIX]='' # suffix within the backend
306 STR[LDAP_DOMAIN]=${X%%.} # domainname on Server (default value)
307
308 # DS specific information
309 STR[DS_HOST]=''
310 INT[DS_PORT]=389
311 INT[NEED_TIME]=0
312 INT[NEED_SIZE]=0
313 INT[DS_TIMELIMIT]=0
314 INT[DS_SIZELIMIT]=0
315
316 # LDAP PROFILE related defaults
317 STR[LDAP_ROOTDN]='cn=Directory Manager' # Provide common default.
318 STR[LDAP_ROOTPWD]='' # NULL passwd (is invalid)
319 STR[LDAP_PROFILE_NAME]='default'
320 STR[LDAP_BASEDN]=''
321 STR[LDAP_SERVER_LIST]=''
322 STR[LDAP_AUTHMETHOD]=''
323 INT[LDAP_FOLLOWREF]=0
324 INT[NEED_CRYPT]=0
325 INT[NEED_SRVAUTH_PAM]=0
326 INT[NEED_SRVAUTH_KEY]=0
327 INT[NEED_SRVAUTH_CMD]=0
328 (( ! INT[NEED_CRYPT_IMPORT] )) && INT[NEED_CRYPT_IMPORT]=0
329 STR[LDAP_SEARCH_SCOPE]='one'
330 STR[LDAP_SRV_AUTHMETHOD_PAM]=''
331 STR[LDAP_SRV_AUTHMETHOD_KEY]=''
332 STR[LDAP_SRV_AUTHMETHOD_CMD]=''
333 INT[LDAP_SEARCH_TIME_LIMIT]=30
334 STR[LDAP_PREF_SRVLIST]=''
335 INT[LDAP_PROFILE_TTL]=43200
336 STR[LDAP_CRED_LEVEL]='proxy'
337 INT[LDAP_BIND_LIMIT]=10
338
339 # Service Search Descriptors (just make sure it is empty)
340 SSD=( ); unset SSD[0] # unset is required!
341
342 # GSSAPI setup
343 INT[GSSAPI_ENABLE]=0
344 STR[LDAP_KRB_REALM]=''
345
346 # temp settings
347 TMPF[STEP]=0 # internal file counter - see nextFile()
348 TMPF[IS_OPENDJ]=0 # set if detected DS is OpenDS/OpenDJ
349 TMPF[DEL_OLD_PROFILE]=0 # 0 = don't, 1 = delete old profile
350 TMPF[STEP]=1 # simple progress indicator
351 TMPF[GSSAPI_AUTH_MAY_BE_USED]=0 # DS GSSAPI SASL support
352 TMPF[NEED_CREATE_SUFFIX]=0 # see add_suffix()
353 TMPF[NEED_CREATE_BACKEND]=0 # see add_suffix()
354 # schema completion syntax to use:
355 # 0 .. detect, 1 .. force OpenDJ, 2 .. force DSEE
356 (( TMPF[SYNTAX] < 0 || TMPF[SYNTAX] > 2 )) && TMPF[SYNTAX]=0
357
358 TMP[FILE]='' # tmp output filename - see nextFile()
359 TMP[LDAP_ROOTPWF]=${TMP[DIR]}/rootPWD # filename containing the root PW
360 TMP[WARN]='' # set if possibly incompatible DS
361 TMP[SUFFIX_OBJ]='' # suffix objectclass (long name)
362 TMP[SUFFIX_ATT]='' # suffix RDN attr name
363 TMP[SUFFIX_VAL]='' # suffix RDN attr value
364 TMP[DS_DBS_AVAIL]='' # next available suffix DBs
365 TMP[VLV_CMDS]='' # where VLV commands to exec are stored
366 # Set via getopts - just make sure, they are registered
367 [[ -z ${TMP[IN]} ]] && TMP[IN]='' # the config file to read
368 [[ -z ${TMP[OUT]} ]] && TMP[OUT]='' # the config file to write
369 # redirect ldap output to file instead of stdout
370 if (( TMPF[FD] > 2 )); then
371 exec 4>${TMP[DIR]}/ldap.out
372 fi
373 return 0
374 }
375
376 # internal
377 function showProgress {
378 typeset NUM=${ printf "%3d" TMPF[STEP] ; }
379 Log.info "${NUM}. " "$*"
380 (( TMPF[STEP]++ ))
381 }
382
383 # internal
384 function nextFile {
385 typeset CMD="$1" FN="${2// /_}" EXT='cmd'
386 (( TMPF[STEP]++ ))
387 case "$1" in
388 add|modify|delete) CMD="ldap$1" EXT='ldif' ;;
389 sh) EXT='sh'
390 esac
391 TMP[FILE]=${ printf "${TMP[DIR]}/%03d_${CMD}_${FN}.${EXT}" ${TMPF[STEP]} ; }
392 [[ -e ${TMP[FILE]} ]] && Log.warn "Overwriting ${TMP[FILE]} ..."
393 }
394
395 Man.addFunc show_vars '' '[+NAME?show_vars - List of all config variables and their values.]
396 [+DESCRIPTION?Lists all config variables and their current values in a more or less human readable manner.]
397 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage INT STR SSD ; }" '}
398 '
399 function show_vars {
400 (( ! VERBOSE )) && return
401
402 typeset S=${!STR[@]} OUT='Current non-NULL values:\n'
403 S=${ print ${S// /$'\n'} | sort ; }
404 for KEY in $S ; do
405 [[ -n ${STR[$KEY]} ]] && \
406 OUT+=${ printf "%32s = '%s'" ${KEY} "${STR[$KEY]}" ; }'\n'
407 done
408 S=${!INT[@]}
409 S=${ print ${S// /$'\n'} | sort ; }
410 for KEY in $S ; do
411 (( INT[$KEY] )) && \
412 OUT+=${ printf "%32s = %d" ${KEY} "${INT[$KEY]}" ; }'\n'
413 done
414 if (( ${#SSD[@]} )); then
415 OUT+=${ printf "%32s = (" 'SSD' ; }
416 for S in "${SSD[@]}" ; do
417 OUT+="\t\t${S}\n"
418 done
419 OUT+='\t)\n'
420 fi
421 print -u2 "${OUT}"
422 }
423
424 Man.addFunc save_password '' '[+NAME?save_password - Save password to temporary file.]
425 [+DESCRIPTION?Save the current password from \bSTR[LDAP_ROOTPWD]]\b to the file \bTMP[LDAP_ROOTPWF]]\b.]
426 '
427 function save_password {
428 print "${STR[LDAP_ROOTPWD]}" >"${TMP[LDAP_ROOTPWF]}"
429 }
430 #############################################################################
431 # EOG
432 #############################################################################
433
434
435 #############################################################################
436 # config file stuff
437 #############################################################################
438 Man.addFunc create_config_file '' '[+NAME?create_config_file - Write config data to the specified file.]
439 [+DESCRIPTION?Write config data to \afile\a.]
440 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage INT STR SSD ; }" '}
441 [+RETURN VALUES]{
442 [+0?file was written successfully.]
443 [+>= 1?otherwise.]
444 }
445 [+SEE ALSO?\bload_config_file()\b.]
446 \n\n\afile\a
447 '
448 function create_config_file {
449 typeset OUT="$1" KEY
450 [[ -z ${OUT} ]] && return 1
451
452 # Create output file.
453 (
454 print '
455 # '"${OUT}"' - This file contains configuration information for
456 # LDAP naming services. Use the '"${PROG}"' tool to load it.
457 #
458 # WARNING: This file was generated by '"${PROG}"', and is intended to
459 # be loaded by '"${PROG}"' as is. DO NOT EDIT THIS FILE!
460 '
461 print 'typeset -A -i IIN=( )'
462 for KEY in "${!INT[@]}" ; do
463 print "IIN[${KEY}]=${INT[${KEY}]}"
464 done
465 print '\ntypeset -A SIN=( )'
466 for KEY in "${!STR[@]}" ; do
467 printf "SIN[${KEY}]=%q\n" "${STR[${KEY}]}"
468 done
469 print '\ntypeset -a SIN_SSD=( )'
470 for KEY in "${SSD[@]}" ; do
471 [[ -n ${KEY} ]] && printf "SIN_SSD+=( %q )\n" "${KEY}"
472 done
473 print "\n# End of ${OUT}"
474 ) >"${OUT}"
475 }
476
477 # for backward compatibilty, but not documented: old format is bogus and should
478 # not be used anymore.
479 function source_old_config {
480 typeset IN="$1" TODO='' VNAME KEY VAL LINE
481 typeset -A OLDMAP=(
482 [DS_HOST]=IDS_SERVER
483 [DS_PORT]=IDS_PORT
484 [DS_DB]=IDS_DATABASE
485 [DS_TIMELIMIT]=IDS_TIMELIMIT
486 [DS_SIZELIMIT]=IDS_SIZELIMIT
487 [SSD]=LDAP_SERV_SRCH_DES
488 )
489
490 for KEY in "${!INT[@]}" ; do
491 VNAME=${OLDMAP[${KEY}]}
492 [[ -z ${VNAME} ]] && VNAME=${KEY}
493 typeset -n VAR=${VNAME}
494 INT[${KEY}]=${VAR}
495 TODO+="${VNAME} "
496 done
497 for KEY in "${!STR[@]}" ; do
498 VNAME=${OLDMAP[${KEY}]}
499 [[ -z ${VNAME} ]] && VNAME=${KEY}
500 typeset -n VAR=${VNAME}
501 STR[${KEY}]="${VAR}"
502 TODO+="${VNAME} "
503 done
504 while read LINE; do
505 if [[ ${LINE:0:19} == 'LDAP_SERV_SRCH_DES=' ]]; then
506 VAL="${LINE:19}"
507 [[ -n ${VAL} ]] && SSD+=( "${VAL}" )
508 fi
509 done < "${IN}"
510
511 # cleanup "global" namespace
512 [[ -n ${TODO} ]] && eval "unset ${TODO}"
513 }
514
515 Man.addFunc load_config_file '' '[+NAME?load_config_file - load an '"${PROG}"' config file.]
516 [+DESCRIPTION?Loads the initial config from \afile\a, which has been generated in a previous run by '"${PROG}"'. Sets \bTMPF[DEL_OLD_PROFILE]]\b to 1 on success.]
517 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage INT STR SSD ; }" '}
518 [+RETURN VALUES]{
519 [+0?on success.]
520 [+>= 66? \afile\a is not a file or unreadable.]
521 }
522 [+SEE ALSO?\bsave_password()\b, \bshow_vars()\b.]
523 \n\n\afile\a
524 '
525 function load_config_file {
526 typeset IN="$1" KEY VAL
527 integer I
528 [[ ! -f ${IN} ]] && Log.fatal "${IN} is not a file" && return 66
529 [[ ! -r ${IN} ]] && Log.fatal "${IN} is not readable" && return 67
530
531 # source in the stuff - not nice but less work ;-)
532 . "${IN}"
533
534 KEY=${ typeset -p IIN ; }
535 if [[ -z ${KEY} ]]; then
536 source_old_config "${IN}" || return 68
537 else
538 for KEY in "${!INT[@]}" ; do
539 INT[${KEY}]=${IIN[${KEY}]}
540 done
541 for KEY in "${!STR[@]}" ; do
542 STR[${KEY}]="${SIN[${KEY}]}"
543 done
544 for KEY in "${SIN_SSD[@]}" ; do
545 [[ -n ${KEY} ]] && SSD+=( "${KEY}" )
546 done
547 # cleanup "global" namespace
548 unset IIN SIN SIN_SSD
549 fi
550
551 TMPF[DEL_OLD_PROFILE]=1
552 save_password
553 show_vars
554
555 return 0
556 }
557 #############################################################################
558 # End Of config file stuff
559 #############################################################################
560
561
562 ############################################################################
563 # Basic [menu] stuff
564 ############################################################################
565 Man.addFunc display_msg '' '[+NAME?display_msg - display a message]
566 [+DESCRIPTION?Display a message corresponding to the \atag\a passed in.]
567 [+ENVIRONMENT VARIABLES]{'"${ Man.varUsage INT STR TMP ; }" '}
568 \n\n\atag\a
569 '
570 function display_msg {
571 typeset X
572 integer I
573
574 case "$1" in
575 backup_server)
576 print '
577 It is strongly recommended that you BACKUP the directory server
578 before running '"${PROG}"'.
579
580 Hit Ctrl-C at any time before the final confirmation to exit.\n'
581 ;;
582 cred_level_menu)
583 print 'The following are the supported credential levels:'
584 for (( I=0; I < ${#CRED_LEVELS[@]}; I++ )); do
585 printf ' %2d %s\n' $((I+1)) "${CRED_LEVELS[I]}"
586 done
587 ;;
588 auth_method_menu)
589 print 'The following are the supported Client Authentication Methods:'
590 for (( I=0; I < ${#AUTH_METHODS[@]}; I++ )); do
591 printf ' %-2d %s\n' $((I+1)) "${AUTH_METHODS[I]}"
592 done
593 ;;
594 srvauth_method_menu)
595 print 'The following are the supported Service Authentication Methods:'
596 # skip 'none'
597 for (( I=1; I < ${#AUTH_METHODS[@]}; I++ )); do
598 printf ' %-2d %s\n' $((I)) "${AUTH_METHODS[I]}"
599 done
600 ;;
601 prompt_ssd_menu)
602 print ' A Add a Service Search Descriptor (SSD)
603 D Delete a SSD
604 M Modify a SSD
605 P Display all SSDs
606 H Help
607 X Clear all SSDs
608
609 Q Exit menu'
610 ;;
611 summary_menu)
612 typeset SUFFIX_INFO=''
613 typeset DB_INFO=''
614
615 if (( TMPF[NEED_CREATE_SUFFIX] )); then
616 SUFFIX_INFO='
617 Suffix to create : '"${STR[LDAP_SUFFIX]}"'\n'
618 (( TMPF[NEED_CREATE_BACKEND] )) && DB_INFO='
619 Database to create : '"${STR[DS_DB]}"'\n'
620 fi
621 typeset BASEDN
622 BASEDN="${STR[LDAP_BASEDN]}${STR[SUFFIX_INFO]}${STR[DB_INFO]}"
623
624 print ' Summary of Configuration
625
626 1 Domain to serve : '"${STR[LDAP_DOMAIN]}"'
627 2 Base DN to setup : '"${BASEDN}"'
628 3 Profile name to create : '"${STR[LDAP_PROFILE_NAME]}"'
629 4 Default Server List : '"${STR[LDAP_SERVER_LIST]}"'
630 5 Preferred Server List : '"${STR[LDAP_PREF_SRVLIST]}"'
631 6 Default Search Scope : '"${STR[LDAP_SEARCH_SCOPE]}"'
632 7 Credential Level : '"${STR[LDAP_CRED_LEVEL]}"'
633 8 Authentication Method : '"${STR[LDAP_AUTHMETHOD]}"'
634 9 Enable Follow Referrals : '"${INT[LDAP_FOLLOWREF]}"'
635 10 DS Time Limit : '"${INT[DS_TIMELIMIT]}"'
636 11 DS Size Limit : '"${INT[DS_SIZELIMIT]}"'
637 12 Enable crypt password storage : '"${INT[NEED_CRYPT]}"'
638 13 Service Auth Method pam_ldap : '"${STR[LDAP_SRV_AUTHMETHOD_PAM]}"'
639 14 Service Auth Method keyserv : '"${STR[LDAP_SRV_AUTHMETHOD_KEY]}"'
640 15 Service Auth Method passwd-cmd: '"${STR[LDAP_SRV_AUTHMETHOD_CMD]}"'
641 16 Search Time Limit : '"${INT[LDAP_SEARCH_TIME_LIMIT]}"'
642 17 Profile Time to Live : '"${INT[LDAP_PROFILE_TTL]}"'
643 18 Bind Limit : '"${INT[LDAP_BIND_LIMIT]}"'
644 19 Enable shadow update : '"${INT[LDAP_ENABLE_SHADOW_UPDATE]}"'
645 20 Service Search Descriptors Menu\n'
646 ;;
647 sorry)
648 print '
649 HELP - No help is available for this topic.\n'
650 ;;
651 create_suffix_help)
652 print '
653 HELP - Our Base DN is "'"${STR[LDAP_BASEDN]}"'"
654 and we need to create a Directory Suffix,
655 which can be equal to Base DN itself or be any of Base DN parents.
656 All intermediate entries up to suffix will be created on demand.\n'
657 ;;
658 enter_ldbm_db_help)
659 print '
660 HELP - database backend is an internal database for storage of our suffix data.
661 Backend name must be alphanumeric due to Directory Server restriction.
662 '
663 ;;
664 backup_help)
665 print '
666 HELP - Since '"${PROG}"' modifies the directory server configuration,
667 it is strongly recommended that you backup the server prior
668 to running this utility. This is especially true if the server
669 being configured is a production server.\n'
670 ;;
671 port_help)
672 print '
673 HELP - Enter the port number the directory server is configured to
674 use for LDAP.\n'
675 ;;
676 adminport_help)
677 print '
678 HELP - Enter the Admin port number the directory server is configured to
679 use for for DS administration commands.\n'
680 ;;
681 domain_help)
682 print '
683 HELP - This is the DNS domain name this server will be serving. You
684 must provide this name even if the server is not going to be populated
685 with hostnames. Any unqualified hostname stored in the directory
686 will be fully qualified using this DNS domain name.\n'
687 ;;
688 basedn_help)
689 print '
690 HELP - This parameter defines the default location in the directory tree for
691 the naming services entries. You can override this default by using
692 Service Search Descriptors (SSD). You will be given the option to set up
693 an SSD later on in the setup.\n'
694 ;;
695 profile_help)
696 print '
697 HELP - Name of the configuration profile with which the clients will be
698 configured. A directory server can store various profiles for multiple
699 groups of clients. The initialization tool, (ldapclient(1M)), assumes
700 "default" unless another is specified.\n'
701 ;;
702 def_srvlist_help)
703 print '
704 HELP - Provide a list of directory servers to serve clients using this profile.
705 All these servers should contain consistent data and provide similar
706 functionality. This list is not ordered, and clients might change the
707 order given in this list. Note that this is a space separated list of
708 *IP addresses* (not host names). Providing port numbers is optional.\n'
709 ;;
710 pref_srvlist_help)
711 print '
712 HELP - Provide a list of directory servers to serve this client profile.
713 Unlike the default server list, which is not ordered, the preferred
714 servers must be entered IN THE ORDER you wish to have them contacted.
715 If you do specify a preferred server list, clients will always contact
716 them before attempting to contact any of the servers on the default
717 server list. Note that you must enter the preferred server list as a
718 space-separated list of *IP addresses* (not host names). Providing port
719 numbers is optional.\n'
720 ;;
721 srch_scope_help)
722 print '
723 HELP - Default search scope to be used for all searches unless they are
724 overwritten using serviceSearchDescriptors. The valid options
725 are "one", which would specify the search will only be performed
726 at the base DN for the given service, or "sub", which would specify
727 the search will be performed through *all* levels below the base DN
728 for the given service. If you use the default DIT layout, "one" should
729 be ok and probably a little bit faster.\n'
730 ;;
731 cred_lvl_help)
732 print '
733 HELP - This parameter defines what credentials (identity) the clients use to
734 authenticate (bind) to the directory server. This list might contain
735 multiple credential levels and is ordered. If a proxy level is
736 configured, you will also be prompted to enter a bind DN for the
737 proxy agent along with a password. This proxy agent will be created
738 if it does not exist. See also ldapclient(1M).\n'
739 ;;
740 auth_help)
741 print '
742 HELP - The default authentication (bind) method(s) to be used by all services
743 in the client using this profile. This is a ordered list of
744 authentication methods separated by a ";". The supported methods are
745 provided in a menu. Note that sasl/DIGEST-MD5 binds require passwords
746 to be stored un-encrypted on the server. See also ldapclient(1M).\n'
747 ;;
748 srvauth_help)
749 print '
750 HELP - The non-default authentication (bind) methods to be used by certain
751 services (for now pam_ldap, keyserv, and passwd-cmd are supported).
752 The authentication methods specified in this attribute overrides
753 the default authentication method defined in the profile. This
754 feature can be used to select stronger authentication methods for
755 services which require increased security.\n'
756 ;;
757 pam_ldap_help)
758 print '
759 HELP - The authentication (bind) method(s) to be used by pam_ldap when
760 contacting the directory server. This is a ordered list, and, if
761 provided, will override the default authentication method parameter.\n'
762 ;;
763 keyserv_help)
764 print '
765 HELP - The authentication (bind) method(s) to be used by newkey(1M) and chkey(1)
766 when contacting the directory server. This is a ordered list and if
767 provided will override the default authentication method parameter.\n'
768 ;;
769 passwd-cmd_help)
770 print '
771 HELP - The authentication (bind) method(s) to be used by passwd(1) command when
772 contacting the directory server. This is a ordered list and if
773 provided will override the default authentication method parameter.\n'
774 ;;
775 referrals_help)
776 print '
777 HELP - This parameter indicates whether the client should follow
778 ldap referrals if it encounters one during naming lookups.\n'
779 ;;
780 tlim_help)
781 print '
782 HELP - The server time limit value indicates the maximum amount of time the
783 server would spend on a query from the client before abandoning it.
784 A value of "-1" indicates no limit.\n'
785 ;;
786 slim_help)
787 print '
788 HELP - The server sizelimit value indicates the maximum number of entries
789 the server would return in respond to a query from the client. A
790 value of "-1" indicates no limit.\n'
791 ;;
792 crypt_help)
793 print '
794 HELP - By default a DS does not store userPassword attribute values using
795 unix "crypt" formats (like bsdmd5, sunmd5, sha256, sha512, old crypt,
796 etc. - see crypt.conf(4)). If you need to keep your passwords in the
797 crypt formats for backward or pam_unix compatibility, choose "yes".
798 If any other password storage scheme than crypt is used, pam_ldap
799 MUST be used by clients to authenticate users to the system. Note
800 that if you wish to use sasl/*-MD5 in conjunction with pam_ldap,
801 user passwords are/must be stored in the clear text.\n'
802 ;;
803 srchtime_help)
804 print '
805 HELP - The search time limit the client will enforce for directory lookups.\n'
806 ;;
807 profttl_help)
808 print '
809 HELP - The time to live value for profile. The client will refresh its
810 cached version of the configuration profile at this TTL interval.\n'
811 ;;
812 bindlim_help)
813 print '
814 HELP - The time limit for the bind operation to the directory. This
815 value controls the responsiveness of the client in case a server
816 becomes unavailable. The smallest timeout value for a given
817 network architecture/conditions would work best. This is very
818 similar to setting TCP timeout, but only for LDAP bind operation.\n'
819 ;;
820 ssd_help)
821 print '
822 HELP - Using Service Search Descriptors (SSD), you can override the
823 default configuration for a given service. The SSD can be
824 used to override the default search base DN, the default search
825 scope, and the default search filter to be used for directory
826 lookups. SSD are supported for all services (databases)
827 defined in nsswitch.conf(4). See also ldapclient(1M).
828
829 Note: SSD are powerful tools in defining configuration profiles
830 and provide a great deal of flexibility. However, care
831 must be taken in creating them. If you decide to make use
832 of SSDs, consult the documentation first.\n'
833 ;;
834 ssd_menu_help)
835 print '
836 HELP - Using this menu SSD can be added, updated, or deleted from
837 the profile.
838
839 A - This option creates a new SSD by prompting for the
840 service name, base DN, and scope. Service name is
841 any valid service as defined in ldap(1). base is
842 either the distinguished name to the container where
843 this service will use, or a relative DN followed
844 by a ",". For more information see ldapclient(1M).
845 D - Delete a previously created SSD.
846 M - Modify a previously created SSD.
847 P - Display a list of all the previously created SSD.
848 X - Delete all of the previously created SSD.
849
850 Q - Exit the menu and continue with the server configuration.\n'
851 ;;
852 enable_shadow_update_help)
853 print '
854 HELP - Enter "y" to set up the LDAP server for shadow update.
855 The setup will add an administrator identity/credential
856 and modify the necessary access controls for the client
857 to update shadow(4), auth_attr(4), exec_attr(4), prof_attr(4),
858 user_attr(4), and project(4) data on the LDAP server. If
859 sasl/GSSAPI is in use, the Kerberos host principal will be used
860 as the administrator identity.
861
862 Shadow data is used for password aging and account locking.
863 Please refer to the shadow(4) manual page for details.\n'
864 ;;
865 add_admin_cred_help)
866 print '
867 HELP - Start the setup to add an administrator identity/credential
868 and to modify access controls for the client to update
869 shadow(4), auth_attr(4), exec_attr(4), prof_attr(4),
870 user_attr(4), and project(4) data on the LDAP server.
871
872 Shadow data is used for password aging and account locking.
873 Please refer to the shadow(4) manual page for details.\n'
874 ;;
875 use_host_principal_help)
876 print '
877 HELP - A profile with a "sasl/GSSAPI" authentication method and a "self"
878 credential level is detected, enter "y" to modify the necessary
879 access controls for allowing the client to update shadow(4) data
880 on the LDAP server.
881
882 Shadow data is used for password aging and account locking.
883 Please refer to the shadow(4) manual page for details.\n'
884 ;;
885 esac
886 }
887
888 Man.addVar ANS 'Variable used to return the user input.'
889 Man.addFunc get_ans '' '[+NAME?get_ans - gets an answer from the user.]
890 [+DESCRIPTION?Read a string from stdin. Arguments:]{
891 [+prompt?instruction/comment/description/question to show.]
892 [+default?Default value to use if no answer/empty string was read.]
893 }
894 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage ANS ; }" '}
895 \n\n\aprompt\a [\adefault\a]
896 '
897 function get_ans {
898 typeset PROMPT="$1 "
899 [[ -n $2 ]] && PROMPT+="[$2] "
900
901 read ANS?"${PROMPT}"
902 [[ -z ${ANS} ]] && ANS="$2"
903 }
904
905
906 Man.addFunc get_ans_req '' '[+NAME?get_ans_req - get a non-empty answer from the user.]
907 [+DESCRIPTION?Read a string from stdin. Does not return until the string is a non-empty string or a \adefault\a value is given. Arguments:]{
908 [+prompt?instruction/comment/description/question to show.]
909 [+default?Default value to use if no answer/empty string was read.]
910 }
911 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage ANS ; }" '}
912 [+SEE ALSO?\bget_ans()\b]
913 \n\n\aprompt\a [\adefault\a]
914 '
915 function get_ans_req {
916 ANS=''
917 while [[ -z ${ANS} ]]; do
918 get_ans "$@"
919 [[ -z ${ANS} ]] && Log.warn 'NULL value not allowed'
920 done
921 }
922
923 Man.addFunc is_numeric '' '[+NAME?is_numeric - check whether arg is a numeric string]
924 [+DESCRIPTION?Check whether the given \astring\a is a numeric string.]
925 [+RETURN VALUES]{
926 [+0?If the string is a numeric string.]
927 [+1?Otherwise.]
928 }
929 [+SEE ALSO?\bnot_numeric()\b]
930 \n\n\astring\a
931 '
932 function is_numeric {
933 (( $# != 1 )) && return 1
934 [[ $1 =~ ^[0-9]+$ ]] && return 0 || return 1
935 }
936
937 Man.addFunc not_numeric '' '[+NAME?not_numeric - check whether arg is NOT a numeric string]
938 [+DESCRIPTION?Check whether the given \astring\a is NOT a numeric string. Useful for if and while statements that want to test for non-numeric data.]
939 [+RETURN VALUES]{
940 [+0?If the string is NOT a numeric string.]
941 [+1?Otherwise.]
942 }
943 [+SEE ALSO?\bis_numeric()\b]
944 \n\n\astring\a
945 '
946 function not_numeric {
947 is_numeric $1 && return 1 || return 0
948 }
949
950 Man.addVar NUM 'Variable used to return the user input as a number.'
951 integer NUM
952 Man.addFunc get_number '' '[+NAME?get_number - get a number from the user.]
953 [+DESCRIPTION?Read a string from stdin until it represents a number. Arguments:]
954 {
955 [+prompt?instruction/comment/description/question to show.]
956 [+default?Default value to use if no answer/empty string was read.]
957 [+helpTag?Tag of the help message to show, when the string read is h|H|?|help|Help.]
958 }
959 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage NUM ANS ; }" '}
960 [+SEE ALSO?\bget_ans()\b, \bis_numeric()\b, \bdisplay_msg()\b]
961 \n\n\aprompt\a \adefault\a [\ahelpTag\a]
962 '
963 function get_number {
964 ANS=''
965
966 get_ans "$1" "$2"
967
968 while not_numeric $ANS ; do
969 case "${ANS}" in
970 [Hh?] | help | Help) display_msg ${3:-sorry} ;;
971 * ) Log.warn "Invalid value: '${ANS}'" ;;
972 esac
973 get_ans 'Enter a numeric value:' "$2"
974 done
975 NUM=${ANS}
976 }
977
978
979 Man.addFunc get_negone_num '' '[+NAME?get_negone_num - get a number >= -1 from the user.]
980 [+DESCRIPTION?Read a string from stdin until it represents a number >= -1. Arguments:]
981 {
982 [+prompt?instruction/comment/description/question to show.]
983 [+default?Default value to use if no answer/empty string was read.]
984 [+helpTag?Tag of the help message to show, when the string read is h|H|?|help|Help.]
985 }
986 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage NUM ANS ; }" '}
987 [+SEE ALSO?\bget_number()\b]
988 \n\n\aprompt\a \adefault\a [\ahelpTag\a]
989 '
990 function get_negone_num {
991 while : ; do
992 get_number "$1" "$2" "$3"
993 (( NUM >= -1 )) && break
994 Log.warn 'Invalid number! Enter a number >= -1'
995 done
996 }
997
998 Man.addFunc get_passwd '' '[+NAME?get_passwd - get a password from the user.]
999 [+DESCRIPTION?Read a password from stdin and verify with second until both match. Password gets not echoed to stdout. Arguments:]
1000 {
1001 [+prompt?instruction/comment/description/question to show.]
1002 [+default?Default value to use if no answer/empty string was read.]
1003 }
1004 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage ANS ; }" '}
1005 [+SEE ALSO?\bget_ans()\b]
1006 \n\n\aprompt\a [\adefault\a]
1007 '
1008 function get_passwd {
1009 typeset _PASS1='' _PASS2=''
1010
1011 ${STTY} -echo # Turn echo OFF
1012
1013 # continue until passwd and re-entered passwd match
1014 while : ; do
1015 ANS=''
1016 # Don't allow NULL for first try.
1017 while [[ -z ${ANS} ]]; do
1018 get_ans "$@"
1019 [[ -z ${ANS} ]] && \
1020 print -u2 && Log.warn 'Empty password not allowed'
1021 done
1022 _PASS1="${ANS}" # Store first try.
1023
1024 print
1025 get_ans 'Re-enter password:'
1026 _PASS2="${ANS}"
1027
1028 [[ ${_PASS1} == ${_PASS2} ]] && break
1029 print -u2 && Log.warn "passwords don't match - try again"
1030 done
1031
1032 ${STTY} echo # Turn echo ON
1033
1034 print
1035 }
1036
1037 Man.addFunc get_passwd_nochk '' '[+NAME?get_passwd_nochk - get a password from the user w/o check.]
1038 [+DESCRIPTION?Read a password from stdin. Actually the same as \bget_ans()\b but echoing characters read to stdout is switched off. Arguments:]
1039 {
1040 [+prompt?instruction/comment/description/question to show.]
1041 [+default?Default value to use if no answer/empty string was read.]
1042 }
1043 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage ANS ; }" '}
1044 [+SEE ALSO?\bget_ans()\b]
1045 \n\n\aprompt\a [\adefault\a]
1046 '
1047 function get_passwd_nochk {
1048 ${STTY} -echo # Turn echo OFF
1049 get_ans "$@"
1050 ${STTY} echo # Turn echo ON
1051 print
1052 }
1053
1054 Man.addFunc get_menu_choice '' '[+NAME?get_menu_choice - get a valid menu choice number.]
1055 [+DESCRIPTION?Get a menu choice from user. Continue prompting until the choice is in required range. Arguments:]
1056 {
1057 [+prompt?Message text.]
1058 [+min?Min value.]
1059 [+max?Max value.]
1060 [+default?Default value to use if no answer/empty string was read.]
1061 [+helpTag?If given, "h" is allowed as well and the help message for this tag gets shown, when it got typed and before the prompt is shown the first time. The prompt should contain a hint in this case.]
1062 [+menuTag?If given the menu choices for the given menu gest displayed at start and after each help text.]
1063 }
1064 [+RETURN VALUES]{
1065 [+-1?on error (invalid parameters).]
1066 [+>= \amin\a?the selected value.]
1067 }
1068 [+SEE ALSO?\bis_numeric()\b, \bget_ans()\b, \bdisplay_msg()\b.]
1069 \n\n\aprompt\a \amin\a \amax\a [\adefault\a [\ahelpTag\a]]
1070 '
1071 function get_menu_choice {
1072 if (( $# < 3 )); then
1073 Log.warn "${.sh.fun}(): Did not get required parameters"
1074 return -1
1075 fi
1076
1077 [[ -n $6 ]] && display_msg "$6"
1078 while : ; do
1079 get_ans "$1" "$4"
1080 if is_numeric ${ANS} && NUM=${ANS} && (( NUM >= $2 )) && (( NUM <= $3 ))
1081 then
1082 return ${NUM}
1083 fi
1084 if [[ -n $5 && ${ANS} == 'h' ]]; then
1085 display_msg "$5"
1086 [[ -n $6 ]] && display_msg "$6"
1087 continue
1088 fi
1089 Log.warn "Invalid choice! Enter a number in the range $2 .. $3"
1090 done
1091 return -1
1092 }
1093
1094 Man.addFunc get_confirm '' '[+NAME?get_confirm - Get confirmation from the user.]
1095 [+DESCRIPTION?Read a string from stdin until it matches Y|y|Yes|yes|YES|N|n|No|no|NO or an empty string. Arguments:]
1096 {
1097 [+prompt?instruction/comment/description/question to show.]
1098 [+default?Default value to use if no answer/empty string was read.]
1099 [+helpTag?Tag of the help message to show, when the string read is h|H|?|help|Help.]
1100 }
1101 [+RETURN VALUES]{
1102 [+0?for NO]
1103 [+1?for YES]
1104 }
1105 [+SEE ALSO?\bdisplay_msg()\b]
1106 \n\n\aprompt\a \adefault\a [\ahelpTag\a]
1107 '
1108 function get_confirm {
1109 typeset _ANSWER=''
1110
1111 if [[ -z $2 ]]; then
1112 Log.fatal "INTERNAL ERROR: ${.sh.fun} requires 2 args, 3rd is optional"
1113 exit 2
1114 fi
1115
1116 while : ; do
1117 read _ANSWER?"$1 [$2] "
1118 [[ -z ${_ANSWER} ]] && _ANSWER="$2"
1119
1120 case "${_ANSWER}" in
1121 [Yy] | yes | Yes | YES) return 1 ;;
1122 [Nn] | no | No | NO) return 0 ;;
1123 [Hh?] | help | Help) display_msg ${3:-sorry} ;;
1124 * ) Log.warn 'Please enter y or n' ;;
1125 esac
1126 done
1127 }
1128
1129 Man.addFunc get_confirm_nodef '' '[+NAME?get_confirm_nodef - Get confirmation from the user.]
1130 [+DESCRIPTION?Read a string from stdin until it matches Y|y|Yes|yes|YES|N|n|No|no|NO. No default value and help tag supported. Arguments:]
1131 {
1132 [+prompt?instruction/comment/description/question to show.]
1133 }
1134 [+RETURN VALUES]{
1135 [+0?for NO]
1136 [+1?for YES]
1137 }
1138 \n\n[\aprompt\a]...
1139 '
1140 function get_confirm_nodef {
1141 typeset _ANSWER=''
1142
1143 while : ; do
1144 read _ANSWER?"$@ "
1145 case "${_ANSWER}" in
1146 [Yy] | yes | Yes | YES) return 1 ;;
1147 [Nn] | no | No | NO) return 0 ;;
1148 * ) Log.warn 'Please enter y or n' ;;
1149 esac
1150 done
1151 }
1152 ############################################################################
1153 # End of basic [menu] stuff
1154 ############################################################################
1155
1156
1157 ######################################################################
1158 # FUNCTIONS FOR prompt_config_info() START HERE.
1159 ######################################################################
1160 Man.addFunc get_ids_server '' '[+NAME?get_ids_server - Prompt for DS server name.]
1161 [+DESCRIPTION?Ask the user for the DS hostname, store it into \bSTR[DS_HOST]]\b and adjusts \bCON_ARGS\b.]
1162 [+ENVIRONMENT VARIABLES]{'"${ Man.varUsage CON_ARGS ; }"'}
1163 [+SEE ALSO?\bget_ans()\b, \bget_ids_port()\b, \bping\b(1M).]
1164 '
1165 function get_ids_server {
1166 typeset SRV="${STR[DS_HOST]}"
1167 typeset OS=${ uname -s ; }
1168
1169 while : ; do
1170 get_ans "Enter the Directory Server's hostname to setup:" \
1171 "${STR[DS_HOST]}"
1172 SRV="${ANS}"
1173
1174 # Ping server to see if alive. If reachable break out of loop
1175 if [[ ${OS} == 'SunOS' ]]; then
1176 ${PING} "${SRV}" 3 >/dev/null 2>&1 && break
1177 else
1178 # assume Linux
1179 ${PING} -W 3 "${SRV}" >/dev/null 2>&1 && break
1180 fi
1181 Log.warn "Server '${SRV}' is invalid or unreachable"
1182 done
1183 STR[DS_HOST]="${SRV}"
1184
1185 # Set CON_ARGS since values might have changed
1186 CON_ARGS="-h ${SRV} -p ${INT[DS_PORT]}"
1187 }
1188
1189 Man.addFunc get_ids_port '' '[+NAME?get_ids_port - Prompt for DS port number.]
1190 [+DESCRIPTION?Ask the user for the DS port number and host, store it into \bINT[DS_PORT]]\b, \bSTR[DS_HOST]]\b and adjust \bCON_ARGS\b.]
1191 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage CON_ARGS ; }" '}
1192 [+SEE ALSO?\bget_number()\b, \bget_ids_server()\b, \bldapsearch\b(1).]
1193 \n\n\aarg\a'
1194 function get_ids_port {
1195 typeset ASK='Enter the port number for the directory server (h=help):'
1196 typeset HELP='port_help' KEY='DS_PORT'
1197
1198 integer PORT
1199 while : ; do
1200 # Enter port number
1201 get_number "${ASK}" ${INT[${KEY}]} "${HELP}"
1202 PORT=${ANS}
1203 # Do a simple search to check hostname and LDAP port number
1204 if [[ -z $1 ]]; then
1205 if ${LDAPSEARCH} -h ${STR[DS_HOST]} -p ${PORT} -b '' \
1206 -s base 'objectclass=*' > /dev/null 2>&1
1207 then
1208 break
1209 fi
1210 Log.warn "Invalid host or port '${STR[DS_HOST]}:${PORT}'"
1211 get_ids_server
1212 else
1213 break
1214 fi
1215 done
1216 INT[${KEY}]=${PORT}
1217 [[ -n $1 ]] && return
1218
1219 # Set CON_ARGS since values might have changed
1220 CON_ARGS="-h ${STR[DS_HOST]} -p ${PORT}"
1221 }
1222
1223 Man.addFunc chk_ids_version '' '[+NAME?chk_ids_version - Read the DS version info.]
1224 [+DESCRIPTION?Query the DS for version info and store it into \bTMP[DS_INFO]]\b as "ProductName MajorVersionNum MinorVersionNum". If the DS is OpenDS or OpenDJ \bTMPF[IS_OPENDJ]]\b gets set to 1, 0 otherwise. If the DS seems to be unsupported by this script, an appropriate message gets stored into \bTMP[WARN]]\b.]
1225 [+RETURN VALUES]{
1226 [+0?on success.]
1227 [+>= 66?on fatal error (got no info).]
1228 }
1229 [+SEE ALSO?\bldapsearch\b(1).]
1230 '
1231 function chk_ids_version {
1232 typeset PROD='' X LINE
1233 typeset -a SPLIT=( )
1234 integer MAJOR=0 MINOR=0
1235 ${LDAPSEARCH} ${CON_ARGS} -b cn=monitor -s base 'objectclass=*' \
1236 2>/dev/null | \
1237 while read LINE ; do
1238 if [[ ${LINE:0:14} == 'vendorVersion=' ]]; then
1239 # OpenD*
1240 X=${LINE:14}
1241 X=${X//Directory Server } # usually <= 2.3.x
1242 PROD=${X%% *}
1243 SPLIT=( ${.sh.match//./ } )
1244 MAJOR=${SPLIT[0]}
1245 MINOR=${SPLIT[1]}
1246 break
1247 elif [[ ${LINE:0:8} == 'version=' ]]; then
1248 # *DSEE
1249 X=${LINE:8}
1250 PROD=${X%%/*}
1251 X=${.sh.match#/}
1252 SPLIT=( ${X//./ } )
1253 MAJOR=${SPLIT[0]}
1254 MINOR=${SPLIT[1]}
1255 break
1256 fi
1257 done
1258 if [[ -z ${PROD} ]] || (( MAJOR == 0 )); then
1259 Log.fatal 'Can not determine the version number of the DS'
1260 return 66
1261 fi
1262
1263 TMP[DS_INFO]="${PROD} ${MAJOR} ${MINOR}"
1264
1265 # for easier maintainance we don't put it into a single expr
1266 X=''
1267 if [[ ${PROD} == 'OpenDS' || ${PROD} == 'OpenDJ' ]]; then
1268 TMPF[IS_OPENDJ]=1
1269 (( MAJOR < 2 )) && X='1'
1270 elif (( MAJOR < 5 || (7 < MAJOR && MAJOR < 11) )); then
1271 # not a supported DSEE version
1272 TMPF[IS_OPENDJ]=0
1273 X='1'
1274 fi
1275 if [[ -n ${X} ]]; then
1276 TMP[WARN]="$PROG only works with DSEE version 5.x, 6.x, 7.x, "
1277 TMP[WARN]+='ODSEE 11g and OpenDS/OpenDJ 2.x'
1278 Log.warn "${TMP[WARN]}"
1279 fi
1280 Log.printMarker
1281 Log.info "Detected DS: ${PROD} ${MAJOR}.${MINOR}"
1282 Log.printMarker
1283 return 0
1284 }
1285
1286 Man.addFunc get_dirmgr_dn '' '[+NAME?get_dirmgr_dn - get the directory manger DN.]
1287 [+DESCRIPTION?Ask the user for the directory manger DN and store it into \bSTR[LDAP_ROOTDN]]\b and adjust \bAUTH_ARGS\b.]
1288 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage AUTH_ARGS ; }" '}
1289 [+SEE ALSO?\bget_ans()\b.]
1290 '
1291 function get_dirmgr_dn {
1292 get_ans 'Enter the directory manager DN:' "${STR[LDAP_ROOTDN]}"
1293 STR[LDAP_ROOTDN]="${ANS}"
1294 AUTH_ARGS=( '-D' "${STR[LDAP_ROOTDN]}" '-j' "${TMP[LDAP_ROOTPWF]}" )
1295 }
1296
1297 Man.addFunc get_dirmgr_pw '' '[+NAME?get_dirmgr_pw - get the Root DN password.]
1298 [+DESCRIPTION?Ask the user for the Root DN (\bSTR[LDAP_ROOTDN]]\b), store it into \bSTR[LDAP_ROOTPWD]]\b as well as a temp file for later use. Finally adjust \bAUTH_ARGS\b and check, whether the changes work.]
1299 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage AUTH_ARGS ; }" '}
1300 [+SEE ALSO?\bget_passwd_nochk()\b, \bsave_password()\b, \bldapsearch\b(1).]
1301 '
1302 function get_dirmgr_pw {
1303 typeset RES
1304
1305 while : ; do
1306 get_passwd_nochk "Enter passwd for ${STR[LDAP_ROOTDN]} :"
1307 STR[LDAP_ROOTPWD]="${ANS}" # stored for create_config_file(), only
1308 save_password
1309 AUTH_ARGS=( '-D' "${STR[LDAP_ROOTDN]}" '-j' "${TMP[LDAP_ROOTPWF]}" )
1310
1311 # Verify that ROOTDN and ROOTPWD are valid
1312 RES=${ ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
1313 -b '' -s base 'objectclass=*' supportedLDAPVersion 2>&1 ; }
1314 (( $? == 0 )) && break # Both are valid.
1315
1316 if [[ ${RES} =~ (credential|no password) ]]; then
1317 Log.warn 'Password for Root DN is invalid'
1318 else
1319 Log.warn "Root DN '${STR[LDAP_ROOTDN]}' is invalid"
1320 get_dirmgr_dn
1321 fi
1322 done
1323 }
1324
1325 Man.addFunc get_domain '' '[+NAME?get_domain - Ask user for domain to be served.]
1326 [+DESCRIPTION?Ask the user for the Domain that will be served by the LDAP server and store it into \bSTR[LDAP_DOMAIN]]\b.]
1327 [+SEE ALSO?\bget_ans()\b.]
1328 '
1329 function get_domain {
1330 while : ; do
1331 get_ans 'Enter the domainname to be served (h=help):' \
1332 "${STR[LDAP_DOMAIN]}"
1333 case "${ANS}" in
1334 [Hh?] | help | Help) display_msg 'domain_help' ; continue ;;
1335 esac
1336 # check, whether it has at least 2 dot separated components
1337 [[ ${ANS} =~ [^.]+\.[^.]+ ]] && break
1338 Log.warn "Invalid domainname '${ANS}'"
1339 done
1340 STR[LDAP_DOMAIN]="${ANS}"
1341 }
1342
1343 Man.addFunc getDSobjectclasses '' '[+NAME?getDSobjectclasses - get all DS schema objectclasses.]
1344 [+DESCRIPTION?Fetch all objectclasses definitions of the DS via \bcn=schema\b and cache them into \bOID2ODEF\b. Once successfully fetched, this function does nothing but return 0.]
1345 [+RETURN VALUES]{
1346 [+0?on success.]
1347 [+>0?failed to retrieve attribute definitions.]
1348 }
1349 '
1350 function getDSobjectclasses {
1351 (( ${#OID2ODEF[@]} )) && return 0
1352
1353 typeset AT OID NAME TAIL
1354 set -o pipefail
1355 ${LDAPSEARCH} ${CON_ARGS} -b cn=schema -s base 'objectclass=*' \
1356 objectclasses 2>/dev/null | \
1357 while read AT OID NAME TAIL ; do
1358 [[ ${AT} != 'objectclasses=(' ]] && continue
1359 TAIL=${TAIL%%+( )$')'};
1360 OID2ODEF["${OID}"]="${TAIL}"
1361 : # always return 0
1362 done
1363 }
1364
1365 Man.addFunc getDSattributes '' '[+NAME?getDSattributes - get all DS schema attributes.]
1366 [+DESCRIPTION?Fetch all attribute definitions of the DS via \bcn=schema\b and cache them into \bOID2ADEF\b. Also populate the hash map \bANAME2OID\b for all the attributes definied. Once successfully fetched, this function does nothing but return 0.]
1367 [+RETURN VALUES]{
1368 [+0?on success.]
1369 [+>0?failed to retrieve attribute definitions.]
1370 }
1371 '
1372 function getDSattributes {
1373 (( ${#ANAME2OID[@]} )) && return 0
1374
1375 typeset AT OID NAME TAIL
1376 typeset -l ALIAS
1377 set -o pipefail
1378 ${LDAPSEARCH} ${CON_ARGS} -b cn=schema -s base 'objectclass=*' \
1379 attributeTypes 2>/dev/null | \
1380 while read AT OID NAME TAIL ; do
1381 [[ ${AT} != 'attributeTypes=(' ]] && continue
1382 TAIL=${TAIL%%+( )$')'};
1383 OID2ADEF["${OID}"]="${TAIL}"
1384 # 'name'
1385 if [[ ${TAIL:0:1} == "'" ]]; then
1386 NAME=${TAIL:1}
1387 ALIAS=${NAME%%"'"*}
1388 ANAME2OID["${ALIAS}"]="${OID}"
1389 continue
1390 fi
1391 # ( 'name' 'name 1' ... )
1392 NAME=${TAIL%%$')'*}
1393 NAME=${NAME##$'('*([[:space:]])}
1394 while [[ ${NAME} == ~(E)"'"([^"'"]+)"'" ]]; do
1395 ALIAS=${.sh.match[1]}
1396 ANAME2OID["${ALIAS}"]="${OID}"
1397 NAME=${NAME:${#ALIAS}+2}
1398 NAME=${NAME#*([[:space:]])}
1399 done
1400 : # always return 0
1401 done
1402 }
1403
1404 Man.addFunc check_attrName '' '[+NAME?check_attrName - validate an attribute name.]
1405 [+DESCRIPTION?Check that \akey\a is a valid attribute name.]
1406 [+RETURN VALUES]{
1407 [0?key is a valid name.]
1408 [1?key is a invalid name.]
1409 [66?failed to fetch attribute definitions from server.]
1410 }
1411 [+SEE ALSO?\bldapsearch\b(1).]
1412 \n\n\akey\a
1413 '
1414 function check_attrName {
1415 typeset KEY=$1
1416
1417 if ! getDSattributes ; then
1418 Log.fatal 'Unable to fetch attribute definitions from server'
1419 return 66
1420 fi
1421 [[ -z ${KEY} ]] && return 1
1422 if [[ ${KEY} =~ ^[0-9]+(\.[0-9]+)*$ ]]; then
1423 # OID value
1424 [[ -n ${OID2ADEF[${KEY}]} ]] && return 0
1425 else
1426 # symbol. name
1427 KEY=${ANAME2OID[${KEY}]}
1428 # if have a mapping, than we also have a definition for it - no need
1429 # to double check
1430 [[ -n ${KEY} ]] && return 0
1431 fi
1432 return 1
1433 }
1434
1435 Man.addFunc check_baseDN '' '[+NAME?check_baseDN - check validity of the baseDN name.]
1436 [+DESCRIPTION?Check that \abaseDN\a is a valid base DN.]
1437 [+RETURN VALUES]{
1438 [+0?baseDN is a valid.]
1439 [+>= 1?baseDN is a invalid.]
1440 }
1441 [+SEE ALSO?\bcheck_attrName()\b.]
1442 [+NOTES?This function does not catch all invalid DNs. Its purpose is to reduce the number of invalid DNs to get past the input routine. The invalid DNs will be caught by the LDAP server when they are attempted to be created.]
1443 \n\n\abaseDN\a
1444 '
1445 function check_baseDN {
1446 # NOTE: we preserve spaces! And try to report all errors instead of just one
1447 Log.info 'Checking LDAP Base DN ...'
1448 [[ -z $1 ]] && return 0
1449
1450 # NOTE: when fancy debug via trap is enabled, splitting via IFS does not
1451 # work: IFS=',' PAIRS=( $1 ) - so we do it manually
1452
1453 typeset PAIR KEY VAL TAIL="${1},"
1454 typeset -A UNIQ_KEYS=( ) # avoid repeated lookup of the same attrName
1455 integer ERR=0
1456 while [[ -n ${TAIL} ]]; do
1457 TAIL=${TAIL#*,}
1458 PAIR=${.sh.match%,}
1459 VAL=${PAIR#*=}
1460 KEY=${.sh.match%=}
1461 if [[ -z ${KEY} || -z ${VAL} ]]; then
1462 Log.warn "Invalid key=value pair '${PAIR}'"
1463 (( ERR++ ))
1464 continue
1465 fi
1466 UNIQ_KEYS[${KEY}]=1
1467 done
1468
1469 for KEY in "${!UNIQ_KEYS[@]}" ; do
1470 if ! check_attrName "${KEY}" ; then
1471 Log.warn "Unknown attribute name '${KEY}'"
1472 fi
1473 done
1474 return ${ERR}
1475 }
1476
1477 Man.addFunc discover_serv_suffix '' '[+NAME?discover_serv_suffix - query the DS to find suffixes available.]
1478 [+DESCRIPTION?Query the DS to find suffixes available. All suffixes found are stored into the variable \avname\a which must be an indexed array.]
1479 [+RETURN VALUES]{
1480 [+0?at least one suffix was found.]
1481 [+1?no suffix found.]
1482 }
1483 [+SEE ALSO?\bldapsearch\b(1).]
1484 \n\n\avname\a
1485 '
1486 function discover_serv_suffix {
1487 typeset LINE
1488 integer NUM_TOP=0
1489 typeset -n DST=$1
1490 DST=( ); unset DST[0]
1491
1492 # Search the server for the TOP of the TREE. Usually none for virgin DS
1493 ${LDAPSEARCH} ${CON_ARGS} -b '' -s base 'objectclass=*' namingContexts \
1494 2>/dev/null | \
1495 while read LINE ; do
1496 if [[ -n ${LINE} && ${LINE} != ~(Ei)NetscapeRoot ]]; then
1497 (( NUM_TOP++ ))
1498 DST+=( "${LINE#*=}\n" ) # strip off '^namingContexts='
1499 fi
1500 done
1501
1502 if (( NUM_TOP == 0 )); then
1503 Log.verbose 'No suffix found in LDAP tree'
1504 return 1
1505 fi
1506
1507 Log.verbose "LDAP_SUFFIX_LIST = ${DST[@]}"
1508 return 0
1509 }
1510
1511 Man.addFunc get_backend '' '[+NAME?get_backend - get the relevant database backend for the Base DN.]
1512 [+DESCRIPTION?Get the relevant database backend name for the Base DN and store it into \bSTR[DS_DB]]\b.]
1513 [+?Prerequisite: \bSTR[LDAP_BASEDN]]\b must be set and valid.]
1514 [+?backend is retrieved from suffixes and subsuffixes defined under "cn=mapping tree,cn=config". The nsslapd-state attribute of these suffixes entries is filled with either Backend, Disabled or referrals related values. We only want those that have a true backend database to select the relevant backend.]
1515 [+RETURN VALUES]{
1516 [+0?on success.]
1517 [+>= 66?an fatal error occured.]
1518 }
1519 [+SEE ALSO?\bldapsearch\b(1).]
1520 '
1521 function get_backend {
1522 typeset CUR_DN=${STR[LDAP_BASEDN]} PREV_DN='' FILTER
1523
1524 while [[ ${CUR_DN} != ${PREV_DN} ]]; do
1525 typeset -a DB=( )
1526 Log.verbose "Testing LDAP suffix: ${CUR_DN} ..."
1527
1528 if (( TMPF[IS_OPENDJ] )); then
1529 FILTER='(&(&(objectclass=ds-cfg-backend)(ds-cfg-base-dn='"${CUR_DN}"
1530 FILTER+='))(objectClass=ds-cfg-local-db-backend))'
1531 ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
1532 -b 'cn=Backends,cn=config' -s one "${FILTER}" 2>/dev/null | \
1533 while read LINE ; do
1534 [[ ${LINE:0:18} == 'ds-cfg-backend-id=' && \
1535 ${LINE: -10} != ',cn=config' ]] && DB+=( "${LINE:18}" )
1536 done
1537 else
1538
1539 ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
1540 -b "cn=${CUR_DN},cn=mapping tree,cn=config" \
1541 -s base 'nsslapd-state=Backend' 'nsslapd-backend' 2>/dev/null |\
1542 while read LINE ; do
1543 [[ ${LINE:0:16} == 'nsslapd-backend=' ]] && DB+=( "${LINE:16}" )
1544 done
1545 fi
1546
1547 if (( ${#DB[@]} == 0 )); then
1548 # not a suffix, or suffix not activated; try next
1549 PREV_DN=${CUR_DN}
1550 CUR_DN="${CUR_DN#*,}"
1551 elif (( ${#DB[@]} == 1 )); then
1552 break
1553 else
1554 Log.fatal "More than one database is configured for '${CUR_DN}'!" \
1555 "$PROG can not configure suffixes where" \
1556 'more than one database is used for one suffix'
1557 return 66
1558 fi
1559 done
1560
1561 if (( ${#DB[@]} == 0 )); then
1562 # should not happen, since STR[LDAP_BASEDN] is supposed to be valid
1563 Log.fatal "Could not find a valid backend for '${STR[LDAP_BASEDN]}'"
1564 if (( TMPF[IS_OPENDJ] )); then
1565 Log.fatal 'Check the "Creating a New Database Backend" section in the Administration Guide'
1566 fi
1567 return 67
1568 fi
1569 STR[DS_DB]="${DB[0]}"
1570
1571 Log.verbose "DB backend '${STR[DS_DB]}' selected"
1572
1573 return 0
1574 }
1575
1576 Man.addFunc normalizeDN '' '[+NAME?normalizeDN - normalize a [relative]] distinguished name.]
1577 [+DESCRIPTION?Strip off unnecessary spaces around \b,\b and \b=\b as well as at the beginning and end of the given \adn\a, optionally convert it to lower or upper case (if either \bl\b or \bu\b is given) and print it to stdout.]
1578 \n\n\adn\a [\bl\b|\bu\b]
1579 '
1580 function normalizeDN {
1581 [[ -z $1 ]] && return
1582 typeset VAL=",${1},"
1583 VAL="${VAL//*( ),*( )/,}"
1584 VAL="${VAL//*( )=*( )/=}"
1585 if [[ $2 == 'l' ]]; then
1586 typeset -l LC="${VAL}"
1587 VAL="${LC}"
1588 elif [[ $2 == 'u' ]]; then
1589 typeset -u UC="${VAL}"
1590 VAL="${UC}"
1591 fi
1592 print -- "${VAL:1:${#VAL}-2}"
1593 }
1594
1595 Man.addFunc check_basedn_suffix '' '[+NAME?check_basedn_suffix - check that there is an existing valid suffix to hold current base DN.]
1596 [+DESCRIPTION?Check that there is an existing valid suffix for \bSTR[LDAP_BASEDN]]\b. If one is found, store it into \bSTR[LDAP_SUFFIX]]\b and make a corresponding backend check.]
1597 [+RETURN VALUES]{
1598 [+0?valid suffix found or new one should be created (\bTMPF[NEED_CREATE_SUFFIX]]\b flag actually indicates that).]
1599 [+>= 66?a fatal error occured.]
1600 }
1601 [+SEE ALSO?\bdiscover_serv_suffix()\b, \bldapsearch\b(1), \bnormalizeDN()\b, \bget_backend()\b.]
1602 '
1603 function check_basedn_suffix {
1604 Log.info 'Validating LDAP Base DN and Suffix ...'
1605 TMPF[NEED_CREATE_SUFFIX]=0
1606
1607 # check that LDAP Base DN might be added
1608 typeset CUR_DN="${STR[LDAP_BASEDN]}" PREV_DN=''
1609
1610 while [[ ${CUR_DN} != ${PREV_DN} ]]; do
1611 ${LDAPSEARCH} ${CON_ARGS} -b "${CUR_DN}" -s one 'objectclass=*' \
1612 >/dev/null 2>&1 && break
1613 PREV_DN=${CUR_DN}
1614 CUR_DN="${CUR_DN#*,}" # remove leading component
1615 done
1616
1617 if [[ ${CUR_DN} == ${PREV_DN} ]]; then
1618 Log.info "No valid suffixes were found for Base DN '${STR[LDAP_BASEDN]}'"
1619 TMPF[NEED_CREATE_SUFFIX]=1
1620 return 0
1621 fi
1622
1623 # find out existing suffixes
1624 typeset -a SUFFIXES=( )
1625 discover_serv_suffix SUFFIXES
1626
1627 # Now looking for relevant suffix for this entry (using lower case - LC).
1628 # STR[LDAP_SUFFIX] will then be used to add necessary base objects via
1629 # add_base_objects().
1630 typeset LC_DN=,${ normalizeDN "${CUR_DN}" l ; }
1631 typeset SFX LC_SFX
1632 for SFX in "${SUFFIXES[@]}" ; do
1633 Log.verbose "Testing suffix: ${SFX} ..."
1634 # LC_DN ends with ,SFX ?
1635 LC_SFX=,${ normalizeDN "${SFX}" l ; }
1636 if [[ ${LC_DN: -${#LC_SFX}} == ${LC_SFX} ]]; then
1637 STR[LDAP_SUFFIX]="${SFX}"
1638 break
1639 fi
1640 done
1641
1642 if [[ -z ${STR[LDAP_SUFFIX]} ]]; then
1643 # should not happen, since we found the entry
1644 Log.fatal "Could not find a valid suffix for '${STR[LDAP_BASEDN]}'"
1645 return 66
1646 fi
1647
1648 # Getting relevant database (backend)
1649 # DS_DB will then be used to create indexes.
1650 get_backend || return 67
1651
1652 return 0
1653 }
1654
1655 Man.addFunc get_objectclass '' '[+NAME?get_objectclass - get the objectclass for the given attribute name.]
1656 [+DESCRIPTION?Get the objectclass for the given attribute name \aattrName\a and print it to stdout. Right now ou, dc, o, and c and related aliases/OIDs are supported, only. For all others nothing will be printed.]
1657 [+NOTES?An attribute name can be valid but still we might not be able to determine the objectclass from the table. In such cases, the user needs to create the necessary object(s).]
1658 \n\n\aattrName\a
1659 '
1660 function get_objectclass {
1661 typeset -l ANAME="$1"
1662
1663 case "${ANAME}" in
1664 ou | organizationalunitname | 2.5.4.11)
1665 print 'organizationalUnit'
1666 ;;
1667 dc | domaincomponent | 0.9.2342.19200300.100.1.25)
1668 print 'domain'
1669 ;;
1670 o | organizationname | 2.5.4.10)
1671 print 'organization'
1672 ;;
1673 c | countryname | 2.5.4.6)
1674 print 'country'
1675 ;;
1676 esac
1677 }
1678
1679 function checkSuffixRDN {
1680 typeset RDN="${STR[LDAP_SUFFIX]%%,*}"
1681 TMP[SUFFIX_VAL]="${RDN#*=}"
1682 TMP[SUFFIX_ATT]="${.sh.match%=}"
1683
1684 # find out an objectclass for suffix entry if it is not defined yet
1685 TMP[SUFFIX_OBJ]=${ get_objectclass "${TMP[SUFFIX_ATT]}" ; }
1686 if [[ -z ${TMP[SUFFIX_OBJ]} ]]; then
1687 Log.fatal 'Unable to find an objectclass for' "'${TMP[SUFFIX_ATT]}'" \
1688 'attribute'
1689 return 1
1690 fi
1691 return 0
1692 }
1693
1694 Man.addFunc prep_create_sfx_entry '' '[+NAME?prep_create_sfx_entry - prepare for the suffix entry creation.]
1695 [+DESCRIPTION?Prepare suffix entry creation based on \bSTR[LDAP_BASEDN|LDAP_SUFFIX]]\b and \bTMP[SUFFIX_OBJ]]\b. If the latter are unset (no config file read), set them to defaults depending on the baseDN. Finally check, whether the suffix entry already exists and if so check for consistency with the current config. This function sets:]{
1696 [+TMPF[NEED_CREATE_BACKEND]]?0 .. backend already exists. 1 .. create a backend.]
1697 [+TMP[SUFFIX_ATT]]?The attribute name of the leading RDN of the suffix (ID).]
1698 [+TMP[SUFFIX_VAL]]?The attribute value of the leading RDN of the suffix (ID).]
1699 }
1700 [+RETURN VALUES]{
1701 [+0?on success.]
1702 [+1?an attribute/consistence related error occured.]
1703 [+>= 66?a fatal error occured.]
1704 }
1705 [+SEE ALSO?\bnormalizeDN()\b, \bdisplay_msg()\b, \badd_suffix()\b, \bldapsearch\b(1)]
1706 '
1707 function prep_create_sfx_entry {
1708 # check whether suffix corresponds to base dn (i.e. baseDN ends with suffix)
1709 typeset X=,${ normalizeDN "${STR[LDAP_BASEDN]}" l ; }
1710 typeset SFX=,${STR[LDAP_SUFFIX]}
1711 if [[ ${X: -${#SFX}} != ${SFX} ]]; then
1712 Log.warn "Sorry, suffix '${STR[LDAP_SUFFIX]}' is not suitable for" \
1713 "Base DN '${STR[LDAP_BASEDN]}'"
1714 return 1
1715 fi
1716
1717 checkSuffixRDN || return 66
1718 Log.verbose "Suffix entry object: '${TMP[SUFFIX_OBJ]}'"
1719
1720 TMPF[NEED_CREATE_BACKEND]=0
1721
1722 if (( TMPF[IS_OPENDJ] )); then
1723 # 1st just check, whether any backend matches the suffix
1724 typeset FILTER='(&(objectClass=ds-cfg-local-db-backend)'
1725 FILTER+="(|(ds-cfg-base-dn=${STR[LDAP_SUFFIX]})"
1726 FILTER+="(ds-cfg-base-dn=*,${STR[LDAP_SUFFIX]})))"
1727 X=${ ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
1728 -b 'cn=Backends,cn=config' -s one "${FILTER}" 2>/dev/null ; }
1729 if [[ -n ${X} ]]; then
1730 Log.verbose 'Suffix backend already exists'
1731 get_backend || return 66
1732 return 0
1733 fi
1734 else
1735 # DSEE: check the suffix mapping tree ...
1736 # If mapping exists, suffix should work, otherwise DSEE inconsistent
1737 # NOTE: -b 'cn=mapping tree,cn=config' -s one 'cn=\"$1\"' won't work
1738 # in case of 'cn' value in LDAP is not quoted by '"',
1739 # -b 'cn=\"$1\",cn=mapping tree,cn=config' works in all cases
1740 if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
1741 -b "cn=\"${STR[LDAP_SUFFIX]}\",cn=mapping tree,cn=config" \
1742 -s base 'objectclass=*' dn 2>/dev/null
1743 then
1744 Log.verbose 'Suffix mapping already exists'
1745 get_backend || return 66
1746 return 0
1747 fi
1748
1749 # no suffix mapping, just in case check ldbm backends consistency -
1750 # there are must be NO any databases pointing to STR[LDAP_SUFFIX]
1751 X=${ ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
1752 -b 'cn=ldbm database,cn=plugins,cn=config' \
1753 -s one "nsslapd-suffix=${STR[LDAP_SUFFIX]}" dn 2>/dev/null ; }
1754 if [[ -n ${X} ]]; then
1755 Log.warn 'Sorry, there is no suffix mapping for' \
1756 "'${STR[LDAP_SUFFIX]}', while ldbm database exists, server" \
1757 'configuration needs to be fixed manually, look at cn=mapping' \
1758 'tree,cn=config and cn=ldbm database,cn=plugins,cn=config'
1759 return 1
1760 fi
1761 fi
1762
1763 Log.verbose 'Backend needs to be created ...'
1764 TMPF[NEED_CREATE_BACKEND]=1
1765 return 0
1766 }
1767
1768 Man.addFunc prep_create_sfx_backend '' '[+NAME?prep_create_sfx_backend - prepare for the suffix backend creation.]
1769 [+DESCRIPTION?Prepare for the suffix backend creation by checking available DBs starting with \bSTR[DS_DB]]\b. Sets \bTMP[DS_DB_AVAIL]]\b if not yet set or != \bSTR[DS_DB]]\b.]
1770 [+RETURN VALUES]{
1771 [+0?backend db name is ok.]
1772 [+1?\bSTR[DS_DB]]\b exists, so \bTMP[DS_DB_AVAIL]]\b contains available name.]
1773 [+2?unable to find any available name.]
1774 }
1775 [+SEE ALSO?\bldapsearch\b(1).]
1776 '
1777 function prep_create_sfx_backend {
1778 # check if requested name available
1779 [[ ${STR[DS_DB]} == ${TMP[DS_DBS_AVAIL]} ]] && return 0
1780
1781 # get the list of database names start with a requested name
1782 typeset -a DBS=( )
1783 if (( TMPF[IS_OPENDJ] )); then
1784 typeset FILTER='(&(objectclass=ds-cfg-local-db-backend)'
1785 FILTER+="(ds-cfg-backend-id=${STR[DS_DB]}*))"
1786 ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
1787 -b 'cn=Backends,cn=config' -s one "${FILTER}" ds-cfg-backend-id \
1788 2>/dev/null | \
1789 while read LINE ; do
1790 [[ -n ${LINE} && ${LINE: -10} != ',cn=config' ]] && \
1791 DBS+=( "${LINE#ds-cfg-backend-id=}" )
1792 done
1793 else
1794 ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
1795 -b 'cn=ldbm database,cn=plugins,cn=config' \
1796 -s one "cn=${STR[DS_DB]}*" cn 2>/dev/null | \
1797 while read LINE ; do
1798 [[ -n ${LINE} && ${LINE: -10} != ',cn=config' ]] && \
1799 DBS+=( "${LINE#cn=}" )
1800 done
1801 fi
1802 if (( ${#DBS[@]} == 0 )); then
1803 # no backend name starts with STR[DS_DB]
1804 TMP[DS_DBS_AVAIL]="${STR[DS_DB]}"
1805 return 0
1806 fi
1807
1808 # find a non-existing db name based on a requested name
1809 integer I FOUND
1810 typeset -l NAME DB
1811 for (( I=0 ; I < 10; I++ )); do
1812 (( I )) && NAME="${STR[DS_DB]}${I}" || NAME="${STR[DS_DB]}"
1813 FOUND=0
1814 for DB in "${DBS[@]}" ; do
1815 [[ ${DB} == ${NAME} ]] && FOUND=1 && break
1816 done
1817 if (( ! FOUND )); then
1818 if (( I == 0 )); then
1819 TMP[DS_DBS_AVAIL]="${STR[DS_DB]}"
1820 return 0 # requested name is available
1821 fi
1822 TMP[DS_DBS_AVAIL]="${STR[DS_DB]}${I}"
1823 break
1824 fi
1825 done
1826
1827 if [[ -n ${TMP[DS_DBS_AVAIL]} ]]; then
1828 Log.warn "Database backend '${STR[DS_DB]}' already exists," \
1829 "however '${TMP[DS_DBS_AVAIL]}' is available"
1830 return 1
1831 fi
1832
1833 Log.warn 'Unable to find any available database backend close to' \
1834 "'${STR[DS_DB]}'"
1835 return 2
1836 }
1837
1838 Man.addFunc get_suffix '' '[+NAME?get_suffix - Ask user for suffix and related backend.]
1839 [+DESCRIPTION?Ask the user for the suffix (default: \bSTR[LDAP_BASEDN]]\b) to create and the db name if it does not yet exist. \bTMP[DS_DBS_AVAIL]]\b gets set to the given db name (if any), \bSTR[DS_DB]]\b to the prepared db name and \bSTR[LDAP_SUFFIX]]\b to the given suffix.]
1840 [+RETURN VALUES]{
1841 [+0?on success (user gave a correct suffix).]
1842 [+1?unable to create suffix given by user.]
1843 [+>= 66?a fatal error occured.]
1844 }
1845 [+SEE ALSO?\bget_ans()\b, \bdisplay_msg()\b, \bnormalizeDN()\b, \bprep_create_sfx_entry()\b, \bprep_create_sfx_backend()\b.]
1846 '
1847 function get_suffix {
1848 while : ; do
1849 get_ans 'Enter suffix to be created (b=back/h=help):' \
1850 "${STR[LDAP_BASEDN]}"
1851 case "${ANS}" in
1852 [Hh?] | Help | help)
1853 display_msg 'create_suffix_help'
1854 continue
1855 ;;
1856 [Bb] | '<' | Back | back)
1857 return 1
1858 ;;
1859 esac
1860 STR[LDAP_SUFFIX]=${ normalizeDN "${ANS}" l ; }
1861 prep_create_sfx_entry
1862 integer REDO=$?
1863 (( REDO >= 66 )) && return 66
1864 (( REDO )) && continue
1865
1866 if (( TMPF[NEED_CREATE_BACKEND] )); then
1867 TMP[DS_DBS_AVAIL]='' # reset the available db name
1868 REDO=0
1869 while : ; do
1870 X=${TMP[DS_DBS_AVAIL]}
1871 # Basically for OpenDJ we could use 'userRoot' as default aka
1872 # TMP[SUFFIX_VAL], however, users may use it for trying out
1873 # examples from the docs
1874 get_ans 'Enter local database backend name (b=back/h=help):' \
1875 "${X:-${TMP[SUFFIX_VAL]}}"
1876 case "${ANS}" in
1877 [Hh?])
1878 display_msg 'enter_ldbm_db_help'
1879 continue
1880 ;;
1881 [Bb] | '<')
1882 REDO=1
1883 break
1884 ;;
1885 esac
1886 STR[DS_DB]="${ANS}"
1887 prep_create_sfx_backend && break
1888 done
1889
1890 (( REDO )) && continue
1891
1892 Log.verbose 'Databse backend name for suffix ${STR[LDAP_SUFFIX]}:' \
1893 "${DS_DB}"
1894 fi
1895 # eventually everything is prepared
1896 break
1897 done
1898 return 0
1899 }
1900
1901 Man.addFunc domain_2_dc '' '[+NAME?domain_2_dc - Convert a domain name into dc string.]
1902 [+DESCRIPTION?Convert a domain name \adomain\a into a dc=...,dc=... string and print it to stdout.]
1903 \n\n\adomain\a
1904 '
1905 function domain_2_dc {
1906 [[ -z $1 ]] && return
1907 typeset DC='' SD
1908 for SD in ${1//./ } ; do # removes leading && trailing && double dots
1909 DC+=",dc=${SD}"
1910 done
1911 print -- "${DC:1}"
1912 }
1913
1914 Man.addFunc get_basedn '' '[+NAME?get_basedn - Ask user for Base DN.]
1915 [+DESCRIPTION?Ask the user for the BaseDN to use, check whether to create a suffix and store the value into \bSTR[LDAP_BASEDN]]\b.]
1916 [+RETURN VALUES]{
1917 [+0?on success.]
1918 [+>= 66?a fatal error occured.]
1919 }
1920 [+SEE ALSO?\bget_ans_req()\b, \bdisplay_msg()\b, \bcheck_baseDN()\b, \bcheck_basedn_suffix()\b, \bget_suffix()\b.]
1921 '
1922 function get_basedn {
1923 typeset BASEDN=${ domain_2_dc ${STR[LDAP_DOMAIN]} ; }
1924 integer RES
1925
1926 while : ; do
1927 # Get Base DN.
1928 while : ; do
1929 get_ans_req 'Enter LDAP Base DN (h=help):' "${BASEDN}"
1930 case "${ANS}" in
1931 [Hh?] | help | Help) display_msg 'basedn_help' ; continue ;;
1932 esac
1933 check_baseDN "${ANS}" && break
1934 Log.warn "Invalid base DN: '${ANS}'"
1935 done
1936
1937 # Set base DN and check its suffix
1938 STR[LDAP_BASEDN]="${ANS}"
1939 check_basedn_suffix || return 66
1940
1941 # suffix may need to be created, in that case get suffix from user
1942 if (( TMPF[NEED_CREATE_SUFFIX] )); then
1943 get_suffix
1944 RES=$?
1945 (( RES >= 66 )) && return 67
1946 (( RES )) && continue
1947 fi
1948
1949 # suffix is ok, break out of the base dn inquire loop
1950 break
1951 done
1952 return 0
1953 }
1954
1955 Man.addFunc chk_vlv_indexes '' '[+NAME?chk_vlv_indexes - check if server supports VLV.]
1956 [+DESCRIPTION?Checks, whether the DS supports Virtual List Views (VLV).]
1957 [+RETURN VALUES]{
1958 [+0?if VLVs are supported.]
1959 [+>= 66?if VLVs are not supported.]
1960 }
1961 [+SEE ALSO?\bldapsearch\b(1).]
1962 '
1963 function chk_vlv_indexes {
1964 typeset ATTR=''
1965 ${LDAPSEARCH} ${CON_ARGS} -b '' -s base 'objectclass=*' \
1966 supportedControl 2>/dev/null | \
1967 while read LINE ; do
1968 if [[ ${LINE#*=} == '2.16.840.1.113730.3.4.9' ]]; then
1969 ATTR=${.sh.match%=}
1970 break
1971 fi
1972 done
1973 if [[ -z ${ATTR} ]]; then
1974 Log.fatal 'VLV is not supported on LDAP server'
1975 return 66
1976 fi
1977 return 0
1978 }
1979
1980 Man.addFunc validate_suffix '' '[+NAME?validate_suffix - validate suffix obtained via config file.]
1981 [+DESCRIPTION?This function validates STR[LDAP_SUFFIX]] AFTER THE LOAD OF A CONFIG FILE (should not be used for interactive use). Also does a consistency check wrt. \bSTR[LDAP_BASEDN]]\b.]
1982 [+RETURN VALUES]{
1983 [+0?on success.]
1984 [+>= 66?a fatal error occured.]
1985 }
1986 [+SEE ALSO?\bnormalizeDN()\b, \bldapsearch\b(1), \bprep_create_sfx_entry()\b, \bprep_create_sfx_backend()\b.]
1987 '
1988 function validate_suffix {
1989 # Check STR[LDAP_SUFFIX] is not null
1990 if [[ -z ${STR[LDAP_SUFFIX]} ]]; then
1991 Log.fatal 'Invalid suffix (null suffix)'
1992 return 66
1993 fi
1994
1995 # STR[LDAP_SUFFIX] and STR[LDAP_BASEDN] are consistent ?
1996 typeset X=,${ normalizeDN "${STR[LDAP_BASEDN]}" l ; }
1997 typeset SFX=,${ normalizeDN "${STR[LDAP_SUFFIX]}" l ; }
1998 if [[ ${X: -${#SFX}} != ${SFX} ]]; then
1999 Log.fatal "Invalid suffix '${SFX}' for Base DN '${X}'"
2000 return 67
2001 fi
2002
2003 # STR[LDAP_SUFFIX] does exist ?
2004 if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b "${STR[LDAP_SUFFIX]}" \
2005 -s base 'objectclass=*' >/dev/null 2>&1
2006 then
2007 checkSuffixRDN && return 0 || return 68
2008 fi
2009
2010 # Well, suffix does not exist, try to prepare create it ...
2011 TMPF[NEED_CREATE_SUFFIX]=1
2012 prep_create_sfx_entry || return 69
2013 if (( TMPF[NEED_CREATE_BACKEND] )); then
2014 if [[ -z ${STR[DS_DB]} ]]; then
2015 Log.fatal 'Database backend name is not set. Either set SIN[DS_DB]'\
2016 'in the input file to a valid, i.e. non-existing DB name, or' \
2017 'create the backend with the default DS tools'
2018 return 70
2019 fi
2020 # too risky, even if a available backend name could be found
2021 prep_create_sfx_backend || return 71
2022 fi
2023
2024 Log.verbose "Suffix: '${STR[LDAP_SUFFIX]}' Database: '${STR[DS_DB]}'"
2025 return 0
2026 }
2027
2028 Man.addFunc validate_info '' '[+NAME?validate_info - validate basic info obtained via config file.]
2029 [+DESCRIPTION?This function updates \bCON_ARGS\b as well as \bAUTH_ARGS\b, checks, whether they work so that some problems are caught right away AFTER THE LOAD OF A CONFIG FILE (should not be used for interactive use). It also validates the obtained suffix and whether the DS supports VLVs.]
2030 [+RETURN VALUES]{
2031 [+0?on success.]
2032 [+>= 66?a fatal error occured.]
2033 }
2034 [+SEE ALSO?\bldapsearch\b(1), \bchk_vlv_indexes()\b, \bvalidate_suffix()\b.]
2035 '
2036 function validate_info {
2037 # Set CON_ARGS and AUTH_ARGS for the config file.
2038 CON_ARGS="-h ${STR[DS_HOST]} -p ${INT[DS_PORT]}"
2039 AUTH_ARGS=( '-D' "${STR[LDAP_ROOTDN]}" '-j' "${TMP[LDAP_ROOTPWF]}" )
2040 chk_ids_version || return 1 # Check DSEE version for compatibility
2041
2042 # Check the Root DN and Root DN passwd.o Same as for get_dirmgr_pw()
2043 RES=${ ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b '' -s base \
2044 'objectclass=*' supportedLDAPVersion 2>&1 ; }
2045 if (( $? )); then
2046 if [[ ${RES} =~ credential ]]; then
2047 Log.fatal 'Root DN passwd is invalid'
2048 else
2049 Log.fatal "Invalid Root DN '${STR[LDAP_ROOTDN]}'"
2050 fi
2051 return 66
2052 fi
2053 Log.verbose 'RootDN: ok RootDN passwd: ok'
2054
2055 # Check if the server supports the VLV
2056 chk_vlv_indexes || return 67
2057 Log.verbose 'VLV indexes ... ok'
2058
2059 # Check LDAP suffix
2060 validate_suffix || return 66
2061 Log.verbose 'LDAP suffix ... ok'
2062 return 0
2063 }
2064
2065 Man.addFunc gssapi_setup '' '[+NAME?gssapi_setup - set up GSSAPI if necessary.]
2066 [+DESCRIPTION?Check, whether the DS supports the SASL mechanism \bGSSAPI\b. If so, ask the user whether it should be enabled and depending on the answer ask for related Kerberos realm info. \bINT[GSSAPI_ENABLE]]\b and \bTMPF[GSSAPI_AUTH_MAY_BE_USED]]\b and optionally \bSTR[LDAP_KRB_REALM]]\b are set accordingly.]
2067 [+SEE ALSO?\bldapsearch\b(1), \bget_ans_req()\b.]
2068 '
2069 function gssapi_setup {
2070 INT[GSSAPI_ENABLE]=0
2071 TMPF[GSSAPI_AUTH_MAY_BE_USED]=0
2072
2073 ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b '' -s base 'objectclass=*' \
2074 supportedSASLMechanisms 2>/dev/null | \
2075 while read LINE ; do
2076 if [[ ${LINE:0:24} == 'supportedSASLMechanisms=' && \
2077 ${LINE:24} == 'GSSAPI' ]]
2078 then
2079 TMPF[GSSAPI_AUTH_MAY_BE_USED]=1
2080 break
2081 fi
2082 done
2083 if (( ! TMPF[GSSAPI_AUTH_MAY_BE_USED] )); then
2084 Log.info 'sasl/GSSAPI is not supported by this LDAP server'
2085 return
2086 fi
2087
2088 get_confirm 'GSSAPI is supported. Do you want to set up GSSAPI:(y/n)' 'n'
2089 if (( $? )); then
2090 INT[GSSAPI_ENABLE]=1
2091 # get kerberos realm
2092 typeset -u REALM=${STR[LDAP_DOMAIN]}
2093 get_ans_req "Enter Kerberos Realm:" "${REALM}"
2094 REALM="${ANS}" # make sure, it is upper case
2095 STR[LDAP_KRB_REALM]="${REALM}"
2096 else
2097 Log.info 'GSSAPI is not set up - ' \
2098 'sasl/GSSAPI bind may not work if it is not set up first'
2099 fi
2100 }
2101
2102 Man.addFunc get_profile_name '' '[+NAME?get_profile_name - Ask user for client profile name.]
2103 [+DESCRIPTION?Ask the user for the name of the client profile to create, check whether it already exists, and if so ask whether it should be overwritten. Sets \bSTR[LDAP_PROFILE_NAME]]\b, \bTMPF[DEL_OLD_PROFILE]]\b and if the user wants to just enable shadow update \bINT[LDAP_ENABLE_SHADOW_UPDATE]]\b and \bINT[EXISTING_PROFILE]]\b.]
2104 [+SEE ALSO?\bget_ans()\b, \bldapsearch\b(1), \bget_confirm()\b, \bget_confirm_nodef()\b, \bdisplay_msg()\b.]
2105 '
2106 function get_profile_name {
2107 TMPF[DEL_OLD_PROFILE]=0 # Reset since getting new profile name
2108
2109 typeset PNAME="${STR[LDAP_PROFILE_NAME]}"
2110 # Loop until valid profile name, or replace.
2111 while : ; do
2112 get_ans 'Enter the client profile name (h=help):' "${PNAME}"
2113 case "${ANS}" in
2114 [Hh] | help | Help | '?') display_msg 'profile_help' ; continue ;;
2115 esac
2116
2117 # Search to see if profile name already exists.
2118 if ! ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
2119 -b "cn=${ANS},ou=profile,${STR[LDAP_BASEDN]}" -s base \
2120 'objectclass=*' >/dev/null 2>&1
2121 then
2122 break # Unique profile name (does not yet exist)
2123 fi
2124
2125 Log.info 'Profile "'"${ANS}"'" already exists, it is possible to' \
2126 'enable shadow update now.' "${PROG}" 'will exit after shadow' \
2127 'update is enabled. You can also continue to overwrite the' \
2128 'profile or create a new one and be given the chance to enable' \
2129 'shadow update later.'
2130
2131 get_confirm 'Just enable shadow update (y/n/h)?' 'n' \
2132 'enable_shadow_update_help'
2133 if (( $? )); then
2134 # set up credentials for shadow update
2135 INT[LDAP_ENABLE_SHADOW_UPDATE]=1
2136 # display alternate messages
2137 INT[EXISTING_PROFILE]=1
2138 break
2139 fi
2140
2141 get_confirm_nodef \
2142 "Are you sure you want to overwrite profile 'cn=${ANS}'?"
2143 if (( $? )); then
2144 TMPF[DEL_OLD_PROFILE]=1 # Replace old profile name
2145 break
2146 fi
2147 done
2148
2149 STR[LDAP_PROFILE_NAME]="${ANS}"
2150 }
2151
2152 Man.addFunc getACIs '' '[+NAME?getACIs - get ACIs for the current base DN.]
2153 [+DESCRIPTION?Get all ACIs for \abaseDN\a and append them to the indexed array of strings \avname\a. If \abaseDN\a is not given, \bSTR[LDAP_BASEDN]]\b will be used instead. If \ascope\a is set to \bGlobal\b this method queries for "ds-cfg-global-aci" instead of "aci" unless \bTMPF[IS_OPENDJ]]\b is \b0\b.]
2154 [+RETURN VALUES]{
2155 [+-1?invalid function usage.]
2156 [+0?on success.]
2157 [+1?an error occured when executing the ldapsearch operation.]
2158 }
2159 \n\n\avname\a [\abaseDN\a] [\ascope\a]
2160 '
2161 function getACIs {
2162 set -o pipefail # wanna have the exit code of ldapsearch
2163 [[ -z $1 ]] && Log.warn "${.sh.fun}(): invalid function usage" && \
2164 return -1
2165 typeset -n ACILIST=$1
2166 typeset LINE
2167 typeset DN="$2" ACI='aci'
2168 [[ -z ${DN} ]] && DN="${STR[LDAP_BASEDN]}"
2169 [[ $3 == 'Global' ]] && (( TMPF[IS_OPENDJ] )) && ACI='ds-cfg-global-aci'
2170
2171 ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b "${DN}" -s base \
2172 'objectclass=*' ${ACI} 2>/dev/null | \
2173 while read LINE ; do
2174 # NOTE: the || : is required to always get success (pipe doesn't break)
2175 [[ ${LINE:0:${#ACI}+1} == "${ACI}=" ]] && \
2176 ACILIST+=( "${LINE:${#ACI}+1}" ) || :
2177 done
2178 if (( $? )); then
2179 Log.fatal "Unable to get aci list for '${STR[LDAP_BASEDN]}'"
2180 return 1
2181 fi
2182 return 0
2183 }
2184
2185 Man.addFunc findACI '' '[+NAME?findACI - find an ACI in the given list.]
2186 [+DESCRIPTION?Find the first ACI which matches \aregex\a in the indexed array of ACIs \avname\a. If a match occurs, print out a message using the given \aaciName\a prefixed with \ascope\a. If \ascope\a is not given or empty, \bBaseDN\b will be used instead.]
2187 [+RETURN VALUES]{
2188 [+0?no ACI matched.]
2189 [+>=1?the index+1 of the ACI matched.]
2190 }
2191 [+SEE ALSO?\bgetACIs()\b, \bfindACI()\b, \bfind_and_delete_ACI\b()]
2192 \n\n\avname\a \aaciName\a \aregex\a [\ascope\a]
2193 '
2194 function findACI {
2195 typeset -n LIST=$1
2196 typeset NAME="$2" REGEX="$3" SCOPE="$4"
2197 integer MAX=${#LIST[@]} I
2198 [[ -z ${SCOPE} ]] && SCOPE='BaseDN'
2199 for (( I=0; I < MAX; I++ )); do
2200 if [[ ${LIST[${I}]} =~ ${REGEX} ]]; then
2201 showProgress "${SCOPE} ACI '${NAME}' exists."
2202 return $((I+1))
2203 fi
2204 done
2205 return 0
2206 }
2207
2208 Man.addFunc allow_proxy_read_pw '' '[+NAME?allow_proxy_read_pw - add Proxy Agent read permission for password.]
2209 [+DESCRIPTION?Add the ACI \bPROXY_ACI_NAME\b for \bSTR[LDAP_PROXYAGENT]]\b to \bSTR[LDAP_BASEDN]]\b if it not already exists.]
2210 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage PROXY_ACI_NAME ; }" '}
2211 [+RETURN VALUES]{
2212 [+0?on success (ACI already exists or added successfully).]
2213 [+>= 66?a fatal error occured.]
2214 }
2215 [+SEE ALSO?\bgetACIs()\b, \bldapmodify\b(1).]
2216 '
2217 function allow_proxy_read_pw {
2218 typeset ACI PATTERN TARGET
2219
2220 typeset -a LIST=( )
2221 getACIs LIST || return 66
2222
2223 PATTERN='acl[ ]+"?('"${PROXY_ACI_NAME}|${PROXY_ACI_NAME// /_}"')"?'
2224 findACI LIST "${PROXY_ACI_NAME}" "${PATTERN}" || return 0
2225
2226 PATTERN='userPassword'
2227 if (( TMPF[IS_OPENDJ] )); then
2228 PATTERN+=' || authPassword'
2229 # At least in OpenDJ specifying the same target as where the ACI gets
2230 # attached is redundant wrt. the result and causes minimal overhead
2231 TARGET=''
2232 else
2233 TARGET='(target = "ldap:///'"${STR[LDAP_BASEDN]}"'")'
2234 fi
2235
2236 nextFile modify $0
2237 print '
2238 dn: '"${STR[LDAP_BASEDN]}"'
2239 changetype: modify
2240 add: aci
2241 aci: '"${TARGET}"'(targetattr = "'"${PATTERN}"'")
2242 (
2243 version 3.0; acl "'"${PROXY_ACI_NAME}"'";
2244 allow (compare,read,search) userdn = "ldap:///'"${STR[LDAP_PROXYAGENT]}"'";
2245 )
2246 ' > ${TMP[FILE]}
2247
2248 if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
2249 >&${TMPF[FD]} 2>&1
2250 then
2251 Log.fatal "Adding '${PROXY_ACI_NAME}' ACI failed"
2252 return 66
2253 fi
2254
2255 showProgress "ACI '${PROXY_ACI_NAME}' added."
2256 return 0
2257 }
2258
2259 Man.addFunc delete_proxy_read_pw '' '[+NAME?delete_proxy_read_pw - delete Proxy Agent read permission for password.]
2260 [+DESCRIPTION?Remove the ACI \bPROXY_ACI_NAME\b from \bSTR[LDAP_BASEDN]]\b if such an ACI exists.]
2261 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage PROXY_ACI_NAME ; }" '}
2262 [+RETURN VALUES]{
2263 [+0?on success (no delete required or ACI deleted).]
2264 [+>= 66?a fatal error occured.]
2265 }
2266 [+SEE ALSO?\bgetACIs()\b, \bget_menu_choice()\b, \bldapmodify\b(1).]
2267 '
2268 function delete_proxy_read_pw {
2269 typeset PROXY_ACI='' ACI PATTERN X
2270
2271 typeset -a LIST=( )
2272 getACIs LIST || return 66
2273
2274 # Search for ACI_NAME - no findACI() because we need ALL matching ACIs
2275 typeset -a ACILIST=( )
2276 PATTERN='acl[ ]+"?('"${PROXY_ACI_NAME}|${PROXY_ACI_NAME// /_}"')"?'
2277 for ACI in "${LIST[@]}" ; do
2278 [[ ${ACI} =~ ${PATTERN} ]] && ACILIST+=( "${ACI#*=}" )
2279 done
2280
2281 # We need to remove proxy agent's read access to user passwords,
2282 # but We do not know the value of the ${LDAP_PROXYAGENT} here, so
2283 # 1. if only one match found, delete it
2284 # 2. if more than one matches found, ask the user which one to delete
2285 if (( ${#ACILIST[@]} == 0 )); then
2286 Log.warn "ACI '${PROXY_ACI_NAME}' does not exist for" \
2287 "'${STR[LDAP_BASEDN]}'"
2288 return 0
2289 fi
2290 if (( ${#ACILIST[@]} == 1 ));then
2291 PROXY_ACI="${ACI[0]}"
2292 else
2293 X='
2294 Proxy agent is not allowed to read user passwords when shadow
2295 update is enabled. There are more than one proxy agents found.
2296 Please select the proxy agent currently being used, so that
2297 '"${PROG}"' can remove its read access to user passwords.
2298
2299 The proxy agents are:
2300 '
2301 # print the list of ACIs for selection
2302 integer I MAX
2303 MAX=${#ACILIST[@]}
2304 for (( I=0; I < MAX; I++ )) ; do
2305 ACI="${ACILIST[${I}]}"
2306 if (( ! Log.VERBOSE )); then
2307 # older versions used
2308 # sed -e 's|.*ldap:///.*ldap:///||' -e 's|";)||'
2309 ACI=${ACI##*ldap:///}
2310 ACI=${ACI%\"*}
2311 fi
2312 X+=${ printf '%2d: %s\n' $((I+1)) "${ACI}" ; }
2313 done
2314 Log.warn "${X}"
2315
2316 # ask the user to pick one
2317 get_menu_choice "Select the proxy agent (1-${MAX}): " 1 ${MAX}
2318 I=$(( $? - 1 ))
2319 PROXY_ACI="${ACILIST[$I]}"
2320 fi
2321
2322 nextFile modify $0
2323 print '
2324 dn: '"${STR[LDAP_BASEDN]}"'
2325 changetype: modify
2326 delete: aci
2327 aci: '"${PROXY_ACI}"'
2328 ' >${TMP[FILE]}
2329
2330 if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
2331 >&${TMPF[FD]} 2>&1
2332 then
2333 Log.fatal "Remove of '${PROXY_ACI_NAME}' ACI failed"
2334 cat ${TMP[FILE]}
2335 return 66
2336 fi
2337
2338 Log.info "Removed '${PROXY_ACI_NAME}' ACI"
2339 return 0
2340 }
2341
2342 Man.addFunc allow_host_read_write_shadow '' '[+NAME?allow_host_read_write_shadow - add host principal read/write permission for shadow data.]
2343 [+DESCRIPTION?Add the ACI \bHOST_ACI_NAME\b to \bSTR[LDAP_BASEDN]]\b unless it already exists.]
2344 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage HOST_ACI_NAME ; }" '}
2345 [+RETURN VALUES]{
2346 [+0?on success (ACI already exists or added successfully).]
2347 [+>= 66?a fatal error occured.]
2348 }
2349 [+SEE ALSO?\bgetACIs()\b, \bldapmodify\b(1).]
2350 '
2351 function allow_host_read_write_shadow {
2352 typeset ACI PATTERN TARGET=''
2353
2354 typeset -a LIST=( )
2355 getACIs LIST || return 66
2356
2357 PATTERN='acl[ ]+"?('"${HOST_ACI_NAME}|${HOST_ACI_NAME// /_}"')"?'
2358 findACI LIST "${HOST_ACI_NAME}" "${PATTERN}" || return 0
2359
2360 (( ! TMPF[IS_OPENDJ] )) && \
2361 TARGET='(target = "ldap:///'"${STR[LDAP_BASEDN]}"'")' # OD: redundant
2362
2363 nextFile modify $0
2364 print '
2365 dn: '"${STR[LDAP_BASEDN]}"'
2366 changetype: modify
2367 add: aci
2368 aci: '"${TARGET}"'(targetattr = "shadowLastChange || shadowMin || shadowMax || shadowWarning || shadowInactive || shadowExpire || shadowFlag || userPassword || loginShell || homeDirectory || gecos")
2369 (
2370 version 3.0; acl '"${HOST_ACI_NAME}"';
2371 allow (write,compare,read,search) authmethod = "sasl GSSAPI" and userdn = "ldap:///cn=*+ipHostNumber=*,ou=Hosts,'"${STR[LDAP_BASEDN]}"';
2372 )
2373 ' > ${TMP[FILE]}
2374
2375 if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
2376 >&${TMPF[FD]} 2>&1
2377 then
2378 Log.fatal 'Remove of '${ACI_NAME}' ACI failed'
2379 return 66
2380 fi
2381
2382 showProgress "ACI '${ACI_NAME}' added."
2383 return 0
2384 }
2385
2386 Man.addFunc find_and_delete_ACI '' '[+NAME?find_and_delete_ACI - find and delete an ACI in the given list.]
2387 [+DESCRIPTION?Find the first ACI which matches \aregex\a in the indexed array of ACIs \avname\a and delete it. If no ACI matches, the function does nothing and returns. Otherwise it tries to delete it from \bSTR[LDAP_BASEDN]]\b and prints out a message using \aaciName\a.]
2388 [+RETURN VALUES]{
2389 [+0?on success (no ACI matched or ACI removed successfully).]
2390 [+66?an error occured when removing the matched ACI.]
2391 }
2392 [+SEE ALSO?\bgetACIs()\b, \bldapmodify\b(1)]
2393 \n\n\avname\a \aaciName\a \aregex\a
2394 '
2395 function find_and_delete_ACI {
2396 typeset -n LIST=$1
2397 typeset ACI_NAME="$2" REGEX="$3" DEL='' ACI
2398
2399 for ACI in "${LIST[@]}" ; do
2400 [[ ${ACI} =~ ${REGEX} ]] && DEL="${ACI}" && break
2401 done
2402 [[ -z ${DEL} ]] && return 0
2403
2404 nextFile modify "${0}-${ACI_NAME}"
2405 print '
2406 dn: '"${STR[LDAP_BASEDN]}"'
2407 changetype: modify
2408 delete: aci
2409 aci: '"${DEL}"'
2410 ' > ${TMP[FILE]}
2411
2412 if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
2413 >&${TMPF[FD]} 2>&1
2414 then
2415 Log.fatal "Remove of '${ACI_NAME}' ACI failed"
2416 return 66
2417 fi
2418
2419 showProgress "ACI '${ACI_NAME}' deleted."
2420 return 0
2421 }
2422
2423 Man.addFunc deny_non_host_shadow_access '' '[+NAME?deny_non_host_shadow_access - add a deny non-host access to shadow data.]
2424 [+DESCRIPTION?Add the ACI \bNON_HOST_ACI_NAME\b to \bSTR[LDAP_BASEDN]]\b unless it already exists. If it does not exists the ACI \bNON_ADMIN_ACI_NAME\b gets deleted first if available.]
2425 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage NON_HOST_ACI_NAME NON_ADMIN_ACI_NAME ; }" '}
2426 [+RETURN VALUES]{
2427 [+0?on success (ACI already exists or added successfully).]
2428 [+>= 66?a fatal error occured.]
2429 }
2430 [+SEE ALSO?\bgetACIs()\b, \bfind_and_delete_ACI()\b, \bldapmodify\b(1).]
2431 '
2432 function deny_non_host_shadow_access {
2433 typeset ACI PATTERN TARGET=''
2434
2435 typeset -a LIST=( )
2436 getACIs LIST || return 66
2437
2438 # If an ACI with ${NON_HOST_ACI_NAME} already exists, we are done
2439 PATTERN='acl[ ]+"?('"${NON_HOST_ACI_NAME}|${NON_HOST_ACI_NAME// /_}"')"?'
2440 findACI LIST "${NON_HOST_ACI_NAME}" "${PATTERN}" || return 0
2441
2442 # The deny_non_admin_shadow_access and deny_non_host_shadow_access ACIs
2443 # should be mutually exclusive, so if the former exists, delete it
2444 PATTERN='acl[ ]+"?('"${NON_ADMIN_ACI_NAME}|${NON_ADMIN_ACI_NAME// /_}"')"?'
2445 find_and_delete_ACI LIST "${NON_ADMIN_ACI_NAME}" "${PATTERN}" || return 67
2446
2447 (( ! TMPF[IS_OPENDJ] )) && \
2448 TARGET='(target = "ldap:///'"${STR[LDAP_BASEDN]}"'")' # OD: redundant
2449
2450 nextFile modify $0
2451 print '
2452 dn: '"${STR[LDAP_BASEDN]}"'
2453 changetype: modify
2454 add: aci
2455 aci: '"${TARGET}"'(targetattr = "shadowLastChange || shadowMin || shadowMax ||shadowWarning || shadowInactive || shadowExpire || shadowFlag || userPassword")
2456 (
2457 version 3.0; acl "'"${NON_HOST_ACI_NAME}"'";
2458 deny (write,read,search,compare) userdn != "ldap:///cn=*+ipHostNumber=*,ou=Hosts,'"${STR[LDAP_BASEDN]}"'";
2459 )
2460 ' > ${TMP[FILE]}
2461
2462 if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
2463 >&${TMPF[FD]} 2>&1
2464 then
2465 Log.fatal "Adding ACI '${NON_HOST_ACI_NAME}' failed"
2466 return 67
2467 fi
2468
2469 showProgress "ACI '${NON_HOST_ACI_NAME}' added."
2470 return 0
2471 }
2472
2473 Man.addFunc get_adminDN '' '[+NAME?get_adminDN - ask user for Admin DN.]
2474 [+DESCRIPTION?Ask the user for the Admin DN and store it into \bSTR[LDAP_BASEDN]]\b.]
2475 [+SEE ALSO?\bget_ans()\b.]
2476 '
2477 function get_adminDN {
2478 get_ans 'Enter DN for the administrator:' \
2479 "cn=admin,ou=profile,${STR[LDAP_BASEDN]}"
2480 STR[LDAP_ADMINDN]="${ANS}"
2481 }
2482
2483 Man.addFunc get_admin_pw '' '[+NAME?get_admin_pw - ask user for Admin password]
2484 [+DESCRIPTION?Ask the user for the Admin password and store it into \bSTR[LDAP_ADMIN_CRED]]\b.]
2485 [+SEE ALSO?\bget_passwd()\b.]
2486 '
2487 function get_admin_pw {
2488 get_passwd 'Enter passwd for the administrator:'
2489 STR[LDAP_ADMIN_CRED]="${ANS}"
2490 }
2491
2492 Man.addFunc add_admin '' '[+NAME?add_admin - Add administrator identity.]
2493 [+DESCRIPTION?Add the \bSTR[LDAP_ADMINDN]]\b entry with the password \bSTR[LDAP_ADMIN_CRED]]\b unless it already exists.]
2494 [+RETURN VALUES]{
2495 [+0?on success (entry already exists or added successfully).]
2496 [+>= 66?a fatal error occured.]
2497 }
2498 [+SEE ALSO?\bldapsearch\b(1), \bldapmodify\b(1).]
2499 '
2500 function add_admin {
2501 if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b "${STR[LDAP_ADMINDN]}" \
2502 -s base 'objectclass=*' >/dev/null 2>&1
2503 then
2504 showProgress "Administrator identity exists."
2505 return 0
2506 fi
2507
2508 typeset CN="${STR[LDAP_ADMINDN]%%,*}"
2509 CN="${CN#*=}"
2510
2511 nextFile add $0
2512 print '
2513 dn: '"${STR[LDAP_ADMINDN]}"'
2514 cn: '"${CN}"'
2515 sn: '"${CN}"'
2516 objectclass: top
2517 objectclass: person
2518 userpassword: '"${STR[LDAP_ADMIN_CRED]}"'
2519 ' > ${TMP[FILE]}
2520
2521 if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
2522 >&${TMPF[FD]} 2>&1
2523 then
2524 Log.fatal 'Adding administrator identity failed'
2525 return 66
2526 fi
2527
2528 showProgress 'Administrator identity added.'
2529 return 0
2530 }
2531
2532 Man.addFunc allow_admin_read_write_shadow '' '[+NAME?allow_admin_read_write_shadow - add Admin read/write permission for shadow, rbac and mount data.]
2533 [+DESCRIPTION?Add the ACI \bADMIN_ACI_NAME\b to \bSTR[LDAP_BASEDN]]\b unless it already exists. Also tries to remove old similar ACIs if they exist.]
2534 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage ADMIN_ACI_NAME ; }" '}
2535 [+RETURN VALUES]{
2536 [+0?on success (aci already exists or addition was successfull).]
2537 [+>= 66?a fatal error occured.]
2538 }
2539 [+SEE ALSO?\bgetACIs()\b, \bfind_and_delete_ACI()\b, \bldapmodify\b(1).]
2540 '
2541 function allow_admin_read_write_shadow {
2542 typeset PERMS='write,compare,read,search,add,delete' \
2543 ACI RBAC PATTERN TARGET=''
2544
2545 typeset -a LIST=( )
2546 getACIs LIST || return 66
2547
2548 # If the ACI already exists, we are done
2549 PATTERN='acl[ ]+"?('"${ADMIN_ACI_NAME}|${ADMIN_ACI_NAME// /_}"')"?'
2550 PATTERN+='.*\('"${PERMS}"'\).*'"${STR[LDAP_ADMINDN]}"
2551 findACI LIST "${ADMIN_ACI_NAME}" "${PATTERN}" || return 0
2552
2553 # If an ACI with ${ADMIN_ACI_NAME} and "(write|write,compare,read,search)"
2554 # and ${LDAP_ADMINDN} exists, delete it
2555 PATTERN='acl[ ]+"?('"${ADMIN_ACI_NAME}|${ADMIN_ACI_NAME// /_}"')"?'
2556 PATTERN+='.*\(write\).*'"${STR[LDAP_ADMINDN]}"
2557 find_and_delete_ACI LIST "${ADMIN_ACI_NAME}" "${PATTERN}" || return 67
2558
2559 PATTERN='acl[ ]+"?('"${ADMIN_ACI_NAME}|${ADMIN_ACI_NAME// /_}"')"?'
2560 PATTERN+='.*\(write,compare,read,search\).*'"${STR[LDAP_ADMINDN]}"
2561 find_and_delete_ACI LIST "${ADMIN_ACI_NAME}" "${PATTERN}" || return 68
2562
2563 RBAC='objectClass || uid || uidNumber || gidNumber || cn'
2564 RBAC+=' || SolarisAttrKeyValue || SolarisAttrShortDesc'
2565 RBAC+=' || SolarisAttrLongDesc || SolarisKernelSecurityPolicy'
2566 RBAC+=' || SolarisProfileType || SolarisProfileId || SolarisUserQualifier'
2567 RBAC+=' || SolarisReserved1 || SolarisReserved2'
2568 RBAC+=' || SolarisAttrReserved1 || SolarisAttrReserved2'
2569 RBAC+=' || SolarisProjectID || SolarisProjectName'
2570 RBAC+=' || SolarisProjectAttr || memberUid || memberGid || description'
2571 RBAC+=' || automountKey || automountMapName || automountInformation'
2572 RBAC+=' || ipTnetTemplateName || ipTnetNumber'
2573
2574 (( ! TMPF[IS_OPENDJ] )) && \
2575 TARGET='(target = "ldap:///'"${STR[LDAP_BASEDN]}"'")' # OD: redundant
2576
2577 nextFile modify $0
2578 print '
2579 dn: '"${STR[LDAP_BASEDN]}"'
2580 changetype: modify
2581 add: aci
2582 aci: '"${TARGET}"'(targetattr = "shadowLastChange || shadowMin || shadowMax || shadowWarning || shadowInactive || shadowExpire || shadowFlag || userPassword || loginShell || homeDirectory || gecos || '"${RBAC}"'")
2583 (
2584 version 3.0; acl "'${ADMIN_ACI_NAME}'";
2585 allow ('"${PERMS}"') userdn = "ldap:///'"${STR[LDAP_ADMINDN]}"'";
2586 )
2587 ' > ${TMP[FILE]}
2588
2589 if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
2590 >&${TMPF[FD]} 2>&1
2591 then
2592 Log.fatal "Adding '${ADMIN_ACI_NAME}' ACI failed"
2593 return 69
2594 fi
2595
2596 showProgress "ACI '${ADMIN_ACI_NAME}' added."
2597 return 0
2598 }
2599
2600 Man.addFunc deny_non_admin_shadow_access '' '[+NAME?deny_non_admin_shadow_access - add a deny Admin access to shadow data.]
2601 [+DESCRIPTION?Add the ACI \bNON_ADMIN_ACI_NAME\b to \bSTR[LDAP_BASEDN]]\b unless it already exists. If it does not exists the ACI \bNON_HOST_ACI_NAME\b gets deleted first if available.]
2602 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage NON_ADMIN_ACI_NAME NON_HOST_ACI_NAME ; }" '}
2603 [+RETURN VALUES]{
2604 [+0?on success (ACI already exists or added successfully).]
2605 [+>= 66?a fatal error occured.]
2606 }
2607 [+SEE ALSO?\bgetACIs()\b, \bfind_and_delete_ACI()\b, \bldapmodify\b(1).]
2608 '
2609 function deny_non_admin_shadow_access {
2610 typeset TARGET=''
2611 typeset -a LIST=( )
2612 getACIs LIST || return 66
2613
2614 # If the ACI already exists, we are done
2615 PATTERN='acl[ ]+"?('"${NON_ADMIN_ACI_NAME}|${NON_ADMIN_ACI_NAME// /_}"')"?'
2616 findACI LIST "${NON_ADMIN_ACI_NAME}" "${PATTERN}" || return 0
2617
2618 # The deny_non_admin_shadow_access and deny_non_host_shadow_access ACIs
2619 # should be mutually exclusive, so if the latter exists, delete it
2620 PATTERN='acl[ ]+"?('"${NON_HOST_ACI_NAME}|${NON_HOST_ACI_NAME// /_}"')"?'
2621 find_and_delete_ACI LIST "${NON_HOST_ACI_NAME}" "${PATTERN}" || return 67
2622
2623 (( ! TMPF[IS_OPENDJ] )) && \
2624 TARGET='(target = "ldap:///'"${STR[LDAP_BASEDN]}"'")' # OD: redundant
2625
2626 nextFile modify $0
2627 print '
2628 dn: '"${STR[LDAP_BASEDN]}"'
2629 changetype: modify
2630 add: aci
2631 aci: '"${TARGET}"'(targetattr = "shadowLastChange || shadowMin || shadowMax || shadowWarning || shadowInactive || shadowExpire || shadowFlag || userPassword")
2632 (
2633 version 3.0; acl "'"${NON_ADMIN_ACI_NAME}"'";
2634 deny (write,read,search,compare,add,delete) userdn != "ldap:///'"${STR[LDAP_ADMINDN]}"'";
2635 )
2636 ' > ${TMP[FILE]}
2637
2638 if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
2639 >&${TMPF[FD]} 2>&1
2640 then
2641 Log.fatal "Adding '${NON_ADMIN_ACI_NAME}' ACI failed"
2642 ${CAT} ${TMP[FILE]}
2643 return 68
2644 fi
2645
2646 showProgress "ACI '${NON_ADMIN_ACI_NAME}' added."
2647 return 0
2648 }
2649
2650 Man.addFunc setup_shadow_update '' '[+NAME?setup_shadow_update - set up shadow update.]
2651 [+DESCRIPTION?Check whether the profile \bSTR[LDAP_PROFILE_NAME]]\b for \bSTR[LDAP_BASEDN]]\b exists. If not simply notify the user and return. Otherwise check whether the profile uses authenticationMethod "GSSAPI" and credentialLevel "self". If so ask the user whether to use host or "Admin" user principal for shadow updates and collect the related info. Sets \bINT[NEED_HOSTACL]]\b if the host principal should be used for shadow update (requires that \bTMPF[GSSAPI_AUTH_MAY_BE_USED]]\b is already set).]
2652 [+RETURN VALUES]{
2653 [+0?on success.]
2654 [+>= 66? a fatal error occured.]
2655 }
2656 [+SEE ALSO?\bldapsearch\b(1), \bget_confirm()\b, \bdelete_proxy_read_pw()\b, \ballow_host_read_write_shadow()\b, \bdeny_non_host_shadow_access()\b, \bget_adminDN()\b, \bget_admin_pw()\b, \badd_admin()\b, \ballow_admin_read_write_shadow()\b, \bdeny_non_admin_shadow_access()\b.]
2657 '
2658 function setup_shadow_update {
2659 # get content of the profile
2660 integer CN=0 GSSAPI=0 SELF=0
2661 typeset -l LINE
2662
2663 ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
2664 -b "cn=${STR[LDAP_PROFILE_NAME]},ou=profile,${STR[LDAP_BASEDN]}" \
2665 -s base 'objectclass=*' 2>/dev/null | \
2666 while read LINE ; do
2667 [[ ${LINE:0:3} == 'cn=' ]] && CN=1
2668 [[ ${LINE:0:21} == 'authenticationmethod=' && ${LINE:21} == 'GSSAPI' ]]\
2669 && GSSAPI=1
2670 [[ ${LINE:0:16} == 'credentiallevel=' && ${LINE:16} == 'self' ]] \
2671 && SELF=1
2672 done
2673 if (( ! CN )); then
2674 Log.verbose "Profile '${STR[LDAP_PROFILE_NAME]}' does not exist"
2675 return 0
2676 fi
2677
2678 # If authenticationMethod has 'GSSAPI' and credentialLevel
2679 # has 'self', ask to use the host principal for shadow update
2680 if (( TMPF[GSSAPI_AUTH_MAY_BE_USED] && GSSAPI && SELF )); then
2681 INT[NEED_HOSTACL]=1
2682 fi
2683 Log.verbose "NEED_HOSTACL = ${INT[NEED_HOSTACL]}"
2684
2685 if (( INT[NEED_HOSTACL] )); then
2686 get_confirm 'Use host principal for shadow data update (y/n/h)?' 'y' \
2687 'use_host_principal_help'
2688 if (( $? )); then
2689 delete_proxy_read_pw || return 66
2690 allow_host_read_write_shadow || return 67
2691 deny_non_host_shadow_access || return 68
2692 Log.info 'Shadow update has been enabled'
2693 else
2694 Log.warn 'Shadow update may not work'
2695 fi
2696 return 0
2697 fi
2698
2699 get_confirm 'Add the administrator identity (y/n/h)?' 'y' \
2700 'add_admin_cred_help'
2701 if (( $? )); then
2702 get_adminDN
2703 get_admin_pw
2704 add_admin || return 69
2705 delete_proxy_read_pw || return 66
2706 allow_admin_read_write_shadow || return 70
2707 deny_non_admin_shadow_access || return 71
2708 Log.info 'Shadow update has been enabled'
2709 else
2710 Log.warn 'No administrator identity specified, shadow update may not' \
2711 'work'
2712 fi
2713 return 0
2714 }
2715
2716 Man.addFunc get_srv_list '' '[+NAME?get_srv_list - Ask user for default server list.]
2717 [+DESCRIPTION?Ask the user for the default server list and store it into \bSTR[LDAP_SERVER_LIST]]\b.]
2718 [+SEE ALSO?\bget_ans()\b, \bdisplay_msg()\b.]
2719 '
2720 function get_srv_list {
2721 # If LDAP_SERVER_LIST is NULL, then set, otherwise leave alone
2722 if [[ -z ${STR[LDAP_SERVER_LIST]} ]]; then
2723 ANS=${ ${GETENT} hosts ${STR[DS_HOST]} ; }
2724 STR[LDAP_SERVER_LIST]=${ANS%%[[:space:]]*}
2725 if (( INT[DS_PORT] != 389 )); then
2726 STR[LDAP_SERVER_LIST]="${STR[LDAP_SERVER_LIST]}:${INT[DS_PORT]}"
2727 fi
2728 fi
2729
2730 while : ; do
2731 get_ans 'Default server list (h=help):' "${STR[LDAP_SERVER_LIST]}"
2732 case "${ANS}" in
2733 [Hh] | help | Help | '?') display_msg 'def_srvlist_help' ;;
2734 * ) break ;;
2735 esac
2736 done
2737 STR[LDAP_SERVER_LIST]="${ANS}"
2738 }
2739
2740 Man.addFunc get_pref_srv '' '[+NAME?get_pref_srv - Ask user for preferred server list.]
2741 [+DESCRIPTION?Ask the user for the preferred server list and store it into \bSTR[LDAP_PREF_SRVLIST]]\b (overrides the server list).]
2742 [+SEE ALSO?\bget_ans()\b, \bdisplay_msg()\b.]
2743 '
2744 function get_pref_srv {
2745 while : ; do
2746 get_ans 'Preferred server list (h=help):' "${STR[LDAP_PREF_SRVLIST]}"
2747 case "${ANS}" in
2748 [Hh] | help | Help | '?') display_msg 'pref_srvlist_help' ;;
2749 * ) break ;;
2750 esac
2751 done
2752 STR[LDAP_PREF_SRVLIST]="${ANS}"
2753 }
2754
2755 Man.addFunc get_search_scope '' '[+NAME?get_search_scope - Ask user for search scope.]
2756 [+DESCRIPTION?Ask the user for the search scope and store it into \bSTR[LDAP_SEARCH_SCOPE]]\b.]
2757 [+RETURN VALUES]{
2758 [+1?search scope "one" selected.]
2759 [+2?search scope "sub" selected.]
2760 }
2761 [+SEE ALSO?\bget_ans()\b, \bdisplay_msg()\b.]
2762 '
2763 function get_search_scope {
2764 integer RES
2765 get_menu_choice 'Choose desired search scope (1=one, 2=sub, h=help): ' \
2766 1 2 1 srch_scope_help
2767 (( $? == 2 )) && { STR[LDAP_SEARCH_SCOPE]='sub' ; return 2 ; }
2768 STR[LDAP_SEARCH_SCOPE]='one'
2769 return 1
2770 }
2771
2772 Man.addFunc get_cred_level '' '[+NAME?get_cred_level - Ask user for credential level.]
2773 [+DESCRIPTION?Ask the user for the client credential level to use and store it into \bSTR[LDAP_CRED_LEVEL]]\b.]
2774 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage CRED_LEVELS STR ; }" '}
2775 [+RETURN VALUES?The index wrt. \bCRED_LEVELS\b of the selected credential level \b+1\b.]
2776 [+SEE ALSO?\bget_ans()\b, \bdisplay_msg()\b.]
2777 '
2778 function get_cred_level {
2779 integer RES
2780 typeset PROMPT=''
2781 (( INT[GSSAPI_ENABLE] )) && PROMPT='"self" is needed for GSSAPI profile.\n'
2782 PROMPT+='Choose Credential level (identity) [h=help]:'
2783
2784 get_menu_choice "${PROMPT}" 1 4 1 'cred_lvl_help' 'cred_level_menu'
2785 RES=$?
2786 STR[LDAP_CRED_LEVEL]="${CRED_LEVELS[RES-1]}"
2787 return ${RES}
2788 }
2789
2790 Man.addFunc get_auth '' '[+NAME?get_auth - ask user for authentication methods.]
2791 [+DESCRIPTION?Ask the user for authentication methods to enable and store them as a semicolon separated list into \bSTR[LDAP_AUTHMETHOD | LDAP_SRV_AUTHMETHOD_{PAM|KEY|CMD}}]]\b and set \bINT[NEED_SRVAUTH_{PAM|KEY|CMD}]]\b to 0 depending on the given \atype\a (either "client", "pam_ldap", "keyserv", or "passwd-cmd") and selected methods.]
2792 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage AUTH_METHODS STR ; }" '}
2793 [+RETURN VALUES]{
2794 [+0?on success.]
2795 [+-1?if an invalid \atype\a was given.]
2796 }
2797 [+SEE ALSO?\bget_menu_choice()\b, \bget_confirm_nodef()\b.]
2798 \n\n\atype\a
2799 '
2800 function get_auth {
2801 typeset TYPE=$1 VNAME HELPTAG MENU
2802 integer RES MAX=${#AUTH_METHODS[@]} OFFSET=0
2803 typeset -a SELECTED=( )
2804 typeset -u UTYPE=${TYPE}
2805
2806 case "${TYPE}" in
2807 client) VNAME=LDAP_AUTHMETHOD ; OFFSET=1 ; UTYPE='DEFAULT' ;;
2808 pam_ldap) VNAME=LDAP_SRV_AUTHMETHOD_PAM ;;
2809 keyserv) VNAME=LDAP_SRV_AUTHMETHOD_KEY ;;
2810 passwd-cmd) VNAME=LDAP_SRV_AUTHMETHOD_CMD ;;
2811 *) print -u2 "${.sh.fun}() bug: invalid type argument" && return -1 ;;
2812 esac
2813
2814 typeset ASK='' VAL='' M=''
2815 if (( OFFSET )); then
2816 # client
2817 (( INT[GSSAPI_ENABLE] )) && \
2818 ASK='"sasl/GSSAPI" is needed for GSSAPI profile.\n'
2819 ASK+='Choose DEFAULT authentication (bind) method (0=reset, h=help):'
2820 MENU='auth_method_menu'
2821 HELPTAG='auth_help'
2822 else
2823 ASK="Choose ${UTYPE} authentication (bind) method (0=reset, h=help):"
2824 (( MAX-- ))
2825 MENU='srvauth_method_menu'
2826 HELPTAG='srvauth_help'
2827 fi
2828
2829 while : ; do
2830 get_menu_choice "${ASK}" 0 ${MAX} 1 ${HELPTAG} ${MENU}
2831 RES=$?
2832 if (( RES )); then
2833 M=${AUTH_METHODS[RES - OFFSET]}
2834 # avoid doubles
2835 [[ ${VAL} != ~(E)[ ]${M}[ ] ]] && SELECTED+=( ${M} )
2836 VAL=" ${SELECTED[@]} "
2837 M=${VAL// /\;}
2838 M=${M#\;}
2839 else
2840 typeset -a SELECTED=( ) # reset
2841 VAL=''
2842 M=''
2843 fi
2844 print && Log.info "Current authentication method(s): ${M%\;}\n"
2845
2846 get_confirm_nodef "Do you want to add another ${UTYPE} authentication method (y/n)?" \
2847 && break
2848 done
2849 M=${M%\;}
2850 if (( ! OFFSET )); then
2851 M=${M//\;/\;${TYPE}:}
2852 if [[ -n ${M} ]]; then
2853 STR[${VNAME}]="${TYPE}:${M}"
2854 else
2855 STR[${VNAME}]=''
2856 INT[NEED_SRVAUTH_${TYPE##*_}]=0
2857 fi
2858 else
2859 STR[${VNAME}]="${M}"
2860 fi
2861 Log.verbose "Selected ${UTYPE} authentication methods: '${STR[${VNAME}]}'"
2862 return 0
2863 }
2864
2865 Man.addFunc get_followref '' '[+NAME?get_followref - Ask user whether or not to follow referrals.]
2866 [+DESCRIPTION?Ask the user whether the client should follow referrals. Result gets stored into \bINT[LDAP_FOLLOWREF]]\b.]
2867 [+SEE ALSO?\bget_confirm()\b, \bldapclient\b(1M).]
2868 '
2869 function get_followref {
2870 get_confirm 'Do you want the clients to follow referrals (y/n/h)?' 'n' \
2871 'referrals_help'
2872 INT[LDAP_FOLLOWREF]=$?
2873 }
2874
2875 Man.addFunc get_timelimit '' '[+NAME?get_timelimit - Ask user for search time limit.]
2876 [+DESCRIPTION?Ask the user for the max. time allowed to process a search operation and store it into \bINT[DS_TIMELIMIT]]\b.]
2877 [+RETURN VALUES]{
2878 [+0?on success.]
2879 [+>= 66?a fatal error occured.]
2880 }
2881 [+SEE ALSO?\bis_numeric()\b, \bget_negone_num()\b.]
2882 '
2883 function get_timelimit {
2884 typeset NAME='nsslapd-timelimit' VAL=''
2885 (( TMPF[IS_OPENDJ] )) && NAME='ds-cfg-time-limit' # min val = 0
2886
2887 # Get current timeout value from cn=config
2888 ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b 'cn=config' -s base \
2889 'objectclass=*' "${NAME}" 2>/dev/null | \
2890 while read LINE; do
2891 if [[ ${LINE%%=*} == ${NAME} ]]; then
2892 VAL=${LINE#*=}
2893 break
2894 fi
2895 done
2896 if [[ -z ${VAL} ]]; then
2897 Log.fatal 'Unable to check current search processing timeout of the DS'
2898 return 66
2899 fi
2900 VAL=${VAL%%[[:space:]]*}
2901 is_numeric ${VAL} && NUM=${VAL} || NUM=INT[DS_TIMELIMIT]
2902
2903 get_negone_num "Enter the DS search processing time limit in seconds (current=${NUM})" \
2904 '30'
2905 (( TMPF[IS_OPENDJ] && NUM < 0 )) && NUM=0 # unlimited
2906
2907 INT[DS_TIMELIMIT]=${NUM}
2908 return 0
2909 }
2910
2911 Man.addFunc get_sizelimit '' '[+NAME?get_sizelimit - Ask user for search size limit.]
2912 [+DESCRIPTION?Ask the user for the max. number of entries to return for a single search operation and store it into \bINT[DS_SIZELIMIT]]\b.]
2913 [+RETURN VALUES]{
2914 [+0?on success.]
2915 [+>= 66?a fatal error occured.]
2916 }
2917 [+SEE ALSO?\bis_numeric()\b, \bget_negone_num()\b.]
2918 '
2919 function get_sizelimit {
2920 typeset NAME='nsslapd-sizelimit' VAL=''
2921 (( TMPF[IS_OPENDJ] )) && NAME='ds-cfg-size-limit' # min val = 0
2922
2923 # Get current search sizelimit
2924 ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b 'cn=config' -s base \
2925 'objectclass=*' "${NAME}" 2>/dev/null | \
2926 while read LINE; do
2927 if [[ ${LINE%%=*} == ${NAME} ]]; then
2928 VAL=${LINE#*=}
2929 break
2930 fi
2931 done
2932 if [[ -z ${VAL} ]]; then
2933 Log.fatal 'Unable to check current search entry result limit of the DS'
2934 return 66
2935 fi
2936 is_numeric ${VAL} && NUM=${VAL} || NUM=INT[DS_SIZELIMIT]
2937
2938 get_negone_num "Enter max. entries per search the DS returns (current=${NUM})" '1000'
2939 (( TMPF[IS_OPENDJ] && NUM < 0 )) && NUM=0 # unlimited
2940 INT[DS_SIZELIMIT]=${NUM}
2941 return 0
2942 }
2943
2944 Man.addFunc get_want_crypt '' '[+NAME?get_want_crypt - Ask user whether to store passwords in crypt.]
2945 [+DESCRIPTION?Ask the user whether the default password storage scheme should be set to "CRYPT" and stores the result into \bINT[NEED_CRYPT]]\b.]
2946 [+SEE ALSO?\bget_confirm()\b.]
2947 '
2948 function get_want_crypt {
2949 get_confirm 'Do you want to store passwords in "CRYPT" formats (y/n/h)?' \
2950 'n' 'crypt_help'
2951 INT[NEED_CRYPT]=$?
2952 }
2953
2954 Man.addFunc get_srch_time '' '[+NAME?get_srch_time - Ask user for client search time limit.]
2955 [+DESCRIPTION?Ask the user for the max. time in seconds a client waits for a search result and store it into \bINT[LDAP_SEARCH_TIME_LIMIT]]\b.]
2956 [+SEE ALSO?\bget_negone_num()\b, \bldapclient\b(1M).]
2957 '
2958 function get_srch_time {
2959 get_negone_num 'Client search time limit in seconds (h=help):' \
2960 ${INT[LDAP_SEARCH_TIME_LIMIT]} 'srchtime_help'
2961 INT[LDAP_SEARCH_TIME_LIMIT]=${NUM}
2962 }
2963
2964 Man.addFunc get_prof_ttl '' '[+NAME?get_prof_ttl - Ask user for client profile time to live (TTL).]
2965 [+DESCRIPTION?Ask the user for the max. time in seconds a client may cache its profile before refreshing again and store it into \bINT[LDAP_PROFILE_TTL]]\b.]
2966 [+SEE ALSO?\bget_negone_num()\b, \bldapclient\b(1M).]
2967 '
2968 function get_prof_ttl {
2969 get_negone_num 'Client Profile Time To Live in seconds (h=help):' \
2970 ${INT[LDAP_PROFILE_TTL]} 'profttl_help'
2971 INT[LDAP_PROFILE_TTL]=${NUM}
2972 }
2973
2974 Man.addFunc get_bind_limit '' '[+NAME?get_bind_limit - Ask user for client bind time limit.]
2975 [+DESCRIPTION?Ask the user for the max. time in seconds a client may try to bind to the server and store it into \bINT[LDAP_BIND_LIMIT]]\b.]
2976 [+SEE ALSO?\bget_negone_num()\b, \bldapclient\b(1M).]
2977 '
2978 function get_bind_limit {
2979 get_negone_num 'Client bind time limit in seconds (h=help):' \
2980 ${INT[LDAP_BIND_LIMIT]} 'bindlim_help'
2981 INT[LDAP_BIND_LIMIT]=${NUM}
2982 }
2983
2984 Man.addFunc get_want_shadow_update '' '[+NAME?get_want_shadow_update - Ask user whether to enable shadow update.]
2985 [+DESCRIPTION?Ask the user whether to enable shadow update. Set \bINT[LDAP_ENABLE_SHADOW_UPDATE]]\b to 0 if not desired, to 1 otherwise.]
2986 [+SEE ALSO?\bget_confirm()\b.]
2987 '
2988 function get_want_shadow_update {
2989 get_confirm 'Do you want to enable shadow update (y/n/h)?' 'n' \
2990 'enable_shadow_update_help'
2991 INT[LDAP_ENABLE_SHADOW_UPDATE]=$?
2992 }
2993
2994 ######################################################################
2995 # FUNCTIONS FOR Service Search Descriptor's START HERE.
2996 ######################################################################
2997 Man.addFunc add_ssd '' '[+NAME?add_ssd - Ask user for SSD to add.]
2998 [+DESCRIPTION?Ask the user for the ID:BASE:SCOPE and add it to \bSSD\b list.]
2999 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage SSD ; }" '}
3000 [+SEE ALSO?\bget_ans\b, \bget_ans_req()\b.]
3001 '
3002 function add_ssd {
3003 typeset ID='' BASE='' X
3004 typeset -l SCOPE=''
3005 integer FOUND
3006
3007 while : ; do
3008 get_ans 'Enter the service name (e.g. passwd):'
3009 [[ -z ${ANS} ]] && return
3010 [[ ${ANS} =~ [:] ]] && print 'Invalid service name' && continue
3011
3012 FOUND=0
3013 for X in "${SSD[@]}" ; do
3014 [[ ${X%%:*} == ${ANS} ]] && FOUND=1 && break
3015 done
3016 (( ! FOUND )) && break
3017 Log.warn "An SSD for '${ANS}' already exists:\n${X}\n"
3018 done
3019 ID="${ANS}"
3020
3021 while : ; do
3022 get_ans_req 'Enter the search base (e.g. ou=people,o=inet):'
3023 [[ ${ANS} != ~(E)[:] ]] && break
3024 Log.warn 'Invalid search base' && continue
3025 done
3026 BASE="${ANS}"
3027
3028 while : ; do
3029 get_ans_req "Enter the search scope (one|sub):"
3030 SCOPE=${ANS}
3031 [[ ${SCOPE} == 'one' || ${SCOPE} == 'sub' ]] && break
3032 Log.warn "'${ANS}' is NOT valid - Enter 'one' or 'sub'"
3033 done
3034
3035 SSD+=( "${ID}:${BASE}?${SCOPE}" )
3036 }
3037
3038 Man.addFunc delete_ssd '' '[+NAME?delete_ssd - Ask user which SSD to delete.]
3039 [+DESCRIPTION?Ask the user for the ID of the SSD to delete and remove it from \bSSD\b list.]
3040 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage SSD ; }" '}
3041 [+SEE ALSO?\bget_ans()\b.]
3042 '
3043 function delete_ssd {
3044 get_ans 'Enter the service name of the SSD to delete (e.g. passwd):'
3045 [[ -z ${ANS} ]] && return
3046
3047 typeset X
3048 integer I FOUND=-1 MAX=${#SSD[@]}
3049
3050 for (( I=0; I < MAX ; I++ )); do
3051 X=${SSD[I]}
3052 [[ ${X%%:*} == ${ANS} ]] && FOUND=$I && break
3053 done
3054 if (( FOUND == -1 )); then
3055 Log.warn "Invalid service name: '${ANS}' not present in list"
3056 return
3057 fi
3058 (( FOUND == 0 )) && unset SSD[0] && return
3059
3060 # need to do a little bit more, since ksh allows to remove the 1st entry,
3061 # only (i.e. like "shift 1" for positional params)
3062 for (( I=FOUND; I > 0; I-- )); do
3063 SSD[${I}]="${SSD[I-1]}"
3064 done
3065 unset SSD[0]
3066 }
3067
3068 Man.addFunc modify_ssd '' '[+NAME?modify_ssd - Allow user to modify an SSD.]
3069 [+DESCRIPTION?Ask the user for the ID of the SSD to modify, let the user modify it and finally save changes back to the \bSSD\b list.]
3070 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage SSD ; }" '}
3071 [+SEE ALSO?\bget_ans()\b, \bread\b(1).]
3072 '
3073 function modify_ssd {
3074 get_ans 'Enter the service name of the SSD to modify:'
3075 [[ -z ${ANS} ]] && return
3076
3077 typeset ID BASE
3078 typeset -l SCOPE
3079 integer I FOUND=-1 MAX=${#SSD[@]}
3080 for (( I=0; I < MAX ; I++ )); do
3081 X=${SSD[I]}
3082 [[ ${X%%:*} == ${ANS} ]] && FOUND=$I && break
3083 done
3084 if (( FOUND == -1 )); then
3085 Log.warn "Invalid service name: '${ANS}'"
3086 return 0
3087 fi
3088
3089 # most users expect emacs edit behavior (don't have a proper profile)
3090 set -o emacs
3091 read -v X?'Current SSD: '
3092
3093 # now verify
3094 ID=${X%%:*}
3095 BASE=${.sh.match#:}
3096 SCOPE=${BASE#*$'?'}
3097 BASE=${.sh.match%$'?'}
3098 if [[ -z ${ID} || -z ${BASE} || -z ${SCOPE} ]] || \
3099 [[ ${SCOPE} != 'one' && ${SCOPE} != 'sub' ]]
3100 then
3101 Log.warn 'SSD is invalid. Change skipped'
3102 return
3103 fi
3104 SSD[${FOUND}]="${ID}:${BASE}?${SCOPE}"
3105 }
3106
3107 Man.addFunc reset_ssd '' '[+NAME?reset_ssd - Blank out current list of SSDs.]
3108 [+DESCRIPTION?Clear the \bSSD\b array.]
3109 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage SSD ; }" '}
3110 '
3111 function reset_ssd {
3112 SSD=( )
3113 unset SSD[0] # required otherwise it would contain a single '\n'. Bug?
3114 }
3115
3116 Man.addFunc display_ssd '' '[+NAME?display_ssd - Display current SSD list.]
3117 [+DESCRIPTION?Display the current \bSSD\b list and return, when the user hit the enter key.]
3118 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage SSD ; }" '}
3119 '
3120 function display_ssd {
3121 typeset X
3122 print '
3123 Current Service Search Descriptors:
3124 =================================='
3125 for X in "${SSD[@]}" ; do
3126 print " ${X}"
3127 done
3128 print '\nHit return to continue.'
3129 read
3130 }
3131
3132 Man.addFunc prompt_ssd '' '[+NAME?prompt_ssd - Get SSDs from user.]
3133 [+DESCRIPTION?Ask the user whether to add/delete/modify/display one or more SSDs currently set and execute the corresponding action.]
3134 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage ANS ; }" '}
3135 [+SEE ALSO?\bdisplay_msg()\b, \bget_ans()\b, \badd_ssd()\b, \bdelete_ssd()\b, \bmodify_ssd()\b, \bdisplay_ssd()\b, \breset_ssd()\b.]
3136 '
3137 function prompt_ssd {
3138 if get_confirm 'Do you wish to setup Service Search Descriptors (y/n/h)?' \
3139 'n' 'ssd_help'
3140 then
3141 return
3142 fi
3143
3144 # Display menu for SSD choices
3145 while : ; do
3146 display_msg prompt_ssd_menu
3147 get_ans 'Enter menu choice:' 'Quit'
3148 case "${ANS}" in
3149 [Qq] | Quit | quit) return ;;
3150 [Aa] | add) add_ssd ;;
3151 [Dd] | delete) delete_ssd ;;
3152 [Mm] | modify) modify_ssd ;;
3153 [Pp] | print | display) display_ssd ;;
3154 [Xx] | reset | clear) reset_ssd ;;
3155 [Hh] | Help | help)
3156 display_msg 'ssd_menu_help '
3157 print ' Press return to continue.'
3158 read
3159 ;;
3160 *) Log.warn "Invalid choice: '${ANS}' please re-enter from menu!" ;;
3161 esac
3162 done
3163 }
3164
3165 ######################################################################
3166 # End Of FUNCTIONS FOR Service Search Descriptor's
3167 ######################################################################
3168 Man.addFunc prompt_config_info '' '[+NAME?prompt_config_info - Ask user for missing config info.]
3169 [+DESCRIPTION?Ask the user for the config info not yet available/read from an '"${PROG}"' config file.]
3170 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage INT STR SSD ; }" '}
3171 [+RETURN VALUES]{
3172 [+0?on success (all info aquired).]
3173 [+>= 66?a fatal error occured.]
3174 }
3175 '
3176 function prompt_config_info {
3177 # Prompt for DS server name
3178 get_ids_server
3179
3180 # Prompt for DS port number
3181 get_ids_port
3182
3183 # Check DS version for compatibility
3184 chk_ids_version || return 66
3185
3186 # Check if the DS supports the VLV
3187 chk_vlv_indexes || return 67
3188
3189 # Get the Directory manager DN and passwd
3190 get_dirmgr_dn
3191 get_dirmgr_pw
3192
3193 get_confirm 'Do you want to modify the DS timelimit for processing searches (y/n/h)?' 'n' 'tlim_help'
3194 INT[NEED_TIME]=$?
3195 if (( INT[NEED_TIME] )); then
3196 get_timelimit || return 70
3197 fi
3198
3199 get_confirm 'Do you want to modify the DS sizelimit - max. entries to return (y/n/h)?' 'n' 'slim_help'
3200 INT[NEED_SIZE]=$?
3201 if (( INT[NEED_SIZE] )); then
3202 get_sizelimit || return 71
3203 fi
3204
3205
3206 # LDAP CLIENT PROFILE SPECIFIC INFORMATION
3207 # (i.e. the fields that show up in the profile)
3208 get_domain
3209 get_basedn || return 68
3210
3211 # Check/Get Kerberos infos
3212 gssapi_setup
3213
3214 get_profile_name
3215
3216 if (( INT[LDAP_ENABLE_SHADOW_UPDATE] ));then
3217 setup_shadow_update || return 69
3218 return 0
3219 fi
3220
3221 get_srv_list
3222 get_pref_srv
3223 get_search_scope
3224 get_followref
3225
3226 # Store passwords in crypt format?
3227 get_want_crypt
3228
3229 # If cred is "anonymous", make auth == "none"
3230 get_cred_level
3231 [[ ${STR[LDAP_CRED_LEVEL]} != anonymous ]] && get_auth 'client'
3232
3233 get_confirm 'Do you want to setup any non-default Authentication Methods (y/n/h)?' 'n' 'srvauth_help'
3234 if (( $? )); then
3235 get_confirm 'Do you want to setup Authentication Methods for "pam_ldap" (y/n/h)?' 'n' 'pam_ldap_help'
3236 INT[NEED_SRVAUTH_PAM]=$?
3237 (( INT[NEED_SRVAUTH_PAM] )) && get_auth 'pam_ldap'
3238
3239 get_confirm 'Do you want to setup Authentication Methods for "keyserv" (y/n/h)?' 'n' 'keyserv_help'
3240 INT[NEED_SRVAUTH_KEY]=$?
3241 (( INT[NEED_SRVAUTH_KEY] )) && get_auth 'keyserv'
3242
3243 get_confirm 'Do you want to setup Authentication Methods for "passwd-cmd (y/n/h)?' 'n' 'passwd-cmd_help'
3244 INT[NEED_SRVAUTH_CMD]=$?
3245 (( INT[NEED_SRVAUTH_CMD] )) && get_auth 'passwd-cmd'
3246 fi
3247
3248 # Get client timeouts
3249 get_srch_time
3250 get_prof_ttl
3251 get_bind_limit
3252
3253 get_want_shadow_update
3254
3255 reset_ssd
3256 prompt_ssd
3257
3258 show_vars
3259
3260 Log.printMarker
3261 return 0
3262 }
3263 ######################################################################
3264 # End Of FUNCTIONS FOR prompt_config_info()
3265 ######################################################################
3266
3267
3268 ######################################################################
3269 # FUNCTIONS FOR display_summary() START HERE.
3270 ######################################################################
3271 Man.addFunc get_proxyagent '' '[+NAME?get_proxyagent - Ask user for the proxy agent DN and password.]
3272 [+DESCRIPTION?Ask the user for the proxy agent DN and password to use and store it into \bSTR[LDAP_PROXYAGENT]]\b, \bSTR[LDAP_PROXYAGENT_CRED]]\b.]
3273 [+SEE ALSO?\bget_ans()\b.]
3274 '
3275 function get_proxyagent {
3276 STR[LDAP_PROXYAGENT]="cn=proxyagent,ou=profile,${STR[LDAP_BASEDN]}"
3277 get_ans 'Enter DN for proxy agent:' "${STR[LDAP_PROXYAGENT]}"
3278 STR[LDAP_PROXYAGENT]="${ANS}"
3279 get_passwd 'Enter passwd for proxyagent:'
3280 STR[LDAP_PROXYAGENT_CRED]="${ANS}"
3281 }
3282
3283 Man.addFunc display_summary '' '[+NAME?display_summary - Display a summary of values entered and let the user modify values at will.]
3284 [+DESCRIPTION?Display a summary of all configuration relevant info and let the user re-enter data if needed.]
3285 '
3286 function display_summary {
3287 # Create lookup table for function names. Needs to be in sync with
3288 # helpTag 'summary_menu' in display_msg()!
3289 typeset -a FN=( 'dummy' ) # dummy for commit and quit
3290 FN+=( 'get_domain' 'get_basedn' 'get_profile_name' )
3291 FN+=( 'get_srv_list' 'get_pref_srv' 'get_search_scope' 'get_cred_level' )
3292 FN+=( 'get_auth client' 'get_followref' )
3293 FN+=( 'get_timelimit' 'get_sizelimit' 'get_want_crypt' )
3294 FN+=( 'get_auth pam_ldap' 'get_auth keyserv' 'get_auth passwd-cmd' )
3295 FN+=( 'get_srch_time' 'get_prof_ttl' 'get_bind_limit' )
3296 FN+=( 'get_want_shadow_update' )
3297 FN+=( 'prompt_ssd' )
3298
3299 # Since menu prompt string is long, set here
3300 typeset PROMPT='Enter config value to change: (1-20 0=commit changes)'
3301 integer RES MAX=${#FN[@]}
3302 (( MAX-- ))
3303
3304 while : ; do
3305 # Display menu and get value in range
3306 get_menu_choice "${PROMPT}" '0' ${MAX} '0' '' 'summary_menu'
3307 RES=$?
3308
3309 # Make sure where not exiting
3310 (( RES == 0 )) && break # quit selected
3311
3312 # Call appropriate function from function table
3313 ${FN[RES]}
3314 done
3315
3316 # If credlevel is still proxy see if user wants a change?
3317 if [[ ${STR[LDAP_CRED_LEVEL]:0:5} == 'proxy' ]]; then
3318 if [[ ${STR[LDAP_AUTHMETHOD]} != none ]]; then
3319 INT[NEED_PROXY]=1
3320 get_proxyagent
3321 else
3322 Log.warn 'Since Authentication method is "none",' \
3323 'credential level will be set to "anonymous"'
3324 STR[LDAP_CRED_LEVEL]='anonymous'
3325 fi
3326 fi
3327
3328 # If shadow update is enabled, set up administrator credential
3329 if (( INT[LDAP_ENABLE_SHADOW_UPDATE] )); then
3330 INT[NEED_ADMIN]=1
3331 if [[ ${STR[LDAP_CRED_LEVEL]} == 'self' && \
3332 ${STR[LDAP_AUTHMETHOD]} == 'sasl/GSSAPI' ]];
3333 then
3334 INT[NEED_HOSTACL]=1
3335 INT[NEED_ADMIN]=0
3336 fi
3337 if (( INT[NEED_ADMIN] )); then
3338 get_adminDN
3339 get_admin_pw
3340 fi
3341 fi
3342
3343 show_vars
3344
3345 get_confirm_nodef '
3346 WARNING: About to start committing changes. (y=continue, n=EXIT)'
3347 if (( ! $? )); then
3348 Log.info 'Terminating setup without making changes at users request'
3349 return 1
3350 fi
3351
3352 Log.printMarker
3353 return 0
3354 }
3355 ######################################################################
3356 # End Of FUNCTIONS FOR display_summary()
3357 ######################################################################
3358
3359 Man.addFunc modify_cn '' '[+NAME?modify_cn - modify objectclass "ipNetwork" to RFC 2307bis.]
3360 [+DESCRIPTION?Change the cn from MUST to MAY in ipNetwork objectclass.]
3361 [+RETURN VALUES]{
3362 [+0?on success.]
3363 [+>= 66?a fatal error occurred.]
3364 }
3365 [+SEE ALSO?\bldapmodify\b(1).]
3366 '
3367 function modify_cn {
3368 getDSobjectclasses || return 66
3369 typeset NEWDEF="'ipNetwork' SUP top STRUCTURAL DESC 'Abstraction of a network. The distinguished value of the cn attribute denotes the canonical name of the network' MUST ipNetworkNumber MAY "'( cn $ ipNetmaskNumber $ l $ description $ manager )'" X-ORIGIN 'draft-howard-rfc2307bis'"
3370
3371 # bis-delta: MUST ( -cn ) MAY ( +cn )
3372 typeset DEF=${OID2ODEF['1.3.6.1.1.1.2.7']}
3373 if [[ -n ${DEF} ]]; then
3374 DEF=${DEF##*MUST*([[:space:]])}
3375 if [[ ${DEF:0:9} == 'ipNetwork' ]]; then
3376 # assume no need to fix, old definition would start with a '('
3377 showProgress 'Schema definition of ipNetwork ok (RFC2307bis).'
3378 return 0
3379 fi
3380 fi
3381
3382 nextFile modify $0
3383 print '
3384 dn: cn=schema
3385 changetype: modify
3386 add: objectclasses
3387 objectclasses: ( 1.3.6.1.1.1.2.7 NAME '"${NEWDEF}"')
3388 ' > ${TMP[FILE]}
3389
3390 if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
3391 >&${TMPF[FD]} 2>&1
3392 then
3393 Log.fatal 'Schema update of ipNetwork to RFC2307bis failed'
3394 return 67
3395 fi
3396 showProgress 'Schema update of ipNetwork to RFC2307bis done.'
3397 OID2ODEF['1.3.6.1.1.1.2.7']="${NEWDEF}"
3398 return 0
3399 }
3400
3401 Man.addFunc modify_timelimit '' '[+NAME?modify_timelimit - Set the DS timelimit.]
3402 [+DESCRIPTION?Set the DS timelimit to \bINT[DS_TIMELIMIT]]\b.]
3403 [+RETURN VALUES]{
3404 [+0?on success.]
3405 [+>= 66?a fatal error occurred.]
3406 }
3407 [+SEE ALSO?\bldapmodify\b(1).]
3408 '
3409 function modify_timelimit {
3410 typeset NAME='nsslapd-timelimit'
3411 (( TMPF[IS_OPENDJ] )) && NAME='ds-cfg-time-limit'
3412
3413 nextFile modify $0
3414 print '
3415 dn: cn=config
3416 changetype: modify
3417 replace: '"${NAME}"'
3418 '"${NAME}"': '"${INT[DS_TIMELIMIT]}"' s
3419 ' > ${TMP[FILE]}
3420
3421 if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
3422 >&${TMPF[FD]} 2>&1
3423 then
3424 Log.fatal 'Update of ${NAME} failed'
3425 return 66
3426 fi
3427
3428 showProgress "Changed ${NAME} to ${INT[DS_TIMELIMIT]} in 'cn=config'."
3429 return 0
3430 }
3431
3432 Man.addFunc modify_sizelimit '' '[+NAME?modify_sizelimit - Set the DS sizelimit.]
3433 [+DESCRIPTION?Set the DS sizelimit to \bINT[DS_SIZELIMIT]]\b.]
3434 [+RETURN VALUES]{
3435 [+0?on success.]
3436 [+>= 66?a fatal error occurred.]
3437 }
3438 [+SEE ALSO?\bldapmodify\b(1).]
3439 '
3440 function modify_sizelimit {
3441 typeset NAME='nsslapd-sizelimit'
3442 (( TMPF[IS_OPENDJ] )) && NAME='ds-cfg-size-limit'
3443
3444 nextFile modify $0
3445 print '
3446 dn: cn=config
3447 changetype: modify
3448 replace: '"${NAME}"'
3449 '"${NAME}"': '"${INT[DS_SIZELIMIT]}"'
3450 ' > ${TMP[FILE]}
3451
3452 if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
3453 >&${TMPF[FD]} 2>&1
3454 then
3455 Log.fatal "Update of ${NAME} failed"
3456 return 66
3457 fi
3458
3459 showProgress "Changed ${NAME} to ${INT[DS_SIZELIMIT]} in 'cn=config'."
3460 return 0
3461 }
3462
3463 Man.addFunc modify_pwd_crypt '' '[+NAME?modify_pwd_crypt - modify the passwd storage scheme to use CRYPT.]
3464 [+DESCRIPTION?Set the default password policy of the DS to CRYPT.]
3465 [+RETURN VALUES]{
3466 [+0?on success.]
3467 [+>= 66?a fatal error occurred.]
3468 }
3469 [+SEE ALSO?\bldapmodify\b(1).]
3470 '
3471 function modify_pwd_crypt {
3472 # DS 5.2 moved passwordchangescheme off to a new data structure
3473 typeset -a INFO=( ${TMP[DS_INFO]} )
3474 typeset DN='cn=config' TARGET='passwordStorageScheme' VALUE='CRYPT' MSG=''
3475 typeset FMT='dn: %s\nchangetype: modify\nreplace: %s\n%s: %s\n\n'
3476 nextFile modify $0
3477
3478 if (( TMPF[IS_OPENDJ] )); then
3479 DN='cn=Default Password Policy,cn=Password Policies,cn=config'
3480 TARGET='ds-cfg-default-password-storage-scheme'
3481 VALUE='cn=CRYPT,cn=Password Storage Schemes,cn=config'
3482 else
3483 # DSEE
3484 integer VER=$(( ${INFO[1]} * 1000 + ${INFO[2]} ))
3485 (( VER >= 5002 )) && DN='cn=Password Policy,cn=config'
3486 fi
3487 printf "${FMT}" "${DN}" "${TARGET}" "${TARGET}" "${VALUE}" >${TMP[FILE]}
3488 MSG="Changed '${TARGET}' to 'CRYPT'"
3489
3490 if (( TMPF[IS_OPENDJ] )); then
3491 if (( INT[NEED_CRYPT_IMPORT] )); then
3492 TARGET='ds-cfg-allow-pre-encoded-passwords'
3493 printf "${FMT}" "${DN}" "${TARGET}" "${TARGET}" 'true'>>${TMP[FILE]}
3494 MSG+="and '${TARGET}' to 'true'"
3495 fi
3496 DN='cn=Password Policy Import,cn=Plugins,cn=config'
3497 TARGET='ds-cfg-default-user-password-storage-scheme'
3498 printf "${FMT}" "${DN}" "${TARGET}" "${TARGET}" "${VALUE}">>${TMP[FILE]}
3499 fi
3500
3501 if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
3502 >&${TMPF[FD]} 2>&1
3503 then
3504 Log.fatal 'Update of passwordStorageScheme failed'
3505 return 66
3506 fi
3507
3508 showProgress "${MSG}."
3509 return 0
3510 }
3511
3512 Man.addFunc update_schema_attr '' '[+NAME?update_schema_attr - Update DS schema to support Naming Services.]
3513 [+DESCRIPTION?Update the schema of the DS with the attribute types required for the Solaris Naming Services. It just checks, whether the OID is defined in the server schema. If already defined, it is left as is, otherwise added.]
3514 [+RETURN VALUES]{
3515 [+0?on success.]
3516 [+>= 66?a fatal error occurred.]
3517 }
3518 [+SEE ALSO?\bldapmodify\b(1), \bgetDSattributes()\b.]
3519 '
3520 function update_schema_attr {
3521
3522 # incorporate former 'keep_backward_compatibility()'
3523 getDSattributes || return 66
3524 typeset MEMBERGID_OID='1.3.6.1.4.1.42.2.27.5.1.30'
3525 typeset DEF=${ANAME2OID['membergid-oid']}
3526 [[ -n ${DEF} ]] && MEMBERGID_OID='memberGid-oid'
3527 typeset RFC822MAILMEMBER_OID='1.3.6.1.4.1.42.2.27.2.1.15'
3528 DEF=${ANAME2OID['rfc822mailmember-oid']}
3529 [[ -n ${DEF} ]] && RFC822MAILMEMBER_OID='rfc822mailMember-oid'
3530
3531 # EE and OD definitions seem to be compatible wrt. to Solaris. However, the
3532 # OD defs usually specifies explicitly the server behavior (what happens, if
3533 # EQUALITY|SUBSTR is not specified => caseIgnore[Substring]Match)) and
3534 # sometimes a different kind of String to use (see RFC 4517):
3535 # IA5 String: ASCII character in the range of 0..127
3536 # Octet String: byte collection (0..255), usually not human readable,
3537 # bytewise comparision
3538 # Directory String: an UTF-8 string
3539 # DN: basically an UTF-8 string, but with some constraints wrt. backslash
3540 # escaping '\0', '"', '+', ',', ';', '<', '>', and '\'
3541 # Boolean String: TRUE|FALSE
3542 typeset -A EE=( )
3543 typeset -A OD=( )
3544 EE['1.3.6.1.1.1.1.28']="'nisPublickey' DESC 'NIS public key' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
3545 OD['1.3.6.1.1.1.1.28']="'nisPublicKey' DESC 'NIS public key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE X-ORIGIN 'draft-howard-rfc2307bis'" # Directory vs. Octet String
3546
3547 EE['1.3.6.1.1.1.1.29']="'nisSecretkey' DESC 'NIS secret key' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
3548 OD['1.3.6.1.1.1.1.29']="'nisSecretKey' DESC 'NIS secret key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE X-ORIGIN 'draft-howard-rfc2307bis'" # Directory vs. Octet String
3549
3550 EE['1.3.6.1.1.1.1.30']="'nisDomain' DESC 'NIS domain' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
3551 OD['1.3.6.1.1.1.1.30']="'nisDomain' DESC 'NIS domain' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'draft-howard-rfc2307bis'" # Directory vs. IA5 String
3552
3553 EE['1.3.6.1.1.1.1.31']="'automountMapName' DESC 'automount Map Name' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
3554 OD['1.3.6.1.1.1.1.31']="'automountMapName' DESC 'automount Map Name' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'draft-howard-rfc2307bis'"
3555
3556 EE['1.3.6.1.1.1.1.32']="'automountKey' DESC 'automount Key Value' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
3557 OD['1.3.6.1.1.1.1.32']="'automountKey' DESC 'Automount Key value' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'draft-howard-rfc2307bis'"
3558
3559 EE['1.3.6.1.1.1.1.33']="'automountInformation' DESC 'automount information' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
3560 OD['1.3.6.1.1.1.1.33']="'automountInformation' DESC 'Automount information' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'draft-howard-rfc2307bis'"
3561
3562 EE['1.3.6.1.4.1.42.2.27.1.1.12']="'nisNetIdUser' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26"
3563 OD['1.3.6.1.4.1.42.2.27.1.1.12']="'nisNetIdUser' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Solaris Specific'"
3564
3565 EE['1.3.6.1.4.1.42.2.27.1.1.13']="'nisNetIdGroup' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26"
3566 OD['1.3.6.1.4.1.42.2.27.1.1.13']="'nisNetIdGroup' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Solaris Specific'"
3567
3568 EE['1.3.6.1.4.1.42.2.27.1.1.14']="'nisNetIdHost' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26"
3569 OD['1.3.6.1.4.1.42.2.27.1.1.14']="'nisNetIdHost' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Solaris Specific'"
3570
3571 EE[${RFC822MAILMEMBER_OID}]="'rfc822mailMember' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26"
3572 OD[${RFC822MAILMEMBER_OID}]="'rfc822mailMember' DESC 'rfc822 mail addresss of group member' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Solaris Specific'"
3573
3574 EE['2.16.840.1.113730.3.1.30']="'mgrpRFC822MailMember' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
3575 OD['2.16.840.1.113730.3.1.30']="'mgrpRFC822MailMember' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Solaris Specific'"
3576
3577 EE['1.3.6.1.4.1.42.2.27.5.1.15']="'SolarisLDAPServers' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
3578 OD['1.3.6.1.4.1.42.2.27.5.1.15']="'SolarisLDAPServers' DESC 'LDAP Server address eg. 76.234.3.1:389' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Solaris Specific'" # Directory vs. IA5 String
3579
3580 EE['1.3.6.1.4.1.42.2.27.5.1.16']="'SolarisSearchBaseDN' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE"
3581 OD['1.3.6.1.4.1.42.2.27.5.1.16']="'SolarisSearchBaseDN' DESC 'Search Base Distinguished Name' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Solaris Specific'" # DN vs. Directory String
3582
3583 EE['1.3.6.1.4.1.42.2.27.5.1.17']="'SolarisCacheTTL' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3584 OD['1.3.6.1.4.1.42.2.27.5.1.17']="'SolarisCacheTTL' DESC 'TTL value for the Domain information eg. 1w, 2d, 3h, 10m, or 5s' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'" # Directory vs. IA5 String
3585
3586 EE['1.3.6.1.4.1.42.2.27.5.1.18']="'SolarisBindDN' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE"
3587 OD['1.3.6.1.4.1.42.2.27.5.1.18']="'SolarisBindDN' DESC 'DN to be used to bind to the directory as proxy' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Solaris Specific'" # DN vs. Directory String
3588
3589 EE['1.3.6.1.4.1.42.2.27.5.1.19']="'SolarisBindPassword' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
3590 OD['1.3.6.1.4.1.42.2.27.5.1.19']="'SolarisBindPassword' DESC 'Password for bindDN to authenticate to the directory' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE X-ORIGIN 'Solaris Specific'" # IA5 vs. Octet String
3591
3592 EE['1.3.6.1.4.1.42.2.27.5.1.20']="'SolarisAuthMethod' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
3593 OD['1.3.6.1.4.1.42.2.27.5.1.20']="'SolarisAuthMethod' DESC 'Authentication method to be used eg. \"NS_LDAP_AUTH_NONE\", \"NS_LDAP_AUTH_SIMPLE\" or \"NS_LDAP_AUTH_SASL_CRAM_MD5\"' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Solaris Specific'" # Directory vs. IA5 String
3594
3595 EE['1.3.6.1.4.1.42.2.27.5.1.21']="'SolarisTransportSecurity' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
3596 OD['1.3.6.1.4.1.42.2.27.5.1.21']="'SolarisTransportSecurity' DESC 'Transport Level Security method to be used eg. \"NS_LDAP_SEC_NONE\" or \"NS_LDAP_SEC_SASL_TLS\"' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'" # Directory vs. IA5 String
3597
3598 EE['1.3.6.1.4.1.42.2.27.5.1.22']="'SolarisCertificatePath' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
3599 OD['1.3.6.1.4.1.42.2.27.5.1.22']="'SolarisCertificatePath' DESC 'Path to certificate file/device' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"
3600
3601 EE['1.3.6.1.4.1.42.2.27.5.1.23']="'SolarisCertificatePassword' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
3602 OD['1.3.6.1.4.1.42.2.27.5.1.23']="'SolarisCertificatePassword' DESC 'Password or PIN that grants access to certificate.' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE X-ORIGIN 'Solaris Specific'" # IA5 vs. Octet String
3603
3604 EE['1.3.6.1.4.1.42.2.27.5.1.24']="'SolarisDataSearchDN' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
3605 OD['1.3.6.1.4.1.42.2.27.5.1.24']="'SolarisDataSearchDN' DESC 'Search DN for data lookup in \":(DN0),(DN1),...\" format' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Solaris Specific'"
3606
3607 EE['1.3.6.1.4.1.42.2.27.5.1.25']="'SolarisSearchScope' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3608 OD['1.3.6.1.4.1.42.2.27.5.1.25']="'SolarisSearchScope' DESC 'Scope to be used for search operations eg. \"NS_LDAP_SCOPE_BASE\", \"NS_LDAP_SCOPE_ONELEVEL\" or \"NS_LDAP_SCOPE_SUBTREE\"' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'" # Directory vs. IA5 String
3609
3610 EE['1.3.6.1.4.1.42.2.27.5.1.26']="'SolarisSearchTimeLimit' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE"
3611 OD['1.3.6.1.4.1.42.2.27.5.1.26']="'SolarisSearchTimeLimit' DESC 'Time Limit in seconds for search operations' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"
3612
3613 EE['1.3.6.1.4.1.42.2.27.5.1.27']="'SolarisPreferredServer' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
3614 OD['1.3.6.1.4.1.42.2.27.5.1.27']="'SolarisPreferredServer' DESC 'Preferred LDAP Server address or network number' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Solaris Specific'" # Directory vs. IA5 String
3615
3616 EE['1.3.6.1.4.1.42.2.27.5.1.28']="'SolarisPreferredServerOnly' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3617 OD['1.3.6.1.4.1.42.2.27.5.1.28']="'SolarisPreferredServerOnly' DESC 'Boolean flag for use of preferredServer or not' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'Solaris Specific'" # Directory vs. Boolean String
3618
3619 EE['1.3.6.1.4.1.42.2.27.5.1.29']="'SolarisSearchReferral' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3620 OD['1.3.6.1.4.1.42.2.27.5.1.29']="'SolarisSearchReferral' DESC 'referral chasing option eg. \"NS_LDAP_NOREF\" or \"NS_LDAP_FOLLOWREF\"' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'" # Directory vs. IA5 String
3621
3622 EE['1.3.6.1.4.1.42.2.27.5.1.4']="'SolarisAttrKeyValue' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3623 OD['1.3.6.1.4.1.42.2.27.5.1.4']="'SolarisAttrKeyValue' DESC 'Semi-colon separated key=value pairs of attributes' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'" # Directory vs. IA5 String
3624
3625 EE['1.3.6.1.4.1.42.2.27.5.1.5']="'SolarisAuditAlways' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3626 OD['1.3.6.1.4.1.42.2.27.5.1.5']="'SolarisAuditAlways' DESC 'Always audited attributes per-user' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'" # Directory vs. IA5 String
3627
3628 EE['1.3.6.1.4.1.42.2.27.5.1.6']="'SolarisAuditNever' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3629 OD['1.3.6.1.4.1.42.2.27.5.1.6']="'SolarisAuditNever' DESC 'Never audited attributes per-user' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'" # Directory vs. IA5 String
3630
3631 EE['1.3.6.1.4.1.42.2.27.5.1.7']="'SolarisAttrShortDesc' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3632 OD['1.3.6.1.4.1.42.2.27.5.1.7']="'SolarisAttrShortDesc' DESC 'Short description about an entry, used by GUIs' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'" # Directory vs. IA5 String
3633
3634 EE['1.3.6.1.4.1.42.2.27.5.1.8']="'SolarisAttrLongDesc' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3635 OD['1.3.6.1.4.1.42.2.27.5.1.8']="'SolarisAttrLongDesc' DESC 'Detail description about an entry' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'" # Directory vs. IA5 String
3636
3637 EE['1.3.6.1.4.1.42.2.27.5.1.9']="'SolarisKernelSecurityPolicy' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3638 OD['1.3.6.1.4.1.42.2.27.5.1.9']="'SolarisKernelSecurityPolicy' DESC 'Solaris kernel security policy' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'" # Directory vs. IA5 String
3639
3640 EE['1.3.6.1.4.1.42.2.27.5.1.10']="'SolarisProfileType' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3641 OD['1.3.6.1.4.1.42.2.27.5.1.10']="'SolarisProfileType' DESC 'Type of object defined in profile'EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'" # Directory vs. IA5 String
3642
3643 EE['1.3.6.1.4.1.42.2.27.5.1.11']="'SolarisProfileId' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
3644 OD['1.3.6.1.4.1.42.2.27.5.1.11']="'SolarisProfileId' DESC 'Identifier of object defined in profile' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"
3645
3646 EE['1.3.6.1.4.1.42.2.27.5.1.12']="'SolarisUserQualifier' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3647 OD['1.3.6.1.4.1.42.2.27.5.1.12']="'SolarisUserQualifier' DESC 'Per-user login attributes' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'" # Directory vs. IA5 String
3648
3649 EE['1.3.6.1.4.1.42.2.27.5.1.13']="'SolarisAttrReserved1' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3650 OD['1.3.6.1.4.1.42.2.27.5.1.13']="'SolarisAttrReserved1' DESC 'Reserved for future use' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'" # Directory vs. IA5 String
3651
3652 EE['1.3.6.1.4.1.42.2.27.5.1.14']="'SolarisAttrReserved2' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3653 OD['1.3.6.1.4.1.42.2.27.5.1.14']="'SolarisAttrReserved2' DESC 'Reserved for future use' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'" # Directory vs. IA5 String
3654
3655 EE['1.3.6.1.4.1.42.2.27.5.1.1']="'SolarisProjectID' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE"
3656 OD['1.3.6.1.4.1.42.2.27.5.1.1']="'SolarisProjectID' DESC 'Unique ID for a Solaris Project entry' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"
3657
3658 EE['1.3.6.1.4.1.42.2.27.5.1.2']="'SolarisProjectName' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
3659 OD['1.3.6.1.4.1.42.2.27.5.1.2']="'SolarisProjectName' DESC 'Name of a Solaris Project Entry' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"
3660
3661 EE['1.3.6.1.4.1.42.2.27.5.1.3']="'SolarisProjectAttr' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26"
3662 OD['1.3.6.1.4.1.42.2.27.5.1.3']="'SolarisProjectAttr' DESC 'Attributes of a Solaris Project entry' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"
3663
3664 EE[${MEMBERGID_OID}]="'memberGid' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26"
3665 OD[${MEMBERGID_OID}]="'memberGid' DESC 'Posix Group Name' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Solaris Specific'"
3666
3667 EE['1.3.6.1.4.1.11.1.3.1.1.0']="'defaultServerList' DESC 'Default LDAP server host address used by a DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3668 OD['1.3.6.1.4.1.11.1.3.1.1.0']="'defaultServerList' DESC 'List of default servers' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 4876'"
3669
3670 EE['1.3.6.1.4.1.11.1.3.1.1.1']="'defaultSearchBase' DESC 'Default LDAP base DN used by a DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE"
3671 OD['1.3.6.1.4.1.11.1.3.1.1.1']="'defaultSearchBase' DESC 'Default base for searches' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'RFC 4876'"
3672
3673 EE['1.3.6.1.4.1.11.1.3.1.1.2']="'preferredServerList' DESC 'Preferred LDAP server host addresses to be used by a DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3674 OD['1.3.6.1.4.1.11.1.3.1.1.2']="'preferredServerList' DESC 'List of preferred servers' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 4876'"
3675
3676 EE['1.3.6.1.4.1.11.1.3.1.1.3']="'searchTimeLimit' DESC 'Maximum time in seconds a DUA should allow for a search to complete' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE"
3677 OD['1.3.6.1.4.1.11.1.3.1.1.3']="'searchTimeLimit' DESC 'Maximum time an agent or service allows for a search to complete' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 4876'"
3678
3679 EE['1.3.6.1.4.1.11.1.3.1.1.4']="'bindTimeLimit' DESC 'Maximum time in seconds a DUA should allow for the bind operation to complete' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE"
3680 OD['1.3.6.1.4.1.11.1.3.1.1.4']="'bindTimeLimit' DESC 'Maximum time an agent or service allows for a bind operation to complete' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 4876'"
3681
3682 EE['1.3.6.1.4.1.11.1.3.1.1.5']="'followReferrals' DESC 'Tells DUA if it should follow referrals returned by a DSA search result' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3683 OD['1.3.6.1.4.1.11.1.3.1.1.5']="'followReferrals' DESC 'An agent or service does or should follow referrals' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'RFC 4876'" # Directory vs. Boolean String
3684
3685 EE['1.3.6.1.4.1.11.1.3.1.1.6']="'authenticationMethod' DESC 'A keystring which identifies the type of authentication method used to contact the DSA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3686 OD['1.3.6.1.4.1.11.1.3.1.1.6']="'authenticationMethod' DESC 'Identifies the types of authentication methods either used, required, or provided by a service or peer' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 4876'"
3687
3688 EE['1.3.6.1.4.1.11.1.3.1.1.7']="'profileTTL' DESC 'Time to live before a client DUA should re-read this configuration profile' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE"
3689 OD['1.3.6.1.4.1.11.1.3.1.1.7']="'profileTTL' DESC 'Time to live, in seconds, before a profile is considered stale' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 4876'"
3690
3691 EE['1.3.6.1.4.1.11.1.3.1.1.14']="'serviceSearchDescriptor' DESC 'LDAP search descriptor list used by Naming-DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26"
3692 OD['1.3.6.1.4.1.11.1.3.1.1.14']="'serviceSearchDescriptor' DESC 'Specifies search descriptors required, used, or supported by a particular service or agent' EQUALITY caseExactMatch SUBSTR caseExactSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 4876'" # IA5 vs. Directory String
3693
3694 EE['1.3.6.1.4.1.11.1.3.1.1.9']="'attributeMap' DESC 'Attribute mappings used by a Naming-DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
3695 OD['1.3.6.1.4.1.11.1.3.1.1.9']="'attributeMap' DESC 'Attribute mappings used, required, or supported by an agent or service' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC 4876'" # Directory vs. IA5 String
3696
3697 EE['1.3.6.1.4.1.11.1.3.1.1.10']="'credentialLevel' DESC 'Identifies type of credentials a DUA should use when binding to the LDAP server' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3698 OD['1.3.6.1.4.1.11.1.3.1.1.10']="'credentialLevel' DESC 'Identifies type of credentials either used, required, or supported by an agent or service' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'RFC 4876'" # Directory vs. IA5 String
3699
3700 EE['1.3.6.1.4.1.11.1.3.1.1.11']="'objectclassMap' DESC 'Objectclass mappings used by a Naming-DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
3701 OD['1.3.6.1.4.1.11.1.3.1.1.11']="'objectclassMap' DESC 'Object class mappings used, required, or supported by an agent or service' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC 4876'" # Directory vs. IA5 String
3702
3703 EE['1.3.6.1.4.1.11.1.3.1.1.12']="'defaultSearchScope' DESC 'Default search scope used by a DUA' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3704 OD['1.3.6.1.4.1.11.1.3.1.1.12']="'defaultSearchScope' DESC 'Default scope used when performing a search' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'RFC 4876'" # Directory vs. IA5 String
3705
3706 EE['1.3.6.1.4.1.11.1.3.1.1.13']="'serviceCredentialLevel' DESC 'Search scope used by a service of the DUA' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26"
3707 OD['1.3.6.1.4.1.11.1.3.1.1.13']="'serviceCredentialLevel' DESC 'Specifies the type of credentials either used, required, or supported by a specific service' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC 4876'"
3708
3709 EE['1.3.6.1.4.1.11.1.3.1.1.15']="'serviceAuthenticationMethod' DESC 'Authentication Method used by a service of the DUA' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
3710 OD['1.3.6.1.4.1.11.1.3.1.1.15']="'serviceAuthenticationMethod' DESC 'Specifies types authentication methods either used, required, or supported by a particular service' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 4876'"
3711
3712 EE['1.3.18.0.2.4.1140']="'printer-uri' DESC 'A URI supported by this printer. This URI SHOULD be used as a relative distinguished name (RDN). If printer-xri-supported is implemented, then this URI value MUST be listed in a member value of printer-xri-supported.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3713 OD['1.3.18.0.2.4.1140']="'printer-uri' DESC 'A URI supported by this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3714
3715 EE['1.3.18.0.2.4.1107']="'printer-xri-supported' DESC 'The unordered list of XRI (extended resource identifiers) supported by this printer. Each member of the list consists of a URI (uniform resource identifier) followed by optional authentication and security metaparameters.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
3716 OD['1.3.18.0.2.4.1107']="'printer-xri-supported' DESC 'The unordered list of XRI (extended resource identifiers) supported by this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 3712'"
3717
3718 EE['1.3.18.0.2.4.1135']="'printer-name' DESC 'The site-specific administrative name of this printer, more end-user friendly than a URI.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE"
3719 OD['1.3.18.0.2.4.1135']="'printer-name' DESC 'The site-specific administrative name of this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3720
3721 EE['1.3.18.0.2.4.1119']="'printer-natural-language-configured' DESC 'The configured language in which error and status messages will be generated (by default) by this printer. Also, a possible language for printer string attributes set by operator, system administrator, or manufacturer. Also, the (declared) language of the \"printer-name\", \"printer-location\", \"printer-info\", and \"printer-make-and-model\" attributes of this printer. For example: \"en-us\" (US English) or \"fr-fr\" (French in France) Legal values of language tags conform to [RFC3066] \"Tags for the Identification of Languages\".' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE"
3722 OD['1.3.18.0.2.4.1119']="'printer-natural-language-configured' DESC 'The configured natural language in which error and status messages will be generated (by default) by this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3723
3724 EE['1.3.18.0.2.4.1136']="'printer-location' DESC 'Identifies the location of the printer. This could include things like: \"in Room 123A\", \"second floor of building XYZ\".' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE"
3725 OD['1.3.18.0.2.4.1136']="'printer-location' DESC 'The physical location of this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3726
3727 EE['1.3.18.0.2.4.1139']="'printer-info' DESC 'Identifies the descriptive information about this printer. This could include things like: \"This printer can be used for printing color transparencies for HR presentations\", or \"Out of courtesy for others, please print only small (1-5 page) jobs at this printer\", or even \"This printer is going away on July 1, 1997, please find a new printer\".' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE"
3728 OD['1.3.18.0.2.4.1139']="'printer-info' DESC 'Descriptive information about this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3729
3730 EE['1.3.18.0.2.4.1134']="'printer-more-info' DESC 'A URI used to obtain more information about this specific printer. For example, this could be an HTTP type URI referencing an HTML page accessible to a Web Browser. The information obtained from this URI is intended for end user consumption.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3731 OD['1.3.18.0.2.4.1134']="'printer-more-info' DESC 'A URI for more information about this specific printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3732
3733 EE['1.3.18.0.2.4.1138']="'printer-make-and-model' DESC 'Identifies the make and model of the device. The device manufacturer MAY initially populate this attribute.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE"
3734 OD['1.3.18.0.2.4.1138']="'printer-make-and-model' DESC 'Make and model of this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3735
3736 EE['1.3.18.0.2.4.1133']="'printer-ipp-versions-supported' DESC 'Identifies the IPP protocol version(s) that this printer supports, including major and minor versions, i.e., the version numbers for which this Printer implementation meets the conformance requirements.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}"
3737 OD['1.3.18.0.2.4.1133']="'printer-ipp-versions-supported' DESC 'IPP protocol version(s) that this printer supports.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} X-ORIGIN 'RFC 3712'"
3738
3739 EE['1.3.18.0.2.4.1132']="'printer-multiple-document-jobs-supported' DESC 'Indicates whether or not the printer supports more than one document per job, i.e., more than one Send-Document or Send-Data operation with document data.' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE"
3740 OD['1.3.18.0.2.4.1132']="'printer-multiple-document-jobs-supported' DESC 'Indicates whether or not this printer supports more than one document per job.' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3741
3742 EE['1.3.18.0.2.4.1109']="'printer-charset-configured' DESC 'The configured charset in which error and status messages will be generated (by default) by this printer. Also, a possible charset for printer string attributes set by operator, system administrator, or manufacturer. For example: \"utf-8\" (ISO 10646/Unicode) or \"iso-8859-1\" (Latin1). Legal values are defined by the IANA Registry of Coded Character Sets and the \"(preferred MIME name)\" SHALL be used as the tag. For coherence with IPP Model, charset tags in this attribute SHALL be lowercase normalized. This attribute SHOULD be static (time of registration) and SHOULD NOT be dynamically refreshed attributetypes: (subsequently).' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{63} SINGLE-VALUE"
3743 OD['1.3.18.0.2.4.1109']="'printer-charset-configured' DESC 'The configured charset in which error and status messages will be generated (by default) by this printer.' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{63} SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3744
3745 EE['1.3.18.0.2.4.1131']="'printer-charset-supported' DESC 'Identifies the set of charsets supported for attribute type values of type Directory String for this directory entry. For example: \"utf-8\" (ISO 10646/Unicode) or \"iso-8859-1\" (Latin1). Legal values are defined by the IANA Registry of Coded Character Sets and the preferred MIME name.' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{63}"
3746 OD['1.3.18.0.2.4.1131']="'printer-charset-supported' DESC 'Set of charsets supported for the attribute values of syntax DirectoryString for this directory entry.' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{63} X-ORIGIN 'RFC 3712'"
3747
3748 EE['1.3.18.0.2.4.1137']="'printer-generated-natural-language-supported' DESC 'Identifies the natural language(s) supported for this directory entry. For example: \"en-us\" (US English) or \"fr-fr\" (French in France). Legal values conform to [RFC3066], Tags for the Identification of Languages.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{63}"
3749 OD['1.3.18.0.2.4.1137']="'printer-generated-natural-language-supported' DESC 'Natural language(s) supported for this directory entry.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{63} X-ORIGIN 'RFC 3712'"
3750
3751 EE['1.3.18.0.2.4.1130']="'printer-document-format-supported' DESC 'The possible document formats in which data may be interpreted and printed by this printer. Legal values are MIME types come from the IANA Registry of Internet Media Types.' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}"
3752 OD['1.3.18.0.2.4.1130']="'printer-document-format-supported' DESC 'The possible source document formats which may be interpreted and printed by this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} X-ORIGIN 'RFC 3712'"
3753
3754 EE['1.3.18.0.2.4.1129']="'printer-color-supported' DESC 'Indicates whether this printer is capable of any type of color printing at all, including highlight color.' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE"
3755 OD['1.3.18.0.2.4.1129']="'printer-color-supported' DESC 'Indicates whether this printer is capable of any type of color printing at all, including highlight color.' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3756
3757 EE['1.3.18.0.2.4.1128']="'printer-compression-supported' DESC 'Compression algorithms supported by this printer. For example: \"deflate, gzip\". Legal values include; \"none\", \"deflate\" attributetypes: (public domain ZIP), \"gzip\" (GNU ZIP), \"compress\" (UNIX).' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255}"
3758 OD['1.3.18.0.2.4.1128']="'printer-compression-supported' DESC 'Compression algorithms supported by this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} X-ORIGIN 'RFC 3712'"
3759
3760 EE['1.3.18.0.2.4.1127']="'printer-pages-per-minute' DESC 'The nominal number of pages per minute which may be output by this printer (e.g., a simplex or black-and-white printer). This attribute is informative, NOT a service guarantee. Typically, it is the value used in marketing literature to describe this printer.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE"
3761 OD['1.3.18.0.2.4.1127']="'printer-pages-per-minute' DESC 'The nominal number of pages per minute which may be output by this printer.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3762
3763 EE['1.3.18.0.2.4.1126']="'printer-pages-per-minute-color' DESC 'The nominal number of color pages per minute which may be output by this printer (e.g., a simplex or color printer). This attribute is informative, NOT a service guarantee. Typically, it is the value used in marketing literature to describe this printer.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE"
3764 OD['1.3.18.0.2.4.1126']="'printer-pages-per-minute-color' DESC 'The nominal number of color pages per minute which may be output by this printer.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3765
3766 EE['1.3.18.0.2.4.1125']="'printer-finishings-supported' DESC 'The possible finishing operations supported by this printer. Legal values include; \"none\", \"staple\", \"punch\", \"cover\", \"bind\", \"saddle-stitch\", \"edge-stitch\", \"staple-top-left\", \"staple-bottom-left\", \"staple-top-right\", \"staple-bottom-right\", \"edge-stitch-left\", \"edge-stitch-top\", \"edge-stitch-right\", \"edge-stitch-bottom\", \"staple-dual-left\", \"staple-dual-top\", \"staple-dual-right\", \"staple-dual-bottom\".' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255}"
3767 OD['1.3.18.0.2.4.1125']="'printer-finishings-supported' DESC 'The possible finishing operations supported by this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} X-ORIGIN 'RFC 3712'"
3768
3769 EE['1.3.18.0.2.4.1124']="'printer-number-up-supported' DESC 'The possible numbers of print-stream pages to impose upon a single side of an instance of a selected medium. Legal values include; 1, 2, and 4. Implementations may support other values.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27"
3770 OD['1.3.18.0.2.4.1124']="'printer-number-up-supported' DESC 'The possible numbers of print-stream pages to impose upon a single side of an instance of a selected medium.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 X-ORIGIN 'RFC 3712'"
3771
3772 EE['1.3.18.0.2.4.1123']="'printer-sides-supported' DESC 'The number of impression sides (one or two) and the two-sided impression rotations supported by this printer. Legal values include; \"one-sided\", \"two-sided-long-edge\", \"two-sided-short-edge\".' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}"
3773 OD['1.3.18.0.2.4.1123']="'printer-sides-supported' DESC 'The number of impression sides (one or two) and the two-sided impression rotations supported by this printer.' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} X-ORIGIN 'RFC 3712'"
3774
3775 EE['1.3.18.0.2.4.1122']="'printer-media-supported' DESC 'The standard names/types/sizes (and optional color suffixes) of the media supported by this printer. For example: \"iso-a4\", \"envelope\", or \"na-letter-white\". Legal values conform to ISO 10175, Document Printing Application (DPA), and any IANA registered extensions.' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255}"
3776 OD['1.3.18.0.2.4.1122']="'printer-media-supported' DESC 'The standard names/types/sizes (and optional color suffixes) of the media supported by this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} X-ORIGIN 'RFC 3712'"
3777
3778 EE['1.3.18.0.2.4.1117']="'printer-media-local-supported' DESC 'Site-specific names of media supported by this printer, in the language in \"printer-natural-language-configured\". For example: \"purchasing-form\" (site-specific name) as opposed to (in \"printer-media-supported\"): \"na-letter\" (standard keyword from ISO 10175).' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255}"
3779 OD['1.3.18.0.2.4.1117']="'printer-media-local-supported' DESC 'Site-specific names of media supported by this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} X-ORIGIN 'RFC 3712'"
3780
3781 EE['1.3.18.0.2.4.1121']="'printer-resolution-supported' DESC 'List of resolutions supported for printing documents by this printer. Each resolution value is a string with 3 fields: 1) Cross feed direction resolution (positive integer), 2) Feed direction resolution (positive integer), 3) Resolution unit. Legal values are \"dpi\" (dots per inch) and \"dpcm\" (dots per centimeter). Each resolution field is delimited by \">\". For example: \"300> 300> dpi>\".' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255}"
3782 OD['1.3.18.0.2.4.1121']="'printer-resolution-supported' DESC 'List of resolutions supported for printing documents by this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} X-ORIGIN 'RFC 3712'"
3783
3784 EE['1.3.18.0.2.4.1120']="'printer-print-quality-supported' DESC 'List of print qualities supported for printing documents on this printer. For example: \"draft, normal\". Legal values include; \"unknown\", \"draft\", \"normal\", \"high\".' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}"
3785 OD['1.3.18.0.2.4.1120']="'printer-print-quality-supported' DESC 'List of print qualities supported for printing documents on this printer.' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} X-ORIGIN 'RFC 3712'"
3786
3787 EE['1.3.18.0.2.4.1110']="'printer-job-priority-supported' DESC 'Indicates the number of job priority levels supported. An IPP conformant printer which supports job priority must always support a full range of priorities from \"1\" to \"100\" (to ensure consistent behavior), therefore this attribute describes the \"granularity\". Legal values of this attribute are from \"1\" to \"100\".' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE"
3788 OD['1.3.18.0.2.4.1110']="'printer-job-priority-supported' DESC 'Indicates the number of job priority levels supported by this printer.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3789
3790 EE['1.3.18.0.2.4.1118']="'printer-copies-supported' DESC 'The maximum number of copies of a document that may be printed as a single job. A value of \"0\" indicates no maximum limit. A value of \"-1\" indicates unknown.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE"
3791 OD['1.3.18.0.2.4.1118']="'printer-copies-supported' DESC 'The maximum number of copies of a document that may be printed as a single job on this printer.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3792
3793 EE['1.3.18.0.2.4.1111']="'printer-job-k-octets-supported' DESC 'The maximum size in kilobytes (1,024 octets actually) incoming print job that this printer will accept. A value of \"0\" indicates no maximum limit. A value of \"-1\" indicates unknown.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE"
3794 OD['1.3.18.0.2.4.1111']="'printer-job-k-octets-supported' DESC 'The maximum size in kilobytes (1,024 octets actually) incoming print job that this printer will accept.' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3795
3796 EE['1.3.18.0.2.4.1112']="'printer-current-operator' DESC 'The name of the current human operator responsible for operating this printer. It is suggested that this string include information that would enable other humans to reach the operator, such as a phone number.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE"
3797 OD['1.3.18.0.2.4.1112']="'printer-current-operator' DESC 'The identity of the current human operator responsible for operating this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3798
3799 EE['1.3.18.0.2.4.1113']="'printer-service-person' DESC 'The name of the current human service person responsible for servicing this printer. It is suggested that this string include information that would enable other humans to reach the service person, such as a phone number.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE"
3800 OD['1.3.18.0.2.4.1113']="'printer-service-person' DESC 'The identity of the current human service person responsible for servicing this printer.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} SINGLE-VALUE X-ORIGIN 'RFC 3712'"
3801
3802 EE['1.3.18.0.2.4.1114']="'printer-delivery-orientation-supported' DESC 'The possible delivery orientations of pages as they are printed and ejected from this printer. Legal values include; \"unknown\", \"face-up\", and \"face-down\".' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}"
3803 OD['1.3.18.0.2.4.1114']="'printer-delivery-orientation-supported' DESC 'The possible delivery orientations of pages as they are printed and ejected from this printer.' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} X-ORIGIN 'RFC 3712'"
3804
3805 EE['1.3.18.0.2.4.1115']="'printer-stacking-order-supported' DESC 'The possible stacking order of pages as they are printed and ejected from this printer. Legal values include; \"unknown\", \"first-to-last\", \"last-to-first\".' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}"
3806 OD['1.3.18.0.2.4.1115']="'printer-stacking-order-supported' DESC 'The possible stacking order of pages as they are printed and ejected from this printer.' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} X-ORIGIN 'RFC 3712'"
3807
3808 EE['1.3.18.0.2.4.1116']="'printer-output-features-supported' DESC 'The possible output features supported by this printer. Legal values include; \"unknown\", \"bursting\", \"decollating\", \"page-collating\", \"offset-stacking\".' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}"
3809 OD['1.3.18.0.2.4.1116']="'printer-output-features-supported' DESC 'The possible output features supported by this printer.' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} X-ORIGIN 'RFC 3712'"
3810
3811 EE['1.3.18.0.2.4.1108']="'printer-aliases' DESC 'Site-specific administrative names of this printer in addition the printer name specified for printer-name.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127}"
3812 OD['1.3.18.0.2.4.1108']="'printer-aliases' DESC 'List of site-specific administrative names of this printer in addition to the value specified for printer-name.' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{127} X-ORIGIN 'RFC 3712'"
3813
3814 EE['1.3.6.1.4.1.42.2.27.5.1.63']="'sun-printer-bsdaddr' DESC 'Sets the server, print queue destination name and whether the client generates protocol extensions. \"Solaris\" specifies a Solaris print server extension. The value is represented by the following value: server \",\" destination \", Solaris\".' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
3815 OD['1.3.6.1.4.1.42.2.27.5.1.63']="'sun-printer-bsdaddr' DESC 'Sets the server, print queue destination name and whether the client generates protocol extensions. \"Solaris\" specifies a Solaris print server extension. The value is represented by the following value: server \",\" destination \", Solaris\".' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"
3816
3817 EE['1.3.6.1.4.1.42.2.27.5.1.64']="'sun-printer-kvp' DESC 'This attribute contains a set of key value pairs which may have meaning to the print subsystem or may be user defined. Each value is represented by the following: key \"=\" value.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
3818 OD['1.3.6.1.4.1.42.2.27.5.1.64']="'sun-printer-kvp' DESC 'This attribute contains a set of key value pairs which may have meaning to the print subsystem or may be user defined. Each value is represented by the following: key \"=\" value.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Solaris Specific'"
3819
3820 EE['1.3.6.1.4.1.42.2.27.5.1.57']="'nisplusTimeZone' DESC 'tzone column from NIS+ timezone table' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
3821 OD['1.3.6.1.4.1.42.2.27.5.1.57']="'nisplusTimeZone' DESC 'tzone column from NIS+ timezone table' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"
3822
3823 EE['1.3.6.1.4.1.42.2.27.5.1.67']="'ipTnetTemplateName' DESC 'Trusted Solaris network template template_name' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
3824 OD['1.3.6.1.4.1.42.2.27.5.1.67']="'ipTnetTemplateName' DESC 'Trusted Solaris network template template_name' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"
3825
3826 EE['1.3.6.1.4.1.42.2.27.5.1.68']="'ipTnetNumber' DESC 'Trusted Solaris network template ip_address' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE"
3827 OD['1.3.6.1.4.1.42.2.27.5.1.68']="'ipTnetNumber' DESC 'Trusted Solaris network template ip_address' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Solaris Specific'"
3828
3829 # obey CLI syntax force option (if any)
3830 if (( TMPF[SYNTAX] == 1 )); then
3831 typeset -n MAP=OD
3832 elif (( TMPF[SYNTAX] == 2 )); then
3833 typeset -n MAP=EE
3834 elif (( TMPF[IS_OPENDJ] )); then
3835 typeset -n MAP=OD
3836 else
3837 typeset -n MAP=EE
3838 fi
3839
3840 typeset TODO='' OID X
3841 for OID in ${!MAP[@]}; do
3842 [[ -n ${OID2ADEF[${OID}]} ]] && continue
3843 X="${MAP[${OID}]}"
3844 TODO+='attributetypes: ( '"${OID} NAME ${X}"' )\n'
3845 OID2ADEF["${OID}"]="${X}"
3846 X=${X:1}
3847 X=${X%%"'"*} # we have no aliases above
3848 ANAME2OID["${X}"]="${OID}"
3849 done
3850
3851 if [[ -z ${TODO} ]]; then
3852 X='Schema contains all required attribute definitions'
3853 else
3854 nextFile add $0
3855 print 'dn: cn=schema\nchangetype: modify\nadd: attributetypes' \
3856 "\n${TODO}" >${TMP[FILE]}
3857 if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
3858 >&${TMPF[FD]} 2>&1
3859 then
3860 Log.fatal 'Adding attribute definitions to schema failed'
3861 return 67
3862 fi
3863 X='Schema attribute definitions added'
3864 fi
3865 showProgress "${X}."
3866 return 0
3867 }
3868
3869 Man.addFunc update_schema_obj '' '[+NAME?update_schema_obj - Update DS schema to support Naming Services.]
3870 [+DESCRIPTION?Update the schema of the DS with the objectclasses required for the Solaris Naming Services. It just checks, whether the OID is already defined on the server. If already defined, it is left as is, otherwise added.]
3871 [+RETURN VALUES]{
3872 [+0?on success.]
3873 [+>= 66?a fatal error occurred.]
3874 }
3875 [+SEE ALSO?\bupdate_schema_attr()\b, \bldapmodify\b(1).]
3876 '
3877 function update_schema_obj {
3878 getDSobjectclasses || return 66
3879
3880 typeset -A EE=( )
3881 typeset -A OD=( )
3882 EE['1.3.6.1.1.1.2.14']="'NisKeyObject' SUP top MUST "'( cn $ nisPublickey $ nisSecretkey ) MAY ( uidNumber $ description )'
3883 OD['1.3.6.1.1.1.2.14']="'nisKeyObject' SUP top AUXILIARY DESC 'An object with a public and secret key' MUST "'( cn $ nisPublicKey $ nisSecretKey ) MAY ( uidNumber $ description )'" X-ORIGIN 'draft-howard-rfc2307bis'"
3884
3885 EE['1.3.6.1.1.1.2.15']="'nisDomainObject' SUP top MUST nisDomain"
3886 OD['1.3.6.1.1.1.2.15']="'nisDomainObject' SUP top AUXILIARY DESC 'Associates a NIS domain with a naming context' MUST nisDomain X-ORIGIN 'draft-howard-rfc2307bis'"
3887
3888 EE['1.3.6.1.1.1.2.16']="'automountMap' SUP top MUST automountMapName MAY description"
3889 OD['1.3.6.1.1.1.2.16']="'automountMap' SUP top STRUCTURAL MUST ( automountMapName ) MAY description X-ORIGIN 'draft-howard-rfc2307bis'"
3890
3891 EE['1.3.6.1.1.1.2.17']="'automount' SUP top MUST "'( automountKey $ automountInformation ) MAY description'
3892 OD['1.3.6.1.1.1.2.17']="'automount' SUP top STRUCTURAL DESC 'Automount information' MUST "'( automountKey $ automountInformation )'" MAY description X-ORIGIN 'draft-howard-rfc2307bis'"
3893
3894 EE['1.3.6.1.4.1.42.2.27.5.2.7']="'SolarisNamingProfile' SUP top MUST "'( cn $ SolarisLDAPservers $ SolarisSearchBaseDN ) MAY ( SolarisBindDN $ SolarisBindPassword $ SolarisAuthMethod $ SolarisTransportSecurity $ SolarisCertificatePath $ SolarisCertificatePassword $ SolarisDataSearchDN $ SolarisSearchScope $ SolarisSearchTimeLimit $ SolarisPreferredServer $ SolarisPreferredServerOnly $ SolarisCacheTTL $ SolarisSearchReferral )'
3895 OD['1.3.6.1.4.1.42.2.27.5.2.7']="'SolarisNamingProfile' SUP top STRUCTURAL DESC 'Solaris LDAP Naming client profile objectClass' MUST "'( cn $ SolarisLDAPServers $ SolarisSearchBaseDN ) MAY ( SolarisBindDN $ SolarisBindPassword $ SolarisAuthMethod $ SolarisTransportSecurity $ SolarisCertificatePath $ SolarisCertificatePassword $ SolarisDataSearchDN $ SolarisSearchScope $ SolarisSearchTimeLimit $ SolarisPreferredServer $ SolarisPreferredServerOnly $ SolarisCacheTTL $ SolarisSearchReferral $ SolarisBindTimeLimit )'" X-ORIGIN 'Solaris Specific'"
3896
3897 EE['2.16.840.1.113730.3.2.4']="'mailGroup' SUP top MUST mail MAY "'( cn $ mgrpRFC822MailMember )'
3898 OD['2.16.840.1.113730.3.2.4']="'mailGroup' SUP top STRUCTURAL MUST mail MAY "'( cn $ mgrpRFC822MailMember )'" X-ORIGIN 'Solaris Specific'"
3899
3900 EE['1.3.6.1.4.1.42.2.27.1.2.5']="'nisMailAlias' SUP top MUST cn MAY rfc822mailMember"
3901 OD['1.3.6.1.4.1.42.2.27.1.2.5']="'nisMailAlias' SUP top MUST cn MAY rfc822mailMember X-ORIGIN 'Solaris Specific'"
3902
3903 EE['1.3.6.1.4.1.42.2.27.1.2.6']="'nisNetId' SUP top MUST cn MAY "'( nisNetIdUser $ nisNetIdGroup $ nisNetIdHost )'
3904 OD['1.3.6.1.4.1.42.2.27.1.2.6']="'nisNetId' SUP top MUST cn MAY "'( nisNetIdUser $ nisNetIdGroup $ nisNetIdHost )'" X-ORIGIN 'Solaris Specific'"
3905
3906 EE['1.3.6.1.4.1.42.2.27.5.2.2']="'SolarisAuditUser' SUP top AUXILIARY MAY "'( SolarisAuditAlways $ SolarisAuditNever )'
3907 OD['1.3.6.1.4.1.42.2.27.5.2.2']="'SolarisAuditUser' SUP top AUXILIARY MAY "'( SolarisAuditAlways $ SolarisAuditNever )'" X-ORIGIN 'Solaris Specific'"
3908
3909 EE['1.3.6.1.4.1.42.2.27.5.2.3']="'SolarisUserAttr' SUP top AUXILIARY MAY "'( SolarisUserQualifier $ SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrKeyValue )'
3910 OD['1.3.6.1.4.1.42.2.27.5.2.3']="'SolarisUserAttr' SUP top AUXILIARY DESC 'User attributes' MAY "'( SolarisUserQualifier $ SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrKeyValue )'" X-ORIGIN 'Solaris Specific'"
3911
3912 EE['1.3.6.1.4.1.42.2.27.5.2.4']="'SolarisAuthAttr' SUP top MUST cn MAY "'( SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrShortDesc $ SolarisAttrLongDesc $ SolarisAttrKeyValue )'
3913 OD['1.3.6.1.4.1.42.2.27.5.2.4']="'SolarisAuthAttr' SUP top STRUCTURAL DESC 'Authorizations data' MUST cn MAY "'( SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrShortDesc $ SolarisAttrLongDesc $ SolarisAttrKeyValue )'" X-ORIGIN 'Solaris Specific'"
3914
3915 EE['1.3.6.1.4.1.42.2.27.5.2.5']="'SolarisProfAttr' SUP top MUST cn MAY "'( SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrLongDesc $ SolarisAttrKeyValue )'
3916 OD['1.3.6.1.4.1.42.2.27.5.2.5']="'SolarisProfAttr' SUP top STRUCTURAL DESC 'Profiles data' MUST cn MAY "'( SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisAttrLongDesc $ SolarisAttrKeyValue )'" X-ORIGIN 'Solaris Specific'"
3917
3918 EE['1.3.6.1.4.1.42.2.27.5.2.6']="'SolarisExecAttr' SUP top AUXILIARY MAY "'( SolarisKernelSecurityPolicy $ SolarisProfileType $ SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisProfileID $ SolarisAttrKeyValue )'
3919 OD['1.3.6.1.4.1.42.2.27.5.2.6']="'SolarisExecAttr' SUP top AUXILIARY DESC 'Profiles execution attributes' MAY "'( SolarisKernelSecurityPolicy $ SolarisProfileType $ SolarisAttrReserved1 $ SolarisAttrReserved2 $ SolarisProfileId $ SolarisAttrKeyValue )'" X-ORIGIN 'Solaris Specific'"
3920
3921 EE['1.3.6.1.4.1.42.2.27.5.2.1']="'SolarisProject' SUP top MUST "'( SolarisProjectID $ SolarisProjectName ) MAY ( memberUid $ memberGid $ description $ SolarisProjectAttr )'
3922 OD['1.3.6.1.4.1.42.2.27.5.2.1']="'SolarisProject' SUP top STRUCTURAL MUST "'( SolarisProjectID $ SolarisProjectName ) MAY ( memberUid $ memberGid $ description $ SolarisProjectAttr )'" X-ORIGIN 'Solaris Specific'"
3923
3924 EE['1.3.6.1.4.1.11.1.3.1.2.4']="'DUAConfigProfile' SUP top DESC 'Abstraction of a base configuration for a DUA' MUST cn MAY "'( defaultServerList $ preferredServerList $ defaultSearchBase $ defaultSearchScope $ searchTimeLimit $ bindTimeLimit $ credentialLevel $ authenticationMethod $ followReferrals $ serviceSearchDescriptor $ serviceCredentialLevel $ serviceAuthenticationMethod $ objectclassMap $ attributeMap $ profileTTL )'
3925 OD['1.3.6.1.4.1.11.1.3.1.2.4']="'DUAConfigProfile' SUP top STRUCTURAL DESC 'Abstraction of a base configuration for a DUA' MUST "'( cn ) MAY ( defaultServerList $ preferredServerList $ defaultSearchBase $ defaultSearchScope $ searchTimeLimit $ bindTimeLimit $ credentialLevel $ authenticationMethod $ followReferrals $ dereferenceAliases $ serviceSearchDescriptor $ serviceCredentialLevel $ serviceAuthenticationMethod $ objectclassMap $ attributeMap $ profileTTL )'" X-ORIGIN 'RFC 4876'"
3926
3927 EE['1.3.18.0.2.6.2549']="'slpService' DESC 'DUMMY definition' SUP top MUST objectclass"
3928 OD['1.3.18.0.2.6.2549']="'slpService' DESC 'parent superclass for SLP services' SUP top ABSTRACT MUST "'( template-major-version-number $ template-minor-version-number $ description $ template-url-syntax $ service-advert-service-type $ service-advert-scopes ) MAY ( service-advert-url-authenticator $ service-advert-attribute-authenticator )'" X-ORIGIN 'RFC 2926'"
3929
3930 EE['1.3.18.0.2.6.254']="'slpServicePrinter' DESC 'Service Location Protocol (SLP) information.' SUP slpService AUXILIARY"
3931 OD['1.3.18.0.2.6.254']="'slpServicePrinter' DESC 'Service Location Protocol (SLP) information.' SUP slpService AUXILIARY X-ORIGIN 'RFC 3712'"
3932
3933 EE['1.3.18.0.2.6.258']="'printerAbstract' DESC 'Printer related information.' SUP top ABSTRACT MAY "'( printer-name $ printer-natural-language-configured $ printer-location $ printer-info $ printer-more-info $ printer-make-and-model $ printer-multiple-document-jobs-supported $ printer-charset-configured $ printer-charset-supported $ printer-generated-natural-language-supported $ printer-document-format-supported $ printer-color-supported $ printer-compression-supported $ printer-pages-per-minute $ printer-pages-per-minute-color $ printer-finishings-supported $ printer-number-up-supported $ printer-sides-supported $ printer-media-supported $ printer-media-local-supported $ printer-resolution-supported $ printer-print-quality-supported $ printer-job-priority-supported $ printer-copies-supported $ printer-job-k-octets-supported $ printer-current-operator $ printer-service-person $ printer-delivery-orientation-supported $ printer-stacking-order-supported $ printer-output-features-supported )'
3934 OD['1.3.18.0.2.6.258']="'printerAbstract' DESC 'Printer related information.' SUP top ABSTRACT MAY "'( printer-name $ printer-natural-language-configured $ printer-location $ printer-info $ printer-more-info $ printer-make-and-model $ printer-multiple-document-jobs-supported $ printer-charset-configured $ printer-charset-supported $ printer-generated-natural-language-supported $ printer-document-format-supported $ printer-color-supported $ printer-compression-supported $ printer-pages-per-minute $ printer-pages-per-minute-color $ printer-finishings-supported $ printer-number-up-supported $ printer-sides-supported $ printer-media-supported $ printer-media-local-supported $ printer-resolution-supported $ printer-print-quality-supported $ printer-job-priority-supported $ printer-copies-supported $ printer-job-k-octets-supported $ printer-current-operator $ printer-service-person $ printer-delivery-orientation-supported $ printer-stacking-order-supported $ printer-output-features-supported )'" X-ORIGIN 'RFC 3712' )"
3935
3936 EE['1.3.18.0.2.6.255']="'printerService' DESC 'Printer information.' SUP printerAbstract STRUCTURAL MAY "'( printer-uri $ printer-xri-supported )'
3937 OD['1.3.18.0.2.6.255']="'printerService' DESC 'Printer information.' SUP printerAbstract STRUCTURAL MAY "'( printer-uri $ printer-xri-supported )'" X-ORIGIN 'RFC 3712'"
3938
3939 EE['1.3.18.0.2.6.257']="'printerServiceAuxClass' DESC 'Printer information.' SUP printerAbstract AUXILIARY MAY "'( printer-uri $ printer-xri-supported )'
3940 OD['1.3.18.0.2.6.257']="'printerServiceAuxClass' DESC 'Printer information.' SUP printerAbstract AUXILIARY MAY "'( printer-uri $ printer-xri-supported )'" X-ORIGIN 'RFC 3712'"
3941
3942 EE['1.3.18.0.2.6.256']="'printerIPP' DESC 'Internet Printing Protocol (IPP) information.' SUP top AUXILIARY MAY "'( printer-ipp-versions-supported $ printer-multiple-document-jobs-supported )'
3943 OD['1.3.18.0.2.6.256']="'printerIPP' DESC 'Internet Printing Protocol (IPP) information.' SUP top AUXILIARY MAY "'( printer-ipp-versions-supported $ printer-multiple-document-jobs-supported )'" X-ORIGIN 'RFC 3712'"
3944
3945 EE['1.3.18.0.2.6.253']="'printerLPR' DESC 'LPR information.' SUP top AUXILIARY MUST printer-name MAY printer-aliases"
3946 OD['1.3.18.0.2.6.253']="'printerLPR' DESC 'LPR information.' SUP top AUXILIARY MUST ( printer-name ) MAY ( printer-aliases ) X-ORIGIN 'RFC 3712'"
3947
3948 EE['1.3.6.1.4.1.42.2.27.5.2.14']="'sunPrinter' DESC 'Sun printer information' SUP top AUXILIARY MUST printer-name MAY "'( sun-printer-bsdaddr $ sun-printer-kvp )'
3949 OD['1.3.6.1.4.1.42.2.27.5.2.14']="'sunPrinter' DESC 'Sun printer information' SUP top AUXILIARY MUST printer-name MAY "'(sun-printer-bsdaddr $ sun-printer-kvp)'" X-ORIGIN 'Solaris Specific'"
3950
3951 EE['1.3.6.1.4.1.42.2.27.5.2.12']="'nisplusTimeZoneData' DESC 'NIS+ timezone table data' SUP top STRUCTURAL MUST cn MAY "'( nisplusTimeZone $ description )'
3952 OD['1.3.6.1.4.1.42.2.27.5.2.12']="'nisplusTimeZoneData' DESC 'NIS+ timezone table data' SUP top STRUCTURAL MUST cn MAY "'( nisplusTimeZone $ description )'" X-ORIGIN 'Solaris Specific'"
3953
3954 EE['1.3.6.1.4.1.42.2.27.5.2.8']="'ipTnetTemplate' DESC 'Object class for TSOL network templates' SUP top MUST ipTnetTemplateName MAY SolarisAttrKeyValue"
3955 OD['1.3.6.1.4.1.42.2.27.5.2.8']="'ipTnetTemplate' DESC 'Object class for TSOL network templates' SUP top STRUCTURAL MUST ipTnetTemplateName MAY SolarisAttrKeyValue X-ORIGIN 'Solaris Specific'"
3956
3957 EE['1.3.6.1.4.1.42.2.27.5.2.9']="'ipTnetHost' DESC 'Associates an IP address or wildcard with a TSOL template_name' SUP top AUXILIARY MUST ipTnetNumber"
3958 OD['1.3.6.1.4.1.42.2.27.5.2.9']="'ipTnetHost' DESC 'Associates an IP address or wildcard with a TSOL template_name' SUP top AUXILIARY MUST ipTnetNumber X-ORIGIN 'Solaris Specific'"
3959
3960 # obey CLI syntax force option (if any)
3961 if (( TMPF[SYNTAX] == 1 )); then
3962 typeset -n MAP=OD
3963 elif (( TMPF[SYNTAX] == 2 )); then
3964 typeset -n MAP=EE
3965 elif (( TMPF[IS_OPENDJ] )); then
3966 typeset -n MAP=OD
3967 else
3968 typeset -n MAP=EE
3969 fi
3970
3971 # we need to preserve order, so 2 passes
3972 typeset TODO='' OID
3973 for OID in ${!MAP[@]}; do
3974 [[ -n ${OID2ODEF[${OID}]} ]] && continue
3975 TODO+="${OID} "
3976 done
3977
3978 if [[ -z ${TODO} ]]; then
3979 X='Schema contains all required objectclass defintions'
3980 else
3981 # 2nd pass
3982 typeset X SORTED
3983 SORTED=${ print ${TODO// /$'\n'} | sort -n -t. ; }
3984 TODO='' TODO2=''
3985 for OID in ${SORTED} ; do
3986 X="${MAP[${OID}]}"
3987 OID2ODEF["${OID}"]="${X}"
3988 # 1.3.18.0.2.6.254 requires 1.3.18.0.2.6.2549
3989 # 1.3.18.0.2.6.255,1.3.18.0.2.6.257 require 1.3.18.0.2.6.258
3990 [[ ${OID} == '1.3.18.0.2.6.254' \
3991 || ${OID} == '1.3.18.0.2.6.255' \
3992 || ${OID} == '1.3.18.0.2.6.257' ]] \
3993 && TODO2+='objectclasses: ( '"${OID} NAME ${X}"' )\n' \
3994 || TODO+='objectclasses: ( '"${OID} NAME ${X}"' )\n'
3995 done
3996
3997 nextFile modify $0
3998 print 'dn: cn=schema\nchangetype: modify\nadd: objectclasses' \
3999 "\n${TODO}${TODO2}" >${TMP[FILE]}
4000 if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
4001 >&${TMPF[FD]} 2>&1
4002 then
4003 Log.fatal 'Adding objectclass definitions to schema failed'
4004 return 67
4005 fi
4006 X='Schema objectclass definitions added'
4007 fi
4008
4009 showProgress "${X}."
4010 return 0
4011 }
4012
4013 Man.addFunc add_suffix '' '[+NAME?add_suffix - add suffix to DS if needed.]
4014 [+DESCRIPTION?Add a suffix to the DS if needed (\bTMPF[NEED_CREATE_SUFFIX]]\b is set) and optionally create the backend for it (\bTMPF[NEED_CREATE_BACKEND]]\b is set). Suffix entry and backend MUST be prepared by \bprep_create_sfx_entry()\b and \bprep_create_sfx_backend()\b correspondingly to have the following vars set:]{
4015 [+STR[LDAP_SUFFIX]] ]
4016 [+STR[DS_DB]] ]
4017 [+TMP[SUFFIX_OBJ]] ]
4018 [+TMP[SUFFIX_ATT]] ]
4019 [+TMP[SUFFIX_VAL]] ]
4020 }
4021 [+RETURN VALUES]{
4022 [+0?on success (suffix not needed or created successfully).]
4023 [+1?otherwise (unable to create suffix).]
4024 }
4025 [+SEE ALSO?\bldapadd\b(1), \bdisplay_msg()\b.]
4026 '
4027 function add_suffix {
4028 if (( ! TMPF[NEED_CREATE_BACKEND] )); then
4029 showProgress "Database backend exists."
4030 else
4031 nextFile add "${0}-backend"
4032 if (( TMPF[IS_OPENDJ] )); then
4033 print '
4034 dn: ds-cfg-backend-id='"${STR[DS_DB]}"',cn=Backends,cn=config
4035 ds-cfg-backend-id: '"${STR[DS_DB]}"'
4036 ds-cfg-base-dn: '"${STR[LDAP_SUFFIX]}"'
4037 objectclass: top
4038 objectclass: ds-cfg-backend
4039 objectclass: ds-cfg-local-db-backend
4040 ds-cfg-java-class: org.opends.server.backends.jeb.BackendImpl
4041 ds-cfg-enabled: true
4042 ds-cfg-writability-mode: enabled
4043 ds-cfg-preload-time-limit: 0 ms
4044 ds-cfg-compact-encoding: true
4045 ds-cfg-entries-compressed: false
4046 ds-cfg-index-entry-limit: 4000
4047 ds-cfg-db-directory: db
4048 ds-cfg-db-directory-permissions: 700
4049 ds-cfg-disk-low-threshold: 100 mb
4050 ds-cfg-disk-full-threshold: 20 mb
4051 ds-cfg-db-run-cleaner: true
4052 ds-cfg-db-cleaner-min-utilization: 50
4053 ds-cfg-db-logging-file-handler-on: true
4054 ds-cfg-db-logging-level: CONFIG
4055 ds-cfg-db-log-filecache-size: 100
4056 ds-cfg-db-log-file-max: 10 mb
4057 ds-cfg-db-cache-size: 0 b
4058 ds-cfg-db-cache-percent: 50
4059 ds-cfg-db-evictor-core-threads: 1
4060 ds-cfg-db-evictor-max-threads: 10
4061 ds-cfg-db-evictor-nodes-per-scan: 10
4062 ds-cfg-db-evictor-lru-only: true
4063 ds-cfg-db-evictor-keep-alive: 600 s
4064 ds-cfg-db-txn-no-sync: false
4065 ds-cfg-db-txn-write-no-sync: true
4066 ds-cfg-db-checkpointer-wakeup-interval: 30 s
4067 ds-cfg-db-checkpointer-bytes-interval: 20 mb
4068 ' >${TMP[FILE]}
4069 else
4070 print '
4071 dn: cn="'"${STR[LDAP_SUFFIX]}"'",cn=mapping tree,cn=config
4072 objectclass: top
4073 objectclass: extensibleObject
4074 objectclass: nsMappingTree
4075 cn: '"${STR[LDAP_SUFFIX]}"'
4076 nsslapd-state: backend
4077 nsslapd-backend: '"${STR[DS_DB]}"'
4078
4079 dn: cn='"${STR[DS_DB]}"',cn=ldbm database,cn=plugins,cn=config
4080 objectclass: top
4081 objectclass: extensibleObject
4082 objectclass: nsBackendInstance
4083 cn: '"${STR[DS_DB]}"'
4084 nsslapd-suffix: '"${STR[LDAP_SUFFIX]}"'
4085 ' >${TMP[FILE]}
4086 fi
4087
4088 if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
4089 >&${TMPF[FD]} 2>&1
4090 then
4091 Log.fatal 'Unable to create backend' "'${STR[DS_DB]}'" \
4092 'with suffix' "'${STR[LDAP_SUFFIX]}'" 'due to server error.'
4093 return 1
4094 fi
4095 showProgress "Database backend created."
4096 fi
4097
4098 if (( ! TMPF[NEED_CREATE_SUFFIX] )); then
4099 showProgress "Suffix exists."
4100 else
4101 nextFile add $0
4102 print '
4103 dn: '"${STR[LDAP_SUFFIX]}"'
4104 objectclass: top
4105 objectclass: '"${TMP[SUFFIX_OBJ]}"'
4106 '"${TMP[SUFFIX_ATT]}: ${TMP[SUFFIX_VAL]}"'
4107 ' >${TMP[FILE]}
4108 if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
4109 >&${TMPF[FD]} 2>&1
4110 then
4111 Log.warn 'Unable to create entry' "'${STR[LDAP_SUFFIX]}'" 'of' \
4112 "'${TMP[SUFFIX_OBJ]}'" 'class'
4113 return 1
4114 fi
4115 showProgress "Suffix added."
4116 fi
4117 return 0
4118 }
4119
4120 function add_suffix_aci {
4121 typeset PW_STATE PW_STATE_RO ANY_NO_READ SELF_NO_WRITE
4122 typeset ADMIN_DN ADMIN_GROUP_DN
4123 if (( TMPF[IS_OPENDJ] )); then
4124 # TBD: include Password Policy State extended ops ?
4125
4126 # password state information aka ds-pwp-*, pwd* and ds-pta-* WITHOUT
4127 # attrs, which are schema flagged with NO-USER-MODIFICATION
4128 PW_STATE=' ds-pwp-account-disabled || ds-pwp-account-expiration-time
4129 || ds-pwp-last-login-time || ds-pwp-password-changed-by-required-time
4130 || ds-pwp-password-policy-dn || ds-pwp-reset-time || ds-pwp-warned-time
4131 || ds-privilege-name || pwdReset'
4132 # password state information flagged with NO-USER-MODIFICATION
4133 # ds-pwp-password-expiration-time is the same as pwdExpirationTime
4134 # so save some parse time ;-)
4135 PW_STATE_RO=' pwdExpirationTime || pwdChangedTime || pwdGraceUseTime
4136 || pwdFailureTime || pwdHistory || pwdAccountLockedTime'
4137 # People using PassThroughAuthentication probably wish that too:
4138 #PW_STATE_RO+='|| ds-pta-cached-password || ds-pta-cached-password-time'
4139
4140 # passwords + password state
4141 ANY_NO_READ="userPassword || authPassword ||${PW_STATE}||${PW_STATE_RO}"
4142 # aci + search limits aka ds-rlim-* + RW password state/policy
4143 SELF_NO_WRITE='aci || ds-rlim-idle-time-limit
4144 || ds-rlim-lookthrough-limit || ds-rlim-size-limit || ds-rlim-time-limit
4145 || pwdPolicySubentry ||'"${PW_STATE}"
4146 ADMIN_DN='uid=admin,cn=Administrators'
4147 ADMIN_GROUP_DN='cn=Administrators'
4148 ADMIN_DN+=',cn=admin data'
4149 ADMIN_GROUP_DN+=',cn=admin data'
4150 else
4151 # DSEE
4152 # password state information aka passwordObject
4153 PW_STATE=' accountUnlockTime || passwordAllowChangeTime
4154 || passwordExpWarned || passwordExpirationTime || passwordHistory
4155 || passwordRetryCount || retryCountResetTime'
4156
4157 # passwords + password state
4158 ANY_NO_READ="userPassword ||${PW_STATE}"
4159 # aci + search limits + password state/policy
4160 SELF_NO_WRITE='aci || nsIdleTimeout || nsLookThroughLimit
4161 || nsSizeLimit || nsTimeLimit || nsroledn || passwordPolicySubentry
4162 ||'"${PW_STATE}"
4163 ADMIN_DN='uid=admin,ou=Administrators'
4164 ADMIN_GROUP_DN='cn=Configuration Administrators,ou=Groups'
4165 ADMIN_DN+=',ou=TopologyManagement,o=NetscapeRoot'
4166 ADMIN_GROUP_DN+=',ou=TopologyManagement,o=NetscapeRoot"'
4167 fi
4168
4169 typeset -A RULES=(
4170 [SFX_ANYONE_ACI_NAME]='aci: (targetattr != "'"${ANY_NO_READ//$'\n'}"'")
4171 (
4172 version 3.0; acl "'"${SFX_ANYONE_ACI_NAME}"'";
4173 allow (read, search, compare) userdn = "ldap:///anyone";
4174 )'
4175 [SFX_SELF_ACI_NAME]='aci: (targetattr != "'"${SELF_NO_WRITE//$'\n'}"'")
4176 (
4177 version 3.0; acl "'"${SFX_SELF_ACI_NAME}"'";
4178 allow (write) userdn = "ldap:///self";
4179 )'
4180 [SFX_ADMIN_ACI_NAME]='aci: (targetattr = "*")
4181 (
4182 version 3.0; acl "'"${SFX_ADMIN_ACI_NAME}"'";
4183 allow (all) userdn = "ldap:///'"${ADMIN_DN}"'";
4184 )'
4185 [SFX_ADMINGRP_ACI_NAME]='aci: (targetattr ="*")
4186 (
4187 version 3.0; acl "'"${SFX_ADMINGRP_ACI_NAME}"'";
4188 allow (all) groupdn = "ldap:///'"${ADMIN_GROUP_DN}"'";
4189 )'
4190 )
4191
4192 # Check and set if doesn't already exist
4193 typeset -a LIST=( )
4194 getACIs LIST "${STR[LDAP_SUFFIX]}"
4195
4196 for ACI in "${!RULES[@]}" ; do
4197 typeset -n NAME=${ACI}
4198 [[ -z ${NAME} ]] && continue # if it has no name, ignore it
4199 PATTERN='acl[ ]+"?'"${NAME}"'"?'
4200 findACI LIST "${NAME}" "${PATTERN}" 'Suffix' || continue # exists
4201 nextFile add "${0}-${NAME}"
4202 print '
4203 dn: '"${STR[LDAP_SUFFIX]}"'
4204 changetype: modify
4205 add: aci
4206 '"${RULES[${ACI}]}"'
4207 ' >${TMP[FILE]}
4208 if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
4209 >&${TMPF[FD]} 2>&1
4210 then
4211 Log.warn "Adding '${NAME}' suffix ACI failed"
4212 return 1
4213 fi
4214 showProgress "Suffix ACI '${NAME}' added."
4215 done
4216 return 0
4217 }
4218
4219 Man.addFunc add_base_objects '' '[+NAME?add_base_objects - add possibly missing, necessary base objects.]
4220 [+DESCRIPTION?Determine all RDNs required to form the \bSTR[LDAP_BASEDN]]\b using the suffix \bSTR[LDAP_SUFFIX]]\b (RDN1,RDN2,...,suffix == baseDN) and create the missing entries.]
4221 [+RETURN VALUES]{
4222 [+0?on success (all entries available or created successfully).]
4223 [+>= 66?a fatal error occured.]
4224 }
4225 [+SEE ALSO?\bnormalizeDN()\b, \bldapsearch\b(1), \bldapmodify\b(1).]
4226 '
4227 function add_base_objects {
4228 # typeset -A STR
4229 # STR[LDAP_BASEDN]=dc=x,dc=my,dc=do,dc=main,dc=de
4230 # STR[LDAP_SUFFIX]=dc=do,dc=main,dc=de
4231
4232 # Convert to lower case for basename.
4233 typeset LC_DN=','${ normalizeDN "${STR[LDAP_BASEDN]}" l ; }
4234 typeset LC_SFX=','${ normalizeDN "${STR[LDAP_SUFFIX]}" l ; }
4235
4236 # first, test that baseDN ends with suffix
4237 if [[ ${LC_DN: -${#LC_SFX}} != ${LC_SFX} ]]; then
4238 # should not happen since check_basedn_suffix() succeeded
4239 Log.fatal "Invalid suffix '${LC_SFX}' for Base DN '${LC_DN}'"
4240 return 66
4241 fi
4242 # Save the stuff before LC_SFX w/o leading ',' -> further called prefix
4243 LC_DN=${LC_DN:1:${#LC_DN}-${#LC_SFX}-1}
4244
4245 # Remove redundant spaces around ',' and '=' first from LDAP_BASEDN
4246 typeset DN=${ normalizeDN ${STR[LDAP_BASEDN]} ; }
4247
4248 # Now LC_DN and DN differ at most in lower vs. uppercase character and
4249 # we can get the prefix of the baseDN by just copying corresponding chars
4250 DN=",${DN:0:${#LC_DN}}"
4251
4252 if [[ ${DN} == ',' ]]; then
4253 X='No need to create a DN component (baseDN equals suffix)'
4254 else
4255 typeset LAST=${ normalizeDN ${STR[LDAP_SUFFIX]} ; } DC KEY VAL CLASS
4256 X="Created DN components for ${DN#,}"
4257 while [[ -n ${DN} ]]; do
4258 # Get trailing key=val (DC) from DN and strip it off
4259 DN=${DN%,*}
4260 DC="${.sh.match#,}"
4261 LAST="${DC},${LAST}"
4262
4263 # Check if entry exists first, if so, skip to next.
4264 ${LDAPSEARCH} ${CON_ARGS} -b "${LAST}" -s base \
4265 'objectclass=*' >/dev/null 2>&1 && continue
4266
4267 VAL=${DC#*=}
4268 KEY=${.sh.match%=}
4269 # Determine the objectclass for the entry.
4270 CLASS=${ get_objectclass ${KEY} ; }
4271 if [[ -z ${CLASS} ]]; then
4272 Log.fatal "Unable to determine objectClass for '${KEY}'." \
4273 "Please create the following entry and re-run ${PROG}:" \
4274 "${KEY}=${VAL},${LAST}"
4275 return 66
4276 fi
4277
4278 nextFile add "${0}-${LAST}"
4279 print '
4280 dn: '"${LAST}"'
4281 '"${KEY}: ${VAL}"'
4282 objectClass: top
4283 objectClass: '"${CLASS}"'
4284 ' > ${TMP[FILE]}
4285
4286 if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]}\
4287 >&${TMPF[FD]} 2>&1
4288 then
4289 Log.fatal "Update of base objects '${DC}' failed"
4290 return 66
4291 fi
4292 done
4293 fi
4294 showProgress "${X}."
4295 return 0
4296 }
4297
4298 Man.addFunc set_nisdomain '' '[+NAME?set_nisdomain - Add the NisDomainObject to the Base DN.]
4299 [+DESCRIPTION?Add a NisDomainObject with nisdomain \bSTR[LDAP_DOMAIN]]\b to the \bSTR[LDAP_BASEDN]]\b unless there is already one.]
4300 [+RETURN VALUES]{
4301 [+0?on success.]
4302 [+>= 66?a fatal error occured.]
4303 }
4304 [+SEE ALSO?\bldapsearch\b(1), \bldapmodify\b(1).]
4305 '
4306 function set_nisdomain {
4307 # Check if nisDomain is already set
4308 ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b "${STR[LDAP_BASEDN]}" \
4309 -s base 'objectclass=*' 2>/dev/null | \
4310 while read LINE ; do
4311 if [[ ${LINE} == ~(Ei)^nisDomain= ]]; then
4312 showProgress 'NisDomainObject was already set for' \
4313 "'${STR[LDAP_BASEDN]}'."
4314 return 0
4315 fi
4316 done
4317
4318 nextFile modify $0
4319 print '
4320 dn: '"${STR[LDAP_BASEDN]}"'
4321 changetype: modify
4322 objectclass: nisDomainObject
4323 nisdomain: '"${STR[LDAP_DOMAIN]}"'
4324 ' >${TMP[FILE]}
4325
4326 if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
4327 >&${TMPF[FD]} 2>&1
4328 then
4329 Log.fatal "Update of NisDomainObject in '${STR[LDAP_BASEDN]}' failed"
4330 return 66
4331 fi
4332
4333 showProgress "NisDomainObject added to '${STR[LDAP_BASEDN]}'."
4334 return 0
4335 }
4336
4337 Man.addFunc add_new_containers '' '[+NAME?add_new_containers - Add top level containers to the base DN.]
4338 [+DESCRIPTION?Add the Name Service Switch top level containers to the \bSTR[LDAP_BASEDN]]\b unless they already exist.]
4339 [+RETURN VALUES]{
4340 [+0?on success.]
4341 [+>= 66?a fatal error occured.]
4342 }
4343 [+SEE ALSO?\b/etc/nsswitch.ldap\b, \bldapsearch\b(1), \bldapmodify\b(1).]
4344 '
4345 function add_new_containers {
4346 typeset OU
4347
4348 for OU in people group rpc protocols networks netgroup \
4349 aliases hosts services ethers profile printers projects \
4350 SolarisAuthAttr SolarisProfAttr Timezone ipTnet
4351 do
4352 if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
4353 -b "ou=${OU},${STR[LDAP_BASEDN]}" -s base 'objectclass=*' \
4354 >/dev/null 2>&1
4355 then
4356 showProgress "'ou=${OU}' exists."
4357 continue
4358 fi
4359
4360 nextFile add "${0}-${OU}"
4361 print '
4362 dn: ou='"${OU},${STR[LDAP_BASEDN]}"'
4363 ou: '"${OU}"'
4364 objectClass: top
4365 objectClass: organizationalUnit
4366 ' > ${TMP[FILE]}
4367
4368 if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
4369 >&${TMPF[FD]} 2>&1
4370 then
4371 Log.fatal "Adding 'ou=${OU}' failed"
4372 return 66
4373 fi
4374 showProgress "'ou=${OU}' added."
4375 done
4376
4377 return 0
4378 }
4379
4380 Man.addFunc add_auto_maps '' '[+NAME?add_auto_maps - Add the automount map entries.]
4381 [+DESCRIPTION?Add the automount maps \bauto_home\b, \bauto_direct\b, \bauto_master\b, \bauto_shared\b to \bSTR[LDAP_BASEDN]]\b unless they already exist.]
4382 [+RETURN VALUES]{
4383 [+0?on success.]
4384 [+>= 66?a fatal error occured.]
4385 }
4386 [+SEE ALSO?\bldapsearch\b(1), \bldapmodify\b(1).]
4387 '
4388 function add_auto_maps {
4389 # AUTO_MAPS for maps to create
4390 typeset AUTO_MAPS="auto_home auto_direct auto_master auto_shared" MAP
4391
4392 for MAP in ${AUTO_MAPS}; do
4393 # Check if automap already exist
4394 if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
4395 -b "automountMapName=${MAP},${STR[LDAP_BASEDN]}" -s base \
4396 'objectclass=*' >/dev/null 2>&1
4397 then
4398 showProgress "'${MAP}' automount exists."
4399 continue
4400 fi
4401
4402 nextFile add "${0}-${MAP}"
4403 print '
4404 dn: automountMapName='"${MAP},${STR[LDAP_BASEDN]}"'
4405 automountMapName: '"${MAP}"'
4406 objectClass: top
4407 objectClass: automountMap
4408 ' > ${TMP[FILE]}
4409
4410 if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
4411 >&${TMPF[FD]} 2>&1
4412 then
4413 Log.fatal "Adding '${MAP}' automount map failed"
4414 return 66
4415 fi
4416 showProgress "'${MAP}' automount added."
4417 done
4418
4419 return 0
4420 }
4421
4422 Man.addFunc modify_top_aci '' '[+NAME?modify_top_aci - add a deny self modify ACI.]
4423 [+DESCRIPTION?Add the ACI \bUSER_ACI_NAME\b to \bSTR[LDAP_BASEDN]]\b to disable self modify of user attributes like uid, uidNumber, gidNumber, shadowExpire, etc. This does nothing if an ACI with the same name already exists for this entry.]
4424 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage USER_ACI_NAME ; }" '}
4425 [+RETURN VALUES]{
4426 [+0?on success (ACI already exists or added successfully).]
4427 [+>= 66?a fatal error occured.]
4428 }
4429 [+SEE ALSO?\bgetACIs()\b, \bfindACI()\b, \bldapmodify\b(1).]
4430 '
4431 function modify_top_aci {
4432 typeset PATTERN
4433
4434 typeset -a LIST=( )
4435 getACIs LIST || return 66
4436
4437 # check, whether ACI already exists
4438 PATTERN='acl[ ]+"?('"${USER_ACI_NAME}|${USER_ACI_NAME// /_}"')"?'
4439 findACI LIST "${USER_ACI_NAME}" "${PATTERN}" || return 0 # exists
4440
4441 # Create LDIF for top level ACI
4442 nextFile modify $0
4443 print '
4444 dn: '"${STR[LDAP_BASEDN]}"'
4445 changetype: modify
4446 add: aci
4447 aci: (targetattr = "cn || uid || uidNumber || gidNumber || homeDirectory || shadowLastChange || shadowMin || shadowMax || shadowWarning || shadowInactive || shadowExpire || shadowFlag || memberUid || SolarisAttrKeyValue || SolarisAttrReserved1 || SolarisAttrReserved2 || SolarisUserQualifier")
4448 (
4449 version 3.0; acl "'"${USER_ACI_NAME}"'";
4450 deny (write) userdn = "ldap:///self";
4451 )
4452 ' > ${TMP[FILE]}
4453
4454 if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
4455 >&${TMPF[FD]} 2>&1
4456 then
4457 Log.fatal 'Deny user to change non-password attributes failed'
4458 return 66
4459 fi
4460
4461 showProgress "Self modify for non-password attributes disabled."
4462 return 0
4463 }
4464
4465 Man.addFunc add_vlv_aci '' '[+NAME?add_vlv_aci - Add ACI for VLV.]
4466 [+DESCRIPTION?Add the global ACI to allow everyone read-only access to VLVs.]
4467 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage VLV_ACI_NAME ; }" '}
4468 [+RETURN VALUES]{
4469 [+0?on success (ACI added successfully).]
4470 [+>= 66?a fatal error occured.]
4471 }
4472 [+SEE ALSO?\bldapmodify\b(1).]
4473 '
4474 function add_vlv_aci {
4475 # VLV Request = 2.16.840.1.113730.3.4.9
4476 typeset RULE='version 3.0; acl "'"${VLV_ACI_NAME}"'";\n\t'
4477 RULE+='allow (read,search,compare) userdn = "ldap:///anyone";'
4478 typeset DN='oid=2.16.840.1.113730.3.4.9,cn=features,cn=config'
4479 (( TMPF[IS_OPENDJ] )) && DN='cn=Access Control Handler,cn=config'
4480
4481 typeset -a LIST=( )
4482 getACIs LIST "${DN}" 'Global' || return 66
4483
4484 PATTERN='acl[ ]+"?('"${VLV_ACI_NAME}|${VLV_ACI_NAME// /_}"')"?'
4485 findACI LIST "${VLV_ACI_NAME}" "${PATTERN}" 'Global' || return 0
4486
4487 nextFile modify $0
4488 if (( TMPF[IS_OPENDJ] )); then
4489 print '
4490 dn: '"${DN}"'
4491 changetype: modify
4492 add: ds-cfg-global-aci
4493 ds-cfg-global-aci: (targetcontrol = "2.16.840.1.113730.3.4.9")(targetattr != "aci")
4494 (
4495 '"${RULE}"'
4496 )
4497 ' > ${TMP[FILE]}
4498 else
4499 print '
4500 dn: '"${DN}"'
4501 changetype: modify
4502 replace: aci
4503 aci: (targetattr != "aci")
4504 (
4505 '"${RULE}"'
4506 )
4507 ' > ${TMP[FILE]}
4508 fi
4509
4510 if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
4511 >&${TMPF[FD]} 2>&1
4512 then
4513 Log.fatal "Adding '${VLV_ACI_NAME}' global ACI failed"
4514 return 66
4515 fi
4516
4517 showProgress "Global ACI '${VLV_ACI_NAME}' added."
4518 return 0
4519 }
4520
4521 Man.addFunc add_proxyagent '' '[+NAME?add_proxyagent - Add proxy agent user to DS.]
4522 [+DESCRIPTION?Add the proxy agent user \bSTR[LDAP_PROXYAGENT]]\b to the DS unless it already exists to allow nameservice access to the server.]
4523 [+RETURN VALUES]{
4524 [+0?on success (entry already exists or added successfully).]
4525 [+>= 66?a fatal error occured.]
4526 }
4527 [+SEE ALSO?\bldapmodify\b(1).]
4528 '
4529 function add_proxyagent {
4530 # Check if proxy agent already exists
4531 if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
4532 -b "${STR[LDAP_PROXYAGENT]}" -s base 'objectclass=*' >/dev/null 2>&1
4533 then
4534 showProgress "Proxyagent identity exists."
4535 return 0
4536 fi
4537
4538 # Get cn and sn names from LDAP_PROXYAGENT.
4539 typeset NAME="${STR[LDAP_PROXYAGENT]%%,*}"
4540 NAME=${NAME#*=}
4541
4542 # Add the entry
4543 nextFile add $0
4544 print '
4545 dn: '"${STR[LDAP_PROXYAGENT]}"'
4546 cn: '"${NAME}"'
4547 sn: '"${NAME}"'
4548 objectclass: top
4549 objectclass: person
4550 userpassword: '"${STR[LDAP_PROXYAGENT_CRED]}"'
4551 ' > ${TMP[FILE]}
4552
4553 if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
4554 >&${TMPF[FD]} 2>&1
4555 then
4556 Log.fatal 'Adding proxyagent identity failed'
4557 return 66
4558 fi
4559
4560 showProgress 'Proxyagent identity added.'
4561 return 0
4562 }
4563
4564 Man.addFunc add_entry_by_DN '' '[+NAME?add_entry_by_DN - Add an ldif file by DN.]
4565 [+DESCRIPTION?Add the entries in the given LDIF \afile\a to the DS unless a base entry for \aDN\a already exists.]
4566 [+RETURN VALUES]{
4567 [+0?on success (\aDN\a already exists or added successfully).]
4568 [+1?on error (failed to add entries).]
4569 }
4570 [+SEE ALSO?\bldapsearch\b(1), \bldapadd\b(1).]
4571 \n\n\aDN\a \afile\a
4572 '
4573 function add_entry_by_DN {
4574 if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b "$1" -s base \
4575 'objectclass=*' >/dev/null 2>&1
4576 then
4577 showProgress "'${1}' exists."
4578 return 0
4579 fi
4580 if ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f "$2" >&${TMPF[FD]} 2>&1
4581 then
4582 showProgress "'${1}' added."
4583 return 0
4584 fi
4585 Log.fatal "Adding '${1}' failed"
4586 return 1
4587 }
4588
4589 Man.addFunc add_id_mapping_rules '' '[+NAME?add_id_mapping_rules - Add Kerberos principal to DN mapping rules to the DS.]
4590 [+DESCRIPTION?Add GSSAPI identity mapping rules for host credentails and user credentials to the DS config unless they already exists. Hosts are matched against \b*.STR[LDAP_DOMAIN]]@STR[LDAP_KRB_REALM]]\b and ou=hosts in \bSTR[LDAP_BASEDN]]\b, users against \b*.@STR[LDAP_KRB_REALM]]\b and uid=$1,ou=People in \bSTR[LDAP_BASEDN]]\b.]
4591 [+SEE ALSO?\badd_entry_by_DN()\b.]
4592 '
4593 function add_id_mapping_rules {
4594 Log.info 'Adding Kerberos principal to DN mapping rules ...'
4595 typeset C_DN='cn=GSSAPI,cn=identity mapping,cn=config' OC='nsContainer'
4596 if (( TMPF[IS_OPENDJ] )); then
4597 # we create a new branch instead of reusing the default, possibly unused
4598 # 'cn=Regular Expression,cn=Identity Mappers,cn=config' GSSAPI ID mapper
4599 C_DN='cn=GSSAPI,cn=Identity Mappers,cn=config'
4600 OC='ds-cfg-branch'
4601 fi
4602
4603 nextFile add "${0}-krbPrincipal"
4604 print '
4605 dn: cn='"${C_DN}"'
4606 objectClass: top
4607 objectClass: '"${OC}"'
4608 cn: GSSAPI
4609 ' > ${TMP[FILE]}
4610 add_entry_by_DN "${C_DN}" ${TMP[FILE]} || return
4611
4612 typeset H_CN="host_auth_${STR[LDAP_KRB_REALM]}"
4613 typeset H_DN="cn=${H_CN}, ${C_DN}"
4614 nextFile add "${0}-krbHostAuth"
4615 if (( TMPF[IS_OPENDJ] )); then
4616 print '
4617 # For now (2.6.0) OpenDJ supports a single-valued ds-cfg-identity-mapper, only.
4618 # So either you merge this and the next Identity Mapper to something more useful
4619 # together or just enable one of them until it gets fixed. For more information
4620 # see https://bugster.forgerock.org/jira/browse/OPENDJ-521
4621 dn: '"${H_DN}"'
4622 cn: '"${H_CN}"'
4623 objectClass: top
4624 objectClass=ds-cfg-identity-mapper
4625 objectClass=ds-cfg-regular-expression-identity-mapper
4626 ds-cfg-java-class=org.opends.server.extensions.RegularExpressionIdentityMapper
4627 ds-cfg-enabled=false
4628 ds-cfg-match-base-dn=ou=hosts,'"${STR[LDAP_BASEDN]}"'
4629 ds-cfg-match-pattern=host\/(.*).'"${STR[LDAP_DOMAIN]}@${STR[LDAP_KRB_REALM]}"'
4630 ds-cfg-replace-pattern=$1
4631 ds-cfg-match-attribute=cn
4632 ' > ${TMP[FILE]}
4633 else
4634 print '
4635 dn: '"${H_DN}"'
4636 objectClass: top
4637 objectClass: nsContainer
4638 objectClass: dsIdentityMapping
4639 objectClass: dsPatternMatching
4640 cn: '"${H_CN}"'
4641 dsMatching-pattern: ${Principal}
4642 dsMatching-regexp: host\/(.*).'"${STR[LDAP_DOMAIN]}@${STR[LDAP_KRB_REALM]}"'
4643 dsSearchBaseDN: ou=hosts,'"${STR[LDAP_BASEDN]}"'
4644 dsSearchFilter: (&(objectClass=ipHost)(cn=$1))
4645 dsSearchScope: one
4646 ' > ${TMP[FILE]}
4647 fi
4648 add_entry_by_DN "${H_DN}" ${TMP[FILE]}
4649
4650 typeset U_CN="user_auth_${STR[LDAP_KRB_REALM]}"
4651 typeset U_DN="cn=${U_CN}, ${C_DN}"
4652 nextFile add "${0}-krbUserAuth"
4653 if (( TMPF[IS_OPENDJ] )); then
4654 print '
4655 dn: '"${U_DN}"'
4656 cn: '"${U_CN}"'
4657 objectClass: top
4658 objectClass=ds-cfg-identity-mapper
4659 objectClass=ds-cfg-regular-expression-identity-mapper
4660 ds-cfg-java-class=org.opends.server.extensions.RegularExpressionIdentityMapper
4661 ds-cfg-enabled=true
4662 ds-cfg-match-base-dn=ou=People,'"${STR[LDAP_BASEDN]}"'
4663 ds-cfg-match-pattern=(.*)@'"${STR[LDAP_KRB_REALM]}"'
4664 ds-cfg-replace-pattern=$1
4665 ds-cfg-match-attribute=uid
4666 ' > ${TMP[FILE]}
4667 else
4668 print '
4669 dn: '"${U_DN}"'
4670 objectClass: top
4671 objectClass: nsContainer
4672 objectClass: dsIdentityMapping
4673 objectClass: dsPatternMatching
4674 cn: '"${U_CN}"'
4675 dsMatching-pattern: ${Principal}
4676 dsMatching-regexp: (.*)@'"${STR[LDAP_KRB_REALM]}"'
4677 dsMappedDN: uid=$1,ou=People,'"${STR[LDAP_BASEDN]}"'
4678 ' > ${TMP[FILE]}
4679 fi
4680 add_entry_by_DN "${U_DN}" ${TMP[FILE]}
4681 }
4682
4683 Man.addFunc modify_userpassword_acl_for_gssapi '' '[+NAME?modify_userpassword_acl_for_gssapi - Allow hosts and user to read password(s).]
4684 [+DESCRIPTION?Modify ACL to allow hosts to read all and a user to read its own password only, when sasl/GSSAPI bind is used.]
4685 [+RETURN VALUES]{
4686 [+0?on success (entries already exist or added successfully).]
4687 [+>= 66?a fatal error occured.]
4688 }
4689 [+SEE ALSO?\badd_entry_by_DN()\b.]
4690 '
4691 function modify_userpassword_acl_for_gssapi {
4692 typeset P_DN="ou=People,${STR[LDAP_BASEDN]}"
4693 typeset H_DN="ou=Hosts,${STR[LDAP_BASEDN]}"
4694
4695 if ! ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b "${P_DN}" -s base \
4696 'objectclass=*' > /dev/null 2>&1
4697 then
4698 Log.verbose "'${P_DN}' does not exist"
4699
4700 nextFile add $0
4701 print '
4702 dn: '"${P_DN}"'
4703 ou: People
4704 objectClass: top
4705 objectClass: organizationalUnit
4706 ' > ${TMP[FILE]}
4707
4708 add_entry_by_DN "${P_DN}" ${TMP[FILE]}
4709 else
4710 Log.verbose "'${P_DN}' already exists"
4711 fi
4712 typeset TARGET='userPassword' PATTERN
4713 (( TMPF[IS_OPENDJ] )) && TARGET+=' || authPassword'
4714
4715 typeset -A RULES=(
4716 [SELF_GSS_ACI_NAME]='aci: (targetattr = "'"${TARGET}"'")
4717 (
4718 version 3.0; acl self-read-pwd;
4719 allow (read,search) userdn="ldap:///self" and authmethod="sasl GSSAPI";
4720 )'
4721 [HOST_GSS_ACI_NAME]='aci: (targetattr = "'"${TARGET}"'")
4722 (
4723 version 3.0; acl host-read-pwd;
4724 allow (read,search) userdn="ldap:///cn=*+ipHostNumber=*,ou=Hosts,'"${STR[LDAP_BASEDN]}"'" and authmethod="sasl GSSAPI";
4725 )'
4726 )
4727
4728 typeset -a LIST=( )
4729 getACIs LIST "${P_DN}" || return 66
4730
4731 for ACI in "${!RULES[@]}" ; do
4732 typeset -n NAME=${ACI}
4733 [[ -z ${NAME} ]] && continue # if it has no name, ignore it
4734 PATTERN='acl[ ]+"?'"${NAME}"'"?'
4735 findACI LIST "${NAME}" "${PATTERN}" 'ou=people' || continue # exists
4736 nextFile add "${0}-${NAME}"
4737 print '
4738 dn: '"${P_DN}"'
4739 changetype: modify
4740 add: aci
4741 '"${RULES[${ACI}]}"'
4742 ' > ${TMP[FILE]}
4743
4744 if ! ${LDAPMODIFY} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
4745 >&${TMPF[FD]} 2>&1
4746 then
4747 Log.warn "Adding '${NAME}' ou=people ACI failed."
4748 return 67
4749 fi
4750 showProgress "ou=people ACI '${NAME}' added."
4751 done
4752 return 0
4753 }
4754
4755 Man.addFunc add_profile '' '[+NAME?add_profile - Add client profile to server.]
4756 [+DESCRIPTION?Generates a client profile and adds it to the DS as "\bcn=STR[LDAP_PROFILE_NAME]],ou=profile,STR[LDAP_BASEDN]]\b" unless it already exists and \bTMPF[DEL_OLD_PROFILE]]\b is not set. Other profile related variables are:]{
4757 [+?STR[LDAP_SERVER_LIST]] ]
4758 [+?STR[LDAP_SEARCH_SCOPE]] ]
4759 [+?STR[LDAP_CRED_LEVEL]] ]
4760 [+?STR[LDAP_AUTHMETHOD]] ]
4761 [+?INT[LDAP_FOLLOWREF]] ]
4762 [+?INT[LDAP_SEARCH_TIME_LIMIT]] ]
4763 [+?INT[LDAP_PROFILE_TTL]] ]
4764 [+?INT[LDAP_BIND_LIMIT]] ]
4765 [+?STR[LDAP_PREF_SRVLIST]] ]
4766 [+?STR[LDAP_SRV_AUTHMETHOD_PAM]] ]
4767 [+?STR[LDAP_SRV_AUTHMETHOD_KEY]] ]
4768 [+?STR[LDAP_SRV_AUTHMETHOD_CMD]] ]
4769 [+?SSD]
4770 }
4771 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage INT STR SSD ; }" '}
4772 [+RETURN VALUES]{
4773 [+0?on success.]
4774 [+>= 66?fatal error.]
4775 }
4776 [+SEE ALSO?\bldapclient\b(1M), \bldapdelete\b(1), \bldapmodify\b(1).]
4777 '
4778 function add_profile {
4779 # If profile name already exists, DELETE it, and add new one
4780 if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
4781 -b "cn=${STR[LDAP_PROFILE_NAME]},ou=profile,${STR[LDAP_BASEDN]}" \
4782 -s base 'objectclass=*' >/dev/null 2>&1
4783 then
4784 if (( ! TMPF[DEL_OLD_PROFILE] )); then
4785 Log.fatal "Adding client profile name '${STR[LDAP_PROFILE_NAME]}'" \
4786 'failed (entry already exists)'
4787 return 66
4788 fi
4789
4790 nextFile delete $0
4791 print "cn=${STR[LDAP_PROFILE_NAME]},ou=profile,${STR[LDAP_BASEDN]}" \
4792 >${TMP[FILE]}
4793 if ! ${LDAPDELETE} ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
4794 >&${TMPF[FD]} 2>&1
4795 then
4796 Log.fatal 'Attempt to DELETE old client profile' \
4797 "'${STR[LDAP_PROFILE_NAME]}' failed"
4798 return 67
4799 fi
4800 fi
4801
4802 # Build the "ldapclient genprofile" command string to execute
4803 typeset -a ARG=( )
4804 ARG+=( genprofile '-a' "profileName=${STR[LDAP_PROFILE_NAME]}" )
4805
4806 # Add required argument defaultSearchBase
4807 ARG+=( -a "defaultSearchBase=${STR[LDAP_BASEDN]}" )
4808
4809 # Add optional parameters
4810 [[ -n ${STR[LDAP_SERVER_LIST]} ]] && \
4811 ARG+=( -a "defaultServerList=${STR[LDAP_SERVER_LIST]}" )
4812 [[ -n ${STR[LDAP_SEARCH_SCOPE]} ]] && \
4813 ARG+=( -a "defaultSearchScope=${STR[LDAP_SEARCH_SCOPE]}" )
4814 [[ -n ${STR[LDAP_CRED_LEVEL]} ]] && \
4815 ARG+=( -a "credentialLevel=${STR[LDAP_CRED_LEVEL]}" )
4816 [[ -n ${STR[LDAP_AUTHMETHOD]} ]] && \
4817 ARG+=( -a "authenticationMethod=${STR[LDAP_AUTHMETHOD]}" )
4818 (( INT[LDAP_FOLLOWREF] )) && X='TRUE"' || X='FALSE"'
4819 ARG+=( -a "followReferrals=${X}" )
4820 (( INT[LDAP_SEARCH_TIME_LIMIT] )) && \
4821 ARG+=( -a "searchTimeLimit=${INT[LDAP_SEARCH_TIME_LIMIT]}" )
4822 (( INT[LDAP_PROFILE_TTL] )) && \
4823 ARG+=( -a "profileTTL=${INT[LDAP_PROFILE_TTL]}" )
4824 [[ -n ${INT[LDAP_BIND_LIMIT]} ]] && \
4825 ARG+=( -a "bindTimeLimit=${INT[LDAP_BIND_LIMIT]}" )
4826 [[ -n ${STR[LDAP_PREF_SRVLIST]} ]] && \
4827 ARG+=( -a "preferredServerList=${STR[LDAP_PREF_SRVLIST]}" )
4828 [[ -n ${STR[LDAP_SRV_AUTHMETHOD_PAM]} ]] && \
4829 ARG+=(-a "serviceAuthenticationMethod=${STR[LDAP_SRV_AUTHMETHOD_PAM]}")
4830 [[ -n ${STR[LDAP_SRV_AUTHMETHOD_KEY]} ]] && \
4831 ARG+=(-a "serviceAuthenticationMethod=${STR[LDAP_SRV_AUTHMETHOD_KEY]}")
4832 [[ -n ${STR[LDAP_SRV_AUTHMETHOD_CMD]} ]] && \
4833 ARG+=(-a "serviceAuthenticationMethod=${STR[LDAP_SRV_AUTHMETHOD_CMD]}")
4834
4835 # Add SSDs
4836 typeset X
4837 for X in "${SSD[@]}" ; do
4838 ARG+=( -a "serviceSearchDescriptor=${X}" )
4839 done
4840
4841 # Execute "ldapclient genprofile" to create profile
4842 nextFile add $0
4843 if ! ${LDAPCLIENT} "${ARG[@]}" >${TMP[FILE]} 2>${TMP[DIR]}/gen_profile.err
4844 then
4845 Log.fatal 'ldapclient genprofile failed'
4846 return 68
4847 fi
4848
4849 # Add the generated profile
4850 if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
4851 >&${TMPF[FD]} 2>&1
4852 then
4853 log.fatal 'Attempt to add profile failed!'
4854 return 69
4855 fi
4856
4857 showProgress 'Client profile generated and pushed to the DS.'
4858 return 0
4859 }
4860
4861 Man.addFunc checkTaskCompletion '' '[+NAME?checkTaskCompletion - Wait and check completion of a DS task.]
4862 [+DESCRIPTION?Checks the state of the DS task with the given \adn\a periodically until it got stopped due to an error or has been finished successfully, or the timeout has been hit. Timeout is an integer and specifies the number of seconds to max. wait for completion. If not given or invalid 60 will be used instead.]
4863 [+RETURN VALUES]{
4864 [+0?on success.]
4865 [+1?task failed.]
4866 [+2?timeout has been hit, task not yet finished or has an unknown state.]
4867 }
4868 [+See Also?\bldapsearch\b(1)]
4869 \n\n\adn\a [\atimeout\a]
4870 '
4871 function checkTaskCompletion {
4872 typeset DN="$1" STATUS='nstaskstatus=' TASKID X
4873 integer TIMEOUT=${2:-${INT[TASK_TIMEOUT]}} RESULT=2 SEEN
4874 (( TIMEOUT < 10 )) && TIMEOUT=60
4875 (( TMPF[IS_OPENDJ] )) && STATUS='ds-task-state='
4876 TASKID=${DN%%,*}
4877 # Wait for task to finish, display current status.
4878 while (( TIMEOUT > 0 )) ; do
4879 SEEN=0 X=''
4880 ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
4881 -b "${DN}" -s base 'objectclass=*' ${STATUS%=} 2>/dev/null | \
4882 while read LINE ; do
4883 [[ ${LINE%%,*} == ${TASKID} ]] && SEEN=1 && continue
4884 [[ -z ${X} && ${LINE:0:${#STATUS}} == ${STATUS} ]] && \
4885 X=${LINE:${#STATUS}}
4886 done
4887 (( ! SEEN )) && break # an error occured
4888 print -n '.'
4889 [[ ${X} =~ Finished || ${X} == 'COMPLETED_SUCCESSFULLY' ]] && \
4890 RESULT=0 && break
4891 [[ ${X:0:12} == 'Index failed' || ${X:016} == 'STOPPED_BY_ERROR' ]] && \
4892 RESULT=1 && break
4893 sleep 1
4894 (( TIMEOUT-=1 ))
4895 done
4896 # DSEE removes non-recurring tasks automagically, OpenDJ not
4897 (( RESULT < 2 && TMPF[IS_OPENDJ] )) && \
4898 ${LDAPDELETE} ${CON_ARGS} "${AUTH_ARGS[@]}" "${DN}" >&${TMPF[FD]} 2>&1
4899 return ${RESULT}
4900 }
4901
4902 Man.addFunc rebuildIndex '' '[+NAME?rebuildIndex - Rebuild a single index.]
4903 [+DESCRIPTION?Instruct the DS to rebuild the index with the name \aname\a. If the \aname\a starts with "vlv." it indicates a Virtual List View, which is supported for OpenDJ, only. Wrt. to OpenDJ and VLVs a return code of \b0\b does not necessaryly mean, that the index is finally in a non-degraded state. It just means, the task has been executed successfully.]
4904 [+RETURN VALUES]{
4905 [+0?on success.]
4906 [+1?if a VLV index was specified, but the current DS is != OpenDJ/OpenDS.]
4907 [+2?if the task failed or did not complete within 60 seconds.]
4908 [+66?if scheduling a rebuild task on the DS failed.]
4909 }
4910 [+SEE ALSO?\bcheckTaskCompletion()\b, \bldapsearch\b(1), \bldapmodify\b(1).]
4911 \n\n\aname\a
4912 '
4913 function rebuildIndex {
4914 typeset IDX=$1
4915 TASKNAME=${IDX}_${ date "+%Y_%m_%d_%H_%M_%S" ; }
4916
4917 if [[ ${IDX:0:4} == 'vlv.' ]] && (( ! TMPF[IS_OPENDJ] )) ; then
4918 Log.warn 'Non-OpenDJ/OpenDS servers do not support VLV rebuildTasks'
4919 return 1
4920 fi
4921
4922 nextFile add "${0}-task-${TASKNAME}"
4923 if (( TMPF[IS_OPENDJ] )); then
4924 # NOTE: rebuildTask requires ldif-import LDAP privilege.
4925 # It's a little bit inefficient: one could schedule a single task at
4926 # the end of the function and use 'rebuildall' or a space separated
4927 # list of all attributes in ds-task-rebuild-index to do it at once.
4928 DN='ds-task-id='"${TASKNAME}"',cn=Scheduled Tasks,cn=Tasks'
4929 print '
4930 # rebuild-index --index '"${IDX}"' --baseDN '"${STR[LDAP_BASEDN]}"' \
4931 # '"${CON_ARGS} ${AUTH_ARGS[@]}"' -X
4932
4933 dn: '"${DN}"'
4934 ds-task-id: '"${TASKNAME}"'
4935 objectClass: top
4936 objectClass: ds-task
4937 objectClass: ds-task-rebuild
4938 ds-task-class-name: org.opends.server.tasks.RebuildTask
4939 ds-task-rebuild-base-dn: '"${STR[LDAP_SUFFIX]}"'
4940 ds-task-rebuild-index: '"${IDX}"'
4941 #ds-task-rebuild-tmp-directory:
4942 ' > ${TMP[FILE]}
4943 else
4944 DN='cn='"${TASKNAME}"',cn=index,cn=tasks,cn=config'
4945 print '
4946 dn: '"${DN}"'
4947 cn: '"${TASKNAME}"'
4948 objectclass: top
4949 objectclass: extensibleObject
4950 nsInstance: '"${STR[DS_DB]}"'
4951 nsIndexAttribute: '"${IDX}"'
4952 ' > ${TMP[FILE]}
4953 fi
4954
4955 if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
4956 >&${TMPF[FD]} 2>&1
4957 then
4958 Log.fatal "Adding task for '${IDX}' failed"
4959 return 66
4960 fi
4961
4962 checkTaskCompletion "${DN}" && print "" || { Log.warn 'FAILED'; return 2; }
4963 return 0
4964 }
4965
4966 Man.addFunc add_indexes '' '[+NAME?add_indexes - Add indexes.]
4967 [+DESCRIPTION?Add indexes of the given \atypes\a (e.g. "pres eq") for the given \aattributes\a (e.g. "uidNumber gidnumber") and schedule corresponding tasks to actually create the indexes unless they already exist. Both arguments are handle as a whitespace separated list.]
4968 [+RETURN VALUES]{
4969 [+-1?syntax error (insufficient parameters).]
4970 [+0?on success.]
4971 [+>= 66?fatal error.]
4972 }
4973 [+SEE ALSO?\bldapsearch\b(1), \bldapmodify\b(1).]
4974 \n\n\atypes\a \aattributes\a
4975 '
4976 function add_indexes {
4977 if [[ -z ${STR[DS_DB]} ]]; then
4978 get_backend || return 66
4979 fi
4980 [[ -z $1 || -z $2 ]] && Log.warn "${.sh.fun}(): syntax error" && return -1
4981
4982 typeset -l TYPES=${1//,/ } # we allow comma separated lists as well
4983 typeset IDX=${2//,/ }
4984
4985 Log.verbose "Processing '${TYPES// /,}' indexes ..."
4986
4987 typeset DN="cn=index,cn=${STR[DS_DB]},cn=ldbm database,cn=plugins,cn=config"
4988 typeset LTYPE="nsIndexType: ${TYPES// /$'\n'nsIndexType: }"
4989 typeset ATTR='cn' OC='extensibleObject' DST TASKNAME LINE X
4990 integer SEEN
4991 if (( TMPF[IS_OPENDJ] )); then
4992 OC='ds-cfg-branch'
4993 DN="cn=Index,ds-cfg-backend-id=${STR[DS_DB]},cn=Backends,cn=config"
4994 ATTR='ds-cfg-attribute'
4995 LTYPE=''
4996 for X in ${TYPES}; do
4997 [[ $X == 'eq' ]] && LTYPE+='ds-cfg-index-type: equality\n'
4998 [[ $X == 'pres' ]] && LTYPE+='ds-cfg-index-type: presence\n'
4999 [[ $X == 'sub' ]] && LTYPE+='ds-cfg-index-type: substring\n'
5000 done
5001 fi
5002
5003 # check, whether Index container exists - if not, create it
5004 if ! ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b "${DN}" \
5005 -s base 'objectclass=*' > /dev/null 2>&1
5006 then
5007 nextFile add $0
5008 X=${DN%%,*}
5009 print '
5010 dn: '"${DN}"'
5011 objectClass: top
5012 objectClass: '"${OC}"'
5013 cn: '"${X#*=}"'
5014 ' >${TMP[FILE]}
5015 if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
5016 >&${TMPF[FD]} 2>&1
5017 then
5018 Log.fatal 'Failed to add backend Index base'
5019 return 66
5020 fi
5021 fi
5022
5023 for DST in ${IDX} ; do
5024 # Check if entry exists first. If so, skip to next
5025 if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" \
5026 -b "${ATTR}=${DST},${DN}" -s base 'objectclass=*' > /dev/null 2>&1
5027 then
5028 showProgress "'${DST}' index exists."
5029 continue
5030 fi
5031
5032 nextFile add "${0}-${DST}"
5033 if (( TMPF[IS_OPENDJ] )); then
5034 X=${LTYPE//'\n'/ }
5035 X=${X//: /:}
5036 print '
5037 # dsconfig create-local-db-index '"${CON_ARGS} ${AUTH_ARGS[@]}"' -X \
5038 # '"${X//ds-cfg-/--set }"' \
5039 # --backend-name '"${STR[DS_DB]}"' --index-name '"${DST}"'
5040
5041 dn: ds-cfg-attribute='"${DST},${DN}"'
5042 ds-cfg-attribute: '"${DST}"'
5043 objectClass: top
5044 objectClass: ds-cfg-local-db-index
5045 '"${LTYPE}"'
5046 ' > ${TMP[FILE]}
5047 else
5048 print '
5049 dn: cn='"${DST},${DN}"'
5050 objectClass: top
5051 objectClass: nsIndex
5052 cn: '"${DST}"'
5053 nsSystemIndex: false
5054 '"${LTYPE}"'
5055 ' > ${TMP[FILE]}
5056 fi
5057 if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
5058 >&${TMPF[FD]} 2>&1
5059 then
5060 Log.fatal "Adding '${DST}' backend index failed"
5061 return 67
5062 fi
5063 showProgress "'${DST}' backend index added."
5064 rebuildIndex ${DST}
5065 done
5066 return 0
5067 }
5068
5069 Man.addFunc add_eq_indexes '' '[+NAME?add_eq_indexes - Add indexes of type pres and eq.]
5070 [+DESCRIPTION?Add eq,pres indexes and schedule corresponding tasks to actually create the indexes unless they already exist.]
5071 [+RETURN VALUES]{
5072 [+0?on success.]
5073 [+>= 66?fatal error.]
5074 }
5075 [+SEE ALSO?\badd_indexes()\b.]
5076 '
5077 function add_eq_indexes {
5078 add_indexes "pres eq" \
5079 "uidNumber ipNetworkNumber gidnumber oncrpcnumber automountKey"
5080 }
5081
5082 Man.addFunc add_sub_indexes '' '[+NAME?add_sub_indexes - Add indexes of type pres, eq and sub.]
5083 [+DESCRIPTION?Add eq,pres,sub indexes and schedule corresponding tasks to actually create the indexes unless they already exist.]
5084 [+RETURN VALUES]{
5085 [+0?on success.]
5086 [+>= 66?fatal error.]
5087 }
5088 [+SEE ALSO?\badd_indexes()\b.]
5089 '
5090 function add_sub_indexes {
5091 add_indexes "pres eq sub" \
5092 "ipHostNumber membernisnetgroup nisnetgrouptriple"
5093 }
5094
5095 Man.addFunc add_vlv_indexes_OpenDJ '' '[+NAME?add_vlv_indexes_OpenDJ - Add VLV indexes to OpenDS/OpenDJ.]
5096 [+DESCRIPTION?OpenDS/OpenDJ specialized part of \badd_vlv_indexes()\b (pulled out for easier maintenance).]
5097 [+SEE ALSO?\badd_vlv_indexes()\b, https://blogs.oracle.com/kanthi/entry/ldap_paged_results_more]
5098 [+NOTES?\bpagedResultsControl\b and \bVLV\b is per default allowed for authenticated users, only. To check, try something like this:]{
5099 [+?ldapsearch -r -j /tmp/pw -D "cn=Directory Manager" -h ldaphost \]
5100 [+? -b "cn=Access Control Handler,cn=config" "objectclass=*" | \]
5101 [+? egrep "1.2.840.113556.1.4.319|2.16.840.1.113730.3.4.9"]
5102 }
5103 \n\n\avname\a \afile\a
5104 '
5105 function add_vlv_indexes_OpenDJ {
5106 typeset -n INDEX_TABLE=$1
5107 typeset OUT="$2" ENTRY IDX_NAME CN SCOPE='single-level' BASE FILTER
5108
5109 [[ ${STR[LDAP_SEARCH_SCOPE]} == sub ]] && SCOPE='subordinate-subtree'
5110 BACKEND="cn=VLV Index,ds-cfg-backend-id=${STR[DS_DB]},cn=Backends,cn=config"
5111
5112 # check, whether VLV Index container exists - if not, create it
5113 if ! ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -b "${BACKEND}" \
5114 -s base 'objectclass=*' > /dev/null 2>&1
5115 then
5116 nextFile add $0
5117 print '
5118 dn: '"${BACKEND}"'
5119 objectClass: top
5120 objectClass: ds-cfg-branch
5121 cn: VLV Index
5122 ' >${TMP[FILE]}
5123 if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
5124 >&${TMPF[FD]} 2>&1
5125 then
5126 Log.fatal 'Adding VLV Index base'
5127 return 66
5128 fi
5129 fi
5130
5131 integer COUNT=0
5132 # create index entries
5133 for ENTRY in "${INDEX_TABLE[@]}" ; do
5134 typeset -a F=( ${ENTRY} ) # split columns
5135
5136 IDX_NAME="${STR[LDAP_DOMAIN]}.get${F[0]}"
5137 BASE="ou=${F[2]},${STR[LDAP_BASEDN]}"
5138 [[ ${F[2]} =~ = ]] && BASE="${BASE:3}" # cut out ou=
5139 FILTER="objectClass=${F[3]}"
5140 [[ ${F[3]:0:1} == '&' ]] && FILTER="&(objectClass=${F[3]:2}"
5141
5142 if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -s base \
5143 -b "ds-cfg-name=${IDX_NAME},${BACKEND}" 'objectclass=*' \
5144 > /dev/null 2>&1
5145 then
5146 showProgress "'${IDX_NAME}' VLV index exists."
5147 continue
5148 fi
5149
5150 nextFile add "${0}-${IDX_NAME}"
5151 print '
5152 # dsconfig create-local-db-vlv-index '"${CON_ARGS} ${AUTH_ARGS[@]}"' -X \
5153 # --backend-name "'"${STR[DS_DB]}"'" \
5154 # --set "base-dn:'"${BASE}"'" \
5155 # --index-name '"${IDX_NAME}"' --set "sort-order:cn uid" \
5156 # --set "scope:'"${SCOPE}"'" --set "filter:'"${FILTER}"'"
5157
5158 dn: ds-cfg-name='"${IDX_NAME},${BACKEND}"'
5159 objectClass: top
5160 objectClass: ds-cfg-local-db-vlv-index
5161 ds-cfg-name: '"${IDX_NAME}"'
5162 ds-cfg-base-dn: '"${BASE}"'
5163 ds-cfg-scope: '"${SCOPE}"'
5164 ds-cfg-filter: '"${FILTER}"'
5165 ds-cfg-sort-order: cn uid
5166 aci: (targetattr = "*")
5167 (
5168 version 3.0; acl "Config";
5169 allow (read,search,compare) userdn="ldap:///anyone";
5170 )
5171 ' > ${TMP[FILE]}
5172
5173 if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
5174 >&${TMPF[FD]} 2>&1
5175 then
5176 Log.fatal "Adding '${IDX_NAME}' VLV index failed"
5177 return 67
5178 fi
5179 showProgress "'${IDX_NAME}' VLV index added."
5180
5181 if rebuildIndex "vlv.${IDX_NAME}" ; then
5182 (( COUNT++ ))
5183 else
5184 print "rebuild-index -b '${STR[LDAP_SUFFIX]}' " \
5185 "--index 'vlv.${IDX_NAME}'" >>${OUT}
5186 fi
5187 done
5188 if (( COUNT )); then
5189 # Bug or feature: Even if scheduled as task, VLV idx rebuild leaves
5190 # the index in degraded state. So:
5191 showProgress 'Rebuilding degraded indexes.'
5192 if ! rebuildIndex rebuilddegraded ; then
5193 print "svcadm disable opendj@VERS@\n" \
5194 "rebuild-index -b '${STR[LDAP_SUFFIX]}' --rebuildDegraded\n" \
5195 "svcadm enable opendj@VERS@"
5196 >>${OUT}
5197 fi
5198 fi
5199 }
5200
5201 Man.addFunc add_vlv_indexes_DSEE '' '[+NAME?add_vlv_indexes_DSEE - Add VLV indexes to DSEE.]
5202 [+DESCRIPTION?DSEE specialized part of \badd_vlv_indexes()\b (pulled out for easier maintenance).]
5203 [+SEE ALSO?\b\badd_vlv_indexes()\b.]
5204 \n\n\avname\a \afile\a
5205 '
5206 function add_vlv_indexes_DSEE {
5207 typeset -n INDEX_TABLE=$1
5208 typeset OUT="$2" ENTRY IDX_NAME CN SCOPE=1 BASE FILTER
5209
5210 typeset INFO=( ${TMP[DS_INFO]} )
5211 integer MAJOR=${INFO[${#INFO[@]}-2]}
5212 typeset INSTANCE="@serverInstance@" LINE
5213 ${LDAPSEARCH} -v ${CON_ARGS} "${AUTH_ARGS[@]}" -b 'cn=config' \
5214 -s base 'objectclass=*' nsslapd-instancedir 2>/dev/null | \
5215 while read LINE ; do
5216 [[ ${LINE:0:20} == 'nsslapd-instancedir=' ]] && LINE=${LINE:20} && break
5217 done
5218 if (( MAJOR < 6 )); then
5219 # DSEE 5.x only.
5220 [[ ${LINE} =~ slapd- ]] && LINE=${LINE#*/} && INSTANCE=${LINE#*-}
5221 else
5222 # 6+ - the instance path
5223 INSTANCE="${LINE}"
5224 fi
5225 [[ ${STR[LDAP_SEARCH_SCOPE]} == sub ]] && SCOPE=2
5226 BACKEND="cn=${STR[DS_DB]},cn=ldbm database,cn=plugins,cn=config"
5227
5228 # create index entries
5229 for ENTRY in "${INDEX_TABLE[@]}" ; do
5230 typeset -a F=( ${ENTRY} ) # split columns
5231
5232 IDX_NAME="${STR[LDAP_DOMAIN]}.get${F[0]}"
5233 CN="${STR[LDAP_DOMAIN]}_${F[1]}_vlv_index"
5234 BASE="ou=${F[2]},${STR[LDAP_BASEDN]}"
5235 [[ ${F[2]} =~ = ]] && BASE="${BASE:3}" # cut out ou=
5236 FILTER="objectClass=${F[3]}"
5237 [[ ${F[3]:0:1} == '&' ]] && FILTER="&(objectClass=${F[3]:2}"
5238
5239 if ${LDAPSEARCH} ${CON_ARGS} "${AUTH_ARGS[@]}" -s base \
5240 -b "cn=${IDX_NAME},cn=${CN},${BACKEND}" 'objectclass=*' \
5241 > /dev/null 2>&1
5242 then
5243 showProgress "'${IDX_NAME}' VLV index exists."
5244 continue
5245 fi
5246
5247 nextFile add "${0}-${IDX_NAME}"
5248 print '
5249 dn: '"cn=${CN},${BACKEND}"'
5250 objectClass: top
5251 objectClass: vlvSearch
5252 cn: '"${CN}"'
5253 vlvbase: '"${BASE}"'
5254 vlvscope: '${SCOPE}'
5255 vlvfilter: ('"${FILTER}"')
5256 aci: (target = "ldap:///'"cn=${CN},${BACKEND}"'") (targetattr = "*")
5257 (
5258 version 3.0; acl "Config";
5259 allow (read,search,compare) userdn="ldap:///anyone";
5260 )
5261
5262 dn: cn='"${IDX_NAME},cn=${CN},${BACKEND}"'
5263 cn: '"${IDX_NAME}"'
5264 vlvSort: cn uid
5265 objectclass: top
5266 objectclass: vlvIndex
5267 ' > ${TMP[FILE]}
5268
5269 if ! ${LDAPMODIFY} -a ${CON_ARGS} "${AUTH_ARGS[@]}" -f ${TMP[FILE]} \
5270 >&${TMPF[FD]} 2>&1
5271 then
5272 Log.fatal "Adding '${IDX_NAME}' VLV index failed"
5273 return 66
5274 fi
5275 showProgress "'${IDX_NAME}' VLV index added."
5276
5277 if (( MAJOR < 6 )); then
5278 # DSEE 5.x
5279 print "directoryserver -s '${INSTANCE}' vlvindex" \
5280 "-n '${STR[DS_DB]}' -T '${IDX_NAME}'" >> ${OUT}
5281 else
5282 # assume DSEE 6+
5283 print "dsadm reindex -l -t '${IDX_NAME}'" \
5284 "'${INSTANCE}' '${STR[LDAP_SUFFIX]}'" >> ${OUT}
5285 fi
5286 done
5287 }
5288
5289 Man.addFunc add_vlv_indexes '' '[+NAME?add_vlv_indexes - Add VLV indexes.]
5290 [+DESCRIPTION?Create VLV indexes entries on the \bSTR[DS_DB]]\b for \bSTR[LDAP_DOMAIN]]\b with \bSTR[LDAP_SEARCH_SCOPE]]\b and create the script \bTMP[DIR]]/do_vlv_index\b to be started on the DS to actually re-index the DB.]
5291 [+RETURN VALUES]{
5292 [+0?on success.]
5293 [+>= 66?fatal error.]
5294 }
5295 [+SEE ALSO?\bldapsearch\b(1), \bldapmodify\b(1).]
5296 '
5297 function add_vlv_indexes {
5298 Log.verbose 'Processing VLV indexes ...'
5299
5300 # F[0] F[1] F[2] F[3]
5301 # ${LDAP_DOMAIN}.get ${LDAP_DOMAIN}_%s_vlv_index ou=%s objectClass=$1||&(%s)
5302 typeset -a INDEXES=(
5303 'grent group group posixGroup'
5304 'hostent hosts hosts ipHost'
5305 'netent networks networks ipNetwork'
5306 'pwent passwd people posixAccount'
5307 'rpcent rpc rpc oncRpc'
5308 'spent shadow people shadowAccount'
5309 # Indexes added during NIS to LDAP transition
5310 'auhoent auho automountMapName=auto_home automount'
5311 'soluent solu people SolarisUserAttr'
5312 'authent auth SolarisAuthAttr SolarisAuthAttr'
5313 'execent exec SolarisProfAttr &(SolarisExecAttr)(SolarisKernelSecurityPolicy=*)'
5314 'profent prof SolarisProfAttr &(SolarisProfAttr)(SolarisAttrLongDesc=*)'
5315 'mailent mail aliases mailGroup'
5316 'bootent _boot ethers &(bootableDevice)(bootParameter=*)'
5317 'ethent ethers ethers &(ieee802Device)(macAddress=*)'
5318 'ngrpent netgroup netgroup nisNetgroup'
5319 'ipnent ipn networks &(ipNetwork)(cn=*)'
5320 'maskent mask networks &(ipNetwork)(ipNetmaskNumber=*)'
5321 'prent pr printers printerService'
5322 'ip4ent ip4 hosts &(ipHost)(ipHostNumber=*.*)'
5323 'ip6ent ip6 hosts &(ipHost)(ipHostNumber=*:*)'
5324 )
5325
5326 # temp file for vlvindex commands
5327 typeset OUT=${TMP[DIR]}/tmp
5328 rm -f ${OUT} && touch ${OUT}
5329
5330 if (( TMPF[IS_OPENDJ] )); then
5331 add_vlv_indexes_OpenDJ INDEXES ${OUT}
5332 else
5333 add_vlv_indexes_DSEE INDEXES ${OUT}
5334 fi
5335 nextFile sh
5336 mv ${OUT} ${TMP[FILE]}
5337 TMP[VLV_CMDS]=${TMP[FILE]}
5338 }
5339
5340 Man.addFunc display_vlv_cmds '' '[+NAME?display_vlv_cmds - Display VLV index commands to run on server.]
5341 [+DESCRIPTION?Display VLV index commands to run on server and save the file to /var/tmp/doIndexVLV-\bSTR[DS_HOST]].sh\b.]
5342 '
5343 function display_vlv_cmds {
5344 typeset SAV="/var/tmp/doIndexVLV-${STR[DS_HOST]}.sh"
5345
5346 [[ -s ${TMP[VLV_CMDS]} ]] || return
5347 # some problems occured, so the file is not empty
5348 [[ -e ${SAV} ]] && SAV="${SAV%.sh}-$$.sh"
5349 cp -p ${TMP[VLV_CMDS]} "${SAV}"
5350
5351 typeset MSG='NOTE: '"${PROG}"'configured the entries for VLV indexes.'
5352 if (( TMPF[IS_OPENDJ] )); then
5353 MSG+='
5354 To create the actual VLV indexes, you need to stop the DS on the host
5355 '"'${STR[DS_HOST]}'"', e.g. using "svcadm disable -t opendj@VERS@"
5356 or, if manually started, "ds-stop" and than run the commands shown in the file
5357 '"'${SAV}'"'. Than restart the DS e.g. using
5358 "svcadm enable opendj@VERS@" or "ds-start".
5359 '
5360 else
5361 typeset INFO=( ${DS_INFO[@]} )
5362 if (( INFO[1] >= 6 )); then
5363 MSG+='
5364 Use the dsadm command delivered with the DS on the host '"'${STR[DS_HOST]}'"'
5365 to stop the server. Then, using dsadm, follow the dsadm examples shown in the
5366 file '"'${SAV}'"' to create the actual VLV indexes.
5367 '
5368 else
5369 MSG+='
5370 Use the directoryserver(1m) script on the host '"'${STR[DS_HOST]}'"'
5371 to stop the server. Then, using directoryserver, follow the directoryserver
5372 examples shown in the file '"'${SAV}'"' to create the
5373 actual VLV indexes.
5374 '
5375 fi
5376 fi
5377 Log.info "\n\n${MSG}"
5378 }
5379
5380 Man.addFunc doMain '' '[+NAME?doMain - the main entry point.]
5381 [+DESCRIPTION?The entry point, where the real work starts.]
5382 '
5383 function doMain {
5384 # Initialize the variables that need to be set to NULL, or some
5385 # other initial value before the rest of the functions can be called
5386 init || return 1
5387 show_vars
5388
5389 # Print extra line to separate from prompt
5390 print
5391
5392 # Either load the user specified config file or prompt user for config info
5393 if [[ -n ${TMP[IN]} ]]; then
5394 load_config_file "${TMP[IN]}"
5395 validate_info || return 1 # Validate basic info in file
5396 else
5397 display_msg 'backup_server'
5398 get_confirm 'Do you wish to continue with server setup (y/n/h)?' \
5399 'n' 'backup_help' && return 1
5400
5401 # Ask for all required infos
5402 prompt_config_info || return 1
5403 (( INT[LDAP_ENABLE_SHADOW_UPDATE] && INT[EXISTING_PROFILE] )) && \
5404 return 0 # just enabled shadow update in an existing profile
5405 # Allow user to modify results
5406 integer RES
5407 display_summary
5408 RES=$?
5409 # save the work for now, so that even on exit/errors it can be re-used
5410 [[ -n ${TMP[OUT]} ]] && create_config_file "${TMP[OUT]}"
5411 (( RES )) && return 1
5412 fi
5413
5414 if (( INT[NEED_TIME] )); then
5415 modify_timelimit || return 1
5416 fi
5417
5418 if (( INT[NEED_SIZE] )); then
5419 modify_sizelimit || return 1
5420 fi
5421
5422 # Modify the password storage scheme to support CRYPT
5423 if (( INT[NEED_CRYPT] )); then
5424 modify_pwd_crypt || return 1
5425 fi
5426
5427 # schema modifications
5428 modify_cn || return 1
5429 update_schema_attr || return 1
5430 update_schema_obj || return 1
5431
5432 add_suffix || return 1
5433
5434 # Add missing suffix ACIs
5435 add_suffix_aci || return 1
5436
5437 # Add base objects (if needed)
5438 add_base_objects || return 1
5439
5440 # Update the NisDomainObject.
5441 # The Base DN might of just been created, so this MUST happen after
5442 # the base objects have been added!
5443 set_nisdomain || return 1
5444
5445 # Add top level classes (new containers)
5446 add_new_containers || return 1
5447
5448 add_auto_maps || return 1
5449
5450 modify_top_aci || return 1
5451
5452 add_vlv_aci || return 1
5453
5454 if (( INT[NEED_PROXY] )); then
5455 add_proxyagent || return 1
5456 if (( ! INT[LDAP_ENABLE_SHADOW_UPDATE] )); then
5457 allow_proxy_read_pw || return 1
5458 fi
5459 fi
5460
5461 if (( INT[NEED_ADMIN] )); then
5462 add_admin || return 1
5463 allow_admin_read_write_shadow || return 1
5464 deny_non_admin_shadow_access || return 1
5465 fi
5466
5467 if (( INT[GSSAPI_ENABLE] )); then
5468 add_id_mapping_rules
5469 # do not modify ACI if "sasl/GSSAPI" and "self" are not selected
5470 if [[ ${STR[LDAP_CRED_LEVEL]} == 'self' && \
5471 ${STR[LDAP_AUTHMETHOD]} == 'sasl/GSSAPI' ]]
5472 then
5473 modify_userpassword_acl_for_gssapi || return 1
5474 else
5475 Log.warn 'ACL for GSSAPI was not set because of incompatibility' \
5476 'in profile'
5477 fi
5478 fi
5479
5480 if (( INT[NEED_HOSTACL] )); then
5481 allow_host_read_write_shadow || return 66
5482 deny_non_host_shadow_access || return 67
5483 fi
5484
5485
5486 # Generate client profile and add it to the server
5487 add_profile || return 1
5488
5489 # Add Indexes to improve search performance
5490 add_eq_indexes || return 1
5491 add_sub_indexes || return 1
5492 add_vlv_indexes || return 1
5493
5494 # Display setup complete message
5495 Log.printMarker
5496 Log.info 'Setup of DS server' "'${STR[DS_HOST]}'" 'is complete.'
5497 Log.printMarker
5498
5499 # Display VLV index commands to be executed on server (if any)
5500 display_vlv_cmds
5501
5502 # Create final config file if requested
5503 [[ -n ${TMP[OUT]} ]] && create_config_file "${TMP[OUT]}"
5504 return 0
5505 }
5506
5507 Man.addFunc cleanup '' '[+NAME?cleanup - cleanup tempfiles, tty and exit.]
5508 [+DESCRIPTION?Removes \aTMP[DIR]]\a unless \aTMPF[DEBUG]]\a is set and restores the echo for the tty.]
5509 [+ENVIRONMENT VARIABLES]{' "${ Man.varUsage TMP TMPF ; }" '}
5510 '
5511 function cleanup {
5512 (( TMPF[CLEANUP_DONE] )) && return
5513 if (( TMPF[DEBUG] )); then
5514 typeset X=${ ls -1 ${TMP[DIR]} 2>/dev/null ; }
5515 if [[ -z $X || $X == 'rootPWD' ]]; then
5516 rm -rf ${TMP[DIR]}
5517 else
5518 Log.info "Leaving temp dir ${TMP[DIR]} as is. Remove it manually"
5519 fi
5520 elif (( TMPF[KEEP] )); then
5521 typeset X=${ ls -1 ${TMP[DIR]} 2>/dev/null ; }
5522 if [[ -z $X || $X == 'rootPWD' ]]; then
5523 rm -rf ${TMP[DIR]}
5524 else
5525 Log.info "Keeping setup scripts and files in ${TMP[DIR]}"
5526 fi
5527 elif [[ -d ${TMP[DIR]} ]]; then
5528 rm -rf ${TMP[DIR]}
5529 fi
5530 ${STTY:-/usr/bin/stty} echo
5531 trap - EXIT 1 2 3 6 15
5532 # Might be trapped in the scope of a function which will stop executing
5533 # the function itself but not the script. So:
5534 [[ -z $1 ]] && kill $$
5535 TMPF[CLEANUP_DONE]=1
5536 }
5537
5538 # debug helper function. Required to be not a 'function'!
5539 showCommand() {
5540 typeset CMD="${.sh.command}"
5541 [[ -z ${CMD} ]] && return
5542 print -n -u2 '\E[0;30;47m'
5543 print -u2 -r -n "DEBUG: ${.sh.fun} '${CMD}'"
5544 print '\E[0m'
5545 }
5546
5547 Man.addFunc MAIN '' '[+NAME?'"${PROG}"' - setup the infrastructure of a directory server to provide data and security required by the Solaris (or similar OS) LDAP Naming Services.]
5548 [+DESCRIPTION?This script assumes that the Sun/Oracle Directory Server Enterprise Edition (DSEE), or Sun OpenDS or Forgerock OpenDJ is installed and that its setup has been run. This script takes the directory server from that point and sets up the infrastructure for LDAP Naming Services. After running this script, \bldapaddent\b(1M) or some other tools can be used to populate data.]
5549 [h:help?Print this help and exit.]
5550 [F:functions?Print out a list of names of all currently defined script functions and exit (see \btypeset +f\b).]
5551 [H:usage]:[function?Show the usage info for the function with the given name if available and exit. (see also option \b-F\b).]
5552 [T:trace]:[fname_list?A comma or whitespace separated list of function names, which should be traced when running this script. If the list consist of the single word "ALL" or "*" all known functions get traced. "MAIN" is the special word to enable the trace of the main script. Gets activated as soon as this option gets processed, so option order might be important.]
5553 [d:debug?Enable really verbose debug info.]
5554 [C:no-color?Do not use ANSI escape codes to color the output.]
5555 [k:keep?Keep the files used to modify the DS. Files are enumerated and prefixed with the command to use for executing it so that one is able to do the same manually what this script did and thus may help to fine tune the setup of your DS. Actually it is recommended to run this script against a virgin DS and than re-use/adjust everything you need on your production system.]
5556 [I:importpwp?If specified, the storage scheme for Password Policy Import will be changed in the same way as the storage scheme for the Default Password Policy. If not specified, the storage scheme for Password Policy Import stays untouched. This option gets ignored for non-OpenDS/OpenDJ directory servers.]
5557 [i:in]:[file?Get setup info from the given file.]
5558 [o:out]:[file?Generate a server configuration output file.]
5559 [s:djSyntax?If given, the OpenDJ schema defintions will be used to complement the servers schema if needed, no matter which kind of server has been detected.]
5560 [S:eeSyntax?If given, the Sun DSEE schema defintions will be used to complement the servers schema if needed, no matter which kind of server has been detected.
5561 Wrt. Solaris it should not make a difference, whether OpenDJ or DSEE syntax is used. OpenDJ syntax is usually a little bit more precise.]
5562 [t:timeout]:[seconds:=60?When this script creates an index, it also schedules a task to rebuild the index immediately. The \atimeout\a specifies, how long to wait for task completion. If the task gets not finished within the given time, the script treats that as an error and continues its work.]
5563 [v:verbose?Verbose mode - makes the script a little bit more chatty.]
5564 [+NOTES?This script should work for the following DS:]{
5565 [+?Sun DS 5.x]
5566 [+?Sun DSEE 6.x/7.x]
5567 [+?Oracle ODSEE 11g]
5568 [+?Sun OpenDS 2.x]
5569 [+?Forgerock OpenDJ 2.x]
5570 }
5571 '
5572
5573 TMPF[DEBUG]=0 TMPF[KEEP]=0 TMPF[FD]=4
5574
5575 X="${ print ${Man.FUNC[MAIN]} ; }"
5576 while getopts "${X}" option ; do
5577 case "${option}" in
5578 '?'|h) showUsage ${PROG} MAIN ; exit 0 ;;
5579 F) typeset +f ; exit 0 ;;
5580 T) if [[ ${OPTARG} == '*' || ${OPTARG} == 'ALL' ]]; then
5581 typeset -ft ${ typeset +f ; }
5582 elif [[ ${OPTARG} == 'MAIN' ]]; then
5583 set -x
5584 else
5585 typeset -ft ${OPTARG//,/ }
5586 fi
5587 ;;
5588 H) if [[ ${OPTARG%_t} != $OPTARG ]]; then
5589 $OPTARG --man # self-defined types
5590 else
5591 showUsage "$OPTARG" "$OPTARG" # functions
5592 fi
5593 exit 0
5594 ;;
5595 C) Log.COLORED=0 ;;
5596 d) TMPF[DEBUG]=1 ;;
5597 k) TMPF[KEEP]=1 ;;
5598 I) INT[NEED_CRYPT_IMPORT]=1 ;;
5599 i) TMP[IN]="${OPTARG}" ;;
5600 o) TMP[OUT]="${OPTARG}" ;;
5601 S) TMPF[SYNTAX]=2 ; print DSEE ;;
5602 s) TMPF[SYNTAX]=1 ; print DJ ;;
5603 t) is_numeric "${OPTARG}" && INT[TASK_TIMEOUT]=${OPTARG} ;;
5604 v) Log.VERBOSE=1 ; TMPF[FD]=1 ;;
5605 *) Log.fatal '**Internal ERROR: Supported option missing handler'
5606 exit 1
5607 ;;
5608 esac
5609 done
5610 X=$(( OPTIND - 1 ))
5611 shift $X
5612 (( TMPF[DEBUG] )) && Man.listVars
5613
5614 unset LC_ALL LC_LANG
5615 export LC_CTYPE=C # avoid any surprises
5616
5617 # Create TMP[DIR]
5618 TMP[DIR]=${ mktemp -d /tmp/${PROG}.XXXXX ; }
5619 if [[ -z ${TMP[DIR]} ]]; then
5620 Log.fatal 'Unable to create a safe temporary directory'
5621 exit 1
5622 fi
5623 trap cleanup EXIT 1 2 3 6 15 # and register to cleanup on exit/signal
5624 if (( TMPF[DEBUG] )); then
5625 trap 'typeset _CMD_="${.sh.command}"
5626 print -u2 -n "\E[0;30;47m"
5627 print -u2 -n -r "${.sh.fun:-MAIN}(): ${_CMD_}"
5628 print -u2 "\E[0m"
5629 ' TMPF[DEBUG]
5630 fi
5631
5632 # Prevent new files from being read by group or others
5633 umask 077
5634
5635 doMain
5636 X=$?
5637
5638 cleanup NOKILL
5639
5640 exit ${X}
5641
5642 # vim:ts=4 filetype=sh
5643 # :syntax sync fromstart
|