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