1 /*--------------------------------*-C-*---------------------------------*
2  * File:	utmp.c
3  *----------------------------------------------------------------------*
4  * Copyright 1997,1998 Geoff Wing <gcw@pobox.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *----------------------------------------------------------------------*/
20 /*----------------------------------------------------------------------*
21  * Originally written:
22  *    1992      John Bovey <jdb@ukc.ac.uk>
23  * Modifications:
24  *    1993      lipka
25  *    1993      Brian Stempien <stempien@cs.wmich.edu>
26  *    1995      Raul Garcia Garcia <rgg@tid.es>
27  *    1995      Piet W. Plomp <piet@idefix.icce.rug.nl>
28  *    1997      Raul Garcia Garcia <rgg@tid.es>
29  *    1997,1998 Geoff Wing <mason@primenet.com.au>
30  *----------------------------------------------------------------------*/
31 /*----------------------------------------------------------------------*
32  * Public:
33  *	extern void cleanutent (void);
34  *	extern void makeutent (const char * pty, const char * hostname);
35  *
36  * Private:
37  *	write_utmp ();
38  *	update_wtmp ();
39  *----------------------------------------------------------------------*/
40 
41 #ifndef lint
42 static const char rcsid[] = "$Id: utmp.c,v 1.1.1.1 2004/11/10 17:21:52 sasha Exp $";
43 #endif
44 
45 #include "rxvt.h"		/* NECESSARY */
46 
47 /*
48  * HAVE_SETUTENT corresponds to SYSV-style utmp support.
49  * Without it corresponds to using BSD utmp support.
50  * SYSV-style utmp support is further divided in normal utmp support
51  * and utmpx support (Solaris 2.x) by HAVE_UTMPX_H
52  */
53 
54 /*
55  * update wtmp entries - only for SYSV style UTMP systems
56  */
57 #ifdef UTMP_SUPPORT
58 static char     ut_id[5];	/* remember if entry to utmp made */
59 # ifndef USE_SYSV_UTMP
60 static int      utmp_pos;	/* BSD position of utmp-stamp */
61 # endif
62 #endif
63 
64 /* ------------------------------------------------------------------------- */
65 #ifndef HAVE_UTMPX_H		/* supposedly we have updwtmpx ? */
66 #ifdef WTMP_SUPPORT
67 /* PROTO */
68 void
rxvt_update_wtmp(char * fname,struct utmp * putmp)69 rxvt_update_wtmp(char *fname, struct utmp *putmp)
70 {
71     int             fd, retry = 10;	/* 10 attempts at locking */
72     struct flock    lck;	/* fcntl locking scheme */
73 
74     if ((fd = open(fname, O_WRONLY | O_APPEND, 0)) < 0)
75 	return;
76 
77     lck.l_whence = SEEK_END;	/* start lock at current eof */
78     lck.l_len = 0;		/* end at ``largest possible eof'' */
79     lck.l_start = 0;
80     lck.l_type = F_WRLCK;	/* we want a write lock */
81 
82     while (retry--)
83     /* attempt lock with F_SETLK - F_SETLKW would cause a deadlock! */
84 	if ((fcntl(fd, F_SETLK, &lck) < 0) && errno != EACCESS) {
85 	    close(fd);
86 	    return;		/* failed for unknown reason: give up */
87 	}
88     write(fd, putmp, sizeof(struct utmp));
89 
90 /* unlocking the file */
91     lck.l_type = F_UNLCK;
92     fcntl(fd, F_SETLK, &lck);
93 
94     close(fd);
95 }
96 #endif				/* WTMP_SUPPORT */
97 #endif				/* !HAVE_UTMPX_H */
98 /* ------------------------------------------------------------------------- */
99 #ifdef UTMP_SUPPORT
100 /*
101  * make a utmp entry
102  */
103 /* PROTO */
104 void
makeutent(const char * pty,const char * hostname)105 makeutent(const char *pty, const char *hostname)
106 {
107 
108     struct passwd  *pwent = getpwuid(getuid());
109     UTMP	    utmp;
110 
111 #ifndef USE_SYSV_UTMP
112 /*
113  * BSD style utmp entry
114  *      ut_line, ut_name, ut_host, ut_time
115  */
116     int             i;
117     FILE           *fd0, *fd1;
118     char            buf[256], name[256];
119 
120 #else
121 /*
122  * SYSV style utmp entry
123  *      ut_user, ut_id, ut_line, ut_pid, ut_type, ut_exit, ut_time
124  */
125 #ifndef linux
126     char           *colon;
127 #endif
128 
129 #endif				/* !USE_SYSV_UTMP */
130 
131 /* BSD naming is of the form /dev/tty?? or /dev/pty?? */
132 
133     MEMSET(&utmp, 0, sizeof(UTMP));
134     if (!strncmp(pty, "/dev/", 5))
135 	pty += 5;		/* skip /dev/ prefix */
136     if (!strncmp(pty, "pty", 3) || !strncmp(pty, "tty", 3))
137 	STRNCPY(ut_id, (pty + 3), sizeof(ut_id));
138     else
139 #ifndef USE_SYSV_UTMP
140     {
141 	print_error("can't parse tty name \"%s\"", pty);
142 	ut_id[0] = '\0';	/* entry not made */
143 	return;
144     }
145 
146     STRNCPY(utmp.ut_line, pty, sizeof(utmp.ut_line));
147     STRNCPY(utmp.ut_name, (pwent && pwent->pw_name) ? pwent->pw_name : "?",
148 	    sizeof(utmp.ut_name));
149     STRNCPY(utmp.ut_host, hostname, sizeof(utmp.ut_host));
150     utmp.ut_time = time(NULL);
151 
152     if ((fd0 = fopen(UTMP_FILENAME, "r+")) == NULL)
153 	ut_id[0] = '\0';	/* entry not made */
154     else {
155 	utmp_pos = -1;
156 	if ((fd1 = fopen(TTYTAB_FILENAME, "r")) != NULL) {
157 	    for (i = 1; (fgets(buf, sizeof(buf), fd1) != NULL); i++) {
158 		if (*buf == '#' || sscanf(buf, "%s", name) != 1)
159 		    continue;
160 		if (!strcmp(utmp.ut_line, name)) {
161 		    fclose(fd1);
162 		    utmp_pos = i * sizeof(struct utmp);
163 
164 		    break;
165 		}
166 	    }
167 	    fclose(fd1);
168 	}
169 	if (utmp_pos < 0)
170 	    ut_id[0] = '\0';	/* entry not made */
171 	else {
172 	    fseek(fd0, utmp_pos, 0);
173 	    fwrite(&utmp, sizeof(UTMP), 1, fd0);
174 	}
175 	fclose(fd0);
176     }
177 
178 #else				/* USE_SYSV_UTMP */
179     {
180 	int             n;
181 
182 	if (sscanf(pty, "pts/%d", &n) == 1)
183 	    sprintf(ut_id, "vt%02x", (n % 256));	/* sysv naming */
184 	else {
185 	    print_error("can't parse tty name \"%s\"", pty);
186 	    ut_id[0] = '\0';	/* entry not made */
187 	    return;
188 	}
189     }
190 
191     utmpname(UTMP_FILENAME);
192 
193     setutent();			/* XXX: should be unnecessaray */
194 
195     STRNCPY(utmp.ut_id, ut_id, sizeof(utmp.ut_id));
196     utmp.ut_type = DEAD_PROCESS;
197     (void)getutid(&utmp);	/* position to entry in utmp file */
198 
199 /* set up the new entry */
200     utmp.ut_type = USER_PROCESS;
201 #ifndef linux
202     utmp.ut_exit.e_exit = 2;
203 #endif
204     STRNCPY(utmp.ut_user, (pwent && pwent->pw_name) ? pwent->pw_name : "?",
205 	    sizeof(utmp.ut_user));
206     STRNCPY(utmp.ut_id, ut_id, sizeof(utmp.ut_id));
207     STRNCPY(utmp.ut_line, pty, sizeof(utmp.ut_line));
208 
209 #ifdef HAVE_UTMP_HOST
210     STRNCPY(utmp.ut_host, hostname, sizeof(utmp.ut_host));
211 #ifndef linux
212     if ((colon = strrchr(utmp.ut_host, ':')) != NULL)
213 	*colon = '\0';
214 #endif
215 #endif				/* HAVE_UTMP_HOST */
216 
217 /* ut_name is normally the same as ut_user, but .... */
218     STRNCPY(utmp.ut_name, (pwent && pwent->pw_name) ? pwent->pw_name : "?",
219 	    sizeof(utmp.ut_name));
220 
221     utmp.ut_pid = getpid();
222 
223 #ifdef HAVE_UTMPX_H
224     utmp.ut_session = getsid(0);
225     utmp.ut_tv.tv_sec = time(NULL);
226     utmp.ut_tv.tv_usec = 0;
227 #else
228     utmp.ut_time = time(NULL);
229 #endif				/* HAVE_UTMPX_H */
230 
231     pututline(&utmp);
232 
233 #ifdef WTMP_SUPPORT
234     update_wtmp(WTMP_FILENAME, &utmp);
235 #endif
236 
237     endutent();			/* close the file */
238 #endif				/* !USE_SYSV_UTMP */
239 }
240 #endif				/* UTMP_SUPPORT */
241 
242 /* ------------------------------------------------------------------------- */
243 #ifdef UTMP_SUPPORT
244 /*
245  * remove a utmp entry
246  */
247 /* PROTO */
248 void
cleanutent(void)249 cleanutent(void)
250 {
251     UTMP            utmp;
252 
253 #ifndef USE_SYSV_UTMP
254     FILE           *fd;
255 
256     if (ut_id[0] && ((fd = fopen(UTMP_FILENAME, "r+")) != NULL)) {
257 	MEMSET(&utmp, 0, sizeof(struct utmp));
258 
259 	fseek(fd, utmp_pos, 0);
260 	fwrite(&utmp, sizeof(struct utmp), 1, fd);
261 
262 	fclose(fd);
263     }
264 #else				/* USE_SYSV_UTMP */
265     UTMP	   *putmp;
266 
267     if (!ut_id[0])
268 	return;			/* entry not made */
269 
270     utmpname(UTMP_FILENAME);
271     MEMSET(&utmp, 0, sizeof(UTMP));
272     STRNCPY(utmp.ut_id, ut_id, sizeof(utmp.ut_id));
273     utmp.ut_type = USER_PROCESS;
274 
275     setutent();			/* XXX: should be unnecessaray */
276 
277     putmp = getutid(&utmp);
278     if (!putmp || putmp->ut_pid != getpid())
279 	return;
280 
281     putmp->ut_type = DEAD_PROCESS;
282 
283 #ifdef HAVE_UTMPX_H
284     putmp->ut_session = getsid(0);
285     putmp->ut_tv.tv_sec = time(NULL);
286     putmp->ut_tv.tv_usec = 0;
287 #else				/* HAVE_UTMPX_H */
288     putmp->ut_time = time(NULL);
289 #endif				/* HAVE_UTMPX_H */
290     pututline(putmp);
291 
292 #ifdef WTMP_SUPPORT
293     update_wtmp(WTMP_FILENAME, putmp);
294 #endif
295 
296     endutent();
297 #endif				/* !USE_SYSV_UTMP */
298 }
299 #endif
300