xref: /haiku/src/system/libroot/posix/grp.cpp (revision 204dee708a999d5a71d0cb9497650ee7cef85d0a)
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
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;
54 
55 	int32 gid;
56 	const char* password;
57 
58 	if ((error = reply.FindInt32("gid", &gid)) != B_OK
59 		|| (error = reply.FindString("name", &name)) != B_OK
60 		|| (error = reply.FindString("password", &password)) != B_OK) {
61 		return error;
62 	}
63 
64 	const char* members[MAX_GROUP_MEMBER_COUNT];
65 	int memberCount = 0;
66 	for (int memberCount = 0; memberCount < MAX_GROUP_MEMBER_COUNT;) {
67 		if (reply.FindString("members", members + memberCount) != B_OK)
68 			break;
69 		memberCount++;
70 	}
71 
72 	error = BPrivate::copy_group_to_buffer(name, password, gid, members,
73 		memberCount, group, buffer, bufferSize);
74 	if (error == B_OK)
75 		*_result = group;
76 
77 	return error;
78 }
79 
80 
81 static status_t
82 init_group_db()
83 {
84 	if (sGroupEntries != NULL)
85 		return B_OK;
86 
87 	// ask the registrar
88 	KMessage message(BPrivate::B_REG_GET_GROUP_DB);
89 	status_t error = BPrivate::send_authentication_request_to_registrar(message,
90 		sGroupDBReply);
91 	if (error != B_OK)
92 		return error;
93 
94 	// unpack the reply
95 	int32 count;
96 	group** entries;
97 	int32 numBytes;
98 	if ((error = sGroupDBReply.FindInt32("count", &count)) != B_OK
99 		|| (error = sGroupDBReply.FindData("entries", B_RAW_TYPE,
100 				(const void**)&entries, &numBytes)) != B_OK) {
101 		return error;
102 	}
103 
104 	// relocate the entries
105 	addr_t baseAddress = (addr_t)entries;
106 	for (int32 i = 0; i < count; i++) {
107 		group* entry = relocate_pointer(baseAddress, entries[i]);
108 		relocate_pointer(baseAddress, entry->gr_name);
109 		relocate_pointer(baseAddress, entry->gr_passwd);
110 		relocate_pointer(baseAddress, entry->gr_mem);
111 		int32 k = 0;
112 		for (; entry->gr_mem[k] != (void*)-1; k++)
113 			relocate_pointer(baseAddress, entry->gr_mem[k]);
114 		entry->gr_mem[k] = NULL;
115 	}
116 
117 	sGroupEntries = entries;
118 	sGroupEntryCount = count;
119 
120 	return B_OK;
121 }
122 
123 
124 // #pragma mark -
125 
126 
127 struct group*
128 getgrent(void)
129 {
130 	struct group* result = NULL;
131 	int status = getgrent_r(&sGroupBuffer, sGroupStringBuffer,
132 		sizeof(sGroupStringBuffer), &result);
133 	if (status != 0)
134 		__set_errno(status);
135 	return result;
136 }
137 
138 
139 int
140 getgrent_r(struct group* group, char* buffer, size_t bufferSize,
141 	struct group** _result)
142 {
143 	UserGroupLocker _;
144 
145 	int status = B_NO_MEMORY;
146 
147 	*_result = NULL;
148 
149 	if ((status = init_group_db()) == B_OK) {
150 		if (sIterationIndex >= sGroupEntryCount)
151 			return ENOENT;
152 
153 		status = BPrivate::copy_group_to_buffer(
154 			sGroupEntries[sIterationIndex], group, buffer, bufferSize);
155 
156 		if (status == B_OK) {
157 			sIterationIndex++;
158 			*_result = group;
159 		}
160 	}
161 
162 	return status;
163 }
164 
165 
166 void
167 setgrent(void)
168 {
169 	UserGroupLocker _;
170 
171 	sIterationIndex = 0;
172 }
173 
174 
175 void
176 endgrent(void)
177 {
178 	UserGroupLocker locker;
179 
180 	sGroupDBReply.Unset();
181 	sGroupEntries = NULL;
182 	sGroupEntryCount = 0;
183 	sIterationIndex = 0;
184 }
185 
186 
187 struct group *
188 getgrnam(const char *name)
189 {
190 	struct group* result = NULL;
191 	int status = getgrnam_r(name, &sGroupBuffer, sGroupStringBuffer,
192 		sizeof(sGroupStringBuffer), &result);
193 	if (status != 0)
194 		__set_errno(status);
195 	return result;
196 }
197 
198 
199 int
200 getgrnam_r(const char *name, struct group *group, char *buffer,
201 	size_t bufferSize, struct group **_result)
202 {
203 	return query_group_entry(name, 0, group, buffer, bufferSize, _result);
204 }
205 
206 
207 struct group *
208 getgrgid(gid_t gid)
209 {
210 	struct group* result = NULL;
211 	int status = getgrgid_r(gid, &sGroupBuffer, sGroupStringBuffer,
212 		sizeof(sGroupStringBuffer), &result);
213 	if (status != 0)
214 		__set_errno(status);
215 	return result;
216 }
217 
218 
219 int
220 getgrgid_r(gid_t gid, struct group *group, char *buffer,
221 	size_t bufferSize, struct group **_result)
222 {
223 	return query_group_entry(NULL, gid, group, buffer, bufferSize, _result);
224 }
225 
226 
227 int
228 getgrouplist(const char* user, gid_t baseGroup, gid_t* groupList,
229 	int* groupCount)
230 {
231 	int maxGroupCount = *groupCount;
232 	*groupCount = 0;
233 
234 	status_t error = B_OK;
235 
236 	// prepare request
237 	KMessage message(BPrivate::B_REG_GET_USER_GROUPS);
238 	if (message.AddString("name", user) != B_OK
239 		|| message.AddInt32("max count", maxGroupCount) != B_OK) {
240 		return -1;
241 	}
242 
243 	// send request
244 	KMessage reply;
245 	error = BPrivate::send_authentication_request_to_registrar(message, reply);
246 	if (error != B_OK)
247 		return -1;
248 
249 	// unpack reply
250 	int32 count;
251 	const int32* groups;
252 	int32 groupsSize;
253 	if (reply.FindInt32("count", &count) != B_OK
254 		|| reply.FindData("groups", B_INT32_TYPE, (const void**)&groups,
255 				&groupsSize) != B_OK) {
256 		return -1;
257 	}
258 
259 	memcpy(groupList, groups, groupsSize);
260 	*groupCount = count;
261 
262 	// add the base group
263 	if (*groupCount < maxGroupCount)
264 		groupList[*groupCount] = baseGroup;
265 	++*groupCount;
266 
267 	return *groupCount <= maxGroupCount ? *groupCount : -1;
268 }
269 
270 
271 int
272 initgroups(const char* user, gid_t baseGroup)
273 {
274 	gid_t groups[NGROUPS_MAX + 1];
275 	int groupCount = NGROUPS_MAX + 1;
276 	if (getgrouplist(user, baseGroup, groups, &groupCount) < 0)
277 		return -1;
278 
279 	return setgroups(groupCount, groups);
280 }
281