1/*	$NetBSD: process.c,v 1.13 2009/03/16 01:04:32 lukem Exp $	*/
2
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#include <sys/cdefs.h>
33#ifndef lint
34#if 0
35static char sccsid[] = "@(#)process.c	8.2 (Berkeley) 11/16/93";
36#else
37__RCSID("$NetBSD: process.c,v 1.13 2009/03/16 01:04:32 lukem Exp $");
38#endif
39#endif /* not lint */
40
41/*
42 * process.c handles the requests, which can be of three types:
43 *	ANNOUNCE - announce to a user that a talk is wanted
44 *	LEAVE_INVITE - insert the request into the table
45 *	LOOK_UP - look up to see if a request is waiting in
46 *		  in the table for the local user
47 *	DELETE - delete invitation
48 */
49
50#include <sys/param.h>
51#include <sys/stat.h>
52#include <sys/socket.h>
53
54#include <netinet/in.h>
55
56#include <protocols/talkd.h>
57
58#include <netdb.h>
59#include <syslog.h>
60#include <stdio.h>
61#include <string.h>
62#include <paths.h>
63
64#include "extern.h"
65
66#include "utmpentry.h"
67
68void
69process_request(CTL_MSG *mp, CTL_RESPONSE *rp)
70{
71	CTL_MSG *ptr;
72
73	rp->vers = TALK_VERSION;
74	rp->type = mp->type;
75	rp->id_num = htonl(0);
76	mp->id_num = ntohl(mp->id_num);
77	mp->addr.sa_family = ntohs(mp->addr.sa_family);
78	mp->ctl_addr.sa_family = ntohs(mp->ctl_addr.sa_family);
79	mp->pid = ntohl(mp->pid);
80	if (mp->vers != TALK_VERSION) {
81		syslog(LOG_WARNING, "Bad protocol version %d", mp->vers);
82		rp->answer = BADVERSION;
83		return;
84	}
85	if (mp->addr.sa_family != AF_INET) {
86		syslog(LOG_WARNING, "Bad address, family %d",
87		    mp->addr.sa_family);
88		rp->answer = BADADDR;
89		return;
90	}
91	if (mp->ctl_addr.sa_family != AF_INET) {
92		syslog(LOG_WARNING, "Bad control address, family %d",
93		    mp->ctl_addr.sa_family);
94		rp->answer = BADCTLADDR;
95		return;
96	}
97	if (debug || logging)
98		print_request("request", mp);
99	switch (mp->type) {
100
101	case ANNOUNCE:
102		do_announce(mp, rp);
103		break;
104
105	case LEAVE_INVITE:
106		ptr = find_request(mp);
107		if (ptr != (CTL_MSG *)0) {
108			rp->id_num = htonl(ptr->id_num);
109			rp->answer = SUCCESS;
110		} else
111			insert_table(mp, rp);
112		break;
113
114	case LOOK_UP:
115		ptr = find_match(mp);
116		if (ptr != (CTL_MSG *)0) {
117			rp->id_num = htonl(ptr->id_num);
118			rp->addr = ptr->addr;
119			rp->addr.sa_family = htons(ptr->addr.sa_family);
120			rp->answer = SUCCESS;
121		} else
122			rp->answer = NOT_HERE;
123		break;
124
125	case DELETE:
126		rp->answer = delete_invite(mp->id_num);
127		break;
128
129	default:
130		rp->answer = UNKNOWN_REQUEST;
131		break;
132	}
133	if (debug)
134		print_response("process_request done", rp);
135}
136
137void
138do_announce(CTL_MSG *mp, CTL_RESPONSE *rp)
139{
140	CTL_MSG *ptr;
141	int result;
142	char hostname[NI_MAXHOST];
143	struct sockaddr sa;
144
145	tsa2sa(&sa, &mp->ctl_addr);
146
147	/* see if the user is logged */
148	result = find_user(mp->r_name, mp->r_tty, sizeof(mp->r_tty));
149	if (result != SUCCESS) {
150		rp->answer = result;
151		return;
152	}
153	if (getnameinfo(&sa, sa.sa_len, hostname, sizeof(hostname), NULL,
154	    0, 0)) {
155		rp->answer = MACHINE_UNKNOWN;
156		return;
157	}
158	ptr = find_request(mp);
159	if (ptr == (CTL_MSG *) 0) {
160		insert_table(mp, rp);
161		rp->answer = announce(mp, hostname);
162		return;
163	}
164	if (mp->id_num > ptr->id_num) {
165		/*
166		 * This is an explicit re-announce, so update the id_num
167		 * field to avoid duplicates and re-announce the talk.
168		 */
169		ptr->id_num = new_id();
170		rp->id_num = htonl(ptr->id_num);
171		rp->answer = announce(mp, hostname);
172	} else {
173		/* a duplicated request, so ignore it */
174		rp->id_num = htonl(ptr->id_num);
175		rp->answer = SUCCESS;
176	}
177}
178
179/*
180 * Search utmp for the local user
181 */
182int
183find_user(const char *name, char *tty, size_t ttysize)
184{
185	int status;
186	struct stat statb;
187	struct utmpentry *ep;
188	char ftty[sizeof(_PATH_DEV) + sizeof(ep->line)];
189	time_t atime = 0;
190	int anytty = 0;
191
192	(void)getutentries(NULL, &ep);
193
194	status = NOT_HERE;
195	(void) strlcpy(ftty, _PATH_DEV, sizeof(ftty));
196
197	if (*tty == '\0')
198		anytty = 1;
199
200	for (; ep; ep = ep->next) {
201		if (strcmp(ep->name, name) != 0)
202			continue;
203		if (anytty) {
204			/* no particular tty was requested */
205			(void)strlcpy(ftty + sizeof(_PATH_DEV) - 1, ep->line,
206			     sizeof(ftty) - sizeof(_PATH_DEV) + 1);
207			if (stat(ftty, &statb) != 0)
208				continue;
209
210			if (!(statb.st_mode & S_IWGRP)) {
211				if (status != SUCCESS)
212					status = PERMISSION_DENIED;
213				continue;
214			}
215			if (statb.st_atime > atime &&
216			    strlcpy(tty, ep->line, ttysize) < ttysize) {
217				atime = statb.st_atime;
218				status = SUCCESS;
219			}
220		} else if (strcmp(ep->line, tty) == 0) {
221			status = SUCCESS;
222			break;
223		}
224	}
225	return (status);
226}
227