parse_prs.c
来自「samba-3.0.22.tar.gz 编译smb服务器的源码」· C语言 代码 · 共 1,734 行 · 第 1/4 页
C
1,734 行
return True;}/******************************************************************* prs_uint16 wrapper. Call this and it sets up a pointer to where the uint16 should be stored, or gets the size if reading. ********************************************************************/BOOL prs_uint16_pre(const char *name, prs_struct *ps, int depth, uint16 *data16, uint32 *offset){ *offset = ps->data_offset; if (UNMARSHALLING(ps)) { /* reading. */ return prs_uint16(name, ps, depth, data16); } else { char *q = prs_mem_get(ps, sizeof(uint16)); if(q ==NULL) return False; ps->data_offset += sizeof(uint16); } return True;}/******************************************************************* prs_uint16 wrapper. call this and it retrospectively stores the size. does nothing on reading, as that is already handled by ...._pre() ********************************************************************/BOOL prs_uint16_post(const char *name, prs_struct *ps, int depth, uint16 *data16, uint32 ptr_uint16, uint32 start_offset){ if (MARSHALLING(ps)) { /* * Writing - temporarily move the offset pointer. */ uint16 data_size = ps->data_offset - start_offset; uint32 old_offset = ps->data_offset; ps->data_offset = ptr_uint16; if(!prs_uint16(name, ps, depth, &data_size)) { ps->data_offset = old_offset; return False; } ps->data_offset = old_offset; } else { ps->data_offset = start_offset + (uint32)(*data16); } return True;}/******************************************************************* prs_uint32 wrapper. Call this and it sets up a pointer to where the uint32 should be stored, or gets the size if reading. ********************************************************************/BOOL prs_uint32_pre(const char *name, prs_struct *ps, int depth, uint32 *data32, uint32 *offset){ *offset = ps->data_offset; if (UNMARSHALLING(ps) && (data32 != NULL)) { /* reading. */ return prs_uint32(name, ps, depth, data32); } else { ps->data_offset += sizeof(uint32); } return True;}/******************************************************************* prs_uint32 wrapper. call this and it retrospectively stores the size. does nothing on reading, as that is already handled by ...._pre() ********************************************************************/BOOL prs_uint32_post(const char *name, prs_struct *ps, int depth, uint32 *data32, uint32 ptr_uint32, uint32 data_size){ if (MARSHALLING(ps)) { /* * Writing - temporarily move the offset pointer. */ uint32 old_offset = ps->data_offset; ps->data_offset = ptr_uint32; if(!prs_uint32(name, ps, depth, &data_size)) { ps->data_offset = old_offset; return False; } ps->data_offset = old_offset; } return True;}/* useful function to store a structure in rpc wire format */int tdb_prs_store(TDB_CONTEXT *tdb, char *keystr, prs_struct *ps){ TDB_DATA kbuf, dbuf; kbuf.dptr = keystr; kbuf.dsize = strlen(keystr)+1; dbuf.dptr = ps->data_p; dbuf.dsize = prs_offset(ps); return tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);}/* useful function to fetch a structure into rpc wire format */int tdb_prs_fetch(TDB_CONTEXT *tdb, char *keystr, prs_struct *ps, TALLOC_CTX *mem_ctx){ TDB_DATA kbuf, dbuf; kbuf.dptr = keystr; kbuf.dsize = strlen(keystr)+1; dbuf = tdb_fetch(tdb, kbuf); if (!dbuf.dptr) return -1; prs_init(ps, 0, mem_ctx, UNMARSHALL); prs_give_memory(ps, dbuf.dptr, dbuf.dsize, True); return 0;} /******************************************************************* hash a stream. ********************************************************************/BOOL prs_hash1(prs_struct *ps, uint32 offset, int len){ char *q; q = ps->data_p; q = &q[offset];#ifdef DEBUG_PASSWORD DEBUG(100, ("prs_hash1\n")); dump_data(100, ps->sess_key, 16); dump_data(100, q, len);#endif SamOEMhash((uchar *) q, (const unsigned char *)ps->sess_key, len);#ifdef DEBUG_PASSWORD dump_data(100, q, len);#endif return True;}/******************************************************************* Create a digest over the entire packet (including the data), and MD5 it with the session key. ********************************************************************/static void schannel_digest(struct schannel_auth_struct *a, enum pipe_auth_level auth_level, RPC_AUTH_SCHANNEL_CHK * verf, char *data, size_t data_len, uchar digest_final[16]) { uchar whole_packet_digest[16]; static uchar zeros[4]; struct MD5Context ctx3; /* verfiy the signature on the packet by MD5 over various bits */ MD5Init(&ctx3); /* use our sequence number, which ensures the packet is not out of order */ MD5Update(&ctx3, zeros, sizeof(zeros)); MD5Update(&ctx3, verf->sig, sizeof(verf->sig)); if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) { MD5Update(&ctx3, verf->confounder, sizeof(verf->confounder)); } MD5Update(&ctx3, (const unsigned char *)data, data_len); MD5Final(whole_packet_digest, &ctx3); dump_data_pw("whole_packet_digest:\n", whole_packet_digest, sizeof(whole_packet_digest)); /* MD5 this result and the session key, to prove that only a valid client could had produced this */ hmac_md5(a->sess_key, whole_packet_digest, sizeof(whole_packet_digest), digest_final);}/******************************************************************* Calculate the key with which to encode the data payload ********************************************************************/static void schannel_get_sealing_key(struct schannel_auth_struct *a, RPC_AUTH_SCHANNEL_CHK *verf, uchar sealing_key[16]) { static uchar zeros[4]; uchar digest2[16]; uchar sess_kf0[16]; int i; for (i = 0; i < sizeof(sess_kf0); i++) { sess_kf0[i] = a->sess_key[i] ^ 0xf0; } dump_data_pw("sess_kf0:\n", sess_kf0, sizeof(sess_kf0)); /* MD5 of sess_kf0 and 4 zero bytes */ hmac_md5(sess_kf0, zeros, 0x4, digest2); dump_data_pw("digest2:\n", digest2, sizeof(digest2)); /* MD5 of the above result, plus 8 bytes of sequence number */ hmac_md5(digest2, verf->seq_num, sizeof(verf->seq_num), sealing_key); dump_data_pw("sealing_key:\n", sealing_key, 16);}/******************************************************************* Encode or Decode the sequence number (which is symmetric) ********************************************************************/static void schannel_deal_with_seq_num(struct schannel_auth_struct *a, RPC_AUTH_SCHANNEL_CHK *verf){ static uchar zeros[4]; uchar sequence_key[16]; uchar digest1[16]; hmac_md5(a->sess_key, zeros, sizeof(zeros), digest1); dump_data_pw("(sequence key) digest1:\n", digest1, sizeof(digest1)); hmac_md5(digest1, verf->packet_digest, 8, sequence_key); dump_data_pw("sequence_key:\n", sequence_key, sizeof(sequence_key)); dump_data_pw("seq_num (before):\n", verf->seq_num, sizeof(verf->seq_num)); SamOEMhash(verf->seq_num, sequence_key, 8); dump_data_pw("seq_num (after):\n", verf->seq_num, sizeof(verf->seq_num));}/*******************************************************************creates an RPC_AUTH_SCHANNEL_CHK structure.********************************************************************/static BOOL init_rpc_auth_schannel_chk(RPC_AUTH_SCHANNEL_CHK * chk, const uchar sig[8], const uchar packet_digest[8], const uchar seq_num[8], const uchar confounder[8]){ if (chk == NULL) return False; memcpy(chk->sig, sig, sizeof(chk->sig)); memcpy(chk->packet_digest, packet_digest, sizeof(chk->packet_digest)); memcpy(chk->seq_num, seq_num, sizeof(chk->seq_num)); memcpy(chk->confounder, confounder, sizeof(chk->confounder)); return True;}/******************************************************************* Encode a blob of data using the schannel alogrithm, also produceing a checksum over the original data. We currently only support signing and sealing togeather - the signing-only code is close, but not quite compatible with what MS does. ********************************************************************/void schannel_encode(struct schannel_auth_struct *a, enum pipe_auth_level auth_level, enum schannel_direction direction, RPC_AUTH_SCHANNEL_CHK * verf, char *data, size_t data_len){ uchar digest_final[16]; uchar confounder[8]; uchar seq_num[8]; static const uchar nullbytes[8]; static const uchar schannel_seal_sig[8] = SCHANNEL_SEAL_SIGNATURE; static const uchar schannel_sign_sig[8] = SCHANNEL_SIGN_SIGNATURE; const uchar *schannel_sig = NULL; DEBUG(10,("SCHANNEL: schannel_encode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len)); if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) { schannel_sig = schannel_seal_sig; } else { schannel_sig = schannel_sign_sig; } /* fill the 'confounder' with random data */ generate_random_buffer(confounder, sizeof(confounder)); dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key)); RSIVAL(seq_num, 0, a->seq_num); switch (direction) { case SENDER_IS_INITIATOR: SIVAL(seq_num, 4, 0x80); break; case SENDER_IS_ACCEPTOR: SIVAL(seq_num, 4, 0x0); break; } dump_data_pw("verf->seq_num:\n", seq_num, sizeof(verf->seq_num)); init_rpc_auth_schannel_chk(verf, schannel_sig, nullbytes, seq_num, confounder); /* produce a digest of the packet to prove it's legit (before we seal it) */ schannel_digest(a, auth_level, verf, data, data_len, digest_final); memcpy(verf->packet_digest, digest_final, sizeof(verf->packet_digest)); if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) { uchar sealing_key[16]; /* get the key to encode the data with */ schannel_get_sealing_key(a, verf, sealing_key); /* encode the verification data */ dump_data_pw("verf->confounder:\n", verf->confounder, sizeof(verf->confounder)); SamOEMhash(verf->confounder, sealing_key, 8); dump_data_pw("verf->confounder_enc:\n", verf->confounder, sizeof(verf->confounder)); /* encode the packet payload */ dump_data_pw("data:\n", (const unsigned char *)data, data_len); SamOEMhash((unsigned char *)data, sealing_key, data_len); dump_data_pw("data_enc:\n", (const unsigned char *)data, data_len); } /* encode the sequence number (key based on packet digest) */ /* needs to be done after the sealing, as the original version is used in the sealing stuff... */ schannel_deal_with_seq_num(a, verf); return;}/******************************************************************* Decode a blob of data using the schannel alogrithm, also verifiying a checksum over the original data. We currently can verify signed messages, as well as decode sealed messages ********************************************************************/BOOL schannel_decode(struct schannel_auth_struct *a, enum pipe_auth_level auth_level, enum schannel_direction direction, RPC_AUTH_SCHANNEL_CHK * verf, char *data, size_t data_len){ uchar digest_final[16]; static const uchar schannel_seal_sig[8] = SCHANNEL_SEAL_SIGNATURE; static const uchar schannel_sign_sig[8] = SCHANNEL_SIGN_SIGNATURE; const uchar *schannel_sig = NULL; uchar seq_num[8]; DEBUG(10,("SCHANNEL: schannel_decode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len)); if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) { schannel_sig = schannel_seal_sig; } else { schannel_sig = schannel_sign_sig; } /* Create the expected sequence number for comparison */ RSIVAL(seq_num, 0, a->seq_num); switch (direction) { case SENDER_IS_INITIATOR: SIVAL(seq_num, 4, 0x80); break; case SENDER_IS_ACCEPTOR: SIVAL(seq_num, 4, 0x0); break; } DEBUG(10,("SCHANNEL: schannel_decode seq_num=%d data_len=%lu\n", a->seq_num, (unsigned long)data_len)); dump_data_pw("a->sess_key:\n", a->sess_key, sizeof(a->sess_key)); dump_data_pw("seq_num:\n", seq_num, sizeof(seq_num)); /* extract the sequence number (key based on supplied packet digest) */ /* needs to be done before the sealing, as the original version is used in the sealing stuff... */ schannel_deal_with_seq_num(a, verf); if (memcmp(verf->seq_num, seq_num, sizeof(seq_num))) { /* don't even bother with the below if the sequence number is out */ /* The sequence number is MD5'ed with a key based on the whole-packet digest, as supplied by the client. We check that it's a valid checksum after the decode, below */ DEBUG(2, ("schannel_decode: FAILED: packet sequence number:\n")); dump_data(2, (const char*)verf->seq_num, sizeof(verf->seq_num)); DEBUG(2, ("should be:\n")); dump_data(2, (const char*)seq_num, sizeof(seq_num)); return False; } if (memcmp(verf->sig, schannel_sig, sizeof(verf->sig))) { /* Validate that the other end sent the expected header */ DEBUG(2, ("schannel_decode: FAILED: packet header:\n")); dump_data(2, (const char*)verf->sig, sizeof(verf->sig)); DEBUG(2, ("should be:\n")); dump_data(2, (const char*)schannel_sig, sizeof(schannel_sig)); return False; } if (auth_level == PIPE_AUTH_LEVEL_PRIVACY) { uchar sealing_key[16]; /* get the key to extract the data with */ schannel_get_sealing_key(a, verf, sealing_key); /* extract the verification data */ dump_data_pw("verf->confounder:\n", verf->confounder, sizeof(verf->confounder)); SamOEMhash(verf->confounder, sealing_key, 8); dump_data_pw("verf->confounder_dec:\n", verf->confounder, sizeof(verf->confounder)); /* extract the packet payload */ dump_data_pw("data :\n", (const unsigned char *)data, data_len); SamOEMhash((unsigned char *)data, sealing_key, data_len); dump_data_pw("datadec:\n", (const unsigned char *)data, data_len); } /* digest includes 'data' after unsealing */ schannel_digest(a, auth_level, verf, data, data_len, digest_final); dump_data_pw("Calculated digest:\n", digest_final, sizeof(digest_final)); dump_data_pw("verf->packet_digest:\n", verf->packet_digest, sizeof(verf->packet_digest)); /* compare - if the client got the same result as us, then it must know the session key */ return (memcmp(digest_final, verf->packet_digest, sizeof(verf->packet_digest)) == 0);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?