1 /* Copyright (C) 1998-2000, 2002, 2003, 2004 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
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 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 #include <rpcsvc/yp.h>
29 #include <rpcsvc/ypclnt.h>
30 #include <sys/param.h>
34 /* Get the declaration of the parser function. */
36 #define STRUCTURE group
38 #include <nss/nss_files/files-parse.c>
42 struct response_t
*next
;
48 struct response_t
*start
;
49 struct response_t
*next
;
51 typedef struct intern_t intern_t
;
54 saveit (int instatus
, char *inkey
, int inkeylen
, char *inval
,
55 int invallen
, char *indata
)
57 intern_t
*intern
= (intern_t
*) indata
;
59 if (instatus
!= YP_TRUE
)
62 if (inkey
&& inkeylen
> 0 && inval
&& invallen
> 0)
64 struct response_t
*newp
= malloc (sizeof (struct response_t
)
67 return 1; /* We have no error code for out of memory */
69 if (intern
->start
== NULL
)
72 intern
->next
->next
= newp
;
76 *((char *) mempcpy (newp
->val
, inval
, invallen
)) = '\0';
82 static enum nss_status
83 internal_setgrent (char *domainname
, intern_t
*intern
)
85 struct ypall_callback ypcb
;
86 enum nss_status status
;
90 ypcb
.foreach
= saveit
;
91 ypcb
.data
= (char *) intern
;
92 status
= yperr2nss (yp_all (domainname
, "group.byname", &ypcb
));
93 intern
->next
= intern
->start
;
98 static enum nss_status
99 internal_getgrent_r (struct group
*grp
, char *buffer
, size_t buflen
,
100 int *errnop
, intern_t
*intern
)
102 struct parser_data
*data
= (void *) buffer
;
106 if (intern
->start
== NULL
)
107 return NSS_STATUS_NOTFOUND
;
109 /* Get the next entry until we found a correct one. */
112 if (intern
->next
== NULL
)
113 return NSS_STATUS_NOTFOUND
;
115 p
= strncpy (buffer
, intern
->next
->val
, buflen
);
119 parse_res
= _nss_files_parse_grent (p
, grp
, data
, buflen
, errnop
);
121 return NSS_STATUS_TRYAGAIN
;
122 intern
->next
= intern
->next
->next
;
126 return NSS_STATUS_SUCCESS
;
131 get_uid (const char *user
, uid_t
*uidp
)
133 size_t buflen
= sysconf (_SC_GETPW_R_SIZE_MAX
);
134 char *buf
= (char *) alloca (buflen
);
138 struct passwd result
;
141 int r
= getpwnam_r (user
, &result
, buf
, buflen
, &resp
);
142 if (r
== 0 && resp
!= NULL
)
144 *uidp
= resp
->pw_uid
;
151 extend_alloca (buf
, buflen
, 2 * buflen
);
158 static enum nss_status
159 initgroups_netid (uid_t uid
, gid_t group
, long int *start
, long int *size
,
160 gid_t
**groupsp
, long int limit
, int *errnop
,
161 const char *domainname
)
163 /* Prepare the key. The form is "unix.UID@DOMAIN" with the UID and
164 DOMAIN field filled in appropriately. */
165 char key
[sizeof ("unix.@") + sizeof (uid_t
) * 3 + strlen (domainname
)];
166 ssize_t keylen
= snprintf (key
, sizeof (key
), "unix.%lu@%s",
167 (unsigned long int) uid
, domainname
);
169 enum nss_status retval
;
172 retval
= yperr2nss (yp_match (domainname
, "netid.byname", key
, keylen
,
174 if (retval
!= NSS_STATUS_SUCCESS
)
177 /* Parse the result: following the colon is a comma separated list of
179 char *cp
= strchr (result
, ':');
184 return NSS_STATUS_NOTFOUND
;
186 /* Skip the colon. */
189 gid_t
*groups
= *groupsp
;
193 unsigned long int gid
= strtoul (cp
, &endp
, 0);
198 else if (*endp
!= '\0')
203 /* We do not need this group again. */
206 /* Insert this group. */
209 /* Need a bigger buffer. */
213 if (limit
> 0 && *size
== limit
)
214 /* We reached the maximum. */
220 newsize
= MIN (limit
, 2 * *size
);
222 newgroups
= realloc (groups
, newsize
* sizeof (*groups
));
223 if (newgroups
== NULL
)
225 *groupsp
= groups
= newgroups
;
229 groups
[*start
] = gid
;
235 return NSS_STATUS_SUCCESS
;
240 _nss_nis_initgroups_dyn (const char *user
, gid_t group
, long int *start
,
241 long int *size
, gid_t
**groupsp
, long int limit
,
244 /* We always need the domain name. */
246 if (yp_get_default_domain (&domainname
))
247 return NSS_STATUS_UNAVAIL
;
249 /* Check whether we are supposed to use the netid.byname map. */
250 if (_nis_default_nss () & NSS_FLAG_NETID_AUTHORITATIVE
)
252 /* We need the user ID. */
255 if (get_uid (user
, &uid
) == 0
256 && initgroups_netid (uid
, group
, start
, size
, groupsp
, limit
,
257 errnop
, domainname
) == NSS_STATUS_SUCCESS
)
258 return NSS_STATUS_SUCCESS
;
261 struct group grpbuf
, *g
;
262 size_t buflen
= sysconf (_SC_GETPW_R_SIZE_MAX
);
264 enum nss_status status
;
265 intern_t intern
= { NULL
, NULL
};
266 gid_t
*groups
= *groupsp
;
268 status
= internal_setgrent (domainname
, &intern
);
269 if (status
!= NSS_STATUS_SUCCESS
)
272 tmpbuf
= __alloca (buflen
);
277 internal_getgrent_r (&grpbuf
, tmpbuf
, buflen
, errnop
,
278 &intern
)) == NSS_STATUS_TRYAGAIN
279 && *errnop
== ERANGE
)
280 tmpbuf
= extend_alloca (tmpbuf
, buflen
, 2 * buflen
);
282 if (status
!= NSS_STATUS_SUCCESS
)
287 if (g
->gr_gid
!= group
)
291 for (m
= g
->gr_mem
; *m
!= NULL
; ++m
)
292 if (strcmp (*m
, user
) == 0)
294 /* Matches user. Insert this group. */
297 /* Need a bigger buffer. */
301 if (limit
> 0 && *size
== limit
)
302 /* We reached the maximum. */
308 newsize
= MIN (limit
, 2 * *size
);
310 newgroups
= realloc (groups
, newsize
* sizeof (*groups
));
311 if (newgroups
== NULL
)
313 *groupsp
= groups
= newgroups
;
317 groups
[*start
] = g
->gr_gid
;
324 while (status
== NSS_STATUS_SUCCESS
);
327 while (intern
.start
!= NULL
)
329 intern
.next
= intern
.start
;
330 intern
.start
= intern
.start
->next
;
334 return NSS_STATUS_SUCCESS
;