Edit

IABSD.fr/src/usr.sbin/ldapd/attributes.c

Branch :

  • Show log

    Commit

  • Author : claudio
    Date : 2021-12-20 13:26:11
    Hash : 5387241f
    Message : When removing the last value from an attribute in ldap_del_values() the actuall attribute needs to removed instead of leaving back an empty attribute. Empty attributes are not valid and fail later on in ldap_modify(). By calling ldap_del_attribute() in this case properly removes the attribute and with that validate_entry() no longer fails later on. OK jmatthew@

  • usr.sbin/ldapd/attributes.c
  • /*	$OpenBSD: attributes.c,v 1.7 2021/12/20 13:26:11 claudio Exp $ */
    
    /*
     * Copyright (c) 2009 Martin Hedenfalk <martin@bzero.se>
     *
     * Permission to use, copy, modify, and distribute this software for any
     * purpose with or without fee is hereby granted, provided that the above
     * copyright notice and this permission notice appear in all copies.
     *
     * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     */
    
    #include <sys/queue.h>
    #include <sys/types.h>
    
    #include <assert.h>
    #include <string.h>
    #include <time.h>
    
    #include "ldapd.h"
    #include "log.h"
    
    struct ber_element *
    ldap_get_attribute(struct ber_element *entry, const char *attr)
    {
    	char			*s;
    	struct ber_element	*elm, *a;
    
    	assert(entry);
    	assert(attr);
    	if (entry->be_encoding != BER_TYPE_SEQUENCE)
    		return NULL;
    
    	for (elm = entry->be_sub; elm != NULL; elm = elm->be_next) {
    		a = elm->be_sub;
    		if (a && ober_get_string(a, &s) == 0 && strcasecmp(s, attr) == 0)
    			return a;
    	}
    
    	return NULL;
    }
    
    struct ber_element *
    ldap_find_attribute(struct ber_element *entry, struct attr_type *at)
    {
    	struct ber_element	*elm = NULL;
    	struct name		*an;
    
    	SLIST_FOREACH(an, at->names, next) {
    		if ((elm = ldap_get_attribute(entry, an->name)) != NULL)
    			return elm;
    	}
    	if (an == NULL)
    		elm = ldap_get_attribute(entry, at->oid);
    
    	return elm;
    }
    
    struct ber_element *
    ldap_find_value(struct ber_element *elm, const char *value)
    {
    	char			*s;
    	struct ber_element	*a;
    
    	if (elm == NULL)
    		return NULL;
    
    	for (a = elm->be_sub; a != NULL; a = a->be_next) {
    		if (ober_get_string(a, &s) == 0 && strcasecmp(s, value) == 0)
    			return a;
    	}
    
    	return NULL;
    }
    
    struct ber_element *
    ldap_add_attribute(struct ber_element *entry, const char *attr,
    	struct ber_element *value_set)
    {
    	struct ber_element	*elm, *a, *last;
    
    	assert(entry);
    	assert(attr);
    	assert(value_set);
    
    	if (entry->be_encoding != BER_TYPE_SEQUENCE) {
    		log_warnx("entries should be a sequence");
    		return NULL;
    	}
    
    	if (value_set->be_type != BER_TYPE_SET) {
    		log_warnx("values should be a set");
    		return NULL;
    	}
    
    	last = entry->be_sub;
    	if (last == NULL)
    		last = entry;
    	else while (last != NULL && last->be_next != NULL)
    		last = last->be_next;
    
    	if ((elm = ober_add_sequence(last)) == NULL)
    		return NULL;
    	if ((a = ober_add_string(elm, attr)) == NULL) {
    		ober_free_elements(elm);
    		return NULL;
    	}
    	ober_link_elements(a, value_set);
    
    	return elm;
    }
    
    int
    ldap_set_values(struct ber_element *elm, struct ber_element *vals)
    {
    	char			*attr;
    	struct ber_element	*old_vals;
    
    	assert(elm);
    	assert(vals);
    	assert(vals->be_sub);
    
    	if (ober_scanf_elements(elm, "se(", &attr, &old_vals) != 0) {
    		log_warnx("failed to parse element");
    		return -1;
    	}
    
    	ober_free_elements(old_vals->be_sub);
    	old_vals->be_sub = NULL;
    	ober_link_elements(old_vals, vals->be_sub);
    
    	vals->be_sub = NULL;
    	ober_free_elements(vals);
    
    	return 0;
    }
    
    int
    ldap_merge_values(struct ber_element *elm, struct ber_element *vals)
    {
    	char			*attr;
    	struct ber_element	*old_vals, *last;
    
    	assert(elm);
    	assert(vals);
    	assert(vals->be_type == BER_TYPE_SET);
    	assert(vals->be_sub);
    
    	if (ober_scanf_elements(elm, "se(", &attr, &old_vals) != 0) {
    		log_warnx("failed to parse element");
    		return -1;
    	}
    
    	last = old_vals->be_sub;
    	while (last && last->be_next)
    		last = last->be_next;
    
    	ober_link_elements(last, vals->be_sub);
    
    	vals->be_sub = NULL;
    	ober_free_elements(vals);
    
    	return 0;
    }
    
    
    int
    ldap_del_attribute(struct ber_element *entry, const char *attrdesc)
    {
    	struct ber_element	*attr, *prev = NULL;
    	char			*s;
    
    	assert(entry);
    	assert(attrdesc);
    
    	attr = entry->be_sub;
    	while (attr) {
    		if (ober_scanf_elements(attr, "{s", &s) != 0) {
    			log_warnx("failed to parse attribute");
    			return -1;
    		}
    
    		if (strcasecmp(s, attrdesc) == 0) {
    			if (prev == NULL)
    				entry->be_sub = attr->be_next;
    			else
    				prev->be_next = attr->be_next;
    			attr->be_next = NULL;
    			ober_free_elements(attr);
    			break;
    		}
    
    		prev = attr;
    		attr = attr->be_next;
    	}
    
    	return 0;
    }
    
    int
    ldap_del_values(struct ber_element *elm, struct ber_element *vals)
    {
    	char			*attr;
    	struct ber_element	*old_vals, *v, *x, *prev, *next;
    	struct ber_element	*removed;
    	int			removed_p;
    	assert(elm);
    	assert(vals);
    	assert(vals->be_sub);
    
    	if (ober_scanf_elements(elm, "se(", &attr, &old_vals) != 0) {
    		log_warnx("failed to parse element");
    		return -1;
    	}
    
    	prev = old_vals;
    	removed_p = 0;
    	for (v = old_vals->be_sub; v; v = next) {
    		next = v->be_next;
    
    		for (x = vals->be_sub; x; x = x->be_next) {
    			if (x && v->be_len == x->be_len &&
    			    memcmp(v->be_val, x->be_val, x->be_len) == 0) {
    				removed = ober_unlink_elements(prev);
    				ober_link_elements(prev, removed->be_next);
    				ober_free_element(removed);
    				removed_p = 1;
    				break;
    			}
    		}
    		if (removed_p) {
    			removed_p = 0;
    		} else {
    			prev = v;
    		}
    	}
    
    	if (old_vals->be_sub == NULL)
    		return 1;
    
    	return 0;
    }
    
    char *
    ldap_strftime(time_t tm)
    {
    	static char	 tmbuf[16];
    	struct tm	*gmt = gmtime(&tm);
    
    	strftime(tmbuf, sizeof(tmbuf), "%Y%m%d%H%M%SZ", gmt);
    	return tmbuf;
    }
    
    char *
    ldap_now(void)
    {
    	return ldap_strftime(time(0));
    }