]> git.sesse.net Git - nbtscanner/blob - configfile.c
Import nbtscanner 0.2.0.
[nbtscanner] / configfile.c
1 /*
2  * nbtscanner -- a tool for scanning large networks for SMB servers.
3  *
4  * configfile.c: Functions for parsing the configuration file.
5  * Copyright (C) 2000 Steinar H. Gunderson
6  *
7  * Large amounts of code adapted from Samba (http://www.samba.org/)
8  * Copyright (C) Andrew Tridgell 1994-1998, and others.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 #include "configfile.h"
26 #include "nbtscanner.h"
27 #include "mysql_interface.h"
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35
36 int num_retries;
37 int retry_time;
38 int delay_time;
39 int ghost_lifetime;
40 int verbosity;
41
42 int scan_interval;
43 int scan_wait;
44
45 struct in_addr scanrange[NUM_RANGES];
46 int scanrangesize[NUM_RANGES];
47 int ranges;
48
49 int use_mysql;
50 char mysql_host[64];
51 char mysql_username[32];
52 char mysql_password[32];
53
54 void parse_configfile()
55 {
56         FILE *configfile = fopen("nbtscanner.conf", "r");
57         int lineno = 0;
58
59         if (configfile == NULL) {
60                 perror("nbtscanner.conf");
61                 exit(1);
62         }
63
64         /* defaults */
65         num_retries = 3;
66         retry_time = 5000;
67         delay_time = 100;
68         ghost_lifetime = 1800;
69         verbosity = 2;
70
71         ranges = 0;
72
73         use_mysql = 0;
74         strcpy(mysql_host, "no_host_given");
75         strcpy(mysql_username, "no_username_given");
76         strcpy(mysql_password, "no_password_given");
77
78         while (!feof(configfile)) {
79                 char buf[1024];
80         
81                 lineno++;
82
83                 fgets(buf, 1024, configfile);
84                 while (buf[strlen(buf) - 1] == '\n' || buf[strlen(buf) - 1] == '\r') {
85                         buf[strlen(buf) - 1] = '\0';
86                 }
87
88                 if (buf[0] == '#' || buf[0] == '\0') {
89                         /* comment or blank line */
90                         continue;
91                 }
92                 if (strspn(buf, " \t") == strlen(buf)) {
93                         /* blank line */
94                         continue;
95                 }
96                 
97                 parse_line(buf, lineno);
98         }
99
100         fclose(configfile);
101 }
102
103 void parse_line(char *buf, int lineno)
104 {
105         char *ptr = strchr(buf, '=');
106
107         if (ptr == NULL || strchr(ptr + 1, '=') != NULL) {
108                 line_error(lineno, "Malformed line (must be exactly one `=' sign)");
109         }
110
111         /* split the line into a keyword and a value */
112         ptr[0] = 0;
113         ptr++;
114
115         /*
116          * trim any trailing spaces, make sure there are no spaces in
117          * the value
118          */
119         {
120                 char *ptr2 = strchr(ptr, ' ');
121                 if (ptr2 != NULL) {
122                         /* must only be spaces from here */
123                         if (strspn(ptr2 + 1, " ") != strlen(ptr2 + 1)) {
124                                 line_error(lineno, "Malformed value (can't have any spaces)");
125                         }
126
127                         ptr2[0] = 0;
128                 }
129         }
130
131         /* make sure both the parameter and the value is non-empty */
132         if (buf[0] == '\0') {
133                 line_error(lineno, "Malformed keyword (can't be empty)");
134         }
135         if (ptr[0] == '\0') {
136                 line_error(lineno, "Malformed value (can't be empty)");
137         }
138
139         /* finally pass it on to the keyword checker */
140         parse_keyword(buf, ptr, lineno);
141 }
142
143 void parse_keyword(char *keyword, char *value, int lineno)
144 {
145         if (strcasecmp(keyword, "num_retries") == 0) {
146                 parse_int(value, &num_retries, lineno);
147         } else if (strcasecmp(keyword, "retry_time") == 0) {
148                 parse_int(value, &retry_time, lineno);
149         } else if (strcasecmp(keyword, "delay_time") == 0) {
150                 parse_int(value, &delay_time, lineno);
151         } else if (strcasecmp(keyword, "ghost_lifetime") == 0) {
152                 parse_int(value, &ghost_lifetime, lineno);
153         } else if (strcasecmp(keyword, "verbosity") == 0) {
154                 parse_int(value, &verbosity, lineno);
155         } else if (strcasecmp(keyword, "scan_interval") == 0) {
156                 parse_int(value, &scan_interval, lineno);
157         } else if (strcasecmp(keyword, "scan_wait") == 0) {
158                 parse_int(value, &scan_wait, lineno);
159         } else if (strcasecmp(keyword, "use_mysql") == 0) {
160                 parse_int(value, &use_mysql, lineno);
161         } else if (strcasecmp(keyword, "mysql_host") == 0) {
162                 strcpy(mysql_host, value);
163         } else if (strcasecmp(keyword, "mysql_username") == 0) {
164                 strcpy(mysql_username, value);
165         } else if (strcasecmp(keyword, "mysql_password") == 0) {
166                 strcpy(mysql_password, value);
167         } else if (strcasecmp(keyword, "range") == 0) {
168                 parse_range(value, lineno);
169         } else {
170                 char buf[1024];
171                 sprintf(buf, "Unknown keyword `%s'", keyword);
172                 line_error(lineno, buf);
173         }
174 }
175
176 void parse_int(char *string, int *retval, int lineno)
177 {
178         if (strspn(string, "0123456789") != strlen(string)) {
179                 char buf[1024];
180                 sprintf(buf, "`%s' isn't a positive integer", string);
181                 line_error(lineno, buf);
182         }
183
184         *retval = atoi(string);
185 }
186
187 void parse_range(char *string, int lineno)
188 {
189         /* exactly one / is allowed */
190         char *ptr = strchr(string, '/');
191         struct in_addr in;
192         int rangesize;
193
194         if (ptr != NULL && strchr(ptr + 1, '/') != NULL) {
195                 line_error(lineno, "Malformed range (only one `/' allowed)"); 
196         }
197
198         /* lots and lots of code :-) */
199         if (ptr == NULL) {              /* single IP */
200                 rangesize = 32;
201         } else {                        /* range */
202                 ptr[0] = 0;
203                 ptr++;
204
205                 /* find out whether this is a pure integer or not */
206                 if (strspn(ptr, "0123456789") == strlen(ptr)) {
207                         rangesize = atoi(ptr);
208                         if (rangesize < 0 || rangesize > 32) {
209                                 line_error(lineno, "Malformed range (significant bits must be between 0 and 32, inclusive)");
210                         }
211                 } else if (strspn(ptr, "0123456789.") == strlen(ptr)) {
212                         /* IP address... */
213                         struct in_addr netmask;
214                         int found, i;
215
216                         if (inet_aton(ptr, &netmask) == 0) {
217                                 line_error(lineno, "Malformed range (malformed netmask)");
218                         }
219
220                         /* find the rightmost 1-bit (by finding the leftmost 0-bit) */
221                         found = 0;
222                         for (i = 31; i >= 0; i--) {
223                                 if ((netmask.s_addr & (1 << i)) == 0) {
224                                         found = 1;
225                                         break;
226                                 }
227                         }
228                         if (found == 0) {
229                                 rangesize = 32;         /* 255.255.255.255 */
230                         } else {
231                                 unsigned int clean_mask = htonl(~((1 << (31-i)) - 1));
232
233                                 rangesize = i + 1;
234
235                                 /* verify that this is a `clean' netmask */
236                                 if (netmask.s_addr != clean_mask) {
237                                         line_error(lineno, "Malformed range (netmask must be `clean')");
238                                 }
239                         }
240                 } else {
241                         line_error(lineno, "Malformed range (malformed netmask)");
242                         rangesize = 32; /* will never reach this, but for gcc */
243                 }
244         }
245
246         /* try to scan the IP part */
247         if (inet_aton(string, &in) == 0) {
248                 line_error(lineno, "Malformed range (malformed IP address)");
249         }
250
251         /* check that the IP address and the netmask match */
252         if (rangesize != 32) {
253                 /* not really the netmask, actually it's the inverted netmask */
254                 unsigned int netmask = htonl((1 << (31-rangesize)) - 1);        
255
256                 if ((in.s_addr & netmask) != 0) {
257                         line_error(lineno, "Malformed range (IP address doesn't match netmask)");
258                 }
259         }
260
261         memcpy((char *)(&(scanrange[ranges])), (char *)(&in), sizeof(in));
262         scanrangesize[ranges++] = rangesize;
263 }
264
265 void line_error(int lineno, char *err_str)
266 {
267         fprintf(stderr, "nbtscanner.conf:%d: %s\n", lineno, err_str);
268         exit(1);
269 }