2 * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
7 #include <user_group.h>
18 #include <errno_private.h>
20 #include <libroot_private.h>
22 #include <RegistrarDefs.h>
24 #include <util/KMessage.h>
27 using BPrivate::Tokenizer
;
30 static const char* const kUserGroupLockName
= "user group";
32 const char* BPrivate::kPasswdFile
= "/etc/passwd";
33 const char* BPrivate::kGroupFile
= "/etc/group";
34 const char* BPrivate::kShadowPwdFile
= "/etc/shadow";
36 static mutex sUserGroupLock
= MUTEX_INITIALIZER(kUserGroupLockName
);
37 static port_id sRegistrarPort
= -1;
41 BPrivate::user_group_lock()
43 return mutex_lock(&sUserGroupLock
);
48 BPrivate::user_group_unlock()
50 mutex_unlock(&sUserGroupLock
);
56 BPrivate::get_registrar_authentication_port()
58 if (sRegistrarPort
< 0) {
59 BPrivate::KMessage data
;
60 if (BPrivate::get_launch_data(B_REGISTRAR_SIGNATURE
, data
)
62 sRegistrarPort
= data
.GetInt32(
63 B_REGISTRAR_AUTHENTICATION_PORT_NAME
"_port", -1);
66 return sRegistrarPort
;
71 BPrivate::set_registrar_authentication_port(port_id port
)
73 sRegistrarPort
= port
;
78 BPrivate::send_authentication_request_to_registrar(KMessage
& request
,
81 status_t error
= request
.SendTo(get_registrar_authentication_port(), 0,
86 return (status_t
)reply
.What();
90 class BPrivate::Tokenizer
{
92 Tokenizer(char* string
)
97 char* NextToken(char separator
)
102 char* token
= fString
;
103 fString
= strchr(fString
, separator
);
104 if (fString
!= NULL
) {
112 char* NextTrimmedToken(char separator
)
114 char* token
= NextToken(separator
);
118 // skip spaces at the beginning
119 while (*token
!= '\0' && isspace(*token
))
122 // cut off spaces at the end
123 char* end
= token
+ strlen(token
);
124 while (end
!= token
&& isspace(end
[-1]))
137 buffer_dup_string(const char* string
, char*& buffer
, size_t& bufferLen
)
142 size_t size
= strlen(string
) + 1;
143 if (size
> bufferLen
)
146 strcpy(buffer
, string
);
147 char* result
= buffer
;
156 buffer_allocate(size_t size
, size_t align
, char*& buffer
, size_t& bufferSize
)
159 addr_t pad
= align
- (((addr_t
)buffer
- 1) & (align
- 1)) - 1;
160 if (pad
+ size
> bufferSize
)
163 char* result
= buffer
+ pad
;
164 buffer
= result
+ size
;
165 bufferSize
-= pad
+ size
;
171 // #pragma mark - passwd support
175 BPrivate::copy_passwd_to_buffer(const char* name
, const char* password
,
176 uid_t uid
, gid_t gid
, const char* home
, const char* shell
,
177 const char* realName
, passwd
* entry
, char* buffer
, size_t bufferSize
)
182 entry
->pw_name
= buffer_dup_string(name
, buffer
, bufferSize
);
183 entry
->pw_passwd
= buffer_dup_string(password
, buffer
, bufferSize
);
184 entry
->pw_dir
= buffer_dup_string(home
, buffer
, bufferSize
);
185 entry
->pw_shell
= buffer_dup_string(shell
, buffer
, bufferSize
);
186 entry
->pw_gecos
= buffer_dup_string(realName
, buffer
, bufferSize
);
188 if (entry
->pw_name
&& entry
->pw_passwd
&& entry
->pw_dir
189 && entry
->pw_shell
&& entry
->pw_gecos
) {
198 BPrivate::copy_passwd_to_buffer(const passwd
* from
, passwd
* entry
, char* buffer
,
201 return copy_passwd_to_buffer(from
->pw_name
, from
->pw_passwd
, from
->pw_uid
,
202 from
->pw_gid
, from
->pw_dir
, from
->pw_shell
, from
->pw_gecos
, entry
,
208 BPrivate::parse_passwd_line(char* line
, char*& name
, char*& password
,
209 uid_t
& uid
, gid_t
& gid
, char*& home
, char*& shell
, char*& realName
)
211 Tokenizer
tokenizer(line
);
213 name
= tokenizer
.NextTrimmedToken(':');
214 password
= tokenizer
.NextTrimmedToken(':');
215 char* userID
= tokenizer
.NextTrimmedToken(':');
216 char* groupID
= tokenizer
.NextTrimmedToken(':');
217 realName
= tokenizer
.NextTrimmedToken(':');
218 home
= tokenizer
.NextTrimmedToken(':');
219 shell
= tokenizer
.NextTrimmedToken(':');
223 if (shell
== NULL
|| (nameLen
= strlen(name
)) == 0
224 || !isdigit(*userID
) || !isdigit(*groupID
)
225 || nameLen
>= MAX_PASSWD_NAME_LEN
226 || strlen(password
) >= MAX_PASSWD_PASSWORD_LEN
227 || strlen(realName
) >= MAX_PASSWD_REAL_NAME_LEN
228 || strlen(home
) >= MAX_PASSWD_HOME_DIR_LEN
229 || strlen(shell
) >= MAX_PASSWD_SHELL_LEN
) {
240 // #pragma mark - group support
244 BPrivate::copy_group_to_buffer(const char* name
, const char* password
,
245 gid_t gid
, const char* const* members
, int memberCount
, group
* entry
,
246 char* buffer
, size_t bufferSize
)
250 // allocate member array (do that first for alignment reasons)
251 entry
->gr_mem
= (char**)buffer_allocate(sizeof(char*) * (memberCount
+ 1),
252 sizeof(char*), buffer
, bufferSize
);
253 if (entry
->gr_mem
== NULL
)
256 // copy name and password
257 entry
->gr_name
= buffer_dup_string(name
, buffer
, bufferSize
);
258 entry
->gr_passwd
= buffer_dup_string(password
, buffer
, bufferSize
);
259 if (entry
->gr_name
== NULL
|| entry
->gr_passwd
== NULL
)
263 for (int i
= 0; i
< memberCount
; i
++) {
264 entry
->gr_mem
[i
] = buffer_dup_string(members
[i
], buffer
, bufferSize
);
265 if (entry
->gr_mem
[i
] == NULL
)
268 entry
->gr_mem
[memberCount
] = NULL
;
275 BPrivate::copy_group_to_buffer(const group
* from
, group
* entry
, char* buffer
,
279 while (from
->gr_mem
[memberCount
] != NULL
)
282 return copy_group_to_buffer(from
->gr_name
, from
->gr_passwd
,
283 from
->gr_gid
, from
->gr_mem
, memberCount
, entry
, buffer
, bufferSize
);
288 BPrivate::parse_group_line(char* line
, char*& name
, char*& password
, gid_t
& gid
,
289 char** members
, int& memberCount
)
291 Tokenizer
tokenizer(line
);
293 name
= tokenizer
.NextTrimmedToken(':');
294 password
= tokenizer
.NextTrimmedToken(':');
295 char* groupID
= tokenizer
.NextTrimmedToken(':');
299 if (groupID
== NULL
|| (nameLen
= strlen(name
)) == 0 || !isdigit(*groupID
)
300 || nameLen
>= MAX_GROUP_NAME_LEN
301 || strlen(password
) >= MAX_GROUP_PASSWORD_LEN
) {
309 while (char* groupUser
= tokenizer
.NextTrimmedToken(',')) {
310 // ignore invalid members
311 if (*groupUser
== '\0' || strlen(groupUser
) >= MAX_PASSWD_NAME_LEN
)
314 members
[memberCount
++] = groupUser
;
316 // ignore excess members
317 if (memberCount
== MAX_GROUP_MEMBER_COUNT
)
325 // #pragma mark - shadow password support
329 BPrivate::copy_shadow_pwd_to_buffer(const char* name
, const char* password
,
330 int lastChanged
, int min
, int max
, int warn
, int inactive
, int expiration
,
331 int flags
, spwd
* entry
, char* buffer
, size_t bufferSize
)
333 entry
->sp_lstchg
= lastChanged
;
336 entry
->sp_warn
= warn
;
337 entry
->sp_inact
= inactive
;
338 entry
->sp_expire
= expiration
;
339 entry
->sp_flag
= flags
;
341 entry
->sp_namp
= buffer_dup_string(name
, buffer
, bufferSize
);
342 entry
->sp_pwdp
= buffer_dup_string(password
, buffer
, bufferSize
);
344 if (entry
->sp_namp
&& entry
->sp_pwdp
)
352 BPrivate::copy_shadow_pwd_to_buffer(const spwd
* from
, spwd
* entry
,
353 char* buffer
, size_t bufferSize
)
355 return copy_shadow_pwd_to_buffer(from
->sp_namp
, from
->sp_pwdp
,
356 from
->sp_lstchg
, from
->sp_min
, from
->sp_max
, from
->sp_warn
,
357 from
->sp_inact
, from
->sp_expire
, from
->sp_flag
, entry
, buffer
,
363 BPrivate::parse_shadow_pwd_line(char* line
, char*& name
, char*& password
,
364 int& lastChanged
, int& min
, int& max
, int& warn
, int& inactive
,
365 int& expiration
, int& flags
)
367 Tokenizer
tokenizer(line
);
369 name
= tokenizer
.NextTrimmedToken(':');
370 password
= tokenizer
.NextTrimmedToken(':');
371 char* lastChangedString
= tokenizer
.NextTrimmedToken(':');
372 char* minString
= tokenizer
.NextTrimmedToken(':');
373 char* maxString
= tokenizer
.NextTrimmedToken(':');
374 char* warnString
= tokenizer
.NextTrimmedToken(':');
375 char* inactiveString
= tokenizer
.NextTrimmedToken(':');
376 char* expirationString
= tokenizer
.NextTrimmedToken(':');
377 char* flagsString
= tokenizer
.NextTrimmedToken(':');
381 if (flagsString
== NULL
|| (nameLen
= strlen(name
)) == 0
382 || nameLen
>= MAX_SHADOW_PWD_NAME_LEN
383 || strlen(password
) >= MAX_SHADOW_PWD_PASSWORD_LEN
) {
387 lastChanged
= atoi(lastChangedString
);
388 min
= minString
[0] != '\0' ? atoi(minString
) : -1;
389 max
= maxString
[0] != '\0' ? atoi(maxString
) : -1;
390 warn
= warnString
[0] != '\0' ? atoi(warnString
) : -1;
391 inactive
= inactiveString
[0] != '\0' ? atoi(inactiveString
) : -1;
392 expiration
= expirationString
[0] != '\0' ? atoi(expirationString
) : -1;
393 flags
= atoi(flagsString
);
403 __init_pwd_backend(void)
409 __reinit_pwd_backend_after_fork(void)
411 mutex_init(&sUserGroupLock
, kUserGroupLockName
);