diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
commit | 8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch) | |
tree | 4099e8021376c7d8c05bdf8503093d80e9c7bad0 /source4/torture/winbind | |
parent | Initial commit. (diff) | |
download | samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip |
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'source4/torture/winbind')
-rw-r--r-- | source4/torture/winbind/struct_based.c | 1190 | ||||
-rw-r--r-- | source4/torture/winbind/winbind.c | 335 | ||||
-rw-r--r-- | source4/torture/winbind/wscript_build | 10 |
3 files changed, 1535 insertions, 0 deletions
diff --git a/source4/torture/winbind/struct_based.c b/source4/torture/winbind/struct_based.c new file mode 100644 index 0000000..1c8751e --- /dev/null +++ b/source4/torture/winbind/struct_based.c @@ -0,0 +1,1190 @@ +/* + Unix SMB/CIFS implementation. + SMB torture tester - winbind struct based protocol + Copyright (C) Stefan Metzmacher 2007 + Copyright (C) Michael Adam 2007 + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "torture/torture.h" +#include "nsswitch/libwbclient/wbclient.h" +#include "nsswitch/winbind_nss_config.h" +#include "nsswitch/winbind_struct_protocol.h" +#include "nsswitch/libwbclient/wbclient_internal.h" +#include "libcli/security/security.h" +#include "librpc/gen_ndr/netlogon.h" +#include "param/param.h" +#include "../libcli/auth/pam_errors.h" +#include "torture/winbind/proto.h" +#include "lib/util/string_wrappers.h" + +#define DO_STRUCT_REQ_REP_EXT(op,req,rep,expected,strict,warnaction,cmt) do { \ + const char *__cmt = (cmt); \ + wbcErr __wbc_status = WBC_ERR_UNKNOWN_FAILURE; \ + NSS_STATUS __got, __expected = (expected); \ + __wbc_status = wbcRequestResponse(NULL, op, req, rep); \ + switch (__wbc_status) { \ + case WBC_ERR_SUCCESS: \ + __got = NSS_STATUS_SUCCESS; \ + break; \ + case WBC_ERR_WINBIND_NOT_AVAILABLE: \ + __got = NSS_STATUS_UNAVAIL; \ + break; \ + case WBC_ERR_DOMAIN_NOT_FOUND: \ + __got = NSS_STATUS_NOTFOUND; \ + break; \ + default: \ + torture_result(torture, TORTURE_FAIL, \ + __location__ ": " __STRING(op) \ + " returned unmapped %s, expected nss %d%s%s", \ + wbcErrorString(__wbc_status), __expected, \ + (__cmt) ? ": " : "", \ + (__cmt) ? (__cmt) : ""); \ + return false; \ + } \ + if (__got != __expected) { \ + if (strict) { \ + torture_result(torture, TORTURE_FAIL, \ + __location__ ": " __STRING(op) \ + " returned %s, got %d , expected %d%s%s", \ + wbcErrorString(__wbc_status), __got, __expected, \ + (__cmt) ? ": " : "", \ + (__cmt) ? (__cmt) : ""); \ + return false; \ + } else { \ + torture_warning(torture, \ + __location__ ": " __STRING(op) \ + " returned %s, got %d , expected %d%s%s", \ + wbcErrorString(__wbc_status), __got, __expected, \ + (__cmt) ? ": " : "", \ + (__cmt) ? (__cmt) : ""); \ + warnaction; \ + } \ + } \ +} while(0) + +#undef _STRUCT_NOOP +#define _STRUCT_NOOP do {} while(0); +#define DO_STRUCT_REQ_REP(op,req,rep) do { \ + DO_STRUCT_REQ_REP_EXT(op,req,rep,NSS_STATUS_SUCCESS,true, _STRUCT_NOOP, NULL); \ +} while (0) + +static bool torture_winbind_struct_interface_version(struct torture_context *torture) +{ + struct winbindd_request req; + struct winbindd_response rep; + + ZERO_STRUCT(req); + ZERO_STRUCT(rep); + + torture_comment(torture, "Running WINBINDD_INTERFACE_VERSION (struct based)\n"); + + DO_STRUCT_REQ_REP(WINBINDD_INTERFACE_VERSION, &req, &rep); + + torture_assert_int_equal(torture, + rep.data.interface_version, + WINBIND_INTERFACE_VERSION, + "winbind server and client doesn't match"); + + return true; +} + +static bool torture_winbind_struct_ping(struct torture_context *torture) +{ + struct timeval tv = timeval_current(); + int timelimit = torture_setting_int(torture, "timelimit", 5); + uint32_t total = 0; + + torture_comment(torture, + "Running WINBINDD_PING (struct based) for %d seconds\n", + timelimit); + + while (timeval_elapsed(&tv) < timelimit) { + DO_STRUCT_REQ_REP(WINBINDD_PING, NULL, NULL); + total++; + } + + torture_comment(torture, + "%u (%.1f/s) WINBINDD_PING (struct based)\n", + total, total / timeval_elapsed(&tv)); + + return true; +} + + +static char winbind_separator(struct torture_context *torture) +{ + struct winbindd_response rep; + + ZERO_STRUCT(rep); + + DO_STRUCT_REQ_REP(WINBINDD_INFO, NULL, &rep); + + return rep.data.info.winbind_separator; +} + +static bool torture_winbind_struct_info(struct torture_context *torture) +{ + struct winbindd_response rep; + const char *separator; + + ZERO_STRUCT(rep); + + torture_comment(torture, "Running WINBINDD_INFO (struct based)\n"); + + DO_STRUCT_REQ_REP(WINBINDD_INFO, NULL, &rep); + + separator = torture_setting_string(torture, + "winbindd_separator", + lpcfg_winbind_separator(torture->lp_ctx)); + + torture_assert_int_equal(torture, + rep.data.info.winbind_separator, + *separator, + "winbind separator doesn't match"); + + torture_comment(torture, "Samba Version '%s'\n", + rep.data.info.samba_version); + + return true; +} + +static bool torture_winbind_struct_priv_pipe_dir(struct torture_context *torture) +{ + struct winbindd_response rep; + const char *got_dir; + + ZERO_STRUCT(rep); + + torture_comment(torture, "Running WINBINDD_PRIV_PIPE_DIR (struct based)\n"); + + DO_STRUCT_REQ_REP(WINBINDD_PRIV_PIPE_DIR, NULL, &rep); + + got_dir = (const char *)rep.extra_data.data; + + torture_assert(torture, got_dir, "NULL WINBINDD_PRIV_PIPE_DIR\n"); + + SAFE_FREE(rep.extra_data.data); + return true; +} + +static bool torture_winbind_struct_netbios_name(struct torture_context *torture) +{ + struct winbindd_response rep; + const char *expected; + + ZERO_STRUCT(rep); + + torture_comment(torture, "Running WINBINDD_NETBIOS_NAME (struct based)\n"); + + DO_STRUCT_REQ_REP(WINBINDD_NETBIOS_NAME, NULL, &rep); + + expected = torture_setting_string(torture, + "winbindd_netbios_name", + lpcfg_netbios_name(torture->lp_ctx)); + expected = strupper_talloc(torture, expected); + + torture_assert_str_equal(torture, + rep.data.netbios_name, expected, + "winbindd's netbios name doesn't match"); + + return true; +} + +static bool get_winbind_domain(struct torture_context *torture, char **domain) +{ + struct winbindd_response rep; + + ZERO_STRUCT(rep); + + DO_STRUCT_REQ_REP(WINBINDD_DOMAIN_NAME, NULL, &rep); + + *domain = talloc_strdup(torture, rep.data.domain_name); + torture_assert(torture, domain, "talloc error"); + + return true; +} + +static bool torture_winbind_struct_domain_name(struct torture_context *torture) +{ + const char *expected; + char *domain; + + torture_comment(torture, "Running WINBINDD_DOMAIN_NAME (struct based)\n"); + + expected = torture_setting_string(torture, + "winbindd_netbios_domain", + lpcfg_workgroup(torture->lp_ctx)); + + get_winbind_domain(torture, &domain); + + torture_assert_str_equal(torture, domain, expected, + "winbindd's netbios domain doesn't match"); + + return true; +} + +static bool torture_winbind_struct_check_machacc(struct torture_context *torture) +{ + bool ok; + bool strict = torture_setting_bool(torture, "strict mode", false); + struct winbindd_response rep; + + ZERO_STRUCT(rep); + + torture_comment(torture, "Running WINBINDD_CHECK_MACHACC (struct based)\n"); + + ok = true; + DO_STRUCT_REQ_REP_EXT(WINBINDD_CHECK_MACHACC, NULL, &rep, + NSS_STATUS_SUCCESS, strict, ok = false, + "WINBINDD_CHECK_MACHACC"); + + if (!ok) { + torture_assert(torture, + strlen(rep.data.auth.nt_status_string)>0, + "Failed with empty nt_status_string"); + + torture_warning(torture,"%s:%s:%s:%d\n", + nt_errstr(NT_STATUS(rep.data.auth.nt_status)), + rep.data.auth.nt_status_string, + rep.data.auth.error_string, + rep.data.auth.pam_error); + return true; + } + + torture_assert_ntstatus_ok(torture, + NT_STATUS(rep.data.auth.nt_status), + "WINBINDD_CHECK_MACHACC ok: nt_status"); + + torture_assert_str_equal(torture, + rep.data.auth.nt_status_string, + nt_errstr(NT_STATUS_OK), + "WINBINDD_CHECK_MACHACC ok:nt_status_string"); + + torture_assert_str_equal(torture, + rep.data.auth.error_string, + get_friendly_nt_error_msg(NT_STATUS_OK), + "WINBINDD_CHECK_MACHACC ok: error_string"); + + torture_assert_int_equal(torture, + rep.data.auth.pam_error, + nt_status_to_pam(NT_STATUS_OK), + "WINBINDD_CHECK_MACHACC ok: pam_error"); + + return true; +} + +struct torture_trust_domain { + const char *netbios_name; + const char *dns_name; + struct dom_sid *sid; +}; + +static bool get_trusted_domains(struct torture_context *torture, + struct torture_trust_domain **_d) +{ + struct winbindd_request req; + struct winbindd_response rep; + struct torture_trust_domain *d = NULL; + uint32_t dcount = 0; + char line[256]; + const char *extra_data; + + ZERO_STRUCT(req); + ZERO_STRUCT(rep); + + DO_STRUCT_REQ_REP(WINBINDD_LIST_TRUSTDOM, &req, &rep); + + extra_data = (char *)rep.extra_data.data; + torture_assert(torture, extra_data != NULL, + "Trust list was NULL: the list of trusted domain " + "should be returned, with at least 2 entries " + "(BUILTIN, and the local domain)"); + + while (next_token(&extra_data, line, "\n", sizeof(line))) { + char *p, *lp; + + d = talloc_realloc(torture, d, + struct torture_trust_domain, + dcount + 2); + ZERO_STRUCT(d[dcount+1]); + + lp = line; + p = strchr(lp, '\\'); + torture_assert(torture, p, "missing 1st '\\' in line"); + *p = 0; + d[dcount].netbios_name = talloc_strdup(d, lp); + torture_assert(torture, strlen(d[dcount].netbios_name) > 0, + "empty netbios_name"); + + lp = p+1; + p = strchr(lp, '\\'); + torture_assert(torture, p, "missing 2nd '\\' in line"); + *p = 0; + d[dcount].dns_name = talloc_strdup(d, lp); + /* it's ok to have an empty dns_name */ + + lp = p+1; + d[dcount].sid = dom_sid_parse_talloc(d, lp); + torture_assert(torture, d[dcount].sid, + "failed to parse sid"); + + dcount++; + } + SAFE_FREE(rep.extra_data.data); + + torture_assert(torture, dcount >= 2, + "The list of trusted domain should contain 2 entries " + "(BUILTIN, and the local domain)"); + + *_d = d; + return true; +} + +static bool torture_winbind_struct_list_trustdom(struct torture_context *torture) +{ + struct winbindd_request req; + struct winbindd_response rep; + char *list1; + char *list2; + bool ok; + struct torture_trust_domain *listd = NULL; + uint32_t i; + + torture_comment(torture, "Running WINBINDD_LIST_TRUSTDOM (struct based)\n"); + + ZERO_STRUCT(req); + ZERO_STRUCT(rep); + + req.data.list_all_domains = false; + + DO_STRUCT_REQ_REP(WINBINDD_LIST_TRUSTDOM, &req, &rep); + + list1 = (char *)rep.extra_data.data; + + torture_comment(torture, "%s\n", list1); + + ZERO_STRUCT(req); + ZERO_STRUCT(rep); + + req.data.list_all_domains = true; + + DO_STRUCT_REQ_REP(WINBINDD_LIST_TRUSTDOM, &req, &rep); + + list2 = (char *)rep.extra_data.data; + + /* + * The list_all_domains parameter should be ignored + */ + torture_assert_str_equal(torture, list2, list1, "list_all_domains not ignored"); + + SAFE_FREE(list1); + SAFE_FREE(list2); + + ok = get_trusted_domains(torture, &listd); + torture_assert(torture, ok, "failed to get trust list"); + + for (i=0; listd && listd[i].netbios_name; i++) { + if (i == 0) { + struct dom_sid *builtin_sid; + + builtin_sid = dom_sid_parse_talloc(torture, SID_BUILTIN); + + torture_assert_str_equal(torture, + listd[i].netbios_name, + NAME_BUILTIN, + "first domain should be 'BUILTIN'"); + + torture_assert_str_equal(torture, + listd[i].dns_name, + "", + "BUILTIN domain should not have a dns name"); + + ok = dom_sid_equal(builtin_sid, + listd[i].sid); + torture_assert(torture, ok, "BUILTIN domain should have S-1-5-32"); + + continue; + } + + /* + * TODO: verify the content of the 2nd and 3rd (in member server mode) + * domain entries + */ + } + + return true; +} + +static bool torture_winbind_struct_domain_info(struct torture_context *torture) +{ + bool ok; + struct torture_trust_domain *listd = NULL; + uint32_t i; + + torture_comment(torture, "Running WINBINDD_DOMAIN_INFO (struct based)\n"); + + ok = get_trusted_domains(torture, &listd); + torture_assert(torture, ok, "failed to get trust list"); + + for (i=0; listd && listd[i].netbios_name; i++) { + torture_comment(torture, "LIST[%u] '%s' => '%s' [%s]\n", + (unsigned)i, + listd[i].netbios_name, + listd[i].dns_name, + dom_sid_string(torture, listd[i].sid)); + } + + for (i=0; listd && listd[i].netbios_name; i++) { + struct winbindd_request req; + struct winbindd_response rep; + struct dom_sid *sid; + char *flagstr = talloc_strdup(torture," "); + + ZERO_STRUCT(req); + ZERO_STRUCT(rep); + + fstrcpy(req.domain_name, listd[i].netbios_name); + + DO_STRUCT_REQ_REP(WINBINDD_DOMAIN_INFO, &req, &rep); + + if (rep.data.domain_info.primary) { + flagstr = talloc_strdup_append(flagstr, "PR "); + } + + if (rep.data.domain_info.active_directory) { + torture_assert(torture, + strlen(rep.data.domain_info.alt_name)>0, + "Active Directory without DNS name"); + flagstr = talloc_strdup_append(flagstr, "AD "); + } + + if (rep.data.domain_info.native_mode) { + torture_assert(torture, + rep.data.domain_info.active_directory, + "Native-Mode, but no Active Directory"); + flagstr = talloc_strdup_append(flagstr, "NA "); + } + + torture_comment(torture, "DOMAIN[%u] '%s' => '%s' [%s] [%s]\n", + (unsigned)i, + rep.data.domain_info.name, + rep.data.domain_info.alt_name, + flagstr, + rep.data.domain_info.sid); + + sid = dom_sid_parse_talloc(torture, rep.data.domain_info.sid); + torture_assert(torture, sid, "Failed to parse SID"); + + ok = dom_sid_equal(listd[i].sid, sid); + torture_assert(torture, ok, talloc_asprintf(torture, "SID's doesn't match [%s] != [%s]", + dom_sid_string(torture, listd[i].sid), + dom_sid_string(torture, sid))); + + torture_assert_str_equal(torture, + rep.data.domain_info.name, + listd[i].netbios_name, + "Netbios domain name doesn't match"); + + torture_assert_str_equal(torture, + rep.data.domain_info.alt_name, + listd[i].dns_name, + "DNS domain name doesn't match"); + } + + return true; +} + +static bool torture_winbind_struct_getdcname(struct torture_context *torture) +{ + bool ok; + bool strict = torture_setting_bool(torture, "strict mode", false); + const char *domain_name = torture_setting_string(torture, + "winbindd_netbios_domain", + lpcfg_workgroup(torture->lp_ctx)); + struct torture_trust_domain *listd = NULL; + uint32_t i, count = 0; + + torture_comment(torture, "Running WINBINDD_GETDCNAME (struct based)\n"); + + ok = get_trusted_domains(torture, &listd); + torture_assert(torture, ok, "failed to get trust list"); + + for (i=0; listd && listd[i].netbios_name; i++) { + struct winbindd_request req; + struct winbindd_response rep; + + /* getdcname is not expected to work on "BUILTIN" or our own + * domain */ + if (strequal(listd[i].netbios_name, "BUILTIN") || + strequal(listd[i].netbios_name, domain_name)) { + continue; + } + + ZERO_STRUCT(req); + ZERO_STRUCT(rep); + + fstrcpy(req.domain_name, listd[i].netbios_name); + + ok = true; + DO_STRUCT_REQ_REP_EXT(WINBINDD_GETDCNAME, &req, &rep, + NSS_STATUS_SUCCESS, + (i <2 || strict), ok = false, + talloc_asprintf(torture, "DOMAIN '%s'", + req.domain_name)); + if (!ok) continue; + + /* TODO: check rep.data.dc_name; */ + torture_comment(torture, "DOMAIN '%s' => DCNAME '%s'\n", + req.domain_name, rep.data.dc_name); + count++; + } + + if (strict) { + torture_assert(torture, count > 0, + "WiNBINDD_GETDCNAME was not tested"); + } + return true; +} + +static bool torture_winbind_struct_dsgetdcname(struct torture_context *torture) +{ + bool ok; + bool strict = torture_setting_bool(torture, "strict mode", false); + struct torture_trust_domain *listd = NULL; + uint32_t i; + uint32_t count = 0; + + torture_comment(torture, "Running WINBINDD_DSGETDCNAME (struct based)\n"); + + ok = get_trusted_domains(torture, &listd); + torture_assert(torture, ok, "failed to get trust list"); + + for (i=0; listd && listd[i].netbios_name; i++) { + struct winbindd_request req; + struct winbindd_response rep; + + ZERO_STRUCT(req); + ZERO_STRUCT(rep); + + if (strlen(listd[i].dns_name) == 0) continue; + + /* + * TODO: remove this and let winbindd give no dns name + * for NT4 domains + */ + if (strcmp(listd[i].dns_name, listd[i].netbios_name) == 0) { + continue; + } + + fstrcpy(req.domain_name, listd[i].dns_name); + + /* TODO: test more flag combinations */ + req.flags = DS_DIRECTORY_SERVICE_REQUIRED; + + ok = true; + DO_STRUCT_REQ_REP_EXT(WINBINDD_DSGETDCNAME, &req, &rep, + NSS_STATUS_SUCCESS, + strict, ok = false, + talloc_asprintf(torture, "DOMAIN '%s'", + req.domain_name)); + if (!ok) continue; + + /* TODO: check rep.data.dc_name; */ + torture_comment(torture, "DOMAIN '%s' => DCNAME '%s'\n", + req.domain_name, rep.data.dc_name); + + count++; + } + + if (count == 0) { + torture_warning(torture, "WINBINDD_DSGETDCNAME" + " was not tested with %d non-AD domains", + i); + } + + if (strict) { + torture_assert(torture, count > 0, + "WiNBINDD_DSGETDCNAME was not tested"); + } + + return true; +} + +static bool get_user_list(struct torture_context *torture, char ***users) +{ + struct winbindd_request req; + struct winbindd_response rep; + char **u = NULL; + uint32_t count; + char name[256]; + const char *extra_data; + + ZERO_STRUCT(req); + ZERO_STRUCT(rep); + + DO_STRUCT_REQ_REP(WINBINDD_LIST_USERS, &req, &rep); + + extra_data = (char *)rep.extra_data.data; + torture_assert(torture, extra_data, "NULL extra data"); + + for(count = 0; + next_token(&extra_data, name, ",", sizeof(name)); + count++) + { + u = talloc_realloc(torture, u, char *, count + 2); + u[count+1] = NULL; + u[count] = talloc_strdup(u, name); + } + + SAFE_FREE(rep.extra_data.data); + + *users = u; + return true; +} + +static bool torture_winbind_struct_list_users(struct torture_context *torture) +{ + char **users; + uint32_t count; + bool ok; + + torture_comment(torture, "Running WINBINDD_LIST_USERS (struct based)\n"); + + ok = get_user_list(torture, &users); + torture_assert(torture, ok, "failed to get user list"); + + for (count = 0; users[count]; count++) { } + + torture_comment(torture, "got %d users\n", count); + + return true; +} + +static bool get_group_list(struct torture_context *torture, + unsigned int *num_entries, + char ***groups) +{ + struct winbindd_request req; + struct winbindd_response rep; + char **g = NULL; + uint32_t count; + char name[256]; + const char *extra_data; + + ZERO_STRUCT(req); + ZERO_STRUCT(rep); + + DO_STRUCT_REQ_REP(WINBINDD_LIST_GROUPS, &req, &rep); + extra_data = (char *)rep.extra_data.data; + + *num_entries = rep.data.num_entries; + + if (*num_entries == 0) { + torture_assert(torture, extra_data == NULL, + "extra data is null for >0 reported entries\n"); + *groups = NULL; + return true; + } + + torture_assert(torture, extra_data, "NULL extra data"); + + for(count = 0; + next_token(&extra_data, name, ",", sizeof(name)); + count++) + { + g = talloc_realloc(torture, g, char *, count + 2); + g[count+1] = NULL; + g[count] = talloc_strdup(g, name); + } + + SAFE_FREE(rep.extra_data.data); + + torture_assert_int_equal(torture, *num_entries, count, + "Wrong number of group entries reported."); + + *groups = g; + return true; +} + +static bool torture_winbind_struct_list_groups(struct torture_context *torture) +{ + char **groups; + uint32_t count; + bool ok; + + torture_comment(torture, "Running WINBINDD_LIST_GROUPS (struct based)\n"); + + ok = get_group_list(torture, &count, &groups); + torture_assert(torture, ok, "failed to get group list"); + + torture_comment(torture, "got %d groups\n", count); + + return true; +} + +struct torture_domain_sequence { + const char *netbios_name; + uint32_t seq; +}; + +static bool get_sequence_numbers(struct torture_context *torture, + struct torture_domain_sequence **seqs) +{ + struct winbindd_request req; + struct winbindd_response rep; + const char *extra_data; + char line[256]; + uint32_t count = 0; + struct torture_domain_sequence *s = NULL; + + ZERO_STRUCT(req); + ZERO_STRUCT(rep); + + DO_STRUCT_REQ_REP(WINBINDD_SHOW_SEQUENCE, &req, &rep); + + extra_data = (char *)rep.extra_data.data; + torture_assert(torture, extra_data, "NULL sequence list"); + + while (next_token(&extra_data, line, "\n", sizeof(line))) { + char *p, *lp; + uint32_t seq; + + s = talloc_realloc(torture, s, struct torture_domain_sequence, + count + 2); + ZERO_STRUCT(s[count+1]); + + lp = line; + p = strchr(lp, ' '); + torture_assert(torture, p, "invalid line format"); + *p = 0; + s[count].netbios_name = talloc_strdup(s, lp); + + lp = p+1; + torture_assert(torture, strncmp(lp, ": ", 2) == 0, + "invalid line format"); + lp += 2; + if (strcmp(lp, "DISCONNECTED") == 0) { + seq = (uint32_t)-1; + } else { + seq = (uint32_t)strtol(lp, &p, 10); + torture_assert(torture, (*p == '\0'), + "invalid line format"); + torture_assert(torture, (seq != (uint32_t)-1), + "sequence number -1 encountered"); + } + s[count].seq = seq; + + count++; + } + SAFE_FREE(rep.extra_data.data); + + torture_assert(torture, count >= 2, "The list of domain sequence " + "numbers should contain 2 entries"); + + *seqs = s; + return true; +} + +static bool torture_winbind_struct_show_sequence(struct torture_context *torture) +{ + bool ok; + uint32_t i; + struct torture_trust_domain *domlist = NULL; + struct torture_domain_sequence *s = NULL; + + torture_comment(torture, "Running WINBINDD_SHOW_SEQUENCE (struct based)\n"); + + ok = get_sequence_numbers(torture, &s); + torture_assert(torture, ok, "failed to get list of sequence numbers"); + + ok = get_trusted_domains(torture, &domlist); + torture_assert(torture, ok, "failed to get trust list"); + + for (i=0; domlist[i].netbios_name; i++) { + struct winbindd_request req; + struct winbindd_response rep; + uint32_t seq; + + torture_assert(torture, s[i].netbios_name, + "more domains received in second run"); + torture_assert_str_equal(torture, domlist[i].netbios_name, + s[i].netbios_name, + "inconsistent order of domain lists"); + + ZERO_STRUCT(req); + ZERO_STRUCT(rep); + fstrcpy(req.domain_name, domlist[i].netbios_name); + + ok = true; + DO_STRUCT_REQ_REP_EXT(WINBINDD_SHOW_SEQUENCE, &req, &rep, + NSS_STATUS_SUCCESS, + false, ok = false, + "WINBINDD_SHOW_SEQUENCE"); + if (ok == false) { + torture_warning(torture, + "WINBINDD_SHOW_SEQUENCE on " + "domain %s failed\n", + req.domain_name); + + /* + * Only fail for the first two domain that we + * check specially below, otherwise we fail on + * trusts generated by the LSA torture test + * that do not really exist. + */ + if (i > 1) { + /* + * Do not confirm the sequence numbers + * below + */ + return true; + } + + torture_comment(torture, + "Full trust list for " + "WINBINDD_SHOW_SEQUENCE " + "test was:\n"); + for (i=0; domlist[i].netbios_name; i++) { + torture_comment(torture, + "%s\n", + domlist[i].netbios_name); + } + + return false; + } + + seq = rep.data.sequence_number; + + if (i == 0) { + torture_assert(torture, (seq != (uint32_t)-1), + "BUILTIN domain disconnected"); + } else if (i == 1) { + torture_assert(torture, (seq != (uint32_t)-1), + "local domain disconnected"); + } + + + if (seq == (uint32_t)-1) { + torture_comment(torture, " * %s : DISCONNECTED\n", + req.domain_name); + } else { + torture_comment(torture, " * %s : %d\n", + req.domain_name, seq); + } + torture_assert(torture, (seq >= s[i].seq), + "illegal sequence number encountered"); + } + + return true; +} + +static bool torture_winbind_struct_setpwent(struct torture_context *torture) +{ + struct winbindd_request req; + struct winbindd_response rep; + + torture_comment(torture, "Running WINBINDD_SETPWENT (struct based)\n"); + + ZERO_STRUCT(req); + ZERO_STRUCT(rep); + + DO_STRUCT_REQ_REP(WINBINDD_SETPWENT, &req, &rep); + + return true; +} + +static bool torture_winbind_struct_getpwent(struct torture_context *torture) +{ + struct winbindd_request req; + struct winbindd_response rep; + struct winbindd_pw *pwent; + + torture_comment(torture, "Running WINBINDD_GETPWENT (struct based)\n"); + + torture_comment(torture, " - Running WINBINDD_SETPWENT first\n"); + ZERO_STRUCT(req); + ZERO_STRUCT(rep); + DO_STRUCT_REQ_REP(WINBINDD_SETPWENT, &req, &rep); + + torture_comment(torture, " - Running WINBINDD_GETPWENT now\n"); + ZERO_STRUCT(req); + ZERO_STRUCT(rep); + req.data.num_entries = 1; + if (torture_setting_bool(torture, "samba3", false)) { + DO_STRUCT_REQ_REP_EXT(WINBINDD_GETPWENT, &req, &rep, + NSS_STATUS_SUCCESS, false, _STRUCT_NOOP, + NULL); + } else { + DO_STRUCT_REQ_REP(WINBINDD_GETPWENT, &req, &rep); + } + pwent = (struct winbindd_pw *)rep.extra_data.data; + if (!torture_setting_bool(torture, "samba3", false)) { + torture_assert(torture, (pwent != NULL), "NULL pwent"); + } + if (pwent) { + torture_comment(torture, "name: %s, uid: %d, gid: %d, shell: %s\n", + pwent->pw_name, pwent->pw_uid, pwent->pw_gid, + pwent->pw_shell); + } + + return true; +} + +static bool torture_winbind_struct_endpwent(struct torture_context *torture) +{ + struct winbindd_request req; + struct winbindd_response rep; + + torture_comment(torture, "Running WINBINDD_ENDPWENT (struct based)\n"); + + ZERO_STRUCT(req); + ZERO_STRUCT(rep); + + DO_STRUCT_REQ_REP(WINBINDD_ENDPWENT, &req, &rep); + + return true; +} + +/* Copy of parse_domain_user from winbindd_util.c. Parse a string of the + form DOMAIN/user into a domain and a user */ + +static bool parse_domain_user(struct torture_context *torture, + const char *domuser, fstring domain, + fstring user) +{ + char *p = strchr(domuser, winbind_separator(torture)); + char *dom = NULL; + + if (!p) { + /* Maybe it was a UPN? */ + if ((p = strchr(domuser, '@')) != NULL) { + fstrcpy(domain, ""); + fstrcpy(user, domuser); + return true; + } + + fstrcpy(user, domuser); + get_winbind_domain(torture, &dom); + fstrcpy(domain, dom); + return true; + } + + fstrcpy(user, p+1); + fstrcpy(domain, domuser); + domain[PTR_DIFF(p, domuser)] = 0; + + return true; +} + +static bool lookup_name_sid_list(struct torture_context *torture, char **list) +{ + uint32_t count; + + for (count = 0; list[count]; count++) { + struct winbindd_request req; + struct winbindd_response rep; + char *sid; + char *name; + const char *domain_name = torture_setting_string(torture, + "winbindd_domain_without_prefix", + NULL); + + ZERO_STRUCT(req); + ZERO_STRUCT(rep); + + parse_domain_user(torture, list[count], req.data.name.dom_name, + req.data.name.name); + + DO_STRUCT_REQ_REP(WINBINDD_LOOKUPNAME, &req, &rep); + + sid = talloc_strdup(torture, rep.data.sid.sid); + + ZERO_STRUCT(req); + ZERO_STRUCT(rep); + + fstrcpy(req.data.sid, sid); + + DO_STRUCT_REQ_REP(WINBINDD_LOOKUPSID, &req, &rep); + + if (domain_name != NULL && + strequal(rep.data.name.dom_name, domain_name)) + { + name = talloc_asprintf(torture, "%s", + rep.data.name.name); + } else { + name = talloc_asprintf(torture, "%s%c%s", + rep.data.name.dom_name, + winbind_separator(torture), + rep.data.name.name); + } + + torture_assert_casestr_equal(torture, list[count], name, + "LOOKUP_SID after LOOKUP_NAME != id"); + +#if 0 + torture_comment(torture, " %s -> %s -> %s\n", list[count], + sid, name); +#endif + + talloc_free(sid); + talloc_free(name); + } + + return true; +} + +static bool name_is_in_list(const char *name, char **list) +{ + uint32_t count; + + for (count = 0; list && list[count]; count++) { + if (strequal(name, list[count])) { + return true; + } + } + return false; +} + +static bool torture_winbind_struct_lookup_name_sid(struct torture_context *torture) +{ + struct winbindd_request req; + struct winbindd_response rep; + const char *invalid_sid = "S-0-0-7"; + char *domain = NULL; + const char *invalid_user = "no one"; + char *invalid_name; + bool strict = torture_setting_bool(torture, "strict mode", false); + char **users; + char **groups; + uint32_t count, num_groups; + bool ok; + + torture_comment(torture, "Running WINBINDD_LOOKUP_NAME_SID (struct based)\n"); + + ok = get_user_list(torture, &users); + torture_assert(torture, ok, "failed to retrieve list of users"); + lookup_name_sid_list(torture, users); + + ok = get_group_list(torture, &num_groups, &groups); + torture_assert(torture, ok, "failed to retrieve list of groups"); + if (num_groups > 0) { + lookup_name_sid_list(torture, groups); + } + + ZERO_STRUCT(req); + ZERO_STRUCT(rep); + + fstrcpy(req.data.sid, invalid_sid); + + ok = true; + DO_STRUCT_REQ_REP_EXT(WINBINDD_LOOKUPSID, &req, &rep, + NSS_STATUS_NOTFOUND, + strict, + ok=false, + talloc_asprintf(torture, + "invalid sid %s was resolved", + invalid_sid)); + + ZERO_STRUCT(req); + ZERO_STRUCT(rep); + + /* try to find an invalid name... */ + + count = 0; + get_winbind_domain(torture, &domain); + do { + count++; + invalid_name = talloc_asprintf(torture, "%s/%s%u", + domain, + invalid_user, count); + } while(name_is_in_list(invalid_name, users) || + name_is_in_list(invalid_name, groups)); + + fstrcpy(req.data.name.dom_name, domain); + fstrcpy(req.data.name.name, + talloc_asprintf(torture, "%s%u", invalid_user, + count)); + + ok = true; + DO_STRUCT_REQ_REP_EXT(WINBINDD_LOOKUPNAME, &req, &rep, + NSS_STATUS_NOTFOUND, + strict, + ok=false, + talloc_asprintf(torture, + "invalid name %s was resolved", + invalid_name)); + + talloc_free(users); + talloc_free(groups); + + return true; +} + +static bool torture_winbind_struct_lookup_sids_invalid( + struct torture_context *torture) +{ + struct winbindd_request req = {0}; + struct winbindd_response rep = {0}; + bool strict = torture_setting_bool(torture, "strict mode", false); + bool ok; + + torture_comment(torture, + "Running WINBINDD_LOOKUP_SIDS (struct based)\n"); + + ok = true; + DO_STRUCT_REQ_REP_EXT(WINBINDD_LOOKUPSIDS, &req, &rep, + NSS_STATUS_NOTFOUND, + strict, + ok=false, + talloc_asprintf( + torture, + "invalid lookupsids succeeded")); + + return ok; +} + +struct torture_suite *torture_winbind_struct_init(TALLOC_CTX *ctx) +{ + struct torture_suite *suite = torture_suite_create(ctx, "struct"); + + torture_suite_add_simple_test(suite, "interface_version", torture_winbind_struct_interface_version); + torture_suite_add_simple_test(suite, "ping", torture_winbind_struct_ping); + torture_suite_add_simple_test(suite, "info", torture_winbind_struct_info); + torture_suite_add_simple_test(suite, "priv_pipe_dir", torture_winbind_struct_priv_pipe_dir); + torture_suite_add_simple_test(suite, "netbios_name", torture_winbind_struct_netbios_name); + torture_suite_add_simple_test(suite, "domain_name", torture_winbind_struct_domain_name); + torture_suite_add_simple_test(suite, "check_machacc", torture_winbind_struct_check_machacc); + torture_suite_add_simple_test(suite, "list_trustdom", torture_winbind_struct_list_trustdom); + torture_suite_add_simple_test(suite, "domain_info", torture_winbind_struct_domain_info); + torture_suite_add_simple_test(suite, "getdcname", torture_winbind_struct_getdcname); + torture_suite_add_simple_test(suite, "dsgetdcname", torture_winbind_struct_dsgetdcname); + torture_suite_add_simple_test(suite, "list_users", torture_winbind_struct_list_users); + torture_suite_add_simple_test(suite, "list_groups", torture_winbind_struct_list_groups); + torture_suite_add_simple_test(suite, "show_sequence", torture_winbind_struct_show_sequence); + torture_suite_add_simple_test(suite, "setpwent", torture_winbind_struct_setpwent); + torture_suite_add_simple_test(suite, "getpwent", torture_winbind_struct_getpwent); + torture_suite_add_simple_test(suite, "endpwent", torture_winbind_struct_endpwent); + torture_suite_add_simple_test(suite, "lookup_name_sid", torture_winbind_struct_lookup_name_sid); + torture_suite_add_simple_test( + suite, + "lookup_sids_invalid", + torture_winbind_struct_lookup_sids_invalid); + + suite->description = talloc_strdup(suite, "WINBIND - struct based protocol tests"); + + return suite; +} diff --git a/source4/torture/winbind/winbind.c b/source4/torture/winbind/winbind.c new file mode 100644 index 0000000..4acfd38 --- /dev/null +++ b/source4/torture/winbind/winbind.c @@ -0,0 +1,335 @@ +/* + Unix SMB/CIFS implementation. + SMB torture tester + Copyright (C) Stefan Metzmacher 2007 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2012 + Copyright (C) Christof Schmit <christof.schmitt@us.ibm.com> 2012 + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "torture/smbtorture.h" +#include "torture/winbind/proto.h" +#include "auth/auth.h" +#include "auth/auth_sam_reply.h" +#include "auth/gensec/gensec.h" +#include "system/kerberos.h" +#include "auth/kerberos/kerberos.h" +#include "auth/credentials/credentials.h" +#include "param/param.h" +#include "lib/cmdline/cmdline.h" +#include "auth/kerberos/pac_utils.h" +#include "wbclient.h" + +struct pac_data { + DATA_BLOB pac_blob; +}; + +/* A helper function which avoids touching the local databases to + * generate the session info, as we just want to verify the PAC + * details, not the full local token */ +static NTSTATUS test_generate_session_info_pac(struct auth4_context *auth_ctx, + TALLOC_CTX *mem_ctx, + struct smb_krb5_context *smb_krb5_context, + DATA_BLOB *pac_blob, + const char *principal_name, + const struct tsocket_address *remote_address, + uint32_t session_info_flags, + struct auth_session_info **session_info) +{ + NTSTATUS nt_status; + struct auth_user_info_dc *user_info_dc; + TALLOC_CTX *tmp_ctx; + struct pac_data *pac_data; + + if (pac_blob == NULL) { + DBG_ERR("pac_blob missing\n"); + return NT_STATUS_NO_IMPERSONATION_TOKEN; + } + + tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context"); + NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); + + auth_ctx->private_data = pac_data = talloc_zero(auth_ctx, struct pac_data); + + pac_data->pac_blob = *pac_blob; + + talloc_steal(pac_data, pac_data->pac_blob.data); + nt_status = kerberos_pac_blob_to_user_info_dc(tmp_ctx, + *pac_blob, + smb_krb5_context->krb5_context, + &user_info_dc, + NULL, NULL); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(tmp_ctx); + return nt_status; + } + + if (!(user_info_dc->info->user_flags & NETLOGON_GUEST)) { + session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED; + } + + session_info_flags |= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES; + nt_status = auth_generate_session_info(mem_ctx, + NULL, + NULL, + user_info_dc, session_info_flags, + session_info); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(tmp_ctx); + return nt_status; + } + + talloc_free(tmp_ctx); + return nt_status; +} + +static bool torture_decode_compare_pac(struct torture_context *tctx, + DATA_BLOB pac) +{ + struct wbcAuthUserParams params; + struct wbcAuthUserInfo *info; + struct wbcAuthErrorInfo *error; + struct PAC_LOGON_INFO *logon_info; + struct netr_SamInfo3 *info3; + struct netr_SamBaseInfo *base; + struct PAC_DOMAIN_GROUP_MEMBERSHIP *resource_groups = NULL; + wbcErr wbc_err; + NTSTATUS status; + int sid_idx, i; + char sid_str[50]; + + /* Let winbind decode the PAC */ + memset(¶ms, 0, sizeof(params)); + params.level = WBC_AUTH_USER_LEVEL_PAC; + params.password.pac.data = pac.data; + params.password.pac.length = pac.length; + + wbc_err = wbcAuthenticateUserEx(¶ms, &info, &error); + torture_assert(tctx, WBC_ERROR_IS_OK(wbc_err), wbcErrorString(wbc_err)); + + /* Decode the PAC internally */ + status = kerberos_pac_logon_info(tctx, pac, NULL, NULL, NULL, NULL, 0, + &logon_info); + torture_assert(tctx, NT_STATUS_IS_OK(status), "pac_logon_info"); + info3 = &logon_info->info3; + base = &info3->base; + resource_groups = &logon_info->resource_groups; + + /* Compare the decoded data from winbind and from internal call */ + torture_assert(tctx, info->user_flags == base->user_flags, "user_flags"); + torture_assert_str_equal(tctx, info->account_name, base->account_name.string, "account_name"); + torture_assert_str_equal(tctx, info->full_name, base->full_name.string, "full_name"); + torture_assert_str_equal(tctx, info->domain_name, base->logon_domain.string, "domain_name"); + torture_assert(tctx, info->acct_flags == base->acct_flags, "acct_flags"); + torture_assert(tctx, info->logon_count == base->logon_count, "logon_count"); + torture_assert(tctx, info->bad_password_count == base->bad_password_count, "bad_password_count"); + torture_assert(tctx, info->logon_time == nt_time_to_unix(base->logon_time), "logon_time"); + torture_assert(tctx, info->logoff_time == nt_time_to_unix(base->logoff_time), "logoff_time"); + torture_assert(tctx, info->kickoff_time == nt_time_to_unix(base->kickoff_time), "kickoff_time"); + torture_assert(tctx, info->pass_last_set_time == nt_time_to_unix(base->last_password_change), "last_password_change"); + torture_assert(tctx, info->pass_can_change_time == nt_time_to_unix(base->allow_password_change), "allow_password_change"); + torture_assert(tctx, info->pass_must_change_time == nt_time_to_unix(base->force_password_change), "force_password_change"); + torture_assert(tctx, info->num_sids == 2 + base->groups.count + info3->sidcount + resource_groups->groups.count, "num_sids"); + + sid_idx = 0; + wbcSidToStringBuf(&info->sids[sid_idx].sid, sid_str, sizeof(sid_str)); + torture_assert(tctx, + dom_sid_equal(dom_sid_parse_talloc(tctx, sid_str), + dom_sid_add_rid(tctx, base->domain_sid, base->rid)), + sid_str); + + sid_idx++; + wbcSidToStringBuf(&info->sids[sid_idx].sid, sid_str, sizeof(sid_str)); + torture_assert(tctx, + dom_sid_equal(dom_sid_parse_talloc(tctx, sid_str), + dom_sid_add_rid(tctx, base->domain_sid, base->primary_gid)), + sid_str); + + for(i = 0; i < base->groups.count; i++ ) { + sid_idx++; + wbcSidToStringBuf(&info->sids[sid_idx].sid, + sid_str, sizeof(sid_str)); + torture_assert_sid_equal(tctx, + dom_sid_parse_talloc(tctx, sid_str), + dom_sid_add_rid(tctx, base->domain_sid, + base->groups.rids[i].rid), + "base SID mismatch"); + } + + for(i = 0; i < info3->sidcount; i++) { + sid_idx++; + wbcSidToStringBuf(&info->sids[sid_idx].sid, + sid_str, sizeof(sid_str)); + torture_assert_sid_equal(tctx, + dom_sid_parse_talloc(tctx, sid_str), + info3->sids[i].sid, + "extra SID mismatch"); + } + + for (i = 0; i < resource_groups->groups.count; i++) { + sid_idx++; + wbcSidToStringBuf(&info->sids[sid_idx].sid, + sid_str, sizeof(sid_str)); + torture_assert_sid_equal(tctx, + dom_sid_parse_talloc(tctx, sid_str), + dom_sid_add_rid(tctx, resource_groups->domain_sid, + resource_groups->groups.rids[i].rid), + "resource SID mismatch"); + } + + sid_idx++; + torture_assert_int_equal(tctx, sid_idx, info->num_sids, "some SIDs still unaccounted for"); + + return true; +} + +static bool torture_winbind_pac(struct torture_context *tctx, + const char *sasl_mech, + const char *mech) +{ + NTSTATUS status; + + struct gensec_security *gensec_client_context; + struct gensec_security *gensec_server_context; + struct cli_credentials *machine_credentials; + + DATA_BLOB client_to_server, server_to_client; + + struct auth4_context *auth_context; + struct auth_session_info *session_info; + struct pac_data *pac_data; + + TALLOC_CTX *tmp_ctx = talloc_new(tctx); + torture_assert(tctx, tmp_ctx != NULL, "talloc_new() failed"); + + machine_credentials = cli_credentials_init_server(tmp_ctx, + tctx->lp_ctx); + torture_assert(tctx, machine_credentials != NULL, "cli_credentials_init() failed"); + + auth_context = talloc_zero(tmp_ctx, struct auth4_context); + torture_assert(tctx, auth_context != NULL, "talloc_new() failed"); + + auth_context->generate_session_info_pac = test_generate_session_info_pac; + + status = gensec_client_start(tctx, &gensec_client_context, + lpcfg_gensec_settings(tctx, tctx->lp_ctx)); + torture_assert_ntstatus_ok(tctx, status, "gensec_client_start (client) failed"); + + status = gensec_set_target_hostname(gensec_client_context, cli_credentials_get_workstation(machine_credentials)); + torture_assert_ntstatus_ok(tctx, status, "gensec_set_target_hostname (client) failed"); + + status = gensec_set_credentials(gensec_client_context, + samba_cmdline_get_creds()); + torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (client) failed"); + + if (sasl_mech) { + status = gensec_start_mech_by_sasl_name(gensec_client_context, sasl_mech); + torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (client) failed"); + } else { + status = gensec_start_mech_by_name(gensec_client_context, mech); + torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_name (client) failed"); + } + + + status = gensec_server_start(tctx, + lpcfg_gensec_settings(tctx, tctx->lp_ctx), + auth_context, &gensec_server_context); + torture_assert_ntstatus_ok(tctx, status, "gensec_server_start (server) failed"); + + status = gensec_set_credentials(gensec_server_context, machine_credentials); + torture_assert_ntstatus_ok(tctx, status, "gensec_set_credentials (server) failed"); + + if (sasl_mech) { + status = gensec_start_mech_by_sasl_name(gensec_server_context, sasl_mech); + torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_sasl_name (server) failed"); + } else { + status = gensec_start_mech_by_name(gensec_server_context, mech); + torture_assert_ntstatus_ok(tctx, status, "gensec_start_mech_by_name (server) failed"); + } + + server_to_client = data_blob(NULL, 0); + + do { + /* Do a client-server update dance */ + status = gensec_update(gensec_client_context, tmp_ctx, server_to_client, &client_to_server); + if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {; + torture_assert_ntstatus_ok(tctx, status, "gensec_update (client) failed"); + } + + status = gensec_update(gensec_server_context, tmp_ctx, client_to_server, &server_to_client); + if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {; + torture_assert_ntstatus_ok(tctx, status, "gensec_update (server) failed"); + } + + if (NT_STATUS_IS_OK(status)) { + break; + } + } while (1); + + /* Extract the PAC using Samba's code */ + + status = gensec_session_info(gensec_server_context, gensec_server_context, &session_info); + torture_assert_ntstatus_ok(tctx, status, "gensec_session_info failed"); + + pac_data = talloc_get_type(auth_context->private_data, struct pac_data); + + torture_assert(tctx, pac_data != NULL, "gensec_update failed to fill in pac_data in auth_context"); + torture_assert(tctx, pac_data->pac_blob.data != NULL, "pac_blob not present"); + torture_decode_compare_pac(tctx, pac_data->pac_blob); + + return true; +} + +static bool torture_winbind_pac_gssapi(struct torture_context *tctx) +{ + return torture_winbind_pac(tctx, "GSSAPI", NULL); +} + +static bool torture_winbind_pac_gss_spnego(struct torture_context *tctx) +{ + return torture_winbind_pac(tctx, "GSS-SPNEGO", NULL); +} + +static bool torture_winbind_pac_krb5(struct torture_context *tctx) +{ + return torture_winbind_pac(tctx, NULL, "krb5"); +} + +NTSTATUS torture_winbind_init(TALLOC_CTX *ctx) +{ + struct torture_suite *suite = torture_suite_create(ctx, "winbind"); + struct torture_suite *pac_suite; + torture_suite_add_suite(suite, torture_winbind_struct_init(suite)); + torture_suite_add_suite(suite, torture_wbclient(suite)); + + pac_suite = torture_suite_create(ctx, "pac"); + torture_suite_add_simple_test(pac_suite, + "GSSAPI", torture_winbind_pac_gssapi); + torture_suite_add_simple_test(pac_suite, + "GSS-SPNEGO", torture_winbind_pac_gss_spnego); + torture_suite_add_simple_test(pac_suite, + "krb5", torture_winbind_pac_krb5); + + pac_suite->description = talloc_strdup(suite, "Winbind Kerberos PAC tests"); + + torture_suite_add_suite(suite, pac_suite); + + suite->description = talloc_strdup(suite, "WINBIND tests"); + + torture_register_suite(ctx, suite); + + return NT_STATUS_OK; +} diff --git a/source4/torture/winbind/wscript_build b/source4/torture/winbind/wscript_build new file mode 100644 index 0000000..07b0b2b --- /dev/null +++ b/source4/torture/winbind/wscript_build @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +bld.SAMBA_MODULE('TORTURE_WINBIND', + source='winbind.c struct_based.c ../../../nsswitch/libwbclient/tests/wbclient.c', + autoproto='proto.h', + subsystem='smbtorture', + init_function='torture_winbind_init', + deps='popt wbclient torture PAM_ERRORS winbindd-lib', + internal_module=True + ) |