xref: /haiku/src/add-ons/kernel/file_systems/nfs4/idmapper/IdMapper.cpp (revision be012e21222c4d8d70082d12353acb163dc60ba8)
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
38 SendError(status_t error)
39 {
40 	return write_port(gReplyPort, MsgError, &error, sizeof(error));
41 }
42 
43 
44 status_t
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*
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
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
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
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
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
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
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
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
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