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
read_dbf(re_read)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
get_dbf(dbf_p,cmd_p)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
scan_dbf(path)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
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)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
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)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
check_version(void)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 **
mkdbfargv(dbp)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 *
getentry(fd)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
pushmod(fd,mp)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