1 %{
2
3 /*
4 * ufdbGuard is copyrighted (C) 2005-2020 by URLfilterDB B.V. with all rights reserved.
5 *
6 * Parts of the ufdbGuard daemon are based on squidGuard.
7 * squidGuard is copyrighted (C) 1998 by
8 * ElTele �st AS, Oslo, Norway, with all rights reserved.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License (version 2) as
12 * published by the Free Software Foundation. It is distributed in the
13 * hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License (GPL) for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * (GPL2) along with this program.
19 */
20
21 #define YYMALLOC ufdbMalloc
22 #define YYFREE ufdbFree
23
24 #define UFDB_LOG_USER_QUOTA 0 /* TODO remove */
25
26 #undef UFDB_DEBUG_ACL_ACCESS
27 #define UFDB_DEBUG_ACL_ACCESS 1
28
29 #include "ufdb.h"
30 #include "sg.h"
31 #include "ufdb_globals.h"
32 #include "ufdblib.h"
33 #include "ufdbdb.h"
34 #include "ufdbchkport.h"
35
36 #define UFDB_DEBUG 1
37
38 #if UFDB_DEBUG
39 #undef YYDEBUG
40 #define YYDEBUG 1
41 #endif
42
43 #define UFDB_TIME_DEBUG 0
44
45 #if __linux__
46 #include <sys/mman.h>
47 #endif
48 #include <pthread.h>
49 #include <sys/types.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <errno.h>
53 #include <netdb.h>
54 #include <grp.h>
55 #include <syslog.h>
56 #include <signal.h>
57 #include <sched.h>
58 #include <fcntl.h>
59 #include <sys/stat.h>
60 #include <unistd.h>
61 #include <sys/socket.h>
62
63
64 extern FILE * yyin;
65 extern FILE * yyout;
66
67 int lineno;
68
69 static int numTimeElements = 0;
70 static int * TimeElementsEvents = NULL;
71
72 static int time_switch = 0;
73 static int date_switch = 0;
74
75 static void setDBhome( char * dbhome );
76 static void setAdministrator( char * value );
77 static void setLogdir( char * value );
78 static void setPidfile( char * value );
79 static void setRefreshUserlist( int nmin );
80 static void setRefreshDomainlist( int nmin );
81 static void setRefreshIPlist( int nmin );
82 static void ufdbSourceExecIPList( char * command );
83
84 static void ufdbSourceGroup( int groupType, char * groupName );
85 static void ufdbSourceUserQuota( const char * seconds, const char * sporadic, const char * renew );
86 static void ufdbSourceUser( char * user );
87 static void ufdbSourceUserList( char * file );
88 static void ufdbSourceExecUserList( char * command );
89
90 static void defSource( char * source );
91 static void defSourceEnd( void );
92 static struct Source * defSourceFindName( struct Source * slist, const char * name );
93 static void defSourceDomain( char * );
94 static void ufdbSourceEval( int method );
95 static void defSourceIPV4List( char * file );
96 static void defSourceIPV6List( char * file );
97
98 static void ufdbCategoryCACertsFile( char * cacertsFile );
99 static void ufdbCategoryCACertsDir( char * cacertsDir );
100
101 static void sgIpv4( const char * name, int type, const char * file, int lineno );
102 static void sgIpv6( const char * addr, int type, const char * file, int line );
103
104 void ufdbFreeDomainDb( struct sgDb * dbp );
105
106 static void ufdbAcl( const char * name, const char * value, int within );
107 static void ufdbAclSetValue( const char * what, const char * value, int allowed );
108
109 static void sgTime( char * );
110 static struct ufdbTime * sgTimeFindName( const char * name );
111 static void sgTimeElementInit( void );
112 static void sgTimeElementAdd( char *, char );
113 static void sgTimeElementEnd( void );
114 static void sgTimeElementClone( void );
115 static void defSourceTime( char * name, int within );
116
117 static void ufdbCategoryTime( char * name, int within );
118 static void ufdbCategoryActiveBumping( int flag );
119 static void ufdbCategoryBlockConnect( int flag );
120 static void ufdbCategoryRewrite( char * value );
121 static void ufdbCategoryRedirect( char * value );
122 static void ufdbCategoryExecDomainList( char * command );
123
124 static void ufdbCategoryUrlList( char * urllist );
125 static void ufdbCategoryOption( int value, int option );
126
127 static void sgRewrite( char * rewrite );
128 static void sgRewriteTime( char * name, int within );
129 static void sgRewriteSubstitute( char * string );
130 static struct sgRewrite * sgRewriteFindName( const char * name );
131
132 static void logConfig( void );
133
134 %}
135
136 %union {
137 char * string;
138 char * tval;
139 char * dval;
140 char * dvalcron;
141 int integer;
142 }
143
144 %token ADMINISTRATOR QSTRING
145 %token CHECK_PROXY_TUNNELS QUEUE_CHECKS AGGRESSIVE LOG_ONLY
146 %token ON OFF
147 %token CHAR_MINUS CHAR_I CHAR_EXCLAMATION
148 %token IGNORECASE
149 %token COMMA EQUAL PORT
150 %token HTTP_SERVER INTERFACE IMAGES
151 %token HTTPS_PROHIBIT_INSECURE_SSLV2 HTTPS_PROHIBIT_INSECURE_SSLV3
152 %token HTTPS_CONNECTION_CACHE_SIZE
153 %token IDENTIFIER WORD END START_BRACKET STOP_BRACKET WEEKDAY
154 %token CATEGORY REWRITE ACL CPUS TIME TVAL DVAL DVALCRON
155 %token BLOCK_BUMPED_CONNECT EVALUATE_AND EVALUATE_OR
156 %token SOURCE CONTINUE
157 %token IPV4ADDR IPV4NET IPV4CLASS IPV4RANGE
158 %token IPV6ADDR IPV6NET
159 %token DBHOME DOMAINLIST EXECDOMAINLIST REFRESHDOMAINLIST
160 %token URLLIST EXPRESSIONLIST CACERTS CACERTSDIR
161 %token IPV4 IPV4LIST IPV6 IPV6LIST
162 %token DOMAIN UNIX LDAP USER USERLIST EXECUSERLIST REFRESHUSERLIST
163 %token EXECIPLIST REFRESHIPLIST
164 %token USERQUOTA GROUP
165 %token NL NUMBER NUMBERS
166 %token PASS REDIRECT SUBST CHAR MINUTELY HOURLY DAILY WEEKLY DATE
167 %token REDIRECT_FATAL_ERROR REDIRECT_LOADING_DATABASE REDIRECT_HTTPS REDIRECT_BUMPED_HTTPS
168 %token WITHIN OUTSIDE ELSE ANONYMOUS SPORADIC
169 %token PIDFILE LOGFILE LOGDIR LOGPASS LOGBLOCK LOGALL LOGALL_HTTPD
170 %token MAIL_SERVER MY_HOSTNAME ADMIN_EMAIL SENDER_EMAIL EXTERNAL_STATUS_COMMAND
171 %token TOKEN_ALLOW TOKEN_DENY
172 %token YOUTUBE_EDUFILTER YOUTUBE_EDUFILTER_ID ALLOW_GOOGLE_HTTPS_USING_IP
173 %token URL_LOOKUP_RESULT_DB_RELOAD URL_LOOKUP_RESULT_FATAL_ERROR
174 %token URL_LOOKUP_DELAY_DB_RELOAD
175 %token OPTION UFDB_SHOW_URL_DETAILS UFDB_LOG_URL_DETAILS
176 %token SQUID_VERSION SQUID_USES_ACTIVE_BUMPING
177 %token UPLOAD_CRASH_REPORTS LOOKUP_REVERSE_IP USE_IPV6_ON_WAN PARSE_URL_PARAMETERS
178 %token STRIP_DOMAIN_FROM_USERNAME
179 %token UFDB_DEBUG_FILTER UFDB_DEBUG_COREDUMP
180 %token MADVISE_HUGEPAGES FAST_REFRESH
181 %token UFDB_DEBUG_SKYPE_PROBES UFDB_DEBUG_GTALK_PROBES
182 %token UFDB_DEBUG_YAHOOMSG_PROBES UFDB_DEBUG_AIM_PROBES UFDB_DEBUG_FBCHAT_PROBES
183 %token UFDB_DEBUG_CITRIXONLINE_PROBES
184 %token UFDB_EXPRESSION_OPTIMISATION UFDB_EXPRESSION_DEBUG UFDB_DEBUG_EXTERNAL_SCRIPTS
185 %token UFDB_NUM_WORKER_THREADS
186 %token ENFORCE_HTTPS_WITH_HOSTNAME ENFORCE_HTTPS_OFFICAL_CERTIFICATE
187 %token ALLOW_SKYPE_OVER_HTTPS ALLOW_UNKNOWN_PROTOCOL_OVER_HTTPS
188 %token ALLOW_GTALK_OVER_HTTPS ALLOW_YAHOOMSG_OVER_HTTPS
189 %token ALLOW_AIM_OVER_HTTPS ALLOW_FBCHAT_OVER_HTTPS ALLOW_CITRIXONLINE_OVER_HTTPS
190 %token ALLOW_ANYDESK_OVER_HTTPS ALLOW_TEAMVIEWER_OVER_HTTPS
191 %token ANALYSE_UNCATEGORISED LOG_UNCATEGORISED_URLS UPLOAD_STATS
192 %token SAFE_SEARCH MAX_LOGFILE_SIZE
193
194
195 %type <string> IDENTIFIER
196 %type <string> WORD
197 %type <string> QSTRING
198 %type <string> WEEKDAY
199 %type <string> NUMBER
200 %type <string> NUMBERS
201 %type <tval> TVAL
202 %type <string> DVAL
203 %type <string> DVALCRON
204 %type <string> CHAR
205 %type <string> SUBST
206 %type <string> IPV4ADDR
207 %type <string> IPV4NET
208 %type <string> IPV4RANGE
209 %type <string> IPV4CLASS
210 %type <string> IPV6ADDR
211 %type <string> IPV6NET
212 %type <string> DBHOME LOGDIR
213 %type <string> dval
214 %type <string> dvalcron
215 %type <string> tval
216 %type <string> date
217 %type <string> ttime
218 %type <string> qidentifier
219
220 %type <integer> check_proxy_tunnel_option
221 %type <integer> allow_or_deny
222 %type <integer> on_or_off
223
224 %%
225
226 start: statements
227 ;
228
229 qidentifier:
230 IDENTIFIER { $$ = $1; }
231 | QSTRING { $$ = $1; }
232 ;
233
234 https_cache_size:
235 HTTPS_CONNECTION_CACHE_SIZE NUMBER { ufdbNewGV.httpsConnectionCacheSize = atoi( $2 );
236 ufdbFree( $2 ); }
237 ;
238
239 allow_or_deny:
240 TOKEN_ALLOW { $$ = UFDB_ALLOW; }
241 | TOKEN_DENY { $$ = UFDB_DENY; }
242 ;
243
244 on_or_off:
245 ON { $$ = 1; }
246 | OFF { $$ = 0; }
247 | error { ufdbLogFatalError( "syntax error at line %d: expected 'on' or 'off'", lineno ); }
248 ;
249
250 log_pass:
251 LOGPASS on_or_off { ufdbNewGV.logPass = $2; }
252 ;
253
254 log_block:
255 LOGBLOCK on_or_off { ufdbNewGV.logBlock = $2; }
256 ;
257
258 log_all:
259 LOGALL on_or_off { ufdbNewGV.logAllRequests = $2; }
260 ;
261
262 logall_httpd:
263 LOGALL_HTTPD on_or_off { ufdbNewGV.debugHttpd = $2; }
264 ;
265
266 youtube_edufilter:
267 YOUTUBE_EDUFILTER on_or_off { ufdbNewGV.YoutubeEdufilter = $2; }
268 ;
269
270 youtube_edufilter_id:
271 YOUTUBE_EDUFILTER_ID QSTRING { ufdbNewGV.YoutubeEdufilterID = $2; }
272 ;
273
274 allow_google_https_using_ip:
275 ALLOW_GOOGLE_HTTPS_USING_IP on_or_off { ufdbNewGV.allowGoogleHTTPSusingIP = $2; }
276 ;
277
278 madvise_hugepages:
279 MADVISE_HUGEPAGES on_or_off { ufdbNewGV.madviseHugePages = $2; }
280 ;
281
282 fast_refresh:
283 FAST_REFRESH on_or_off { ufdbNewGV.fastRefresh = $2; }
284 ;
285
286 debug_filter:
287 UFDB_DEBUG_FILTER on_or_off { ufdbNewGV.debug = ufdbGV.debug = $2; }
288 | UFDB_DEBUG_FILTER NUMBER { ufdbNewGV.debug = ufdbGV.debug = atoi( $2 );
289 ufdbFree( $2 ); }
290 ;
291
292 debug_coredump:
293 UFDB_DEBUG_COREDUMP on_or_off { ufdbNewGV.debugCoreDump = $2; }
294 ;
295
296 enforce_https_with_hostname:
297 ENFORCE_HTTPS_WITH_HOSTNAME on_or_off
298 { ufdbLogError( "line %d: option enforce-https-with-hostname must be part of "
299 "the security category", lineno ); }
300 ;
301
302 enforce_https_offical_certificate:
303 ENFORCE_HTTPS_OFFICAL_CERTIFICATE on_or_off
304 { ufdbLogError( "line %d: option enforce-https-official-certificate must be part of "
305 "the security category", lineno ); }
306 ;
307
308 https_prohibit_insecure_sslv2:
309 HTTPS_PROHIBIT_INSECURE_SSLV2 on_or_off
310 { ufdbLogError( "line %d: option https-prohibit-insecure-sslv2 must be part of "
311 "the security category", lineno ); }
312 ;
313
314 https_prohibit_insecure_sslv3:
315 HTTPS_PROHIBIT_INSECURE_SSLV3 on_or_off
316 { ufdbLogError( "line %d: option https-prohibit-insecure-sslv3 must be part of "
317 "the security category", lineno ); }
318 ;
319
320
321 check_proxy_tunnel_option:
322 OFF { $$ = UFDB_API_HTTPS_CHECK_OFF; }
323 | QUEUE_CHECKS { $$ = UFDB_API_HTTPS_CHECK_QUEUE_CHECKS; }
324 | AGGRESSIVE { $$ = UFDB_API_HTTPS_CHECK_AGGRESSIVE; }
325 | LOG_ONLY { $$ = UFDB_API_HTTPS_LOG_ONLY; }
326 ;
327
328 check_proxy_tunnels:
329 CHECK_PROXY_TUNNELS check_proxy_tunnel_option { ufdbNewGV.tunnelCheckMethod = $2; }
330 ;
331
332 admin_spec:
333 ADMINISTRATOR QSTRING { setAdministrator( $2 ); }
334 ;
335
336 dbhome:
337 DBHOME qidentifier { setDBhome( $2 ); }
338 | DBHOME WORD { setDBhome( $2 ); }
339 ;
340
341 refreshuserlist:
342 REFRESHUSERLIST NUMBER { setRefreshUserlist( atoi($2) );
343 ufdbFree( $2 ); }
344 ;
345
346 refreshiplist:
347 REFRESHIPLIST NUMBER { setRefreshIPlist( atoi($2) );
348 ufdbFree( $2 ); }
349 ;
350
351 refreshdomainlist:
352 REFRESHDOMAINLIST NUMBER { setRefreshDomainlist( atoi($2) );
353 ufdbFree( $2 ); }
354 ;
355
356 url_lookup_result_db_reload:
357 URL_LOOKUP_RESULT_DB_RELOAD allow_or_deny
358 { ufdbNewGV.URLlookupResultDBreload = $2; }
359
360 url_lookup_result_fatal_error:
361 URL_LOOKUP_RESULT_FATAL_ERROR allow_or_deny
362 { ufdbNewGV.URLlookupResultFatalError = $2; }
363
364 url_lookup_delay_db_reload:
365 URL_LOOKUP_DELAY_DB_RELOAD on_or_off
366 { ufdbNewGV.URLlookupDelayDBreload = $2; }
367
368 squid_version:
369 SQUID_VERSION QSTRING
370 { ufdbFree( ufdbNewGV.SquidVersion ); ufdbNewGV.SquidVersion = $2; }
371 ;
372
373 num_worker_threads:
374 UFDB_NUM_WORKER_THREADS NUMBER
375 { int new_n_workers;
376 /* ONLY increase #workers */
377 new_n_workers = atoi( $2 );
378 ufdbFree( $2 );
379 if (new_n_workers < UFDB_MIN_THREADS)
380 {
381 ufdbLogError( "num-worker-threads must be at least %d",
382 UFDB_MIN_THREADS );
383 new_n_workers = UFDB_MIN_THREADS;
384 }
385 else if (new_n_workers > UFDB_MAX_THREADS)
386 {
387 ufdbLogError( "num-worker-threads can be at most %d",
388 UFDB_MAX_THREADS );
389 new_n_workers = UFDB_MAX_THREADS;
390 }
391 if (new_n_workers > ufdbNewGV.nWorkers)
392 ufdbNewGV.nWorkers = new_n_workers;
393 }
394 ;
395
396 upload_crash_reports:
397 UPLOAD_CRASH_REPORTS on_or_off
398 { ufdbNewGV.uploadCrashReports = $2; }
399 ;
400
401 lookup_reverse_ip:
402 LOOKUP_REVERSE_IP on_or_off
403 { ufdbNewGV.lookupReverseIP = $2; }
404 ;
405
406 use_ipv6_on_wan:
407 USE_IPV6_ON_WAN on_or_off
408 { ufdbNewGV.useAlsoIPv6onWan = $2; }
409 ;
410
411 parse_url_parameters:
412 PARSE_URL_PARAMETERS on_or_off
413 { ufdbNewGV.parseURLparameters = $2; }
414 ;
415
416 squid_uses_active_bumping:
417 SQUID_USES_ACTIVE_BUMPING on_or_off
418 { ufdbNewGV.SquidUsesActiveBumping = $2; }
419 ;
420
421 ufdb_log_url_details:
422 UFDB_LOG_URL_DETAILS on_or_off { ufdbNewGV.logURLdetails = $2; }
423 ;
424
425 ufdb_show_url_details:
426 UFDB_SHOW_URL_DETAILS on_or_off { ufdbNewGV.showURLdetails = $2; }
427 ;
428
429 ufdb_debug_skype_probes:
430 UFDB_DEBUG_SKYPE_PROBES on_or_off { ufdbNewGV.debugSkype = $2; }
431 ;
432
433 ufdb_debug_gtalk_probes:
434 UFDB_DEBUG_GTALK_PROBES on_or_off { ufdbNewGV.debugGtalk = $2; }
435 ;
436
437 ufdb_debug_yahoomsg_probes:
438 UFDB_DEBUG_YAHOOMSG_PROBES on_or_off { ufdbNewGV.debugYahooMsg = $2; }
439 ;
440
441 ufdb_debug_aim_probes:
442 UFDB_DEBUG_AIM_PROBES on_or_off { ufdbNewGV.debugAim = $2; }
443 ;
444
445 ufdb_debug_fbchat_probes:
446 UFDB_DEBUG_FBCHAT_PROBES on_or_off { ufdbNewGV.debugFBchat = $2; }
447 ;
448
449 ufdb_debug_citrixonline_probes:
450 UFDB_DEBUG_CITRIXONLINE_PROBES on_or_off { ufdbNewGV.debugCitrixOnline = $2; }
451 ;
452
453 ufdb_expression_optimisation:
454 UFDB_EXPRESSION_OPTIMISATION on_or_off { ufdbNewGV.expressionOptimisation = $2; }
455 ;
456
457 ufdb_expression_debug:
458 UFDB_EXPRESSION_DEBUG on_or_off { ufdbNewGV.debugRegexp = $2; }
459 ;
460
461 ufdb_debug_external_scripts:
462 UFDB_DEBUG_EXTERNAL_SCRIPTS on_or_off { ufdbNewGV.debugExternalScripts = $2; }
463 ;
464
465 mail_server:
466 MAIL_SERVER QSTRING { ufdbFree( ufdbNewGV.emailServer ); ufdbNewGV.emailServer = $2; }
467 ;
468
469 my_hostname:
470 MY_HOSTNAME QSTRING { ufdbFree( ufdbNewGV.myHostname ); ufdbNewGV.myHostname = $2; }
471 ;
472
473 admin_email:
474 ADMIN_EMAIL QSTRING { ufdbFree( ufdbNewGV.adminEmail ); ufdbNewGV.adminEmail = $2; }
475 ;
476
477 sender_email:
478 SENDER_EMAIL QSTRING { ufdbFree( ufdbNewGV.senderEmail ); ufdbNewGV.senderEmail = $2; }
479 ;
480
481 external_status_command:
482 EXTERNAL_STATUS_COMMAND QSTRING { ufdbFree( ufdbNewGV.externalStatusCommand );
483 ufdbNewGV.externalStatusCommand = $2; }
484 ;
485
486 logdir:
487 LOGDIR qidentifier { setLogdir( $2 ); }
488 | LOGDIR WORD { setLogdir( $2 ); }
489 ;
490
491 pidfile:
492 PIDFILE qidentifier { setPidfile( $2 ); }
493 | PIDFILE WORD { setPidfile( $2 ); }
494 ;
495
496 port:
497 PORT NUMBER { ufdbNewGV.portNum = atoi( $2 ); ufdbFree( $2 );
498 if (ufdbNewGV.portNum <= 0)
499 {
500 ufdbLogError( "port number must be > 0, using default port %d",
501 UFDB_DAEMON_PORT );
502 ufdbNewGV.portNum = UFDB_DAEMON_PORT;
503 }
504 }
505 ;
506
507 interface:
508 INTERFACE qidentifier {
509 #if HAVE_UNIX_SOCKETS
510 ufdbLogError( "ufdbguardd is configured to use UNIX sockets. "
511 "\"interface\" is ignored." );
512 #else
513 if (strcmp( $2, "all" ) == 0)
514 strcpy( ufdbNewGV.interface, "all" );
515 else
516 ufdbLogFatalError( "interface must be \"all\" or IP address" );
517 #endif
518 ufdbFree( $2 );
519 }
520 | INTERFACE IPV4ADDR { strcpy( ufdbNewGV.interface, $2 ); ufdbFree( $2 ); }
521 ;
522
523 cpus:
524 CPUS NUMBER { ufdbSetCPU( $2 ); ufdbFree( $2 ); }
525 | CPUS NUMBERS { ufdbSetCPU( $2 ); ufdbFree( $2 ); }
526 ;
527
528 upload_stats:
529 UPLOAD_STATS on_or_off
530 { ufdbNewGV.uploadStats = $2; }
531 ;
532
533 redirect_https:
534 REDIRECT_HTTPS QSTRING
535 { strcpy( ufdbNewGV.redirectHttps, $2 ); ufdbFree( $2 ); }
536 ;
537
538 redirect_bumped_https:
539 REDIRECT_BUMPED_HTTPS QSTRING
540 { strcpy( ufdbNewGV.redirectBumpedHttps, $2 ); ufdbFree( $2 ); }
541 ;
542
543 redirect_loading_database:
544 REDIRECT_LOADING_DATABASE QSTRING
545 { strcpy( ufdbNewGV.loadingDatabaseRedirect, $2 ); ufdbFree( $2 ); }
546 ;
547
548 redirect_fatal_error:
549 REDIRECT_FATAL_ERROR QSTRING
550 { strcpy( ufdbNewGV.fatalErrorRedirect, $2 ); ufdbFree( $2 ); }
551 ;
552
553 log_uncategorised_urls:
554 LOG_UNCATEGORISED_URLS on_or_off
555 {
556 ufdbNewGV.logUncategorisedURLs = $2;
557 }
558 ;
559
560 analyse_uncategorised:
561 ANALYSE_UNCATEGORISED on_or_off
562 {
563 ufdbNewGV.analyseUncategorisedURLs = $2;
564 }
565 |
566 ANALYSE_UNCATEGORISED NUMBER
567 {
568 ufdbNewGV.analyseUncategorisedURLs = atoi( $2 );
569 ufdbFree( $2 );
570 }
571 ;
572
573 strip_domain_from_username:
574 STRIP_DOMAIN_FROM_USERNAME on_or_off
575 {
576 ufdbNewGV.stripDomainFromUsername = $2;
577 }
578 ;
579
580 safe_search:
581 SAFE_SEARCH on_or_off
582 { ufdbNewGV.safeSearch = $2; }
583 ;
584
585 max_logfile_size:
586 MAX_LOGFILE_SIZE NUMBER
587 {
588 ufdbNewGV.maxLogfileSize = strtoul( $2, NULL, 10 );
589 ufdbFree( $2 );
590 if (ufdbNewGV.maxLogfileSize < 2 * 1024 * 1024) // minimum is 2 MB
591 ufdbNewGV.maxLogfileSize = 2 * 1024 * 1024;
592 if (ufdbNewGV.maxLogfileSize > 2000000000) // maximum is 2 GB
593 ufdbNewGV.maxLogfileSize = 2000000000;
594 }
595 ;
596
597 httpd_option:
598 PORT EQUAL NUMBER { ufdbNewGV.httpdPort = atoi( $3 ); ufdbFree( $3 ); }
599 | INTERFACE EQUAL qidentifier { if (strcmp($3,"all")== 0)
600 strcpy( ufdbNewGV.httpdInterface, "all" );
601 else
602 ufdbLogFatalError( "http-server interface must be \"all\" or IP address" );
603 ufdbFree( $3 );
604 }
605 | INTERFACE EQUAL WORD { if (strcmp($3,"all")== 0)
606 strcpy( ufdbNewGV.httpdInterface, "all" );
607 else
608 ufdbLogFatalError( "http-server interface must be \"all\" or IP address" );
609 ufdbFree( $3 );
610 }
611 | INTERFACE EQUAL IPV4ADDR { strcpy( ufdbNewGV.httpdInterface, $3 ); ufdbFree( $3 ); }
612 | IMAGES EQUAL qidentifier { strcpy( ufdbNewGV.httpdImagesDirectory, $3 ); ufdbFree( $3 ); }
613 | IMAGES EQUAL WORD { strcpy( ufdbNewGV.httpdImagesDirectory, $3 ); ufdbFree( $3 ); }
614 ;
615
616 httpd_options:
617 httpd_option COMMA httpd_options
618 | httpd_option
619 ;
620
621 http_server_def:
622 HTTP_SERVER START_BRACKET httpd_options STOP_BRACKET
623 ;
624
625 category:
626 CATEGORY qidentifier { ufdbCategory( $2 ); }
627 | CATEGORY AGGRESSIVE { ufdbCategory( ufdbStrdup("aggressive") );
628 yyerror( (char *) "\"aggressive\" is a keyword and must be surrounded by quotes" ); }
629 | CATEGORY TOKEN_ALLOW { ufdbCategory( ufdbStrdup("allow") );
630 yyerror( (char *) "\"allow\" is a keyword and must be surrounded by quotes" ); }
631 | CATEGORY TOKEN_DENY { ufdbCategory( ufdbStrdup("deny") );
632 yyerror( (char *) "\"deny\" is a keyword and must be surrounded by quotes" ); }
633 | CATEGORY error { ufdbCategory( ufdbStrdup("syntax-error") );
634 yyerror( (char *) "erroneous category definition. Perhaps the category ID is a reserved word?" ); }
635 ;
636
637 category_block:
638 category START_BRACKET category_contents STOP_BRACKET
639 { ufdbCategoryEnd(); }
640 ;
641
642 category_contents: %empty
643 | category_contents category_content
644 ;
645
646 category_content:
647 DOMAINLIST qidentifier { ufdbCategoryDomainList( $2 ); }
648 | DOMAINLIST WORD { ufdbCategoryDomainList( $2 ); }
649 | DOMAINLIST CHAR_MINUS { ufdbCategoryDomainList( NULL ); }
650 | EXECDOMAINLIST qidentifier { ufdbCategoryExecDomainList( $2 ); }
651 | URLLIST qidentifier { ufdbCategoryUrlList( $2 ); }
652 | URLLIST WORD { ufdbCategoryUrlList( $2 ); }
653 | URLLIST CHAR_MINUS { ufdbCategoryUrlList( NULL ); }
654 | EXPRESSIONLIST qidentifier { ufdbCategoryExpressionList( $2, "n" ); }
655 | EXPRESSIONLIST WORD { ufdbCategoryExpressionList( $2, "n" ); }
656 | EXPRESSIONLIST CHAR_MINUS { ufdbCategoryExpressionList( NULL, NULL ); }
657 | EXPRESSIONLIST CHAR_I qidentifier { ufdbCategoryExpressionList( $3, "i" ); }
658 | EXPRESSIONLIST CHAR_I WORD { ufdbCategoryExpressionList( $3, "i" ); }
659 | EXPRESSIONLIST IGNORECASE qidentifier { ufdbCategoryExpressionList( $3, "i" ); }
660 | EXPRESSIONLIST IGNORECASE WORD { ufdbCategoryExpressionList( $3, "i" ); }
661 | CACERTS qidentifier { ufdbCategoryCACertsFile( $2 ); ufdbFree( $2 ); }
662 | CACERTS WORD { ufdbCategoryCACertsFile( $2 ); ufdbFree( $2 ); }
663 | CACERTSDIR qidentifier { ufdbCategoryCACertsDir( $2 ); ufdbFree( $2 ); }
664 | CACERTSDIR WORD { ufdbCategoryCACertsDir( $2 ); ufdbFree( $2 ); }
665 | REDIRECT qidentifier { ufdbCategoryRedirect( $2 ); }
666 | REDIRECT WORD { ufdbCategoryRedirect( $2 ); }
667 | REWRITE qidentifier { ufdbCategoryRewrite( $2 ); }
668 | REWRITE WORD { ufdbCategoryRewrite( $2 ); }
669 | WITHIN qidentifier { ufdbCategoryTime( $2, UFDB_ACL_WITHIN ); }
670 | OUTSIDE qidentifier { ufdbCategoryTime( $2, UFDB_ACL_OUTSIDE ); }
671 | OPTION BLOCK_BUMPED_CONNECT on_or_off { ufdbCategoryBlockConnect( $3 ); }
672 | OPTION SQUID_USES_ACTIVE_BUMPING on_or_off { ufdbCategoryActiveBumping( $3 ); }
673 | OPTION SAFE_SEARCH on_or_off { ufdbCategoryOption( $3, UFDB_OPT_SAFE_SEARCH ); }
674 | OPTION YOUTUBE_EDUFILTER on_or_off { ufdbCategoryOption( $3, UFDB_OPT_YOUTUBE_EDUFILTER ); }
675 | OPTION ENFORCE_HTTPS_WITH_HOSTNAME { ufdbCategoryOption( 1, UFDB_OPT_HTTPS_WITH_HOSTNAME ); }
676 | OPTION ENFORCE_HTTPS_WITH_HOSTNAME on_or_off { ufdbCategoryOption( $3, UFDB_OPT_HTTPS_WITH_HOSTNAME ); }
677 | OPTION ENFORCE_HTTPS_OFFICAL_CERTIFICATE { ufdbCategoryOption( 1, UFDB_OPT_HTTPS_OFFICAL_CERTIFICATE ); }
678 | OPTION ENFORCE_HTTPS_OFFICAL_CERTIFICATE on_or_off { ufdbCategoryOption( $3, UFDB_OPT_HTTPS_OFFICAL_CERTIFICATE ); }
679 | OPTION HTTPS_PROHIBIT_INSECURE_SSLV2 on_or_off { ufdbCategoryOption( $3, UFDB_OPT_PROHIBIT_INSECURE_SSLV2 ); }
680 | OPTION HTTPS_PROHIBIT_INSECURE_SSLV3 on_or_off { ufdbCategoryOption( $3, UFDB_OPT_PROHIBIT_INSECURE_SSLV3 ); }
681 | OPTION ALLOW_SKYPE_OVER_HTTPS on_or_off { ufdbCategoryOption( $3, UFDB_OPT_SKYPE_OVER_HTTPS ); }
682 | OPTION ALLOW_GTALK_OVER_HTTPS on_or_off { ufdbCategoryOption( $3, UFDB_OPT_GTALK_OVER_HTTPS ); }
683 | OPTION ALLOW_YAHOOMSG_OVER_HTTPS on_or_off { ufdbCategoryOption( $3, UFDB_OPT_YAHOOMSG_OVER_HTTPS ); }
684 | OPTION ALLOW_AIM_OVER_HTTPS on_or_off { ufdbCategoryOption( $3, UFDB_OPT_AIM_OVER_HTTPS ); }
685 | OPTION ALLOW_FBCHAT_OVER_HTTPS on_or_off { ufdbCategoryOption( $3, UFDB_OPT_FBCHAT_OVER_HTTPS ); }
686 | OPTION ALLOW_CITRIXONLINE_OVER_HTTPS on_or_off { ufdbCategoryOption( $3, UFDB_OPT_CITRIXONLINE_OVER_HTTPS ); }
687 | OPTION ALLOW_ANYDESK_OVER_HTTPS on_or_off { ufdbCategoryOption( $3, UFDB_OPT_ANYDESK_OVER_HTTPS ); }
688 | OPTION ALLOW_TEAMVIEWER_OVER_HTTPS on_or_off { ufdbCategoryOption( $3, UFDB_OPT_TEAMVIEWER_OVER_HTTPS ); }
689 | OPTION ALLOW_UNKNOWN_PROTOCOL_OVER_HTTPS on_or_off { ufdbCategoryOption( $3, UFDB_OPT_UNKNOWN_PROTOCOL_OVER_HTTPS ); }
690 | LOGFILE ANONYMOUS qidentifier { ufdbLogError( "line %d: unsupported logfile context for %s", lineno, $3 );
691 ufdbFree( $3 ); }
692 | LOGFILE ANONYMOUS WORD { ufdbLogError( "line %d: unsupported logfile context for %s", lineno, $3 );
693 ufdbFree( $3 ); }
694 | LOGFILE qidentifier { ufdbLogError( "line %d: unsupported logfile context for %s", lineno, $2 );
695 ufdbFree( $2 ); }
696 | LOGFILE WORD { ufdbLogError( "line %d: unsupported logfile context for %s", lineno, $2 );
697 ufdbFree( $2 ); }
698 ;
699
700 source:
701 SOURCE qidentifier { defSource( $2 ); }
702 ;
703
704 source_block:
705 source START_BRACKET source_contents STOP_BRACKET { defSourceEnd(); }
706 ;
707
708 source_contents:
709 %empty
710 | source_contents source_content
711 ;
712
713 source_content:
714 DOMAIN domain
715 | USER user
716 | UNIX USER user
717 | USERLIST qidentifier { ufdbSourceUserList( $2 ); }
718 | USERLIST WORD { ufdbSourceUserList( $2 ); }
719 | UNIX USERLIST qidentifier { ufdbSourceUserList( $3 ); }
720 | UNIX USERLIST WORD { ufdbSourceUserList( $3 ); }
721 | EXECUSERLIST qidentifier { ufdbSourceExecUserList( $2 ); }
722 | EXECIPLIST qidentifier { ufdbSourceExecIPList( $2 ); }
723 | GROUP qidentifier { ufdbSourceGroup( UFDB_GROUPTYPE_UNIX, $2 ); }
724 | GROUP WORD { ufdbSourceGroup( UFDB_GROUPTYPE_UNIX, $2 ); }
725 | UNIX GROUP qidentifier { ufdbSourceGroup( UFDB_GROUPTYPE_UNIX, $3 ); }
726 | UNIX GROUP WORD { ufdbSourceGroup( UFDB_GROUPTYPE_UNIX, $3 ); }
727 | USERQUOTA NUMBER NUMBER HOURLY { ufdbSourceUserQuota( $2, $3, "3600" );
728 ufdbFree( $2 ); ufdbFree( $3 ); }
729 | USERQUOTA NUMBER NUMBER DAILY { ufdbSourceUserQuota( $2, $3, "86400" );
730 ufdbFree( $2 ); ufdbFree( $3 ); }
731 | USERQUOTA NUMBER NUMBER WEEKLY { ufdbSourceUserQuota( $2, $3, "604800" );
732 ufdbFree( $2 ); ufdbFree( $3 ); }
733 | USERQUOTA NUMBER NUMBER NUMBER { ufdbSourceUserQuota( $2, $3, $4 );
734 ufdbFree( $2 ); ufdbFree( $3 ); ufdbFree( $4 ); }
735 | IPV4 ipv4s
736 | IPV4LIST qidentifier { defSourceIPV4List( $2 ); }
737 | IPV4LIST WORD { defSourceIPV4List( $2 ); }
738 | IPV6 ipv6s
739 | IPV6LIST qidentifier { defSourceIPV6List( $2 ); }
740 | IPV6LIST WORD { defSourceIPV6List( $2 ); }
741 | EVALUATE_AND { ufdbSourceEval( UFDB_EVAL_AND ); }
742 | EVALUATE_OR { ufdbSourceEval( UFDB_EVAL_OR ); }
743 | WITHIN qidentifier { defSourceTime( $2, UFDB_ACL_WITHIN ); }
744 | OUTSIDE qidentifier { defSourceTime( $2, UFDB_ACL_OUTSIDE ); }
745 | LOGFILE ANONYMOUS qidentifier { ufdbLogError( "line %d: unsupported logfile context for %s",
746 lineno, $3 );
747 ufdbFree( $3 ); }
748 | LOGFILE ANONYMOUS WORD { ufdbLogError( "line %d: unsupported logfile context for %s",
749 lineno, $3 );
750 ufdbFree( $3 ); }
751 | LOGFILE qidentifier { ufdbLogError( "line %d: unsupported logfile context for %s",
752 lineno, $2 );
753 ufdbFree( $2 ); }
754 | LOGFILE WORD { ufdbLogError( "line %d: unsupported logfile context for %s",
755 lineno, $2 );
756 ufdbFree( $2 ); }
757 | CONTINUE { ufdbNewGV.lastSource->cont_search = 1; }
758 ;
759
760
761 domain:
762 %empty
763 | domain qidentifier { defSourceDomain( $2 ); }
764 | domain WORD { defSourceDomain( $2 ); }
765 | domain COMMA
766 ;
767
768 user:
769 %empty
770 | user qidentifier { ufdbSourceUser( $2 ); }
771 | user WORD { ufdbSourceUser( $2 ); }
772 | user COMMA
773 ;
774
775 acl_block:
776 ACL START_BRACKET acl_contents STOP_BRACKET
777 ;
778
779 acl_contents: %empty
780 | acl_contents acl_content
781 ;
782
783 acl_header:
784 qidentifier START_BRACKET { ufdbAcl( $1, NULL, UFDB_ACL_NONE ); }
785 | qidentifier WITHIN qidentifier START_BRACKET { ufdbAcl( $1, $3, UFDB_ACL_WITHIN ); }
786 | qidentifier OUTSIDE qidentifier START_BRACKET { ufdbAcl( $1, $3, UFDB_ACL_OUTSIDE ); }
787 ;
788
789 acl_content:
790 acl_header access_contents STOP_BRACKET
791 | acl_header access_contents STOP_BRACKET ELSE
792 { ufdbAcl( NULL, NULL, UFDB_ACL_ELSE ); }
793 START_BRACKET access_contents STOP_BRACKET
794 ;
795
796 access_contents:
797 %empty
798 | access_contents access_content
799 ;
800
801 access_content:
802 PASS access_pass { if (ufdbNewGV.lastAcl != NULL &&
803 ufdbNewGV.lastAcl->pass == NULL)
804 {
805 ufdbLogMessage( "line %d: acl has an empty pass statement."
806 " Adding 'any'.", lineno );
807 ufdbAclSetValue( "pass", ufdbStrdup("any"), 1 );
808 }
809 }
810 | REWRITE qidentifier { ufdbAclSetValue( "rewrite", $2, 0 ); }
811 | REWRITE WORD { ufdbAclSetValue( "rewrite", $2, 0 ); }
812 | REDIRECT qidentifier { ufdbAclSetValue( "redirect", $2, 0 ); }
813 | REDIRECT WORD { ufdbAclSetValue( "redirect", $2, 0 ); }
814 | LOGFILE ANONYMOUS qidentifier { ufdbLogError( "line %d: unsupported logfile context for %s",
815 lineno, $3 );
816 ufdbFree( $3 ); }
817 | LOGFILE ANONYMOUS WORD { ufdbLogError( "line %d: unsupported logfile context for %s",
818 lineno, $3 );
819 ufdbFree( $3 ); }
820 | LOGFILE qidentifier { ufdbLogError( "line %d: unsupported logfile context for %s",
821 lineno, $2 );
822 ufdbFree( $2 ); }
823 | LOGFILE WORD { ufdbLogError( "line %d: unsupported logfile context for %s",
824 lineno, $2 );
825 ufdbFree( $2 ); }
826 ;
827
828 access_pass:
829 %empty
830 | access_pass AGGRESSIVE { yyerror( (char *) "\"aggressive\" is a keyword and must be surrounded by quotes" ); }
831 | access_pass qidentifier { ufdbAclSetValue( "pass", $2, 1 ); }
832 | access_pass CHAR_EXCLAMATION AGGRESSIVE { yyerror( (char *) "\"aggressive\" is a keyword and must be surrounded by quotes" ); }
833 | access_pass CHAR_EXCLAMATION qidentifier { ufdbAclSetValue( "pass", $3, 0 ); }
834 | access_pass COMMA
835 ;
836
837 ipv4s:
838 %empty
839 | ipv4s ipv4
840 | ipv4s COMMA ipv4
841 ;
842
843 ipv4:
844 IPV4ADDR { sgIpv4( $1, SG_IPTYPE_HOST, ufdbNewGV.configFile, lineno );
845 ufdbFree( $1 ); }
846 | IPV4RANGE { sgIpv4( $1, SG_IPTYPE_RANGE, ufdbNewGV.configFile, lineno );
847 ufdbFree( $1 ); }
848 | IPV4CLASS { sgIpv4( $1, SG_IPTYPE_CLASS, ufdbNewGV.configFile, lineno );
849 ufdbFree( $1 ); }
850 | IPV4NET { sgIpv4( $1, SG_IPTYPE_CIDR, ufdbNewGV.configFile, lineno );
851 ufdbFree( $1 ); }
852 ;
853
854 ipv6s:
855 %empty
856 | ipv6s ipv6
857 | ipv6s COMMA ipv6
858 ;
859
860 ipv6:
861 IPV6ADDR { sgIpv6( $1, SG_IPV6TYPE_HOST, ufdbNewGV.configFile, lineno );
862 ufdbFree( $1 ); }
863 | IPV6NET { sgIpv6( $1, SG_IPV6TYPE_CIDR, ufdbNewGV.configFile, lineno );
864 ufdbFree( $1 ); }
865 ;
866
867 rew:
868 REWRITE qidentifier { sgRewrite( $2 ); }
869 | REWRITE WORD { sgRewrite( $2 ); }
870 ;
871
872 rew_block:
873 rew START_BRACKET rew_contents STOP_BRACKET
874 ;
875
876 rew_contents:
877 %empty
878 | rew_contents rew_content
879 ;
880
881
882 rew_content:
883 SUBST { sgRewriteSubstitute( $1 ); ufdbFree( $1 ); }
884 | WITHIN qidentifier { sgRewriteTime( $2, UFDB_ACL_WITHIN ); }
885 | OUTSIDE qidentifier { sgRewriteTime( $2, UFDB_ACL_OUTSIDE ); }
886 | LOGFILE ANONYMOUS qidentifier { ufdbLogError( "line %d: unsupported logfile context for %s",
887 lineno, $3 );
888 ufdbFree( $3 ); }
889 | LOGFILE ANONYMOUS WORD { ufdbLogError( "line %d: unsupported logfile context for %s",
890 lineno, $3 );
891 ufdbFree( $3 ); }
892 | LOGFILE qidentifier { ufdbLogError( "line %d: unsupported logfile context for %s",
893 lineno, $2 );
894 ufdbFree( $2 ); }
895 | LOGFILE WORD { ufdbLogError( "line %d: unsupported logfile context for %s",
896 lineno, $2 );
897 ufdbFree( $2 ); }
898 ;
899
900
901 time:
902 TIME qidentifier { sgTime( $2 ); }
903 ;
904
905 time_block:
906 time START_BRACKET time_contents STOP_BRACKET
907 ;
908
909 time_contents:
910 %empty
911 | time_contents time_content
912 ;
913
914
915 time_content:
916 WEEKLY { sgTimeElementInit(); } WEEKDAY { sgTimeElementAdd($3,T_WEEKDAY); } ttime
917 | WEEKLY { sgTimeElementInit(); } qidentifier { sgTimeElementAdd($3,T_WEEKLY); } ttime
918 | WEEKLY { sgTimeElementInit(); } WORD { sgTimeElementAdd($3,T_WEEKLY); } ttime
919 | DATE { sgTimeElementInit(); } date { sgTimeElementEnd(); }
920 | error { ufdbLogFatalError( "invalid time specification at line %d", lineno ); }
921 ;
922
923 ttime:
924 ttime { sgTimeElementClone(); } tval CHAR_MINUS tval
925 | tval CHAR_MINUS tval
926 ;
927
928 date:
929 dval ttime
930 | dval
931 | dval CHAR_MINUS dval ttime
932 | dval CHAR_MINUS dval
933 | dvalcron ttime
934 | dvalcron
935 ;
936
937 dval: DVAL { sgTimeElementAdd( $1, T_DVAL ); }
938 ;
939
940 tval: TVAL { sgTimeElementAdd( $1, T_TVAL ); }
941 ;
942
943 dvalcron: DVALCRON { sgTimeElementAdd( $1, T_DVALCRON ); }
944 ;
945
946 an_error:
947 error { yyerror( (char *) "syntax error" );
948 if (ufdbNewGV.serialno > 1 && ufdbNewGV.debug)
949 logConfig();
950 }
951 ;
952
953 statements: %empty
954 | statements statement
955 ;
956
957 statement:
958 category
959 | source_block
960 | category_block
961 | http_server_def
962 | admin_spec
963 | https_cache_size
964 | check_proxy_tunnels
965 | log_pass
966 | log_block
967 | log_all
968 | logall_httpd
969 | madvise_hugepages
970 | fast_refresh
971 | debug_filter
972 | debug_coredump
973 | enforce_https_with_hostname
974 | enforce_https_offical_certificate
975 | https_prohibit_insecure_sslv2
976 | https_prohibit_insecure_sslv3
977 | dbhome
978 | logdir
979 | pidfile
980 | mail_server
981 | my_hostname
982 | admin_email
983 | sender_email
984 | external_status_command
985 | url_lookup_delay_db_reload
986 | url_lookup_result_db_reload
987 | url_lookup_result_fatal_error
988 | squid_version
989 | num_worker_threads
990 | upload_crash_reports
991 | lookup_reverse_ip
992 | use_ipv6_on_wan
993 | parse_url_parameters
994 | squid_uses_active_bumping
995 | ufdb_log_url_details
996 | ufdb_show_url_details
997 | ufdb_debug_skype_probes
998 | ufdb_debug_gtalk_probes
999 | ufdb_debug_yahoomsg_probes
1000 | ufdb_debug_aim_probes
1001 | ufdb_debug_fbchat_probes
1002 | ufdb_debug_citrixonline_probes
1003 | ufdb_expression_optimisation
1004 | ufdb_expression_debug
1005 | refreshuserlist
1006 | refreshiplist
1007 | refreshdomainlist
1008 | ufdb_debug_external_scripts
1009 | interface
1010 | port
1011 | cpus
1012 | upload_stats
1013 | redirect_https
1014 | redirect_bumped_https
1015 | redirect_loading_database
1016 | redirect_fatal_error
1017 | analyse_uncategorised
1018 | log_uncategorised_urls
1019 | safe_search
1020 | strip_domain_from_username
1021 | youtube_edufilter
1022 | allow_google_https_using_ip
1023 | youtube_edufilter_id
1024 | max_logfile_size
1025 | acl_block
1026 | rew_block
1027 | time_block
1028 | NL
1029 | an_error
1030 ;
1031
1032 %%
1033
1034 int ufdbReadConfig(
1035 const char * file )
1036 {
1037 struct Source * source;
1038 struct Category * cat;
1039 struct Acl * acl;
1040
1041 lineno = 1;
1042 ufdbResetCPUs();
1043
1044 ufdbNewGV.configFile = file;
1045
1046 yyin = fopen( ufdbNewGV.configFile, "r" );
1047 if (yyin == NULL)
1048 {
1049 syslog( LOG_ALERT, "%s: cannot open configuration file %s", ufdbNewGV.progname, ufdbNewGV.configFile );
1050 ufdbLogFatalError( "cannot open configuration file %s", ufdbNewGV.configFile );
1051 return 0;
1052 }
1053
1054 ufdbLogMessage( "configuration file: %s", ufdbNewGV.configFile );
1055
1056 /* keep the old HTTPS redirection URL. It is most likely that we need it during the database reload */
1057 /* dot not reset ufdbNewGV.RedirectHttps and ufdbNewGV.RedirectBumpedHttps. */
1058
1059 ufdbNewGV.debug = 0;
1060 ufdbNewGV.debugCoreDump = 0;
1061 strcpy( ufdbNewGV.interface, "all" );
1062 ufdbNewGV.portNum = UFDB_DAEMON_PORT;
1063 ufdbNewGV.nWorkers = UFDB_MIN_THREADS;
1064 ufdbNewGV.debugHttpd = 0;
1065 ufdbNewGV.logPass = 0;
1066 ufdbNewGV.logBlock = 0;
1067 ufdbNewGV.logAllRequests = 0;
1068 ufdbNewGV.YoutubeEdufilter = 0;
1069 ufdbFree( ufdbNewGV.YoutubeEdufilterID );
1070 ufdbNewGV.YoutubeEdufilterID = NULL;
1071 ufdbNewGV.allowGoogleHTTPSusingIP = 0;
1072
1073 /* When a database is reloaded, these variables may NOT be reset since they are used during the reload !! */
1074 ufdbNewGV.URLlookupDelayDBreload = 0;
1075 ufdbNewGV.URLlookupResultDBreload = UFDB_ALLOW;
1076 ufdbNewGV.URLlookupResultFatalError = UFDB_ALLOW;
1077 strcpy( ufdbNewGV.loadingDatabaseRedirect, "http://cgibin.urlfilterdb.com/cgi-bin/URLblocked.cgi?"
1078 "category=loading-database" );
1079 ufdbNewGV.SquidVersion = ufdbStrdup( UFDB_DEFAULT_SQUID_VERSION );
1080
1081 ufdbNewGV.showURLdetails = 0;
1082 ufdbNewGV.logURLdetails = 0;
1083 ufdbNewGV.uploadCrashReports = 1;
1084 ufdbNewGV.lookupReverseIP = 0;
1085 ufdbNewGV.useAlsoIPv6onWan = 1;
1086 ufdbNewGV.debugSkype = 0;
1087 ufdbNewGV.debugGtalk = 0;
1088 ufdbNewGV.debugYahooMsg = 0;
1089 ufdbNewGV.debugAim = 0;
1090 ufdbNewGV.debugFBchat = 0;
1091 ufdbNewGV.debugCitrixOnline = 0;
1092 ufdbNewGV.debugRegexp = 0;
1093 ufdbNewGV.debugExternalScripts = 0;
1094 ufdbNewGV.expressionOptimisation = 1;
1095 ufdbNewGV.refreshUserlistInterval = UFDB_DEFAULT_REFRESH_USERLIST;
1096 ufdbNewGV.refreshIPlistInterval = UFDB_DEFAULT_REFRESH_IPLIST;
1097 ufdbNewGV.refreshDomainlistInterval = UFDB_DEFAULT_REFRESH_DOMAINLIST;
1098 ufdbNewGV.analyseUncategorisedURLs = 1;
1099 ufdbNewGV.logUncategorisedURLs = 0;
1100 ufdbNewGV.uploadStats = 1;
1101 ufdbNewGV.safeSearch = 1;
1102 ufdbNewGV.skipSafeCategory = 0;
1103 ufdbNewGV.stripDomainFromUsername = 0;
1104 ufdbNewGV.tunnelCheckMethod = UFDB_API_HTTPS_CHECK_OFF;
1105 ufdbNewGV.SquidUsesActiveBumping = 0;
1106 ufdbNewGV.httpsWithHostname = 0;
1107 ufdbNewGV.httpsOfficialCertificate = 0;
1108 ufdbNewGV.unknownProtocolOverHttps = 1;
1109 ufdbNewGV.httpsNoSSLv2 = 1;
1110 ufdbNewGV.httpsNoSSLv3 = 1;
1111 ufdbNewGV.httpdPort = 0;
1112 ufdbNewGV.dateOfCheckedDB[0] = '\0';
1113 strcpy( ufdbNewGV.httpdInterface, "all" );
1114 strcpy( ufdbNewGV.httpdImagesDirectory, "." );
1115
1116 ufdbNewGV.databaseStatus = UFDB_API_STATUS_DATABASE_OK;
1117
1118 (void) yyparse(); /* parse the configuration file ********************/
1119 fclose( yyin );
1120
1121 ufdbNewGV.databaseLoadTime = time( NULL );
1122
1123 /*
1124 * For analysis of uncategorised URLs we also load a "checked" category
1125 * that contains URLs that are reviewed and checked not to be part of
1126 * any other category.
1127 */
1128 char * dbhome;
1129 char dbfname[1024];
1130
1131 dbhome = ufdbNewGV.databaseDirectory;
1132
1133 /* TODO: check if "checked" was not already loaded... */
1134 if (ufdbNewGV.analyseUncategorisedURLs > 0)
1135 {
1136 int status;
1137 sprintf( dbfname, "%s/checked/domains.ufdb", dbhome );
1138 status = UFDBloadDatabase( &ufdbNewGV, &ufdbNewGV.checkedDB, dbfname );
1139 if (status != UFDB_API_OK && status != UFDB_API_STATUS_DATABASE_OLD)
1140 {
1141 ufdbNewGV.checkedDB.mem = NULL;
1142 ufdbNewGV.checkedDB.index = NULL;
1143 ufdbNewGV.checkedDB.table.nNextLevels = 0;
1144 if (ufdbGV.debug)
1145 ufdbLogMessage( "The URL database appears not be from URLfilterDB. No problem." );
1146 }
1147 else
1148 {
1149 if (ufdbGV.debug)
1150 ufdbLogMessage( "table \"checked\" is loaded: %s %8.8s",
1151 ufdbNewGV.checkedDB.date, ufdbNewGV.checkedDB.flags );
1152 sprintf( dbfname, "%s/checked/expressions", dbhome );
1153 (void) UFDBloadExpressions( &ufdbNewGV.checkedExpressions, dbfname );
1154 ufdbLogMessage( "The implicitly allowed URL category 'checked' is loaded." );
1155 }
1156 }
1157
1158 if (ufdbNewGV.defaultAcl == NULL)
1159 ufdbLogFatalError( "\"default\" ACL is not defined" );
1160 else if (ufdbNewGV.defaultAcl->pass == NULL)
1161 ufdbLogError( "\"default\" ACL is empty: by default all URLs are blocked." );
1162
1163 /* A configuration file may have a source definition which is not used in the ACL list.
1164 * This raises the question "what to do with this ?".
1165 * If we do nothing, the source is matched but has no ACL definition and is silently skipped.
1166 * Most likely the administrator overlooked something so a warning is useful.
1167 */
1168 source = ufdbNewGV.sourceList;
1169 if (source == NULL && ufdbNewGV.defaultAcl == NULL)
1170 ufdbLogFatalError( "There are no sources and there is no default ACL" );
1171
1172 for ( ; source != NULL; source = source->next)
1173 {
1174 int found;
1175
1176 found = 0;
1177 for (acl = ufdbNewGV.aclList; acl != NULL; acl = acl->next)
1178 {
1179 if (strcmp( acl->name, source->name ) == 0)
1180 {
1181 found = 1;
1182 break;
1183 }
1184 }
1185 if (!found)
1186 {
1187 ufdbLogError( "source \"%s\" has no ACL. *****\n"
1188 "This most likely may lead to unexpected results when the source is matched. *****\n"
1189 "It is strongly suggested to remove the source definition OR add the source to the acl. *****",
1190 source->name );
1191 source->active = 0;
1192 }
1193 else if (acl->pass == NULL)
1194 {
1195 ufdbLogMessage( "source \"%s\" has an empty \"pass\" in its ACL *****", source->name );
1196 }
1197 }
1198
1199 for (cat = ufdbNewGV.catList; cat != NULL; cat = cat->next)
1200 {
1201 if (cat->options == 0 && cat->domainlist == NULL && cat->execdomainlist == NULL &&
1202 cat->expressionlist == NULL && cat->rewrite == NULL && cat->name != NULL)
1203 {
1204 ufdbLogError( "category \"%s\" has no content definition *****", cat->name );
1205 }
1206 }
1207
1208 if (ufdbNewGV.adminEmail != NULL && ufdbNewGV.emailServer == NULL)
1209 {
1210 ufdbLogError( "No email server is defined; cannot send email to \"%s\" *****", ufdbNewGV.adminEmail );
1211 }
1212 if (ufdbNewGV.adminEmail != NULL && ufdbNewGV.emailServer != NULL && ufdbNewGV.senderEmail == NULL)
1213 {
1214 ufdbLogMessage( "WARNING: No sender email address is defined; using \"%s\" as sender",
1215 ufdbNewGV.adminEmail );
1216 }
1217
1218 if (strncmp( ufdbNewGV.SquidVersion, "5.", 2 ) != 0 &&
1219 strncmp( ufdbNewGV.SquidVersion, "4.", 2 ) != 0 &&
1220 strncmp( ufdbNewGV.SquidVersion, "3.5", 3 ) != 0 &&
1221 strncmp( ufdbNewGV.SquidVersion, "3.4", 3 ) != 0 &&
1222 strncmp( ufdbNewGV.SquidVersion, "3.3", 3 ) != 0 &&
1223 strncmp( ufdbNewGV.SquidVersion, "3.2", 3 ) != 0 &&
1224 strncmp( ufdbNewGV.SquidVersion, "3.1", 3 ) != 0 &&
1225 strncmp( ufdbNewGV.SquidVersion, "3.0", 3 ) != 0 &&
1226 strncmp( ufdbNewGV.SquidVersion, "2.7", 3 ) != 0 &&
1227 strncmp( ufdbNewGV.SquidVersion, "2.6", 3 ) != 0)
1228 {
1229 ufdbLogFatalError( "Unsupported Squid version \"%s\" *****\n"
1230 "The supported values for squid-version are: "
1231 "5.x, 4.x, 3.5, 3.4, 3.3, 3.2, 3.1, 3.0, 2.7, 2.6 *****\n"
1232 "If the version of Squid is higher, it is recommended to upgrade ufdbGuard. *****\n"
1233 "Alternatively set squid-version to the highest supported version",
1234 ufdbNewGV.SquidVersion );
1235 }
1236 if (strncmp( ufdbNewGV.SquidVersion, "5.", 2 ) == 0 ||
1237 strncmp( ufdbNewGV.SquidVersion, "4.", 2 ) == 0 ||
1238 strncmp( ufdbNewGV.SquidVersion, "3.5", 3 ) == 0 ||
1239 strncmp( ufdbNewGV.SquidVersion, "3.4", 3 ) == 0)
1240 ufdbNewGV.SquidHelperProtocol = UFDB_SQUID_HELPER_PROTOCOL3;
1241 else if (strncmp( ufdbNewGV.SquidVersion, "2.6", 3 ) == 0 ||
1242 strncmp( ufdbNewGV.SquidVersion, "2.7", 3 ) == 0)
1243 ufdbNewGV.SquidHelperProtocol = UFDB_SQUID_HELPER_PROTOCOL1;
1244 else
1245 ufdbNewGV.SquidHelperProtocol = UFDB_SQUID_HELPER_PROTOCOL2; /* 3.0 - 3.3 */
1246
1247 BuildImplicitPassLists( &ufdbNewGV );
1248
1249 return 1;
1250 }
1251
1252
setDBhome(char * dbhome)1253 static void setDBhome( char * dbhome )
1254 {
1255 struct stat dirbuf;
1256
1257 if (strlen(dbhome) > sizeof(ufdbNewGV.databaseDirectory)-1)
1258 {
1259 ufdbLogFatalError( "maximum length for dbhome is %d", (int) sizeof(ufdbNewGV.databaseDirectory)-1 );
1260 ufdbFree( dbhome );
1261 return;
1262 }
1263 strcpy( ufdbNewGV.databaseDirectory, dbhome );
1264
1265 if (stat( dbhome, &dirbuf ) != 0)
1266 {
1267 ufdbLogFatalError( "dbhome %s: directory does not exist or access rights are insufficient", dbhome );
1268 }
1269 else
1270 {
1271 if (!S_ISDIR(dirbuf.st_mode))
1272 ufdbLogFatalError( "dbhome: %s is not a directory", dbhome );
1273 }
1274
1275 ufdbFree( dbhome );
1276 }
1277
1278
setAdministrator(char * value)1279 static void setAdministrator( char * value )
1280 {
1281 char * p;
1282
1283 if (strlen(value) > sizeof(ufdbNewGV.administrator)-1)
1284 {
1285 ufdbLogError( "maximum length for administrator is %d", (int) sizeof(ufdbNewGV.administrator)-1 );
1286 return;
1287 }
1288
1289 while ((p = (char *) strchr( value, '?' )) != NULL)
1290 *p = '_';
1291 while ((p = (char *) strchr( value, '&' )) != NULL)
1292 *p = '_';
1293
1294 strcpy( ufdbNewGV.administrator, value );
1295 ufdbFree( value );
1296 }
1297
1298
setLogdir(char * value)1299 static void setLogdir( char * value )
1300 {
1301 if (ufdbNewGV.logDir != NULL)
1302 ufdbFree( ufdbNewGV.logDir );
1303 ufdbNewGV.logDir = value;
1304
1305 ufdbSetGlobalErrorLogFile( ufdbNewGV.logDir, NULL, 0 );
1306 }
1307
1308
setPidfile(char * value)1309 static void setPidfile( char * value )
1310 {
1311 if (ufdbNewGV.pidFilename != NULL)
1312 ufdbFree( ufdbNewGV.pidFilename );
1313 ufdbNewGV.pidFilename = value;
1314 }
1315
1316
setRefreshUserlist(int nmin)1317 static void setRefreshUserlist( int nmin )
1318 {
1319 if (nmin < 5 || nmin > 24*60)
1320 {
1321 ufdbLogError( "refreshuserlist must have a value between 5 and %d, resetting to %d.",
1322 24*60, UFDB_DEFAULT_REFRESH_USERLIST );
1323 nmin = UFDB_DEFAULT_REFRESH_USERLIST;
1324 }
1325 ufdbNewGV.refreshUserlistInterval = nmin;
1326 }
1327
1328
setRefreshIPlist(int nmin)1329 static void setRefreshIPlist( int nmin )
1330 {
1331 if (nmin < 5 || nmin > 24*60)
1332 {
1333 ufdbLogError( "refreshiplist must have a value between 5 and %d, resetting to %d.",
1334 24*60, UFDB_DEFAULT_REFRESH_IPLIST );
1335 nmin = UFDB_DEFAULT_REFRESH_IPLIST;
1336 }
1337 ufdbNewGV.refreshIPlistInterval = nmin;
1338 }
1339
1340
setRefreshDomainlist(int nmin)1341 static void setRefreshDomainlist( int nmin )
1342 {
1343 if (nmin < 5 || nmin > 24*60)
1344 {
1345 ufdbLogError( "refreshdomainlist must have a value between 5 and %d, resetting to %d.",
1346 24*60, UFDB_DEFAULT_REFRESH_DOMAINLIST );
1347 nmin = UFDB_DEFAULT_REFRESH_DOMAINLIST;
1348 }
1349 ufdbNewGV.refreshDomainlistInterval = nmin;
1350 }
1351
1352
1353 /*
1354 * Source functions
1355 */
1356
defSource(char * source)1357 static void defSource(
1358 char * source )
1359 {
1360 struct Source * sp;
1361
1362 if (ufdbGV.debug)
1363 ufdbLogMessage( "defSource: defining source \"%s\"", source );
1364
1365 if ((struct Source *) defSourceFindName(ufdbNewGV.sourceList,source) != NULL)
1366 {
1367 ufdbLogFatalError( "line %d: source %s is already defined in configuration file %s",
1368 lineno, source, ufdbNewGV.configFile );
1369 ufdbFree( source );
1370 return;
1371 }
1372
1373 sp = (struct Source *) ufdbMallocAligned( UFDB_CACHELINE_SIZE, sizeof(struct Source) );
1374 sp->name = source;
1375 sp->active = 1;
1376 sp->evaluationMethod = UFDB_EVAL_OR;
1377 sp->ipv4hosts = NULL;
1378 sp->ipv4 = NULL;
1379 sp->ipv6hosts = NULL;
1380 sp->ipv6 = NULL;
1381 sp->domainDb = NULL;
1382 sp->userDb = NULL;
1383 sp->time = NULL;
1384 sp->within = UFDB_ACL_NONE;
1385 sp->cont_search = 0;
1386 sp->sarg0 = NULL;
1387 sp->execiplistCommand = NULL;
1388 sp->next = NULL;
1389 sp->nblocks = 0;
1390 sp->nmatches = 0;
1391
1392 if (ufdbNewGV.sourceList == NULL)
1393 {
1394 if (ufdbGV.debug)
1395 ufdbLogMessage( "defSource: SourceList is set to point to \"%s\"", source );
1396 ufdbNewGV.sourceList = sp;
1397 ufdbNewGV.lastSource = sp;
1398 }
1399 else
1400 {
1401 ufdbNewGV.lastSource->next = sp;
1402 ufdbNewGV.lastSource = sp;
1403 }
1404 }
1405
1406
defSourceEnd(void)1407 static void defSourceEnd( void )
1408 {
1409 struct Source * s;
1410
1411 s = ufdbNewGV.lastSource;
1412 if (s->ipv4 == NULL && s->ipv4hosts == NULL &&
1413 s->ipv6 == NULL && s->ipv6hosts == NULL &&
1414 s->domainDb == NULL && s->userDb == NULL)
1415 {
1416 if (s->execiplistCommand == NULL)
1417 {
1418 ufdbLogError( "source \"%s\" missing active content, set inactive *****", s->name );
1419 s->time = NULL;
1420 s->active = 0;
1421 }
1422 else
1423 ufdbLogError( "source \"%s\" has an execiplist command but the list is empty and set inactive *****",
1424 s->name );
1425 }
1426 }
1427
1428
ufdbSourceUser(char * user)1429 static void ufdbSourceUser(
1430 char * user )
1431 {
1432 char * lc;
1433 struct Source * sp;
1434
1435 sp = ufdbNewGV.lastSource;
1436 if (sp->userDb != NULL && sp->userDb->type != SGDBTYPE_USERLIST)
1437 {
1438 ufdbLogFatalError( "user \"%s\" in source \"%s\" on line %d: "
1439 "found mix of exec and non-exec userlists",
1440 user, sp->name, lineno );
1441 return;
1442 }
1443 if (sp->userDb == NULL)
1444 {
1445 sp->userDb = (struct sgDb *) ufdbMalloc( sizeof(struct sgDb) );
1446 sp->userDb->dbhome = NULL;
1447 sp->userDb->dbcp = (void *) UFDBmemDBinit();
1448 sp->userDb->type = SGDBTYPE_USERLIST;
1449 sp->userDb->entries = 0;
1450 }
1451
1452 for (lc = user; *lc != '\0'; lc++) // convert username to lowercase
1453 {
1454 if (*lc <= 'Z' && *lc >= 'A')
1455 *lc += 'a' - 'A';
1456 }
1457
1458 if (ufdbGV.debug > 1)
1459 ufdbLogMessage( "ufdbSourceUser: adding user \"%s\"", user );
1460
1461 sp->userDb->entries++;
1462 UFDBmemDBinsert( (struct UFDBmemDB *) sp->userDb->dbcp, user, NULL );
1463 ufdbFree( user );
1464 }
1465
1466
ufdbSourceUnixGroup(char * groupName)1467 static void ufdbSourceUnixGroup(
1468 char * groupName )
1469 {
1470 struct Source * sp;
1471 struct group * grp;
1472 int n;
1473 char * user;
1474
1475 sp = ufdbNewGV.lastSource;
1476 if (sp->userDb != NULL && sp->userDb->type != SGDBTYPE_USERLIST)
1477 {
1478 ufdbLogFatalError( "unix group \"%s\" in source \"%s\" on line %d: "
1479 "found mix of exec and non-exec userlists",
1480 groupName, sp->name, lineno );
1481 return;
1482 }
1483 if (sp->userDb == NULL)
1484 {
1485 sp->userDb = (struct sgDb *) ufdbMalloc( sizeof(struct sgDb) );
1486 sp->userDb->dbhome = NULL;
1487 sp->userDb->dbcp = (void *) UFDBmemDBinit();
1488 sp->userDb->type = SGDBTYPE_USERLIST;
1489 sp->userDb->entries = 0;
1490 }
1491
1492 n = 0;
1493 setgrent();
1494 errno = 0;
1495 grp = getgrnam( groupName );
1496 if (grp != NULL)
1497 {
1498 if (ufdbGV.debug > 1)
1499 ufdbLogMessage( "found group \"%s\"", grp->gr_name );
1500
1501 while ((user = grp->gr_mem[n]) != NULL)
1502 {
1503 char * lc;
1504
1505 if (ufdbGV.debug > 1)
1506 ufdbLogMessage( "group \"%s\" has user \"%s\"", grp->gr_name, user );
1507 for (lc = user; *lc != '\0'; lc++) // convert username to lowercase
1508 {
1509 if (*lc <= 'Z' && *lc >= 'A')
1510 *lc += 'a' - 'A';
1511 }
1512 UFDBmemDBinsert( (struct UFDBmemDB *) sp->userDb->dbcp, user, NULL );
1513 sp->userDb->entries++;
1514 n++;
1515 }
1516 ufdbLogMessage( "source \"%s\": unix group \"%s\" has %d members", sp->name, groupName, n );
1517 if (n == 0)
1518 ufdbLogMessage( "WARNING: source \"%s\": \"%s\" is an empty group +++++", sp->name, groupName );
1519 }
1520 else
1521 {
1522 ufdbLogFatalError( "source \"%s\": \"%s\" is not a unix group", sp->name, groupName );
1523 if (errno)
1524 ufdbLogError( "ufdbSourceUnixGroup: getgrnam returned error %d: %s", errno, strerror(errno) );
1525 }
1526 endgrent();
1527 }
1528
1529
ufdbSourceGroup(int groupType,char * groupName)1530 static void ufdbSourceGroup(
1531 int groupType,
1532 char * groupName )
1533 {
1534 switch (groupType)
1535 {
1536 case UFDB_GROUPTYPE_UNIX:
1537 ufdbSourceUnixGroup( groupName );
1538 break;
1539 default:
1540 ufdbLogFatalError( "ufdbSourceGroup: unknown group type %d", groupType );
1541 }
1542
1543 ufdbFree( groupName );
1544 }
1545
1546
UFDBretrieveExecDomainlist(struct Category * cat)1547 struct sgDb * UFDBretrieveExecDomainlist( struct Category * cat ) // uses ufdbGV
1548 {
1549 char * t;
1550 FILE * fp;
1551 struct sgDb * newdb;
1552 int exitcode;
1553 struct stat Stat0;
1554 struct stat Stat1;
1555 char line[1024];
1556 char basefilename[1024];
1557 char fullfilename[1024];
1558 char command[3000];
1559
1560 if (cat == NULL)
1561 {
1562 ufdbLogFatalError( "UFDBretrieveExecDomainlist: category is NULL" );
1563 return NULL;
1564 }
1565
1566 if (cat->domainlist == NULL)
1567 {
1568 ufdbLogError( "will not execute command for category %s since domainlist is undefined", cat->name );
1569 return NULL;
1570 }
1571
1572 if (cat->execdomainlist == NULL)
1573 {
1574 ufdbLogError( "can't execute command for category %s since execdomainlist is undefined", cat->name );
1575 return NULL;
1576 }
1577
1578 if (cat->domainlist[0] == '/')
1579 {
1580 strcpy( basefilename, cat->domainlist );
1581 }
1582 else
1583 {
1584 char * dbhome;
1585 dbhome = ufdbGV.databaseDirectory;
1586 sprintf( basefilename, "%s/%s", dbhome, cat->domainlist );
1587 }
1588 strcpy( fullfilename, basefilename );
1589 strcat( fullfilename, UFDBfileSuffix );
1590
1591 if (stat( fullfilename, &Stat0 ) != 0)
1592 {
1593 Stat0.st_mtime = 0;
1594 ufdbLogMessage( "category %s: pre-execdomainlist: domainlist does not exist (%s)",
1595 cat->name, fullfilename );
1596 }
1597
1598 /* The script that we will call needs the directory where the files reside,
1599 * so the popen-command contains a "cd" just before executing the script.
1600 * (note that we are multithreaded and cannot use chdir() here)
1601 */
1602 strcpy( command, "cd " );
1603 strcat( command, basefilename );
1604 t = strrchr( command, '/' );
1605 if (t != NULL)
1606 *t = '\0';
1607 strcat( command, " ; " );
1608 strcat( command, cat->execdomainlist );
1609
1610 errno = 0;
1611 if ((fp = popen(command,"r")) == NULL)
1612 {
1613 ufdbLogFatalError( "category %s: can't execute command of execdomainlist \"%s\": popen failed: %s *****",
1614 cat->name, cat->execdomainlist, strerror(errno) );
1615 return NULL;
1616 }
1617
1618 while (UFDBfgetsNoNL(line,sizeof(line)-1,fp) != NULL)
1619 {
1620 ufdbLogMessage( "execdomainlist for %s produced: %s", cat->name, line );
1621 }
1622 errno = 0;
1623 exitcode = pclose( fp );
1624
1625 if (exitcode == -1 && errno == ECHILD)
1626 exitcode = 0;
1627 /* most likely the child handler thread already did a wait() */
1628
1629 if (exitcode == 0)
1630 {
1631 if (ufdbGV.debug || ufdbGV.debugExternalScripts)
1632 ufdbLogMessage( " execdomainlist for %s: exit 0 (OK)", cat->name );
1633 }
1634 else if (exitcode == -1)
1635 {
1636 ufdbLogError( "execdomainlist for %s: pclose error: %d (%s)", cat->name, errno, strerror(errno) );
1637 return NULL;
1638 }
1639 else if (exitcode > 0)
1640 {
1641 ufdbLogError( "execdomainlist for %s: command (%s) terminated with an error exit code %d",
1642 cat->name, cat->execdomainlist, exitcode );
1643 return NULL;
1644 }
1645
1646 /* The command defined by 'execdomainlist' has been executed and the exit code was 0 (OK), so
1647 * now it is verified if the file timestamp of domains.ufdb is newer.
1648 */
1649
1650 if (stat( fullfilename, &Stat1 ) != 0)
1651 {
1652 ufdbLogError( "execdomainlist for %s: command failed to produce a .ufdb file (%s)",
1653 cat->name, fullfilename );
1654 return NULL;
1655 }
1656
1657 newdb = (struct sgDb *) ufdbCalloc( sizeof(struct sgDb), 1 );
1658 newdb->dbhome = NULL;
1659 newdb->dbcp = NULL;
1660 newdb->type = SGDBTYPE_DOMAINLIST;
1661
1662 sgDbInit( newdb, basefilename );
1663 if (newdb->dbcp == NULL)
1664 {
1665 ufdbLogError( "execdomainlist for %s: command produced a .ufdb file but I failed to load it", cat->name );
1666 ufdbFree( newdb );
1667 return NULL;
1668 }
1669
1670 if (ufdbGV.debug || ufdbGV.debugExternalScripts)
1671 ufdbLogMessage( "execdomainlist for %s: new URL table is loaded", cat->name );
1672
1673 return newdb;
1674 }
1675
1676
ufdbSourceExecUserList(char * command)1677 static void ufdbSourceExecUserList(
1678 char * command ) // must be malloced
1679 {
1680 time_t t0, te;
1681 struct Source * sp;
1682
1683 /* execuserlist is used to dynamically retrieve a list of usernames and
1684 * is executed every 15 minutes to refresh the list of usernames.
1685 */
1686
1687 sp = ufdbNewGV.lastSource;
1688 if (sp->userDb != NULL && sp->userDb->type != SGDBTYPE_EXECUSERLIST)
1689 {
1690 ufdbLogFatalError( "execuserlist \"%s\" in source \"%s\" on line %d: "
1691 "found mix of exec and non-exec userlists",
1692 command, sp->name, lineno );
1693 return;
1694 }
1695 if (sp->userDb != NULL)
1696 {
1697 ufdbLogFatalError( "execuserlist \"%s\" in source \"%s\" on line %d: "
1698 "more than one execuserlist is not supported. Merge the userlists in the script.",
1699 command, sp->name, lineno );
1700 return;
1701 }
1702 ufdbLogMessage( "execuserlist \"%s\"", command );
1703
1704 t0 = time( NULL );
1705 sp->userDb = UFDBretrieveExecUserlist( &ufdbNewGV, command );
1706 sp->sarg0 = command; /* command is already malloc-ed */
1707 te = time( NULL );
1708
1709 if (te - t0 > 4)
1710 ufdbLogMessage( "WARNING: it took %ld seconds to execute \"%s\" *****", te - t0, command );
1711
1712 if (ufdbGV.debug>1 || ufdbGV.debugExternalScripts)
1713 {
1714 UFDBmemDBprintUserDB( "user", (struct UFDBmemDB *) sp->userDb->dbcp );
1715 }
1716 }
1717
1718
ufdbSourceExecIPList(char * command)1719 static void ufdbSourceExecIPList(
1720 char * command ) // must be malloced
1721 {
1722 time_t t0, te;
1723 struct Source * sp;
1724
1725 /* execiplist is used to dynamically retrieve a list of IP addresses and
1726 * is executed every 15 minutes to refresh the list of IP addresses.
1727 */
1728
1729 sp = ufdbNewGV.lastSource;
1730 if (sp->ipv4 != NULL || sp->ipv6 != NULL)
1731 {
1732 ufdbLogFatalError( "execiplist \"%s\" in source \"%s\" on line %d: "
1733 "found mix of exec and non-exec iplists",
1734 command, sp->name, lineno );
1735 return;
1736 }
1737 ufdbLogMessage( "execiplist \"%s\"", command );
1738
1739 t0 = time( NULL );
1740 UFDBretrieveExecIPlist( &ufdbNewGV, command, &sp->ipv4hosts, &sp->ipv4, &sp->ipv6hosts, &sp->ipv6 );
1741 sp->execiplistCommand = command; /* command is already malloc-ed */
1742 te = time( NULL );
1743
1744 if (te - t0 > 4)
1745 ufdbLogMessage( "WARNING: it took %ld seconds to execute \"%s\" *****", te - t0, command );
1746
1747 if (ufdbGV.debug>1 || ufdbGV.debugExternalScripts)
1748 {
1749 UFDBlogIPv4( sp->ipv4 );
1750 UFDBlogIPv6( sp->ipv6 );
1751 }
1752 }
1753
1754
ufdbSourceUserList(char * file)1755 static void ufdbSourceUserList(
1756 char * file )
1757 {
1758 char * dbhome;
1759 char * f;
1760 FILE * fp;
1761 char * p;
1762 char * c;
1763 char * s;
1764 char * lc;
1765 char * lineptr;
1766 int ullineno;
1767 struct sgDb * udb;
1768 struct Source * sp;
1769 char line[10000];
1770
1771 sp = ufdbNewGV.lastSource;
1772 if (ufdbGV.debug)
1773 ufdbLogMessage( "ufdbSourceUserList: source \"%s\" file \"%s\"",
1774 sp->name != NULL ? sp->name : "nosource", file );
1775 udb = sp->userDb;
1776 if (udb != NULL && udb->type != SGDBTYPE_USERLIST)
1777 {
1778 ufdbLogFatalError( "userlist \"%s\" in source \"%s\" on line %d: "
1779 "found mix of exec and non-exec userlists",
1780 file, sp->name, lineno );
1781 return;
1782 }
1783 if (udb == NULL)
1784 {
1785 udb = sp->userDb = (struct sgDb *) ufdbMalloc( sizeof(struct sgDb) );
1786 udb->dbhome = NULL;
1787 udb->dbcp = (void *) UFDBmemDBinit();
1788 udb->type = SGDBTYPE_USERLIST;
1789 udb->entries = 0;
1790 }
1791
1792 dbhome = ufdbNewGV.databaseDirectory;
1793
1794 if (file[0] == '/')
1795 f = file;
1796 else
1797 {
1798 f = (char *) ufdbMalloc( strlen(dbhome) + strlen(file) + 2 );
1799 strcpy( f, dbhome );
1800 strcat( f, "/" );
1801 strcat( f, file );
1802 ufdbFree( file );
1803 }
1804
1805 if ((fp = fopen(f,"r")) == NULL)
1806 {
1807 ufdbLogError( "line %d: can't open userlist %s: %s *****", lineno, f, strerror(errno) );
1808 ufdbFree( f );
1809 return;
1810 }
1811 ullineno = 0;
1812
1813 ufdbLogMessage( "userlist \"%s\"", f );
1814
1815 while (fgets(line,sizeof(line),fp) != NULL)
1816 {
1817 ullineno++;
1818 if (line[0] == '#') /* skip comments */
1819 continue;
1820
1821 p = strchr( line, '\n' );
1822 if (p != NULL)
1823 {
1824 *p = '\0';
1825 if (p != line)
1826 {
1827 if (*(p - 1) == '\r') /* remove ^M */
1828 *(p-1) = '\0';
1829 }
1830 }
1831
1832 if (line[0] == '\0')
1833 {
1834 ufdbLogError( "userlist %s: line %d: line is empty", f, ullineno );
1835 continue;
1836 }
1837
1838 c = strchr( line, '#' ); /* remove comment */
1839 if (c != NULL)
1840 *c = '\0';
1841
1842 p = strtok_r( line, " \t,", &lineptr );
1843 if (p == NULL || *p == '\0')
1844 continue;
1845
1846 /* we may have a passwd-style formatted file. Ignore ':' and everything else that follows. */
1847 if ((s = strchr(p,':')) != NULL)
1848 *s = '\0';
1849
1850 do
1851 {
1852 for (lc = p; *lc != '\0'; lc++) // convert username to lowercase
1853 {
1854 if (*lc <= 'Z' && *lc >= 'A')
1855 *lc += 'a' - 'A';
1856 }
1857 if (*p != '\0')
1858 {
1859 udb->entries++;
1860 UFDBmemDBinsert( (struct UFDBmemDB *) udb->dbcp, p, NULL );
1861 }
1862 } while ((p = strtok_r(NULL," \t,",&lineptr)) != NULL && *p != '\0');
1863 }
1864 fclose( fp );
1865
1866 if (ufdbGV.debug > 1)
1867 {
1868 ufdbLogMessage( "just read userlist \"%s\"", f );
1869 UFDBmemDBprintUserDB( "user", (struct UFDBmemDB *) udb->dbcp );
1870 }
1871
1872 ufdbFree( f );
1873 }
1874
1875
ufdbSourceUserQuota(const char * seconds,const char * sporadic,const char * renew)1876 static void ufdbSourceUserQuota(
1877 const char * seconds,
1878 const char * sporadic,
1879 const char * renew )
1880 {
1881 if (seconds == NULL || sporadic == NULL || renew == NULL)
1882 { ; } // prevent compiler warning
1883
1884 ufdbLogError( "line %d: userquota is not supported", lineno );
1885 }
1886
1887
defSourceDomain(char * domain)1888 static void defSourceDomain(
1889 char * domain )
1890 {
1891 struct Source * sp;
1892
1893 sp = ufdbNewGV.lastSource;
1894 if (sp->domainDb == NULL)
1895 sp->domainDb = (struct sgDb *) UFDBmemDBinit();
1896
1897 if (ufdbGV.debug)
1898 ufdbLogMessage( "defSourceDomain \"%s\"", domain );
1899
1900 UFDBmemDBinsert( (struct UFDBmemDB *) sp->domainDb, domain, NULL );
1901
1902 ufdbFree( domain );
1903 }
1904
1905
ufdbSourceEval(int method)1906 static void ufdbSourceEval(
1907 int method )
1908 {
1909 if (ufdbNewGV.lastSource != NULL)
1910 {
1911 if (ufdbGV.debug)
1912 ufdbLogMessage( "ufdbSourceEval %d: %s", method,
1913 method == UFDB_EVAL_OR ? "evaluate-or" : "evaluate-and" );
1914 ufdbNewGV.lastSource->evaluationMethod = method;
1915 }
1916 }
1917
1918
defSourceTime(char * name,int within)1919 static void defSourceTime(
1920 char * name,
1921 int within )
1922 {
1923 struct ufdbTime * t;
1924
1925 if ((t = sgTimeFindName(name)) == NULL)
1926 {
1927 ufdbLogFatalError( "line %d: time \"%s\" is not defined in configuration file %s",
1928 lineno, name, ufdbNewGV.configFile );
1929 ufdbFree( name );
1930 return;
1931 }
1932
1933 ufdbNewGV.lastSource->within = within;
1934 ufdbNewGV.lastSource->time = t;
1935 ufdbFree( name );
1936 }
1937
1938
defSourceFindName(struct Source * slist,const char * name)1939 static struct Source * defSourceFindName(
1940 struct Source * slist,
1941 const char * name )
1942 {
1943 for ( ; slist != NULL; slist = slist->next)
1944 {
1945 if (strcmp(name,slist->name) == 0)
1946 return slist;
1947 }
1948 return NULL;
1949 }
1950
1951
defSourceIPV4List(char * file)1952 static void defSourceIPV4List(
1953 char * file )
1954 {
1955 char * dbhome;
1956 char * f;
1957 FILE * fp;
1958 char * p;
1959 char * c;
1960 char * cidr;
1961 int i;
1962 int l = 0;
1963 char * lineptr;
1964 char line[UFDB_MAX_URL_LENGTH];
1965
1966 dbhome = ufdbNewGV.databaseDirectory;
1967
1968 if (file[0] == '/')
1969 {
1970 f = file;
1971 }
1972 else
1973 {
1974 f = (char *) ufdbMalloc( strlen(dbhome) + strlen(file) + 2 );
1975 strcpy( f, dbhome );
1976 strcat( f, "/" );
1977 strcat( f, file );
1978 ufdbFree( file );
1979 }
1980
1981 if ((fp = fopen(f,"r")) == NULL)
1982 {
1983 ufdbLogError( "line %d: can't open ipv4list %s: %s", lineno, f, strerror(errno) );
1984 ufdbFree( f );
1985 return;
1986 }
1987
1988 ufdbLogMessage( "ipv4list \"%s\"", f );
1989
1990 while (fgets(line,sizeof(line),fp) != NULL)
1991 {
1992 l++;
1993 if (*line == '#')
1994 continue;
1995 p = strchr( line, '\n' );
1996 if (p != NULL && p != line)
1997 {
1998 if (*(p - 1) == '\r') // remove ^M
1999 p--;
2000 *p = '\0';
2001 }
2002 c = strchr( line, '#' );
2003 p = strtok_r( line, " \t,", &lineptr );
2004 do {
2005 if (c != NULL && p >= c) // find the comment
2006 break;
2007 i = strspn( p, ".0123456789/-" );
2008 if (i == 0)
2009 break;
2010 *(p + i) = '\0';
2011 if ((cidr = strchr(p,'/')) != NULL)
2012 {
2013 *cidr = '\0';
2014 cidr++;
2015 if (strchr(cidr,'.') == NULL)
2016 sgIpv4( p, SG_IPTYPE_CIDR, f, l );
2017 else
2018 sgIpv4( p, SG_IPTYPE_CLASS, f, l );
2019 }
2020 else if ((cidr = strchr(p,'-')) != NULL)
2021 {
2022 sgIpv4( p, SG_IPTYPE_RANGE, f, l );
2023 }
2024 else
2025 {
2026 sgIpv4( p, SG_IPTYPE_HOST, f, l );
2027 }
2028 } while ((p = strtok_r(NULL," \t,",&lineptr)) != NULL);
2029 }
2030
2031 fclose( fp );
2032 ufdbFree( f );
2033 }
2034
2035
defSourceIPV6List(char * file)2036 static void defSourceIPV6List(
2037 char * file )
2038 {
2039 char * dbhome;
2040 char * f;
2041 FILE * fp;
2042 char * p;
2043 char * c;
2044 int i;
2045 int l = 0;
2046 char * lineptr;
2047 char line[UFDB_MAX_URL_LENGTH];
2048
2049 dbhome = ufdbNewGV.databaseDirectory;
2050
2051 if (file[0] == '/')
2052 {
2053 f = file;
2054 }
2055 else
2056 {
2057 f = (char *) ufdbMalloc( strlen(dbhome) + strlen(file) + 2 );
2058 strcpy( f, dbhome );
2059 strcat( f, "/" );
2060 strcat( f, file );
2061 ufdbFree( file );
2062 }
2063
2064 if ((fp = fopen(f,"r")) == NULL)
2065 {
2066 ufdbLogError( "line %d: can't open ipv6list %s: %s", lineno, f, strerror(errno) );
2067 ufdbFree( f );
2068 return;
2069 }
2070
2071 ufdbLogMessage( "ipv6list \"%s\"", f );
2072
2073 while (fgets(line,sizeof(line),fp) != NULL)
2074 {
2075 l++;
2076 if (*line == '#')
2077 continue;
2078 p = strchr( line, '\n' );
2079 if (p != NULL && p != line)
2080 {
2081 if (*(p - 1) == '\r') // remove ^M
2082 p--;
2083 *p = '\0';
2084 }
2085 c = strchr( line, '#' );
2086 p = strtok_r( line, " \t,", &lineptr );
2087 do {
2088 if (c != NULL && p >= c) // find the comment
2089 break;
2090 i = strspn( p, ":.0123456789ABCDEFabcdef/" );
2091 if (i == 0)
2092 break;
2093 *(p + i) = '\0';
2094 if (strchr(p,'/') != NULL)
2095 {
2096 sgIpv6( p, SG_IPV6TYPE_CIDR, f, l );
2097 }
2098 else
2099 {
2100 sgIpv6( p, SG_IPV6TYPE_HOST, f, l );
2101 }
2102 } while ((p = strtok_r(NULL," \t,",&lineptr)) != NULL);
2103 }
2104
2105 fclose( fp );
2106 ufdbFree( f );
2107 }
2108
2109
2110 /* category block functions */
2111
ufdbCategory(char * cat)2112 void ufdbCategory(
2113 char * cat )
2114 {
2115 struct Category * sp;
2116
2117 #if UFDB_DEBUG
2118 ufdbLogMessage( "ufdbCategory %s", cat );
2119 #endif
2120
2121 if (ufdbNewGV.catList != NULL)
2122 {
2123 if ((struct Category *) ufdbCategoryFindByName(&ufdbNewGV,cat) != NULL)
2124 {
2125 ufdbLogFatalError( "line %d: category %s is already defined in configuration file %s",
2126 lineno, cat, ufdbNewGV.configFile );
2127 ufdbFree( cat );
2128 return;
2129 }
2130 }
2131
2132 sp = (struct Category *) ufdbMallocAligned( UFDB_CACHELINE_SIZE, sizeof(struct Category) );
2133 sp->active = 1;
2134 sp->within = UFDB_ACL_NONE;
2135 sp->activeBumping = UFDB_ACTIVE_BUMPING_NOTSET;
2136 sp->blockBumpedConnect = 0;
2137 sp->options = 0;
2138 sp->name = cat;
2139 sp->domainlist = NULL;
2140 sp->domainlistDb = NULL;
2141 sp->execdomainlist = NULL;
2142 sp->expressionlist = NULL;
2143 sp->regExp = NULL;
2144 sp->redirect = NULL;
2145 sp->time = NULL;
2146 sp->rewrite = NULL;
2147 sp->next = NULL;
2148 sp->nblocks = 0;
2149 sp->nmatches = 0;
2150
2151 if (ufdbNewGV.catList == NULL) {
2152 ufdbNewGV.catList = sp;
2153 ufdbNewGV.lastCat = sp;
2154 } else {
2155 ufdbNewGV.lastCat->next = sp;
2156 ufdbNewGV.lastCat = sp;
2157 }
2158
2159 /* category "security" is a special case: the options cannot be set default to 0
2160 * because the default value for allow-unknown-protocol-over-https is ON.
2161 */
2162 if (strcmp( cat, "security" ) == 0)
2163 sp->options = UFDB_OPT_UNKNOWN_PROTOCOL_OVER_HTTPS;
2164 }
2165
2166
ufdbCategoryEnd(void)2167 void ufdbCategoryEnd( void )
2168 {
2169 struct Category * d;
2170
2171 d = ufdbNewGV.lastCat;
2172 if (d->domainlist == NULL && d->expressionlist == NULL &&
2173 d->redirect == NULL && d->rewrite == NULL &&
2174 d->options == 0)
2175 {
2176 ufdbLogError( "category \"%s\" is missing content, set inactive *****", d->name );
2177 d->time = NULL;
2178 d->active = 0;
2179 }
2180 }
2181
2182
ufdbCategoryOption(int value,int option)2183 static void ufdbCategoryOption( int value, int option )
2184 {
2185 struct Category * sp;
2186
2187 sp = ufdbNewGV.lastCat;
2188 if (value)
2189 sp->options = sp->options | option;
2190 else
2191 sp->options = sp->options & (~option);
2192
2193 if (option == UFDB_OPT_HTTPS_WITH_HOSTNAME)
2194 ufdbNewGV.httpsWithHostname = value;
2195 else if (option == UFDB_OPT_HTTPS_OFFICAL_CERTIFICATE)
2196 ufdbNewGV.httpsOfficialCertificate = value;
2197 else if (option == UFDB_OPT_SKYPE_OVER_HTTPS)
2198 ufdbNewGV.SkypeOverHttps = value;
2199 else if (option == UFDB_OPT_GTALK_OVER_HTTPS)
2200 ufdbNewGV.GtalkOverHttps = value;
2201 else if (option == UFDB_OPT_YAHOOMSG_OVER_HTTPS)
2202 ufdbNewGV.YahooMsgOverHttps = value;
2203 else if (option == UFDB_OPT_AIM_OVER_HTTPS)
2204 ufdbNewGV.AimOverHttps = value;
2205 else if (option == UFDB_OPT_FBCHAT_OVER_HTTPS)
2206 ufdbNewGV.FBchatOverHttps = value;
2207 else if (option == UFDB_OPT_CITRIXONLINE_OVER_HTTPS)
2208 ufdbNewGV.CitrixOnlineOverHttps = value;
2209 else if (option == UFDB_OPT_ANYDESK_OVER_HTTPS)
2210 ufdbNewGV.AnydeskOverHttps = value;
2211 else if (option == UFDB_OPT_TEAMVIEWER_OVER_HTTPS)
2212 ufdbNewGV.TeamviewerOverHttps = value;
2213 else if (option == UFDB_OPT_PROHIBIT_INSECURE_SSLV2)
2214 ufdbNewGV.httpsNoSSLv2 = value;
2215 else if (option == UFDB_OPT_PROHIBIT_INSECURE_SSLV3)
2216 ufdbNewGV.httpsNoSSLv3 = value;
2217 else if (option == UFDB_OPT_UNKNOWN_PROTOCOL_OVER_HTTPS)
2218 ufdbNewGV.unknownProtocolOverHttps = value;
2219 else if (option == UFDB_OPT_SAFE_SEARCH)
2220 ;
2221 else if (option == UFDB_OPT_YOUTUBE_EDUFILTER)
2222 ;
2223 else
2224 ufdbLogError( "ufdbCategoryOption: unrecognised option %d *****", option );
2225
2226 if (ufdbGV.debug > 1)
2227 ufdbLogMessage( "ufdbCategoryOption: %s: option %d set to %d", sp->name, option, value );
2228 }
2229
2230
ufdbCategoryDomainList(char * domainlist)2231 void ufdbCategoryDomainList(
2232 char * domainlist )
2233 {
2234 struct Category * sp;
2235 const char * dbhome;
2236 char * dl;
2237 const char * name;
2238
2239 if (ufdbGV.debug > 1)
2240 ufdbLogMessage( "ufdbCategoryDomainList %s", domainlist==NULL ? "NULL" : domainlist );
2241
2242 if (ufdbNewGV.terminating)
2243 return;
2244
2245 sp = ufdbNewGV.lastCat;
2246
2247 if (sp->domainlistDb != NULL)
2248 {
2249 ufdbLogFatalError( "line %d: specify only one domainlist per category in configuration file %s",
2250 lineno, ufdbNewGV.configFile );
2251 return;
2252 }
2253
2254 dbhome = ufdbNewGV.databaseDirectory;
2255
2256 if (domainlist == NULL)
2257 {
2258 name = sp->name;
2259 dl = (char *) ufdbMalloc( sizeof("/dest/") + strlen(name) + sizeof("/domainlist") + 2 );
2260 strcpy(dl,"/dest/");
2261 strcat(dl,name);
2262 strcat(dl,"/domainlist");
2263
2264 sp->domainlist = (char *) ufdbMalloc( strlen(dbhome) + strlen(dl) + 2 );
2265 strcpy(sp->domainlist,dbhome);
2266 strcat(sp->domainlist,"/");
2267 strcat(sp->domainlist,dl);
2268 }
2269 else
2270 {
2271 if (domainlist[0] == '/')
2272 sp->domainlist = domainlist;
2273 else
2274 {
2275 sp->domainlist = (char *) ufdbMalloc( strlen(dbhome) + strlen(domainlist) + 2 );
2276 strcpy( sp->domainlist, dbhome );
2277 strcat( sp->domainlist, "/" );
2278 strcat( sp->domainlist, domainlist );
2279 ufdbFree( (void*) domainlist );
2280 }
2281 }
2282
2283 sp->domainlistDb = (struct sgDb *) ufdbCalloc( 1, sizeof(struct sgDb) );
2284 sp->domainlistDb->type = SGDBTYPE_DOMAINLIST;
2285 ufdbLogMessage( "loading URL table from \"%s\"", sp->domainlist );
2286 sgDbInit( sp->domainlistDb, sp->domainlist );
2287 if (sp->domainlistDb->dbcp == NULL ||
2288 ((struct UFDBmemTable *) sp->domainlistDb->dbcp)->table.nNextLevels == 0)
2289 {
2290 ufdbLogError( "URL database table \"%s\" is empty and is ignored *****", sp->domainlist );
2291 ufdbFreeDomainDb( sp->domainlistDb );
2292 sp->domainlistDb = NULL;
2293 }
2294 }
2295
2296
ufdbCategoryExecDomainList(char * command)2297 static void ufdbCategoryExecDomainList(
2298 char * command )
2299 {
2300 struct Category * sp;
2301
2302 #if UFDB_DEBUG
2303 ufdbLogMessage( "ufdbCategoryExecDomainList %s", command );
2304 #endif
2305
2306 sp = ufdbNewGV.lastCat;
2307
2308 if (sp == NULL)
2309 {
2310 ufdbLogFatalError( "execdomainlist is not within a URL category" );
2311 return;
2312 }
2313 sp->execdomainlist = command;
2314
2315 if (ufdbGV.debug)
2316 ufdbLogMessage( "execdomainlist for category %s: \"%s\"", sp->name, command );
2317 }
2318
2319
ufdbFreeDomainDb(struct sgDb * dbp)2320 void ufdbFreeDomainDb(
2321 struct sgDb * dbp )
2322 {
2323 struct UFDBmemTable * mt;
2324
2325 if (dbp == NULL)
2326 return;
2327
2328 mt = (struct UFDBmemTable *) dbp->dbcp;
2329 if (mt != NULL)
2330 {
2331 if (mt->index != NULL)
2332 {
2333 ufdbFree( mt->index ); /* version 2.x */
2334 ufdbFree( mt->table.nextLevel );
2335 }
2336 else
2337 UFDBfreeTableIndex_1_2( &(mt->table) ); /* version 1.2 */
2338 #if HAVE_MADVISE && !UFDB_BARE_METAL_SUPPORT && __linux__
2339 if (mt->madvisedSize)
2340 madvise( mt->mem, mt->madvisedSize, MADV_NORMAL );
2341 #endif
2342 if (mt->memStatus == UFDB_MEMSTATUS_MALLOC)
2343 ufdbFree( (void *) mt->mem );
2344 ufdbFree( mt );
2345 }
2346 ufdbFree( dbp );
2347 }
2348
2349
ufdbFreeIpv4List(struct Ipv4 * ipv4)2350 void ufdbFreeIpv4List( struct Ipv4 * ipv4 )
2351 {
2352 struct Ipv4 * tmp;
2353
2354 while (ipv4 != NULL)
2355 {
2356 tmp = ipv4->next;
2357 ufdbFree( (void*) ipv4 );
2358 ipv4 = tmp;
2359 }
2360 }
2361
2362
ufdbFreeIpv6List(struct Ipv6 * ipv6)2363 void ufdbFreeIpv6List( struct Ipv6 * ipv6 )
2364 {
2365 struct Ipv6 * tmp;
2366
2367 while (ipv6 != NULL)
2368 {
2369 tmp = ipv6->next;
2370 ufdbFree( (void*) ipv6 );
2371 ipv6 = tmp;
2372 }
2373 }
2374
2375
ufdbFreeSourceList(struct Source * src)2376 static void ufdbFreeSourceList( struct Source * src )
2377 {
2378 struct Source * tmp;
2379
2380 while (src != NULL)
2381 {
2382 if (src->ipv4hosts != NULL)
2383 UFDBmemDBdeleteDB( src->ipv4hosts );
2384 ufdbFreeIpv4List( src->ipv4 );
2385 if (src->ipv6hosts != NULL)
2386 UFDBmemDBdeleteDB( src->ipv6hosts );
2387 ufdbFreeIpv6List( src->ipv6 );
2388
2389 ufdbFree( (void*) src->name );
2390 if (src->domainDb != NULL)
2391 UFDBmemDBdeleteDB( (struct UFDBmemDB *) src->domainDb );
2392
2393 /* execuserlist content is saved during a reload except when ufdbguardd terminates */
2394 if (src->userDb != NULL && src->userDb->type != SGDBTYPE_EXECUSERLIST)
2395 {
2396 UFDBmemDBdeleteDB( (struct UFDBmemDB *) src->userDb->dbcp );
2397 ufdbFree( (void*) src->userDb );
2398 }
2399 ufdbFree( (void*) src->sarg0 );
2400 ufdbFree( (void*) src->execiplistCommand );
2401
2402 tmp = src->next;
2403 ufdbFree( (void*) src );
2404 src = tmp;
2405 }
2406 }
2407
2408
ufdbFreeAclCategoryList(struct AclCategory * ac)2409 static void ufdbFreeAclCategoryList( struct AclCategory * ac )
2410 {
2411 struct AclCategory * tmp;
2412
2413 while (ac != NULL)
2414 {
2415 ufdbFree( (void*) ac->name );
2416 tmp = ac->next;
2417 ufdbFree( (void*) ac );
2418 ac = tmp;
2419 }
2420 }
2421
2422
ufdbFreeAclList(struct Acl * acl)2423 static void ufdbFreeAclList( struct Acl * acl )
2424 {
2425 struct Acl * tmp;
2426
2427 while (acl != NULL)
2428 {
2429 ufdbFree( (void*) acl->name );
2430 ufdbFreeAclCategoryList( acl->pass );
2431 ufdbFreeAclCategoryList( acl->implicitPass );
2432 ufdbFree( (void*) acl->redirect );
2433 tmp = acl->next;
2434 ufdbFree( (void*) acl );
2435 acl = tmp;
2436 }
2437 }
2438
2439
ufdbFreeCategoryList(struct Category * cat)2440 static void ufdbFreeCategoryList( struct Category * cat )
2441 {
2442 struct Category * tmp;
2443
2444 while (cat != NULL)
2445 {
2446 if (ufdbGV.debug > 1 || ufdbGV.debugRegexp)
2447 ufdbLogMessage( "ufdbFreeCategoryList: freeing regexp of category %s", cat->name );
2448 ufdbFreeRegExprList( cat->regExp );
2449 ufdbFree( (void*) cat->name );
2450 ufdbFree( (void*) cat->domainlist );
2451 ufdbFreeDomainDb( cat->domainlistDb );
2452 ufdbFree( (void*) cat->execdomainlist );
2453 ufdbFree( (void*) cat->expressionlist );
2454 ufdbFree( (void*) cat->redirect );
2455 /* ufdbFree( cat->rewrite ); freed in ufdbFreeRewriteList() */
2456 tmp = cat->next;
2457 ufdbFree( (void*) cat );
2458 cat = tmp;
2459 }
2460 }
2461
2462
ufdbFreeRewriteList(struct sgRewrite * p)2463 static void ufdbFreeRewriteList(
2464 struct sgRewrite * p )
2465 {
2466 struct sgRewrite * tmp;
2467
2468 while (p != NULL)
2469 {
2470 ufdbFreeRegExprList( p->rewrite );
2471 ufdbFree( (void*) p->name );
2472 tmp = p->next;
2473 ufdbFree( (void*) p );
2474 p = tmp;
2475 }
2476 }
2477
2478
ufdbFreeTimeElement(struct TimeElement * p)2479 static void ufdbFreeTimeElement(
2480 struct TimeElement * p )
2481 {
2482 struct TimeElement * tmp;
2483
2484 while (p != NULL)
2485 {
2486 tmp = p->next;
2487 ufdbFree( (void*) p );
2488 p = tmp;
2489 }
2490 }
2491
2492
ufdbFreeTime(struct ufdbTime * p)2493 static void ufdbFreeTime(
2494 struct ufdbTime * p )
2495 {
2496 struct ufdbTime * tmp;
2497
2498 while (p != NULL)
2499 {
2500 ufdbFree( (void*) p->name );
2501 ufdbFreeTimeElement( p->element );
2502 tmp = p->next;
2503 ufdbFree( (void*) p );
2504 p = tmp;
2505 }
2506 }
2507
2508
ufdbFreeLastBits(struct ufdbGV * gv)2509 void ufdbFreeLastBits( struct ufdbGV * gv )
2510 {
2511 /* we may need these variables during a reload */
2512 if (gv->pidFilename != NULL)
2513 {
2514 ufdbFree( (void*) gv->pidFilename );
2515 gv->pidFilename = NULL;
2516 }
2517 if (gv->emailServer != NULL)
2518 {
2519 ufdbFree( (void*) gv->emailServer );
2520 gv->emailServer = NULL;
2521 }
2522 if (gv->myHostname != NULL)
2523 {
2524 ufdbFree( (void*) gv->myHostname );
2525 gv->myHostname = NULL;
2526 }
2527 if (gv->adminEmail != NULL)
2528 {
2529 ufdbFree( (void*) gv->adminEmail );
2530 gv->adminEmail = NULL;
2531 }
2532 if (gv->senderEmail != NULL)
2533 {
2534 ufdbFree( (void*) gv->senderEmail );
2535 gv->senderEmail = NULL;
2536 }
2537 if (gv->externalStatusCommand != NULL)
2538 {
2539 ufdbFree( (void*) gv->externalStatusCommand );
2540 gv->externalStatusCommand = NULL;
2541 }
2542 }
2543
2544
ufdbFreeAllMemory(struct ufdbGV * gv)2545 void ufdbFreeAllMemory( struct ufdbGV * gv )
2546 {
2547 if (gv->logDir != NULL)
2548 ufdbFree( gv->logDir );
2549 gv->logDir = NULL;
2550
2551 ufdbFreeRewriteList( gv->rewrite );
2552 gv->rewrite = NULL;
2553 gv->lastRewrite = NULL;
2554 gv->lastRewriteRegExec = NULL;
2555
2556 ufdbFreeCategoryList( gv->catList );
2557 gv->catList = NULL;
2558 gv->lastCat = NULL;
2559
2560 ufdbFreeAclList( gv->aclList );
2561 gv->aclList = NULL;
2562 gv->lastAcl = NULL;
2563 gv->defaultAcl = NULL;
2564 gv->lastAclCategory = NULL;
2565
2566 ufdbFreeSourceList( (struct Source *) gv->sourceList );
2567 gv->sourceList = NULL;
2568 gv->lastSource = NULL;
2569
2570 /* free ufdbNewGV.checkedDB */
2571 if (gv->checkedDB.mem != NULL)
2572 {
2573 if (gv->checkedDB.index != NULL)
2574 {
2575 ufdbFree( (void*) gv->checkedDB.index );
2576 ufdbFree( gv->checkedDB.table.nextLevel );
2577 }
2578 else
2579 UFDBfreeTableIndex_1_2( &(gv->checkedDB.table) );
2580 #if HAVE_MADVISE && !UFDB_BARE_METAL_SUPPORT && __linux__
2581 if (gv->checkedDB.madvisedSize)
2582 madvise( gv->checkedDB.mem, gv->checkedDB.madvisedSize, MADV_NORMAL );
2583 #endif
2584 gv->checkedDB.madvisedSize = 0;
2585 if (gv->checkedDB.memStatus == UFDB_MEMSTATUS_MALLOC)
2586 ufdbFree( (void*) gv->checkedDB.mem );
2587 }
2588 gv->checkedDB.table.nextLevel = NULL;
2589 gv->checkedDB.table.nNextLevels = 0;
2590 gv->checkedDB.mem = NULL;
2591 gv->checkedDB.index = NULL;
2592
2593 if (gv->checkedExpressions != NULL)
2594 {
2595 ufdbFreeRegExprList( gv->checkedExpressions );
2596 gv->checkedExpressions = NULL;
2597 }
2598
2599 ufdbFreeTime( gv->timeList );
2600 gv->timeList = NULL;
2601 gv->lastTime = NULL;
2602
2603 gv->lastTimeElement = NULL;
2604 gv->timeElement = NULL;
2605
2606 gv->lastRegExpDest = NULL;
2607
2608 ufdbFree( (void*) gv->SquidVersion );
2609 gv->SquidVersion = NULL;
2610 }
2611
2612
ufdbCategoryUrlList(char * urllist)2613 static void ufdbCategoryUrlList(
2614 char * urllist )
2615 {
2616 if (urllist == NULL)
2617 urllist = (char *) "-";
2618 ufdbLogError( "line %d: \"urllist %s\" is deprecated and ignored *****\n"
2619 "ufdbGenTable should be called with the -u option to include URLs\n"
2620 "ufdbGenTable combines URLs and domains in one table file so only the domainlist is required",
2621 lineno, urllist );
2622 if (urllist[0] != '-')
2623 ufdbFree( (void*) urllist );
2624 }
2625
2626
ufdbCategoryExpressionList(char * exprlist,const char * chcase)2627 void ufdbCategoryExpressionList(
2628 char * exprlist,
2629 const char * chcase )
2630 {
2631 FILE * fp;
2632 char * dbhome;
2633 char * dl;
2634 const char * name;
2635 char * p;
2636 int flags;
2637 struct stat statbuf;
2638 struct Category * sp;
2639 struct ufdbRegExp * regexp;
2640 char buf[UFDB_MAX_URL_LENGTH];
2641 char errbuf[256];
2642
2643 #if UFDB_DEBUG
2644 ufdbLogMessage( "ufdbCategoryExpressionList %s", exprlist );
2645 #endif
2646
2647 flags = REG_EXTENDED | REG_NOSUB;
2648 sp = ufdbNewGV.lastCat;
2649 dbhome = ufdbNewGV.databaseDirectory;
2650
2651 if (exprlist == NULL)
2652 {
2653 name = sp->name;
2654 dl = (char *) ufdbMalloc( sizeof("/dest/") + strlen(name) + sizeof("/expressionlist") + 2 );
2655 strcpy(dl,"/dest/");
2656 strcat(dl,name);
2657 strcat(dl,"/expressionlist");
2658
2659 flags |= REG_ICASE; /* default case insensitive */
2660
2661 sp->expressionlist = (char *) ufdbMalloc( strlen(dbhome) + strlen(dl) + 2 );
2662 strcpy(sp->expressionlist,dbhome);
2663 strcat(sp->expressionlist,"/");
2664 strcat(sp->expressionlist,dl);
2665 }
2666 else
2667 {
2668 if (exprlist[0] == '/')
2669 {
2670 sp->expressionlist = exprlist;
2671 }
2672 else
2673 {
2674 sp->expressionlist = (char *) ufdbMalloc( strlen(dbhome) + strlen(exprlist) + 2 );
2675 strcpy( sp->expressionlist, dbhome );
2676 strcat( sp->expressionlist, "/" );
2677 strcat( sp->expressionlist, exprlist );
2678 ufdbFree( (void*) exprlist );
2679 }
2680 if (*chcase == 'i')
2681 flags |= REG_ICASE; /* set case insensitive */
2682 }
2683
2684 ufdbLogMessage( "loading regular expressions from \"%s\"", sp->expressionlist );
2685
2686 if ((fp = fopen(sp->expressionlist, "r")) == NULL)
2687 {
2688 ufdbLogFatalError( "cannot open expression list %s: %s", sp->expressionlist, strerror(errno) );
2689 return;
2690 }
2691
2692 if (0 == fstat( fileno(fp), &statbuf ))
2693 {
2694 if (!S_ISREG(statbuf.st_mode))
2695 {
2696 ufdbLogFatalError( "expression list %s: not a regular file", sp->expressionlist );
2697 fclose( fp );
2698 return;
2699 }
2700 }
2701
2702 while (!feof(fp) && fgets(buf, sizeof(buf), fp) != NULL)
2703 {
2704 if (buf[0] == '#')
2705 continue;
2706
2707 p = (char *) strchr( buf, '\n' );
2708 if (p != NULL && p != buf)
2709 {
2710 if (*(p-1) == '\r') /* removing ^M */
2711 p--;
2712 *p = '\0';
2713 }
2714 /* TO-DO: warn about leading and trailing spaces */
2715 regexp = ufdbNewPatternBuffer( buf, flags );
2716 if (regexp->error)
2717 {
2718 regerror( regexp->error, (regex_t*) regexp->compiled[0], errbuf, sizeof(errbuf) );
2719 ufdbLogError( "regular expression error in %s:\n%s : %s *****", sp->expressionlist, errbuf, buf );
2720 }
2721 if (ufdbNewGV.lastCat->regExp == NULL)
2722 {
2723 ufdbNewGV.lastCat->regExp = regexp;
2724 ufdbNewGV.lastRegExpDest = regexp;
2725 }
2726 else
2727 {
2728 ufdbNewGV.lastRegExpDest->next = regexp;
2729 ufdbNewGV.lastRegExpDest = regexp;
2730 }
2731 }
2732 fclose( fp );
2733
2734 if (ufdbNewGV.expressionOptimisation)
2735 ufdbNewGV.lastCat->regExp = UFDBoptimizeExprList( sp->expressionlist, ufdbNewGV.lastCat->regExp );
2736 }
2737
2738
ufdbCategoryCACertsFile(char * cacertsFile)2739 static void ufdbCategoryCACertsFile(
2740 char * cacertsFile )
2741 {
2742 struct Category * cat;
2743
2744 cat = ufdbNewGV.lastCat;
2745 if (cat == NULL || strcmp( cat->name, "security" ) != 0)
2746 {
2747 ufdbLogFatalError( "cacerts can only be defined inside the \"security\" category" );
2748 return;
2749 }
2750
2751 if (*cacertsFile == '/')
2752 strcpy( ufdbNewGV.CAcertsFile, cacertsFile );
2753 else
2754 {
2755 char * dbh;
2756 dbh = ufdbNewGV.databaseDirectory;
2757 strcpy( ufdbNewGV.CAcertsFile, dbh );
2758 strcat( ufdbNewGV.CAcertsFile, "/" );
2759 strcat( ufdbNewGV.CAcertsFile, cacertsFile );
2760 }
2761 }
2762
2763
ufdbCategoryCACertsDir(char * cacertsDir)2764 static void ufdbCategoryCACertsDir(
2765 char * cacertsDir )
2766 {
2767 struct Category * cat;
2768
2769 cat = ufdbNewGV.lastCat;
2770 if (cat == NULL || strcmp( cat->name, "security" ) != 0)
2771 {
2772 ufdbLogFatalError( "cacerts-dir can only be defined inside the \"security\" category" );
2773 return;
2774 }
2775
2776 if (*cacertsDir == '/')
2777 strcpy( ufdbNewGV.CAcertsDir, cacertsDir );
2778 else
2779 {
2780 char * dbh;
2781 dbh = ufdbNewGV.databaseDirectory;
2782 strcpy( ufdbNewGV.CAcertsDir, dbh );
2783 strcat( ufdbNewGV.CAcertsDir, "/" );
2784 strcat( ufdbNewGV.CAcertsDir, cacertsDir );
2785 }
2786 }
2787
2788
ufdbCategoryRedirect(char * value)2789 static void ufdbCategoryRedirect(
2790 char * value )
2791 {
2792 struct Category * sp;
2793
2794 #if UFDB_DEBUG
2795 ufdbLogMessage( "ufdbCategoryRedirect %s", value );
2796 #endif
2797
2798 sp = ufdbNewGV.lastCat;
2799 sp->redirect = value;
2800 /* TODO: check that "localhost" is not here if no 302 is used */
2801 }
2802
2803
ufdbCategoryRewrite(char * value)2804 static void ufdbCategoryRewrite(
2805 char * value )
2806 {
2807 struct sgRewrite * rewrite;
2808
2809 if ((rewrite = sgRewriteFindName(value)) == NULL)
2810 {
2811 ufdbLogFatalError( "line %d: rewrite %s is not defined in configuration file %s",
2812 lineno, value, ufdbNewGV.configFile );
2813 return;
2814 }
2815
2816 ufdbNewGV.lastCat->rewrite = rewrite;
2817 }
2818
2819
ufdbCategoryBlockConnect(int flag)2820 static void ufdbCategoryBlockConnect(
2821 int flag )
2822 {
2823 ufdbNewGV.lastCat->blockBumpedConnect = flag;
2824
2825 if (ufdbGV.debug > 1)
2826 ufdbLogMessage( "ufdbCategoryBlockConnect: category \"%s\" : block-bumped-connect %s",
2827 ufdbNewGV.lastCat->name, flag ? "on" : "off" );
2828 }
2829
2830
ufdbCategoryActiveBumping(int flag)2831 static void ufdbCategoryActiveBumping(
2832 int flag )
2833 {
2834 ufdbNewGV.lastCat->activeBumping = flag ? UFDB_ACTIVE_BUMPING_ON : UFDB_ACTIVE_BUMPING_OFF;
2835
2836 if (ufdbGV.debug > 1)
2837 ufdbLogMessage( "ufdbCategoryActiveBumping: category \"%s\" : squid-uses-active-bumping %s",
2838 ufdbNewGV.lastCat->name, flag ? "on" : "off" );
2839 }
2840
2841
ufdbCategoryTime(char * name,int within)2842 static void ufdbCategoryTime(
2843 char * name,
2844 int within )
2845 {
2846 struct ufdbTime * t;
2847
2848 if ((t = sgTimeFindName(name)) == NULL)
2849 {
2850 ufdbLogFatalError( "line %d: time \"%s\" is not defined in configuration file %s",
2851 lineno, name, ufdbNewGV.configFile );
2852 ufdbFree( (void*) name );
2853 return;
2854 }
2855
2856 ufdbNewGV.lastCat->within = within;
2857 ufdbNewGV.lastCat->time = t;
2858 ufdbFree( (void*) name );
2859 }
2860
2861
ufdbCategoryFindByName(struct ufdbGV * gv,const char * name)2862 struct Category * ufdbCategoryFindByName(
2863 struct ufdbGV * gv,
2864 const char * name )
2865 {
2866 struct Category * p;
2867
2868 for (p = gv->catList; p != NULL; p = p->next)
2869 {
2870 if (strcmp(name,p->name) == 0)
2871 return p;
2872 }
2873 return NULL;
2874 }
2875
2876
sgRewrite(char * rewrite)2877 static void sgRewrite(
2878 char * rewrite )
2879 {
2880 struct sgRewrite * rew;
2881
2882 #if UFDB_DEBUG
2883 ufdbLogMessage( "sgRewrite %s", rewrite );
2884 #endif
2885
2886 if (ufdbNewGV.rewrite != NULL)
2887 {
2888 if ((struct sgRewrite *) sgRewriteFindName(rewrite) != NULL)
2889 {
2890 ufdbLogFatalError( "line %d: rewrite \"%s\" is not defined in configuration file %s",
2891 lineno, rewrite, ufdbNewGV.configFile );
2892 ufdbFree( (void*) rewrite );
2893 return;
2894 }
2895 }
2896
2897 rew = (struct sgRewrite *) ufdbMalloc( sizeof(struct sgRewrite) );
2898 rew->name = rewrite;
2899 rew->active = 1;
2900 rew->rewrite = NULL;
2901 rew->time = NULL;
2902 rew->within = UFDB_ACL_NONE;
2903 rew->next = NULL;
2904
2905 if (ufdbNewGV.rewrite == NULL)
2906 {
2907 ufdbNewGV.rewrite = rew;
2908 ufdbNewGV.lastRewrite = rew;
2909 }
2910 else
2911 {
2912 ufdbNewGV.lastRewrite->next = rew;
2913 ufdbNewGV.lastRewrite = rew;
2914 }
2915 }
2916
2917
sgRewriteTime(char * name,int within)2918 static void sgRewriteTime(
2919 char * name,
2920 int within )
2921 {
2922 struct ufdbTime * t;
2923
2924 #if UFDB_DEBUG
2925 ufdbLogMessage( "sgRewriteTime %s %d", name, within );
2926 #endif
2927
2928 if ((t = sgTimeFindName(name)) == NULL)
2929 {
2930 ufdbLogFatalError( "line %d: time \"%s\" is not defined in configuration file %s",
2931 lineno, name, ufdbNewGV.configFile );
2932 ufdbFree( (void*) name );
2933 return;
2934 }
2935
2936 ufdbNewGV.lastRewrite->within = within;
2937 ufdbNewGV.lastRewrite->time = t;
2938 ufdbFree( (void*) name );
2939 }
2940
2941
sgRewriteSubstitute(char * string)2942 static void sgRewriteSubstitute(
2943 char * string )
2944 {
2945 char * pattern;
2946 char * subst = NULL;
2947 char * p;
2948 int flags = REG_EXTENDED;
2949 int global = 0;
2950 char * httpcode = NULL;
2951 struct ufdbRegExp * regexp;
2952 char errbuf[256];
2953
2954 pattern = string + 2; /* skipping s@ */
2955 p = pattern;
2956 while ((p = strchr(p,'@')) != NULL)
2957 {
2958 if (*(p - 1) != '\\')
2959 {
2960 *p = '\0';
2961 subst = p + 1;
2962 break;
2963 }
2964 p++;
2965 }
2966
2967 p = strrchr( subst, '@' );
2968 while (p != NULL && *p != '\0')
2969 {
2970 if (*p == 'r' )
2971 httpcode = (char *) REDIRECT_TEMPORARILY;
2972 if (*p == 'R' )
2973 httpcode = (char *) REDIRECT_PERMANENT;
2974 if (*p == 'i' || *p == 'I')
2975 flags |= REG_ICASE;
2976 if (*p == 'g')
2977 global = 1;
2978 *p = '\0'; /* removes @i from string */
2979 p++;
2980 }
2981
2982 regexp = ufdbNewPatternBuffer( pattern, flags );
2983 if (regexp->error)
2984 {
2985 regerror( regexp->error, (regex_t*) regexp->compiled[0], errbuf, sizeof(errbuf) );
2986 ufdbLogError( "line %d: regular expression error in %s:\n%s *****", lineno, pattern, errbuf );
2987 }
2988 else {
2989 regexp->substitute = ufdbStrdup( subst );
2990 }
2991
2992 if (ufdbNewGV.lastRewrite->rewrite == NULL)
2993 ufdbNewGV.lastRewrite->rewrite = regexp;
2994 else
2995 ufdbNewGV.lastRewriteRegExec->next = regexp;
2996 regexp->httpcode = httpcode;
2997 regexp->global = global;
2998 ufdbNewGV.lastRewriteRegExec = regexp;
2999 }
3000
3001
sgRewriteFindName(const char * name)3002 static struct sgRewrite * sgRewriteFindName(
3003 const char * name )
3004 {
3005 struct sgRewrite * p;
3006
3007 for (p = ufdbNewGV.rewrite; p != NULL; p = p->next)
3008 {
3009 if (strcmp(name,p->name) == 0)
3010 return p;
3011 }
3012 return NULL;
3013 }
3014
3015
3016 /*
3017 * Time functions
3018 */
3019
3020 /*
3021 * sgTime - parse configuration time statement.
3022 */
sgTime(char * name)3023 static void sgTime(
3024 char * name )
3025 {
3026 struct ufdbTime * t;
3027
3028 if (ufdbGV.debug > 1)
3029 ufdbLogMessage( "sgTime %s", name );
3030
3031 if (ufdbNewGV.timeList != NULL)
3032 {
3033 if ((struct ufdbTime *) sgTimeFindName(name) != NULL)
3034 {
3035 ufdbLogFatalError( "line %d: time \"%s\" is not defined in configuration file %s",
3036 lineno, name, ufdbNewGV.configFile );
3037 ufdbFree( (void*) name );
3038 return;
3039 }
3040 }
3041 else
3042 numTimeElements = 0;
3043
3044 t = (struct ufdbTime *) ufdbMalloc( sizeof(struct ufdbTime) );
3045 t->name = name;
3046 t->active = 1;
3047 t->element = NULL;
3048 t->next = NULL;
3049
3050 ufdbNewGV.timeElement = NULL;
3051 ufdbNewGV.lastTimeElement = NULL;
3052 if (ufdbNewGV.timeList == NULL)
3053 {
3054 ufdbNewGV.timeList = t;
3055 ufdbNewGV.lastTime = t;
3056 }
3057 else
3058 {
3059 ufdbNewGV.lastTime->next = t;
3060 ufdbNewGV.lastTime = t;
3061 }
3062 }
3063
3064
3065 /*
3066 * sgTimeElementInit - initialise parsing of a configuration time element.
3067 */
sgTimeElementInit(void)3068 static void sgTimeElementInit( void )
3069 {
3070 struct TimeElement * te;
3071
3072 te = (struct TimeElement *) ufdbCalloc( 1, sizeof(struct TimeElement) );
3073 numTimeElements++;
3074
3075 if (ufdbNewGV.lastTime->element == NULL)
3076 ufdbNewGV.lastTime->element = te;
3077 if (ufdbNewGV.lastTimeElement != NULL)
3078 ufdbNewGV.lastTimeElement->next = te;
3079 ufdbNewGV.lastTimeElement = te;
3080 }
3081
3082
3083 /*
3084 * sgTimeElementEnd - finalise parsing of configuration time element.
3085 */
sgTimeElementEnd(void)3086 static void sgTimeElementEnd( void )
3087 {
3088 time_switch = 0;
3089 date_switch = 0;
3090
3091 if (ufdbNewGV.lastTimeElement->fromdate != 0)
3092 {
3093 if (ufdbNewGV.lastTimeElement->todate == 0)
3094 ufdbNewGV.lastTimeElement->todate = ufdbNewGV.lastTimeElement->fromdate + 86399;
3095 else
3096 ufdbNewGV.lastTimeElement->todate = ufdbNewGV.lastTimeElement->todate + 86399;
3097 }
3098
3099 if (ufdbNewGV.lastTimeElement->from == 0 && ufdbNewGV.lastTimeElement->to == 0)
3100 ufdbNewGV.lastTimeElement->to = 1439; /* set time to 23:59 */
3101 }
3102
3103
3104 /*
3105 * sgTimeElementAdd - add configuration time element.
3106 */
sgTimeElementAdd(char * element,char type)3107 static void sgTimeElementAdd(
3108 char * element,
3109 char type )
3110 {
3111 struct TimeElement * te;
3112 char * p;
3113 char wday;
3114 int h, m, Y, M, D;
3115 time_t sec;
3116 char * lineptr;
3117
3118 wday = 0;
3119 M = 0;
3120 D = -1;
3121 te = ufdbNewGV.lastTimeElement;
3122
3123 switch (type)
3124 {
3125 case T_WEEKDAY:
3126 p = strtok_r( element, " \t,", &lineptr );
3127 do {
3128 if (*p == '*') {
3129 wday = 0x7F;
3130 } else if (!strncmp(p,"sun",3)) {
3131 wday = wday | 0x01;
3132 } else if (!strncmp(p,"mon",3)) {
3133 wday = wday | 0x02;
3134 } else if (!strncmp(p,"tue",3)) {
3135 wday = wday | 0x04;
3136 } else if (!strncmp(p,"wed",3)) {
3137 wday = wday | 0x08;
3138 } else if (!strncmp(p,"thu",3)) {
3139 wday = wday | 0x10;
3140 } else if (!strncmp(p,"fri",3)) {
3141 wday = wday | 0x20;
3142 } else if (!strncmp(p,"sat",3)) {
3143 wday = wday | 0x40;
3144 }
3145 p = strtok_r( NULL, " \t,", &lineptr );
3146 } while (p != NULL);
3147 te->wday = wday;
3148 break;
3149
3150 case T_TVAL:
3151 h = -1;
3152 m = -1;
3153 sscanf( element, "%d:%d", &h, &m );
3154 if ((h < 0 || h > 24) || (m < 0 || m > 59))
3155 {
3156 ufdbLogFatalError( "line %d: time format error in %s", lineno, ufdbNewGV.configFile );
3157 h = 0;
3158 m = 0;
3159 }
3160 if (time_switch == 0)
3161 {
3162 time_switch++;
3163 te->from = (h * 60) + m ;
3164 }
3165 else
3166 {
3167 time_switch = 0;
3168 te->to = (h * 60) + m ;
3169 }
3170 break;
3171
3172 case T_DVAL:
3173 sec = date2sec( element );
3174 if (sec == -1)
3175 {
3176 ufdbLogFatalError( "line %d: date format error in %s", lineno, ufdbNewGV.configFile );
3177 sec = 1;
3178 }
3179 if (date_switch == 0) {
3180 date_switch++;
3181 te->fromdate = sec;
3182 } else {
3183 date_switch = 0;
3184 te->todate = sec;
3185 }
3186 break;
3187
3188 case T_DVALCRON:
3189 p = strtok_r( element, "-./", &lineptr );
3190 Y = atoi(p);
3191 if (*p == '*')
3192 Y = -1;
3193 else
3194 Y = atoi(p);
3195 while ((p=strtok_r(NULL,"-./",&lineptr)) != NULL)
3196 {
3197 if (*p == '*')
3198 if (M == 0)
3199 M = -1;
3200 else
3201 D = -1;
3202 else
3203 if (M == 0)
3204 M = atoi(p);
3205 else
3206 D = atoi(p);
3207 }
3208 te->y = Y;
3209 te->m = M;
3210 te->d = D;
3211 break;
3212
3213 case T_WEEKLY:
3214 p = element;
3215 while (*p != '\0')
3216 {
3217 switch (*p) {
3218 case 'S':
3219 case 's':
3220 wday = wday | 0x01;
3221 break;
3222 case 'M':
3223 case 'm':
3224 wday = wday | 0x02;
3225 break;
3226 case 'T':
3227 case 't':
3228 wday = wday | 0x04;
3229 break;
3230 case 'W':
3231 case 'w':
3232 wday = wday | 0x08;
3233 break;
3234 case 'H':
3235 case 'h':
3236 wday = wday | 0x10;
3237 break;
3238 case 'F':
3239 case 'f':
3240 wday = wday | 0x20;
3241 break;
3242 case 'A':
3243 case 'a':
3244 wday = wday | 0x40;
3245 break;
3246 default:
3247 ufdbLogFatalError( "line %d: weekday format error in %s", lineno, ufdbNewGV.configFile );
3248 break;
3249 }
3250 p++;
3251 }
3252 te->wday = wday;
3253 break;
3254 }
3255
3256 ufdbFree( (void*) element );
3257 }
3258
3259
3260 /*
3261 * lookup a ufdbTime element by name.
3262 */
sgTimeFindName(const char * name)3263 static struct ufdbTime * sgTimeFindName(
3264 const char * name )
3265 {
3266 struct ufdbTime * p;
3267
3268 for (p = ufdbNewGV.timeList; p != NULL; p = p->next)
3269 {
3270 if (strcmp(name,p->name) == 0)
3271 return p;
3272 }
3273 return NULL;
3274 }
3275
3276
3277 /*
3278 * sgTimeCmp - Time array sort function.
3279 */
sgTimeCmp(const void * a,const void * b)3280 static int sgTimeCmp( const void * a, const void * b )
3281 {
3282 const int * aa = (const int *) a;
3283 const int * bb = (const int *) b;
3284
3285 return *aa - *bb;
3286 }
3287
3288
3289 /*
3290 * _getSortedTimeElementTimes - produce a sorted array of time element times
3291 */
_getSortedTimeElementTimes(void)3292 static void _getSortedTimeElementTimes( void ) // uses ufdbGV
3293 {
3294 struct ufdbTime * p;
3295 struct TimeElement * te;
3296 int i, j;
3297 int totalNumElems;
3298
3299 if (ufdbGV.debug > 1)
3300 ufdbLogMessage( "_getSortedTimeElementEvents" );
3301
3302 if (ufdbGV.timeList == NULL)
3303 return;
3304
3305 /* find total number of time elements */
3306 totalNumElems = 0;
3307 for (p = ufdbGV.timeList; p != NULL; p = p->next)
3308 for (te = p->element; te != NULL; te = te->next)
3309 totalNumElems++;
3310
3311 TimeElementsEvents = (int *) ufdbCalloc( totalNumElems * 2 , sizeof(int) );
3312
3313 i = 0;
3314 for (p = ufdbGV.timeList; p != NULL; p = p->next)
3315 {
3316 for (te = p->element; te != NULL; te = te->next)
3317 {
3318 TimeElementsEvents[i++] = te->from == 0 ? 1440 : te->from;
3319 TimeElementsEvents[i++] = te->to == 0 ? 1440 : te->to;
3320 }
3321 }
3322
3323 qsort( TimeElementsEvents, totalNumElems * 2, sizeof(int), sgTimeCmp );
3324
3325 if (ufdbGV.debug > 1)
3326 ufdbLogMessage( " _getSortedTimeElementEvents: after qsort" );
3327
3328 /* remove identical time elements */
3329 for (i=1,j=1; i < totalNumElems * 2; i++)
3330 {
3331 if (TimeElementsEvents[i] > TimeElementsEvents[i-1])
3332 {
3333 TimeElementsEvents[j] = TimeElementsEvents[i];
3334 j++;
3335 }
3336 }
3337
3338 numTimeElements = j; /* #unique time elements */
3339 }
3340
3341
3342 /*
3343 * _TimeEvaluateElements - evaluate all elements if they match the current time/date and mark them active.
3344 */
_TimeEvaluateElements(struct tm * tm_now,time_t now)3345 static void _TimeEvaluateElements( // uses ufdbGV
3346 struct tm * tm_now,
3347 time_t now )
3348 {
3349 struct ufdbTime * tlist;
3350 struct TimeElement * te;
3351 int min;
3352
3353 if (ufdbGV.debug > 1)
3354 ufdbLogMessage( " _TimeEvaluateElements" );
3355
3356 for (tlist = ufdbGV.timeList; tlist != NULL; tlist = tlist->next)
3357 {
3358 tlist->active = 0;
3359 for (te = tlist->element; te != NULL; te = te->next)
3360 {
3361 if (te->wday != 0) /* check wday */
3362 {
3363 if (((1 << tm_now->tm_wday) & te->wday) != 0)
3364 {
3365 min = (tm_now->tm_hour * 60) + tm_now->tm_min;
3366 if (min >= te->from && min < te->to)
3367 {
3368 tlist->active = 1;
3369 break;
3370 }
3371 }
3372 }
3373 else if (te->fromdate != 0) /* check date */
3374 {
3375 if (now >= te->fromdate && now <= te->todate)
3376 {
3377 min = (tm_now->tm_hour * 60) + tm_now->tm_min;
3378 if (min >= te->from && min < te->to)
3379 {
3380 tlist->active = 1;
3381 break;
3382 }
3383 }
3384 }
3385 else /* check crondate */
3386 {
3387 if (te->y == -1 || te->y == (tm_now->tm_year + 1900))
3388 {
3389 if (te->m == -1 || te->m == (tm_now->tm_mon + 1))
3390 {
3391 if (te->d == -1 || te->d == (tm_now->tm_mday))
3392 {
3393 min = (tm_now->tm_hour * 60) + tm_now->tm_min;
3394 if (min >= te->from && min < te->to)
3395 {
3396 tlist->active = 1;
3397 break;
3398 }
3399 }
3400 }
3401 }
3402 }
3403 }
3404 if (ufdbGV.debug > 1)
3405 ufdbLogMessage( " _TimeEvaluateElements: time %s is %sactive", tlist->name, tlist->active?"":"not " );
3406 }
3407 }
3408
3409
3410 /*
3411 * _TimeSetAclSrcDestRew - mark all acl/source/dest/rew (in)active.
3412 */
_TimeSetAclSrcDestRew(void)3413 static void _TimeSetAclSrcDestRew( void ) // uses ufdbGV
3414 {
3415 struct Acl * acl;
3416 struct Category * cat;
3417 struct Source * s;
3418 struct sgRewrite * rew;
3419 int a;
3420
3421 if (ufdbGV.debug > 1)
3422 ufdbLogMessage( " _TimeSetAclSrcDestRew" );
3423
3424 for (acl = ufdbGV.aclList; acl != NULL; acl = acl->next)
3425 {
3426 if (acl->time != NULL && acl->within != UFDB_ACL_ELSE)
3427 {
3428 /* Be careful here: we are multithreaded and other threads use the value
3429 * of acl->active at the same time.
3430 */
3431 a = acl->time->active;
3432 if (acl->within == UFDB_ACL_OUTSIDE)
3433 a = !a;
3434 if (acl->next != NULL && acl->next->within == UFDB_ACL_ELSE)
3435 acl->next->active = !a;
3436 acl->active = a;
3437 }
3438 #if 0
3439 if (acl->pass == NULL)
3440 acl->active = 0; /* it can have a 'continue' so do not make it inactive */
3441 #endif
3442 if (ufdbGV.debug > 1)
3443 ufdbLogMessage( " _TimeSetAclSrcDestRew: acl %s %s is %sactive", acl->name,
3444 acl->within==UFDB_ACL_ELSE ? "ELSE" :
3445 acl->within==UFDB_ACL_WITHIN ? "WITHIN" :
3446 acl->within==UFDB_ACL_OUTSIDE ? "OUTSIDE" : "",
3447 acl->active?"":"not " );
3448 }
3449
3450 for (cat = ufdbGV.catList; cat != NULL; cat = cat->next)
3451 {
3452 if (cat->time != NULL)
3453 {
3454 cat->active = cat->time->active;
3455 if (cat->within == UFDB_ACL_OUTSIDE)
3456 cat->active = !cat->active;
3457 }
3458 if (ufdbGV.debug > 1)
3459 ufdbLogMessage( " _TimeSetAclSrcDestRew: category %s is %sactive", cat->name, cat->active?"":"not " );
3460 }
3461
3462 for (s = ufdbGV.sourceList; s != NULL; s = s->next)
3463 {
3464 if (s->time != NULL)
3465 {
3466 s->active = s->time->active;
3467 if (s->within == UFDB_ACL_OUTSIDE)
3468 s->active = !s->active;
3469 }
3470 if (ufdbGV.debug > 1)
3471 ufdbLogMessage( " _TimeSetAclSrcDestRew: source %s is %sactive", s->name, s->active?"":"not " );
3472 }
3473
3474 for (rew = ufdbGV.rewrite; rew != NULL; rew = rew->next)
3475 {
3476 if (rew->time != NULL)
3477 {
3478 rew->active = rew->time->active;
3479 if (rew->within == UFDB_ACL_OUTSIDE)
3480 rew->active = !rew->active;
3481 }
3482 if (ufdbGV.debug > 1)
3483 ufdbLogMessage( " _TimeSetAclSrcDestRew: rewrite %s is %sactive", rew->name, rew->active?"":"not " );
3484 }
3485 }
3486
3487
sgAlarm(int s)3488 static void sgAlarm( int s )
3489 {
3490 if (s) { ; } // prevent compiler warning
3491 // do nothing; there is a thread that waits for a SIGALRM which calls ufdbHandleAlarmForTimeEvents()
3492 }
3493
3494
3495 /*
3496 * ufdbHandleAlarmForTimeEvents - the alarm for the next time event went off so
3497 * recalculate the time-dependent active state.
3498 */
ufdbHandleAlarmForTimeEvents(int why)3499 void ufdbHandleAlarmForTimeEvents( // uses ufdbGV
3500 int why )
3501 {
3502 time_t now;
3503 struct tm tm_now;
3504 int m;
3505 int tindex;
3506 int lastval;
3507
3508 if (ufdbGV.debug)
3509 ufdbLogMessage( "ufdbHandleAlarmForTimeEvents( why=%s )", why==UFDB_PARAM_INIT ? "init" : "alarm" );
3510
3511 if (why == UFDB_PARAM_INIT)
3512 ufdbLogMessage( "time definitions are used; evaluating current ACLs" );
3513 else
3514 {
3515 ufdbLogMessage( "alarm went off to recalculate time ACLs" );
3516 if (ufdbGV.terminating)
3517 {
3518 ufdbLogMessage( "This alarm is ignored because ufdbguardd is exiting" );
3519 return;
3520 }
3521 if (ufdbGV.reconfig)
3522 {
3523 ufdbLogMessage( "This alarm is ignored because the configuration is being reloaded"
3524 " and a new alarm is set to go off in 15 seconds" );
3525 alarm( 15 );
3526 return;
3527 }
3528 }
3529
3530 if (ufdbGV.timeList == NULL)
3531 {
3532 return;
3533 }
3534
3535 // NOTE: _getSortedTimeElementTimes() mallocs TimeElementsEvents[] and this function frees it.
3536 _getSortedTimeElementTimes();
3537
3538 now = UFDBtime() + 30;
3539 localtime_r( &now, &tm_now );
3540 m = (tm_now.tm_hour * 60) + tm_now.tm_min;
3541
3542 lastval = 0;
3543 for (tindex = 0; tindex < numTimeElements; tindex++)
3544 {
3545 #if UFDB_TIME_DEBUG
3546 if (ufdbGV.debug > 1)
3547 ufdbLogMessage( " TimeElementsEvents[%d] = %d", tindex, TimeElementsEvents[tindex] );
3548 #endif
3549 lastval = TimeElementsEvents[tindex];
3550 if (TimeElementsEvents[tindex] >= m)
3551 break;
3552 }
3553
3554 if (ufdbGV.debug > 1)
3555 ufdbLogMessage( " ufdbHandleAlarmForTimeEvents: m = %d tindex = %d, lastval = %d", m, tindex, lastval );
3556
3557 if (lastval < m)
3558 m = (((1440 - m) + TimeElementsEvents[0]) * 60) - tm_now.tm_sec;
3559 else
3560 m = ((lastval - m) * 60) - tm_now.tm_sec;
3561
3562 if (m <= 0)
3563 m = 30;
3564
3565 _TimeEvaluateElements( &tm_now, now );
3566 _TimeSetAclSrcDestRew();
3567
3568 ufdbFree( (void*) TimeElementsEvents );
3569 TimeElementsEvents = NULL;
3570
3571 ufdbLogMessage( "next alarm is in %d seconds", (unsigned int) m );
3572 ufdbSetSignalHandler( SIGALRM, sgAlarm );
3573 (void) alarm( (unsigned int) m );
3574 }
3575
3576
3577 /*
3578 * sgTimeElementClone - copy a time specification.
3579 */
sgTimeElementClone(void)3580 static void sgTimeElementClone( void )
3581 {
3582 struct TimeElement * te;
3583 struct TimeElement * tmp;
3584
3585 te = ufdbNewGV.lastTimeElement;
3586 if (te == NULL)
3587 {
3588 ufdbLogFatalError( "No previous TimeElement in sgTimeElementClone !" );
3589 return;
3590 }
3591 else
3592 {
3593 sgTimeElementInit();
3594 ufdbNewGV.lastTimeElement->wday = te->wday;
3595 ufdbNewGV.lastTimeElement->from = te->from;
3596 ufdbNewGV.lastTimeElement->to = te->to;
3597 ufdbNewGV.lastTimeElement->y = te->y;
3598 ufdbNewGV.lastTimeElement->m = te->m;
3599 ufdbNewGV.lastTimeElement->d = te->d;
3600 ufdbNewGV.lastTimeElement->fromdate = te->fromdate;
3601 ufdbNewGV.lastTimeElement->todate = te->todate;
3602 tmp = ufdbNewGV.lastTimeElement;
3603 ufdbNewGV.lastTimeElement = te;
3604 sgTimeElementEnd();
3605 ufdbNewGV.lastTimeElement = tmp;
3606 }
3607 }
3608
3609
3610 /*
3611 * IP functions
3612 */
3613
sgIpv4Last(struct Source * s)3614 static struct Ipv4 * sgIpv4Last(
3615 struct Source * s )
3616 {
3617 struct Ipv4 * ipv4;
3618 struct Ipv4 * last;
3619
3620 last = NULL;
3621 for (ipv4 = s->ipv4; ipv4 != NULL; ipv4 = ipv4->next)
3622 last = ipv4;
3623
3624 return last;
3625 }
3626
3627
sgIpv4(const char * addr,int type,const char * file,int lineno)3628 static void sgIpv4(
3629 const char * addr,
3630 int type,
3631 const char * file,
3632 int lineno )
3633 {
3634 struct Ipv4 * ipv4;
3635 char * addr2;
3636 char * cidr;
3637 char * end;
3638 unsigned int octet;
3639
3640 #if 1
3641 if (ufdbGV.debug> 1)
3642 ufdbLogMessage( " sgIpv4( %s %d %s %d )", addr, type, file, lineno );
3643 #endif
3644
3645 switch (type)
3646 {
3647 case SG_IPTYPE_HOST:
3648 if (ufdbNewGV.lastSource->ipv4hosts == NULL)
3649 ufdbNewGV.lastSource->ipv4hosts = UFDBmemDBinit();
3650 UFDBmemDBinsert( ufdbNewGV.lastSource->ipv4hosts, addr, NULL );
3651 break;
3652
3653 case SG_IPTYPE_RANGE:
3654 addr2 = strchr( addr, '-' );
3655 *addr2 = '\0';
3656 end = addr2;
3657 while (*(end-1) == ' ' || *(end-1) == '\t')
3658 {
3659 *(end-1) = '\0';
3660 end--;
3661 }
3662 addr2++;
3663 while (*addr2 == ' ' || *addr2 == '\t')
3664 addr2++;
3665
3666 ipv4 = (struct Ipv4 *) ufdbMalloc( sizeof(struct Ipv4) );
3667 ipv4->type = SG_IPTYPE_RANGE;
3668 ipv4->net_is_set = 1;
3669 ipv4->next = NULL;
3670 if (ufdbNewGV.lastSource->ipv4 == NULL)
3671 ufdbNewGV.lastSource->ipv4 = ipv4;
3672 else
3673 sgIpv4Last( ufdbNewGV.lastSource )->next = ipv4;
3674
3675 if (sgConvDot(addr,&ipv4->net) == NULL)
3676 {
3677 ufdbLogFatalError( "IPv4 address error in %s line %d: %s - %s", file, lineno, addr, addr2 );
3678 ipv4->net = 0;
3679 ipv4->net_is_set = 0;
3680 }
3681 if (sgConvDot(addr2,&ipv4->mask) == NULL)
3682 {
3683 ufdbLogFatalError( "IPv4 address error in %s line %d: %s - %s", file, lineno, addr, addr2 );
3684 ipv4->mask = 0;
3685 ipv4->net_is_set = 0;
3686 }
3687
3688 if ((unsigned int) ipv4->net > (unsigned int) ipv4->mask)
3689 ufdbLogFatalError( "IPv4 range error in %s line %d: %s - %s", file, lineno, addr, addr2 );
3690 break;
3691
3692 case SG_IPTYPE_CLASS:
3693 addr2 = strchr( addr, '/' );
3694 *addr2 = '\0';
3695 addr2++;
3696 ipv4 = (struct Ipv4 *) ufdbMalloc( sizeof(struct Ipv4) );
3697 ipv4->type = SG_IPTYPE_CLASS;
3698 ipv4->net_is_set = 1;
3699 ipv4->next = NULL;
3700 if (ufdbNewGV.lastSource->ipv4 == NULL)
3701 ufdbNewGV.lastSource->ipv4 = ipv4;
3702 else
3703 sgIpv4Last( ufdbNewGV.lastSource )->next = ipv4;
3704
3705 if (sgConvDot(addr,&ipv4->net) == NULL)
3706 {
3707 ufdbLogFatalError( "IPv4 address error in %s line %d: %s/%s", file, lineno, addr, addr2 );
3708 ipv4->net = 0;
3709 ipv4->net_is_set = 0;
3710 }
3711 if (sgConvDot(addr2,&ipv4->mask) == NULL)
3712 {
3713 ufdbLogFatalError( "IPv4 address error in %s line %d: %s/%s", file, lineno, addr, addr2 );
3714 ipv4->mask = 0;
3715 }
3716 break;
3717
3718 case SG_IPTYPE_CIDR:
3719 cidr = strchr( addr, '/' );
3720 *cidr = '\0';
3721 cidr++;
3722 octet = (unsigned long) atoi( cidr );
3723 if (octet > 32)
3724 {
3725 ufdbLogFatalError( "IPv4 address CIDR out of range in %s line %d: %s/%s",
3726 file, lineno, addr, cidr );
3727 octet = 32;
3728 }
3729 ipv4 = (struct Ipv4 *) ufdbMalloc( sizeof(struct Ipv4) );
3730 ipv4->type = SG_IPTYPE_CIDR;
3731 ipv4->net_is_set = 1;
3732 ipv4->next = NULL;
3733 if (ufdbNewGV.lastSource->ipv4 == NULL)
3734 ufdbNewGV.lastSource->ipv4 = ipv4;
3735 else
3736 sgIpv4Last( ufdbNewGV.lastSource )->next = ipv4;
3737
3738 if (sgConvDot(addr,&ipv4->net) == NULL)
3739 {
3740 ufdbLogFatalError( "IPv4 address error in %s line %d: %s/%s", file, lineno, addr, cidr );
3741 ipv4->net = 0;
3742 ipv4->net_is_set = 0;
3743 }
3744 if (octet == 32)
3745 ipv4->mask = 0xffffffff;
3746 else
3747 ipv4->mask = 0xffffffff ^ (0xffffffff >> octet);
3748 ipv4->net = ipv4->net & ipv4->mask;
3749 break;
3750 }
3751 }
3752
3753
sgIpv6Last(struct Source * s)3754 static struct Ipv6 * sgIpv6Last(
3755 struct Source * s )
3756 {
3757 struct Ipv6 * ipv6;
3758 struct Ipv6 * last;
3759
3760 last = NULL;
3761 for (ipv6 = s->ipv6; ipv6 != NULL; ipv6 = ipv6->next)
3762 last = ipv6;
3763
3764 return last;
3765 }
3766
3767
3768
sgIpv6(const char * addr,int type,const char * file,int line)3769 static void sgIpv6(
3770 const char * addr,
3771 int type,
3772 const char * file,
3773 int line )
3774 {
3775 #if 1
3776 if (ufdbGV.debug > 1)
3777 ufdbLogMessage( " sgIpv6( %s %d %s %d/%d )", addr, type, file, line, lineno );
3778 #endif
3779
3780 if (type == SG_IPV6TYPE_HOST)
3781 {
3782 struct in6_addr dummy;
3783 if (!sgValidateIPv6( addr, &dummy ))
3784 {
3785 ufdbLogFatalError( "incorrect IPv6 address \"%s\" in %s line %d", addr, file, lineno );
3786 }
3787 else
3788 {
3789 if (ufdbNewGV.lastSource->ipv6hosts == NULL)
3790 ufdbNewGV.lastSource->ipv6hosts = UFDBmemDBinit();
3791 UFDBmemDBinsert( ufdbNewGV.lastSource->ipv6hosts, addr, NULL );
3792 }
3793 }
3794 else if (type == SG_IPV6TYPE_CIDR)
3795 {
3796 char * s = (char*) strchr( addr, '/' );
3797 if (s == NULL)
3798 {
3799 ufdbLogFatalError( "IPv6 net has no '/' in \"%s\" in %s line %d", addr, file, lineno );
3800 }
3801 else
3802 {
3803 struct Ipv6 * ipv6;
3804
3805 ipv6 = (struct Ipv6 *) ufdbMalloc( sizeof(struct Ipv6) );
3806 ipv6->type = SG_IPV6TYPE_CIDR;
3807 ipv6->next = NULL;
3808 if (ufdbNewGV.lastSource->ipv6 == NULL)
3809 ufdbNewGV.lastSource->ipv6 = ipv6;
3810 else
3811 sgIpv6Last( ufdbNewGV.lastSource )->next = ipv6;
3812
3813 *s = '\0';
3814 ipv6->cidr = (unsigned long) atoi( s+1 );
3815 if (ipv6->cidr < 1 || ipv6->cidr > 128)
3816 {
3817 ufdbLogFatalError( "IPv6 address CIDR out of range \"%s\" in %s line %d", addr, file, lineno );
3818 ipv6->cidr = 128;
3819 }
3820 if (!sgValidateIPv6( addr, &ipv6->ipv6 ))
3821 {
3822 ufdbLogFatalError( "incorrect IPv6 address \"%s\" in %s line %d", addr, file, lineno );
3823 }
3824 *s = '/';
3825 }
3826 }
3827 else
3828 {
3829 ufdbLogFatalError( "sgIpv6 called with unsupported type %d in %s line %d: %s", type, file, lineno, addr );
3830 }
3831 }
3832
3833
3834 /*
3835 * ACL functions
3836 */
3837
ufdbAcl(const char * name,const char * value,int within)3838 static void ufdbAcl(
3839 const char * name,
3840 const char * value,
3841 int within )
3842 {
3843 struct Acl * acl;
3844 struct Source * source;
3845
3846 #if UFDB_DEBUG
3847 ufdbLogMessage( "ufdbAcl name=\"%s\" value=\"%s\" within=%d line=%d",
3848 name==NULL?"NULL":name, value==NULL?"NULL":value, within, lineno );
3849 #endif
3850
3851 if (ufdbNewGV.aclList != NULL)
3852 {
3853 if (ufdbAclFindByName(&ufdbNewGV,name) != NULL)
3854 {
3855 ufdbLogFatalError( "line %d: ACL \"%s\" is already defined in configuration file %s",
3856 lineno, name, ufdbNewGV.configFile );
3857 }
3858 }
3859
3860 if (within == UFDB_ACL_ELSE)
3861 {
3862 if (ufdbNewGV.lastAcl == NULL)
3863 {
3864 ufdbLogFatalError( "line %d: ACL \"else\" has no parent ACL", lineno );
3865 return;
3866 }
3867 if (name == NULL)
3868 name = ufdbStrdup( ufdbNewGV.lastAcl->name );
3869 }
3870
3871 acl = (struct Acl *) ufdbMalloc( sizeof(struct Acl) );
3872
3873 source = NULL;
3874 if (strcmp(name,"default") == 0)
3875 {
3876 ufdbNewGV.defaultAcl = acl;
3877 }
3878 else
3879 {
3880 if ((source = defSourceFindName(ufdbNewGV.sourceList,name)) == NULL)
3881 {
3882 ufdbLogFatalError( "line %d: ACL source \"%s\" is not defined in configuration file %s",
3883 lineno, name, ufdbNewGV.configFile );
3884 if (ufdbNewGV.fastRefresh && ufdbGV.fastRefresh &&
3885 defSourceFindName(ufdbGV.sourceList,name) != NULL)
3886 ufdbLogError( "But ACL source \"%s\" is defined in the old configuration *****", name );
3887 if (ufdbGV.debug > 1)
3888 UFDBlogConfig( &ufdbGV );
3889 ufdbFree( (void*) name );
3890 ufdbFree( (void*) acl );
3891 return;
3892 }
3893 }
3894
3895 acl->name = name;
3896 acl->active = within == UFDB_ACL_ELSE ? 0 : 1;
3897 acl->source = source;
3898 acl->pass = NULL;
3899 acl->implicitPass = NULL;
3900 acl->hasTerminatorNone = 0;
3901 acl->rewriteDefault = 1;
3902 acl->rewrite = NULL;
3903 acl->redirect = NULL;
3904 acl->time = NULL;
3905 acl->within = within;
3906 acl->next = NULL;
3907
3908 if (value != NULL)
3909 {
3910 struct ufdbTime * t;
3911 if ((t = sgTimeFindName(value)) == NULL)
3912 {
3913 ufdbLogFatalError( "line %d: ACL time %s is not defined in configuration file %s",
3914 lineno, value, ufdbNewGV.configFile );
3915 return;
3916 }
3917 acl->time = t;
3918 }
3919
3920 if (ufdbNewGV.aclList == NULL)
3921 {
3922 ufdbNewGV.aclList = acl;
3923 ufdbNewGV.lastAcl = acl;
3924 }
3925 else
3926 {
3927 ufdbNewGV.lastAcl->next = acl;
3928 ufdbNewGV.lastAcl = acl;
3929 }
3930 }
3931
3932
ufdbAclSetValue(const char * what,const char * value,int allowed)3933 static void ufdbAclSetValue(
3934 const char * what,
3935 const char * value,
3936 int allowed )
3937 {
3938 struct Category * cat = NULL;
3939 struct AclCategory * aclcat;
3940 int type;
3941
3942 #if UFDB_DEBUG
3943 ufdbLogMessage( "ufdbAclSetValue %s %s%s", what, allowed ? "" : "!", value );
3944 #endif
3945
3946 if (ufdbNewGV.lastAcl == NULL)
3947 {
3948 ufdbLogError( "error in configuration file on line %d: "
3949 "cannot set value for \"%s\" because there is no defined ACL",
3950 lineno, what );
3951 ufdbFree( (void*) value );
3952 return;
3953 }
3954
3955 type = ACL_TYPE_TERMINATOR;
3956
3957 if (strcmp(what,"pass") == 0)
3958 {
3959 if (strcmp(value,"any")==0 || strcmp(value,"all")==0)
3960 {
3961 if (!allowed)
3962 ufdbLogFatalError( "error in configuration file on line %d: do not use '!any' or '!all'. "
3963 "Use 'none' instead.", lineno );
3964 allowed = 1;
3965 }
3966 else if (strcmp(value,"none") == 0)
3967 {
3968 if (!allowed)
3969 ufdbLogFatalError( "error in configuration file on line %d: do not use '!none'. "
3970 "Use 'any' instead.", lineno );
3971 allowed = 0;
3972 }
3973 else if (strcmp(value,"in-addr") == 0) {
3974 type = ACL_TYPE_INADDR;
3975 }
3976 else
3977 {
3978 if ((cat = ufdbCategoryFindByName(&ufdbNewGV,value)) == NULL)
3979 {
3980 ufdbLogFatalError( "ACL category \"%s\" (line %d) is not defined in configuration file %s",
3981 value, lineno, ufdbNewGV.configFile );
3982 if (ufdbNewGV.fastRefresh && ufdbGV.fastRefresh &&
3983 ufdbCategoryFindByName(&ufdbGV,value) != NULL)
3984 ufdbLogError( "But category \"%s\" is defined in the old configuration *****", value );
3985 if (ufdbGV.debug > 1)
3986 UFDBlogConfig( &ufdbGV );
3987 ufdbFree( (void*) value );
3988 return;
3989 }
3990 type = ACL_TYPE_DEFAULT;
3991 }
3992
3993 aclcat = (struct AclCategory *) ufdbMallocAligned( UFDB_CACHELINE_SIZE, sizeof(struct AclCategory) );
3994 aclcat->name = value;
3995 aclcat->cat = cat;
3996 aclcat->access = allowed;
3997 aclcat->type = type;
3998 aclcat->next = NULL;
3999 aclcat->nblocks = 0;
4000 aclcat->nmatches = 0;
4001
4002 if (ufdbNewGV.lastAcl->pass == NULL) {
4003 ufdbNewGV.lastAcl->pass = aclcat;
4004 } else {
4005 ufdbNewGV.lastAclCategory->next = aclcat;
4006 }
4007 ufdbNewGV.lastAclCategory = aclcat;
4008 }
4009 else if (strcmp(what,"redirect") == 0)
4010 {
4011 if (strcmp(value,"default") != 0)
4012 {
4013 ufdbNewGV.lastAcl->redirect = value;
4014 }
4015 else
4016 {
4017 ufdbNewGV.lastAcl->redirect = NULL;
4018 ufdbFree( (void*) value );
4019 }
4020 }
4021 else if (strcmp(what,"rewrite") == 0)
4022 {
4023 if (strcmp(value,"none") == 0)
4024 {
4025 ufdbNewGV.lastAcl->rewriteDefault = 0;
4026 ufdbNewGV.lastAcl->rewrite = NULL;
4027 }
4028 else
4029 {
4030 struct sgRewrite * rewrite;
4031
4032 if ((rewrite = sgRewriteFindName(value)) == NULL)
4033 {
4034 ufdbLogFatalError( "rewrite %s is not defined in configuration file %s",
4035 value, ufdbNewGV.configFile );
4036 }
4037 ufdbNewGV.lastAcl->rewriteDefault = 0;
4038 ufdbNewGV.lastAcl->rewrite = rewrite;
4039 }
4040 ufdbFree( (void*) value );
4041 }
4042 }
4043
4044
ufdbAclFindByName(struct ufdbGV * gv,const char * name)4045 struct Acl * ufdbAclFindByName(
4046 struct ufdbGV * gv,
4047 const char * name )
4048 {
4049 struct Acl * p;
4050
4051 if (name == NULL)
4052 return NULL;
4053
4054 for (p = gv->aclList; p != NULL; p = p->next)
4055 {
4056 if (strcmp(name,p->name) == 0)
4057 return p;
4058 }
4059
4060 return NULL;
4061 }
4062
4063
logConfig(void)4064 static void logConfig( void )
4065 {
4066 int lno;
4067 FILE * fin;
4068 char line[32678];
4069
4070 if (ufdbNewGV.configLogged)
4071 return;
4072 ufdbNewGV.configLogged = 1;
4073
4074 fin = fopen( ufdbNewGV.configFile, "r" );
4075 if (fin == NULL)
4076 return;
4077
4078 ufdbLogMessage( "======== literal content of config file ========" );
4079 lno = 1;
4080 while (UFDBfgetsNoNL(line,sizeof(line)-1,fin) != NULL)
4081 {
4082 ufdbLogMessage( "%04d: %s", lno, line );
4083 lno++;
4084 }
4085 ufdbLogMessage( "======== end of literal content ========" );
4086 fclose( fin );
4087 }
4088
4089
yyerror(const char * s)4090 void yyerror( const char * s )
4091 {
4092 ufdbLogFatalError( "line %d: %s in configuration file %s", lineno, s, ufdbNewGV.configFile );
4093 }
4094
4095
yywrap()4096 int yywrap()
4097 {
4098 return 1;
4099 }
4100
4101