4 * - deal with overlap between this and sys_auth_allowed_user
5 * sys_auth_record_login and record_failed_login.
9 * Copyright 1988-2002 Sun Microsystems, Inc. All rights reserved.
10 * Use is subject to license terms.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 /* #pragma ident "@(#)bsmaudit.c 1.1 01/09/17 SMI" */
36 #if defined(USE_BSM_AUDIT)
38 #include <sys/types.h>
57 # define AUE_openssh 32800
59 #include <bsm/audit.h>
60 #include <bsm/libbsm.h>
61 #include <bsm/audit_uevents.h>
62 #include <bsm/audit_record.h>
65 #if defined(HAVE_GETAUDIT_ADDR)
66 #define AuditInfoStruct auditinfo_addr
67 #define AuditInfoTermID au_tid_addr_t
68 #define SetAuditFunc(a,b) setaudit_addr((a),(b))
69 #define SetAuditFuncText "setaudit_addr"
70 #define AUToSubjectFunc au_to_subject_ex
71 #define AUToReturnFunc(a,b) au_to_return32((a), (int32_t)(b))
73 #define AuditInfoStruct auditinfo
74 #define AuditInfoTermID au_tid_t
75 #define SetAuditFunc(a,b) setaudit(a)
76 #define SetAuditFuncText "setaudit"
77 #define AUToSubjectFunc au_to_subject
78 #define AUToReturnFunc(a,b) au_to_return((a), (u_int)(b))
82 extern int cannot_audit(int);
84 extern void aug_init(void);
85 extern void aug_save_auid(au_id_t);
86 extern void aug_save_uid(uid_t);
87 extern void aug_save_euid(uid_t);
88 extern void aug_save_gid(gid_t);
89 extern void aug_save_egid(gid_t);
90 extern void aug_save_pid(pid_t);
91 extern void aug_save_asid(au_asid_t);
92 extern void aug_save_tid(dev_t, unsigned int);
93 extern void aug_save_tid_ex(dev_t, u_int32_t *, u_int32_t);
94 extern int aug_save_me(void);
95 extern int aug_save_namask(void);
96 extern void aug_save_event(au_event_t);
97 extern void aug_save_sorf(int);
98 extern void aug_save_text(char *);
99 extern void aug_save_text1(char *);
100 extern void aug_save_text2(char *);
101 extern void aug_save_na(int);
102 extern void aug_save_user(char *);
103 extern void aug_save_path(char *);
104 extern int aug_save_policy(void);
105 extern void aug_save_afunc(int (*)(int));
106 extern int aug_audit(void);
107 extern int aug_na_selected(void);
108 extern int aug_selected(void);
109 extern int aug_daemon_session(void);
112 # define gettext(a) (a)
115 extern Authctxt *the_authctxt;
116 static AuditInfoTermID ssh_bsm_tid;
118 #ifdef BROKEN_BSM_API
119 /* For some reason this constant is no longer defined
121 #define BSM_TEXTBUFSZ 256
124 /* Below is the low-level BSM interface code */
127 * aug_get_machine is only required on IPv6 capable machines, we use a
128 * different mechanism in audit_connection_from() for IPv4-only machines.
129 * getaudit_addr() is only present on IPv6 capable machines.
131 #if defined(HAVE_AUG_GET_MACHINE) || !defined(HAVE_GETAUDIT_ADDR)
132 extern int aug_get_machine(char *, u_int32_t *, u_int32_t *);
135 aug_get_machine(char *host, u_int32_t *addr, u_int32_t *type)
138 struct sockaddr_in *in4;
139 struct sockaddr_in6 *in6;
142 if ((r = getaddrinfo(host, NULL, NULL, &ai)) != 0) {
143 error("BSM audit: getaddrinfo failed for %.100s: %.100s", host,
144 r == EAI_SYSTEM ? strerror(errno) : gai_strerror(r));
148 switch (ai->ai_family) {
150 in4 = (struct sockaddr_in *)ai->ai_addr;
152 memcpy(addr, &in4->sin_addr, sizeof(struct in_addr));
156 in6 = (struct sockaddr_in6 *)ai->ai_addr;
158 memcpy(addr, &in6->sin6_addr, sizeof(struct in6_addr));
162 error("BSM audit: unknown address family for %.100s: %d",
163 host, ai->ai_family);
171 #ifdef BROKEN_BSM_API
173 In Solaris 11 the audit daemon has been moved to SMF. In the process
174 they simply dropped getacna() from the API, since it read from a now
175 non-existent config file. This function re-implements getacna() to
176 read from the SMF repository instead.
179 getacna(char *auditstring, int len)
181 scf_handle_t *handle = NULL;
182 scf_property_t *property = NULL;
183 scf_value_t *value = NULL;
186 handle = scf_handle_create(SCF_VERSION);
188 return -2; /* The man page for getacna on Solaris 10 states
189 we should return -2 in case of error and set
190 errno to indicate the error. We don't bother
191 with errno here, though, since the only use
192 of this function below doesn't check for errors
196 ret = scf_handle_bind(handle);
200 property = scf_property_create(handle);
201 if (property == NULL)
204 ret = scf_handle_decode_fmri(handle,
205 "svc:/system/auditd:default/:properties/preselection/naflags",
206 NULL, NULL, NULL, NULL, property, 0);
210 value = scf_value_create(handle);
214 ret = scf_property_get_value(property, value);
218 ret = scf_value_get_astring(value, auditstring, len);
222 scf_value_destroy(value);
223 scf_property_destroy(property);
224 scf_handle_destroy(handle);
231 * Check if the specified event is selected (enabled) for auditing.
232 * Returns 1 if the event is selected, 0 if not and -1 on failure.
235 selected(char *username, uid_t uid, au_event_t event, int sf)
241 mask.am_success = mask.am_failure = 0;
243 /* get flags for non-attributable (to a real user) events */
244 rc = getacna(naflags, sizeof(naflags));
246 (void) getauditflagsbin(naflags, &mask);
248 rc = au_user_mask(username, &mask);
250 sorf = (sf == 0) ? AU_PRS_SUCCESS : AU_PRS_FAILURE;
251 return(au_preselect(event, &mask, sorf, AU_PRS_REREAD));
255 bsm_audit_record(int typ, char *string, au_event_t event_no)
260 pid_t pid = getpid();
261 AuditInfoTermID tid = ssh_bsm_tid;
263 if (the_authctxt != NULL && the_authctxt->valid) {
264 uid = the_authctxt->pw->pw_uid;
265 gid = the_authctxt->pw->pw_gid;
268 rc = (typ == 0) ? 0 : -1;
269 sel = selected(the_authctxt->user, uid, event_no, rc);
270 debug3("BSM audit: typ %d rc %d \"%s\"", typ, rc, string);
272 return; /* audit event does not match mask, do not write */
274 debug3("BSM audit: writing audit new record");
277 (void) au_write(ad, AUToSubjectFunc(uid, uid, gid, uid, gid,
279 (void) au_write(ad, au_to_text(string));
280 (void) au_write(ad, AUToReturnFunc(typ, rc));
282 #ifdef BROKEN_BSM_API
283 /* The last argument is the event modifier flags. For
284 some seemingly undocumented reason it was added in
286 rc = au_close(ad, AU_TO_WRITE, event_no, 0);
288 rc = au_close(ad, AU_TO_WRITE, event_no);
292 error("BSM audit: %s failed to write \"%s\" record: %s",
293 __func__, string, strerror(errno));
297 bsm_audit_session_setup(void)
300 struct AuditInfoStruct info;
303 if (the_authctxt == NULL) {
304 error("BSM audit: session setup internal error (NULL ctxt)");
308 if (the_authctxt->valid)
309 info.ai_auid = the_authctxt->pw->pw_uid;
312 info.ai_asid = getpid();
316 (void) au_user_mask(the_authctxt->user, &mask);
318 info.ai_mask.am_success = mask.am_success;
319 info.ai_mask.am_failure = mask.am_failure;
321 info.ai_termid = ssh_bsm_tid;
323 rc = SetAuditFunc(&info, sizeof(info));
325 error("BSM audit: %s: %s failed: %s", __func__,
326 SetAuditFuncText, strerror(errno));
330 bsm_audit_bad_login(const char *what)
332 char textbuf[BSM_TEXTBUFSZ];
334 if (the_authctxt->valid) {
335 (void) snprintf(textbuf, sizeof (textbuf),
336 gettext("invalid %s for user %s"),
337 what, the_authctxt->user);
338 bsm_audit_record(4, textbuf, AUE_openssh);
340 (void) snprintf(textbuf, sizeof (textbuf),
341 gettext("invalid user name \"%s\""),
343 bsm_audit_record(3, textbuf, AUE_openssh);
347 /* Below is the sshd audit API code */
350 audit_connection_from(const char *host, int port)
352 AuditInfoTermID *tid = &ssh_bsm_tid;
357 debug3("BSM audit: connection from %.100s port %d", host, port);
359 /* populate our terminal id structure */
360 #if defined(HAVE_GETAUDIT_ADDR)
361 tid->at_port = (dev_t)port;
362 aug_get_machine((char *)host, &(tid->at_addr[0]), &(tid->at_type));
363 snprintf(buf, sizeof(buf), "%08x %08x %08x %08x", tid->at_addr[0],
364 tid->at_addr[1], tid->at_addr[2], tid->at_addr[3]);
365 debug3("BSM audit: iptype %d machine ID %s", (int)tid->at_type, buf);
367 /* this is used on IPv4-only machines */
368 tid->port = (dev_t)port;
369 tid->machine = inet_addr(host);
370 snprintf(buf, sizeof(buf), "%08x", tid->machine);
371 debug3("BSM audit: machine ID %s", buf);
376 audit_run_command(const char *command)
378 /* not implemented */
382 audit_session_open(struct logininfo *li)
384 /* not implemented */
388 audit_session_close(struct logininfo *li)
390 /* not implemented */
394 audit_event(ssh_audit_event_t event)
396 char textbuf[BSM_TEXTBUFSZ];
397 static int logged_in = 0;
398 const char *user = the_authctxt ? the_authctxt->user : "(unknown user)";
404 case SSH_AUTH_SUCCESS:
406 bsm_audit_session_setup();
407 snprintf(textbuf, sizeof(textbuf),
408 gettext("successful login %s"), user);
409 bsm_audit_record(0, textbuf, AUE_openssh);
412 case SSH_CONNECTION_CLOSE:
414 * We can also get a close event if the user attempted auth
415 * but never succeeded.
418 snprintf(textbuf, sizeof(textbuf),
419 gettext("sshd logout %s"), the_authctxt->user);
420 bsm_audit_record(0, textbuf, AUE_logout);
422 debug("%s: connection closed without authentication",
429 gettext("logins disabled by /etc/nologin"), AUE_openssh);
432 case SSH_LOGIN_EXCEED_MAXTRIES:
433 snprintf(textbuf, sizeof(textbuf),
434 gettext("too many tries for user %s"), the_authctxt->user);
435 bsm_audit_record(1, textbuf, AUE_openssh);
438 case SSH_LOGIN_ROOT_DENIED:
439 bsm_audit_record(2, gettext("not_console"), AUE_openssh);
442 case SSH_AUTH_FAIL_PASSWD:
443 bsm_audit_bad_login("password");
446 case SSH_AUTH_FAIL_KBDINT:
447 bsm_audit_bad_login("interactive password entry");
451 debug("%s: unhandled event %d", __func__, event);