root/source3/libsmb/credentials.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. credstr
  2. creds_init_128
  3. creds_init_64
  4. creds_step
  5. creds_server_init
  6. netlogon_creds_server_check
  7. creds_reseed
  8. netlogon_creds_server_step
  9. creds_client_init
  10. netlogon_creds_client_check
  11. netlogon_creds_client_step

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    code to manipulate domain credentials
   4    Copyright (C) Andrew Tridgell 1997-1998
   5    Largely rewritten by Jeremy Allison 2005.
   6    
   7    This program is free software; you can redistribute it and/or modify
   8    it under the terms of the GNU General Public License as published by
   9    the Free Software Foundation; either version 3 of the License, or
  10    (at your option) any later version.
  11    
  12    This program is distributed in the hope that it will be useful,
  13    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15    GNU General Public License for more details.
  16    
  17    You should have received a copy of the GNU General Public License
  18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19 */
  20 
  21 #include "includes.h"
  22 
  23 /****************************************************************************
  24  Represent a credential as a string.
  25 ****************************************************************************/
  26 
  27 char *credstr(const unsigned char *cred)
     /* [<][>][^][v][top][bottom][index][help] */
  28 {
  29         char *result;
  30         result = talloc_asprintf(talloc_tos(),
  31                                  "%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         SMB_ASSERT(result != NULL);
  35         return result;
  36 }
  37 
  38 /****************************************************************************
  39  Setup the session key and the client and server creds in dc.
  40  ADS-style 128 bit session keys.
  41  Used by both client and server creds setup.
  42 ****************************************************************************/
  43 
  44 static void creds_init_128(struct dcinfo *dc,
     /* [<][>][^][v][top][bottom][index][help] */
  45                            const struct netr_Credential *clnt_chal_in,
  46                            const struct netr_Credential *srv_chal_in,
  47                            const unsigned char mach_pw[16])
  48 {
  49         unsigned char zero[4], tmp[16];
  50         HMACMD5Context ctx;
  51         struct MD5Context md5;
  52 
  53         /* Just in case this isn't already there */
  54         memcpy(dc->mach_pw, mach_pw, 16);
  55 
  56         ZERO_STRUCT(dc->sess_key);
  57 
  58         memset(zero, 0, sizeof(zero));
  59 
  60         hmac_md5_init_rfc2104(mach_pw, 16, &ctx);
  61         MD5Init(&md5);
  62         MD5Update(&md5, zero, sizeof(zero));
  63         MD5Update(&md5, clnt_chal_in->data, 8);
  64         MD5Update(&md5, srv_chal_in->data, 8);
  65         MD5Final(tmp, &md5);
  66         hmac_md5_update(tmp, sizeof(tmp), &ctx);
  67         hmac_md5_final(dc->sess_key, &ctx);
  68 
  69         /* debug output */
  70         DEBUG(5,("creds_init_128\n"));
  71         DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
  72         DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data)));
  73         dump_data_pw("\tsession_key ", (const unsigned char *)dc->sess_key, 16);
  74 
  75         /* Generate the next client and server creds. */
  76         
  77         des_crypt112(dc->clnt_chal.data,                /* output */
  78                         clnt_chal_in->data,             /* input */
  79                         dc->sess_key,                   /* input */
  80                         1);
  81 
  82         des_crypt112(dc->srv_chal.data,                 /* output */
  83                         srv_chal_in->data,              /* input */
  84                         dc->sess_key,                   /* input */
  85                         1);
  86 
  87         /* Seed is the client chal. */
  88         memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
  89 }
  90 
  91 /****************************************************************************
  92  Setup the session key and the client and server creds in dc.
  93  Used by both client and server creds setup.
  94 ****************************************************************************/
  95 
  96 static void creds_init_64(struct dcinfo *dc,
     /* [<][>][^][v][top][bottom][index][help] */
  97                           const struct netr_Credential *clnt_chal_in,
  98                           const struct netr_Credential *srv_chal_in,
  99                           const unsigned char mach_pw[16])
 100 {
 101         uint32 sum[2];
 102         unsigned char sum2[8];
 103 
 104         /* Just in case this isn't already there */
 105         if (dc->mach_pw != mach_pw) {
 106                 memcpy(dc->mach_pw, mach_pw, 16);
 107         }
 108 
 109         sum[0] = IVAL(clnt_chal_in->data, 0) + IVAL(srv_chal_in->data, 0);
 110         sum[1] = IVAL(clnt_chal_in->data, 4) + IVAL(srv_chal_in->data, 4);
 111 
 112         SIVAL(sum2,0,sum[0]);
 113         SIVAL(sum2,4,sum[1]);
 114 
 115         ZERO_STRUCT(dc->sess_key);
 116 
 117         des_crypt128(dc->sess_key, sum2, dc->mach_pw);
 118 
 119         /* debug output */
 120         DEBUG(5,("creds_init_64\n"));
 121         DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
 122         DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data)));
 123         DEBUG(5,("\tclnt+srv : %s\n", credstr(sum2)));
 124         DEBUG(5,("\tsess_key_out : %s\n", credstr(dc->sess_key)));
 125 
 126         /* Generate the next client and server creds. */
 127         
 128         des_crypt112(dc->clnt_chal.data,                /* output */
 129                         clnt_chal_in->data,             /* input */
 130                         dc->sess_key,                   /* input */
 131                         1);
 132 
 133         des_crypt112(dc->srv_chal.data,                 /* output */
 134                         srv_chal_in->data,              /* input */
 135                         dc->sess_key,                   /* input */
 136                         1);
 137 
 138         /* Seed is the client chal. */
 139         memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
 140 }
 141 
 142 /****************************************************************************
 143  Utility function to step credential chain one forward.
 144  Deliberately doesn't update the seed. See reseed comment below.
 145 ****************************************************************************/
 146 
 147 static void creds_step(struct dcinfo *dc)
     /* [<][>][^][v][top][bottom][index][help] */
 148 {
 149         struct netr_Credential time_chal;
 150 
 151         DEBUG(5,("\tsequence = 0x%x\n", (unsigned int)dc->sequence ));
 152 
 153         DEBUG(5,("\tseed:        %s\n", credstr(dc->seed_chal.data) ));
 154 
 155         SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence);
 156         SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
 157                                                                                                    
 158         DEBUG(5,("\tseed+seq   %s\n", credstr(time_chal.data) ));
 159 
 160         des_crypt112(dc->clnt_chal.data, time_chal.data, dc->sess_key, 1);
 161 
 162         DEBUG(5,("\tCLIENT      %s\n", credstr(dc->clnt_chal.data) ));
 163 
 164         SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
 165         SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
 166 
 167         DEBUG(5,("\tseed+seq+1   %s\n", credstr(time_chal.data) ));
 168 
 169         des_crypt112(dc->srv_chal.data, time_chal.data, dc->sess_key, 1);
 170 
 171         DEBUG(5,("\tSERVER      %s\n", credstr(dc->srv_chal.data) ));
 172 }
 173 
 174 /****************************************************************************
 175  Create a server credential struct.
 176 ****************************************************************************/
 177 
 178 void creds_server_init(uint32 neg_flags,
     /* [<][>][^][v][top][bottom][index][help] */
 179                         struct dcinfo *dc,
 180                         struct netr_Credential *clnt_chal,
 181                         struct netr_Credential *srv_chal,
 182                         const unsigned char mach_pw[16],
 183                         struct netr_Credential *init_chal_out)
 184 {
 185         DEBUG(10,("creds_server_init: neg_flags : %x\n", (unsigned int)neg_flags));
 186         DEBUG(10,("creds_server_init: client chal : %s\n", credstr(clnt_chal->data) ));
 187         DEBUG(10,("creds_server_init: server chal : %s\n", credstr(srv_chal->data) ));
 188         dump_data_pw("creds_server_init: machine pass", mach_pw, 16);
 189 
 190         /* Generate the session key and the next client and server creds. */
 191         if (neg_flags & NETLOGON_NEG_128BIT) {
 192                 creds_init_128(dc,
 193                         clnt_chal,
 194                         srv_chal,
 195                         mach_pw);
 196         } else {
 197                 creds_init_64(dc,
 198                         clnt_chal,
 199                         srv_chal,
 200                         mach_pw);
 201         }
 202 
 203         dump_data_pw("creds_server_init: session key", dc->sess_key, 16);
 204 
 205         DEBUG(10,("creds_server_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
 206         DEBUG(10,("creds_server_init: server : %s\n", credstr(dc->srv_chal.data) ));
 207         DEBUG(10,("creds_server_init: seed : %s\n", credstr(dc->seed_chal.data) ));
 208 
 209         memcpy(init_chal_out->data, dc->srv_chal.data, 8);
 210 }
 211 
 212 /****************************************************************************
 213  Check a credential sent by the client.
 214 ****************************************************************************/
 215 
 216 bool netlogon_creds_server_check(const struct dcinfo *dc,
     /* [<][>][^][v][top][bottom][index][help] */
 217                                  const struct netr_Credential *rcv_cli_chal_in)
 218 {
 219         if (memcmp(dc->clnt_chal.data, rcv_cli_chal_in->data, 8)) {
 220                 DEBUG(5,("netlogon_creds_server_check: challenge : %s\n",
 221                         credstr(rcv_cli_chal_in->data)));
 222                 DEBUG(5,("calculated: %s\n", credstr(dc->clnt_chal.data)));
 223                 DEBUG(2,("netlogon_creds_server_check: credentials check failed.\n"));
 224                 return false;
 225         }
 226 
 227         DEBUG(10,("netlogon_creds_server_check: credentials check OK.\n"));
 228 
 229         return true;
 230 }
 231 /****************************************************************************
 232  Replace current seed chal. Internal function - due to split server step below.
 233 ****************************************************************************/
 234 
 235 static void creds_reseed(struct dcinfo *dc)
     /* [<][>][^][v][top][bottom][index][help] */
 236 {
 237         struct netr_Credential time_chal;
 238 
 239         SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
 240         SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
 241 
 242         dc->seed_chal = time_chal;
 243 
 244         DEBUG(5,("cred_reseed: seed %s\n", credstr(dc->seed_chal.data) ));
 245 }
 246 
 247 /****************************************************************************
 248  Step the server credential chain one forward. 
 249 ****************************************************************************/
 250 
 251 bool netlogon_creds_server_step(struct dcinfo *dc,
     /* [<][>][^][v][top][bottom][index][help] */
 252                                 const struct netr_Authenticator *received_cred,
 253                                 struct netr_Authenticator *cred_out)
 254 {
 255         bool ret;
 256         struct dcinfo tmp_dc = *dc;
 257 
 258         if (!received_cred || !cred_out) {
 259                 return false;
 260         }
 261 
 262         /* Do all operations on a temporary copy of the dc,
 263            which we throw away if the checks fail. */
 264 
 265         tmp_dc.sequence = received_cred->timestamp;
 266 
 267         creds_step(&tmp_dc);
 268 
 269         /* Create the outgoing credentials */
 270         cred_out->timestamp = tmp_dc.sequence + 1;
 271         memcpy(&cred_out->cred, &tmp_dc.srv_chal, sizeof(cred_out->cred));
 272 
 273         creds_reseed(&tmp_dc);
 274 
 275         ret = netlogon_creds_server_check(&tmp_dc, &received_cred->cred);
 276         if (!ret) {
 277                 return false;
 278         }
 279 
 280         /* creds step succeeded - replace the current creds. */
 281         *dc = tmp_dc;
 282         return true;
 283 }
 284 
 285 /****************************************************************************
 286  Create a client credential struct.
 287 ****************************************************************************/
 288 
 289 void creds_client_init(uint32 neg_flags,
     /* [<][>][^][v][top][bottom][index][help] */
 290                         struct dcinfo *dc,
 291                         struct netr_Credential *clnt_chal,
 292                         struct netr_Credential *srv_chal,
 293                         const unsigned char mach_pw[16],
 294                         struct netr_Credential *init_chal_out)
 295 {
 296         dc->sequence = time(NULL);
 297 
 298         DEBUG(10,("creds_client_init: neg_flags : %x\n", (unsigned int)neg_flags));
 299         DEBUG(10,("creds_client_init: client chal : %s\n", credstr(clnt_chal->data) ));
 300         DEBUG(10,("creds_client_init: server chal : %s\n", credstr(srv_chal->data) ));
 301         dump_data_pw("creds_client_init: machine pass", (const unsigned char *)mach_pw, 16);
 302 
 303         /* Generate the session key and the next client and server creds. */
 304         if (neg_flags & NETLOGON_NEG_128BIT) {
 305                 creds_init_128(dc,
 306                                 clnt_chal,
 307                                 srv_chal,
 308                                 mach_pw);
 309         } else {
 310                 creds_init_64(dc,
 311                         clnt_chal,
 312                         srv_chal,
 313                         mach_pw);
 314         }
 315 
 316         dump_data_pw("creds_client_init: session key", dc->sess_key, 16);
 317 
 318         DEBUG(10,("creds_client_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
 319         DEBUG(10,("creds_client_init: server : %s\n", credstr(dc->srv_chal.data) ));
 320         DEBUG(10,("creds_client_init: seed : %s\n", credstr(dc->seed_chal.data) ));
 321 
 322         memcpy(init_chal_out->data, dc->clnt_chal.data, 8);
 323 }
 324 
 325 /****************************************************************************
 326  Check a credential returned by the server.
 327 ****************************************************************************/
 328 
 329 bool netlogon_creds_client_check(const struct dcinfo *dc,
     /* [<][>][^][v][top][bottom][index][help] */
 330                                  const struct netr_Credential *rcv_srv_chal_in)
 331 {
 332         if (memcmp(dc->srv_chal.data, rcv_srv_chal_in->data,
 333                    sizeof(dc->srv_chal.data))) {
 334 
 335                 DEBUG(0,("netlogon_creds_client_check: credentials check failed.\n"));
 336                 DEBUGADD(5,("netlogon_creds_client_check: challenge : %s\n",
 337                         credstr(rcv_srv_chal_in->data)));
 338                 DEBUGADD(5,("calculated: %s\n", credstr(dc->srv_chal.data)));
 339                 return false;
 340         }
 341 
 342         DEBUG(10,("netlogon_creds_client_check: credentials check OK.\n"));
 343 
 344         return true;
 345 }
 346 
 347 
 348 /****************************************************************************
 349   Step the client credentials to the next element in the chain, updating the
 350   current client and server credentials and the seed
 351   produce the next authenticator in the sequence ready to send to
 352   the server
 353 ****************************************************************************/
 354 
 355 void netlogon_creds_client_step(struct dcinfo *dc,
     /* [<][>][^][v][top][bottom][index][help] */
 356                                 struct netr_Authenticator *next_cred_out)
 357 {
 358         dc->sequence += 2;
 359         creds_step(dc);
 360         creds_reseed(dc);
 361 
 362         memcpy(&next_cred_out->cred.data, &dc->clnt_chal.data,
 363                 sizeof(next_cred_out->cred.data));
 364         next_cred_out->timestamp = dc->sequence;
 365 }

/* [<][>][^][v][top][bottom][index][help] */