11592Srgrimes/*
21592Srgrimes * Copyright (c) 1983, 1993
31592Srgrimes *	The Regents of the University of California.  All rights reserved.
41592Srgrimes *
51592Srgrimes * Redistribution and use in source and binary forms, with or without
61592Srgrimes * modification, are permitted provided that the following conditions
71592Srgrimes * are met:
81592Srgrimes * 1. Redistributions of source code must retain the above copyright
91592Srgrimes *    notice, this list of conditions and the following disclaimer.
101592Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111592Srgrimes *    notice, this list of conditions and the following disclaimer in the
121592Srgrimes *    documentation and/or other materials provided with the distribution.
13262435Sbrueffer * 3. Neither the name of the University nor the names of its contributors
141592Srgrimes *    may be used to endorse or promote products derived from this software
151592Srgrimes *    without specific prior written permission.
161592Srgrimes *
171592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201592Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211592Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271592Srgrimes * SUCH DAMAGE.
281592Srgrimes */
291592Srgrimes
301592Srgrimes#ifndef lint
3131491Scharnier#if 0
321592Srgrimesstatic char sccsid[] = "@(#)process.c	8.2 (Berkeley) 11/16/93";
3331491Scharnier#endif
3431491Scharnierstatic const char rcsid[] =
3550476Speter  "$FreeBSD$";
361592Srgrimes#endif /* not lint */
371592Srgrimes
381592Srgrimes/*
391592Srgrimes * process.c handles the requests, which can be of three types:
401592Srgrimes *	ANNOUNCE - announce to a user that a talk is wanted
411592Srgrimes *	LEAVE_INVITE - insert the request into the table
421592Srgrimes *	LOOK_UP - look up to see if a request is waiting in
431592Srgrimes *		  in the table for the local user
441592Srgrimes *	DELETE - delete invitation
451592Srgrimes */
461592Srgrimes#include <sys/param.h>
471592Srgrimes#include <sys/stat.h>
481592Srgrimes#include <sys/socket.h>
491592Srgrimes#include <netinet/in.h>
501592Srgrimes#include <protocols/talkd.h>
5131491Scharnier#include <ctype.h>
5231491Scharnier#include <err.h>
531592Srgrimes#include <netdb.h>
5431491Scharnier#include <paths.h>
551592Srgrimes#include <stdio.h>
561592Srgrimes#include <string.h>
5731491Scharnier#include <syslog.h>
58202210Sed#include <utmpx.h>
591592Srgrimes
6090261Simp#include "extern.h"
611592Srgrimes
6231491Scharniervoid
6390261Simpprocess_request(CTL_MSG *mp, CTL_RESPONSE *rp)
641592Srgrimes{
6590261Simp	CTL_MSG *ptr;
663793Sache	char *s;
671592Srgrimes
681592Srgrimes	rp->vers = TALK_VERSION;
691592Srgrimes	rp->type = mp->type;
701592Srgrimes	rp->id_num = htonl(0);
711592Srgrimes	if (mp->vers != TALK_VERSION) {
7231491Scharnier		syslog(LOG_WARNING, "bad protocol version %d", mp->vers);
731592Srgrimes		rp->answer = BADVERSION;
741592Srgrimes		return;
751592Srgrimes	}
761592Srgrimes	mp->id_num = ntohl(mp->id_num);
771592Srgrimes	mp->addr.sa_family = ntohs(mp->addr.sa_family);
781592Srgrimes	if (mp->addr.sa_family != AF_INET) {
7931491Scharnier		syslog(LOG_WARNING, "bad address, family %d",
801592Srgrimes		    mp->addr.sa_family);
811592Srgrimes		rp->answer = BADADDR;
821592Srgrimes		return;
831592Srgrimes	}
841592Srgrimes	mp->ctl_addr.sa_family = ntohs(mp->ctl_addr.sa_family);
851592Srgrimes	if (mp->ctl_addr.sa_family != AF_INET) {
8631491Scharnier		syslog(LOG_WARNING, "bad control address, family %d",
871592Srgrimes		    mp->ctl_addr.sa_family);
881592Srgrimes		rp->answer = BADCTLADDR;
891592Srgrimes		return;
901592Srgrimes	}
913793Sache	for (s = mp->l_name; *s; s++)
923793Sache		if (!isprint(*s)) {
9331491Scharnier			syslog(LOG_NOTICE, "illegal user name. Aborting");
943793Sache			rp->answer = FAILED;
953793Sache			return;
963793Sache		}
971592Srgrimes	mp->pid = ntohl(mp->pid);
981592Srgrimes	if (debug)
991592Srgrimes		print_request("process_request", mp);
1001592Srgrimes	switch (mp->type) {
1011592Srgrimes
1021592Srgrimes	case ANNOUNCE:
1031592Srgrimes		do_announce(mp, rp);
1041592Srgrimes		break;
1051592Srgrimes
1061592Srgrimes	case LEAVE_INVITE:
1071592Srgrimes		ptr = find_request(mp);
1081592Srgrimes		if (ptr != (CTL_MSG *)0) {
1091592Srgrimes			rp->id_num = htonl(ptr->id_num);
1101592Srgrimes			rp->answer = SUCCESS;
1111592Srgrimes		} else
1121592Srgrimes			insert_table(mp, rp);
1131592Srgrimes		break;
1141592Srgrimes
1151592Srgrimes	case LOOK_UP:
1161592Srgrimes		ptr = find_match(mp);
1171592Srgrimes		if (ptr != (CTL_MSG *)0) {
1181592Srgrimes			rp->id_num = htonl(ptr->id_num);
1191592Srgrimes			rp->addr = ptr->addr;
1201592Srgrimes			rp->addr.sa_family = htons(ptr->addr.sa_family);
1211592Srgrimes			rp->answer = SUCCESS;
1221592Srgrimes		} else
1231592Srgrimes			rp->answer = NOT_HERE;
1241592Srgrimes		break;
1251592Srgrimes
1261592Srgrimes	case DELETE:
1271592Srgrimes		rp->answer = delete_invite(mp->id_num);
1281592Srgrimes		break;
1291592Srgrimes
1301592Srgrimes	default:
1311592Srgrimes		rp->answer = UNKNOWN_REQUEST;
1321592Srgrimes		break;
1331592Srgrimes	}
1341592Srgrimes	if (debug)
1351592Srgrimes		print_response("process_request", rp);
1361592Srgrimes}
1371592Srgrimes
13831491Scharniervoid
13990261Simpdo_announce(CTL_MSG *mp, CTL_RESPONSE *rp)
1401592Srgrimes{
1411592Srgrimes	struct hostent *hp;
1421592Srgrimes	CTL_MSG *ptr;
1431592Srgrimes	int result;
1441592Srgrimes
1451592Srgrimes	/* see if the user is logged */
1461592Srgrimes	result = find_user(mp->r_name, mp->r_tty);
1471592Srgrimes	if (result != SUCCESS) {
1481592Srgrimes		rp->answer = result;
1491592Srgrimes		return;
1501592Srgrimes	}
151201022Sed#define	satosin(sa)	((struct sockaddr_in *)(void *)(sa))
152201022Sed	hp = gethostbyaddr(&satosin(&mp->ctl_addr)->sin_addr,
1531592Srgrimes		sizeof (struct in_addr), AF_INET);
1541592Srgrimes	if (hp == (struct hostent *)0) {
1551592Srgrimes		rp->answer = MACHINE_UNKNOWN;
1561592Srgrimes		return;
1571592Srgrimes	}
1581592Srgrimes	ptr = find_request(mp);
1591592Srgrimes	if (ptr == (CTL_MSG *) 0) {
1601592Srgrimes		insert_table(mp, rp);
1611592Srgrimes		rp->answer = announce(mp, hp->h_name);
1621592Srgrimes		return;
1631592Srgrimes	}
1641592Srgrimes	if (mp->id_num > ptr->id_num) {
1651592Srgrimes		/*
1661592Srgrimes		 * This is an explicit re-announce, so update the id_num
1671592Srgrimes		 * field to avoid duplicates and re-announce the talk.
1681592Srgrimes		 */
1691592Srgrimes		ptr->id_num = new_id();
1701592Srgrimes		rp->id_num = htonl(ptr->id_num);
1711592Srgrimes		rp->answer = announce(mp, hp->h_name);
1721592Srgrimes	} else {
1731592Srgrimes		/* a duplicated request, so ignore it */
1741592Srgrimes		rp->id_num = htonl(ptr->id_num);
1751592Srgrimes		rp->answer = SUCCESS;
1761592Srgrimes	}
1771592Srgrimes}
1781592Srgrimes
1791592Srgrimes/*
1801592Srgrimes * Search utmp for the local user
1811592Srgrimes */
18231491Scharnierint
18390261Simpfind_user(const char *name, char *tty)
1841592Srgrimes{
185200983Sed	struct utmpx *ut;
1861592Srgrimes	int status;
1871592Srgrimes	struct stat statb;
18814783Sjkh	time_t best = 0;
189200983Sed	char ftty[sizeof(_PATH_DEV) - 1 + sizeof(ut->ut_line)];
1901592Srgrimes
191200983Sed	setutxent();
1921592Srgrimes	status = NOT_HERE;
1931592Srgrimes	(void) strcpy(ftty, _PATH_DEV);
194200983Sed	while ((ut = getutxent()) != NULL)
195200983Sed		if (ut->ut_type == USER_PROCESS &&
196200983Sed		    strcmp(ut->ut_user, name) == 0) {
19714783Sjkh			if (*tty == '\0' || best != 0) {
19814783Sjkh				if (best == 0)
19914783Sjkh					status = PERMISSION_DENIED;
2001592Srgrimes				/* no particular tty was requested */
2011592Srgrimes				(void) strcpy(ftty + sizeof(_PATH_DEV) - 1,
202200983Sed				    ut->ut_line);
2031592Srgrimes				if (stat(ftty, &statb) == 0) {
2041592Srgrimes					if (!(statb.st_mode & 020))
2051592Srgrimes						continue;
20614783Sjkh					if (statb.st_atime > best) {
20714783Sjkh						best = statb.st_atime;
208200983Sed						(void) strcpy(tty, ut->ut_line);
20914783Sjkh						status = SUCCESS;
21014783Sjkh						continue;
21114783Sjkh					}
2121592Srgrimes				}
2131592Srgrimes			}
214200983Sed			if (strcmp(ut->ut_line, tty) == 0) {
2151592Srgrimes				status = SUCCESS;
2161592Srgrimes				break;
2171592Srgrimes			}
2181592Srgrimes		}
219200983Sed	endutxent();
2201592Srgrimes	return (status);
2211592Srgrimes}
222