| 1 | /* 
 | 
|---|
| 2 |    some simple CGI helper routines
 | 
|---|
| 3 |    Copyright (C) Andrew Tridgell 1997-1998
 | 
|---|
| 4 |    
 | 
|---|
| 5 |    This program is free software; you can redistribute it and/or modify
 | 
|---|
| 6 |    it under the terms of the GNU General Public License as published by
 | 
|---|
| 7 |    the Free Software Foundation; either version 3 of the License, or
 | 
|---|
| 8 |    (at your option) any later version.
 | 
|---|
| 9 |    
 | 
|---|
| 10 |    This program is distributed in the hope that it will be useful,
 | 
|---|
| 11 |    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
| 12 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|---|
| 13 |    GNU General Public License for more details.
 | 
|---|
| 14 |    
 | 
|---|
| 15 |    You should have received a copy of the GNU General Public License
 | 
|---|
| 16 |    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
|---|
| 17 | */
 | 
|---|
| 18 | 
 | 
|---|
| 19 | 
 | 
|---|
| 20 | #include "includes.h"
 | 
|---|
| 21 | #include "web/swat_proto.h"
 | 
|---|
| 22 | 
 | 
|---|
| 23 | #define MAX_VARIABLES 10000
 | 
|---|
| 24 | 
 | 
|---|
| 25 | /* set the expiry on fixed pages */
 | 
|---|
| 26 | #define EXPIRY_TIME (60*60*24*7)
 | 
|---|
| 27 | 
 | 
|---|
| 28 | #ifdef DEBUG_COMMENTS
 | 
|---|
| 29 | extern void print_title(char *fmt, ...);
 | 
|---|
| 30 | #endif
 | 
|---|
| 31 | 
 | 
|---|
| 32 | struct cgi_var {
 | 
|---|
| 33 |         char *name;
 | 
|---|
| 34 |         char *value;
 | 
|---|
| 35 | };
 | 
|---|
| 36 | 
 | 
|---|
| 37 | static struct cgi_var variables[MAX_VARIABLES];
 | 
|---|
| 38 | static int num_variables;
 | 
|---|
| 39 | static int content_length;
 | 
|---|
| 40 | static int request_post;
 | 
|---|
| 41 | static char *query_string;
 | 
|---|
| 42 | static const char *baseurl;
 | 
|---|
| 43 | static char *pathinfo;
 | 
|---|
| 44 | static char *C_user;
 | 
|---|
| 45 | static bool inetd_server;
 | 
|---|
| 46 | static bool got_request;
 | 
|---|
| 47 | 
 | 
|---|
| 48 | static char *grab_line(FILE *f, int *cl)
 | 
|---|
| 49 | {
 | 
|---|
| 50 |         char *ret = NULL;
 | 
|---|
| 51 |         int i = 0;
 | 
|---|
| 52 |         int len = 0;
 | 
|---|
| 53 | 
 | 
|---|
| 54 |         while ((*cl)) {
 | 
|---|
| 55 |                 int c;
 | 
|---|
| 56 |         
 | 
|---|
| 57 |                 if (i == len) {
 | 
|---|
| 58 |                         char *ret2;
 | 
|---|
| 59 |                         if (len == 0) len = 1024;
 | 
|---|
| 60 |                         else len *= 2;
 | 
|---|
| 61 |                         ret2 = (char *)SMB_REALLOC_KEEP_OLD_ON_ERROR(ret, len);
 | 
|---|
| 62 |                         if (!ret2) return ret;
 | 
|---|
| 63 |                         ret = ret2;
 | 
|---|
| 64 |                 }
 | 
|---|
| 65 |         
 | 
|---|
| 66 |                 c = fgetc(f);
 | 
|---|
| 67 |                 (*cl)--;
 | 
|---|
| 68 | 
 | 
|---|
| 69 |                 if (c == EOF) {
 | 
|---|
| 70 |                         (*cl) = 0;
 | 
|---|
| 71 |                         break;
 | 
|---|
| 72 |                 }
 | 
|---|
| 73 |                 
 | 
|---|
| 74 |                 if (c == '\r') continue;
 | 
|---|
| 75 | 
 | 
|---|
| 76 |                 if (strchr_m("\n&", c)) break;
 | 
|---|
| 77 | 
 | 
|---|
| 78 |                 ret[i++] = c;
 | 
|---|
| 79 | 
 | 
|---|
| 80 |         }
 | 
|---|
| 81 |         
 | 
|---|
| 82 |         if (ret) {
 | 
|---|
| 83 |                 ret[i] = 0;
 | 
|---|
| 84 |         }
 | 
|---|
| 85 |         return ret;
 | 
|---|
| 86 | }
 | 
|---|
| 87 | 
 | 
|---|
| 88 | /**
 | 
|---|
| 89 |  URL encoded strings can have a '+', which should be replaced with a space
 | 
|---|
| 90 | 
 | 
|---|
| 91 |  (This was in rfc1738_unescape(), but that broke the squid helper)
 | 
|---|
| 92 | **/
 | 
|---|
| 93 | 
 | 
|---|
| 94 | static void plus_to_space_unescape(char *buf)
 | 
