headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / libroot / posix / grp.cpp
blobf04f5891e2ff6e7163acc31af42c42ad08e4f221
1 /*
2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
6 #include <grp.h>
8 #include <errno.h>
9 #include <string.h>
10 #include <unistd.h>
12 #include <new>
14 #include <OS.h>
16 #include <errno_private.h>
17 #include <libroot_private.h>
18 #include <RegistrarDefs.h>
19 #include <user_group.h>
21 #include <util/KMessage.h>
24 using BPrivate::UserGroupLocker;
25 using BPrivate::relocate_pointer;
28 static KMessage sGroupDBReply;
29 static group** sGroupEntries = NULL;
30 static size_t sGroupEntryCount = 0;
31 static size_t sIterationIndex = 0;
33 static struct group sGroupBuffer;
34 static char sGroupStringBuffer[MAX_GROUP_BUFFER_SIZE];
37 static status_t
38 query_group_entry(const char* name, gid_t _gid, struct group *group,
39 char *buffer, size_t bufferSize, struct group **_result)
41 *_result = NULL;
43 KMessage message(BPrivate::B_REG_GET_GROUP);
44 if (name)
45 message.AddString("name", name);
46 else
47 message.AddInt32("gid", _gid);
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;
56 int32 gid;
57 const char* password;
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;
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++;
73 error = BPrivate::copy_group_to_buffer(name, password, gid, members,
74 memberCount, group, buffer, bufferSize);
75 if (error == B_OK)
76 *_result = group;
78 return error;
82 static status_t
83 init_group_db()
85 if (sGroupEntries != NULL)
86 return B_OK;
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;
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;
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;
118 sGroupEntries = entries;
119 sGroupEntryCount = count;
121 return B_OK;
125 // #pragma mark -
128 struct group*
129 getgrent(void)
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;
141 getgrent_r(struct group* group, char* buffer, size_t bufferSize,
142 struct group** _result)
144 UserGroupLocker _;
146 int status = B_NO_MEMORY;
148 *_result = NULL;
150 if ((status = init_group_db()) == B_OK) {
151 if (sIterationIndex >= sGroupEntryCount)
152 return ENOENT;
154 status = BPrivate::copy_group_to_buffer(
155 sGroupEntries[sIterationIndex], group, buffer, bufferSize);
157 if (status == B_OK) {
158 sIterationIndex++;
159 *_result = group;
163 return status;
167 void
168 setgrent(void)
170 UserGroupLocker _;
172 sIterationIndex = 0;
176 void
177 endgrent(void)
179 UserGroupLocker locker;
181 sGroupDBReply.Unset();
182 sGroupEntries = NULL;
183 sGroupEntryCount = 0;
184 sIterationIndex = 0;
188 struct group *
189 getgrnam(const char *name)
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;
201 getgrnam_r(const char *name, struct group *group, char *buffer,
202 size_t bufferSize, struct group **_result)
204 return query_group_entry(name, 0, group, buffer, bufferSize, _result);
208 struct group *
209 getgrgid(gid_t gid)
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;
221 getgrgid_r(gid_t gid, struct group *group, char *buffer,
222 size_t bufferSize, struct group **_result)
224 return query_group_entry(NULL, gid, group, buffer, bufferSize, _result);
229 getgrouplist(const char* user, gid_t baseGroup, gid_t* groupList,
230 int* groupCount)
232 int maxGroupCount = *groupCount;
233 *groupCount = 0;
235 status_t error = B_OK;
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;
244 // send request
245 KMessage reply;
246 error = BPrivate::send_authentication_request_to_registrar(message, reply);
247 if (error != B_OK)
248 return -1;
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;
260 memcpy(groupList, groups, groupsSize);
261 *groupCount = count;
263 // add the base group
264 if (*groupCount < maxGroupCount)
265 groupList[*groupCount] = baseGroup;
266 ++*groupCount;
268 return *groupCount <= maxGroupCount ? *groupCount : -1;
273 initgroups(const char* user, gid_t baseGroup)
275 gid_t groups[NGROUPS_MAX + 1];
276 int groupCount = NGROUPS_MAX + 1;
277 if (getgrouplist(user, baseGroup, groups, &groupCount) < 0)
278 return -1;
280 return setgroups(groupCount, groups);