Teach ypldap to use tls when connecting to ldap servers.
authorjmatthew <jmatthew@openbsd.org>
Tue, 30 May 2017 09:33:31 +0000 (09:33 +0000)
committerjmatthew <jmatthew@openbsd.org>
Tue, 30 May 2017 09:33:31 +0000 (09:33 +0000)
libtls help from jsing@, linker help from deraadt@

usr.sbin/ypldap/Makefile
usr.sbin/ypldap/aldap.c
usr.sbin/ypldap/aldap.h
usr.sbin/ypldap/ldapclient.c
usr.sbin/ypldap/parse.y
usr.sbin/ypldap/ypldap.conf.5
usr.sbin/ypldap/ypldap.h

index 6339334..178ffb1 100644 (file)
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.8 2015/09/09 15:33:18 deraadt Exp $
+# $OpenBSD: Makefile,v 1.9 2017/05/30 09:33:31 jmatthew Exp $
 
 PROG=          ypldap
 SRCS=          parse.y ypldap.c log.c  \
@@ -8,8 +8,9 @@ SRCS=           parse.y ypldap.c log.c  \
 
 MAN=           ypldap.8 ypldap.conf.5
 
-DPADD=         ${LIBEVENT} ${LIBUTIL} ${LIBRPCSVC}
-LDADD=         -levent -lutil -lrpcsvc
+DPADD=         ${LIBTLS} ${LIBSSL} ${LIBCRYPTO} ${LIBEVENT} ${LIBUTIL} \
+               ${LIBRPCSVC}
+LDADD=         -ltls -lssl -lcrypto -levent -lutil -lrpcsvc
 CFLAGS+=       -I${.CURDIR}
 CFLAGS+=       -Wall
 CFLAGS+=       -Wstrict-prototypes -Wmissing-prototypes
