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