1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 *
21 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
22 * Use is subject to license terms.
23 */
24
25 /*
26 * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
27 * All Rights Reserved.
28 */
29
30 /*
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California.
33 * All Rights Reserved.
34 *
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
37 * contributors.
38 */
39
40 /*
41 * process.c handles the requests, which can be of three types:
42 *
43 * ANNOUNCE - announce to a user that a talk is wanted
44 *
45 * LEAVE_INVITE - insert the request into the table
46 *
47 * LOOK_UP - look up to see if a request is waiting in
48 * in the table for the local user
49 *
50 * DELETE - delete invitation
51 *
52 */
53
54 #include <sys/types.h>
55 #include <sys/stat.h>
56 #include <fcntl.h>
57 #include <syslog.h>
58 #include <string.h>
59 #include <utmpx.h>
60 #include <unistd.h>
61 #include <stdlib.h>
62 #include <stdio.h>
63 #include "talkd_impl.h"
64
65 static void do_announce(CTL_MSG *request, CTL_RESPONSE *response);
66 static int find_user(char *name, char *tty);
67
68 void
process_request(CTL_MSG * request,CTL_RESPONSE * response)69 process_request(CTL_MSG *request, CTL_RESPONSE *response)
70 {
71 CTL_MSG *ptr;
72
73 response->type = request->type;
74 response->id_num = 0;
75
76 /*
77 * Check if any of the strings within the request structure aren't
78 * NUL terminated, and if so don't bother processing the request
79 * further.
80 */
81 if ((memchr(request->l_name, '\0', sizeof (request->l_name)) == NULL) ||
82 (memchr(request->r_name, '\0', sizeof (request->r_name)) == NULL) ||
83 (memchr(request->r_tty, '\0', sizeof (request->r_tty)) == NULL)) {
84 response->answer = FAILED;
85 openlog("talk", 0, LOG_AUTH);
86 syslog(LOG_CRIT, "malformed talk request\n");
87 closelog();
88 return;
89 }
90
91 switch (request->type) {
92
93 case ANNOUNCE :
94
95 do_announce(request, response);
96 break;
97
98 case LEAVE_INVITE :
99
100 ptr = find_request(request);
101 if (ptr != NULL) {
102 response->id_num = ptr->id_num;
103 response->answer = SUCCESS;
104 } else {
105 insert_table(request, response);
106 }
107 break;
108
109 case LOOK_UP :
110
111 ptr = find_match(request);
112 if (ptr != NULL) {
113 response->id_num = ptr->id_num;
114 response->addr = ptr->addr;
115 response->answer = SUCCESS;
116 } else {
117 response->answer = NOT_HERE;
118 }
119 break;
120
121 case DELETE :
122
123 response->answer = delete_invite(request->id_num);
124 break;
125
126 default :
127
128 response->answer = UNKNOWN_REQUEST;
129 break;
130 }
131 }
132
133 static void
do_announce(CTL_MSG * request,CTL_RESPONSE * response)134 do_announce(CTL_MSG *request, CTL_RESPONSE *response)
135 {
136 struct hostent *hp;
137 CTL_MSG *ptr;
138 int result;
139
140 /*
141 * See if the user is logged.
142 */
143 result = find_user(request->r_name, request->r_tty);
144 if (result != SUCCESS) {
145 response->answer = result;
146 return;
147 }
148
149 hp = gethostbyaddr((const char *)&request->ctl_addr.sin_addr,
150 sizeof (struct in_addr), AF_INET);
151 if (hp == NULL) {
152 response->answer = MACHINE_UNKNOWN;
153 return;
154 }
155
156 ptr = find_request(request);
157 if (ptr == NULL) {
158 insert_table(request, response);
159 response->answer = announce(request, hp->h_name);
160 } else if (request->id_num > ptr->id_num) {
161 /*
162 * This is an explicit re-announce, so update the id_num
163 * field to avoid duplicates and re-announce the talk.
164 */
165 ptr->id_num = response->id_num = new_id();
166 response->answer = announce(request, hp->h_name);
167 } else {
168 /* a duplicated request, so ignore it */
169 response->id_num = ptr->id_num;
170 response->answer = SUCCESS;
171 }
172 }
173
174 /*
175 * Search utmp for the local user.
176 */
177
178 static int
find_user(char * name,char * tty)179 find_user(char *name, char *tty)
180 {
181 struct utmpx *ubuf;
182 int tfd;
183 char dev[MAXPATHLEN];
184 struct stat stbuf;
185 int problem = NOT_HERE;
186
187 setutxent(); /* reset the utmpx file */
188
189 while (ubuf = getutxent()) {
190 if (ubuf->ut_type == USER_PROCESS &&
191 strncmp(ubuf->ut_user, name, sizeof (ubuf->ut_user)) == 0) {
192 /*
193 * Check if this entry is really a tty.
194 */
195 (void) snprintf(dev, sizeof (dev), "/dev/%.*s",
196 sizeof (ubuf->ut_line), ubuf->ut_line);
197 if ((tfd = open(dev, O_WRONLY|O_NOCTTY)) == -1) {
198 continue;
199 }
200 if (!isatty(tfd)) {
201 (void) close(tfd);
202 openlog("talk", 0, LOG_AUTH);
203 syslog(LOG_CRIT, "%.*s in utmp is not a tty\n",
204 sizeof (ubuf->ut_line), ubuf->ut_line);
205 closelog();
206 continue;
207 }
208 if (*tty == '\0') {
209 /*
210 * No particular tty was requested.
211 */
212 if (fstat(tfd, &stbuf) < 0 ||
213 (stbuf.st_mode&020) == 0) {
214 (void) close(tfd);
215 problem = PERMISSION_DENIED;
216 continue;
217 }
218 (void) close(tfd);
219 (void) strlcpy(tty, ubuf->ut_line, TTY_SIZE);
220 endutxent(); /* close the utmpx file */
221 return (SUCCESS);
222 }
223 (void) close(tfd);
224 if (strcmp(ubuf->ut_line, tty) == 0) {
225 endutxent(); /* close the utmpx file */
226 return (SUCCESS);
227 }
228 }
229 }
230
231 endutxent(); /* close the utmpx file */
232 return (problem);
233 }
234