~ubuntu-branches/ubuntu/quantal/sudo/quantal

« back to all changes in this revision

Viewing changes to iolog.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2011-11-20 12:07:45 UTC
  • mfrom: (1.3.17 sid)
  • Revision ID: package-import@ubuntu.com-20111120120745-o3qpklobmygytndc
Tags: 1.8.3p1-1ubuntu1
* Merge from debian/testing, remaining changes:
  - debian/patches/keep_home_by_default.patch:
    + Set HOME in initial_keepenv_table. (rebased for 1.8.3p1)
  - debian/patches/enable_badpass.patch: turn on "mail_badpass" by default:
    + attempting sudo without knowing a login password is as bad as not
      being listed in the sudoers file, especially if getting the password
      wrong means doing the access-check-email-notification never happens
      (rebased for 1.8.3p1)
  - debian/rules:
    + compile with --without-lecture --with-tty-tickets (Ubuntu specific)
    + install man/man8/sudo_root.8 (Ubuntu specific)
    + install apport hooks
    + The ubuntu-sudo-as-admin-successful.patch was taken upstream by
      Debian however it requires a --enable-admin-flag configure flag to
      actually enable it.
  - debian/sudoers: 
    + grant admin group sudo access
  - debian/sudo-ldap.dirs, debian/sudo.dirs: 
    + add usr/share/apport/package-hooks
  - debian/sudo.preinst:
    + avoid conffile prompt by checking for known default /etc/sudoers
      and if found installing the correct default /etc/sudoers file

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (c) 2009-2010 Todd C. Miller <Todd.Miller@courtesan.com>
3
 
 *
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.
7
 
 *
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.
15
 
 */
16
 
 
17
 
#include <config.h>
18
 
 
19
 
#include <sys/types.h>
20
 
#include <sys/param.h>
21
 
#include <sys/stat.h>
22
 
#include <sys/time.h>
23
 
#include <stdio.h>
24
 
#ifdef STDC_HEADERS
25
 
# include <stdlib.h>
26
 
# include <stddef.h>
27
 
#else
28
 
# ifdef HAVE_STDLIB_H
29
 
#  include <stdlib.h>
30
 
# endif
31
 
#endif /* STDC_HEADERS */
32
 
#ifdef HAVE_STRING_H
33
 
# include <string.h>
34
 
#endif /* HAVE_STRING_H */
35
 
#ifdef HAVE_STRINGS_H
36
 
# include <strings.h>
37
 
#endif /* HAVE_STRINGS_H */
38
 
#ifdef HAVE_UNISTD_H
39
 
# include <unistd.h>
40
 
#endif /* HAVE_UNISTD_H */
41
 
#if TIME_WITH_SYS_TIME
42
 
# include <time.h>
43
 
#endif
44
 
#include <errno.h>
45
 
#include <fcntl.h>
46
 
#include <signal.h>
47
 
#include <pwd.h>
48
 
#include <grp.h>
49
 
#ifdef HAVE_ZLIB_H
50
 
# include <zlib.h>
51
 
#endif
52
 
 
53
 
#include "sudo.h"
54
 
 
55
 
union io_fd {
56
 
    FILE *f;
57
 
#ifdef HAVE_ZLIB_H
58
 
    gzFile g;
59
 
#endif
60
 
    void *v;
61
 
};
62
 
 
63
 
struct script_buf {
64
 
    int len; /* buffer length (how much read in) */
65
 
    int off; /* write position (how much already consumed) */
66
 
    char buf[16 * 1024];
67
 
};
68
 
 
69
 
#define IOFD_STDIN      0
70
 
#define IOFD_STDOUT     1
71
 
#define IOFD_STDERR     2
72
 
#define IOFD_TTYIN      3
73
 
#define IOFD_TTYOUT     4
74
 
#define IOFD_TIMING     5
75
 
#define IOFD_MAX        6
76
 
 
77
 
#ifdef __STDC__
78
 
# define SESSID_MAX     2176782336U
79
 
#else
80
 
# define SESSID_MAX     (unsigned long)2176782336
81
 
#endif
82
 
 
83
 
