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