Annotation of embedaddon/curl/lib/openldap.c, revision 1.1

1.1     ! misho       1: /***************************************************************************
        !             2:  *                      _   _ ____  _
        !             3:  *  Project         ___| | | |  _ \| |
        !             4:  *                 / __| | | | |_) | |
        !             5:  *                | (__| |_| |  _ <| |___
        !             6:  *                 \___|\___/|_| \_\_____|
        !             7:  *
        !             8:  * Copyright (C) 2010, Howard Chu, <hyc@openldap.org>
        !             9:  * Copyright (C) 2011 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
        !            10:  *
        !            11:  * This software is licensed as described in the file COPYING, which
        !            12:  * you should have received as part of this distribution. The terms
        !            13:  * are also available at https://curl.haxx.se/docs/copyright.html.
        !            14:  *
        !            15:  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
        !            16:  * copies of the Software, and permit persons to whom the Software is
        !            17:  * furnished to do so, under the terms of the COPYING file.
        !            18:  *
        !            19:  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
        !            20:  * KIND, either express or implied.
        !            21:  *
        !            22:  ***************************************************************************/
        !            23: 
        !            24: #include "curl_setup.h"
        !            25: 
        !            26: #if !defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP)
        !            27: 
        !            28: /*
        !            29:  * Notice that USE_OPENLDAP is only a source code selection switch. When
        !            30:  * libcurl is built with USE_OPENLDAP defined the libcurl source code that
        !            31:  * gets compiled is the code from openldap.c, otherwise the code that gets
        !            32:  * compiled is the code from ldap.c.
        !            33:  *
        !            34:  * When USE_OPENLDAP is defined a recent version of the OpenLDAP library
        !            35:  * might be required for compilation and runtime. In order to use ancient
        !            36:  * OpenLDAP library versions, USE_OPENLDAP shall not be defined.
        !            37:  */
        !            38: 
        !            39: #include <ldap.h>
        !            40: 
        !            41: #include "urldata.h"
        !            42: #include <curl/curl.h>
        !            43: #include "sendf.h"
        !            44: #include "vtls/vtls.h"
        !            45: #include "transfer.h"
        !            46: #include "curl_ldap.h"
        !            47: #include "curl_base64.h"
        !            48: #include "connect.h"
        !            49: /* The last 3 #include files should be in this order */
        !            50: #include "curl_printf.h"
        !            51: #include "curl_memory.h"
        !            52: #include "memdebug.h"
        !            53: 
        !            54: /*
        !            55:  * Uncommenting this will enable the built-in debug logging of the openldap
        !            56:  * library. The debug log level can be set using the CURL_OPENLDAP_TRACE
        !            57:  * environment variable. The debug output is written to stderr.
        !            58:  *
        !            59:  * The library supports the following debug flags:
        !            60:  * LDAP_DEBUG_NONE         0x0000
        !            61:  * LDAP_DEBUG_TRACE        0x0001
        !            62:  * LDAP_DEBUG_CONSTRUCT    0x0002
        !            63:  * LDAP_DEBUG_DESTROY      0x0004
        !            64:  * LDAP_DEBUG_PARAMETER    0x0008
        !            65:  * LDAP_DEBUG_ANY          0xffff
        !            66:  *
        !            67:  * For example, use CURL_OPENLDAP_TRACE=0 for no debug,
        !            68:  * CURL_OPENLDAP_TRACE=2 for LDAP_DEBUG_CONSTRUCT messages only,
        !            69:  * CURL_OPENLDAP_TRACE=65535 for all debug message levels.
        !            70:  */
        !            71: /* #define CURL_OPENLDAP_DEBUG */
        !            72: 
        !            73: #ifndef _LDAP_PVT_H
        !            74: extern int ldap_pvt_url_scheme2proto(const char *);
        !            75: extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url,
        !            76:                         LDAP **ld);
        !            77: #endif
        !            78: 
        !            79: static CURLcode ldap_setup_connection(struct connectdata *conn);
        !            80: static CURLcode ldap_do(struct connectdata *conn, bool *done);
        !            81: static CURLcode ldap_done(struct connectdata *conn, CURLcode, bool);
        !            82: static CURLcode ldap_connect(struct connectdata *conn, bool *done);
        !            83: static CURLcode ldap_connecting(struct connectdata *conn, bool *done);
        !            84: static CURLcode ldap_disconnect(struct connectdata *conn, bool dead);
        !            85: 
        !            86: static Curl_recv ldap_recv;
        !            87: 
        !            88: /*
        !            89:  * LDAP protocol handler.
        !            90:  */
        !            91: 
        !            92: const struct Curl_handler Curl_handler_ldap = {
        !            93:   "LDAP",                               /* scheme */
        !            94:   ldap_setup_connection,                /* setup_connection */
        !            95:   ldap_do,                              /* do_it */
        !            96:   ldap_done,                            /* done */
        !            97:   ZERO_NULL,                            /* do_more */
        !            98:   ldap_connect,                         /* connect_it */
        !            99:   ldap_connecting,                      /* connecting */
        !           100:   ZERO_NULL,                            /* doing */
        !           101:   ZERO_NULL,                            /* proto_getsock */
        !           102:   ZERO_NULL,                            /* doing_getsock */
        !           103:   ZERO_NULL,                            /* domore_getsock */
        !           104:   ZERO_NULL,                            /* perform_getsock */
        !           105:   ldap_disconnect,                      /* disconnect */
        !           106:   ZERO_NULL,                            /* readwrite */
        !           107:   ZERO_NULL,                            /* connection_check */
        !           108:   PORT_LDAP,                            /* defport */
        !           109:   CURLPROTO_LDAP,                       /* protocol */
        !           110:   PROTOPT_NONE                          /* flags */
        !           111: };
        !           112: 
        !           113: #ifdef USE_SSL
        !           114: /*
        !           115:  * LDAPS protocol handler.
        !           116:  */
        !           117: 
        !           118: const struct Curl_handler Curl_handler_ldaps = {
        !           119:   "LDAPS",                              /* scheme */
        !           120:   ldap_setup_connection,                /* setup_connection */
        !           121:   ldap_do,                              /* do_it */
        !           122:   ldap_done,                            /* done */
        !           123:   ZERO_NULL,                            /* do_more */
        !           124:   ldap_connect,                         /* connect_it */
        !           125:   ldap_connecting,                      /* connecting */
        !           126:   ZERO_NULL,                            /* doing */
        !           127:   ZERO_NULL,                            /* proto_getsock */
        !           128:   ZERO_NULL,                            /* doing_getsock */
        !           129:   ZERO_NULL,                            /* domore_getsock */
        !           130:   ZERO_NULL,                            /* perform_getsock */
        !           131:   ldap_disconnect,                      /* disconnect */
        !           132:   ZERO_NULL,                            /* readwrite */
        !           133:   ZERO_NULL,                            /* connection_check */
        !           134:   PORT_LDAPS,                           /* defport */
        !           135:   CURLPROTO_LDAP,                       /* protocol */
        !           136:   PROTOPT_SSL                           /* flags */
        !           137: };
        !           138: #endif
        !           139: 
        !           140: static const char *url_errs[] = {
        !           141:   "success",
        !           142:   "out of memory",
        !           143:   "bad parameter",
        !           144:   "unrecognized scheme",
        !           145:   "unbalanced delimiter",
        !           146:   "bad URL",
        !           147:   "bad host or port",
        !           148:   "bad or missing attributes",
        !           149:   "bad or missing scope",
        !           150:   "bad or missing filter",
        !           151:   "bad or missing extensions"
        !           152: };
        !           153: 
        !           154: struct ldapconninfo {
        !           155:   LDAP *ld;
        !           156:   Curl_recv *recv;  /* for stacking SSL handler */
        !           157:   Curl_send *send;
        !           158:   int proto;
        !           159:   int msgid;
        !           160:   bool ssldone;
        !           161:   bool sslinst;
        !           162:   bool didbind;
        !           163: };
        !           164: 
        !           165: typedef struct ldapreqinfo {
        !           166:   int msgid;
        !           167:   int nument;
        !           168: } ldapreqinfo;
        !           169: 
        !           170: static CURLcode ldap_setup_connection(struct connectdata *conn)
        !           171: {
        !           172:   struct ldapconninfo *li;
        !           173:   LDAPURLDesc *lud;
        !           174:   struct Curl_easy *data = conn->data;
        !           175:   int rc, proto;
        !           176:   CURLcode status;
        !           177: 
        !           178:   rc = ldap_url_parse(data->change.url, &lud);
        !           179:   if(rc != LDAP_URL_SUCCESS) {
        !           180:     const char *msg = "url parsing problem";
        !           181:     status = CURLE_URL_MALFORMAT;
        !           182:     if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) {
        !           183:       if(rc == LDAP_URL_ERR_MEM)
        !           184:         status = CURLE_OUT_OF_MEMORY;
        !           185:       msg = url_errs[rc];
        !           186:     }
        !           187:     failf(conn->data, "LDAP local: %s", msg);
        !           188:     return status;
        !           189:   }
        !           190:   proto = ldap_pvt_url_scheme2proto(lud->lud_scheme);
        !           191:   ldap_free_urldesc(lud);
        !           192: 
        !           193:   li = calloc(1, sizeof(struct ldapconninfo));
        !           194:   if(!li)
        !           195:     return CURLE_OUT_OF_MEMORY;
        !           196:   li->proto = proto;
        !           197:   conn->proto.ldapc = li;
        !           198:   connkeep(conn, "OpenLDAP default");
        !           199:   return CURLE_OK;
        !           200: }
        !           201: 
        !           202: #ifdef USE_SSL
        !           203: static Sockbuf_IO ldapsb_tls;
        !           204: #endif
        !           205: 
        !           206: static CURLcode ldap_connect(struct connectdata *conn, bool *done)
        !           207: {
        !           208:   struct ldapconninfo *li = conn->proto.ldapc;
        !           209:   struct Curl_easy *data = conn->data;
        !           210:   int rc, proto = LDAP_VERSION3;
        !           211:   char hosturl[1024];
        !           212:   char *ptr;
        !           213: 
        !           214:   (void)done;
        !           215: 
        !           216:   strcpy(hosturl, "ldap");
        !           217:   ptr = hosturl + 4;
        !           218:   if(conn->handler->flags & PROTOPT_SSL)
        !           219:     *ptr++ = 's';
        !           220:   msnprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d",
        !           221:             conn->host.name, conn->remote_port);
        !           222: 
        !           223: #ifdef CURL_OPENLDAP_DEBUG
        !           224:   static int do_trace = 0;
        !           225:   const char *env = getenv("CURL_OPENLDAP_TRACE");
        !           226:   do_trace = (env && strtol(env, NULL, 10) > 0);
        !           227:   if(do_trace) {
        !           228:     ldap_set_option(li->ld, LDAP_OPT_DEBUG_LEVEL, &do_trace);
        !           229:   }
        !           230: #endif
        !           231: 
        !           232:   rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld);
        !           233:   if(rc) {
        !           234:     failf(data, "LDAP local: Cannot connect to %s, %s",
        !           235:           hosturl, ldap_err2string(rc));
        !           236:     return CURLE_COULDNT_CONNECT;
        !           237:   }
        !           238: 
        !           239:   ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
        !           240: 
        !           241: #ifdef USE_SSL
        !           242:   if(conn->handler->flags & PROTOPT_SSL) {
        !           243:     CURLcode result;
        !           244:     result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone);
        !           245:     if(result)
        !           246:       return result;
        !           247:   }
        !           248: #endif
        !           249: 
        !           250:   return CURLE_OK;
        !           251: }
        !           252: 
        !           253: static CURLcode ldap_connecting(struct connectdata *conn, bool *done)
        !           254: {
        !           255:   struct ldapconninfo *li = conn->proto.ldapc;
        !           256:   struct Curl_easy *data = conn->data;
        !           257:   LDAPMessage *msg = NULL;
        !           258:   struct timeval tv = {0, 1}, *tvp;
        !           259:   int rc, err;
        !           260:   char *info = NULL;
        !           261: 
        !           262: #ifdef USE_SSL
        !           263:   if(conn->handler->flags & PROTOPT_SSL) {
        !           264:     /* Is the SSL handshake complete yet? */
        !           265:     if(!li->ssldone) {
        !           266:       CURLcode result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET,
        !           267:                                                      &li->ssldone);
        !           268:       if(result || !li->ssldone)
        !           269:         return result;
        !           270:     }
        !           271: 
        !           272:     /* Have we installed the libcurl SSL handlers into the sockbuf yet? */
        !           273:     if(!li->sslinst) {
        !           274:       Sockbuf *sb;
        !           275:       ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
        !           276:       ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, conn);
        !           277:       li->sslinst = TRUE;
        !           278:       li->recv = conn->recv[FIRSTSOCKET];
        !           279:       li->send = conn->send[FIRSTSOCKET];
        !           280:     }
        !           281:   }
        !           282: #endif
        !           283: 
        !           284:   tvp = &tv;
        !           285: 
        !           286:   retry:
        !           287:   if(!li->didbind) {
        !           288:     char *binddn;
        !           289:     struct berval passwd;
        !           290: 
        !           291:     if(conn->bits.user_passwd) {
        !           292:       binddn = conn->user;
        !           293:       passwd.bv_val = conn->passwd;
        !           294:       passwd.bv_len = strlen(passwd.bv_val);
        !           295:     }
        !           296:     else {
        !           297:       binddn = NULL;
        !           298:       passwd.bv_val = NULL;
        !           299:       passwd.bv_len = 0;
        !           300:     }
        !           301:     rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd,
        !           302:                         NULL, NULL, &li->msgid);
        !           303:     if(rc)
        !           304:       return CURLE_LDAP_CANNOT_BIND;
        !           305:     li->didbind = TRUE;
        !           306:     if(tvp)
        !           307:       return CURLE_OK;
        !           308:   }
        !           309: 
        !           310:   rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, tvp, &msg);
        !           311:   if(rc < 0) {
        !           312:     failf(data, "LDAP local: bind ldap_result %s", ldap_err2string(rc));
        !           313:     return CURLE_LDAP_CANNOT_BIND;
        !           314:   }
        !           315:   if(rc == 0) {
        !           316:     /* timed out */
        !           317:     return CURLE_OK;
        !           318:   }
        !           319: 
        !           320:   rc = ldap_parse_result(li->ld, msg, &err, NULL, &info, NULL, NULL, 1);
        !           321:   if(rc) {
        !           322:     failf(data, "LDAP local: bind ldap_parse_result %s", ldap_err2string(rc));
        !           323:     return CURLE_LDAP_CANNOT_BIND;
        !           324:   }
        !           325: 
        !           326:   /* Try to fallback to LDAPv2? */
        !           327:   if(err == LDAP_PROTOCOL_ERROR) {
        !           328:     int proto;
        !           329:     ldap_get_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
        !           330:     if(proto == LDAP_VERSION3) {
        !           331:       if(info) {
        !           332:         ldap_memfree(info);
        !           333:         info = NULL;
        !           334:       }
        !           335:       proto = LDAP_VERSION2;
        !           336:       ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
        !           337:       li->didbind = FALSE;
        !           338:       goto retry;
        !           339:     }
        !           340:   }
        !           341: 
        !           342:   if(err) {
        !           343:     failf(data, "LDAP remote: bind failed %s %s", ldap_err2string(rc),
        !           344:           info ? info : "");
        !           345:     if(info)
        !           346:       ldap_memfree(info);
        !           347:     return CURLE_LOGIN_DENIED;
        !           348:   }
        !           349: 
        !           350:   if(info)
        !           351:     ldap_memfree(info);
        !           352:   conn->recv[FIRSTSOCKET] = ldap_recv;
        !           353:   *done = TRUE;
        !           354: 
        !           355:   return CURLE_OK;
        !           356: }
        !           357: 
        !           358: static CURLcode ldap_disconnect(struct connectdata *conn, bool dead_connection)
        !           359: {
        !           360:   struct ldapconninfo *li = conn->proto.ldapc;
        !           361:   (void) dead_connection;
        !           362: 
        !           363:   if(li) {
        !           364:     if(li->ld) {
        !           365:       ldap_unbind_ext(li->ld, NULL, NULL);
        !           366:       li->ld = NULL;
        !           367:     }
        !           368:     conn->proto.ldapc = NULL;
        !           369:     free(li);
        !           370:   }
        !           371:   return CURLE_OK;
        !           372: }
        !           373: 
        !           374: static CURLcode ldap_do(struct connectdata *conn, bool *done)
        !           375: {
        !           376:   struct ldapconninfo *li = conn->proto.ldapc;
        !           377:   ldapreqinfo *lr;
        !           378:   CURLcode status = CURLE_OK;
        !           379:   int rc = 0;
        !           380:   LDAPURLDesc *ludp = NULL;
        !           381:   int msgid;
        !           382:   struct Curl_easy *data = conn->data;
        !           383: 
        !           384:   connkeep(conn, "OpenLDAP do");
        !           385: 
        !           386:   infof(data, "LDAP local: %s\n", data->change.url);
        !           387: 
        !           388:   rc = ldap_url_parse(data->change.url, &ludp);
        !           389:   if(rc != LDAP_URL_SUCCESS) {
        !           390:     const char *msg = "url parsing problem";
        !           391:     status = CURLE_URL_MALFORMAT;
        !           392:     if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) {
        !           393:       if(rc == LDAP_URL_ERR_MEM)
        !           394:         status = CURLE_OUT_OF_MEMORY;
        !           395:       msg = url_errs[rc];
        !           396:     }
        !           397:     failf(conn->data, "LDAP local: %s", msg);
        !           398:     return status;
        !           399:   }
        !           400: 
        !           401:   rc = ldap_search_ext(li->ld, ludp->lud_dn, ludp->lud_scope,
        !           402:                        ludp->lud_filter, ludp->lud_attrs, 0,
        !           403:                        NULL, NULL, NULL, 0, &msgid);
        !           404:   ldap_free_urldesc(ludp);
        !           405:   if(rc != LDAP_SUCCESS) {
        !           406:     failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc));
        !           407:     return CURLE_LDAP_SEARCH_FAILED;
        !           408:   }
        !           409:   lr = calloc(1, sizeof(ldapreqinfo));
        !           410:   if(!lr)
        !           411:     return CURLE_OUT_OF_MEMORY;
        !           412:   lr->msgid = msgid;
        !           413:   data->req.protop = lr;
        !           414:   Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
        !           415:   *done = TRUE;
        !           416:   return CURLE_OK;
        !           417: }
        !           418: 
        !           419: static CURLcode ldap_done(struct connectdata *conn, CURLcode res,
        !           420:                           bool premature)
        !           421: {
        !           422:   ldapreqinfo *lr = conn->data->req.protop;
        !           423: 
        !           424:   (void)res;
        !           425:   (void)premature;
        !           426: 
        !           427:   if(lr) {
        !           428:     /* if there was a search in progress, abandon it */
        !           429:     if(lr->msgid) {
        !           430:       struct ldapconninfo *li = conn->proto.ldapc;
        !           431:       ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL);
        !           432:       lr->msgid = 0;
        !           433:     }
        !           434:     conn->data->req.protop = NULL;
        !           435:     free(lr);
        !           436:   }
        !           437: 
        !           438:   return CURLE_OK;
        !           439: }
        !           440: 
        !           441: static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
        !           442:                          size_t len, CURLcode *err)
        !           443: {
        !           444:   struct ldapconninfo *li = conn->proto.ldapc;
        !           445:   struct Curl_easy *data = conn->data;
        !           446:   ldapreqinfo *lr = data->req.protop;
        !           447:   int rc, ret;
        !           448:   LDAPMessage *msg = NULL;
        !           449:   LDAPMessage *ent;
        !           450:   BerElement *ber = NULL;
        !           451:   struct timeval tv = {0, 1};
        !           452: 
        !           453:   (void)len;
        !           454:   (void)buf;
        !           455:   (void)sockindex;
        !           456: 
        !           457:   rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_RECEIVED, &tv, &msg);
        !           458:   if(rc < 0) {
        !           459:     failf(data, "LDAP local: search ldap_result %s", ldap_err2string(rc));
        !           460:     *err = CURLE_RECV_ERROR;
        !           461:     return -1;
        !           462:   }
        !           463: 
        !           464:   *err = CURLE_AGAIN;
        !           465:   ret = -1;
        !           466: 
        !           467:   /* timed out */
        !           468:   if(!msg)
        !           469:     return ret;
        !           470: 
        !           471:   for(ent = ldap_first_message(li->ld, msg); ent;
        !           472:       ent = ldap_next_message(li->ld, ent)) {
        !           473:     struct berval bv, *bvals;
        !           474:     int binary = 0, msgtype;
        !           475:     CURLcode writeerr;
        !           476: 
        !           477:     msgtype = ldap_msgtype(ent);
        !           478:     if(msgtype == LDAP_RES_SEARCH_RESULT) {
        !           479:       int code;
        !           480:       char *info = NULL;
        !           481:       rc = ldap_parse_result(li->ld, ent, &code, NULL, &info, NULL, NULL, 0);
        !           482:       if(rc) {
        !           483:         failf(data, "LDAP local: search ldap_parse_result %s",
        !           484:               ldap_err2string(rc));
        !           485:         *err = CURLE_LDAP_SEARCH_FAILED;
        !           486:       }
        !           487:       else if(code && code != LDAP_SIZELIMIT_EXCEEDED) {
        !           488:         failf(data, "LDAP remote: search failed %s %s", ldap_err2string(rc),
        !           489:               info ? info : "");
        !           490:         *err = CURLE_LDAP_SEARCH_FAILED;
        !           491:       }
        !           492:       else {
        !           493:         /* successful */
        !           494:         if(code == LDAP_SIZELIMIT_EXCEEDED)
        !           495:           infof(data, "There are more than %d entries\n", lr->nument);
        !           496:         data->req.size = data->req.bytecount;
        !           497:         *err = CURLE_OK;
        !           498:         ret = 0;
        !           499:       }
        !           500:       lr->msgid = 0;
        !           501:       ldap_memfree(info);
        !           502:       break;
        !           503:     }
        !           504:     else if(msgtype != LDAP_RES_SEARCH_ENTRY)
        !           505:       continue;
        !           506: 
        !           507:     lr->nument++;
        !           508:     rc = ldap_get_dn_ber(li->ld, ent, &ber, &bv);
        !           509:     if(rc < 0) {
        !           510:       *err = CURLE_RECV_ERROR;
        !           511:       return -1;
        !           512:     }
        !           513:     writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
        !           514:     if(writeerr) {
        !           515:       *err = writeerr;
        !           516:       return -1;
        !           517:     }
        !           518: 
        !           519:     writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
        !           520:                                  bv.bv_len);
        !           521:     if(writeerr) {
        !           522:       *err = writeerr;
        !           523:       return -1;
        !           524:     }
        !           525: 
        !           526:     writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
        !           527:     if(writeerr) {
        !           528:       *err = writeerr;
        !           529:       return -1;
        !           530:     }
        !           531:     data->req.bytecount += bv.bv_len + 5;
        !           532: 
        !           533:     for(rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, &bvals);
        !           534:         rc == LDAP_SUCCESS;
        !           535:         rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, &bvals)) {
        !           536:       int i;
        !           537: 
        !           538:       if(bv.bv_val == NULL)
        !           539:         break;
        !           540: 
        !           541:       if(bv.bv_len > 7 && !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7))
        !           542:         binary = 1;
        !           543:       else
        !           544:         binary = 0;
        !           545: 
        !           546:       if(bvals == NULL) {
        !           547:         writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
        !           548:         if(writeerr) {
        !           549:           *err = writeerr;
        !           550:           return -1;
        !           551:         }
        !           552:         writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
        !           553:                                      bv.bv_len);
        !           554:         if(writeerr) {
        !           555:           *err = writeerr;
        !           556:           return -1;
        !           557:         }
        !           558:         writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":\n", 2);
        !           559:         if(writeerr) {
        !           560:           *err = writeerr;
        !           561:           return -1;
        !           562:         }
        !           563:         data->req.bytecount += bv.bv_len + 3;
        !           564:         continue;
        !           565:       }
        !           566: 
        !           567:       for(i = 0; bvals[i].bv_val != NULL; i++) {
        !           568:         int binval = 0;
        !           569:         writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
        !           570:         if(writeerr) {
        !           571:           *err = writeerr;
        !           572:           return -1;
        !           573:         }
        !           574: 
        !           575:         writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
        !           576:                                      bv.bv_len);
        !           577:         if(writeerr) {
        !           578:           *err = writeerr;
        !           579:           return -1;
        !           580:         }
        !           581: 
        !           582:         writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":", 1);
        !           583:         if(writeerr) {
        !           584:           *err = writeerr;
        !           585:           return -1;
        !           586:         }
        !           587:         data->req.bytecount += bv.bv_len + 2;
        !           588: 
        !           589:         if(!binary) {
        !           590:           /* check for leading or trailing whitespace */
        !           591:           if(ISSPACE(bvals[i].bv_val[0]) ||
        !           592:              ISSPACE(bvals[i].bv_val[bvals[i].bv_len-1]))
        !           593:             binval = 1;
        !           594:           else {
        !           595:             /* check for unprintable characters */
        !           596:             unsigned int j;
        !           597:             for(j = 0; j<bvals[i].bv_len; j++)
        !           598:               if(!ISPRINT(bvals[i].bv_val[j])) {
        !           599:                 binval = 1;
        !           600:                 break;
        !           601:               }
        !           602:           }
        !           603:         }
        !           604:         if(binary || binval) {
        !           605:           char *val_b64 = NULL;
        !           606:           size_t val_b64_sz = 0;
        !           607:           /* Binary value, encode to base64. */
        !           608:           CURLcode error = Curl_base64_encode(data,
        !           609:                                               bvals[i].bv_val,
        !           610:                                               bvals[i].bv_len,
        !           611:                                               &val_b64,
        !           612:                                               &val_b64_sz);
        !           613:           if(error) {
        !           614:             ber_memfree(bvals);
        !           615:             ber_free(ber, 0);
        !           616:             ldap_msgfree(msg);
        !           617:             *err = error;
        !           618:             return -1;
        !           619:           }
        !           620:           writeerr = Curl_client_write(conn, CLIENTWRITE_BODY,
        !           621:                                        (char *)": ", 2);
        !           622:           if(writeerr) {
        !           623:             *err = writeerr;
        !           624:             return -1;
        !           625:           }
        !           626: 
        !           627:           data->req.bytecount += 2;
        !           628:           if(val_b64_sz > 0) {
        !           629:             writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64,
        !           630:                                          val_b64_sz);
        !           631:             if(writeerr) {
        !           632:               *err = writeerr;
        !           633:               return -1;
        !           634:             }
        !           635:             free(val_b64);
        !           636:             data->req.bytecount += val_b64_sz;
        !           637:           }
        !           638:         }
        !           639:         else {
        !           640:           writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)" ", 1);
        !           641:           if(writeerr) {
        !           642:             *err = writeerr;
        !           643:             return -1;
        !           644:           }
        !           645: 
        !           646:           writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, bvals[i].bv_val,
        !           647:                                        bvals[i].bv_len);
        !           648:           if(writeerr) {
        !           649:             *err = writeerr;
        !           650:             return -1;
        !           651:           }
        !           652: 
        !           653:           data->req.bytecount += bvals[i].bv_len + 1;
        !           654:         }
        !           655:         writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
        !           656:         if(writeerr) {
        !           657:           *err = writeerr;
        !           658:           return -1;
        !           659:         }
        !           660: 
        !           661:         data->req.bytecount++;
        !           662:       }
        !           663:       ber_memfree(bvals);
        !           664:       writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
        !           665:       if(writeerr) {
        !           666:         *err = writeerr;
        !           667:         return -1;
        !           668:       }
        !           669:       data->req.bytecount++;
        !           670:     }
        !           671:     writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
        !           672:     if(writeerr) {
        !           673:       *err = writeerr;
        !           674:       return -1;
        !           675:     }
        !           676:     data->req.bytecount++;
        !           677:     ber_free(ber, 0);
        !           678:   }
        !           679:   ldap_msgfree(msg);
        !           680:   return ret;
        !           681: }
        !           682: 
        !           683: #ifdef USE_SSL
        !           684: static int
        !           685: ldapsb_tls_setup(Sockbuf_IO_Desc *sbiod, void *arg)
        !           686: {
        !           687:   sbiod->sbiod_pvt = arg;
        !           688:   return 0;
        !           689: }
        !           690: 
        !           691: static int
        !           692: ldapsb_tls_remove(Sockbuf_IO_Desc *sbiod)
        !           693: {
        !           694:   sbiod->sbiod_pvt = NULL;
        !           695:   return 0;
        !           696: }
        !           697: 
        !           698: /* We don't need to do anything because libcurl does it already */
        !           699: static int
        !           700: ldapsb_tls_close(Sockbuf_IO_Desc *sbiod)
        !           701: {
        !           702:   (void)sbiod;
        !           703:   return 0;
        !           704: }
        !           705: 
        !           706: static int
        !           707: ldapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
        !           708: {
        !           709:   (void)arg;
        !           710:   if(opt == LBER_SB_OPT_DATA_READY) {
        !           711:     struct connectdata *conn = sbiod->sbiod_pvt;
        !           712:     return Curl_ssl_data_pending(conn, FIRSTSOCKET);
        !           713:   }
        !           714:   return 0;
        !           715: }
        !           716: 
        !           717: static ber_slen_t
        !           718: ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
        !           719: {
        !           720:   struct connectdata *conn = sbiod->sbiod_pvt;
        !           721:   struct ldapconninfo *li = conn->proto.ldapc;
        !           722:   ber_slen_t ret;
        !           723:   CURLcode err = CURLE_RECV_ERROR;
        !           724: 
        !           725:   ret = (li->recv)(conn, FIRSTSOCKET, buf, len, &err);
        !           726:   if(ret < 0 && err == CURLE_AGAIN) {
        !           727:     SET_SOCKERRNO(EWOULDBLOCK);
        !           728:   }
        !           729:   return ret;
        !           730: }
        !           731: 
        !           732: static ber_slen_t
        !           733: ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
        !           734: {
        !           735:   struct connectdata *conn = sbiod->sbiod_pvt;
        !           736:   struct ldapconninfo *li = conn->proto.ldapc;
        !           737:   ber_slen_t ret;
        !           738:   CURLcode err = CURLE_SEND_ERROR;
        !           739: 
        !           740:   ret = (li->send)(conn, FIRSTSOCKET, buf, len, &err);
        !           741:   if(ret < 0 && err == CURLE_AGAIN) {
        !           742:     SET_SOCKERRNO(EWOULDBLOCK);
        !           743:   }
        !           744:   return ret;
        !           745: }
        !           746: 
        !           747: static Sockbuf_IO ldapsb_tls =
        !           748: {
        !           749:   ldapsb_tls_setup,
        !           750:   ldapsb_tls_remove,
        !           751:   ldapsb_tls_ctrl,
        !           752:   ldapsb_tls_read,
        !           753:   ldapsb_tls_write,
        !           754:   ldapsb_tls_close
        !           755: };
        !           756: #endif /* USE_SSL */
        !           757: 
        !           758: #endif /* !CURL_DISABLE_LDAP && USE_OPENLDAP */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>