Libinfo-278.tar.gz
[apple/libinfo.git] / membership.subproj / membership.c
1 /*
2 * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23 #include "membership.h"
24 #include "membershipPriv.h"
25 #include "DSmemberdMIG.h"
26 #include "DSmemberdMIG_types.h"
27 #include <sys/errno.h>
28 #include <mach/mach.h>
29 #include <servers/bootstrap.h>
30 #include <stdlib.h>
31 #include <libkern/OSByteOrder.h>
32
33
34 extern mach_port_t _ds_port;
35 extern int _ds_running(void);
36
37 static const uint8_t _mbr_root_uuid[] = {0xff, 0xff, 0xee, 0xee, 0xdd, 0xdd, 0xcc, 0xcc, 0xbb, 0xbb, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00};
38
39 #define MAX_LOOKUP_ATTEMPTS 10
40
41 __private_extern__ uid_t
42 audit_token_uid(audit_token_t a)
43 {
44 /*
45 * This should really call audit_token_to_au32,
46 * but that's in libbsm, not in a Libsystem library.
47 */
48 return (uid_t)a.val[1];
49 }
50
51 static int
52 _mbr_MembershipCall(struct kauth_identity_extlookup *req)
53 {
54 audit_token_t token;
55 kern_return_t status;
56 uint32_t i;
57
58 if (_ds_running() == 0) return EIO;
59 if (_ds_port == MACH_PORT_NULL) return EIO;
60
61 memset(&token, 0, sizeof(audit_token_t));
62
63 status = MIG_SERVER_DIED;
64 for (i = 0; (_ds_port != MACH_PORT_NULL) && (status == MIG_SERVER_DIED) && (i < MAX_LOOKUP_ATTEMPTS); i++)
65 {
66 status = memberdDSmig_MembershipCall(_ds_port, req, &token);
67 if (status == MACH_SEND_INVALID_DEST)
68 {
69 mach_port_mod_refs(mach_task_self(), _ds_port, MACH_PORT_RIGHT_SEND, -1);
70 _ds_port = MACH_PORT_NULL;
71 _ds_running();
72 status = MIG_SERVER_DIED;
73 }
74 }
75
76 if (status != KERN_SUCCESS) return EIO;
77 if (audit_token_uid(token) != 0) return EAUTH;
78
79 return 0;
80 }
81
82 static int
83 _mbr_MapName(char *name, int type, guid_t *uu)
84 {
85 kern_return_t status;
86 audit_token_t token;
87 uint32_t i;
88
89 if (name == NULL) return EINVAL;
90 if (strlen(name) > 255) return EINVAL;
91
92 if (_ds_running() == 0) return EIO;
93 if (_ds_port == MACH_PORT_NULL) return EIO;
94
95 memset(&token, 0, sizeof(audit_token_t));
96
97 status = MIG_SERVER_DIED;
98 for (i = 0; (_ds_port != MACH_PORT_NULL) && (status == MIG_SERVER_DIED) && (i < MAX_LOOKUP_ATTEMPTS); i++)
99 {
100 status = memberdDSmig_MapName(_ds_port, type, name, uu, &token);
101 if (status == KERN_FAILURE) return ENOENT;
102
103 if (status == MACH_SEND_INVALID_DEST)
104 {
105 mach_port_mod_refs(mach_task_self(), _ds_port, MACH_PORT_RIGHT_SEND, -1);
106 _ds_port = MACH_PORT_NULL;
107 _ds_running();
108 status = MIG_SERVER_DIED;
109 }
110 }
111
112 if (status != KERN_SUCCESS) return EIO;
113 if (audit_token_uid(token) != 0) return EAUTH;
114
115 return 0;
116 }
117
118 static int
119 _mbr_ClearCache()
120 {
121 kern_return_t status;
122 uint32_t i;
123
124 if (_ds_running() == 0) return EIO;
125 if (_ds_port == MACH_PORT_NULL) return EIO;
126
127 status = MIG_SERVER_DIED;
128 for (i = 0; (_ds_port != MACH_PORT_NULL) && (status == MIG_SERVER_DIED) && (i < MAX_LOOKUP_ATTEMPTS); i++)
129 {
130 status = memberdDSmig_ClearCache(_ds_port);
131 if (status == MACH_SEND_INVALID_DEST)
132 {
133 mach_port_mod_refs(mach_task_self(), _ds_port, MACH_PORT_RIGHT_SEND, -1);
134 _ds_port = MACH_PORT_NULL;
135 _ds_running();
136 status = MIG_SERVER_DIED;
137 }
138 }
139
140 if (status != KERN_SUCCESS) return EIO;
141
142 return 0;
143 }
144
145 int mbr_uid_to_uuid(uid_t id, uuid_t uu)
146 {
147 struct kauth_identity_extlookup request;
148 int status;
149
150 if (id == 0)
151 {
152 memcpy(uu, _mbr_root_uuid, sizeof(uuid_t));
153 return 0;
154 }
155
156 /* used as a byte order field */
157 request.el_seqno = 1;
158 request.el_flags = KAUTH_EXTLOOKUP_VALID_UID | KAUTH_EXTLOOKUP_WANT_UGUID;
159 request.el_uid = id;
160
161 status = _mbr_MembershipCall(&request);
162 if (status != 0) return status;
163 if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_UGUID) == 0) return ENOENT;
164
165 memcpy(uu, &request.el_uguid, sizeof(guid_t));
166 return 0;
167 }
168
169 int mbr_gid_to_uuid(gid_t id, uuid_t uu)
170 {
171 struct kauth_identity_extlookup request;
172 int status;
173
174 request.el_seqno = 1;
175 request.el_flags = KAUTH_EXTLOOKUP_VALID_GID | KAUTH_EXTLOOKUP_WANT_GGUID;
176 request.el_gid = id;
177
178 status = _mbr_MembershipCall(&request);
179 if (status != 0) return status;
180 if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_GGUID) == 0) return ENOENT;
181
182 memcpy(uu, &request.el_gguid, sizeof(guid_t));
183 return 0;
184 }
185
186 int mbr_uuid_to_id(const uuid_t uu, uid_t *id, int *id_type)
187 {
188 struct kauth_identity_extlookup request;
189 int status;
190
191 if (id == NULL) return EIO;
192 if (id_type == NULL) return EIO;
193
194 if (!memcmp(uu, _mbr_root_uuid, sizeof(uuid_t)))
195 {
196 *id = 0;
197 *id_type = ID_TYPE_UID;
198 return 0;
199 }
200
201 request.el_seqno = 1;
202 request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GGUID | KAUTH_EXTLOOKUP_WANT_UID | KAUTH_EXTLOOKUP_WANT_GID;
203 memcpy(&request.el_uguid, uu, sizeof(guid_t));
204 memcpy(&request.el_gguid, uu, sizeof(guid_t));
205
206 status = _mbr_MembershipCall(&request);
207 if (status != 0) return status;
208
209 if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_UID) != 0)
210 {
211 *id = request.el_uid;
212 *id_type = ID_TYPE_UID;
213 }
214 else if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_GID) != 0)
215 {
216 *id = request.el_gid;
217 *id_type = ID_TYPE_GID;
218 }
219 else
220 {
221 return ENOENT;
222 }
223
224 return 0;
225 }
226
227 int mbr_sid_to_uuid(const nt_sid_t *sid, uuid_t uu)
228 {
229 struct kauth_identity_extlookup request;
230 int status;
231
232 request.el_seqno = 1;
233 request.el_flags = KAUTH_EXTLOOKUP_VALID_GSID | KAUTH_EXTLOOKUP_WANT_GGUID;
234 memset(&request.el_gsid, 0, sizeof(ntsid_t));
235 memcpy(&request.el_gsid, sid, KAUTH_NTSID_SIZE(sid));
236
237 status = _mbr_MembershipCall(&request);
238 if (status != 0) return status;
239 if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_GGUID) == 0) return ENOENT;
240
241 memcpy(uu, &request.el_gguid, sizeof(guid_t));
242 return 0;
243 }
244
245 int mbr_uuid_to_sid_type(const uuid_t uu, nt_sid_t *sid, int *id_type)
246 {
247 struct kauth_identity_extlookup request;
248 int status;
249
250 request.el_seqno = 1;
251 request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GGUID | KAUTH_EXTLOOKUP_WANT_USID | KAUTH_EXTLOOKUP_WANT_GSID;
252 memcpy(&request.el_uguid, uu, sizeof(guid_t));
253 memcpy(&request.el_gguid, uu, sizeof(guid_t));
254
255 status = _mbr_MembershipCall(&request);
256 if (status != 0) return status;
257
258 if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_USID) != 0)
259 {
260 *id_type = SID_TYPE_USER;
261 memcpy(sid, &request.el_usid, sizeof(nt_sid_t));
262 }
263 else if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_GSID) != 0)
264 {
265 *id_type = SID_TYPE_GROUP;
266 memcpy(sid, &request.el_gsid, sizeof(nt_sid_t));
267 }
268 else
269 {
270 return ENOENT;
271 }
272
273 return 0;
274 }
275
276 int mbr_uuid_to_sid(const uuid_t uu, nt_sid_t *sid)
277 {
278 int type, status;
279
280 type = 0;
281
282 status = mbr_uuid_to_sid_type(uu, sid, &type);
283 if (status != 0) return status;
284
285 return 0;
286 }
287
288 int mbr_check_membership(uuid_t user, uuid_t group, int *ismember)
289 {
290 struct kauth_identity_extlookup request;
291 int status;
292
293 request.el_seqno = 1;
294 request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GGUID | KAUTH_EXTLOOKUP_WANT_MEMBERSHIP;
295 memcpy(&request.el_uguid, user, sizeof(guid_t));
296 memcpy(&request.el_gguid, group, sizeof(guid_t));
297
298 status = _mbr_MembershipCall(&request);
299 if (status != 0) return status;
300 if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_MEMBERSHIP) == 0) return ENOENT;
301
302 *ismember = ((request.el_flags & KAUTH_EXTLOOKUP_ISMEMBER) != 0);
303 return 0;
304 }
305
306 int mbr_check_membership_refresh(const uuid_t user, uuid_t group, int *ismember)
307 {
308 struct kauth_identity_extlookup request;
309 int status;
310
311 request.el_seqno = 1;
312 request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GGUID | KAUTH_EXTLOOKUP_WANT_MEMBERSHIP | (1<<15);
313 memcpy(&request.el_uguid, user, sizeof(guid_t));
314 memcpy(&request.el_gguid, group, sizeof(guid_t));
315
316 status = _mbr_MembershipCall(&request);
317 if (status != 0) return status;
318 if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_MEMBERSHIP) == 0) return ENOENT;
319
320 *ismember = ((request.el_flags & KAUTH_EXTLOOKUP_ISMEMBER) != 0);
321 return 0;
322 }
323
324 int mbr_check_membership_by_id(uuid_t user, gid_t group, int *ismember)
325 {
326 struct kauth_identity_extlookup request;
327 int status;
328
329 request.el_seqno = 1;
330 request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GID | KAUTH_EXTLOOKUP_WANT_MEMBERSHIP;
331 memcpy(&request.el_uguid, user, sizeof(guid_t));
332 request.el_gid = group;
333
334 status = _mbr_MembershipCall(&request);
335 if (status != 0) return status;
336 if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_MEMBERSHIP) == 0) return ENOENT;
337
338 *ismember = ((request.el_flags & KAUTH_EXTLOOKUP_ISMEMBER) != 0);
339 return 0;
340 }
341
342 int mbr_reset_cache()
343 {
344 return _mbr_ClearCache();
345 }
346
347 int mbr_user_name_to_uuid(const char *name, uuid_t uu)
348 {
349 return _mbr_MapName((char *)name, 1, (guid_t *)uu);
350 }
351
352 int mbr_group_name_to_uuid(const char *name, uuid_t uu)
353 {
354 return _mbr_MapName((char *)name, 0, (guid_t *)uu);
355 }
356
357 int mbr_check_service_membership(const uuid_t user, const char *servicename, int *ismember)
358 {
359 char *prefix = "com.apple.access_";
360 char *all_services = "com.apple.access_all_services";
361 char groupName[256];
362 uuid_t group_uu;
363 int result, dummy;
364
365 if (servicename == NULL) return EINVAL;
366 if (strlen(servicename) > 255 - strlen(prefix)) return EINVAL;
367
368 /* start by checking "all services" */
369 result = mbr_group_name_to_uuid(all_services, group_uu);
370
371 if (result == EAUTH) return result;
372
373 if (result == ENOENT)
374 {
375 /* all_services group didn't exist, check individual group */
376 memcpy(groupName, prefix, strlen(prefix));
377 strcpy(groupName + strlen(prefix), servicename);
378 result = mbr_group_name_to_uuid(groupName, group_uu);
379 }
380
381 if (result == 0)
382 {
383 result = mbr_check_membership_refresh(user, group_uu, ismember);
384 }
385 else if (result == EAUTH)
386 {
387 return result;
388 }
389 else
390 {
391 /* just force cache update with bogus membership check */
392 memset(group_uu, 0, sizeof(group_uu));
393 mbr_check_membership_refresh(user, group_uu, &dummy);
394 }
395
396 return result;
397 }
398
399 static char *ConvertBytesToDecimal(char *buffer, unsigned long long value)
400 {
401 char *temp;
402 buffer[24] = '\0';
403 buffer[23] = '0';
404
405 if (value == 0)
406 return &buffer[23];
407
408 temp = &buffer[24];
409 while (value != 0)
410 {
411 temp--;
412 *temp = '0' + (value % 10);
413 value /= 10;
414 }
415
416 return temp;
417 }
418
419 int mbr_sid_to_string(const nt_sid_t *sid, char *string)
420 {
421 char *current = string;
422 long long temp = 0;
423 int i;
424 char tempBuffer[25];
425
426 if (sid->sid_authcount > NTSID_MAX_AUTHORITIES) return EINVAL;
427
428 for (i = 0; i < 6; i++)
429 temp = (temp << 8) | sid->sid_authority[i];
430
431 current[0] = 'S';
432 current[1] = '-';
433 current += 2;
434 strcpy(current, ConvertBytesToDecimal(tempBuffer, sid->sid_kind));
435 current = current + strlen(current);
436 *current = '-';
437 current++;
438 strcpy(current, ConvertBytesToDecimal(tempBuffer, temp));
439
440 for(i=0; i < sid->sid_authcount; i++)
441 {
442 current = current + strlen(current);
443 *current = '-';
444 current++;
445 strcpy(current, ConvertBytesToDecimal(tempBuffer, sid->sid_authorities[i]));
446 }
447
448 return 0;
449 }
450
451 int mbr_string_to_sid(const char *string, nt_sid_t *sid)
452 {
453 char *current = (char *)string+2;
454 int count = 0;
455 long long temp;
456
457 if (string == NULL) return EINVAL;
458
459 memset(sid, 0, sizeof(nt_sid_t));
460 if (string[0] != 'S' || string[1] != '-') return EINVAL;
461
462 sid->sid_kind = strtol(current, &current, 10);
463 if (*current == '\0') return EINVAL;
464 current++;
465 temp = strtoll(current, &current, 10);
466
467 /* convert to BigEndian before copying */
468 temp = OSSwapHostToBigInt64(temp);
469 memcpy(sid->sid_authority, ((char*)&temp)+2, 6);
470 while (*current != '\0' && count < NTSID_MAX_AUTHORITIES)
471 {
472 current++;
473 sid->sid_authorities[count] = strtol(current, &current, 10);
474 count++;
475 }
476
477 if (*current != '\0') return EINVAL;
478
479 sid->sid_authcount = count;
480
481 return 0;
482 }
483
484 static void ConvertBytesToHex(char **string, char **data, int numBytes)
485 {
486 int i;
487
488 for (i=0; i < numBytes; i++)
489 {
490 unsigned char hi = ((**data) >> 4) & 0xf;
491 unsigned char low = (**data) & 0xf;
492 if (hi < 10)
493 **string = '0' + hi;
494 else
495 **string = 'A' + hi - 10;
496
497 (*string)++;
498
499 if (low < 10)
500 **string = '0' + low;
501 else
502 **string = 'A' + low - 10;
503
504 (*string)++;
505 (*data)++;
506 }
507 }
508
509 int mbr_uuid_to_string(const uuid_t uu, char *string)
510 {
511 char *guid = (char*)uu;
512 char *strPtr = string;
513 ConvertBytesToHex(&strPtr, &guid, 4);
514 *strPtr = '-'; strPtr++;
515 ConvertBytesToHex(&strPtr, &guid, 2);
516 *strPtr = '-'; strPtr++;
517 ConvertBytesToHex(&strPtr, &guid, 2);
518 *strPtr = '-'; strPtr++;
519 ConvertBytesToHex(&strPtr, &guid, 2);
520 *strPtr = '-'; strPtr++;
521 ConvertBytesToHex(&strPtr, &guid, 6);
522 *strPtr = '\0';
523
524 return 0;
525 }
526
527 int mbr_string_to_uuid(const char *string, uuid_t uu)
528 {
529 short dataIndex = 0;
530 int isFirstNibble = 1;
531
532 if (string == NULL) return EINVAL;
533 if (strlen(string) > MBR_UU_STRING_SIZE) return EINVAL;
534
535 while (*string != '\0' && dataIndex < 16)
536 {
537 char nibble;
538
539 if (*string >= '0' && *string <= '9')
540 nibble = *string - '0';
541 else if (*string >= 'A' && *string <= 'F')
542 nibble = *string - 'A' + 10;
543 else if (*string >= 'a' && *string <= 'f')
544 nibble = *string - 'a' + 10;
545 else
546 {
547 if (*string != '-')
548 return EINVAL;
549 string++;
550 continue;
551 }
552
553 if (isFirstNibble)
554 {
555 uu[dataIndex] = nibble << 4;
556 isFirstNibble = 0;
557 }
558 else
559 {
560 uu[dataIndex] |= nibble;
561 dataIndex++;
562 isFirstNibble = 1;
563 }
564
565 string++;
566 }
567
568 if (dataIndex != 16) return EINVAL;
569
570 return 0;
571 }
572