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