1 /*
2  * Copyright (c) 2001-2002 Secure Software, Inc
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  *
18  */
19 
20 #include <ctype.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #ifdef _MSC_VER
24 #include <windows.h>
25 #else
26 #include <sys/time.h>
27 #endif
28 
29 #include <string.h>
30 #include "report.h"
31 
32 int warning_level = 2;
33 
34 static input_t *            input_head  = (input_t *)NULL;
35 static input_t *            input_tail  = (input_t *)NULL;
36 static ignore_t *           ignore_list = (ignore_t *)NULL;
37 static vulnerability_t *    list_head   = (vulnerability_t *)NULL;
38 static vulnerability_t *    list_tail   = (vulnerability_t *)NULL;
39 
40 static char *context_filename = NULL;
41 static FILE *context_fp = NULL;
42 static int context_line = 0;
43 static int lookup_ignore(char *filename, int lineno, char *token);
44 static int determine_ignorance(vulnerability_t *ptr);
45 static void diff_times(const struct timeval *, const struct timeval *,  struct timeval *);
46 
47 int total_lines = 0;
48 #ifdef _MSC_VER
49 DWORD time_started;
50 DWORD time_finished;
51 #else
52 struct timeval time_started;
53 struct timeval time_finished;
54 #endif
55 
56 
57 /* This function EXPECTS a MALLOCED BUFFER to be passed into it, as it will
58  * free it if it needs to be
59  */
60 static char *
xml_escape(char * xstr)61 xml_escape(char *xstr)
62 {
63 
64   char *result = NULL;
65   char *cntptr = NULL;
66   char *cpptr = NULL;
67   char *dstptr = NULL;
68   unsigned int newsz = 0;
69 
70   newsz = strlen(xstr)+1;
71 
72   cntptr = xstr;
73   while((cntptr = strchr(cntptr, '&')))
74   {
75     newsz += 4;
76     cntptr++;
77   }
78 
79   cntptr = xstr;
80 
81   while((cntptr = strchr(cntptr, '<')))
82   {
83     newsz += 3;
84     cntptr++;
85   }
86 
87   cntptr = xstr;
88 
89   while((cntptr = strchr(cntptr, '>')))
90   {
91     newsz += 3;
92     cntptr++;
93   }
94 
95   if (newsz == strlen(xstr)+1)
96   {
97     return xstr;
98   }
99   result = malloc(newsz);
100   cpptr = xstr;
101   dstptr = result;
102   while(*cpptr && (dstptr < result+newsz))
103   {
104     if (*cpptr == '&')
105     {
106       strncat(dstptr, "&amp;", 5);
107       dstptr += 5;
108     } else if (*cpptr == '<') {
109       strncat(dstptr, "&lt;", 4);
110       dstptr += 4;
111     } else if (*cpptr == '>') {
112       strncat(dstptr, "&gt;", 4);
113       dstptr += 4;
114     } else {
115        *dstptr = *cpptr;
116        *(dstptr+1) = 0;
117        dstptr++;
118     }
119     cpptr++;
120   }
121   free(xstr);
122   return result;
123 }
124 
125 
126 /* Exclusively for debugging vulnerabilities.
127  * - robbat2@gentoo.org 21/05/2006 */
debug_vuln_dump(vulnerability_t * ptr)128 static void debug_vuln_dump(vulnerability_t *ptr) {
129        fprintf(stderr,"vuln_dump: this=%x f=%s l=%d c=%d d=%x t=%d s=%d u=%x p=(%x,%x)\n",
130                        (unsigned int) ptr,
131                        ptr->filename,ptr->lineno,ptr->column,
132                        (unsigned int) ptr->data,ptr->type,ptr->severity,
133                        (unsigned int) ptr->uses, (unsigned int) ptr->next, (unsigned int) ptr->prev);
134 }
135 
136 
137 
138 static void
replace_cfname(char * filename)139 replace_cfname(char *filename)
140 {
141 
142   if (context_filename)
143     free(context_filename);
144 
145   context_filename = malloc(strlen(filename)+1);
146   strncpy(context_filename, filename, strlen(filename));
147   context_filename[strlen(filename)] = 0;
148 }
149 
150 static char *
getctx(char * filename,int lineno)151 getctx(char *filename, int lineno)
152 {
153 
154     char *ret = NULL;
155     char buf[4096] = {0};
156 
157     if (context_filename && strcmp(context_filename, filename))
158     {
159         replace_cfname(filename);
160         if (context_fp)
161         {
162             fclose(context_fp);
163             context_fp = NULL;
164         }
165     }
166 
167     if (!context_filename)
168     {
169       replace_cfname(filename);
170     }
171 
172     if (!context_fp)
173     {
174        context_fp = fopen(context_filename, "r");
175        context_line = 0;
176        if (!context_fp)
177           return NULL;
178     }
179 
180 
181     if (lineno <= context_line)
182     {
183       context_line = 0;
184       fseek(context_fp, 0, SEEK_SET);
185     }
186 
187     while(fgets(buf, 4096, context_fp))
188     {
189         if(buf[strlen(buf)-1] == '\n')
190         {
191             context_line++;
192         }
193         if (context_line == lineno)
194         {
195           ret = malloc(strlen(buf)+1);
196           strncpy(ret, buf, strlen(buf));
197           ret[strlen(buf)] = 0;
198           return ret;
199         }
200     }
201     return NULL;
202 }
203 
204 
205 
206 static
insert_vulnerability(vulnerability_t * log)207 void insert_vulnerability(vulnerability_t *log)
208 {
209     int                 insert = 0;
210     vulnerability_t *   ptr;
211 
212     for (ptr = list_head;  ptr != (vulnerability_t *)NULL;  ptr = ptr->next)
213     {
214         if (ptr->severity < log->severity)
215         {
216             insert = 1;
217             ptr = ptr->prev;
218             break;
219         }
220         if (ptr->type == log->type && ptr->data == log->data)
221         {
222             for (ptr = ptr->next;  ptr != (vulnerability_t *)NULL;  ptr = ptr->next)
223             {
224                 if (ptr->type != log->type || ptr->data != log->data)
225                 {
226                     ptr = ptr->prev;
227                     break;
228                 }
229             }
230             break;
231         }
232     }
233     if (ptr == (vulnerability_t *)NULL && !insert)
234         ptr = list_tail;
235 
236     log->next = (ptr == (vulnerability_t *)NULL ? list_head : ptr->next);
237     log->prev = ptr;
238 
239     if (log->next != (vulnerability_t *)NULL)
240         log->next->prev = log;
241     else
242         list_tail = log;
243     if (log->prev != (vulnerability_t *)NULL)
244         log->prev->next = log;
245     else
246         list_head = log;
247 }
248 
log_toctou(toctou_t ** table,int first,int last,int check)249 void log_toctou(toctou_t **table, int first, int last, int check)
250 {
251     int                 i;
252     vulnerability_t *   log;
253 
254     if (check != -1)
255     {
256         int count = 0, index = 0;
257 
258         for (i = first;  i <= last;  i++)
259             count += (table[i]->use);
260 
261         log = (vulnerability_t *)malloc(sizeof(vulnerability_t));
262         log->filename = current_file;
263         log->lineno   = table[check]->lineno;
264         log->column   = table[check]->column;
265         log->data     = table[check]->data;
266         log->type     = RaceConditionCheck;
267 
268         if (count > 0)
269         {
270             log->severity = Medium;
271             log->uses     = (toctou_use_t *)malloc(sizeof(toctou_use_t) * (count + 1));
272 
273             for (i = first;  i <= last;  i++)
274             {
275                 if (table[i]->use)
276                 {
277                     log->uses[index].name   = table[i]->data->Name;
278                     log->uses[index].lineno = table[i]->lineno;
279                     log->uses[index].column = table[i]->column;
280                     index++;
281                 }
282             }
283             log->uses[index].name   = (char *)NULL;
284             log->uses[index].lineno = 0;
285             log->uses[index].column = 0;
286 
287         }
288         else
289         {
290             log->severity = Low;
291             log->uses     = (toctou_use_t *)NULL;
292         }
293         insert_vulnerability(log);
294     }
295     else
296     {
297         for (i = first;  i <= last;  i++)
298         {
299             log = (vulnerability_t *)malloc(sizeof(vulnerability_t));
300             log->filename = current_file;
301             log->column   = table[i]->column;
302             log->lineno   = table[i]->lineno;
303             log->data     = table[i]->data;
304             log->type     = RaceConditionUse;
305             log->severity = Low;
306             log->uses     = (toctou_use_t *)NULL;
307 
308             insert_vulnerability(log);
309         }
310     }
311 }
312 
log_vulnerability(type_t type,Severity_t severity)313 void log_vulnerability(type_t type, Severity_t severity)
314 {
315     vulnerability_t *   log;
316 
317     log = (vulnerability_t *)malloc(sizeof(vulnerability_t));
318     log->column   = current_frame->column;
319     log->filename = current_file;
320     log->lineno   = current_frame->lineno;
321     log->data     = current_frame->data;
322     log->type     = type;
323     log->severity = severity;
324     log->uses     = (toctou_use_t *)NULL;
325 
326     insert_vulnerability(log);
327 }
328 
329 /* These are special static vulnerabilities because we don't
330  * want NULL data elements in the vulnerability_t->data
331  * field, because the HTML and XML output formats use that
332  * pointer without checking it for being null first.
333  * - robbat2@gentoo.org 21/05/2006 */
334 static struct Vuln_t vuln_PerlBacktick = {
335        .Name = "Perl Backtick"
336 };
337 static struct Vuln_t vuln_PhpBacktick = {
338        .Name = "PHP Backtick"
339 };
340 static struct Vuln_t vuln_PythonBacktick = {
341        .Name = "Python Backtick"
342 };
343 static struct Vuln_t vuln_StaticLocalBuffer = {
344        .Name = "Static Local Buffer"
345 };
346 static struct Vuln_t vuln_StaticGlobalBuffer = {
347        .Name = "Static Global Buffer"
348 };
349 
log_perlbacktick(int lineno,int column,Severity_t severity)350 void log_perlbacktick(int lineno, int column, Severity_t severity)
351 {
352     vulnerability_t *   log;
353 
354     log = (vulnerability_t *)malloc(sizeof(vulnerability_t));
355     log->filename = current_file;
356     log->column   = column;
357     log->lineno   = lineno;
358     log->data     = &vuln_PerlBacktick;
359     log->type     = PerlBacktick;
360     log->severity = severity;
361     log->uses     = (toctou_use_t *)NULL;
362 
363     insert_vulnerability(log);
364 }
365 
366 
log_phpbacktick(int lineno,int column,Severity_t severity)367 void log_phpbacktick(int lineno, int column, Severity_t severity)
368 {
369     vulnerability_t *   log;
370 
371     log = (vulnerability_t *)malloc(sizeof(vulnerability_t));
372     log->filename = current_file;
373     log->column   = column;
374     log->lineno   = lineno;
375     log->data     = &vuln_PhpBacktick;
376     log->type     = PhpBacktick;
377     log->severity = severity;
378     log->uses     = (toctou_use_t *)NULL;
379 
380     insert_vulnerability(log);
381 }
382 
log_rubybacktick(int lineno,int column,Severity_t severity)383 void log_rubybacktick(int lineno, int column, Severity_t severity)
384 {
385     vulnerability_t *   log;
386 
387     log = (vulnerability_t *)malloc(sizeof(vulnerability_t));
388     log->filename = current_file;
389     log->column   = column;
390     log->lineno   = lineno;
391     log->data     = (Vuln_t *)NULL;
392     log->type     = RubyBacktick;
393     log->severity = severity;
394     log->uses     = (toctou_use_t *)NULL;
395 
396     insert_vulnerability(log);
397 }
398 
log_pythonbacktick(int lineno,int column,Severity_t severity)399 void log_pythonbacktick(int lineno, int column, Severity_t severity)
400 {
401     vulnerability_t *   log;
402 
403     log = (vulnerability_t *)malloc(sizeof(vulnerability_t));
404     log->filename = current_file;
405     log->column   = column;
406     log->lineno   = lineno;
407     log->data     = &vuln_PythonBacktick;
408     log->type     = PythonBacktick;
409     log->severity = severity;
410     log->uses     = (toctou_use_t *)NULL;
411 
412     insert_vulnerability(log);
413 }
414 
log_staticbuffer(type_t type,int lineno,int column,Severity_t severity)415 void log_staticbuffer(type_t type, int lineno, int column, Severity_t severity)
416 {
417     vulnerability_t *   log;
418 
419     log = (vulnerability_t *)malloc(sizeof(vulnerability_t));
420     log->filename = current_file;
421     log->column   = column;
422     log->lineno   = lineno;
423     switch(type) {
424             case StaticLocalBuffer:
425                     log->data     = &vuln_StaticLocalBuffer;
426                     break;
427             case StaticGlobalBuffer:
428                     log->data     = &vuln_StaticGlobalBuffer;
429                     break;
430             default:
431                     log->data     = (Vuln_t *)NULL;
432     }
433     log->type     = type;
434     log->severity = severity;
435     log->uses     = (toctou_use_t *)NULL;
436 
437     insert_vulnerability(log);
438 }
439 
record_input(void)440 void record_input(void)
441 {
442     input_t *   input;
443 
444     input = (input_t *)malloc(sizeof(input_t));
445     input->column   = current_frame->column;
446     input->filename = current_file;
447     input->lineno   = current_frame->lineno;
448     input->data     = current_frame->data;
449     input->next     = (input_t *)NULL;
450 
451     if (input_tail != (input_t *)NULL)
452         input_tail->next = input;
453     else
454         input_head = input;
455     input_tail = input;
456 }
457 
458 static
cleanup_string(char * str)459 void cleanup_string(char *str)
460 {
461     int     len;
462     char *  c;
463 
464     /* strip off leading a trailing whitespace */
465     for (c = str;  *c && isspace(*c);  c++);
466     for (len = strlen(c);  len > 0 && isspace(*(c + len - 1));  len--);
467     *(c + len) = '\0';
468     memmove(str, c, len + 1);
469 
470     /* squash occurences of multiple whitespace characters to a single one */
471 	/* msg -- this code seems to corrupt memory on occasion */
472     //for (c = str + 1;  *c;  c++)
473     //{
474     //    if (isspace(*c) && isspace(*(c - 1)))
475     //    {
476     //        char *  start;
477 
478     //        for (start = c++;  isspace(*c);  c++);
479     //        memmove(start, c, (len + 1) - (c - str));
480     //        len -= (c - start);
481     //        *(start - 1) = ' ';
482     //    }
483     //}
484 }
485 
486 static char *severities[] = { "Default", "Low", "Medium", "High" };
487 
build_xml_vulnerability(vulnerability_t * ptr)488 static void build_xml_vulnerability(vulnerability_t *ptr) {
489     int i;
490 
491     /* Debugging - robbat2@gentoo.org 21/05/2006 */
492     if(ptr->data == NULL)
493             debug_vuln_dump(ptr);
494 
495     printf("<vulnerability>\n");
496 
497     /* Output the severity */
498     printf("  <severity>%s</severity>\n",
499 	   severities[ptr->severity]);
500 
501     switch (ptr->type)
502     {
503     case BOProblem:
504       if (ptr->data->BOProblem->FormatArg > 0)
505 	{
506 	  printf("  <type>%s</type>\n",
507 		 ptr->data->Name);
508 	  printf("  <message>\n");
509 	  printf("    Check to be sure that the format string passed as argument %d to this\n", ptr->data->BOProblem->FormatArg);
510 	  printf("    function call does not come from an untrusted source that could have added\n");
511 	  printf("    formatting characters that the code is not prepared to handle.\n");
512 	  printf("    Additionally, the format string could contain `%%s' without precision that\n");
513 	  printf("    could result in a buffer overflow.\n");
514 	  printf("  </message>\n");
515 	}
516       if (ptr->data->BOProblem->SrcBufArg > 0)
517 	{
518 	  printf("  <message>\n");
519 	  printf("    Check to be sure that argument %d passed to this function call will not\n", ptr->data->BOProblem->SrcBufArg);
520 	  printf("    copy more data than can be handled, resulting in a buffer overflow.\n");
521 	  printf("  </message>\n");
522 	}
523       break;
524 
525     case FSProblem:
526       printf("  <type>%s</type>\n",
527 	     ptr->data->Name);
528       printf("  <message>\n");
529       printf("    Check to be sure that the non-constant format string passed as argument %d \n", ptr->data->FSProblem->Arg);
530       printf("    to this function call does not come from an untrusted source that could\n");
531       printf("    have added formatting characters that the code is not prepared to handle.\n");
532       printf("  </message>\n");
533       break;
534 
535     case InputProblem:
536       printf("  <type>%s</type>\n",
537 	     ptr->data->Name);
538       printf("  <message>\n");
539       printf("    Argument %d to this function call should be checked to ensure that it does\n", ptr->data->InputProblem->Arg);
540       printf("    not come from an untrusted source without first verifying that it contains\n");
541       printf("    nothing dangerous.\n");
542       printf("  </message>\n");
543       break;
544 
545     case Info:
546       printf("  <type>%s</type>\n",
547 	     ptr->data->Name);
548       printf("  <message>\n");
549       if (ptr->data->Info->Description != (char *)NULL) {
550 	cleanup_string(ptr->data->Info->Description);
551 	printf("    %s\n", ptr->data->Info->Description);
552       }
553       if (ptr->data->Info->URL != (char *)NULL)	{
554 	cleanup_string(ptr->data->Info->URL);
555 	/* This should possibly be made into it's own tag -- Robert */
556 	printf("    foSee also:\n %s\n", ptr->data->Info->URL);
557       }
558       printf("  </message>\n");
559       break;
560 
561     case RaceConditionCheck:
562       printf("  <type>%s</type>\n",
563 	     ptr->data->Name);
564       printf("  <message>\n");
565       printf("    A potential TOCTOU (Time Of Check, Time Of Use) vulnerability exists.\n");
566       printf("    This is the first line where a check has occured.");
567       if (ptr->uses != (toctou_use_t *)NULL && ptr->uses[0].lineno != 0)
568 	{
569 	  printf("\n    The following line(s) contain uses that may match up with this check:\n");
570 	  for (i = 0;  ptr->uses[i].lineno != 0;  i++)
571 	    printf("    %s%d (%s)", (i == 0 ? "" : ", "), ptr->uses[i].lineno, ptr->uses[i].name);
572 	  printf("\n");
573 	}
574       else
575 	{
576 	  printf("    No matching uses were detected.\n");
577 	}
578       printf("  </message>\n");
579       break;
580 
581     case RaceConditionUse:
582       printf("  <type>fixed size local buffer</type>\n");
583       printf("  <message>\n");
584       printf("    A potential race condition vulnerability exists here.  Normally a call\n");
585       printf("    to this function is vulnerable only when a match check precedes it.  No\n");
586       printf("    check was detected, however one could still exist that could not be\n");
587       printf("    detected.\n");
588       printf("  </message>\n");
589       break;
590 
591     case StaticLocalBuffer:
592       printf("  <type>fixed size global buffer</type>\n");
593       printf("  <message>\n");
594       printf("    Extra care should be taken to ensure that character arrays that are\n");
595       printf("    allocated on the stack are used safely.  They are prime targets for\n");
596       printf("    buffer overflow attacks.\n");
597       printf("  </message>\n");
598       break;
599 
600     case StaticGlobalBuffer:
601       printf("  <type>%s</type>\n",
602 	     ptr->data->Name);
603       printf("  <message>\n");
604       printf("    Extra care should be taken to ensure that character arrays that are\n");
605       printf("    allocated with a static size are used safely.  This appears to be a\n");
606       printf("    global allocation and is less dangerous than a similar one on the stack.\n");
607       printf("    Extra caution is still advised, however.\n");
608       printf("  </message>\n");
609       break;
610 
611     case Reference:
612       printf("  <type>%s</type>\n",
613 	     ptr->data->Name);
614       printf("  <message>\n");
615       printf("    A function call is not being made here, but a reference is being made to\n");
616       printf("    a name that is normally a vulnerable function.  It could be being\n");
617       printf("    assigned as a pointer to function.\n\n");
618       printf("  </message>\n");
619       break;
620 
621     case PythonBacktick:
622       printf("  <type>Backtick</type>\n");
623       printf("  <message>\n");
624       printf("    Do not use a variable that has been derived from untrusted sources\n");
625       printf("    within a backtick.  Doing so could allow an attacker to execute\n");
626       printf("    arbitrary python code.\n");
627       printf("  </message>\n");
628       break;
629 
630     case PhpBacktick:
631     case PerlBacktick:
632 	case RubyBacktick:
633       printf("  <type>Backtick</type>\n");
634       printf("  <message>\n");
635       printf("    The backtick will act just like an call to exec(), so care should be\n");
636       printf("    exercised that the string being backtick evaluated does not come from an\n");
637       printf("    untrusted source.\n");
638       printf("  </message>\n");
639       break;
640 
641     case None:
642       printf("  <type>%s</type>\n",
643 	     ptr->data->Name);
644       printf("  <message>\n");
645       printf("    Unknown!?!?\n\n");
646       printf("  </message>\n");
647       break;
648     }
649 }
650 
651 static
report_vulnerability(vulnerability_t * ptr)652 void report_vulnerability(vulnerability_t *ptr)
653 {
654     int i;
655     if(ptr->data == NULL)
656             debug_vuln_dump(ptr);
657     switch (ptr->type)
658     {
659         case BOProblem:
660             if (ptr->data->BOProblem->FormatArg > 0)
661             {
662                 printf("Check to be sure that the format string passed as argument %d to this function\n", ptr->data->BOProblem->FormatArg);
663                 printf("call does not come from an untrusted source that could have added formatting\n");
664                 printf("characters that the code is not prepared to handle.  Additionally, the format\n");
665                 printf("string could contain `%%s' without precision that could result in a buffer\n");
666                 printf("overflow.\n");
667             }
668             if (ptr->data->BOProblem->SrcBufArg > 0)
669             {
670                 printf("Check to be sure that argument %d passed to this function call will not copy\n", ptr->data->BOProblem->SrcBufArg);
671                 printf("more data than can be handled, resulting in a buffer overflow.\n");
672             }
673             printf("\n");
674             break;
675 
676         case FSProblem:
677             printf("Check to be sure that the non-constant format string passed as argument %d to\n", ptr->data->FSProblem->Arg);
678             printf("this function call does not come from an untrusted source that could have added\n");
679             printf("formatting characters that the code is not prepared to handle.\n\n");
680             break;
681 
682         case InputProblem:
683             printf("Argument %d to this function call should be checked to ensure that it does not\n", ptr->data->InputProblem->Arg);
684             printf("come from an untrusted source without first verifying that it contains nothing\n");
685             printf("dangerous.\n\n");
686             break;
687 
688         case Info:
689             if (ptr->data->Info->Description != (char *)NULL)
690             {
691                 cleanup_string(ptr->data->Info->Description);// comment out if causing problems
692                 printf("%s\n", ptr->data->Info->Description);
693             }
694             if (ptr->data->Info->URL != (char *)NULL)
695             {
696                 cleanup_string(ptr->data->Info->URL);
697                 printf("See also: %s\n", ptr->data->Info->URL);
698             }
699             printf("\n");
700             break;
701 
702         case RaceConditionCheck:
703             printf("A potential TOCTOU (Time Of Check, Time Of Use) vulnerability exists.  This is\n");
704             printf("the first line where a check has occured.");
705             if (ptr->uses != (toctou_use_t *)NULL && ptr->uses[0].lineno != 0)
706             {
707                 printf("\nThe following line(s) contain uses that may match up with this check:\n");
708                 for (i = 0;  ptr->uses[i].lineno != 0;  i++)
709                     printf("%s%d (%s)", (i == 0 ? "" : ", "), ptr->uses[i].lineno, ptr->uses[i].name);
710                 printf("\n");
711             }
712             else
713             {
714                 printf("  No matching uses were detected.\n");
715             }
716             printf("\n");
717             break;
718 
719         case RaceConditionUse:
720             printf("A potential race condition vulnerability exists here.  Normally a call to this\n");
721             printf("function is vulnerable only when a match check precedes it.  No check was\n");
722             printf("detected, however one could still exist that could not be detected.\n\n");
723             break;
724 
725         case StaticLocalBuffer:
726             printf("Extra care should be taken to ensure that character arrays that are allocated\n");
727             printf("on the stack are used safely.  They are prime targets for buffer overflow\n");
728             printf("attacks.\n\n");
729             break;
730 
731         case StaticGlobalBuffer:
732             printf("Extra care should be taken to ensure that character arrays that are allocated\n");
733             printf("with a static size are used safely.  This appears to be a global allocation\n");
734             printf("and is less dangerous than a similar one on the stack.  Extra caution is still\n");
735             printf("advised, however.\n\n");
736             break;
737 
738         case Reference:
739             printf("A function call is not being made here, but a reference is being made to a name\n");
740             printf("that is normally a vulnerable function.  It could be being assigned as a\n");
741             printf("pointer to function.\n\n");
742             break;
743 
744         case PythonBacktick:
745             printf("Do not use a variable that has been derived from untrusted sources within a backtick.\n");
746             printf("Doing so could allow an attacker to execute arbitrary python code\n\n");
747             break;
748 
749         case PhpBacktick:
750         case PerlBacktick:
751 		case RubyBacktick:
752             printf("The backtick will act just like an call to exec(), so care should be exercised that the\n");
753             printf(" string being backtick evaluated does not come from an untrusted source\n\n");
754             break;
755 
756         case None:
757             printf("Unknown!?!?\n\n");
758             break;
759     }
760 }
761 
762 static
html_report_inputs(void)763 void html_report_inputs(void)
764 {
765     int         count = 0;
766     input_t *   next;
767     input_t *   ptr;
768 
769     if (!(flags & INPUT_MODE))
770         return;
771 
772     for (ptr = input_head;  ptr != (input_t *)NULL;  ptr = next)
773     {
774         next = ptr->next;
775         if (!lookup_ignore(ptr->filename, ptr->lineno, ptr->data->Name))
776         {
777             count++;
778             printf("<b>%s</b>: Line %d: function %s<br>\n", ptr->filename, ptr->lineno, ptr->data->Name);
779         }
780         free(ptr);
781     }
782     input_head = input_tail = (input_t *)NULL;
783 
784     if (count > 0)
785     {
786         printf("<br>Double check to be sure that all input accepted from an external data source\n");
787         printf("does not exceed the limits of the variable being used to hold it. Also make\n");
788         printf("sure that the input cannot be used in such a manner as to alter your program's\n");
789 	    printf("behaviour in an undesirable way.<br>\n");
790     }
791 }
792 
793 static
xml_report_inputs(void)794 void xml_report_inputs(void)
795 {
796     int         count = 0;
797     input_t *   next;
798     input_t *   ptr;
799 
800     if (!(flags & INPUT_MODE))
801         return;
802 
803     for (ptr = input_head;  ptr != (input_t *)NULL;  ptr = next)
804     {
805         next = ptr->next;
806         if (!lookup_ignore(ptr->filename, ptr->lineno, ptr->data->Name))
807         {
808             count++;
809             printf("<input>\n");
810             printf("<message>");
811             printf("Double check to be sure that all input accepted from an external data source does not exceed the limits of the variable being used to hold it. Also make sure that the input cannot be used in such a manner as to alter your program's behaviour in an undesireable way");
812             printf("</message>\n") ;
813             printf("<function>%s</function>\n", ptr->data->Name);
814             printf("<file><name>%s</name><line>%d</line></file>\n", ptr->filename, ptr->lineno);
815             printf("</input>\n");
816         }
817         free(ptr);
818     }
819     input_head = input_tail = (input_t *)NULL;
820 
821 }
822 
823 
824 static
report_inputs(void)825 void report_inputs(void)
826 {
827     int         count = 0;
828     input_t *   next;
829     input_t *   ptr;
830 
831     if (!(flags & INPUT_MODE))
832         return;
833 
834     for (ptr = input_head;  ptr != (input_t *)NULL;  ptr = next)
835     {
836         next = ptr->next;
837         if (!lookup_ignore(ptr->filename, ptr->lineno, ptr->data->Name))
838         {
839             count++;
840             printf("%s: %d: %s\n", ptr->filename, ptr->lineno, ptr->data->Name);
841         }
842         free(ptr);
843     }
844     input_head = input_tail = (input_t *)NULL;
845 
846     if (count > 0)
847     {
848         printf("Double check to be sure that all input accepted from an external data source\n");
849         printf("does not exceed the limits of the variable being used to hold it.  Also make\n");
850         printf("sure that the input cannot be used in such a manner as to alter your program's\n");
851         printf("behaviour in an undesirable way.\n\n");
852     }
853 }
854 
generate_xml()855 void generate_xml() {
856   char vuln_reported=0;		/* Have we spewed the vuln message yet? */
857   vulnerability_t *   ptr;
858 
859   /* Initial necessary cruft */
860   /* Loop iterates through all of the problems found */
861   for (ptr = list_head;  ptr != (vulnerability_t *)NULL;  ptr = ptr->next) {
862 
863     /* Check the severity of the vuln.  If it's below our level, skip
864      * and go to the next one */
865     if (ptr->severity != Default && ptr->severity < warning_level) {
866       continue;
867     }
868 
869     if (determine_ignorance(ptr))
870     {
871       continue;
872     }
873 
874     /* If we haven't reported the vuln message yet for this type, do so. */
875     if(!vuln_reported) {
876       build_xml_vulnerability(ptr);
877       vuln_reported++;
878     }
879 
880     /* If the filename of this vuln is different from the filename of the
881      * previous vuln, report the filename, or if the vuln type is different*/
882     if(ptr->prev==(vulnerability_t *)NULL||
883        strcmp(ptr->filename,ptr->prev->filename)|| ptr->type == RaceConditionCheck ||
884        ptr->prev->type != ptr->type || ptr->prev->data != ptr->data) {
885       printf("  <file>\n    <name>%s</name>\n",
886 	     ptr->filename);
887     }
888 
889     /* report the line number of the infraction */
890     printf("    <line>%d</line>\n",
891 	   ptr->lineno);
892     if (flags & SHOW_COLUMNS)
893         printf("    <column>%d</column>\n", ptr->column);
894     if (flags & SHOW_CONTEXT)
895     {
896       char *ctx = NULL;
897       ctx = getctx(ptr->filename, ptr->lineno);
898       if (ctx)
899       {
900         ctx = xml_escape(ctx);
901         printf("<context>%s</context>\n", ctx);
902         free(ctx);
903       }
904     }
905 
906     /* If the next file or vuln type is different close the file tag */
907     if(ptr->next==(vulnerability_t *)NULL||
908        strcmp(ptr->filename,ptr->next->filename)|| ptr->type == RaceConditionCheck ||
909        ptr->next->type != ptr->type || ptr->next->data != ptr->data) {
910       printf("  </file>\n");
911     }
912 
913     /* If the next vuln is different reset the vuln_reported variable to 0 so
914      * we know to report next time */
915     if (ptr->next == (vulnerability_t *)NULL || ptr->next->type != ptr->type ||
916 	ptr->type == RaceConditionCheck || ptr->next->data != ptr->data) {
917       printf("</vulnerability>\n");
918       vuln_reported=0;
919     }
920 
921   }
922   xml_report_inputs();
923 
924  if (!(flags & NO_FOOTER))
925  {
926 #ifdef _MSC_VER
927 	DWORD ttime;
928 #else
929 	struct timeval ttime;
930 #endif
931 
932 	float fsecs;
933 
934 #ifdef _MSC_VER
935 	ttime = time_finished - time_started;
936 	fsecs = ttime/1000 + (float)((ttime%1000)/1000);
937 #else
938 	diff_times(&time_finished, &time_started, &ttime);
939 	fsecs = ttime.tv_sec+ (ttime.tv_usec/(double)1000000);
940 #endif
941     printf("<timing>\n");
942     printf("<total_lines>%d</total_lines>\n", total_lines);
943     printf("<total_time>%f</total_time>\n", fsecs);
944     printf("<lines_per_second>%d</lines_per_second>\n", (int)(total_lines/fsecs));
945     printf("</timing>\n");
946     }
947 
948   printf("</rats_output>\n");
949 
950 }
951 
build_html_vulnerability(vulnerability_t * ptr)952 static void build_html_vulnerability(vulnerability_t *ptr) {
953     int i;
954 
955     /* Debugging - robbat2@gentoo.org 21/05/2006 */
956     if(ptr->data == NULL)
957             debug_vuln_dump(ptr);
958 
959     /* Output the severity */
960     printf("  <b>Severity: %s</b><br/>\n",
961 	   severities[ptr->severity]);
962 
963     switch (ptr->type)
964     {
965     case BOProblem:
966       if (ptr->data->BOProblem->FormatArg > 0)
967 	{
968 	  printf("  Issue: %s<br/>\n",
969 		 ptr->data->Name);
970 	  printf("    Check to be sure that the format string passed as argument %d to this\n", ptr->data->BOProblem->FormatArg);
971 	  printf("    function call does not come from an untrusted source that could have added\n");
972 	  printf("    formatting characters that the code is not prepared to handle.\n");
973 	  printf("    Additionally, the format string could contain `%%s' without precision that\n");
974 	  printf("    could result in a buffer overflow.\n");
975 	  printf("  <br/>\n");
976 	}
977       if (ptr->data->BOProblem->SrcBufArg > 0)
978 	{
979 	  printf("  Issue: %s<br/>\n",
980 		 ptr->data->Name);
981 	  printf("    Check to be sure that argument %d passed to this function call will not\n", ptr->data->BOProblem->SrcBufArg);
982 	  printf("    copy more data than can be handled, resulting in a buffer overflow.\n");
983 	  printf("  <br/>\n");
984 	}
985       break;
986 
987     case FSProblem:
988       printf("  Issue: %s<br/>\n",
989 	     ptr->data->Name);
990       printf("    Check to be sure that the non-constant format string passed as argument %d \n", ptr->data->FSProblem->Arg);
991       printf("    to this function call does not come from an untrusted source that could\n");
992       printf("    have added formatting characters that the code is not prepared to handle.\n");
993       printf("  <br/>\n");
994       break;
995 
996     case InputProblem:
997       printf("  Issue: %s<br/>\n",
998 	     ptr->data->Name);
999       printf("    Argument %d to this function call should be checked to ensure that it does\n", ptr->data->InputProblem->Arg);
1000       printf("    not come from an untrusted source without first verifying that it contains\n");
1001       printf("    nothing dangerous.\n");
1002       printf("  <br/>\n");
1003       break;
1004 
1005     case Info:
1006       printf("  Issue: %s<br/>\n",
1007 	     ptr->data->Name);
1008       if (ptr->data->Info->Description != (char *)NULL) {
1009 	cleanup_string(ptr->data->Info->Description);
1010 	printf("    %s\n", ptr->data->Info->Description);
1011       }
1012       if (ptr->data->Info->URL != (char *)NULL)	{
1013 	cleanup_string(ptr->data->Info->URL);
1014 	/* This should possibly be made into it's own tag -- Robert */
1015 	printf("    See also:\n %s\n", ptr->data->Info->URL);
1016       }
1017       printf("  <br/>\n");
1018       break;
1019 
1020     case RaceConditionCheck:
1021       printf("  Issue: %s<br/>\n",
1022 	     ptr->data->Name);
1023       printf("    A potential TOCTOU (Time Of Check, Time Of Use) vulnerability exists.\n");
1024       printf("    This is the first line where a check has occured.");
1025       if (ptr->uses != (toctou_use_t *)NULL && ptr->uses[0].lineno != 0)
1026 	{
1027 	  printf("\n    The following line(s) contain uses that may match up with this check:\n");
1028 	  for (i = 0;  ptr->uses[i].lineno != 0;  i++)
1029 	    printf("    %s%d (%s)", (i == 0 ? "" : ", "), ptr->uses[i].lineno, ptr->uses[i].name);
1030 	  printf("\n");
1031 	}
1032       else
1033 	{
1034 	  printf("    No matching uses were detected.\n");
1035 	}
1036       printf("  <br/>\n");
1037       break;
1038 
1039     case RaceConditionUse:
1040       printf("  Issue: fixed size local buffer<br/>\n");
1041       printf("    A potential race condition vulnerability exists here.  Normally a call\n");
1042       printf("    to this function is vulnerable only when a match check precedes it.  No\n");
1043       printf("    check was detected, however one could still exist that could not be\n");
1044       printf("    detected.\n");
1045       printf("  <br/>\n");
1046       break;
1047 
1048     case StaticLocalBuffer:
1049       printf("  Issue: fixed size global buffer<br/>\n");
1050       printf("    Extra care should be taken to ensure that character arrays that are\n");
1051       printf("    allocated on the stack are used safely.  They are prime targets for\n");
1052       printf("    buffer overflow attacks.\n");
1053       printf("  <br/>\n");
1054       break;
1055 
1056     case StaticGlobalBuffer:
1057       printf("  Issue: %s<br/>\n",
1058 	     ptr->data->Name);
1059       printf("    Extra care should be taken to ensure that character arrays that are\n");
1060       printf("    allocated with a static size are used safely.  This appears to be a\n");
1061       printf("    global allocation and is less dangerous than a similar one on the stack.\n");
1062       printf("    Extra caution is still advised, however.\n");
1063       printf("  <br/>\n");
1064       break;
1065 
1066     case Reference:
1067       printf("  Issue: %s<br/>\n",
1068 	     ptr->data->Name);
1069       printf("    A function call is not being made here, but a reference is being made to\n");
1070       printf("    a name that is normally a vulnerable function.  It could be being\n");
1071       printf("    assigned as a pointer to function.\n\n");
1072       printf("  <br/>\n");
1073       break;
1074 
1075     case PythonBacktick:
1076       printf("  Issue: backtick<br/>\n");
1077       printf("    Do not use a variable that has been derived from untrusted sources\n");
1078       printf("    within a backtick.  Doing so could allow an attacker to execute\n");
1079       printf("    arbitrary python code.\n");
1080       printf("  <br/>\n");
1081       break;
1082 
1083     case PhpBacktick:
1084     case PerlBacktick:
1085 	case RubyBacktick:
1086       printf("  Issue: backtick<br/>\n");
1087       printf("    The backtick will act just like an call to exec(), so care should be\n");
1088       printf("    exercised that the string being backtick evaluated does not come from an\n");
1089       printf("    untrusted source.\n");
1090       printf("  <br/>\n");
1091       break;
1092 
1093     case None:
1094       printf("  Issue: %s<br/>\n",
1095 	     ptr->data->Name);
1096       printf("    Unknown!?!?\n\n");
1097       printf("  <br/>\n");
1098       break;
1099     }
1100 }
1101 
generate_html()1102 void generate_html() {
1103   char vuln_reported=0;		/* Have we spewed the vuln message yet? */
1104   vulnerability_t *   ptr;
1105 
1106   /* Initial necessary cruft */
1107   printf("<h2>RATS results.\n</h2><br>\n");
1108 
1109   /* Loop iterates through all of the problems found */
1110   for (ptr = list_head;  ptr != (vulnerability_t *)NULL;  ptr = ptr->next) {
1111 
1112     /* Check the severity of the vuln.  If it's below our level, skip
1113      * and go to the next one */
1114     if (ptr->severity != Default && ptr->severity < warning_level) {
1115       continue;
1116     }
1117 
1118     if (determine_ignorance(ptr))
1119     {
1120       continue;
1121     }
1122     /* If we haven't reported the vuln message yet for this type, do so. */
1123     if(!vuln_reported) {
1124       build_html_vulnerability(ptr);
1125       vuln_reported++;
1126     }
1127 
1128     /* If the filename of this vuln is different from the filename of the
1129      * previous vuln, report the filename, or if the vuln type is different*/
1130     if(ptr->prev==(vulnerability_t *)NULL||
1131        strcmp(ptr->filename,ptr->prev->filename)|| ptr->type == RaceConditionCheck ||
1132        ptr->prev->type != ptr->type || ptr->prev->data != ptr->data) {
1133        printf("<ul>\n");
1134        if (!(flags & SHOW_CONTEXT))
1135        {
1136          printf("File: <b>%s</b><br/>Lines: \n",
1137 	     ptr->filename);
1138        }
1139     }
1140 
1141     /* report the line number of the infraction */
1142    if (!(flags & SHOW_CONTEXT))
1143    {
1144       printf("%d",
1145 	   ptr->lineno);
1146       if (flags & SHOW_COLUMNS)
1147         printf("[%d]", ptr->column);
1148       printf(" ");
1149     } else {
1150       char *ctx = NULL;
1151       printf("File: <b>%s</b> Line:<b>%d", ptr->filename, ptr->lineno);
1152       if (flags & SHOW_COLUMNS)
1153         printf("[%d]", ptr->column);
1154       printf("</b><br>\n");
1155       ctx = getctx(ptr->filename, ptr->lineno);
1156       if(ctx)
1157       {
1158         printf("%s<br>\n", ctx);
1159         free(ctx);
1160       }
1161     }
1162 
1163 
1164 
1165 
1166     /* If the next file or vuln type is different close the file tag */
1167     if(ptr->next==(vulnerability_t *)NULL||
1168        strcmp(ptr->filename,ptr->next->filename)|| ptr->type == RaceConditionCheck ||
1169        ptr->next->type != ptr->type || ptr->next->data != ptr->data) {
1170       printf("  </ul>\n");
1171     }
1172 
1173     /* If the next vuln is different reset the vuln_reported variable to 0 so
1174      * we know to report next time */
1175     if (ptr->next == (vulnerability_t *)NULL || ptr->next->type != ptr->type ||
1176 	ptr->type == RaceConditionCheck || ptr->next->data != ptr->data) {
1177       vuln_reported=0;
1178     }
1179 
1180   }
1181 
1182 
1183   printf("<h3>Inputs detected at the following points</h3>\n");
1184 
1185   printf("<ul>\n");
1186   html_report_inputs();
1187   printf("</ul>\n");
1188 
1189   printf("<br><br>\n");
1190 
1191 
1192   if (!(flags & NO_FOOTER))
1193   {
1194 #ifdef _MSC_VER
1195 	DWORD ttime;
1196 #else
1197 	struct timeval ttime;
1198 #endif
1199 
1200 	float fsecs;
1201 
1202 #ifdef _MSC_VER
1203 	ttime = time_finished - time_started;
1204 	fsecs = ttime/1000 + (float)((ttime%1000)/1000);
1205 #else
1206 	diff_times(&time_finished, &time_started, &ttime);
1207 	fsecs = ttime.tv_sec+(ttime.tv_usec/(double)1000000);
1208 #endif
1209 
1210 
1211     printf("Total lines analyzed: <b>%d</b><br>\n", total_lines);
1212     printf("Total time <b>%f</b> seconds<br>\n", fsecs);
1213     printf("<b>%d</b> lines per second<br>\n", (int)(total_lines/fsecs));
1214     }
1215 
1216   printf("</body></html>\n");
1217 }
1218 
1219 
1220 static int
time_greater(const struct timeval * a,const struct timeval * b)1221 time_greater(const struct timeval *a, const struct timeval *b)
1222 {
1223   if(a->tv_sec > b->tv_sec || (a->tv_sec == b->tv_sec &&
1224                                a->tv_usec > b->tv_usec))
1225   {
1226     return 1;
1227   }
1228   return 0;
1229 }
1230 
1231 static void
diff_times(const struct timeval * a,const struct timeval * b,struct timeval * result)1232 diff_times(const struct timeval *a, const struct timeval *b,
1233                  struct timeval *result)
1234 {
1235   const struct timeval *bigger, *lesser;
1236 
1237   if(time_greater(a,b))
1238   {
1239     bigger = a; lesser = b;
1240   } else
1241   {
1242       bigger = b; lesser = a;
1243   }
1244   if(bigger->tv_usec < lesser->tv_usec)
1245   {
1246     result->tv_usec = 1000000 - lesser->tv_usec + bigger->tv_usec;
1247     result->tv_sec  = bigger->tv_sec - lesser->tv_sec - 1;
1248   }
1249   else
1250   {
1251     result->tv_usec = bigger->tv_usec - lesser->tv_usec;
1252     result->tv_sec  = bigger->tv_sec  - lesser->tv_sec;
1253   }
1254 }
1255 
1256 
1257 /* returns 1 if you should ignore this, 0 if not */
1258 static int
determine_ignorance(vulnerability_t * ptr)1259 determine_ignorance(vulnerability_t *ptr)
1260 {
1261 
1262     char *lookup = NULL;
1263 
1264     switch (ptr->type)
1265     {
1266         case BOProblem:
1267         case FSProblem:
1268         case Info:
1269         case InputProblem:
1270         case RaceConditionCheck:
1271         case RaceConditionUse:
1272             lookup = ptr->data->Name;
1273             break;
1274 
1275         case StaticLocalBuffer:
1276             lookup = "$fixed_buffer$";
1277             break;
1278 
1279         case StaticGlobalBuffer:
1280             lookup = "$global_buffer$";
1281             break;
1282 
1283         case Reference:
1284             lookup = ptr->data->Name;
1285             break;
1286 
1287         case PythonBacktick:
1288             lookup = "$python_backtick$";
1289             break;
1290 
1291         case PhpBacktick:
1292             lookup = "$php_backtick$";
1293             break;
1294 
1295         case PerlBacktick:
1296             lookup = "$perl_backtick$";
1297             break;
1298 		case RubyBacktick:
1299 			lookup = "$ruby_backtick$";
1300 			break;
1301 
1302         case None:
1303         default:
1304             lookup = (char *)NULL;
1305             break;
1306     }
1307     if (lookup != NULL)
1308     {
1309         if (lookup_ignore(ptr->filename, ptr->lineno, lookup))
1310         {
1311             return 1;
1312         }
1313     }
1314     return 0;
1315 }
1316 
1317 
generate_report()1318 void generate_report()
1319 {
1320     char *              name;
1321     char *              name2 = (char *)NULL;
1322     int   		doprint = 0;
1323     int			reported = 0;
1324     ignore_t *          iptr;
1325     ignore_t *          inext;
1326     vulnerability_t *   ptr;
1327     vulnerability_t *   next;
1328 
1329 
1330     for (ptr = list_head;  ptr != (vulnerability_t *)NULL;  ptr = ptr->next)
1331     {
1332         if (ptr->severity == Default || ptr->severity >= warning_level)
1333         {
1334             switch (ptr->type)
1335             {
1336                 case BOProblem:
1337                 case FSProblem:
1338                 case Info:
1339                 case InputProblem:
1340                 case RaceConditionCheck:
1341                 case RaceConditionUse:
1342                     name = ptr->data->Name;
1343                     break;
1344 
1345                 case StaticLocalBuffer:
1346                     name = "fixed size local buffer";
1347                     break;
1348 
1349                 case StaticGlobalBuffer:
1350                     name = "fixed size global buffer";
1351                     break;
1352 
1353                 case Reference:
1354                     name = "non-function call reference";
1355 
1356                     name2 = ptr->data->Name;
1357                     break;
1358 
1359                 case PythonBacktick:
1360                 case PhpBacktick:
1361                 case PerlBacktick:
1362 				case RubyBacktick:
1363 					name = "backtick";
1364 					break;
1365 
1366                 case None:
1367                 default:
1368                     name = "Unknown / Database Error";
1369                     break;
1370             }
1371             doprint = 1;
1372             if (determine_ignorance(ptr))
1373             {
1374               doprint =  0;
1375             }
1376 
1377             if (doprint)
1378             {
1379 	      if (name2 == (char *)NULL) {
1380                     printf("%s:%d", ptr->filename, ptr->lineno);
1381                     if (flags & SHOW_COLUMNS)
1382                         printf("[%d]", ptr->column);
1383                     printf(": %s: %s\n", severities[ptr->severity], name);
1384 	      }
1385 	      else {
1386                    printf("%s:%d", ptr->filename, ptr->lineno);
1387                     if (flags & SHOW_COLUMNS)
1388                         printf("[%d]", ptr->column);
1389                     printf(": %s: %s: %s\n", severities[ptr->severity], name, name2);
1390 
1391 	      }
1392 
1393              if (flags & SHOW_CONTEXT)
1394              {
1395                  char *ctx = NULL;
1396                  ctx = getctx(ptr->filename, ptr->lineno);
1397                  if (ctx)
1398                  {
1399                      printf("%s", ctx);
1400                      free(ctx);
1401                  }
1402               }
1403 	      reported++;
1404             }
1405 
1406             if (ptr->next == (vulnerability_t *)NULL || ptr->next->type != ptr->type ||
1407                 ptr->type == RaceConditionCheck || ptr->next->data != ptr->data)
1408             {
1409                 if (reported)
1410                     report_vulnerability(ptr);
1411             }
1412             if (ptr->next && (ptr->next->type != ptr->type))
1413               reported = 0;
1414 
1415         }
1416     }
1417 
1418     report_inputs();
1419 
1420     for (iptr = ignore_list;  iptr != (ignore_t *)NULL;  iptr = inext)
1421     {
1422         inext = iptr->next;
1423         if (iptr->token != (char *)NULL)
1424             free(iptr->token);
1425         free(iptr);
1426     }
1427     ignore_list = (ignore_t *)NULL;
1428 
1429     for (ptr = list_head;  ptr != (vulnerability_t *)NULL;  ptr = next)
1430     {
1431         next = ptr->next;
1432         free(ptr);
1433     }
1434     list_head = list_tail = (vulnerability_t *)NULL;
1435     if (!(flags & NO_FOOTER))
1436     {
1437 #ifdef _MSC_VER
1438 	DWORD ttime;
1439 #else
1440 	struct timeval ttime;
1441 #endif
1442 
1443 	float fsecs;
1444 
1445 #ifdef _MSC_VER
1446 	ttime = time_finished - time_started;
1447 	fsecs = ttime/1000 + (float)(ttime%1000)/1000;
1448 #else
1449 	diff_times(&time_finished, &time_started, &ttime);
1450 	fsecs = ttime.tv_sec+(ttime.tv_usec/(double)1000000);
1451 #endif
1452 
1453       printf("Total lines analyzed: %d\n", total_lines);
1454       printf("Total time %f seconds\n", fsecs);
1455       printf("%d lines per second\n", (int)(total_lines/fsecs));
1456     }
1457 }
1458 
new_ignore(int lineno,char * token)1459 ignore_t *new_ignore(int lineno, char *token)
1460 {
1461     ignore_t *  ign;
1462 
1463     if ((ign = (ignore_t *)malloc(sizeof(ignore_t))) == (ignore_t *)NULL)
1464         return (ignore_t *)NULL;
1465     ign->filename = current_file;
1466     ign->lineno   = lineno;
1467     ign->token    = (token == (char *)NULL ? token : strdup(token));
1468     ign->next     = ignore_list;
1469     ignore_list   = ign;
1470 
1471     return ign;
1472 }
1473 
1474 static
lookup_ignore(char * filename,int lineno,char * token)1475 int lookup_ignore(char *filename, int lineno, char *token)
1476 {
1477     ignore_t *  ptr;
1478 
1479     for (ptr = ignore_list;  ptr != (ignore_t *)NULL;  ptr = ptr->next)
1480     {
1481         if (ptr->filename != filename)  /* yes, this is safe and will work */
1482             continue;
1483         if (ptr->lineno != lineno)
1484             continue;
1485         if (ptr->token == (char *)NULL || !strcmp(ptr->token, token))
1486             return 1;
1487     }
1488 
1489     return 0;
1490 }
1491