Merge branch 'master' of ssh://git.samba.org/data/git/samba into libcli-auth-merge...
[bbaumbach/samba-autobuild/.git] / libcli / auth / credentials.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    code to manipulate domain credentials
5
6    Copyright (C) Andrew Tridgell 1997-2003
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "system/time.h"
25 #include "../lib/crypto/crypto.h"
26 #include "libcli/auth/libcli_auth.h"
27
28 /*
29   initialise the credentials state for old-style 64 bit session keys
30
31   this call is made after the netr_ServerReqChallenge call
32 */
33 static void netlogon_creds_init_64bit(struct netlogon_creds_CredentialState *creds,
34                                       const struct netr_Credential *client_challenge,
35                                       const struct netr_Credential *server_challenge,
36                                       const struct samr_Password *machine_password)
37 {
38         uint32_t sum[2];
39         uint8_t sum2[8];
40
41         sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
42         sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
43
44         SIVAL(sum2,0,sum[0]);
45         SIVAL(sum2,4,sum[1]);
46
47         ZERO_STRUCT(creds->session_key);
48
49         des_crypt128(creds->session_key, sum2, machine_password->hash);
50
51         des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
52         des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
53
54         creds->seed = creds->client;
55 }
56
57 /*
58   initialise the credentials state for ADS-style 128 bit session keys
59
60   this call is made after the netr_ServerReqChallenge call
61 */
62 static void netlogon_creds_init_128bit(struct netlogon_creds_CredentialState *creds,
63                                        const struct netr_Credential *client_challenge,
64                                        const struct netr_Credential *server_challenge,
65                                        const struct samr_Password *machine_password)
66 {
67         unsigned char zero[4], tmp[16];
68         HMACMD5Context ctx;
69         struct MD5Context md5;
70
71         ZERO_STRUCT(creds->session_key);
72
73         memset(zero, 0, sizeof(zero));
74
75         hmac_md5_init_rfc2104(machine_password->hash, sizeof(machine_password->hash), &ctx);    
76         MD5Init(&md5);
77         MD5Update(&md5, zero, sizeof(zero));
78         MD5Update(&md5, client_challenge->data, 8);
79         MD5Update(&md5, server_challenge->data, 8);
80         MD5Final(tmp, &md5);
81         hmac_md5_update(tmp, sizeof(tmp), &ctx);
82         hmac_md5_final(creds->session_key, &ctx);
83
84         creds->client = *client_challenge;
85         creds->server = *server_challenge;
86
87         des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
88         des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
89
90         creds->seed = creds->client;
91 }
92
93
94 /*
95   step the credentials to the next element in the chain, updating the
96   current client and server credentials and the seed
97 */
98 static void netlogon_creds_step(struct netlogon_creds_CredentialState *creds)
99 {
100         struct netr_Credential time_cred;
101
102         DEBUG(5,("\tseed        %08x:%08x\n", 
103                  IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
104
105         SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
106         SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
107
108         DEBUG(5,("\tseed+time   %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
109
110         des_crypt112(creds->client.data, time_cred.data, creds->session_key, 1);
111
112         DEBUG(5,("\tCLIENT      %08x:%08x\n", 
113                  IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
114
115         SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
116         SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
117
118         DEBUG(5,("\tseed+time+1 %08x:%08x\n", 
119                  IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
120
121         des_crypt112(creds->server.data, time_cred.data, creds->session_key, 1);
122
123         DEBUG(5,("\tSERVER      %08x:%08x\n", 
124                  IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
125
126         creds->seed = time_cred;
127 }
128
129
130 /*
131   DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
132 */
133 void netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
134 {
135         struct netr_LMSessionKey tmp;
136         des_crypt56(tmp.key, key->key, creds->session_key, 1);
137         *key = tmp;
138 }
139
140 /*
141   DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
142 */
143 void netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds, struct netr_LMSessionKey *key)
144 {
145         struct netr_LMSessionKey tmp;
146         des_crypt56(tmp.key, key->key, creds->session_key, 0);
147         *key = tmp;
148 }
149
150 /*
151   DES encrypt a 16 byte password buffer using the session key
152 */
153 void netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
154 {
155         struct samr_Password tmp;
156         des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
157         *pass = tmp;
158 }
159
160 /*
161   DES decrypt a 16 byte password buffer using the session key
162 */
163 void netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState *creds, struct samr_Password *pass)
164 {
165         struct samr_Password tmp;
166         des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
167         *pass = tmp;
168 }
169
170 /*
171   ARCFOUR encrypt/decrypt a password buffer using the session key
172 */
173 void netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
174 {
175         DATA_BLOB session_key = data_blob(creds->session_key, 16);
176
177         arcfour_crypt_blob(data, len, &session_key);
178
179         data_blob_free(&session_key);
180 }
181
182 /*****************************************************************
183 The above functions are common to the client and server interface
184 next comes the client specific functions
185 ******************************************************************/
186
187 /*
188   initialise the credentials chain and return the first client
189   credentials
190 */
191  
192 struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *mem_ctx, 
193                                                                   const char *client_account,
194                                                                   const char *client_computer_name, 
195                                                                   const struct netr_Credential *client_challenge,
196                                                                   const struct netr_Credential *server_challenge,
197                                                                   const struct samr_Password *machine_password,
198                                                                   struct netr_Credential *initial_credential,
199                                                                   uint32_t negotiate_flags)
200 {
201         struct netlogon_creds_CredentialState *creds = talloc(mem_ctx, struct netlogon_creds_CredentialState);
202         
203         if (!creds) {
204                 return NULL;
205         }
206         
207         creds->sequence = time(NULL);
208         creds->negotiate_flags = negotiate_flags;
209
210         creds->computer_name = talloc_strdup(creds, client_computer_name);
211         if (!creds->computer_name) {
212                 talloc_free(creds);
213                 return NULL;
214         }
215         creds->account_name = talloc_strdup(creds, client_account);
216         if (!creds->account_name) {
217                 talloc_free(creds);
218                 return NULL;
219         }
220
221         dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
222         dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
223         dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
224
225         if (negotiate_flags & NETLOGON_NEG_128BIT) {
226                 netlogon_creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
227         } else {
228                 netlogon_creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
229         }
230
231         dump_data_pw("Session key", creds->session_key, 16);
232         dump_data_pw("Credential ", creds->client.data, 8);
233
234         *initial_credential = creds->client;
235         return creds;
236 }
237
238 /*
239   initialise the credentials structure with only a session key.  The caller better know what they are doing!
240  */
241
242 struct netlogon_creds_CredentialState *netlogon_creds_client_init_session_key(TALLOC_CTX *mem_ctx, 
243                                                                               const uint8_t session_key[16])
244 {
245         struct netlogon_creds_CredentialState *creds = talloc(mem_ctx, struct netlogon_creds_CredentialState);
246         
247         if (!creds) {
248                 return NULL;
249         }
250         
251         memcpy(creds->session_key, session_key, 16);
252
253         return creds;
254 }
255
256 /*
257   step the credentials to the next element in the chain, updating the
258   current client and server credentials and the seed
259
260   produce the next authenticator in the sequence ready to send to 
261   the server
262 */
263 void netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds,
264                                 struct netr_Authenticator *next)
265 {       
266         creds->sequence += 2;
267         netlogon_creds_step(creds);
268
269         next->cred = creds->client;
270         next->timestamp = creds->sequence;
271 }
272
273 /*
274   check that a credentials reply from a server is correct
275 */
276 bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds,
277                         const struct netr_Credential *received_credentials)
278 {
279         if (!received_credentials || 
280             memcmp(received_credentials->data, creds->server.data, 8) != 0) {
281                 DEBUG(2,("credentials check failed\n"));
282                 return false;
283         }
284         return true;
285 }
286
287
288 /*****************************************************************
289 The above functions are common to the client and server interface
290 next comes the server specific functions
291 ******************************************************************/
292
293 /*
294   check that a credentials reply from a server is correct
295 */
296 static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState *creds,
297                                                  const struct netr_Credential *received_credentials)
298 {
299         if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
300                 DEBUG(2,("credentials check failed\n"));
301                 dump_data_pw("client creds", creds->client.data, 8);
302                 dump_data_pw("calc   creds", received_credentials->data, 8);
303                 return false;
304         }
305         return true;
306 }
307
308 /*
309   initialise the credentials chain and return the first server
310   credentials
311 */
312 struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *mem_ctx, 
313                                                                   const char *client_account,
314                                                                   const char *client_computer_name, 
315                                                                   uint16_t secure_channel_type,
316                                                                   const struct netr_Credential *client_challenge,
317                                                                   const struct netr_Credential *server_challenge,
318                                                                   const struct samr_Password *machine_password,
319                                                                   struct netr_Credential *credentials_in,
320                                                                   struct netr_Credential *credentials_out,
321                                                                   uint32_t negotiate_flags)
322 {
323         
324         struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
325         
326         if (!creds) {
327                 return NULL;
328         }
329         
330         creds->negotiate_flags = negotiate_flags;
331
332         creds->computer_name = talloc_strdup(creds, client_computer_name);
333         if (!creds->computer_name) {
334                 talloc_free(creds);
335                 return NULL;
336         }
337         creds->account_name = talloc_strdup(creds, client_account);
338         if (!creds->account_name) {
339                 talloc_free(creds);
340                 return NULL;
341         }
342
343         if (negotiate_flags & NETLOGON_NEG_128BIT) {
344                 netlogon_creds_init_128bit(creds, client_challenge, server_challenge, 
345                                            machine_password);
346         } else {
347                 netlogon_creds_init_64bit(creds, client_challenge, server_challenge, 
348                                           machine_password);
349         }
350
351         /* And before we leak information about the machine account
352          * password, check that they got the first go right */
353         if (!netlogon_creds_server_check_internal(creds, credentials_in)) {
354                 talloc_free(creds);
355                 return NULL;
356         }
357
358         *credentials_out = creds->server;
359
360         return creds;
361 }
362
363 NTSTATUS netlogon_creds_server_step_check(struct netlogon_creds_CredentialState *creds,
364                                  struct netr_Authenticator *received_authenticator,
365                                  struct netr_Authenticator *return_authenticator) 
366 {
367         if (!received_authenticator || !return_authenticator) {
368                 return NT_STATUS_INVALID_PARAMETER;
369         }
370
371         if (!creds) {
372                 return NT_STATUS_ACCESS_DENIED;
373         }
374
375         /* TODO: this may allow the a replay attack on a non-signed
376            connection. Should we check that this is increasing? */
377         creds->sequence = received_authenticator->timestamp;
378         netlogon_creds_step(creds);
379         if (netlogon_creds_server_check_internal(creds, &received_authenticator->cred)) {
380                 return_authenticator->cred = creds->server;
381                 return_authenticator->timestamp = creds->sequence;
382                 return NT_STATUS_OK;
383         } else {
384                 ZERO_STRUCTP(return_authenticator);
385                 return NT_STATUS_ACCESS_DENIED;
386         }
387 }
388
389 void netlogon_creds_decrypt_samlogon(struct netlogon_creds_CredentialState *creds,
390                             uint16_t validation_level,
391                             union netr_Validation *validation) 
392 {
393         static const char zeros[16];
394
395         struct netr_SamBaseInfo *base = NULL;
396         switch (validation_level) {
397         case 2:
398                 if (validation->sam2) {
399                         base = &validation->sam2->base;
400                 }
401                 break;
402         case 3:
403                 if (validation->sam3) {
404                         base = &validation->sam3->base;
405                 }
406                 break;
407         case 6:
408                 if (validation->sam6) {
409                         base = &validation->sam6->base;
410                 }
411                 break;
412         default:
413                 /* If we can't find it, we can't very well decrypt it */
414                 return;
415         }
416
417         if (!base) {
418                 return;
419         }
420
421         /* find and decyrpt the session keys, return in parameters above */
422         if (validation_level == 6) {
423                 /* they aren't encrypted! */
424         } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
425                 if (memcmp(base->key.key, zeros,  
426                            sizeof(base->key.key)) != 0) {
427                         netlogon_creds_arcfour_crypt(creds, 
428                                             base->key.key, 
429                                             sizeof(base->key.key));
430                 }
431                         
432                 if (memcmp(base->LMSessKey.key, zeros,  
433                            sizeof(base->LMSessKey.key)) != 0) {
434                         netlogon_creds_arcfour_crypt(creds, 
435                                             base->LMSessKey.key, 
436                                             sizeof(base->LMSessKey.key));
437                 }
438         } else {
439                 if (memcmp(base->LMSessKey.key, zeros,  
440                            sizeof(base->LMSessKey.key)) != 0) {
441                         netlogon_creds_des_decrypt_LMKey(creds, 
442                                                 &base->LMSessKey);
443                 }
444         }
445 }       
446