2 * ========================================================================
3 * Copyright 2013-2022 Eduardo Chappa
4 * Copyright 2006-2008 University of Washington
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
15 #include "../pith/headers.h"
16 #include "../pith/ldap.h"
17 #include "../pith/state.h"
18 #include "../pith/conf.h"
19 #include "../pith/status.h"
20 #include "../pith/util.h"
21 #include "../pith/imap.h"
22 #include "../pith/busy.h"
23 #include "../pith/signal.h"
24 #include "../pith/ablookup.h"
25 #include "../pith/readfile.h"
28 * Until we can think of a better way to do this. If user exits from an
29 * ldap address selection screen we want to return -1 so that call_builder
30 * will stay on the same line. Might want to use another return value
31 * for the builder so that call_builder more fully understands what we're
40 * Hook to allow user input on whether or not to save chosen LDAP result
42 void (*pith_opt_save_ldap_entry
)(struct pine
*, LDAP_CHOOSE_S
*, int);
48 LDAP_SERV_RES_S
*ldap_lookup(LDAP_SERV_S
*, char *, CUSTOM_FILT_S
*, WP_ERR_S
*, int);
49 LDAP_SERV_S
*copy_ldap_serv_info(LDAP_SERV_S
*);
50 int our_ldap_get_lderrno(LDAP
*, char **, char **);
51 int our_ldap_set_lderrno(LDAP
*, int, char *, char *);
52 #endif /* ENABLE_LDAP */
56 * This function does white pages lookups.
58 * Args string -- the string to use in the lookup
60 * Returns NULL -- lookup failed
61 * Address -- A single address is returned if lookup was successful.
64 wp_lookups(char *string
, WP_ERR_S
*wp_err
, int recursing
)
66 ADDRESS
*ret_a
= NULL
;
69 LDAP_SERV_RES_S
*free_when_done
= NULL
;
70 LDAPLookupStyle style
;
71 LDAP_CHOOSE_S
*winning_e
= NULL
;
72 LDAP_SERV_S
*info
= NULL
;
73 static char *fakedomain
= "@";
78 * Runtime ldap lookup of addrbook entry.
80 if(!strncmp(string
, RUN_LDAP
, LEN_RL
)){
81 LDAP_SERV_RES_S
*head_of_result_list
;
83 info
= break_up_ldap_server(string
+LEN_RL
);
84 head_of_result_list
= ldap_lookup(info
, "", NULL
, wp_err
, 1);
86 if(head_of_result_list
){
88 auwe_rv
= ask_user_which_entry(head_of_result_list
, string
,
91 wp_err
->wp_err_occurred
92 ? DisplayIfOne
: DisplayIfTwo
);
95 free_when_done
= head_of_result_list
;
98 wp_err
->wp_err_occurred
= 1;
100 q_status_message(SM_ORDER
, 3, 5, wp_err
->error
);
101 display_message('x');
102 fs_give((void **)&wp_err
->error
);
105 /* try using backup email address */
106 if(info
&& info
->mail
&& *info
->mail
){
107 tmp_a_string
= cpystr(info
->mail
);
108 rfc822_parse_adrlist(&ret_a
, tmp_a_string
, fakedomain
);
109 fs_give((void **)&tmp_a_string
);
112 cpystr(_("Directory lookup failed, using backup email address"));
116 * Do this so the awful LDAP: ... string won't show up
117 * in the composer. This shouldn't actually happen in
118 * real life, so we're not too concerned about it. If we
119 * were we'd want to recover the nickname we started with
120 * somehow, or something like that.
122 ret_a
= mail_newaddr();
123 ret_a
->mailbox
= cpystr("missing-username");
124 wp_err
->error
= cpystr(_("Directory lookup failed, no backup email address available"));
127 q_status_message(SM_ORDER
, 3, 5, wp_err
->error
);
128 display_message('x');
132 style
= F_ON(F_COMPOSE_REJECTS_UNQUAL
, ps_global
)
133 ? DisplayIfOne
: DisplayIfTwo
;
134 auwe_rv
= ldap_lookup_all(string
, as
.n_serv
, recursing
, style
, NULL
,
135 &winning_e
, wp_err
, &free_when_done
);
138 if(winning_e
&& auwe_rv
!= -5){
139 ret_a
= address_from_ldap(winning_e
);
141 if(pith_opt_save_ldap_entry
&& ret_a
&& F_ON(F_ADD_LDAP_TO_ABOOK
, ps_global
) && !info
)
142 (*pith_opt_save_ldap_entry
)(ps_global
, winning_e
, 1);
145 fs_give((void **)&winning_e
);
148 /* Info's only set in the RUN_LDAP case */
150 if(ret_a
&& ret_a
->host
){
151 ADDRESS
*backup
= NULL
;
153 if(info
->mail
&& *info
->mail
)
154 rfc822_parse_adrlist(&backup
, info
->mail
, fakedomain
);
156 if(!backup
|| !address_is_same(ret_a
, backup
)){
158 q_status_message(SM_ORDER
, 3, 5, wp_err
->error
);
159 display_message('x');
160 fs_give((void **)&wp_err
->error
);
163 snprintf(ebuf
, sizeof(ebuf
),
164 _("Warning: current address different from saved address (%s)"),
166 wp_err
->error
= cpystr(ebuf
);
167 q_status_message(SM_ORDER
, 3, 5, wp_err
->error
);
168 display_message('x');
172 mail_free_address(&backup
);
175 free_ldap_server_info(&info
);
179 free_ldap_result_list(&free_when_done
);
180 #endif /* ENABLE_LDAP */
183 if(ret_a
->mailbox
){ /* indicates there was a MAIL attribute */
184 if(!ret_a
->host
|| !ret_a
->host
[0]){
186 fs_give((void **)&ret_a
->host
);
188 ret_a
->host
= cpystr("missing-hostname");
189 wp_err
->wp_err_occurred
= 1;
191 fs_give((void **)&wp_err
->error
);
193 wp_err
->error
= cpystr(_("Missing hostname in LDAP address"));
194 q_status_message(SM_ORDER
, 3, 5, wp_err
->error
);
195 display_message('x');
198 if(!ret_a
->mailbox
[0]){
200 fs_give((void **)&ret_a
->mailbox
);
202 ret_a
->mailbox
= cpystr("missing-username");
203 wp_err
->wp_err_occurred
= 1;
205 fs_give((void **)&wp_err
->error
);
207 wp_err
->error
= cpystr(_("Missing username in LDAP address"));
208 q_status_message(SM_ORDER
, 3, 5, wp_err
->error
);
209 display_message('x');
213 wp_err
->wp_err_occurred
= 1;
216 fs_give((void **)&wp_err
->error
);
218 snprintf(ebuf
, sizeof(ebuf
), _("No email address available for \"%s\""),
219 (ret_a
->personal
&& *ret_a
->personal
)
222 wp_err
->error
= cpystr(ebuf
);
223 q_status_message(SM_ORDER
, 3, 5, wp_err
->error
);
224 display_message('x');
225 mail_free_address(&ret_a
);
237 * Goes through all servers looking up string.
239 * Args string -- String to search for
240 * who -- Which servers to look on
241 * style -- Sometimes we want to display no matter what, sometimes
242 * only if more than one entry, sometimes only if email
245 * The possible styles are:
246 * AlwaysDisplayAndMailRequired: This happens when user ^T's from
247 * composer to address book screen, and
248 * then queries directory server.
249 * AlwaysDisplay: This happens when user is browsing
250 * in address book maintenance screen and
251 * then queries directory server.
252 * DisplayIfOne: These two come from implicit lookups
253 * DisplayIfTwo: from build_address. If the compose rejects
254 * unqualified feature is on we get the
255 * DisplayIfOne, otherwise IfTwo.
257 * cust -- Use this custom filter instead of configured filters
258 * winning_e -- Return value
259 * wp_err -- Error handling
260 * free_when_done -- Caller needs to free this
262 * Returns -- value returned by ask_user_which_entry
265 ldap_lookup_all(char *string
, int who
, int recursing
, LDAPLookupStyle style
,
266 CUSTOM_FILT_S
*cust
, LDAP_CHOOSE_S
**winning_e
,
267 WP_ERR_S
*wp_err
, LDAP_SERV_RES_S
**free_when_done
)
270 LDAP_SERV_RES_S
*head_of_result_list
= NULL
;
272 wp_exit
= wp_nobail
= 0;
274 *free_when_done
= NULL
;
276 head_of_result_list
= ldap_lookup_all_work(string
, who
, recursing
,
280 retval
= ask_user_which_entry(head_of_result_list
, string
, winning_e
,
282 (wp_err
->wp_err_occurred
&&
283 style
== DisplayIfTwo
) ? DisplayIfOne
287 * Because winning_e probably points into the result list
288 * we need to leave the result list alone and have the caller
289 * free it after they are done with winning_e.
291 if(retval
!= -5 && free_when_done
)
292 *free_when_done
= head_of_result_list
;
299 * Goes through all servers looking up string.
301 * Args string -- String to search for
302 * who -- Which servers to look on
303 * cust -- Use this custom filter instead of configured filters
304 * wp_err -- Error handling
306 * Returns -- list of results that needs to be freed by caller
309 ldap_lookup_all_work(char *string
, int who
, int recursing
,
310 CUSTOM_FILT_S
*cust
, WP_ERR_S
*wp_err
)
313 LDAP_SERV_RES_S
*serv_res
;
314 LDAP_SERV_RES_S
*rr
, *head_of_result_list
= NULL
;
316 /* If there is at least one server */
317 if(ps_global
->VAR_LDAP_SERVERS
&& ps_global
->VAR_LDAP_SERVERS
[0] &&
318 ps_global
->VAR_LDAP_SERVERS
[0][0]){
319 int how_many_servers
;
321 for(i
= 0; ps_global
->VAR_LDAP_SERVERS
[i
] &&
322 ps_global
->VAR_LDAP_SERVERS
[i
][0]; i
++)
325 how_many_servers
= i
;
327 /* For each server in list */
328 for(i
= 0; !wp_exit
&& ps_global
->VAR_LDAP_SERVERS
[i
] &&
329 ps_global
->VAR_LDAP_SERVERS
[i
][0]; i
++){
332 dprint((6, "ldap_lookup_all_work: lookup on server (%.256s)\n",
333 ps_global
->VAR_LDAP_SERVERS
[i
]));
335 if(who
== -1 || who
== i
|| who
== as
.n_serv
)
336 info
= break_up_ldap_server(ps_global
->VAR_LDAP_SERVERS
[i
]);
339 * Who tells us which servers to look on.
340 * Who == -1 means all servers.
341 * Who == 0 means server[0].
342 * Who == 1 means server[1].
343 * Who == as.n_serv means query on those with impl set.
345 if(!(who
== -1 || who
== i
||
346 (who
== as
.n_serv
&& !recursing
&& info
&& info
->impl
) ||
347 (who
== as
.n_serv
&& recursing
&& info
&& info
->rhs
))){
350 free_ldap_server_info(&info
);
355 dprint((6, "ldap_lookup_all_work: ldap_lookup (server: %.20s...)(string: %s)\n",
356 ps_global
->VAR_LDAP_SERVERS
[i
], string
));
357 serv_res
= ldap_lookup(info
, string
, cust
,
358 wp_err
, how_many_servers
> 1);
360 /* Add new one to end of list so they come in the right order */
361 for(rr
= head_of_result_list
; rr
&& rr
->next
; rr
= rr
->next
)
367 head_of_result_list
= serv_res
;
371 free_ldap_server_info(&info
);
375 return(head_of_result_list
);
380 * Do an LDAP lookup to the server described in the info argument.
382 * Args info -- LDAP info for server.
383 * string -- String to lookup.
384 * cust -- Possible custom filter description.
385 * wp_err -- We set this is we get a white pages error.
386 * name_in_error -- Caller sets this if they want us to include the server
387 * name in error messages.
389 * Returns Results of lookup, NULL if lookup failed.
392 ldap_lookup(LDAP_SERV_S
*info
, char *string
, CUSTOM_FILT_S
*cust
,
393 WP_ERR_S
*wp_err
, int name_in_error
)
397 char *serv
, *base
, *serv_errstr
, *s
, *t
;
398 char *mailattr
, *snattr
, *gnattr
, *cnattr
;
399 int we_cancel
= 0, we_turned_on
= 0;
400 LDAP_SERV_RES_S
*serv_res
= NULL
;
410 serv
= cpystr((info
->serv
&& *info
->serv
) ? info
->serv
: "?");
413 snprintf(ebuf
, sizeof(ebuf
), " (%s)",
414 (info
->nick
&& *info
->nick
) ? info
->nick
: serv
);
418 serv_errstr
= cpystr(ebuf
);
419 base
= cpystr(info
->base
? info
->base
: "");
422 info
->port
= LDAP_PORT
;
425 info
->type
= DEF_LDAP_TYPE
;
428 info
->srch
= DEF_LDAP_SRCH
;
431 info
->time
= DEF_LDAP_TIME
;
434 info
->size
= DEF_LDAP_SIZE
;
437 info
->scope
= DEF_LDAP_SCOPE
;
439 mailattr
= (info
->mailattr
&& info
->mailattr
[0]) ? info
->mailattr
441 snattr
= (info
->snattr
&& info
->snattr
[0]) ? info
->snattr
443 gnattr
= (info
->gnattr
&& info
->gnattr
[0]) ? info
->gnattr
445 cnattr
= (info
->cnattr
&& info
->cnattr
[0]) ? info
->cnattr
449 * We may want to keep ldap handles open, but at least for
450 * now, re-open them every time.
453 dprint((3, "ldap_lookup(%s,%d)\n", serv
? serv
: "?", info
->port
));
455 snprintf(ebuf
, sizeof(ebuf
), "Searching%s%s%s on %s",
456 (string
&& *string
) ? " for \"" : "",
457 (string
&& *string
) ? string
: "",
458 (string
&& *string
) ? "\"" : "",
460 we_turned_on
= intr_handling_on(); /* this erases keymenu */
461 we_cancel
= busy_cue(ebuf
, NULL
, 0);
463 *(wp_err
->mangled
) = 1;
466 if(info
->tls
|| info
->tlsmust
)
467 ldapssl_client_init(NULL
, NULL
);
468 if((ld
= ldap_init(serv
, info
->port
)) == NULL
)
472 if((ld
= ldap_init(serv
, info
->port
)) == NULL
)
474 #ifdef SMIME_SSLCERTS
475 /* If we are attempting a ldaps secure connection, we need to tell
476 * ldap that we have certificates. There are many ways to do so.
477 * OpenLDAP has many ways to configure this through configuration
478 * files. For example the global (to the system) ldap.conf file, or the
479 * personal ldaprc or .ldaprc files. Setting the location of the
480 * certificates must happen at the time we call ldap_initialize, we
481 * cannot set it up before that call, nor after, so what we are going
482 * to do is to test for a .ldaprc file in the home directory. If such
483 * file exists we read it, if not we create it and if it does not have
484 * a line for the location of the certificates in the system, we add one.
485 * (so we ignore all other configuration files)
487 if(info
->ldaps
&& ps_global
->home_dir
){
489 char *text
, *tls_conf
;
490 char filename
[MAXPATH
+1];
492 build_path(filename
, ps_global
->home_dir
, ".ldaprc", sizeof(filename
));
494 if((text
= read_file(filename
, 0)) != NULL
)
496 && (tls_conf
= strstr(text
, "TLS_CACERTDIR")) != NULL
497 && (tls_conf
== text
|| *(tls_conf
- 1) == '\n')){
498 tls_conf
+= 13; /* 13 = strlen("TLS_CACERTDIR") */
499 while (isspace(*tls_conf
))
501 if(!strncmp(tls_conf
, SMIME_SSLCERTS
, strlen(SMIME_SSLCERTS
)))
508 if((so
= so_get(FileStar
, filename
, WRITE_ACCESS
)) != NULL
){
511 so_puts(so
, NEWLINE
);
513 so_puts(so
, "TLS_CACERTDIR");
515 so_puts(so
, SMIME_SSLCERTS
);
516 so_puts(so
, NEWLINE
);
521 fs_give((void **)&text
);
523 #endif /* SMIME_SSLCERTS */
525 tmp_20k_buf
[0] = '\0';
528 if ((t
= strchr(s
, ' ')) != NULL
) *t
= '\0';
529 snprintf(tmp_20k_buf
+ strlen(tmp_20k_buf
),
530 SIZEOF_20KBUF
- strlen(tmp_20k_buf
), "%s://%s",
531 info
->ldaps
? "ldaps" : "ldap", s
);
532 if (strchr(s
, ':') == NULL
){
533 snprintf(tmp_20k_buf
+ strlen(tmp_20k_buf
),
534 SIZEOF_20KBUF
- strlen(tmp_20k_buf
),
535 "%s%d", ":", info
->port
);
539 for( ; *t
== ' '; t
++);
540 snprintf(tmp_20k_buf
+ strlen(tmp_20k_buf
),
541 SIZEOF_20KBUF
- strlen(tmp_20k_buf
), "%s", " ");
546 tmp_20k_buf
[SIZEOF_20KBUF
- 1] = '\0';
548 if(ldap_initialize(&ld
, tmp_20k_buf
) != LDAP_SUCCESS
)
551 if((ld
= ldap_open(serv
, info
->port
)) == NULL
)
555 /* TRANSLATORS: All of the three args together are an error message */
556 snprintf(ebuf
, sizeof(ebuf
), _("Access to LDAP server failed: %s%s(%s)"),
557 errno
? error_description(errno
) : "",
560 wp_err
->wp_err_occurred
= 1;
562 fs_give((void **)&wp_err
->error
);
564 wp_err
->error
= cpystr(ebuf
);
568 q_status_message(SM_ORDER
, 3, 5, wp_err
->error
);
569 display_message('x');
570 dprint((2, "%s\n", ebuf
));
572 else if(!ps_global
->intr_pending
){
573 int proto
= 3, tlsmustbail
= 0;
574 char *pwd
= NULL
, user
[NETMAXUSER
];
578 struct berval passwd
= { 0 };
586 memset(&mb
, 0, sizeof(mb
));
589 if(info
->tls
|| info
->tlsmust
)
590 rc
= ldapssl_install_routines(ld
);
593 if(ldap_v3_is_supported(ld
) &&
594 our_ldap_set_option(ld
, LDAP_OPT_PROTOCOL_VERSION
, &proto
) == 0){
595 dprint((5, "ldap: using version 3 protocol\n"));
599 * If we don't set RESTART then the select() waiting for the answer
600 * in libldap will be interrupted and stopped by our busy_cue.
602 our_ldap_set_option(ld
, LDAP_OPT_RESTART
, LDAP_OPT_ON
);
605 * If we need to authenticate, get the password
607 if(info
->binddn
&& info
->binddn
[0]){
611 snprintf(hostbuf
, sizeof(hostbuf
), "{%s}dummy", info
->serv
? info
->serv
: "?");
614 * We don't handle multiple space-delimited hosts well.
615 * We don't know which we're asking for a password for.
616 * We're not connected yet so we can't know.
618 if((space
=strindex(hostbuf
, ' ')) != NULL
)
621 mail_valid_net_parse_work(hostbuf
, &mb
, info
->ldaps
? "ldaps" : "ldap");
622 mb
.port
= info
->port
;
623 mb
.tlsflag
= (info
->tls
|| info
->tlsmust
) ? 1 : 0;
624 mb
.sslflag
= info
->ldaps
? 1 : 0;
633 #else /* !_SOLARIS_SDK */
634 ((rc
=ldap_start_tls_s(ld
, NULL
, NULL
)) == LDAP_SUCCESS
)
635 #endif /* !_SOLARIS_SDK */
637 0 /* TODO: find a way to do this in Windows */
638 #endif /* _WINDOWS */
644 if((info
->tls
|| info
->tlsmust
) && !mb
.tlsflag
){
645 q_status_message(SM_ORDER
, 3, 5, "Not able to start TLS encryption for LDAP server");
651 snprintf(pmt
, sizeof(pmt
), " %s", (info
->nick
&& *info
->nick
) ? info
->nick
: serv
);
652 mm_login_work(&mb
, user
, &pwd
, pwdtrial
, pmt
, info
->binddn
);
657 passwd
.bv_len
= strlen(pwd
);
666 * LDAPv2 requires the bind. v3 doesn't require it but we want
667 * to tell the server we're v3 if the server supports v3, and if the
668 * server doesn't support v3 the bind is required.
672 || ldap_simple_bind_s(ld
, info
->binddn
, passwd
) != LDAP_SUCCESS
){
674 || ldap_sasl_bind_s(ld
, info
->binddn
, LDAP_SASL_SIMPLE
, &passwd
, NULL
, NULL
, NULL
) != LDAP_SUCCESS
){
676 wp_err
->wp_err_occurred
= 1;
678 ld_errnum
= our_ldap_get_lderrno(ld
, NULL
, &ld_errstr
);
680 if(!tlsmustbail
&& info
->binddn
&& info
->binddn
[0] && pwdtrial
< 2L
681 && ld_errnum
== LDAP_INVALID_CREDENTIALS
){
683 q_status_message(SM_ORDER
, 3, 5, _("Invalid password"));
684 goto try_password_again
;
687 snprintf(ebuf
, sizeof(ebuf
), _("LDAP server failed: %s%s%s%s"),
688 ldap_err2string(ld_errnum
),
690 (ld_errstr
&& *ld_errstr
) ? ": " : "",
691 (ld_errstr
&& *ld_errstr
) ? ld_errstr
: "");
694 fs_give((void **)&wp_err
->error
);
701 ldap_unbind_ext(ld
, NULL
, NULL
);
703 wp_err
->error
= cpystr(ebuf
);
704 q_status_message(SM_ORDER
, 3, 5, wp_err
->error
);
705 display_message('x');
706 dprint((2, "%s\n", ebuf
));
708 else if(!ps_global
->intr_pending
){
709 int srch_res
= LDAP_SUCCESS
, args
, slen
, flen
;
710 #define TEMPLATELEN 512
711 char filt_template
[TEMPLATELEN
+ 1];
712 char filt_format
[2*TEMPLATELEN
+ 1];
713 char filter
[2*TEMPLATELEN
+ 1];
714 char scp
[2*TEMPLATELEN
+ 1];
716 LDAPMessage
*res
= NULL
;
717 int intr_happened
= 0;
720 tl
= (info
->time
== 0) ? info
->time
: info
->time
+ 10;
722 our_ldap_set_option(ld
, LDAP_OPT_TIMELIMIT
, &tl
);
723 our_ldap_set_option(ld
, LDAP_OPT_SIZELIMIT
, &info
->size
);
726 * If a custom filter has been passed in and it doesn't include a
727 * request to combine it with the configured filter, then replace
728 * any configured filter with the passed in filter.
730 if(cust
&& cust
->filt
&& !cust
->combine
){
732 fs_give((void **)&info
->cust
);
734 info
->cust
= cpystr(cust
->filt
);
737 if(info
->cust
&& *info
->cust
){ /* use custom filter if present */
738 strncpy(filt_template
, info
->cust
, sizeof(filt_template
));
739 filt_template
[sizeof(filt_template
)-1] = '\0';
741 else{ /* else use configured filter */
744 snprintf(filt_template
, sizeof(filt_template
), "(%s=%%s)", snattr
);
746 case LDAP_TYPE_GIVEN
:
747 snprintf(filt_template
, sizeof(filt_template
), "(%s=%%s)", gnattr
);
749 case LDAP_TYPE_EMAIL
:
750 snprintf(filt_template
, sizeof(filt_template
), "(%s=%%s)", mailattr
);
752 case LDAP_TYPE_CN_EMAIL
:
753 snprintf(filt_template
, sizeof(filt_template
), "(|(%s=%%s)(%s=%%s))", cnattr
,
756 case LDAP_TYPE_SUR_GIVEN
:
757 snprintf(filt_template
, sizeof(filt_template
), "(|(%s=%%s)(%s=%%s))",
760 case LDAP_TYPE_SEVERAL
:
761 snprintf(filt_template
, sizeof(filt_template
),
762 "(|(%s=%%s)(%s=%%s)(%s=%%s)(%s=%%s))",
763 cnattr
, mailattr
, snattr
, gnattr
);
767 snprintf(filt_template
, sizeof(filt_template
), "(%s=%%s)", cnattr
);
772 /* just copy if custom */
773 if(info
->cust
&& *info
->cust
)
774 info
->srch
= LDAP_SRCH_EQUALS
;
778 memset((void *)filt_format
, 0, sizeof(filt_format
));
780 while(*p
&& (q
- filt_format
) + 4 < sizeof(filt_format
)){
781 if(*p
== '%' && *(p
+1) == 's'){
785 case LDAP_SRCH_EQUALS
:
790 /* Append wildcard after %s */
791 case LDAP_SRCH_BEGINS
:
797 /* Insert wildcard before %s */
804 /* Put wildcard before and after %s */
806 case LDAP_SRCH_CONTAINS
:
818 if(q
- filt_format
< sizeof(filt_format
))
821 filt_format
[sizeof(filt_format
)-1] = '\0';
824 * If combine is lit we put the custom filter and the filt_format
825 * filter and combine them with an &.
827 if(cust
&& cust
->filt
&& cust
->combine
){
831 l
= strlen(filt_format
) + strlen(cust
->filt
) + 3;
832 combined
= (char *) fs_get((l
+1) * sizeof(char));
833 snprintf(combined
, l
+1, "(&%s%s)", cust
->filt
, filt_format
);
834 strncpy(filt_format
, combined
, sizeof(filt_format
));
835 filt_format
[sizeof(filt_format
)-1] = '\0';
836 fs_give((void **) &combined
);
840 * Ad hoc attempt to make "Steve Hubert" match
841 * Steven Hubert but not Steven Shubert.
842 * We replace a <SPACE> with * <SPACE> (not * <SPACE> *).
844 memset((void *)scp
, 0, sizeof(scp
));
846 strncpy(scp
, string
, sizeof(scp
));
850 while(*p
&& (q
- scp
) + 1 < sizeof(scp
)){
851 if(*p
== SPACE
&& *(p
+1) != SPACE
){
860 scp
[sizeof(scp
)-1] = '\0';
863 flen
= strlen(filt_format
);
864 /* truncate string if it will overflow filter */
865 if(args
*slen
+ flen
- 2*args
> sizeof(filter
)-1)
866 scp
[(sizeof(filter
)-1 - flen
)/args
] = '\0';
869 * Replace %s's with scp.
873 snprintf(filter
, sizeof(filter
), "%s", filt_format
);
876 snprintf(filter
, sizeof(filter
), filt_format
, scp
);
879 snprintf(filter
, sizeof(filter
), filt_format
, scp
, scp
);
882 snprintf(filter
, sizeof(filter
), filt_format
, scp
, scp
, scp
);
885 snprintf(filter
, sizeof(filter
), filt_format
, scp
, scp
, scp
, scp
);
888 snprintf(filter
, sizeof(filter
), filt_format
, scp
, scp
, scp
, scp
, scp
);
891 snprintf(filter
, sizeof(filter
), filt_format
, scp
, scp
, scp
, scp
, scp
, scp
);
894 snprintf(filter
, sizeof(filter
), filt_format
, scp
, scp
, scp
, scp
, scp
, scp
, scp
);
897 snprintf(filter
, sizeof(filter
), filt_format
, scp
, scp
, scp
, scp
, scp
, scp
, scp
,
901 snprintf(filter
, sizeof(filter
), filt_format
, scp
, scp
, scp
, scp
, scp
, scp
, scp
,
906 snprintf(filter
, sizeof(filter
), filt_format
, scp
, scp
, scp
, scp
, scp
, scp
, scp
,
911 /* replace double *'s with single *'s in filter */
912 for(p
= q
= filter
; *p
; p
++)
913 if(*p
!= '*' || p
== filter
|| *(p
-1) != '*')
918 (void) removing_double_quotes(base
);
919 dprint((5, "about to ldap_search(\"%s\", %s)\n",
920 base
? base
: "?", filter
? filter
: "?"));
921 if(ps_global
->intr_pending
)
922 srch_res
= LDAP_PROTOCOL_ERROR
;
926 struct timeval tv
= {0}, *tvp
= NULL
;
928 memset((void *)&tv
, 0, sizeof(struct timeval
));
929 tv
.tv_sec
= info
->time
;
932 start_time
= time((time_t *)0);
934 dprint((6, "ldap_lookup: calling ldap_search\n"));
936 msgid
= ldap_search(ld
, base
, info
->scope
, filter
, NULL
, 0);
938 if(ldap_search_ext(ld
, base
, info
->scope
, filter
, NULL
, 0,
939 NULL
, NULL
, tvp
, info
->size
, &msgid
) != LDAP_SUCCESS
)
944 srch_res
= our_ldap_get_lderrno(ld
, NULL
, NULL
);
948 * Warning: struct timeval is not portable. However, since it is
949 * part of LDAP api it must be portable to all platforms LDAP
950 * has been ported to.
954 t
.tv_sec
= 1; t
.tv_usec
= 0;
957 if(ps_global
->intr_pending
)
960 dprint((6, "ldap_result(id=%d): ", msgid
));
961 if((lres
=ldap_result(ld
, msgid
, LDAP_MSG_ALL
, &t
, &res
)) == -1){
963 srch_res
= our_ldap_get_lderrno(ld
, NULL
, NULL
);
964 dprint((6, "error (-1 returned): ld_errno=%d\n",
967 else if(lres
== 0){ /* timeout, no results available */
970 ldap_abandon(ld
, msgid
);
972 ldap_abandon_ext(ld
, msgid
, NULL
, NULL
);
974 srch_res
= LDAP_PROTOCOL_ERROR
;
975 if(our_ldap_get_lderrno(ld
, NULL
, NULL
) == LDAP_SUCCESS
)
976 our_ldap_set_lderrno(ld
, LDAP_PROTOCOL_ERROR
, NULL
, NULL
);
978 dprint((6, "timeout, intr: srch_res=%d\n",
981 else if(info
->time
> 0 &&
982 ((long)time((time_t *)0) - start_time
) > info
->time
){
983 /* try for partial results */
984 t
.tv_sec
= 0; t
.tv_usec
= 0;
985 lres
= ldap_result(ld
, msgid
, LDAP_MSG_RECEIVED
, &t
, &res
);
986 if(lres
> 0 && lres
!= LDAP_RES_SEARCH_RESULT
){
987 srch_res
= LDAP_SUCCESS
;
988 dprint((6, "partial result: lres=0x%x\n", lres
));
993 ldap_abandon(ld
, msgid
);
995 ldap_abandon_ext(ld
, msgid
, NULL
, NULL
);
998 srch_res
= LDAP_TIMEOUT
;
999 if(our_ldap_get_lderrno(ld
, NULL
, NULL
) == LDAP_SUCCESS
)
1000 our_ldap_set_lderrno(ld
, LDAP_TIMEOUT
, NULL
, NULL
);
1003 "timeout, total_time (%d), srch_res=%d\n",
1004 info
->time
, srch_res
));
1008 dprint((6, "timeout\n"));
1013 srch_res
= ldap_result2error(ld
, res
, 0);
1014 dprint((6, "lres=0x%x, srch_res=%d\n", lres
,
1018 char *dn
, *text
, **ref
;
1021 dn
= text
= NULL
; ref
= NULL
; srv
= NULL
;
1022 srch_res
= ldap_parse_result(ld
, res
,
1023 &err
, &dn
, &text
, &ref
, &srv
, 0);
1024 dprint((6, "lres=0x%x, srch_res=%d, dn=%s, text=%s\n", lres
,
1025 srch_res
, dn
? dn
: "", text
? text
: ""));
1026 if(dn
) ber_memfree(dn
);
1027 if(text
) ber_memfree(text
);
1028 if(ref
) ber_memvfree((void **) ref
);
1029 if(srv
) ldap_controls_free(srv
);
1035 ((long)time((time_t *)0) - start_time
) > info
->time
)));
1042 cancel_busy_cue(-1);
1045 fs_give((void **)&wp_err
->error
);
1047 q_status_message(SM_ORDER
, 0, 1, "Interrupt");
1048 display_message('x');
1058 ldap_unbind_ext(ld
, NULL
, NULL
);
1061 res
= NULL
; ld
= NULL
;
1063 else if(srch_res
!= LDAP_SUCCESS
&&
1064 srch_res
!= LDAP_TIMELIMIT_EXCEEDED
&&
1065 srch_res
!= LDAP_RESULTS_TOO_LARGE
&&
1066 srch_res
!= LDAP_TIMEOUT
&&
1067 srch_res
!= LDAP_SIZELIMIT_EXCEEDED
){
1068 wp_err
->wp_err_occurred
= 1;
1070 ld_errnum
= our_ldap_get_lderrno(ld
, NULL
, &ld_errstr
);
1072 snprintf(ebuf
, sizeof(ebuf
), _("LDAP search failed: %s%s%s%s"),
1073 ldap_err2string(ld_errnum
),
1075 (ld_errstr
&& *ld_errstr
) ? ": " : "",
1076 (ld_errstr
&& *ld_errstr
) ? ld_errstr
: "");
1079 fs_give((void **)&wp_err
->error
);
1081 wp_err
->error
= cpystr(ebuf
);
1083 cancel_busy_cue(-1);
1085 q_status_message(SM_ORDER
, 3, 5, wp_err
->error
);
1086 display_message('x');
1087 dprint((2, "%s\n", ebuf
));
1094 ldap_unbind_ext(ld
, NULL
, NULL
);
1097 res
= NULL
; ld
= NULL
;
1102 cnt
= ldap_count_entries(ld
, res
);
1106 if(srch_res
== LDAP_TIMELIMIT_EXCEEDED
||
1107 srch_res
== LDAP_RESULTS_TOO_LARGE
||
1108 srch_res
== LDAP_TIMEOUT
||
1109 srch_res
== LDAP_SIZELIMIT_EXCEEDED
){
1110 wp_err
->wp_err_occurred
= 1;
1111 ld_errnum
= our_ldap_get_lderrno(ld
, NULL
, &ld_errstr
);
1113 snprintf(ebuf
, sizeof(ebuf
), _("LDAP partial results: %s%s%s%s"),
1114 ldap_err2string(ld_errnum
),
1116 (ld_errstr
&& *ld_errstr
) ? ": " : "",
1117 (ld_errstr
&& *ld_errstr
) ? ld_errstr
: "");
1118 dprint((2, "%s\n", ebuf
));
1120 fs_give((void **)&wp_err
->error
);
1122 wp_err
->error
= cpystr(ebuf
);
1124 cancel_busy_cue(-1);
1126 q_status_message(SM_ORDER
, 3, 5, wp_err
->error
);
1127 display_message('x');
1130 dprint((5, "Matched %d entries on %s\n",
1131 cnt
, serv
? serv
: "?"));
1133 serv_res
= (LDAP_SERV_RES_S
*)fs_get(sizeof(LDAP_SERV_RES_S
));
1134 memset((void *)serv_res
, 0, sizeof(*serv_res
));
1136 serv_res
->res
= res
;
1137 serv_res
->info_used
= copy_ldap_serv_info(info
);
1138 /* Save by reference? */
1140 snprintf(buf
, sizeof(buf
), "%s:%s", serv
, comatose(info
->port
));
1141 serv_res
->serv
= cpystr(buf
);
1144 serv_res
->serv
= NULL
;
1146 serv_res
->next
= NULL
;
1149 if(srch_res
== LDAP_TIMELIMIT_EXCEEDED
||
1150 srch_res
== LDAP_RESULTS_TOO_LARGE
||
1151 srch_res
== LDAP_TIMEOUT
||
1152 srch_res
== LDAP_SIZELIMIT_EXCEEDED
){
1153 wp_err
->wp_err_occurred
= 1;
1154 wp_err
->ldap_errno
= srch_res
;
1156 ld_errnum
= our_ldap_get_lderrno(ld
, NULL
, &ld_errstr
);
1158 snprintf(ebuf
, sizeof(ebuf
), _("LDAP search failed: %s%s%s%s"),
1159 ldap_err2string(ld_errnum
),
1161 (ld_errstr
&& *ld_errstr
) ? ": " : "",
1162 (ld_errstr
&& *ld_errstr
) ? ld_errstr
: "");
1165 fs_give((void **)&wp_err
->error
);
1167 wp_err
->error
= cpystr(ebuf
);
1169 cancel_busy_cue(-1);
1171 q_status_message(SM_ORDER
, 3, 5, wp_err
->error
);
1172 display_message('x');
1173 dprint((2, "%s\n", ebuf
));
1176 dprint((5, "Matched 0 entries on %s\n",
1177 serv
? serv
: "?"));
1184 ldap_unbind_ext(ld
, NULL
, NULL
);
1187 res
= NULL
; ld
= NULL
;
1192 fs_give((void **) &pwd
);
1196 cancel_busy_cue(-1);
1199 intr_handling_off();
1202 fs_give((void **)&serv
);
1204 fs_give((void **)&base
);
1206 fs_give((void **)&serv_errstr
);
1213 * Given a list of entries, present them to user so user may
1216 * Args head -- The head of the list of results
1217 * orig -- The string the user was searching for
1218 * result -- Returned pointer to chosen LDAP_SEARCH_WINNER or NULL
1219 * wp_err -- Error handling
1223 * -1 Exit chosen by user
1224 * -2 None of matched entries had an email address
1225 * -3 No matched entries
1226 * -4 Goback to Abook List chosen by user
1227 * -5 caller shouldn't free head
1230 ask_user_which_entry(LDAP_SERV_RES_S
*head
, char *orig
, LDAP_CHOOSE_S
**result
,
1231 WP_ERR_S
*wp_err
, LDAPLookupStyle style
)
1237 dprint((3, "ask_user_which(style=%s)\n",
1238 style
== AlwaysDisplayAndMailRequired
? "AlwaysDisplayAndMailRequired" :
1239 style
== AlwaysDisplay
? "AlwaysDisplay" :
1240 style
== DisplayIfTwo
? "DisplayIfTwo" :
1241 style
== DisplayForURL
? "DisplayForURL" :
1242 style
== DisplayIfOne
? "DisplayIfOne" : "?"));
1245 * Set up a screen for user to choose one entry.
1248 if(style
== AlwaysDisplay
|| style
== DisplayForURL
)
1249 snprintf(t
, sizeof(t
), "SEARCH RESULTS INDEX");
1254 snprintf(t
, sizeof(t
), _("SELECT ONE ADDRESS%s%s%s"),
1255 (orig
&& *orig
&& len
< 40) ? " FOR \"" : "",
1256 (orig
&& *orig
&& len
< 40) ? orig
: "",
1257 (orig
&& *orig
&& len
< 40) ? "\"" : "");
1260 memset(&ac
, 0, sizeof(ADDR_CHOOSE_S
));
1261 ac
.title
= cpystr(t
);
1264 retval
= ldap_addr_select(ps_global
, &ac
, result
, style
, wp_err
, orig
);
1270 case -1: /* Exit chosen by user */
1274 case -4: /* GoBack to AbookList chosen by user */
1282 if(style
!= AlwaysDisplay
){
1284 fs_give((void **)&wp_err
->error
);
1287 cpystr(_("None of the names matched on directory server has an email address"));
1288 q_status_message(SM_ORDER
, 3, 5, wp_err
->error
);
1289 display_message('x');
1295 if(style
== AlwaysDisplayAndMailRequired
){
1297 fs_give((void **)&wp_err
->error
);
1299 wp_err
->error
= cpystr(_("No matches on directory server"));
1300 q_status_message(SM_ORDER
, 3, 5, wp_err
->error
);
1301 display_message('x');
1307 fs_give((void **)&ac
.title
);
1314 address_from_ldap(LDAP_CHOOSE_S
*winning_e
)
1316 ADDRESS
*ret_a
= NULL
;
1322 ret_a
= mail_newaddr();
1323 for(a
= ldap_first_attribute(winning_e
->ld
, winning_e
->selected_entry
, &ber
);
1325 a
= ldap_next_attribute(winning_e
->ld
, winning_e
->selected_entry
, ber
)){
1328 struct berval
**vals
;
1330 dprint((9, "attribute: %s\n", a
? a
: "?"));
1331 if(!ret_a
->personal
&&
1332 strcmp(a
, winning_e
->info_used
->cnattr
) == 0){
1333 dprint((9, "Got cnattr:"));
1334 vals
= ldap_get_values_len(winning_e
->ld
, winning_e
->selected_entry
, a
);
1335 for(i
= 0; i
< ldap_count_values_len(vals
); i
++)
1337 vals
[i
] ? vals
[i
]->bv_val
: "?"));
1339 if(ALPINE_LDAP_can_use(vals
))
1340 ret_a
->personal
= cpystr(vals
[0]->bv_val
);
1342 ldap_value_free_len(vals
);
1344 else if(!ret_a
->mailbox
&&
1345 strcmp(a
, winning_e
->info_used
->mailattr
) == 0){
1346 dprint((9, "Got mailattr:"));
1347 vals
= ldap_get_values_len(winning_e
->ld
, winning_e
->selected_entry
, a
);
1348 for(i
= 0; i
< ldap_count_values_len(vals
); i
++)
1350 vals
[i
] ? vals
[i
]->bv_val
: "?"));
1353 if(ALPINE_LDAP_can_use(vals
)){
1354 if((p
= strindex(vals
[0]->bv_val
, '@')) != NULL
){
1355 ret_a
->host
= cpystr(p
+1);
1359 ret_a
->mailbox
= cpystr(vals
[0]->bv_val
);
1362 ldap_value_free_len(vals
);
1365 our_ldap_memfree(a
);
1374 * Break up the ldap-server string stored in the pinerc into its
1375 * parts. The structure is allocated here and should be freed by the caller.
1377 * The original string looks like
1378 * <servername>[:port] <SPACE> "/base=<base>/impl=1/..."
1380 * Args serv_str -- The original string from the pinerc to parse.
1382 * Returns A pointer to a structure with filled in answers.
1384 * Some of the members have defaults. If port is -1, that means to use
1385 * the default LDAP_PORT. If base is NULL, use "". Type and srch have
1386 * defaults defined in alpine.h. If cust is non-NULL, it overrides type and
1390 break_up_ldap_server(char *serv_str
)
1394 int i
, only_one
= 1;
1395 LDAP_SERV_S
*info
= NULL
;
1400 info
= (LDAP_SERV_S
*)fs_get(sizeof(LDAP_SERV_S
));
1403 * Initialize to defaults.
1405 memset((void *)info
, 0, sizeof(*info
));
1413 /* copy the whole string to work on */
1414 lserv
= cpystr(serv_str
);
1416 removing_trailing_white_space(lserv
);
1418 if(!lserv
|| !*lserv
|| *lserv
== '"'){
1420 fs_give((void **)&lserv
);
1423 free_ldap_server_info(&info
);
1429 while((tail
= strindex(tail
, SPACE
)) != NULL
){
1431 if(*tail
== '"' || *tail
== '/'){
1439 /* tail is the part after server[:port] <SPACE> */
1441 removing_leading_white_space(tail
);
1442 (void)removing_double_quotes(tail
);
1445 /* get the optional port number */
1446 if(only_one
&& (q
= strindex(lserv
, ':')) != NULL
){
1450 if((ldapport
= atoi(q
+1)) >= 0)
1451 info
->port
= ldapport
;
1454 /* use lserv for serv even though it has a few extra bytes alloced */
1458 /* get the search base */
1459 if((q
= srchstr(tail
, "/base=")) != NULL
)
1460 info
->base
= remove_backslash_escapes(q
+6);
1462 if((q
= srchstr(tail
, "/binddn=")) != NULL
)
1463 info
->binddn
= remove_backslash_escapes(q
+8);
1465 /* get the implicit parameter */
1466 if((q
= srchstr(tail
, "/impl=1")) != NULL
)
1469 /* get the rhs parameter */
1470 if((q
= srchstr(tail
, "/rhs=1")) != NULL
)
1473 /* get the ref parameter */
1474 if((q
= srchstr(tail
, "/ref=1")) != NULL
)
1477 /* get the nosub parameter */
1478 if((q
= srchstr(tail
, "/nosub=1")) != NULL
)
1481 /* get the tls parameter */
1482 if((q
= srchstr(tail
, "/tls=1")) != NULL
)
1485 /* get the tlsmust parameter */
1486 if((q
= srchstr(tail
, "/tlsm=1")) != NULL
)
1489 /* get the ldaps parameter */
1490 if((q
= srchstr(tail
, "/ldaps=1")) != NULL
)
1493 /* get the search type value */
1494 if((q
= srchstr(tail
, "/type=")) != NULL
){
1498 if((p
= strindex(q
, '/')) != NULL
)
1501 for(i
= 0; (v
= ldap_search_types(i
)); i
++)
1502 if(!strucmp(q
, v
->name
)){
1503 info
->type
= v
->value
;
1511 /* get the search rule value */
1512 if((q
= srchstr(tail
, "/srch=")) != NULL
){
1516 if((p
= strindex(q
, '/')) != NULL
)
1519 for(i
= 0; (v
= ldap_search_rules(i
)); i
++)
1520 if(!strucmp(q
, v
->name
)){
1521 info
->srch
= v
->value
;
1530 if((q
= srchstr(tail
, "/scope=")) != NULL
){
1534 if((p
= strindex(q
, '/')) != NULL
)
1537 for(i
= 0; (v
= ldap_search_scope(i
)); i
++)
1538 if(!strucmp(q
, v
->name
)){
1539 info
->scope
= v
->value
;
1547 /* get the time limit */
1548 if((q
= srchstr(tail
, "/time=")) != NULL
){
1550 if((p
= strindex(q
, '/')) != NULL
)
1553 /* This one's a number */
1557 err
= strtoval(q
, &i
, 0, 500, 0, tmp_20k_buf
, SIZEOF_20KBUF
, "ldap timelimit");
1559 dprint((1, "%s\n", err
? err
: "?"));
1569 /* get the size limit */
1570 if((q
= srchstr(tail
, "/size=")) != NULL
){
1572 if((p
= strindex(q
, '/')) != NULL
)
1575 /* This one's a number */
1579 err
= strtoval(q
, &i
, 0, 500, 0, tmp_20k_buf
, SIZEOF_20KBUF
, "ldap sizelimit");
1581 dprint((1, "%s\n", err
? err
: "?"));
1591 /* get the custom search filter */
1592 if((q
= srchstr(tail
, "/cust=")) != NULL
)
1593 info
->cust
= remove_backslash_escapes(q
+6);
1595 /* get the nickname */
1596 if((q
= srchstr(tail
, "/nick=")) != NULL
)
1597 info
->nick
= remove_backslash_escapes(q
+6);
1599 /* get the mail attribute name */
1600 if((q
= srchstr(tail
, "/matr=")) != NULL
)
1601 info
->mailattr
= remove_backslash_escapes(q
+6);
1603 /* get the sn attribute name */
1604 if((q
= srchstr(tail
, "/satr=")) != NULL
)
1605 info
->snattr
= remove_backslash_escapes(q
+6);
1607 /* get the gn attribute name */
1608 if((q
= srchstr(tail
, "/gatr=")) != NULL
)
1609 info
->gnattr
= remove_backslash_escapes(q
+6);
1611 /* get the cn attribute name */
1612 if((q
= srchstr(tail
, "/catr=")) != NULL
)
1613 info
->cnattr
= remove_backslash_escapes(q
+6);
1615 /* get the backup mail address */
1616 if((q
= srchstr(tail
, "/mail=")) != NULL
)
1617 info
->mail
= remove_backslash_escapes(q
+6);
1625 free_ldap_server_info(LDAP_SERV_S
**info
)
1629 fs_give((void **)&(*info
)->serv
);
1632 fs_give((void **)&(*info
)->base
);
1635 fs_give((void **)&(*info
)->cust
);
1638 fs_give((void **)&(*info
)->binddn
);
1641 fs_give((void **)&(*info
)->nick
);
1644 fs_give((void **)&(*info
)->mail
);
1646 if((*info
)->mailattr
)
1647 fs_give((void **)&(*info
)->mailattr
);
1650 fs_give((void **)&(*info
)->snattr
);
1653 fs_give((void **)&(*info
)->gnattr
);
1656 fs_give((void **)&(*info
)->cnattr
);
1658 fs_give((void **)info
);
1665 copy_ldap_serv_info(LDAP_SERV_S
*src
)
1667 LDAP_SERV_S
*info
= NULL
;
1670 info
= (LDAP_SERV_S
*) fs_get(sizeof(*info
));
1673 * Initialize to defaults.
1675 memset((void *)info
, 0, sizeof(*info
));
1677 info
->serv
= src
->serv
? cpystr(src
->serv
) : NULL
;
1678 info
->base
= src
->base
? cpystr(src
->base
) : NULL
;
1679 info
->cust
= src
->cust
? cpystr(src
->cust
) : NULL
;
1680 info
->binddn
= src
->binddn
? cpystr(src
->binddn
) : NULL
;
1681 info
->nick
= src
->nick
? cpystr(src
->nick
) : NULL
;
1682 info
->mail
= src
->mail
? cpystr(src
->mail
) : NULL
;
1683 info
->mailattr
= cpystr((src
->mailattr
&& src
->mailattr
[0])
1684 ? src
->mailattr
: DEF_LDAP_MAILATTR
);
1685 info
->snattr
= cpystr((src
->snattr
&& src
->snattr
[0])
1686 ? src
->snattr
: DEF_LDAP_SNATTR
);
1687 info
->gnattr
= cpystr((src
->gnattr
&& src
->gnattr
[0])
1688 ? src
->gnattr
: DEF_LDAP_GNATTR
);
1689 info
->cnattr
= cpystr((src
->cnattr
&& src
->cnattr
[0])
1690 ? src
->cnattr
: DEF_LDAP_CNATTR
);
1692 info
->port
= (src
->port
< 0) ? LDAP_PORT
: src
->port
;
1693 info
->time
= (src
->time
< 0) ? DEF_LDAP_TIME
: src
->time
;
1694 info
->size
= (src
->size
< 0) ? DEF_LDAP_SIZE
: src
->size
;
1695 info
->type
= (src
->type
< 0) ? DEF_LDAP_TYPE
: src
->type
;
1696 info
->srch
= (src
->srch
< 0) ? DEF_LDAP_SRCH
: src
->srch
;
1697 info
->scope
= (src
->scope
< 0) ? DEF_LDAP_SCOPE
: src
->scope
;
1698 info
->impl
= src
->impl
;
1699 info
->rhs
= src
->rhs
;
1700 info
->ref
= src
->ref
;
1701 info
->nosub
= src
->nosub
;
1702 info
->tls
= src
->tls
;
1710 free_ldap_result_list(LDAP_SERV_RES_S
**r
)
1713 free_ldap_result_list(&(*r
)->next
);
1715 ldap_msgfree((*r
)->res
);
1718 ldap_unbind((*r
)->ld
);
1720 ldap_unbind_ext((*r
)->ld
, NULL
, NULL
);
1723 free_ldap_server_info(&(*r
)->info_used
);
1725 fs_give((void **) &(*r
)->serv
);
1727 fs_give((void **) r
);
1733 * Mask API differences.
1736 our_ldap_memfree(void *a
)
1746 * Mask API differences.
1749 our_ldap_dn_memfree(void *a
)
1751 #if defined(_WINDOWS)
1770 our_ldap_get_lderrno(LDAP
*ld
, char **m
, char **s
)
1774 #if (LDAPAPI >= 2000)
1775 if(ldap_get_option(ld
, LDAP_OPT_ERROR_NUMBER
, (void *)&ret
) == 0){
1777 ldap_get_option(ld
, LDAP_OPT_ERROR_STRING
, (void *)s
);
1779 #elif (LDAPAPI >= 15)
1780 ret
= ldap_get_lderrno(ld
, m
, s
);
1795 our_ldap_set_lderrno(LDAP
*ld
, int e
, char *m
, char *s
)
1799 #if (LDAPAPI >= 2000)
1800 if(ldap_set_option(ld
, LDAP_OPT_ERROR_NUMBER
, (void *)&e
) == 0)
1803 (void)ldap_get_option(ld
, LDAP_OPT_ERROR_NUMBER
, (void *)&ret
);
1804 #elif (LDAPAPI >= 15)
1805 ret
= ldap_set_lderrno(ld
, e
, m
, s
);
1807 /* this is all we care about */
1820 our_ldap_set_option(LDAP
*ld
, int option
, void *optdata
)
1825 ret
= ldap_set_option(ld
, option
, optdata
);
1828 case LDAP_OPT_TIMELIMIT
:
1829 ld
->ld_timelimit
= *(int *)optdata
;
1832 case LDAP_OPT_SIZELIMIT
:
1833 ld
->ld_sizelimit
= *(int *)optdata
;
1836 case LDAP_OPT_RESTART
:
1838 ld
->ld_options
|= LDAP_OPT_RESTART
;
1840 ld
->ld_options
&= ~LDAP_OPT_RESTART
;
1845 * Does nothing here. There is only one protocol version supported.
1847 case LDAP_OPT_PROTOCOL_VERSION
:
1852 alpine_panic("LDAP function not implemented");
1861 * Returns 1 if we can use LDAP version 3 protocol.
1864 ldap_v3_is_supported(LDAP
*ld
)
1874 static struct tl_table ldap_trans_table
[]={
1876 * TRANSLATORS: This is a list of LDAP attributes with translations to present
1877 * to the user. For example the attribute mail is Email Address and the attribute
1880 {"mail", N_("Email Address")},
1881 #define LDAP_MAIL_ATTR 0
1882 {"sn", N_("Surname")},
1883 #define LDAP_SN_ATTR 1
1884 {"givenName", N_("Given Name")},
1885 #define LDAP_GN_ATTR 2
1887 #define LDAP_CN_ATTR 3
1888 {"electronicmail", N_("Email Address")},
1889 #define LDAP_EMAIL_ATTR 4
1890 {"o", N_("Organization")},
1892 {"c", N_("Country")},
1893 {"st", N_("State or Province")},
1894 {"l", N_("Locality")},
1895 {"objectClass", N_("Object Class")},
1896 {"title", N_("Title")},
1897 {"departmentNumber", N_("Department")},
1898 {"postalAddress", N_("Postal Address")},
1899 {"homePostalAddress", N_("Home Address")},
1900 {"mailStop", N_("Mail Stop")},
1901 {"telephoneNumber", N_("Voice Telephone")},
1902 {"homePhone", N_("Home Telephone")},
1903 {"officePhone", N_("Office Telephone")},
1904 {"facsimileTelephoneNumber", N_("FAX Telephone")},
1905 {"mobile", N_("Mobile Telephone")},
1906 {"voiceMailTelephoneNumber", N_("Voice Mail")},
1907 {"pager", N_("Pager")},
1908 {"roomNumber", N_("Room Number")},
1909 {"uid", N_("User ID")},
1910 {"userCertificate", N_("User Certificate")},
1915 ldap_translate(char *a
, LDAP_SERV_S
*info_used
)
1917 char *s
, *ret_a
= a
;
1920 if((s
= strchr(a
, ';')) != NULL
)
1924 if(info_used
->mailattr
&& strucmp(info_used
->mailattr
, a
) == 0)
1925 ret_a
= _(ldap_trans_table
[LDAP_MAIL_ATTR
].translated
);
1926 else if(info_used
->snattr
&& strucmp(info_used
->snattr
, a
) == 0)
1927 ret_a
= _(ldap_trans_table
[LDAP_SN_ATTR
].translated
);
1928 else if(info_used
->gnattr
&& strucmp(info_used
->gnattr
, a
) == 0)
1929 ret_a
= _(ldap_trans_table
[LDAP_GN_ATTR
].translated
);
1930 else if(info_used
->cnattr
&& strucmp(info_used
->cnattr
, a
) == 0)
1931 ret_a
= _(ldap_trans_table
[LDAP_CN_ATTR
].translated
);
1934 for(i
= 0; ldap_trans_table
[i
].ldap_ese
; i
++){
1937 case LDAP_MAIL_ATTR
:
1941 case LDAP_EMAIL_ATTR
:
1945 if(strucmp(ldap_trans_table
[i
].ldap_ese
, a
) == 0)
1946 ret_a
= _(ldap_trans_table
[i
].translated
);
1956 berval_to_array(struct berval
**v
)
1961 if(v
== NULL
) return rv
;
1962 len
= ldap_count_values_len(v
);
1964 rv
= fs_get((len
+1)*sizeof(char *));
1965 for(i
= 0; i
< len
; i
++)
1966 if(ALPINE_LDAP_can_use_num(v
, i
))
1967 rv
[i
] = cpystr(v
[i
]->bv_val
);
1975 #endif /* ENABLE_LDAP */