/ securityd / src / ccaudit_extensions.cpp
ccaudit_extensions.cpp
  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 <security_utilities/simulatecrash_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
422  RightAuthenticationLogger::logAuthenticatorFailure(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