These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / ipxe / 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 };