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