index 8e2d8a6..e1092c7 100644 (file)
@@ -1,5 +1,5 @@
-/*     $Id: aldap.c,v 1.36 2017/03/27 04:46:47 jmatthew Exp $ */
-/*     $OpenBSD: aldap.c,v 1.36 2017/03/27 04:46:47 jmatthew Exp $ */
+/*     $Id: aldap.c,v 1.37 2017/05/30 09:33:31 jmatthew Exp $ */
+/*     $OpenBSD: aldap.c,v 1.37 2017/05/30 09:33:31 jmatthew Exp $ */
 
 /*
  * Copyright (c) 2008 Alexander Schrijver <aschrijver@openbsd.org>
@@ -26,6 +26,8 @@
 #include <stdlib.h>
 #include <unistd.h>
 
+#include <event.h>
+
 #include "aldap.h"
 
 #if 0
@@ -43,6 +45,9 @@ static int                     isu8cont(unsigned char);
 char                           *parseval(char *, size_t);
 int                            aldap_create_page_control(struct ber_element *,
                                    int, struct aldap_page_control *);
+int                            aldap_send(struct aldap *,
+                                   struct ber_element *);
+unsigned long                  aldap_application(struct ber_element *);
 
 #ifdef DEBUG
 void                    ldap_debug_elements(struct ber_element *);
@@ -56,13 +61,21 @@ void                         ldap_debug_elements(struct ber_element *);
 #define LDAP_DEBUG(x, y)       do { } while (0)
 #endif
 
+unsigned long
+aldap_application(struct ber_element *elm)
+{
+       return BER_TYPE_OCTETSTRING;
+}
+
 int
 aldap_close(struct aldap *al)
 {
-       if (close(al->ber.fd) == -1)
-               return (-1);
+       if (al->fd != -1)
+               if (close(al->ber.fd) == -1)
+                       return (-1);
 
        ber_free(&al->ber);
+       evbuffer_free(al->buf);
        free(al);
 
        return (0);
@@ -75,16 +88,110 @@ aldap_init(int fd)
 
        if ((a = calloc(1, sizeof(*a))) == NULL)
                return NULL;
-       a->ber.fd = fd;
+       a->buf = evbuffer_new();
+       a->fd = fd;
+       a->ber.fd = -1;
+       ber_set_application(&a->ber, aldap_application);
 
        return a;
 }
 
+int
+aldap_tls(struct aldap *ldap, struct tls_config *cfg, const char *name)
+{
+       ldap->tls = tls_client();
+       if (ldap->tls == NULL) {
+               ldap->err = ALDAP_ERR_OPERATION_FAILED;
+               return (-1);
+       }
+
+       if (tls_configure(ldap->tls, cfg) == -1) {
+               ldap->err = ALDAP_ERR_TLS_ERROR;
+               return (-1);
+       }
+
+       if (tls_connect_socket(ldap->tls, ldap->fd, name) == -1) {
+               ldap->err = ALDAP_ERR_TLS_ERROR;
+               return (-1);
+       }
+
+       if (tls_handshake(ldap->tls) == -1) {
+               ldap->err = ALDAP_ERR_TLS_ERROR;
+               return (-1);
+       }
+
+       ldap->fd = -1;
+       return (0);
+}
+
+int
+aldap_send(struct aldap *ldap, struct ber_element *root)
+{
+       int error, wrote;
+       void *ptr;
+       char *data;
+       size_t len, done;
+
+       len = ber_calc_len(root);
+       error = ber_write_elements(&ldap->ber, root);
+       ber_free_elements(root);
+       if (error == -1)
+               return -1;
+
+       ber_get_writebuf(&ldap->ber, &ptr);
+       done = 0;
+       data = ptr;
+       while (len > 0) {
+               if (ldap->tls != NULL) {
+                       wrote = tls_write(ldap->tls, data + done, len);
+                       if (wrote == TLS_WANT_POLLIN ||
+                           wrote == TLS_WANT_POLLOUT)
+                               continue;
+               } else
+                       wrote = write(ldap->fd, data + done, len);
+
+               if (wrote == -1)
+                       return -1;
+
+               len -= wrote;
+               done += wrote;
+       }
+
+       return 0;
+}
+
+int
+aldap_req_starttls(struct aldap *ldap)
+{
+       struct ber_element *root = NULL, *ber;
+
+       if ((root = ber_add_sequence(NULL)) == NULL)
+               goto fail;
+
+       ber = ber_printf_elements(root, "d{tst", ++ldap->msgid, BER_CLASS_APP,
+           (unsigned long) LDAP_REQ_EXTENDED, LDAP_STARTTLS_OID,
+           BER_CLASS_CONTEXT, (unsigned long) 0);
+       if (ber == NULL) {
+               ldap->err = ALDAP_ERR_OPERATION_FAILED;
+               goto fail;
+       }
+
+       if (aldap_send(ldap, root) == -1)
+               goto fail;
+
+       return (ldap->msgid);
+fail:
+       if (root != NULL)
+               ber_free_elements(root);
+
+       ldap->err = ALDAP_ERR_OPERATION_FAILED;
+       return (-1);
+}
+
 int
 aldap_bind(struct aldap *ldap, char *binddn, char *bindcred)
 {
        struct ber_element *root = NULL, *elm;
-       int error;
 
        if (binddn == NULL)
                binddn = "";
@@ -102,12 +209,10 @@ aldap_bind(struct aldap *ldap, char *binddn, char *bindcred)
 
        LDAP_DEBUG("aldap_bind", root);
 
-       error = ber_write_elements(&ldap->ber, root);
-       ber_free_elements(root);
-       root = NULL;
-       if (error == -1)
+       if (aldap_send(ldap, root) == -1) {
+               root = NULL;
                goto fail;
-
+       }
        return (ldap->msgid);
 fail:
        if (root != NULL)
@@ -121,7 +226,6 @@ int
 aldap_unbind(struct aldap *ldap)
 {
        struct ber_element *root = NULL, *elm;
-       int error;
 
        if ((root = ber_add_sequence(NULL)) == NULL)
                goto fail;
@@ -132,12 +236,10 @@ aldap_unbind(struct aldap *ldap)
 
        LDAP_DEBUG("aldap_unbind", root);
 
-       error = ber_write_elements(&ldap->ber, root);
-       ber_free_elements(root);
-       root = NULL;
-       if (error == -1)
+       if (aldap_send(ldap, root) == -1) {
+               root = NULL;
                goto fail;
-
+       }
        return (ldap->msgid);
 fail:
        if (root != NULL)
@@ -154,7 +256,7 @@ aldap_search(struct aldap *ldap, char *basedn, enum scope scope, char *filter,
     struct aldap_page_control *page)
 {
        struct ber_element *root = NULL, *ber, *c;
-       int i, error;
+       int i;
 
        if ((root = ber_add_sequence(NULL)) == NULL)
                goto fail;
@@ -192,10 +294,8 @@ aldap_search(struct aldap *ldap, char *basedn, enum scope scope, char *filter,
 
        LDAP_DEBUG("aldap_search", root);
 
-       error = ber_write_elements(&ldap->ber, root);
-       ber_free_elements(root);
-       root = NULL;
-       if (error == -1) {
+       if (aldap_send(ldap, root) == -1) {
+               root = NULL;
                ldap->err = ALDAP_ERR_OPERATION_FAILED;
                goto fail;
        }
@@ -256,12 +356,44 @@ aldap_parse(struct aldap *ldap)
        long long                msgid = 0;
        struct aldap_message    *m;
        struct ber_element      *a = NULL, *ep;
+       char                     rbuf[512];
+       int                      ret, retry;
 
        if ((m = calloc(1, sizeof(struct aldap_message))) == NULL)
                return NULL;
 
-       if ((m->msg = ber_read_elements(&ldap->ber, NULL)) == NULL)
-               goto parsefail;
+       retry = 0;
+       while (m->msg == NULL) {
+               if (retry || EVBUFFER_LENGTH(ldap->buf) == 0) {
+                       if (ldap->tls) {
+                               ret = tls_read(ldap->tls, rbuf, sizeof(rbuf));
+                               if (ret == TLS_WANT_POLLIN ||
+                                   ret == TLS_WANT_POLLOUT)
+                                       continue;
+                       } else
+                               ret = read(ldap->fd, rbuf, sizeof(rbuf));
+
+                       if (ret == -1) {
+                               goto parsefail;
+                       }
+
+                       evbuffer_add(ldap->buf, rbuf, ret);
+               }
+
+               if (EVBUFFER_LENGTH(ldap->buf) > 0) {
+                       ber_set_readbuf(&ldap->ber, EVBUFFER_DATA(ldap->buf),
+                           EVBUFFER_LENGTH(ldap->buf));
+                       errno = 0;
+                       m->msg = ber_read_elements(&ldap->ber, NULL);
+                       if (errno != 0 && errno != ECANCELED) {
+                               goto parsefail;
+                       }
+
+                       retry = 1;
+               }
+       }
+
+       evbuffer_drain(ldap->buf, ldap->ber.br_rptr - ldap->ber.br_rbuf);
 
        LDAP_DEBUG("message", m->msg);
 
@@ -304,10 +436,17 @@ aldap_parse(struct aldap *ldap)
                if (ber_scanf_elements(m->protocol_op, "{e", &m->references) != 0)
                        goto parsefail;
                break;
+       case LDAP_RES_EXTENDED:
+               if (ber_scanf_elements(m->protocol_op, "{E",
+                   &m->body.res.rescode) != 0) {
+                       goto parsefail;
+               }
+               break;
        }
 
        return m;
 parsefail:
+       evbuffer_drain(ldap->buf, EVBUFFER_LENGTH(ldap->buf));
        ldap->err = ALDAP_ERR_PARSER_ERROR;
        aldap_freemsg(m);
        return NULL;
@@ -1241,6 +1380,9 @@ aldap_get_errno(struct aldap *a, const char **estr)
        case ALDAP_ERR_OPERATION_FAILED:
                *estr = "operation failed";
                break;
+       case ALDAP_ERR_TLS_ERROR:
+               *estr = tls_error(a->tls);
+               break;
        default:
                *estr = "unknown";
                break;
index 8e3a7d8..0ee6202 100644 (file)
@@ -1,5 +1,5 @@
-/*     $Id: aldap.h,v 1.9 2012/04/30 21:40:03 jmatthew Exp $ */
-/*     $OpenBSD: aldap.h,v 1.9 2012/04/30 21:40:03 jmatthew Exp $ */
+/*     $Id: aldap.h,v 1.10 2017/05/30 09:33:31 jmatthew Exp $ */
+/*     $OpenBSD: aldap.h,v 1.10 2017/05/30 09:33:31 jmatthew Exp $ */
 
 /*
  * Copyright (c) 2008 Alexander Schrijver <aschrijver@openbsd.org>
  */
 
 #include <stdio.h>
