xref: /openbsd/libexec/talkd/process.c (revision c9899b11)
1 /*	$OpenBSD: process.c,v 1.23 2016/03/16 15:41:10 krw Exp $	*/
2 
3 /*
4  * Copyright (c) 1983 Regents of the University of California.
5  * 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 /*
33  * process.c handles the requests, which can be of three types:
34  *	ANNOUNCE - announce to a user that a talk is wanted
35  *	LEAVE_INVITE - insert the request into the table
36  *	LOOK_UP - look up to see if a request is waiting in
37  *		  in the table for the local user
38  *	DELETE - delete invitation
39  */
40 #include <sys/socket.h>
41 #include <sys/stat.h>
42 #include <arpa/inet.h>
43 #include <protocols/talkd.h>
44 
45 #include <ctype.h>
46 #include <limits.h>
47 #include <netdb.h>
48 #include <paths.h>
49 #include <stdio.h>
50 #include <string.h>
51 #include <syslog.h>
52 #include <utmp.h>
53 
54 #include "talkd.h"
55 
56 #define	satosin(sa)	((struct sockaddr_in *)(sa))
57 
58 void
process_request(CTL_MSG * mp,CTL_RESPONSE * rp)59 process_request(CTL_MSG *mp, CTL_RESPONSE *rp)
60 {
61 	CTL_MSG *ptr;
62 	char *s;
63 
64 	rp->vers = TALK_VERSION;
65 	rp->type = mp->type;
66 	rp->id_num = htonl(0);
67 	if (mp->vers != TALK_VERSION) {
68 		syslog(LOG_WARNING, "Bad protocol version %d", mp->vers);
69 		rp->answer = BADVERSION;
70 		return;
71 	}
72 	mp->id_num = ntohl(mp->id_num);
73 	if (ntohs(mp->addr.sa_family) != AF_INET) {
74 		syslog(LOG_WARNING, "Bad address, family %d",
75 		    ntohs(mp->addr.sa_family));
76 		rp->answer = BADADDR;
77 		return;
78 	}
79 	if (ntohs(mp->ctl_addr.sa_family) != AF_INET) {
80 		syslog(LOG_WARNING, "Bad control address, family %d",
81 		    ntohs(mp->ctl_addr.sa_family));
82 		rp->answer = BADCTLADDR;
83 		return;
84 	}
85 	for (s = mp->l_name; *s; s++)
86 		if (!isprint((unsigned char)*s)) {
87 			syslog(LOG_NOTICE, "Illegal user name. Aborting");
88 			rp->answer = FAILED;
89 			return;
90 		}
91 	if (memcmp(&satosin(&rp->addr)->sin_addr,
92 	    &satosin(&mp->ctl_addr)->sin_addr,
93 	    sizeof(struct in_addr))) {
94 		char buf1[32], buf2[32];
95 
96 		strlcpy(buf1, inet_ntoa(satosin(&rp->addr)->sin_addr),
97 		    sizeof(buf1));
98 		strlcpy(buf2, inet_ntoa(satosin(&mp->ctl_addr)->sin_addr),
99 		    sizeof(buf2));
100 		syslog(LOG_WARNING, "addresses are different, %s != %s",
101 		    buf1, buf2);
102 	}
103 	rp->addr.sa_family = 0;
104 	mp->pid = ntohl(mp->pid);
105 	if (debug)
106 		print_request("process_request", mp);
107 	switch (mp->type) {
108 
109 	case ANNOUNCE:
110 		do_announce(mp, rp);
111 		break;
112 
113 	case LEAVE_INVITE:
114 		ptr = find_request(mp);
115 		if (ptr != NULL) {
116 			rp->id_num = htonl(ptr->id_num);
117 			rp->answer = SUCCESS;
118 		} else
119 			insert_table(mp, rp);
120 		break;
121 
122 	case LOOK_UP:
123 		ptr = find_match(mp);
124 		if (ptr != NULL) {
125 			rp->id_num = htonl(ptr->id_num);
126 			rp->addr = ptr->addr;
127 			rp->addr.sa_family = ptr->addr.sa_family;
128 			rp->answer = SUCCESS;
129 		} else
130 			rp->answer = NOT_HERE;
131 		break;
132 
133 	case DELETE:
134 		rp->answer = delete_invite(mp->id_num);
135 		break;
136 
137 	default:
138 		rp->answer = UNKNOWN_REQUEST;
139 		break;
140 	}
141 	if (debug)
142 		print_response("process_request", rp);
143 }
144 
145 void
do_announce(CTL_MSG * mp,CTL_RESPONSE * rp)146 do_announce(CTL_MSG *mp, CTL_RESPONSE *rp)
147 {
148 	struct hostent *hp;
149 	CTL_MSG *ptr;
150 	int result;
151 
152 	/* see if the user is logged */
153 	result = find_user(mp->r_name, mp->r_tty, sizeof(mp->r_tty));
154 	if (result != SUCCESS) {
155 		rp->answer = result;
156 		return;
157 	}
158 	hp = gethostbyaddr((char *)&satosin(&mp->ctl_addr)->sin_addr,
159 		sizeof(struct in_addr), AF_INET);
160 	if (hp == NULL) {
161 		rp->answer = MACHINE_UNKNOWN;
162 		return;
163 	}
164 	ptr = find_request(mp);
165 	if (ptr == (CTL_MSG *) 0) {
166 		insert_table(mp, rp);
167 		rp->answer = announce(mp, hp->h_name);
168 		return;
169 	}
170 	if (mp->id_num > ptr->id_num) {
171 		/*
172 		 * This is an explicit re-announce, so update the id_num
173 		 * field to avoid duplicates and re-announce the talk.
174 		 */
175 		ptr->id_num = new_id();
176 		rp->id_num = htonl(ptr->id_num);
177 		rp->answer = announce(mp, hp->h_name);
178 	} else {
179 		/* a duplicated request, so ignore it */
180 		rp->id_num = htonl(ptr->id_num);
181 		rp->answer = SUCCESS;
182 	}
183 }
184 
185 /*
186  * Search utmp for the local user
187  */
188 int
find_user(char * name,char * tty,size_t ttyl)189 find_user(char *name, char *tty, size_t ttyl)
190 {
191 	struct utmp ubuf, ubuf1;
192 	int status;
193 	FILE *fp;
194 	char line[UT_LINESIZE+1];
195 	char ftty[PATH_MAX];
196 	time_t	idle, now;
197 
198 	time(&now);
199 	idle = INT_MAX;
200 	if ((fp = fopen(_PATH_UTMP, "r")) == NULL) {
201 		fprintf(stderr, "talkd: can't read %s.\n", _PATH_UTMP);
202 		return (FAILED);
203 	}
204 #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
205 	status = NOT_HERE;
206 	(void) strlcpy(ftty, _PATH_DEV, sizeof(ftty));
207 	while (fread((char *) &ubuf, sizeof(ubuf), 1, fp) == 1)
208 		if (SCMPN(ubuf.ut_name, name) == 0) {
209 			if (*tty == '\0') {
210 				/* no particular tty was requested */
211 				struct stat statb;
212 
213 				memcpy(line, ubuf.ut_line, UT_LINESIZE);
214 				line[sizeof(line)-1] = '\0';
215 				ftty[sizeof(_PATH_DEV)-1] = '\0';
216 				strlcat(ftty, line, sizeof(ftty));
217 				if (stat(ftty, &statb) == 0) {
218 					if (!(statb.st_mode & S_IWGRP)) {
219 						if (status == NOT_HERE)
220 							status = PERMISSION_DENIED;
221 					} else if (now - statb.st_atime < idle) {
222 						idle = now - statb.st_atime;
223 						status = SUCCESS;
224 						ubuf1 = ubuf;
225 					}
226 				}
227 			} else if (SCMPN(ubuf.ut_line, tty) == 0) {
228 				status = SUCCESS;
229 				break;
230 			}
231 		}
232 	fclose(fp);
233 	if (*tty == '\0' && status == SUCCESS) {
234 		memcpy(line, ubuf1.ut_line, UT_LINESIZE);
235 		line[sizeof(line)-1] = '\0';
236 		strlcpy(tty, line, ttyl);
237 	}
238 	return (status);
239 }
240