]> git.saurik.com Git - apple/security.git/blob - OSX/authd/credential.c
Security-59754.41.1.tar.gz
[apple/security.git] / OSX / authd / credential.c
1 /* Copyright (c) 2012-2013 Apple Inc. All Rights Reserved. */
2
3 #include "credential.h"
4 #include "authutilities.h"
5 #include "authitems.h"
6 #include <Security/AuthorizationTagsPriv.h>
7 #include "debugging.h"
8 #include "crc.h"
9
10 #include <pwd.h>
11 #include <membership.h>
12 #include <membershipPriv.h>
13
14 struct _credential_s {
15 __AUTH_BASE_STRUCT_HEADER__;
16
17 bool right; // is least-privileged credential
18
19 uid_t uid;
20 char * name;
21 char * realName;
22
23 CFAbsoluteTime creationTime;
24 bool valid;
25 bool shared;
26
27 CFMutableSetRef cachedGroups;
28 };
29
30 static void
31 _credential_finalize(CFTypeRef value)
32 {
33 credential_t cred = (credential_t)value;
34
35 free_safe(cred->name);
36 free_safe(cred->realName);
37 CFReleaseNull(cred->cachedGroups);
38 }
39
40 static CFStringRef
41 _credential_copy_description(CFTypeRef value)
42 {
43 credential_t cred = (credential_t)value;
44 CFStringRef str = NULL;
45 CFTimeZoneRef sys_tz = CFTimeZoneCopySystem();
46 CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(cred->creationTime, sys_tz);
47 CFReleaseSafe(sys_tz);
48 if (cred->right) {
49 str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("credential: right=%s, shared=%i, creation=%01i:%01i:%01i, valid=%i"), cred->name, cred->shared, date.hour,date.minute,(int32_t)date.second, cred->valid);
50 } else {
51 str = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("credential: uid=%i, name=%s, shared=%i, creation=%01i:%01i:%01i valid=%i"), cred->uid, cred->name, cred->shared, date.hour,date.minute,(int32_t)date.second, cred->valid);
52 }
53 return str;
54 }
55
56 static CFHashCode
57 _credential_hash(CFTypeRef value)
58 {
59 credential_t cred = (credential_t)value;
60 uint64_t crc = crc64_init();
61 if (cred->right) {
62 crc = crc64_update(crc, cred->name, strlen(cred->name));
63 } else {
64 crc = crc64_update(crc, &cred->uid, sizeof(cred->uid));
65 }
66 crc = crc64_update(crc, &cred->shared, sizeof(cred->shared));
67 crc = crc64_final(crc);
68
69 return (CFHashCode)crc;
70 }
71
72 static Boolean
73 _credential_equal(CFTypeRef value1, CFTypeRef value2)
74 {
75 credential_t cred1 = (credential_t)value1;
76 credential_t cred2 = (credential_t)value2;
77
78 return _credential_hash(cred1) == _credential_hash(cred2);
79 }
80
81 AUTH_TYPE_INSTANCE(credential,
82 .init = NULL,
83 .copy = NULL,
84 .finalize = _credential_finalize,
85 .equal = _credential_equal,
86 .hash = _credential_hash,
87 .copyFormattingDesc = NULL,
88 .copyDebugDesc = _credential_copy_description
89 );
90
91 static CFTypeID credential_get_type_id() {
92 static CFTypeID type_id = _kCFRuntimeNotATypeID;
93 static dispatch_once_t onceToken;
94
95 dispatch_once(&onceToken, ^{
96 type_id = _CFRuntimeRegisterClass(&_auth_type_credential);
97 });
98
99 return type_id;
100 }
101
102 static credential_t
103 _credential_create()
104 {
105 credential_t cred = NULL;
106
107 cred = (credential_t)_CFRuntimeCreateInstance(kCFAllocatorDefault, credential_get_type_id(), AUTH_CLASS_SIZE(credential), NULL);
108 require(cred != NULL, done);
109
110 cred->creationTime = CFAbsoluteTimeGetCurrent();
111 cred->cachedGroups = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);;
112
113 done:
114 return cred;
115 }
116
117 credential_t
118 credential_create(uid_t uid)
119 {
120 credential_t cred = NULL;
121
122 cred = _credential_create();
123 require(cred != NULL, done);
124
125 struct passwd *pw = getpwuid(uid);
126 if (pw != NULL) {
127 // avoid hinting a locked account
128 // LibInfo started to return asterisk for system accounts in <rdar://problem/31633690> J93: 17a240: Hang during boot (opendirectoryd/powerd deadlock)
129 // so do not make this check for those system accounts
130 if ( (uid < 500) || (pw->pw_passwd == NULL) || strcmp(pw->pw_passwd, "*") ) {
131 cred->uid = pw->pw_uid;
132 cred->name = _copy_string(pw->pw_name);
133 cred->realName = _copy_string(pw->pw_gecos);
134 cred->valid = true;
135 } else {
136 cred->uid = (uid_t)-2;
137 cred->valid = false;
138 }
139 endpwent();
140 }
141
142 done:
143 return cred;
144 }
145
146 credential_t
147 credential_create_lwos(auth_items_t context, bool session)
148 {
149 credential_t cred = NULL;
150
151 cred = _credential_create();
152 require(cred != NULL, done);
153
154 const char *username = session ? "system session" : auth_items_get_string(context, AGENT_USERNAME);
155 cred->uid = session ? 0 : -500;
156 cred->name = _copy_string(username);
157 cred->realName = _copy_string(username);
158 cred->valid = false;
159 done:
160 return cred;
161 }
162
163 credential_t
164 credential_create_with_credential(credential_t srcCred, bool shared)
165 {
166 credential_t cred = NULL;
167
168 cred = _credential_create();
169 require(cred != NULL, done);
170
171 cred->uid = srcCred->uid;
172 cred->name = _copy_string(srcCred->name);
173 cred->realName = _copy_string(srcCred->realName);
174 cred->valid = srcCred->valid;
175 cred->right = srcCred->right;
176 cred->shared = shared;
177
178 done:
179 return cred;
180 }
181
182 credential_t
183 credential_create_with_right(const char * right)
184 {
185 credential_t cred = NULL;
186
187 cred = _credential_create();
188 require(cred != NULL, done);
189
190 cred->right = true;
191 cred->name = _copy_string(right);
192 cred->uid = (uid_t)-2;
193 cred->valid = true;
194
195 done:
196 return cred;
197 }
198
199 uid_t
200 credential_get_uid(credential_t cred)
201 {
202 return cred->uid;
203 }
204
205 const char *
206 credential_get_name(credential_t cred)
207 {
208 return cred->name;
209 }
210
211 const char *
212 credential_get_realname(credential_t cred)
213 {
214 return cred->realName;
215 }
216
217 CFAbsoluteTime
218 credential_get_creation_time(credential_t cred)
219 {
220 return cred->creationTime;
221 }
222
223 bool
224 credential_get_valid(credential_t cred)
225 {
226 return cred->valid;
227 }
228
229 bool
230 credential_get_shared(credential_t cred)
231 {
232 return cred->shared;
233 }
234
235 bool
236 credential_is_right(credential_t cred)
237 {
238 return cred->right;
239 }
240
241 bool
242 credential_check_membership(credential_t cred, const char* group)
243 {
244 bool result = false;
245
246 if (isInLWOS()) {
247 return false; // cannot succeed in LWOS as we do not have group data
248 }
249
250 CFStringRef cachedGroup = NULL;
251 require(group != NULL, done);
252 require(cred->uid != 0 || cred->uid != (uid_t)-2, done);
253 require(cred->right != true, done);
254
255 cachedGroup = CFStringCreateWithCString(kCFAllocatorDefault, group, kCFStringEncodingUTF8);
256 require(cachedGroup != NULL, done);
257
258 if (CFSetGetValue(cred->cachedGroups, cachedGroup) != NULL) {
259 result = true;
260 goto done;
261 }
262
263 int rc, ismember;
264 uuid_t group_uuid, user_uuid;
265 rc = mbr_group_name_to_uuid(group, group_uuid);
266 require_noerr(rc, done);
267
268 rc = mbr_uid_to_uuid(cred->uid, user_uuid);
269 require_noerr(rc, done);
270
271 rc = mbr_check_membership(user_uuid, group_uuid, &ismember);
272 require_noerr(rc, done);
273
274 result = ismember;
275
276 if (ismember) {
277 CFSetSetValue(cred->cachedGroups, cachedGroup);
278 }
279
280 done:
281 CFReleaseSafe(cachedGroup);
282 return result;
283 }
284
285 void
286 credential_invalidate(credential_t cred)
287 {
288 cred->valid = false;
289 }