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 /* 24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 29 /* All Rights Reserved */ 30 31 32 /* 33 * data base routines for the network listener process 34 */ 35 36 /* system include files */ 37 38 #include <fcntl.h> 39 #include <stdio.h> 40 #include <string.h> 41 #include <ctype.h> 42 #include <sys/param.h> 43 #include <sys/types.h> 44 #include <sys/tiuser.h> 45 #include <sys/stropts.h> 46 47 /* listener include files */ 48 49 #include "lsparam.h" /* listener parameters */ 50 #include "listen.h" /* listener includes */ 51 #include "lsfiles.h" /* listener files info */ 52 #include "lserror.h" /* listener error codes */ 53 #include "lsdbf.h" /* data base file stuff */ 54 /* #include "nsaddr.h" nls includes */ 55 56 #define SUPPRESS 1 /* suppress messages during scan*/ 57 #define NOSUPPRESS 0 /* don't suppress messages */ 58 59 /* static data */ 60 61 static char *dbfopenmsg = "Trouble opening data base file"; 62 static char *dbfrderror = "Error reading data base file: line %d"; 63 static char *dbfbadlmsg = "Data base file: Error on line %d"; 64 static char *dbfdupcmsg = "Data base file: Duplicate service code: <%s>"; 65 static char *dbfunknown = "Unknown error reading data base file: line %d"; 66 static char *dbfsvccmsg = "Data base file: Illegal service code: <%s>"; 67 static char *dbfcorrupt = "Data base file has been corrupted"; 68 69 static int Dbflineno; /* current line number in dbf */ 70 static unsigned Dbfentries; /* number of non-comment lines */ 71 extern char *Server_cmd_lines; /* contains svc_code, cmd_line, mod_list */ 72 extern char *New_cmd_lines; /* svc_code, cmd_line, mod_list (on reread)*/ 73 74 /* public variables */ 75 76 77 /* 78 * read_dbf: 79 * 80 * read the data base file into internal structures 81 * 82 * all data base routines under read_dbf log there own errors and return -1 83 * in case of an error. 84 * 85 * if 're_read' is non-zero, this stuff is being called to read a new 86 * data base file after the listener's initialization. 87 */ 88 89 int 90 read_dbf(re_read) 91 int re_read; /* zero means first time */ 92 { 93 register unsigned size; 94 int exit_flag = EXIT | NOCORE; 95 register dbf_t *dbf_p; 96 register char *cmd_p; 97 unsigned scan_dbf(); 98 extern dbf_t *Dbfhead; /* Dbfentries (when allocated) */ 99 extern dbf_t *Newdbf; /* Dbfentries (on re-read) */ 100 extern char *calloc(); 101 102 DEBUG((9,"in read_dbf")); 103 104 if (check_version()) 105 error(E_BADVER, EXIT | NOCORE); 106 107 if (re_read) { /* not first time */ 108 exit_flag = CONTINUE; 109 } 110 111 /* 112 * note: data base routines log their own error messages 113 */ 114 115 Dbfentries = 0; 116 DEBUG((9,"read_dbf: open file here: %s", DBFNAME)); 117 if ( (size = scan_dbf(DBFNAME)) == (unsigned)(-1) ) 118 error( E_SCAN_DBF, exit_flag | NO_MSG ); 119 120 DEBUG((5,"read_dbf: scan complete: non-commented lines: %u, size: %u", 121 Dbfentries, size)); 122 123 if (!size) { 124 logmessage("No database? 0 entries?"); 125 return(0); 126 } 127 128 /* 129 * allocate enough space for Dbfentries of 'size' bytes (total) 130 * The +1 is to insure a NULL last entry! 131 */ 132 133 if (!(dbf_p = (dbf_t *)calloc(Dbfentries+1,sizeof(dbf_t))) 134 || !(cmd_p = calloc(size, 1))) { 135 DEBUG((1,"cannot calloc %u + %u bytes", size, 136 (Dbfentries+1)*(unsigned)sizeof(dbf_t))); 137 error( E_DBF_ALLOC, exit_flag); /* if init, exit */ 138 139 /* if still here, this is a re-read */ 140 141 if (dbf_p) 142 free(dbf_p); 143 if (cmd_p) 144 free(cmd_p); 145 return(-1); 146 } 147 148 if (get_dbf(dbf_p, cmd_p)) { 149 DEBUG((9, "get_dbf FAILED")); 150 error(E_DBF_IO, exit_flag | NO_MSG); 151 152 /* if still here, this is a re_read */ 153 free(dbf_p); 154 free(cmd_p); 155 return(-1); 156 } 157 158 if (re_read) { 159 Newdbf = dbf_p; 160 New_cmd_lines = cmd_p; 161 #ifdef DEBUGMODE 162 DEBUG((7,"read_dbf: NEW data base dump...")); 163 if (Newdbf) 164 for (dbf_p = Newdbf; dbf_p->dbf_svc_code; ++dbf_p) 165 DEBUG((7, "svc code <%s>; id: %s; private address: %s; modules: %s; cmd line: %s; sflags: %x, prognum: %d version: %d", 166 dbf_p->dbf_svc_code, dbf_p->dbf_id, dbf_p->dbf_prv_adr, dbf_p->dbf_modules, dbf_p->dbf_cmd_line, dbf_p->dbf_sflags, dbf_p->dbf_prognum, dbf_p->dbf_version)); 167 #endif /* DEBUGMODE */ 168 } 169 else { 170 Dbfhead = dbf_p; 171 Server_cmd_lines = cmd_p; 172 #ifdef DEBUGMODE 173 DEBUG((7,"read_dbf: data base dump...")); 174 if (Dbfhead) 175 for (dbf_p = Dbfhead; dbf_p->dbf_svc_code; ++dbf_p) 176 DEBUG((7, "svc code <%s>; id: %s; r1: %s; r2: %s; r3: %s; private address: %s; modules: %s; cmd line: %s; sflags: %x, prognum: %d version: %d", 177 dbf_p->dbf_svc_code, dbf_p->dbf_id, dbf_p->dbf_res1, dbf_p->dbf_res2, dbf_p->dbf_res3, dbf_p->dbf_prv_adr, dbf_p->dbf_modules, dbf_p->dbf_cmd_line, dbf_p->dbf_sflags, dbf_p->dbf_prognum, dbf_p->dbf_version)); 178 #endif /* DEBUGMODE */ 179 } 180 181 return(0); 182 } 183 184 185 /* 186 * get_dbf: read the file and fill the structures 187 * checking for duplicate entries as we go 188 */ 189 190 int 191 get_dbf(dbf_p, cmd_p) 192 register dbf_t *dbf_p; 193 register char *cmd_p; 194 { 195 dbf_t *dbfhead = dbf_p; 196 register int n, i; 197 char buf[DBFLINESZ]; 198 register char *p = buf; 199 char scratch[128]; 200 FILE *dbfilep; 201 char *cmd_line_p; 202 int flags; 203 char *svc_code_p; 204 char *id_p; 205 char *res1_p; 206 char *res2_p; 207 char *res3_p; 208 char *private_p; 209 int sflags; 210 int prognum; 211 int vernum; 212 char *module_p; 213 register dbf_t *tdbf_p; 214 extern int atoi(); 215 extern int Dbf_entries; 216 extern int NLPS_proc; 217 extern int errno; 218 219 Dbflineno = 0; 220 Dbf_entries = 0; /* number of private addresses in dbf file */ 221 222 DEBUG((9,"in get_dbf: ")); 223 if (!(dbfilep = fopen(DBFNAME,"r"))) { 224 logmessage(dbfopenmsg); 225 error(E_DBF_IO, EXIT | NOCORE | NO_MSG); 226 } 227 228 while (n = rd_dbf_line(dbfilep,p,&svc_code_p,&flags,&id_p,&res1_p,&res2_p,&res3_p,&private_p,&prognum,&vernum,&module_p,&sflags,&cmd_line_p,NOSUPPRESS)) { 229 230 if (n == -1) { /* read error */ 231 fclose(dbfilep); 232 return(-1); 233 } 234 235 /* make sure service code is legal */ 236 237 i = strlen(svc_code_p); 238 if ( (i == 0) || (i >= SVC_CODE_SZ) ) 239 goto reject; 240 241 /* check for duplicate service code */ 242 tdbf_p = dbfhead; 243 while (tdbf_p->dbf_svc_code) { /* duplicate svc code? */ 244 if (!strcmp(svc_code_p, tdbf_p->dbf_svc_code)) { 245 sprintf(scratch, dbfdupcmsg, svc_code_p); 246 logmessage(scratch); 247 return(-1); 248 } 249 ++tdbf_p; 250 } 251 252 /* NLPS_proc is set by the nlps_server, which also uses these 253 * routines. The actual listener child shouldn't ever need 254 * to read a database, so it will never be here 255 */ 256 if (!NLPS_proc && (strlen(private_p) == 0) && !(sflags & DFLAG)) 257 continue; /* ignore entries with no address */ 258 259 /* 260 * child doesn't care about private addresses 261 */ 262 263 if (!NLPS_proc) { 264 i = strlen(private_p); 265 if (i >= PRV_ADR_SZ) { 266 goto p_reject; 267 } 268 Dbf_entries++; 269 } 270 271 /* 272 * legal, non-duplicate entry: copy it into internal data base 273 */ 274 275 dbf_p->dbf_fd = -1; /* set to actual fd in add_prvaddr */ 276 dbf_p->dbf_flags = flags; 277 dbf_p->dbf_sflags = sflags; 278 dbf_p->dbf_prognum = prognum; 279 dbf_p->dbf_version = vernum; 280 strcpy(cmd_p, svc_code_p); 281 dbf_p->dbf_svc_code = cmd_p; 282 cmd_p += strlen(svc_code_p) + 1; /* +1 for null */ 283 strcpy(cmd_p, cmd_line_p); 284 dbf_p->dbf_cmd_line = cmd_p; 285 cmd_p += strlen(cmd_line_p) + 1; 286 strcpy(cmd_p, id_p); 287 dbf_p->dbf_id = cmd_p; 288 cmd_p += strlen(id_p) + 1; 289 strcpy(cmd_p, res1_p); 290 dbf_p->dbf_res1 = cmd_p; 291 cmd_p += strlen(res1_p) + 1; 292 strcpy(cmd_p, res2_p); 293 dbf_p->dbf_res2 = cmd_p; 294 cmd_p += strlen(res2_p) + 1; 295 strcpy(cmd_p, res3_p); 296 dbf_p->dbf_res3 = cmd_p; 297 cmd_p += strlen(res3_p) + 1; 298 if (strlen(private_p) != 0) { 299 strcpy(cmd_p, private_p); 300 dbf_p->dbf_prv_adr = cmd_p; 301 cmd_p += strlen(private_p) + 1; 302 } 303 else 304 dbf_p->dbf_prv_adr = NULL; 305 strcpy(cmd_p, module_p); 306 dbf_p->dbf_modules = cmd_p; 307 cmd_p += strlen(module_p) + 1; /* cmd line + null char */ 308 ++dbf_p; 309 } 310 311 fclose(dbfilep); 312 return(0); 313 314 reject: 315 DEBUG((9, "svc_code <%s> failed validation test", svc_code_p)); 316 sprintf(scratch, dbfsvccmsg, svc_code_p); 317 logmessage(scratch); 318 return(-1); 319 p_reject: 320 DEBUG((9,"private address <%s> failed validation test", private_p)); 321 sprintf(scratch, "Invalid private address ignored: \\x%x", private_p); 322 logmessage(scratch); 323 return(-1); 324 } 325 326 327 /* 328 * scan_dbf: Take a quick pass through the data base file to figure out 329 * approx. how many items in the file we'll need to 330 * allocate storage for. Essentially, returns the number 331 * of non-null, non-comment lines in the data base file. 332 * 333 * return: -1 == error. 334 * other == number of non-comment characters. 335 * Dbfentries set. 336 */ 337 338 unsigned 339 scan_dbf(path) 340 register char *path; 341 { 342 register unsigned int size = 0; 343 register int n; 344 register FILE *dbfilep; 345 char buf[DBFLINESZ]; 346 register char *p = buf; 347 char *svc_code_p; 348 int flags; 349 char *cmd_line_p; 350 char *module_p; 351 char *id_p; 352 char *res1_p; 353 char *res2_p; 354 char *res3_p; 355 int sflags; 356 int prognum; 357 int vernum; 358 char *private_p; 359 extern int errno; 360 361 DEBUG((9, "In scan_dbf. Scanning data base file %s.", path)); 362 363 if (!(dbfilep = fopen(path,"r"))) { 364 DEBUG((9,"errorno = %d", errno)); 365 logmessage(dbfopenmsg); 366 return(-1); 367 } 368 369 do { 370 n = rd_dbf_line(dbfilep,p,&svc_code_p,&flags,&id_p,&res1_p,&res2_p,&res3_p,&private_p,&prognum,&vernum,&module_p,&sflags,&cmd_line_p,SUPPRESS); 371 if (n == -1) { 372 fclose(dbfilep); 373 return(-1); 374 } 375 size += (unsigned)n; 376 if (n) 377 ++Dbfentries; 378 } while (n); 379 380 fclose(dbfilep); 381 return(size); 382 } 383 384 385 /* 386 * rd_dbf_line: Returns the next non-comment line into the 387 * given buffer (up to DBFLINESZ bytes). 388 * Skips 'ignore' lines. 389 * 390 * Returns: 0 = done, -1 = error, 391 * other = cmd line size incl. terminating null. 392 * *svc_code_p = service code; 393 * *id_p = user id string; 394 * *res1_p = reserved string; 395 * *res2_p = reserved string; 396 * *res3_p = reserved string; 397 * *private_p = contains private address; 398 * *flags_p = decoded flags; 399 * prognum = RPC program #; 400 * vernum = RPC version $; 401 * cnd_line_p points to null terminated cmd line; 402 * 403 * When logging errors, the extern Dbflineno is used. 404 */ 405 406 int 407 rd_dbf_line(fp, bp, svc_code_p, flags_p, id_p, res1_p, res2_p, res3_p, private_p, prognum, vernum, module_p, sflags, cmd_line_p, mflag) 408 register FILE *fp; 409 register char *bp; 410 char **svc_code_p; 411 int *flags_p; 412 char **id_p; 413 char **res1_p; 414 char **res2_p; 415 char **res3_p; 416 char **private_p; 417 int *prognum; 418 int *vernum; 419 char **module_p; 420 int *sflags; 421 char **cmd_line_p; 422 int mflag; 423 { 424 register int length; 425 register char *p; 426 427 do { 428 ++Dbflineno; 429 length = 0; 430 431 if (!fgets(bp, DBFLINESZ, fp)) { 432 if (feof(fp)) { 433 return(0); /* EOF */ 434 } 435 if (ferror(fp)) { 436 sprintf(bp,dbfrderror,Dbflineno); 437 logmessage(bp); 438 return(-1); 439 } 440 sprintf(bp,dbfunknown,Dbflineno); 441 logmessage(bp); 442 return(-1); /* Unknown error (?) */ 443 } 444 445 if (*(bp+strlen(bp)-1) != '\n') { /* terminating newline? */ 446 sprintf(bp, dbfbadlmsg, Dbflineno); 447 logmessage(bp); 448 return(-1); 449 } 450 451 *(bp + strlen(bp) -1) = (char)0; /* delete newline */ 452 453 if (strlen(bp) && (p = strchr(bp, DBFCOMMENT))) 454 *p = (char)0; /* delete comments */ 455 if (!strlen(bp)) 456 continue; 457 458 p = bp + strlen(bp) - 1; /* bp->start; p->end */ 459 while ((p != bp) && (isspace(*p))) { 460 *p = (char)0; /* delete terminating spaces */ 461 --p; 462 } 463 464 while (*bp) /* del beginning white space*/ 465 if (isspace(*bp)) 466 ++bp; 467 else 468 break; 469 470 if (strlen(bp)) { /* anything left? */ 471 472 if (!(length=scan_line(bp,svc_code_p,flags_p,id_p,res1_p,res2_p,res3_p,private_p,prognum,vernum,module_p,sflags,cmd_line_p,mflag))) { 473 474 DEBUG((1, "rd_dbf_line line %d, error while scanning entry", 475 Dbflineno)); 476 sprintf(bp, dbfbadlmsg, Dbflineno); 477 logmessage(bp); 478 return(-1); 479 } 480 } 481 482 } while (!length); /* until we have something */ 483 484 DEBUG((5,"rd_dbf_line: line: %d,cmd line len: %d",Dbflineno, length+1)); 485 486 return(length+1); /* +1 for the trailing NULL */ 487 488 } 489 490 491 /* 492 * scan a non-white space line 493 * 0 = error; 494 * other = length of cmd line; 495 * 496 * non-null lines have the following format: 497 * 498 * service_code: flags: id: res1: res2: res3: private address: rpcdata: sflags: modules: cmd_line # comments 499 * 500 * mflag is set to suppress messages (scan_line is called both for parsing 501 * and counting, messages should only be output once) 502 */ 503 504 int 505 scan_line(bp, svc_code_p, flags_p, id_p, res1_p, res2_p, res3_p, private_p, prognum, vernum, module_p, sflags, cmd_line_p, mflag) 506 register char *bp; 507 char **svc_code_p; 508 register int *flags_p; 509 char **id_p; 510 char **res1_p; 511 char **res2_p; 512 char **res3_p; 513 char **private_p; 514 int *prognum; 515 int *vernum; 516 char **module_p; 517 int *sflags; 518 register char **cmd_line_p; 519 int mflag; 520 { 521 register char *p; 522 register char *nexttok; 523 register char *ptr; 524 int sawsep = 0; 525 char scratch[BUFSIZ]; 526 527 *flags_p = 0; 528 529 if (!(p = strchr(bp, DBFTOKSEP ))) { /* look for service code string */ 530 DEBUG((9,"scan_line failed svc_code strchr")); 531 return(0); 532 } 533 *p = '\0'; 534 *svc_code_p = bp; 535 nexttok = ++p; 536 537 if (!(p = strchr(nexttok, DBFTOKSEP ))) { 538 DEBUG((9,"scan_line failed flags strchr")); 539 return(0); 540 } 541 *p = '\0'; 542 543 while (*nexttok) { 544 switch (*nexttok) { 545 case 'x': /* service is turned off */ 546 case 'X': 547 *flags_p |= DBF_OFF; 548 break; 549 case 'u': /* create utmp entry */ 550 *flags_p |= DBF_UTMP; 551 break; 552 default: 553 DEBUG((1,"scan_line: unknown flag char: 0x%x",*nexttok)); 554 *flags_p = DBF_UNKNOWN; 555 break; 556 } 557 ++nexttok; 558 } 559 nexttok = ++p; 560 561 if (!(p = strchr(nexttok, DBFTOKSEP ))) { 562 DEBUG((9,"scan_line failed id strchr")); 563 return(0); 564 } 565 *p = '\0'; 566 *id_p = nexttok; 567 nexttok = ++p; 568 569 if (!(p = strchr(nexttok, DBFTOKSEP ))) { 570 DEBUG((9,"scan_line failed res1 strchr")); 571 return(0); 572 } 573 *p = '\0'; 574 *res1_p = nexttok; 575 nexttok = ++p; 576 577 if (!(p = strchr(nexttok, DBFTOKSEP ))) { 578 DEBUG((9,"scan_line failed res2 strchr")); 579 return(0); 580 } 581 *p = '\0'; 582 *res2_p = nexttok; 583 nexttok = ++p; 584 585 if (!(p = strchr(nexttok, DBFTOKSEP ))) { 586 DEBUG((9,"scan_line failed res3 strchr")); 587 return(0); 588 } 589 *p = '\0'; 590 *res3_p = nexttok; 591 nexttok = ++p; 592 593 if (!(p = strchr(nexttok, DBFTOKSEP ))) { 594 DEBUG((9,"scan_line failed private strchr")); 595 return(0); 596 } 597 *p = '\0'; 598 *private_p = nexttok; 599 nexttok = ++p; 600 601 if (!(p = strchr(nexttok, DBFTOKSEP ))) { 602 DEBUG((9,"scan_line failed rpc strchr")); 603 return(0); 604 } 605 *p = '\0'; 606 607 *prognum = -1; 608 *vernum = -1; 609 if (*nexttok) { 610 /* there is rpc info */ 611 for (ptr = nexttok; *ptr; ++ptr) { 612 if ((*ptr == ',') && !sawsep) { 613 /* 614 * skip separator - note that if 615 * separator has been seen, it's not 616 * a digit so it will fail below 617 */ 618 sawsep++; 619 continue; 620 } 621 if (!isdigit(*ptr)) { 622 sprintf(scratch, "service code <%s> specifies non-integer rpc info", *svc_code_p); 623 logmessage(scratch); 624 return(0); 625 } 626 } 627 ptr = strchr(nexttok, ','); 628 if (ptr) { 629 if ((*prognum = atoi(nexttok)) < 0) { 630 if (!mflag) { 631 /* messages aren't suppressed */ 632 sprintf(scratch, "service code <%s> specifies negative program number", *svc_code_p); 633 logmessage(scratch); 634 } 635 return(0); 636 } 637 if ((*vernum = atoi(ptr + 1)) < 0) { 638 if (!mflag) { 639 sprintf(scratch, "service code <%s> specifies negative version number", *svc_code_p); 640 logmessage(scratch); 641 } 642 return(0); 643 } 644 } 645 else { 646 if (!mflag) { 647 sprintf(scratch, "service code <%s> - invalid rpcinfo", *svc_code_p); 648 logmessage(scratch); 649 } 650 return(0); 651 } 652 } 653 nexttok = ++p; 654 655 if (!(p = strchr(nexttok, DBFTOKSEP ))) { 656 DEBUG((9,"scan_line failed sflags strchr")); 657 return(0); 658 } 659 *p = '\0'; 660 661 *sflags = 0; 662 while (*nexttok) { 663 switch (*nexttok) { 664 case 'c': /* dbf_cmd_line is a command */ 665 *sflags |= CFLAG; 666 break; 667 case 'd': /* dynamic address */ 668 if ((int) strlen(*private_p) > 0) { 669 if (!mflag) { 670 sprintf(scratch, "service code <%s> specifies static and dynamic address", *svc_code_p); 671 logmessage(scratch); 672 logmessage(" address info ignored"); 673 } 674 /* don't set DFLAG and wipe out private addr */ 675 **private_p = '\0'; 676 } 677 else { 678 *sflags |= DFLAG; 679 } 680 break; 681 case 'p': /* dbf_cmd_line is a pipe */ 682 *sflags |= PFLAG; 683 break; 684 default: 685 if (!mflag) { 686 sprintf(scratch, "service code <%s> unknown flag <%c> ignored", *svc_code_p, *nexttok); 687 logmessage(scratch); 688 } 689 break; 690 } 691 ++nexttok; 692 } 693 nexttok = ++p; 694 695 if (!(p = strchr(nexttok, DBFTOKSEP ))) { 696 DEBUG((9,"scan_line failed module strchr")); 697 return(0); 698 } 699 *p = '\0'; 700 *module_p = nexttok; 701 nexttok = ++p; 702 703 *cmd_line_p = nexttok; 704 705 DEBUG((9,"scan_line: modules: %s; line: %s; len: %d", *module_p, *cmd_line_p, strlen(*svc_code_p)+strlen(*id_p)+strlen(*res1_p)+strlen(*res2_p)+strlen(*res3_p)+strlen(*private_p)+strlen(*module_p)+strlen(*cmd_line_p)+9)); 706 /* 707 * return the length of the buffer. Add 9 for the NULLs after each 708 * string 709 */ 710 return(strlen(*svc_code_p)+strlen(*id_p)+strlen(*res1_p)+strlen(*res2_p)+strlen(*res3_p)+strlen(*private_p)+strlen(*module_p)+strlen(*cmd_line_p)+9); 711 } 712 713 714 715 #define VERSIONSTR "# VERSION=" 716 717 int 718 check_version(void) 719 { 720 FILE *fp; 721 char *line, *p, *tmp; 722 int version; 723 724 if ((fp = fopen(DBFNAME, "r")) == NULL) { 725 logmessage(dbfopenmsg); 726 error(E_DBF_IO, EXIT | NOCORE | NO_MSG); 727 } 728 if ((line = (char *) malloc(DBFLINESZ)) == NULL) 729 error(E_DBF_ALLOC, EXIT | NOCORE); 730 p = line; 731 while (fgets(p, DBFLINESZ, fp)) { 732 if (!strncmp(p, VERSIONSTR, strlen(VERSIONSTR))) { 733 /* pitch the newline */ 734 tmp = strchr(p, '\n'); 735 if (tmp) 736 *tmp = '\0'; 737 else { 738 logmessage(dbfcorrupt); 739 error(E_DBF_CORRUPT, EXIT | NOCORE); 740 } 741 p += strlen(VERSIONSTR); 742 if (*p) 743 version = atoi(p); 744 else { 745 logmessage(dbfcorrupt); 746 error(E_DBF_CORRUPT, EXIT | NOCORE); 747 } 748 free(line); 749 fclose(fp); 750 if (version != VERSION) 751 return(1); /* wrong version */ 752 else 753 return(0); /* version ok */ 754 } 755 p = line; 756 } 757 logmessage(dbfcorrupt); 758 error(E_DBF_CORRUPT, EXIT | NOCORE); 759 return(1); 760 } 761 762 763 /* 764 * mkdbfargv: Given a pointer to a dbf_t, construct argv 765 * for an exec system call. 766 * Warning: returns a pointer to static data which are 767 * overritten by each call. 768 * 769 * There is a practical limit of 50 arguments (including argv[0]) 770 * 771 * Warning: calling mkdbfargv destroys the data (by writing null 772 * characters via strtok) pointed to by dbp->dbf_cmd_line. 773 */ 774 775 static char *dbfargv[50]; 776 static char *delim = " \t'\""; /* delimiters */ 777 778 char ** 779 mkdbfargv(dbp) 780 register dbf_t *dbp; 781 { 782 register char **argvp = dbfargv; 783 register char *p = dbp->dbf_cmd_line; 784 char delch; 785 register char *savep; 786 register char *tp; 787 char scratch[BUFSIZ]; 788 char *strpbrk(); 789 #ifdef DEBUGMODE 790 register int i = 0; 791 #endif 792 793 *argvp = 0; 794 savep = p; 795 while (p && *p) { 796 if (p = strpbrk(p, delim)) { 797 switch (*p) { 798 case ' ': 799 case '\t': 800 /* "normal" cases */ 801 *p++ = '\0'; 802 *argvp++ = savep; 803 DEBUG((9, "argv[%d] = %s", i++, savep)); 804 /* zap trailing white space */ 805 while (isspace(*p)) 806 p++; 807 savep = p; 808 break; 809 case '"': 810 case '\'': 811 /* found a string */ 812 delch = *p; /* remember the delimiter */ 813 savep = ++p; 814 815 /* 816 * We work the string in place, embedded instances of the string delimiter, 817 * i.e. \" must have the '\' removed. Since we'd have to do a compare to 818 * decide if a copy were needed, it's less work to just do the copy, even 819 * though it is most likely unnecessary. 820 */ 821 822 tp = p; 823 for (;;) { 824 if (*p == '\0') { 825 sprintf(scratch, "invalid command line, non-terminated string for service code %s", dbp->dbf_svc_code); 826 logmessage(scratch); 827 exit(2); /* server, don't log */ 828 } 829 if (*p == delch) { 830 if (*(tp - 1) == '\\') { /* \delim */ 831 *(tp - 1) = *p; 832 p++; 833 } 834 else { /* end of string */ 835 *tp = 0; 836 *argvp++ = savep; 837 DEBUG((9, "argv[%d] = %s", i++, savep)); 838 p++; 839 /* zap trailing white space */ 840 while (isspace(*p)) 841 p++; 842 savep = p; 843 break; 844 } 845 } 846 else { 847 *tp++ = *p++; 848 } 849 } 850 break; 851 default: 852 logmessage("Internal error in parse routine"); 853 exit(2); /* server, don't log */ 854 } 855 } 856 else { 857 *argvp++ = savep; 858 DEBUG((9, "argv[%d] = %s", i++, savep)); 859 } 860 } 861 *argvp = 0; 862 return(dbfargv); 863 } 864 865 866 867 /* 868 * 869 * getentry: Given a fd, this routine will return a 870 * dbf entry. If the entry doesn't exist it will 871 * return NULL. 872 */ 873 874 dbf_t * 875 getentry(fd) 876 int fd; 877 { 878 extern dbf_t *Dbfhead; /* Dbfentries (when allocated) */ 879 register dbf_t *dbp = Dbfhead; 880 881 if (!Dbfhead) { /* no private address in database file */ 882 DEBUG((9, "getdbfentry - nothing in Dbfhead = %s ",Dbfhead)); 883 return((dbf_t *)0); 884 } 885 else 886 for (dbp = Dbfhead; dbp->dbf_prv_adr; ++dbp) 887 if (fd == dbp->dbf_fd) { 888 return(dbp); 889 } 890 891 return((dbf_t *)0); /* requested private address not in list */ 892 893 } 894 895 896 /* 897 * pushmod: push modules if defined in the data base entry. 898 * 899 * WARNING: This routine writes into the in-memory copy 900 * of the database file. Therefore, after it is called, 901 * the incore copy of the database file will no longer be valid. 902 */ 903 904 int 905 pushmod(fd, mp) 906 int fd; 907 register char *mp; 908 { 909 register char *cp; 910 register char *bufp = mp; 911 char name[32]; 912 extern int errno; 913 914 DEBUG((9,"in pushmod:")); 915 if (!mp || *mp == '\0') { 916 DEBUG((9,"NULL list: exiting pushmod")); 917 return(0); 918 } 919 /* pop timod if it is on the stack */ 920 if (ioctl(fd, I_LOOK, name) >= 0) { 921 if (strcmp(name, "timod") == 0) { 922 if (ioctl(fd, I_POP, 0) < 0) 923 DEBUG((9,"pushmod: I_POP failed")); 924 } 925 } 926 while ((cp = strtok(bufp, ",")) != NULL) { 927 bufp = NULL; 928 DEBUG((9,"pushmod: about to push %s", cp)); 929 if (ioctl(fd, I_PUSH, cp) < 0) { 930 DEBUG((9,"pushmod: ioctl failed, errno = %d",errno)); 931 return(1); 932 } 933 } 934 DEBUG((9,"exiting pushmod:")); 935 return(0); 936 } 937