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>
58 # define AUE_openssh 32800
60 #include <bsm/audit.h>
61 #include <bsm/libbsm.h>
62 #include <bsm/audit_uevents.h>
63 #include <bsm/audit_record.h>
66 #if defined(HAVE_GETAUDIT_ADDR)
67 #define AuditInfoStruct auditinfo_addr
68 #define AuditInfoTermID au_tid_addr_t
69 #define SetAuditFunc(a,b) setaudit_addr((a),(b))
70 #define SetAuditFuncText "setaudit_addr"
71 #define AUToSubjectFunc au_to_subject_ex
72 #define AUToReturnFunc(a,b) au_to_return32((a), (int32_t)(b))
74 #define AuditInfoStruct auditinfo
75 #define AuditInfoTermID au_tid_t
76 #define SetAuditFunc(a,b) setaudit(a)
77 #define SetAuditFuncText "setaudit"
78 #define AUToSubjectFunc au_to_subject
79 #define AUToReturnFunc(a,b) au_to_return((a), (u_int)(b))
83 extern int cannot_audit(int);
85 extern void aug_init(void);
86 extern void aug_save_auid(au_id_t
);
87 extern void aug_save_uid(uid_t
);
88 extern void aug_save_euid(uid_t
);
89 extern void aug_save_gid(gid_t
);
90 extern void aug_save_egid(gid_t
);
91 extern void aug_save_pid(pid_t
);
92 extern void aug_save_asid(au_asid_t
);
93 extern void aug_save_tid(dev_t
, unsigned int);
94 extern void aug_save_tid_ex(dev_t
, u_int32_t
*, u_int32_t
);
95 extern int aug_save_me(void);
96 extern int aug_save_namask(void);
97 extern void aug_save_event(au_event_t
);
98 extern void aug_save_sorf(int);
99 extern void aug_save_text(char *);
100 extern void aug_save_text1(char *);
101 extern void aug_save_text2(char *);
102 extern void aug_save_na(int);
103 extern void aug_save_user(char *);
104 extern void aug_save_path(char *);
105 extern int aug_save_policy(void);
106 extern void aug_save_afunc(int (*)(int));
107 extern int aug_audit(void);
108 extern int aug_na_selected(void);
109 extern int aug_selected(void);
110 extern int aug_daemon_session(void);
113 # define gettext(a) (a)
116 extern Authctxt
*the_authctxt
;
117 static AuditInfoTermID ssh_bsm_tid
;
119 #ifdef BROKEN_BSM_API
120 /* For some reason this constant is no longer defined
122 #define BSM_TEXTBUFSZ 256
125 /* Below is the low-level BSM interface code */
128 * aug_get_machine is only required on IPv6 capable machines, we use a
129 * different mechanism in audit_connection_from() for IPv4-only machines.
130 * getaudit_addr() is only present on IPv6 capable machines.
132 #if defined(HAVE_AUG_GET_MACHINE) || !defined(HAVE_GETAUDIT_ADDR)
133 extern int aug_get_machine(char *, u_int32_t
*, u_int32_t
*);
136 aug_get_machine(char *host
, u_int32_t
*addr
, u_int32_t
*type
)
139 struct sockaddr_in
*in4
;
140 struct sockaddr_in6
*in6
;
143 if ((r
= getaddrinfo(host
, NULL
, NULL
, &ai
)) != 0) {
144 error("BSM audit: getaddrinfo failed for %.100s: %.100s", host
,
145 r
== EAI_SYSTEM
? strerror(errno
) : gai_strerror(r
));
149 switch (ai
->ai_family
) {
151 in4
= (struct sockaddr_in
*)ai
->ai_addr
;
153 memcpy(addr
, &in4
->sin_addr
, sizeof(struct in_addr
));
157 in6
= (struct sockaddr_in6
*)ai
->ai_addr
;
159 memcpy(addr
, &in6
->sin6_addr
, sizeof(struct in6_addr
));
163 error("BSM audit: unknown address family for %.100s: %d",
164 host
, ai
->ai_family
);
172 #ifdef BROKEN_BSM_API
174 In Solaris 11 the audit daemon has been moved to SMF. In the process
175 they simply dropped getacna() from the API, since it read from a now
176 non-existent config file. This function re-implements getacna() to
177 read from the SMF repository instead.
180 getacna(char *auditstring
, int len
)
182 scf_handle_t
*handle
= NULL
;
183 scf_property_t
*property
= NULL
;
184 scf_value_t
*value
= NULL
;
187 handle
= scf_handle_create(SCF_VERSION
);
189 return -2; /* The man page for getacna on Solaris 10 states
190 we should return -2 in case of error and set
191 errno to indicate the error. We don't bother
192 with errno here, though, since the only use
193 of this function below doesn't check for errors
197 ret
= scf_handle_bind(handle
);
201 property
= scf_property_create(handle
);
202 if (property
== NULL
)
205 ret
= scf_handle_decode_fmri(handle
,
206 "svc:/system/auditd:default/:properties/preselection/naflags",
207 NULL
, NULL
, NULL
, NULL
, property
, 0);
211 value
= scf_value_create(handle
);
215 ret
= scf_property_get_value(property
, value
);
219 ret
= scf_value_get_astring(value
, auditstring
, len
);
223 scf_value_destroy(value
);
224 scf_property_destroy(property
);
225 scf_handle_destroy(handle
);
232 * Check if the specified event is selected (enabled) for auditing.
233 * Returns 1 if the event is selected, 0 if not and -1 on failure.
236 selected(char *username
, uid_t uid
, au_event_t event
, int sf
)
242 mask
.am_success
= mask
.am_failure
= 0;
244 /* get flags for non-attributable (to a real user) events */
245 rc
= getacna(naflags
, sizeof(naflags
));
247 (void) getauditflagsbin(naflags
, &mask
);
249 rc
= au_user_mask(username
, &mask
);
251 sorf
= (sf
== 0) ? AU_PRS_SUCCESS
: AU_PRS_FAILURE
;
252 return(au_preselect(event
, &mask
, sorf
, AU_PRS_REREAD
));
256 bsm_audit_record(int typ
, char *string
, au_event_t event_no
)
261 pid_t pid
= getpid();
262 AuditInfoTermID tid
= ssh_bsm_tid
;
264 if (the_authctxt
!= NULL
&& the_authctxt
->valid
) {
265 uid
= the_authctxt
->pw
->pw_uid
;
266 gid
= the_authctxt
->pw
->pw_gid
;
269 rc
= (typ
== 0) ? 0 : -1;
270 sel
= selected(the_authctxt
->user
, uid
, event_no
, rc
);
271 debug3("BSM audit: typ %d rc %d \"%s\"", typ
, rc
, string
);
273 return; /* audit event does not match mask, do not write */
275 debug3("BSM audit: writing audit new record");
278 (void) au_write(ad
, AUToSubjectFunc(uid
, uid
, gid
, uid
, gid
,
280 (void) au_write(ad
, au_to_text(string
));
281 (void) au_write(ad
, AUToReturnFunc(typ
, rc
));
283 #ifdef BROKEN_BSM_API
284 /* The last argument is the event modifier flags. For
285 some seemingly undocumented reason it was added in
287 rc
= au_close(ad
, AU_TO_WRITE
, event_no
, 0);
289 rc
= au_close(ad
, AU_TO_WRITE
, event_no
);
293 error("BSM audit: %s failed to write \"%s\" record: %s",
294 __func__
, string
, strerror(errno
));
298 bsm_audit_session_setup(void)
301 struct AuditInfoStruct info
;
304 if (the_authctxt
== NULL
) {
305 error("BSM audit: session setup internal error (NULL ctxt)");
309 if (the_authctxt
->valid
)
310 info
.ai_auid
= the_authctxt
->pw
->pw_uid
;
313 info
.ai_asid
= getpid();
317 (void) au_user_mask(the_authctxt
->user
, &mask
);
319 info
.ai_mask
.am_success
= mask
.am_success
;
320 info
.ai_mask
.am_failure
= mask
.am_failure
;
322 info
.ai_termid
= ssh_bsm_tid
;
324 rc
= SetAuditFunc(&info
, sizeof(info
));
326 error("BSM audit: %s: %s failed: %s", __func__
,
327 SetAuditFuncText
, strerror(errno
));
331 bsm_audit_bad_login(const char *what
)
333 char textbuf
[BSM_TEXTBUFSZ
];
335 if (the_authctxt
->valid
) {
336 (void) snprintf(textbuf
, sizeof (textbuf
),
337 gettext("invalid %s for user %s"),
338 what
, the_authctxt
->user
);
339 bsm_audit_record(4, textbuf
, AUE_openssh
);
341 (void) snprintf(textbuf
, sizeof (textbuf
),
342 gettext("invalid user name \"%s\""),
344 bsm_audit_record(3, textbuf
, AUE_openssh
);
348 /* Below is the sshd audit API code */
351 audit_connection_from(const char *host
, int port
)
353 AuditInfoTermID
*tid
= &ssh_bsm_tid
;
358 debug3("BSM audit: connection from %.100s port %d", host
, port
);
360 /* populate our terminal id structure */
361 #if defined(HAVE_GETAUDIT_ADDR)
362 tid
->at_port
= (dev_t
)port
;
363 aug_get_machine((char *)host
, &(tid
->at_addr
[0]), &(tid
->at_type
));
364 snprintf(buf
, sizeof(buf
), "%08x %08x %08x %08x", tid
->at_addr
[0],
365 tid
->at_addr
[1], tid
->at_addr
[2], tid
->at_addr
[3]);
366 debug3("BSM audit: iptype %d machine ID %s", (int)tid
->at_type
, buf
);
368 /* this is used on IPv4-only machines */
369 tid
->port
= (dev_t
)port
;
370 tid
->machine
= inet_addr(host
);
371 snprintf(buf
, sizeof(buf
), "%08x", tid
->machine
);
372 debug3("BSM audit: machine ID %s", buf
);
377 audit_run_command(const char *command
)
379 /* not implemented */
383 audit_session_open(struct logininfo
*li
)
385 /* not implemented */
389 audit_session_close(struct logininfo
*li
)
391 /* not implemented */
395 audit_event(ssh_audit_event_t event
)
397 char textbuf
[BSM_TEXTBUFSZ
];
398 static int logged_in
= 0;
399 const char *user
= the_authctxt
? the_authctxt
->user
: "(unknown user)";
405 case SSH_AUTH_SUCCESS
:
407 bsm_audit_session_setup();
408 snprintf(textbuf
, sizeof(textbuf
),
409 gettext("successful login %s"), user
);
410 bsm_audit_record(0, textbuf
, AUE_openssh
);
413 case SSH_CONNECTION_CLOSE
:
415 * We can also get a close event if the user attempted auth
416 * but never succeeded.
419 snprintf(textbuf
, sizeof(textbuf
),
420 gettext("sshd logout %s"), the_authctxt
->user
);
421 bsm_audit_record(0, textbuf
, AUE_logout
);
423 debug("%s: connection closed without authentication",
430 gettext("logins disabled by /etc/nologin"), AUE_openssh
);
433 case SSH_LOGIN_EXCEED_MAXTRIES
:
434 snprintf(textbuf
, sizeof(textbuf
),
435 gettext("too many tries for user %s"), the_authctxt
->user
);
436 bsm_audit_record(1, textbuf
, AUE_openssh
);
439 case SSH_LOGIN_ROOT_DENIED
:
440 bsm_audit_record(2, gettext("not_console"), AUE_openssh
);
443 case SSH_AUTH_FAIL_PASSWD
:
444 bsm_audit_bad_login("password");
447 case SSH_AUTH_FAIL_KBDINT
:
448 bsm_audit_bad_login("interactive password entry");
452 debug("%s: unhandled event %d", __func__
, event
);