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

« back to all changes in this revision

Viewing changes to src/utmp.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) 2011 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/time.h>
 
22
#include <sys/wait.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
# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
 
34
#  include <memory.h>
 
35
# endif
 
36
# include <string.h>
 
37
#endif /* HAVE_STRING_H */
 
38
#ifdef HAVE_STRINGS_H
 
39
# include <strings.h>
 
40
#endif /* HAVE_STRINGS_H */
 
41
#ifdef HAVE_UNISTD_H
 
42
# include <unistd.h>
 
43
#endif /* HAVE_UNISTD_H */
 
44
#if TIME_WITH_SYS_TIME
 
45
# include <time.h>
 
46
#endif
 
47
#ifdef HAVE_UTMPX_H
 
48
# include <utmpx.h>
 
49
#else
 
50
# include <utmp.h>
 
51
#endif /* HAVE_UTMPX_H */
 
52
#ifdef HAVE_GETTTYENT
 
53
# include <ttyent.h>
 
54
#endif
 
55
#include <fcntl.h>
 
56
 
 
57
#include "sudo.h"
 
58
#include "sudo_exec.h"
 
59
 
 
60
/*
 
61
 * Simplify handling of utmp vs. utmpx
 
62
 */
 
63
#if !defined(HAVE_GETUTXID) && defined(HAVE_GETUTID)
 
64
# define getutxline(u)  getutline(u)
 
65
# define pututxline(u)  pututline(u)
 
66
# define setutxent      setutent(u)
 
67
# define endutxent      endutent(u)
 
68
#endif /* !HAVE_GETUTXID && HAVE_GETUTID */
 
69
 
 
70
#ifdef HAVE_GETUTXID
 
71
typedef struct utmpx sudo_utmp_t;
 
72
#else
 
73
typedef struct utmp sudo_utmp_t;
 
74
/* Older systems have ut_name, not us_user */
 
75
# if !defined(HAVE_STRUCT_UTMP_UT_USER) && !defined(ut_user)
 
76
#  define ut_user ut_name
 
77
# endif
 
78
#endif
 
79
 
 
80
/* HP-UX has __e_termination and __e_exit, others lack the __ */
 
81
#if defined(HAVE_STRUCT_UTMPX_UT_EXIT_E_TERMINATION) || defined(HAVE_STRUCT_UTMP_UT_EXIT_E_TERMINATION)
 
82
# undef  __e_termination
 
83
# define __e_termination        e_termination
 
84
# undef  __e_exit
 
85
# define __e_exit               e_exit
 
86
#endif
 
87
 
 
88
#if defined(HAVE_GETUTXID) || defined(HAVE_GETUTID)
 
89
/*
 
90
 * Create ut_id from the new ut_line and the old ut_id.
 
91
 */
 
92
static void
 
93
utmp_setid(sudo_utmp_t *old, sudo_utmp_t *new)
 
94
{
 
95
    const char *line = new->ut_line;
 
96
    size_t idlen;
 
97
 
 
98
    /* Skip over "tty" in the id if old entry did too. */
 
99
    if (old != NULL) {
 
100
        if (strncmp(line, "tty", 3) == 0) {
 
101
            idlen = MIN(sizeof(old->ut_id), 3);
 
102
            if (strncmp(old->ut_id, "tty", idlen) != 0)
 
103
                line += 3;
 
104
        }
 
105
    }
 
106
    
 
107
    /* Store as much as will fit, skipping parts of the beginning as needed. */
 
108
    idlen = strlen(line);
 
109
    if (idlen > sizeof(new->ut_id)) {
 
110
        line += idlen - sizeof(new->ut_id);
 
111
        idlen = sizeof(new->ut_id);
 
112
    }
 
113
    strncpy(new->ut_id, line, idlen);
 
114
}
 
115
#endif /* HAVE_GETUTXID || HAVE_GETUTID */
 
116
 
 
117
/*
 
118
 * Store time in utmp structure.
 
119
 */
 
120
static void
 
121
utmp_settime(sudo_utmp_t *ut)
 
122
{
 
123
    struct timeval tv;
 
124
 
 
125
    gettimeofday(&tv, NULL);
 
126
 
 
127
#if defined(HAVE_STRUCT_UTMP_UT_TV) || defined(HAVE_STRUCT_UTMPX_UT_TV)
 
128
    ut->ut_tv.tv_sec = tv.tv_sec;
 
129
    ut->ut_tv.tv_usec = tv.tv_usec;
 
130
#else
 
131
    ut->ut_time = tv.tv_sec;
 
132
#endif
 
133
}
 
134
 
 
135
/*
 
136
 * Fill in a utmp entry, using an old entry as a template if there is one.
 
137
 */
 
138
static void
 
139
utmp_fill(const char *line, const char *user, sudo_utmp_t *ut_old,
 
140
    sudo_utmp_t *ut_new)
 
