0: #!/usr/bin/perl -w
1: # by Steve Haslam
2:
3: # description:
4:
5: # adds a user into an LDAP group- where "users" and "groups" are the
6: # objects seen by nss_ldap.
7:
8: # would be nice to be able to use pam-ldap here, but I've not got
9: # that to work yet.
10:
11: # notes:
12: # at least on my machine, Term::Readkey gives loads of "use of
13: # uninitialized value" errors. ymmv.
14:
15: # illustrates lots of things, and a resonably nice showcase for some
16: # techniques for working with Net::LDAP (e.g. the ldapassert() sub)
17:
18: require 5;
19: use strict;
20: use Net::LDAP;
21: use Net::LDAP::Util qw(ldap_error_text);
22: use Term::ReadKey;
23: use Getopt::Std;
24: use vars qw($hostname $basedn $ldap $sr $username $groupname $userdn $groupdn $entry $admindn $adminpw $verbose %opts);
25:
26: getopts('h:D:b:v', \%opts) && @ARGV == 2 or die "Syntax: $0 [-v] [-h hostname] [-D binddn] [-b basedn] username groupname";
27:
28: ($username, $groupname) = (lc($ARGV[0]), lc($ARGV[1]));
29:
30: $verbose = 1 if ($opts{'v'});
31:
32: # Print something if the -v switch was given
33: sub printv {
34: print(@_) if ($verbose);
35: }
36:
37: # Wrapper for a Net::LDAP call- assert the server message is a "success"
38: # code- die with a decoded error message if it isn't
39: sub ldapassert {
40: my $mesg = shift;
41: my $op = shift;
42: $mesg->code && die "LDAP error".($op?" during $op":"").": ".ldap_error_text($mesg->code)."\n";
43: $mesg;
44: }
45:
46: # Extract a configuration option from the nss-ldap configuration file
47: # /etc/libnss-ldap.conf is the Debian conf file location
48: # /etc/ldap.conf is an alternative plausible location
49: sub confoption {
50: my $optname = lc(shift);
51: my $conffile;
52:
53: foreach $conffile (qw|/etc/libnss-ldap.conf /etc/ldap.conf|) {
54: if (-f $conffile) {
55: open(LDAPCONF, $conffile) or die "Unable to open nss-ldap configuration file $conffile: $!\n";
56: while (<LDAPCONF>) {
57: s/\#.*//;
58: chomp;
59: my($keyword, $value) = split(/ +/, $_, 2);
60: next unless (defined($keyword) && defined($value));
61: $keyword = lc($keyword);
62: if ($keyword eq $optname) {
63: close(LDAPCONF);
64: printv "[ldapconf $conffile] using \"$value\" for \"$optname\"\n";
65: return $value;
66: }
67: }
68: return undef;
69: }
70: }
71:
72: printv "[ldapconf] no value for \"$optname\"\n";
73:
74: return undef;
75: }
76:
77: $hostname = $opts{'h'} || confoption('host');
78: $basedn = $opts{'b'} || confoption('base');
79:
80: $ldap = Net::LDAP->new($hostname) or die "$@";
81:
82: # Bind as administrator user
83: $admindn = $opts{'D'} || confoption('binddn');
84:
85: # Get admin password iff a bind dn was specified
86: if ($admindn) {
87: print "LDAP password: ";
88: ReadMode('noecho');
89: $adminpw = ReadLine;
90: chomp($adminpw);
91: ReadMode(0);
92: print "\n";
93: }
94:
95: # Perform bind
96: # bind anonymously if no pw given
97: if ($adminpw) {
98: printv "Binding as $admindn\n";
99: ldapassert($ldap->bind(dn => $admindn, password => $adminpw), "bind");
100: }
101: else {
102: printv "Binding anonymously\n";
103: ldapassert($ldap->bind, "anonymous bind");
104: }
105:
106: # Find the user- get the user dn
107: $sr = ldapassert($ldap->search(base => "ou=People, $basedn", filter => "(&(objectClass=posixAccount)(uid=$username))"), "user search");
108:
109: if ($sr->count == 0) {
110: die "Unknown user '$username'\n";
111: }
112: elsif ($sr->count > 1) {
113: die "Ambiguous user '$username' (this is really bad)\n";
114: }
115:
116: $entry = $sr->shift_entry;
117: $userdn = $entry->dn;
118:
119: # Find the group- get the group dn
120: $sr = ldapassert($ldap->search(base => "ou=Group, $basedn", filter => "(&(objectClass=posixGroup)(cn=$groupname))"), "group search");
121:
122: if ($sr->count == 0) {
123: die "Unknown group '$groupname'\n";
124: }
125: elsif ($sr->count > 1) {
126: die "Ambiguous group '$groupname' (this is really bad)\n";
127: }
128:
129: $entry = $sr->shift_entry;
130: $groupdn = $entry->dn;
131:
132: # Is the user already in the group?
133: foreach (@{$entry->get('memberuid')}) {
134: if (lc($_) eq lc($username)) {
135: print "$username is already a member of $groupname\n";
136: exit(0);
137: }
138: }
139:
140: # OK, now update the group entry
141: # $entry is the group entry
142: printv "Adding [$userdn] to [$groupdn]\n";
143:
144: $entry->add(memberuid => $username);
145:
146: ldapassert($entry->update($ldap), "update"); # Write updated entry to directory server
147:
148: exit(0);
Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
Read Where should I post X? if you're not absolutely sure you're posting in the right place.
Please read these before you post! —
Posts may use any of the Perl Monks Approved HTML tags:
- a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
| |
For: |
|
Use: |
| & | | & |
| < | | < |
| > | | > |
| [ | | [ |
| ] | | ] |
Link using PerlMonks shortcuts! What shortcuts can I use for linking?
See Writeup Formatting Tips and other pages linked from there for more info.