]>
Commit | Line | Data |
---|---|---|
427c49bc A |
1 | /* Copyright (c) 2012 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 | CFReleaseSafe(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 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 | if ( (pw->pw_passwd == NULL) || strcmp(pw->pw_passwd, "*") ) { | |
127 | cred->uid = pw->pw_uid; | |
128 | cred->name = _copy_string(pw->pw_name); | |
129 | cred->realName = _copy_string(pw->pw_gecos); | |
130 | cred->valid = true; | |
131 | } else { | |
132 | cred->uid = (uid_t)-2; | |
133 | cred->valid = false; | |
134 | } | |
135 | endpwent(); | |
136 | } | |
137 | ||
138 | done: | |
139 | return cred; | |
140 | } | |
141 | ||
142 | credential_t | |
143 | credential_create_with_credential(credential_t srcCred, bool shared) | |
144 | { | |
145 | credential_t cred = NULL; | |
146 | ||
147 | cred = _credential_create(); | |
148 | require(cred != NULL, done); | |
149 | ||
150 | cred->uid = srcCred->uid; | |
151 | cred->name = _copy_string(srcCred->name); | |
152 | cred->realName = _copy_string(srcCred->realName); | |
153 | cred->valid = srcCred->valid; | |
154 | cred->right = srcCred->right; | |
155 | cred->shared = shared; | |
156 | ||
157 | done: | |
158 | return cred; | |
159 | } | |
160 | ||
161 | credential_t | |
162 | credential_create_with_right(const char * right) | |
163 | { | |
164 | credential_t cred = NULL; | |
165 | ||
166 | cred = _credential_create(); | |
167 | require(cred != NULL, done); | |
168 | ||
169 | cred->right = true; | |
170 | cred->name = _copy_string(right); | |
171 | cred->uid = (uid_t)-2; | |
172 | cred->valid = true; | |
173 | ||
174 | done: | |
175 | return cred; | |
176 | } | |
177 | ||
178 | uid_t | |
179 | credential_get_uid(credential_t cred) | |
180 | { | |
181 | return cred->uid; | |
182 | } | |
183 | ||
184 | const char * | |
185 | credential_get_name(credential_t cred) | |
186 | { | |
187 | return cred->name; | |
188 | } | |
189 | ||
190 | const char * | |
191 | credential_get_realname(credential_t cred) | |
192 | { | |
193 | return cred->realName; | |
194 | } | |
195 | ||
196 | CFAbsoluteTime | |
197 | credential_get_creation_time(credential_t cred) | |
198 | { | |
199 | return cred->creationTime; | |
200 | } | |
201 | ||
202 | bool | |
203 | credential_get_valid(credential_t cred) | |
204 | { | |
205 | return cred->valid; | |
206 | } | |
207 | ||
208 | bool | |
209 | credential_get_shared(credential_t cred) | |
210 | { | |
211 | return cred->shared; | |
212 | } | |
213 | ||
214 | bool | |
215 | credential_is_right(credential_t cred) | |
216 | { | |
217 | return cred->right; | |
218 | } | |
219 | ||
220 | bool | |
221 | credential_check_membership(credential_t cred,const char* group) | |
222 | { | |
223 | bool result = false; | |
224 | CFStringRef cachedGroup = NULL; | |
225 | require(group != NULL, done); | |
226 | require(cred->uid != 0 || cred->uid != (uid_t)-2, done); | |
227 | require(cred->right != true, done); | |
228 | ||
229 | cachedGroup = CFStringCreateWithCString(kCFAllocatorDefault, group, kCFStringEncodingUTF8); | |
230 | require(cachedGroup != NULL, done); | |
231 | ||
232 | if (CFSetGetValue(cred->cachedGroups, cachedGroup) != NULL) { | |
233 | result = true; | |
234 | goto done; | |
235 | } | |
236 | ||
237 | int rc, ismember; | |
238 | uuid_t group_uuid, user_uuid; | |
239 | rc = mbr_group_name_to_uuid(group, group_uuid); | |
240 | require_noerr(rc, done); | |
241 | ||
242 | rc = mbr_uid_to_uuid(cred->uid, user_uuid); | |
243 | require_noerr(rc, done); | |
244 | ||
245 | rc = mbr_check_membership(user_uuid, group_uuid, &ismember); | |
246 | require_noerr(rc, done); | |
247 | ||
248 | result = ismember; | |
249 | ||
250 | if (ismember) { | |
251 | CFSetSetValue(cred->cachedGroups, cachedGroup); | |
252 | } | |
253 | ||
254 | done: | |
255 | CFReleaseSafe(cachedGroup); | |
256 | return result; | |
257 | } | |
258 | ||
259 | void | |
260 | credential_invalidate(credential_t cred) | |
261 | { | |
262 | cred->valid = false; | |
263 | } |