Annotation of embedaddon/sudo/plugins/sudoers/pwutil_impl.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (c) 1996, 1998-2005, 2007-2013
3: * Todd C. Miller <Todd.Miller@courtesan.com>
4: *
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.
8: *
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.
16: *
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.
20: */
21:
22: #include <config.h>
23:
24: #include <sys/types.h>
25: #include <stdio.h>
26: #ifdef STDC_HEADERS
27: # include <stdlib.h>
28: # include <stddef.h>
29: #else
30: # ifdef HAVE_STDLIB_H
31: # include <stdlib.h>
32: # endif
33: #endif /* STDC_HEADERS */
34: #ifdef HAVE_STRING_H
35: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
36: # include <memory.h>
37: # endif
38: # include <string.h>
39: #endif /* HAVE_STRING_H */
40: #ifdef HAVE_STRINGS_H
41: # include <strings.h>
42: #endif /* HAVE_STRINGS_H */
43: #ifdef HAVE_UNISTD_H
44: # include <unistd.h>
45: #endif /* HAVE_UNISTD_H */
46: #include <limits.h>
47: #include <pwd.h>
48: #include <grp.h>
49:
50: #include "sudoers.h"
51: #include "pwutil.h"
52:
53: #ifndef LOGIN_NAME_MAX
54: # ifdef _POSIX_LOGIN_NAME_MAX
55: # define LOGIN_NAME_MAX _POSIX_LOGIN_NAME_MAX
56: # else
57: # define LOGIN_NAME_MAX 9
58: # endif
59: #endif /* LOGIN_NAME_MAX */
60:
61: #define FIELD_SIZE(src, name, size) \
62: do { \
63: if (src->name) { \
64: size = strlen(src->name) + 1; \
65: total += size; \
66: } \
67: } while (0)
68:
69: #define FIELD_COPY(src, dst, name, size) \
70: do { \
71: if (src->name) { \
72: memcpy(cp, src->name, size); \
73: dst->name = cp; \
74: cp += size; \
75: } \
76: } while (0)
77:
78: /*
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.
82: */
83: struct cache_item *
84: sudo_make_pwitem(uid_t uid, const char *name)
85: {
86: char *cp;
87: const char *pw_shell;
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)
92:
93: /* Look up by name or uid. */
94: pw = name ? getpwnam(name) : getpwuid(uid);
95: if (pw == NULL)
96: debug_return_ptr(NULL);
97:
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;
101:
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);
109: #endif
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;
114: total += ssize;
115: if (name != NULL)
116: total += strlen(name) + 1;
117:
118: /* Allocate space for struct item, struct passwd and the strings. */
119: pwitem = ecalloc(1, total);
120: newpw = &pwitem->pw;
121:
122: /*
123: * Copy in passwd contents and make strings relative to space
124: * at the end of the struct.
125: */
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);
132: #endif
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;
138: cp += ssize;
139:
140: /* Set key and datum. */
141: if (name != NULL) {
142: memcpy(cp, name, strlen(name) + 1);
143: pwitem->cache.k.name = cp;
144: } else {
145: pwitem->cache.k.uid = pw->pw_uid;
146: }
147: pwitem->cache.d.pw = newpw;
148: pwitem->cache.refcnt = 1;
149:
150: debug_return_ptr(&pwitem->cache);
151: }
152:
153: /*
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.
157: */
158: struct cache_item *
159: sudo_make_gritem(gid_t gid, const char *name)
160: {
161: char *cp;
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)
166:
167: /* Look up by name or gid. */
168: gr = name ? getgrnam(name) : getgrgid(gid);
169: if (gr == NULL)
170: debug_return_ptr(NULL);
171:
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);
177: if (gr->gr_mem) {
178: for (nmem = 0; gr->gr_mem[nmem] != NULL; nmem++)
179: total += strlen(gr->gr_mem[nmem]) + 1;
180: nmem++;
181: total += sizeof(char *) * nmem;
182: }
183: if (name != NULL)
184: total += strlen(name) + 1;
185:
186: gritem = ecalloc(1, total);
187:
188: /*
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.
192: */
193: newgr = &gritem->gr;
194: memcpy(newgr, gr, sizeof(*gr));
195: cp = (char *)(gritem + 1);
196: if (gr->gr_mem) {
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;
203: cp += len;
204: }
205: newgr->gr_mem[nmem] = NULL;
206: }
207: FIELD_COPY(gr, newgr, gr_passwd, psize);
208: FIELD_COPY(gr, newgr, gr_name, nsize);
209:
210: /* Set key and datum. */
211: if (name != NULL) {
212: memcpy(cp, name, strlen(name) + 1);
213: gritem->cache.k.name = cp;
214: } else {
215: gritem->cache.k.gid = gr->gr_gid;
216: }
217: gritem->cache.d.gr = newgr;
218: gritem->cache.refcnt = 1;
219:
220: debug_return_ptr(&gritem->cache);
221: }
222:
223: /*
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).
226: */
227: struct cache_item *
228: sudo_make_grlist_item(struct passwd *pw, char * const *unused1,
229: char * const *unused2)
230: {
231: char *cp;
232: size_t i, nsize, ngroups, total, len;
233: struct cache_item_grlist *grlitem;
234: struct group_list *grlist;
235: GETGROUPS_T *gids;
236: struct group *grp;
237: int ngids, groupname_len;
238: debug_decl(sudo_make_grlist_item, SUDO_DEBUG_NSS)
239:
240: if (pw == sudo_user.pw && sudo_user.gids != NULL) {
241: gids = user_gids;
242: ngids = user_ngids;
243: user_gids = NULL;
244: user_ngids = 0;
245: } else {
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);
250: } else {
251: #if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX)
252: ngids = (int)sysconf(_SC_NGROUPS_MAX) * 2;
253: if (ngids < 0)
254: #endif
255: ngids = NGROUPS_MAX * 2;
256: gids = emalloc2(ngids, sizeof(GETGROUPS_T));
257: if (getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids) == -1) {
258: efree(gids);
259: gids = emalloc2(ngids, sizeof(GETGROUPS_T));
260: if (getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids) == -1)
261: ngids = -1;
262: }
263: }
264: }
265: if (ngids <= 0) {
266: efree(gids);
267: debug_return_ptr(NULL);
268: }
269:
270: #ifdef HAVE_SETAUTHDB
271: aix_setauthdb((char *) pw->pw_name);
272: #endif
273:
274: #if defined(HAVE_SYSCONF) && defined(_SC_LOGIN_NAME_MAX)
275: groupname_len = MAX((int)sysconf(_SC_LOGIN_NAME_MAX), 32);
276: #else
277: groupname_len = MAX(LOGIN_NAME_MAX, 32);
278: #endif
279:
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;
286:
287: again:
288: grlitem = ecalloc(1, total);
289:
290: /*
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.
294: */
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;
301:
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;
307: cp += nsize;
308:
309: /*
310: * Store group IDs.
311: */
312: for (i = 0; i < ngids; i++)
313: grlist->gids[i] = gids[i];
314: grlist->ngids = ngids;
315:
316: /*
317: * Resolve and store group names by ID.
318: */
319: ngroups = 0;
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;
325: efree(grlitem);
326: sudo_gr_delref(grp);
327: goto again;
328: }
329: memcpy(cp, grp->gr_name, len);
330: grlist->groups[ngroups++] = cp;
331: cp += len;
332: sudo_gr_delref(grp);
333: }
334: }
335: grlist->ngroups = ngroups;
336: efree(gids);
337:
338: #ifdef HAVE_SETAUTHDB
339: aix_restoreauthdb();
340: #endif
341:
342: debug_return_ptr(&grlitem->cache);
343: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>