posix.c - utmp - simple login manager
HTML git clone git://git.suckless.org/utmp
DIR Log
DIR Files
DIR Refs
DIR README
DIR LICENSE
---
posix.c (2790B)
---
1
2 #define _POSIX_C_SOURCE 200112L
3
4 #include <errno.h>
5 #include <ctype.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <time.h>
10
11 #include <sys/types.h>
12 #include <unistd.h>
13 #include <pwd.h>
14 #include <grp.h>
15
16 #ifdef UTMP_SYSTEMV
17 #include <utmp.h>
18 #define getutxent getutent
19 #define getutxid getutid
20 #define getutxline getutline
21 #define pututxline pututline
22 #define setutxent setutent
23 #define endutxent endutent
24 #define utmpx utmp
25 #else
26 #include <utmpx.h>
27 #endif
28
29 extern void die(const char *fmt, ...);
30 static struct utmpx utmp;
31 extern struct passwd *pw;
32 extern gid_t egid, gid;
33
34
35 /*
36 * From utmp(5)
37 * xterm and other terminal emulators directly create a USER_PROCESS
38 * record and generate the ut_id by using the string that suffix part of
39 * the terminal name (the characters following /dev/[pt]ty). If they find
40 * a DEAD_PROCESS for this ID, they recycle it, otherwise they create a new
41 * entry. If they can, they will mark it as DEAD_PROCESS on exiting and it
42 * is advised that they null ut_line, ut_time, ut_user, and ut_host as well.
43 */
44
45 struct utmpx *
46 findutmp(int type)
47 {
48 struct utmpx *r;
49
50 utmp.ut_type = type;
51 setutxent();
52 for(;;) {
53 /*
54 * we can not use getutxline because we can search in
55 * DEAD_PROCESS to
56 */
57 if(!(r = getutxid(&utmp)))
58 break;
59 if(!strcmp(r->ut_line, utmp.ut_line))
60 break;
61 memset(r, 0, sizeof(*r)); /* for Solaris, IRIX64 and HPUX */
62 }
63 return r;
64 }
65
66 void
67 addutmp(void)
68 {
69 unsigned ptyid;
70 char *pts, *cp, buf[5] = {'x'};
71
72 if (strlen(pw->pw_name) > sizeof(utmp.ut_user))
73 die("utmp:incorrect username %s", pw->pw_name);
74
75 if ((pts = ttyname(STDIN_FILENO)) == NULL)
76 die("utmp:error getting pty name\n");
77
78 for (cp = pts + strlen(pts) - 1; isdigit(*cp); --cp)
79 /* nothing */;
80
81 ptyid = atoi(++cp);
82 if (ptyid > 999 || strlen(pts + 5) > sizeof(utmp.ut_line))
83 die("utmp:Incorrect pts name %s\n", pts);
84 sprintf(buf + 1, "%03d", ptyid);
85 strncpy(utmp.ut_id, buf, 4);
86
87 /* remove /dev/ part of the string */
88 strncpy(utmp.ut_line, pts + 5, sizeof(utmp.ut_line));
89
90 if(!findutmp(DEAD_PROCESS))
91 findutmp(USER_PROCESS);
92
93 utmp.ut_type = USER_PROCESS;
94 strncpy(utmp.ut_user, pw->pw_name, sizeof(utmp.ut_user));
95 utmp.ut_pid = getpid();
96 utmp.ut_tv.tv_sec = time(NULL);
97 utmp.ut_tv.tv_usec = 0;
98 /* don't use no standard fields host and session */
99
100 setegid(egid);
101 if(!pututxline(&utmp))
102 die("utmp:error adding utmp entry:%s", strerror(errno));
103 setegid(gid);
104 endutxent();
105 }
106
107 void
108 delutmp(void)
109 {
110 struct utmpx *r;
111
112 setutxent();
113 if((r = getutxline(&utmp)) != NULL) {
114 r->ut_type = DEAD_PROCESS;
115 r->ut_tv.tv_usec = r->ut_tv.tv_sec = 0;
116 setgid(egid);
117 if (!pututxline(r))
118 die("utmp:error removing utmp entry:%s", strerror(errno));
119 setgid(gid);
120 }
121 endutxent();
122 }
123