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