1 /*
2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2003-2018 Michael Rasmussen and the Claws Mail team
4 *
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.
9 *
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.
14 *
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/>.
17 */
18
19 /*
20 * Functions necessary to access LDAP servers.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #include "claws-features.h"
26 #endif
27
28 #ifdef USE_LDAP
29
30 #include <glib.h>
31 #include <glib/gi18n.h>
32 #include <sys/time.h>
33 #include <string.h>
34
35 #include "ldapupdate.h"
36 #include "mgutils.h"
37 #include "addritem.h"
38 #include "addrcache.h"
39 #include "ldapctrl.h"
40 #include "ldapquery.h"
41 #include "ldapserver.h"
42 #include "ldaputil.h"
43 #include "utils.h"
44 #include "adbookbase.h"
45 #include "editaddress_other_attributes_ldap.h"
46 #include "log.h"
47
48 /**
49 * Structure to hold user defined attributes
50 * from contacts
51 */
52 typedef struct _AttrKeyValue AttrKeyValue;
53 struct _AttrKeyValue {
54 gchar *key;
55 gchar *value;
56 };
57
58 /**
59 * Structure to hold contact information.
60 * Each addressbook will have 0..N contacts.
61 */
62 typedef struct _EmailKeyValue EmailKeyValue;
63 struct _EmailKeyValue {
64 gchar *mail;
65 gchar *alias;
66 gchar *remarks;
67 };
68
69 /**
70 * Structure to hold information about RDN.
71 */
72 typedef struct _Rdn Rdn;
73 struct _Rdn {
74 gchar *attribute;
75 gchar *value;
76 gchar *new_dn;
77 };
78
79 /**
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.
83 */
ldapsvr_retrieve_item_group(ItemGroup * group,GHashTable * array)84 void ldapsvr_retrieve_item_group(ItemGroup *group, GHashTable *array) {
85 /* Not implemented in this release */
86 cm_return_if_fail(group != NULL);
87 }
88
89 /**
90 * Create an initial EmailKeyValue structure
91 * \return empty structure
92 */
emailkeyvalue_create()93 EmailKeyValue *emailkeyvalue_create() {
94 EmailKeyValue *buf;
95
96 buf = g_new0(EmailKeyValue, 1);
97 buf->alias = NULL;
98 buf->mail = NULL;
99 buf->remarks = NULL;
100 return buf;
101 }
102
103 /**
104 * Create an initial AttrKeyValue structure
105 * \return empty structure
106 */
attrkeyvalue_create()107 AttrKeyValue *attrkeyvalue_create() {
108 AttrKeyValue *buf;
109
110 buf = g_new0(AttrKeyValue, 1);
111 buf->key = NULL;
112 buf->value = NULL;
113 return buf;
114 }
115
116 /**
117 * Free created AttrKeyValue structure
118 * \param akv AttrKeyValue structure to free
119 */
attrkeyvalue_free(AttrKeyValue * akv)120 void attrkeyvalue_free(AttrKeyValue *akv) {
121 if (akv->key) {
122 g_free(akv->key);
123 akv->key = NULL;
124 }
125 if (akv->value) {
126 g_free(akv->value);
127 akv->value = NULL;
128 }
129 g_free(akv);
130 akv = NULL;
131 }
132
133 /**
134 * Retrieve E-Mail address object for update.
135 * \param item ItemEmail to update.
136 * \return object, or <i>NULL</i> if none created.
137 */
ldapsvr_retrieve_item_email(ItemEMail * item)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);
145 return newItem;
146 }
147
148 /**
149 * Retrieve user attribute object for update.
150 * \param item UserAttribute to update.
151 * \return object, or <i>NULL</i> if none created.
152 */
ldapsvr_retrieve_attribute(UserAttribute * item)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);
159 return newItem;
160 }
161
162 /**
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.
167 */
ldapsvr_retrieve_item_person(ItemPerson * person,GHashTable * array)168 gboolean ldapsvr_retrieve_item_person(ItemPerson *person, GHashTable *array) {
169 GList *node, *attr;
170
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);
178 }
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;
187 attr = NULL;
188 while (node) {
189 EmailKeyValue *newEmail = ldapsvr_retrieve_item_email(node->data);
190 if (newEmail)
191 attr = g_list_append(attr, newEmail);
192 node = g_list_next(node);
193 }
194 g_hash_table_insert(array, "mail", attr);
195 node = person->listAttrib;
196 attr = NULL;
197 while (node) {
198 AttrKeyValue *newAttr = ldapsvr_retrieve_attribute(node->data);
199 if (newAttr)
200 attr = g_list_append(attr, newAttr);
201 node = g_list_next(node);
202 }
203 g_hash_table_insert(array, "attribute", attr);
204 return TRUE;
205 }
206
207 /**
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.
213 */
ldapsvr_print_contacts_hashtable(gpointer key,gpointer data,gpointer fd)214 void ldapsvr_print_contacts_hashtable(gpointer key, gpointer data, gpointer fd) {
215 gchar *keyName = (gchar *) key;
216 GList *node;
217
218 if (g_ascii_strcasecmp("mail", keyName) == 0) {
219 node = (GList *) data;
220 while (node) {
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");
226 }
227 else if (fd) {
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");
232 }
233 node = g_list_next(node);
234 }
235 }
236 else if (g_ascii_strcasecmp("attribute", keyName) == 0) {
237 node = (GList *) data;
238 while (node) {
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");
243 }
244 else if (fd) {
245 FILE *stream = (FILE *) fd;
246 fprintf(stream, "\t\t%s = %s\n", item->key?item->key:"null",
247 item->value?item->value:"null");
248 }
249 node = g_list_next(node);
250 }
251 }
252 else {
253 if (debug_get_mode())
254 debug_print("\t\t%s = %s\n", keyName?keyName:"null", data?(gchar *)data:"null");
255 else if (fd) {
256 FILE *stream = (FILE *) fd;
257 fprintf(stream, "\t\t%s = %s\n", keyName?keyName:"null", data?(gchar *)data:"null");
258 }
259 }
260 }
261
262 /**
263 * Free list of changed contacts
264 *
265 * \param list List of GHashTable
266 */
ldapsvr_free_hashtable(GList * list)267 void ldapsvr_free_hashtable(GList *list) {
268 GList *tmp = list;
269 while (tmp) {
270 g_hash_table_destroy(tmp->data);
271 tmp->data = NULL;
272 tmp = g_list_next(tmp);
273 }
274 g_list_free(list);
275 list = NULL;
276 }
277
278 /**
279 * Get person object from cache
280 *
281 * \param server Resource to LDAP
282 * \param uid PersonID in cache
283 * \return person object, or <i>NULL</i> if fail
284 */
ldapsvr_get_contact(LdapServer * server,gchar * uid)285 ItemPerson *ldapsvr_get_contact(LdapServer *server, gchar *uid) {
286 AddrItemObject *aio;
287 cm_return_val_if_fail(server != NULL || uid != NULL, NULL);
288 aio = addrcache_get_object(server->addressCache, uid);
289 if (aio) {
290 if(aio->type == ITEMTYPE_PERSON) {
291 return (ItemPerson *) aio;
292 }
293 }
294 return NULL;
295 }
296
297 /**
298 * Create an initial Rdn structure
299 *
300 * \return empty structure
301 */
rdn_create()302 Rdn *rdn_create() {
303 Rdn *buf;
304
305 buf = g_new0(Rdn, 1);
306 buf->attribute = NULL;
307 buf->value = NULL;
308 buf->new_dn = NULL;
309 return buf;
310 }
311
312 /**
313 * Free a created Rdn structure
314 * \param rdn Structure to free
315 */
rdn_free(Rdn * rdn)316 void rdn_free(Rdn *rdn) {
317 if (rdn->attribute) {
318 g_free(rdn->attribute);
319 rdn->attribute = NULL;
320 }
321 if (rdn->value) {
322 g_free(rdn->value);
323 rdn->value = NULL;
324 }
325 if (rdn->new_dn) {
326 g_free(rdn->new_dn);
327 rdn->new_dn = NULL;
328 }
329 g_free(rdn);
330 rdn = NULL;
331 }
332
333 /**
334 * update Rdn structure
335 *
336 * \param rdn Rdn structure to update
337 * \param head Uniq part of dn
338 * \param tail Common part of dn
339 */
update_rdn(Rdn * rdn,gchar * head,gchar * tail)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);
343 }
344
345 /**
346 * Deside if dn needs to be changed
347 *
348 * \param hash GHashTable with user input.
349 * \param dn dn for current object
350 * \return Rdn structure
351 */
ldapsvr_modify_dn(GHashTable * hash,gchar * dn)352 Rdn *ldapsvr_modify_dn(GHashTable *hash, gchar *dn) {
353 Rdn *rdn;
354 gchar *pos, *compare;
355 gchar *rest;
356 gchar *val;
357 cm_return_val_if_fail(hash != NULL || dn != NULL, NULL);
358
359 pos = g_strstr_len(dn, strlen(dn), "=");
360 if (!pos)
361 return NULL;
362
363 compare = g_strndup(dn, pos - dn);
364
365 pos++;
366 rest = g_strstr_len(pos, strlen(pos), ",");
367 val = g_strndup(pos, rest - pos);
368 if (val == NULL) {
369 if (compare)
370 g_free(compare);
371 return NULL;
372 }
373 rdn = rdn_create();
374 rdn->value = val;
375 rdn->attribute = compare;
376
377 if (strcmp("mail", rdn->attribute) == 0) {
378 GList *list = g_hash_table_lookup(hash, rdn->attribute);
379 while (list) {
380 EmailKeyValue *item = list->data;
381 compare = (gchar *) item->mail;
382 if (strcmp(compare, rdn->value) == 0) {
383 update_rdn(rdn, compare, rest);
384 return rdn;
385 }
386 list = g_list_next(list);
387 }
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);
392 return rdn;
393 }
394 }
395 else {
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);
400 return rdn;
401 }
402 }
403 rdn_free(rdn);
404 return NULL;
405 }
406
407 /**
408 * This macro is borrowed from the Balsa project
409 * Creates a LDAPMod structure
410 *
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
417 */
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; \
421 } while(0)
422
423 /**
424 * Creates a LDAPMod structure
425 *
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
431 */
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; \
435 } while(0)
436 #define MODSIZE 10
437
438 /**
439 * Clean up, close LDAP connection, and refresh cache
440 *
441 * \param ld Resource to LDAP
442 * \param server AddressBook resource
443 * \param contact GHashTable with current changed object
444 */
clean_up(LDAP * ld,LdapServer * server,GHashTable * contact)445 void clean_up(LDAP *ld, LdapServer *server, GHashTable *contact) {
446 ItemPerson *person =
447 ldapsvr_get_contact(server, g_hash_table_lookup(contact , "uid"));
448 if (person) {
449 gchar *displayName;
450 person->status = NONE;
451 displayName = g_hash_table_lookup(contact, "displayName");
452 if (displayName)
453 person->nickName = g_strdup(displayName);
454 }
455 if (server->retVal != LDAPRC_SUCCESS) {
456 if (person) {
457 ItemPerson *res =
458 addrcache_remove_person(server->addressCache, person);
459 if (!res)
460 g_critical("ldapsvr_update_book: Could not clean cache\n");
461 else
462 addritem_free_item_person(res);
463 }
464 }
465 if (ld)
466 ldapsvr_disconnect(ld);
467 }
468
469 /**
470 * Get cn attribute from dn
471 *
472 * \param dn Distinguesh Name for current object
473 * \return AttrKeyValue, or <i>NULL</i> if none created
474 */
get_cn(gchar * dn)475 AttrKeyValue *get_cn(gchar *dn) {
476 AttrKeyValue *cn;
477 gchar *start;
478 gchar *end;
479 gchar *item;
480 gchar **key_value;
481 cm_return_val_if_fail(dn != NULL, NULL);
482
483 cn = attrkeyvalue_create();
484 start = g_strstr_len(dn, strlen(dn), "cn");
485 if (start == NULL) {
486 attrkeyvalue_free(cn);
487 return NULL;
488 }
489 end = g_strstr_len(start, strlen(start), ",");
490 item = g_strndup(start, end - start);
491 if (item == NULL) {
492 attrkeyvalue_free(cn);
493 return NULL;
494 }
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);
499 g_free(item);
500 return cn;
501 }
502
503 /**
504 * Get mail attribute from dn
505 *
506 * \param dn Distinguesh Name for current object
507 * \return AttrKeyValue, or <i>NULL</i> if none created
508 */
get_mail(gchar * dn)509 AttrKeyValue *get_mail(gchar *dn) {
510 AttrKeyValue *mail;
511 gchar *start;
512 gchar *end;
513 gchar *item;
514 gchar **key_value;
515 cm_return_val_if_fail(dn != NULL, NULL);
516
517 mail = attrkeyvalue_create();
518 start = g_strstr_len(dn, strlen(dn), "mail");
519 if (start == NULL) {
520 attrkeyvalue_free(mail);
521 return NULL;
522 }
523 end = g_strstr_len(start, strlen(start), ",");
524 item = g_strndup(start, end - start);
525 if (item == NULL) {
526 attrkeyvalue_free(mail);
527 return NULL;
528 }
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);
533 g_free(item);
534 return mail;
535 }
536
537 /**
538 * Get ou or o attribute from dn
539 *
540 * \param dn Distinguesh Name for current object
541 * \return AttrKeyValue, or <i>NULL</i> if none created
542 */
get_ou(gchar * dn)543 AttrKeyValue *get_ou(gchar *dn) {
544 AttrKeyValue *ou;
545 gchar *start;
546 gchar *end;
547 gchar *item;
548 gchar **key_value;
549
550 cm_return_val_if_fail(dn != NULL, NULL);
551 ou = attrkeyvalue_create();
552 start = g_strstr_len(dn, strlen(dn), ",o=");
553 if (start == NULL)
554 start = g_strstr_len(dn, strlen(dn), ",ou=");
555 if (start == NULL) {
556 attrkeyvalue_free(ou);
557 return NULL;
558 }
559 start++;
560 end = g_strstr_len(start, strlen(start), ",");
561 item = g_strndup(start, end - start);
562 if (item == NULL) {
563 attrkeyvalue_free(ou);
564 return NULL;
565 }
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);
570 g_free(item);
571 return ou;
572 }
573
574 /**
575 * Print the contents of a LDAPMod structure for debuging purposes
576 *
577 * \param mods LDAPMod structure
578 */
ldapsvr_print_ldapmod(LDAPMod * mods[])579 void ldapsvr_print_ldapmod(LDAPMod *mods[]) {
580 gchar *mod_op;
581 int i;
582
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];
587 gchar **vals;
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");
593 }
594 g_printerr( "Operation: %s\tType:%s\nValues:\n", mod_op, mod->mod_type);
595 vals = mod->mod_vals.modv_strvals;
596 while (*vals) {
597 g_printerr( "\t%s\n", *vals++);
598 }
599 }
600 }
601
602 /**
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
606 *
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
611 */
ldapsvr_compare_attr(LDAP * ld,gchar * dn,gint cnt,LDAPMod * mods[])612 void ldapsvr_compare_attr(LDAP *ld, gchar *dn, gint cnt, LDAPMod *mods[]) {
613 int i, rc;
614
615 #ifdef OPEN_LDAP_API_AT_LEAST_3000
616
617 struct berval val;
618
619 #endif
620
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");
626
627 #ifdef OPEN_LDAP_API_AT_LEAST_3000
628
629 val.bv_val = value;
630 val.bv_len = strlen(value);
631
632 rc = ldap_compare_ext_s(ld, dn, mods[i]->mod_type, &val, NULL, NULL);
633
634 #else
635
636 /* This is deprecated as of OpenLDAP-2.3.0 */
637 rc = ldap_compare_s(ld, dn, mods[i]->mod_type, value);
638
639 #endif
640
641 g_printerr("ldap_compare for (%s:%s)\" failed[0x%x]: %s\n",
642 mods[i]->mod_type, value, rc, ldaputil_get_error(ld));
643 g_free(value);
644 }
645 }
646
647 /**
648 * compare attribute to LDAP in case of LDAP_INAPPROPRIATE_MATCHING
649 *
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
656 */
ldapsvr_compare_manual_attr(LDAP * ld,LdapServer * server,gchar * dn,char * attr,char * value)657 int ldapsvr_compare_manual_attr(LDAP *ld, LdapServer *server, gchar *dn, char *attr, char *value) {
658 LDAPMessage *res, *e = NULL;
659 BerElement *ber;
660 struct berval **vals;
661 int rc;
662 LdapControl *ctl;
663 gchar *filter;
664 gchar *attribute;
665 int retVal = -2, i;
666 AttrKeyValue *mail;
667
668 cm_return_val_if_fail(ld != NULL || server != NULL || attr != NULL, -1);
669 ctl = server->control;
670 mail = get_mail(dn);
671 if (! mail)
672 return -2;
673 filter = g_strdup_printf("(&(mail=%s)(%s=*))", mail->value, attr);
674 attrkeyvalue_free(mail);
675 if (ctl) {
676
677 rc = ldap_search_ext_s(ld, ctl->baseDN, LDAP_SCOPE_ONELEVEL, filter, NULL, 0, NULL, NULL, NULL, 0, &res);
678
679 if (rc) {
680 log_error(LOG_PROTOCOL, _("LDAP error (search): for attribute '%s': %d (%s)\n"),
681 attr, rc, ldaputil_get_error(ld));
682 retVal = -2;
683 }
684 else {
685 e = ldap_first_entry(ld, res);
686 /* entry has this attribute */
687 if (e) {
688 attribute = ldap_first_attribute( ld, e, &ber );
689 if (attribute) {
690 if (value) {
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)
696 retVal = -1;
697 /* attribute has new value */
698 else
699 retVal = LDAP_MOD_REPLACE;
700 }
701 }
702 ldap_value_free_len(vals);
703 }
704 else
705 retVal = LDAP_MOD_DELETE;
706 }
707 if( ber != NULL ) {
708 ber_free( ber, 0 );
709 }
710 ldap_memfree(attribute);
711 }
712 /* entry does not have this attribute */
713 else {
714 /* Only add if this is a real attribute */
715 if (value)
716 retVal = LDAP_MOD_ADD;
717 /* This is dummy value used to avoid ldap_compare error */
718 else
719 retVal = -1;
720 }
721 }
722 }
723 else
724 retVal = -2;
725 g_free(filter);
726 return retVal;
727 }
728
729 /**
730 * Deside which kind of operation is required to handle
731 * updating the specified attribute
732 *
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
739 */
ldapsvr_deside_operation(LDAP * ld,LdapServer * server,char * dn,char * attr,char * value)740 int ldapsvr_deside_operation(LDAP *ld, LdapServer *server, char *dn, char *attr, char *value) {
741 int rc;
742 gboolean dummy = FALSE;
743
744 #ifdef OPEN_LDAP_API_AT_LEAST_3000
745
746 struct berval val;
747
748 #endif
749
750 cm_return_val_if_fail(ld != NULL || server != NULL || dn != NULL || attr != NULL, -1);
751 if (value == NULL)
752 return -1;
753 /* value containing empty string cause invalid syntax. A bug in
754 * the LDAP library? Therefore we add a dummy value
755 */
756 if (strcmp(value,"") == 0) {
757 value = g_strdup("thisisonlyadummy");
758 dummy = TRUE;
759 }
760
761 #ifdef OPEN_LDAP_API_AT_LEAST_3000
762
763 val.bv_val = value;
764 val.bv_len = strlen(value);
765
766 rc = ldap_compare_ext_s(ld, dn, attr, &val, NULL, NULL);
767
768 #else
769
770 /* This is deprecated as of OpenLDAP-2.3.0 */
771 rc = ldap_compare_s(ld, dn, attr, value);
772
773 #endif
774
775 debug_print("ldap_compare for (%s:%s)\" error_code[0x%x]: %s\n",
776 attr, value, rc, ldaputil_get_error(ld));
777 switch (rc) {
778 case LDAP_COMPARE_FALSE:
779 if (dummy)
780 return LDAP_MOD_DELETE;
781 else
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!
787 */
788 case LDAP_INAPPROPRIATE_MATCHING:
789 if (dummy)
790 value = NULL;
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;
794 default: return -2;
795 }
796 }
797
798 /**
799 * Check if attribute is part of the current search criteria
800 *
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
804 */
ldapsvr_check_search_attributes(char ** list,char * attr)805 gboolean ldapsvr_check_search_attributes(char **list, char *attr) {
806 while (*list) {
807 if (strcmp(*list++, attr) == 0)
808 return TRUE;
809 }
810 return FALSE;
811 }
812
813 /**
814 * Deside which other attributes needs updating
815 *
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
820 */
ldapsvr_handle_other_attributes(LDAP * ld,LdapServer * server,char * dn,GHashTable * contact)821 void ldapsvr_handle_other_attributes(LDAP *ld, LdapServer *server, char *dn, GHashTable *contact) {
822 GList *node;
823 gboolean CHECKED_ATTRIBUTE[ATTRIBUTE_SIZE + 1];
824 LDAPMod *mods[ATTRIBUTE_SIZE + 1];
825 LDAPMod modarr[ATTRIBUTE_SIZE];
826 gint cnt = 0;
827 char *attr[ATTRIBUTE_SIZE + 1][2];
828 int mod_op, rc, i;
829
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;
834 }
835 node = g_hash_table_lookup(contact , "attribute");
836 while (node) {
837 AttrKeyValue *item = node->data;
838 if (item) {
839 int index = get_attribute_index(item->key);
840 if (index >= 0) {
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
846 */
847 if (mod_op < 0) {
848 CHECKED_ATTRIBUTE[index] = TRUE;
849 node = g_list_next(node);
850 continue;
851 }
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
858 */
859 item->value = NULL;
860 }
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
865 * the attribute.
866 */
867 mod_op = LDAP_MOD_DELETE;
868 item->value = NULL;
869 }
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
874 */
875 }
876 else {
877 SETMOD(mods[cnt], modarr[cnt], mod_op, g_strdup(item->key), attr[cnt], g_strdup(item->value));
878 cnt++;
879 CHECKED_ATTRIBUTE[index] = TRUE;
880 }
881 }
882 }
883 node = g_list_next(node);
884 }
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
892 */
893 if (!strcmp(ATTRIBUTE[i], "jpegPhoto")) {
894 debug_print("not updating jpegPhoto\n");
895 continue;
896 }
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);
901 cnt++;
902 }
903 }
904 }
905 }
906 ldapctl_free_attribute_array(attribs);
907 mods[cnt] = NULL;
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);
912 if (rc) {
913 switch (rc) {
914 case LDAP_ALREADY_EXISTS:
915 server->retVal = LDAPRC_ALREADY_EXIST;
916 break;
917 default:
918 log_error(LOG_PROTOCOL, _("LDAP error (modify): for DN '%s': %d (%s)\n"),
919 dn, rc, ldaputil_get_error(ld));
920 if (rc == 0x8)
921 server->retVal = LDAPRC_STRONG_AUTH;
922 else
923 server->retVal = LDAPRC_NAMING_VIOLATION;
924 }
925 }
926 else {
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");
931 continue;
932 }
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]);
938 }
939 }
940 }
941 ldapctl_free_attribute_array(attribs);
942 }
943 }
944
945 /**
946 * Add new contact to LDAP
947 *
948 * \param server AddressBook resource
949 * \param contact GHashTable with object to add
950 */
ldapsvr_add_contact(LdapServer * server,GHashTable * contact)951 void ldapsvr_add_contact(LdapServer *server, GHashTable *contact) {
952 gchar *email = NULL, *param = NULL;
953 LDAP *ld = NULL;
954 LDAPMod *mods[MODSIZE];
955 LDAPMod modarr[7];
956 gint cnt = 0;
957 char *cn[] = {NULL, NULL};
958 char *displayName[] = {NULL, NULL};
959 char *givenName[] = {NULL, NULL};
960 char **mail = NULL;
961 char *sn[] = {NULL, NULL};
962 char *org[] = {NULL, NULL};
963 char *obj[] = {/*"top",*/ "person", "organizationalPerson", "inetOrgPerson", NULL};
964 int rc=0;
965 GList *node;
966 AttrKeyValue *ou, *commonName;
967 ItemPerson *person;
968 gchar *base_dn;
969 GList *mailList;
970
971 cm_return_if_fail(server != NULL || contact != NULL);
972 node = g_hash_table_lookup(contact , "mail");
973 if (node) {
974 EmailKeyValue *newEmail = node->data;
975 email = g_strdup(newEmail->mail);
976 }
977 if (email == NULL) {
978 server->retVal = LDAPRC_NODN;
979 clean_up(ld, server, contact);
980 return;
981 }
982 base_dn = g_strdup_printf("mail=%s,%s",
983 email, server->control->baseDN?server->control->baseDN:"null");
984 g_free(email);
985 person =
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);
990 if (ld == NULL) {
991 clean_up(ld, server, contact);
992 debug_print("no ldap found\n");
993 return;
994 }
995 SETMODS(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "objectClass", obj);
996 cnt++;
997 ou = get_ou(base_dn);
998 if (ou != NULL) {
999 SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, g_strdup(ou->key), org, g_strdup(ou->value));
1000 cnt++;
1001 attrkeyvalue_free(ou);
1002 }
1003
1004 commonName = get_cn(base_dn);
1005 if (commonName == NULL) {
1006 param = g_hash_table_lookup(contact , "cn");
1007 if (param) {
1008 SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "cn", cn, param);
1009 }
1010 else {
1011 clean_up(ld, server, contact);
1012 debug_print("no CN found\n");
1013 return;
1014 }
1015 }
1016 else {
1017 SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, g_strdup(commonName->key), cn, g_strdup(commonName->value));
1018 cnt++;
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);
1023 }
1024 cnt++;
1025 param = g_hash_table_lookup(contact , "givenName");
1026 if (param) {
1027 SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "givenName", givenName, param);
1028 cnt++;
1029 }
1030 mailList = g_hash_table_lookup(contact , "mail");
1031 if (mailList) {
1032 char **tmp;
1033 tmp = g_malloc(sizeof(*tmp) * (g_list_length(mailList)+1));
1034 mail = tmp;
1035 while (mailList) {
1036 EmailKeyValue *item = mailList->data;
1037 *tmp++ = g_strdup((gchar *) item->mail);
1038 mailList = g_list_next(mailList);
1039 }
1040 *tmp = NULL;
1041 SETMODS(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "mail", mail);
1042 cnt++;
1043 }
1044 param = g_hash_table_lookup(contact, "sn");
1045 if (param == NULL)
1046 param = g_strdup(N_("Some SN"));
1047 SETMOD(mods[cnt], modarr[cnt], LDAP_MOD_ADD, "sn", sn, param);
1048 cnt++;
1049 mods[cnt] = NULL;
1050 if (debug_get_mode()) {
1051 ldapsvr_print_ldapmod(mods);
1052 }
1053 server->retVal = LDAPRC_SUCCESS;
1054 rc = ldap_add_ext_s(ld, base_dn, mods, NULL, NULL);
1055 if (rc) {
1056 switch (rc) {
1057 case LDAP_ALREADY_EXISTS:
1058 server->retVal = LDAPRC_ALREADY_EXIST;
1059 break;
1060 default:
1061 log_error(LOG_PROTOCOL, _("LDAP error (modify): for DN '%s': %d (%s)\n"),
1062 base_dn, rc, ldaputil_get_error(ld));
1063 if (rc == 0x8)
1064 server->retVal = LDAPRC_STRONG_AUTH;
1065 else
1066 server->retVal = LDAPRC_NAMING_VIOLATION;
1067 }
1068 }
1069 ldapsvr_handle_other_attributes(ld, server, base_dn, contact);
1070 g_free(base_dn);
1071 clean_up(ld, server, contact);
1072 }
1073
1074 /**
1075 * Update contact to LDAP
1076 *
1077 * \param server AddressBook resource
1078 * \param contact GHashTable with object to update
1079 */
ldapsvr_update_contact(LdapServer * server,GHashTable * contact)1080 void ldapsvr_update_contact(LdapServer *server, GHashTable *contact) {
1081 LDAP *ld = NULL;
1082 LDAPMod *mods[MODSIZE];
1083 LDAPMod modarr[4];
1084 gint cnt = 0;
1085 gchar *param, *dn;
1086 Rdn *NoRemove = NULL;
1087 char *cn[] = {NULL, NULL};
1088 char *givenName[] = {NULL, NULL};
1089 char **mail = NULL;
1090 char *sn[] = {NULL, NULL};
1091 GList *mailList;
1092 int mod_op;
1093
1094 cm_return_if_fail(server != NULL || contact != NULL);
1095 ld = ldapsvr_connect(server->control);
1096 if (ld == NULL) {
1097 clean_up(ld, server, contact);
1098 return;
1099 }
1100 dn = g_hash_table_lookup(contact, "dn");
1101
1102 if (dn == NULL) {
1103 clean_up(ld, server, contact);
1104 return;
1105 }
1106 NoRemove = ldapsvr_modify_dn(contact, dn);
1107 if (NoRemove) {
1108 /* We are trying to change RDN */
1109 gchar *newRdn = g_strdup_printf("%s=%s", NoRemove->attribute, NoRemove->value);
1110
1111 #ifdef OPEN_LDAP_API_AT_LEAST_3000
1112
1113 int rc = ldap_rename_s(ld, dn, newRdn, NULL, 1, NULL, NULL);
1114
1115 #else
1116
1117 /* This is deprecated as of OpenLDAP-2.3.0 */
1118 int rc = ldap_modrdn2_s(ld, dn, newRdn, 1);
1119
1120 #endif
1121
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
1126 */
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.
1130 */
1131 }
1132 else {
1133 log_error(LOG_PROTOCOL, _("LDAP error (rename): from '%s' to '%s': %d (%s)\n"),
1134 dn, newRdn, rc, ldaputil_get_error(ld));
1135 g_free(newRdn);
1136 clean_up(ld, server, contact);
1137 return;
1138 }
1139 }
1140 else {
1141 ItemPerson *person = g_hash_table_lookup(contact, "person");
1142 g_free(newRdn);
1143 dn = g_strdup(NoRemove->new_dn);
1144 g_hash_table_replace(contact, "dn", dn);
1145 if (person) {
1146 g_free(person->externalID);
1147 person->externalID = dn;
1148 }
1149 }
1150 }
1151 else {
1152 server->retVal = LDAPRC_NODN;
1153 clean_up(ld, server, contact);
1154 return;
1155 }
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
1165 */
1166 param = NULL;
1167 }
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
1172 * the attribute.
1173 */
1174 mod_op = LDAP_MOD_DELETE;
1175 param = NULL;
1176 }
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
1181 */
1182 }
1183 else {
1184 SETMOD(mods[cnt], modarr[cnt], mod_op, "displayName", cn, param);
1185 cnt++;
1186 g_hash_table_insert(contact, "displayName", param);
1187 }
1188 }
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
1198 */
1199 param = NULL;
1200 }
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
1205 * the attribute.
1206 */
1207 mod_op = LDAP_MOD_DELETE;
1208 param = NULL;
1209 }
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
1214 */
1215 }
1216 else {
1217 SETMOD(mods[cnt], modarr[cnt], mod_op, "givenName", givenName, param);
1218 cnt++;
1219 }
1220 }
1221 mailList = g_hash_table_lookup(contact , "mail");
1222 if (mailList) {
1223 debug_print("# of mail: %d\n", g_list_length(mailList));
1224 if (!(strcmp("mail", NoRemove->attribute) == 0 && g_list_length(mailList) == 1)) {
1225 char **tmp;
1226 tmp = g_malloc(sizeof(*tmp) * (g_list_length(mailList)+1));
1227 mail = tmp;
1228 while (mailList) {
1229 EmailKeyValue *item = mailList->data;
1230 *tmp++ = g_strdup((gchar *) item->mail);
1231 mailList = g_list_next(mailList);
1232 }
1233 *tmp = NULL;
1234 /*
1235 * At least one email address is required
1236 * in which case it will always be a replace
1237 */
1238 SETMODS(mods[cnt], modarr[cnt], LDAP_MOD_REPLACE, "mail", mail);
1239 cnt++;
1240 }
1241 }
1242 else {
1243 /*
1244 * an error condition since at least one email adress
1245 * is required. Should never occur though.
1246 */
1247 }
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
1257 */
1258 param = NULL;
1259 }
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
1264 * the attribute.
1265 */
1266 mod_op = LDAP_MOD_DELETE;
1267 param = NULL;
1268 }
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
1273 */
1274 }
1275 else {
1276 SETMOD(mods[cnt], modarr[cnt], mod_op, "sn", sn, param);
1277 cnt++;
1278 }
1279 }
1280 debug_print("newDN: %s\n", dn);
1281 if (NoRemove)
1282 rdn_free(NoRemove);
1283 server->retVal = LDAPRC_SUCCESS;
1284 if (cnt > 0) {
1285 int rc;
1286 mods[cnt] = NULL;
1287 rc = ldap_modify_ext_s(ld, dn, mods, NULL, NULL);
1288 if (rc) {
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;
1292 }
1293 if (mail)
1294 g_free(mail);
1295 }
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);
1303 }
1304
1305 /**
1306 * Delete contact from LDAP
1307 *
1308 * \param server AddressBook resource
1309 * \param contact GHashTable with object to delete
1310 */
ldapsvr_delete_contact(LdapServer * server,GHashTable * contact)1311 void ldapsvr_delete_contact(LdapServer *server, GHashTable *contact) {
1312 LDAP *ld = NULL;
1313 gchar *dn;
1314 int rc;
1315
1316 cm_return_if_fail(server != NULL || contact != NULL);
1317 ld = ldapsvr_connect(server->control);
1318 if (ld == NULL) {
1319 clean_up(ld, server, contact);
1320 return;
1321 }
1322 dn = g_hash_table_lookup(contact, "dn");
1323 if (dn == NULL) {
1324 clean_up(ld, server, contact);
1325 return;
1326 }
1327 server->retVal = LDAPRC_SUCCESS;
1328 rc = ldap_delete_ext_s(ld, dn, NULL, NULL);
1329 if (rc) {
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;
1333 }
1334 clean_up(ld, server, contact);
1335 }
1336
1337 /**
1338 * Update any changes to the server.
1339 *
1340 * \param server AddressBook resource.
1341 * \param person ItemPerson holding user input.
1342 */
ldapsvr_update_book(LdapServer * server,ItemPerson * item)1343 void ldapsvr_update_book(LdapServer *server, ItemPerson *item) {
1344 GList *node = NULL;
1345 GHashTable *contact = NULL;
1346 GList *contacts = NULL, *head = NULL;
1347
1348 cm_return_if_fail(server != NULL);
1349 debug_print("updating ldap addressbook\n");
1350
1351 contact = g_hash_table_new(g_str_hash, g_str_equal);
1352 if (item) {
1353 gboolean result = ldapsvr_retrieve_item_person(item, contact);
1354 debug_print("Found contact to update: %s\n", result? "Yes" : "No");
1355 if (result) {
1356 if (debug_get_mode()) {
1357 addritem_print_item_person(item, stdout);
1358 }
1359 contacts = g_list_append(contacts, contact);
1360 }
1361 }
1362 else {
1363 ItemFolder *folder = server->addressCache->rootFolder;
1364 node = folder->listFolder;
1365 if (node) {
1366 while (node) {
1367 AddrItemObject *aio = node->data;
1368 if (aio) {
1369 if (aio->type == ITEMTYPE_FOLDER) {
1370 ItemFolder *folder = (ItemFolder *) aio;
1371 GList *persons = folder->listPerson;
1372 while (persons) {
1373 AddrItemObject *aio = persons->data;
1374 if (aio) {
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");
1379 if (result) {
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);
1384 }
1385 contacts = g_list_append(contacts, contact);
1386 }
1387 }
1388 }
1389 persons = g_list_next(persons);
1390 }
1391 }
1392 }
1393 else {
1394 g_printerr("\t\tpid : ???\n");
1395 }
1396 node = g_list_next(node);
1397 }
1398 }
1399 }
1400 head = contacts;
1401 if (debug_get_mode()) {
1402 if (contacts)
1403 debug_print("Contacts which must be updated in LDAP:\n");
1404 while (contacts) {
1405 debug_print("\tContact:\n");
1406 g_hash_table_foreach(contacts->data,
1407 ldapsvr_print_contacts_hashtable, stderr);
1408 contacts = g_list_next(contacts);
1409 }
1410 }
1411 if (contacts == NULL)
1412 contacts = head;
1413 while (contacts) {
1414 gchar *status;
1415 contact = (GHashTable *) contacts->data;
1416 status = (gchar *) g_hash_table_lookup(contact, "status");
1417 if (status == NULL)
1418 status = g_strdup("NULL");
1419 if (g_ascii_strcasecmp(status, "new") == 0) {
1420 ldapsvr_add_contact(server, contact);
1421 }
1422 else if (g_ascii_strcasecmp(status, "update") == 0) {
1423 ldapsvr_update_contact(server, contact);
1424 }
1425 else if (g_ascii_strcasecmp(status, "delete") == 0) {
1426 ldapsvr_delete_contact(server, contact);
1427 }
1428 else
1429 g_critical("ldapsvr_update_book->Unknown status: %s\n", status);
1430 contacts = g_list_next(contacts);
1431 }
1432 ldapsvr_free_hashtable(head);
1433 }
1434
1435 #endif /* USE_LDAP */
1436
1437 /*
1438 * End of Source.
1439 */
1440
1441