summaryrefslogtreecommitdiff
blob: 7cafc449d82478653949e02495e491d2adc7d716 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/perl

# A Perl wrapper for setquota utility which updates LDAP accordingly.

# /etc/fstab: usrquota,grpquota
# mount -o remount /f/s
# touch /f/s/aquota.{user,group}
# chmod 600 /f/s/aquota.{user,group}
# quotacheck -cguvamf

use strict;
use warnings;
use Net::LDAP;
use Net::LDAP::Entry;
use Getopt::Long;
Getopt::Long::Configure ("bundling");

my $help = $#ARGV >= 0 ? 0 : 1;
my $ldaphost = 'localhost';
my $passwordfile = '';
my $password = '';
my $binddn = $ENV{BINDDN};
my $basedn = $ENV{BASEDN};
my $oc = 'systemQuotas';
my $attr = 'quota';
my %Q = ();
my $F = 'cn=*';
GetOptions(
        'help|?' => \$help,
        'oc|o=s' => \$oc,
        'attr|a=s' => \$attr,
        'quota|Q=s' => \%Q,
        'filter|F=s' => \$F,
        'ldaphost|h=s' => \$ldaphost,
        'basedn|b=s' => \$basedn,
        'binddn|D=s' => \$binddn,
        'password|w=s' => \$password,
        'passwordfile|W=s' => \$passwordfile,
);
die "Usage: $0 -b basedn [-o objectClass] [-a attr] [-F '(extrafilter)'] [-Q
/f/s=sb:hb:gb:sf:hf:gf ...]\n" if $help;
%Q = checkQ(%Q);

my ($ldap, $bind);
if ( $ldap = Net::LDAP->new($ldaphost, version => 3, timeout => 3) ) {
        if ( $binddn && $password ) {
                $bind = $ldap->bind($binddn, password=>$password);
        } elsif ( $binddn && $passwordfile ){
                $bind = $ldap->bind($binddn, password=>bindpw($passwordfile));
        } else {
                $bind = $ldap->bind();
        }
        die "Unable to connect to LDAP\n" if $bind->code;
        undef $passwordfile;
} else {
        die "Unable to connect to LDAP\n";
}

my $search = $ARGV[0] ? $ldap->search(base=>$basedn, filter=>"uid=$ARGV[0]") : $ldap->search(base=>$basedn, filter=>$F);
if ( $search->code ) {
        die "LDAP Error: ", error($search), "\n";
} elsif ( $search->count <= 0 ) {
        die "0 results found in LDAP\n";
} else {
        my $i = 0;
        for ( $i=0; $i<$search->count; $i++ ) {
                my $entry = $search->entry($i);
                my @oc = $entry->get_value('objectClass');
                # objectClass: $oc
                unless ( grep { /^$oc$/ } @oc ) {
                        my $modify = $ldap->modify($entry->dn, add => {objectClass => $oc});
                        if ( $modify->code ) {
                                print STDERR "Failed to add objectClass $oc:", error($modify), "\n";
                        }
                }
                # $attr: /f/s=sb:hb:sf:hf
                if ( $entry->exists($attr) ) {
                        my @attr = $entry->get_value($attr);
                        if ( keys %Q ) {
                                foreach my $fs ( keys %Q ) {
                                        foreach ( @attr ) {
                                                next unless /^$fs=/;
                                                my $modify = $ldap->modify($entry->dn, delete => {$attr => "$_"});
                                                if ( $modify->code ) {
                                                        print STDERR "Failed to delete $attr: $_: ", error($modify), "\n";
                                                }
                                        }
                                        my $modify = $ldap->modify($entry->dn, add => {$attr => "$fs=$Q{$fs}"});
                                        if ( $modify->code ) {
                                                print STDERR "Failed to add $attr: $fs=$Q{$fs}: ", error($modify), "\n";
                                        } else {
                                                print STDERR "Failed to setquota: $fs=$Q{$fs}\n" if setquota($entry->get_value('uid'), $fs, $Q{$fs});
                                        }
                                }
                        } else {
                                my $modify = $ldap->modify($entry->dn, delete => [($attr)]);
                                if ( $modify->code ) {
                                        print STDERR "Failed to delete $attr: ", error($modify), "\n";
                                } else {
                                        foreach ( @attr ) {
                                                my ($fs) = m!^(/[^=]*)!;
                                                $Q{$fs} = '0:0:0:0:0:0';
                                                print STDERR "Failed to setquota: $fs=$Q{$fs}\n" if setquota($entry->get_value('uid'), $fs, $Q{$fs});
                                        }
                                }
                        }
                } else {
                        if ( keys %Q ) {
                                foreach my $fs ( keys %Q ) {
                                        my $modify = $ldap->modify($entry->dn, add => {$attr => "$fs=$Q{$fs}"});
                                        if ( $modify->code ) {
                                                print STDERR "Failed to add $attr: $fs=$Q{$fs}: ", error($modify), "\n";
                                        } else {
                                                print STDERR "Failed to setquota: $fs=$Q{$fs}\n" if setquota($entry->get_value('uid'), $fs, $Q{$fs});
                                        }
                                }
                        }
                }
        }
}

sub setquota {
        $_[2] = '0:0:0:0:0:0' unless $_[2];
        $_[2] =~ /^(\d+):(\d+):(\d+):(\d+):(\d+):(\d+)$/;
        qx{/usr/sbin/setquota -u $_[0] $1 $2 $4 $5 $_[1]};
        qx{/usr/sbin/setquota -T -u $_[0] $3 $6 $_[1]};
        return 0;
}

sub checkQ {
        my (%Q) = @_;
        foreach ( keys %Q ) {
                die "$_: invalid format\n" unless m!^(/[^=]*)! && $Q{$_} =~ /^(\d+):(\d+):(\d+):(\d+):(\d+):(\d+)$/;
        }
        return %Q;
}

sub bindpw {
        my ($passwordfile) = @_;
        open P, $passwordfile or die "Can't open passwordfile: $!";
        chomp(my $password = <P>);
        close P;
        return $password;
}

sub error {
        return $_[0]->error, "(", $_[0]->code, ")";
}