audit-linux.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. /*
  2. * Copyright 2010 Red Hat, Inc. All rights reserved.
  3. * Use is subject to license terms.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  15. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  16. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  17. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  18. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  19. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  20. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  21. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  23. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. *
  25. * Red Hat author: Jan F. Chadima <jchadima@redhat.com>
  26. */
  27. #include "includes.h"
  28. #if defined(USE_LINUX_AUDIT)
  29. #include <libaudit.h>
  30. #include <unistd.h>
  31. #include <string.h>
  32. #include "log.h"
  33. #include "audit.h"
  34. #include "sshkey.h"
  35. #include "hostfile.h"
  36. #include "auth.h"
  37. #include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */
  38. #include "servconf.h"
  39. #include "canohost.h"
  40. #include "packet.h"
  41. #include "cipher.h"
  42. #include "channels.h"
  43. #include "session.h"
  44. #define AUDIT_LOG_SIZE 256
  45. extern ServerOptions options;
  46. extern Authctxt *the_authctxt;
  47. extern u_int utmp_len;
  48. const char *audit_username(void);
  49. static void
  50. linux_audit_user_logxxx(int uid, const char *username,
  51. const char *ip, const char *ttyn, int success, int event)
  52. {
  53. int audit_fd, rc, saved_errno;
  54. if ((audit_fd = audit_open()) < 0) {
  55. if (errno == EINVAL || errno == EPROTONOSUPPORT ||
  56. errno == EAFNOSUPPORT)
  57. return; /* No audit support in kernel */
  58. else
  59. goto fatal_report; /* Must prevent login */
  60. }
  61. rc = audit_log_acct_message(audit_fd, event,
  62. NULL, "login", username ? username : "(unknown)",
  63. username == NULL ? uid : -1, NULL, ip, ttyn, success);
  64. saved_errno = errno;
  65. close(audit_fd);
  66. /*
  67. * Do not report error if the error is EPERM and sshd is run as non
  68. * root user.
  69. */
  70. if ((rc == -EPERM) && (geteuid() != 0))
  71. rc = 0;
  72. errno = saved_errno;
  73. if (rc < 0) {
  74. fatal_report:
  75. fatal("linux_audit_write_entry failed: %s", strerror(errno));
  76. }
  77. }
  78. static void
  79. linux_audit_user_auth(int uid, const char *username,
  80. const char *ip, const char *ttyn, int success, int event)
  81. {
  82. int audit_fd, rc, saved_errno;
  83. static const char *event_name[] = {
  84. "maxtries exceeded",
  85. "root denied",
  86. "success",
  87. "none",
  88. "password",
  89. "challenge-response",
  90. "pubkey",
  91. "hostbased",
  92. "gssapi",
  93. "invalid user",
  94. "nologin",
  95. "connection closed",
  96. "connection abandoned",
  97. "unknown"
  98. };
  99. audit_fd = audit_open();
  100. if (audit_fd < 0) {
  101. if (errno == EINVAL || errno == EPROTONOSUPPORT ||
  102. errno == EAFNOSUPPORT)
  103. return; /* No audit support in kernel */
  104. else
  105. goto fatal_report; /* Must prevent login */
  106. }
  107. if ((event < 0) || (event > SSH_AUDIT_UNKNOWN))
  108. event = SSH_AUDIT_UNKNOWN;
  109. rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH,
  110. NULL, event_name[event], username ? username : "(unknown)",
  111. username == NULL ? uid : -1, NULL, ip, ttyn, success);
  112. saved_errno = errno;
  113. close(audit_fd);
  114. /*
  115. * Do not report error if the error is EPERM and sshd is run as non
  116. * root user.
  117. */
  118. if ((rc == -EPERM) && (geteuid() != 0))
  119. rc = 0;
  120. errno = saved_errno;
  121. if (rc < 0) {
  122. fatal_report:
  123. fatal("linux_audit_write_entry failed: %s", strerror(errno));
  124. }
  125. }
  126. int
  127. audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv)
  128. {
  129. char buf[AUDIT_LOG_SIZE];
  130. int audit_fd, rc, saved_errno;
  131. audit_fd = audit_open();
  132. if (audit_fd < 0) {
  133. if (errno == EINVAL || errno == EPROTONOSUPPORT ||
  134. errno == EAFNOSUPPORT)
  135. return 1; /* No audit support in kernel */
  136. else
  137. return 0; /* Must prevent login */
  138. }
  139. snprintf(buf, sizeof(buf), "%s_auth grantors=auth-key", host_user ? "pubkey" : "hostbased");
  140. rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL,
  141. buf, audit_username(), -1, NULL, ssh_remote_ipaddr(ssh), NULL, rv);
  142. if ((rc < 0) && ((rc != -1) || (getuid() == 0)))
  143. goto out;
  144. snprintf(buf, sizeof(buf), "op=negotiate kind=auth-key fp=%s", fp);
  145. rc = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, buf, NULL,
  146. ssh_remote_ipaddr(ssh), NULL, rv);
  147. out:
  148. saved_errno = errno;
  149. audit_close(audit_fd);
  150. errno = saved_errno;
  151. /* do not report error if the error is EPERM and sshd is run as non root user */
  152. return (rc >= 0) || ((rc == -EPERM) && (getuid() != 0));
  153. }
  154. static int user_login_count = 0;
  155. /* Below is the sshd audit API code */
  156. void
  157. audit_connection_from(const char *host, int port)
  158. {
  159. /* not implemented */
  160. }
  161. int
  162. audit_run_command(struct ssh *ssh, const char *command)
  163. {
  164. if (!user_login_count++)
  165. linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL,
  166. ssh_remote_ipaddr(ssh),
  167. "ssh", 1, AUDIT_USER_LOGIN);
  168. linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL,
  169. ssh_remote_ipaddr(ssh),
  170. "ssh", 1, AUDIT_USER_START);
  171. return 0;
  172. }
  173. void
  174. audit_end_command(struct ssh *ssh, int handle, const char *command)
  175. {
  176. linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL,
  177. ssh_remote_ipaddr(ssh),
  178. "ssh", 1, AUDIT_USER_END);
  179. if (user_login_count && !--user_login_count)
  180. linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL,
  181. ssh_remote_ipaddr(ssh),
  182. "ssh", 1, AUDIT_USER_LOGOUT);
  183. }
  184. void
  185. audit_count_session_open(void)
  186. {
  187. user_login_count++;
  188. }
  189. void
  190. audit_session_open(struct logininfo *li)
  191. {
  192. if (!user_login_count++)
  193. linux_audit_user_logxxx(li->uid, NULL, li->hostname,
  194. li->line, 1, AUDIT_USER_LOGIN);
  195. linux_audit_user_logxxx(li->uid, NULL, li->hostname,
  196. li->line, 1, AUDIT_USER_START);
  197. }
  198. void
  199. audit_session_close(struct logininfo *li)
  200. {
  201. linux_audit_user_logxxx(li->uid, NULL, li->hostname,
  202. li->line, 1, AUDIT_USER_END);
  203. if (user_login_count && !--user_login_count)
  204. linux_audit_user_logxxx(li->uid, NULL, li->hostname,
  205. li->line, 1, AUDIT_USER_LOGOUT);
  206. }
  207. void
  208. audit_event(struct ssh *ssh, ssh_audit_event_t event)
  209. {
  210. switch(event) {
  211. case SSH_NOLOGIN:
  212. case SSH_LOGIN_ROOT_DENIED:
  213. linux_audit_user_auth(-1, audit_username(),
  214. ssh_remote_ipaddr(ssh), "ssh", 0, event);
  215. linux_audit_user_logxxx(-1, audit_username(),
  216. ssh_remote_ipaddr(ssh), "ssh", 0, AUDIT_USER_LOGIN);
  217. break;
  218. case SSH_AUTH_FAIL_PASSWD:
  219. if (options.use_pam)
  220. break;
  221. case SSH_LOGIN_EXCEED_MAXTRIES:
  222. case SSH_AUTH_FAIL_KBDINT:
  223. case SSH_AUTH_FAIL_PUBKEY:
  224. case SSH_AUTH_FAIL_HOSTBASED:
  225. case SSH_AUTH_FAIL_GSSAPI:
  226. linux_audit_user_auth(-1, audit_username(),
  227. ssh_remote_ipaddr(ssh), "ssh", 0, event);
  228. break;
  229. case SSH_CONNECTION_CLOSE:
  230. if (user_login_count) {
  231. while (user_login_count--)
  232. linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL,
  233. ssh_remote_ipaddr(ssh),
  234. "ssh", 1, AUDIT_USER_END);
  235. linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL,
  236. ssh_remote_ipaddr(ssh),
  237. "ssh", 1, AUDIT_USER_LOGOUT);
  238. }
  239. break;
  240. case SSH_CONNECTION_ABANDON:
  241. case SSH_INVALID_USER:
  242. linux_audit_user_logxxx(-1, audit_username(),
  243. ssh_remote_ipaddr(ssh), "ssh", 0, AUDIT_USER_LOGIN);
  244. break;
  245. default:
  246. debug("%s: unhandled event %d", __func__, event);
  247. break;
  248. }
  249. }
  250. void
  251. audit_unsupported_body(struct ssh *ssh, int what)
  252. {
  253. #ifdef AUDIT_CRYPTO_SESSION
  254. char buf[AUDIT_LOG_SIZE];
  255. const static char *name[] = { "cipher", "mac", "comp" };
  256. char *s;
  257. int audit_fd;
  258. snprintf(buf, sizeof(buf), "op=unsupported-%s direction=? cipher=? ksize=? rport=%d laddr=%s lport=%d ",
  259. name[what], ssh_remote_port(ssh), (s = get_local_ipaddr(ssh_packet_get_connection_in(ssh))),
  260. ssh_local_port(ssh));
  261. free(s);
  262. audit_fd = audit_open();
  263. if (audit_fd < 0)
  264. /* no problem, the next instruction will be fatal() */
  265. return;
  266. audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION,
  267. buf, NULL, ssh_remote_ipaddr(ssh), NULL, 0);
  268. audit_close(audit_fd);
  269. #endif
  270. }
  271. const static char *direction[] = { "from-server", "from-client", "both" };
  272. void
  273. audit_kex_body(struct ssh *ssh, int ctos, char *enc, char *mac, char *compress,
  274. char *pfs, pid_t pid, uid_t uid)
  275. {
  276. #ifdef AUDIT_CRYPTO_SESSION
  277. char buf[AUDIT_LOG_SIZE];
  278. int audit_fd, audit_ok;
  279. const struct sshcipher *cipher = cipher_by_name(enc);
  280. char *s;
  281. 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 ",
  282. direction[ctos], enc, cipher ? 8 * cipher->key_len : 0, mac, pfs,
  283. (intmax_t)pid, (intmax_t)uid,
  284. ssh_remote_port(ssh), (s = get_local_ipaddr(ssh_packet_get_connection_in(ssh))), ssh_local_port(ssh));
  285. free(s);
  286. audit_fd = audit_open();
  287. if (audit_fd < 0) {
  288. if (errno == EINVAL || errno == EPROTONOSUPPORT ||
  289. errno == EAFNOSUPPORT)
  290. return; /* No audit support in kernel */
  291. else
  292. fatal("cannot open audit"); /* Must prevent login */
  293. }
  294. audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION,
  295. buf, NULL, ssh_remote_ipaddr(ssh), NULL, 1);
  296. audit_close(audit_fd);
  297. /* do not abort if the error is EPERM and sshd is run as non root user */
  298. if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
  299. fatal("cannot write into audit"); /* Must prevent login */
  300. #endif
  301. }
  302. void
  303. audit_session_key_free_body(struct ssh *ssh, int ctos, pid_t pid, uid_t uid)
  304. {
  305. char buf[AUDIT_LOG_SIZE];
  306. int audit_fd, audit_ok;
  307. char *s;
  308. snprintf(buf, sizeof(buf), "op=destroy kind=session fp=? direction=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ",
  309. direction[ctos], (intmax_t)pid, (intmax_t)uid,
  310. ssh_remote_port(ssh),
  311. (s = get_local_ipaddr(ssh_packet_get_connection_in(ssh))),
  312. ssh_local_port(ssh));
  313. free(s);
  314. audit_fd = audit_open();
  315. if (audit_fd < 0) {
  316. if (errno != EINVAL && errno != EPROTONOSUPPORT &&
  317. errno != EAFNOSUPPORT)
  318. error("cannot open audit");
  319. return;
  320. }
  321. audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER,
  322. buf, NULL, ssh_remote_ipaddr(ssh), NULL, 1);
  323. audit_close(audit_fd);
  324. /* do not abort if the error is EPERM and sshd is run as non root user */
  325. if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
  326. error("cannot write into audit");
  327. }
  328. void
  329. audit_destroy_sensitive_data(struct ssh *ssh, const char *fp, pid_t pid, uid_t uid)
  330. {
  331. char buf[AUDIT_LOG_SIZE];
  332. int audit_fd, audit_ok;
  333. snprintf(buf, sizeof(buf), "op=destroy kind=server fp=%s direction=? spid=%jd suid=%jd ",
  334. fp, (intmax_t)pid, (intmax_t)uid);
  335. audit_fd = audit_open();
  336. if (audit_fd < 0) {
  337. if (errno != EINVAL && errno != EPROTONOSUPPORT &&
  338. errno != EAFNOSUPPORT)
  339. error("cannot open audit");
  340. return;
  341. }
  342. audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER,
  343. buf, NULL,
  344. listening_for_clients() ? NULL : ssh_remote_ipaddr(ssh),
  345. NULL, 1);
  346. audit_close(audit_fd);
  347. /* do not abort if the error is EPERM and sshd is run as non root user */
  348. if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
  349. error("cannot write into audit");
  350. }
  351. #endif /* USE_LINUX_AUDIT */