Commit | Line | Data |
---|---|---|
73dcdb9f PE |
1 | /* group-member.c -- determine whether group id is in calling user's group list |
2 | ||
9ff99d22 | 3 | Copyright (C) 1994, 1997-1998, 2003, 2005-2006, 2009-2013 Free Software |
73dcdb9f PE |
4 | Foundation, Inc. |
5 | ||
6 | This program is free software: you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 3 of the License, or | |
9 | (at your option) any later version. | |
10 | ||
11 | This program is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
18 | ||
19 | #include <config.h> | |
20 | ||
21 | /* Specification. */ | |
22 | #include <unistd.h> | |
23 | ||
24 | #include <stdio.h> | |
25 | #include <sys/types.h> | |
26 | #include <stdlib.h> | |
27 | ||
28 | #include "xalloc-oversized.h" | |
29 | ||
30 | /* Most processes have no more than this many groups, and for these | |
31 | processes we can avoid using malloc. */ | |
32 | enum { GROUPBUF_SIZE = 100 }; | |
33 | ||
34 | struct group_info | |
35 | { | |
36 | gid_t *group; | |
37 | gid_t groupbuf[GROUPBUF_SIZE]; | |
38 | }; | |
39 | ||
40 | static void | |
41 | free_group_info (struct group_info const *g) | |
42 | { | |
43 | if (g->group != g->groupbuf) | |
44 | free (g->group); | |
45 | } | |
46 | ||
47 | static int | |
48 | get_group_info (struct group_info *gi) | |
49 | { | |
50 | int n_groups = getgroups (GROUPBUF_SIZE, gi->groupbuf); | |
51 | gi->group = gi->groupbuf; | |
52 | ||
53 | if (n_groups < 0) | |
54 | { | |
55 | int n_group_slots = getgroups (0, NULL); | |
56 | if (0 <= n_group_slots | |
57 | && ! xalloc_oversized (n_group_slots, sizeof *gi->group)) | |
58 | { | |
59 | gi->group = malloc (n_group_slots * sizeof *gi->group); | |
60 | if (gi->group) | |
61 | n_groups = getgroups (n_group_slots, gi->group); | |
62 | } | |
63 | } | |
64 | ||
65 | /* In case of error, the user loses. */ | |
66 | return n_groups; | |
67 | } | |
68 | ||
69 | /* Return non-zero if GID is one that we have in our groups list. | |
70 | Note that the groups list is not guaranteed to contain the current | |
71 | or effective group ID, so they should generally be checked | |
72 | separately. */ | |
73 | ||
74 | int | |
75 | group_member (gid_t gid) | |
76 | { | |
77 | int i; | |
78 | int found; | |
79 | struct group_info gi; | |
80 | int n_groups = get_group_info (&gi); | |
81 | ||
82 | /* Search through the list looking for GID. */ | |
83 | found = 0; | |
84 | for (i = 0; i < n_groups; i++) | |
85 | { | |
86 | if (gid == gi.group[i]) | |
87 | { | |
88 | found = 1; | |
89 | break; | |
90 | } | |
91 | } | |
92 | ||
93 | free_group_info (&gi); | |
94 | ||
95 | return found; | |
96 | } | |
97 | ||
98 | #ifdef TEST | |
99 | ||
100 | char *program_name; | |
101 | ||
102 | int | |
103 | main (int argc, char **argv) | |
104 | { | |
105 | int i; | |
106 | ||
107 | program_name = argv[0]; | |
108 | ||
109 | for (i = 1; i < argc; i++) | |
110 | { | |
111 | gid_t gid; | |
112 | ||
113 | gid = atoi (argv[i]); | |
114 | printf ("%d: %s\n", gid, group_member (gid) ? "yes" : "no"); | |
115 | } | |
116 | exit (0); | |
117 | } | |
118 | ||
119 | #endif /* TEST */ |