mld6query(8): Rename mld6.c -> mld6query.c
[dragonfly.git] / crypto / openssh / audit-bsm.c
blobf8e0bea89ad0b2b5e46e071a6b17acf7eb4e6b91
1 /*
2 * TODO
4 * - deal with overlap between this and sys_auth_allowed_user
5 * sys_auth_record_login and record_failed_login.
6 */
8 /*
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
14 * are met:
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" */
35 #include "includes.h"
36 #if defined(USE_BSM_AUDIT)
38 #include <sys/types.h>
40 #include <errno.h>
41 #include <netdb.h>
42 #include <stdarg.h>
43 #include <string.h>
44 #include <unistd.h>
46 #ifdef BROKEN_BSM_API
47 #include <libscf.h>
48 #endif
50 #include "ssh.h"
51 #include "log.h"
52 #include "key.h"
53 #include "hostfile.h"
54 #include "auth.h"
55 #include "xmalloc.h"
57 #ifndef AUE_openssh
58 # define AUE_openssh 32800
59 #endif
60 #include <bsm/audit.h>
61 #include <bsm/libbsm.h>
62 #include <bsm/audit_uevents.h>
63 #include <bsm/audit_record.h>
64 #include <locale.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))
73 #else
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))
80 #endif
82 #ifndef cannot_audit
83 extern int cannot_audit(int);
84 #endif
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);
112 #ifndef HAVE_GETTEXT
113 # define gettext(a) (a)
114 #endif
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
121 in Solaris 11. */
122 #define BSM_TEXTBUFSZ 256
123 #endif
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 *);
134 #else
135 static int
136 aug_get_machine(char *host, u_int32_t *addr, u_int32_t *type)
138 struct addrinfo *ai;
139 struct sockaddr_in *in4;
140 struct sockaddr_in6 *in6;
141 int ret = 0, r;
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));
146 return -1;
149 switch (ai->ai_family) {
150 case AF_INET:
151 in4 = (struct sockaddr_in *)ai->ai_addr;
152 *type = AU_IPv4;
153 memcpy(addr, &in4->sin_addr, sizeof(struct in_addr));
154 break;
155 #ifdef AU_IPv6
156 case AF_INET6:
157 in6 = (struct sockaddr_in6 *)ai->ai_addr;
158 *type = AU_IPv6;
159 memcpy(addr, &in6->sin6_addr, sizeof(struct in6_addr));
160 break;
161 #endif
162 default:
163 error("BSM audit: unknown address family for %.100s: %d",
164 host, ai->ai_family);
165 ret = -1;
167 freeaddrinfo(ai);
168 return ret;
170 #endif
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;
185 int ret = 0;
187 handle = scf_handle_create(SCF_VERSION);
188 if (handle == NULL)
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
194 anyway.
197 ret = scf_handle_bind(handle);
198 if (ret == -1)
199 return -2;
201 property = scf_property_create(handle);
202 if (property == NULL)
203 return -2;
205 ret = scf_handle_decode_fmri(handle,
206 "svc:/system/auditd:default/:properties/preselection/naflags",
207 NULL, NULL, NULL, NULL, property, 0);
208 if (ret == -1)
209 return -2;
211 value = scf_value_create(handle);
212 if (value == NULL)
213 return -2;
215 ret = scf_property_get_value(property, value);
216 if (ret == -1)
217 return -2;
219 ret = scf_value_get_astring(value, auditstring, len);
220 if (ret == -1)
221 return -2;
223 scf_value_destroy(value);
224 scf_property_destroy(property);
225 scf_handle_destroy(handle);
227 return 0;
229 #endif
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.
235 static int
236 selected(char *username, uid_t uid, au_event_t event, int sf)
238 int rc, sorf;
239 char naflags[512];
240 struct au_mask mask;
242 mask.am_success = mask.am_failure = 0;
243 if (uid < 0) {
244 /* get flags for non-attributable (to a real user) events */
245 rc = getacna(naflags, sizeof(naflags));
246 if (rc == 0)
247 (void) getauditflagsbin(naflags, &mask);
248 } else
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));
255 static void
256 bsm_audit_record(int typ, char *string, au_event_t event_no)
258 int ad, rc, sel;
259 uid_t uid = -1;
260 gid_t gid = -1;
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);
272 if (!sel)
273 return; /* audit event does not match mask, do not write */
275 debug3("BSM audit: writing audit new record");
276 ad = au_open();
278 (void) au_write(ad, AUToSubjectFunc(uid, uid, gid, uid, gid,
279 pid, pid, &tid));
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
286 Solaris 11. */
287 rc = au_close(ad, AU_TO_WRITE, event_no, 0);
288 #else
289 rc = au_close(ad, AU_TO_WRITE, event_no);
290 #endif
292 if (rc < 0)
293 error("BSM audit: %s failed to write \"%s\" record: %s",
294 __func__, string, strerror(errno));
297 static void
298 bsm_audit_session_setup(void)
300 int rc;
301 struct AuditInfoStruct info;
302 au_mask_t mask;
304 if (the_authctxt == NULL) {
305 error("BSM audit: session setup internal error (NULL ctxt)");
306 return;
309 if (the_authctxt->valid)
310 info.ai_auid = the_authctxt->pw->pw_uid;
311 else
312 info.ai_auid = -1;
313 info.ai_asid = getpid();
314 mask.am_success = 0;
315 mask.am_failure = 0;
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));
325 if (rc < 0)
326 error("BSM audit: %s: %s failed: %s", __func__,
327 SetAuditFuncText, strerror(errno));
330 static void
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);
340 } else {
341 (void) snprintf(textbuf, sizeof (textbuf),
342 gettext("invalid user name \"%s\""),
343 the_authctxt->user);
344 bsm_audit_record(3, textbuf, AUE_openssh);
348 /* Below is the sshd audit API code */
350 void
351 audit_connection_from(const char *host, int port)
353 AuditInfoTermID *tid = &ssh_bsm_tid;
354 char buf[1024];
356 if (cannot_audit(0))
357 return;
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);
367 #else
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);
373 #endif
376 void
377 audit_run_command(const char *command)
379 /* not implemented */
382 void
383 audit_session_open(struct logininfo *li)
385 /* not implemented */
388 void
389 audit_session_close(struct logininfo *li)
391 /* not implemented */
394 void
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)";
401 if (cannot_audit(0))
402 return;
404 switch(event) {
405 case SSH_AUTH_SUCCESS:
406 logged_in = 1;
407 bsm_audit_session_setup();
408 snprintf(textbuf, sizeof(textbuf),
409 gettext("successful login %s"), user);
410 bsm_audit_record(0, textbuf, AUE_openssh);
411 break;
413 case SSH_CONNECTION_CLOSE:
415 * We can also get a close event if the user attempted auth
416 * but never succeeded.
418 if (logged_in) {
419 snprintf(textbuf, sizeof(textbuf),
420 gettext("sshd logout %s"), the_authctxt->user);
421 bsm_audit_record(0, textbuf, AUE_logout);
422 } else {
423 debug("%s: connection closed without authentication",
424 __func__);
426 break;
428 case SSH_NOLOGIN:
429 bsm_audit_record(1,
430 gettext("logins disabled by /etc/nologin"), AUE_openssh);
431 break;
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);
437 break;
439 case SSH_LOGIN_ROOT_DENIED:
440 bsm_audit_record(2, gettext("not_console"), AUE_openssh);
441 break;
443 case SSH_AUTH_FAIL_PASSWD:
444 bsm_audit_bad_login("password");
445 break;
447 case SSH_AUTH_FAIL_KBDINT:
448 bsm_audit_bad_login("interactive password entry");
449 break;
451 default:
452 debug("%s: unhandled event %d", __func__, event);
455 #endif /* BSM */