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