added netr_ServerAuthenticate() and test code
[sfrench/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    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 /****************************************************************************
26 represent a credential as a string
27 ****************************************************************************/
28 char *credstr(const uchar *cred)
29 {
30         static fstring buf;
31         slprintf(buf, sizeof(buf) - 1, "%02X%02X%02X%02X%02X%02X%02X%02X",
32                 cred[0], cred[1], cred[2], cred[3], 
33                 cred[4], cred[5], cred[6], cred[7]);
34         return buf;
35 }
36
37
38 /****************************************************************************
39   setup the session key. 
40 Input: 8 byte challenge block
41        8 byte server challenge block
42       16 byte md4 encrypted password
43 Output:
44       8 byte session key
45 ****************************************************************************/
46 void cred_session_key(const struct netr_Credential *client_challenge, 
47                       const struct netr_Credential *server_challenge, 
48                       const uint8  md4_pass[16], 
49                       uint8 session_key[8])
50 {
51         uint32 sum[2];
52         uint8 sum2[8];
53
54         sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
55         sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
56
57         SIVAL(sum2,0,sum[0]);
58         SIVAL(sum2,4,sum[1]);
59
60         cred_hash1(session_key, sum2, md4_pass);
61 }
62
63
64 /****************************************************************************
65 create a credential
66
67 Input:
68       8 byte sesssion key
69       8 byte stored credential
70       4 byte timestamp
71
72 Output:
73       8 byte credential
74 ****************************************************************************/
75 void cred_create(uchar session_key[8], struct netr_Credential *stor_cred, time_t timestamp, 
76                  struct netr_Credential *cred)
77 {
78         struct netr_Credential time_cred;
79
80         SIVAL(time_cred.data, 0, IVAL(stor_cred->data, 0) + timestamp);
81         SIVAL(time_cred.data, 4, IVAL(stor_cred->data, 4));
82
83         cred_hash2(cred->data, time_cred.data, session_key);
84
85         /* debug output*/
86         DEBUG(4,("cred_create\n"));
87
88         DEBUG(5,("      sess_key : %s\n", credstr(session_key)));
89         DEBUG(5,("      stor_cred: %s\n", credstr(stor_cred->data)));
90         DEBUG(5,("      timestamp: %x\n", (unsigned)timestamp));
91         DEBUG(5,("      timecred : %s\n", credstr(time_cred.data)));
92         DEBUG(5,("      calc_cred: %s\n", credstr(cred->data)));
93 }
94
95
96 /****************************************************************************
97   check a supplied credential
98
99 Input:
100       8 byte received credential
101       8 byte sesssion key
102       8 byte stored credential
103       4 byte timestamp
104
105 Output:
106       returns 1 if computed credential matches received credential
107       returns 0 otherwise
108 ****************************************************************************/
109 int cred_assert(struct netr_Credential *cred, uchar session_key[8], 
110                 struct netr_Credential *stored_cred,
111                 time_t timestamp)
112 {
113         struct netr_Credential cred2;
114
115         cred_create(session_key, stored_cred, timestamp, &cred2);
116
117         /* debug output*/
118         DEBUG(4,("cred_assert\n"));
119
120         DEBUG(5,("      challenge : %s\n", credstr(cred->data)));
121         DEBUG(5,("      calculated: %s\n", credstr(cred2.data)));
122
123         if (memcmp(cred->data, cred2.data, 8) == 0)
124         {
125                 DEBUG(5, ("credentials check ok\n"));
126                 return True;
127         }
128         else
129         {
130                 DEBUG(5, ("credentials check wrong\n"));
131                 return False;
132         }
133 }
134
135
136 /****************************************************************************
137   checks credentials; generates next step in the credential chain
138 ****************************************************************************/
139 BOOL clnt_deal_with_creds(uchar sess_key[8],
140                           struct netr_Authenticator *sto_clnt_cred, 
141                           struct netr_Authenticator *rcv_srv_cred)
142 {
143         time_t new_clnt_time;
144         uint32 new_cred;
145
146         DEBUG(5,("clnt_deal_with_creds: %d\n", __LINE__));
147
148         /* increment client time by one second !?! */
149         new_clnt_time = sto_clnt_cred->timestamp + 1;
150
151         /* check that the received server credentials are valid */
152         if (!cred_assert(&rcv_srv_cred->cred, sess_key,
153                          &sto_clnt_cred->cred, new_clnt_time)) {
154                 return False;
155         }
156
157         /* first 4 bytes of the new seed is old client 4 bytes + clnt time + 1 */
158         new_cred = IVAL(sto_clnt_cred->cred.data, 0);
159         new_cred += new_clnt_time;
160
161         /* store new seed in client credentials */
162         SIVAL(sto_clnt_cred->cred.data, 0, new_cred);
163
164         DEBUG(5,("      new clnt cred: %s\n", credstr(sto_clnt_cred->cred.data)));
165         return True;
166 }
167
168
169 /****************************************************************************
170   checks credentials; generates next step in the credential chain
171 ****************************************************************************/
172 BOOL deal_with_creds(uchar sess_key[8],
173                      struct netr_Authenticator *sto_clnt_cred, 
174                      struct netr_Authenticator *rcv_clnt_cred, 
175                      struct netr_Authenticator *rtn_srv_cred)
176 {
177         time_t new_clnt_time;
178         uint32 new_cred;
179
180         DEBUG(5,("deal_with_creds: %d\n", __LINE__));
181
182         /* check that the received client credentials are valid */
183         if (!cred_assert(&rcv_clnt_cred->cred, sess_key,
184                     &sto_clnt_cred->cred, rcv_clnt_cred->timestamp))
185         {
186                 return False;
187         }
188
189         /* increment client time by one second */
190         new_clnt_time = rcv_clnt_cred->timestamp + 1;
191
192         /* first 4 bytes of the new seed is old client 4 bytes + clnt time + 1 */
193         new_cred = IVAL(sto_clnt_cred->cred.data, 0);
194         new_cred += new_clnt_time;
195
196         DEBUG(5,("deal_with_creds: new_cred[0]=%x\n", new_cred));
197
198         /* doesn't matter that server time is 0 */
199         rtn_srv_cred->timestamp = 0;
200
201         DEBUG(5,("deal_with_creds: new_clnt_time=%x\n", (unsigned)new_clnt_time));
202
203         /* create return credentials for inclusion in the reply */
204         cred_create(sess_key, &sto_clnt_cred->cred, new_clnt_time,
205                     &rtn_srv_cred->cred);
206         
207         DEBUG(5,("deal_with_creds: clnt_cred=%s\n", credstr(sto_clnt_cred->cred.data)));
208
209         /* store new seed in client credentials */
210         SIVAL(sto_clnt_cred->cred.data, 0, new_cred);
211
212         return True;
213 }