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