1 /* 2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <grp.h> 7 8 #include <errno.h> 9 #include <string.h> 10 #include <unistd.h> 11 12 #include <new> 13 14 #include <OS.h> 15 16 #include <errno_private.h> 17 #include <libroot_private.h> 18 #include <RegistrarDefs.h> 19 #include <user_group.h> 20 21 #include <util/KMessage.h> 22 23 24 using BPrivate::UserGroupLocker; 25 using BPrivate::relocate_pointer; 26 27 28 static KMessage sGroupDBReply; 29 static group** sGroupEntries = NULL; 30 static size_t sGroupEntryCount = 0; 31 static size_t sIterationIndex = 0; 32 33 static struct group sGroupBuffer; 34 static char sGroupStringBuffer[MAX_GROUP_BUFFER_SIZE]; 35 36 37 static status_t 38 query_group_entry(const char* name, gid_t _gid, struct group *group, 39 char *buffer, size_t bufferSize, struct group **_result) 40 { 41 *_result = NULL; 42 43 KMessage message(BPrivate::B_REG_GET_GROUP); 44 if (name) 45 message.AddString("name", name); 46 else 47 message.AddInt32("gid", _gid); 48 49 KMessage reply; 50 status_t error = BPrivate::send_authentication_request_to_registrar(message, 51 reply); 52 if (error != B_OK) { 53 return error == ENOENT ? B_OK : error; 54 } 55 56 int32 gid; 57 const char* password; 58 59 if ((error = reply.FindInt32("gid", &gid)) != B_OK 60 || (error = reply.FindString("name", &name)) != B_OK 61 || (error = reply.FindString("password", &password)) != B_OK) { 62 return error; 63 } 64 65 const char* members[MAX_GROUP_MEMBER_COUNT]; 66 int memberCount = 0; 67 for (int32 index = 0; memberCount < MAX_GROUP_MEMBER_COUNT; index++) { 68 if (reply.FindString("members", index, members + memberCount) != B_OK) 69 break; 70 memberCount++; 71 } 72 73 error = BPrivate::copy_group_to_buffer(name, password, gid, members, 74 memberCount, group, buffer, bufferSize); 75 if (error == B_OK) 76 *_result = group; 77 78 return error; 79 } 80 81 82 static status_t 83 init_group_db() 84 { 85 if (sGroupEntries != NULL) 86 return B_OK; 87 88 // ask the registrar 89 KMessage message(BPrivate::B_REG_GET_GROUP_DB); 90 status_t error = BPrivate::send_authentication_request_to_registrar(message, 91 sGroupDBReply); 92 if (error != B_OK) 93 return error; 94 95 // unpack the reply 96 int32 count; 97 group** entries; 98 int32 numBytes; 99 if ((error = sGroupDBReply.FindInt32("count", &count)) != B_OK 100 || (error = sGroupDBReply.FindData("entries", B_RAW_TYPE, 101 (const void**)&entries, &numBytes)) != B_OK) { 102 return error; 103 } 104 105 // relocate the entries 106 addr_t baseAddress = (addr_t)entries; 107 for (int32 i = 0; i < count; i++) { 108 group* entry = relocate_pointer(baseAddress, entries[i]); 109 relocate_pointer(baseAddress, entry->gr_name); 110 relocate_pointer(baseAddress, entry->gr_passwd); 111 relocate_pointer(baseAddress, entry->gr_mem); 112 int32 k = 0; 113 for (; entry->gr_mem[k] != (void*)-1; k++) 114 relocate_pointer(baseAddress, entry->gr_mem[k]); 115 entry->gr_mem[k] = NULL; 116 } 117 118 sGroupEntries = entries; 119 sGroupEntryCount = count; 120 121 return B_OK; 122 } 123 124 125 // #pragma mark - 126 127 128 struct group* 129 getgrent(void) 130 { 131 struct group* result = NULL; 132 int status = getgrent_r(&sGroupBuffer, sGroupStringBuffer, 133 sizeof(sGroupStringBuffer), &result); 134 if (status != 0) 135 __set_errno(status); 136 return result; 137 } 138 139 140 int 141 getgrent_r(struct group* group, char* buffer, size_t bufferSize, 142 struct group** _result) 143 { 144 UserGroupLocker _; 145 146 int status = B_NO_MEMORY; 147 148 *_result = NULL; 149 150 if ((status = init_group_db()) == B_OK) { 151 if (sIterationIndex >= sGroupEntryCount) 152 return ENOENT; 153 154 status = BPrivate::copy_group_to_buffer( 155 sGroupEntries[sIterationIndex], group, buffer, bufferSize); 156 157 if (status == B_OK) { 158 sIterationIndex++; 159 *_result = group; 160 } 161 } 162 163 return status; 164 } 165 166 167 void 168 setgrent(void) 169 { 170 UserGroupLocker _; 171 172 sIterationIndex = 0; 173 } 174 175 176 void 177 endgrent(void) 178 { 179 UserGroupLocker locker; 180 181 sGroupDBReply.Unset(); 182 sGroupEntries = NULL; 183 sGroupEntryCount = 0; 184 sIterationIndex = 0; 185 } 186 187 188 struct group * 189 getgrnam(const char *name) 190 { 191 struct group* result = NULL; 192 int status = getgrnam_r(name, &sGroupBuffer, sGroupStringBuffer, 193 sizeof(sGroupStringBuffer), &result); 194 if (status != 0) 195 __set_errno(status); 196 return result; 197 } 198 199 200 int 201 getgrnam_r(const char *name, struct group *group, char *buffer, 202 size_t bufferSize, struct group **_result) 203 { 204 return query_group_entry(name, 0, group, buffer, bufferSize, _result); 205 } 206 207 208 struct group * 209 getgrgid(gid_t gid) 210 { 211 struct group* result = NULL; 212 int status = getgrgid_r(gid, &sGroupBuffer, sGroupStringBuffer, 213 sizeof(sGroupStringBuffer), &result); 214 if (status != 0) 215 __set_errno(status); 216 return result; 217 } 218 219 220 int 221 getgrgid_r(gid_t gid, struct group *group, char *buffer, 222 size_t bufferSize, struct group **_result) 223 { 224 return query_group_entry(NULL, gid, group, buffer, bufferSize, _result); 225 } 226 227 228 int 229 getgrouplist(const char* user, gid_t baseGroup, gid_t* groupList, 230 int* groupCount) 231 { 232 int maxGroupCount = *groupCount; 233 *groupCount = 0; 234 235 status_t error = B_OK; 236 237 // prepare request 238 KMessage message(BPrivate::B_REG_GET_USER_GROUPS); 239 if (message.AddString("name", user) != B_OK 240 || message.AddInt32("max count", maxGroupCount) != B_OK) { 241 return -1; 242 } 243 244 // send request 245 KMessage reply; 246 error = BPrivate::send_authentication_request_to_registrar(message, reply); 247 if (error != B_OK) 248 return -1; 249 250 // unpack reply 251 int32 count; 252 const int32* groups; 253 int32 groupsSize; 254 if (reply.FindInt32("count", &count) != B_OK 255 || reply.FindData("groups", B_INT32_TYPE, (const void**)&groups, 256 &groupsSize) != B_OK) { 257 return -1; 258 } 259 260 memcpy(groupList, groups, groupsSize); 261 *groupCount = count; 262 263 // add the base group 264 if (*groupCount < maxGroupCount) 265 groupList[*groupCount] = baseGroup; 266 ++*groupCount; 267 268 return *groupCount <= maxGroupCount ? *groupCount : -1; 269 } 270 271 272 int 273 initgroups(const char* user, gid_t baseGroup) 274 { 275 gid_t groups[NGROUPS_MAX + 1]; 276 int groupCount = NGROUPS_MAX + 1; 277 if (getgrouplist(user, baseGroup, groups, &groupCount) < 0) 278 return -1; 279 280 return setgroups(groupCount, groups); 281 } 282