Libinfo-391.tar.gz
[apple/libinfo.git] / membership.subproj / membership.c
1 /*
2 * Copyright (c) 2004-2010 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 <mach/mach.h>
26 #include "membership.h"
27 #include "membershipPriv.h"
28 #include <servers/bootstrap.h>
29 #include <libkern/OSByteOrder.h>
30 #ifdef DS_AVAILABLE
31 #include "DSmemberdMIG.h"
32 #endif
33
34 #ifdef DS_AVAILABLE
35 extern mach_port_t _mbr_port;
36 extern int _ds_running(void);
37
38 static const uuid_t _user_compat_prefix = {0xff, 0xff, 0xee, 0xee, 0xdd, 0xdd, 0xcc, 0xcc, 0xbb, 0xbb, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00};
39 static const uuid_t _group_compat_prefix = {0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0x00, 0x00, 0x00, 0x00};
40
41 #define COMPAT_PREFIX_LEN (sizeof(uuid_t) - sizeof(id_t))
42
43 #define MAX_LOOKUP_ATTEMPTS 10
44 #endif
45
46 uid_t
47 audit_token_uid(audit_token_t a)
48 {
49 /*
50 * This should really call audit_token_to_au32,
51 * but that's in libbsm, not in a Libsystem library.
52 */
53 return (uid_t)a.val[1];
54 }
55
56 #ifdef DS_AVAILABLE
57 static int
58 _mbr_MembershipCall(struct kauth_identity_extlookup *req)
59 {
60 audit_token_t token;
61 kern_return_t status;
62 uint32_t i;
63
64 /* call _ds_running() to look up _mbr_port */
65 _ds_running();
66 if (_mbr_port == MACH_PORT_NULL) return EIO;
67
68 memset(&token, 0, sizeof(audit_token_t));
69
70 status = MIG_SERVER_DIED;
71 for (i = 0; (_mbr_port != MACH_PORT_NULL) && (status == MIG_SERVER_DIED) && (i < MAX_LOOKUP_ATTEMPTS); i++)
72 {
73 status = memberdDSmig_MembershipCall(_mbr_port, req, &token);
74 if (status == MACH_SEND_INVALID_DEST)
75 {
76 mach_port_mod_refs(mach_task_self(), _mbr_port, MACH_PORT_RIGHT_SEND, -1);
77 _mbr_port = MACH_PORT_NULL;
78 _ds_running();
79 status = MIG_SERVER_DIED;
80 }
81 }
82
83 if (status != KERN_SUCCESS) return EIO;
84 if (audit_token_uid(token) != 0) return EAUTH;
85
86 return 0;
87 }
88 #endif
89
90 #ifdef DS_AVAILABLE
91 static int
92 _mbr_MapName(char *name, int type, guid_t *uu)
93 {
94 kern_return_t status;
95 audit_token_t token;
96 uint32_t i;
97
98 if (name == NULL) return EINVAL;
99 if (strlen(name) > 255) return EINVAL;
100
101 /* call _ds_running() to look up _mbr_port */
102 _ds_running();
103 if (_mbr_port == MACH_PORT_NULL) return EIO;
104
105 memset(&token, 0, sizeof(audit_token_t));
106
107 status = MIG_SERVER_DIED;
108 for (i = 0; (_mbr_port != MACH_PORT_NULL) && (status == MIG_SERVER_DIED) && (i < MAX_LOOKUP_ATTEMPTS); i++)
109 {
110 status = memberdDSmig_MapName(_mbr_port, type, name, uu, &token);
111 if (status == KERN_FAILURE) return ENOENT;
112
113 if (status == MACH_SEND_INVALID_DEST)
114 {
115 mach_port_mod_refs(mach_task_self(), _mbr_port, MACH_PORT_RIGHT_SEND, -1);
116 _mbr_port = MACH_PORT_NULL;
117 _ds_running();
118 status = MIG_SERVER_DIED;
119 }
120 }
121
122 if (status != KERN_SUCCESS) return EIO;
123 if (audit_token_uid(token) != 0) return EAUTH;
124
125 return 0;
126 }
127 #endif
128
129 #ifdef DS_AVAILABLE
130 static int
131 _mbr_ClearCache()
132 {
133 kern_return_t status;
134 uint32_t i;
135
136 /* call _ds_running() to look up _mbr_port */
137 _ds_running();
138 if (_mbr_port == MACH_PORT_NULL) return EIO;
139
140 status = MIG_SERVER_DIED;
141 for (i = 0; (_mbr_port != MACH_PORT_NULL) && (status == MIG_SERVER_DIED) && (i < MAX_LOOKUP_ATTEMPTS); i++)
142 {
143 status = memberdDSmig_ClearCache(_mbr_port);
144 if (status == MACH_SEND_INVALID_DEST)
145 {
146 mach_port_mod_refs(mach_task_self(), _mbr_port, MACH_PORT_RIGHT_SEND, -1);
147 _mbr_port = MACH_PORT_NULL;
148 _ds_running();
149 status = MIG_SERVER_DIED;
150 }
151 }
152
153 if (status != KERN_SUCCESS) return EIO;
154
155 return 0;
156 }
157 #endif
158
159 #ifdef DS_AVAILABLE
160 static int
161 _mbr_SetIdentifierTTL(int idType, const void *identifier, size_t identifier_size, unsigned int seconds)
162 {
163 kern_return_t status;
164 uint32_t i;
165
166 /* call _ds_running() to look up _mbr_port */
167 _ds_running();
168 if (_mbr_port == MACH_PORT_NULL) return EIO;
169
170 status = MIG_SERVER_DIED;
171 for (i = 0; (_mbr_port != MACH_PORT_NULL) && (status == MIG_SERVER_DIED) && (i < MAX_LOOKUP_ATTEMPTS); i++)
172 {
173 status = memberdDSmig_SetIdentifierTTL(_mbr_port, idType, (identifier_data_t)identifier, identifier_size, seconds);
174 if (status == MACH_SEND_INVALID_DEST)
175 {
176 mach_port_mod_refs(mach_task_self(), _mbr_port, MACH_PORT_RIGHT_SEND, -1);
177 _mbr_port = MACH_PORT_NULL;
178 _ds_running();
179 status = MIG_SERVER_DIED;
180 }
181 }
182
183 if (status != KERN_SUCCESS) return EIO;
184
185 return 0;
186 }
187 #endif
188
189 int
190 mbr_uid_to_uuid(uid_t id, uuid_t uu)
191 {
192 return mbr_identifier_to_uuid(ID_TYPE_UID, &id, sizeof(id), uu);
193 }
194
195 int
196 mbr_gid_to_uuid(gid_t id, uuid_t uu)
197 {
198 return mbr_identifier_to_uuid(ID_TYPE_GID, &id, sizeof(id), uu);
199 }
200
201 int
202 mbr_uuid_to_id(const uuid_t uu, uid_t *id, int *id_type)
203 {
204 #ifdef DS_AVAILABLE
205 struct kauth_identity_extlookup request;
206 int status;
207 id_t tempID;
208
209 if (id == NULL) return EIO;
210 if (id_type == NULL) return EIO;
211
212 if (!memcmp(uu, _user_compat_prefix, COMPAT_PREFIX_LEN))
213 {
214 memcpy(&tempID, &uu[COMPAT_PREFIX_LEN], sizeof(tempID));
215 *id = ntohl(tempID);
216 *id_type = ID_TYPE_UID;
217 return 0;
218 }
219 else if (!memcmp(uu, _group_compat_prefix, COMPAT_PREFIX_LEN))
220 {
221 memcpy(&tempID, &uu[COMPAT_PREFIX_LEN], sizeof(tempID));
222 *id = ntohl(tempID);
223 *id_type = ID_TYPE_GID;
224 return 0;
225 }
226
227 request.el_seqno = 1;
228 request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GGUID | KAUTH_EXTLOOKUP_WANT_UID | KAUTH_EXTLOOKUP_WANT_GID;
229 memcpy(&request.el_uguid, uu, sizeof(guid_t));
230 memcpy(&request.el_gguid, uu, sizeof(guid_t));
231
232 status = _mbr_MembershipCall(&request);
233 if (status != 0) return status;
234
235 if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_UID) != 0)
236 {
237 *id = request.el_uid;
238 *id_type = ID_TYPE_UID;
239 }
240 else if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_GID) != 0)
241 {
242 *id = request.el_gid;
243 *id_type = ID_TYPE_GID;
244 }
245 else
246 {
247 return ENOENT;
248 }
249
250 return 0;
251 #else
252 return EIO;
253 #endif
254 }
255
256 int
257 mbr_sid_to_uuid(const nt_sid_t *sid, uuid_t uu)
258 {
259 #ifdef DS_AVAILABLE
260 struct kauth_identity_extlookup request;
261 int status;
262
263 request.el_seqno = 1;
264 request.el_flags = KAUTH_EXTLOOKUP_VALID_GSID | KAUTH_EXTLOOKUP_WANT_GGUID | KAUTH_EXTLOOKUP_VALID_USID | KAUTH_EXTLOOKUP_WANT_UGUID;
265 memset(&request.el_gsid, 0, sizeof(ntsid_t));
266 memcpy(&request.el_gsid, sid, KAUTH_NTSID_SIZE(sid));
267 memset(&request.el_usid, 0, sizeof(ntsid_t));
268 memcpy(&request.el_usid, sid, KAUTH_NTSID_SIZE(sid));
269
270 status = _mbr_MembershipCall(&request);
271 if (status != 0) return status;
272
273 if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_GGUID) != 0) memcpy(uu, &request.el_gguid, sizeof(guid_t));
274 else if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_UGUID) != 0) memcpy(uu, &request.el_uguid, sizeof(guid_t));
275 else return ENOENT;
276
277 return 0;
278 #else
279 return EIO;
280 #endif
281 }
282
283 int
284 mbr_identifier_to_uuid(int id_type, const void *identifier, size_t identifier_size, uuid_t uu)
285 {
286 #ifdef DS_AVAILABLE
287 kern_return_t status;
288 audit_token_t token;
289 vm_offset_t ool = 0;
290 mach_msg_type_number_t oolCnt = 0;
291 uint32_t i;
292 id_t tempID;
293 #if __BIG_ENDIAN__
294 id_t newID;
295 #endif
296
297 if (identifier == NULL) return EINVAL;
298 if (identifier_size == 0) return EINVAL;
299 else if (identifier_size == -1) identifier_size = strlen((char*) identifier) + 1;
300
301 /* call _ds_running() to look up _mbr_port */
302 _ds_running();
303
304 /* if this is a UID or GID translation, we shortcut UID/GID 0 */
305 /* if no DS, we return compatibility UUIDs */
306 switch (id_type)
307 {
308 case ID_TYPE_UID:
309 {
310 if (identifier_size != sizeof(tempID)) return EINVAL;
311
312 tempID = *((id_t *) identifier);
313 if ((tempID == 0) || (_mbr_port == MACH_PORT_NULL))
314 {
315 uuid_copy(uu, _user_compat_prefix);
316 *((id_t *) &uu[COMPAT_PREFIX_LEN]) = htonl(tempID);
317 return 0;
318 }
319 break;
320 }
321 case ID_TYPE_GID:
322 {
323 if (identifier_size != sizeof(tempID)) return EINVAL;
324
325 tempID = *((id_t *) identifier);
326 if ((tempID == 0) || (_mbr_port == MACH_PORT_NULL))
327 {
328 uuid_copy(uu, _group_compat_prefix);
329 *((id_t *) &uu[COMPAT_PREFIX_LEN]) = htonl(tempID);
330 return 0;
331 }
332 break;
333 }
334 }
335
336 if (_mbr_port == MACH_PORT_NULL) return EIO;
337
338 memset(&token, 0, sizeof(audit_token_t));
339
340 #if __BIG_ENDIAN__
341 switch (id_type)
342 {
343 case ID_TYPE_UID:
344 case ID_TYPE_GID:
345 if (identifier_size < sizeof(id_t)) return EINVAL;
346 newID = OSSwapInt32(*((id_t *) identifier));
347 identifier = &newID;
348 break;
349 }
350 #endif
351
352 if (identifier_size > MAX_MIG_INLINE_DATA)
353 {
354 if (vm_read(mach_task_self(), (vm_offset_t) identifier, identifier_size, &ool, &oolCnt) != 0) return ENOMEM;
355 identifier = NULL;
356 identifier_size = 0;
357 }
358
359 status = MIG_SERVER_DIED;
360 for (i = 0; (_mbr_port != MACH_PORT_NULL) && (status == MIG_SERVER_DIED) && (i < MAX_LOOKUP_ATTEMPTS); i++)
361 {
362 status = memberdDSmig_MapIdentifier(_mbr_port, id_type, (identifier_data_t) identifier, identifier_size, ool, oolCnt, (guid_t *)uu, &token);
363 if (status == KERN_FAILURE) return ENOENT;
364
365 if (status == MACH_SEND_INVALID_DEST)
366 {
367 if (ool != 0) vm_deallocate(mach_task_self(), ool, oolCnt);
368
369 mach_port_mod_refs(mach_task_self(), _mbr_port, MACH_PORT_RIGHT_SEND, -1);
370 _mbr_port = MACH_PORT_NULL;
371 _ds_running();
372 status = MIG_SERVER_DIED;
373 }
374 }
375
376 if (status != KERN_SUCCESS) return EIO;
377 if (audit_token_uid(token) != 0) return EAUTH;
378
379 return 0;
380 #else
381 return EIO;
382 #endif
383 }
384
385 int
386 mbr_uuid_to_sid_type(const uuid_t uu, nt_sid_t *sid, int *id_type)
387 {
388 #ifdef DS_AVAILABLE
389 struct kauth_identity_extlookup request;
390 int status;
391
392 request.el_seqno = 1;
393 request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GGUID | KAUTH_EXTLOOKUP_WANT_USID | KAUTH_EXTLOOKUP_WANT_GSID;
394 memcpy(&request.el_uguid, uu, sizeof(guid_t));
395 memcpy(&request.el_gguid, uu, sizeof(guid_t));
396
397 status = _mbr_MembershipCall(&request);
398 if (status != 0) return status;
399
400 if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_USID) != 0)
401 {
402 *id_type = SID_TYPE_USER;
403 memcpy(sid, &request.el_usid, sizeof(nt_sid_t));
404 }
405 else if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_GSID) != 0)
406 {
407 *id_type = SID_TYPE_GROUP;
408 memcpy(sid, &request.el_gsid, sizeof(nt_sid_t));
409 }
410 else
411 {
412 return ENOENT;
413 }
414
415 return 0;
416 #else
417 return EIO;
418 #endif
419 }
420
421 int
422 mbr_uuid_to_sid(const uuid_t uu, nt_sid_t *sid)
423 {
424 #ifdef DS_AVAILABLE
425 int type, status;
426
427 type = 0;
428
429 status = mbr_uuid_to_sid_type(uu, sid, &type);
430 if (status != 0) return status;
431
432 return 0;
433 #else
434 return EIO;
435 #endif
436 }
437
438 int
439 mbr_check_membership(const uuid_t user, const uuid_t group, int *ismember)
440 {
441 #ifdef DS_AVAILABLE
442 struct kauth_identity_extlookup request;
443 int status;
444
445 request.el_seqno = 1;
446 request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GGUID | KAUTH_EXTLOOKUP_WANT_MEMBERSHIP;
447 memcpy(&request.el_uguid, user, sizeof(guid_t));
448 memcpy(&request.el_gguid, group, sizeof(guid_t));
449
450 status = _mbr_MembershipCall(&request);
451 if (status != 0) return status;
452 if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_MEMBERSHIP) == 0) return ENOENT;
453
454 *ismember = ((request.el_flags & KAUTH_EXTLOOKUP_ISMEMBER) != 0);
455 return 0;
456 #else
457 return EIO;
458 #endif
459 }
460
461 int
462 mbr_check_membership_refresh(const uuid_t user, uuid_t group, int *ismember)
463 {
464 #ifdef DS_AVAILABLE
465 struct kauth_identity_extlookup request;
466 int status;
467
468 request.el_seqno = 1;
469 request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GGUID | KAUTH_EXTLOOKUP_WANT_MEMBERSHIP | (1<<15);
470 memcpy(&request.el_uguid, user, sizeof(guid_t));
471 memcpy(&request.el_gguid, group, sizeof(guid_t));
472
473 status = _mbr_MembershipCall(&request);
474 if (status != 0) return status;
475 if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_MEMBERSHIP) == 0) return ENOENT;
476
477 *ismember = ((request.el_flags & KAUTH_EXTLOOKUP_ISMEMBER) != 0);
478 return 0;
479 #else
480 return EIO;
481 #endif
482 }
483
484 int
485 mbr_check_membership_by_id(uuid_t user, gid_t group, int *ismember)
486 {
487 #ifdef DS_AVAILABLE
488 struct kauth_identity_extlookup request;
489 int status;
490
491 request.el_seqno = 1;
492 request.el_flags = KAUTH_EXTLOOKUP_VALID_UGUID | KAUTH_EXTLOOKUP_VALID_GID | KAUTH_EXTLOOKUP_WANT_MEMBERSHIP;
493 memcpy(&request.el_uguid, user, sizeof(guid_t));
494 request.el_gid = group;
495
496 status = _mbr_MembershipCall(&request);
497 if (status != 0) return status;
498 if ((request.el_flags & KAUTH_EXTLOOKUP_VALID_MEMBERSHIP) == 0) return ENOENT;
499
500 *ismember = ((request.el_flags & KAUTH_EXTLOOKUP_ISMEMBER) != 0);
501 return 0;
502 #else
503 return EIO;
504 #endif
505 }
506
507 int
508 mbr_reset_cache()
509 {
510 #ifdef DS_AVAILABLE
511 return _mbr_ClearCache();
512 #else
513 return EIO;
514 #endif
515 }
516
517 int
518 mbr_user_name_to_uuid(const char *name, uuid_t uu)
519 {
520 #ifdef DS_AVAILABLE
521 return _mbr_MapName((char *)name, 1, (guid_t *)uu);
522 #else
523 return EIO;
524 #endif
525 }
526
527 int
528 mbr_group_name_to_uuid(const char *name, uuid_t uu)
529 {
530 #ifdef DS_AVAILABLE
531 return _mbr_MapName((char *)name, 0, (guid_t *)uu);
532 #else
533 return EIO;
534 #endif
535 }
536
537 int
538 mbr_check_service_membership(const uuid_t user, const char *servicename, int *ismember)
539 {
540 #ifdef DS_AVAILABLE
541 char *prefix = "com.apple.access_";
542 char *all_services = "com.apple.access_all_services";
543 char groupName[256];
544 uuid_t group_uu;
545 int result;
546
547 if (servicename == NULL) return EINVAL;
548 if (strlen(servicename) > 255 - strlen(prefix)) return EINVAL;
549
550 /* start by checking "all services" */
551 result = mbr_group_name_to_uuid(all_services, group_uu);
552
553 if (result == EAUTH) return result;
554
555 if (result == ENOENT)
556 {
557 /* all_services group didn't exist, check individual group */
558 memcpy(groupName, prefix, strlen(prefix));
559 strcpy(groupName + strlen(prefix), servicename);
560 result = mbr_group_name_to_uuid(groupName, group_uu);
561 }
562
563 if (result == 0)
564 {
565 /* refreshes are driven at a higher level, just check membership */
566 result = mbr_check_membership(user, group_uu, ismember);
567 }
568
569 return result;
570 #else
571 return EIO;
572 #endif
573 }
574
575 #ifdef DS_AVAILABLE
576 static char *
577 ConvertBytesToDecimal(char *buffer, unsigned long long value)
578 {
579 char *temp;
580 buffer[24] = '\0';
581 buffer[23] = '0';
582
583 if (value == 0)
584 return &buffer[23];
585
586 temp = &buffer[24];
587 while (value != 0)
588 {
589 temp--;
590 *temp = '0' + (value % 10);
591 value /= 10;
592 }
593
594 return temp;
595 }
596 #endif
597
598 int
599 mbr_sid_to_string(const nt_sid_t *sid, char *string)
600 {
601 #ifdef DS_AVAILABLE
602 char *current = string;
603 long long temp = 0;
604 int i;
605 char tempBuffer[25];
606
607 if (sid->sid_authcount > NTSID_MAX_AUTHORITIES) return EINVAL;
608
609 for (i = 0; i < 6; i++)
610 temp = (temp << 8) | sid->sid_authority[i];
611
612 current[0] = 'S';
613 current[1] = '-';
614 current += 2;
615 strcpy(current, ConvertBytesToDecimal(tempBuffer, sid->sid_kind));
616 current = current + strlen(current);
617 *current = '-';
618 current++;
619 strcpy(current, ConvertBytesToDecimal(tempBuffer, temp));
620
621 for(i=0; i < sid->sid_authcount; i++)
622 {
623 current = current + strlen(current);
624 *current = '-';
625 current++;
626 strcpy(current, ConvertBytesToDecimal(tempBuffer, sid->sid_authorities[i]));
627 }
628
629 return 0;
630 #else
631 return EIO;
632 #endif
633 }
634
635 int
636 mbr_string_to_sid(const char *string, nt_sid_t *sid)
637 {
638 #ifdef DS_AVAILABLE
639 char *current = (char *)string+2;
640 int count = 0;
641 long long temp;
642
643 if (string == NULL) return EINVAL;
644
645 memset(sid, 0, sizeof(nt_sid_t));
646 if (string[0] != 'S' || string[1] != '-') return EINVAL;
647
648 sid->sid_kind = strtol(current, &current, 10);
649 if (*current == '\0') return EINVAL;
650 current++;
651 temp = strtoll(current, &current, 10);
652
653 /* convert to BigEndian before copying */
654 temp = OSSwapHostToBigInt64(temp);
655 memcpy(sid->sid_authority, ((char*)&temp)+2, 6);
656 while (*current != '\0' && count < NTSID_MAX_AUTHORITIES)
657 {
658 current++;
659 errno = 0;
660 sid->sid_authorities[count] = (u_int32_t)strtoll(current, &current, 10);
661 if ((sid->sid_authorities[count] == 0) && (errno == EINVAL)) {
662 return EINVAL;
663 }
664 count++;
665 }
666
667 if (*current != '\0') return EINVAL;
668
669 sid->sid_authcount = count;
670
671 return 0;
672 #else
673 return EIO;
674 #endif
675 }
676
677 #ifdef DS_AVAILABLE
678 static void
679 ConvertBytesToHex(char **string, char **data, int numBytes)
680 {
681 int i;
682
683 for (i=0; i < numBytes; i++)
684 {
685 unsigned char hi = ((**data) >> 4) & 0xf;
686 unsigned char low = (**data) & 0xf;
687 if (hi < 10)
688 **string = '0' + hi;
689 else
690 **string = 'A' + hi - 10;
691
692 (*string)++;
693
694 if (low < 10)
695 **string = '0' + low;
696 else
697 **string = 'A' + low - 10;
698
699 (*string)++;
700 (*data)++;
701 }
702 }
703 #endif
704
705 int
706 mbr_uuid_to_string(const uuid_t uu, char *string)
707 {
708 #ifdef DS_AVAILABLE
709 char *guid = (char*)uu;
710 char *strPtr = string;
711 ConvertBytesToHex(&strPtr, &guid, 4);
712 *strPtr = '-'; strPtr++;
713 ConvertBytesToHex(&strPtr, &guid, 2);
714 *strPtr = '-'; strPtr++;
715 ConvertBytesToHex(&strPtr, &guid, 2);
716 *strPtr = '-'; strPtr++;
717 ConvertBytesToHex(&strPtr, &guid, 2);
718 *strPtr = '-'; strPtr++;
719 ConvertBytesToHex(&strPtr, &guid, 6);
720 *strPtr = '\0';
721
722 return 0;
723 #else
724 return EIO;
725 #endif
726 }
727
728 int
729 mbr_string_to_uuid(const char *string, uuid_t uu)
730 {
731 #ifdef DS_AVAILABLE
732 short dataIndex = 0;
733 int isFirstNibble = 1;
734
735 if (string == NULL) return EINVAL;
736 if (strlen(string) > MBR_UU_STRING_SIZE) return EINVAL;
737
738 while (*string != '\0' && dataIndex < 16)
739 {
740 char nibble;
741
742 if (*string >= '0' && *string <= '9')
743 nibble = *string - '0';
744 else if (*string >= 'A' && *string <= 'F')
745 nibble = *string - 'A' + 10;
746 else if (*string >= 'a' && *string <= 'f')
747 nibble = *string - 'a' + 10;
748 else
749 {
750 if (*string != '-')
751 return EINVAL;
752 string++;
753 continue;
754 }
755
756 if (isFirstNibble)
757 {
758 uu[dataIndex] = nibble << 4;
759 isFirstNibble = 0;
760 }
761 else
762 {
763 uu[dataIndex] |= nibble;
764 dataIndex++;
765 isFirstNibble = 1;
766 }
767
768 string++;
769 }
770
771 if (dataIndex != 16) return EINVAL;
772
773 return 0;
774 #else
775 return EIO;
776 #endif
777 }
778
779 int
780 mbr_set_identifier_ttl(int id_type, const void *identifier, size_t identifier_size, unsigned int seconds)
781 {
782 #ifdef DS_AVAILABLE
783 _mbr_SetIdentifierTTL(id_type, identifier, identifier_size, seconds);
784 return 0;
785 #else
786 return EIO;
787 #endif
788 }