diff options
Diffstat (limited to 'audit-bsm.c')
-rw-r--r-- | audit-bsm.c | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/audit-bsm.c b/audit-bsm.c new file mode 100644 index 000000000..c2679d3da --- /dev/null +++ b/audit-bsm.c | |||
@@ -0,0 +1,329 @@ | |||
1 | /* $Id: audit-bsm.c,v 1.1 2005/02/20 10:08:00 dtucker Exp $ */ | ||
2 | |||
3 | /* | ||
4 | * TODO | ||
5 | * | ||
6 | * - deal with overlap between this and sys_auth_allowed_user | ||
7 | * sys_auth_record_login and record_failed_login. | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * Copyright 1988-2002 Sun Microsystems, Inc. All rights reserved. | ||
12 | * Use is subject to license terms. | ||
13 | * | ||
14 | * Redistribution and use in source and binary forms, with or without | ||
15 | * modification, are permitted provided that the following conditions | ||
16 | * are met: | ||
17 | * 1. Redistributions of source code must retain the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer. | ||
19 | * 2. Redistributions in binary form must reproduce the above copyright | ||
20 | * notice, this list of conditions and the following disclaimer in the | ||
21 | * documentation and/or other materials provided with the distribution. | ||
22 | * | ||
23 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
24 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
25 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
26 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
27 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
28 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
32 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | * | ||
34 | */ | ||
35 | /* #pragma ident "@(#)bsmaudit.c 1.1 01/09/17 SMI" */ | ||
36 | |||
37 | #include "includes.h" | ||
38 | #if defined(USE_BSM_AUDIT) | ||
39 | |||
40 | #include "ssh.h" | ||
41 | #include "log.h" | ||
42 | #include "auth.h" | ||
43 | #include "xmalloc.h" | ||
44 | |||
45 | #ifndef AUE_openssh | ||
46 | # define AUE_openssh 32800 | ||
47 | #endif | ||
48 | #include <bsm/audit.h> | ||
49 | #include <bsm/libbsm.h> | ||
50 | #include <bsm/audit_uevents.h> | ||
51 | #include <bsm/audit_record.h> | ||
52 | #include <locale.h> | ||
53 | |||
54 | #if defined(HAVE_GETAUDIT_ADDR) | ||
55 | #define AuditInfoStruct auditinfo_addr | ||
56 | #define AuditInfoTermID au_tid_addr_t | ||
57 | #define GetAuditFunc(a,b) getaudit_addr((a),(b)) | ||
58 | #define GetAuditFuncText "getaudit_addr" | ||
59 | #define SetAuditFunc(a,b) setaudit_addr((a),(b)) | ||
60 | #define SetAuditFuncText "setaudit_addr" | ||
61 | #define AUToSubjectFunc au_to_subject_ex | ||
62 | #define AUToReturnFunc(a,b) au_to_return32((a), (int32_t)(b)) | ||
63 | #else | ||
64 | #define AuditInfoStruct auditinfo | ||
65 | #define AuditInfoTermID au_tid_t | ||
66 | #define GetAuditFunc(a,b) getaudit(a) | ||
67 | #define GetAuditFuncText "getaudit" | ||
68 | #define SetAuditFunc(a,b) setaudit(a) | ||
69 | #define SetAuditFuncText "setaudit" | ||
70 | #define AUToSubjectFunc au_to_subject | ||
71 | #define AUToReturnFunc(a,b) au_to_return((a), (u_int)(b)) | ||
72 | #endif | ||
73 | |||
74 | extern int cannot_audit(int); | ||
75 | extern void aug_init(void); | ||
76 | extern dev_t aug_get_port(void); | ||
77 | extern int aug_get_machine(char *, u_int32_t *, u_int32_t *); | ||
78 | extern void aug_save_auid(au_id_t); | ||
79 | extern void aug_save_uid(uid_t); | ||
80 | extern void aug_save_euid(uid_t); | ||
81 | extern void aug_save_gid(gid_t); | ||
82 | extern void aug_save_egid(gid_t); | ||
83 | extern void aug_save_pid(pid_t); | ||
84 | extern void aug_save_asid(au_asid_t); | ||
85 | extern void aug_save_tid(dev_t, unsigned int); | ||
86 | extern void aug_save_tid_ex(dev_t, u_int32_t *, u_int32_t); | ||
87 | extern int aug_save_me(void); | ||
88 | extern int aug_save_namask(void); | ||
89 | extern void aug_save_event(au_event_t); | ||
90 | extern void aug_save_sorf(int); | ||
91 | extern void aug_save_text(char *); | ||
92 | extern void aug_save_text1(char *); | ||
93 | extern void aug_save_text2(char *); | ||
94 | extern void aug_save_na(int); | ||
95 | extern void aug_save_user(char *); | ||
96 | extern void aug_save_path(char *); | ||
97 | extern int aug_save_policy(void); | ||
98 | extern void aug_save_afunc(int (*)(int)); | ||
99 | extern int aug_audit(void); | ||
100 | extern int aug_na_selected(void); | ||
101 | extern int aug_selected(void); | ||
102 | extern int aug_daemon_session(void); | ||
103 | |||
104 | #ifndef HAVE_GETTEXT | ||
105 | # define gettext(a) (a) | ||
106 | #endif | ||
107 | |||
108 | extern Authctxt *the_authctxt; | ||
109 | static AuditInfoTermID ssh_bsm_tid; | ||
110 | |||
111 | /* Below is the low-level BSM interface code */ | ||
112 | |||
113 | /* | ||
114 | * Check if the specified event is selected (enabled) for auditing. | ||
115 | * Returns 1 if the event is selected, 0 if not and -1 on failure. | ||
116 | */ | ||
117 | static int | ||
118 | selected(char *username, uid_t uid, au_event_t event, int sf) | ||
119 | { | ||
120 | int rc, sorf; | ||
121 | char naflags[512]; | ||
122 | struct au_mask mask; | ||
123 | |||
124 | mask.am_success = mask.am_failure = 0; | ||
125 | if (uid < 0) { | ||
126 | /* get flags for non-attributable (to a real user) events */ | ||
127 | rc = getacna(naflags, sizeof(naflags)); | ||
128 | if (rc == 0) | ||
129 | (void) getauditflagsbin(naflags, &mask); | ||
130 | } else | ||
131 | rc = au_user_mask(username, &mask); | ||
132 | |||
133 | sorf = (sf == 0) ? AU_PRS_SUCCESS : AU_PRS_FAILURE; | ||
134 | return(au_preselect(event, &mask, sorf, AU_PRS_REREAD)); | ||
135 | } | ||
136 | |||
137 | static void | ||
138 | bsm_audit_record(int typ, char *string, au_event_t event_no) | ||
139 | { | ||
140 | int ad, rc, sel; | ||
141 | uid_t uid = -1; | ||
142 | gid_t gid = -1; | ||
143 | pid_t pid = getpid(); | ||
144 | AuditInfoTermID tid = ssh_bsm_tid; | ||
145 | |||
146 | if (the_authctxt != NULL && the_authctxt->valid) { | ||
147 | uid = the_authctxt->pw->pw_uid; | ||
148 | gid = the_authctxt->pw->pw_gid; | ||
149 | } | ||
150 | |||
151 | rc = (typ == 0) ? 0 : -1; | ||
152 | sel = selected(the_authctxt->user, uid, event_no, rc); | ||
153 | debug3("BSM audit: typ %d rc %d \"%s\"", typ, rc, string); | ||
154 | if (!sel) | ||
155 | return; /* audit event does not match mask, do not write */ | ||
156 | |||
157 | debug3("BSM audit: writing audit new record"); | ||
158 | ad = au_open(); | ||
159 | |||
160 | (void) au_write(ad, AUToSubjectFunc(uid, uid, gid, uid, gid, | ||
161 | pid, pid, &tid)); | ||
162 | (void) au_write(ad, au_to_text(string)); | ||
163 | (void) au_write(ad, AUToReturnFunc(typ, rc)); | ||
164 | |||
165 | rc = au_close(ad, AU_TO_WRITE, event_no); | ||
166 | if (rc < 0) | ||
167 | error("BSM audit: %s failed to write \"%s\" record: %s", | ||
168 | __func__, string, strerror(errno)); | ||
169 | } | ||
170 | |||
171 | static void | ||
172 | bsm_audit_session_setup(void) | ||
173 | { | ||
174 | int rc; | ||
175 | struct AuditInfoStruct info; | ||
176 | au_mask_t mask; | ||
177 | |||
178 | if (the_authctxt == NULL) { | ||
179 | error("BSM audit: session setup internal error (NULL ctxt)"); | ||
180 | return; | ||
181 | } | ||
182 | |||
183 | if (the_authctxt->valid) | ||
184 | info.ai_auid = the_authctxt->pw->pw_uid; | ||
185 | else | ||
186 | info.ai_auid = -1; | ||
187 | info.ai_asid = getpid(); | ||
188 | mask.am_success = 0; | ||
189 | mask.am_failure = 0; | ||
190 | |||
191 | (void) au_user_mask(the_authctxt->user, &mask); | ||
192 | |||
193 | info.ai_mask.am_success = mask.am_success; | ||
194 | info.ai_mask.am_failure = mask.am_failure; | ||
195 | |||
196 | info.ai_termid = ssh_bsm_tid; | ||
197 | |||
198 | rc = SetAuditFunc(&info, sizeof(info)); | ||
199 | if (rc < 0) | ||
200 | error("BSM audit: %s: %s failed: %s", __func__, | ||
201 | SetAuditFuncText, strerror(errno)); | ||
202 | } | ||
203 | |||
204 | static void | ||
205 | bsm_audit_bad_login(const char *what) | ||
206 | { | ||
207 | char textbuf[BSM_TEXTBUFSZ]; | ||
208 | |||
209 | if (the_authctxt->valid) { | ||
210 | (void) snprintf(textbuf, sizeof (textbuf), | ||
211 | gettext("invalid %s for user %s"), | ||
212 | what, the_authctxt->user); | ||
213 | bsm_audit_record(4, textbuf, AUE_openssh); | ||
214 | } else { | ||
215 | (void) snprintf(textbuf, sizeof (textbuf), | ||
216 | gettext("invalid user name \"%s\""), | ||
217 | the_authctxt->user); | ||
218 | bsm_audit_record(3, textbuf, AUE_openssh); | ||
219 | } | ||
220 | } | ||
221 | |||
222 | /* Below is the sshd audit API code */ | ||
223 | |||
224 | void | ||
225 | audit_connection_from(const char *host, int port) | ||
226 | { | ||
227 | AuditInfoTermID *tid = &ssh_bsm_tid; | ||
228 | char buf[1024]; | ||
229 | |||
230 | if (cannot_audit(0)) | ||
231 | return; | ||
232 | debug3("BSM audit: connection from %.100s port %d", host, port); | ||
233 | |||
234 | /* populate our terminal id structure */ | ||
235 | #if defined(HAVE_GETAUDIT_ADDR) | ||
236 | tid->at_port = (dev_t)port; | ||
237 | aug_get_machine((char *)host, &(tid->at_addr[0]), &(tid->at_type)); | ||
238 | snprintf(buf, sizeof(buf), "%08x %08x %08x %08x", tid->at_addr[0], | ||
239 | tid->at_addr[1], tid->at_addr[2], tid->at_addr[3]); | ||
240 | debug3("BSM audit: iptype %d machine ID %s", (int)tid->at_type, buf); | ||
241 | #else | ||
242 | /* this is used on IPv4-only machines */ | ||
243 | tid->port = (dev_t)port; | ||
244 | tid->machine = inet_addr(host); | ||
245 | snprintf(buf, sizeof(buf), "%08x", tid->machine); | ||
246 | debug3("BSM audit: machine ID %s", buf); | ||
247 | #endif | ||
248 | } | ||
249 | |||
250 | void | ||
251 | audit_run_command(const char *command) | ||
252 | { | ||
253 | /* not implemented */ | ||
254 | } | ||
255 | |||
256 | void | ||
257 | audit_session_open(const char *ttyn) | ||
258 | { | ||
259 | /* not implemented */ | ||
260 | } | ||
261 | |||
262 | void | ||
263 | audit_session_close(const char *ttyn) | ||
264 | { | ||
265 | /* not implemented */ | ||
266 | } | ||
267 | |||
268 | void | ||
269 | audit_event(ssh_audit_event_t event) | ||
270 | { | ||
271 | char textbuf[BSM_TEXTBUFSZ]; | ||
272 | static int logged_in = 0; | ||
273 | const char *user = the_authctxt ? the_authctxt->user : "(unknown user)"; | ||
274 | |||
275 | if (cannot_audit(0)) | ||
276 | return; | ||
277 | |||
278 | switch(event) { | ||
279 | case SSH_AUTH_SUCCESS: | ||
280 | logged_in = 1; | ||
281 | bsm_audit_session_setup(); | ||
282 | snprintf(textbuf, sizeof(textbuf), | ||
283 | gettext("successful login %s"), user); | ||
284 | bsm_audit_record(0, textbuf, AUE_openssh); | ||
285 | break; | ||
286 | |||
287 | case SSH_CONNECTION_CLOSE: | ||
288 | /* | ||
289 | * We can also get a close event if the user attempted auth | ||
290 | * but never succeeded. | ||
291 | */ | ||
292 | if (logged_in) { | ||
293 | snprintf(textbuf, sizeof(textbuf), | ||
294 | gettext("sshd logout %s"), the_authctxt->user); | ||
295 | bsm_audit_record(0, textbuf, AUE_logout); | ||
296 | } else { | ||
297 | debug("%s: connection closed without authentication", | ||
298 | __func__); | ||
299 | } | ||
300 | break; | ||
301 | |||
302 | case SSH_NOLOGIN: | ||
303 | bsm_audit_record(1, | ||
304 | gettext("logins disabled by /etc/nologin"), AUE_openssh); | ||
305 | break; | ||
306 | |||
307 | case SSH_LOGIN_EXCEED_MAXTRIES: | ||
308 | snprintf(textbuf, sizeof(textbuf), | ||
309 | gettext("too many tries for user %s"), the_authctxt->user); | ||
310 | bsm_audit_record(1, textbuf, AUE_openssh); | ||
311 | break; | ||
312 | |||
313 | case SSH_LOGIN_ROOT_DENIED: | ||
314 | bsm_audit_record(2, gettext("not_console"), AUE_openssh); | ||
315 | break; | ||
316 | |||
317 | case SSH_AUTH_FAIL_PASSWD: | ||
318 | bsm_audit_bad_login("password"); | ||
319 | break; | ||
320 | |||
321 | case SSH_AUTH_FAIL_KBDINT: | ||
322 | bsm_audit_bad_login("interactive password entry"); | ||
323 | break; | ||
324 | |||
325 | default: | ||
326 | debug("%s: unhandled event %d", __func__, event); | ||
327 | } | ||
328 | } | ||
329 | #endif /* BSM */ | ||