4 Created: by Philip Homburg <philip@cs.vu.nl>
5 Log: Utmp improvement by Kees Bot <kjb@cs.vu.nl>
6 Split to compile easier on i86 by kjb
11 #include <sys/ioctl.h>
26 char pty_str
[]= "/dev/ptyXX";
27 char tty_str
[]= "/dev/ttyXX";
28 char hex_str
[16]= "0123456789abcdef";
30 char PATH_UTMP
[] = "/etc/utmp"; /* current logins */
31 char PATH_WTMP
[] = "/usr/adm/wtmp"; /* login/logout history */
33 char term
[64]= "TERM=";
34 #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation. */
39 static void do_child(int tty_fd
, char *tty_str
);
40 static void dealloc_term(int slot
, char *tty_str
, int pid
);
41 static void wtmp(char *user
, char *id
, char *line
, int pid
, int type
, int slot
);
42 static void setup_term(int fd
);
43 static speed_t
num2speed(int num
);
44 static int do_control(char *buf
, int cnt
);
45 static void readall(char *buf
, int cnt
);
47 int main(int argc
, char *argv
[])
52 int login_pid
, write_pid
;
53 int count
, bytes
, tmp_count
;
55 struct stat struct_stat
;
60 /* Check if the remote user is allowed in. */
63 write(1, "", 1); /* Send the '\0' */
66 /* We try to convince the other side not the do ^S/^Q, the rlogin
67 * protocol indicates the we only send this when XOFF is turned off
68 * but we don't know when this happens so we tell the other side that
77 /* Let's look for a pty. */
79 for (i
= 'p'; i
<= 'z'; i
++)
81 pty_str
[sizeof(pty_str
)-3]= i
;
82 pty_str
[sizeof(pty_str
)-2]= '0';
83 error
= stat(pty_str
, &struct_stat
);
86 for (j
= 0; j
< 16; j
++)
88 pty_str
[sizeof(pty_str
)-2]= hex_str
[j
];
89 pty_fd
= open(pty_str
, O_RDWR
);
98 printf("%s: out of ptys\r\n", prog_name
);
101 tty_str
[sizeof(pty_str
)-3]= i
;
102 tty_str
[sizeof(pty_str
)-2]= hex_str
[j
];
104 tty_fd
= open(tty_str
, O_RDWR
);
107 printf("%s: unable to open '%s': %s\r\n", prog_name
, tty_str
,
112 slot
= fttyslot(tty_fd
);
117 printf("%s: unable to fork: %s\r\n", prog_name
,
124 wtmp("", "", tty_str
, login_pid
, LOGIN_PROCESS
, slot
);
125 do_child(tty_fd
, tty_str
);
132 printf("%s: unable to fork: %s\r\n", prog_name
,
144 count
= read(0, line
, sizeof(line
));
149 bytes
= write(1, lp
, count
);
150 if (bytes
<= 0 || bytes
> count
)
155 kill(getppid(), SIGKILL
);
156 dealloc_term(slot
, tty_str
, login_pid
);
166 count
= read(0, line
, sizeof(line
));
172 cp
= memchr(lp
, 255, count
);
178 tmp_count
= do_control(lp
, count
);
187 bytes
= write(1, lp
, tmp_count
);
188 if (bytes
<= 0 || bytes
> count
)
193 kill(write_pid
, SIGKILL
);
194 dealloc_term(slot
, tty_str
, login_pid
);
198 static void do_child(int tty_fd
, char *tty_str
)
205 /* Set up the terminal attributes. */
208 /* Let's start the new session. */
210 ctty_fd
= open(tty_str
, O_RDWR
);
213 printf("%s(do_child): unable to open '%s': %s\r\n",
214 prog_name
, tty_str
, strerror(errno
));
217 /* Test if we really got a controlling tty. */
218 tst_fd
= open("/dev/tty", O_RDWR
);
222 "%s(do_child): '%s' didn't result in a controlling tty (%s)\r\n",
223 prog_name
, tty_str
, strerror(errno
));
234 if (lusername
[0] != '\0')
237 /* We reached the point of no return. */
249 fprintf(stderr
, "execing login\r\n");
252 execve("/bin/login", args
, env
);
253 if (errno
== ENOENT
) execve("/usr/bin/login", args
, env
);
255 tty_file
= fdopen(2, "w");
258 fprintf(tty_file
, "%s(do_child): unable to exec login: %s\r\n",
259 prog_name
, strerror(sav_errno
));
265 static void dealloc_term(int slot
, char *tty_str
, int pid
)
267 wtmp("", "", tty_str
, pid
, DEAD_PROCESS
, slot
);
269 /* Finally we reset the owner and mode of the terminal. */
270 chown(tty_str
, 0, 0);
271 chmod(tty_str
, 0666);
275 char *user
, /* name of user */
276 char *id
, /* inittab ID */
277 char *line
, /* TTY name */
278 int pid
, /* PID of process */
279 int type
, /* TYPE of entry */
280 int slot
) /* slot number in UTMP */
282 /* Log an event into the UTMP and WTMP files. */
284 struct utmp utmp
; /* UTMP/WTMP User Accounting */
286 int log
= 1; /* log in wtmp */
289 /* Strip the /dev part of the TTY name. */
290 p
= strrchr(line
, '/');
294 if (type
== DEAD_PROCESS
) {
295 /* Don't add a logout entry for just a dying login. */
296 if ((fd
= open(PATH_UTMP
, O_RDONLY
)) < 0) return;
297 if (lseek(fd
, (off_t
) slot
* sizeof(utmp
), SEEK_SET
) != -1
298 && read(fd
, (void *) &utmp
, sizeof(utmp
)) == sizeof(utmp
))
300 if (utmp
.ut_type
!= INIT_PROCESS
301 && utmp
.ut_type
!= USER_PROCESS
)
306 if (type
== LOGIN_PROCESS
) log
= 0; /* and don't log this one */
308 /* Clear the utmp record. */
309 memset((void *) &utmp
, 0, sizeof(utmp
));
311 /* Enter new values. */
312 strncpy(utmp
.ut_name
, user
, sizeof(utmp
.ut_name
));
313 strncpy(utmp
.ut_id
, id
, sizeof(utmp
.ut_id
));
314 strncpy(utmp
.ut_line
, line
, sizeof(utmp
.ut_line
));
315 strncpy(utmp
.ut_host
, hostname
, sizeof(utmp
.ut_host
));
318 utmp
.ut_time
= time((time_t *)0);
321 if ((fd
= open(PATH_WTMP
, O_WRONLY
| O_APPEND
)) < 0) return;
322 write(fd
, (char *) &utmp
, sizeof(struct utmp
));
326 /* write entry to utmp */
327 if ((fd
= open(PATH_UTMP
, O_WRONLY
)) < 0) return;
328 if (lseek(fd
, (off_t
) slot
* sizeof(utmp
), SEEK_SET
) != -1)
329 write(fd
, (char *) &utmp
, sizeof(struct utmp
));
333 void fatal(int fd
, char *msg
, int err
)
342 len
= sprintf(bp
, "rlogind: %s: %s.\r\n", msg
, strerror(err
));
344 len
= sprintf(bp
, "rlogind: %s.\r\n", msg
);
345 write(fd
, buf
, bp
+len
-buf
);
349 static void setup_term(int fd
)
357 cp
= strchr(term
, '/');
363 cp
= strchr(speed
, '/');
366 num
= strtol(speed
, &check
, 0);
368 if (spd
!= B0
&& check
[0] == '\0')
370 cfsetospeed(&tt
, spd
);
371 cfsetispeed(&tt
, spd
);
373 tcsetattr(fd
, TCSANOW
, &tt
);
379 static speed_t
num2speed(int num
)
387 { 0, B0
, }, { 50, B50
, }, { 75, B75
, }, { 110, B110
, },
388 { 134, B134
, }, { 150, B150
, }, { 200, B200
, }, { 300, B300
, },
389 { 600, B600
, }, { 1200, B1200
, }, { 1800, B1800
, },
390 { 2400, B2400
, }, { 4800, B4800
, }, { 9600, B9600
, },
391 { 19200, B19200
, }, { 38400, B38400
, },
396 for (i
= 0; speed_table
[i
].num
!= -1; i
++)
398 if (speed_table
[i
].num
== num
)
399 return (speed_table
[i
].value
);
404 static int do_control(char *cp
, int cnt
)
407 struct winsize winsize
;
409 if (cnt
> sizeof(buf
))
412 memcpy(buf
, cp
, cnt
);
414 /* Let's fetch the first 2 bytes. */
416 readall(buf
+cnt
, 2-cnt
);
417 if ((unsigned char)buf
[1] != 255)
420 /* Let's fetch the first 4 bytes. */
422 readall(buf
+cnt
, 4-cnt
);
423 if (buf
[2] != 's' || buf
[3] != 's')
426 /* Let's fetch a winsize structure. */
427 if (cnt
< 4 + sizeof(winsize
))
428 readall(buf
+cnt
, 4 + sizeof(winsize
) - cnt
);
430 memcpy(&winsize
, buf
+4, sizeof(winsize
));
431 winsize
.ws_row
= ntohs(winsize
.ws_row
);
432 winsize
.ws_col
= ntohs(winsize
.ws_col
);
433 winsize
.ws_xpixel
= ntohs(winsize
.ws_xpixel
);
434 winsize
.ws_ypixel
= ntohs(winsize
.ws_ypixel
);
436 fprintf(stderr
, "setting window size to %d, %d\r\n", winsize
.ws_row
,
439 ioctl(1, TIOCSWINSZ
, &winsize
);
440 return 4 + sizeof(winsize
);
443 static void readall(char *buf
, int cnt
)
449 res
= read(0, buf
, cnt
);