]> git.saurik.com Git - apple/securityd.git/blob - src/ccaudit_extensions.cpp
securityd-36975.tar.gz
[apple/securityd.git] / src / ccaudit_extensions.cpp
1 /*
2 * ccaudit_extensions.cpp
3 * securityd
4 *
5 * Created by G H on 3/24/09.
6 * Copyright 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.auditSession();
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
422 RightAuthenticationLogger::logFailure(uid_t authenticator, const char *targetName)
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