1/* 2 By accepting this notice, you agree to be bound by the following 3 agreements: 4 5 This software product, squidGuard, is copyrighted (C) 1998-2008 6 by Christine Kronberg, Shalla Secure Services. All rights reserved. 7 8 This program is free software; you can redistribute it and/or modify it 9 under the terms of the GNU General Public License (version 2) as 10 published by the Free Software Foundation. It is distributed in the 11 hope that it will be useful, but WITHOUT ANY WARRANTY; without even the 12 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 13 PURPOSE. See the GNU General Public License (GPL) for more details. 14 15 You should have received a copy of the GNU General Public License 16 (GPL) along with this program. 17*/ 18 19 20%{ 21#include "sg.h" 22extern int globalDebug; 23 24#ifdef HAVE_LIBLDAP 25#include "lber.h" 26#include "ldap.h" 27#endif 28 29#ifdef HAVE_MYSQL 30#include <mysql.h> 31#endif 32 33#include "sgEx.h" 34 35FILE *yyin, *yyout; 36char *configFile; 37 38int numTimeElements; 39int *TimeElementsEvents; 40 41static int time_switch = 0; 42static int date_switch = 0; 43 44int numSource = 0; 45 46void rfc1738_unescape(char *); 47void 48rfc1738_unescape(char *s) 49{ 50 char hexnum[3]; 51 int i, j; /* i is write, j is read */ 52 unsigned int x; 53 for (i = j = 0; s[j]; i++, j++) { 54 s[i] = s[j]; 55 if (s[i] != '%') 56 continue; 57 if (s[j + 1] == '%') { /* %% case */ 58 j++; 59 continue; 60 } 61 if (s[j + 1] && s[j + 2]) { 62 if (s[j + 1] == '0' && s[j + 2] == '0') { /* %00 case */ 63 j += 2; 64 continue; 65 } 66 hexnum[0] = s[j + 1]; 67 hexnum[1] = s[j + 2]; 68 hexnum[2] = '\0'; 69 if (1 == sscanf(hexnum, "%x", &x)) { 70 s[i] = (char) (0x0ff & x); 71 j += 2; 72 } 73 } 74 } 75 s[i] = '\0'; 76} 77 78%} 79 80%union { 81 char *string; 82 char *tval; 83 char *dval; 84 char *dvalcron; 85 int *integer; 86} 87 88%token WORD END START_BRACKET STOP_BRACKET WEEKDAY LDAPDNSTR 89%token DESTINATION REWRITE ACL TIME TVAL DVAL DVALCRON 90%token SOURCE CIDR IPCLASS CONTINUE 91%token IPADDR DBHOME DOMAINLIST URLLIST EXPRESSIONLIST IPLIST 92%token DOMAIN USER USERLIST USERQUERY LDAPUSERSEARCH USERQUOTA IP NL NUMBER 93%token PASS REDIRECT LOGDIR SUBST CHAR MINUTELY HOURLY DAILY WEEKLY DATE 94%token WITHIN OUTSIDE ELSE LOGFILE ANONYMOUS VERBOSE CONTINIOUS SPORADIC 95%token LDAPCACHETIME EXECUSERLIST EXECCMD LDAPPROTOVER 96%token LDAPBINDDN LDAPBINDPASS MYSQLUSERNAME MYSQLPASSWORD DATABASE 97 98%type <string> WORD 99%type <string> EXECCMD 100%type <string> WEEKDAY 101%type <string> LDAPDNSTR 102%type <string> NUMBER 103%type <tval> TVAL 104%type <string> DVAL 105%type <string> DVALCRON 106%type <string> CHAR 107%type <string> SUBST 108%type <string> IPADDR 109%type <string> DBHOME LOGDIR 110%type <string> CIDR 111%type <string> IPCLASS 112%type <string> acl_content 113%type <string> acl 114%type <string> dval 115%type <string> dvalcron 116%type <string> tval 117%type <string> date 118%type <string> ttime 119%% 120 121start: statements 122 ; 123 124dbhome: DBHOME WORD { sgSetting("dbhome",$2); } 125 ; 126 127logdir: LOGDIR WORD { sgSetting("logdir",$2); } 128 ; 129 130ldapcachetime: LDAPCACHETIME NUMBER { sgSetting("ldapcachetime",$2); } 131 ; 132 133ldapprotover: LDAPPROTOVER NUMBER {sgSetting("ldapprotover",$2); } 134 ; 135 136ldapbinddn: LDAPBINDDN LDAPDNSTR { sgSetting("ldapbinddn",$2); } 137 ; 138 139ldapbindpass: LDAPBINDPASS WORD { sgSetting("ldapbindpass",$2); } 140 ; 141 142mysqlusername: MYSQLUSERNAME WORD { sgSetting("mysqlusername",$2); } 143 ; 144 145mysqlpassword: MYSQLPASSWORD WORD { sgSetting("mysqlpassword",$2); } 146 ; 147 148mysqldb: DATABASE WORD { sgSetting("mysqldb",$2); } 149 ; 150 151start_block: 152 START_BRACKET 153 ; 154 155stop_block: 156 STOP_BRACKET 157 ; 158 159destination: DESTINATION WORD { sgDest($2); } 160 ; 161 162destination_block: destination start_block destination_contents stop_block 163 { sgDestEnd();} 164 ; 165 166destination_contents: 167 | destination_contents destination_content 168 ; 169destination_content: 170 DOMAINLIST WORD { sgDestDomainList($2); } 171 | DOMAINLIST '-' { sgDestDomainList(NULL); } 172 | URLLIST WORD { sgDestUrlList($2); } 173 | URLLIST '-' { sgDestUrlList(NULL); } 174 | EXPRESSIONLIST '-' { sgDestExpressionList(NULL,NULL); } 175 | EXPRESSIONLIST 'i' WORD { sgDestExpressionList($3,"i"); } 176 | EXPRESSIONLIST WORD { sgDestExpressionList($2,"n"); } 177 | REDIRECT WORD {sgDestRedirect($2); } 178 | REWRITE WORD {sgDestRewrite($2); } 179 | WITHIN WORD { sgDestTime($2,WITHIN); } 180 | OUTSIDE WORD { sgDestTime($2,OUTSIDE); } 181 | LOGFILE ANONYMOUS WORD { sgLogFile(SG_BLOCK_DESTINATION,1,0,$3); } 182 | LOGFILE VERBOSE WORD { sgLogFile(SG_BLOCK_DESTINATION,0,1,$3); } 183 | LOGFILE ANONYMOUS VERBOSE WORD { sgLogFile(SG_BLOCK_DESTINATION,1,1,$4); } 184 | LOGFILE VERBOSE ANONYMOUS WORD { sgLogFile(SG_BLOCK_DESTINATION,1,1,$4); } 185 | LOGFILE WORD { sgLogFile(SG_BLOCK_DESTINATION,0,0,$2); } 186 ; 187 188source: SOURCE WORD { sgSource($2); } 189 ; 190 191source_block: source start_block source_contents stop_block {sgSourceEnd();} 192 ; 193 194source_contents: 195 | source_contents source_content 196 ; 197 198source_content: DOMAIN domain 199 | USER user 200 | USERLIST WORD { sgSourceUserList($2); } 201@MYSQLLINE@ 202@YACCLINE@ 203 | EXECUSERLIST EXECCMD { sgSourceExecUserList($2); } 204 | USERQUOTA NUMBER NUMBER HOURLY { sgSourceUserQuota($2,$3,"3600");} 205 | USERQUOTA NUMBER NUMBER DAILY { sgSourceUserQuota($2,$3,"86400");} 206 | USERQUOTA NUMBER NUMBER WEEKLY { sgSourceUserQuota($2,$3,"604800");} 207 | USERQUOTA NUMBER NUMBER NUMBER { sgSourceUserQuota($2,$3,$4);} 208 | IP ips 209 | IPLIST WORD { sgSourceIpList($2); } 210 | WITHIN WORD { sgSourceTime($2,WITHIN); } 211 | OUTSIDE WORD { sgSourceTime($2,OUTSIDE); } 212 | LOGFILE ANONYMOUS WORD {sgLogFile(SG_BLOCK_SOURCE,1,0,$3);} 213 | LOGFILE VERBOSE WORD {sgLogFile(SG_BLOCK_SOURCE,0,1,$3);} 214 | LOGFILE ANONYMOUS VERBOSE WORD {sgLogFile(SG_BLOCK_SOURCE,1,1,$4);} 215 | LOGFILE VERBOSE ANONYMOUS WORD {sgLogFile(SG_BLOCK_SOURCE,1,1,$4);} 216 | LOGFILE WORD { sgLogFile(SG_BLOCK_SOURCE,0,0,$2); } 217 | CONTINUE { lastSource->cont_search = 1; } 218 ; 219domain: 220 | domain WORD { sgSourceDomain($2); } 221 | domain ',' 222 ; 223 224user: 225 | user WORD { sgSourceUser($2); } 226 | user ',' 227 ; 228 229acl_block: ACL start_block acl_contents stop_block 230 ; 231 232acl_contents: 233 | acl_contents acl_content 234 ; 235 236acl: WORD {sgAcl($1,NULL,0);} 237 | WORD WITHIN WORD {sgAcl($1,$3,WITHIN);} 238 | WORD OUTSIDE WORD { sgAcl($1,$3,OUTSIDE); } 239 ; 240 241acl_content: acl start_block access_contents stop_block 242 | acl start_block access_contents stop_block ELSE 243 {sgAcl(NULL,NULL,ELSE);} 244 start_block access_contents stop_block 245 ; 246 247access_contents: 248 | access_contents access_content 249 ; 250 251access_content: PASS access_pass { } 252 | REWRITE WORD { sgAclSetValue("rewrite",$2,0); } 253 | REDIRECT WORD { sgAclSetValue("redirect",$2,0); } 254 | LOGFILE ANONYMOUS WORD {sgLogFile(SG_BLOCK_ACL,1,0,$3);} 255 | LOGFILE VERBOSE WORD {sgLogFile(SG_BLOCK_ACL,0,1,$3);} 256 | LOGFILE ANONYMOUS VERBOSE WORD {sgLogFile(SG_BLOCK_ACL,1,1,$4);} 257 | LOGFILE VERBOSE ANONYMOUS WORD {sgLogFile(SG_BLOCK_ACL,1,1,$4);} 258 | LOGFILE WORD { sgLogFile(SG_BLOCK_ACL,0,0,$2); } 259 ; 260 261access_pass: 262 | access_pass WORD { sgAclSetValue("pass",$2,1);} 263 | access_pass '!' WORD { sgAclSetValue("pass",$3,0);} 264 | access_pass ',' 265 ; 266 267cidr: CIDR { sgIp($1); } 268 ; 269 270ipclass: IPCLASS { sgIp($1); } 271 ; 272ips: 273 | ips ip { sgIp("255.255.255.255") ; sgSetIpType(SG_IPTYPE_HOST,NULL,0); } 274 | ips ip cidr { sgSetIpType(SG_IPTYPE_CIDR,NULL,0); } 275 | ips ip ipclass { sgSetIpType(SG_IPTYPE_CLASS,NULL,0); } 276 | ips ip '-' ip { sgSetIpType(SG_IPTYPE_RANGE,NULL,0); } 277 | ips ',' 278 ; 279 280ip: IPADDR { sgIp($1);} 281 ; 282 283rew: REWRITE WORD { sgRewrite($2); } 284 ; 285 286rew_block: rew start_block rew_contents stop_block 287 ; 288 289rew_contents: 290 | rew_contents rew_content 291 ; 292 293 294rew_content: SUBST { sgRewriteSubstitute($1); } 295 | WITHIN WORD { sgRewriteTime($2,WITHIN); } 296 | OUTSIDE WORD { sgRewriteTime($2,OUTSIDE); } 297 | LOGFILE ANONYMOUS WORD { sgLogFile(SG_BLOCK_REWRITE,1,0,$3); } 298 | LOGFILE VERBOSE WORD { sgLogFile(SG_BLOCK_REWRITE,0,1,$3); } 299 | LOGFILE ANONYMOUS VERBOSE WORD { sgLogFile(SG_BLOCK_REWRITE,1,1,$4); } 300 | LOGFILE VERBOSE ANONYMOUS WORD { sgLogFile(SG_BLOCK_REWRITE,1,1,$4); } 301 | LOGFILE WORD { sgLogFile(SG_BLOCK_REWRITE,0,0,$2); } 302 ; 303 304 305time: TIME WORD { sgTime($2); } 306 ; 307 308time_block: time start_block time_contents stop_block 309 ; 310 311time_contents: 312 | time_contents time_content 313 ; 314 315 316time_content: WEEKLY {sgTimeElementInit();} WORD 317 {sgTimeElementAdd($3,T_WEEKLY);} ttime 318 | WEEKLY {sgTimeElementInit();} WEEKDAY 319 {sgTimeElementAdd($3,T_WEEKDAY);} ttime 320 | DATE {sgTimeElementInit();} date 321 {sgTimeElementEnd();} 322 ; 323 324ttime: ttime { sgTimeElementClone(); } tval '-' tval 325 | tval '-' tval 326 ; 327 328date: dval ttime 329 | dval 330 | dval '-' dval ttime 331 | dval '-' dval 332 | dvalcron ttime 333 | dvalcron 334 ; 335 336dval: DVAL { sgTimeElementAdd($1,T_DVAL);} 337 ; 338 339tval: TVAL { sgTimeElementAdd($1,T_TVAL);} 340 ; 341 342dvalcron: DVALCRON { sgTimeElementAdd($1,T_DVALCRON);} 343 ; 344 345statements: 346 | statements statement 347 ; 348 349statement: 350 destination 351 | source_block 352 | destination_block 353 | dbhome 354 | logdir 355 | ldapprotover 356 | ldapbinddn 357 | ldapbindpass 358 | ldapcachetime 359 | mysqlusername 360 | mysqlpassword 361 | mysqldb 362 | acl_block 363 | rew_block 364 | time_block 365 | NL 366 ; 367 368%% 369 370#if __STDC__ 371void sgReadConfig (char *file) 372#else 373void sgReadConfig (file) 374 char *file; 375#endif 376{ 377 char *defaultFile=DEFAULT_CONFIGFILE; 378 lineno = 1; 379 configFile = file; 380 if(configFile == NULL) 381 configFile = defaultFile; 382 yyin = fopen(configFile,"r"); 383 if(yyin == NULL) 384 sgLogFatalError("%s: can't open configfile %s",progname, configFile); 385 (void)yyparse(); 386 if(defaultAcl == NULL) 387 sgLogFatalError("%s: default acl not defined in configfile %s", 388 progname, configFile); 389 fclose(yyin); 390} 391 392 393/* 394 395 Logfile functions 396 397*/ 398 399#if __STDC__ 400void sgLogFile (int block, int anonymous, int verbose, char *file) 401#else 402void sgLogFile (block, anonymous, verbose, file) 403 int block; 404 int anonymous; 405 int verbose; 406 char *file; 407#endif 408{ 409 void **v; 410 char *name; 411 struct LogFile *p; 412 switch(block){ 413 case(SG_BLOCK_DESTINATION): 414 v = (void **) &lastDest->logfile; 415 name = lastDest->name; 416 break; 417 case(SG_BLOCK_SOURCE): 418 v = (void **) &lastSource->logfile; 419 name = lastSource->name; 420 break; 421 case(SG_BLOCK_REWRITE): 422 v = (void **) &lastRewrite->logfile; 423 name = lastRewrite->name; 424 break; 425 case(SG_BLOCK_ACL): 426 v = (void **) &lastAcl->logfile; 427 name = lastAcl->name; 428 if(strcmp(name,"default")){ 429 sgLogError("logfile not allowed in acl other than default"); 430 } 431 break; 432 default: 433 return; 434 } 435 if(*v == NULL){ 436 p = (struct LogFile *) sgCalloc(1,sizeof(struct LogFile)); 437 p->stat = sgLogFileStat(file); 438 p->parent_name = name; 439 p->parent_type = block; 440 p->anonymous = anonymous; 441 p->verbose = verbose; 442 *v = p; 443 } else { 444 sgLogError("%s: redefine of logfile %s in line %d", 445 progname,file,lineno); 446 return; 447 } 448} 449 450#if __STDC__ 451struct LogFileStat *sgLogFileStat(char *file) 452#else 453struct LogFileStat *sgLogFileStat(file) 454 char *file; 455#endif 456{ 457 struct LogFileStat *sg; 458 struct stat s; 459 char buf[MAX_BUF]; 460 FILE *fd; 461 strncpy(buf,file,MAX_BUF); 462 if(*file != '/'){ 463 if(globalLogDir == NULL) 464 strncpy(buf,DEFAULT_LOGDIR,MAX_BUF); 465 else 466 strncpy(buf,globalLogDir,MAX_BUF); 467 strcat(buf,"/"); 468 strcat(buf,file); 469 } 470 if((fd = fopen(buf, "a")) == NULL){ 471 sgLogError("%s: can't write to logfile %s",progname,buf); 472 return NULL; 473 } 474 if(stat(buf,&s) != 0){ 475 sgLogError("%s: can't stat logfile %s",progname,buf); 476 return NULL; 477 } 478 if(LogFileStat == NULL){ 479 sg = (struct LogFileStat *) sgCalloc(1,sizeof(struct LogFileStat)); 480 sg->name = sgMalloc(strlen(buf) + 1); 481 strcpy(sg->name,buf); 482 sg->st_ino = s.st_ino; 483 sg->st_dev = s.st_dev; 484 sg->fd = fd; 485 sg->next = NULL; 486 LogFileStat = sg; 487 lastLogFileStat = sg; 488 } else { 489 for(sg = LogFileStat; sg != NULL; sg = sg->next){ 490 if(sg->st_ino == s.st_ino && sg->st_dev == s.st_dev){ 491 fclose(fd); 492 return sg; 493 } 494 } 495 sg = (struct LogFileStat *) sgCalloc(1,sizeof(struct LogFileStat)); 496 sg->name = sgMalloc(strlen(buf) + 1); 497 strcpy(sg->name,buf); 498 sg->st_ino = s.st_ino; 499 sg->st_dev = s.st_dev; 500 sg->fd = fd; 501 sg->next = NULL; 502 lastLogFileStat->next = sg; 503 lastLogFileStat = sg; 504 } 505 return lastLogFileStat; 506} 507/* 508 509 Source functions 510 511*/ 512 513#if __STDC__ 514void sgSource(char *source) 515#else 516void sgSource(source) 517 char *source; 518#endif 519{ 520 struct Source *sp; 521 if(Source != NULL){ 522 if((struct Source *) sgSourceFindName(source) != NULL) 523 sgLogFatalError("%s: source %s is defined in configfile %s", 524 progname,source, configFile); 525 } 526 sp = (struct Source *)sgCalloc(1,sizeof(struct Source)); 527 sp->ip=NULL; 528 sp->userDb=NULL; 529 sp->domainDb=NULL; 530 sp->active = 1; 531 sp->within = 0; 532 sp->cont_search = 0; 533 sp->time = NULL; 534 sp->userquota.seconds = 0; 535 sp->userquota.renew = 0; 536 sp->userquota.sporadic = 0; 537 sp->next=NULL; 538 sp->logfile = NULL; 539 sp->name = (char *) sgCalloc(1,strlen(source) + 1); 540 strcpy(sp->name,source); 541 542 if(Source == NULL){ 543 Source = sp; 544 lastSource = sp; 545 } else { 546 lastSource->next = sp; 547 lastSource = sp; 548 } 549} 550 551#ifdef HAVE_LIBLDAP 552void sgSourceEnd() 553{ 554 struct Source *s; 555 s = lastSource; 556 if(s->ip == NULL && s->domainDb == NULL && s->userDb == NULL 557 && s->ldapurlcount == 0){ 558 sgLogError("sourceblock %s missing active content, set inactive",s->name); 559 s->time = NULL; 560 s->active = 0; 561 } 562} 563#else 564void sgSourceEnd() 565{ 566 struct Source *s; 567 s = lastSource; 568 if(s->ip == NULL && s->domainDb == NULL && s->userDb == NULL){ 569 sgLogError("sourceblock %s missing active content, set inactive",s->name); 570 s->time = NULL; 571 s->active = 0; 572 } 573} 574#endif 575 576#if __STDC__ 577void sgSourceUser(char *user) 578#else 579void sgSourceUser(user) 580 char *user; 581#endif 582{ 583 struct Source *sp; 584 char *lc; 585 sp = lastSource; 586 if(sp->userDb == NULL){ 587 sp->userDb = (struct sgDb *) sgCalloc(1,sizeof(struct sgDb)); 588 sp->userDb->type=SGDBTYPE_USERLIST; 589 sgDbInit(sp->userDb,NULL); 590 } 591 for(lc=user; *lc != '\0'; lc++) /* convert username to lowercase chars */ 592 *lc = tolower(*lc); 593 sgDbUpdate(sp->userDb, user, (char *) setuserinfo(), 594 sizeof(struct UserInfo)); 595// DEBUG 596 sgLogError("Added User: %s", user); 597} 598 599#if __STDC__ 600void sgSourceUserList(char *file) 601#else 602void sgSourceUserList(file) 603 char *file; 604#endif 605{ 606 char *dbhome = NULL, *f; 607 FILE *fd; 608 char line[MAX_BUF]; 609 char *p,*c,*s,*lc; 610 int l=0; 611 struct Source *sp; 612 sp = lastSource; 613 if(sp->userDb == NULL){ 614 sp->userDb = (struct sgDb *) sgCalloc(1,sizeof(struct sgDb)); 615 sp->userDb->type=SGDBTYPE_USERLIST; 616 sgDbInit(sp->userDb,NULL); 617 } 618 dbhome = sgSettingGetValue("dbhome"); 619 if(dbhome == NULL) 620 dbhome = DEFAULT_DBHOME; 621 if (file[0] == '/') { 622 f = strdup(file); 623 } else { 624 f = (char *) sgCalloc(1,strlen(dbhome) + strlen(file) + 5); 625 strcpy(f,dbhome); 626 strcat(f,"/"); 627 strcat(f,file); 628 } 629 if((fd = fopen(f,"r")) == NULL){ 630 sgLogError("%s: can't open userlist %s: %s",progname, f,strerror(errno)); 631 return; 632 } 633 while(fgets(line,sizeof(line),fd) != NULL){ 634 l++; 635 if(*line == '#') 636 continue; 637 p = strchr(line,'\n'); 638 if(p != NULL && p != line){ 639 if(*(p - 1) == '\r') /* removing ^M */ 640 p--; 641 *p = '\0'; 642 } 643 c = strchr(line,'#'); 644 p = strtok(line," \t,"); 645 if((s = strchr(line,':')) != NULL){ 646 *s = '\0'; 647 for(lc=line; *lc != '\0'; lc++) /* convert username to lowercase chars */ 648 *lc = tolower(*lc); 649 sgDbUpdate(sp->userDb, line, (char *) setuserinfo(), 650 sizeof(struct UserInfo)); 651 } else { 652 do { 653 if(c != NULL && p >= c) /*find the comment */ 654 break; 655 for(lc=p; *lc != '\0'; lc++) /* convert username to lowercase chars */ 656 *lc = tolower(*lc); 657 sgDbUpdate(sp->userDb, p, (char *) setuserinfo(), 658 sizeof(struct UserInfo)); 659// DEBUG 660 sgLogError("Added UserList source: %s", p); 661 } while((p=strtok(NULL," \t,")) != NULL); 662 } 663 } 664 fclose(fd); 665} 666 667 668/* MySQLsupport */ 669#ifdef HAVE_MYSQL 670#if __STDC__ 671void sgSourceUserQuery(char *query) 672#else 673void sgSourceUserQuery(query) 674 char *query; 675#endif 676{ 677 char *dbhome = NULL, *f; 678 MYSQL *conn; 679 MYSQL_RES *res; 680 MYSQL_ROW *row; 681 char line[MAX_BUF]; 682 char *my_query, *my_user, *my_pass, *my_db; 683 char *str=";"; 684 int l=0; 685 struct Source *sp; 686 sp = lastSource; 687 if(sp->userDb == NULL){ 688 sp->userDb = (struct sgDb *) sgCalloc(1,sizeof(struct sgDb)); 689 sp->userDb->type=SGDBTYPE_USERLIST; 690 sgDbInit(sp->userDb,NULL); 691 } 692 dbhome = sgSettingGetValue("dbhome"); 693 my_user = sgSettingGetValue("mysqlusername"); 694 my_pass = sgSettingGetValue("mysqlpassword"); 695 my_db = sgSettingGetValue("mysqldb"); 696 if(dbhome == NULL) { 697 dbhome = DEFAULT_DBHOME; 698 } 699 if( !(conn = mysql_init(0)) ) { 700 @NOLOG1@ sgLogError("%s: can't open userquery: mysql init",progname); @NOLOG2@ 701 return; 702 } 703 if( ! mysql_real_connect(conn, "localhost", my_user, my_pass, my_db, 704 0,NULL,0) ) { 705 @NOLOG1@ sgLogError("%s: can't open userquery: mysql connect",progname); @NOLOG2@ 706 return; 707 } 708 my_query=(char *)calloc(strlen(query) + strlen(str) + 1,sizeof(char)); 709 strcat(my_query, query); 710 strcat(my_query, str); 711 /* DEBUG: sgLogError("%s: TEST: MySQL Query %s",progname,my_query); */ 712 if( mysql_query(conn, my_query) ) { 713 @NOLOG1@ sgLogError("%s: can't open userquery: mysql query",progname); @NOLOG2@ 714 return; 715 } 716 res = mysql_use_result(conn); 717 while( row = mysql_fetch_row(res) ) { 718 strncpy(line, row[0], sizeof(line)-1); 719 l++; 720 sgDbUpdate(sp->userDb, line, (char *) setuserinfo(), sizeof(struct UserInfo)); 721 sgLogError("Added MySQL source: %s", line); 722 } 723 mysql_free_result(res); 724 mysql_close(conn); 725 } 726#endif 727 728 729/* LDAP Support */ 730#ifdef HAVE_LIBLDAP 731#if __STDC__ 732void sgSourceLdapUserSearch(char *url) 733#else 734void sgSourceLdapUserSearch(url) 735 char *url; 736#endif 737{ 738 struct Source *sp; 739 sp = lastSource; 740 741/* DEBUG 742 sgLogError("sgSourceLdapUserSearch called with: %s", url); 743*/ 744 745 if(!ldap_is_ldap_url(url)) { 746 @NOLOG1@ sgLogError("%s: can't parse LDAP url %s",progname, url); @NOLOG2@ 747 return; 748 } 749 750 /* looks ok, add the url to the source object url array */ 751 sp->ldapurls = (char**) sgRealloc(sp->ldapurls, 752 sizeof(char*) * (sp->ldapurlcount+1)); 753 sp->ldapurls[sp->ldapurlcount] = (char*) sgMalloc(strlen(url) + 1); 754 strcpy(sp->ldapurls[sp->ldapurlcount], url); 755 sp->ldapurlcount++; 756 757 /* create a userDb if it doesn't exist, since we'll need it later 758 * for caching */ 759 if(sp->userDb == NULL){ 760 sp->userDb = (struct sgDb *) sgCalloc(1,sizeof(struct sgDb)); 761 sp->userDb->type=SGDBTYPE_USERLIST; 762 sgDbInit(sp->userDb,NULL); 763 } 764} 765#endif 766 767#if __STDC__ 768void sgSourceExecUserList(char *cmd) 769#else 770void sgSourceExecUserList(cmd) 771 char *cmd; 772#endif 773{ 774 FILE *pInput; 775 char buffer[100]; 776 struct Source *sp; 777 char *lc; 778 sp = lastSource; 779 if(sp->userDb == NULL){ 780 sp->userDb = (struct sgDb *) sgCalloc(1,sizeof(struct sgDb)); 781 sp->userDb->type=SGDBTYPE_USERLIST; 782 sgDbInit(sp->userDb,NULL); 783 } 784 785/* DEBUG 786 sgLogError("sgSourceExecUserList called with: %s", cmd); 787*/ 788 789 pInput = popen(cmd, "r"); 790 if(pInput == NULL) { 791 sgLogError("%s: Unable to run execuserlist command: %s", progname, cmd); 792 return; 793 } 794 795 while(fgets(buffer, sizeof(buffer), pInput) != NULL) { 796 char *sc; 797 /* skip leading whitespace */ 798 for(sc=buffer; *sc != '\0' && isspace(*sc); sc++) 799 ; 800 /* convert username to lowercase */ 801 for(lc=sc; *lc != '\0'; lc++) 802 *lc = tolower(*lc); 803 /* remove newline and trailing whitespace */ 804 while(lc>=sc && (*lc=='\0' || isspace(*lc))) 805 *lc-- = '\0'; 806 if(lc >= sc) { 807 sgDbUpdate(sp->userDb, sc, (char *) setuserinfo(), 808 sizeof(struct UserInfo)); 809// DEBUG 810 sgLogError("Added exec source: %s", sc); 811 } 812 } 813 814 pclose(pInput); 815} 816 817 818 819#if __STDC__ 820void sgSourceUserQuota(char *seconds, char *sporadic, char *renew) 821#else 822void sgSourceUserQuota(seconds, sporadic, renew) 823 char *seconds; 824 char *sporadic; 825 char *renew; 826#endif 827{ 828 int s; 829 struct UserQuota *uq; 830 struct Source *sp; 831 sp = lastSource; 832 uq = &sp->userquota; 833 s = atoi(seconds); 834 if(s <= 0) 835 sgLogError("Userquota seconds sporadic hourly|daily|weekly"); 836 uq->seconds = s; 837 s = atoi(sporadic); 838 if(s <= 0) 839 sgLogError("Userquota seconds sporadic hourly|daily|weekly"); 840 uq->sporadic = s; 841 s = atoi(renew); 842 if(s <= 0) 843 sgLogError("Userquota seconds sporadic hourly|daily|weekly"); 844 uq->renew = s; 845} 846 847 848#if __STDC__ 849void sgSourceDomain(char *domain) 850#else 851void sgSourceDomain(domain) 852 char *domain; 853#endif 854{ 855 struct Source *sp; 856 sp = lastSource; 857 if(sp->domainDb == NULL){ 858 sp->domainDb = (struct sgDb *) sgCalloc(1,sizeof(struct sgDb)); 859 sp->domainDb->type=SGDBTYPE_DOMAINLIST; 860 sgDbInit(sp->domainDb,NULL); 861 } 862 sgDbUpdate(sp->domainDb,domain, NULL, 0); 863} 864 865#if __STDC__ 866void sgSourceTime(char *name, int within) 867#else 868void sgSourceTime(name, within) 869 char *name; 870 int within; 871#endif 872{ 873 struct Time *time = NULL; 874 struct Source *sp; 875 sp = lastSource; 876 if((time = sgTimeFindName(name)) == NULL){ 877 sgLogFatalError("%s: Time %s is not defined in configfile %s", 878 progname,name, configFile); 879 } 880 sp->within = within; 881 sp->time = time; 882} 883 884#if __STDC__ 885struct Source *sgSourceFindName(char *name) 886#else 887struct Source *sgSourceFindName(name) 888 char *name; 889#endif 890{ 891 struct Source *p; 892 for(p=Source; p != NULL; p = p->next){ 893 if(!strcmp(name,p->name)) 894 return p; 895 } 896 return NULL; 897} 898 899#if __STDC__ 900void sgSourceIpList(char *file) 901#else 902void sgSourceIpList(file) 903 char *file; 904#endif 905{ 906 char *dbhome = NULL, *f; 907 FILE *fd; 908 char line[MAX_BUF]; 909 char *p,*c,*cidr; 910 int i,l=0; 911 dbhome = sgSettingGetValue("dbhome"); 912 if(dbhome == NULL) 913 dbhome = DEFAULT_DBHOME; 914 if (file[0] == '/') { 915 f = strdup(file); 916 } else { 917 f = (char *) sgCalloc(1,strlen(dbhome) + strlen(file) + 5); 918 strcpy(f,dbhome); 919 strcat(f,"/"); 920 strcat(f,file); 921 } 922 if((fd = fopen(f,"r")) == NULL){ 923 sgLogError("%s: can't open iplist %s: %s",progname, f,strerror(errno)); 924 return; 925 } 926 sgLogError("init iplist %s",f); 927 while(fgets(line,sizeof(line),fd) != NULL){ 928 l++; 929 if(*line == '#') 930 continue; 931 p = strchr(line,'\n'); 932 if(p != NULL && p != line){ 933 if(*(p - 1) == '\r') /* removing ^M */ 934 p--; 935 *p = '\0'; 936 } 937 c = strchr(line,'#'); 938 p = strtok(line," \t,"); 939 do { 940 if(c != NULL && p >= c) /*find the comment */ 941 break; 942 i=strspn(p,".0123456789/-"); 943 if(i == 0) 944 break; 945 *(p + i ) = '\0'; 946 if((cidr = strchr(p,'/')) != NULL){ 947 *cidr = '\0'; 948 cidr++; 949 sgIp(p); 950 sgIp(cidr); 951 if(strchr(cidr,'.') == NULL) 952 sgSetIpType(SG_IPTYPE_CIDR,f,l); 953 else 954 sgSetIpType(SG_IPTYPE_CLASS,f,l); 955 } else if((cidr = strchr(p,'-')) != NULL) { 956 *cidr = '\0'; 957 cidr++; 958 sgIp(p); 959 sgIp(cidr); 960 sgSetIpType(SG_IPTYPE_RANGE,f,l); 961 } else { 962 sgIp(p); 963 sgIp(strdup("255.255.255.255")); 964 sgSetIpType(SG_IPTYPE_HOST,f,l); 965 } 966 } while((p=strtok(NULL," \t,")) != NULL); 967 } 968 fclose(fd); 969} 970 971/* 972 973 974 */ 975 976#if __STDC__ 977struct Source *sgFindSource (struct Source *bsrc, 978 char *net, char *ident, char *domain) 979#else 980struct Source *sgFindSource (bsrc, net, ident, domain) 981 struct Source *bsrc; 982 char *net; 983 char *ident; 984 char *domain; 985#endif 986{ 987 struct Source *s; 988 struct Ip *ip; 989 int foundip, founduser, founddomain, unblockeduser; 990 unsigned long i, octet = 0, *op; 991 struct UserInfo *userquota; 992 if(net != NULL){ 993 op = sgConvDot(net); 994 if(op != NULL) 995 octet = *op; 996 } 997 for(s=bsrc; s != NULL; s = s->next){ 998 foundip = founduser = founddomain = 0; 999 unblockeduser = 1; 1000 if(s->active == 0) 1001 continue; 1002 if(s->ip != NULL){ 1003 if(net == NULL) 1004 foundip = 0; 1005 else { 1006 for(ip=s->ip; ip != NULL; ip = ip->next){ 1007 if(ip->net_is_set == 0) 1008 continue; 1009 if(ip->type == SG_IPTYPE_RANGE){ 1010 if(octet >= ip->net && octet <= ip->mask){ 1011 foundip = 1; 1012 break; 1013 } 1014 } else { /* CIDR or HOST */ 1015 i = octet & ip->mask; 1016 if(i == ip->net){ 1017 foundip = 1; 1018 break; 1019 } 1020 } 1021 } 1022 } 1023 } else 1024 foundip = 1; 1025 if(s->userDb != NULL){ 1026 if(*ident == '\0') 1027 founduser = 0; 1028 else { 1029#ifdef HAVE_LIBLDAP 1030 if(sgFindUser(s, ident, &userquota)) { 1031#else 1032 rfc1738_unescape(ident); 1033 if(defined(s->userDb, ident, (char **) &userquota) == 1){ 1034#endif 1035 founduser = 1; 1036 unblockeduser = 1; 1037 if(s->userquota.seconds != 0){ 1038 struct UserInfo uq; 1039 time_t t = time(NULL) + globalDebugTimeDelta; 1040 //sgLogError("status %d time %d lasttime %d consumed %d", userquota->status, userquota->time, userquota->last, userquota->consumed); 1041 //sgLogError("renew %d seconds %d", s->userquota.renew, s->userquota.seconds); 1042 if(userquota->status == 0){ //first time 1043 userquota->status = 1; 1044 userquota->time = t; 1045 userquota->last = t; 1046 //sgLogError("user %s first time %d", ident, userquota->time); 1047 } else if(userquota->status == 1){ 1048 //sgLogError("user %s other time %d %d",ident,userquota->time,t); 1049 if(s->userquota.sporadic > 0){ 1050 if(t - userquota->last < s->userquota.sporadic){ 1051 userquota->consumed += t - userquota->last; 1052 userquota->time = t; 1053 } 1054 if(userquota->consumed > s->userquota.seconds){ 1055 userquota->status = 2; // block this user, time is up 1056 unblockeduser = 0; 1057 } 1058 userquota->last = t; 1059 //sgLogError("user %s consumed %d %d",ident,userquota->consumed, userquota->last); 1060 } else if(userquota->time + s->userquota.seconds < t){ 1061 sgLogError("time is up user %s blocket", ident); 1062 userquota->status = 2; // block this user, time is up 1063 unblockeduser = 0; 1064 } 1065 } else { 1066 //sgLogError("user %s blocket %d %d %d %d", ident, userquota->status, userquota->time, t, (userquota->time + s->userquota.renew) - t); 1067 if(userquota->time + s->userquota.renew < t){ // new chance 1068 //sgLogError("user %s new chance", ident); 1069 unblockeduser = 1; 1070 userquota->status = 1; 1071 userquota->time = t; 1072 userquota->consumed = 0; 1073 } else 1074 unblockeduser = 0; 1075 } 1076 sgDbUpdate(s->userDb, ident, (void *) userquota, 1077 sizeof(struct UserInfo)); 1078 } 1079 } 1080 } 1081 } else 1082 founduser = 1; 1083 if(s->domainDb != NULL){ 1084 if(*domain == '\0') 1085 founddomain = 0; 1086 else { 1087 if(defined(s->domainDb, domain, (char **) NULL) == 1) 1088 founddomain = 1; 1089 } 1090 } else 1091 founddomain = 1; 1092 if(founduser && foundip && founddomain){ 1093 if(unblockeduser) 1094 return s; 1095 else { 1096 lastActiveSource = s; 1097 return NULL; 1098 } 1099 } 1100 } 1101 return NULL; 1102} 1103 1104 1105 1106/*destination block funtions */ 1107 1108#if __STDC__ 1109void sgDest(char *dest) 1110#else 1111void sgDest(dest) 1112 char *dest; 1113#endif 1114{ 1115 struct Destination *sp; 1116 if(Dest != NULL){ 1117 if((struct Destination *) sgDestFindName(dest) != NULL) 1118 sgLogFatalError("%s: destination %s is defined in configfile %s", 1119 progname,dest, configFile); 1120 } 1121 sp = (struct Destination *) sgCalloc(1,sizeof(struct Destination)); 1122 sp->domainlist=NULL; 1123 sp->urllist=NULL; 1124 sp->expressionlist=NULL; 1125 sp->redirect=NULL; 1126 sp->rewrite=NULL; 1127 sp->active = 1; 1128 sp->time = NULL; 1129 sp->within = 0; 1130 sp->logfile = NULL; 1131 sp->next=NULL; 1132 sp->name = (char *) sgCalloc(1,strlen(dest) + 1); 1133 strcpy(sp->name,dest); 1134 1135 if(Dest == NULL){ 1136 Dest = sp; 1137 lastDest = sp; 1138 } else { 1139 lastDest->next = sp; 1140 lastDest = sp; 1141 } 1142} 1143 1144void sgDestEnd() 1145{ 1146 struct Destination *d; 1147 d = lastDest; 1148 if(d->domainlist == NULL && d->urllist == NULL && d->expressionlist == NULL 1149 && d->redirect == NULL && d->rewrite == NULL){ 1150 sgLogError("destblock %s missing active content, set inactive",d->name); 1151 d->time = NULL; 1152 d->active = 0; 1153 } 1154} 1155 1156#if __STDC__ 1157void sgDestDomainList(char *domainlist) 1158#else 1159void sgDestDomainList(domainlist) 1160 char *domainlist; 1161#endif 1162{ 1163 struct Destination *sp; 1164 char *dbhome = NULL, *dl = domainlist, *name; 1165 dbhome = sgSettingGetValue("dbhome"); 1166 sp = lastDest; 1167 if(dbhome == NULL) 1168 dbhome = DEFAULT_DBHOME; 1169 if(domainlist == NULL){ 1170 name = sp->name; 1171 dl = (char *) sgCalloc(1,strlen("/dest/") + strlen(name) + strlen("/domainlist")); 1172 strcpy(dl,"/dest/"); 1173 strcat(dl,name); 1174 strcat(dl,"/domainlist"); 1175 sp->domainlist = (char *) sgCalloc(1,strlen(dbhome) + strlen("/") + strlen(dl) + 4); 1176 strcpy(sp->domainlist,dbhome); 1177 strcat(sp->domainlist,"/"); 1178 strcat(sp->domainlist,dl); 1179 sgFree(dl); 1180 } else { 1181 if (domainlist[0] == '/') { 1182 sp->domainlist = strdup(domainlist); 1183 } else { 1184 sp->domainlist = (char *) sgCalloc(1,strlen(dbhome) + strlen("/") + strlen(domainlist) + 4); 1185 strcpy(sp->domainlist,dbhome); 1186 strcat(sp->domainlist,"/"); 1187 strcat(sp->domainlist,domainlist); 1188 } 1189 } 1190 sp->domainlistDb = (struct sgDb *) sgCalloc(1,sizeof(struct sgDb)); 1191 sp->domainlistDb->type=SGDBTYPE_DOMAINLIST; 1192 sgLogError("init domainlist %s",sp->domainlist); 1193 sgDbInit(sp->domainlistDb,sp->domainlist); 1194 if(sp->domainlistDb->entries == 0) { /* empty database */ 1195 sgLogError("domainlist empty, removed from memory"); 1196 sgFree(sp->domainlistDb); 1197 sp->domainlistDb = NULL; 1198 } 1199} 1200 1201#if __STDC__ 1202void sgDestUrlList(char *urllist) 1203#else 1204void sgDestUrlList(urllist) 1205 char *urllist; 1206#endif 1207{ 1208 struct Destination *sp; 1209 char *dbhome = NULL, *dl = urllist, *name; 1210 dbhome = sgSettingGetValue("dbhome"); 1211 sp = lastDest; 1212 if(dbhome == NULL) 1213 dbhome = DEFAULT_DBHOME; 1214 if(urllist == NULL){ 1215 name = sp->name; 1216 dl = (char *) sgCalloc(1,strlen("/dest/") + strlen(name) + strlen("/urllist")); 1217 strcpy(dl,"/dest/"); 1218 strcat(dl,name); 1219 strcat(dl,"/urllist"); 1220 sp->urllist = (char *) sgCalloc(1,strlen(dbhome) + strlen("/") + strlen(dl) + 4); 1221 strcpy(sp->urllist,dbhome); 1222 strcat(sp->urllist,"/"); 1223 strcat(sp->urllist,dl); 1224 sgFree(dl); 1225 } else { 1226 if (urllist[0] == '/') { 1227 sp->urllist = strdup(urllist); 1228 } else { 1229 sp->urllist = (char *) sgCalloc(1,strlen(dbhome) + strlen("/") + strlen(urllist) + 4); 1230 strcpy(sp->urllist,dbhome); 1231 strcat(sp->urllist,"/"); 1232 strcat(sp->urllist,urllist); 1233 } 1234 } 1235 sp->urllistDb = (struct sgDb *) sgCalloc(1,sizeof(struct sgDb)); 1236 sp->urllistDb->type=SGDBTYPE_URLLIST; 1237 sgLogError("init urllist %s",sp->urllist); 1238 sgDbInit(sp->urllistDb,sp->urllist); 1239 if(sp->urllistDb->entries == 0) { /* empty database */ 1240 sgLogError("urllist empty, removed from memory"); 1241 sgFree(sp->urllistDb); 1242 sp->urllistDb = NULL; 1243 } 1244} 1245 1246#if __STDC__ 1247void sgDestExpressionList(char *exprlist, char *chcase) 1248#else 1249void sgDestExpressionList(exprlist, chcase) 1250 char *exprlist; 1251 char *chcase; 1252#endif 1253{ 1254 FILE *fp; 1255 char buf[MAX_BUF],errbuf[256]; 1256 struct Destination *sp; 1257 struct sgRegExp *regexp; 1258 char *dbhome = NULL, *dl = exprlist, *name, *p; 1259 int flags = REG_EXTENDED; 1260 dbhome = sgSettingGetValue("dbhome"); 1261 sp = lastDest; 1262 if(dbhome == NULL) 1263 dbhome = DEFAULT_DBHOME; 1264 if(exprlist == NULL){ 1265 name = sp->name; 1266 dl = (char *) sgCalloc(1,strlen("/dest/") +strlen(name) + strlen("/expressionlist")); 1267 strcpy(dl,"/dest/"); 1268 strcat(dl,name); 1269 strcat(dl,"/expressionlist"); 1270 flags |= REG_ICASE; /* default case insensitive */ 1271 sp->expressionlist = (char *) sgCalloc(1,strlen(dbhome)+strlen(dl)+10); 1272 strcpy(sp->expressionlist,dbhome); 1273 strcat(sp->expressionlist,"/"); 1274 strcat(sp->expressionlist,dl); 1275 sgFree(dl); 1276 } else { 1277 if (exprlist[0] == '/') { 1278 sp->expressionlist = strdup(exprlist); 1279 } else { 1280 sp->expressionlist = (char *) sgCalloc(1,strlen(dbhome) + strlen("/") + strlen(exprlist) + 4); 1281 strcpy(sp->expressionlist,dbhome); 1282 strcat(sp->expressionlist,"/"); 1283 strcat(sp->expressionlist,exprlist); 1284 } 1285 if(strncmp(chcase,"c",1)) 1286 flags |= REG_ICASE; /* set case insensitive */ 1287 } 1288 sgLogError("init expressionlist %s",sp->expressionlist); 1289 if ((fp = fopen(sp->expressionlist, "r")) == NULL) 1290 sgLogFatalError("%s: %s", sp->expressionlist, strerror(errno)); 1291 while(fgets(buf, sizeof(buf), fp) != NULL){ 1292 p = (char *) strchr(buf,'\n'); 1293 if(p != NULL && p != buf){ 1294 if(*(p - 1) == '\r') /* removing ^M */ 1295 p--; 1296 *p = '\0'; 1297 } 1298 regexp=sgNewPatternBuffer(buf,flags); 1299 if(regexp->error){ 1300 regerror(regexp->error,regexp->compiled, errbuf,sizeof(errbuf)); 1301 sgLogError("%s: %s", sp->expressionlist, strerror(errno)); 1302 } 1303 if(lastDest->regExp == NULL){ 1304 lastDest->regExp = regexp; 1305 lastRegExpDest = regexp; 1306 } else { 1307 lastRegExpDest->next = regexp; 1308 lastRegExpDest = regexp; 1309 } 1310 } 1311 fclose(fp); 1312} 1313 1314#if __STDC__ 1315void sgDestRedirect(char *value) 1316#else 1317void sgDestRedirect(value) 1318 char *value; 1319#endif 1320{ 1321 struct Destination *sp; 1322 sp = lastDest; 1323 sp->redirect = (char *) sgCalloc(1,strlen(value) + 1); 1324 strcpy(sp->redirect,value); 1325} 1326 1327void sgDestRewrite(char *value){ 1328 struct sgRewrite *rewrite = NULL; 1329 struct Destination *sp; 1330 sp = lastDest; 1331 if((rewrite = sgRewriteFindName(value)) == NULL){ 1332 sgLogFatalError("%s: Rewrite %s is not defined in configfile %s", 1333 progname,value, configFile); 1334 } 1335 sp->rewrite = rewrite; 1336} 1337 1338#if __STDC__ 1339int sgRegExpMatch(struct sgRegExp *regexp, char *str) 1340#else 1341int sgRegExpMatch(regexp, str) 1342 struct sgRegExp *regexp; 1343 char *str; 1344#endif 1345{ 1346 struct sgRegExp *rp; 1347 static char errbuf[256]; 1348 int error; 1349 for(rp = regexp; rp != NULL; rp = rp->next){ 1350 error = regexec(rp->compiled, str, 0,0,0); 1351 if(error != 0 && error != REG_NOMATCH) { 1352 regerror(error,rp->compiled, errbuf,sizeof(errbuf)); 1353 sgLogError("Error in regex %30.30s %-60.60s %d %s\n",rp->pattern,str,error,errbuf); 1354 } 1355 if(error == 0) /* match */ 1356 return 1; 1357 } 1358 return 0; 1359} 1360 1361#if __STDC__ 1362void sgDestTime(char *name, int within) 1363#else 1364void sgDestTime(name, within) 1365 char *name; 1366 int within; 1367#endif 1368{ 1369 struct Time *time = NULL; 1370 struct Destination *sp; 1371 sp = lastDest; 1372 if((time = sgTimeFindName(name)) == NULL){ 1373 sgLogFatalError("%s: Time %s is not defined in configfile %s", 1374 progname,name, configFile); 1375 } 1376 sp->within = within; 1377 sp->time = time; 1378} 1379 1380#if __STDC__ 1381struct Destination *sgDestFindName(char *name) 1382#else 1383struct Destination *sgDestFindName(name) 1384 char *name; 1385#endif 1386{ 1387 struct Destination *p; 1388 for(p=Dest; p != NULL; p = p->next){ 1389 if(!strcmp(name,p->name)) 1390 return p; 1391 } 1392 return NULL; 1393} 1394 1395/* 1396 Setting functions 1397*/ 1398 1399 1400#if __STDC__ 1401void sgSetting(char *name, char *value) 1402#else 1403void sgSetting(name, value) 1404 char *name; 1405 char *value; 1406#endif 1407{ 1408 struct Setting *sp; 1409 if(Setting != NULL){ 1410 if((struct Setting *) sgSettingFindName(name) != NULL) 1411 sgLogFatalError("%s: setting %s is defined in configfile %s", 1412 progname,name, configFile); 1413 } 1414 sp = (struct Setting *) sgCalloc(1,sizeof(struct Setting)); 1415 1416 sp->name = strdup(name); 1417 sp->value = strdup(value); 1418 1419// DEBUG 1420 sgLogError("New setting: %s: %s", name, value); 1421 1422 1423 if(Setting == NULL){ 1424 Setting = sp; 1425 lastSetting = sp; 1426 } else { 1427 lastSetting->next = sp; 1428 lastSetting = sp; 1429 } 1430 if(!strcmp(name,"logdir")){ 1431 globalLogDir= strdup(value); 1432 } 1433} 1434 1435#if __STDC__ 1436struct Setting *sgSettingFindName(char *name) 1437#else 1438struct Setting *sgSettingFindName(name) 1439 char *name; 1440#endif 1441{ 1442 struct Setting *p; 1443 for(p=Setting; p != NULL; p = p->next){ 1444 if(!strcmp(name,p->name)) 1445 return p; 1446 } 1447 return NULL; 1448} 1449 1450 1451#if __STDC__ 1452char *sgSettingGetValue(char *name) 1453#else 1454char *sgSettingGetValue(name) 1455 char *name; 1456#endif 1457{ 1458 struct Setting *p; 1459 p = sgSettingFindName(name); 1460 if(p != NULL) 1461 return p->value; 1462 return NULL; 1463} 1464 1465 1466/* 1467 1468 sgRewrite function 1469 1470 */ 1471 1472#if __STDC__ 1473void sgRewrite(char *rewrite) 1474#else 1475void sgRewrite(rewrite) 1476 char *rewrite; 1477#endif 1478{ 1479 struct sgRewrite *rew; 1480 if(Rewrite != NULL){ 1481 if((struct sgRewrite *) sgRewriteFindName(rewrite) != NULL) 1482 sgLogFatalError("%s: rewrite %s is defined in configfile %s", 1483 progname,rewrite, configFile); 1484 } 1485 rew = (struct sgRewrite *) sgCalloc(1,sizeof(struct sgRewrite)); 1486 rew->name = strdup(rewrite); 1487 rew ->rewrite = NULL; 1488 rew->logfile = NULL; 1489 rew->time = NULL; 1490 rew->active = 1; 1491 rew->within = 0; 1492 rew->next=NULL; 1493 1494 if(Rewrite == NULL){ 1495 Rewrite = rew; 1496 lastRewrite = rew; 1497 } else { 1498 lastRewrite->next = rew; 1499 lastRewrite = rew; 1500 } 1501} 1502 1503#if __STDC__ 1504void sgRewriteTime(char *name, int within) 1505#else 1506void sgRewriteTime(name, within) 1507 char *name; 1508 int within; 1509#endif 1510{ 1511 struct Time *time = NULL; 1512 struct sgRewrite *sp; 1513 sp = lastRewrite; 1514 if((time = sgTimeFindName(name)) == NULL){ 1515 sgLogFatalError("%s: Time %s is not defined in configfile %s", 1516 progname,name, configFile); 1517 } 1518 sp->within = within; 1519 sp->time = time; 1520} 1521 1522#if __STDC__ 1523void sgRewriteSubstitute (char *string) 1524#else 1525void sgRewriteSubstitute (string) 1526 char *string; 1527#endif 1528{ 1529 char *pattern, *subst = NULL , *p; 1530 int flags = REG_EXTENDED ; 1531 int global = 0; 1532 char *httpcode = NULL; 1533 struct sgRegExp *regexp; 1534 char errbuf[256]; 1535 pattern = string + 2 ; /* skipping s@ */ 1536 p = pattern; 1537 while((p = strchr(p,'@')) != NULL){ 1538 if(*( p - 1) != '\\'){ 1539 *p = '\0'; 1540 subst = p + 1; 1541 break; 1542 } 1543 p++; 1544 } 1545 p= strrchr(subst,'@'); 1546 while(p != NULL && *p != '\0'){ 1547 if(*p == 'r' ) 1548 httpcode = REDIRECT_TEMPORARILY; 1549 if(*p == 'R' ) 1550 httpcode = REDIRECT_PERMANENT; 1551 if(*p == 'i' || *p == 'I') 1552 flags |= REG_ICASE; 1553 if(*p == 'g') 1554 global = 1; 1555 *p = '\0'; /*removes @i from string */ 1556 p++; 1557 } 1558 regexp=sgNewPatternBuffer(pattern,flags); 1559 if(regexp->error){ 1560 regerror(regexp->error,regexp->compiled, errbuf,sizeof(errbuf)); 1561 sgLogError("Error in regexp %s: %s",pattern,errbuf); 1562 } else { 1563 regexp->substitute = strdup(subst); 1564 } 1565 if(lastRewrite->rewrite == NULL) 1566 lastRewrite->rewrite = regexp; 1567 else 1568 lastRewriteRegExec->next=regexp; 1569 regexp->httpcode = httpcode; 1570 regexp->global = global; 1571 lastRewriteRegExec = regexp; 1572} 1573 1574#if __STDC__ 1575char *sgRewriteExpression(struct sgRewrite *rewrite, char *subst) 1576#else 1577char *sgRewriteExpression(rewrite, subst) 1578 struct sgRewrite *rewrite; 1579 char *subst; 1580#endif 1581{ 1582 char *result = NULL; 1583 result = sgRegExpSubst(rewrite->rewrite, subst); 1584 return result; 1585} 1586 1587#if __STDC__ 1588struct sgRewrite *sgRewriteFindName(char *name) 1589#else 1590struct sgRewrite *sgRewriteFindName(name) 1591 char *name; 1592#endif 1593{ 1594 struct sgRewrite *p; 1595 for(p=Rewrite; p != NULL; p = p->next){ 1596 if(!strcmp(name,p->name)) 1597 return p; 1598 } 1599 return NULL; 1600} 1601 1602 1603 1604/* 1605 Time functions 1606*/ 1607 1608#if __STDC__ 1609void sgTime(char *name) 1610#else 1611void sgTime(name) 1612 char *name; 1613#endif 1614{ 1615 struct Time *t; 1616 if(Time != NULL){ 1617 if((struct Time *) sgTimeFindName(name) != NULL) 1618 sgLogFatalError("%s: time %s is defined in configfile %s", 1619 progname,name, configFile); 1620 } else 1621 numTimeElements = 0; 1622 t = (struct Time *) sgCalloc(1,sizeof(struct Time)); 1623 t->name = strdup(name); 1624 t->element = NULL; 1625 t->active = 1; 1626 TimeElement = NULL; 1627 lastTimeElement = NULL; 1628 if(Time == NULL){ 1629 Time = t; 1630 lastTime = t; 1631 } else { 1632 lastTime->next = t; 1633 lastTime = t; 1634 } 1635} 1636 1637#if __STDC__ 1638void sgTimeElementInit() 1639#else 1640void sgTimeElementInit() 1641#endif 1642{ 1643 struct TimeElement *te; 1644 te = (struct TimeElement *) sgCalloc(1,sizeof(struct TimeElement)); 1645 numTimeElements++; 1646 if(lastTime->element == NULL) 1647 lastTime->element = te; 1648 if(lastTimeElement != NULL) 1649 lastTimeElement->next = te; 1650 lastTimeElement = te; 1651} 1652 1653#if __STDC__ 1654void sgTimeElementEnd () 1655#else 1656void sgTimeElementEnd () 1657#endif 1658{ 1659 time_switch = 0; 1660 date_switch = 0; 1661 if(lastTimeElement->fromdate !=0){ 1662 if(lastTimeElement->todate == 0) 1663 lastTimeElement->todate = lastTimeElement->fromdate + 86399; 1664 else 1665 lastTimeElement->todate = lastTimeElement->todate + 86399; 1666 } 1667 if(lastTimeElement->from == 0 && lastTimeElement->to == 0) 1668 lastTimeElement->to = 1439; /* set time to 23:59 */ 1669} 1670 1671#if __STDC__ 1672void sgTimeElementAdd (char *element, char type) 1673#else 1674void sgTimeElementAdd (element, type) 1675 char *element; 1676 char type; 1677#endif 1678{ 1679 struct TimeElement *te; 1680 char *p; 1681 char wday = 0; 1682 int h,m,Y,M = 0,D = -1; 1683 time_t sec; 1684 te = lastTimeElement; 1685 switch(type) { 1686 case T_WEEKDAY: 1687 p = strtok(element," \t,"); 1688 do { 1689 if(*p == '*'){ 1690 wday = 127; 1691 } else if(!strncmp(p,"sun",3)){ 1692 wday = wday | 0x01; 1693 } else if(!strncmp(p,"mon",3)){ 1694 wday = wday | 0x02; 1695 } else if(!strncmp(p,"tue",3)){ 1696 wday = wday | 0x04; 1697 } else if(!strncmp(p,"wed",3)){ 1698 wday = wday | 0x08; 1699 } else if(!strncmp(p,"thu",3)){ 1700 wday = wday | 0x10; 1701 } else if(!strncmp(p,"fri",3)){ 1702 wday = wday | 0x20; 1703 } else if(!strncmp(p,"sat",3)){ 1704 wday = wday | 0x40; 1705 } 1706 p=strtok(NULL," \t,"); 1707 } while(p != NULL); 1708 te->wday = wday; 1709 break; 1710 case T_TVAL: 1711 sscanf(element,"%d:%d",&h,&m); 1712 if((h < 0 && h > 24) && (m < 0 && m > 59)) 1713 sgLogFatalError("%s: time formaterror in %s line %d", 1714 progname, configFile,lineno); 1715 if(time_switch == 0){ 1716 time_switch++; 1717 te->from = (h * 60) + m ; 1718 } else { 1719 time_switch=0; 1720 te->to = (h * 60) + m ; 1721 } 1722 break; 1723 case T_DVAL: 1724 sec = date2sec(element); 1725 if(sec == -1){ 1726 sgLogFatalError("%s: date formaterror in %s line %d", 1727 progname, configFile,lineno); 1728 } 1729 if(date_switch == 0){ 1730 date_switch++; 1731 te->fromdate = sec; 1732 } else { 1733 date_switch=0; 1734 te->todate = sec; 1735 } 1736 break; 1737 case T_DVALCRON: 1738 p = strtok(element,"-."); 1739 Y = atoi(p); 1740 if(*p == '*') 1741 Y = -1; 1742 else 1743 Y = atoi(p); 1744 while((p=strtok(NULL,"-.")) != NULL){ 1745 if(*p == '*') 1746 if(M == 0) 1747 M = -1; 1748 else 1749 D = -1; 1750 else 1751 if(M == 0) 1752 M = atoi(p); 1753 else 1754 D = atoi(p); 1755 } 1756 te->y=Y; te->m=M; te->d=D; 1757 break; 1758 case T_WEEKLY: 1759 p = element; 1760 while(*p != '\0'){ 1761 switch(*p){ 1762 case 'S': 1763 case 's': 1764 wday = wday | 0x01; 1765 break; 1766 case 'M': 1767 case 'm': 1768 wday = wday | 0x02; 1769 break; 1770 case 'T': 1771 case 't': 1772 wday = wday | 0x04; 1773 break; 1774 case 'W': 1775 case 'w': 1776 wday = wday | 0x08; 1777 break; 1778 case 'H': 1779 case 'h': 1780 wday = wday | 0x10; 1781 break; 1782 case 'F': 1783 case 'f': 1784 wday = wday | 0x20; 1785 break; 1786 case 'A': 1787 case 'a': 1788 wday = wday | 0x40; 1789 break; 1790 default: 1791 sgLogFatalError("%s: weekday formaterror in %s line %d", 1792 progname, configFile,lineno); 1793 break; 1794 } 1795 p++; 1796 } 1797 te->wday = wday; 1798 break; 1799 } 1800} 1801 1802 1803#if __STDC__ 1804struct Time *sgTimeFindName(char *name) 1805#else 1806struct Time *sgTimeFindName(name) 1807 char *name; 1808#endif 1809{ 1810 struct Time *p; 1811 for(p=Time; p != NULL; p = p->next){ 1812 if(!strcmp(name,p->name)) 1813 return p; 1814 } 1815 return NULL; 1816} 1817 1818#if __STDC__ 1819int sgTimeCmp(const int *a, const int *b) 1820#else 1821int sgTimeCmp(a, b) 1822 const int *a; 1823 const int *b; 1824#endif 1825{ 1826 return *a - *b; 1827} 1828 1829#if __STDC__ 1830void sgTimeElementSortEvents() 1831#else 1832void sgTimeElementSortEvents() 1833#endif 1834{ 1835 struct Time *p; 1836 struct TimeElement *te; 1837 int i = 0,j; 1838 int *t; 1839 if(Time != NULL){ 1840 TimeElementsEvents = (int *) sgCalloc(numTimeElements * 2 , sizeof(int)); 1841 t = (int *) sgCalloc(numTimeElements * 2, sizeof(int)); 1842 for(p = Time; p != NULL; p = p->next){ 1843 for(te = p->element; te != NULL; te = te->next){ 1844 TimeElementsEvents[i++]= te->from == 0 ? 1440 : te->from; 1845 TimeElementsEvents[i++]= te->to == 0 ? 1440 : te->to; 1846 } 1847 } 1848 qsort(TimeElementsEvents,numTimeElements * 2,sizeof(int), 1849 (void *) &sgTimeCmp); 1850 for(i=0,j=0; i < numTimeElements * 2; i++){ 1851 if(j==0){ 1852 t[j++] = TimeElementsEvents[i]; 1853 } else { 1854 if(t[j-1] != TimeElementsEvents[i]){ 1855 t[j++]=TimeElementsEvents[i]; 1856 } 1857 } 1858 } 1859 sgFree(TimeElementsEvents); 1860 numTimeElements = j; 1861 TimeElementsEvents = t; 1862 } 1863} 1864 1865#if __STDC__ 1866int sgTimeNextEvent() 1867#else 1868int sgTimeNextEvent() 1869#endif 1870{ 1871 time_t t; 1872 struct tm *lt; 1873 int m = 0; 1874 static int lastval= 0; 1875 static int index = 0; 1876#if HAVE_SIGACTION 1877 struct sigaction act; 1878#endif 1879 if(Time == NULL) 1880 return 0; 1881 t = time(NULL) + globalDebugTimeDelta; 1882 1883 lt = localtime(&t); 1884 m = (lt->tm_hour * 60) + lt->tm_min ; 1885 1886 for(index=0; index < numTimeElements; index++){ 1887 if(TimeElementsEvents[index] >= m){ 1888 break; 1889 } 1890 } 1891 lastval = TimeElementsEvents[index]; 1892#if HAVE_SIGACTION 1893#ifndef SA_NODEFER 1894#define SA_NODEFER 0 1895#endif 1896 act.sa_handler = sgAlarm; 1897 act.sa_flags = SA_NODEFER | SA_RESTART; 1898 sigaction(SIGALRM, &act, NULL); 1899#else 1900#if HAVE_SIGNAL 1901 signal(SIGALRM, &sgAlarm); 1902#else 1903#endif 1904#endif 1905 if(lastval < m ) 1906 m = (((1440 - m ) + lastval) * 60) - lt->tm_sec; 1907 else 1908 m = ((lastval - m) * 60) - lt->tm_sec; 1909 if(m <= 0) 1910 m = 30; 1911@NOLOG1@ sgLogError("Info: recalculating alarm in %d seconds", (unsigned int)m); @NOLOG2@ 1912 alarm((unsigned int) m); 1913 sgTimeCheck(lt,t); 1914 sgTimeSetAcl(); 1915 return 0; 1916} 1917 1918#if __STDC__ 1919int sgTimeCheck(struct tm *lt, time_t t) 1920#else 1921int sgTimeCheck(lt, t) 1922 struct tm *lt; 1923 time_t t; 1924#endif 1925{ 1926 struct Time *sg; 1927 struct TimeElement *te; 1928 int min; 1929 if(Time == NULL) 1930 return -1; 1931 for(sg = Time; sg != NULL; sg = sg->next){ 1932 sg->active = 0; 1933 for(te = sg->element; te != NULL ; te = te->next){ 1934 if(te->wday != 0){ 1935 if(((1 << lt->tm_wday ) & te->wday) != 0) { 1936 min = (lt->tm_hour * 60 ) + lt->tm_min; 1937 if(min >= te->from && min < te->to){ 1938 sg->active = 1; 1939 break; 1940 } 1941 } 1942 } else { /* date */ 1943 if(te->fromdate != 0){ 1944 if(t >= te->fromdate && t <= te->todate){ 1945 min = (lt->tm_hour * 60 ) + lt->tm_min; 1946 if(min >= te->from && min < te->to){ 1947 sg->active =1; 1948 break; 1949 } 1950 } 1951 } else { /* cron */ 1952 if(te->y == -1 || te->y == (lt->tm_year + 1900)){ 1953 if(te->m == -1 || te->m == (lt->tm_mon + 1)){ 1954 if(te->d == -1 || te->d == (lt->tm_mday)){ 1955 min = (lt->tm_hour * 60 ) + lt->tm_min; 1956 if(min >= te->from && min < te->to){ 1957 sg->active =1; 1958 break; 1959 } 1960 } 1961 } 1962 } 1963 } 1964 } 1965 } 1966 } 1967 return 0; 1968} 1969 1970void sgTimeSetAcl() 1971{ 1972 struct Acl *acl = defaultAcl; 1973 struct Destination *d; 1974 struct Source *s; 1975 struct sgRewrite *rew; 1976 for(acl=Acl; acl != NULL; acl = acl->next){ 1977 if(acl->time != NULL){ 1978 acl->active = acl->time->active; 1979 if(acl->within == OUTSIDE){ 1980 if(acl->active){ 1981 acl->active = 0; 1982 } 1983 else { 1984 acl->active = 1; 1985 } 1986 } 1987 if(acl->next != NULL && acl->next->within == ELSE){ 1988 if(acl->active == 0){ 1989 acl->next->active = 1; 1990 } else { 1991 acl->next->active = 0; 1992 } 1993 } 1994 } 1995 } 1996 for(d = Dest; d != NULL; d = d->next){ 1997 if(d->time != NULL){ 1998 d->active = d->time->active; 1999 if(d->within == OUTSIDE){ 2000 if(d->active){ 2001 d->active = 0; 2002 } else { 2003 d->active = 1; 2004 } 2005 } 2006 } 2007 } 2008 for(s = Source; s != NULL; s = s->next){ 2009 if(s->time != NULL){ 2010 s->active = s->time->active; 2011 if(s->within == OUTSIDE){ 2012 if(s->active){ 2013 s->active = 0; 2014 } 2015 else { 2016 s->active = 1; 2017 } 2018 } 2019 } 2020 } 2021 for(rew = Rewrite; rew != NULL; rew = rew->next){ 2022 if(rew->time != NULL){ 2023 rew->active = rew->time->active; 2024 if(rew->within == OUTSIDE) 2025 if(rew->active) 2026 rew->active = 0; 2027 else 2028 rew->active = 1; 2029 } 2030 } 2031} 2032 2033void sgTimeElementClone() { 2034 struct TimeElement *te = lastTimeElement, *tmp; 2035 if ( lastTimeElement == NULL ) { 2036 sgLogFatalError("No prev TimeElement in sgTimeElementClone !"); 2037 } else { 2038 sgTimeElementInit(); 2039 lastTimeElement->wday = te->wday; 2040 lastTimeElement->from = te->from; 2041 lastTimeElement->to = te->to; 2042 lastTimeElement->y = te->y; 2043 lastTimeElement->m = te->m; 2044 lastTimeElement->d = te->d; 2045 lastTimeElement->fromdate = te->fromdate; 2046 lastTimeElement->todate = te->todate; 2047 tmp = lastTimeElement; 2048 lastTimeElement = te; 2049 sgTimeElementEnd(); 2050 lastTimeElement = tmp; 2051 } 2052} 2053 2054void sgTimePrint() { 2055 struct Time *t; 2056 struct TimeElement *te; 2057 for(t = Time; t != NULL; t = t->next){ 2058 printf("Time %s is ",t->name); 2059 t->active ? printf("active\n") : printf("inactive\n"); 2060 for(te = t->element; te != NULL; te = te->next){ 2061 printf("\tte->wday = %x\n",te->wday); 2062 printf("\tte->from = %d\n",te->from); 2063 printf("\tte->to = %d\n",te->to); 2064 printf("\tte->y,m,d = %d-%d-%d\n",te->y,te->m,te->d); 2065 printf("\tte->fromdate = %s\n",te->fromdate == 0 ? 2066 "0" : niso(te->fromdate)); 2067 printf("\tte->todate = %s\n\n",te->todate == 0 ? 2068 "0" : niso(te->todate)); 2069 } 2070 } 2071} 2072 2073 2074/* 2075 Ip functions 2076*/ 2077 2078 2079#if __STDC__ 2080void sgSetIpType(int type, char *file, int line) 2081#else 2082void sgSetIpType(type, file, line) 2083 int type; 2084 char *file; 2085 int line; 2086#endif 2087{ 2088 struct Ip *ip = sgIpLast(lastSource),*nip; 2089 char *p; 2090 char *f = file == NULL ? configFile : file; 2091 int l = line == 0 ? lineno : line ; 2092 unsigned long octet, *op = NULL; 2093 if(type == SG_IPTYPE_HOST) 2094 ip->mask = 0xffffffff; 2095 if(type == SG_IPTYPE_RANGE){ 2096 if((op=sgConvDot(ip->str)) == NULL) 2097 sgLogFatalError("%s: address error in %s line %d", progname, f,l); 2098 else 2099 ip->mask = *op; 2100 if(ip->net > ip->mask) 2101 sgLogFatalError("%s: iprange error in %s line %d", progname, f,l); 2102 } 2103 if(type == SG_IPTYPE_CLASS){ 2104 p=ip->str; 2105 if(*p == '/') 2106 p++; 2107 if((op=sgConvDot(p)) == NULL) 2108 sgLogFatalError("%s: address error in %s line %d", progname, f,l); 2109 else 2110 ip->mask = *op; 2111 } 2112 if(type == SG_IPTYPE_CIDR){ 2113 p=ip->str; 2114 if(*p == '/') 2115 p++; 2116 octet = atoi(p); 2117 if(octet < 0 || octet > 32){ 2118 sgLogFatalError("%s: prefix error /%s in %s line %d", 2119 progname,p, f,l); 2120 } 2121 if(octet == 32) 2122 ip->mask = 0xffffffff; 2123 else 2124 ip->mask = 0xffffffff ^ (0xffffffff >> octet); 2125 ip->net = ip->net & ip->mask; 2126 } 2127 ip->type = type; 2128 nip = (struct Ip *) sgCalloc(1,sizeof(struct Ip)); 2129 ip->next = nip ; 2130} 2131 2132#if __STDC__ 2133void sgIp(char *name) 2134#else 2135void sgIp(name) 2136 char *name; 2137#endif 2138{ 2139 struct Ip *ip; 2140 unsigned long *op; 2141 if(lastSource->ip == NULL){ 2142 ip = (struct Ip *) sgCalloc(1,sizeof(struct Ip)); 2143 ip->next = NULL; 2144 lastSource->ip = ip; 2145 lastSource->lastip = ip; 2146 } else { 2147 ip = sgIpLast(lastSource); 2148 } 2149 if(ip->net_is_set == 0){ 2150 ip->net_is_set = 1; 2151 if((op=sgConvDot(name)) == NULL){ 2152 sgLogFatalError("%s: address error in %s line %d", progname, configFile,lineno); 2153 } else 2154 ip->net = *op; 2155 } else { 2156 ip->str = (char *) sgCalloc(1,strlen(name) + 1); 2157 strcpy(ip->str,name); 2158 } 2159} 2160 2161#if __STDC__ 2162struct Ip *sgIpLast(struct Source *s) 2163#else 2164struct Ip *sgIpLast(s) 2165 struct Source *s; 2166#endif 2167{ 2168 struct Ip *ip,*ret = NULL ; 2169 for(ip=s->ip; ip != NULL; ip = ip->next) 2170 ret = ip; 2171 return ret; 2172} 2173 2174/* 2175 ACL functions 2176*/ 2177 2178 2179#if __STDC__ 2180void sgAcl(char *name, char *value, int within) 2181#else 2182void sgAcl(name, value, within) 2183 char *name; 2184 char *value; 2185 int within; 2186#endif 2187{ 2188 struct Acl *acl; 2189 struct Source *source = NULL; 2190 struct Time *time = NULL; 2191 int def = 0; 2192 char *s; 2193 if(name != NULL){ 2194 /* due to some strange things in my yacc code */ 2195 if((s=(char *) strchr(name,' ')) != NULL) 2196 *s='\0'; 2197 if((s=(char *) strchr(name,'\t')) != NULL) 2198 *s='\0'; 2199 /* 2200 if(Acl != NULL){ 2201 if((struct Acl *) sgAclFindName(name) != NULL){ 2202 sgLogFatalError("%s: ACL %s is defined in configfile %s", 2203 progname,name, configFile); 2204 } 2205 } 2206 */ 2207 } 2208 if(lastAcl != NULL && name == NULL && within == ELSE) 2209 name = lastAcl->name; 2210 acl = (struct Acl *)sgCalloc(1,sizeof(struct Acl)); 2211 if(!strcmp(name,"default")){ 2212 defaultAcl=acl; 2213 def++; 2214 } else { 2215 if((source = sgSourceFindName(name)) == NULL && !def){ 2216 sgLogFatalError("%s: ACL source %s is not defined in configfile %s", 2217 progname,name, configFile); 2218 } 2219 } 2220 acl->name = sgCalloc(1,strlen(name) + 1); 2221 strcpy(acl->name,name); 2222 acl->active = within == ELSE ? 0 : 1; 2223 acl->source = source; 2224 acl->pass = NULL; 2225 acl->rewriteDefault = 1; 2226 acl->rewrite = NULL; 2227 acl->redirect = NULL; 2228 acl->within = within; 2229 acl->logfile = NULL; 2230 acl->next = NULL; 2231 if(value != NULL){ 2232 if((time = sgTimeFindName(value)) == NULL){ 2233 sgLogFatalError("%s: ACL time %s is not defined in configfile %s", 2234 progname,value, configFile); 2235 } 2236 acl->time = time; 2237 } 2238 if(Acl == NULL){ 2239 Acl = acl; 2240 lastAcl = acl; 2241 } else { 2242 lastAcl->next = acl; 2243 lastAcl = acl; 2244 } 2245} 2246 2247#if __STDC__ 2248void sgAclSetValue (char *what, char *value, int allowed) 2249#else 2250void sgAclSetValue (what, value, allowed) 2251 char *what; 2252 char *value; 2253 int allowed; 2254#endif 2255{ 2256 struct Destination *dest = NULL; 2257 struct sgRewrite *rewrite = NULL; 2258 struct AclDest *acldest; 2259 int type = ACL_TYPE_TERMINATOR; 2260 if(!strcmp(what,"pass")){ 2261 if(!strcmp(value,"any") || !strcmp(value,"all")) 2262 allowed = 1; 2263 else if(!strcmp(value,"none")) 2264 allowed=0; 2265 else if(!strcmp(value,"in-addr")){ 2266 type = ACL_TYPE_INADDR; 2267 } else { 2268 if((dest = sgDestFindName(value)) == NULL){ 2269 sgLogFatalError("%s: ACL destination %s is not defined in configfile %s", 2270 progname,value, configFile); 2271 } 2272 type = ACL_TYPE_DEFAULT; 2273 } 2274 2275 acldest = sgCalloc(1,sizeof(struct AclDest)); 2276 acldest->name = (char *) sgCalloc(1,strlen(value) + 1); 2277 strcpy(acldest->name,value); 2278 acldest->dest = dest; 2279 acldest->access = allowed; 2280 acldest->type = type; 2281 acldest->next = NULL; 2282 if(lastAcl->pass == NULL){ 2283 lastAcl->pass = acldest; 2284 } else { 2285 lastAclDest->next = acldest; 2286 } 2287 lastAclDest = acldest; 2288 } 2289 2290 if(!strcmp(what,"rewrite")){ 2291 if(!strcmp(value,"none")){ 2292 lastAcl->rewriteDefault = 0; 2293 lastAcl->rewrite = NULL; 2294 } else { 2295 if((rewrite = sgRewriteFindName(value)) == NULL){ 2296 sgLogFatalError("%s: Rewrite %s is not defined in configfile %s", 2297 progname,value, configFile); 2298 } 2299 lastAcl->rewriteDefault = 0; 2300 lastAcl->rewrite = rewrite; 2301 } 2302 } 2303 if(!strcmp(what,"redirect")){ 2304 if(strcmp(value,"default")){ 2305 lastAcl->redirect = (char *) sgCalloc(1,strlen(value) + 1); 2306 strcpy(lastAcl->redirect,value); 2307 } else { 2308 lastAcl->redirect= NULL; 2309 } 2310 } 2311} 2312 2313#if __STDC__ 2314struct Acl *sgAclFindName(char *name) 2315#else 2316struct Acl *sgAclFindName(name) 2317 char *name; 2318#endif 2319{ 2320 struct Acl *p; 2321 for(p=Acl; p != NULL; p = p->next){ 2322 if(!strcmp(name,p->name)) 2323 return p; 2324 } 2325 return NULL; 2326} 2327 2328 2329#if __STDC__ 2330struct Acl *sgAclCheckSource(struct Source *source) 2331#else 2332struct Acl *sgAclCheckSource(source) 2333 struct Source *source; 2334#endif 2335{ 2336 struct Acl *acl = defaultAcl; 2337 int found = 0; 2338 if(source != NULL){ 2339 for(acl=Acl; acl != NULL; acl = acl->next){ 2340 if(acl->source == source){ 2341 if(acl->active){ 2342 found++; 2343 break; 2344 } else { 2345 if(acl->next->source == source && acl->next->active != 0){ 2346 found++; 2347 acl=acl->next; 2348 break; 2349 } 2350 } 2351 } 2352 } 2353 } 2354@NOLOG1@ 2355 else { 2356 if( globalDebug == 1 ) { sgLogError("source not found"); } 2357 } 2358@NOLOG2@ 2359 if(!found) { 2360 acl = defaultAcl; 2361@NOLOG1@ 2362 if( globalDebug == 1 ) { sgLogError("no ACL matching source, using default"); } 2363@NOLOG2@ 2364 } 2365 return acl; 2366} 2367 2368#if __STDC__ 2369char *sgAclAccess(struct Source *src, struct Acl *acl, struct SquidInfo *req) 2370#else 2371char *sgAclAccess(src, acl, req) 2372 struct Source *src; 2373 struct Acl *acl; 2374 struct SquidInfo *req; 2375#endif 2376{ 2377 int access = 1,result; 2378 char *redirect = NULL, *dbdata = NULL, *p; 2379 struct sgRewrite *rewrite = NULL; 2380 struct AclDest *aclpass = NULL; 2381 if(acl == NULL) 2382 return NULL; 2383 if(acl->pass == NULL) 2384 acl->pass = defaultAcl->pass; 2385 if(acl->pass != NULL){ 2386 for(aclpass = acl->pass; aclpass != NULL; aclpass = aclpass->next){ 2387 if(aclpass->dest != NULL && !aclpass->dest->active) 2388 continue; 2389 if(aclpass->type == ACL_TYPE_TERMINATOR){ 2390 access=aclpass->access; 2391 break; 2392 } 2393 if(aclpass->type == ACL_TYPE_INADDR){ 2394 if(req->dot){ 2395 access=aclpass->access; 2396 break; 2397 } 2398 continue; 2399 } 2400 if(aclpass->dest->domainlistDb != NULL){ 2401 result = defined(aclpass->dest->domainlistDb, req->domain, &dbdata); 2402 if(result != DB_NOTFOUND) { 2403 if(result){ 2404 if(aclpass->access){ 2405 access++; 2406 break; 2407 } else { 2408 access = 0; 2409 break; 2410 } 2411 } 2412 } 2413 else { 2414 } 2415 } 2416 if(aclpass->dest->urllistDb != NULL && access){ 2417 result = defined(aclpass->dest->urllistDb,req->strippedurl, &dbdata); 2418 if (!result) { 2419 result = defined(aclpass->dest->urllistDb,req->furl, &dbdata); 2420 } 2421 if ((result) && (result != DB_NOTFOUND)) { 2422 if(aclpass->access){ 2423 access++; 2424 break; 2425 } else { 2426 access = 0; 2427 break; 2428 } 2429 } 2430 else { 2431 } 2432 } 2433 if(aclpass->dest->regExp != NULL && access){ 2434 if((result = sgRegExpMatch(aclpass->dest->regExp,req->strippedurl)) != 0){ 2435 if(aclpass->access){ 2436 access++; 2437 break; 2438 } else { 2439 access = 0; 2440 break; 2441 } 2442 } 2443 } 2444 } 2445 if(!access){ 2446 if(dbdata != NULL) 2447 redirect = dbdata; 2448 else if(aclpass->dest != NULL && aclpass->dest->redirect != NULL) 2449 redirect = aclpass->dest->redirect; 2450 else if(aclpass->dest != NULL && aclpass->dest->rewrite != NULL && 2451 (redirect = 2452 sgRewriteExpression(aclpass->dest->rewrite,req->orig)) != NULL){ 2453 ; 2454 } 2455 else if(acl->redirect == NULL) 2456 redirect = defaultAcl->redirect; 2457 else 2458 redirect = acl->redirect; 2459 } 2460 } else { /* acl->pass == NULL, probably defaultAcl->pass == NULL */ 2461 access=0; 2462 redirect = defaultAcl->redirect; 2463 } 2464 if(acl->rewrite == NULL) 2465 rewrite = defaultAcl->rewrite; 2466 else 2467 rewrite = acl->rewrite; 2468 if(rewrite != NULL && access){ 2469 if((p = sgRewriteExpression(rewrite,req->orig)) != NULL){ 2470 redirect = p; 2471 if(rewrite->logfile != NULL){ 2472 globalLogFile = rewrite->logfile; 2473 sgLogRequest(globalLogFile,req,acl,aclpass,rewrite,REQUEST_TYPE_REWRITE); 2474 return redirect; 2475 } 2476 } 2477 } else if(redirect != NULL) { 2478 redirect = sgParseRedirect(redirect, req, acl, aclpass); 2479 } 2480 if(src != NULL && src->logfile != NULL) 2481 globalLogFile = src->logfile; 2482 if(aclpass == NULL || aclpass->dest == NULL){ 2483 if(defaultAcl->logfile != NULL) 2484 globalLogFile = defaultAcl->logfile; 2485 } else 2486 if(aclpass->dest->logfile != NULL) 2487 globalLogFile = aclpass->dest->logfile; 2488 if(globalLogFile != NULL) { 2489 if(redirect != NULL) { 2490 sgLogRequest(globalLogFile,req,acl,aclpass,NULL,REQUEST_TYPE_REDIRECT); 2491 } else { 2492 sgLogRequest(globalLogFile,req,acl,aclpass,NULL,REQUEST_TYPE_PASS); 2493 } 2494 } 2495 return redirect; 2496} 2497 2498#if __STDC__ 2499void yyerror(char *s) 2500#else 2501void yyerror(s) 2502 char *s; 2503#endif 2504{ 2505 sgLogFatalError("%s in configfile %s line %d",s,configFile,lineno); 2506} 2507 2508 2509#if __STDC__ 2510int yywrap() 2511#else 2512int yywrap() 2513#endif 2514{ 2515 return 1; 2516} 2517 2518/* returns 1 if user was found for the specified Source 2519 * returns a pointer to a UserInfo structure when found 2520 * handles all LDAP sub-lookups and caching 2521 */ 2522#if __STDC__ 2523int sgFindUser(struct Source *src, char *ident, struct UserInfo **rval) 2524#else 2525int sgFindUser(src, ident, rval) 2526 struct Source *src; 2527 char *ident; 2528 struct UserInfo **rval; 2529#endif 2530 2531{ 2532 int i, found; 2533 int CacheTimeOut; 2534 char *interval; 2535 struct UserInfo *userinfo; 2536 static struct UserInfo info; 2537 2538 /* defined in the userDB? */ 2539 if(defined(src->userDb, ident, (char **) &userinfo) == 1) { 2540#ifdef HAVE_LIBLDAP 2541 /* LDAP user? */ 2542 if(!userinfo->ldapuser) { 2543 *rval = userinfo; 2544 return 1; /* no, return regular user */ 2545 } 2546 2547 /* from here on, we assume it is an LDAP user */ 2548 2549 /* is this info valid? */ 2550 interval = sgSettingGetValue("ldapcachetime"); 2551 CacheTimeOut = atoi(interval != NULL ? interval : "0"); 2552 if((time(NULL) - userinfo->cachetime) <= CacheTimeOut) { 2553 if(userinfo->found) 2554 *rval = userinfo; 2555 return userinfo->found; /* yes */ 2556 } 2557#endif 2558 } 2559 else { 2560 userinfo = NULL; /* no record defined, must add our own*/ 2561 } 2562 2563 found = 0; /* assume not found */ 2564 2565#ifdef HAVE_LIBLDAP 2566 /* loop through all LDAP URLs and do a search */ 2567 for(i = 0; i < src->ldapurlcount; i++) { 2568 2569 found = sgDoLdapSearch(src->ldapurls[i], ident); 2570 2571 /* cache every search in the user database */ 2572 /* this should be safe, since squid only sends real idents 2573 that have been authenticated (?) */ 2574 2575 /* any record defined from above? */ 2576 if(userinfo == NULL) { 2577 /* no, must use our own memory */ 2578 userinfo = &info; 2579 info.status = 0; 2580 info.time = 0; 2581 info.consumed = 0; 2582 info.last = 0; 2583 info.ldapuser = 1; 2584 info.found = found; 2585 info.cachetime = time(NULL); 2586 } 2587 else { 2588 /* yes, just update the found flag */ 2589 userinfo->found = found; 2590 userinfo->cachetime = time(NULL); 2591 } 2592 2593 sgDbUpdate(src->userDb, ident, (char *) userinfo, 2594 sizeof(struct UserInfo)); 2595 @NOLOG1@ sgLogError("Added LDAP source: %s", ident); @NOLOG2@ 2596 2597 if(found) { 2598 *rval = userinfo; 2599 break; 2600 } 2601 } 2602#endif 2603 return found; 2604} 2605 2606#ifdef HAVE_LIBLDAP 2607 2608#if __STDC__ 2609static int get_ldap_errno(LDAP *ld) 2610#else 2611static int get_ldap_errno(ld) 2612 LDAP *ld; 2613#endif 2614 2615{ 2616 int err = 0; 2617 if(ld) { 2618 if(ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err) != LDAP_OPT_SUCCESS) 2619 err = 0; 2620 } 2621 return err; 2622} 2623 2624/* 2625 * expand_url - expand the %s codes in the given LDAP url 2626 * 2627 * Returns: 1 on success, 0 on error 2628 * 2629 * char *expand; destination buffer for expanded URL 2630 * size_t expand_size; size of dest buffer (sizeof() works here) 2631 * char *url; original URL (MAXWORDLEN) 2632 * char *s_item; word to replace each occurance of %s with 2633 */ 2634int expand_url(char *expand, size_t expand_size, const char *url, 2635 const char *s_item) 2636{ 2637 int item_length; 2638 char *end = expand + expand_size; 2639 2640 item_length = strlen(s_item); 2641 2642 while (*url && expand < end) { 2643 if (url[0] == '%' && url[1] == 's') { 2644 /* check buffer overrun */ 2645 if ((expand + item_length) >= end) 2646 return 0; 2647 strcpy(expand, s_item); 2648 expand += item_length; 2649 2650 url += 2; 2651 } 2652 else { 2653 *expand++ = *url++; 2654 } 2655 } 2656 2657 if (expand < end) { 2658 *expand = '\0'; /* null terminate string */ 2659 return 1; 2660 } 2661 else { 2662 return 0; 2663 } 2664} 2665 2666 2667/* does a raw LDAP search and returns 1 if found, 0 if not */ 2668#if __STDC__ 2669int sgDoLdapSearch(const char *url, const char *username) 2670#else 2671int sgDoLdapSearch(url, username) 2672 const char *url; 2673 const char *username; 2674#endif 2675{ 2676 LDAPURLDesc *lud; 2677 LDAP *ld; 2678 LDAPMessage *ldapresult, *ldapentry; 2679 char *binddn = NULL, *bindpass = NULL; 2680 int ext_i; 2681 char **ldapvals; 2682 char buffer[MAX_BUF]; 2683 int found = 0; 2684 int protoversion = -1; /* default to library defaults*/ 2685 char *protosetting; 2686 2687 /* Which protocol version should we use? */ 2688 protosetting = sgSettingGetValue("ldapprotover"); 2689 if (protosetting != NULL) { 2690 if (atoi(protosetting) == 3) { 2691 protoversion = LDAP_VERSION3; 2692 } 2693 else if (atoi(protosetting) == 2) { 2694 protoversion = LDAP_VERSION2; 2695 } 2696 } 2697 2698 /* insert the username into the url, if needed... allow multiple %s */ 2699 if (!expand_url(buffer, sizeof(buffer), url, username)) { 2700 sgLogError("%s: unable to expand LDAP URL: size: %u, username: " 2701 "%s url: %s", progname, sizeof(buffer), username, url); 2702 return found; 2703 } 2704 2705 /* Parse RFC2255 LDAP URL */ 2706 if(ldap_url_parse(buffer, &lud)) { 2707 sgLogError("%s: can't parse LDAP url %s",progname, buffer); 2708 return found; 2709 } 2710 2711 /* get a handle to an LDAP connection */ 2712 if((ld = ldap_init(lud->lud_host, lud->lud_port)) == NULL) { 2713 sgLogError("%s: ldap_init(%s, %d) failed: %s", progname, 2714 lud->lud_host, lud->lud_port, strerror(errno)); 2715 ldap_free_urldesc(lud); 2716 return found; 2717 } 2718 2719 /* force an LDAP protocol version if set */ 2720 if (protoversion != -1) { 2721 if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, 2722 &protoversion) != LDAP_OPT_SUCCESS) 2723 { 2724 /* this will enter emergency mode */ 2725 sgLogFatalError("%s: ldap_set_option failed: %s", 2726 progname, ldap_err2string(get_ldap_errno(ld))); 2727 } 2728 } 2729 2730 /* 2731 * Set binddn and bindpass with values from the config 2732 * file. Do this before the URL extentions so that they 2733 * override on a per-block basis. 2734 */ 2735 binddn = sgSettingGetValue("ldapbinddn"); 2736 bindpass = sgSettingGetValue("ldapbindpass"); 2737 2738 /* check for supported URL extensions: 2739 * bindname=<binddn> (RFC2255) 2740 * x-bindpass=<bindpass> (user-specific, allowed by RFC2255) 2741 */ 2742 for(ext_i = 0; 2743 lud->lud_exts != NULL && lud->lud_exts[ext_i] != NULL; 2744 ext_i++) { 2745 2746 char *key = lud->lud_exts[ext_i]; 2747 char *data; 2748 2749 /* skip over any 'critical' markers */ 2750 if (*key == '!') 2751 key++; 2752 2753 /* find '=' sign (first one is all we care about) */ 2754 data = strchr(key, '='); 2755 if (data == NULL) 2756 continue; /* invalid extension, skip */ 2757 data++; /* good extension, get data */ 2758 2759 /* do we recognize the key? */ 2760 if (strncmp(key, "bindname=", 9) == 0) 2761 { 2762 binddn = data; 2763 @NOLOG1@ sgLogError("Extracted binddn: %s", binddn); @NOLOG2@ 2764 } 2765 else if (strncmp(key, "x-bindpass=", 11) == 0) 2766 { 2767 bindpass = data; 2768 @NOLOG1@ sgLogError("Extracted x-bindpass: %s", bindpass); @NOLOG2@ 2769 } 2770 } 2771 2772 /* authenticate to the directory */ 2773 if (ldap_simple_bind_s(ld, binddn, bindpass) != LDAP_SUCCESS) { 2774 sgLogError("%s: ldap_simple_bind_s failed: %s", progname, 2775 ldap_err2string(get_ldap_errno(ld))); 2776 ldap_unbind(ld); 2777 ldap_free_urldesc(lud); 2778 return found; 2779 } 2780 2781 /* Perform search */ 2782 if(ldap_search_ext_s(ld, lud->lud_dn, lud->lud_scope, lud->lud_filter, 2783 lud->lud_attrs, 0, NULL, NULL, NULL, -1, 2784 &ldapresult) != LDAP_SUCCESS) { 2785 2786@NOLOG1@ 2787 sgLogError("%s: ldap_search_ext_s failed: %s " 2788 2789 "(params: %s, %d, %s, %s)", 2790 progname, ldap_err2string(get_ldap_errno(ld)), 2791 lud->lud_dn, lud->lud_scope, lud->lud_filter, 2792 lud->lud_attrs[0]); 2793@NOLOG2@ 2794 2795 ldap_unbind(ld); 2796 ldap_free_urldesc(lud); 2797 return found; 2798 } 2799 2800 /* return hash */ 2801 ldapentry = ldap_first_entry(ld, ldapresult); 2802 if(ldapentry != NULL) { 2803 /* Use first attribute to get value */ 2804 ldapvals = ldap_get_values(ld, ldapentry, lud->lud_attrs[0]); 2805 if(ldapvals != NULL) { 2806 if(*ldapvals != NULL) 2807 found = 1; 2808 ldap_value_free(ldapvals); 2809 } 2810 } 2811 2812 /* cleanup */ 2813 ldap_msgfree(ldapresult); 2814 ldap_unbind(ld); 2815 ldap_free_urldesc(lud); 2816 return found; 2817} 2818 2819#endif 2820