lib: Make sid_parse return the parsed length
[samba.git] / source4 / torture / unix / whoami.c
index 25f9b11beead6f42e4cc7cc3d66fbc2ecba8537a..f554c9e17114f0097a082fb38d226fd72fef260c 100644 (file)
@@ -5,7 +5,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
-#include "torture/torture.h"
-#include "torture/basic/proto.h"
 #include "libcli/libcli.h"
-#include "libcli/raw/interfaces.h"
+#include "libcli/raw/raw_proto.h"
+#include "torture/torture.h"
+#include "torture/unix/proto.h"
 #include "lib/cmdline/popt_common.h"
 #include "auth/credentials/credentials.h"
+#include "param/param.h"
+#include "libcli/resolve/resolve.h"
+#include <ldb.h>
+#include "lib/util/util_ldb.h"
+#include "ldb_wrap.h"
+#include "dsdb/samdb/samdb.h"
+#include "../libcli/security/security.h"
 
-#define SMB_QUERY_POSIX_WHOAMI     0x202
 
 /* Size (in bytes) of the required fields in the SMBwhoami response. */
 #define WHOAMI_REQUIRED_SIZE   40
 
-enum smb_whoami_flags {
-    SMB_WHOAMI_GUEST = 0x1 /* Logged in as (or squashed to) guest */
-};
-
 /*
    SMBWhoami - Query the user mapping performed by the server for the
    connected tree. This is a subcommand of the TRANS2_QFSINFO.
@@ -51,7 +52,7 @@ enum smb_whoami_flags {
        4 bytes -               pad / reserved (must be zero)
 
        8 bytes unsigned[] -    list of GIDs (may be empty)
-       DOM_SID[] -             list of SIDs (may be empty)
+       struct dom_sid[] -             list of SIDs (may be empty)
 */
 
 struct smb_whoami
@@ -68,28 +69,42 @@ struct smb_whoami
        struct dom_sid ** sid_list;
 };
 
-static struct smbcli_state *connect_to_server(void *mem_ctx)
+static struct smbcli_state *connect_to_server(struct torture_context *tctx,
+               struct cli_credentials *creds)
 {
        NTSTATUS status;
        struct smbcli_state *cli;
 
-       const char *host = lp_parm_string(-1, "torture", "host");
-       const char *share = lp_parm_string(-1, "torture", "share");
+       const char *host = torture_setting_string(tctx, "host", NULL);
+       const char *share = torture_setting_string(tctx, "share", NULL);
+       struct smbcli_options options;
+       struct smbcli_session_options session_options;
+
+       lpcfg_smbcli_options(tctx->lp_ctx, &options);
+       lpcfg_smbcli_session_options(tctx->lp_ctx, &session_options);
 
-       status = smbcli_full_connection(mem_ctx, &cli,
-                                       host, share, NULL,
-                                       cmdline_credentials, NULL);
+       status = smbcli_full_connection(tctx, &cli, host, 
+                                       lpcfg_smb_ports(tctx->lp_ctx),
+                                       share, NULL, lpcfg_socket_options(tctx->lp_ctx),
+                                       creds, lpcfg_resolve_context(tctx->lp_ctx),
+                                       tctx->ev, &options, &session_options,
+                                       lpcfg_gensec_settings(tctx, tctx->lp_ctx));
 
        if (!NT_STATUS_IS_OK(status)) {
-               printf("failed to connect to //%s/%s: %s\n",
-                       host, share, nt_errstr(status));
+               torture_comment(tctx,
+                               "FATAL: Failed to connect to //%s/%s "
+                               "with %s - %s\n",
+                               host,
+                               share,
+                               cli_credentials_get_username(creds),
+                               nt_errstr(status));
                return NULL;
        }
 
        return cli;
 }
 
