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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 
43 /*
44  * process.c handles the requests, which can be of three types:
45  *
46  * ANNOUNCE - announce to a user that a talk is wanted
47  *
48  * LEAVE_INVITE - insert the request into the table
49  *
50  * LOOK_UP - look up to see if a request is waiting in
51  * in the table for the local user
52  *
53  * DELETE - delete invitation
54  *
55  */
56 
57 #include <sys/types.h>
58 #include <sys/stat.h>
59 #include <fcntl.h>
60 #include <syslog.h>
61 #include <string.h>
62 #include <utmpx.h>
63 #include <unistd.h>
64 #include <stdlib.h>
65 #include <stdio.h>
66 #include "talkd_impl.h"
67 
68 static void do_announce(CTL_MSG *request, CTL_RESPONSE *response);
69 static int find_user(char *name, char *tty);
70 
71 void
process_request(CTL_MSG * request,CTL_RESPONSE * response)72 process_request(CTL_MSG *request, CTL_RESPONSE *response)
73 {
74 	CTL_MSG *ptr;
75 
76 	response->type = request->type;
77 	response->id_num = 0;
78 
79 	/*
80 	 * Check if any of the strings within the request structure aren't
81 	 * NUL terminated, and if so don't bother processing the request
82 	 * further.
83 	 */
84 	if ((memchr(request->l_name, '\0', sizeof (request->l_name)) == NULL) ||
85 	    (memchr(request->r_name, '\0', sizeof (request->r_name)) == NULL) ||
86 	    (memchr(request->r_tty, '\0', sizeof (request->r_tty)) == NULL)) {
87 		response->answer = FAILED;
88 		openlog("talk", 0, LOG_AUTH);
89 		syslog(LOG_CRIT, "malformed talk request\n");
90 		closelog();
91 		return;
92 	}
93 
94 	switch (request->type) {
95 
96 	    case ANNOUNCE :
97 
98 		do_announce(request, response);
99 		break;
100 
101 	    case LEAVE_INVITE :
102 
103 		ptr = find_request(request);
104 		if (ptr != NULL) {
105 			response->id_num = ptr->id_num;
106 			response->answer = SUCCESS;
107 		} else {
108 			insert_table(request, response);
109 		}
110 		break;
111 
112 	    case LOOK_UP :
113 
114 		ptr = find_match(request);
115 		if (ptr != NULL) {
116 			response->id_num = ptr->id_num;
117 			response->addr = ptr->addr;
118 			response->answer = SUCCESS;
119 		} else {
120 			response->answer = NOT_HERE;
121 		}
122 		break;
123 
124 	    case DELETE :
125 
126 		response->answer = delete_invite(request->id_num);
127 		break;
128 
129 	    default :
130 
131 		response->answer = UNKNOWN_REQUEST;
132 		break;
133 	}
134 }
135 
136 static void
do_announce(CTL_MSG * request,CTL_RESPONSE * response)137 do_announce(CTL_MSG *request, CTL_RESPONSE *response)
138 {
139 	struct hostent *hp;
140 	CTL_MSG *ptr;
141 	int result;
142 
143 	/*
144 	 * See if the user is logged.
145 	 */
146 	result = find_user(request->r_name, request->r_tty);
147 	if (result != SUCCESS) {
148 		response->answer = result;
149 		return;
150 	}
151 
152 	hp = gethostbyaddr((const char *)&request->ctl_addr.sin_addr,
153 	    sizeof (struct in_addr), AF_INET);
154 	if (hp == NULL) {
155 		response->answer = MACHINE_UNKNOWN;
156 		return;
157 	}
158 
159 	ptr = find_request(request);
160 	if (ptr == NULL) {
161 		insert_table(request, response);
162 		response->answer = announce(request, hp->h_name);
163 	} else if (request->id_num > ptr->id_num) {
164 		/*
165 		 * This is an explicit re-announce, so update the id_num
166 		 * field to avoid duplicates and re-announce the talk.
167 		 */
168 		ptr->id_num = response->id_num = new_id();
169 		response->answer = announce(request, hp->h_name);
170 	} else {
171 		/* a duplicated request, so ignore it */
172 		response->id_num = ptr->id_num;
173 		response->answer = SUCCESS;
174 	}
175 }
176 
177 /*
178  * Search utmp for the local user.
179  */
180 
181 static int
find_user(char * name,char * tty)182 find_user(char *name, char *tty)
183 {
184 	struct utmpx *ubuf;
185 	int tfd;
186 	char dev[MAXPATHLEN];
187 	struct stat stbuf;
188 	int problem = NOT_HERE;
189 
190 	setutxent();		/* reset the utmpx file */
191 
192 	while (ubuf = getutxent()) {
193 		if (ubuf->ut_type == USER_PROCESS &&
194 		    strncmp(ubuf->ut_user, name, sizeof (ubuf->ut_user)) == 0) {
195 			/*
196 			 * Check if this entry is really a tty.
197 			 */
198 			(void) snprintf(dev, sizeof (dev), "/dev/%.*s",
199 			    sizeof (ubuf->ut_line), ubuf->ut_line);
200 			if ((tfd = open(dev, O_WRONLY|O_NOCTTY)) == -1) {
201 				continue;
202 			}
203 			if (!isatty(tfd)) {
204 				(void) close(tfd);
205 				openlog("talk", 0, LOG_AUTH);
206 				syslog(LOG_CRIT, "%.*s in utmp is not a tty\n",
207 				    sizeof (ubuf->ut_line), ubuf->ut_line);
208 				closelog();
209 				continue;
210 			}
211 			if (*tty == '\0') {
212 				/*
213 				 * No particular tty was requested.
214 				 */
215 				if (fstat(tfd, &stbuf) < 0 ||
216 				    (stbuf.st_mode&020) == 0) {
217 					(void) close(tfd);
218 					problem = PERMISSION_DENIED;
219 					continue;
220 				}
221 				(void) close(tfd);
222 				(void) strlcpy(tty, ubuf->ut_line, TTY_SIZE);
223 				endutxent();	/* close the utmpx file */
224 				return (SUCCESS);
225 			}
226 			(void) close(tfd);
227 			if (strcmp(ubuf->ut_line, tty) == 0) {
228 				endutxent();	/* close the utmpx file */
229 				return (SUCCESS);
230 			}
231 		}
232 	}
233 
234 	endutxent();		/* close the utmpx file */
235 	return (problem);
236 }
237