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