|---|
| 95 | {
 | 
|---|
| 96 |         char *p=buf;
 | 
|---|
| 97 | 
 | 
|---|
| 98 |         while ((p=strchr_m(p,'+')))
 | 
|---|
| 99 |                 *p = ' ';
 | 
|---|
| 100 | }
 | 
|---|
| 101 | 
 | 
|---|
| 102 | /***************************************************************************
 | 
|---|
| 103 |   load all the variables passed to the CGI program. May have multiple variables
 | 
|---|
| 104 |   with the same name and the same or different values. Takes a file parameter
 | 
|---|
| 105 |   for simulating CGI invocation eg loading saved preferences.
 | 
|---|
| 106 |   ***************************************************************************/
 | 
|---|
| 107 | void cgi_load_variables(void)
 | 
|---|
| 108 | {
 | 
|---|
| 109 |         static char *line;
 | 
|---|
| 110 |         char *p, *s, *tok;
 | 
|---|
| 111 |         int len, i;
 | 
|---|
| 112 |         FILE *f = stdin;
 | 
|---|
| 113 | 
 | 
|---|
| 114 | #ifdef DEBUG_COMMENTS
 | 
|---|
| 115 |         char dummy[100]="";
 | 
|---|
| 116 |         print_title(dummy);
 | 
|---|
| 117 |         d_printf("<!== Start dump in cgi_load_variables() %s ==>\n",__FILE__);
 | 
|---|
| 118 | #endif
 | 
|---|
| 119 | 
 | 
|---|
| 120 |         if (!content_length) {
 | 
|---|
| 121 |                 p = getenv("CONTENT_LENGTH");
 | 
|---|
| 122 |                 len = p?atoi(p):0;
 | 
|---|
| 123 |         } else {
 | 
|---|
| 124 |                 len = content_length;
 | 
|---|
| 125 |         }
 | 
|---|
| 126 | 
 | 
|---|
| 127 | 
 | 
|---|
| 128 |         if (len > 0 && 
 | 
|---|
| 129 |             (request_post ||
 | 
|---|
| 130 |              ((s=getenv("REQUEST_METHOD")) && 
 | 
|---|
| 131 |               strequal(s,"POST")))) {
 | 
|---|
| 132 |                 while (len && (line=grab_line(f, &len))) {
 | 
|---|
| 133 |                         p = strchr_m(line,'=');
 | 
|---|
| 134 |                         if (!p) continue;
 | 
|---|
| 135 |                         
 | 
|---|
| 136 |                         *p = 0;
 | 
|---|
| 137 |                         
 | 
|---|
| 138 |                         variables[num_variables].name = SMB_STRDUP(line);
 | 
|---|
| 139 |                         variables[num_variables].value = SMB_STRDUP(p+1);
 | 
|---|
| 140 | 
 | 
|---|
| 141 |                         SAFE_FREE(line);
 | 
|---|
| 142 |                         
 | 
|---|
| 143 |                         if (!variables[num_variables].name || 
 | 
|---|
| 144 |                             !variables[num_variables].value)
 | 
|---|
| 145 |                                 continue;
 | 
|---|
| 146 | 
 | 
|---|
| 147 |                         plus_to_space_unescape(variables[num_variables].value);
 | 
|---|
| 148 |                         rfc1738_unescape(variables[num_variables].value);
 | 
|---|
| 149 |                         plus_to_space_unescape(variables[num_variables].name);
 | 
|---|
| 150 |                         rfc1738_unescape(variables[num_variables].name);
 | 
|---|
| 151 | 
 | 
|---|
| 152 | #ifdef DEBUG_COMMENTS
 | 
|---|
| 153 |                         printf("<!== POST var %s has value \"%s\"  ==>\n",
 | 
|---|
| 154 |                                variables[num_variables].name,
 | 
|---|
| 155 |                                variables[num_variables].value);
 | 
|---|
| 156 | #endif
 | 
|---|
| 157 |                         
 | 
|---|
| 158 |                         num_variables++;
 | 
|---|
| 159 |                         if (num_variables == MAX_VARIABLES) break;
 | 
|---|
| 160 |                 }
 | 
|---|
| 161 |         }
 | 
|---|
| 162 | 
 | 
|---|
| 163 |         fclose(stdin);
 | 
|---|
| 164 |         open("/dev/null", O_RDWR);
 | 
|---|
| 165 | 
 | 
|---|
| 166 |         if ((s=query_string) || (s=getenv("QUERY_STRING"))) {
 | 
|---|
| 167 |                 char *saveptr;
 | 
|---|
| 168 |                 for (tok=strtok_r(s, "&;", &saveptr); tok;
 | 
|---|
| 169 |                      tok=strtok_r(NULL, "&;", &saveptr)) {
 | 
|---|
| 170 |                         p = strchr_m(tok,'=');
 | 
|---|
| 171 |                         if (!p) continue;
 | 
|---|
| 172 |                         
 | 
|---|
| 173 |                         *p = 0;
 | 
|---|
| 174 |                         
 | 
|---|
| 175 |                         variables[num_variables].name = SMB_STRDUP(tok);
 | 
|---|
| 176 |                         variables[num_variables].value = SMB_STRDUP(p+1);
 | 
|---|
| 177 | 
 | 
|---|
| 178 |                         if (!variables[num_variables].name ||
 | 
|---|
| 179 |                             !variables[num_variables].value)
 | 
|---|
| 180 |                                 continue;
 | 
|---|
| 181 | 
 | 
|---|
| 182 |                         plus_to_space_unescape(variables[num_variables].value);
 | 
|---|
| 183 |                         rfc1738_unescape(variables[num_variables].value);
 | 
|---|
| 184 |                         plus_to_space_unescape(variables[num_variables].name);
 | 
|---|
| 185 |                         rfc1738_unescape(variables[num_variables].name);
 | 
|---|
| 186 | 
 | 
|---|
| 187 | #ifdef DEBUG_COMMENTS
 | 
|---|
| 188 |                         printf("<!== Commandline var %s has value \"%s\"  ==>\n",
 | 
|---|
| 189 |                                variables[num_variables].name,
 | 
|---|
| 190 |                                variables[num_variables].value);
 | 
|---|
| 191 | #endif
 | 
|---|
| 192 |                         num_variables++;
 | 
|---|
| 193 |                         if (num_variables == MAX_VARIABLES) break;
 | 
|---|
| 194 |                 }
 | 
|---|
| 195 | 
 | 
|---|
| 196 |         }
 | 
|---|
| 197 | #ifdef DEBUG_COMMENTS
 | 
|---|
| 198 |         printf("<!== End dump in cgi_load_variables() ==>\n");
 | 
|---|
| 199 | #endif
 | 
|---|
| 200 | 
 | 
|---|
| 201 |         /* variables from the client are in UTF-8 - convert them
 | 
|---|
| 202 |            to our internal unix charset before use */
 | 
|---|
| 203 |         for (i=0;i<num_variables;i++) {
 | 
|---|
| 204 |                 TALLOC_CTX *frame = talloc_stackframe();
 | 
|---|
| 205 |                 char *dest = NULL;
 | 
|---|
| 206 |                 size_t dest_len;
 | 
|---|
| 207 | 
 | 
|---|
| 208 |                 convert_string_talloc(frame, CH_UTF8, CH_UNIX,
 | 
|---|
| 209 |                                variables[i].name, strlen(variables[i].name),
 | 
|---|
| 210 |                                &dest, &dest_len, True);
 | 
|---|
| 211 |                 SAFE_FREE(variables[i].name);
 | 
|---|
| 212 |                 variables[i].name = SMB_STRDUP(dest ? dest : "");
 | 
|---|
| 213 | 
 | 
|---|
| 214 |                 dest = NULL;
 | 
|---|
| 215 |                 convert_string_talloc(frame, CH_UTF8, CH_UNIX,
 | 
|---|
| 216 |                                variables[i].value, strlen(variables[i].value),
 | 
|---|
| 217 |                                &dest, &dest_len, True);
 | 
|---|
| 218 |                 SAFE_FREE(variables[i].value);
 | 
|---|
| 219 |                 variables[i].value = SMB_STRDUP(dest ? dest : "");
 | 
|---|
| 220 |                 TALLOC_FREE(frame);
 | 
|---|
| 221 |         }
 | 
|---|
| 222 | }
 | 
