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