"Fossies" - the Fresh Open Source Software Archive 
Member "nss_ldap-265/ldap-grp.c" (6 Nov 2009, 30682 Bytes) of package /linux/privat/old/nss_ldap-265.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /* Copyright (C) 1997-2006 Luke Howard.
2 This file is part of the nss_ldap library.
3 Contributed by Luke Howard, <lukeh@padl.com>, 1997.
4
5 The nss_ldap library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The nss_ldap library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the nss_ldap library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21 static char rcsId[] =
22 "$Id: ldap-grp.c,v 2.110 2009/11/06 10:15:26 lukeh Exp $";
23
24 #include "config.h"
25
26 #ifdef HAVE_PORT_BEFORE_H
27 #include <port_before.h>
28 #endif
29
30 #if defined(HAVE_THREAD_H) && !defined(_AIX)
31 #include <thread.h>
32 #elif defined(HAVE_PTHREAD_H)
33 #include <pthread.h>
34 #endif
35
36 #include <assert.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <stdio.h>
40 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <grp.h>
43
44 #ifdef HAVE_LBER_H
45 #include <lber.h>
46 #endif
47 #ifdef HAVE_LDAP_H
48 #include <ldap.h>
49 #endif
50
51 #ifndef HAVE_SNPRINTF
52 #include "snprintf.h"
53 #endif
54
55 #include "ldap-nss.h"
56 #include "ldap-grp.h"
57 #include "util.h"
58
59 #ifdef HAVE_PORT_AFTER_H
60 #include <port_after.h>
61 #endif
62
63 #ifdef HAVE_NSS_H
64 static ent_context_t *gr_context = NULL;
65 #endif
66
67 #ifdef HAVE_USERSEC_H
68 typedef struct ldap_initgroups_args
69 {
70 char *grplist;
71 size_t listlen;
72 int depth;
73 struct name_list *known_groups;
74 int backlink;
75 }
76 ldap_initgroups_args_t;
77 #else
78 # ifdef HAVE_NSSWITCH_H
79 typedef struct ldap_initgroups_args
80 {
81 struct nss_groupsbymem *gbm;
82 int depth;
83 struct name_list *known_groups;
84 int backlink;
85 }
86 ldap_initgroups_args_t;
87 # else
88 typedef struct ldap_initgroups_args
89 {
90 gid_t group;
91 long int *start;
92 long int *size;
93 gid_t **groups;
94 long int limit;
95 int depth;
96 struct name_list *known_groups;
97 int backlink;
98 }
99 ldap_initgroups_args_t;
100 # endif
101 #endif /* HAVE_USERSEC_H */
102
103 static NSS_STATUS
104 ng_chase (const char *dn, ldap_initgroups_args_t * lia);
105
106 static NSS_STATUS
107 ng_chase_backlink (const char ** membersOf, ldap_initgroups_args_t * lia);
108
109 /*
110 * Range retrieval logic was reimplemented from example in
111 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/searching_using_range_retrieval.asp
112 */
113
114 static NSS_STATUS
115 do_parse_range (const char *attributeType,
116 const char *attributeDescription, int *start, int *end)
117 {
118 NSS_STATUS stat = NSS_NOTFOUND;
119 char *attribute;
120 size_t attributeTypeLength;
121 size_t attributeDescriptionLength;
122 char *p;
123 #ifdef HAVE_STRTOK_R
124 char *st = NULL;
125 #endif
126
127 *start = 0;
128 *end = -1;
129
130 if (strcasecmp (attributeType, attributeDescription) == 0)
131 {
132 return NSS_SUCCESS;
133 }
134
135 attributeDescriptionLength = strlen (attributeDescription);
136 attributeTypeLength = strlen (attributeType);
137
138 if (attributeDescriptionLength < attributeTypeLength)
139 {
140 /* could not be a subtype */
141 return NSS_NOTFOUND;
142 }
143
144 /* XXX need to copy as strtok() is destructive */
145 attribute = strdup (attributeDescription);
146 if (attribute == NULL)
147 {
148 return NSS_TRYAGAIN;
149 }
150
151 #ifndef HAVE_STRTOK_R
152 for (p = strtok (attribute, ";"); p != NULL; p = strtok (NULL, ";"))
153 #else
154 for (p = strtok_r (attribute, ";", &st);
155 p != NULL; p = strtok_r (NULL, ";", &st))
156 #endif /* !HAVE_STRTOK_R */
157 {
158 char *q;
159
160 if (p == attribute)
161 {
162 if (strcasecmp (p, attributeType) != 0)
163 {
164 free (attribute);
165 return NSS_NOTFOUND;
166 }
167 }
168 else if (strncasecmp (p, "range=", sizeof ("range=") - 1) == 0)
169 {
170 p += sizeof ("range=") - 1;
171
172 q = strchr (p, '-');
173 if (q == NULL)
174 {
175 free (attribute);
176 return NSS_NOTFOUND;
177 }
178
179 *q++ = '\0';
180
181 *start = strtoul (p, (char **) NULL, 10);
182 if (strcmp (q, "*") == 0)
183 *end = -1;
184 else
185 *end = strtoul (q, (char **) NULL, 10);
186
187 stat = NSS_SUCCESS;
188 break;
189 }
190 }
191
192 free (attribute);
193 return stat;
194 }
195
196 static NSS_STATUS
197 do_get_range_values (LDAPMessage * e,
198 const char *attributeType,
199 int *start, int *end, char ***pGroupMembers)
200 {
201 NSS_STATUS stat = NSS_NOTFOUND;
202 BerElement *ber = NULL;
203 char *attribute;
204
205 *pGroupMembers = NULL;
206
207 for (attribute = _nss_ldap_first_attribute (e, &ber);
208 attribute != NULL; attribute = _nss_ldap_next_attribute (e, ber))
209 {
210 stat = do_parse_range (attributeType, attribute, start, end);
211 if (stat == NSS_SUCCESS)
212 {
213 *pGroupMembers = _nss_ldap_get_values (e, attribute);
214 if (*pGroupMembers == NULL)
215 {
216 stat = NSS_NOTFOUND;
217 }
218 else if ((*pGroupMembers)[0] == NULL)
219 {
220 ldap_value_free (*pGroupMembers);
221 *pGroupMembers = NULL;
222 stat = NSS_NOTFOUND;
223 }
224 }
225
226 #ifdef HAVE_LDAP_MEMFREE
227 ldap_memfree (attribute);
228 #endif
229
230 if (stat == NSS_SUCCESS)
231 break;
232 }
233
234 if (ber != NULL)
235 ber_free (ber, 0);
236
237 return stat;
238 }
239
240 /*
241 * Format an attribute with description as:
242 * attribute;range=START-END
243 */
244 static NSS_STATUS
245 do_construct_range_attribute (const char *attribute,
246 int start,
247 int end,
248 char **buffer,
249 size_t * buflen,
250 const char **pAttributeWithRange)
251 {
252 size_t len;
253 char startbuf[32], endbuf[32];
254
255 snprintf (startbuf, sizeof (startbuf), "%u", start);
256
257 if (end != -1)
258 snprintf (endbuf, sizeof (endbuf), "%u", end);
259 else
260 snprintf (endbuf, sizeof (endbuf), "*");
261
262 len = strlen (attribute) + sizeof (";range=") - 1;
263 len += strlen (startbuf) + 1 /* - */ + strlen (endbuf);
264 len++; /* \0 */
265
266 if (*buflen < len)
267 return NSS_TRYAGAIN;
268
269 *pAttributeWithRange = *buffer;
270
271 snprintf (*buffer, len, "%s;range=%s-%s", attribute, startbuf, endbuf);
272
273 *buffer += len;
274 *buflen -= len;
275
276 return NSS_SUCCESS;
277 }
278
279 /*
280 * Expand group members, including nested groups
281 */
282 static NSS_STATUS
283 do_parse_group_members (LDAPMessage * e,
284 char ***pGroupMembers,
285 size_t * pGroupMembersCount,
286 size_t * pGroupMembersNext,
287 size_t * pGroupMembersBufferSize,
288 int *pGroupMembersBufferIsMalloced,
289 char **buffer, size_t * buflen,
290 int *depth,
291 struct name_list **pKnownGroups,
292 int itemsLeft) /* traversed groups */
293 {
294 NSS_STATUS stat = NSS_SUCCESS;
295 char **dnValues = NULL;
296 char **uidValues = NULL;
297 char **groupMembers;
298 size_t groupMembersCount, i;
299 char **valiter;
300 /* support for range retrieval */
301 const char *uniquemember_attr;
302 const char *uniquemember_attrs[2];
303 LDAPMessage *res = NULL;
304 int start, end = 0;
305 char *groupdn = NULL;
306
307 uniquemember_attr = ATM (LM_GROUP, uniqueMember);
308
309 uniquemember_attrs[0] = uniquemember_attr;
310 uniquemember_attrs[1] = NULL;
311
312 if (*depth > LDAP_NSS_MAXGR_DEPTH)
313 {
314 return NSS_NOTFOUND;
315 }
316
317 i = *pGroupMembersNext; /* index of next member */
318 groupMembers = *pGroupMembers;
319
320 groupdn = _nss_ldap_get_dn (e);
321 if (groupdn == NULL)
322 {
323 stat = NSS_NOTFOUND;
324 goto out;
325 }
326
327 if (_nss_ldap_namelist_find (*pKnownGroups, groupdn))
328 {
329 stat = NSS_NOTFOUND;
330 goto out;
331 }
332
333 /* store group DN for nested group loop detection */
334 stat = _nss_ldap_namelist_push (pKnownGroups, groupdn);
335 if (stat != NSS_SUCCESS)
336 {
337 goto out;
338 }
339
340 do
341 {
342 if (e == NULL)
343 {
344 stat = NSS_NOTFOUND;
345 goto out;
346 }
347
348 groupMembersCount = 0; /* number of members in this group */
349
350 (void) do_get_range_values (e, uniquemember_attrs[0], &start, &end, &dnValues);
351 if (dnValues != NULL)
352 {
353 groupMembersCount += ldap_count_values (dnValues);
354 }
355
356 uidValues = _nss_ldap_get_values (e, ATM (LM_GROUP, memberUid));
357 if (uidValues != NULL)
358 {
359 groupMembersCount += ldap_count_values (uidValues);
360 }
361
362 /*
363 * Check whether we need to increase the group membership buffer.
364 * As an optimization the buffer is preferentially allocated off
365 * the stack
366 */
367 if ((*pGroupMembersCount + groupMembersCount) * sizeof (char *) >=
368 *pGroupMembersBufferSize)
369 {
370 *pGroupMembersBufferSize =
371 (*pGroupMembersCount + groupMembersCount + 1) * sizeof (char *);
372 *pGroupMembersBufferSize +=
373 (LDAP_NSS_NGROUPS * sizeof (char *)) - 1;
374 *pGroupMembersBufferSize -=
375 (*pGroupMembersBufferSize %
376 (LDAP_NSS_NGROUPS * sizeof (char *)));
377
378 if (*pGroupMembersBufferIsMalloced == 0)
379 {
380 groupMembers = *pGroupMembers;
381 *pGroupMembers = NULL; /* force malloc() */
382 }
383
384 *pGroupMembers =
385 (char **) realloc (*pGroupMembers, *pGroupMembersBufferSize);
386 if (*pGroupMembers == NULL)
387 {
388 *pGroupMembersBufferIsMalloced = 0; /* don't try to free */
389 stat = NSS_TRYAGAIN;
390 goto out;
391 }
392
393 if (*pGroupMembersBufferIsMalloced == 0)
394 {
395 memcpy (*pGroupMembers, groupMembers, i * sizeof (char *));
396 groupMembers = NULL; /* defensive programming */
397 *pGroupMembersBufferIsMalloced = 1;
398 }
399 }
400
401 groupMembers = *pGroupMembers;
402 *pGroupMembersCount += groupMembersCount;
403
404 /* Parse distinguished name members */
405 if (dnValues != NULL)
406 {
407 for (valiter = dnValues; *valiter != NULL; valiter++)
408 {
409 LDAPMessage *res;
410 NSS_STATUS parseStat;
411 int isNestedGroup = 0;
412 char *uid;
413
414 uid = strrchr (*valiter, '#');
415 if (uid != NULL)
416 {
417 *uid = '\0';
418 }
419
420 parseStat = _nss_ldap_dn2uid (*valiter, &groupMembers[i],
421 buffer, buflen, &isNestedGroup,
422 &res);
423 if (parseStat == NSS_SUCCESS)
424 {
425 if (isNestedGroup == 0)
426 {
427 /* just a normal user which we have flattened */
428 i++;
429 itemsLeft--;
430 continue;
431 }
432
433 (*depth)++;
434 parseStat =
435 do_parse_group_members (_nss_ldap_first_entry (res),
436 &groupMembers, pGroupMembersCount, &i,
437 pGroupMembersBufferSize,
438 pGroupMembersBufferIsMalloced,
439 buffer, buflen, depth,
440 pKnownGroups, itemsLeft);
441 (*depth)--;
442
443 if (parseStat == NSS_TRYAGAIN)
444 {
445 stat = NSS_TRYAGAIN;
446 goto out;
447 }
448
449 ldap_msgfree (res);
450 }
451 else if (parseStat == NSS_TRYAGAIN)
452 {
453 stat = NSS_TRYAGAIN;
454 goto out;
455 }
456 }
457 }
458
459 /* Parse RFC 2307 (flat) members */
460 if (uidValues != NULL)
461 {
462 for (valiter = uidValues; *valiter != NULL; valiter++)
463 {
464 size_t len = strlen (*valiter) + 1;
465 if (*buflen < len)
466 {
467 stat = NSS_TRYAGAIN;
468 goto out;
469 }
470 groupMembers[i] = *buffer;
471 *buffer += len;
472 *buflen -= len;
473
474 memcpy (groupMembers[i++], *valiter, len);
475 }
476 }
477
478 /* Get next range for Active Directory compat */
479 if (end != -1)
480 {
481 stat = do_construct_range_attribute (uniquemember_attr,
482 end + 1,
483 -1,
484 buffer,
485 buflen,
486 &uniquemember_attrs[0]);
487 if (stat == NSS_SUCCESS)
488 {
489 if (dnValues != NULL)
490 {
491 ldap_value_free (dnValues);
492 dnValues = NULL;
493 }
494 if (uidValues != NULL)
495 {
496 ldap_value_free (uidValues);
497 uidValues = NULL;
498 }
499 if (res != NULL)
500 {
501 ldap_msgfree (res);
502 res = NULL;
503 }
504
505 stat = _nss_ldap_read (groupdn, uniquemember_attrs, &res);
506 if (stat != NSS_SUCCESS)
507 goto out;
508
509 e = _nss_ldap_first_entry (res);
510 }
511 }
512 }
513 while (end != -1);
514
515 out:
516 if (dnValues != NULL)
517 ldap_value_free (dnValues);
518 if (uidValues != NULL)
519 ldap_value_free (uidValues);
520 if (res != NULL)
521 ldap_msgfree (res);
522 if (groupdn != NULL)
523 #ifdef HAVE_LDAP_MEMFREE
524 ldap_memfree (groupdn);
525 #else
526 free (groupdn);
527 #endif
528
529 *pGroupMembers = groupMembers;
530 *pGroupMembersNext = i;
531
532 return stat;
533 }
534
535 /*
536 * "Fix" group membership list into caller provided buffer,
537 * and NULL terminate.
538 */
539 static NSS_STATUS
540 do_fix_group_members_buffer (char **mallocedGroupMembers,
541 size_t groupMembersCount,
542 char ***pGroupMembers,
543 char **buffer, size_t * buflen)
544 {
545 size_t len;
546
547 len = (groupMembersCount + 1) * sizeof (char *);
548
549 if (bytesleft (*buffer, *buflen, char *) < len)
550 {
551 return NSS_TRYAGAIN;
552 }
553
554 align (*buffer, *buflen, char *);
555 *pGroupMembers = (char **) *buffer;
556 *buffer += len;
557 *buflen -= len;
558
559 memcpy (*pGroupMembers, mallocedGroupMembers,
560 groupMembersCount * sizeof (char *));
561 (*pGroupMembers)[groupMembersCount] = NULL;
562
563 return NSS_SUCCESS;
564 }
565
566 static NSS_STATUS
567 _nss_ldap_parse_gr (LDAPMessage * e,
568 ldap_state_t * pvt,
569 void *result, char *buffer, size_t buflen)
570 {
571 struct group *gr = (struct group *) result;
572 char *gid;
573 NSS_STATUS stat;
574 char **groupMembers;
575 size_t groupMembersCount, groupMembersAttrCount;
576 size_t groupMembersBufferSize;
577 char *groupMembersBuffer[LDAP_NSS_NGROUPS];
578 int groupMembersBufferIsMalloced;
579 int depth;
580 struct name_list *knownGroups = NULL;
581
582 stat =
583 _nss_ldap_assign_attrval (e, ATM (LM_GROUP, gidNumber), &gid, &buffer,
584 &buflen);
585 if (stat != NSS_SUCCESS)
586 return stat;
587
588 gr->gr_gid =
589 (*gid == '\0') ? (unsigned) GID_NOBODY : (gid_t) strtoul (gid,
590 (char **) NULL,
591 10);
592
593 stat =
594 _nss_ldap_getrdnvalue (e, ATM (LM_GROUP, cn), &gr->gr_name, &buffer,
595 &buflen);
596 if (stat != NSS_SUCCESS)
597 return stat;
598
599 stat =
600 _nss_ldap_assign_userpassword (e, ATM (LM_GROUP, userPassword),
601 &gr->gr_passwd, &buffer, &buflen);
602 if (stat != NSS_SUCCESS)
603 return stat;
604
605 if (_nss_ldap_test_config_flag (NSS_LDAP_FLAGS_RFC2307BIS))
606 {
607 groupMembers = groupMembersBuffer;
608 groupMembersAttrCount = 0;
609 groupMembersCount = 0;
610 groupMembersBufferSize = sizeof (groupMembersBuffer);
611 groupMembersBufferIsMalloced = 0;
612 depth = 0;
613
614 stat = do_parse_group_members (e, &groupMembers,
615 &groupMembersAttrCount,
616 &groupMembersCount,
617 &groupMembersBufferSize,
618 &groupMembersBufferIsMalloced, &buffer,
619 &buflen, &depth, &knownGroups, 0);
620 if (stat != NSS_SUCCESS)
621 {
622 if (groupMembersBufferIsMalloced)
623 free (groupMembers);
624 _nss_ldap_namelist_destroy (&knownGroups);
625 return stat;
626 }
627
628 stat = do_fix_group_members_buffer (groupMembers, groupMembersCount,
629 &gr->gr_mem, &buffer, &buflen);
630
631 if (groupMembersBufferIsMalloced)
632 free (groupMembers);
633 _nss_ldap_namelist_destroy (&knownGroups);
634 }
635 else
636 {
637 stat =
638 _nss_ldap_assign_attrvals (e, ATM (LM_GROUP, memberUid), NULL,
639 &gr->gr_mem, &buffer, &buflen, NULL);
640 }
641
642 return stat;
643 }
644
645 /*
646 * Add a group ID to a group list, and optionally the group IDs
647 * of any groups to which this group belongs (RFC2307bis nested
648 * group expansion is done by do_parse_initgroups_nested()).
649 */
650 static NSS_STATUS
651 do_parse_initgroups (LDAPMessage * e,
652 ldap_state_t * pvt, void *result,
653 char *buffer, size_t buflen)
654 {
655 char **values;
656 ssize_t i;
657 gid_t gid;
658 ldap_initgroups_args_t *lia = (ldap_initgroups_args_t *) result;
659
660 values = _nss_ldap_get_values (e, ATM (LM_GROUP, gidNumber));
661 if (values == NULL)
662 {
663 /* invalid group; skip it */
664 return NSS_NOTFOUND;
665 }
666
667 if (values[0] == NULL)
668 {
669 /* invalid group; skip it */
670 ldap_value_free (values);
671 return NSS_NOTFOUND;
672 }
673
674 #ifdef HAVE_USERSEC_H
675 i = strlen (values[0]);
676 lia->grplist = realloc (lia->grplist, lia->listlen + i + 2);
677 if (lia->grplist == NULL)
678 {
679 ldap_value_free (values);
680 return NSS_TRYAGAIN;
681 }
682 memcpy (lia->grplist + lia->listlen, values[0], i);
683 lia->grplist[lia->listlen + i] = ',';
684 lia->listlen += i + 1;
685 ldap_value_free (values);
686 #else
687 gid = strtoul (values[0], (char **) NULL, 10);
688 ldap_value_free (values);
689
690 if (gid == LONG_MAX && errno == ERANGE)
691 {
692 /* invalid group, skip it */
693 return NSS_NOTFOUND;
694 }
695
696 # ifdef HAVE_NSSWITCH_H
697 /* weed out duplicates; is this really our resposibility? */
698 for (i = 0; i < lia->gbm->numgids; i++)
699 {
700 if (lia->gbm->gid_array[i] == (gid_t) gid)
701 return NSS_NOTFOUND;
702 }
703
704 if (lia->gbm->numgids == lia->gbm->maxgids)
705 {
706 /* can't fit any more */
707 /*
708 * should probably return NSS_TRYAGAIN but IIRC
709 * will send Solaris into an infinite loop XXX
710 */
711 return NSS_SUCCESS;
712 }
713
714 lia->gbm->gid_array[lia->gbm->numgids++] = (gid_t) gid;
715 # else
716 if (gid == lia->group)
717 {
718 /* primary group, so skip it */
719 return NSS_NOTFOUND;
720 }
721
722 if (lia->limit > 0)
723 {
724 if (*(lia->start) >= lia->limit)
725 {
726 /* can't fit any more */
727 return NSS_TRYAGAIN;
728 }
729 }
730
731 if (*(lia->size) == 0)
732 {
733 *(lia->groups) = (gid_t *) realloc(*(lia->groups),
734 LDAP_NSS_NGROUPS * sizeof (gid_t));
735 if (*(lia->groups) == NULL)
736 {
737 return NSS_TRYAGAIN;
738 }
739 *(lia->size) = LDAP_NSS_NGROUPS;
740 }
741 if (*(lia->start) == *(lia->size))
742 {
743 /* Need a bigger buffer */
744 *(lia->groups) = (gid_t *) realloc (*(lia->groups),
745 2 * *(lia->size) * sizeof (gid_t));
746 if (*(lia->groups) == NULL)
747 {
748 return NSS_TRYAGAIN;
749 }
750 *(lia->size) *= 2;
751 }
752 else
753 {
754 assert(*(lia->start) < *(lia->size));
755 }
756
757 /* weed out duplicates; is this really our responsibility? */
758 for (i = 0; i < *(lia->start); i++)
759 {
760 if ((*(lia->groups))[i] == gid)
761 {
762 return NSS_NOTFOUND;
763 }
764 }
765
766 /* add to group list */
767 (*(lia->groups))[*(lia->start)] = gid;
768 (*(lia->start)) += 1;
769 # endif /* HAVE_NSSWITCH_H */
770 #endif /* HAVE_USERSEC_H */
771
772 return NSS_NOTFOUND;
773 }
774
775 static NSS_STATUS
776 do_parse_initgroups_nested (LDAPMessage * e,
777 ldap_state_t * pvt, void *result,
778 char *buffer, size_t buflen)
779 {
780 NSS_STATUS stat;
781 ldap_initgroups_args_t *lia = (ldap_initgroups_args_t *) result;
782 char **values;
783 char *groupdn;
784
785 stat = do_parse_initgroups (e, pvt, result, buffer, buflen);
786 if (stat != NSS_NOTFOUND)
787 {
788 return stat;
789 }
790
791 if (!_nss_ldap_test_config_flag (NSS_LDAP_FLAGS_RFC2307BIS))
792 {
793 return NSS_NOTFOUND;
794 }
795
796 if (lia->backlink != 0)
797 {
798 /*
799 * Now add the GIDs of any groups of which this group is
800 * a member.
801 */
802 values = _nss_ldap_get_values (e, ATM (LM_GROUP, memberOf));
803 if (values != NULL)
804 {
805 NSS_STATUS stat;
806
807 lia->depth++;
808 stat = ng_chase_backlink ((const char **)values, lia);
809 lia->depth--;
810
811 ldap_value_free (values);
812
813 return stat;
814 }
815 }
816 else
817 {
818 /*
819 * Now add the GIDs of any groups which refer to this group
820 */
821 groupdn = _nss_ldap_get_dn (e);
822 if (groupdn != NULL)
823 {
824 NSS_STATUS stat;
825
826 lia->depth++;
827 stat = ng_chase (groupdn, lia);
828 lia->depth--;
829 #ifdef HAVE_LDAP_MEMFREE
830 ldap_memfree (groupdn);
831 #else
832 free (groupdn);
833 #endif
834 }
835 }
836
837 return stat;
838 }
839
840 static NSS_STATUS
841 ng_chase (const char *dn, ldap_initgroups_args_t * lia)
842 {
843 ldap_args_t a;
844 NSS_STATUS stat;
845 ent_context_t *ctx = NULL;
846 const char *gidnumber_attrs[2];
847 int erange;
848
849 if (lia->depth > LDAP_NSS_MAXGR_DEPTH)
850 return NSS_NOTFOUND;
851
852 if (_nss_ldap_namelist_find (lia->known_groups, dn))
853 return NSS_NOTFOUND;
854
855 gidnumber_attrs[0] = ATM (LM_GROUP, gidNumber);
856 gidnumber_attrs[1] = NULL;
857
858 LA_INIT (a);
859 LA_STRING (a) = dn;
860 LA_TYPE (a) = LA_TYPE_STRING;
861
862 if (_nss_ldap_ent_context_init_locked (&ctx) == NULL)
863 {
864 return NSS_UNAVAIL;
865 }
866
867 stat = _nss_ldap_getent_ex (&a, &ctx, lia, NULL, 0,
868 &erange, _nss_ldap_filt_getgroupsbydn,
869 LM_GROUP, gidnumber_attrs,
870 do_parse_initgroups_nested);
871
872 if (stat == NSS_SUCCESS)
873 {
874 stat = _nss_ldap_namelist_push (&lia->known_groups, dn);
875 }
876
877 _nss_ldap_ent_context_release (&ctx);
878
879 return stat;
880 }
881
882 static NSS_STATUS
883 ng_chase_backlink (const char ** membersOf, ldap_initgroups_args_t * lia)
884 {
885 ldap_args_t a;
886 NSS_STATUS stat;
887 ent_context_t *ctx = NULL;
888 const char *gidnumber_attrs[3];
889 const char **memberP;
890 const char **filteredMembersOf; /* remove already traversed groups */
891 size_t memberCount, i;
892 int erange;
893
894 if (lia->depth > LDAP_NSS_MAXGR_DEPTH)
895 return NSS_NOTFOUND;
896
897 for (memberCount = 0; membersOf[memberCount] != NULL; memberCount++)
898 ;
899
900 /* Build a list of membersOf values without any already traversed groups */
901 filteredMembersOf = (const char **) malloc(sizeof(char *) * (memberCount + 1));
902 if (filteredMembersOf == NULL)
903 {
904 return NSS_TRYAGAIN;
905 }
906
907 memberP = filteredMembersOf;
908
909 for (i = 0; i < memberCount; i++)
910 {
911 if (_nss_ldap_namelist_find (lia->known_groups, membersOf[i]))
912 continue;
913
914 *memberP = membersOf[i];
915 memberP++;
916 }
917
918 *memberP = NULL;
919
920 if (filteredMembersOf[0] == NULL)
921 {
922 free (filteredMembersOf);
923 return NSS_NOTFOUND;
924 }
925
926 gidnumber_attrs[0] = ATM (LM_GROUP, gidNumber);
927 gidnumber_attrs[1] = ATM (LM_GROUP, memberOf);
928 gidnumber_attrs[2] = NULL;
929
930 LA_INIT (a);
931 LA_STRING_LIST (a) = filteredMembersOf;
932 LA_TYPE (a) = LA_TYPE_STRING_LIST_OR;
933
934 if (_nss_ldap_ent_context_init_locked (&ctx) == NULL)
935 {
936 free (filteredMembersOf);
937 return NSS_UNAVAIL;
938 }
939
940 stat = _nss_ldap_getent_ex (&a, &ctx, lia, NULL, 0,
941 &erange, "(distinguishedName=%s)",
942 LM_GROUP, gidnumber_attrs,
943 do_parse_initgroups_nested);
944
945 if (stat == NSS_SUCCESS)
946 {
947 NSS_STATUS stat2;
948
949 for (memberP = filteredMembersOf; *memberP != NULL; memberP++)
950 {
951 stat2 = _nss_ldap_namelist_push (&lia->known_groups, *memberP);
952 if (stat2 != NSS_SUCCESS)
953 {
954 stat = stat2;
955 break;
956 }
957 }
958 }
959
960 free (filteredMembersOf);
961
962 _nss_ldap_ent_context_release (&ctx);
963
964 return stat;
965 }
966
967 #if defined(HAVE_NSSWITCH_H) || defined(HAVE_NSS_H) || defined(HAVE_USERSEC_H)
968 #ifdef HAVE_NSS_H
969 NSS_STATUS _nss_ldap_initgroups_dyn (const char *user, gid_t group,
970 long int *start, long int *size,
971 gid_t ** groupsp, long int limit,
972 int *errnop);
973
974 NSS_STATUS
975 _nss_ldap_initgroups (const char *user, gid_t group, long int *start,
976 long int *size, gid_t * groups, long int limit,
977 int *errnop)
978 {
979 return (_nss_ldap_initgroups_dyn (user, group, start, size, &groups, limit,
980 errnop));
981 }
982 #endif
983
984 #ifdef HAVE_NSSWITCH_H
985 #define NSS_LDAP_INITGROUPS_FUNCTION "_nss_ldap_getgroupsbymember_r"
986 #elif defined(HAVE_NSS_H)
987 #define NSS_LDAP_INITGROUPS_FUNCTION "_nss_ldap_initgroups_dyn"
988 #elif defined(HAVE_USERSEC_H)
989 #define NSS_LDAP_INITGROUPS_FUNCTION "_nss_ldap_getgrset"
990 #endif
991
992 #ifdef HAVE_NSSWITCH_H
993 static NSS_STATUS
994 _nss_ldap_getgroupsbymember_r (nss_backend_t * be, void *args)
995 #elif defined(HAVE_NSS_H)
996 NSS_STATUS
997 _nss_ldap_initgroups_dyn (const char *user, gid_t group, long int *start,
998 long int *size, gid_t ** groupsp, long int limit,
999 int *errnop)
1000 #elif defined(HAVE_USERSEC_H)
1001 char *_nss_ldap_getgrset (char *user)
1002 #endif
1003 {
1004 ldap_initgroups_args_t lia;
1005 #ifndef HAVE_NSS_H
1006 int erange = 0;
1007 #endif /* HAVE_NSS_H */
1008 char *userdn = NULL;
1009 LDAPMessage *res, *e;
1010 static const char *no_attrs[] = { NULL };
1011 const char *filter;
1012 ldap_args_t a;
1013 NSS_STATUS stat;
1014 ent_context_t *ctx = NULL;
1015 const char *gidnumber_attrs[3];
1016 ldap_map_selector_t map = LM_GROUP;
1017
1018 LA_INIT (a);
1019 #if defined(HAVE_NSS_H) || defined(HAVE_USERSEC_H)
1020 LA_STRING (a) = user;
1021 #else
1022 LA_STRING (a) = ((struct nss_groupsbymem *) args)->username;
1023 #endif /* HAVE_NSS_H || HAVE_USERSEC_H */
1024 LA_TYPE (a) = LA_TYPE_STRING;
1025
1026 debug ("==> " NSS_LDAP_INITGROUPS_FUNCTION " (user=%s)", LA_STRING (a) );
1027
1028 #ifdef INITGROUPS_ROOT_ONLY
1029 /* XXX performance hack for old versions of KDE only */
1030 if ((getuid() != 0) && (geteuid() != 0))
1031 return NSS_NOTFOUND;
1032 #endif
1033
1034 #ifdef HAVE_USERSEC_H
1035 lia.grplist = NULL;
1036 lia.listlen = 0;
1037 #elif defined(HAVE_NSSWITCH_H)
1038 lia.gbm = (struct nss_groupsbymem *) args;
1039 #else
1040 lia.group = group;
1041 lia.start = start;
1042 lia.size = size;
1043 lia.groups = groupsp;
1044 lia.limit = limit;
1045 #endif /* HAVE_USERSEC_H */
1046 lia.depth = 0;
1047 lia.known_groups = NULL;
1048
1049 _nss_ldap_enter ();
1050
1051 /* initialize schema */
1052 stat = _nss_ldap_init ();
1053 if (stat != NSS_SUCCESS)
1054 {
1055 debug ("<== " NSS_LDAP_INITGROUPS_FUNCTION " (init failed)");
1056 _nss_ldap_leave ();
1057 # ifdef HAVE_USERSEC_H
1058 return NULL;
1059 # else
1060 return stat;
1061 # endif /* !HAVE_USERSEC_H */
1062 }
1063
1064 if (_nss_ldap_test_initgroups_ignoreuser (LA_STRING (a)))
1065 {
1066 debug ("<== " NSS_LDAP_INITGROUPS_FUNCTION " (user ignored)");
1067 _nss_ldap_leave ();
1068 return NSS_NOTFOUND;
1069 }
1070
1071 lia.backlink = _nss_ldap_test_config_flag (NSS_LDAP_FLAGS_INITGROUPS_BACKLINK);
1072
1073 if (lia.backlink != 0)
1074 {
1075 filter = _nss_ldap_filt_getpwnam_groupsbymember;
1076 LA_STRING2 (a) = LA_STRING (a);
1077 LA_TYPE (a) = LA_TYPE_STRING_AND_STRING;
1078
1079 gidnumber_attrs[0] = ATM (LM_GROUP, gidNumber);
1080 gidnumber_attrs[1] = ATM (LM_GROUP, memberOf);
1081 gidnumber_attrs[2] = NULL;
1082
1083 map = LM_PASSWD;
1084 }
1085 else
1086 {
1087 if (_nss_ldap_test_config_flag (NSS_LDAP_FLAGS_RFC2307BIS))
1088 {
1089 /* lookup the user's DN. */
1090 stat = _nss_ldap_search_s (&a, _nss_ldap_filt_getpwnam, LM_PASSWD,
1091 no_attrs, 1, &res);
1092 if (stat == NSS_SUCCESS)
1093 {
1094 e = _nss_ldap_first_entry (res);
1095 if (e != NULL)
1096 {
1097 userdn = _nss_ldap_get_dn (e);
1098 }
1099 ldap_msgfree (res);
1100 }
1101 }
1102 else
1103 {
1104 userdn = NULL;
1105 }
1106
1107 if (userdn != NULL)
1108 {
1109 LA_STRING2 (a) = userdn;
1110 LA_TYPE (a) = LA_TYPE_STRING_AND_STRING;
1111 filter = _nss_ldap_filt_getgroupsbymemberanddn;
1112 }
1113 else
1114 {
1115 filter = _nss_ldap_filt_getgroupsbymember;
1116 }
1117
1118 gidnumber_attrs[0] = ATM (LM_GROUP, gidNumber);
1119 gidnumber_attrs[1] = NULL;
1120 }
1121
1122 if (_nss_ldap_ent_context_init_locked (&ctx) == NULL)
1123 {
1124 debug ("<== " NSS_LDAP_INITGROUPS_FUNCTION " (ent_context_init failed)");
1125 _nss_ldap_leave ();
1126 # ifdef HAVE_USERSEC_H
1127 return NULL;
1128 # else
1129 return NSS_UNAVAIL;
1130 # endif /* HAVE_USERSEC_H */
1131 }
1132
1133 stat = _nss_ldap_getent_ex (&a, &ctx, (void *) &lia, NULL, 0,
1134 #ifdef HAVE_NSS_H
1135 errnop,
1136 #else
1137 &erange,
1138 #endif /* HAVE_NSS_H */
1139 filter,
1140 map,
1141 gidnumber_attrs,
1142 do_parse_initgroups_nested);
1143
1144 if (userdn != NULL)
1145 {
1146 #ifdef HAVE_LDAP_MEMFREE
1147 ldap_memfree (userdn);
1148 #else
1149 free (userdn);
1150 #endif /* HAVE_LDAP_MEMFREE */
1151 }
1152
1153 _nss_ldap_namelist_destroy (&lia.known_groups);
1154 _nss_ldap_ent_context_release (&ctx);
1155 _nss_ldap_leave ();
1156
1157 /*
1158 * We return NSS_NOTFOUND to force the parser to be called
1159 * for as many entries (i.e. groups) as exist, for all
1160 * search descriptors. So confusingly this means "success".
1161 */
1162 if (stat != NSS_SUCCESS && stat != NSS_NOTFOUND)
1163 {
1164 debug ("<== " NSS_LDAP_INITGROUPS_FUNCTION " (not found)");
1165 #ifndef HAVE_NSS_H
1166 if (erange)
1167 errno = ERANGE;
1168 #endif /* HAVE_NSS_H */
1169 #ifndef HAVE_USERSEC_H
1170 return stat;
1171 #else
1172 return NULL;
1173 #endif /* HAVE_USERSEC_H */
1174 }
1175
1176 debug ("<== " NSS_LDAP_INITGROUPS_FUNCTION " (success)");
1177
1178 #ifdef HAVE_NSS_H
1179 return NSS_SUCCESS;
1180 #elif defined(HAVE_USERSEC_H)
1181 /* Strip last comma and terminate the string */
1182 if (lia.grplist == NULL)
1183 lia.grplist = strdup("");
1184 else if (lia.listlen != 0)
1185 lia.grplist[lia.listlen - 1] = '\0';
1186
1187 return lia.grplist;
1188 #else
1189 /* yes, NSS_NOTFOUND is the successful errno code. see nss_dbdefs.h */
1190 return NSS_NOTFOUND;
1191 #endif /* HAVE_NSS_H */
1192 }
1193
1194 #endif /* HAVE_NSSWITCH_H || HAVE_NSS_H || HAVE_USERSEC_H */
1195
1196 #ifdef HAVE_NSS_H
1197 NSS_STATUS
1198 _nss_ldap_getgrnam_r (const char *name,
1199 struct group * result,
1200 char *buffer, size_t buflen, int *errnop)
1201 {
1202 LOOKUP_NAME (name, result, buffer, buflen, errnop, _nss_ldap_filt_getgrnam,
1203 LM_GROUP, _nss_ldap_parse_gr, LDAP_NSS_BUFLEN_GROUP);
1204 }
1205 #elif defined(HAVE_NSSWITCH_H)
1206 static NSS_STATUS
1207 _nss_ldap_getgrnam_r (nss_backend_t * be, void *args)
1208 {
1209 LOOKUP_NAME (args, _nss_ldap_filt_getgrnam, LM_GROUP, _nss_ldap_parse_gr,
1210 LDAP_NSS_BUFLEN_GROUP);
1211 }
1212 #endif
1213
1214 #ifdef HAVE_NSS_H
1215 NSS_STATUS
1216 _nss_ldap_getgrgid_r (gid_t gid,
1217 struct group *result,
1218 char *buffer, size_t buflen, int *errnop)
1219 {
1220 LOOKUP_NUMBER (gid, result, buffer, buflen, errnop, _nss_ldap_filt_getgrgid,
1221 LM_GROUP, _nss_ldap_parse_gr, LDAP_NSS_BUFLEN_GROUP);
1222 }
1223 #elif defined(HAVE_NSSWITCH_H)
1224 static NSS_STATUS
1225 _nss_ldap_getgrgid_r (nss_backend_t * be, void *args)
1226 {
1227 LOOKUP_NUMBER (args, key.gid, _nss_ldap_filt_getgrgid, LM_GROUP,
1228 _nss_ldap_parse_gr, LDAP_NSS_BUFLEN_GROUP);
1229 }
1230 #endif
1231
1232 #if defined(HAVE_NSS_H)
1233 NSS_STATUS _nss_ldap_setgrent (void)
1234 {
1235 LOOKUP_SETENT (gr_context);
1236 }
1237 #elif defined(HAVE_NSSWITCH_H)
1238 static NSS_STATUS
1239 _nss_ldap_setgrent_r (nss_backend_t * gr_context, void *args)
1240 {
1241 LOOKUP_SETENT (gr_context);
1242 }
1243 #endif
1244
1245 #if defined(HAVE_NSS_H)
1246 NSS_STATUS _nss_ldap_endgrent (void)
1247 {
1248 LOOKUP_ENDENT (gr_context);
1249 }
1250 #elif defined(HAVE_NSSWITCH_H)
1251 static NSS_STATUS
1252 _nss_ldap_endgrent_r (nss_backend_t * gr_context, void *args)
1253 {
1254 LOOKUP_ENDENT (gr_context);
1255 }
1256 #endif
1257
1258 #ifdef HAVE_NSS_H
1259 NSS_STATUS
1260 _nss_ldap_getgrent_r (struct group *result,
1261 char *buffer, size_t buflen, int *errnop)
1262 {
1263 LOOKUP_GETENT (gr_context, result, buffer, buflen, errnop,
1264 _nss_ldap_filt_getgrent, LM_GROUP, _nss_ldap_parse_gr,
1265 LDAP_NSS_BUFLEN_GROUP);
1266 }
1267 #elif defined(HAVE_NSSWITCH_H)
1268 static NSS_STATUS
1269 _nss_ldap_getgrent_r (nss_backend_t * gr_context, void *args)
1270 {
1271 LOOKUP_GETENT (args, gr_context, _nss_ldap_filt_getgrent, LM_GROUP,
1272 _nss_ldap_parse_gr, LDAP_NSS_BUFLEN_GROUP);
1273 }
1274 #endif
1275
1276 #ifdef HAVE_NSSWITCH_H
1277 static NSS_STATUS
1278 _nss_ldap_group_destr (nss_backend_t * gr_context, void *args)
1279 {
1280 return _nss_ldap_default_destr (gr_context, args);
1281 }
1282
1283 static nss_backend_op_t group_ops[] = {
1284 _nss_ldap_group_destr,
1285 _nss_ldap_endgrent_r,
1286 _nss_ldap_setgrent_r,
1287 _nss_ldap_getgrent_r,
1288 _nss_ldap_getgrnam_r,
1289 _nss_ldap_getgrgid_r,
1290 _nss_ldap_getgroupsbymember_r
1291 };
1292
1293 nss_backend_t *
1294 _nss_ldap_group_constr (const char *db_name,
1295 const char *src_name, const char *cfg_args)
1296 {
1297 nss_ldap_backend_t *be;
1298
1299 if (!(be = (nss_ldap_backend_t *) malloc (sizeof (*be))))
1300 return NULL;
1301
1302 be->ops = group_ops;
1303 be->n_ops = sizeof (group_ops) / sizeof (nss_backend_op_t);
1304
1305 /* a NOOP at the moment */
1306 if (_nss_ldap_default_constr (be) != NSS_SUCCESS)
1307 return NULL;
1308
1309 return (nss_backend_t *) be;
1310 }
1311
1312
1313 #endif /* !HAVE_NSS_H */
1314
1315 #ifdef HAVE_IRS_H
1316 #include "irs-grp.c"
1317 #endif