Libinfo-517.200.9.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 }
287 break;
288
289 case ID_TYPE_UUID:
290 /* if this is a UID or GID translation, we shortcut UID/GID 0 */
291 /* or if no OD, we return compatibility UUIDs */
292 switch (id_type) {
293 case ID_TYPE_UID:
294 if (identifier_size != sizeof(tempID)) return EINVAL;
295
296 tempID = *((id_t *) identifier);
297 if ((tempID == 0) || (_mbr_od_available() == false)) {
298 uint8_t *tempUU = malloc(sizeof(uuid_t));
299 if (tempUU == NULL) return ENOMEM;
300 uuid_copy(tempUU, _user_compat_prefix);
301 *((id_t *) &tempUU[COMPAT_PREFIX_LEN]) = htonl(tempID);
302 (*result) = tempUU;
303 if (rec_type != NULL) {
304 (*rec_type) = MBR_REC_TYPE_USER;
305 }
306 return 0;
307 }
308 break;
309
310 case ID_TYPE_GID:
311 if (identifier_size != sizeof(tempID)) return EINVAL;
312
313 tempID = *((id_t *) identifier);
314 if ((tempID == 0) || (_mbr_od_available() == false)) {
315 uint8_t *tempUU = malloc(sizeof(uuid_t));
316 if (tempUU == NULL) return ENOMEM;
317 uuid_copy(tempUU, _group_compat_prefix);
318 *((id_t *) &tempUU[COMPAT_PREFIX_LEN]) = htonl(tempID);
319 (*result) = tempUU;
320 if (rec_type != NULL) {
321 (*rec_type) = MBR_REC_TYPE_GROUP;
322 }
323 return 0;
324 }
325 break;
326 }
327 break;
328
329 case ID_TYPE_USERNAME:
330 case ID_TYPE_GROUPNAME:
331 case ID_TYPE_NAME:
332 #if !DS_AVAILABLE
333 /* Convert compatibility UUIDs to names in-process. */
334 if (id_type == ID_TYPE_UUID) {
335 if (identifier_size != sizeof(uuid_t)) return EINVAL;
336 if (compatibility_name_for_uuid(identifier, (char **)result, rec_type)) {
337 return 0;
338 }
339 } else if (id_type == ID_TYPE_UID) {
340 if (identifier_size != sizeof(tempID)) return EINVAL;
341
342 tempID = *((id_t *) identifier);
343 if (compatibility_name_for_id(tempID, MBR_REC_TYPE_USER, (char **)result)) {
344 if (rec_type != NULL) {
345 (*rec_type) = MBR_REC_TYPE_USER;
346 }
347 return 0;
348 }
349 } else if (id_type == ID_TYPE_GID) {
350 if (identifier_size != sizeof(tempID)) return EINVAL;
351
352 tempID = *((id_t *) identifier);
353 if (compatibility_name_for_id(tempID, MBR_REC_TYPE_GROUP, (char **)result)) {
354 if (rec_type != NULL) {
355 (*rec_type) = MBR_REC_TYPE_GROUP;
356 }
357 return 0;
358 }
359 }
360 #endif
361 break;
362 }
363
364 #if DS_AVAILABLE
365 payload = xpc_dictionary_create(NULL, NULL, 0);
366 if (payload == NULL) return EIO;
367
368 MBR_OS_ACTIVITY("Membership API: translate identifier");
369
370 xpc_dictionary_set_int64(payload, "requesting", target_type);
371 xpc_dictionary_set_int64(payload, "type", id_type);
372 xpc_dictionary_set_data(payload, "identifier", identifier, identifier_size);
373
374 reply = _od_rpc_call("mbr_identifier_translate", payload, _mbr_xpc_pipe);
375 if (reply != NULL) {
376 const void *reply_id;
377 size_t idLen;
378
379 rc = (int) xpc_dictionary_get_int64(reply, "error");
380 if (rc == 0) {
381 reply_id = xpc_dictionary_get_data(reply, "identifier", &idLen);
382 if (reply_id != NULL) {
383 char *identifier = malloc(idLen);
384 if (identifier == NULL) return ENOMEM;
385
386 memcpy(identifier, reply_id, idLen); // should already be NULL terminated, etc.
387 (*result) = identifier;
388
389 if (rec_type != NULL) {
390 (*rec_type) = (int) xpc_dictionary_get_int64(reply, "rectype");
391 }
392 } else {
393 (*result) = NULL;
394 rc = ENOENT;
395 }
396 }
397
398 xpc_release(reply);
399 }
400
401 xpc_release(payload);
402 #endif
403
404 return rc;
405 }
406
407 LIBINFO_EXPORT
408 int
409 mbr_uid_to_uuid(uid_t id, uuid_t uu)
410 {
411 return mbr_identifier_to_uuid(ID_TYPE_UID, &id, sizeof(id), uu);
412 }
413
414 LIBINFO_EXPORT
415 int
416 mbr_gid_to_uuid(gid_t id, uuid_t uu)
417 {
418 return mbr_identifier_to_uuid(ID_TYPE_GID, &id, sizeof(id), uu);
419 }
420
421 LIBINFO_EXPORT
422 int
423 mbr_uuid_to_id(const uuid_t uu, uid_t *id, int *id_type)
424 {
425 id_t *result;
426 int local_type;
427 int rc;
428
429 rc = mbr_identifier_translate(ID_TYPE_UUID, uu, sizeof(uuid_t), ID_TYPE_UID_OR_GID, (void **) &result, &local_type);
430 if (rc == 0) {
431 switch (local_type) {
432 case MBR_REC_TYPE_GROUP:
433 (*id_type) = ID_TYPE_GID;
434 break;
435
436 case MBR_REC_TYPE_USER:
437 (*id_type) = ID_TYPE_UID;
438 break;
439
440 default:
441 (*id_type) = -1;
442 break;
443 }
444
445 (*id) = (*result);
446 free(result);
447 }
448
449 return rc;
450 }
451
452 LIBINFO_EXPORT
453 int
454 mbr_sid_to_uuid(const nt_sid_t *sid, uuid_t uu)
455 {
456 #ifdef DS_AVAILABLE
457 return mbr_identifier_to_uuid(ID_TYPE_SID, sid, sizeof(*sid), uu);
458 #else
459 return EIO;
460 #endif
461 }
462
463 LIBINFO_EXPORT
464 int
465 mbr_identifier_to_uuid(int id_type, const void *identifier, size_t identifier_size, uuid_t uu)
466 {
467 uint8_t *result;
468 int rc;
469
470 rc = mbr_identifier_translate(id_type, identifier, identifier_size, ID_TYPE_UUID, (void **) &result, NULL);
471 if (rc == 0) {
472 uuid_copy(uu, result);
473 free(result);
474 }
475 else if ((rc == EIO) && (_mbr_od_available() == false)) {
476 switch (id_type) {
477 case ID_TYPE_USERNAME:
478 {
479 struct passwd *pw = getpwnam(identifier);
480 if (pw) {
481 rc = mbr_identifier_translate(ID_TYPE_UID, &(pw->pw_uid), sizeof(id_t), ID_TYPE_UUID, (void **) &result, NULL);
482 if (rc == 0) {
483 uuid_copy(uu, result);
484 free(result);
485 }
486 }
487 break;
488 }
489 case ID_TYPE_GROUPNAME:
490 {
491 struct group *grp = getgrnam(identifier);
492 if (grp) {
493 rc = mbr_identifier_translate(ID_TYPE_GID, &(grp->gr_gid), sizeof(id_t), ID_TYPE_UUID, (void **) &result, NULL);
494 if (rc == 0) {
495 uuid_copy(uu, result);
496 free(result);
497 }
498 }
499 break;
500 }
501
502 default:
503 break;
504 }
505 }
506
507 return rc;
508 }
509
510 LIBINFO_EXPORT
511 int
512 mbr_uuid_to_sid_type(const uuid_t uu, nt_sid_t *sid, int *id_type)
513 {
514 #ifdef DS_AVAILABLE
515 void *result;
516 int local_type;
517 int rc;
518
519 rc = mbr_identifier_translate(ID_TYPE_UUID, uu, sizeof(uuid_t), ID_TYPE_SID, &result, &local_type);
520 if (rc == 0) {
521 memcpy(sid, result, sizeof(nt_sid_t));
522 if (id_type != NULL) {
523 /* remap ID types */
524 switch (local_type) {
525 case MBR_REC_TYPE_USER:
526 (*id_type) = SID_TYPE_USER;
527 break;
528
529 case MBR_REC_TYPE_GROUP:
530 (*id_type) = SID_TYPE_GROUP;
531 break;
532
533 default:
534 break;
535 }
536 }
537
538 free(result);
539 }
540
541 return rc;
542 #else
543 return EIO;
544 #endif
545 }
546
547 LIBINFO_EXPORT
548 int
549 mbr_uuid_to_sid(const uuid_t uu, nt_sid_t *sid)
550 {
551 #ifdef DS_AVAILABLE
552 int type, status;
553
554 type = 0;
555
556 status = mbr_uuid_to_sid_type(uu, sid, &type);
557 if (status != 0) return status;
558
559 return 0;
560 #else
561 return EIO;
562 #endif
563 }
564
565 LIBINFO_EXPORT
566 int
567 mbr_check_membership(const uuid_t user, const uuid_t group, int *ismember)
568 {
569 return mbr_check_membership_ext(ID_TYPE_UUID, user, sizeof(uuid_t), ID_TYPE_UUID, group, 0, ismember);
570 }
571
572 LIBINFO_EXPORT
573 int
574 mbr_check_membership_refresh(const uuid_t user, uuid_t group, int *ismember)
575 {
576 return mbr_check_membership_ext(ID_TYPE_UUID, user, sizeof(uuid_t), ID_TYPE_UUID, group, 1, ismember);
577 }
578
579 LIBINFO_EXPORT
580 int
581 mbr_check_membership_ext(int userid_type, const void *userid, size_t userid_size, int groupid_type, const void *groupid, int refresh, int *isMember)
582 {
583 #ifdef DS_AVAILABLE
584 xpc_object_t payload, reply;
585 int rc = 0;
586
587 MBR_OS_ACTIVITY("Membership API: Validating user is a member of group");
588 payload = xpc_dictionary_create(NULL, NULL, 0);
589 if (payload == NULL) return ENOMEM;
590
591 xpc_dictionary_set_int64(payload, "user_idtype", userid_type);
592 xpc_dictionary_set_data(payload, "user_id", userid, userid_size);
593 xpc_dictionary_set_int64(payload, "group_idtype", groupid_type);
594 xpc_dictionary_set_bool(payload, "refresh", refresh);
595
596 switch (groupid_type) {
597 case ID_TYPE_GROUPNAME:
598 case ID_TYPE_GROUP_NFS:
599 xpc_dictionary_set_data(payload, "group_id", groupid, strlen(groupid));
600 break;
601
602 case ID_TYPE_GID:
603 xpc_dictionary_set_data(payload, "group_id", groupid, sizeof(id_t));
604 break;
605
606 case ID_TYPE_SID:
607 xpc_dictionary_set_data(payload, "group_id", groupid, sizeof(nt_sid_t));
608 break;
609
610 case ID_TYPE_UUID:
611 xpc_dictionary_set_data(payload, "group_id", groupid, sizeof(uuid_t));
612 break;
613
614 default:
615 rc = EINVAL;
616 break;
617 }
618
619 if (rc == 0) {
620 reply = _od_rpc_call("mbr_check_membership", payload, _mbr_xpc_pipe);
621 if (reply != NULL) {
622 rc = (int) xpc_dictionary_get_int64(reply, "error");
623 (*isMember) = xpc_dictionary_get_bool(reply, "ismember");
624 xpc_release(reply);
625 } else {
626 rc = EIO;
627 }
628 }
629
630 xpc_release(payload);
631
632 return rc;
633 #else
634 return EIO;
635 #endif
636 }
637
638 LIBINFO_EXPORT
639 int
640 mbr_check_membership_by_id(uuid_t user, gid_t group, int *ismember)
641 {
642 return mbr_check_membership_ext(ID_TYPE_UUID, user, sizeof(uuid_t), ID_TYPE_GID, &group, 0, ismember);
643 }
644
645 LIBINFO_EXPORT
646 int
647 mbr_reset_cache()
648 {
649 #ifdef DS_AVAILABLE
650 MBR_OS_ACTIVITY("Membership API: Flush the membership cache");
651 _od_rpc_call("mbr_cache_flush", NULL, _mbr_xpc_pipe);
652 return 0;
653 #else
654 return EIO;
655 #endif
656 }
657
658 LIBINFO_EXPORT
659 int
660 mbr_user_name_to_uuid(const char *name, uuid_t uu)
661 {
662 return mbr_identifier_to_uuid(ID_TYPE_USERNAME, name, -1, uu);
663 }
664
665 LIBINFO_EXPORT
666 int
667 mbr_group_name_to_uuid(const char *name, uuid_t uu)
668 {
669 return mbr_identifier_to_uuid(ID_TYPE_GROUPNAME, name, -1, uu);
670 }
671
672 LIBINFO_EXPORT
673 int
674 mbr_check_service_membership(const uuid_t user, const char *servicename, int *ismember)
675 {
676 #ifdef DS_AVAILABLE
677 xpc_object_t payload, reply;
678 int result = EIO;
679
680 if (ismember == NULL || servicename == NULL) return EINVAL;
681
682 payload = xpc_dictionary_create(NULL, NULL, 0);
683 if (payload == NULL) return EIO;
684
685 MBR_OS_ACTIVITY("Membership API: Validating user is allowed by service");
686
687 xpc_dictionary_set_data(payload, "user_id", user, sizeof(uuid_t));
688 xpc_dictionary_set_int64(payload, "user_idtype", ID_TYPE_UUID);
689 xpc_dictionary_set_string(payload, "service", servicename);
690
691 reply = _od_rpc_call("mbr_check_service_membership", payload, _mbr_xpc_pipe);
692 if (reply != NULL) {
693 result = (int) xpc_dictionary_get_int64(reply, "error");
694 (*ismember) = xpc_dictionary_get_bool(reply, "ismember");
695
696 xpc_release(reply);
697 } else {
698 (*ismember) = 0;
699 }
700
701 xpc_release(payload);
702
703 return result;
704 #else
705 return EIO;
706 #endif
707 }
708
709 #ifdef DS_AVAILABLE
710 static char *
711 ConvertBytesToDecimal(char *buffer, unsigned long long value)
712 {
713 char *temp;
714 buffer[24] = '\0';
715 buffer[23] = '0';
716
717 if (value == 0)
718 return &buffer[23];
719
720 temp = &buffer[24];
721 while (value != 0)
722 {
723 temp--;
724 *temp = '0' + (value % 10);
725 value /= 10;
726 }
727
728 return temp;
729 }
730 #endif
731
732 LIBINFO_EXPORT
733 int
734 mbr_sid_to_string(const nt_sid_t *sid, char *string)
735 {
736 #ifdef DS_AVAILABLE
737 char *current = string;
738 long long temp = 0;
739 int i;
740 char tempBuffer[25];
741
742 if (sid->sid_authcount > NTSID_MAX_AUTHORITIES) return EINVAL;
743
744 for (i = 0; i < 6; i++)
745 temp = (temp << 8) | sid->sid_authority[i];
746
747 current[0] = 'S';
748 current[1] = '-';
749 current += 2;
750 strcpy(current, ConvertBytesToDecimal(tempBuffer, sid->sid_kind));
751 current = current + strlen(current);
752 *current = '-';
753 current++;
754 strcpy(current, ConvertBytesToDecimal(tempBuffer, temp));
755
756 for(i=0; i < sid->sid_authcount; i++)
757 {
758 current = current + strlen(current);
759 *current = '-';
760 current++;
761 strcpy(current, ConvertBytesToDecimal(tempBuffer, sid->sid_authorities[i]));
762 }
763
764 return 0;
765 #else
766 return EIO;
767 #endif
768 }
769
770 LIBINFO_EXPORT
771 int
772 mbr_string_to_sid(const char *string, nt_sid_t *sid)
773 {
774 #ifdef DS_AVAILABLE
775 char *current = (char *)string+2;
776 int count = 0;
777 long long temp;
778
779 if (string == NULL) return EINVAL;
780
781 memset(sid, 0, sizeof(nt_sid_t));
782 if (string[0] != 'S' || string[1] != '-') return EINVAL;
783
784 sid->sid_kind = strtol(current, &current, 10);
785 if (*current == '\0') return EINVAL;
786 current++;
787 temp = strtoll(current, &current, 10);
788
789 /* convert to BigEndian before copying */
790 temp = OSSwapHostToBigInt64(temp);
791 memcpy(sid->sid_authority, ((char*)&temp)+2, 6);
792 while (*current != '\0' && count < NTSID_MAX_AUTHORITIES)
793 {
794 current++;
795 errno = 0;
796 sid->sid_authorities[count] = (u_int32_t)strtoll(current, &current, 10);
797 if ((sid->sid_authorities[count] == 0) && (errno == EINVAL)) {
798 return EINVAL;
799 }
800 count++;
801 }
802
803 if (*current != '\0') return EINVAL;
804
805 sid->sid_authcount = count;
806
807 return 0;
808 #else
809 return EIO;
810 #endif
811 }
812
813 int
814 mbr_uuid_to_string(const uuid_t uu, char *string)
815 {
816 uuid_unparse_upper(uu, string);
817
818 return 0;
819 }
820
821 int
822 mbr_string_to_uuid(const char *string, uuid_t uu)
823 {
824 return uuid_parse(string, uu);
825 }
826
827 LIBINFO_EXPORT
828 int
829 mbr_set_identifier_ttl(int id_type, const void *identifier, size_t identifier_size, unsigned int seconds)
830 {
831 #ifdef DS_AVAILABLE
832 xpc_object_t payload, reply;
833 int rc = 0;
834
835 payload = xpc_dictionary_create(NULL, NULL, 0);
836 if (payload == NULL) return ENOMEM;
837
838 MBR_OS_ACTIVITY("Membership API: Change the TTL of a given identifier in SystemCache");
839
840 xpc_dictionary_set_int64(payload, "type", id_type);
841 xpc_dictionary_set_data(payload, "identifier", identifier, identifier_size);
842 xpc_dictionary_set_int64(payload, "ttl", seconds);
843
844 if (rc == 0) {
845 reply = _od_rpc_call("mbr_set_identifier_ttl", payload, _mbr_xpc_pipe);
846 if (reply != NULL) {
847 rc = (int) xpc_dictionary_get_int64(reply, "error");
848 xpc_release(reply);
849 } else {
850 rc = EIO;
851 }
852 }
853
854 xpc_release(payload);
855
856 return rc;
857 #else
858 return EIO;
859 #endif
860 }