+
+#include <tls.h>
+
 #include "ber.h"
 
-#define LDAP_URL "ldap://"
-#define LDAP_PORT 389
-#define LDAP_PAGED_OID  "1.2.840.113556.1.4.319"
+#define LDAP_URL               "ldap://"
+#define LDAP_PORT              389
+#define LDAPS_PORT             636
+#define LDAP_PAGED_OID         "1.2.840.113556.1.4.319"
+#define LDAP_STARTTLS_OID      "1.3.6.1.4.1.1466.20037"
 
 struct aldap {
 #define ALDAP_ERR_SUCCESS              0
 #define ALDAP_ERR_PARSER_ERROR         1
 #define ALDAP_ERR_INVALID_FILTER       2
 #define ALDAP_ERR_OPERATION_FAILED     3
+#define ALDAP_ERR_TLS_ERROR            4
        u_int8_t        err;
        int             msgid;
        struct ber      ber;
+
+       int             fd;
+       struct tls      *tls;
+
+       struct evbuffer *buf;
 };
 
 struct aldap_page_control {
@@ -103,6 +114,9 @@ enum protocol_op {
        LDAP_REQ_ABANDON_30     = 16,
 
        LDAP_RES_SEARCH_REFERENCE = 19,
+
+       LDAP_REQ_EXTENDED       = 23,
+       LDAP_RES_EXTENDED       = 24
 };
 
 enum deref_aliases {
@@ -189,11 +203,15 @@ enum subfilter {
        LDAP_FILT_SUBS_FIN      = 2,
 };
 
-struct aldap           *aldap_init(int fd);
+struct aldap           *aldap_init(int);
+int                     aldap_tls(struct aldap *, struct tls_config *,
+                           const char *);
 int                     aldap_close(struct aldap *);
 struct aldap_message   *aldap_parse(struct aldap *);
 void                    aldap_freemsg(struct aldap_message *);
 
+int                     aldap_req_starttls(struct aldap *);
+
 int     aldap_bind(struct aldap *, char *, char *);
 int     aldap_unbind(struct aldap *);
 int     aldap_search(struct aldap *, char *, enum scope, char *, char **, int, int, int, struct aldap_page_control *);
index dbaae8b..57bcb31 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldapclient.c,v 1.38 2017/01/20 12:39:36 benno Exp $ */
+/* $OpenBSD: ldapclient.c,v 1.39 2017/05/30 09:33:31 jmatthew Exp $ */
 
 /*
  * Copyright (c) 2008 Alexander Schrijver <aschrijver@openbsd.org>
@@ -84,6 +84,7 @@ client_aldap_open(struct ypldap_addr_list *addr)
 
                warn("connect to %s port %s (%s) failed", hbuf, sbuf, "tcp");
                close(fd);
+               fd = -1;
        }
 
        if (fd == -1)
@@ -97,20 +98,28 @@ client_addr_init(struct idm *idm)
 {
         struct sockaddr_in      *sa_in;
         struct sockaddr_in6     *sa_in6;
-        struct ypldap_addr         *h;
+        struct ypldap_addr      *h;
+       int                     defport;
+
+       if (idm->idm_port != 0)
+               defport = idm->idm_port;
+       else if (idm->idm_flags & F_SSL)
+               defport = LDAPS_PORT;
+       else
+               defport = LDAP_PORT;
 
        TAILQ_FOREACH(h, &idm->idm_addr, next) {
                 switch (h->ss.ss_family) {
                 case AF_INET:
                         sa_in = (struct sockaddr_in *)&h->ss;
                         if (ntohs(sa_in->sin_port) == 0)
-                                sa_in->sin_port = htons(LDAP_PORT);
+                                sa_in->sin_port = htons(defport);
                         idm->idm_state = STATE_DNS_DONE;
                         break;
                 case AF_INET6:
                         sa_in6 = (struct sockaddr_in6 *)&h->ss;
                         if (ntohs(sa_in6->sin6_port) == 0)
-                                sa_in6->sin6_port = htons(LDAP_PORT);
+                                sa_in6->sin6_port = htons(defport);
                         idm->idm_state = STATE_DNS_DONE;
                         break;
                 default:
@@ -584,6 +593,39 @@ client_try_idm(struct env *env, struct idm *idm)
        if ((al = client_aldap_open(&idm->idm_addr)) == NULL)
                return (-1);
 
+       if (idm->idm_flags & F_STARTTLS) {
+               log_debug("requesting starttls");
+               where = "starttls";
+               if (aldap_req_starttls(al) == -1)
+                       goto bad;
+
+               where = "parsing";
+               if ((m = aldap_parse(al)) == NULL)
+                       goto bad;
+               where = "verifying msgid";
+               if (al->msgid != m->msgid) {
+                       aldap_freemsg(m);
+                       goto bad;
+               }
+               where = "starttls result";
+               if (aldap_get_resultcode(m) != LDAP_SUCCESS) {
+                       aldap_freemsg(m);
+                       goto bad;
+               }
+               aldap_freemsg(m);
+       }
+
+       if (idm->idm_flags & (F_STARTTLS | F_SSL)) {
+               log_debug("starting tls");
+               where = "enabling tls";
+               if (aldap_tls(al, idm->idm_tls_config, idm->idm_name) < 0) {
+                       const char *err;
+                       aldap_get_errno(al, &err);
+                       log_debug("tls failed: %s", err);
+                       goto bad;
+               }
+       }
+
        if (idm->idm_flags & F_NEEDAUTH) {
                where = "binding";
                if (aldap_bind(al, idm->idm_binddn, idm->idm_bindcred) == -1)
index e0a8a6e..9dc32c8 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: parse.y,v 1.21 2017/01/05 13:53:10 krw Exp $  */
+/*     $OpenBSD: parse.y,v 1.22 2017/05/30 09:33:31 jmatthew Exp $     */
 
 /*
  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -101,11 +101,12 @@ typedef struct {
 %token SERVER FILTER ATTRIBUTE BASEDN BINDDN GROUPDN BINDCRED MAPS CHANGE DOMAIN PROVIDE
 %token USER GROUP TO EXPIRE HOME SHELL GECOS UID GID INTERVAL
 %token PASSWD NAME FIXED LIST GROUPNAME GROUPPASSWD GROUPGID MAP
-%token INCLUDE DIRECTORY CLASS PORT ERROR GROUPMEMBERS
+%token INCLUDE DIRECTORY CLASS PORT ERROR GROUPMEMBERS LDAPS TLS CAFILE
 %token <v.string>      STRING
 %token  <v.number>     NUMBER
 %type  <v.number>      opcode attribute
-%type  <v.string>      port
+%type  <v.number>      port
+%type  <v.number>      ssl
 
 %%
 
@@ -157,8 +158,28 @@ varset             : STRING '=' STRING                     {
                }
                ;
 
-port           : /* empty */   { $$ = NULL; }
-               | PORT STRING   { $$ = $2; }
+port           : PORT STRING                           {
+                       struct servent *servent;
+
+                       servent = getservbyname($2, "tcp");
+                       if (servent == NULL) {
+                               yyerror("port %s is invalid", $2);
+                               free($2);
+                               YYERROR;
+                       }
+                       $$ = ntohs(servent->s_port);
+                       free($2);
+               }
+               | PORT NUMBER                           {
+                       if ($2 <= 0 || $2 >= (int)USHRT_MAX) {
+                               yyerror("invalid port: %lld", $2);
+                               YYERROR;
+                       }
+                       $$ = $2;
+               }
+               | /* empty */                           {
+                       $$ = 0;
+               }
                ;
 
 opcode         : GROUP                                 { $$ = 0; }
@@ -268,7 +289,12 @@ diropt             : BINDDN STRING                         {
                }
                ;
 
-directory      : DIRECTORY STRING port {
+ssl            : /* empty */                           { $$ = 0; }
+               | LDAPS                                 { $$ = F_SSL; }
+               | TLS                                   { $$ = F_STARTTLS; }
+               ;
+
+directory      : DIRECTORY STRING port ssl {
                        if ((idm = calloc(1, sizeof(*idm))) == NULL)
                                fatal(NULL);
                        idm->idm_id = conf->sc_maxid++;
@@ -280,8 +306,54 @@ directory  : DIRECTORY STRING port {
                                free($2);
                                YYERROR;
                        }
-
                        free($2);
+
+                       idm->idm_port = $3;
+
+                       if ($4 != 0) {
+                               if (tls_init()) {
+                                       yyerror("tls init failed");
+                                       YYERROR;
+                               }
+
+                               idm->idm_flags |= $4;
+                               idm->idm_tls_config = tls_config_new();
+                               if (idm->idm_tls_config == NULL) {
+                                       yyerror("tls config failed");
+                                       YYERROR;
+                               }
+
+                               if (tls_config_set_protocols(
+                                   idm->idm_tls_config,
+                                   TLS_PROTOCOLS_ALL) == -1) {
+                                       yyerror("tls set protocols failed: %s",
+                                           tls_config_error(
+                                           idm->idm_tls_config));
+                                       tls_config_free(idm->idm_tls_config);
+                                       idm->idm_tls_config = NULL;
+                                       YYERROR;
+                               }
+                               if (tls_config_set_ciphers(idm->idm_tls_config,
+                                   "compat") == -1) {
+                                       yyerror("tls set ciphers failed: %s",
+                                           tls_config_error(
+                                           idm->idm_tls_config));
+                                       tls_config_free(idm->idm_tls_config);
+                                       idm->idm_tls_config = NULL;
+                                       YYERROR;
+                               }
+
+                               if (tls_config_set_ca_file(idm->idm_tls_config,
+                                   conf->sc_cafile) == -1) {
+                                       yyerror("tls set CA bundle failed: %s",
+                                           tls_config_error(
+                                           idm->idm_tls_config));
+                                       tls_config_free(idm->idm_tls_config);
+                                       idm->idm_tls_config = NULL;
+                                       YYERROR;
+                               }
+                       }
+
                } '{' optnl diropts '}'                 {
                        TAILQ_INSERT_TAIL(&conf->sc_idms, idm, idm_entry);
                        idm = NULL;
@@ -324,6 +396,10 @@ main               : INTERVAL NUMBER                       {
                        }
                        free($3);
                }
+               | CAFILE STRING                         {
+                       free(conf->sc_cafile);
+                       conf->sc_cafile = $2;
+               } 
                ;
 
 diropts                : diropts diropt nl
@@ -368,6 +444,7 @@ lookup(char *s)
                { "basedn",             BASEDN },
                { "bindcred",           BINDCRED },
                { "binddn",             BINDDN },
+               { "cafile",             CAFILE },
                { "change",             CHANGE },
                { "class",              CLASS },
                { "directory",          DIRECTORY },
@@ -386,6 +463,7 @@ lookup(char *s)
                { "home",               HOME },
                { "include",            INCLUDE },
                { "interval",           INTERVAL },
+               { "ldaps",              LDAPS },
                { "list",               LIST },
                { "map",                MAP },
                { "maps",               MAPS },
@@ -395,6 +473,7 @@ lookup(char *s)
                { "provide",            PROVIDE },
                { "server",             SERVER },
                { "shell",              SHELL },
+               { "tls",                TLS },
                { "to",                 TO },
                { "uid",                UID },
                { "user",               USER },
@@ -731,6 +810,11 @@ parse_config(struct env *x_conf, const char *filename, int opts)
        TAILQ_INIT(&conf->sc_idms);
        conf->sc_conf_tv.tv_sec = DEFAULT_INTERVAL;
        conf->sc_conf_tv.tv_usec = 0;
+       conf->sc_cafile = strdup(YPLDAP_CERT_FILE);
+       if (conf->sc_cafile == NULL) {
+               log_warn("malloc");
+               return (-1);
+       }
 
        errors = 0;
 
index 386368b..656b760 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: ypldap.conf.5,v 1.19 2012/04/30 11:28:25 jmatthew Exp $
+.\"    $OpenBSD: ypldap.conf.5,v 1.20 2017/05/30 09:33:31 jmatthew Exp $
 .\"
 .\" Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
 .\"
@@ -14,7 +14,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: April 30 2012 $
+.Dd $Mdocdate: May 30 2017 $
 .Dt YPLDAP.CONF 5
 .Os
 .Sh NAME
@@ -52,7 +52,6 @@ Macros are not expanded inside quotes.
 .Pp
 For example:
 .Bd -literal -offset indent
-
 fixed_gecos="Pulled from LDAP"
 
 fixed attribute gecos $fixed_gecos
@@ -73,6 +72,10 @@ Specify a map that should be provided by
 .Nm
 The currently implemented maps are: passwd.byname, passwd.byuid,
 group.byname, group.bygid.
+.It Ic cafile Ar filename
+Load CA certificates from the specified file to validate the server certificate.
+If not specified, CA certificates will be loaded from
+.Pa /etc/ssl/cert.pem .
 .El
 .Sh DIRECTORIES
 Directories are used to describe the LDAP schema and help
@@ -83,11 +86,23 @@ convert LDAP entries to
 and
 .Xr group 5
 lines.
-A directory declaration is of the following form:
-.Bd -literal -offset indent
-directory "some.host" {
-       # directives
-}
+Each directory section consists of a declaration of the directory
+server name and a set of directives describing how entries from the
+directory are used to construct YP map entries.
+.Bl -tag -width Ds
+.It Ic directory Ar hostname Oo Ic port Ar port Oc Oo tls Oc Brq ...
+Defines a directory by hostname and optionally port number.
+If the
+.Ar tls
+argument is not specified, no transport-level security will be used.
+Valid options are:
+.Bl -tag -width Ds
+.It Ic tls
+Use STARTTLS to negotiate TLS, by default on port 389.
+.It Ic ldaps
+Connect with TLS enabled, by default on port 636.
+.El
+.El
 .Ed
 .Pp
 Valid directives for directories are:
index 8ee7222..6903663 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ypldap.h,v 1.18 2017/01/20 12:39:36 benno Exp $ */
+/*     $OpenBSD: ypldap.h,v 1.19 2017/05/30 09:33:31 jmatthew Exp $ */
 
 /*
  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
  */
 
 #include <imsg.h>
+#include <tls.h>
 
 #define YPLDAP_USER            "_ypldap"
 #define YPLDAP_CONF_FILE       "/etc/ypldap.conf"
+#define YPLDAP_CERT_FILE       "/etc/ssl/cert.pem"
 #define DEFAULT_INTERVAL       600
 #define LINE_WIDTH             1024
 #define FILTER_WIDTH           128
@@ -91,6 +93,7 @@ struct idm {
 #define F_SSL                           0x00100000
 #define F_CONFIGURING                   0x00200000
 #define F_NEEDAUTH                      0x00400000
+#define F_STARTTLS                      0x00800000
 #define F_FIXED_ATTR(n)                         (1<<n)
 #define F_LIST(n)                        (1<<n)
        enum client_state                idm_state;
@@ -124,10 +127,7 @@ struct idm {
 #define ATTR_GR_MAX                     14
        char                             idm_attrs[14][ATTR_WIDTH];
        struct env                      *idm_env;
-       struct event                     idm_ev;
-#ifdef SSL
-       struct ssl                      *idm_ssl;
-#endif
+       struct tls_config               *idm_tls_config;
 };
 
 struct idm_req {
@@ -164,6 +164,7 @@ struct env {
        char                             sc_domainname[HOST_NAME_MAX+1];
        struct timeval                   sc_conf_tv;
        struct event                     sc_conf_ev;
+       char                            *sc_cafile;
        TAILQ_HEAD(idm_list, idm)        sc_idms;
        struct imsgev                   *sc_iev;
        struct imsgev                   *sc_iev_dns;