/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ /** * $Id$ * * @brief Function prototypes and datatypes for the REST (HTTP) transport. * @file rest.h * * @copyright 2012-2014 Arran Cudbard-Bell */ RCSIDH(other_h, "$Id$") #include #include "config.h" #define CURL_NO_OLDIES 1 #include #ifdef HAVE_WDOCUMENTATION DIAG_OFF(documentation) #endif #ifdef HAVE_JSON # if defined(HAVE_JSONMC_JSON_H) # include # elif defined(HAVE_JSON_JSON_H) # include # endif #endif #ifdef HAVE_WDOCUMENTATION DIAG_ON(documentation) #endif #define REST_URI_MAX_LEN 2048 #define REST_BODY_MAX_LEN 8192 #define REST_BODY_INIT 1024 #define REST_BODY_MAX_ATTRS 256 typedef enum { HTTP_METHOD_UNKNOWN = 0, HTTP_METHOD_GET, HTTP_METHOD_POST, HTTP_METHOD_PUT, HTTP_METHOD_PATCH, HTTP_METHOD_DELETE, HTTP_METHOD_CUSTOM //!< Must always come last, should not be in method table } http_method_t; typedef enum { HTTP_BODY_UNKNOWN = 0, HTTP_BODY_UNSUPPORTED, HTTP_BODY_UNAVAILABLE, HTTP_BODY_INVALID, HTTP_BODY_NONE, HTTP_BODY_CUSTOM_XLAT, HTTP_BODY_CUSTOM_LITERAL, HTTP_BODY_POST, HTTP_BODY_JSON, HTTP_BODY_XML, HTTP_BODY_YAML, HTTP_BODY_HTML, HTTP_BODY_PLAIN, HTTP_BODY_NUM_ENTRIES } http_body_type_t; typedef enum { HTTP_AUTH_UNKNOWN = 0, HTTP_AUTH_NONE, HTTP_AUTH_TLS_SRP, HTTP_AUTH_BASIC, HTTP_AUTH_DIGEST, HTTP_AUTH_DIGEST_IE, HTTP_AUTH_GSSNEGOTIATE, HTTP_AUTH_NTLM, HTTP_AUTH_NTLM_WB, HTTP_AUTH_ANY, HTTP_AUTH_ANY_SAFE, HTTP_AUTH_NUM_ENTRIES } http_auth_type_t; /* * Must be updated (in rest.c) if additional values are added to * http_body_type_t */ extern const http_body_type_t http_body_type_supported[HTTP_BODY_NUM_ENTRIES]; extern const unsigned long http_curl_auth[HTTP_AUTH_NUM_ENTRIES]; extern const FR_NAME_NUMBER http_auth_table[]; extern const FR_NAME_NUMBER http_method_table[]; extern const FR_NAME_NUMBER http_body_type_table[]; extern const FR_NAME_NUMBER http_content_type_table[]; extern const FR_NAME_NUMBER http_negotiation_table[]; /* * Structure for section configuration */ typedef struct rlm_rest_section_t { char const *name; //!< Section name. char const *uri; //!< URI to send HTTP request to. char const *method_str; //!< The string version of the HTTP method. http_method_t method; //!< What HTTP method should be used, GET, POST etc... char const *body_str; //!< The string version of the encoding/content type. http_body_type_t body; //!< What encoding type should be used. bool attr_num; //!< If true, the the attribute number is supplied for each attribute. bool raw_value; //!< If true, enumerated attributes are provided as a numeric value char const *force_to_str; //!< Force decoding with this decoder. http_body_type_t force_to; //!< Override the Content-Type header in the response //!< to force decoding as a particular type. char const *data; //!< Custom body data (optional). char const *auth_str; //!< The string version of the Auth-Type. http_auth_type_t auth; //!< HTTP auth type. bool require_auth; //!< Whether HTTP-Auth is required or not. char const *username; //!< Username used for HTTP-Auth char const *password; //!< Password used for HTTP-Auth char const *tls_certificate_file; char const *tls_private_key_file; char const *tls_private_key_password; char const *tls_ca_file; char const *tls_ca_info_file; char const *tls_ca_path; char const *tls_random_file; bool tls_check_cert; bool tls_check_cert_cn; bool body_encode; //!< Should the body data be URI encoded. Only applies //!< to xlats. struct timeval timeout_tv; //!< Timeout timeval. long timeout; //!< Timeout in ms. uint32_t chunk; //!< Max chunk-size (mainly for testing the encoders) } rlm_rest_section_t; /* * Structure for module configuration */ typedef struct rlm_rest_t { char const *xlat_name; //!< Instance name. char const *connect_uri; //!< URI we attempt to connect to, to pre-establish //!< TCP connections. struct timeval connect_timeout_tv; //!< Connection timeout timeval. long connect_timeout; //!< Connection timeout ms. char const *http_negotiation_str; //!< The string version of the http_negotiation long http_negotiation; //!< The HTTP protocol version to use fr_connection_pool_t *pool; //!< Pointer to the connection pool. rlm_rest_section_t authorize; //!< Configuration specific to authorisation. rlm_rest_section_t authenticate; //!< Configuration specific to authentication. rlm_rest_section_t preacct; //!< Configuration specific to preacct. rlm_rest_section_t accounting; //!< Configuration specific to accounting. rlm_rest_section_t checksimul; //!< Configuration specific to simultaneous session //!< checking. rlm_rest_section_t post_auth; //!< Configuration specific to Post-auth rlm_rest_section_t pre_proxy; //!< Configuration specific to pre_proxy rlm_rest_section_t post_proxy; //!< Configuration specific to post_proxy rlm_rest_section_t xlat; //!< Configuration specific to xlats #ifdef WITH_COA rlm_rest_section_t recv_coa; //!< Configuration specific to recv-coa #endif } rlm_rest_t; /* * States for stream based attribute encoders */ typedef enum { READ_STATE_INIT = 0, READ_STATE_ATTR_BEGIN, READ_STATE_ATTR_CONT, READ_STATE_ATTR_END, READ_STATE_END, } read_state_t; /* * States for the response parser */ typedef enum { WRITE_STATE_INIT = 0, WRITE_STATE_PARSE_HEADERS, WRITE_STATE_PARSE_CONTENT, WRITE_STATE_DISCARD, } write_state_t; /* * Outbound data context (passed to CURLOPT_READFUNCTION as CURLOPT_READDATA) */ typedef struct rlm_rest_request_t { rlm_rest_t *instance; //!< This instance of rlm_rest. REQUEST *request; //!< Current request. read_state_t state; //!< Encoder state vp_cursor_t cursor; //!< Cursor pointing to the start of the list to encode. size_t chunk; //!< Chunk size rlm_rest_section_t *section; //!< Configuration data void *encoder; //!< Encoder specific data. } rlm_rest_request_t; /* * Curl inbound data context (passed to CURLOPT_WRITEFUNCTION and * CURLOPT_HEADERFUNCTION as CURLOPT_WRITEDATA and CURLOPT_HEADERDATA) */ typedef struct rlm_rest_response_t { rlm_rest_t *instance; //!< This instance of rlm_rest. REQUEST *request; //!< Current request. write_state_t state; //!< Decoder state. char *buffer; //!< Raw incoming HTTP data. size_t alloc; //!< Space allocated for buffer. size_t used; //!< Space used in buffer. int code; //!< HTTP Status Code. http_body_type_t type; //!< HTTP Content Type. http_body_type_t force_to; //!< Force decoding the body type as a particular encoding. void *decoder; //!< Decoder specific data. } rlm_rest_response_t; /* * Curl context data */ typedef struct rlm_rest_curl_context_t { struct curl_slist *headers; //!< Any HTTP headers which will be sent with the //!< request. char *body; //!< Pointer to the buffer which contains body data/ //!< Only used when not performing chunked encoding. rlm_rest_request_t request; //!< Request context data. rlm_rest_response_t response; //!< Response context data. } rlm_rest_curl_context_t; /* * Connection API handle */ typedef struct rlm_rest_handle_t { void *handle; //!< Real Handle. rlm_rest_curl_context_t *ctx; //!< Context. } rlm_rest_handle_t; /* * Function prototype for rest_read_wrapper. Matches CURL's * CURLOPT_READFUNCTION prototype. */ typedef size_t (*rest_read_t)(void *ptr, size_t size, size_t nmemb, void *userdata); /* * Connection API callbacks */ int rest_init(rlm_rest_t *instance); void rest_cleanup(void); void *mod_conn_create(TALLOC_CTX *ctx, void *instance); int mod_conn_alive(void *instance, void *handle); /* * Request processing API */ int rest_request_config(rlm_rest_t *instance, rlm_rest_section_t *section, REQUEST *request, void *handle, http_method_t method, http_body_type_t type, char const *uri, char const *username, char const *password) CC_HINT(nonnull (1,2,3,4,7)); int rest_request_perform(rlm_rest_t *instance, rlm_rest_section_t *section, REQUEST *request, void *handle); int rest_response_decode(rlm_rest_t *instance, UNUSED rlm_rest_section_t *section, REQUEST *request, void *handle); void rest_response_error(REQUEST *request, rlm_rest_handle_t *handle); void rest_request_cleanup(rlm_rest_t *instance, rlm_rest_section_t *section, void *handle); #define rest_get_handle_code(handle)(((rlm_rest_curl_context_t*)((rlm_rest_handle_t*)handle)->ctx)->response.code) #define rest_get_handle_type(handle)(((rlm_rest_curl_context_t*)((rlm_rest_handle_t*)handle)->ctx)->response.type) size_t rest_get_handle_data(char const **out, rlm_rest_handle_t *handle); /* * Helper functions */ size_t rest_uri_escape(UNUSED REQUEST *request, char *out, size_t outlen, char const *raw, UNUSED void *arg); ssize_t rest_uri_build(char **out, rlm_rest_t *instance, REQUEST *request, char const *uri); ssize_t rest_uri_host_unescape(char **out, UNUSED rlm_rest_t *instance, REQUEST *request, void *handle, char const *uri);