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