1 /*
2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6 #include <grp.h>
7
8 #include <errno.h>
9 #include <string.h>
10 #include <unistd.h>
11
12 #include <new>
13
14 #include <OS.h>
15
16 #include <errno_private.h>
17 #include <libroot_private.h>
18 #include <RegistrarDefs.h>
19 #include <user_group.h>
20
21 #include <util/KMessage.h>
22
23
24 using BPrivate::UserGroupLocker;
25 using BPrivate::relocate_pointer;
26
27
28 static KMessage sGroupDBReply;
29 static group** sGroupEntries = NULL;
30 static size_t sGroupEntryCount = 0;
31 static size_t sIterationIndex = 0;
32
33 static struct group sGroupBuffer;
34 static char sGroupStringBuffer[MAX_GROUP_BUFFER_SIZE];
35
36
37 static status_t
query_group_entry(const char * name,gid_t _gid,struct group * group,char * buffer,size_t bufferSize,struct group ** _result)38 query_group_entry(const char* name, gid_t _gid, struct group *group,
39 char *buffer, size_t bufferSize, struct group **_result)
40 {
41 *_result = NULL;
42
43 KMessage message(BPrivate::B_REG_GET_GROUP);
44 if (name)
45 message.AddString("name", name);
46 else
47 message.AddInt32("gid", _gid);
48
49 KMessage reply;
50 status_t error = BPrivate::send_authentication_request_to_registrar(message,
51 reply);
52 if (error != B_OK) {
53 return error == ENOENT ? B_OK : error;
54 }
55
56 int32 gid;
57 const char* password;
58
59 if ((error = reply.FindInt32("gid", &gid)) != B_OK
60 || (error = reply.FindString("name", &name)) != B_OK
61 || (error = reply.FindString("password", &password)) != B_OK) {
62 return error;
63 }
64
65 const char* members[MAX_GROUP_MEMBER_COUNT];
66 int memberCount = 0;
67 for (int32 index = 0; memberCount < MAX_GROUP_MEMBER_COUNT; index++) {
68 if (reply.FindString("members", index, members + memberCount) != B_OK)
69 break;
70 memberCount++;
71 }
72
73 error = BPrivate::copy_group_to_buffer(name, password, gid, members,
74 memberCount, group, buffer, bufferSize);
75 if (error == B_OK)
76 *_result = group;
77
78 return error;
79 }
80
81
82 static status_t
init_group_db()83 init_group_db()
84 {
85 if (sGroupEntries != NULL)
86 return B_OK;
87
88 // ask the registrar
89 KMessage message(BPrivate::B_REG_GET_GROUP_DB);
90 status_t error = BPrivate::send_authentication_request_to_registrar(message,
91 sGroupDBReply);
92 if (error != B_OK)
93 return error;
94
95 // unpack the reply
96 int32 count;
97 group** entries;
98 int32 numBytes;
99 if ((error = sGroupDBReply.FindInt32("count", &count)) != B_OK
100 || (error = sGroupDBReply.FindData("entries", B_RAW_TYPE,
101 (const void**)&entries, &numBytes)) != B_OK) {
102 return error;
103 }
104
105 // relocate the entries
106 addr_t baseAddress = (addr_t)entries;
107 for (int32 i = 0; i < count; i++) {
108 group* entry = relocate_pointer(baseAddress, entries[i]);
109 relocate_pointer(baseAddress, entry->gr_name);
110 relocate_pointer(baseAddress, entry->gr_passwd);
111 relocate_pointer(baseAddress, entry->gr_mem);
112 int32 k = 0;
113 for (; entry->gr_mem[k] != (void*)-1; k++)
114 relocate_pointer(baseAddress, entry->gr_mem[k]);
115 entry->gr_mem[k] = NULL;
116 }
117
118 sGroupEntries = entries;
119 sGroupEntryCount = count;
120
121 return B_OK;
122 }
123
124
125 // #pragma mark -
126
127
128 struct group*
getgrent(void)129 getgrent(void)
130 {
131 struct group* result = NULL;
132 int status = getgrent_r(&sGroupBuffer, sGroupStringBuffer,
133 sizeof(sGroupStringBuffer), &result);
134 if (status != 0)
135 __set_errno(status);
136 return result;
137 }
138
139
140 int
getgrent_r(struct group * group,char * buffer,size_t bufferSize,struct group ** _result)141 getgrent_r(struct group* group, char* buffer, size_t bufferSize,
142 struct group** _result)
143 {
144 UserGroupLocker _;
145
146 int status = B_NO_MEMORY;
147
148 *_result = NULL;
149
150 if ((status = init_group_db()) == B_OK) {
151 if (sIterationIndex >= sGroupEntryCount)
152 return ENOENT;
153
154 status = BPrivate::copy_group_to_buffer(
155 sGroupEntries[sIterationIndex], group, buffer, bufferSize);
156
157 if (status == B_OK) {
158 sIterationIndex++;
159 *_result = group;
160 }
161 }
162
163 return status;
164 }
165
166
167 void
setgrent(void)168 setgrent(void)
169 {
170 UserGroupLocker _;
171
172 sIterationIndex = 0;
173 }
174
175
176 void
endgrent(void)177 endgrent(void)
178 {
179 UserGroupLocker locker;
180
181 sGroupDBReply.Unset();
182 sGroupEntries = NULL;
183 sGroupEntryCount = 0;
184 sIterationIndex = 0;
185 }
186
187
188 struct group *
getgrnam(const char * name)189 getgrnam(const char *name)
190 {
191 struct group* result = NULL;
192 int status = getgrnam_r(name, &sGroupBuffer, sGroupStringBuffer,
193 sizeof(sGroupStringBuffer), &result);
194 if (status != 0)
195 __set_errno(status);
196 return result;
197 }
198
199
200 int
getgrnam_r(const char * name,struct group * group,char * buffer,size_t bufferSize,struct group ** _result)201 getgrnam_r(const char *name, struct group *group, char *buffer,
202 size_t bufferSize, struct group **_result)
203 {
204 return query_group_entry(name, 0, group, buffer, bufferSize, _result);
205 }
206
207
208 struct group *
getgrgid(gid_t gid)209 getgrgid(gid_t gid)
210 {
211 struct group* result = NULL;
212 int status = getgrgid_r(gid, &sGroupBuffer, sGroupStringBuffer,
213 sizeof(sGroupStringBuffer), &result);
214 if (status != 0)
215 __set_errno(status);
216 return result;
217 }
218
219
220 int
getgrgid_r(gid_t gid,struct group * group,char * buffer,size_t bufferSize,struct group ** _result)221 getgrgid_r(gid_t gid, struct group *group, char *buffer,
222 size_t bufferSize, struct group **_result)
223 {
224 return query_group_entry(NULL, gid, group, buffer, bufferSize, _result);
225 }
226
227
228 int
getgrouplist(const char * user,gid_t baseGroup,gid_t * groupList,int * groupCount)229 getgrouplist(const char* user, gid_t baseGroup, gid_t* groupList,
230 int* groupCount)
231 {
232 int maxGroupCount = *groupCount;
233 *groupCount = 0;
234
235 status_t error = B_OK;
236
237 // prepare request
238 KMessage message(BPrivate::B_REG_GET_USER_GROUPS);
239 if (message.AddString("name", user) != B_OK
240 || message.AddInt32("max count", maxGroupCount) != B_OK) {
241 return -1;
242 }
243
244 // send request
245 KMessage reply;
246 error = BPrivate::send_authentication_request_to_registrar(message, reply);
247 if (error != B_OK)
248 return -1;
249
250 // unpack reply
251 int32 count;
252 const int32* groups;
253 int32 groupsSize;
254 if (reply.FindInt32("count", &count) != B_OK
255 || reply.FindData("groups", B_INT32_TYPE, (const void**)&groups,
256 &groupsSize) != B_OK) {
257 return -1;
258 }
259
260 memcpy(groupList, groups, groupsSize);
261 *groupCount = count;
262
263 // add the base group
264 if (*groupCount < maxGroupCount)
265 groupList[*groupCount] = baseGroup;
266 ++*groupCount;
267
268 return *groupCount <= maxGroupCount ? *groupCount : -1;
269 }
270
271
272 int
initgroups(const char * user,gid_t baseGroup)273 initgroups(const char* user, gid_t baseGroup)
274 {
275 gid_t groups[NGROUPS_MAX + 1];
276 int groupCount = NGROUPS_MAX + 1;
277 if (getgrouplist(user, baseGroup, groups, &groupCount) < 0)
278 return -1;
279
280 return setgroups(groupCount, groups);
281 }
282