blob: cc3e58329f3349e3e2662e3c9f11504dd93dcde2 [file] [log] [blame]
William Roberts29d238d2013-02-08 09:45:26 +09001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <ctype.h>
18#include <errno.h>
19#include <stdarg.h>
20#include <stdlib.h>
21#include <sys/klog.h>
22
23#include "libaudit.h"
24#include "LogAudit.h"
25
26LogAudit::LogAudit(LogBuffer *buf, LogReader *reader)
27 : SocketListener(getLogSocket(), false)
28 , logbuf(buf)
29 , reader(reader) {
30 logDmsg();
31}
32
33bool LogAudit::onDataAvailable(SocketClient *cli) {
34 struct audit_message rep;
35
36 if (audit_get_reply(cli->getSocket(), &rep, GET_REPLY_BLOCKING, 0) < 0) {
37 SLOGE("Failed on audit_get_reply with error: %s", strerror(errno));
38 return false;
39 }
40
41 logPrint("type=%d %.*s", rep.nlh.nlmsg_type, rep.nlh.nlmsg_len, rep.data);
42
43 return true;
44}
45
46#define AUDIT_LOG_ID LOG_ID_MAIN
47#define AUDIT_LOG_PRIO ANDROID_LOG_WARN
48
49int LogAudit::logPrint(const char *fmt, ...) {
50 if (fmt == NULL) {
51 return -EINVAL;
52 }
53
54 va_list args;
55
56 char *str = NULL;
57 va_start(args, fmt);
58 int rc = vasprintf(&str, fmt, args);
59 va_end(args);
60
61 if (rc < 0) {
62 return rc;
63 }
64
65 pid_t pid = getpid();
66 pid_t tid = gettid();
67 uid_t uid = getuid();
68 log_time now;
69
70 static const char audit_str[] = " audit(";
71 char *timeptr = strstr(str, audit_str);
72 char *cp;
73 if (timeptr
74 && ((cp = now.strptime(timeptr + sizeof(audit_str) - 1, "%s.%q")))
75 && (*cp == ':')) {
76 memcpy(timeptr + sizeof(audit_str) - 1, "0.0", 3);
77 strcpy(timeptr + sizeof(audit_str) - 1 + 3, cp);
78 } else {
79 now.strptime("", ""); // side effect of setting CLOCK_REALTIME
80 }
81
82 static const char pid_str[] = " pid=";
83 char *pidptr = strstr(str, pid_str);
84 if (pidptr && isdigit(pidptr[sizeof(pid_str) - 1])) {
85 cp = pidptr + sizeof(pid_str) - 1;
86 pid = 0;
87 while (isdigit(*cp)) {
88 pid = (pid * 10) + (*cp - '0');
89 ++cp;
90 }
91 tid = pid;
92 uid = logbuf->pidToUid(pid);
93 strcpy(pidptr, cp);
94 }
95
96 static const char comm_str[] = " comm=\"";
97 char *comm = strstr(str, comm_str);
98 if (comm) {
99 cp = comm;
100 comm += sizeof(comm_str) - 1;
101 char *ecomm = strchr(comm, '"');
102 if (ecomm) {
103 *ecomm = '\0';
104 }
105 comm = strdup(comm);
106 if (ecomm) {
107 strcpy(cp, ecomm + 1);
108 }
109 } else if (pid == getpid()) {
110 pid = tid;
111 comm = strdup("auditd");
112 } else if (!(comm = logbuf->pidToName(pid))) {
113 comm = strdup("unknown");
114 }
115
116 size_t l = strlen(comm) + 1;
117 size_t n = l + strlen(str) + 2;
118
119 char *newstr = reinterpret_cast<char *>(malloc(n));
120 if (!newstr) {
121 free(comm);
122 free(str);
123 return -ENOMEM;
124 }
125
126 *newstr = AUDIT_LOG_PRIO;
127 strcpy(newstr + 1, comm);
128 free(comm);
129 strcpy(newstr + 1 + l, str);
130 free(str);
131
132 unsigned short len = n; // cap to internal maximum
133 if (len != n) {
134 len = -1;
135 }
136 logbuf->log(AUDIT_LOG_ID, now, uid, pid, tid, newstr, len);
137 reader->notifyNewLog();
138
139 free(newstr);
140
141 return rc;
142}
143
144void LogAudit::logDmsg() {
145 int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
146 if (len <= 0) {
147 return;
148 }
149
150 len++;
151 char buf[len];
152
153 int rc = klogctl(KLOG_READ_ALL, buf, len);
154
155 buf[len - 1] = '\0';
156
157 for(char *tok = buf; (rc >= 0) && ((tok = strtok(tok, "\r\n"))); tok = NULL) {
158 char *audit = strstr(tok, " audit(");
159 if (!audit) {
160 continue;
161 }
162
163 *audit++ = '\0';
164
165 char *type = strstr(tok, "type=");
166 if (type) {
167 rc = logPrint("%s %s", type, audit);
168 } else {
169 rc = logPrint("%s", audit);
170 }
171 }
172}
173
174int LogAudit::getLogSocket() {
175 int fd = audit_open();
176 if (fd < 0) {
177 return fd;
178 }
179 if (audit_set_pid(fd, getpid(), WAIT_YES) < 0) {
180 audit_close(fd);
181 fd = -1;
182 }
183 return fd;
184}