pam_filter not working

So here is the problem you want to limit your cluster to a special user group. You have everything LDAP managed and use pam_ldap for authentication. But when you edit the /etc/ldap.conf and set a pam_filter nothing happens. First of all the the syntax of pam_filter :
(|(gidNumber=1028)(gidNumber=1160))
Will not work
Literally only
pam_filter gidNumber=1028
Will work. This is the way they stupidly implemented it
      else if (!strcasecmp (k, "pam_filter"))
{
CHECKPOINTER (result->filter = strdup (v));
}

where v is everything after the ' '

while (*v != '\0' && *v != ' ' && *v != '\t')
v++;

*(v++) = '\0';

For those that know C
So you can give it one value max. Now you have to modify the /etc/pam.d/system-auth file. The default configuration is:
[root@lxb5477 ~]# cat /etc/pam.d/system-auth.back | grep ldap
auth sufficient /lib/security/$ISA/pam_ldap.so use_first_pass
account [default=bad success=ok user_unknown=ignore] /lib/security/$ISA/pam_ldap.so
password sufficient /lib/security/$ISA/pam_ldap.so use_authtok
session optional /lib/security/$ISA/pam_ldap.so

But of course a optional is not really enough. You, of course, want that if the user doesn't fulfill your filter he should be chucked into nirvana. So change to:
[root@lxb5477 ~]# cat /etc/pam.d/system-auth | grep ldap
auth required /lib/security/$ISA/pam_ldap.so
account required /lib/security/$ISA/pam_ldap.so
password requried /lib/security/$ISA/pam_ldap.so use_authtok
session required /lib/security/$ISA/pam_ldap.so

Through this if ldap fails the login fails.

But be aware that in /etc/nsswitch.conf files is before ldap
passwd:     files ldap
shadow: files ldap
group: files ldap

Otherwise you have locked yourself out :)

Really nice idea

While registering for the BCS I had to supply a Email address, nothing special, but after that they asked me for an alternative Email. What now thinking about it is really clever. If my main server goes offline for some reason. (Gmail starts charging) they can always send messages to my alternative address so I don't lose information. One thing the BCS did well. One out of thousands they did absolutely disgrace full.

strcpy fu**ing easy

While trying to optimize some c code I had a look at the strcpy.c file and was astonished what to see there:

do
{
c = *s++;
s[off] = c;
}
while (c != '\0');

This is pretty much it. Some boundary checks. But THAT is it. And nearly all the files in glibc/string are like that.

update: (thx to Edd) the OpenBSD way of doing it
char *
strcpy(char *to, const char *from)
{
char *save = to;

for (; (*to = *from) != '\0'; ++from, ++to);
return(save);
}

Cern Week 24

I spent most of the week rewriting the
CERN-CC-NodeServiceManagerMsg
As already mentioned this tool scanns all the hosts and if the ssh certificate is about to expire sends an email to the responsible person. Further it creates a webpage so that people can easially check what has to be done.
After some analysis on the current program I decided to rewrite the whole thing. The old version was not maintained the guy who had written it had left and it looked more like a patchwork rung than a properly designed pice of code.
So following a lot of perl code some results
Some optimization I made

$ time CERN-CC-NodeServiceManagerMsg > /dev/null

real 1m12.080s
user 0m23.730s
sys 0m1.930s
$ time ./sendIt > /dev/null

real 0m1.514s
user 0m0.430s
sys 0m0.040s
and more

$ time ./CERN-CC-NodeCertCheck -m > /dev/null

real 0m0.784s
user 0m0.500s
sys 0m0.050s

