2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2003-2018 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/>.
20 * Functions necessary to access LDAP servers.
25 #include "claws-features.h"
31 #include <glib/gi18n.h>
35 #include "ldapupdate.h"
38 #include "addrcache.h"
40 #include "ldapquery.h"
41 #include "ldapserver.h"
44 #include "adbookbase.h"
45 #include "editaddress_other_attributes_ldap.h"
49 * Structure to hold user defined attributes
52 typedef struct _AttrKeyValue AttrKeyValue
;
53 struct _AttrKeyValue
{
59 * Structure to hold contact information.
60 * Each addressbook will have 0..N contacts.
62 typedef struct _EmailKeyValue EmailKeyValue
;
63 struct _EmailKeyValue
{
70 * Structure to hold information about RDN.
72 typedef struct _Rdn Rdn
;
80 * Retrieve address group item for update.
81 * \param group Group to print.
82 * \param array GHashTAble of item_group, or <i>NULL</i> if none created.
84 void ldapsvr_retrieve_item_group(ItemGroup
*group
, GHashTable
*array
) {
85 /* Not implemented in this release */
86 cm_return_if_fail(group
!= NULL
);
90 * Create an initial EmailKeyValue structure
91 * \return empty structure
93 EmailKeyValue
*emailkeyvalue_create() {
96 buf
= g_new0(EmailKeyValue
, 1);
104 * Create an initial AttrKeyValue structure
105 * \return empty structure
107 AttrKeyValue
*attrkeyvalue_create() {
110 buf
= g_new0(AttrKeyValue
, 1);
117 * Free created AttrKeyValue structure
118 * \param akv AttrKeyValue structure to free
120 void attrkeyvalue_free(AttrKeyValue
*akv
) {
134 * Retrieve E-Mail address object for update.
135 * \param item ItemEmail to update.
136 * \return object, or <i>NULL</i> if none created.
138 EmailKeyValue
*ldapsvr_retrieve_item_email(ItemEMail
*item
) {
139 EmailKeyValue
*newItem
;
140 cm_return_val_if_fail(item
!= NULL
, NULL
);
141 newItem
= emailkeyvalue_create();
142 newItem
->alias
= g_strdup(ADDRITEM_NAME(item
));
143 newItem
->mail
= g_strdup(item
->address
);
144 newItem
->remarks
= g_strdup(item
->remarks
);
149 * Retrieve user attribute object for update.
150 * \param item UserAttribute to update.
151 * \return object, or <i>NULL</i> if none created.
153 AttrKeyValue
*ldapsvr_retrieve_attribute(UserAttribute
*item
) {
154 AttrKeyValue
*newItem
;
155 cm_return_val_if_fail(item
!= NULL
, NULL
);
156 newItem
= attrkeyvalue_create();
157 newItem
->key
= g_strdup(item
->name
);
158 newItem
->value
= g_strdup(item
->value
);
163 * Retrieve person object for update.
164 * \param person ItemPerson to update.
165 * \param array GHashTable with user input.
166 * \return false if update is not needed, or true if update is needed.
168 gboolean
ldapsvr_retrieve_item_person(ItemPerson
*person
, GHashTable
*array
) {
171 cm_return_val_if_fail(person
!= NULL
, FALSE
);
172 switch (person
->status
) {
173 case NONE
: return FALSE
;
174 case ADD_ENTRY
: g_hash_table_insert(array
, "status", "new"); break;
175 case UPDATE_ENTRY
: g_hash_table_insert(array
, "status", "update"); break;
176 case DELETE_ENTRY
: g_hash_table_insert(array
, "status", "delete"); break;
177 default: g_critical("ldapsvr_retrieve_item_person->Unknown status: %d", person
->status
);
179 g_hash_table_insert(array
, "uid", ADDRITEM_ID(person
));
180 g_hash_table_insert(array
, "cn", ADDRITEM_NAME(person
));
181 g_hash_table_insert(array
, "givenName", person
->firstName
);
182 g_hash_table_insert(array
, "sn", person
->lastName
);
183 g_hash_table_insert(array
, "nickName", person
->nickName
);
184 g_hash_table_insert(array
, "dn", person
->externalID
);
185 g_hash_table_insert(array
, "person", person
);
186 node
= person
->listEMail
;
189 EmailKeyValue
*newEmail
= ldapsvr_retrieve_item_email(node
->data
);
191 attr
= g_list_append(attr
, newEmail
);
192 node
= g_list_next(node
);
194 g_hash_table_insert(array
, "mail", attr
);
195 node
= person
->listAttrib
;
198 AttrKeyValue
*newAttr
= ldapsvr_retrieve_attribute(node
->data
);
200 attr
= g_list_append(attr
, newAttr
);
201 node
= g_list_next(node
);
203 g_hash_table_insert(array
, "attribute", attr
);
208 * Print contents of contacts hashtable for debug.
209 * This function must be called with g_hash_table_foreach.
210 * \param key Key to process.
211 * \param data Data to process.
212 * \param fd Output stream.
214 void ldapsvr_print_contacts_hashtable(gpointer key
, gpointer data
, gpointer fd
) {
215 gchar
*keyName
= (gchar
*) key
;
218 if (g_ascii_strcasecmp("mail", keyName
) == 0) {
219 node
= (GList
*) data
;
221 EmailKeyValue
*item
= node
->data
;
222 if (debug_get_mode()) {
223 debug_print("\t\talias = %s\n", item
->alias
?item
->alias
:"null");
224 debug_print("\t\tmail = %s\n", item
->mail
?item
->mail
:"null");
225 debug_print("\t\tremarks = %s\n", item
->remarks
?item
->remarks
:"null");
228 FILE *stream
= (FILE *) fd
;
229 fprintf(stream
, "\t\talias = %s\n", item
->alias
?item
->alias
:"null");
230 fprintf(stream
, "\t\tmail = %s\n", item
->mail
?item
->mail
:"null");
231 fprintf(stream
, "\t\tremarks = %s\n", item
->remarks
?item
->remarks
:"null");
233 node
= g_list_next(node
);
236 else if (g_ascii_strcasecmp("attribute", keyName
) == 0) {
237 node
= (GList
*) data
;
239 AttrKeyValue
*item
= node
->data
;
240 if (debug_get_mode()) {
241 debug_print("\t\t%s = %s\n", item
->key
?item
->key
:"null",
242 item
->value
?item
->value
:"null");
245 FILE *stream
= (FILE *) fd
;
246 fprintf(stream
, "\t\t%s = %s\n", item
->key
?item
->key
:"null",
247 item
->value
?item
->value
:"null");
249 node
= g_list_next(node
);
253 if (debug_get_mode())
254 debug_print("\t\t%s = %s\n", keyName
?keyName
:"null", data
?(gchar
*)data
:"null");
256 FILE *stream
= (FILE *) fd
;
257 fprintf(stream
, "\t\t%s = %s\n", keyName
?keyName
:"null", data
?(gchar
*)data
:"null");
263 * Free list of changed contacts
265 * \param list List of GHashTable
267 void ldapsvr_free_hashtable(GList
*list
) {
270 g_hash_table_destroy(tmp
->data
);
272 tmp
= g_list_next(tmp
);
279 * Get person object from cache
281 * \param server Resource to LDAP
282 * \param uid PersonID in cache
283 * \return person object, or <i>NULL</i> if fail
285 ItemPerson
*ldapsvr_get_contact(LdapServer
*server
, gchar
*uid
) {
287 cm_return_val_if_fail(server
!= NULL
|| uid
!= NULL
, NULL
);
288 aio
= addrcache_get_object(server
->addressCache
, uid
);
290 if(aio
->type
== ITEMTYPE_PERSON
) {
291 return (ItemPerson
*) aio
;
298 * Create an initial Rdn structure
300 * \return empty structure
305 buf
= g_new0(Rdn
, 1);
306 buf
->attribute
= NULL
;
313 * Free a created Rdn structure
314 * \param rdn Structure to free
316 void rdn_free(Rdn
*rdn
) {
317 if (rdn
->attribute
) {
318 g_free(rdn
->attribute
);
319 rdn
->attribute
= NULL
;
334 * update Rdn structure
336 * \param rdn Rdn structure to update
337 * \param head Uniq part of dn
338 * \param tail Common part of dn
340 void update_rdn(Rdn
*rdn
, gchar
*head
, gchar
*tail
) {
341 rdn
->value
= g_strdup(head
);
342 rdn
->new_dn
= g_strdup_printf("%s=%s%s", rdn
->attribute
, head
, tail
);
346 * Deside if dn needs to be changed
348 * \param hash GHashTable with user input.
349 * \param dn dn for current object
350 * \return Rdn structure
352 Rdn
*ldapsvr_modify_dn(GHashTable
*hash
, gchar
*dn
) {
354 gchar
*pos
, *compare
;
357 cm_return_val_if_fail(hash
!= NULL
|| dn
!= NULL
, NULL
);
359 pos
= g_strstr_len(dn
, strlen(dn
), "=");
363 compare
= g_strndup(dn
, pos
- dn
);
366 rest
= g_strstr_len(pos
, strlen(pos
), ",");
367 val
= g_strndup(pos
, rest
- pos
);
375 rdn
->attribute
= compare
;
377 if (strcmp("mail", rdn
->attribute
) == 0) {
378 GList
*list
= g_hash_table_lookup(hash
, rdn
->attribute
);
380 EmailKeyValue
*item
= list
->data
;
381 compare
= (gchar
*) item
->mail
;
382 if (strcmp(compare
, rdn
->value
) == 0) {
383 update_rdn(rdn
, compare
, rest
);
386 list
= g_list_next(list
);
388 /* if compare and rdn->attribute are equal then last email removed/empty */
389 if (strcmp(compare
, rdn
->attribute
) != 0) {
390 /* RDN changed. Find new */
391 update_rdn(rdn
, compare
, rest
);
396 compare
= g_hash_table_lookup(hash
, rdn
->attribute
);
397 /* if compare and rdn->attribute are equal then dn removed/empty */
398 if (compare
!= NULL
&& strcmp(compare
, rdn
->attribute
) != 0) {
399 update_rdn(rdn
, compare
, rest
);
408 * This macro is borrowed from the Balsa project
409 * Creates a LDAPMod structure
411 * \param mods Empty LDAPMod structure
412 * \param modarr Array with values to insert
413 * \param op Operation to perform on LDAP
414 * \param attr Attribute to insert
415 * \param strv Empty array which is NULL terminated
416 * \param val Value for attribute
418 #define SETMOD(mods,modarr,op,attr,strv,val) \
419 do { (mods) = &(modarr); (modarr).mod_type=attr; (modarr).mod_op=op;\
420 (strv)[0]=(val); (modarr).mod_values=strv; \
424 * Creates a LDAPMod structure
426 * \param mods Empty LDAPMod structure
427 * \param modarr Array with values to insert
428 * \param op Operation to perform on LDAP
429 * \param attr Attribute to insert
430 * \param strv Array with values to insert. Must be NULL terminated
432 #define SETMODS(mods,modarr,op,attr,strv) \
433 do { (mods) = &(modarr); (modarr).mod_type=attr; \
434 (modarr).mod_op=op; (modarr).mod_values=strv; \
439 * Clean up, close LDAP connection, and refresh cache
441 * \param ld Resource to LDAP
442 * \param server AddressBook resource
443 * \param contact GHashTable with current changed object
445 void clean_up(LDAP
*ld
, LdapServer
*server
, GHashTable
*contact
) {
447 ldapsvr_get_contact(server
, g_hash_table_lookup(contact
, "uid"));
450 person
->status
= NONE
;
451 displayName
= g_hash_table_lookup(contact
, "displayName");
453 person
->nickName
= g_strdup(displayName
);
455 if (server
->retVal
!= LDAPRC_SUCCESS
) {
458 addrcache_remove_person(server
->addressCache
, person
);
460 g_critical("ldapsvr_update_book: Could not clean cache\n");
462 addritem_free_item_person(res
);
466 ldapsvr_disconnect(ld
);
470 * Get cn attribute from dn
472 * \param dn Distinguesh Name for current object
473 * \return AttrKeyValue, or <i>NULL</i> if none created
475 AttrKeyValue
*get_cn(gchar
*dn
) {
481 cm_return_val_if_fail(dn
!= NULL
, NULL
);
483 cn
= attrkeyvalue_create();
484 start
= g_strstr_len(dn
, strlen(dn
), "cn");
486 attrkeyvalue_free(cn
);
489 end
= g_strstr_len(start
, strlen(start
), ",");
490 item
= g_strndup(start
, end
- start
);
492 attrkeyvalue_free(cn
);
495 key_value
= g_strsplit(item
, "=", 2);
496 cn
->key
= g_strdup(key_value
[0]);
497 cn
->value
= g_strdup(key_value
[1]);
498 g_strfreev(key_value
);
504 * Get mail attribute from dn
506 * \param dn Distinguesh Name for current object
507 * \return AttrKeyValue, or <i>NULL</i> if none created
509 AttrKeyValue
*get_mail(gchar
*dn
) {
515 cm_return_val_if_fail(dn
!= NULL
, NULL
);
517 mail
= attrkeyvalue_create();
518 start
= g_strstr_len(dn
, strlen(dn
), "mail");
520 attrkeyvalue_free(mail
);
523 end
= g_strstr_len(start
, strlen(start
), ",");
524 item
= g_strndup(start
, end
- start
);
526 attrkeyvalue_free(mail
);
529 key_value
= g_strsplit(item
, "=", 2);
530 mail
->key
= g_strdup(key_value
[0]);
531 mail
->value
= g_strdup(key_value
[1]);
532 g_strfreev(key_value
);
538 * Get ou or o attribute from dn
540 * \param dn Distinguesh Name for current object
541 * \return AttrKeyValue, or <i>NULL</i> if none created
543 AttrKeyValue
*get_ou(gchar
*dn
) {
550 cm_return_val_if_fail(dn
!= NULL
, NULL
);
551 ou
= attrkeyvalue_create();
552 start
= g_strstr_len(dn
, strlen(dn
), ",o=");
554 start
= g_strstr_len(dn
, strlen(dn
), ",ou=");
556 attrkeyvalue_free(ou
);
560 end
= g_strstr_len(start
, strlen(start
), ",");
561 item
= g_strndup(start
, end
- start
);
563 attrkeyvalue_free(ou
);
566 key_value
= g_strsplit(item
, "=", 2);
567 ou
->key
= g_strdup(key_value
[0]);
568 ou
->value
= g_strdup(key_value
[1]);
569 g_strfreev(key_value
);
575 * Print the contents of a LDAPMod structure for debuging purposes
577 * \param mods LDAPMod structure
579 void ldapsvr_print_ldapmod(LDAPMod
*mods
[]) {
583 cm_return_if_fail(mods
!= NULL
);
584 g_printerr( "Type\n");
585 for (i
= 0; NULL
!= mods
[i
]; i
++) {
586 LDAPMod
*mod
= (LDAPMod
*) mods
[i
];
588 switch (mod
->mod_op
) {
589 case LDAP_MOD_ADD
: mod_op
= g_strdup("ADD"); break;
590 case LDAP_MOD_REPLACE
: mod_op
= g_strdup("MODIFY"); break;
591 case LDAP_MOD_DELETE
: mod_op
= g_strdup("DELETE"); break;
592 default: mod_op
= g_strdup("UNKNOWN");
594 g_printerr( "Operation: %s\tType:%s\nValues:\n", mod_op
, mod
->mod_type
);
595 vals
= mod
->mod_vals
.modv_strvals
;
597 g_printerr( "\t%s\n", *vals
++);
603 * Make a compare for every new value we want to store in the
604 * directory with the current values. Great tool for debugging
605 * against invalid syntax in attributes
607 * \param ld AddressBook resource
608 * \param dn dn for the entry
609 * \param cnt Number of attributes to compare
610 * \param mods LDAPMod structure
612 void ldapsvr_compare_attr(LDAP
*ld
, gchar
*dn
, gint cnt
, LDAPMod
*mods
[]) {
615 #ifdef OPEN_LDAP_API_AT_LEAST_3000
621 cm_return_if_fail(ld
!= NULL
|| dn
!= NULL
|| cnt
>= 0 || mods
!= NULL
);
622 for (i
= 0; i
< cnt
; i
++) {
623 gchar
*value
= g_strdup(mods
[i
]->mod_vals
.modv_strvals
[0]);
624 if (!value
|| strcmp(value
, "") == 0)
625 value
= g_strdup("thisisonlyadummy");
627 #ifdef OPEN_LDAP_API_AT_LEAST_3000
630 val
.bv_len
= strlen(value
);
632 rc
= ldap_compare_ext_s(ld
, dn
, mods
[i
]->mod_type
, &val
, NULL
, NULL
);
636 /* This is deprecated as of OpenLDAP-2.3.0 */
637 rc
= ldap_compare_s(ld
, dn
, mods
[i
]->mod_type
, value
);
641 g_printerr("ldap_compare for (%s:%s)\" failed[0x%x]: %s\n",
642 mods
[i
]->mod_type
, value
, rc
, ldaputil_get_error(ld
));
648 * compare attribute to LDAP in case of LDAP_INAPPROPRIATE_MATCHING
650 * \param ld AddressBook resource
651 * \param server Reference to server
652 * \param dn dn for the entry
653 * \param attr Attribute
654 * \param value New value
655 * \return int, return will be LDAP_MOD_ADD, LDAP_MOD_REPLACE, or LDAP_MOD_DELETE
657 int ldapsvr_compare_manual_attr(LDAP
*ld
, LdapServer
*server
, gchar
*dn
, char *attr
, char *value
) {
658 LDAPMessage
*res
, *e
= NULL
;
660 struct berval
**vals
;
668 cm_return_val_if_fail(ld
!= NULL
|| server
!= NULL
|| attr
!= NULL
, -1);
669 ctl
= server
->control
;
673 filter
= g_strdup_printf("(&(mail=%s)(%s=*))", mail
->value
, attr
);
674 attrkeyvalue_free(mail
);
677 rc
= ldap_search_ext_s(ld
, ctl
->baseDN
, LDAP_SCOPE_ONELEVEL
, filter
, NULL
, 0, NULL
, NULL
, NULL
, 0, &res
);
680 log_error(LOG_PROTOCOL
, _("LDAP error (search): for attribute '%s': %d (%s)\n"),
681 attr
, rc
, ldaputil_get_error(ld
));
685 e
= ldap_first_entry(ld
, res
);
686 /* entry has this attribute */
688 attribute
= ldap_first_attribute( ld
, e
, &ber
);
691 if( ( vals
= ldap_get_values_len( ld
, e
, attr
) ) != NULL
) {
692 for( i
= 0; vals
[i
] != NULL
; i
++ ) {
693 debug_print("Compare: %s=%s\n", attr
, vals
[i
]->bv_val
);
694 /* attribute has same value */
695 if (strcmp(vals
[i
]->bv_val
, value
) == 0)
697 /* attribute has new value */
699 retVal
= LDAP_MOD_REPLACE
;
702 ldap_value_free_len(vals
);
705 retVal
= LDAP_MOD_DELETE
;
710 ldap_memfree(attribute
);
712 /* entry does not have this attribute */
714 /* Only add if this is a real attribute */
716 retVal
= LDAP_MOD_ADD
;
717 /* This is dummy value used to avoid ldap_compare error */
730 * Deside which kind of operation is required to handle
731 * updating the specified attribute
733 * \param ld AddressBook resource
734 * \param server Reference to server
735 * \param dn dn for the entry
736 * \param attr Attribute
737 * \param value New value
738 * \return int, return will be LDAP_MOD_ADD, LDAP_MOD_REPLACE, or LDAP_MOD_DELETE
740 int ldapsvr_deside_operation(LDAP
*ld
, LdapServer
*server
, char *dn
, char *attr
, char *value
) {
742 gboolean dummy
= FALSE
;
744 #ifdef OPEN_LDAP_API_AT_LEAST_3000
750 cm_return_val_if_fail(ld
!= NULL
|| server
!= NULL
|| dn
!= NULL
|| attr
!= NULL
, -1);
753 /* value containing empty string cause invalid syntax. A bug in
754 * the LDAP library? Therefore we add a dummy value
756 if (strcmp(value
,"") == 0) {
757 value
= g_strdup("thisisonlyadummy");
761 #ifdef OPEN_LDAP_API_AT_LEAST_3000
764 val
.bv_len
= strlen(value
);
766 rc
= ldap_compare_ext_s(ld
, dn
, attr
, &val
, NULL
, NULL
);
770 /* This is deprecated as of OpenLDAP-2.3.0 */
771 rc
= ldap_compare_s(ld
, dn
, attr
, value
);
775 debug_print("ldap_compare for (%s:%s)\" error_code[0x%x]: %s\n",
776 attr
, value
, rc
, ldaputil_get_error(ld
));
778 case LDAP_COMPARE_FALSE
:
780 return LDAP_MOD_DELETE
;
782 return LDAP_MOD_REPLACE
;
783 case LDAP_COMPARE_TRUE
: return -1;
784 case LDAP_NO_SUCH_ATTRIBUTE
: return LDAP_MOD_ADD
;
785 /* LDAP_INAPPROPRIATE_MATCHING needs extensive testing because I
786 * am not aware off the condition causing this return value!
788 case LDAP_INAPPROPRIATE_MATCHING
:
791 return ldapsvr_compare_manual_attr(ld
, server
, dn
, attr
, value
);
792 case LDAP_UNDEFINED_TYPE
: return -2;
793 case LDAP_INVALID_SYNTAX
: return -2;
799 * Check if attribute is part of the current search criteria
801 * \param list Array containing attributes in the current search criteria
802 * \param attr Attribute to check
803 * \result <i>TRUE</i> if attribute is found in the current search criteria
805 gboolean
ldapsvr_check_search_attributes(char **list
, char *attr
) {
807 if (strcmp(*list
++, attr
) == 0)
814 * Deside which other attributes needs updating
816 * \param ld LDAP resource
817 * \param server AddressBook resource
818 * \param dn dn for the entry
819 * \param contact GHashTable with information for the current contact
821 void ldapsvr_handle_other_attributes(LDAP
*ld
, LdapServer
*server
, char *dn
, GHashTable
*contact
) {
823 gboolean CHECKED_ATTRIBUTE
[ATTRIBUTE_SIZE
+ 1];
824 LDAPMod
*mods
[ATTRIBUTE_SIZE
+ 1];
825 LDAPMod modarr
[ATTRIBUTE_SIZE
];
827 char *attr
[ATTRIBUTE_SIZE
+ 1][2];
830 cm_return_if_fail(server
!= NULL
|| dn
!= NULL
|| contact
!= NULL
);
831 for (i
= 0; i
<= ATTRIBUTE_SIZE
; i
++) {
832 CHECKED_ATTRIBUTE
[i
] = FALSE
;
833 attr
[i
][0] = attr
[i
][1] = NULL
;
835 node
= g_hash_table_lookup(contact
, "attribute");
837 AttrKeyValue
*item
= node
->data
;
839 int index
= get_attribute_index(item
->key
);
841 debug_print("Found other attribute: %s = %s\n",
842 item
->key
?item
->key
:"null", item
->value
?item
->value
:"null");
843 mod_op
= ldapsvr_deside_operation(ld
, server
, dn
, item
->key
, item
->value
);
844 /* Only consider attributes which we no how to handle.
845 * Set to TRUE in CHECKED_ATTRIBUTE array to indicate no further action
848 CHECKED_ATTRIBUTE
[index
] = TRUE
;
849 node
= g_list_next(node
);
852 if (mod_op
== LDAP_MOD_DELETE
) {
853 /* Setting param to NULL instructs OpenLDAP to remove any
854 * value stored for this attribute and remove the attribute
855 * completely. Should multiple instances of an attribute be
856 * allowed in the future param is required to have the value
857 * store for the attribute which is going to be deleted
861 if (mod_op
== LDAP_MOD_REPLACE
&& strcmp(item
->value
, "") == 0) {
862 /* Having an empty string is considered a syntax error in
863 * ldap. E.g attributes with empty strings are not allowed
864 * in which case we treate this as a request for deleting
867 mod_op
= LDAP_MOD_DELETE
;
870 if (mod_op
== LDAP_MOD_ADD
&& strcmp(item
->value
, "") == 0) {
871 /* Adding an empty string is considered a syntax error in
872 * ldap. E.g attributes with empty strings are not allowed
873 * in which case we silently refuse to add this entry
877 SETMOD(mods
[cnt
], modarr
[cnt
], mod_op
, g_strdup(item
->key
), attr
[cnt
], g_strdup(item
->value
));
879 CHECKED_ATTRIBUTE
[index
] = TRUE
;
883 node
= g_list_next(node
);
885 char **attribs
= ldapctl_full_attribute_array(server
->control
);
886 for (i
= 0; i
< ATTRIBUTE_SIZE
; i
++) {
887 /* Attributes which holds no information are to be removed */
888 if (CHECKED_ATTRIBUTE
[i
] == FALSE
) {
889 /* Only consider those attributes which is currently part of the search criteria.
890 * If attributes are not part of the search criteria they would seem to hold
891 * no information since their values will not be populated in the GUI
893 if (!strcmp(ATTRIBUTE
[i
], "jpegPhoto")) {
894 debug_print("not updating jpegPhoto\n");
897 if (ldapsvr_check_search_attributes(attribs
, (char *) ATTRIBUTE
[i
])) {
898 mod_op
= ldapsvr_deside_operation(ld
, server
, dn
, (char *) ATTRIBUTE
[i
], "");
899 if (mod_op
== LDAP_MOD_DELETE
) {
900 SETMOD(mods
[cnt
], modarr
[cnt
], LDAP_MOD_DELETE
, g_strdup((char *) ATTRIBUTE
[i
]), attr
[cnt
], NULL
);
906 ldapctl_free_attribute_array(attribs
);
908 if (debug_get_mode())
909 ldapsvr_print_ldapmod(mods
);
910 server
->retVal
= LDAPRC_SUCCESS
;
911 rc
= ldap_modify_ext_s(ld
, dn
, mods
, NULL
, NULL
);
914 case LDAP_ALREADY_EXISTS
:
915 server
->retVal
= LDAPRC_ALREADY_EXIST
;
918 log_error(LOG_PROTOCOL
, _("LDAP error (modify): for DN '%s': %d (%s)\n"),
919 dn
, rc
, ldaputil_get_error(ld
));
921 server
->retVal
= LDAPRC_STRONG_AUTH
;
923 server
->retVal
= LDAPRC_NAMING_VIOLATION
;
927 char **attribs
= ldapctl_full_attribute_array(server
->control
);
928 for (i
= 0; i
< ATTRIBUTE_SIZE
; i
++) {
929 if (!strcmp(ATTRIBUTE
[i
], "jpegPhoto")) {
930 debug_print("not updating jpegPhoto\n");
933 if (ldapsvr_check_search_attributes(attribs
, (char *) ATTRIBUTE
[i
])) {
934 if (CHECKED_ATTRIBUTE
[i
] == FALSE
) {
935 AddrItemObject
*aio
= addrcache_get_object(server
->addressCache
, g_hash_table_lookup(contact
, "uid"));
936 ItemPerson
*person
= (ItemPerson
*) aio
;
937 addritem_person_remove_attribute(person
, (const gchar
*) ATTRIBUTE
[i
]);
941 ldapctl_free_attribute_array(attribs
);
946 * Add new contact to LDAP
948 * \param server AddressBook resource
949 * \param contact GHashTable with object to add
951 void ldapsvr_add_contact(LdapServer
*server
, GHashTable
*contact
) {
952 gchar
*email
= NULL
, *param
= NULL
;
954 LDAPMod
*mods
[MODSIZE
];
957 char *cn
[] = {NULL
, NULL
};
958 char *displayName
[] = {NULL
, NULL
};
959 char *givenName
[] = {NULL
, NULL
};
961 char *sn
[] = {NULL
, NULL
};
962 char *org
[] = {NULL
, NULL
};
963 char *obj
[] = {/*"top",*/ "person", "organizationalPerson", "inetOrgPerson", NULL
};
966 AttrKeyValue
*ou
, *commonName
;
971 cm_return_if_fail(server
!= NULL
|| contact
!= NULL
);
972 node
= g_hash_table_lookup(contact
, "mail");
974 EmailKeyValue
*newEmail
= node
->data
;
975 email
= g_strdup(newEmail
->mail
);
978 server
->retVal
= LDAPRC_NODN
;
979 clean_up(ld
, server
, contact
);
982 base_dn
= g_strdup_printf("mail=%s,%s",
983 email
, server
->control
->baseDN
?server
->control
->baseDN
:"null");
986 ldapsvr_get_contact(server
, g_hash_table_lookup(contact
, "uid"));
987 person
->externalID
= g_strdup(base_dn
);
988 debug_print("dn: %s\n", base_dn
);
989 ld
= ldapsvr_connect(server
->control
);
991 clean_up(ld
, server
, contact
);
992 debug_print("no ldap found\n");
995 SETMODS(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, "objectClass", obj
);
997 ou
= get_ou(base_dn
);
999 SETMOD(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, g_strdup(ou
->key
), org
, g_strdup(ou
->value
));
1001 attrkeyvalue_free(ou
);
1004 commonName
= get_cn(base_dn
);
1005 if (commonName
== NULL
) {
1006 param
= g_hash_table_lookup(contact
, "cn");
1008 SETMOD(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, "cn", cn
, param
);
1011 clean_up(ld
, server
, contact
);
1012 debug_print("no CN found\n");
1017 SETMOD(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, g_strdup(commonName
->key
), cn
, g_strdup(commonName
->value
));
1019 param
= g_hash_table_lookup(contact
, "cn");
1020 SETMOD(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, "displayName", displayName
, param
);
1021 g_hash_table_insert(contact
, "displayName", param
);
1022 attrkeyvalue_free(commonName
);
1025 param
= g_hash_table_lookup(contact
, "givenName");
1027 SETMOD(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, "givenName", givenName
, param
);
1030 mailList
= g_hash_table_lookup(contact
, "mail");
1033 tmp
= g_malloc(sizeof(*tmp
) * (g_list_length(mailList
)+1));
1036 EmailKeyValue
*item
= mailList
->data
;
1037 *tmp
++ = g_strdup((gchar
*) item
->mail
);
1038 mailList
= g_list_next(mailList
);
1041 SETMODS(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, "mail", mail
);
1044 param
= g_hash_table_lookup(contact
, "sn");
1046 param
= g_strdup(N_("Some SN"));
1047 SETMOD(mods
[cnt
], modarr
[cnt
], LDAP_MOD_ADD
, "sn", sn
, param
);
1050 if (debug_get_mode()) {
1051 ldapsvr_print_ldapmod(mods
);
1053 server
->retVal
= LDAPRC_SUCCESS
;
1054 rc
= ldap_add_ext_s(ld
, base_dn
, mods
, NULL
, NULL
);
1057 case LDAP_ALREADY_EXISTS
:
1058 server
->retVal
= LDAPRC_ALREADY_EXIST
;
1061 log_error(LOG_PROTOCOL
, _("LDAP error (modify): for DN '%s': %d (%s)\n"),
1062 base_dn
, rc
, ldaputil_get_error(ld
));
1064 server
->retVal
= LDAPRC_STRONG_AUTH
;
1066 server
->retVal
= LDAPRC_NAMING_VIOLATION
;
1069 ldapsvr_handle_other_attributes(ld
, server
, base_dn
, contact
);
1071 clean_up(ld
, server
, contact
);
1075 * Update contact to LDAP
1077 * \param server AddressBook resource
1078 * \param contact GHashTable with object to update
1080 void ldapsvr_update_contact(LdapServer
*server
, GHashTable
*contact
) {
1082 LDAPMod
*mods
[MODSIZE
];
1086 Rdn
*NoRemove
= NULL
;
1087 char *cn
[] = {NULL
, NULL
};
1088 char *givenName
[] = {NULL
, NULL
};
1090 char *sn
[] = {NULL
, NULL
};
1094 cm_return_if_fail(server
!= NULL
|| contact
!= NULL
);
1095 ld
= ldapsvr_connect(server
->control
);
1097 clean_up(ld
, server
, contact
);
1100 dn
= g_hash_table_lookup(contact
, "dn");
1103 clean_up(ld
, server
, contact
);
1106 NoRemove
= ldapsvr_modify_dn(contact
, dn
);
1108 /* We are trying to change RDN */
1109 gchar
*newRdn
= g_strdup_printf("%s=%s", NoRemove
->attribute
, NoRemove
->value
);
1111 #ifdef OPEN_LDAP_API_AT_LEAST_3000
1113 int rc
= ldap_rename_s(ld
, dn
, newRdn
, NULL
, 1, NULL
, NULL
);
1117 /* This is deprecated as of OpenLDAP-2.3.0 */
1118 int rc
= ldap_modrdn2_s(ld
, dn
, newRdn
, 1);
1122 if(rc
!= LDAP_SUCCESS
) {
1123 if (rc
== LDAP_ALREADY_EXISTS
) {
1124 /* We are messing with a contact with more than one listed email
1125 * address and the email we are changing is not the one used for dn
1127 /* It needs to be able to handle renaming errors to an already defined
1128 * dn. For now we just refuse the update. It will be caught later on as
1129 * a LDAPRC_NAMING_VIOLATION error.
1133 log_error(LOG_PROTOCOL
, _("LDAP error (rename): from '%s' to '%s': %d (%s)\n"),
1134 dn
, newRdn
, rc
, ldaputil_get_error(ld
));
1136 clean_up(ld
, server
, contact
);
1141 ItemPerson
*person
= g_hash_table_lookup(contact
, "person");
1143 dn
= g_strdup(NoRemove
->new_dn
);
1144 g_hash_table_replace(contact
, "dn", dn
);
1146 g_free(person
->externalID
);
1147 person
->externalID
= dn
;
1152 server
->retVal
= LDAPRC_NODN
;
1153 clean_up(ld
, server
, contact
);
1156 param
= g_hash_table_lookup(contact
, "cn");
1157 mod_op
= ldapsvr_deside_operation(ld
, server
, dn
, "displayName", param
);
1158 if (mod_op
>= 0 && (strcmp(param
, NoRemove
->value
) != 0 && strcmp("cn", NoRemove
->attribute
) != 0)) {
1159 if (mod_op
== LDAP_MOD_DELETE
) {
1160 /* Setting param to NULL instructs OpenLDAP to remove any
1161 * value stored for this attribute and remove the attribute
1162 * completely. Should multiple instances of an attribute be
1163 * allowed in the future param is required to have the value
1164 * store for the attribute which is going to be deleted
1168 if (mod_op
== LDAP_MOD_REPLACE
&& strcmp(param
, "") == 0) {
1169 /* Having an empty string is considered a syntax error in
1170 * ldap. E.g attributes with empty strings are not allowed
1171 * in which case we treate this as a request for deleting
1174 mod_op
= LDAP_MOD_DELETE
;
1177 if (mod_op
== LDAP_MOD_ADD
&& strcmp(param
, "") == 0) {
1178 /* Adding an empty string is considered a syntax error in
1179 * ldap. E.g attributes with empty strings are not allowed
1180 * in which case we silently refuse to add this entry
1184 SETMOD(mods
[cnt
], modarr
[cnt
], mod_op
, "displayName", cn
, param
);
1186 g_hash_table_insert(contact
, "displayName", param
);
1189 param
= g_hash_table_lookup(contact
, "givenName");
1190 mod_op
= ldapsvr_deside_operation(ld
, server
, dn
, "givenName", param
);
1191 if (mod_op
>= 0 && (strcmp(param
, NoRemove
->value
) != 0 && strcmp("givenName", NoRemove
->attribute
) != 0)) {
1192 if (mod_op
== LDAP_MOD_DELETE
) {
1193 /* Setting param to NULL instructs OpenLDAP to remove any
1194 * value stored for this attribute and remove the attribute
1195 * completely. Should multiple instances of an attribute be
1196 * allowed in the future param is required to have the value
1197 * store for the attribute which is going to be deleted
1201 if (mod_op
== LDAP_MOD_REPLACE
&& strcmp(param
, "") == 0) {
1202 /* Having an empty string is considered a syntax error in
1203 * ldap. E.g attributes with empty strings are not allowed
1204 * in which case we treate this as a request for deleting
1207 mod_op
= LDAP_MOD_DELETE
;
1210 if (mod_op
== LDAP_MOD_ADD
&& strcmp(param
, "") == 0) {
1211 /* Adding an empty string is considered a syntax error in
1212 * ldap. E.g attributes with empty strings are not allowed
1213 * in which case we silently refuse to add this entry
1217 SETMOD(mods
[cnt
], modarr
[cnt
], mod_op
, "givenName", givenName
, param
);
1221 mailList
= g_hash_table_lookup(contact
, "mail");
1223 debug_print("# of mail: %d\n", g_list_length(mailList
));
1224 if (!(strcmp("mail", NoRemove
->attribute
) == 0 && g_list_length(mailList
) == 1)) {
1226 tmp
= g_malloc(sizeof(*tmp
) * (g_list_length(mailList
)+1));
1229 EmailKeyValue
*item
= mailList
->data
;
1230 *tmp
++ = g_strdup((gchar
*) item
->mail
);
1231 mailList
= g_list_next(mailList
);
1235 * At least one email address is required
1236 * in which case it will always be a replace
1238 SETMODS(mods
[cnt
], modarr
[cnt
], LDAP_MOD_REPLACE
, "mail", mail
);
1244 * an error condition since at least one email adress
1245 * is required. Should never occur though.
1248 param
= g_hash_table_lookup(contact
, "sn");
1249 mod_op
= ldapsvr_deside_operation(ld
, server
, dn
, "sn", param
);
1250 if (mod_op
>= 0 && (strcmp(param
, NoRemove
->value
) != 0 && strcmp("sn", NoRemove
->attribute
) != 0)) {
1251 if (mod_op
== LDAP_MOD_DELETE
) {
1252 /* Setting param to NULL instructs OpenLDAP to remove any
1253 * value stored for this attribute and remove the attribute
1254 * completely. Should multiple instances of an attribute be
1255 * allowed in the future param is required to have the value
1256 * store for the attribute which is going to be deleted
1260 if (mod_op
== LDAP_MOD_REPLACE
&& strcmp(param
, "") == 0) {
1261 /* Having an empty string is considered a syntax error in
1262 * ldap. E.g attributes with empty strings are not allowed
1263 * in which case we treate this as a request for deleting
1266 mod_op
= LDAP_MOD_DELETE
;
1269 if (mod_op
== LDAP_MOD_ADD
&& strcmp(param
, "") == 0) {
1270 /* Adding an empty string is considered a syntax error in
1271 * ldap. E.g attributes with empty strings are not allowed
1272 * in which case we silently refuse to add this entry
1276 SETMOD(mods
[cnt
], modarr
[cnt
], mod_op
, "sn", sn
, param
);
1280 debug_print("newDN: %s\n", dn
);
1283 server
->retVal
= LDAPRC_SUCCESS
;
1287 rc
= ldap_modify_ext_s(ld
, dn
, mods
, NULL
, NULL
);
1289 log_error(LOG_PROTOCOL
, _("LDAP error (modify): for DN '%s': %d (%s)\n"),
1290 dn
, rc
, ldaputil_get_error(ld
));
1291 server
->retVal
= LDAPRC_NAMING_VIOLATION
;
1296 ldapsvr_handle_other_attributes(ld
, server
, dn
, contact
);
1297 /* If we do not make changes persistent at this point then changes
1298 * will be lost if the user makes new search on the same server since
1299 * changes are only present in Claws' internal cache. This issue has to
1300 * be solved in addressbook.c since this involves access to structures
1301 * which are only accessible in addressbook.c */
1302 clean_up(ld
, server
, contact
);
1306 * Delete contact from LDAP
1308 * \param server AddressBook resource
1309 * \param contact GHashTable with object to delete
1311 void ldapsvr_delete_contact(LdapServer
*server
, GHashTable
*contact
) {
1316 cm_return_if_fail(server
!= NULL
|| contact
!= NULL
);
1317 ld
= ldapsvr_connect(server
->control
);
1319 clean_up(ld
, server
, contact
);
1322 dn
= g_hash_table_lookup(contact
, "dn");
1324 clean_up(ld
, server
, contact
);
1327 server
->retVal
= LDAPRC_SUCCESS
;
1328 rc
= ldap_delete_ext_s(ld
, dn
, NULL
, NULL
);
1330 log_error(LOG_PROTOCOL
, _("LDAP error (modify): for DN '%s': %d (%s)\n"),
1331 dn
, rc
, ldaputil_get_error(ld
));
1332 server
->retVal
= LDAPRC_NODN
;
1334 clean_up(ld
, server
, contact
);
1338 * Update any changes to the server.
1340 * \param server AddressBook resource.
1341 * \param person ItemPerson holding user input.
1343 void ldapsvr_update_book(LdapServer
*server
, ItemPerson
*item
) {
1345 GHashTable
*contact
= NULL
;
1346 GList
*contacts
= NULL
, *head
= NULL
;
1348 cm_return_if_fail(server
!= NULL
);
1349 debug_print("updating ldap addressbook\n");
1351 contact
= g_hash_table_new(g_str_hash
, g_str_equal
);
1353 gboolean result
= ldapsvr_retrieve_item_person(item
, contact
);
1354 debug_print("Found contact to update: %s\n", result
? "Yes" : "No");
1356 if (debug_get_mode()) {
1357 addritem_print_item_person(item
, stdout
);
1359 contacts
= g_list_append(contacts
, contact
);
1363 ItemFolder
*folder
= server
->addressCache
->rootFolder
;
1364 node
= folder
->listFolder
;
1367 AddrItemObject
*aio
= node
->data
;
1369 if (aio
->type
== ITEMTYPE_FOLDER
) {
1370 ItemFolder
*folder
= (ItemFolder
*) aio
;
1371 GList
*persons
= folder
->listPerson
;
1373 AddrItemObject
*aio
= persons
->data
;
1375 if (aio
->type
== ITEMTYPE_PERSON
) {
1376 ItemPerson
*item
= (ItemPerson
*) aio
;
1377 gboolean result
= ldapsvr_retrieve_item_person(item
, contact
);
1378 debug_print("Found contact to update: %s\n", result
? "Yes" : "No");
1380 if (debug_get_mode()) {
1381 gchar
*uid
= g_hash_table_lookup(contact
, "uid");
1382 item
= ldapsvr_get_contact(server
, uid
);
1383 addritem_print_item_person(item
, stdout
);
1385 contacts
= g_list_append(contacts
, contact
);
1389 persons
= g_list_next(persons
);
1394 g_printerr("\t\tpid : ???\n");
1396 node
= g_list_next(node
);
1401 if (debug_get_mode()) {
1403 debug_print("Contacts which must be updated in LDAP:\n");
1405 debug_print("\tContact:\n");
1406 g_hash_table_foreach(contacts
->data
,
1407 ldapsvr_print_contacts_hashtable
, stderr
);
1408 contacts
= g_list_next(contacts
);
1411 if (contacts
== NULL
)
1415 contact
= (GHashTable
*) contacts
->data
;
1416 status
= (gchar
*) g_hash_table_lookup(contact
, "status");
1418 status
= g_strdup("NULL");
1419 if (g_ascii_strcasecmp(status
, "new") == 0) {
1420 ldapsvr_add_contact(server
, contact
);
1422 else if (g_ascii_strcasecmp(status
, "update") == 0) {
1423 ldapsvr_update_contact(server
, contact
);
1425 else if (g_ascii_strcasecmp(status
, "delete") == 0) {
1426 ldapsvr_delete_contact(server
, contact
);
1429 g_critical("ldapsvr_update_book->Unknown status: %s\n", status
);
1430 contacts
= g_list_next(contacts
);
1432 ldapsvr_free_hashtable(head
);
1435 #endif /* USE_LDAP */