/** * Make a compare for every new value we want to store in the * directory with the current values. Great tool for debugging * against invalid syntax in attributes * * \param ld AddressBook resource * \param dn dn for the entry * \param cnt Number of attributes to compare * \param mods LDAPMod structure */ void ldapsvr_compare_attr(LDAP *ld, gchar *dn, gint cnt, LDAPMod *mods[]) { int i, rc; #ifdef OPEN_LDAP_API_AT_LEAST_3000 struct berval val; #endif cm_return_if_fail(ld != NULL || dn != NULL || cnt >= 0 || mods != NULL); for (i = 0; i < cnt; i++) { gchar *value = g_strdup(mods[i]->mod_vals.modv_strvals[0]); if (!value || strcmp(value, "") == 0) value = g_strdup("thisisonlyadummy"); #ifdef OPEN_LDAP_API_AT_LEAST_3000 val.bv_val = value; val.bv_len = strlen(value); rc = ldap_compare_ext_s(ld, dn, mods[i]->mod_type, &val, NULL, NULL); #else /* This is deprecated as of OpenLDAP-2.3.0 */ rc = ldap_compare_s(ld, dn, mods[i]->mod_type, value); #endif g_printerr("ldap_compare for (%s:%s)\" failed[0x%x]: %s\n", mods[i]->mod_type, value, rc, ldaputil_get_error(ld)); g_free(value); } }
/** * Delete contact from LDAP * * \param server AddressBook resource * \param contact GHashTable with object to delete */ void ldapsvr_delete_contact(LdapServer *server, GHashTable *contact) { LDAP *ld = NULL; gchar *dn; int rc; cm_return_if_fail(server != NULL || contact != NULL); ld = ldapsvr_connect(server->control); if (ld == NULL) { clean_up(ld, server, contact); return; } dn = g_hash_table_lookup(contact, "dn"); if (dn == NULL) { clean_up(ld, server, contact); return; } server->retVal = LDAPRC_SUCCESS; rc = ldap_delete_ext_s(ld, dn, NULL, NULL); if (rc) { g_printerr("ldap_modify for dn=%s\" failed[0x%x]: %s\n", dn, rc, ldaputil_get_error(ld)); server->retVal = LDAPRC_NODN; } clean_up(ld, server, contact); }
/** * Deside which kind of operation is required to handle * updating the specified attribute * * \param ld AddressBook resource * \param server Reference to server * \param dn dn for the entry * \param attr Attribute * \param value New value * \return int, return will be LDAP_MOD_ADD, LDAP_MOD_REPLACE, or LDAP_MOD_DELETE */ int ldapsvr_deside_operation(LDAP *ld, LdapServer *server, char *dn, char *attr, char *value) { int rc; gboolean dummy = FALSE; #ifdef OPEN_LDAP_API_AT_LEAST_3000 struct berval val; #endif cm_return_val_if_fail(ld != NULL || server != NULL || dn != NULL || attr != NULL, -1); if (value == NULL) return -1; /* value containing empty string cause invalid syntax. A bug in * the LDAP library? Therefore we add a dummy value */ if (strcmp(value,"") == 0) { value = g_strdup("thisisonlyadummy"); dummy = TRUE; } #ifdef OPEN_LDAP_API_AT_LEAST_3000 val.bv_val = value; val.bv_len = strlen(value); rc = ldap_compare_ext_s(ld, dn, attr, &val, NULL, NULL); #else /* This is deprecated as of OpenLDAP-2.3.0 */ rc = ldap_compare_s(ld, dn, attr, value); #endif debug_print("ldap_compare for (%s:%s)\" error_code[0x%x]: %s\n", attr, value, rc, ldaputil_get_error(ld)); switch (rc) { case LDAP_COMPARE_FALSE: if (dummy) return LDAP_MOD_DELETE; else return LDAP_MOD_REPLACE; case LDAP_COMPARE_TRUE: return -1; case LDAP_NO_SUCH_ATTRIBUTE: return LDAP_MOD_ADD; /* LDAP_INAPPROPRIATE_MATCHING needs extensive testing because I * am not aware off the condition causing this return value! */ case LDAP_INAPPROPRIATE_MATCHING: if (dummy) value = NULL; return ldapsvr_compare_manual_attr(ld, server, dn, attr, value); case LDAP_UNDEFINED_TYPE: return -2; case LDAP_INVALID_SYNTAX: return -2; default: return -2; } }
/** * Connect to LDAP server. * \param qry Query object to process. * \return Error/status code. */ static gint ldapqry_disconnect( LdapQuery *qry ) { gint rc; /* Disconnect */ if( qry->ldap ) { rc = ldap_unbind_ext( qry->ldap, NULL, NULL ); if (rc != LDAP_SUCCESS) { log_error(LOG_PROTOCOL, _("LDAP error (unbind): %d (%s)\n"), rc, ldaputil_get_error(qry->ldap)); } else { log_print(LOG_PROTOCOL, _("LDAP (unbind): successful\n")); } } qry->ldap = NULL; ldapqry_touch( qry ); qry->elapsedTime = qry->touchTime - qry->startTime; return ADDRQUERY_RETVAL(qry); }
/** * Perform the LDAP search, reading LDAP entries into cache. * Note that one LDAP entry can have multiple values for many of its * attributes. If these attributes are E-Mail addresses; these are * broken out into separate address items. For any other attribute, * only the first occurrence is read. * * \param qry Query object to process. * \return Error/status code. */ static gint ldapqry_search_retrieve( LdapQuery *qry ) { LdapControl *ctl; LDAP *ld; LDAPMessage *result = NULL, *e = NULL; char **attribs; gchar *criteria; gboolean searchFlag; gboolean entriesFound; gboolean first; struct timeval timeout; gint rc; AddressCache *cache; GList *listEMail; /* Initialize some variables */ ld = qry->ldap; ctl = qry->control; cache = qry->server->addressCache; timeout.tv_sec = ctl->timeOut; timeout.tv_usec = 0L; entriesFound = FALSE; ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS; /* Define all attributes we are interested in. */ attribs = ldapctl_full_attribute_array( ctl ); /* Create LDAP search string */ criteria = ldapctl_format_criteria( ctl, ADDRQUERY_SEARCHVALUE(qry) ); debug_print("Search criteria ::%s::\n", criteria?criteria:"null"); /* * Execute the search - this step may take some time to complete * depending on network traffic and server response time. */ ADDRQUERY_RETVAL(qry) = LDAPRC_TIMEOUT; rc = ldap_search_ext_s( ld, ctl->baseDN, LDAP_SCOPE_SUBTREE, criteria, attribs, 0, NULL, NULL, &timeout, 0, &result ); debug_print("LDAP ldap_search_ext_s: %d (%s)\n", rc, ldaputil_get_error(ld)); ldapctl_free_attribute_array( attribs ); g_free( criteria ); criteria = NULL; if( rc == LDAP_TIMEOUT ) { log_warning(LOG_PROTOCOL, _("LDAP (search): timeout\n")); return ADDRQUERY_RETVAL(qry); } ADDRQUERY_RETVAL(qry) = LDAPRC_SEARCH; /* Test valid returns */ searchFlag = FALSE; if( rc == LDAP_ADMINLIMIT_EXCEEDED ) { log_warning(LOG_PROTOCOL, _("LDAP (search): server limits exceeded\n")); searchFlag = TRUE; } else if( rc == LDAP_SUCCESS ) { log_print(LOG_PROTOCOL, _("LDAP (search): successful\n")); searchFlag = TRUE; } else if( rc == LDAP_PARTIAL_RESULTS || (result && ldap_count_entries(ld, result) > 0) ) { log_print(LOG_PROTOCOL, _("LDAP (search): successful (partial results)\n")); searchFlag = TRUE; } else { log_error(LOG_PROTOCOL, _("LDAP error (search): %d (%s)\n"), rc, ldaputil_get_error(ld)); return ADDRQUERY_RETVAL(qry); } ADDRQUERY_RETVAL(qry) = LDAPRC_STOP_FLAG; #ifdef G_OS_WIN32 debug_print("Total results are: %lu\n", ldap_count_entries(ld, result)); #else debug_print("Total results are: %d\n", ldap_count_entries(ld, result)); #endif /* Process results */ first = TRUE; while( searchFlag ) { ldapqry_touch( qry ); if( qry->entriesRead >= ctl->maxEntries ) break; /* Test for stop */ if( ldapqry_get_stop_flag( qry ) ) { break; } /* Retrieve entry */ if( first ) { first = FALSE; e = ldap_first_entry( ld, result ); } else { e = ldap_next_entry( ld, e ); } if( e == NULL ) break; entriesFound = TRUE; /* Setup a critical section here */ pthread_mutex_lock( qry->mutexEntry ); /* Process entry */ listEMail = ldapqry_process_single_entry( cache, qry, ld, e ); /* Process callback */ if( qry->callBackEntry ) qry->callBackEntry( qry, ADDRQUERY_ID(qry), listEMail, qry->data ); else g_list_free( listEMail ); pthread_mutex_unlock( qry->mutexEntry ); } /* Free up and disconnect */ ldap_msgfree( result ); if( searchFlag ) { if( entriesFound ) { ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS; } else { ADDRQUERY_RETVAL(qry) = LDAPRC_NOENTRIES; } } return ADDRQUERY_RETVAL(qry); }
/** * Perform the data retrieval for a specific LDAP record. * * \param qry Query object to process. * \return Error/status code. */ static gint ldapqry_locate_retrieve( LdapQuery *qry ) { LdapControl *ctl; LDAP *ld; LDAPMessage *result, *e = NULL; gboolean entriesFound; gboolean first; struct timeval timeout; gint rc; gchar *dn; GList *listValues; /* Initialize some variables */ ld = qry->ldap; ctl = qry->control; dn = ADDRQUERY_SEARCHVALUE(qry); timeout.tv_sec = ctl->timeOut; timeout.tv_usec = 0L; entriesFound = FALSE; /* * Execute the search - this step may take some time to complete * depending on network traffic and server response time. */ ADDRQUERY_RETVAL(qry) = LDAPRC_TIMEOUT; rc = ldap_search_ext_s( ld, dn, LDAP_SCOPE_BASE, CRITERIA_SINGLE, NULL, 0, NULL, NULL, &timeout, 0, &result ); if( rc == LDAP_TIMEOUT ) { return ADDRQUERY_RETVAL(qry); } ADDRQUERY_RETVAL(qry) = LDAPRC_SEARCH; if( rc != LDAP_SUCCESS ) { log_error(LOG_PROTOCOL, _("LDAP error (search): %d (%s)\n"), rc, ldaputil_get_error(ld)); debug_print("LDAP Error: ldap_search_ext_s: %d (%s)\n", rc, ldaputil_get_error(ld)); return ADDRQUERY_RETVAL(qry); } else { log_print(LOG_PROTOCOL, _("LDAP (search): successful\n")); } #ifdef G_OS_WIN32 debug_print("Total results are: %lu\n", ldap_count_entries(ld, result)); #else debug_print("Total results are: %d\n", ldap_count_entries(ld, result)); #endif /* Process results */ ADDRQUERY_RETVAL(qry) = LDAPRC_STOP_FLAG; first = TRUE; while( TRUE ) { ldapqry_touch( qry ); if( qry->entriesRead >= ctl->maxEntries ) break; /* Test for stop */ if( ldapqry_get_stop_flag( qry ) ) { break; } /* Retrieve entry */ if( first ) { first = FALSE; e = ldap_first_entry( ld, result ); } else { e = ldap_next_entry( ld, e ); } if( e == NULL ) break; entriesFound = TRUE; /* Setup a critical section here */ pthread_mutex_lock( qry->mutexEntry ); /* Process entry */ listValues = ldapqry_fetch_attribs( ld, e ); /* Process callback */ if( qry->callBackEntry ) { qry->callBackEntry( qry, ADDRQUERY_ID(qry), listValues, qry->data ); } ldapqry_free_list_name_value( listValues ); listValues = NULL; pthread_mutex_unlock( qry->mutexEntry ); } /* Free up and disconnect */ ldap_msgfree( result ); if( entriesFound ) { ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS; } else { ADDRQUERY_RETVAL(qry) = LDAPRC_NOENTRIES; } return ADDRQUERY_RETVAL(qry); }
/** * Add new contact to LDAP * * \param server AddressBook resource * \param contact GHashTable with object to add */ void ldapsvr_add_contact(LdapServer *server, GHashTable *contact) { gchar *email = NULL, *param = NULL; LDAP *ld = NULL; LDAPMod *mods[MODSIZE]; LDAPMod modarr[7]; gint cnt = 0; char *cn[] = {NULL, NULL}; char *displayName[] = {NULL, NULL}; char *givenName[] = {NULL, NULL}; char **mail = NULL; char *sn[] = {NULL, NULL}; char *org[] = {NULL, NULL}; char *obj[] = {/*"top",*/ "person", "organizationalPerson", "inetOrgPerson", NULL}; int rc=0; GList *node; AttrKeyValue *ou, *commonName; ItemPerson *person; gchar *base_dn; GList *mailList; cm_return_if_fail(server != NULL || contact != NULL); node = g_hash_table_lookup(contact , "mail"); if (node) { EmailKeyValue *newEmail = node->data; email = g_strdup(newEmail->mail); } if (email == NULL) { server->retVal = LDAPRC_NODN; clean_up(ld, server, contact); return; } base_dn = g_strdup_printf("mail=%s,%s", email, server->control->baseDN?server->control->baseDN:"null"); g_free(email); person = ldapsvr_get_contact(server, g_hash_table_lookup(contact , "uid")); person->externalID = g_strdup(base_dn); debug_print("dn: %s\n", base_dn); ld = ldapsvr_connect(server->control); if (ld == NULL) { clean_up(ld, server, contact); debug_print("no ldap found\n"); return; } SETMODS(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "objectClass", obj); cnt++; ou = get_ou(base_dn); if (ou != NULL) { SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, g_strdup(ou->key), org, g_strdup(ou->value)); cnt++; attrkeyvalue_free(ou); } commonName = get_cn(base_dn); if (commonName == NULL) { param = g_hash_table_lookup(contact , "cn"); if (param) { SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "cn", cn, param); } else { clean_up(ld, server, contact); debug_print("no CN found\n"); return; } } else { SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, g_strdup(commonName->key), cn, g_strdup(commonName->value)); cnt++; param = g_hash_table_lookup(contact , "cn"); SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "displayName", displayName, param); g_hash_table_insert(contact, "displayName", param); attrkeyvalue_free(commonName); } cnt++; param = g_hash_table_lookup(contact , "givenName"); if (param) { SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "givenName", givenName, param); cnt++; } mailList = g_hash_table_lookup(contact , "mail"); if (mailList) { char **tmp; tmp = g_malloc(sizeof(*tmp) * (g_list_length(mailList)+1)); mail = tmp; while (mailList) { EmailKeyValue *item = mailList->data; *tmp++ = g_strdup((gchar *) item->mail); mailList = g_list_next(mailList); } *tmp = NULL; SETMODS(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "mail", mail); cnt++; } param = g_hash_table_lookup(contact, "sn"); if (param == NULL) param = g_strdup(N_("Some SN")); SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "sn", sn, param); cnt++; mods[cnt] = NULL; if (debug_get_mode()) { ldapsvr_print_ldapmod(mods); } server->retVal = LDAPRC_SUCCESS; rc = ldap_add_ext_s(ld, base_dn, mods, NULL, NULL); if (rc) { switch (rc) { case LDAP_ALREADY_EXISTS: server->retVal = LDAPRC_ALREADY_EXIST; break; default: g_printerr("ldap_modify for dn=%s\" failed[0x%x]: %s\n", base_dn, rc, ldaputil_get_error(ld)); if (rc == 0x8) server->retVal = LDAPRC_STRONG_AUTH; else server->retVal = LDAPRC_NAMING_VIOLATION; } } ldapsvr_handle_other_attributes(ld, server, base_dn, contact); g_free(base_dn); clean_up(ld, server, contact); }
/** * Deside which other attributes needs updating * * \param ld LDAP resource * \param server AddressBook resource * \param dn dn for the entry * \param contact GHashTable with information for the current contact */ void ldapsvr_handle_other_attributes(LDAP *ld, LdapServer *server, char *dn, GHashTable *contact) { GList *node; gboolean CHECKED_ATTRIBUTE[ATTRIBUTE_SIZE + 1]; LDAPMod *mods[ATTRIBUTE_SIZE + 1]; LDAPMod modarr[ATTRIBUTE_SIZE]; gint cnt = 0; char *attr[ATTRIBUTE_SIZE + 1][2]; int mod_op, rc, i; cm_return_if_fail(server != NULL || dn != NULL || contact != NULL); for (i = 0; i <= ATTRIBUTE_SIZE; i++) { CHECKED_ATTRIBUTE[i] = FALSE; attr[i][0] = attr[i][1] = NULL; } node = g_hash_table_lookup(contact , "attribute"); while (node) { AttrKeyValue *item = node->data; if (item) { int index = get_attribute_index(item->key); if (index >= 0) { debug_print("Found other attribute: %s = %s\n", item->key?item->key:"null", item->value?item->value:"null"); mod_op = ldapsvr_deside_operation(ld, server, dn, item->key, item->value); /* Only consider attributes which we no how to handle. * Set to TRUE in CHECKED_ATTRIBUTE array to indicate no further action */ if (mod_op < 0) { CHECKED_ATTRIBUTE[index] = TRUE; node = g_list_next(node); continue; } if (mod_op == LDAP_MOD_DELETE) { /* Setting param to NULL instructs OpenLDAP to remove any * value stored for this attribute and remove the attribute * completely. Should multiple instances of an attribute be * allowed in the future param is required to have the value * store for the attribute which is going to be deleted */ item->value = NULL; } if (mod_op == LDAP_MOD_REPLACE && strcmp(item->value, "") == 0) { /* Having an empty string is considered a syntax error in * ldap. E.g attributes with empty strings are not allowed * in which case we treate this as a request for deleting * the attribute. */ mod_op = LDAP_MOD_DELETE; item->value = NULL; } if (mod_op == LDAP_MOD_ADD && strcmp(item->value, "") == 0) { /* Adding an empty string is considered a syntax error in * ldap. E.g attributes with empty strings are not allowed * in which case we silently refuse to add this entry */ } else { SETMOD(mods[cnt], modarr[cnt], mod_op, g_strdup(item->key), attr[cnt], g_strdup(item->value)); cnt++; CHECKED_ATTRIBUTE[index] = TRUE; } } } node = g_list_next(node); } char **attribs = ldapctl_full_attribute_array(server->control); for (i = 0; i < ATTRIBUTE_SIZE; i++) { /* Attributes which holds no information are to be removed */ if (CHECKED_ATTRIBUTE[i] == FALSE) { /* Only consider those attributes which is currently part of the search criteria. * If attributes are not part of the search criteria they would seem to hold * no information since their values will not be populated in the GUI */ if (!strcmp(ATTRIBUTE[i], "jpegPhoto")) { debug_print("not updating jpegPhoto\n"); continue; } if (ldapsvr_check_search_attributes(attribs, (char *) ATTRIBUTE[i])) { mod_op = ldapsvr_deside_operation(ld, server, dn, (char *) ATTRIBUTE[i], ""); if (mod_op == LDAP_MOD_DELETE) { SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_DELETE, g_strdup((char *) ATTRIBUTE[i]), attr[cnt], NULL); cnt++; } } } } ldapctl_free_attribute_array(attribs); mods[cnt] = NULL; if (debug_get_mode()) ldapsvr_print_ldapmod(mods); server->retVal = LDAPRC_SUCCESS; rc = ldap_modify_ext_s(ld, dn, mods, NULL, NULL); if (rc) { switch (rc) { case LDAP_ALREADY_EXISTS: server->retVal = LDAPRC_ALREADY_EXIST; break; default: g_printerr("ldap_modify for dn=%s\" failed[0x%x]: %s\n", dn, rc, ldaputil_get_error(ld)); if (rc == 0x8) server->retVal = LDAPRC_STRONG_AUTH; else server->retVal = LDAPRC_NAMING_VIOLATION; } } else { char **attribs = ldapctl_full_attribute_array(server->control); for (i = 0; i < ATTRIBUTE_SIZE; i++) { if (!strcmp(ATTRIBUTE[i], "jpegPhoto")) { debug_print("not updating jpegPhoto\n"); continue; } if (ldapsvr_check_search_attributes(attribs, (char *) ATTRIBUTE[i])) { if (CHECKED_ATTRIBUTE[i] == FALSE) { AddrItemObject *aio = addrcache_get_object(server->addressCache, g_hash_table_lookup(contact , "uid")); ItemPerson *person = (ItemPerson *) aio; addritem_person_remove_attribute(person, (const gchar *) ATTRIBUTE[i]); } } } ldapctl_free_attribute_array(attribs); } }
/** * compare attribute to LDAP in case of LDAP_INAPPROPRIATE_MATCHING * * \param ld AddressBook resource * \param server Reference to server * \param dn dn for the entry * \param attr Attribute * \param value New value * \return int, return will be LDAP_MOD_ADD, LDAP_MOD_REPLACE, or LDAP_MOD_DELETE */ int ldapsvr_compare_manual_attr(LDAP *ld, LdapServer *server, gchar *dn, char *attr, char *value) { LDAPMessage *res, *e = NULL; BerElement *ber; struct berval **vals; int rc; LdapControl *ctl; gchar *filter; gchar *attribute; int retVal = -2, i; AttrKeyValue *mail; cm_return_val_if_fail(ld != NULL || server != NULL || attr != NULL, -1); ctl = server->control; mail = get_mail(dn); if (! mail) return -2; filter = g_strdup_printf("(&(mail=%s)(%s=*))", mail->value, attr); attrkeyvalue_free(mail); if (ctl) { rc = ldap_search_ext_s(ld, ctl->baseDN, LDAP_SCOPE_ONELEVEL, filter, NULL, 0, NULL, NULL, NULL, 0, &res); if (rc) { g_printerr("ldap_search for attr=%s\" failed[0x%x]: %s\n",attr, rc, ldaputil_get_error(ld)); retVal = -2; } else { e = ldap_first_entry(ld, res); /* entry has this attribute */ if (e) { attribute = ldap_first_attribute( ld, e, &ber ); if (attribute) { if (value) { if( ( vals = ldap_get_values_len( ld, e, attr ) ) != NULL ) { for( i = 0; vals[i] != NULL; i++ ) { debug_print("Compare: %s=%s\n", attr, vals[i]->bv_val); /* attribute has same value */ if (strcmp(vals[i]->bv_val, value) == 0) retVal = -1; /* attribute has new value */ else retVal = LDAP_MOD_REPLACE; } } ldap_value_free_len(vals); } else retVal = LDAP_MOD_DELETE; } if( ber != NULL ) { ber_free( ber, 0 ); } ldap_memfree(attribute); } /* entry does not have this attribute */ else { /* Only add if this is a real attribute */ if (value) retVal = LDAP_MOD_ADD; /* This is dummy value used to avoid ldap_compare error */ else retVal = -1; } } } else retVal = -2; g_free(filter); return retVal; }
/** * Update contact to LDAP * * \param server AddressBook resource * \param contact GHashTable with object to update */ void ldapsvr_update_contact(LdapServer *server, GHashTable *contact) { LDAP *ld = NULL; LDAPMod *mods[MODSIZE]; LDAPMod modarr[4]; gint cnt = 0; gchar *param, *dn; Rdn *NoRemove = NULL; char *cn[] = {NULL, NULL}; char *givenName[] = {NULL, NULL}; char **mail = NULL; char *sn[] = {NULL, NULL}; GList *mailList; int mod_op; cm_return_if_fail(server != NULL || contact != NULL); ld = ldapsvr_connect(server->control); if (ld == NULL) { clean_up(ld, server, contact); return; } dn = g_hash_table_lookup(contact, "dn"); if (dn == NULL) { clean_up(ld, server, contact); return; } NoRemove = ldapsvr_modify_dn(contact, dn); if (NoRemove) { /* We are trying to change RDN */ gchar *newRdn = g_strdup_printf("%s=%s", NoRemove->attribute, NoRemove->value); #ifdef OPEN_LDAP_API_AT_LEAST_3000 int rc = ldap_rename_s(ld, dn, newRdn, NULL, 1, NULL, NULL); #else /* This is deprecated as of OpenLDAP-2.3.0 */ int rc = ldap_modrdn2_s(ld, dn, newRdn, 1); #endif if(rc != LDAP_SUCCESS) { if (rc == LDAP_ALREADY_EXISTS) { /* We are messing with a contact with more than one listed email * address and the email we are changing is not the one used for dn */ /* It needs to be able to handle renaming errors to an already defined * dn. For now we just refuse the update. It will be caught later on as * a LDAPRC_NAMING_VIOLATION error. */ } else { g_printerr("Current dn: %s\n", dn); g_printerr("new dn: %s\n", newRdn); g_printerr("LDAP Error(ldap_modrdn2_s) failed[0x%x]: %s\n", rc, ldaputil_get_error(ld)); g_free(newRdn); clean_up(ld, server, contact); return; } } else { ItemPerson *person = g_hash_table_lookup(contact, "person"); g_free(newRdn); dn = g_strdup(NoRemove->new_dn); g_hash_table_replace(contact, "dn", dn); if (person) { g_free(person->externalID); person->externalID = dn; } } } else { server->retVal = LDAPRC_NODN; clean_up(ld, server, contact); return; } param = g_hash_table_lookup(contact , "cn"); mod_op = ldapsvr_deside_operation(ld, server, dn, "displayName", param); if (mod_op >= 0 && (strcmp(param, NoRemove->value) != 0 && strcmp("cn", NoRemove->attribute) != 0)) { if (mod_op == LDAP_MOD_DELETE) { /* Setting param to NULL instructs OpenLDAP to remove any * value stored for this attribute and remove the attribute * completely. Should multiple instances of an attribute be * allowed in the future param is required to have the value * store for the attribute which is going to be deleted */ param = NULL; } if (mod_op == LDAP_MOD_REPLACE && strcmp(param, "") == 0) { /* Having an empty string is considered a syntax error in * ldap. E.g attributes with empty strings are not allowed * in which case we treate this as a request for deleting * the attribute. */ mod_op = LDAP_MOD_DELETE; param = NULL; } if (mod_op == LDAP_MOD_ADD && strcmp(param, "") == 0) { /* Adding an empty string is considered a syntax error in * ldap. E.g attributes with empty strings are not allowed * in which case we silently refuse to add this entry */ } else { SETMOD(mods[cnt], modarr[cnt], mod_op, "displayName", cn, param); cnt++; g_hash_table_insert(contact, "displayName", param); } } param = g_hash_table_lookup(contact , "givenName"); mod_op = ldapsvr_deside_operation(ld, server, dn, "givenName", param); if (mod_op >= 0 && (strcmp(param, NoRemove->value) != 0 && strcmp("givenName", NoRemove->attribute) != 0)) { if (mod_op == LDAP_MOD_DELETE) { /* Setting param to NULL instructs OpenLDAP to remove any * value stored for this attribute and remove the attribute * completely. Should multiple instances of an attribute be * allowed in the future param is required to have the value * store for the attribute which is going to be deleted */ param = NULL; } if (mod_op == LDAP_MOD_REPLACE && strcmp(param, "") == 0) { /* Having an empty string is considered a syntax error in * ldap. E.g attributes with empty strings are not allowed * in which case we treate this as a request for deleting * the attribute. */ mod_op = LDAP_MOD_DELETE; param = NULL; } if (mod_op == LDAP_MOD_ADD && strcmp(param, "") == 0) { /* Adding an empty string is considered a syntax error in * ldap. E.g attributes with empty strings are not allowed * in which case we silently refuse to add this entry */ } else { SETMOD(mods[cnt], modarr[cnt], mod_op, "givenName", givenName, param); cnt++; } } mailList = g_hash_table_lookup(contact , "mail"); if (mailList) { debug_print("# of mail: %d\n", g_list_length(mailList)); if (!(strcmp("mail", NoRemove->attribute) == 0 && g_list_length(mailList) == 1)) { char **tmp; tmp = g_malloc(sizeof(*tmp) * (g_list_length(mailList)+1)); mail = tmp; while (mailList) { EmailKeyValue *item = mailList->data; *tmp++ = g_strdup((gchar *) item->mail); mailList = g_list_next(mailList); } *tmp = NULL; /* * At least one email address is required * in which case it will always be a replace */ SETMODS(mods[cnt], modarr[cnt], LDAP_MOD_REPLACE, "mail", mail); cnt++; } } else { /* * an error condition since at least one email adress * is required. Should never occur though. */ } param = g_hash_table_lookup(contact , "sn"); mod_op = ldapsvr_deside_operation(ld, server, dn, "sn", param); if (mod_op >= 0 && (strcmp(param, NoRemove->value) != 0 && strcmp("sn", NoRemove->attribute) != 0)) { if (mod_op == LDAP_MOD_DELETE) { /* Setting param to NULL instructs OpenLDAP to remove any * value stored for this attribute and remove the attribute * completely. Should multiple instances of an attribute be * allowed in the future param is required to have the value * store for the attribute which is going to be deleted */ param = NULL; } if (mod_op == LDAP_MOD_REPLACE && strcmp(param, "") == 0) { /* Having an empty string is considered a syntax error in * ldap. E.g attributes with empty strings are not allowed * in which case we treate this as a request for deleting * the attribute. */ mod_op = LDAP_MOD_DELETE; param = NULL; } if (mod_op == LDAP_MOD_ADD && strcmp(param, "") == 0) { /* Adding an empty string is considered a syntax error in * ldap. E.g attributes with empty strings are not allowed * in which case we silently refuse to add this entry */ } else { SETMOD(mods[cnt], modarr[cnt], mod_op, "sn", sn, param); cnt++; } } debug_print("newDN: %s\n", dn); if (NoRemove) rdn_free(NoRemove); server->retVal = LDAPRC_SUCCESS; if (cnt > 0) { int rc; mods[cnt] = NULL; rc = ldap_modify_ext_s(ld, dn, mods, NULL, NULL); if (rc) { g_printerr("ldap_modify for dn=%s\" failed[0x%x]: %s\n", dn, rc, ldaputil_get_error(ld)); server->retVal = LDAPRC_NAMING_VIOLATION; } if (mail) g_free(mail); } ldapsvr_handle_other_attributes(ld, server, dn, contact); /* If we do not make changes persistent at this point then changes * will be lost if the user makes new search on the same server since * changes are only present in Claws' internal cache. This issue has to * be solved in addressbook.c since this involves access to structures * which are only accessible in addressbook.c */ clean_up(ld, server, contact); }