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 (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2013 Gary Mills
  23  *
  24  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  25  * Use is subject to license terms.
  26  */
  27 
  28 
  29 #include <syslog.h>
  30 #include "ldap_common.h"
  31 
  32 /* netgroup attributes filters */
  33 #define _N_TRIPLE               "nisnetgrouptriple"
  34 #define _N_MEMBER               "membernisnetgroup"
  35 
  36 #define PRINT_VAL(a)            (((a).argc == 0) || ((a).argv == NULL) || \
  37                                     ((a).argv[0] == NULL)) ? "*" : (a).argv[0]
  38 #define ISNULL(a)               (a == NULL ? "<NULL>" : a)
  39 #define MAX_DOMAIN_LEN          1024
  40 #ifdef  LOGNAME_MAX_ILLUMOS
  41 #define MAX_TRIPLE_LEN          (MAXHOSTNAMELEN + LOGNAME_MAX_ILLUMOS + \
  42                                         MAX_DOMAIN_LEN + 5)
  43 #else /* LOGNAME_MAX_ILLUMOS */
  44 #define MAX_TRIPLE_LEN          (MAXHOSTNAMELEN + LOGNAME_MAX + \
  45                                         MAX_DOMAIN_LEN + 5)
  46 #endif /* LOGNAME_MAX_ILLUMOS */
  47 
  48 #define _F_SETMEMBER            "(&(objectClass=nisNetGroup)(cn=%s))"
  49 #define _F_SETMEMBER_SSD        "(&(%%s)(cn=%s))"
  50 
  51 #define N_HASH          257
  52 #define COMMA           ','
  53 
  54 static const char *netgrent_attrs[] = {
  55         _N_TRIPLE,
  56         _N_MEMBER,
  57         (char *)NULL
  58 };
  59 
  60 typedef struct netgroup_name {
  61         char *name;
  62         struct netgroup_name *next;
  63         struct netgroup_name *next_hash;
  64 } netgroup_name_t;
  65 
  66 typedef struct {
  67         netgroup_name_t *hash_list[N_HASH];
  68         netgroup_name_t *to_do;
  69         netgroup_name_t *done;
  70 } netgroup_table_t;
  71 
  72 typedef struct {
  73         ns_ldap_result_t *results;
  74         ns_ldap_entry_t *entry;
  75         char **attrs;
  76         char *netgroup;
  77         netgroup_table_t tab;
  78 } getnetgrent_cookie_t;
  79 
  80 typedef struct {
  81         struct nss_innetgr_args *ia;
  82         const char *ssd_filter;
  83         const char *netgrname;
  84         const char *membername;
  85         netgroup_table_t tab;
  86 } innetgr_cookie_t;
  87 
  88 typedef unsigned int hash_t;
  89 
  90 static hash_t
  91 get_hash(const char *s)
  92 {
  93         unsigned int sum = 0;
  94         unsigned int i;
  95 
  96         for (i = 0; s[i] != '\0'; i++)
  97                 sum += ((unsigned char *)s)[i];
  98 
  99         return ((sum + i) % N_HASH);
 100 }
 101 
 102 /*
 103  * Adds a name to the netgroup table
 104  *
 105  * Returns
 106  *      0 if successfully added or already present
 107  *      -1 if memory allocation error or NULL netgroup_table_t
 108  *         from caller.
 109  */
 110 
 111 static int
 112 add_netgroup_name(const char *name, netgroup_table_t *tab)
 113 {
 114         hash_t          h;
 115         netgroup_name_t *ng;
 116         netgroup_name_t *ng_new;
 117 
 118         if (tab == NULL) {
 119                 /*
 120                  * Should never happen. But if it does,
 121                  * that's an error condition.
 122                  */
 123                 return (-1);
 124         }
 125         if (name == NULL || *name == '\0') {
 126                 /* no name to add means success */
 127                 return (0);
 128         }
 129 
 130         h = get_hash(name);
 131         ng = tab->hash_list[h];
 132 
 133         while (ng != NULL) {
 134                 if (strcmp(name, ng->name) == 0)
 135                         break;
 136                 ng = ng->next_hash;
 137         }
 138 
 139         if (ng == NULL) {
 140                 ng_new = (netgroup_name_t *)
 141                     calloc(1, sizeof (netgroup_name_t));
 142                 if (ng_new == NULL)
 143                         return (-1);
 144                 ng_new->name = strdup(name);
 145                 if (ng_new->name == NULL) {
 146                         free(ng_new);
 147                         return (-1);
 148                 }
 149                 ng_new->next_hash = tab->hash_list[h];
 150                 tab->hash_list[h] = ng_new;
 151                 ng_new->next = tab->to_do;
 152                 tab->to_do = ng_new;
 153         }
 154         return (0);
 155 }
 156 
 157 static netgroup_name_t *
 158 get_next_netgroup(netgroup_table_t *tab)
 159 {
 160         netgroup_name_t *ng;
 161 
 162         if (tab == NULL)
 163                 return (NULL);
 164 
 165         ng = tab->to_do;
 166         if (ng != NULL) {
 167                 tab->to_do = ng->next;
 168                 ng->next = tab->done;
 169                 tab->done = ng;
 170         }
 171         return (ng);
 172 }
 173 
 174 static void
 175 free_netgroup_table(netgroup_table_t *tab)
 176 {
 177         netgroup_name_t *ng, *next;
 178 
 179         if (tab == NULL)
 180                 return;
 181 
 182         for (ng = tab->to_do; ng != NULL; ng = next) {
 183                 if (ng->name != NULL)
 184                         free(ng->name);
 185                 next = ng->next;
 186                 free(ng);
 187         }
 188 
 189         for (ng = tab->done; ng != NULL; ng = next) {
 190                 if (ng->name != NULL)
 191                         free(ng->name);
 192                 next = ng->next;
 193                 free(ng);
 194         }
 195         (void) memset(tab, 0, sizeof (*tab));
 196 }
 197 
 198 /*
 199  * domain comparing routine
 200  *      n1: See if n1 is n2 or an ancestor of it
 201  *      n2: (in string terms, n1 is a suffix of n2)
 202  * Returns ZERO for success, -1 for failure.
 203  */
 204 static int
 205 domcmp(const char *n1, const char *n2)
 206 {
 207 #define PASS    0
 208 #define FAIL    -1
 209 
 210         size_t          l1, l2;
 211 
 212         if ((n1 == NULL) || (n2 == NULL))
 213                 return (FAIL);
 214 
 215         l1 = strlen(n1);
 216         l2 = strlen(n2);
 217 
 218         /* Turn a blind eye to the presence or absence of trailing periods */
 219         if (l1 != 0 && n1[l1 - 1] == '.') {
 220                 --l1;
 221         }
 222         if (l2 != 0 && n2[l2 - 1] == '.') {
 223                 --l2;
 224         }
 225         if (l1 > l2) {               /* Can't be a suffix */
 226                 return (FAIL);
 227         } else if (l1 == 0) {   /* Trivially a suffix; */
 228                                 /* (do we want this case?) */
 229                 return (PASS);
 230         }
 231         /* So 0 < l1 <= l2 */
 232         if (l1 < l2 && n2[l2 - l1 - 1] != '.') {
 233                 return (FAIL);
 234         }
 235         if (strncasecmp(n1, &n2[l2 - l1], l1) == 0) {
 236                 return (PASS);
 237         } else {
 238                 return (FAIL);
 239         }
 240 }
 241 
 242 static int
 243 split_triple(char *triple, char **hostname, char **username, char **domain)
 244 {
 245         int     i, syntax_err;
 246         char    *splittriple[3];
 247         char    *p = triple;
 248 
 249 #ifdef  DEBUG
 250         (void) fprintf(stdout, "\n[getnetgrent.c: split_triple]\n");
 251 #endif  /* DEBUG */
 252 
 253         if (triple == NULL)
 254                 return (-1);
 255 
 256         p++;
 257         syntax_err = 0;
 258         for (i = 0; i < 3; i++) {
 259                 char    *start;
 260                 char    *limit;
 261                 const char      *terminators = ",) \t";
 262 
 263                 if (i == 2) {
 264                         /* Don't allow comma */
 265                         terminators++;
 266                 }
 267                 while (isspace(*p)) {
 268                         p++;
 269                 }
 270                 start = p;
 271                 limit = strpbrk(start, terminators);
 272                 if (limit == 0) {
 273                         syntax_err++;
 274                         break;
 275                 }
 276                 p = limit;
 277                 while (isspace(*p)) {
 278                         p++;
 279                 }
 280                 if (*p == terminators[0]) {
 281                         /*
 282                          * Successfully parsed this name and
 283                          * the separator after it (comma or
 284                          * right paren); leave p ready for
 285                          * next parse.
 286                          */
 287                         p++;
 288                         if (start == limit) {
 289                                 /* Wildcard */
 290                                 splittriple[i] = NULL;
 291                         } else {
 292                                 *limit = '\0';
 293                                 splittriple[i] = start;
 294                         }
 295                 } else {
 296                         syntax_err++;
 297                         break;
 298                 }
 299         }
 300 
 301         if (syntax_err != 0)
 302                 return (-1);
 303 
 304         *hostname = splittriple[0];
 305         *username = splittriple[1];
 306         *domain = splittriple[2];
 307 
 308         return (0);
 309 }
 310 
 311 /*
 312  * Test membership in triple
 313  *      return 0 = no match
 314  *      return 1 = match
 315  */
 316 
 317 static int
 318 match_triple_entry(struct nss_innetgr_args *ia, const ns_ldap_entry_t *entry)
 319 {
 320         int     ndomains;
 321         char    **pdomains;
 322         int     nhost;
 323         char    **phost;
 324         int     nusers;
 325         char    **pusers;
 326         char    **attr;
 327         char    triple[MAX_TRIPLE_LEN];
 328         char    *tuser, *thost, *tdomain;
 329         int     i;
 330         char    *current, *limit;
 331         int     pulen, phlen;
 332         char    *pusers0, *phost0;
 333 
 334         nhost = ia->arg[NSS_NETGR_MACHINE].argc;
 335         phost = (char **)ia->arg[NSS_NETGR_MACHINE].argv;
 336         if (phost == NULL || *phost == NULL) {
 337                 nhost = 0;
 338         } else {
 339                 phost0 = phost[0];
 340                 phlen = strlen(phost0);
 341 #ifdef DEBUG
 342                 syslog(LOG_DEBUG, "nss_ldap: match_triple_entry: "
 343                     "entering with host: %s", phost0 ? phost0 : "");
 344 #endif
 345         }
 346         nusers = ia->arg[NSS_NETGR_USER].argc;
 347         pusers = (char **)ia->arg[NSS_NETGR_USER].argv;
 348         if (pusers == NULL || *pusers == NULL) {
 349                 nusers = 0;
 350         } else {
 351                 pusers0 = pusers[0];
 352                 pulen = strlen(pusers0);
 353 #ifdef DEBUG
 354                 syslog(LOG_DEBUG, "nss_ldap: match_triple_entry: "
 355                     "entering with user: %s", pusers0 ? pusers0 : "");
 356 #endif
 357         }
 358         ndomains = ia->arg[NSS_NETGR_DOMAIN].argc;
 359         pdomains = (char **)ia->arg[NSS_NETGR_DOMAIN].argv;
 360         if (pdomains == NULL || *pdomains == NULL)
 361                 ndomains = 0;
 362 #ifdef DEBUG
 363         else
 364                 syslog(LOG_DEBUG, "nss_ldap: match_triple_entry: "
 365                     "entering with domain: %s", pdomains[0] ? pdomains[0] : "");
 366 #endif
 367 
 368         attr = __ns_ldap_getAttr(entry, _N_TRIPLE);
 369         if (attr == NULL || *attr == NULL)
 370                 return (0);
 371 
 372 #ifdef DEBUG
 373         syslog(LOG_DEBUG, "nss_ldap: match_triple_entry: "
 374             "(nusers: %d, nhost:%d, ndomains: %d)",
 375             nusers, nhost, ndomains);
 376 #endif
 377 
 378         /* Special cases for speedup */
 379         if (nusers == 1 && nhost == 0 && ndomains == 0) {
 380                 /* Special case for finding a single user in a netgroup */
 381                 for (; *attr; attr++) {
 382                         /* jump to first comma and check next character */
 383                         current = *attr;
 384 #ifdef DEBUG
 385                         syslog(LOG_DEBUG, "nss_ldap: match_triple_entry: "
 386                             "current is: %s", current);
 387 #endif
 388                         if ((current = strchr(current, COMMA)) == NULL)
 389                                 continue;
 390                         current++;
 391 
 392                         /* skip whitespaces */
 393                         while (isspace(*current))
 394                                 current++;
 395 
 396                         /* if user part is null, then treat as wildcard */
 397                         if (*current == COMMA)
 398                                 return (1);
 399 
 400                         /* compare first character */
 401                         if (*pusers0 != *current)
 402                                 continue;
 403 
 404                         /* limit username to COMMA */
 405                         if ((limit = strchr(current, COMMA)) == NULL)
 406                                 continue;
 407                         *limit = '\0';
 408 
 409                         /* remove blanks before COMMA */
 410                         if ((limit = strpbrk(current, " \t")) != NULL)
 411                                 *limit = '\0';
 412 
 413                         /* compare size of username */
 414                         if (pulen != strlen(current)) {
 415                                 continue;
 416                         }
 417 
 418                         /* do actual compare */
 419                         if (strncmp(pusers0, current, pulen) == 0) {
 420                                 return (1);
 421                         } else {
 422                                 continue;
 423                         }
 424                 }
 425         } else if (nusers == 0 && nhost == 1 && ndomains == 0) {
 426                 /* Special case for finding a single host in a netgroup */
 427                 for (; *attr; attr++) {
 428 
 429                         /* jump to first character and check */
 430                         current = *attr;
 431 #ifdef DEBUG
 432                         syslog(LOG_DEBUG, "nss_ldap: match_triple_entry: "
 433                             "current is: %s", current);
 434 #endif
 435                         current++;
 436 
 437                         /* skip whitespaces */
 438                         while (isspace(*current))
 439                                 current++;
 440 
 441                         /* if host part is null, then treat as wildcard */
 442                         if (*current == COMMA)
 443                                 return (1);
 444 
 445                         /* limit hostname to COMMA */
 446                         if ((limit = strchr(current, COMMA)) == NULL)
 447                                 continue;
 448                         *limit = '\0';
 449 
 450                         /* remove blanks before COMMA */
 451                         if ((limit = strpbrk(current, " \t")) != NULL)
 452                                 *limit = '\0';
 453 
 454                         /* compare size of hostname */
 455                         if (phlen != strlen(current)) {
 456                                 continue;
 457                         }
 458 
 459                         /* do actual compare */
 460                         if (strncasecmp(phost0, current, phlen) == 0) {
 461                                 return (1);
 462                         } else {
 463                                 continue;
 464                         }
 465                 }
 466         } else {
 467                 for (; *attr; attr++) {
 468                         if (strlcpy(triple, *attr,
 469                             sizeof (triple)) >= sizeof (triple))
 470                                 continue;
 471 #ifdef DEBUG
 472                         syslog(LOG_DEBUG, "nss_ldap: match_triple_entry: "
 473                             "triple is: %s", triple);
 474 #endif
 475                         if (split_triple(triple, &thost, &tuser, &tdomain) != 0)
 476                                 continue;
 477                         if (thost != NULL && *thost != '\0' && nhost != 0) {
 478                                 for (i = 0; i < nhost; i++)
 479                                         if (strcasecmp(thost, phost[i]) == 0)
 480                                                 break;
 481                                 if (i == nhost)
 482                                         continue;
 483                         }
 484                         if (tuser != NULL && *tuser != '\0' && nusers != 0) {
 485                                 for (i = 0; i < nusers; i++)
 486                                         if (strcmp(tuser, pusers[i]) == 0)
 487                                                 break;
 488                                 if (i == nusers)
 489                                         continue;
 490                         }
 491                         if (tdomain != NULL && *tdomain != '\0' &&
 492                             ndomains != 0) {
 493                                 for (i = 0; i < ndomains; i++)
 494                                         if (domcmp(tdomain, pdomains[i]) == 0)
 495                                                 break;
 496                                 if (i == ndomains)
 497                                         continue;
 498                         }
 499                         return (1);
 500                 }
 501         }
 502 
 503         return (0);
 504 }
 505 
 506 static int
 507 match_triple(struct nss_innetgr_args *ia, ns_ldap_result_t *result)
 508 {
 509         ns_ldap_entry_t *entry;
 510 
 511         for (entry = result->entry; entry != NULL; entry = entry->next)
 512                 if (match_triple_entry(ia, entry) == 1)
 513                         return (1);
 514 
 515         return (0);
 516 }
 517 
 518 static int
 519 add_netgroup_member_entry(ns_ldap_entry_t *entry, netgroup_table_t *tab)
 520 {
 521         char            **attrs;
 522         char            **a;
 523 
 524         attrs = __ns_ldap_getAttr(entry, _N_MEMBER);
 525         if (attrs == NULL || *attrs == NULL)
 526                 return (0);
 527 
 528         for (a = attrs; *a != NULL; a++) {}
 529 
 530         do {
 531                 a--;
 532                 if (add_netgroup_name(*a, tab) != 0)
 533                         return (-1);
 534         } while (a > attrs);
 535         return (0);
 536 }
 537 
 538 static int
 539 add_netgroup_member(ns_ldap_result_t *result, netgroup_table_t *tab)
 540 {
 541         ns_ldap_entry_t *entry;
 542         int             ret = 0;
 543 
 544         for (entry = result->entry; entry != NULL; entry = entry->next) {
 545                 ret = add_netgroup_member_entry(entry, tab);
 546                 if (ret != 0)
 547                         break;
 548         }
 549         return (ret);
 550 }
 551 
 552 /*
 553  * top_down_search checks only checks the netgroup specified in netgrname
 554  */
 555 static nss_status_t
 556 top_down_search(struct nss_innetgr_args *ia, char *netgrname)
 557 {
 558         char                    searchfilter[SEARCHFILTERLEN];
 559         char                    name[SEARCHFILTERLEN];
 560         char                    userdata[SEARCHFILTERLEN];
 561         ns_ldap_result_t        *result = NULL;
 562         ns_ldap_error_t         *error = NULL;
 563         int                     rc;
 564         nss_status_t            status = NSS_NOTFOUND;
 565         nss_status_t            status1;
 566         netgroup_table_t        tab;
 567         netgroup_name_t         *ng;
 568         int                     ret;
 569 
 570         (void) memset(&tab, 0, sizeof (tab));
 571 
 572         if (add_netgroup_name(netgrname, &tab) != 0)
 573                 return ((nss_status_t)NSS_NOTFOUND);
 574 
 575         while ((ng = get_next_netgroup(&tab)) != NULL) {
 576 #ifdef DEBUG
 577                 syslog(LOG_DEBUG, "nss_ldap: top_down_search: netgroup  loop "
 578                     "(ng->name: %s)", ng->name ? ng->name : "null !");
 579 #endif
 580                 if (_ldap_filter_name(name, ng->name, sizeof (name)) != 0)
 581                         break;
 582                 ret = snprintf(searchfilter, sizeof (searchfilter),
 583                     _F_SETMEMBER, name);
 584                 if (ret >= sizeof (searchfilter) || ret < 0)
 585                         break;
 586 
 587                 ret = snprintf(userdata, sizeof (userdata), _F_SETMEMBER_SSD,
 588                     name);
 589                 if (ret >= sizeof (userdata) || ret < 0)
 590                         break;
 591 
 592                 /* searching for current netgroup name entry */
 593                 rc = __ns_ldap_list(_NETGROUP, searchfilter,
 594                     _merge_SSD_filter, netgrent_attrs, NULL, 0, &result,
 595                     &error, NULL, userdata);
 596 
 597                 if (error != NULL) {
 598                         status1 = switch_err(rc, error);
 599                         if (status1 == NSS_TRYAGAIN) {
 600                                 (void) __ns_ldap_freeError(&error);
 601                                 free_netgroup_table(&tab);
 602                                 return (status1);
 603                         }
 604                 }
 605 
 606                 (void) __ns_ldap_freeError(&error);
 607                 if (rc == NS_LDAP_SUCCESS) {
 608                         if (match_triple(ia, result) == 1) {
 609                                 /* We found a match */
 610                                 ia->status = NSS_NETGR_FOUND;
 611                                 status = NSS_SUCCESS;
 612 #ifdef DEBUG
 613                                 syslog(LOG_DEBUG, "nss_ldap: top_down_search: "
 614                                     "found match");
 615 #endif
 616                                 break;
 617                         }
 618 
 619                         /*
 620                          * No match found. Check for membernisnetgroup
 621                          * in result and if yes, start again with those.
 622                          */
 623                         rc = add_netgroup_member(result, &tab);
 624                         if (rc != 0)
 625                                 break;
 626                 } else if (rc != NS_LDAP_NOTFOUND) {
 627                         break;
 628                 }
 629                 (void) __ns_ldap_freeResult(&result);
 630         }
 631 
 632         (void) __ns_ldap_freeResult(&result);
 633         free_netgroup_table(&tab);
 634         return (status);
 635 }
 636 
 637 /*
 638  * __netgr_in checks only checks the netgroup specified in ngroup
 639  */
 640 static nss_status_t
 641 __netgr_in(void *a, char *netgrname)
 642 {
 643         struct nss_innetgr_args *ia = (struct nss_innetgr_args *)a;
 644         nss_status_t            status = NSS_NOTFOUND;
 645 
 646 #ifdef DEBUG
 647         (void) fprintf(stdout, "\n[getnetgrent.c: netgr_in]\n");
 648         (void) fprintf(stdout, "\tmachine: argc[%d]='%s' user: "
 649             "argc[%d]='%s',\n\tdomain:argc[%d]='%s' "
 650             "netgroup: argc[%d]='%s'\n",
 651             NSS_NETGR_MACHINE,
 652             PRINT_VAL(ia->arg[NSS_NETGR_MACHINE]),
 653             NSS_NETGR_USER,
 654             PRINT_VAL(ia->arg[NSS_NETGR_USER]),
 655             NSS_NETGR_DOMAIN,
 656             PRINT_VAL(ia->arg[NSS_NETGR_DOMAIN]),
 657             NSS_NETGR_N,
 658             PRINT_VAL(ia->arg[NSS_NETGR_N]));
 659         (void) fprintf(stdout, "\tgroups='%s'\n", netgrname);
 660 #endif  /* DEBUG */
 661 
 662         ia->status = NSS_NETGR_NO;
 663 
 664         if (netgrname == NULL)
 665                 return (status);
 666 
 667         return (top_down_search(ia, netgrname));
 668 }
 669 
 670 /*ARGSUSED0*/
 671 static nss_status_t
 672 netgr_in(ldap_backend_ptr be, void *a)
 673 {
 674         struct nss_innetgr_args *ia = (struct nss_innetgr_args *)a;
 675         int     i;
 676         nss_status_t    rc = (nss_status_t)NSS_NOTFOUND;
 677 
 678         ia->status = NSS_NETGR_NO;
 679         for (i = 0; i < ia->groups.argc; i++) {
 680                 rc = __netgr_in(a, ia->groups.argv[i]);
 681                 if (ia->status == NSS_NETGR_FOUND)
 682                         return (NSS_SUCCESS);
 683         }
 684         return (rc);
 685 }
 686 
 687 /*
 688  *
 689  */
 690 
 691 static nss_status_t
 692 getnetgr_ldap_setent(ldap_backend_ptr be, void *a)
 693 {
 694         const char      *netgroup = (const char *) a;
 695         getnetgrent_cookie_t    *cookie;
 696 
 697 #ifdef  DEBUG
 698         (void) fprintf(stdout, "\n[getnetgrent.c: getnetgr_ldap_setent]\n");
 699 #endif  /* DEBUG */
 700 
 701         cookie = (getnetgrent_cookie_t *)be->netgroup_cookie;
 702         if (cookie != NULL && cookie->netgroup != NULL) {
 703                 /* is this another set on the same netgroup */
 704                 if (strcmp(cookie->netgroup, netgroup) == 0)
 705                         return ((nss_status_t)NSS_SUCCESS);
 706         }
 707 
 708         return (NSS_NOTFOUND);
 709 }
 710 
 711 static void
 712 free_getnetgrent_cookie(getnetgrent_cookie_t **cookie)
 713 {
 714         getnetgrent_cookie_t *p = *cookie;
 715 
 716 #ifdef DEBUG
 717         (void) fprintf(stdout, "\n[getnetgrent.c: free_getnetgrent_cookie]\n");
 718 #endif  /* DEBUG */
 719 
 720         if (p == NULL)
 721                 return;
 722 
 723         (void) __ns_ldap_freeResult(&p->results);
 724         free_netgroup_table(&p->tab);
 725         free(p->netgroup);
 726         free(p);
 727         *cookie = NULL;
 728 }
 729 
 730 /*ARGSUSED1*/
 731 static nss_status_t
 732 getnetgr_ldap_endent(ldap_backend_ptr be, void *a)
 733 {
 734 
 735 #ifdef  DEBUG
 736         (void) fprintf(stdout, "\n[getnetgrent.c: getnetgr_ldap_endent]\n");
 737 #endif  /* DEBUG */
 738 
 739         free_getnetgrent_cookie((getnetgrent_cookie_t **)&be->netgroup_cookie);
 740 
 741         return ((nss_status_t)NSS_NOTFOUND);
 742 }
 743 
 744 
 745 /*ARGSUSED1*/
 746 static nss_status_t
 747 getnetgr_ldap_destr(ldap_backend_ptr be, void *a)
 748 {
 749 
 750 #ifdef  DEBUG
 751         (void) fprintf(stdout, "\n[getnetgrent.c: getnetgr_ldap_destr]\n");
 752 #endif  /* DEBUG */
 753 
 754         free_getnetgrent_cookie((getnetgrent_cookie_t **)&be->netgroup_cookie);
 755         free(be);
 756 
 757         return ((nss_status_t)NSS_NOTFOUND);
 758 }
 759 
 760 
 761 static nss_status_t
 762 getnetgr_ldap_getent(ldap_backend_ptr be, void *a)
 763 {
 764         struct nss_getnetgrent_args     *args;
 765         getnetgrent_cookie_t    *p;
 766         char                    searchfilter[SEARCHFILTERLEN];
 767         char                    userdata[SEARCHFILTERLEN];
 768         char                    name[SEARCHFILTERLEN];
 769         int                     rc;
 770         ns_ldap_result_t        *result = NULL;
 771         ns_ldap_error_t         *error = NULL;
 772         char                    **attrs;
 773         char                    *hostname, *username, *domain;
 774         char                    *buffer;
 775         nss_status_t            status = NSS_SUCCESS;
 776         netgroup_name_t         *ng;
 777         int                     ret;
 778 
 779 #ifdef  DEBUG
 780         (void) fprintf(stdout, "\n[getnetgrent.c: getnetgr_ldap_getent]\n");
 781 #endif  /* DEBUG */
 782 
 783         args = (struct nss_getnetgrent_args *)a;
 784 
 785         args->status = NSS_NETGR_NO;
 786 
 787         p = (getnetgrent_cookie_t *)be->netgroup_cookie;
 788         if (p == NULL)
 789                 return ((nss_status_t)NSS_SUCCESS);
 790 
 791         for (;;) {
 792                 /*
 793                  * Search through each netgroup consecutively: only search
 794                  * next netgroup when results from previous netgroup are
 795                  * processed.
 796                  * Needed for nested netgroup (memberNisNetgroup attributes).
 797                  */
 798                 if (p->results == NULL) {
 799                         if ((ng = get_next_netgroup(&p->tab)) != NULL) {
 800                                 if (_ldap_filter_name(name, ng->name,
 801                                     sizeof (name)) != 0)
 802                                         break;
 803 
 804                                 ret = snprintf(searchfilter,
 805                                     sizeof (searchfilter),
 806                                     _F_SETMEMBER, name);
 807                                 if (ret >= sizeof (searchfilter) || ret < 0)
 808                                         break;
 809 
 810 #ifdef DEBUG
 811                                 syslog(LOG_DEBUG, "nss_ldap: "
 812                                     "getnetgr_ldap_getent: "
 813                                     "netgroup name: %s", name);
 814 #endif
 815                                 ret = snprintf(userdata, sizeof (userdata),
 816                                     _F_SETMEMBER_SSD, name);
 817                                 if (ret >= sizeof (userdata) || ret < 0)
 818                                         break;
 819 
 820                                 result = NULL;
 821                                 rc = __ns_ldap_list(_NETGROUP, searchfilter,
 822                                     _merge_SSD_filter, netgrent_attrs, NULL,
 823                                     0, &result, &error, NULL, userdata);
 824                                 (void) __ns_ldap_freeError(&error);
 825 
 826                                 if (rc == NS_LDAP_SUCCESS && result != NULL) {
 827                                         p->results = result;
 828                                 } else {
 829 #ifdef DEBUG
 830                                         syslog(LOG_DEBUG, "nss_ldap: "
 831                                             "getnetgr_ldap_getent: "
 832                                             "__ns_ldap_list() returned %d "
 833                                             "(result: 0x%x)", rc, result);
 834 #endif
 835                                         /*
 836                                          * Will exit when no more netgroup
 837                                          * to search and no more p->results
 838                                          * to process.
 839                                          */
 840                                         (void) __ns_ldap_freeResult(&result);
 841                                 }
 842                         } else { /* no more netgroup to process */
 843                                 /*
 844                                  * If no more results to process, and since
 845                                  * there's no more netgroup to process either,
 846                                  * then it's time to break and exit the for
 847                                  * loop.
 848                                  */
 849 #ifdef DEBUG
 850                                 syslog(LOG_DEBUG, "nss_ldap: "
 851                                     "getnetgr_ldap_getent: no more netgroup "
 852                                     "to process, p->results: 0x%x",
 853                                     p->results);
 854 #endif
 855                                 if (p->results == NULL)
 856                                         break;
 857                         }
 858                 }
 859                 if (p->results == NULL)
 860                         continue;
 861 
 862                 if (p->entry == NULL)
 863                         p->entry = p->results->entry;
 864 
 865                 if (p->entry == NULL)
 866                         continue;
 867 
 868                 if (p->attrs == NULL) {
 869                         attrs = __ns_ldap_getAttr(p->entry, _N_TRIPLE);
 870                         if (attrs != NULL && *attrs != NULL)
 871                                 p->attrs = attrs;
 872                 }
 873 
 874                 if (p->attrs != NULL) {
 875                         attrs = p->attrs;
 876                         buffer = args->buffer;
 877 
 878                         if (strlcpy(buffer, *attrs, args->buflen) >=
 879                             args->buflen) {
 880                                 status = NSS_STR_PARSE_ERANGE;
 881                                 break;
 882                         }
 883 
 884                         rc = split_triple(buffer, &hostname, &username,
 885                             &domain);
 886                         attrs++;
 887                         if (attrs != NULL && *attrs != NULL)
 888                                 p->attrs = attrs;
 889                         else
 890                                 p->attrs = NULL;
 891                         if (rc == 0) {
 892                                 args->retp[NSS_NETGR_MACHINE] = hostname;
 893                                 args->retp[NSS_NETGR_USER] = username;
 894                                 args->retp[NSS_NETGR_DOMAIN] = domain;
 895                                 args->status = NSS_NETGR_FOUND;
 896 #ifdef DEBUG
 897                                 syslog(LOG_DEBUG, "nss_ldap: "
 898                                     "getnetgr_ldap_getent: found triple "
 899                                     "(%s, %s, %s), 0x%x to process",
 900                                     hostname ? hostname : "",
 901                                     username ? username : "",
 902                                     domain ? domain : "",
 903                                     p->attrs);
 904 #endif
 905                                 if (p->attrs != NULL)
 906                                         break;
 907                         }
 908                 }
 909 
 910                 if (p->attrs == NULL) {
 911                         rc = add_netgroup_member_entry(p->entry, &p->tab);
 912                         if (rc != 0) {
 913                                 args->status = NSS_NETGR_NO;
 914                                 break;
 915                         }
 916 
 917                         p->entry = p->entry->next;
 918                         if (p->entry == NULL)
 919                                 (void) __ns_ldap_freeResult(&p->results);
 920                         if (args->status == NSS_NETGR_FOUND)
 921                                 break;
 922                 }
 923         }
 924 
 925         return (status);
 926 }
 927 
 928 static ldap_backend_op_t getnetgroup_ops[] = {
 929         getnetgr_ldap_destr,
 930         getnetgr_ldap_endent,
 931         getnetgr_ldap_setent,
 932         getnetgr_ldap_getent,
 933 };
 934 
 935 /*
 936  *
 937  */
 938 
 939 static nss_status_t
 940 netgr_set(ldap_backend_ptr be, void *a)
 941 {
 942         struct nss_setnetgrent_args     *args =
 943             (struct nss_setnetgrent_args *)a;
 944         ldap_backend_ptr                get_be;
 945         getnetgrent_cookie_t            *p;
 946 
 947 #ifdef DEBUG
 948         (void) fprintf(stdout, "\n[getnetgrent.c: netgr_set]\n");
 949         (void) fprintf(stdout,
 950             "\targs->netgroup: %s\n", ISNULL(args->netgroup));
 951 #endif /* DEBUG */
 952 
 953         if (args->netgroup == NULL)
 954                 return ((nss_status_t)NSS_NOTFOUND);
 955 
 956         free_getnetgrent_cookie((getnetgrent_cookie_t **)&be->netgroup_cookie);
 957         p = (getnetgrent_cookie_t *)calloc(1, sizeof (getnetgrent_cookie_t));
 958         if (p == NULL)
 959                 return ((nss_status_t)NSS_NOTFOUND);
 960         p->netgroup = strdup(args->netgroup);
 961         if (p->netgroup == NULL) {
 962                 free(p);
 963                 return ((nss_status_t)NSS_NOTFOUND);
 964         }
 965         if (add_netgroup_name(args->netgroup, &p->tab) == -1) {
 966                 free_getnetgrent_cookie(&p);
 967                 return ((nss_status_t)NSS_NOTFOUND);
 968         }
 969 
 970         /* now allocate and return iteration backend structure */
 971         if ((get_be = (ldap_backend_ptr)malloc(sizeof (*get_be))) == NULL)
 972                 return (NSS_UNAVAIL);
 973         get_be->ops = getnetgroup_ops;
 974         get_be->nops = sizeof (getnetgroup_ops) / sizeof (getnetgroup_ops[0]);
 975         get_be->tablename = NULL;
 976         get_be->attrs = netgrent_attrs;
 977         get_be->result = NULL;
 978         get_be->ldapobj2str = NULL;
 979         get_be->setcalled = 1;
 980         get_be->filter = NULL;
 981         get_be->toglue = NULL;
 982         get_be->enumcookie = NULL;
 983         get_be->netgroup_cookie = p;
 984         args->iterator = (nss_backend_t *)get_be;
 985 
 986         (void) __ns_ldap_freeResult(&be->result);
 987 
 988         return (NSS_SUCCESS);
 989 }
 990 
 991 
 992 /*ARGSUSED1*/
 993 static nss_status_t
 994 netgr_ldap_destr(ldap_backend_ptr be, void *a)
 995 {
 996 
 997 #ifdef  DEBUG
 998         (void) fprintf(stdout, "\n[getnetgrent.c: netgr_ldap_destr]\n");
 999 #endif  /* DEBUG */
1000 
1001         (void) _clean_ldap_backend(be);
1002 
1003         return ((nss_status_t)NSS_NOTFOUND);
1004 }
1005 
1006 
1007 
1008 
1009 static ldap_backend_op_t netgroup_ops[] = {
1010         netgr_ldap_destr,
1011         0,
1012         0,
1013         0,
1014         netgr_in,               /*      innetgr()       */
1015         netgr_set               /*      setnetgrent()   */
1016 };
1017 
1018 
1019 /*
1020  * _nss_ldap_netgroup_constr is where life begins. This function calls the
1021  * generic ldap constructor function to define and build the abstract data
1022  * types required to support ldap operations.
1023  */
1024 
1025 /*ARGSUSED0*/
1026 nss_backend_t *
1027 _nss_ldap_netgroup_constr(const char *dummy1, const char *dummy2,
1028                         const char *dummy3)
1029 {
1030 
1031 #ifdef  DEBUG
1032         (void) fprintf(stdout,
1033             "\n[getnetgrent.c: _nss_ldap_netgroup_constr]\n");
1034 #endif  /* DEBUG */
1035 
1036         return ((nss_backend_t *)_nss_ldap_constr(netgroup_ops,
1037             sizeof (netgroup_ops)/sizeof (netgroup_ops[0]), _NETGROUP,
1038             netgrent_attrs, NULL));
1039 }