Home | History | Annotate | Download | only in libnisdb
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2001-2003 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include <sys/systeminfo.h>
     30 #include <strings.h>
     31 #include <rpcsvc/nis.h>
     32 
     33 #include "nis_parse_ldap_conf.h"
     34 
     35 #include "ldap_attr.h"
     36 #include "ldap_util.h"
     37 #include "ldap_structs.h"
     38 
     39 
     40 /*
     41  * If 'name' doesn't end in a trailing dot, return a copy with the
     42  * value of "nisplusLDAPbaseDomain" appended. Otherwise, return a
     43  * copy of 'name'. If deallocate!=0, free 'name'.
     44  */
     45 char *
     46 fullObjName(int deallocate, char *name) {
     47 	int	l;
     48 	char	*full;
     49 	char	*myself = "fullObjName";
     50 
     51 	if (name == 0)
     52 		return (sdup(myself, T, proxyInfo.default_nis_domain));
     53 
     54 	l = strlen(name);
     55 	if (name[l-1] == '.') {
     56 		full = sdup(myself, T, name);
     57 	} else {
     58 		full = scat(myself, T, scat(myself, F, name, "."),
     59 			sdup(myself, T, proxyInfo.default_nis_domain));
     60 	}
     61 	if (deallocate)
     62 		free(name);
     63 
     64 	return (full);
     65 }
     66 
     67 /*
     68  * Convert a domain name ("x.y.z.", say) to a "dc=..." type LDAP equivalent
     69  * ("dc=x,dc=y,dx=z"). The domain name supplied MUST be terminated by a
     70  * trailing dot. If 'domain' is NULL, the value of "nisplusLDAPbaseDomain"
     71  * is converted.
     72  */
     73 char *
     74 domain2base(char *domain) {
     75 	char	*base = 0;
     76 	int	l, i;
     77 	char	*myself = "domain2base";
     78 
     79 	if (domain == 0)
     80 		domain = sdup(myself, T, proxyInfo.default_nis_domain);
     81 	if (domain == 0)
     82 		return (0);
     83 
     84 	for (l = 0, i = 0; domain[i] != '\0'; i++) {
     85 		if (domain[i] == '.') {
     86 			domain[i] = '\0';
     87 			if (l != 0)
     88 				base = scat(myself, T, base,
     89 					scat(myself, F, ",dc=", &domain[l]));
     90 			else
     91 				base = scat(myself, T, base,
     92 					scat(myself, F, "dc=", &domain[l]));
     93 			l = i+1;
     94 		}
     95 	}
     96 
     97 	return (base);
     98 }
     99 
    100 /*
    101  * If 'name' ends in a trailing comma, append the value of the
    102  * "defaultSearchBase". If deallocate!=0, free 'name'.
    103  */
    104 char *
    105 fullLDAPname(int deallocate, char *name) {
    106 	int	err = 0;
    107 
    108 	return (appendBase(name, proxyInfo.default_search_base, &err,
    109 				deallocate));
    110 }
    111 
    112 /*
    113  * If the 'item' string ends in a comma, append 'base', and return
    114  * the result. On exit, '*err' will be zero if successful, non-zero
    115  * otherwise. If 'dealloc' is non-zero, 'item' is freed; this happens
    116  * even if an error status is returned.
    117  *
    118  * The return value is always allocated, and must be freed by the caller.
    119  */
    120 char *
    121 appendBase(char *item, char *base, int *err, int dealloc) {
    122 	char	*new;
    123 	int	len, deferr;
    124 	char	*myself = "appendBase";
    125 
    126 	/*
    127 	 * Make sure that 'err' points to something valid, so that we can
    128 	 * dispense with all those 'if (err != 0)'.
    129 	 */
    130 	if (err == 0)
    131 		err = &deferr;
    132 
    133 	/* Establish default (successful) error status */
    134 	*err = 0;
    135 
    136 	/* Trivial case 1: If 'item' is NULL, return a copy of 'base' */
    137 	if (item == 0) {
    138 		new = sdup(myself, T, base);
    139 		if (new == 0)
    140 			*err = -1;
    141 		return (new);
    142 	}
    143 
    144 	/* Trivial case 2: If 'base' is NULL, return a copy of 'item' */
    145 	if (base == 0) {
    146 		new = sdup(myself, T, item);
    147 		if (new == 0)
    148 			*err = -1;
    149 		if (dealloc)
    150 			free(item);
    151 		return (new);
    152 	}
    153 
    154 	len = strlen(item);
    155 
    156 	/* If 'item' is the empty string, return a copy of 'base' */
    157 	if (len <= 0) {
    158 		new = sdup(myself, T, base);
    159 		if (new == 0)
    160 			*err = -1;
    161 		if (dealloc)
    162 			free(item);
    163 		return (new);
    164 	}
    165 
    166 	/*
    167 	 * If 'item' ends in a comma, append 'base', and return a copy
    168 	 * of the result. Otherwise, return a copy of 'item'.
    169 	 */
    170 	if (item[len-1] == ',') {
    171 		int	blen = slen(base);
    172 		new = am(myself, len + blen + 1);
    173 		if (new != 0) {
    174 			(void) memcpy(new, item, len);
    175 			(void) memcpy(&new[len], base, blen);
    176 		} else {
    177 			*err = -1;
    178 		}
    179 	} else {
    180 		new = sdup(myself, T, item);
    181 		if (new == 0)
    182 			*err = -1;
    183 	}
    184 
    185 	if (dealloc)
    186 		free(item);
    187 
    188 	return (new);
    189 }
    190 
    191 /*
    192  * Despite its general-sounding name, this function only knows how to
    193  * turn a list of attributes ("a,b,c") into an AND filter ("(&(a)(b)(c))").
    194  */
    195 char *
    196 makeFilter(char *attr) {
    197 	int	len, s, e, c;
    198 	char	*str, *filter, *tmp;
    199 	char	*myself = "makeFilter";
    200 
    201 	if (attr == 0 || (len = strlen(attr)) == 0)
    202 		return (0);
    203 
    204 	/* Assume already of appropriate form if first char is '(' */
    205 	if (len > 1 && attr[0] == '(' && attr[len-1] == ')')
    206 		return (sdup(myself, T, attr));
    207 
    208 	str = sdup(myself, T, attr);
    209 	if (str == 0)
    210 		return (0);
    211 	filter = sdup(myself, T, "(&");
    212 	if (filter == 0) {
    213 		free(str);
    214 		return (0);
    215 	}
    216 	for (s = c = 0; s < len; s = e+1) {
    217 		/* Skip blank space, if any */
    218 		for (0; str[s] == ' ' || str[s] == '\t'; s++);
    219 		/* Find delimiter (comma) or end of string */
    220 		for (e = s; str[e] != '\0' && str[e] != ','; e++);
    221 		str[e] = '\0';
    222 		tmp = scat(myself, T, sdup(myself, T, "("),
    223 			scat(myself, F, &str[s], ")"));
    224 		if (tmp == 0) {
    225 			sfree(filter);
    226 			return (0);
    227 		}
    228 		c++;
    229 		filter = scat(myself, T, filter, tmp);
    230 	}
    231 
    232 	/*
    233 	 * If there's just one component, we return it as is. This
    234 	 * means we avoid turning "objectClass=posixAccount" into
    235 	 * "(&(objectClass=posixAccount))".
    236 	 */
    237 	if (c == 1) {
    238 		sfree(filter);
    239 		return (str);
    240 	}
    241 
    242 	/* Add the closing ')' */
    243 	tmp = filter;
    244 	filter = scat(myself, F, tmp, ")");
    245 	sfree(tmp);
    246 
    247 	free(str);
    248 
    249 	return (filter);
    250 }
    251 
    252 /*
    253  * Split an AND-filter string into components.
    254  */
    255 char **
    256 makeFilterComp(char *filter, int *numComps) {
    257 	int	nc = 0, s, e, i;
    258 	char	**comp = 0, **new, *str;
    259 	int	len;
    260 	char	*myself = "makeFilterComp";
    261 
    262 	if ((len = slen(filter)) <= 0)
    263 		return (0);
    264 
    265 	/* Is it just a plain "attr=val" string ? If so, return a copy */
    266 	if (len <= 2 || filter[0] != '(') {
    267 		comp = am(myself, 2 * sizeof (comp[0]));
    268 		if (comp == 0)
    269 			return (0);
    270 		comp[0] = sdup(myself, T, filter);
    271 		if (comp[0] == 0) {
    272 			sfree(comp);
    273 			return (0);
    274 		}
    275 		if (numComps != 0)
    276 			*numComps = 1;
    277 		return (comp);
    278 	}
    279 
    280 	if (filter != 0 && (len = strlen(filter)) != 0 && len > 2 &&
    281 			filter[0] == '(' && filter[1] == '&' &&
    282 			filter[len-1] == ')') {
    283 		str = sdup(myself, T, filter);
    284 		if (str == 0)
    285 			return (0);
    286 		for (s = 2; s < len; s = e+1) {
    287 			/* Skip past the '(' */
    288 			for (0; s < len && str[s] != '('; s++);
    289 			s++;
    290 			if (s >= len)
    291 				break;
    292 			for (e = s; str[e] != '\0' && str[e] != ')'; e++);
    293 			str[e] = '\0';
    294 			new = realloc(comp, (nc+1) * sizeof (comp[nc]));
    295 			if (new == 0) {
    296 				if (comp != 0) {
    297 					for (i = 0; i < nc; i++)
    298 						sfree(comp[i]);
    299 					free(comp);
    300 					comp = 0;
    301 				}
    302 				nc = 0;
    303 				break;
    304 			}
    305 			comp = new;
    306 			comp[nc] = sdup(myself, T, &str[s]);
    307 			if (comp[nc] == 0) {
    308 				for (i = 0; i < nc; i++)
    309 					sfree(comp[i]);
    310 				sfree(comp);
    311 				comp = 0;
    312 				nc = 0;
    313 				break;
    314 			}
    315 			nc++;
    316 		}
    317 		sfree(str);
    318 	}
    319 
    320 	if (numComps != 0)
    321 		*numComps = nc;
    322 
    323 	return (comp);
    324 }
    325 
    326 void
    327 freeFilterComp(char **comp, int numComps) {
    328 	int	i;
    329 
    330 	if (comp == 0)
    331 		return;
    332 
    333 	for (i = 0; i < numComps; i++) {
    334 		sfree(comp[i]);
    335 	}
    336 	free(comp);
    337 }
    338 
    339 char **
    340 addFilterComp(char *new, char **comp, int *numComps) {
    341 	char	**tmp, *str;
    342 	char	*myself = "addFilterComp";
    343 
    344 	if (new == 0 || numComps == 0 || *numComps < 0)
    345 		return (comp);
    346 
    347 	str = sdup(myself, T, new);
    348 	if (str == 0)
    349 		return (0);
    350 	tmp = realloc(comp, ((*numComps)+1) * sizeof (comp[0]));
    351 	if (tmp == 0) {
    352 		sfree(str);
    353 		return (0);
    354 	}
    355 
    356 	comp = tmp;
    357 	comp[*numComps] = str;
    358 	*numComps += 1;
    359 
    360 	return (comp);
    361 }
    362 
    363 char *
    364 concatenateFilterComps(int numComps, char **comp) {
    365 	int		i;
    366 	__nis_buffer_t	b = {0, 0};
    367 	char		*myself = "concatenateFilterComps";
    368 
    369 	if (numComps == 0 || comp == 0)
    370 		return (0);
    371 
    372 	bp2buf(myself, &b, "(&");
    373 	for (i = 0; i < numComps; i++) {
    374 		if (comp[i] == 0)
    375 			continue;
    376 		bp2buf(myself, &b, "(%s)", comp[i]);
    377 	}
    378 	bp2buf(myself, &b, ")");
    379 
    380 	return (b.buf);
    381 }
    382 
    383 void
    384 freeDNs(char **dn, int numDN) {
    385 	int	i;
    386 
    387 	if (dn == 0)
    388 		return;
    389 
    390 	for (i = 0; i < numDN; i++) {
    391 		sfree(dn[i]);
    392 	}
    393 	sfree(dn);
    394 }
    395 
    396 /*
    397  * Search the supplied rule-value structure array for any attributes called
    398  * "dn", and return their values. If the "dn" value(s) end in a comma, they
    399  * get the 'defBase' value appended.
    400  */
    401 char **
    402 findDNs(char *msg, __nis_rule_value_t *rv, int nrv, char *defBase,
    403 		int *numDN) {
    404 	char	**dn;
    405 	int	irv, iv, ndn;
    406 	char	*myself = "findDNs";
    407 
    408 	if (rv == 0 || nrv <= 0 || numDN == 0)
    409 		return (0);
    410 
    411 	if (msg == 0)
    412 		msg = myself;
    413 
    414 	/* Avoid realloc() by pre-allocating 'dn' at maximum size */
    415 	dn = am(msg, nrv * sizeof (dn[0]));
    416 	if (dn == 0)
    417 		return (0);
    418 
    419 	for (ndn = 0, irv = 0; irv < nrv; irv++) {
    420 		for (iv = 0; iv < rv[irv].numAttrs; iv++) {
    421 			/* Looking for string-valued attribute called "dn" */
    422 			if (rv[irv].attrName[iv] != 0 &&
    423 				rv[irv].attrVal[iv].type == vt_string &&
    424 				rv[irv].attrVal[iv].numVals >= 1 &&
    425 				strcasecmp("dn", rv[irv].attrName[iv]) == 0) {
    426 				int	err = 0;
    427 				dn[ndn] = appendBase(
    428 					rv[irv].attrVal[iv].val[0].value,
    429 					defBase, &err, 0);
    430 				if (err != 0) {
    431 					freeDNs(dn, ndn);
    432 					return (0);
    433 				}
    434 				ndn++;
    435 				break;
    436 			}
    437 		}
    438 	}
    439 
    440 	*numDN = ndn;
    441 	return (dn);
    442 }
    443