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