bool ZoneAdminRpcMethod::validCaller(const HttpRequestContext& requestContext, const UtlString& peerName, XmlRpcResponse& response, const SipxRpc& sipxRpcImpl, const char* callingMethod ) { bool result = false; if (!peerName.isNull() && requestContext.isTrustedPeer(peerName)) { // ssl says the connection is from the named host if (sipxRpcImpl.isAllowedPeer(peerName)) { // sipXsupervisor says it is one of the allowed peers. result = true; OsSysLog::add(FAC_SUPERVISOR, PRI_DEBUG, "ZoneAdminRpcMethod::validCaller '%s' peer authenticated for %s", peerName.data(), callingMethod ); } else { // this peer is authenticated, but not configured, so provide a good error response UtlString faultMsg; faultMsg.append("Unconfigured calling host '"); faultMsg.append(peerName); faultMsg.append("'"); response.setFault(ZoneAdminRpcMethod::UnconfiguredPeer, faultMsg.data()); OsSysLog::add(FAC_SUPERVISOR, PRI_ERR, "%s failed - '%s' not a configured peer", callingMethod, peerName.data() ); } } else { // ssl says not authenticated - provide only a generic error response.setFault(XmlRpcResponse::AuthenticationRequired, "TLS Peer Authentication Failure"); OsSysLog::add(FAC_SUPERVISOR, PRI_ERR, "%s failed: '%s' failed SSL authentication", callingMethod, peerName.data() ); } return result; }
/// Whether or not an HTTP request is from some allowed peer, and if so which one. bool SipxRpc::isAllowedPeer(const HttpRequestContext& context, ///< the request to be checked UtlString& peer ///< if allowed, the name of the peer ) const { bool isAllowed = false; peer.remove(0); UtlSListIterator allowedPeers(mAllowedPeers); UtlString* tryPeer; while (!isAllowed && (tryPeer = dynamic_cast<UtlString*>(allowedPeers()))) { isAllowed = context.isTrustedPeer(*tryPeer); } if (isAllowed) { peer = *tryPeer; } return isAllowed; }
/// Access check function XmlRpcMethod::ExecutionStatus ConfigRPC_InDomainCallback::accessAllowed( const HttpRequestContext& requestContext, ConfigRPC_Callback::Method method ) const { XmlRpcMethod::ExecutionStatus isAllowed = ( requestContext.isTrustedPeer(mAllowedDomain) ? XmlRpcMethod::OK : XmlRpcMethod::FAILED ); /* * - XmlRpcMethod::OK if allowed * - XmlRpcMethod::FAILED if not allowed, * - XmlRpcMethod::REQUIRE_AUTHENTICATION if authentication is missing or invalid. */ if (XmlRpcMethod::FAILED == isAllowed) { Os::Logger::instance().log(FAC_KERNEL, PRI_WARNING, "ConfigRPC_InDomainCallback disallowed configuration from untrusted peer" ); } return isAllowed; }
/// Provide access to files as allowed by process definitions. void HttpFileAccess::processRequest(const HttpRequestContext& requestContext, const HttpMessage& request, HttpMessage*& response ) { UtlString message; response = new HttpMessage(); UtlString peerName; if (mSipxRpc->isAllowedPeer(requestContext, peerName)) { if (requestContext.methodIs(HTTP_GET_METHOD)) { UtlString path; requestContext.getMappedPath(path); FileResource* resource = FileResourceManager::getInstance()->find(path); if (resource) { if (resource->isReadable()) { sendFile(path, peerName, requestContext, request, response); } else { message.append("resource "); resource->appendDescription(message); message.append(" does not allow write access to '"); message.append(path); message.append("'"); OsSysLog::add(FAC_SUPERVISOR, PRI_ERR, "HttpFileAccess::processRequest from %s %s", peerName.data(), message.data()); response->setResponseFirstHeaderLine(HTTP_PROTOCOL_VERSION, HTTP_FORBIDDEN_CODE, "Access denied by process definition"); response->setBody(new HttpBody(message.data(),message.length())); response->setContentType(CONTENT_TYPE_TEXT_PLAIN); response->setContentLength(message.length()); } } else { message.append("File resource '"); message.append(path); message.append("' not known to sipXsupervisor."); OsSysLog::add(FAC_SUPERVISOR, PRI_ERR, "HttpFileAccess::processRequest from %s %s", peerName.data(), message.data()); response->setResponseFirstHeaderLine(HTTP_PROTOCOL_VERSION, HTTP_FILE_NOT_FOUND_CODE, HTTP_FILE_NOT_FOUND_TEXT); response->setBody(new HttpBody(message.data(),message.length())); response->setContentType(CONTENT_TYPE_TEXT_PLAIN); response->setContentLength(message.length()); } } else if (requestContext.methodIs(HTTP_DELETE_METHOD)) { UtlString path; requestContext.getMappedPath(path); FileResource* resource = FileResourceManager::getInstance()->find(path); if (resource) { if (resource->isWriteable()) { OsPath filePath(path); if (OsFileSystem::exists(filePath)) { if (OS_SUCCESS == OsFileSystem::remove(filePath, TRUE /* recursive */, TRUE /* force */)) { message.append("File '"); message.append(path); message.append("' deleted"); OsSysLog::add(FAC_SUPERVISOR, PRI_INFO, "HttpFileAccess::processRequest from %s %s", peerName.data(), message.data()); response->setResponseFirstHeaderLine(HTTP_PROTOCOL_VERSION_1_1, HTTP_OK_CODE, "Deleted"); response->setContentLength(0); // tell anyone who cares that this has changed resource->modified(); } else { int httpStatusCode; UtlString httpStatusText; switch (errno) { case EACCES: httpStatusCode = HTTP_FORBIDDEN_CODE; httpStatusText = "File Access Denied"; break; default: httpStatusCode = HTTP_SERVER_ERROR_CODE; httpStatusText.append("Unknown error "); httpStatusText.appendNumber(errno); break; } message.append("File '"); message.append(path); message.append("' errno "); message.appendNumber(errno); message.append(" "); char errnoMsg[1024]; strerror_r(errno, errnoMsg, sizeof(errnoMsg)); message.append(errnoMsg); OsSysLog::add(FAC_SUPERVISOR, PRI_ERR, "HttpFileAccess::processRequest from %s %s", peerName.data(), message.data()); response->setResponseFirstHeaderLine(HTTP_PROTOCOL_VERSION, httpStatusCode, httpStatusText); response->setBody(new HttpBody(message.data(),message.length())); response->setContentType(CONTENT_TYPE_TEXT_PLAIN); response->setContentLength(message.length()); } } else { message.append("File to be deleted '"); message.append(path); message.append("' does not exist"); OsSysLog::add(FAC_SUPERVISOR, PRI_INFO, "HttpFileAccess::processRequest from %s %s", peerName.data(), message.data()); response->setResponseFirstHeaderLine(HTTP_PROTOCOL_VERSION_1_1, HTTP_OK_CODE, "File does not exist"); response->setContentLength(0); } } else { message.append("resource "); resource->appendDescription(message); message.append(" does not allow write access to '"); message.append(path); message.append("'"); OsSysLog::add(FAC_SUPERVISOR, PRI_ERR, "HttpFileAccess::processRequest from %s %s", peerName.data(), message.data()); response->setResponseFirstHeaderLine(HTTP_PROTOCOL_VERSION, HTTP_FORBIDDEN_CODE, "Access denied by process definition"); response->setBody(new HttpBody(message.data(),message.length())); response->setContentType(CONTENT_TYPE_TEXT_PLAIN); response->setContentLength(message.length()); } } else { message.append("File resource '"); message.append(path); message.append("' not known to sipXsupervisor."); OsSysLog::add(FAC_SUPERVISOR, PRI_ERR, "HttpFileAccess::processRequest from %s %s", peerName.data(), message.data()); response->setResponseFirstHeaderLine(HTTP_PROTOCOL_VERSION, HTTP_FILE_NOT_FOUND_CODE, HTTP_FILE_NOT_FOUND_TEXT); response->setBody(new HttpBody(message.data(),message.length())); response->setContentType(CONTENT_TYPE_TEXT_PLAIN); response->setContentLength(message.length()); } } else { OsSysLog::add(FAC_SUPERVISOR, PRI_ERR, "HttpFileAccess::processRequest %s from %s", HTTP_UNSUPPORTED_METHOD_TEXT, peerName.data()); response->setResponseFirstHeaderLine(HTTP_PROTOCOL_VERSION, HTTP_UNSUPPORTED_METHOD_CODE, HTTP_UNSUPPORTED_METHOD_TEXT); } } else { message.append("Request not supported from untrusted peer."); OsSysLog::add(FAC_SUPERVISOR, PRI_ERR, "HttpFileAccess::processRequest %s", message.data()); response->setResponseFirstHeaderLine(HTTP_PROTOCOL_VERSION, HTTP_FORBIDDEN_CODE, HTTP_FORBIDDEN_TEXT); response->setBody(new HttpBody(message.data(),message.length())); response->setContentType(CONTENT_TYPE_TEXT_PLAIN); response->setContentLength(message.length()); } }
void HttpFileAccess::sendFile(const UtlString& path, const UtlString& peerName, const HttpRequestContext& requestContext, const HttpMessage& request, HttpMessage*& response ) { UtlString message; int file = open(path.data(), O_RDONLY); if (0 <= file) { UtlString fileBuffer; if (fileBuffer.capacity(MAX_FILE_CHUNK_SIZE + 1) >= MAX_FILE_CHUNK_SIZE + 1) { response->setResponseFirstHeaderLine(HTTP_PROTOCOL_VERSION_1_1, HTTP_OK_CODE, HTTP_OK_TEXT); response->useChunkedBody(true); // @TODO Annotate file resources with a mime type? // add a Content-Disposition header to suggest saving as the basename of the file response->setContentType("application/octet-stream"); UtlString dispositionValue; UtlString basename; ssize_t finalSlash = path.last('/'); if (UTL_NOT_FOUND != finalSlash) { basename.append(path, finalSlash+1, path.length()-finalSlash); } else { basename.append(path); // don't think this should ever be true.... } dispositionValue.append("attachment; filename=\""); dispositionValue.append(basename); dispositionValue.append("\""); response->setHeaderValue(HTTP_CONTENT_DISPOSITION_FIELD,dispositionValue.data()); bool writtenOk = response->writeHeaders(requestContext.socket()); ssize_t bytes; Int64 totalBytes = 0; Int64 chunks = 0; while ( writtenOk && (bytes = read(file, (void*)fileBuffer.data(), MAX_FILE_CHUNK_SIZE))) { fileBuffer.setLength(bytes); writtenOk = response->writeChunk(requestContext.socket(), fileBuffer); if (writtenOk) { totalBytes += bytes; chunks++; } OsSysLog::add(FAC_SUPERVISOR, PRI_DEBUG, "file block %"FORMAT_INTLL"d %zd %s", chunks, bytes, writtenOk ? "ok" : "failed"); } if (writtenOk) { response->writeEndOfChunks(requestContext.socket()); message.append(" sent file '"); message.append(path); message.append("' ("); message.appendNumber(totalBytes,"%"FORMAT_INTLL"d"); message.append(" bytes in "); message.appendNumber(chunks,"%"FORMAT_INTLL"d"); message.append(" chunks) to peer "); message.append(peerName); OsSysLog::add(FAC_SUPERVISOR, PRI_INFO, "HttpFileAccess::processRequest %s", message.data()); } else { message.append("error writing response after "); message.appendNumber(totalBytes,"%"FORMAT_INTLL"d"); message.append(" body bytes in "); message.appendNumber(chunks,"%"FORMAT_INTLL"d"); message.append(" chunks) to peer "); message.append(peerName); OsSysLog::add(FAC_SUPERVISOR, PRI_ERR, "HttpFileAccess::processRequest %s", message.data()); } /* * We've already written the response, so prevent HttpServer from sending it by * not passing it back. */ delete response; response = NULL; } else { // Send out-of-resources message message.append("Supervisor Buffer Exhausted"); response->setResponseFirstHeaderLine(HTTP_PROTOCOL_VERSION, HTTP_OUT_OF_RESOURCES_CODE, message.data()); response->setContentType(CONTENT_TYPE_TEXT_PLAIN); response->setBody(new HttpBody(message.data(),message.length())); response->setContentLength(message.length()); OsSysLog::add(FAC_SUPERVISOR, PRI_ERR, "HttpFileAccess::processRequest from %s %s", peerName.data(), message.data()); } } else { int httpStatusCode; UtlString httpStatusText; switch (errno) { case EACCES: httpStatusCode = HTTP_FORBIDDEN_CODE; httpStatusText = "File Access Denied"; break; case ENOENT: httpStatusCode = HTTP_FILE_NOT_FOUND_CODE; httpStatusText = HTTP_FILE_NOT_FOUND_TEXT; break; default: httpStatusCode = HTTP_SERVER_ERROR_CODE; httpStatusText = HTTP_SERVER_ERROR_TEXT; break; } message.append("File '"); message.append(path); message.append("' errno "); message.appendNumber(errno); message.append(" "); char errnoMsg[1024]; strerror_r(errno, errnoMsg, sizeof(errnoMsg)); message.append(errnoMsg); OsSysLog::add(FAC_SUPERVISOR, PRI_ERR, "HttpFileAccess::processRequest from %s %s", peerName.data(), message.data()); response->setResponseFirstHeaderLine(HTTP_PROTOCOL_VERSION, httpStatusCode, httpStatusText); response->setBody(new HttpBody(message.data(),message.length())); response->setContentType(CONTENT_TYPE_TEXT_PLAIN); response->setContentLength(message.length()); } }
void HttpServer::testCgiRequest(const HttpRequestContext& requestContext, const HttpMessage& request, HttpMessage*& response) { UtlString url; UtlString value; requestContext.getEnvironmentVariable(HttpRequestContext::HTTP_ENV_RAW_URL, url); UtlString cgiDump("<HTML>\n<TITLE>\n"); cgiDump.append(url); cgiDump.append(" dump\n</TITLE>\n<BODY>\n<H3>Environment Variables\n</H3>\n"); cgiDump.append("<TABLE BORDER=1>\n<TR>\n<TH ALIGN=LEFT>Name</TH>\n<TH ALIGN=LEFT>Value</TH>\n</TR>\n"); requestContext.getEnvironmentVariable(HttpRequestContext::HTTP_ENV_RAW_URL, value); cgiDump.append("<TR>\n<TD ALIGN=LEFT>HTTP_ENV_RAW_URL</TD>\n<TD ALIGN=LEFT>"); cgiDump.append(value); cgiDump.append("</TD>\n</TR>\n"); requestContext.getEnvironmentVariable(HttpRequestContext::HTTP_ENV_UNMAPPED_FILE, value); cgiDump.append("<TR>\n<TD ALIGN=LEFT>HTTP_ENV_UNMAPPED_FILE</TD>\n<TD ALIGN=LEFT>"); cgiDump.append(value); cgiDump.append("</TD>\n</TR>\n"); requestContext.getEnvironmentVariable(HttpRequestContext::HTTP_ENV_MAPPED_FILE, value); cgiDump.append("<TR>\n<TD ALIGN=LEFT>HTTP_ENV_MAPPED_FILE</TD>\n<TD ALIGN=LEFT>"); cgiDump.append(value); cgiDump.append("</TD>\n</TR>\n"); requestContext.getEnvironmentVariable(HttpRequestContext::HTTP_ENV_QUERY_STRING, value); cgiDump.append("<TR>\n<TD ALIGN=LEFT>HTTP_ENV_QUERY_STRING</TD>\n<TD ALIGN=LEFT>"); cgiDump.append(value); cgiDump.append("</TD>\n</TR>\n"); requestContext.getEnvironmentVariable(HttpRequestContext::HTTP_ENV_SERVER_NAME, value); cgiDump.append("<TR>\n<TD ALIGN=LEFT>HTTP_ENV_SERVER_NAME</TD>\n<TD ALIGN=LEFT>"); cgiDump.append(value); cgiDump.append("</TD>\n</TR>\n"); requestContext.getEnvironmentVariable(HttpRequestContext::HTTP_ENV_REQUEST_METHOD, value); cgiDump.append("<TR>\n<TD ALIGN=LEFT>HTTP_ENV_REQUEST_METHOD</TD>\n<TD ALIGN=LEFT>"); cgiDump.append(value); cgiDump.append("</TD>\n</TR>\n"); requestContext.getEnvironmentVariable(HttpRequestContext::HTTP_ENV_USER, value); cgiDump.append("<TR>\n<TD ALIGN=LEFT>HTTP_ENV_USER</TD>\n<TD ALIGN=LEFT>"); cgiDump.append(value); cgiDump.append("</TD>\n</TR>\n</TABLE>\n"); cgiDump.append("<H3>CGI/Form Variables\n</H3>\n"); cgiDump.append("<TABLE BORDER=1>\n<TR>\n<TH>Name</TH>\n<TH>Value</TH>\n</TR>\n"); int index = 0; UtlString name; while(requestContext.getCgiVariable(index, name, value)) { cgiDump.append("<TR>\n<TD ALIGN=LEFT>"); cgiDump.append(name); cgiDump.append("</TD>\n<TD ALIGN=LEFT>"); cgiDump.append(value); cgiDump.append("</TD>\n</TR>\n"); index++; } cgiDump.append("</TABLE>\n"); createHtmlResponse(HTTP_OK_CODE, HTTP_OK_TEXT, cgiDump.data(), response); url.remove(0); value.remove(0); cgiDump.remove(0); name.remove(0); }
/* ============================ ACCESSORS ================================= */ void WebServer::ProcessEvent( const HttpRequestContext& requestContext, const HttpMessage& request, HttpMessage*& response ) { // get the action type (used to be the event) UtlString event; response = new HttpMessage(); ssize_t len; UtlString httpString; SubscribeServerPluginBase* plugin = NULL; request.getBytes(&httpString , &len); Os::Logger::instance().log(FAC_SIP, PRI_INFO, "WebServer::ProcessEvent HttpEvent \n%s", httpString.data()); // get the ACTION CGI variable requestContext.getCgiVariable( EVENTTYPE, event ); if( !event.isNull()) { //according to event type , get the correct plugin from spPluginTable StatusPluginReference* pluginContainer = spPluginTable->getPlugin(event); if(pluginContainer) { plugin = pluginContainer->getPlugin(); if(plugin) { // send 200 ok reply. response->setResponseFirstHeaderLine ( HTTP_PROTOCOL_VERSION, HTTP_OK_CODE, HTTP_OK_TEXT ); //call the event handler for the plugin plugin->handleEvent(requestContext, request, *response); } else { Os::Logger::instance().log(FAC_SIP, PRI_ERR, "WebServer::ProcessEvent no plugin in container for event type '%s'", event.data() ); } } else { Os::Logger::instance().log(FAC_SIP, PRI_WARNING, "WebServer::ProcessEvent no plugin found for event type '%s'", event.data() ); } } else { Os::Logger::instance().log(FAC_SIP, PRI_WARNING, "WebServer::ProcessEvent no '" EVENTTYPE "' variable found" ); } // We did not find a plugin so nobody handled this request. if(plugin == NULL) { response->setResponseFirstHeaderLine ( HTTP_PROTOCOL_VERSION, HTTP_FILE_NOT_FOUND_CODE, HTTP_FILE_NOT_FOUND_TEXT ); } Os::Logger::instance().flush(); }