[Date Prev][Date Next] [Chronological] [Thread] [Top]

back-passwd patch for chfn data



I'm probably doing this all wrong, but then I'm probably
not going to do much more work on this, and I thought I'd at least share
my ideas even if my code's all rubbish :-)

I was looking for something that would talk LDAP to Netscape 4.5
and run on Linux, and found this project. I managed to get it going and
played a bit with an address database, then found the passwd backend
and figured out how to run that.

We're setting up a Linux box to run sendmail and IMAP, with a captive
shell to let people change their display name and password. We'll probably
use "chfn" for this. chfn and finger assume that the GECOS field may be
comma-delimited into name, office, work phone and home phone (and "other"
in cfingerd). It occurred to me that if we set up openLDAP with the passwd
backend, then we get a correct email directory for free. We're using
sendmail, with the MatchGECOS option enabled. This lets people use an
alias e.g. "Andrew_Daviel@triumf.ca" for "advax@triumf.ca" (or
Andrew.Daviel, but I disabled dot blank substitution when I found we have
many people with initials in GECOS).
#O BlankSub=.
O MatchGECOS
in /etc/sendmail.cf (version 8.8 & up)

The attached patch against ldap/servers/slapd/back-passwd/search.c
splits out these extra fields from the GECOS, and adds a mail alias
created by underscore substitution from the fullname field.
I assigned:
  cn = real name
  telephonenumber = work phone
  homephone = home phone
  mail = pw_name
  mail = real_name
  l = office
  givenname = real name[0]
  sn = real name[n]

There's problems with dealing adequately with all variants
"Andrew Daviel", "Andrew J Daviel" "Rip van Winkle", "A. Daviel" etc. - 
it gets RvW's last name as "Winkle" instead of "van Winkle". chfn
disallows "Daviel, Andrew" which removes one hiccup, at any rate.  

"properties" of an address entry in Netscape shows the full record, more
or less, with both email aliases. Only the first appears in the
original entry - one can re-order them in search.c, or possibly add
an ifdef to do it.


One could perhaps assign "ou" or "office" to office; I arbitrarily
assigned "l" (= location) since it appears in the Netscape listing (though
as "City");as a list for primarily internal consumption room numbers
seem a bit more useful than City.... 

My demo is at ldap://trmail.triumf.ca:390, server root = "triumf.ca"
e.g. ldapsearch -p 390 -h trmail.triumf.ca -b triumf.ca sn=daviel

X-Mosaic lets one see finger info as
gopher://trmail.triumf.ca:79/0advax which seemed cool, but Netscape
won't. Finger of course as advax@trmail.triumf.ca .
One can check out aliases as 
telnet trmail.triumf.ca 25
helo me
vrfy advax
vrfy andrew_daviel
quit

etc.

As regards the code, clearly it needs fixing somewhat if anyone wants to
adopt it officially; it needs to inherit DOMAIN and MatchGECOS
properly from config.h or something, and my "C" is a bit inept, though I
believe it doesn't crash (at least, not straightaway...)  :-7


(on a side note, does anyone know how to configure openldap to use
Netscape's username/password dialog? I didn't see it in a quick grep
through the archives)


regards

Deniable unless digitally signed
Andrew Daviel, TRIUMF, Canada
Tel. +1 (604) 222-7376
http://andrew.triumf.ca/andrew 
--- ldap.stable.back-passwd/search.c	Wed Jan 13 20:52:12 1999
+++ search.c	Fri Mar  5 22:55:03 1999
@@ -1,4 +1,10 @@
 /* search.c - /etc/passwd backend search function */
+/* some gecos splits added, as per 'chfn' and 'finger' - A.Daviel Mar 1999 */
+
+#define MatchGECOS 1
+#define DOMAIN "triumf.ca"
+#define ORG "TRIUMF"
+#define MINUID 100
 
 #include "portable.h"
 
@@ -12,6 +18,16 @@
 
 #include "slap.h"
 
+typedef struct  {
+  char *office;
+  char *officephone;
+  char *homephone ;
+  char *realname ;
+  char *first ;
+  char *last ;
+} gecos_def ;
+
+
 static Entry	*pw2entry(Backend *be, struct passwd *pw);
 
 int