While reducing the time for the program to run from 72 seconds to 0.78 seconds, I started adding more features, like command line options, showing the ok nodes, checking if the path where the web page should be created exists and if not create the whole path tree, etc... After this was all ok I started writing the spec file for the rpm. Further I wrote a little 'man page' after I had built a source rpm and a 'normal' rpm my package went into testing. After the results had came back and the only thing not Ok was a typo in the email. I started uploading the package onto the official cern repository and rolled it out.
Another thing I did was help a friend with png transparency under windows. Better the not existing one. So now his web page dynamically loads the appropriate image. png for Linux and gif for windows with a Internet Explorer version before 7. I further spent some time on my phone Perl rewrite which is turning out to be quite tricky. Not only because of the backwards compatibility.

Cern Week 23

This was a fairly short week, as I came back from holidays on Thursday. Nothing really has changed since I left. We are all preparing for LHC to start to fire (fingers crossed) so the Castor team is sweating and we are trying to get a untested version to run on SL4. Further I started a little project with Dan to rewrite the phone program, which hasn't been touched since 1999. Further I started writing a Perl script that will find out when a ssh certificate expires and then send an email to the systems admin or the person responsible (Not always the same). Not as easy as you would have thought. You can't run it on every machine. You have to query a huge Oracle database for when the Certificate was created and then find out who is responsible for that machine (root@localhost will NOT work) and then send a very nice email. I further started to set up a Cern chat server. Everything here is done par email. Because no one uses a chat program. This has to change I set up a Jabber server and am now trying to get it to work with the Cern nice login. Which despite the name is not nice because everything is done in SOAP.

Create a /etc/passwd out of ldap

I wanted to create the /etc/passwd and /etc/group file from my ldap server. As LDAP is now replacing these (having a backup is always good :) So here is the perl script that will do such a thing. Of course this is very Cern specific, you will have to modify it for your use. I wrote a script that used the Perl NET::Ldap module. But this was far too slow (3 min +-) . See below right at the end

 1: #!/usr/bin/perl -w