|---|
| 223 | 
 | 
|---|
| 224 | 
 | 
|---|
| 225 | /***************************************************************************
 | 
|---|
| 226 |   find a variable passed via CGI
 | 
|---|
| 227 |   Doesn't quite do what you think in the case of POST text variables, because
 | 
|---|
| 228 |   if they exist they might have a value of "" or even " ", depending on the
 | 
|---|
| 229 |   browser. Also doesn't allow for variables[] containing multiple variables
 | 
|---|
| 230 |   with the same name and the same or different values.
 | 
|---|
| 231 |   ***************************************************************************/
 | 
|---|
| 232 | 
 | 
|---|
| 233 | const char *cgi_variable(const char *name)
 | 
|---|
| 234 | {
 | 
|---|
| 235 |         int i;
 | 
|---|
| 236 | 
 | 
|---|
| 237 |         for (i=0;i<num_variables;i++)
 | 
|---|
| 238 |                 if (strcmp(variables[i].name, name) == 0)
 | 
|---|
| 239 |                         return variables[i].value;
 | 
|---|
| 240 |         return NULL;
 | 
|---|
| 241 | }
 | 
|---|
| 242 | 
 | 
|---|
| 243 | /***************************************************************************
 | 
|---|
| 244 |  Version of the above that can't return a NULL pointer.
 | 
|---|
| 245 | ***************************************************************************/
 | 
|---|
| 246 | 
 | 
|---|
| 247 | const char *cgi_variable_nonull(const char *name)
 | 
|---|
| 248 | {
 | 
|---|
| 249 |         const char *var = cgi_variable(name);
 | 
|---|
| 250 |         if (var) {
 | 
|---|
| 251 |                 return var;
 | 
|---|
| 252 |         } else {
 | 
|---|
| 253 |                 return "";
 | 
|---|
| 254 |         }
 | 
|---|
| 255 | }
 | 
|---|
| 256 | 
 | 
|---|
| 257 | /***************************************************************************
 | 
|---|
| 258 | tell a browser about a fatal error in the http processing
 | 
|---|
| 259 |   ***************************************************************************/
 | 
