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