[http] Cleanly shut down potentially looped interfaces
[ipxe.git] / src / net / tcp / httpauth.c
1 /*
2 * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26 /**
27 * @file
28 *
29 * Hyper Text Transfer Protocol (HTTP) authentication
30 *
31 */
32
33 #include <stdio.h>
34 #include <strings.h>
35 #include <errno.h>
36 #include <ipxe/http.h>
37
38 /**
39 * Identify authentication scheme
40 *
41 * @v http HTTP transaction
42 * @v name Scheme name
43 * @ret auth Authentication scheme, or NULL
44 */
45 static struct http_authentication * http_authentication ( const char *name ) {
46 struct http_authentication *auth;
47
48 /* Identify authentication scheme */
49 for_each_table_entry ( auth, HTTP_AUTHENTICATIONS ) {
50 if ( strcasecmp ( name, auth->name ) == 0 )
51 return auth;
52 }
53
54 return NULL;
55 }
56
57 /** An HTTP "WWW-Authenticate" response field */
58 struct http_www_authenticate_field {
59 /** Name */
60 const char *name;
61 /** Offset */
62 size_t offset;
63 };
64
65 /** Define an HTTP "WWW-Authenticate" response field */
66 #define HTTP_WWW_AUTHENTICATE_FIELD( _name ) { \
67 .name = #_name, \
68 .offset = offsetof ( struct http_transaction, \
69 response.auth._name ), \
70 }
71
72 /**
73 * Set HTTP "WWW-Authenticate" response field value
74 *
75 * @v http HTTP transaction
76 * @v field Response field
77 * @v value Field value
78 */
79 static inline void
80 http_www_auth_field ( struct http_transaction *http,
81 struct http_www_authenticate_field *field, char *value ) {
82 char **ptr;
83
84 ptr = ( ( ( void * ) http ) + field->offset );
85 *ptr = value;
86 }
87
88 /** HTTP "WWW-Authenticate" fields */
89 static struct http_www_authenticate_field http_www_auth_fields[] = {
90 HTTP_WWW_AUTHENTICATE_FIELD ( realm ),
91 HTTP_WWW_AUTHENTICATE_FIELD ( qop ),
92 HTTP_WWW_AUTHENTICATE_FIELD ( algorithm ),
93 HTTP_WWW_AUTHENTICATE_FIELD ( nonce ),
94 HTTP_WWW_AUTHENTICATE_FIELD ( opaque ),
95 };
96
97 /**
98 * Parse HTTP "WWW-Authenticate" header
99 *
100 * @v http HTTP transaction
101 * @v line Remaining header line
102 * @ret rc Return status code
103 */
104 static int http_parse_www_authenticate ( struct http_transaction *http,
105 char *line ) {
106 struct http_www_authenticate_field *field;
107 char *name;
108 char *key;
109 char *value;
110 unsigned int i;
111
112 /* Get scheme name */
113 name = http_token ( &line, NULL );
114 if ( ! name ) {
115 DBGC ( http, "HTTP %p malformed WWW-Authenticate \"%s\"\n",
116 http, value );
117 return -EPROTO;
118 }
119
120 /* Identify scheme */
121 http->response.auth.auth = http_authentication ( name );
122 if ( ! http->response.auth.auth ) {
123 DBGC ( http, "HTTP %p unrecognised authentication scheme "
124 "\"%s\"\n", http, name );
125 return -ENOTSUP;
126 }
127
128 /* Process fields */
129 while ( ( key = http_token ( &line, &value ) ) ) {
130 for ( i = 0 ; i < ( sizeof ( http_www_auth_fields ) /
131 sizeof ( http_www_auth_fields[0] ) ) ; i++){
132 field = &http_www_auth_fields[i];
133 if ( strcasecmp ( key, field->name ) == 0 )
134 http_www_auth_field ( http, field, value );
135 }
136 }
137
138 /* Allow HTTP request to be retried if the request had not
139 * already tried authentication.
140 */
141 if ( ! http->request.auth.auth )
142 http->response.flags |= HTTP_RESPONSE_RETRY;
143
144 return 0;
145 }
146
147 /** HTTP "WWW-Authenticate" header */
148 struct http_response_header
149 http_response_www_authenticate __http_response_header = {
150 .name = "WWW-Authenticate",
151 .parse = http_parse_www_authenticate,
152 };
153
154 /**
155 * Construct HTTP "Authorization" header
156 *
157 * @v http HTTP transaction
158 * @v buf Buffer
159 * @v len Length of buffer
160 * @ret len Length of header value, or negative error
161 */
162 static int http_format_authorization ( struct http_transaction *http,
163 char *buf, size_t len ) {
164 struct http_authentication *auth = http->request.auth.auth;
165 size_t used;
166 int auth_len;
167 int rc;
168
169 /* Do nothing unless we have an authentication scheme */
170 if ( ! auth )
171 return 0;
172
173 /* Construct header */
174 used = snprintf ( buf, len, "%s ", auth->name );
175 auth_len = auth->format ( http, ( buf + used ),
176 ( ( used < len ) ? ( len - used ) : 0 ) );
177 if ( auth_len < 0 ) {
178 rc = auth_len;
179 return rc;
180 }
181 used += auth_len;
182
183 return used;
184 }
185
186 /** HTTP "Authorization" header */
187 struct http_request_header http_request_authorization __http_request_header = {
188 .name = "Authorization",
189 .format = http_format_authorization,
190 };