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