]> git.ipfire.org Git - thirdparty/glibc.git/blob - nis/nss_nis/nis-initgroups.c
Update.
[thirdparty/glibc.git] / nis / nss_nis / nis-initgroups.c
1 /* Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
4
5 The GNU C 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 GNU C 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 GNU C 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 #include <nss.h>
21 #include <grp.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <rpcsvc/yp.h>
27 #include <rpcsvc/ypclnt.h>
28 #include <sys/param.h>
29
30 #include "nss-nis.h"
31
32 /* Get the declaration of the parser function. */
33 #define ENTNAME grent
34 #define STRUCTURE group
35 #define EXTERN_PARSER
36 #include <nss/nss_files/files-parse.c>
37
38 struct response_t
39 {
40 char *val;
41 struct response_t *next;
42 };
43
44 struct intern_t
45 {
46 struct response_t *start;
47 struct response_t *next;
48 };
49 typedef struct intern_t intern_t;
50
51 static int
52 saveit (int instatus, char *inkey, int inkeylen, char *inval,
53 int invallen, char *indata)
54 {
55 intern_t *intern = (intern_t *) indata;
56
57 if (instatus != YP_TRUE)
58 return instatus;
59
60 if (inkey && inkeylen > 0 && inval && invallen > 0)
61 {
62 if (intern->start == NULL)
63 {
64 intern->start = malloc (sizeof (struct response_t));
65 if (intern->start == NULL)
66 return YP_FALSE;
67 intern->next = intern->start;
68 }
69 else
70 {
71 intern->next->next = malloc (sizeof (struct response_t));
72 if (intern->next->next == NULL)
73 return YP_FALSE;
74 intern->next = intern->next->next;
75 }
76 intern->next->next = NULL;
77 intern->next->val = malloc (invallen + 1);
78 if (intern->next->val == NULL)
79 return YP_FALSE;
80 strncpy (intern->next->val, inval, invallen);
81 intern->next->val[invallen] = '\0';
82 }
83
84 return 0;
85 }
86
87 static enum nss_status
88 internal_setgrent (intern_t *intern)
89 {
90 char *domainname;
91 struct ypall_callback ypcb;
92 enum nss_status status;
93
94 if (yp_get_default_domain (&domainname))
95 return NSS_STATUS_UNAVAIL;
96
97 intern->start = NULL;
98
99 ypcb.foreach = saveit;
100 ypcb.data = (char *) intern;
101 status = yperr2nss (yp_all (domainname, "group.byname", &ypcb));
102 intern->next = intern->start;
103
104 return status;
105 }
106
107 static enum nss_status
108 internal_getgrent_r (struct group *grp, char *buffer, size_t buflen,
109 int *errnop, intern_t *intern)
110 {
111 struct parser_data *data = (void *) buffer;
112 int parse_res;
113 char *p;
114
115 if (intern->start == NULL)
116 internal_setgrent (intern);
117
118 /* Get the next entry until we found a correct one. */
119 do
120 {
121 if (intern->next == NULL)
122 {
123 *errnop = ENOENT;
124 return NSS_STATUS_NOTFOUND;
125 }
126 p = strncpy (buffer, intern->next->val, buflen);
127 while (isspace (*p))
128 ++p;
129
130 parse_res = _nss_files_parse_grent (p, grp, data, buflen, errnop);
131 if (parse_res == -1)
132 return NSS_STATUS_TRYAGAIN;
133 intern->next = intern->next->next;
134 }
135 while (!parse_res);
136
137 return NSS_STATUS_SUCCESS;
138 }
139
140 enum nss_status
141 _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start,
142 long int *size, gid_t **groupsp, long int limit,
143 int *errnop)
144 {
145 struct group grpbuf, *g;
146 size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
147 char *tmpbuf;
148 enum nss_status status;
149 intern_t intern = { NULL, NULL };
150 gid_t *groups = *groupsp;
151
152 status = internal_setgrent (&intern);
153 if (status != NSS_STATUS_SUCCESS)
154 return status;
155
156 tmpbuf = __alloca (buflen);
157
158 do
159 {
160 while ((status =
161 internal_getgrent_r (&grpbuf, tmpbuf, buflen, errnop,
162 &intern)) == NSS_STATUS_TRYAGAIN
163 && *errnop == ERANGE)
164 {
165 buflen *= 2;
166 tmpbuf = __alloca (buflen);
167 }
168
169 if (status != NSS_STATUS_SUCCESS)
170 goto done;
171
172
173 g = &grpbuf;
174 if (g->gr_gid != group)
175 {
176 char **m;
177
178 for (m = g->gr_mem; *m != NULL; ++m)
179 if (strcmp (*m, user) == 0)
180 {
181 /* Matches user. Insert this group. */
182 if (*start == *size)
183 {
184 /* Need a bigger buffer. */
185 gid_t *newgroups;
186 long int newsize;
187
188 if (limit > 0 && *size == limit)
189 /* We reached the maximum. */
190 goto done;
191
192 if (limit <= 0)
193 newsize = 2 * *size;
194 else
195 newsize = MIN (limit, 2 * *size);
196
197 newgroups = realloc (groups, newsize * sizeof (*groups));
198 if (newgroups == NULL)
199 goto done;
200 *groupsp = groups = newgroups;
201 *size = newsize;
202 }
203
204 groups[*start] = g->gr_gid;
205 *start += 1;
206
207 break;
208 }
209 }
210 }
211 while (status == NSS_STATUS_SUCCESS);
212
213 done:
214 while (intern.start != NULL)
215 {
216 if (intern.start->val != NULL)
217 free (intern.start->val);
218 intern.next = intern.start;
219 intern.start = intern.start->next;
220 free (intern.next);
221 }
222
223 return NSS_STATUS_SUCCESS;
224 }