#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/fcntl.h>
#include <sys/time.h>
#include <time.h>
#include <stdio.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include "talkd_impl.h"
static int nofork = 0;
static int announce_proc(CTL_MSG *request, char *remote_machine);
static void print_mesg(FILE *tf, CTL_MSG *request, char *remote_machine);
int
announce(CTL_MSG *request, char *remote_machine)
{
pid_t pid, val;
int status;
if (nofork) {
return (announce_proc(request, remote_machine));
}
if (pid = fork()) {
if (pid == (pid_t)-1) {
return (FAILED);
}
do {
val = wait(&status);
if (val == (pid_t)-1) {
if (errno == EINTR) {
continue;
} else {
print_error("wait");
return (FAILED);
}
}
} while (val != pid);
if ((status & 0377) > 0) {
return (FAILED);
}
return ((status>>8)&0377);
} else {
_exit(announce_proc(request, remote_machine));
}
}
static int
announce_proc(CTL_MSG *request, char *remote_machine)
{
#define TTY_BUFSZ 32
char full_tty[TTY_BUFSZ];
FILE *tf;
struct stat stbuf;
int fd;
struct passwd *p;
(void) snprintf(full_tty, TTY_BUFSZ, "/dev/%s", request->r_tty);
p = getpwnam(request->r_name);
if (p == 0 || access(full_tty, 0) != 0) {
return (FAILED);
}
if ((fd = open(full_tty, O_WRONLY|O_NONBLOCK)) == -1) {
return (PERMISSION_DENIED);
}
if (!isatty(fd)) {
(void) close(fd);
return (PERMISSION_DENIED);
}
(void) setsid();
if (fstat(fd, &stbuf) < 0 || stbuf.st_uid != p->pw_uid) {
(void) close(fd);
return (PERMISSION_DENIED);
}
if ((stbuf.st_mode&020) == 0) {
(void) close(fd);
return (PERMISSION_DENIED);
}
if ((tf = fdopen(fd, "w")) == NULL) {
(void) close(fd);
return (PERMISSION_DENIED);
}
print_mesg(tf, request, remote_machine);
(void) fclose(tf);
return (SUCCESS);
}
#define max(a, b) ((a) > (b) ? (a) : (b))
#define N_LINES 5
#define N_CHARS 300
static void
print_mesg(FILE *tf, CTL_MSG *request, char *remote_machine)
{
struct timeval clock;
struct tm *localclock;
char line_buf[N_LINES][N_CHARS];
int sizes[N_LINES];
char *bptr, *lptr;
int i, j, max_size;
char big_buf[3 + (N_LINES * (N_CHARS - 1)) + (N_LINES * 2) + 1];
char l_username[((NAME_SIZE - 1) * 4) + 1];
int len, k;
i = 0;
max_size = 0;
(void) gettimeofday(&clock, NULL);
localclock = localtime(&clock.tv_sec);
(void) sprintf(line_buf[i], " ");
sizes[i] = strlen(line_buf[i]);
max_size = max(max_size, sizes[i]);
i++;
(void) snprintf(line_buf[i], N_CHARS,
"Message from Talk_Daemon@%s at %d:%02d ...", hostname,
localclock->tm_hour, localclock->tm_min);
sizes[i] = strlen(line_buf[i]);
max_size = max(max_size, sizes[i]);
i++;
len = (strlen(request->l_name) > NAME_SIZE - 1) ? (NAME_SIZE - 1) :
strlen(request->l_name);
for (j = 0, k = 0; j < len; j++) {
if (!isprint((unsigned char)request->l_name[j])) {
char c;
if (!isascii((unsigned char)request->l_name[j])) {
l_username[k++] = 'M';
l_username[k++] = '-';
c = toascii(request->l_name[j]);
}
if (iscntrl((unsigned char)request->l_name[j])) {
l_username[k++] = '^';
c = request->l_name[j] + 0100;
}
l_username[k++] = c;
} else {
l_username[k++] = request->l_name[j];
}
}
l_username[k] = '\0';
(void) snprintf(line_buf[i], N_CHARS,
"talk: connection requested by %s@%s.", l_username, remote_machine);
sizes[i] = strlen(line_buf[i]);
max_size = max(max_size, sizes[i]);
i++;
(void) snprintf(line_buf[i], N_CHARS, "talk: respond with: talk %s@%s",
l_username, remote_machine);
sizes[i] = strlen(line_buf[i]);
max_size = max(max_size, sizes[i]);
i++;
(void) sprintf(line_buf[i], " ");
sizes[i] = strlen(line_buf[i]);
max_size = max(max_size, sizes[i]);
i++;
bptr = big_buf;
*(bptr++) = '\a';
*(bptr++) = '\r';
*(bptr++) = '\n';
for (i = 0; i < N_LINES; i++) {
lptr = line_buf[i];
while (*lptr != '\0') {
*(bptr++) = *(lptr++);
}
for (j = sizes[i]; j < max_size; j++) {
*(bptr++) = ' ';
}
*(bptr++) = '\r';
*(bptr++) = '\n';
}
*bptr = '\0';
(void) fputs(big_buf, tf);
(void) fflush(tf);
(void) setsid();
}