ping
On 10/23/18 9:50 AM, Martijn van Duren wrote:
> The following diff is a half decent solution to the problems and
> (together with my earlier patches) makes our output (minus the comments)
> identical to ldapsearch output (for my particular usecase).
>
> Another issue I addressed in this patch is that a base64 encoded value
> must be prepended with an additional colon according to rfc2849:
> value-spec = ":" ( FILL 0*1(SAFE-STRING) /
> ":" FILL (BASE64-STRING) /
> "<" FILL url)
> ; See notes 7 and 8, below
>
> The aldap return strings where I'm certain that the OCTETSTRINGS must
> be an LDAPString I've retained the utoa. Functions that aren't used
> in ldap(1) I've transformed because it was easier for now and should
> be revisited when backporting to ypldap.
>
> And although the SAFE-CHARS are defined as
> SAFE-CHAR %x01-09 / %x0B-0C / %x0E-7F
> I think it would be wise to follow ldapsearch's lead, where they also
> encode non-printable and strings containing only whitespace. This way
> the output is more human readable when the output is just a whitespace
> and we don't have the risk of sending escape-sequences to the console.
>
> Thoughts on both the diff and b64 encoding some of the SAFE-STRINGs?
>
> martijn@
>
> On 10/22/18 9:01 AM, Martijn van Duren wrote:
>> I found another bug while testing ldap(1) to M$ AD.
>> Attributes like objectGUID are encoded as OCTET STRING, but are binary
>> data, which are not UTF-8 strings.
>> When looking at RFC4511 I found the following:
>> 4.1.5. Attribute Value
>> A field of type AttributeValue is an OCTET STRING containing an
>> encoded attribute value. The attribute value is encoded according to
>> the LDAP-specific encoding definition of its corresponding syntax.
>>
>> So we should not blindly utoa on an OCTET STRING.
>>
>> Diff below alleviates the problems when comparing the output of
>> ldapsearch from OpenLDAP, but is probably horribly wrong.
>>
>> Note that because of the current assumptions some values aren't printed
>> at all, because they contain NUL-characters in the string. The patch
>> below does not address this issue.
>>
>> martijn@
>>
> Index: aldap.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/ldap/aldap.c,v
> retrieving revision 1.5
> diff -u -p -r1.5 aldap.c
> --- aldap.c 12 Aug 2018 22:04:09 -0000 1.5
> +++ aldap.c 23 Oct 2018 07:35:54 -0000
> @@ -39,7 +39,7 @@ static struct ber_element *ldap_parse_se
> char *);
> static struct ber_element *ldap_do_parse_search_filter(
> struct ber_element *, char **);
> -char **aldap_get_stringset(struct ber_element *);
> +struct ber_octetstring *aldap_get_stringset(struct ber_element
> *);
> char *utoa(char *);
> static int isu8cont(unsigned char);
> char *parseval(char *, size_t);
> @@ -511,7 +511,7 @@ aldap_get_resultcode(struct aldap_messag
> char *
> aldap_get_dn(struct aldap_message *msg)
> {
> - char *dn;
> + struct ber_octetstring dn;
>
> if (msg->dn == NULL)
> return NULL;
> @@ -519,10 +519,10 @@ aldap_get_dn(struct aldap_message *msg)
> if (ber_get_string(msg->dn, &dn) == -1)
> return NULL;
>
> - return utoa(dn);
> + return utoa(dn.bv_val);
> }
>
> -char **
> +struct ber_octetstring *
> aldap_get_references(struct aldap_message *msg)
> {
> if (msg->references == NULL)
> @@ -547,7 +547,7 @@ aldap_free_references(char **values)
> char *
> aldap_get_diagmsg(struct aldap_message *msg)
> {
> - char *s;
> + struct ber_octetstring s;
>
> if (msg->body.res.diagmsg == NULL)
> return NULL;
> @@ -555,7 +555,7 @@ aldap_get_diagmsg(struct aldap_message *
> if (ber_get_string(msg->body.res.diagmsg, &s) == -1)
> return NULL;
>
> - return utoa(s);
> + return utoa(s.bv_val);
> }
>
> int
> @@ -576,11 +576,12 @@ aldap_count_attrs(struct aldap_message *
> }
>
> int
> -aldap_first_attr(struct aldap_message *msg, char **outkey, char ***outvalues)
> +aldap_first_attr(struct aldap_message *msg, char **outkey,
> + struct ber_octetstring **outvalues)
> {
> struct ber_element *b, *c;
> char *key;
> - char **ret;
> + struct ber_octetstring *ret;
>
> if (msg->body.search.attrs == NULL)
> goto fail;
> @@ -605,11 +606,12 @@ fail:
> }
>
> int
> -aldap_next_attr(struct aldap_message *msg, char **outkey, char ***outvalues)
> +aldap_next_attr(struct aldap_message *msg, char **outkey,
> + struct ber_octetstring **outvalues)
> {
> struct ber_element *a, *b;
> char *key;
> - char **ret;
> + struct ber_octetstring *ret;
>
> if (msg->body.search.iter == NULL)
> goto notfound;
> @@ -640,11 +642,12 @@ notfound:
> }
>
> int
> -aldap_match_attr(struct aldap_message *msg, char *inkey, char ***outvalues)
> +aldap_match_attr(struct aldap_message *msg, char *inkey,
> + struct ber_octetstring **outvalues)
> {
> struct ber_element *a, *b;
> char *descr = NULL;
> - char **ret;
> + struct ber_octetstring *ret;
>
> if (msg->body.search.attrs == NULL)
> goto fail;
> @@ -677,16 +680,11 @@ notfound:
> }
>
> int
> -aldap_free_attr(char **values)
> +aldap_free_attr(struct ber_octetstring *values)
> {
> - int i;
> -
> if (values == NULL)
> return -1;
>
> - for (i = 0; values[i] != NULL; i++)
> - free(values[i]);
> -
> free(values);
>
> return (1);
> @@ -836,13 +834,12 @@ fail:
> * internal functions
> */
>
> -char **
> +struct ber_octetstring *
> aldap_get_stringset(struct ber_element *elm)
> {
> struct ber_element *a;
> int i;
> - char **ret;
> - char *s;
> + struct ber_octetstring *ret;
>
> if (elm->be_type != BER_TYPE_OCTETSTRING)
> return NULL;
> @@ -853,16 +850,13 @@ aldap_get_stringset(struct ber_element *
> if (i == 1)
> return NULL;
>
> - if ((ret = calloc(i + 1, sizeof(char *))) == NULL)
> + if ((ret = calloc(i + 1, sizeof(*ret))) == NULL)
> return NULL;
>
> for (a = elm, i = 0; a != NULL && a->be_type == BER_TYPE_OCTETSTRING;
> a = a->be_next, i++) {
> -
> - ber_get_string(a, &s);
> - ret[i] = utoa(s);
> + ber_get_string(a, &(ret[i]));
> }
> - ret[i + 1] = NULL;
>
> return ret;
> }
> Index: aldap.h
> ===================================================================
> RCS file: /cvs/src/usr.bin/ldap/aldap.h,v
> retrieving revision 1.1.1.1
> diff -u -p -r1.1.1.1 aldap.h
> --- aldap.h 13 Jun 2018 15:45:57 -0000 1.1.1.1
> +++ aldap.h 23 Oct 2018 07:35:54 -0000
> @@ -226,7 +226,7 @@ int aldap_get_errno(struct aldap *, con
> int aldap_get_resultcode(struct aldap_message *);
> char *aldap_get_dn(struct aldap_message *);
> char *aldap_get_diagmsg(struct aldap_message *);
> -char **aldap_get_references(struct aldap_message *);
> +struct ber_octetstring *aldap_get_references(struct aldap_message *);
> void aldap_free_references(char **values);
> int aldap_parse_url(const char *, struct aldap_url *);
> void aldap_free_url(struct aldap_url *);
> @@ -234,10 +234,13 @@ int aldap_search_url(struct aldap *, ch
> struct aldap_page_control *);
>
> int aldap_count_attrs(struct aldap_message *);
> -int aldap_match_attr(struct aldap_message *, char *, char ***);
> -int aldap_first_attr(struct aldap_message *, char **, char ***);
> -int aldap_next_attr(struct aldap_message *, char **, char ***);
> -int aldap_free_attr(char **);
> +int aldap_match_attr(struct aldap_message *, char *,
> + struct ber_octetstring **);
> +int aldap_first_attr(struct aldap_message *, char **,
> + struct ber_octetstring **);
> +int aldap_next_attr(struct aldap_message *, char **,
> + struct ber_octetstring **);
> +int aldap_free_attr(struct ber_octetstring *);
>
> struct aldap_page_control *aldap_parse_page_control(struct ber_element *,
> size_t len);
> void aldap_freepage(struct aldap_page_control *);
> Index: ber.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/ldap/ber.c,v
> retrieving revision 1.19
> diff -u -p -r1.19 ber.c
> --- ber.c 12 Aug 2018 22:04:09 -0000 1.19
> +++ ber.c 23 Oct 2018 07:35:54 -0000
> @@ -283,12 +283,13 @@ ber_add_nstring(struct ber_element *prev
> }
>
> int
> -ber_get_string(struct ber_element *elm, char **s)
> +ber_get_string(struct ber_element *elm, struct ber_octetstring *s)
> {
> if (elm->be_encoding != BER_TYPE_OCTETSTRING)
> return -1;
>
> - *s = elm->be_val;
> + s->bv_val = elm->be_val;
> + s->be_len = elm->be_len;
> return 0;
> }
>
> @@ -660,6 +661,7 @@ ber_scanf_elements(struct ber_element *b
> off_t *pos;
> struct ber_oid *o;
> struct ber_element *parent[_MAX_SEQ], **e;
> + struct ber_octetstring octstr;
>
> memset(parent, 0, sizeof(struct ber_element *) * _MAX_SEQ);
>
> @@ -714,8 +716,9 @@ ber_scanf_elements(struct ber_element *b
> break;
> case 's':
> s = va_arg(ap, char **);
> - if (ber_get_string(ber, s) == -1)
> + if (ber_get_string(ber, &octstr) == -1)
> goto fail;
> + *s = octstr.bv_val;
> ret++;
> break;
> case 't':
> Index: ber.h
> ===================================================================
> RCS file: /cvs/src/usr.bin/ldap/ber.h,v
> retrieving revision 1.7
> diff -u -p -r1.7 ber.h
> --- ber.h 12 Aug 2018 22:04:09 -0000 1.7
> +++ ber.h 23 Oct 2018 07:35:54 -0000
> @@ -52,6 +52,11 @@ struct ber {
> unsigned int (*br_application)(struct ber_element *);
> };
>
> +struct ber_octetstring {
> + void *bv_val;
> + size_t be_len;
> +};
> +
> /* well-known ber_element types */
> #define BER_TYPE_DEFAULT ((unsigned int)-1)
> #define BER_TYPE_EOC 0
> @@ -104,7 +109,8 @@ int ber_get_boolean(struct
> ber_elemen
> struct ber_element *ber_add_string(struct ber_element *, const char *);
> struct ber_element *ber_add_nstring(struct ber_element *, const char *,
> size_t);
> -int ber_get_string(struct ber_element *, char **);
> +int ber_get_string(struct ber_element *, struct
> + ber_octetstring *);
> int ber_get_nstring(struct ber_element *, void **,
> size_t *);
> struct ber_element *ber_add_bitstring(struct ber_element *, const void *,
> Index: ldapclient.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/ldap/ldapclient.c,v
> retrieving revision 1.3
> diff -u -p -r1.3 ldapclient.c
> --- ldapclient.c 3 Jul 2018 10:10:09 -0000 1.3
> +++ ldapclient.c 23 Oct 2018 07:35:54 -0000
> @@ -83,7 +83,8 @@ struct ldapc_search {
> __dead void usage(void);
> int ldapc_connect(struct ldapc *);
> int ldapc_search(struct ldapc *, struct ldapc_search *);
> -int ldapc_printattr(struct ldapc *, const char *, const char *);
> +int ldapc_printattr(struct ldapc *, const char *,
> + struct ber_octetstring *);
> void ldapc_disconnect(struct ldapc *);
> int ldapc_parseurl(struct ldapc *, struct ldapc_search *,
> const char *);
> @@ -298,7 +299,7 @@ ldapc_search(struct ldapc *ldap, struct
> const char *errstr;
> const char *searchdn, *dn = NULL;
> char *outkey;
> - char **outvalues;
> + struct ber_octetstring *outvalues;
> int ret, i, code, fail = 0;
>
> do {
> @@ -359,9 +360,9 @@ ldapc_search(struct ldapc *ldap, struct
> ret != -1;
> ret = aldap_next_attr(m, &outkey, &outvalues)) {
> for (i = 0; outvalues != NULL &&
> - outvalues[i] != NULL; i++) {
> + outvalues[i].bv_val != NULL; i++) {
> if (ldapc_printattr(ldap, outkey,
> - outvalues[i]) == -1) {
> + &(outvalues[i])) == -1) {
> fail = 1;
> break;
> }
> @@ -383,11 +384,13 @@ ldapc_search(struct ldapc *ldap, struct
> }
>
> int
> -ldapc_printattr(struct ldapc *ldap, const char *key, const char *value)
> +ldapc_printattr(struct ldapc *ldap, const char *key,
> + struct ber_octetstring *value)
> {
> char *p = NULL, *out;
> const unsigned char *cp;
> int encode;
> + size_t i;
> size_t inlen, outlen, left;
>
> if (ldap->ldap_flags & F_LDIF) {
> @@ -402,34 +405,34 @@ ldapc_printattr(struct ldapc *ldap, cons
> * in SAFE-STRINGs. String value that do not match the
> * criteria must be encoded as Base64.
> */
> - for (cp = (const unsigned char *)value;
> - encode == 0 &&*cp != '\0'; cp++) {
> + for (cp = value->bv_val, i = 0;
> + encode == 0 && i <= value->be_len - 1; i++) {
> /* !SAFE-CHAR %x01-09 / %x0B-0C / %x0E-7F */
> - if (*cp > 127 ||
> - *cp == '\0' ||
> - *cp == '\n' ||
> - *cp == '\r')
> + if (cp[i] > 127 ||
> + cp[i] == '\0' ||
> + cp[i] == '\n' ||
> + cp[i] == '\r')
> encode = 1;
> }
>
> if (!encode) {
> - if (asprintf(&p, "%s: %s", key, value) == -1) {
> + if (asprintf(&p, "%s: %s", key, value->bv_val) == -1) {
> log_warnx("asprintf");
> return (-1);
> }
> } else {
> - inlen = strlen(value);
> - outlen = inlen * 2 + 1;
> + outlen = value->be_len * 2 + 1;
>
> if ((out = calloc(1, outlen)) == NULL ||
> - b64_ntop(value, inlen, out, outlen) == -1) {
> + b64_ntop(value->bv_val, value->be_len, out, outlen)
> + == -1) {
> log_warnx("Base64 encoding failed");
> free(p);
> return (-1);
> }
>
> /* Base64 is indicated with a double-colon */
> - if (asprintf(&p, "%s: %s", key, out) == -1) {
> + if (asprintf(&p, "%s:: %s", key, out) == -1) {
> log_warnx("asprintf");
> free(out);
> return (-1);
> @@ -458,7 +461,9 @@ ldapc_printattr(struct ldapc *ldap, cons
> * on all values no matter if they include non-printable
> * characters.
> */
> - if (stravis(&p, value, VIS_SAFE|VIS_NL) == -1) {
> + p = calloc(1, 4 * value->be_len + 1);
> + if (strvisx(p, value->bv_val, value->be_len, VIS_SAFE|VIS_NL)
> + == -1) {
> log_warn("visual encoding failed");
> return (-1);
> }
>