|---|
| 260 | static void cgi_setup_error(const char *err, const char *header, const char *info)
 | 
|---|
| 261 | {
 | 
|---|
| 262 |         if (!got_request) {
 | 
|---|
| 263 |                 /* damn browsers don't like getting cut off before they give a request */
 | 
|---|
| 264 |                 char line[1024];
 | 
|---|
| 265 |                 while (fgets(line, sizeof(line)-1, stdin)) {
 | 
|---|
| 266 |                         if (strnequal(line,"GET ", 4) || 
 | 
|---|
| 267 |                             strnequal(line,"POST ", 5) ||
 | 
|---|
| 268 |                             strnequal(line,"PUT ", 4)) {
 | 
|---|
| 269 |                                 break;
 | 
|---|
| 270 |                         }
 | 
|---|
| 271 |                 }
 | 
|---|
| 272 |         }
 | 
|---|
| 273 | 
 | 
|---|
| 274 |         d_printf("HTTP/1.0 %s\r\n%sConnection: close\r\nContent-Type: text/html\r\n\r\n<HTML><HEAD><TITLE>%s</TITLE></HEAD><BODY><H1>%s</H1>%s<p></BODY></HTML>\r\n\r\n", err, header, err, err, info);
 | 
|---|
| 275 |         fclose(stdin);
 | 
|---|
| 276 |         fclose(stdout);
 | 
|---|
| 277 |         exit(0);
 | 
|---|
| 278 | }
 | 
|---|
| 279 | 
 | 
|---|
| 280 | 
 | 
|---|
| 281 | /***************************************************************************
 | 
|---|
| 282 | tell a browser about a fatal authentication error
 | 
|---|
| 283 |   ***************************************************************************/
 | 
|---|
| 284 | static void cgi_auth_error(void)
 | 
|---|
| 285 | {
 | 
|---|
| 286 |         if (inetd_server) {
 | 
|---|
| 287 |                 cgi_setup_error("401 Authorization Required", 
 | 
|---|
| 288 |                                 "WWW-Authenticate: Basic realm=\"SWAT\"\r\n",
 | 
|---|
| 289 |                                 "You must be authenticated to use this service");
 | 
|---|
| 290 |         } else {
 | 
|---|
| 291 |                 printf("Content-Type: text/html\r\n");
 | 
|---|
| 292 | 
 | 
|---|
| 293 |                 printf("\r\n<HTML><HEAD><TITLE>SWAT</TITLE></HEAD>\n");
 | 
|---|
| 294 |                 printf("<BODY><H1>Installation Error</H1>\n");
 | 
|---|
| 295 |                 printf("SWAT must be installed via inetd. It cannot be run as a CGI script<p>\n");
 | 
|---|
| 296 |                 printf("</BODY></HTML>\r\n");
 | 
|---|
| 297 |         }
 | 
|---|
| 298 |         exit(0);
 | 
|---|
| 299 | }
 | 
|---|
| 300 | 
 | 
|---|
| 301 | /***************************************************************************
 | 
|---|
| 302 | authenticate when we are running as a CGI
 | 
|---|
| 303 |   ***************************************************************************/
 | 
|---|
| 304 | static void cgi_web_auth(void)
 | 
|---|
| 305 | {
 | 
|---|
| 306 |         const char *user = getenv("REMOTE_USER");
 | 
|---|
| 307 |         struct passwd *pwd;
 | 
|---|
| 308 |         const char *head = "Content-Type: text/html\r\n\r\n<HTML><BODY><H1>SWAT installation Error</H1>\n";
 | 
|---|
| 309 |         const char *tail = "</BODY></HTML>\r\n";
 | 
|---|
| 310 | 
 | 
|---|
| 311 |         if (!user) {
 | 
|---|
| 312 |                 printf("%sREMOTE_USER not set. Not authenticated by web server.<br>%s\n",
 | 
|---|
| 313 |                        head, tail);
 | 
|---|
| 314 |                 exit(0);
 | 
|---|
| 315 |         }
 | 
|---|
| 316 | 
 | 
|---|
| 317 |         pwd = getpwnam_alloc(talloc_autofree_context(), user);
 | 
|---|
| 318 |         if (!pwd) {
 | 
|---|
| 319 |                 printf("%sCannot find user %s<br>%s\n", head, user, tail);
 | 
|---|
| 320 |                 exit(0);
 | 
|---|
| 321 |         }
 | 
|---|
| 322 | 
 | 
|---|
| 323 |         setuid(0);
 | 
|---|
| 324 |         setuid(pwd->pw_uid);
 | 
|---|
| 325 |         if (geteuid() != pwd->pw_uid || getuid() != pwd->pw_uid) {
 | 
|---|
| 326 |                 printf("%sFailed to become user %s - uid=%d/%d<br>%s\n", 
 | 
|---|
| 327 |                        head, user, (int)geteuid(), (int)getuid(), tail);
 | 
|---|
| 328 |                 exit(0);
 | 
|---|
| 329 |         }
 | 
|---|
| 330 |         TALLOC_FREE(pwd);
 | 
|---|
| 331 | }
 | 
|---|
| 332 | 
 | 
|---|
| 333 | 
 | 
|---|
| 334 | /***************************************************************************
 | 
|---|
| 335 | handle a http authentication line
 | 
|---|
| 336 |   ***************************************************************************/
 | 