141
{
 
142
    if (ut_old == NULL) {
 
143
        memset(ut_new, 0, sizeof(*ut_new));
 
144
        if (user == NULL) {
 
145
            strncpy(ut_new->ut_user, user_details.username,
 
146
                sizeof(ut_new->ut_user));
 
147
        }
 
148
    } else if (ut_old != ut_new) {
 
149
        memcpy(ut_new, ut_old, sizeof(*ut_new));
 
150
    }
 
151
    if (user != NULL)
 
152
        strncpy(ut_new->ut_user, user, sizeof(ut_new->ut_user));
 
153
    strncpy(ut_new->ut_line, line, sizeof(ut_new->ut_line));
 
154
#if defined(HAVE_STRUCT_UTMPX_UT_ID) || defined(HAVE_STRUCT_UTMP_UT_ID)
 
155
    utmp_setid(ut_old, ut_new);
 
156
#endif
 
157
#if defined(HAVE_STRUCT_UTMPX_UT_PID) || defined(HAVE_STRUCT_UTMP_UT_PID)
 
158
    ut_new->ut_pid = getpid();
 
159
#endif
 
160
    utmp_settime(ut_new);
 
161
#if defined(HAVE_STRUCT_UTMPX_UT_TYPE) || defined(HAVE_STRUCT_UTMP_UT_TYPE)
 
162
    ut_new->ut_type = USER_PROCESS;
 
163
#endif
 
164
}
 
165
 
 
166
/*
 
167
 * There are two basic utmp file types:
 
168
 *
 
169
 *  POSIX:  sequential access with new entries appended to the end.
 
170
 *          Manipulated via {get,put}utent()/{get,put}getutxent().
 
171
 *
 
172
 *  Legacy: sparse file indexed by ttyslot() * sizeof(struct utmp)
 
173
 */
 
174
#if defined(HAVE_GETUTXID) || defined(HAVE_GETUTID)
 
175
int
 
176
utmp_login(const char *from_line, const char *to_line, int ttyfd,
 
177
    const char *user)
 
