3
# BEGIN COPYRIGHT BLOCK
4
# This Program is free software; you can redistribute it and/or modify it under
5
# the terms of the GNU General Public License as published by the Free Software
6
# Foundation; version 2 of the License.
8
# This Program is distributed in the hope that it will be useful, but WITHOUT
9
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
# You should have received a copy of the GNU General Public License along with
13
# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
14
# Place, Suite 330, Boston, MA 02111-1307 USA.
16
# In addition, as a special exception, Red Hat, Inc. gives You the additional
17
# right to link the code of this Program with code not covered under the GNU
18
# General Public License ("Non-GPL Code") and to distribute linked combinations
19
# including the two, subject to the limitations in this paragraph. Non-GPL Code
20
# permitted under this exception must only link to the code of this Program
21
# through those well defined interfaces identified in the file named EXCEPTION
22
# found in the source code files (the "Approved Interfaces"). The files of
23
# Non-GPL Code may instantiate templates or use macros or inline functions from
24
# the Approved Interfaces without causing the resulting work to be covered by
25
# the GNU General Public License. Only Red Hat, Inc. may make changes or
26
# additions to the list of Approved Interfaces. You must obey the GNU General
27
# Public License in all respects for all of the Program code and other code used
28
# in conjunction with the Program except the Non-GPL Code covered by this
29
# exception. If you modify this file, you may extend this exception to your
30
# version of the file, but you are not obligated to do so. If you do not wish to
31
# provide this exception without modification, you must delete this exception
32
# statement from your version and license this file solely under the GPL without
36
# Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
37
# Copyright (C) 2013 Red Hat, Inc.
38
# All rights reserved.
42
use lib qw(@perlpath@);
45
DSUtil::libpath_add("@nss_libdir@");
46
DSUtil::libpath_add("/usr/lib");
47
$ENV{'PATH'} = "@ldaptool_bindir@:/usr/bin:/usr/lib64/mozldap/";
48
$ENV{'SHLIB_PATH'} = "$ENV{'LD_LIBRARY_PATH'}";
53
###############################
55
###############################
59
print (STDERR "ns-activate.pl [-Z serverID] [-D rootdn] { -w password | -w - | -j filename } \n");
60
print (STDERR " [-p port] [-h host] [-P protocol] -I DN-to-$operation\n\n");
61
print (STDERR "May be used to $operation a user or a domain of users\n\n");
62
print (STDERR "Arguments:\n");
63
print (STDERR " -? - Display usage\n");
64
print (STDERR " -D rootdn - Provide a Directory Manager DN\n");
65
print (STDERR " -w password - Provide a password for the Directory Manager DN\n");
66
print (STDERR " -w - - Prompt for the Directory Manager's password\n");
67
print (STDERR " -Z serverID - Server instance identifier\n");
68
print (STDERR " -j filename - Read the Directory Manager's password from file\n");
69
print (STDERR " -p port - Provide a port\n");
70
print (STDERR " -h host - Provide a host name'\n");
71
print (STDERR " -P protocol - STARTTLS, LDAPS, LDAPI, LDAP (default: uses most secure protocol available)\n");
72
print (STDERR " -I DN-to-$operation - Single entry DN or role DN to $operation\n");
85
# --------------------------
86
# Check if the entry is part of a locked role:
87
# i.e.: for each role member (nsroledn) of nsdisabledrole, check if
88
# * it is the same as the entry
89
# * the entry is member of role (==has nsroledn attributes), compare each of
90
# them with the nsroledn of nsdisabledrole
91
# * if nsroledn of nsdisabledrole are complex, go through each of them
92
# argv[0] is the local file handler
93
# argv[1] is the entry (may be a single entry DN or a role DN)
94
# argv[2] is the base for the search
95
# --------------------------
101
# For recursivity, file handler must be local
102
my $L_filehandle=$_[0];
106
# Remove useless space
107
my @L_intern=split /([,])/,$L_entry;
109
foreach $L_part (@L_intern){
111
$L_part=~ tr/A-Z/a-z/;
112
$L_result="$L_result$L_part";
122
$info{base} = $L_base;
123
$info{filter} = "(|(objectclass=*)(objectclass=ldapsubentry))";
124
$info{scope} = "base";
125
$info{attrs} = "nsroledn";
126
$info{redirect} = ">> /dev/null 2>&1";
127
DSUtil::ldapsrch_ext(%info);
128
$info{redirect} = "";
130
if ( $retCode != 0 ){
135
# Check if the role is a nested role
136
$info{filter} = "(|(objectclass=nsNestedRoleDefinition)(objectclass=ldapsubentry))";
138
@L_Nested=DSUtil::ldapsrch(%info);
139
# L_isNested == 1 means that we are going through a nested role, so for each member of that
140
# nested role, check that the member is below the scope of the nested
141
$L_isNested=@L_Nested;
143
# Not Direct Lock, Go through roles if any
144
$info{attrs} = "nsroledn";
145
$info{filter} = "(|(objectclass=*)(objectclass=ldapsubentry))";
146
$L_search=DSUtil::ldapsrch(%info);
148
debug("\t-->indirectLock: check if $L_entry is part of a locked role from base $L_base\n\n");
150
unless (open ($L_filehandle, "$L_search |")){
151
out("Can't open file $L_filehandle\n");
154
while (<$L_filehandle>) {
156
if (/^nsroledn: (.*)\n/) {
159
# Remove useless space
160
my @L_intern=split /([,])/,$L_currentrole;
162
foreach $L_part (@L_intern){
164
$L_part=~ tr/A-Z/a-z/;
165
$L_result="$L_result$L_part";
167
$L_currentrole=$L_result;
169
debug("\t-- indirectLock loop: current nsroledn $L_currentrole of base $L_base\n");
170
if ( $L_isNested == 1 ){
171
if ( checkScope($L_currentrole, $L_base) == 0 ){
172
# Scope problem probably a bad conf, skip the currentrole
177
if ( $L_currentrole eq $L_entry ){
178
# the entry is a role that is directly locked
179
# i.e, nsroledn of nsdisabledrole contains the entry
180
$throughRole=$L_base;
181
$throughRole=~ tr/A-Z/a-z/;
183
# skipDisabled means that we've just found that the entry (which is a role)
184
# is locked directly (==its DN is part of nsroledn attributes)
185
# we just want to know now, if it is locked through another role
187
if ( $skipDisabled == 1 ){
188
# direct inactivation
190
# just go through that test once
194
debug("\t-- 1 indirectLock: $L_currentrole locked throughRole == $throughRole\n");
198
$L_retCode=memberOf($L_currentrole, $L_entry);
199
if ( $L_retCode == 0 && $single == 1 ){
200
$throughRole=$L_currentrole;
201
$throughRole=~ tr/A-Z/a-z/;
202
if ( $skipManaged == 1 ){
203
if ( $L_currentrole eq $nsManagedDisabledRole){
210
debug("\t-- 2 indirectLock: $L_currentrole locked throughRole == $throughRole\n");
214
# Only for the first iteration
215
# the first iteration is with nsdisabledrole as base, other
217
$L_local=$skipDisabled;
220
# the current nsroledn may be a complex role, just go through
222
$L_retCode=indirectLock($L_filehandle,$L_entry, $L_currentrole);
224
# Because of recursivity, to keep the initial value for the first level
225
$skipDisabled=$L_local;
227
if ( $L_retCode == 0 ){
228
$throughRole=$L_currentrole;
229
$throughRole=~ tr/A-Z/a-z/;
230
debug("\t-- 3 indirectLock: $L_entry locked throughRole == $throughRole\n");
236
close($L_filehandle);
238
debug("\t<--indirectLock: no more nsroledn to process\n");
242
# --------------------------
243
# Check if nsroledn is part of the entry attributes
244
# argv[0] is a role DN (nsroledn attribute)
245
# argv[1] is the entry
246
# --------------------------
249
my $L_nsroledn=$_[0];
250
$L_nsroledn=~ tr/A-Z/a-z/;
255
$info{base} = $L_entry;
256
$info{filter} = "(|(objectclass=*)(objectclass=ldapsubentry))";
257
$info{scope} = "base";
258
$info{attrs} = "nsrole";
259
$L_search = DSUtil::ldapsrch(%info);
261
debug("\t\t-->memberOf: $L_search: check if $L_entry has $L_nsroledn as nsroledn attribute\n");
263
open (LDAP2, "$L_search |");
266
if (/^nsrole: (.*)\n/) {
268
$L_currentrole=~ tr/A-Z/a-z/;
269
if ( $L_currentrole eq $L_nsroledn ){
270
# the parm is part of the $L_entry nsroledn
271
debug("\t\t<--memberOf: $L_entry locked through $L_nsroledn\n");
278
# the parm is not part of the $L_entry nsroledn
279
debug("\t\t<--memberOf: $L_entry not locked through $L_nsroledn\n");
284
# --------------------------
285
# Remove the rdn of a DN
287
# --------------------------
292
@L_entryToTest=split /([,])/,$L_entry;
293
debug("removeRdn: entry to split: $L_entry**@L_entryToTest\n");
297
foreach $part (@L_entryToTest){
300
if ( $removeRDN <= 2 ){
301
$removeRDN=$removeRDN+1;
303
$newDN="$newDN$part";
307
debug("removeRdn: new DN **$newDN**\n");
310
# --------------------------
311
# Check if L_current is below the scope of
314
# argv[1] is the nested role
315
# --------------------------
321
debug("checkScope: check if $L_current is below $L_nestedRole\n");
323
removeRdn($L_nestedRole);
324
$L_nestedRoleSuffix=$newDN;
325
debug("checkScope: nested role based: $L_nestedRoleSuffix\n");
328
while ( ($cont == 1) && ($L_current ne "") ){
329
removeRdn($L_current);
331
debug("checkScope: current DN to check: $currentDn\n");
333
if ( $currentDn eq $L_nestedRoleSuffix ){
334
debug("checkScope: DN match!!!\n");
337
$L_current=$currentDn;
342
debug("checkScope: $_[0] and $_[1] are not compatible\n");
345
debug("checkScope: $_[0] and $_[1] are compatible\n");
351
###############################
353
###############################
357
# Determine which command we are running
358
if ( $0 =~ /ns-inactivate(.pl)?$/ ){
359
$cmd="ns-inactivate.pl";
360
$operation="inactivate";
361
$state="inactivated";
364
} elsif ( $0 =~ /ns-activate(.pl)?$/ ){
365
$cmd="ns-activate.pl";
366
$operation="activate";
370
} elsif ( $0 =~ /ns-accountstatus(.pl)?$/ ){
371
$cmd="ns-accountstatus.pl";
372
$operation="get status of";
374
# no need for $modrole as no operation is performed
378
out("$0: unknown command\n");
382
debug("Running ** $cmd ** $operation\n");
384
# Process the command line arguments
390
} elsif($arg eq "-D"){
391
$rootdn = shift @ARGV;
392
} elsif($arg eq "-w"){
393
$rootpw = shift @ARGV;
394
} elsif($arg eq "-j"){
395
$pwfile = shift @ARGV;
396
} elsif($arg eq "-p"){
398
} elsif($arg eq "-h"){
400
} elsif($arg eq "-I"){
401
$entry = shift @ARGV;
402
} elsif($arg eq "-Z"){
403
$servid = shift @ARGV;
404
} elsif ($arg eq "-P") {
405
$protocol = shift @ARGV;
407
print "$arg: Unknown command line argument.\n";
414
# Gather all our config settings
416
($servid, $confdir) = DSUtil::get_server_id($servid, "@initconfigdir@");
417
%info = DSUtil::get_info($confdir, $host, $port, $rootdn);
418
$info{rootdnpw} = DSUtil::get_password_from_file($rootpw, $pwfile);
419
$info{protocol} = $protocol;
427
# Check the actual existence of the entry to inactivate/activate
428
# and at the same time, validate the various parm: port, host, rootdn, rootpw
430
$info{base} = $entry;
431
$info{filter} = "(objectclass=*)";
432
$info{scope} = "base";
434
@exist=DSUtil::ldapsrch_ext(%info);
436
if ( $retCode1 != 0 ){
441
$info{filter} = "(&(objectclass=LDAPsubentry)(objectclass=nsRoleDefinition))";
442
@isRole = DSUtil::ldapsrch_ext(%info);
445
if ( $retCode2 != 0 ){
450
if ( $nbLineRole > 0 ){
451
debug("Groups of users\n");
454
debug("Single user\n");
459
# First of all, check the existence of the nsaccountlock attribute in the entry
463
$info{filter} = "(objectclass=*)";
464
$info{attrs} = "nsaccountlock";
465
$searchAccountLock= DSUtil::ldapsrch(%info);
466
open (LDAP1, "$searchAccountLock |");
469
if (/^nsaccountlock: (.*)\n/) {
470
$L_currentvalue = $1;
471
$L_currentvalue=~ tr/A-Z/a-z/;
472
if ( $L_currentvalue eq "true"){
474
} elsif ( $L_currentvalue eq "false" ){
481
debug("Is the entry already locked? ==> $isLocked\n");
484
# Get the suffix name of that entry
487
# Remove the space at the beginning (just in case...)
488
# -I "uid=jvedder , ou=People , o=sun.com"
489
@suffix=split /([,])/,$entry;
491
foreach $part (@suffix){
494
$result="$result$part";
498
debug("Entry to $operation: #@suffix#\n");
499
debug("Entry to $operation: #@suffixN#\n");
504
# Look if suffix is the suffix of the entry
505
# ldapsearch -s one -b "cn=mapping tree,cn=config" "cn=\"uid=jvedder,ou=People,o=sun.com\""
507
debug("\tSuffix from the entry: #@suffixN#\n");
508
$info{base} = "cn=mapping tree, cn=config";
509
$info{filter} = "cn=\"@suffixN\"";
510
$info{scope} = "one";
512
@mapping = DSUtil::ldapsrch_ext(%info);
514
if ( $retCode != 0 ){
519
# If we get a result, remove the dn:
520
# dn: cn="o=sun.com",cn=mapping tree,cn=config
525
foreach $res (@mapping){
526
# Break the string cn: "o=sun.com" into pieces
527
@cn= split(/ /,$res);
529
# And remove the cn: part
532
# Now compare the suffix we extract from the mapping tree
533
# with the suffix derived from the entry
534
debug("\tSuffix from mapping tree: #@cn#\n");
535
if ( @cn eq @suffixN ) {
536
debug("Found matching suffix\n");
542
# Remove the current rdn to try another suffix
546
foreach $part (@suffix){
549
$result="$result$part";
553
debug("\t\tNothing found => go up one level in rdn #@suffix#\n");
556
debug("Can not find suffix. Problem\n");
562
out("Can not find suffix for entry $entry\n");
566
if ( $operation eq "inactivate" ){
568
# Now that we have the suffix and we know if we deal with a single entry or
569
# a role, just try to create the COS and roles associated.
571
$role1="dn: cn=nsManagedDisabledRole,@suffixN\n" .
572
"objectclass: LDAPsubentry\n" .
573
"objectclass: nsRoleDefinition\n" .
574
"objectclass: nsSimpleRoleDefinition\n" .
575
"objectclass: nsManagedRoleDefinition\n" .
576
"cn: nsManagedDisabledRole\n\n";
577
$role2="dn: cn=nsDisabledRole,@suffixN\n" .
578
"objectclass: top\n" .
579
"objectclass: LDAPsubentry\n" .
580
"objectclass: nsRoleDefinition\n" .
581
"objectclass: nsComplexRoleDefinition\n" .
582
"objectclass: nsNestedRoleDefinition\n" .
583
"nsRoleDN: cn=nsManagedDisabledRole,@suffixN\n" .
584
"cn: nsDisabledRole\n\n";
585
$cos1="dn: cn=nsAccountInactivationTmp,@suffixN\n" .
586
"objectclass: top\n" .
587
"objectclass: nsContainer\n\n";
588
$cos2="dn: cn=\"cn=nsDisabledRole,@suffixN\",cn=nsAccountInactivationTmp,@suffixN\n" .
589
"objectclass: top\n" .
590
"objectclass: extensibleObject\n" .
591
"objectclass: costemplate\n" .
592
"objectclass: ldapsubentry\n" .
594
"nsAccountLock: true\n\n";
595
$cos3="dn: cn=nsAccountInactivation_cos,@suffixN\n" .
596
"objectclass: top\n" .
597
"objectclass: LDAPsubentry\n" .
598
"objectclass: cosSuperDefinition\n" .
599
"objectclass: cosClassicDefinition\n" .
600
"cosTemplateDn: cn=nsAccountInactivationTmp,@suffixN\n" .
601
"cosSpecifier: nsRole\n" .
602
"cosAttribute: nsAccountLock operational\n\n";
603
$all=$role1 . $role2 . $cos1 . $cos2 . $cos3;
605
$info{args} = "-c -a";
606
DSUtil::ldapmod($all[$i], %info);
609
if ( $retCode == 68 ){
610
debug("Entry already exists, ignore error\n");
612
# Probably a more serious problem.
613
# Exit with LDAP error
617
debug("Role/cos entries created\n");
625
$nsDisabledRole="cn=nsDisabledRole,@suffixN";
626
$nsDisabledRole=~ tr/A-Z/a-z/;
628
$nsManagedDisabledRole="cn=nsManagedDisabledRole,@suffixN";
629
$nsManagedDisabledRole=~ tr/A-Z/a-z/;
631
if ( $operation eq "inactivate" ){
632
# Go through all the roles part of nsdisabledrole to check if the entry
633
# is a member of one of those roles
634
$ret=indirectLock("LDAP00", $entry, $nsDisabledRole);
636
if ( $throughRole ne $nsDisabledRole && $throughRole ne $nsManagedDisabledRole ){
638
out("$entry already $state through $throughRole.\n");
641
out("$entry already $state.\n");
644
} elsif ( $isLocked == 1 ){
645
# the entry is not locked through a role, may be nsaccountlock is "hardcoded" ?
646
out("$entry already $state (probably directly).\n");
649
} elsif ( $operation eq "activate" || $operation eq "get status of" ){
650
$skipManaged=$single;
653
$ret=indirectLock("LDAP00",$entry, $nsDisabledRole);
657
if ( $throughRole ne $nsDisabledRole && $throughRole ne $nsManagedDisabledRole ){
658
if ( $operation eq "activate" ){
659
out("$entry inactivated through $throughRole. Can not activate it individually.\n");
662
out("$entry inactivated through $throughRole.\n");
666
debug("$entry locked individually\n");
668
if ( $operation ne "activate" ){
669
out("$entry inactivated.\n");
672
} elsif ( $directLocked == 0 ){
673
if ( $operation eq "activate" && $isLocked != 1 ){
674
out("$entry $already $state.\n");
676
} elsif ( $isLocked != 1 ) {
677
out("$entry $already $state.\n");
680
# not locked using our schema, but nsaccountlock is probably present
681
out("$entry inactivated (probably directly).\n");
684
} elsif ( $operation ne "activate" ){
685
out("$entry inactivated.\n");
688
# else Locked directly, juste unlock it!
689
debug("$entry locked individually\n");
693
# Inactivate/activate the entry
696
$record = "dn: $entry\n" . "changetype: modify\n" . "$modrole: nsRoleDN\n" . "nsRoleDN: cn=nsManagedDisabledRole,@suffixN\n";
698
$record = "dn: cn=nsDisabledRole,@suffixN\n" . "changetype: modify\n" . "$modrole: nsRoleDN\n" . "nsRoleDN: $entry\n";
702
DSUtil::ldapmod($record, %info);
704
debug("$modrole, $entry\n");
709
out("$entry $state.\n");