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 }