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 |
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 |
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 |
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 |
|
|
} |