Icinga-core 1.4.0
next gen monitoring
cgi/getcgi.c
Go to the documentation of this file.
00001 /*****************************************************************************
00002  *
00003  * GETCGI.C -  Icinga CGI Input Routines
00004  *
00005  * Copyright (c) 1999-2009 Ethan Galstad (egalstad@nagios.org)
00006  * Copyright (c) 2009-2011 Icinga Development Team (http://www.icinga.org)
00007  *
00008  * License:
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License version 2 as
00012  * published by the Free Software Foundation.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00022  *
00023  *****************************************************************************/
00024 
00025 #include "../include/config.h"
00026 #include "../include/getcgi.h"
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 
00030 
00031 #undef PARANOID_CGI_INPUT
00032 
00033 
00034 /* Remove potentially harmful characters from CGI input that we don't need or want */
00035 void sanitize_cgi_input(char **cgivars){
00036         char *strptr;
00037         int x,y,i;
00038         int keep;
00039 
00040         /* don't strip for now... */
00041         return;
00042 
00043         for(strptr=cgivars[i=0];strptr!=NULL;strptr=cgivars[++i]){
00044 
00045                 for(x=0,y=0;strptr[x]!='\x0';x++){
00046 
00047                         keep=1;
00048 
00049                         /* remove potentially nasty characters */
00050                         if(strptr[x]==';' || strptr[x]=='|' || strptr[x]=='&' || strptr[x]=='<' || strptr[x]=='>')
00051                                 keep=0;
00052 #ifdef PARANOID_CGI_INPUT
00053                         else if(strptr[x]=='/' || strptr[x]=='\\')
00054                                 keep=0;
00055 #endif
00056                         if(keep==1)
00057                                 strptr[y++]=strptr[x];
00058                         }
00059 
00060                 strptr[y]='\x0';
00061                 }
00062 
00063         return;
00064         }
00065 
00066 
00067 /* convert encoded hex string (2 characters representing an 8-bit number) to its ASCII char equivalent */
00068 unsigned char hex_to_char(char *input){
00069         unsigned char outchar='\x0';
00070         unsigned int outint;
00071         char tempbuf[3];
00072 
00073         /* NULL or empty string */
00074         if(input==NULL)
00075                 return '\x0';
00076         if(input[0]=='\x0')
00077                 return '\x0';
00078 
00079         tempbuf[0]=input[0];
00080         tempbuf[1]=input[1];
00081         tempbuf[2]='\x0';
00082 
00083         sscanf(tempbuf,"%X",&outint);
00084 
00085         /* only convert "normal" ASCII characters - we don't want the rest.  Normally you would
00086            convert all characters (i.e. for allowing users to post binary files), but since we
00087            aren't doing this, stay on the cautious side of things and reject outsiders... */
00088 #ifdef PARANOID_CGI_INPUT
00089         if(outint<32 || outint>126)
00090                 outint=0;
00091 #endif
00092 
00093         outchar=(unsigned char)outint;
00094 
00095         return outchar;
00096         }
00097 
00098 
00099 
00100 /* unescape hex characters in CGI input */
00101 void unescape_cgi_input(char *input){
00102         int x,y;
00103         int len;
00104 
00105         if(input==NULL)
00106                 return;
00107 
00108         len=strlen(input);
00109         for(x=0,y=0;x<len;x++,y++){
00110 
00111                 if(input[x]=='\x0')
00112                         break;
00113                 else if(input[x]=='%'){
00114                         input[y]=hex_to_char(&input[x+1]);
00115                         x+=2;
00116                         }
00117                 else
00118                         input[y]=input[x];
00119                 }
00120         input[y]='\x0';
00121 
00122         return;
00123         }
00124 
00125 
00126 
00127 /* read the CGI input and place all name/val pairs into list. returns list containing name1, value1, name2, value2, ... , NULL */
00128 /* this is a hacked version of a routine I found a long time ago somewhere - can't remember where anymore */
00129 char **getcgivars(void){
00130         register int i;
00131         char *request_method;
00132         char *content_type;
00133         char *content_length_string;
00134         int content_length;
00135         char *cgiinput;
00136         char **cgivars;
00137         char **pairlist;
00138         int paircount;
00139         char *nvpair;
00140         char *eqpos;
00141 
00142         /* initialize char variable(s) */
00143         cgiinput="";
00144 
00145         /* depending on the request method, read all CGI input into cgiinput */
00146 
00147         request_method=getenv("REQUEST_METHOD");
00148         if(request_method==NULL)
00149                 request_method="";
00150 
00151         if(!strcmp(request_method,"GET") || !strcmp(request_method,"HEAD")){
00152 
00153                 /* check for NULL query string environment variable - 04/28/00 (Ludo Bosmans) */
00154                 if(getenv("QUERY_STRING")==NULL){
00155                         cgiinput=(char *)malloc(1);
00156                         if(cgiinput==NULL){
00157                                 printf("getcgivars(): Could not allocate memory for CGI input.\n");
00158                                 exit(1);
00159                                 }
00160                         cgiinput[0]='\x0';
00161                         }
00162                 else
00163                         cgiinput=strdup(getenv("QUERY_STRING"));
00164                 }
00165 
00166         else if(!strcmp(request_method,"POST") || !strcmp(request_method,"PUT")){
00167 
00168                 /* if CONTENT_TYPE variable is not specified, RFC-2068 says we should assume it is "application/octet-string" */
00169                 /* mobile (WAP) stations generate CONTENT_TYPE with charset, we we should only check first 33 chars */
00170 
00171                 content_type=getenv("CONTENT_TYPE");
00172                 if(content_type==NULL)
00173                         content_type="";
00174 
00175                 if(strlen(content_type) && strncasecmp(content_type,"application/x-www-form-urlencoded",33)){
00176                         printf("getcgivars(): Unsupported Content-Type.\n");
00177                         exit(1);
00178                         }
00179 
00180                 content_length_string=getenv("CONTENT_LENGTH");
00181                 if(content_length_string==NULL)
00182                         content_length_string="0";
00183 
00184                 if(!(content_length=atoi(content_length_string))){
00185                         printf("getcgivars(): No Content-Length was sent with the POST request.\n") ;
00186                         exit(1);
00187                         }
00188                 /* suspicious content length */
00189                 if((content_length<0) || (content_length>=INT_MAX-1)){
00190                         printf("getcgivars(): Suspicious Content-Length was sent with the POST request.\n");
00191                         exit(1);
00192                         }
00193 
00194                 if(!(cgiinput=(char *)malloc(content_length+1))){
00195                         printf("getcgivars(): Could not allocate memory for CGI input.\n");
00196                         exit(1);
00197                         }
00198                 if(!fread(cgiinput,content_length,1,stdin)){
00199                         printf("getcgivars(): Could not read input from STDIN.\n");
00200                         exit(1);
00201                         }
00202                 cgiinput[content_length]='\0';
00203                 }
00204         else{
00205 
00206                 printf("getcgivars(): Unsupported REQUEST_METHOD -> '%s'\n",request_method);
00207                 printf("\n");
00208                 printf("I'm guessing you're trying to execute the CGI from a command line.\n");
00209                 printf("In order to do that, you need to set the REQUEST_METHOD environment\n");
00210                 printf("variable to either \"GET\", \"HEAD\", or \"POST\".  When using the\n");
00211                 printf("GET and HEAD methods, arguments can be passed to the CGI\n");
00212                 printf("by setting the \"QUERY_STRING\" environment variable.  If you're\n");
00213                 printf("using the POST method, data is read from standard input.  Also of\n");
00214                 printf("note: if you've enabled authentication in the CGIs, you must set the\n");
00215                 printf("\"REMOTE_USER\" environment variable to be the name of the user you're\n");
00216                 printf("\"authenticated\" as.\n");
00217                 printf("\n");
00218 
00219                 exit(1);
00220                 }
00221 
00222         /* change all plus signs back to spaces */
00223         for(i=0;cgiinput[i];i++){
00224                 if(cgiinput[i]=='+')
00225                         cgiinput[i]=' ';
00226                 }
00227 
00228         /* first, split on ampersands (&) to extract the name-value pairs into pairlist */
00229         /* allocate memory for 256 name-value pairs at a time, increasing by same
00230            amount as necessary... */
00231         pairlist=(char **)malloc(256*sizeof(char **));
00232         if(pairlist==NULL){
00233                 printf("getcgivars(): Could not allocate memory for name-value pairlist.\n");
00234                 exit(1);
00235                 }
00236         paircount=0;
00237         nvpair=strtok(cgiinput,"&");
00238         while(nvpair){
00239                 pairlist[paircount++]=strdup(nvpair);
00240                 if(!(paircount%256)){
00241                         pairlist=(char **)realloc(pairlist,(paircount+256)*sizeof(char **));
00242                         if(pairlist==NULL){
00243                                 printf("getcgivars(): Could not re-allocate memory for name-value pairlist.\n");
00244                                 exit(1);
00245                                 }
00246                         }
00247                 nvpair=strtok(NULL,"&");
00248                 }
00249 
00250         /* terminate the list */
00251         pairlist[paircount]='\x0';
00252 
00253         /* extract the names and values from the pairlist */
00254         cgivars=(char **)malloc((paircount*2+1)*sizeof(char **));
00255         if(cgivars==NULL){
00256                 printf("getcgivars(): Could not allocate memory for name-value list.\n");
00257                 exit(1);
00258                 }
00259         for(i=0;i<paircount;i++){
00260 
00261                 /* get the variable name preceding the equal (=) sign */
00262                 if((eqpos=strchr(pairlist[i],'='))!=NULL){
00263                         *eqpos='\0';
00264                         unescape_cgi_input(cgivars[i*2+1]=strdup(eqpos+1));
00265                         }
00266                 else
00267                         unescape_cgi_input(cgivars[i*2+1]=strdup(""));
00268 
00269                 /* get the variable value (or name/value of there was no real "pair" in the first place) */
00270                 unescape_cgi_input(cgivars[i*2]=strdup(pairlist[i]));
00271                 }
00272 
00273         /* terminate the name-value list */
00274         cgivars[paircount*2]='\x0';
00275 
00276         /* free allocated memory */
00277         free(cgiinput);
00278         for(i=0;pairlist[i]!=NULL;i++)
00279                 free(pairlist[i]);
00280         free(pairlist);
00281 
00282         /* sanitize the name-value strings */
00283         sanitize_cgi_input(cgivars);
00284 
00285         /* return the list of name-value strings */
00286         return cgivars;
00287         }
00288 
00289 
00290 
00291 /* free() memory allocated to storing the CGI variables */
00292 void free_cgivars(char **cgivars){
00293         register int x;
00294 
00295         for(x=0;cgivars[x]!='\x0';x++)
00296                 free(cgivars[x]);
00297 
00298         return;
00299         }
 All Data Structures Files Functions Variables Typedefs Defines