xref: /openbsd-src/usr.sbin/rpc.lockd/procs.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
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