Libinfo-278.0.3.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 | KAUTH_EXTLOOKUP_VALID_USID | KAUTH_EXTLOOKUP_WANT_UGUID;
234 memset(&request.el_gsid, 0, sizeof(ntsid_t));
235 memcpy(&request.el_gsid, sid, KAUTH_NTSID_SIZE(sid));
236 memset(&request.el_usid, 0, sizeof(ntsid_t));
237 memcpy(&request.el_usid, sid, KAUTH_NTSID_SIZE(sid));
238
239 status = _mbr_MembershipCall(&request);
240 if (status != 0) return status;
241
242 if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_GGUID) != 0) memcpy(uu, &request.el_gguid, sizeof(guid_t));
243 else if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_UGUID) != 0) memcpy(uu, &request.el_uguid, sizeof(guid_t));
244 else return ENOENT;
245
246 return 0;
247 }
248
249 int mbr_uuid_to_sid_type(const uuid_t uu, nt_sid_t *sid, int *id_type)
250 {
251 struct kauth_identity_extlookup request;
252 int status;
253
254 request.el_seqno = 1;
255 request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GGUID | KAUTH_EXTLOOKUP_WANT_USID | KAUTH_EXTLOOKUP_WANT_GSID;
256 memcpy(&request.el_uguid, uu, sizeof(guid_t));
257 memcpy(&request.el_gguid, uu, sizeof(guid_t));
258
259 status = _mbr_MembershipCall(&request);
260 if (status != 0) return status;
261
262 if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_USID) != 0)
263 {
264 *id_type = SID_TYPE_USER;
265 memcpy(sid, &request.el_usid, sizeof(nt_sid_t));
266 }
267 else if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_GSID) != 0)
268 {
269 *id_type = SID_TYPE_GROUP;
270 memcpy(sid, &request.el_gsid, sizeof(nt_sid_t));
271 }
272 else
273 {
274 return ENOENT;
275 }
276
277 return 0;
278 }
279
280 int mbr_uuid_to_sid(const uuid_t uu, nt_sid_t *sid)
281 {
282 int type, status;
283
284 type = 0;
285
286 status = mbr_uuid_to_sid_type(uu, sid, &type);
287 if (status != 0) return status;
288
289 return 0;
290 }
291
292 int mbr_check_membership(uuid_t user, uuid_t group, int *ismember)
293 {
294 struct kauth_identity_extlookup request;
295 int status;
296
297 request.el_seqno = 1;
298 request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GGUID | KAUTH_EXTLOOKUP_WANT_MEMBERSHIP;
299 memcpy(&request.el_uguid, user, sizeof(guid_t));
300 memcpy(&request.el_gguid, group, sizeof(guid_t));
301
302 status = _mbr_MembershipCall(&request);
303 if (status != 0) return status;
304 if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_MEMBERSHIP) == 0) return ENOENT;
305
306 *ismember = ((request.el_flags & KAUTH_EXTLOOKUP_ISMEMBER) != 0);
307 return 0;
308 }
309
310 int mbr_check_membership_refresh(const uuid_t user, uuid_t group, int *ismember)
311 {
312 struct kauth_identity_extlookup request;
313 int status;
314
315 request.el_seqno = 1;
316 request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GGUID | KAUTH_EXTLOOKUP_WANT_MEMBERSHIP | (1<<15);
317 memcpy(&request.el_uguid, user, sizeof(guid_t));
318 memcpy(&request.el_gguid, group, sizeof(guid_t));
319
320 status = _mbr_MembershipCall(&request);
321 if (status != 0) return status;
322 if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_MEMBERSHIP) == 0) return ENOENT;
323
324 *ismember = ((request.el_flags & KAUTH_EXTLOOKUP_ISMEMBER) != 0);
325 return 0;
326 }
327
328 int mbr_check_membership_by_id(uuid_t user, gid_t group, int *ismember)
329 {
330 struct kauth_identity_extlookup request;
331 int status;
332
333 request.el_seqno = 1;
334 request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GID | KAUTH_EXTLOOKUP_WANT_MEMBERSHIP;
335 memcpy(&request.el_uguid, user, sizeof(guid_t));
336 request.el_gid = group;
337
338 status = _mbr_MembershipCall(&request);
339 if (status != 0) return status;
340 if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_MEMBERSHIP) == 0) return ENOENT;
341
342 *ismember = ((request.el_flags & KAUTH_EXTLOOKUP_ISMEMBER) != 0);
343 return 0;
344 }
345
346 int mbr_reset_cache()
347 {
348 return _mbr_ClearCache();
349 }
350
351 int mbr_user_name_to_uuid(const char *name, uuid_t uu)
352 {
353 return _mbr_MapName((char *)name, 1, (guid_t *)uu);
354 }
355
356 int mbr_group_name_to_uuid(const char *name, uuid_t uu)
357 {
358 return _mbr_MapName((char *)name, 0, (guid_t *)uu);
359 }
360
361 int mbr_check_service_membership(const uuid_t user, const char *servicename, int *ismember)
362 {
363 char *prefix = "com.apple.access_";
364 char *all_services = "com.apple.access_all_services";
365 char groupName[256];
366 uuid_t group_uu;
367 int result, dummy;
368
369 if (servicename == NULL) return EINVAL;
370 if (strlen(servicename) > 255 - strlen(prefix)) return EINVAL;
371
372 /* start by checking "all services" */
373 result = mbr_group_name_to_uuid(all_services, group_uu);
374
375 if (result == EAUTH) return result;
376
377 if (result == ENOENT)
378 {
379 /* all_services group didn't exist, check individual group */
380 memcpy(groupName, prefix, strlen(prefix));
381 strcpy(groupName + strlen(prefix), servicename);
382 result = mbr_group_name_to_uuid(groupName, group_uu);
383 }
384
385 if (result == 0)
386 {
387 result = mbr_check_membership_refresh(user, group_uu, ismember);
388 }
389 else if (result == EAUTH)
390 {
391 return result;
392 }
393 else
394 {
395 /* just force cache update with bogus membership check */
396 memset(group_uu, 0, sizeof(group_uu));
397 mbr_check_membership_refresh(user, group_uu, &dummy);
398 }
399
400 return result;
401 }
402
403 static char *ConvertBytesToDecimal(char *buffer, unsigned long long value)
404 {
405 char *temp;
406 buffer[24] = '\0';
407 buffer[23] = '0';
408
409 if (value == 0)
410 return &buffer[23];
411
412 temp = &buffer[24];
413 while (value != 0)
414 {
415 temp--;
416 *temp = '0' + (value % 10);
417 value /= 10;
418 }
419
420 return temp;
421 }
422
423 int mbr_sid_to_string(const nt_sid_t *sid, char *string)
424 {
425 char *current = string;
426 long long temp = 0;
427 int i;
428 char tempBuffer[25];
429
430 if (sid->sid_authcount > NTSID_MAX_AUTHORITIES) return EINVAL;
431
432 for (i = 0; i < 6; i++)
433 temp = (temp << 8) | sid->sid_authority[i];
434
435 current[0] = 'S';
436 current[1] = '-';
437 current += 2;
438 strcpy(current, ConvertBytesToDecimal(tempBuffer, sid->sid_kind));
439 current = current + strlen(current);
440 *current = '-';
441 current++;
442 strcpy(current, ConvertBytesToDecimal(tempBuffer, temp));
443
444 for(i=0; i < sid->sid_authcount; i++)
445 {
446 current = current + strlen(current);
447 *current = '-';
448 current++;
449 strcpy(current, ConvertBytesToDecimal(tempBuffer, sid->sid_authorities[i]));
450 }
451
452 return 0;
453 }
454
455 int mbr_string_to_sid(const char *string, nt_sid_t *sid)
456 {
457 char *current = (char *)string+2;
458 int count = 0;
459 long long temp;
460
461 if (string == NULL) return EINVAL;
462
463 memset(sid, 0, sizeof(nt_sid_t));
464 if (string[0] != 'S' || string[1] != '-') return EINVAL;
465
466 sid->sid_kind = strtol(current, &current, 10);
467 if (*current == '\0') return EINVAL;
468 current++;
469 temp = strtoll(current, &current, 10);
470
471 /* convert to BigEndian before copying */
472 temp = OSSwapHostToBigInt64(temp);
473 memcpy(sid->sid_authority, ((char*)&temp)+2, 6);
474 while (*current != '\0' && count < NTSID_MAX_AUTHORITIES)
475 {
476 current++;
477 sid->sid_authorities[count] = (u_int32_t)strtoll(current, &current, 10);
478 count++;
479 }
480
481 if (*current != '\0') return EINVAL;
482
483 sid->sid_authcount = count;
484
485 return 0;
486 }
487
488 static void ConvertBytesToHex(char **string, char **data, int numBytes)
489 {
490 int i;
491
492 for (i=0; i < numBytes; i++)
493 {
494 unsigned char hi = ((**data) >> 4) & 0xf;
495 unsigned char low = (**data) & 0xf;
496 if (hi < 10)
497 **string = '0' + hi;
498 else
499 **string = 'A' + hi - 10;
500
501 (*string)++;
502
503 if (low < 10)
504 **string = '0' + low;
505 else
506 **string = 'A' + low - 10;
507
508 (*string)++;
509 (*data)++;
510 }
511 }
512
513 int mbr_uuid_to_string(const uuid_t uu, char *string)
514 {
515 char *guid = (char*)uu;
516 char *strPtr = string;
517 ConvertBytesToHex(&strPtr, &guid, 4);
518 *strPtr = '-'; strPtr++;
519 ConvertBytesToHex(&strPtr, &guid, 2);
520 *strPtr = '-'; strPtr++;
521 ConvertBytesToHex(&strPtr, &guid, 2);
522 *strPtr = '-'; strPtr++;
523 ConvertBytesToHex(&strPtr, &guid, 2);
524 *strPtr = '-'; strPtr++;
525 ConvertBytesToHex(&strPtr, &guid, 6);
526 *strPtr = '\0';
527
528 return 0;
529 }
530
531 int mbr_string_to_uuid(const char *string, uuid_t uu)
532 {
533 short dataIndex = 0;
534 int isFirstNibble = 1;
535
536 if (string == NULL) return EINVAL;
537 if (strlen(string) > MBR_UU_STRING_SIZE) return EINVAL;
538
539 while (*string != '\0' && dataIndex < 16)
540 {
541 char nibble;
542
543 if (*string >= '0' && *string <= '9')
544 nibble = *string - '0';
545 else if (*string >= 'A' && *string <= 'F')
546 nibble = *string - 'A' + 10;
547 else if (*string >= 'a' && *string <= 'f')
548 nibble = *string - 'a' + 10;
549 else
550 {
551 if (*string != '-')
552 return EINVAL;
553 string++;
554 continue;
555 }
556
557 if (isFirstNibble)
558 {
559 uu[dataIndex] = nibble << 4;
560 isFirstNibble = 0;
561 }
562 else
563 {
564 uu[dataIndex] |= nibble;
565 dataIndex++;
566 isFirstNibble = 1;
567 }
568
569 string++;
570 }
571
572 if (dataIndex != 16) return EINVAL;
573
574 return 0;
575 }
576