X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source3%2Fweb%2Fcgi.c;h=49a8fa92de4a937da3f44e6bfc344d54856c13c4;hb=d5573ccde3b5c39eb9a4637d5a9d7a95b66d86e3;hp=a99b9d3c5d2b30531c40b3bc07e8db7603238326;hpb=9e70ba71af8253b7b9995b55d9851b73bb58bf78;p=samba.git diff --git a/source3/web/cgi.c b/source3/web/cgi.c index a99b9d3c5d2..49a8fa92de4 100644 --- a/source3/web/cgi.c +++ b/source3/web/cgi.c @@ -19,7 +19,7 @@ #include "includes.h" -#include "smb.h" +#include "../web/swat_proto.h" #define MAX_VARIABLES 10000 @@ -40,61 +40,31 @@ static int num_variables; static int content_length; static int request_post; static char *query_string; -static char *baseurl; +static const char *baseurl; static char *pathinfo; static char *C_user; static BOOL inetd_server; static BOOL got_request; -static void unescape(char *buf) -{ - char *p=buf; - - while ((p=strchr(p,'+'))) - *p = ' '; - - p = buf; - - while (p && *p && (p=strchr(p,'%'))) { - int c1 = p[1]; - int c2 = p[2]; - - if (c1 >= '0' && c1 <= '9') - c1 = c1 - '0'; - else if (c1 >= 'A' && c1 <= 'F') - c1 = 10 + c1 - 'A'; - else if (c1 >= 'a' && c1 <= 'f') - c1 = 10 + c1 - 'a'; - else {p++; continue;} - - if (c2 >= '0' && c2 <= '9') - c2 = c2 - '0'; - else if (c2 >= 'A' && c2 <= 'F') - c2 = 10 + c2 - 'A'; - else if (c2 >= 'a' && c2 <= 'f') - c2 = 10 + c2 - 'a'; - else {p++; continue;} - - *p = (c1<<4) | c2; - - memcpy(p+1, p+3, strlen(p+3)+1); - p++; - } -} - - static char *grab_line(FILE *f, int *cl) { - char *ret; + char *ret = NULL; int i = 0; - int len = 1024; - - ret = (char *)malloc(len); - if (!ret) return NULL; - + int len = 0; while ((*cl)) { - int c = fgetc(f); + int c; + + if (i == len) { + char *ret2; + if (len == 0) len = 1024; + else len *= 2; + ret2 = (char *)Realloc(ret, len); + if (!ret2) return ret; + ret = ret2; + } + + c = fgetc(f); (*cl)--; if (c == EOF) { @@ -104,17 +74,10 @@ static char *grab_line(FILE *f, int *cl) if (c == '\r') continue; - if (strchr("\n&", c)) break; + if (strchr_m("\n&", c)) break; ret[i++] = c; - if (i == len-1) { - char *ret2; - ret2 = (char *)realloc(ret, len*2); - if (!ret2) return ret; - len *= 2; - ret = ret2; - } } @@ -127,40 +90,33 @@ static char *grab_line(FILE *f, int *cl) with the same name and the same or different values. Takes a file parameter for simulating CGI invocation eg loading saved preferences. ***************************************************************************/ -void cgi_load_variables(FILE *f1) +void cgi_load_variables(void) { - FILE *f = f1; static char *line; char *p, *s, *tok; - int len; + int len, i; + FILE *f = stdin; #ifdef DEBUG_COMMENTS char dummy[100]=""; print_title(dummy); - printf("\n",__FILE__); + d_printf("\n",__FILE__); #endif - if (!f1) { - f = stdin; - if (!content_length) { - p = getenv("CONTENT_LENGTH"); - len = p?atoi(p):0; - } else { - len = content_length; - } + if (!content_length) { + p = getenv("CONTENT_LENGTH"); + len = p?atoi(p):0; } else { - fseek(f, 0, SEEK_END); - len = ftell(f); - fseek(f, 0, SEEK_SET); + len = content_length; } if (len > 0 && - (f1 || request_post || + (request_post || ((s=getenv("REQUEST_METHOD")) && - strcasecmp(s,"POST")==0))) { + strequal(s,"POST")))) { while (len && (line=grab_line(f, &len))) { - p = strchr(line,'='); + p = strchr_m(line,'='); if (!p) continue; *p = 0; @@ -168,14 +124,14 @@ void cgi_load_variables(FILE *f1) variables[num_variables].name = strdup(line); variables[num_variables].value = strdup(p+1); - free(line); + SAFE_FREE(line); if (!variables[num_variables].name || !variables[num_variables].value) continue; - unescape(variables[num_variables].value); - unescape(variables[num_variables].name); + rfc1738_unescape(variables[num_variables].value); + rfc1738_unescape(variables[num_variables].name); #ifdef DEBUG_COMMENTS printf("\n", @@ -188,19 +144,12 @@ void cgi_load_variables(FILE *f1) } } - if (f1) { -#ifdef DEBUG_COMMENTS - printf("\n"); -#endif - return; - } - fclose(stdin); open("/dev/null", O_RDWR); if ((s=query_string) || (s=getenv("QUERY_STRING"))) { for (tok=strtok(s,"&;");tok;tok=strtok(NULL,"&;")) { - p = strchr(tok,'='); + p = strchr_m(tok,'='); if (!p) continue; *p = 0; @@ -212,8 +161,8 @@ void cgi_load_variables(FILE *f1) !variables[num_variables].value) continue; - unescape(variables[num_variables].value); - unescape(variables[num_variables].name); + rfc1738_unescape(variables[num_variables].value); + rfc1738_unescape(variables[num_variables].name); #ifdef DEBUG_COMMENTS printf("\n", @@ -228,6 +177,24 @@ void cgi_load_variables(FILE *f1) #ifdef DEBUG_COMMENTS printf("\n"); #endif + + /* variables from the client are in display charset - convert them + to our internal charset before use */ + for (i=0;i%s

