1 /**
2 * Copyright 2011 Google Inc. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * Author: Nikki VonHollen <vonhollen@gmail.com>
17 */
18
19 #include <grp.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/types.h>
25
26 #define GROUP_CONFIG_KEY "MOCK_GROUP"
27
28 static FILE *global_stream = NULL;
29
setgrent(void)30 void setgrent(void) {
31 if (global_stream)
32 endgrent();
33
34 const char *path = getenv(GROUP_CONFIG_KEY);
35 if (!path)
36 return;
37
38 global_stream = fopen(path, "r");
39 }
40
getgrent(void)41 struct group *getgrent(void) {
42 if (!global_stream)
43 setgrent();
44
45 if (!global_stream)
46 return NULL;
47
48 return fgetgrent(global_stream);
49 }
50
endgrent(void)51 void endgrent(void) {
52 if (!global_stream)
53 return;
54
55 fclose(global_stream);
56 global_stream = NULL;
57 }
58
getgrnam(const char * name)59 struct group *getgrnam(const char *name) {
60 const char *path = getenv(GROUP_CONFIG_KEY);
61 if (!path)
62 return NULL;
63
64 FILE *stream = fopen(path, "r");
65 if (!stream)
66 return NULL;
67
68 struct group *entry;
69 while ((entry = fgetgrent(stream))) {
70 if (strcmp(entry->gr_name, name) == 0) {
71 fclose(stream);
72 return entry;
73 }
74 }
75
76 fclose(stream);
77 return NULL;
78 }
79
getgrgid(gid_t gid)80 struct group *getgrgid(gid_t gid) {
81 const char *path = getenv(GROUP_CONFIG_KEY);
82 if (!path)
83 return NULL;
84
85 FILE *stream = fopen(path, "r");
86 if (!stream)
87 return NULL;
88
89 struct group *entry;
90 while ((entry = fgetgrent(stream))) {
91 if (entry->gr_gid == gid) {
92 fclose(stream);
93 return entry;
94 }
95 }
96
97 fclose(stream);
98 return NULL;
99 }
100
getgrouplist(const char * user,gid_t group,gid_t * groups,int * ngroups)101 int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups) {
102 const char *path = getenv(GROUP_CONFIG_KEY);
103 if (!path) {
104 *ngroups = 0;
105 return -1;
106 }
107
108 FILE *stream = fopen(path, "r");
109 if (!stream) {
110 *ngroups = 0;
111 return -1;
112 }
113
114 int default_group_found = 0;
115 int groups_found = 0;
116
117 // Loop through all groups
118 struct group *entry;
119 while ((entry = fgetgrent(stream))) {
120 // Loop through all users in group
121 char **cur_user;
122 for (cur_user = entry->gr_mem; *cur_user; cur_user++) {
123 // Skip users who don't match arg 'user'
124 if (strcmp(*cur_user, user))
125 continue;
126
127 // Is this the default group? if so, flag it
128 if (entry->gr_gid == group)
129 default_group_found = 1;
130
131 // Only insert new entries if we have room
132 if (groups_found < *ngroups) {
133 groups[groups_found] = entry->gr_gid;
134 }
135
136 groups_found++;
137 }
138 }
139
140 // Include the default group if it wasn't found
141 if (!default_group_found) {
142 if (groups_found < *ngroups) {
143 groups[groups_found] = group;
144 }
145 groups_found++;
146 }
147
148 // Did we have to leave out some groups? If not, tell how many we found.
149 int retval = (groups_found > *ngroups) ? -1 : groups_found;
150
151 // Always tell the user how many groups we found via *ngroups
152 *ngroups = groups_found;
153
154 fclose(stream);
155 return retval;
156 }
157