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