Annotation of embedaddon/curl/lib/openldap.c, revision 1.1.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>