xref: /haiku/src/system/libroot/posix/grp.cpp (revision e1a5b2976092e6100fbbb8d8c11ea96aebac4d26)
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 <libroot_private.h>
17 
18 #include "user_group_common.h"
19 
20 
21 using BPrivate::GroupDB;
22 using BPrivate::GroupDBReader;
23 using BPrivate::GroupEntryHandler;
24 using BPrivate::UserGroupLocker;
25 
26 static GroupDB* sGroupDB = NULL;
27 
28 static struct group sGroupBuffer;
29 static char sGroupStringBuffer[MAX_GROUP_BUFFER_SIZE];
30 
31 
32 namespace {
33 
34 class GroupEntryFindHandler : public GroupEntryHandler {
35 public:
36 	GroupEntryFindHandler(const char* name, uid_t gid,
37 			group* entry, char* buffer, size_t bufferSize)
38 		:
39 		fName(name),
40 		fGID(gid),
41 		fEntry(entry),
42 		fBuffer(buffer),
43 		fBufferSize(bufferSize)
44 	{
45 	}
46 
47 	virtual status_t HandleEntry(const char* name, const char* password,
48 		gid_t gid, const char* const* members, int memberCount)
49 	{
50 		if (fName != NULL ? strcmp(fName, name) != 0 : fGID != gid)
51 			return 0;
52 
53 		// found
54 		status_t error = BPrivate::copy_group_to_buffer(name, password, gid,
55 			members, memberCount, fEntry, fBuffer, fBufferSize);
56 
57 		return error == B_OK ? 1 : error;
58 	}
59 
60 private:
61 	const char*	fName;
62 	gid_t		fGID;
63 	group*		fEntry;
64 	char*		fBuffer;
65 	size_t		fBufferSize;
66 };
67 
68 
69 class UserGroupEntryHandler : public BPrivate::GroupEntryHandler {
70 public:
71 	UserGroupEntryHandler(const char* user, gid_t* groupList, int maxGroupCount,
72 			int* groupCount)
73 		:
74 		fUser(user),
75 		fGroupList(groupList),
76 		fMaxGroupCount(maxGroupCount),
77 		fGroupCount(groupCount)
78 	{
79 	}
80 
81 	virtual status_t HandleEntry(const char* name, const char* password,
82 		gid_t gid, const char* const* members, int memberCount)
83 	{
84 		for (int i = 0; i < memberCount; i++) {
85 			const char* member = members[i];
86 			if (*member != '\0' && strcmp(member, fUser) == 0) {
87 				if (*fGroupCount < fMaxGroupCount)
88 					fGroupList[*fGroupCount] = gid;
89 				++*fGroupCount;
90 			}
91 		}
92 
93 		return 0;
94 	}
95 
96 private:
97 	const char*	fUser;
98 	gid_t*		fGroupList;
99 	int			fMaxGroupCount;
100 	int*		fGroupCount;
101 };
102 
103 }	// empty namespace
104 
105 
106 static GroupDB*
107 init_group_db()
108 {
109 	if (sGroupDB != NULL)
110 		return sGroupDB;
111 
112 	sGroupDB = new(std::nothrow) GroupDB;
113 	if (sGroupDB == NULL)
114 		return NULL;
115 
116 	if (sGroupDB->Init() != B_OK) {
117 		delete sGroupDB;
118 		sGroupDB = NULL;
119 	}
120 
121 	return sGroupDB;
122 }
123 
124 
125 // #pragma mark -
126 
127 
128 struct group*
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 		errno = status;
136 	return result;
137 }
138 
139 
140 int
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 (GroupDB* db = init_group_db()) {
151 		status = db->GetNextEntry(group, buffer, bufferSize);
152 		if (status == 0)
153 			*_result = group;
154 
155 	}
156 
157 	return status;
158 }
159 
160 
161 void
162 setgrent(void)
163 {
164 	UserGroupLocker _;
165 
166 	if (GroupDB* db = init_group_db())
167 		db->RewindEntries();
168 }
169 
170 
171 void
172 endgrent(void)
173 {
174 	UserGroupLocker locker;
175 
176 	GroupDB* db = sGroupDB;
177 	sGroupDB = NULL;
178 
179 	locker.Unlock();
180 
181 	delete db;
182 }
183 
184 
185 struct group *
186 getgrnam(const char *name)
187 {
188 	struct group* result = NULL;
189 	int status = getgrnam_r(name, &sGroupBuffer, sGroupStringBuffer,
190 		sizeof(sGroupStringBuffer), &result);
191 	if (status != 0)
192 		errno = status;
193 	return result;
194 }
195 
196 
197 int
198 getgrnam_r(const char *name, struct group *group, char *buffer,
199 	size_t bufferSize, struct group **_result)
200 {
201 	GroupEntryFindHandler handler(name, 0, group, buffer, bufferSize);
202 	status_t status = GroupDBReader(&handler).Read(BPrivate::kGroupFile);
203 
204 	*_result = (status == 1 ? group : NULL);
205 	return (status == 1 ? 0 : (status == 0 ? ENOENT : status));
206 }
207 
208 
209 struct group *
210 getgrgid(gid_t gid)
211 {
212 	struct group* result = NULL;
213 	int status = getgrgid_r(gid, &sGroupBuffer, sGroupStringBuffer,
214 		sizeof(sGroupStringBuffer), &result);
215 	if (status != 0)
216 		errno = status;
217 	return result;
218 }
219 
220 
221 int
222 getgrgid_r(gid_t gid, struct group *group, char *buffer,
223 	size_t bufferSize, struct group **_result)
224 {
225 	GroupEntryFindHandler handler(NULL, gid, group, buffer, bufferSize);
226 	status_t status = GroupDBReader(&handler).Read(BPrivate::kGroupFile);
227 
228 	*_result = (status == 1 ? group : NULL);
229 	return (status == 1 ? 0 : (status == 0 ? ENOENT : status));
230 }
231 
232 
233 int
234 getgrouplist(const char* user, gid_t baseGroup, gid_t* groupList,
235 	int* groupCount)
236 {
237 	int maxGroupCount = *groupCount;
238 	*groupCount = 0;
239 
240 	UserGroupEntryHandler handler(user, groupList, maxGroupCount, groupCount);
241 	BPrivate::GroupDBReader(&handler).Read(BPrivate::kGroupFile);
242 
243 	// put in the base group
244 	if (*groupCount < maxGroupCount)
245 		groupList[*groupCount] = baseGroup;
246 	++*groupCount;
247 
248 	return *groupCount <= maxGroupCount ? *groupCount : -1;
249 }
250 
251 
252 int
253 initgroups(const char* user, gid_t baseGroup)
254 {
255 	gid_t groups[NGROUPS_MAX + 1];
256 	int groupCount = NGROUPS_MAX + 1;
257 	if (getgrouplist(user, baseGroup, groups, &groupCount) < 0)
258 		return -1;
259 
260 	return setgroups(groupCount, groups);
261 }
262