]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
1 | /* |
2 | * ccaudit_extensions.cpp | |
3 | * securityd | |
4 | * | |
5 | * Created by G H on 3/24/09. | |
6 | * Copyright (c) 2009 Apple Inc. All Rights Reserved. | |
7 | * | |
8 | */ | |
9 | ||
10 | #include <errno.h> | |
11 | #include <assert.h> | |
12 | #include <stdio.h> // vsnprintf() | |
13 | #include <stdarg.h> // va_start(), et al. | |
14 | #include <syslog.h> | |
15 | #include <string.h> // memcpy() | |
16 | #include <bsm/audit_uevents.h> // AUE_ssauth* | |
17 | #include <bsm/libbsm.h> | |
18 | #include <security_utilities/errors.h> | |
19 | #include <security_utilities/ccaudit.h> | |
20 | #include "ccaudit_extensions.h" | |
21 | ||
22 | namespace Security | |
23 | { | |
24 | ||
25 | namespace CommonCriteria | |
26 | { | |
27 | ||
28 | namespace Securityd | |
29 | { | |
30 | ||
31 | // | |
32 | // AuditLogger | |
33 | // | |
34 | AuditLogger::AuditLogger(const audit_token_t *srcToken, short auEvent) | |
35 | : mAuditFd(-1), mEvent(auEvent), mClientInfoSet(false) | |
36 | { | |
37 | setClientInfo(srcToken); | |
38 | } | |
39 | ||
40 | AuditLogger::AuditLogger(const AuditToken &srcToken, short auEvent) | |
41 | : mAuditFd(-1), mEvent(auEvent), mClientInfoSet(false) | |
42 | { | |
43 | setClientInfo(srcToken); | |
44 | } | |
45 | ||
46 | AuditLogger::~AuditLogger() | |
47 | { | |
48 | close(); | |
49 | } | |
50 | ||
51 | bool | |
52 | AuditLogger::open() | |
53 | { | |
54 | if (-1 != mAuditFd) | |
55 | return true; | |
56 | ||
57 | // @@@ use audit_get_cond() when it's available | |
58 | int acond = au_get_state(); | |
59 | switch (acond) | |
60 | { | |
61 | case AUC_NOAUDIT: | |
62 | return false; | |
63 | case AUC_AUDITING: | |
64 | break; | |
65 | default: | |
66 | logInternalError("error checking auditing status (%d)", acond); | |
67 | UnixError::throwMe(acond); // assume it's a Unix error | |
68 | } | |
69 | if ((mAuditFd = au_open()) < 0) | |
70 | { | |
71 | logInternalError("au_open() failed (%s)", strerror(errno)); | |
72 | UnixError::throwMe(errno); | |
73 | } | |
74 | return true; | |
75 | } | |
76 | ||
77 | void | |
78 | AuditLogger::close(bool writeLog/* = true*/) | |
79 | { | |
80 | if (-1 != mAuditFd) | |
81 | { | |
82 | int keep = writeLog == true ? AU_TO_WRITE : AU_TO_NO_WRITE; | |
83 | int error = au_close(mAuditFd, keep, mEvent); | |
84 | mAuditFd = -1; | |
85 | if (writeLog == true && error < 0) | |
86 | { | |
87 | logInternalError("au_close() failed; record not committed"); | |
88 | UnixError::throwMe(error); | |
89 | } | |
90 | } | |
91 | } | |
92 | ||
93 | void | |
94 | AuditLogger::setClientInfo(const audit_token_t *srcToken) | |
95 | { | |
96 | assert(srcToken); | |
97 | audit_token_to_au32(*srcToken, &mAuditId, &mEuid, &mEgid, &mRuid, &mRgid, &mPid, &mAuditSessionId, &mOldTerminalId); | |
98 | ||
99 | mTerminalId.at_type = AU_IPv4; | |
100 | mTerminalId.at_addr[0] = mOldTerminalId.machine; | |
101 | mTerminalId.at_port = mOldTerminalId.port; | |
102 | ||
103 | mClientInfoSet = true; | |
104 | } | |
105 | ||
106 | void | |
107 | AuditLogger::setClientInfo(const AuditToken &srcToken) | |
108 | { | |
109 | mAuditId = srcToken.auditId(); | |
110 | mEuid = srcToken.euid(); | |
111 | mEgid = srcToken.egid(); | |
112 | mRuid = srcToken.ruid(); | |
113 | mRgid = srcToken.rgid(); | |
114 | mPid = srcToken.pid(); | |
115 | mAuditSessionId = srcToken.sessionId(); | |
116 | memcpy(&mOldTerminalId, &(srcToken.terminalId()), sizeof(mOldTerminalId)); | |
117 | ||
118 | mTerminalId.at_type = AU_IPv4; | |
119 | mTerminalId.at_addr[0] = mOldTerminalId.machine; | |
120 | mTerminalId.at_port = mOldTerminalId.port; | |
121 | ||
122 | mClientInfoSet = true; | |
123 | } | |
124 | ||
125 | void | |
126 | AuditLogger::writeToken(token_t *token, const char *name) | |
127 | { | |
128 | const char *tokenName = name ? name : "<unidentified>"; | |
129 | if (NULL == token) | |
130 | { | |
131 | logInternalError("Invalid '%s' token", tokenName); | |
132 | close(); | |
133 | UnixError::throwMe(EPERM); // per audit_submit() | |
134 | } | |
135 | if (au_write(mAuditFd, token) < 0) | |
136 | { | |
137 | logInternalError("Error writing '%s' token (%s)", tokenName, strerror(errno)); | |
138 | close(); | |
139 | UnixError::throwMe(errno); | |
140 | } | |
141 | } | |
142 | ||
143 | void | |
144 | AuditLogger::writeSubject() | |
145 | { | |
146 | assert(mClientInfoSet); | |
147 | ||
148 | token_t *token; | |
149 | ||
150 | // @@@ terminal ID is not carried in the audit trailer nowadays, but | |
151 | // this code should be harmless: it replicates the current logic in | |
152 | // audit_submit() | |
153 | if (AU_IPv4 == mTerminalId.at_type) | |
154 | token = au_to_subject32(mAuditId, mEuid, mEgid, mRuid, mRgid, mPid, mAuditSessionId, &mOldTerminalId); | |
155 | else | |
156 | token = au_to_subject_ex(mAuditId, mEuid, mEgid, mRuid, mRgid, mPid, mAuditSessionId, &mTerminalId); | |
157 | writeToken(token, "subject"); | |
158 | } | |
159 | ||
160 | void | |
161 | AuditLogger::writeReturn(char status, int reterr) | |
162 | { | |
163 | writeToken(au_to_return32(status, reterr), "return"); | |
164 | } | |
165 | ||
166 | void | |
167 | AuditLogger::logSuccess() | |
168 | { | |
169 | if (false == open()) | |
170 | return; | |
171 | writeCommon(); | |
172 | writeReturn(0, 0); | |
173 | close(); | |
174 | } | |
175 | ||
176 | void | |
177 | AuditLogger::logFailure(const char *errMsg, int errcode) | |
178 | { | |
179 | if (false == open()) | |
180 | return; | |
181 | writeCommon(); | |
182 | if (errMsg) | |
183 | writeToken(au_to_text(errMsg), "evaluation error"); | |
184 | writeReturn(EPERM, errcode); | |
185 | close(); | |
186 | } | |
187 | ||
188 | // cribbed from audit_submit() | |
189 | void | |
190 | AuditLogger::logInternalError(const char *fmt, ...) | |
191 | { | |
192 | va_list ap; | |
193 | char text[MAX_AUDITSTRING_LEN]; | |
194 | ||
195 | if (fmt != NULL) | |
196 | { | |
197 | int error = errno; | |
198 | va_start(ap, fmt); | |
199 | (void)vsnprintf(text, MAX_AUDITSTRING_LEN, fmt, ap); | |
200 | va_end(ap); | |
201 | syslog(LOG_AUTH | LOG_ERR, "%s", text); | |
202 | errno = error; | |
203 | } | |
204 | } | |
205 | ||
206 | // | |
207 | // KeychainAuthLogger | |
208 | // | |
209 | const char *KeychainAuthLogger::sysKCAuthStr = "System keychain authorization"; | |
210 | const char *KeychainAuthLogger::unknownKCStr = "<unknown keychain>"; | |
211 | const char *KeychainAuthLogger::unknownItemStr = "<unknown item>"; | |
212 | ||
213 | KeychainAuthLogger::KeychainAuthLogger(const audit_token_t *srcToken, short auEvent) | |
214 | : AuditLogger(srcToken, auEvent), mDatabase(unknownKCStr), | |
215 | mItem(unknownItemStr) | |
216 | { | |
217 | } | |
218 | ||
219 | KeychainAuthLogger::KeychainAuthLogger(const AuditToken &srcToken, short auEvent) | |
220 | : AuditLogger(srcToken, auEvent), mDatabase(unknownKCStr), | |
221 | mItem(unknownItemStr) | |
222 | { | |
223 | } | |
224 | ||
225 | KeychainAuthLogger::KeychainAuthLogger(const audit_token_t *srcToken, short auEvent, const char *database, const char *item) | |
226 | : AuditLogger(srcToken, auEvent) | |
227 | { | |
228 | setDbName(database); | |
229 | setItemName(item); | |
230 | } | |
231 | ||
232 | KeychainAuthLogger::KeychainAuthLogger(const AuditToken &srcToken, short auEvent, const char *database, const char *item) | |
233 | : AuditLogger(srcToken, auEvent) | |
234 | { | |
235 | setDbName(database); | |
236 | setItemName(item); | |
237 | } | |
238 | ||
239 | void | |
240 | KeychainAuthLogger::setDbName(const char *database) | |
241 | { | |
242 | mDatabase = database ? database : unknownKCStr; | |
243 | } | |
244 | ||
245 | void | |
246 | KeychainAuthLogger::setItemName(const char *item) | |
247 | { | |
248 | mItem = item ? item : unknownItemStr; | |
249 | } | |
250 | ||
251 | void | |
252 | KeychainAuthLogger::writeCommon() | |
253 | { | |
254 | writeSubject(); | |
255 | writeToken(au_to_text(sysKCAuthStr), sysKCAuthStr); | |
256 | writeToken(au_to_text(mDatabase.c_str()), "keychain"); | |
257 | writeToken(au_to_text(mItem.c_str()), "keychain item"); | |
258 | } | |
259 | ||
260 | ||
261 | // | |
262 | // RightLogger | |
263 | // | |
264 | const char *RightLogger::unknownRightStr = "<unknown right>"; | |
265 | ||
266 | void | |
267 | RightLogger::setRight(const string &rightName) | |
268 | { | |
269 | mRight.clear(); | |
270 | mRight = rightName; | |
271 | } | |
272 | ||
273 | void | |
274 | RightLogger::setRight(const char *rightName) | |
275 | { | |
276 | if (rightName) // NULL bad for string class and au_to_text() | |
277 | { | |
278 | string tmpStr(rightName); // setRight() takes a string& | |
279 | setRight(tmpStr); | |
280 | } | |
281 | } | |
282 | ||
283 | ||
284 | // | |
285 | // AuthMechLogger | |
286 | // | |
287 | const char *AuthMechLogger::unknownMechStr = "<unknown mechanism>"; | |
288 | const char *AuthMechLogger::mechStr = "mechanism "; | |
289 | ||
290 | AuthMechLogger::AuthMechLogger(const AuditToken &srcToken, short auEvent) | |
291 | : AuditLogger(srcToken, auEvent), RightLogger(), | |
292 | mEvaluatingMechanism(false), mCurrentMechanism(unknownMechStr) | |
293 | { | |
294 | } | |
295 | ||
296 | AuthMechLogger::AuthMechLogger(const audit_token_t *srcToken, short auEvent) | |
297 | : AuditLogger(srcToken, auEvent), RightLogger(), | |
298 | mEvaluatingMechanism(false), mCurrentMechanism(unknownMechStr) | |
299 | { | |
300 | } | |
301 | ||
302 | void | |
303 | AuthMechLogger::setCurrentMechanism(const char *mech) | |
304 | { | |
305 | mCurrentMechanism.clear(); | |
306 | if (NULL == mech) | |
307 | { | |
308 | mEvaluatingMechanism = false; | |
309 | } | |
310 | else | |
311 | { | |
312 | mCurrentMechanism = mech; | |
313 | mEvaluatingMechanism = true; | |
314 | } | |
315 | } | |
316 | ||
317 | void | |
318 | AuthMechLogger::writeCommon() | |
319 | { | |
320 | writeSubject(); | |
321 | writeToken(au_to_text(mRight.c_str()), "right"); | |
322 | if (true == mEvaluatingMechanism) | |
323 | { | |
324 | string tmpStr = mechStr; // mechStr includes a trailing space | |
325 | tmpStr += mCurrentMechanism; | |
326 | writeToken(au_to_text(tmpStr.c_str()), "mechanism"); | |
327 | } | |
328 | } | |
329 | ||
330 | void | |
331 | AuthMechLogger::logInterrupt(const char *msg) | |
332 | { | |
333 | if (false == open()) | |
334 | return; | |
335 | writeCommon(); | |
336 | if (msg) | |
337 | writeToken(au_to_text(msg), "interrupt"); | |
338 | writeReturn(0, 0); | |
339 | close(); | |
340 | } | |
341 | ||
342 | // | |
343 | // RightAuthenticationLogger | |
344 | // | |
345 | const char *RightAuthenticationLogger::unknownUserStr = "<unknown user>"; | |
346 | const char *RightAuthenticationLogger::unknownClientStr = "<unknown client>"; | |
347 | const char *RightAuthenticationLogger::unknownAuthCreatorStr = "<unknown creator>"; | |
348 | const char *RightAuthenticationLogger::authenticatorStr = "known UID "; | |
349 | const char *RightAuthenticationLogger::clientStr = "client "; | |
350 | const char *RightAuthenticationLogger::authCreatorStr = "creator "; | |
351 | const char *RightAuthenticationLogger::authenticatedAsStr = "authenticated as "; | |
352 | const char *RightAuthenticationLogger::leastPrivStr = "least-privilege"; | |
353 | ||
354 | RightAuthenticationLogger::RightAuthenticationLogger(const AuditToken &srcToken, short auEvent) | |
355 | : AuditLogger(srcToken, auEvent), RightLogger() | |
356 | { | |
357 | } | |
358 | ||
359 | RightAuthenticationLogger::RightAuthenticationLogger(const audit_token_t *srcToken, short auEvent) | |
360 | : AuditLogger(srcToken, auEvent), RightLogger() | |
361 | { | |
362 | } | |
363 | ||
364 | void | |
365 | RightAuthenticationLogger::writeCommon() | |
366 | { | |
367 | writeSubject(); | |
368 | writeToken(au_to_text(mRight.c_str()), "right"); | |
369 | } | |
370 | ||
371 | void | |
372 | RightAuthenticationLogger::logSuccess(uid_t authenticator, uid_t target, const char *targetName) | |
373 | { | |
374 | if (false == open()) | |
375 | return; | |
376 | writeCommon(); | |
377 | ||
378 | // au_to_arg32() is really meant for auditing syscall arguments; | |
379 | // we're slightly abusing it to get descriptive strings for free. | |
380 | writeToken(au_to_arg32(1, authenticatorStr, authenticator), "authenticator"); | |
381 | string tmpStr(authenticatedAsStr); | |
382 | // targetName shouldn't be NULL on a successful authentication, but allow | |
383 | // for programmer screwups | |
384 | tmpStr += targetName ? targetName : unknownUserStr; | |
385 | writeToken(au_to_arg32(2, tmpStr.c_str(), target), "target"); | |
386 | writeReturn(0, 0); | |
387 | close(); | |
388 | } | |
389 | ||
390 | void | |
391 | RightAuthenticationLogger::logAuthorizationResult(const char *client, const char *authCreator, int errcode) | |
392 | { | |
393 | if (false == open()) | |
394 | return; | |
395 | writeCommon(); | |
396 | string tmpStr(clientStr); | |
397 | tmpStr += client ? client : unknownClientStr; | |
398 | writeToken(au_to_text(tmpStr.c_str()), "Authorization client"); | |
399 | tmpStr.clear(); | |
400 | tmpStr = authCreatorStr; | |
401 | tmpStr += authCreator ? authCreator : unknownAuthCreatorStr; | |
402 | writeToken(au_to_text(tmpStr.c_str()), "Authorization creator"); | |
403 | if (errAuthorizationSuccess == errcode) | |
404 | writeReturn(0, 0); | |
405 | else | |
406 | writeReturn(EPERM, errcode); | |
407 | close(); | |
408 | } | |
409 | ||
410 | void | |
411 | RightAuthenticationLogger::logLeastPrivilege(uid_t userId, bool isAuthorizingUser) | |
412 | { | |
413 | if (false == open()) | |
414 | return; | |
415 | writeCommon(); | |
416 | writeToken(au_to_text(leastPrivStr), leastPrivStr); | |
417 | writeReturn(0, 0); | |
418 | close(); | |
419 | } | |
420 | ||
421 | void | |
fa7225c8 | 422 | RightAuthenticationLogger::logAuthenticatorFailure(uid_t authenticator, const char *targetName) |
d8f41ccd A |
423 | { |
424 | if (false == open()) | |
425 | return; | |
426 | writeCommon(); | |
427 | writeToken(au_to_arg32(1, authenticatorStr, authenticator), "authenticator"); | |
428 | if (NULL == targetName) | |
429 | writeToken(au_to_text(unknownUserStr), "target username"); | |
430 | else | |
431 | writeToken(au_to_text(targetName), "target username"); | |
432 | // @@@ EAUTH more appropriate, but !defined for _POSIX_C_SOURCE | |
433 | writeReturn(EPERM, errAuthorizationDenied); | |
434 | close(); | |
435 | } | |
436 | ||
437 | } // namespace Securityd | |
438 | ||
439 | } // namespace CommonCriteria | |
440 | ||
441 | } // namespace Security |