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
20IdMap*	gIdMapper		= NULL;
21mutex	gIdMapperLock;
22
23
24IdMap::IdMap()
25{
26	mutex_init(&fLock, NULL);
27	fInitStatus = _Repair();
28}
29
30
31IdMap::~IdMap()
32{
33	delete_port(fRequestPort);
34	delete_port(fReplyPort);
35	mutex_destroy(&fLock);
36}
37
38
39uid_t
40IdMap::GetUserId(const char* owner)
41{
42	ASSERT(owner != NULL);
43	return _GetValue<uid_t>(owner, MsgNameToUID);
44}
45
46
47gid_t
48IdMap::GetGroupId(const char* ownerGroup)
49{
50	ASSERT(ownerGroup != NULL);
51	return _GetValue<gid_t>(ownerGroup, MsgNameToGID);
52}
53
54
55char*
56IdMap::GetOwner(uid_t user)
57{
58	return reinterpret_cast<char*>(_GetBuffer(user, MsgUIDToName));
59}
60
61
62char*
63IdMap::GetOwnerGroup(gid_t group)
64{
65	return reinterpret_cast<char*>(_GetBuffer(group, MsgGIDToName));
66}
67
68
69template<typename T>
70T
71IdMap::_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
102template<typename T>
103void*
104IdMap::_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
144status_t
145IdMap::_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