setquota-ldap.pl 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. #!/usr/bin/perl
  2. # A Perl wrapper for setquota utility which updates LDAP accordingly.
  3. # /etc/fstab: usrquota,grpquota
  4. # mount -o remount /f/s
  5. # touch /f/s/aquota.{user,group}
  6. # chmod 600 /f/s/aquota.{user,group}
  7. # quotacheck -cguvamf
  8. use strict;
  9. use warnings;
  10. use Net::LDAP;
  11. use Net::LDAP::Entry;
  12. use Getopt::Long;
  13. Getopt::Long::Configure ("bundling");
  14. my $help = $#ARGV >= 0 ? 0 : 1;
  15. my $ldaphost = 'localhost';
  16. my $passwordfile = '';
  17. my $password = '';
  18. my $binddn = $ENV{BINDDN};
  19. my $basedn = $ENV{BASEDN};
  20. my $oc = 'systemQuotas';
  21. my $attr = 'quota';
  22. my %Q = ();
  23. my $F = 'cn=*';
  24. GetOptions(
  25. 'help|?' => \$help,
  26. 'oc|o=s' => \$oc,
  27. 'attr|a=s' => \$attr,
  28. 'quota|Q=s' => \%Q,
  29. 'filter|F=s' => \$F,
  30. 'ldaphost|h=s' => \$ldaphost,
  31. 'basedn|b=s' => \$basedn,
  32. 'binddn|D=s' => \$binddn,
  33. 'password|w=s' => \$password,
  34. 'passwordfile|W=s' => \$passwordfile,
  35. );
  36. die "Usage: $0 -b basedn [-o objectClass] [-a attr] [-F '(extrafilter)'] [-Q
  37. /f/s=sb:hb:gb:sf:hf:gf ...]\n" if $help;
  38. %Q = checkQ(%Q);
  39. my ($ldap, $bind);
  40. if ( $ldap = Net::LDAP->new($ldaphost, version => 3, timeout => 3) ) {
  41. if ( $binddn && $password ) {
  42. $bind = $ldap->bind($binddn, password=>$password);
  43. } elsif ( $binddn && $passwordfile ){
  44. $bind = $ldap->bind($binddn, password=>bindpw($passwordfile));
  45. } else {
  46. $bind = $ldap->bind();
  47. }
  48. die "Unable to connect to LDAP\n" if $bind->code;
  49. undef $passwordfile;
  50. } else {
  51. die "Unable to connect to LDAP\n";
  52. }
  53. my $search = $ARGV[0] ? $ldap->search(base=>$basedn, filter=>"uid=$ARGV[0]") : $ldap->search(base=>$basedn, filter=>$F);
  54. if ( $search->code ) {
  55. die "LDAP Error: ", error($search), "\n";
  56. } elsif ( $search->count <= 0 ) {
  57. die "0 results found in LDAP\n";
  58. } else {
  59. my $i = 0;
  60. for ( $i=0; $i<$search->count; $i++ ) {
  61. my $entry = $search->entry($i);
  62. my @oc = $entry->get_value('objectClass');
  63. # objectClass: $oc
  64. unless ( grep { /^$oc$/ } @oc ) {
  65. my $modify = $ldap->modify($entry->dn, add => {objectClass => $oc});
  66. if ( $modify->code ) {
  67. print STDERR "Failed to add objectClass $oc:", error($modify), "\n";
  68. }
  69. }
  70. # $attr: /f/s=sb:hb:sf:hf
  71. if ( $entry->exists($attr) ) {
  72. my @attr = $entry->get_value($attr);
  73. if ( keys %Q ) {
  74. foreach my $fs ( keys %Q ) {
  75. foreach ( @attr ) {
  76. next unless /^$fs=/;
  77. my $modify = $ldap->modify($entry->dn, delete => {$attr => "$_"});
  78. if ( $modify->code ) {
  79. print STDERR "Failed to delete $attr: $_: ", error($modify), "\n";
  80. }
  81. }
  82. my $modify = $ldap->modify($entry->dn, add => {$attr => "$fs=$Q{$fs}"});
  83. if ( $modify->code ) {
  84. print STDERR "Failed to add $attr: $fs=$Q{$fs}: ", error($modify), "\n";
  85. } else {
  86. print STDERR "Failed to setquota: $fs=$Q{$fs}\n" if setquota($entry->get_value('uid'), $fs, $Q{$fs});
  87. }
  88. }
  89. } else {
  90. my $modify = $ldap->modify($entry->dn, delete => [($attr)]);
  91. if ( $modify->code ) {
  92. print STDERR "Failed to delete $attr: ", error($modify), "\n";
  93. } else {
  94. foreach ( @attr ) {
  95. my ($fs) = m!^(/[^=]*)!;
  96. $Q{$fs} = '0:0:0:0:0:0';
  97. print STDERR "Failed to setquota: $fs=$Q{$fs}\n" if setquota($entry->get_value('uid'), $fs, $Q{$fs});
  98. }
  99. }
  100. }
  101. } else {
  102. if ( keys %Q ) {
  103. foreach my $fs ( keys %Q ) {
  104. my $modify = $ldap->modify($entry->dn, add => {$attr => "$fs=$Q{$fs}"});
  105. if ( $modify->code ) {
  106. print STDERR "Failed to add $attr: $fs=$Q{$fs}: ", error($modify), "\n";
  107. } else {
  108. print STDERR "Failed to setquota: $fs=$Q{$fs}\n" if setquota($entry->get_value('uid'), $fs, $Q{$fs});
  109. }
  110. }
  111. }
  112. }
  113. }
  114. }
  115. sub setquota {
  116. $_[2] = '0:0:0:0:0:0' unless $_[2];
  117. $_[2] =~ /^(\d+):(\d+):(\d+):(\d+):(\d+):(\d+)$/;
  118. qx{/usr/sbin/setquota -u $_[0] $1 $2 $4 $5 $_[1]};
  119. qx{/usr/sbin/setquota -T -u $_[0] $3 $6 $_[1]};
  120. return 0;
  121. }
  122. sub checkQ {
  123. my (%Q) = @_;
  124. foreach ( keys %Q ) {
  125. die "$_: invalid format\n" unless m!^(/[^=]*)! && $Q{$_} =~ /^(\d+):(\d+):(\d+):(\d+):(\d+):(\d+)$/;
  126. }
  127. return %Q;
  128. }
  129. sub bindpw {
  130. my ($passwordfile) = @_;
  131. open P, $passwordfile or die "Can't open passwordfile: $!";
  132. chomp(my $password = <P>);
  133. close P;
  134. return $password;
  135. }
  136. sub error {
  137. return $_[0]->error, "(", $_[0]->code, ")";
  138. }