xref: /haiku/src/system/libroot/posix/pwd.cpp (revision 239222b2369c39dc52df52b0a7cdd6cc0a91bc92)
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 <pwd.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 #include <RegistrarDefs.h>
18 #include <user_group.h>
19 
20 #include <util/KMessage.h>
21 
22 
23 using BPrivate::UserGroupLocker;
24 using BPrivate::relocate_pointer;
25 
26 
27 static KMessage sPasswdDBReply;
28 static passwd** sPasswdEntries = NULL;
29 static size_t sPasswdEntryCount = 0;
30 static size_t sIterationIndex = 0;
31 
32 static struct passwd sPasswdBuffer;
33 static char sPasswdStringBuffer[MAX_PASSWD_BUFFER_SIZE];
34 
35 
36 static status_t
37 query_passwd_entry(const char* name, uid_t _uid, struct passwd *passwd,
38 	char *buffer, size_t bufferSize, struct passwd **_result)
39 {
40 	*_result = NULL;
41 
42 	KMessage message(BPrivate::B_REG_GET_USER);
43 	if (name)
44 		message.AddString("name", name);
45 	else
46 		message.AddInt32("uid", _uid);
47 
48 	KMessage reply;
49 	status_t error = BPrivate::send_authentication_request_to_registrar(message,
50 		reply);
51 	if (error != B_OK)
52 		return error;
53 
54 	int32 uid;
55 	int32 gid;
56 	const char* password;
57 	const char* home;
58 	const char* shell;
59 	const char* realName;
60 
61 	if ((error = reply.FindInt32("uid", &uid)) != B_OK
62 		|| (error = reply.FindInt32("gid", &gid)) != B_OK
63 		|| (error = reply.FindString("name", &name)) != B_OK
64 		|| (error = reply.FindString("password", &password)) != B_OK
65 		|| (error = reply.FindString("home", &home)) != B_OK
66 		|| (error = reply.FindString("shell", &shell)) != B_OK
67 		|| (error = reply.FindString("real name", &realName)) != B_OK) {
68 		return error;
69 	}
70 
71 	error = BPrivate::copy_passwd_to_buffer(name, password, uid, gid, home,
72 		shell, realName, passwd, buffer, bufferSize);
73 	if (error == B_OK)
74 		*_result = passwd;
75 
76 	return error;
77 }
78 
79 
80 static status_t
81 init_passwd_db()
82 {
83 	if (sPasswdEntries != NULL)
84 		return B_OK;
85 
86 	// ask the registrar
87 	KMessage message(BPrivate::B_REG_GET_PASSWD_DB);
88 	status_t error = BPrivate::send_authentication_request_to_registrar(message,
89 		sPasswdDBReply);
90 	if (error != B_OK)
91 		return error;
92 
93 	// unpack the reply
94 	int32 count;
95 	passwd** entries;
96 	int32 numBytes;
97 	if ((error = sPasswdDBReply.FindInt32("count", &count)) != B_OK
98 		|| (error = sPasswdDBReply.FindData("entries", B_RAW_TYPE,
99 				(const void**)&entries, &numBytes)) != B_OK) {
100 		return error;
101 	}
102 
103 	// relocate the entries
104 	addr_t baseAddress = (addr_t)entries;
105 	for (int32 i = 0; i < count; i++) {
106 		passwd* entry = relocate_pointer(baseAddress, entries[i]);
107 		relocate_pointer(baseAddress, entry->pw_name);
108 		relocate_pointer(baseAddress, entry->pw_passwd);
109 		relocate_pointer(baseAddress, entry->pw_dir);
110 		relocate_pointer(baseAddress, entry->pw_shell);
111 		relocate_pointer(baseAddress, entry->pw_gecos);
112 	}
113 
114 	sPasswdEntries = entries;
115 	sPasswdEntryCount = count;
116 
117 	return B_OK;
118 }
119 
120 
121 // #pragma mark -
122 
123 
124 struct passwd*
125 getpwent(void)
126 {
127 	struct passwd* result = NULL;
128 	int status = getpwent_r(&sPasswdBuffer, sPasswdStringBuffer,
129 		sizeof(sPasswdStringBuffer), &result);
130 	if (status != 0)
131 		errno = status;
132 	return result;
133 }
134 
135 
136 int
137 getpwent_r(struct passwd* passwd, char* buffer, size_t bufferSize,
138 	struct passwd** _result)
139 {
140 	UserGroupLocker _;
141 
142 	int status = B_NO_MEMORY;
143 
144 	*_result = NULL;
145 
146 	if ((status = init_passwd_db()) == B_OK) {
147 		if (sIterationIndex >= sPasswdEntryCount)
148 			return ENOENT;
149 
150 		status = BPrivate::copy_passwd_to_buffer(
151 			sPasswdEntries[sIterationIndex], passwd, buffer, bufferSize);
152 
153 		if (status == B_OK) {
154 			sIterationIndex++;
155 			*_result = passwd;
156 		}
157 	}
158 
159 	return status;
160 }
161 
162 
163 void
164 setpwent(void)
165 {
166 	UserGroupLocker _;
167 
168 	sIterationIndex = 0;
169 }
170 
171 
172 void
173 endpwent(void)
174 {
175 	UserGroupLocker locker;
176 
177 	sPasswdDBReply.Unset();
178 	sPasswdEntries = NULL;
179 	sPasswdEntryCount = 0;
180 	sIterationIndex = 0;
181 }
182 
183 
184 struct passwd *
185 getpwnam(const char *name)
186 {
187 	struct passwd* result = NULL;
188 	int status = getpwnam_r(name, &sPasswdBuffer, sPasswdStringBuffer,
189 		sizeof(sPasswdStringBuffer), &result);
190 	if (status != 0)
191 		errno = status;
192 	return result;
193 }
194 
195 
196 int
197 getpwnam_r(const char *name, struct passwd *passwd, char *buffer,
198 	size_t bufferSize, struct passwd **_result)
199 {
200 	return query_passwd_entry(name, 0, passwd, buffer, bufferSize, _result);
201 }
202 
203 
204 struct passwd *
205 getpwuid(uid_t uid)
206 {
207 	struct passwd* result = NULL;
208 	int status = getpwuid_r(uid, &sPasswdBuffer, sPasswdStringBuffer,
209 		sizeof(sPasswdStringBuffer), &result);
210 	if (status != 0)
211 		errno = status;
212 	return result;
213 }
214 
215 
216 int
217 getpwuid_r(uid_t uid, struct passwd *passwd, char *buffer,
218 	size_t bufferSize, struct passwd **_result)
219 {
220 	return query_passwd_entry(NULL, uid, passwd, buffer, bufferSize, _result);
221 }
222