iPXE
httpntlm.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 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) NTLM authentication
30  *
31  */
32 
33 #include <string.h>
34 #include <errno.h>
35 #include <ipxe/uri.h>
36 #include <ipxe/base64.h>
37 #include <ipxe/ntlm.h>
38 #include <ipxe/netbios.h>
39 #include <ipxe/http.h>
40 
42 
43 /** Workstation name used for NTLM authentication */
44 static const char http_ntlm_workstation[] = "iPXE";
45 
46 /**
47  * Parse HTTP "WWW-Authenticate" header for NTLM authentication
48  *
49  * @v http HTTP transaction
50  * @v line Remaining header line
51  * @ret rc Return status code
52  */
53 static int http_parse_ntlm_auth ( struct http_transaction *http, char *line ) {
54  struct http_response_auth_ntlm *rsp = &http->response.auth.ntlm;
55  char *copy;
56  int len;
57  int rc;
58 
59  /* Create temporary copy of Base64-encoded challenge message */
60  copy = strdup ( line );
61  if ( ! copy ) {
62  rc = -ENOMEM;
63  goto err_alloc;
64  }
65 
66  /* Decode challenge message, overwriting the original */
67  len = base64_decode ( copy, line, strlen ( line ) );
68  if ( len < 0 ) {
69  rc = len;
70  DBGC ( http, "HTTP %p could not decode NTLM challenge "
71  "\"%s\": %s\n", http, copy, strerror ( rc ) );
72  goto err_decode;
73  }
74 
75  /* Parse challenge, if present */
76  if ( len ) {
77  rsp->challenge = ( ( void * ) line );
78  if ( ( rc = ntlm_challenge ( rsp->challenge, len,
79  &rsp->info ) ) != 0 ) {
80  DBGC ( http, "HTTP %p could not parse NTLM challenge: "
81  "%s\n", http, strerror ( rc ) );
82  goto err_challenge;
83  }
84  }
85 
86  /* Allow HTTP request to be retried if the request had not
87  * already tried authentication. Note that NTLM requires an
88  * additional round trip to obtain the challenge message,
89  * which is not present in the initial WWW-Authenticate.
90  */
91  if ( ( http->request.auth.auth == NULL ) ||
92  ( ( http->request.auth.auth == &http_ntlm_auth ) &&
93  ( http->request.auth.ntlm.len == 0 ) && len ) ) {
95  }
96 
97  /* Success */
98  rc = 0;
99 
100  err_challenge:
101  err_decode:
102  free ( copy );
103  err_alloc:
104  return rc;
105 }
106 
107 /**
108  * Perform HTTP NTLM authentication
109  *
110  * @v http HTTP transaction
111  * @ret rc Return status code
112  */
113 static int http_ntlm_authenticate ( struct http_transaction *http ) {
114  struct http_request_auth_ntlm *req = &http->request.auth.ntlm;
115  struct http_response_auth_ntlm *rsp = &http->response.auth.ntlm;
116  struct ntlm_key key;
117  const char *domain;
118  char *username;
119  const char *password;
120 
121  /* If we have no challenge yet, then just send a Negotiate message */
122  if ( ! rsp->challenge ) {
123  DBGC ( http, "HTTP %p sending NTLM Negotiate\n", http );
124  return 0;
125  }
126 
127  /* Record username */
128  if ( ! http->uri->user ) {
129  DBGC ( http, "HTTP %p has no username for NTLM "
130  "authentication\n", http );
131  return -EACCES;
132  }
133  req->username = http->uri->user;
134  password = ( http->uri->password ? http->uri->password : "" );
135 
136  /* Split NetBIOS [domain\]username */
137  username = ( ( char * ) req->username );
138  domain = netbios_domain ( &username );
139 
140  /* Generate key */
141  ntlm_key ( domain, username, password, &key );
142 
143  /* Generate responses */
144  ntlm_response ( &rsp->info, &key, NULL, &req->lm, &req->nt );
145 
146  /* Calculate Authenticate message length */
147  req->len = ntlm_authenticate_len ( &rsp->info, domain, username,
149 
150  /* Restore NetBIOS [domain\]username */
151  netbios_domain_undo ( domain, username );
152 
153  return 0;
154 }
155 
156 /**
157  * Construct HTTP "Authorization" header for NTLM authentication
158  *
159  * @v http HTTP transaction
160  * @v buf Buffer
161  * @v len Length of buffer
162  * @ret len Length of header value, or negative error
163  */
164 static int http_format_ntlm_auth ( struct http_transaction *http,
165  char *buf, size_t len ) {
166  struct http_request_auth_ntlm *req = &http->request.auth.ntlm;
167  struct http_response_auth_ntlm *rsp = &http->response.auth.ntlm;
168  struct ntlm_authenticate *auth;
169  const char *domain;
170  char *username;
171  size_t check;
172 
173  /* If we have no challenge yet, then just send a Negotiate message */
174  if ( ! rsp->challenge ) {
175  return base64_encode ( &ntlm_negotiate,
176  sizeof ( ntlm_negotiate ), buf, len );
177  }
178 
179  /* Skip allocation if just calculating length */
180  if ( ! len )
181  return base64_encoded_len ( req->len );
182 
183  /* Allocate temporary buffer for Authenticate message */
184  auth = malloc ( req->len );
185  if ( ! auth )
186  return -ENOMEM;
187 
188  /* Split NetBIOS [domain\]username */
189  username = ( ( char * ) req->username );
190  domain = netbios_domain ( &username );
191 
192  /* Construct raw Authenticate message */
193  check = ntlm_authenticate ( &rsp->info, domain, username,
194  http_ntlm_workstation, &req->lm,
195  &req->nt, auth );
196  assert ( check == req->len );
197 
198  /* Restore NetBIOS [domain\]username */
199  netbios_domain_undo ( domain, username );
200 
201  /* Base64-encode Authenticate message */
202  len = base64_encode ( auth, req->len, buf, len );
203 
204  /* Free raw Authenticate message */
205  free ( auth );
206 
207  return len;
208 }
209 
210 /** HTTP NTLM authentication scheme */
211 struct http_authentication http_ntlm_auth __http_authentication = {
212  .name = "NTLM",
213  .parse = http_parse_ntlm_auth,
214  .authenticate = http_ntlm_authenticate,
215  .format = http_format_ntlm_auth,
216 };
217 
218 /* Drag in HTTP authentication support */
219 REQUIRING_SYMBOL ( http_ntlm_auth );
220 REQUIRE_OBJECT ( httpauth );
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
unsigned int flags
Flags.
Definition: http.h:350
Error codes.
static void netbios_domain_undo(const char *domain, char *username)
Restore NetBIOS [domain]username.
Definition: netbios.h:23
void ntlm_response(struct ntlm_challenge_info *info, struct ntlm_key *key, struct ntlm_nonce *nonce, struct ntlm_lm_response *lm, struct ntlm_nt_response *nt)
Construct NTLM responses.
Definition: ntlm.c:166
#define DBGC(...)
Definition: compiler.h:505
HTTP response NTLM authorization descriptor.
Definition: http.h:287
struct uri * uri
Request URI.
Definition: http.h:432
static int http_format_ntlm_auth(struct http_transaction *http, char *buf, size_t len)
Construct HTTP "Authorization" header for NTLM authentication.
Definition: httpntlm.c:164
An HTTP authentication scheme.
Definition: http.h:516
#define EACCES
Permission denied.
Definition: errno.h:298
int base64_decode(const char *encoded, void *data, size_t len)
Base64-decode string.
Definition: base64.c:91
Uniform Resource Identifiers.
struct http_response_auth auth
Authorization descriptor.
Definition: http.h:346
static void void * auth
Definition: crypto.h:264
struct ntlm_nt_response nt
NT response.
Definition: http.h:181
struct http_request request
Request.
Definition: http.h:434
size_t ntlm_authenticate(struct ntlm_challenge_info *info, const char *domain, const char *username, const char *workstation, struct ntlm_lm_response *lm, struct ntlm_nt_response *nt, struct ntlm_authenticate *auth)
Construct NTLM Authenticate message.
Definition: ntlm.c:266
static size_t base64_encoded_len(size_t raw_len)
Calculate length of base64-encoded data.
Definition: base64.h:21
#define ENOMEM
Not enough space.
Definition: errno.h:534
size_t len
Authenticate message length.
Definition: http.h:183
struct http_response response
Response.
Definition: http.h:436
const char * netbios_domain(char **username)
Split NetBIOS [domain]username into separate domain and username fields.
Definition: netbios.c:46
An HTTP transaction.
Definition: http.h:415
Hyper Text Transport Protocol.
assert((readw(&hdr->flags) &(GTF_reading|GTF_writing))==0)
struct http_request_auth auth
Authentication descriptor.
Definition: http.h:222
REQUIRE_OBJECT(httpauth)
An Authenticate message.
Definition: ntlm.h:116
An NTLM verification key.
Definition: ntlm.h:175
uint64_t rsp
Definition: librm.h:267
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
struct http_authentication * auth
Authentication scheme (if any)
Definition: http.h:189
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
char * strdup(const char *src)
Duplicate string.
Definition: string.c:380
size_t strlen(const char *src)
Get length of string.
Definition: string.c:243
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
void * malloc(size_t size)
Allocate memory.
Definition: malloc.c:583
struct http_response_auth_ntlm ntlm
NTLM authorization descriptor.
Definition: http.h:305
static const char http_ntlm_workstation[]
Workstation name used for NTLM authentication.
Definition: httpntlm.c:44
static int http_ntlm_authenticate(struct http_transaction *http)
Perform HTTP NTLM authentication.
Definition: httpntlm.c:113
HTTP request NTLM authentication descriptor.
Definition: http.h:175
Base64 encoding.
uint32_t len
Length.
Definition: ena.h:14
A Challenge message.
Definition: ntlm.h:100
size_t ntlm_authenticate_len(struct ntlm_challenge_info *info, const char *domain, const char *username, const char *workstation)
Calculate NTLM Authenticate message length.
Definition: ntlm.c:325
const char * username
Username.
Definition: http.h:177
struct http_request_auth_ntlm ntlm
NTLM authentication descriptor.
Definition: http.h:197
const char * name
Name (e.g.
Definition: http.h:518
NetBIOS user names.
const char * password
Password.
Definition: uri.h:74
const char * user
User name.
Definition: uri.h:72
void ntlm_key(const char *domain, const char *username, const char *password, struct ntlm_key *key)
Calculate NTLM verification key.
Definition: ntlm.c:114
Transaction may be retried on failure.
Definition: http.h:360
NT LAN Manager (NTLM) authentication.
REQUIRING_SYMBOL(http_ntlm_auth)
struct ntlm_lm_response lm
LAN Manager response.
Definition: http.h:179
struct http_authentication http_ntlm_auth __http_authentication
HTTP NTLM authentication scheme.
Definition: httpntlm.c:41
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
String functions.
union @382 key
Sense key.
Definition: crypto.h:284
size_t base64_encode(const void *raw, size_t raw_len, char *data, size_t len)
Base64-encode data.
Definition: base64.c:51
struct ntlm_data domain
Domain name.
Definition: ntlm.h:16
static int http_parse_ntlm_auth(struct http_transaction *http, char *line)
Parse HTTP "WWW-Authenticate" header for NTLM authentication.
Definition: httpntlm.c:53
A Negotiate message.
Definition: ntlm.h:88