static sigset_t ttyblock;
84
 
static struct timeval last_time;
85
 
static union io_fd io_fds[IOFD_MAX];
86
 
 
87
 
void
88
 
io_nextid()
89
 
{
90
 
    struct stat sb;
91
 
    char buf[32], *ep;
92
 
    int fd, i, ch;
93
 
    unsigned long id = 0;
94
 
    int len;
95
 
    ssize_t nread;
96
 
    char pathbuf[PATH_MAX];
97
 
 
98
 
    /*
99
 
     * Create _PATH_SUDO_IO_LOGDIR if it doesn't already exist.
100
 
     */
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);
107
 
    }
108
 
 
109
 
    /*
110
 
     * Open sequence file
111
 
     */
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);
116
 
    }
117
 
    fd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
118
 
    if (fd == -1)
119
 
        log_error(USE_ERRNO, "cannot open %s", pathbuf);
120
 
    lock_file(fd, SUDO_LOCK);
121
 
 
122
 
    /* Read seq number (base 36). */
123
 
    nread = read(fd, buf, sizeof(buf));
124
 
    if (nread != 0) {
125
 
        if (nread == -1)
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);
130
 
    }
131
 
    id++;
132
 
 
133
 
    /*
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.
136
 
     */
137
 
    for (i = 5; i >= 0; i--) {
138
 
        ch = id % 36;
139
 
        id /= 36;
140
 
        buf[i] = ch < 10 ? ch + '0' : ch - 10 + 'A';
141
 
    }
142
 
    buf[6] = '\n';
143
 
 
144
 
    /* Stash id logging purposes */
145
 
    memcpy(sudo_user.sessid, buf, 6);
146
 
    sudo_user.sessid[6] = '\0';
147
 
 
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);
151
 
    close(fd);
152
 
}
153
 
 
154
 
static int
155
 
build_idpath(pathbuf, pathsize)
156
 
    char *pathbuf;
157
 
    size_t pathsize;
158
 
{
159
 
    struct stat sb;
160
 
    int i, len;
161
 
 
162
 
    if (sudo_user.sessid[0] == '\0')
163
 
        log_error(0, "tried to build a session id path without a session id");
164
 
 
165
 
    /*
166
 
     * Path is of the form /var/log/sudo-session/00/00/01.
167
 
     */
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);
174
 
    }
175
 
 
176
 
    /*
177
 
     * Create the intermediate subdirs as needed.
178
 
     */
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));
186
 
        }
187
 
        pathbuf[len - i] = '/';
188
 
    }
189
 
 
190
 
    return(len);
191
 
}
192
 
 
193
 
static void *
194
 
open_io_fd(pathbuf, len, suffix, docompress)
195
 
    char *pathbuf;
196
 
    int len;
197
 
    const char *suffix;
198
 
    int docompress;
199
 
{
200
 
    void *vfd = NULL;
201
 
    int fd;
202
 
 
203
 
    pathbuf[len] = '\0';
204
 
    strlcat(pathbuf, suffix, PATH_MAX);
205
 
    fd = open(pathbuf, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR);
206
 
    if (fd != -1) {
207
 
        fcntl(fd, F_SETFD, FD_CLOEXEC);
208
 
#ifdef HAVE_ZLIB_H
209
 
        if (docompress)
210
 
            vfd = gzdopen(fd, "w");
211
 
        else
212
 
#endif
213
 
            vfd = fdopen(fd, "w");
214
 
    }
215
 
    return vfd;
216
 
}
217
 
 
218
 
int
219
 
io_log_open()
220
 
{
221
 
    char pathbuf[PATH_MAX];
222
 
    FILE *io_logfile;
223
 
    int len;
224
 
 
225
 
    if (!def_log_input && !def_log_output)
226
 
        return FALSE;
227
 
 
228
 
    /*
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.
231
 
     */
232
 
    len = build_idpath(pathbuf, sizeof(pathbuf));
233
 
    if (len == -1)
234
 
        return -1;
235
 
 
236
 
    if (mkdir(pathbuf, S_IRUSR|S_IWUSR|S_IXUSR) != 0)
237
 
        log_error(USE_ERRNO, "Can't mkdir %s", pathbuf);
238
 
 
239
 
    /*
240
 
     * We create 7 files: a log file, a timing file and 5 for input/output.
241
 
     */
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);
245
 
 
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);
249
 
 
250
 
    if (def_log_input) {
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);
254
 
    }
