1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1983, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#ifndef lint
33#if 0
34static char sccsid[] = "@(#)process.c	8.2 (Berkeley) 11/16/93";
35#endif
36static const char rcsid[] =
37  "$FreeBSD$";
38#endif /* not lint */
39
40/*
41 * process.c handles the requests, which can be of three types:
42 *	ANNOUNCE - announce to a user that a talk is wanted
43 *	LEAVE_INVITE - insert the request into the table
44 *	LOOK_UP - look up to see if a request is waiting in
45 *		  in the table for the local user
46 *	DELETE - delete invitation
47 */
48#include <sys/param.h>
49#include <sys/stat.h>
50#include <sys/socket.h>
51#include <netinet/in.h>
52#include <protocols/talkd.h>
53#include <ctype.h>
54#include <err.h>
55#include <netdb.h>
56#include <paths.h>
57#include <stdio.h>
58#include <string.h>
59#include <syslog.h>
60#include <utmpx.h>
61
62#include "extern.h"
63
64void
65process_request(CTL_MSG *mp, CTL_RESPONSE *rp)
66{
67	CTL_MSG *ptr;
68	char *s;
69
70	rp->vers = TALK_VERSION;
71	rp->type = mp->type;
72	rp->id_num = htonl(0);
73	if (mp->vers != TALK_VERSION) {
74		syslog(LOG_WARNING, "bad protocol version %d", mp->vers);
75		rp->answer = BADVERSION;
76		return;
77	}
78	mp->id_num = ntohl(mp->id_num);
79	mp->addr.sa_family = ntohs(mp->addr.sa_family);
80	if (mp->addr.sa_family != AF_INET) {
81		syslog(LOG_WARNING, "bad address, family %d",
82		    mp->addr.sa_family);
83		rp->answer = BADADDR;
84		return;
85	}
86	mp->ctl_addr.sa_family = ntohs(mp->ctl_addr.sa_family);
87	if (mp->ctl_addr.sa_family != AF_INET) {
88		syslog(LOG_WARNING, "bad control address, family %d",
89		    mp->ctl_addr.sa_family);
90		rp->answer = BADCTLADDR;
91		return;
92	}
93	for (s = mp->l_name; *s; s++)
94		if (!isprint(*s)) {
95			syslog(LOG_NOTICE, "illegal user name. Aborting");
96			rp->answer = FAILED;
97			return;
98		}
99	mp->pid = ntohl(mp->pid);
100	if (debug)
101		print_request("process_request", mp);
102	switch (mp->type) {
103
104	case ANNOUNCE:
105		do_announce(mp, rp);
106		break;
107
108	case LEAVE_INVITE:
109		ptr = find_request(mp);
110		if (ptr != (CTL_MSG *)0) {
111			rp->id_num = htonl(ptr->id_num);
112			rp->answer = SUCCESS;
113		} else
114			insert_table(mp, rp);
115		break;
116
117	case LOOK_UP:
118		ptr = find_match(mp);
119		if (ptr != (CTL_MSG *)0) {
120			rp->id_num = htonl(ptr->id_num);
121			rp->addr = ptr->addr;
122			rp->addr.sa_family = htons(ptr->addr.sa_family);
123			rp->answer = SUCCESS;
124		} else
125			rp->answer = NOT_HERE;
126		break;
127
128	case DELETE:
129		rp->answer = delete_invite(mp->id_num);
130		break;
131
132	default:
133		rp->answer = UNKNOWN_REQUEST;
134		break;
135	}
136	if (debug)
137		print_response("process_request", rp);
138}
139
140void
141do_announce(CTL_MSG *mp, CTL_RESPONSE *rp)
142{
143	struct hostent *hp;
144	CTL_MSG *ptr;
145	int result;
146
147	/* see if the user is logged */
148	result = find_user(mp->r_name, mp->r_tty);
149	if (result != SUCCESS) {
150		rp->answer = result;
151		return;
152	}
153#define	satosin(sa)	((struct sockaddr_in *)(void *)(sa))
154	hp = gethostbyaddr(&satosin(&mp->ctl_addr)->sin_addr,
155		sizeof (struct in_addr), AF_INET);
156	if (hp == (struct hostent *)0) {
157		rp->answer = MACHINE_UNKNOWN;
158		return;
159	}
160	ptr = find_request(mp);
161	if (ptr == (CTL_MSG *) 0) {
162		insert_table(mp, rp);
163		rp->answer = announce(mp, hp->h_name);
164		return;
165	}
166	if (mp->id_num > ptr->id_num) {
167		/*
168		 * This is an explicit re-announce, so update the id_num
169		 * field to avoid duplicates and re-announce the talk.
170		 */
171		ptr->id_num = new_id();
172		rp->id_num = htonl(ptr->id_num);
173		rp->answer = announce(mp, hp->h_name);
174	} else {
175		/* a duplicated request, so ignore it */
176		rp->id_num = htonl(ptr->id_num);
177		rp->answer = SUCCESS;
178	}
179}
180
181/*
182 * Search utmp for the local user
183 */
184int
185find_user(const char *name, char *tty)
186{
187	struct utmpx *ut;
188	int status;
189	struct stat statb;
190	time_t best = 0;
191	char ftty[sizeof(_PATH_DEV) - 1 + sizeof(ut->ut_line)];
192
193	setutxent();
194	status = NOT_HERE;
195	(void) strcpy(ftty, _PATH_DEV);
196	while ((ut = getutxent()) != NULL)
197		if (ut->ut_type == USER_PROCESS &&
198		    strcmp(ut->ut_user, name) == 0) {
199			if (*tty == '\0' || best != 0) {
200				if (best == 0)
201					status = PERMISSION_DENIED;
202				/* no particular tty was requested */
203				(void) strcpy(ftty + sizeof(_PATH_DEV) - 1,
204				    ut->ut_line);
205				if (stat(ftty, &statb) == 0) {
206					if (!(statb.st_mode & 020))
207						continue;
208					if (statb.st_atime > best) {
209						best = statb.st_atime;
210						(void) strcpy(tty, ut->ut_line);
211						status = SUCCESS;
212						continue;
213					}
214				}
215			}
216			if (strcmp(ut->ut_line, tty) == 0) {
217				status = SUCCESS;
218				break;
219			}
220		}
221	endutxent();
222	return (status);
223}
224