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
main(int argc,char ** argv)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
yptol_exit(int status)112 yptol_exit(int status)
113 {
114 if (yptol_mode) {
115 thr_join(0, NULL, NULL);
116 }
117 exit(status);
118 }
119
120 dbmfyl *
getdbm_1_svc(hosereq * argp,struct svc_req * rqstp)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
xdr_myfyl(XDR * xdrs,struct mycon * objp)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
xdr_pages(XDR * xdrs,struct mycon * m)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
mygetdir(char * block,int * no,struct mycon * m)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
xdr_dirs(XDR * xdrs,struct mycon * m)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
mygetpage(char * block,int * pageno,struct mycon * m)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
mydbm_topkey(DBM * db,datum okey)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