xref: /illumos-gate/usr/src/cmd/ypcmd/ypxfrd_server.c (revision fe803bd5f9b7924e4f8a4ec0dc40c2c38854d619)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 /* Portions Copyright 2005 Juergen Keil */
27 
28 #include <sys/types.h>
29 #include <signal.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <ndbm.h>
34 #include <rpc/rpc.h>
35 #include <rpc/svc.h>
36 #include <netinet/in.h>
37 #include <sys/socket.h>
38 #include <syslog.h>
39 #include "ypxfrd.h"
40 #include "ypsym.h"
41 #include "ypdefs.h"
42 /*
43  * Because this code hacks into DBM underneath its API it can't use the N2L
44  * shim in it's normal way. It thus includes shim.h instead of shim_hooks.h
45  * and has knowledge of shim internals. While copying the DBM files it does
46  * not lock them. This reflects the behavior of the pre N2L code.
47  */
48 #include "shim.h"
49 #include "yptol.h"
50 
51 #if (defined(vax) || defined(i386))
52 #define	DOSWAB 1
53 #endif
54 
55 USE_YP_SECURE
56 
57 /* per connection stuff */
58 struct mycon {
59 	map_ctrl *map;
60 	int	lblk;
61 	int	firstd;
62 	datum	key;
63 };
64 
65 bool_t xdr_myfyl(XDR *xdrs, struct mycon *objp);
66 bool_t xdr_pages(XDR *xdrs, struct mycon *m);
67 bool_t xdr_dirs(XDR *xdrs, struct mycon *m);
68 
69 int mygetdir(char *block, int *no, struct mycon *m);
70 int mygetpage(char *block, int *pageno, struct mycon *m);
71 
72 datum mydbm_topkey(DBM *db, datum okey);
73 datum dbm_do_nextkey();
74 datum shim_dbm_do_nextkey();
75 
76 extern void get_secure_nets(char *);
77 extern int check_secure_net_ti(struct netbuf *, char *);
78 extern int _main(int, char **);
79 
80 int
81 main(int argc, char **argv)
82 {
83 	int connmaxrec = RPC_MAXDATASIZE;
84 
85 	/* load up the securenet file */
86 	get_secure_nets(argv[0]);
87 
88 	/*
89 	 * Set non-blocking mode and maximum record size for
90 	 * connection oriented RPC transports.
91 	 */
92 	if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
93 		syslog(LOG_INFO|LOG_DAEMON,
94 			"unable to set maximum RPC record size");
95 	}
96 
97 	/* Initialize file locking etc. */
98 	if (!init_lock_system(TRUE))
99 		/* An detailed error will already have been logged */
100 		exit(-1);
101 
102 	return (_main(argc, argv));
103 }
104 
105 /*
106  * In yptol mode we may start a cache update thread within a child process.
107  * It is thus important that child processes do not exit, killing any such
108  * threads, before the thread has completed. They must thus call this version
109  * of the exit() function.
110  */
111 void
112 yptol_exit(int status)
113 {
114 	if (yptol_mode) {
115 		thr_join(0, NULL, NULL);
116 	}
117 	exit(status);
118 }
119 
120 dbmfyl *
121 getdbm_1_svc(hosereq *argp, struct svc_req *rqstp)
122 {
123 	static dbmfyl  result;
124 	char path[MAXNAMLEN + 1];
125 	SVCXPRT *xprt;
126 	int pid;
127 	int res;
128 	struct mycon m;
129 	char *ypname = "ypxfrd";
130 	struct netbuf *nbuf;
131 	sa_family_t af;
132 	in_port_t port;
133 
134 	xprt = rqstp->rq_xprt;
135 
136 	signal(SIGPIPE, SIG_IGN);
137 	signal(SIGCHLD, SIG_IGN);
138 
139 	/*
140 	 * Build up path name. If we are working in N2L mode also conv
141 	 * to the new N2L style mapname.
142 	 *
143 	 * Do not allow any path as a domain name or map name.
144 	 */
145 	if ((strchr(argp->domain, '/') != NULL) ||
146 		(strchr(argp->map, '/') != NULL) ||
147 		(!ypmkfilename(argp->domain, argp->map, (char *)&path))) {
148 		res = GETDBM_ERROR;
149 		if (!svc_sendreply(rqstp->rq_xprt, xdr_answer,
150 					(caddr_t)&res)) {
151 			svcerr_systemerr(rqstp->rq_xprt);
152 		}
153 		return (NULL);
154 	}
155 
156 	pid = fork1();
157 	if (pid < 0) {
158 		perror("fork");
159 
160 		res = GETDBM_ERROR;
161 		if (!svc_sendreply(rqstp->rq_xprt, xdr_answer,
162 					(caddr_t)&res)) {
163 			svcerr_systemerr(rqstp->rq_xprt);
164 		}
165 		return (NULL);
166 	}
167 	if (pid != 0)
168 		return (NULL);
169 
170 	m.map = (map_ctrl *)shim_dbm_open(path, 0, 0);
171 	if (m.map == NULL) {
172 		perror(path);
173 		res = GETDBM_ERROR;
174 		if (!svc_sendreply(rqstp->rq_xprt, xdr_answer,
175 					(caddr_t)&res)) {
176 		    svcerr_systemerr(rqstp->rq_xprt);
177 		}
178 		yptol_exit(0);
179 		return (NULL);
180 	}
181 
182 	/* Do the security thing */
183 	if ((nbuf = svc_getrpccaller(xprt)) == 0) {
184 		res = GETDBM_ERROR;
185 		if (!svc_sendreply(xprt, xdr_answer, (caddr_t)&res)) {
186 			svcerr_systemerr(xprt);
187 		}
188 		shim_dbm_close((DBM *)m.map);
189 		yptol_exit(0);
190 		return (NULL);
191 	}
192 	if (!check_secure_net_ti(nbuf, ypname)) {
193 		res = GETDBM_ERROR;
194 		if (!svc_sendreply(xprt, xdr_answer, (caddr_t)&res)) {
195 			svcerr_systemerr(xprt);
196 		}
197 		shim_dbm_close((DBM *)m.map);
198 		yptol_exit(1);
199 		return (NULL);
200 	}
201 
202 	af = ((struct sockaddr_storage *)nbuf->buf)->ss_family;
203 	port = (af == AF_INET6) ?
204 		((struct sockaddr_in6 *)nbuf->buf)->sin6_port :
205 		((struct sockaddr_in  *)nbuf->buf)->sin_port;
206 
207 	if ((af == AF_INET || af == AF_INET6) &&
208 		(ntohs(port) > IPPORT_RESERVED)) {
209 		datum key, val;
210 
211 		key.dptr = yp_secure;
212 		key.dsize = yp_secure_sz;
213 		val = shim_dbm_fetch((DBM *)m.map, key);
214 		if (val.dptr != NULL) {
215 			res = GETDBM_ERROR;
216 			if (!svc_sendreply(xprt, xdr_answer, (caddr_t)&res)) {
217 				svcerr_systemerr(xprt);
218 			}
219 			shim_dbm_close((DBM *)m.map);
220 			yptol_exit(1);
221 			return (NULL);
222 		}
223 	}
224 
225 	/* OK, we're through */
226 	m.key = shim_dbm_firstkey((DBM *)m.map);
227 
228 	m.lblk = -1;
229 	m.firstd = 0;
230 
231 	if (!svc_sendreply(rqstp->rq_xprt, xdr_myfyl, (caddr_t)&m)) {
232 		svcerr_systemerr(rqstp->rq_xprt);
233 	}
234 	shim_dbm_close((DBM *)m.map);
235 	yptol_exit(0);
236 
237 	return (&result);
238 }
239 
240 bool_t
241 xdr_myfyl(XDR *xdrs, struct mycon *objp)
242 {
243 	int	ans = OK;
244 
245 	if (!xdr_answer(xdrs, (answer *) &ans))
246 		return (FALSE);
247 	if (!xdr_pages(xdrs, objp))
248 		return (FALSE);
249 	if (!xdr_dirs(xdrs, objp))
250 		return (FALSE);
251 
252 	return (TRUE);
253 }
254 
255 bool_t
256 xdr_pages(XDR *xdrs, struct mycon *m)
257 {
258 	static	struct pag res;
259 	bool_t	false = FALSE;
260 	bool_t	true = TRUE;
261 #ifdef DOSWAB
262 	short	*s;
263 	int	i;
264 	int	cnt;
265 #endif
266 	res.status = mygetpage(res.pag_u.ok.blkdat, &(res.pag_u.ok.blkno), m);
267 
268 #ifdef DOSWAB
269 	if (res.status == OK) {
270 		s = (short *)res.pag_u.ok.blkdat;
271 		cnt = s[0];
272 		for (i = 0; i <= cnt; i++)
273 			s[i] = ntohs(s[i]);
274 	}
275 #endif
276 
277 	if (!xdr_pag(xdrs, &res))
278 		return (FALSE);
279 
280 	while (res.status == OK) {
281 		if (!xdr_bool(xdrs, &true))
282 			return (FALSE);
283 		res.status = mygetpage(res.pag_u.ok.blkdat,
284 					&(res.pag_u.ok.blkno), m);
285 
286 #ifdef DOSWAB
287 		if (res.status == OK) {
288 			s = (short *)res.pag_u.ok.blkdat;
289 			cnt = s[0];
290 			for (i = 0; i <= cnt; i++)
291 				s[i] = ntohs(s[i]);
292 		}
293 #endif
294 
295 		if (!xdr_pag(xdrs, &res))
296 			return (FALSE);
297 	}
298 
299 	return (xdr_bool(xdrs, &false));
300 }
301 
302 int
303 mygetdir(char *block, int *no, struct mycon *m)
304 {
305 	int	status;
306 	int	len;
307 
308 	if (m->firstd == 0) {
309 		lseek(m->map->entries->dbm_dirf, 0, 0);
310 		m->firstd = 1;
311 	} else
312 		m->firstd++;
313 
314 	len = read(m->map->entries->dbm_dirf, block, DBLKSIZ);
315 	*no = (m->firstd) - 1;
316 	status = OK;
317 
318 	/*
319 	 * printf("dir block %d\n", (m->firstd) - 1);
320 	 */
321 
322 	if (len < 0) {
323 		perror("read directory");
324 		status = GETDBM_ERROR;
325 	} else if (len == 0) {
326 		status = GETDBM_EOF;
327 		/*
328 		 * printf("dir EOF\n");
329 		 */
330 	}
331 	return (status);
332 }
333 
334 bool_t
335 xdr_dirs(XDR *xdrs, struct mycon *m)
336 {
337 	static	struct dir res;
338 	bool_t	false = FALSE;
339 	bool_t	true = TRUE;
340 
341 	res.status = mygetdir(res.dir_u.ok.blkdat, &(res.dir_u.ok.blkno), m);
342 
343 	if (!xdr_dir(xdrs, &res))
344 		return (FALSE);
345 
346 	while (res.status == OK) {
347 		if (!xdr_bool(xdrs, &true))
348 			return (FALSE);
349 		res.status = mygetdir(res.dir_u.ok.blkdat,
350 					&(res.dir_u.ok.blkno), m);
351 		if (!xdr_dir(xdrs, &res))
352 			return (FALSE);
353 	}
354 
355 	return (xdr_bool(xdrs, &false));
356 }
357 
358 int
359 mygetpage(char *block, int *pageno, struct mycon *m)
360 {
361 
362 	for (; m->key.dptr;
363 			m->key = shim_dbm_do_nextkey((DBM *)m->map, m->key)) {
364 
365 		if (m->map->entries->dbm_pagbno != m->lblk) {
366 			/*
367 			 * printf("block=%d lblk=%d\n",
368 			 *		m->map->entries->dbm_pagbno,
369 			 * 		m->lblk);
370 			 */
371 			m->lblk = m->map->entries->dbm_pagbno;
372 			*pageno = m->lblk;
373 			memmove(block, m->map->entries->dbm_pagbuf, PBLKSIZ);
374 			/* advance key on first  try	*/
375 			m->key = mydbm_topkey(m->map->entries, m->key);
376 			m->key = shim_dbm_do_nextkey((DBM *)m->map, m->key);
377 			return (OK);
378 		}
379 	}
380 	/*
381 	 * printf("EOF\n");
382 	 */
383 	return (GETDBM_EOF);
384 }
385 
386 datum
387 mydbm_topkey(DBM *db, datum okey)
388 {
389 	datum		ans;
390 	datum		tmp;
391 	register char	*buf;
392 	int		n;
393 	register short	*sp;
394 	register short 	t;
395 	datum		item;
396 #if defined(_XPG4_2)
397 	register size_t	m;
398 #else
399 	register long	m;
400 #endif
401 	register char	*p1, *p2;
402 
403 	buf = db->dbm_pagbuf;
404 	sp = (short *)buf;
405 	/* find the maximum key in cmpdatum order */
406 
407 	if ((unsigned)0 >= sp[0]) {
408 		return (okey);
409 	} else {
410 		ans.dptr = buf + sp[1];
411 		ans.dsize = PBLKSIZ - sp[1];
412 	}
413 	for (n = 2; ; n += 2) {
414 		if ((unsigned)n >= sp[0]) {
415 			if (ans.dptr == NULL) {
416 				return (okey);
417 			} else {
418 				return (ans);
419 			}
420 		} else {
421 			t = PBLKSIZ;
422 			if (n > 0)
423 				t = sp[n];
424 			tmp.dptr = buf + sp[n + 1];
425 			tmp.dsize = t - sp[n + 1];
426 		}
427 
428 		m = tmp.dsize;
429 		if (m != ans.dsize) {
430 			if ((m - ans.dsize) < 0)
431 				ans = tmp;
432 		} else if (m == 0) {
433 		} else {
434 			p1 = tmp.dptr;
435 			p2 = ans.dptr;
436 			do
437 				if (*p1++ != *p2++) {
438 					if ((*--p1 - *--p2) < 0)
439 						ans = tmp;
440 				break;
441 				}
442 			while (--m);
443 		}
444 	}
445 }
446