2 * Copyright (c) 1996, 1998-2005, 2007-2013
3 * Todd C. Miller <Todd.Miller@courtesan.com>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 * Sponsored in part by the Defense Advanced Research Projects
18 * Agency (DARPA) and Air Force Research Laboratory, Air Force
19 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
24 #include <sys/types.h>
33 #endif /* STDC_HEADERS */
35 # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
39 #endif /* HAVE_STRING_H */
42 #endif /* HAVE_STRINGS_H */
45 #endif /* HAVE_UNISTD_H */
53 #ifndef LOGIN_NAME_MAX
54 # ifdef _POSIX_LOGIN_NAME_MAX
55 # define LOGIN_NAME_MAX _POSIX_LOGIN_NAME_MAX
57 # define LOGIN_NAME_MAX 9
59 #endif /* LOGIN_NAME_MAX */
61 #define FIELD_SIZE(src, name, size) \
64 size = strlen(src->name) + 1; \
69 #define FIELD_COPY(src, dst, name, size) \
72 memcpy(cp, src->name, size); \
79 * Dynamically allocate space for a struct item plus the key and data
80 * elements. If name is non-NULL it is used as the key, else the
81 * uid is the key. Fills in datum from struct password.
84 sudo_make_pwitem(uid_t uid, const char *name)
88 size_t nsize, psize, csize, gsize, dsize, ssize, total;
89 struct cache_item_pw *pwitem;
90 struct passwd *pw, *newpw;
91 debug_decl(sudo_make_pwitem, SUDO_DEBUG_NSS)
93 /* Look up by name or uid. */
94 pw = name ? getpwnam(name) : getpwuid(uid);
96 debug_return_ptr(NULL);
98 /* If shell field is empty, expand to _PATH_BSHELL. */
99 pw_shell = (pw->pw_shell == NULL || pw->pw_shell[0] == '\0')
100 ? _PATH_BSHELL : pw->pw_shell;
102 /* Allocate in one big chunk for easy freeing. */
103 nsize = psize = csize = gsize = dsize = ssize = 0;
104 total = sizeof(*pwitem);
105 FIELD_SIZE(pw, pw_name, nsize);
106 FIELD_SIZE(pw, pw_passwd, psize);
107 #ifdef HAVE_LOGIN_CAP_H
108 FIELD_SIZE(pw, pw_class, csize);
110 FIELD_SIZE(pw, pw_gecos, gsize);
111 FIELD_SIZE(pw, pw_dir, dsize);
112 /* Treat shell specially since we expand "" -> _PATH_BSHELL */
113 ssize = strlen(pw_shell) + 1;
116 total += strlen(name) + 1;
118 /* Allocate space for struct item, struct passwd and the strings. */
119 pwitem = ecalloc(1, total);
123 * Copy in passwd contents and make strings relative to space
124 * at the end of the struct.
126 memcpy(newpw, pw, sizeof(*pw));
127 cp = (char *)(pwitem + 1);
128 FIELD_COPY(pw, newpw, pw_name, nsize);
129 FIELD_COPY(pw, newpw, pw_passwd, psize);
130 #ifdef HAVE_LOGIN_CAP_H
131 FIELD_COPY(pw, newpw, pw_class, csize);
133 FIELD_COPY(pw, newpw, pw_gecos, gsize);
134 FIELD_COPY(pw, newpw, pw_dir, dsize);
135 /* Treat shell specially since we expand "" -> _PATH_BSHELL */
136 memcpy(cp, pw_shell, ssize);
137 newpw->pw_shell = cp;
140 /* Set key and datum. */
142 memcpy(cp, name, strlen(name) + 1);
143 pwitem->cache.k.name = cp;
145 pwitem->cache.k.uid = pw->pw_uid;
147 pwitem->cache.d.pw = newpw;
148 pwitem->cache.refcnt = 1;
150 debug_return_ptr(&pwitem->cache);
154 * Dynamically allocate space for a struct item plus the key and data
155 * elements. If name is non-NULL it is used as the key, else the
156 * gid is the key. Fills in datum from struct group.
159 sudo_make_gritem(gid_t gid, const char *name)
162 size_t nsize, psize, nmem, total, len;
163 struct cache_item_gr *gritem;
164 struct group *gr, *newgr;
165 debug_decl(sudo_make_gritem, SUDO_DEBUG_NSS)
167 /* Look up by name or gid. */
168 gr = name ? getgrnam(name) : getgrgid(gid);
170 debug_return_ptr(NULL);
172 /* Allocate in one big chunk for easy freeing. */
173 nsize = psize = nmem = 0;
174 total = sizeof(*gritem);
175 FIELD_SIZE(gr, gr_name, nsize);
176 FIELD_SIZE(gr, gr_passwd, psize);
178 for (nmem = 0; gr->gr_mem[nmem] != NULL; nmem++)
179 total += strlen(gr->gr_mem[nmem]) + 1;
181 total += sizeof(char *) * nmem;
184 total += strlen(name) + 1;
186 gritem = ecalloc(1, total);
189 * Copy in group contents and make strings relative to space
190 * at the end of the buffer. Note that gr_mem must come
191 * immediately after struct group to guarantee proper alignment.
194 memcpy(newgr, gr, sizeof(*gr));
195 cp = (char *)(gritem + 1);
197 newgr->gr_mem = (char **)cp;
198 cp += sizeof(char *) * nmem;
199 for (nmem = 0; gr->gr_mem[nmem] != NULL; nmem++) {
200 len = strlen(gr->gr_mem[nmem]) + 1;
201 memcpy(cp, gr->gr_mem[nmem], len);
202 newgr->gr_mem[nmem] = cp;
205 newgr->gr_mem[nmem] = NULL;
207 FIELD_COPY(gr, newgr, gr_passwd, psize);
208 FIELD_COPY(gr, newgr, gr_name, nsize);
210 /* Set key and datum. */
212 memcpy(cp, name, strlen(name) + 1);
213 gritem->cache.k.name = cp;
215 gritem->cache.k.gid = gr->gr_gid;
217 gritem->cache.d.gr = newgr;
218 gritem->cache.refcnt = 1;
220 debug_return_ptr(&gritem->cache);
224 * Dynamically allocate space for a struct item plus the key and data
225 * elements. Fills in datum from user_gids or from getgrouplist(3).
228 sudo_make_grlist_item(struct passwd *pw, char * const *unused1,
229 char * const *unused2)
232 size_t i, nsize, ngroups, total, len;
233 struct cache_item_grlist *grlitem;
234 struct group_list *grlist;
237 int ngids, groupname_len;
238 debug_decl(sudo_make_grlist_item, SUDO_DEBUG_NSS)
240 if (pw == sudo_user.pw && sudo_user.gids != NULL) {
246 if (sudo_user.max_groups != -1) {
247 ngids = sudo_user.max_groups;
248 gids = emalloc2(ngids, sizeof(GETGROUPS_T));
249 (void)getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids);
251 #if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX)
252 ngids = (int)sysconf(_SC_NGROUPS_MAX) * 2;
255 ngids = NGROUPS_MAX * 2;
256 gids = emalloc2(ngids, sizeof(GETGROUPS_T));
257 if (getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids) == -1) {
259 gids = emalloc2(ngids, sizeof(GETGROUPS_T));
260 if (getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids) == -1)
267 debug_return_ptr(NULL);
270 #ifdef HAVE_SETAUTHDB
271 aix_setauthdb((char *) pw->pw_name);
274 #if defined(HAVE_SYSCONF) && defined(_SC_LOGIN_NAME_MAX)
275 groupname_len = MAX((int)sysconf(_SC_LOGIN_NAME_MAX), 32);
277 groupname_len = MAX(LOGIN_NAME_MAX, 32);
280 /* Allocate in one big chunk for easy freeing. */
281 nsize = strlen(pw->pw_name) + 1;
282 total = sizeof(*grlitem) + nsize;
283 total += sizeof(char *) * ngids;
284 total += sizeof(gid_t *) * ngids;
285 total += groupname_len * ngids;
288 grlitem = ecalloc(1, total);
291 * Copy in group list and make pointers relative to space
292 * at the end of the buffer. Note that the groups array must come
293 * immediately after struct group to guarantee proper alignment.
295 grlist = &grlitem->grlist;
296 cp = (char *)(grlitem + 1);
297 grlist->groups = (char **)cp;
298 cp += sizeof(char *) * ngids;
299 grlist->gids = (gid_t *)cp;
300 cp += sizeof(gid_t) * ngids;
302 /* Set key and datum. */
303 memcpy(cp, pw->pw_name, nsize);
304 grlitem->cache.k.name = cp;
305 grlitem->cache.d.grlist = grlist;
306 grlitem->cache.refcnt = 1;
312 for (i = 0; i < ngids; i++)
313 grlist->gids[i] = gids[i];
314 grlist->ngids = ngids;
317 * Resolve and store group names by ID.
320 for (i = 0; i < ngids; i++) {
321 if ((grp = sudo_getgrgid(gids[i])) != NULL) {
322 len = strlen(grp->gr_name) + 1;
323 if (cp - (char *)grlitem + len > total) {
324 total += len + groupname_len;
329 memcpy(cp, grp->gr_name, len);
330 grlist->groups[ngroups++] = cp;
335 grlist->ngroups = ngroups;
338 #ifdef HAVE_SETAUTHDB
342 debug_return_ptr(&grlitem->cache);