From 7ae9feb654f41173f99e96ba617d018e990da80c Mon Sep 17 00:00:00 2001 From: Wilfried Goesgens Date: Mon, 30 Mar 2015 16:29:58 +0200 Subject: [PATCH] By Harry Coin: 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 | 2 +- citadel/ldap.c | 53 +++++++++++++++++------------- citadel/modules/vcard/serv_vcard.c | 41 +++++++++++++---------- citadel/user_ops.c | 4 +-- 4 files changed, 58 insertions(+), 42 deletions(-) diff --git a/citadel/citadel_ldap.h b/citadel/citadel_ldap.h index 9ec1d9269..9a312795a 100644 --- a/citadel/citadel_ldap.h +++ b/citadel/citadel_ldap.h @@ -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); diff --git a/citadel/ldap.c b/citadel/ldap.c index 6fd3fd309..f7f415a8a 100644 --- a/citadel/ldap.c +++ b/citadel/ldap.c @@ -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;icm_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); diff --git a/citadel/user_ops.c b/citadel/user_ops.c index 92cf99e24..6cce2a15b 100644 --- a/citadel/user_ops.c +++ b/citadel/user_ops.c @@ -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); } } -- 2.30.2