|---|
| 337 | static bool cgi_handle_authorization(char *line)
 | 
|---|
| 338 | {
 | 
|---|
| 339 |         char *p;
 | 
|---|
| 340 |         fstring user, user_pass;
 | 
|---|
| 341 |         struct passwd *pass = NULL;
 | 
|---|
| 342 | 
 | 
|---|
| 343 |         if (!strnequal(line,"Basic ", 6)) {
 | 
|---|
| 344 |                 goto err;
 | 
|---|
| 345 |         }
 | 
|---|
| 346 |         line += 6;
 | 
|---|
| 347 |         while (line[0] == ' ') line++;
 | 
|---|
| 348 |         base64_decode_inplace(line);
 | 
|---|
| 349 |         if (!(p=strchr_m(line,':'))) {
 | 
|---|
| 350 |                 /*
 | 
|---|
| 351 |                  * Always give the same error so a cracker
 | 
|---|
| 352 |                  * cannot tell why we fail.
 | 
|---|
| 353 |                  */
 | 
|---|
| 354 |                 goto err;
 | 
|---|
| 355 |         }
 | 
|---|
| 356 |         *p = 0;
 | 
|---|
| 357 | 
 | 
|---|
| 358 |         convert_string(CH_UTF8, CH_UNIX, 
 | 
|---|
| 359 |                        line, -1, 
 | 
|---|
| 360 |                        user, sizeof(user), True);
 | 
|---|
| 361 | 
 | 
|---|
| 362 |         convert_string(CH_UTF8, CH_UNIX, 
 | 
|---|
| 363 |                        p+1, -1, 
 | 
|---|
| 364 |                        user_pass, sizeof(user_pass), True);
 | 
|---|
| 365 | 
 | 
|---|
| 366 |         /*
 | 
|---|
| 367 |          * Try and get the user from the UNIX password file.
 | 
|---|
| 368 |          */
 | 
|---|
| 369 |         
 | 
|---|
| 370 |         pass = getpwnam_alloc(talloc_autofree_context(), user);
 | 
|---|
| 371 |         
 | 
|---|
| 372 |         /*
 | 
|---|
| 373 |          * Validate the password they have given.
 | 
|---|
| 374 |          */
 | 
|---|
| 375 |         
 | 
|---|
| 376 |         if NT_STATUS_IS_OK(pass_check(pass, user, user_pass, 
 | 
|---|
| 377 |                       strlen(user_pass), NULL, False)) {
 | 
|---|
| 378 |                 
 | 
|---|
| 379 |                 if (pass) {
 | 
|---|
| 380 |                         /*
 | 
|---|
| 381 |                          * Password was ok.
 | 
|---|
| 382 |                          */
 | 
|---|
| 383 |                         
 | 
|---|
| 384 |                         if ( initgroups(pass->pw_name, pass->pw_gid) != 0 )
 | 
|---|
| 385 |                                 goto err;
 | 
|---|
| 386 | 
 | 
|---|
| 387 |                         become_user_permanently(pass->pw_uid, pass->pw_gid);
 | 
|---|
| 388 |                         
 | 
|---|
| 389 |                         /* Save the users name */
 | 
|---|
| 390 |                         C_user = SMB_STRDUP(user);
 | 
|---|
| 391 |                         TALLOC_FREE(pass);
 | 
|---|
| 392 |                         return True;
 | 
|---|
| 393 |                 }
 | 
|---|
| 394 |         }
 | 
|---|
| 395 |         
 | 
|---|
| 396 | err:
 | 
|---|
| 397 |         cgi_setup_error("401 Bad Authorization", 
 | 
|---|
| 398 |                         "WWW-Authenticate: Basic realm=\"SWAT\"\r\n",
 | 
|---|
| 399 |                         "username or password incorrect");
 | 
|---|
| 400 | 
 | 
|---|
| 401 |         TALLOC_FREE(pass);
 | 
|---|
| 402 |         return False;
 | 
|---|
| 403 | }
 | 
|---|
| 404 | 
 | 
|---|
| 405 | /***************************************************************************
 | 
|---|
| 406 | is this root?
 | 
|---|
| 407 |   ***************************************************************************/
 | 
|---|
| 408 | bool am_root(void)
 | 
|---|
| 409 | {
 | 
|---|
| 410 |         if (geteuid() == 0) {
 | 
|---|
| 411 |                 return( True);
 | 
|---|
| 412 |         } else {
 | 
|---|
| 413 |                 return( False);
 | 
|---|
| 414 |         }
 | 
|---|
| 415 | }
 | 
|---|
| 416 | 
 | 
|---|
| 417 | /***************************************************************************
 | 
|---|
| 418 | return a ptr to the users name
 | 
|---|
| 419 |   ***************************************************************************/
 | 
|---|
| 420 | char *cgi_user_name(void)
 | 
|---|
| 421 | {
 | 
|---|
| 422 |         return(C_user);
 | 
|---|
| 423 | }
 | 
|---|
| 424 | 
 | 
|---|
| 425 | 
 | 
|---|
| 426 | /***************************************************************************
 | 
|---|
| 427 | handle a file download
 | 
|---|
| 428 |   ***************************************************************************/
 | 
