libsmb/credentials.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    code to manipulate domain credentials
00004    Copyright (C) Andrew Tridgell 1997-1998
00005    Largely rewritten by Jeremy Allison 2005.
00006    
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011    
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016    
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software
00019    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00020 */
00021 
00022 #include "includes.h"
00023 
00024 /****************************************************************************
00025  Represent a credential as a string.
00026 ****************************************************************************/
00027 
00028 char *credstr(const unsigned char *cred)
00029 {
00030         static fstring buf;
00031         slprintf(buf, sizeof(buf) - 1, "%02X%02X%02X%02X%02X%02X%02X%02X",
00032                 cred[0], cred[1], cred[2], cred[3], 
00033                 cred[4], cred[5], cred[6], cred[7]);
00034         return buf;
00035 }
00036 
00037 /****************************************************************************
00038  Setup the session key and the client and server creds in dc.
00039  ADS-style 128 bit session keys.
00040  Used by both client and server creds setup.
00041 ****************************************************************************/
00042 
00043 static void creds_init_128(struct dcinfo *dc,
00044                                 const DOM_CHAL *clnt_chal_in,
00045                                 const DOM_CHAL *srv_chal_in,
00046                                 const unsigned char mach_pw[16])
00047 {
00048         unsigned char zero[4], tmp[16];
00049         HMACMD5Context ctx;
00050         struct MD5Context md5;
00051 
00052         /* Just in case this isn't already there */
00053         memcpy(dc->mach_pw, mach_pw, 16);
00054 
00055         ZERO_STRUCT(dc->sess_key);
00056 
00057         memset(zero, 0, sizeof(zero));
00058 
00059         hmac_md5_init_rfc2104(mach_pw, 16, &ctx);
00060         MD5Init(&md5);
00061         MD5Update(&md5, zero, sizeof(zero));
00062         MD5Update(&md5, clnt_chal_in->data, 8);
00063         MD5Update(&md5, srv_chal_in->data, 8);
00064         MD5Final(tmp, &md5);
00065         hmac_md5_update(tmp, sizeof(tmp), &ctx);
00066         hmac_md5_final(dc->sess_key, &ctx);
00067 
00068         /* debug output */
00069         DEBUG(5,("creds_init_128\n"));
00070         DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
00071         DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data)));
00072         dump_data_pw("\tsession_key ", (const unsigned char *)dc->sess_key, 16);
00073 
00074         /* Generate the next client and server creds. */
00075         
00076         des_crypt112(dc->clnt_chal.data,                /* output */
00077                         clnt_chal_in->data,             /* input */
00078                         dc->sess_key,                   /* input */
00079                         1);
00080 
00081         des_crypt112(dc->srv_chal.data,                 /* output */
00082                         srv_chal_in->data,              /* input */
00083                         dc->sess_key,                   /* input */
00084                         1);
00085 
00086         /* Seed is the client chal. */
00087         memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
00088 }
00089 
00090 /****************************************************************************
00091  Setup the session key and the client and server creds in dc.
00092  Used by both client and server creds setup.
00093 ****************************************************************************/
00094 
00095 static void creds_init_64(struct dcinfo *dc,
00096                         const DOM_CHAL *clnt_chal_in,
00097                         const DOM_CHAL *srv_chal_in,
00098                         const unsigned char mach_pw[16])
00099 {
00100         uint32 sum[2];
00101         unsigned char sum2[8];
00102 
00103         /* Just in case this isn't already there */
00104         if (dc->mach_pw != mach_pw) {
00105                 memcpy(dc->mach_pw, mach_pw, 16);
00106         }
00107 
00108         sum[0] = IVAL(clnt_chal_in->data, 0) + IVAL(srv_chal_in->data, 0);
00109         sum[1] = IVAL(clnt_chal_in->data, 4) + IVAL(srv_chal_in->data, 4);
00110 
00111         SIVAL(sum2,0,sum[0]);
00112         SIVAL(sum2,4,sum[1]);
00113 
00114         ZERO_STRUCT(dc->sess_key);
00115 
00116         des_crypt128(dc->sess_key, sum2, dc->mach_pw);
00117 
00118         /* debug output */
00119         DEBUG(5,("creds_init_64\n"));
00120         DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
00121         DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data)));
00122         DEBUG(5,("\tclnt+srv : %s\n", credstr(sum2)));
00123         DEBUG(5,("\tsess_key_out : %s\n", credstr(dc->sess_key)));
00124 
00125         /* Generate the next client and server creds. */
00126         
00127         des_crypt112(dc->clnt_chal.data,                /* output */
00128                         clnt_chal_in->data,             /* input */
00129                         dc->sess_key,                   /* input */
00130                         1);
00131 
00132         des_crypt112(dc->srv_chal.data,                 /* output */
00133                         srv_chal_in->data,              /* input */
00134                         dc->sess_key,                   /* input */
00135                         1);
00136 
00137         /* Seed is the client chal. */
00138         memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
00139 }
00140 
00141 /****************************************************************************
00142  Utility function to step credential chain one forward.
00143  Deliberately doesn't update the seed. See reseed comment below.
00144 ****************************************************************************/
00145 
00146 static void creds_step(struct dcinfo *dc)
00147 {
00148         DOM_CHAL time_chal;
00149 
00150         DEBUG(5,("\tsequence = 0x%x\n", (unsigned int)dc->sequence ));
00151 
00152         DEBUG(5,("\tseed:        %s\n", credstr(dc->seed_chal.data) ));
00153 
00154         SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence);
00155         SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
00156                                                                                                    
00157         DEBUG(5,("\tseed+seq   %s\n", credstr(time_chal.data) ));
00158 
00159         des_crypt112(dc->clnt_chal.data, time_chal.data, dc->sess_key, 1);
00160 
00161         DEBUG(5,("\tCLIENT      %s\n", credstr(dc->clnt_chal.data) ));
00162 
00163         SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
00164         SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
00165 
00166         DEBUG(5,("\tseed+seq+1   %s\n", credstr(time_chal.data) ));
00167 
00168         des_crypt112(dc->srv_chal.data, time_chal.data, dc->sess_key, 1);
00169 
00170         DEBUG(5,("\tSERVER      %s\n", credstr(dc->srv_chal.data) ));
00171 }
00172 
00173 /****************************************************************************
00174  Create a server credential struct.
00175 ****************************************************************************/
00176 
00177 void creds_server_init(uint32 neg_flags,
00178                         struct dcinfo *dc,
00179                         DOM_CHAL *clnt_chal,
00180                         DOM_CHAL *srv_chal,
00181                         const unsigned char mach_pw[16],
00182                         DOM_CHAL *init_chal_out)
00183 {
00184         DEBUG(10,("creds_server_init: neg_flags : %x\n", (unsigned int)neg_flags));
00185         DEBUG(10,("creds_server_init: client chal : %s\n", credstr(clnt_chal->data) ));
00186         DEBUG(10,("creds_server_init: server chal : %s\n", credstr(srv_chal->data) ));
00187         dump_data_pw("creds_server_init: machine pass", mach_pw, 16);
00188 
00189         /* Generate the session key and the next client and server creds. */
00190         if (neg_flags & NETLOGON_NEG_128BIT) {
00191                 creds_init_128(dc,
00192                         clnt_chal,
00193                         srv_chal,
00194                         mach_pw);
00195         } else {
00196                 creds_init_64(dc,
00197                         clnt_chal,
00198                         srv_chal,
00199                         mach_pw);
00200         }
00201 
00202         dump_data_pw("creds_server_init: session key", dc->sess_key, 16);
00203 
00204         DEBUG(10,("creds_server_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
00205         DEBUG(10,("creds_server_init: server : %s\n", credstr(dc->srv_chal.data) ));
00206         DEBUG(10,("creds_server_init: seed : %s\n", credstr(dc->seed_chal.data) ));
00207 
00208         memcpy(init_chal_out->data, dc->srv_chal.data, 8);
00209 }
00210 
00211 /****************************************************************************
00212  Check a credential sent by the client.
00213 ****************************************************************************/
00214 
00215 BOOL creds_server_check(const struct dcinfo *dc, const DOM_CHAL *rcv_cli_chal_in)
00216 {
00217         if (memcmp(dc->clnt_chal.data, rcv_cli_chal_in->data, 8)) {
00218                 DEBUG(5,("creds_server_check: challenge : %s\n", credstr(rcv_cli_chal_in->data)));
00219                 DEBUG(5,("calculated: %s\n", credstr(dc->clnt_chal.data)));
00220                 DEBUG(2,("creds_server_check: credentials check failed.\n"));
00221                 return False;
00222         }
00223         DEBUG(10,("creds_server_check: credentials check OK.\n"));
00224         return True;
00225 }
00226 
00227 /****************************************************************************
00228  Replace current seed chal. Internal function - due to split server step below.
00229 ****************************************************************************/
00230 
00231 static void creds_reseed(struct dcinfo *dc)
00232 {
00233         DOM_CHAL time_chal;
00234 
00235         SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
00236         SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
00237 
00238         dc->seed_chal = time_chal;
00239 
00240         DEBUG(5,("cred_reseed: seed %s\n", credstr(dc->seed_chal.data) ));
00241 }
00242 
00243 /****************************************************************************
00244  Step the server credential chain one forward. 
00245 ****************************************************************************/
00246 
00247 BOOL creds_server_step(struct dcinfo *dc, const DOM_CRED *received_cred, DOM_CRED *cred_out)
00248 {
00249         BOOL ret;
00250         struct dcinfo tmp_dc = *dc;
00251 
00252         /* Do all operations on a temporary copy of the dc,
00253            which we throw away if the checks fail. */
00254 
00255         tmp_dc.sequence = received_cred->timestamp.time;
00256 
00257         creds_step(&tmp_dc);
00258 
00259         /* Create the outgoing credentials */
00260         cred_out->timestamp.time = tmp_dc.sequence + 1;
00261         cred_out->challenge = tmp_dc.srv_chal;
00262 
00263         creds_reseed(&tmp_dc);
00264 
00265         ret = creds_server_check(&tmp_dc, &received_cred->challenge);
00266         if (!ret) {
00267                 return False;
00268         }
00269 
00270         /* creds step succeeded - replace the current creds. */
00271         *dc = tmp_dc;
00272         return True;
00273 }
00274 
00275 /****************************************************************************
00276  Create a client credential struct.
00277 ****************************************************************************/
00278 
00279 void creds_client_init(uint32 neg_flags,
00280                         struct dcinfo *dc,
00281                         DOM_CHAL *clnt_chal,
00282                         DOM_CHAL *srv_chal,
00283                         const unsigned char mach_pw[16],
00284                         DOM_CHAL *init_chal_out)
00285 {
00286         dc->sequence = time(NULL);
00287 
00288         DEBUG(10,("creds_client_init: neg_flags : %x\n", (unsigned int)neg_flags));
00289         DEBUG(10,("creds_client_init: client chal : %s\n", credstr(clnt_chal->data) ));
00290         DEBUG(10,("creds_client_init: server chal : %s\n", credstr(srv_chal->data) ));
00291         dump_data_pw("creds_client_init: machine pass", (const unsigned char *)mach_pw, 16);
00292 
00293         /* Generate the session key and the next client and server creds. */
00294         if (neg_flags & NETLOGON_NEG_128BIT) {
00295                 creds_init_128(dc,
00296                                 clnt_chal,
00297                                 srv_chal,
00298                                 mach_pw);
00299         } else {
00300                 creds_init_64(dc,
00301                         clnt_chal,
00302                         srv_chal,
00303                         mach_pw);
00304         }
00305 
00306         dump_data_pw("creds_client_init: session key", dc->sess_key, 16);
00307 
00308         DEBUG(10,("creds_client_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
00309         DEBUG(10,("creds_client_init: server : %s\n", credstr(dc->srv_chal.data) ));
00310         DEBUG(10,("creds_client_init: seed : %s\n", credstr(dc->seed_chal.data) ));
00311 
00312         memcpy(init_chal_out->data, dc->clnt_chal.data, 8);
00313 }
00314 
00315 /****************************************************************************
00316  Check a credential returned by the server.
00317 ****************************************************************************/
00318 
00319 BOOL creds_client_check(const struct dcinfo *dc, const DOM_CHAL *rcv_srv_chal_in)
00320 {
00321         if (memcmp(dc->srv_chal.data, rcv_srv_chal_in->data, 8)) {
00322                 DEBUG(5,("creds_client_check: challenge : %s\n", credstr(rcv_srv_chal_in->data)));
00323                 DEBUG(5,("calculated: %s\n", credstr(dc->srv_chal.data)));
00324                 DEBUG(0,("creds_client_check: credentials check failed.\n"));
00325                 return False;
00326         }
00327         DEBUG(10,("creds_client_check: credentials check OK.\n"));
00328         return True;
00329 }
00330 
00331 /****************************************************************************
00332   Step the client credentials to the next element in the chain, updating the
00333   current client and server credentials and the seed
00334   produce the next authenticator in the sequence ready to send to
00335   the server
00336 ****************************************************************************/
00337 
00338 void creds_client_step(struct dcinfo *dc, DOM_CRED *next_cred_out)
00339 {
00340         dc->sequence += 2;
00341         creds_step(dc);
00342         creds_reseed(dc);
00343 
00344         next_cred_out->challenge = dc->clnt_chal;
00345         next_cred_out->timestamp.time = dc->sequence;
00346 }

Sambaに対してSat Aug 29 21:23:05 2009に生成されました。  doxygen 1.4.7