![]() |
Icinga-core 1.4.0
next gen monitoring
|
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 }