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