2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2003-2012 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 3 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, see <http://www.gnu.org/licenses/>.
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
38 #include "claws-features.h"
44 #include <glib/gi18n.h>
48 #include "ldapupdate.h"
51 #include "addrcache.h"
53 #include "ldapquery.h"
54 #include "ldapserver.h"
57 #include "adbookbase.h"
58 #include "editaddress_other_attributes_ldap.h"
61 * Structure to hold user defined attributes
64 typedef struct _AttrKeyValue AttrKeyValue
;
65 struct _AttrKeyValue
{
71 * Structure to hold contact information.
72 * Each addressbook will have 0..N contacts.
74 typedef struct _EmailKeyValue EmailKeyValue
;
75 struct _EmailKeyValue
{
82 * Structure to hold information about RDN.
84 typedef struct _Rdn Rdn
;
92 * Retrieve address group item for update.
93 * \param group Group to print.
94 * \param array GHashTAble of item_group, or <i>NULL</i> if none created.
96 void ldapsvr_retrieve_item_group(ItemGroup
*group
, GHashTable
*array
) {
97 /* Not implemented in this release */
98 cm_return_if_fail(group
!= NULL
);
102 * Create an initial EmailKeyValue structure
103 * \return empty structure
105 EmailKeyValue
*emailkeyvalue_create() {
108 buf
= g_new0(EmailKeyValue
, 1);
116 * Create an initial AttrKeyValue structure
117 * \return empty structure
119 AttrKeyValue
*attrkeyvalue_create() {
122 buf
= g_new0(AttrKeyValue
, 1);
129 * Free created AttrKeyValue structure
130 * \param akv AttrKeyValue structure to free
132 void attrkeyvalue_free(AttrKeyValue
*akv
) {
146 * Retrieve E-Mail address object for update.
147 * \param item ItemEmail to update.
148 * \return object, or <i>NULL</i> if none created.
150 EmailKeyValue
*ldapsvr_retrieve_item_email(ItemEMail
*item
) {
151 EmailKeyValue
*newItem
;
152 cm_return_val_if_fail(item
!= NULL
, NULL
);
153 newItem
= emailkeyvalue_create();
154 newItem
->alias
= g_strdup(ADDRITEM_NAME(item
));
155 newItem
->mail
= g_strdup(item
->address
);
156 newItem
->remarks
= g_strdup(item
->remarks
);
161 * Retrieve user attribute object for update.
162 * \param item UserAttribute to update.
163 * \return object, or <i>NULL</i> if none created.
165 AttrKeyValue
*ldapsvr_retrieve_attribute(UserAttribute
*item
) {
166 AttrKeyValue
*newItem
;
167 cm_return_val_if_fail(item
!= NULL
, NULL
);
168 newItem
= attrkeyvalue_create();
169 newItem
->key
= g_strdup(item
->name
);
170 newItem
->value
= g_strdup(item
->value
);
175 * Retrieve person object for update.
176 * \param person ItemPerson to update.
177 * \param array GHashTable with user input.
178 * \return false if update is not needed, or true if update is needed.
180 gboolean
ldapsvr_retrieve_item_person(ItemPerson
*person
, GHashTable
*array
) {
183 cm_return_val_if_fail(person
!= NULL
, FALSE
);
184 switch (person
->status
) {
185 case NONE
: return FALSE
;
186 case ADD_ENTRY
: g_hash_table_insert(array
, "status", "new"); break;
187 case UPDATE_ENTRY
: g_hash_table_insert(array
, "status", "update"); break;
188 case DELETE_ENTRY
: g_hash_table_insert(array
, "status", "delete"); break;
189 default: g_critical("ldapsvr_retrieve_item_person->Unknown status: %d", person
->status
);
191 g_hash_table_insert(array
, "uid", ADDRITEM_ID(person
));
192 g_hash_table_insert(array
, "cn", ADDRITEM_NAME(person
));
193 g_hash_table_insert(array
, "givenName", person
->firstName
);
194 g_hash_table_insert(array
, "sn", person
->lastName
);
195 g_hash_table_insert(array
, "nickName", person
->nickName
);
196 g_hash_table_insert(array
, "dn", person
->externalID
);
197 g_hash_table_insert(array
, "person", person
);
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
?item
->alias
:"null");
236 debug_print("\t\tmail = %s\n", item
->mail
?item
->mail
:"null");
237 debug_print("\t\tremarks = %s\n", item
->remarks
?item
->remarks
:"null");
240 FILE *stream
= (FILE *) fd
;
241 fprintf(stream
, "\t\talias = %s\n", item
->alias
?item
->alias
:"null");
242 fprintf(stream
, "\t\tmail = %s\n", item
->mail
?item
->mail
:"null");
243 fprintf(stream
, "\t\tremarks = %s\n", item
->remarks
?item
->remarks
:"null");
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
->key
:"null",
254 item
->value
?item
->value
:"null");
257 FILE *stream
= (FILE *) fd
;
258 fprintf(stream
, "\t\t%s = %s\n", item
->key
?item
->key
:"null",
259 item
->value
?item
->value
:"null");
261 node
= g_list_next(node
);
265 if (debug_get_mode())
266 debug_print("\t\t%s = %s\n", keyName
?keyName
:"null", data
?(gchar
*)data
:"null");
268 FILE *stream
= (FILE *) fd
;
269 fprintf(stream
, "\t\t%s = %s\n", keyName
?keyName
:"null", data
?(gchar
*)data
:"null");
275 * Free list of changed contacts
277 * \param list List of GHashTable
279 void ldapsvr_free_hashtable(GList
*list
) {
282 g_hash_table_destroy(tmp
->data
);
284 tmp
= g_list_next(tmp
);
291 * Get person object from cache
293 * \param server Resource to LDAP
294 * \param uid PersonID in cache
295 * \return person object, or <i>NULL</i> if fail
297 ItemPerson
*ldapsvr_get_contact(LdapServer
*server
, gchar
*uid
) {
299 cm_return_val_if_fail(server
!= NULL
|| uid
!= NULL
, NULL
);
300 aio
= addrcache_get_object(server
->addressCache
, uid
);
302 if(aio
->type
== ITEMTYPE_PERSON
) {
303 return (ItemPerson
*) aio
;
310 * Create an initial Rdn structure
312 * \return empty structure
317 buf
= g_new0(Rdn
, 1);
318 buf
->attribute
= NULL
;
325 * Free a created Rdn structure
326 * \param rdn Structure to free
328 void rdn_free(Rdn
*rdn
) {
329 if (rdn
->attribute
) {
330 g_free(rdn
->attribute
);
331 rdn
->attribute
= NULL
;
346 * update Rdn structure
348 * \param rdn Rdn structure to update
349 * \param head Uniq part of dn
350 * \param tail Common part of dn
352 void update_rdn(Rdn
*rdn
, gchar
*head
, gchar
*tail
) {
353 rdn
->value
= g_strdup(head
);
354 rdn
->new_dn
= g_strdup_printf("%s=%s%s", rdn
->attribute
, head
, tail
);
358 * Deside if dn needs to be changed
360 * \param hash GHashTable with user input.
361 * \param dn dn for current object
362 * \return Rdn structure
364 Rdn
*ldapsvr_modify_dn(GHashTable
*hash
, gchar
*dn
) {
366 gchar
*pos
, *compare
;
369 cm_return_val_if_fail(hash
!= NULL
|| dn
!= NULL
, NULL
);
371 pos
= g_strstr_len(dn
, strlen(dn
), "=");
375 compare
= g_strndup(dn
, pos
- dn
);
378 rest
= g_strstr_len(pos
, strlen(pos
), ",");
379 val
= g_strndup(pos
, rest
- pos
);
387 rdn
->attribute
= compare
;
389 if (strcmp("mail", rdn
->attribute
) == 0) {
390 GList
*list
= g_hash_table_lookup(hash
, rdn
->attribute
);
392 EmailKeyValue
*item
= list
->data
;
393 compare
= (gchar
*) item
->mail
;
394 if (strcmp(compare
, rdn
->value
) == 0) {
395 update_rdn(rdn
, compare
, rest
);
398 list
= g_list_next(list
);
400 /* if compare and rdn->attribute are equal then last email removed/empty */
401 if (strcmp(compare
, rdn
->attribute
) != 0) {
402 /* RDN changed. Find new */
403 update_rdn(rdn
, compare
, rest
);
408 compare
= g_hash_table_lookup(hash
, rdn
->attribute
);
409 /* if compare and rdn->attribute are equal then dn removed/empty */
410 if (compare
!= NULL
&& strcmp(compare
, rdn
->attribute
) != 0) {
411 update_rdn(rdn
, compare
, rest
);
420 * This macro is borrowed from the Balsa project
421 * Creates a LDAPMod structure
423 * \param mods Empty LDAPMod structure
424 * \param modarr Array with values to insert
425 * \param op Operation to perform on LDAP
426 * \param attr Attribute to insert
427 * \param strv Empty array which is NULL terminated
428 * \param val Value for attribute
430 #define SETMOD(mods,modarr,op,attr,strv,val) \
431 do { (mods) = &(modarr); (modarr).mod_type=attr; (modarr).mod_op=op;\
432 (strv)[0]=(val); (modarr).mod_values=strv; \
436 * Creates a LDAPMod structure
438 * \param mods Empty LDAPMod structure
439 * \param modarr Array with values to insert
440 * \param op Operation to perform on LDAP
441 * \param attr Attribute to insert
442 * \param strv Array with values to insert. Must be NULL terminated
444 #define SETMODS(mods,modarr,op,attr,strv) \
445 do { (mods) = &(modarr); (modarr).mod_type=attr; \
446 (modarr).mod_op=op; (modarr).mod_values=strv; \
451 * Clean up, close LDAP connection, and refresh cache
453 * \param ld Resource to LDAP
454 * \param server AddressBook resource
455 * \param contact GHashTable with current changed object
457 void clean_up(LDAP
*ld
, LdapServer
*server
, GHashTable
*contact
) {
459 ldapsvr_get_contact(server
, g_hash_table_lookup(contact
, "uid"));
462 person
->status
= NONE
;
463 displayName
= g_hash_table_lookup(contact
, "displayName");
465 person
->nickName
= g_strdup(displayName
);
467 if (server
->retVal
!= LDAPRC_SUCCESS
) {
470 addrcache_remove_person(server
->addressCache
, person
);
472 g_critical("ldapsvr_update_book: Could not clean cache\n");
474 addritem_free_item_person(res
);
478 ldapsvr_disconnect(ld
);
482 * Get cn attribute from dn
484 * \param dn Distinguesh Name for current object
485 * \return AttrKeyValue, or <i>NULL</i> if none created
487 AttrKeyValue
*get_cn(gchar
*dn
) {
493 cm_return_val_if_fail(dn
!= NULL
, NULL
);
495 cn
= attrkeyvalue_create();
496 start
= g_strstr_len(dn
, strlen(dn
), "cn");
498 attrkeyvalue_free(cn
);
501 end
= g_strstr_len(start
, strlen(start
), ",");
502 item
= g_strndup(start
, end
- start
);
504 attrkeyvalue_free(cn
);
507 key_value
= g_strsplit(item
, "=", 2);
508 cn
->key
= g_strdup(key_value
[0]);
509 cn
->value
= g_strdup(key_value
[1]);
510 g_strfreev(key_value
);
516 * Get mail attribute from dn
518 * \param dn Distinguesh Name for current object
519 * \return AttrKeyValue, or <i>NULL</i> if none created
521 AttrKeyValue
*get_mail(gchar
*dn
) {
527 cm_return_val_if_fail(dn
!= NULL
, NULL
);
529 mail
= attrkeyvalue_create();
530 start
= g_strstr_len(dn
, strlen(dn
), "mail");
532 attrkeyvalue_free(mail
);
535 end
= g_strstr_len(start
, strlen(start
), ",");
536 item
= g_strndup(start
, end
- start
);
538 attrkeyvalue_free(mail
);
541 key_value
= g_strsplit(item
, "=", 2);
542 mail
->key
= g_strdup(key_value
[0]);
543 mail
->value
= g_strdup(key_value
[1]);
544 g_strfreev(key_value
);
550 * Get ou or o attribute from dn
552 * \param dn Distinguesh Name for current object
553 * \return AttrKeyValue, or <i>NULL</i> if none created
555 AttrKeyValue
*get_ou(gchar
*dn
) {
562 cm_return_val_if_fail(dn
!= NULL
, NULL
);
563 ou
= attrkeyvalue_create();
564 start
= g_strstr_len(dn
, strlen(dn
), ",o=");
566 start
= g_strstr_len(dn
, strlen(dn
), ",ou=");
568 attrkeyvalue_free(ou
);
572 end
= g_strstr_len(start
, strlen(start
), ",");
573 item
= g_strndup(start
, end
- start
);
575 attrkeyvalue_free(ou
);
578 key_value
= g_strsplit(item
, "=", 2);
579 ou
->key
= g_strdup(key_value
[0]);
580 ou
->value
= g_strdup(key_value
[1]);
581 g_strfreev(key_value
);
587 * Print the contents of a LDAPMod structure for debuging purposes
589 * \param mods LDAPMod structure
591 void ldapsvr_print_ldapmod(LDAPMod
*mods
[]) {
595 cm_return_if_fail(mods
!= NULL
);
596 g_printerr( "Type\n");
597 for (i
= 0; NULL
!= mods
[i
]; i
++) {
598 LDAPMod
*mod
= (LDAPMod
*) mods
[i
];
600 switch (mod
->mod_op
) {
601 case LDAP_MOD_ADD
: mod_op
= g_strdup("ADD"); break;
602 case LDAP_MOD_REPLACE
: mod_op
= g_strdup("MODIFY"); break;
603 case LDAP_MOD_DELETE
: mod_op
= g_strdup("DELETE"); break;
604 default: mod_op
= g_strdup("UNKNOWN");
606 g_printerr( "Operation: %s\tType:%s\nValues:\n", mod_op
, mod
->mod_type
);
607 vals
= mod
->mod_vals
.modv_strvals
;
609 g_printerr( "\t%s\n", *vals
++);
615 * Make a compare for every new value we want to store in the
616 * directory with the current values. Great tool for debugging
617 * against invalid syntax in attributes
619 * \param ld AddressBook resource
620 * \param dn dn for the entry
621 * \param cnt Number of attributes to compare
622 * \param mods LDAPMod structure
624 void ldapsvr_compare_attr(LDAP
*ld
, gchar
*dn
, gint cnt
, LDAPMod
*mods
[]) {
627 #ifdef OPEN_LDAP_API_AT_LEAST_3000
633 cm_return_if_fail(ld
!= NULL
|| dn
!= NULL
|| cnt
>= 0 || mods
!= NULL
);
634 for (i
= 0; i
< cnt
; i
++) {
635 gchar
*value
= g_strdup(mods
[i
]->mod_vals
.modv_strvals
[0]);
636 if (!value
|| strcmp(value
, "") == 0)
637 value
= g_strdup("thisisonlyadummy");
639 #ifdef OPEN_LDAP_API_AT_LEAST_3000
642 val
.bv_len
= strlen(value
);
644 rc
= ldap_compare_ext_s(ld
, dn
, mods
[i
]->mod_type
, &val
, NULL
, NULL
);
648 /* This is deprecated as of OpenLDAP-2.3.0 */
649 rc
= ldap_compare_s(ld
, dn
, mods
[i
]->mod_type
, value
);
653 g_printerr("ldap_compare for (%s:%s)\" failed[0x%x]: %s\n",
654 mods
[i
]->mod_type
, value
, rc
, ldaputil_get_error(ld
));
660 * compare attribute to LDAP in case of LDAP_INAPPROPRIATE_MATCHING
662 * \param ld AddressBook resource
663 * \param server Reference to server
664 * \param dn dn for the entry
665 * \param attr Attribute
666 * \param value New value
667 * \return int, return will be LDAP_MOD_ADD, LDAP_MOD_REPLACE, or LDAP_MOD_DELETE
669 int ldapsvr_compare_manual_attr(LDAP
*ld
, LdapServer
*server
, gchar
*dn
, char *attr
, char *value
) {
670 LDAPMessage
*res
, *e
= NULL
;
672 struct berval
**vals
;
680 cm_return_val_if_fail(ld
!= NULL
|| server
!= NULL
|| attr
!= NULL
, -1);
681 ctl
= server
->control
;
685 filter
= g_strdup_printf("(&(mail=%s)(%s=*))", mail
->value
, attr
);
686 attrkeyvalue_free(mail
);
689 rc
= ldap_search_ext_s(ld
, ctl
->baseDN
, LDAP_SCOPE_ONELEVEL
, filter
, NULL
, 0, NULL
, NULL
, NULL
, 0, &res
);
692 g_printerr("ldap_search for attr=%s\" failed[0x%x]: %s\n",attr
, rc
, ldaputil_get_error(ld
));
696 e
= ldap_first_entry(ld
, res
);
697 /* entry has this attribute */
699 attribute
= ldap_first_attribute( ld
, e
, &ber
);
702 if( ( vals
= ldap_get_values_len( ld
, e
, attr
) ) != NULL
) {
703 for( i
= 0; vals
[i
] != NULL
; i
++ ) {
704 debug_print("Compare: %s=%s\n", attr
, vals
[i
]->bv_val
);
705 /* attribute has same value */
706 if (strcmp(vals
[i
]->bv_val
, value
) == 0)
708 /* attribute has new value */
710 retVal
= LDAP_MOD_REPLACE
;
713 ldap_value_free_len(vals
);
716 retVal
= LDAP_MOD_DELETE
;
721 ldap_memfree(attribute
);
723 /* entry does not have this attribute */
725 /* Only add if this is a real attribute */
727 retVal
= LDAP_MOD_ADD
;
728 /* This is dummy value used to avoid ldap_compare error */
741 * Deside which kind of operation is required to handle
742 * updating the specified attribute
744 * \param ld AddressBook resource
745 * \param server Reference to server
746 * \param dn dn for the entry
747 * \param attr Attribute
748 * \param value New value
749 * \return int, return will be LDAP_MOD_ADD, LDAP_MOD_REPLACE, or LDAP_MOD_DELETE
751 int ldapsvr_deside_operation(LDAP
*ld
, LdapServer
*server
, char *dn
, char *attr
, char *value
) {
753 gboolean dummy
= FALSE
;
755 #ifdef OPEN_LDAP_API_AT_LEAST_3000
761 cm_return_val_if_fail(ld
!= NULL
|| server
!= NULL
|| dn
!= NULL
|| attr
!= NULL
, -1);
764 /* value containing empty string cause invalid syntax. A bug in
765 * the LDAP library? Therefore we add a dummy value
767 if (strcmp(value
,"") == 0) {
768 value
= g_strdup("thisisonlyadummy");
772 #ifdef OPEN_LDAP_API_AT_LEAST_3000
775 val
.bv_len
= strlen(value
);
777 rc
= ldap_compare_ext_s(ld
, dn
, attr
, &val
, NULL
, NULL
);
781 /* This is deprecated as of OpenLDAP-2.3.0 */
782 rc
= ldap_compare_s(ld
, dn
, attr
, value
);
786 debug_print("ldap_compare for (%s:%s)\" error_code[0x%x]: %s\n",
787 attr
, value
, rc
, ldaputil_get_error(ld
));
789 case LDAP_COMPARE_FALSE
:
791 return LDAP_MOD_DELETE
;
793 return LDAP_MOD_REPLACE
;
794 case LDAP_COMPARE_TRUE
: return -1;
795 case LDAP_NO_SUCH_ATTRIBUTE
: return LDAP_MOD_ADD
;
796 /* LDAP_INAPPROPRIATE_MATCHING needs extensive testing because I
797 * am not aware off the condition causing this return value!
799 case LDAP_INAPPROPRIATE_MATCHING
:
802 return ldapsvr_compare_manual_attr(ld
, server
, dn
, attr
, value
);
803 case LDAP_UNDEFINED_TYPE
: return -2;
804 case LDAP_INVALID_SYNTAX
: return -2;
810 * Check if attribute is part of the current search criteria
812 * \param list Array containing attributes in the current search criteria
813 * \param attr Attribute to check
814 * \result <i>TRUE</i> if attribute is found in the current search criteria
816 gboolean
ldapsvr_check_search_attributes(char **list
, char *attr
) {
818 if (strcmp(*list
++, attr
) == 0)
825 * Deside which other attributes needs updating
827 * \param ld LDAP resource
828 * \param server AddressBook resource
829 * \param dn dn for the entry
830 * \param contact GHashTable with information for the current contact
832 void ldapsvr_handle_other_attributes(LDAP
*ld
, LdapServer
*server
, char *dn
, GHashTable
*contact
) {
834 gboolean CHECKED_ATTRIBUTE
[ATTRIBUTE_SIZE
+ 1];
835 LDAPMod
*mods
[ATTRIBUTE_SIZE
+ 1];
836 LDAPMod modarr
[ATTRIBUTE_SIZE
];
838 char *attr
[ATTRIBUTE_SIZE
+ 1][2];
841 cm_return_if_fail(server
!= NULL
|| dn
!= NULL
|| contact
!= NULL
);
842 for (i
= 0; i
<= ATTRIBUTE_SIZE
; i
++) {
843 CHECKED_ATTRIBUTE
[i
] = FALSE
;
844 attr
[i
][0] = attr
[i
][1] = NULL
;
846 node
= g_hash_table_lookup(contact
, "attribute");
848 AttrKeyValue
*item
= node
->data
;
850 int index
= get_attribute_index(item
->key
);
852 debug_print("Found other attribute: %s = %s\n",
853 item
->key
?item
->key
:"null", item
->value
?item
->value
:"null");
854 mod_op
= ldapsvr_deside_operation(ld
, server
, dn
, item
->key
, item
->value
);
855 /* Only consider attributes which we no how to handle.
856 * Set to TRUE in CHECKED_ATTRIBUTE array to indicate no further action
859 CHECKED_ATTRIBUTE
[index
] = TRUE
;
860 node
= g_list_next(node
);
863 if (mod_op
== LDAP_MOD_DELETE
) {
864 /* Setting param to NULL instructs OpenLDAP to remove any
865 * value stored for this attribute and remove the attribute
866 * completely. Should multiple instances of an attribute be
867 * allowed in the future param is required to have the value
868 * store for the attribute which is going to be deleted
872 if (mod_op
== LDAP_MOD_REPLACE
&& strcmp(item
->value
, "") == 0) {
873 /* Having an empty string is considered a syntax error in
874 * ldap. E.g attributes with empty strings are not allowed
875 * in which case we treate this as a request for deleting
878 mod_op
= LDAP_MOD_DELETE
;
881 if (mod_op
== LDAP_MOD_ADD
&& strcmp(item
->value
, "") == 0) {
882 /* Adding an empty string is considered a syntax error in
883 * ldap. E.g attributes with empty strings are not allowed
884 * in which case we silently refuse to add this entry
888 SETMOD(mods
[cnt
], modarr
[cnt
], mod_op
, g_strdup(item
->key
), attr
[cnt
], g_strdup(item
->value
));
890 CHECKED_ATTRIBUTE
[index
] = TRUE
;
894 node
= g_list_next(node
);
896 char **attribs
= ldapctl_full_attribute_array(server
->control
);
897 for (i
= 0; i
< ATTRIBUTE_SIZE
; i
++) {
898 /* Attributes which holds no information are to be removed */
899 if (CHECKED_ATTRIBUTE
[i
] == FALSE
) {
900 /* Only consider those attributes which is currently part of the search criteria.
901 * If attributes are not part of the search criteria they would seem to hold
902 * no information since their values will not be populated in the GUI
904 if (!strcmp(ATTRIBUTE
[i
], "jpegPhoto")) {
905 debug_print("not updating jpegPhoto\n");
908 if (ldapsvr_check_search_attributes(attribs
, (char *) ATTRIBUTE
[i
])) {
909 mod_op
= ldapsvr_deside_operation(ld
, server
, dn
, (char *) ATTRIBUTE
[i
], "");
910 if (mod_op
== LDAP_MOD_DELETE
) {
911 SETMOD(mods
[cnt
], modarr
[cnt
], LDAP_MOD_DELETE
, g_strdup((char *) ATTRIBUTE
[i
]), attr
[cnt
], NULL
);
917 ldapctl_free_attribute_array(attribs
);
919 if (debug_get_mode())
920 ldapsvr_print_ldapmod(mods
);
921 server
->retVal
= LDAPRC_SUCCESS
;
922 rc
= ldap_modify_ext_s(ld
, dn
, mods
, NULL
, NULL
);
925 case LDAP_ALREADY_EXISTS
:
926 server
->retVal
= LDAPRC_ALREADY_EXIST
;
929 g_printerr("ldap_modify for dn=%s\" failed[0x%x]: %s\n", dn
, rc
, ldaputil_get_error(ld
));
931 server
->retVal
= LDAPRC_STRONG_AUTH
;
933 server
->retVal
= LDAPRC_NAMING_VIOLATION
;
937 char **attribs
= ldapctl_full_attribute_array(server
->control
);
938 for (i
= 0; i
< ATTRIBUTE_SIZE
; i
++) {
939 if (!strcmp(ATTRIBUTE
[i
], "jpegPhoto")) {
940 debug_print("not updating jpegPhoto\n");
943 if (ldapsvr_check_search_attributes(attribs
, (char *) ATTRIBUTE
[i
])) {
944 if (CHECKED_ATTRIBUTE
[i
] == FALSE
) {
945 AddrItemObject
*aio
= addrcache_get_object(server
->addressCache
, g_hash_table_lookup(contact
, "uid"));
946 ItemPerson
*person
= (ItemPerson
*) aio
;
947 addritem_person_remove_attribute(person
, (const gchar
*) ATTRIBUTE
[i
]);
951 ldapctl_free_attribute_array(attribs
);
956 * Add new contact to LDAP
958 * \param server AddressBook resource
959 * \param contact GHashTable with object to add
961 void ldapsvr_add_contact(LdapServer
*server
, GHashTable
*contact
) {
962 gchar
*email
= NULL
, *param
= NULL
;
964 LDAPMod
*mods
[MODSIZE
];
967 char *cn
[] = {NULL
, NULL
};
968 char *displayName
[] = {NULL
, NULL
};
969 char *givenName
[] = {NULL
, NULL
};
971 char *sn
[] = {NULL
, NULL
};
972 char *org
[] = {NULL
, NULL
};
973 char *obj
[] = {/*"top",*/ "person", "organizationalPerson", "inetOrgPerson", NULL
};
976 AttrKeyValue
*ou
, *commonName
;
981 cm_return_if_fail(server
!= NULL
|| contact
!= NULL
);
982 node
= g_hash_table_lookup(contact
, "mail");
984 EmailKeyValue
*newEmail
= node
->data
;
985 email
= g_strdup(newEmail
->mail
);
988 server
->retVal
= LDAPRC_NODN
;
989 clean_up(ld
, server
, contact
);
992 base_dn
= g_strdup_printf("mail=%s,%s",
993 email
, server
->control
->baseDN
?server
->control
->baseDN
:"null");
996 ldapsvr_get_contact(server
, g_hash_table_lookup(contact
, "uid"));
997 person
->externalID
= g_strdup(base_dn
);
998 debug_print("dn: %s\n", base_dn
);
999 ld
= ldapsvr_connect(server
->control
);
1001 clean_up(ld
, server
, contact
);
1002 debug_print("no ldap found\n");
1005 SETMODS(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, "objectClass", obj
);
1007 ou
= get_ou(base_dn
);
1009 SETMOD(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, g_strdup(ou
->key
), org
, g_strdup(ou
->value
));
1011 attrkeyvalue_free(ou
);
1014 commonName
= get_cn(base_dn
);
1015 if (commonName
== NULL
) {
1016 param
= g_hash_table_lookup(contact
, "cn");
1018 SETMOD(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, "cn", cn
, param
);
1021 clean_up(ld
, server
, contact
);
1022 debug_print("no CN found\n");
1027 SETMOD(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, g_strdup(commonName
->key
), cn
, g_strdup(commonName
->value
));
1029 param
= g_hash_table_lookup(contact
, "cn");
1030 SETMOD(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, "displayName", displayName
, param
);
1031 g_hash_table_insert(contact
, "displayName", param
);
1032 attrkeyvalue_free(commonName
);
1035 param
= g_hash_table_lookup(contact
, "givenName");
1037 SETMOD(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, "givenName", givenName
, param
);
1040 mailList
= g_hash_table_lookup(contact
, "mail");
1043 tmp
= g_malloc(sizeof(*tmp
) * (g_list_length(mailList
)+1));
1046 EmailKeyValue
*item
= mailList
->data
;
1047 *tmp
++ = g_strdup((gchar
*) item
->mail
);
1048 mailList
= g_list_next(mailList
);
1051 SETMODS(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, "mail", mail
);
1054 param
= g_hash_table_lookup(contact
, "sn");
1056 param
= g_strdup(N_("Some SN"));
1057 SETMOD(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, "sn", sn
, param
);
1060 if (debug_get_mode()) {
1061 ldapsvr_print_ldapmod(mods
);
1063 server
->retVal
= LDAPRC_SUCCESS
;
1064 rc
= ldap_add_ext_s(ld
, base_dn
, mods
, NULL
, NULL
);
1067 case LDAP_ALREADY_EXISTS
:
1068 server
->retVal
= LDAPRC_ALREADY_EXIST
;
1071 g_printerr("ldap_modify for dn=%s\" failed[0x%x]: %s\n",
1072 base_dn
, rc
, ldaputil_get_error(ld
));
1074 server
->retVal
= LDAPRC_STRONG_AUTH
;
1076 server
->retVal
= LDAPRC_NAMING_VIOLATION
;
1079 ldapsvr_handle_other_attributes(ld
, server
, base_dn
, contact
);
1081 clean_up(ld
, server
, contact
);
1085 * Update contact to LDAP
1087 * \param server AddressBook resource
1088 * \param contact GHashTable with object to update
1090 void ldapsvr_update_contact(LdapServer
*server
, GHashTable
*contact
) {
1092 LDAPMod
*mods
[MODSIZE
];
1096 Rdn
*NoRemove
= NULL
;
1097 char *cn
[] = {NULL
, NULL
};
1098 char *givenName
[] = {NULL
, NULL
};
1100 char *sn
[] = {NULL
, NULL
};
1104 cm_return_if_fail(server
!= NULL
|| contact
!= NULL
);
1105 ld
= ldapsvr_connect(server
->control
);
1107 clean_up(ld
, server
, contact
);
1110 dn
= g_hash_table_lookup(contact
, "dn");
1113 clean_up(ld
, server
, contact
);
1116 NoRemove
= ldapsvr_modify_dn(contact
, dn
);
1118 /* We are trying to change RDN */
1119 gchar
*newRdn
= g_strdup_printf("%s=%s", NoRemove
->attribute
, NoRemove
->value
);
1121 #ifdef OPEN_LDAP_API_AT_LEAST_3000
1123 int rc
= ldap_rename_s(ld
, dn
, newRdn
, NULL
, 1, NULL
, NULL
);
1127 /* This is deprecated as of OpenLDAP-2.3.0 */
1128 int rc
= ldap_modrdn2_s(ld
, dn
, newRdn
, 1);
1132 if(rc
!= LDAP_SUCCESS
) {
1133 if (rc
== LDAP_ALREADY_EXISTS
) {
1134 /* We are messing with a contact with more than one listed email
1135 * address and the email we are changing is not the one used for dn
1137 /* It needs to be able to handle renaming errors to an already defined
1138 * dn. For now we just refuse the update. It will be caught later on as
1139 * a LDAPRC_NAMING_VIOLATION error.
1143 g_printerr("Current dn: %s\n", dn
);
1144 g_printerr("new dn: %s\n", newRdn
);
1145 g_printerr("LDAP Error(ldap_modrdn2_s) failed[0x%x]: %s\n", rc
, ldaputil_get_error(ld
));
1147 clean_up(ld
, server
, contact
);
1152 ItemPerson
*person
= g_hash_table_lookup(contact
, "person");
1154 dn
= g_strdup(NoRemove
->new_dn
);
1155 g_hash_table_replace(contact
, "dn", dn
);
1157 g_free(person
->externalID
);
1158 person
->externalID
= dn
;
1163 server
->retVal
= LDAPRC_NODN
;
1164 clean_up(ld
, server
, contact
);
1167 param
= g_hash_table_lookup(contact
, "cn");
1168 mod_op
= ldapsvr_deside_operation(ld
, server
, dn
, "displayName", param
);
1169 if (mod_op
>= 0 && (strcmp(param
, NoRemove
->value
) != 0 && strcmp("cn", NoRemove
->attribute
) != 0)) {
1170 if (mod_op
== LDAP_MOD_DELETE
) {
1171 /* Setting param to NULL instructs OpenLDAP to remove any
1172 * value stored for this attribute and remove the attribute
1173 * completely. Should multiple instances of an attribute be
1174 * allowed in the future param is required to have the value
1175 * store for the attribute which is going to be deleted
1179 if (mod_op
== LDAP_MOD_REPLACE
&& strcmp(param
, "") == 0) {
1180 /* Having an empty string is considered a syntax error in
1181 * ldap. E.g attributes with empty strings are not allowed
1182 * in which case we treate this as a request for deleting
1185 mod_op
= LDAP_MOD_DELETE
;
1188 if (mod_op
== LDAP_MOD_ADD
&& strcmp(param
, "") == 0) {
1189 /* Adding an empty string is considered a syntax error in
1190 * ldap. E.g attributes with empty strings are not allowed
1191 * in which case we silently refuse to add this entry
1195 SETMOD(mods
[cnt
], modarr
[cnt
], mod_op
, "displayName", cn
, param
);
1197 g_hash_table_insert(contact
, "displayName", param
);
1200 param
= g_hash_table_lookup(contact
, "givenName");
1201 mod_op
= ldapsvr_deside_operation(ld
, server
, dn
, "givenName", param
);
1202 if (mod_op
>= 0 && (strcmp(param
, NoRemove
->value
) != 0 && strcmp("givenName", NoRemove
->attribute
) != 0)) {
1203 if (mod_op
== LDAP_MOD_DELETE
) {
1204 /* Setting param to NULL instructs OpenLDAP to remove any
1205 * value stored for this attribute and remove the attribute
1206 * completely. Should multiple instances of an attribute be
1207 * allowed in the future param is required to have the value
1208 * store for the attribute which is going to be deleted
1212 if (mod_op
== LDAP_MOD_REPLACE
&& strcmp(param
, "") == 0) {
1213 /* Having an empty string is considered a syntax error in
1214 * ldap. E.g attributes with empty strings are not allowed
1215 * in which case we treate this as a request for deleting
1218 mod_op
= LDAP_MOD_DELETE
;
1221 if (mod_op
== LDAP_MOD_ADD
&& strcmp(param
, "") == 0) {
1222 /* Adding an empty string is considered a syntax error in
1223 * ldap. E.g attributes with empty strings are not allowed
1224 * in which case we silently refuse to add this entry
1228 SETMOD(mods
[cnt
], modarr
[cnt
], mod_op
, "givenName", givenName
, param
);
1232 mailList
= g_hash_table_lookup(contact
, "mail");
1234 debug_print("# of mail: %d\n", g_list_length(mailList
));
1235 if (!(strcmp("mail", NoRemove
->attribute
) == 0 && g_list_length(mailList
) == 1)) {
1237 tmp
= g_malloc(sizeof(*tmp
) * (g_list_length(mailList
)+1));
1240 EmailKeyValue
*item
= mailList
->data
;
1241 *tmp
++ = g_strdup((gchar
*) item
->mail
);
1242 mailList
= g_list_next(mailList
);
1246 * At least one email address is required
1247 * in which case it will always be a replace
1249 SETMODS(mods
[cnt
], modarr
[cnt
], LDAP_MOD_REPLACE
, "mail", mail
);
1255 * an error condition since at least one email adress
1256 * is required. Should never occur though.
1259 param
= g_hash_table_lookup(contact
, "sn");
1260 mod_op
= ldapsvr_deside_operation(ld
, server
, dn
, "sn", param
);
1261 if (mod_op
>= 0 && (strcmp(param
, NoRemove
->value
) != 0 && strcmp("sn", NoRemove
->attribute
) != 0)) {
1262 if (mod_op
== LDAP_MOD_DELETE
) {
1263 /* Setting param to NULL instructs OpenLDAP to remove any
1264 * value stored for this attribute and remove the attribute
1265 * completely. Should multiple instances of an attribute be
1266 * allowed in the future param is required to have the value
1267 * store for the attribute which is going to be deleted
1271 if (mod_op
== LDAP_MOD_REPLACE
&& strcmp(param
, "") == 0) {
1272 /* Having an empty string is considered a syntax error in
1273 * ldap. E.g attributes with empty strings are not allowed
1274 * in which case we treate this as a request for deleting
1277 mod_op
= LDAP_MOD_DELETE
;
1280 if (mod_op
== LDAP_MOD_ADD
&& strcmp(param
, "") == 0) {
1281 /* Adding an empty string is considered a syntax error in
1282 * ldap. E.g attributes with empty strings are not allowed
1283 * in which case we silently refuse to add this entry
1287 SETMOD(mods
[cnt
], modarr
[cnt
], mod_op
, "sn", sn
, param
);
1291 debug_print("newDN: %s\n", dn
);
1294 server
->retVal
= LDAPRC_SUCCESS
;
1298 rc
= ldap_modify_ext_s(ld
, dn
, mods
, NULL
, NULL
);
1300 g_printerr("ldap_modify for dn=%s\" failed[0x%x]: %s\n",
1301 dn
, rc
, ldaputil_get_error(ld
));
1302 server
->retVal
= LDAPRC_NAMING_VIOLATION
;
1307 ldapsvr_handle_other_attributes(ld
, server
, dn
, contact
);
1308 /* If we do not make changes persistent at this point then changes
1309 * will be lost if the user makes new search on the same server since
1310 * changes are only present in Claws' internal cache. This issue has to
1311 * be solved in addressbook.c since this involves access to structures
1312 * which are only accessible in addressbook.c */
1313 clean_up(ld
, server
, contact
);
1317 * Delete contact from LDAP
1319 * \param server AddressBook resource
1320 * \param contact GHashTable with object to delete
1322 void ldapsvr_delete_contact(LdapServer
*server
, GHashTable
*contact
) {
1327 cm_return_if_fail(server
!= NULL
|| contact
!= NULL
);
1328 ld
= ldapsvr_connect(server
->control
);
1330 clean_up(ld
, server
, contact
);
1333 dn
= g_hash_table_lookup(contact
, "dn");
1335 clean_up(ld
, server
, contact
);
1338 server
->retVal
= LDAPRC_SUCCESS
;
1339 rc
= ldap_delete_ext_s(ld
, dn
, NULL
, NULL
);
1341 g_printerr("ldap_modify for dn=%s\" failed[0x%x]: %s\n",
1342 dn
, rc
, ldaputil_get_error(ld
));
1343 server
->retVal
= LDAPRC_NODN
;
1345 clean_up(ld
, server
, contact
);
1349 * Update any changes to the server.
1351 * \param server AddressBook resource.
1352 * \param person ItemPerson holding user input.
1354 void ldapsvr_update_book(LdapServer
*server
, ItemPerson
*item
) {
1356 GHashTable
*contact
= NULL
;
1357 GList
*contacts
= NULL
, *head
= NULL
;
1359 cm_return_if_fail(server
!= NULL
);
1360 debug_print("updating ldap addressbook\n");
1362 contact
= g_hash_table_new(g_str_hash
, g_str_equal
);
1364 gboolean result
= ldapsvr_retrieve_item_person(item
, contact
);
1365 debug_print("Found contact to update: %s\n", result
? "Yes" : "No");
1367 if (debug_get_mode()) {
1368 addritem_print_item_person(item
, stdout
);
1370 contacts
= g_list_append(contacts
, contact
);
1374 ItemFolder
*folder
= server
->addressCache
->rootFolder
;
1375 node
= folder
->listFolder
;
1378 AddrItemObject
*aio
= node
->data
;
1380 if (aio
->type
== ITEMTYPE_FOLDER
) {
1381 ItemFolder
*folder
= (ItemFolder
*) aio
;
1382 GList
*persons
= folder
->listPerson
;
1384 AddrItemObject
*aio
= persons
->data
;
1386 if (aio
->type
== ITEMTYPE_PERSON
) {
1387 ItemPerson
*item
= (ItemPerson
*) aio
;
1388 gboolean result
= ldapsvr_retrieve_item_person(item
, contact
);
1389 debug_print("Found contact to update: %s\n", result
? "Yes" : "No");
1391 if (debug_get_mode()) {
1392 gchar
*uid
= g_hash_table_lookup(contact
, "uid");
1393 item
= ldapsvr_get_contact(server
, uid
);
1394 addritem_print_item_person(item
, stdout
);
1396 contacts
= g_list_append(contacts
, contact
);
1400 persons
= g_list_next(persons
);
1405 g_printerr("\t\tpid : ???\n");
1407 node
= g_list_next(node
);
1412 if (debug_get_mode()) {
1414 debug_print("Contacts which must be updated in LDAP:\n");
1416 debug_print("\tContact:\n");
1417 g_hash_table_foreach(contacts
->data
,
1418 ldapsvr_print_contacts_hashtable
, stderr
);
1419 contacts
= g_list_next(contacts
);
1422 if (contacts
== NULL
)
1426 contact
= (GHashTable
*) contacts
->data
;
1427 status
= (gchar
*) g_hash_table_lookup(contact
, "status");
1429 status
= g_strdup("NULL");
1430 if (g_ascii_strcasecmp(status
, "new") == 0) {
1431 ldapsvr_add_contact(server
, contact
);
1433 else if (g_ascii_strcasecmp(status
, "update") == 0) {
1434 ldapsvr_update_contact(server
, contact
);
1436 else if (g_ascii_strcasecmp(status
, "delete") == 0) {
1437 ldapsvr_delete_contact(server
, contact
);
1440 g_critical("ldapsvr_update_book->Unknown status: %s\n", status
);
1441 contacts
= g_list_next(contacts
);
1443 ldapsvr_free_hashtable(head
);
1446 #endif /* USE_LDAP */