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 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 112 yptol_exit(int status) 113 { 114 if (yptol_mode) { 115 thr_join(0, NULL, NULL); 116 } 117 exit(status); 118 } 119 120 dbmfyl * 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 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 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 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 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 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 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