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 + -
显示快捷键?