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