]>
Commit | Line | Data |
---|---|---|
17d728c8 SS |
1 | diff -up openssh-6.8p1/Makefile.in.audit openssh-6.8p1/Makefile.in |
2 | --- openssh-6.8p1/Makefile.in.audit 2015-03-20 13:41:15.065883826 +0100 | |
3 | +++ openssh-6.8p1/Makefile.in 2015-03-20 13:41:15.100883769 +0100 | |
4 | @@ -98,7 +98,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ | |
5 | sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o \ | |
6 | kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \ | |
7 | kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o \ | |
8 | - kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o | |
9 | + kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o auditstub.o | |
10 | ||
11 | SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ | |
12 | sshconnect.o sshconnect1.o sshconnect2.o mux.o \ | |
13 | diff -up openssh-6.8p1/audit-bsm.c.audit openssh-6.8p1/audit-bsm.c | |
14 | --- openssh-6.8p1/audit-bsm.c.audit 2015-03-17 06:49:20.000000000 +0100 | |
15 | +++ openssh-6.8p1/audit-bsm.c 2015-03-20 13:41:15.092883782 +0100 | |
16 | @@ -375,10 +375,23 @@ audit_connection_from(const char *host, | |
17 | #endif | |
18 | } | |
19 | ||
20 | -void | |
21 | +int | |
22 | audit_run_command(const char *command) | |
23 | { | |
24 | /* not implemented */ | |
25 | + return 0; | |
26 | +} | |
27 | + | |
28 | +void | |
29 | +audit_end_command(int handle, const char *command) | |
30 | +{ | |
31 | + /* not implemented */ | |
32 | +} | |
33 | + | |
34 | +void | |
35 | +audit_count_session_open(void) | |
36 | +{ | |
37 | + /* not necessary */ | |
38 | } | |
39 | ||
40 | void | |
41 | @@ -393,6 +406,12 @@ audit_session_close(struct logininfo *li) | |
42 | /* not implemented */ | |
43 | } | |
44 | ||
45 | +int | |
46 | +audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) | |
47 | +{ | |
48 | + /* not implemented */ | |
49 | +} | |
50 | + | |
51 | void | |
52 | audit_event(ssh_audit_event_t event) | |
53 | { | |
54 | @@ -454,4 +473,40 @@ audit_event(ssh_audit_event_t event) | |
55 | debug("%s: unhandled event %d", __func__, event); | |
56 | } | |
57 | } | |
58 | + | |
59 | +void | |
60 | +audit_unsupported_body(int what) | |
61 | +{ | |
62 | + /* not implemented */ | |
63 | +} | |
64 | + | |
65 | +void | |
66 | +audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, uid_t uid) | |
67 | +{ | |
68 | + /* not implemented */ | |
69 | +} | |
70 | + | |
71 | +void | |
72 | +audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) | |
73 | +{ | |
74 | + /* not implemented */ | |
75 | +} | |
76 | + | |
77 | +void | |
78 | +audit_destroy_sensitive_data(const char *fp) | |
79 | +{ | |
80 | + /* not implemented */ | |
81 | +} | |
82 | + | |
83 | +void | |
84 | +audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) | |
85 | +{ | |
86 | + /* not implemented */ | |
87 | +} | |
88 | + | |
89 | +void | |
90 | +audit_generate_ephemeral_server_key(const char *fp) | |
91 | +{ | |
92 | + /* not implemented */ | |
93 | +} | |
94 | #endif /* BSM */ | |
95 | diff -up openssh-6.8p1/audit-linux.c.audit openssh-6.8p1/audit-linux.c | |
96 | --- openssh-6.8p1/audit-linux.c.audit 2015-03-17 06:49:20.000000000 +0100 | |
97 | +++ openssh-6.8p1/audit-linux.c 2015-03-20 13:41:15.093883780 +0100 | |
98 | @@ -35,13 +35,25 @@ | |
99 | ||
100 | #include "log.h" | |
101 | #include "audit.h" | |
102 | +#include "key.h" | |
103 | +#include "hostfile.h" | |
104 | +#include "auth.h" | |
105 | +#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */ | |
106 | +#include "servconf.h" | |
107 | #include "canohost.h" | |
108 | +#include "packet.h" | |
109 | +#include "cipher.h" | |
110 | ||
111 | +#define AUDIT_LOG_SIZE 256 | |
112 | + | |
113 | +extern ServerOptions options; | |
114 | +extern Authctxt *the_authctxt; | |
115 | +extern u_int utmp_len; | |
116 | const char* audit_username(void); | |
117 | ||
118 | -int | |
119 | -linux_audit_record_event(int uid, const char *username, | |
120 | - const char *hostname, const char *ip, const char *ttyn, int success) | |
121 | +static void | |
122 | +linux_audit_user_logxxx(int uid, const char *username, | |
123 | + const char *hostname, const char *ip, const char *ttyn, int success, int event) | |
124 | { | |
125 | int audit_fd, rc, saved_errno; | |
126 | ||
127 | @@ -49,11 +61,11 @@ linux_audit_record_event(int uid, const char *username, | |
128 | if (audit_fd < 0) { | |
129 | if (errno == EINVAL || errno == EPROTONOSUPPORT || | |
130 | errno == EAFNOSUPPORT) | |
131 | - return 1; /* No audit support in kernel */ | |
132 | + return; /* No audit support in kernel */ | |
133 | else | |
134 | - return 0; /* Must prevent login */ | |
135 | + goto fatal_report; /* Must prevent login */ | |
136 | } | |
137 | - rc = audit_log_acct_message(audit_fd, AUDIT_USER_LOGIN, | |
138 | + rc = audit_log_acct_message(audit_fd, event, | |
139 | NULL, "login", username ? username : "(unknown)", | |
140 | username == NULL ? uid : -1, hostname, ip, ttyn, success); | |
141 | saved_errno = errno; | |
142 | @@ -65,35 +77,154 @@ linux_audit_record_event(int uid, const char *username, | |
143 | if ((rc == -EPERM) && (geteuid() != 0)) | |
144 | rc = 0; | |
145 | errno = saved_errno; | |
146 | - return (rc >= 0); | |
147 | + if (rc < 0) { | |
148 | +fatal_report: | |
149 | + fatal("linux_audit_write_entry failed: %s", strerror(errno)); | |
150 | + } | |
151 | } | |
152 | ||
153 | +static void | |
154 | +linux_audit_user_auth(int uid, const char *username, | |
155 | + const char *hostname, const char *ip, const char *ttyn, int success, int event) | |
156 | +{ | |
157 | + int audit_fd, rc, saved_errno; | |
158 | + static const char *event_name[] = { | |
159 | + "maxtries exceeded", | |
160 | + "root denied", | |
161 | + "success", | |
162 | + "none", | |
163 | + "password", | |
164 | + "challenge-response", | |
165 | + "pubkey", | |
166 | + "hostbased", | |
167 | + "gssapi", | |
168 | + "invalid user", | |
169 | + "nologin", | |
170 | + "connection closed", | |
171 | + "connection abandoned", | |
172 | + "unknown" | |
173 | + }; | |
174 | + | |
175 | + audit_fd = audit_open(); | |
176 | + if (audit_fd < 0) { | |
177 | + if (errno == EINVAL || errno == EPROTONOSUPPORT || | |
178 | + errno == EAFNOSUPPORT) | |
179 | + return; /* No audit support in kernel */ | |
180 | + else | |
181 | + goto fatal_report; /* Must prevent login */ | |
182 | + } | |
183 | + | |
184 | + if ((event < 0) || (event > SSH_AUDIT_UNKNOWN)) | |
185 | + event = SSH_AUDIT_UNKNOWN; | |
186 | + | |
187 | + rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, | |
188 | + NULL, event_name[event], username ? username : "(unknown)", | |
189 | + username == NULL ? uid : -1, hostname, ip, ttyn, success); | |
190 | + saved_errno = errno; | |
191 | + close(audit_fd); | |
192 | + /* | |
193 | + * Do not report error if the error is EPERM and sshd is run as non | |
194 | + * root user. | |
195 | + */ | |
196 | + if ((rc == -EPERM) && (geteuid() != 0)) | |
197 | + rc = 0; | |
198 | + errno = saved_errno; | |
199 | + if (rc < 0) { | |
200 | +fatal_report: | |
201 | + fatal("linux_audit_write_entry failed: %s", strerror(errno)); | |
202 | + } | |
203 | +} | |
204 | + | |
205 | +int | |
206 | +audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) | |
207 | +{ | |
208 | + char buf[AUDIT_LOG_SIZE]; | |
209 | + int audit_fd, rc, saved_errno; | |
210 | + | |
211 | + audit_fd = audit_open(); | |
212 | + if (audit_fd < 0) { | |
213 | + if (errno == EINVAL || errno == EPROTONOSUPPORT || | |
214 | + errno == EAFNOSUPPORT) | |
215 | + return 1; /* No audit support in kernel */ | |
216 | + else | |
217 | + return 0; /* Must prevent login */ | |
218 | + } | |
219 | + snprintf(buf, sizeof(buf), "%s_auth rport=%d", host_user ? "pubkey" : "hostbased", get_remote_port()); | |
220 | + rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, | |
221 | + buf, audit_username(), -1, NULL, get_remote_ipaddr(), NULL, rv); | |
222 | + if ((rc < 0) && ((rc != -1) || (getuid() == 0))) | |
223 | + goto out; | |
224 | + /* is the fingerprint_prefix() still needed? | |
225 | + snprintf(buf, sizeof(buf), "key algo=%s size=%d fp=%s%s rport=%d", | |
226 | + type, bits, sshkey_fingerprint_prefix(), fp, get_remote_port()); | |
227 | + */ | |
228 | + snprintf(buf, sizeof(buf), "key algo=%s size=%d fp=%s rport=%d", | |
229 | + type, bits, fp, get_remote_port()); | |
230 | + rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, | |
231 | + buf, audit_username(), -1, NULL, get_remote_ipaddr(), NULL, rv); | |
232 | +out: | |
233 | + saved_errno = errno; | |
234 | + audit_close(audit_fd); | |
235 | + errno = saved_errno; | |
236 | + /* do not report error if the error is EPERM and sshd is run as non root user */ | |
237 | + return (rc >= 0) || ((rc == -EPERM) && (getuid() != 0)); | |
238 | +} | |
239 | + | |
240 | +static int user_login_count = 0; | |
241 | + | |
242 | /* Below is the sshd audit API code */ | |
243 | ||
244 | void | |
245 | audit_connection_from(const char *host, int port) | |
246 | { | |
247 | -} | |
248 | /* not implemented */ | |
249 | +} | |
250 | ||
251 | -void | |
252 | +int | |
253 | audit_run_command(const char *command) | |
254 | { | |
255 | - /* not implemented */ | |
256 | + if (!user_login_count++) | |
257 | + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), | |
258 | + NULL, "ssh", 1, AUDIT_USER_LOGIN); | |
259 | + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), | |
260 | + NULL, "ssh", 1, AUDIT_USER_START); | |
261 | + return 0; | |
262 | +} | |
263 | + | |
264 | +void | |
265 | +audit_end_command(int handle, const char *command) | |
266 | +{ | |
267 | + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), | |
268 | + NULL, "ssh", 1, AUDIT_USER_END); | |
269 | + if (user_login_count && !--user_login_count) | |
270 | + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), | |
271 | + NULL, "ssh", 1, AUDIT_USER_LOGOUT); | |
272 | +} | |
273 | + | |
274 | +void | |
275 | +audit_count_session_open(void) | |
276 | +{ | |
277 | + user_login_count++; | |
278 | } | |
279 | ||
280 | void | |
281 | audit_session_open(struct logininfo *li) | |
282 | { | |
283 | - if (linux_audit_record_event(li->uid, NULL, li->hostname, | |
284 | - NULL, li->line, 1) == 0) | |
285 | - fatal("linux_audit_write_entry failed: %s", strerror(errno)); | |
286 | + if (!user_login_count++) | |
287 | + linux_audit_user_logxxx(li->uid, NULL, li->hostname, | |
288 | + NULL, li->line, 1, AUDIT_USER_LOGIN); | |
289 | + linux_audit_user_logxxx(li->uid, NULL, li->hostname, | |
290 | + NULL, li->line, 1, AUDIT_USER_START); | |
291 | } | |
292 | ||
293 | void | |
294 | audit_session_close(struct logininfo *li) | |
295 | { | |
296 | - /* not implemented */ | |
297 | + linux_audit_user_logxxx(li->uid, NULL, li->hostname, | |
298 | + NULL, li->line, 1, AUDIT_USER_END); | |
299 | + if (user_login_count && !--user_login_count) | |
300 | + linux_audit_user_logxxx(li->uid, NULL, li->hostname, | |
301 | + NULL, li->line, 1, AUDIT_USER_LOGOUT); | |
302 | } | |
303 | ||
304 | void | |
305 | @@ -101,21 +232,43 @@ audit_event(ssh_audit_event_t event) | |
306 | { | |
307 | switch(event) { | |
308 | case SSH_AUTH_SUCCESS: | |
309 | - case SSH_CONNECTION_CLOSE: | |
310 | + linux_audit_user_auth(-1, audit_username(), NULL, | |
311 | + get_remote_ipaddr(), "ssh", 1, event); | |
312 | + break; | |
313 | + | |
314 | case SSH_NOLOGIN: | |
315 | - case SSH_LOGIN_EXCEED_MAXTRIES: | |
316 | case SSH_LOGIN_ROOT_DENIED: | |
317 | + linux_audit_user_auth(-1, audit_username(), NULL, | |
318 | + get_remote_ipaddr(), "ssh", 0, event); | |
319 | + linux_audit_user_logxxx(-1, audit_username(), NULL, | |
320 | + get_remote_ipaddr(), "ssh", 0, AUDIT_USER_LOGIN); | |
321 | break; | |
322 | ||
323 | + case SSH_LOGIN_EXCEED_MAXTRIES: | |
324 | case SSH_AUTH_FAIL_NONE: | |
325 | case SSH_AUTH_FAIL_PASSWD: | |
326 | case SSH_AUTH_FAIL_KBDINT: | |
327 | case SSH_AUTH_FAIL_PUBKEY: | |
328 | case SSH_AUTH_FAIL_HOSTBASED: | |
329 | case SSH_AUTH_FAIL_GSSAPI: | |
330 | + linux_audit_user_auth(-1, audit_username(), NULL, | |
331 | + get_remote_ipaddr(), "ssh", 0, event); | |
332 | + break; | |
333 | + | |
334 | + case SSH_CONNECTION_CLOSE: | |
335 | + if (user_login_count) { | |
336 | + while (user_login_count--) | |
337 | + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), | |
338 | + NULL, "ssh", 1, AUDIT_USER_END); | |
339 | + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), | |
340 | + NULL, "ssh", 1, AUDIT_USER_LOGOUT); | |
341 | + } | |
342 | + break; | |
343 | + | |
344 | + case SSH_CONNECTION_ABANDON: | |
345 | case SSH_INVALID_USER: | |
346 | - linux_audit_record_event(-1, audit_username(), NULL, | |
347 | - get_remote_ipaddr(), "sshd", 0); | |
348 | + linux_audit_user_logxxx(-1, audit_username(), NULL, | |
349 | + get_remote_ipaddr(), "ssh", 0, AUDIT_USER_LOGIN); | |
350 | break; | |
351 | ||
352 | default: | |
353 | @@ -123,4 +276,135 @@ audit_event(ssh_audit_event_t event) | |
354 | } | |
355 | } | |
356 | ||
357 | +void | |
358 | +audit_unsupported_body(int what) | |
359 | +{ | |
360 | +#ifdef AUDIT_CRYPTO_SESSION | |
361 | + char buf[AUDIT_LOG_SIZE]; | |
362 | + const static char *name[] = { "cipher", "mac", "comp" }; | |
363 | + char *s; | |
364 | + int audit_fd; | |
365 | + | |
366 | + snprintf(buf, sizeof(buf), "op=unsupported-%s direction=? cipher=? ksize=? rport=%d laddr=%s lport=%d ", | |
367 | + name[what], get_remote_port(), (s = get_local_ipaddr(packet_get_connection_in())), | |
368 | + get_local_port()); | |
369 | + free(s); | |
370 | + audit_fd = audit_open(); | |
371 | + if (audit_fd < 0) | |
372 | + /* no problem, the next instruction will be fatal() */ | |
373 | + return; | |
374 | + audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION, | |
375 | + buf, NULL, get_remote_ipaddr(), NULL, 0); | |
376 | + audit_close(audit_fd); | |
377 | +#endif | |
378 | +} | |
379 | + | |
380 | +const static char *direction[] = { "from-server", "from-client", "both" }; | |
381 | + | |
382 | +void | |
383 | +audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, | |
384 | + uid_t uid) | |
385 | +{ | |
386 | +#ifdef AUDIT_CRYPTO_SESSION | |
387 | + char buf[AUDIT_LOG_SIZE]; | |
388 | + int audit_fd, audit_ok; | |
389 | + const Cipher *cipher = cipher_by_name(enc); | |
390 | + char *s; | |
391 | + | |
392 | + snprintf(buf, sizeof(buf), "op=start direction=%s cipher=%s ksize=%d mac=%s pfs=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ", | |
393 | + direction[ctos], enc, cipher ? 8 * cipher->key_len : 0, mac, pfs, | |
394 | + (intmax_t)pid, (intmax_t)uid, | |
395 | + get_remote_port(), (s = get_local_ipaddr(packet_get_connection_in())), get_local_port()); | |
396 | + free(s); | |
397 | + audit_fd = audit_open(); | |
398 | + if (audit_fd < 0) { | |
399 | + if (errno == EINVAL || errno == EPROTONOSUPPORT || | |
400 | + errno == EAFNOSUPPORT) | |
401 | + return; /* No audit support in kernel */ | |
402 | + else | |
403 | + fatal("cannot open audit"); /* Must prevent login */ | |
404 | + } | |
405 | + audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION, | |
406 | + buf, NULL, get_remote_ipaddr(), NULL, 1); | |
407 | + audit_close(audit_fd); | |
408 | + /* do not abort if the error is EPERM and sshd is run as non root user */ | |
409 | + if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) | |
410 | + fatal("cannot write into audit"); /* Must prevent login */ | |
411 | +#endif | |
412 | +} | |
413 | + | |
414 | +void | |
415 | +audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) | |
416 | +{ | |
417 | + char buf[AUDIT_LOG_SIZE]; | |
418 | + int audit_fd, audit_ok; | |
419 | + char *s; | |
420 | + | |
421 | + snprintf(buf, sizeof(buf), "op=destroy kind=session fp=? direction=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ", | |
422 | + direction[ctos], (intmax_t)pid, (intmax_t)uid, | |
423 | + get_remote_port(), | |
424 | + (s = get_local_ipaddr(packet_get_connection_in())), | |
425 | + get_local_port()); | |
426 | + free(s); | |
427 | + audit_fd = audit_open(); | |
428 | + if (audit_fd < 0) { | |
429 | + if (errno != EINVAL && errno != EPROTONOSUPPORT && | |
430 | + errno != EAFNOSUPPORT) | |
431 | + error("cannot open audit"); | |
432 | + return; | |
433 | + } | |
434 | + audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, | |
435 | + buf, NULL, get_remote_ipaddr(), NULL, 1); | |
436 | + audit_close(audit_fd); | |
437 | + /* do not abort if the error is EPERM and sshd is run as non root user */ | |
438 | + if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) | |
439 | + error("cannot write into audit"); | |
440 | +} | |
441 | + | |
442 | +void | |
443 | +audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) | |
444 | +{ | |
445 | + char buf[AUDIT_LOG_SIZE]; | |
446 | + int audit_fd, audit_ok; | |
447 | + | |
448 | + snprintf(buf, sizeof(buf), "op=destroy kind=server fp=%s direction=? spid=%jd suid=%jd ", | |
449 | + fp, (intmax_t)pid, (intmax_t)uid); | |
450 | + audit_fd = audit_open(); | |
451 | + if (audit_fd < 0) { | |
452 | + if (errno != EINVAL && errno != EPROTONOSUPPORT && | |
453 | + errno != EAFNOSUPPORT) | |
454 | + error("cannot open audit"); | |
455 | + return; | |
456 | + } | |
457 | + audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, | |
458 | + buf, NULL, | |
459 | + listening_for_clients() ? get_remote_ipaddr() : NULL, | |
460 | + NULL, 1); | |
461 | + audit_close(audit_fd); | |
462 | + /* do not abort if the error is EPERM and sshd is run as non root user */ | |
463 | + if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) | |
464 | + error("cannot write into audit"); | |
465 | +} | |
466 | + | |
467 | +void | |
468 | +audit_generate_ephemeral_server_key(const char *fp) | |
469 | +{ | |
470 | + char buf[AUDIT_LOG_SIZE]; | |
471 | + int audit_fd, audit_ok; | |
472 | + | |
473 | + snprintf(buf, sizeof(buf), "op=create kind=server fp=%s direction=? ", fp); | |
474 | + audit_fd = audit_open(); | |
475 | + if (audit_fd < 0) { | |
476 | + if (errno != EINVAL && errno != EPROTONOSUPPORT && | |
477 | + errno != EAFNOSUPPORT) | |
478 | + error("cannot open audit"); | |
479 | + return; | |
480 | + } | |
481 | + audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, | |
482 | + buf, NULL, 0, NULL, 1); | |
483 | + audit_close(audit_fd); | |
484 | + /* do not abort if the error is EPERM and sshd is run as non root user */ | |
485 | + if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) | |
486 | + error("cannot write into audit"); | |
487 | +} | |
488 | #endif /* USE_LINUX_AUDIT */ | |
489 | diff -up openssh-6.8p1/audit.c.audit openssh-6.8p1/audit.c | |
490 | --- openssh-6.8p1/audit.c.audit 2015-03-17 06:49:20.000000000 +0100 | |
491 | +++ openssh-6.8p1/audit.c 2015-03-20 13:41:15.093883780 +0100 | |
492 | @@ -28,6 +28,7 @@ | |
493 | ||
494 | #include <stdarg.h> | |
495 | #include <string.h> | |
496 | +#include <unistd.h> | |
497 | ||
498 | #ifdef SSH_AUDIT_EVENTS | |
499 | ||
500 | @@ -36,6 +37,11 @@ | |
501 | #include "key.h" | |
502 | #include "hostfile.h" | |
503 | #include "auth.h" | |
504 | +#include "ssh-gss.h" | |
505 | +#include "monitor_wrap.h" | |
506 | +#include "xmalloc.h" | |
507 | +#include "misc.h" | |
508 | +#include "servconf.h" | |
509 | ||
510 | /* | |
511 | * Care must be taken when using this since it WILL NOT be initialized when | |
512 | @@ -43,6 +49,7 @@ | |
513 | * audit_event(CONNECTION_ABANDON) is called. Test for NULL before using. | |
514 | */ | |
515 | extern Authctxt *the_authctxt; | |
516 | +extern ServerOptions options; | |
517 | ||
518 | /* Maybe add the audit class to struct Authmethod? */ | |
519 | ssh_audit_event_t | |
520 | @@ -71,13 +78,10 @@ audit_classify_auth(const char *method) | |
521 | const char * | |
522 | audit_username(void) | |
523 | { | |
524 | - static const char unknownuser[] = "(unknown user)"; | |
525 | - static const char invaliduser[] = "(invalid user)"; | |
526 | + static const char unknownuser[] = "(unknown)"; | |
527 | ||
528 | - if (the_authctxt == NULL || the_authctxt->user == NULL) | |
529 | + if (the_authctxt == NULL || the_authctxt->user == NULL || !the_authctxt->valid) | |
530 | return (unknownuser); | |
531 | - if (!the_authctxt->valid) | |
532 | - return (invaliduser); | |
533 | return (the_authctxt->user); | |
534 | } | |
535 | ||
536 | @@ -111,6 +115,40 @@ audit_event_lookup(ssh_audit_event_t ev) | |
537 | return(event_lookup[i].name); | |
538 | } | |
539 | ||
540 | +void | |
541 | +audit_key(int host_user, int *rv, const Key *key) | |
542 | +{ | |
543 | + char *fp; | |
544 | + const char *crypto_name; | |
545 | + | |
546 | + fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX); | |
547 | + if (key->type == KEY_RSA1) | |
548 | + crypto_name = "ssh-rsa1"; | |
549 | + else | |
550 | + crypto_name = key_ssh_name(key); | |
551 | + if (audit_keyusage(host_user, crypto_name, key_size(key), fp, *rv) == 0) | |
552 | + *rv = 0; | |
553 | + free(fp); | |
554 | +} | |
555 | + | |
556 | +void | |
557 | +audit_unsupported(int what) | |
558 | +{ | |
559 | + PRIVSEP(audit_unsupported_body(what)); | |
560 | +} | |
561 | + | |
562 | +void | |
563 | +audit_kex(int ctos, char *enc, char *mac, char *comp, char *pfs) | |
564 | +{ | |
565 | + PRIVSEP(audit_kex_body(ctos, enc, mac, comp, pfs, getpid(), getuid())); | |
566 | +} | |
567 | + | |
568 | +void | |
569 | +audit_session_key_free(int ctos) | |
570 | +{ | |
571 | + PRIVSEP(audit_session_key_free_body(ctos, getpid(), getuid())); | |
572 | +} | |
573 | + | |
574 | # ifndef CUSTOM_SSH_AUDIT_EVENTS | |
575 | /* | |
576 | * Null implementations of audit functions. | |
577 | @@ -140,6 +178,17 @@ audit_event(ssh_audit_event_t event) | |
578 | } | |
579 | ||
580 | /* | |
581 | + * Called when a child process has called, or will soon call, | |
582 | + * audit_session_open. | |
583 | + */ | |
584 | +void | |
585 | +audit_count_session_open(void) | |
586 | +{ | |
587 | + debug("audit count session open euid %d user %s", geteuid(), | |
588 | + audit_username()); | |
589 | +} | |
590 | + | |
591 | +/* | |
592 | * Called when a user session is started. Argument is the tty allocated to | |
593 | * the session, or NULL if no tty was allocated. | |
594 | * | |
595 | @@ -174,13 +223,91 @@ audit_session_close(struct logininfo *li) | |
596 | /* | |
597 | * This will be called when a user runs a non-interactive command. Note that | |
598 | * it may be called multiple times for a single connection since SSH2 allows | |
599 | - * multiple sessions within a single connection. | |
600 | + * multiple sessions within a single connection. Returns a "handle" for | |
601 | + * audit_end_command. | |
602 | */ | |
603 | -void | |
604 | +int | |
605 | audit_run_command(const char *command) | |
606 | { | |
607 | debug("audit run command euid %d user %s command '%.200s'", geteuid(), | |
608 | audit_username(), command); | |
609 | + return 0; | |
610 | +} | |
611 | + | |
612 | +/* | |
613 | + * This will be called when the non-interactive command finishes. Note that | |
614 | + * it may be called multiple times for a single connection since SSH2 allows | |
615 | + * multiple sessions within a single connection. "handle" should come from | |
616 | + * the corresponding audit_run_command. | |
617 | + */ | |
618 | +void | |
619 | +audit_end_command(int handle, const char *command) | |
620 | +{ | |
621 | + debug("audit end nopty exec euid %d user %s command '%.200s'", geteuid(), | |
622 | + audit_username(), command); | |
623 | +} | |
624 | + | |
625 | +/* | |
626 | + * This will be called when user is successfully autherized by the RSA1/RSA/DSA key. | |
627 | + * | |
628 | + * Type is the key type, len is the key length(byte) and fp is the fingerprint of the key. | |
629 | + */ | |
630 | +int | |
631 | +audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) | |
632 | +{ | |
633 | + debug("audit %s key usage euid %d user %s key type %s key length %d fingerprint %s%s, result %d", | |
634 | + host_user ? "pubkey" : "hostbased", geteuid(), audit_username(), type, bits, | |
635 | + sshkey_fingerprint_prefix(), fp, rv); | |
636 | +} | |
637 | + | |
638 | +/* | |
639 | + * This will be called when the protocol negotiation fails. | |
640 | + */ | |
641 | +void | |
642 | +audit_unsupported_body(int what) | |
643 | +{ | |
644 | + debug("audit unsupported protocol euid %d type %d", geteuid(), what); | |
645 | +} | |
646 | + | |
647 | +/* | |
648 | + * This will be called on succesfull protocol negotiation. | |
649 | + */ | |
650 | +void | |
651 | +audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, | |
652 | + uid_t uid) | |
653 | +{ | |
654 | + debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s pfs %s from pid %ld uid %u", | |
655 | + (unsigned)geteuid(), ctos, enc, mac, compress, pfs, (long)pid, | |
656 | + (unsigned)uid); | |
657 | +} | |
658 | + | |
659 | +/* | |
660 | + * This will be called on succesfull session key discard | |
661 | + */ | |
662 | +void | |
663 | +audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) | |
664 | +{ | |
665 | + debug("audit session key discard euid %u direction %d from pid %ld uid %u", | |
666 | + (unsigned)geteuid(), ctos, (long)pid, (unsigned)uid); | |
667 | +} | |
668 | + | |
669 | +/* | |
670 | + * This will be called on destroy private part of the server key | |
671 | + */ | |
672 | +void | |
673 | +audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) | |
674 | +{ | |
675 | + debug("audit destroy sensitive data euid %d fingerprint %s from pid %ld uid %u", | |
676 | + geteuid(), fp, (long)pid, (unsigned)uid); | |
677 | +} | |
678 | + | |
679 | +/* | |
680 | + * This will be called on generation of the ephemeral server key | |
681 | + */ | |
682 | +void | |
683 | +audit_generate_ephemeral_server_key(const char *) | |
684 | +{ | |
685 | + debug("audit create ephemeral server key euid %d fingerprint %s", geteuid(), fp); | |
686 | } | |
687 | # endif /* !defined CUSTOM_SSH_AUDIT_EVENTS */ | |
688 | #endif /* SSH_AUDIT_EVENTS */ | |
689 | diff -up openssh-6.8p1/audit.h.audit openssh-6.8p1/audit.h | |
690 | --- openssh-6.8p1/audit.h.audit 2015-03-17 06:49:20.000000000 +0100 | |
691 | +++ openssh-6.8p1/audit.h 2015-03-20 13:41:15.093883780 +0100 | |
692 | @@ -28,6 +28,7 @@ | |
693 | # define _SSH_AUDIT_H | |
694 | ||
695 | #include "loginrec.h" | |
696 | +#include "key.h" | |
697 | ||
698 | enum ssh_audit_event_type { | |
699 | SSH_LOGIN_EXCEED_MAXTRIES, | |
700 | @@ -47,11 +48,25 @@ enum ssh_audit_event_type { | |
701 | }; | |
702 | typedef enum ssh_audit_event_type ssh_audit_event_t; | |
703 | ||
704 | +int listening_for_clients(void); | |
705 | + | |
706 | void audit_connection_from(const char *, int); | |
707 | void audit_event(ssh_audit_event_t); | |
708 | +void audit_count_session_open(void); | |
709 | void audit_session_open(struct logininfo *); | |
710 | void audit_session_close(struct logininfo *); | |
711 | -void audit_run_command(const char *); | |
712 | +int audit_run_command(const char *); | |
713 | +void audit_end_command(int, const char *); | |
714 | ssh_audit_event_t audit_classify_auth(const char *); | |
715 | +int audit_keyusage(int, const char *, unsigned, char *, int); | |
716 | +void audit_key(int, int *, const Key *); | |
717 | +void audit_unsupported(int); | |
718 | +void audit_kex(int, char *, char *, char *, char *); | |
719 | +void audit_unsupported_body(int); | |
720 | +void audit_kex_body(int, char *, char *, char *, char *, pid_t, uid_t); | |
721 | +void audit_session_key_free(int ctos); | |
722 | +void audit_session_key_free_body(int ctos, pid_t, uid_t); | |
723 | +void audit_destroy_sensitive_data(const char *, pid_t, uid_t); | |
724 | +void audit_generate_ephemeral_server_key(const char *); | |
725 | ||
726 | #endif /* _SSH_AUDIT_H */ | |
727 | diff -up openssh-6.8p1/auditstub.c.audit openssh-6.8p1/auditstub.c | |
728 | --- openssh-6.8p1/auditstub.c.audit 2015-03-20 13:41:15.093883780 +0100 | |
729 | +++ openssh-6.8p1/auditstub.c 2015-03-20 13:41:15.093883780 +0100 | |
730 | @@ -0,0 +1,50 @@ | |
731 | +/* $Id: auditstub.c,v 1.1 jfch Exp $ */ | |
732 | + | |
733 | +/* | |
734 | + * Copyright 2010 Red Hat, Inc. All rights reserved. | |
735 | + * Use is subject to license terms. | |
736 | + * | |
737 | + * Redistribution and use in source and binary forms, with or without | |
738 | + * modification, are permitted provided that the following conditions | |
739 | + * are met: | |
740 | + * 1. Redistributions of source code must retain the above copyright | |
741 | + * notice, this list of conditions and the following disclaimer. | |
742 | + * 2. Redistributions in binary form must reproduce the above copyright | |
743 | + * notice, this list of conditions and the following disclaimer in the | |
744 | + * documentation and/or other materials provided with the distribution. | |
745 | + * | |
746 | + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
747 | + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
748 | + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
749 | + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
750 | + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
751 | + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
752 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
753 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
754 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
755 | + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
756 | + * | |
757 | + * Red Hat author: Jan F. Chadima <jchadima@redhat.com> | |
758 | + */ | |
759 | + | |
760 | +#include <sys/types.h> | |
761 | + | |
762 | +void | |
763 | +audit_unsupported(int n) | |
764 | +{ | |
765 | +} | |
766 | + | |
767 | +void | |
768 | +audit_kex(int ctos, char *enc, char *mac, char *comp, char *pfs) | |
769 | +{ | |
770 | +} | |
771 | + | |
772 | +void | |
773 | +audit_session_key_free(int ctos) | |
774 | +{ | |
775 | +} | |
776 | + | |
777 | +void | |
778 | +audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) | |
779 | +{ | |
780 | +} | |
781 | diff -up openssh-6.8p1/auth-rsa.c.audit openssh-6.8p1/auth-rsa.c | |
782 | --- openssh-6.8p1/auth-rsa.c.audit 2015-03-17 06:49:20.000000000 +0100 | |
783 | +++ openssh-6.8p1/auth-rsa.c 2015-03-20 13:41:15.094883779 +0100 | |
784 | @@ -95,7 +95,10 @@ auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16]) | |
785 | { | |
786 | u_char buf[32], mdbuf[16]; | |
787 | struct ssh_digest_ctx *md; | |
788 | - int len; | |
789 | + int len, rv; | |
790 | +#ifdef SSH_AUDIT_EVENTS | |
791 | + char *fp; | |
792 | +#endif | |
793 | ||
794 | /* don't allow short keys */ | |
795 | if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { | |
796 | @@ -119,12 +122,18 @@ auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16]) | |
797 | ssh_digest_free(md); | |
798 | ||
799 | /* Verify that the response is the original challenge. */ | |
800 | - if (timingsafe_bcmp(response, mdbuf, 16) != 0) { | |
801 | - /* Wrong answer. */ | |
802 | - return (0); | |
803 | + rv = timingsafe_bcmp(response, mdbuf, 16) == 0; | |
804 | + | |
805 | +#ifdef SSH_AUDIT_EVENTS | |
806 | + fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX); | |
807 | + if (audit_keyusage(1, "ssh-rsa1", RSA_size(key->rsa) * 8, fp, rv) == 0) { | |
808 | + debug("unsuccessful audit"); | |
809 | + rv = 0; | |
810 | } | |
811 | - /* Correct answer. */ | |
812 | - return (1); | |
813 | + free(fp); | |
814 | +#endif | |
815 | + | |
816 | + return rv; | |
817 | } | |
818 | ||
819 | /* | |
820 | diff -up openssh-6.8p1/auth.c.audit openssh-6.8p1/auth.c | |
821 | --- openssh-6.8p1/auth.c.audit 2015-03-17 06:49:20.000000000 +0100 | |
822 | +++ openssh-6.8p1/auth.c 2015-03-20 13:41:15.094883779 +0100 | |
823 | @@ -644,9 +644,6 @@ getpwnamallow(const char *user) | |
824 | record_failed_login(user, | |
825 | get_canonical_hostname(options.use_dns), "ssh"); | |
826 | #endif | |
827 | -#ifdef SSH_AUDIT_EVENTS | |
828 | - audit_event(SSH_INVALID_USER); | |
829 | -#endif /* SSH_AUDIT_EVENTS */ | |
830 | return (NULL); | |
831 | } | |
832 | if (!allowed_user(pw)) | |
833 | diff -up openssh-6.8p1/auth.h.audit openssh-6.8p1/auth.h | |
834 | --- openssh-6.8p1/auth.h.audit 2015-03-20 13:41:15.002883927 +0100 | |
835 | +++ openssh-6.8p1/auth.h 2015-03-20 13:41:15.094883779 +0100 | |
836 | @@ -195,6 +195,7 @@ void abandon_challenge_response(Authctxt | |
837 | ||
838 | char *expand_authorized_keys(const char *, struct passwd *pw); | |
839 | char *authorized_principals_file(struct passwd *); | |
840 | +int user_key_verify(const Key *, const u_char *, u_int, const u_char *, u_int); | |
841 | ||
842 | FILE *auth_openkeyfile(const char *, struct passwd *, int); | |
843 | FILE *auth_openprincipals(const char *, struct passwd *, int); | |
844 | @@ -213,6 +214,7 @@ int get_hostkey_index(Key *, int, struc | |
845 | int ssh1_session_key(BIGNUM *); | |
846 | int sshd_hostkey_sign(Key *, Key *, u_char **, size_t *, | |
847 | const u_char *, size_t, u_int); | |
848 | +int hostbased_key_verify(const Key *, const u_char *, u_int, const u_char *, u_int); | |
849 | ||
850 | /* debug messages during authentication */ | |
851 | void auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2))); | |
852 | diff -up openssh-6.8p1/auth2-hostbased.c.audit openssh-6.8p1/auth2-hostbased.c | |
853 | --- openssh-6.8p1/auth2-hostbased.c.audit 2015-03-20 13:41:15.002883927 +0100 | |
854 | +++ openssh-6.8p1/auth2-hostbased.c 2015-03-20 13:41:15.093883780 +0100 | |
855 | @@ -147,7 +147,7 @@ userauth_hostbased(Authctxt *authctxt) | |
856 | /* test for allowed key and correct signature */ | |
857 | authenticated = 0; | |
858 | if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) && | |
859 | - PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), | |
860 | + PRIVSEP(hostbased_key_verify(key, sig, slen, buffer_ptr(&b), | |
861 | buffer_len(&b))) == 1) | |
862 | authenticated = 1; | |
863 | ||
864 | @@ -164,6 +164,18 @@ done: | |
865 | return authenticated; | |
866 | } | |
867 | ||
868 | +int | |
869 | +hostbased_key_verify(const Key *key, const u_char *sig, u_int slen, const u_char *data, u_int datalen) | |
870 | +{ | |
871 | + int rv; | |
872 | + | |
873 | + rv = key_verify(key, sig, slen, data, datalen); | |
874 | +#ifdef SSH_AUDIT_EVENTS | |
875 | + audit_key(0, &rv, key); | |
876 | +#endif | |
877 | + return rv; | |
878 | +} | |
879 | + | |
880 | /* return 1 if given hostkey is allowed */ | |
881 | int | |
882 | hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, | |
883 | diff -up openssh-6.8p1/auth2-pubkey.c.audit openssh-6.8p1/auth2-pubkey.c | |
884 | --- openssh-6.8p1/auth2-pubkey.c.audit 2015-03-20 13:41:15.013883910 +0100 | |
885 | +++ openssh-6.8p1/auth2-pubkey.c 2015-03-20 13:41:15.094883779 +0100 | |
886 | @@ -172,7 +172,7 @@ userauth_pubkey(Authctxt *authctxt) | |
887 | /* test for correct signature */ | |
888 | authenticated = 0; | |
889 | if (PRIVSEP(user_key_allowed(authctxt->pw, key)) && | |
890 | - PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), | |
891 | + PRIVSEP(user_key_verify(key, sig, slen, buffer_ptr(&b), | |
892 | buffer_len(&b))) == 1) { | |
893 | authenticated = 1; | |
894 | /* Record the successful key to prevent reuse */ | |
895 | @@ -250,6 +250,18 @@ pubkey_auth_info(Authctxt *authctxt, con | |
896 | free(extra); | |
897 | } | |
898 | ||
899 | +int | |
900 | +user_key_verify(const Key *key, const u_char *sig, u_int slen, const u_char *data, u_int datalen) | |
901 | +{ | |
902 | + int rv; | |
903 | + | |
904 | + rv = key_verify(key, sig, slen, data, datalen); | |
905 | +#ifdef SSH_AUDIT_EVENTS | |
906 | + audit_key(1, &rv, key); | |
907 | +#endif | |
908 | + return rv; | |
909 | +} | |
910 | + | |
911 | static int | |
912 | match_principals_option(const char *principal_list, struct sshkey_cert *cert) | |
913 | { | |
914 | diff -up openssh-6.8p1/auth2.c.audit openssh-6.8p1/auth2.c | |
915 | --- openssh-6.8p1/auth2.c.audit 2015-03-20 13:41:15.044883860 +0100 | |
916 | +++ openssh-6.8p1/auth2.c 2015-03-20 13:41:15.093883780 +0100 | |
917 | @@ -249,9 +249,6 @@ input_userauth_request(int type, u_int32 | |
918 | } else { | |
919 | logit("input_userauth_request: invalid user %s", user); | |
920 | authctxt->pw = fakepw(); | |
921 | -#ifdef SSH_AUDIT_EVENTS | |
922 | - PRIVSEP(audit_event(SSH_INVALID_USER)); | |
923 | -#endif | |
924 | } | |
925 | #ifdef USE_PAM | |
926 | if (options.use_pam) | |
927 | diff -up openssh-6.8p1/cipher.c.audit openssh-6.8p1/cipher.c | |
928 | --- openssh-6.8p1/cipher.c.audit 2015-03-17 06:49:20.000000000 +0100 | |
929 | +++ openssh-6.8p1/cipher.c 2015-03-20 13:41:15.101883767 +0100 | |
930 | @@ -57,26 +59,6 @@ extern const EVP_CIPHER *evp_ssh1_3des(v | |
931 | extern int ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); | |
932 | #endif | |
933 | ||
934 | -struct sshcipher { | |
935 | - char *name; | |
936 | - int number; /* for ssh1 only */ | |
937 | - u_int block_size; | |
938 | - u_int key_len; | |
939 | - u_int iv_len; /* defaults to block_size */ | |
940 | - u_int auth_len; | |
941 | - u_int discard_len; | |
942 | - u_int flags; | |
943 | -#define CFLAG_CBC (1<<0) | |
944 | -#define CFLAG_CHACHAPOLY (1<<1) | |
945 | -#define CFLAG_AESCTR (1<<2) | |
946 | -#define CFLAG_NONE (1<<3) | |
947 | -#ifdef WITH_OPENSSL | |
948 | - const EVP_CIPHER *(*evptype)(void); | |
949 | -#else | |
950 | - void *ignored; | |
951 | -#endif | |
952 | -}; | |
953 | - | |
954 | static const struct sshcipher ciphers[] = { | |
955 | #ifdef WITH_SSH1 | |
956 | { "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc }, | |
957 | diff -up openssh-6.8p1/cipher.h.audit openssh-6.8p1/cipher.h | |
958 | --- openssh-6.8p1/cipher.h.audit 2015-03-17 06:49:20.000000000 +0100 | |
959 | +++ openssh-6.8p1/cipher.h 2015-03-20 13:41:15.094883779 +0100 | |
960 | @@ -62,7 +62,26 @@ | |
961 | #define CIPHER_ENCRYPT 1 | |
962 | #define CIPHER_DECRYPT 0 | |
963 | ||
964 | -struct sshcipher; | |
965 | +struct sshcipher { | |
966 | + char *name; | |
967 | + int number; /* for ssh1 only */ | |
968 | + u_int block_size; | |
969 | + u_int key_len; | |
970 | + u_int iv_len; /* defaults to block_size */ | |
971 | + u_int auth_len; | |
972 | + u_int discard_len; | |
973 | + u_int flags; | |
974 | +#define CFLAG_CBC (1<<0) | |
975 | +#define CFLAG_CHACHAPOLY (1<<1) | |
976 | +#define CFLAG_AESCTR (1<<2) | |
977 | +#define CFLAG_NONE (1<<3) | |
978 | +#ifdef WITH_OPENSSL | |
979 | + const EVP_CIPHER *(*evptype)(void); | |
980 | +#else | |
981 | + void *ignored; | |
982 | +#endif | |
983 | +}; | |
984 | + | |
985 | struct sshcipher_ctx { | |
986 | int plaintext; | |
987 | int encrypt; | |
988 | diff -up openssh-6.8p1/kex.c.audit openssh-6.8p1/kex.c | |
989 | --- openssh-6.8p1/kex.c.audit 2015-03-20 13:41:15.046883856 +0100 | |
990 | +++ openssh-6.8p1/kex.c 2015-03-20 13:41:15.101883767 +0100 | |
991 | @@ -54,6 +55,7 @@ | |
992 | #include "ssherr.h" | |
993 | #include "sshbuf.h" | |
994 | #include "digest.h" | |
995 | +#include "audit.h" | |
996 | ||
997 | #ifdef GSSAPI | |
998 | #include "ssh-gss.h" | |
999 | @@ -484,8 +508,12 @@ choose_enc(struct sshenc *enc, char *cli | |
1000 | { | |
1001 | char *name = match_list(client, server, NULL); | |
1002 | ||
1003 | - if (name == NULL) | |
1004 | + if (name == NULL) { | |
1005 | +#ifdef SSH_AUDIT_EVENTS | |
1006 | + audit_unsupported(0); | |
1007 | +#endif | |
1008 | return SSH_ERR_NO_CIPHER_ALG_MATCH; | |
1009 | + } | |
1010 | if ((enc->cipher = cipher_by_name(name)) == NULL) | |
1011 | return SSH_ERR_INTERNAL_ERROR; | |
1012 | enc->name = name; | |
1013 | @@ -503,8 +531,12 @@ choose_mac(struct ssh *ssh, struct sshma | |
1014 | { | |
1015 | char *name = match_list(client, server, NULL); | |
1016 | ||
1017 | - if (name == NULL) | |
1018 | + if (name == NULL) { | |
1019 | +#ifdef SSH_AUDIT_EVENTS | |
1020 | + audit_unsupported(1); | |
1021 | +#endif | |
1022 | return SSH_ERR_NO_MAC_ALG_MATCH; | |
1023 | + } | |
1024 | if (mac_setup(mac, name) < 0) | |
1025 | return SSH_ERR_INTERNAL_ERROR; | |
1026 | /* truncate the key */ | |
1027 | @@ -521,8 +553,12 @@ choose_comp(struct sshcomp *comp, char * | |
1028 | { | |
1029 | char *name = match_list(client, server, NULL); | |
1030 | ||
1031 | - if (name == NULL) | |
1032 | + if (name == NULL) { | |
1033 | +#ifdef SSH_AUDIT_EVENTS | |
1034 | + audit_unsupported(2); | |
1035 | +#endif | |
1036 | return SSH_ERR_NO_COMPRESS_ALG_MATCH; | |
1037 | + } | |
1038 | if (strcmp(name, "zlib@openssh.com") == 0) { | |
1039 | comp->type = COMP_DELAYED; | |
1040 | } else if (strcmp(name, "zlib") == 0) { | |
1041 | @@ -672,6 +708,10 @@ kex_choose_conf(struct ssh *ssh) | |
1042 | dh_need = MAX(dh_need, newkeys->enc.block_size); | |
1043 | dh_need = MAX(dh_need, newkeys->enc.iv_len); | |
1044 | dh_need = MAX(dh_need, newkeys->mac.key_len); | |
1045 | + debug("kex: %s need=%d dh_need=%d", kex->name, need, dh_need); | |
1046 | +#ifdef SSH_AUDIT_EVENTS | |
1047 | + audit_kex(mode, newkeys->enc.name, newkeys->mac.name, newkeys->comp.name, kex->name); | |
1048 | +#endif | |
1049 | } | |
1050 | /* XXX need runden? */ | |
1051 | kex->we_need = need; | |
1052 | @@ -847,3 +887,34 @@ dump_digest(char *msg, u_char *digest, i | |
1053 | sshbuf_dump_data(digest, len, stderr); | |
1054 | } | |
1055 | #endif | |
1056 | + | |
1057 | +static void | |
1058 | +enc_destroy(struct sshenc *enc) | |
1059 | +{ | |
1060 | + if (enc == NULL) | |
1061 | + return; | |
1062 | + | |
1063 | + if (enc->key) { | |
1064 | + memset(enc->key, 0, enc->key_len); | |
1065 | + free(enc->key); | |
1066 | + } | |
1067 | + | |
1068 | + if (enc->iv) { | |
1069 | + memset(enc->iv, 0, enc->block_size); | |
1070 | + free(enc->iv); | |
1071 | + } | |
1072 | + | |
1073 | + memset(enc, 0, sizeof(*enc)); | |
1074 | +} | |
1075 | + | |
1076 | +void | |
1077 | +newkeys_destroy(struct newkeys *newkeys) | |
1078 | +{ | |
1079 | + if (newkeys == NULL) | |
1080 | + return; | |
1081 | + | |
1082 | + enc_destroy(&newkeys->enc); | |
1083 | + mac_destroy(&newkeys->mac); | |
1084 | + memset(&newkeys->comp, 0, sizeof(newkeys->comp)); | |
1085 | +} | |
1086 | + | |
1087 | diff -up openssh-6.8p1/kex.h.audit openssh-6.8p1/kex.h | |
1088 | --- openssh-6.8p1/kex.h.audit 2015-03-20 13:41:15.046883856 +0100 | |
1089 | +++ openssh-6.8p1/kex.h 2015-03-20 13:41:15.095883777 +0100 | |
1090 | @@ -199,6 +199,8 @@ int kexgss_client(struct ssh *); | |
1091 | int kexgss_server(struct ssh *); | |
1092 | #endif | |
1093 | ||
1094 | +void newkeys_destroy(struct newkeys *newkeys); | |
1095 | + | |
1096 | int kex_dh_hash(const char *, const char *, | |
1097 | const u_char *, size_t, const u_char *, size_t, const u_char *, size_t, | |
1098 | const BIGNUM *, const BIGNUM *, const BIGNUM *, u_char *, size_t *); | |
1099 | diff -up openssh-6.8p1/key.h.audit openssh-6.8p1/key.h | |
1100 | --- openssh-6.8p1/key.h.audit 2015-03-17 06:49:20.000000000 +0100 | |
1101 | +++ openssh-6.8p1/key.h 2015-03-20 13:41:15.095883777 +0100 | |
1102 | @@ -50,6 +50,7 @@ typedef struct sshkey Key; | |
1103 | #define key_ecdsa_bits_to_nid sshkey_ecdsa_bits_to_nid | |
1104 | #define key_ecdsa_key_to_nid sshkey_ecdsa_key_to_nid | |
1105 | #define key_is_cert sshkey_is_cert | |
1106 | +#define key_is_private sshkey_is_private | |
1107 | #define key_type_plain sshkey_type_plain | |
1108 | #define key_cert_is_legacy sshkey_cert_is_legacy | |
1109 | #define key_curve_name_to_nid sshkey_curve_name_to_nid | |
1110 | diff -up openssh-6.8p1/mac.c.audit openssh-6.8p1/mac.c | |
1111 | --- openssh-6.8p1/mac.c.audit 2015-03-17 06:49:20.000000000 +0100 | |
1112 | +++ openssh-6.8p1/mac.c 2015-03-20 13:41:15.102883766 +0100 | |
1113 | @@ -226,6 +246,20 @@ mac_clear(struct sshmac *mac) | |
1114 | mac->umac_ctx = NULL; | |
1115 | } | |
1116 | ||
1117 | +void | |
1118 | +mac_destroy(struct sshmac *mac) | |
1119 | +{ | |
1120 | + if (mac == NULL) | |
1121 | + return; | |
1122 | + | |
1123 | + if (mac->key) { | |
1124 | + memset(mac->key, 0, mac->key_len); | |
1125 | + free(mac->key); | |
1126 | + } | |
1127 | + | |
1128 | + memset(mac, 0, sizeof(*mac)); | |
1129 | +} | |
1130 | + | |
1131 | /* XXX copied from ciphers_valid */ | |
1132 | #define MAC_SEP "," | |
1133 | int | |
1134 | diff -up openssh-6.8p1/mac.h.audit openssh-6.8p1/mac.h | |
1135 | --- openssh-6.8p1/mac.h.audit 2015-03-17 06:49:20.000000000 +0100 | |
1136 | +++ openssh-6.8p1/mac.h 2015-03-20 13:41:15.095883777 +0100 | |
1137 | @@ -47,5 +47,6 @@ int mac_init(struct sshmac *); | |
1138 | int mac_compute(struct sshmac *, u_int32_t, const u_char *, int, | |
1139 | u_char *, size_t); | |
1140 | void mac_clear(struct sshmac *); | |
1141 | +void mac_destroy(struct sshmac *); | |
1142 | ||
1143 | #endif /* SSHMAC_H */ | |
1144 | diff -up openssh-6.8p1/monitor.c.audit openssh-6.8p1/monitor.c | |
1145 | --- openssh-6.8p1/monitor.c.audit 2015-03-20 13:41:15.072883814 +0100 | |
1146 | +++ openssh-6.8p1/monitor.c 2015-03-20 13:41:15.107883758 +0100 | |
1147 | @@ -102,6 +102,7 @@ | |
1148 | #include "ssh2.h" | |
1149 | #include "roaming.h" | |
1150 | #include "authfd.h" | |
1151 | +#include "audit.h" | |
1152 | #include "match.h" | |
1153 | #include "ssherr.h" | |
1154 | ||
1155 | @@ -117,6 +118,8 @@ extern Buffer auth_debug; | |
1156 | extern int auth_debug_init; | |
1157 | extern Buffer loginmsg; | |
1158 | ||
1159 | +extern void destroy_sensitive_data(int); | |
1160 | + | |
1161 | /* State exported from the child */ | |
1162 | static struct sshbuf *child_state; | |
1163 | ||
1164 | @@ -167,6 +170,11 @@ int mm_answer_gss_updatecreds(int, Buffe | |
1165 | #ifdef SSH_AUDIT_EVENTS | |
1166 | int mm_answer_audit_event(int, Buffer *); | |
1167 | int mm_answer_audit_command(int, Buffer *); | |
1168 | +int mm_answer_audit_end_command(int, Buffer *); | |
1169 | +int mm_answer_audit_unsupported_body(int, Buffer *); | |
1170 | +int mm_answer_audit_kex_body(int, Buffer *); | |
1171 | +int mm_answer_audit_session_key_free_body(int, Buffer *); | |
1172 | +int mm_answer_audit_server_key_free(int, Buffer *); | |
1173 | #endif | |
1174 | ||
1175 | static int monitor_read_log(struct monitor *); | |
1176 | @@ -226,6 +234,10 @@ struct mon_table mon_dispatch_proto20[] | |
1177 | #endif | |
1178 | #ifdef SSH_AUDIT_EVENTS | |
1179 | {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, | |
1180 | + {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, | |
1181 | + {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, | |
1182 | + {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, | |
1183 | + {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, | |
1184 | #endif | |
1185 | #ifdef BSD_AUTH | |
1186 | {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery}, | |
1187 | @@ -264,6 +276,11 @@ struct mon_table mon_dispatch_postauth20 | |
1188 | #ifdef SSH_AUDIT_EVENTS | |
1189 | {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, | |
1190 | {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT, mm_answer_audit_command}, | |
1191 | + {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command}, | |
1192 | + {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, | |
1193 | + {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, | |
1194 | + {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, | |
1195 | + {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, | |
1196 | #endif | |
1197 | {0, 0, NULL} | |
1198 | }; | |
1199 | @@ -296,6 +313,10 @@ struct mon_table mon_dispatch_proto15[] | |
1200 | #endif | |
1201 | #ifdef SSH_AUDIT_EVENTS | |
1202 | {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, | |
1203 | + {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, | |
1204 | + {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, | |
1205 | + {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, | |
1206 | + {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, | |
1207 | #endif | |
1208 | #endif /* WITH_SSH1 */ | |
1209 | {0, 0, NULL} | |
1210 | @@ -309,6 +330,11 @@ struct mon_table mon_dispatch_postauth15 | |
1211 | #ifdef SSH_AUDIT_EVENTS | |
1212 | {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, | |
1213 | {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT|MON_ONCE, mm_answer_audit_command}, | |
1214 | + {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command}, | |
1215 | + {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, | |
1216 | + {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, | |
1217 | + {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, | |
1218 | + {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, | |
1219 | #endif | |
1220 | #endif /* WITH_SSH1 */ | |
1221 | {0, 0, NULL} | |
1222 | @@ -1466,9 +1493,11 @@ mm_answer_keyverify(int sock, Buffer *m) | |
1223 | Key *key; | |
1224 | u_char *signature, *data, *blob; | |
1225 | u_int signaturelen, datalen, bloblen; | |
1226 | + int type = 0; | |
1227 | int verified = 0; | |
1228 | int valid_data = 0; | |
1229 | ||
1230 | + type = buffer_get_int(m); | |
1231 | blob = buffer_get_string(m, &bloblen); | |
1232 | signature = buffer_get_string(m, &signaturelen); | |
1233 | data = buffer_get_string(m, &datalen); | |
1234 | @@ -1476,6 +1505,8 @@ mm_answer_keyverify(int sock, Buffer *m) | |
1235 | if (hostbased_cuser == NULL || hostbased_chost == NULL || | |
1236 | !monitor_allowed_key(blob, bloblen)) | |
1237 | fatal("%s: bad key, not previously allowed", __func__); | |
1238 | + if (type != key_blobtype) | |
1239 | + fatal("%s: bad key type", __func__); | |
1240 | ||
1241 | key = key_from_blob(blob, bloblen); | |
1242 | if (key == NULL) | |
1243 | @@ -1496,7 +1527,17 @@ mm_answer_keyverify(int sock, Buffer *m) | |
1244 | if (!valid_data) | |
1245 | fatal("%s: bad signature data blob", __func__); | |
1246 | ||
1247 | - verified = key_verify(key, signature, signaturelen, data, datalen); | |
1248 | + switch (key_blobtype) { | |
1249 | + case MM_USERKEY: | |
1250 | + verified = user_key_verify(key, signature, signaturelen, data, datalen); | |
1251 | + break; | |
1252 | + case MM_HOSTKEY: | |
1253 | + verified = hostbased_key_verify(key, signature, signaturelen, data, datalen); | |
1254 | + break; | |
1255 | + default: | |
1256 | + verified = 0; | |
1257 | + break; | |
1258 | + } | |
1259 | debug3("%s: key %p signature %s", | |
1260 | __func__, key, (verified == 1) ? "verified" : "unverified"); | |
1261 | ||
1262 | @@ -1554,6 +1595,12 @@ mm_session_close(Session *s) | |
1263 | debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd); | |
1264 | session_pty_cleanup2(s); | |
1265 | } | |
1266 | +#ifdef SSH_AUDIT_EVENTS | |
1267 | + if (s->command != NULL) { | |
1268 | + debug3("%s: command %d", __func__, s->command_handle); | |
1269 | + session_end_command2(s); | |
1270 | + } | |
1271 | +#endif | |
1272 | session_unused(s->self); | |
1273 | } | |
1274 | ||
1275 | @@ -1836,6 +1883,8 @@ mm_answer_term(int sock, Buffer *req) | |
1276 | sshpam_cleanup(); | |
1277 | #endif | |
1278 | ||
1279 | + destroy_sensitive_data(0); | |
1280 | + | |
1281 | while (waitpid(pmonitor->m_pid, &status, 0) == -1) | |
1282 | if (errno != EINTR) | |
1283 | exit(1); | |
1284 | @@ -1878,11 +1927,43 @@ mm_answer_audit_command(int socket, Buff | |
1285 | { | |
1286 | u_int len; | |
1287 | char *cmd; | |
1288 | + Session *s; | |
1289 | ||
1290 | debug3("%s entering", __func__); | |
1291 | cmd = buffer_get_string(m, &len); | |
1292 | + | |
1293 | /* sanity check command, if so how? */ | |
1294 | - audit_run_command(cmd); | |
1295 | + s = session_new(); | |
1296 | + if (s == NULL) | |
1297 | + fatal("%s: error allocating a session", __func__); | |
1298 | + s->command = cmd; | |
1299 | + s->command_handle = audit_run_command(cmd); | |
1300 | + | |
1301 | + buffer_clear(m); | |
1302 | + buffer_put_int(m, s->self); | |
1303 | + | |
1304 | + mm_request_send(socket, MONITOR_ANS_AUDIT_COMMAND, m); | |
1305 | + | |
1306 | + return (0); | |
1307 | +} | |
1308 | + | |
1309 | +int | |
1310 | +mm_answer_audit_end_command(int socket, Buffer *m) | |
1311 | +{ | |
1312 | + int handle; | |
1313 | + u_int len; | |
1314 | + char *cmd; | |
1315 | + Session *s; | |
1316 | + | |
1317 | + debug3("%s entering", __func__); | |
1318 | + handle = buffer_get_int(m); | |
1319 | + cmd = buffer_get_string(m, &len); | |
1320 | + | |
1321 | + s = session_by_id(handle); | |
1322 | + if (s == NULL || s->ttyfd != -1 || s->command == NULL || | |
1323 | + strcmp(s->command, cmd) != 0) | |
1324 | + fatal("%s: invalid handle", __func__); | |
1325 | + mm_session_close(s); | |
1326 | free(cmd); | |
1327 | return (0); | |
1328 | } | |
1329 | @@ -1936,6 +2017,7 @@ | |
1330 | void | |
1331 | mm_get_keystate(struct monitor *pmonitor) | |
1332 | { | |
1333 | + Buffer m; | |
1334 | debug3("%s: Waiting for new keys", __func__); | |
1335 | ||
1336 | if ((child_state = sshbuf_new()) == NULL) | |
1337 | @@ -1946,6 +2027,21 @@ mm_get_keystate(struct monitor *pmonitor | |
1338 | mm_request_receive_expect(pmonitor->m_sendfd, MONITOR_REQ_KEYEXPORT, | |
1339 | child_state); | |
1340 | debug3("%s: GOT new keys", __func__); | |
1341 | + | |
1342 | +#ifdef SSH_AUDIT_EVENTS | |
1343 | + if (compat20) { | |
1344 | + buffer_init(&m); | |
1345 | + mm_request_receive_expect(pmonitor->m_sendfd, | |
1346 | + MONITOR_REQ_AUDIT_SESSION_KEY_FREE, &m); | |
1347 | + mm_answer_audit_session_key_free_body(pmonitor->m_sendfd, &m); | |
1348 | + buffer_free(&m); | |
1349 | + } | |
1350 | +#endif | |
1351 | + | |
1352 | + /* Drain any buffered messages from the child */ | |
1353 | + while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0) | |
1354 | + ; | |
1355 | + | |
1356 | } | |
1357 | ||
1358 | ||
1359 | @@ -2212,3 +2308,87 @@ mm_answer_gss_updatecreds(int socket, Bu | |
1360 | ||
1361 | #endif /* GSSAPI */ | |
1362 | ||
1363 | +#ifdef SSH_AUDIT_EVENTS | |
1364 | +int | |
1365 | +mm_answer_audit_unsupported_body(int sock, Buffer *m) | |
1366 | +{ | |
1367 | + int what; | |
1368 | + | |
1369 | + what = buffer_get_int(m); | |
1370 | + | |
1371 | + audit_unsupported_body(what); | |
1372 | + | |
1373 | + buffer_clear(m); | |
1374 | + | |
1375 | + mm_request_send(sock, MONITOR_ANS_AUDIT_UNSUPPORTED, m); | |
1376 | + return 0; | |
1377 | +} | |
1378 | + | |
1379 | +int | |
1380 | +mm_answer_audit_kex_body(int sock, Buffer *m) | |
1381 | +{ | |
1382 | + int ctos, len; | |
1383 | + char *cipher, *mac, *compress, *pfs; | |
1384 | + pid_t pid; | |
1385 | + uid_t uid; | |
1386 | + | |
1387 | + ctos = buffer_get_int(m); | |
1388 | + cipher = buffer_get_string(m, &len); | |
1389 | + mac = buffer_get_string(m, &len); | |
1390 | + compress = buffer_get_string(m, &len); | |
1391 | + pfs = buffer_get_string(m, &len); | |
1392 | + pid = buffer_get_int64(m); | |
1393 | + uid = buffer_get_int64(m); | |
1394 | + | |
1395 | + audit_kex_body(ctos, cipher, mac, compress, pfs, pid, uid); | |
1396 | + | |
1397 | + free(cipher); | |
1398 | + free(mac); | |
1399 | + free(compress); | |
1400 | + free(pfs); | |
1401 | + buffer_clear(m); | |
1402 | + | |
1403 | + mm_request_send(sock, MONITOR_ANS_AUDIT_KEX, m); | |
1404 | + return 0; | |
1405 | +} | |
1406 | + | |
1407 | +int | |
1408 | +mm_answer_audit_session_key_free_body(int sock, Buffer *m) | |
1409 | +{ | |
1410 | + int ctos; | |
1411 | + pid_t pid; | |
1412 | + uid_t uid; | |
1413 | + | |
1414 | + ctos = buffer_get_int(m); | |
1415 | + pid = buffer_get_int64(m); | |
1416 | + uid = buffer_get_int64(m); | |
1417 | + | |
1418 | + audit_session_key_free_body(ctos, pid, uid); | |
1419 | + | |
1420 | + buffer_clear(m); | |
1421 | + | |
1422 | + mm_request_send(sock, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, m); | |
1423 | + return 0; | |
1424 | +} | |
1425 | + | |
1426 | +int | |
1427 | +mm_answer_audit_server_key_free(int sock, Buffer *m) | |
1428 | +{ | |
1429 | + int len; | |
1430 | + char *fp; | |
1431 | + pid_t pid; | |
1432 | + uid_t uid; | |
1433 | + | |
1434 | + fp = buffer_get_string(m, &len); | |
1435 | + pid = buffer_get_int64(m); | |
1436 | + uid = buffer_get_int64(m); | |
1437 | + | |
1438 | + audit_destroy_sensitive_data(fp, pid, uid); | |
1439 | + | |
1440 | + free(fp); | |
1441 | + buffer_clear(m); | |
1442 | + | |
1443 | + mm_request_send(sock, MONITOR_ANS_AUDIT_SERVER_KEY_FREE, m); | |
1444 | + return 0; | |
1445 | +} | |
1446 | +#endif /* SSH_AUDIT_EVENTS */ | |
1447 | diff -up openssh-6.8p1/monitor.h.audit openssh-6.8p1/monitor.h | |
1448 | --- openssh-6.8p1/monitor.h.audit 2015-03-20 13:41:15.072883814 +0100 | |
1449 | +++ openssh-6.8p1/monitor.h 2015-03-20 13:41:15.096883775 +0100 | |
1450 | @@ -69,7 +69,13 @@ enum monitor_reqtype { | |
1451 | MONITOR_REQ_PAM_QUERY = 106, MONITOR_ANS_PAM_QUERY = 107, | |
1452 | MONITOR_REQ_PAM_RESPOND = 108, MONITOR_ANS_PAM_RESPOND = 109, | |
1453 | MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111, | |
1454 | - MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113, | |
1455 | + MONITOR_REQ_AUDIT_EVENT = 112, | |
1456 | + MONITOR_REQ_AUDIT_COMMAND = 114, MONITOR_ANS_AUDIT_COMMAND = 115, | |
1457 | + MONITOR_REQ_AUDIT_END_COMMAND = 116, | |
1458 | + MONITOR_REQ_AUDIT_UNSUPPORTED = 118, MONITOR_ANS_AUDIT_UNSUPPORTED = 119, | |
1459 | + MONITOR_REQ_AUDIT_KEX = 120, MONITOR_ANS_AUDIT_KEX = 121, | |
1460 | + MONITOR_REQ_AUDIT_SESSION_KEY_FREE = 122, MONITOR_ANS_AUDIT_SESSION_KEY_FREE = 123, | |
1461 | + MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 124, MONITOR_ANS_AUDIT_SERVER_KEY_FREE = 125 | |
1462 | ||
1463 | }; | |
1464 | ||
1465 | diff -up openssh-6.8p1/monitor_wrap.c.audit openssh-6.8p1/monitor_wrap.c | |
1466 | --- openssh-6.8p1/monitor_wrap.c.audit 2015-03-20 13:41:15.047883855 +0100 | |
1467 | +++ openssh-6.8p1/monitor_wrap.c 2015-03-20 13:41:15.108883756 +0100 | |
1468 | @@ -461,7 +461,7 @@ mm_key_allowed(enum mm_keytype type, cha | |
1469 | */ | |
1470 | ||
1471 | int | |
1472 | -mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) | |
1473 | +mm_key_verify(enum mm_keytype type, Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) | |
1474 | { | |
1475 | Buffer m; | |
1476 | u_char *blob; | |
1477 | @@ -475,6 +475,7 @@ mm_key_verify(Key *key, u_char *sig, u_i | |
1478 | return (0); | |
1479 | ||
1480 | buffer_init(&m); | |
1481 | + buffer_put_int(&m, type); | |
1482 | buffer_put_string(&m, blob, len); | |
1483 | buffer_put_string(&m, sig, siglen); | |
1484 | buffer_put_string(&m, data, datalen); | |
1485 | @@ -492,6 +493,18 @@ mm_key_verify(Key *key, u_char *sig, u_i | |
1486 | return (verified); | |
1487 | } | |
1488 | ||
1489 | +int | |
1490 | +mm_hostbased_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) | |
1491 | +{ | |
1492 | + return mm_key_verify(MM_HOSTKEY, key, sig, siglen, data, datalen); | |
1493 | +} | |
1494 | + | |
1495 | +int | |
1496 | +mm_user_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) | |
1497 | +{ | |
1498 | + return mm_key_verify(MM_USERKEY, key, sig, siglen, data, datalen); | |
1499 | +} | |
1500 | + | |
1501 | void | |
1502 | mm_send_keystate(struct monitor *monitor) | |
1503 | { | |
1504 | @@ -1005,10 +1018,11 @@ mm_audit_event(ssh_audit_event_t event) | |
1505 | buffer_free(&m); | |
1506 | } | |
1507 | ||
1508 | -void | |
1509 | +int | |
1510 | mm_audit_run_command(const char *command) | |
1511 | { | |
1512 | Buffer m; | |
1513 | + int handle; | |
1514 | ||
1515 | debug3("%s entering command %s", __func__, command); | |
1516 | ||
1517 | @@ -1016,6 +1030,26 @@ mm_audit_run_command(const char *command | |
1518 | buffer_put_cstring(&m, command); | |
1519 | ||
1520 | mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_COMMAND, &m); | |
1521 | + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_COMMAND, &m); | |
1522 | + | |
1523 | + handle = buffer_get_int(&m); | |
1524 | + buffer_free(&m); | |
1525 | + | |
1526 | + return (handle); | |
1527 | +} | |
1528 | + | |
1529 | +void | |
1530 | +mm_audit_end_command(int handle, const char *command) | |
1531 | +{ | |
1532 | + Buffer m; | |
1533 | + | |
1534 | + debug3("%s entering command %s", __func__, command); | |
1535 | + | |
1536 | + buffer_init(&m); | |
1537 | + buffer_put_int(&m, handle); | |
1538 | + buffer_put_cstring(&m, command); | |
1539 | + | |
1540 | + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_END_COMMAND, &m); | |
1541 | buffer_free(&m); | |
1542 | } | |
1543 | #endif /* SSH_AUDIT_EVENTS */ | |
1544 | @@ -1151,3 +1185,72 @@ mm_ssh_gssapi_update_creds(ssh_gssapi_cc | |
1545 | ||
1546 | #endif /* GSSAPI */ | |
1547 | ||
1548 | +#ifdef SSH_AUDIT_EVENTS | |
1549 | +void | |
1550 | +mm_audit_unsupported_body(int what) | |
1551 | +{ | |
1552 | + Buffer m; | |
1553 | + | |
1554 | + buffer_init(&m); | |
1555 | + buffer_put_int(&m, what); | |
1556 | + | |
1557 | + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_UNSUPPORTED, &m); | |
1558 | + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_UNSUPPORTED, | |
1559 | + &m); | |
1560 | + | |
1561 | + buffer_free(&m); | |
1562 | +} | |
1563 | + | |
1564 | +void | |
1565 | +mm_audit_kex_body(int ctos, char *cipher, char *mac, char *compress, char *fps, pid_t pid, | |
1566 | + uid_t uid) | |
1567 | +{ | |
1568 | + Buffer m; | |
1569 | + | |
1570 | + buffer_init(&m); | |
1571 | + buffer_put_int(&m, ctos); | |
1572 | + buffer_put_cstring(&m, cipher); | |
1573 | + buffer_put_cstring(&m, (mac ? mac : "")); | |
1574 | + buffer_put_cstring(&m, compress); | |
1575 | + buffer_put_cstring(&m, fps); | |
1576 | + buffer_put_int64(&m, pid); | |
1577 | + buffer_put_int64(&m, uid); | |
1578 | + | |
1579 | + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_KEX, &m); | |
1580 | + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_KEX, | |
1581 | + &m); | |
1582 | + | |
1583 | + buffer_free(&m); | |
1584 | +} | |
1585 | + | |
1586 | +void | |
1587 | +mm_audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) | |
1588 | +{ | |
1589 | + Buffer m; | |
1590 | + | |
1591 | + buffer_init(&m); | |
1592 | + buffer_put_int(&m, ctos); | |
1593 | + buffer_put_int64(&m, pid); | |
1594 | + buffer_put_int64(&m, uid); | |
1595 | + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SESSION_KEY_FREE, &m); | |
1596 | + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, | |
1597 | + &m); | |
1598 | + buffer_free(&m); | |
1599 | +} | |
1600 | + | |
1601 | +void | |
1602 | +mm_audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) | |
1603 | +{ | |
1604 | + Buffer m; | |
1605 | + | |
1606 | + buffer_init(&m); | |
1607 | + buffer_put_cstring(&m, fp); | |
1608 | + buffer_put_int64(&m, pid); | |
1609 | + buffer_put_int64(&m, uid); | |
1610 | + | |
1611 | + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, &m); | |
1612 | + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SERVER_KEY_FREE, | |
1613 | + &m); | |
1614 | + buffer_free(&m); | |
1615 | +} | |
1616 | +#endif /* SSH_AUDIT_EVENTS */ | |
1617 | diff -up openssh-6.8p1/monitor_wrap.h.audit openssh-6.8p1/monitor_wrap.h | |
1618 | --- openssh-6.8p1/monitor_wrap.h.audit 2015-03-20 13:41:15.048883853 +0100 | |
1619 | +++ openssh-6.8p1/monitor_wrap.h 2015-03-20 13:41:15.096883775 +0100 | |
1620 | @@ -52,7 +52,8 @@ int mm_key_allowed(enum mm_keytype, char | |
1621 | int mm_user_key_allowed(struct passwd *, Key *); | |
1622 | int mm_hostbased_key_allowed(struct passwd *, char *, char *, Key *); | |
1623 | int mm_auth_rhosts_rsa_key_allowed(struct passwd *, char *, char *, Key *); | |
1624 | -int mm_key_verify(Key *, u_char *, u_int, u_char *, u_int); | |
1625 | +int mm_hostbased_key_verify(Key *, u_char *, u_int, u_char *, u_int); | |
1626 | +int mm_user_key_verify(Key *, u_char *, u_int, u_char *, u_int); | |
1627 | int mm_auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **); | |
1628 | int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *); | |
1629 | BIGNUM *mm_auth_rsa_generate_challenge(Key *); | |
1630 | @@ -79,7 +80,12 @@ void mm_sshpam_free_ctx(void *); | |
1631 | #ifdef SSH_AUDIT_EVENTS | |
1632 | #include "audit.h" | |
1633 | void mm_audit_event(ssh_audit_event_t); | |
1634 | -void mm_audit_run_command(const char *); | |
1635 | +int mm_audit_run_command(const char *); | |
1636 | +void mm_audit_end_command(int, const char *); | |
1637 | +void mm_audit_unsupported_body(int); | |
1638 | +void mm_audit_kex_body(int, char *, char *, char *, char *, pid_t, uid_t); | |
1639 | +void mm_audit_session_key_free_body(int, pid_t, uid_t); | |
1640 | +void mm_audit_destroy_sensitive_data(const char *, pid_t, uid_t); | |
1641 | #endif | |
1642 | ||
1643 | struct Session; | |
1644 | diff -up openssh-6.8p1/packet.c.audit openssh-6.8p1/packet.c | |
1645 | --- openssh-6.8p1/packet.c.audit 2015-03-20 13:41:14.990883947 +0100 | |
1646 | +++ openssh-6.8p1/packet.c 2015-03-20 13:41:15.097883774 +0100 | |
1647 | @@ -67,6 +67,7 @@ | |
1648 | #include "key.h" /* typedefs XXX */ | |
1649 | ||
1650 | #include "xmalloc.h" | |
1651 | +#include "audit.h" | |
1652 | #include "crc32.h" | |
1653 | #include "deattack.h" | |
1654 | #include "compat.h" | |
1655 | @@ -448,6 +449,13 @@ ssh_packet_get_connection_out(struct ssh | |
1656 | return ssh->state->connection_out; | |
1657 | } | |
1658 | ||
1659 | +static int | |
1660 | +packet_state_has_keys (const struct session_state *state) | |
1661 | +{ | |
1662 | + return state != NULL && | |
1663 | + (state->newkeys[MODE_IN] != NULL || state->newkeys[MODE_OUT] != NULL); | |
1664 | +} | |
1665 | + | |
1666 | /* | |
1667 | * Returns the IP-address of the remote host as a string. The returned | |
1668 | * string must not be freed. | |
1669 | @@ -478,13 +486,6 @@ ssh_packet_close(struct ssh *ssh) | |
1670 | if (!state->initialized) | |
1671 | return; | |
1672 | state->initialized = 0; | |
1673 | - if (state->connection_in == state->connection_out) { | |
1674 | - shutdown(state->connection_out, SHUT_RDWR); | |
1675 | - close(state->connection_out); | |
1676 | - } else { | |
1677 | - close(state->connection_in); | |
1678 | - close(state->connection_out); | |
1679 | - } | |
1680 | sshbuf_free(state->input); | |
1681 | sshbuf_free(state->output); | |
1682 | sshbuf_free(state->outgoing_packet); | |
1683 | @@ -516,14 +517,24 @@ ssh_packet_close(struct ssh *ssh) | |
1684 | inflateEnd(stream); | |
1685 | } | |
1686 | } | |
1687 | - if ((r = cipher_cleanup(&state->send_context)) != 0) | |
1688 | - error("%s: cipher_cleanup failed: %s", __func__, ssh_err(r)); | |
1689 | - if ((r = cipher_cleanup(&state->receive_context)) != 0) | |
1690 | - error("%s: cipher_cleanup failed: %s", __func__, ssh_err(r)); | |
1691 | + if (packet_state_has_keys(state)) { | |
1692 | + if ((r = cipher_cleanup(&state->send_context)) != 0) | |
1693 | + error("%s: cipher_cleanup failed: %s", __func__, ssh_err(r)); | |
1694 | + if ((r = cipher_cleanup(&state->receive_context)) != 0) | |
1695 | + error("%s: cipher_cleanup failed: %s", __func__, ssh_err(r)); | |
1696 | + audit_session_key_free(2); | |
1697 | + } | |
1698 | if (ssh->remote_ipaddr) { | |
1699 | free(ssh->remote_ipaddr); | |
1700 | ssh->remote_ipaddr = NULL; | |
1701 | } | |
1702 | + if (state->connection_in == state->connection_out) { | |
1703 | + shutdown(state->connection_out, SHUT_RDWR); | |
1704 | + close(state->connection_out); | |
1705 | + } else { | |
1706 | + close(state->connection_in); | |
1707 | + close(state->connection_out); | |
1708 | + } | |
1709 | free(ssh->state); | |
1710 | ssh->state = NULL; | |
1711 | } | |
1712 | @@ -941,6 +952,7 @@ ssh_set_newkeys(struct ssh *ssh, int mod | |
1713 | } | |
1714 | if (state->newkeys[mode] != NULL) { | |
1715 | debug("set_newkeys: rekeying"); | |
1716 | + audit_session_key_free(mode); | |
1717 | if ((r = cipher_cleanup(cc)) != 0) | |
1718 | return r; | |
1719 | enc = &state->newkeys[mode]->enc; | |
1720 | @@ -2263,6 +2275,75 @@ ssh_packet_get_output(struct ssh *ssh) | |
1721 | return (void *)ssh->state->output; | |
1722 | } | |
1723 | ||
1724 | +static void | |
1725 | +newkeys_destroy_and_free(struct newkeys *newkeys) | |
1726 | +{ | |
1727 | + if (newkeys == NULL) | |
1728 | + return; | |
1729 | + | |
1730 | + free(newkeys->enc.name); | |
1731 | + | |
1732 | + if (newkeys->mac.enabled) { | |
1733 | + mac_clear(&newkeys->mac); | |
1734 | + free(newkeys->mac.name); | |
1735 | + } | |
1736 | + | |
1737 | + free(newkeys->comp.name); | |
1738 | + | |
1739 | + newkeys_destroy(newkeys); | |
1740 | + free(newkeys); | |
1741 | +} | |
1742 | + | |
1743 | +static void | |
1744 | +packet_destroy_state(struct session_state *state) | |
1745 | +{ | |
1746 | + if (state == NULL) | |
1747 | + return; | |
1748 | + | |
1749 | + cipher_cleanup(&state->receive_context); | |
1750 | + cipher_cleanup(&state->send_context); | |
1751 | + | |
1752 | + buffer_free(state->input); | |
1753 | + state->input = NULL; | |
1754 | + buffer_free(state->output); | |
1755 | + state->output = NULL; | |
1756 | + buffer_free(state->outgoing_packet); | |
1757 | + state->outgoing_packet = NULL; | |
1758 | + buffer_free(state->incoming_packet); | |
1759 | + state->incoming_packet = NULL; | |
1760 | + if( state->compression_buffer ) { | |
1761 | + buffer_free(state->compression_buffer); | |
1762 | + state->compression_buffer = NULL; | |
1763 | + } | |
1764 | + newkeys_destroy_and_free(state->newkeys[MODE_IN]); | |
1765 | + state->newkeys[MODE_IN] = NULL; | |
1766 | + newkeys_destroy_and_free(state->newkeys[MODE_OUT]); | |
1767 | + state->newkeys[MODE_OUT] = NULL; | |
1768 | + mac_destroy(state->packet_discard_mac); | |
1769 | +// TAILQ_HEAD(, packet) outgoing; | |
1770 | +// memset(state, 0, sizeof(state)); | |
1771 | +} | |
1772 | + | |
1773 | +void | |
1774 | +packet_destroy_all(int audit_it, int privsep) | |
1775 | +{ | |
1776 | + if (audit_it) | |
1777 | + audit_it = (active_state != NULL && packet_state_has_keys(active_state->state)) | |
1778 | + || (backup_state != NULL && packet_state_has_keys(backup_state->state)); | |
1779 | + if (active_state != NULL) | |
1780 | + packet_destroy_state(active_state->state); | |
1781 | + if (backup_state != NULL) | |
1782 | + packet_destroy_state(backup_state->state); | |
1783 | + if (audit_it) { | |
1784 | +#ifdef SSH_AUDIT_EVENTS | |
1785 | + if (privsep) | |
1786 | + audit_session_key_free(2); | |
1787 | + else | |
1788 | + audit_session_key_free_body(2, getpid(), getuid()); | |
1789 | +#endif | |
1790 | + } | |
1791 | +} | |
1792 | + | |
1793 | /* XXX TODO update roaming to new API (does not work anyway) */ | |
1794 | /* | |
1795 | * Save the state for the real connection, and use a separate state when | |
1796 | @@ -2272,18 +2373,12 @@ void | |
1797 | ssh_packet_backup_state(struct ssh *ssh, | |
1798 | struct ssh *backup_state) | |
1799 | { | |
1800 | - struct ssh *tmp; | |
1801 | - | |
1802 | close(ssh->state->connection_in); | |
1803 | ssh->state->connection_in = -1; | |
1804 | close(ssh->state->connection_out); | |
1805 | ssh->state->connection_out = -1; | |
1806 | - if (backup_state) | |
1807 | - tmp = backup_state; | |
1808 | - else | |
1809 | - tmp = ssh_alloc_session_state(); | |
1810 | backup_state = ssh; | |
1811 | - ssh = tmp; | |
1812 | + ssh = ssh_alloc_session_state(); | |
1813 | } | |
1814 | ||
1815 | /* XXX FIXME FIXME FIXME */ | |
1816 | @@ -2302,9 +2397,7 @@ ssh_packet_restore_state(struct ssh *ssh | |
1817 | backup_state = ssh; | |
1818 | ssh = tmp; | |
1819 | ssh->state->connection_in = backup_state->state->connection_in; | |
1820 | - backup_state->state->connection_in = -1; | |
1821 | ssh->state->connection_out = backup_state->state->connection_out; | |
1822 | - backup_state->state->connection_out = -1; | |
1823 | len = sshbuf_len(backup_state->state->input); | |
1824 | if (len > 0) { | |
1825 | if ((r = sshbuf_putb(ssh->state->input, | |
1826 | @@ -2313,6 +2406,11 @@ ssh_packet_restore_state(struct ssh *ssh | |
1827 | sshbuf_reset(backup_state->state->input); | |
1828 | add_recv_bytes(len); | |
1829 | } | |
1830 | + backup_state->state->connection_in = -1; | |
1831 | + backup_state->state->connection_out = -1; | |
1832 | + packet_destroy_state(backup_state->state); | |
1833 | + free(backup_state); | |
1834 | + backup_state = NULL; | |
1835 | } | |
1836 | ||
1837 | /* Reset after_authentication and reset compression in post-auth privsep */ | |
1838 | diff -up openssh-6.8p1/packet.h.audit openssh-6.8p1/packet.h | |
1839 | --- openssh-6.8p1/packet.h.audit 2015-03-17 06:49:20.000000000 +0100 | |
1840 | +++ openssh-6.8p1/packet.h 2015-03-20 13:41:15.097883774 +0100 | |
1841 | @@ -189,7 +189,7 @@ int sshpkt_get_end(struct ssh *ssh); | |
1842 | const u_char *sshpkt_ptr(struct ssh *, size_t *lenp); | |
1843 | ||
1844 | /* OLD API */ | |
1845 | -extern struct ssh *active_state; | |
1846 | +extern struct ssh *active_state, *backup_state; | |
1847 | #include "opacket.h" | |
1848 | ||
1849 | #if !defined(WITH_OPENSSL) | |
1850 | @@ -203,4 +203,5 @@ extern struct ssh *active_state; | |
1851 | # undef EC_POINT | |
1852 | #endif | |
1853 | ||
1854 | +void packet_destroy_all(int, int); | |
1855 | #endif /* PACKET_H */ | |
1856 | diff -up openssh-6.8p1/session.c.audit openssh-6.8p1/session.c | |
1857 | --- openssh-6.8p1/session.c.audit 2015-03-20 13:41:15.073883813 +0100 | |
1858 | +++ openssh-6.8p1/session.c 2015-03-20 13:41:15.097883774 +0100 | |
1859 | @@ -139,7 +139,7 @@ extern int log_stderr; | |
1860 | extern int debug_flag; | |
1861 | extern u_int utmp_len; | |
1862 | extern int startup_pipe; | |
1863 | -extern void destroy_sensitive_data(void); | |
1864 | +extern void destroy_sensitive_data(int); | |
1865 | extern Buffer loginmsg; | |
1866 | ||
1867 | /* original command from peer. */ | |
1868 | @@ -731,6 +731,14 @@ do_exec_pty(Session *s, const char *comm | |
1869 | /* Parent. Close the slave side of the pseudo tty. */ | |
1870 | close(ttyfd); | |
1871 | ||
1872 | +#ifndef HAVE_OSF_SIA | |
1873 | + /* do_login in the child did not affect state in this process, | |
1874 | + compensate. From an architectural standpoint, this is extremely | |
1875 | + ugly. */ | |
1876 | + if (!(options.use_login && command == NULL)) | |
1877 | + audit_count_session_open(); | |
1878 | +#endif | |
1879 | + | |
1880 | /* Enter interactive session. */ | |
1881 | s->ptymaster = ptymaster; | |
1882 | packet_set_interactive(1, | |
1883 | @@ -853,15 +861,19 @@ do_exec(Session *s, const char *command) | |
1884 | get_remote_port()); | |
1885 | ||
1886 | #ifdef SSH_AUDIT_EVENTS | |
1887 | + if (s->command != NULL || s->command_handle != -1) | |
1888 | + fatal("do_exec: command already set"); | |
1889 | if (command != NULL) | |
1890 | - PRIVSEP(audit_run_command(command)); | |
1891 | + s->command = xstrdup(command); | |
1892 | else if (s->ttyfd == -1) { | |
1893 | char *shell = s->pw->pw_shell; | |
1894 | ||
1895 | if (shell[0] == '\0') /* empty shell means /bin/sh */ | |
1896 | shell =_PATH_BSHELL; | |
1897 | - PRIVSEP(audit_run_command(shell)); | |
1898 | + s->command = xstrdup(shell); | |
1899 | } | |
1900 | + if (s->command != NULL && s->ptyfd == -1) | |
1901 | + s->command_handle = PRIVSEP(audit_run_command(s->command)); | |
1902 | #endif | |
1903 | if (s->ttyfd != -1) | |
1904 | ret = do_exec_pty(s, command); | |
1905 | @@ -1704,7 +1716,10 @@ do_child(Session *s, const char *command | |
1906 | int r = 0; | |
1907 | ||
1908 | /* remove hostkey from the child's memory */ | |
1909 | - destroy_sensitive_data(); | |
1910 | + destroy_sensitive_data(1); | |
1911 | + /* Don't audit this - both us and the parent would be talking to the | |
1912 | + monitor over a single socket, with no synchronization. */ | |
1913 | + packet_destroy_all(0, 1); | |
1914 | ||
1915 | /* Force a password change */ | |
1916 | if (s->authctxt->force_pwchange) { | |
1917 | @@ -1934,6 +1949,7 @@ session_unused(int id) | |
1918 | sessions[id].ttyfd = -1; | |
1919 | sessions[id].ptymaster = -1; | |
1920 | sessions[id].x11_chanids = NULL; | |
1921 | + sessions[id].command_handle = -1; | |
1922 | sessions[id].next_unused = sessions_first_unused; | |
1923 | sessions_first_unused = id; | |
1924 | } | |
1925 | @@ -2016,6 +2032,19 @@ session_open(Authctxt *authctxt, int cha | |
1926 | } | |
1927 | ||
1928 | Session * | |
1929 | +session_by_id(int id) | |
1930 | +{ | |
1931 | + if (id >= 0 && id < sessions_nalloc) { | |
1932 | + Session *s = &sessions[id]; | |
1933 | + if (s->used) | |
1934 | + return s; | |
1935 | + } | |
1936 | + debug("session_by_id: unknown id %d", id); | |
1937 | + session_dump(); | |
1938 | + return NULL; | |
1939 | +} | |
1940 | + | |
1941 | +Session * | |
1942 | session_by_tty(char *tty) | |
1943 | { | |
1944 | int i; | |
1945 | @@ -2532,6 +2561,32 @@ session_exit_message(Session *s, int sta | |
1946 | chan_write_failed(c); | |
1947 | } | |
1948 | ||
1949 | +#ifdef SSH_AUDIT_EVENTS | |
1950 | +void | |
1951 | +session_end_command2(Session *s) | |
1952 | +{ | |
1953 | + if (s->command != NULL) { | |
1954 | + if (s->command_handle != -1) | |
1955 | + audit_end_command(s->command_handle, s->command); | |
1956 | + free(s->command); | |
1957 | + s->command = NULL; | |
1958 | + s->command_handle = -1; | |
1959 | + } | |
1960 | +} | |
1961 | + | |
1962 | +static void | |
1963 | +session_end_command(Session *s) | |
1964 | +{ | |
1965 | + if (s->command != NULL) { | |
1966 | + if (s->command_handle != -1) | |
1967 | + PRIVSEP(audit_end_command(s->command_handle, s->command)); | |
1968 | + free(s->command); | |
1969 | + s->command = NULL; | |
1970 | + s->command_handle = -1; | |
1971 | + } | |
1972 | +} | |
1973 | +#endif | |
1974 | + | |
1975 | void | |
1976 | session_close(Session *s) | |
1977 | { | |
1978 | @@ -2540,6 +2593,10 @@ session_close(Session *s) | |
1979 | debug("session_close: session %d pid %ld", s->self, (long)s->pid); | |
1980 | if (s->ttyfd != -1) | |
1981 | session_pty_cleanup(s); | |
1982 | +#ifdef SSH_AUDIT_EVENTS | |
1983 | + if (s->command) | |
1984 | + session_end_command(s); | |
1985 | +#endif | |
1986 | free(s->term); | |
1987 | free(s->display); | |
1988 | free(s->x11_chanids); | |
1989 | @@ -2754,6 +2811,15 @@ do_authenticated2(Authctxt *authctxt) | |
1990 | server_loop2(authctxt); | |
1991 | } | |
1992 | ||
1993 | +static void | |
1994 | +do_cleanup_one_session(Session *s) | |
1995 | +{ | |
1996 | + session_pty_cleanup2(s); | |
1997 | +#ifdef SSH_AUDIT_EVENTS | |
1998 | + session_end_command2(s); | |
1999 | +#endif | |
2000 | +} | |
2001 | + | |
2002 | void | |
2003 | do_cleanup(Authctxt *authctxt) | |
2004 | { | |
2005 | @@ -2802,5 +2868,5 @@ do_cleanup(Authctxt *authctxt) | |
2006 | * or if running in monitor. | |
2007 | */ | |
2008 | if (!use_privsep || mm_is_monitor()) | |
2009 | - session_destroy_all(session_pty_cleanup2); | |
2010 | + session_destroy_all(do_cleanup_one_session); | |
2011 | } | |
2012 | diff -up openssh-6.8p1/session.h.audit openssh-6.8p1/session.h | |
2013 | --- openssh-6.8p1/session.h.audit 2015-03-17 06:49:20.000000000 +0100 | |
2014 | +++ openssh-6.8p1/session.h 2015-03-20 13:41:15.097883774 +0100 | |
2015 | @@ -61,6 +61,12 @@ struct Session { | |
2016 | char *name; | |
2017 | char *val; | |
2018 | } *env; | |
2019 | + | |
2020 | + /* exec */ | |
2021 | +#ifdef SSH_AUDIT_EVENTS | |
2022 | + int command_handle; | |
2023 | + char *command; | |
2024 | +#endif | |
2025 | }; | |
2026 | ||
2027 | void do_authenticated(Authctxt *); | |
2028 | @@ -73,8 +79,10 @@ void session_close_by_pid(pid_t, int); | |
2029 | void session_close_by_channel(int, void *); | |
2030 | void session_destroy_all(void (*)(Session *)); | |
2031 | void session_pty_cleanup2(Session *); | |
2032 | +void session_end_command2(Session *); | |
2033 | ||
2034 | Session *session_new(void); | |
2035 | +Session *session_by_id(int); | |
2036 | Session *session_by_tty(char *); | |
2037 | void session_close(Session *); | |
2038 | void do_setusercontext(struct passwd *); | |
2039 | diff -up openssh-6.8p1/sshd.c.audit openssh-6.8p1/sshd.c | |
2040 | --- openssh-6.8p1/sshd.c.audit 2015-03-20 13:41:15.083883796 +0100 | |
2041 | +++ openssh-6.8p1/sshd.c 2015-03-20 13:41:15.110883753 +0100 | |
2042 | @@ -121,6 +124,7 @@ | |
2043 | #endif | |
2044 | #include "monitor_wrap.h" | |
2045 | #include "roaming.h" | |
2046 | +#include "audit.h" | |
2047 | #include "ssh-sandbox.h" | |
2048 | #include "version.h" | |
2049 | #include "ssherr.h" | |
2050 | @@ -260,7 +264,7 @@ Buffer loginmsg; | |
2051 | struct passwd *privsep_pw = NULL; | |
2052 | ||
2053 | /* Prototypes for various functions defined later in this file. */ | |
2054 | -void destroy_sensitive_data(void); | |
2055 | +void destroy_sensitive_data(int); | |
2056 | void demote_sensitive_data(void); | |
2057 | ||
2058 | #ifdef WITH_SSH1 | |
2059 | @@ -281,6 +285,15 @@ close_listen_socks(void) | |
2060 | num_listen_socks = -1; | |
2061 | } | |
2062 | ||
2063 | +/* | |
2064 | + * Is this process listening for clients (i.e. not specific to any specific | |
2065 | + * client connection?) | |
2066 | + */ | |
2067 | +int listening_for_clients(void) | |
2068 | +{ | |
2069 | + return num_listen_socks > 0; | |
2070 | +} | |
2071 | + | |
2072 | static void | |
2073 | close_startup_pipes(void) | |
2074 | { | |
2075 | @@ -560,22 +573,45 @@ sshd_exchange_identification(int sock_in | |
2076 | } | |
2077 | } | |
2078 | ||
2079 | -/* Destroy the host and server keys. They will no longer be needed. */ | |
2080 | +/* | |
2081 | + * Destroy the host and server keys. They will no longer be needed. Careful, | |
2082 | + * this can be called from cleanup_exit() - i.e. from just about anywhere. | |
2083 | + */ | |
2084 | void | |
2085 | -destroy_sensitive_data(void) | |
2086 | +destroy_sensitive_data(int privsep) | |
2087 | { | |
2088 | int i; | |
2089 | + pid_t pid; | |
2090 | + uid_t uid; | |
2091 | ||
2092 | if (sensitive_data.server_key) { | |
2093 | key_free(sensitive_data.server_key); | |
2094 | sensitive_data.server_key = NULL; | |
2095 | } | |
2096 | + pid = getpid(); | |
2097 | + uid = getuid(); | |
2098 | for (i = 0; i < options.num_host_key_files; i++) { | |
2099 | if (sensitive_data.host_keys[i]) { | |
2100 | + char *fp; | |
2101 | + | |
2102 | + if (key_is_private(sensitive_data.host_keys[i])) | |
2103 | + fp = sshkey_fingerprint(sensitive_data.host_keys[i], options.fingerprint_hash, SSH_FP_HEX); | |
2104 | + else | |
2105 | + fp = NULL; | |
2106 | key_free(sensitive_data.host_keys[i]); | |
2107 | sensitive_data.host_keys[i] = NULL; | |
2108 | + if (fp != NULL) { | |
2109 | + if (privsep) | |
2110 | + PRIVSEP(audit_destroy_sensitive_data(fp, | |
2111 | + pid, uid)); | |
2112 | + else | |
2113 | + audit_destroy_sensitive_data(fp, | |
2114 | + pid, uid); | |
2115 | + free(fp); | |
2116 | + } | |
2117 | } | |
2118 | - if (sensitive_data.host_certificates[i]) { | |
2119 | + if (sensitive_data.host_certificates | |
2120 | + && sensitive_data.host_certificates[i]) { | |
2121 | key_free(sensitive_data.host_certificates[i]); | |
2122 | sensitive_data.host_certificates[i] = NULL; | |
2123 | } | |
2124 | @@ -589,6 +625,8 @@ void | |
2125 | demote_sensitive_data(void) | |
2126 | { | |
2127 | Key *tmp; | |
2128 | + pid_t pid; | |
2129 | + uid_t uid; | |
2130 | int i; | |
2131 | ||
2132 | if (sensitive_data.server_key) { | |
2133 | @@ -597,13 +635,25 @@ demote_sensitive_data(void) | |
2134 | sensitive_data.server_key = tmp; | |
2135 | } | |
2136 | ||
2137 | + pid = getpid(); | |
2138 | + uid = getuid(); | |
2139 | for (i = 0; i < options.num_host_key_files; i++) { | |
2140 | if (sensitive_data.host_keys[i]) { | |
2141 | + char *fp; | |
2142 | + | |
2143 | + if (key_is_private(sensitive_data.host_keys[i])) | |
2144 | + fp = sshkey_fingerprint(sensitive_data.host_keys[i], options.fingerprint_hash, SSH_FP_HEX); | |
2145 | + else | |
2146 | + fp = NULL; | |
2147 | tmp = key_demote(sensitive_data.host_keys[i]); | |
2148 | key_free(sensitive_data.host_keys[i]); | |
2149 | sensitive_data.host_keys[i] = tmp; | |
2150 | if (tmp->type == KEY_RSA1) | |
2151 | sensitive_data.ssh1_host_key = tmp; | |
2152 | + if (fp != NULL) { | |
2153 | + audit_destroy_sensitive_data(fp, pid, uid); | |
2154 | + free(fp); | |
2155 | + } | |
2156 | } | |
2157 | /* Certs do not need demotion */ | |
2158 | } | |
2159 | @@ -675,7 +725,7 @@ privsep_preauth(Authctxt *authctxt) | |
2160 | ||
2161 | if (use_privsep == PRIVSEP_ON) | |
2162 | box = ssh_sandbox_init(pmonitor); | |
2163 | - pid = fork(); | |
2164 | + pmonitor->m_pid = pid = fork(); | |
2165 | if (pid == -1) { | |
2166 | fatal("fork of unprivileged child failed"); | |
2167 | } else if (pid != 0) { | |
2168 | @@ -759,6 +811,12 @@ privsep_postauth(Authctxt *authctxt) | |
2169 | else if (pmonitor->m_pid != 0) { | |
2170 | verbose("User child is on pid %ld", (long)pmonitor->m_pid); | |
2171 | buffer_clear(&loginmsg); | |
2172 | + if (*pmonitor->m_pkex != NULL ){ | |
2173 | + newkeys_destroy((*pmonitor->m_pkex)->newkeys[MODE_OUT]); | |
2174 | + newkeys_destroy((*pmonitor->m_pkex)->newkeys[MODE_IN]); | |
2175 | + audit_session_key_free_body(2, getpid(), getuid()); | |
2176 | + packet_destroy_all(0, 0); | |
2177 | + } | |
2178 | monitor_child_postauth(pmonitor); | |
2179 | ||
2180 | /* NEVERREACHED */ | |
2181 | @@ -1286,6 +1341,7 @@ server_accept_loop(int *sock_in, int *so | |
2182 | if (received_sigterm) { | |
2183 | logit("Received signal %d; terminating.", | |
2184 | (int) received_sigterm); | |
2185 | + destroy_sensitive_data(0); | |
2186 | close_listen_socks(); | |
2187 | if (options.pid_file != NULL) | |
2188 | unlink(options.pid_file); | |
2189 | @@ -2242,6 +2321,7 @@ main(int ac, char **av) | |
2190 | */ | |
2191 | if (use_privsep) { | |
2192 | mm_send_keystate(pmonitor); | |
2193 | + packet_destroy_all(1, 1); | |
2194 | exit(0); | |
2195 | } | |
2196 | ||
2197 | @@ -2287,7 +2367,7 @@ main(int ac, char **av) | |
2198 | privsep_postauth(authctxt); | |
2199 | /* the monitor process [priv] will not return */ | |
2200 | if (!compat20) | |
2201 | - destroy_sensitive_data(); | |
2202 | + destroy_sensitive_data(0); | |
2203 | } | |
2204 | ||
2205 | packet_set_timeout(options.client_alive_interval, | |
2206 | @@ -2301,6 +2381,9 @@ main(int ac, char **av) | |
2207 | do_authenticated(authctxt); | |
2208 | ||
2209 | /* The connection has been terminated. */ | |
2210 | + packet_destroy_all(1, 1); | |
2211 | + destroy_sensitive_data(1); | |
2212 | + | |
2213 | packet_get_bytes(&ibytes, &obytes); | |
2214 | verbose("Transferred: sent %llu, received %llu bytes", | |
2215 | (unsigned long long)obytes, (unsigned long long)ibytes); | |
2216 | @@ -2461,6 +2544,10 @@ do_ssh1_kex(void) | |
2217 | if (cookie[i] != packet_get_char()) | |
2218 | packet_disconnect("IP Spoofing check bytes do not match."); | |
2219 | ||
2220 | +#ifdef SSH_AUDIT_EVENTS | |
2221 | + audit_kex(2, cipher_name(cipher_type), "crc", "none", "none"); | |
2222 | +#endif | |
2223 | + | |
2224 | debug("Encryption type: %.200s", cipher_name(cipher_type)); | |
2225 | ||
2226 | /* Get the encrypted integer. */ | |
2227 | @@ -2520,7 +2607,7 @@ do_ssh1_kex(void) | |
2228 | } | |
2229 | ||
2230 | /* Destroy the private and public keys. No longer. */ | |
2231 | - destroy_sensitive_data(); | |
2232 | + destroy_sensitive_data(1); | |
2233 | ||
2234 | if (use_privsep) | |
2235 | mm_ssh1_session_id(session_id); | |
2236 | @@ -2703,6 +2802,16 @@ do_ssh2_kex(void) | |
2237 | void | |
2238 | cleanup_exit(int i) | |
2239 | { | |
2240 | + static int in_cleanup = 0; | |
2241 | + int is_privsep_child; | |
2242 | + | |
2243 | + /* cleanup_exit can be called at the very least from the privsep | |
2244 | + wrappers used for auditing. Make sure we don't recurse | |
2245 | + indefinitely. */ | |
2246 | + if (in_cleanup) | |
2247 | + _exit(i); | |
2248 | + in_cleanup = 1; | |
2249 | + | |
2250 | if (the_authctxt) { | |
2251 | do_cleanup(the_authctxt); | |
2252 | if (use_privsep && privsep_is_preauth && | |
2253 | @@ -2714,9 +2823,14 @@ cleanup_exit(int i) | |
2254 | pmonitor->m_pid, strerror(errno)); | |
2255 | } | |
2256 | } | |
2257 | + is_privsep_child = use_privsep && pmonitor != NULL && pmonitor->m_pid == 0; | |
2258 | + if (sensitive_data.host_keys != NULL) | |
2259 | + destroy_sensitive_data(is_privsep_child); | |
2260 | + packet_destroy_all(1, is_privsep_child); | |
2261 | #ifdef SSH_AUDIT_EVENTS | |
2262 | /* done after do_cleanup so it can cancel the PAM auth 'thread' */ | |
2263 | - if (!use_privsep || mm_is_monitor()) | |
2264 | + if ((the_authctxt == NULL || !the_authctxt->authenticated) && | |
2265 | + (!use_privsep || mm_is_monitor())) | |
2266 | audit_event(SSH_CONNECTION_ABANDON); | |
2267 | #endif | |
2268 | _exit(i); | |
2269 | diff -up openssh-6.8p1/sshkey.c.audit openssh-6.8p1/sshkey.c | |
2270 | --- openssh-6.8p1/sshkey.c.audit 2015-03-17 06:49:20.000000000 +0100 | |
2271 | +++ openssh-6.8p1/sshkey.c 2015-03-20 13:41:15.111883751 +0100 | |
2272 | @@ -317,6 +319,33 @@ sshkey_type_is_valid_ca(int type) | |
2273 | } | |
2274 | ||
2275 | int | |
2276 | +sshkey_is_private(const struct sshkey *k) | |
2277 | +{ | |
2278 | + switch (k->type) { | |
2279 | + case KEY_RSA_CERT_V00: | |
2280 | + case KEY_RSA_CERT: | |
2281 | + case KEY_RSA1: | |
2282 | + case KEY_RSA: | |
2283 | + return k->rsa->d != NULL; | |
2284 | + case KEY_DSA_CERT_V00: | |
2285 | + case KEY_DSA_CERT: | |
2286 | + case KEY_DSA: | |
2287 | + return k->dsa->priv_key != NULL; | |
2288 | +#ifdef OPENSSL_HAS_ECC | |
2289 | + case KEY_ECDSA_CERT: | |
2290 | + case KEY_ECDSA: | |
2291 | + return EC_KEY_get0_private_key(k->ecdsa) != NULL; | |
2292 | +#endif | |
2293 | + case KEY_ED25519_CERT: | |
2294 | + case KEY_ED25519: | |
2295 | + return (k->ed25519_pk != NULL); | |
2296 | + default: | |
2297 | + /* fatal("key_is_private: bad key type %d", k->type); */ | |
2298 | + return 0; | |
2299 | + } | |
2300 | +} | |
2301 | + | |
2302 | +int | |
2303 | sshkey_is_cert(const struct sshkey *k) | |
2304 | { | |
2305 | if (k == NULL) | |
2306 | diff -up openssh-6.8p1/sshkey.h.audit openssh-6.8p1/sshkey.h | |
2307 | --- openssh-6.8p1/sshkey.h.audit 2015-03-17 06:49:20.000000000 +0100 | |
2308 | +++ openssh-6.8p1/sshkey.h 2015-03-20 13:41:15.098883772 +0100 | |
2309 | @@ -134,6 +134,7 @@ u_int sshkey_size(const struct sshkey | |
2310 | int sshkey_generate(int type, u_int bits, struct sshkey **keyp); | |
2311 | int sshkey_from_private(const struct sshkey *, struct sshkey **); | |
2312 | int sshkey_type_from_name(const char *); | |
2313 | +int sshkey_is_private(const struct sshkey *); | |
2314 | int sshkey_is_cert(const struct sshkey *); | |
2315 | int sshkey_type_is_cert(int); | |
2316 | int sshkey_type_plain(int); | |
2317 | diff -up openssh-6.8p1/sandbox-seccomp-filter.c.audit openssh-6.8p1/sandbox-seccomp-filter.c | |
2318 | --- openssh-6.8p1/sandbox-seccomp-filter.c.audit 2015-03-20 13:41:15.088883788 +0100 | |
2319 | +++ openssh-6.8p1/sandbox-seccomp-filter.c 2015-03-20 13:41:15.097883774 +0100 | |
2320 | @@ -110,6 +110,12 @@ static const struct sock_filter preauth_ | |
2321 | #ifdef __NR_time /* not defined on EABI ARM */ | |
2322 | SC_ALLOW(time), | |
2323 | #endif | |
2324 | +#ifdef SSH_AUDIT_EVENTS | |
2325 | + SC_ALLOW(getuid), | |
2326 | +#ifdef __NR_getuid32 /* not defined on x86_64 */ | |
2327 | + SC_ALLOW(getuid32), | |
2328 | +#endif | |
2329 | +#endif | |
2330 | SC_ALLOW(read), | |
2331 | SC_ALLOW(write), | |
2332 | SC_ALLOW(close), |