Files
ipxe/src/net/tcp/httpauth.c
T
Michael Brown 518a98eb56 [http] Rewrite HTTP core to support content encodings
Rewrite the HTTP core to allow for the addition of arbitrary content
encoding mechanisms, such as PeerDist and gzip.

The core now exposes http_open() which can be used to create requests
with an explicitly selected HTTP method, an optional requested content
range, and an optional request body.  A simple wrapper provides the
preexisting behaviour of creating either a GET request or an
application/x-www-form-urlencoded POST request (if the URI includes
parameters).

The HTTP SAN interface is now implemented using the generic block
device translator.  Individual blocks are requested using http_open()
to create a range request.

Server connections are now managed via a connection pool; this allows
for multiple requests to the same server (e.g. for SAN blocks) to be
completely unaware of each other.  Repeated HTTPS connections to the
same server can reuse a pooled connection, avoiding the per-connection
overhead of establishing a TLS session (which can take several seconds
if using a client certificate).

Support for HTTP SAN booting and for the Basic and Digest
authentication schemes is now optional and can be controlled via the
SANBOOT_PROTO_HTTP, HTTP_AUTH_BASIC, and HTTP_AUTH_DIGEST build
configuration options in config/general.h.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2015-08-17 13:24:33 +01:00

191 lines
5.0 KiB
C

/*
* Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 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 Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/**
* @file
*
* Hyper Text Transfer Protocol (HTTP) authentication
*
*/
#include <stdio.h>
#include <strings.h>
#include <errno.h>
#include <ipxe/http.h>
/**
* Identify authentication scheme
*
* @v http HTTP transaction
* @v name Scheme name
* @ret auth Authentication scheme, or NULL
*/
static struct http_authentication * http_authentication ( const char *name ) {
struct http_authentication *auth;
/* Identify authentication scheme */
for_each_table_entry ( auth, HTTP_AUTHENTICATIONS ) {
if ( strcasecmp ( name, auth->name ) == 0 )
return auth;
}
return NULL;
}
/** An HTTP "WWW-Authenticate" response field */
struct http_www_authenticate_field {
/** Name */
const char *name;
/** Offset */
size_t offset;
};
/** Define an HTTP "WWW-Authenticate" response field */
#define HTTP_WWW_AUTHENTICATE_FIELD( _name ) { \
.name = #_name, \
.offset = offsetof ( struct http_transaction, \
response.auth._name ), \
}
/**
* Set HTTP "WWW-Authenticate" response field value
*
* @v http HTTP transaction
* @v field Response field
* @v value Field value
*/
static inline void
http_www_auth_field ( struct http_transaction *http,
struct http_www_authenticate_field *field, char *value ) {
char **ptr;
ptr = ( ( ( void * ) http ) + field->offset );
*ptr = value;
}
/** HTTP "WWW-Authenticate" fields */
static struct http_www_authenticate_field http_www_auth_fields[] = {
HTTP_WWW_AUTHENTICATE_FIELD ( realm ),
HTTP_WWW_AUTHENTICATE_FIELD ( qop ),
HTTP_WWW_AUTHENTICATE_FIELD ( algorithm ),
HTTP_WWW_AUTHENTICATE_FIELD ( nonce ),
HTTP_WWW_AUTHENTICATE_FIELD ( opaque ),
};
/**
* Parse HTTP "WWW-Authenticate" header
*
* @v http HTTP transaction
* @v line Remaining header line
* @ret rc Return status code
*/
static int http_parse_www_authenticate ( struct http_transaction *http,
char *line ) {
struct http_www_authenticate_field *field;
char *name;
char *key;
char *value;
unsigned int i;
/* Get scheme name */
name = http_token ( &line, NULL );
if ( ! name ) {
DBGC ( http, "HTTP %p malformed WWW-Authenticate \"%s\"\n",
http, value );
return -EPROTO;
}
/* Identify scheme */
http->response.auth.auth = http_authentication ( name );
if ( ! http->response.auth.auth ) {
DBGC ( http, "HTTP %p unrecognised authentication scheme "
"\"%s\"\n", http, name );
return -ENOTSUP;
}
/* Process fields */
while ( ( key = http_token ( &line, &value ) ) ) {
for ( i = 0 ; i < ( sizeof ( http_www_auth_fields ) /
sizeof ( http_www_auth_fields[0] ) ) ; i++){
field = &http_www_auth_fields[i];
if ( strcasecmp ( key, field->name ) == 0 )
http_www_auth_field ( http, field, value );
}
}
/* Allow HTTP request to be retried if the request had not
* already tried authentication.
*/
if ( ! http->request.auth.auth )
http->response.flags |= HTTP_RESPONSE_RETRY;
return 0;
}
/** HTTP "WWW-Authenticate" header */
struct http_response_header
http_response_www_authenticate __http_response_header = {
.name = "WWW-Authenticate",
.parse = http_parse_www_authenticate,
};
/**
* Construct HTTP "Authorization" header
*
* @v http HTTP transaction
* @v buf Buffer
* @v len Length of buffer
* @ret len Length of header value, or negative error
*/
static int http_format_authorization ( struct http_transaction *http,
char *buf, size_t len ) {
struct http_authentication *auth = http->request.auth.auth;
size_t used;
int auth_len;
int rc;
/* Do nothing unless we have an authentication scheme */
if ( ! auth )
return 0;
/* Construct header */
used = snprintf ( buf, len, "%s ", auth->name );
auth_len = auth->format ( http, ( buf + used ),
( ( used < len ) ? ( len - used ) : 0 ) );
if ( auth_len < 0 ) {
rc = auth_len;
return rc;
}
used += auth_len;
return used;
}
/** HTTP "Authorization" header */
struct http_request_header http_request_authorization __http_request_header = {
.name = "Authorization",
.format = http_format_authorization,
};