xref: /haiku/src/system/libroot/posix/shadow.cpp (revision b671e9bbdbd10268a042b4f4cc4317ccd03d105e)
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 <shadow.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 <AutoDeleter.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 sShadowPwdDBReply;
29 static spwd** sShadowPwdEntries = NULL;
30 static size_t sShadowPwdEntryCount = 0;
31 static size_t sIterationIndex = 0;
32 
33 static struct spwd sShadowPwdBuffer;
34 static char sShadowPwdStringBuffer[MAX_SHADOW_PWD_BUFFER_SIZE];
35 
36 
37 static status_t
38 init_shadow_pwd_db()
39 {
40 	if (sShadowPwdEntries != NULL)
41 		return B_OK;
42 
43 	// ask the registrar
44 	KMessage message(BPrivate::B_REG_GET_SHADOW_PASSWD_DB);
45 	status_t error = BPrivate::send_authentication_request_to_registrar(message,
46 		sShadowPwdDBReply);
47 	if (error != B_OK)
48 		return error;
49 
50 	// unpack the reply
51 	int32 count;
52 	spwd** entries;
53 	int32 numBytes;
54 	if ((error = sShadowPwdDBReply.FindInt32("count", &count)) != B_OK
55 		|| (error = sShadowPwdDBReply.FindData("entries", B_RAW_TYPE,
56 				(const void**)&entries, &numBytes)) != B_OK) {
57 		return error;
58 	}
59 
60 	// relocate the entries
61 	addr_t baseAddress = (addr_t)entries;
62 	for (int32 i = 0; i < count; i++) {
63 		spwd* entry = relocate_pointer(baseAddress, entries[i]);
64 		relocate_pointer(baseAddress, entry->sp_namp);
65 		relocate_pointer(baseAddress, entry->sp_pwdp);
66 	}
67 
68 	sShadowPwdEntries = entries;
69 	sShadowPwdEntryCount = count;
70 
71 	return B_OK;
72 }
73 
74 
75 // #pragma mark -
76 
77 
78 struct spwd*
79 getspent(void)
80 {
81 	struct spwd* result = NULL;
82 	int status = getspent_r(&sShadowPwdBuffer, sShadowPwdStringBuffer,
83 		sizeof(sShadowPwdStringBuffer), &result);
84 	if (status != 0)
85 		errno = status;
86 	return result;
87 }
88 
89 
90 int
91 getspent_r(struct spwd* spwd, char* buffer, size_t bufferSize,
92 	struct spwd** _result)
93 {
94 	UserGroupLocker _;
95 
96 	int status = B_NO_MEMORY;
97 
98 	*_result = NULL;
99 
100 	if ((status = init_shadow_pwd_db()) == B_OK) {
101 		if (sIterationIndex >= sShadowPwdEntryCount)
102 			return ENOENT;
103 
104 		status = BPrivate::copy_shadow_pwd_to_buffer(
105 			sShadowPwdEntries[sIterationIndex], spwd, buffer, bufferSize);
106 
107 		if (status == B_OK) {
108 			sIterationIndex++;
109 			*_result = spwd;
110 		}
111 	}
112 
113 	return status;
114 }
115 
116 
117 void
118 setspent(void)
119 {
120 	UserGroupLocker _;
121 
122 	sIterationIndex = 0;
123 }
124 
125 
126 void
127 endspent(void)
128 {
129 	UserGroupLocker locker;
130 
131 	sShadowPwdDBReply.Unset();
132 	sShadowPwdEntries = NULL;
133 	sShadowPwdEntryCount = 0;
134 	sIterationIndex = 0;
135 }
136 
137 
138 struct spwd *
139 getspnam(const char *name)
140 {
141 	struct spwd* result = NULL;
142 	int status = getspnam_r(name, &sShadowPwdBuffer, sShadowPwdStringBuffer,
143 		sizeof(sShadowPwdStringBuffer), &result);
144 	if (status != 0)
145 		errno = status;
146 	return result;
147 }
148 
149 
150 int
151 getspnam_r(const char *name, struct spwd *spwd, char *buffer,
152 	size_t bufferSize, struct spwd **_result)
153 {
154 	*_result = NULL;
155 
156 	KMessage message(BPrivate::B_REG_GET_USER);
157 	message.AddString("name", name);
158 	message.AddBool("shadow", true);
159 
160 	KMessage reply;
161 	status_t error = BPrivate::send_authentication_request_to_registrar(message,
162 		reply);
163 	if (error != B_OK)
164 		return error;
165 
166 	const char* password;
167 	int32 lastChanged;
168 	int32 min;
169 	int32 max;
170 	int32 warn;
171 	int32 inactive;
172 	int32 expiration;
173 	int32 flags;
174 
175 	if ((error = reply.FindString("name", &name)) != B_OK
176 		|| (error = reply.FindString("shadow password", &password)) != B_OK
177 		|| (error = reply.FindInt32("last changed", &lastChanged)) != B_OK
178 		|| (error = reply.FindInt32("min", &min)) != B_OK
179 		|| (error = reply.FindInt32("max", &max)) != B_OK
180 		|| (error = reply.FindInt32("warn", &warn)) != B_OK
181 		|| (error = reply.FindInt32("inactive", &inactive)) != B_OK
182 		|| (error = reply.FindInt32("expiration", &expiration)) != B_OK
183 		|| (error = reply.FindInt32("flags", &flags)) != B_OK) {
184 		return error;
185 	}
186 
187 	error = BPrivate::copy_shadow_pwd_to_buffer(name, password, lastChanged,
188 		min, max, warn, inactive, expiration, flags, spwd, buffer, bufferSize);
189 	if (error == B_OK)
190 		*_result = spwd;
191 
192 	return error;
193 }
194 
195 
196 struct spwd*
197 sgetspent(const char* line)
198 {
199 	struct spwd* result = NULL;
200 	int status = sgetspent_r(line, &sShadowPwdBuffer, sShadowPwdStringBuffer,
201 		sizeof(sShadowPwdStringBuffer), &result);
202 	if (status != 0)
203 		errno = status;
204 	return result;
205 }
206 
207 
208 int
209 sgetspent_r(const char* _line, struct spwd *spwd, char *buffer,
210 	size_t bufferSize, struct spwd** _result)
211 {
212 	*_result = NULL;
213 
214 	if (_line == NULL)
215 		return B_BAD_VALUE;
216 
217 	// we need a mutable copy of the line
218 	char* line = strdup(_line);
219 	if (line == NULL)
220 		return B_NO_MEMORY;
221 	MemoryDeleter _(line);
222 
223 	char* name;
224 	char* password;
225 	int lastChanged;
226 	int min;
227 	int max;
228 	int warn;
229 	int inactive;
230 	int expiration;
231 	int flags;
232 
233 	status_t status = BPrivate::parse_shadow_pwd_line(line, name, password,
234 		lastChanged, min, max, warn, inactive, expiration, flags);
235 	if (status != B_OK)
236 		return status;
237 
238 	status = BPrivate::copy_shadow_pwd_to_buffer(name, password, lastChanged,
239 		min, max, warn, inactive, expiration, flags, spwd, buffer, bufferSize);
240 	if (status != B_OK)
241 		return status;
242 
243 	*_result = spwd;
244 	return 0;
245 }
246 
247 
248 struct spwd*
249 fgetspent(FILE* file)
250 {
251 	struct spwd* result = NULL;
252 	int status = fgetspent_r(file, &sShadowPwdBuffer, sShadowPwdStringBuffer,
253 		sizeof(sShadowPwdStringBuffer), &result);
254 	if (status != 0)
255 		errno = status;
256 	return result;
257 }
258 
259 
260 int
261 fgetspent_r(FILE* file, struct spwd* spwd, char* buffer, size_t bufferSize,
262 	struct spwd** _result)
263 {
264 	*_result = NULL;
265 
266 	// read a line
267 	char lineBuffer[LINE_MAX + 1];
268 	errno = 0;
269 	char* line = fgets(lineBuffer, sizeof(lineBuffer), file);
270 	if (line == NULL) {
271 		if (errno != 0)
272 			return errno;
273 		return ENOENT;
274 	}
275 
276 	return sgetspent_r(line, spwd, buffer, bufferSize, _result);
277 }
278