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