]>
Commit | Line | Data |
---|---|---|
d8f41ccd | 1 | /* Copyright (c) 2012-2013 Apple Inc. All Rights Reserved. */ |
427c49bc A |
2 | |
3 | #include "ccaudit.h" | |
4 | #include "debugging.h" | |
5 | #include "process.h" | |
6 | #include "authtoken.h" | |
7 | ||
8 | #include <Security/Authorization.h> | |
9 | #include <Security/AuthorizationPlugin.h> | |
10 | #include <bsm/libbsm.h> | |
11 | ||
12 | ||
13 | struct _ccaudit_s { | |
14 | __AUTH_BASE_STRUCT_HEADER__; | |
15 | ||
16 | int fd; | |
17 | int32_t event; | |
18 | ||
19 | auth_token_t auth; | |
20 | process_t proc; | |
21 | audit_info_s auditInfo; | |
22 | au_tid_t tid; | |
23 | }; | |
24 | ||
25 | static void | |
26 | _ccaudit_finalizer(CFTypeRef value) | |
27 | { | |
28 | ccaudit_t ccaudit = (ccaudit_t)value; | |
29 | ||
30 | CFReleaseSafe(ccaudit->auth); | |
31 | CFReleaseSafe(ccaudit->proc); | |
32 | } | |
33 | ||
34 | AUTH_TYPE_INSTANCE(ccaudit, | |
35 | .init = NULL, | |
36 | .copy = NULL, | |
37 | .finalize = _ccaudit_finalizer, | |
38 | .equal = NULL, | |
39 | .hash = NULL, | |
40 | .copyFormattingDesc = NULL, | |
41 | .copyDebugDesc = NULL | |
42 | ); | |
43 | ||
44 | static CFTypeID ccaudit_get_type_id() { | |
45 | static CFTypeID type_id = _kCFRuntimeNotATypeID; | |
46 | static dispatch_once_t onceToken; | |
47 | ||
48 | dispatch_once(&onceToken, ^{ | |
49 | type_id = _CFRuntimeRegisterClass(&_auth_type_ccaudit); | |
50 | }); | |
51 | ||
52 | return type_id; | |
53 | } | |
54 | ||
55 | ccaudit_t | |
56 | ccaudit_create(process_t proc, auth_token_t auth, int32_t event) | |
57 | { | |
58 | ccaudit_t ccaudit = NULL; | |
59 | ||
60 | require(auth != NULL, done); | |
61 | ||
62 | ccaudit = (ccaudit_t)_CFRuntimeCreateInstance(kCFAllocatorDefault, ccaudit_get_type_id(), AUTH_CLASS_SIZE(ccaudit), NULL); | |
63 | require(ccaudit != NULL, done); | |
64 | ||
65 | ccaudit->auth = (auth_token_t)CFRetain(auth); | |
66 | ccaudit->proc = (process_t)CFRetain(proc); | |
67 | ccaudit->fd = -1; | |
68 | ccaudit->event = event; | |
69 | ||
70 | ccaudit->auditInfo = *auth_token_get_audit_info(auth); | |
71 | ccaudit->tid.port = ccaudit->auditInfo.tid; | |
72 | ||
73 | done: | |
74 | return ccaudit; | |
75 | } | |
76 | ||
77 | static bool _enabled() | |
78 | { | |
79 | static dispatch_once_t onceToken; | |
80 | static bool enabled = false; | |
81 | ||
82 | dispatch_once(&onceToken, ^{ | |
83 | int acond = au_get_state(); | |
84 | switch (acond) { | |
85 | case AUC_NOAUDIT: | |
86 | break; | |
87 | case AUC_AUDITING: | |
88 | enabled = true; | |
89 | break; | |
90 | default: | |
91 | LOGE("ccaudit: error checking auditing status (%d)", acond); | |
92 | } | |
93 | }); | |
94 | ||
95 | return enabled; | |
96 | } | |
97 | ||
98 | static bool _open(ccaudit_t ccaudit) | |
99 | { | |
100 | if (!_enabled()) { | |
101 | return false; | |
102 | } | |
103 | ||
104 | if (-1 != ccaudit->fd) | |
105 | return true; | |
106 | ||
107 | if ((ccaudit->fd = au_open()) < 0) { | |
108 | LOGE("ccaudit: au_open() failed (%s)", strerror(errno)); | |
109 | return false; | |
110 | } | |
111 | ||
112 | return true; | |
113 | } | |
114 | ||
115 | static void _close(ccaudit_t ccaudit) | |
116 | { | |
117 | if (-1 != ccaudit->fd) { | |
118 | int err = au_close(ccaudit->fd, AU_TO_WRITE, (short)ccaudit->event); | |
119 | ccaudit->fd = -1; | |
120 | if (err < 0) { | |
121 | LOGE("ccaudit: au_close() failed; record not committed"); | |
122 | } | |
123 | } | |
124 | } | |
125 | ||
126 | static bool _write(ccaudit_t ccaudit, token_t * token, const char * name) | |
127 | { | |
128 | const char *tokenName = name ? name : "<unidentified>"; | |
129 | if (NULL == token) | |
130 | { | |
131 | LOGE("ccaudit: invalid '%s' token", tokenName); | |
132 | return false; | |
133 | } | |
134 | if (au_write(ccaudit->fd, token) < 0) { | |
135 | LOGE("ccaudit: error writing '%s' token (%s)", tokenName, strerror(errno)); | |
136 | return false; | |
137 | } | |
138 | return true; | |
139 | } | |
140 | ||
141 | static bool _subject(ccaudit_t ccaudit) | |
142 | { | |
143 | token_t * token = au_to_subject32(ccaudit->auditInfo.auid, ccaudit->auditInfo.euid, ccaudit->auditInfo.egid, | |
144 | ccaudit->auditInfo.ruid, ccaudit->auditInfo.rgid, ccaudit->auditInfo.pid, ccaudit->auditInfo.asid, &ccaudit->tid); | |
145 | return _write(ccaudit, token, "subject"); | |
146 | } | |
147 | ||
148 | void ccaudit_log_authorization(ccaudit_t ccaudit, const char * right, OSStatus err) | |
149 | { | |
150 | ||
151 | if (!_open(ccaudit)) { | |
152 | return; | |
153 | } | |
154 | char buf[PATH_MAX+1]; | |
155 | ||
156 | _subject(ccaudit); | |
157 | _write(ccaudit, au_to_text(right), "right"); | |
158 | snprintf(buf, sizeof(buf), "client %s", process_get_code_url(ccaudit->proc)); | |
159 | _write(ccaudit, au_to_text(buf), "Authorization client"); | |
160 | snprintf(buf, sizeof(buf), "creator %s", auth_token_get_code_url(ccaudit->auth)); | |
161 | _write(ccaudit, au_to_text(buf), "Authorization creator"); | |
162 | ||
163 | if (auth_token_least_privileged(ccaudit->auth)) { | |
164 | _write(ccaudit, au_to_text("least-privilege"), "least-privilege"); | |
165 | } | |
166 | ||
167 | if (err == errAuthorizationSuccess) { | |
168 | _write(ccaudit, au_to_return32(0, 0), "return"); | |
169 | } else { | |
170 | _write(ccaudit, au_to_return32(EPERM, (uint32_t)err), "return"); | |
171 | } | |
172 | ||
173 | _close(ccaudit); | |
174 | } | |
175 | ||
176 | void ccaudit_log_success(ccaudit_t ccaudit, credential_t cred, const char * right) | |
177 | { | |
178 | ||
179 | if (!_open(ccaudit)) { | |
180 | return; | |
181 | } | |
182 | char buf[PATH_MAX+1]; | |
183 | ||
184 | _subject(ccaudit); | |
185 | _write(ccaudit, au_to_text(right), "right"); | |
186 | _write(ccaudit, au_to_arg32(1, "known UID ", auth_token_get_uid(ccaudit->auth)), "authenticator"); | |
187 | snprintf(buf, sizeof(buf), "authenticated as %s", credential_get_name(cred)); | |
188 | _write(ccaudit, au_to_arg32(2, buf, credential_get_uid(cred)), "target"); | |
189 | _write(ccaudit, au_to_return32(0, 0), "return"); | |
190 | ||
191 | _close(ccaudit); | |
192 | } | |
193 | ||
fa7225c8 A |
194 | #pragma clang diagnostic push |
195 | #pragma clang diagnostic ignored "-Wunused-parameter" | |
196 | ||
427c49bc A |
197 | void ccaudit_log_failure(ccaudit_t ccaudit, const char * credName, const char * right) |
198 | { | |
199 | ||
200 | if (!_open(ccaudit)) { | |
201 | return; | |
202 | } | |
203 | _subject(ccaudit); | |
204 | _write(ccaudit, au_to_text(right), "right"); | |
205 | _write(ccaudit, au_to_arg32(1, "authenticated as ", auth_token_get_uid(ccaudit->auth)), "authenticator"); | |
206 | ||
fa7225c8 | 207 | _write(ccaudit, au_to_text("<unknown user>"), "target username"); |
427c49bc A |
208 | _write(ccaudit, au_to_return32(EPERM, (uint32_t)errAuthorizationDenied), "return"); |
209 | ||
210 | _close(ccaudit); | |
211 | } | |
212 | ||
fa7225c8 A |
213 | #pragma clang diagnostic pop |
214 | ||
427c49bc A |
215 | void ccaudit_log_mechanism(ccaudit_t ccaudit, const char * right, const char * mech, uint32_t status, const char * interrupted) |
216 | { | |
217 | ||
218 | if (!_open(ccaudit)) { | |
219 | return; | |
220 | } | |
221 | char buf[PATH_MAX+1]; | |
222 | ||
223 | _subject(ccaudit); | |
224 | _write(ccaudit, au_to_text(right), "right"); | |
225 | snprintf(buf, sizeof(buf), "mechanism %s", mech); | |
226 | _write(ccaudit, au_to_text(buf), "mechanism"); | |
227 | ||
228 | if (interrupted) { | |
229 | _write(ccaudit, au_to_text(interrupted), "interrupt"); | |
230 | } | |
231 | ||
232 | if (status == kAuthorizationResultAllow) { | |
233 | _write(ccaudit, au_to_return32(0, 0), "return"); | |
234 | } else { | |
235 | _write(ccaudit, au_to_return32(EPERM, (uint32_t)status), "return"); | |
236 | } | |
237 | ||
238 | _close(ccaudit); | |
239 | } | |
240 | ||
241 | void ccaudit_log(ccaudit_t ccaudit, const char * right, const char * msg, OSStatus err) | |
242 | { | |
243 | if (!_open(ccaudit)) { | |
244 | return; | |
245 | } | |
246 | ||
247 | _subject(ccaudit); | |
248 | _write(ccaudit, au_to_text(right), "right"); | |
249 | ||
250 | if (msg) { | |
251 | _write(ccaudit, au_to_text(msg), "evaluation error"); | |
252 | } | |
253 | ||
254 | if (err == errAuthorizationSuccess) { | |
255 | _write(ccaudit, au_to_return32(0, 0), "return"); | |
256 | } else { | |
257 | _write(ccaudit, au_to_return32(EPERM, (uint32_t)err), "return"); | |
258 | } | |
259 | ||
260 | _close(ccaudit); | |
261 | } |