tags:

views:

198

answers:

1

I'm using openldap on Mac OS X Server 10.6 and need to generate a vcard for all the users in a given group. By using the ldapsearch I can list all the memberUid's for all users in that group. I found a perl script (Advanced LDAP Search or ALS) that was written by someone that will generate the vcard easily. ALS can be found here http://www.ldapman.org/tools/als.gz

So what I need to do is create a wrapper script (in python or perl) that will effectively loop through the memberUid's and run the ALS command to create the vcard and append it to the file.

This command provides the memberUid's:

ldapsearch -x -b 'dc=ldap,dc=server,dc=com' '(cn=testgroup)'

Then running ALS gives the vcard:

als -b dc=ldap,dc=server,dc=com -V uid=aaronh > vcardlist.vcf

If it's easier to do this using Perl since ALS is already using it that would be fine. I've done more work in python but I'm open to suggestions.

Thanks in advance, Aaron

EDIT:

Here is a link to the Net:LDAP code that I have to date. So far it pulls down the ldap entries with all user information. What I'm missing is how to capture just the UID for each user and then push it into ALS.

http://www.queencitytech.com/net-ldap

Here is an example entry (after running the code from the above link):

#-------------------------------
DN: uid=aaronh,cn=users,dc=ldap,dc=server,dc=com
  altSecurityIdentities : Kerberos:[email protected]
  apple-generateduid : F0F9DA73-70B3-47EB-BD25-FE4139E16942
  apple-imhandle : Jabber:[email protected]
  apple-mcxflags : <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;
<plist version="1.0">
<dict>
    <key>simultaneous_login_enabled</key>
    <true/>
</dict>
</plist>

  authAuthority : ;ApplePasswordServer;0x4c11231147c72b59000001f800001663,1024 35 131057002239213764263627099108547501925287731311742942286788930775556419648865483768960345576253082450228562208107642206135992876630494830143899597135936566841409094870100055573569425410665510365545238751677692308677943427807426637133913499488233527734757673201849965347880843479632671824597968768822920700439 [email protected]:192.168.1.175;Kerberosv5;0x4c11231147c72b59000001f800001663;[email protected];LDAP.SERVER.COM;1024 35 131057002239213764263627099108547501925287731311742942286788930775556419648865483768960345576253082450228562208107642206135992876630494830143899597135936566841409094870100055573569425410665510365545238751677692308677943427807426637133913499488233527734757673201849965347880843479632671824597968768822920700439 [email protected]:192.168.1.170
  cn : Aaron Hoffman
  gidNumber : 20
  givenName : Aaron
  homeDirectory : 99
  loginShell : /bin/bash
  objectClass : inetOrgPersonposixAccountshadowAccountapple-userextensibleObjectorganizationalPersontopperson
  sn : Hoffman
  uid : aaronh
  uidNumber : 2643
  userPassword : ********
#-------------------------------
+1  A: 

My language of choice would be Perl - but only because I've done similar operations using Perl and LDAP.

If I remember correctly, that ldapsearch command will give you the full LDIF entry for each uid in the testgroup cn. If that's the case, then you'll need to clean it up a bit before it's ready for the als part. Though it's definitely not the most elegant solution, a quick and dirty method is to use backticks and run the command's output through a grep. This will return a nice list of all the memberUids. From there it's just a simple foreach loop and you're done. Without any testing or knowing for sure what your LDAP output looks like, I'd go with something like this:

#!/usr/bin/perl

# should return a list of "memberUid: name" entries
@uids = `ldapsearch -x -b 'cn=testgroup,cn=groups,dc=ldap,dc=server,dc=com' | grep memberUid:`;

foreach (@uids) {
   $_ =~ s/memberUid: //;  # get rid of the "uid: " part, leaving just the name
   chomp $_;         # get rid of the pesky newline
   system "als -b \"dc=ldap,dc=server,dc=com\" -V uid=$_ >> vcardlist.vcf";
}

As I said, I haven't tested this, and I'm not exactly sure what the output of your ldapsearch looks like, so you may have to tweak it a bit to fit your exact needs. That should be enough to get you going though.

If anyone has a better idea I'd love to hear it too.