%s

%s

\r\n\r\n", err, header, err, err, info); + d_printf("HTTP/1.0 %s\r\n%sConnection: close\r\nContent-Type: text/html\r\n\r\n%s

%s

%s

\r\n\r\n", err, header, err, err, info); fclose(stdin); fclose(stdout); exit(0); @@ -292,63 +259,55 @@ static void cgi_auth_error(void) exit(0); } - /*************************************************************************** -decode a base64 string in-place - simple and slow algorithm +authenticate when we are running as a CGI ***************************************************************************/ -static void base64_decode(char *s) +static void cgi_web_auth(void) { - char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - int bit_offset, byte_offset, idx, i, n; - unsigned char *d = (unsigned char *)s; - char *p; + const char *user = getenv("REMOTE_USER"); + struct passwd *pwd; + const char *head = "Content-Type: text/html\r\n\r\n

SWAT installation Error

\n"; + const char *tail = "\r\n"; - n=i=0; + if (!user) { + printf("%sREMOTE_USER not set. Not authenticated by web server.
%s\n", + head, tail); + exit(0); + } - while (*s && (p=strchr(b64,*s))) { - idx = (int)(p - b64); - byte_offset = (i*6)/8; - bit_offset = (i*6)%8; - d[byte_offset] &= ~((1<<(8-bit_offset))-1); - if (bit_offset < 3) { - d[byte_offset] |= (idx << (2-bit_offset)); - n = byte_offset+1; - } else { - d[byte_offset] |= (idx >> (bit_offset-2)); - d[byte_offset+1] = 0; - d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF; - n = byte_offset+2; - } - s++; i++; + pwd = getpwnam_alloc(user); + if (!pwd) { + printf("%sCannot find user %s
%s\n", head, user, tail); + exit(0); } - /* null terminate */ - d[n] = 0; + + setuid(0); + setuid(pwd->pw_uid); + if (geteuid() != pwd->pw_uid || getuid() != pwd->pw_uid) { + printf("%sFailed to become user %s - uid=%d/%d
%s\n", + head, user, (int)geteuid(), (int)getuid(), tail); + exit(0); + } + passwd_free(&pwd); } + /*************************************************************************** handle a http authentication line ***************************************************************************/ static BOOL cgi_handle_authorization(char *line) { - char *p, *user, *user_pass; + char *p; + fstring user, user_pass; struct passwd *pass = NULL; - BOOL ret = False; - BOOL got_name = False; - BOOL tested_pass = False; - fstring default_user_lookup; - fstring default_user_pass; - - /* Dummy user lookup to take the same time as a valid user. */ - fstrcpy(default_user_lookup, "zzzz bibble"); - fstrcpy(default_user_pass, "123456789"); - if (strncasecmp(line,"Basic ", 6)) { + if (!strnequal(line,"Basic ", 6)) { goto err; } line += 6; while (line[0] == ' ') line++; - base64_decode(line); - if (!(p=strchr(line,':'))) { + base64_decode_inplace(line); + if (!(p=strchr_m(line,':'))) { /* * Always give the same error so a cracker * cannot tell why we fail. @@ -356,59 +315,50 @@ static BOOL cgi_handle_authorization(char *line) goto err; } *p = 0; - user = line; - user_pass = p+1; + + convert_string(CH_DISPLAY, CH_UNIX, + line, -1, + user, sizeof(user)); + + convert_string(CH_DISPLAY, CH_UNIX, + p+1, -1, + user_pass, sizeof(user_pass)); /* * Try and get the user from the UNIX password file. */ - - if(!(pass = Get_Pwnam(user,False))) { - /* - * Always give the same error so a cracker - * cannot tell why we fail. - */ - got_name = True; - goto err; - } - + + pass = getpwnam_alloc(user); + /* * Validate the password they have given. */ - - tested_pass = True; - - if((ret = pass_check(user, user_pass, strlen(user_pass), NULL, NULL)) == True) { - - /* - * Password was ok. - */ - - if(pass->pw_uid != 0) { + + if NT_STATUS_IS_OK(pass_check(pass, user, user_pass, + strlen(user_pass), NULL, False)) { + + if (pass) { /* - * We have not authenticated as root, - * become the user *permanently*. + * Password was ok. */ + + if ( initgroups(pass->pw_name, pass->pw_gid) != 0 ) + goto err; + become_user_permanently(pass->pw_uid, pass->pw_gid); + + /* Save the users name */ + C_user = strdup(user); + passwd_free(&pass); + return True; } - - /* Save the users name */ - C_user = strdup(user); } - - err: - - /* Always take the same time. */ - if (!got_name) - Get_Pwnam(default_user_lookup,False); - - if (!tested_pass) - pass_check(default_user_lookup, default_user_pass, - strlen(default_user_pass), NULL, NULL); - + +err: cgi_setup_error("401 Bad Authorization", "", "username or password incorrect"); + passwd_free(&pass); return False; } @@ -442,10 +392,11 @@ static void cgi_download(char *file) char buf[1024]; int fd, l, i; char *p; + char *lang; /* sanitise the filename */ for (i=0;file[i];i++) { - if (!isalnum((int)file[i]) && !strchr("/.-_", file[i])) { + if (!isalnum((int)file[i]) && !strchr_m("/.-_", file[i])) { cgi_setup_error("404 File Not Found","", "Illegal character in filename"); } @@ -455,13 +406,14 @@ static void cgi_download(char *file) cgi_setup_error("404 File Not Found","", "The requested file was not found"); } - fd = sys_open(file,O_RDONLY,0); + + fd = web_open(file,O_RDONLY,0); if (fd == -1) { cgi_setup_error("404 File Not Found","", "The requested file was not found"); } printf("HTTP/1.0 200 OK\r\n"); - if ((p=strrchr(file,'.'))) { + if ((p=strrchr_m(file,'.'))) { if (strcmp(p,".gif")==0) { printf("Content-Type: image/gif\r\n"); } else if (strcmp(p,".jpg")==0) { @@ -474,6 +426,11 @@ static void cgi_download(char *file) } printf("Expires: %s\r\n", http_timestring(time(NULL)+EXPIRY_TIME)); + lang = lang_tdb_current(); + if (lang) { + printf("Content-Language: %s\r\n", lang); + } + printf("Content-Length: %d\r\n\r\n", (int)st.st_size); while ((l=read(fd,buf,sizeof(buf)))>0) { fwrite(buf, 1, l, stdout); @@ -483,26 +440,40 @@ static void cgi_download(char *file) } -/*************************************************************************** -setup the cgi framework, handling the possability that this program is either -run as a true cgi program by a web browser or is itself a mini web server - ***************************************************************************/ -void cgi_setup(char *rootdir, int auth_required) + + +/** + * @brief Setup the CGI framework. + * + * Setup the cgi framework, handling the possibility that this program + * is either run as a true CGI program with a gateway to a web server, or + * is itself a mini web server. + **/ +void cgi_setup(const char *rootdir, int auth_required) { BOOL authenticated = False; char line[1024]; char *url=NULL; char *p; + char *lang; if (chdir(rootdir)) { - cgi_setup_error("400 Server Error", "", + cgi_setup_error("500 Server Error", "", "chdir failed - the server is not configured correctly"); } + /* Handle the possibility we might be running as non-root */ + sec_init(); + + if ((lang=getenv("HTTP_ACCEPT_LANGUAGE"))) { + /* if running as a cgi program */ + web_set_lang(lang); + } + /* maybe we are running under a web server */ if (getenv("CONTENT_LENGTH") || getenv("REQUEST_METHOD")) { if (auth_required) { - cgi_auth_error(); + cgi_web_auth(); } return; } @@ -510,7 +481,7 @@ void cgi_setup(char *rootdir, int auth_required) inetd_server = True; if (!check_access(1, lp_hostsallow(-1), lp_hostsdeny(-1))) { - cgi_setup_error("400 Server Error", "", + cgi_setup_error("403 Forbidden", "", "Samba is configured to deny access from this client\n
Check your \"hosts allow\" and \"hosts deny\" options in smb.conf "); } @@ -518,21 +489,23 @@ void cgi_setup(char *rootdir, int auth_required) and handle authentication etc */ while (fgets(line, sizeof(line)-1, stdin)) { if (line[0] == '\r' || line[0] == '\n') break; - if (strncasecmp(line,"GET ", 4)==0) { + if (strnequal(line,"GET ", 4)) { got_request = True; url = strdup(&line[4]); - } else if (strncasecmp(line,"POST ", 5)==0) { + } else if (strnequal(line,"POST ", 5)) { got_request = True; request_post = 1; url = strdup(&line[5]); - } else if (strncasecmp(line,"PUT ", 4)==0) { + } else if (strnequal(line,"PUT ", 4)) { got_request = True; cgi_setup_error("400 Bad Request", "", "This server does not accept PUT requests"); - } else if (strncasecmp(line,"Authorization: ", 15)==0) { + } else if (strnequal(line,"Authorization: ", 15)) { authenticated = cgi_handle_authorization(&line[15]); - } else if (strncasecmp(line,"Content-Length: ", 16)==0) { + } else if (strnequal(line,"Content-Length: ", 16)) { content_length = atoi(&line[16]); + } else if (strnequal(line,"Accept-Language: ", 17)) { + web_set_lang(&line[17]); } /* ignore all other requests! */ } @@ -547,15 +520,15 @@ void cgi_setup(char *rootdir, int auth_required) } /* trim the URL */ - if ((p = strchr(url,' ')) || (p=strchr(url,'\t'))) { + if ((p = strchr_m(url,' ')) || (p=strchr_m(url,'\t'))) { *p = 0; } - while (*url && strchr("\r\n",url[strlen(url)-1])) { + while (*url && strchr_m("\r\n",url[strlen(url)-1])) { url[strlen(url)-1] = 0; } /* anything following a ? in the URL is part of the query string */ - if ((p=strchr(url,'?'))) { + if ((p=strchr_m(url,'?'))) { query_string = p+1; *p = 0; } @@ -576,7 +549,7 @@ void cgi_setup(char *rootdir, int auth_required) /*************************************************************************** return the current pages URL ***************************************************************************/ -char *cgi_baseurl(void) +const char *cgi_baseurl(void) { if (inetd_server) { return baseurl; @@ -587,7 +560,7 @@ char *cgi_baseurl(void) /*************************************************************************** return the current pages path info ***************************************************************************/ -char *cgi_pathinfo(void) +const char *cgi_pathinfo(void) { char *r; if (inetd_server) { @@ -605,7 +578,7 @@ return the hostname of the client char *cgi_remote_host(void) { if (inetd_server) { - return get_socket_name(1); + return get_peer_name(1,False); } return getenv("REMOTE_HOST"); } @@ -616,7 +589,7 @@ return the hostname of the client char *cgi_remote_addr(void) { if (inetd_server) { - return get_socket_addr(1); + return get_peer_addr(1); } return getenv("REMOTE_ADDR"); }