(root)/
Linux-PAM-1.5.3/
libpam/
pam_audit.c
       1  /* pam_audit.c -- Instrumentation code for Linux Auditing System  */
       2  
       3  /* (C) 2005-2006 Red Hat, Inc. -- Licensing details are in the COPYING
       4     file accompanying the Linux-PAM source distribution.
       5  
       6     Authors:
       7     Steve Grubb <sgrubb@redhat.com> */
       8  
       9  #include "pam_private.h"
      10  #include "pam_modutil_private.h"
      11  
      12  #ifdef HAVE_LIBAUDIT
      13  #include <stdio.h>
      14  #include <syslog.h>
      15  #include <libaudit.h>
      16  #include <pwd.h>
      17  #include <netdb.h>
      18  #include <unistd.h>
      19  #include <sys/types.h>
      20  #include <sys/socket.h>
      21  #include <arpa/inet.h>
      22  #include <errno.h>
      23  
      24  #define PAMAUDIT_LOGGED 1
      25  
      26  static int
      27  _pam_audit_writelog(pam_handle_t *pamh, int audit_fd, int type,
      28  	const char *message, const char *grantors, int retval)
      29  {
      30    static int old_errno = -1;
      31    int rc = -ENOMEM;
      32    char *buf;
      33    const char *grantors_field = " grantors=";
      34  
      35    if (grantors == NULL) {
      36        grantors = "";
      37        grantors_field = "";
      38    }
      39  
      40    if (asprintf(&buf, "PAM:%s%s%s", message, grantors_field, grantors) >= 0) {
      41        rc = audit_log_acct_message(audit_fd, type, NULL, buf,
      42  	(retval != PAM_USER_UNKNOWN && pamh->user) ? pamh->user : "?",
      43  	-1, pamh->rhost, NULL, pamh->tty, retval == PAM_SUCCESS);
      44        free(buf);
      45    }
      46  
      47    /* libaudit sets errno to his own negative error code. This can be
      48       an official errno number, but must not. It can also be a audit
      49       internal error code. Which makes errno useless :-((. Try the
      50       best to fix it. */
      51    errno = -rc;
      52  
      53    pamh->audit_state |= PAMAUDIT_LOGGED;
      54  
      55    if (rc < 0) {
      56        if (rc == -EPERM)
      57            return 0;
      58        if (errno != old_errno) {
      59            old_errno = errno;
      60            pam_syslog (pamh, LOG_CRIT, "audit_log_acct_message() failed: %m");
      61        }
      62    }
      63    return rc;
      64  }
      65  
      66  static int
      67  _pam_audit_open(pam_handle_t *pamh)
      68  {
      69    int audit_fd;
      70    audit_fd = audit_open();
      71    if (audit_fd < 0) {
      72      /* You get these error codes only when the kernel doesn't have
      73       * audit compiled in. */
      74      if (errno == EINVAL || errno == EPROTONOSUPPORT ||
      75          errno == EAFNOSUPPORT)
      76          return -2;
      77  
      78      /* this should only fail in case of extreme resource shortage,
      79       * need to prevent login in that case for CAPP compliance.
      80       */
      81      pam_syslog(pamh, LOG_CRIT, "audit_open() failed: %m");
      82      return -1;
      83    }
      84  
      85    return audit_fd;
      86  }
      87  
      88  static int
      89  _pam_list_grantors(struct handler *hlist, int retval, char **list)
      90  {
      91    *list = NULL;
      92  
      93    if (retval == PAM_SUCCESS) {
      94      struct handler *h;
      95      char *p = NULL;
      96      size_t len = 0;
      97  
      98      for (h = hlist; h != NULL; h = h->next) {
      99        if (h->grantor) {
     100          len += strlen(h->mod_name) + 1;
     101        }
     102      }
     103  
     104      if (len == 0) {
     105        return 0;
     106      }
     107  
     108      *list = malloc(len);
     109      if (*list == NULL) {
     110        return -1;
     111      }
     112  
     113      for (h = hlist; h != NULL; h = h->next) {
     114        if (h->grantor) {
     115          if (p == NULL) {
     116            p = *list;
     117          } else {
     118            p = stpcpy(p, ",");
     119          }
     120  
     121          p = stpcpy(p, h->mod_name);
     122        }
     123      }
     124    }
     125  
     126    return 0;
     127  }
     128  
     129  int
     130  _pam_auditlog(pam_handle_t *pamh, int action, int retval, int flags, struct handler *h)
     131  {
     132    const char *message;
     133    int type;
     134    int audit_fd;
     135    char *grantors;
     136  
     137    if ((audit_fd=_pam_audit_open(pamh)) == -1) {
     138      return PAM_SYSTEM_ERR;
     139    } else if (audit_fd == -2) {
     140      return retval;
     141    }
     142  
     143    switch (action) {
     144    case PAM_AUTHENTICATE:
     145      message = "authentication";
     146      type = AUDIT_USER_AUTH;
     147      break;
     148    case PAM_OPEN_SESSION:
     149      message = "session_open";
     150      type = AUDIT_USER_START;
     151      break;
     152    case PAM_CLOSE_SESSION:
     153      message = "session_close";
     154      type = AUDIT_USER_END;
     155      break;
     156    case PAM_ACCOUNT:
     157      message = "accounting";
     158      type = AUDIT_USER_ACCT;
     159      break;
     160    case PAM_CHAUTHTOK:
     161      message = "chauthtok";
     162      type = AUDIT_USER_CHAUTHTOK;
     163      break;
     164    case PAM_SETCRED:
     165      message = "setcred";
     166      if (flags & PAM_ESTABLISH_CRED)
     167  	type = AUDIT_CRED_ACQ;
     168      else if ((flags & PAM_REINITIALIZE_CRED) || (flags & PAM_REFRESH_CRED))
     169  	type = AUDIT_CRED_REFR;
     170      else if (flags & PAM_DELETE_CRED)
     171  	type = AUDIT_CRED_DISP;
     172      else
     173          type = AUDIT_USER_ERR;
     174      break;
     175    case _PAM_ACTION_DONE:
     176      message = "bad_ident";
     177      type = AUDIT_USER_ERR;
     178      break;
     179    default:
     180      message = "UNKNOWN";
     181      type = AUDIT_USER_ERR;
     182      pam_syslog(pamh, LOG_CRIT, "_pam_auditlog() should never get here");
     183      retval = PAM_SYSTEM_ERR;
     184    }
     185  
     186    if (_pam_list_grantors(h, retval, &grantors) < 0) {
     187      /* allocation failure */
     188      pam_syslog(pamh, LOG_CRIT, "_pam_list_grantors() failed: %m");
     189      retval = PAM_SYSTEM_ERR;
     190    }
     191  
     192    if (_pam_audit_writelog(pamh, audit_fd, type, message,
     193        grantors ? grantors : "?", retval) < 0)
     194      retval = PAM_SYSTEM_ERR;
     195  
     196    free(grantors);
     197  
     198    audit_close(audit_fd);
     199    return retval;
     200  }
     201  
     202  int
     203  _pam_audit_end(pam_handle_t *pamh, int status UNUSED)
     204  {
     205    if (! (pamh->audit_state & PAMAUDIT_LOGGED)) {
     206      /* PAM library is being shut down without any of the auditted
     207       * stacks having been run. Assume that this is sshd faking
     208       * things for an unknown user.
     209       */
     210      _pam_auditlog(pamh, _PAM_ACTION_DONE, PAM_USER_UNKNOWN, 0, NULL);
     211    }
     212  
     213    return 0;
     214  }
     215  
     216  int
     217  pam_modutil_audit_write(pam_handle_t *pamh, int type,
     218      const char *message, int retval)
     219  {
     220    int audit_fd;
     221    int rc;
     222  
     223    if ((audit_fd=_pam_audit_open(pamh)) == -1) {
     224      return PAM_SYSTEM_ERR;
     225    } else if (audit_fd == -2) {
     226      return retval;
     227    }
     228  
     229    rc = _pam_audit_writelog(pamh, audit_fd, type, message, NULL, retval);
     230  
     231    audit_close(audit_fd);
     232  
     233    return rc < 0 ? PAM_SYSTEM_ERR : PAM_SUCCESS;
     234  }
     235  
     236  #else
     237  int pam_modutil_audit_write(pam_handle_t *pamh UNUSED, int type UNUSED,
     238      const char *message UNUSED, int retval UNUSED)
     239  {
     240    return PAM_SUCCESS;
     241  }
     242  #endif /* HAVE_LIBAUDIT */