|---|
| 429 | static void cgi_download(char *file)
 | 
|---|
| 430 | {
 | 
|---|
| 431 |         SMB_STRUCT_STAT st;
 | 
|---|
| 432 |         char buf[1024];
 | 
|---|
| 433 |         int fd, l, i;
 | 
|---|
| 434 |         char *p;
 | 
|---|
| 435 |         char *lang;
 | 
|---|
| 436 | 
 | 
|---|
| 437 |         /* sanitise the filename */
 | 
|---|
| 438 |         for (i=0;file[i];i++) {
 | 
|---|
| 439 |                 if (!isalnum((int)file[i]) && !strchr_m("/.-_", file[i])) {
 | 
|---|
| 440 |                         cgi_setup_error("404 File Not Found","",
 | 
|---|
| 441 |                                         "Illegal character in filename");
 | 
|---|
| 442 |                 }
 | 
|---|
| 443 |         }
 | 
|---|
| 444 | 
 | 
|---|
| 445 |         if (sys_stat(file, &st, false) != 0)    {
 | 
|---|
| 446 |                 cgi_setup_error("404 File Not Found","",
 | 
|---|
| 447 |                                 "The requested file was not found");
 | 
|---|
| 448 |         }
 | 
|---|
| 449 | 
 | 
|---|
| 450 |         if (S_ISDIR(st.st_ex_mode))
 | 
|---|
| 451 |         {
 | 
|---|
| 452 |                 snprintf(buf, sizeof(buf), "%s/index.html", file);
 | 
|---|
| 453 |                 if (!file_exist_stat(buf, &st, false)
 | 
|---|
| 454 |                     || !S_ISREG(st.st_ex_mode))
 | 
|---|
| 455 |                 {
 | 
|---|
| 456 |                         cgi_setup_error("404 File Not Found","",
 | 
|---|
| 457 |                                         "The requested file was not found");
 | 
|---|
| 458 |                 }
 | 
|---|
| 459 |         }
 | 
|---|
| 460 |         else if (S_ISREG(st.st_ex_mode))
 | 
|---|
| 461 |         {
 | 
|---|
| 462 |                 snprintf(buf, sizeof(buf), "%s", file);
 | 
|---|
| 463 |         }
 | 
|---|
| 464 |         else
 | 
|---|
| 465 |         {
 | 
|---|
| 466 |                 cgi_setup_error("404 File Not Found","",
 | 
|---|
| 467 |                                 "The requested file was not found");
 | 
|---|
| 468 |         }
 | 
|---|
| 469 | 
 | 
|---|
| 470 |         fd = web_open(buf,O_RDONLY,0);
 | 
|---|
| 471 |         if (fd == -1) {
 | 
|---|
| 472 |                 cgi_setup_error("404 File Not Found","",
 | 
|---|
| 473 |                                 "The requested file was not found");
 | 
|---|
| 474 |         }
 | 
|---|
| 475 |         printf("HTTP/1.0 200 OK\r\n");
 | 
|---|
| 476 |         if ((p=strrchr_m(buf, '.'))) {
 | 
|---|
| 477 |                 if (strcmp(p,".gif")==0) {
 | 
|---|
| 478 |                         printf("Content-Type: image/gif\r\n");
 | 
|---|
| 479 |                 } else if (strcmp(p,".jpg")==0) {
 | 
|---|
| 480 |                         printf("Content-Type: image/jpeg\r\n");
 | 
|---|
| 481 |                 } else if (strcmp(p,".png")==0) {
 | 
|---|
| 482 |                         printf("Content-Type: image/png\r\n");
 | 
|---|
| 483 |                 } else if (strcmp(p,".css")==0) {
 | 
|---|
| 484 |                         printf("Content-Type: text/css\r\n");
 | 
|---|
| 485 |                 } else if (strcmp(p,".txt")==0) {
 | 
|---|
| 486 |                         printf("Content-Type: text/plain\r\n");
 | 
|---|
| 487 |                 } else {
 | 
|---|
| 488 |                         printf("Content-Type: text/html\r\n");
 | 
|---|
| 489 |                 }
 | 
|---|
| 490 |         }
 | 
|---|
| 491 |         printf("Expires: %s\r\n", 
 | 
|---|
| 492 |                    http_timestring(talloc_tos(), time(NULL)+EXPIRY_TIME));
 | 
|---|
| 493 | 
 | 
|---|
| 494 |         lang = lang_tdb_current();
 | 
|---|
| 495 |         if (lang) {
 | 
|---|
| 496 |                 printf("Content-Language: %s\r\n", lang);
 | 
|---|
| 497 |         }
 | 
|---|
| 498 | 
 | 
|---|
| 499 |         printf("Content-Length: %d\r\n\r\n", (int)st.st_ex_size);
 | 
|---|
| 500 |         while ((l=read(fd,buf,sizeof(buf)))>0) {
 | 
|---|
| 501 |                 if (fwrite(buf, 1, l, stdout) != l) {
 | 
|---|
| 502 |                         break;
 | 
|---|
| 503 |                 }
 | 
|---|
| 504 |         }
 | 
|---|
| 505 |         close(fd);
 | 
|---|
| 506 |         exit(0);
 | 
|---|
| 507 | }
 | 