2: #
3: # A program that queries a ldap server and creates /etc/passwd and /etc/groups syntax files
4: #
5: # $Id: cpgfl.pl,v 1.7 2007/12/18 15:01:45 jveldik Exp $
6:
7: #All the includes
8: use strict;
9: use diagnostics;
10: use MIME::Base64;
11: use Data::Dumper;
12: $Data::Dumper::Sortkeys = 1;
13:
14: my $lockfile = "lock_the_file.loc";
15: my $ldappasswdfile = my $ldapgroufile = undef;
16:
17: my $lUsersQuery = '/usr/bin/ldapsearch -h lxb5479 -x -b "ou=People,dc=example,dc=edu" -D "cn=Manager,dc=example,dc=edu" -w youknow "(&(objectClass=posixAccount)(uid=*))" 2> /dev/null |';
18: my $lGroupQuery = '/usr/bin/ldapsearch -h lxb5479 -x -b "ou=Group,dc=example,dc=edu" -D "cn=Manager,dc=example,dc=edu" -w youknow "(&(objectClass=posixGroup)(cn=*))" 2> /dev/null |';
19:
20: sub createLock() {
21: if ( -e $lockfile ) {
22: warn("Program is already running: $lockfile exists\n");
23: exit(1);
24: }
25: open(LOCK, ">$lockfile" ) or die "Cannot open lock file!\n";
26: close(LOCK);
27: }
28:
29: sub releaseLock() {
30: unlink $lockfile;
31: }
32:
33: sub getPasswd () {
34: my %object;
35:
36: open( LDAP, $lUsersQuery ) or die("Cannot run ldapsearch: $!");
37:
38: createLock();
39: open( DAT, ">" . $ldappasswdfile );
40:
41: while (<LDAP>) {
42: chomp;
43: s/\s+$//; # remove trailing whitespace (if any...)
44:
if (/^$/) {
45:
46: #If an emtpy line and uid is defined do some stuff
47: if ( defined( $object{"uid"} ) && ( $object{"uid"} ne "" ) ) {
48:
49: #if ($object{"uid"}) {
50:
51: my $line = join( ":",
52: $object{"uid"}, $object{"userPassword"},
53: $object{"uidNumber"}, $object{"gidNumber"},
54: $object{"gecos"}, $object{"homeDirectory"},
55: $object{"loginShell"} );
56:
57: print DAT $line . "\n";
58: }
59: %object = ();
60: next;
61: }
62:
63: createObjectHash( \%object, $_ );
64:
65: }
66:
67: close DAT;
68: releaseLock();
69:
70: close(LDAP);
71:
72: }
73: ################################################################GROUPS####################
74:
75: sub getGroup () {
76:
77: my %object;
78: open( GROUP,$lGroupQuery ) or die("Cannot run ldapsearch: $!");
79:
80: createLock();
81: open( DAT, ">" . $ldapgroufile );
82:
83: while ( my $buff = <GROUP> ) {
84: chomp $buff;
85: $buff =~ s/\s+$//; # remove trailing whitespace (if any...)
86:
if ( $buff =~ /^$/ ) {
87:
88: #If an emtpy line and uid is defined do some stuff
89: if ( defined( $object{"cn"} ) && ( $object{"cn"} ne "" ) ) {
90:
91: #if ($object{"uid"}) {
92: my $line = join( ":",
93: $object{"cn"}, $object{"userPassword"},
94: $object{"gidNumber"}, "" );
95: print DAT $line . "\n";
96: }
97: %object = ();
98: next;
99: }
100: createObjectHash( \%object, $buff );
101:
102: }
103: close DAT;
104: releaseLock();
105:
106: close(GROUP);
107:
108: }
109:
110: sub createObjectHash($$) {
111: my ( $h_rObj, $comline ) = @_;
112:
113: my ( $lhs, $rhs ) = split( /:\s+/, $comline );
114:
115: #Because of (userPassword:: e2NyeXB0fXg=) the ::
116: if ( $lhs eq "userPassword:" ) {
117:
118: #Have to decode because it comes in base64 encodeing
119: my $a = decode_base64($rhs);
120:
121: #Now we have to get rid of the {crypt}
122: $a =~ s/\{crypt\}//g;
123:

124: $h_rObj->{"userPassword"} = $a;
125: }
126: else {
127: $h_rObj->{$lhs} = $rhs;
128: }
129:
130: }
131:
132: # AND OFF WE GO
133:
134: if ( scalar(@ARGV) == 2 ) {
135: $ldappasswdfile = $ARGV[0];
136: $ldapgroufile = $ARGV[1];
137: print "Getting group\n";
138: getGroup();
139: print "Getting passwd\n";
140: getPasswd();
141: }
142: else {
143: print("A program that gets passwd + group entries out of Ldap\n");
144: print("Usage : ./cpgfl.pl passwdfile groupfile\n");
145: }


And out of interrest here is the version that uses NET::LDAP


#!/usr/bin/perl
# A little program that creates a /etc/passwd from ldap
use strict;
use Net::LDAP;

# Please modify appropriate
my $ldap = Net::LDAP->new("lxb5479.cern.ch") or die "Error in creating new Connection: $@";;

$ldap->bind("cn=Manager,dc=example,dc=edu", password=>"IHATETHIS");

my $mesg = $ldap->search(filter=>"(&(objectClass=posixAccount)(uid=*))", base=>"ou=People,dc=example,dc=edu");

$mesg->code && die $mesg->error;

#########!!!DO NOT TOUCH!!!##########

#foreach my $entry ($mesg->entries) {

while (my $entry=$mesg->pop_entry ( )){

# Get rid of {crypt}
my $a = $entry->get_value("userPassword");
$a =~ s/\{crypt\}//g;

my $line = join (":", $entry->get_value("uid"),
$a ,
$entry->get_value("uidNumber") ,
$entry->get_value("gidNumber") ,
$entry->get_value("gecos") ,
$entry->get_value("homeDirectory") ,
$entry->get_value("loginShell") );
print $line . "\n";
}


$ldap->unbind;

#end