void creds_client_init(uint32 neg_flags, struct dcinfo *dc, DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal, const unsigned char mach_pw[16], DOM_CHAL *init_chal_out) { dc->sequence = time(NULL); DEBUG(10,("creds_client_init: neg_flags : %x\n", (unsigned int)neg_flags)); DEBUG(10,("creds_client_init: client chal : %s\n", credstr(clnt_chal->data) )); DEBUG(10,("creds_client_init: server chal : %s\n", credstr(srv_chal->data) )); dump_data_pw("creds_client_init: machine pass", (const unsigned char *)mach_pw, 16); /* Generate the session key and the next client and server creds. */ if (neg_flags & NETLOGON_NEG_128BIT) { creds_init_128(dc, clnt_chal, srv_chal, mach_pw); } else { creds_init_64(dc, clnt_chal, srv_chal, mach_pw); } dump_data_pw("creds_client_init: session key", dc->sess_key, 16); DEBUG(10,("creds_client_init: clnt : %s\n", credstr(dc->clnt_chal.data) )); DEBUG(10,("creds_client_init: server : %s\n", credstr(dc->srv_chal.data) )); DEBUG(10,("creds_client_init: seed : %s\n", credstr(dc->seed_chal.data) )); memcpy(init_chal_out->data, dc->clnt_chal.data, 8); }
static void creds_step(struct dcinfo *dc) { DOM_CHAL time_chal; DEBUG(5,("\tsequence = 0x%x\n", (unsigned int)dc->sequence )); DEBUG(5,("\tseed: %s\n", credstr(dc->seed_chal.data) )); SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence); SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4)); DEBUG(5,("\tseed+seq %s\n", credstr(time_chal.data) )); des_crypt112(dc->clnt_chal.data, time_chal.data, dc->sess_key, 1); DEBUG(5,("\tCLIENT %s\n", credstr(dc->clnt_chal.data) )); SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1); SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4)); DEBUG(5,("\tseed+seq+1 %s\n", credstr(time_chal.data) )); des_crypt112(dc->srv_chal.data, time_chal.data, dc->sess_key, 1); DEBUG(5,("\tSERVER %s\n", credstr(dc->srv_chal.data) )); }
BOOL creds_client_check(const struct dcinfo *dc, const DOM_CHAL *rcv_srv_chal_in) { if (memcmp(dc->srv_chal.data, rcv_srv_chal_in->data, 8)) { DEBUG(5,("creds_client_check: challenge : %s\n", credstr(rcv_srv_chal_in->data))); DEBUG(5,("calculated: %s\n", credstr(dc->srv_chal.data))); DEBUG(0,("creds_client_check: credentials check failed.\n")); return False; } DEBUG(10,("creds_client_check: credentials check OK.\n")); return True; }
bool netlogon_creds_server_check(const struct dcinfo *dc, const struct netr_Credential *rcv_cli_chal_in) { if (memcmp(dc->clnt_chal.data, rcv_cli_chal_in->data, 8)) { DEBUG(5,("netlogon_creds_server_check: challenge : %s\n", credstr(rcv_cli_chal_in->data))); DEBUG(5,("calculated: %s\n", credstr(dc->clnt_chal.data))); DEBUG(2,("netlogon_creds_server_check: credentials check failed.\n")); return false; } DEBUG(10,("netlogon_creds_server_check: credentials check OK.\n")); return true; }
/**************************************************************************** checks credentials; generates next step in the credential chain ****************************************************************************/ BOOL clnt_deal_with_creds(uchar sess_key[8], DOM_CRED *sto_clnt_cred, DOM_CRED *rcv_srv_cred) { UTIME new_clnt_time; uint32 new_cred; DEBUG(5,("clnt_deal_with_creds: %d\n", __LINE__)); /* increment client time by one second */ new_clnt_time.time = sto_clnt_cred->timestamp.time + 1; /* check that the received server credentials are valid */ if (!cred_assert(&rcv_srv_cred->challenge, sess_key, &sto_clnt_cred->challenge, new_clnt_time)) { return False; } /* first 4 bytes of the new seed is old client 4 bytes + clnt time + 1 */ new_cred = IVAL(sto_clnt_cred->challenge.data, 0); new_cred += new_clnt_time.time; /* store new seed in client credentials */ SIVAL(sto_clnt_cred->challenge.data, 0, new_cred); DEBUG(5,(" new clnt cred: %s\n", credstr(sto_clnt_cred->challenge.data))); return True; }
static void creds_init_128(struct dcinfo *dc, const DOM_CHAL *clnt_chal_in, const DOM_CHAL *srv_chal_in, const unsigned char mach_pw[16]) { unsigned char zero[4], tmp[16]; HMACMD5Context ctx; struct MD5Context md5; /* Just in case this isn't already there */ memcpy(dc->mach_pw, mach_pw, 16); ZERO_STRUCT(dc->sess_key); memset(zero, 0, sizeof(zero)); hmac_md5_init_rfc2104(mach_pw, 16, &ctx); MD5Init(&md5); MD5Update(&md5, zero, sizeof(zero)); MD5Update(&md5, clnt_chal_in->data, 8); MD5Update(&md5, srv_chal_in->data, 8); MD5Final(tmp, &md5); hmac_md5_update(tmp, sizeof(tmp), &ctx); hmac_md5_final(dc->sess_key, &ctx); /* debug output */ DEBUG(5,("creds_init_128\n")); DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data))); DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data))); dump_data_pw("\tsession_key ", (const unsigned char *)dc->sess_key, 16); /* Generate the next client and server creds. */ des_crypt112(dc->clnt_chal.data, /* output */ clnt_chal_in->data, /* input */ dc->sess_key, /* input */ 1); des_crypt112(dc->srv_chal.data, /* output */ srv_chal_in->data, /* input */ dc->sess_key, /* input */ 1); /* Seed is the client chal. */ memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8); }
static void creds_init_64(struct dcinfo *dc, const DOM_CHAL *clnt_chal_in, const DOM_CHAL *srv_chal_in, const unsigned char mach_pw[16]) { uint32 sum[2]; unsigned char sum2[8]; /* Just in case this isn't already there */ if (dc->mach_pw != mach_pw) { memcpy(dc->mach_pw, mach_pw, 16); } sum[0] = IVAL(clnt_chal_in->data, 0) + IVAL(srv_chal_in->data, 0); sum[1] = IVAL(clnt_chal_in->data, 4) + IVAL(srv_chal_in->data, 4); SIVAL(sum2,0,sum[0]); SIVAL(sum2,4,sum[1]); ZERO_STRUCT(dc->sess_key); des_crypt128(dc->sess_key, sum2, dc->mach_pw); /* debug output */ DEBUG(5,("creds_init_64\n")); DEBUG(5,("\tclnt_chal_in: %s\n", credstr(clnt_chal_in->data))); DEBUG(5,("\tsrv_chal_in : %s\n", credstr(srv_chal_in->data))); DEBUG(5,("\tclnt+srv : %s\n", credstr(sum2))); DEBUG(5,("\tsess_key_out : %s\n", credstr(dc->sess_key))); /* Generate the next client and server creds. */ des_crypt112(dc->clnt_chal.data, /* output */ clnt_chal_in->data, /* input */ dc->sess_key, /* input */ 1); des_crypt112(dc->srv_chal.data, /* output */ srv_chal_in->data, /* input */ dc->sess_key, /* input */ 1); /* Seed is the client chal. */ memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8); }
/**************************************************************************** create a credential Input: 8 byte sesssion key 8 byte stored credential 4 byte timestamp Output: 8 byte credential ****************************************************************************/ void cred_create(uchar session_key[8], DOM_CHAL *stor_cred, UTIME timestamp, DOM_CHAL *cred) { DOM_CHAL time_cred; SIVAL(time_cred.data, 0, IVAL(stor_cred->data, 0) + timestamp.time); SIVAL(time_cred.data, 4, IVAL(stor_cred->data, 4)); cred_hash2(cred->data, time_cred.data, session_key); /* debug output*/ DEBUG(4,("cred_create\n")); DEBUG(5,(" sess_key : %s\n", credstr(session_key))); DEBUG(5,(" stor_cred: %s\n", credstr(stor_cred->data))); DEBUG(5,(" timestamp: %x\n" , timestamp.time)); DEBUG(5,(" timecred : %s\n", credstr(time_cred.data))); DEBUG(5,(" calc_cred: %s\n", credstr(cred->data))); }
static void creds_reseed(struct dcinfo *dc) { DOM_CHAL time_chal; SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1); SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4)); dc->seed_chal = time_chal; DEBUG(5,("cred_reseed: seed %s\n", credstr(dc->seed_chal.data) )); }
/**************************************************************************** setup the session key. Input: 8 byte challenge block 8 byte server challenge block 16 byte md4 encrypted password Output: 8 byte session key ****************************************************************************/ void cred_session_key(const DOM_CHAL *clnt_chal, const DOM_CHAL *srv_chal, const uchar *pass, uchar session_key[8]) { uint32 sum[2]; unsigned char sum2[8]; sum[0] = IVAL(clnt_chal->data, 0) + IVAL(srv_chal->data, 0); sum[1] = IVAL(clnt_chal->data, 4) + IVAL(srv_chal->data, 4); SIVAL(sum2,0,sum[0]); SIVAL(sum2,4,sum[1]); cred_hash1(session_key, sum2, pass); /* debug output */ DEBUG(4,("cred_session_key\n")); DEBUG(5,(" clnt_chal: %s\n", credstr(clnt_chal->data))); DEBUG(5,(" srv_chal : %s\n", credstr(srv_chal->data))); DEBUG(5,(" clnt+srv : %s\n", credstr(sum2))); DEBUG(5,(" sess_key : %s\n", credstr(session_key))); }
/**************************************************************************** check a supplied credential Input: 8 byte received credential 8 byte sesssion key 8 byte stored credential 4 byte timestamp Output: returns 1 if computed credential matches received credential returns 0 otherwise ****************************************************************************/ int cred_assert(DOM_CHAL *cred, uchar session_key[8], DOM_CHAL *stored_cred, UTIME timestamp) { DOM_CHAL cred2; cred_create(session_key, stored_cred, timestamp, &cred2); /* debug output*/ DEBUG(4,("cred_assert\n")); DEBUG(5,(" challenge : %s\n", credstr(cred->data))); DEBUG(5,(" calculated: %s\n", credstr(cred2.data))); if (memcmp(cred->data, cred2.data, 8) == 0) { DEBUG(5, ("credentials check ok\n")); return True; } else { DEBUG(5, ("credentials check wrong\n")); return False; } }
/**************************************************************************** checks credentials; generates next step in the credential chain ****************************************************************************/ BOOL deal_with_creds(uchar sess_key[8], DOM_CRED *sto_clnt_cred, DOM_CRED *rcv_clnt_cred, DOM_CRED *rtn_srv_cred) { UTIME new_clnt_time; uint32 new_cred; DEBUG(5,("deal_with_creds: %d\n", __LINE__)); /* check that the received client credentials are valid */ if (!cred_assert(&rcv_clnt_cred->challenge, sess_key, &sto_clnt_cred->challenge, rcv_clnt_cred->timestamp)) { return False; } /* increment client time by one second */ new_clnt_time.time = rcv_clnt_cred->timestamp.time + 1; /* first 4 bytes of the new seed is old client 4 bytes + clnt time + 1 */ new_cred = IVAL(sto_clnt_cred->challenge.data, 0); new_cred += new_clnt_time.time; DEBUG(5,("deal_with_creds: new_cred[0]=%x\n", new_cred)); /* doesn't matter that server time is 0 */ rtn_srv_cred->timestamp.time = 0; DEBUG(5,("deal_with_creds: new_clnt_time=%x\n", new_clnt_time.time)); /* create return credentials for inclusion in the reply */ cred_create(sess_key, &sto_clnt_cred->challenge, new_clnt_time, &rtn_srv_cred->challenge); DEBUG(5,("deal_with_creds: clnt_cred=%s\n", credstr(sto_clnt_cred->challenge.data))); /* store new seed in client credentials */ SIVAL(sto_clnt_cred->challenge.data, 0, new_cred); return True; }
/*************************************************************************** do a LSA SAM Logoff ****************************************************************************/ BOOL do_lsa_sam_logoff(uint16 fnum, uint32 call_id, uchar sess_key[8], DOM_CRED *sto_clnt_cred, char *logon_srv, char *comp_name, DOM_CRED *clnt_cred, DOM_CRED *rtn_cred, uint16 logon_level, uint16 switch_value, DOM_ID_INFO_1 *id1, DOM_CRED *srv_cred) { char *rparam = NULL; char *rdata = NULL; char *p; int rdrcnt,rprcnt; pstring data; /* only 1024 bytes */ uint16 setup[2]; /* only need 2 uint16 setup parameters */ LSA_Q_SAM_LOGOFF q_s; BOOL valid_cred = False; if (srv_cred == NULL || clnt_cred == NULL || rtn_cred == NULL) return False; /* create and send a MSRPC command with api LSA_SAMLOGON */ DEBUG(4,("LSA SAM Logoff: srv:%s mc:%s clnt %s %lx rtn: %s %lx ll: %d\n", logon_srv, comp_name, credstr(clnt_cred->challenge.data), clnt_cred->timestamp.time, credstr(rtn_cred->challenge.data), rtn_cred ->timestamp.time, logon_level)); /* store the parameters */ make_sam_info(&(q_s.sam_id), logon_srv, comp_name, clnt_cred, rtn_cred, logon_level, switch_value, id1); /* turn parameters into data stream */ p = lsa_io_q_sam_logoff(False, &q_s, data + 0x18, data, 4, 0); /* create the request RPC_HDR_RR _after_ the main data: length is now known */ create_rpc_request(call_id, LSA_SAMLOGOFF, data, PTR_DIFF(p, data)); /* create setup parameters. */ setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */ setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */ /* send the data on \PIPE\ */ if (cli_call_api("\\PIPE\\", 0, 0, PTR_DIFF(p, data), 2, 1024, BUFFER_SIZE, &rprcnt,&rdrcnt, NULL, data, setup, &rparam,&rdata)) { LSA_R_SAM_LOGOFF r_s; RPC_HDR_RR hdr; int hdr_len; int pkt_len; DEBUG(5, ("cli_call_api: return OK\n")); p = rdata; if (p) p = smb_io_rpc_hdr_rr (True, &hdr, p, rdata, 4, 0); if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */ hdr_len = PTR_DIFF(p, rdata); if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint) { /* header length not same as calculated header length */ DEBUG(2,("do_lsa_sam_logoff: hdr_len %x != frag_len-alloc_hint %x\n", hdr_len, hdr.hdr.frag_len - hdr.alloc_hint)); p = NULL; } if (p) p = lsa_io_r_sam_logoff(True, &r_s, p, rdata, 4, 0); pkt_len = PTR_DIFF(p, rdata); if (p && pkt_len != hdr.hdr.frag_len) { /* packet data size not same as reported fragment length */ DEBUG(2,("do_lsa_sam_logoff: pkt_len %x != frag_len \n", pkt_len, hdr.hdr.frag_len)); p = NULL; } if (p && r_s.status != 0) { /* report error code */ DEBUG(0,("LSA_SAMLOGOFF: nt_status error %lx\n", r_s.status)); p = NULL; } if (p) { if (clnt_deal_with_creds(sess_key, sto_clnt_cred, &(r_s.srv_creds))) { DEBUG(5, ("do_lsa_sam_logoff: server credential check OK\n")); /* ok, at last: we're happy. return the challenge */ memcpy(srv_cred, &(r_s.srv_creds), sizeof(r_s.srv_creds)); valid_cred = True; } else { DEBUG(5, ("do_lsa_sam_logoff: server credential check failed\n")); } } } if (rparam) free(rparam); if (rdata) free(rdata); return valid_cred; }
/**************************************************************************** do a LSA Request Challenge ****************************************************************************/ BOOL do_lsa_req_chal(uint16 fnum, uint32 call_id, char *desthost, char *myhostname, DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal) { char *rparam = NULL; char *rdata = NULL; char *p; int rdrcnt,rprcnt; pstring data; /* only 1024 bytes */ uint16 setup[2]; /* only need 2 uint16 setup parameters */ LSA_Q_REQ_CHAL q_c; BOOL valid_chal = False; if (srv_chal == NULL || clnt_chal == NULL) return False; /* create and send a MSRPC command with api LSA_REQCHAL */ DEBUG(4,("LSA Request Challenge from %s to %s: %s\n", desthost, myhostname, credstr(clnt_chal->data))); /* store the parameters */ make_q_req_chal(&q_c, desthost, myhostname, clnt_chal); /* turn parameters into data stream */ p = lsa_io_q_req_chal(False, &q_c, data + 0x18, data, 4, 0); /* create the request RPC_HDR_RR _after_ the main data: length is now known */ create_rpc_request(call_id, LSA_REQCHAL, data, PTR_DIFF(p, data)); /* create setup parameters. */ setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */ setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */ /* send the data on \PIPE\ */ if (cli_call_api("\\PIPE\\", 0, 0, PTR_DIFF(p, data), 2, 1024, BUFFER_SIZE, &rprcnt,&rdrcnt, NULL, data, setup, &rparam,&rdata)) { LSA_R_REQ_CHAL r_c; RPC_HDR_RR hdr; int hdr_len; int pkt_len; DEBUG(5, ("cli_call_api: return OK\n")); p = rdata; if (p) p = smb_io_rpc_hdr_rr (True, &hdr, p, rdata, 4, 0); if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */ hdr_len = PTR_DIFF(p, rdata); if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint) { /* header length not same as calculated header length */ DEBUG(2,("do_lsa_req_chal: hdr_len %x != frag_len-alloc_hint %x\n", hdr_len, hdr.hdr.frag_len - hdr.alloc_hint)); p = NULL; } if (p) p = lsa_io_r_req_chal(True, &r_c, p, rdata, 4, 0); pkt_len = PTR_DIFF(p, rdata); if (p && pkt_len != hdr.hdr.frag_len) { /* packet data size not same as reported fragment length */ DEBUG(2,("do_lsa_req_chal: pkt_len %x != frag_len \n", pkt_len, hdr.hdr.frag_len)); p = NULL; } if (p && r_c.status != 0) { /* report error code */ DEBUG(0,("LSA_REQ_CHAL: nt_status error %lx\n", r_c.status)); p = NULL; } if (p) { /* ok, at last: we're happy. return the challenge */ memcpy(srv_chal, r_c.srv_chal.data, sizeof(srv_chal->data)); valid_chal = True; } } if (rparam) free(rparam); if (rdata) free(rdata); return valid_chal; }
/**************************************************************************** do a LSA Authenticate 2 ****************************************************************************/ BOOL do_lsa_auth2(uint16 fnum, uint32 call_id, char *logon_srv, char *acct_name, uint16 sec_chan, char *comp_name, DOM_CHAL *clnt_chal, uint32 neg_flags, DOM_CHAL *srv_chal) { char *rparam = NULL; char *rdata = NULL; char *p; int rdrcnt,rprcnt; pstring data; /* only 1024 bytes */ uint16 setup[2]; /* only need 2 uint16 setup parameters */ LSA_Q_AUTH_2 q_a; BOOL valid_chal = False; if (srv_chal == NULL || clnt_chal == NULL) return False; /* create and send a MSRPC command with api LSA_AUTH2 */ DEBUG(4,("LSA Authenticate 2: srv:%s acct:%s sc:%x mc: %s chal %s neg: %lx\n", logon_srv, acct_name, sec_chan, comp_name, credstr(clnt_chal->data), neg_flags)); /* store the parameters */ make_q_auth_2(&q_a, logon_srv, acct_name, sec_chan, comp_name, clnt_chal, neg_flags); /* turn parameters into data stream */ p = lsa_io_q_auth_2(False, &q_a, data + 0x18, data, 4, 0); /* create the request RPC_HDR_RR _after_ the main data: length is now known */ create_rpc_request(call_id, LSA_AUTH2, data, PTR_DIFF(p, data)); /* create setup parameters. */ setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */ setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */ /* send the data on \PIPE\ */ if (cli_call_api("\\PIPE\\", 0, 0, PTR_DIFF(p, data), 2, 1024, BUFFER_SIZE, &rprcnt,&rdrcnt, NULL, data, setup, &rparam,&rdata)) { LSA_R_AUTH_2 r_a; RPC_HDR_RR hdr; int hdr_len; int pkt_len; DEBUG(5, ("cli_call_api: return OK\n")); p = rdata; if (p) p = smb_io_rpc_hdr_rr (True, &hdr, p, rdata, 4, 0); if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */ hdr_len = PTR_DIFF(p, rdata); if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint) { /* header length not same as calculated header length */ DEBUG(2,("do_lsa_auth2: hdr_len %x != frag_len-alloc_hint %x\n", hdr_len, hdr.hdr.frag_len - hdr.alloc_hint)); p = NULL; } if (p) p = lsa_io_r_auth_2(True, &r_a, p, rdata, 4, 0); pkt_len = PTR_DIFF(p, rdata); if (p && pkt_len != hdr.hdr.frag_len) { /* packet data size not same as reported fragment length */ DEBUG(2,("do_lsa_auth2: pkt_len %x != frag_len \n", pkt_len, hdr.hdr.frag_len)); p = NULL; } if (p && r_a.status != 0) { /* report error code */ DEBUG(0,("LSA_AUTH2: nt_status error %lx\n", r_a.status)); p = NULL; } if (p && r_a.srv_flgs.neg_flags != q_a.clnt_flgs.neg_flags) { /* report different neg_flags */ DEBUG(0,("LSA_AUTH2: error neg_flags (q,r) differ - (%lx,%lx)\n", q_a.clnt_flgs.neg_flags, r_a.srv_flgs.neg_flags)); p = NULL; } if (p) { /* ok, at last: we're happy. return the challenge */ memcpy(srv_chal, r_a.srv_chal.data, sizeof(srv_chal->data)); valid_chal = True; } } if (rparam) free(rparam); if (rdata) free(rdata); return valid_chal; }