1 /* $OpenBSD: procs.c,v 1.9 2000/06/29 00:30:39 millert Exp $ */ 2 3 /* 4 * Copyright (c) 1995 5 * A.R. Gordon (andrew.gordon@net-tel.co.uk). 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. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed for the FreeBSD project 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 */ 35 36 #include <sys/param.h> 37 #include <sys/socket.h> 38 #include <netinet/in.h> 39 #include <rpc/rpc.h> 40 #include <rpc/pmap_clnt.h> 41 #include <rpcsvc/sm_inter.h> 42 #include "nlm_prot.h" 43 #include <arpa/inet.h> 44 #include <stdio.h> 45 #include <syslog.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <netdb.h> 49 50 #include "lockd.h" 51 52 #define CLIENT_CACHE_SIZE 64 /* No. of client sockets cached */ 53 #define CLIENT_CACHE_LIFETIME 120 /* In seconds */ 54 55 static void 56 log_from_addr(fun_name, req) 57 char *fun_name; 58 struct svc_req *req; 59 { 60 struct sockaddr_in *addr; 61 struct hostent *host; 62 char hostname_buf[MAXHOSTNAMELEN]; 63 64 addr = svc_getcaller(req->rq_xprt); 65 host = gethostbyaddr((char *) &(addr->sin_addr), addr->sin_len, AF_INET); 66 if (host) { 67 strncpy(hostname_buf, host->h_name, sizeof(hostname_buf) - 1); 68 hostname_buf[sizeof(hostname_buf) - 1] = '\0'; 69 } else 70 strcpy(hostname_buf, inet_ntoa(addr->sin_addr)); 71 syslog(LOG_DEBUG, "%s from %s", fun_name, hostname_buf); 72 } 73 74 75 static CLIENT *clnt_cache_ptr[CLIENT_CACHE_SIZE]; 76 static long clnt_cache_time[CLIENT_CACHE_SIZE]; /* time entry created */ 77 static struct in_addr clnt_cache_addr[CLIENT_CACHE_SIZE]; 78 static int clnt_cache_next_to_use = 0; 79 80 static CLIENT * 81 get_client(host_addr) 82 struct sockaddr_in *host_addr; 83 { 84 CLIENT *client; 85 int sock_no, i; 86 struct timeval retry_time, time_now; 87 88 gettimeofday(&time_now, NULL); 89 90 /* Search for the given client in the cache, zapping any expired */ 91 /* entries that we happen to notice in passing. */ 92 for (i = 0; i < CLIENT_CACHE_SIZE; i++) { 93 client = clnt_cache_ptr[i]; 94 if (client && 95 ((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME) < time_now.tv_sec)) { 96 /* Cache entry has expired. */ 97 if (debug_level > 3) 98 syslog(LOG_DEBUG, "Expired CLIENT* in cache"); 99 clnt_cache_time[i] = 0L; 100 clnt_destroy(client); 101 clnt_cache_ptr[i] = NULL; 102 client = NULL; 103 } 104 if (client && !memcmp(&clnt_cache_addr[i], &host_addr->sin_addr, 105 sizeof(struct in_addr))) { 106 /* Found it! */ 107 if (debug_level > 3) 108 syslog(LOG_DEBUG, "Found CLIENT* in cache"); 109 return (client); 110 } 111 } 112 113 /* Not found in cache. Free the next entry if it is in use */ 114 if (clnt_cache_ptr[clnt_cache_next_to_use]) { 115 clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]); 116 clnt_cache_ptr[clnt_cache_next_to_use] = NULL; 117 } 118 119 sock_no = RPC_ANYSOCK; 120 retry_time.tv_sec = 5; 121 retry_time.tv_usec = 0; 122 host_addr->sin_port = 0; 123 client = clntudp_create(host_addr, NLM_PROG, NLM_VERS, retry_time, &sock_no); 124 if (!client) { 125 syslog(LOG_ERR, "%s", clnt_spcreateerror("clntudp_create")); 126 syslog(LOG_ERR, "Unable to return result to %s", 127 inet_ntoa(host_addr->sin_addr)); 128 return (NULL); 129 } 130 clnt_cache_ptr[clnt_cache_next_to_use] = client; 131 clnt_cache_addr[clnt_cache_next_to_use] = host_addr->sin_addr; 132 clnt_cache_time[clnt_cache_next_to_use] = time_now.tv_sec; 133 if (++clnt_cache_next_to_use > CLIENT_CACHE_SIZE) 134 clnt_cache_next_to_use = 0; 135 136 retry_time.tv_sec = -1; 137 retry_time.tv_usec = -1; 138 clnt_control(client, CLSET_TIMEOUT, &retry_time); 139 140 if (debug_level > 3) 141 syslog(LOG_DEBUG, "Created CLIENT* for %s", 142 inet_ntoa(host_addr->sin_addr)); 143 return (client); 144 } 145 146 147 static void 148 transmit_result(opcode, result, req) 149 int opcode; 150 nlm_res *result; 151 struct svc_req *req; 152 { 153 static char dummy; 154 struct sockaddr_in *addr; 155 CLIENT *cli; 156 int success; 157 struct timeval timeo; 158 159 addr = svc_getcaller(req->rq_xprt); 160 if ((cli = get_client(addr))) { 161 timeo.tv_sec = 0; 162 timeo.tv_usec = 0; 163 164 success = clnt_call(cli, opcode, xdr_nlm_res, result, xdr_void, 165 &dummy, timeo); 166 if (debug_level > 2) 167 syslog(LOG_DEBUG, "clnt_call returns %d", success); 168 } 169 } 170 171 nlm_testres * 172 nlm_test_1_svc(arg, rqstp) 173 nlm_testargs *arg; 174 struct svc_req *rqstp; 175 { 176 static nlm_testres res; 177 178 if (debug_level) 179 log_from_addr("nlm_test", rqstp); 180 res.cookie = arg->cookie; 181 res.stat.stat = nlm_granted; 182 return (&res); 183 } 184 185 void * 186 nlm_test_msg_1_svc(arg, rqstp) 187 nlm_testargs *arg; 188 struct svc_req *rqstp; 189 { 190 nlm_testres res; 191 static char dummy; 192 struct sockaddr_in *addr; 193 CLIENT *cli; 194 int success; 195 struct timeval timeo; 196 197 if (debug_level) 198 log_from_addr("nlm_test_msg", rqstp); 199 200 res.cookie = arg->cookie; 201 res.stat.stat = nlm_granted; 202 203 addr = svc_getcaller(rqstp->rq_xprt); 204 if ((cli = get_client(addr))) { 205 timeo.tv_sec = 0; 206 timeo.tv_usec = 0; 207 success = clnt_call(cli, NLM_TEST_RES, xdr_nlm_testres, &res, xdr_void, 208 &dummy, timeo); 209 if (debug_level > 2) 210 syslog(LOG_DEBUG, "clnt_call returns %d", success); 211 } 212 return (NULL); 213 } 214 215 nlm_res * 216 nlm_lock_1_svc(arg, rqstp) 217 nlm_lockargs *arg; 218 struct svc_req *rqstp; 219 { 220 static nlm_res res; 221 222 if (debug_level) 223 log_from_addr("nlm_lock", rqstp); 224 res.cookie = arg->cookie; 225 res.stat.stat = nlm_granted; 226 return (&res); 227 } 228 229 void * 230 nlm_lock_msg_1_svc(arg, rqstp) 231 nlm_lockargs *arg; 232 struct svc_req *rqstp; 233 { 234 static nlm_res res; 235 236 if (debug_level) 237 log_from_addr("nlm_lock_msg", rqstp); 238 res.cookie = arg->cookie; 239 res.stat.stat = nlm_granted; 240 transmit_result(NLM_LOCK_RES, &res, rqstp); 241 return (NULL); 242 } 243 244 nlm_res * 245 nlm_cancel_1_svc(arg, rqstp) 246 nlm_cancargs *arg; 247 struct svc_req *rqstp; 248 { 249 static nlm_res res; 250 251 if (debug_level) 252 log_from_addr("nlm_cancel", rqstp); 253 res.cookie = arg->cookie; 254 res.stat.stat = nlm_denied; 255 return (&res); 256 } 257 258 void * 259 nlm_cancel_msg_1_svc(arg, rqstp) 260 nlm_cancargs *arg; 261 struct svc_req *rqstp; 262 { 263 static nlm_res res; 264 265 if (debug_level) 266 log_from_addr("nlm_cancel_msg", rqstp); 267 res.cookie = arg->cookie; 268 res.stat.stat = nlm_denied; 269 transmit_result(NLM_CANCEL_RES, &res, rqstp); 270 return (NULL); 271 } 272 273 nlm_res * 274 nlm_unlock_1_svc(arg, rqstp) 275 nlm_unlockargs *arg; 276 struct svc_req *rqstp; 277 { 278 static nlm_res res; 279 280 if (debug_level) 281 log_from_addr("nlm_unlock", rqstp); 282 res.stat.stat = nlm_granted; 283 res.cookie = arg->cookie; 284 return (&res); 285 } 286 287 void * 288 nlm_unlock_msg_1_svc(arg, rqstp) 289 nlm_unlockargs *arg; 290 struct svc_req *rqstp; 291 { 292 static nlm_res res; 293 294 if (debug_level) 295 log_from_addr("nlm_unlock_msg", rqstp); 296 res.stat.stat = nlm_granted; 297 res.cookie = arg->cookie; 298 transmit_result(NLM_UNLOCK_RES, &res, rqstp); 299 return (NULL); 300 } 301 302 nlm_res * 303 nlm_granted_1_svc(arg, rqstp) 304 nlm_testargs *arg; 305 struct svc_req *rqstp; 306 { 307 static nlm_res res; 308 309 if (debug_level) 310 log_from_addr("nlm_granted", rqstp); 311 res.cookie = arg->cookie; 312 res.stat.stat = nlm_granted; 313 return (&res); 314 } 315 316 void * 317 nlm_granted_msg_1_svc(arg, rqstp) 318 nlm_testargs *arg; 319 struct svc_req *rqstp; 320 { 321 nlm_res res; 322 323 if (debug_level) 324 log_from_addr("nlm_granted_msg", rqstp); 325 res.cookie = arg->cookie; 326 res.stat.stat = nlm_granted; 327 transmit_result(NLM_GRANTED_RES, &res, rqstp); 328 return (NULL); 329 } 330 331 void * 332 nlm_test_res_1_svc(arg, rqstp) 333 nlm_testres *arg; 334 struct svc_req *rqstp; 335 { 336 if (debug_level) 337 log_from_addr("nlm_test_res", rqstp); 338 return (NULL); 339 } 340 341 void * 342 nlm_lock_res_1_svc(arg, rqstp) 343 nlm_res *arg; 344 struct svc_req *rqstp; 345 { 346 if (debug_level) 347 log_from_addr("nlm_lock_res", rqstp); 348 349 return (NULL); 350 } 351 352 void * 353 nlm_cancel_res_1_svc(arg, rqstp) 354 nlm_res *arg; 355 struct svc_req *rqstp; 356 { 357 if (debug_level) 358 log_from_addr("nlm_cancel_res", rqstp); 359 return (NULL); 360 } 361 362 void * 363 nlm_unlock_res_1_svc(arg, rqstp) 364 nlm_res *arg; 365 struct svc_req *rqstp; 366 { 367 if (debug_level) 368 log_from_addr("nlm_unlock_res", rqstp); 369 return (NULL); 370 } 371 372 void * 373 nlm_granted_res_1_svc(arg, rqstp) 374 nlm_res *arg; 375 struct svc_req *rqstp; 376 { 377 if (debug_level) 378 log_from_addr("nlm_granted_res", rqstp); 379 return (NULL); 380 } 381 382 nlm_shareres * 383 nlm_share_3_svc(arg, rqstp) 384 nlm_shareargs *arg; 385 struct svc_req *rqstp; 386 { 387 static nlm_shareres res; 388 389 if (debug_level) 390 log_from_addr("nlm_share", rqstp); 391 res.cookie = arg->cookie; 392 res.stat = nlm_granted; 393 res.sequence = 1234356; /* X/Open says this field is ignored? */ 394 return (&res); 395 } 396 397 nlm_shareres * 398 nlm_unshare_3_svc(arg, rqstp) 399 nlm_shareargs *arg; 400 struct svc_req *rqstp; 401 { 402 static nlm_shareres res; 403 404 if (debug_level) 405 log_from_addr("nlm_unshare", rqstp); 406 res.cookie = arg->cookie; 407 res.stat = nlm_granted; 408 res.sequence = 1234356; /* X/Open says this field is ignored? */ 409 return (&res); 410 } 411 412 nlm_res * 413 nlm_nm_lock_3_svc(arg, rqstp) 414 nlm_lockargs *arg; 415 struct svc_req *rqstp; 416 { 417 static nlm_res res; 418 419 if (debug_level) 420 log_from_addr("nlm_nm_lock", rqstp); 421 res.cookie = arg->cookie; 422 res.stat.stat = nlm_granted; 423 return (&res); 424 } 425 426 void * 427 nlm_free_all_3_svc(arg, rqstp) 428 nlm_notify *arg; 429 struct svc_req *rqstp; 430 { 431 static char dummy; 432 433 if (debug_level) 434 log_from_addr("nlm_free_all", rqstp); 435 return (&dummy); 436 } 437