]> granicus.if.org Git - linux-pam/blob - libpam/pam_audit.c
7f2e0b2c0f4a342c33315a61f63e2200c0da1f74
[linux-pam] / 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 <stdio.h>
10 #include <syslog.h>
11 #include "pam_private.h"
12 #include "pam_modutil_private.h"
13
14 #ifdef HAVE_LIBAUDIT
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, int retval)
29 {
30   static int old_errno = -1;
31   int rc;
32   char buf[32];
33
34   snprintf(buf, sizeof(buf), "PAM:%s", message);
35
36   rc = audit_log_acct_message (audit_fd, type, NULL, buf,
37        (retval != PAM_USER_UNKNOWN && pamh->user) ? pamh->user : "?",
38         -1, pamh->rhost, NULL, pamh->tty, retval == PAM_SUCCESS );
39
40   /* libaudit sets errno to his own negative error code. This can be
41      an official errno number, but must not. It can also be a audit
42      internal error code. Which makes errno useless :-((. Try the
43      best to fix it. */
44   errno = -rc;
45
46   pamh->audit_state |= PAMAUDIT_LOGGED;
47
48   if (rc < 0) {
49       if (rc == -EPERM && getuid() != 0)
50           return 0;
51       if (errno != old_errno) {
52           old_errno = errno;
53           pam_syslog (pamh, LOG_CRIT, "audit_log_acct_message() failed: %m");
54       }
55   }
56   return rc;
57 }
58
59 static int
60 _pam_audit_open(pam_handle_t *pamh)
61 {
62   int audit_fd;
63   audit_fd = audit_open();
64   if (audit_fd < 0) {
65     /* You get these error codes only when the kernel doesn't have
66      * audit compiled in. */
67     if (errno == EINVAL || errno == EPROTONOSUPPORT ||
68         errno == EAFNOSUPPORT)
69         return -2;
70
71     /* this should only fail in case of extreme resource shortage,
72      * need to prevent login in that case for CAPP compliance.
73      */
74     pam_syslog(pamh, LOG_CRIT, "audit_open() failed: %m");
75     return -1;
76   }
77
78   return audit_fd;
79 }
80
81 int
82 _pam_auditlog(pam_handle_t *pamh, int action, int retval, int flags)
83 {
84   const char *message;
85   int type;
86   int audit_fd;
87
88   if ((audit_fd=_pam_audit_open(pamh)) == -1) {
89     return PAM_SYSTEM_ERR;
90   } else if (audit_fd == -2) {
91     return retval;
92   }
93
94   switch (action) {
95   case PAM_AUTHENTICATE:
96     message = "authentication";
97     type = AUDIT_USER_AUTH;
98     break;
99   case PAM_OPEN_SESSION:
100     message = "session_open";
101     type = AUDIT_USER_START;
102     break;
103   case PAM_CLOSE_SESSION:
104     message = "session_close";
105     type = AUDIT_USER_END;
106     break;
107   case PAM_ACCOUNT:
108     message = "accounting";
109     type = AUDIT_USER_ACCT;
110     break;
111   case PAM_CHAUTHTOK:
112     message = "chauthtok";
113     type = AUDIT_USER_CHAUTHTOK;
114     break;
115   case PAM_SETCRED:
116     message = "setcred";
117     if (flags & PAM_ESTABLISH_CRED)
118         type = AUDIT_CRED_ACQ;
119     else if ((flags & PAM_REINITIALIZE_CRED) || (flags & PAM_REFRESH_CRED))
120         type = AUDIT_CRED_REFR;
121     else if (flags & PAM_DELETE_CRED)
122         type = AUDIT_CRED_DISP;
123     else
124         type = AUDIT_USER_ERR;
125     break;
126   case _PAM_ACTION_DONE:
127     message = "bad_ident";
128     type = AUDIT_USER_ERR;
129     break;
130   default:
131     message = "UNKNOWN";
132     type = AUDIT_USER_ERR;
133     pam_syslog(pamh, LOG_CRIT, "_pam_auditlog() should never get here");
134     retval = PAM_SYSTEM_ERR;
135   }
136
137   if (_pam_audit_writelog(pamh, audit_fd, type, message, retval) < 0)
138     retval = PAM_SYSTEM_ERR;
139
140   audit_close(audit_fd);
141   return retval;
142 }
143
144 int
145 _pam_audit_end(pam_handle_t *pamh, int status UNUSED)
146 {
147   if (! (pamh->audit_state & PAMAUDIT_LOGGED)) {
148     /* PAM library is being shut down without any of the auditted
149      * stacks having been run. Assume that this is sshd faking
150      * things for an unknown user.
151      */
152     _pam_auditlog(pamh, _PAM_ACTION_DONE, PAM_USER_UNKNOWN, 0);
153   }
154
155   return 0;
156 }
157
158 int
159 pam_modutil_audit_write(pam_handle_t *pamh, int type,
160     const char *message, int retval)
161 {
162   int audit_fd;
163   int rc;
164         
165   if ((audit_fd=_pam_audit_open(pamh)) == -1) {
166     return PAM_SYSTEM_ERR;
167   } else if (audit_fd == -2) {
168     return retval;
169   }
170
171   rc = _pam_audit_writelog(pamh, audit_fd, type, message, retval);
172
173   audit_close(audit_fd);
174   
175   return rc < 0 ? PAM_SYSTEM_ERR : PAM_SUCCESS;
176 }
177
178 #else
179 int pam_modutil_audit_write(pam_handle_t *pamh UNUSED, int type UNUSED,
180     const char *message UNUSED, int retval UNUSED)
181 {
182   return PAM_SUCCESS;
183 }
184 #endif /* HAVE_LIBAUDIT */