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