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