r4641: Push a few more details into the schannel ldb, and into the
[kai/samba-autobuild/.git] / source4 / 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 2 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, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "system/time.h"
26 #include "auth/auth.h"
27 #include "lib/crypto/crypto.h"
28 #include "librpc/gen_ndr/ndr_netlogon.h"
29
30 /*
31   initialise the credentials state for old-style 64 bit session keys
32
33   this call is made after the netr_ServerReqChallenge call
34 */
35 static void creds_init_64bit(struct creds_CredentialState *creds,
36                              const struct netr_Credential *client_challenge,
37                              const struct netr_Credential *server_challenge,
38                              const struct samr_Password *machine_password)
39 {
40         uint32_t sum[2];
41         uint8_t sum2[8];
42
43         sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
44         sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
45
46         SIVAL(sum2,0,sum[0]);
47         SIVAL(sum2,4,sum[1]);
48
49         ZERO_STRUCT(creds->session_key);
50
51         des_crypt128(creds->session_key, sum2, machine_password->hash);
52
53         des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
54         des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
55
56         creds->seed = creds->client;
57 }
58
59 /*
60   initialise the credentials state for ADS-style 128 bit session keys
61
62   this call is made after the netr_ServerReqChallenge call
63 */
64 static void creds_init_128bit(struct creds_CredentialState *creds,
65                               const struct netr_Credential *client_challenge,
66                               const struct netr_Credential *server_challenge,
67                               const struct samr_Password *machine_password)
68 {
69         unsigned char zero[4], tmp[16];
70         HMACMD5Context ctx;
71         struct MD5Context md5;
72
73         ZERO_STRUCT(creds->session_key);
74
75         memset(zero, 0, sizeof(zero));
76
77         hmac_md5_init_rfc2104(machine_password->hash, sizeof(machine_password->hash), &ctx);    
78         MD5Init(&md5);
79         MD5Update(&md5, zero, sizeof(zero));
80         MD5Update(&md5, client_challenge->data, 8);
81         MD5Update(&md5, server_challenge->data, 8);
82         MD5Final(tmp, &md5);
83         hmac_md5_update(tmp, sizeof(tmp), &ctx);
84         hmac_md5_final(creds->session_key, &ctx);
85
86         creds->client = *client_challenge;
87         creds->server = *server_challenge;
88
89         des_crypt112(creds->client.data, client_challenge->data, creds->session_key, 1);
90         des_crypt112(creds->server.data, server_challenge->data, creds->session_key, 1);
91
92         creds->seed = creds->client;
93 }
94
95
96 /*
97   step the credentials to the next element in the chain, updating the
98   current client and server credentials and the seed
99 */
100 static void creds_step(struct creds_CredentialState *creds)
101 {
102         struct netr_Credential time_cred;
103
104         DEBUG(5,("\tseed        %08x:%08x\n", 
105                  IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
106
107         SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
108         SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
109
110         DEBUG(5,("\tseed+time   %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
111
112         des_crypt112(creds->client.data, time_cred.data, creds->session_key, 1);
113
114         DEBUG(5,("\tCLIENT      %08x:%08x\n", 
115                  IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
116
117         SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
118         SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
119
120         DEBUG(5,("\tseed+time+1 %08x:%08x\n", 
121                  IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
122
123         des_crypt112(creds->server.data, time_cred.data, creds->session_key, 1);
124
125         DEBUG(5,("\tSERVER      %08x:%08x\n", 
126                  IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
127
128         creds->seed = time_cred;
129 }
130
131
132 /*
133   DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
134 */
135 void creds_des_encrypt_LMKey(struct creds_CredentialState *creds, struct netr_LMSessionKey *key)
136 {
137         struct netr_LMSessionKey tmp;
138         des_crypt56(tmp.key, key->key, creds->session_key, 1);
139         *key = tmp;
140 }
141
142 /*
143   DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
144 */
145 void creds_des_decrypt_LMKey(struct creds_CredentialState *creds, struct netr_LMSessionKey *key)
146 {
147         struct netr_LMSessionKey tmp;
148         des_crypt56(tmp.key, key->key, creds->session_key, 0);
149         *key = tmp;
150 }
151
152 /*
153   DES encrypt a 16 byte password buffer using the session key
154 */
155 void creds_des_encrypt(struct creds_CredentialState *creds, struct samr_Password *pass)
156 {
157         struct samr_Password tmp;
158         des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 1);
159         *pass = tmp;
160 }
161
162 /*
163   DES decrypt a 16 byte password buffer using the session key
164 */
165 void creds_des_decrypt(struct creds_CredentialState *creds, struct samr_Password *pass)
166 {
167         struct samr_Password tmp;
168         des_crypt112_16(tmp.hash, pass->hash, creds->session_key, 0);
169         *pass = tmp;
170 }
171
172 /*
173   ARCFOUR encrypt/decrypt a password buffer using the session key
174 */
175 void creds_arcfour_crypt(struct creds_CredentialState *creds, uint8_t *data, size_t len)
176 {
177         DATA_BLOB session_key = data_blob(creds->session_key, 16);
178
179         arcfour_crypt_blob(data, len, &session_key);
180
181         data_blob_free(&session_key);
182 }
183
184 /*****************************************************************
185 The above functions are common to the client and server interface
186 next comes the client specific functions
187 ******************************************************************/
188
189 /*
190   initialise the credentials chain and return the first client
191   credentials
192 */
193 void creds_client_init(struct creds_CredentialState *creds,
194                        const struct netr_Credential *client_challenge,
195                        const struct netr_Credential *server_challenge,
196                        const struct samr_Password *machine_password,
197                        struct netr_Credential *initial_credential,
198                        uint32_t negotiate_flags)
199 {
200         creds->sequence = time(NULL);
201         creds->negotiate_flags = negotiate_flags;
202
203         dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
204         dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
205         dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
206
207         if (negotiate_flags & NETLOGON_NEG_128BIT) {
208                 creds_init_128bit(creds, client_challenge, server_challenge, machine_password);
209         } else {
210                 creds_init_64bit(creds, client_challenge, server_challenge, machine_password);
211         }
212
213         dump_data_pw("Session key", creds->session_key, 16);
214         dump_data_pw("Credential ", creds->client.data, 8);
215
216         *initial_credential = creds->client;
217 }
218
219 /*
220   step the credentials to the next element in the chain, updating the
221   current client and server credentials and the seed
222
223   produce the next authenticator in the sequence ready to send to 
224   the server
225 */
226 void creds_client_authenticator(struct creds_CredentialState *creds,
227                                 struct netr_Authenticator *next)
228 {       
229         creds->sequence += 2;
230         creds_step(creds);
231
232         next->cred = creds->client;
233         next->timestamp = creds->sequence;
234 }
235
236 /*
237   check that a credentials reply from a server is correct
238 */
239 BOOL creds_client_check(struct creds_CredentialState *creds,
240                         const struct netr_Credential *received_credentials)
241 {
242         if (!received_credentials || 
243             memcmp(received_credentials->data, creds->server.data, 8) != 0) {
244                 DEBUG(2,("credentials check failed\n"));
245                 return False;
246         }
247         return True;
248 }
249
250
251 /*****************************************************************
252 The above functions are common to the client and server interface
253 next comes the server specific functions
254 ******************************************************************/
255
256 /*
257   initialise the credentials chain and return the first server
258   credentials
259 */
260 void creds_server_init(struct creds_CredentialState *creds,
261                        const struct netr_Credential *client_challenge,
262                        const struct netr_Credential *server_challenge,
263                        const struct samr_Password *machine_password,
264                        struct netr_Credential *initial_credential,
265                        uint32_t negotiate_flags)
266 {
267         if (negotiate_flags & NETLOGON_NEG_128BIT) {
268                 creds_init_128bit(creds, client_challenge, server_challenge, 
269                                   machine_password);
270         } else {
271                 creds_init_64bit(creds, client_challenge, server_challenge, 
272                                  machine_password);
273         }
274
275         *initial_credential = creds->server;
276         creds->negotiate_flags = negotiate_flags;
277 }
278
279 /*
280   check that a credentials reply from a server is correct
281 */
282 BOOL creds_server_check(const struct creds_CredentialState *creds,
283                         const struct netr_Credential *received_credentials)
284 {
285         if (memcmp(received_credentials->data, creds->client.data, 8) != 0) {
286                 DEBUG(2,("credentials check failed\n"));
287                 dump_data_pw("client creds", creds->client.data, 8);
288                 dump_data_pw("calc   creds", received_credentials->data, 8);
289                 return False;
290         }
291         return True;
292 }
293
294 NTSTATUS creds_server_step_check(struct creds_CredentialState *creds,
295                                  struct netr_Authenticator *received_authenticator,
296                                  struct netr_Authenticator *return_authenticator) 
297 {
298         if (!received_authenticator || !return_authenticator) {
299                 return NT_STATUS_INVALID_PARAMETER;
300         }
301
302         if (!creds) {
303                 return NT_STATUS_ACCESS_DENIED;
304         }
305
306         /* TODO: this may allow the a replay attack on a non-signed
307            connection. Should we check that this is increasing? */
308         creds->sequence = received_authenticator->timestamp;
309         creds_step(creds);
310         if (creds_server_check(creds, &received_authenticator->cred)) {
311                 return_authenticator->cred = creds->server;
312                 return_authenticator->timestamp = creds->sequence;
313                 return NT_STATUS_OK;
314         } else {
315                 ZERO_STRUCTP(return_authenticator);
316                 return NT_STATUS_ACCESS_DENIED;
317         }
318 }