1 /*
2 * utmp/wtmp file updating
3 *
4 * Authors:
5 * Miguel de Icaza (miguel@gnu.org).
6 * Timur I. Bakeyev (timur@gnu.org).
7 *
8 * FIXME: Do we want to register the PID of the process running *under* the
9 * subshell or the PID of the parent process? (we are doing the latter now).
10 *
11 * FIXME: Solaris (utmpx) stuff need to be checked.
12 */
13
14 #include <config.h>
15 #include <sys/types.h>
16 #include <sys/file.h>
17 #include <stdio.h>
18 #include <unistd.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <fcntl.h>
22 #include <pwd.h>
23 #include <errno.h>
24
25 #if defined(TIME_WITH_SYS_TIME)
26 # include <sys/time.h>
27 #include <time.h>
28 #else
29 # if defined(HAVE_SYS_TIME_H)
30 # include <sys/time.h>
31 # else
32 # include <time.h>
33 # endif
34 #endif
35
36 #if defined(HAVE_LASTLOG_H)
37 # include <lastlog.h>
38 #endif
39
40 #if defined(HAVE_PATHS_H)
41 # include <paths.h>
42 #endif
43
44 #if defined(HAVE_UTMP_H)
45 # include <utmp.h>
46 #endif
47
48 #if defined(HAVE_UTMPX_H)
49 # include <utmpx.h>
50 #endif
51
52 #if defined(HAVE_TTYENT_H)
53 # include <ttyent.h>
54 #endif
55
56 #include "gnome-pty.h"
57 #include "gnome-login-support.h"
58
59
60
61 #if !defined(UTMP_OUTPUT_FILENAME)
62 # if defined(UTMP_FILE)
63 # define UTMP_OUTPUT_FILENAME UTMP_FILE
64 # elif defined(_PATH_UTMP) /* BSD systems */
65 # define UTMP_OUTPUT_FILENAME _PATH_UTMP
66 # else
67 # define UTMP_OUTPUT_FILENAME "/etc/utmp"
68 # endif
69 #endif
70
71 #if !defined(WTMP_OUTPUT_FILENAME)
72 # if defined(WTMPX_FILE)
73 # define WTMP_OUTPUT_FILENAME WTMPX_FILE
74 # elif defined(_PATH_WTMPX)
75 # define WTMP_OUTPUT_FILENAME _PATH_WTMPX
76 # elif defined(WTMPX_FILENAME)
77 # define WTMP_OUTPUT_FILENAME WTMPX_FILENAME
78 # elif defined(WTMP_FILE)
79 # define WTMP_OUTPUT_FILENAME WTMP_FILE
80 # elif defined(_PATH_WTMP) /* BSD systems */
81 # define WTMP_OUTPUT_FILENAME _PATH_WTMP
82 # else
83 # define WTMP_OUTPUT_FILENAME "/etc/wtmp"
84 # endif
85 #endif
86
87 #if defined(_PATH_LASTLOG) /* BSD systems */
88 # define LASTLOG_OUTPUT_FILE _PATH_LASTLOG
89 #else
90 # define LASTLOG_OUTPUT_FILE "/var/log/lastlog"
91 #endif
92
93 #if defined(HAVE_UPDWTMPX)
94 #include <utmpx.h>
95 #define update_wtmp updwtmpx
96 #elif defined(HAVE_UPDWTMP)
97 #define update_wtmp updwtmp
98 #else /* !HAVE_UPDWTMPX && !HAVE_UPDWTMP */
99 static void
update_wtmp(char * file,UTMP * putmp)100 update_wtmp (char *file, UTMP *putmp)
101 {
102 int fd, times = 3;
103 #if defined(HAVE_FCNTL)
104 struct flock lck;
105
106 lck.l_whence = SEEK_END;
107 lck.l_len = 0;
108 lck.l_start = 0;
109 lck.l_type = F_WRLCK;
110 #endif
111
112 if ((fd = open (file, O_WRONLY|O_APPEND, 0)) < 0)
113 return;
114
115 #if defined (HAVE_FCNTL)
116 while (times--)
117 if ((fcntl (fd, F_SETLK, &lck) < 0))
118 {
119 if (errno != EAGAIN && errno != EACCES) {
120 close (fd);
121 return;
122 }
123 sleep (1); /*?!*/
124 } else
125 break;
126 #elif defined(HAVE_FLOCK)
127 while (times--)
128 if (flock (fd, LOCK_EX | LOCK_NB) < 0)
129 {
130 if (errno != EWOULDBLOCK)
131 {
132 close (fd);
133 return;
134 }
135 sleep (1); /*?!*/
136 } else
137 break;
138 #endif /* HAVE_FLOCK */
139
140 lseek (fd, 0, SEEK_END);
141 write (fd, putmp, sizeof(UTMP));
142
143 /* unlock the file */
144 #if defined(HAVE_FCNTL)
145 lck.l_type = F_UNLCK;
146 fcntl (fd, F_SETLK, &lck);
147 #elif defined(HAVE_FLOCK)
148 flock (fd, LOCK_UN);
149 #endif
150 close (fd);
151 }
152 #endif /* !HAVE_GETUTMPX */
153
154
155 #if defined(HAVE_GETUTMPX) || defined(HAVE_GETUTXID)
156 static void
update_utmp(UTMP * ut)157 update_utmp (UTMP *ut)
158 {
159 setutxent();
160 pututxline (ut);
161 endutxent();
162 }
163 #elif defined(HAVE_GETUTENT)
164 static void
update_utmp(UTMP * ut)165 update_utmp (UTMP *ut)
166 {
167 setutent();
168 pututline (ut);
169 endutent();
170 }
171 #elif defined(HAVE_GETTTYENT)
172 /* This variant is sutable for most BSD */
173 static void
update_utmp(UTMP * ut)174 update_utmp (UTMP *ut)
175 {
176 struct ttyent *ty;
177 int fd, pos = 0;
178
179 if ((fd = open (UTMP_OUTPUT_FILENAME, O_RDWR|O_CREAT, 0644)) < 0)
180 return;
181
182 setttyent ();
183 while ((ty = getttyent ()) != NULL)
184 {
185 ++pos;
186 if (strncmp (ty->ty_name, ut->ut_line, sizeof (ut->ut_line)) == 0)
187 {
188 lseek (fd, (off_t)(pos * sizeof(UTMP)), SEEK_SET);
189 write(fd, ut, sizeof(UTMP));
190 }
191 }
192 endttyent ();
193
194 close(fd);
195 }
196 #else
197 #define update_utmp(ut)
198 #endif
199
200 #if !defined(HAVE_LASTLOG)
201 #define update_lastlog(login_name, ut)
202 #else
203 static void
update_lastlog(char * login_name,UTMP * ut)204 update_lastlog(char* login_name, UTMP *ut)
205 {
206 struct passwd *pwd;
207 struct lastlog ll;
208 int fd;
209
210 if ((fd = open(LASTLOG_OUTPUT_FILE, O_WRONLY, 0)) < 0)
211 return;
212
213 if ((pwd=getpwnam(login_name)) == NULL)
214 return;
215
216 memset (&ll, 0, sizeof(ll));
217
218 lseek (fd, (off_t)pwd->pw_uid * sizeof (ll), SEEK_SET);
219
220 time (&ll.ll_time);
221
222 strncpy (ll.ll_line, ut->ut_line, sizeof (ll.ll_line));
223
224 #if defined(HAVE_UT_UT_HOST)
225 if (ut->ut_host)
226 strncpy (ll.ll_host, ut->ut_host, sizeof (ll.ll_host));
227 #endif
228
229 write (fd, (void *)&ll, sizeof (ll));
230 close (fd);
231 }
232 #endif /* HAVE_LASTLOG */
233
234 void
write_logout_record(char * login_name,void * data,int utmp,int wtmp)235 write_logout_record (char *login_name, void *data, int utmp, int wtmp)
236 {
237 UTMP put, *ut = data;
238 struct timeval tv;
239
240 memset (&put, 0, sizeof(UTMP));
241
242 #if defined(HAVE_UT_UT_TYPE)
243 put.ut_type = DEAD_PROCESS;
244 #endif
245 #if defined(HAVE_UT_UT_ID)
246 strncpy (put.ut_id, ut->ut_id, sizeof (put.ut_id));
247 #endif
248
249 strncpy (put.ut_line, ut->ut_line, sizeof (put.ut_line));
250
251 #if defined(HAVE_UT_UT_TV)
252 gettimeofday(&tv, NULL);
253 put.ut_tv.tv_sec = tv.tv_sec;
254 put.ut_tv.tv_usec = tv.tv_usec;
255 #elif defined(HAVE_UT_UT_TIME)
256 time (&put.ut_time);
257 #endif
258
259 #if defined(HAVE_UT_UT_NAME)
260 strncpy (put.ut_name, login_name, sizeof (put.ut_name));
261 #elif defined(HAVE_UT_UT_USER)
262 strncpy (put.ut_user, login_name, sizeof (put.ut_user));
263 #endif
264
265 if (utmp)
266 update_utmp (&put);
267
268 if (wtmp)
269 update_wtmp (WTMP_OUTPUT_FILENAME, &put);
270
271 free (ut);
272 }
273
274 void *
write_login_record(char * login_name,char * display_name,char * term_name,int utmp,int wtmp,int lastlog)275 write_login_record (char *login_name, char *display_name,
276 char *term_name, int utmp, int wtmp, int lastlog)
277 {
278 UTMP *ut;
279 char *pty = term_name;
280 struct timeval tv;
281
282 if ((ut=(UTMP *) malloc (sizeof (UTMP))) == NULL)
283 return NULL;
284
285 memset (ut, 0, sizeof (UTMP));
286
287 #if defined(HAVE_UT_UT_NAME)
288 strncpy (ut->ut_name, login_name, sizeof (ut->ut_name));
289 #elif defined(HAVE_UT_UT_USER)
290 strncpy (ut->ut_user, login_name, sizeof (ut->ut_user));
291 #endif
292
293 /* This shouldn't happen */
294 if (strncmp (pty, "/dev/", 5) == 0)
295 pty += 5;
296
297 #if defined(HAVE_STRRCHR)
298 {
299 char *p;
300
301 if (strncmp (pty, "pts", 3) &&
302 (p = strrchr (pty, '/')) != NULL)
303 pty = p + 1;
304 }
305 #endif
306
307 #if defined(HAVE_UT_UT_ID)
308 /* Just a safe-guard */
309 ut->ut_id [0] = '\0';
310
311 /* BSD-like terminal name */
312 if (strncmp (pty, "pts", 3) == 0 ||
313 strncmp (pty, "pty", 3) == 0 ||
314 strncmp (pty, "tty", 3) == 0) {
315 strncpy (ut->ut_id, pty+3, sizeof (ut->ut_id));
316 } else {
317 unsigned int num;
318 char buf[10];
319 /* Try to get device number and convert it to gnome-terminal # */
320 if (sscanf (pty, "%*[^0-9a-f]%x", &num) == 1) {
321 sprintf (buf, "gt%2.2x", num);
322 strncpy (ut->ut_id, buf, sizeof (ut->ut_id));
323 }
324 }
325 #endif
326
327 /* For utmpx ut_line should be null terminated */
328 /* We do that for both cases to be sure */
329 strncpy (ut->ut_line, pty, sizeof (ut->ut_line));
330 ut->ut_line[sizeof (ut->ut_line)-1] = '\0';
331
332 /* We want parent's pid, not our own */
333 #if defined(HAVE_UT_UT_PID)
334 ut->ut_pid = getppid ();
335 #endif
336
337 #if defined(HAVE_UT_UT_TYPE)
338 ut->ut_type = USER_PROCESS;
339 #endif
340 /* If structure has ut_tv it doesn't need ut_time */
341 #if defined(HAVE_UT_UT_TV)
342 gettimeofday(&tv, NULL);
343 ut->ut_tv.tv_sec = tv.tv_sec;
344 ut->ut_tv.tv_usec = tv.tv_usec;
345 #elif defined(HAVE_UT_UT_TIME)
346 time (&ut->ut_time);
347 #endif
348 /* ut_ host supposed to be null terminated or len should */
349 /* be specifid in additional field. We do both :) */
350 #if defined(HAVE_UT_UT_HOST)
351 strncpy (ut->ut_host, display_name, sizeof (ut->ut_host));
352 ut->ut_host [sizeof (ut->ut_host)-1] = '\0';
353 # if defined(HAVE_UT_UT_SYSLEN)
354 ut->ut_syslen = strlen (ut->ut_host);
355 # endif
356 #endif
357 if (utmp)
358 update_utmp (ut);
359
360 if (wtmp)
361 update_wtmp (WTMP_OUTPUT_FILENAME, ut);
362
363 if (lastlog)
364 update_lastlog(login_name, ut);
365
366 return ut;
367 }
368
369 void *
update_dbs(int utmp,int wtmp,int lastlog,char * login_name,char * display_name,char * term_name)370 update_dbs (int utmp, int wtmp, int lastlog, char *login_name, char *display_name, char *term_name)
371 {
372 return write_login_record (login_name, display_name,
373 term_name, utmp, wtmp, lastlog);
374 }
375