From 6ab5e14494ed6b579658f4fe3410759582d909cd Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 16 Jul 2003 22:57:56 +0000 Subject: 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) --- source3/include/client.h | 12 --- source3/include/smb.h | 14 +++ source3/libsmb/cliconnect.c | 5 ++ source3/libsmb/smb_signing.c | 205 ++++++++++++++++++++++++------------------- source3/param/loadparm.c | 17 ++-- 5 files changed, 143 insertions(+), 110 deletions(-) diff --git a/source3/include/client.h b/source3/include/client.h index fad2c099b9..598e6c0bda 100644 --- a/source3/include/client.h +++ b/source3/include/client.h @@ -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; diff --git a/source3/include/smb.h b/source3/include/smb.h index d2714e78bc..85ee5cdfc6 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -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 */ diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 0dcc9e2845..49430616b3 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -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); diff --git a/source3/libsmb/smb_signing.c b/source3/libsmb/smb_signing.c index e18d1ed42a..683a382369 100644 --- a/source3/libsmb/smb_signing.c +++ b/source3/libsmb/smb_signing.c @@ -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; +} diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index dd429fa688..3739407810 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -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 */ -- cgit