1 /*
2 * Copyright (C) 1997-2009, Michael Jennings
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies of the Software, its documentation and marketing & publicity
13 * materials, and acknowledgment shall be given in the documentation, materials
14 * and software packages that this Software was used.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 static const char cvs_ident[] = "$Id: utmp.c 51650 2010-08-26 01:34:13Z lucas $";
25
26 #include "config.h"
27 #include "feature.h"
28
29 # include "eterm_utmp.h"
30 # include "command.h"
31 # include "screen.h"
32
33 #if defined(UTMP_SUPPORT) && !defined(HAVE_LIBUTEMPTER)
34
35 /* screen.h includes config.h again, so re-fix these. Pointed out by Sung-Hyun Nam <namsh@lgic.co.kr> */
36 # if defined(_HPUX_SOURCE) || defined(_AIX) || ((__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1))
37 # undef HAVE_UTMPX_H
38 # endif
39
40 /* don't go off end of ut_id & remember if an entry has been made */
41 # if defined(USE_SYSV_UTMP) || defined(__OpenBSD__)
42 static char ut_id[5]; /* remember if entry to utmp made */
43 # elif !defined(NEW_BSD_UTMP)
44 static int utmp_pos; /* BSD position of utmp-stamp */
45 # endif
46
47 # ifdef USE_SYSV_UTMP
48
49 # ifdef HAVE_UTMPX_H
50 # undef WTMP_FILENAME
51 # define WTMP_FILENAME WTMPX_FILE
52 # define update_wtmp updwtmpx
53 # else /* HAVE_UTMPX_H */
54
55 static void
update_wtmp(char * fname,struct utmp * putmp)56 update_wtmp(char *fname, struct utmp *putmp)
57 {
58
59 int fd, retry = 10; /* 10 attempts at locking */
60 struct flock lck; /* fcntl locking scheme */
61
62 if ((fd = open(fname, O_WRONLY | O_APPEND, 0)) < 0) {
63 D_UTMP(("Warning: Unable to open \"%s\" for writing -- %s\n", fname, strerror(errno)));
64 return;
65 }
66 lck.l_whence = SEEK_END; /* start lock at current eof */
67 lck.l_len = 0; /* end at ``largest possible eof'' */
68 lck.l_start = 0;
69 lck.l_type = F_WRLCK; /* we want a write lock */
70
71 /* attempt lock with F_SETLK - F_SETLKW would cause a deadlock! */
72 while (retry--) {
73 if ((fcntl(fd, F_SETLK, &lck) < 0) && errno != EACCESS) {
74 D_UTMP(("Warning: Unable to establish file lock on \"%s\" -- %s\n", fname, strerror(errno)));
75 close(fd);
76 return; /* failed for unknown reason: give up */
77 } else if (errno == EACCESS) {
78 D_UTMP(("Warning: Unable to establish file lock on \"%s\" -- %s\n", fname, strerror(errno)));
79 }
80 }
81
82 write(fd, putmp, sizeof(struct utmp));
83
84 /* unlocking the file */
85 lck.l_type = F_UNLCK;
86 fcntl(fd, F_SETLK, &lck);
87
88 close(fd);
89 }
90 # endif /* HAVE_UTMPX_H */
91
92 void
add_utmp_entry(const char * pty,const char * hostname,int fd)93 add_utmp_entry(const char *pty, const char *hostname, int fd)
94 {
95 struct passwd *pwent = getpwuid(my_ruid);
96
97 # ifdef HAVE_UTMPX_H
98 struct utmpx utmp;
99 struct utmp utmp2;
100 MEMSET(&utmp, 0, sizeof(struct utmpx));
101 # else
102 struct utmp utmp;
103 MEMSET(&utmp, 0, sizeof(struct utmp));
104 # endif
105
106 # ifdef WITH_DMALLOC
107 return;
108 # endif
109
110 if (!strncmp(pty, "/dev/", 5))
111 pty += 5; /* skip /dev/ prefix */
112 if (!strncmp(pty, "pty", 3) || !strncmp(pty, "tty", 3))
113 strncpy(ut_id, (pty + 3), sizeof(ut_id)); /* bsd naming */
114 else {
115 int n;
116
117 if (sscanf(pty, "pts/%d", &n) == 1)
118 sprintf(ut_id, "vt%02x", n); /* sysv naming */
119 else {
120 libast_print_error("can't parse tty name \"%s\"\n", pty);
121 ut_id[0] = '\0'; /* entry not made */
122 return;
123 }
124 }
125 strncpy(utmp.ut_id, ut_id, sizeof(utmp.ut_id));
126 utmp.ut_type = DEAD_PROCESS;
127
128 privileges(INVOKE);
129 # ifdef HAVE_UTMPX_H
130 getutmp(&utmp, &utmp2);
131 getutid(&utmp2); /* position to entry in utmp file */
132 # else
133 getutid(&utmp); /* position to entry in utmp file */
134 # endif
135
136 /* set up the new entry */
137 strncpy(utmp.ut_id, ut_id, sizeof(utmp.ut_id));
138 strncpy(utmp.ut_line, pty, sizeof(utmp.ut_line));
139 strncpy(utmp.ut_name, pwent->pw_name, sizeof(utmp.ut_name));
140 strncpy(utmp.ut_user, pwent->pw_name, sizeof(utmp.ut_user));
141 strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
142 utmp.ut_type = USER_PROCESS;
143 utmp.ut_pid = getpid();
144 # ifdef HAVE_UTMPX_H
145 utmp.ut_session = getsid(0);
146 utmp.ut_xtime = time(NULL);
147 utmp.ut_tv.tv_usec = 0;
148 # else
149 utmp.ut_time = time(NULL);
150 # endif
151
152 /*
153 * write a utmp entry to the utmp file
154 */
155 utmpname(UTMP_FILENAME);
156 # ifdef HAVE_UTMPX_H
157 getutmp(&utmp, &utmp2);
158 pututline(&utmp2);
159 pututxline(&utmp);
160 # else
161 pututline(&utmp);
162 # endif
163 update_wtmp(WTMP_FILENAME, &utmp);
164 endutent(); /* close the file */
165 privileges(REVERT);
166 return;
167 fd = 0;
168 }
169
170 void
remove_utmp_entry(void)171 remove_utmp_entry(void)
172 {
173 # ifdef HAVE_UTMPX_H
174 struct utmp utmp;
175 struct utmpx utmpx;
176
177 if (!ut_id[0])
178 return; /* entry not made */
179
180 utmpname(UTMP_FILENAME);
181 setutent();
182 strncpy(utmp.ut_id, ut_id, sizeof(utmp.ut_id));
183 utmp.ut_type = USER_PROCESS;
184 if (!getutid(&utmp)) {
185 return;
186 }
187 utmp.ut_type = DEAD_PROCESS;
188 utmp.ut_time = time(NULL);
189 pututline(&utmp);
190 getutmpx(&utmp, &utmpx);
191 update_wtmp(WTMP_FILENAME, &utmpx);
192 endutent();
193
194 # else /* HAVE_UTMPX_H */
195 struct utmp *putmp;
196 pid_t pid = getpid();
197
198 if (!ut_id[0])
199 return; /* entry not made */
200
201 utmpname(UTMP_FILENAME);
202 setutent();
203 /*
204 * The following code waw copied from the poeigl-1.20 login/init package.
205 * Special thanks to poe for the code examples.
206 */
207 while ((putmp = getutent())) {
208 if (putmp->ut_pid == pid) {
209 putmp->ut_type = DEAD_PROCESS;
210 putmp->ut_pid = 0;
211 putmp->ut_user[0] = '\0';
212 putmp->ut_time = time(NULL);
213 pututline(putmp);
214 update_wtmp(WTMP_FILENAME, putmp);
215 break;
216 }
217 }
218 endutent();
219 # endif /* HAVE_UTMPX_H */
220 }
221
222 # else /* USE_SYSV_UTMP */
223 /* BSD utmp support */
224
225 # ifdef NEW_BSD_UTMP
226
227 /* used to hold the line we are using */
228 static char ut_line[32];
229
230 static int
get_tslot(const char * ttyname)231 get_tslot(const char *ttyname)
232 {
233 register struct ttyent *ttyp;
234 register int slot;
235
236 setttyent();
237 for (slot = 1; (ttyp = getttyent()); ++slot)
238 if (!strcmp(ttyp->ty_name, ttyname)) {
239 endttyent();
240 return (slot);
241 }
242 endttyent();
243 return 0;
244 }
245
246 void
b_login(struct utmp * ut)247 b_login(struct utmp *ut)
248 {
249 /*
250 ** replacement for freebsd's login(), which uses ttyslot()
251 **
252 ** like I shouldn't have just KNOWN that from the comment on get_tslot
253 ** below...
254 ** - brian
255 */
256 register int fd;
257 int tty;
258
259 tty = get_tslot(ut->ut_line);
260 if (tty > 0 && (fd = open(_PATH_UTMP, O_WRONLY | O_CREAT, 0644)) >= 0) {
261 (void) lseek(fd, (off_t) (tty * sizeof(struct utmp)), L_SET);
262 (void) write(fd, ut, sizeof(struct utmp));
263
264 (void) close(fd);
265 }
266 if ((fd = open(_PATH_WTMP, O_WRONLY | O_APPEND, 0)) >= 0) {
267 (void) write(fd, ut, sizeof(struct utmp));
268
269 (void) close(fd);
270 }
271 }
272
273 # else /* NEW_BSD_UTMP */
274 static int utmp_pos = 0; /* position of utmp-stamp */
275
276 /*----------------------------------------------------------------------*
277 * get_tslot() - grabbed from xvt-1.0 - modified by David Perry
278 *
279 * find ttyname in /etc/ttytab and return a slot number that can be used to
280 * access the utmp file. Can't use ttyslot() because the tty name is not
281 * that of fd 0.
282 *----------------------------------------------------------------------*/
283 static int
get_tslot(const char * ttyname)284 get_tslot(const char *ttyname)
285 {
286 char buf[256], name[256];
287 FILE *fd;
288
289 if ((fd = fopen(UTMP_FILENAME, "r"))) {
290 int i;
291
292 for (i = 1; fgets(buf, sizeof(buf), fd); i++) {
293 if (*buf == '#' || sscanf(buf, "%s", name) != 1)
294 continue;
295 if (!strcmp(ttyname, name)) {
296 fclose(fd);
297 return i;
298 }
299 }
300 fclose(fd);
301 }
302 return -1;
303 }
304
305 /*
306 * write utmp entry to UTMP_FILENAME
307 */
308 static int
write_utmp(struct utmp * putmp)309 write_utmp(struct utmp *putmp)
310 {
311 int rval = 0;
312 FILE *fd;
313
314 fprintf(stderr, "Utmp file is %s\n", UTMP_FILENAME);
315 privileges(INVOKE);
316 if ((fd = fopen(UTMP_FILENAME, "r+"))) {
317 utmp_pos = get_tslot(putmp->ut_line) * sizeof(struct utmp);
318
319 if (utmp_pos >= 0) {
320 fseek(fd, utmp_pos, 0);
321 fwrite(putmp, sizeof(struct utmp), 1, fd);
322
323 rval = 1;
324 }
325 fclose(fd);
326 }
327 privileges(REVERT);
328 return rval;
329 }
330
331 # endif /* NEW_BSD_UTMP */
332
333 void
add_utmp_entry(const char * pty,const char * hostname,int fd)334 add_utmp_entry(const char *pty, const char *hostname, int fd)
335 {
336 struct passwd *pwent = getpwuid(my_ruid);
337 struct utmp utmp;
338
339 MEMSET(&utmp, 0, sizeof(struct utmp));
340
341 if (!strncmp(pty, "/dev/", 5))
342 pty += 5; /* skip /dev/ prefix */
343
344 # ifdef NEW_BSD_UTMP
345 strncpy(ut_line, pty, 31);
346
347 strncpy(utmp.ut_line, pty, UT_LINESIZE);
348 strncpy(utmp.ut_name, pwent->pw_name, UT_NAMESIZE);
349 strncpy(utmp.ut_host, hostname, UT_HOSTSIZE);
350 utmp.ut_time = time(NULL);
351
352 b_login(&utmp);
353 # else /* NEW_BSD_UTMP */
354 if (!strncmp(pty, "pty", 3) || !strncmp(pty, "tty", 3))
355 strncpy(ut_id, (pty + 3), sizeof(ut_id)); /* bsd naming */
356 else {
357 libast_print_error("can't parse tty name \"%s\"\n", pty);
358 ut_id[0] = '\0'; /* entry not made */
359 return;
360 }
361
362 strncpy(utmp.ut_line, ut_id, sizeof(utmp.ut_line));
363 strncpy(utmp.ut_name, pwent->pw_name, sizeof(utmp.ut_name));
364 strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
365 utmp.ut_time = time(NULL);
366
367 if (write_utmp(&utmp) < 0)
368 ut_id[0] = '\0'; /* entry not made */
369 # endif
370 return;
371 fd = 0;
372 }
373
374 /*
375 * remove a utmp entry
376 */
377 void
remove_utmp_entry(void)378 remove_utmp_entry(void)
379 {
380 # ifdef NEW_BSD_UTMP
381 logout(ut_line);
382 logwtmp(ut_line, "", "");
383 # else /* NEW_BSD_UTMP */
384 FILE *fd;
385
386 privileges(INVOKE);
387 if (!ut_id[0] && (fd = fopen(UTMP_FILENAME, "r+"))) {
388 struct utmp utmp;
389 MEMSET(&utmp, 0, sizeof(struct utmp));
390
391 fseek(fd, utmp_pos, 0);
392 fwrite(&utmp, sizeof(struct utmp), 1, fd);
393
394 fclose(fd);
395 }
396 privileges(REVERT);
397 # endif /* NEW_BSD_UTMP */
398 }
399
400 # endif /* USE_SYSV_UTMP */
401
402 #endif /* UTMP_SUPPORT */
403