@@ -49,16 +65,18 @@
 #endif /* HAVE_SETPWFILE */
 
 	if ( scope == LDAP_SCOPE_BASE ) {
+		/* dn is set to email address; come here for 
+		 * "properties" in Netscape 4.5
+		 */
 		if ( (s = strchr( base, '@' )) != NULL ) {
 			*s = '\0';
 		}
 
-		if ( (pw = getpwnam( base )) == NULL ) {
+		if ( (pw = getpwnam( base )) == NULL || pw->pw_uid < MINUID ) {
 			send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT,
 			    s != NULL ? s + 1 : NULL, NULL );
 			return( -1 );
 		}
-
 		e = pw2entry( be, pw );
 		if ( test_filter( be, conn, op, e, filter ) == 0 ) {
 			send_search_entry( be, conn, op, e, attrs, attrsonly );
@@ -92,9 +110,12 @@
 		}
 		pthread_mutex_unlock( &currenttime_mutex );
 
-		e = pw2entry( be, pw );
+	        /* only return "real" users, uids above 100 or so */
+		if (pw->pw_uid >= MINUID) {
 
-		if ( test_filter( be, conn, op, e, filter ) == 0 ) {
+		    e = pw2entry( be, pw );
+
+		    if ( test_filter( be, conn, op, e, filter ) == 0 ) {
 			/* check size limit */
 			if ( --slimit == -1 ) {
 				send_ldap_result( conn, op, LDAP_SIZELIMIT_EXCEEDED,
@@ -104,9 +125,10 @@
 			}
 
 			send_search_entry( be, conn, op, e, attrs, attrsonly );
-		}
+		    }
 
-		entry_free( e );
+		    entry_free( e );
+		}
 	}
 	endpwent();
 	send_ldap_result( conn, op, LDAP_SUCCESS, "", "" );
@@ -121,34 +143,110 @@
 	char		buf[256];
 	struct berval	val;
 	struct berval	*vals[2];
+        char *bp, *p, *t;
+        gecos_def *gecos ;
+	char *domain = DOMAIN ;
+	char *org = ORG ;
+	char *alias ;
 
 	vals[0] = &val;
 	vals[1] = NULL;
 
 	/*
-	 * from pw we get pw_name and make it uid and cn and sn and
-	 * we get pw_gecos and make it cn and we give it an objectclass
-	 * of person.
+	 * From pw we get pw_name, add '@DOMAIN' and make it mail.
+	 * We get pw_gecos, split it and make cn, l, telephonenumber
+	 * and homephone. (See chfn manpage).
+	 * We take the first word from cn to make givenname and
+	 * take the last word and make sn.
+	 * If MatchGECOS is defined, we substitute '_' for spaces in
+	 * cn to create a mail alias.
+	 * We give the result an objectclass of person.
 	 */
 
 	e = (Entry *) ch_calloc( 1, sizeof(Entry) );
 	e->e_attrs = NULL;
-
+	if (!pw->pw_name) return(e) ; /* unk! */
+	sprintf( buf, "%s@%s",pw->pw_name,domain);
+	val.bv_val = buf;
+	val.bv_len = strlen( val.bv_val );
+	attr_merge( e, "mail", vals );
+	val.bv_val = org ;
+	val.bv_len = strlen( val.bv_val );
+	attr_merge( e, "o", vals );
+	val.bv_val = "person";
+	val.bv_len = strlen( val.bv_val );
+	attr_merge( e, "objectclass", vals );
 	sprintf( buf, "%s@%s", pw->pw_name, be->be_suffix[0] );
 	e->e_dn = ch_strdup( buf );
 	e->e_ndn = ch_strdup( buf );
+	
+	bp = pw->pw_gecos ;
+	if (strlen(bp)==0)  return(e) ;
+
+        if (*bp == '*') ++bp;
+        gecos = (gecos_def *)malloc( sizeof(gecos_def)) ;
+        gecos->realname =  ((p = strsep(&bp, ",")) && *p) ?
+          strdup(p) : NULL;
+	
+	gecos->office = ((p = strsep(&bp, ",")) && *p) ?  strdup(p) : NULL;
+	gecos->officephone = ((p = strsep(&bp, ",")) && *p) ?  strdup(p) : NULL;
+	gecos->homephone = ((p = strsep(&bp, ",")) && *p) ?  strdup(p) : NULL;
 
-	val.bv_val = pw->pw_name;
-	val.bv_len = strlen( pw->pw_name );
-	attr_merge( e, "cn", vals );
-	attr_merge( e, "sn", vals );
-	attr_merge( e, "uid", vals );
-	val.bv_val = pw->pw_gecos;
-	val.bv_len = strlen( pw->pw_gecos );
-	attr_merge( e, "cn", vals );
-	val.bv_val = "person";
+	val.bv_val = gecos->realname ;
 	val.bv_len = strlen( val.bv_val );
-	attr_merge( e, "objectclass", vals );
+	attr_merge( e, "cn", vals );
 
+	if (gecos->office) {
+	  val.bv_val = gecos->office ;
+	  val.bv_len = strlen( val.bv_val );
+	  attr_merge( e, "l", vals );
+	}
+	if (gecos->officephone) {
+          val.bv_val = gecos->officephone ;
+          val.bv_len = strlen( val.bv_val );
+          attr_merge( e, "telephonenumber", vals );
+	}
+        if (gecos->homephone) {
+	  val.bv_val = gecos->homephone ;
+          val.bv_len = strlen( val.bv_val );
+          attr_merge( e, "homephone", vals );
+	}
+
+	if (gecos->realname) {
+#ifdef MatchGECOS
+	  alias = strdup(gecos->realname) ;
+	  /* '_' substitutes for spaces in sendmail */
+	  for (t=alias;*t;t++) {
+	    if (*t == ' ') *t = '_' ;
+	  }
+	  sprintf( buf, "%s@%s",alias,domain) ;
+	  val.bv_val = buf;
+	  val.bv_len = strlen( val.bv_val );
+	  attr_merge( e, "mail", vals );
+	  free(alias) ;
+#endif
+	  gecos->last = (gecos->realname && (p=rindex(gecos->realname,' ')) && *p) ?
+            strdup(++p) : strdup(pw->pw_name);
+	  bp = gecos->realname ;
+	  gecos->first = ((p = strsep(&bp, " ")) && *p) ?  strdup(p) : NULL;
+
+	  val.bv_val = gecos->first ;
+	  val.bv_len = strlen( val.bv_val );
+	  attr_merge( e, "givenname", vals );
+
+	  val.bv_val = gecos->last ;
+          val.bv_len = strlen( val.bv_val );
+          attr_merge( e, "sn", vals );
+	}
+
+	/* free up stuff alloc'd by strdup */
+	free(gecos->realname) ;
+	free(gecos->office) ;
+	free(gecos->officephone) ;
+	free(gecos->homephone) ;
+	free(gecos->first) ;
+	free(gecos->last) ;
+	free(gecos) ;
 	return( e );
 }
+