|---|
| 508 | 
 | 
|---|
| 509 | 
 | 
|---|
| 510 | 
 | 
|---|
| 511 | 
 | 
|---|
| 512 | /**
 | 
|---|
| 513 |  * @brief Setup the CGI framework.
 | 
|---|
| 514 |  *
 | 
|---|
| 515 |  * Setup the cgi framework, handling the possibility that this program
 | 
|---|
| 516 |  * is either run as a true CGI program with a gateway to a web server, or
 | 
|---|
| 517 |  * is itself a mini web server.
 | 
|---|
| 518 |  **/
 | 
|---|
| 519 | void cgi_setup(const char *rootdir, int auth_required)
 | 
|---|
| 520 | {
 | 
|---|
| 521 |         bool authenticated = False;
 | 
|---|
| 522 |         char line[1024];
 | 
|---|
| 523 |         char *url=NULL;
 | 
|---|
| 524 |         char *p;
 | 
|---|
| 525 |         char *lang;
 | 
|---|
| 526 | 
 | 
|---|
| 527 |         if (chdir(rootdir)) {
 | 
|---|
| 528 |                 cgi_setup_error("500 Server Error", "",
 | 
|---|
| 529 |                                 "chdir failed - the server is not configured correctly");
 | 
|---|
| 530 |         }
 | 
|---|
| 531 | 
 | 
|---|
| 532 |         /* Handle the possibility we might be running as non-root */
 | 
|---|
| 533 |         sec_init();
 | 
|---|
| 534 | 
 | 
|---|
| 535 |         if ((lang=getenv("HTTP_ACCEPT_LANGUAGE"))) {
 | 
|---|
| 536 |                 /* if running as a cgi program */
 | 
|---|
| 537 |                 web_set_lang(lang);
 | 
|---|
| 538 |         }
 | 
|---|
| 539 | 
 | 
|---|
| 540 |         /* maybe we are running under a web server */
 | 
|---|
| 541 |         if (getenv("CONTENT_LENGTH") || getenv("REQUEST_METHOD")) {
 | 
|---|
| 542 |                 if (auth_required) {
 | 
|---|
| 543 |                         cgi_web_auth();
 | 
|---|
| 544 |                 }
 | 
|---|
| 545 |                 return;
 | 
|---|
| 546 |         }
 | 
|---|
| 547 | 
 | 
|---|
| 548 |         inetd_server = True;
 | 
|---|
| 549 | 
 | 
|---|
| 550 |         if (!check_access(1, lp_hostsallow(-1), lp_hostsdeny(-1))) {
 | 
|---|
| 551 |                 cgi_setup_error("403 Forbidden", "",
 | 
|---|
| 552 |                                 "Samba is configured to deny access from this client\n<br>Check your \"hosts allow\" and \"hosts deny\" options in smb.conf ");
 | 
|---|
| 553 |         }
 | 
|---|
| 554 | 
 | 
|---|
| 555 |         /* we are a mini-web server. We need to read the request from stdin
 | 
|---|
| 556 |            and handle authentication etc */
 | 
|---|
| 557 |         while (fgets(line, sizeof(line)-1, stdin)) {
 | 
|---|
| 558 |                 if (line[0] == '\r' || line[0] == '\n') break;
 | 
|---|
| 559 |                 if (strnequal(line,"GET ", 4)) {
 | 
|---|
| 560 |                         got_request = True;
 | 
|---|
| 561 |                         url = SMB_STRDUP(&line[4]);
 | 
|---|
| 562 |                 } else if (strnequal(line,"POST ", 5)) {
 | 
|---|
| 563 |                         got_request = True;
 | 
|---|
| 564 |                         request_post = 1;
 | 
|---|
| 565 |                         url = SMB_STRDUP(&line[5]);
 | 
|---|
| 566 |                 } else if (strnequal(line,"PUT ", 4)) {
 | 
|---|
| 567 |                         got_request = True;
 | 
|---|
| 568 |                         cgi_setup_error("400 Bad Request", "",
 | 
|---|
| 569 |                                         "This server does not accept PUT requests");
 | 
|---|
| 570 |                 } else if (strnequal(line,"Authorization: ", 15)) {
 | 
|---|
| 571 |                         authenticated = cgi_handle_authorization(&line[15]);
 | 
|---|
| 572 |                 } else if (strnequal(line,"Content-Length: ", 16)) {
 | 
|---|
| 573 |                         content_length = atoi(&line[16]);
 | 
|---|
| 574 |                 } else if (strnequal(line,"Accept-Language: ", 17)) {
 | 
|---|
| 575 |                         web_set_lang(&line[17]);
 | 
|---|
| 576 |                 }
 | 
|---|
| 577 |                 /* ignore all other requests! */
 | 
|---|
| 578 |         }
 | 
|---|
| 579 | 
 | 
|---|
| 580 |         if (auth_required && !authenticated) {
 | 
|---|
| 581 |                 cgi_auth_error();
 | 
|---|
| 582 |         }
 | 
|---|
| 583 | 
 | 
|---|
| 584 |         if (!url) {
 | 
|---|
| 585 |                 cgi_setup_error("400 Bad Request", "",
 | 
|---|
| 586 |                                 "You must specify a GET or POST request");
 | 
|---|
| 587 |         }
 | 
|---|
| 588 | 
 | 
|---|
| 589 |         /* trim the URL */
 | 
|---|
| 590 |         if ((p = strchr_m(url,' ')) || (p=strchr_m(url,'\t'))) {
 | 
|---|
| 591 |                 *p = 0;
 | 
|---|
| 592 |         }
 | 
|---|
| 593 |         while (*url && strchr_m("\r\n",url[strlen(url)-1])) {
 | 
|---|
| 594 |                 url[strlen(url)-1] = 0;
 | 
|---|
| 595 |         }
 | 
|---|
| 596 | 
 | 
|---|
| 597 |         /* anything following a ? in the URL is part of the query string */
 | 
|---|
| 598 |         if ((p=strchr_m(url,'?'))) {
 | 
|---|
| 599 |                 query_string = p+1;
 | 
|---|
| 600 |                 *p = 0;
 | 
|---|
| 601 |         }
 | 
|---|
| 602 | 
 | 
|---|
| 603 |         string_sub(url, "/swat/", "", 0);
 | 
|---|
| 604 | 
 | 
|---|
| 605 |         if (url[0] != '/' && strstr(url,"..")==0) {
 | 
|---|
| 606 |                 cgi_download(url);
 | 
|---|
| 607 |         }
 | 
|---|
| 608 | 
 | 
|---|
| 609 |         printf("HTTP/1.0 200 OK\r\nConnection: close\r\n");
 | 
|---|
| 610 |         printf("Date: %s\r\n", http_timestring(talloc_tos(), time(NULL)));
 | 
|---|
| 611 |         baseurl = "";
 | 
|---|
| 612 |         pathinfo = url+1;
 | 
|---|
| 613 | }
 | 
