1/*
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 <endian.h>
19#include <errno.h>
20#include <limits.h>
21#include <stdarg.h>
22#include <stdlib.h>
23#include <sys/prctl.h>
24#include <sys/uio.h>
25#include <syslog.h>
26
27#include <private/android_filesystem_config.h>
28#include <private/android_logger.h>
29
30#include "libaudit.h"
31#include "LogAudit.h"
32#include "LogKlog.h"
33
34#define KMSG_PRIORITY(PRI)                          \
35    '<',                                            \
36    '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) / 10, \
37    '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) % 10, \
38    '>'
39
40LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg) :
41        SocketListener(getLogSocket(), false),
42        logbuf(buf),
43        reader(reader),
44        fdDmesg(fdDmesg),
45        initialized(false) {
46    static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
47        'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':',
48        ' ', 's', 't', 'a', 'r', 't', '\n' };
49    write(fdDmesg, auditd_message, sizeof(auditd_message));
50}
51
52bool LogAudit::onDataAvailable(SocketClient *cli) {
53    if (!initialized) {
54        prctl(PR_SET_NAME, "logd.auditd");
55        initialized = true;
56    }
57
58    struct audit_message rep;
59
60    rep.nlh.nlmsg_type = 0;
61    rep.nlh.nlmsg_len = 0;
62    rep.data[0] = '\0';
63
64    if (audit_get_reply(cli->getSocket(), &rep, GET_REPLY_BLOCKING, 0) < 0) {
65        SLOGE("Failed on audit_get_reply with error: %s", strerror(errno));
66        return false;
67    }
68
69    logPrint("type=%d %.*s",
70        rep.nlh.nlmsg_type, rep.nlh.nlmsg_len, rep.data);
71
72    return true;
73}
74
75int LogAudit::logPrint(const char *fmt, ...) {
76    if (fmt == NULL) {
77        return -EINVAL;
78    }
79
80    va_list args;
81
82    char *str = NULL;
83    va_start(args, fmt);
84    int rc = vasprintf(&str, fmt, args);
85    va_end(args);
86
87    if (rc < 0) {
88        return rc;
89    }
90
91    char *cp;
92    while ((cp = strstr(str, "  "))) {
93        memmove(cp, cp + 1, strlen(cp + 1) + 1);
94    }
95
96    bool info = strstr(str, " permissive=1") || strstr(str, " policy loaded ");
97    if ((fdDmesg >= 0) && initialized) {
98        struct iovec iov[3];
99        static const char log_info[] = { KMSG_PRIORITY(LOG_INFO) };
100        static const char log_warning[] = { KMSG_PRIORITY(LOG_WARNING) };
101
102        iov[0].iov_base = info ? const_cast<char *>(log_info)
103                               : const_cast<char *>(log_warning);
104        iov[0].iov_len = info ? sizeof(log_info) : sizeof(log_warning);
105        iov[1].iov_base = str;
106        iov[1].iov_len = strlen(str);
107        iov[2].iov_base = const_cast<char *>("\n");
108        iov[2].iov_len = 1;
109
110        writev(fdDmesg, iov, sizeof(iov) / sizeof(iov[0]));
111    }
112
113    pid_t pid = getpid();
114    pid_t tid = gettid();
115    uid_t uid = AID_LOGD;
116    log_time now;
117
118    static const char audit_str[] = " audit(";
119    char *timeptr = strstr(str, audit_str);
120    if (timeptr
121            && ((cp = now.strptime(timeptr + sizeof(audit_str) - 1, "%s.%q")))
122            && (*cp == ':')) {
123        memcpy(timeptr + sizeof(audit_str) - 1, "0.0", 3);
124        memmove(timeptr + sizeof(audit_str) - 1 + 3, cp, strlen(cp) + 1);
125        //
126        // We are either in 1970ish (MONOTONIC) or 2015+ish (REALTIME) so to
127        // differentiate without prejudice, we use 1980 to delineate, earlier
128        // is monotonic, later is real.
129        //
130#       define EPOCH_PLUS_10_YEARS (10 * 1461 / 4 * 24 * 60 * 60)
131        if (now.tv_sec < EPOCH_PLUS_10_YEARS) {
132            LogKlog::convertMonotonicToReal(now);
133        }
134    } else {
135        now.strptime("", ""); // side effect of setting CLOCK_REALTIME
136    }
137
138    static const char pid_str[] = " pid=";
139    char *pidptr = strstr(str, pid_str);
140    if (pidptr && isdigit(pidptr[sizeof(pid_str) - 1])) {
141        cp = pidptr + sizeof(pid_str) - 1;
142        pid = 0;
143        while (isdigit(*cp)) {
144            pid = (pid * 10) + (*cp - '0');
145            ++cp;
146        }
147        tid = pid;
148        logbuf->lock();
149        uid = logbuf->pidToUid(pid);
150        logbuf->unlock();
151        memmove(pidptr, cp, strlen(cp) + 1);
152    }
153
154    // log to events
155
156    size_t l = strlen(str);
157    size_t n = l + sizeof(android_log_event_string_t);
158
159    bool notify = false;
160
161    android_log_event_string_t *event = static_cast<android_log_event_string_t *>(malloc(n));
162    if (!event) {
163        rc = -ENOMEM;
164    } else {
165        event->header.tag = htole32(AUDITD_LOG_TAG);
166        event->type = EVENT_TYPE_STRING;
167        event->length = htole32(l);
168        memcpy(event->data, str, l);
169
170        rc = logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid,
171                         reinterpret_cast<char *>(event),
172                         (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
173        free(event);
174
175        if (rc >= 0) {
176            notify = true;
177        }
178    }
179
180    // log to main
181
182    static const char comm_str[] = " comm=\"";
183    const char *comm = strstr(str, comm_str);
184    const char *estr = str + strlen(str);
185    char *commfree = NULL;
186    if (comm) {
187        estr = comm;
188        comm += sizeof(comm_str) - 1;
189    } else if (pid == getpid()) {
190        pid = tid;
191        comm = "auditd";
192    } else {
193        logbuf->lock();
194        comm = commfree = logbuf->pidToName(pid);
195        logbuf->unlock();
196        if (!comm) {
197            comm = "unknown";
198        }
199    }
200
201    const char *ecomm = strchr(comm, '"');
202    if (ecomm) {
203        ++ecomm;
204        l = ecomm - comm;
205    } else {
206        l = strlen(comm) + 1;
207        ecomm = "";
208    }
209    n = (estr - str) + strlen(ecomm) + l + 2;
210
211    char *newstr = static_cast<char *>(malloc(n));
212    if (!newstr) {
213        rc = -ENOMEM;
214    } else {
215        *newstr = info ? ANDROID_LOG_INFO : ANDROID_LOG_WARN;
216        strlcpy(newstr + 1, comm, l);
217        strncpy(newstr + 1 + l, str, estr - str);
218        strcpy(newstr + 1 + l + (estr - str), ecomm);
219
220        rc = logbuf->log(LOG_ID_MAIN, now, uid, pid, tid, newstr,
221                         (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
222        free(newstr);
223
224        if (rc >= 0) {
225            notify = true;
226        }
227    }
228
229    free(commfree);
230    free(str);
231
232    if (notify) {
233        reader->notifyNewLog();
234        if (rc < 0) {
235            rc = n;
236        }
237    }
238
239    return rc;
240}
241
242int LogAudit::log(char *buf) {
243    char *audit = strstr(buf, " audit(");
244    if (!audit) {
245        return 0;
246    }
247
248    *audit = '\0';
249
250    int rc;
251    char *type = strstr(buf, "type=");
252    if (type) {
253        rc = logPrint("%s %s", type, audit + 1);
254    } else {
255        rc = logPrint("%s", audit + 1);
256    }
257    *audit = ' ';
258    return rc;
259}
260
261int LogAudit::getLogSocket() {
262    int fd = audit_open();
263    if (fd < 0) {
264        return fd;
265    }
266    if (audit_setup(fd, getpid()) < 0) {
267        audit_close(fd);
268        fd = -1;
269    }
270    return fd;
271}
272