2 * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
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>
31 #include "DSmemberdMIG.h"
35 extern mach_port_t _mbr_port
;
36 extern int _ds_running(void);
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};
41 #define COMPAT_PREFIX_LEN (sizeof(uuid_t) - sizeof(id_t))
43 #define MAX_LOOKUP_ATTEMPTS 10
47 audit_token_uid(audit_token_t a
)
50 * This should really call audit_token_to_au32,
51 * but that's in libbsm, not in a Libsystem library.
53 return (uid_t
)a
.val
[1];
58 _mbr_MembershipCall(struct kauth_identity_extlookup
*req
)
64 /* call _ds_running() to look up _mbr_port */
66 if (_mbr_port
== MACH_PORT_NULL
) return EIO
;
68 memset(&token
, 0, sizeof(audit_token_t
));
70 status
= MIG_SERVER_DIED
;
71 for (i
= 0; (_mbr_port
!= MACH_PORT_NULL
) && (status
== MIG_SERVER_DIED
) && (i
< MAX_LOOKUP_ATTEMPTS
); i
++)
73 status
= memberdDSmig_MembershipCall(_mbr_port
, req
, &token
);
74 if (status
== MACH_SEND_INVALID_DEST
)
76 mach_port_mod_refs(mach_task_self(), _mbr_port
, MACH_PORT_RIGHT_SEND
, -1);
77 _mbr_port
= MACH_PORT_NULL
;
79 status
= MIG_SERVER_DIED
;
83 if (status
!= KERN_SUCCESS
) return EIO
;
84 if (audit_token_uid(token
) != 0) return EAUTH
;
92 _mbr_MapName(char *name
, int type
, guid_t
*uu
)
98 if (name
== NULL
) return EINVAL
;
99 if (strlen(name
) > 255) return EINVAL
;
101 /* call _ds_running() to look up _mbr_port */
103 if (_mbr_port
== MACH_PORT_NULL
) return EIO
;
105 memset(&token
, 0, sizeof(audit_token_t
));
107 status
= MIG_SERVER_DIED
;
108 for (i
= 0; (_mbr_port
!= MACH_PORT_NULL
) && (status
== MIG_SERVER_DIED
) && (i
< MAX_LOOKUP_ATTEMPTS
); i
++)
110 status
= memberdDSmig_MapName(_mbr_port
, type
, name
, uu
, &token
);
111 if (status
== KERN_FAILURE
) return ENOENT
;
113 if (status
== MACH_SEND_INVALID_DEST
)
115 mach_port_mod_refs(mach_task_self(), _mbr_port
, MACH_PORT_RIGHT_SEND
, -1);
116 _mbr_port
= MACH_PORT_NULL
;
118 status
= MIG_SERVER_DIED
;
122 if (status
!= KERN_SUCCESS
) return EIO
;
123 if (audit_token_uid(token
) != 0) return EAUTH
;
133 kern_return_t status
;
136 /* call _ds_running() to look up _mbr_port */
138 if (_mbr_port
== MACH_PORT_NULL
) return EIO
;
140 status
= MIG_SERVER_DIED
;
141 for (i
= 0; (_mbr_port
!= MACH_PORT_NULL
) && (status
== MIG_SERVER_DIED
) && (i
< MAX_LOOKUP_ATTEMPTS
); i
++)
143 status
= memberdDSmig_ClearCache(_mbr_port
);
144 if (status
== MACH_SEND_INVALID_DEST
)
146 mach_port_mod_refs(mach_task_self(), _mbr_port
, MACH_PORT_RIGHT_SEND
, -1);
147 _mbr_port
= MACH_PORT_NULL
;
149 status
= MIG_SERVER_DIED
;
153 if (status
!= KERN_SUCCESS
) return EIO
;
161 _mbr_SetIdentifierTTL(int idType
, const void *identifier
, size_t identifier_size
, unsigned int seconds
)
163 kern_return_t status
;
166 /* call _ds_running() to look up _mbr_port */
168 if (_mbr_port
== MACH_PORT_NULL
) return EIO
;
170 status
= MIG_SERVER_DIED
;
171 for (i
= 0; (_mbr_port
!= MACH_PORT_NULL
) && (status
== MIG_SERVER_DIED
) && (i
< MAX_LOOKUP_ATTEMPTS
); i
++)
173 status
= memberdDSmig_SetIdentifierTTL(_mbr_port
, idType
, (identifier_data_t
)identifier
, identifier_size
, seconds
);
174 if (status
== MACH_SEND_INVALID_DEST
)
176 mach_port_mod_refs(mach_task_self(), _mbr_port
, MACH_PORT_RIGHT_SEND
, -1);
177 _mbr_port
= MACH_PORT_NULL
;
179 status
= MIG_SERVER_DIED
;
183 if (status
!= KERN_SUCCESS
) return EIO
;
190 mbr_uid_to_uuid(uid_t id
, uuid_t uu
)
192 return mbr_identifier_to_uuid(ID_TYPE_UID
, &id
, sizeof(id
), uu
);
196 mbr_gid_to_uuid(gid_t id
, uuid_t uu
)
198 return mbr_identifier_to_uuid(ID_TYPE_GID
, &id
, sizeof(id
), uu
);
202 mbr_uuid_to_id(const uuid_t uu
, uid_t
*id
, int *id_type
)
205 struct kauth_identity_extlookup request
;
209 if (id
== NULL
) return EIO
;
210 if (id_type
== NULL
) return EIO
;
212 if (!memcmp(uu
, _user_compat_prefix
, COMPAT_PREFIX_LEN
))
214 memcpy(&tempID
, &uu
[COMPAT_PREFIX_LEN
], sizeof(tempID
));
216 *id_type
= ID_TYPE_UID
;
219 else if (!memcmp(uu
, _group_compat_prefix
, COMPAT_PREFIX_LEN
))
221 memcpy(&tempID
, &uu
[COMPAT_PREFIX_LEN
], sizeof(tempID
));
223 *id_type
= ID_TYPE_GID
;
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
));
232 status
= _mbr_MembershipCall(&request
);
233 if (status
!= 0) return status
;
235 if ((request
.el_flags
& KAUTH_EXTLOOKUP_VALID_UID
) != 0)
237 *id
= request
.el_uid
;
238 *id_type
= ID_TYPE_UID
;
240 else if ((request
.el_flags
& KAUTH_EXTLOOKUP_VALID_GID
) != 0)
242 *id
= request
.el_gid
;
243 *id_type
= ID_TYPE_GID
;
257 mbr_sid_to_uuid(const nt_sid_t
*sid
, uuid_t uu
)
260 struct kauth_identity_extlookup request
;
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
));
270 status
= _mbr_MembershipCall(&request
);
271 if (status
!= 0) return status
;
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
));
284 mbr_identifier_to_uuid(int id_type
, const void *identifier
, size_t identifier_size
, uuid_t uu
)
287 kern_return_t status
;
290 mach_msg_type_number_t oolCnt
= 0;
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;
301 /* call _ds_running() to look up _mbr_port */
304 /* if this is a UID or GID translation, we shortcut UID/GID 0 */
305 /* if no DS, we return compatibility UUIDs */
310 if (identifier_size
!= sizeof(tempID
)) return EINVAL
;
312 tempID
= *((id_t
*) identifier
);
313 if ((tempID
== 0) || (_mbr_port
== MACH_PORT_NULL
))
315 uuid_copy(uu
, _user_compat_prefix
);
316 *((id_t
*) &uu
[COMPAT_PREFIX_LEN
]) = htonl(tempID
);
323 if (identifier_size
!= sizeof(tempID
)) return EINVAL
;
325 tempID
= *((id_t
*) identifier
);
326 if ((tempID
== 0) || (_mbr_port
== MACH_PORT_NULL
))
328 uuid_copy(uu
, _group_compat_prefix
);
329 *((id_t
*) &uu
[COMPAT_PREFIX_LEN
]) = htonl(tempID
);
336 if (_mbr_port
== MACH_PORT_NULL
) return EIO
;
338 memset(&token
, 0, sizeof(audit_token_t
));
345 if (identifier_size
< sizeof(id_t
)) return EINVAL
;
346 newID
= OSSwapInt32(*((id_t
*) identifier
));
352 if (identifier_size
> MAX_MIG_INLINE_DATA
)
354 if (vm_read(mach_task_self(), (vm_offset_t
) identifier
, identifier_size
, &ool
, &oolCnt
) != 0) return ENOMEM
;
359 status
= MIG_SERVER_DIED
;
360 for (i
= 0; (_mbr_port
!= MACH_PORT_NULL
) && (status
== MIG_SERVER_DIED
) && (i
< MAX_LOOKUP_ATTEMPTS
); i
++)
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
;
365 if (status
== MACH_SEND_INVALID_DEST
)
367 if (ool
!= 0) vm_deallocate(mach_task_self(), ool
, oolCnt
);
369 mach_port_mod_refs(mach_task_self(), _mbr_port
, MACH_PORT_RIGHT_SEND
, -1);
370 _mbr_port
= MACH_PORT_NULL
;
372 status
= MIG_SERVER_DIED
;
376 if (status
!= KERN_SUCCESS
) return EIO
;
377 if (audit_token_uid(token
) != 0) return EAUTH
;
386 mbr_uuid_to_sid_type(const uuid_t uu
, nt_sid_t
*sid
, int *id_type
)
389 struct kauth_identity_extlookup request
;
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
));
397 status
= _mbr_MembershipCall(&request
);
398 if (status
!= 0) return status
;
400 if ((request
.el_flags
& KAUTH_EXTLOOKUP_VALID_USID
) != 0)
402 *id_type
= SID_TYPE_USER
;
403 memcpy(sid
, &request
.el_usid
, sizeof(nt_sid_t
));
405 else if ((request
.el_flags
& KAUTH_EXTLOOKUP_VALID_GSID
) != 0)
407 *id_type
= SID_TYPE_GROUP
;
408 memcpy(sid
, &request
.el_gsid
, sizeof(nt_sid_t
));
422 mbr_uuid_to_sid(const uuid_t uu
, nt_sid_t
*sid
)
429 status
= mbr_uuid_to_sid_type(uu
, sid
, &type
);
430 if (status
!= 0) return status
;
439 mbr_check_membership(const uuid_t user
, const uuid_t group
, int *ismember
)
442 struct kauth_identity_extlookup request
;
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
));
450 status
= _mbr_MembershipCall(&request
);
451 if (status
!= 0) return status
;
452 if ((request
.el_flags
& KAUTH_EXTLOOKUP_VALID_MEMBERSHIP
) == 0) return ENOENT
;
454 *ismember
= ((request
.el_flags
& KAUTH_EXTLOOKUP_ISMEMBER
) != 0);
462 mbr_check_membership_refresh(const uuid_t user
, uuid_t group
, int *ismember
)
465 struct kauth_identity_extlookup request
;
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
));
473 status
= _mbr_MembershipCall(&request
);
474 if (status
!= 0) return status
;
475 if ((request
.el_flags
& KAUTH_EXTLOOKUP_VALID_MEMBERSHIP
) == 0) return ENOENT
;
477 *ismember
= ((request
.el_flags
& KAUTH_EXTLOOKUP_ISMEMBER
) != 0);
485 mbr_check_membership_by_id(uuid_t user
, gid_t group
, int *ismember
)
488 struct kauth_identity_extlookup request
;
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
;
496 status
= _mbr_MembershipCall(&request
);
497 if (status
!= 0) return status
;
498 if ((request
.el_flags
& KAUTH_EXTLOOKUP_VALID_MEMBERSHIP
) == 0) return ENOENT
;
500 *ismember
= ((request
.el_flags
& KAUTH_EXTLOOKUP_ISMEMBER
) != 0);
511 return _mbr_ClearCache();
518 mbr_user_name_to_uuid(const char *name
, uuid_t uu
)
521 return _mbr_MapName((char *)name
, 1, (guid_t
*)uu
);
528 mbr_group_name_to_uuid(const char *name
, uuid_t uu
)
531 return _mbr_MapName((char *)name
, 0, (guid_t
*)uu
);
538 mbr_check_service_membership(const uuid_t user
, const char *servicename
, int *ismember
)
541 char *prefix
= "com.apple.access_";
542 char *all_services
= "com.apple.access_all_services";
547 if (servicename
== NULL
) return EINVAL
;
548 if (strlen(servicename
) > 255 - strlen(prefix
)) return EINVAL
;
550 /* start by checking "all services" */
551 result
= mbr_group_name_to_uuid(all_services
, group_uu
);
553 if (result
== EAUTH
) return result
;
555 if (result
== ENOENT
)
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
);
565 /* refreshes are driven at a higher level, just check membership */
566 result
= mbr_check_membership(user
, group_uu
, ismember
);
577 ConvertBytesToDecimal(char *buffer
, unsigned long long value
)
590 *temp
= '0' + (value
% 10);
599 mbr_sid_to_string(const nt_sid_t
*sid
, char *string
)
602 char *current
= string
;
607 if (sid
->sid_authcount
> NTSID_MAX_AUTHORITIES
) return EINVAL
;
609 for (i
= 0; i
< 6; i
++)
610 temp
= (temp
<< 8) | sid
->sid_authority
[i
];
615 strcpy(current
, ConvertBytesToDecimal(tempBuffer
, sid
->sid_kind
));
616 current
= current
+ strlen(current
);
619 strcpy(current
, ConvertBytesToDecimal(tempBuffer
, temp
));
621 for(i
=0; i
< sid
->sid_authcount
; i
++)
623 current
= current
+ strlen(current
);
626 strcpy(current
, ConvertBytesToDecimal(tempBuffer
, sid
->sid_authorities
[i
]));
636 mbr_string_to_sid(const char *string
, nt_sid_t
*sid
)
639 char *current
= (char *)string
+2;
643 if (string
== NULL
) return EINVAL
;
645 memset(sid
, 0, sizeof(nt_sid_t
));
646 if (string
[0] != 'S' || string
[1] != '-') return EINVAL
;
648 sid
->sid_kind
= strtol(current
, ¤t
, 10);
649 if (*current
== '\0') return EINVAL
;
651 temp
= strtoll(current
, ¤t
, 10);
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
)
660 sid
->sid_authorities
[count
] = (u_int32_t
)strtoll(current
, ¤t
, 10);
661 if ((sid
->sid_authorities
[count
] == 0) && (errno
== EINVAL
)) {
667 if (*current
!= '\0') return EINVAL
;
669 sid
->sid_authcount
= count
;
679 ConvertBytesToHex(char **string
, char **data
, int numBytes
)
683 for (i
=0; i
< numBytes
; i
++)
685 unsigned char hi
= ((**data
) >> 4) & 0xf;
686 unsigned char low
= (**data
) & 0xf;
690 **string
= 'A' + hi
- 10;
695 **string
= '0' + low
;
697 **string
= 'A' + low
- 10;
706 mbr_uuid_to_string(const uuid_t uu
, char *string
)
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);
729 mbr_string_to_uuid(const char *string
, uuid_t uu
)
733 int isFirstNibble
= 1;
735 if (string
== NULL
) return EINVAL
;
736 if (strlen(string
) > MBR_UU_STRING_SIZE
) return EINVAL
;
738 while (*string
!= '\0' && dataIndex
< 16)
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;
758 uu
[dataIndex
] = nibble
<< 4;
763 uu
[dataIndex
] |= nibble
;
771 if (dataIndex
!= 16) return EINVAL
;
780 mbr_set_identifier_ttl(int id_type
, const void *identifier
, size_t identifier_size
, unsigned int seconds
)
783 _mbr_SetIdentifierTTL(id_type
, identifier
, identifier_size
, seconds
);