178
{
 
179
    sudo_utmp_t utbuf, *ut_old = NULL;
 
180
    int rval = FALSE;
 
181
 
 
182
    /* Strip off /dev/ prefix from line as needed. */
 
183
    if (strncmp(to_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
 
184
        to_line += sizeof(_PATH_DEV) - 1;
 
185
    setutxent();
 
186
    if (from_line != NULL) {
 
187
        if (strncmp(from_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
 
188
            from_line += sizeof(_PATH_DEV) - 1;
 
189
 
 
190
        /* Lookup old line. */
 
191
        memset(&utbuf, 0, sizeof(utbuf));
 
192
        strncpy(utbuf.ut_line, from_line, sizeof(utbuf.ut_line));
 
193
        ut_old = getutxline(&utbuf);
 
194
    }
 
195
    utmp_fill(to_line, user, ut_old, &utbuf);
 
196
    if (pututxline(&utbuf) != NULL)
 
197
        rval = TRUE;
 
198
    endutxent();
 
199
 
 
200
    return rval;
 
201
}
 
202
 
 
203
int
 
204
utmp_logout(const char *line, int status)
 
205
{
 
206
    int rval = FALSE;
 
207
    sudo_utmp_t *ut, utbuf;
 
208
 
 
209
    /* Strip off /dev/ prefix from line as needed. */
 
210
    if (strncmp(line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
 
211
        line += sizeof(_PATH_DEV) - 1;
 
212
   
 
213
    memset(&utbuf, 0, sizeof(utbuf));
 
214
    strncpy(utbuf.ut_line, line, sizeof(utbuf.ut_line));
 
215
    if ((ut = getutxline(&utbuf)) != NULL) {
 
216
        memset(ut->ut_user, 0, sizeof(ut->ut_user));
 
217
# if defined(HAVE_STRUCT_UTMPX_UT_TYPE) || defined(HAVE_STRUCT_UTMP_UT_TYPE)
 
218
        ut->ut_type = DEAD_PROCESS;
 
219
# endif
 
220
# if defined(HAVE_STRUCT_UTMPX_UT_EXIT) || defined(HAVE_STRUCT_UTMP_UT_EXIT)
 
221
        ut->ut_exit.__e_exit = WEXITSTATUS(status);
 
222
        ut->ut_exit.__e_termination = WIFEXITED(status) ? WEXITSTATUS(status) : 0;
 
223
# endif
 
224
        utmp_settime(ut);
 
225
        if (pututxline(ut) != NULL)
 
226
            rval = TRUE;
 
227
    }
 
228
    return rval;
 
229
}
 
230
 
 
231
#else /* !HAVE_GETUTXID && !HAVE_GETUTID */
 
232
 
 
233
/*
 
234
 * Find the slot for the specified line (tty name and file descriptor).
 
235
 * Returns a slot suitable for seeking into utmp on success or <= 0 on error.
 
236
 * If getttyent() is available we can use that to compute the slot.
 
237
 */
 
238
# ifdef HAVE_GETTTYENT
 
239
static int
 
240
utmp_slot(const char *line, int ttyfd)
 
241
{
 
242
    int slot = 1;
 
243
    struct ttyent *tty;
 
244
 
 
245
    setttyent();
 
246
    while ((tty = getttyent()) != NULL) {
 
247
        if (strcmp(line, tty->ty_name) == 0)
 
248
            break;
 
249
        slot++;
 
250
    }
 
251
    endttyent();
 
252
    return tty ? slot : 0;
 
253
}
 
254
# else
 
255
static int
 
256
utmp_slot(const char *line, int ttyfd)
 
257
{
 
258
    int sfd, slot;
 
259
 
 
260
    /*
 
261
     * Temporarily point stdin to the tty since ttyslot()
 
262
     * doesn't take an argument.
 
263
     */
 
264
    if ((sfd = dup(STDIN_FILENO)) == -1)
 
265
        error(1, _("unable to save stdin"));
 
266
    if (dup2(ttyfd, STDIN_FILENO) == -1)
 
267
        error(1, _("unable to dup2 stdin"));
 
268
    slot = ttyslot();
 
269
    if (dup2(sfd, STDIN_FILENO) == -1)
 
270
        error(1, _("unable to restore stdin"));
 
271
    close(sfd);
 
272
 
 
273
    return slot;
 
274
}
 
275
# endif /* HAVE_GETTTYENT */
 
276
 
 
277
int
 
278
utmp_login(const char *from_line, const char *to_line, int ttyfd,
 
279
    const char *user)
 
280
{
 
281
    sudo_utmp_t utbuf, *ut_old = NULL;
 
282
    int slot, rval = FALSE;
 
283
    FILE *fp;
 
284
 
 
285
    /* Strip off /dev/ prefix from line as needed. */
 
286
    if (strncmp(to_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
 
287
        to_line += sizeof(_PATH_DEV) - 1;
 
288
 
 
289
    /* Find slot for new entry. */
 
290
    slot = utmp_slot(to_line, ttyfd);
 
291
    if (slot <= 0)
 
292
        goto done;
 
293
 
 
294
    if ((fp = fopen(_PATH_UTMP, "r+")) == NULL)
 
295
        goto done;
 
296
 
 
297
    if (from_line != NULL) {
 
298
        if (strncmp(from_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
 
299
            from_line += sizeof(_PATH_DEV) - 1;
 
300
 
 
301
        /* Lookup old line. */
 
302
        while (fread(&utbuf, sizeof(utbuf), 1, fp) == 1) {
 
303
# ifdef HAVE_STRUCT_UTMP_UT_ID
 
304
            if (utbuf.ut_type != LOGIN_PROCESS && utbuf.ut_type != USER_PROCESS)
 
305
                continue;
 
306
# endif
 
307
            if (utbuf.ut_user[0] &&
 
308
                !strncmp(utbuf.ut_line, from_line, sizeof(utbuf.ut_line))) {
 
309
                ut_old = &utbuf;
 
310
                break;
 
311
            }
 
312
        }
 
313
    }
 
314
    utmp_fill(to_line, user, ut_old, &utbuf);
 
315
    if (fseek(fp, slot * (long)sizeof(utbuf), SEEK_SET) == 0) {
 
316
        if (fwrite(&utbuf, sizeof(utbuf), 1, fp) == 1)
 
317
            rval = TRUE;
 
318
    }
 
319
    fclose(fp);
 
320
 
 
321
done:
 
322
    return rval;
 
323
}
 
324
 
 
325
int
 
326
utmp_logout(const char *line, int status)
 
327
{
 
328
    sudo_utmp_t utbuf;
 
329
    int rval = FALSE;
 
330
    FILE *fp;
 
331
 
 
332
    if ((fp = fopen(_PATH_UTMP, "r+")) == NULL)
 
333
        return rval;
 
334
 
 
335
    /* Strip off /dev/ prefix from line as needed. */
 
336
    if (strncmp(line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
 
337
        line += sizeof(_PATH_DEV) - 1;
 
338
   
 
339
    while (fread(&utbuf, sizeof(utbuf), 1, fp) == 1) {
 
340
        if (!strncmp(utbuf.ut_line, line, sizeof(utbuf.ut_line))) {
 
341
            memset(utbuf.ut_user, 0, sizeof(utbuf.ut_user));
 
342
# if defined(HAVE_STRUCT_UTMP_UT_TYPE)
 
343
            utbuf.ut_type = DEAD_PROCESS;
 
344
# endif
 
345
            utmp_settime(&utbuf);
 
346
            /* Back up and overwrite record. */
 
347
            if (fseek(fp, 0L - (long)sizeof(utbuf), SEEK_CUR) == 0) {
 
348
                if (fwrite(&utbuf, sizeof(utbuf), 1, fp) == 1)
 
349
                    rval = TRUE;
 
350
            }
 
351
            break;
 
352
        }
 
353
    }
 
354
    fclose(fp);
 
355
 
 
356
    return rval;
 
357
}
 
358
#endif /* HAVE_GETUTXID || HAVE_GETUTID */