|---|
| 614 | 
 | 
|---|
| 615 | 
 | 
|---|
| 616 | /***************************************************************************
 | 
|---|
| 617 | return the current pages URL
 | 
|---|
| 618 |   ***************************************************************************/
 | 
|---|
| 619 | const char *cgi_baseurl(void)
 | 
|---|
| 620 | {
 | 
|---|
| 621 |         if (inetd_server) {
 | 
|---|
| 622 |                 return baseurl;
 | 
|---|
| 623 |         }
 | 
|---|
| 624 |         return getenv("SCRIPT_NAME");
 | 
|---|
| 625 | }
 | 
|---|
| 626 | 
 | 
|---|
| 627 | /***************************************************************************
 | 
|---|
| 628 | return the current pages path info
 | 
|---|
| 629 |   ***************************************************************************/
 | 
|---|
| 630 | const char *cgi_pathinfo(void)
 | 
|---|
| 631 | {
 | 
|---|
| 632 |         char *r;
 | 
|---|
| 633 |         if (inetd_server) {
 | 
|---|
| 634 |                 return pathinfo;
 | 
|---|
| 635 |         }
 | 
|---|
| 636 |         r = getenv("PATH_INFO");
 | 
|---|
| 637 |         if (!r) return "";
 | 
|---|
| 638 |         if (*r == '/') r++;
 | 
|---|
| 639 |         return r;
 | 
|---|
| 640 | }
 | 
|---|
| 641 | 
 | 
|---|
| 642 | /***************************************************************************
 | 
|---|
| 643 | return the hostname of the client
 | 
|---|
| 644 |   ***************************************************************************/
 | 
|---|
| 645 | const char *cgi_remote_host(void)
 | 
|---|
| 646 | {
 | 
|---|
| 647 |         if (inetd_server) {
 | 
|---|
| 648 |                 return get_peer_name(1,False);
 | 
|---|
| 649 |         }
 | 
|---|
| 650 |         return getenv("REMOTE_HOST");
 | 
|---|
| 651 | }
 | 
|---|
| 652 | 
 | 
|---|
| 653 | /***************************************************************************
 | 
|---|
| 654 | return the hostname of the client
 | 
|---|
| 655 |   ***************************************************************************/
 | 
|---|
| 656 | const char *cgi_remote_addr(void)
 | 
|---|
| 657 | {
 | 
|---|
| 658 |         if (inetd_server) {
 | 
|---|
| 659 |                 char addr[INET6_ADDRSTRLEN];
 | 
|---|
| 660 |                 get_peer_addr(1,addr,sizeof(addr));
 | 
|---|
| 661 |                 return talloc_strdup(talloc_tos(), addr);
 | 
|---|
| 662 |         }
 | 
|---|
| 663 |         return getenv("REMOTE_ADDR");
 | 
|---|
| 664 | }
 | 
|---|
| 665 | 
 | 
|---|
| 666 | 
 | 
|---|
| 667 | /***************************************************************************
 | 
|---|
| 668 | return True if the request was a POST
 | 
|---|
| 669 |   ***************************************************************************/
 | 
|---|
| 670 | bool cgi_waspost(void)
 | 
|---|
| 671 | {
 | 
|---|
| 672 |         if (inetd_server) {
 | 
|---|
| 673 |                 return request_post;
 | 
|---|
| 674 |         }
 | 
|---|
| 675 |         return strequal(getenv("REQUEST_METHOD"), "POST");
 | 
|---|
| 676 | }
 | 
|---|