Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssh/audit-bsm.c
34677 views
1
/*
2
* TODO
3
*
4
* - deal with overlap between this and sys_auth_allowed_user
5
* sys_auth_record_login and record_failed_login.
6
*/
7
8
/*
9
* Copyright 1988-2002 Sun Microsystems, Inc. All rights reserved.
10
* Use is subject to license terms.
11
*
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.
20
*
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.
31
*
32
*/
33
/* #pragma ident "@(#)bsmaudit.c 1.1 01/09/17 SMI" */
34
35
#include "includes.h"
36
#if defined(USE_BSM_AUDIT)
37
38
#include <sys/types.h>
39
40
#include <errno.h>
41
#include <netdb.h>
42
#include <stdarg.h>
43
#include <string.h>
44
#include <unistd.h>
45
46
#ifdef BROKEN_BSM_API
47
#include <libscf.h>
48
#endif
49
50
#include "ssh.h"
51
#include "log.h"
52
#include "hostfile.h"
53
#include "auth.h"
54
#include "xmalloc.h"
55
56
#ifndef AUE_openssh
57
# define AUE_openssh 32800
58
#endif
59
#include <bsm/audit.h>
60
#include <bsm/libbsm.h>
61
#include <bsm/audit_uevents.h>
62
#include <bsm/audit_record.h>
63
#include <locale.h>
64
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))
72
#else
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))
79
#endif
80
81
#ifndef cannot_audit
82
extern int cannot_audit(int);
83
#endif
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);
110
111
#ifndef HAVE_GETTEXT
112
# define gettext(a) (a)
113
#endif
114
115
extern Authctxt *the_authctxt;
116
static AuditInfoTermID ssh_bsm_tid;
117
118
#ifdef BROKEN_BSM_API
119
/* For some reason this constant is no longer defined
120
in Solaris 11. */
121
#define BSM_TEXTBUFSZ 256
122
#endif
123
124
/* Below is the low-level BSM interface code */
125
126
/*
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.
130
*/
131
#if defined(HAVE_AUG_GET_MACHINE) || !defined(HAVE_GETAUDIT_ADDR)
132
extern int aug_get_machine(char *, u_int32_t *, u_int32_t *);
133
#else
134
static int
135
aug_get_machine(char *host, u_int32_t *addr, u_int32_t *type)
136
{
137
struct addrinfo *ai;
138
struct sockaddr_in *in4;
139
struct sockaddr_in6 *in6;
140
int ret = 0, r;
141
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));
145
return -1;
146
}
147
148
switch (ai->ai_family) {
149
case AF_INET:
150
in4 = (struct sockaddr_in *)ai->ai_addr;
151
*type = AU_IPv4;
152
memcpy(addr, &in4->sin_addr, sizeof(struct in_addr));
153
break;
154
#ifdef AU_IPv6
155
case AF_INET6:
156
in6 = (struct sockaddr_in6 *)ai->ai_addr;
157
*type = AU_IPv6;
158
memcpy(addr, &in6->sin6_addr, sizeof(struct in6_addr));
159
break;
160
#endif
161
default:
162
error("BSM audit: unknown address family for %.100s: %d",
163
host, ai->ai_family);
164
ret = -1;
165
}
166
freeaddrinfo(ai);
167
return ret;
168
}
169
#endif
170
171
#ifdef BROKEN_BSM_API
172
/*
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.
177
*/
178
int
179
getacna(char *auditstring, int len)
180
{
181
scf_handle_t *handle = NULL;
182
scf_property_t *property = NULL;
183
scf_value_t *value = NULL;
184
int ret = 0;
185
186
/*
187
* The man page for getacna on Solaris 10 states we should return -2
188
* in case of error and set errno to indicate the error. We don't
189
* bother with errno here, though, since the only use of this function
190
* below doesn't check for errors anyway.
191
*/
192
handle = scf_handle_create(SCF_VERSION);
193
if (handle == NULL)
194
return -2;
195
196
ret = scf_handle_bind(handle);
197
if (ret == -1)
198
return -2;
199
200
property = scf_property_create(handle);
201
if (property == NULL)
202
return -2;
203
204
ret = scf_handle_decode_fmri(handle,
205
"svc:/system/auditd:default/:properties/preselection/naflags",
206
NULL, NULL, NULL, NULL, property, 0);
207
if (ret == -1)
208
return -2;
209
210
value = scf_value_create(handle);
211
if (value == NULL)
212
return -2;
213
214
ret = scf_property_get_value(property, value);
215
if (ret == -1)
216
return -2;
217
218
ret = scf_value_get_astring(value, auditstring, len);
219
if (ret == -1)
220
return -2;
221
222
scf_value_destroy(value);
223
scf_property_destroy(property);
224
scf_handle_destroy(handle);
225
226
return 0;
227
}
228
#endif
229
230
/*
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.
233
*/
234
static int
235
selected(char *username, uid_t uid, au_event_t event, int sf)
236
{
237
int rc, sorf;
238
char naflags[512];
239
struct au_mask mask;
240
241
mask.am_success = mask.am_failure = 0;
242
if (uid < 0) {
243
/* get flags for non-attributable (to a real user) events */
244
rc = getacna(naflags, sizeof(naflags));
245
if (rc == 0)
246
(void) getauditflagsbin(naflags, &mask);
247
} else
248
rc = au_user_mask(username, &mask);
249
250
sorf = (sf == 0) ? AU_PRS_SUCCESS : AU_PRS_FAILURE;
251
return(au_preselect(event, &mask, sorf, AU_PRS_REREAD));
252
}
253
254
static void
255
bsm_audit_record(int typ, char *string, au_event_t event_no)
256
{
257
int ad, rc, sel;
258
uid_t uid = -1;
259
gid_t gid = -1;
260
pid_t pid = getpid();
261
AuditInfoTermID tid = ssh_bsm_tid;
262
263
if (the_authctxt != NULL && the_authctxt->valid) {
264
uid = the_authctxt->pw->pw_uid;
265
gid = the_authctxt->pw->pw_gid;
266
}
267
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);
271
if (!sel)
272
return; /* audit event does not match mask, do not write */
273
274
debug3("BSM audit: writing audit new record");
275
ad = au_open();
276
277
(void) au_write(ad, AUToSubjectFunc(uid, uid, gid, uid, gid,
278
pid, pid, &tid));
279
(void) au_write(ad, au_to_text(string));
280
(void) au_write(ad, AUToReturnFunc(typ, rc));
281
282
#ifdef BROKEN_BSM_API
283
/*
284
* The last argument is the event modifier flags. For some seemingly
285
* undocumented reason it was added in Solaris 11.
286
*/
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
291
292
if (rc < 0)
293
error("BSM audit: %s failed to write \"%s\" record: %s",
294
__func__, string, strerror(errno));
295
}
296
297
static void
298
bsm_audit_session_setup(void)
299
{
300
int rc;
301
struct AuditInfoStruct info;
302
au_mask_t mask;
303
304
if (the_authctxt == NULL) {
305
error("BSM audit: session setup internal error (NULL ctxt)");
306
return;
307
}
308
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;
316
317
(void) au_user_mask(the_authctxt->user, &mask);
318
319
info.ai_mask.am_success = mask.am_success;
320
info.ai_mask.am_failure = mask.am_failure;
321
322
info.ai_termid = ssh_bsm_tid;
323
324
rc = SetAuditFunc(&info, sizeof(info));
325
if (rc < 0)
326
error("BSM audit: %s: %s failed: %s", __func__,
327
SetAuditFuncText, strerror(errno));
328
}
329
330
static void
331
bsm_audit_bad_login(const char *what)
332
{
333
char textbuf[BSM_TEXTBUFSZ];
334
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);
345
}
346
}
347
348
/* Below is the sshd audit API code */
349
350
void
351
audit_connection_from(const char *host, int port)
352
{
353
AuditInfoTermID *tid = &ssh_bsm_tid;
354
char buf[1024];
355
356
if (cannot_audit(0))
357
return;
358
debug3("BSM audit: connection from %.100s port %d", host, port);
359
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
374
}
375
376
void
377
audit_run_command(const char *command)
378
{
379
/* not implemented */
380
}
381
382
void
383
audit_session_open(struct logininfo *li)
384
{
385
/* not implemented */
386
}
387
388
void
389
audit_session_close(struct logininfo *li)
390
{
391
/* not implemented */
392
}
393
394
void
395
audit_event(struct ssh *ssh, ssh_audit_event_t event)
396
{
397
char textbuf[BSM_TEXTBUFSZ];
398
static int logged_in = 0;
399
const char *user = the_authctxt ? the_authctxt->user : "(unknown user)";
400
401
if (cannot_audit(0))
402
return;
403
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;
412
413
case SSH_CONNECTION_CLOSE:
414
/*
415
* We can also get a close event if the user attempted auth
416
* but never succeeded.
417
*/
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__);
425
}
426
break;
427
428
case SSH_NOLOGIN:
429
bsm_audit_record(1,
430
gettext("logins disabled by /etc/nologin"), AUE_openssh);
431
break;
432
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;
438
439
case SSH_LOGIN_ROOT_DENIED:
440
bsm_audit_record(2, gettext("not_console"), AUE_openssh);
441
break;
442
443
case SSH_AUTH_FAIL_PASSWD:
444
bsm_audit_bad_login("password");
445
break;
446
447
case SSH_AUTH_FAIL_KBDINT:
448
bsm_audit_bad_login("interactive password entry");
449
break;
450
451
default:
452
debug("%s: unhandled event %d", __func__, event);
453
}
454
}
455
#endif /* BSM */
456
457