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 }