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