-static BOOL sid_parse(void *mem_ctx,
+static bool whoami_sid_parse(void *mem_ctx,
                struct torture_context *torture,
                DATA_BLOB *data, size_t *offset,
                struct dom_sid **psid)
@@ -117,20 +132,15 @@ static BOOL sid_parse(void *mem_ctx,
        torture_assert(torture, (*psid)->num_auths <= 15,
                        "invalid sub_auth value");
 
-       (*psid)->sub_auths = talloc_array(mem_ctx, uint32_t,
-                       (*psid)->num_auths);
-       torture_assert(torture, (*psid)->sub_auths != NULL,
-                       "out of memory");
-
         for (i = 0; i < (*psid)->num_auths; i++) {
                 (*psid)->sub_auths[i] = IVAL(data->data, *offset);
                (*offset) += 4;
        }
 
-       return True;
+       return true;
 }
 
-static BOOL smb_raw_query_posix_whoami(void *mem_ctx,
+static bool smb_raw_query_posix_whoami(void *mem_ctx,
                                struct torture_context *torture,
                                struct smbcli_state *cli,
                                struct smb_whoami *whoami,
@@ -154,13 +164,13 @@ static BOOL smb_raw_query_posix_whoami(void *mem_ctx,
        tp.in.max_data = (uint16_t)max_data;
        tp.in.setup = &setup;
        tp.in.trans_name = NULL;
-       SSVAL(&info_level, 0, SMB_QUERY_POSIX_WHOAMI);
+       SSVAL(&info_level, 0, SMB_QFS_POSIX_WHOAMI);
        tp.in.params = data_blob_talloc(mem_ctx, &info_level, 2);
        tp.in.data = data_blob_talloc(mem_ctx, NULL, 0);
 
        status = smb_raw_trans2(cli->tree, mem_ctx, &tp);
        torture_assert_ntstatus_equal(torture, status, NT_STATUS_OK,
-                       "doing SMB_QUERY_POSIX_WHOAMI");
+                       "doing SMB_QFS_POSIX_WHOAMI");
 
        /* Make sure we got back all the required fields. */
        torture_assert(torture, tp.out.params.length == 0,
@@ -187,8 +197,8 @@ static BOOL smb_raw_query_posix_whoami(void *mem_ctx,
 
        printf("\tmapping_flags=0x%08x mapping_mask=0x%08x\n",
                        whoami->mapping_flags, whoami->mapping_mask);
-       printf("\tserver UID=%lld GID=%lld\n",
-                       whoami->server_uid, whoami->server_gid);
+       printf("\tserver UID=%llu GID=%llu\n",
+              (unsigned long long)whoami->server_uid, (unsigned long long)whoami->server_gid);
        printf("\t%u GIDs, %u SIDs, %u SID bytes\n",
                        whoami->num_gids, whoami->num_sids,
                        whoami->num_sid_bytes);
@@ -206,7 +216,7 @@ static BOOL smb_raw_query_posix_whoami(void *mem_ctx,
                                "invalid SID count");
                torture_assert_int_equal(torture, whoami->num_sid_bytes, 0,
                                "invalid SID byte count");
-               return True;
+               return true;
        }
 
        if (whoami->num_gids != 0) {
@@ -224,9 +234,12 @@ static BOOL smb_raw_query_posix_whoami(void *mem_ctx,
                whoami->gid_list = talloc_array(mem_ctx, uint64_t, whoami->num_gids);
                torture_assert(torture, whoami->gid_list != NULL, "out of memory");
 
+               torture_comment(torture, "\tGIDs:\n");
+               
                for (i = 0; i < whoami->num_gids; ++i) {
                        whoami->gid_list[i] = BVAL(tp.out.data.data, offset);
                        offset += 8;
+                       torture_comment(torture, "\t\t%u\n", (unsigned int)whoami->gid_list[i]);
                }
        }
 
@@ -234,7 +247,7 @@ static BOOL smb_raw_query_posix_whoami(void *mem_ctx,
        if (tp.out.data.length == offset) {
                torture_assert_int_equal(torture, whoami->num_sids, 0,
                                "invalid SID count");
-               return True;
+               return true;
        }
 
        /* All the remaining bytes must be the SID list. */
@@ -249,13 +262,17 @@ static BOOL smb_raw_query_posix_whoami(void *mem_ctx,
                torture_assert(torture, whoami->sid_list != NULL,
                                "out of memory");
 
+               torture_comment(torture, "\tSIDs:\n");
+
                for (i = 0; i < whoami->num_sids; ++i) {
-                       if (!sid_parse(mem_ctx, torture,
+                       if (!whoami_sid_parse(mem_ctx, torture,
                                        &tp.out.data, &offset,
                                        &whoami->sid_list[i])) {
-                               return False;
+                               return false;
                        }
 
+                       torture_comment(torture, "\t\t%s\n",
+                                       dom_sid_string(torture, whoami->sid_list[i]));
                }
        }
 
@@ -263,37 +280,138 @@ static BOOL smb_raw_query_posix_whoami(void *mem_ctx,
        torture_assert_int_equal(torture, tp.out.data.length, offset,
                        "trailing garbage bytes");
 
-       return True;
+       return true;
+}
+
+static bool test_against_ldap(struct torture_context *torture, struct ldb_context *ldb, bool is_dc, 
+                             struct smb_whoami *whoami)
+{
+       struct ldb_message *msg;
+       struct ldb_message_element *el;
+
+       const char *attrs[] = { "tokenGroups", NULL };
+       int i;
+
+       torture_assert_int_equal(torture, dsdb_search_one(ldb, torture, &msg, NULL, LDB_SCOPE_BASE, attrs, 0, NULL), LDB_SUCCESS, "searching for tokenGroups");
+       el = ldb_msg_find_element(msg, "tokenGroups");
+       torture_assert(torture, el, "obtaining tokenGroups");
+       torture_assert(torture, el->num_values > 0, "Number of SIDs from LDAP needs to be more than 0");
+       torture_assert(torture, whoami->num_sids > 0, "Number of SIDs from LDAP needs to be more than 0");
+       
+       if (is_dc) {
+               torture_assert_int_equal(torture, el->num_values, whoami->num_sids, "Number of SIDs from LDAP and number of SIDs from CIFS does not match!");
+               
+               for (i = 0; i < el->num_values; i++) {
+                       struct dom_sid *sid = talloc(torture, struct dom_sid);
+                       struct sid_parse_ret ret;
+                       torture_assert(torture, sid != NULL, "talloc failed");
+
+                       ret = sid_parse(el->values[i].data,
+                                       el->values[i].length, sid);
+                       torture_assert(torture,
+                                      ret.len != -1,
+                                      "sid parse failed");
+                       torture_assert_str_equal(torture, dom_sid_string(sid, sid), dom_sid_string(sid, whoami->sid_list[i]), "SID from LDAP and SID from CIFS does not match!");
+                       talloc_free(sid);
+               }
+       } else {
+               unsigned int num_domain_sids_dc = 0, num_domain_sids_member = 0;
+               struct dom_sid *user_sid = talloc(torture, struct dom_sid);
+               struct dom_sid *dom_sid = talloc(torture, struct dom_sid);
+               struct dom_sid *dc_sids = talloc_array(torture, struct dom_sid, el->num_values);
+               struct dom_sid *member_sids = talloc_array(torture, struct dom_sid, whoami->num_sids);
+               struct sid_parse_ret ret;
+               torture_assert(torture, user_sid != NULL, "talloc failed");
+               ret = sid_parse(el->values[0].data,
+                               el->values[0].length,
+                               user_sid);
+               torture_assert(torture,
+                              ret.len != -1,
+                              "sid parse failed");
+               torture_assert_ntstatus_equal(torture, dom_sid_split_rid(torture, user_sid, &dom_sid, NULL), NT_STATUS_OK, "failed to split domain SID from user SID");
+               for (i = 0; i < el->num_values; i++) {
+                       struct dom_sid *sid = talloc(dc_sids, struct dom_sid);
+                       torture_assert(torture, sid != NULL, "talloc failed");
+
+                       ret = sid_parse(el->values[i].data,
+                                       el->values[i].length,
+                                       sid);
+                       torture_assert(torture,
+                                      ret.len != -1,
+                                      "sid parse failed");
+                       if (dom_sid_in_domain(dom_sid, sid)) {
+                               dc_sids[num_domain_sids_dc] = *sid;
+                               num_domain_sids_dc++;
+                       }
+                       talloc_free(sid);
+               }
+
+               for (i = 0; i < whoami->num_sids; i++) {
+                       if (dom_sid_in_domain(dom_sid, whoami->sid_list[i])) {
+                               member_sids[num_domain_sids_member] = *whoami->sid_list[i];
+                               num_domain_sids_member++;
+                       }
+               }
+
+               torture_assert_int_equal(torture, num_domain_sids_dc, num_domain_sids_member, "Number of Domain SIDs from LDAP DC and number of SIDs from CIFS member does not match!");
+               for (i = 0; i < num_domain_sids_dc; i++) {
+                       torture_assert_str_equal(torture, dom_sid_string(dc_sids, &dc_sids[i]), dom_sid_string(member_sids, &member_sids[i]), "Domain SID from LDAP DC and SID from CIFS member server does not match!");
+               }
+               talloc_free(dc_sids);
+               talloc_free(member_sids);
+       }
+       return true;
 }
 
-BOOL torture_unix_whoami(struct torture_context *torture)
+bool torture_unix_whoami(struct torture_context *torture)
 {
        struct smbcli_state *cli;
        struct smb_whoami whoami;
-       void *mem_ctx;
+       bool ret = false;
+       struct ldb_context *ldb;
+       const char *addc, *host;
+
+       cli = connect_to_server(torture, popt_get_cmdline_credentials());
+       torture_assert(torture, cli, "connecting to server with authenticated credentials");
 
-       mem_ctx = talloc_init("smb_query_posix_whoami");
-       torture_assert(torture, mem_ctx != NULL, "malloc failed");
+       /* Test basic authenticated mapping. */
+       torture_assert_goto(torture, smb_raw_query_posix_whoami(torture, torture,
+                                                      cli, &whoami, 0xFFFF), ret, fail,
+                           "calling SMB_QFS_POSIX_WHOAMI on an authenticated connection");
 
-       if (!(cli = connect_to_server(mem_ctx))) {
-               goto fail;
+       /* Check that our anonymous login mapped us to guest on the server, but
+        * only if the server supports this.
+        */
+       if (whoami.mapping_mask & SMB_WHOAMI_GUEST) {
+               bool guest = whoami.mapping_flags & SMB_WHOAMI_GUEST;
+               torture_comment(torture, "checking whether we were logged in as guest... %s\n",
+                       guest ? "YES" : "NO");
+               torture_assert(torture,
+                       cli_credentials_is_anonymous(
+                               popt_get_cmdline_credentials()) == guest,
+                              "login did not credentials map to guest");
+       } else {
+               torture_comment(torture, "server does not support SMB_WHOAMI_GUEST flag\n");
        }
 
-       /* Test basic authenticated mapping. */
-       printf("calling SMB_QUERY_POSIX_WHOAMI on an authenticated connection\n");
-       if (!smb_raw_query_posix_whoami(mem_ctx, torture,
-                               cli, &whoami, 0xFFFF)) {
-               smbcli_tdis(cli);
-               goto fail;
+       addc = torture_setting_string(torture, "addc", NULL);
+       host = torture_setting_string(torture, "host", NULL);
+       
+       if (addc) {
+               ldb = ldb_wrap_connect(torture, torture->ev, torture->lp_ctx, talloc_asprintf(torture, "ldap://%s", addc),
+                                      NULL, popt_get_cmdline_credentials(), 0);
+               torture_assert(torture, ldb, "ldb connect failed");
+
+               /* We skip this testing if we could not contact the LDAP server */
+               if (!test_against_ldap(torture, ldb, strcasecmp(addc, host) == 0, &whoami)) {
+                       goto fail;
+               }
        }
 
        /* Test that the server drops the UID and GID list. */
-       printf("calling SMB_QUERY_POSIX_WHOAMI with a small buffer\n");
-       if (!smb_raw_query_posix_whoami(mem_ctx, torture,
-                               cli, &whoami, 0x40)) {
-               smbcli_tdis(cli);
-               goto fail;
-       }
+       torture_assert_goto(torture, smb_raw_query_posix_whoami(torture, torture,
+                                                 cli, &whoami, 0x40), ret, fail,
+                      "calling SMB_QFS_POSIX_WHOAMI with a small buffer\n");
 
        torture_assert_int_equal(torture, whoami.num_gids, 0,
                        "invalid GID count");
@@ -303,40 +421,12 @@ BOOL torture_unix_whoami(struct torture_context *torture)
                        "invalid SID bytes count");
 
        smbcli_tdis(cli);
-       cli_credentials_set_anonymous(cmdline_credentials);
-
-       if (!(cli = connect_to_server(mem_ctx))) {
-               goto fail;
-       }
-
-       printf("calling SMB_QUERY_POSIX_WHOAMI on an anonymous connection\n");
-       if (!smb_raw_query_posix_whoami(mem_ctx, torture,
-                               cli, &whoami, 0xFFFF)) {
-               smbcli_tdis(cli);
-               goto fail;
-       }
-
-       smbcli_tdis(cli);
-
-       /* Check that our anonymous login mapped us to guest on the server, but
-        * only if the server supports this.
-        */
-       if (whoami.mapping_mask & SMB_WHOAMI_GUEST) {
-               printf("checking whether we were logged in as guest... %s\n",
-                       whoami.mapping_flags & SMB_WHOAMI_GUEST ? "YES" : "NO");
-               torture_assert(torture, whoami.mapping_flags & SMB_WHOAMI_GUEST,
-                               "anonymous login did not map to guest");
-       } else {
-               printf("server does not support SMB_WHOAMI_GUEST flag\n");
-       }
-
-       talloc_free(mem_ctx);
-       return True;
 
+       return true;
 fail:
-       talloc_free(mem_ctx);
-       return False;
 
+       smbcli_tdis(cli);
+       return ret;
 }
 
 /* vim: set sts=8 sw=8 : */