1 /*
2 * Copyright 2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Paweł Dziepak, pdziepak@quarnos.org
7 */
8
9
10 #include "IdMapper.h"
11
12 #include <grp.h>
13 #include <pwd.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/types.h>
18
19 #include <File.h>
20 #include <FindDirectory.h>
21 #include <OS.h>
22 #include <Path.h>
23
24
25 port_id gRequestPort;
26 port_id gReplyPort;
27
28 const char* kNobodyName = "nobody";
29 uid_t gNobodyId;
30
31 const char* kNogroupName = "nobody";
32 uid_t gNogroupId;
33
34 const char* gDomainName = "localdomain";
35
36
37 status_t
SendError(status_t error)38 SendError(status_t error)
39 {
40 return write_port(gReplyPort, MsgError, &error, sizeof(error));
41 }
42
43
44 status_t
MatchDomain(char * name)45 MatchDomain(char* name)
46 {
47 char* domain = strchr(name, '@');
48 if (domain == NULL)
49 return B_MISMATCHED_VALUES;
50
51 if (strcmp(domain + 1, gDomainName) != 0)
52 return B_BAD_VALUE;
53
54 *domain = '\0';
55
56 return B_OK;
57 }
58
59
60 char*
AddDomain(const char * name)61 AddDomain(const char* name)
62 {
63 uint32 fullLength = strlen(name) + strlen(gDomainName) + 2;
64 char* fullName = reinterpret_cast<char*>(malloc(fullLength));
65 if (fullName == NULL)
66 return NULL;
67
68 strcpy(fullName, name);
69 strcat(fullName, "@");
70 strcat(fullName, gDomainName);
71
72 return fullName;
73 }
74
75
76 status_t
NameToUID(void * buffer)77 NameToUID(void* buffer)
78 {
79 char* userName = reinterpret_cast<char*>(buffer);
80
81 struct passwd* userInfo = NULL;
82
83 if (MatchDomain(userName) == B_OK)
84 userInfo = getpwnam(userName);
85
86 if (userInfo == NULL)
87 return write_port(gReplyPort, MsgReply, &gNobodyId, sizeof(gNobodyId));
88
89 return write_port(gReplyPort, MsgReply, &userInfo->pw_uid, sizeof(uid_t));
90 }
91
92
93 status_t
UIDToName(void * buffer)94 UIDToName(void* buffer)
95 {
96 uid_t userId = *reinterpret_cast<uid_t*>(buffer);
97
98 const char* name = NULL;
99
100 struct passwd* userInfo = getpwuid(userId);
101 if (userInfo != NULL) {
102 name = userInfo->pw_name;
103 name = AddDomain(name);
104 }
105
106 status_t result;
107
108 if (name != NULL) {
109 result = write_port(gReplyPort, MsgReply, name, strlen(name) + 1);
110 free(const_cast<char*>(name));
111 } else {
112 result = write_port(gReplyPort, MsgReply, kNobodyName,
113 strlen(kNobodyName) + 1);
114 }
115
116 return result;
117 }
118
119
120 status_t
NameToGID(void * buffer)121 NameToGID(void* buffer)
122 {
123 char* groupName = reinterpret_cast<char*>(buffer);
124
125 struct group* groupInfo = NULL;
126
127 if (MatchDomain(groupName) == B_OK)
128 groupInfo = getgrnam(groupName);
129
130 if (groupInfo == NULL) {
131 return write_port(gReplyPort, MsgReply, &gNogroupId,
132 sizeof(gNogroupId));
133 }
134
135 return write_port(gReplyPort, MsgReply, &groupInfo->gr_gid, sizeof(gid_t));
136 }
137
138
139 status_t
GIDToName(void * buffer)140 GIDToName(void* buffer)
141 {
142 gid_t groupId = *reinterpret_cast<gid_t*>(buffer);
143
144 const char* name = NULL;
145
146 struct group* groupInfo = getgrgid(groupId);
147 if (groupInfo != NULL) {
148 name = groupInfo->gr_name;
149 name = AddDomain(name);
150 }
151
152 status_t result;
153
154 if (name != NULL) {
155 result = write_port(gReplyPort, MsgReply, name, strlen(name) + 1);
156 free(const_cast<char*>(name));
157 } else {
158 result = write_port(gReplyPort, MsgReply, kNogroupName,
159 strlen(kNogroupName) + 1);
160 }
161
162 return result;
163 }
164
165
166 status_t
ParseRequest(int32 code,void * buffer)167 ParseRequest(int32 code, void* buffer)
168 {
169 switch (code) {
170 case MsgNameToUID:
171 return NameToUID(buffer);
172
173 case MsgUIDToName:
174 return UIDToName(buffer);
175
176 case MsgNameToGID:
177 return NameToGID(buffer);
178
179 case MsgGIDToName:
180 return GIDToName(buffer);
181
182 default:
183 return SendError(B_BAD_VALUE);
184 }
185 }
186
187
188 status_t
MainLoop()189 MainLoop()
190 {
191 do {
192 ssize_t size = port_buffer_size(gRequestPort);
193 if (size < B_OK)
194 return 0;
195
196 void* buffer = malloc(size);
197 if (buffer == NULL)
198 return B_NO_MEMORY;
199
200 int32 code;
201 size = read_port(gRequestPort, &code, buffer, size);
202 if (size < B_OK) {
203 free(buffer);
204 return 0;
205 }
206
207 status_t result = ParseRequest(code, buffer);
208 free(buffer);
209
210 if (result != B_OK)
211 return 0;
212
213 } while (true);
214 }
215
216
217 status_t
ReadSettings()218 ReadSettings()
219 {
220 BPath path;
221 status_t result = find_directory(B_SYSTEM_SETTINGS_DIRECTORY, &path);
222 if (result != B_OK)
223 return result;
224 result = path.Append("nfs4_idmapper.conf");
225 if (result != B_OK)
226 return result;
227
228 BFile file(path.Path(), B_READ_ONLY);
229 if (file.InitCheck() != B_OK)
230 return file.InitCheck();
231
232 off_t size;
233 result = file.GetSize(&size);
234 if (result != B_OK)
235 return result;
236
237 void* buffer = malloc(size);
238 if (buffer == NULL)
239 return B_NO_MEMORY;
240
241 file.Read(buffer, size);
242
243 gDomainName = reinterpret_cast<char*>(buffer);
244
245 return B_OK;
246 }
247
248
249 int
main(int argc,char ** argv)250 main(int argc, char** argv)
251 {
252 gRequestPort = find_port(kRequestPortName);
253 if (gRequestPort < B_OK) {
254 fprintf(stderr, "%s\n", strerror(gRequestPort));
255 return gRequestPort;
256 }
257
258 gReplyPort = find_port(kReplyPortName);
259 if (gReplyPort < B_OK) {
260 fprintf(stderr, "%s\n", strerror(gReplyPort));
261 return gReplyPort;
262 }
263
264 ReadSettings();
265
266 struct passwd* userInfo = getpwnam(kNobodyName);
267 if (userInfo != NULL)
268 gNobodyId = userInfo->pw_uid;
269 else
270 gNobodyId = 0;
271
272 struct group* groupInfo = getgrnam(kNogroupName);
273 if (groupInfo != NULL)
274 gNogroupId = groupInfo->gr_gid;
275 else
276 gNogroupId = 0;
277
278 return MainLoop();
279 }
280
281