20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  *
  25  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  26  */
  27 
  28 #include <grp.h>
  29 #include "ldap_common.h"
  30 #include <string.h>
  31 
  32 /* String which may need to be removed from beginning of group password */
  33 #define _CRYPT          "{CRYPT}"
  34 #define _NO_PASSWD_VAL  ""
  35 
  36 /* Group attributes filters */
  37 #define _G_NAME         "cn"
  38 #define _G_GID          "gidnumber"
  39 #define _G_PASSWD       "userpassword"
  40 #define _G_MEM          "memberuid"
  41 
  42 #define _F_GETGRNAM     "(&(objectClass=posixGroup)(cn=%s))"
  43 #define _F_GETGRNAM_SSD "(&(%%s)(cn=%s))"
  44 #define _F_GETGRGID     "(&(objectClass=posixGroup)(gidNumber=%u))"
  45 #define _F_GETGRGID_SSD "(&(%%s)(gidNumber=%u))"
  46 /*
  47  * Group membership can be defined by either username or DN, so when searching
  48  * for groups by member we need to consider both. The first parameter in the
  49  * filter is replaced by username, the second by DN.
  50  */
  51 #define _F_GETGRMEM \
  52         "(&(objectClass=posixGroup)(|(memberUid=%s)(memberUid=%s)))"
  53 #define _F_GETGRMEM_SSD "(&(%%s)(|(memberUid=%s)(memberUid=%s)))"
  54 
  55 /*
  56  * Copied from getpwnam.c, needed to look up user DN.
  57  * Would it be better to move to ldap_common.h rather than duplicate?
  58  */
  59 #define _F_GETPWNAM     "(&(objectClass=posixAccount)(uid=%s))"
  60 #define _F_GETPWNAM_SSD "(&(%%s)(uid=%s))"
  61 
  62 static const char *gr_attrs[] = {
  63         _G_NAME,
  64         _G_GID,
  65         _G_PASSWD,
  66         _G_MEM,
  67         (char *)NULL
  68 };
  69 
  70 
  71 /*
  72  * _nss_ldap_group2str is the data marshaling method for the group getXbyY
  73  * (e.g., getgrnam(), getgrgid(), getgrent()) backend processes. This method
  74  * is called after a successful ldap search has been performed. This method
  75  * will parse the ldap search values into the file format.
  76  * e.g.
  77  *
  78  * adm::4:root,adm,daemon
  79  *
  80  */
  81 
  82 static int
  83 _nss_ldap_group2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
  84 {
  85         int             i;
  86         int             nss_result;
  87         int             buflen = 0, len;
  88         int             firstime = 1;
  89         char            *buffer = NULL;
  90         ns_ldap_result_t        *result = be->result;
  91         char            **gname, **passwd, **gid, *password, *end;
  92         char            gid_nobody[NOBODY_STR_LEN];
  93         char            *gid_nobody_v[1];
  94         char            *member_str, *strtok_state;
  95         ns_ldap_attr_t  *members;
  96 
  97         (void) snprintf(gid_nobody, sizeof (gid_nobody), "%u", GID_NOBODY);
  98         gid_nobody_v[0] = gid_nobody;
  99 
 100         if (result == NULL)
 101                 return (NSS_STR_PARSE_PARSE);
 102         buflen = argp->buf.buflen;
 103 
 104         if (argp->buf.result != NULL) {
 105                 if ((be->buffer = calloc(1, buflen)) == NULL) {
 106                         nss_result = NSS_STR_PARSE_PARSE;
 107                         goto result_grp2str;
 108                 }
 109                 buffer = be->buffer;
 110         } else
 111                 buffer = argp->buf.buffer;
 112 
 113         nss_result = NSS_STR_PARSE_SUCCESS;
 114         (void) memset(buffer, 0, buflen);
 
 129                  * then the password may be plain text.  And thus
 130                  * perhaps crypt(3c) should be used to encrypt it.
 131                  * Currently the password is copied verbatim.
 132                  */
 133                 if (strncasecmp(passwd[0], _CRYPT, strlen(_CRYPT)) == 0)
 134                         password = passwd[0] + strlen(_CRYPT);
 135                 else
 136                         password = passwd[0];
 137         }
 138         gid = __ns_ldap_getAttr(result->entry, _G_GID);
 139         if (gid == NULL || gid[0] == NULL || (strlen(gid[0]) < 1)) {
 140                 nss_result = NSS_STR_PARSE_PARSE;
 141                 goto result_grp2str;
 142         }
 143         /* Validate GID */
 144         if (strtoul(gid[0], &end, 10) > MAXUID)
 145                 gid = gid_nobody_v;
 146         len = snprintf(buffer, buflen, "%s:%s:%s:", gname[0], password, gid[0]);
 147         TEST_AND_ADJUST(len, buffer, buflen, result_grp2str);
 148 
 149         members = __ns_ldap_getAttrStruct(result->entry, _G_MEM);
 150         if (members == NULL || members->attrvalue == NULL) {
 151                 /* no member is fine, skip processing the member list */
 152                 goto nomember;
 153         }
 154 
 155         for (i = 0; i < members->value_count; i++) {
 156                 if (members->attrvalue[i] == NULL) {
 157                         nss_result = NSS_STR_PARSE_PARSE;
 158                         goto result_grp2str;
 159                 }
 160                 /*
 161                  * If we find an '=' in the member attribute value, treat it as
 162                  * a DN, otherwise as a username.
 163                  */
 164                 if (member_str = strchr(members->attrvalue[i], '=')) {
 165                         member_str++; /* skip over the '=' */
 166                         /* Fail if we can't pull a username out of the RDN */
 167                         if (! (member_str = strtok_r(member_str,
 168                             ",", &strtok_state))) {
 169                                 nss_result = NSS_STR_PARSE_PARSE;
 170                                 goto result_grp2str;
 171                         }
 172                 } else {
 173                         member_str = members->attrvalue[i];
 174                 }
 175                 if (*member_str != '\0') {
 176                         if (firstime) {
 177                                 len = snprintf(buffer, buflen, "%s",
 178                                     member_str);
 179                                 TEST_AND_ADJUST(len, buffer, buflen,
 180                                     result_grp2str);
 181                                 firstime = 0;
 182                         } else {
 183                                 len = snprintf(buffer, buflen, ",%s",
 184                                     member_str);
 185                                 TEST_AND_ADJUST(len, buffer, buflen,
 186                                     result_grp2str);
 187                         }
 188                 }
 189         }
 190 nomember:
 191         /* The front end marshaller doesn't need the trailing nulls */
 192         if (argp->buf.result != NULL)
 193                 be->buflen = strlen(be->buffer);
 194 result_grp2str:
 195         (void) __ns_ldap_freeResult(&be->result);
 196         return (nss_result);
 197 }
 198 
 199 /*
 200  * getbynam gets a group entry by name. This function constructs an ldap
 201  * search filter using the name invocation parameter and the getgrnam search
 202  * filter defined. Once the filter is constructed, we searche for a matching
 203  * entry and marshal the data results into struct group for the frontend
 204  * process. The function _nss_ldap_group2ent performs the data marshaling.
 205  */
 206 
 207 static nss_status_t
 208 getbynam(ldap_backend_ptr be, void *a)
 209 {
 210         nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
 211         char            searchfilter[SEARCHFILTERLEN];
 212         char            userdata[SEARCHFILTERLEN];
 213         char            groupname[SEARCHFILTERLEN];
 214         int             ret;
 215 
 
 250         if (argp->key.uid > MAXUID)
 251                 return ((nss_status_t)NSS_NOTFOUND);
 252 
 253         ret = snprintf(searchfilter, sizeof (searchfilter),
 254             _F_GETGRGID, argp->key.uid);
 255         if (ret >= sizeof (searchfilter) || ret < 0)
 256                 return ((nss_status_t)NSS_NOTFOUND);
 257 
 258         ret = snprintf(userdata, sizeof (userdata),
 259             _F_GETGRGID_SSD, argp->key.uid);
 260         if (ret >= sizeof (userdata) || ret < 0)
 261                 return ((nss_status_t)NSS_NOTFOUND);
 262 
 263         return ((nss_status_t)_nss_ldap_lookup(be, argp,
 264             _GROUP, searchfilter, NULL, _merge_SSD_filter, userdata));
 265 
 266 }
 267 
 268 
 269 /*
 270  * getbymember returns all groups a user is defined in. This function
 271  * uses different architectural procedures than the other group backend
 272  * system calls because it's a private interface. This function constructs
 273  * an ldap search filter using the name invocation parameter. Once the
 274  * filter is constructed, we search for all matching groups counting
 275  * and storing each group name, gid, etc. Data marshaling is used for
 276  * group processing. The function _nss_ldap_group2ent() performs the
 277  * data marshaling.
 278  *
 279  * (const char *)argp->username;     (size_t)strlen(argp->username);
 280  * (gid_t)argp->gid_array;           (int)argp->maxgids;
 281  * (int)argp->numgids;
 282  */
 283 
 284 static nss_status_t
 285 getbymember(ldap_backend_ptr be, void *a)
 286 {
 287         int                     i, j, k;
 288         int                     gcnt = (int)0;
 289         char                    **groupvalue, **membervalue, *member_str;
 290         char                    *strtok_state;
 291         nss_status_t            lstat;
 292         struct nss_groupsbymem  *argp = (struct nss_groupsbymem *)a;
 293         char                    searchfilter[SEARCHFILTERLEN];
 294         char                    userdata[SEARCHFILTERLEN];
 295         char                    name[SEARCHFILTERLEN];
 296         ns_ldap_result_t        *result;
 297         ns_ldap_entry_t         *curEntry;
 298         char                    *username, **dn_attr, *dn;
 299         gid_t                   gid;
 300         int                     ret;
 301 
 302         if (strcmp(argp->username, "") == 0 ||
 303             strcmp(argp->username, "root") == 0)
 304                 return ((nss_status_t)NSS_NOTFOUND);
 305 
 306         if (_ldap_filter_name(name, argp->username, sizeof (name)) != 0)
 307                 return ((nss_status_t)NSS_NOTFOUND);
 308 
 309         ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETPWNAM, name);
 310         if (ret >= sizeof (searchfilter) || ret < 0)
 311                 return ((nss_status_t)NSS_NOTFOUND);
 312 
 313         ret = snprintf(userdata, sizeof (userdata), _F_GETPWNAM_SSD, name);
 314         if (ret >= sizeof (userdata) || ret < 0)
 315                 return ((nss_status_t)NSS_NOTFOUND);
 316 
 317         /*
 318          * Look up the user DN in ldap. If it's not found, search solely by
 319          * username.
 320          */
 321         lstat = (nss_status_t)_nss_ldap_nocb_lookup(be, NULL,
 322             _PASSWD, searchfilter, NULL, _merge_SSD_filter, userdata);
 323         if (lstat != (nss_status_t)NS_LDAP_SUCCESS)
 324                 return ((nss_status_t)lstat);
 325 
 326         if (be->result == NULL ||
 327             !(dn_attr = __ns_ldap_getAttr(be->result->entry, "dn")))
 328                 dn = name;
 329         else
 330                 dn = dn_attr[0];
 331 
 332         ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETGRMEM, name,
 333             dn);
 334         if (ret >= sizeof (searchfilter) || ret < 0)
 335                 return ((nss_status_t)NSS_NOTFOUND);
 336 
 337         ret = snprintf(userdata, sizeof (userdata), _F_GETGRMEM_SSD, name,
 338             dn);
 339         if (ret >= sizeof (userdata) || ret < 0)
 340                 return ((nss_status_t)NSS_NOTFOUND);
 341 
 342         /*
 343          * Free up resources from user DN search before performing group
 344          * search.
 345          */
 346         (void) __ns_ldap_freeResult((ns_ldap_result_t **)&be->result);
 347 
 348         gcnt = (int)argp->numgids;
 349         lstat = (nss_status_t)_nss_ldap_nocb_lookup(be, NULL,
 350             _GROUP, searchfilter, NULL, _merge_SSD_filter, userdata);
 351         if (lstat != (nss_status_t)NS_LDAP_SUCCESS)
 352                 return ((nss_status_t)lstat);
 353         if (be->result == NULL)
 354                 return (NSS_NOTFOUND);
 355         username = (char *)argp->username;
 356         result = (ns_ldap_result_t *)be->result;
 357         curEntry = (ns_ldap_entry_t *)result->entry;
 358         for (i = 0; i < result->entries_count && curEntry != NULL; i++) {
 359                 membervalue = __ns_ldap_getAttr(curEntry, "memberUid");
 360                 if (membervalue == NULL) {
 361                         curEntry = curEntry->next;
 362                         continue;
 363                 }
 364                 for (j = 0; membervalue[j]; j++) {
 365                         /*
 366                          * If we find an '=' in the member attribute
 367                          * value, treat it as a DN, otherwise as a
 368                          * username.
 369                          */
 370                         if (member_str = strchr(membervalue[j], '=')) {
 371                                 member_str++; /* skip over the '=' */
 372                                 member_str = strtok_r(member_str, ",",
 373                                     &strtok_state);
 374                         } else {
 375                                 member_str = membervalue[j];
 376                         }
 377                         if (member_str != NULL &&
 378                             strcmp(member_str, username) == 0) {
 379                                 groupvalue = __ns_ldap_getAttr(curEntry,
 380                                     "gidnumber");
 381                                 if (groupvalue == NULL ||
 382                                     groupvalue[0] == NULL) {
 383                                         /* Drop this group from the list */
 384                                         break;
 385                                 }
 386                                 errno = 0;
 387                                 gid = (gid_t)strtol(groupvalue[0],
 388                                     (char **)NULL, 10);
 389 
 390                                 if (errno == 0 &&
 391                                     argp->numgids < argp->maxgids) {
 392                                         for (k = 0; k < argp->numgids; k++) {
 393                                                 if (argp->gid_array[k] == gid)
 394                                                         /* already exists */
 395                                                         break;
 396                                         }
 397                                         if (k == argp->numgids)
 398                                                 argp->gid_array[argp->numgids++]
 399                                                     = gid;
 400                                 }
 401                                 break;
 402                         }
 403                 }
 404                 curEntry = curEntry->next;
 405         }
 406 
 407         (void) __ns_ldap_freeResult((ns_ldap_result_t **)&be->result);
 408         if (gcnt == argp->numgids)
 409                 return ((nss_status_t)NSS_NOTFOUND);
 410 
 411         /*
 412          * Return NSS_SUCCESS only if array is full.
 413          * Explained in <nss_dbdefs.h>.
 414          */
 415         return ((nss_status_t)((argp->numgids == argp->maxgids)
 416             ? NSS_SUCCESS
 417             : NSS_NOTFOUND));
 418 }
 419 
 420 static ldap_backend_op_t gr_ops[] = {
 421         _nss_ldap_destr,
 422         _nss_ldap_endent,
 423         _nss_ldap_setent,
 | 
 
 
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  *
  25  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  26  */
  27 
  28 #include <grp.h>
  29 #include "ldap_common.h"
  30 #include <string.h>
  31 
  32 /* String which may need to be removed from beginning of group password */
  33 #define _CRYPT          "{CRYPT}"
  34 #define _NO_PASSWD_VAL  ""
  35 
  36 /* Group attributes filters */
  37 #define _G_NAME         "cn"
  38 #define _G_GID          "gidnumber"
  39 #define _G_PASSWD       "userpassword"
  40 #define _G_MEMUID       "memberuid"
  41 #define _G_MEM_DN       "member"        /* DN */
  42 
  43 #define _F_GETGRNAM     "(&(objectClass=posixGroup)(cn=%s))"
  44 #define _F_GETGRNAM_SSD "(&(%%s)(cn=%s))"
  45 #define _F_GETGRGID     "(&(objectClass=posixGroup)(gidNumber=%u))"
  46 #define _F_GETGRGID_SSD "(&(%%s)(gidNumber=%u))"
  47 
  48 /*
  49  * When searching for groups in which a specified user is a member,
  50  * there are a few different membership schema that might be in use.
  51  * We'll use a filter that should work with an of the common ones:
  52  * "memberUid=NAME", or "member=DN" (try uniquemember too?)
  53  * The first parameter in the filter string is replaced by username,
  54  * and the remaining ones by the full DN.
  55  */
  56 #define _F_GETGRMEM "(&(objectClass=posixGroup)" \
  57         "(|(memberUid=%s)(member=%s)))"
  58 #define _F_GETGRMEM_SSD "(&(%%s)" \
  59         "(|(memberUid=%s)(member=%s)))"
  60 
  61 static const char *gr_attrs[] = {
  62         _G_NAME,
  63         _G_GID,
  64         _G_PASSWD,
  65         _G_MEMUID,
  66         _G_MEM_DN,
  67         (char *)NULL
  68 };
  69 
  70 static int
  71 getmembers_UID(char **bufpp, int *lenp, ns_ldap_attr_t *members);
  72 static int
  73 getmembers_DN(char **bufpp, int *lenp, ns_ldap_attr_t *members);
  74 
  75 
  76 /*
  77  * _nss_ldap_group2str is the data marshaling method for the group getXbyY
  78  * (e.g., getgrnam(), getgrgid(), getgrent()) backend processes. This method
  79  * is called after a successful ldap search has been performed. This method
  80  * will parse the ldap search values into the file format.
  81  * e.g.
  82  *
  83  * adm::4:root,adm,daemon
  84  *
  85  */
  86 
  87 static int
  88 _nss_ldap_group2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
  89 {
  90         int             i;
  91         int             nss_result;
  92         int             buflen = 0, len;
  93         char            *buffer = NULL;
  94         ns_ldap_result_t        *result = be->result;
  95         char            **gname, **passwd, **gid, *password, *end;
  96         char            gid_nobody[NOBODY_STR_LEN];
  97         char            *gid_nobody_v[1];
  98         ns_ldap_attr_t  *members;
  99 
 100         (void) snprintf(gid_nobody, sizeof (gid_nobody), "%u", GID_NOBODY);
 101         gid_nobody_v[0] = gid_nobody;
 102 
 103         if (result == NULL)
 104                 return (NSS_STR_PARSE_PARSE);
 105         buflen = argp->buf.buflen;
 106 
 107         if (argp->buf.result != NULL) {
 108                 if ((be->buffer = calloc(1, buflen)) == NULL) {
 109                         nss_result = NSS_STR_PARSE_PARSE;
 110                         goto result_grp2str;
 111                 }
 112                 buffer = be->buffer;
 113         } else
 114                 buffer = argp->buf.buffer;
 115 
 116         nss_result = NSS_STR_PARSE_SUCCESS;
 117         (void) memset(buffer, 0, buflen);
 
 132                  * then the password may be plain text.  And thus
 133                  * perhaps crypt(3c) should be used to encrypt it.
 134                  * Currently the password is copied verbatim.
 135                  */
 136                 if (strncasecmp(passwd[0], _CRYPT, strlen(_CRYPT)) == 0)
 137                         password = passwd[0] + strlen(_CRYPT);
 138                 else
 139                         password = passwd[0];
 140         }
 141         gid = __ns_ldap_getAttr(result->entry, _G_GID);
 142         if (gid == NULL || gid[0] == NULL || (strlen(gid[0]) < 1)) {
 143                 nss_result = NSS_STR_PARSE_PARSE;
 144                 goto result_grp2str;
 145         }
 146         /* Validate GID */
 147         if (strtoul(gid[0], &end, 10) > MAXUID)
 148                 gid = gid_nobody_v;
 149         len = snprintf(buffer, buflen, "%s:%s:%s:", gname[0], password, gid[0]);
 150         TEST_AND_ADJUST(len, buffer, buflen, result_grp2str);
 151 
 152         members = __ns_ldap_getAttrStruct(result->entry, _G_MEMUID);
 153         if (members != NULL && members->attrvalue != NULL) {
 154                 nss_result = getmembers_UID(&buffer, &buflen, members);
 155                 if (nss_result != 0)
 156                         goto result_grp2str;
 157         }
 158 
 159         members = __ns_ldap_getAttrStruct(result->entry, _G_MEM_DN);
 160         if (members != NULL && members->attrvalue != NULL) {
 161                 nss_result = getmembers_DN(&buffer, &buflen, members);
 162                 if (nss_result != 0)
 163                         goto result_grp2str;
 164         }
 165 
 166         /* The front end marshaller doesn't need the trailing nulls */
 167         if (argp->buf.result != NULL)
 168                 be->buflen = strlen(be->buffer);
 169 result_grp2str:
 170         (void) __ns_ldap_freeResult(&be->result);
 171         return (nss_result);
 172 }
 173 
 174 /*
 175  * Process the list values from the "memberUid" attribute of the
 176  * current group.  Note that this list is often empty, and we
 177  * get the real list of members via getmember_DN (see below).
 178  */
 179 static int
 180 getmembers_UID(char **bufpp, int *lenp, ns_ldap_attr_t *members)
 181 {
 182         char    *member_str, *strtok_state;
 183         char    *buffer;
 184         int     buflen;
 185         int     i, len;
 186         int     nss_result = 0;
 187         int     firsttime;
 188 
 189         buffer = *bufpp;
 190         buflen = *lenp;
 191         firsttime = (buffer[-1] == ':');
 192 
 193         for (i = 0; i < members->value_count; i++) {
 194                 member_str = members->attrvalue[i];
 195                 if (member_str == NULL)
 196                         goto out;
 197 
 198 #ifdef DEBUG
 199                 (void) fprintf(stdout, "getmembers_UID: uid=<%s>\n",
 200                     member_str);
 201 #endif
 202                 /*
 203                  * If not a valid Unix user name, or
 204                  * not valid in ldap, just skip.
 205                  */
 206                 if (member_str[0] == '\0' ||
 207                     strpbrk(member_str, " ,:=") != NULL)
 208                         continue;
 209 
 210                 if (firsttime)
 211                         len = snprintf(buffer, buflen, "%s", member_str);
 212                 else
 213                         len = snprintf(buffer, buflen, ",%s", member_str);
 214                 TEST_AND_ADJUST(len, buffer, buflen, out);
 215         }
 216 
 217 out:
 218         *bufpp = buffer;
 219         *lenp = buflen;
 220         return (nss_result);
 221 }
 222 
 223 /*
 224  * Process the list values from the "member" attribute of the
 225  * current group.  Note that this list is ONLY one that can be
 226  * assumed to be non-empty.  The problem here is that this list
 227  * contains the list of members as "distinguished names" (DN),
 228  * and we want the Unix names (known here as "uid").  We must
 229  * lookup the "uid" for each DN in the member list.  Example:
 230  * CN=Doe\, John,OU=Users,DC=contoso,DC=com => john.doe
 231  */
 232 static int
 233 getmembers_DN(char **bufpp, int *lenp, ns_ldap_attr_t *members)
 234 {
 235         ns_ldap_error_t *error = NULL;
 236         char    *member_dn, *member_uid;
 237         char    *buffer;
 238         int     buflen;
 239         int     i, len;
 240         int     nss_result = 0;
 241         int     firsttime;
 242 
 243         buffer = *bufpp;
 244         buflen = *lenp;
 245         firsttime = (buffer[-1] == ':');
 246 
 247         for (i = 0; i < members->value_count; i++) {
 248                 member_dn = members->attrvalue[i];
 249                 if (member_dn == NULL)
 250                         goto out;
 251 
 252                 /*
 253                  * The attribute name was "member", so these should be
 254                  * full distinguisned names (DNs).  We need to loookup
 255                  * the Unix UID (name) for each.
 256                  */
 257 #ifdef DEBUG
 258                 (void) fprintf(stdout, "getmembers_DN: dn=%s\n",
 259                     member_dn);
 260 #endif
 261                 if (member_dn[0] == '\0')
 262                         continue;
 263 
 264                 nss_result = __ns_ldap_dn2uid(member_dn,
 265                     &member_uid, NULL, &error);
 266                 if (nss_result != NS_LDAP_SUCCESS) {
 267                         (void) __ns_ldap_freeError(&error);
 268                         error = NULL;
 269                         continue;
 270                 }
 271 #ifdef DEBUG
 272                 (void) fprintf(stdout, "getmembers_DN: uid=<%s>\n",
 273                     member_uid);
 274 #endif
 275                 /* Skip invalid names. */
 276                 if (member_uid[0] == '\0' ||
 277                     strpbrk(member_uid, " ,:=") != NULL) {
 278                         free(member_uid);
 279                         continue;
 280                 }
 281 
 282                 if (firsttime)
 283                         len = snprintf(buffer, buflen, "%s", member_uid);
 284                 else
 285                         len = snprintf(buffer, buflen, ",%s", member_uid);
 286                 free(member_uid);
 287                 TEST_AND_ADJUST(len, buffer, buflen, out);
 288         }
 289 
 290 out:
 291         *bufpp = buffer;
 292         *lenp = buflen;
 293         return (nss_result);
 294 }
 295 
 296 /*
 297  * getbynam gets a group entry by name. This function constructs an ldap
 298  * search filter using the name invocation parameter and the getgrnam search
 299  * filter defined. Once the filter is constructed, we searche for a matching
 300  * entry and marshal the data results into struct group for the frontend
 301  * process. The function _nss_ldap_group2ent performs the data marshaling.
 302  */
 303 
 304 static nss_status_t
 305 getbynam(ldap_backend_ptr be, void *a)
 306 {
 307         nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
 308         char            searchfilter[SEARCHFILTERLEN];
 309         char            userdata[SEARCHFILTERLEN];
 310         char            groupname[SEARCHFILTERLEN];
 311         int             ret;
 312 
 
 347         if (argp->key.uid > MAXUID)
 348                 return ((nss_status_t)NSS_NOTFOUND);
 349 
 350         ret = snprintf(searchfilter, sizeof (searchfilter),
 351             _F_GETGRGID, argp->key.uid);
 352         if (ret >= sizeof (searchfilter) || ret < 0)
 353                 return ((nss_status_t)NSS_NOTFOUND);
 354 
 355         ret = snprintf(userdata, sizeof (userdata),
 356             _F_GETGRGID_SSD, argp->key.uid);
 357         if (ret >= sizeof (userdata) || ret < 0)
 358                 return ((nss_status_t)NSS_NOTFOUND);
 359 
 360         return ((nss_status_t)_nss_ldap_lookup(be, argp,
 361             _GROUP, searchfilter, NULL, _merge_SSD_filter, userdata));
 362 
 363 }
 364 
 365 
 366 /*
 367  * Use a custom attributes list for getbymember, because the LDAP
 368  * query for this requests a list of groups, and the result can be
 369  * very large if it includes the list of members with each group.
 370  * We don't need or want the list of members in this case.
 371  */
 372 static const char *grbymem_attrs[] = {
 373         _G_NAME,        /* cn */
 374         _G_GID,         /* gidnumber */
 375         (char *)NULL
 376 };
 377 
 378 /*
 379  * getbymember returns all groups a user is defined in. This function
 380  * uses different architectural procedures than the other group backend
 381  * system calls because it's a private interface. This function constructs
 382  * an ldap search filter using the name invocation parameter. Once the
 383  * filter is constructed, we search for all matching groups counting
 384  * and storing each group name, gid, etc. Data marshaling is used for
 385  * group processing. The function _nss_ldap_group2ent() performs the
 386  * data marshaling.
 387  *
 388  * (const char *)argp->username;     (size_t)strlen(argp->username);
 389  * (gid_t)argp->gid_array;           (int)argp->maxgids;
 390  * (int)argp->numgids;
 391  */
 392 
 393 static nss_status_t
 394 getbymember(ldap_backend_ptr be, void *a)
 395 {
 396         ns_ldap_error_t         *error = NULL;
 397         int                     i, j, k;
 398         int                     gcnt = (int)0;
 399         char                    **groupvalue;
 400         nss_status_t            lstat;
 401         struct nss_groupsbymem  *argp = (struct nss_groupsbymem *)a;
 402         char                    searchfilter[SEARCHFILTERLEN];
 403         char                    userdata[SEARCHFILTERLEN];
 404         char                    name[SEARCHFILTERLEN];
 405         char                    escdn[SEARCHFILTERLEN];
 406         ns_ldap_result_t        *result;
 407         ns_ldap_entry_t         *curEntry;
 408         char                    *dn;
 409         gid_t                   gid;
 410         int                     ret1, ret2;
 411 
 412         if (strcmp(argp->username, "") == 0 ||
 413             strcmp(argp->username, "root") == 0)
 414                 return ((nss_status_t)NSS_NOTFOUND);
 415 
 416         if (_ldap_filter_name(name, argp->username, sizeof (name)) != 0)
 417                 return ((nss_status_t)NSS_NOTFOUND);
 418 
 419         /*
 420          * Look up the user DN in ldap. If it's not found, search solely by
 421          * username.
 422          */
 423         lstat = __ns_ldap_uid2dn(name, &dn, NULL, &error);
 424         if (lstat != (nss_status_t)NS_LDAP_SUCCESS) {
 425                 /* Can't get DN.  Use bare name */
 426                 (void) __ns_ldap_freeError(&error);
 427                 dn = name;
 428         }
 429         /* Note: must free dn if != name */
 430 
 431         /*
 432          * Compose filter patterns
 433          */
 434         ret1 = snprintf(searchfilter, sizeof (searchfilter),
 435             _F_GETGRMEM, name, dn);
 436         ret2 = snprintf(userdata, sizeof (userdata),
 437             _F_GETGRMEM_SSD, name, dn);
 438         if (dn != name)
 439                 free(dn);
 440         if (ret1 >= sizeof (searchfilter) || ret1 < 0)
 441                 return ((nss_status_t)NSS_NOTFOUND);
 442         if (ret2 >= sizeof (userdata) || ret2 < 0)
 443                 return ((nss_status_t)NSS_NOTFOUND);
 444 
 445         /*
 446          * Query for groups matching the filter.
 447          */
 448         lstat = (nss_status_t)_nss_ldap_nocb_lookup(be, NULL,
 449             _GROUP, searchfilter, grbymem_attrs,
 450             _merge_SSD_filter, userdata);
 451         if (lstat != (nss_status_t)NS_LDAP_SUCCESS)
 452                 return ((nss_status_t)lstat);
 453         if (be->result == NULL)
 454                 return (NSS_NOTFOUND);
 455 
 456         /*
 457          * Walk the query result, collecting GIDs.
 458          */
 459         result = (ns_ldap_result_t *)be->result;
 460         curEntry = (ns_ldap_entry_t *)result->entry;
 461         gcnt = (int)argp->numgids;
 462         for (i = 0; i < result->entries_count; i++) {
 463 
 464                 /*
 465                  * Does this group have a gidNumber attr?
 466                  */
 467                 groupvalue = __ns_ldap_getAttr(curEntry, _G_GID);
 468                 if (groupvalue == NULL || groupvalue[0] == NULL) {
 469                         /* Drop this group from the list */
 470                         goto next_group;
 471                 }
 472 
 473                 /*
 474                  * Convert it to a numeric GID
 475                  */
 476                 errno = 0;
 477                 gid = (gid_t)strtol(groupvalue[0], (char **)NULL, 10);
 478                 if (errno != 0)
 479                         goto next_group;
 480 
 481                 /*
 482                  * If we don't already have this GID, add it.
 483                  */
 484                 if (argp->numgids < argp->maxgids) {
 485                         for (k = 0; k < argp->numgids; k++) {
 486                                 if (argp->gid_array[k] == gid) {
 487                                         /* already have it */
 488                                         goto next_group;
 489                                 }
 490                         }
 491                         argp->gid_array[argp->numgids++] = gid;
 492                 }
 493 
 494         next_group:
 495                 curEntry = curEntry->next;
 496         }
 497 
 498         (void) __ns_ldap_freeResult((ns_ldap_result_t **)&be->result);
 499         if (gcnt == argp->numgids)
 500                 return ((nss_status_t)NSS_NOTFOUND);
 501 
 502         /*
 503          * Return NSS_SUCCESS only if array is full.
 504          * Explained in <nss_dbdefs.h>.
 505          */
 506         return ((nss_status_t)((argp->numgids == argp->maxgids)
 507             ? NSS_SUCCESS
 508             : NSS_NOTFOUND));
 509 }
 510 
 511 static ldap_backend_op_t gr_ops[] = {
 512         _nss_ldap_destr,
 513         _nss_ldap_endent,
 514         _nss_ldap_setent,
 |