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