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