2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2003-2007 Michael Rasmussen and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 * Functions necessary to access LDAP servers.
26 * 1) When adding a contact to an empty addressbook from the pop-up menu
27 * when right-clicking on an email address causes claws-mail to crash in
28 * addritem.c line 965. Severity: Show stopper. Solved in 2.9.2cvs17
29 * 2) Updating a contact gets lost if the user makes a new search on the
30 * same LdapServer. Severity: Medium. Solved in 2.9.2cvs17 (patch added to solve 1) also solved this bug)
31 * 3) After adding a new contact the displayName for the contact is empty
32 * until the user makes a reread from the LdapServer. Severity: minor.
33 * Solved in 2.9.2cvs24
43 #include <glib/gi18n.h>
49 #include "ldapupdate.h"
52 #include "addrcache.h"
54 #include "ldapquery.h"
55 #include "ldapserver.h"
58 #include "adbookbase.h"
59 #include "editaddress_other_attributes_ldap.h"
62 * Structure to hold user defined attributes
65 typedef struct _AttrKeyValue AttrKeyValue;
66 struct _AttrKeyValue {
72 * Structure to hold contact information.
73 * Each addressbook will have 0..N contacts.
75 typedef struct _EmailKeyValue EmailKeyValue;
76 struct _EmailKeyValue {
83 * Structure to hold information about RDN.
85 typedef struct _Rdn Rdn;
93 * Retrieve address group item for update.
94 * \param group Group to print.
95 * \param array GHashTAble of item_group, or <i>NULL</i> if none created.
97 void ldapsvr_retrieve_item_group(ItemGroup *group, GHashTable *array) {
98 /* Not implemented in this release */
99 g_return_if_fail(group != NULL);
103 * Create an initial EmailKeyValue structure
104 * \return empty structure
106 EmailKeyValue *emailkeyvalue_create() {
109 buf = g_new0(EmailKeyValue, 1);
117 * Create an initial AttrKeyValue structure
118 * \return empty structure
120 AttrKeyValue *attrkeyvalue_create() {
123 buf = g_new0(AttrKeyValue, 1);
130 * Free created AttrKeyValue structure
131 * \param akv AttrKeyValue structure to free
133 void attrkeyvalue_free(AttrKeyValue *akv) {
147 * Retrieve E-Mail address object for update.
148 * \param item ItemEmail to update.
149 * \return object, or <i>NULL</i> if none created.
151 EmailKeyValue *ldapsvr_retrieve_item_email(ItemEMail *item) {
152 EmailKeyValue *newItem;
153 g_return_val_if_fail(item != NULL, NULL);
154 newItem = emailkeyvalue_create();
155 newItem->alias = g_strdup(ADDRITEM_NAME(item));
156 newItem->mail = g_strdup(item->address);
157 newItem->remarks = g_strdup(item->remarks);
162 * Retrieve user attribute object for update.
163 * \param item UserAttribute to update.
164 * \return object, or <i>NULL</i> if none created.
166 AttrKeyValue *ldapsvr_retrieve_attribute(UserAttribute *item) {
167 AttrKeyValue *newItem;
168 g_return_val_if_fail(item != NULL, NULL);
169 newItem = attrkeyvalue_create();
170 newItem->key = g_strdup(item->name);
171 newItem->value = g_strdup(item->value);
176 * Retrieve person object for update.
177 * \param person ItemPerson to update.
178 * \param array GHashTable with user input.
179 * \return false if update is not needed, or true if update is needed.
181 gboolean ldapsvr_retrieve_item_person(ItemPerson *person, GHashTable *array) {
184 g_return_val_if_fail(person != NULL, FALSE);
185 switch (person->status) {
186 case NONE: return FALSE;
187 case ADD_ENTRY: g_hash_table_insert(array, "status", "new"); break;
188 case UPDATE_ENTRY: g_hash_table_insert(array, "status", "update"); break;
189 case DELETE_ENTRY: g_hash_table_insert(array, "status", "delete"); break;
190 default: g_critical(_("ldapsvr_retrieve_item_person->Unknown status: %d"), person->status);
192 g_hash_table_insert(array, "uid", ADDRITEM_ID(person));
193 g_hash_table_insert(array, "cn", ADDRITEM_NAME(person));
194 g_hash_table_insert(array, "givenName", person->firstName);
195 g_hash_table_insert(array, "sn", person->lastName);
196 g_hash_table_insert(array, "nickName", person->nickName);
197 g_hash_table_insert(array, "dn", person->externalID);
198 node = person->listEMail;
201 EmailKeyValue *newEmail = ldapsvr_retrieve_item_email(node->data);
203 attr = g_list_append(attr, newEmail);
204 node = g_list_next(node);
206 g_hash_table_insert(array, "mail", attr);
207 node = person->listAttrib;
210 AttrKeyValue *newAttr = ldapsvr_retrieve_attribute(node->data);
212 attr = g_list_append(attr, newAttr);
213 node = g_list_next(node);
215 g_hash_table_insert(array, "attribute", attr);
220 * Print contents of contacts hashtable for debug.
221 * This function must be called with g_hash_table_foreach.
222 * \param key Key to process.
223 * \param data Data to process.
224 * \param fd Output stream.
226 void ldapsvr_print_contacts_hashtable(gpointer key, gpointer data, gpointer fd) {
227 gchar *keyName = (gchar *) key;
230 if (g_ascii_strcasecmp("mail", keyName) == 0) {
231 node = (GList *) data;
233 EmailKeyValue *item = node->data;
234 if (debug_get_mode()) {
235 debug_print("\t\talias = %s\n", item->alias);
236 debug_print("\t\tmail = %s\n", item->mail);
237 debug_print("\t\tremarks = %s\n", item->remarks);
240 FILE *stream = (FILE *) fd;
241 fprintf(stream, "\t\talias = %s\n", item->alias);
242 fprintf(stream, "\t\tmail = %s\n", item->mail);
243 fprintf(stream, "\t\tremarks = %s\n", item->remarks);
245 node = g_list_next(node);
248 else if (g_ascii_strcasecmp("attribute", keyName) == 0) {
249 node = (GList *) data;
251 AttrKeyValue *item = node->data;
252 if (debug_get_mode()) {
253 debug_print("\t\t%s = %s\n", item->key, item->value);
256 FILE *stream = (FILE *) fd;
257 fprintf(stream, "\t\t%s = %s\n", item->key, item->value);
259 node = g_list_next(node);
263 if (debug_get_mode())
264 debug_print("\t\t%s = %s\n", keyName, (gchar *) data);
266 FILE *stream = (FILE *) fd;
267 fprintf(stream, "\t\t%s = %s\n", keyName, (gchar *) data);
273 * Free list of changed contacts
275 * \param list List of GHashTable
277 void ldapsvr_free_hashtable(GList *list) {
280 g_hash_table_destroy(tmp->data);
282 tmp = g_list_next(tmp);
289 * Get person object from cache
291 * \param server Resource to LDAP
292 * \param uid PersonID in cache
293 * \return person object, or <i>NULL</i> if fail
295 ItemPerson *ldapsvr_get_contact(LdapServer *server, gchar *uid) {
297 g_return_val_if_fail(server != NULL || uid != NULL, NULL);
298 aio = addrcache_get_object(server->addressCache, uid);
300 if(aio->type == ITEMTYPE_PERSON) {
301 return (ItemPerson *) aio;
308 * Connect to LDAP server.
309 * \param ctl Control object to process.
310 * \return LDAP Resource to LDAP.
312 LDAP *ldapsvr_connect(LdapControl *ctl) {
318 g_return_val_if_fail(ctl != NULL, NULL);
320 uri = g_strdup_printf("ldap%s://%s:%d",
321 ctl->enableSSL?"s":"",
322 ctl->hostName, ctl->port);
323 ldap_initialize(&ld, uri);
329 debug_print("connected to LDAP host %s on port %d\n", ctl->hostName, ctl->port);
333 version = LDAP_VERSION3;
334 rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
335 if (rc == LDAP_OPT_SUCCESS) {
336 ctl->version = LDAP_VERSION3;
339 if (ctl->version == LDAP_VERSION3) {
340 if (ctl->enableTLS && !ctl->enableSSL) {
341 rc = ldap_start_tls_s(ld, NULL, NULL);
343 if (rc != LDAP_SUCCESS) {
344 fprintf(stderr, "LDAP Error(tls): ldap_simple_bind_s: %s\n",
345 ldap_err2string(rc));
352 /* Bind to the server, if required */
354 if (* ctl->bindDN != '\0') {
355 rc = claws_ldap_simple_bind_s(ld, ctl->bindDN, ctl->bindPass);
356 if (rc != LDAP_SUCCESS) {
357 fprintf(stderr, "bindDN: %s, bindPass: %s\n", ctl->bindDN, ctl->bindPass);
358 fprintf(stderr, "LDAP Error(bind): ldap_simple_bind_s: %s\n",
359 ldap_err2string(rc));
368 * Disconnect to LDAP server.
369 * \param ld Resource to LDAP.
371 void ldapsvr_disconnect(LDAP *ld) {
373 g_return_if_fail(ld != NULL);
374 ldap_unbind_ext(ld, NULL, NULL);
378 * Create an initial Rdn structure
380 * \return empty structure
385 buf = g_new0(Rdn, 1);
386 buf->attribute = NULL;
393 * Free a created Rdn structure
394 * \param rdn Structure to free
396 void rdn_free(Rdn *rdn) {
397 if (rdn->attribute) {
398 g_free(rdn->attribute);
399 rdn->attribute = NULL;
414 * update Rdn structure
416 * \param rdn Rdn structure to update
417 * \param head Uniq part of dn
418 * \param tail Common part of dn
420 void update_rdn(Rdn *rdn, gchar *head, gchar *tail) {
421 rdn->value = g_strdup(head);
422 rdn->new_dn = g_strdup_printf("mail=%s%s", head, tail);
426 * Deside if dn needs to be changed
428 * \param hash GHashTable with user input.
429 * \param dn dn for current object
430 * \return Rdn structure
432 Rdn *ldapsvr_modify_dn(GHashTable *hash, gchar *dn) {
434 gchar *pos, *compare;
437 g_return_val_if_fail(hash != NULL || dn != NULL, NULL);
439 pos = g_strstr_len(dn, strlen(dn), "=");
440 compare = g_strndup(dn, pos - dn);
445 rest = g_strstr_len(pos, strlen(pos), ",");
446 val = g_strndup(pos, rest - pos);
453 rdn->value = g_strdup(val);
454 rdn->attribute = g_strdup(compare);
456 if (strcmp("mail", rdn->attribute) == 0) {
457 GList *list = g_hash_table_lookup(hash, rdn->attribute);
459 EmailKeyValue *item = list->data;
460 compare = g_strdup((gchar *) item->mail);
461 if (strcmp(compare, rdn->value) == 0) {
462 update_rdn(rdn, compare, rest);
466 list = g_list_next(list);
468 /* if compare and rdn->attribute are equal then last email removed/empty */
469 if (strcmp(compare, rdn->attribute) != 0) {
470 /* RDN changed. Find new */
471 update_rdn(rdn, compare, rest);
476 /* We cannot remove dn */
483 compare = g_hash_table_lookup(hash, rdn->attribute);
484 /* if compare and rdn->attribute are equal then dn removed/empty */
485 if (strcmp(compare, rdn->attribute) != 0) {
486 update_rdn(rdn, compare, rest);
490 /* We cannot remove dn */
500 * This macro is borrowed from the Balsa project
501 * Creates a LDAPMod structure
503 * \param mods Empty LDAPMod structure
504 * \param modarr Array with values to insert
505 * \param op Operation to perform on LDAP
506 * \param attr Attribute to insert
507 * \param strv Empty array which is NULL terminated
508 * \param val Value for attribute
510 #define SETMOD(mods,modarr,op,attr,strv,val) \
511 do { (mods) = &(modarr); (modarr).mod_type=attr; (modarr).mod_op=op;\
512 (strv)[0]=(val); (modarr).mod_values=strv; \
516 * Creates a LDAPMod structure
518 * \param mods Empty LDAPMod structure
519 * \param modarr Array with values to insert
520 * \param op Operation to perform on LDAP
521 * \param attr Attribute to insert
522 * \param strv Array with values to insert. Must be NULL terminated
524 #define SETMODS(mods,modarr,op,attr,strv) \
525 do { (mods) = &(modarr); (modarr).mod_type=attr; \
526 (modarr).mod_op=op; (modarr).mod_values=strv; \
531 * Clean up, close LDAP connection, and refresh cache
533 * \param ld Resource to LDAP
534 * \param server AddressBook resource
535 * \param contact GHashTable with current changed object
537 void clean_up(LDAP *ld, LdapServer *server, GHashTable *contact) {
539 ldapsvr_get_contact(server, g_hash_table_lookup(contact , "uid"));
542 person->status = NONE;
543 displayName = g_hash_table_lookup(contact, "displayName");
545 person->nickName = g_strdup(displayName);
547 if (server->retVal != LDAPRC_SUCCESS) {
550 addrcache_remove_person(server->addressCache, person);
552 g_critical(N_("ldapsvr_update_book: Could not clean cache\n"));
554 addritem_free_item_person(res);
558 ldapsvr_disconnect(ld);
562 * Get cn attribute from dn
564 * \param dn Distinguesh Name for current object
565 * \return AttrKeyValue, or <i>NULL</i> if none created
567 AttrKeyValue *get_cn(gchar *dn) {
573 g_return_val_if_fail(dn != NULL, NULL);
575 cn = attrkeyvalue_create();
576 start = g_strstr_len(dn, strlen(dn), "cn");
578 attrkeyvalue_free(cn);
581 end = g_strstr_len(start, strlen(start), ",");
582 item = g_strndup(start, end - start);
584 attrkeyvalue_free(cn);
587 key_value = g_strsplit(item, "=", 2);
588 cn->key = g_strdup(key_value[0]);
589 cn->value = g_strdup(key_value[1]);
590 g_strfreev(key_value);
596 * Get mail attribute from dn
598 * \param dn Distinguesh Name for current object
599 * \return AttrKeyValue, or <i>NULL</i> if none created
601 AttrKeyValue *get_mail(gchar *dn) {
607 g_return_val_if_fail(dn != NULL, NULL);
609 mail = attrkeyvalue_create();
610 start = g_strstr_len(dn, strlen(dn), "mail");
612 attrkeyvalue_free(mail);
615 end = g_strstr_len(start, strlen(start), ",");
616 item = g_strndup(start, end - start);
618 attrkeyvalue_free(mail);
621 key_value = g_strsplit(item, "=", 2);
622 mail->key = g_strdup(key_value[0]);
623 mail->value = g_strdup(key_value[1]);
624 g_strfreev(key_value);
630 * Get ou or o attribute from dn
632 * \param dn Distinguesh Name for current object
633 * \return AttrKeyValue, or <i>NULL</i> if none created
635 AttrKeyValue *get_ou(gchar *dn) {
642 g_return_val_if_fail(dn != NULL, NULL);
643 ou = attrkeyvalue_create();
644 start = g_strstr_len(dn, strlen(dn), ",o=");
646 start = g_strstr_len(dn, strlen(dn), ",ou=");
648 attrkeyvalue_free(ou);
652 end = g_strstr_len(start, strlen(start), ",");
653 item = g_strndup(start, end - start);
655 attrkeyvalue_free(ou);
658 key_value = g_strsplit(item, "=", 2);
659 ou->key = g_strdup(key_value[0]);
660 ou->value = g_strdup(key_value[1]);
661 g_strfreev(key_value);
667 * Print the contents of a LDAPMod structure for debuging purposes
669 * \param mods LDAPMod structure
671 void ldapsvr_print_ldapmod(LDAPMod *mods[]) {
675 g_return_if_fail(mods != NULL);
676 fprintf( stderr, "Type\n");
677 for (i = 0; NULL != mods[i]; i++) {
678 LDAPMod *mod = (LDAPMod *) mods[i];
680 switch (mod->mod_op) {
681 case LDAP_MOD_ADD: mod_op = g_strdup("ADD"); break;
682 case LDAP_MOD_REPLACE: mod_op = g_strdup("MODIFY"); break;
683 case LDAP_MOD_DELETE: mod_op = g_strdup("DELETE"); break;
684 default: mod_op = g_strdup("UNKNOWN");
686 fprintf( stderr, "Operation: %s\tType:%s\nValues:\n", mod_op, mod->mod_type);
687 vals = mod->mod_vals.modv_strvals;
689 fprintf( stderr, "\t%s\n", *vals++);
695 * Make a compare for every new value we want to store in the
696 * directory with the current values. Great tool for debugging
697 * against invalid syntax in attributes
699 * \param ld AddressBook resource
700 * \param dn dn for the entry
701 * \param cnt Number of attributes to compare
702 * \param mods LDAPMod structure
704 void ldapsvr_compare_attr(LDAP *ld, gchar *dn, gint cnt, LDAPMod *mods[]) {
707 g_return_if_fail(ld != NULL || dn != NULL || cnt >= 0 || mods != NULL);
708 for (i = 0; i < cnt; i++) {
709 gchar *value = g_strdup(mods[i]->mod_vals.modv_strvals[0]);
710 if (!value || strcmp(value, "") == 0)
711 value = g_strdup("thisisonlyadummy");
712 rc = ldap_compare_s(ld, dn, mods[i]->mod_type, value);
713 fprintf(stderr, "ldap_compare for (%s:%s)\" failed[0x%x]: %s\n",
714 mods[i]->mod_type, value, rc, ldap_err2string(rc));
720 * compare attribute to LDAP in case of LDAP_INAPPROPRIATE_MATCHING
722 * \param ld AddressBook resource
723 * \param server Reference to server
724 * \param dn dn for the entry
725 * \param attr Attribute
726 * \param value New value
727 * \return int, return will be LDAP_MOD_ADD, LDAP_MOD_REPLACE, or LDAP_MOD_DELETE
729 int ldapsvr_compare_manual_attr(LDAP *ld, LdapServer *server, gchar *dn, char *attr, char *value) {
730 LDAPMessage *res, *e = NULL;
732 struct berval **vals;
740 g_return_val_if_fail(ld != NULL || server != NULL || attr != NULL, -1);
741 ctl = server->control;
745 filter = g_strdup_printf("(&(mail=%s)(%s=*))", mail->value, attr);
746 attrkeyvalue_free(mail);
748 rc = ldap_search_s(ld, ctl->baseDN, /*LDAP_SCOPE_SUBTREE*/LDAP_SCOPE_ONELEVEL, filter, NULL, 0, &res);
750 fprintf(stderr, "ldap_search for attr=%s\" failed[0x%x]: %s\n",attr, rc, ldap_err2string(rc));
754 e = ldap_first_entry(ld, res);
755 /* entry has this attribute */
757 attribute = ldap_first_attribute( ld, e, &ber );
760 if( ( vals = ldap_get_values_len( ld, e, attr ) ) != NULL ) {
761 for( i = 0; vals[i] != NULL; i++ ) {
762 debug_print("Compare: %s=%s\n", attr, vals[i]->bv_val);
763 /* attribute has same value */
764 if (strcmp(vals[i]->bv_val, value) == 0)
766 /* attribute has new value */
768 retVal = LDAP_MOD_REPLACE;
771 ldap_value_free_len(vals);
774 retVal = LDAP_MOD_DELETE;
779 ldap_memfree(attribute);
781 /* entry does not have this attribute */
783 /* Only add if this is a real attribute */
785 retVal = LDAP_MOD_ADD;
786 /* This is dummy value used to avoid ldap_compare error */
799 * Deside which kind of operation is required to handle
800 * updating the specified attribute
802 * \param ld AddressBook resource
803 * \param server Reference to server
804 * \param dn dn for the entry
805 * \param attr Attribute
806 * \param value New value
807 * \return int, return will be LDAP_MOD_ADD, LDAP_MOD_REPLACE, or LDAP_MOD_DELETE
809 int ldapsvr_deside_operation(LDAP *ld, LdapServer *server, char *dn, char *attr, char *value) {
811 gboolean dummy = FALSE;
813 g_return_val_if_fail(ld != NULL || server != NULL || dn != NULL || attr != NULL, -1);
816 /* value containing empty string cause invalid syntax. A bug in
817 * the LDAP library? Therefore we add a dummy value
819 if (strcmp(value,"") == 0) {
820 value = g_strdup("thisisonlyadummy");
823 rc = ldap_compare_s(ld, dn, attr, value);
824 debug_print("ldap_compare for (%s:%s)\" error_code[0x%x]: %s\n",
825 attr, value, rc, ldap_err2string(rc));
827 case LDAP_COMPARE_FALSE:
829 return LDAP_MOD_DELETE;
831 return LDAP_MOD_REPLACE;
832 case LDAP_COMPARE_TRUE: return -1;
833 case LDAP_NO_SUCH_ATTRIBUTE: return LDAP_MOD_ADD;
834 /* LDAP_INAPPROPRIATE_MATCHING needs extensive testing because I
835 * am not aware off the condition causing this return value!
837 case LDAP_INAPPROPRIATE_MATCHING:
840 return ldapsvr_compare_manual_attr(ld, server, dn, attr, value);
841 case LDAP_UNDEFINED_TYPE: return -2;
842 case LDAP_INVALID_SYNTAX: return -2;
848 * Check if attribute is part of the current search criteria
850 * \param list Array containing attributes in the current search criteria
851 * \param attr Attribute to check
852 * \result <i>TRUE</i> if attribute is found in the current search criteria
854 gboolean ldapsvr_check_search_attributes(char **list, char *attr) {
856 if (strcmp(*list++, attr) == 0)
863 * Deside which other attributes needs updating
865 * \param ld LDAP resource
866 * \param server AddressBook resource
867 * \param dn dn for the entry
868 * \param contact GHashTable with information for the current contact
870 void ldapsvr_handle_other_attributes(LDAP *ld, LdapServer *server, char *dn, GHashTable *contact) {
872 gboolean CHECKED_ATTRIBUTE[ATTRIBUTE_SIZE];
873 LDAPMod *mods[ATTRIBUTE_SIZE + 1];
874 LDAPMod modarr[ATTRIBUTE_SIZE];
876 char *attr[] = {NULL, NULL};
879 g_return_if_fail(server != NULL || dn != NULL || contact != NULL);
880 for (i = 0; i < ATTRIBUTE_SIZE; i++)
881 CHECKED_ATTRIBUTE[i] = FALSE;
882 node = g_hash_table_lookup(contact , "attribute");
884 AttrKeyValue *item = node->data;
886 int index = get_attribute_index(item->key);
888 debug_print("Found other attribute: %s = %s\n", item->key, item->value);
889 mod_op = ldapsvr_deside_operation(ld, server, dn, item->key, item->value);
890 /* Only consider attributes which we no how to handle.
891 * Set to TRUE in CHECKED_ATTRIBUTE array to indicate no further action
894 CHECKED_ATTRIBUTE[index] = TRUE;
895 node = g_list_next(node);
898 if (mod_op == LDAP_MOD_DELETE) {
899 /* Setting param to NULL instructs OpenLDAP to remove any
900 * value stored for this attribute and remove the attribute
901 * completely. Should multiple instances of an attribute be
902 * allowed in the future param is required to have the value
903 * store for the attribute which is going to be deleted
907 if (mod_op == LDAP_MOD_REPLACE && strcmp(item->value, "") == 0) {
908 /* Having an empty string is considered a syntax error in
909 * ldap. E.g attributes with empty strings are not allowed
910 * in which case we treate this as a request for deleting
913 mod_op = LDAP_MOD_DELETE;
916 if (mod_op == LDAP_MOD_ADD && strcmp(item->value, "") == 0) {
917 /* Adding an empty string is considered a syntax error in
918 * ldap. E.g attributes with empty strings are not allowed
919 * in which case we silently refuse to add this entry
923 SETMOD(mods[cnt], modarr[cnt], mod_op, g_strdup(item->key), attr, g_strdup(item->value));
925 CHECKED_ATTRIBUTE[index] = TRUE;
929 node = g_list_next(node);
931 char **attribs = ldapctl_attribute_array(server->control);
932 for (i = 0; i < ATTRIBUTE_SIZE; i++) {
933 /* Attributes which holds no information are to be removed */
934 if (CHECKED_ATTRIBUTE[i] == FALSE) {
935 /* Only consider those attributes which is currently part of the search criteria.
936 * If attributes are not part of the search criteria they would seem to hold
937 * no information since their values will not be populated in the GUI
939 if (ldapsvr_check_search_attributes(attribs, (char *) ATTRIBUTE[i])) {
940 mod_op = ldapsvr_deside_operation(ld, server, dn, (char *) ATTRIBUTE[i], "");
941 if (mod_op == LDAP_MOD_DELETE) {
942 SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_DELETE, g_strdup((char *) ATTRIBUTE[i]), attr, NULL);
948 ldapctl_free_attribute_array(attribs);
950 if (debug_get_mode())
951 ldapsvr_print_ldapmod(mods);
952 server->retVal = LDAPRC_SUCCESS;
953 rc = ldap_modify_ext_s(ld, dn, mods, NULL, NULL);
956 case LDAP_ALREADY_EXISTS:
957 server->retVal = LDAPRC_ALREADY_EXIST;
960 fprintf(stderr, "ldap_modify for dn=%s\" failed[0x%x]: %s\n",dn, rc, ldap_err2string(rc));
962 server->retVal = LDAPRC_STRONG_AUTH;
964 server->retVal = LDAPRC_NAMING_VIOLATION;
968 /* Only consider those attributes which is currently part of the search criteria.
969 * If attributes are not part of the search criteria they would seem to hold
970 * no information since their values will not be populated in the GUI
972 char **attribs = ldapctl_attribute_array(server->control);
973 for (i = 0; i < ATTRIBUTE_SIZE; i++) {
974 if (ldapsvr_check_search_attributes(attribs, (char *) ATTRIBUTE[i])) {
975 if (CHECKED_ATTRIBUTE[i] == FALSE) {
976 AddrItemObject *aio = addrcache_get_object(server->addressCache, g_hash_table_lookup(contact , "uid"));
977 ItemPerson *person = (ItemPerson *) aio;
978 addritem_person_remove_attribute(person, (const gchar *) ATTRIBUTE[i]);
982 ldapctl_free_attribute_array(attribs);
987 * Add new contact to LDAP
989 * \param server AddressBook resource
990 * \param contact GHashTable with object to add
992 void ldapsvr_add_contact(LdapServer *server, GHashTable *contact) {
993 gchar *email = NULL, *param = NULL;
995 LDAPMod *mods[MODSIZE];
998 char *cn[] = {NULL, NULL};
999 char *displayName[] = {NULL, NULL};
1000 char *givenName[] = {NULL, NULL};
1002 char *sn[] = {NULL, NULL};
1003 char *org[] = {NULL, NULL};
1004 char *obj[] = {/*"top",*/ "person", "organizationalPerson", "inetOrgPerson", NULL};
1007 AttrKeyValue *ou, *commonName;
1012 g_return_if_fail(server != NULL || contact != NULL);
1013 node = g_hash_table_lookup(contact , "mail");
1015 EmailKeyValue *newEmail = node->data;
1016 email = g_strdup(newEmail->mail);
1018 if (email == NULL) {
1019 server->retVal = LDAPRC_NODN;
1020 clean_up(ld, server, contact);
1023 base_dn = g_strdup_printf("mail=%s,%s", email, server->control->baseDN);
1026 ldapsvr_get_contact(server, g_hash_table_lookup(contact , "uid"));
1027 person->externalID = g_strdup(base_dn);
1028 debug_print("dn: %s\n", base_dn);
1029 ld = ldapsvr_connect(server->control);
1031 clean_up(ld, server, contact);
1032 debug_print("no ldap found\n");
1035 SETMODS(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "objectClass", obj);
1037 ou = get_ou(base_dn);
1039 SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, g_strdup(ou->key), org, g_strdup(ou->value));
1041 attrkeyvalue_free(ou);
1044 commonName = get_cn(base_dn);
1045 if (commonName == NULL) {
1046 param = g_hash_table_lookup(contact , "cn");
1048 SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "cn", cn, param);
1051 clean_up(ld, server, contact);
1052 debug_print("no CN found\n");
1057 SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, g_strdup(commonName->key), cn, g_strdup(commonName->value));
1059 param = g_hash_table_lookup(contact , "cn");
1060 SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "displayName", displayName, param);
1061 g_hash_table_insert(contact, "displayName", param);
1062 attrkeyvalue_free(commonName);
1065 param = g_hash_table_lookup(contact , "givenName");
1067 SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "givenName", givenName, param);
1070 mailList = g_hash_table_lookup(contact , "mail");
1073 tmp = g_malloc(sizeof(*tmp) * (g_list_length(mailList)+1));
1076 EmailKeyValue *item = mailList->data;
1077 *tmp++ = g_strdup((gchar *) item->mail);
1078 mailList = g_list_next(mailList);
1081 SETMODS(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "mail", mail);
1084 param = g_hash_table_lookup(contact, "sn");
1086 param = g_strdup(N_("Some SN"));
1087 SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "sn", sn, param);
1090 if (debug_get_mode()) {
1091 ldapsvr_print_ldapmod(mods);
1093 server->retVal = LDAPRC_SUCCESS;
1094 rc = ldap_add_ext_s(ld, base_dn, mods, NULL, NULL);
1097 case LDAP_ALREADY_EXISTS:
1098 server->retVal = LDAPRC_ALREADY_EXIST;
1101 fprintf(stderr, "ldap_modify for dn=%s\" failed[0x%x]: %s\n",base_dn, rc, ldap_err2string(rc));
1103 server->retVal = LDAPRC_STRONG_AUTH;
1105 server->retVal = LDAPRC_NAMING_VIOLATION;
1108 ldapsvr_handle_other_attributes(ld, server, base_dn, contact);
1110 clean_up(ld, server, contact);
1114 * Update contact to LDAP
1116 * \param server AddressBook resource
1117 * \param contact GHashTable with object to update
1119 void ldapsvr_update_contact(LdapServer *server, GHashTable *contact) {
1121 LDAPMod *mods[MODSIZE];
1125 Rdn *NoRemove = NULL;
1126 char *cn[] = {NULL, NULL};
1127 char *givenName[] = {NULL, NULL};
1129 char *sn[] = {NULL, NULL};
1133 g_return_if_fail(server != NULL || contact != NULL);
1134 ld = ldapsvr_connect(server->control);
1136 clean_up(ld, server, contact);
1139 dn = g_hash_table_lookup(contact, "dn");
1141 clean_up(ld, server, contact);
1144 NoRemove = ldapsvr_modify_dn(contact, dn);
1146 /* We are trying to change RDN */
1147 gchar *newRdn = g_strdup_printf("%s=%s", NoRemove->attribute, NoRemove->value);
1148 int rc = ldap_modrdn2_s(ld, dn, newRdn, 1);
1149 if(rc != LDAP_SUCCESS) {
1150 if (rc == LDAP_ALREADY_EXISTS) {
1151 /* We are messing with a contact with more than one listed email
1152 * address and the email we are changing is not the one used for dn
1154 /* It needs to be able to handle renaming errors to an already defined
1155 * dn. For now we just refuse the update. It will be caught later on as
1156 * a LDAPRC_NAMING_VIOLATION error.
1160 fprintf(stderr, "Current dn: %s\n", dn);
1161 fprintf(stderr, "new dn: %s\n", newRdn);
1162 fprintf(stderr, "LDAP Error(ldap_modrdn2_s) failed[0x%x]: %s\n", rc, ldap_err2string(rc));
1164 clean_up(ld, server, contact);
1170 dn = g_strdup(NoRemove->new_dn);
1174 server->retVal = LDAPRC_NODN;
1175 clean_up(ld, server, contact);
1178 param = g_hash_table_lookup(contact , "cn");
1179 mod_op = ldapsvr_deside_operation(ld, server, dn, "displayName", param);
1180 if (mod_op >= 0 && (strcmp(param, NoRemove->value) != 0 && strcmp("cn", NoRemove->attribute) != 0)) {
1181 if (mod_op == LDAP_MOD_DELETE) {
1182 /* Setting param to NULL instructs OpenLDAP to remove any
1183 * value stored for this attribute and remove the attribute
1184 * completely. Should multiple instances of an attribute be
1185 * allowed in the future param is required to have the value
1186 * store for the attribute which is going to be deleted
1190 if (mod_op == LDAP_MOD_REPLACE && strcmp(param, "") == 0) {
1191 /* Having an empty string is considered a syntax error in
1192 * ldap. E.g attributes with empty strings are not allowed
1193 * in which case we treate this as a request for deleting
1196 mod_op = LDAP_MOD_DELETE;
1199 if (mod_op == LDAP_MOD_ADD && strcmp(param, "") == 0) {
1200 /* Adding an empty string is considered a syntax error in
1201 * ldap. E.g attributes with empty strings are not allowed
1202 * in which case we silently refuse to add this entry
1206 SETMOD(mods[cnt], modarr[cnt], mod_op, "displayName", cn, param);
1208 g_hash_table_insert(contact, "displayName", param);
1211 param = g_hash_table_lookup(contact , "givenName");
1212 mod_op = ldapsvr_deside_operation(ld, server, dn, "givenName", param);
1213 if (mod_op >= 0 && (strcmp(param, NoRemove->value) != 0 && strcmp("givenName", NoRemove->attribute) != 0)) {
1214 if (mod_op == LDAP_MOD_DELETE) {
1215 /* Setting param to NULL instructs OpenLDAP to remove any
1216 * value stored for this attribute and remove the attribute
1217 * completely. Should multiple instances of an attribute be
1218 * allowed in the future param is required to have the value
1219 * store for the attribute which is going to be deleted
1223 if (mod_op == LDAP_MOD_REPLACE && strcmp(param, "") == 0) {
1224 /* Having an empty string is considered a syntax error in
1225 * ldap. E.g attributes with empty strings are not allowed
1226 * in which case we treate this as a request for deleting
1229 mod_op = LDAP_MOD_DELETE;
1232 if (mod_op == LDAP_MOD_ADD && strcmp(param, "") == 0) {
1233 /* Adding an empty string is considered a syntax error in
1234 * ldap. E.g attributes with empty strings are not allowed
1235 * in which case we silently refuse to add this entry
1239 SETMOD(mods[cnt], modarr[cnt], mod_op, "givenName", givenName, param);
1243 mailList = g_hash_table_lookup(contact , "mail");
1245 debug_print("# of mail: %d\n", g_list_length(mailList));
1246 if (!(strcmp("mail", NoRemove->attribute) == 0 && g_list_length(mailList) == 1)) {
1248 tmp = g_malloc(sizeof(*tmp) * (g_list_length(mailList)+1));
1251 EmailKeyValue *item = mailList->data;
1252 *tmp++ = g_strdup((gchar *) item->mail);
1253 mailList = g_list_next(mailList);
1257 * At least one email address is required
1258 * in which case it will always be a replace
1260 SETMODS(mods[cnt], modarr[cnt], LDAP_MOD_REPLACE, "mail", mail);
1266 * an error condition since at least one email adress
1267 * is required. Should never occur though.
1270 param = g_hash_table_lookup(contact , "sn");
1271 mod_op = ldapsvr_deside_operation(ld, server, dn, "sn", param);
1272 if (mod_op >= 0 && (strcmp(param, NoRemove->value) != 0 && strcmp("sn", NoRemove->attribute) != 0)) {
1273 if (mod_op == LDAP_MOD_DELETE) {
1274 /* Setting param to NULL instructs OpenLDAP to remove any
1275 * value stored for this attribute and remove the attribute
1276 * completely. Should multiple instances of an attribute be
1277 * allowed in the future param is required to have the value
1278 * store for the attribute which is going to be deleted
1282 if (mod_op == LDAP_MOD_REPLACE && strcmp(param, "") == 0) {
1283 /* Having an empty string is considered a syntax error in
1284 * ldap. E.g attributes with empty strings are not allowed
1285 * in which case we treate this as a request for deleting
1288 mod_op = LDAP_MOD_DELETE;
1291 if (mod_op == LDAP_MOD_ADD && strcmp(param, "") == 0) {
1292 /* Adding an empty string is considered a syntax error in
1293 * ldap. E.g attributes with empty strings are not allowed
1294 * in which case we silently refuse to add this entry
1298 SETMOD(mods[cnt], modarr[cnt], mod_op, "sn", sn, param);
1302 debug_print("newDN: %s\n", dn);
1305 server->retVal = LDAPRC_SUCCESS;
1309 rc = ldap_modify_ext_s(ld, dn, mods, NULL, NULL);
1311 fprintf(stderr, "ldap_modify for dn=%s\" failed[0x%x]: %s\n",
1312 dn, rc, ldap_err2string(rc));
1313 server->retVal = LDAPRC_NAMING_VIOLATION;
1318 ldapsvr_handle_other_attributes(ld, server, dn, contact);
1319 /* If we do not make changes persistent at this point then changes
1320 * will be lost if the user makes new search on the same server since
1321 * changes are only present in Claws' internal cache. This issue has to
1322 * be solved in addressbook.c since this involves access to structures
1323 * which are only accessible in addressbook.c */
1324 clean_up(ld, server, contact);
1328 * Delete contact from LDAP
1330 * \param server AddressBook resource
1331 * \param contact GHashTable with object to delete
1333 void ldapsvr_delete_contact(LdapServer *server, GHashTable *contact) {
1338 g_return_if_fail(server != NULL || contact != NULL);
1339 ld = ldapsvr_connect(server->control);
1341 clean_up(ld, server, contact);
1344 dn = g_hash_table_lookup(contact, "dn");
1346 clean_up(ld, server, contact);
1349 server->retVal = LDAPRC_SUCCESS;
1350 rc = ldap_delete_ext_s(ld, dn, NULL, NULL);
1352 fprintf(stderr, "ldap_modify for dn=%s\" failed[0x%x]: %s\n",
1353 dn, rc, ldap_err2string(rc));
1354 server->retVal = LDAPRC_NODN;
1356 clean_up(ld, server, contact);
1360 * Update any changes to the server.
1362 * \param server AddressBook resource.
1363 * \param person ItemPerson holding user input.
1365 void ldapsvr_update_book(LdapServer *server, ItemPerson *item) {
1367 GHashTable *contact = NULL;
1368 GList *contacts = NULL, *head = NULL;
1370 g_return_if_fail(server != NULL);
1371 debug_print("updating ldap addressbook\n");
1373 contact = g_hash_table_new(g_str_hash, g_str_equal);
1375 gboolean result = ldapsvr_retrieve_item_person(item, contact);
1376 debug_print("Found contact to update: %s\n", result? "Yes" : "No");
1378 if (debug_get_mode()) {
1379 addritem_print_item_person(item, stdout);
1381 contacts = g_list_append(contacts, contact);
1385 ItemFolder *folder = server->addressCache->rootFolder;
1386 node = folder->listFolder;
1389 AddrItemObject *aio = node->data;
1391 if (aio->type == ITEMTYPE_FOLDER) {
1392 ItemFolder *folder = (ItemFolder *) aio;
1393 GList *persons = folder->listPerson;
1395 AddrItemObject *aio = persons->data;
1397 if (aio->type == ITEMTYPE_PERSON) {
1398 ItemPerson *item = (ItemPerson *) aio;
1399 gboolean result = ldapsvr_retrieve_item_person(item, contact);
1400 debug_print("Found contact to update: %s\n", result? "Yes" : "No");
1402 if (debug_get_mode()) {
1403 gchar *uid = g_hash_table_lookup(contact, "uid");
1404 item = ldapsvr_get_contact(server, uid);
1405 addritem_print_item_person(item, stdout);
1407 contacts = g_list_append(contacts, contact);
1411 persons = g_list_next(persons);
1416 fprintf(stderr, "\t\tpid : ???\n");
1418 node = g_list_next(node);
1423 if (debug_get_mode()) {
1425 debug_print("Contacts which must be updated in LDAP:\n");
1427 debug_print("\tContact:\n");
1428 g_hash_table_foreach(contacts->data,
1429 ldapsvr_print_contacts_hashtable, stderr);
1430 contacts = g_list_next(contacts);
1433 if (contacts == NULL)
1437 contact = (GHashTable *) contacts->data;
1438 status = (gchar *) g_hash_table_lookup(contact, "status");
1440 status = g_strdup("NULL");
1441 if (g_ascii_strcasecmp(status, "new") == 0) {
1442 ldapsvr_add_contact(server, contact);
1444 else if (g_ascii_strcasecmp(status, "update") == 0) {
1445 ldapsvr_update_contact(server, contact);
1447 else if (g_ascii_strcasecmp(status, "delete") == 0) {
1448 ldapsvr_delete_contact(server, contact);
1451 g_critical(_("ldapsvr_update_book->Unknown status: %s\n"), status);
1452 contacts = g_list_next(contacts);
1454 ldapsvr_free_hashtable(head);
1457 #endif /* USE_LDAP */