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