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