예제 #1
0
size_t
AbyssServer::Session::Impl::contentLength() const {

    try {
        const char * const contentLength = 
            RequestHeaderValue(this->cSessionP, "content-length");
        
        if (contentLength == NULL)
            throwf("Header is not present");
        else {
            if (contentLength[0] == '\0')
                throwf("The value is a null string");
            else {
                unsigned long contentLengthValue;
                char * tail;
        
                contentLengthValue = strtoul(contentLength, &tail, 10);
        
                if (*tail != '\0')
                    throwf("There's non-numeric crap in the value: '%s'",
                           tail);
                else if ((unsigned long)(size_t)contentLengthValue 
                         != contentLengthValue)
                    throwf("Value is too large; "
                           "we can't even do arithmetic on it: '%s'",
                           contentLength);
                else
                    return (size_t)contentLengthValue;
            }
        }
    } catch (exception const& e) {
        throw AbyssServer::Exception(
            400, string("Invalid content-length header field.  ") + e.what());
    }
}
예제 #2
0
static void
validateContentType(TSession *     const httpRequestP,
                    unsigned int * const httpErrorP) {
/*----------------------------------------------------------------------------
   If the client didn't specify a content-type of "text/xml", return
   "400 Bad Request".  We can't allow the client to default this header,
   because some firewall software may rely on all XML-RPC requests
   using the POST method and a content-type of "text/xml".
-----------------------------------------------------------------------------*/
    const char * const content_type =
        RequestHeaderValue(httpRequestP, "content-type");

    if (content_type == NULL)
        *httpErrorP = 400;
    else {
        const char * const sempos = strchr(content_type, ';');
        unsigned int baselen;
            /* Length of the base portion of the content type, e.g.
               "text/xml" int "text/xml;charset=utf-8"
            */

        if (sempos)
            baselen = sempos - content_type;
        else
            baselen = strlen(content_type);

        if (!xmlrpc_strneq(content_type, "text/xml", baselen))
            *httpErrorP = 400;
        else
            *httpErrorP = 0;
    }
}
예제 #3
0
bool
RequestAuth(TSession *   const sessionP,
            const char * const credential,
            const char * const user,
            const char * const pass) {
/*----------------------------------------------------------------------------
   Authenticate requester, in a very simplistic fashion.

   If the request executing on session *sessionP specifies basic
   authentication (via Authorization header) with username 'user', password
   'pass', then return TRUE.  Else, return FALSE and set up an authorization
   failure response (HTTP response status 401) that says user must supply an
   identity in the 'credential' domain.

   When we return TRUE, we also set the username in the request info for the
   session to 'user' so that a future SessionGetRequestInfo can get it.
-----------------------------------------------------------------------------*/
    bool authorized;
    char * authHdrPtr;

    authHdrPtr = RequestHeaderValue(sessionP, "authorization");
    if (authHdrPtr) {
        const char * authType;
        NextToken((const char **)&authHdrPtr);
        GetTokenConst(&authHdrPtr, &authType);
        authType = GetToken(&authHdrPtr);
        if (authType) {
            if (xmlrpc_strcaseeq(authType, "basic")) {
                const char * userPass;
                char userPassEncoded[80];

                NextToken((const char **)&authHdrPtr);

                xmlrpc_asprintf(&userPass, "%s:%s", user, pass);
                xmlrpc_base64Encode(userPass, userPassEncoded);
                xmlrpc_strfree(userPass);

                if (xmlrpc_streq(authHdrPtr, userPassEncoded)) {
                    sessionP->requestInfo.user = strdup(user);
                    authorized = TRUE;
                } else
                    authorized = FALSE;
            } else
                authorized = FALSE;
        } else
            authorized = FALSE;
    } else
        authorized = FALSE;

    if (!authorized) {
        const char * hdrValue;
        xmlrpc_asprintf(&hdrValue, "Basic realm=\"%s\"", credential);
        ResponseAddField(sessionP, "WWW-Authenticate", hdrValue);

        xmlrpc_strfree(hdrValue);

        ResponseStatus(sessionP, 401);
    }
    return authorized;
}
예제 #4
0
static void
validateContentType(TSession *     const httpRequestP,
                    const char **  const errorP) {
/*----------------------------------------------------------------------------
   If the client didn't specify a content-type of "text/xml", fail.
   We can't allow the client to default this header, because some
   firewall software may rely on all XML-RPC requests using the POST
   method and a content-type of "text/xml".x
-----------------------------------------------------------------------------*/
    const char * const content_type =
        RequestHeaderValue(httpRequestP, "content-type");

    if (content_type == NULL)
        xmlrpc_asprintf(errorP,
                        "You did not supply a content-type HTTP header");
    else {
        const char * const sempos = strchr(content_type, ';');
        unsigned int baselen;
            /* Length of the base portion of the content type, e.g.
               "text/xml" int "text/xml;charset=utf-8"
            */

        if (sempos)
            baselen = sempos - content_type;
        else
            baselen = strlen(content_type);

        if (!xmlrpc_strneq(content_type, "text/xml", baselen))
            xmlrpc_asprintf(errorP, "Your content-type HTTP header value '%s' "
                            "does not have a base type of 'text/xml'",
                            content_type);
        else
            *errorP = NULL;
    }
}
예제 #5
0
abyss_bool
RequestAuth(TSession *r,char *credential,char *user,char *pass) {

    char *p,*x;
    char z[80],t[80];

    p=RequestHeaderValue(r,"authorization");
    if (p) {
        NextToken((const char **)&p);
        x=GetToken(&p);
        if (x) {
            if (strcasecmp(x,"basic")==0) {
                NextToken((const char **)&p);
                sprintf(z,"%s:%s",user,pass);
                Base64Encode(z,t);

                if (strcmp(p,t)==0) {
                    r->request_info.user=strdup(user);
                    return TRUE;
                };
            };
        }
    };

    sprintf(z,"Basic realm=\"%s\"",credential);
    ResponseAddField(r,"WWW-Authenticate",z);
    ResponseStatus(r,401);
    return FALSE;
}
예제 #6
0
static void
processContentLength(TSession *    const httpRequestP,
                     size_t *      const inputLenP,
                     bool *        const missingP,
                     const char ** const errorP) {
/*----------------------------------------------------------------------------
  Make sure the content length is present and non-zero.  This is
  technically required by XML-RPC, but we only enforce it because we
  don't want to figure out how to safely handle HTTP < 1.1 requests
  without it.
-----------------------------------------------------------------------------*/
    const char * const content_length = 
        RequestHeaderValue(httpRequestP, "content-length");

    if (content_length == NULL) {
        *missingP = TRUE;
        *errorP = NULL;
    } else {
        *missingP = FALSE;
        *inputLenP = 0;  /* quiet compiler warning */
        if (content_length[0] == '\0')
            xmlrpc_asprintf(errorP, "The value in your content-length "
                            "HTTP header value is a null string");
        else {
            unsigned long contentLengthValue;
            char * tail;
        
            contentLengthValue = strtoul(content_length, &tail, 10);
        
            if (*tail != '\0')
                xmlrpc_asprintf(errorP, "There's non-numeric crap in "
                                "the value of your content-length "
                                "HTTP header: '%s'", tail);
            else if (contentLengthValue < 1)
                xmlrpc_asprintf(errorP, "According to your content-length "
                                "HTTP header, your request is empty (zero "
                                "length)");
            else if ((unsigned long)(size_t)contentLengthValue 
                     != contentLengthValue)
                xmlrpc_asprintf(errorP, "According to your content-length "
                                "HTTP header, your request is too big to "
                                "process; we can't even do arithmetic on its "
                                "size: %s bytes", content_length);
            else {
                *errorP = NULL;
                *inputLenP = (size_t)contentLengthValue;
            }
        }
    }
}
예제 #7
0
static void
storeCookies(TSession *     const httpRequestP,
             unsigned int * const httpErrorP) {
/*----------------------------------------------------------------------------
   Get the cookie settings from the HTTP headers and remember them for
   use in responses.
-----------------------------------------------------------------------------*/
    const char * const cookie = RequestHeaderValue(httpRequestP, "cookie");
    if (cookie) {
        /*
           Setting the value in an environment variable doesn't make
           any sense.  So for now, cookie code is disabled.
           -Bryan 04.10.03.

        setenv("HTTP_COOKIE", cookie, 1);
        */
    }
    /* TODO: parse HTTP_COOKIE to find auth pair, if there is one */

    *httpErrorP = 0;
}
예제 #8
0
static void
processContentLength(TSession *     const httpRequestP,
                     size_t *       const inputLenP,
                     unsigned int * const httpErrorP) {
/*----------------------------------------------------------------------------
  Make sure the content length is present and non-zero.  This is
  technically required by XML-RPC, but we only enforce it because we
  don't want to figure out how to safely handle HTTP < 1.1 requests
  without it.  If the length is missing, return "411 Length Required".
-----------------------------------------------------------------------------*/
    const char * const content_length =
        RequestHeaderValue(httpRequestP, "content-length");

    if (content_length == NULL)
        *httpErrorP = 411;
    else {
        if (content_length[0] == '\0')
            *httpErrorP = 400;
        else {
            unsigned long contentLengthValue;
            char * tail;

            contentLengthValue = strtoul(content_length, &tail, 10);

            if (*tail != '\0')
                /* There's non-numeric crap in the length */
                *httpErrorP = 400;
            else if (contentLengthValue < 1)
                *httpErrorP = 400;
            else if ((unsigned long)(size_t)contentLengthValue
                     != contentLengthValue)
                *httpErrorP = 400;
            else {
                *httpErrorP = 0;
                *inputLenP = (size_t)contentLengthValue;
            }
        }
    }
}
예제 #9
0
파일: handler.c 프로젝트: arssivka/naomech
static bool
notRecentlyModified(TSession *const sessionP,
                    time_t const fileModTime) {

    bool retval;
    const char *imsHdr;

    imsHdr = RequestHeaderValue(sessionP, "if-modified-since");
    if (imsHdr) {
        bool valid;
        time_t datetime;
        DateDecode(imsHdr, &valid, &datetime);
        if (valid) {
            if (MIN(fileModTime, sessionP->date) <= datetime)
                retval = TRUE;
            else
                retval = FALSE;
        } else
            retval = FALSE;
    } else
        retval = FALSE;

    return retval;
}
예제 #10
0
파일: http.c 프로젝트: mirror/xmlrpc-c
abyss_bool
RequestAuth(TSession *   const sessionP,
            const char * const credential,
            const char * const user,
            const char * const pass) {
/*----------------------------------------------------------------------------
   Authenticate requester, in a very simplistic fashion.

   If the request executing on session *sessionP specifies basic
   authentication (via Authorization header) with username 'user', password
   'pass', then return true.  Else, return false and set up an authorization
   failure response (HTTP response status 401) that says user must supply an
   identity in the 'credential' domain.

   When we return true, we also set the username in the request info for the
   session to 'user' so that a future SessionGetRequestInfo can get it.
-----------------------------------------------------------------------------*/
    bool authorized;
    const char * authValue;

    authValue = RequestHeaderValue(sessionP, "authorization");
    if (authValue) {
        char * const valueBuffer = malloc(strlen(authValue));
            /* A buffer we can mangle as we parse the authorization: value */

        if (!authValue)
            /* Should return error, but we have no way to do that */
            authorized = false;
        else {
            const char * authType;
            char * authHdrPtr;

            strcpy(valueBuffer, authValue);
            authHdrPtr = &valueBuffer[0];

            NextToken((const char **)&authHdrPtr);
            GetTokenConst(&authHdrPtr, &authType);
            if (authType) {
                if (xmlrpc_strcaseeq(authType, "basic")) {
                    const char * userPass;
                    char userPassEncoded[80];

                    NextToken((const char **)&authHdrPtr);

                    xmlrpc_asprintf(&userPass, "%s:%s", user, pass);
                    xmlrpc_base64Encode(userPass, userPassEncoded);
                    xmlrpc_strfree(userPass);

                    if (xmlrpc_streq(authHdrPtr, userPassEncoded)) {
                        sessionP->requestInfo.user = xmlrpc_strdupsol(user);
                        authorized = true;
                    } else
                        authorized = false;
                } else
                    authorized = false;
            } else
                authorized = false;

            free(valueBuffer);
        }
    } else
        authorized = false;

    if (!authorized) {
        const char * hdrValue;
        xmlrpc_asprintf(&hdrValue, "Basic realm=\"%s\"", credential);
        ResponseAddField(sessionP, "WWW-Authenticate", hdrValue);

        xmlrpc_strfree(hdrValue);

        ResponseStatus(sessionP, 401);
    }
    return authorized;
}
예제 #11
0
abyss_bool handler_hook(TSession * r)
{
	switch_stream_handle_t stream = { 0 };
	char *command;
	int i;
	char *fs_user = NULL, *fs_domain = NULL;
	char *path_info = NULL;
	abyss_bool ret = TRUE;
	int html = 0, text = 0, xml = 0, api = 0;
	const char *api_str;
	const char *uri = 0;
	TRequestInfo *info = 0;
	switch_event_t *evnt = 0; /* shortcut to stream.param_event */

	if (!r || !(info = &r->requestInfo) || !(uri = info->uri)) {
		return FALSE;
	}

	stream.data = r;
	stream.write_function = http_stream_write;
	stream.raw_write_function = http_stream_raw_write;

	if ((command = strstr(uri, "/api/"))) {
		command += 5;
		api++;
	} else if ((command = strstr(uri, "/webapi/"))) {
		command += 8;
		html++;
	} else if ((command = strstr(uri, "/txtapi/"))) {
		command += 8;
		text++;
	} else if ((command = strstr(uri, "/xmlapi/"))) {
		command += 8;
		xml++;
	} else {
		return FALSE; /* 404 */
	}

	if ((path_info = strchr(command, '/'))) {
		*path_info++ = '\0';
	}

	for (i = 0; i < r->responseHeaderFields.size; i++) {
		TTableItem *ti = &r->responseHeaderFields.item[i];
		if (!strcasecmp(ti->name, "freeswitch-user")) {
			fs_user = ti->value;
		} else if (!strcasecmp(ti->name, "freeswitch-domain")) {
			fs_domain = ti->value;
		}
	}

	if (!is_authorized(r, command)) {
		ret = TRUE;
		goto end;
	}

/*  auth: */

	if (switch_event_create(&stream.param_event, SWITCH_EVENT_API) == SWITCH_STATUS_SUCCESS) {
		const char *const content_length = RequestHeaderValue(r, "content-length");
		evnt = stream.param_event;

		if (html) {
			switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "Content-Type", "text/html");
		} else if (text) {
			switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "Content-Type", "text/plain");
		} else if (xml) {
			switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "Content-Type", "text/xml");
		}
		if (api) {
			switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-API", "api");
		}
		if (fs_user)   switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "FreeSWITCH-User", fs_user);
		if (fs_domain) switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "FreeSWITCH-Domain", fs_domain);
		if (path_info) switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-Path-Info", path_info);

		if (info->host)        switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-HOST", info->host);
		if (info->from)        switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-FROM", info->from);
		if (info->useragent)   switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-USER-AGENT", info->useragent);
		if (info->referer)     switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-REFERER", info->referer);
		if (info->requestline) switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-REQUESTLINE", info->requestline);
		if (info->user)        switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-USER", info->user);
		if (info->port)        switch_event_add_header(evnt, SWITCH_STACK_BOTTOM, "HTTP-PORT", "%u", info->port);

		{
			char *q, *qd;
			char *next;
			char *query = (char *) info->query;
			char *name, *val;
			char qbuf[8192] = "";

			/* first finish reading from the socket if post method was used*/
			if (info->method == m_post && content_length) {
				int len = atoi(content_length);
				int qlen = 0;

				if (len > 0) {
					int succeeded = TRUE;
					char *qp = qbuf;
					char *readError;

					do {
						int blen = r->connP->buffersize - r->connP->bufferpos;

						if ((qlen + blen) > len) {
							blen = len - qlen;
						}

						qlen += blen;

						if (qlen > sizeof(qbuf)) {
							break;
						}

						memcpy(qp, r->connP->buffer.b + r->connP->bufferpos, blen);
						qp += blen;

						if (qlen >= len) {
							break;
						}

						ConnRead(r->connP, 2000, NULL, NULL, &readError);
		                if (readError) {
							succeeded = FALSE;
							free(readError);
						}

					} while (succeeded);

					query = qbuf;
				}
			}

			/* parse query and add kv-pairs as event headers  */
			/* a kv pair starts with '&', '+' or \0 mark the end */
			if (query) {
				switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-QUERY", query);
				qd = strdup(query);
			} else {
				qd = strdup(uri);
			}

			switch_assert(qd != NULL);

			q = qd;
			next = q;

			do {
				char *p;

				if (next = strchr(next, '&')) {
					if (!query) {
						/* pass kv pairs from uri to query       */
			            /* "?" is absent in url so parse uri     */
						*((char *)uri + (next - q - 1)) = '\0';
						query = next;
						switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-QUERY", next);
						/* and strip uri                                     */
						/* the start of first kv pair marks the end of uri   */
						/* to prevent kv-pairs confusing fs api commands     */
						/* that have arguments separated by space            */
					}
					*next++ = '\0';
				}

				for (p = q; p && *p; p++) {
					if (*p == '+') {
						*p = ' ';
					}
				}
				/* hmmm, get method requests are already decoded ... */
				switch_url_decode(q);

				name = q;
				if ((val = strchr(name, '='))) {
					*val++ = '\0';
					switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, name, val);
				}
				q = next;
			} while (q != NULL);

			free(qd);
		}
	}

	switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-URI", uri);

	/* We made it this far, always OK */
	if (!HTTPWrite(r, "HTTP/1.1 200 OK\r\n", (uint32_t) strlen("HTTP/1.1 200 OK\r\n"))) {
		return TRUE;
	}

	ResponseAddField(r, "Connection", "close");

	/* generation of the date field */
	if (evnt)
	{
		ResponseAddField(r, "Date", switch_event_get_header(evnt, "Event-Date-GMT"));
	}
	else {
		const char *dateValue;

		DateToString(r->date, &dateValue);
		if (dateValue) {
			ResponseAddField(r, "Date", dateValue);
			free((void *)dateValue);
		}
	}

	/* Generation of the server field */
	ResponseAddField(r, "Server", "FreeSWITCH-" SWITCH_VERSION_FULL "-mod_xml_rpc");

	if (html) {
		ResponseAddField(r, "Content-Type", "text/html");
	} else if (text) {
		ResponseAddField(r, "Content-Type", "text/plain");
	} else if (xml) {
		ResponseAddField(r, "Content-Type", "text/xml");
	}

	for (i = 0; i < r->responseHeaderFields.size; i++) {
		TTableItem *ti = &r->responseHeaderFields.item[i];
		char *header = switch_mprintf("%s: %s\r\n", ti->name, ti->value);
		if (!ConnWrite(r->connP, header, (uint32_t) strlen(header))) {
			switch_safe_free(header);
			return TRUE;
		}
		switch_safe_free(header);
	}

	/* send end http header */
	if (html||text||xml) {
		if (!ConnWrite(r->connP, CRLF, 2)) {
			return TRUE;
		}
	}
	else {
		/* content-type and end of http header will be streamed by fs api or http_stream_write */
	}

	if (switch_stristr("unload", command) && switch_stristr("mod_xml_rpc", info->query)) {
		command = "bgapi";
		api_str = "unload mod_xml_rpc";
	} else if (switch_stristr("reload", command) && switch_stristr("mod_xml_rpc", info->query)) {
		command = "bgapi";
		api_str = "reload mod_xml_rpc";
	} else {
		api_str = info->query;
	}

	/* TODO (maybe): take "refresh=xxx" out of query as to not confuse fs api commands         */

	/* execute actual fs api command                                                            */
	/* fs api command will write to stream,  calling http_stream_write / http_stream_raw_write	*/
	/* switch_api_execute will stream INVALID COMMAND before it fails					        */
	switch_api_execute(command, api_str, NULL, &stream);

	r->responseStarted = TRUE;
	ResponseStatus(r, 200);     /* we don't want an assertion failure */
	r->requestInfo.keepalive = 0;

  end:

	return ret;
}
예제 #12
0
static abyss_bool http_directory_auth(TSession *r, char *domain_name)
{
	char *p = NULL;
	char *x = NULL;
	char z[256] = "", t[80] = "";
	char user[512] = "" ;
	char *pass = NULL;
	const char *mypass1 = NULL, *mypass2 = NULL;
	const char *box = NULL;
	int at = 0;
	char *dp = NULL;
	abyss_bool rval = FALSE;
	char *dup_domain = NULL;

	p = RequestHeaderValue(r, "authorization");

	if (p) {
		NextToken((const char **const) &p);
		x = GetToken(&p);
		if (x) {
			if (!strcasecmp(x, "basic")) {
				NextToken((const char **const) &p);
				switch_b64_decode(p, user, sizeof(user));
				if ((pass = strchr(user, ':'))) {
					*pass++ = '\0';
				}

				if ((dp = strchr(user, '@'))) {
					*dp++ = '\0';
					domain_name = dp;
					at++;
				}

				if (!domain_name) {
					if (globals.virtual_host) {
						if ((domain_name = (char *) r->requestInfo.host)) {
							if (!strncasecmp(domain_name, "www.", 3)) {
								domain_name += 4;
							}
						}
					}
					if (!domain_name) {
						if (globals.default_domain) {
							domain_name = globals.default_domain;
						} else {
							if ((dup_domain = switch_core_get_variable_dup("domain"))) {
								domain_name = dup_domain;
							}
						}
					}
				}

				if (zstr(user) || zstr(domain_name)) {
					goto fail;
				}

				if (!zstr(globals.realm) && !zstr(globals.user) && !zstr(globals.pass)) {
					if (at) {
						switch_snprintf(z, sizeof(z), "%s@%s:%s", globals.user, globals.realm, globals.pass);
					} else {
						switch_snprintf(z, sizeof(z), "%s:%s", globals.user, globals.pass);
					}
					xmlrpc_base64Encode(z, t);

					if (!strcmp(p, t)) {
						goto authed;
					}
				}

				if (!user_attributes(user, domain_name, &mypass1, &mypass2, &box, NULL)) {
					goto fail;
				}


				if (!zstr(mypass2) && !strcasecmp(mypass2, "user-choose")) {
					switch_safe_free(mypass2);
				}

				if (!mypass1) {
					goto authed;
				} else {
					if (at) {
						switch_snprintf(z, sizeof(z), "%s@%s:%s", user, domain_name, mypass1);
					} else {
						switch_snprintf(z, sizeof(z), "%s:%s", user, mypass1);
					}
					xmlrpc_base64Encode(z, t);

					if (!strcmp(p, t)) {
						goto authed;
					}

					if (mypass2) {
						if (at) {
							switch_snprintf(z, sizeof(z), "%s@%s:%s", user, domain_name, mypass2);
						} else {
							switch_snprintf(z, sizeof(z), "%s:%s", user, mypass2);
						}
						xmlrpc_base64Encode(z, t);

						if (!strcmp(p, t)) {
							goto authed;
						}
					}

					if (box) {
						if (at) {
							switch_snprintf(z, sizeof(z), "%s@%s:%s", box, domain_name, mypass1);
						} else {
							switch_snprintf(z, sizeof(z), "%s:%s", box, mypass1);
						}
						xmlrpc_base64Encode(z, t);

						if (!strcmp(p, t)) {
							goto authed;
						}

						if (mypass2) {
							if (at) {
								switch_snprintf(z, sizeof(z), "%s@%s:%s", box, domain_name, mypass2);
							} else {
								switch_snprintf(z, sizeof(z), "%s:%s", box, mypass2);
							}

							xmlrpc_base64Encode(z, t);

							if (!strcmp(p, t)) {
								goto authed;
							}
						}
					}
				}
				goto fail;

			  authed:

				switch_snprintf(z, sizeof(z), "%s@%s", (box ? box : user), domain_name);
				r->requestInfo.user = strdup(z);

				ResponseAddField(r, "freeswitch-user", (box ? box : user));
				ResponseAddField(r, "freeswitch-domain", domain_name);
				rval = TRUE;
				goto done;
			}
		}
	}

  fail:

	switch_snprintf(z, sizeof(z), "Basic realm=\"%s\"", domain_name ? domain_name : globals.realm);
	ResponseAddField(r, "WWW-Authenticate", z);
	ResponseStatus(r, 401);

  done:

	switch_safe_free(mypass1);
	switch_safe_free(mypass2);
	switch_safe_free(box);
	switch_safe_free(dup_domain);

	return rval;
}
예제 #13
0
abyss_bool websocket_hook(TSession *r)
{
	wsh_t *wsh;
	int ret;
	int i;
	ws_opcode_t opcode;
	uint8_t *data;
	switch_event_node_t *nodes[MAX_EVENT_BIND_SLOTS];
	int node_count = 0;
	char *p;
	char *key = NULL;
	char *version = NULL;
	char *proto = NULL;
	char *upgrade = NULL;

	for (i = 0; i < r->requestHeaderFields.size; i++) {
		TTableItem * const item = &r->requestHeaderFields.item[i];

		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "headers %s: %s\n", item->name, item->value);
	}

	key = RequestHeaderValue(r, "sec-websocket-key");
	version = RequestHeaderValue(r, "sec-websocket-version");
	proto = RequestHeaderValue(r, "sec-websocket-protocol");
	upgrade = RequestHeaderValue(r, "upgrade");

	if (!key || !version || !proto || !upgrade) return FALSE;
	if (strncasecmp(upgrade, "websocket", 9) || strncasecmp(proto, "websocket", 9)) return FALSE;

	wsh = ws_init(r);
	if (!wsh) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "websocket error %d\n", ret);
		return FALSE;
	}

	ret = ws_handshake_kvp(wsh, key, version, proto);
	if (ret < 0) wsh->down = 1;

	if (ret != 0) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "handshake error %d\n", ret);
		return FALSE;
	}

	if (switch_event_bind_removable("websocket", SWITCH_EVENT_CUSTOM, "websocket::stophook", stop_hook_event_handler, wsh, &nodes[node_count++]) != SWITCH_STATUS_SUCCESS) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't bind!\n");
		node_count--;
	}

	while (!wsh->down) {
		int bytes = ws_read_frame(wsh, &opcode, &data);

		if (bytes < 0) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%d %s\n", opcode, (char *)data);
			switch_yield(100000);
			continue;
		}

		switch (opcode) {
			case WSOC_CLOSE:
				ws_close(wsh, 1000);
				break;
			case WSOC_CONTINUATION:
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "continue\n");
				continue;
			case WSOC_TEXT:
				p = data;
				if (!p) continue;
				if (!strncasecmp(data, "event ", 6)) {
					switch_event_types_t type;
					char *subclass;

					if (node_count == MAX_EVENT_BIND_SLOTS - 1) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "cannot subscribe more than %d events\n", node_count);
						continue;
					}
					p += 6;
					if (p = strchr(p, ' ')) p++;
					if (!strncasecmp(p, "json ", 5)) {
						p += 5;
					} else if (!strncasecmp(p, "xml ", 4)) {
						p += 4;
					} else if (!strncasecmp(p, "plain ", 6)) {
						p += 6;
					}
					if (!*p) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "missing event type in [%s]\n", data);
						break;
					} else {
					}
					if (subclass = strchr(p, ' ')) {
						*subclass++ = '\0';
						if (!*subclass) {
							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "missing subclass\n");
							continue;
						}
					} else {
						subclass = SWITCH_EVENT_SUBCLASS_ANY;
					}

					if (switch_name_event(p, &type) != SWITCH_STATUS_SUCCESS) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown event %s\n", p);
						continue;
					}

					if (switch_event_bind_removable("websocket", type, subclass, event_handler, wsh, &nodes[node_count++]) != SWITCH_STATUS_SUCCESS) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't bind!\n");
						node_count--;
						continue;
					} else {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Bind %s\n", data);
					}

				}
				break;
			default:
				break;
		}
	}

	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "wsh->down = %d, node_count = %d\n", wsh->down, node_count);

	switch_yield(2000);
	while (--node_count >= 0) switch_event_unbind(&nodes[node_count]);

	switch_safe_free(wsh);

	return FALSE;
}
예제 #14
0
abyss_bool handler_hook(TSession * r)
{
	//char *mime = "text/html";
	char buf[80] = "HTTP/1.1 200 OK\n";
	switch_stream_handle_t stream = { 0 };
	char *command;
	int i;
	TTableItem *ti;
	char *fs_user = NULL, *fs_domain = NULL;
	char *path_info = NULL;
	abyss_bool ret = TRUE;
	int html = 0, text = 0, xml = 0;
	const char *api_str;

	stream.data = r;
	stream.write_function = http_stream_write;
	stream.raw_write_function = http_stream_raw_write;

	if (!r || !r->requestInfo.uri) {
		return FALSE;
	}
	
	if ((command = strstr(r->requestInfo.uri, "/api/"))) {
		command += 5;
	} else if ((command = strstr(r->requestInfo.uri, "/webapi/"))) {
		command += 8;
		html++;
	} else if ((command = strstr(r->requestInfo.uri, "/txtapi/"))) {
		command += 8;
		text++;
	} else if ((command = strstr(r->requestInfo.uri, "/xmlapi/"))) {
		command += 8;
		xml++;
	} else {
		return FALSE;
	}

	if ((path_info = strchr(command, '/'))) {
		*path_info++ = '\0';
	}

	for (i = 0; i < r->response_headers.size; i++) {
		ti = &r->response_headers.item[i];
		if (!strcasecmp(ti->name, "freeswitch-user")) {
			fs_user = ti->value;
		} else if (!strcasecmp(ti->name, "freeswitch-domain")) {
			fs_domain = ti->value;
		}
	}

	if (is_authorized(r, command)) {
		goto auth;
	}

	ret = TRUE;
	goto end;

  auth:

	if (switch_event_create(&stream.param_event, SWITCH_EVENT_API) == SWITCH_STATUS_SUCCESS) {
		const char *const content_length = RequestHeaderValue(r, "content-length");

		if (html)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "Content-type", "text/html");
		else if (text)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "Content-type", "text/plain");
		else if (xml)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "Content-type", "text/xml");
		if (fs_user)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "FreeSWITCH-User", fs_user);
		if (fs_domain)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "FreeSWITCH-Domain", fs_domain);
		if (path_info)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-Path-Info", path_info);
		switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-URI", r->requestInfo.uri);
		if (r->requestInfo.query)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-QUERY", r->requestInfo.query);
		if (r->requestInfo.host)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-HOST", r->requestInfo.host);
		if (r->requestInfo.from)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-FROM", r->requestInfo.from);
		if (r->requestInfo.useragent)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-USER-AGENT", r->requestInfo.useragent);
		if (r->requestInfo.referer)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-REFERER", r->requestInfo.referer);
		if (r->requestInfo.requestline)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-REQUESTLINE", r->requestInfo.requestline);
		if (r->requestInfo.user)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-USER", r->requestInfo.user);
		if (r->requestInfo.port)
			switch_event_add_header(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-PORT", "%u", r->requestInfo.port);
		if (r->requestInfo.query || content_length) {
			char *q, *qd;
			char *next;
			char *query = (char *) r->requestInfo.query;
			char *name, *val;
			char qbuf[8192] = "";

			if (r->requestInfo.method == m_post && content_length) {
				int len = atoi(content_length);
				int qlen = 0;

				if (len > 0) {
					int succeeded;
					char *qp = qbuf;
					do {
						int blen = r->conn->buffersize - r->conn->bufferpos;

						if ((qlen + blen) > len) {
							blen = len - qlen;
						}

						qlen += blen;

						if (qlen > sizeof(qbuf)) {
							break;
						}

						memcpy(qp, r->conn->buffer + r->conn->bufferpos, blen);
						qp += blen;

						if (qlen >= len) {
							break;
						}
					} while ((succeeded = ConnRead(r->conn, 2000)));

					query = qbuf;
				}
			}
			if (query) {
				switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-QUERY", query);

				qd = strdup(query);
				switch_assert(qd != NULL);

				q = qd;
				next = q;

				do {
					char *p;

					if ((next = strchr(next, '&'))) {
						*next++ = '\0';
					}

					for (p = q; p && *p; p++) {
						if (*p == '+') {
							*p = ' ';
						}
					}

					switch_url_decode(q);

					name = q;
					if ((val = strchr(name, '='))) {
						*val++ = '\0';
						switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, name, val);
					}
					q = next;
				} while (q != NULL);

				free(qd);
			}
		}
	}
	//ResponseChunked(r);

	//ResponseContentType(r, mime);
	//ResponseWrite(r);

	HTTPWrite(r, buf, (uint32_t) strlen(buf));

	//HTTPWrite(r, "<pre>\n\n", 7);

	/* generation of the date field */
	{
		const char *dateValue;

		DateToString(r->date, &dateValue);

		if (dateValue) {
			ResponseAddField(r, "Date", dateValue);
		}
	}


	/* Generation of the server field */
	ResponseAddField(r, "Server", "FreeSWITCH-" SWITCH_VERSION_FULL "-mod_xml_rpc");

	if (html) {
		ResponseAddField(r, "Content-Type", "text/html");
	} else if (text) {
		ResponseAddField(r, "Content-Type", "text/plain");
	} else if (xml) {
		ResponseAddField(r, "Content-Type", "text/xml");
	}

	for (i = 0; i < r->response_headers.size; i++) {
		ti = &r->response_headers.item[i];
		ConnWrite(r->conn, ti->name, (uint32_t) strlen(ti->name));
		ConnWrite(r->conn, ": ", 2);
		ConnWrite(r->conn, ti->value, (uint32_t) strlen(ti->value));
		ConnWrite(r->conn, CRLF, 2);
	}

	switch_snprintf(buf, sizeof(buf), "Connection: close\r\n");
	ConnWrite(r->conn, buf, (uint32_t) strlen(buf));

	if (html || text || xml) {
		ConnWrite(r->conn, "\r\n", 2);
	}

	if (switch_stristr("unload", command) && switch_stristr("mod_xml_rpc", r->requestInfo.query)) {
		command = "bgapi";
		api_str = "unload mod_xml_rpc";
	} else if (switch_stristr("reload", command) && switch_stristr("mod_xml_rpc", r->requestInfo.query)) {
		command = "bgapi";
		api_str = "reload mod_xml_rpc";
	} else {
		api_str = r->requestInfo.query;
	}

	if (switch_api_execute(command, api_str, NULL, &stream) == SWITCH_STATUS_SUCCESS) {
		ResponseStatus(r, 200);
		r->responseStarted = TRUE;
		//r->done = TRUE;
	} else {
		ResponseStatus(r, 404);
		ResponseError(r);
	}

	//SocketClose(&(r->conn->socket));

	HTTPWriteEnd(r);
	//if (r->conn->channelP)
	//ConnKill(r->conn);
	//ChannelInterrupt(r->conn->channelP);
	//ConnClose(r->conn);
	//ChannelDestroy(r->conn->channelP);
	r->requestInfo.keepalive = 0;

  end:

	return ret;
}
예제 #15
0
bool
AbyssServer::Session::hasContentLength() const {

    return
        RequestHeaderValue(this->implP->cSessionP, "content-length")!= NULL;
}
예제 #16
0
static abyss_bool
ServerDirectoryHandler(TSession * const r,
                       char *     const z,
                       time_t     const fileModTime,
                       MIMEType * const mimeTypeP) {

    TList list;
    abyss_bool text;
    abyss_bool ascending;
    uint16_t sort;    /* 1=by name, 2=by date */
    TPool pool;
    TDate date;
    const char * error;
    uint16_t responseStatus;
    TDate dirdate;
    const char * imsHdr;
    
    determineSortType(r->request_info.query, &ascending, &sort, &text, &error);

    if (error) {
        ResponseStatus(r,400);
        xmlrpc_strfree(error);
        return TRUE;
    }

    fileDate(r, fileModTime, &dirdate);

    imsHdr = RequestHeaderValue(r, "If-Modified-Since");
    if (imsHdr) {
        if (DateDecode(imsHdr, &date)) {
            if (DateCompare(&dirdate, &date) <= 0) {
                ResponseStatus(r, 304);
                ResponseWrite(r);
                return TRUE;
            }
        }
    }

    if (!PoolCreate(&pool, 1024)) {
        ResponseStatus(r, 500);
        return TRUE;
    }

    generateListing(&list, z, r->request_info.uri,
                    &pool, &error, &responseStatus);
    if (error) {
        ResponseStatus(r, responseStatus);
        xmlrpc_strfree(error);
        PoolFree(&pool);
        return TRUE;
    }

    /* Send something to the user to show that we are still alive */
    ResponseStatus(r, 200);
    ResponseContentType(r, (text ? "text/plain" : "text/html"));

    if (DateToString(&dirdate, z))
        ResponseAddField(r, "Last-Modified", z);
    
    ResponseChunked(r);
    ResponseWrite(r);

    if (r->request_info.method!=m_head)
        sendDirectoryDocument(&list, ascending, sort, text,
                              r->request_info.uri, mimeTypeP, r, z);

    HTTPWriteEndChunk(r);

    /* Free memory and exit */
    ListFree(&list);
    PoolFree(&pool);

    return TRUE;
}
예제 #17
0
static abyss_bool
ServerFileHandler(TSession * const r,
                  char *     const z,
                  time_t     const fileModTime,
                  MIMEType * const mimeTypeP) {

    const char * mediatype;
    TFile file;
    uint64_t filesize;
    uint64_t start;
    uint64_t end;
    TDate date;
    char * p;
    TDate filedate;
    
    mediatype = MIMETypeGuessFromFile2(mimeTypeP, z);

    if (!FileOpen(&file,z,O_BINARY | O_RDONLY)) {
        ResponseStatusErrno(r);
        return TRUE;
    }

    fileDate(r, fileModTime, &filedate);

    p = RequestHeaderValue(r, "if-modified-since");
    if (p) {
        if (DateDecode(p,&date)) {
            if (DateCompare(&filedate, &date) <= 0) {
                ResponseStatus(r, 304);
                ResponseWrite(r);
                return TRUE;
            } else
                r->ranges.size = 0;
        }
    }
    filesize = FileSize(&file);

    switch (r->ranges.size) {
    case 0:
        ResponseStatus(r, 200);
        break;

    case 1: {
        abyss_bool decoded;
        decoded = RangeDecode((char *)(r->ranges.item[0]), filesize,
                              &start, &end);
        if (!decoded) {
            ListFree(&(r->ranges));
            ResponseStatus(r, 200);
            break;
        }
        
        sprintf(z, "bytes %llu-%llu/%llu", start, end, filesize);

        ResponseAddField(r, "Content-range", z);
        ResponseContentLength(r, end - start + 1);
        ResponseStatus(r, 206);
    } break;

    default:
        ResponseContentType(r, "multipart/ranges; boundary=" BOUNDARY);
        ResponseStatus(r, 206);
        break;
    }
    
    if (r->ranges.size == 0) {
        ResponseContentLength(r, filesize);
        ResponseContentType(r, mediatype);
    }
    
    if (DateToString(&filedate, z))
        ResponseAddField(r, "Last-Modified", z);

    ResponseWrite(r);

    if (r->request_info.method != m_head)
        sendBody(r, &file, filesize, mediatype, start, end, z);

    FileClose(&file);

    return TRUE;
}
예제 #18
0
/**************************************
* ProcessRequest
*	Procesa una peticion
*************************************/
int XmlHandler::ProcessRequest(TRequestInfo *req,TSession * const ses)
{
	xmlrpc_env env;
	int inputLen;
	char *method;
	xmlrpc_value *params = NULL;
	timeval tv;

	Log(">ProcessRequest [uri:%s]\n",req->uri);

	//Init timer
	getUpdDifTime(&tv);

	//Creamos un enviroment
	xmlrpc_env_init(&env);

	//Si no es post
	if (req->method != m_post)
		//Mandamos error
		return XmlRpcServer::SendError(ses, 405, "Only POST allowed");

	//Obtenemos el content type
	const char * content_type = RequestHeaderValue(ses, (char*)"content-type");

	//Si no es el bueno
	 if (content_type == NULL || strcmp(content_type, "text/xml") != 0)
		return XmlRpcServer::SendError(ses, 400, "Wrong content-type");

	//Obtenemos el content length
	const char * content_length = RequestHeaderValue(ses, (char*)"content-length");

	//Si no hay 
	if (content_length == NULL)
		return XmlRpcServer::SendError(ses,411,"No content-length");

	//Obtenemos el entero
	inputLen = atoi(content_length);

	//Tiene que ser mayor que cero
	if ((inputLen < 0) || (inputLen > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID)))
		return XmlRpcServer::SendError(ses,400,"Size limit");

	//Creamos un buffer para el body
	char * buffer = (char *) malloc(inputLen);

	if (!XmlRpcServer::GetBody(ses,buffer,inputLen))
	{
		//LIberamos el buffer
		free(buffer);

		//Y salimos sin devolver nada
		Log("Operation timedout\n");
		return 1;
	}

	//Get method name
	xmlrpc_parse_call(&env,buffer,inputLen,(const char**)&method,&params);

	Log("-ProcessRequest [method:%s]\n",method);

	//Free name and params
	free(method);
	xmlrpc_DECREF(params);

	//Generamos la respuesta
	xmlrpc_mem_block *output = xmlrpc_registry_process_call(
			&env, 
			registry, 
			NULL,
			buffer,
			inputLen
		);

	//Si todo ha ido bien
	if (!env.fault_occurred)
	{
		//POnemos el content type
		ResponseContentType(ses, (char*)"text/xml; charset=\"utf-8\"");
		//Y mandamos la respuesta
		XmlRpcServer::SendResponse(ses,200,XMLRPC_MEMBLOCK_CONTENTS(char, output), XMLRPC_MEMBLOCK_SIZE(char, output));
	} else