255
 
 
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);
260
 
    }
261
 
 
262
 
    if (def_log_input) {
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);
266
 
    }
267
 
 
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);
272
 
    }
273
 
 
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);
278
 
    }
279
 
 
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);
287
 
 
288
 
    gettimeofday(&last_time, NULL);
289
 
 
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 : "");
296
 
    fclose(io_logfile);
297
 
 
298
 
    return TRUE;
299
 
}
300
 
 
301
 
void
302
 
io_log_close()
303
 
{
304
 
    int i;
305
 
 
306
 
    for (i = 0; i < IOFD_MAX; i++) {
307
 
        if (io_fds[i].v == NULL)
308
 
            continue;
309
 
#ifdef HAVE_ZLIB_H
310
 
        if (def_compress_io)
311
 
            gzclose(io_fds[i].g);
312
 
        else
313
 
#endif
314
 
            fclose(io_fds[i].f);
315
 
    }
316
 
}
317
 
 
318
 
static int
319
 
log_io(buf, len, idx)
320
 
    const char *buf;
321
 
    unsigned int len;
322
 
    int idx;
323
 
{
324
 
    struct timeval now, delay;
325
 
    sigset_t omask;
326
 
 
327
 
    gettimeofday(&now, NULL);
328
 
 
329
 
    sigprocmask(SIG_BLOCK, &ttyblock, &omask);
330
 
 
331
 
#ifdef HAVE_ZLIB_H
332
 
    if (def_compress_io)
333
 
        gzwrite(io_fds[idx].g, buf, len);
334
 
    else
335
 
#endif
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);
340
 
#ifdef HAVE_ZLIB_H
341
 
    if (def_compress_io)
342
 
        gzprintf(io_fds[IOFD_TIMING].g, "%d %f %d\n", idx,
343
 
            delay.tv_sec + ((double)delay.tv_usec / 1000000), len);
344
 
    else
345
 
#endif
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;
350
 
 
351
 
    sigprocmask(SIG_SETMASK, &omask, NULL);
352
 
 
353
 
    return TRUE;
354
 
}
355
 
 
356
 
int
357
 
log_ttyin(buf, len)
358
 
    const char *buf;
359
 
    unsigned int len;
360
 
{
361
 
    if (!io_fds[IOFD_TTYIN].v)
362
 
        return TRUE;
363
 
    return log_io(buf, len, IOFD_TTYIN);
364
 
}
365
 
 
366
 
int
367
 
log_ttyout(buf, len)
368
 
    const char *buf;
369
 
    unsigned int len;
370
 
{
371
 
    if (!io_fds[IOFD_TTYOUT].v)
372
 
        return TRUE;
373
 
    return log_io(buf, len, IOFD_TTYOUT);
374
 
}
375
 
 
376
 
int
377
 
log_stdin(buf, len)
378
 
    const char *buf;
379
 
    unsigned int len;
380
 
{
381
 
    if (!io_fds[IOFD_STDIN].v)
382
 
        return TRUE;
383
 
    return log_io(buf, len, IOFD_STDIN);
384
 
}
385
 
 
386
 
int
387
 
log_stdout(buf, len)
388
 
    const char *buf;
389
 
    unsigned int len;
390
 
{
391
 
    if (!io_fds[IOFD_STDOUT].v)
392
 
        return TRUE;
393
 
    return log_io(buf, len, IOFD_STDOUT);
394
 
}
395
 
 
396
 
int
397
 
log_stderr(buf, len)
398
 
    const char *buf;
399
 
    unsigned int len;
400
 
{
401
 
    if (!io_fds[IOFD_STDOUT].v)
402
 
        return TRUE;
403
 
    return log_io(buf, len, IOFD_STDERR);
404
 
}