By Harry Coin:
authorWilfried Goesgens <dothebart@citadel.org>
Mon, 30 Mar 2015 14:29:58 +0000 (16:29 +0200)
committerWilfried Goesgens <dothebart@citadel.org>
Mon, 30 Mar 2015 14:29:58 +0000 (16:29 +0200)
1)  The problem long discussed upstream to do with LDAP auth wanting the user name offered after the PASS command to stick around for later vcard use.  The approach is to have vcard related searches use the citserver username to search against the ldap CN, while login searches behave as in the release version.

2) The vcard has a field uid, which citserver uses to tag vcards  for uniqueness.  LDAP also has a uuid for each of its records, most aptly saved also in the vcard as uuid.  These collided causing the vcard to be reloaded every check owing to the overwriting the LDAP written uid over the citserver use of the same field. The patches below use the RFC approved 2.1 X- extension to support the field X-UUID for the ldap uuid.  There's also small code cleanup to avoid setting the UID twice.

citadel/citadel_ldap.h
citadel/ldap.c
citadel/modules/vcard/serv_vcard.c
citadel/user_ops.c

index 9ec1d92693cbe579802a67136df519d09cb54e12..9a312795a37c96888701dba8576831361a5f1341 100644 (file)
@@ -12,6 +12,6 @@
  *  GNU General Public License for more details.
  */
 
-int CtdlTryUserLDAP(char *username, char *found_dn, int found_dn_size, char *fullname, int fullname_size, uid_t *found_uid);
+int CtdlTryUserLDAP(char *username, char *found_dn, int found_dn_size, char *fullname, int fullname_size, uid_t *found_uid, int lookup_based_on_uid);
 int CtdlTryPasswordLDAP(char *user_dn, const char *password);
 int Ctdl_LDAP_to_vCard(char *ldap_dn, struct vCard *v);
