]> git.saurik.com Git - apple/libinfo.git/blob - membership.subproj/membership.c
Libinfo-517.tar.gz
[apple/libinfo.git] / membership.subproj / membership.c
1 /*
2 * Copyright (c) 2004-2015 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 <stdlib.h>
24 #include <sys/errno.h>
25 #include <sys/types.h>
26 #include <pwd.h>
27 #include <grp.h>
28 #include <unistd.h>
29 #include <mach/mach.h>
30 #include "membership.h"
31 #include "membershipPriv.h"
32 #include <servers/bootstrap.h>
33 #include <libkern/OSByteOrder.h>
34 #ifdef DS_AVAILABLE
35 #include <xpc/xpc.h>
36 #include <xpc/private.h>
37 #include <os/activity.h>
38 #include <opendirectory/odipc.h>
39 #include <pthread.h>
40 #include <mach-o/dyld_priv.h>
41 #endif
42
43 static const uuid_t _user_compat_prefix = {0xff, 0xff, 0xee, 0xee, 0xdd, 0xdd, 0xcc, 0xcc, 0xbb, 0xbb, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00};
44 static const uuid_t _group_compat_prefix = {0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0x00, 0x00, 0x00, 0x00};
45
46 #define COMPAT_PREFIX_LEN (sizeof(uuid_t) - sizeof(id_t))
47
48 #if DS_AVAILABLE
49 #define MBR_OS_ACTIVITY(_desc) \
50 os_activity_t activity __attribute__((__cleanup__(_mbr_auto_os_release))) = os_activity_create(_desc, OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); \
51 os_activity_scope(activity)
52 #else
53 #define MBR_OS_ACTIVITY(_desc)
54 #endif
55
56 #ifdef DS_AVAILABLE
57
58 int _si_opendirectory_disabled;
59 static xpc_pipe_t __mbr_pipe; /* use accessor */
60 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
61 __private_extern__ xpc_object_t _od_rpc_call(const char *procname, xpc_object_t payload, xpc_pipe_t (*get_pipe)(bool));
62
63 #endif
64
65 #ifdef DS_AVAILABLE
66 static void
67 _mbr_fork_child(void)
68 {
69 if (__mbr_pipe != NULL) {
70 xpc_pipe_invalidate(__mbr_pipe);
71 /* disable release due to 10649340, it will cause a minor leak for each fork without exec */
72 // xpc_release(__mbr_pipe);
73 __mbr_pipe = NULL;
74 }
75
76 pthread_mutex_unlock(&mutex);
77 }
78 #endif
79
80 #ifdef DS_AVAILABLE
81 static void
82 _mbr_fork_prepare(void)
83 {
84 pthread_mutex_lock(&mutex);
85 }
86 #endif
87
88 #ifdef DS_AVAILABLE
89 static void
90 _mbr_fork_parent(void)
91 {
92 pthread_mutex_unlock(&mutex);
93 }
94 #endif
95
96 #ifdef DS_AVAILABLE
97 static void
98 _mbr_auto_os_release(os_activity_t *activity)
99 {
100 os_release(*activity);
101 (*activity) = NULL;
102 }
103
104 XPC_RETURNS_RETAINED
105 static xpc_pipe_t
106 _mbr_xpc_pipe(bool resetPipe)
107 {
108 static dispatch_once_t once;
109 xpc_pipe_t pipe = NULL;
110
111 dispatch_once(&once, ^(void) {
112 char *xbs_disable;
113
114 /* if this is a build environment we ignore opendirectoryd */
115 xbs_disable = getenv("XBS_DISABLE_LIBINFO");
116 if (xbs_disable != NULL && strcmp(xbs_disable, "YES") == 0) {
117 _si_opendirectory_disabled = 1;
118 return;
119 }
120
121 pthread_atfork(_mbr_fork_prepare, _mbr_fork_parent, _mbr_fork_child);
122 });
123
124 if (_si_opendirectory_disabled == 1) {
125 return NULL;
126 }
127
128 pthread_mutex_lock(&mutex);
129 if (resetPipe) {
130 xpc_release(__mbr_pipe);
131 __mbr_pipe = NULL;
132 }
133
134 if (__mbr_pipe == NULL) {
135 if (!dyld_process_is_restricted() && getenv("OD_DEBUG_MODE") != NULL) {
136 __mbr_pipe = xpc_pipe_create(kODMachMembershipPortNameDebug, 0);
137 } else {
138 __mbr_pipe = xpc_pipe_create(kODMachMembershipPortName, XPC_PIPE_FLAG_PRIVILEGED);
139 }
140 }
141
142 if (__mbr_pipe != NULL) pipe = xpc_retain(__mbr_pipe);
143 pthread_mutex_unlock(&mutex);
144
145 return pipe;
146 }
147 #endif
148
149 static bool
150 _mbr_od_available(void)
151 {
152 #if DS_AVAILABLE
153 xpc_pipe_t pipe = _mbr_xpc_pipe(false);
154 if (pipe != NULL) {
155 xpc_release(pipe);
156 return true;
157 }
158 #endif
159 return false;
160 }
161
162 static bool
163 parse_compatibility_uuid(const uuid_t uu, id_t *result, int *rec_type)
164 {
165 id_t tempID;
166
167 if (memcmp(uu, _user_compat_prefix, COMPAT_PREFIX_LEN) == 0) {
168 memcpy(&tempID, &uu[COMPAT_PREFIX_LEN], sizeof(tempID));
169 (*result) = ntohl(tempID);
170 if (rec_type != NULL) {
171 (*rec_type) = MBR_REC_TYPE_USER;
172 }
173 return true;
174 } else if (memcmp(uu, _group_compat_prefix, COMPAT_PREFIX_LEN) == 0) {
175 memcpy(&tempID, &uu[COMPAT_PREFIX_LEN], sizeof(tempID));
176 (*result) = ntohl(tempID);
177 if (rec_type != NULL) {
178 (*rec_type) = MBR_REC_TYPE_GROUP;
179 }
180 return true;
181 }
182 return false;
183 }
184
185 #if !DS_AVAILABLE
186 static bool
187 compatibility_name_for_id(id_t id, int rec_type, char **result)
188 {
189 int bufsize;
190
191 if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1)
192 return false;
193
194 if (rec_type == MBR_REC_TYPE_USER) {
195 char buffer[bufsize];
196 struct passwd pwd, *pwdp = NULL;
197
198 if (getpwuid_r(id, &pwd, buffer, bufsize, &pwdp) != 0 || pwdp == NULL) {
199 return false;
200 }
201 (*result) = strdup(pwd.pw_name);
202 return (*result) != NULL;
203 } else if (rec_type == MBR_REC_TYPE_GROUP) {
204 char buffer[bufsize];
205 struct group grp, *grpp = NULL;
206
207 if (getgrgid_r(id, &grp, buffer, bufsize, &grpp) != 0 || grpp == NULL) {
208 return false;
209 }
210 (*result) = strdup(grp.gr_name);
211 return (*result) != NULL;
212 }
213 return false;
214 }
215
216 static bool
217 compatibility_name_for_uuid(const uuid_t uu, char **result, int *rec_type)
218 {
219 int temp_type;
220 id_t id;
221
222 if (parse_compatibility_uuid(uu, &id, &temp_type) &&
223 compatibility_name_for_id(id, temp_type, result)) {
224 if (rec_type != NULL) {
225 (*rec_type) = temp_type;
226 }
227 return true;
228 } else {
229 return false;
230 }
231 }
232 #endif
233
234 int
235 mbr_identifier_translate(int id_type, const void *identifier, size_t identifier_size, int target_type, void **result, int *rec_type)
236 {
237 #if DS_AVAILABLE
238 xpc_object_t payload, reply;
239 #endif
240 id_t tempID;
241 size_t identifier_len;
242 int rc = EIO;
243
244 if (identifier == NULL || result == NULL || identifier_size == 0) return EIO;
245
246 if (identifier_size == -1) {
247 identifier_size = strlen(identifier);
248 } else {
249 /* 10898647: For types that are known to be strings, send the smallest necessary amount of data. */
250 switch (id_type) {
251 case ID_TYPE_USERNAME:
252 case ID_TYPE_GROUPNAME:
253 case ID_TYPE_GROUP_NFS:
254 case ID_TYPE_USER_NFS:
255 case ID_TYPE_X509_DN:
256 case ID_TYPE_KERBEROS:
257 case ID_TYPE_NAME:
258 identifier_len = strlen(identifier);
259 if (identifier_size > identifier_len) {
260 identifier_size = identifier_len;
261 }
262 break;
263 }
264 }
265
266 switch (target_type) {
267 case ID_TYPE_GID:
268 case ID_TYPE_UID:
269 case ID_TYPE_UID_OR_GID:
270 /* shortcut UUIDs using compatibility prefixes */
271 if (id_type == ID_TYPE_UUID) {
272 id_t *tempRes;
273
274 if (identifier_size != sizeof(uuid_t)) return EINVAL;
275
276 tempRes = malloc(sizeof(*tempRes));
277 if (tempRes == NULL) return ENOMEM;
278
279 if (parse_compatibility_uuid(identifier, tempRes, rec_type)) {
280 (*result) = tempRes;
281 return 0;
282 }
283 }
284 break;
285
286 case ID_TYPE_UUID:
287 /* if this is a UID or GID translation, we shortcut UID/GID 0 */
288 /* or if no OD, we return compatibility UUIDs */
289 switch (id_type) {
290 case ID_TYPE_UID:
291 if (identifier_size != sizeof(tempID)) return EINVAL;
292
293 tempID = *((id_t *) identifier);
294 if ((tempID == 0) || (_mbr_od_available() == false)) {
295 uint8_t *tempUU = malloc(sizeof(uuid_t));
296 if (tempUU == NULL) return ENOMEM;
297 uuid_copy(tempUU, _user_compat_prefix);
298 *((id_t *) &tempUU[COMPAT_PREFIX_LEN]) = htonl(tempID);
299 (*result) = tempUU;
300 if (rec_type != NULL) {
301 (*rec_type) = MBR_REC_TYPE_USER;
302 }
303 return 0;
304 }
305 break;
306
307 case ID_TYPE_GID:
308 if (identifier_size != sizeof(tempID)) return EINVAL;
309
310 tempID = *((id_t *) identifier);
311 if ((tempID == 0) || (_mbr_od_available() == false)) {
312 uint8_t *tempUU = malloc(sizeof(uuid_t));
313 if (tempUU == NULL) return ENOMEM;
314 uuid_copy(tempUU, _group_compat_prefix);
315 *((id_t *) &tempUU[COMPAT_PREFIX_LEN]) = htonl(tempID);
316 (*result) = tempUU;
317 if (rec_type != NULL) {
318 (*rec_type) = MBR_REC_TYPE_GROUP;
319 }
320 return 0;
321 }
322 break;
323 }
324 break;
325
326 case ID_TYPE_USERNAME:
327 case ID_TYPE_GROUPNAME:
328 case ID_TYPE_NAME:
329 #if !DS_AVAILABLE
330 /* Convert compatibility UUIDs to names in-process. */
331 if (id_type == ID_TYPE_UUID) {
332 if (identifier_size != sizeof(uuid_t)) return EINVAL;
333 if (compatibility_name_for_uuid(identifier, (char **)result, rec_type)) {
334 return 0;
335 }
336 } else if (id_type == ID_TYPE_UID) {
337 if (identifier_size != sizeof(tempID)) return EINVAL;
338
339 tempID = *((id_t *) identifier);
340 if (compatibility_name_for_id(tempID, MBR_REC_TYPE_USER, (char **)result)) {
341 if (rec_type != NULL) {
342 (*rec_type) = MBR_REC_TYPE_USER;
343 }
344 return 0;
345 }
346 } else if (id_type == ID_TYPE_GID) {
347 if (identifier_size != sizeof(tempID)) return EINVAL;
348
349 tempID = *((id_t *) identifier);
350 if (compatibility_name_for_id(tempID, MBR_REC_TYPE_GROUP, (char **)result)) {
351 if (rec_type != NULL) {
352 (*rec_type) = MBR_REC_TYPE_GROUP;
353 }
354 return 0;
355 }
356 }
357 #endif
358 break;
359 }
360
361 #if DS_AVAILABLE
362 payload = xpc_dictionary_create(NULL, NULL, 0);
363 if (payload == NULL) return EIO;
364
365 MBR_OS_ACTIVITY("Membership API: translate identifier");
366
367 xpc_dictionary_set_int64(payload, "requesting", target_type);
368 xpc_dictionary_set_int64(payload, "type", id_type);
369 xpc_dictionary_set_data(payload, "identifier", identifier, identifier_size);
370
371 reply = _od_rpc_call("mbr_identifier_translate", payload, _mbr_xpc_pipe);
372 if (reply != NULL) {
373 const void *reply_id;
374 size_t idLen;
375
376 rc = (int) xpc_dictionary_get_int64(reply, "error");
377 if (rc == 0) {
378 reply_id = xpc_dictionary_get_data(reply, "identifier", &idLen);
379 if (reply_id != NULL) {
380 char *identifier = malloc(idLen);
381 if (identifier == NULL) return ENOMEM;
382
383 memcpy(identifier, reply_id, idLen); // should already be NULL terminated, etc.
384 (*result) = identifier;
385
386 if (rec_type != NULL) {
387 (*rec_type) = (int) xpc_dictionary_get_int64(reply, "rectype");
388 }
389 } else {
390 (*result) = NULL;
391 rc = ENOENT;
392 }
393 }
394
395 xpc_release(reply);
396 }
397
398 xpc_release(payload);
399 #endif
400
401 return rc;
402 }
403
404 int
405 mbr_uid_to_uuid(uid_t id, uuid_t uu)
406 {
407 return mbr_identifier_to_uuid(ID_TYPE_UID, &id, sizeof(id), uu);
408 }
409
410 int
411 mbr_gid_to_uuid(gid_t id, uuid_t uu)
412 {
413 return mbr_identifier_to_uuid(ID_TYPE_GID, &id, sizeof(id), uu);
414 }
415
416 int
417 mbr_uuid_to_id(const uuid_t uu, uid_t *id, int *id_type)
418 {
419 id_t *result;
420 int local_type;
421 int rc;
422
423 rc = mbr_identifier_translate(ID_TYPE_UUID, uu, sizeof(uuid_t), ID_TYPE_UID_OR_GID, (void **) &result, &local_type);
424 if (rc == 0) {
425 switch (local_type) {
426 case MBR_REC_TYPE_GROUP:
427 (*id_type) = ID_TYPE_GID;
428 break;
429
430 case MBR_REC_TYPE_USER:
431 (*id_type) = ID_TYPE_UID;
432 break;
433
434 default:
435 (*id_type) = -1;
436 break;
437 }
438
439 (*id) = (*result);
440 free(result);
441 }
442
443 return rc;
444 }
445
446 int
447 mbr_sid_to_uuid(const nt_sid_t *sid, uuid_t uu)
448 {
449 #ifdef DS_AVAILABLE
450 return mbr_identifier_to_uuid(ID_TYPE_SID, sid, sizeof(*sid), uu);
451 #else
452 return EIO;
453 #endif
454 }
455
456 int
457 mbr_identifier_to_uuid(int id_type, const void *identifier, size_t identifier_size, uuid_t uu)
458 {
459 uint8_t *result;
460 int rc;
461
462 rc = mbr_identifier_translate(id_type, identifier, identifier_size, ID_TYPE_UUID, (void **) &result, NULL);
463 if (rc == 0) {
464 uuid_copy(uu, result);
465 free(result);
466 }
467 else if ((rc == EIO) && (_mbr_od_available() == false)) {
468 switch (id_type) {
469 case ID_TYPE_USERNAME:
470 {
471 struct passwd *pw = getpwnam(identifier);
472 if (pw) {
473 rc = mbr_identifier_translate(ID_TYPE_UID, &(pw->pw_uid), sizeof(id_t), ID_TYPE_UUID, (void **) &result, NULL);
474 if (rc == 0) {
475 uuid_copy(uu, result);
476 free(result);
477 }
478 }
479 break;
480 }
481 case ID_TYPE_GROUPNAME:
482 {
483 struct group *grp = getgrnam(identifier);
484 if (grp) {
485 rc = mbr_identifier_translate(ID_TYPE_GID, &(grp->gr_gid), sizeof(id_t), ID_TYPE_UUID, (void **) &result, NULL);
486 if (rc == 0) {
487 uuid_copy(uu, result);
488 free(result);
489 }
490 }
491 break;
492 }
493
494 default:
495 break;
496 }
497 }
498
499 return rc;
500 }
501
502 int
503 mbr_uuid_to_sid_type(const uuid_t uu, nt_sid_t *sid, int *id_type)
504 {
505 #ifdef DS_AVAILABLE
506 void *result;
507 int local_type;
508 int rc;
509
510 rc = mbr_identifier_translate(ID_TYPE_UUID, uu, sizeof(uuid_t), ID_TYPE_SID, &result, &local_type);
511 if (rc == 0) {
512 memcpy(sid, result, sizeof(nt_sid_t));
513 if (id_type != NULL) {
514 /* remap ID types */
515 switch (local_type) {
516 case MBR_REC_TYPE_USER:
517 (*id_type) = SID_TYPE_USER;
518 break;
519
520 case MBR_REC_TYPE_GROUP:
521 (*id_type) = SID_TYPE_GROUP;
522 break;
523
524 default:
525 break;
526 }
527 }
528
529 free(result);
530 }
531
532 return rc;
533 #else
534 return EIO;
535 #endif
536 }
537
538 int
539 mbr_uuid_to_sid(const uuid_t uu, nt_sid_t *sid)
540 {
541 #ifdef DS_AVAILABLE
542 int type, status;
543
544 type = 0;
545
546 status = mbr_uuid_to_sid_type(uu, sid, &type);
547 if (status != 0) return status;
548
549 return 0;
550 #else
551 return EIO;
552 #endif
553 }
554
555 int
556 mbr_check_membership(const uuid_t user, const uuid_t group, int *ismember)
557 {
558 return mbr_check_membership_ext(ID_TYPE_UUID, user, sizeof(uuid_t), ID_TYPE_UUID, group, 0, ismember);
559 }
560
561 int
562 mbr_check_membership_refresh(const uuid_t user, uuid_t group, int *ismember)
563 {
564 return mbr_check_membership_ext(ID_TYPE_UUID, user, sizeof(uuid_t), ID_TYPE_UUID, group, 1, ismember);
565 }
566
567 int
568 mbr_check_membership_ext(int userid_type, const void *userid, size_t userid_size, int groupid_type, const void *groupid, int refresh, int *isMember)
569 {
570 #ifdef DS_AVAILABLE
571 xpc_object_t payload, reply;
572 int rc = 0;
573
574 MBR_OS_ACTIVITY("Membership API: Validating user is a member of group");
575 payload = xpc_dictionary_create(NULL, NULL, 0);
576 if (payload == NULL) return ENOMEM;
577
578 xpc_dictionary_set_int64(payload, "user_idtype", userid_type);
579 xpc_dictionary_set_data(payload, "user_id", userid, userid_size);
580 xpc_dictionary_set_int64(payload, "group_idtype", groupid_type);
581 xpc_dictionary_set_bool(payload, "refresh", refresh);
582
583 switch (groupid_type) {
584 case ID_TYPE_GROUPNAME:
585 case ID_TYPE_GROUP_NFS:
586 xpc_dictionary_set_data(payload, "group_id", groupid, strlen(groupid));
587 break;
588
589 case ID_TYPE_GID:
590 xpc_dictionary_set_data(payload, "group_id", groupid, sizeof(id_t));
591 break;
592
593 case ID_TYPE_SID:
594 xpc_dictionary_set_data(payload, "group_id", groupid, sizeof(nt_sid_t));
595 break;
596
597 case ID_TYPE_UUID:
598 xpc_dictionary_set_data(payload, "group_id", groupid, sizeof(uuid_t));
599 break;
600
601 default:
602 rc = EINVAL;
603 break;
604 }
605
606 if (rc == 0) {
607 reply = _od_rpc_call("mbr_check_membership", payload, _mbr_xpc_pipe);
608 if (reply != NULL) {
609 rc = (int) xpc_dictionary_get_int64(reply, "error");
610 (*isMember) = xpc_dictionary_get_bool(reply, "ismember");
611 xpc_release(reply);
612 } else {
613 rc = EIO;
614 }
615 }
616
617 xpc_release(payload);
618
619 return rc;
620 #else
621 return EIO;
622 #endif
623 }
624
625 int
626 mbr_check_membership_by_id(uuid_t user, gid_t group, int *ismember)
627 {
628 return mbr_check_membership_ext(ID_TYPE_UUID, user, sizeof(uuid_t), ID_TYPE_GID, &group, 0, ismember);
629 }
630
631 int
632 mbr_reset_cache()
633 {
634 #ifdef DS_AVAILABLE
635 MBR_OS_ACTIVITY("Membership API: Flush the membership cache");
636 _od_rpc_call("mbr_cache_flush", NULL, _mbr_xpc_pipe);
637 return 0;
638 #else
639 return EIO;
640 #endif
641 }
642
643 int
644 mbr_user_name_to_uuid(const char *name, uuid_t uu)
645 {
646 return mbr_identifier_to_uuid(ID_TYPE_USERNAME, name, -1, uu);
647 }
648
649 int
650 mbr_group_name_to_uuid(const char *name, uuid_t uu)
651 {
652 return mbr_identifier_to_uuid(ID_TYPE_GROUPNAME, name, -1, uu);
653 }
654
655 int
656 mbr_check_service_membership(const uuid_t user, const char *servicename, int *ismember)
657 {
658 #ifdef DS_AVAILABLE
659 xpc_object_t payload, reply;
660 int result = EIO;
661
662 if (ismember == NULL || servicename == NULL) return EINVAL;
663
664 payload = xpc_dictionary_create(NULL, NULL, 0);
665 if (payload == NULL) return EIO;
666
667 MBR_OS_ACTIVITY("Membership API: Validating user is allowed by service");
668
669 xpc_dictionary_set_data(payload, "user_id", user, sizeof(uuid_t));
670 xpc_dictionary_set_int64(payload, "user_idtype", ID_TYPE_UUID);
671 xpc_dictionary_set_string(payload, "service", servicename);
672
673 reply = _od_rpc_call("mbr_check_service_membership", payload, _mbr_xpc_pipe);
674 if (reply != NULL) {
675 result = (int) xpc_dictionary_get_int64(reply, "error");
676 (*ismember) = xpc_dictionary_get_bool(reply, "ismember");
677
678 xpc_release(reply);
679 } else {
680 (*ismember) = 0;
681 }
682
683 xpc_release(payload);
684
685 return result;
686 #else
687 return EIO;
688 #endif
689 }
690
691 #ifdef DS_AVAILABLE
692 static char *
693 ConvertBytesToDecimal(char *buffer, unsigned long long value)
694 {
695 char *temp;
696 buffer[24] = '\0';
697 buffer[23] = '0';
698
699 if (value == 0)
700 return &buffer[23];
701
702 temp = &buffer[24];
703 while (value != 0)
704 {
705 temp--;
706 *temp = '0' + (value % 10);
707 value /= 10;
708 }
709
710 return temp;
711 }
712 #endif
713
714 int
715 mbr_sid_to_string(const nt_sid_t *sid, char *string)
716 {
717 #ifdef DS_AVAILABLE
718 char *current = string;
719 long long temp = 0;
720 int i;
721 char tempBuffer[25];
722
723 if (sid->sid_authcount > NTSID_MAX_AUTHORITIES) return EINVAL;
724
725 for (i = 0; i < 6; i++)
726 temp = (temp << 8) | sid->sid_authority[i];
727
728 current[0] = 'S';
729 current[1] = '-';
730 current += 2;
731 strcpy(current, ConvertBytesToDecimal(tempBuffer, sid->sid_kind));
732 current = current + strlen(current);
733 *current = '-';
734 current++;
735 strcpy(current, ConvertBytesToDecimal(tempBuffer, temp));
736
737 for(i=0; i < sid->sid_authcount; i++)
738 {
739 current = current + strlen(current);
740 *current = '-';
741 current++;
742 strcpy(current, ConvertBytesToDecimal(tempBuffer, sid->sid_authorities[i]));
743 }
744
745 return 0;
746 #else
747 return EIO;
748 #endif
749 }
750
751 int
752 mbr_string_to_sid(const char *string, nt_sid_t *sid)
753 {
754 #ifdef DS_AVAILABLE
755 char *current = (char *)string+2;
756 int count = 0;
757 long long temp;
758
759 if (string == NULL) return EINVAL;
760
761 memset(sid, 0, sizeof(nt_sid_t));
762 if (string[0] != 'S' || string[1] != '-') return EINVAL;
763
764 sid->sid_kind = strtol(current, &current, 10);
765 if (*current == '\0') return EINVAL;
766 current++;
767 temp = strtoll(current, &current, 10);
768
769 /* convert to BigEndian before copying */
770 temp = OSSwapHostToBigInt64(temp);
771 memcpy(sid->sid_authority, ((char*)&temp)+2, 6);
772 while (*current != '\0' && count < NTSID_MAX_AUTHORITIES)
773 {
774 current++;
775 errno = 0;
776 sid->sid_authorities[count] = (u_int32_t)strtoll(current, &current, 10);
777 if ((sid->sid_authorities[count] == 0) && (errno == EINVAL)) {
778 return EINVAL;
779 }
780 count++;
781 }
782
783 if (*current != '\0') return EINVAL;
784
785 sid->sid_authcount = count;
786
787 return 0;
788 #else
789 return EIO;
790 #endif
791 }
792
793 int
794 mbr_uuid_to_string(const uuid_t uu, char *string)
795 {
796 uuid_unparse_upper(uu, string);
797
798 return 0;
799 }
800
801 int
802 mbr_string_to_uuid(const char *string, uuid_t uu)
803 {
804 return uuid_parse(string, uu);
805 }
806
807 int
808 mbr_set_identifier_ttl(int id_type, const void *identifier, size_t identifier_size, unsigned int seconds)
809 {
810 #ifdef DS_AVAILABLE
811 xpc_object_t payload, reply;
812 int rc = 0;
813
814 payload = xpc_dictionary_create(NULL, NULL, 0);
815 if (payload == NULL) return ENOMEM;
816
817 MBR_OS_ACTIVITY("Membership API: Change the TTL of a given identifier in SystemCache");
818
819 xpc_dictionary_set_int64(payload, "type", id_type);
820 xpc_dictionary_set_data(payload, "identifier", identifier, identifier_size);
821 xpc_dictionary_set_int64(payload, "ttl", seconds);
822
823 if (rc == 0) {
824 reply = _od_rpc_call("mbr_set_identifier_ttl", payload, _mbr_xpc_pipe);
825 if (reply != NULL) {
826 rc = (int) xpc_dictionary_get_int64(reply, "error");
827 xpc_release(reply);
828 } else {
829 rc = EIO;
830 }
831 }
832
833 xpc_release(payload);
834
835 return rc;
836 #else
837 return EIO;
838 #endif
839 }