diff options
author | Eduardo Chappa <echappa@gmx.com> | 2013-02-03 00:59:38 -0700 |
---|---|---|
committer | Eduardo Chappa <echappa@gmx.com> | 2013-02-03 00:59:38 -0700 |
commit | 094ca96844842928810f14844413109fc6cdd890 (patch) | |
tree | e60efbb980f38ba9308ccb4fb2b77b87bbc115f3 /pith/ldap.c | |
download | alpine-094ca96844842928810f14844413109fc6cdd890.tar.xz |
Initial Alpine Version
Diffstat (limited to 'pith/ldap.c')
-rw-r--r-- | pith/ldap.c | 1798 |
1 files changed, 1798 insertions, 0 deletions
diff --git a/pith/ldap.c b/pith/ldap.c new file mode 100644 index 00000000..d40641e4 --- /dev/null +++ b/pith/ldap.c @@ -0,0 +1,1798 @@ +#if !defined(lint) && !defined(DOS) +static char rcsid[] = "$Id: ldap.c 1204 2009-02-02 19:54:23Z hubert@u.washington.edu $"; +#endif + +/* + * ======================================================================== + * Copyright 2006-2008 University of Washington + * Copyright 2013 Eduardo Chappa + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include "../pith/headers.h" +#include "../pith/ldap.h" +#include "../pith/state.h" +#include "../pith/conf.h" +#include "../pith/status.h" +#include "../pith/util.h" +#include "../pith/imap.h" +#include "../pith/busy.h" +#include "../pith/signal.h" +#include "../pith/ablookup.h" + + +/* + * Until we can think of a better way to do this. If user exits from an + * ldap address selection screen we want to return -1 so that call_builder + * will stay on the same line. Might want to use another return value + * for the builder so that call_builder more fully understands what we're + * up to. + */ +int wp_exit; +int wp_nobail; + + +#ifdef ENABLE_LDAP +/* + * Hook to allow user input on whether or not to save chosen LDAP result + */ +void (*pith_opt_save_ldap_entry)(struct pine *, LDAP_CHOOSE_S *, int); + + +/* + * Internal prototypes + */ +LDAP_SERV_RES_S *ldap_lookup(LDAP_SERV_S *, char *, CUSTOM_FILT_S *, WP_ERR_S *, int); +LDAP_SERV_S *copy_ldap_serv_info(LDAP_SERV_S *); +int our_ldap_get_lderrno(LDAP *, char **, char **); +int our_ldap_set_lderrno(LDAP *, int, char *, char *); +#endif /* ENABLE_LDAP */ + + +/* + * This function does white pages lookups. + * + * Args string -- the string to use in the lookup + * + * Returns NULL -- lookup failed + * Address -- A single address is returned if lookup was successfull. + */ +ADDRESS * +wp_lookups(char *string, WP_ERR_S *wp_err, int recursing) +{ + ADDRESS *ret_a = NULL; + char ebuf[200]; +#ifdef ENABLE_LDAP + LDAP_SERV_RES_S *free_when_done = NULL; + LDAPLookupStyle style; + LDAP_CHOOSE_S *winning_e = NULL; + LDAP_SERV_S *info = NULL; + static char *fakedomain = "@"; + char *tmp_a_string; + int auwe_rv = 0; + + /* + * Runtime ldap lookup of addrbook entry. + */ + if(!strncmp(string, RUN_LDAP, LEN_RL)){ + LDAP_SERV_RES_S *head_of_result_list; + + info = break_up_ldap_server(string+LEN_RL); + head_of_result_list = ldap_lookup(info, "", NULL, wp_err, 1); + + if(head_of_result_list){ + if(!wp_exit) + auwe_rv = ask_user_which_entry(head_of_result_list, string, + &winning_e, + wp_err, + wp_err->wp_err_occurred + ? DisplayIfOne : DisplayIfTwo); + + if(auwe_rv != -5) + free_when_done = head_of_result_list; + } + else{ + wp_err->wp_err_occurred = 1; + if(wp_err->error){ + q_status_message(SM_ORDER, 3, 5, wp_err->error); + display_message('x'); + fs_give((void **)&wp_err->error); + } + + /* try using backup email address */ + if(info && info->mail && *info->mail){ + tmp_a_string = cpystr(info->mail); + rfc822_parse_adrlist(&ret_a, tmp_a_string, fakedomain); + fs_give((void **)&tmp_a_string); + + wp_err->error = + cpystr(_("Directory lookup failed, using backup email address")); + } + else{ + /* + * Do this so the awful LDAP: ... string won't show up + * in the composer. This shouldn't actually happen in + * real life, so we're not too concerned about it. If we + * were we'd want to recover the nickname we started with + * somehow, or something like that. + */ + ret_a = mail_newaddr(); + ret_a->mailbox = cpystr("missing-username"); + wp_err->error = cpystr(_("Directory lookup failed, no backup email address available")); + } + + q_status_message(SM_ORDER, 3, 5, wp_err->error); + display_message('x'); + } + } + else{ + style = F_ON(F_COMPOSE_REJECTS_UNQUAL, ps_global) + ? DisplayIfOne : DisplayIfTwo; + auwe_rv = ldap_lookup_all(string, as.n_serv, recursing, style, NULL, + &winning_e, wp_err, &free_when_done); + } + + if(winning_e && auwe_rv != -5){ + ret_a = address_from_ldap(winning_e); + + if(pith_opt_save_ldap_entry && ret_a && F_ON(F_ADD_LDAP_TO_ABOOK, ps_global) && !info) + (*pith_opt_save_ldap_entry)(ps_global, winning_e, 1); + + + fs_give((void **)&winning_e); + } + + /* Info's only set in the RUN_LDAP case */ + if(info){ + if(ret_a && ret_a->host){ + ADDRESS *backup = NULL; + + if(info->mail && *info->mail) + rfc822_parse_adrlist(&backup, info->mail, fakedomain); + + if(!backup || !address_is_same(ret_a, backup)){ + if(wp_err->error){ + q_status_message(SM_ORDER, 3, 5, wp_err->error); + display_message('x'); + fs_give((void **)&wp_err->error); + } + + snprintf(ebuf, sizeof(ebuf), + _("Warning: current address different from saved address (%s)"), + info->mail); + wp_err->error = cpystr(ebuf); + q_status_message(SM_ORDER, 3, 5, wp_err->error); + display_message('x'); + } + + if(backup) + mail_free_address(&backup); + } + + free_ldap_server_info(&info); + } + + if(free_when_done) + free_ldap_result_list(&free_when_done); +#endif /* ENABLE_LDAP */ + + if(ret_a){ + if(ret_a->mailbox){ /* indicates there was a MAIL attribute */ + if(!ret_a->host || !ret_a->host[0]){ + if(ret_a->host) + fs_give((void **)&ret_a->host); + + ret_a->host = cpystr("missing-hostname"); + wp_err->wp_err_occurred = 1; + if(wp_err->error) + fs_give((void **)&wp_err->error); + + wp_err->error = cpystr(_("Missing hostname in LDAP address")); + q_status_message(SM_ORDER, 3, 5, wp_err->error); + display_message('x'); + } + + if(!ret_a->mailbox[0]){ + if(ret_a->mailbox) + fs_give((void **)&ret_a->mailbox); + + ret_a->mailbox = cpystr("missing-username"); + wp_err->wp_err_occurred = 1; + if(wp_err->error) + fs_give((void **)&wp_err->error); + + wp_err->error = cpystr(_("Missing username in LDAP address")); + q_status_message(SM_ORDER, 3, 5, wp_err->error); + display_message('x'); + } + } + else{ + wp_err->wp_err_occurred = 1; + + if(wp_err->error) + fs_give((void **)&wp_err->error); + + snprintf(ebuf, sizeof(ebuf), _("No email address available for \"%s\""), + (ret_a->personal && *ret_a->personal) + ? ret_a->personal + : "selected entry"); + wp_err->error = cpystr(ebuf); + q_status_message(SM_ORDER, 3, 5, wp_err->error); + display_message('x'); + mail_free_address(&ret_a); + ret_a = NULL; + } + } + + return(ret_a); +} + + +#ifdef ENABLE_LDAP + +/* + * Goes through all servers looking up string. + * + * Args string -- String to search for + * who -- Which servers to look on + * style -- Sometimes we want to display no matter what, sometimes + * only if more than one entry, sometimes only if email + * addresses, ... + * + * The possible styles are: + * AlwaysDisplayAndMailRequired: This happens when user ^T's from + * composer to address book screen, and + * then queries directory server. + * AlwaysDisplay: This happens when user is browsing + * in address book maintenance screen and + * then queries directory server. + * DisplayIfOne: These two come from implicit lookups + * DisplayIfTwo: from build_address. If the compose rejects + * unqualified feature is on we get the + * DisplayIfOne, otherwise IfTwo. + * + * cust -- Use this custom filter instead of configured filters + * winning_e -- Return value + * wp_err -- Error handling + * free_when_done -- Caller needs to free this + * + * Returns -- value returned by ask_user_which_entry + */ +int +ldap_lookup_all(char *string, int who, int recursing, LDAPLookupStyle style, + CUSTOM_FILT_S *cust, LDAP_CHOOSE_S **winning_e, + WP_ERR_S *wp_err, LDAP_SERV_RES_S **free_when_done) +{ + int retval = -1; + LDAP_SERV_RES_S *head_of_result_list = NULL; + + wp_exit = wp_nobail = 0; + if(free_when_done) + *free_when_done = NULL; + + head_of_result_list = ldap_lookup_all_work(string, who, recursing, + cust, wp_err); + + if(!wp_exit) + retval = ask_user_which_entry(head_of_result_list, string, winning_e, + wp_err, + (wp_err->wp_err_occurred && + style == DisplayIfTwo) ? DisplayIfOne + : style); + + /* + * Because winning_e probably points into the result list + * we need to leave the result list alone and have the caller + * free it after they are done with winning_e. + */ + if(retval != -5 && free_when_done) + *free_when_done = head_of_result_list; + + return(retval); +} + + +/* + * Goes through all servers looking up string. + * + * Args string -- String to search for + * who -- Which servers to look on + * cust -- Use this custom filter instead of configured filters + * wp_err -- Error handling + * + * Returns -- list of results that needs to be freed by caller + */ +LDAP_SERV_RES_S * +ldap_lookup_all_work(char *string, int who, int recursing, + CUSTOM_FILT_S *cust, WP_ERR_S *wp_err) +{ + int i; + LDAP_SERV_RES_S *serv_res; + LDAP_SERV_RES_S *rr, *head_of_result_list = NULL; + + /* If there is at least one server */ + if(ps_global->VAR_LDAP_SERVERS && ps_global->VAR_LDAP_SERVERS[0] && + ps_global->VAR_LDAP_SERVERS[0][0]){ + int how_many_servers; + + for(i = 0; ps_global->VAR_LDAP_SERVERS[i] && + ps_global->VAR_LDAP_SERVERS[i][0]; i++) + ; + + how_many_servers = i; + + /* For each server in list */ + for(i = 0; !wp_exit && ps_global->VAR_LDAP_SERVERS[i] && + ps_global->VAR_LDAP_SERVERS[i][0]; i++){ + LDAP_SERV_S *info; + + dprint((6, "ldap_lookup_all_work: lookup on server (%.256s)\n", + ps_global->VAR_LDAP_SERVERS[i])); + info = NULL; + if(who == -1 || who == i || who == as.n_serv) + info = break_up_ldap_server(ps_global->VAR_LDAP_SERVERS[i]); + + /* + * Who tells us which servers to look on. + * Who == -1 means all servers. + * Who == 0 means server[0]. + * Who == 1 means server[1]. + * Who == as.n_serv means query on those with impl set. + */ + if(!(who == -1 || who == i || + (who == as.n_serv && !recursing && info && info->impl) || + (who == as.n_serv && recursing && info && info->rhs))){ + + if(info) + free_ldap_server_info(&info); + + continue; + } + + dprint((6, "ldap_lookup_all_work: ldap_lookup (server: %.20s...)(string: %s)\n", + ps_global->VAR_LDAP_SERVERS[i], string)); + serv_res = ldap_lookup(info, string, cust, + wp_err, how_many_servers > 1); + if(serv_res){ + /* Add new one to end of list so they come in the right order */ + for(rr = head_of_result_list; rr && rr->next; rr = rr->next) + ; + + if(rr) + rr->next = serv_res; + else + head_of_result_list = serv_res; + } + + if(info) + free_ldap_server_info(&info); + } + } + + return(head_of_result_list); +} + + +/* + * Do an LDAP lookup to the server described in the info argument. + * + * Args info -- LDAP info for server. + * string -- String to lookup. + * cust -- Possible custom filter description. + * wp_err -- We set this is we get a white pages error. + * name_in_error -- Caller sets this if they want us to include the server + * name in error messages. + * + * Returns Results of lookup, NULL if lookup failed. + */ +LDAP_SERV_RES_S * +ldap_lookup(LDAP_SERV_S *info, char *string, CUSTOM_FILT_S *cust, + WP_ERR_S *wp_err, int name_in_error) +{ + char ebuf[900]; + char buf[900]; + char *serv, *base, *serv_errstr; + char *mailattr, *snattr, *gnattr, *cnattr; + int we_cancel = 0, we_turned_on = 0; + LDAP_SERV_RES_S *serv_res = NULL; + LDAP *ld; + long pwdtrial = 0L; + int ld_errnum; + char *ld_errstr; + + + if(!info) + return(serv_res); + + serv = cpystr((info->serv && *info->serv) ? info->serv : "?"); + + if(name_in_error) + snprintf(ebuf, sizeof(ebuf), " (%s)", + (info->nick && *info->nick) ? info->nick : serv); + else + ebuf[0] = '\0'; + + serv_errstr = cpystr(ebuf); + base = cpystr(info->base ? info->base : ""); + + if(info->port < 0) + info->port = LDAP_PORT; + + if(info->type < 0) + info->type = DEF_LDAP_TYPE; + + if(info->srch < 0) + info->srch = DEF_LDAP_SRCH; + + if(info->time < 0) + info->time = DEF_LDAP_TIME; + + if(info->size < 0) + info->size = DEF_LDAP_SIZE; + + if(info->scope < 0) + info->scope = DEF_LDAP_SCOPE; + + mailattr = (info->mailattr && info->mailattr[0]) ? info->mailattr + : DEF_LDAP_MAILATTR; + snattr = (info->snattr && info->snattr[0]) ? info->snattr + : DEF_LDAP_SNATTR; + gnattr = (info->gnattr && info->gnattr[0]) ? info->gnattr + : DEF_LDAP_GNATTR; + cnattr = (info->cnattr && info->cnattr[0]) ? info->cnattr + : DEF_LDAP_CNATTR; + + /* + * We may want to keep ldap handles open, but at least for + * now, re-open them every time. + */ + + dprint((3, "ldap_lookup(%s,%d)\n", serv ? serv : "?", info->port)); + + snprintf(ebuf, sizeof(ebuf), "Searching%s%s%s on %s", + (string && *string) ? " for \"" : "", + (string && *string) ? string : "", + (string && *string) ? "\"" : "", + serv); + we_turned_on = intr_handling_on(); /* this erases keymenu */ + we_cancel = busy_cue(ebuf, NULL, 0); + if(wp_err->mangled) + *(wp_err->mangled) = 1; + +#ifdef _SOLARIS_SDK + if(info->tls || info->tlsmust) + ldapssl_client_init(NULL, NULL); + if((ld = ldap_init(serv, info->port)) == NULL) +#else +#if (LDAPAPI >= 11) + if((ld = ldap_init(serv, info->port)) == NULL) +#else + if((ld = ldap_open(serv, info->port)) == NULL) +#endif +#endif + { + /* TRANSLATORS: All of the three args together are an error message */ + snprintf(ebuf, sizeof(ebuf), _("Access to LDAP server failed: %s%s(%s)"), + errno ? error_description(errno) : "", + errno ? " " : "", + serv); + wp_err->wp_err_occurred = 1; + if(wp_err->error) + fs_give((void **)&wp_err->error); + + wp_err->error = cpystr(ebuf); + if(we_cancel) + cancel_busy_cue(-1); + + q_status_message(SM_ORDER, 3, 5, wp_err->error); + display_message('x'); + dprint((2, "%s\n", ebuf)); + } + else if(!ps_global->intr_pending){ + int proto = 3, tlsmustbail = 0; + char pwd[NETMAXPASSWD], user[NETMAXUSER]; + char *passwd = NULL; + char hostbuf[1024]; + NETMBX mb; +#ifndef _WINDOWS + int rc; +#endif + + memset(&mb, 0, sizeof(mb)); + +#ifdef _SOLARIS_SDK + if(info->tls || info->tlsmust) + rc = ldapssl_install_routines(ld); +#endif + + if(ldap_v3_is_supported(ld) && + our_ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &proto) == 0){ + dprint((5, "ldap: using version 3 protocol\n")); + } + + /* + * If we don't set RESTART then the select() waiting for the answer + * in libldap will be interrupted and stopped by our busy_cue. + */ + our_ldap_set_option(ld, LDAP_OPT_RESTART, LDAP_OPT_ON); + + /* + * If we need to authenticate, get the password. We are not + * supporting SASL authentication, just LDAP simple. + */ + if(info->binddn && info->binddn[0]){ + char pmt[500]; + char *space; + + snprintf(hostbuf, sizeof(hostbuf), "{%s}dummy", info->serv ? info->serv : "?"); + + /* + * We don't handle multiple space-delimited hosts well. + * We don't know which we're asking for a password for. + * We're not connected yet so we can't know. + */ + if((space=strindex(hostbuf, ' ')) != NULL) + *space = '\0'; + + mail_valid_net_parse_work(hostbuf, &mb, "ldap"); + mb.port = info->port; + mb.tlsflag = (info->tls || info->tlsmust) ? 1 : 0; + +try_password_again: + + if(mb.tlsflag + && (pwdtrial > 0 || +#ifndef _WINDOWS +#ifdef _SOLARIS_SDK + (rc == LDAP_SUCCESS) +#else /* !_SOLARIS_SDK */ + ((rc=ldap_start_tls_s(ld, NULL, NULL)) == LDAP_SUCCESS) +#endif /* !_SOLARIS_SDK */ +#else /* _WINDOWS */ + 0 /* TODO: find a way to do this in Windows */ +#endif /* _WINDOWS */ + )) + mb.tlsflag = 1; + else + mb.tlsflag = 0; + + if((info->tls || info->tlsmust) && !mb.tlsflag){ + q_status_message(SM_ORDER, 3, 5, "Not able to start TLS encryption for LDAP server"); + if(info->tlsmust) + tlsmustbail++; + } + + if(!tlsmustbail){ + snprintf(pmt, sizeof(pmt), " %s", (info->nick && *info->nick) ? info->nick : serv); + mm_login_work(&mb, user, pwd, pwdtrial, pmt, info->binddn); + if(pwd && pwd[0]) + passwd = pwd; + } + } + + + /* + * LDAPv2 requires the bind. v3 doesn't require it but we want + * to tell the server we're v3 if the server supports v3, and if the + * server doesn't support v3 the bind is required. + */ + if(tlsmustbail || ldap_simple_bind_s(ld, info->binddn, passwd) != LDAP_SUCCESS){ + wp_err->wp_err_occurred = 1; + + ld_errnum = our_ldap_get_lderrno(ld, NULL, &ld_errstr); + + if(!tlsmustbail && info->binddn && info->binddn[0] && pwdtrial < 2L + && ld_errnum == LDAP_INVALID_CREDENTIALS){ + pwdtrial++; + q_status_message(SM_ORDER, 3, 5, _("Invalid password")); + goto try_password_again; + } + + snprintf(ebuf, sizeof(ebuf), _("LDAP server failed: %s%s%s%s"), + ldap_err2string(ld_errnum), + serv_errstr, + (ld_errstr && *ld_errstr) ? ": " : "", + (ld_errstr && *ld_errstr) ? ld_errstr : ""); + + if(wp_err->error) + fs_give((void **)&wp_err->error); + + if(we_cancel) + cancel_busy_cue(-1); + + ldap_unbind(ld); + wp_err->error = cpystr(ebuf); + q_status_message(SM_ORDER, 3, 5, wp_err->error); + display_message('x'); + dprint((2, "%s\n", ebuf)); + } + else if(!ps_global->intr_pending){ + int srch_res, args, slen, flen; +#define TEMPLATELEN 512 + char filt_template[TEMPLATELEN + 1]; + char filt_format[2*TEMPLATELEN + 1]; + char filter[2*TEMPLATELEN + 1]; + char scp[2*TEMPLATELEN + 1]; + char *p, *q; + LDAPMessage *res = NULL; + int intr_happened = 0; + int tl; + + tl = (info->time == 0) ? info->time : info->time + 10; + + our_ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &tl); + our_ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &info->size); + + /* + * If a custom filter has been passed in and it doesn't include a + * request to combine it with the configured filter, then replace + * any configured filter with the passed in filter. + */ + if(cust && cust->filt && !cust->combine){ + if(info->cust) + fs_give((void **)&info->cust); + + info->cust = cpystr(cust->filt); + } + + if(info->cust && *info->cust){ /* use custom filter if present */ + strncpy(filt_template, info->cust, sizeof(filt_template)); + filt_template[sizeof(filt_template)-1] = '\0'; + } + else{ /* else use configured filter */ + switch(info->type){ + case LDAP_TYPE_SUR: + snprintf(filt_template, sizeof(filt_template), "(%s=%%s)", snattr); + break; + case LDAP_TYPE_GIVEN: + snprintf(filt_template, sizeof(filt_template), "(%s=%%s)", gnattr); + break; + case LDAP_TYPE_EMAIL: + snprintf(filt_template, sizeof(filt_template), "(%s=%%s)", mailattr); + break; + case LDAP_TYPE_CN_EMAIL: + snprintf(filt_template, sizeof(filt_template), "(|(%s=%%s)(%s=%%s))", cnattr, + mailattr); + break; + case LDAP_TYPE_SUR_GIVEN: + snprintf(filt_template, sizeof(filt_template), "(|(%s=%%s)(%s=%%s))", + snattr, gnattr); + break; + case LDAP_TYPE_SEVERAL: + snprintf(filt_template, sizeof(filt_template), + "(|(%s=%%s)(%s=%%s)(%s=%%s)(%s=%%s))", + cnattr, mailattr, snattr, gnattr); + break; + default: + case LDAP_TYPE_CN: + snprintf(filt_template, sizeof(filt_template), "(%s=%%s)", cnattr); + break; + } + } + + /* just copy if custom */ + if(info->cust && *info->cust) + info->srch = LDAP_SRCH_EQUALS; + + p = filt_template; + q = filt_format; + memset((void *)filt_format, 0, sizeof(filt_format)); + args = 0; + while(*p && (q - filt_format) + 4 < sizeof(filt_format)){ + if(*p == '%' && *(p+1) == 's'){ + args++; + switch(info->srch){ + /* Exact match */ + case LDAP_SRCH_EQUALS: + *q++ = *p++; + *q++ = *p++; + break; + + /* Append wildcard after %s */ + case LDAP_SRCH_BEGINS: + *q++ = *p++; + *q++ = *p++; + *q++ = '*'; + break; + + /* Insert wildcard before %s */ + case LDAP_SRCH_ENDS: + *q++ = '*'; + *q++ = *p++; + *q++ = *p++; + break; + + /* Put wildcard before and after %s */ + default: + case LDAP_SRCH_CONTAINS: + *q++ = '*'; + *q++ = *p++; + *q++ = *p++; + *q++ = '*'; + break; + } + } + else + *q++ = *p++; + } + + if(q - filt_format < sizeof(filt_format)) + *q = '\0'; + + filt_format[sizeof(filt_format)-1] = '\0'; + + /* + * If combine is lit we put the custom filter and the filt_format + * filter and combine them with an &. + */ + if(cust && cust->filt && cust->combine){ + char *combined; + size_t l; + + l = strlen(filt_format) + strlen(cust->filt) + 3; + combined = (char *) fs_get((l+1) * sizeof(char)); + snprintf(combined, l+1, "(&%s%s)", cust->filt, filt_format); + strncpy(filt_format, combined, sizeof(filt_format)); + filt_format[sizeof(filt_format)-1] = '\0'; + fs_give((void **) &combined); + } + + /* + * Ad hoc attempt to make "Steve Hubert" match + * Steven Hubert but not Steven Shubert. + * We replace a <SPACE> with * <SPACE> (not * <SPACE> *). + */ + memset((void *)scp, 0, sizeof(scp)); + if(info->nosub) + strncpy(scp, string, sizeof(scp)); + else{ + p = string; + q = scp; + while(*p && (q - scp) + 1 < sizeof(scp)){ + if(*p == SPACE && *(p+1) != SPACE){ + *q++ = '*'; + *q++ = *p++; + } + else + *q++ = *p++; + } + } + + scp[sizeof(scp)-1] = '\0'; + + slen = strlen(scp); + flen = strlen(filt_format); + /* truncate string if it will overflow filter */ + if(args*slen + flen - 2*args > sizeof(filter)-1) + scp[(sizeof(filter)-1 - flen)/args] = '\0'; + + /* + * Replace %s's with scp. + */ + switch(args){ + case 0: + snprintf(filter, sizeof(filter), filt_format); + break; + case 1: + snprintf(filter, sizeof(filter), filt_format, scp); + break; + case 2: + snprintf(filter, sizeof(filter), filt_format, scp, scp); + break; + case 3: + snprintf(filter, sizeof(filter), filt_format, scp, scp, scp); + break; + case 4: + snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp); + break; + case 5: + snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp); + break; + case 6: + snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp, scp); + break; + case 7: + snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp, scp, scp); + break; + case 8: + snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp, scp, scp, + scp); + break; + case 9: + snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp, scp, scp, + scp, scp); + break; + case 10: + default: + snprintf(filter, sizeof(filter), filt_format, scp, scp, scp, scp, scp, scp, scp, + scp, scp, scp); + break; + } + + /* replace double *'s with single *'s in filter */ + for(p = q = filter; *p; p++) + if(*p != '*' || p == filter || *(p-1) != '*') + *q++ = *p; + + *q = '\0'; + + (void) removing_double_quotes(base); + dprint((5, "about to ldap_search(\"%s\", %s)\n", + base ? base : "?", filter ? filter : "?")); + if(ps_global->intr_pending) + srch_res = LDAP_PROTOCOL_ERROR; + else{ + int msgid; + time_t start_time; + + start_time = time((time_t *)0); + + dprint((6, "ldap_lookup: calling ldap_search\n")); + msgid = ldap_search(ld, base, info->scope, filter, NULL, 0); + + if(msgid == -1) + srch_res = our_ldap_get_lderrno(ld, NULL, NULL); + else{ + int lres; + /* + * Warning: struct timeval is not portable. However, since it is + * part of LDAP api it must be portable to all platforms LDAP + * has been ported to. + */ + struct timeval t; + + t.tv_sec = 1; t.tv_usec = 0; + + do { + if(ps_global->intr_pending) + intr_happened = 1; + + dprint((6, "ldap_result(id=%d): ", msgid)); + if((lres=ldap_result(ld, msgid, LDAP_MSG_ALL, &t, &res)) == -1){ + /* error */ + srch_res = our_ldap_get_lderrno(ld, NULL, NULL); + dprint((6, "error (-1 returned): ld_errno=%d\n", + srch_res)); + } + else if(lres == 0){ /* timeout, no results available */ + if(intr_happened){ + ldap_abandon(ld, msgid); + srch_res = LDAP_PROTOCOL_ERROR; + if(our_ldap_get_lderrno(ld, NULL, NULL) == LDAP_SUCCESS) + our_ldap_set_lderrno(ld, LDAP_PROTOCOL_ERROR, NULL, NULL); + + dprint((6, "timeout, intr: srch_res=%d\n", + srch_res)); + } + else if(info->time > 0 && + ((long)time((time_t *)0) - start_time) > info->time){ + /* try for partial results */ + t.tv_sec = 0; t.tv_usec = 0; + lres = ldap_result(ld, msgid, LDAP_MSG_RECEIVED, &t, &res); + if(lres > 0 && lres != LDAP_RES_SEARCH_RESULT){ + srch_res = LDAP_SUCCESS; + dprint((6, "partial result: lres=0x%x\n", lres)); + } + else{ + if(lres == 0) + ldap_abandon(ld, msgid); + + srch_res = LDAP_TIMEOUT; + if(our_ldap_get_lderrno(ld, NULL, NULL) == LDAP_SUCCESS) + our_ldap_set_lderrno(ld, LDAP_TIMEOUT, NULL, NULL); + + dprint((6, + "timeout, total_time (%d), srch_res=%d\n", + info->time, srch_res)); + } + } + else{ + dprint((6, "timeout\n")); + } + } + else{ + srch_res = ldap_result2error(ld, res, 0); + dprint((6, "lres=0x%x, srch_res=%d\n", lres, + srch_res)); + } + }while(lres == 0 && + !(intr_happened || + (info->time > 0 && + ((long)time((time_t *)0) - start_time) > info->time))); + } + } + + if(intr_happened){ + wp_exit = 1; + if(we_cancel) + cancel_busy_cue(-1); + + if(wp_err->error) + fs_give((void **)&wp_err->error); + else{ + q_status_message(SM_ORDER, 0, 1, "Interrupt"); + display_message('x'); + fflush(stdout); + } + + if(res) + ldap_msgfree(res); + if(ld) + ldap_unbind(ld); + + res = NULL; ld = NULL; + } + else if(srch_res != LDAP_SUCCESS && + srch_res != LDAP_TIMELIMIT_EXCEEDED && + srch_res != LDAP_RESULTS_TOO_LARGE && + srch_res != LDAP_TIMEOUT && + srch_res != LDAP_SIZELIMIT_EXCEEDED){ + wp_err->wp_err_occurred = 1; + + ld_errnum = our_ldap_get_lderrno(ld, NULL, &ld_errstr); + + snprintf(ebuf, sizeof(ebuf), _("LDAP search failed: %s%s%s%s"), + ldap_err2string(ld_errnum), + serv_errstr, + (ld_errstr && *ld_errstr) ? ": " : "", + (ld_errstr && *ld_errstr) ? ld_errstr : ""); + + if(wp_err->error) + fs_give((void **)&wp_err->error); + + wp_err->error = cpystr(ebuf); + if(we_cancel) + cancel_busy_cue(-1); + + q_status_message(SM_ORDER, 3, 5, wp_err->error); + display_message('x'); + dprint((2, "%s\n", ebuf)); + if(res) + ldap_msgfree(res); + if(ld) + ldap_unbind(ld); + + res = NULL; ld = NULL; + } + else{ + int cnt; + + cnt = ldap_count_entries(ld, res); + + if(cnt > 0){ + + if(srch_res == LDAP_TIMELIMIT_EXCEEDED || + srch_res == LDAP_RESULTS_TOO_LARGE || + srch_res == LDAP_TIMEOUT || + srch_res == LDAP_SIZELIMIT_EXCEEDED){ + wp_err->wp_err_occurred = 1; + ld_errnum = our_ldap_get_lderrno(ld, NULL, &ld_errstr); + + snprintf(ebuf, sizeof(ebuf), _("LDAP partial results: %s%s%s%s"), + ldap_err2string(ld_errnum), + serv_errstr, + (ld_errstr && *ld_errstr) ? ": " : "", + (ld_errstr && *ld_errstr) ? ld_errstr : ""); + dprint((2, "%s\n", ebuf)); + if(wp_err->error) + fs_give((void **)&wp_err->error); + + wp_err->error = cpystr(ebuf); + if(we_cancel) + cancel_busy_cue(-1); + + q_status_message(SM_ORDER, 3, 5, wp_err->error); + display_message('x'); + } + + dprint((5, "Matched %d entries on %s\n", + cnt, serv ? serv : "?")); + + serv_res = (LDAP_SERV_RES_S *)fs_get(sizeof(LDAP_SERV_RES_S)); + memset((void *)serv_res, 0, sizeof(*serv_res)); + serv_res->ld = ld; + serv_res->res = res; + serv_res->info_used = copy_ldap_serv_info(info); + /* Save by reference? */ + if(info->ref){ + snprintf(buf, sizeof(buf), "%s:%s", serv, comatose(info->port)); + serv_res->serv = cpystr(buf); + } + else + serv_res->serv = NULL; + + serv_res->next = NULL; + } + else{ + if(srch_res == LDAP_TIMELIMIT_EXCEEDED || + srch_res == LDAP_RESULTS_TOO_LARGE || + srch_res == LDAP_TIMEOUT || + srch_res == LDAP_SIZELIMIT_EXCEEDED){ + wp_err->wp_err_occurred = 1; + wp_err->ldap_errno = srch_res; + + ld_errnum = our_ldap_get_lderrno(ld, NULL, &ld_errstr); + + snprintf(ebuf, sizeof(ebuf), _("LDAP search failed: %s%s%s%s"), + ldap_err2string(ld_errnum), + serv_errstr, + (ld_errstr && *ld_errstr) ? ": " : "", + (ld_errstr && *ld_errstr) ? ld_errstr : ""); + + if(wp_err->error) + fs_give((void **)&wp_err->error); + + wp_err->error = cpystr(ebuf); + if(we_cancel) + cancel_busy_cue(-1); + + q_status_message(SM_ORDER, 3, 5, wp_err->error); + display_message('x'); + dprint((2, "%s\n", ebuf)); + } + + dprint((5, "Matched 0 entries on %s\n", + serv ? serv : "?")); + if(res) + ldap_msgfree(res); + if(ld) + ldap_unbind(ld); + + res = NULL; ld = NULL; + } + } + } + } + + if(we_cancel) + cancel_busy_cue(-1); + + if(we_turned_on) + intr_handling_off(); + + if(serv) + fs_give((void **)&serv); + if(base) + fs_give((void **)&base); + if(serv_errstr) + fs_give((void **)&serv_errstr); + + return(serv_res); +} + + +/* + * Given a list of entries, present them to user so user may + * select one. + * + * Args head -- The head of the list of results + * orig -- The string the user was searching for + * result -- Returned pointer to chosen LDAP_SEARCH_WINNER or NULL + * wp_err -- Error handling + * style -- + * + * Returns 0 ok + * -1 Exit chosen by user + * -2 None of matched entries had an email address + * -3 No matched entries + * -4 Goback to Abook List chosen by user + * -5 caller shouldn't free head + */ +int +ask_user_which_entry(LDAP_SERV_RES_S *head, char *orig, LDAP_CHOOSE_S **result, + WP_ERR_S *wp_err, LDAPLookupStyle style) +{ + ADDR_CHOOSE_S ac; + char t[200]; + int retval; + + dprint((3, "ask_user_which(style=%s)\n", + style == AlwaysDisplayAndMailRequired ? "AlwaysDisplayAndMailRequired" : + style == AlwaysDisplay ? "AlwaysDisplay" : + style == DisplayIfTwo ? "DisplayIfTwo" : + style == DisplayForURL ? "DisplayForURL" : + style == DisplayIfOne ? "DisplayIfOne" : "?")); + + /* + * Set up a screen for user to choose one entry. + */ + + if(style == AlwaysDisplay || style == DisplayForURL) + snprintf(t, sizeof(t), "SEARCH RESULTS INDEX"); + else{ + int len; + + len = strlen(orig); + snprintf(t, sizeof(t), _("SELECT ONE ADDRESS%s%s%s"), + (orig && *orig && len < 40) ? " FOR \"" : "", + (orig && *orig && len < 40) ? orig : "", + (orig && *orig && len < 40) ? "\"" : ""); + } + + memset(&ac, 0, sizeof(ADDR_CHOOSE_S)); + ac.title = cpystr(t); + ac.res_head = head; + + retval = ldap_addr_select(ps_global, &ac, result, style, wp_err, orig); + + switch(retval){ + case 0: /* Ok */ + break; + + case -1: /* Exit chosen by user */ + wp_exit = 1; + break; + + case -4: /* GoBack to AbookList chosen by user */ + break; + + case -5: + wp_nobail = 1; + break; + + case -2: + if(style != AlwaysDisplay){ + if(wp_err->error) + fs_give((void **)&wp_err->error); + + wp_err->error = + cpystr(_("None of the names matched on directory server has an email address")); + q_status_message(SM_ORDER, 3, 5, wp_err->error); + display_message('x'); + } + + break; + + case -3: + if(style == AlwaysDisplayAndMailRequired){ + if(wp_err->error) + fs_give((void **)&wp_err->error); + + wp_err->error = cpystr(_("No matches on directory server")); + q_status_message(SM_ORDER, 3, 5, wp_err->error); + display_message('x'); + } + + break; + } + + fs_give((void **)&ac.title); + + return(retval); +} + + +ADDRESS * +address_from_ldap(LDAP_CHOOSE_S *winning_e) +{ + ADDRESS *ret_a = NULL; + + if(winning_e){ + char *a; + BerElement *ber; + + ret_a = mail_newaddr(); + for(a = ldap_first_attribute(winning_e->ld, winning_e->selected_entry, &ber); + a != NULL; + a = ldap_next_attribute(winning_e->ld, winning_e->selected_entry, ber)){ + int i; + char *p; + char **vals; + + dprint((9, "attribute: %s\n", a ? a : "?")); + if(!ret_a->personal && + strcmp(a, winning_e->info_used->cnattr) == 0){ + dprint((9, "Got cnattr:")); + vals = ldap_get_values(winning_e->ld, winning_e->selected_entry, a); + for(i = 0; vals[i] != NULL; i++) + dprint((9, " %s\n", + vals[i] ? vals[i] : "?")); + + if(vals && vals[0]) + ret_a->personal = cpystr(vals[0]); + + ldap_value_free(vals); + } + else if(!ret_a->mailbox && + strcmp(a, winning_e->info_used->mailattr) == 0){ + dprint((9, "Got mailattr:")); + vals = ldap_get_values(winning_e->ld, winning_e->selected_entry, a); + for(i = 0; vals[i] != NULL; i++) + dprint((9, " %s\n", + vals[i] ? vals[i] : "?")); + + /* use first one */ + if(vals && vals[0]){ + if((p = strindex(vals[0], '@')) != NULL){ + ret_a->host = cpystr(p+1); + *p = '\0'; + } + + ret_a->mailbox = cpystr(vals[0]); + } + + ldap_value_free(vals); + } + + our_ldap_memfree(a); + } + } + + return(ret_a); +} + + +/* + * Break up the ldap-server string stored in the pinerc into its + * parts. The structure is allocated here and should be freed by the caller. + * + * The original string looks like + * <servername>[:port] <SPACE> "/base=<base>/impl=1/..." + * + * Args serv_str -- The original string from the pinerc to parse. + * + * Returns A pointer to a structure with filled in answers. + * + * Some of the members have defaults. If port is -1, that means to use + * the default LDAP_PORT. If base is NULL, use "". Type and srch have + * defaults defined in alpine.h. If cust is non-NULL, it overrides type and + * srch. + */ +LDAP_SERV_S * +break_up_ldap_server(char *serv_str) +{ + char *lserv; + char *q, *p, *tail; + int i, only_one = 1; + LDAP_SERV_S *info = NULL; + + if(!serv_str) + return(info); + + info = (LDAP_SERV_S *)fs_get(sizeof(LDAP_SERV_S)); + + /* + * Initialize to defaults. + */ + memset((void *)info, 0, sizeof(*info)); + info->port = -1; + info->srch = -1; + info->type = -1; + info->time = -1; + info->size = -1; + info->scope = -1; + + /* copy the whole string to work on */ + lserv = cpystr(serv_str); + if(lserv) + removing_trailing_white_space(lserv); + + if(!lserv || !*lserv || *lserv == '"'){ + if(lserv) + fs_give((void **)&lserv); + + if(info) + free_ldap_server_info(&info); + + return(NULL); + } + + tail = lserv; + while((tail = strindex(tail, SPACE)) != NULL){ + tail++; + if(*tail == '"' || *tail == '/'){ + *(tail-1) = '\0'; + break; + } + else + only_one = 0; + } + + /* tail is the part after server[:port] <SPACE> */ + if(tail && *tail){ + removing_leading_white_space(tail); + (void)removing_double_quotes(tail); + } + + /* get the optional port number */ + if(only_one && (q = strindex(lserv, ':')) != NULL){ + int ldapport = -1; + + *q = '\0'; + if((ldapport = atoi(q+1)) >= 0) + info->port = ldapport; + } + + /* use lserv for serv even though it has a few extra bytes alloced */ + info->serv = lserv; + + if(tail && *tail){ + /* get the search base */ + if((q = srchstr(tail, "/base=")) != NULL) + info->base = remove_backslash_escapes(q+6); + + if((q = srchstr(tail, "/binddn=")) != NULL) + info->binddn = remove_backslash_escapes(q+8); + + /* get the implicit parameter */ + if((q = srchstr(tail, "/impl=1")) != NULL) + info->impl = 1; + + /* get the rhs parameter */ + if((q = srchstr(tail, "/rhs=1")) != NULL) + info->rhs = 1; + + /* get the ref parameter */ + if((q = srchstr(tail, "/ref=1")) != NULL) + info->ref = 1; + + /* get the nosub parameter */ + if((q = srchstr(tail, "/nosub=1")) != NULL) + info->nosub = 1; + + /* get the tls parameter */ + if((q = srchstr(tail, "/tls=1")) != NULL) + info->tls = 1; + + /* get the tlsmust parameter */ + if((q = srchstr(tail, "/tlsm=1")) != NULL) + info->tlsmust = 1; + + /* get the search type value */ + if((q = srchstr(tail, "/type=")) != NULL){ + NAMEVAL_S *v; + + q += 6; + if((p = strindex(q, '/')) != NULL) + *p = '\0'; + + for(i = 0; (v = ldap_search_types(i)); i++) + if(!strucmp(q, v->name)){ + info->type = v->value; + break; + } + + if(p) + *p = '/'; + } + + /* get the search rule value */ + if((q = srchstr(tail, "/srch=")) != NULL){ + NAMEVAL_S *v; + + q += 6; + if((p = strindex(q, '/')) != NULL) + *p = '\0'; + + for(i = 0; (v = ldap_search_rules(i)); i++) + if(!strucmp(q, v->name)){ + info->srch = v->value; + break; + } + + if(p) + *p = '/'; + } + + /* get the scope */ + if((q = srchstr(tail, "/scope=")) != NULL){ + NAMEVAL_S *v; + + q += 7; + if((p = strindex(q, '/')) != NULL) + *p = '\0'; + + for(i = 0; (v = ldap_search_scope(i)); i++) + if(!strucmp(q, v->name)){ + info->scope = v->value; + break; + } + + if(p) + *p = '/'; + } + + /* get the time limit */ + if((q = srchstr(tail, "/time=")) != NULL){ + q += 6; + if((p = strindex(q, '/')) != NULL) + *p = '\0'; + + /* This one's a number */ + if(*q){ + char *err; + + err = strtoval(q, &i, 0, 500, 0, tmp_20k_buf, SIZEOF_20KBUF, "ldap timelimit"); + if(err){ + dprint((1, "%s\n", err ? err : "?")); + } + else + info->time = i; + } + + if(p) + *p = '/'; + } + + /* get the size limit */ + if((q = srchstr(tail, "/size=")) != NULL){ + q += 6; + if((p = strindex(q, '/')) != NULL) + *p = '\0'; + + /* This one's a number */ + if(*q){ + char *err; + + err = strtoval(q, &i, 0, 500, 0, tmp_20k_buf, SIZEOF_20KBUF, "ldap sizelimit"); + if(err){ + dprint((1, "%s\n", err ? err : "?")); + } + else + info->size = i; + } + + if(p) + *p = '/'; + } + + /* get the custom search filter */ + if((q = srchstr(tail, "/cust=")) != NULL) + info->cust = remove_backslash_escapes(q+6); + + /* get the nickname */ + if((q = srchstr(tail, "/nick=")) != NULL) + info->nick = remove_backslash_escapes(q+6); + + /* get the mail attribute name */ + if((q = srchstr(tail, "/matr=")) != NULL) + info->mailattr = remove_backslash_escapes(q+6); + + /* get the sn attribute name */ + if((q = srchstr(tail, "/satr=")) != NULL) + info->snattr = remove_backslash_escapes(q+6); + + /* get the gn attribute name */ + if((q = srchstr(tail, "/gatr=")) != NULL) + info->gnattr = remove_backslash_escapes(q+6); + + /* get the cn attribute name */ + if((q = srchstr(tail, "/catr=")) != NULL) + info->cnattr = remove_backslash_escapes(q+6); + + /* get the backup mail address */ + if((q = srchstr(tail, "/mail=")) != NULL) + info->mail = remove_backslash_escapes(q+6); + } + + return(info); +} + + +void +free_ldap_server_info(LDAP_SERV_S **info) +{ + if(info && *info){ + if((*info)->serv) + fs_give((void **)&(*info)->serv); + + if((*info)->base) + fs_give((void **)&(*info)->base); + + if((*info)->cust) + fs_give((void **)&(*info)->cust); + + if((*info)->binddn) + fs_give((void **)&(*info)->binddn); + + if((*info)->nick) + fs_give((void **)&(*info)->nick); + + if((*info)->mail) + fs_give((void **)&(*info)->mail); + + if((*info)->mailattr) + fs_give((void **)&(*info)->mailattr); + + if((*info)->snattr) + fs_give((void **)&(*info)->snattr); + + if((*info)->gnattr) + fs_give((void **)&(*info)->gnattr); + + if((*info)->cnattr) + fs_give((void **)&(*info)->cnattr); + + fs_give((void **)info); + *info = NULL; + } +} + + +LDAP_SERV_S * +copy_ldap_serv_info(LDAP_SERV_S *src) +{ + LDAP_SERV_S *info = NULL; + + if(src){ + info = (LDAP_SERV_S *) fs_get(sizeof(*info)); + + /* + * Initialize to defaults. + */ + memset((void *)info, 0, sizeof(*info)); + + info->serv = src->serv ? cpystr(src->serv) : NULL; + info->base = src->base ? cpystr(src->base) : NULL; + info->cust = src->cust ? cpystr(src->cust) : NULL; + info->binddn = src->binddn ? cpystr(src->binddn) : NULL; + info->nick = src->nick ? cpystr(src->nick) : NULL; + info->mail = src->mail ? cpystr(src->mail) : NULL; + info->mailattr = cpystr((src->mailattr && src->mailattr[0]) + ? src->mailattr : DEF_LDAP_MAILATTR); + info->snattr = cpystr((src->snattr && src->snattr[0]) + ? src->snattr : DEF_LDAP_SNATTR); + info->gnattr = cpystr((src->gnattr && src->gnattr[0]) + ? src->gnattr : DEF_LDAP_GNATTR); + info->cnattr = cpystr((src->cnattr && src->cnattr[0]) + ? src->cnattr : DEF_LDAP_CNATTR); + + info->port = (src->port < 0) ? LDAP_PORT : src->port; + info->time = (src->time < 0) ? DEF_LDAP_TIME : src->time; + info->size = (src->size < 0) ? DEF_LDAP_SIZE : src->size; + info->type = (src->type < 0) ? DEF_LDAP_TYPE : src->type; + info->srch = (src->srch < 0) ? DEF_LDAP_SRCH : src->srch; + info->scope = (src->scope < 0) ? DEF_LDAP_SCOPE : src->scope; + info->impl = src->impl; + info->rhs = src->rhs; + info->ref = src->ref; + info->nosub = src->nosub; + info->tls = src->tls; + } + + return(info); +} + + +void +free_ldap_result_list(LDAP_SERV_RES_S **r) +{ + if(r && *r){ + free_ldap_result_list(&(*r)->next); + if((*r)->res) + ldap_msgfree((*r)->res); + if((*r)->ld) + ldap_unbind((*r)->ld); + if((*r)->info_used) + free_ldap_server_info(&(*r)->info_used); + if((*r)->serv) + fs_give((void **) &(*r)->serv); + + fs_give((void **) r); + } +} + + +/* + * Mask API differences. + */ +void +our_ldap_memfree(void *a) +{ +#if (LDAPAPI >= 15) + if(a) + ldap_memfree(a); +#endif +} + + +/* + * Mask API differences. + */ +void +our_ldap_dn_memfree(void *a) +{ +#if defined(_WINDOWS) + if(a) + ldap_memfree(a); +#else +#if (LDAPAPI >= 15) + if(a) + ldap_memfree(a); +#else + if(a) + free(a); +#endif +#endif +} + + +/* + * More API masking. + */ +int +our_ldap_get_lderrno(LDAP *ld, char **m, char **s) +{ + int ret = 0; + +#if (LDAPAPI >= 2000) + if(ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, (void *)&ret) == 0){ + if(s) + ldap_get_option(ld, LDAP_OPT_ERROR_STRING, (void *)s); + } +#elif (LDAPAPI >= 15) + ret = ldap_get_lderrno(ld, m, s); +#else + ret = ld->ld_errno; + if(s) + *s = ld->ld_error; +#endif + + return(ret); +} + + +/* + * More API masking. + */ +int +our_ldap_set_lderrno(LDAP *ld, int e, char *m, char *s) +{ + int ret; + +#if (LDAPAPI >= 2000) + if(ldap_set_option(ld, LDAP_OPT_ERROR_NUMBER, (void *)&e) == 0) + ret = LDAP_SUCCESS; + else + (void)ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, (void *)&ret); +#elif (LDAPAPI >= 15) + ret = ldap_set_lderrno(ld, e, m, s); +#else + /* this is all we care about */ + ld->ld_errno = e; + ret = LDAP_SUCCESS; +#endif + + return(ret); +} + + +/* + * More API masking. + */ +int +our_ldap_set_option(LDAP *ld, int option, void *optdata) +{ + int ret; + +#if (LDAPAPI >= 15) + ret = ldap_set_option(ld, option, optdata); +#else + switch(option){ + case LDAP_OPT_TIMELIMIT: + ld->ld_timelimit = *(int *)optdata; + break; + + case LDAP_OPT_SIZELIMIT: + ld->ld_sizelimit = *(int *)optdata; + break; + + case LDAP_OPT_RESTART: + if((int)optdata) + ld->ld_options |= LDAP_OPT_RESTART; + else + ld->ld_options &= ~LDAP_OPT_RESTART; + + break; + + /* + * Does nothing here. There is only one protocol version supported. + */ + case LDAP_OPT_PROTOCOL_VERSION: + ret = -1; + break; + + default: + panic("LDAP function not implemented"); + } +#endif + + return(ret); +} + + +/* + * Returns 1 if we can use LDAP version 3 protocol. + */ +int +ldap_v3_is_supported(LDAP *ld) +{ + return(1); +} + +struct tl_table { + char *ldap_ese; + char *translated; +}; + +static struct tl_table ldap_trans_table[]={ + /* + * TRANSLATORS: This is a list of LDAP attributes with translations to present + * to the user. For example the attribute mail is Email Address and the attribute + * cn is Name. + */ + {"mail", N_("Email Address")}, +#define LDAP_MAIL_ATTR 0 + {"sn", N_("Surname")}, +#define LDAP_SN_ATTR 1 + {"givenName", N_("Given Name")}, +#define LDAP_GN_ATTR 2 + {"cn", N_("Name")}, +#define LDAP_CN_ATTR 3 + {"electronicmail", N_("Email Address")}, +#define LDAP_EMAIL_ATTR 4 + {"o", N_("Organization")}, + {"ou", N_("Unit")}, + {"c", N_("Country")}, + {"st", N_("State or Province")}, + {"l", N_("Locality")}, + {"objectClass", N_("Object Class")}, + {"title", N_("Title")}, + {"departmentNumber", N_("Department")}, + {"postalAddress", N_("Postal Address")}, + {"homePostalAddress", N_("Home Address")}, + {"mailStop", N_("Mail Stop")}, + {"telephoneNumber", N_("Voice Telephone")}, + {"homePhone", N_("Home Telephone")}, + {"officePhone", N_("Office Telephone")}, + {"facsimileTelephoneNumber", N_("FAX Telephone")}, + {"mobile", N_("Mobile Telephone")}, + {"pager", N_("Pager")}, + {"roomNumber", N_("Room Number")}, + {"uid", N_("User ID")}, + {NULL, NULL} +}; + +char * +ldap_translate(char *a, LDAP_SERV_S *info_used) +{ + int i; + + if(info_used){ + if(info_used->mailattr && strucmp(info_used->mailattr, a) == 0) + return(_(ldap_trans_table[LDAP_MAIL_ATTR].translated)); + else if(info_used->snattr && strucmp(info_used->snattr, a) == 0) + return(_(ldap_trans_table[LDAP_SN_ATTR].translated)); + else if(info_used->gnattr && strucmp(info_used->gnattr, a) == 0) + return(_(ldap_trans_table[LDAP_GN_ATTR].translated)); + else if(info_used->cnattr && strucmp(info_used->cnattr, a) == 0) + return(_(ldap_trans_table[LDAP_CN_ATTR].translated)); + } + + for(i = 0; ldap_trans_table[i].ldap_ese; i++){ + if(info_used) + switch(i){ + case LDAP_MAIL_ATTR: + case LDAP_SN_ATTR: + case LDAP_GN_ATTR: + case LDAP_CN_ATTR: + case LDAP_EMAIL_ATTR: + continue; + } + + if(strucmp(ldap_trans_table[i].ldap_ese, a) == 0) + return(_(ldap_trans_table[i].translated)); + } + + return(a); +} + + +#endif /* ENABLE_LDAP */ |