Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/libexec/bootpd/readfile.c
34822 views
1
/************************************************************************
2
Copyright 1988, 1991 by Carnegie Mellon University
3
4
All Rights Reserved
5
6
Permission to use, copy, modify, and distribute this software and its
7
documentation for any purpose and without fee is hereby granted, provided
8
that the above copyright notice appear in all copies and that both that
9
copyright notice and this permission notice appear in supporting
10
documentation, and that the name of Carnegie Mellon University not be used
11
in advertising or publicity pertaining to distribution of the software
12
without specific, written prior permission.
13
14
CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
15
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
16
IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
17
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
18
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20
SOFTWARE.
21
22
************************************************************************/
23
24
/*
25
* bootpd configuration file reading code.
26
*
27
* The routines in this file deal with reading, interpreting, and storing
28
* the information found in the bootpd configuration file (usually
29
* /etc/bootptab).
30
*/
31
32
33
#include <sys/errno.h>
34
#include <sys/types.h>
35
#include <sys/stat.h>
36
#include <sys/file.h>
37
#include <sys/time.h>
38
#include <netinet/in.h>
39
40
#include <stdlib.h>
41
#include <stdio.h>
42
#include <string.h>
43
#include <ctype.h>
44
#include <assert.h>
45
#include <syslog.h>
46
47
#include "bootp.h"
48
#include "hash.h"
49
#include "hwaddr.h"
50
#include "lookup.h"
51
#include "readfile.h"
52
#include "report.h"
53
#include "tzone.h"
54
#include "bootpd.h"
55
56
#define HASHTABLESIZE 257 /* Hash table size (prime) */
57
58
/* Non-standard hardware address type (see bootp.h) */
59
#define HTYPE_DIRECT 0
60
61
/* Error codes returned by eval_symbol: */
62
#define SUCCESS 0
63
#define E_END_OF_ENTRY (-1)
64
#define E_SYNTAX_ERROR (-2)
65
#define E_UNKNOWN_SYMBOL (-3)
66
#define E_BAD_IPADDR (-4)
67
#define E_BAD_HWADDR (-5)
68
#define E_BAD_LONGWORD (-6)
69
#define E_BAD_HWATYPE (-7)
70
#define E_BAD_PATHNAME (-8)
71
#define E_BAD_VALUE (-9)
72
73
/* Tag idendities. */
74
#define SYM_NULL 0
75
#define SYM_BOOTFILE 1
76
#define SYM_COOKIE_SERVER 2
77
#define SYM_DOMAIN_SERVER 3
78
#define SYM_GATEWAY 4
79
#define SYM_HWADDR 5
80
#define SYM_HOMEDIR 6
81
#define SYM_HTYPE 7
82
#define SYM_IMPRESS_SERVER 8
83
#define SYM_IPADDR 9
84
#define SYM_LOG_SERVER 10
85
#define SYM_LPR_SERVER 11
86
#define SYM_NAME_SERVER 12
87
#define SYM_RLP_SERVER 13
88
#define SYM_SUBNET_MASK 14
89
#define SYM_TIME_OFFSET 15
90
#define SYM_TIME_SERVER 16
91
#define SYM_VENDOR_MAGIC 17
92
#define SYM_SIMILAR_ENTRY 18
93
#define SYM_NAME_SWITCH 19
94
#define SYM_BOOTSIZE 20
95
#define SYM_BOOT_SERVER 22
96
#define SYM_TFTPDIR 23
97
#define SYM_DUMP_FILE 24
98
#define SYM_DOMAIN_NAME 25
99
#define SYM_SWAP_SERVER 26
100
#define SYM_ROOT_PATH 27
101
#define SYM_EXTEN_FILE 28
102
#define SYM_REPLY_ADDR 29
103
#define SYM_NIS_DOMAIN 30 /* RFC 1533 */
104
#define SYM_NIS_SERVER 31 /* RFC 1533 */
105
#define SYM_NTP_SERVER 32 /* RFC 1533 */
106
#define SYM_EXEC_FILE 33 /* YORK_EX_OPTION */
107
#define SYM_MSG_SIZE 34
108
#define SYM_MIN_WAIT 35
109
/* XXX - Add new tags here */
110
111
#define OP_ADDITION 1 /* Operations on tags */
112
#define OP_DELETION 2
113
#define OP_BOOLEAN 3
114
115
#define MAXINADDRS 16 /* Max size of an IP address list */
116
#define MAXBUFLEN 256 /* Max temp buffer space */
117
#define MAXENTRYLEN 2048 /* Max size of an entire entry */
118
119
120
121
/*
122
* Structure used to map a configuration-file symbol (such as "ds") to a
123
* unique integer.
124
*/
125
126
struct symbolmap {
127
char *symbol;
128
int symbolcode;
129
};
130
131
132
struct htypename {
133
char *name;
134
byte htype;
135
};
136
137
138
PRIVATE int nhosts; /* Number of hosts (/w hw or IP address) */
139
PRIVATE int nentries; /* Total number of entries */
140
PRIVATE int32 modtime = 0; /* Last modification time of bootptab */
141
PRIVATE char *current_hostname; /* Name of the current entry. */
142
PRIVATE char current_tagname[8];
143
144
/*
145
* List of symbolic names used in the bootptab file. The order and actual
146
* values of the symbol codes (SYM_. . .) are unimportant, but they must
147
* all be unique.
148
*/
149
150
PRIVATE struct symbolmap symbol_list[] = {
151
{"bf", SYM_BOOTFILE},
152
{"bs", SYM_BOOTSIZE},
153
{"cs", SYM_COOKIE_SERVER},
154
{"df", SYM_DUMP_FILE},
155
{"dn", SYM_DOMAIN_NAME},
156
{"ds", SYM_DOMAIN_SERVER},
157
{"ef", SYM_EXTEN_FILE},
158
{"ex", SYM_EXEC_FILE}, /* YORK_EX_OPTION */
159
{"gw", SYM_GATEWAY},
160
{"ha", SYM_HWADDR},
161
{"hd", SYM_HOMEDIR},
162
{"hn", SYM_NAME_SWITCH},
163
{"ht", SYM_HTYPE},
164
{"im", SYM_IMPRESS_SERVER},
165
{"ip", SYM_IPADDR},
166
{"lg", SYM_LOG_SERVER},
167
{"lp", SYM_LPR_SERVER},
168
{"ms", SYM_MSG_SIZE},
169
{"mw", SYM_MIN_WAIT},
170
{"ns", SYM_NAME_SERVER},
171
{"nt", SYM_NTP_SERVER},
172
{"ra", SYM_REPLY_ADDR},
173
{"rl", SYM_RLP_SERVER},
174
{"rp", SYM_ROOT_PATH},
175
{"sa", SYM_BOOT_SERVER},
176
{"sm", SYM_SUBNET_MASK},
177
{"sw", SYM_SWAP_SERVER},
178
{"tc", SYM_SIMILAR_ENTRY},
179
{"td", SYM_TFTPDIR},
180
{"to", SYM_TIME_OFFSET},
181
{"ts", SYM_TIME_SERVER},
182
{"vm", SYM_VENDOR_MAGIC},
183
{"yd", SYM_NIS_DOMAIN},
184
{"ys", SYM_NIS_SERVER},
185
/* XXX - Add new tags here */
186
};
187
188
189
/*
190
* List of symbolic names for hardware types. Name translates into
191
* hardware type code listed with it. Names must begin with a letter
192
* and must be all lowercase. This is searched linearly, so put
193
* commonly-used entries near the beginning.
194
*/
195
196
PRIVATE struct htypename htnamemap[] = {
197
{"ethernet", HTYPE_ETHERNET},
198
{"ethernet3", HTYPE_EXP_ETHERNET},
199
{"ether", HTYPE_ETHERNET},
200
{"ether3", HTYPE_EXP_ETHERNET},
201
{"ieee802", HTYPE_IEEE802},
202
{"tr", HTYPE_IEEE802},
203
{"token-ring", HTYPE_IEEE802},
204
{"pronet", HTYPE_PRONET},
205
{"chaos", HTYPE_CHAOS},
206
{"arcnet", HTYPE_ARCNET},
207
{"ax.25", HTYPE_AX25},
208
{"direct", HTYPE_DIRECT},
209
{"serial", HTYPE_DIRECT},
210
{"slip", HTYPE_DIRECT},
211
{"ppp", HTYPE_DIRECT}
212
};
213
214
215
216
/*
217
* Externals and forward declarations.
218
*/
219
220
boolean nmcmp(hash_datum *, hash_datum *);
221
222
PRIVATE void
223
adjust(char **);
224
PRIVATE void
225
del_string(struct shared_string *);
226
PRIVATE void
227
del_bindata(struct shared_bindata *);
228
PRIVATE void
229
del_iplist(struct in_addr_list *);
230
PRIVATE void
231
eat_whitespace(char **);
232
PRIVATE int
233
eval_symbol(char **, struct host *);
234
PRIVATE void
235
fill_defaults(struct host *, char **);
236
PRIVATE void
237
free_host(hash_datum *);
238
PRIVATE struct in_addr_list *
239
get_addresses(char **);
240
PRIVATE struct shared_string *
241
get_shared_string(char **);
242
PRIVATE char *
243
get_string(char **, char *, u_int *);
244
PRIVATE u_int32
245
get_u_long(char **);
246
PRIVATE boolean
247
goodname(char *);
248
PRIVATE boolean
249
hwinscmp(hash_datum *, hash_datum *);
250
PRIVATE int
251
interp_byte(char **, byte *);
252
PRIVATE void
253
makelower(char *);
254
PRIVATE boolean
255
nullcmp(hash_datum *, hash_datum *);
256
PRIVATE int
257
process_entry(struct host *, char *);
258
PRIVATE int
259
process_generic(char **, struct shared_bindata **, u_int);
260
PRIVATE byte *
261
prs_haddr(char **, u_int);
262
PRIVATE int
263
prs_inetaddr(char **, u_int32 *);
264
PRIVATE void
265
read_entry(FILE *, char *, u_int *);
266
PRIVATE char *
267
smalloc(u_int);
268
269
270
/*
271
* Vendor magic cookies for CMU and RFC1048
272
*/
273
u_char vm_cmu[4] = VM_CMU;
274
u_char vm_rfc1048[4] = VM_RFC1048;
275
276
/*
277
* Main hash tables
278
*/
279
hash_tbl *hwhashtable;
280
hash_tbl *iphashtable;
281
hash_tbl *nmhashtable;
282
283
/*
284
* Allocate hash tables for hardware address, ip address, and hostname
285
* (shared by bootpd and bootpef)
286
*/
287
void
288
rdtab_init(void)
289
{
290
hwhashtable = hash_Init(HASHTABLESIZE);
291
iphashtable = hash_Init(HASHTABLESIZE);
292
nmhashtable = hash_Init(HASHTABLESIZE);
293
if (!(hwhashtable && iphashtable && nmhashtable)) {
294
report(LOG_ERR, "Unable to allocate hash tables.");
295
exit(1);
296
}
297
}
298
299
300
/*
301
* Read bootptab database file. Avoid rereading the file if the
302
* write date hasn't changed since the last time we read it.
303
*/
304
305
void
306
readtab(int force)
307
{
308
struct host *hp;
309
FILE *fp;
310
struct stat st;
311
unsigned hashcode, buflen;
312
static char buffer[MAXENTRYLEN];
313
314
/*
315
* Check the last modification time.
316
*/
317
if (stat(bootptab, &st) < 0) {
318
report(LOG_ERR, "stat on \"%s\": %s",
319
bootptab, get_errmsg());
320
return;
321
}
322
#ifdef DEBUG
323
if (debug > 3) {
324
char timestr[28];
325
strcpy(timestr, ctime(&(st.st_mtime)));
326
/* zap the newline */
327
timestr[24] = '\0';
328
report(LOG_INFO, "bootptab mtime: %s",
329
timestr);
330
}
331
#endif
332
if ((force == 0) &&
333
(st.st_mtime == modtime) &&
334
st.st_nlink) {
335
/*
336
* hasn't been modified or deleted yet.
337
*/
338
return;
339
}
340
if (debug)
341
report(LOG_INFO, "reading %s\"%s\"",
342
(modtime != 0L) ? "new " : "",
343
bootptab);
344
345
/*
346
* Open bootptab file.
347
*/
348
if ((fp = fopen(bootptab, "r")) == NULL) {
349
report(LOG_ERR, "error opening \"%s\": %s", bootptab, get_errmsg());
350
return;
351
}
352
/*
353
* Record file modification time.
354
*/
355
if (fstat(fileno(fp), &st) < 0) {
356
report(LOG_ERR, "fstat: %s", get_errmsg());
357
fclose(fp);
358
return;
359
}
360
modtime = st.st_mtime;
361
362
/*
363
* Entirely erase all hash tables.
364
*/
365
hash_Reset(hwhashtable, free_host);
366
hash_Reset(iphashtable, free_host);
367
hash_Reset(nmhashtable, free_host);
368
369
nhosts = 0;
370
nentries = 0;
371
while (TRUE) {
372
buflen = sizeof(buffer);
373
read_entry(fp, buffer, &buflen);
374
if (buflen == 0) { /* More entries? */
375
break;
376
}
377
hp = (struct host *) smalloc(sizeof(struct host));
378
bzero((char *) hp, sizeof(*hp));
379
/* the link count it zero */
380
381
/*
382
* Get individual info
383
*/
384
if (process_entry(hp, buffer) < 0) {
385
hp->linkcount = 1;
386
free_host((hash_datum *) hp);
387
continue;
388
}
389
/*
390
* If this is not a dummy entry, and the IP or HW
391
* address is not yet set, try to get them here.
392
* Dummy entries have . as first char of name.
393
*/
394
if (goodname(hp->hostname->string)) {
395
char *hn = hp->hostname->string;
396
u_int32 value;
397
if (hp->flags.iaddr == 0) {
398
if (lookup_ipa(hn, &value)) {
399
report(LOG_ERR, "can not get IP addr for %s", hn);
400
report(LOG_ERR, "(dummy names should start with '.')");
401
} else {
402
hp->iaddr.s_addr = value;
403
hp->flags.iaddr = TRUE;
404
}
405
}
406
/* Set default subnet mask. */
407
if (hp->flags.subnet_mask == 0) {
408
if (lookup_netmask(hp->iaddr.s_addr, &value)) {
409
report(LOG_ERR, "can not get netmask for %s", hn);
410
} else {
411
hp->subnet_mask.s_addr = value;
412
hp->flags.subnet_mask = TRUE;
413
}
414
}
415
}
416
if (hp->flags.iaddr) {
417
nhosts++;
418
}
419
/* Register by HW addr if known. */
420
if (hp->flags.htype && hp->flags.haddr) {
421
/* We will either insert it or free it. */
422
hp->linkcount++;
423
hashcode = hash_HashFunction(hp->haddr, haddrlength(hp->htype));
424
if (hash_Insert(hwhashtable, hashcode, hwinscmp, hp, hp) < 0) {
425
report(LOG_NOTICE, "duplicate %s address: %s",
426
netname(hp->htype),
427
haddrtoa(hp->haddr, haddrlength(hp->htype)));
428
free_host((hash_datum *) hp);
429
continue;
430
}
431
}
432
/* Register by IP addr if known. */
433
if (hp->flags.iaddr) {
434
hashcode = hash_HashFunction((u_char *) & (hp->iaddr.s_addr), 4);
435
if (hash_Insert(iphashtable, hashcode, nullcmp, hp, hp) < 0) {
436
report(LOG_ERR,
437
"hash_Insert() failed on IP address insertion");
438
} else {
439
/* Just inserted the host struct in a new hash list. */
440
hp->linkcount++;
441
}
442
}
443
/* Register by Name (always known) */
444
hashcode = hash_HashFunction((u_char *) hp->hostname->string,
445
strlen(hp->hostname->string));
446
if (hash_Insert(nmhashtable, hashcode, nullcmp,
447
hp->hostname->string, hp) < 0) {
448
report(LOG_ERR,
449
"hash_Insert() failed on insertion of hostname: \"%s\"",
450
hp->hostname->string);
451
} else {
452
/* Just inserted the host struct in a new hash list. */
453
hp->linkcount++;
454
}
455
456
nentries++;
457
}
458
459
fclose(fp);
460
if (debug)
461
report(LOG_INFO, "read %d entries (%d hosts) from \"%s\"",
462
nentries, nhosts, bootptab);
463
return;
464
}
465
466
467
468
/*
469
* Read an entire host entry from the file pointed to by "fp" and insert it
470
* into the memory pointed to by "buffer". Leading whitespace and comments
471
* starting with "#" are ignored (removed). Backslashes (\) always quote
472
* the next character except that newlines preceded by a backslash cause
473
* line-continuation onto the next line. The entry is terminated by a
474
* newline character which is not preceded by a backslash. Sequences
475
* surrounded by double quotes are taken literally (including newlines, but
476
* not backslashes).
477
*
478
* The "bufsiz" parameter points to an unsigned int which specifies the
479
* maximum permitted buffer size. Upon return, this value will be replaced
480
* with the actual length of the entry (not including the null terminator).
481
*
482
* This code is a little scary. . . . I don't like using gotos in C
483
* either, but I first wrote this as an FSM diagram and gotos seemed like
484
* the easiest way to implement it. Maybe later I'll clean it up.
485
*/
486
487
PRIVATE void
488
read_entry(FILE *fp, char *buffer, unsigned *bufsiz)
489
{
490
int c, length;
491
492
length = 0;
493
494
/*
495
* Eat whitespace, blank lines, and comment lines.
496
*/
497
top:
498
c = fgetc(fp);
499
if (c < 0) {
500
goto done; /* Exit if end-of-file */
501
}
502
if (isspace(c)) {
503
goto top; /* Skip over whitespace */
504
}
505
if (c == '#') {
506
while (TRUE) { /* Eat comments after # */
507
c = fgetc(fp);
508
if (c < 0) {
509
goto done; /* Exit if end-of-file */
510
}
511
if (c == '\n') {
512
goto top; /* Try to read the next line */
513
}
514
}
515
}
516
ungetc(c, fp); /* Other character, push it back to reprocess it */
517
518
519
/*
520
* Now we're actually reading a data entry. Get each character and
521
* assemble it into the data buffer, processing special characters like
522
* double quotes (") and backslashes (\).
523
*/
524
525
mainloop:
526
c = fgetc(fp);
527
switch (c) {
528
case EOF:
529
case '\n':
530
goto done; /* Exit on EOF or newline */
531
case '\\':
532
c = fgetc(fp); /* Backslash, read a new character */
533
if (c < 0) {
534
goto done; /* Exit on EOF */
535
}
536
*buffer++ = c; /* Store the literal character */
537
length++;
538
if (length < *bufsiz - 1) {
539
goto mainloop;
540
} else {
541
goto done;
542
}
543
case '"':
544
*buffer++ = '"'; /* Store double-quote */
545
length++;
546
if (length >= *bufsiz - 1) {
547
goto done;
548
}
549
while (TRUE) { /* Special quote processing loop */
550
c = fgetc(fp);
551
switch (c) {
552
case EOF:
553
goto done; /* Exit on EOF . . . */
554
case '"':
555
*buffer++ = '"';/* Store matching quote */
556
length++;
557
if (length < *bufsiz - 1) {
558
goto mainloop; /* And continue main loop */
559
} else {
560
goto done;
561
}
562
case '\\':
563
if ((c = fgetc(fp)) < 0) { /* Backslash */
564
goto done; /* EOF. . . .*/
565
}
566
/* FALLTHROUGH */
567
default:
568
*buffer++ = c; /* Other character, store it */
569
length++;
570
if (length >= *bufsiz - 1) {
571
goto done;
572
}
573
}
574
}
575
case ':':
576
*buffer++ = c; /* Store colons */
577
length++;
578
if (length >= *bufsiz - 1) {
579
goto done;
580
}
581
do { /* But remove whitespace after them */
582
c = fgetc(fp);
583
if ((c < 0) || (c == '\n')) {
584
goto done;
585
}
586
} while (isspace(c)); /* Skip whitespace */
587
588
if (c == '\\') { /* Backslash quotes next character */
589
c = fgetc(fp);
590
if (c < 0) {
591
goto done;
592
}
593
if (c == '\n') {
594
goto top; /* Backslash-newline continuation */
595
}
596
}
597
/* FALLTHROUGH if "other" character */
598
default:
599
*buffer++ = c; /* Store other characters */
600
length++;
601
if (length >= *bufsiz - 1) {
602
goto done;
603
}
604
}
605
goto mainloop; /* Keep going */
606
607
done:
608
*buffer = '\0'; /* Terminate string */
609
*bufsiz = length; /* Tell the caller its length */
610
}
611
612
613
614
/*
615
* Parse out all the various tags and parameters in the host entry pointed
616
* to by "src". Stuff all the data into the appropriate fields of the
617
* host structure pointed to by "host". If there is any problem with the
618
* entry, an error message is reported via report(), no further processing
619
* is done, and -1 is returned. Successful calls return 0.
620
*
621
* (Some errors probably shouldn't be so completely fatal. . . .)
622
*/
623
624
PRIVATE int
625
process_entry(struct host *host, char *src)
626
{
627
int retval;
628
char *msg;
629
630
if (!host || *src == '\0') {
631
return -1;
632
}
633
host->hostname = get_shared_string(&src);
634
#if 0
635
/* Be more liberal for the benefit of dummy tag names. */
636
if (!goodname(host->hostname->string)) {
637
report(LOG_ERR, "bad hostname: \"%s\"", host->hostname->string);
638
del_string(host->hostname);
639
return -1;
640
}
641
#endif
642
current_hostname = host->hostname->string;
643
adjust(&src);
644
while (TRUE) {
645
retval = eval_symbol(&src, host);
646
if (retval == SUCCESS) {
647
adjust(&src);
648
continue;
649
}
650
if (retval == E_END_OF_ENTRY) {
651
/* The default subnet mask is set in readtab() */
652
return 0;
653
}
654
/* Some kind of error. */
655
switch (retval) {
656
case E_SYNTAX_ERROR:
657
msg = "bad syntax";
658
break;
659
case E_UNKNOWN_SYMBOL:
660
msg = "unknown symbol";
661
break;
662
case E_BAD_IPADDR:
663
msg = "bad INET address";
664
break;
665
case E_BAD_HWADDR:
666
msg = "bad hardware address";
667
break;
668
case E_BAD_LONGWORD:
669
msg = "bad longword value";
670
break;
671
case E_BAD_HWATYPE:
672
msg = "bad HW address type";
673
break;
674
case E_BAD_PATHNAME:
675
msg = "bad pathname (need leading '/')";
676
break;
677
case E_BAD_VALUE:
678
msg = "bad value";
679
break;
680
default:
681
msg = "unknown error";
682
break;
683
} /* switch */
684
report(LOG_ERR, "in entry named \"%s\", symbol \"%s\": %s",
685
current_hostname, current_tagname, msg);
686
return -1;
687
}
688
}
689
690
691
/*
692
* Macros for use in the function below:
693
*/
694
695
/* Parse one INET address stored directly in MEMBER. */
696
#define PARSE_IA1(MEMBER) do \
697
{ \
698
if (optype == OP_BOOLEAN) \
699
return E_SYNTAX_ERROR; \
700
hp->flags.MEMBER = FALSE; \
701
if (optype == OP_ADDITION) { \
702
if (prs_inetaddr(symbol, &value) < 0) \
703
return E_BAD_IPADDR; \
704
hp->MEMBER.s_addr = value; \
705
hp->flags.MEMBER = TRUE; \
706
} \
707
} while (0)
708
709
/* Parse a list of INET addresses pointed to by MEMBER */
710
#define PARSE_IAL(MEMBER) do \
711
{ \
712
if (optype == OP_BOOLEAN) \
713
return E_SYNTAX_ERROR; \
714
if (hp->flags.MEMBER) { \
715
hp->flags.MEMBER = FALSE; \
716
assert(hp->MEMBER); \
717
del_iplist(hp->MEMBER); \
718
hp->MEMBER = NULL; \
719
} \
720
if (optype == OP_ADDITION) { \
721
hp->MEMBER = get_addresses(symbol); \
722
if (hp->MEMBER == NULL) \
723
return E_SYNTAX_ERROR; \
724
hp->flags.MEMBER = TRUE; \
725
} \
726
} while (0)
727
728
/* Parse a shared string pointed to by MEMBER */
729
#define PARSE_STR(MEMBER) do \
730
{ \
731
if (optype == OP_BOOLEAN) \
732
return E_SYNTAX_ERROR; \
733
if (hp->flags.MEMBER) { \
734
hp->flags.MEMBER = FALSE; \
735
assert(hp->MEMBER); \
736
del_string(hp->MEMBER); \
737
hp->MEMBER = NULL; \
738
} \
739
if (optype == OP_ADDITION) { \
740
hp->MEMBER = get_shared_string(symbol); \
741
if (hp->MEMBER == NULL) \
742
return E_SYNTAX_ERROR; \
743
hp->flags.MEMBER = TRUE; \
744
} \
745
} while (0)
746
747
/* Parse an unsigned integer value for MEMBER */
748
#define PARSE_UINT(MEMBER) do \
749
{ \
750
if (optype == OP_BOOLEAN) \
751
return E_SYNTAX_ERROR; \
752
hp->flags.MEMBER = FALSE; \
753
if (optype == OP_ADDITION) { \
754
value = get_u_long(symbol); \
755
hp->MEMBER = value; \
756
hp->flags.MEMBER = TRUE; \
757
} \
758
} while (0)
759
760
/*
761
* Evaluate the two-character tag symbol pointed to by "symbol" and place
762
* the data in the structure pointed to by "hp". The pointer pointed to
763
* by "symbol" is updated to point past the source string (but may not
764
* point to the next tag entry).
765
*
766
* Obviously, this need a few more comments. . . .
767
*/
768
PRIVATE int
769
eval_symbol(char **symbol, struct host *hp)
770
{
771
char tmpstr[MAXSTRINGLEN];
772
byte *tmphaddr;
773
struct symbolmap *symbolptr;
774
u_int32 value;
775
int32 timeoff;
776
int i, numsymbols;
777
unsigned len;
778
int optype; /* Indicates boolean, addition, or deletion */
779
780
eat_whitespace(symbol);
781
782
/* Make sure this is set before returning. */
783
current_tagname[0] = (*symbol)[0];
784
current_tagname[1] = (*symbol)[1];
785
current_tagname[2] = 0;
786
787
if ((*symbol)[0] == '\0') {
788
return E_END_OF_ENTRY;
789
}
790
if ((*symbol)[0] == ':') {
791
return SUCCESS;
792
}
793
if ((*symbol)[0] == 'T') { /* generic symbol */
794
(*symbol)++;
795
value = get_u_long(symbol);
796
snprintf(current_tagname, sizeof(current_tagname),
797
"T%d", (int)value);
798
eat_whitespace(symbol);
799
if ((*symbol)[0] != '=') {
800
return E_SYNTAX_ERROR;
801
}
802
(*symbol)++;
803
if (!(hp->generic)) {
804
hp->generic = (struct shared_bindata *)
805
smalloc(sizeof(struct shared_bindata));
806
}
807
if (process_generic(symbol, &(hp->generic), (byte) (value & 0xFF)))
808
return E_SYNTAX_ERROR;
809
hp->flags.generic = TRUE;
810
return SUCCESS;
811
}
812
/*
813
* Determine the type of operation to be done on this symbol
814
*/
815
switch ((*symbol)[2]) {
816
case '=':
817
optype = OP_ADDITION;
818
break;
819
case '@':
820
optype = OP_DELETION;
821
break;
822
case ':':
823
case '\0':
824
optype = OP_BOOLEAN;
825
break;
826
default:
827
return E_SYNTAX_ERROR;
828
}
829
830
symbolptr = symbol_list;
831
numsymbols = sizeof(symbol_list) / sizeof(struct symbolmap);
832
for (i = 0; i < numsymbols; i++) {
833
if (((symbolptr->symbol)[0] == (*symbol)[0]) &&
834
((symbolptr->symbol)[1] == (*symbol)[1])) {
835
break;
836
}
837
symbolptr++;
838
}
839
if (i >= numsymbols) {
840
return E_UNKNOWN_SYMBOL;
841
}
842
/*
843
* Skip past the = or @ character (to point to the data) if this
844
* isn't a boolean operation. For boolean operations, just skip
845
* over the two-character tag symbol (and nothing else. . . .).
846
*/
847
(*symbol) += (optype == OP_BOOLEAN) ? 2 : 3;
848
849
eat_whitespace(symbol);
850
851
/* The cases below are in order by symbolcode value. */
852
switch (symbolptr->symbolcode) {
853
854
case SYM_BOOTFILE:
855
PARSE_STR(bootfile);
856
break;
857
858
case SYM_COOKIE_SERVER:
859
PARSE_IAL(cookie_server);
860
break;
861
862
case SYM_DOMAIN_SERVER:
863
PARSE_IAL(domain_server);
864
break;
865
866
case SYM_GATEWAY:
867
PARSE_IAL(gateway);
868
break;
869
870
case SYM_HWADDR:
871
if (optype == OP_BOOLEAN)
872
return E_SYNTAX_ERROR;
873
hp->flags.haddr = FALSE;
874
if (optype == OP_ADDITION) {
875
/* Default the HW type to Ethernet */
876
if (hp->flags.htype == 0) {
877
hp->flags.htype = TRUE;
878
hp->htype = HTYPE_ETHERNET;
879
}
880
tmphaddr = prs_haddr(symbol, hp->htype);
881
if (!tmphaddr)
882
return E_BAD_HWADDR;
883
bcopy(tmphaddr, hp->haddr, haddrlength(hp->htype));
884
hp->flags.haddr = TRUE;
885
}
886
break;
887
888
case SYM_HOMEDIR:
889
PARSE_STR(homedir);
890
break;
891
892
case SYM_HTYPE:
893
if (optype == OP_BOOLEAN)
894
return E_SYNTAX_ERROR;
895
hp->flags.htype = FALSE;
896
if (optype == OP_ADDITION) {
897
value = 0L; /* Assume an illegal value */
898
eat_whitespace(symbol);
899
if (isdigit(**symbol)) {
900
value = get_u_long(symbol);
901
} else {
902
len = sizeof(tmpstr);
903
(void) get_string(symbol, tmpstr, &len);
904
makelower(tmpstr);
905
numsymbols = sizeof(htnamemap) /
906
sizeof(struct htypename);
907
for (i = 0; i < numsymbols; i++) {
908
if (!strcmp(htnamemap[i].name, tmpstr)) {
909
break;
910
}
911
}
912
if (i < numsymbols) {
913
value = htnamemap[i].htype;
914
}
915
}
916
if (value >= hwinfocnt) {
917
return E_BAD_HWATYPE;
918
}
919
hp->htype = (byte) (value & 0xFF);
920
hp->flags.htype = TRUE;
921
}
922
break;
923
924
case SYM_IMPRESS_SERVER:
925
PARSE_IAL(impress_server);
926
break;
927
928
case SYM_IPADDR:
929
PARSE_IA1(iaddr);
930
break;
931
932
case SYM_LOG_SERVER:
933
PARSE_IAL(log_server);
934
break;
935
936
case SYM_LPR_SERVER:
937
PARSE_IAL(lpr_server);
938
break;
939
940
case SYM_NAME_SERVER:
941
PARSE_IAL(name_server);
942
break;
943
944
case SYM_RLP_SERVER:
945
PARSE_IAL(rlp_server);
946
break;
947
948
case SYM_SUBNET_MASK:
949
PARSE_IA1(subnet_mask);
950
break;
951
952
case SYM_TIME_OFFSET:
953
if (optype == OP_BOOLEAN)
954
return E_SYNTAX_ERROR;
955
hp->flags.time_offset = FALSE;
956
if (optype == OP_ADDITION) {
957
len = sizeof(tmpstr);
958
(void) get_string(symbol, tmpstr, &len);
959
if (!strncmp(tmpstr, "auto", 4)) {
960
hp->time_offset = secondswest;
961
} else {
962
if (sscanf(tmpstr, "%d", (int*)&timeoff) != 1)
963
return E_BAD_LONGWORD;
964
hp->time_offset = timeoff;
965
}
966
hp->flags.time_offset = TRUE;
967
}
968
break;
969
970
case SYM_TIME_SERVER:
971
PARSE_IAL(time_server);
972
break;
973
974
case SYM_VENDOR_MAGIC:
975
if (optype == OP_BOOLEAN)
976
return E_SYNTAX_ERROR;
977
hp->flags.vm_cookie = FALSE;
978
if (optype == OP_ADDITION) {
979
if (strncmp(*symbol, "auto", 4)) {
980
/* The string is not "auto" */
981
if (!strncmp(*symbol, "rfc", 3)) {
982
bcopy(vm_rfc1048, hp->vm_cookie, 4);
983
} else if (!strncmp(*symbol, "cmu", 3)) {
984
bcopy(vm_cmu, hp->vm_cookie, 4);
985
} else {
986
if (!isdigit(**symbol))
987
return E_BAD_IPADDR;
988
if (prs_inetaddr(symbol, &value) < 0)
989
return E_BAD_IPADDR;
990
bcopy(&value, hp->vm_cookie, 4);
991
}
992
hp->flags.vm_cookie = TRUE;
993
}
994
}
995
break;
996
997
case SYM_SIMILAR_ENTRY:
998
switch (optype) {
999
case OP_ADDITION:
1000
fill_defaults(hp, symbol);
1001
break;
1002
default:
1003
return E_SYNTAX_ERROR;
1004
}
1005
break;
1006
1007
case SYM_NAME_SWITCH:
1008
switch (optype) {
1009
case OP_ADDITION:
1010
return E_SYNTAX_ERROR;
1011
case OP_DELETION:
1012
hp->flags.send_name = FALSE;
1013
hp->flags.name_switch = FALSE;
1014
break;
1015
case OP_BOOLEAN:
1016
hp->flags.send_name = TRUE;
1017
hp->flags.name_switch = TRUE;
1018
break;
1019
}
1020
break;
1021
1022
case SYM_BOOTSIZE:
1023
switch (optype) {
1024
case OP_ADDITION:
1025
if (!strncmp(*symbol, "auto", 4)) {
1026
hp->flags.bootsize = TRUE;
1027
hp->flags.bootsize_auto = TRUE;
1028
} else {
1029
hp->bootsize = (unsigned int) get_u_long(symbol);
1030
hp->flags.bootsize = TRUE;
1031
hp->flags.bootsize_auto = FALSE;
1032
}
1033
break;
1034
case OP_DELETION:
1035
hp->flags.bootsize = FALSE;
1036
break;
1037
case OP_BOOLEAN:
1038
hp->flags.bootsize = TRUE;
1039
hp->flags.bootsize_auto = TRUE;
1040
break;
1041
}
1042
break;
1043
1044
case SYM_BOOT_SERVER:
1045
PARSE_IA1(bootserver);
1046
break;
1047
1048
case SYM_TFTPDIR:
1049
PARSE_STR(tftpdir);
1050
if ((hp->tftpdir != NULL) &&
1051
(hp->tftpdir->string[0] != '/'))
1052
return E_BAD_PATHNAME;
1053
break;
1054
1055
case SYM_DUMP_FILE:
1056
PARSE_STR(dump_file);
1057
break;
1058
1059
case SYM_DOMAIN_NAME:
1060
PARSE_STR(domain_name);
1061
break;
1062
1063
case SYM_SWAP_SERVER:
1064
PARSE_IA1(swap_server);
1065
break;
1066
1067
case SYM_ROOT_PATH:
1068
PARSE_STR(root_path);
1069
break;
1070
1071
case SYM_EXTEN_FILE:
1072
PARSE_STR(exten_file);
1073
break;
1074
1075
case SYM_REPLY_ADDR:
1076
PARSE_IA1(reply_addr);
1077
break;
1078
1079
case SYM_NIS_DOMAIN:
1080
PARSE_STR(nis_domain);
1081
break;
1082
1083
case SYM_NIS_SERVER:
1084
PARSE_IAL(nis_server);
1085
break;
1086
1087
case SYM_NTP_SERVER:
1088
PARSE_IAL(ntp_server);
1089
break;
1090
1091
#ifdef YORK_EX_OPTION
1092
case SYM_EXEC_FILE:
1093
PARSE_STR(exec_file);
1094
break;
1095
#endif
1096
1097
case SYM_MSG_SIZE:
1098
PARSE_UINT(msg_size);
1099
if (hp->msg_size < BP_MINPKTSZ ||
1100
hp->msg_size > MAX_MSG_SIZE)
1101
return E_BAD_VALUE;
1102
break;
1103
1104
case SYM_MIN_WAIT:
1105
PARSE_UINT(min_wait);
1106
break;
1107
1108
/* XXX - Add new tags here */
1109
1110
default:
1111
return E_UNKNOWN_SYMBOL;
1112
1113
} /* switch symbolcode */
1114
1115
return SUCCESS;
1116
}
1117
#undef PARSE_IA1
1118
#undef PARSE_IAL
1119
#undef PARSE_STR
1120
1121
1122
1123
1124
/*
1125
* Read a string from the buffer indirectly pointed to through "src" and
1126
* move it into the buffer pointed to by "dest". A pointer to the maximum
1127
* allowable length of the string (including null-terminator) is passed as
1128
* "length". The actual length of the string which was read is returned in
1129
* the unsigned integer pointed to by "length". This value is the same as
1130
* that which would be returned by applying the strlen() function on the
1131
* destination string (i.e the terminating null is not counted as a
1132
* character). Trailing whitespace is removed from the string. For
1133
* convenience, the function returns the new value of "dest".
1134
*
1135
* The string is read until the maximum number of characters, an unquoted
1136
* colon (:), or a null character is read. The return string in "dest" is
1137
* null-terminated.
1138
*/
1139
1140
PRIVATE char *
1141
get_string(char **src, char *dest, unsigned *length)
1142
{
1143
int n, len, quoteflag;
1144
1145
quoteflag = FALSE;
1146
n = 0;
1147
len = *length - 1;
1148
while ((n < len) && (**src)) {
1149
if (!quoteflag && (**src == ':')) {
1150
break;
1151
}
1152
if (**src == '"') {
1153
(*src)++;
1154
quoteflag = !quoteflag;
1155
continue;
1156
}
1157
if (**src == '\\') {
1158
(*src)++;
1159
if (!**src) {
1160
break;
1161
}
1162
}
1163
*dest++ = *(*src)++;
1164
n++;
1165
}
1166
1167
/*
1168
* Remove that troublesome trailing whitespace. . .
1169
*/
1170
while ((n > 0) && isspace(dest[-1])) {
1171
dest--;
1172
n--;
1173
}
1174
1175
*dest = '\0';
1176
*length = n;
1177
return dest;
1178
}
1179
1180
1181
1182
/*
1183
* Read the string indirectly pointed to by "src", update the caller's
1184
* pointer, and return a pointer to a malloc'ed shared_string structure
1185
* containing the string.
1186
*
1187
* The string is read using the same rules as get_string() above.
1188
*/
1189
1190
PRIVATE struct shared_string *
1191
get_shared_string(char **src)
1192
{
1193
char retstring[MAXSTRINGLEN];
1194
struct shared_string *s;
1195
unsigned length;
1196
1197
length = sizeof(retstring);
1198
(void) get_string(src, retstring, &length);
1199
1200
s = (struct shared_string *) smalloc(sizeof(struct shared_string)
1201
+ length);
1202
s->linkcount = 1;
1203
strcpy(s->string, retstring);
1204
1205
return s;
1206
}
1207
1208
1209
1210
/*
1211
* Load RFC1048 generic information directly into a memory buffer.
1212
*
1213
* "src" indirectly points to the ASCII representation of the generic data.
1214
* "dest" points to a string structure which is updated to point to a new
1215
* string with the new data appended to the old string. The old string is
1216
* freed.
1217
*
1218
* The given tag value is inserted with the new data.
1219
*
1220
* The data may be represented as either a stream of hexadecimal numbers
1221
* representing bytes (any or all bytes may optionally start with '0x' and
1222
* be separated with periods ".") or as a quoted string of ASCII
1223
* characters (the quotes are required).
1224
*/
1225
1226
PRIVATE int
1227
process_generic(char **src, struct shared_bindata **dest, u_int tagvalue)
1228
{
1229
byte tmpbuf[MAXBUFLEN];
1230
byte *str;
1231
struct shared_bindata *bdata;
1232
u_int newlength, oldlength;
1233
1234
str = tmpbuf;
1235
*str++ = (tagvalue & 0xFF); /* Store tag value */
1236
str++; /* Skip over length field */
1237
if ((*src)[0] == '"') { /* ASCII data */
1238
newlength = sizeof(tmpbuf) - 2; /* Set maximum allowed length */
1239
(void) get_string(src, (char *) str, &newlength);
1240
newlength++; /* null terminator */
1241
} else { /* Numeric data */
1242
newlength = 0;
1243
while (newlength < sizeof(tmpbuf) - 2) {
1244
if (interp_byte(src, str++) < 0)
1245
break;
1246
newlength++;
1247
if (**src == '.') {
1248
(*src)++;
1249
}
1250
}
1251
}
1252
if ((*src)[0] != ':')
1253
return -1;
1254
1255
tmpbuf[1] = (newlength & 0xFF);
1256
oldlength = ((*dest)->length);
1257
bdata = (struct shared_bindata *) smalloc(sizeof(struct shared_bindata)
1258
+ oldlength + newlength + 1);
1259
if (oldlength > 0) {
1260
bcopy((*dest)->data, bdata->data, oldlength);
1261
}
1262
bcopy(tmpbuf, bdata->data + oldlength, newlength + 2);
1263
bdata->length = oldlength + newlength + 2;
1264
bdata->linkcount = 1;
1265
if (*dest) {
1266
del_bindata(*dest);
1267
}
1268
*dest = bdata;
1269
return 0;
1270
}
1271
1272
1273
1274
/*
1275
* Verify that the given string makes sense as a hostname (according to
1276
* Appendix 1, page 29 of RFC882).
1277
*
1278
* Return TRUE for good names, FALSE otherwise.
1279
*/
1280
1281
PRIVATE boolean
1282
goodname(char *hostname)
1283
{
1284
do {
1285
if (!isalpha(*hostname++)) { /* First character must be a letter */
1286
return FALSE;
1287
}
1288
while (isalnum(*hostname) ||
1289
(*hostname == '-') ||
1290
(*hostname == '_') )
1291
{
1292
hostname++; /* Alphanumeric or a hyphen */
1293
}
1294
if (!isalnum(hostname[-1])) { /* Last must be alphanumeric */
1295
return FALSE;
1296
}
1297
if (*hostname == '\0') {/* Done? */
1298
return TRUE;
1299
}
1300
} while (*hostname++ == '.'); /* Dot, loop for next label */
1301
1302
return FALSE; /* If it's not a dot, lose */
1303
}
1304
1305
1306
1307
/*
1308
* Null compare function -- always returns FALSE so an element is always
1309
* inserted into a hash table (i.e. there is never a collision with an
1310
* existing element).
1311
*/
1312
1313
PRIVATE boolean
1314
nullcmp(hash_datum *d1, hash_datum *d2)
1315
{
1316
return FALSE;
1317
}
1318
1319
1320
/*
1321
* Function for comparing a string with the hostname field of a host
1322
* structure.
1323
*/
1324
1325
boolean
1326
nmcmp(hash_datum *d1, hash_datum *d2)
1327
{
1328
char *name = (char *) d1; /* XXX - OK? */
1329
struct host *hp = (struct host *) d2;
1330
1331
return !strcmp(name, hp->hostname->string);
1332
}
1333
1334
1335
/*
1336
* Compare function to determine whether two hardware addresses are
1337
* equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
1338
* otherwise.
1339
*
1340
* If the hardware addresses of "host1" and "host2" are identical, but
1341
* they are on different IP subnets, this function returns FALSE.
1342
*
1343
* This function is used when inserting elements into the hardware address
1344
* hash table.
1345
*/
1346
1347
PRIVATE boolean
1348
hwinscmp(hash_datum *d1, hash_datum *d2)
1349
{
1350
struct host *host1 = (struct host *) d1;
1351
struct host *host2 = (struct host *) d2;
1352
1353
if (host1->htype != host2->htype) {
1354
return FALSE;
1355
}
1356
if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
1357
return FALSE;
1358
}
1359
/* XXX - Is the subnet_mask field set yet? */
1360
if ((host1->subnet_mask.s_addr) == (host2->subnet_mask.s_addr)) {
1361
if (((host1->iaddr.s_addr) & (host1->subnet_mask.s_addr)) !=
1362
((host2->iaddr.s_addr) & (host2->subnet_mask.s_addr)))
1363
{
1364
return FALSE;
1365
}
1366
}
1367
return TRUE;
1368
}
1369
1370
1371
/*
1372
* Macros for use in the function below:
1373
*/
1374
1375
#define DUP_COPY(MEMBER) do \
1376
{ \
1377
if (!hp->flags.MEMBER) { \
1378
if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1379
hp->MEMBER = hp2->MEMBER; \
1380
} \
1381
} \
1382
} while (0)
1383
1384
#define DUP_LINK(MEMBER) do \
1385
{ \
1386
if (!hp->flags.MEMBER) { \
1387
if ((hp->flags.MEMBER = hp2->flags.MEMBER) != 0) { \
1388
assert(hp2->MEMBER); \
1389
hp->MEMBER = hp2->MEMBER; \
1390
(hp->MEMBER->linkcount)++; \
1391
} \
1392
} \
1393
} while (0)
1394
1395
/*
1396
* Process the "similar entry" symbol.
1397
*
1398
* The host specified as the value of the "tc" symbol is used as a template
1399
* for the current host entry. Symbol values not explicitly set in the
1400
* current host entry are inferred from the template entry.
1401
*/
1402
PRIVATE void
1403
fill_defaults(struct host *hp, char **src)
1404
{
1405
unsigned int tlen, hashcode;
1406
struct host *hp2;
1407
char tstring[MAXSTRINGLEN];
1408
1409
tlen = sizeof(tstring);
1410
(void) get_string(src, tstring, &tlen);
1411
hashcode = hash_HashFunction((u_char *) tstring, tlen);
1412
hp2 = (struct host *) hash_Lookup(nmhashtable, hashcode, nmcmp, tstring);
1413
1414
if (hp2 == NULL) {
1415
report(LOG_ERR, "can't find tc=\"%s\"", tstring);
1416
return;
1417
}
1418
DUP_LINK(bootfile);
1419
DUP_LINK(cookie_server);
1420
DUP_LINK(domain_server);
1421
DUP_LINK(gateway);
1422
/* haddr not copied */
1423
DUP_LINK(homedir);
1424
DUP_COPY(htype);
1425
1426
DUP_LINK(impress_server);
1427
/* iaddr not copied */
1428
DUP_LINK(log_server);
1429
DUP_LINK(lpr_server);
1430
DUP_LINK(name_server);
1431
DUP_LINK(rlp_server);
1432
1433
DUP_COPY(subnet_mask);
1434
DUP_COPY(time_offset);
1435
DUP_LINK(time_server);
1436
1437
if (!hp->flags.vm_cookie) {
1438
if ((hp->flags.vm_cookie = hp2->flags.vm_cookie)) {
1439
bcopy(hp2->vm_cookie, hp->vm_cookie, 4);
1440
}
1441
}
1442
if (!hp->flags.name_switch) {
1443
if ((hp->flags.name_switch = hp2->flags.name_switch)) {
1444
hp->flags.send_name = hp2->flags.send_name;
1445
}
1446
}
1447
if (!hp->flags.bootsize) {
1448
if ((hp->flags.bootsize = hp2->flags.bootsize)) {
1449
hp->flags.bootsize_auto = hp2->flags.bootsize_auto;
1450
hp->bootsize = hp2->bootsize;
1451
}
1452
}
1453
DUP_COPY(bootserver);
1454
1455
DUP_LINK(tftpdir);
1456
DUP_LINK(dump_file);
1457
DUP_LINK(domain_name);
1458
1459
DUP_COPY(swap_server);
1460
DUP_LINK(root_path);
1461
DUP_LINK(exten_file);
1462
1463
DUP_COPY(reply_addr);
1464
1465
DUP_LINK(nis_domain);
1466
DUP_LINK(nis_server);
1467
DUP_LINK(ntp_server);
1468
1469
#ifdef YORK_EX_OPTION
1470
DUP_LINK(exec_file);
1471
#endif
1472
1473
DUP_COPY(msg_size);
1474
DUP_COPY(min_wait);
1475
1476
/* XXX - Add new tags here */
1477
1478
DUP_LINK(generic);
1479
1480
}
1481
#undef DUP_COPY
1482
#undef DUP_LINK
1483
1484
1485
1486
/*
1487
* This function adjusts the caller's pointer to point just past the
1488
* first-encountered colon. If it runs into a null character, it leaves
1489
* the pointer pointing to it.
1490
*/
1491
1492
PRIVATE void
1493
adjust(char **s)
1494
{
1495
char *t;
1496
1497
t = *s;
1498
while (*t && (*t != ':')) {
1499
t++;
1500
}
1501
if (*t) {
1502
t++;
1503
}
1504
*s = t;
1505
}
1506
1507
1508
1509
1510
/*
1511
* This function adjusts the caller's pointer to point to the first
1512
* non-whitespace character. If it runs into a null character, it leaves
1513
* the pointer pointing to it.
1514
*/
1515
1516
PRIVATE void
1517
eat_whitespace(char **s)
1518
{
1519
char *t;
1520
1521
t = *s;
1522
while (*t && isspace(*t)) {
1523
t++;
1524
}
1525
*s = t;
1526
}
1527
1528
1529
1530
/*
1531
* This function converts the given string to all lowercase.
1532
*/
1533
1534
PRIVATE void
1535
makelower(char *s)
1536
{
1537
while (*s) {
1538
if (isupper(*s)) {
1539
*s = tolower(*s);
1540
}
1541
s++;
1542
}
1543
}
1544
1545
1546
1547
/*
1548
*
1549
* N O T E :
1550
*
1551
* In many of the functions which follow, a parameter such as "src" or
1552
* "symbol" is passed as a pointer to a pointer to something. This is
1553
* done for the purpose of letting the called function update the
1554
* caller's copy of the parameter (i.e. to effect call-by-reference
1555
* parameter passing). The value of the actual parameter is only used
1556
* to locate the real parameter of interest and then update this indirect
1557
* parameter.
1558
*
1559
* I'm sure somebody out there won't like this. . . .
1560
* (Yea, because it usually makes code slower... -gwr)
1561
*
1562
*/
1563
1564
1565
1566
/*
1567
* "src" points to a character pointer which points to an ASCII string of
1568
* whitespace-separated IP addresses. A pointer to an in_addr_list
1569
* structure containing the list of addresses is returned. NULL is
1570
* returned if no addresses were found at all. The pointer pointed to by
1571
* "src" is updated to point to the first non-address (illegal) character.
1572
*/
1573
1574
PRIVATE struct in_addr_list *
1575
get_addresses(char **src)
1576
{
1577
struct in_addr tmpaddrlist[MAXINADDRS];
1578
struct in_addr *address1, *address2;
1579
struct in_addr_list *result;
1580
unsigned addrcount, totalsize;
1581
1582
address1 = tmpaddrlist;
1583
for (addrcount = 0; addrcount < MAXINADDRS; addrcount++) {
1584
while (isspace(**src) || (**src == ',')) {
1585
(*src)++;
1586
}
1587
if (!**src) { /* Quit if nothing more */
1588
break;
1589
}
1590
if (prs_inetaddr(src, &(address1->s_addr)) < 0) {
1591
break;
1592
}
1593
address1++; /* Point to next address slot */
1594
}
1595
if (addrcount < 1) {
1596
result = NULL;
1597
} else {
1598
totalsize = sizeof(struct in_addr_list)
1599
+ (addrcount - 1) * sizeof(struct in_addr);
1600
result = (struct in_addr_list *) smalloc(totalsize);
1601
result->linkcount = 1;
1602
result->addrcount = addrcount;
1603
address1 = tmpaddrlist;
1604
address2 = result->addr;
1605
for (; addrcount > 0; addrcount--) {
1606
address2->s_addr = address1->s_addr;
1607
address1++;
1608
address2++;
1609
}
1610
}
1611
return result;
1612
}
1613
1614
1615
1616
/*
1617
* prs_inetaddr(src, result)
1618
*
1619
* "src" is a value-result parameter; the pointer it points to is updated
1620
* to point to the next data position. "result" points to an unsigned long
1621
* in which an address is returned.
1622
*
1623
* This function parses the IP address string in ASCII "dot notation" pointed
1624
* to by (*src) and places the result (in network byte order) in the unsigned
1625
* long pointed to by "result". For malformed addresses, -1 is returned,
1626
* (*src) points to the first illegal character, and the unsigned long pointed
1627
* to by "result" is unchanged. Successful calls return 0.
1628
*/
1629
1630
PRIVATE int
1631
prs_inetaddr(char **src, u_int32 *result)
1632
{
1633
char tmpstr[MAXSTRINGLEN];
1634
u_int32 value;
1635
u_int32 parts[4], *pp;
1636
int n;
1637
char *s, *t;
1638
1639
/* Leading alpha char causes IP addr lookup. */
1640
if (isalpha(**src)) {
1641
/* Lookup IP address. */
1642
s = *src;
1643
t = tmpstr;
1644
while ((isalnum(*s) || (*s == '.') ||
1645
(*s == '-') || (*s == '_') ) &&
1646
(t < &tmpstr[MAXSTRINGLEN - 1]) )
1647
*t++ = *s++;
1648
*t = '\0';
1649
*src = s;
1650
1651
n = lookup_ipa(tmpstr, result);
1652
if (n < 0)
1653
report(LOG_ERR, "can not get IP addr for %s", tmpstr);
1654
return n;
1655
}
1656
1657
/*
1658
* Parse an address in Internet format:
1659
* a.b.c.d
1660
* a.b.c (with c treated as 16-bits)
1661
* a.b (with b treated as 24 bits)
1662
*/
1663
pp = parts;
1664
loop:
1665
/* If it's not a digit, return error. */
1666
if (!isdigit(**src))
1667
return -1;
1668
*pp++ = get_u_long(src);
1669
if (**src == '.') {
1670
if (pp < (parts + 4)) {
1671
(*src)++;
1672
goto loop;
1673
}
1674
return (-1);
1675
}
1676
#if 0
1677
/* This is handled by the caller. */
1678
if (**src && !(isspace(**src) || (**src == ':'))) {
1679
return (-1);
1680
}
1681
#endif
1682
1683
/*
1684
* Construct the address according to
1685
* the number of parts specified.
1686
*/
1687
n = pp - parts;
1688
switch (n) {
1689
case 1: /* a -- 32 bits */
1690
value = parts[0];
1691
break;
1692
case 2: /* a.b -- 8.24 bits */
1693
value = (parts[0] << 24) | (parts[1] & 0xFFFFFF);
1694
break;
1695
case 3: /* a.b.c -- 8.8.16 bits */
1696
value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1697
(parts[2] & 0xFFFF);
1698
break;
1699
case 4: /* a.b.c.d -- 8.8.8.8 bits */
1700
value = (parts[0] << 24) | ((parts[1] & 0xFF) << 16) |
1701
((parts[2] & 0xFF) << 8) | (parts[3] & 0xFF);
1702
break;
1703
default:
1704
return (-1);
1705
}
1706
*result = htonl(value);
1707
return (0);
1708
}
1709
1710
1711
1712
/*
1713
* "src" points to a pointer which in turn points to a hexadecimal ASCII
1714
* string. This string is interpreted as a hardware address and returned
1715
* as a pointer to the actual hardware address, represented as an array of
1716
* bytes.
1717
*
1718
* The ASCII string must have the proper number of digits for the specified
1719
* hardware type (e.g. twelve digits for a 48-bit Ethernet address).
1720
* Two-digit sequences (bytes) may be separated with periods (.) and/or
1721
* prefixed with '0x' for readability, but this is not required.
1722
*
1723
* For bad addresses, the pointer which "src" points to is updated to point
1724
* to the start of the first two-digit sequence which was bad, and the
1725
* function returns a NULL pointer.
1726
*/
1727
1728
PRIVATE byte *
1729
prs_haddr(char **src, u_int htype)
1730
{
1731
static byte haddr[MAXHADDRLEN];
1732
byte *hap;
1733
char tmpstr[MAXSTRINGLEN];
1734
u_int tmplen;
1735
unsigned hal;
1736
char *p;
1737
1738
hal = haddrlength(htype); /* Get length of this address type */
1739
if (hal <= 0) {
1740
report(LOG_ERR, "Invalid addr type for HW addr parse");
1741
return NULL;
1742
}
1743
tmplen = sizeof(tmpstr);
1744
get_string(src, tmpstr, &tmplen);
1745
p = tmpstr;
1746
1747
/* If it's a valid host name, try to lookup the HW address. */
1748
if (goodname(p)) {
1749
/* Lookup Hardware Address for hostname. */
1750
if ((hap = lookup_hwa(p, htype)) != NULL)
1751
return hap; /* success */
1752
report(LOG_ERR, "Add 0x prefix if hex value starts with A-F");
1753
/* OK, assume it must be numeric. */
1754
}
1755
1756
hap = haddr;
1757
while (hap < haddr + hal) {
1758
if ((*p == '.') || (*p == ':'))
1759
p++;
1760
if (interp_byte(&p, hap++) < 0) {
1761
return NULL;
1762
}
1763
}
1764
return haddr;
1765
}
1766
1767
1768
1769
/*
1770
* "src" is a pointer to a character pointer which in turn points to a
1771
* hexadecimal ASCII representation of a byte. This byte is read, the
1772
* character pointer is updated, and the result is deposited into the
1773
* byte pointed to by "retbyte".
1774
*
1775
* The usual '0x' notation is allowed but not required. The number must be
1776
* a two digit hexadecimal number. If the number is invalid, "src" and
1777
* "retbyte" are left untouched and -1 is returned as the function value.
1778
* Successful calls return 0.
1779
*/
1780
1781
PRIVATE int
1782
interp_byte(char **src, byte *retbyte)
1783
{
1784
int v;
1785
1786
if ((*src)[0] == '0' &&
1787
((*src)[1] == 'x' ||
1788
(*src)[1] == 'X')) {
1789
(*src) += 2; /* allow 0x for hex, but don't require it */
1790
}
1791
if (!isxdigit((*src)[0]) || !isxdigit((*src)[1])) {
1792
return -1;
1793
}
1794
if (sscanf(*src, "%2x", &v) != 1) {
1795
return -1;
1796
}
1797
(*src) += 2;
1798
*retbyte = (byte) (v & 0xFF);
1799
return 0;
1800
}
1801
1802
1803
1804
/*
1805
* The parameter "src" points to a character pointer which points to an
1806
* ASCII string representation of an unsigned number. The number is
1807
* returned as an unsigned long and the character pointer is updated to
1808
* point to the first illegal character.
1809
*/
1810
1811
PRIVATE u_int32
1812
get_u_long(char **src)
1813
{
1814
u_int32 value, base;
1815
char c;
1816
1817
/*
1818
* Collect number up to first illegal character. Values are specified
1819
* as for C: 0x=hex, 0=octal, other=decimal.
1820
*/
1821
value = 0;
1822
base = 10;
1823
if (**src == '0') {
1824
base = 8;
1825
(*src)++;
1826
}
1827
if (**src == 'x' || **src == 'X') {
1828
base = 16;
1829
(*src)++;
1830
}
1831
while ((c = **src)) {
1832
if (isdigit(c)) {
1833
value = (value * base) + (c - '0');
1834
(*src)++;
1835
continue;
1836
}
1837
if (base == 16 && isxdigit(c)) {
1838
value = (value << 4) + ((c & ~32) + 10 - 'A');
1839
(*src)++;
1840
continue;
1841
}
1842
break;
1843
}
1844
return value;
1845
}
1846
1847
1848
1849
/*
1850
* Routines for deletion of data associated with the main data structure.
1851
*/
1852
1853
1854
/*
1855
* Frees the entire host data structure given. Does nothing if the passed
1856
* pointer is NULL.
1857
*/
1858
1859
PRIVATE void
1860
free_host(hash_datum *hmp)
1861
{
1862
struct host *hostptr = (struct host *) hmp;
1863
if (hostptr == NULL)
1864
return;
1865
assert(hostptr->linkcount > 0);
1866
if (--(hostptr->linkcount))
1867
return; /* Still has references */
1868
del_iplist(hostptr->cookie_server);
1869
del_iplist(hostptr->domain_server);
1870
del_iplist(hostptr->gateway);
1871
del_iplist(hostptr->impress_server);
1872
del_iplist(hostptr->log_server);
1873
del_iplist(hostptr->lpr_server);
1874
del_iplist(hostptr->name_server);
1875
del_iplist(hostptr->rlp_server);
1876
del_iplist(hostptr->time_server);
1877
del_iplist(hostptr->nis_server);
1878
del_iplist(hostptr->ntp_server);
1879
1880
/*
1881
* XXX - Add new tags here
1882
* (if the value is an IP list)
1883
*/
1884
1885
del_string(hostptr->hostname);
1886
del_string(hostptr->homedir);
1887
del_string(hostptr->bootfile);
1888
del_string(hostptr->tftpdir);
1889
del_string(hostptr->root_path);
1890
del_string(hostptr->domain_name);
1891
del_string(hostptr->dump_file);
1892
del_string(hostptr->exten_file);
1893
del_string(hostptr->nis_domain);
1894
1895
#ifdef YORK_EX_OPTION
1896
del_string(hostptr->exec_file);
1897
#endif
1898
1899
/*
1900
* XXX - Add new tags here
1901
* (if it is a shared string)
1902
*/
1903
1904
del_bindata(hostptr->generic);
1905
free((char *) hostptr);
1906
}
1907
1908
1909
1910
/*
1911
* Decrements the linkcount on the given IP address data structure. If the
1912
* linkcount goes to zero, the memory associated with the data is freed.
1913
*/
1914
1915
PRIVATE void
1916
del_iplist(struct in_addr_list *iplist)
1917
{
1918
if (iplist) {
1919
if (!(--(iplist->linkcount))) {
1920
free((char *) iplist);
1921
}
1922
}
1923
}
1924
1925
1926
1927
/*
1928
* Decrements the linkcount on a string data structure. If the count
1929
* goes to zero, the memory associated with the string is freed. Does
1930
* nothing if the passed pointer is NULL.
1931
*/
1932
1933
PRIVATE void
1934
del_string(struct shared_string *stringptr)
1935
{
1936
if (stringptr) {
1937
if (!(--(stringptr->linkcount))) {
1938
free((char *) stringptr);
1939
}
1940
}
1941
}
1942
1943
1944
1945
/*
1946
* Decrements the linkcount on a shared_bindata data structure. If the
1947
* count goes to zero, the memory associated with the data is freed. Does
1948
* nothing if the passed pointer is NULL.
1949
*/
1950
1951
PRIVATE void
1952
del_bindata(struct shared_bindata *dataptr)
1953
{
1954
if (dataptr) {
1955
if (!(--(dataptr->linkcount))) {
1956
free((char *) dataptr);
1957
}
1958
}
1959
}
1960
1961
1962
1963
1964
/* smalloc() -- safe malloc()
1965
*
1966
* Always returns a valid pointer (if it returns at all). The allocated
1967
* memory is initialized to all zeros. If malloc() returns an error, a
1968
* message is printed using the report() function and the program aborts
1969
* with a status of 1.
1970
*/
1971
1972
PRIVATE char *
1973
smalloc(unsigned nbytes)
1974
{
1975
char *retvalue;
1976
1977
retvalue = malloc(nbytes);
1978
if (!retvalue) {
1979
report(LOG_ERR, "malloc() failure -- exiting");
1980
exit(1);
1981
}
1982
bzero(retvalue, nbytes);
1983
return retvalue;
1984
}
1985
1986
1987
/*
1988
* Compare function to determine whether two hardware addresses are
1989
* equivalent. Returns TRUE if "host1" and "host2" are equivalent, FALSE
1990
* otherwise.
1991
*
1992
* This function is used when retrieving elements from the hardware address
1993
* hash table.
1994
*/
1995
1996
boolean
1997
hwlookcmp(hash_datum *d1, hash_datum *d2)
1998
{
1999
struct host *host1 = (struct host *) d1;
2000
struct host *host2 = (struct host *) d2;
2001
2002
if (host1->htype != host2->htype) {
2003
return FALSE;
2004
}
2005
if (bcmp(host1->haddr, host2->haddr, haddrlength(host1->htype))) {
2006
return FALSE;
2007
}
2008
return TRUE;
2009
}
2010
2011
2012
/*
2013
* Compare function for doing IP address hash table lookup.
2014
*/
2015
2016
boolean
2017
iplookcmp(hash_datum *d1, hash_datum *d2)
2018
{
2019
struct host *host1 = (struct host *) d1;
2020
struct host *host2 = (struct host *) d2;
2021
2022
return (host1->iaddr.s_addr == host2->iaddr.s_addr);
2023
}
2024
2025
/*
2026
* Local Variables:
2027
* tab-width: 4
2028
* c-indent-level: 4
2029
* c-argdecl-indent: 4
2030
* c-continued-statement-offset: 4
2031
* c-continued-brace-offset: -4
2032
* c-label-offset: -4
2033
* c-brace-offset: 0
2034
* End:
2035
*/
2036
2037