File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / openldap.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (5 years, 6 months ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    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>