index 6fd3fd3093afcd2925cd57bbba12c9bb2880a4f3..f7f415a8affe0a3ddbcb7085a1082b2db45f00c9 100644 (file)
@@ -60,7 +60,7 @@ int ctdl_ldap_initialize(LDAP **ld) {
 int CtdlTryUserLDAP(char *username,
                char *found_dn, int found_dn_size,
                char *fullname, int fullname_size,
-               uid_t *uid)
+               uid_t *uid, int lookup_based_on_username)
 {
        LDAP *ldserver = NULL;
        int i;
@@ -96,10 +96,16 @@ int CtdlTryUserLDAP(char *username,
        tv.tv_usec = 0;
 
        if (config.c_auth_mode == AUTHMODE_LDAP_AD) {
-               snprintf(searchstring, sizeof(searchstring), "(sAMAccountName=%s)", username);
+               if (lookup_based_on_username != 0)
+                       snprintf(searchstring, sizeof(searchstring), "(displayName=%s)",username);
+               else
+                       snprintf(searchstring, sizeof(searchstring), "(sAMAccountName=%s)", username);
        }
        else {
-               snprintf(searchstring, sizeof(searchstring), "(&(objectclass=posixAccount)(uid=%s))", username);
+               if (lookup_based_on_username != 0)
+                       snprintf(searchstring, sizeof(searchstring), "(cn=%s)",username);
+               else
+                       snprintf(searchstring, sizeof(searchstring), "(&(objectclass=posixAccount)(uid=%s))", username);
        }
 
        syslog(LOG_DEBUG, "LDAP search: %s", searchstring);
@@ -157,29 +163,31 @@ int CtdlTryUserLDAP(char *username,
                                ldap_value_free(values);
                        }
                }
-
-               if (config.c_auth_mode == AUTHMODE_LDAP_AD) {
-                       values = ldap_get_values(ldserver, search_result, "objectGUID");
-                       if (values) {
-                               if (values[0]) {
-                                       if (uid != NULL) {
-                                               *uid = abs(HashLittle(values[0], strlen(values[0])));
-                                               syslog(LOG_DEBUG, "uid hashed from objectGUID = %d", *uid);
+               /* If we know the username is the CN/displayName, we already set the uid*/
+               if (lookup_based_on_username==0) {
+                       if (config.c_auth_mode == AUTHMODE_LDAP_AD) {
+                               values = ldap_get_values(ldserver, search_result, "objectGUID");
+                               if (values) {
+                                       if (values[0]) {
+                                               if (uid != NULL) {
+                                                       *uid = abs(HashLittle(values[0], strlen(values[0])));
+                                                       syslog(LOG_DEBUG, "uid hashed from objectGUID = %d", *uid);
+                                               }
                                        }
+                                       ldap_value_free(values);
                                }
-                               ldap_value_free(values);
                        }
-               }
-               else {
-                       values = ldap_get_values(ldserver, search_result, "uidNumber");
-                       if (values) {
-                               if (values[0]) {
-                                       syslog(LOG_DEBUG, "uidNumber = %s", values[0]);
-                                       if (uid != NULL) {
-                                               *uid = atoi(values[0]);
+                       else {
+                               values = ldap_get_values(ldserver, search_result, "uidNumber");
+                               if (values) {
+                                       if (values[0]) {
+                                               syslog(LOG_DEBUG, "uidNumber = %s", values[0]);
+                                               if (uid != NULL) {
+                                                       *uid = atoi(values[0]);
+                                               }
                                        }
+                                       ldap_value_free(values);
                                }
-                               ldap_value_free(values);
                        }
                }
 
@@ -244,6 +252,7 @@ int vcard_set_props_iff_different(struct vCard *v,char *propname,int numvals, ch
          if (strcmp(vals[i],oldval)) break;
        }
        if (i!=numvals) {
+               syslog(LOG_DEBUG, "LDAP: vcard property %s, element %d of %d changed from %s to %s\n", propname, i, numvals, oldval, vals[i]);
                for(i=0;i<numvals;i++) vcard_set_prop(v,propname,vals[i],(i==0) ? 0 : 1);
                return 1;
        }
@@ -399,7 +408,7 @@ int Ctdl_LDAP_to_vCard(char *ldap_dn, struct vCard *v)
                if (mail) {
                        changed_something |= vcard_set_props_iff_different(v,"email;internet",ldap_count_values(mail),mail);
                }
-               if (uuid) changed_something |= vcard_set_one_prop_iff_different(v,"uid","%s",uuid[0]);
+               if (uuid) changed_something |= vcard_set_one_prop_iff_different(v,"X-uuid","%s",uuid[0]);
                if (o) changed_something |= vcard_set_one_prop_iff_different(v,"org","%s",o[0]);
                if (cn) changed_something |= vcard_set_one_prop_iff_different(v,"fn","%s",cn[0]);
                if (title) changed_something |= vcard_set_one_prop_iff_different(v,"title","%s",title[0]);
index dad28b8dd508f1d2ec7b8832e81eddb6f2b7c367..39820f7762dc7a821609c060995ec6ecb99c77c0 100644 (file)
@@ -441,18 +441,19 @@ int vcard_upload_beforesave(struct CtdlMessage *msg, recptypes *recp) {
                vcard_set_prop(v, "FBURL;PREF", buf, 0);
        }
 
-       /* If the vCard has no UID, then give it one. */
+
        s = vcard_get_prop(v, "UID", 1, 0, 0);
-       if (s == NULL) {
+       if (s == NULL) { /* Note LDAP auth sets UID from the LDAP UUID, use that if it exists. */
+         /* Enforce local UID policy if applicable */
+         if (yes_my_citadel_config) {
+               snprintf(buf, sizeof buf, VCARD_EXT_FORMAT, msg->cm_fields[eAuthor], NODENAME);
+         } else {
+               /* If the vCard has no UID, then give it one. */
                generate_uuid(buf);
-               vcard_set_prop(v, "UID", buf, 0);
-       }
+         }
+         vcard_set_prop(v, "UID", buf, 0);
+    }
 
-       /* Enforce local UID policy if applicable */
-       if (yes_my_citadel_config) {
-               snprintf(buf, sizeof buf, VCARD_EXT_FORMAT, msg->cm_fields[eAuthor], NODENAME);
-               vcard_set_prop(v, "UID", buf, 0);
-       }
 
        /* 
         * Set the EUID of the message to the UID of the vCard.
@@ -849,7 +850,9 @@ void vcard_newuser(struct ctdluser *usbuf) {
        char buf[256];
        int i;
        struct vCard *v;
+       int need_default_vcard;
 
+       need_default_vcard =1;
        vcard_fn_to_n(vname, usbuf->fullname, sizeof vname);
        syslog(LOG_DEBUG, "Converted <%s> to <%s>", usbuf->fullname, vname);
 
@@ -875,16 +878,11 @@ void vcard_newuser(struct ctdluser *usbuf) {
 #endif // HAVE_GETPWUID_R
                        snprintf(buf, sizeof buf, "%s@%s", pwd.pw_name, config.c_fqdn);
                        vcard_add_prop(v, "email;internet", buf);
+                       need_default_vcard=0;
                }
        }
 #endif
 
-       /* Everyone gets an email address based on their display name */
-       snprintf(buf, sizeof buf, "%s@%s", usbuf->fullname, config.c_fqdn);
-       for (i=0; buf[i]; ++i) {
-               if (buf[i] == ' ') buf[i] = '_';
-       }
-       vcard_add_prop(v, "email;internet", buf);
 
 #ifdef HAVE_LDAP
        /*
@@ -892,20 +890,29 @@ void vcard_newuser(struct ctdluser *usbuf) {
         * into the user's vCard.
         */
        if ((config.c_auth_mode == AUTHMODE_LDAP) || (config.c_auth_mode == AUTHMODE_LDAP_AD)) {
-            uid_t ldap_uid;
+            //uid_t ldap_uid;
            int found_user;
             char ldap_cn[512];
             char ldap_dn[512];
-           found_user = CtdlTryUserLDAP(usbuf->fullname, ldap_dn, sizeof ldap_dn, ldap_cn, sizeof ldap_cn, &ldap_uid);
+           found_user = CtdlTryUserLDAP(usbuf->fullname, ldap_dn, sizeof ldap_dn, ldap_cn, sizeof ldap_cn, &usbuf->uid,1);
             if (found_user == 0) {
                if (Ctdl_LDAP_to_vCard(ldap_dn, v)) {
                        /* Allow global address book and internet directory update without login long enough to write this. */
                        CC->vcard_updated_by_ldap++;  /* Otherwise we'll only update the user config. */
+                       need_default_vcard=0;
                        syslog(LOG_DEBUG, "LDAP Created Initial Vcard for %s\n",usbuf->fullname);
                }
            }
        }
 #endif
+       if (need_default_vcard!=0) {
+         /* Everyone gets an email address based on their display name */
+         snprintf(buf, sizeof buf, "%s@%s", usbuf->fullname, config.c_fqdn);
+         for (i=0; buf[i]; ++i) {
+               if (buf[i] == ' ') buf[i] = '_';
+         }
+         vcard_add_prop(v, "email;internet", buf);
+    }
 
        vcard_write_user(usbuf, v);
        vcard_free(v);
index 92cf99e24c8164c65cf316ac6ac59f60afbaa68e..6cce2a15bdf7c8bff110a0d75d794b25a2695aa5 100644 (file)
@@ -594,7 +594,7 @@ int CtdlLoginExistingUser(char *authname, const char *trythisname)
                char ldap_cn[256];
                char ldap_dn[256];
 
-               found_user = CtdlTryUserLDAP(username, ldap_dn, sizeof ldap_dn, ldap_cn, sizeof ldap_cn, &ldap_uid);
+               found_user = CtdlTryUserLDAP(username, ldap_dn, sizeof ldap_dn, ldap_cn, sizeof ldap_cn, &ldap_uid, 0);
                if (found_user != 0) {
                        return login_not_found;
                }
@@ -1122,7 +1122,7 @@ int create_user(const char *newusername, long len, int become_user)
 
 #ifdef HAVE_LDAP
        if ((config.c_auth_mode == AUTHMODE_LDAP) || (config.c_auth_mode == AUTHMODE_LDAP_AD)) {
-               if (CtdlTryUserLDAP(username, NULL, 0, username, sizeof username, &uid) != 0) {
+               if (CtdlTryUserLDAP(username, NULL, 0, username, sizeof username, &uid, 0) != 0) {
                        return(ERROR + NO_SUCH_USER);
                }
        }