s3:smb_signing: add support for easier negotiation of SMB signing
authorStefan Metzmacher <metze@samba.org>
Mon, 12 Sep 2011 07:04:53 +0000 (09:04 +0200)
committerStefan Metzmacher <metze@samba.org>
Wed, 14 Sep 2011 06:09:15 +0000 (08:09 +0200)
We don't make use of it yet, but it will follow.

metze

source3/include/smb_signing.h
source3/libsmb/clientgen.c
source3/libsmb/clisigning.c
source3/libsmb/smb_signing.c
source3/smbd/signing.c

index d2eda9b3e625b5e529f0007f91e9231b9d929ee6..481be1d50065f3dc9014b4575dbbbe46b4f5860e 100644 (file)
@@ -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_ */
index db5e5459193c09f26f9fc978c9d1eb5521157dfd..15e450a8029a0e54145e32f71d2c8e13e22645c4 100644 (file)
@@ -259,6 +259,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) {
index ac4db7626f5c4e526ac9633b80f784708e7d80c1..134938fc89194b88713879f3f0bc9f5fab6e0dd7 100644 (file)
@@ -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)
index c926b48e72504bf7c26ccd8ae73fe8d9a2c0dc82..ba207231faa389d604c3451985b50770e6f98f2f 100644 (file)
@@ -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;
 }
 
index 25b3c40d7d21957bc54779b21b5ada08e4b072f3..1ae8ffca367329e48c5fe8544fb968d542f29bf0 100644 (file)
@@ -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);
 }
 
 /***********************************************************