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