Commit message: CVE-2020-14323 torture4: Add a simple test for invalid lookup_sids winbind call

We can't add this test before the fix, add it to knownfail and have the fix
remove the knownfail entry again. As this crashes winbind, many tests after
this one will fail.

Reported by Bas Alberts of the GitHub Security Lab Team as GHSL-2020-134

Bug: https://bugzilla.samba.org/show_bug.cgi?id=14436
Signed-off-by: Volker Lendecke <vl@samba.org>
CVE: CVE-2020-14323
Vulnerability description: A null pointer dereference flaw was found in samba's Winbind service in versions before 4.11.15, before 4.12.9 and before 4.13.1. A local user could use this flaw to crash the winbind service causing denial of service.

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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 = "noone";
	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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}

Project: samba
File: struct_based.c

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;
}