]> git.sesse.net Git - nbtscanner/blob - configfile.c
0faf1e5dbcccdbdd8a2231773762ce56086041fe
[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 verbosity;
40
41 int scan_interval;
42 int scan_wait;
43
44 struct in_addr scanrange[NUM_RANGES];
45 int scanrangesize[NUM_RANGES];
46 int ranges;
47
48 int use_mysql;
49 char mysql_host[64];
50 char mysql_username[32];
51 char mysql_password[32];
52
53 void parse_configfile()
54 {
55         FILE *configfile = fopen("nbtscanner.conf", "r");
56         int lineno = 0;
57
58         if (configfile == NULL) {
59                 perror("nbtscanner.conf");
60                 exit(1);
61         }
62
63         /* defaults */
64         num_retries = 3;
65         retry_time = 5000;
66         delay_time = 100;
67         verbosity = 2;
68
69         ranges = 0;
70
71         use_mysql = 0;
72         strcpy(mysql_host, "no_host_given");
73         strcpy(mysql_username, "no_username_given");
74         strcpy(mysql_password, "no_password_given");
75
76         while (!feof(configfile)) {
77                 char buf[1024];
78         
79                 lineno++;
80
81                 fgets(buf, 1024, configfile);
82                 while (buf[strlen(buf) - 1] == '\n' || buf[strlen(buf) - 1] == '\r') {
83                         buf[strlen(buf) - 1] = '\0';
84                 }
85
86                 if (buf[0] == '#' || buf[0] == '\0') {
87                         /* comment or blank line */
88                         continue;
89                 }
90                 if (strspn(buf, " \t") == strlen(buf)) {
91                         /* blank line */
92                         continue;
93                 }
94                 
95                 parse_line(buf, lineno);
96         }
97
98         fclose(configfile);
99 }
100
101 void parse_line(char *buf, int lineno)
102 {
103         char *ptr = strchr(buf, '=');
104
105         if (ptr == NULL || strchr(ptr + 1, '=') != NULL) {
106                 line_error(lineno, "Malformed line (must be exactly one `=' sign)");
107         }
108
109         /* split the line into a keyword and a value */
110         ptr[0] = 0;
111         ptr++;
112
113         /*
114          * trim any trailing spaces, make sure there are no spaces in
115          * the value
116          */
117         {
118                 char *ptr2 = strchr(ptr, ' ');
119                 if (ptr2 != NULL) {
120                         /* must only be spaces from here */
121                         if (strspn(ptr2 + 1, " ") != strlen(ptr2 + 1)) {
122                                 line_error(lineno, "Malformed value (can't have any spaces)");
123                         }
124
125                         ptr2[0] = 0;
126                 }
127         }
128
129         /* make sure both the parameter and the value is non-empty */
130         if (buf[0] == '\0') {
131                 line_error(lineno, "Malformed keyword (can't be empty)");
132         }
133         if (ptr[0] == '\0') {
134                 line_error(lineno, "Malformed value (can't be empty)");
135         }
136
137         /* finally pass it on to the keyword checker */
138         parse_keyword(buf, ptr, lineno);
139 }
140
141 void parse_keyword(char *keyword, char *value, int lineno)
142 {
143         if (strcasecmp(keyword, "num_retries") == 0) {
144                 parse_int(value, &num_retries, lineno);
145         } else if (strcasecmp(keyword, "retry_time") == 0) {
146                 parse_int(value, &retry_time, lineno);
147         } else if (strcasecmp(keyword, "delay_time") == 0) {
148                 parse_int(value, &delay_time, lineno);
149         } else if (strcasecmp(keyword, "verbosity") == 0) {
150                 parse_int(value, &verbosity, lineno);
151         } else if (strcasecmp(keyword, "scan_interval") == 0) {
152                 parse_int(value, &scan_interval, lineno);
153         } else if (strcasecmp(keyword, "scan_wait") == 0) {
154                 parse_int(value, &scan_wait, lineno);
155         } else if (strcasecmp(keyword, "use_mysql") == 0) {
156                 parse_int(value, &use_mysql, lineno);
157         } else if (strcasecmp(keyword, "mysql_host") == 0) {
158                 strcpy(mysql_host, value);
159         } else if (strcasecmp(keyword, "mysql_username") == 0) {
160                 strcpy(mysql_username, value);
161         } else if (strcasecmp(keyword, "mysql_password") == 0) {
162                 strcpy(mysql_password, value);
163         } else if (strcasecmp(keyword, "range") == 0) {
164                 parse_range(value, lineno);
165         } else {
166                 char buf[1024];
167                 sprintf(buf, "Unknown keyword `%s'", keyword);
168                 line_error(lineno, buf);
169         }
170 }
171
172 void parse_int(char *string, int *retval, int lineno)
173 {
174         if (strspn(string, "0123456789") != strlen(string)) {
175                 char buf[1024];
176                 sprintf(buf, "`%s' isn't a positive integer", string);
177                 line_error(lineno, buf);
178         }
179
180         *retval = atoi(string);
181 }
182
183 void parse_range(char *string, int lineno)
184 {
185         /* exactly one / is allowed */
186         char *ptr = strchr(string, '/');
187         struct in_addr in;
188         int rangesize;
189
190         if (ptr != NULL && strchr(ptr + 1, '/') != NULL) {
191                 line_error(lineno, "Malformed range (only one `/' allowed)"); 
192         }
193
194         /* lots and lots of code :-) */
195         if (ptr == NULL) {              /* single IP */
196                 rangesize = 32;
197         } else {                        /* range */
198                 ptr[0] = 0;
199                 ptr++;
200
201                 /* find out whether this is a pure integer or not */
202                 if (strspn(ptr, "0123456789") == strlen(ptr)) {
203                         rangesize = atoi(ptr);
204                         if (rangesize < 0 || rangesize > 32) {
205                                 line_error(lineno, "Malformed range (significant bits must be between 0 and 32, inclusive)");
206                         }
207                 } else if (strspn(ptr, "0123456789.") == strlen(ptr)) {
208                         /* IP address... */
209                         struct in_addr netmask;
210                         int found, i;
211
212                         if (inet_aton(ptr, &netmask) == 0) {
213                                 line_error(lineno, "Malformed range (malformed netmask)");
214                         }
215
216                         /* find the rightmost 1-bit (by finding the leftmost 0-bit) */
217                         found = 0;
218                         for (i = 31; i >= 0; i--) {
219                                 if ((netmask.s_addr & (1 << i)) == 0) {
220                                         found = 1;
221                                         break;
222                                 }
223                         }
224                         if (found == 0) {
225                                 rangesize = 32;         /* 255.255.255.255 */
226                         } else {
227                                 unsigned int clean_mask = htonl(~((1 << (31-i)) - 1));
228
229                                 rangesize = i + 1;
230
231                                 /* verify that this is a `clean' netmask */
232                                 if (netmask.s_addr != clean_mask) {
233                                         line_error(lineno, "Malformed range (netmask must be `clean')");
234                                 }
235                         }
236                 } else {
237                         line_error(lineno, "Malformed range (malformed netmask)");
238                         rangesize = 32; /* will never reach this, but for gcc */
239                 }
240         }
241
242         /* try to scan the IP part */
243         if (inet_aton(string, &in) == 0) {
244                 line_error(lineno, "Malformed range (malformed IP address)");
245         }
246
247         /* check that the IP address and the netmask match */
248         if (rangesize != 32) {
249                 /* not really the netmask, actually it's the inverted netmask */
250                 unsigned int netmask = htonl((1 << (31-rangesize)) - 1);        
251
252                 if ((in.s_addr & netmask) != 0) {
253                         line_error(lineno, "Malformed range (IP address doesn't match netmask)");
254                 }
255         }
256
257         memcpy((char *)(&(scanrange[ranges])), (char *)(&in), sizeof(in));
258         scanrangesize[ranges++] = rangesize;
259 }
260
261 void line_error(int lineno, char *err_str)
262 {
263         fprintf(stderr, "nbtscanner.conf:%d: %s\n", lineno, err_str);
264         exit(1);
265 }