mirror of
https://github.com/samba-team/samba.git
synced 2025-01-29 21:47:30 +03:00
Refactor signing code to remove most dependencies on 'struct cli'.
Ensure a server can't do a downgrade attack if client signing is mandatory. Add a lp_server_signing() function and a 'server signing' parameter that will act as the client one does. Jeremy (This used to be commit 203e4bf0bfb66fd9239e9a0656438a71280113cb)
This commit is contained in:
parent
cdb3b5dec2
commit
6ab5e14494
@ -57,18 +57,6 @@ struct print_job_info
|
||||
time_t t;
|
||||
};
|
||||
|
||||
typedef struct smb_sign_info {
|
||||
void (*sign_outgoing_message)(struct cli_state *cli);
|
||||
BOOL (*check_incoming_message)(struct cli_state *cli);
|
||||
void (*free_signing_context)(struct cli_state *cli);
|
||||
void *signing_context;
|
||||
|
||||
BOOL negotiated_smb_signing;
|
||||
BOOL allow_smb_signing;
|
||||
BOOL doing_signing;
|
||||
BOOL mandatory_signing;
|
||||
} smb_sign_info;
|
||||
|
||||
struct cli_state {
|
||||
int port;
|
||||
int fd;
|
||||
|
@ -1630,4 +1630,18 @@ struct ip_service {
|
||||
unsigned port;
|
||||
};
|
||||
|
||||
/* Used by the SMB signing functions. */
|
||||
|
||||
typedef struct smb_sign_info {
|
||||
void (*sign_outgoing_message)(char *outbuf, struct smb_sign_info *si);
|
||||
BOOL (*check_incoming_message)(char *inbuf, struct smb_sign_info *si);
|
||||
void (*free_signing_context)(struct smb_sign_info *si);
|
||||
void *signing_context;
|
||||
|
||||
BOOL negotiated_smb_signing;
|
||||
BOOL allow_smb_signing;
|
||||
BOOL doing_signing;
|
||||
BOOL mandatory_signing;
|
||||
} smb_sign_info;
|
||||
|
||||
#endif /* _SMB_H */
|
||||
|
@ -989,6 +989,11 @@ BOOL cli_negprot(struct cli_state *cli)
|
||||
|
||||
cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
|
||||
|
||||
if ((cli->protocol < PROTOCOL_NT1) && (lp_client_signing() == Required)) {
|
||||
DEBUG(1,("cli_negprot: SMB signing is mandatory and the selected protocol level doesn't support it.\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
if (cli->protocol >= PROTOCOL_NT1) {
|
||||
/* NT protocol */
|
||||
cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
|
||||
|
@ -81,7 +81,7 @@ static BOOL cli_set_smb_signing_common(struct cli_state *cli)
|
||||
}
|
||||
|
||||
if (cli->sign_info.free_signing_context)
|
||||
cli->sign_info.free_signing_context(cli);
|
||||
cli->sign_info.free_signing_context(&cli->sign_info);
|
||||
|
||||
/* These calls are INCOMPATIBLE with SMB signing */
|
||||
cli->readbraw_supported = False;
|
||||
@ -94,11 +94,11 @@ static BOOL cli_set_smb_signing_common(struct cli_state *cli)
|
||||
SMB signing - Common code for 'real' implementations
|
||||
************************************************************/
|
||||
|
||||
static BOOL cli_set_smb_signing_real_common(struct cli_state *cli)
|
||||
static BOOL set_smb_signing_real_common(struct smb_sign_info *si)
|
||||
{
|
||||
if (cli->sign_info.mandatory_signing) {
|
||||
if (si->mandatory_signing) {
|
||||
DEBUG(5, ("Mandatory SMB signing enabled!\n"));
|
||||
cli->sign_info.doing_signing = True;
|
||||
si->doing_signing = True;
|
||||
}
|
||||
|
||||
DEBUG(5, ("SMB signing enabled!\n"));
|
||||
@ -114,22 +114,85 @@ static void mark_packet_signed(char *outbuf)
|
||||
SSVAL(outbuf,smb_flg2, flags2);
|
||||
}
|
||||
|
||||
static BOOL cli_signing_good(struct cli_state *cli, BOOL good)
|
||||
/***********************************************************
|
||||
SMB signing - NULL implementation - calculate a MAC to send.
|
||||
************************************************************/
|
||||
|
||||
static void null_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
|
||||
{
|
||||
/* we can't zero out the sig, as we might be trying to send a
|
||||
session request - which is NBT-level, not SMB level and doesn't
|
||||
have the field */
|
||||
return;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - NULL implementation - check a MAC sent by server.
|
||||
************************************************************/
|
||||
|
||||
static BOOL null_check_incoming_message(char *inbuf, struct smb_sign_info *si)
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - NULL implementation - free signing context
|
||||
************************************************************/
|
||||
|
||||
static void null_free_signing_context(struct smb_sign_info *si)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
SMB signing - NULL implementation - setup the MAC key.
|
||||
|
||||
@note Used as an initialisation only - it will not correctly
|
||||
shut down a real signing mechanism
|
||||
*/
|
||||
|
||||
static BOOL null_set_signing(struct smb_sign_info *si)
|
||||
{
|
||||
si->signing_context = NULL;
|
||||
|
||||
si->sign_outgoing_message = null_sign_outgoing_message;
|
||||
si->check_incoming_message = null_check_incoming_message;
|
||||
si->free_signing_context = null_free_signing_context;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the signing context
|
||||
*/
|
||||
|
||||
static void free_signing_context(struct smb_sign_info *si)
|
||||
{
|
||||
if (si->free_signing_context) {
|
||||
si->free_signing_context(si);
|
||||
si->signing_context = NULL;
|
||||
}
|
||||
|
||||
null_set_signing(si);
|
||||
}
|
||||
|
||||
|
||||
static BOOL signing_good(char *inbuf, struct smb_sign_info *si, BOOL good)
|
||||
{
|
||||
DEBUG(10, ("got SMB signature of\n"));
|
||||
dump_data(10,&cli->inbuf[smb_ss_field] , 8);
|
||||
dump_data(10,&inbuf[smb_ss_field] , 8);
|
||||
|
||||
if (good && !cli->sign_info.doing_signing) {
|
||||
cli->sign_info.doing_signing = True;
|
||||
if (good && !si->doing_signing) {
|
||||
si->doing_signing = True;
|
||||
}
|
||||
|
||||
if (!good) {
|
||||
if (cli->sign_info.doing_signing) {
|
||||
if (si->doing_signing) {
|
||||
DEBUG(1, ("SMB signature check failed!\n"));
|
||||
return False;
|
||||
} else {
|
||||
DEBUG(3, ("Server did not sign reply correctly\n"));
|
||||
cli_free_signing_context(cli);
|
||||
free_signing_context(si);
|
||||
return False;
|
||||
}
|
||||
}
|
||||
@ -188,28 +251,27 @@ static void simple_packet_signature(struct smb_basic_signing_context *data,
|
||||
SMB signing - Simple implementation - send the MAC.
|
||||
************************************************************/
|
||||
|
||||
static void cli_simple_sign_outgoing_message(struct cli_state *cli)
|
||||
static void cli_simple_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
|
||||
{
|
||||
unsigned char calc_md5_mac[16];
|
||||
struct smb_basic_signing_context *data = cli->sign_info.signing_context;
|
||||
struct smb_basic_signing_context *data = si->signing_context;
|
||||
|
||||
/* mark the packet as signed - BEFORE we sign it...*/
|
||||
mark_packet_signed(cli->outbuf);
|
||||
mark_packet_signed(outbuf);
|
||||
|
||||
simple_packet_signature(data, cli->outbuf, data->send_seq_num,
|
||||
calc_md5_mac);
|
||||
simple_packet_signature(data, outbuf, data->send_seq_num, calc_md5_mac);
|
||||
|
||||
DEBUG(10, ("sent SMB signature of\n"));
|
||||
dump_data(10, calc_md5_mac, 8);
|
||||
|
||||
memcpy(&cli->outbuf[smb_ss_field], calc_md5_mac, 8);
|
||||
memcpy(&outbuf[smb_ss_field], calc_md5_mac, 8);
|
||||
|
||||
/* cli->outbuf[smb_ss_field+2]=0;
|
||||
Uncomment this to test if the remote server actually verifies signatures...*/
|
||||
|
||||
data->send_seq_num++;
|
||||
store_sequence_for_reply(&data->outstanding_packet_list,
|
||||
cli->mid,
|
||||
SVAL(outbuf,smb_mid),
|
||||
data->send_seq_num);
|
||||
data->send_seq_num++;
|
||||
}
|
||||
@ -218,24 +280,24 @@ static void cli_simple_sign_outgoing_message(struct cli_state *cli)
|
||||
SMB signing - Simple implementation - check a MAC sent by server.
|
||||
************************************************************/
|
||||
|
||||
static BOOL cli_simple_check_incoming_message(struct cli_state *cli)
|
||||
static BOOL cli_simple_check_incoming_message(char *inbuf, struct smb_sign_info *si)
|
||||
{
|
||||
BOOL good;
|
||||
uint32 reply_seq_number;
|
||||
unsigned char calc_md5_mac[16];
|
||||
unsigned char *server_sent_mac;
|
||||
|
||||
struct smb_basic_signing_context *data = cli->sign_info.signing_context;
|
||||
struct smb_basic_signing_context *data = si->signing_context;
|
||||
|
||||
if (!get_sequence_for_reply(&data->outstanding_packet_list,
|
||||
SVAL(cli->inbuf, smb_mid),
|
||||
SVAL(inbuf, smb_mid),
|
||||
&reply_seq_number)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
simple_packet_signature(data, cli->inbuf, reply_seq_number, calc_md5_mac);
|
||||
simple_packet_signature(data, inbuf, reply_seq_number, calc_md5_mac);
|
||||
|
||||
server_sent_mac = &cli->inbuf[smb_ss_field];
|
||||
server_sent_mac = &inbuf[smb_ss_field];
|
||||
good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
|
||||
|
||||
if (!good) {
|
||||
@ -245,16 +307,16 @@ static BOOL cli_simple_check_incoming_message(struct cli_state *cli)
|
||||
DEBUG(5, ("BAD SIG: got SMB signature of\n"));
|
||||
dump_data(5, server_sent_mac, 8);
|
||||
}
|
||||
return cli_signing_good(cli, good);
|
||||
return signing_good(inbuf, si, good);
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - Simple implementation - free signing context
|
||||
************************************************************/
|
||||
|
||||
static void cli_simple_free_signing_context(struct cli_state *cli)
|
||||
static void cli_simple_free_signing_context(struct smb_sign_info *si)
|
||||
{
|
||||
struct smb_basic_signing_context *data = cli->sign_info.signing_context;
|
||||
struct smb_basic_signing_context *data = si->signing_context;
|
||||
struct outstanding_packet_lookup *list = data->outstanding_packet_list;
|
||||
|
||||
while (list) {
|
||||
@ -264,7 +326,7 @@ static void cli_simple_free_signing_context(struct cli_state *cli)
|
||||
}
|
||||
|
||||
data_blob_free(&data->mac_key);
|
||||
SAFE_FREE(cli->sign_info.signing_context);
|
||||
SAFE_FREE(si->signing_context);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -284,7 +346,7 @@ BOOL cli_simple_set_signing(struct cli_state *cli, const uchar user_session_key[
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!cli_set_smb_signing_real_common(cli)) {
|
||||
if (!set_smb_signing_real_common(&cli->sign_info)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
@ -310,66 +372,18 @@ BOOL cli_simple_set_signing(struct cli_state *cli, const uchar user_session_key[
|
||||
return True;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - NULL implementation - calculate a MAC to send.
|
||||
************************************************************/
|
||||
|
||||
static void cli_null_sign_outgoing_message(struct cli_state *cli)
|
||||
{
|
||||
/* we can't zero out the sig, as we might be trying to send a
|
||||
session request - which is NBT-level, not SMB level and doesn't
|
||||
have the field */
|
||||
return;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - NULL implementation - check a MAC sent by server.
|
||||
************************************************************/
|
||||
|
||||
static BOOL cli_null_check_incoming_message(struct cli_state *cli)
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - NULL implementation - free signing context
|
||||
************************************************************/
|
||||
|
||||
static void cli_null_free_signing_context(struct cli_state *cli)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
SMB signing - NULL implementation - setup the MAC key.
|
||||
|
||||
@note Used as an initialisation only - it will not correctly
|
||||
shut down a real signing mechanism
|
||||
*/
|
||||
|
||||
BOOL cli_null_set_signing(struct cli_state *cli)
|
||||
{
|
||||
cli->sign_info.signing_context = NULL;
|
||||
|
||||
cli->sign_info.sign_outgoing_message = cli_null_sign_outgoing_message;
|
||||
cli->sign_info.check_incoming_message = cli_null_check_incoming_message;
|
||||
cli->sign_info.free_signing_context = cli_null_free_signing_context;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - TEMP implementation - calculate a MAC to send.
|
||||
************************************************************/
|
||||
|
||||
static void cli_temp_sign_outgoing_message(struct cli_state *cli)
|
||||
static void cli_temp_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
|
||||
{
|
||||
/* mark the packet as signed - BEFORE we sign it...*/
|
||||
mark_packet_signed(cli->outbuf);
|
||||
mark_packet_signed(outbuf);
|
||||
|
||||
/* I wonder what BSRSPYL stands for - but this is what MS
|
||||
actually sends! */
|
||||
memcpy(&cli->outbuf[smb_ss_field], "BSRSPYL ", 8);
|
||||
memcpy(&outbuf[smb_ss_field], "BSRSPYL ", 8);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -377,7 +391,7 @@ static void cli_temp_sign_outgoing_message(struct cli_state *cli)
|
||||
SMB signing - TEMP implementation - check a MAC sent by server.
|
||||
************************************************************/
|
||||
|
||||
static BOOL cli_temp_check_incoming_message(struct cli_state *cli)
|
||||
static BOOL cli_temp_check_incoming_message(char *inbuf, struct smb_sign_info *si)
|
||||
{
|
||||
return True;
|
||||
}
|
||||
@ -386,7 +400,7 @@ static BOOL cli_temp_check_incoming_message(struct cli_state *cli)
|
||||
SMB signing - TEMP implementation - free signing context
|
||||
************************************************************/
|
||||
|
||||
static void cli_temp_free_signing_context(struct cli_state *cli)
|
||||
static void cli_temp_free_signing_context(struct smb_sign_info *si)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -395,6 +409,15 @@ static void cli_temp_free_signing_context(struct cli_state *cli)
|
||||
SMB signing - NULL implementation - setup the MAC key.
|
||||
************************************************************/
|
||||
|
||||
BOOL cli_null_set_signing(struct cli_state *cli)
|
||||
{
|
||||
return null_set_signing(&cli->sign_info);
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
SMB signing - temp implementation - setup the MAC key.
|
||||
************************************************************/
|
||||
|
||||
BOOL cli_temp_set_signing(struct cli_state *cli)
|
||||
{
|
||||
if (!cli_set_smb_signing_common(cli)) {
|
||||
@ -410,16 +433,9 @@ BOOL cli_temp_set_signing(struct cli_state *cli)
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the signing context
|
||||
*/
|
||||
|
||||
void cli_free_signing_context(struct cli_state *cli)
|
||||
void cli_free_signing_context(struct cli_state *cli)
|
||||
{
|
||||
if (cli->sign_info.free_signing_context)
|
||||
cli->sign_info.free_signing_context(cli);
|
||||
|
||||
cli_null_set_signing(cli);
|
||||
free_signing_context(&cli->sign_info);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -428,7 +444,7 @@ void cli_free_signing_context(struct cli_state *cli)
|
||||
|
||||
void cli_calculate_sign_mac(struct cli_state *cli)
|
||||
{
|
||||
cli->sign_info.sign_outgoing_message(cli);
|
||||
cli->sign_info.sign_outgoing_message(cli->outbuf, &cli->sign_info);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -445,14 +461,14 @@ BOOL cli_check_sign_mac(struct cli_state *cli)
|
||||
DEBUG(cli->sign_info.doing_signing ? 1 : 10, ("Can't check signature on short packet! smb_len = %u\n", smb_len(cli->inbuf)));
|
||||
good = False;
|
||||
} else {
|
||||
good = cli->sign_info.check_incoming_message(cli);
|
||||
good = cli->sign_info.check_incoming_message(cli->inbuf, &cli->sign_info);
|
||||
}
|
||||
|
||||
if (!good) {
|
||||
if (cli->sign_info.doing_signing) {
|
||||
return False;
|
||||
} else {
|
||||
cli_free_signing_context(cli);
|
||||
free_signing_context(&cli->sign_info);
|
||||
}
|
||||
}
|
||||
|
||||
@ -479,3 +495,8 @@ BOOL srv_check_sign_mac(char *buf)
|
||||
void srv_calculate_sign_mac(char *buf)
|
||||
{
|
||||
}
|
||||
|
||||
BOOL allow_sendfile(void)
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
@ -292,6 +292,7 @@ typedef struct
|
||||
int restrict_anonymous;
|
||||
int name_cache_timeout;
|
||||
int client_signing;
|
||||
int server_signing;
|
||||
param_opt_struct *param_opt;
|
||||
}
|
||||
global;
|
||||
@ -693,15 +694,17 @@ static const struct enum_list enum_smb_signing_vals[] = {
|
||||
{False, "False"},
|
||||
{False, "0"},
|
||||
{False, "Off"},
|
||||
{False, "disabled"},
|
||||
{True, "Yes"},
|
||||
{True, "True"},
|
||||
{True, "1"},
|
||||
{True, "On"},
|
||||
{Required, "Required"},
|
||||
{Required, "Mandatory"},
|
||||
{Required, "Force"},
|
||||
{Required, "Forced"},
|
||||
{Required, "Enforced"},
|
||||
{True, "enabled"},
|
||||
{Required, "required"},
|
||||
{Required, "mandatory"},
|
||||
{Required, "force"},
|
||||
{Required, "forced"},
|
||||
{Required, "enforced"},
|
||||
{-1, NULL}
|
||||
};
|
||||
|
||||
@ -894,6 +897,7 @@ static struct parm_struct parm_table[] = {
|
||||
{"unix extensions", P_BOOL, P_GLOBAL, &Globals.bUnixExtensions, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER},
|
||||
{"use spnego", P_BOOL, P_GLOBAL, &Globals.bUseSpnego, NULL, NULL, FLAG_DEVELOPER},
|
||||
{"client signing", P_ENUM, P_GLOBAL, &Globals.client_signing, NULL, enum_smb_signing_vals, FLAG_ADVANCED | FLAG_DEVELOPER},
|
||||
{"server signing", P_ENUM, P_GLOBAL, &Globals.server_signing, NULL, enum_smb_signing_vals, FLAG_ADVANCED | FLAG_DEVELOPER},
|
||||
{"client use spnego", P_BOOL, P_GLOBAL, &Globals.bClientUseSpnego, NULL, NULL, FLAG_DEVELOPER},
|
||||
|
||||
{"Tuning Options", P_SEP, P_SEPARATOR},
|
||||
@ -1885,7 +1889,8 @@ FN_GLOBAL_INTEGER(lp_winbind_cache_time, &Globals.winbind_cache_time)
|
||||
FN_GLOBAL_BOOL(lp_hide_local_users, &Globals.bHideLocalUsers)
|
||||
FN_GLOBAL_INTEGER(lp_algorithmic_rid_base, &Globals.AlgorithmicRidBase)
|
||||
FN_GLOBAL_INTEGER(lp_name_cache_timeout, &Globals.name_cache_timeout)
|
||||
FN_GLOBAL_BOOL(lp_client_signing, &Globals.client_signing)
|
||||
FN_GLOBAL_INTEGER(lp_client_signing, &Globals.client_signing)
|
||||
FN_GLOBAL_INTEGER(lp_server_signing, &Globals.server_signing)
|
||||
|
||||
/* local prototypes */
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user