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