From 4349975e433a02f79a35d2bfd6c347a9eeea86cb Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 9 Sep 2011 22:44:44 +0200 Subject: [PATCH 1/4] s3:smbd: echo FLAGS2_SMB_SECURITY_SIGNATURES* and the signature field in the reply This matches what windows is doing. metze --- source3/smbd/process.c | 12 +++++++++--- 1 files changed, 9 insertions(+), 3 deletions(-) diff --git a/source3/smbd/process.c b/source3/smbd/process.c index a60d77e..deba86c 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -1674,15 +1674,21 @@ void remove_from_common_flags2(uint32 v) static void construct_reply_common(struct smb_request *req, const char *inbuf, char *outbuf) { + uint16_t in_flags2 = SVAL(inbuf,smb_flg2); + uint16_t out_flags2 = common_flags2; + + out_flags2 |= in_flags2 & FLAGS2_UNICODE_STRINGS; + out_flags2 |= in_flags2 & FLAGS2_SMB_SECURITY_SIGNATURES; + out_flags2 |= in_flags2 & FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED; + srv_set_message(outbuf,0,0,false); SCVAL(outbuf, smb_com, req->cmd); SIVAL(outbuf,smb_rcls,0); SCVAL(outbuf,smb_flg, FLAG_REPLY | (CVAL(inbuf,smb_flg) & FLAG_CASELESS_PATHNAMES)); - SSVAL(outbuf,smb_flg2, - (SVAL(inbuf,smb_flg2) & FLAGS2_UNICODE_STRINGS) | - common_flags2); + SSVAL(outbuf,smb_flg2, out_flags2); memset(outbuf+smb_pidhigh,'\0',(smb_tid-smb_pidhigh)); + memcpy(outbuf+smb_ss_field, inbuf+smb_ss_field, 8); SSVAL(outbuf,smb_tid,SVAL(inbuf,smb_tid)); SSVAL(outbuf,smb_pid,SVAL(inbuf,smb_pid)); -- 1.7.4.1 From bdeb6e07109ce762ff7d59b60c7a12d2b716f2e0 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 12 Sep 2011 09:04:53 +0200 Subject: [PATCH 2/4] s3:smb_signing: add support for easier negotiation of SMB signing We don't make use of it yet, but it will follow. metze --- source3/include/smb_signing.h | 5 ++- source3/libsmb/clientgen.c | 1 + source3/libsmb/clisigning.c | 4 +- source3/libsmb/smb_signing.c | 100 ++++++++++++++++++++++++++++------------- source3/smbd/signing.c | 10 +++- 5 files changed, 83 insertions(+), 37 deletions(-) diff --git a/source3/include/smb_signing.h b/source3/include/smb_signing.h index d2eda9b..481be1d 100644 --- a/source3/include/smb_signing.h +++ b/source3/include/smb_signing.h @@ -26,9 +26,11 @@ struct smb_signing_state; struct smb_signing_state *smb_signing_init(TALLOC_CTX *mem_ctx, bool allowed, + bool desired, bool mandatory); struct smb_signing_state *smb_signing_init_ex(TALLOC_CTX *mem_ctx, bool allowed, + bool desired, bool mandatory, void *(*alloc_fn)(TALLOC_CTX *, size_t), void (*free_fn)(TALLOC_CTX *, void *)); @@ -45,7 +47,8 @@ bool smb_signing_activate(struct smb_signing_state *si, bool smb_signing_is_active(struct smb_signing_state *si); bool smb_signing_is_allowed(struct smb_signing_state *si); bool smb_signing_is_mandatory(struct smb_signing_state *si); -bool smb_signing_set_negotiated(struct smb_signing_state *si); +bool smb_signing_set_negotiated(struct smb_signing_state *si, + bool allowed, bool mandatory); bool smb_signing_is_negotiated(struct smb_signing_state *si); #endif /* _SMB_SIGNING_H_ */ diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index f274dc0..91e2286 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -260,6 +260,7 @@ struct cli_state *cli_state_create(TALLOC_CTX *mem_ctx, /* initialise signing */ cli->signing_state = smb_signing_init(cli, allow_smb_signing, + allow_smb_signing, mandatory_signing); if (!cli->signing_state) { goto error; diff --git a/source3/libsmb/clisigning.c b/source3/libsmb/clisigning.c index ac4db76..134938f 100644 --- a/source3/libsmb/clisigning.c +++ b/source3/libsmb/clisigning.c @@ -44,7 +44,7 @@ bool cli_simple_set_signing(struct cli_state *cli, bool cli_temp_set_signing(struct cli_state *cli) { - return smb_signing_set_bsrspyl(cli->signing_state); + return true; } void cli_calculate_sign_mac(struct cli_state *cli, char *buf, uint32_t *seqnum) @@ -70,7 +70,7 @@ bool cli_check_sign_mac(struct cli_state *cli, const char *buf, uint32_t seqnum) void cli_set_signing_negotiated(struct cli_state *cli) { - smb_signing_set_negotiated(cli->signing_state); + smb_signing_set_negotiated(cli->signing_state, true, false); } bool client_is_signing_on(struct cli_state *cli) diff --git a/source3/libsmb/smb_signing.c b/source3/libsmb/smb_signing.c index c926b48..ba20723 100644 --- a/source3/libsmb/smb_signing.c +++ b/source3/libsmb/smb_signing.c @@ -29,15 +29,15 @@ struct smb_signing_state { /* is signing localy allowed */ bool allowed; + /* is signing localy desired */ + bool desired; + /* is signing localy mandatory */ bool mandatory; /* is signing negotiated by the peer */ bool negotiated; - /* send BSRSPYL signatures */ - bool bsrspyl; - bool active; /* Have I ever seen a validly signed packet? */ /* mac_key.length > 0 means signing is started */ @@ -54,7 +54,6 @@ struct smb_signing_state { static void smb_signing_reset_info(struct smb_signing_state *si) { si->active = false; - si->bsrspyl = false; si->seqnum = 0; if (si->free_fn) { @@ -68,6 +67,7 @@ static void smb_signing_reset_info(struct smb_signing_state *si) struct smb_signing_state *smb_signing_init_ex(TALLOC_CTX *mem_ctx, bool allowed, + bool desired, bool mandatory, void *(*alloc_fn)(TALLOC_CTX *, size_t), void (*free_fn)(TALLOC_CTX *, void *)) @@ -92,10 +92,15 @@ struct smb_signing_state *smb_signing_init_ex(TALLOC_CTX *mem_ctx, } if (mandatory) { + desired = true; + } + + if (desired) { allowed = true; } si->allowed = allowed; + si->desired = desired; si->mandatory = mandatory; return si; @@ -103,9 +108,11 @@ struct smb_signing_state *smb_signing_init_ex(TALLOC_CTX *mem_ctx, struct smb_signing_state *smb_signing_init(TALLOC_CTX *mem_ctx, bool allowed, + bool desired, bool mandatory) { - return smb_signing_init_ex(mem_ctx, allowed, mandatory, NULL, NULL); + return smb_signing_init_ex(mem_ctx, allowed, desired, mandatory, + NULL, NULL); } static bool smb_signing_good(struct smb_signing_state *si, @@ -210,10 +217,11 @@ void smb_signing_sign_pdu(struct smb_signing_state *si, uint8_t *outbuf, uint32_t seqnum) { uint8_t calc_md5_mac[16]; - uint16_t flags2; + uint8_t com; + uint8_t flags; if (si->mac_key.length == 0) { - if (!si->bsrspyl) { + if (!si->negotiated) { return; } } @@ -226,15 +234,32 @@ void smb_signing_sign_pdu(struct smb_signing_state *si, abort(); } - /* mark the packet as signed - BEFORE we sign it...*/ - flags2 = SVAL(outbuf,smb_flg2); - flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES; - SSVAL(outbuf, smb_flg2, flags2); + com = SVAL(outbuf,smb_com); + flags = SVAL(outbuf,smb_flg); + + if (!(flags & FLAG_REPLY)) { + uint16_t flags2 = SVAL(outbuf,smb_flg2); + /* + * If this is a request, specify what is + * supported or required by the client + */ + if (si->negotiated && si->desired) { + flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES; + } + if (si->negotiated && si->mandatory) { + flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED; + } + SSVAL(outbuf, smb_flg2, flags2); + } - if (si->bsrspyl) { + if (si->mac_key.length == 0) { /* I wonder what BSRSPYL stands for - but this is what MS actually sends! */ - memcpy(calc_md5_mac, "BSRSPYL ", 8); + if (com == SMBsesssetupX) { + memcpy(calc_md5_mac, "BSRSPYL ", 8); + } else { + memset(calc_md5_mac, 0, 8); + } } else { smb_signing_md5(&si->mac_key, outbuf, seqnum, calc_md5_mac); @@ -305,21 +330,6 @@ bool smb_signing_check_pdu(struct smb_signing_state *si, return smb_signing_good(si, good, seqnum); } -bool smb_signing_set_bsrspyl(struct smb_signing_state *si) -{ - if (!si->negotiated) { - return false; - } - - if (si->active) { - return false; - } - - si->bsrspyl = true; - - return true; -} - bool smb_signing_activate(struct smb_signing_state *si, const DATA_BLOB user_session_key, const DATA_BLOB response) @@ -398,14 +408,42 @@ bool smb_signing_is_mandatory(struct smb_signing_state *si) return si->mandatory; } -bool smb_signing_set_negotiated(struct smb_signing_state *si) +bool smb_signing_set_negotiated(struct smb_signing_state *si, + bool allowed, bool mandatory) { - if (!si->allowed) { + if (si->active) { + return true; + } + + if (!si->allowed && mandatory) { return false; } - si->negotiated = true; + if (si->mandatory && !allowed) { + return false; + } + + if (si->mandatory) { + si->negotiated = true; + return true; + } + + if (mandatory) { + si->negotiated = true; + return true; + } + + if (!si->desired) { + si->negotiated = false; + return true; + } + + if (si->desired && allowed) { + si->negotiated = true; + return true; + } + si->negotiated = false; return true; } diff --git a/source3/smbd/signing.c b/source3/smbd/signing.c index 25b3c40..1ae8ffc 100644 --- a/source3/smbd/signing.c +++ b/source3/smbd/signing.c @@ -157,6 +157,7 @@ static void smbd_shm_signing_free(TALLOC_CTX *mem_ctx, void *ptr) bool srv_init_signing(struct smbd_server_connection *conn) { bool allowed = true; + bool desired; bool mandatory = false; switch (lp_server_signing()) { @@ -172,6 +173,8 @@ bool srv_init_signing(struct smbd_server_connection *conn) break; } + desired = allowed; + if (lp_async_smb_echo_handler()) { struct smbd_shm_signing *s; @@ -189,7 +192,7 @@ bool srv_init_signing(struct smbd_server_connection *conn) } talloc_set_destructor(s, smbd_shm_signing_destructor); conn->smb1.signing_state = smb_signing_init_ex(s, - allowed, mandatory, + allowed, desired, mandatory, smbd_shm_signing_alloc, smbd_shm_signing_free); if (!conn->smb1.signing_state) { @@ -199,7 +202,7 @@ bool srv_init_signing(struct smbd_server_connection *conn) } conn->smb1.signing_state = smb_signing_init(server_event_context(), - allowed, mandatory); + allowed, desired, mandatory); if (!conn->smb1.signing_state) { return false; } @@ -209,7 +212,8 @@ bool srv_init_signing(struct smbd_server_connection *conn) void srv_set_signing_negotiated(struct smbd_server_connection *conn) { - smb_signing_set_negotiated(conn->smb1.signing_state); + smb_signing_set_negotiated(conn->smb1.signing_state, + true, false); } /*********************************************************** -- 1.7.4.1 From aff3f91516cf09a43107d3b47f5ca3312304af9d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 12 Sep 2011 09:16:27 +0200 Subject: [PATCH 3/4] s3:libsmb: make use of new advanded SMB signing metze --- source3/libsmb/cliconnect.c | 59 ++++++++++++++++++++---------------------- source3/libsmb/clientgen.c | 47 ++++++++++++++++++++++------------ source3/libsmb/clisigning.c | 11 +++----- source3/libsmb/proto.h | 4 +- 4 files changed, 64 insertions(+), 57 deletions(-) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index fd0536c..860d39d 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -943,7 +943,6 @@ static struct tevent_req *cli_session_setup_nt1_send( SMBsesskeygen_ntv1(nt_hash, session_key.data); #endif } - cli_temp_set_signing(cli); } else { /* pre-encrypted password supplied. Only used for security=server, can't do @@ -1441,8 +1440,6 @@ static struct tevent_req *cli_session_setup_kerberos_send( state->cli = cli; state->ads_status = ADS_SUCCESS; - cli_temp_set_signing(cli); - /* * Ok, this is cheating: spnego_gen_krb5_negTokenInit can block if * we have to acquire a ticket. To be fixed later :-) @@ -1587,8 +1584,6 @@ static struct tevent_req *cli_session_setup_ntlmssp_send( talloc_set_destructor( state, cli_session_setup_ntlmssp_state_destructor); - cli_temp_set_signing(cli); - status = ntlmssp_client_start(state, lp_netbios_name(), lp_workgroup(), @@ -2638,7 +2633,11 @@ static void cli_negprot_done(struct tevent_req *subreq) if (cli_state_protocol(cli) >= PROTOCOL_NT1) { struct timespec ts; - bool negotiated_smb_signing = false; + const char *client_signing = NULL; + bool server_mandatory; + bool server_allowed; + const char *server_signing = NULL; + bool ok; /* NT protocol */ cli->sec_mode = CVAL(vwv + 1, 0); @@ -2668,35 +2667,33 @@ static void cli_negprot_done(struct tevent_req *subreq) } } - /* - * As signing is slow we only turn it on if either the client or - * the server require it. JRA. - */ + client_signing = "disabled"; + if (client_is_signing_allowed(cli)) { + client_signing = "allowed"; + } + if (client_is_signing_mandatory(cli)) { + client_signing = "required"; + } + server_signing = "not supported"; + if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) { + server_signing = "supported"; + server_allowed = true; + } if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) { - /* Fail if server says signing is mandatory and we don't want to support it. */ - if (!client_is_signing_allowed(cli)) { - DEBUG(0,("cli_negprot: SMB signing is mandatory and we have disabled it.\n")); - tevent_req_nterror(req, - NT_STATUS_ACCESS_DENIED); - return; - } - negotiated_smb_signing = true; - } else if (client_is_signing_mandatory(cli) && client_is_signing_allowed(cli)) { - /* Fail if client says signing is mandatory and the server doesn't support it. */ - if (!(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) { - DEBUG(1,("cli_negprot: SMB signing is mandatory and the server doesn't support it.\n")); - tevent_req_nterror(req, - NT_STATUS_ACCESS_DENIED); - return; - } - negotiated_smb_signing = true; - } else if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) { - negotiated_smb_signing = true; + server_signing = "required"; + server_mandatory = true; } - if (negotiated_smb_signing) { - cli_set_signing_negotiated(cli); + ok = cli_set_signing_negotiated(cli, + server_allowed, + server_mandatory); + if (!ok) { + DEBUG(1,("cli_negprot: SMB signing is required, " + "but client[%s] and server[%s] mismatch\n", + client_signing, server_signing)); + tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); + return; } } else if (cli_state_protocol(cli) >= PROTOCOL_LANMAN1) { diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 91e2286..bae80ef 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -168,8 +168,9 @@ struct cli_state *cli_state_create(TALLOC_CTX *mem_ctx, int signing_state, int flags) { struct cli_state *cli = NULL; - bool allow_smb_signing = false; - bool mandatory_signing = false; + bool allow_smb_signing; + bool desire_smb_signing; + bool mandatory_signing; socklen_t ss_length; int ret; @@ -236,31 +237,43 @@ struct cli_state *cli_state_create(TALLOC_CTX *mem_ctx, cli->use_level_II_oplocks = true; } - if (lp_client_signing()) { - allow_smb_signing = true; - } - - if (lp_client_signing() == Required) { - mandatory_signing = true; - } - - if (signing_state != Undefined) { - allow_smb_signing = true; + if (signing_state == Undefined) { + signing_state = lp_client_signing(); } - if (signing_state == false) { + switch (signing_state) { + case false: + /* never */ allow_smb_signing = false; + desire_smb_signing = false; mandatory_signing = false; - } - - if (signing_state == Required) { + break; + case true: + /* if the server supports it */ + allow_smb_signing = true; + desire_smb_signing = true; + mandatory_signing = false; + break; + default: + case Undefined: + case Auto: + /* if the server requires it */ + allow_smb_signing = true; + desire_smb_signing = false; + mandatory_signing = false; + break; + case Required: + /* always */ + allow_smb_signing = true; + desire_smb_signing = true; mandatory_signing = true; + break; } /* initialise signing */ cli->signing_state = smb_signing_init(cli, allow_smb_signing, - allow_smb_signing, + desire_smb_signing, mandatory_signing); if (!cli->signing_state) { goto error; diff --git a/source3/libsmb/clisigning.c b/source3/libsmb/clisigning.c index 134938f..acdc24f 100644 --- a/source3/libsmb/clisigning.c +++ b/source3/libsmb/clisigning.c @@ -42,11 +42,6 @@ bool cli_simple_set_signing(struct cli_state *cli, return true; } -bool cli_temp_set_signing(struct cli_state *cli) -{ - return true; -} - void cli_calculate_sign_mac(struct cli_state *cli, char *buf, uint32_t *seqnum) { *seqnum = smb_signing_next_seqnum(cli->signing_state, false); @@ -68,9 +63,11 @@ bool cli_check_sign_mac(struct cli_state *cli, const char *buf, uint32_t seqnum) return true; } -void cli_set_signing_negotiated(struct cli_state *cli) +bool cli_set_signing_negotiated(struct cli_state *cli, + bool allowed, bool mandatory) { - smb_signing_set_negotiated(cli->signing_state, true, false); + return smb_signing_set_negotiated(cli->signing_state, + allowed, mandatory); } bool client_is_signing_on(struct cli_state *cli) diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h index 83da457..7acc13c 100644 --- a/source3/libsmb/proto.h +++ b/source3/libsmb/proto.h @@ -859,13 +859,13 @@ void cli_free_enc_buffer(struct cli_state *cli, char *buf); bool cli_simple_set_signing(struct cli_state *cli, const DATA_BLOB user_session_key, const DATA_BLOB response); -bool cli_temp_set_signing(struct cli_state *cli); void cli_calculate_sign_mac(struct cli_state *cli, char *buf, uint32_t *seqnum); bool cli_check_sign_mac(struct cli_state *cli, const char *buf, uint32_t seqnum); bool client_is_signing_on(struct cli_state *cli); bool client_is_signing_allowed(struct cli_state *cli); bool client_is_signing_mandatory(struct cli_state *cli); -void cli_set_signing_negotiated(struct cli_state *cli); +bool cli_set_signing_negotiated(struct cli_state *cli, + bool allowed, bool mandatory); /* The following definitions come from libsmb/reparse_symlink.c */ -- 1.7.4.1 From c7188c18a38613d927b7e745a7359a20ed878b49 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 12 Sep 2011 09:19:06 +0200 Subject: [PATCH 4/4] s3:smbd: make use of better SMB signing negotiation metze --- source3/smbd/negprot.c | 1 - source3/smbd/proto.h | 3 ++- source3/smbd/sesssetup.c | 18 ++++++++++++++++++ source3/smbd/signing.c | 13 +++++++++++-- 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c index 71e0291..89ef52c 100644 --- a/source3/smbd/negprot.c +++ b/source3/smbd/negprot.c @@ -375,7 +375,6 @@ static void reply_nt1(struct smb_request *req, uint16 choice) capabilities &= ~CAP_RAW_MODE; if (lp_server_signing() == Required) secword |=NEGOTIATE_SECURITY_SIGNATURES_REQUIRED; - srv_set_signing_negotiated(sconn); } else { DEBUG(0,("reply_nt1: smb signing is incompatible with share level security !\n")); if (lp_server_signing() == Required) { diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index 8edd695..3d0665d 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -54,7 +54,8 @@ void srv_calculate_sign_mac(struct smbd_server_connection *conn, char *outbuf, uint32_t seqnum); void srv_cancel_sign_response(struct smbd_server_connection *conn); bool srv_init_signing(struct smbd_server_connection *conn); -void srv_set_signing_negotiated(struct smbd_server_connection *conn); +void srv_set_signing_negotiated(struct smbd_server_connection *conn, + bool allowed, bool mandatory); bool srv_is_signing_active(struct smbd_server_connection *conn); bool srv_is_signing_negotiated(struct smbd_server_connection *conn); void srv_set_signing(struct smbd_server_connection *conn, diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index 6dc8609..28ae24e9 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -1306,6 +1306,8 @@ void reply_sesssetup_and_X(struct smb_request *req) struct smbd_server_connection *sconn = req->sconn; bool doencrypt = sconn->smb1.negprot.encrypted_passwords; + bool signing_allowed = false; + bool signing_mandatory = false; START_PROFILE(SMBsesssetupX); @@ -1315,6 +1317,22 @@ void reply_sesssetup_and_X(struct smb_request *req) DEBUG(3,("wct=%d flg2=0x%x\n", req->wct, req->flags2)); + if (req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES) { + signing_allowed = true; + } + if (req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED) { + signing_mandatory = true; + } + + /* + * We can call srv_set_signing_negotiated() each time. + * It finds out when it needs to turn into a noop + * itself. + */ + srv_set_signing_negotiated(req->sconn, + signing_allowed, + signing_mandatory); + /* a SPNEGO session setup has 12 command words, whereas a normal NT1 session setup has 13. See the cifs spec. */ if (req->wct == 12 && diff --git a/source3/smbd/signing.c b/source3/smbd/signing.c index 1ae8ffc..bdf920c 100644 --- a/source3/smbd/signing.c +++ b/source3/smbd/signing.c @@ -173,6 +173,14 @@ bool srv_init_signing(struct smbd_server_connection *conn) break; } + /* + * if the client and server allow signing, + * we desire to use it. + * + * This matches Windows behavior and is needed + * because not every client that requires signing + * sends FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED. + */ desired = allowed; if (lp_async_smb_echo_handler()) { @@ -210,10 +218,11 @@ bool srv_init_signing(struct smbd_server_connection *conn) return true; } -void srv_set_signing_negotiated(struct smbd_server_connection *conn) +void srv_set_signing_negotiated(struct smbd_server_connection *conn, + bool allowed, bool mandatory) { smb_signing_set_negotiated(conn->smb1.signing_state, - true, false); + allowed, mandatory); } /*********************************************************** -- 1.7.4.1