elmugrat
Looks like it should work to me. I haven't used LDAP in years, but when I did I used the Net::LDAP pure-Perl library. Although since the guts of the LDAP processing is in this external als script anyway, it wouldn't really be too useful here, but could be used to replace the ldapsearch invocation.
araqnid
Yes you're absolutely right. Net::LDAP could certainly be used here to get the UIDs, but it would take considerably more time and effort to get working - far more, I think, than the OP would want to spend on a one time use script when ldapsearch is readily available.
elmugrat
Thanks for the help with this. I needed to make a couple changes. When I ran ldapsearch it output each of the uid's as "memberUid". Also, als couldn't be found so I needed to tell it to use perl. Now the vcardlist.vcf does output however the file only seems to have the testgroup vcard as well as another group which all users are also a part of. Any ideas why it would do this?
Aaron
Well now I see just how foolish I was for diving right into the Perl without looking at the ALS command first. Take a look at my other answer for what I now believe to be correct. My apologies for not looking before I leaped.
elmugrat
I just tried running ALS with the wildcard. I seem to be getting some interesting results. It's giving my back 25 entries none of which are actually in that testgroup. Then when I adjust the base dn to the group it only gives the vcard for that group. I have been messing with Net LDAP and was able to all the ldap info for all the users in the testgroup. I'm just not sure how to pull just the memberUid's. Is there a chance this method would be better than the quick and dirty method? Let me know what you think.
Aaron
I also added the code I have for net ldap to my original post above. If that is a better direction.
Aaron
Hmm could you post an LDIF for an example entry? Change the contact information of course, but it would be helpful to see exactly what we're dealing with. I tried running als on a database that I have and it worked just fine, so I doubt that using Net::LDAP will be much of an advantage. However, if you're interested in learning more about Net::LDAP, I'd highly recommend giving this article a read:http://www.linuxjournal.com/article/7086It helped me out a ton when I first started using it.
elmugrat
I posted an example entry above. Thats is a pretty interesting article, thanks for posting it. I'm certainly not set on using Net::LDAP if we can get this working with our original method I would be plenty happy :)
Aaron
Well I just found a bug in the original code I posted. In the ALS command there you need '>> vcardlist.vcf', not '> vcardlist.vcf' (append to file vs. overwrite). I've edited my answer (...again lol). This would explain why only 1 entry appeared. Also IIRC using ldapsearch for a group will return the group itself as the last match, which explains why you were getting an entry for the testgroup. Assuming that adding the > works, the easiest way to deal with that extra entry is to just delete it from the .vcf once its been generated.
elmugrat
I think we're getting closer! I've been doing some testing with this. For now I commented out the chomp part and I'm printing each uid. This makes it easier to see what's happening when I run the command. When it goes through each person, it appears to be pulling the groups that each individual is associated with AND it is writing that to the vcf. It was showing 25 entries because there's only a 25 groups that users might be associated. You're '>>' did work but now it just keeps repeating the groups. Somehow, I need to get it to give the user information and not the group. Any ideas on that?
Aaron
Run "ldapsearch -x -b 'dc=ldap,dc=server,dc=com' 'memberUid=aaronh' and check to make sure that there are no other lines in the output that contain 'memberUid:'. Then look for the line with your memberUid. It *should* be 'memberUid: aaronh'. If it's not, or if there is more than 1 line with memberUid in it then tell me exactly what the extra line is or what it has instead of what I think it should be. If you find either, then we just need to tweak the grep part a little bit.
elmugrat
I ran that command and it is giving me all the memberUid's for all users. And when I don't specify the group it gives me each group that I'm in as well as all the memberUid's...if that make sense. Before it outputs the memberUid's it lists all the apple-group-memberguid's for all the users. Lastly, if I do specify 'cn=testgroup' when I do the same ldapsearch it just lists the 3 groups that I am a part of and the DN.
Aaron
Ok now we're are getting to the bottom of this. What is the full DN of the test group? cn=testgroup,ou=group,dc=ldap,dc=server,dc=com?
elmugrat
it's cn=testgroup,cn=groups,dc=ldap,dc=server,dc=com
Aaron
ok I have once again updated my answer. Now that I remember the critical difference between uid and memberUid I think it might work!
elmugrat
You're the best! It's working now, looks the DN was the issue. Now the only thing that has me wondering...I've been adding entries on each person's 'chat' entry on the ldap server so that it has their [email protected]. None of these come through on the vcards. So I looked in ALS and sure enough it doesn't appear to even have that field. I found apple-imhandler which looks like the right field and added it as an attribute. It still won't pull it and I noticed that the Email doesn't either. Should I start a new question for this? Or do you think it is simple?
Aaron
So the Email is showing up...its just the "apple-imhandler" field. I do realize that since we already are getting the uid's it would be pretty easy to use that and concatenate the "@chat.server.com to create the "chat" field I need. However, it would be much nicer if we could modify ALS to accept it.
Aaron
Ok that looks pretty simple. You're just going to have to add a couple lines. 1) the attribute apple-imhandler at line ~65 (you said you did this already). 2) get the value at line ~189 with "my ($chat) = $entry->get_value("apple-imhandler");. 3) print to the .vcf at line ~211 with "print "X-JABBER:$chat\n" if($chat);" and 4) addition to default attribs at line ~348 with "apple-imhandler" somewhere in that qw() block. I think that's it. You may have to get fancier with the X-JABBER part if your people use varying chat services (http://bit.ly/daiMua for details)
elmugrat
Thanks for all the help on this. I was missing "apple-imhandler" in the qw() block. Now the Jabber line appears in the vcard. The only issue I seem to have is that it displays it as Jabber:[email protected] and therefore doesn't populate the im client because "Jabber:" is in front of it. As soon as I remove the "Jabber:" from the persons vcard entry it populates. Is there a way I can remove this before each address?
Aaron
so i'm stupid, i just used substr() and was able to remove the jabber part in the string. looks like it's all working great. thank you so much!
Aaron
Excellent! Glad I could help!
elmugrat
So it seems i'm having a slight issue. When I run the script it gives me an error afters its been running awhile. It says, "Use of uninitialized value $appleimhandle in substr at als line 220 <DATA> line 466" Based on the code it happens here: $appleimhandle=substr($appleimhandle,7) which tells me that maybe the variable doesn't have anything and cannot remove the beginning 7 chars. Is there a way to determine which entry is causing this to fail?
Aaron
Put 'print "$_\n";' between the chomp and system commands. The last username that prints will be the one that failed. Once you know that you can ldapsearch for that username and see what's going on. I suspect that your diagnosis is correct - if so an easy fix would be to either a) add the missing data in ldap, and/or b) change the substr() to '$appleimhandle =~ s/.+://;'. That will remove any characters before the ':', plus the ':' itself (if they exist).
elmugrat