2
* Copyright (c) 2009-2010 Todd C. Miller <Todd.Miller@courtesan.com>
4
* Permission to use, copy, modify, and distribute this software for any
5
* purpose with or without fee is hereby granted, provided that the above
6
* copyright notice and this permission notice appear in all copies.
8
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
#include <sys/types.h>
20
#include <sys/param.h>
31
#endif /* STDC_HEADERS */
34
#endif /* HAVE_STRING_H */
37
#endif /* HAVE_STRINGS_H */
40
#endif /* HAVE_UNISTD_H */
41
#if TIME_WITH_SYS_TIME
64
int len; /* buffer length (how much read in) */
65
int off; /* write position (how much already consumed) */
78
# define SESSID_MAX 2176782336U
80
# define SESSID_MAX (unsigned long)2176782336
83
static sigset_t ttyblock;
84
static struct timeval last_time;
85
static union io_fd io_fds[IOFD_MAX];
96
char pathbuf[PATH_MAX];
99
* Create _PATH_SUDO_IO_LOGDIR if it doesn't already exist.
101
if (stat(_PATH_SUDO_IO_LOGDIR, &sb) != 0) {
102
if (mkdir(_PATH_SUDO_IO_LOGDIR, S_IRWXU) != 0)
103
log_error(USE_ERRNO, "Can't mkdir %s", _PATH_SUDO_IO_LOGDIR);
104
} else if (!S_ISDIR(sb.st_mode)) {
105
log_error(0, "%s exists but is not a directory (0%o)",
106
_PATH_SUDO_IO_LOGDIR, (unsigned int) sb.st_mode);
112
len = snprintf(pathbuf, sizeof(pathbuf), "%s/seq", _PATH_SUDO_IO_LOGDIR);
113
if (len <= 0 || len >= sizeof(pathbuf)) {
114
errno = ENAMETOOLONG;
115
log_error(USE_ERRNO, "%s/seq", pathbuf);
117
fd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
119
log_error(USE_ERRNO, "cannot open %s", pathbuf);
120
lock_file(fd, SUDO_LOCK);
122
/* Read seq number (base 36). */
123
nread = read(fd, buf, sizeof(buf));
126
log_error(USE_ERRNO, "cannot read %s", pathbuf);
127
id = strtoul(buf, &ep, 36);
128
if (buf == ep || id >= SESSID_MAX)
129
log_error(0, "invalid sequence number %s", pathbuf);
134
* Convert id to a string and stash in sudo_user.sessid.
135
* Note that that least significant digits go at the end of the string.
137
for (i = 5; i >= 0; i--) {
140
buf[i] = ch < 10 ? ch + '0' : ch - 10 + 'A';
144
/* Stash id logging purposes */
145
memcpy(sudo_user.sessid, buf, 6);
146
sudo_user.sessid[6] = '\0';
148
/* Rewind and overwrite old seq file. */
149
if (lseek(fd, 0, SEEK_SET) == (off_t)-1 || write(fd, buf, 7) != 7)
150
log_error(USE_ERRNO, "Can't write to %s", pathbuf);
155
build_idpath(pathbuf, pathsize)
162
if (sudo_user.sessid[0] == '\0')
163
log_error(0, "tried to build a session id path without a session id");
166
* Path is of the form /var/log/sudo-session/00/00/01.
168
len = snprintf(pathbuf, pathsize, "%s/%c%c/%c%c/%c%c", _PATH_SUDO_IO_LOGDIR,
169
sudo_user.sessid[0], sudo_user.sessid[1], sudo_user.sessid[2],
170
sudo_user.sessid[3], sudo_user.sessid[4], sudo_user.sessid[5]);
171
if (len <= 0 && len >= pathsize) {
172
errno = ENAMETOOLONG;
173
log_error(USE_ERRNO, "%s/%s", _PATH_SUDO_IO_LOGDIR, sudo_user.sessid);
177
* Create the intermediate subdirs as needed.
179
for (i = 6; i > 0; i -= 3) {
180
pathbuf[len - i] = '\0';
181
if (stat(pathbuf, &sb) != 0) {
182
if (mkdir(pathbuf, S_IRWXU) != 0)
183
log_error(USE_ERRNO, "Can't mkdir %s", pathbuf);
184
} else if (!S_ISDIR(sb.st_mode)) {
185
log_error(0, "%s: %s", pathbuf, strerror(ENOTDIR));
187
pathbuf[len - i] = '/';
194
open_io_fd(pathbuf, len, suffix, docompress)
204
strlcat(pathbuf, suffix, PATH_MAX);
205
fd = open(pathbuf, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR);
207
fcntl(fd, F_SETFD, FD_CLOEXEC);
210
vfd = gzdopen(fd, "w");
213
vfd = fdopen(fd, "w");
221
char pathbuf[PATH_MAX];
225
if (!def_log_input && !def_log_output)
229
* Build a path containing the session id split into two-digit subdirs,
230
* so ID 000001 becomes /var/log/sudo-session/00/00/01.
232
len = build_idpath(pathbuf, sizeof(pathbuf));
236
if (mkdir(pathbuf, S_IRUSR|S_IWUSR|S_IXUSR) != 0)
237
log_error(USE_ERRNO, "Can't mkdir %s", pathbuf);
240
* We create 7 files: a log file, a timing file and 5 for input/output.
242
io_logfile = open_io_fd(pathbuf, len, "/log", FALSE);
243
if (io_logfile == NULL)
244
log_error(USE_ERRNO, "Can't create %s", pathbuf);
246
io_fds[IOFD_TIMING].v = open_io_fd(pathbuf, len, "/timing", def_compress_io);
247
if (io_fds[IOFD_TIMING].v == NULL)
248
log_error(USE_ERRNO, "Can't create %s", pathbuf);
251
io_fds[IOFD_TTYIN].v = open_io_fd(pathbuf, len, "/ttyin", def_compress_io);
252
if (io_fds[IOFD_TTYIN].v == NULL)
253
log_error(USE_ERRNO, "Can't create %s", pathbuf);
256
if (def_log_output) {
257
io_fds[IOFD_TTYOUT].v = open_io_fd(pathbuf, len, "/ttyout", def_compress_io);
258
if (io_fds[IOFD_TTYOUT].v == NULL)
259
log_error(USE_ERRNO, "Can't create %s", pathbuf);
263
io_fds[IOFD_STDIN].v = open_io_fd(pathbuf, len, "/stdin", def_compress_io);
264
if (io_fds[IOFD_STDIN].v == NULL)
265
log_error(USE_ERRNO, "Can't create %s", pathbuf);
268
if (def_log_output) {
269
io_fds[IOFD_STDOUT].v = open_io_fd(pathbuf, len, "/stdout", def_compress_io);
270
if (io_fds[IOFD_STDOUT].v == NULL)
271
log_error(USE_ERRNO, "Can't create %s", pathbuf);
274
if (def_log_output) {
275
io_fds[IOFD_STDERR].v = open_io_fd(pathbuf, len, "/stderr", def_compress_io);
276
if (io_fds[IOFD_STDERR].v == NULL)
277
log_error(USE_ERRNO, "Can't create %s", pathbuf);
280
/* So we can block tty-generated signals */
281
sigemptyset(&ttyblock);
282
sigaddset(&ttyblock, SIGINT);
283
sigaddset(&ttyblock, SIGQUIT);
284
sigaddset(&ttyblock, SIGTSTP);
285
sigaddset(&ttyblock, SIGTTIN);
286
sigaddset(&ttyblock, SIGTTOU);
288
gettimeofday(&last_time, NULL);
290
/* XXX - log more stuff? window size? environment? */
291
fprintf(io_logfile, "%ld:%s:%s:%s:%s\n", (long)last_time.tv_sec, user_name,
292
runas_pw->pw_name, runas_gr ? runas_gr->gr_name : "", user_tty);
293
fprintf(io_logfile, "%s\n", user_cwd);
294
fprintf(io_logfile, "%s%s%s\n", user_cmnd, user_args ? " " : "",
295
user_args ? user_args : "");
306
for (i = 0; i < IOFD_MAX; i++) {
307
if (io_fds[i].v == NULL)
311
gzclose(io_fds[i].g);
319
log_io(buf, len, idx)
324
struct timeval now, delay;
327
gettimeofday(&now, NULL);
329
sigprocmask(SIG_BLOCK, &ttyblock, &omask);
333
gzwrite(io_fds[idx].g, buf, len);
336
fwrite(buf, 1, len, io_fds[idx].f);
337
delay.tv_sec = now.tv_sec;
338
delay.tv_usec = now.tv_usec;
339
timevalsub(&delay, &last_time);
342
gzprintf(io_fds[IOFD_TIMING].g, "%d %f %d\n", idx,
343
delay.tv_sec + ((double)delay.tv_usec / 1000000), len);
346
fprintf(io_fds[IOFD_TIMING].f, "%d %f %d\n", idx,
347
delay.tv_sec + ((double)delay.tv_usec / 1000000), len);
348
last_time.tv_sec = now.tv_sec;
349
last_time.tv_usec = now.tv_usec;
351
sigprocmask(SIG_SETMASK, &omask, NULL);
361
if (!io_fds[IOFD_TTYIN].v)
363
return log_io(buf, len, IOFD_TTYIN);
371
if (!io_fds[IOFD_TTYOUT].v)
373
return log_io(buf, len, IOFD_TTYOUT);
381
if (!io_fds[IOFD_STDIN].v)
383
return log_io(buf, len, IOFD_STDIN);
391
if (!io_fds[IOFD_STDOUT].v)
393
return log_io(buf, len, IOFD_STDOUT);
401
if (!io_fds[IOFD_STDOUT].v)
403
return log_io(buf, len, IOFD_STDERR);