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