xref: /haiku/src/add-ons/kernel/file_systems/nfs4/IdMap.cpp (revision 25a7b01d15612846f332751841da3579db313082)
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 "IdMap.h"
11 
12 #include <AutoDeleter.h>
13 #include <FindDirectory.h>
14 #include <team.h>
15 #include <util/AutoLock.h>
16 
17 #include "idmapper/IdMapper.h"
18 
19 
20 IdMap*	gIdMapper		= NULL;
21 mutex	gIdMapperLock;
22 
23 
IdMap()24 IdMap::IdMap()
25 {
26 	mutex_init(&fLock, NULL);
27 	fInitStatus = _Repair();
28 }
29 
30 
~IdMap()31 IdMap::~IdMap()
32 {
33 	delete_port(fRequestPort);
34 	delete_port(fReplyPort);
35 	mutex_destroy(&fLock);
36 }
37 
38 
39 uid_t
GetUserId(const char * owner)40 IdMap::GetUserId(const char* owner)
41 {
42 	ASSERT(owner != NULL);
43 	return _GetValue<uid_t>(owner, MsgNameToUID);
44 }
45 
46 
47 gid_t
GetGroupId(const char * ownerGroup)48 IdMap::GetGroupId(const char* ownerGroup)
49 {
50 	ASSERT(ownerGroup != NULL);
51 	return _GetValue<gid_t>(ownerGroup, MsgNameToGID);
52 }
53 
54 
55 char*
GetOwner(uid_t user)56 IdMap::GetOwner(uid_t user)
57 {
58 	return reinterpret_cast<char*>(_GetBuffer(user, MsgUIDToName));
59 }
60 
61 
62 char*
GetOwnerGroup(gid_t group)63 IdMap::GetOwnerGroup(gid_t group)
64 {
65 	return reinterpret_cast<char*>(_GetBuffer(group, MsgGIDToName));
66 }
67 
68 
69 template<typename T>
70 T
_GetValue(const char * buffer,int32 code)71 IdMap::_GetValue(const char* buffer, int32 code)
72 {
73 	ASSERT(buffer != NULL);
74 
75 	MutexLocker _(fLock);
76 	do {
77 		status_t result = write_port(fRequestPort, MsgNameToUID, buffer,
78 			strlen(buffer) + 1);
79 		if (result != B_OK) {
80 			if (_Repair() != B_OK)
81 				return 0;
82 			continue;
83 		}
84 
85 		int32 code;
86 		T value;
87 		result = read_port(fReplyPort, &code, &value, sizeof(T));
88 		if (result < B_OK) {
89 			if (_Repair() != B_OK)
90 				return 0;
91 			continue;
92 		}
93 
94 		if (code != MsgReply)
95 			return 0;
96 
97 		return value;
98 	} while (true);
99 }
100 
101 
102 template<typename T>
103 void*
_GetBuffer(T value,int32 code)104 IdMap::_GetBuffer(T value, int32 code)
105 {
106 	MutexLocker _(fLock);
107 	do {
108 		status_t result = write_port(fRequestPort, code, &value, sizeof(value));
109 		if (result != B_OK) {
110 			if (_Repair() != B_OK)
111 				return NULL;
112 			continue;
113 		}
114 
115 		ssize_t size = port_buffer_size(fReplyPort);
116 		if (size < B_OK) {
117 			if (_Repair() != B_OK)
118 				return NULL;
119 			continue;
120 		}
121 
122 		int32 code;
123 		void* buffer = malloc(size);
124 		if (buffer == NULL)
125 			return NULL;
126 		MemoryDeleter bufferDeleter(buffer);
127 
128 		size = read_port(fReplyPort, &code, buffer, size);
129 		if (size < B_OK) {
130 			if (_Repair() != B_OK)
131 				return 0;
132 			continue;
133 		}
134 
135 		if (code != MsgReply)
136 			return NULL;
137 
138 		bufferDeleter.Detach();
139 		return buffer;
140 	} while (true);
141 }
142 
143 
144 status_t
_Repair()145 IdMap::_Repair()
146 {
147 	status_t result = B_OK;
148 
149 	fRequestPort = create_port(1, kRequestPortName);
150 	if (fRequestPort < B_OK)
151 		return fRequestPort;
152 
153 	fReplyPort = create_port(1, kReplyPortName);
154 	if (fReplyPort < B_OK) {
155 		delete_port(fRequestPort);
156 		return fReplyPort;
157 	}
158 
159 	char path[256];
160 	if (find_directory(B_SYSTEM_SERVERS_DIRECTORY, static_cast<dev_t>(-1),
161 		false, path, sizeof(path)) != B_OK) {
162 		delete_port(fReplyPort);
163 		delete_port(fRequestPort);
164 		return B_NAME_NOT_FOUND;
165 	}
166 	strlcat(path, "/nfs4_idmapper_server", sizeof(path));
167 
168 	const char* args[] = { path, NULL };
169 	thread_id thread = load_image_etc(1, args, NULL, B_NORMAL_PRIORITY,
170 		B_SYSTEM_TEAM, 0);
171 	if (thread < B_OK) {
172 		delete_port(fReplyPort);
173 		delete_port(fRequestPort);
174 		return thread;
175 	}
176 
177 	set_port_owner(fRequestPort, thread);
178 	set_port_owner(fReplyPort, thread);
179 
180 	result = resume_thread(thread);
181 	if (result != B_OK) {
182 		kill_thread(thread);
183 		delete_port(fReplyPort);
184 		delete_port(fRequestPort);
185 		return result;
186 	}
187 
188 	return B_OK;
189 }
190 
191