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