summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--WHATSNEW.txt97
-rw-r--r--lib/async_req/async_sock.c5
-rw-r--r--libcli/util/tstream.c5
-rw-r--r--librpc/rpc/dcerpc_util.c14
-rw-r--r--nsswitch/libwbclient/wbc_sid.c7
-rw-r--r--nsswitch/pam_winbind.c6
-rw-r--r--nsswitch/wbinfo.c23
-rw-r--r--source3/lib/ctdb_conn.c5
-rw-r--r--source3/lib/netapi/group.c98
-rw-r--r--source3/lib/netapi/localgroup.c8
-rw-r--r--source3/lib/netapi/user.c72
-rw-r--r--source3/lib/util_tsock.c5
-rw-r--r--source3/libnet/libnet_join.c16
-rw-r--r--source3/librpc/rpc/dcerpc_helpers.c4
-rw-r--r--source3/rpc_client/cli_lsarpc.c35
-rw-r--r--source3/rpc_client/cli_pipe.c41
-rw-r--r--source3/rpc_server/netlogon/srv_netlog_nt.c2
-rw-r--r--source3/rpcclient/cmd_lsarpc.c13
-rw-r--r--source3/rpcclient/cmd_samr.c66
-rw-r--r--source3/smbd/lanman.c8
-rw-r--r--source3/utils/net_rpc.c47
-rw-r--r--source3/utils/net_rpc_join.c9
-rw-r--r--source3/winbindd/wb_lookupsids.c3
-rw-r--r--source3/winbindd/winbindd_msrpc.c10
-rw-r--r--source3/winbindd/winbindd_rpc.c54
-rw-r--r--source4/libcli/util/clilsa.c22
-rw-r--r--source4/libnet/groupinfo.c9
-rw-r--r--source4/libnet/groupman.c10
-rw-r--r--source4/libnet/libnet_join.c12
-rw-r--r--source4/libnet/libnet_lookup.c5
-rw-r--r--source4/libnet/libnet_passwd.c10
-rw-r--r--source4/libnet/userinfo.c8
-rw-r--r--source4/libnet/userman.c24
-rw-r--r--source4/librpc/rpc/dcerpc.c4
-rw-r--r--source4/librpc/rpc/dcerpc_smb.c6
-rw-r--r--source4/librpc/rpc/dcerpc_smb2.c6
-rw-r--r--source4/librpc/rpc/dcerpc_sock.c6
-rw-r--r--source4/winbind/wb_async_helpers.c26
38 files changed, 733 insertions, 68 deletions
diff --git a/WHATSNEW.txt b/WHATSNEW.txt
index 5e5cfabbf19..75db2475d61 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -1,4 +1,97 @@
=============================
+ Release Notes for Samba 4.1.3
+ December 9, 2013
+ =============================
+
+
+This is a security release in order to address
+CVE-2013-4408 (DCE-RPC fragment length field is incorrectly checked) and
+CVE-2012-6150 (pam_winbind login without require_membership_of restrictions).
+
+o CVE-2013-4408:
+ Samba versions 3.4.0 and above (versions 3.4.0 - 3.4.17, 3.5.0 -
+ 3.5.22, 3.6.0 - 3.6.21, 4.0.0 - 4.0.12 and including 4.1.2) are
+ vulnerable to buffer overrun exploits in the client processing of
+ DCE-RPC packets. This is due to incorrect checking of the DCE-RPC
+ fragment length in the client code.
+
+ This is a critical vulnerability as the DCE-RPC client code is part of
+ the winbindd authentication and identity mapping daemon, which is
+ commonly configured as part of many server installations (when joined
+ to an Active Directory Domain). A malicious Active Directory Domain
+ Controller or man-in-the-middle attacker impersonating an Active
+ Directory Domain Controller could achieve root-level access by
+ compromising the winbindd process.
+
+ Samba server versions 3.4.0 - 3.4.17 and versions 3.5.0 - 3.5.22 are
+ also vulnerable to a denial of service attack (server crash) due to a
+ similar error in the server code of those versions.
+
+ Samba server versions 3.6.0 and above (including all 3.6.x versions,
+ all 4.0.x versions and 4.1.x) are not vulnerable to this problem.
+
+ In addition range checks were missing on arguments returned from calls
+ to the DCE-RPC functions LookupSids (lsa and samr), LookupNames (lsa and samr)
+ and LookupRids (samr) which could also cause similar problems.
+
+ As this was found during an internal audit of the Samba code there are
+ no currently known exploits for this problem (as of December 9th 2013).
+
+o CVE-2012-6150:
+ Winbind allows for the further restriction of authenticated PAM logins using
+ the require_membership_of parameter. System administrators may specify a list
+ of SIDs or groups for which an authenticated user must be a member of. If an
+ authenticated user does not belong to any of the entries, then login should
+ fail. Invalid group name entries are ignored.
+
+ Samba versions 3.3.10, 3.4.3, 3.5.0 and later incorrectly allow login from
+ authenticated users if the require_membership_of parameter specifies only
+ invalid group names.
+
+ This is a vulnerability with low impact. All require_membership_of group
+ names must be invalid for this bug to be encountered.
+
+
+Changes since 4.1.2:
+--------------------
+
+o Jeremy Allison <jra@samba.org>
+ * BUG 10185: CVE-2013-4408: Correctly check DCE-RPC fragment length field.
+
+
+o Stefan Metzmacher <metze@samba.org>
+ * BUG 10185: CVE-2013-4408: Correctly check DCE-RPC fragment length field.
+
+
+o Noel Power <noel.power@suse.com>
+ * BUGs 10300, 10306: CVE-2012-6150: Fail authentication if user isn't
+ member of *any* require_membership_of specified groups.
+
+
+#######################################
+Reporting bugs & Development Discussion
+#######################################
+
+Please discuss this release on the samba-technical mailing list or by
+joining the #samba-technical IRC channel on irc.freenode.net.
+
+If you do report problems then please try to send high quality
+feedback. If you don't provide vital information to help us track down
+the problem then you will probably be ignored. All bug reports should
+be filed under the Samba 4.1 product in the project's Bugzilla
+database (https://bugzilla.samba.org/).
+
+
+======================================================================
+== Our Code, Our Bugs, Our Responsibility.
+== The Samba Team
+======================================================================
+
+
+Release notes for older releases follow:
+----------------------------------------
+
+ =============================
Release Notes for Samba 4.1.2
November 22, 2013
=============================
@@ -87,8 +180,8 @@ database (https://bugzilla.samba.org/).
======================================================================
-Release notes for older releases follow:
-----------------------------------------
+----------------------------------------------------------------------
+
=============================
Release Notes for Samba 4.1.1
diff --git a/lib/async_req/async_sock.c b/lib/async_req/async_sock.c
index 59dde885921..74b2cb7baa8 100644
--- a/lib/async_req/async_sock.c
+++ b/lib/async_req/async_sock.c
@@ -667,6 +667,11 @@ static void read_packet_handler(struct tevent_context *ev,
return;
}
+ if (total + more < total) {
+ tevent_req_error(req, EMSGSIZE);
+ return;
+ }
+
tmp = talloc_realloc(state, state->buf, uint8_t, total+more);
if (tevent_req_nomem(tmp, req)) {
return;
diff --git a/libcli/util/tstream.c b/libcli/util/tstream.c
index 12cef9b6ddd..dd830e2aa44 100644
--- a/libcli/util/tstream.c
+++ b/libcli/util/tstream.c
@@ -129,6 +129,11 @@ static void tstream_read_pdu_blob_done(struct tevent_req *subreq)
return;
}
+ if (new_buf_size <= old_buf_size) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_BUFFER_SIZE);
+ return;
+ }
+
buf = talloc_realloc(state, state->pdu_blob.data, uint8_t, new_buf_size);
if (tevent_req_nomem(buf, req)) {
return;
diff --git a/librpc/rpc/dcerpc_util.c b/librpc/rpc/dcerpc_util.c
index de292c83669..0b9cca3d255 100644
--- a/librpc/rpc/dcerpc_util.c
+++ b/librpc/rpc/dcerpc_util.c
@@ -223,6 +223,15 @@ static int dcerpc_read_ncacn_packet_next_vector(struct tstream_context *stream,
ofs = state->buffer.length;
+ if (frag_len < ofs) {
+ /*
+ * something is wrong, let the caller deal with it
+ */
+ *_vector = NULL;
+ *_count = 0;
+ return 0;
+ }
+
state->buffer.data = talloc_realloc(state,
state->buffer.data,
uint8_t, frag_len);
@@ -292,6 +301,11 @@ static void dcerpc_read_ncacn_packet_done(struct tevent_req *subreq)
return;
}
+ if (state->pkt->frag_length != state->buffer.length) {
+ tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+ return;
+ }
+
tevent_req_done(req);
}
diff --git a/nsswitch/libwbclient/wbc_sid.c b/nsswitch/libwbclient/wbc_sid.c
index bab69331087..82ac339865e 100644
--- a/nsswitch/libwbclient/wbc_sid.c
+++ b/nsswitch/libwbclient/wbc_sid.c
@@ -421,6 +421,13 @@ wbcErr wbcLookupSids(const struct wbcDomainSid *sids, int num_sids,
for (i=0; i<num_names; i++) {
names[i].domain_index = strtoul(p, &q, 10);
+ if (names[i].domain_index < 0) {
+ goto wbc_err_invalid;
+ }
+ if (names[i].domain_index >= num_domains) {
+ goto wbc_err_invalid;
+ }
+
if (*q != ' ') {
goto wbc_err_invalid;
}
diff --git a/nsswitch/pam_winbind.c b/nsswitch/pam_winbind.c
index 9f855564bcc..98cf97e2daa 100644
--- a/nsswitch/pam_winbind.c
+++ b/nsswitch/pam_winbind.c
@@ -1163,6 +1163,12 @@ static bool winbind_name_list_to_sid_string_list(struct pwb_context *ctx,
_make_remark_format(ctx, PAM_TEXT_INFO, _("Cannot convert group %s "
"to sid, please contact your administrator to see "
"if group %s is valid."), search_location, search_location);
+
+ /* If no valid groups were converted we should fail outright */
+ if (name_list != NULL && strlen(sid_list_buffer) == 0) {
+ result = false;
+ goto out;
+ }
/*
* The lookup of the last name failed..
* It results in require_member_of_sid ends with ','
diff --git a/nsswitch/wbinfo.c b/nsswitch/wbinfo.c
index 17977ed8aa8..3f0310a44b1 100644
--- a/nsswitch/wbinfo.c
+++ b/nsswitch/wbinfo.c
@@ -1391,11 +1391,28 @@ static bool wbinfo_lookup_sids(const char *arg)
}
for (i=0; i<num_sids; i++) {
+ const char *domain = NULL;
+
wbcSidToStringBuf(&sids[i], sidstr, sizeof(sidstr));
- d_printf("%s -> %s\\%s %d\n", sidstr,
- domains[names[i].domain_index].short_name,
- names[i].name, names[i].type);
+ if (names[i].domain_index >= num_domains) {
+ domain = "<none>";
+ } else if (names[i].domain_index < 0) {
+ domain = "<none>";
+ } else {
+ domain = domains[names[i].domain_index].short_name;
+ }
+
+ if (names[i].type == WBC_SID_NAME_DOMAIN) {
+ d_printf("%s -> %s %d\n", sidstr,
+ domain,
+ names[i].type);
+ } else {
+ d_printf("%s -> %s%c%s %d\n", sidstr,
+ domain,
+ winbind_separator(),
+ names[i].name, names[i].type);
+ }
}
wbcFreeMemory(names);
wbcFreeMemory(domains);
diff --git a/source3/lib/ctdb_conn.c b/source3/lib/ctdb_conn.c
index 90930eb86b0..40071d4e5cb 100644
--- a/source3/lib/ctdb_conn.c
+++ b/source3/lib/ctdb_conn.c
@@ -233,6 +233,11 @@ static ssize_t ctdb_packet_more(uint8_t *buf, size_t buflen, void *p)
return 0;
}
memcpy(&len, buf, sizeof(len));
+
+ if (len < sizeof(uint32_t)) {
+ return -1;
+ }
+
return (len - sizeof(uint32_t));
}
diff --git a/source3/lib/netapi/group.c b/source3/lib/netapi/group.c
index 9813f7eacb3..b806fc4f141 100644
--- a/source3/lib/netapi/group.c
+++ b/source3/lib/netapi/group.c
@@ -309,6 +309,15 @@ WERROR NetGroupDel_r(struct libnetapi_ctx *ctx,
goto done;
}
+ if (rids.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+ if (types.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+
if (types.ids[0] != SID_NAME_DOM_GRP) {
werr = WERR_INVALID_DATATYPE;
goto done;
@@ -386,6 +395,14 @@ WERROR NetGroupDel_r(struct libnetapi_ctx *ctx,
werr = ntstatus_to_werror(result);
goto done;
}
+ if (names.count != rid_array->count) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+ if (member_types.count != rid_array->count) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
}
for (i=0; i < rid_array->count; i++) {
@@ -511,6 +528,14 @@ WERROR NetGroupSetInfo_r(struct libnetapi_ctx *ctx,
werr = ntstatus_to_werror(result);
goto done;
}
+ if (rids.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+ if (types.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
if (types.ids[0] != SID_NAME_DOM_GRP) {
werr = WERR_INVALID_DATATYPE;
@@ -781,6 +806,14 @@ WERROR NetGroupGetInfo_r(struct libnetapi_ctx *ctx,
werr = ntstatus_to_werror(result);
goto done;
}
+ if (rids.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+ if (types.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
if (types.ids[0] != SID_NAME_DOM_GRP) {
werr = WERR_INVALID_DATATYPE;
@@ -921,6 +954,14 @@ WERROR NetGroupAddUser_r(struct libnetapi_ctx *ctx,
werr = WERR_GROUPNOTFOUND;
goto done;
}
+ if (rids.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+ if (types.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
if (types.ids[0] != SID_NAME_DOM_GRP) {
werr = WERR_GROUPNOTFOUND;
@@ -959,6 +1000,14 @@ WERROR NetGroupAddUser_r(struct libnetapi_ctx *ctx,
werr = WERR_USER_NOT_FOUND;
goto done;
}
+ if (rids.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+ if (types.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
if (types.ids[0] != SID_NAME_USER) {
werr = WERR_USER_NOT_FOUND;
@@ -1065,6 +1114,14 @@ WERROR NetGroupDelUser_r(struct libnetapi_ctx *ctx,
werr = WERR_GROUPNOTFOUND;
goto done;
}
+ if (rids.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+ if (types.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
if (types.ids[0] != SID_NAME_DOM_GRP) {
werr = WERR_GROUPNOTFOUND;
@@ -1104,6 +1161,14 @@ WERROR NetGroupDelUser_r(struct libnetapi_ctx *ctx,
werr = WERR_USER_NOT_FOUND;
goto done;
}
+ if (rids.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+ if (types.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
if (types.ids[0] != SID_NAME_USER) {
werr = WERR_USER_NOT_FOUND;
@@ -1515,6 +1580,14 @@ WERROR NetGroupGetUsers_r(struct libnetapi_ctx *ctx,
werr = ntstatus_to_werror(result);
goto done;
}
+ if (group_rids.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+ if (name_types.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
status = dcerpc_samr_OpenGroup(b, talloc_tos(),
&domain_handle,
@@ -1559,6 +1632,14 @@ WERROR NetGroupGetUsers_r(struct libnetapi_ctx *ctx,
werr = ntstatus_to_werror(result);
goto done;
}
+ if (names.count != rid_array->count) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+ if (member_types.count != rid_array->count) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
for (i=0; i < names.count; i++) {
@@ -1691,6 +1772,14 @@ WERROR NetGroupSetUsers_r(struct libnetapi_ctx *ctx,
werr = ntstatus_to_werror(result);
goto done;
}
+ if (group_rids.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+ if (group_types.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
status = dcerpc_samr_OpenGroup(b, talloc_tos(),
&domain_handle,
@@ -1769,6 +1858,15 @@ WERROR NetGroupSetUsers_r(struct libnetapi_ctx *ctx,
goto done;
}
+ if (r->in.num_entries != user_rids.count) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+ if (r->in.num_entries != name_types.count) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+
member_rids = user_rids.ids;
status = dcerpc_samr_QueryGroupMember(b, talloc_tos(),
diff --git a/source3/lib/netapi/localgroup.c b/source3/lib/netapi/localgroup.c
index 1a544adecd3..17cab689b4e 100644
--- a/source3/lib/netapi/localgroup.c
+++ b/source3/lib/netapi/localgroup.c
@@ -58,6 +58,12 @@ static NTSTATUS libnetapi_samr_lookup_and_open_alias(TALLOC_CTX *mem_ctx,
if (!NT_STATUS_IS_OK(result)) {
return result;
}
+ if (user_rids.count != 1) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ if (name_types.count != 1) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
switch (name_types.ids[0]) {
case SID_NAME_ALIAS:
@@ -1041,7 +1047,7 @@ static NTSTATUS libnetapi_lsa_lookup_names3(TALLOC_CTX *mem_ctx,
NT_STATUS_NOT_OK_RETURN(result);
if (count != 1 || sids.count != 1) {
- return NT_STATUS_NONE_MAPPED;
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
sid_copy(sid, sids.sids[0].sid);
diff --git a/source3/lib/netapi/user.c b/source3/lib/netapi/user.c
index df3914cb4fc..a971e2dc91c 100644
--- a/source3/lib/netapi/user.c
+++ b/source3/lib/netapi/user.c
@@ -604,6 +604,14 @@ WERROR NetUserDel_r(struct libnetapi_ctx *ctx,
werr = ntstatus_to_werror(result);
goto done;
}
+ if (user_rids.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+ if (name_types.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
status = dcerpc_samr_OpenUser(b, talloc_tos(),
&domain_handle,
@@ -1803,6 +1811,14 @@ WERROR NetUserGetInfo_r(struct libnetapi_ctx *ctx,
werr = ntstatus_to_werror(result);
goto done;
}
+ if (user_rids.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+ if (name_types.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
status = libnetapi_samr_lookup_user_map_USER_INFO(ctx, pipe_cli,
domain_sid,
@@ -1968,6 +1984,14 @@ WERROR NetUserSetInfo_r(struct libnetapi_ctx *ctx,
werr = ntstatus_to_werror(result);
goto done;
}
+ if (user_rids.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+ if (name_types.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
status = dcerpc_samr_OpenUser(b, talloc_tos(),
&domain_handle,
@@ -3027,6 +3051,14 @@ WERROR NetUserGetGroups_r(struct libnetapi_ctx *ctx,
werr = ntstatus_to_werror(result);
goto done;
}
+ if (user_rids.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+ if (name_types.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
status = dcerpc_samr_OpenUser(b, talloc_tos(),
&domain_handle,
@@ -3082,6 +3114,14 @@ WERROR NetUserGetGroups_r(struct libnetapi_ctx *ctx,
werr = ntstatus_to_werror(result);
goto done;
}
+ if (names.count != rid_array->count) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+ if (types.count != rid_array->count) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
for (i=0; i < names.count; i++) {
status = add_GROUP_USERS_INFO_X_buffer(ctx,
@@ -3202,6 +3242,14 @@ WERROR NetUserSetGroups_r(struct libnetapi_ctx *ctx,
werr = ntstatus_to_werror(result);
goto done;
}
+ if (user_rids.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+ if (name_types.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
status = dcerpc_samr_OpenUser(b, talloc_tos(),
&domain_handle,
@@ -3262,6 +3310,14 @@ WERROR NetUserSetGroups_r(struct libnetapi_ctx *ctx,
werr = ntstatus_to_werror(result);
goto done;
}
+ if (group_rids.count != r->in.num_entries) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+ if (name_types.count != r->in.num_entries) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
member_rids = group_rids.ids;
@@ -3539,6 +3595,14 @@ WERROR NetUserGetLocalGroups_r(struct libnetapi_ctx *ctx,
werr = ntstatus_to_werror(result);
goto done;
}
+ if (user_rids.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+ if (name_types.count != 1) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
status = dcerpc_samr_OpenUser(b, talloc_tos(),
&domain_handle,
@@ -3660,6 +3724,14 @@ WERROR NetUserGetLocalGroups_r(struct libnetapi_ctx *ctx,
werr = ntstatus_to_werror(result);
goto done;
}
+ if (names.count != num_rids) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
+ if (types.count != num_rids) {
+ werr = WERR_BAD_NET_RESP;
+ goto done;
+ }
for (i=0; i < names.count; i++) {
status = add_LOCALGROUP_USERS_INFO_X_buffer(ctx,
diff --git a/source3/lib/util_tsock.c b/source3/lib/util_tsock.c
index 35a97f5e692..03380ef244b 100644
--- a/source3/lib/util_tsock.c
+++ b/source3/lib/util_tsock.c
@@ -110,6 +110,11 @@ static void tstream_read_packet_done(struct tevent_req *subreq)
return;
}
+ if (total + more < total) {
+ tevent_req_error(req, EMSGSIZE);
+ return;
+ }
+
tmp = talloc_realloc(state, state->buf, uint8_t, total+more);
if (tevent_req_nomem(tmp, req)) {
return;
diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index 7edccd17259..14183853bdc 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -1038,6 +1038,14 @@ static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
status = result;
goto done;
}
+ if (user_rids.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
+ if (name_types.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
if (name_types.ids[0] != SID_NAME_USER) {
DEBUG(0,("%s is not a user account (type=%d)\n",
@@ -1431,6 +1439,14 @@ static NTSTATUS libnet_join_unjoindomain_rpc(TALLOC_CTX *mem_ctx,
status = result;
goto done;
}
+ if (user_rids.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
+ if (name_types.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
if (name_types.ids[0] != SID_NAME_USER) {
DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name,
diff --git a/source3/librpc/rpc/dcerpc_helpers.c b/source3/librpc/rpc/dcerpc_helpers.c
index d36c2da3838..a55e419fc13 100644
--- a/source3/librpc/rpc/dcerpc_helpers.c
+++ b/source3/librpc/rpc/dcerpc_helpers.c
@@ -127,6 +127,10 @@ NTSTATUS dcerpc_pull_ncacn_packet(TALLOC_CTX *mem_ctx,
NDR_PRINT_DEBUG(ncacn_packet, r);
}
+ if (r->frag_length != blob->length) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
return NT_STATUS_OK;
}
diff --git a/source3/rpc_client/cli_lsarpc.c b/source3/rpc_client/cli_lsarpc.c
index 126f3705a3a..974538b87bd 100644
--- a/source3/rpc_client/cli_lsarpc.c
+++ b/source3/rpc_client/cli_lsarpc.c
@@ -279,11 +279,26 @@ static NTSTATUS dcerpc_lsa_lookup_sids_noalloc(struct dcerpc_binding_handle *h,
for (i = 0; i < num_sids; i++) {
const char *name, *dom_name;
- uint32_t dom_idx = lsa_names.names[i].sid_index;
+ uint32_t dom_idx;
+
+ if (i >= lsa_names.count) {
+ *presult = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ return status;
+ }
+
+ dom_idx = lsa_names.names[i].sid_index;
/* Translate optimised name through domain index array */
if (dom_idx != 0xffffffff) {
+ if (ref_domains == NULL) {
+ *presult = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ return status;
+ }
+ if (dom_idx >= ref_domains->count) {
+ *presult = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ return status;
+ }
dom_name = ref_domains->domains[dom_idx].name.string;
name = lsa_names.names[i].name.string;
@@ -647,9 +662,19 @@ NTSTATUS dcerpc_lsa_lookup_names_generic(struct dcerpc_binding_handle *h,
struct dom_sid *sid = &(*sids)[i];
if (use_lookupnames4) {
+ if (i >= sid_array3.count) {
+ *presult = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
+
dom_idx = sid_array3.sids[i].sid_index;
(*types)[i] = sid_array3.sids[i].sid_type;
} else {
+ if (i >= sid_array.count) {
+ *presult = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
+
dom_idx = sid_array.sids[i].sid_index;
(*types)[i] = sid_array.sids[i].sid_type;
}
@@ -662,6 +687,14 @@ NTSTATUS dcerpc_lsa_lookup_names_generic(struct dcerpc_binding_handle *h,
(*types)[i] = SID_NAME_UNKNOWN;
continue;
}
+ if (domains == NULL) {
+ *presult = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
+ if (dom_idx >= domains->count) {
+ *presult = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
if (use_lookupnames4) {
sid_copy(sid, sid_array3.sids[i].sid);
diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c
index 2e978efb8d9..385ae25289b 100644
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -284,6 +284,10 @@ static struct tevent_req *get_complete_frag_send(TALLOC_CTX *mem_ctx,
}
state->frag_len = dcerpc_get_frag_length(pdu);
+ if (state->frag_len < RPC_HEADER_LEN) {
+ tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+ return tevent_req_post(req, ev);
+ }
/*
* Ensure we have frag_len bytes of data.
@@ -332,6 +336,10 @@ static void get_complete_frag_got_header(struct tevent_req *subreq)
}
state->frag_len = dcerpc_get_frag_length(state->pdu);
+ if (state->frag_len < RPC_HEADER_LEN) {
+ tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
+ return;
+ }
if (!data_blob_realloc(NULL, state->pdu, state->frag_len)) {
tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
@@ -381,6 +389,7 @@ static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx,
struct ncacn_packet *pkt,
DATA_BLOB *pdu,
uint8_t expected_pkt_type,
+ uint32_t call_id,
DATA_BLOB *rdata,
DATA_BLOB *reply_pdu)
{
@@ -479,7 +488,7 @@ static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx,
"from %s!\n",
(unsigned int)pkt->ptype,
rpccli_pipe_txt(talloc_tos(), cli)));
- return NT_STATUS_INVALID_INFO_CLASS;
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
}
if (pkt->ptype != expected_pkt_type) {
@@ -487,7 +496,15 @@ static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx,
"RPC packet type - %u, not %u\n",
rpccli_pipe_txt(talloc_tos(), cli),
pkt->ptype, expected_pkt_type));
- return NT_STATUS_INVALID_INFO_CLASS;
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ if (pkt->call_id != call_id) {
+ DEBUG(3, (__location__ ": Connection to %s got an unexpected "
+ "RPC call_id - %u, not %u\n",
+ rpccli_pipe_txt(talloc_tos(), cli),
+ pkt->call_id, call_id));
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
}
/* Do this just before return - we don't want to modify any rpc header
@@ -693,6 +710,7 @@ struct rpc_api_pipe_state {
struct tevent_context *ev;
struct rpc_pipe_client *cli;
uint8_t expected_pkt_type;
+ uint32_t call_id;
DATA_BLOB incoming_frag;
struct ncacn_packet *pkt;
@@ -711,7 +729,8 @@ static struct tevent_req *rpc_api_pipe_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct rpc_pipe_client *cli,
DATA_BLOB *data, /* Outgoing PDU */
- uint8_t expected_pkt_type)
+ uint8_t expected_pkt_type,
+ uint32_t call_id)
{
struct tevent_req *req, *subreq;
struct rpc_api_pipe_state *state;
@@ -725,6 +744,7 @@ static struct tevent_req *rpc_api_pipe_send(TALLOC_CTX *mem_ctx,
state->ev = ev;
state->cli = cli;
state->expected_pkt_type = expected_pkt_type;
+ state->call_id = call_id;
state->incoming_frag = data_blob_null;
state->reply_pdu = data_blob_null;
state->reply_pdu_offset = 0;
@@ -876,6 +896,7 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq)
state->cli, state->pkt,
&state->incoming_frag,
state->expected_pkt_type,
+ state->call_id,
&rdata,
&state->reply_pdu);
@@ -1218,7 +1239,8 @@ struct tevent_req *rpc_api_pipe_req_send(TALLOC_CTX *mem_ctx,
if (is_last_frag) {
subreq = rpc_api_pipe_send(state, ev, state->cli,
&state->rpc_out,
- DCERPC_PKT_RESPONSE);
+ DCERPC_PKT_RESPONSE,
+ state->call_id);
if (subreq == NULL) {
goto fail;
}
@@ -1354,7 +1376,8 @@ static void rpc_api_pipe_req_write_done(struct tevent_req *subreq)
if (is_last_frag) {
subreq = rpc_api_pipe_send(state, state->ev, state->cli,
&state->rpc_out,
- DCERPC_PKT_RESPONSE);
+ DCERPC_PKT_RESPONSE,
+ state->call_id);
if (tevent_req_nomem(subreq, req)) {
return;
}
@@ -1600,7 +1623,7 @@ struct tevent_req *rpc_pipe_bind_send(TALLOC_CTX *mem_ctx,
}
subreq = rpc_api_pipe_send(state, ev, cli, &state->rpc_out,
- DCERPC_PKT_BIND_ACK);
+ DCERPC_PKT_BIND_ACK, state->rpc_call_id);
if (subreq == NULL) {
goto fail;
}
@@ -1908,7 +1931,8 @@ static NTSTATUS rpc_bind_next_send(struct tevent_req *req,
}
subreq = rpc_api_pipe_send(state, state->ev, state->cli,
- &state->rpc_out, DCERPC_PKT_ALTER_RESP);
+ &state->rpc_out, DCERPC_PKT_ALTER_RESP,
+ state->rpc_call_id);
if (subreq == NULL) {
return NT_STATUS_NO_MEMORY;
}
@@ -1940,7 +1964,8 @@ static NTSTATUS rpc_bind_finish_send(struct tevent_req *req,
}
subreq = rpc_api_pipe_send(state, state->ev, state->cli,
- &state->rpc_out, DCERPC_PKT_AUTH3);
+ &state->rpc_out, DCERPC_PKT_AUTH3,
+ state->rpc_call_id);
if (subreq == NULL) {
return NT_STATUS_NO_MEMORY;
}
diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c
index 6a6c125da9a..e5ca4740649 100644
--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
@@ -580,7 +580,7 @@ static NTSTATUS samr_find_machine_account(TALLOC_CTX *mem_ctx,
status = NT_STATUS_NO_SUCH_USER;
goto out;
}
- if (rids.count != types.count) {
+ if (types.count != 1) {
status = NT_STATUS_INVALID_PARAMETER;
goto out;
}
diff --git a/source3/rpcclient/cmd_lsarpc.c b/source3/rpcclient/cmd_lsarpc.c
index cbc089f7391..5c28b1c1787 100644
--- a/source3/rpcclient/cmd_lsarpc.c
+++ b/source3/rpcclient/cmd_lsarpc.c
@@ -323,7 +323,7 @@ static NTSTATUS cmd_lsa_lookup_names4(struct rpc_pipe_client *cli,
uint32_t num_names;
struct lsa_String *names;
- struct lsa_RefDomainList *domains;
+ struct lsa_RefDomainList *domains = NULL;
struct lsa_TransSidArray3 sids;
uint32_t count = 0;
int i;
@@ -361,6 +361,10 @@ static NTSTATUS cmd_lsa_lookup_names4(struct rpc_pipe_client *cli,
return result;
}
+ if (sids.count != num_names) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
for (i = 0; i < sids.count; i++) {
fstring sid_str;
sid_to_fstring(sid_str, sids.sids[i].sid);
@@ -450,7 +454,7 @@ static NTSTATUS cmd_lsa_lookup_sids3(struct rpc_pipe_client *cli,
NTSTATUS status = NT_STATUS_UNSUCCESSFUL, result;
int i;
struct lsa_SidArray sids;
- struct lsa_RefDomainList *domains;
+ struct lsa_RefDomainList *domains = NULL;
struct lsa_TransNameArray2 names;
uint32_t count = 0;
struct dcerpc_binding_handle *b = cli->binding_handle;
@@ -506,9 +510,12 @@ static NTSTATUS cmd_lsa_lookup_sids3(struct rpc_pipe_client *cli,
/* Print results */
- for (i = 0; i < count; i++) {
+ for (i = 0; i < names.count; i++) {
fstring sid_str;
+ if (i >= sids.num_sids) {
+ break;
+ }
sid_to_fstring(sid_str, sids.sids[i].sid);
printf("%s %s (%d)\n", sid_str,
names.names[i].name.string,
diff --git a/source3/rpcclient/cmd_samr.c b/source3/rpcclient/cmd_samr.c
index 022230becb5..87882c3ce4e 100644
--- a/source3/rpcclient/cmd_samr.c
+++ b/source3/rpcclient/cmd_samr.c
@@ -385,7 +385,17 @@ static NTSTATUS cmd_samr_query_user(struct rpc_pipe_client *cli,
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
+
if (NT_STATUS_IS_OK(result)) {
+ if (rids.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
+ if (types.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
+
status = dcerpc_samr_OpenUser(b, mem_ctx,
&domain_pol,
access_mask,
@@ -1453,6 +1463,15 @@ static NTSTATUS cmd_samr_delete_alias(struct rpc_pipe_client *cli,
goto done;
}
if (NT_STATUS_IS_OK(result)) {
+ if (rids.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
+ if (types.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
+
status = dcerpc_samr_OpenAlias(b, mem_ctx,
&domain_pol,
access_mask,
@@ -2115,6 +2134,14 @@ static NTSTATUS cmd_samr_lookup_names(struct rpc_pipe_client *cli,
status = result;
goto done;
}
+ if (rids.count != num_names) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
+ if (name_types.count != num_names) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
/* Display results */
@@ -2196,6 +2223,14 @@ static NTSTATUS cmd_samr_lookup_rids(struct rpc_pipe_client *cli,
goto done;
/* Display results */
+ if (num_rids != names.count) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
+ if (num_rids != types.count) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
for (i = 0; i < num_rids; i++) {
printf("rid 0x%x: %s (%d)\n",
@@ -2272,6 +2307,14 @@ static NTSTATUS cmd_samr_delete_dom_group(struct rpc_pipe_client *cli,
status = result;
goto done;
}
+ if (group_rids.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
+ if (name_types.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
status = dcerpc_samr_OpenGroup(b, mem_ctx,
&domain_pol,
@@ -2375,6 +2418,14 @@ static NTSTATUS cmd_samr_delete_dom_user(struct rpc_pipe_client *cli,
status = result;
goto done;
}
+ if (user_rids.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
+ if (name_types.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
status = dcerpc_samr_OpenUser(b, mem_ctx,
&domain_pol,
@@ -2763,6 +2814,14 @@ static NTSTATUS cmd_samr_chgpasswd(struct rpc_pipe_client *cli,
status = result;
goto done;
}
+ if (rids.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
+ if (types.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
status = dcerpc_samr_OpenUser(b, mem_ctx,
&domain_pol,
@@ -3166,7 +3225,12 @@ static NTSTATUS cmd_samr_setuserinfo_int(struct rpc_pipe_client *cli,
if (!NT_STATUS_IS_OK(result)) {
return result;
}
-
+ if (rids.count != 1) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ if (types.count != 1) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
status = dcerpc_samr_OpenUser(b, mem_ctx,
&domain_pol,
diff --git a/source3/smbd/lanman.c b/source3/smbd/lanman.c
index b5598a4382d..e6b9530410c 100644
--- a/source3/smbd/lanman.c
+++ b/source3/smbd/lanman.c
@@ -2629,6 +2629,14 @@ static bool api_NetUserGetGroups(struct smbd_server_connection *sconn,
nt_errstr(result)));
goto close_domain;
}
+ if (rid.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto close_domain;
+ }
+ if (type.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto close_domain;
+ }
if (type.ids[0] != SID_NAME_USER) {
DEBUG(10, ("%s is a %s, not a user\n", UserName,
diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c
index 870ad2287f2..92964b5ab55 100644
--- a/source3/utils/net_rpc.c
+++ b/source3/utils/net_rpc.c
@@ -1667,6 +1667,14 @@ static NTSTATUS rpc_group_delete_internals(struct net_context *c,
d_fprintf(stderr, _("Lookup of '%s' failed\n"),argv[0]);
goto done;
}
+ if (group_rids.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
+ if (name_types.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
switch (name_types.ids[0])
{
@@ -2074,6 +2082,14 @@ static NTSTATUS rpc_add_groupmem(struct rpc_pipe_client *pipe_hnd,
member);
goto done;
}
+ if (rids.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
+ if (rid_types.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
status = dcerpc_samr_OpenGroup(b, mem_ctx,
&domain_pol,
@@ -2329,6 +2345,14 @@ static NTSTATUS rpc_del_groupmem(struct net_context *c,
member);
goto done;
}
+ if (rids.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
+ if (rid_types.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
status = dcerpc_samr_OpenGroup(b, mem_ctx,
&domain_pol,
@@ -2876,7 +2900,12 @@ static NTSTATUS rpc_list_group_members(struct net_context *c,
if (!NT_STATUS_IS_OK(result)) {
return result;
}
-
+ if (names.count != this_time) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ if (types.count != this_time) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
/* We only have users as members, but make the output
the same as the output of alias members */
@@ -3112,8 +3141,14 @@ static NTSTATUS rpc_group_members_internals(struct net_context *c,
if (rids.count != 1) {
d_fprintf(stderr, _("Couldn't find group %s\n"),
argv[0]);
- return result;
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
+ if (rid_types.count != 1) {
+ d_fprintf(stderr, _("Couldn't find group %s\n"),
+ argv[0]);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
if (rid_types.ids[0] == SID_NAME_DOM_GRP) {
return rpc_list_group_members(c, pipe_hnd, mem_ctx, domain_name,
@@ -6064,6 +6099,14 @@ static NTSTATUS rpc_trustdom_del_internals(struct net_context *c,
acct_name, nt_errstr(result) );
goto done;
}
+ if (user_rids.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
+ if (name_types.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
status = dcerpc_samr_OpenUser(b, mem_ctx,
&domain_pol,
diff --git a/source3/utils/net_rpc_join.c b/source3/utils/net_rpc_join.c
index 7167cf9f3c4..56799cdf4bd 100644
--- a/source3/utils/net_rpc_join.c
+++ b/source3/utils/net_rpc_join.c
@@ -380,6 +380,15 @@ int net_rpc_join_newstyle(struct net_context *c, int argc, const char **argv)
("error looking up rid for user %s: %s/%s\n",
acct_name, nt_errstr(status), nt_errstr(result)));
+ if (user_rids.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
+ if (name_types.count != 1) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto done;
+ }
+
if (name_types.ids[0] != SID_NAME_USER) {
DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types.ids[0]));
goto done;
diff --git a/source3/winbindd/wb_lookupsids.c b/source3/winbindd/wb_lookupsids.c
index 2c4ebda3eb7..e10d5114938 100644
--- a/source3/winbindd/wb_lookupsids.c
+++ b/source3/winbindd/wb_lookupsids.c
@@ -402,6 +402,9 @@ static bool wb_lookupsids_move_name(struct lsa_RefDomainList *src_domains,
uint32_t src_domain_index, dst_domain_index;
src_domain_index = src_name->sid_index;
+ if (src_domain_index >= src_domains->count) {
+ return false;
+ }
src_domain = &src_domains->domains[src_domain_index];
if (!wb_lookupsids_find_dom_idx(
diff --git a/source3/winbindd/winbindd_msrpc.c b/source3/winbindd/winbindd_msrpc.c
index 61447d3acf0..426d64cf1f9 100644
--- a/source3/winbindd/winbindd_msrpc.c
+++ b/source3/winbindd/winbindd_msrpc.c
@@ -744,14 +744,20 @@ static NTSTATUS msrpc_lookup_groupmem(struct winbindd_domain *domain,
/* Copy result into array. The talloc system will take
care of freeing the temporary arrays later on. */
- if (tmp_names.count != tmp_types.count) {
- return NT_STATUS_UNSUCCESSFUL;
+ if (tmp_names.count != num_lookup_rids) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ if (tmp_types.count != num_lookup_rids) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
for (r=0; r<tmp_names.count; r++) {
if (tmp_types.ids[r] == SID_NAME_UNKNOWN) {
continue;
}
+ if (total_names >= *num_names) {
+ break;
+ }
(*names)[total_names] = fill_domain_username_talloc(
mem_ctx, domain->name,
tmp_names.names[r].string, true);
diff --git a/source3/winbindd/winbindd_rpc.c b/source3/winbindd/winbindd_rpc.c
index 44deeb071c9..0986d825d9a 100644
--- a/source3/winbindd/winbindd_rpc.c
+++ b/source3/winbindd/winbindd_rpc.c
@@ -871,14 +871,20 @@ NTSTATUS rpc_lookup_groupmem(TALLOC_CTX *mem_ctx,
/* Copy result into array. The talloc system will take
care of freeing the temporary arrays later on. */
- if (tmp_names.count != tmp_types.count) {
- return NT_STATUS_UNSUCCESSFUL;
+ if (tmp_names.count != num_names) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ if (tmp_types.count != num_names) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
for (r = 0; r < tmp_names.count; r++) {
if (tmp_types.ids[r] == SID_NAME_UNKNOWN) {
continue;
}
+ if (total_names >= num_names) {
+ break;
+ }
names[total_names] = fill_domain_username_talloc(names,
domain_name,
tmp_names.names[r].string,
@@ -1063,7 +1069,7 @@ static NTSTATUS rpc_try_lookup_sids3(TALLOC_CTX *mem_ctx,
struct lsa_TransNameArray **pnames)
{
struct lsa_TransNameArray2 lsa_names2;
- struct lsa_TransNameArray *names;
+ struct lsa_TransNameArray *names = *pnames;
uint32_t i, count;
NTSTATUS status, result;
@@ -1084,10 +1090,10 @@ static NTSTATUS rpc_try_lookup_sids3(TALLOC_CTX *mem_ctx,
if (NT_STATUS_IS_ERR(result)) {
return result;
}
- names = talloc_zero(mem_ctx, struct lsa_TransNameArray);
- if (names == NULL) {
- return NT_STATUS_NO_MEMORY;
+ if (sids->num_sids != lsa_names2.count) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
+
names->count = lsa_names2.count;
names->names = talloc_array(names, struct lsa_TranslatedName,
names->count);
@@ -1099,8 +1105,17 @@ static NTSTATUS rpc_try_lookup_sids3(TALLOC_CTX *mem_ctx,
names->names[i].name.string = talloc_move(
names->names, &lsa_names2.names[i].name.string);
names->names[i].sid_index = lsa_names2.names[i].sid_index;
+
+ if (names->names[i].sid_index == UINT32_MAX) {
+ continue;
+ }
+ if ((*pdomains) == NULL) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ if (names->names[i].sid_index >= (*pdomains)->count) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
}
- *pnames = names;
return result;
}
@@ -1110,10 +1125,11 @@ NTSTATUS rpc_lookup_sids(TALLOC_CTX *mem_ctx,
struct lsa_RefDomainList **pdomains,
struct lsa_TransNameArray **pnames)
{
- struct lsa_TransNameArray *names;
+ struct lsa_TransNameArray *names = *pnames;
struct rpc_pipe_client *cli = NULL;
struct policy_handle lsa_policy;
uint32_t count;
+ uint32_t i;
NTSTATUS status, result;
status = cm_connect_lsat(domain, mem_ctx, &cli, &lsa_policy);
@@ -1126,10 +1142,6 @@ NTSTATUS rpc_lookup_sids(TALLOC_CTX *mem_ctx,
pdomains, pnames);
}
- names = talloc_zero(mem_ctx, struct lsa_TransNameArray);
- if (names == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
status = dcerpc_lsa_LookupSids(cli->binding_handle, mem_ctx,
&lsa_policy, sids, pdomains,
names, LSA_LOOKUP_NAMES_ALL,
@@ -1140,6 +1152,22 @@ NTSTATUS rpc_lookup_sids(TALLOC_CTX *mem_ctx,
if (NT_STATUS_IS_ERR(result)) {
return result;
}
- *pnames = names;
+
+ if (sids->num_sids != names->count) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ for (i=0; i < names->count; i++) {
+ if (names->names[i].sid_index == UINT32_MAX) {
+ continue;
+ }
+ if ((*pdomains) == NULL) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ if (names->names[i].sid_index >= (*pdomains)->count) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ }
+
return result;
}
diff --git a/source4/libcli/util/clilsa.c b/source4/libcli/util/clilsa.c
index 812f953ce85..0437352e757 100644
--- a/source4/libcli/util/clilsa.c
+++ b/source4/libcli/util/clilsa.c
@@ -260,7 +260,21 @@ NTSTATUS smblsa_lookup_sid(struct smbcli_state *cli,
}
if (names.count != 1) {
talloc_free(mem_ctx2);
- return NT_STATUS_UNSUCCESSFUL;
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ if (domains == NULL) {
+ talloc_free(mem_ctx2);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ if (domains->count != 1) {
+ talloc_free(mem_ctx2);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ if (names.names[0].sid_index != UINT32_MAX &&
+ names.names[0].sid_index >= domains->count)
+ {
+ talloc_free(mem_ctx2);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
(*name) = talloc_asprintf(mem_ctx, "%s\\%s",
@@ -321,7 +335,11 @@ NTSTATUS smblsa_lookup_name(struct smbcli_state *cli,
}
if (sids.count != 1) {
talloc_free(mem_ctx2);
- return NT_STATUS_UNSUCCESSFUL;
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ if (domains->count != 1) {
+ talloc_free(mem_ctx2);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
sid = domains->domains[0].sid;
diff --git a/source4/libnet/groupinfo.c b/source4/libnet/groupinfo.c
index 9060973e02e..5c8b0f734ca 100644
--- a/source4/libnet/groupinfo.c
+++ b/source4/libnet/groupinfo.c
@@ -88,11 +88,14 @@ static void continue_groupinfo_lookup(struct tevent_req *subreq)
s->monitor_fn(&msg);
}
-
/* have we actually got name resolved
- we're looking for only one at the moment */
- if (s->lookup.out.rids->count == 0) {
- composite_error(c, NT_STATUS_NO_SUCH_USER);
+ if (s->lookup.out.rids->count != s->lookup.in.num_names) {
+ composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ if (s->lookup.out.types->count != s->lookup.in.num_names) {
+ composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
return;
}
diff --git a/source4/libnet/groupman.c b/source4/libnet/groupman.c
index 9771ea54966..59a3f35d62c 100644
--- a/source4/libnet/groupman.c
+++ b/source4/libnet/groupman.c
@@ -219,13 +219,13 @@ static void continue_groupdel_name_found(struct tevent_req *subreq)
/* what to do when there's no group account to delete
and what if there's more than one rid resolved */
- if (!s->lookupname.out.rids->count) {
- c->status = NT_STATUS_NO_SUCH_GROUP;
+ if (s->lookupname.out.rids->count != s->lookupname.in.num_names) {
+ c->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
composite_error(c, c->status);
return;
-
- } else if (!s->lookupname.out.rids->count > 1) {
- c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
+ }
+ if (s->lookupname.out.types->count != s->lookupname.in.num_names) {
+ c->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
composite_error(c, c->status);
return;
}
diff --git a/source4/libnet/libnet_join.c b/source4/libnet/libnet_join.c
index 09774038fb3..8c1b57ddde1 100644
--- a/source4/libnet/libnet_join.c
+++ b/source4/libnet/libnet_join.c
@@ -656,9 +656,17 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
"samr_LookupNames for [%s] returns %d RIDs",
r->in.account_name, ln.out.rids->count);
talloc_free(tmp_ctx);
- return NT_STATUS_INVALID_PARAMETER;
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
}
-
+
+ if (ln.out.types->count != 1) {
+ r->out.error_string = talloc_asprintf(mem_ctx,
+ "samr_LookupNames for [%s] returns %d RID TYPEs",
+ r->in.account_name, ln.out.types->count);
+ talloc_free(tmp_ctx);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
/* prepare samr_OpenUser */
ZERO_STRUCTP(u_handle);
ou.in.domain_handle = &d_handle;
diff --git a/source4/libnet/libnet_lookup.c b/source4/libnet/libnet_lookup.c
index cf2d70c41df..77072b7ecce 100644
--- a/source4/libnet/libnet_lookup.c
+++ b/source4/libnet/libnet_lookup.c
@@ -365,6 +365,11 @@ static void continue_name_found(struct tevent_req *subreq)
c->status = s->lookup.out.result;
if (!composite_is_ok(c)) return;
+ if (s->lookup.out.sids->count != s->lookup.in.num_names) {
+ composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
composite_done(c);
}
diff --git a/source4/libnet/libnet_passwd.c b/source4/libnet/libnet_passwd.c
index 861d746fd11..77176bc16c7 100644
--- a/source4/libnet/libnet_passwd.c
+++ b/source4/libnet/libnet_passwd.c
@@ -627,10 +627,18 @@ static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX *
r->samr.out.error_string = talloc_asprintf(mem_ctx,
"samr_LookupNames for [%s] returns %d RIDs",
r->samr.in.account_name, ln.out.rids->count);
- status = NT_STATUS_INVALID_PARAMETER;
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
goto disconnect;
}
+ if (ln.out.types->count != 1) {
+ r->samr.out.error_string = talloc_asprintf(mem_ctx,
+ "samr_LookupNames for [%s] returns %d RID TYPEs",
+ r->samr.in.account_name, ln.out.types->count);
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto disconnect;
+ }
+
/* prepare samr_OpenUser */
ZERO_STRUCT(u_handle);
ou.in.domain_handle = &d_handle;
diff --git a/source4/libnet/userinfo.c b/source4/libnet/userinfo.c
index 75c46e477d7..9530f9efdb5 100644
--- a/source4/libnet/userinfo.c
+++ b/source4/libnet/userinfo.c
@@ -90,8 +90,12 @@ static void continue_userinfo_lookup(struct tevent_req *subreq)
/* have we actually got name resolved
- we're looking for only one at the moment */
- if (s->lookup.out.rids->count == 0) {
- composite_error(c, NT_STATUS_NO_SUCH_USER);
+ if (s->lookup.out.rids->count != s->lookup.in.num_names) {
+ composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ if (s->lookup.out.types->count != s->lookup.in.num_names) {
+ composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
return;
}
diff --git a/source4/libnet/userman.c b/source4/libnet/userman.c
index c1ee0179902..a7301eab6c6 100644
--- a/source4/libnet/userman.c
+++ b/source4/libnet/userman.c
@@ -237,14 +237,12 @@ static void continue_userdel_name_found(struct tevent_req *subreq)
/* what to do when there's no user account to delete
and what if there's more than one rid resolved */
- if (!s->lookupname.out.rids->count) {
- c->status = NT_STATUS_NO_SUCH_USER;
- composite_error(c, c->status);
+ if (s->lookupname.out.rids->count != s->lookupname.in.num_names) {
+ composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
return;
-
- } else if (!s->lookupname.out.rids->count > 1) {
- c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
- composite_error(c, c->status);
+ }
+ if (s->lookupname.out.types->count != s->lookupname.in.num_names) {
+ composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
return;
}
@@ -513,14 +511,12 @@ static void continue_usermod_name_found(struct tevent_req *subreq)
/* what to do when there's no user account to delete
and what if there's more than one rid resolved */
- if (!s->lookupname.out.rids->count) {
- c->status = NT_STATUS_NO_SUCH_USER;
- composite_error(c, c->status);
+ if (s->lookupname.out.rids->count != s->lookupname.in.num_names) {
+ composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
return;
-
- } else if (!s->lookupname.out.rids->count > 1) {
- c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
- composite_error(c, c->status);
+ }
+ if (s->lookupname.out.types->count != s->lookupname.in.num_names) {
+ composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
return;
}
diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c
index e653cbaea69..2826160a353 100644
--- a/source4/librpc/rpc/dcerpc.c
+++ b/source4/librpc/rpc/dcerpc.c
@@ -693,6 +693,10 @@ static NTSTATUS ncacn_pull(struct dcecli_connection *c, DATA_BLOB *blob, TALLOC_
return ndr_map_error2ntstatus(ndr_err);
}
+ if (pkt->frag_length != blob->length) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
return NT_STATUS_OK;
}
diff --git a/source4/librpc/rpc/dcerpc_smb.c b/source4/librpc/rpc/dcerpc_smb.c
index e02631e2b11..efb76cf89d7 100644
--- a/source4/librpc/rpc/dcerpc_smb.c
+++ b/source4/librpc/rpc/dcerpc_smb.c
@@ -163,6 +163,12 @@ static NTSTATUS send_read_request_continue(struct dcecli_connection *c, DATA_BLO
} else {
uint32_t frag_length = blob->length>=16?
dcerpc_get_frag_length(blob):0x2000;
+
+ if (frag_length < state->data.length) {
+ talloc_free(state);
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
state->received = blob->length;
state->data = data_blob_talloc(state, NULL, frag_length);
if (!state->data.data) {
diff --git a/source4/librpc/rpc/dcerpc_smb2.c b/source4/librpc/rpc/dcerpc_smb2.c
index 473ca78ad1d..2b1c66e232f 100644
--- a/source4/librpc/rpc/dcerpc_smb2.c
+++ b/source4/librpc/rpc/dcerpc_smb2.c
@@ -173,6 +173,12 @@ static NTSTATUS send_read_request_continue(struct dcecli_connection *c, DATA_BLO
if (state->data.length >= 16) {
uint16_t frag_length = dcerpc_get_frag_length(&state->data);
+
+ if (frag_length < state->data.length) {
+ talloc_free(state);
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
io.in.length = frag_length - state->data.length;
} else {
io.in.length = 0x2000;
diff --git a/source4/librpc/rpc/dcerpc_sock.c b/source4/librpc/rpc/dcerpc_sock.c
index 58fca4ce372..d36af11e923 100644
--- a/source4/librpc/rpc/dcerpc_sock.c
+++ b/source4/librpc/rpc/dcerpc_sock.c
@@ -102,6 +102,12 @@ static NTSTATUS sock_complete_packet(void *private_data, DATA_BLOB blob, size_t
return STATUS_MORE_ENTRIES;
}
*size = dcerpc_get_frag_length(&blob);
+ if (*size < blob.length) {
+ /*
+ * something is wrong, let the caller deal with it
+ */
+ *size = blob.length;
+ }
if (*size > blob.length) {
return STATUS_MORE_ENTRIES;
}
diff --git a/source4/winbind/wb_async_helpers.c b/source4/winbind/wb_async_helpers.c
index 2af8567fd4c..2a05f124656 100644
--- a/source4/winbind/wb_async_helpers.c
+++ b/source4/winbind/wb_async_helpers.c
@@ -122,6 +122,12 @@ static void lsa_lookupsids_recv_names(struct tevent_req *subreq)
return;
}
+ if (state->names.count != state->num_sids) {
+ composite_error(state->ctx,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
state->result = talloc_array(state, struct wb_sid_object *,
state->num_sids);
if (composite_nomem(state->result, state->ctx)) return;
@@ -142,9 +148,14 @@ static void lsa_lookupsids_recv_names(struct tevent_req *subreq)
continue;
}
+ if (domains == NULL) {
+ composite_error(state->ctx,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
if (name->sid_index >= domains->count) {
composite_error(state->ctx,
- NT_STATUS_INVALID_PARAMETER);
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
return;
}
@@ -274,6 +285,12 @@ static void lsa_lookupnames_recv_sids(struct tevent_req *subreq)
return;
}
+ if (state->sids.count != state->num_names) {
+ composite_error(state->ctx,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
state->result = talloc_array(state, struct wb_sid_object *,
state->num_names);
if (composite_nomem(state->result, state->ctx)) return;
@@ -292,9 +309,14 @@ static void lsa_lookupnames_recv_sids(struct tevent_req *subreq)
continue;
}
+ if (domains == NULL) {
+ composite_error(state->ctx,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
if (sid->sid_index >= domains->count) {
composite_error(state->ctx,
- NT_STATUS_INVALID_PARAMETER);
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
return;
}