summaryrefslogtreecommitdiffstats
path: root/libcli
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
commit8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch)
tree4099e8021376c7d8c05bdf8503093d80e9c7bad0 /libcli
parentInitial commit. (diff)
downloadsamba-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 'libcli')
-rw-r--r--libcli/auth/credentials.c1222
-rw-r--r--libcli/auth/credentials.h70
-rw-r--r--libcli/auth/libcli_auth.h28
-rw-r--r--libcli/auth/msrpc_parse.c409
-rw-r--r--libcli/auth/msrpc_parse.h58
-rw-r--r--libcli/auth/netlogon_creds_cli.c4256
-rw-r--r--libcli/auth/netlogon_creds_cli.h236
-rw-r--r--libcli/auth/ntlm_check.c656
-rw-r--r--libcli/auth/ntlm_check.h87
-rw-r--r--libcli/auth/pam_errors.c143
-rw-r--r--libcli/auth/pam_errors.h33
-rw-r--r--libcli/auth/proto.h296
-rw-r--r--libcli/auth/schannel.h25
-rw-r--r--libcli/auth/schannel_proto.h31
-rw-r--r--libcli/auth/schannel_state.h54
-rw-r--r--libcli/auth/schannel_state_tdb.c646
-rw-r--r--libcli/auth/session.c247
-rw-r--r--libcli/auth/smbdes.c213
-rw-r--r--libcli/auth/smbencrypt.c1325
-rw-r--r--libcli/auth/spnego.h82
-rw-r--r--libcli/auth/spnego_parse.c446
-rw-r--r--libcli/auth/spnego_proto.h28
-rw-r--r--libcli/auth/tests/ntlm_check.c413
-rw-r--r--libcli/auth/tests/test_encode_decode.c162
-rw-r--r--libcli/auth/tests/test_gnutls.c524
-rw-r--r--libcli/auth/tests/test_rc4_passwd_buffer.c336
-rw-r--r--libcli/auth/tests/test_schannel.c305
-rw-r--r--libcli/auth/wscript_build100
-rw-r--r--libcli/cldap/cldap.c1209
-rw-r--r--libcli/cldap/cldap.h134
-rw-r--r--libcli/cldap/wscript_build10
-rw-r--r--libcli/dns/dns.c591
-rw-r--r--libcli/dns/dns.h64
-rw-r--r--libcli/dns/dns_lookup.c374
-rw-r--r--libcli/dns/dns_lookup.h48
-rw-r--r--libcli/dns/dns_lookuptest.c55
-rw-r--r--libcli/dns/libdns.h43
-rw-r--r--libcli/dns/resolvconf.c123
-rw-r--r--libcli/dns/resolvconf.h37
-rw-r--r--libcli/dns/resolvconftest.c82
-rw-r--r--libcli/dns/wscript_build21
-rw-r--r--libcli/drsuapi/drsuapi.h32
-rw-r--r--libcli/drsuapi/repl_decrypt.c391
-rw-r--r--libcli/drsuapi/tests/test_repl_decrypt.c522
-rw-r--r--libcli/drsuapi/wscript_build19
-rw-r--r--libcli/echo/echo.c209
-rw-r--r--libcli/echo/libecho.h56
-rw-r--r--libcli/echo/tests/echo.c97
-rw-r--r--libcli/echo/tests/wscript_build8
-rw-r--r--libcli/echo/wscript_build7
-rw-r--r--libcli/http/gensec/basic.c204
-rw-r--r--libcli/http/gensec/generic.c286
-rw-r--r--libcli/http/http.c882
-rw-r--r--libcli/http/http.h143
-rw-r--r--libcli/http/http_auth.c383
-rw-r--r--libcli/http/http_conn.c347
-rw-r--r--libcli/http/http_internal.h50
-rw-r--r--libcli/http/wscript_build21
-rw-r--r--libcli/ldap/ldap_errors.h68
-rw-r--r--libcli/ldap/ldap_message.c1673
-rw-r--r--libcli/ldap/ldap_message.h244
-rw-r--r--libcli/ldap/ldap_ndr.c95
-rw-r--r--libcli/ldap/ldap_ndr.h34
-rw-r--r--libcli/ldap/tests/data/10000-or.datbin0 -> 39875 bytes
-rw-r--r--libcli/ldap/tests/data/ldap-recursive.datbin0 -> 970 bytes
-rw-r--r--libcli/ldap/tests/data/ldap-starttls-response.datbin0 -> 38 bytes
-rw-r--r--libcli/ldap/tests/ldap_message_test.c345
-rw-r--r--libcli/ldap/wscript_build23
-rw-r--r--libcli/lsarpc/util_lsarpc.c359
-rw-r--r--libcli/lsarpc/util_lsarpc.h38
-rw-r--r--libcli/lsarpc/wscript_build5
-rw-r--r--libcli/named_pipe_auth/npa_tstream.c1406
-rw-r--r--libcli/named_pipe_auth/npa_tstream.h145
-rw-r--r--libcli/named_pipe_auth/tstream_u32_read.c159
-rw-r--r--libcli/named_pipe_auth/tstream_u32_read.h37
-rw-r--r--libcli/named_pipe_auth/wscript_build9
-rw-r--r--libcli/nbt/libnbt.h377
-rw-r--r--libcli/nbt/lmhosts.c243
-rw-r--r--libcli/nbt/man/nmblookup4.1.xml213
-rw-r--r--libcli/nbt/namequery.c234
-rw-r--r--libcli/nbt/namerefresh.c347
-rw-r--r--libcli/nbt/nameregister.c514
-rw-r--r--libcli/nbt/namerelease.c134
-rw-r--r--libcli/nbt/nbt_proto.h65
-rw-r--r--libcli/nbt/nbtname.c486
-rw-r--r--libcli/nbt/nbtsocket.c566
-rw-r--r--libcli/nbt/pynbt.c447
-rw-r--r--libcli/nbt/tools/nmblookup.c477
-rw-r--r--libcli/nbt/wscript_build32
-rw-r--r--libcli/netlogon/netlogon.c285
-rw-r--r--libcli/netlogon/netlogon.h41
-rw-r--r--libcli/netlogon/netlogon_proto.h28
-rw-r--r--libcli/netlogon/wscript_build6
-rw-r--r--libcli/registry/util_reg.c138
-rw-r--r--libcli/registry/util_reg.h32
-rw-r--r--libcli/registry/wscript_build5
-rw-r--r--libcli/samsync/decrypt.c209
-rw-r--r--libcli/samsync/samsync.h36
-rw-r--r--libcli/samsync/wscript_build8
-rw-r--r--libcli/security/access_check.c958
-rw-r--r--libcli/security/access_check.h100
-rw-r--r--libcli/security/claims-conversions.c1216
-rw-r--r--libcli/security/claims-conversions.h60
-rw-r--r--libcli/security/conditional_ace.c2550
-rw-r--r--libcli/security/conditional_ace.h97
-rw-r--r--libcli/security/create_descriptor.c666
-rw-r--r--libcli/security/display_sec.c274
-rw-r--r--libcli/security/display_sec.h34
-rw-r--r--libcli/security/dom_sid.c582
-rw-r--r--libcli/security/dom_sid.h155
-rw-r--r--libcli/security/object_tree.c127
-rw-r--r--libcli/security/privileges.c498
-rw-r--r--libcli/security/privileges.h116
-rw-r--r--libcli/security/privileges_private.h41
-rw-r--r--libcli/security/pysecurity.c96
-rw-r--r--libcli/security/sddl.c1341
-rw-r--r--libcli/security/sddl.h47
-rw-r--r--libcli/security/sddl_conditional_ace.c3476
-rw-r--r--libcli/security/secace.c204
-rw-r--r--libcli/security/secace.h40
-rw-r--r--libcli/security/secacl.c75
-rw-r--r--libcli/security/secacl.h33
-rw-r--r--libcli/security/secdesc.c623
-rw-r--r--libcli/security/secdesc.h96
-rw-r--r--libcli/security/security.h121
-rw-r--r--libcli/security/security_descriptor.c908
-rw-r--r--libcli/security/security_descriptor.h99
-rw-r--r--libcli/security/security_token.c228
-rw-r--r--libcli/security/security_token.h74
-rw-r--r--libcli/security/session.c74
-rw-r--r--libcli/security/session.h44
-rw-r--r--libcli/security/tests/data/conditional_aces.txt83
-rw-r--r--libcli/security/tests/data/conditional_aces.txt.json1
-rw-r--r--libcli/security/tests/data/conditional_aces_case_insensitive.txt1
-rw-r--r--libcli/security/tests/data/conditional_aces_should_fail.txt14
-rw-r--r--libcli/security/tests/data/conditional_aces_windows_only.txt14
-rwxr-xr-xlibcli/security/tests/data/export-sddl-fuzz-seeds-as-json49
-rwxr-xr-xlibcli/security/tests/data/extract-sddl-seeds72
-rw-r--r--libcli/security/tests/data/ndr_dumps/fileb5iJt4bin0 -> 118 bytes
-rw-r--r--libcli/security/tests/data/ndr_dumps/fileb8cNVSbin0 -> 360 bytes
-rw-r--r--libcli/security/tests/data/ndr_dumps/filebI7h5Hbin0 -> 112 bytes
-rw-r--r--libcli/security/tests/data/ndr_dumps/filebNdBgtbin0 -> 344 bytes
-rw-r--r--libcli/security/tests/data/ndr_dumps/filebOjK4Hbin0 -> 124 bytes
-rw-r--r--libcli/security/tests/data/ndr_dumps/filebzCPTHbin0 -> 480 bytes
-rw-r--r--libcli/security/tests/data/oversize-acls.json20
-rw-r--r--libcli/security/tests/data/registry-object-rights.json1
-rw-r--r--libcli/security/tests/data/short-conditional-and-resource-aces-successes.json.gzbin0 -> 17815 bytes
-rw-r--r--libcli/security/tests/data/short-conditional-and-resource-aces-tx-int.json.gzbin0 -> 2183 bytes
-rw-r--r--libcli/security/tests/data/short-ordinary-acls-v2.json.gzbin0 -> 7223 bytes
-rw-r--r--libcli/security/tests/data/short-ordinary-acls.json.gzbin0 -> 220742 bytes
-rw-r--r--libcli/security/tests/test_claim_conversion.c171
-rw-r--r--libcli/security/tests/test_run_conditional_ace.c730
-rw-r--r--libcli/security/tests/test_sddl_conditional_ace.c1003
-rw-r--r--libcli/security/tests/windows/canonical.txt19
-rw-r--r--libcli/security/tests/windows/conditional_aces.txt.json1
-rw-r--r--libcli/security/tests/windows/non_canonical.txt50
-rw-r--r--libcli/security/tests/windows/should_fail.txt47
-rw-r--r--libcli/security/tests/windows/windows-sddl-tests.c341
-rw-r--r--libcli/security/tests/windows/windows-sddl-tests.py181
-rw-r--r--libcli/security/tests/windows/windows_is_fussy.txt1
-rw-r--r--libcli/security/tests/windows/windows_is_less_fussy.txt23
-rw-r--r--libcli/security/tests/windows/windows_is_weird.txt10
-rw-r--r--libcli/security/util_sid.c1117
-rw-r--r--libcli/security/wscript_build64
-rw-r--r--libcli/smb/py_reparse_symlink.c198
-rw-r--r--libcli/smb/read_smb.c114
-rw-r--r--libcli/smb/read_smb.h33
-rw-r--r--libcli/smb/reparse.c567
-rw-r--r--libcli/smb/reparse.h77
-rw-r--r--libcli/smb/smb1cli_close.c188
-rw-r--r--libcli/smb/smb1cli_create.c296
-rw-r--r--libcli/smb/smb1cli_echo.c169
-rw-r--r--libcli/smb/smb1cli_read.c241
-rw-r--r--libcli/smb/smb1cli_session.c821
-rw-r--r--libcli/smb/smb1cli_trans.c908
-rw-r--r--libcli/smb/smb1cli_write.c284
-rw-r--r--libcli/smb/smb2_constants.h317
-rw-r--r--libcli/smb/smb2_create_blob.c227
-rw-r--r--libcli/smb/smb2_create_blob.h75
-rw-r--r--libcli/smb/smb2_create_ctx.h47
-rw-r--r--libcli/smb/smb2_lease.c102
-rw-r--r--libcli/smb/smb2_lease.h43
-rw-r--r--libcli/smb/smb2_lock.h32
-rw-r--r--libcli/smb/smb2_negotiate_context.c203
-rw-r--r--libcli/smb/smb2_negotiate_context.h92
-rw-r--r--libcli/smb/smb2_posix.c51
-rw-r--r--libcli/smb/smb2_posix.h36
-rw-r--r--libcli/smb/smb2_signing.c1110
-rw-r--r--libcli/smb/smb2_signing.h102
-rw-r--r--libcli/smb/smb2cli_close.c136
-rw-r--r--libcli/smb/smb2cli_create.c580
-rw-r--r--libcli/smb/smb2cli_echo.c122
-rw-r--r--libcli/smb/smb2cli_flush.c133
-rw-r--r--libcli/smb/smb2cli_ioctl.c519
-rw-r--r--libcli/smb/smb2cli_notify.c236
-rw-r--r--libcli/smb/smb2cli_query_directory.c210
-rw-r--r--libcli/smb/smb2cli_query_info.c266
-rw-r--r--libcli/smb/smb2cli_read.c218
-rw-r--r--libcli/smb/smb2cli_session.c350
-rw-r--r--libcli/smb/smb2cli_set_info.c183
-rw-r--r--libcli/smb/smb2cli_tcon.c461
-rw-r--r--libcli/smb/smb2cli_write.c183
-rw-r--r--libcli/smb/smbXcli_base.c7034
-rw-r--r--libcli/smb/smbXcli_base.h969
-rw-r--r--libcli/smb/smb_common.h34
-rw-r--r--libcli/smb/smb_constants.h649
-rw-r--r--libcli/smb/smb_seal.c220
-rw-r--r--libcli/smb/smb_seal.h37
-rw-r--r--libcli/smb/smb_signing.c552
-rw-r--r--libcli/smb/smb_signing.h58
-rw-r--r--libcli/smb/smb_unix_ext.h458
-rw-r--r--libcli/smb/smb_util.h57
-rw-r--r--libcli/smb/test_smb1cli_session.c216
-rw-r--r--libcli/smb/test_util_translate.c83
-rw-r--r--libcli/smb/tstream_smbXcli_np.c1399
-rw-r--r--libcli/smb/tstream_smbXcli_np.h75
-rw-r--r--libcli/smb/util.c716
-rw-r--r--libcli/smb/wscript86
-rw-r--r--libcli/smbreadline/smbreadline.c184
-rw-r--r--libcli/smbreadline/smbreadline.h30
-rw-r--r--libcli/smbreadline/wscript_build8
-rw-r--r--libcli/smbreadline/wscript_configure85
-rw-r--r--libcli/tstream_binding_handle/tstream_binding_handle.c341
-rw-r--r--libcli/tstream_binding_handle/tstream_binding_handle.h37
-rw-r--r--libcli/tstream_binding_handle/wscript_build5
-rw-r--r--libcli/util/doserr.c147
-rw-r--r--libcli/util/doserr.h176
-rw-r--r--libcli/util/errmap_unix.c297
-rw-r--r--libcli/util/error.h59
-rw-r--r--libcli/util/errormap.c1246
-rw-r--r--libcli/util/hresult_err_table.txt20520
-rw-r--r--libcli/util/nterr.c377
-rw-r--r--libcli/util/ntstatus.h199
-rw-r--r--libcli/util/ntstatus_err_table.txt12629
-rw-r--r--libcli/util/tstream.c205
-rw-r--r--libcli/util/tstream.h123
-rw-r--r--libcli/util/werror.h171
-rw-r--r--libcli/util/werror_err_table.txt18949
-rw-r--r--libcli/util/wscript_build58
-rw-r--r--libcli/wsp/test_wsp_parser.c402
-rw-r--r--libcli/wsp/wscript_build41
-rw-r--r--libcli/wsp/wsp_aqs.c877
-rw-r--r--libcli/wsp/wsp_aqs.h166
-rw-r--r--libcli/wsp/wsp_aqs_lexer.l152
-rw-r--r--libcli/wsp/wsp_aqs_parser.y422
245 files changed, 127987 insertions, 0 deletions
diff --git a/libcli/auth/credentials.c b/libcli/auth/credentials.c
new file mode 100644
index 0000000..84838be
--- /dev/null
+++ b/libcli/auth/credentials.c
@@ -0,0 +1,1222 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ code to manipulate domain credentials
+
+ Copyright (C) Andrew Tridgell 1997-2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
+
+ 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 "system/time.h"
+#include "libcli/auth/libcli_auth.h"
+#include "../libcli/security/dom_sid.h"
+#include "lib/util/util_str_escape.h"
+
+#include "lib/crypto/gnutls_helpers.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+bool netlogon_creds_is_random_challenge(const struct netr_Credential *challenge)
+{
+ /*
+ * If none of the first 5 bytes of the client challenge is unique, the
+ * server MUST fail session-key negotiation without further processing
+ * of the following steps.
+ */
+
+ if (challenge->data[1] == challenge->data[0] &&
+ challenge->data[2] == challenge->data[0] &&
+ challenge->data[3] == challenge->data[0] &&
+ challenge->data[4] == challenge->data[0])
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void netlogon_creds_random_challenge(struct netr_Credential *challenge)
+{
+ ZERO_STRUCTP(challenge);
+ while (!netlogon_creds_is_random_challenge(challenge)) {
+ generate_random_buffer(challenge->data, sizeof(challenge->data));
+ }
+}
+
+static NTSTATUS netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds,
+ const struct netr_Credential *in,
+ struct netr_Credential *out)
+{
+ NTSTATUS status;
+ int rc;
+
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ memcpy(out->data, in->data, sizeof(out->data));
+
+ status = netlogon_creds_aes_encrypt(creds,
+ out->data,
+ sizeof(out->data));
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ } else {
+ rc = des_crypt112(out->data, in->data, creds->session_key, SAMBA_GNUTLS_ENCRYPT);
+ if (rc != 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ initialise the credentials state for old-style 64 bit session keys
+
+ this call is made after the netr_ServerReqChallenge call
+*/
+static NTSTATUS netlogon_creds_init_64bit(struct netlogon_creds_CredentialState *creds,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge,
+ const struct samr_Password *machine_password)
+{
+ uint32_t sum[2];
+ uint8_t sum2[8];
+ int rc;
+
+ sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
+ sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
+
+ SIVAL(sum2,0,sum[0]);
+ SIVAL(sum2,4,sum[1]);
+
+ ZERO_ARRAY(creds->session_key);
+
+ rc = des_crypt128(creds->session_key, sum2, machine_password->hash);
+ if (rc != 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ initialise the credentials state for ADS-style 128 bit session keys
+
+ this call is made after the netr_ServerReqChallenge call
+*/
+static NTSTATUS netlogon_creds_init_128bit(struct netlogon_creds_CredentialState *creds,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge,
+ const struct samr_Password *machine_password)
+{
+ uint8_t zero[4] = {0};
+ uint8_t tmp[gnutls_hash_get_len(GNUTLS_DIG_MD5)];
+ gnutls_hash_hd_t hash_hnd = NULL;
+ int rc;
+
+ ZERO_ARRAY(creds->session_key);
+
+ rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+
+ rc = gnutls_hash(hash_hnd, zero, sizeof(zero));
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+ rc = gnutls_hash(hash_hnd, client_challenge->data, 8);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+ rc = gnutls_hash(hash_hnd, server_challenge->data, 8);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+
+ gnutls_hash_deinit(hash_hnd, tmp);
+
+ /* This doesn't require HMAC MD5 RFC2104 as the hash is only 16 bytes */
+ rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
+ machine_password->hash,
+ sizeof(machine_password->hash),
+ tmp,
+ sizeof(tmp),
+ creds->session_key);
+ ZERO_ARRAY(tmp);
+
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ initialise the credentials state for AES/HMAC-SHA256-style 128 bit session keys
+
+ this call is made after the netr_ServerReqChallenge call
+*/
+static NTSTATUS netlogon_creds_init_hmac_sha256(struct netlogon_creds_CredentialState *creds,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge,
+ const struct samr_Password *machine_password)
+{
+ gnutls_hmac_hd_t hmac_hnd = NULL;
+ uint8_t digest[gnutls_hmac_get_len(GNUTLS_MAC_SHA256)];
+ int rc;
+
+ ZERO_ARRAY(creds->session_key);
+
+ rc = gnutls_hmac_init(&hmac_hnd,
+ GNUTLS_MAC_SHA256,
+ machine_password->hash,
+ sizeof(machine_password->hash));
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+ rc = gnutls_hmac(hmac_hnd,
+ client_challenge->data,
+ 8);
+ if (rc < 0) {
+ gnutls_hmac_deinit(hmac_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+ rc = gnutls_hmac(hmac_hnd,
+ server_challenge->data,
+ 8);
+ if (rc < 0) {
+ gnutls_hmac_deinit(hmac_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+ gnutls_hmac_deinit(hmac_hnd, digest);
+
+ memcpy(creds->session_key, digest, sizeof(creds->session_key));
+
+ ZERO_ARRAY(digest);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS netlogon_creds_first_step(struct netlogon_creds_CredentialState *creds,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge)
+{
+ NTSTATUS status;
+
+ status = netlogon_creds_step_crypt(creds,
+ client_challenge,
+ &creds->client);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = netlogon_creds_step_crypt(creds,
+ server_challenge,
+ &creds->server);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ creds->seed = creds->client;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ step the credentials to the next element in the chain, updating the
+ current client and server credentials and the seed
+*/
+static NTSTATUS netlogon_creds_step(struct netlogon_creds_CredentialState *creds)
+{
+ struct netr_Credential time_cred;
+ NTSTATUS status;
+
+ DEBUG(5,("\tseed %08x:%08x\n",
+ IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
+
+ SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
+ SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
+
+ DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
+
+ status = netlogon_creds_step_crypt(creds,
+ &time_cred,
+ &creds->client);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(5,("\tCLIENT %08x:%08x\n",
+ IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
+
+ SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
+ SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
+
+ DEBUG(5,("\tseed+time+1 %08x:%08x\n",
+ IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
+
+ status = netlogon_creds_step_crypt(creds, &time_cred, &creds->server);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(5,("\tSERVER %08x:%08x\n",
+ IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
+
+ creds->seed = time_cred;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
+*/
+NTSTATUS netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds,
+ struct netr_LMSessionKey *key)
+{
+ int rc;
+ struct netr_LMSessionKey tmp;
+
+ rc = des_crypt56_gnutls(tmp.key, key->key, creds->session_key, SAMBA_GNUTLS_ENCRYPT);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ *key = tmp;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
+*/
+NTSTATUS netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds,
+ struct netr_LMSessionKey *key)
+{
+ int rc;
+ struct netr_LMSessionKey tmp;
+
+ rc = des_crypt56_gnutls(tmp.key, key->key, creds->session_key, SAMBA_GNUTLS_DECRYPT);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ *key = tmp;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ DES encrypt a 16 byte password buffer using the session key
+*/
+NTSTATUS netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState *creds,
+ struct samr_Password *pass)
+{
+ struct samr_Password tmp;
+ int rc;
+
+ rc = des_crypt112_16(tmp.hash, pass->hash, creds->session_key, SAMBA_GNUTLS_ENCRYPT);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ *pass = tmp;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ DES decrypt a 16 byte password buffer using the session key
+*/
+NTSTATUS netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState *creds,
+ struct samr_Password *pass)
+{
+ struct samr_Password tmp;
+ int rc;
+
+ rc = des_crypt112_16(tmp.hash, pass->hash, creds->session_key, SAMBA_GNUTLS_DECRYPT);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ *pass = tmp;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ ARCFOUR encrypt/decrypt a password buffer using the session key
+*/
+NTSTATUS netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState *creds,
+ uint8_t *data,
+ size_t len)
+{
+ gnutls_cipher_hd_t cipher_hnd = NULL;
+ gnutls_datum_t session_key = {
+ .data = creds->session_key,
+ .size = sizeof(creds->session_key),
+ };
+ int rc;
+
+ rc = gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_ARCFOUR_128,
+ &session_key,
+ NULL);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_CRYPTO_SYSTEM_INVALID);
+ }
+ rc = gnutls_cipher_encrypt(cipher_hnd,
+ data,
+ len);
+ gnutls_cipher_deinit(cipher_hnd);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_CRYPTO_SYSTEM_INVALID);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ AES encrypt a password buffer using the session key
+*/
+NTSTATUS netlogon_creds_aes_encrypt(struct netlogon_creds_CredentialState *creds,
+ uint8_t *data,
+ size_t len)
+{
+ gnutls_cipher_hd_t cipher_hnd = NULL;
+ gnutls_datum_t key = {
+ .data = creds->session_key,
+ .size = sizeof(creds->session_key),
+ };
+ uint32_t iv_size =
+ gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8);
+ uint8_t _iv[iv_size];
+ gnutls_datum_t iv = {
+ .data = _iv,
+ .size = iv_size,
+ };
+ int rc;
+
+ ZERO_ARRAY(_iv);
+
+ rc = gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_AES_128_CFB8,
+ &key,
+ &iv);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
+ }
+
+ rc = gnutls_cipher_encrypt(cipher_hnd, data, len);
+ gnutls_cipher_deinit(cipher_hnd);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ AES decrypt a password buffer using the session key
+*/
+NTSTATUS netlogon_creds_aes_decrypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
+{
+ gnutls_cipher_hd_t cipher_hnd = NULL;
+ gnutls_datum_t key = {
+ .data = creds->session_key,
+ .size = sizeof(creds->session_key),
+ };
+ uint32_t iv_size =
+ gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8);
+ uint8_t _iv[iv_size];
+ gnutls_datum_t iv = {
+ .data = _iv,
+ .size = iv_size,
+ };
+ int rc;
+
+ ZERO_ARRAY(_iv);
+
+ rc = gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_AES_128_CFB8,
+ &key,
+ &iv);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_CRYPTO_SYSTEM_INVALID);
+ }
+
+ rc = gnutls_cipher_decrypt(cipher_hnd, data, len);
+ gnutls_cipher_deinit(cipher_hnd);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_CRYPTO_SYSTEM_INVALID);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*****************************************************************
+The above functions are common to the client and server interface
+next comes the client specific functions
+******************************************************************/
+
+/*
+ initialise the credentials chain and return the first client
+ credentials
+*/
+
+struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *mem_ctx,
+ const char *client_account,
+ const char *client_computer_name,
+ uint16_t secure_channel_type,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge,
+ const struct samr_Password *machine_password,
+ struct netr_Credential *initial_credential,
+ uint32_t negotiate_flags)
+{
+ struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
+ NTSTATUS status;
+
+ if (!creds) {
+ return NULL;
+ }
+
+ creds->sequence = time(NULL);
+ creds->negotiate_flags = negotiate_flags;
+ creds->secure_channel_type = secure_channel_type;
+
+ creds->computer_name = talloc_strdup(creds, client_computer_name);
+ if (!creds->computer_name) {
+ talloc_free(creds);
+ return NULL;
+ }
+ creds->account_name = talloc_strdup(creds, client_account);
+ if (!creds->account_name) {
+ talloc_free(creds);
+ return NULL;
+ }
+
+ dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
+ dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
+ dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
+
+ if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ status = netlogon_creds_init_hmac_sha256(creds,
+ client_challenge,
+ server_challenge,
+ machine_password);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(creds);
+ return NULL;
+ }
+ } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
+ status = netlogon_creds_init_128bit(creds,
+ client_challenge,
+ server_challenge,
+ machine_password);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(creds);
+ return NULL;
+ }
+ } else {
+ status = netlogon_creds_init_64bit(creds,
+ client_challenge,
+ server_challenge,
+ machine_password);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(creds);
+ return NULL;
+ }
+ }
+
+ status = netlogon_creds_first_step(creds,
+ client_challenge,
+ server_challenge);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(creds);
+ return NULL;
+ }
+
+ dump_data_pw("Session key", creds->session_key, 16);
+ dump_data_pw("Credential ", creds->client.data, 8);
+
+ *initial_credential = creds->client;
+ return creds;
+}
+
+/*
+ initialise the credentials structure with only a session key. The caller better know what they are doing!
+ */
+
+struct netlogon_creds_CredentialState *netlogon_creds_client_init_session_key(TALLOC_CTX *mem_ctx,
+ const uint8_t session_key[16])
+{
+ struct netlogon_creds_CredentialState *creds;
+
+ creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
+ if (!creds) {
+ return NULL;
+ }
+
+ memcpy(creds->session_key, session_key, 16);
+
+ return creds;
+}
+
+/*
+ step the credentials to the next element in the chain, updating the
+ current client and server credentials and the seed
+
+ produce the next authenticator in the sequence ready to send to
+ the server
+*/
+NTSTATUS
+netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds,
+ struct netr_Authenticator *next)
+{
+ uint32_t t32n = (uint32_t)time(NULL);
+ NTSTATUS status;
+
+ /*
+ * we always increment and ignore an overflow here
+ */
+ creds->sequence += 2;
+
+ if (t32n > creds->sequence) {
+ /*
+ * we may increment more
+ */
+ creds->sequence = t32n;
+ } else {
+ uint32_t d = creds->sequence - t32n;
+
+ if (d >= INT32_MAX) {
+ /*
+ * got an overflow of time_t vs. uint32_t
+ */
+ creds->sequence = t32n;
+ }
+ }
+
+ status = netlogon_creds_step(creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ next->cred = creds->client;
+ next->timestamp = creds->sequence;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ check that a credentials reply from a server is correct
+*/
+bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds,
+ const struct netr_Credential *received_credentials)
+{
+ if (!received_credentials ||
+ !mem_equal_const_time(received_credentials->data, creds->server.data, 8)) {
+ DEBUG(2,("credentials check failed\n"));
+ return false;
+ }
+ return true;
+}
+
+
+/*****************************************************************
+The above functions are common to the client and server interface
+next comes the server specific functions
+******************************************************************/
+
+/*
+ check that a credentials reply from a server is correct
+*/
+static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState *creds,
+ const struct netr_Credential *received_credentials)
+{
+ if (!mem_equal_const_time(received_credentials->data, creds->client.data, 8)) {
+ DEBUG(2,("credentials check failed\n"));
+ dump_data_pw("client creds", creds->client.data, 8);
+ dump_data_pw("calc creds", received_credentials->data, 8);
+ return false;
+ }
+ return true;
+}
+
+/*
+ initialise the credentials chain and return the first server
+ credentials
+*/
+struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *mem_ctx,
+ const char *client_account,
+ const char *client_computer_name,
+ uint16_t secure_channel_type,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge,
+ const struct samr_Password *machine_password,
+ const struct netr_Credential *credentials_in,
+ struct netr_Credential *credentials_out,
+ uint32_t negotiate_flags)
+{
+
+ struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
+ NTSTATUS status;
+ bool ok;
+
+ if (!creds) {
+ return NULL;
+ }
+
+ creds->negotiate_flags = negotiate_flags;
+ creds->secure_channel_type = secure_channel_type;
+
+ dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
+ dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
+ dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
+
+ ok = netlogon_creds_is_random_challenge(client_challenge);
+ if (!ok) {
+ DBG_WARNING("CVE-2020-1472(ZeroLogon): "
+ "non-random client challenge rejected for "
+ "client_account[%s] client_computer_name[%s]\n",
+ log_escape(mem_ctx, client_account),
+ log_escape(mem_ctx, client_computer_name));
+ dump_data(DBGLVL_WARNING,
+ client_challenge->data,
+ sizeof(client_challenge->data));
+ talloc_free(creds);
+ return NULL;
+ }
+
+ creds->computer_name = talloc_strdup(creds, client_computer_name);
+ if (!creds->computer_name) {
+ talloc_free(creds);
+ return NULL;
+ }
+ creds->account_name = talloc_strdup(creds, client_account);
+ if (!creds->account_name) {
+ talloc_free(creds);
+ return NULL;
+ }
+
+ if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ status = netlogon_creds_init_hmac_sha256(creds,
+ client_challenge,
+ server_challenge,
+ machine_password);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(creds);
+ return NULL;
+ }
+ } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
+ status = netlogon_creds_init_128bit(creds,
+ client_challenge,
+ server_challenge,
+ machine_password);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(creds);
+ return NULL;
+ }
+ } else {
+ status = netlogon_creds_init_64bit(creds,
+ client_challenge,
+ server_challenge,
+ machine_password);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(creds);
+ return NULL;
+ }
+ }
+
+ status = netlogon_creds_first_step(creds,
+ client_challenge,
+ server_challenge);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(creds);
+ return NULL;
+ }
+
+ dump_data_pw("Session key", creds->session_key, 16);
+ dump_data_pw("Client Credential ", creds->client.data, 8);
+ dump_data_pw("Server Credential ", creds->server.data, 8);
+
+ dump_data_pw("Credentials in", credentials_in->data, sizeof(credentials_in->data));
+
+ /* And before we leak information about the machine account
+ * password, check that they got the first go right */
+ if (!netlogon_creds_server_check_internal(creds, credentials_in)) {
+ talloc_free(creds);
+ return NULL;
+ }
+
+ *credentials_out = creds->server;
+
+ dump_data_pw("Credentials out", credentials_out->data, sizeof(credentials_out->data));
+
+ return creds;
+}
+
+NTSTATUS netlogon_creds_server_step_check(struct netlogon_creds_CredentialState *creds,
+ const struct netr_Authenticator *received_authenticator,
+ struct netr_Authenticator *return_authenticator)
+{
+ NTSTATUS status;
+
+ if (!received_authenticator || !return_authenticator) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!creds) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ creds->sequence = received_authenticator->timestamp;
+ status = netlogon_creds_step(creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ ZERO_STRUCTP(return_authenticator);
+ return status;
+ }
+
+ if (netlogon_creds_server_check_internal(creds, &received_authenticator->cred)) {
+ return_authenticator->cred = creds->server;
+ return_authenticator->timestamp = 0;
+ return NT_STATUS_OK;
+ } else {
+ ZERO_STRUCTP(return_authenticator);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+}
+
+static NTSTATUS netlogon_creds_crypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
+ uint16_t validation_level,
+ union netr_Validation *validation,
+ bool do_encrypt)
+{
+ struct netr_SamBaseInfo *base = NULL;
+ NTSTATUS status;
+
+ if (validation == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ switch (validation_level) {
+ case 2:
+ if (validation->sam2) {
+ base = &validation->sam2->base;
+ }
+ break;
+ case 3:
+ if (validation->sam3) {
+ base = &validation->sam3->base;
+ }
+ break;
+ case 6:
+ if (validation->sam6) {
+ base = &validation->sam6->base;
+ }
+ break;
+ default:
+ /* If we can't find it, we can't very well decrypt it */
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ if (!base) {
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ /* find and decrypt the session keys, return in parameters above */
+ if (validation_level == 6) {
+ /* they aren't encrypted! */
+ } else if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
+ if (!all_zero(base->key.key, sizeof(base->key.key))) {
+ if (do_encrypt) {
+ status = netlogon_creds_aes_encrypt(
+ creds,
+ base->key.key,
+ sizeof(base->key.key));
+ } else {
+ status = netlogon_creds_aes_decrypt(
+ creds,
+ base->key.key,
+ sizeof(base->key.key));
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ if (!all_zero(base->LMSessKey.key,
+ sizeof(base->LMSessKey.key))) {
+ if (do_encrypt) {
+ status = netlogon_creds_aes_encrypt(
+ creds,
+ base->LMSessKey.key,
+ sizeof(base->LMSessKey.key));
+ } else {
+ status = netlogon_creds_aes_decrypt(
+ creds,
+ base->LMSessKey.key,
+ sizeof(base->LMSessKey.key));
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+ /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
+ if (!all_zero(base->key.key, sizeof(base->key.key))) {
+ status = netlogon_creds_arcfour_crypt(creds,
+ base->key.key,
+ sizeof(base->key.key));
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ if (!all_zero(base->LMSessKey.key,
+ sizeof(base->LMSessKey.key))) {
+ status = netlogon_creds_arcfour_crypt(creds,
+ base->LMSessKey.key,
+ sizeof(base->LMSessKey.key));
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ } else {
+ /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
+ if (!all_zero(base->LMSessKey.key,
+ sizeof(base->LMSessKey.key))) {
+ if (do_encrypt) {
+ status = netlogon_creds_des_encrypt_LMKey(creds,
+ &base->LMSessKey);
+ } else {
+ status = netlogon_creds_des_decrypt_LMKey(creds,
+ &base->LMSessKey);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_decrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
+ uint16_t validation_level,
+ union netr_Validation *validation)
+{
+ return netlogon_creds_crypt_samlogon_validation(creds,
+ validation_level,
+ validation,
+ false);
+}
+
+NTSTATUS netlogon_creds_encrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
+ uint16_t validation_level,
+ union netr_Validation *validation)
+{
+ return netlogon_creds_crypt_samlogon_validation(creds,
+ validation_level,
+ validation,
+ true);
+}
+
+static NTSTATUS netlogon_creds_crypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
+ enum netr_LogonInfoClass level,
+ union netr_LogonLevel *logon,
+ bool do_encrypt)
+{
+ NTSTATUS status;
+
+ if (logon == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ switch (level) {
+ case NetlogonInteractiveInformation:
+ case NetlogonInteractiveTransitiveInformation:
+ case NetlogonServiceInformation:
+ case NetlogonServiceTransitiveInformation:
+ if (logon->password == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ uint8_t *h;
+
+ h = logon->password->lmpassword.hash;
+ if (!all_zero(h, 16)) {
+ if (do_encrypt) {
+ status = netlogon_creds_aes_encrypt(
+ creds,
+ h,
+ 16);
+ } else {
+ status = netlogon_creds_aes_decrypt(
+ creds,
+ h,
+ 16);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ h = logon->password->ntpassword.hash;
+ if (!all_zero(h, 16)) {
+ if (do_encrypt) {
+ status = netlogon_creds_aes_encrypt(creds,
+ h,
+ 16);
+ } else {
+ status = netlogon_creds_aes_decrypt(creds,
+ h,
+ 16);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+ uint8_t *h;
+
+ h = logon->password->lmpassword.hash;
+ if (!all_zero(h, 16)) {
+ status = netlogon_creds_arcfour_crypt(creds,
+ h,
+ 16);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ h = logon->password->ntpassword.hash;
+ if (!all_zero(h, 16)) {
+ status = netlogon_creds_arcfour_crypt(creds,
+ h,
+ 16);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ } else {
+ struct samr_Password *p;
+
+ p = &logon->password->lmpassword;
+ if (!all_zero(p->hash, 16)) {
+ if (do_encrypt) {
+ status = netlogon_creds_des_encrypt(creds, p);
+ } else {
+ status = netlogon_creds_des_decrypt(creds, p);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ p = &logon->password->ntpassword;
+ if (!all_zero(p->hash, 16)) {
+ if (do_encrypt) {
+ status = netlogon_creds_des_encrypt(creds, p);
+ } else {
+ status = netlogon_creds_des_decrypt(creds, p);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ }
+ break;
+
+ case NetlogonNetworkInformation:
+ case NetlogonNetworkTransitiveInformation:
+ break;
+
+ case NetlogonGenericInformation:
+ if (logon->generic == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ if (do_encrypt) {
+ status = netlogon_creds_aes_encrypt(
+ creds,
+ logon->generic->data,
+ logon->generic->length);
+ } else {
+ status = netlogon_creds_aes_decrypt(
+ creds,
+ logon->generic->data,
+ logon->generic->length);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+ status = netlogon_creds_arcfour_crypt(creds,
+ logon->generic->data,
+ logon->generic->length);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ } else {
+ /* Using DES to verify kerberos tickets makes no sense */
+ }
+ break;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_decrypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
+ enum netr_LogonInfoClass level,
+ union netr_LogonLevel *logon)
+{
+ return netlogon_creds_crypt_samlogon_logon(creds, level, logon, false);
+}
+
+NTSTATUS netlogon_creds_encrypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
+ enum netr_LogonInfoClass level,
+ union netr_LogonLevel *logon)
+{
+ return netlogon_creds_crypt_samlogon_logon(creds, level, logon, true);
+}
+
+union netr_LogonLevel *netlogon_creds_shallow_copy_logon(TALLOC_CTX *mem_ctx,
+ enum netr_LogonInfoClass level,
+ const union netr_LogonLevel *in)
+{
+ union netr_LogonLevel *out;
+
+ if (in == NULL) {
+ return NULL;
+ }
+
+ out = talloc(mem_ctx, union netr_LogonLevel);
+ if (out == NULL) {
+ return NULL;
+ }
+
+ *out = *in;
+
+ switch (level) {
+ case NetlogonInteractiveInformation:
+ case NetlogonInteractiveTransitiveInformation:
+ case NetlogonServiceInformation:
+ case NetlogonServiceTransitiveInformation:
+ if (in->password == NULL) {
+ return out;
+ }
+
+ out->password = talloc(out, struct netr_PasswordInfo);
+ if (out->password == NULL) {
+ talloc_free(out);
+ return NULL;
+ }
+ *out->password = *in->password;
+
+ return out;
+
+ case NetlogonNetworkInformation:
+ case NetlogonNetworkTransitiveInformation:
+ break;
+
+ case NetlogonGenericInformation:
+ if (in->generic == NULL) {
+ return out;
+ }
+
+ out->generic = talloc(out, struct netr_GenericInfo);
+ if (out->generic == NULL) {
+ talloc_free(out);
+ return NULL;
+ }
+ *out->generic = *in->generic;
+
+ if (in->generic->data == NULL) {
+ return out;
+ }
+
+ if (in->generic->length == 0) {
+ return out;
+ }
+
+ out->generic->data = talloc_memdup(out->generic,
+ in->generic->data,
+ in->generic->length);
+ if (out->generic->data == NULL) {
+ talloc_free(out);
+ return NULL;
+ }
+
+ return out;
+ }
+
+ return out;
+}
+
+/*
+ copy a netlogon_creds_CredentialState struct
+*/
+
+struct netlogon_creds_CredentialState *netlogon_creds_copy(
+ TALLOC_CTX *mem_ctx,
+ const struct netlogon_creds_CredentialState *creds_in)
+{
+ struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
+
+ if (!creds) {
+ return NULL;
+ }
+
+ creds->sequence = creds_in->sequence;
+ creds->negotiate_flags = creds_in->negotiate_flags;
+ creds->secure_channel_type = creds_in->secure_channel_type;
+
+ creds->computer_name = talloc_strdup(creds, creds_in->computer_name);
+ if (!creds->computer_name) {
+ talloc_free(creds);
+ return NULL;
+ }
+ creds->account_name = talloc_strdup(creds, creds_in->account_name);
+ if (!creds->account_name) {
+ talloc_free(creds);
+ return NULL;
+ }
+
+ if (creds_in->sid) {
+ creds->sid = dom_sid_dup(creds, creds_in->sid);
+ if (!creds->sid) {
+ talloc_free(creds);
+ return NULL;
+ }
+ }
+
+ memcpy(creds->session_key, creds_in->session_key, sizeof(creds->session_key));
+ memcpy(creds->seed.data, creds_in->seed.data, sizeof(creds->seed.data));
+ memcpy(creds->client.data, creds_in->client.data, sizeof(creds->client.data));
+ memcpy(creds->server.data, creds_in->server.data, sizeof(creds->server.data));
+
+ return creds;
+}
diff --git a/libcli/auth/credentials.h b/libcli/auth/credentials.h
new file mode 100644
index 0000000..7b8fac6
--- /dev/null
+++ b/libcli/auth/credentials.h
@@ -0,0 +1,70 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ code to manipulate domain credentials
+
+ Copyright (C) Andrew Tridgell 2004
+
+ 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 "librpc/gen_ndr/netlogon.h"
+
+/* The 7 here seems to be required to get Win2k not to downgrade us
+ to NT4. Actually, anything other than 1ff would seem to do... */
+#define NETLOGON_NEG_AUTH2_FLAGS 0x000701ff
+/*
+ (NETLOGON_NEG_ACCOUNT_LOCKOUT |
+ NETLOGON_NEG_PERSISTENT_SAMREPL |
+ NETLOGON_NEG_ARCFOUR |
+ NETLOGON_NEG_PROMOTION_COUNT |
+ NETLOGON_NEG_CHANGELOG_BDC |
+ NETLOGON_NEG_FULL_SYNC_REPL |
+ NETLOGON_NEG_MULTIPLE_SIDS |
+ NETLOGON_NEG_REDO |
+ NETLOGON_NEG_PASSWORD_CHANGE_REFUSAL |
+ NETLOGON_NEG_DNS_DOMAIN_TRUSTS |
+ NETLOGON_NEG_PASSWORD_SET2 |
+ NETLOGON_NEG_GETDOMAININFO)
+*/
+#define NETLOGON_NEG_DOMAIN_TRUST_ACCOUNT 0x2010b000
+
+/* these are the flags that ADS clients use */
+/*
+ (NETLOGON_NEG_ACCOUNT_LOCKOUT |
+ NETLOGON_NEG_PERSISTENT_SAMREPL |
+ NETLOGON_NEG_ARCFOUR |
+ NETLOGON_NEG_PROMOTION_COUNT |
+ NETLOGON_NEG_CHANGELOG_BDC |
+ NETLOGON_NEG_FULL_SYNC_REPL |
+ NETLOGON_NEG_MULTIPLE_SIDS |
+ NETLOGON_NEG_REDO |
+ NETLOGON_NEG_PASSWORD_CHANGE_REFUSAL |
+ NETLOGON_NEG_SEND_PASSWORD_INFO_PDC |
+ NETLOGON_NEG_GENERIC_PASSTHROUGH |
+ NETLOGON_NEG_CONCURRENT_RPC |
+ NETLOGON_NEG_AVOID_ACCOUNT_DB_REPL |
+ NETLOGON_NEG_AVOID_SECURITYAUTH_DB_REPL |
+ NETLOGON_NEG_128BIT |
+ NETLOGON_NEG_TRANSITIVE_TRUSTS |
+ NETLOGON_NEG_DNS_DOMAIN_TRUSTS |
+ NETLOGON_NEG_PASSWORD_SET2 |
+ NETLOGON_NEG_GETDOMAININFO |
+ NETLOGON_NEG_CROSS_FOREST_TRUSTS |
+ NETLOGON_NEG_AUTHENTICATED_RPC_LSASS |
+ NETLOGON_NEG_SCHANNEL)
+*/
+
+#define NETLOGON_NEG_AUTH2_ADS_FLAGS (0x200fbffb | NETLOGON_NEG_ARCFOUR | NETLOGON_NEG_128BIT | NETLOGON_NEG_SCHANNEL)
+
diff --git a/libcli/auth/libcli_auth.h b/libcli/auth/libcli_auth.h
new file mode 100644
index 0000000..c5c7a7b
--- /dev/null
+++ b/libcli/auth/libcli_auth.h
@@ -0,0 +1,28 @@
+/*
+ samba -- Unix SMB/CIFS implementation.
+
+ 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/>.
+*/
+#ifndef __LIBCLI_AUTH_H__
+#define __LIBCLI_AUTH_H__
+
+#include "librpc/gen_ndr/netlogon.h"
+#include "librpc/gen_ndr/wkssvc.h"
+#include "librpc/gen_ndr/schannel.h"
+#include "libcli/auth/credentials.h"
+#include "libcli/auth/ntlm_check.h"
+#include "libcli/auth/proto.h"
+#include "libcli/auth/msrpc_parse.h"
+
+#endif /* __LIBCLI_AUTH_H__ */
diff --git a/libcli/auth/msrpc_parse.c b/libcli/auth/msrpc_parse.c
new file mode 100644
index 0000000..8326261
--- /dev/null
+++ b/libcli/auth/msrpc_parse.c
@@ -0,0 +1,409 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple kerberos5/SPNEGO routines
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
+ Copyright (C) Andrew Bartlett 2002-2003
+
+ 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 "libcli/auth/msrpc_parse.h"
+
+/*
+ this is a tiny msrpc packet generator. I am only using this to
+ avoid tying this code to a particular variant of our rpc code. This
+ generator is not general enough for all our rpc needs, its just
+ enough for the spnego/ntlmssp code
+
+ format specifiers are:
+
+ U = unicode string (input is unix string)
+ a = address (input is char *unix_string)
+ (1 byte type, 1 byte length, unicode/ASCII string, all inline)
+ A = ASCII string (input is unix string)
+ B = data blob (pointer + length)
+ b = data blob in header (pointer + length)
+ D
+ d = word (4 bytes)
+ C = constant ascii string
+ */
+NTSTATUS msrpc_gen(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob,
+ const char *format, ...)
+{
+ int i, j;
+ bool ret;
+ va_list ap;
+ char *s;
+ uint8_t *b;
+ int head_size=0, data_size=0;
+ int head_ofs, data_ofs;
+ int *intargs;
+ size_t n;
+
+ DATA_BLOB *pointers;
+
+ pointers = talloc_array(mem_ctx, DATA_BLOB, strlen(format));
+ if (!pointers) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ intargs = talloc_array(pointers, int, strlen(format));
+ if (!intargs) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* first scan the format to work out the header and body size */
+ va_start(ap, format);
+ for (i=0; format[i]; i++) {
+ switch (format[i]) {
+ case 'U':
+ s = va_arg(ap, char *);
+ head_size += 8;
+ ret = push_ucs2_talloc(
+ pointers,
+ (smb_ucs2_t **)(void *)&pointers[i].data,
+ s, &n);
+ if (!ret) {
+ va_end(ap);
+ return map_nt_error_from_unix_common(errno);
+ }
+ pointers[i].length = n;
+ pointers[i].length -= 2;
+ data_size += pointers[i].length;
+ break;
+ case 'A':
+ s = va_arg(ap, char *);
+ head_size += 8;
+ ret = push_ascii_talloc(
+ pointers, (char **)(void *)&pointers[i].data,
+ s, &n);
+ if (!ret) {
+ va_end(ap);
+ return map_nt_error_from_unix_common(errno);
+ }
+ pointers[i].length = n;
+ pointers[i].length -= 1;
+ data_size += pointers[i].length;
+ break;
+ case 'a':
+ j = va_arg(ap, int);
+ intargs[i] = j;
+ s = va_arg(ap, char *);
+ ret = push_ucs2_talloc(
+ pointers,
+ (smb_ucs2_t **)(void *)&pointers[i].data,
+ s, &n);
+ if (!ret) {
+ va_end(ap);
+ return map_nt_error_from_unix_common(errno);
+ }
+ pointers[i].length = n;
+ pointers[i].length -= 2;
+ data_size += pointers[i].length + 4;
+ break;
+ case 'B':
+ b = va_arg(ap, uint8_t *);
+ head_size += 8;
+ pointers[i].data = b;
+ pointers[i].length = va_arg(ap, int);
+ data_size += pointers[i].length;
+ break;
+ case 'b':
+ b = va_arg(ap, uint8_t *);
+ pointers[i].data = b;
+ pointers[i].length = va_arg(ap, int);
+ head_size += pointers[i].length;
+ break;
+ case 'd':
+ j = va_arg(ap, int);
+ intargs[i] = j;
+ head_size += 4;
+ break;
+ case 'C':
+ s = va_arg(ap, char *);
+ pointers[i].data = (uint8_t *)s;
+ pointers[i].length = strlen(s)+1;
+ head_size += pointers[i].length;
+ break;
+ default:
+ va_end(ap);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+ va_end(ap);
+
+ if (head_size + data_size == 0) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* allocate the space, then scan the format again to fill in the values */
+ *blob = data_blob_talloc(mem_ctx, NULL, head_size + data_size);
+ if (!blob->data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ head_ofs = 0;
+ data_ofs = head_size;
+
+ va_start(ap, format);
+ for (i=0; format[i]; i++) {
+ switch (format[i]) {
+ case 'U':
+ case 'A':
+ case 'B':
+ n = pointers[i].length;
+ SSVAL(blob->data, head_ofs, n); head_ofs += 2;
+ SSVAL(blob->data, head_ofs, n); head_ofs += 2;
+ SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
+ if (pointers[i].data && n) /* don't follow null pointers... */
+ memcpy(blob->data+data_ofs, pointers[i].data, n);
+ data_ofs += n;
+ break;
+ case 'a':
+ j = intargs[i];
+ SSVAL(blob->data, data_ofs, j); data_ofs += 2;
+
+ n = pointers[i].length;
+ SSVAL(blob->data, data_ofs, n); data_ofs += 2;
+ memcpy(blob->data+data_ofs, pointers[i].data, n);
+ data_ofs += n;
+ break;
+ case 'd':
+ j = intargs[i];
+ SIVAL(blob->data, head_ofs, j);
+ head_ofs += 4;
+ break;
+ case 'b':
+ n = pointers[i].length;
+ if (pointers[i].data && n) {
+ /* don't follow null pointers... */
+ memcpy(blob->data + head_ofs, pointers[i].data, n);
+ }
+ head_ofs += n;
+ break;
+ case 'C':
+ n = pointers[i].length;
+ memcpy(blob->data + head_ofs, pointers[i].data, n);
+ head_ofs += n;
+ break;
+ default:
+ va_end(ap);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+ va_end(ap);
+
+ talloc_free(pointers);
+
+ return NT_STATUS_OK;
+}
+
+
+/* a helpful macro to avoid running over the end of our blob */
+#define NEED_DATA(amount) \
+if ((head_ofs + amount) > blob->length) { \
+ va_end(ap); \
+ return false; \
+}
+
+/**
+ this is a tiny msrpc packet parser. This the the partner of msrpc_gen
+
+ format specifiers are:
+
+ U = unicode string (output is unix string)
+ A = ascii string
+ B = data blob
+ b = data blob in header
+ d = word (4 bytes)
+ C = constant ascii string
+ */
+
+bool msrpc_parse(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *blob,
+ const char *format, ...)
+{
+ int i;
+ va_list ap;
+ char **ps, *s;
+ DATA_BLOB *b;
+ size_t head_ofs = 0;
+ uint16_t len1, len2;
+ uint32_t ptr;
+ uint32_t *v;
+ bool ret = true;
+
+ va_start(ap, format);
+ for (i=0; format[i]; i++) {
+ switch (format[i]) {
+ case 'U':
+ NEED_DATA(8);
+ len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
+
+ ps = va_arg(ap, char **);
+ if (len1 == 0 && len2 == 0) {
+ *ps = talloc_strdup(mem_ctx, "");
+ if (*ps == NULL) {
+ ret = false;
+ goto cleanup;
+ }
+ } else {
+ /* make sure its in the right format - be strict */
+ if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
+ ret = false;
+ goto cleanup;
+ }
+ if (len1 & 1) {
+ /* if odd length and unicode */
+ ret = false;
+ goto cleanup;
+ }
+ if (blob->data + ptr < (uint8_t *)(uintptr_t)ptr ||
+ blob->data + ptr < blob->data) {
+ ret = false;
+ goto cleanup;
+ }
+
+ if (0 < len1) {
+ size_t pull_len;
+ if (!convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
+ blob->data + ptr, len1,
+ ps, &pull_len)) {
+ ret = false;
+ goto cleanup;
+ }
+ } else {
+ *ps = talloc_strdup(mem_ctx, "");
+ if (*ps == NULL) {
+ ret = false;
+ goto cleanup;
+ }
+ }
+ }
+ break;
+ case 'A':
+ NEED_DATA(8);
+ len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
+
+ ps = (char **)va_arg(ap, char **);
+ /* make sure its in the right format - be strict */
+ if (len1 == 0 && len2 == 0) {
+ *ps = talloc_strdup(mem_ctx, "");
+ if (*ps == NULL) {
+ ret = false;
+ goto cleanup;
+ }
+ } else {
+ if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
+ ret = false;
+ goto cleanup;
+ }
+
+ if (blob->data + ptr < (uint8_t *)(uintptr_t)ptr ||
+ blob->data + ptr < blob->data) {
+ ret = false;
+ goto cleanup;
+ }
+
+ if (0 < len1) {
+ size_t pull_len;
+
+ if (!convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX,
+ blob->data + ptr, len1,
+ ps, &pull_len)) {
+ ret = false;
+ goto cleanup;
+ }
+ } else {
+ *ps = talloc_strdup(mem_ctx, "");
+ if (*ps == NULL) {
+ ret = false;
+ goto cleanup;
+ }
+ }
+ }
+ break;
+ case 'B':
+ NEED_DATA(8);
+ len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
+
+ b = (DATA_BLOB *)va_arg(ap, void *);
+ if (len1 == 0 && len2 == 0) {
+ *b = data_blob_talloc(mem_ctx, NULL, 0);
+ } else {
+ /* make sure its in the right format - be strict */
+ if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
+ ret = false;
+ goto cleanup;
+ }
+
+ if (blob->data + ptr < (uint8_t *)(uintptr_t)ptr ||
+ blob->data + ptr < blob->data) {
+ ret = false;
+ goto cleanup;
+ }
+
+ *b = data_blob_talloc(mem_ctx, blob->data + ptr, len1);
+ }
+ break;
+ case 'b':
+ b = (DATA_BLOB *)va_arg(ap, void *);
+ len1 = va_arg(ap, unsigned int);
+ /* make sure its in the right format - be strict */
+ NEED_DATA(len1);
+ if (blob->data + head_ofs < (uint8_t *)head_ofs ||
+ blob->data + head_ofs < blob->data) {
+ ret = false;
+ goto cleanup;
+ }
+
+ *b = data_blob_talloc(mem_ctx, blob->data + head_ofs, len1);
+ head_ofs += len1;
+ break;
+ case 'd':
+ v = va_arg(ap, uint32_t *);
+ NEED_DATA(4);
+ *v = IVAL(blob->data, head_ofs); head_ofs += 4;
+ break;
+ case 'C':
+ s = va_arg(ap, char *);
+
+ if (blob->data + head_ofs < (uint8_t *)head_ofs ||
+ blob->data + head_ofs < blob->data ||
+ (head_ofs + (strlen(s) + 1)) > blob->length) {
+ ret = false;
+ goto cleanup;
+ }
+
+ if (memcmp(blob->data + head_ofs, s, strlen(s)+1) != 0) {
+ ret = false;
+ goto cleanup;
+ }
+ head_ofs += (strlen(s) + 1);
+
+ break;
+ }
+ }
+
+cleanup:
+ va_end(ap);
+ return ret;
+}
diff --git a/libcli/auth/msrpc_parse.h b/libcli/auth/msrpc_parse.h
new file mode 100644
index 0000000..717dec9
--- /dev/null
+++ b/libcli/auth/msrpc_parse.h
@@ -0,0 +1,58 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple kerberos5/SPNEGO routines
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
+ Copyright (C) Andrew Bartlett 2002-2003
+
+ 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/>.
+*/
+
+#ifndef _LIBCLI_AUTH_MSRPC_PARSE_H__
+#define _LIBCLI_AUTH_MSRPC_PARSE_H__
+
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2)
+
+/* this file contains prototypes for functions that are private
+ * to this subsystem or library. These functions should not be
+ * used outside this particular subsystem! */
+
+
+/* The following definitions come from libcli/auth/msrpc_parse.c */
+
+NTSTATUS msrpc_gen(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob,
+ const char *format, ...);
+
+/**
+ this is a tiny msrpc packet parser. This the the partner of msrpc_gen
+
+ format specifiers are:
+
+ U = unicode string (output is unix string)
+ A = ascii string
+ B = data blob
+ b = data blob in header
+ d = word (4 bytes)
+ C = constant ascii string
+ */
+bool msrpc_parse(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *blob,
+ const char *format, ...);
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2)
+
+#endif
+
diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
new file mode 100644
index 0000000..118c81f
--- /dev/null
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -0,0 +1,4256 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ module to store/fetch session keys for the schannel client
+
+ Copyright (C) Stefan Metzmacher 2013
+
+ 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 "system/filesys.h"
+#include <tevent.h>
+#include "lib/util/tevent_ntstatus.h"
+#include "lib/dbwrap/dbwrap.h"
+#include "lib/dbwrap/dbwrap_rbt.h"
+#include "lib/util/util_tdb.h"
+#include "libcli/security/security.h"
+#include "../lib/param/param.h"
+#include "../libcli/auth/schannel.h"
+#include "../librpc/gen_ndr/ndr_schannel.h"
+#include "../librpc/gen_ndr/ndr_netlogon_c.h"
+#include "../librpc/gen_ndr/ndr_netlogon.h"
+#include "../librpc/gen_ndr/server_id.h"
+#include "netlogon_creds_cli.h"
+#include "source3/include/messages.h"
+#include "source3/include/g_lock.h"
+#include "libds/common/roles.h"
+#include "lib/crypto/md4.h"
+#include "auth/credentials/credentials.h"
+#include "lib/param/loadparm.h"
+
+struct netlogon_creds_cli_locked_state;
+
+struct netlogon_creds_cli_context {
+ struct {
+ const char *computer;
+ const char *account;
+ uint32_t proposed_flags;
+ uint32_t required_flags;
+ enum netr_SchannelType type;
+ enum dcerpc_AuthLevel auth_level;
+ } client;
+
+ struct {
+ const char *computer;
+ const char *netbios_domain;
+ const char *dns_domain;
+ uint32_t cached_flags;
+ bool try_validation6;
+ bool try_logon_ex;
+ bool try_logon_with;
+ } server;
+
+ struct {
+ const char *key_name;
+ TDB_DATA key_data;
+ struct db_context *ctx;
+ struct g_lock_ctx *g_ctx;
+ struct netlogon_creds_cli_locked_state *locked_state;
+ enum netlogon_creds_cli_lck_type lock;
+ } db;
+};
+
+struct netlogon_creds_cli_locked_state {
+ struct netlogon_creds_cli_context *context;
+ bool is_glocked;
+ struct netlogon_creds_CredentialState *creds;
+};
+
+static int netlogon_creds_cli_locked_state_destructor(
+ struct netlogon_creds_cli_locked_state *state)
+{
+ struct netlogon_creds_cli_context *context = state->context;
+
+ if (context == NULL) {
+ return 0;
+ }
+
+ if (context->db.locked_state == state) {
+ context->db.locked_state = NULL;
+ }
+
+ if (state->is_glocked) {
+ g_lock_unlock(context->db.g_ctx,
+ string_term_tdb_data(context->db.key_name));
+ }
+
+ return 0;
+}
+
+static NTSTATUS netlogon_creds_cli_context_common(
+ const char *client_computer,
+ const char *client_account,
+ enum netr_SchannelType type,
+ enum dcerpc_AuthLevel auth_level,
+ uint32_t proposed_flags,
+ uint32_t required_flags,
+ const char *server_computer,
+ const char *server_netbios_domain,
+ const char *server_dns_domain,
+ TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_cli_context **_context)
+{
+ struct netlogon_creds_cli_context *context = NULL;
+ char *_key_name = NULL;
+ size_t server_netbios_name_len;
+ char *p = NULL;
+
+ *_context = NULL;
+
+ context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
+ if (context == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ context->client.computer = talloc_strdup(context, client_computer);
+ if (context->client.computer == NULL) {
+ TALLOC_FREE(context);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ context->client.account = talloc_strdup(context, client_account);
+ if (context->client.account == NULL) {
+ TALLOC_FREE(context);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ context->client.proposed_flags = proposed_flags;
+ context->client.required_flags = required_flags;
+ context->client.type = type;
+ context->client.auth_level = auth_level;
+
+ context->server.computer = talloc_strdup(context, server_computer);
+ if (context->server.computer == NULL) {
+ TALLOC_FREE(context);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
+ if (context->server.netbios_domain == NULL) {
+ TALLOC_FREE(context);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ context->server.dns_domain = talloc_strdup(context, server_dns_domain);
+ if (context->server.dns_domain == NULL) {
+ TALLOC_FREE(context);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /*
+ * TODO:
+ * Force the callers to provide a unique
+ * value for server_computer and use this directly.
+ *
+ * For now we have to deal with
+ * "HOSTNAME" vs. "hostname.example.com".
+ */
+
+ p = strchr(server_computer, '.');
+ if (p != NULL) {
+ server_netbios_name_len = p-server_computer;
+ } else {
+ server_netbios_name_len = strlen(server_computer);
+ }
+
+ _key_name = talloc_asprintf(context, "CLI[%s/%s]/SRV[%.*s/%s]",
+ client_computer,
+ client_account,
+ (int)server_netbios_name_len,
+ server_computer,
+ server_netbios_domain);
+ if (_key_name == NULL) {
+ TALLOC_FREE(context);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ context->db.key_name = talloc_strdup_upper(context, _key_name);
+ TALLOC_FREE(_key_name);
+ if (context->db.key_name == NULL) {
+ TALLOC_FREE(context);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ context->db.key_data = string_term_tdb_data(context->db.key_name);
+
+ *_context = context;
+ return NT_STATUS_OK;
+}
+
+static struct db_context *netlogon_creds_cli_global_db;
+
+NTSTATUS netlogon_creds_cli_set_global_db(struct loadparm_context *lp_ctx,
+ struct db_context **db)
+{
+ netlogon_creds_cli_warn_options(lp_ctx);
+
+ if (netlogon_creds_cli_global_db != NULL) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ netlogon_creds_cli_global_db = talloc_move(NULL, db);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
+{
+ char *fname;
+ struct db_context *global_db;
+ int hash_size, tdb_flags;
+
+ netlogon_creds_cli_warn_options(lp_ctx);
+
+ if (netlogon_creds_cli_global_db != NULL) {
+ return NT_STATUS_OK;
+ }
+
+ fname = lpcfg_private_db_path(NULL, lp_ctx, "netlogon_creds_cli");
+ if (fname == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ hash_size = lpcfg_tdb_hash_size(lp_ctx, fname);
+ tdb_flags = lpcfg_tdb_flags(
+ lp_ctx,
+ TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH);
+
+ global_db = dbwrap_local_open(
+ NULL,
+ fname,
+ hash_size,
+ tdb_flags,
+ O_RDWR|O_CREAT,
+ 0600,
+ DBWRAP_LOCK_ORDER_2,
+ DBWRAP_FLAG_NONE);
+ if (global_db == NULL) {
+ DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
+ fname, strerror(errno)));
+ talloc_free(fname);
+ return NT_STATUS_NO_MEMORY;
+ }
+ TALLOC_FREE(fname);
+
+ netlogon_creds_cli_global_db = global_db;
+ return NT_STATUS_OK;
+}
+
+void netlogon_creds_cli_close_global_db(void)
+{
+ TALLOC_FREE(netlogon_creds_cli_global_db);
+}
+
+void netlogon_creds_cli_warn_options(struct loadparm_context *lp_ctx)
+{
+ bool global_reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
+ bool global_require_strong_key = lpcfg_require_strong_key(lp_ctx);
+ int global_client_schannel = lpcfg_client_schannel(lp_ctx);
+ bool global_seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
+ int global_kerberos_enctypes = lpcfg_kerberos_encryption_types(lp_ctx);
+ static bool warned_global_reject_md5_servers = false;
+ static bool warned_global_require_strong_key = false;
+ static bool warned_global_client_schannel = false;
+ static bool warned_global_seal_secure_channel = false;
+ static bool warned_global_kerberos_encryption_types = false;
+ static int warned_global_pid = 0;
+ int current_pid = tevent_cached_getpid();
+
+ if (warned_global_pid != current_pid) {
+ warned_global_reject_md5_servers = false;
+ warned_global_require_strong_key = false;
+ warned_global_client_schannel = false;
+ warned_global_seal_secure_channel = false;
+ warned_global_kerberos_encryption_types = false;
+ warned_global_pid = current_pid;
+ }
+
+ if (!global_reject_md5_servers && !warned_global_reject_md5_servers) {
+ /*
+ * We want admins to notice their misconfiguration!
+ */
+ DBG_ERR("CVE-2022-38023 (and others): "
+ "Please configure 'reject md5 servers = yes' (the default), "
+ "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
+ warned_global_reject_md5_servers = true;
+ }
+
+ if (!global_require_strong_key && !warned_global_require_strong_key) {
+ /*
+ * We want admins to notice their misconfiguration!
+ */
+ DBG_ERR("CVE-2022-38023 (and others): "
+ "Please configure 'require strong key = yes' (the default), "
+ "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
+ warned_global_require_strong_key = true;
+ }
+
+ if (global_client_schannel != true && !warned_global_client_schannel) {
+ /*
+ * We want admins to notice their misconfiguration!
+ */
+ DBG_ERR("CVE-2022-38023 (and others): "
+ "Please configure 'client schannel = yes' (the default), "
+ "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
+ warned_global_client_schannel = true;
+ }
+
+ if (!global_seal_secure_channel && !warned_global_seal_secure_channel) {
+ /*
+ * We want admins to notice their misconfiguration!
+ */
+ DBG_ERR("CVE-2022-38023 (and others): "
+ "Please configure 'winbind sealed pipes = yes' (the default), "
+ "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
+ warned_global_seal_secure_channel = true;
+ }
+
+ if (global_kerberos_enctypes == KERBEROS_ETYPES_LEGACY &&
+ !warned_global_kerberos_encryption_types)
+ {
+ /*
+ * We want admins to notice their misconfiguration!
+ */
+ DBG_ERR("CVE-2022-37966: "
+ "Please void 'kerberos encryption types = legacy', "
+ "See https://bugzilla.samba.org/show_bug.cgi?id=15237\n");
+ warned_global_kerberos_encryption_types = true;
+ }
+}
+
+NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
+ struct messaging_context *msg_ctx,
+ const char *client_account,
+ enum netr_SchannelType type,
+ const char *server_computer,
+ const char *server_netbios_domain,
+ const char *server_dns_domain,
+ TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_cli_context **_context)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct netlogon_creds_cli_context *context = NULL;
+ const char *client_computer;
+ uint32_t proposed_flags;
+ uint32_t required_flags = 0;
+ bool reject_md5_servers = true;
+ bool require_strong_key = true;
+ int require_sign_or_seal = true;
+ bool seal_secure_channel = true;
+ enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
+ bool neutralize_nt4_emulation = false;
+
+ *_context = NULL;
+
+ if (msg_ctx == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ client_computer = lpcfg_netbios_name(lp_ctx);
+ if (strlen(client_computer) > 15) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ /*
+ * allow overwrite per domain
+ * reject md5 servers:<netbios_domain>
+ */
+ reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
+ reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
+ "reject md5 servers",
+ server_netbios_domain,
+ reject_md5_servers);
+
+ /*
+ * allow overwrite per domain
+ * require strong key:<netbios_domain>
+ */
+ require_strong_key = lpcfg_require_strong_key(lp_ctx);
+ require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
+ "require strong key",
+ server_netbios_domain,
+ require_strong_key);
+
+ /*
+ * allow overwrite per domain
+ * client schannel:<netbios_domain>
+ */
+ require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
+ require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
+ "client schannel",
+ server_netbios_domain,
+ require_sign_or_seal);
+
+ /*
+ * allow overwrite per domain
+ * winbind sealed pipes:<netbios_domain>
+ */
+ seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
+ seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
+ "winbind sealed pipes",
+ server_netbios_domain,
+ seal_secure_channel);
+
+ /*
+ * allow overwrite per domain
+ * neutralize nt4 emulation:<netbios_domain>
+ */
+ neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
+ neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
+ "neutralize nt4 emulation",
+ server_netbios_domain,
+ neutralize_nt4_emulation);
+
+ proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
+ proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
+
+ switch (type) {
+ case SEC_CHAN_WKSTA:
+ if (lpcfg_security(lp_ctx) == SEC_ADS) {
+ /*
+ * AD domains should be secure
+ */
+ required_flags |= NETLOGON_NEG_PASSWORD_SET2;
+ require_sign_or_seal = true;
+ require_strong_key = true;
+ }
+ break;
+
+ case SEC_CHAN_DOMAIN:
+ break;
+
+ case SEC_CHAN_DNS_DOMAIN:
+ /*
+ * AD domains should be secure
+ */
+ required_flags |= NETLOGON_NEG_PASSWORD_SET2;
+ require_sign_or_seal = true;
+ require_strong_key = true;
+ neutralize_nt4_emulation = true;
+ break;
+
+ case SEC_CHAN_BDC:
+ required_flags |= NETLOGON_NEG_PASSWORD_SET2;
+ require_sign_or_seal = true;
+ require_strong_key = true;
+ break;
+
+ case SEC_CHAN_RODC:
+ required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
+ required_flags |= NETLOGON_NEG_PASSWORD_SET2;
+ require_sign_or_seal = true;
+ require_strong_key = true;
+ neutralize_nt4_emulation = true;
+ break;
+
+ default:
+ TALLOC_FREE(frame);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (neutralize_nt4_emulation) {
+ proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
+ }
+
+ if (require_sign_or_seal) {
+ required_flags |= NETLOGON_NEG_ARCFOUR;
+ required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
+ } else {
+ proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
+ }
+
+ if (reject_md5_servers) {
+ required_flags |= NETLOGON_NEG_ARCFOUR;
+ required_flags |= NETLOGON_NEG_PASSWORD_SET2;
+ required_flags |= NETLOGON_NEG_SUPPORTS_AES;
+ required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
+ }
+
+ if (require_strong_key) {
+ required_flags |= NETLOGON_NEG_ARCFOUR;
+ required_flags |= NETLOGON_NEG_STRONG_KEYS;
+ required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
+ }
+
+ /*
+ * If weak crypto is disabled, do not announce that we support RC4 and
+ * require AES.
+ */
+ if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED) {
+ required_flags &= ~NETLOGON_NEG_ARCFOUR;
+ required_flags |= NETLOGON_NEG_SUPPORTS_AES;
+ proposed_flags &= ~NETLOGON_NEG_ARCFOUR;
+ proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
+ }
+
+ proposed_flags |= required_flags;
+
+ if (seal_secure_channel) {
+ auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
+ } else {
+ auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
+ }
+
+ status = netlogon_creds_cli_context_common(client_computer,
+ client_account,
+ type,
+ auth_level,
+ proposed_flags,
+ required_flags,
+ server_computer,
+ server_netbios_domain,
+ "",
+ mem_ctx,
+ &context);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
+ if (context->db.g_ctx == NULL) {
+ TALLOC_FREE(context);
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = netlogon_creds_cli_open_global_db(lp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(context);
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ context->db.ctx = netlogon_creds_cli_global_db;
+ *_context = context;
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_bind_cli_credentials(
+ struct netlogon_creds_cli_context *context, TALLOC_CTX *mem_ctx,
+ struct cli_credentials **pcli_creds)
+{
+ struct cli_credentials *cli_creds;
+ struct netlogon_creds_CredentialState *ncreds;
+ NTSTATUS status;
+
+ cli_creds = cli_credentials_init(mem_ctx);
+ if (cli_creds == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ cli_credentials_set_secure_channel_type(cli_creds,
+ context->client.type);
+ cli_credentials_set_username(cli_creds, context->client.account,
+ CRED_SPECIFIED);
+ cli_credentials_set_domain(cli_creds, context->server.netbios_domain,
+ CRED_SPECIFIED);
+ cli_credentials_set_realm(cli_creds, context->server.dns_domain,
+ CRED_SPECIFIED);
+
+ status = netlogon_creds_cli_get(context, cli_creds, &ncreds);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(cli_creds);
+ return status;
+ }
+ cli_credentials_set_netlogon_creds(cli_creds, ncreds);
+
+ *pcli_creds = cli_creds;
+ return NT_STATUS_OK;
+}
+
+char *netlogon_creds_cli_debug_string(
+ const struct netlogon_creds_cli_context *context,
+ TALLOC_CTX *mem_ctx)
+{
+ return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
+ context->db.key_name);
+}
+
+enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
+ struct netlogon_creds_cli_context *context)
+{
+ return context->client.auth_level;
+}
+
+static bool netlogon_creds_cli_downgraded(uint32_t negotiated_flags,
+ uint32_t proposed_flags,
+ uint32_t required_flags)
+{
+ uint32_t req_flags = required_flags;
+ uint32_t tmp_flags;
+
+ req_flags = required_flags;
+ if ((negotiated_flags & NETLOGON_NEG_SUPPORTS_AES) &&
+ (proposed_flags & NETLOGON_NEG_SUPPORTS_AES))
+ {
+ req_flags &= ~NETLOGON_NEG_ARCFOUR|NETLOGON_NEG_STRONG_KEYS;
+ }
+
+ tmp_flags = negotiated_flags;
+ tmp_flags &= req_flags;
+ if (tmp_flags != req_flags) {
+ return true;
+ }
+
+ return false;
+}
+
+struct netlogon_creds_cli_fetch_state {
+ TALLOC_CTX *mem_ctx;
+ struct netlogon_creds_CredentialState *creds;
+ uint32_t proposed_flags;
+ uint32_t required_flags;
+ NTSTATUS status;
+};
+
+static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
+ void *private_data)
+{
+ struct netlogon_creds_cli_fetch_state *state =
+ (struct netlogon_creds_cli_fetch_state *)private_data;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ bool downgraded;
+
+ state->creds = talloc_zero(state->mem_ctx,
+ struct netlogon_creds_CredentialState);
+ if (state->creds == NULL) {
+ state->status = NT_STATUS_NO_MEMORY;
+ return;
+ }
+
+ blob.data = data.dptr;
+ blob.length = data.dsize;
+
+ ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
+ (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(state->creds);
+ state->status = ndr_map_error2ntstatus(ndr_err);
+ return;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(netlogon_creds_CredentialState, state->creds);
+ }
+
+ downgraded = netlogon_creds_cli_downgraded(
+ state->creds->negotiate_flags,
+ state->proposed_flags,
+ state->required_flags);
+ if (downgraded) {
+ TALLOC_FREE(state->creds);
+ state->status = NT_STATUS_DOWNGRADE_DETECTED;
+ return;
+ }
+
+ state->status = NT_STATUS_OK;
+}
+
+static NTSTATUS netlogon_creds_cli_get_internal(
+ struct netlogon_creds_cli_context *context,
+ TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
+
+NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
+ TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState **_creds)
+{
+ NTSTATUS status;
+ struct netlogon_creds_CredentialState *creds;
+
+ *_creds = NULL;
+
+ status = netlogon_creds_cli_get_internal(context, mem_ctx, &creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /*
+ * mark it as invalid for step operations.
+ */
+ creds->sequence = 0;
+ creds->seed = (struct netr_Credential) {{0}};
+ creds->client = (struct netr_Credential) {{0}};
+ creds->server = (struct netr_Credential) {{0}};
+
+ *_creds = creds;
+ return NT_STATUS_OK;
+}
+
+bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
+ const struct netlogon_creds_CredentialState *creds1)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct netlogon_creds_CredentialState *creds2;
+ DATA_BLOB blob1;
+ DATA_BLOB blob2;
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+ bool equal;
+
+ status = netlogon_creds_cli_get(context, frame, &creds2);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+
+ ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
+ (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+
+ ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
+ (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+
+ equal = data_blob_equal_const_time(&blob1, &blob2);
+
+ TALLOC_FREE(frame);
+
+ return equal;
+}
+
+static NTSTATUS netlogon_creds_cli_store_internal(
+ struct netlogon_creds_cli_context *context,
+ struct netlogon_creds_CredentialState *creds)
+{
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ TDB_DATA data;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
+ }
+
+ ndr_err = ndr_push_struct_blob(&blob, creds, creds,
+ (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ return status;
+ }
+
+ data.dptr = blob.data;
+ data.dsize = blob.length;
+
+ status = dbwrap_store(context->db.ctx,
+ context->db.key_data,
+ data, TDB_REPLACE);
+ TALLOC_FREE(data.dptr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
+ struct netlogon_creds_CredentialState *creds)
+{
+ NTSTATUS status;
+
+ if (context->db.locked_state == NULL) {
+ /*
+ * this was not the result of netlogon_creds_cli_lock*()
+ */
+ return NT_STATUS_INVALID_PAGE_PROTECTION;
+ }
+
+ if (context->db.locked_state->creds != creds) {
+ /*
+ * this was not the result of netlogon_creds_cli_lock*()
+ */
+ return NT_STATUS_INVALID_PAGE_PROTECTION;
+ }
+
+ status = netlogon_creds_cli_store_internal(context, creds);
+ return status;
+}
+
+static NTSTATUS netlogon_creds_cli_delete_internal(
+ struct netlogon_creds_cli_context *context)
+{
+ NTSTATUS status;
+ status = dbwrap_delete(context->db.ctx, context->db.key_data);
+ return status;
+}
+
+NTSTATUS netlogon_creds_cli_delete_lck(
+ struct netlogon_creds_cli_context *context)
+{
+ NTSTATUS status;
+
+ if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
+ return NT_STATUS_NOT_LOCKED;
+ }
+
+ status = netlogon_creds_cli_delete_internal(context);
+ return status;
+}
+
+NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
+ struct netlogon_creds_CredentialState *creds)
+{
+ NTSTATUS status;
+
+ if (context->db.locked_state == NULL) {
+ /*
+ * this was not the result of netlogon_creds_cli_lock*()
+ */
+ return NT_STATUS_INVALID_PAGE_PROTECTION;
+ }
+
+ if (context->db.locked_state->creds != creds) {
+ /*
+ * this was not the result of netlogon_creds_cli_lock*()
+ */
+ return NT_STATUS_INVALID_PAGE_PROTECTION;
+ }
+
+ status = netlogon_creds_cli_delete_internal(context);
+ return status;
+}
+
+struct netlogon_creds_cli_lock_state {
+ struct netlogon_creds_cli_locked_state *locked_state;
+ struct netlogon_creds_CredentialState *creds;
+};
+
+static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
+
+struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context)
+{
+ struct tevent_req *req;
+ struct netlogon_creds_cli_lock_state *state;
+ struct netlogon_creds_cli_locked_state *locked_state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_lock_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (context->db.locked_state != NULL) {
+ tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
+ return tevent_req_post(req, ev);
+ }
+
+ locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
+ if (tevent_req_nomem(locked_state, req)) {
+ return tevent_req_post(req, ev);
+ }
+ talloc_set_destructor(locked_state,
+ netlogon_creds_cli_locked_state_destructor);
+ locked_state->context = context;
+
+ context->db.locked_state = locked_state;
+ state->locked_state = locked_state;
+
+ if (context->db.g_ctx == NULL) {
+ NTSTATUS status;
+
+ status = netlogon_creds_cli_get_internal(
+ context, state, &state->creds);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+ }
+
+ subreq = g_lock_lock_send(state, ev,
+ context->db.g_ctx,
+ string_term_tdb_data(context->db.key_name),
+ G_LOCK_WRITE,
+ NULL, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
+
+ return req;
+}
+
+static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_lock_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_lock_state);
+ NTSTATUS status;
+
+ status = g_lock_lock_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ state->locked_state->is_glocked = true;
+
+ status = netlogon_creds_cli_get_internal(state->locked_state->context,
+ state, &state->creds);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static NTSTATUS netlogon_creds_cli_get_internal(
+ struct netlogon_creds_cli_context *context,
+ TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds)
+{
+ struct netlogon_creds_cli_fetch_state fstate = {
+ .status = NT_STATUS_INTERNAL_ERROR,
+ .proposed_flags = context->client.proposed_flags,
+ .required_flags = context->client.required_flags,
+ };
+ NTSTATUS status;
+
+ fstate.mem_ctx = mem_ctx;
+ status = dbwrap_parse_record(context->db.ctx,
+ context->db.key_data,
+ netlogon_creds_cli_fetch_parser,
+ &fstate);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ if (!NT_STATUS_IS_OK(fstate.status)) {
+ return fstate.status;
+ }
+
+ if (context->server.cached_flags == fstate.creds->negotiate_flags) {
+ *pcreds = fstate.creds;
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * It is really important to try SamLogonEx here,
+ * because multiple processes can talk to the same
+ * domain controller, without using the credential
+ * chain.
+ *
+ * With a normal SamLogon call, we must keep the
+ * credentials chain updated and intact between all
+ * users of the machine account (which would imply
+ * cross-node communication for every NTLM logon).
+ *
+ * The credentials chain is not per NETLOGON pipe
+ * connection, but globally on the server/client pair
+ * by computer name.
+ *
+ * It's also important to use NetlogonValidationSamInfo4 (6),
+ * because it relies on the rpc transport encryption
+ * and avoids using the global netlogon schannel
+ * session key to en/decrypt secret information
+ * like the user_session_key for network logons.
+ *
+ * [MS-APDS] 3.1.5.2 NTLM Network Logon
+ * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
+ * NETLOGON_NEG_AUTHENTICATED_RPC set together
+ * are the indication that the server supports
+ * NetlogonValidationSamInfo4 (6). And it must only
+ * be used if "SealSecureChannel" is used.
+ *
+ * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
+ * check is done in netlogon_creds_cli_LogonSamLogon*().
+ */
+
+ context->server.cached_flags = fstate.creds->negotiate_flags;
+ context->server.try_validation6 = true;
+ context->server.try_logon_ex = true;
+ context->server.try_logon_with = true;
+
+ if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
+ context->server.try_validation6 = false;
+ context->server.try_logon_ex = false;
+ }
+ if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
+ context->server.try_validation6 = false;
+ }
+
+ *pcreds = fstate.creds;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState **creds)
+{
+ struct netlogon_creds_cli_lock_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_lock_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ talloc_steal(state->creds, state->locked_state);
+ state->locked_state->creds = state->creds;
+ *creds = talloc_move(mem_ctx, &state->creds);
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
+ TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState **creds)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_lock_send(frame, ev, context);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct netlogon_creds_cli_lck {
+ struct netlogon_creds_cli_context *context;
+};
+
+struct netlogon_creds_cli_lck_state {
+ struct netlogon_creds_cli_lck *lck;
+ enum netlogon_creds_cli_lck_type type;
+};
+
+static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq);
+static int netlogon_creds_cli_lck_destructor(
+ struct netlogon_creds_cli_lck *lck);
+
+struct tevent_req *netlogon_creds_cli_lck_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ enum netlogon_creds_cli_lck_type type)
+{
+ struct tevent_req *req, *subreq;
+ struct netlogon_creds_cli_lck_state *state;
+ enum g_lock_type gtype;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_lck_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (context->db.lock != NETLOGON_CREDS_CLI_LCK_NONE) {
+ DBG_DEBUG("context already locked\n");
+ tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_SEQUENCE);
+ return tevent_req_post(req, ev);
+ }
+
+ switch (type) {
+ case NETLOGON_CREDS_CLI_LCK_SHARED:
+ gtype = G_LOCK_READ;
+ break;
+ case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE:
+ gtype = G_LOCK_WRITE;
+ break;
+ default:
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ state->lck = talloc(state, struct netlogon_creds_cli_lck);
+ if (tevent_req_nomem(state->lck, req)) {
+ return tevent_req_post(req, ev);
+ }
+ state->lck->context = context;
+ state->type = type;
+
+ subreq = g_lock_lock_send(state, ev,
+ context->db.g_ctx,
+ string_term_tdb_data(context->db.key_name),
+ gtype,
+ NULL, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, netlogon_creds_cli_lck_locked, req);
+
+ return req;
+}
+
+static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct netlogon_creds_cli_lck_state *state = tevent_req_data(
+ req, struct netlogon_creds_cli_lck_state);
+ NTSTATUS status;
+
+ status = g_lock_lock_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ state->lck->context->db.lock = state->type;
+ talloc_set_destructor(state->lck, netlogon_creds_cli_lck_destructor);
+
+ tevent_req_done(req);
+}
+
+static int netlogon_creds_cli_lck_destructor(
+ struct netlogon_creds_cli_lck *lck)
+{
+ struct netlogon_creds_cli_context *ctx = lck->context;
+ NTSTATUS status;
+
+ status = g_lock_unlock(ctx->db.g_ctx,
+ string_term_tdb_data(ctx->db.key_name));
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status));
+ smb_panic("g_lock_unlock failed");
+ }
+ ctx->db.lock = NETLOGON_CREDS_CLI_LCK_NONE;
+ return 0;
+}
+
+NTSTATUS netlogon_creds_cli_lck_recv(
+ struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_cli_lck **lck)
+{
+ struct netlogon_creds_cli_lck_state *state = tevent_req_data(
+ req, struct netlogon_creds_cli_lck_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ *lck = talloc_move(mem_ctx, &state->lck);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_lck(
+ struct netlogon_creds_cli_context *context,
+ enum netlogon_creds_cli_lck_type type,
+ TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_lck_send(frame, ev, context, type);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_lck_recv(req, mem_ctx, lck);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct netlogon_creds_cli_auth_state {
+ struct tevent_context *ev;
+ struct netlogon_creds_cli_context *context;
+ struct dcerpc_binding_handle *binding_handle;
+ uint8_t num_nt_hashes;
+ uint8_t idx_nt_hashes;
+ const struct samr_Password * const *nt_hashes;
+ const struct samr_Password *used_nt_hash;
+ char *srv_name_slash;
+ uint32_t current_flags;
+ struct netr_Credential client_challenge;
+ struct netr_Credential server_challenge;
+ struct netlogon_creds_CredentialState *creds;
+ struct netr_Credential client_credential;
+ struct netr_Credential server_credential;
+ uint32_t rid;
+ bool try_auth3;
+ bool try_auth2;
+ bool require_auth2;
+};
+
+static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
+
+struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ uint8_t num_nt_hashes,
+ const struct samr_Password * const *nt_hashes)
+{
+ struct tevent_req *req;
+ struct netlogon_creds_cli_auth_state *state;
+ NTSTATUS status;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_auth_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->context = context;
+ state->binding_handle = b;
+ if (num_nt_hashes < 1) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+ if (num_nt_hashes > 4) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ state->num_nt_hashes = num_nt_hashes;
+ state->idx_nt_hashes = 0;
+ state->nt_hashes = nt_hashes;
+
+ if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
+ tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
+ return tevent_req_post(req, ev);
+ }
+
+ state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
+ context->server.computer);
+ if (tevent_req_nomem(state->srv_name_slash, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->try_auth3 = true;
+ state->try_auth2 = true;
+
+ if (context->client.required_flags != 0) {
+ state->require_auth2 = true;
+ }
+
+ state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
+ state->current_flags = context->client.proposed_flags;
+
+ status = dbwrap_purge(state->context->db.ctx,
+ state->context->db.key_data);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ netlogon_creds_cli_auth_challenge_start(req);
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
+{
+ struct netlogon_creds_cli_auth_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_auth_state);
+ struct tevent_req *subreq;
+
+ TALLOC_FREE(state->creds);
+
+ netlogon_creds_random_challenge(&state->client_challenge);
+
+ subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->context->client.computer,
+ &state->client_challenge,
+ &state->server_challenge);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_auth_challenge_done,
+ req);
+}
+
+static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_auth_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_auth_state);
+ NTSTATUS status;
+ NTSTATUS result;
+
+ status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ if (tevent_req_nterror(req, result)) {
+ return;
+ }
+
+ if (!state->try_auth3 && !state->try_auth2) {
+ state->current_flags = 0;
+ }
+
+ /* Calculate the session key and client credentials */
+
+ state->creds = netlogon_creds_client_init(state,
+ state->context->client.account,
+ state->context->client.computer,
+ state->context->client.type,
+ &state->client_challenge,
+ &state->server_challenge,
+ state->used_nt_hash,
+ &state->client_credential,
+ state->current_flags);
+ if (tevent_req_nomem(state->creds, req)) {
+ return;
+ }
+
+ if (state->try_auth3) {
+ subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->context->client.account,
+ state->context->client.type,
+ state->context->client.computer,
+ &state->client_credential,
+ &state->server_credential,
+ &state->creds->negotiate_flags,
+ &state->rid);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ } else if (state->try_auth2) {
+ state->rid = 0;
+
+ subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->context->client.account,
+ state->context->client.type,
+ state->context->client.computer,
+ &state->client_credential,
+ &state->server_credential,
+ &state->creds->negotiate_flags);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ } else {
+ state->rid = 0;
+
+ subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->context->client.account,
+ state->context->client.type,
+ state->context->client.computer,
+ &state->client_credential,
+ &state->server_credential);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ }
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_auth_srvauth_done,
+ req);
+}
+
+static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_auth_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_auth_state);
+ NTSTATUS status;
+ NTSTATUS result;
+ bool ok;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ TDB_DATA data;
+ bool downgraded;
+
+ if (state->try_auth3) {
+ status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
+ &result);
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+ state->try_auth3 = false;
+ netlogon_creds_cli_auth_challenge_start(req);
+ return;
+ }
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ } else if (state->try_auth2) {
+ status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
+ &result);
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+ state->try_auth2 = false;
+ if (state->require_auth2) {
+ status = NT_STATUS_DOWNGRADE_DETECTED;
+ tevent_req_nterror(req, status);
+ return;
+ }
+ netlogon_creds_cli_auth_challenge_start(req);
+ return;
+ }
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ } else {
+ status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
+ &result);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ }
+
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
+ {
+ tevent_req_nterror(req, result);
+ return;
+ }
+
+ downgraded = netlogon_creds_cli_downgraded(
+ state->creds->negotiate_flags,
+ state->context->client.proposed_flags,
+ state->context->client.required_flags);
+ if (downgraded) {
+ if (NT_STATUS_IS_OK(result)) {
+ tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
+ return;
+ }
+ tevent_req_nterror(req, result);
+ return;
+ }
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
+ uint32_t tmp_flags = state->context->client.proposed_flags;
+ if ((state->current_flags == tmp_flags) &&
+ (state->creds->negotiate_flags != tmp_flags))
+ {
+ /*
+ * lets retry with the negotiated flags
+ */
+ state->current_flags = state->creds->negotiate_flags;
+ netlogon_creds_cli_auth_challenge_start(req);
+ return;
+ }
+
+ state->idx_nt_hashes += 1;
+ if (state->idx_nt_hashes >= state->num_nt_hashes) {
+ /*
+ * we already retried, giving up...
+ */
+ tevent_req_nterror(req, result);
+ return;
+ }
+
+ /*
+ * lets retry with the old nt hash.
+ */
+ state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
+ state->current_flags = state->context->client.proposed_flags;
+ netlogon_creds_cli_auth_challenge_start(req);
+ return;
+ }
+
+ ok = netlogon_creds_client_check(state->creds,
+ &state->server_credential);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+
+ ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
+ (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ data.dptr = blob.data;
+ data.dsize = blob.length;
+
+ status = dbwrap_store(state->context->db.ctx,
+ state->context->db.key_data,
+ data, TDB_REPLACE);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
+ uint8_t *idx_nt_hashes)
+{
+ struct netlogon_creds_cli_auth_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_auth_state);
+ NTSTATUS status;
+
+ *idx_nt_hashes = 0;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ *idx_nt_hashes = state->idx_nt_hashes;
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ uint8_t num_nt_hashes,
+ const struct samr_Password * const *nt_hashes,
+ uint8_t *idx_nt_hashes)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ *idx_nt_hashes = 0;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_auth_send(frame, ev, context, b,
+ num_nt_hashes, nt_hashes);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct netlogon_creds_cli_check_state {
+ struct tevent_context *ev;
+ struct netlogon_creds_cli_context *context;
+ struct dcerpc_binding_handle *binding_handle;
+
+ char *srv_name_slash;
+
+ union netr_Capabilities caps;
+
+ struct netlogon_creds_CredentialState *creds;
+ struct netr_Authenticator req_auth;
+ struct netr_Authenticator rep_auth;
+};
+
+static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
+ NTSTATUS status);
+static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
+
+struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b)
+{
+ struct tevent_req *req;
+ struct netlogon_creds_cli_check_state *state;
+ struct tevent_req *subreq;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+ NTSTATUS status;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_check_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->context = context;
+ state->binding_handle = b;
+
+ if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
+ tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
+ return tevent_req_post(req, ev);
+ }
+
+ status = netlogon_creds_cli_get_internal(context, state,
+ &state->creds);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
+ context->server.computer);
+ if (tevent_req_nomem(state->srv_name_slash, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ dcerpc_binding_handle_auth_info(state->binding_handle,
+ &auth_type, &auth_level);
+
+ if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ switch (auth_level) {
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ break;
+ default:
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * we defer all callbacks in order to cleanup
+ * the database record.
+ */
+ tevent_req_defer_callback(req, state->ev);
+
+ status = netlogon_creds_client_authenticator(state->creds,
+ &state->req_auth);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+ ZERO_STRUCT(state->rep_auth);
+
+ subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->context->client.computer,
+ &state->req_auth,
+ &state->rep_auth,
+ 1,
+ &state->caps);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_check_caps,
+ req);
+
+ return req;
+}
+
+static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
+ NTSTATUS status)
+{
+ struct netlogon_creds_cli_check_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_check_state);
+
+ if (state->creds == NULL) {
+ return;
+ }
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
+ TALLOC_FREE(state->creds);
+ return;
+ }
+
+ netlogon_creds_cli_delete_lck(state->context);
+ TALLOC_FREE(state->creds);
+}
+
+static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_check_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_check_state);
+ NTSTATUS status;
+ NTSTATUS result;
+ bool ok;
+
+ status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
+ &result);
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+ /*
+ * Note that the negotiated flags are already checked
+ * for our required flags after the ServerAuthenticate3/2 call.
+ */
+ uint32_t negotiated = state->creds->negotiate_flags;
+
+ if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
+ /*
+ * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
+ * already, we expect this to work!
+ */
+ status = NT_STATUS_DOWNGRADE_DETECTED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_check_cleanup(req, status);
+ return;
+ }
+
+ if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
+ /*
+ * If we have negotiated NETLOGON_NEG_STRONG_KEYS
+ * we expect this to work at least as far as the
+ * NOT_SUPPORTED error handled below!
+ *
+ * NT 4.0 and Old Samba servers are not
+ * allowed without "require strong key = no"
+ */
+ status = NT_STATUS_DOWNGRADE_DETECTED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_check_cleanup(req, status);
+ return;
+ }
+
+ /*
+ * If we not require NETLOGON_NEG_SUPPORTS_AES or
+ * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
+ * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
+ *
+ * This is needed against NT 4.0 and old Samba servers.
+ *
+ * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
+ * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
+ * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
+ * with the next request as the sequence number processing
+ * gets out of sync.
+ */
+ netlogon_creds_cli_check_cleanup(req, status);
+ tevent_req_done(req);
+ return;
+ }
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_check_cleanup(req, status);
+ return;
+ }
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
+ /*
+ * Note that the negotiated flags are already checked
+ * for our required flags after the ServerAuthenticate3/2 call.
+ */
+ uint32_t negotiated = state->creds->negotiate_flags;
+
+ if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
+ /*
+ * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
+ * already, we expect this to work!
+ */
+ status = NT_STATUS_DOWNGRADE_DETECTED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_check_cleanup(req, status);
+ return;
+ }
+
+ /*
+ * This is ok, the server does not support
+ * NETLOGON_NEG_SUPPORTS_AES.
+ *
+ * netr_LogonGetCapabilities() was
+ * netr_LogonDummyRoutine1() before
+ * NETLOGON_NEG_SUPPORTS_AES was invented.
+ */
+ netlogon_creds_cli_check_cleanup(req, result);
+ tevent_req_done(req);
+ return;
+ }
+
+ ok = netlogon_creds_client_check(state->creds, &state->rep_auth.cred);
+ if (!ok) {
+ status = NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_check_cleanup(req, status);
+ return;
+ }
+
+ if (tevent_req_nterror(req, result)) {
+ netlogon_creds_cli_check_cleanup(req, result);
+ return;
+ }
+
+ if (state->caps.server_capabilities != state->creds->negotiate_flags) {
+ status = NT_STATUS_DOWNGRADE_DETECTED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_check_cleanup(req, status);
+ return;
+ }
+
+ /*
+ * This is the key check that makes this check secure. If we
+ * get OK here (rather than NOT_SUPPORTED), then the server
+ * did support AES. If the server only proposed STRONG_KEYS
+ * and not AES, then it should have failed with
+ * NOT_IMPLEMENTED. We always send AES as a client, so the
+ * server should always have returned it.
+ */
+ if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
+ status = NT_STATUS_DOWNGRADE_DETECTED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_check_cleanup(req, status);
+ return;
+ }
+
+ status = netlogon_creds_cli_store_internal(state->context,
+ state->creds);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req,
+ union netr_Capabilities *capabilities)
+{
+ struct netlogon_creds_cli_check_state *state = tevent_req_data(
+ req, struct netlogon_creds_cli_check_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ netlogon_creds_cli_check_cleanup(req, status);
+ tevent_req_received(req);
+ return status;
+ }
+
+ if (capabilities != NULL) {
+ *capabilities = state->caps;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ union netr_Capabilities *capabilities)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_check_send(frame, ev, context, b);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_check_recv(req, capabilities);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct netlogon_creds_cli_ServerPasswordSet_state {
+ struct tevent_context *ev;
+ struct netlogon_creds_cli_context *context;
+ struct dcerpc_binding_handle *binding_handle;
+ uint32_t old_timeout;
+
+ char *srv_name_slash;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ struct samr_CryptPassword samr_crypt_password;
+ struct netr_CryptPassword netr_crypt_password;
+ struct samr_Password samr_password;
+
+ struct netlogon_creds_CredentialState *creds;
+ struct netlogon_creds_CredentialState tmp_creds;
+ struct netr_Authenticator req_auth;
+ struct netr_Authenticator rep_auth;
+};
+
+static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
+ NTSTATUS status);
+static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
+
+struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ const DATA_BLOB *new_password,
+ const uint32_t *new_version)
+{
+ struct tevent_req *req;
+ struct netlogon_creds_cli_ServerPasswordSet_state *state;
+ struct tevent_req *subreq;
+ bool ok;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_ServerPasswordSet_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->context = context;
+ state->binding_handle = b;
+
+ if (new_password->length < 14) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * netr_ServerPasswordSet
+ */
+ mdfour(state->samr_password.hash, new_password->data, new_password->length);
+
+ /*
+ * netr_ServerPasswordSet2
+ */
+ ok = set_pw_in_buffer(state->samr_crypt_password.data,
+ new_password);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (new_version != NULL) {
+ struct NL_PASSWORD_VERSION version;
+ uint32_t len = IVAL(state->samr_crypt_password.data, 512);
+ uint32_t ofs = 512 - len;
+ uint8_t *p;
+
+ if (len > 500) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+ ofs -= 12;
+
+ version.ReservedField = 0;
+ version.PasswordVersionNumber = *new_version;
+ version.PasswordVersionPresent =
+ NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
+
+ p = state->samr_crypt_password.data + ofs;
+ SIVAL(p, 0, version.ReservedField);
+ SIVAL(p, 4, version.PasswordVersionNumber);
+ SIVAL(p, 8, version.PasswordVersionPresent);
+ }
+
+ state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
+ context->server.computer);
+ if (tevent_req_nomem(state->srv_name_slash, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ dcerpc_binding_handle_auth_info(state->binding_handle,
+ &state->auth_type,
+ &state->auth_level);
+
+ subreq = netlogon_creds_cli_lock_send(state, state->ev,
+ state->context);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_ServerPasswordSet_locked,
+ req);
+
+ return req;
+}
+
+static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
+ NTSTATUS status)
+{
+ struct netlogon_creds_cli_ServerPasswordSet_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_ServerPasswordSet_state);
+
+ if (state->creds == NULL) {
+ return;
+ }
+
+ dcerpc_binding_handle_set_timeout(state->binding_handle,
+ state->old_timeout);
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
+ TALLOC_FREE(state->creds);
+ return;
+ }
+
+ netlogon_creds_cli_delete(state->context, state->creds);
+ TALLOC_FREE(state->creds);
+}
+
+static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_ServerPasswordSet_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_ServerPasswordSet_state);
+ NTSTATUS status;
+
+ status = netlogon_creds_cli_lock_recv(subreq, state,
+ &state->creds);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
+ switch (state->auth_level) {
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ break;
+ default:
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ } else {
+ uint32_t tmp = state->creds->negotiate_flags;
+
+ if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
+ /*
+ * if DCERPC_AUTH_TYPE_SCHANNEL is supported
+ * it should be used, which means
+ * we had a chance to verify no downgrade
+ * happened.
+ *
+ * This relies on netlogon_creds_cli_check*
+ * being called before, as first request after
+ * the DCERPC bind.
+ */
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ }
+
+ state->old_timeout = dcerpc_binding_handle_set_timeout(
+ state->binding_handle, 600000);
+
+ /*
+ * we defer all callbacks in order to cleanup
+ * the database record.
+ */
+ tevent_req_defer_callback(req, state->ev);
+
+ state->tmp_creds = *state->creds;
+ status = netlogon_creds_client_authenticator(&state->tmp_creds,
+ &state->req_auth);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ ZERO_STRUCT(state->rep_auth);
+
+ if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
+
+ if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ status = netlogon_creds_aes_encrypt(&state->tmp_creds,
+ state->samr_crypt_password.data,
+ 516);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+ return;
+ }
+ } else {
+ status = netlogon_creds_arcfour_crypt(&state->tmp_creds,
+ state->samr_crypt_password.data,
+ 516);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+ return;
+ }
+ }
+
+ memcpy(state->netr_crypt_password.data,
+ state->samr_crypt_password.data, 512);
+ state->netr_crypt_password.length =
+ IVAL(state->samr_crypt_password.data, 512);
+
+ subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->tmp_creds.account_name,
+ state->tmp_creds.secure_channel_type,
+ state->tmp_creds.computer_name,
+ &state->req_auth,
+ &state->rep_auth,
+ &state->netr_crypt_password);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+ return;
+ }
+ } else {
+ status = netlogon_creds_des_encrypt(&state->tmp_creds,
+ &state->samr_password);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+ return;
+ }
+
+ subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->tmp_creds.account_name,
+ state->tmp_creds.secure_channel_type,
+ state->tmp_creds.computer_name,
+ &state->req_auth,
+ &state->rep_auth,
+ &state->samr_password);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+ return;
+ }
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_ServerPasswordSet_done,
+ req);
+}
+
+static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_ServerPasswordSet_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_ServerPasswordSet_state);
+ NTSTATUS status;
+ NTSTATUS result;
+ bool ok;
+
+ if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
+ status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
+ &result);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+ return;
+ }
+ } else {
+ status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
+ &result);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+ return;
+ }
+ }
+
+ ok = netlogon_creds_client_check(&state->tmp_creds,
+ &state->rep_auth.cred);
+ if (!ok) {
+ status = NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+ return;
+ }
+
+ if (tevent_req_nterror(req, result)) {
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
+ return;
+ }
+
+ dcerpc_binding_handle_set_timeout(state->binding_handle,
+ state->old_timeout);
+
+ *state->creds = state->tmp_creds;
+ status = netlogon_creds_cli_store(state->context,
+ state->creds);
+ TALLOC_FREE(state->creds);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_ServerPasswordSet(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ const DATA_BLOB *new_password,
+ const uint32_t *new_version)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
+ new_password,
+ new_version);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_ServerPasswordSet_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct netlogon_creds_cli_LogonSamLogon_state {
+ struct tevent_context *ev;
+ struct netlogon_creds_cli_context *context;
+ struct dcerpc_binding_handle *binding_handle;
+
+ char *srv_name_slash;
+
+ enum netr_LogonInfoClass logon_level;
+ const union netr_LogonLevel *const_logon;
+ union netr_LogonLevel *logon;
+ uint32_t flags;
+
+ uint16_t validation_level;
+ union netr_Validation *validation;
+ uint8_t authoritative;
+
+ /*
+ * do we need encryption at the application layer?
+ */
+ bool user_encrypt;
+ bool try_logon_ex;
+ bool try_validation6;
+
+ /*
+ * the read only credentials before we started the operation
+ * used for netr_LogonSamLogonEx() if required (validation_level = 3).
+ */
+ struct netlogon_creds_CredentialState *ro_creds;
+
+ /*
+ * The (locked) credentials used for the credential chain
+ * used for netr_LogonSamLogonWithFlags() or
+ * netr_LogonSamLogonWith().
+ */
+ struct netlogon_creds_CredentialState *lk_creds;
+
+ /*
+ * While we have locked the global credentials (lk_creds above)
+ * we operate an a temporary copy, because a server
+ * may not support netr_LogonSamLogonWithFlags() and
+ * didn't process our netr_Authenticator, so we need to
+ * restart from lk_creds.
+ */
+ struct netlogon_creds_CredentialState tmp_creds;
+ struct netr_Authenticator req_auth;
+ struct netr_Authenticator rep_auth;
+};
+
+static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
+static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
+ NTSTATUS status);
+
+struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ enum netr_LogonInfoClass logon_level,
+ const union netr_LogonLevel *logon,
+ uint32_t flags)
+{
+ struct tevent_req *req;
+ struct netlogon_creds_cli_LogonSamLogon_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_LogonSamLogon_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->context = context;
+ state->binding_handle = b;
+
+ state->logon_level = logon_level;
+ state->const_logon = logon;
+ state->flags = flags;
+
+ state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
+ context->server.computer);
+ if (tevent_req_nomem(state->srv_name_slash, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ switch (logon_level) {
+ case NetlogonInteractiveInformation:
+ case NetlogonInteractiveTransitiveInformation:
+ case NetlogonServiceInformation:
+ case NetlogonServiceTransitiveInformation:
+ case NetlogonGenericInformation:
+ state->user_encrypt = true;
+ break;
+
+ case NetlogonNetworkInformation:
+ case NetlogonNetworkTransitiveInformation:
+ break;
+ }
+
+ state->validation = talloc_zero(state, union netr_Validation);
+ if (tevent_req_nomem(state->validation, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ netlogon_creds_cli_LogonSamLogon_start(req);
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * we defer all callbacks in order to cleanup
+ * the database record.
+ */
+ tevent_req_defer_callback(req, state->ev);
+ return req;
+}
+
+static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
+ NTSTATUS status)
+{
+ struct netlogon_creds_cli_LogonSamLogon_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_LogonSamLogon_state);
+
+ if (state->lk_creds == NULL) {
+ return;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+ /*
+ * This is a hack to recover from a bug in old
+ * Samba servers, when LogonSamLogonEx() fails:
+ *
+ * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
+ *
+ * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
+ *
+ * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
+ * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
+ * If the sign/seal check fails.
+ *
+ * In that case we need to cleanup the netlogon session.
+ *
+ * It's the job of the caller to disconnect the current
+ * connection, if netlogon_creds_cli_LogonSamLogon()
+ * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
+ */
+ if (!state->context->server.try_logon_with) {
+ status = NT_STATUS_NETWORK_ACCESS_DENIED;
+ }
+ }
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
+ TALLOC_FREE(state->lk_creds);
+ return;
+ }
+
+ netlogon_creds_cli_delete(state->context, state->lk_creds);
+ TALLOC_FREE(state->lk_creds);
+}
+
+static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
+{
+ struct netlogon_creds_cli_LogonSamLogon_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_LogonSamLogon_state);
+ struct tevent_req *subreq;
+ NTSTATUS status;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ TALLOC_FREE(state->ro_creds);
+ TALLOC_FREE(state->logon);
+ ZERO_STRUCTP(state->validation);
+
+ dcerpc_binding_handle_auth_info(state->binding_handle,
+ &auth_type, &auth_level);
+
+ state->try_logon_ex = state->context->server.try_logon_ex;
+ state->try_validation6 = state->context->server.try_validation6;
+
+ if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
+ state->try_logon_ex = false;
+ }
+
+ if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
+ state->try_validation6 = false;
+ }
+
+ if (state->try_logon_ex) {
+ if (state->try_validation6) {
+ state->validation_level = 6;
+ } else {
+ state->validation_level = 3;
+ state->user_encrypt = true;
+ }
+
+ state->logon = netlogon_creds_shallow_copy_logon(state,
+ state->logon_level,
+ state->const_logon);
+ if (tevent_req_nomem(state->logon, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+
+ if (state->user_encrypt) {
+ status = netlogon_creds_cli_get(state->context,
+ state,
+ &state->ro_creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ status = NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+
+ status = netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
+ state->logon_level,
+ state->logon);
+ if (!NT_STATUS_IS_OK(status)) {
+ status = NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+ }
+
+ subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->context->client.computer,
+ state->logon_level,
+ state->logon,
+ state->validation_level,
+ state->validation,
+ &state->authoritative,
+ &state->flags);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_LogonSamLogon_done,
+ req);
+ return;
+ }
+
+ if (state->lk_creds == NULL) {
+ subreq = netlogon_creds_cli_lock_send(state, state->ev,
+ state->context);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_LogonSamLogon_done,
+ req);
+ return;
+ }
+
+ state->tmp_creds = *state->lk_creds;
+ status = netlogon_creds_client_authenticator(&state->tmp_creds,
+ &state->req_auth);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+ ZERO_STRUCT(state->rep_auth);
+
+ state->logon = netlogon_creds_shallow_copy_logon(state,
+ state->logon_level,
+ state->const_logon);
+ if (tevent_req_nomem(state->logon, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+
+ status = netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
+ state->logon_level,
+ state->logon);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+
+ state->validation_level = 3;
+
+ if (state->context->server.try_logon_with) {
+ subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->context->client.computer,
+ &state->req_auth,
+ &state->rep_auth,
+ state->logon_level,
+ state->logon,
+ state->validation_level,
+ state->validation,
+ &state->authoritative,
+ &state->flags);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+ } else {
+ state->flags = 0;
+
+ subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->context->client.computer,
+ &state->req_auth,
+ &state->rep_auth,
+ state->logon_level,
+ state->logon,
+ state->validation_level,
+ state->validation,
+ &state->authoritative);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_LogonSamLogon_done,
+ req);
+}
+
+static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_LogonSamLogon_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_LogonSamLogon_state);
+ NTSTATUS status;
+ NTSTATUS result;
+ bool ok;
+
+ if (state->try_logon_ex) {
+ status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
+ state->validation,
+ &result);
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+ state->context->server.try_validation6 = false;
+ state->context->server.try_logon_ex = false;
+ netlogon_creds_cli_LogonSamLogon_start(req);
+ return;
+ }
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+
+ if ((state->validation_level == 6) &&
+ (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
+ {
+ state->context->server.try_validation6 = false;
+ netlogon_creds_cli_LogonSamLogon_start(req);
+ return;
+ }
+
+ if (tevent_req_nterror(req, result)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
+ return;
+ }
+
+ if (state->ro_creds == NULL) {
+ tevent_req_done(req);
+ return;
+ }
+
+ ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
+ if (!ok) {
+ /*
+ * We got a race, lets retry with on authenticator
+ * protection.
+ *
+ * netlogon_creds_cli_LogonSamLogon_start()
+ * will TALLOC_FREE(state->ro_creds);
+ */
+ state->try_logon_ex = false;
+ netlogon_creds_cli_LogonSamLogon_start(req);
+ return;
+ }
+
+ status = netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
+ state->validation_level,
+ state->validation);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+
+ tevent_req_done(req);
+ return;
+ }
+
+ if (state->lk_creds == NULL) {
+ status = netlogon_creds_cli_lock_recv(subreq, state,
+ &state->lk_creds);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+
+ netlogon_creds_cli_LogonSamLogon_start(req);
+ return;
+ }
+
+ if (state->context->server.try_logon_with) {
+ status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
+ state->validation,
+ &result);
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+ state->context->server.try_logon_with = false;
+ netlogon_creds_cli_LogonSamLogon_start(req);
+ return;
+ }
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+ } else {
+ status = dcerpc_netr_LogonSamLogon_recv(subreq,
+ state->validation,
+ &result);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+ }
+
+ ok = netlogon_creds_client_check(&state->tmp_creds,
+ &state->rep_auth.cred);
+ if (!ok) {
+ status = NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+
+ *state->lk_creds = state->tmp_creds;
+ status = netlogon_creds_cli_store(state->context,
+ state->lk_creds);
+ TALLOC_FREE(state->lk_creds);
+
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+
+ if (tevent_req_nterror(req, result)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
+ return;
+ }
+
+ status = netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
+ state->validation_level,
+ state->validation);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *validation_level,
+ union netr_Validation **validation,
+ uint8_t *authoritative,
+ uint32_t *flags)
+{
+ struct netlogon_creds_cli_LogonSamLogon_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_LogonSamLogon_state);
+ NTSTATUS status;
+
+ /* authoritative is also returned on error */
+ *authoritative = state->authoritative;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ tevent_req_received(req);
+ return status;
+ }
+
+ *validation_level = state->validation_level;
+ *validation = talloc_move(mem_ctx, &state->validation);
+ *flags = state->flags;
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_LogonSamLogon(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ enum netr_LogonInfoClass logon_level,
+ const union netr_LogonLevel *logon,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *validation_level,
+ union netr_Validation **validation,
+ uint8_t *authoritative,
+ uint32_t *flags)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
+ logon_level, logon,
+ *flags);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
+ validation_level,
+ validation,
+ authoritative,
+ flags);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
+ struct tevent_context *ev;
+ struct netlogon_creds_cli_context *context;
+ struct dcerpc_binding_handle *binding_handle;
+
+ char *srv_name_slash;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ const char *site_name;
+ uint32_t dns_ttl;
+ struct NL_DNS_NAME_INFO_ARRAY *dns_names;
+
+ struct netlogon_creds_CredentialState *creds;
+ struct netlogon_creds_CredentialState tmp_creds;
+ struct netr_Authenticator req_auth;
+ struct netr_Authenticator rep_auth;
+};
+
+static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
+ NTSTATUS status);
+static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
+
+struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ const char *site_name,
+ uint32_t dns_ttl,
+ struct NL_DNS_NAME_INFO_ARRAY *dns_names)
+{
+ struct tevent_req *req;
+ struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->context = context;
+ state->binding_handle = b;
+
+ state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
+ context->server.computer);
+ if (tevent_req_nomem(state->srv_name_slash, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->site_name = site_name;
+ state->dns_ttl = dns_ttl;
+ state->dns_names = dns_names;
+
+ dcerpc_binding_handle_auth_info(state->binding_handle,
+ &state->auth_type,
+ &state->auth_level);
+
+ subreq = netlogon_creds_cli_lock_send(state, state->ev,
+ state->context);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
+ req);
+
+ return req;
+}
+
+static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
+ NTSTATUS status)
+{
+ struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
+
+ if (state->creds == NULL) {
+ return;
+ }
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
+ TALLOC_FREE(state->creds);
+ return;
+ }
+
+ netlogon_creds_cli_delete(state->context, state->creds);
+ TALLOC_FREE(state->creds);
+}
+
+static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
+ NTSTATUS status;
+
+ status = netlogon_creds_cli_lock_recv(subreq, state,
+ &state->creds);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
+ switch (state->auth_level) {
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ break;
+ default:
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ } else {
+ uint32_t tmp = state->creds->negotiate_flags;
+
+ if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
+ /*
+ * if DCERPC_AUTH_TYPE_SCHANNEL is supported
+ * it should be used, which means
+ * we had a chance to verify no downgrade
+ * happened.
+ *
+ * This relies on netlogon_creds_cli_check*
+ * being called before, as first request after
+ * the DCERPC bind.
+ */
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ }
+
+ /*
+ * we defer all callbacks in order to cleanup
+ * the database record.
+ */
+ tevent_req_defer_callback(req, state->ev);
+
+ state->tmp_creds = *state->creds;
+ status = netlogon_creds_client_authenticator(&state->tmp_creds,
+ &state->req_auth);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ ZERO_STRUCT(state->rep_auth);
+
+ subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->tmp_creds.computer_name,
+ &state->req_auth,
+ &state->rep_auth,
+ state->site_name,
+ state->dns_ttl,
+ state->dns_names);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
+ return;
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
+ req);
+}
+
+static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
+ NTSTATUS status;
+ NTSTATUS result;
+ bool ok;
+
+ /*
+ * We use state->dns_names as the memory context, as this is
+ * the only in/out variable and it has been overwritten by the
+ * out parameter from the server.
+ *
+ * We need to preserve the return value until the caller can use it.
+ */
+ status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
+ &result);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
+ return;
+ }
+
+ ok = netlogon_creds_client_check(&state->tmp_creds,
+ &state->rep_auth.cred);
+ if (!ok) {
+ status = NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
+ return;
+ }
+
+ *state->creds = state->tmp_creds;
+ status = netlogon_creds_cli_store(state->context,
+ state->creds);
+ TALLOC_FREE(state->creds);
+
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
+ return;
+ }
+
+ if (tevent_req_nterror(req, result)) {
+ netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ const char *site_name,
+ uint32_t dns_ttl,
+ struct NL_DNS_NAME_INFO_ARRAY *dns_names)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
+ site_name,
+ dns_ttl,
+ dns_names);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct netlogon_creds_cli_ServerGetTrustInfo_state {
+ struct tevent_context *ev;
+ struct netlogon_creds_cli_context *context;
+ struct dcerpc_binding_handle *binding_handle;
+
+ char *srv_name_slash;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ struct samr_Password new_owf_password;
+ struct samr_Password old_owf_password;
+ struct netr_TrustInfo *trust_info;
+
+ struct netlogon_creds_CredentialState *creds;
+ struct netlogon_creds_CredentialState tmp_creds;
+ struct netr_Authenticator req_auth;
+ struct netr_Authenticator rep_auth;
+};
+
+static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
+ NTSTATUS status);
+static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
+
+struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b)
+{
+ struct tevent_req *req;
+ struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_ServerGetTrustInfo_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->context = context;
+ state->binding_handle = b;
+
+ state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
+ context->server.computer);
+ if (tevent_req_nomem(state->srv_name_slash, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ dcerpc_binding_handle_auth_info(state->binding_handle,
+ &state->auth_type,
+ &state->auth_level);
+
+ subreq = netlogon_creds_cli_lock_send(state, state->ev,
+ state->context);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_ServerGetTrustInfo_locked,
+ req);
+
+ return req;
+}
+
+static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
+ NTSTATUS status)
+{
+ struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_ServerGetTrustInfo_state);
+
+ if (state->creds == NULL) {
+ return;
+ }
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
+ TALLOC_FREE(state->creds);
+ return;
+ }
+
+ netlogon_creds_cli_delete(state->context, state->creds);
+ TALLOC_FREE(state->creds);
+}
+
+static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_ServerGetTrustInfo_state);
+ NTSTATUS status;
+
+ status = netlogon_creds_cli_lock_recv(subreq, state,
+ &state->creds);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
+ switch (state->auth_level) {
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ break;
+ default:
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ } else {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+
+ /*
+ * we defer all callbacks in order to cleanup
+ * the database record.
+ */
+ tevent_req_defer_callback(req, state->ev);
+
+ state->tmp_creds = *state->creds;
+ status = netlogon_creds_client_authenticator(&state->tmp_creds,
+ &state->req_auth);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ ZERO_STRUCT(state->rep_auth);
+
+ subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->tmp_creds.account_name,
+ state->tmp_creds.secure_channel_type,
+ state->tmp_creds.computer_name,
+ &state->req_auth,
+ &state->rep_auth,
+ &state->new_owf_password,
+ &state->old_owf_password,
+ &state->trust_info);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
+ return;
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_ServerGetTrustInfo_done,
+ req);
+}
+
+static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_ServerGetTrustInfo_state);
+ NTSTATUS status;
+ NTSTATUS result;
+ const struct samr_Password zero = {};
+ bool cmp;
+ bool ok;
+
+ /*
+ * We use state->dns_names as the memory context, as this is
+ * the only in/out variable and it has been overwritten by the
+ * out parameter from the server.
+ *
+ * We need to preserve the return value until the caller can use it.
+ */
+ status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
+ return;
+ }
+
+ ok = netlogon_creds_client_check(&state->tmp_creds,
+ &state->rep_auth.cred);
+ if (!ok) {
+ status = NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
+ return;
+ }
+
+ cmp = mem_equal_const_time(state->new_owf_password.hash,
+ zero.hash, sizeof(zero.hash));
+ if (!cmp) {
+ status = netlogon_creds_des_decrypt(&state->tmp_creds,
+ &state->new_owf_password);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
+ return;
+ }
+ }
+ cmp = mem_equal_const_time(state->old_owf_password.hash,
+ zero.hash, sizeof(zero.hash));
+ if (!cmp) {
+ status = netlogon_creds_des_decrypt(&state->tmp_creds,
+ &state->old_owf_password);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
+ return;
+ }
+ }
+
+ *state->creds = state->tmp_creds;
+ status = netlogon_creds_cli_store(state->context,
+ state->creds);
+ TALLOC_FREE(state->creds);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
+ return;
+ }
+
+ if (tevent_req_nterror(req, result)) {
+ netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct samr_Password *new_owf_password,
+ struct samr_Password *old_owf_password,
+ struct netr_TrustInfo **trust_info)
+{
+ struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_ServerGetTrustInfo_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
+ tevent_req_received(req);
+ return status;
+ }
+
+ if (new_owf_password != NULL) {
+ *new_owf_password = state->new_owf_password;
+ }
+ if (old_owf_password != NULL) {
+ *old_owf_password = state->old_owf_password;
+ }
+ if (trust_info != NULL) {
+ *trust_info = talloc_move(mem_ctx, &state->trust_info);
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx,
+ struct samr_Password *new_owf_password,
+ struct samr_Password *old_owf_password,
+ struct netr_TrustInfo **trust_info)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
+ mem_ctx,
+ new_owf_password,
+ old_owf_password,
+ trust_info);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct netlogon_creds_cli_GetForestTrustInformation_state {
+ struct tevent_context *ev;
+ struct netlogon_creds_cli_context *context;
+ struct dcerpc_binding_handle *binding_handle;
+
+ char *srv_name_slash;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ uint32_t flags;
+ struct lsa_ForestTrustInformation *forest_trust_info;
+
+ struct netlogon_creds_CredentialState *creds;
+ struct netlogon_creds_CredentialState tmp_creds;
+ struct netr_Authenticator req_auth;
+ struct netr_Authenticator rep_auth;
+};
+
+static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
+ NTSTATUS status);
+static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
+
+struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b)
+{
+ struct tevent_req *req;
+ struct netlogon_creds_cli_GetForestTrustInformation_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_GetForestTrustInformation_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->context = context;
+ state->binding_handle = b;
+
+ state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
+ context->server.computer);
+ if (tevent_req_nomem(state->srv_name_slash, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->flags = 0;
+
+ dcerpc_binding_handle_auth_info(state->binding_handle,
+ &state->auth_type,
+ &state->auth_level);
+
+ subreq = netlogon_creds_cli_lock_send(state, state->ev,
+ state->context);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_GetForestTrustInformation_locked,
+ req);
+
+ return req;
+}
+
+static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
+ NTSTATUS status)
+{
+ struct netlogon_creds_cli_GetForestTrustInformation_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_GetForestTrustInformation_state);
+
+ if (state->creds == NULL) {
+ return;
+ }
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
+ TALLOC_FREE(state->creds);
+ return;
+ }
+
+ netlogon_creds_cli_delete(state->context, state->creds);
+ TALLOC_FREE(state->creds);
+}
+
+static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_GetForestTrustInformation_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_GetForestTrustInformation_state);
+ NTSTATUS status;
+
+ status = netlogon_creds_cli_lock_recv(subreq, state,
+ &state->creds);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
+ switch (state->auth_level) {
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ break;
+ default:
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ } else {
+ uint32_t tmp = state->creds->negotiate_flags;
+
+ if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
+ /*
+ * if DCERPC_AUTH_TYPE_SCHANNEL is supported
+ * it should be used, which means
+ * we had a chance to verify no downgrade
+ * happened.
+ *
+ * This relies on netlogon_creds_cli_check*
+ * being called before, as first request after
+ * the DCERPC bind.
+ */
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ }
+
+ /*
+ * we defer all callbacks in order to cleanup
+ * the database record.
+ */
+ tevent_req_defer_callback(req, state->ev);
+
+ state->tmp_creds = *state->creds;
+ status = netlogon_creds_client_authenticator(&state->tmp_creds,
+ &state->req_auth);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ ZERO_STRUCT(state->rep_auth);
+
+ subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->tmp_creds.computer_name,
+ &state->req_auth,
+ &state->rep_auth,
+ state->flags,
+ &state->forest_trust_info);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
+ return;
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_GetForestTrustInformation_done,
+ req);
+}
+
+static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_GetForestTrustInformation_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_GetForestTrustInformation_state);
+ NTSTATUS status;
+ NTSTATUS result;
+ bool ok;
+
+ /*
+ * We use state->dns_names as the memory context, as this is
+ * the only in/out variable and it has been overwritten by the
+ * out parameter from the server.
+ *
+ * We need to preserve the return value until the caller can use it.
+ */
+ status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
+ return;
+ }
+
+ ok = netlogon_creds_client_check(&state->tmp_creds,
+ &state->rep_auth.cred);
+ if (!ok) {
+ status = NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
+ return;
+ }
+
+ *state->creds = state->tmp_creds;
+ status = netlogon_creds_cli_store(state->context,
+ state->creds);
+ TALLOC_FREE(state->creds);
+
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
+ return;
+ }
+
+ if (tevent_req_nterror(req, result)) {
+ netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_ForestTrustInformation **forest_trust_info)
+{
+ struct netlogon_creds_cli_GetForestTrustInformation_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_GetForestTrustInformation_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
+ tevent_req_received(req);
+ return status;
+ }
+
+ *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_ForestTrustInformation **forest_trust_info)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
+ mem_ctx,
+ forest_trust_info);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+struct netlogon_creds_cli_SendToSam_state {
+ struct tevent_context *ev;
+ struct netlogon_creds_cli_context *context;
+ struct dcerpc_binding_handle *binding_handle;
+
+ char *srv_name_slash;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ DATA_BLOB opaque;
+
+ struct netlogon_creds_CredentialState *creds;
+ struct netlogon_creds_CredentialState tmp_creds;
+ struct netr_Authenticator req_auth;
+ struct netr_Authenticator rep_auth;
+};
+
+static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
+ NTSTATUS status);
+static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
+
+struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ struct netr_SendToSamBase *message)
+{
+ struct tevent_req *req;
+ struct netlogon_creds_cli_SendToSam_state *state;
+ struct tevent_req *subreq;
+ enum ndr_err_code ndr_err;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_SendToSam_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->context = context;
+ state->binding_handle = b;
+
+ state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
+ context->server.computer);
+ if (tevent_req_nomem(state->srv_name_slash, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
+ (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+
+ dcerpc_binding_handle_auth_info(state->binding_handle,
+ &state->auth_type,
+ &state->auth_level);
+
+ subreq = netlogon_creds_cli_lock_send(state, state->ev,
+ state->context);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_SendToSam_locked,
+ req);
+
+ return req;
+}
+
+static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
+ NTSTATUS status)
+{
+ struct netlogon_creds_cli_SendToSam_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_SendToSam_state);
+
+ if (state->creds == NULL) {
+ return;
+ }
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
+ TALLOC_FREE(state->creds);
+ return;
+ }
+
+ netlogon_creds_cli_delete(state->context, state->creds);
+ TALLOC_FREE(state->creds);
+}
+
+static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_SendToSam_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_SendToSam_state);
+ NTSTATUS status;
+
+ status = netlogon_creds_cli_lock_recv(subreq, state,
+ &state->creds);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
+ switch (state->auth_level) {
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ break;
+ default:
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ } else {
+ uint32_t tmp = state->creds->negotiate_flags;
+
+ if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
+ /*
+ * if DCERPC_AUTH_TYPE_SCHANNEL is supported
+ * it should be used, which means
+ * we had a chance to verify no downgrade
+ * happened.
+ *
+ * This relies on netlogon_creds_cli_check*
+ * being called before, as first request after
+ * the DCERPC bind.
+ */
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ }
+
+ /*
+ * we defer all callbacks in order to cleanup
+ * the database record.
+ */
+ tevent_req_defer_callback(req, state->ev);
+
+ state->tmp_creds = *state->creds;
+ status = netlogon_creds_client_authenticator(&state->tmp_creds,
+ &state->req_auth);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ ZERO_STRUCT(state->rep_auth);
+
+ if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ status = netlogon_creds_aes_encrypt(&state->tmp_creds,
+ state->opaque.data,
+ state->opaque.length);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_SendToSam_cleanup(req, status);
+ return;
+ }
+ } else {
+ status = netlogon_creds_arcfour_crypt(&state->tmp_creds,
+ state->opaque.data,
+ state->opaque.length);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_SendToSam_cleanup(req, status);
+ return;
+ }
+ }
+
+ subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->tmp_creds.computer_name,
+ &state->req_auth,
+ &state->rep_auth,
+ state->opaque.data,
+ state->opaque.length);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_SendToSam_cleanup(req, status);
+ return;
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_SendToSam_done,
+ req);
+}
+
+static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_SendToSam_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_SendToSam_state);
+ NTSTATUS status;
+ NTSTATUS result;
+ bool ok;
+
+ status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_SendToSam_cleanup(req, status);
+ return;
+ }
+
+ ok = netlogon_creds_client_check(&state->tmp_creds,
+ &state->rep_auth.cred);
+ if (!ok) {
+ status = NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_SendToSam_cleanup(req, status);
+ return;
+ }
+
+ *state->creds = state->tmp_creds;
+ status = netlogon_creds_cli_store(state->context,
+ state->creds);
+ TALLOC_FREE(state->creds);
+
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_SendToSam_cleanup(req, status);
+ return;
+ }
+
+ /*
+ * Creds must be stored before we send back application errors
+ * e.g. NT_STATUS_NOT_IMPLEMENTED
+ */
+ if (tevent_req_nterror(req, result)) {
+ netlogon_creds_cli_SendToSam_cleanup(req, result);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_SendToSam_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ netlogon_creds_cli_SendToSam_cleanup(req, status);
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ struct netr_SendToSamBase *message)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_SendToSam_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct netlogon_creds_cli_LogonGetDomainInfo_state {
+ struct tevent_context *ev;
+ struct netlogon_creds_cli_context *context;
+ struct dcerpc_binding_handle *binding_handle;
+
+ char *srv_name_slash;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ uint32_t level;
+ union netr_WorkstationInfo *query;
+ union netr_DomainInfo *info;
+
+ struct netlogon_creds_CredentialState *creds;
+ struct netlogon_creds_CredentialState tmp_creds;
+ struct netr_Authenticator req_auth;
+ struct netr_Authenticator rep_auth;
+};
+
+static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req,
+ NTSTATUS status);
+static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq);
+
+struct tevent_req *netlogon_creds_cli_LogonGetDomainInfo_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ uint32_t level,
+ union netr_WorkstationInfo *query)
+{
+ struct tevent_req *req;
+ struct netlogon_creds_cli_LogonGetDomainInfo_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_LogonGetDomainInfo_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->context = context;
+ state->binding_handle = b;
+
+ state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
+ context->server.computer);
+ if (tevent_req_nomem(state->srv_name_slash, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->level = level;
+ state->query = query;
+ state->info = talloc_zero(state, union netr_DomainInfo);
+ if (tevent_req_nomem(state->info, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ dcerpc_binding_handle_auth_info(state->binding_handle,
+ &state->auth_type,
+ &state->auth_level);
+
+ subreq = netlogon_creds_cli_lock_send(state, state->ev,
+ state->context);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_LogonGetDomainInfo_locked,
+ req);
+
+ return req;
+}
+
+static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req,
+ NTSTATUS status)
+{
+ struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_LogonGetDomainInfo_state);
+
+ if (state->creds == NULL) {
+ return;
+ }
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
+ TALLOC_FREE(state->creds);
+ return;
+ }
+
+ netlogon_creds_cli_delete(state->context, state->creds);
+}
+
+static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_LogonGetDomainInfo_state);
+ NTSTATUS status;
+
+ status = netlogon_creds_cli_lock_recv(subreq, state,
+ &state->creds);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
+ switch (state->auth_level) {
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ break;
+ default:
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ } else {
+ uint32_t tmp = state->creds->negotiate_flags;
+
+ if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
+ /*
+ * if DCERPC_AUTH_TYPE_SCHANNEL is supported
+ * it should be used, which means
+ * we had a chance to verify no downgrade
+ * happened.
+ *
+ * This relies on netlogon_creds_cli_check*
+ * being called before, as first request after
+ * the DCERPC bind.
+ */
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ }
+
+ /*
+ * we defer all callbacks in order to cleanup
+ * the database record.
+ */
+ tevent_req_defer_callback(req, state->ev);
+
+ state->tmp_creds = *state->creds;
+ status = netlogon_creds_client_authenticator(&state->tmp_creds,
+ &state->req_auth);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ ZERO_STRUCT(state->rep_auth);
+
+ subreq = dcerpc_netr_LogonGetDomainInfo_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->tmp_creds.computer_name,
+ &state->req_auth,
+ &state->rep_auth,
+ state->level,
+ state->query,
+ state->info);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
+ return;
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_LogonGetDomainInfo_done,
+ req);
+}
+
+static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_LogonGetDomainInfo_state);
+ NTSTATUS status;
+ NTSTATUS result;
+ bool ok;
+
+ /*
+ * We use state->dns_names as the memory context, as this is
+ * the only in/out variable and it has been overwritten by the
+ * out parameter from the server.
+ *
+ * We need to preserve the return value until the caller can use it.
+ */
+ status = dcerpc_netr_LogonGetDomainInfo_recv(subreq, state->info, &result);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
+ return;
+ }
+
+ ok = netlogon_creds_client_check(&state->tmp_creds,
+ &state->rep_auth.cred);
+ if (!ok) {
+ status = NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
+ return;
+ }
+
+ if (tevent_req_nterror(req, result)) {
+ netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, result);
+ return;
+ }
+
+ *state->creds = state->tmp_creds;
+ status = netlogon_creds_cli_store(state->context,
+ state->creds);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_LogonGetDomainInfo_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ union netr_DomainInfo **info)
+{
+ struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_LogonGetDomainInfo_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
+ tevent_req_received(req);
+ return status;
+ }
+
+ *info = talloc_move(mem_ctx, &state->info);
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_LogonGetDomainInfo(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx,
+ uint32_t level,
+ union netr_WorkstationInfo *query,
+ union netr_DomainInfo **info)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_OK;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_LogonGetDomainInfo_send(frame, ev, context, b,
+ level, query);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_LogonGetDomainInfo_recv(req,
+ mem_ctx,
+ info);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/auth/netlogon_creds_cli.h b/libcli/auth/netlogon_creds_cli.h
new file mode 100644
index 0000000..600242e
--- /dev/null
+++ b/libcli/auth/netlogon_creds_cli.h
@@ -0,0 +1,236 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ module to store/fetch session keys for the schannel client
+
+ Copyright (C) Stefan Metzmacher 2013
+
+ 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/>.
+*/
+
+#ifndef NETLOGON_CREDS_CLI_H
+#define NETLOGON_CREDS_CLI_H
+
+#include "librpc/gen_ndr/dcerpc.h"
+#include "librpc/gen_ndr/schannel.h"
+
+struct netlogon_creds_cli_context;
+struct cli_credentials;
+struct messaging_context;
+struct dcerpc_binding_handle;
+struct db_context;
+
+NTSTATUS netlogon_creds_cli_set_global_db(struct loadparm_context *lp_ctx, struct db_context **db);
+NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx);
+void netlogon_creds_cli_close_global_db(void);
+
+void netlogon_creds_cli_warn_options(struct loadparm_context *lp_ctx);
+
+NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
+ struct messaging_context *msg_ctx,
+ const char *client_account,
+ enum netr_SchannelType type,
+ const char *server_computer,
+ const char *server_netbios_domain,
+ const char *server_dns_domain,
+ TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_cli_context **_context);
+NTSTATUS netlogon_creds_bind_cli_credentials(
+ struct netlogon_creds_cli_context *context, TALLOC_CTX *mem_ctx,
+ struct cli_credentials **pcli_creds);
+
+char *netlogon_creds_cli_debug_string(
+ const struct netlogon_creds_cli_context *context,
+ TALLOC_CTX *mem_ctx);
+
+enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
+ struct netlogon_creds_cli_context *context);
+
+NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
+ TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState **_creds);
+bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
+ const struct netlogon_creds_CredentialState *creds1);
+
+NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
+ struct netlogon_creds_CredentialState *creds);
+NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
+ struct netlogon_creds_CredentialState *creds);
+NTSTATUS netlogon_creds_cli_delete_lck(
+ struct netlogon_creds_cli_context *context);
+
+struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context);
+NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState **creds);
+NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
+ TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState **creds);
+
+struct netlogon_creds_cli_lck;
+
+enum netlogon_creds_cli_lck_type {
+ NETLOGON_CREDS_CLI_LCK_NONE,
+ NETLOGON_CREDS_CLI_LCK_SHARED,
+ NETLOGON_CREDS_CLI_LCK_EXCLUSIVE,
+};
+
+struct tevent_req *netlogon_creds_cli_lck_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ enum netlogon_creds_cli_lck_type type);
+NTSTATUS netlogon_creds_cli_lck_recv(
+ struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_cli_lck **lck);
+NTSTATUS netlogon_creds_cli_lck(
+ struct netlogon_creds_cli_context *context,
+ enum netlogon_creds_cli_lck_type type,
+ TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck);
+
+struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ uint8_t num_nt_hashes,
+ const struct samr_Password * const *nt_hashes);
+NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
+ uint8_t *idx_nt_hashes);
+NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ uint8_t num_nt_hashes,
+ const struct samr_Password * const *nt_hashes,
+ uint8_t *idx_nt_hashes);
+
+struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b);
+NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req,
+ union netr_Capabilities *capabilities);
+NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ union netr_Capabilities *capabilities);
+
+struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ const DATA_BLOB *new_password,
+ const uint32_t *new_version);
+NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req);
+NTSTATUS netlogon_creds_cli_ServerPasswordSet(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ const DATA_BLOB *new_password,
+ const uint32_t *new_version);
+
+struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ enum netr_LogonInfoClass logon_level,
+ const union netr_LogonLevel *logon,
+ uint32_t flags);
+NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *validation_level,
+ union netr_Validation **validation,
+ uint8_t *authoritative,
+ uint32_t *flags);
+NTSTATUS netlogon_creds_cli_LogonSamLogon(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ enum netr_LogonInfoClass logon_level,
+ const union netr_LogonLevel *logon,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *validation_level,
+ union netr_Validation **validation,
+ uint8_t *authoritative,
+ uint32_t *flags);
+struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ const char *site_name,
+ uint32_t dns_ttl,
+ struct NL_DNS_NAME_INFO_ARRAY *dns_names);
+NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req);
+NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ const char *site_name,
+ uint32_t dns_ttl,
+ struct NL_DNS_NAME_INFO_ARRAY *dns_names);
+
+struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b);
+NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct samr_Password *new_owf_password,
+ struct samr_Password *old_owf_password,
+ struct netr_TrustInfo **trust_info);
+NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx,
+ struct samr_Password *new_owf_password,
+ struct samr_Password *old_owf_password,
+ struct netr_TrustInfo **trust_info);
+
+struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b);
+NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_ForestTrustInformation **forest_trust_info);
+NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_ForestTrustInformation **forest_trust_info);
+
+struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ struct netr_SendToSamBase *message);
+NTSTATUS netlogon_creds_cli_SendToSam_recv(struct tevent_req *req);
+NTSTATUS netlogon_creds_cli_SendToSam(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ struct netr_SendToSamBase *message);
+
+struct tevent_req *netlogon_creds_cli_LogonGetDomainInfo_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ uint32_t level,
+ union netr_WorkstationInfo *query);
+NTSTATUS netlogon_creds_cli_LogonGetDomainInfo_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ union netr_DomainInfo **info);
+NTSTATUS netlogon_creds_cli_LogonGetDomainInfo(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx,
+ uint32_t level,
+ union netr_WorkstationInfo *query,
+ union netr_DomainInfo **info);
+
+#endif /* NETLOGON_CREDS_CLI_H */
diff --git a/libcli/auth/ntlm_check.c b/libcli/auth/ntlm_check.c
new file mode 100644
index 0000000..a238870
--- /dev/null
+++ b/libcli/auth/ntlm_check.c
@@ -0,0 +1,656 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2004
+ Copyright (C) Gerald Carter 2003
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+
+ 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 "lib/crypto/md4.h"
+#include "librpc/gen_ndr/netlogon.h"
+#include "libcli/auth/libcli_auth.h"
+
+/****************************************************************************
+ Core of smb password checking routine.
+****************************************************************************/
+
+static bool smb_pwd_check_ntlmv1(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *nt_response,
+ const uint8_t *part_passwd,
+ const DATA_BLOB *sec_blob,
+ DATA_BLOB *user_sess_key)
+{
+ /* Finish the encryption of part_passwd. */
+ uint8_t p24[24];
+ int rc;
+ bool ok;
+
+ if (part_passwd == NULL) {
+ DEBUG(10,("No password set - DISALLOWING access\n"));
+ /* No password set - always false ! */
+ return false;
+ }
+
+ if (sec_blob->length != 8) {
+ DBG_ERR("incorrect challenge size (%zu)\n", sec_blob->length);
+ return false;
+ }
+
+ if (nt_response->length != 24) {
+ DBG_ERR("incorrect password length (%zu)\n",
+ nt_response->length);
+ return false;
+ }
+
+ rc = SMBOWFencrypt(part_passwd, sec_blob->data, p24);
+ if (rc != 0) {
+ return false;
+ }
+
+#if DEBUG_PASSWORD
+ DEBUG(100,("Part password (P16) was |\n"));
+ dump_data(100, part_passwd, 16);
+ DEBUGADD(100,("Password from client was |\n"));
+ dump_data(100, nt_response->data, nt_response->length);
+ DEBUGADD(100,("Given challenge was |\n"));
+ dump_data(100, sec_blob->data, sec_blob->length);
+ DEBUGADD(100,("Value from encryption was |\n"));
+ dump_data(100, p24, 24);
+#endif
+ ok = mem_equal_const_time(p24, nt_response->data, 24);
+ if (!ok) {
+ return false;
+ }
+ if (user_sess_key != NULL) {
+ *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16);
+ if (user_sess_key->data == NULL) {
+ DBG_ERR("data_blob_talloc failed\n");
+ return false;
+ }
+ SMBsesskeygen_ntv1(part_passwd, user_sess_key->data);
+ }
+ return true;
+}
+
+/****************************************************************************
+ Core of smb password checking routine. (NTLMv2, LMv2)
+ Note: The same code works with both NTLMv2 and LMv2.
+****************************************************************************/
+
+static bool smb_pwd_check_ntlmv2(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *ntv2_response,
+ const uint8_t *part_passwd,
+ const DATA_BLOB *sec_blob,
+ const char *user, const char *domain,
+ DATA_BLOB *user_sess_key)
+{
+ /* Finish the encryption of part_passwd. */
+ uint8_t kr[16];
+ uint8_t value_from_encryption[16];
+ DATA_BLOB client_key_data;
+ NTSTATUS status;
+ bool ok;
+
+ if (part_passwd == NULL) {
+ DEBUG(10,("No password set - DISALLOWING access\n"));
+ /* No password set - always false */
+ return false;
+ }
+
+ if (sec_blob->length != 8) {
+ DBG_ERR("incorrect challenge size (%zu)\n", sec_blob->length);
+ return false;
+ }
+
+ if (ntv2_response->length < 24) {
+ /* We MUST have more than 16 bytes, or the stuff below will go
+ crazy. No known implementation sends less than the 24 bytes
+ for LMv2, let alone NTLMv2. */
+ DBG_ERR("incorrect password length (%zu)\n",
+ ntv2_response->length);
+ return false;
+ }
+
+ client_key_data = data_blob_talloc(mem_ctx, ntv2_response->data+16, ntv2_response->length-16);
+ /*
+ todo: should we be checking this for anything? We can't for LMv2,
+ but for NTLMv2 it is meant to contain the current time etc.
+ */
+
+ if (!ntv2_owf_gen(part_passwd, user, domain, kr)) {
+ return false;
+ }
+
+ status = SMBOWFencrypt_ntv2(kr,
+ sec_blob,
+ &client_key_data,
+ value_from_encryption);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+#if DEBUG_PASSWORD
+ DEBUG(100,("Part password (P16) was |\n"));
+ dump_data(100, part_passwd, 16);
+ DEBUGADD(100,("Password from client was |\n"));
+ dump_data(100, ntv2_response->data, ntv2_response->length);
+ DEBUGADD(100,("Variable data from client was |\n"));
+ dump_data(100, client_key_data.data, client_key_data.length);
+ DEBUGADD(100,("Given challenge was |\n"));
+ dump_data(100, sec_blob->data, sec_blob->length);
+ DEBUGADD(100,("Value from encryption was |\n"));
+ dump_data(100, value_from_encryption, 16);
+#endif
+ data_blob_clear_free(&client_key_data);
+
+ ok = mem_equal_const_time(value_from_encryption, ntv2_response->data, 16);
+ if (!ok) {
+ return false;
+ }
+ if (user_sess_key != NULL) {
+ *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16);
+ if (user_sess_key->data == NULL) {
+ DBG_ERR("data_blob_talloc failed\n");
+ return false;
+ }
+
+ status = SMBsesskeygen_ntv2(
+ kr, value_from_encryption, user_sess_key->data);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/****************************************************************************
+ Core of smb password checking routine. (NTLMv2, LMv2)
+ Note: The same code works with both NTLMv2 and LMv2.
+****************************************************************************/
+
+static bool smb_sess_key_ntlmv2(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *ntv2_response,
+ const uint8_t *part_passwd,
+ const DATA_BLOB *sec_blob,
+ const char *user, const char *domain,
+ DATA_BLOB *user_sess_key)
+{
+ /* Finish the encryption of part_passwd. */
+ uint8_t kr[16];
+ uint8_t value_from_encryption[16];
+ DATA_BLOB client_key_data;
+ NTSTATUS status;
+
+ if (part_passwd == NULL) {
+ DEBUG(10,("No password set - DISALLOWING access\n"));
+ /* No password set - always false */
+ return false;
+ }
+
+ if (sec_blob->length != 8) {
+ DBG_ERR("incorrect challenge size (%zu)\n", sec_blob->length);
+ return false;
+ }
+
+ if (ntv2_response->length < 24) {
+ /* We MUST have more than 16 bytes, or the stuff below will go
+ crazy. No known implementation sends less than the 24 bytes
+ for LMv2, let alone NTLMv2. */
+ DBG_ERR("incorrect password length (%zu)\n",
+ ntv2_response->length);
+ return false;
+ }
+
+ client_key_data = data_blob_talloc(mem_ctx, ntv2_response->data+16, ntv2_response->length-16);
+
+ if (!ntv2_owf_gen(part_passwd, user, domain, kr)) {
+ return false;
+ }
+
+ status = SMBOWFencrypt_ntv2(kr,
+ sec_blob,
+ &client_key_data,
+ value_from_encryption);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16);
+ if (user_sess_key->data == NULL) {
+ DBG_ERR("data_blob_talloc failed\n");
+ return false;
+ }
+ status = SMBsesskeygen_ntv2(kr,
+ value_from_encryption,
+ user_sess_key->data);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Compare password hashes against those from the SAM
+ *
+ * @param mem_ctx talloc context
+ * @param client_lanman LANMAN password hash, as supplied by the client
+ * @param client_nt NT (MD4) password hash, as supplied by the client
+ * @param username internal Samba username, for log messages
+ * @param client_username username the client used
+ * @param client_domain domain name the client used (may be mapped)
+ * @param stored_lanman LANMAN password hash, as stored on the SAM
+ * @param stored_nt NT (MD4) password hash, as stored on the SAM
+ * @param user_sess_key User session key
+ * @param lm_sess_key LM session key (first 8 bytes of the LM hash)
+ */
+
+NTSTATUS hash_password_check(TALLOC_CTX *mem_ctx,
+ bool lanman_auth,
+ enum ntlm_auth_level ntlm_auth,
+ const struct samr_Password *client_lanman,
+ const struct samr_Password *client_nt,
+ const char *username,
+ const struct samr_Password *stored_lanman,
+ const struct samr_Password *stored_nt)
+{
+ if (ntlm_auth == NTLM_AUTH_DISABLED) {
+ DBG_WARNING("hash_password_check: NTLM authentication not "
+ "permitted by configuration.\n");
+ return NT_STATUS_NTLM_BLOCKED;
+ }
+
+ if (stored_nt == NULL) {
+ DEBUG(3,("hash_password_check: NO NT password stored for user %s.\n",
+ username));
+ }
+
+ if (client_nt && stored_nt) {
+ if (mem_equal_const_time(client_nt->hash, stored_nt->hash, sizeof(stored_nt->hash))) {
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("hash_password_check: Interactive logon: NT password check failed for user %s\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ } else if (client_lanman && stored_lanman) {
+ if (!lanman_auth) {
+ DEBUG(3,("hash_password_check: Interactive logon: only LANMAN password supplied for user %s, and LM passwords are disabled!\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+ if (strchr_m(username, '@')) {
+ return NT_STATUS_NOT_FOUND;
+ }
+
+ if (mem_equal_const_time(client_lanman->hash, stored_lanman->hash, sizeof(stored_lanman->hash))) {
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("hash_password_check: Interactive logon: LANMAN password check failed for user %s\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+ }
+ if (strchr_m(username, '@')) {
+ return NT_STATUS_NOT_FOUND;
+ }
+ return NT_STATUS_WRONG_PASSWORD;
+}
+
+/**
+ * Check a challenge-response password against the value of the NT or
+ * LM password hash.
+ *
+ * @param mem_ctx talloc context
+ * @param challenge 8-byte challenge. If all zero, forces plaintext comparison
+ * @param nt_response 'unicode' NT response to the challenge, or unicode password
+ * @param lm_response ASCII or LANMAN response to the challenge, or password in DOS code page
+ * @param username internal Samba username, for log messages
+ * @param client_username username the client used
+ * @param client_domain domain name the client used (may be mapped)
+ * @param stored_lanman LANMAN ASCII password from our passdb or similar
+ * @param stored_nt MD4 unicode password from our passdb or similar
+ * @param user_sess_key User session key
+ * @param lm_sess_key LM session key (first 8 bytes of the LM hash)
+ */
+
+NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx,
+ bool lanman_auth,
+ enum ntlm_auth_level ntlm_auth,
+ uint32_t logon_parameters,
+ const DATA_BLOB *challenge,
+ const DATA_BLOB *lm_response,
+ const DATA_BLOB *nt_response,
+ const char *username,
+ const char *client_username,
+ const char *client_domain,
+ const struct samr_Password *stored_lanman,
+ const struct samr_Password *stored_nt,
+ DATA_BLOB *user_sess_key,
+ DATA_BLOB *lm_sess_key)
+{
+ DATA_BLOB tmp_sess_key;
+ const char *upper_client_domain = NULL;
+
+ if (ntlm_auth == NTLM_AUTH_DISABLED) {
+ DBG_WARNING("ntlm_password_check: NTLM authentication not "
+ "permitted by configuration.\n");
+ return NT_STATUS_NTLM_BLOCKED;
+ }
+
+ if (client_domain != NULL) {
+ upper_client_domain = talloc_strdup_upper(mem_ctx, client_domain);
+ if (upper_client_domain == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (stored_nt == NULL) {
+ DEBUG(3,("ntlm_password_check: NO NT password stored for user %s.\n",
+ username));
+ }
+
+ *lm_sess_key = data_blob(NULL, 0);
+ *user_sess_key = data_blob(NULL, 0);
+
+ /* Check for cleartext netlogon. Used by Exchange 5.5. */
+ if ((logon_parameters & MSV1_0_CLEARTEXT_PASSWORD_ALLOWED)
+ && challenge->length == 8
+ && (all_zero(challenge->data, challenge->length))) {
+ struct samr_Password client_nt;
+ struct samr_Password client_lm;
+ char *unix_pw = NULL;
+ bool lm_ok;
+ size_t converted_size = 0;
+
+ DEBUG(4,("ntlm_password_check: checking plaintext passwords for user %s\n",
+ username));
+ mdfour(client_nt.hash, nt_response->data, nt_response->length);
+
+ if (lm_response->length &&
+ (convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX,
+ lm_response->data, lm_response->length,
+ &unix_pw, &converted_size))) {
+ if (E_deshash(unix_pw, client_lm.hash)) {
+ lm_ok = true;
+ } else {
+ lm_ok = false;
+ }
+ } else {
+ lm_ok = false;
+ }
+ return hash_password_check(mem_ctx,
+ lanman_auth,
+ ntlm_auth,
+ lm_ok ? &client_lm : NULL,
+ nt_response->length ? &client_nt : NULL,
+ username,
+ stored_lanman, stored_nt);
+ }
+
+ if (nt_response->length != 0 && nt_response->length < 24) {
+ DBG_NOTICE("invalid NT password length (%zu) for user %s\n",
+ nt_response->length,
+ username);
+ }
+
+ if (nt_response->length > 24 && stored_nt) {
+ /* We have the NT MD4 hash challenge available - see if we can
+ use it
+ */
+ DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with domain [%s]\n",
+ client_domain ? client_domain : "<NULL>"));
+ if (smb_pwd_check_ntlmv2(mem_ctx,
+ nt_response,
+ stored_nt->hash, challenge,
+ client_username,
+ client_domain,
+ user_sess_key)) {
+ if (user_sess_key->length) {
+ *lm_sess_key = data_blob_talloc(mem_ctx, user_sess_key->data, MIN(8, user_sess_key->length));
+ }
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with uppercased version of domain [%s]\n",
+ upper_client_domain ? upper_client_domain : "<NULL>"));
+ if (smb_pwd_check_ntlmv2(mem_ctx,
+ nt_response,
+ stored_nt->hash, challenge,
+ client_username,
+ upper_client_domain,
+ user_sess_key)) {
+ if (user_sess_key->length) {
+ *lm_sess_key = data_blob_talloc(mem_ctx, user_sess_key->data, MIN(8, user_sess_key->length));
+ }
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(4,("ntlm_password_check: Checking NTLMv2 password without a domain\n"));
+ if (smb_pwd_check_ntlmv2(mem_ctx,
+ nt_response,
+ stored_nt->hash, challenge,
+ client_username,
+ "",
+ user_sess_key)) {
+ if (user_sess_key->length) {
+ *lm_sess_key = data_blob_talloc(mem_ctx, user_sess_key->data, MIN(8, user_sess_key->length));
+ }
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("ntlm_password_check: NTLMv2 password check failed\n"));
+ }
+ } else if (nt_response->length == 24 && stored_nt) {
+ if (ntlm_auth == NTLM_AUTH_ON
+ || (ntlm_auth == NTLM_AUTH_MSCHAPv2_NTLMV2_ONLY && (logon_parameters & MSV1_0_ALLOW_MSVCHAPV2))) {
+ /* We have the NT MD4 hash challenge available - see if we can
+ use it (ie. does it exist in the smbpasswd file).
+ */
+ DEBUG(4,("ntlm_password_check: Checking NT MD4 password\n"));
+ if (smb_pwd_check_ntlmv1(mem_ctx,
+ nt_response,
+ stored_nt->hash, challenge,
+ user_sess_key)) {
+ /* The LM session key for this response is not very secure,
+ so use it only if we otherwise allow LM authentication */
+
+ if (lanman_auth && stored_lanman) {
+ *lm_sess_key = data_blob_talloc(mem_ctx, stored_lanman->hash, MIN(8, user_sess_key->length));
+ }
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("ntlm_password_check: NT MD4 password check failed for user %s\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+ } else {
+ DEBUG(2,("ntlm_password_check: NTLMv1 passwords NOT PERMITTED for user %s\n",
+ username));
+ /* no return, because we might pick up LMv2 in the LM field */
+ }
+ }
+
+ if (lm_response->length == 0) {
+ DEBUG(3,("ntlm_password_check: NEITHER LanMan nor NT password supplied for user %s\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ if (lm_response->length < 24) {
+ DBG_NOTICE("invalid LanMan password length (%zu) for "
+ "user %s\n",
+ nt_response->length, username);
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ if (!lanman_auth) {
+ DEBUG(3,("ntlm_password_check: Lanman passwords NOT PERMITTED for user %s\n",
+ username));
+ } else if (!stored_lanman) {
+ DEBUG(3,("ntlm_password_check: NO LanMan password set for user %s (and no NT password supplied)\n",
+ username));
+ } else if (strchr_m(username, '@')) {
+ DEBUG(3,("ntlm_password_check: NO LanMan password allowed for username@realm logins (user: %s)\n",
+ username));
+ } else {
+ DEBUG(4,("ntlm_password_check: Checking LM password\n"));
+ if (smb_pwd_check_ntlmv1(mem_ctx,
+ lm_response,
+ stored_lanman->hash, challenge,
+ NULL)) {
+ /* The session key for this response is still very odd.
+ It not very secure, so use it only if we otherwise
+ allow LM authentication */
+
+ if (lanman_auth && stored_lanman) {
+ uint8_t first_8_lm_hash[16];
+ memcpy(first_8_lm_hash, stored_lanman->hash, 8);
+ memset(first_8_lm_hash + 8, '\0', 8);
+ *user_sess_key = data_blob_talloc(mem_ctx, first_8_lm_hash, 16);
+ *lm_sess_key = data_blob_talloc(mem_ctx, stored_lanman->hash, 8);
+ }
+ return NT_STATUS_OK;
+ }
+ }
+
+ if (!stored_nt) {
+ DEBUG(4,("ntlm_password_check: LM password check failed for user, no NT password %s\n",username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ /* This is for 'LMv2' authentication. almost NTLMv2 but limited to 24 bytes.
+ - related to Win9X, legacy NAS pass-though authentication
+ */
+ DEBUG(4,("ntlm_password_check: Checking LMv2 password with domain %s\n",
+ client_domain ? client_domain : "<NULL>"));
+ if (smb_pwd_check_ntlmv2(mem_ctx,
+ lm_response,
+ stored_nt->hash, challenge,
+ client_username,
+ client_domain,
+ &tmp_sess_key)) {
+ if (nt_response->length > 24) {
+ /* If NTLMv2 authentication has preceded us
+ * (even if it failed), then use the session
+ * key from that. See the RPC-SAMLOGON
+ * torture test */
+ smb_sess_key_ntlmv2(mem_ctx,
+ nt_response,
+ stored_nt->hash, challenge,
+ client_username,
+ client_domain,
+ user_sess_key);
+ } else {
+ /* Otherwise, use the LMv2 session key */
+ *user_sess_key = tmp_sess_key;
+ }
+ if (user_sess_key->length) {
+ *lm_sess_key = data_blob_talloc(mem_ctx, user_sess_key->data, MIN(8, user_sess_key->length));
+ }
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(4,("ntlm_password_check: Checking LMv2 password with upper-cased version of domain %s\n",
+ upper_client_domain ? upper_client_domain : "<NULL>"));
+ if (smb_pwd_check_ntlmv2(mem_ctx,
+ lm_response,
+ stored_nt->hash, challenge,
+ client_username,
+ upper_client_domain,
+ &tmp_sess_key)) {
+ if (nt_response->length > 24) {
+ /* If NTLMv2 authentication has preceded us
+ * (even if it failed), then use the session
+ * key from that. See the RPC-SAMLOGON
+ * torture test */
+ smb_sess_key_ntlmv2(mem_ctx,
+ nt_response,
+ stored_nt->hash, challenge,
+ client_username,
+ upper_client_domain,
+ user_sess_key);
+ } else {
+ /* Otherwise, use the LMv2 session key */
+ *user_sess_key = tmp_sess_key;
+ }
+ if (user_sess_key->length) {
+ *lm_sess_key = data_blob_talloc(mem_ctx, user_sess_key->data, MIN(8, user_sess_key->length));
+ }
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(4,("ntlm_password_check: Checking LMv2 password without a domain\n"));
+ if (smb_pwd_check_ntlmv2(mem_ctx,
+ lm_response,
+ stored_nt->hash, challenge,
+ client_username,
+ "",
+ &tmp_sess_key)) {
+ if (nt_response->length > 24) {
+ /* If NTLMv2 authentication has preceded us
+ * (even if it failed), then use the session
+ * key from that. See the RPC-SAMLOGON
+ * torture test */
+ smb_sess_key_ntlmv2(mem_ctx,
+ nt_response,
+ stored_nt->hash, challenge,
+ client_username,
+ "",
+ user_sess_key);
+ } else {
+ /* Otherwise, use the LMv2 session key */
+ *user_sess_key = tmp_sess_key;
+ }
+ if (user_sess_key->length) {
+ *lm_sess_key = data_blob_talloc(mem_ctx, user_sess_key->data, MIN(8, user_sess_key->length));
+ }
+ return NT_STATUS_OK;
+ }
+
+ /* Apparently NT accepts NT responses in the LM field
+ - I think this is related to Win9X pass-though authentication
+ */
+ DEBUG(4,("ntlm_password_check: Checking NT MD4 password in LM field\n"));
+ if (ntlm_auth == NTLM_AUTH_ON) {
+ if (smb_pwd_check_ntlmv1(mem_ctx,
+ lm_response,
+ stored_nt->hash, challenge,
+ NULL)) {
+ /* The session key for this response is still very odd.
+ It not very secure, so use it only if we otherwise
+ allow LM authentication */
+
+ if (lanman_auth && stored_lanman) {
+ uint8_t first_8_lm_hash[16];
+ memcpy(first_8_lm_hash, stored_lanman->hash, 8);
+ memset(first_8_lm_hash + 8, '\0', 8);
+ *user_sess_key = data_blob_talloc(mem_ctx, first_8_lm_hash, 16);
+ *lm_sess_key = data_blob_talloc(mem_ctx, stored_lanman->hash, 8);
+ }
+ return NT_STATUS_OK;
+ }
+ DEBUG(3,("ntlm_password_check: LM password, NT MD4 password in LM field and LMv2 failed for user %s\n",username));
+ } else {
+ DEBUG(3,("ntlm_password_check: LM password and LMv2 failed for user %s, and NT MD4 password in LM field not permitted\n",username));
+ }
+
+ /* Try and match error codes */
+ if (strchr_m(username, '@')) {
+ return NT_STATUS_NOT_FOUND;
+ }
+ return NT_STATUS_WRONG_PASSWORD;
+}
+
diff --git a/libcli/auth/ntlm_check.h b/libcli/auth/ntlm_check.h
new file mode 100644
index 0000000..3fcd1f4
--- /dev/null
+++ b/libcli/auth/ntlm_check.h
@@ -0,0 +1,87 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2004
+ Copyright (C) Gerald Carter 2003
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+
+ 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/>.
+*/
+#ifndef __LIBCLI_AUTH_NTLM_CHECK_H__
+#define __LIBCLI_AUTH_NTLM_CHECK_H__
+
+/* mangled names options */
+enum ntlm_auth_level {NTLM_AUTH_DISABLED, NTLM_AUTH_ON,
+ NTLM_AUTH_NTLMV2_ONLY,
+ NTLM_AUTH_MSCHAPv2_NTLMV2_ONLY};
+
+struct samr_Password;
+
+/**
+ * Compare password hashes against those from the SAM
+ *
+ * @param mem_ctx talloc context
+ * @param client_lanman LANMAN password hash, as supplied by the client
+ * @param client_nt NT (MD4) password hash, as supplied by the client
+ * @param username internal Samba username, for log messages
+ * @param client_username username the client used
+ * @param client_domain domain name the client used (may be mapped)
+ * @param stored_lanman LANMAN password hash, as stored on the SAM
+ * @param stored_nt NT (MD4) password hash, as stored on the SAM
+ * @param user_sess_key User session key
+ * @param lm_sess_key LM session key (first 8 bytes of the LM hash)
+ */
+
+NTSTATUS hash_password_check(TALLOC_CTX *mem_ctx,
+ bool lanman_auth,
+ enum ntlm_auth_level ntlm_auth,
+ const struct samr_Password *client_lanman,
+ const struct samr_Password *client_nt,
+ const char *username,
+ const struct samr_Password *stored_lanman,
+ const struct samr_Password *stored_nt);
+
+/**
+ * Check a challenge-response password against the value of the NT or
+ * LM password hash.
+ *
+ * @param mem_ctx talloc context
+ * @param challenge 8-byte challenge. If all zero, forces plaintext comparison
+ * @param nt_response 'unicode' NT response to the challenge, or unicode password
+ * @param lm_response ASCII or LANMAN response to the challenge, or password in DOS code page
+ * @param username internal Samba username, for log messages
+ * @param client_username username the client used
+ * @param client_domain domain name the client used (may be mapped)
+ * @param stored_lanman LANMAN ASCII password from our passdb or similar
+ * @param stored_nt MD4 unicode password from our passdb or similar
+ * @param user_sess_key User session key
+ * @param lm_sess_key LM session key (first 8 bytes of the LM hash)
+ */
+
+NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx,
+ bool lanman_auth,
+ enum ntlm_auth_level ntlm_auth,
+ uint32_t logon_parameters,
+ const DATA_BLOB *challenge,
+ const DATA_BLOB *lm_response,
+ const DATA_BLOB *nt_response,
+ const char *username,
+ const char *client_username,
+ const char *client_domain,
+ const struct samr_Password *stored_lanman,
+ const struct samr_Password *stored_nt,
+ DATA_BLOB *user_sess_key,
+ DATA_BLOB *lm_sess_key);
+
+#endif /* __LIBCLI_AUTH_NTLM_CHECK_H__ */
diff --git a/libcli/auth/pam_errors.c b/libcli/auth/pam_errors.c
new file mode 100644
index 0000000..5592d39
--- /dev/null
+++ b/libcli/auth/pam_errors.c
@@ -0,0 +1,143 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * PAM error mapping functions
+ * Copyright (C) Andrew Bartlett 2002
+ *
+ * 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 "../libcli/auth/pam_errors.h"
+
+#ifdef WITH_PAM
+#if defined(HAVE_SECURITY_PAM_APPL_H)
+#include <security/pam_appl.h>
+#elif defined(HAVE_PAM_PAM_APPL_H)
+#include <pam/pam_appl.h>
+#endif
+
+#if defined(PAM_AUTHTOK_RECOVERY_ERR) && !defined(PAM_AUTHTOK_RECOVER_ERR)
+#define PAM_AUTHTOK_RECOVER_ERR PAM_AUTHTOK_RECOVERY_ERR
+#endif
+
+/* PAM -> NT_STATUS map */
+static const struct {
+ int pam_code;
+ NTSTATUS ntstatus;
+} pam_to_nt_status_map[] = {
+ {PAM_OPEN_ERR, NT_STATUS_UNSUCCESSFUL},
+ {PAM_SYMBOL_ERR, NT_STATUS_UNSUCCESSFUL},
+ {PAM_SERVICE_ERR, NT_STATUS_UNSUCCESSFUL},
+ {PAM_SYSTEM_ERR, NT_STATUS_UNSUCCESSFUL},
+ {PAM_BUF_ERR, NT_STATUS_NO_MEMORY},
+ {PAM_PERM_DENIED, NT_STATUS_ACCESS_DENIED},
+ {PAM_AUTH_ERR, NT_STATUS_WRONG_PASSWORD},
+ {PAM_CRED_INSUFFICIENT, NT_STATUS_INSUFFICIENT_LOGON_INFO}, /* FIXME: Is this correct? */
+ {PAM_AUTHINFO_UNAVAIL, NT_STATUS_LOGON_FAILURE},
+ {PAM_USER_UNKNOWN, NT_STATUS_NO_SUCH_USER},
+ {PAM_MAXTRIES, NT_STATUS_REMOTE_SESSION_LIMIT}, /* FIXME: Is this correct? */
+ {PAM_NEW_AUTHTOK_REQD, NT_STATUS_PASSWORD_MUST_CHANGE},
+ {PAM_ACCT_EXPIRED, NT_STATUS_ACCOUNT_EXPIRED},
+ {PAM_SESSION_ERR, NT_STATUS_INSUFFICIENT_RESOURCES},
+ {PAM_CRED_UNAVAIL, NT_STATUS_NO_TOKEN}, /* FIXME: Is this correct? */
+ {PAM_CRED_EXPIRED, NT_STATUS_PASSWORD_EXPIRED}, /* FIXME: Is this correct? */
+ {PAM_CRED_ERR, NT_STATUS_UNSUCCESSFUL},
+ {PAM_AUTHTOK_ERR, NT_STATUS_UNSUCCESSFUL},
+#ifdef PAM_AUTHTOK_RECOVER_ERR
+ {PAM_AUTHTOK_RECOVER_ERR, NT_STATUS_UNSUCCESSFUL},
+#endif
+ {PAM_AUTHTOK_EXPIRED, NT_STATUS_PASSWORD_EXPIRED},
+ {PAM_SUCCESS, NT_STATUS_OK}
+};
+
+/* NT_STATUS -> PAM map */
+static const struct {
+ NTSTATUS ntstatus;
+ int pam_code;
+} nt_status_to_pam_map[] = {
+ {NT_STATUS_UNSUCCESSFUL, PAM_SYSTEM_ERR},
+ {NT_STATUS_NO_SUCH_USER, PAM_USER_UNKNOWN},
+ {NT_STATUS_WRONG_PASSWORD, PAM_AUTH_ERR},
+ {NT_STATUS_LOGON_FAILURE, PAM_AUTH_ERR},
+ {NT_STATUS_ACCOUNT_EXPIRED, PAM_ACCT_EXPIRED},
+ {NT_STATUS_ACCOUNT_DISABLED, PAM_ACCT_EXPIRED},
+ {NT_STATUS_PASSWORD_EXPIRED, PAM_AUTHTOK_EXPIRED},
+ {NT_STATUS_PASSWORD_MUST_CHANGE, PAM_NEW_AUTHTOK_REQD},
+ {NT_STATUS_ACCOUNT_LOCKED_OUT, PAM_MAXTRIES},
+ {NT_STATUS_NO_MEMORY, PAM_BUF_ERR},
+ {NT_STATUS_PASSWORD_RESTRICTION, PAM_AUTHTOK_ERR},
+ {NT_STATUS_PWD_HISTORY_CONFLICT, PAM_AUTHTOK_ERR},
+ {NT_STATUS_PWD_TOO_RECENT, PAM_AUTHTOK_ERR},
+ {NT_STATUS_PWD_TOO_SHORT, PAM_AUTHTOK_ERR},
+ {NT_STATUS_BACKUP_CONTROLLER, PAM_AUTHINFO_UNAVAIL},
+ {NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND, PAM_AUTHINFO_UNAVAIL},
+ {NT_STATUS_NO_LOGON_SERVERS, PAM_AUTHINFO_UNAVAIL},
+ {NT_STATUS_INVALID_WORKSTATION, PAM_PERM_DENIED},
+ {NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT, PAM_AUTHINFO_UNAVAIL},
+ {NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT, PAM_AUTHINFO_UNAVAIL},
+ {NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT, PAM_AUTHINFO_UNAVAIL},
+ {NT_STATUS_OK, PAM_SUCCESS}
+};
+
+/*****************************************************************************
+convert a PAM error to a NT status32 code
+ *****************************************************************************/
+NTSTATUS pam_to_nt_status(int pam_error)
+{
+ int i;
+ if (pam_error == 0) return NT_STATUS_OK;
+
+ for (i=0; NT_STATUS_V(pam_to_nt_status_map[i].ntstatus); i++) {
+ if (pam_error == pam_to_nt_status_map[i].pam_code)
+ return pam_to_nt_status_map[i].ntstatus;
+ }
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+/*****************************************************************************
+convert an NT status32 code to a PAM error
+ *****************************************************************************/
+int nt_status_to_pam(NTSTATUS nt_status)
+{
+ int i;
+ if NT_STATUS_IS_OK(nt_status) return PAM_SUCCESS;
+
+ for (i=0; NT_STATUS_V(nt_status_to_pam_map[i].ntstatus); i++) {
+ if (NT_STATUS_EQUAL(nt_status,nt_status_to_pam_map[i].ntstatus))
+ return nt_status_to_pam_map[i].pam_code;
+ }
+ return PAM_SYSTEM_ERR;
+}
+
+#else
+
+/*****************************************************************************
+convert a PAM error to a NT status32 code
+ *****************************************************************************/
+NTSTATUS pam_to_nt_status(int pam_error)
+{
+ if (pam_error == 0) return NT_STATUS_OK;
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+/*****************************************************************************
+convert an NT status32 code to a PAM error
+ *****************************************************************************/
+int nt_status_to_pam(NTSTATUS nt_status)
+{
+ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_OK)) return 0;
+ return 4; /* PAM_SYSTEM_ERR */
+}
+
+#endif
diff --git a/libcli/auth/pam_errors.h b/libcli/auth/pam_errors.h
new file mode 100644
index 0000000..128910f
--- /dev/null
+++ b/libcli/auth/pam_errors.h
@@ -0,0 +1,33 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * PAM error mapping functions
+ * Copyright (C) Andrew Bartlett 2002
+ *
+ * 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/>.
+ */
+
+#ifndef __LIBCLI_AUTH_PAM_ERRORS_H__
+#define __LIBCLI_AUTH_PAM_ERRORS_H__
+
+/*****************************************************************************
+convert a PAM error to a NT status32 code
+ *****************************************************************************/
+NTSTATUS pam_to_nt_status(int pam_error);
+
+/*****************************************************************************
+convert an NT status32 code to a PAM error
+ *****************************************************************************/
+int nt_status_to_pam(NTSTATUS nt_status);
+
+#endif /* __LIBCLI_AUTH_PAM_ERRORS_H__ */
diff --git a/libcli/auth/proto.h b/libcli/auth/proto.h
new file mode 100644
index 0000000..b202542
--- /dev/null
+++ b/libcli/auth/proto.h
@@ -0,0 +1,296 @@
+#ifndef _LIBCLI_AUTH_PROTO_H__
+#define _LIBCLI_AUTH_PROTO_H__
+
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2)
+
+#include "lib/crypto/gnutls_helpers.h"
+
+/* this file contains prototypes for functions that are private
+ * to this subsystem or library. These functions should not be
+ * used outside this particular subsystem! */
+
+
+/* The following definitions come from libcli/auth/credentials.c */
+
+bool netlogon_creds_is_random_challenge(const struct netr_Credential *challenge);
+void netlogon_creds_random_challenge(struct netr_Credential *challenge);
+
+NTSTATUS netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds,
+ struct netr_LMSessionKey *key);
+NTSTATUS netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds,
+ struct netr_LMSessionKey *key);
+NTSTATUS netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState *creds,
+ struct samr_Password *pass);
+NTSTATUS netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState *creds,
+ struct samr_Password *pass);
+NTSTATUS netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState *creds,
+ uint8_t *data,
+ size_t len);
+NTSTATUS netlogon_creds_aes_encrypt(struct netlogon_creds_CredentialState *creds,
+ uint8_t *data,
+ size_t len);
+NTSTATUS netlogon_creds_aes_decrypt(struct netlogon_creds_CredentialState *creds,
+ uint8_t *data,
+ size_t len);
+
+/*****************************************************************
+The above functions are common to the client and server interface
+next comes the client specific functions
+******************************************************************/
+struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *mem_ctx,
+ const char *client_account,
+ const char *client_computer_name,
+ uint16_t secure_channel_type,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge,
+ const struct samr_Password *machine_password,
+ struct netr_Credential *initial_credential,
+ uint32_t negotiate_flags);
+struct netlogon_creds_CredentialState *netlogon_creds_client_init_session_key(TALLOC_CTX *mem_ctx,
+ const uint8_t session_key[16]);
+NTSTATUS
+netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds,
+ struct netr_Authenticator *next);
+bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds,
+ const struct netr_Credential *received_credentials);
+struct netlogon_creds_CredentialState *netlogon_creds_copy(
+ TALLOC_CTX *mem_ctx,
+ const struct netlogon_creds_CredentialState *creds_in);
+
+/*****************************************************************
+The above functions are common to the client and server interface
+next comes the server specific functions
+******************************************************************/
+struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *mem_ctx,
+ const char *client_account,
+ const char *client_computer_name,
+ uint16_t secure_channel_type,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge,
+ const struct samr_Password *machine_password,
+ const struct netr_Credential *credentials_in,
+ struct netr_Credential *credentials_out,
+ uint32_t negotiate_flags);
+NTSTATUS netlogon_creds_server_step_check(struct netlogon_creds_CredentialState *creds,
+ const struct netr_Authenticator *received_authenticator,
+ struct netr_Authenticator *return_authenticator) ;
+NTSTATUS netlogon_creds_decrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
+ uint16_t validation_level,
+ union netr_Validation *validation);
+NTSTATUS netlogon_creds_encrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
+ uint16_t validation_level,
+ union netr_Validation *validation);
+NTSTATUS netlogon_creds_decrypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
+ enum netr_LogonInfoClass level,
+ union netr_LogonLevel *logon);
+NTSTATUS netlogon_creds_encrypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
+ enum netr_LogonInfoClass level,
+ union netr_LogonLevel *logon);
+union netr_LogonLevel *netlogon_creds_shallow_copy_logon(TALLOC_CTX *mem_ctx,
+ enum netr_LogonInfoClass level,
+ const union netr_LogonLevel *in);
+
+/* The following definitions come from libcli/auth/session.c */
+
+int sess_crypt_blob(DATA_BLOB *out, const DATA_BLOB *in, const DATA_BLOB *session_key,
+ enum samba_gnutls_direction encrypt);
+DATA_BLOB sess_encrypt_string(const char *str, const DATA_BLOB *session_key);
+char *sess_decrypt_string(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob, const DATA_BLOB *session_key);
+DATA_BLOB sess_encrypt_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob_in, const DATA_BLOB *session_key);
+NTSTATUS sess_decrypt_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, const DATA_BLOB *session_key,
+ DATA_BLOB *ret);
+
+/* The following definitions come from libcli/auth/smbencrypt.c */
+
+int SMBencrypt_hash(const uint8_t lm_hash[16], const uint8_t *c8, uint8_t p24[24]);
+bool SMBencrypt(const char *passwd, const uint8_t *c8, uint8_t p24[24]);
+
+/**
+ * Creates the MD4 Hash of the users password in NT UNICODE.
+ * @param passwd password in 'unix' charset.
+ * @param p16 return password hashed with md4, caller allocated 16 byte buffer
+ */
+bool E_md4hash(const char *passwd, uint8_t p16[16]);
+
+/**
+ * Creates the DES forward-only Hash of the users password in DOS ASCII charset
+ * @param passwd password in 'unix' charset.
+ * @param p16 return password hashed with DES, caller allocated 16 byte buffer
+ * @return false if password was > 14 characters, and therefore may be incorrect, otherwise true
+ * @note p16 is filled in regardless
+ */
+bool E_deshash(const char *passwd, uint8_t p16[16]);
+
+/**
+ * Creates the MD4 and DES (LM) Hash of the users password.
+ * MD4 is of the NT Unicode, DES is of the DOS UPPERCASE password.
+ * @param passwd password in 'unix' charset.
+ * @param nt_p16 return password hashed with md4, caller allocated 16 byte buffer
+ * @param p16 return password hashed with des, caller allocated 16 byte buffer
+ */
+void nt_lm_owf_gen(const char *pwd, uint8_t nt_p16[16], uint8_t p16[16]);
+bool ntv2_owf_gen(const uint8_t owf[16],
+ const char *user_in, const char *domain_in,
+ uint8_t kr_buf[16]);
+int SMBOWFencrypt(const uint8_t passwd[16], const uint8_t *c8, uint8_t p24[24]);
+int SMBNTencrypt_hash(const uint8_t nt_hash[16], const uint8_t *c8, uint8_t *p24);
+int SMBNTencrypt(const char *passwd, const uint8_t *c8, uint8_t *p24);
+NTSTATUS SMBOWFencrypt_ntv2(const uint8_t kr[16],
+ const DATA_BLOB *srv_chal,
+ const DATA_BLOB *smbcli_chal,
+ uint8_t resp_buf[16]);
+NTSTATUS SMBsesskeygen_ntv2(const uint8_t kr[16],
+ const uint8_t *nt_resp,
+ uint8_t sess_key[16]);
+void SMBsesskeygen_ntv1(const uint8_t kr[16], uint8_t sess_key[16]);
+NTSTATUS SMBsesskeygen_lm_sess_key(const uint8_t lm_hash[16],
+ const uint8_t lm_resp[24], /* only uses 8 */
+ uint8_t sess_key[16]);
+DATA_BLOB NTLMv2_generate_names_blob(TALLOC_CTX *mem_ctx,
+ const char *hostname,
+ const char *domain);
+bool SMBNTLMv2encrypt_hash(TALLOC_CTX *mem_ctx,
+ const char *user, const char *domain, const uint8_t nt_hash[16],
+ const DATA_BLOB *server_chal,
+ const NTTIME *server_timestamp,
+ const DATA_BLOB *names_blob,
+ DATA_BLOB *lm_response, DATA_BLOB *nt_response,
+ DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key) ;
+bool SMBNTLMv2encrypt(TALLOC_CTX *mem_ctx,
+ const char *user, const char *domain,
+ const char *password,
+ const DATA_BLOB *server_chal,
+ const DATA_BLOB *names_blob,
+ DATA_BLOB *lm_response, DATA_BLOB *nt_response,
+ DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key) ;
+NTSTATUS NTLMv2_RESPONSE_verify_netlogon_creds(const char *account_name,
+ const char *account_domain,
+ const DATA_BLOB response,
+ const struct netlogon_creds_CredentialState *creds,
+ const char *workgroup);
+
+/***********************************************************
+ encode a password buffer with a unicode password. The buffer
+ is filled with random data to make it harder to attack.
+************************************************************/
+bool encode_pw_buffer(uint8_t buffer[516], const char *password, int string_flags);
+
+/***********************************************************
+ decode a password buffer
+ *new_pw_len is the length in bytes of the possibly mulitbyte
+ returned password including termination.
+************************************************************/
+bool decode_pw_buffer(TALLOC_CTX *ctx,
+ uint8_t in_buffer[516],
+ char **pp_new_pwrd,
+ size_t *new_pw_len,
+ charset_t string_charset);
+
+/**
+ * @brief Encode an password buffer before we encrypt it.
+ *
+ * @param buffer[514] The buffer to encode into.
+ *
+ * @param password The password we want to encode into the buffer.
+ *
+ * @param string_flags String flags for encoding (e.g. STR_UNICODE).
+ *
+ * @return true on success, false otherwise.
+ */
+bool encode_pwd_buffer514_from_str(uint8_t buffer[514],
+ const char *password,
+ uint32_t string_flags);
+
+/**
+ * @brief Extract AES password blob from buffer.
+ *
+ * This extracts the password from the in_buffer as a data blob. It should
+ * then contain an UTF-16 encoded password.
+ *
+ * @param mem_ctx The memory context to allowcate the password on.
+ *
+ * @param in_buffer[514] The input buffer to extract the password from.
+ *
+ * @param new_password A pointer to the store the extracted password blob.
+ *
+ * @return true on success, false otherwise.
+ */
+bool extract_pwd_blob_from_buffer514(TALLOC_CTX *mem_ctx,
+ const uint8_t in_buffer[514],
+ DATA_BLOB *new_password);
+
+/**
+ * @brief Decode AES password buffer to password in the given charset.
+ *
+ * @param mem_ctx The memory context to allocate the decoded password on.
+ *
+ * @param in_buffer[514] The in buffer with the decrypted password data.
+ *
+ * @param string_charset The charset to decode to.
+ *
+ * @param decoded_password A pointer to store the blob for the decoded password.
+ * It ensures that the password is NULL terminated.
+ *
+ * @return true on success, false otherwise.
+ */
+bool decode_pwd_string_from_buffer514(TALLOC_CTX *mem_ctx,
+ const uint8_t in_buffer[514],
+ charset_t string_charset,
+ DATA_BLOB *decoded_password);
+
+/***********************************************************
+ Encode an arc4 password change buffer.
+************************************************************/
+NTSTATUS encode_rc4_passwd_buffer(const char *passwd,
+ const DATA_BLOB *session_key,
+ struct samr_CryptPasswordEx *out_crypt_pwd);
+
+/***********************************************************
+ Decode an arc4 encrypted password change buffer.
+************************************************************/
+NTSTATUS decode_rc4_passwd_buffer(const DATA_BLOB *psession_key,
+ struct samr_CryptPasswordEx *inout_crypt_pwd);
+
+/***********************************************************
+ encode a password buffer with an already unicode password. The
+ rest of the buffer is filled with random data to make it harder to attack.
+************************************************************/
+bool set_pw_in_buffer(uint8_t buffer[516], const DATA_BLOB *password);
+
+/***********************************************************
+ decode a password buffer
+ *new_pw_size is the length in bytes of the extracted unicode password
+************************************************************/
+bool extract_pw_from_buffer(TALLOC_CTX *mem_ctx,
+ uint8_t in_buffer[516], DATA_BLOB *new_pass);
+struct wkssvc_PasswordBuffer;
+WERROR encode_wkssvc_join_password_buffer(TALLOC_CTX *mem_ctx,
+ const char *pwd,
+ DATA_BLOB *session_key,
+ struct wkssvc_PasswordBuffer **pwd_buf);
+WERROR decode_wkssvc_join_password_buffer(TALLOC_CTX *mem_ctx,
+ struct wkssvc_PasswordBuffer *pwd_buf,
+ DATA_BLOB *session_key,
+ char **pwd);
+
+/* The following definitions come from libcli/auth/smbdes.c */
+
+int des_crypt56_gnutls(uint8_t out[8], const uint8_t in[8], const uint8_t key[7],
+ enum samba_gnutls_direction encrypt);
+int E_P16(const uint8_t *p14,uint8_t *p16);
+int E_P24(const uint8_t *p21, const uint8_t *c8, uint8_t *p24);
+int E_old_pw_hash( uint8_t *p14, const uint8_t *in, uint8_t *out);
+int des_crypt128(uint8_t out[8], const uint8_t in[8], const uint8_t key[16]);
+int des_crypt112(uint8_t out[8], const uint8_t in[8], const uint8_t key[14],
+ enum samba_gnutls_direction encrypt);
+int des_crypt112_16(uint8_t out[16], const uint8_t in[16], const uint8_t key[14],
+ enum samba_gnutls_direction encrypt);
+int sam_rid_crypt(unsigned int rid, const uint8_t *in, uint8_t *out,
+ enum samba_gnutls_direction encrypt);
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2)
+
+#endif
+
diff --git a/libcli/auth/schannel.h b/libcli/auth/schannel.h
new file mode 100644
index 0000000..c53d68e
--- /dev/null
+++ b/libcli/auth/schannel.h
@@ -0,0 +1,25 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ dcerpc schannel operations
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
+
+ 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 "libcli/auth/libcli_auth.h"
+#include "libcli/auth/schannel_state.h"
+#include "libcli/auth/schannel_proto.h"
diff --git a/libcli/auth/schannel_proto.h b/libcli/auth/schannel_proto.h
new file mode 100644
index 0000000..bce37c8
--- /dev/null
+++ b/libcli/auth/schannel_proto.h
@@ -0,0 +1,31 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ dcerpc schannel operations
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
+
+ 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/>.
+*/
+
+#ifndef _LIBCLI_AUTH_SCHANNEL_PROTO_H__
+#define _LIBCLI_AUTH_SCHANNEL_PROTO_H__
+
+struct schannel_state;
+
+struct db_context *open_schannel_session_store(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx);
+
+#endif
diff --git a/libcli/auth/schannel_state.h b/libcli/auth/schannel_state.h
new file mode 100644
index 0000000..a333098
--- /dev/null
+++ b/libcli/auth/schannel_state.h
@@ -0,0 +1,54 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ module to store/fetch session keys for the schannel server
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2008
+
+ 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/>.
+*/
+
+#ifndef _LIBCLI_AUTH_SCHANNEL_STATE_H__
+#define _LIBCLI_AUTH_SCHANNEL_STATE_H__
+
+NTSTATUS schannel_get_creds_state(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ const char *computer_name,
+ struct netlogon_creds_CredentialState **creds);
+
+NTSTATUS schannel_save_creds_state(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ struct netlogon_creds_CredentialState *creds);
+
+NTSTATUS schannel_check_creds_state(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ const char *computer_name,
+ struct netr_Authenticator *received_authenticator,
+ struct netr_Authenticator *return_authenticator,
+ struct netlogon_creds_CredentialState **creds_out);
+
+NTSTATUS schannel_get_challenge(struct loadparm_context *lp_ctx,
+ struct netr_Credential *client_challenge,
+ struct netr_Credential *server_challenge,
+ const char *computer_name);
+
+NTSTATUS schannel_save_challenge(struct loadparm_context *lp_ctx,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge,
+ const char *computer_name);
+
+NTSTATUS schannel_delete_challenge(struct loadparm_context *lp_ctx,
+ const char *computer_name);
+#endif
diff --git a/libcli/auth/schannel_state_tdb.c b/libcli/auth/schannel_state_tdb.c
new file mode 100644
index 0000000..2454a43
--- /dev/null
+++ b/libcli/auth/schannel_state_tdb.c
@@ -0,0 +1,646 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ module to store/fetch session keys for the schannel server
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2009
+ Copyright (C) Guenther Deschner 2009
+
+ 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 "system/filesys.h"
+#include "../lib/tdb/include/tdb.h"
+#include "../lib/util/util_tdb.h"
+#include "../lib/param/param.h"
+#include "../libcli/auth/schannel.h"
+#include "../librpc/gen_ndr/ndr_schannel.h"
+#include "lib/dbwrap/dbwrap.h"
+
+#define SECRETS_SCHANNEL_STATE "SECRETS/SCHANNEL"
+
+/******************************************************************************
+ Open or create the schannel session store tdb. Non-static so it can
+ be called from parent processes to correctly handle TDB_CLEAR_IF_FIRST
+*******************************************************************************/
+
+struct db_context *open_schannel_session_store(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx)
+{
+ struct db_context *db_sc = NULL;
+ char *fname = lpcfg_private_db_path(mem_ctx, lp_ctx, "schannel_store");
+ int hash_size, tdb_flags;
+
+ if (!fname) {
+ return NULL;
+ }
+
+ hash_size = lpcfg_tdb_hash_size(lp_ctx, fname);
+ tdb_flags = lpcfg_tdb_flags(lp_ctx, TDB_CLEAR_IF_FIRST|TDB_NOSYNC);
+
+ db_sc = dbwrap_local_open(
+ mem_ctx,
+ fname,
+ hash_size,
+ tdb_flags,
+ O_RDWR|O_CREAT,
+ 0600,
+ DBWRAP_LOCK_ORDER_NONE,
+ DBWRAP_FLAG_NONE);
+
+ if (!db_sc) {
+ DEBUG(0,("open_schannel_session_store: Failed to open %s - %s\n",
+ fname, strerror(errno)));
+ TALLOC_FREE(fname);
+ return NULL;
+ }
+
+ TALLOC_FREE(fname);
+
+ return db_sc;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+static
+NTSTATUS schannel_store_session_key_tdb(struct db_context *db_sc,
+ TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState *creds)
+{
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ TDB_DATA value;
+ char *keystr;
+ char *name_upper;
+ NTSTATUS status;
+
+ if (strlen(creds->computer_name) > 15) {
+ /*
+ * We may want to check for a completely
+ * valid netbios name.
+ */
+ return STATUS_BUFFER_OVERFLOW;
+ }
+
+ name_upper = strupper_talloc(mem_ctx, creds->computer_name);
+ if (!name_upper) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ keystr = talloc_asprintf(mem_ctx, "%s/%s",
+ SECRETS_SCHANNEL_STATE, name_upper);
+ TALLOC_FREE(name_upper);
+ if (!keystr) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ndr_err = ndr_push_struct_blob(&blob, mem_ctx, creds,
+ (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(keystr);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ value.dptr = blob.data;
+ value.dsize = blob.length;
+
+ status = dbwrap_store_bystring(db_sc, keystr, value, TDB_REPLACE);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("Unable to add %s to session key db - %s\n",
+ keystr, nt_errstr(status)));
+ talloc_free(keystr);
+ return status;
+ }
+
+ DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
+ keystr));
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
+ }
+
+ talloc_free(keystr);
+
+ return NT_STATUS_OK;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+static
+NTSTATUS schannel_fetch_session_key_tdb(struct db_context *db_sc,
+ TALLOC_CTX *mem_ctx,
+ const char *computer_name,
+ struct netlogon_creds_CredentialState **pcreds)
+{
+ NTSTATUS status;
+ TDB_DATA value;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netlogon_creds_CredentialState *creds = NULL;
+ char *keystr = NULL;
+ char *name_upper;
+
+ *pcreds = NULL;
+
+ name_upper = strupper_talloc(mem_ctx, computer_name);
+ if (!name_upper) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ keystr = talloc_asprintf(mem_ctx, "%s/%s",
+ SECRETS_SCHANNEL_STATE, name_upper);
+ TALLOC_FREE(name_upper);
+ if (!keystr) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = dbwrap_fetch_bystring(db_sc, keystr, keystr, &value);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
+ keystr ));
+ goto done;
+ }
+
+ creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
+ if (!creds) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ blob = data_blob_const(value.dptr, value.dsize);
+
+ ndr_err = ndr_pull_struct_blob(&blob, creds, creds,
+ (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ goto done;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
+ }
+
+ DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
+ keystr));
+
+ status = NT_STATUS_OK;
+
+ done:
+
+ talloc_free(keystr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(creds);
+ return status;
+ }
+
+ *pcreds = creds;
+
+ return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Wrapper around schannel_fetch_session_key_tdb()
+ Note we must be root here.
+*******************************************************************************/
+
+NTSTATUS schannel_get_creds_state(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ const char *computer_name,
+ struct netlogon_creds_CredentialState **_creds)
+{
+ TALLOC_CTX *tmpctx;
+ struct db_context *db_sc;
+ struct netlogon_creds_CredentialState *creds;
+ NTSTATUS status;
+
+ tmpctx = talloc_named(mem_ctx, 0, "schannel_get_creds_state");
+ if (!tmpctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ db_sc = open_schannel_session_store(tmpctx, lp_ctx);
+ if (!db_sc) {
+ TALLOC_FREE(tmpctx);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ status = schannel_fetch_session_key_tdb(db_sc, tmpctx,
+ computer_name, &creds);
+ if (NT_STATUS_IS_OK(status)) {
+ *_creds = talloc_steal(mem_ctx, creds);
+ if (!*_creds) {
+ status = NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ talloc_free(tmpctx);
+ return status;
+}
+
+/******************************************************************************
+ Wrapper around schannel_store_session_key_tdb()
+ Note we must be root here.
+*******************************************************************************/
+
+NTSTATUS schannel_save_creds_state(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ struct netlogon_creds_CredentialState *creds)
+{
+ TALLOC_CTX *tmpctx;
+ struct db_context *db_sc;
+ NTSTATUS status;
+
+ tmpctx = talloc_named(mem_ctx, 0, "schannel_save_creds_state");
+ if (!tmpctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ db_sc = open_schannel_session_store(tmpctx, lp_ctx);
+ if (!db_sc) {
+ status = NT_STATUS_ACCESS_DENIED;
+ goto fail;
+ }
+
+ status = schannel_store_session_key_tdb(db_sc, tmpctx, creds);
+
+fail:
+ talloc_free(tmpctx);
+ return status;
+}
+
+
+/*
+ * Create a very lossy hash of the computer name.
+ *
+ * The idea here is to compress the computer name into small space so
+ * that malicious clients cannot fill the database with junk, as only a
+ * maximum of 16k of entries are possible.
+ *
+ * Collisions are certainly possible, and the design behaves in the
+ * same way as when the hostname is reused, but clients that use the
+ * same connection do not go via the cache, and the cache only needs
+ * to function between the ReqChallenge and ServerAuthenticate
+ * packets.
+ */
+static void hash_computer_name(const char *computer_name,
+ char keystr[16])
+{
+ unsigned int hash;
+ TDB_DATA computer_tdb_data = {
+ .dptr = (uint8_t *)discard_const_p(char, computer_name),
+ .dsize = strlen(computer_name)
+ };
+ hash = tdb_jenkins_hash(&computer_tdb_data);
+
+ /* we are using 14 bits of the digest to index our connections, so
+ that we use at most 16,384 buckets.*/
+ snprintf(keystr, 15, "CHALLENGE/%x%x", hash & 0xFF,
+ (hash & 0xFF00 >> 8) & 0x3f);
+ return;
+}
+
+
+static
+NTSTATUS schannel_store_challenge_tdb(struct db_context *db_sc,
+ TALLOC_CTX *mem_ctx,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge,
+ const char *computer_name)
+{
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ TDB_DATA value;
+ char *name_upper = NULL;
+ NTSTATUS status;
+ char keystr[16] = { 0, };
+ struct netlogon_cache_entry cache_entry;
+
+ if (strlen(computer_name) > 255) {
+ /*
+ * We don't make this a limit at 15 chars as Samba has
+ * a test showing this can be longer :-(
+ */
+ return STATUS_BUFFER_OVERFLOW;
+ }
+
+ name_upper = strupper_talloc(mem_ctx, computer_name);
+ if (name_upper == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ hash_computer_name(name_upper, keystr);
+
+ cache_entry.computer_name = name_upper;
+ cache_entry.client_challenge = *client_challenge;
+ cache_entry.server_challenge = *server_challenge;
+
+ ndr_err = ndr_push_struct_blob(&blob, mem_ctx, &cache_entry,
+ (ndr_push_flags_fn_t)ndr_push_netlogon_cache_entry);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ value.dptr = blob.data;
+ value.dsize = blob.length;
+
+ status = dbwrap_store_bystring(db_sc, keystr, value, TDB_REPLACE);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("%s: failed to stored challenge info for '%s' "
+ "with key %s - %s\n",
+ __func__, cache_entry.computer_name, keystr,
+ nt_errstr(status)));
+ return status;
+ }
+
+ DEBUG(3,("%s: stored challenge info for '%s' with key %s\n",
+ __func__, cache_entry.computer_name, keystr));
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(netlogon_cache_entry, &cache_entry);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/********************************************************************
+ Fetch a single challenge from the TDB.
+ ********************************************************************/
+
+static
+NTSTATUS schannel_fetch_challenge_tdb(struct db_context *db_sc,
+ TALLOC_CTX *mem_ctx,
+ struct netr_Credential *client_challenge,
+ struct netr_Credential *server_challenge,
+ const char *computer_name)
+{
+ NTSTATUS status;
+ TDB_DATA value;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ char keystr[16] = { 0, };
+ struct netlogon_cache_entry cache_entry;
+ char *name_upper = NULL;
+
+ name_upper = strupper_talloc(mem_ctx, computer_name);
+ if (name_upper == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ hash_computer_name(name_upper, keystr);
+
+ status = dbwrap_fetch_bystring(db_sc, mem_ctx, keystr, &value);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3,("%s: Failed to find entry for %s with key %s - %s\n",
+ __func__, name_upper, keystr, nt_errstr(status)));
+ goto done;
+ }
+
+ blob = data_blob_const(value.dptr, value.dsize);
+
+ ndr_err = ndr_pull_struct_blob_all(&blob, mem_ctx, &cache_entry,
+ (ndr_pull_flags_fn_t)ndr_pull_netlogon_cache_entry);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(3,("%s: Failed to parse entry for %s with key %s - %s\n",
+ __func__, name_upper, keystr, nt_errstr(status)));
+ goto done;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(netlogon_cache_entry, &cache_entry);
+ }
+
+ if (strcmp(cache_entry.computer_name, name_upper) != 0) {
+ status = NT_STATUS_NOT_FOUND;
+
+ DEBUG(1, ("%s: HASH COLLISION with key %s ! "
+ "Wanted to fetch record for %s but got %s.\n",
+ __func__, keystr, name_upper,
+ cache_entry.computer_name));
+ } else {
+
+ DEBUG(3,("%s: restored key %s for %s\n",
+ __func__, keystr, cache_entry.computer_name));
+
+ *client_challenge = cache_entry.client_challenge;
+ *server_challenge = cache_entry.server_challenge;
+ }
+ done:
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Wrapper around schannel_fetch_challenge_tdb()
+ Note we must be root here.
+
+*******************************************************************************/
+
+NTSTATUS schannel_get_challenge(struct loadparm_context *lp_ctx,
+ struct netr_Credential *client_challenge,
+ struct netr_Credential *server_challenge,
+ const char *computer_name)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct db_context *db_sc;
+ NTSTATUS status;
+
+ db_sc = open_schannel_session_store(frame, lp_ctx);
+ if (!db_sc) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ status = schannel_fetch_challenge_tdb(db_sc, frame,
+ client_challenge,
+ server_challenge,
+ computer_name);
+ TALLOC_FREE(frame);
+ return status;
+}
+
+/******************************************************************************
+ Wrapper around dbwrap_delete_bystring()
+ Note we must be root here.
+
+ This allows the challenge to be removed from the TDB, which should be
+ as soon as the TDB or in-memory copy it is used, to avoid reuse.
+*******************************************************************************/
+
+NTSTATUS schannel_delete_challenge(struct loadparm_context *lp_ctx,
+ const char *computer_name)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct db_context *db_sc;
+ char *name_upper;
+ char keystr[16] = { 0, };
+
+ db_sc = open_schannel_session_store(frame, lp_ctx);
+ if (!db_sc) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ name_upper = strupper_talloc(frame, computer_name);
+ if (!name_upper) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ hash_computer_name(name_upper, keystr);
+
+ /* Now delete it, we do not want to permit fetch of this twice */
+ dbwrap_delete_bystring(db_sc, keystr);
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Wrapper around schannel_store_session_key_tdb()
+ Note we must be root here.
+*******************************************************************************/
+
+NTSTATUS schannel_save_challenge(struct loadparm_context *lp_ctx,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge,
+ const char *computer_name)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct db_context *db_sc;
+ NTSTATUS status;
+
+ db_sc = open_schannel_session_store(frame, lp_ctx);
+ if (!db_sc) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ status = schannel_store_challenge_tdb(db_sc, frame,
+ client_challenge,
+ server_challenge,
+ computer_name);
+
+ TALLOC_FREE(frame);
+ return status;
+}
+
+/********************************************************************
+ Validate an incoming authenticator against the credentials for the
+ remote machine stored in the schannel database.
+
+ The credentials are (re)read and from the schannel database, and
+ written back after the calculations are performed.
+
+ If the creds_out parameter is not NULL returns the credentials.
+ ********************************************************************/
+
+NTSTATUS schannel_check_creds_state(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ const char *computer_name,
+ struct netr_Authenticator *received_authenticator,
+ struct netr_Authenticator *return_authenticator,
+ struct netlogon_creds_CredentialState **creds_out)
+{
+ TALLOC_CTX *tmpctx;
+ struct db_context *db_sc;
+ struct netlogon_creds_CredentialState *creds;
+ NTSTATUS status;
+ char *name_upper = NULL;
+ char *keystr = NULL;
+ struct db_record *record;
+ TDB_DATA key;
+
+ if (creds_out != NULL) {
+ *creds_out = NULL;
+ }
+
+ tmpctx = talloc_named(mem_ctx, 0, "schannel_check_creds_state");
+ if (!tmpctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ name_upper = strupper_talloc(tmpctx, computer_name);
+ if (!name_upper) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ keystr = talloc_asprintf(tmpctx, "%s/%s",
+ SECRETS_SCHANNEL_STATE, name_upper);
+ if (!keystr) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ key = string_term_tdb_data(keystr);
+
+ db_sc = open_schannel_session_store(tmpctx, lp_ctx);
+ if (!db_sc) {
+ status = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+
+ record = dbwrap_fetch_locked(db_sc, tmpctx, key);
+ if (!record) {
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto done;
+ }
+
+ /* Because this is a shared structure (even across
+ * disconnects) we must update the database every time we
+ * update the structure */
+
+ status = schannel_fetch_session_key_tdb(db_sc, tmpctx,
+ computer_name, &creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = netlogon_creds_server_step_check(creds,
+ received_authenticator,
+ return_authenticator);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = schannel_store_session_key_tdb(db_sc, tmpctx, creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ if (creds_out) {
+ *creds_out = talloc_steal(mem_ctx, creds);
+ if (!*creds_out) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ }
+
+ status = NT_STATUS_OK;
+
+done:
+ talloc_free(tmpctx);
+ return status;
+}
+
diff --git a/libcli/auth/session.c b/libcli/auth/session.c
new file mode 100644
index 0000000..515b7ae
--- /dev/null
+++ b/libcli/auth/session.c
@@ -0,0 +1,247 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ code to encrypt/decrypt data using the user session key
+
+ Copyright (C) Andrew Tridgell 2004
+
+ 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 "libcli/auth/libcli_auth.h"
+
+/*
+ encrypt or decrypt a blob of data using the user session key
+ as used in lsa_SetSecret
+
+ before calling, the out blob must be initialised to be the same size
+ as the in blob
+*/
+int sess_crypt_blob(DATA_BLOB *out, const DATA_BLOB *in, const DATA_BLOB *session_key,
+ enum samba_gnutls_direction encrypt)
+{
+ int i, k, rc;
+
+ if (in->length % 8 != 0) {
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ if (session_key->length < 7) {
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ for (i=0,k=0;
+ i<in->length;
+ i += 8, k += 7) {
+ uint8_t bin[8], bout[8], key[7];
+
+ memcpy(bin, &in->data[i], 8);
+
+ if (k + 7 > session_key->length) {
+ k = (session_key->length - k);
+ }
+ memcpy(key, &session_key->data[k], 7);
+
+ rc = des_crypt56_gnutls(bout, bin, key, encrypt);
+ if (rc != 0) {
+ return rc;
+ }
+
+ memcpy(&out->data[i], bout, 8);
+ }
+ return 0;
+}
+
+
+/*
+ a convenient wrapper around sess_crypt_blob() for strings, using the LSA convention
+
+ note that we round the length to a multiple of 8. This seems to be needed for
+ compatibility with windows
+
+ caller should free using data_blob_free()
+*/
+DATA_BLOB sess_encrypt_string(const char *str, const DATA_BLOB *session_key)
+{
+ DATA_BLOB ret, src;
+ int slen = strlen(str);
+ int dlen = (slen+7) & ~7;
+ int rc;
+
+ src = data_blob(NULL, 8+dlen);
+ if (!src.data) {
+ return data_blob(NULL, 0);
+ }
+
+ ret = data_blob(NULL, 8+dlen);
+ if (!ret.data) {
+ data_blob_free(&src);
+ return data_blob(NULL, 0);
+ }
+
+ SIVAL(src.data, 0, slen);
+ SIVAL(src.data, 4, 1);
+ memset(src.data+8, 0, dlen);
+ memcpy(src.data+8, str, slen);
+
+ rc = sess_crypt_blob(&ret, &src, session_key, SAMBA_GNUTLS_ENCRYPT);
+
+ data_blob_free(&src);
+ if (rc != 0) {
+ data_blob_free(&ret);
+ return data_blob(NULL, 0);
+ }
+
+ return ret;
+}
+
+/*
+ a convenient wrapper around sess_crypt_blob() for strings, using the LSA convention
+
+ caller should free the returned string
+*/
+char *sess_decrypt_string(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob, const DATA_BLOB *session_key)
+{
+ DATA_BLOB out;
+ int rc, slen;
+ char *ret;
+
+ if (blob->length < 8) {
+ return NULL;
+ }
+
+ out = data_blob_talloc(mem_ctx, NULL, blob->length);
+ if (!out.data) {
+ return NULL;
+ }
+
+ rc = sess_crypt_blob(&out, blob, session_key, SAMBA_GNUTLS_DECRYPT);
+ if (rc != 0) {
+ data_blob_free(&out);
+ return NULL;
+ }
+
+ if (IVAL(out.data, 4) != 1) {
+ DEBUG(0,("Unexpected revision number %d in session encrypted string\n",
+ IVAL(out.data, 4)));
+ data_blob_free(&out);
+ return NULL;
+ }
+
+ slen = IVAL(out.data, 0);
+ if (slen > blob->length - 8) {
+ DEBUG(0,("Invalid crypt length %d\n", slen));
+ data_blob_free(&out);
+ return NULL;
+ }
+
+ ret = talloc_strndup(mem_ctx, (const char *)(out.data+8), slen);
+
+ data_blob_free(&out);
+
+ DEBUG(0,("decrypted string '%s' of length %d\n", ret, slen));
+
+ return ret;
+}
+
+/*
+ a convenient wrapper around sess_crypt_blob() for DATA_BLOBs, using the LSA convention
+
+ note that we round the length to a multiple of 8. This seems to be needed for
+ compatibility with windows
+
+ caller should free using data_blob_free()
+*/
+DATA_BLOB sess_encrypt_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob_in, const DATA_BLOB *session_key)
+{
+ DATA_BLOB ret, src;
+ int dlen = (blob_in->length+7) & ~7;
+ int rc;
+
+ src = data_blob_talloc(mem_ctx, NULL, 8+dlen);
+ if (!src.data) {
+ return data_blob(NULL, 0);
+ }
+
+ ret = data_blob_talloc(mem_ctx, NULL, 8+dlen);
+ if (!ret.data) {
+ data_blob_free(&src);
+ return data_blob(NULL, 0);
+ }
+
+ SIVAL(src.data, 0, blob_in->length);
+ SIVAL(src.data, 4, 1);
+ memset(src.data+8, 0, dlen);
+ memcpy(src.data+8, blob_in->data, blob_in->length);
+
+ rc = sess_crypt_blob(&ret, &src, session_key, SAMBA_GNUTLS_ENCRYPT);
+
+ data_blob_free(&src);
+ if (rc != 0) {
+ data_blob_free(&ret);
+ return data_blob(NULL, 0);
+ }
+
+ return ret;
+}
+
+/*
+ Decrypt a DATA_BLOB using the LSA convention
+*/
+NTSTATUS sess_decrypt_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, const DATA_BLOB *session_key,
+ DATA_BLOB *ret)
+{
+ DATA_BLOB out;
+ int rc, slen;
+
+ if (blob->length < 8) {
+ DEBUG(0, ("Unexpected length %d in session encrypted secret (BLOB)\n",
+ (int)blob->length));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ out = data_blob_talloc(mem_ctx, NULL, blob->length);
+ if (!out.data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ rc = sess_crypt_blob(&out, blob, session_key, SAMBA_GNUTLS_DECRYPT);
+ if (rc != 0) {
+ data_blob_free(&out);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+
+ if (IVAL(out.data, 4) != 1) {
+ DEBUG(2,("Unexpected revision number %d in session encrypted secret (BLOB)\n",
+ IVAL(out.data, 4)));
+ return NT_STATUS_UNKNOWN_REVISION;
+ }
+
+ slen = IVAL(out.data, 0);
+ if (slen > blob->length - 8) {
+ DEBUG(0,("Invalid crypt length %d in session encrypted secret (BLOB)\n", slen));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ *ret = data_blob_talloc(mem_ctx, out.data+8, slen);
+ if (slen && !ret->data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ data_blob_free(&out);
+
+ return NT_STATUS_OK;
+}
diff --git a/libcli/auth/smbdes.c b/libcli/auth/smbdes.c
new file mode 100644
index 0000000..c6c4441
--- /dev/null
+++ b/libcli/auth/smbdes.c
@@ -0,0 +1,213 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ a partial implementation of DES designed for use in the
+ SMB authentication protocol
+
+ Copyright (C) Andrew Tridgell 1998
+
+ 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 "libcli/auth/libcli_auth.h"
+
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+static void str_to_key(const uint8_t *str,uint8_t *key)
+{
+ int i;
+
+ key[0] = str[0]>>1;
+ key[1] = ((str[0]&0x01)<<6) | (str[1]>>2);
+ key[2] = ((str[1]&0x03)<<5) | (str[2]>>3);
+ key[3] = ((str[2]&0x07)<<4) | (str[3]>>4);
+ key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5);
+ key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6);
+ key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7);
+ key[7] = str[6]&0x7F;
+ for (i=0;i<8;i++) {
+ key[i] = (key[i]<<1);
+ }
+}
+
+int des_crypt56_gnutls(uint8_t out[8], const uint8_t in[8],
+ const uint8_t key_in[7],
+ enum samba_gnutls_direction encrypt)
+{
+ /*
+ * A single block DES-CBC op, with an all-zero IV is the same as DES
+ * because the IV is combined with the data using XOR.
+ * This allows us to use GNUTLS_CIPHER_DES_CBC from GnuTLS and not
+ * implement single-DES in Samba.
+ *
+ * In turn this is used to build DES-ECB, which is used
+ * for example in the NTLM challenge/response calculation.
+ */
+ static const uint8_t iv8[8];
+ gnutls_datum_t iv = { discard_const(iv8), 8 };
+ gnutls_datum_t key;
+ gnutls_cipher_hd_t ctx;
+ uint8_t key2[8];
+ uint8_t outb[8];
+ int ret;
+
+ memset(out, 0, 8);
+
+ str_to_key(key_in, key2);
+
+ key.data = key2;
+ key.size = 8;
+
+ ret = gnutls_global_init();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = gnutls_cipher_init(&ctx, GNUTLS_CIPHER_DES_CBC, &key, &iv);
+ if (ret != 0) {
+ return ret;
+ }
+
+ memcpy(outb, in, 8);
+ if (encrypt == SAMBA_GNUTLS_ENCRYPT) {
+ ret = gnutls_cipher_encrypt(ctx, outb, 8);
+ } else {
+ ret = gnutls_cipher_decrypt(ctx, outb, 8);
+ }
+
+ if (ret == 0) {
+ memcpy(out, outb, 8);
+ }
+
+ gnutls_cipher_deinit(ctx);
+
+ return ret;
+}
+
+int E_P16(const uint8_t *p14,uint8_t *p16)
+{
+ const uint8_t sp8[8] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
+ int ret;
+
+ ret = des_crypt56_gnutls(p16, sp8, p14, SAMBA_GNUTLS_ENCRYPT);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return des_crypt56_gnutls(p16+8, sp8, p14+7, SAMBA_GNUTLS_ENCRYPT);
+}
+
+int E_P24(const uint8_t *p21, const uint8_t *c8, uint8_t *p24)
+{
+ int ret;
+
+ ret = des_crypt56_gnutls(p24, c8, p21, SAMBA_GNUTLS_ENCRYPT);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = des_crypt56_gnutls(p24+8, c8, p21+7, SAMBA_GNUTLS_ENCRYPT);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return des_crypt56_gnutls(p24+16, c8, p21+14, SAMBA_GNUTLS_ENCRYPT);
+}
+
+int E_old_pw_hash( uint8_t *p14, const uint8_t *in, uint8_t *out)
+{
+ int ret;
+
+ ret = des_crypt56_gnutls(out, in, p14, SAMBA_GNUTLS_ENCRYPT);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return des_crypt56_gnutls(out+8, in+8, p14+7, SAMBA_GNUTLS_ENCRYPT);
+}
+
+/* des encryption with a 128 bit key */
+int des_crypt128(uint8_t out[8], const uint8_t in[8], const uint8_t key[16])
+{
+ uint8_t buf[8];
+ int ret;
+
+ ret = des_crypt56_gnutls(buf, in, key, SAMBA_GNUTLS_ENCRYPT);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return des_crypt56_gnutls(out, buf, key+9, SAMBA_GNUTLS_ENCRYPT);
+}
+
+/* des encryption with a 112 bit (14 byte) key */
+int des_crypt112(uint8_t out[8], const uint8_t in[8], const uint8_t key[14],
+ enum samba_gnutls_direction encrypt)
+{
+ uint8_t buf[8];
+ int ret;
+
+ if (encrypt == SAMBA_GNUTLS_ENCRYPT) {
+ ret = des_crypt56_gnutls(buf, in, key, SAMBA_GNUTLS_ENCRYPT);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return des_crypt56_gnutls(out, buf, key+7, SAMBA_GNUTLS_ENCRYPT);
+ }
+
+ ret = des_crypt56_gnutls(buf, in, key+7, SAMBA_GNUTLS_DECRYPT);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return des_crypt56_gnutls(out, buf, key, SAMBA_GNUTLS_DECRYPT);
+}
+
+/* des encryption of a 16 byte lump of data with a 112 bit key */
+int des_crypt112_16(uint8_t out[16], const uint8_t in[16], const uint8_t key[14],
+ enum samba_gnutls_direction encrypt)
+{
+ int ret;
+
+ ret = des_crypt56_gnutls(out, in, key, encrypt);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return des_crypt56_gnutls(out + 8, in + 8, key+7, encrypt);
+}
+
+/* Decode a sam password hash into a password. The password hash is the
+ same method used to store passwords in the NT registry. The DES key
+ used is based on the RID of the user. */
+int sam_rid_crypt(unsigned int rid, const uint8_t *in, uint8_t *out,
+ enum samba_gnutls_direction encrypt)
+{
+ uint8_t s[14];
+ int ret;
+
+ s[0] = s[4] = s[8] = s[12] = (uint8_t)(rid & 0xFF);
+ s[1] = s[5] = s[9] = s[13] = (uint8_t)((rid >> 8) & 0xFF);
+ s[2] = s[6] = s[10] = (uint8_t)((rid >> 16) & 0xFF);
+ s[3] = s[7] = s[11] = (uint8_t)((rid >> 24) & 0xFF);
+
+ ret = des_crypt56_gnutls(out, in, s, encrypt);
+ if (ret != 0) {
+ return ret;
+ }
+ return des_crypt56_gnutls(out+8, in+8, s+7, encrypt);
+}
diff --git a/libcli/auth/smbencrypt.c b/libcli/auth/smbencrypt.c
new file mode 100644
index 0000000..725bdcb
--- /dev/null
+++ b/libcli/auth/smbencrypt.c
@@ -0,0 +1,1325 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1998
+ Modified by Jeremy Allison 1995.
+ Copyright (C) Jeremy Allison 1995-2000.
+ Copyright (C) Luke Kennethc Casson Leighton 1996-2000.
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
+
+ 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 "system/time.h"
+#include "../libcli/auth/msrpc_parse.h"
+#include "../lib/crypto/crypto.h"
+#include "../libcli/auth/libcli_auth.h"
+#include "../librpc/gen_ndr/ndr_ntlmssp.h"
+#include "lib/util/bytearray.h"
+
+#include "lib/crypto/gnutls_helpers.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+int SMBencrypt_hash(const uint8_t lm_hash[16], const uint8_t *c8, uint8_t p24[24])
+{
+ uint8_t p21[21];
+ int rc;
+
+ memset(p21,'\0',21);
+ memcpy(p21, lm_hash, 16);
+
+ rc = SMBOWFencrypt(p21, c8, p24);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("SMBencrypt_hash: lm#, challenge, response\n"));
+ dump_data(100, p21, 16);
+ dump_data(100, c8, 8);
+ dump_data(100, p24, 24);
+#endif
+
+ return rc;
+}
+
+/*
+ This implements the X/Open SMB password encryption
+ It takes a password ('unix' string), a 8 byte "crypt key"
+ and puts 24 bytes of encrypted password into p24
+
+ Returns False if password must have been truncated to create LM hash
+*/
+
+bool SMBencrypt(const char *passwd, const uint8_t *c8, uint8_t p24[24])
+{
+ bool ret;
+ uint8_t lm_hash[16];
+ int rc;
+
+ ret = E_deshash(passwd, lm_hash);
+ rc = SMBencrypt_hash(lm_hash, c8, p24);
+ if (rc != 0) {
+ ret = false;
+ }
+ return ret;
+}
+
+/**
+ * Creates the MD4 Hash of the users password in NT UNICODE.
+ * @param passwd password in 'unix' charset.
+ * @param p16 return password hashed with md4, caller allocated 16 byte buffer
+ */
+
+bool E_md4hash(const char *passwd, uint8_t p16[16])
+{
+ size_t len;
+ smb_ucs2_t *wpwd;
+ bool ret;
+
+ ret = push_ucs2_talloc(NULL, &wpwd, passwd, &len);
+ if (!ret || len < 2) {
+ /* We don't want to return fixed data, as most callers
+ * don't check */
+ mdfour(p16, (const uint8_t *)passwd, strlen(passwd));
+ return false;
+ }
+
+ len -= 2;
+ mdfour(p16, (const uint8_t *)wpwd, len);
+
+ talloc_free(wpwd);
+ return true;
+}
+
+/**
+ * Creates the DES forward-only Hash of the users password in DOS ASCII charset
+ * @param passwd password in 'unix' charset.
+ * @param p16 return password hashed with DES, caller allocated 16 byte buffer
+ * @return false if password was > 14 characters, and therefore may be incorrect, otherwise true
+ * @note p16 is filled in regardless
+ */
+
+bool E_deshash(const char *passwd, uint8_t p16[16])
+{
+ bool ret;
+ int rc;
+ uint8_t dospwd[14];
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ size_t converted_size;
+
+ char *tmpbuf;
+
+ ZERO_STRUCT(dospwd);
+
+ tmpbuf = strupper_talloc(frame, passwd);
+ if (tmpbuf == NULL) {
+ /* Too many callers don't check this result, we need to fill in the buffer with something */
+ strlcpy((char *)dospwd, passwd ? passwd : "", sizeof(dospwd));
+ E_P16(dospwd, p16);
+ talloc_free(frame);
+ return false;
+ }
+
+ ZERO_STRUCT(dospwd);
+
+ ret = convert_string_error(CH_UNIX, CH_DOS, tmpbuf, strlen(tmpbuf), dospwd, sizeof(dospwd), &converted_size);
+ talloc_free(frame);
+
+ /* Only the first 14 chars are considered, password need not
+ * be null terminated. We do this in the error and success
+ * case to avoid returning a fixed 'password' buffer, but
+ * callers should not use it when E_deshash returns false */
+
+ rc = E_P16((const uint8_t *)dospwd, p16);
+ if (rc != 0) {
+ ret = false;
+ }
+
+ ZERO_STRUCT(dospwd);
+
+ return ret;
+}
+
+/**
+ * Creates the MD4 and DES (LM) Hash of the users password.
+ * MD4 is of the NT Unicode, DES is of the DOS UPPERCASE password.
+ * @param passwd password in 'unix' charset.
+ * @param nt_p16 return password hashed with md4, caller allocated 16 byte buffer
+ * @param p16 return password hashed with des, caller allocated 16 byte buffer
+ */
+
+/* Does both the NT and LM owfs of a user's password */
+void nt_lm_owf_gen(const char *pwd, uint8_t nt_p16[16], uint8_t p16[16])
+{
+ /* Calculate the MD4 hash (NT compatible) of the password */
+ memset(nt_p16, '\0', 16);
+ E_md4hash(pwd, nt_p16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("nt_lm_owf_gen: pwd, nt#\n"));
+ dump_data(120, (const uint8_t *)pwd, strlen(pwd));
+ dump_data(100, nt_p16, 16);
+#endif
+
+ E_deshash(pwd, (uint8_t *)p16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("nt_lm_owf_gen: pwd, lm#\n"));
+ dump_data(120, (const uint8_t *)pwd, strlen(pwd));
+ dump_data(100, p16, 16);
+#endif
+}
+
+/* Does both the NTLMv2 owfs of a user's password */
+bool ntv2_owf_gen(const uint8_t owf[16],
+ const char *user_in, const char *domain_in,
+ uint8_t kr_buf[16])
+{
+ smb_ucs2_t *user;
+ smb_ucs2_t *domain;
+ size_t user_byte_len;
+ size_t domain_byte_len;
+ gnutls_hmac_hd_t hmac_hnd = NULL;
+ int rc;
+ bool ok = false;
+ TALLOC_CTX *mem_ctx = talloc_init("ntv2_owf_gen for %s\\%s", domain_in, user_in);
+
+ if (!mem_ctx) {
+ return false;
+ }
+
+ if (!user_in) {
+ user_in = "";
+ }
+
+ if (!domain_in) {
+ domain_in = "";
+ }
+
+ user_in = strupper_talloc(mem_ctx, user_in);
+ if (user_in == NULL) {
+ talloc_free(mem_ctx);
+ return false;
+ }
+
+ ok = push_ucs2_talloc(mem_ctx, &user, user_in, &user_byte_len );
+ if (!ok) {
+ DEBUG(0, ("push_uss2_talloc() for user failed)\n"));
+ talloc_free(mem_ctx);
+ return false;
+ }
+
+ ok = push_ucs2_talloc(mem_ctx, &domain, domain_in, &domain_byte_len);
+ if (!ok) {
+ DEBUG(0, ("push_ucs2_talloc() for domain failed\n"));
+ talloc_free(mem_ctx);
+ return false;
+ }
+
+ SMB_ASSERT(user_byte_len >= 2);
+ SMB_ASSERT(domain_byte_len >= 2);
+
+ /* We don't want null termination */
+ user_byte_len = user_byte_len - 2;
+ domain_byte_len = domain_byte_len - 2;
+
+ rc = gnutls_hmac_init(&hmac_hnd,
+ GNUTLS_MAC_MD5,
+ owf,
+ 16);
+ if (rc < 0) {
+ ok = false;
+ goto out;
+ }
+
+ rc = gnutls_hmac(hmac_hnd, user, user_byte_len);
+ if (rc < 0) {
+ gnutls_hmac_deinit(hmac_hnd, NULL);
+ ok = false;
+ goto out;
+ }
+ rc = gnutls_hmac(hmac_hnd, domain, domain_byte_len);
+ if (rc < 0) {
+ gnutls_hmac_deinit(hmac_hnd, NULL);
+ ok = false;
+ goto out;
+ }
+
+ gnutls_hmac_deinit(hmac_hnd, kr_buf);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("ntv2_owf_gen: user, domain, owfkey, kr\n"));
+ dump_data(100, (uint8_t *)user, user_byte_len);
+ dump_data(100, (uint8_t *)domain, domain_byte_len);
+ dump_data(100, owf, 16);
+ dump_data(100, kr_buf, 16);
+#endif
+
+ ok = true;
+out:
+ talloc_free(mem_ctx);
+ return ok;
+}
+
+/* Does the des encryption from the NT or LM MD4 hash. */
+int SMBOWFencrypt(const uint8_t passwd[16], const uint8_t *c8, uint8_t p24[24])
+{
+ uint8_t p21[21];
+
+ ZERO_STRUCT(p21);
+
+ memcpy(p21, passwd, 16);
+ return E_P24(p21, c8, p24);
+}
+
+/* Does the des encryption. */
+
+int SMBNTencrypt_hash(const uint8_t nt_hash[16], const uint8_t *c8, uint8_t *p24)
+{
+ uint8_t p21[21];
+ int rc;
+
+ memset(p21,'\0',21);
+ memcpy(p21, nt_hash, 16);
+ rc = SMBOWFencrypt(p21, c8, p24);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("SMBNTencrypt: nt#, challenge, response\n"));
+ dump_data(100, p21, 16);
+ dump_data(100, c8, 8);
+ dump_data(100, p24, 24);
+#endif
+
+ return rc;
+}
+
+/* Does the NT MD4 hash then des encryption. Plaintext version of the above. */
+
+int SMBNTencrypt(const char *passwd, const uint8_t *c8, uint8_t *p24)
+{
+ uint8_t nt_hash[16];
+ E_md4hash(passwd, nt_hash);
+ return SMBNTencrypt_hash(nt_hash, c8, p24);
+}
+
+
+/* Does the md5 encryption from the Key Response for NTLMv2. */
+NTSTATUS SMBOWFencrypt_ntv2(const uint8_t kr[16],
+ const DATA_BLOB *srv_chal,
+ const DATA_BLOB *smbcli_chal,
+ uint8_t resp_buf[16])
+{
+ gnutls_hmac_hd_t hmac_hnd = NULL;
+ NTSTATUS status;
+ int rc;
+
+ rc = gnutls_hmac_init(&hmac_hnd,
+ GNUTLS_MAC_MD5,
+ kr,
+ 16);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+
+ rc = gnutls_hmac(hmac_hnd, srv_chal->data, srv_chal->length);
+ if (rc < 0) {
+ status = gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ goto out;
+ }
+ rc = gnutls_hmac(hmac_hnd, smbcli_chal->data, smbcli_chal->length);
+ if (rc < 0) {
+ status = gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ goto out;
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBOWFencrypt_ntv2: srv_chal, smbcli_chal, resp_buf\n"));
+ dump_data(100, srv_chal->data, srv_chal->length);
+ dump_data(100, smbcli_chal->data, smbcli_chal->length);
+ dump_data(100, resp_buf, 16);
+#endif
+
+ status = NT_STATUS_OK;
+out:
+ gnutls_hmac_deinit(hmac_hnd, resp_buf);
+ return status;
+}
+
+NTSTATUS SMBsesskeygen_ntv2(const uint8_t kr[16],
+ const uint8_t *nt_resp,
+ uint8_t sess_key[16])
+{
+ int rc;
+
+ /* a very nice, 128 bit, variable session key */
+ rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
+ kr,
+ 16,
+ nt_resp,
+ 16,
+ sess_key);
+ if (rc != 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBsesskeygen_ntv2:\n"));
+ dump_data(100, sess_key, 16);
+#endif
+
+ return NT_STATUS_OK;
+}
+
+void SMBsesskeygen_ntv1(const uint8_t kr[16], uint8_t sess_key[16])
+{
+ /* yes, this session key does not change - yes, this
+ is a problem - but it is 128 bits */
+
+ mdfour((uint8_t *)sess_key, kr, 16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBsesskeygen_ntv1:\n"));
+ dump_data(100, sess_key, 16);
+#endif
+}
+
+NTSTATUS SMBsesskeygen_lm_sess_key(const uint8_t lm_hash[16],
+ const uint8_t lm_resp[24], /* only uses 8 */
+ uint8_t sess_key[16])
+{
+ /* Calculate the LM session key (effective length 40 bits,
+ but changes with each session) */
+ uint8_t p24[24];
+ uint8_t partial_lm_hash[14];
+ int rc;
+
+ memcpy(partial_lm_hash, lm_hash, 8);
+ memset(partial_lm_hash + 8, 0xbd, 6);
+
+ rc = des_crypt56_gnutls(p24, lm_resp, partial_lm_hash, SAMBA_GNUTLS_ENCRYPT);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ rc = des_crypt56_gnutls(p24+8, lm_resp, partial_lm_hash + 7, SAMBA_GNUTLS_ENCRYPT);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+
+ memcpy(sess_key, p24, 16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBsesskeygen_lm_sess_key: \n"));
+ dump_data(100, sess_key, 16);
+#endif
+
+ return NT_STATUS_OK;
+}
+
+DATA_BLOB NTLMv2_generate_names_blob(TALLOC_CTX *mem_ctx,
+ const char *hostname,
+ const char *domain)
+{
+ DATA_BLOB names_blob = data_blob_talloc(mem_ctx, NULL, 0);
+
+ /* Deliberately ignore return here.. */
+ if (hostname != NULL) {
+ (void)msrpc_gen(mem_ctx, &names_blob,
+ "aaa",
+ MsvAvNbDomainName, domain,
+ MsvAvNbComputerName, hostname,
+ MsvAvEOL, "");
+ } else {
+ (void)msrpc_gen(mem_ctx, &names_blob,
+ "aa",
+ MsvAvNbDomainName, domain,
+ MsvAvEOL, "");
+ }
+ return names_blob;
+}
+
+static DATA_BLOB NTLMv2_generate_client_data(TALLOC_CTX *mem_ctx,
+ NTTIME nttime,
+ const DATA_BLOB *names_blob)
+{
+ uint8_t client_chal[8];
+ DATA_BLOB response = data_blob(NULL, 0);
+ uint8_t long_date[8];
+
+ generate_random_buffer(client_chal, sizeof(client_chal));
+
+ push_nttime(long_date, 0, nttime);
+
+ /* See http://www.ubiqx.org/cifs/SMB.html#SMB.8.5 */
+
+ /* Deliberately ignore return here.. */
+ (void)msrpc_gen(mem_ctx, &response, "ddbbdb",
+ 0x00000101, /* Header */
+ 0, /* 'Reserved' */
+ long_date, 8, /* Timestamp */
+ client_chal, 8, /* client challenge */
+ 0, /* Unknown */
+ names_blob->data, names_blob->length); /* End of name list */
+
+ return response;
+}
+
+static DATA_BLOB NTLMv2_generate_response(TALLOC_CTX *out_mem_ctx,
+ const uint8_t ntlm_v2_hash[16],
+ const DATA_BLOB *server_chal,
+ NTTIME nttime,
+ const DATA_BLOB *names_blob)
+{
+ uint8_t ntlmv2_response[16];
+ DATA_BLOB ntlmv2_client_data;
+ DATA_BLOB final_response;
+ NTSTATUS status;
+
+ TALLOC_CTX *mem_ctx = talloc_named(out_mem_ctx, 0,
+ "NTLMv2_generate_response internal context");
+
+ if (!mem_ctx) {
+ return data_blob(NULL, 0);
+ }
+
+ /* NTLMv2 */
+ /* generate some data to pass into the response function - including
+ the hostname and domain name of the server */
+ ntlmv2_client_data = NTLMv2_generate_client_data(mem_ctx, nttime, names_blob);
+
+ /* Given that data, and the challenge from the server, generate a response */
+ status = SMBOWFencrypt_ntv2(ntlm_v2_hash,
+ server_chal,
+ &ntlmv2_client_data,
+ ntlmv2_response);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return data_blob(NULL, 0);
+ }
+
+ final_response = data_blob_talloc(out_mem_ctx, NULL, sizeof(ntlmv2_response) + ntlmv2_client_data.length);
+
+ memcpy(final_response.data, ntlmv2_response, sizeof(ntlmv2_response));
+
+ memcpy(final_response.data+sizeof(ntlmv2_response),
+ ntlmv2_client_data.data, ntlmv2_client_data.length);
+
+ talloc_free(mem_ctx);
+
+ return final_response;
+}
+
+static DATA_BLOB LMv2_generate_response(TALLOC_CTX *mem_ctx,
+ const uint8_t ntlm_v2_hash[16],
+ const DATA_BLOB *server_chal)
+{
+ uint8_t lmv2_response[16];
+ DATA_BLOB lmv2_client_data = data_blob_talloc(mem_ctx, NULL, 8);
+ DATA_BLOB final_response = data_blob_talloc(mem_ctx, NULL,24);
+ NTSTATUS status;
+
+ /* LMv2 */
+ /* client-supplied random data */
+ generate_random_buffer(lmv2_client_data.data, lmv2_client_data.length);
+
+ /* Given that data, and the challenge from the server, generate a response */
+ status = SMBOWFencrypt_ntv2(ntlm_v2_hash,
+ server_chal,
+ &lmv2_client_data,
+ lmv2_response);
+ if (!NT_STATUS_IS_OK(status)) {
+ data_blob_free(&lmv2_client_data);
+ return data_blob(NULL, 0);
+ }
+ memcpy(final_response.data, lmv2_response, sizeof(lmv2_response));
+
+ /* after the first 16 bytes is the random data we generated above,
+ so the server can verify us with it */
+ memcpy(final_response.data+sizeof(lmv2_response),
+ lmv2_client_data.data, lmv2_client_data.length);
+
+ data_blob_free(&lmv2_client_data);
+
+ return final_response;
+}
+
+bool SMBNTLMv2encrypt_hash(TALLOC_CTX *mem_ctx,
+ const char *user, const char *domain, const uint8_t nt_hash[16],
+ const DATA_BLOB *server_chal,
+ const NTTIME *server_timestamp,
+ const DATA_BLOB *names_blob,
+ DATA_BLOB *lm_response, DATA_BLOB *nt_response,
+ DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key)
+{
+ uint8_t ntlm_v2_hash[16];
+ NTSTATUS status;
+
+ /* We don't use the NT# directly. Instead we use it mashed up with
+ the username and domain.
+ This prevents username swapping during the auth exchange
+ */
+ if (!ntv2_owf_gen(nt_hash, user, domain, ntlm_v2_hash)) {
+ return false;
+ }
+
+ if (nt_response) {
+ const NTTIME *nttime = server_timestamp;
+ NTTIME _now = 0;
+
+ if (nttime == NULL) {
+ struct timeval tv_now = timeval_current();
+ _now = timeval_to_nttime(&tv_now);
+ nttime = &_now;
+ }
+
+ *nt_response = NTLMv2_generate_response(mem_ctx,
+ ntlm_v2_hash,
+ server_chal,
+ *nttime,
+ names_blob);
+ if (user_session_key) {
+ *user_session_key = data_blob_talloc(mem_ctx, NULL, 16);
+
+ /* The NTLMv2 calculations also provide a session key, for signing etc later */
+ /* use only the first 16 bytes of nt_response for session key */
+ status = SMBsesskeygen_ntv2(ntlm_v2_hash,
+ nt_response->data,
+ user_session_key->data);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ }
+ }
+
+ /* LMv2 */
+
+ if (lm_response) {
+ if (server_timestamp != NULL) {
+ *lm_response = data_blob_talloc_zero(mem_ctx, 24);
+ } else {
+ *lm_response = LMv2_generate_response(mem_ctx,
+ ntlm_v2_hash,
+ server_chal);
+ }
+ if (lm_session_key) {
+ *lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
+
+ /* The NTLMv2 calculations also provide a session key, for signing etc later */
+ /* use only the first 16 bytes of lm_response for session key */
+ status = SMBsesskeygen_ntv2(ntlm_v2_hash,
+ lm_response->data,
+ lm_session_key->data);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool SMBNTLMv2encrypt(TALLOC_CTX *mem_ctx,
+ const char *user, const char *domain,
+ const char *password,
+ const DATA_BLOB *server_chal,
+ const DATA_BLOB *names_blob,
+ DATA_BLOB *lm_response, DATA_BLOB *nt_response,
+ DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key)
+{
+ uint8_t nt_hash[16];
+ E_md4hash(password, nt_hash);
+
+ return SMBNTLMv2encrypt_hash(mem_ctx,
+ user, domain, nt_hash,
+ server_chal, NULL, names_blob,
+ lm_response, nt_response, lm_session_key, user_session_key);
+}
+
+NTSTATUS NTLMv2_RESPONSE_verify_netlogon_creds(const char *account_name,
+ const char *account_domain,
+ const DATA_BLOB response,
+ const struct netlogon_creds_CredentialState *creds,
+ const char *workgroup)
+{
+ TALLOC_CTX *frame = NULL;
+ /* RespType + HiRespType */
+ static const char *magic = "\x01\x01";
+ int cmp;
+ struct NTLMv2_RESPONSE v2_resp;
+ enum ndr_err_code err;
+ const struct AV_PAIR *av_nb_cn = NULL;
+ const struct AV_PAIR *av_nb_dn = NULL;
+
+ if (response.length < 48) {
+ /*
+ * NTLMv2_RESPONSE has at least 48 bytes.
+ */
+ return NT_STATUS_OK;
+ }
+
+ cmp = memcmp(response.data + 16, magic, 2);
+ if (cmp != 0) {
+ /*
+ * It doesn't look like a valid NTLMv2_RESPONSE
+ */
+ return NT_STATUS_OK;
+ }
+
+ if (response.length == 95) {
+ /*
+ * ndr_pull_NTLMv2_RESPONSE() fails on this strange blob,
+ * because the AvPairs content is not valid
+ * as AvLen of the first pair is 33032 (0x8108).
+ *
+ * I saw a single machine sending the following 3 times
+ * in a row, but I'm not sure if everything is static.
+ *
+ * Note this is NTLMv2_CLIENT_CHALLENGE only, not
+ * the full NTLMv2_RESPONSE (which has Response of 16 bytes
+ * before the NTLMv2_CLIENT_CHALLENGE).
+ *
+ * Note this code only prevents
+ * ndr_pull_error(Buffer Size Error): Pull bytes 39016
+ * debug message for a known case, the actual
+ * bug is also handled below in a generic way to
+ * map NT_STATUS_BUFFER_TOO_SMALL to NT_STATUS_OK.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14932
+ */
+ static const char *netapp_magic =
+ "\x01\x01\x00\x00\x00\x00\x00\x00"
+ "\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x3f"
+ "\xb8\x82\x3a\xf1\xb3\xdd\x08\x15"
+ "\x00\x00\x00\x00\x11\xa2\x08\x81"
+ "\x50\x38\x22\x78\x2b\x94\x47\xfe"
+ "\x54\x94\x7b\xff\x17\x27\x5a\xb4"
+ "\xf4\x18\xba\xdc\x2c\x38\xfd\x5b"
+ "\xfb\x0e\xc1\x85\x1e\xcc\x92\xbb"
+ "\x9b\xb1\xc4\xd5\x53\x14\xff\x8c"
+ "\x76\x49\xf5\x45\x90\x19\xa2";
+ /*
+ * First we check the initial bytes
+ * and the 0x3F timestamp.
+ */
+ cmp = memcmp(response.data + 16,
+ netapp_magic,
+ 16);
+ if (cmp == 0) {
+ /*
+ * Then check everything after the
+ * client challenge
+ */
+ cmp = memcmp(response.data + 40,
+ netapp_magic + 24,
+ response.length - 40);
+ if (cmp == 0) {
+ DBG_DEBUG("Invalid NETAPP NTLMv2_RESPONSE "
+ "for user[%s\\%s] against "
+ "SEC_CHAN(%u)[%s/%s] "
+ "in workgroup[%s]\n",
+ account_domain,
+ account_name,
+ creds->secure_channel_type,
+ creds->computer_name,
+ creds->account_name,
+ workgroup);
+ return NT_STATUS_OK;
+ }
+ }
+ }
+
+ frame = talloc_stackframe();
+
+ err = ndr_pull_struct_blob(&response, frame, &v2_resp,
+ (ndr_pull_flags_fn_t)ndr_pull_NTLMv2_RESPONSE);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ NTSTATUS status;
+ status = ndr_map_error2ntstatus(err);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
+ /*
+ * We are supposed to ignore invalid buffers,
+ * see https://bugzilla.samba.org/show_bug.cgi?id=14932
+ */
+ status = NT_STATUS_OK;
+ }
+ DEBUG(2,("%s: Failed to parse NTLMv2_RESPONSE length=%u "
+ "for user[%s\\%s] against SEC_CHAN(%u)[%s/%s] "
+ "in workgroup[%s] - %s %s %s\n",
+ __func__,
+ (unsigned)response.length,
+ account_domain,
+ account_name,
+ creds->secure_channel_type,
+ creds->computer_name,
+ creds->account_name,
+ workgroup,
+ ndr_map_error2string(err),
+ NT_STATUS_IS_OK(status) ? "(ignoring) =>" : "=>",
+ nt_errstr(status)));
+ dump_data(2, response.data, response.length);
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ if (DEBUGLVL(10)) {
+ NDR_PRINT_DEBUG(NTLMv2_RESPONSE, &v2_resp);
+ }
+
+ /*
+ * Make sure the netbios computer name in the
+ * NTLMv2_RESPONSE matches the computer name
+ * in the secure channel credentials for workstation
+ * trusts.
+ *
+ * And the netbios domain name matches our
+ * workgroup.
+ *
+ * This prevents workstations from requesting
+ * the session key of NTLMSSP sessions of clients
+ * to other hosts.
+ */
+ if (creds->secure_channel_type == SEC_CHAN_WKSTA) {
+ av_nb_cn = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs,
+ MsvAvNbComputerName);
+ av_nb_dn = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs,
+ MsvAvNbDomainName);
+ }
+
+ if (av_nb_cn != NULL) {
+ const char *v = NULL;
+ char *a = NULL;
+ size_t len;
+
+ v = av_nb_cn->Value.AvNbComputerName;
+
+ a = talloc_strdup(frame, creds->account_name);
+ if (a == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+ len = strlen(a);
+ if (len > 0 && a[len - 1] == '$') {
+ a[len - 1] = '\0';
+ }
+
+ cmp = strcasecmp_m(a, v);
+ if (cmp != 0) {
+ DEBUG(2,("%s: NTLMv2_RESPONSE with "
+ "NbComputerName[%s] rejected "
+ "for user[%s\\%s] "
+ "against SEC_CHAN_WKSTA[%s/%s] "
+ "in workgroup[%s]\n",
+ __func__, v,
+ account_domain,
+ account_name,
+ creds->computer_name,
+ creds->account_name,
+ workgroup));
+ TALLOC_FREE(frame);
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ }
+ if (av_nb_dn != NULL) {
+ const char *v = NULL;
+
+ v = av_nb_dn->Value.AvNbDomainName;
+
+ cmp = strcasecmp_m(workgroup, v);
+ if (cmp != 0) {
+ DEBUG(2,("%s: NTLMv2_RESPONSE with "
+ "NbDomainName[%s] rejected "
+ "for user[%s\\%s] "
+ "against SEC_CHAN_WKSTA[%s/%s] "
+ "in workgroup[%s]\n",
+ __func__, v,
+ account_domain,
+ account_name,
+ creds->computer_name,
+ creds->account_name,
+ workgroup));
+ TALLOC_FREE(frame);
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+enum encode_order {
+ ENCODE_ORDER_PASSWORD_FIRST,
+ ENCODE_ORDER_PASSWORD_LAST,
+};
+
+#define PASSWORD_BUFFER_LEN 512
+
+static ssize_t _encode_pwd_buffer_from_str(uint8_t buf[PASSWORD_BUFFER_LEN],
+ const char *password,
+ int string_flags,
+ enum encode_order order)
+{
+ ssize_t new_pw_len;
+ size_t pw_pos = 0;
+ size_t random_pos = 0;
+ size_t random_len = 0;
+
+ /* The incoming buffer can be any alignment. */
+ string_flags |= STR_NOALIGN;
+
+ new_pw_len = push_string(buf,
+ password,
+ PASSWORD_BUFFER_LEN,
+ string_flags);
+ if (new_pw_len < 0) {
+ BURN_DATA_SIZE(buf, PASSWORD_BUFFER_LEN);
+ return -1;
+ }
+
+ if (new_pw_len == PASSWORD_BUFFER_LEN) {
+ return new_pw_len;
+ }
+
+ switch (order) {
+ case ENCODE_ORDER_PASSWORD_FIRST:
+ pw_pos = 0;
+ random_pos = new_pw_len;
+ random_len = PASSWORD_BUFFER_LEN - random_pos;
+ break;
+ case ENCODE_ORDER_PASSWORD_LAST:
+ pw_pos = PASSWORD_BUFFER_LEN - new_pw_len;
+ random_pos = 0;
+ random_len = pw_pos;
+ memmove(buf + pw_pos, buf, new_pw_len);
+ break;
+ }
+
+ generate_random_buffer(buf + random_pos, random_len);
+
+ return new_pw_len;
+}
+
+/***********************************************************
+ encode a password buffer with a unicode password. The buffer
+ is filled with random data to make it harder to attack.
+************************************************************/
+bool encode_pw_buffer(uint8_t buffer[516], const char *password, int string_flags)
+{
+ ssize_t pw_len;
+
+ pw_len = _encode_pwd_buffer_from_str(buffer,
+ password,
+ string_flags,
+ ENCODE_ORDER_PASSWORD_LAST);
+ if (pw_len < 0 || pw_len > PASSWORD_BUFFER_LEN) {
+ return false;
+ }
+
+ PUSH_LE_U32(buffer, PASSWORD_BUFFER_LEN, pw_len);
+
+ return true;
+}
+
+
+/***********************************************************
+ decode a password buffer
+ *new_pw_len is the length in bytes of the possibly mulitbyte
+ returned password including termination.
+************************************************************/
+
+bool decode_pw_buffer(TALLOC_CTX *ctx,
+ uint8_t in_buffer[516],
+ char **pp_new_pwrd,
+ size_t *new_pw_len,
+ charset_t string_charset)
+{
+ DATA_BLOB new_password;
+ int byte_len=0;
+ bool ok;
+
+ *pp_new_pwrd = NULL;
+ *new_pw_len = 0;
+
+ ok = extract_pw_from_buffer(ctx, in_buffer, &new_password);
+ if (!ok) {
+ return false;
+ }
+
+ /*
+ Warning !!! : This function is called from some rpc call.
+ The password IN the buffer may be a UNICODE string.
+ The password IN new_pwrd is an ASCII string
+ If you reuse that code somewhere else check first.
+ */
+
+ /* decode into the return buffer. */
+ ok = convert_string_talloc(ctx,
+ string_charset,
+ CH_UNIX,
+ new_password.data,
+ new_password.length,
+ pp_new_pwrd,
+ new_pw_len);
+ data_blob_free(&new_password);
+ if (!ok) {
+ DBG_ERR("Failed to convert incoming password\n");
+ return false;
+ }
+ talloc_keep_secret(*pp_new_pwrd);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("decode_pw_buffer: new_pwrd: "));
+ dump_data(100, (uint8_t *)*pp_new_pwrd, *new_pw_len);
+ DEBUG(100,("multibyte len:%lu\n", (unsigned long int)*new_pw_len));
+ DEBUG(100,("original char len:%d\n", byte_len/2));
+#endif
+
+ return true;
+}
+
+#define MAX_PASSWORD_LEN 256
+
+/*
+ * [MS-SAMR] 2.2.6.32 This creates the buffer to be sent. It is of type
+ * SAMPR_USER_PASSWORD_AES.
+ */
+bool encode_pwd_buffer514_from_str(uint8_t buffer[514],
+ const char *password,
+ uint32_t string_flags)
+{
+ ssize_t pw_len;
+
+ pw_len = _encode_pwd_buffer_from_str(buffer + 2,
+ password,
+ string_flags,
+ ENCODE_ORDER_PASSWORD_FIRST);
+ if (pw_len < 0) {
+ return false;
+ }
+
+ PUSH_LE_U16(buffer, 0, pw_len);
+
+ return true;
+}
+
+bool extract_pwd_blob_from_buffer514(TALLOC_CTX *mem_ctx,
+ const uint8_t in_buffer[514],
+ DATA_BLOB *new_password)
+{
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("in_buffer: "));
+ dump_data(100, in_buffer, 514);
+#endif
+
+ new_password->length = PULL_LE_U16(in_buffer, 0);
+ if (new_password->length == 0 || new_password->length > 512) {
+ return false;
+ }
+
+ new_password->data =
+ talloc_memdup(mem_ctx, in_buffer + 2, new_password->length);
+ if (new_password->data == NULL) {
+ return false;
+ }
+ talloc_keep_secret(new_password->data);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("new_pwd_len: %zu\n", new_password->length));
+ DEBUG(100, ("new_pwd: "));
+ dump_data(100, new_password->data, new_password->length);
+#endif
+
+ return true;
+}
+
+bool decode_pwd_string_from_buffer514(TALLOC_CTX *mem_ctx,
+ const uint8_t in_buffer[514],
+ charset_t string_charset,
+ DATA_BLOB *decoded_password)
+{
+ DATA_BLOB new_password = {
+ .length = 0,
+ };
+ bool ok;
+
+ ok = extract_pwd_blob_from_buffer514(mem_ctx, in_buffer, &new_password);
+ if (!ok) {
+ return false;
+ }
+
+ ok = convert_string_talloc(mem_ctx,
+ string_charset,
+ CH_UNIX,
+ new_password.data,
+ new_password.length,
+ &decoded_password->data,
+ &decoded_password->length);
+ data_blob_free(&new_password);
+ if (!ok) {
+ return false;
+ }
+ talloc_keep_secret(decoded_password->data);
+
+ return true;
+}
+
+/***********************************************************
+ Encode an arc4 password change buffer.
+************************************************************/
+NTSTATUS encode_rc4_passwd_buffer(const char *passwd,
+ const DATA_BLOB *session_key,
+ struct samr_CryptPasswordEx *out_crypt_pwd)
+{
+ uint8_t _confounder[16] = {0};
+ DATA_BLOB confounder = data_blob_const(_confounder, 16);
+ DATA_BLOB pw_data = data_blob_const(out_crypt_pwd->data, 516);
+ bool ok;
+ int rc;
+
+ ok = encode_pw_buffer(pw_data.data, passwd, STR_UNICODE);
+ if (!ok) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ generate_random_buffer(confounder.data, confounder.length);
+
+ rc = samba_gnutls_arcfour_confounded_md5(&confounder,
+ session_key,
+ &pw_data,
+ SAMBA_GNUTLS_ENCRYPT);
+ if (rc < 0) {
+ ZERO_ARRAY(_confounder);
+ data_blob_clear(&pw_data);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+
+ /*
+ * The packet format is the 516 byte RC4 encrypted
+ * password followed by the 16 byte counfounder
+ * The confounder is a salt to prevent pre-computed hash attacks on the
+ * database.
+ */
+ memcpy(&out_crypt_pwd->data[516], confounder.data, confounder.length);
+ ZERO_ARRAY(_confounder);
+
+ return NT_STATUS_OK;
+}
+
+/***********************************************************
+ Decode an arc4 encrypted password change buffer.
+************************************************************/
+
+NTSTATUS decode_rc4_passwd_buffer(const DATA_BLOB *psession_key,
+ struct samr_CryptPasswordEx *inout_crypt_pwd)
+{
+ /* Confounder is last 16 bytes. */
+ DATA_BLOB confounder = data_blob_const(&inout_crypt_pwd->data[516], 16);
+ DATA_BLOB pw_data = data_blob_const(&inout_crypt_pwd->data, 516);
+ int rc;
+
+ rc = samba_gnutls_arcfour_confounded_md5(&confounder,
+ psession_key,
+ &pw_data,
+ SAMBA_GNUTLS_DECRYPT);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/***********************************************************
+ encode a password buffer with an already unicode password. The
+ rest of the buffer is filled with random data to make it harder to attack.
+************************************************************/
+
+static bool create_pw_buffer_from_blob(uint8_t buffer[512],
+ const DATA_BLOB *in_password,
+ enum encode_order order)
+{
+ size_t pwd_pos = 0;
+ size_t random_pos = 0;
+ size_t random_len = 0;
+
+ if (in_password->length > 512) {
+ return false;
+ }
+
+ switch (order) {
+ case ENCODE_ORDER_PASSWORD_FIRST:
+ pwd_pos = 0;
+ random_pos = in_password->length;
+ break;
+ case ENCODE_ORDER_PASSWORD_LAST:
+ pwd_pos = PASSWORD_BUFFER_LEN - in_password->length;
+ random_pos = 0;
+ break;
+ }
+ random_len = PASSWORD_BUFFER_LEN - in_password->length;
+
+ memcpy(buffer + pwd_pos, in_password->data, in_password->length);
+ generate_random_buffer(buffer + random_pos, random_len);
+
+ return true;
+}
+
+bool set_pw_in_buffer(uint8_t buffer[516], const DATA_BLOB *password)
+{
+ bool ok;
+
+ ok = create_pw_buffer_from_blob(buffer,
+ password,
+ ENCODE_ORDER_PASSWORD_LAST);
+ if (!ok) {
+ return false;
+ }
+
+ /*
+ * The length of the new password is in the last 4 bytes of
+ * the data buffer.
+ */
+ PUSH_LE_U32(buffer, PASSWORD_BUFFER_LEN, password->length);
+
+ return true;
+}
+
+/***********************************************************
+ decode a password buffer
+ *new_pw_size is the length in bytes of the extracted unicode password
+************************************************************/
+bool extract_pw_from_buffer(TALLOC_CTX *mem_ctx,
+ uint8_t in_buffer[516], DATA_BLOB *new_pass)
+{
+ int byte_len=0;
+
+ /* The length of the new password is in the last 4 bytes of the data buffer. */
+
+ byte_len = IVAL(in_buffer, 512);
+
+#ifdef DEBUG_PASSWORD
+ dump_data(100, in_buffer, 516);
+#endif
+
+ /* Password cannot be longer than the size of the password buffer */
+ if ( (byte_len < 0) || (byte_len > 512)) {
+ return false;
+ }
+
+ *new_pass = data_blob_talloc(mem_ctx, &in_buffer[512 - byte_len], byte_len);
+
+ if (!new_pass->data) {
+ return false;
+ }
+ talloc_keep_secret(new_pass->data);
+
+ return true;
+}
+
+
+/* encode a wkssvc_PasswordBuffer:
+ *
+ * similar to samr_CryptPasswordEx. Different: 8byte confounder (instead of
+ * 16byte), confounder in front of the 516 byte buffer (instead of after that
+ * buffer), calling MD5Update() first with session_key and then with confounder
+ * (vice versa in samr) - Guenther */
+
+WERROR encode_wkssvc_join_password_buffer(TALLOC_CTX *mem_ctx,
+ const char *pwd,
+ DATA_BLOB *session_key,
+ struct wkssvc_PasswordBuffer **out_pwd_buf)
+{
+ struct wkssvc_PasswordBuffer *pwd_buf = NULL;
+ uint8_t _confounder[8] = {0};
+ DATA_BLOB confounder = data_blob_const(_confounder, 8);
+ uint8_t pwbuf[516] = {0};
+ DATA_BLOB encrypt_pwbuf = data_blob_const(pwbuf, 516);
+ int rc;
+
+ pwd_buf = talloc_zero(mem_ctx, struct wkssvc_PasswordBuffer);
+ if (pwd_buf == NULL) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ encode_pw_buffer(pwbuf, pwd, STR_UNICODE);
+
+ generate_random_buffer(_confounder, sizeof(_confounder));
+
+ rc = samba_gnutls_arcfour_confounded_md5(session_key,
+ &confounder,
+ &encrypt_pwbuf,
+ SAMBA_GNUTLS_ENCRYPT);
+ if (rc < 0) {
+ ZERO_ARRAY(_confounder);
+ TALLOC_FREE(pwd_buf);
+ return gnutls_error_to_werror(rc, WERR_CONTENT_BLOCKED);
+ }
+
+ memcpy(&pwd_buf->data[0], confounder.data, confounder.length);
+ ZERO_ARRAY(_confounder);
+ memcpy(&pwd_buf->data[8], encrypt_pwbuf.data, encrypt_pwbuf.length);
+ ZERO_ARRAY(pwbuf);
+
+ *out_pwd_buf = pwd_buf;
+
+ return WERR_OK;
+}
+
+WERROR decode_wkssvc_join_password_buffer(TALLOC_CTX *mem_ctx,
+ struct wkssvc_PasswordBuffer *pwd_buf,
+ DATA_BLOB *session_key,
+ char **pwd)
+{
+ uint8_t _confounder[8] = { 0 };
+ DATA_BLOB confounder = data_blob_const(_confounder, 8);
+ uint8_t pwbuf[516] = {0};
+ DATA_BLOB decrypt_pwbuf = data_blob_const(pwbuf, 516);
+ bool ok;
+ int rc;
+
+ if (pwd_buf == NULL) {
+ return WERR_INVALID_PASSWORD;
+ }
+
+ *pwd = NULL;
+
+ if (session_key->length != 16) {
+ DEBUG(10,("invalid session key\n"));
+ return WERR_INVALID_PASSWORD;
+ }
+
+ confounder = data_blob_const(&pwd_buf->data[0], 8);
+ memcpy(&pwbuf, &pwd_buf->data[8], 516);
+
+ rc = samba_gnutls_arcfour_confounded_md5(session_key,
+ &confounder,
+ &decrypt_pwbuf,
+ SAMBA_GNUTLS_ENCRYPT);
+ if (rc < 0) {
+ ZERO_ARRAY(_confounder);
+ TALLOC_FREE(pwd_buf);
+ return gnutls_error_to_werror(rc, WERR_CONTENT_BLOCKED);
+ }
+
+ ok = decode_pw_buffer(mem_ctx,
+ decrypt_pwbuf.data,
+ pwd,
+ &decrypt_pwbuf.length,
+ CH_UTF16);
+ ZERO_ARRAY(pwbuf);
+
+ if (!ok) {
+ return WERR_INVALID_PASSWORD;
+ }
+
+ return WERR_OK;
+}
diff --git a/libcli/auth/spnego.h b/libcli/auth/spnego.h
new file mode 100644
index 0000000..49645e0
--- /dev/null
+++ b/libcli/auth/spnego.h
@@ -0,0 +1,82 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ RFC2478 Compliant SPNEGO implementation
+
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+
+ 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/>.
+*/
+
+#define OID_SPNEGO "1.3.6.1.5.5.2"
+#define OID_NTLMSSP "1.3.6.1.4.1.311.2.2.10"
+#define OID_KERBEROS5_OLD "1.2.840.48018.1.2.2"
+#define OID_KERBEROS5 "1.2.840.113554.1.2.2"
+
+#define ADS_IGNORE_PRINCIPAL "not_defined_in_RFC4178@please_ignore"
+
+#define SPNEGO_DELEG_FLAG 0x01
+#define SPNEGO_MUTUAL_FLAG 0x02
+#define SPNEGO_REPLAY_FLAG 0x04
+#define SPNEGO_SEQUENCE_FLAG 0x08
+#define SPNEGO_ANON_FLAG 0x10
+#define SPNEGO_CONF_FLAG 0x20
+#define SPNEGO_INTEG_FLAG 0x40
+
+#define TOK_ID_KRB_AP_REQ ((const uint8_t *)"\x01\x00")
+#define TOK_ID_KRB_AP_REP ((const uint8_t *)"\x02\x00")
+#define TOK_ID_KRB_ERROR ((const uint8_t *)"\x03\x00")
+#define TOK_ID_GSS_GETMIC ((const uint8_t *)"\x01\x01")
+#define TOK_ID_GSS_WRAP ((const uint8_t *)"\x02\x01")
+
+enum spnego_negResult {
+ SPNEGO_ACCEPT_COMPLETED = 0,
+ SPNEGO_ACCEPT_INCOMPLETE = 1,
+ SPNEGO_REJECT = 2,
+ SPNEGO_REQUEST_MIC = 3,
+ /*
+ * The max value is 0xff (255) on the wire
+ */
+ SPNEGO_NONE_RESULT = 256
+};
+
+struct spnego_negTokenInit {
+ const char * const *mechTypes;
+ DATA_BLOB reqFlags;
+ uint8_t reqFlagsPadding;
+ DATA_BLOB mechToken;
+ DATA_BLOB mechListMIC;
+ char *targetPrincipal;
+};
+
+struct spnego_negTokenTarg {
+ enum spnego_negResult negResult;
+ const char *supportedMech;
+ DATA_BLOB responseToken;
+ DATA_BLOB mechListMIC;
+};
+
+struct spnego_data {
+ int type;
+ struct spnego_negTokenInit negTokenInit;
+ struct spnego_negTokenTarg negTokenTarg;
+};
+
+enum spnego_message_type {
+ SPNEGO_NEG_TOKEN_INIT = 0,
+ SPNEGO_NEG_TOKEN_TARG = 1,
+};
+
+#include "../libcli/auth/spnego_proto.h"
diff --git a/libcli/auth/spnego_parse.c b/libcli/auth/spnego_parse.c
new file mode 100644
index 0000000..f7f19b1
--- /dev/null
+++ b/libcli/auth/spnego_parse.c
@@ -0,0 +1,446 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ RFC2478 Compliant SPNEGO implementation
+
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+
+ 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 "../libcli/auth/spnego.h"
+#include "../lib/util/asn1.h"
+
+static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
+ struct spnego_negTokenInit *token)
+{
+ ZERO_STRUCTP(token);
+
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(0))) return false;
+ if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false;
+
+ while (asn1_tag_remaining(asn1) > 0) {
+ int i;
+ uint8_t context;
+
+ if (!asn1_peek_uint8(asn1, &context)) {
+ asn1_set_error(asn1);
+ break;
+ }
+
+ switch (context) {
+ /* Read mechTypes */
+ case ASN1_CONTEXT(0): {
+ const char **mechTypes;
+
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(0))) return false;
+ if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false;
+
+ mechTypes = talloc(mem_ctx, const char *);
+ if (mechTypes == NULL) {
+ asn1_set_error(asn1);
+ return false;
+ }
+ for (i = 0; asn1_tag_remaining(asn1) > 0; i++) {
+ char *oid;
+ const char **p;
+ p = talloc_realloc(mem_ctx,
+ mechTypes,
+ const char *, i+2);
+ if (p == NULL) {
+ talloc_free(mechTypes);
+ asn1_set_error(asn1);
+ return false;
+ }
+ mechTypes = p;
+
+ if (!asn1_read_OID(asn1, mechTypes, &oid)) return false;
+ mechTypes[i] = oid;
+ }
+ mechTypes[i] = NULL;
+ token->mechTypes = mechTypes;
+
+ asn1_end_tag(asn1);
+ asn1_end_tag(asn1);
+ break;
+ }
+ /* Read reqFlags */
+ case ASN1_CONTEXT(1):
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(1))) return false;
+ if (!asn1_read_BitString(asn1, mem_ctx, &token->reqFlags,
+ &token->reqFlagsPadding)) return false;
+ if (!asn1_end_tag(asn1)) return false;
+ break;
+ /* Read mechToken */
+ case ASN1_CONTEXT(2):
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(2))) return false;
+ if (!asn1_read_OctetString(asn1, mem_ctx, &token->mechToken)) return false;
+ if (!asn1_end_tag(asn1)) return false;
+ break;
+ /* Read mecListMIC */
+ case ASN1_CONTEXT(3):
+ {
+ uint8_t type_peek;
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(3))) return false;
+ if (!asn1_peek_uint8(asn1, &type_peek)) {
+ asn1_set_error(asn1);
+ break;
+ }
+ if (type_peek == ASN1_OCTET_STRING) {
+ if (!asn1_read_OctetString(asn1, mem_ctx,
+ &token->mechListMIC)) return false;
+ } else {
+ /* RFC 2478 says we have an Octet String here,
+ but W2k sends something different... */
+ char *mechListMIC;
+ if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false;
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(0))) return false;
+ if (!asn1_read_GeneralString(asn1, mem_ctx, &mechListMIC)) return false;
+ if (!asn1_end_tag(asn1)) return false;
+ if (!asn1_end_tag(asn1)) return false;
+
+ token->targetPrincipal = mechListMIC;
+ }
+ if (!asn1_end_tag(asn1)) return false;
+ break;
+ }
+ default:
+ asn1_set_error(asn1);
+ break;
+ }
+ }
+
+ if (!asn1_end_tag(asn1)) return false;
+ if (!asn1_end_tag(asn1)) return false;
+
+ return !asn1_has_error(asn1);
+}
+
+static bool write_negTokenInit(struct asn1_data *asn1, struct spnego_negTokenInit *token)
+{
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(0))) return false;
+ if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) return false;
+
+ /* Write mechTypes */
+ if (token->mechTypes && *token->mechTypes) {
+ int i;
+
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(0))) return false;
+ if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) return false;
+ for (i = 0; token->mechTypes[i]; i++) {
+ if (!asn1_write_OID(asn1, token->mechTypes[i])) return false;
+ }
+ if (!asn1_pop_tag(asn1)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+ }
+
+ /* write reqFlags */
+ if (token->reqFlags.length > 0) {
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(1))) return false;
+ if (!asn1_write_BitString(asn1, token->reqFlags.data,
+ token->reqFlags.length,
+ token->reqFlagsPadding)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+ }
+
+ /* write mechToken */
+ if (token->mechToken.data) {
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(2))) return false;
+ if (!asn1_write_OctetString(asn1, token->mechToken.data,
+ token->mechToken.length)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+ }
+
+ /* write mechListMIC */
+ if (token->mechListMIC.data) {
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(3))) return false;
+#if 0
+ /* This is what RFC 2478 says ... */
+ asn1_write_OctetString(asn1, token->mechListMIC.data,
+ token->mechListMIC.length);
+#else
+ /* ... but unfortunately this is what Windows
+ sends/expects */
+ if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) return false;
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(0))) return false;
+ if (!asn1_push_tag(asn1, ASN1_GENERAL_STRING)) return false;
+ if (!asn1_write(asn1, token->mechListMIC.data,
+ token->mechListMIC.length)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+#endif
+ if (!asn1_pop_tag(asn1)) return false;
+ }
+
+ if (!asn1_pop_tag(asn1)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+
+ return !asn1_has_error(asn1);
+}
+
+static bool read_negTokenTarg(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
+ struct spnego_negTokenTarg *token)
+{
+ ZERO_STRUCTP(token);
+
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(1))) return false;
+ if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false;
+
+ while (asn1_tag_remaining(asn1) > 0) {
+ uint8_t context;
+ uint8_t neg_result;
+ char *oid;
+
+ if (!asn1_peek_uint8(asn1, &context)) {
+ asn1_set_error(asn1);
+ break;
+ }
+
+ switch (context) {
+ case ASN1_CONTEXT(0):
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(0))) return false;
+ if (!asn1_start_tag(asn1, ASN1_ENUMERATED)) return false;
+ if (!asn1_read_uint8(asn1, &neg_result)) return false;
+ token->negResult = neg_result;
+ if (!asn1_end_tag(asn1)) return false;
+ if (!asn1_end_tag(asn1)) return false;
+ break;
+ case ASN1_CONTEXT(1):
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(1))) return false;
+ if (!asn1_read_OID(asn1, mem_ctx, &oid)) return false;
+ token->supportedMech = oid;
+ if (!asn1_end_tag(asn1)) return false;
+ break;
+ case ASN1_CONTEXT(2):
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(2))) return false;
+ if (!asn1_read_OctetString(asn1, mem_ctx, &token->responseToken)) return false;
+ if (!asn1_end_tag(asn1)) return false;
+ break;
+ case ASN1_CONTEXT(3):
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(3))) return false;
+ if (!asn1_read_OctetString(asn1, mem_ctx, &token->mechListMIC)) return false;
+ if (!asn1_end_tag(asn1)) return false;
+ break;
+ default:
+ asn1_set_error(asn1);
+ break;
+ }
+ }
+
+ if (!asn1_end_tag(asn1)) return false;
+ if (!asn1_end_tag(asn1)) return false;
+
+ return !asn1_has_error(asn1);
+}
+
+static bool write_negTokenTarg(struct asn1_data *asn1, struct spnego_negTokenTarg *token)
+{
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(1))) return false;
+ if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) return false;
+
+ if (token->negResult != SPNEGO_NONE_RESULT) {
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(0))) return false;
+ if (!asn1_write_enumerated(asn1, token->negResult)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+ }
+
+ if (token->supportedMech) {
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(1))) return false;
+ if (!asn1_write_OID(asn1, token->supportedMech)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+ }
+
+ if (token->responseToken.data) {
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(2))) return false;
+ if (!asn1_write_OctetString(asn1, token->responseToken.data,
+ token->responseToken.length)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+ }
+
+ if (token->mechListMIC.data) {
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(3))) return false;
+ if (!asn1_write_OctetString(asn1, token->mechListMIC.data,
+ token->mechListMIC.length)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+ }
+
+ if (!asn1_pop_tag(asn1)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+
+ return !asn1_has_error(asn1);
+}
+
+ssize_t spnego_read_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, struct spnego_data *token)
+{
+ struct asn1_data *asn1;
+ ssize_t ret = -1;
+ uint8_t context;
+
+ ZERO_STRUCTP(token);
+
+ if (data.length == 0) {
+ return ret;
+ }
+
+ asn1 = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
+ if (asn1 == NULL) {
+ return -1;
+ }
+
+ if (!asn1_load(asn1, data)) goto err;
+
+ if (!asn1_peek_uint8(asn1, &context)) {
+ asn1_set_error(asn1);
+ } else {
+ switch (context) {
+ case ASN1_APPLICATION(0):
+ if (!asn1_start_tag(asn1, ASN1_APPLICATION(0))) goto err;
+ if (!asn1_check_OID(asn1, OID_SPNEGO)) goto err;
+ if (read_negTokenInit(asn1, mem_ctx, &token->negTokenInit)) {
+ token->type = SPNEGO_NEG_TOKEN_INIT;
+ }
+ if (!asn1_end_tag(asn1)) goto err;
+ break;
+ case ASN1_CONTEXT(1):
+ if (read_negTokenTarg(asn1, mem_ctx, &token->negTokenTarg)) {
+ token->type = SPNEGO_NEG_TOKEN_TARG;
+ }
+ break;
+ default:
+ asn1_set_error(asn1);
+ break;
+ }
+ }
+
+ if (!asn1_has_error(asn1)) {
+ ret = asn1_current_ofs(asn1);
+ }
+
+ err:
+
+ asn1_free(asn1);
+
+ return ret;
+}
+
+ssize_t spnego_write_data(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct spnego_data *spnego)
+{
+ struct asn1_data *asn1 = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
+ ssize_t ret = -1;
+
+ if (asn1 == NULL) {
+ return -1;
+ }
+
+ switch (spnego->type) {
+ case SPNEGO_NEG_TOKEN_INIT:
+ if (!asn1_push_tag(asn1, ASN1_APPLICATION(0))) goto err;
+ if (!asn1_write_OID(asn1, OID_SPNEGO)) goto err;
+ if (!write_negTokenInit(asn1, &spnego->negTokenInit)) goto err;
+ if (!asn1_pop_tag(asn1)) goto err;
+ break;
+ case SPNEGO_NEG_TOKEN_TARG:
+ write_negTokenTarg(asn1, &spnego->negTokenTarg);
+ break;
+ default:
+ asn1_set_error(asn1);
+ break;
+ }
+
+ if (!asn1_extract_blob(asn1, mem_ctx, blob)) {
+ goto err;
+ }
+
+ ret = asn1_current_ofs(asn1);
+
+ err:
+
+ asn1_free(asn1);
+
+ return ret;
+}
+
+bool spnego_free_data(struct spnego_data *spnego)
+{
+ bool ret = true;
+
+ if (!spnego) goto out;
+
+ switch(spnego->type) {
+ case SPNEGO_NEG_TOKEN_INIT:
+ if (spnego->negTokenInit.mechTypes) {
+ talloc_free(discard_const(spnego->negTokenInit.mechTypes));
+ }
+ data_blob_free(&spnego->negTokenInit.reqFlags);
+ data_blob_free(&spnego->negTokenInit.mechToken);
+ data_blob_free(&spnego->negTokenInit.mechListMIC);
+ talloc_free(spnego->negTokenInit.targetPrincipal);
+ break;
+ case SPNEGO_NEG_TOKEN_TARG:
+ if (spnego->negTokenTarg.supportedMech) {
+ talloc_free(discard_const(spnego->negTokenTarg.supportedMech));
+ }
+ data_blob_free(&spnego->negTokenTarg.responseToken);
+ data_blob_free(&spnego->negTokenTarg.mechListMIC);
+ break;
+ default:
+ ret = false;
+ break;
+ }
+ ZERO_STRUCTP(spnego);
+out:
+ return ret;
+}
+
+bool spnego_write_mech_types(TALLOC_CTX *mem_ctx,
+ const char * const *mech_types,
+ DATA_BLOB *blob)
+{
+ bool ret = false;
+ struct asn1_data *asn1 = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
+
+ if (asn1 == NULL) {
+ return false;
+ }
+
+ /* Write mechTypes */
+ if (mech_types && *mech_types) {
+ int i;
+
+ if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) goto err;
+ for (i = 0; mech_types[i]; i++) {
+ if (!asn1_write_OID(asn1, mech_types[i])) goto err;
+ }
+ if (!asn1_pop_tag(asn1)) goto err;
+ }
+
+ if (asn1_has_error(asn1)) {
+ goto err;
+ }
+
+ if (!asn1_extract_blob(asn1, mem_ctx, blob)) {
+ goto err;
+ }
+
+ ret = true;
+
+ err:
+
+ asn1_free(asn1);
+
+ return ret;
+}
diff --git a/libcli/auth/spnego_proto.h b/libcli/auth/spnego_proto.h
new file mode 100644
index 0000000..c0fa934
--- /dev/null
+++ b/libcli/auth/spnego_proto.h
@@ -0,0 +1,28 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ RFC2478 Compliant SPNEGO implementation
+
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
+
+ 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/>.
+*/
+
+ssize_t spnego_read_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, struct spnego_data *token);
+ssize_t spnego_write_data(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct spnego_data *spnego);
+bool spnego_free_data(struct spnego_data *spnego);
+bool spnego_write_mech_types(TALLOC_CTX *mem_ctx,
+ const char * const *mech_types,
+ DATA_BLOB *blob);
diff --git a/libcli/auth/tests/ntlm_check.c b/libcli/auth/tests/ntlm_check.c
new file mode 100644
index 0000000..79b8ec9
--- /dev/null
+++ b/libcli/auth/tests/ntlm_check.c
@@ -0,0 +1,413 @@
+/*
+ * Unit tests for the ntlm_check password hash check library.
+ *
+ * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
+ *
+ * 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/>.
+ *
+ */
+
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ *
+ */
+
+/*
+ * Note that the messaging routines (audit_message_send and get_event_server)
+ * are not tested by these unit tests. Currently they are for integration
+ * test support, and as such are exercised by the integration tests.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "includes.h"
+#include "librpc/gen_ndr/netlogon.h"
+#include "libcli/auth/libcli_auth.h"
+#include "auth/credentials/credentials.h"
+
+struct ntlm_state {
+ const char *username;
+ const char *domain;
+ DATA_BLOB challenge;
+ DATA_BLOB ntlm;
+ DATA_BLOB lm;
+ DATA_BLOB ntlm_key;
+ DATA_BLOB lm_key;
+ const struct samr_Password *nt_hash;
+};
+
+static int test_ntlm_setup_with_options(void **state,
+ int flags, bool upn)
+{
+ NTSTATUS status;
+ DATA_BLOB challenge = {
+ .data = discard_const_p(uint8_t, "I am a teapot"),
+ .length = 8
+ };
+ struct ntlm_state *ntlm_state = talloc(NULL, struct ntlm_state);
+ DATA_BLOB target_info = NTLMv2_generate_names_blob(ntlm_state,
+ NULL,
+ "serverdom");
+ struct cli_credentials *creds = cli_credentials_init(ntlm_state);
+ cli_credentials_set_username(creds,
+ "testuser",
+ CRED_SPECIFIED);
+ cli_credentials_set_domain(creds,
+ "testdom",
+ CRED_SPECIFIED);
+ cli_credentials_set_workstation(creds,
+ "testwksta",
+ CRED_SPECIFIED);
+ cli_credentials_set_password(creds,
+ "testpass",
+ CRED_SPECIFIED);
+
+ if (upn) {
+ cli_credentials_set_principal(creds,
+ "testuser@samba.org",
+ CRED_SPECIFIED);
+ }
+
+ cli_credentials_get_ntlm_username_domain(creds,
+ ntlm_state,
+ &ntlm_state->username,
+ &ntlm_state->domain);
+
+ status = cli_credentials_get_ntlm_response(creds,
+ ntlm_state,
+ &flags,
+ challenge,
+ NULL,
+ target_info,
+ &ntlm_state->lm,
+ &ntlm_state->ntlm,
+ &ntlm_state->lm_key,
+ &ntlm_state->ntlm_key);
+ ntlm_state->challenge = challenge;
+
+ ntlm_state->nt_hash = cli_credentials_get_nt_hash(creds,
+ ntlm_state);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+
+ *state = ntlm_state;
+ return 0;
+}
+
+static int test_ntlm_setup(void **state) {
+ return test_ntlm_setup_with_options(state, 0, false);
+}
+
+static int test_ntlm_and_lm_setup(void **state) {
+ return test_ntlm_setup_with_options(state,
+ CLI_CRED_LANMAN_AUTH,
+ false);
+}
+
+static int test_ntlm2_setup(void **state) {
+ return test_ntlm_setup_with_options(state,
+ CLI_CRED_NTLM2,
+ false);
+}
+
+static int test_ntlmv2_setup(void **state) {
+ return test_ntlm_setup_with_options(state,
+ CLI_CRED_NTLMv2_AUTH,
+ false);
+}
+
+static int test_ntlm_teardown(void **state)
+{
+ struct ntlm_state *ntlm_state
+ = talloc_get_type_abort(*state,
+ struct ntlm_state);
+ TALLOC_FREE(ntlm_state);
+ *state = NULL;
+ return 0;
+}
+
+static void test_ntlm_allowed(void **state)
+{
+ DATA_BLOB user_sess_key, lm_sess_key;
+ struct ntlm_state *ntlm_state
+ = talloc_get_type_abort(*state,
+ struct ntlm_state);
+ NTSTATUS status;
+ status = ntlm_password_check(ntlm_state,
+ false,
+ NTLM_AUTH_ON,
+ 0,
+ &ntlm_state->challenge,
+ &ntlm_state->lm,
+ &ntlm_state->ntlm,
+ ntlm_state->username,
+ ntlm_state->username,
+ ntlm_state->domain,
+ NULL,
+ ntlm_state->nt_hash,
+ &user_sess_key,
+ &lm_sess_key);
+
+ assert_int_equal(NT_STATUS_V(status), NT_STATUS_V(NT_STATUS_OK));
+}
+
+static void test_ntlm_allowed_lm_supplied(void **state)
+{
+ test_ntlm_allowed(state);
+}
+
+static void test_ntlm_disabled(void **state)
+{
+ DATA_BLOB user_sess_key, lm_sess_key;
+ struct ntlm_state *ntlm_state
+ = talloc_get_type_abort(*state,
+ struct ntlm_state);
+ NTSTATUS status;
+ status = ntlm_password_check(ntlm_state,
+ false,
+ NTLM_AUTH_DISABLED,
+ 0,
+ &ntlm_state->challenge,
+ &ntlm_state->lm,
+ &ntlm_state->ntlm,
+ ntlm_state->username,
+ ntlm_state->username,
+ ntlm_state->domain,
+ NULL,
+ ntlm_state->nt_hash,
+ &user_sess_key,
+ &lm_sess_key);
+
+ assert_int_equal(NT_STATUS_V(status), NT_STATUS_V(NT_STATUS_NTLM_BLOCKED));
+}
+
+static void test_ntlm2(void **state)
+{
+ DATA_BLOB user_sess_key, lm_sess_key;
+ struct ntlm_state *ntlm_state
+ = talloc_get_type_abort(*state,
+ struct ntlm_state);
+ NTSTATUS status;
+ status = ntlm_password_check(ntlm_state,
+ false,
+ NTLM_AUTH_ON,
+ 0,
+ &ntlm_state->challenge,
+ &ntlm_state->lm,
+ &ntlm_state->ntlm,
+ ntlm_state->username,
+ ntlm_state->username,
+ ntlm_state->domain,
+ NULL,
+ ntlm_state->nt_hash,
+ &user_sess_key,
+ &lm_sess_key);
+
+ /*
+ * NTLM2 session security (where the real challenge is the
+ * MD5(challenge, client-challenge) (in the first 8 bytes of
+ * the lm) isn't decoded by ntlm_password_check(), it must
+ * first be converted back into normal NTLM by the NTLMSSP
+ * layer
+ */
+ assert_int_equal(NT_STATUS_V(status),
+ NT_STATUS_V(NT_STATUS_WRONG_PASSWORD));
+}
+
+static void test_ntlm_mschapv2_only_allowed(void **state)
+{
+ DATA_BLOB user_sess_key, lm_sess_key;
+ struct ntlm_state *ntlm_state
+ = talloc_get_type_abort(*state,
+ struct ntlm_state);
+ NTSTATUS status;
+ status = ntlm_password_check(ntlm_state,
+ false,
+ NTLM_AUTH_MSCHAPv2_NTLMV2_ONLY,
+ MSV1_0_ALLOW_MSVCHAPV2,
+ &ntlm_state->challenge,
+ &ntlm_state->lm,
+ &ntlm_state->ntlm,
+ ntlm_state->username,
+ ntlm_state->username,
+ ntlm_state->domain,
+ NULL,
+ ntlm_state->nt_hash,
+ &user_sess_key,
+ &lm_sess_key);
+
+ assert_int_equal(NT_STATUS_V(status), NT_STATUS_V(NT_STATUS_OK));
+}
+
+static void test_ntlm_mschapv2_only_denied(void **state)
+{
+ DATA_BLOB user_sess_key, lm_sess_key;
+ struct ntlm_state *ntlm_state
+ = talloc_get_type_abort(*state,
+ struct ntlm_state);
+ NTSTATUS status;
+ status = ntlm_password_check(ntlm_state,
+ false,
+ NTLM_AUTH_MSCHAPv2_NTLMV2_ONLY,
+ 0,
+ &ntlm_state->challenge,
+ &ntlm_state->lm,
+ &ntlm_state->ntlm,
+ ntlm_state->username,
+ ntlm_state->username,
+ ntlm_state->domain,
+ NULL,
+ ntlm_state->nt_hash,
+ &user_sess_key,
+ &lm_sess_key);
+
+ assert_int_equal(NT_STATUS_V(status),
+ NT_STATUS_V(NT_STATUS_WRONG_PASSWORD));
+}
+
+static void test_ntlmv2_only_ntlmv2(void **state)
+{
+ DATA_BLOB user_sess_key, lm_sess_key;
+ struct ntlm_state *ntlm_state
+ = talloc_get_type_abort(*state,
+ struct ntlm_state);
+ NTSTATUS status;
+ status = ntlm_password_check(ntlm_state,
+ false,
+ NTLM_AUTH_NTLMV2_ONLY,
+ 0,
+ &ntlm_state->challenge,
+ &ntlm_state->lm,
+ &ntlm_state->ntlm,
+ ntlm_state->username,
+ ntlm_state->username,
+ ntlm_state->domain,
+ NULL,
+ ntlm_state->nt_hash,
+ &user_sess_key,
+ &lm_sess_key);
+
+ assert_int_equal(NT_STATUS_V(status), NT_STATUS_V(NT_STATUS_OK));
+}
+
+static void test_ntlmv2_only_ntlm(void **state)
+{
+ DATA_BLOB user_sess_key, lm_sess_key;
+ struct ntlm_state *ntlm_state
+ = talloc_get_type_abort(*state,
+ struct ntlm_state);
+ NTSTATUS status;
+ status = ntlm_password_check(ntlm_state,
+ false,
+ NTLM_AUTH_NTLMV2_ONLY,
+ 0,
+ &ntlm_state->challenge,
+ &ntlm_state->lm,
+ &ntlm_state->ntlm,
+ ntlm_state->username,
+ ntlm_state->username,
+ ntlm_state->domain,
+ NULL,
+ ntlm_state->nt_hash,
+ &user_sess_key,
+ &lm_sess_key);
+
+ assert_int_equal(NT_STATUS_V(status),
+ NT_STATUS_V(NT_STATUS_WRONG_PASSWORD));
+}
+
+static void test_ntlmv2_only_ntlm_and_lanman(void **state)
+{
+ test_ntlmv2_only_ntlm(state);
+}
+
+static void test_ntlmv2_only_ntlm_once(void **state)
+{
+ DATA_BLOB user_sess_key, lm_sess_key;
+ struct ntlm_state *ntlm_state
+ = talloc_get_type_abort(*state,
+ struct ntlm_state);
+ NTSTATUS status;
+ status = ntlm_password_check(ntlm_state,
+ false,
+ NTLM_AUTH_NTLMV2_ONLY,
+ 0,
+ &ntlm_state->challenge,
+ &data_blob_null,
+ &ntlm_state->ntlm,
+ ntlm_state->username,
+ ntlm_state->username,
+ ntlm_state->domain,
+ NULL,
+ ntlm_state->nt_hash,
+ &user_sess_key,
+ &lm_sess_key);
+
+ assert_int_equal(NT_STATUS_V(status),
+ NT_STATUS_V(NT_STATUS_WRONG_PASSWORD));
+}
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_ntlm_allowed,
+ test_ntlm_setup,
+ test_ntlm_teardown),
+ cmocka_unit_test_setup_teardown(test_ntlm_allowed_lm_supplied,
+ test_ntlm_and_lm_setup,
+ test_ntlm_teardown),
+ cmocka_unit_test_setup_teardown(test_ntlm_disabled,
+ test_ntlm_setup,
+ test_ntlm_teardown),
+ cmocka_unit_test_setup_teardown(test_ntlm2,
+ test_ntlm2_setup,
+ test_ntlm_teardown),
+ cmocka_unit_test_setup_teardown(test_ntlm_mschapv2_only_allowed,
+ test_ntlm_setup,
+ test_ntlm_teardown),
+ cmocka_unit_test_setup_teardown(test_ntlm_mschapv2_only_denied,
+ test_ntlm_setup,
+ test_ntlm_teardown),
+ cmocka_unit_test_setup_teardown(test_ntlmv2_only_ntlm,
+ test_ntlm_setup,
+ test_ntlm_teardown),
+ cmocka_unit_test_setup_teardown(test_ntlmv2_only_ntlm_and_lanman,
+ test_ntlm_and_lm_setup,
+ test_ntlm_teardown),
+ cmocka_unit_test_setup_teardown(test_ntlmv2_only_ntlm_once,
+ test_ntlm_setup,
+ test_ntlm_teardown),
+ cmocka_unit_test_setup_teardown(test_ntlmv2_only_ntlmv2,
+ test_ntlmv2_setup,
+ test_ntlm_teardown)
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/libcli/auth/tests/test_encode_decode.c b/libcli/auth/tests/test_encode_decode.c
new file mode 100644
index 0000000..4683edf
--- /dev/null
+++ b/libcli/auth/tests/test_encode_decode.c
@@ -0,0 +1,162 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2022 Andreas Schneider <asn@samba.org>
+ *
+ * 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 <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "libcli/auth/smbencrypt.c"
+
+/* The following hexdumps are from a Windows Server 2022 time trace */
+static const uint8_t plaintext_data[] = {
+ 0x14, 0x00, 0x50, 0x00, 0x61, 0x00, 0x24, 0x00,
+ 0x24, 0x00, 0x77, 0x00, 0x30, 0x00, 0x72, 0x00,
+ 0x64, 0x00, 0x40, 0x00, 0x32, 0x00, 0xc2, 0x34,
+ 0x7d, 0x21, 0x79, 0x05, 0xef, 0x88, 0xd7, 0x11,
+ 0xec, 0xe2, 0xce, 0xb5, 0xd4, 0x4d, 0x64, 0x2d,
+ 0x15, 0x79, 0x01, 0x39, 0xb8, 0xb9, 0x89, 0x5c,
+ 0x4e, 0x71, 0xbd, 0xf0, 0x14, 0x0c, 0x87, 0x72,
+ 0xa5, 0xfa, 0x90, 0xbe, 0x62, 0x55, 0xad, 0x7f,
+ 0xe9, 0x7f, 0x0d, 0x20, 0x19, 0x3a, 0x76, 0xbe,
+ 0xb2, 0x14, 0x6d, 0x5b, 0x25, 0x1c, 0x67, 0x3a,
+ 0x23, 0x45, 0x1f, 0x7e, 0x36, 0xa0, 0x95, 0xb7,
+ 0xa7, 0xb1, 0x33, 0xe1, 0xc4, 0xb6, 0xe6, 0x2d,
+ 0xd8, 0x2f, 0xe7, 0xdf, 0x01, 0xe8, 0xba, 0x02,
+ 0x54, 0x36, 0xe9, 0xb6, 0x5e, 0x00, 0x52, 0x9e,
+ 0x64, 0x00, 0xcb, 0x3c, 0x6d, 0x05, 0x43, 0x7d,
+ 0x01, 0x9c, 0x22, 0x18, 0x92, 0xe7, 0xa3, 0x55,
+ 0x65, 0x6d, 0x2e, 0xa3, 0x53, 0x6e, 0xc0, 0x67,
+ 0x26, 0xac, 0xaa, 0x98, 0xa4, 0xcb, 0xb4, 0x49,
+ 0x13, 0x60, 0xd4, 0x33, 0x2c, 0x77, 0x58, 0x5e,
+ 0x50, 0x45, 0xaa, 0x1e, 0x05, 0x15, 0x18, 0x59,
+ 0x55, 0xca, 0x14, 0x37, 0x31, 0xac, 0x63, 0xfc,
+ 0x63, 0xa8, 0x2a, 0xa9, 0x99, 0xec, 0x49, 0x87,
+ 0x64, 0x1d, 0x4e, 0xdd, 0xa3, 0xd0, 0xdc, 0x08,
+ 0x00, 0x17, 0xf4, 0x2f, 0x9c, 0x4a, 0x17, 0xc7,
+ 0xbd, 0x30, 0xb7, 0x0e, 0x81, 0xe4, 0xd5, 0x94,
+ 0x31, 0xff, 0xd6, 0xcc, 0xc6, 0xbb, 0x39, 0xcd,
+ 0x72, 0xfe, 0xa6, 0x3d, 0x0d, 0x88, 0x68, 0x40,
+ 0xf8, 0x51, 0x2b, 0xe6, 0xc9, 0xaa, 0x84, 0xf3,
+ 0xf4, 0x6e, 0x55, 0x37, 0xbf, 0x5d, 0x87, 0xce,
+ 0xa6, 0x80, 0x4f, 0x8f, 0x8f, 0x7b, 0xe8, 0x30,
+ 0xc3, 0x2e, 0x24, 0xc7, 0x3e, 0xf1, 0x9f, 0xa6,
+ 0x77, 0xca, 0x04, 0xbe, 0xb5, 0xe1, 0x40, 0x59,
+ 0x43, 0xc5, 0x30, 0xc8, 0xe7, 0xbf, 0xab, 0xfa,
+ 0x86, 0x62, 0xd9, 0x3a, 0x8e, 0xa9, 0x34, 0x73,
+ 0x20, 0x7b, 0x61, 0x1b, 0x0e, 0xca, 0x98, 0xec,
+ 0xa1, 0xc1, 0x78, 0xa9, 0xa7, 0x6c, 0x8c, 0xe3,
+ 0x21, 0x7d, 0xb9, 0x90, 0xe2, 0x73, 0x1a, 0x99,
+ 0x1d, 0x44, 0xa8, 0xd5, 0x7f, 0x0a, 0x59, 0x47,
+ 0xd0, 0xf5, 0x6c, 0x14, 0xff, 0x4a, 0x29, 0x20,
+ 0xb5, 0xfc, 0xe9, 0xf0, 0xa5, 0x35, 0x9e, 0x1c,
+ 0xa1, 0x4c, 0xec, 0xb5, 0x7d, 0x2d, 0x27, 0xff,
+ 0x7a, 0x42, 0x18, 0xb8, 0x53, 0x4e, 0xfb, 0xec,
+ 0xb1, 0xc1, 0x65, 0x2d, 0xa4, 0x69, 0x85, 0x56,
+ 0x61, 0x6d, 0x21, 0x66, 0x88, 0x31, 0xdf, 0xba,
+ 0x28, 0xc6, 0x9a, 0xf8, 0xb7, 0xf6, 0x2a, 0x43,
+ 0xba, 0x9b, 0x84, 0x14, 0xce, 0xa9, 0xc9, 0xf5,
+ 0x85, 0x6f, 0x31, 0x89, 0x8d, 0xfc, 0x25, 0x2e,
+ 0x98, 0x25, 0x5a, 0x03, 0xf0, 0xb8, 0x5d, 0x4a,
+ 0xd4, 0x4c, 0xc8, 0x62, 0x4e, 0xeb, 0x07, 0xc8,
+ 0x5c, 0x9e, 0x63, 0x30, 0xfe, 0x9f, 0x0f, 0x96,
+ 0xd0, 0xd7, 0x70, 0xad, 0xcd, 0x84, 0xbc, 0x1e,
+ 0x48, 0xa0, 0x20, 0x14, 0x10, 0xa4, 0xb1, 0x5b,
+ 0x05, 0x36, 0x9a, 0x6d, 0xb0, 0x10, 0x98, 0xbd,
+ 0x8d, 0xa2, 0xd1, 0xb2, 0xfa, 0x23, 0x37, 0xeb,
+ 0xb0, 0x04, 0x53, 0xcb, 0xa1, 0xa9, 0xc4, 0x88,
+ 0xdd, 0xf9, 0x80, 0xf5, 0xa9, 0xcd, 0x7b, 0xf8,
+ 0x77, 0x0b, 0x19, 0x84, 0x4c, 0xef, 0x2c, 0x14,
+ 0xa1, 0xdc, 0x9f, 0x2f, 0x41, 0xd0, 0xd0, 0x33,
+ 0x29, 0x8a, 0xb9, 0x39, 0x7e, 0xc9, 0x7f, 0xe7,
+ 0x63, 0x64, 0xa4, 0x7b, 0x4a, 0x6a, 0x33, 0xa7,
+ 0xaa, 0xf6, 0xca, 0x98, 0xc4, 0x9b, 0x62, 0x5b,
+ 0xcd, 0x53, 0x82, 0xbf, 0xf0, 0x0b, 0x9c, 0xe7,
+ 0xb2, 0x44, 0x1b, 0x88, 0x71, 0x61, 0xa1, 0x36,
+ 0x9e, 0x7a, 0x0a, 0x3c, 0x20, 0xd8, 0xff, 0xa1,
+ 0x23, 0x66
+};
+
+static void torture_encode_pwd_buffer514_from_str(void **state)
+{
+ uint8_t data[514] = {0};
+ bool ok;
+
+ ok = encode_pwd_buffer514_from_str(data, "Pa$$w0rd@2", STR_UNICODE);
+ assert_true(ok);
+
+ /* We can only compare the first 22 bytes as the rest is random data */
+ assert_memory_equal(data, plaintext_data, 22);
+ assert_memory_not_equal(data + 22,
+ plaintext_data + 22,
+ sizeof(plaintext_data) - 22);
+}
+
+static void torture_extract_pwd_blob_from_buffer514(void **state)
+{
+ DATA_BLOB new_password = {
+ .length = 0,
+ };
+ bool ok;
+
+ ok = extract_pwd_blob_from_buffer514(NULL, plaintext_data, &new_password);
+ assert_true(ok);
+ assert_int_equal(new_password.length, 20);
+ assert_memory_equal(new_password.data,
+ plaintext_data + 2,
+ new_password.length);
+ data_blob_free(&new_password);
+}
+
+static void torture_decode_pwd_string_from_buffer514(void **state)
+{
+ DATA_BLOB decoded_password = {
+ .length = 0,
+ };
+ bool ok;
+
+ ok = decode_pwd_string_from_buffer514(NULL,
+ plaintext_data,
+ CH_UTF16,
+ &decoded_password);
+ assert_true(ok);
+ assert_memory_equal(decoded_password.data, "Pa$$w0rd@2", decoded_password.length);
+ data_blob_free(&decoded_password);
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(torture_encode_pwd_buffer514_from_str),
+ cmocka_unit_test(torture_extract_pwd_blob_from_buffer514),
+ cmocka_unit_test(torture_decode_pwd_string_from_buffer514),
+ };
+
+ if (argc == 2) {
+ cmocka_set_test_filter(argv[1]);
+ }
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ rc = cmocka_run_group_tests(tests, NULL, NULL);
+
+ return rc;
+}
diff --git a/libcli/auth/tests/test_gnutls.c b/libcli/auth/tests/test_gnutls.c
new file mode 100644
index 0000000..860f8b3
--- /dev/null
+++ b/libcli/auth/tests/test_gnutls.c
@@ -0,0 +1,524 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2019 Guenther Deschner <gd@samba.org>
+ *
+ * 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 <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "includes.h"
+#include "libcli/auth/libcli_auth.h"
+
+#include "lib/crypto/gnutls_helpers.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+static void torture_gnutls_aes_128_cfb_flags(void **state,
+ const DATA_BLOB session_key,
+ const DATA_BLOB seq_num_initial,
+ const DATA_BLOB confounder_initial,
+ const DATA_BLOB confounder_expected,
+ const DATA_BLOB clear_initial,
+ const DATA_BLOB crypt_expected)
+{
+ uint8_t confounder[8];
+ DATA_BLOB io;
+ gnutls_cipher_hd_t cipher_hnd = NULL;
+ uint8_t sess_kf0[16] = {0};
+ gnutls_datum_t key = {
+ .data = sess_kf0,
+ .size = sizeof(sess_kf0),
+ };
+ uint32_t iv_size =
+ gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8);
+ uint8_t _iv[iv_size];
+ gnutls_datum_t iv = {
+ .data = _iv,
+ .size = iv_size,
+ };
+ uint32_t i;
+ int rc;
+
+ assert_int_equal(session_key.length, 16);
+ assert_int_equal(seq_num_initial.length, 8);
+ assert_int_equal(confounder_initial.length, 8);
+ assert_int_equal(confounder_expected.length, 8);
+ assert_int_equal(clear_initial.length, crypt_expected.length);
+
+ DEBUG(0,("checking buffer size: %d\n", (int)clear_initial.length));
+
+ io = data_blob_dup_talloc(NULL, clear_initial);
+ assert_non_null(io.data);
+ assert_int_equal(io.length, clear_initial.length);
+
+ memcpy(confounder, confounder_initial.data, 8);
+
+ DEBUG(0,("confounder before crypt:\n"));
+ dump_data(0, confounder, 8);
+ DEBUG(0,("initial seq num:\n"));
+ dump_data(0, seq_num_initial.data, 8);
+ DEBUG(0,("io data before crypt:\n"));
+ dump_data(0, io.data, io.length);
+
+ for (i = 0; i < key.size; i++) {
+ key.data[i] = session_key.data[i] ^ 0xf0;
+ }
+
+ ZERO_ARRAY(_iv);
+
+ memcpy(iv.data + 0, seq_num_initial.data, 8);
+ memcpy(iv.data + 8, seq_num_initial.data, 8);
+
+ rc = gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_AES_128_CFB8,
+ &key,
+ &iv);
+ assert_int_equal(rc, 0);
+
+ rc = gnutls_cipher_encrypt(cipher_hnd,
+ confounder,
+ 8);
+ assert_int_equal(rc, 0);
+
+ rc = gnutls_cipher_encrypt(cipher_hnd,
+ io.data,
+ io.length);
+ assert_int_equal(rc, 0);
+
+ DEBUG(0,("confounder after crypt:\n"));
+ dump_data(0, confounder, 8);
+ DEBUG(0,("initial seq num:\n"));
+ dump_data(0, seq_num_initial.data, 8);
+ DEBUG(0,("io data after crypt:\n"));
+ dump_data(0, io.data, io.length);
+ assert_memory_equal(io.data, crypt_expected.data, crypt_expected.length);
+ assert_memory_equal(confounder, confounder_expected.data, confounder_expected.length);
+
+ rc = gnutls_cipher_decrypt(cipher_hnd,
+ confounder,
+ 8);
+ assert_int_equal(rc, 0);
+
+ rc = gnutls_cipher_decrypt(cipher_hnd,
+ io.data,
+ io.length);
+ assert_int_equal(rc, 0);
+ gnutls_cipher_deinit(cipher_hnd);
+
+ DEBUG(0,("confounder after decrypt:\n"));
+ dump_data(0, confounder, 8);
+ DEBUG(0,("initial seq num:\n"));
+ dump_data(0, seq_num_initial.data, 8);
+ DEBUG(0,("io data after decrypt:\n"));
+ dump_data(0, io.data, io.length);
+ assert_memory_equal(io.data, clear_initial.data, clear_initial.length);
+ assert_memory_equal(confounder, confounder_initial.data, confounder_initial.length);
+}
+
+static void torture_gnutls_aes_128_cfb(void **state)
+{
+ const uint8_t _session_key[16] = {
+ 0x8E, 0xE8, 0x27, 0x85, 0x83, 0x41, 0x3C, 0x8D,
+ 0xC9, 0x54, 0x70, 0x75, 0x8E, 0xC9, 0x69, 0x91
+ };
+ const DATA_BLOB session_key = data_blob_const(_session_key, 16);
+ const uint8_t _seq_num_initial[8] = {
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00
+ };
+ const DATA_BLOB seq_num_initial =
+ data_blob_const(_seq_num_initial, 8);
+ const uint8_t _confounder_initial[8] = {
+ 0x6E, 0x09, 0x25, 0x94, 0x01, 0xA0, 0x09, 0x31
+ };
+ const DATA_BLOB confounder_initial =
+ data_blob_const(_confounder_initial, 8);
+ const uint8_t _confounder_expected[8] = {
+ 0xCA, 0xFB, 0xAC, 0xFB, 0xA8, 0x26, 0x75, 0x2A
+ };
+ const DATA_BLOB confounder_expected =
+ data_blob_const(_confounder_expected, 8);
+ const uint8_t _clear_initial[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x8A, 0xE3, 0x13, 0x71, 0x02, 0xF4, 0x36, 0x71,
+ 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x40, 0x28, 0x00, 0x78, 0x57, 0x34, 0x12,
+ 0x34, 0x12, 0xCD, 0xAB, 0xEF, 0x00, 0x01, 0x23,
+ 0x45, 0x67, 0x89, 0xAB, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x5D, 0x88, 0x8A, 0xEB, 0x1C, 0xC9, 0x11,
+ 0x9F, 0xE8, 0x08, 0x00, 0x2B, 0x10, 0x48, 0x60,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ const DATA_BLOB clear_initial = data_blob_const(_clear_initial,
+ sizeof(_clear_initial));
+ const uint8_t crypt_buffer[] = {
+ 0xE2, 0xE5, 0xE3, 0x26, 0x45, 0xFB, 0xFC, 0xF3,
+ 0x9C, 0x14, 0xDD, 0xE1, 0x39, 0x23, 0xE0, 0x55,
+ 0xED, 0x8F, 0xF4, 0x92, 0xA1, 0xBD, 0xDC, 0x40,
+ 0x58, 0x6F, 0xD2, 0x5B, 0xF9, 0xC9, 0xA3, 0x87,
+ 0x46, 0x4B, 0x7F, 0xB2, 0x03, 0xD2, 0x35, 0x22,
+ 0x3E, 0x70, 0x9F, 0x1E, 0x3F, 0x1F, 0xDB, 0x7D,
+ 0x79, 0x88, 0x5A, 0x3D, 0xD3, 0x40, 0x1E, 0x69,
+ 0xD7, 0xE2, 0x1D, 0x5A, 0xE9, 0x3B, 0xE1, 0xE2,
+ 0x98, 0xFD, 0xCB, 0x3A, 0xF7, 0xB5, 0x1C, 0xF8,
+ 0xCA, 0x02, 0x00, 0x99, 0x9F, 0x0C, 0x01, 0xE6,
+ 0xD2, 0x00, 0xAF, 0xE0, 0x51, 0x88, 0x62, 0x50,
+ 0xB7, 0xE8, 0x6D, 0x63, 0x4B, 0x97, 0x05, 0xC1,
+ 0xD4, 0x83, 0x96, 0x29, 0x80, 0xAE, 0xD8, 0xA2,
+ 0xED, 0xC9, 0x5D, 0x0D, 0x29, 0xFF, 0x2C, 0x23,
+ 0x02, 0xFA, 0x3B, 0xEE, 0xE8, 0xBA, 0x06, 0x01,
+ 0x95, 0xDF, 0x80, 0x76, 0x0B, 0x17, 0x0E, 0xD8
+ };
+ const DATA_BLOB crypt_expected = data_blob_const(crypt_buffer,
+ sizeof(crypt_buffer));
+ int buffer_sizes[] = {
+ 0, 1, 3, 7, 8, 9, 15, 16, 17
+ };
+ int i;
+
+ torture_gnutls_aes_128_cfb_flags(state,
+ session_key,
+ seq_num_initial,
+ confounder_initial,
+ confounder_expected,
+ clear_initial,
+ crypt_expected);
+
+ /* repeat the test for varying buffer sizes */
+
+ for (i = 0; i < ARRAY_SIZE(buffer_sizes); i++) {
+ DATA_BLOB clear_initial_trunc =
+ data_blob_const(clear_initial.data, buffer_sizes[i]);
+ DATA_BLOB crypt_expected_trunc =
+ data_blob_const(crypt_expected.data, buffer_sizes[i]);
+ torture_gnutls_aes_128_cfb_flags(state,
+ session_key,
+ seq_num_initial,
+ confounder_initial,
+ confounder_expected,
+ clear_initial_trunc,
+ crypt_expected_trunc);
+ }
+}
+
+static void torture_gnutls_des_crypt56(void **state)
+{
+ static const uint8_t key[7] = {
+ 0x69, 0x88, 0x96, 0x8E, 0xB5, 0x3A, 0x24
+ };
+ static const uint8_t clear[8] = {
+ 0x3F, 0x49, 0x5B, 0x20, 0xA7, 0x84, 0xC2, 0x34
+ };
+ static const uint8_t crypt_expected[8] = {
+ 0x54, 0x86, 0xCF, 0x51, 0x49, 0x3A, 0x53, 0x5B
+ };
+
+ uint8_t crypt[8];
+ uint8_t decrypt[8];
+ int rc;
+
+ rc = des_crypt56_gnutls(crypt, clear, key, SAMBA_GNUTLS_ENCRYPT);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(crypt, crypt_expected, 8);
+
+ rc = des_crypt56_gnutls(decrypt, crypt, key, SAMBA_GNUTLS_DECRYPT);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(decrypt, clear, 8);
+}
+
+static void torture_gnutls_E_P16(void **state)
+{
+ static const uint8_t key[14] = {
+ 0x98, 0xFD, 0xCB, 0x3A, 0xF7, 0xB5, 0x1C, 0xF8,
+ 0x69, 0x88, 0x96, 0x8E, 0xB5, 0x3A
+ };
+ uint8_t buffer[16] = {
+ 0x9C, 0x14, 0xDD, 0xE1, 0x39, 0x23, 0xE0, 0x55,
+ 0x3F, 0x49, 0x5B, 0x20, 0xA7, 0x84, 0xC2, 0x34
+ };
+ static const uint8_t crypt_expected[16] = {
+ 0x41, 0x4A, 0x7B, 0xEA, 0xAB, 0xBB, 0x95, 0xCE,
+ 0x1D, 0xEA, 0xD9, 0xFF, 0xB0, 0xA9, 0xA4, 0x05
+ };
+
+ int rc;
+
+ rc = E_P16(key, buffer);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(buffer, crypt_expected, 16);
+}
+
+static void torture_gnutls_E_P24(void **state)
+{
+ static const uint8_t key[21] = {
+ 0xFB, 0x67, 0x99, 0xA4, 0x83, 0xF3, 0xD4, 0xED,
+ 0x98, 0xFD, 0xCB, 0x3A, 0xF7, 0xB5, 0x1C, 0xF8,
+ 0x69, 0x88, 0x96, 0x8E, 0x3A
+ };
+ const uint8_t c8[8] = {
+ 0x44, 0xFB, 0xAC, 0xFB, 0x83, 0xB6, 0x75, 0x2A
+ };
+ static const uint8_t crypt_expected[24] = {
+ 0x1A, 0x5E, 0x11, 0xA1, 0x59, 0xA9, 0x6B, 0x4E,
+ 0x12, 0x5D, 0x81, 0x75, 0xA6, 0x62, 0x15, 0x6D,
+ 0x5D, 0x20, 0x25, 0xC1, 0xA3, 0x92, 0xB3, 0x28
+ };
+
+ uint8_t crypt[24];
+ int rc;
+
+ rc = E_P24(key, c8, crypt);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(crypt, crypt_expected, 24);
+}
+
+static void torture_gnutls_SMBOWFencrypt(void **state)
+{
+ static const uint8_t password[16] = {
+ 'M', 'y', 'p', 'a', 's', 's', 'w', 'o',
+ 'r', 'd', 'i', 's', '1', '1', '1', '1'
+ };
+ const uint8_t c8[8] = {
+ 0x79, 0x88, 0x5A, 0x3D, 0xD3, 0x40, 0x1E, 0x69
+ };
+ static const uint8_t crypt_expected[24] = {
+ 0x3F, 0xE3, 0x53, 0x75, 0x81, 0xB4, 0xF0, 0xE7,
+ 0x0C, 0xDE, 0xCD, 0xAE, 0x39, 0x1F, 0x14, 0xB4,
+ 0xA4, 0x2B, 0x3E, 0x39, 0x16, 0xFD, 0x1D, 0x62
+ };
+
+ uint8_t crypt[24];
+ int rc;
+
+ rc = SMBOWFencrypt(password, c8, crypt);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(crypt, crypt_expected, 24);
+}
+
+static void torture_gnutls_E_old_pw_hash(void **state)
+{
+ static uint8_t key[14] = {
+ 0x98, 0xFD, 0xCB, 0x3A, 0xF7, 0xB5, 0x1C, 0xF8,
+ 0x69, 0x88, 0x96, 0x8E, 0xB5, 0x3A
+ };
+ uint8_t clear[16] = {
+ 0x9C, 0x14, 0xDD, 0xE1, 0x39, 0x23, 0xE0, 0x55,
+ 0x3F, 0x49, 0x5B, 0x20, 0xA7, 0x84, 0xC2, 0x34
+ };
+ static const uint8_t crypt_expected[16] = {
+ 0x6A, 0xC7, 0x08, 0xCA, 0x2A, 0xC1, 0xAA, 0x64,
+ 0x37, 0xEF, 0xBE, 0x58, 0xC2, 0x59, 0x33, 0xEC
+ };
+ uint8_t crypt[16];
+ int rc;
+
+ rc = E_old_pw_hash(key, clear, crypt);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(crypt, crypt_expected, 16);
+}
+
+static void torture_gnutls_des_crypt128(void **state)
+{
+ static uint8_t key[16] = {
+ 0x98, 0xFD, 0xCB, 0x3A, 0xF7, 0xB5, 0x1C, 0xF8,
+ 0xA9, 0x69, 0x88, 0x96, 0x8E, 0xB5, 0x3A, 0x24
+ };
+ static const uint8_t clear[8] = {
+ 0x3F, 0x49, 0x5B, 0x20, 0xA7, 0x84, 0xC2, 0x34
+ };
+ static const uint8_t crypt_expected[8] = {
+ 0x4C, 0xB4, 0x4B, 0xD3, 0xC8, 0xC1, 0xA5, 0x50
+ };
+
+ uint8_t crypt[8];
+ int rc;
+
+ rc = des_crypt128(crypt, clear, key);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(crypt, crypt_expected, 8);
+}
+
+static void torture_gnutls_des_crypt112(void **state)
+{
+ static uint8_t key[14] = {
+ 0x98, 0xFD, 0xCB, 0x3A, 0xF7, 0xB5, 0x1C, 0xF8,
+ 0x88, 0x96, 0x8E, 0xB5, 0x3A, 0x24
+ };
+ static const uint8_t clear[8] = {
+ 0x2F, 0x49, 0x5B, 0x20, 0xD7, 0x84, 0xC2, 0x34
+ };
+ static const uint8_t crypt_expected[8] = {
+ 0x87, 0x35, 0xFA, 0xA4, 0x5D, 0x7A, 0xA5, 0x05
+ };
+
+ uint8_t crypt[8];
+ uint8_t decrypt[8];
+ int rc;
+
+ rc = des_crypt112(crypt, clear, key, SAMBA_GNUTLS_ENCRYPT);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(crypt, crypt_expected, 8);
+
+ rc = des_crypt112(decrypt, crypt, key, SAMBA_GNUTLS_DECRYPT);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(decrypt, clear, 8);
+}
+
+static void torture_gnutls_des_crypt112_16(void **state)
+{
+ static uint8_t key[14] = {
+ 0x1E, 0x38, 0x27, 0x5B, 0x3B, 0xB8, 0x67, 0xEB,
+ 0x88, 0x96, 0x8E, 0xB5, 0x3A, 0x24
+ };
+ static const uint8_t clear[16] = {
+ 0x02, 0xFA, 0x3B, 0xEE, 0xE8, 0xBA, 0x06, 0x01,
+ 0xFB, 0x67, 0x99, 0xA4, 0x83, 0xF3, 0xD4, 0xED
+ };
+ static const uint8_t crypt_expected[16] = {
+ 0x3C, 0x10, 0x37, 0x67, 0x96, 0x95, 0xF7, 0x96,
+ 0xAA, 0x03, 0xB9, 0xEA, 0xD6, 0xB3, 0xC3, 0x2D
+ };
+
+ uint8_t crypt[16];
+ uint8_t decrypt[16];
+ int rc;
+
+ rc = des_crypt112_16(crypt, clear, key, SAMBA_GNUTLS_ENCRYPT);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(crypt, crypt_expected, 16);
+
+ rc = des_crypt112_16(decrypt, crypt, key, SAMBA_GNUTLS_DECRYPT);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(decrypt, clear, 16);
+}
+
+static void torture_gnutls_sam_rid_crypt(void **state)
+{
+ static const uint8_t clear[16] = {
+ 0x02, 0xFA, 0x3B, 0xEE, 0xE8, 0xBA, 0x06, 0x01,
+ 0x3F, 0x49, 0x5B, 0x20, 0xA7, 0x84, 0xC2, 0x34
+ };
+ static const uint8_t crypt_expected[16] = {
+ 0x1E, 0x38, 0x27, 0x5B, 0x3B, 0xB8, 0x67, 0xEB,
+ 0xFB, 0x67, 0x99, 0xA4, 0x83, 0xF3, 0xD4, 0xED
+ };
+
+ uint8_t crypt[16];
+ uint8_t decrypt[16];
+ int rid = 500;
+ int rc;
+
+ rc = sam_rid_crypt(rid, clear, crypt, SAMBA_GNUTLS_ENCRYPT);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(crypt, crypt_expected, 16);
+
+ rc = sam_rid_crypt(rid, crypt, decrypt, SAMBA_GNUTLS_DECRYPT);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(decrypt, clear, 16);
+}
+
+static void torture_gnutls_SMBsesskeygen_lm_sess_key(void **state)
+{
+ static const uint8_t lm_hash[16] = {
+ 0xFB, 0x67, 0x99, 0xA4, 0x83, 0xF3, 0xD4, 0xED,
+ 0x9C, 0x14, 0xDD, 0xE1, 0x39, 0x23, 0xE0, 0x55
+ };
+ static const uint8_t lm_resp[24] = {
+ 0x02, 0xFA, 0x3B, 0xEE, 0xE8, 0xBA, 0x06, 0x01,
+ 0x02, 0xFA, 0x3B, 0xEE, 0xE8, 0xBA, 0x06, 0x01,
+ 0x1E, 0x38, 0x27, 0x5B, 0x3B, 0xB8, 0x67, 0xEB
+ };
+ static const uint8_t crypt_expected[16] = {
+ 0x52, 0x8D, 0xB2, 0xD3, 0x89, 0x83, 0xFB, 0x9C,
+ 0x96, 0x45, 0x15, 0x4B, 0xC3, 0xF5, 0xD5, 0x7F
+ };
+
+ uint8_t crypt_sess_key[16];
+ NTSTATUS status;
+
+ status = SMBsesskeygen_lm_sess_key(lm_hash, lm_resp, crypt_sess_key);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_memory_equal(crypt_sess_key, crypt_expected, 16);
+}
+
+static void torture_gnutls_sess_crypt_blob(void **state)
+{
+ static uint8_t _key[16] = {
+ 0x1E, 0x38, 0x27, 0x5B, 0x3B, 0xB8, 0x67, 0xEB,
+ 0xFA, 0xEE, 0xE8, 0xBA, 0x06, 0x01, 0x2D, 0x95
+ };
+ DATA_BLOB key = data_blob_const(_key, 16);
+ static const uint8_t _clear[24] = {
+ 0x98, 0xFD, 0xCB, 0x3A, 0xF7, 0xB5, 0x1C, 0xF8,
+ 0x02, 0xFA, 0x3B, 0xEE, 0xE8, 0xBA, 0x06, 0x01,
+ 0x3F, 0x49, 0x5B, 0x20, 0xA7, 0x84, 0xC2, 0x34
+ };
+ DATA_BLOB clear = data_blob_const(_clear, 24);
+ static const uint8_t crypt_expected[24] = {
+ 0x2B, 0xDD, 0x3B, 0xFA, 0x48, 0xC9, 0x63, 0x56,
+ 0xAE, 0x8B, 0x3E, 0xCF, 0xEF, 0xDF, 0x7A, 0x42,
+ 0xB3, 0x00, 0x71, 0x7F, 0x5D, 0x1D, 0xE4, 0x70
+ };
+ DATA_BLOB crypt = data_blob(NULL, 24);
+ DATA_BLOB decrypt = data_blob(NULL, 24);
+ int rc;
+
+ rc = sess_crypt_blob(&crypt, &clear, &key, SAMBA_GNUTLS_ENCRYPT);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(crypt.data, crypt_expected, 24);
+
+ rc = sess_crypt_blob(&decrypt, &crypt, &key, SAMBA_GNUTLS_DECRYPT);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(decrypt.data, clear.data, 24);
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(torture_gnutls_aes_128_cfb),
+ cmocka_unit_test(torture_gnutls_des_crypt56),
+ cmocka_unit_test(torture_gnutls_E_P16),
+ cmocka_unit_test(torture_gnutls_E_P24),
+ cmocka_unit_test(torture_gnutls_SMBOWFencrypt),
+ cmocka_unit_test(torture_gnutls_E_old_pw_hash),
+ cmocka_unit_test(torture_gnutls_des_crypt128),
+ cmocka_unit_test(torture_gnutls_des_crypt112),
+ cmocka_unit_test(torture_gnutls_des_crypt112_16),
+ cmocka_unit_test(torture_gnutls_sam_rid_crypt),
+ cmocka_unit_test(torture_gnutls_SMBsesskeygen_lm_sess_key),
+ cmocka_unit_test(torture_gnutls_sess_crypt_blob),
+ };
+
+ if (argc == 2) {
+ cmocka_set_test_filter(argv[1]);
+ }
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ rc = cmocka_run_group_tests(tests, NULL, NULL);
+
+ return rc;
+}
diff --git a/libcli/auth/tests/test_rc4_passwd_buffer.c b/libcli/auth/tests/test_rc4_passwd_buffer.c
new file mode 100644
index 0000000..6d97ac6
--- /dev/null
+++ b/libcli/auth/tests/test_rc4_passwd_buffer.c
@@ -0,0 +1,336 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2018-2019 Andreas Schneider <asn@samba.org>
+ *
+ * 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 <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "includes.h"
+#include "libcli/auth/libcli_auth.h"
+#include "rpc_client/init_samr.h"
+
+#define PASSWORD "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+
+static const uint8_t encrypted_test_blob[] = {
+ 0x37, 0x8e, 0x1d, 0xd5, 0xd3, 0x9f, 0xca, 0x8e,
+ 0x2f, 0x2d, 0xee, 0xc3, 0xb5, 0x50, 0xcd, 0x4e,
+ 0xc9, 0x08, 0x04, 0x68, 0x32, 0xc3, 0xac, 0x8e,
+ 0x53, 0x69, 0xd6, 0xb7, 0x56, 0xcc, 0xc0, 0xbe,
+ 0x4e, 0x96, 0xa7, 0x74, 0xe9, 0xaa, 0x10, 0x3d,
+ 0xd5, 0x8c, 0xaa, 0x12, 0x56, 0xb6, 0xf1, 0x85,
+ 0x21, 0xfa, 0xe9, 0xa1, 0x76, 0xe6, 0xa5, 0x33,
+ 0x33, 0x2f, 0x47, 0x29, 0xd6, 0xbd, 0xde, 0x64,
+ 0x4d, 0x15, 0x3e, 0x6a, 0x11, 0x9b, 0x52, 0xbf,
+ 0x7e, 0x3a, 0xeb, 0x1c, 0x55, 0xd1, 0xb2, 0xa4,
+ 0x35, 0x03, 0x6c, 0x39, 0x61, 0x28, 0x98, 0xc3,
+ 0x2d, 0xd4, 0x70, 0x69, 0x8b, 0x83, 0xe9, 0x62,
+ 0xbe, 0xd8, 0x72, 0x4e, 0xdf, 0xd4, 0xe9, 0xe3,
+ 0x46, 0x2a, 0xf9, 0x3c, 0x0f, 0x41, 0x62, 0xe1,
+ 0x43, 0xf0, 0x91, 0xbe, 0x72, 0xa0, 0xc9, 0x08,
+ 0x73, 0x20, 0x1f, 0x0d, 0x68, 0x2e, 0x32, 0xa1,
+ 0xb8, 0x9b, 0x08, 0xa1, 0xb4, 0x81, 0x6b, 0xf1,
+ 0xde, 0x0c, 0x28, 0x34, 0xe2, 0x65, 0x62, 0x54,
+ 0xeb, 0xc0, 0x71, 0x14, 0xad, 0x36, 0x43, 0x0e,
+ 0x92, 0x4d, 0x11, 0xe8, 0xdd, 0x2d, 0x5f, 0x05,
+ 0xff, 0x07, 0xda, 0x81, 0x4e, 0x27, 0x42, 0xa8,
+ 0xa9, 0x64, 0x4c, 0x74, 0xc8, 0x05, 0xbb, 0x83,
+ 0x5a, 0xd9, 0x90, 0x3e, 0x0d, 0x9d, 0xe5, 0x2f,
+ 0x08, 0xf9, 0x1b, 0xbd, 0x26, 0xc3, 0x0d, 0xac,
+ 0x43, 0xd5, 0x17, 0xf2, 0x61, 0xf5, 0x74, 0x9b,
+ 0xf3, 0x5b, 0x5f, 0xe1, 0x8a, 0xa6, 0xfd, 0xdf,
+ 0xff, 0xb5, 0x8b, 0xf1, 0x26, 0xf7, 0xe0, 0xa7,
+ 0x4f, 0x5b, 0xb8, 0x6d, 0xeb, 0xf6, 0x52, 0x68,
+ 0x8d, 0xa3, 0xd4, 0x7f, 0x56, 0x43, 0xaa, 0xec,
+ 0x58, 0x47, 0x03, 0xee, 0x9b, 0x59, 0xd9, 0x78,
+ 0x9a, 0xfb, 0x9e, 0xe9, 0xa6, 0x61, 0x4e, 0x6d,
+ 0x92, 0x35, 0xd3, 0x37, 0x6e, 0xf2, 0x34, 0x39,
+ 0xd4, 0xd2, 0xeb, 0xcf, 0x1c, 0x10, 0xb3, 0x2b,
+ 0x3e, 0x07, 0x42, 0x3e, 0x20, 0x90, 0x07, 0x3e,
+ 0xc7, 0xed, 0xd4, 0xdf, 0x50, 0xe5, 0xff, 0xaf,
+ 0x05, 0xce, 0x29, 0xbe, 0x01, 0xf8, 0xb0, 0x30,
+ 0x96, 0xae, 0x1b, 0x62, 0x23, 0x93, 0x91, 0x1a,
+ 0x52, 0x98, 0xd9, 0x59, 0xb8, 0x11, 0xec, 0xb8,
+ 0xcf, 0x20, 0x32, 0x90, 0x9e, 0xf2, 0x06, 0x43,
+ 0xb8, 0x36, 0xe3, 0x33, 0x4e, 0x6f, 0x75, 0xeb,
+ 0xf7, 0x6c, 0xac, 0x06, 0x5f, 0x24, 0x8e, 0x4a,
+ 0x03, 0xdf, 0x50, 0x31, 0xaa, 0x91, 0xd5, 0x85,
+ 0x95, 0x78, 0x5b, 0xf4, 0x7f, 0x3e, 0xbc, 0x41,
+ 0xfa, 0x10, 0xd3, 0x0f, 0x86, 0x8b, 0x23, 0xed,
+ 0xfc, 0xcc, 0x3e, 0x7d, 0x8c, 0xb4, 0x7c, 0xec,
+ 0x04, 0x7d, 0x12, 0x53, 0xa1, 0x30, 0xc5, 0xac,
+ 0xf3, 0x1e, 0x54, 0x1f, 0x97, 0x05, 0x86, 0x74,
+ 0x51, 0x13, 0x45, 0x98, 0xb8, 0x50, 0x62, 0x18,
+ 0x0f, 0x6d, 0x66, 0xa4, 0x88, 0x31, 0x76, 0xa3,
+ 0xb0, 0x75, 0x55, 0x44, 0x18, 0x7c, 0x67, 0xc7,
+ 0x09, 0x9c, 0xab, 0x53, 0x49, 0xc0, 0xc9, 0x27,
+ 0x53, 0xa6, 0x99, 0x01, 0x10, 0x49, 0x67, 0x8e,
+ 0x5b, 0x12, 0x96, 0x40, 0x16, 0x39, 0x11, 0x53,
+ 0x44, 0x8f, 0xa9, 0xbe, 0x84, 0xbe, 0xe0, 0x45,
+ 0xe3, 0xfd, 0x48, 0x46, 0x43, 0x53, 0x13, 0x5f,
+ 0xfa, 0xcf, 0x09, 0x67, 0x90, 0xa3, 0x94, 0xaa,
+ 0x0d, 0x1f, 0xc2, 0xc3, 0xd4, 0x7e, 0xc8, 0x14,
+ 0xbe, 0x84, 0xa5, 0x55, 0xee, 0x49, 0x8e, 0x03,
+ 0x1d, 0xaf, 0xad, 0x65, 0x2f, 0xf0, 0xd5, 0x90,
+ 0x5e, 0x8d, 0x29, 0x40, 0xba, 0x57, 0x26, 0xa8,
+ 0x6c, 0x4b, 0x59, 0x40, 0x4e, 0xc2, 0xc4, 0x88,
+ 0x0a, 0x06, 0x2b, 0x6c, 0x2a, 0xc7, 0x3f, 0xfe,
+ 0x37, 0x2c, 0x41, 0x58, 0xfe, 0x7e, 0xaf, 0xd1,
+ 0xd9, 0xd2, 0x9c, 0xd7, 0x8a, 0x01, 0x0e, 0x8c,
+ 0x9e, 0x8b, 0x5d, 0x72, 0x54, 0x00, 0xbe, 0xb2,
+ 0x9a, 0xc7, 0xfd, 0x83, 0x1e, 0x9c, 0x79, 0xdd,
+ 0x15, 0x13, 0xdc, 0x15,
+};
+
+
+static const uint8_t encrypted_wkssvc_test_blob[] = {
+ 0x13, 0x79, 0x1f, 0x1a, 0x02, 0x15, 0x72, 0x1c,
+ 0xa6, 0x26, 0x37, 0xeb, 0x1d, 0x41, 0x7f, 0x76,
+ 0x11, 0x3f, 0x49, 0x4c, 0xf9, 0x69, 0x17, 0xc8,
+ 0x90, 0x92, 0x53, 0xb9, 0x3f, 0xcd, 0x06, 0xfe,
+ 0x5c, 0x17, 0x82, 0xbd, 0x86, 0xab, 0x49, 0xee,
+ 0x61, 0x76, 0x55, 0xc0, 0x10, 0x51, 0xcd, 0xd9,
+ 0x6f, 0x12, 0x86, 0xc6, 0x19, 0x59, 0x9a, 0x2f,
+ 0x27, 0x1d, 0x99, 0x30, 0x60, 0x0d, 0x65, 0xc6,
+ 0x43, 0xd6, 0xda, 0x6b, 0x66, 0x95, 0xd4, 0xca,
+ 0xf5, 0x04, 0xf7, 0x01, 0x5a, 0x55, 0xb0, 0x5e,
+ 0x72, 0x8a, 0x75, 0xe5, 0x33, 0x4c, 0xd8, 0xc4,
+ 0x0e, 0xf4, 0x6d, 0x23, 0xdd, 0x05, 0x90, 0xff,
+ 0xe0, 0x91, 0x7b, 0x62, 0x86, 0xee, 0x78, 0x31,
+ 0x07, 0xad, 0x8b, 0xf9, 0xdf, 0x6f, 0x8b, 0xbd,
+ 0x15, 0xde, 0x1b, 0xae, 0x84, 0x68, 0xe5, 0x41,
+ 0x7a, 0xe3, 0x47, 0x99, 0xba, 0x61, 0xe5, 0x51,
+ 0x64, 0x9a, 0xa0, 0x41, 0x44, 0xa1, 0x3a, 0x52,
+ 0x59, 0x7d, 0x6c, 0xcf, 0xcc, 0xf0, 0x11, 0xbc,
+ 0xb7, 0x51, 0xa9, 0xd8, 0xfd, 0xbf, 0x58, 0x77,
+ 0x28, 0x86, 0xa1, 0x27, 0x94, 0xe5, 0xf6, 0x1a,
+ 0x6b, 0x76, 0xf7, 0x72, 0x6e, 0x17, 0x09, 0xd8,
+ 0x3c, 0x6f, 0x39, 0x91, 0xea, 0x48, 0x98, 0xdc,
+ 0x1d, 0x50, 0x2e, 0x02, 0x6e, 0x7f, 0x80, 0x5d,
+ 0x6e, 0x96, 0xe1, 0xcf, 0x8b, 0x6b, 0xb6, 0xed,
+ 0xb4, 0x6a, 0x08, 0xd2, 0x45, 0x09, 0x88, 0x86,
+ 0x32, 0x58, 0xd8, 0x5e, 0x33, 0x8c, 0x29, 0x1a,
+ 0x8f, 0xc5, 0x54, 0x9b, 0xa8, 0x32, 0xb2, 0xc1,
+ 0x72, 0x14, 0x6c, 0x5d, 0x9d, 0xd3, 0xf2, 0x6c,
+ 0x6e, 0xa4, 0x84, 0x52, 0x26, 0x73, 0x7a, 0x30,
+ 0x56, 0x75, 0xef, 0xd1, 0x9d, 0xcd, 0xb7, 0x87,
+ 0xa9, 0x5c, 0xaf, 0xe6, 0xda, 0x1d, 0x3c, 0x9c,
+ 0xa3, 0xb1, 0x03, 0xb0, 0x8e, 0xf6, 0xc8, 0x8f,
+ 0x57, 0x1c, 0xce, 0x05, 0x54, 0x99, 0xf1, 0xf9,
+ 0x35, 0xe6, 0xf7, 0x67, 0x94, 0xb2, 0x67, 0x5b,
+ 0xe7, 0xa0, 0xa2, 0x1e, 0xa2, 0x74, 0xd3, 0x99,
+ 0x9c, 0xd5, 0xd9, 0x90, 0x86, 0x24, 0x0e, 0x1a,
+ 0x0d, 0xc8, 0x9e, 0x68, 0x4c, 0x43, 0x2f, 0x42,
+ 0xb1, 0x7c, 0xce, 0x1e, 0xb6, 0xac, 0x56, 0xb0,
+ 0x8d, 0x93, 0xf1, 0x53, 0x7d, 0x0e, 0x00, 0x46,
+ 0xba, 0x2e, 0x14, 0x7a, 0x0b, 0xaa, 0xcb, 0x07,
+ 0x9b, 0x09, 0x05, 0xa0, 0xd3, 0xa1, 0x80, 0xc2,
+ 0xd3, 0x59, 0x92, 0x27, 0x66, 0x1f, 0xdd, 0x76,
+ 0x36, 0xb3, 0x3c, 0xeb, 0xd7, 0x61, 0x94, 0xb1,
+ 0xf8, 0x3a, 0xe0, 0xba, 0x91, 0x0f, 0xef, 0x72,
+ 0x2b, 0x26, 0xc6, 0xb8, 0x6d, 0x0b, 0xdb, 0x60,
+ 0xf8, 0xb4, 0x98, 0xd7, 0x8b, 0x8d, 0xfb, 0xa7,
+ 0x4e, 0x27, 0xeb, 0x00, 0xe8, 0xf7, 0x5a, 0xec,
+ 0xf5, 0x60, 0x28, 0x37, 0xb2, 0xc4, 0x13, 0x48,
+ 0x2a, 0xe1, 0x34, 0xb2, 0x53, 0xcb, 0x44, 0x34,
+ 0x08, 0x7e, 0x56, 0x5c, 0x2b, 0x9b, 0xe2, 0xca,
+ 0x90, 0xb0, 0x57, 0xee, 0x10, 0x88, 0x39, 0x84,
+ 0xc6, 0x66, 0x07, 0x50, 0x63, 0xcc, 0x2a, 0x7c,
+ 0x99, 0x8c, 0x05, 0xf9, 0xf0, 0xb8, 0x62, 0xf0,
+ 0x92, 0xf7, 0x2a, 0x4a, 0x17, 0x14, 0x78, 0xa1,
+ 0x71, 0xb6, 0x42, 0xf0, 0x87, 0xa8, 0xa4, 0x48,
+ 0xeb, 0xdb, 0xed, 0x8a, 0x15, 0x19, 0x1a, 0xd9,
+ 0xfe, 0x6f, 0x07, 0x93, 0x5d, 0x39, 0xe8, 0x0e,
+ 0x47, 0xe6, 0x7a, 0x7d, 0x52, 0x2e, 0x40, 0x6f,
+ 0x31, 0x1b, 0xf6, 0x0c, 0xc2, 0x83, 0xae, 0xc1,
+ 0xf0, 0xf5, 0x71, 0xcd, 0xe2, 0xf5, 0x19, 0xb6,
+ 0xd8, 0xb0, 0x4d, 0xa9, 0x51, 0x1c, 0xb4, 0xaf,
+ 0x69, 0x9a, 0x89, 0xb6, 0x5b, 0x4d, 0xfa, 0x1b,
+ 0xca, 0xc8, 0x61, 0x92, 0x3a, 0xd6, 0x76, 0xad,
+ 0x5d, 0xa6, 0x17, 0x60, 0x3e, 0xea, 0x94, 0xcf,
+ 0x6d, 0x1b, 0x98, 0x5c, 0x19, 0x9e, 0x4e, 0xd3,
+ 0x21, 0x55, 0xda, 0xe3,
+};
+
+static void torture_decode_rc4_passwd_buffer(void **state)
+{
+ char *password_decoded = NULL;
+ size_t password_decoded_len = 0;
+ DATA_BLOB session_key = data_blob_const("SystemLibraryDTC", 16);
+ struct samr_CryptPasswordEx out_pwd_buf = {
+ .data = {0},
+ };
+ NTSTATUS status;
+ bool ok;
+
+ memcpy(out_pwd_buf.data,
+ encrypted_test_blob,
+ sizeof(out_pwd_buf.data));
+
+ status = decode_rc4_passwd_buffer(&session_key, &out_pwd_buf);
+ assert_true(NT_STATUS_IS_OK(status));
+
+ ok = decode_pw_buffer(NULL,
+ out_pwd_buf.data,
+ &password_decoded,
+ &password_decoded_len,
+ CH_UTF16);
+ assert_true(ok);
+ assert_int_equal(password_decoded_len, strlen(PASSWORD));
+ assert_string_equal(password_decoded, PASSWORD);
+}
+
+static void torture_rc4_passwd_buffer(void **state)
+{
+ char *password_decoded = NULL;
+ size_t password_decoded_len = 0;
+ DATA_BLOB session_key = data_blob_const("SystemLibraryDTC", 16);
+ struct samr_CryptPasswordEx out_pwd_buf = {
+ .data = {0},
+ };
+ NTSTATUS status;
+ bool ok;
+
+ status = init_samr_CryptPasswordEx(PASSWORD,
+ &session_key,
+ &out_pwd_buf);
+ assert_true(NT_STATUS_IS_OK(status));
+
+ status = decode_rc4_passwd_buffer(&session_key, &out_pwd_buf);
+ assert_true(NT_STATUS_IS_OK(status));
+
+ ok = decode_pw_buffer(NULL,
+ out_pwd_buf.data,
+ &password_decoded,
+ &password_decoded_len,
+ CH_UTF16);
+ assert_true(ok);
+ assert_int_equal(password_decoded_len, strlen(PASSWORD));
+ assert_string_equal(password_decoded, PASSWORD);
+ talloc_free(password_decoded);
+}
+
+static void torture_endode_decode_rc4_passwd_buffer(void **state)
+{
+ char *password_decoded = NULL;
+ size_t password_decoded_len = 0;
+ DATA_BLOB session_key = data_blob_const("SystemLibraryDTC", 16);
+ struct samr_CryptPasswordEx out_pwd_buf = {
+ .data = {0},
+ };
+ NTSTATUS status;
+ bool ok;
+
+ status = encode_rc4_passwd_buffer(PASSWORD,
+ &session_key,
+ &out_pwd_buf);
+ assert_true(NT_STATUS_IS_OK(status));
+
+ status = decode_rc4_passwd_buffer(&session_key, &out_pwd_buf);
+ assert_true(NT_STATUS_IS_OK(status));
+
+ ok = decode_pw_buffer(NULL,
+ out_pwd_buf.data,
+ &password_decoded,
+ &password_decoded_len,
+ CH_UTF16);
+ assert_true(ok);
+ assert_int_equal(password_decoded_len, strlen(PASSWORD));
+ assert_string_equal(password_decoded, PASSWORD);
+ talloc_free(password_decoded);
+}
+
+static void torture_decode_wkssvc_join_password_buffer(void **state)
+{
+ DATA_BLOB session_key = data_blob_const("SystemLibraryDTC", 16);
+ struct wkssvc_PasswordBuffer pwd_buf = {
+ .data = {0},
+ };
+ char *password_decoded = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+ WERROR werr;
+
+ mem_ctx = talloc_new(NULL);
+ assert_non_null(mem_ctx);
+
+ memcpy(pwd_buf.data,
+ encrypted_wkssvc_test_blob,
+ sizeof(pwd_buf.data));
+
+ werr = decode_wkssvc_join_password_buffer(mem_ctx,
+ &pwd_buf,
+ &session_key,
+ &password_decoded);
+ assert_true(W_ERROR_IS_OK(werr));
+ assert_non_null(password_decoded);
+ assert_string_equal(password_decoded, PASSWORD);
+
+ TALLOC_FREE(mem_ctx);
+}
+
+static void torture_wkssvc_join_password_buffer(void **state)
+{
+ DATA_BLOB session_key = data_blob_const("SystemLibraryDTC", 16);
+ struct wkssvc_PasswordBuffer *pwd_buf = NULL;
+ char *password_decoded = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+ WERROR werr;
+
+ mem_ctx = talloc_new(NULL);
+ assert_non_null(mem_ctx);
+
+ werr = encode_wkssvc_join_password_buffer(mem_ctx,
+ PASSWORD,
+ &session_key,
+ &pwd_buf);
+ assert_true(W_ERROR_IS_OK(werr));
+ assert_non_null(pwd_buf);
+
+ werr = decode_wkssvc_join_password_buffer(mem_ctx,
+ pwd_buf,
+ &session_key,
+ &password_decoded);
+ assert_true(W_ERROR_IS_OK(werr));
+ assert_non_null(password_decoded);
+ assert_string_equal(password_decoded, PASSWORD);
+
+ TALLOC_FREE(mem_ctx);
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(torture_decode_rc4_passwd_buffer),
+ cmocka_unit_test(torture_rc4_passwd_buffer),
+ cmocka_unit_test(torture_endode_decode_rc4_passwd_buffer),
+ cmocka_unit_test(torture_decode_wkssvc_join_password_buffer),
+ cmocka_unit_test(torture_wkssvc_join_password_buffer),
+ };
+
+ if (argc == 2) {
+ cmocka_set_test_filter(argv[1]);
+ }
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ rc = cmocka_run_group_tests(tests, NULL, NULL);
+
+ return rc;
+}
diff --git a/libcli/auth/tests/test_schannel.c b/libcli/auth/tests/test_schannel.c
new file mode 100644
index 0000000..b1c88fd
--- /dev/null
+++ b/libcli/auth/tests/test_schannel.c
@@ -0,0 +1,305 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2019 Guenther Deschner <gd@samba.org>
+ *
+ * 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 <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "includes.h"
+#include "auth/gensec/schannel.c"
+
+static void torture_schannel_seal_flags(void **state, uint32_t flags,
+ const DATA_BLOB session_key,
+ const DATA_BLOB seq_num_initial,
+ const DATA_BLOB confounder_initial,
+ const DATA_BLOB confounder_expected,
+ const DATA_BLOB clear_initial,
+ const DATA_BLOB crypt_expected)
+{
+ NTSTATUS status;
+ struct schannel_state *schannel_state;
+ struct netlogon_creds_CredentialState *creds;
+ uint8_t confounder[8];
+ DATA_BLOB io;
+
+ assert_int_equal(session_key.length, 16);
+ assert_int_equal(seq_num_initial.length, 8);
+ assert_int_equal(confounder_initial.length, 8);
+ assert_int_equal(confounder_expected.length, 8);
+ assert_int_equal(clear_initial.length, crypt_expected.length);
+
+ DEBUG(0,("checking buffer size: %d\n", (int)clear_initial.length));
+
+ schannel_state = talloc_zero(NULL, struct schannel_state);
+ assert_non_null(schannel_state);
+ creds = talloc_zero(schannel_state,
+ struct netlogon_creds_CredentialState);
+ assert_non_null(creds);
+ schannel_state->creds = creds;
+
+ io = data_blob_dup_talloc(schannel_state, clear_initial);
+ assert_non_null(io.data);
+ assert_int_equal(io.length, clear_initial.length);
+
+ schannel_state->creds->negotiate_flags = flags;
+ memcpy(schannel_state->creds->session_key, session_key.data, 16);
+
+ memcpy(confounder, confounder_initial.data, 8);
+
+ DEBUG(0,("confounder before crypt:\n"));
+ dump_data(0, confounder, 8);
+ dump_data(0, seq_num_initial.data, 8);
+ dump_data(0, io.data, io.length);
+
+ status = netsec_do_seal(schannel_state,
+ seq_num_initial.data,
+ confounder,
+ io.data,
+ io.length,
+ true);
+
+ assert_true(NT_STATUS_IS_OK(status));
+ dump_data(0, io.data, io.length);
+ DEBUG(0,("confounder after crypt:\n"));
+ dump_data(0, confounder, 8);
+ dump_data(0, seq_num_initial.data, 8);
+ assert_memory_equal(io.data, crypt_expected.data, crypt_expected.length);
+ assert_memory_equal(confounder, confounder_expected.data, confounder_expected.length);
+
+ status = netsec_do_seal(schannel_state,
+ seq_num_initial.data,
+ confounder,
+ io.data,
+ io.length,
+ false);
+
+ assert_true(NT_STATUS_IS_OK(status));
+ dump_data(0, io.data, io.length);
+ DEBUG(0,("confounder after decrypt:\n"));
+ dump_data(0, confounder, 8);
+ dump_data(0, seq_num_initial.data, 8);
+ assert_memory_equal(io.data, clear_initial.data, clear_initial.length);
+ assert_memory_equal(confounder, confounder_initial.data, confounder_initial.length);
+
+ talloc_free(schannel_state);
+}
+
+static void torture_schannel_seal_rc4(void **state)
+{
+ const uint8_t _session_key[16] = {
+ 0x14, 0xD5, 0x7F, 0x8D, 0x8E, 0xCF, 0xFB, 0x56,
+ 0x71, 0x29, 0x9D, 0x9C, 0x2A, 0x75, 0x00, 0xA1
+ };
+ const DATA_BLOB session_key = data_blob_const(_session_key, 16);
+ const uint8_t _seq_num_initial[8] = {
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00
+ };
+ const DATA_BLOB seq_num_initial =
+ data_blob_const(_seq_num_initial, 8);
+ const uint8_t _confounder_initial[8] = {
+ 0x1A, 0x5A, 0xE8, 0xC7, 0xBE, 0x4F, 0x1F, 0x07
+ };
+ const DATA_BLOB confounder_initial =
+ data_blob_const(_confounder_initial, 8);
+ const uint8_t _confounder_expected[8] = {
+ 0x25, 0x4A, 0x9C, 0x15, 0x82, 0x3E, 0x4A, 0x42
+ };
+ const DATA_BLOB confounder_expected =
+ data_blob_const(_confounder_expected, 8);
+ const uint8_t _clear_initial[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x8A, 0xE3, 0x13, 0x71, 0x02, 0xF4, 0x36, 0x71,
+ 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x40, 0x28, 0x00, 0x78, 0x57, 0x34, 0x12,
+ 0x34, 0x12, 0xCD, 0xAB, 0xEF, 0x00, 0x01, 0x23,
+ 0x45, 0x67, 0x89, 0xAB, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x5D, 0x88, 0x8A, 0xEB, 0x1C, 0xC9, 0x11,
+ 0x9F, 0xE8, 0x08, 0x00, 0x2B, 0x10, 0x48, 0x60,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ const DATA_BLOB clear_initial = data_blob_const(_clear_initial,
+ sizeof(_clear_initial));
+ const uint8_t crypt_buffer[] = {
+ 0x3E, 0x10, 0x74, 0xD2, 0x3C, 0x71, 0x57, 0x45,
+ 0xB8, 0xAA, 0xCF, 0xE3, 0x84, 0xBE, 0xC4, 0x00,
+ 0xF4, 0x4D, 0x88, 0x0A, 0x9B, 0xCC, 0x53, 0xFC,
+ 0x32, 0xAA, 0x8E, 0x4B, 0x0E, 0xDE, 0x5F, 0x7D,
+ 0x6D, 0x31, 0x4E, 0xAB, 0xE0, 0x7D, 0x37, 0x9D,
+ 0x3D, 0x16, 0xD8, 0xBA, 0x6A, 0xB0, 0xD0, 0x99,
+ 0x14, 0x05, 0x37, 0xCF, 0x63, 0xD3, 0xD7, 0x60,
+ 0x63, 0x3C, 0x03, 0x0A, 0x30, 0xA0, 0x3E, 0xC7,
+ 0xDA, 0x94, 0x3B, 0x40, 0x63, 0x74, 0xEF, 0xCF,
+ 0xE5, 0x48, 0x87, 0xE9, 0x6A, 0x5A, 0xC7, 0x61,
+ 0xF7, 0x09, 0xB7, 0x7C, 0xDE, 0xDB, 0xB0, 0x94,
+ 0x9B, 0x99, 0xC0, 0xA7, 0x7E, 0x78, 0x09, 0x35,
+ 0xB4, 0xF4, 0x11, 0xC3, 0xB3, 0x77, 0xB5, 0x77,
+ 0x25, 0xEE, 0xFD, 0x2F, 0x9A, 0x15, 0x95, 0x27,
+ 0x08, 0xDA, 0xD0, 0x28, 0xD6, 0x31, 0xB4, 0xB7,
+ 0x7A, 0x19, 0xBB, 0xF3, 0x78, 0xF8, 0xC2, 0x5B
+ };
+ const DATA_BLOB crypt_expected = data_blob_const(crypt_buffer,
+ sizeof(crypt_buffer));
+ int buffer_sizes[] = {
+ 0, 1, 3, 7, 8, 9, 15, 16, 17
+ };
+ int i;
+
+ torture_schannel_seal_flags(state, 0,
+ session_key,
+ seq_num_initial,
+ confounder_initial,
+ confounder_expected,
+ clear_initial,
+ crypt_expected);
+
+ /* repeat the test for varying buffer sizes */
+
+ for (i = 0; i < ARRAY_SIZE(buffer_sizes); i++) {
+ DATA_BLOB clear_initial_trunc =
+ data_blob_const(clear_initial.data, buffer_sizes[i]);
+ DATA_BLOB crypt_expected_trunc =
+ data_blob_const(crypt_expected.data, buffer_sizes[i]);
+ torture_schannel_seal_flags(state, 0,
+ session_key,
+ seq_num_initial,
+ confounder_initial,
+ confounder_expected,
+ clear_initial_trunc,
+ crypt_expected_trunc);
+ }
+}
+
+static void torture_schannel_seal_aes(void **state)
+{
+ const uint8_t _session_key[16] = {
+ 0x8E, 0xE8, 0x27, 0x85, 0x83, 0x41, 0x3C, 0x8D,
+ 0xC9, 0x54, 0x70, 0x75, 0x8E, 0xC9, 0x69, 0x91
+ };
+ const DATA_BLOB session_key = data_blob_const(_session_key, 16);
+ const uint8_t _seq_num_initial[8] = {
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00
+ };
+ const DATA_BLOB seq_num_initial =
+ data_blob_const(_seq_num_initial, 8);
+ const uint8_t _confounder_initial[8] = {
+ 0x6E, 0x09, 0x25, 0x94, 0x01, 0xA0, 0x09, 0x31
+ };
+ const DATA_BLOB confounder_initial =
+ data_blob_const(_confounder_initial, 8);
+ const uint8_t _confounder_expected[8] = {
+ 0xCA, 0xFB, 0xAC, 0xFB, 0xA8, 0x26, 0x75, 0x2A
+ };
+ const DATA_BLOB confounder_expected =
+ data_blob_const(_confounder_expected, 8);
+ const uint8_t _clear_initial[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x8A, 0xE3, 0x13, 0x71, 0x02, 0xF4, 0x36, 0x71,
+ 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x40, 0x28, 0x00, 0x78, 0x57, 0x34, 0x12,
+ 0x34, 0x12, 0xCD, 0xAB, 0xEF, 0x00, 0x01, 0x23,
+ 0x45, 0x67, 0x89, 0xAB, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x5D, 0x88, 0x8A, 0xEB, 0x1C, 0xC9, 0x11,
+ 0x9F, 0xE8, 0x08, 0x00, 0x2B, 0x10, 0x48, 0x60,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ const DATA_BLOB clear_initial = data_blob_const(_clear_initial,
+ sizeof(_clear_initial));
+ const uint8_t crypt_buffer[] = {
+ 0xE2, 0xE5, 0xE3, 0x26, 0x45, 0xFB, 0xFC, 0xF3,
+ 0x9C, 0x14, 0xDD, 0xE1, 0x39, 0x23, 0xE0, 0x55,
+ 0xED, 0x8F, 0xF4, 0x92, 0xA1, 0xBD, 0xDC, 0x40,
+ 0x58, 0x6F, 0xD2, 0x5B, 0xF9, 0xC9, 0xA3, 0x87,
+ 0x46, 0x4B, 0x7F, 0xB2, 0x03, 0xD2, 0x35, 0x22,
+ 0x3E, 0x70, 0x9F, 0x1E, 0x3F, 0x1F, 0xDB, 0x7D,
+ 0x79, 0x88, 0x5A, 0x3D, 0xD3, 0x40, 0x1E, 0x69,
+ 0xD7, 0xE2, 0x1D, 0x5A, 0xE9, 0x3B, 0xE1, 0xE2,
+ 0x98, 0xFD, 0xCB, 0x3A, 0xF7, 0xB5, 0x1C, 0xF8,
+ 0xCA, 0x02, 0x00, 0x99, 0x9F, 0x0C, 0x01, 0xE6,
+ 0xD2, 0x00, 0xAF, 0xE0, 0x51, 0x88, 0x62, 0x50,
+ 0xB7, 0xE8, 0x6D, 0x63, 0x4B, 0x97, 0x05, 0xC1,
+ 0xD4, 0x83, 0x96, 0x29, 0x80, 0xAE, 0xD8, 0xA2,
+ 0xED, 0xC9, 0x5D, 0x0D, 0x29, 0xFF, 0x2C, 0x23,
+ 0x02, 0xFA, 0x3B, 0xEE, 0xE8, 0xBA, 0x06, 0x01,
+ 0x95, 0xDF, 0x80, 0x76, 0x0B, 0x17, 0x0E, 0xD8
+ };
+ const DATA_BLOB crypt_expected = data_blob_const(crypt_buffer,
+ sizeof(crypt_buffer));
+ int buffer_sizes[] = {
+ 0, 1, 3, 7, 8, 9, 15, 16, 17
+ };
+ int i;
+
+ torture_schannel_seal_flags(state, NETLOGON_NEG_SUPPORTS_AES,
+ session_key,
+ seq_num_initial,
+ confounder_initial,
+ confounder_expected,
+ clear_initial,
+ crypt_expected);
+
+ /* repeat the test for varying buffer sizes */
+
+ for (i = 0; i < ARRAY_SIZE(buffer_sizes); i++) {
+ DATA_BLOB clear_initial_trunc =
+ data_blob_const(clear_initial.data, buffer_sizes[i]);
+ DATA_BLOB crypt_expected_trunc =
+ data_blob_const(crypt_expected.data, buffer_sizes[i]);
+ torture_schannel_seal_flags(state, NETLOGON_NEG_SUPPORTS_AES,
+ session_key,
+ seq_num_initial,
+ confounder_initial,
+ confounder_expected,
+ clear_initial_trunc,
+ crypt_expected_trunc);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(torture_schannel_seal_rc4),
+ cmocka_unit_test(torture_schannel_seal_aes),
+ };
+
+ if (argc == 2) {
+ cmocka_set_test_filter(argv[1]);
+ }
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ rc = cmocka_run_group_tests(tests, NULL, NULL);
+
+ return rc;
+}
diff --git a/libcli/auth/wscript_build b/libcli/auth/wscript_build
new file mode 100644
index 0000000..c73e0d1
--- /dev/null
+++ b/libcli/auth/wscript_build
@@ -0,0 +1,100 @@
+#!/usr/bin/env python
+
+bld.SAMBA_LIBRARY('cliauth',
+ source='',
+ deps='MSRPC_PARSE LIBCLI_AUTH COMMON_SCHANNEL PAM_ERRORS SPNEGO_PARSE krb5samba samba-errors NTLM_CHECK UTIL_LSARPC',
+ private_library=True,
+ grouping_library=True)
+
+bld.SAMBA_SUBSYSTEM('MSRPC_PARSE',
+ source='msrpc_parse.c',
+ deps='talloc'
+ )
+
+bld.SAMBA_SUBSYSTEM('NTLM_CHECK',
+ source='ntlm_check.c',
+ deps = 'talloc LIBCLI_AUTH'
+ )
+
+bld.SAMBA_SUBSYSTEM('LIBCLI_AUTH',
+ source='credentials.c session.c smbencrypt.c smbdes.c',
+ public_deps='MSRPC_PARSE gnutls GNUTLS_HELPERS util_str_escape',
+ public_headers='credentials.h:domain_credentials.h'
+ )
+
+
+bld.SAMBA_SUBSYSTEM('COMMON_SCHANNEL',
+ source='schannel_state_tdb.c',
+ deps='dbwrap util_tdb samba-hostconfig NDR_NETLOGON'
+ )
+
+bld.SAMBA_SUBSYSTEM('NETLOGON_CREDS_CLI',
+ source='netlogon_creds_cli.c',
+ deps='''
+ dbwrap
+ util_tdb
+ tevent-util
+ samba-hostconfig
+ gensec
+ RPC_NDR_NETLOGON
+ NDR_NETLOGON
+ '''
+ )
+
+bld.SAMBA_SUBSYSTEM('PAM_ERRORS',
+ source='pam_errors.c',
+ deps='talloc'
+ )
+
+bld.SAMBA_SUBSYSTEM('SPNEGO_PARSE',
+ source='spnego_parse.c',
+ deps='asn1util')
+
+bld.SAMBA_BINARY(
+ 'test_ntlm_check',
+ source='tests/ntlm_check.c',
+ deps='''
+ NTLM_CHECK
+ CREDENTIALS_NTLM
+ samba-credentials
+ cmocka
+ talloc
+ ''',
+ for_selftest=True
+ )
+
+bld.SAMBA_BINARY('test_rc4_passwd_buffer',
+ source='tests/test_rc4_passwd_buffer.c',
+ deps='''
+ INIT_SAMR
+ LIBCLI_AUTH
+ cmocka
+ ''',
+ for_selftest=True)
+
+bld.SAMBA_BINARY('test_schannel',
+ source='tests/test_schannel.c',
+ deps='''
+ gensec
+ cmocka
+ ''',
+ for_selftest=True)
+
+bld.SAMBA_BINARY('test_gnutls',
+ source='tests/test_gnutls.c',
+ deps='''
+ gnutls
+ LIBCLI_AUTH
+ cmocka
+ samba-util
+ ''',
+ for_selftest=True)
+
+bld.SAMBA_BINARY('test_encode_decode',
+ source='tests/test_encode_decode.c',
+ deps='''
+ LIBCLI_AUTH
+ cmocka
+ samba-util
+ ''',
+ for_selftest=True)
diff --git a/libcli/cldap/cldap.c b/libcli/cldap/cldap.c
new file mode 100644
index 0000000..8176946
--- /dev/null
+++ b/libcli/cldap/cldap.c
@@ -0,0 +1,1209 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ cldap client library
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Stefan Metzmacher 2009
+
+ 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/>.
+*/
+
+/*
+ see RFC1798 for details of CLDAP
+
+ basic properties
+ - carried over UDP on port 389
+ - request and response matched by message ID
+ - request consists of only a single searchRequest element
+ - response can be in one of two forms
+ - a single searchResponse, followed by a searchResult
+ - a single searchResult
+*/
+
+#include "includes.h"
+#include <tevent.h>
+#include "../lib/util/dlinklist.h"
+#include "../libcli/ldap/ldap_message.h"
+#include "../libcli/ldap/ldap_ndr.h"
+#include "../libcli/cldap/cldap.h"
+#include "../lib/tsocket/tsocket.h"
+#include "../libcli/security/dom_sid.h"
+#include "../librpc/gen_ndr/ndr_nbt.h"
+#include "../lib/util/asn1.h"
+#include "../lib/util/tevent_ntstatus.h"
+#include "lib/util/idtree_random.h"
+
+#undef strcasecmp
+
+/*
+ context structure for operations on cldap packets
+*/
+struct cldap_socket {
+ /* the low level socket */
+ struct tdgram_context *sock;
+
+ /*
+ * Are we in connected mode, which means
+ * we get ICMP errors back instead of timing
+ * out requests. And we can only send requests
+ * to the connected peer.
+ */
+ bool connected;
+
+ /* the queue for outgoing dgrams */
+ struct tevent_queue *send_queue;
+
+ /* do we have an async tsocket_recvfrom request pending */
+ struct tevent_req *recv_subreq;
+
+ struct {
+ /* a queue of pending search requests */
+ struct cldap_search_state *list;
+
+ /* mapping from message_id to pending request */
+ struct idr_context *idr;
+ } searches;
+
+ /* what to do with incoming request packets */
+ struct {
+ struct tevent_context *ev;
+ void (*handler)(struct cldap_socket *,
+ void *private_data,
+ struct cldap_incoming *);
+ void *private_data;
+ } incoming;
+};
+
+struct cldap_search_state {
+ struct cldap_search_state *prev, *next;
+
+ struct {
+ struct tevent_context *ev;
+ struct cldap_socket *cldap;
+ } caller;
+
+ int message_id;
+
+ struct {
+ uint32_t idx;
+ uint32_t delay;
+ uint32_t count;
+ struct tsocket_address *dest;
+ DATA_BLOB blob;
+ } request;
+
+ struct {
+ struct cldap_incoming *in;
+ struct asn1_data *asn1;
+ } response;
+
+ struct tevent_req *req;
+};
+
+/*
+ * For CLDAP we limit the maximum search request size to 4kb
+ */
+#define MAX_SEARCH_REQUEST 4096
+
+static int cldap_socket_destructor(struct cldap_socket *c)
+{
+ while (c->searches.list) {
+ struct cldap_search_state *s = c->searches.list;
+ DLIST_REMOVE(c->searches.list, s);
+ ZERO_STRUCT(s->caller);
+ }
+
+ talloc_free(c->recv_subreq);
+ talloc_free(c->send_queue);
+ talloc_free(c->sock);
+ return 0;
+}
+
+static void cldap_recvfrom_done(struct tevent_req *subreq);
+
+static bool cldap_recvfrom_setup(struct cldap_socket *c)
+{
+ struct tevent_context *ev;
+
+ if (c->recv_subreq) {
+ return true;
+ }
+
+ if (!c->searches.list && !c->incoming.handler) {
+ return true;
+ }
+
+ ev = c->incoming.ev;
+ if (ev == NULL) {
+ /* this shouldn't happen but should be protected against */
+ if (c->searches.list == NULL) {
+ return false;
+ }
+ ev = c->searches.list->caller.ev;
+ }
+
+ c->recv_subreq = tdgram_recvfrom_send(c, ev, c->sock);
+ if (!c->recv_subreq) {
+ return false;
+ }
+ tevent_req_set_callback(c->recv_subreq, cldap_recvfrom_done, c);
+
+ return true;
+}
+
+static void cldap_recvfrom_stop(struct cldap_socket *c)
+{
+ if (!c->recv_subreq) {
+ return;
+ }
+
+ if (c->searches.list || c->incoming.handler) {
+ return;
+ }
+
+ talloc_free(c->recv_subreq);
+ c->recv_subreq = NULL;
+}
+
+static bool cldap_socket_recv_dgram(struct cldap_socket *c,
+ struct cldap_incoming *in);
+
+static void cldap_recvfrom_done(struct tevent_req *subreq)
+{
+ struct cldap_socket *c = tevent_req_callback_data(subreq,
+ struct cldap_socket);
+ struct cldap_incoming *in = NULL;
+ ssize_t ret;
+ bool setup_done;
+
+ c->recv_subreq = NULL;
+
+ in = talloc_zero(c, struct cldap_incoming);
+ if (!in) {
+ goto nomem;
+ }
+
+ ret = tdgram_recvfrom_recv(subreq,
+ &in->recv_errno,
+ in,
+ &in->buf,
+ &in->src);
+ talloc_free(subreq);
+ subreq = NULL;
+ if (ret >= 0) {
+ in->len = ret;
+ }
+ if (ret == -1 && in->recv_errno == 0) {
+ in->recv_errno = EIO;
+ }
+
+ /* this function should free or steal 'in' */
+ setup_done = cldap_socket_recv_dgram(c, in);
+ in = NULL;
+
+ if (!setup_done && !cldap_recvfrom_setup(c)) {
+ goto nomem;
+ }
+
+ return;
+
+nomem:
+ talloc_free(subreq);
+ talloc_free(in);
+}
+
+/*
+ handle recv events on a cldap socket
+*/
+static bool cldap_socket_recv_dgram(struct cldap_socket *c,
+ struct cldap_incoming *in)
+{
+ struct asn1_data *asn1;
+ void *p;
+ struct cldap_search_state *search;
+ NTSTATUS status;
+ struct ldap_request_limits limits = {
+ .max_search_size = MAX_SEARCH_REQUEST
+ };
+
+ if (in->recv_errno != 0) {
+ goto error;
+ }
+
+ asn1 = asn1_init(in, ASN1_MAX_TREE_DEPTH);
+ if (!asn1) {
+ goto nomem;
+ }
+
+ asn1_load_nocopy(asn1, in->buf, in->len);
+
+ in->ldap_msg = talloc(in, struct ldap_message);
+ if (in->ldap_msg == NULL) {
+ goto nomem;
+ }
+
+ /* this initial decode is used to find the message id */
+ status = ldap_decode(asn1, &limits, NULL, in->ldap_msg);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto nterror;
+ }
+
+ /* find the pending request */
+ p = idr_find(c->searches.idr, in->ldap_msg->messageid);
+ if (p == NULL) {
+ if (!c->incoming.handler) {
+ TALLOC_FREE(in);
+ return true;
+ }
+
+ /* this function should free or steal 'in' */
+ c->incoming.handler(c, c->incoming.private_data, in);
+ return false;
+ }
+
+ search = talloc_get_type_abort(p, struct cldap_search_state);
+ search->response.in = talloc_move(search, &in);
+
+ search->response.asn1 = asn1;
+
+ asn1_load_nocopy(search->response.asn1,
+ search->response.in->buf, search->response.in->len);
+
+ DLIST_REMOVE(c->searches.list, search);
+
+ if (cldap_recvfrom_setup(c)) {
+ tevent_req_done(search->req);
+ return true;
+ }
+
+ /*
+ * This request was ok, just defer the notify of the caller
+ * and then just fail the next request if needed
+ */
+ tevent_req_defer_callback(search->req, search->caller.ev);
+ tevent_req_done(search->req);
+
+ status = NT_STATUS_NO_MEMORY;
+ /* in is NULL it this point */
+ goto nterror;
+nomem:
+ in->recv_errno = ENOMEM;
+error:
+ status = map_nt_error_from_unix_common(in->recv_errno);
+nterror:
+ TALLOC_FREE(in);
+ /* in connected mode the first pending search gets the error */
+ if (!c->connected) {
+ /* otherwise we just ignore the error */
+ return false;
+ }
+ if (!c->searches.list) {
+ return false;
+ }
+ /*
+ * We might called tevent_req_done() for a successful
+ * search before, so we better deliver the failure
+ * after the success, that is why we better also
+ * use tevent_req_defer_callback() here.
+ */
+ tevent_req_defer_callback(c->searches.list->req,
+ c->searches.list->caller.ev);
+ tevent_req_nterror(c->searches.list->req, status);
+ return false;
+}
+
+/*
+ initialise a cldap_sock
+*/
+NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
+ const struct tsocket_address *local_addr,
+ const struct tsocket_address *remote_addr,
+ struct cldap_socket **_cldap)
+{
+ struct cldap_socket *c = NULL;
+ struct tsocket_address *any = NULL;
+ NTSTATUS status;
+ int ret;
+ const char *fam = NULL;
+
+ if (local_addr == NULL && remote_addr == NULL) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (remote_addr) {
+ bool is_ipv4;
+ bool is_ipv6;
+
+ is_ipv4 = tsocket_address_is_inet(remote_addr, "ipv4");
+ is_ipv6 = tsocket_address_is_inet(remote_addr, "ipv6");
+
+ if (is_ipv4) {
+ fam = "ipv4";
+ } else if (is_ipv6) {
+ fam = "ipv6";
+ } else {
+ return NT_STATUS_INVALID_ADDRESS;
+ }
+ }
+
+ c = talloc_zero(mem_ctx, struct cldap_socket);
+ if (!c) {
+ goto nomem;
+ }
+
+ if (!local_addr) {
+ /*
+ * Here we know the address family of the remote address.
+ */
+ if (fam == NULL) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ ret = tsocket_address_inet_from_strings(c, fam,
+ NULL, 0,
+ &any);
+ if (ret != 0) {
+ status = map_nt_error_from_unix_common(errno);
+ goto nterror;
+ }
+ local_addr = any;
+ }
+
+ c->searches.idr = idr_init(c);
+ if (!c->searches.idr) {
+ goto nomem;
+ }
+
+ ret = tdgram_inet_udp_socket(local_addr, remote_addr,
+ c, &c->sock);
+ if (ret != 0) {
+ status = map_nt_error_from_unix_common(errno);
+ goto nterror;
+ }
+ talloc_free(any);
+
+ if (remote_addr) {
+ c->connected = true;
+ }
+
+ c->send_queue = tevent_queue_create(c, "cldap_send_queue");
+ if (!c->send_queue) {
+ goto nomem;
+ }
+
+ talloc_set_destructor(c, cldap_socket_destructor);
+
+ *_cldap = c;
+ return NT_STATUS_OK;
+
+nomem:
+ status = NT_STATUS_NO_MEMORY;
+nterror:
+ talloc_free(c);
+ return status;
+}
+
+/*
+ setup a handler for incoming requests
+*/
+NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c,
+ struct tevent_context *ev,
+ void (*handler)(struct cldap_socket *,
+ void *private_data,
+ struct cldap_incoming *),
+ void *private_data)
+{
+ if (c->connected) {
+ return NT_STATUS_PIPE_CONNECTED;
+ }
+
+ c->incoming.ev = ev;
+ c->incoming.handler = handler;
+ c->incoming.private_data = private_data;
+
+ if (!cldap_recvfrom_setup(c)) {
+ ZERO_STRUCT(c->incoming);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+struct cldap_reply_state {
+ struct tsocket_address *dest;
+ DATA_BLOB blob;
+};
+
+static void cldap_reply_state_destroy(struct tevent_req *subreq);
+
+/*
+ queue a cldap reply for send
+*/
+NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
+{
+ struct cldap_reply_state *state = NULL;
+ struct ldap_message *msg;
+ DATA_BLOB blob1, blob2;
+ NTSTATUS status;
+ struct tevent_req *subreq;
+
+ if (cldap->connected) {
+ return NT_STATUS_PIPE_CONNECTED;
+ }
+
+ if (cldap->incoming.ev == NULL) {
+ return NT_STATUS_INVALID_PIPE_STATE;
+ }
+
+ if (!io->dest) {
+ return NT_STATUS_INVALID_ADDRESS;
+ }
+
+ state = talloc(cldap, struct cldap_reply_state);
+ NT_STATUS_HAVE_NO_MEMORY(state);
+
+ state->dest = tsocket_address_copy(io->dest, state);
+ if (!state->dest) {
+ goto nomem;
+ }
+
+ msg = talloc(state, struct ldap_message);
+ if (!msg) {
+ goto nomem;
+ }
+
+ msg->messageid = io->messageid;
+ msg->controls = NULL;
+
+ if (io->response) {
+ msg->type = LDAP_TAG_SearchResultEntry;
+ msg->r.SearchResultEntry = *io->response;
+
+ if (!ldap_encode(msg, NULL, &blob1, state)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto failed;
+ }
+ } else {
+ blob1 = data_blob(NULL, 0);
+ }
+
+ msg->type = LDAP_TAG_SearchResultDone;
+ msg->r.SearchResultDone = *io->result;
+
+ if (!ldap_encode(msg, NULL, &blob2, state)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto failed;
+ }
+ talloc_free(msg);
+
+ state->blob = data_blob_talloc(state, NULL, blob1.length + blob2.length);
+ if (!state->blob.data) {
+ goto nomem;
+ }
+
+ if (blob1.data != NULL) {
+ memcpy(state->blob.data, blob1.data, blob1.length);
+ }
+ memcpy(state->blob.data+blob1.length, blob2.data, blob2.length);
+ data_blob_free(&blob1);
+ data_blob_free(&blob2);
+
+ subreq = tdgram_sendto_queue_send(state,
+ cldap->incoming.ev,
+ cldap->sock,
+ cldap->send_queue,
+ state->blob.data,
+ state->blob.length,
+ state->dest);
+ if (!subreq) {
+ goto nomem;
+ }
+ /* the callback will just free the state, as we don't need a result */
+ tevent_req_set_callback(subreq, cldap_reply_state_destroy, state);
+
+ return NT_STATUS_OK;
+
+nomem:
+ status = NT_STATUS_NO_MEMORY;
+failed:
+ talloc_free(state);
+ return status;
+}
+
+static void cldap_reply_state_destroy(struct tevent_req *subreq)
+{
+ struct cldap_reply_state *state = tevent_req_callback_data(subreq,
+ struct cldap_reply_state);
+
+ /* we don't want to know the result here, we just free the state */
+ talloc_free(subreq);
+ talloc_free(state);
+}
+
+static int cldap_search_state_destructor(struct cldap_search_state *s)
+{
+ if (s->caller.cldap) {
+ if (s->message_id != -1) {
+ idr_remove(s->caller.cldap->searches.idr, s->message_id);
+ s->message_id = -1;
+ }
+ DLIST_REMOVE(s->caller.cldap->searches.list, s);
+ cldap_recvfrom_stop(s->caller.cldap);
+ ZERO_STRUCT(s->caller);
+ }
+
+ return 0;
+}
+
+static void cldap_search_state_queue_done(struct tevent_req *subreq);
+static void cldap_search_state_wakeup_done(struct tevent_req *subreq);
+
+/*
+ queue a cldap reply for send
+*/
+struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cldap_socket *cldap,
+ const struct cldap_search *io)
+{
+ struct tevent_req *req, *subreq;
+ struct cldap_search_state *state = NULL;
+ struct ldap_message *msg;
+ struct ldap_SearchRequest *search;
+ struct timeval now;
+ struct timeval end;
+ uint32_t i;
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cldap_search_state);
+ if (!req) {
+ return NULL;
+ }
+ state->caller.ev = ev;
+ state->req = req;
+ state->caller.cldap = cldap;
+ state->message_id = -1;
+
+ talloc_set_destructor(state, cldap_search_state_destructor);
+
+ if (state->caller.cldap == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ goto post;
+ }
+
+ if (io->in.dest_address) {
+ if (cldap->connected) {
+ tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED);
+ goto post;
+ }
+ ret = tsocket_address_inet_from_strings(state,
+ "ip",
+ io->in.dest_address,
+ io->in.dest_port,
+ &state->request.dest);
+ if (ret != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ goto post;
+ }
+ } else {
+ if (!cldap->connected) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
+ goto post;
+ }
+ state->request.dest = NULL;
+ }
+
+ state->message_id = idr_get_new_random(
+ cldap->searches.idr, state, 1, UINT16_MAX);
+ if (state->message_id == -1) {
+ tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
+ goto post;
+ }
+
+ msg = talloc(state, struct ldap_message);
+ if (tevent_req_nomem(msg, req)) {
+ goto post;
+ }
+
+ msg->messageid = state->message_id;
+ msg->type = LDAP_TAG_SearchRequest;
+ msg->controls = NULL;
+ search = &msg->r.SearchRequest;
+
+ search->basedn = "";
+ search->scope = LDAP_SEARCH_SCOPE_BASE;
+ search->deref = LDAP_DEREFERENCE_NEVER;
+ search->timelimit = 0;
+ search->sizelimit = 0;
+ search->attributesonly = false;
+ search->num_attributes = str_list_length(io->in.attributes);
+ search->attributes = io->in.attributes;
+ search->tree = ldb_parse_tree(msg, io->in.filter);
+ if (tevent_req_nomem(search->tree, req)) {
+ goto post;
+ }
+
+ if (!ldap_encode(msg, NULL, &state->request.blob, state)) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ goto post;
+ }
+ talloc_free(msg);
+
+ state->request.idx = 0;
+ state->request.delay = 10*1000*1000;
+ state->request.count = 3;
+ if (io->in.timeout > 0) {
+ state->request.delay = io->in.timeout * 1000 * 1000;
+ state->request.count = io->in.retries + 1;
+ }
+
+ now = tevent_timeval_current();
+ end = now;
+ for (i = 0; i < state->request.count; i++) {
+ end = tevent_timeval_add(&end, state->request.delay / 1000000,
+ state->request.delay % 1000000);
+ }
+
+ if (!tevent_req_set_endtime(req, state->caller.ev, end)) {
+ goto post;
+ }
+
+ subreq = tdgram_sendto_queue_send(state,
+ state->caller.ev,
+ state->caller.cldap->sock,
+ state->caller.cldap->send_queue,
+ state->request.blob.data,
+ state->request.blob.length,
+ state->request.dest);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
+
+ DLIST_ADD_END(cldap->searches.list, state);
+
+ return req;
+
+ post:
+ return tevent_req_post(req, state->caller.ev);
+}
+
+static void cldap_search_state_queue_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct cldap_search_state *state = tevent_req_data(req,
+ struct cldap_search_state);
+ ssize_t ret;
+ int sys_errno = 0;
+ struct timeval next;
+
+ ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
+ talloc_free(subreq);
+ if (ret == -1) {
+ NTSTATUS status;
+ status = map_nt_error_from_unix_common(sys_errno);
+ DLIST_REMOVE(state->caller.cldap->searches.list, state);
+ ZERO_STRUCT(state->caller.cldap);
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ state->request.idx++;
+
+ /* wait for incoming traffic */
+ if (!cldap_recvfrom_setup(state->caller.cldap)) {
+ tevent_req_oom(req);
+ return;
+ }
+
+ if (state->request.idx > state->request.count) {
+ /* we just wait for the response or a timeout */
+ return;
+ }
+
+ next = tevent_timeval_current_ofs(state->request.delay / 1000000,
+ state->request.delay % 1000000);
+ subreq = tevent_wakeup_send(state,
+ state->caller.ev,
+ next);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req);
+}
+
+static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct cldap_search_state *state = tevent_req_data(req,
+ struct cldap_search_state);
+ bool ok;
+
+ ok = tevent_wakeup_recv(subreq);
+ talloc_free(subreq);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return;
+ }
+
+ subreq = tdgram_sendto_queue_send(state,
+ state->caller.ev,
+ state->caller.cldap->sock,
+ state->caller.cldap->send_queue,
+ state->request.blob.data,
+ state->request.blob.length,
+ state->request.dest);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
+}
+
+/*
+ receive a cldap reply
+*/
+NTSTATUS cldap_search_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct cldap_search *io)
+{
+ struct cldap_search_state *state = tevent_req_data(req,
+ struct cldap_search_state);
+ struct ldap_message *ldap_msg;
+ NTSTATUS status;
+ struct ldap_request_limits limits = {
+ .max_search_size = MAX_SEARCH_REQUEST
+ };
+
+ if (tevent_req_is_nterror(req, &status)) {
+ goto failed;
+ }
+
+ ldap_msg = talloc(mem_ctx, struct ldap_message);
+ if (!ldap_msg) {
+ goto nomem;
+ }
+
+ status = ldap_decode(state->response.asn1, &limits, NULL, ldap_msg);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ ZERO_STRUCT(io->out);
+
+ /* the first possible form has a search result in first place */
+ if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
+ io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
+ if (!io->out.response) {
+ goto nomem;
+ }
+ *io->out.response = ldap_msg->r.SearchResultEntry;
+
+ /* decode the 2nd part */
+ status = ldap_decode(
+ state->response.asn1, &limits, NULL, ldap_msg);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+ }
+
+ if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
+ status = NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
+ goto failed;
+ }
+
+ io->out.result = talloc(mem_ctx, struct ldap_Result);
+ if (!io->out.result) {
+ goto nomem;
+ }
+ *io->out.result = ldap_msg->r.SearchResultDone;
+
+ if (io->out.result->resultcode != LDAP_SUCCESS) {
+ status = NT_STATUS_LDAP(io->out.result->resultcode);
+ goto failed;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+
+nomem:
+ status = NT_STATUS_NO_MEMORY;
+failed:
+ tevent_req_received(req);
+ return status;
+}
+
+
+/*
+ synchronous cldap search
+*/
+NTSTATUS cldap_search(struct cldap_socket *cldap,
+ TALLOC_CTX *mem_ctx,
+ struct cldap_search *io)
+{
+ TALLOC_CTX *frame;
+ struct tevent_req *req;
+ struct tevent_context *ev;
+ NTSTATUS status;
+
+ if (cldap->searches.list) {
+ return NT_STATUS_PIPE_BUSY;
+ }
+
+ if (cldap->incoming.handler) {
+ return NT_STATUS_INVALID_PIPE_STATE;
+ }
+
+ frame = talloc_stackframe();
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ req = cldap_search_send(mem_ctx, ev, cldap, io);
+ if (req == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!tevent_req_poll(req, ev)) {
+ status = map_nt_error_from_unix_common(errno);
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ status = cldap_search_recv(req, mem_ctx, io);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+struct cldap_netlogon_state {
+ struct cldap_search search;
+};
+
+char *cldap_netlogon_create_filter(TALLOC_CTX *mem_ctx,
+ const struct cldap_netlogon *io)
+{
+ char *filter;
+
+ filter = talloc_asprintf(mem_ctx, "(&(NtVer=%s)",
+ ldap_encode_ndr_uint32(mem_ctx, io->in.version));
+
+ if (io->in.user) {
+ talloc_asprintf_addbuf(&filter, "(User=%s)", io->in.user);
+ }
+ if (io->in.host) {
+ talloc_asprintf_addbuf(&filter, "(Host=%s)", io->in.host);
+ }
+ if (io->in.realm) {
+ talloc_asprintf_addbuf(&filter, "(DnsDomain=%s)", io->in.realm);
+ }
+ if (io->in.acct_control != -1) {
+ talloc_asprintf_addbuf(
+ &filter,
+ "(AAC=%s)",
+ ldap_encode_ndr_uint32(mem_ctx, io->in.acct_control));
+ }
+ if (io->in.domain_sid) {
+ struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, io->in.domain_sid);
+
+ talloc_asprintf_addbuf(&filter, "(domainSid=%s)",
+ ldap_encode_ndr_dom_sid(mem_ctx, sid));
+ }
+ if (io->in.domain_guid) {
+ struct GUID guid;
+ GUID_from_string(io->in.domain_guid, &guid);
+
+ talloc_asprintf_addbuf(&filter, "(DomainGuid=%s)",
+ ldap_encode_ndr_GUID(mem_ctx, &guid));
+ }
+ talloc_asprintf_addbuf(&filter, ")");
+
+ return filter;
+}
+
+static void cldap_netlogon_state_done(struct tevent_req *subreq);
+/*
+ queue a cldap netlogon for send
+*/
+struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cldap_socket *cldap,
+ const struct cldap_netlogon *io)
+{
+ struct tevent_req *req, *subreq;
+ struct cldap_netlogon_state *state;
+ char *filter;
+ static const char * const attr[] = { "NetLogon", NULL };
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cldap_netlogon_state);
+ if (!req) {
+ return NULL;
+ }
+
+ filter = cldap_netlogon_create_filter(state, io);
+ if (tevent_req_nomem(filter, req)) {
+ goto post;
+ }
+
+ if (io->in.dest_address) {
+ state->search.in.dest_address = talloc_strdup(state,
+ io->in.dest_address);
+ if (tevent_req_nomem(state->search.in.dest_address, req)) {
+ goto post;
+ }
+ state->search.in.dest_port = io->in.dest_port;
+ } else {
+ state->search.in.dest_address = NULL;
+ state->search.in.dest_port = 0;
+ }
+ state->search.in.filter = filter;
+ state->search.in.attributes = attr;
+ state->search.in.timeout = 2;
+ state->search.in.retries = 2;
+
+ subreq = cldap_search_send(state, ev, cldap, &state->search);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq, cldap_netlogon_state_done, req);
+
+ return req;
+post:
+ return tevent_req_post(req, ev);
+}
+
+static void cldap_netlogon_state_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct cldap_netlogon_state *state = tevent_req_data(req,
+ struct cldap_netlogon_state);
+ NTSTATUS status;
+
+ status = cldap_search_recv(subreq, state, &state->search);
+ talloc_free(subreq);
+
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+/*
+ receive a cldap netlogon reply
+*/
+NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct cldap_netlogon *io)
+{
+ struct cldap_netlogon_state *state = tevent_req_data(req,
+ struct cldap_netlogon_state);
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ DATA_BLOB *data;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ goto failed;
+ }
+
+ if (state->search.out.response == NULL) {
+ status = NT_STATUS_NOT_FOUND;
+ goto failed;
+ }
+
+ if (state->search.out.response->num_attributes != 1 ||
+ strcasecmp(state->search.out.response->attributes[0].name, "netlogon") != 0 ||
+ state->search.out.response->attributes[0].num_values != 1 ||
+ state->search.out.response->attributes[0].values->length < 2) {
+ status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+ goto failed;
+ }
+ data = state->search.out.response->attributes[0].values;
+
+ status = pull_netlogon_samlogon_response(data, mem_ctx,
+ &io->out.netlogon);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ if (io->in.map_response) {
+ map_netlogon_samlogon_response(&io->out.netlogon);
+ }
+
+ status = NT_STATUS_OK;
+failed:
+ tevent_req_received(req);
+ return status;
+}
+
+/*
+ sync cldap netlogon search
+*/
+NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
+ TALLOC_CTX *mem_ctx,
+ struct cldap_netlogon *io)
+{
+ TALLOC_CTX *frame;
+ struct tevent_req *req;
+ struct tevent_context *ev;
+ NTSTATUS status;
+
+ if (cldap->searches.list) {
+ return NT_STATUS_PIPE_BUSY;
+ }
+
+ if (cldap->incoming.handler) {
+ return NT_STATUS_INVALID_PIPE_STATE;
+ }
+
+ frame = talloc_stackframe();
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ req = cldap_netlogon_send(mem_ctx, ev, cldap, io);
+ if (req == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!tevent_req_poll(req, ev)) {
+ status = map_nt_error_from_unix_common(errno);
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ status = cldap_netlogon_recv(req, mem_ctx, io);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+
+/*
+ send an empty reply (used on any error, so the client doesn't keep waiting
+ or send the bad request again)
+*/
+NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
+ uint32_t message_id,
+ struct tsocket_address *dest)
+{
+ NTSTATUS status;
+ struct cldap_reply reply;
+ struct ldap_Result result;
+
+ reply.messageid = message_id;
+ reply.dest = dest;
+ reply.response = NULL;
+ reply.result = &result;
+
+ ZERO_STRUCT(result);
+
+ status = cldap_reply_send(cldap, &reply);
+
+ return status;
+}
+
+/*
+ send an error reply (used on any error, so the client doesn't keep waiting
+ or send the bad request again)
+*/
+NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
+ uint32_t message_id,
+ struct tsocket_address *dest,
+ int resultcode,
+ const char *errormessage)
+{
+ NTSTATUS status;
+ struct cldap_reply reply;
+ struct ldap_Result result;
+
+ reply.messageid = message_id;
+ reply.dest = dest;
+ reply.response = NULL;
+ reply.result = &result;
+
+ ZERO_STRUCT(result);
+ result.resultcode = resultcode;
+ result.errormessage = errormessage;
+
+ status = cldap_reply_send(cldap, &reply);
+
+ return status;
+}
+
+
+/*
+ send a netlogon reply
+*/
+NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
+ uint32_t message_id,
+ struct tsocket_address *dest,
+ uint32_t version,
+ struct netlogon_samlogon_response *netlogon)
+{
+ NTSTATUS status;
+ struct cldap_reply reply;
+ struct ldap_SearchResEntry response;
+ struct ldap_Result result;
+ TALLOC_CTX *tmp_ctx = talloc_new(cldap);
+ DATA_BLOB blob;
+
+ status = push_netlogon_samlogon_response(&blob, tmp_ctx,
+ netlogon);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return status;
+ }
+ reply.messageid = message_id;
+ reply.dest = dest;
+ reply.response = &response;
+ reply.result = &result;
+
+ ZERO_STRUCT(result);
+
+ response.dn = "";
+ response.num_attributes = 1;
+ response.attributes = talloc(tmp_ctx, struct ldb_message_element);
+ NT_STATUS_HAVE_NO_MEMORY(response.attributes);
+ response.attributes->name = "netlogon";
+ response.attributes->num_values = 1;
+ response.attributes->values = &blob;
+
+ status = cldap_reply_send(cldap, &reply);
+
+ talloc_free(tmp_ctx);
+
+ return status;
+}
+
diff --git a/libcli/cldap/cldap.h b/libcli/cldap/cldap.h
new file mode 100644
index 0000000..cd76fee
--- /dev/null
+++ b/libcli/cldap/cldap.h
@@ -0,0 +1,134 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ a async CLDAP library
+
+ Copyright (C) Andrew Tridgell 2005
+
+ 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 "../libcli/netlogon/netlogon.h"
+
+struct ldap_message;
+struct tsocket_address;
+struct cldap_socket;
+
+struct cldap_incoming {
+ int recv_errno;
+ uint8_t *buf;
+ size_t len;
+ struct tsocket_address *src;
+ struct ldap_message *ldap_msg;
+};
+
+/*
+ a general cldap search request
+*/
+struct cldap_search {
+ struct {
+ const char *dest_address;
+ uint16_t dest_port;
+ const char *filter;
+ const char * const *attributes;
+ int timeout;
+ int retries;
+ } in;
+ struct {
+ struct ldap_SearchResEntry *response;
+ struct ldap_Result *result;
+ } out;
+};
+
+NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
+ const struct tsocket_address *local_addr,
+ const struct tsocket_address *remote_addr,
+ struct cldap_socket **_cldap);
+
+NTSTATUS cldap_set_incoming_handler(struct cldap_socket *cldap,
+ struct tevent_context *ev,
+ void (*handler)(struct cldap_socket *,
+ void *private_data,
+ struct cldap_incoming *),
+ void *private_data);
+struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cldap_socket *cldap,
+ const struct cldap_search *io);
+NTSTATUS cldap_search_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct cldap_search *io);
+NTSTATUS cldap_search(struct cldap_socket *cldap, TALLOC_CTX *mem_ctx,
+ struct cldap_search *io);
+
+/*
+ a general cldap reply
+*/
+struct cldap_reply {
+ uint32_t messageid;
+ struct tsocket_address *dest;
+ struct ldap_SearchResEntry *response;
+ struct ldap_Result *result;
+};
+
+NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io);
+
+NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
+ uint32_t message_id,
+ struct tsocket_address *dst);
+NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
+ uint32_t message_id,
+ struct tsocket_address *dst,
+ int resultcode,
+ const char *errormessage);
+
+/*
+ a netlogon cldap request
+*/
+struct cldap_netlogon {
+ struct {
+ const char *dest_address;
+ uint16_t dest_port;
+ const char *realm;
+ const char *host;
+ const char *user;
+ const char *domain_guid;
+ const char *domain_sid;
+ int acct_control;
+ uint32_t version;
+ bool map_response;
+ } in;
+ struct {
+ struct netlogon_samlogon_response netlogon;
+ } out;
+};
+
+struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cldap_socket *cldap,
+ const struct cldap_netlogon *io);
+NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct cldap_netlogon *io);
+NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
+ TALLOC_CTX *mem_ctx,
+ struct cldap_netlogon *io);
+char *cldap_netlogon_create_filter(TALLOC_CTX *mem_ctx,
+ const struct cldap_netlogon *io);
+
+NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
+ uint32_t message_id,
+ struct tsocket_address *dst,
+ uint32_t version,
+ struct netlogon_samlogon_response *netlogon);
+
diff --git a/libcli/cldap/wscript_build b/libcli/cldap/wscript_build
new file mode 100644
index 0000000..889c0af
--- /dev/null
+++ b/libcli/cldap/wscript_build
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+
+bld.SAMBA_LIBRARY('cli_cldap',
+ source='cldap.c',
+ public_deps='cli-ldap',
+ deps='LIBTSOCKET samba-util tevent-util ldb LIBCLI_NETLOGON',
+ private_library=True
+ )
+
diff --git a/libcli/dns/dns.c b/libcli/dns/dns.c
new file mode 100644
index 0000000..943b4d5
--- /dev/null
+++ b/libcli/dns/dns.c
@@ -0,0 +1,591 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Small async DNS library for Samba with socketwrapper support
+
+ Copyright (C) 2010 Kai Blin <kai@samba.org>
+
+ 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 "replace.h"
+#include "system/network.h"
+#include <tevent.h>
+#include "lib/tsocket/tsocket.h"
+#include "libcli/dns/libdns.h"
+#include "lib/util/tevent_unix.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/debug.h"
+#include "libcli/util/error.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/ndr_dns.h"
+
+struct dns_udp_request_state {
+ struct tevent_context *ev;
+ struct tdgram_context *dgram;
+ size_t query_len;
+ uint8_t *reply;
+ size_t reply_len;
+};
+
+#define DNS_REQUEST_TIMEOUT 10
+
+/* Declare callback functions used below. */
+static void dns_udp_request_get_reply(struct tevent_req *subreq);
+static void dns_udp_request_done(struct tevent_req *subreq);
+
+static struct tevent_req *dns_udp_request_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *server_addr_string,
+ const uint8_t *query,
+ size_t query_len)
+{
+ struct tevent_req *req, *subreq;
+ struct dns_udp_request_state *state;
+ struct tsocket_address *local_addr, *server_addr;
+ struct tdgram_context *dgram;
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct dns_udp_request_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+
+ /* Use connected UDP sockets */
+ ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0,
+ &local_addr);
+ if (ret != 0) {
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+
+ ret = tsocket_address_inet_from_hostport_strings(
+ state, "ip", server_addr_string, DNS_SERVICE_PORT, &server_addr);
+ if (ret != 0) {
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+
+ ret = tdgram_inet_udp_socket(local_addr, server_addr, state, &dgram);
+ if (ret != 0) {
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+
+ state->dgram = dgram;
+ state->query_len = query_len;
+
+ dump_data(10, query, query_len);
+
+ subreq = tdgram_sendto_send(state, ev, dgram, query, query_len, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (!tevent_req_set_endtime(req, ev,
+ timeval_current_ofs(DNS_REQUEST_TIMEOUT, 0))) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_callback(subreq, dns_udp_request_get_reply, req);
+ return req;
+}
+
+static void dns_udp_request_get_reply(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct dns_udp_request_state *state = tevent_req_data(req,
+ struct dns_udp_request_state);
+ ssize_t len;
+ int err = 0;
+
+ len = tdgram_sendto_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+
+ if (len == -1 && err != 0) {
+ tevent_req_error(req, err);
+ return;
+ }
+
+ if (len != state->query_len) {
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ subreq = tdgram_recvfrom_send(state, state->ev, state->dgram);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+
+ tevent_req_set_callback(subreq, dns_udp_request_done, req);
+}
+
+static void dns_udp_request_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct dns_udp_request_state *state = tevent_req_data(req,
+ struct dns_udp_request_state);
+
+ ssize_t len;
+ int err = 0;
+
+ len = tdgram_recvfrom_recv(subreq, &err, state, &state->reply, NULL);
+ TALLOC_FREE(subreq);
+
+ if (len == -1 && err != 0) {
+ tevent_req_error(req, err);
+ return;
+ }
+
+ state->reply_len = len;
+ dump_data(10, state->reply, state->reply_len);
+ tevent_req_done(req);
+}
+
+static int dns_udp_request_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **reply,
+ size_t *reply_len)
+{
+ struct dns_udp_request_state *state = tevent_req_data(req,
+ struct dns_udp_request_state);
+ int err;
+
+ if (tevent_req_is_unix_error(req, &err)) {
+ tevent_req_received(req);
+ return err;
+ }
+
+ *reply = talloc_move(mem_ctx, &state->reply);
+ *reply_len = state->reply_len;
+ tevent_req_received(req);
+
+ return 0;
+}
+
+struct dns_tcp_request_state {
+ struct tevent_context *ev;
+ struct tstream_context *stream;
+ const uint8_t *query;
+ size_t query_len;
+
+ uint8_t dns_msglen_hdr[2];
+ struct iovec iov[2];
+
+ size_t nread;
+ uint8_t *reply;
+};
+
+static void dns_tcp_request_connected(struct tevent_req *subreq);
+static void dns_tcp_request_sent(struct tevent_req *subreq);
+static int dns_tcp_request_next_vector(struct tstream_context *stream,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **_vector,
+ size_t *_count);
+static void dns_tcp_request_received(struct tevent_req *subreq);
+
+static struct tevent_req *dns_tcp_request_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *server_addr_string,
+ const uint8_t *query,
+ size_t query_len)
+{
+ struct tevent_req *req, *subreq;
+ struct dns_tcp_request_state *state;
+ struct tsocket_address *local, *remote;
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct dns_tcp_request_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->query = query;
+ state->query_len = query_len;
+
+ if (query_len > UINT16_MAX) {
+ tevent_req_error(req, EMSGSIZE);
+ return tevent_req_post(req, ev);
+ }
+
+ ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local);
+ if (ret != 0) {
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+
+ ret = tsocket_address_inet_from_hostport_strings(
+ state, "ip", server_addr_string, DNS_SERVICE_PORT, &remote);
+ if (ret != 0) {
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = tstream_inet_tcp_connect_send(state, state->ev,
+ local, remote);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, dns_tcp_request_connected, req);
+
+ return req;
+}
+
+static void dns_tcp_request_connected(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct dns_tcp_request_state *state = tevent_req_data(
+ req, struct dns_tcp_request_state);
+ int ret, err;
+
+ ret = tstream_inet_tcp_connect_recv(subreq, &err, state,
+ &state->stream, NULL);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, err);
+ return;
+ }
+
+ RSSVAL(state->dns_msglen_hdr, 0, state->query_len);
+ state->iov[0] = (struct iovec) {
+ .iov_base = state->dns_msglen_hdr,
+ .iov_len = sizeof(state->dns_msglen_hdr)
+ };
+ state->iov[1] = (struct iovec) {
+ .iov_base = discard_const_p(void, state->query),
+ .iov_len = state->query_len
+ };
+
+ subreq = tstream_writev_send(state, state->ev, state->stream,
+ state->iov, ARRAY_SIZE(state->iov));
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, dns_tcp_request_sent, req);
+}
+
+static void dns_tcp_request_sent(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct dns_tcp_request_state *state = tevent_req_data(
+ req, struct dns_tcp_request_state);
+ int ret, err;
+
+ ret = tstream_writev_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, err);
+ return;
+ }
+
+ subreq = tstream_readv_pdu_send(state, state->ev, state->stream,
+ dns_tcp_request_next_vector, state);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, dns_tcp_request_received, req);
+}
+
+static int dns_tcp_request_next_vector(struct tstream_context *stream,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **_vector,
+ size_t *_count)
+{
+ struct dns_tcp_request_state *state = talloc_get_type_abort(
+ private_data, struct dns_tcp_request_state);
+ struct iovec *vector;
+ uint16_t msglen;
+
+ if (state->nread == 0) {
+ vector = talloc_array(mem_ctx, struct iovec, 1);
+ if (vector == NULL) {
+ return -1;
+ }
+ vector[0] = (struct iovec) {
+ .iov_base = state->dns_msglen_hdr,
+ .iov_len = sizeof(state->dns_msglen_hdr)
+ };
+ state->nread = sizeof(state->dns_msglen_hdr);
+
+ *_vector = vector;
+ *_count = 1;
+ return 0;
+ }
+
+ if (state->nread == sizeof(state->dns_msglen_hdr)) {
+ msglen = RSVAL(state->dns_msglen_hdr, 0);
+
+ state->reply = talloc_array(state, uint8_t, msglen);
+ if (state->reply == NULL) {
+ return -1;
+ }
+
+ vector = talloc_array(mem_ctx, struct iovec, 1);
+ if (vector == NULL) {
+ return -1;
+ }
+ vector[0] = (struct iovec) {
+ .iov_base = state->reply,
+ .iov_len = msglen
+ };
+ state->nread += msglen;
+
+ *_vector = vector;
+ *_count = 1;
+ return 0;
+ }
+
+ *_vector = NULL;
+ *_count = 0;
+ return 0;
+}
+
+static void dns_tcp_request_received(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ int ret, err;
+
+ ret = tstream_readv_pdu_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, err);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static int dns_tcp_request_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **reply,
+ size_t *reply_len)
+{
+ struct dns_tcp_request_state *state = tevent_req_data(
+ req, struct dns_tcp_request_state);
+ int err;
+
+ if (tevent_req_is_unix_error(req, &err)) {
+ tevent_req_received(req);
+ return err;
+ }
+
+ *reply_len = talloc_array_length(state->reply);
+ *reply = talloc_move(mem_ctx, &state->reply);
+ tevent_req_received(req);
+
+ return 0;
+}
+
+struct dns_cli_request_state {
+ struct tevent_context *ev;
+ const char *nameserver;
+
+ uint16_t req_id;
+
+ DATA_BLOB query;
+
+ struct dns_name_packet *reply;
+};
+
+static void dns_cli_request_udp_done(struct tevent_req *subreq);
+static void dns_cli_request_tcp_done(struct tevent_req *subreq);
+
+struct tevent_req *dns_cli_request_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *nameserver,
+ const char *name,
+ enum dns_qclass qclass,
+ enum dns_qtype qtype)
+{
+ struct tevent_req *req, *subreq;
+ struct dns_cli_request_state *state;
+ struct dns_name_question question;
+ struct dns_name_packet out_packet;
+ enum ndr_err_code ndr_err;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct dns_cli_request_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->nameserver = nameserver;
+
+ DBG_DEBUG("Asking %s for %s/%d/%d via UDP\n", nameserver,
+ name, (int)qclass, (int)qtype);
+
+ generate_random_buffer((uint8_t *)&state->req_id,
+ sizeof(state->req_id));
+
+ question = (struct dns_name_question) {
+ .name = discard_const_p(char, name),
+ .question_type = qtype, .question_class = qclass
+ };
+
+ out_packet = (struct dns_name_packet) {
+ .id = state->req_id,
+ .operation = DNS_OPCODE_QUERY | DNS_FLAG_RECURSION_DESIRED,
+ .qdcount = 1,
+ .questions = &question
+ };
+
+ ndr_err = ndr_push_struct_blob(
+ &state->query, state, &out_packet,
+ (ndr_push_flags_fn_t)ndr_push_dns_name_packet);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ tevent_req_error(req, ndr_map_error2errno(ndr_err));
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = dns_udp_request_send(state, state->ev, state->nameserver,
+ state->query.data, state->query.length);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, dns_cli_request_udp_done, req);
+ return req;
+}
+
+static void dns_cli_request_udp_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct dns_cli_request_state *state = tevent_req_data(
+ req, struct dns_cli_request_state);
+ DATA_BLOB reply;
+ enum ndr_err_code ndr_err;
+ uint16_t reply_id, operation;
+ int ret;
+
+ ret = dns_udp_request_recv(subreq, state, &reply.data, &reply.length);
+ TALLOC_FREE(subreq);
+ if (tevent_req_error(req, ret)) {
+ return;
+ }
+
+ if (reply.length < 4) {
+ DBG_DEBUG("Short DNS packet: length=%zu\n", reply.length);
+ tevent_req_error(req, EINVAL);
+ return;
+ }
+
+ reply_id = PULL_BE_U16(reply.data, 0);
+ if (reply_id != state->req_id) {
+ DBG_DEBUG("Got id %"PRIu16", expected %"PRIu16"\n",
+ state->reply->id, state->req_id);
+ tevent_req_error(req, ENOMSG);
+ return;
+ }
+
+ operation = PULL_BE_U16(reply.data, 2);
+ if ((operation & DNS_FLAG_TRUNCATION) != 0) {
+ DBG_DEBUG("Reply was truncated, retrying TCP\n");
+ subreq = dns_tcp_request_send(
+ state,
+ state->ev,
+ state->nameserver,
+ state->query.data,
+ state->query.length);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, dns_cli_request_tcp_done, req);
+ return;
+ }
+
+ state->reply = talloc(state, struct dns_name_packet);
+ if (tevent_req_nomem(state->reply, req)) {
+ return;
+ }
+
+ ndr_err = ndr_pull_struct_blob(
+ &reply, state->reply, state->reply,
+ (ndr_pull_flags_fn_t)ndr_pull_dns_name_packet);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ tevent_req_error(req, ndr_map_error2errno(ndr_err));
+ return;
+ }
+ TALLOC_FREE(reply.data);
+
+ tevent_req_done(req);
+}
+
+static void dns_cli_request_tcp_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct dns_cli_request_state *state = tevent_req_data(
+ req, struct dns_cli_request_state);
+ DATA_BLOB reply;
+ enum ndr_err_code ndr_err;
+ int ret;
+
+ ret = dns_tcp_request_recv(subreq, state, &reply.data, &reply.length);
+ TALLOC_FREE(subreq);
+ if (tevent_req_error(req, ret)) {
+ return;
+ }
+
+ state->reply = talloc(state, struct dns_name_packet);
+ if (tevent_req_nomem(state->reply, req)) {
+ return;
+ }
+
+ ndr_err = ndr_pull_struct_blob(
+ &reply, state->reply, state->reply,
+ (ndr_pull_flags_fn_t)ndr_pull_dns_name_packet);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ tevent_req_error(req, ndr_map_error2errno(ndr_err));
+ return;
+ }
+ TALLOC_FREE(reply.data);
+
+ if (state->reply->id != state->req_id) {
+ DBG_DEBUG("Got id %"PRIu16", expected %"PRIu16"\n",
+ state->reply->id, state->req_id);
+ tevent_req_error(req, ENOMSG);
+ return;
+ }
+
+ DBG_DEBUG("Got op=%x %"PRIu16"/%"PRIu16"/%"PRIu16"/%"PRIu16
+ " recs\n", (int)state->reply->operation,
+ state->reply->qdcount, state->reply->ancount,
+ state->reply->nscount, state->reply->nscount);
+
+ tevent_req_done(req);
+}
+
+int dns_cli_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct dns_name_packet **reply)
+{
+ struct dns_cli_request_state *state = tevent_req_data(
+ req, struct dns_cli_request_state);
+ int err;
+
+ if (tevent_req_is_unix_error(req, &err)) {
+ return err;
+ }
+ *reply = talloc_move(mem_ctx, &state->reply);
+ return 0;
+}
diff --git a/libcli/dns/dns.h b/libcli/dns/dns.h
new file mode 100644
index 0000000..34a6cf5
--- /dev/null
+++ b/libcli/dns/dns.h
@@ -0,0 +1,64 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Internal DNS query structures
+ * Copyright (C) Gerald Carter 2006.
+ * Copyright (C) Andrew Bartlett 2011
+ *
+ * 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/>.
+ */
+
+/* DNS query section in replies */
+
+#ifndef __LIBCLI_DNS_DNS_H__
+#define __LIBCLI_DNS_DNS_H__
+
+#include "replace.h"
+#include "system/network.h"
+
+struct dns_query {
+ const char *hostname;
+ uint16_t type;
+ uint16_t in_class;
+};
+
+/* DNS RR record in reply */
+
+struct dns_rr {
+ const char *hostname;
+ uint16_t type;
+ uint16_t in_class;
+ uint32_t ttl;
+ uint16_t rdatalen;
+ uint8_t *rdata;
+};
+
+/* SRV records */
+
+struct dns_rr_srv {
+ const char *hostname;
+ uint16_t priority;
+ uint16_t weight;
+ uint16_t port;
+ size_t num_ips;
+ struct sockaddr_storage *ss_s; /* support multi-homed hosts */
+};
+
+/* NS records */
+
+struct dns_rr_ns {
+ const char *hostname;
+ struct sockaddr_storage ss;
+};
+
+#endif
diff --git a/libcli/dns/dns_lookup.c b/libcli/dns/dns_lookup.c
new file mode 100644
index 0000000..646d0a8
--- /dev/null
+++ b/libcli/dns/dns_lookup.c
@@ -0,0 +1,374 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Internal DNS query structures
+ * Copyright (C) Volker Lendecke 2018
+ *
+ * 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 "replace.h"
+#include "libcli/dns/dns_lookup.h"
+#include "libcli/dns/resolvconf.h"
+#include "libcli/dns/libdns.h"
+#include "lib/util/tevent_unix.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/debug.h"
+
+struct dns_lookup_state {
+ struct tevent_context *ev;
+ const char *name;
+ enum dns_qclass qclass;
+ enum dns_qtype qtype;
+
+ char **nameservers;
+ size_t num_nameservers;
+ size_t num_sent;
+
+ struct tevent_req **dns_subreqs;
+ struct tevent_req *wait_subreq;
+
+ struct dns_name_packet *reply;
+};
+
+static int dns_lookup_send_next(struct tevent_req *req);
+
+static void dns_lookup_done(struct tevent_req *subreq);
+static void dns_lookup_waited(struct tevent_req *subreq);
+
+struct tevent_req *dns_lookup_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ FILE *resolv_conf_fp,
+ const char *name,
+ enum dns_qclass qclass,
+ enum dns_qtype qtype)
+{
+ struct tevent_req *req;
+ struct dns_lookup_state *state;
+ FILE *fp = resolv_conf_fp;
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct dns_lookup_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->name = name;
+ state->qclass = qclass;
+ state->qtype = qtype;
+
+ if (resolv_conf_fp == NULL) {
+ const char *resolvconf = "/etc/resolv.conf";
+
+#ifdef ENABLE_SELFTEST
+ {
+ const char *envvar = getenv("RESOLV_CONF");
+ if (envvar != NULL) {
+ resolvconf = envvar;
+ }
+ }
+#endif
+
+ fp = fopen(resolvconf, "r");
+ if (fp == NULL) {
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+ }
+
+ ret = parse_resolvconf_fp(
+ fp,
+ state,
+ &state->nameservers,
+ &state->num_nameservers);
+
+ if (resolv_conf_fp == NULL) {
+ fclose(fp);
+ }
+
+ if (ret != 0) {
+ tevent_req_error(req, ret);
+ return tevent_req_post(req, ev);
+ }
+
+ if (state->num_nameservers == 0) {
+ /*
+ * glibc's getaddrinfo returns EAI_AGAIN when no
+ * nameservers are configured. EAGAIN seems closest.
+ */
+ tevent_req_error(req, EAGAIN);
+ return tevent_req_post(req, ev);
+ }
+
+ state->dns_subreqs = talloc_zero_array(
+ state,
+ struct tevent_req *,
+ state->num_nameservers);
+
+ if (tevent_req_nomem(state->dns_subreqs, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ ret = dns_lookup_send_next(req);
+ if (tevent_req_error(req, ret)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static int dns_lookup_send_next(struct tevent_req *req)
+{
+ struct dns_lookup_state *state = tevent_req_data(
+ req, struct dns_lookup_state);
+
+ DBG_DEBUG("Sending DNS request #%zu to %s\n",
+ state->num_sent,
+ state->nameservers[state->num_sent]);
+
+ state->dns_subreqs[state->num_sent] = dns_cli_request_send(
+ state->dns_subreqs,
+ state->ev,
+ state->nameservers[state->num_sent],
+ state->name,
+ state->qclass,
+ state->qtype);
+
+ if (state->dns_subreqs[state->num_sent] == NULL) {
+ return ENOMEM;
+ }
+ tevent_req_set_callback(state->dns_subreqs[state->num_sent],
+ dns_lookup_done,
+ req);
+ state->num_sent += 1;
+
+ if (state->num_sent == state->num_nameservers) {
+ /*
+ * No more nameservers left
+ */
+ DBG_DEBUG("cancelling wait_subreq\n");
+ TALLOC_FREE(state->wait_subreq);
+ return 0;
+ }
+
+ if (state->wait_subreq != NULL) {
+ /*
+ * This can happen if we fire the next request upon
+ * dns_cli_request returning a network-level error
+ */
+ return 0;
+ }
+
+ state->wait_subreq = tevent_wakeup_send(
+ state,
+ state->ev,
+ tevent_timeval_current_ofs(1, 0));
+ if (state->wait_subreq == NULL) {
+ return ENOMEM;
+ }
+ tevent_req_set_callback(state->wait_subreq, dns_lookup_waited, req);
+
+ return 0;
+}
+
+static void dns_lookup_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct dns_lookup_state *state = tevent_req_data(
+ req, struct dns_lookup_state);
+ int dns_cli_request_ret;
+ size_t i;
+
+ dns_cli_request_ret = dns_cli_request_recv(
+ subreq,
+ state,
+ &state->reply);
+
+ for (i = 0; i < state->num_nameservers; i++) {
+ if (state->dns_subreqs[i] == subreq) {
+ break;
+ }
+ }
+
+ TALLOC_FREE(subreq);
+
+ if (i == state->num_nameservers) {
+ /* should never happen */
+ DBG_WARNING("Failed to find subreq\n");
+ tevent_req_error(req, EINVAL);
+ return;
+ }
+ state->dns_subreqs[i] = NULL;
+
+ if (dns_cli_request_ret == 0) {
+ /*
+ * Success, cancel everything else
+ */
+ TALLOC_FREE(state->dns_subreqs);
+ TALLOC_FREE(state->wait_subreq);
+ tevent_req_done(req);
+ return;
+ }
+
+ DBG_DEBUG("dns_cli_request[%zu] returned %s\n", i,
+ strerror(dns_cli_request_ret));
+
+ if (state->num_sent < state->num_nameservers) {
+ /*
+ * We have a nameserver left to try
+ */
+ int ret;
+
+ ret = dns_lookup_send_next(req);
+ if (tevent_req_error(req, ret)) {
+ return;
+ }
+ }
+
+ DBG_DEBUG("looking for outstanding requests\n");
+
+ for (i = 0; i<state->num_nameservers; i++) {
+ if (state->dns_subreqs[i] != NULL) {
+ break;
+ }
+ }
+
+ DBG_DEBUG("i=%zu, num_nameservers=%zu\n",
+ i, state->num_nameservers);
+
+ if (i == state->num_nameservers) {
+ /*
+ * Report the lower-level error if we have nothing
+ * outstanding anymore
+ */
+ tevent_req_error(req, dns_cli_request_ret);
+ return;
+ }
+
+ /*
+ * Do nothing: We have other nameservers that might come back
+ * with something good.
+ */
+}
+
+static void dns_lookup_waited(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct dns_lookup_state *state = tevent_req_data(
+ req, struct dns_lookup_state);
+ int ret;
+ bool ok;
+
+ DBG_DEBUG("waited\n");
+
+ ok = tevent_wakeup_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!ok) {
+ tevent_req_oom(req);
+ return;
+ }
+ state->wait_subreq = NULL;
+
+ ret = dns_lookup_send_next(req);
+ if (tevent_req_error(req, ret)) {
+ return;
+ }
+
+ /*
+ * dns_lookup_send_next() has already triggered the next wakeup
+ */
+}
+
+int dns_lookup_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct dns_name_packet **reply)
+{
+ struct dns_lookup_state *state = tevent_req_data(
+ req, struct dns_lookup_state);
+ int err;
+
+ if (tevent_req_is_unix_error(req, &err)) {
+ return err;
+ }
+
+ *reply = talloc_move(mem_ctx, &state->reply);
+
+ tevent_req_received(req);
+ return 0;
+}
+
+int dns_lookup(FILE *resolv_conf_fp,
+ const char *name,
+ enum dns_qclass qclass,
+ enum dns_qtype qtype,
+ TALLOC_CTX *mem_ctx,
+ struct dns_name_packet **reply)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ int ret = ENOMEM;
+
+ ev = samba_tevent_context_init(mem_ctx);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = dns_lookup_send(ev, ev, resolv_conf_fp, name, qclass, qtype);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_unix(req, ev, &ret)) {
+ goto fail;
+ }
+ ret = dns_lookup_recv(req, mem_ctx, reply);
+fail:
+ TALLOC_FREE(ev);
+ return ret;
+}
+
+bool dns_res_rec_get_sockaddr(const struct dns_res_rec *rec,
+ struct sockaddr_storage *addr)
+{
+ sa_family_t family;
+ const char *src;
+ void *dst;
+ int ret;
+
+ switch (rec->rr_type) {
+ case DNS_QTYPE_A:
+ family = AF_INET;
+ src = rec->rdata.ipv4_record;
+ dst = &(((struct sockaddr_in *)addr)->sin_addr);
+ break;
+#ifdef HAVE_IPV6
+ case DNS_QTYPE_AAAA:
+ family = AF_INET6;
+ src = rec->rdata.ipv6_record;
+ dst = &(((struct sockaddr_in6 *)addr)->sin6_addr);
+ break;
+#endif
+ default:
+ /* We only care about IP addresses */
+ return false;
+ }
+
+ *addr = (struct sockaddr_storage) { .ss_family = family };
+
+ ret = inet_pton(family, src, dst);
+ if (ret != 1) {
+ DBG_DEBUG("inet_pton(%s) failed\n", src);
+ return false;
+ }
+
+ return true;
+}
diff --git a/libcli/dns/dns_lookup.h b/libcli/dns/dns_lookup.h
new file mode 100644
index 0000000..0c05e04
--- /dev/null
+++ b/libcli/dns/dns_lookup.h
@@ -0,0 +1,48 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Internal DNS query structures
+ * Copyright (C) Volker Lendecke 2018
+ *
+ * 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/>.
+ */
+
+#ifndef __LIBCLI_DNS_DNS_LOOKUP_H__
+#define __LIBCLI_DNS_DNS_LOOKUP_H__
+
+#include "replace.h"
+#include "system/network.h"
+#include <tevent.h>
+#include "lib/util/data_blob.h"
+#include "lib/util/time.h"
+#include "librpc/gen_ndr/dns.h"
+
+struct tevent_req *dns_lookup_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ FILE *resolv_conf_fp,
+ const char *name,
+ enum dns_qclass qclass,
+ enum dns_qtype qtype);
+int dns_lookup_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct dns_name_packet **reply);
+int dns_lookup(FILE *resolv_conf_fp,
+ const char *name,
+ enum dns_qclass qclass,
+ enum dns_qtype qtype,
+ TALLOC_CTX *mem_ctx,
+ struct dns_name_packet **reply);
+
+bool dns_res_rec_get_sockaddr(const struct dns_res_rec *rec,
+ struct sockaddr_storage *addr);
+
+#endif
diff --git a/libcli/dns/dns_lookuptest.c b/libcli/dns/dns_lookuptest.c
new file mode 100644
index 0000000..c8e0343
--- /dev/null
+++ b/libcli/dns/dns_lookuptest.c
@@ -0,0 +1,55 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Internal DNS query structures
+ * Copyright (C) Volker Lendecke 2018
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <talloc.h>
+#include <errno.h>
+#include "libcli/dns/dns_lookup.h"
+#include "lib/util/debug.h"
+
+static int dns_lookuptest1(void)
+{
+ struct dns_name_packet *reply = NULL;
+ int ret;
+
+ ret = dns_lookup(NULL, "www.samba.org", DNS_QCLASS_IN, DNS_QTYPE_A,
+ NULL, &reply);
+ if (ret != 0) {
+ fprintf(stderr, "dns_lookup failed: %s\n", strerror(ret));
+ return ret;
+ }
+
+ TALLOC_FREE(reply);
+ return 0;
+}
+
+int main(int argc, const char *argv[]) {
+ int ret;
+
+ setup_logging(argv[0], DEBUG_DEFAULT_STDERR);
+ debug_parse_levels("10");
+
+ ret = dns_lookuptest1();
+ if (ret != 0) {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/libcli/dns/libdns.h b/libcli/dns/libdns.h
new file mode 100644
index 0000000..15ca257
--- /dev/null
+++ b/libcli/dns/libdns.h
@@ -0,0 +1,43 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Small async DNS library for Samba with socketwrapper support
+
+ Copyright (C) 2012 Kai Blin <kai@samba.org>
+
+ 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/>.
+*/
+
+#ifndef __LIBDNS_H__
+#define __LIBDNS_H__
+
+#include "lib/util/data_blob.h"
+#include "lib/util/time.h"
+#include "librpc/gen_ndr/dns.h"
+
+/*
+ * DNS request with fallback to TCP on truncation
+ */
+
+struct tevent_req *dns_cli_request_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *nameserver,
+ const char *name,
+ enum dns_qclass qclass,
+ enum dns_qtype qtype);
+int dns_cli_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct dns_name_packet **reply);
+
+
+#endif /*__LIBDNS_H__*/
diff --git a/libcli/dns/resolvconf.c b/libcli/dns/resolvconf.c
new file mode 100644
index 0000000..5cf8b4e
--- /dev/null
+++ b/libcli/dns/resolvconf.c
@@ -0,0 +1,123 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Internal DNS query structures
+ * Copyright (C) Volker Lendecke 2018
+ *
+ * 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 "replace.h"
+#include <stdio.h>
+#include <errno.h>
+#include "libcli/dns/resolvconf.h"
+#include "lib/util/memory.h"
+
+int parse_resolvconf_fp(
+ FILE *fp,
+ TALLOC_CTX *mem_ctx,
+ char ***pnameservers,
+ size_t *pnum_nameservers)
+{
+ char *line = NULL;
+ size_t len = 0;
+ char **nameservers = NULL;
+ size_t num_nameservers = 0;
+ int ret = 0;
+
+ while (true) {
+ char *saveptr = NULL, *option = NULL, *ns = NULL;
+ char **tmp = NULL;
+ ssize_t n = 0;
+
+ n = getline(&line, &len, fp);
+ if (n < 0) {
+ if (!feof(fp)) {
+ /* real error */
+ ret = errno;
+ }
+ break;
+ }
+ if ((n > 0) && (line[n-1] == '\n')) {
+ line[n-1] = '\0';
+ }
+
+ if ((line[0] == '#') || (line[0] == ';')) {
+ continue;
+ }
+
+ option = strtok_r(line, " \t", &saveptr);
+ if (option == NULL) {
+ continue;
+ }
+
+ if (strcmp(option, "nameserver") != 0) {
+ continue;
+ }
+
+ ns = strtok_r(NULL, " \t", &saveptr);
+ if (ns == NULL) {
+ continue;
+ }
+
+ tmp = talloc_realloc(
+ mem_ctx,
+ nameservers,
+ char *,
+ num_nameservers+1);
+ if (tmp == NULL) {
+ ret = ENOMEM;
+ break;
+ }
+ nameservers = tmp;
+
+ nameservers[num_nameservers] = talloc_strdup(nameservers, ns);
+ if (nameservers[num_nameservers] == NULL) {
+ ret = ENOMEM;
+ break;
+ }
+ num_nameservers += 1;
+ }
+
+ SAFE_FREE(line);
+
+ if (ret == 0) {
+ *pnameservers = nameservers;
+ *pnum_nameservers = num_nameservers;
+ } else {
+ TALLOC_FREE(nameservers);
+ }
+
+ return ret;
+}
+
+int parse_resolvconf(
+ const char *resolvconf,
+ TALLOC_CTX *mem_ctx,
+ char ***pnameservers,
+ size_t *pnum_nameservers)
+{
+ FILE *fp;
+ int ret;
+
+ fp = fopen(resolvconf ? resolvconf : "/etc/resolv.conf", "r");
+ if (fp == NULL) {
+ return errno;
+ }
+
+ ret = parse_resolvconf_fp(fp, mem_ctx, pnameservers, pnum_nameservers);
+
+ fclose(fp);
+
+ return ret;
+}
diff --git a/libcli/dns/resolvconf.h b/libcli/dns/resolvconf.h
new file mode 100644
index 0000000..3ea258c
--- /dev/null
+++ b/libcli/dns/resolvconf.h
@@ -0,0 +1,37 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Internal DNS query structures
+ * Copyright (C) Volker Lendecke 2018
+ *
+ * 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/>.
+ */
+
+#ifndef __LIBCLI_DNS_RESOLVCONF_H__
+#define __LIBCLI_DNS_RESOLVCONF_H__
+
+#include <talloc.h>
+#include <stdio.h>
+
+int parse_resolvconf_fp(
+ FILE *fp,
+ TALLOC_CTX *mem_ctx,
+ char ***pnameservers,
+ size_t *pnum_nameservers);
+int parse_resolvconf(
+ const char *resolvconf,
+ TALLOC_CTX *mem_ctx,
+ char ***pnameservers,
+ size_t *pnum_nameservers);
+
+#endif
diff --git a/libcli/dns/resolvconftest.c b/libcli/dns/resolvconftest.c
new file mode 100644
index 0000000..6395264
--- /dev/null
+++ b/libcli/dns/resolvconftest.c
@@ -0,0 +1,82 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Internal DNS query structures
+ * Copyright (C) Volker Lendecke 2018
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <talloc.h>
+#include <errno.h>
+#include "libcli/dns/resolvconf.h"
+#include "lib/util/memory.h"
+
+static int resolvconftest1(void)
+{
+ const char *content =
+ "#foo\nbar\nnameserver 1.2.3.4\nnameserver 2.3.4.5";
+ char *file;
+ FILE *fp;
+ int ret;
+ char **nameservers;
+ size_t num_nameservers;
+
+ file = strdup(content);
+ if (file == NULL) {
+ perror("strdup failed");
+ return ENOMEM;
+ }
+ fp = fmemopen(file, strlen(file), "r");
+ if (fp == NULL) {
+ perror("fmemopen failed");
+ return errno;
+ }
+
+ ret = parse_resolvconf_fp(fp, NULL, &nameservers, &num_nameservers);
+ if (ret != 0) {
+ fprintf(stderr, "parse_resolvconf_fp failed: %s\n",
+ strerror(ret));
+ return ret;
+ }
+
+ if (num_nameservers != 2) {
+ fprintf(stderr, "expected 2 nameservers, got %zu\n",
+ num_nameservers);
+ return EIO;
+ }
+ if ((strcmp(nameservers[0], "1.2.3.4") != 0) ||
+ (strcmp(nameservers[1], "2.3.4.5") != 0)) {
+ fprintf(stderr, "got wrong nameservers\n");
+ return EIO;
+ }
+
+ TALLOC_FREE(nameservers);
+ fclose(fp);
+ SAFE_FREE(file);
+
+ return 0;
+}
+
+int main(void) {
+ int ret;
+
+ ret = resolvconftest1();
+ if (ret != 0) {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/libcli/dns/wscript_build b/libcli/dns/wscript_build
new file mode 100644
index 0000000..2d90aa7
--- /dev/null
+++ b/libcli/dns/wscript_build
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+bld.SAMBA_LIBRARY('clidns',
+ source='dns.c resolvconf.c',
+ public_deps='LIBTSOCKET tevent-util ndr-standard',
+ private_library=True)
+
+bld.SAMBA_BINARY('resolvconftest',
+ source='resolvconftest.c',
+ deps='clidns',
+ enabled=bld.CONFIG_SET('HAVE_FMEMOPEN'),
+ for_selftest=True)
+
+bld.SAMBA_SUBSYSTEM('dns_lookup',
+ source='dns_lookup.c',
+ public_deps='clidns')
+
+bld.SAMBA_BINARY('dns_lookuptest',
+ source='dns_lookuptest.c',
+ deps='dns_lookup',
+ for_selftest=True)
diff --git a/libcli/drsuapi/drsuapi.h b/libcli/drsuapi/drsuapi.h
new file mode 100644
index 0000000..3e1e5ce
--- /dev/null
+++ b/libcli/drsuapi/drsuapi.h
@@ -0,0 +1,32 @@
+/*
+ Unix SMB/CIFS implementation.
+ Helper functions for applying replicated objects
+
+ Copyright (C) Stefan Metzmacher <metze@samba.org> 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/>.
+
+*/
+
+WERROR drsuapi_decrypt_attribute(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *gensec_skey,
+ uint32_t rid,
+ uint32_t dsdb_repl_flags,
+ struct drsuapi_DsReplicaAttribute *attr);
+
+
+WERROR drsuapi_encrypt_attribute(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *gensec_skey,
+ uint32_t rid,
+ struct drsuapi_DsReplicaAttribute *attr);
diff --git a/libcli/drsuapi/repl_decrypt.c b/libcli/drsuapi/repl_decrypt.c
new file mode 100644
index 0000000..d289246
--- /dev/null
+++ b/libcli/drsuapi/repl_decrypt.c
@@ -0,0 +1,391 @@
+/*
+ Unix SMB/CIFS implementation.
+ Helper functions for applying replicated objects
+
+ Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
+
+ 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 "../lib/util/dlinklist.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/gen_ndr/ndr_drsuapi.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+#include "zlib.h"
+#include "../libcli/drsuapi/drsuapi.h"
+#include "libcli/auth/libcli_auth.h"
+#include "dsdb/samdb/samdb.h"
+
+#include "lib/crypto/gnutls_helpers.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+static WERROR drsuapi_decrypt_attribute_value(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *gensec_skey,
+ bool rid_crypt,
+ uint32_t rid,
+ const DATA_BLOB *in,
+ DATA_BLOB *out)
+{
+ DATA_BLOB confounder;
+ DATA_BLOB enc_buffer;
+
+ DATA_BLOB dec_buffer;
+
+ uint32_t crc32_given;
+ uint32_t crc32_calc;
+ DATA_BLOB checked_buffer;
+
+ DATA_BLOB plain_buffer;
+ WERROR result;
+ int rc;
+
+ /*
+ * users with rid == 0 should not exist
+ */
+ if (rid_crypt && rid == 0) {
+ return WERR_DS_DRA_INVALID_PARAMETER;
+ }
+
+ /*
+ * the first 16 bytes at the beginning are the confounder
+ * followed by the 4 byte crc32 checksum
+ */
+ if (in->length < 20) {
+ return WERR_DS_DRA_INVALID_PARAMETER;
+ }
+ confounder = data_blob_const(in->data, 16);
+ enc_buffer = data_blob_const(in->data + 16, in->length - 16);
+
+ /*
+ * decrypt with the encryption key, being md5 over the session
+ * key followed by the confounder. The parameter order to
+ * samba_gnutls_arcfour_confounded_md5() matters for this!
+ *
+ * here the gensec session key is used and
+ * not the dcerpc ncacn_ip_tcp "SystemLibraryDTC" key!
+ */
+
+ /*
+ * reference the encrypted buffer part and
+ * decrypt it using the created encryption key using arcfour
+ */
+ dec_buffer = data_blob_const(enc_buffer.data, enc_buffer.length);
+
+ rc = samba_gnutls_arcfour_confounded_md5(gensec_skey,
+ &confounder,
+ &dec_buffer,
+ SAMBA_GNUTLS_DECRYPT);
+ if (rc < 0) {
+ result = gnutls_error_to_werror(rc, WERR_INTERNAL_ERROR);
+ goto out;
+ }
+
+ /*
+ * the first 4 byte are the crc32 checksum
+ * of the remaining bytes
+ */
+ crc32_given = IVAL(dec_buffer.data, 0);
+ crc32_calc = crc32(0, Z_NULL, 0);
+ crc32_calc = crc32(crc32_calc,
+ dec_buffer.data + 4 ,
+ dec_buffer.length - 4);
+ checked_buffer = data_blob_const(dec_buffer.data + 4, dec_buffer.length - 4);
+
+ plain_buffer = data_blob_talloc(mem_ctx, checked_buffer.data, checked_buffer.length);
+ W_ERROR_HAVE_NO_MEMORY(plain_buffer.data);
+
+ if (crc32_given != crc32_calc) {
+ result = W_ERROR(HRES_ERROR_V(HRES_SEC_E_DECRYPT_FAILURE));
+ goto out;
+ }
+ /*
+ * The following rid_crypt obfuscation isn't session specific
+ * and not really needed here, because we always know the rid of the
+ * user account.
+ *
+ * some attributes with this 'additional encryption' include
+ * dBCSPwd, unicodePwd, ntPwdHistory, lmPwdHistory
+ *
+ * But for the rest of samba it's easier when we remove this static
+ * obfuscation here
+ */
+ if (rid_crypt) {
+ uint32_t i, num_hashes;
+
+ if ((checked_buffer.length % 16) != 0) {
+ result = WERR_DS_DRA_INVALID_PARAMETER;
+ goto out;
+ }
+
+ num_hashes = plain_buffer.length / 16;
+ for (i = 0; i < num_hashes; i++) {
+ uint32_t offset = i * 16;
+ rc = sam_rid_crypt(rid, checked_buffer.data + offset,
+ plain_buffer.data + offset,
+ SAMBA_GNUTLS_DECRYPT);
+ if (rc != 0) {
+ result = gnutls_error_to_werror(rc, WERR_INTERNAL_ERROR);
+ goto out;
+ }
+ }
+ }
+
+ *out = plain_buffer;
+ result = WERR_OK;
+out:
+ return result;
+}
+
+WERROR drsuapi_decrypt_attribute(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *gensec_skey,
+ uint32_t rid,
+ uint32_t dsdb_repl_flags,
+ struct drsuapi_DsReplicaAttribute *attr)
+{
+ WERROR status;
+ DATA_BLOB *enc_data;
+ DATA_BLOB plain_data;
+ bool rid_crypt = false;
+
+ if (attr->value_ctr.num_values == 0) {
+ return WERR_OK;
+ }
+
+ switch (attr->attid) {
+ case DRSUAPI_ATTID_dBCSPwd:
+ case DRSUAPI_ATTID_unicodePwd:
+ case DRSUAPI_ATTID_ntPwdHistory:
+ case DRSUAPI_ATTID_lmPwdHistory:
+ rid_crypt = true;
+ break;
+ case DRSUAPI_ATTID_supplementalCredentials:
+ case DRSUAPI_ATTID_priorValue:
+ case DRSUAPI_ATTID_currentValue:
+ case DRSUAPI_ATTID_trustAuthOutgoing:
+ case DRSUAPI_ATTID_trustAuthIncoming:
+ case DRSUAPI_ATTID_initialAuthOutgoing:
+ case DRSUAPI_ATTID_initialAuthIncoming:
+ break;
+ default:
+ return WERR_OK;
+ }
+
+ if (dsdb_repl_flags & DSDB_REPL_FLAG_EXPECT_NO_SECRETS) {
+ return WERR_TOO_MANY_SECRETS;
+ }
+
+ if (attr->value_ctr.num_values > 1) {
+ return WERR_DS_DRA_INVALID_PARAMETER;
+ }
+
+ if (!attr->value_ctr.values[0].blob) {
+ return WERR_DS_DRA_INVALID_PARAMETER;
+ }
+
+ enc_data = attr->value_ctr.values[0].blob;
+
+ status = drsuapi_decrypt_attribute_value(mem_ctx,
+ gensec_skey,
+ rid_crypt,
+ rid,
+ enc_data,
+ &plain_data);
+ W_ERROR_NOT_OK_RETURN(status);
+
+ talloc_free(attr->value_ctr.values[0].blob->data);
+ *attr->value_ctr.values[0].blob = plain_data;
+
+ return WERR_OK;
+}
+
+static WERROR drsuapi_encrypt_attribute_value(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *gensec_skey,
+ bool rid_crypt,
+ uint32_t rid,
+ const DATA_BLOB *in,
+ DATA_BLOB *out)
+{
+ DATA_BLOB rid_crypt_out = data_blob(NULL, 0);
+ DATA_BLOB confounder;
+
+ DATA_BLOB enc_buffer;
+
+ DATA_BLOB to_encrypt;
+
+ uint32_t crc32_calc;
+ WERROR result;
+ int rc;
+
+ /*
+ * users with rid == 0 should not exist
+ */
+ if (rid_crypt && rid == 0) {
+ return WERR_DS_DRA_INVALID_PARAMETER;
+ }
+
+ /*
+ * The following rid_crypt obfuscation isn't session specific
+ * and not really needed here, because we always know the rid of the
+ * user account.
+ *
+ * some attributes with this 'additional encryption' include
+ * dBCSPwd, unicodePwd, ntPwdHistory, lmPwdHistory
+ *
+ * But for the rest of samba it's easier when we remove this static
+ * obfuscation here
+ */
+ if (rid_crypt) {
+ uint32_t i, num_hashes;
+ rid_crypt_out = data_blob_talloc(mem_ctx, in->data, in->length);
+ W_ERROR_HAVE_NO_MEMORY(rid_crypt_out.data);
+
+ if ((rid_crypt_out.length % 16) != 0) {
+ return WERR_DS_DRA_INVALID_PARAMETER;
+ }
+
+ num_hashes = rid_crypt_out.length / 16;
+ for (i = 0; i < num_hashes; i++) {
+ uint32_t offset = i * 16;
+ rc = sam_rid_crypt(rid, in->data + offset,
+ rid_crypt_out.data + offset,
+ SAMBA_GNUTLS_ENCRYPT);
+ if (rc != 0) {
+ result = gnutls_error_to_werror(rc, WERR_INTERNAL_ERROR);
+ goto out;
+ }
+ }
+ in = &rid_crypt_out;
+ }
+
+ /*
+ * the first 16 bytes at the beginning are the confounder
+ * followed by the 4 byte crc32 checksum
+ */
+
+ enc_buffer = data_blob_talloc(mem_ctx, NULL, in->length+20);
+ if (!enc_buffer.data) {
+ talloc_free(rid_crypt_out.data);
+ return WERR_NOT_ENOUGH_MEMORY;
+ };
+
+ confounder = data_blob_const(enc_buffer.data, 16);
+ generate_random_buffer(confounder.data, confounder.length);
+
+ /*
+ * the first 4 byte are the crc32 checksum
+ * of the remaining bytes
+ */
+ crc32_calc = crc32(0, Z_NULL, 0);
+ crc32_calc = crc32(crc32_calc, in->data, in->length);
+ SIVAL(enc_buffer.data, 16, crc32_calc);
+
+ /*
+ * copy the plain buffer part and
+ * encrypt it using the created encryption key using arcfour
+ */
+ memcpy(enc_buffer.data+20, in->data, in->length);
+ talloc_free(rid_crypt_out.data);
+
+ to_encrypt = data_blob_const(enc_buffer.data+16,
+ enc_buffer.length-16);
+
+ /*
+ * encrypt with the encryption key, being md5 over the session
+ * key followed by the confounder. The parameter order to
+ * samba_gnutls_arcfour_confounded_md5() matters for this!
+ *
+ * here the gensec session key is used and
+ * not the dcerpc ncacn_ip_tcp "SystemLibraryDTC" key!
+ */
+
+ rc = samba_gnutls_arcfour_confounded_md5(gensec_skey,
+ &confounder,
+ &to_encrypt,
+ SAMBA_GNUTLS_ENCRYPT);
+ if (rc < 0) {
+ result = gnutls_error_to_werror(rc, WERR_INTERNAL_ERROR);
+ goto out;
+ }
+
+ *out = enc_buffer;
+ result = WERR_OK;
+out:
+ return result;
+}
+
+/*
+ encrypt a DRSUAPI attribute ready for sending over the wire
+ Only some attribute types are encrypted
+ */
+WERROR drsuapi_encrypt_attribute(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *gensec_skey,
+ uint32_t rid,
+ struct drsuapi_DsReplicaAttribute *attr)
+{
+ WERROR status;
+ DATA_BLOB *plain_data;
+ DATA_BLOB enc_data;
+ bool rid_crypt = false;
+
+ if (attr->value_ctr.num_values == 0) {
+ return WERR_OK;
+ }
+
+ switch (attr->attid) {
+ case DRSUAPI_ATTID_dBCSPwd:
+ case DRSUAPI_ATTID_unicodePwd:
+ case DRSUAPI_ATTID_ntPwdHistory:
+ case DRSUAPI_ATTID_lmPwdHistory:
+ rid_crypt = true;
+ break;
+ case DRSUAPI_ATTID_supplementalCredentials:
+ case DRSUAPI_ATTID_priorValue:
+ case DRSUAPI_ATTID_currentValue:
+ case DRSUAPI_ATTID_trustAuthOutgoing:
+ case DRSUAPI_ATTID_trustAuthIncoming:
+ case DRSUAPI_ATTID_initialAuthOutgoing:
+ case DRSUAPI_ATTID_initialAuthIncoming:
+ break;
+ default:
+ return WERR_OK;
+ }
+
+ if (attr->value_ctr.num_values > 1) {
+ return WERR_DS_DRA_INVALID_PARAMETER;
+ }
+
+ if (!attr->value_ctr.values[0].blob) {
+ return WERR_DS_DRA_INVALID_PARAMETER;
+ }
+
+ plain_data = attr->value_ctr.values[0].blob;
+
+ status = drsuapi_encrypt_attribute_value(mem_ctx,
+ gensec_skey,
+ rid_crypt,
+ rid,
+ plain_data,
+ &enc_data);
+ W_ERROR_NOT_OK_RETURN(status);
+
+ talloc_free(attr->value_ctr.values[0].blob->data);
+ *attr->value_ctr.values[0].blob = enc_data;
+
+ return WERR_OK;
+}
+
diff --git a/libcli/drsuapi/tests/test_repl_decrypt.c b/libcli/drsuapi/tests/test_repl_decrypt.c
new file mode 100644
index 0000000..996c6e6
--- /dev/null
+++ b/libcli/drsuapi/tests/test_repl_decrypt.c
@@ -0,0 +1,522 @@
+/*
+ * Unit tests for source4/rpc_server/dnsserver/dnsutils.c
+ *
+ * Copyright (C) Catalyst.NET Ltd 2018
+ * Copyright (C) Andrew Bartlett 2019
+ *
+ * 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/>.
+ *
+ */
+
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ *
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+
+#include "../repl_decrypt.c"
+
+
+/*
+ * test encryption and decryption including RID obfustincation
+ */
+static void test_drsuapi_rid_encrypt_decrypt_attribute_value(void **state)
+{
+ uint8_t key[] = { 0xa1, 0xb2, 0xc3, 0xd4,
+ 0xe1, 0xf2, 0x03, 0x14,
+ 0x21, 0x32, 0x43, 0x54,
+ 0x61, 0x72, 0x83, 0x94 };
+
+ uint8_t test_data[] = { 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04 };
+ const uint32_t rid = 514;
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ WERROR werr;
+
+ const DATA_BLOB key_blob = data_blob_const(key, sizeof(key));
+ const DATA_BLOB plaintext = data_blob_const(test_data,
+ sizeof(test_data));
+ DATA_BLOB encrypted;
+ DATA_BLOB decrypted = data_blob_null;
+
+ werr = drsuapi_encrypt_attribute_value(mem_ctx,
+ &key_blob,
+ true,
+ rid,
+ &plaintext,
+ &encrypted);
+
+ assert_int_equal(W_ERROR_V(werr), W_ERROR_V(WERR_OK));
+ assert_int_not_equal(encrypted.length, plaintext.length);
+
+ werr = drsuapi_decrypt_attribute_value(mem_ctx,
+ &key_blob,
+ true,
+ rid,
+ &encrypted,
+ &decrypted);
+
+ assert_int_equal(W_ERROR_V(werr), W_ERROR_V(WERR_OK));
+
+ assert_int_equal(decrypted.length, plaintext.length);
+
+ assert_memory_equal(decrypted.data, plaintext.data, plaintext.length);
+ TALLOC_FREE(mem_ctx);
+}
+
+/*
+ * test encryption and decryption failing RID obfustincation (data length)
+ */
+static void test_drsuapi_bad_len_rid_encrypt_decrypt_attribute_value(void **state)
+{
+ uint8_t key[] = { 0xa1, 0xb2, 0xc3, 0xd4,
+ 0xe1, 0xf2, 0x03, 0x14,
+ 0x21, 0x32, 0x43, 0x54,
+ 0x61, 0x72, 0x83, 0x94 };
+
+ uint8_t test_data[] = { 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04, 0x05 };
+ const uint32_t rid = 514;
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ WERROR werr;
+
+ const DATA_BLOB key_blob = data_blob_const(key, sizeof(key));
+ const DATA_BLOB plaintext = data_blob_const(test_data,
+ sizeof(test_data));
+ DATA_BLOB encrypted;
+
+ werr = drsuapi_encrypt_attribute_value(mem_ctx,
+ &key_blob,
+ true,
+ rid,
+ &plaintext,
+ &encrypted);
+
+ assert_int_equal(W_ERROR_V(werr),
+ W_ERROR_V(WERR_DS_DRA_INVALID_PARAMETER));
+ TALLOC_FREE(mem_ctx);
+}
+
+/*
+ * test encryption and decryption failing RID obfustincation (zero rid)
+ */
+static void test_drsuapi_zero_rid_encrypt_decrypt_attribute_value(void **state)
+{
+ uint8_t key[] = { 0xa1, 0xb2, 0xc3, 0xd4,
+ 0xe1, 0xf2, 0x03, 0x14,
+ 0x21, 0x32, 0x43, 0x54,
+ 0x61, 0x72, 0x83, 0x94 };
+
+ uint8_t test_data[] = { 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04 };
+ const uint32_t rid = 0;
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ WERROR werr;
+
+ const DATA_BLOB key_blob = data_blob_const(key, sizeof(key));
+ const DATA_BLOB plaintext = data_blob_const(test_data,
+ sizeof(test_data));
+ DATA_BLOB encrypted;
+
+ werr = drsuapi_encrypt_attribute_value(mem_ctx,
+ &key_blob,
+ true,
+ rid,
+ &plaintext,
+ &encrypted);
+
+ assert_int_equal(W_ERROR_V(werr), W_ERROR_V(WERR_DS_DRA_INVALID_PARAMETER));
+ TALLOC_FREE(mem_ctx);
+}
+
+/*
+ * test encryption and decryption without RID obfustication
+ */
+static void test_drsuapi_encrypt_decrypt_attribute_value(void **state)
+{
+ uint8_t key[] = { 0xa1, 0xb2, 0xc3, 0xd4,
+ 0xe1, 0xf2, 0x03, 0x14,
+ 0x21, 0x32, 0x43, 0x54,
+ 0x61, 0x72, 0x83, 0x94 };
+
+ /* Ensures we can cope with odd lengths */
+ uint8_t test_data[] = { 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04, 0x05 };
+
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ WERROR werr;
+
+ const DATA_BLOB key_blob = data_blob_const(key, sizeof(key));
+ const DATA_BLOB plaintext = data_blob_const(test_data,
+ sizeof(test_data));
+ DATA_BLOB encrypted;
+ DATA_BLOB decrypted = data_blob_null;
+
+ werr = drsuapi_encrypt_attribute_value(mem_ctx,
+ &key_blob,
+ false,
+ 0,
+ &plaintext,
+ &encrypted);
+
+ assert_int_equal(W_ERROR_V(werr), W_ERROR_V(WERR_OK));
+ assert_int_not_equal(encrypted.length, plaintext.length);
+
+ werr = drsuapi_decrypt_attribute_value(mem_ctx,
+ &key_blob,
+ false,
+ 0,
+ &encrypted,
+ &decrypted);
+
+ assert_int_equal(W_ERROR_V(werr), W_ERROR_V(WERR_OK));
+
+ assert_int_equal(decrypted.length, plaintext.length);
+
+ assert_memory_equal(decrypted.data, plaintext.data, plaintext.length);
+ TALLOC_FREE(mem_ctx);
+}
+
+/*
+ * test decryption of fixed buffer
+ */
+static void test_drsuapi_decrypt_attribute_value(void **state)
+{
+ uint8_t key[] = { 0xa1, 0xb2, 0xc3, 0xd4,
+ 0xe1, 0xf2, 0x03, 0x14,
+ 0x21, 0x32, 0x43, 0x54,
+ 0x61, 0x72, 0x83, 0x94 };
+
+ /* Ensures we can cope with odd lengths */
+ uint8_t test_data[] = { 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04, 0x05 };
+
+ uint8_t encrypted_test_data[] = { 0xFF, 0x5C, 0x58, 0x3F,
+ 0xD4, 0x41, 0xCA, 0xB0,
+ 0x14, 0xFE, 0xFB, 0xA6,
+ 0xB0, 0x32, 0x45, 0x45,
+ 0x9D, 0x76, 0x75, 0xD2,
+ 0xFB, 0x34, 0x77, 0xBD,
+ 0x8C, 0x1E, 0x09, 0x1A,
+ 0xF1, 0xAB, 0xD3, 0x0E,
+ 0xBE, 0x80, 0xAB, 0x19, 0xFC };
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ WERROR werr;
+
+ const DATA_BLOB key_blob = data_blob_const(key, sizeof(key));
+ const DATA_BLOB plaintext = data_blob_const(test_data,
+ sizeof(test_data));
+ const DATA_BLOB encrypted
+ = data_blob_const(encrypted_test_data,
+ sizeof(encrypted_test_data));
+ DATA_BLOB decrypted = data_blob_null;
+
+ werr = drsuapi_decrypt_attribute_value(mem_ctx,
+ &key_blob,
+ false,
+ 0,
+ &encrypted,
+ &decrypted);
+
+ assert_int_equal(W_ERROR_V(werr), W_ERROR_V(WERR_OK));
+
+ assert_int_equal(decrypted.length, plaintext.length);
+
+ assert_memory_equal(decrypted.data, plaintext.data, plaintext.length);
+ TALLOC_FREE(mem_ctx);
+}
+
+/*
+ * test decryption of fixed buffer (rid decrypt)
+ */
+static void test_drsuapi_rid_decrypt_attribute_value(void **state)
+{
+ uint8_t key[] = { 0xa1, 0xb2, 0xc3, 0xd4,
+ 0xe1, 0xf2, 0x03, 0x14,
+ 0x21, 0x32, 0x43, 0x54,
+ 0x61, 0x72, 0x83, 0x94 };
+
+ /* Ensures we can cope with odd lengths */
+ uint8_t test_data[] = { 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04 };
+
+ uint8_t encrypted_test_data[] = {0x95, 0xB2, 0xE8, 0x02,
+ 0x05, 0x5E, 0xFD, 0x3D,
+ 0x7D, 0x17, 0xB9, 0x76,
+ 0x4D, 0x91, 0xED, 0x59,
+ 0x98, 0x79, 0x7A, 0xFC,
+ 0x38, 0x73, 0x28, 0x55,
+ 0x62, 0x27, 0x99, 0x3B,
+ 0xD0, 0x18, 0xBD, 0x23,
+ 0x5D, 0x98, 0xFE, 0xA8};
+
+ const uint32_t rid = 514;
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ WERROR werr;
+
+ const DATA_BLOB key_blob = data_blob_const(key, sizeof(key));
+ const DATA_BLOB plaintext = data_blob_const(test_data,
+ sizeof(test_data));
+ const DATA_BLOB encrypted
+ = data_blob_const(encrypted_test_data,
+ sizeof(encrypted_test_data));
+ DATA_BLOB decrypted = data_blob_null;
+
+ werr = drsuapi_decrypt_attribute_value(mem_ctx,
+ &key_blob,
+ true,
+ rid,
+ &encrypted,
+ &decrypted);
+
+ assert_int_equal(W_ERROR_V(werr), W_ERROR_V(WERR_OK));
+
+ assert_int_equal(decrypted.length, plaintext.length);
+
+ assert_memory_equal(decrypted.data, plaintext.data, plaintext.length);
+
+ TALLOC_FREE(mem_ctx);
+}
+
+/*
+ * test decryption of fixed buffer (rid decrypt)
+ */
+static void test_drsuapi_bad_len_rid_decrypt_attribute_value(void **state)
+{
+ uint8_t key[] = { 0xa1, 0xb2, 0xc3, 0xd4,
+ 0xe1, 0xf2, 0x03, 0x14,
+ 0x21, 0x32, 0x43, 0x54,
+ 0x61, 0x72, 0x83, 0x94 };
+
+ uint8_t encrypted_test_data[] = { 0xFF, 0x5C, 0x58, 0x3F,
+ 0xD4, 0x41, 0xCA, 0xB0,
+ 0x14, 0xFE, 0xFB, 0xA6,
+ 0xB0, 0x32, 0x45, 0x45,
+ 0x9D, 0x76, 0x75, 0xD2,
+ 0xFB, 0x34, 0x77, 0xBD,
+ 0x8C, 0x1E, 0x09, 0x1A,
+ 0xF1, 0xAB, 0xD3, 0x0E,
+ 0xBE, 0x80, 0xAB, 0x19, 0xFC };
+
+ const uint32_t rid = 514;
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ WERROR werr;
+
+ const DATA_BLOB key_blob = data_blob_const(key, sizeof(key));
+ const DATA_BLOB encrypted
+ = data_blob_const(encrypted_test_data,
+ sizeof(encrypted_test_data));
+ DATA_BLOB decrypted;
+
+ werr = drsuapi_decrypt_attribute_value(mem_ctx,
+ &key_blob,
+ true,
+ rid,
+ &encrypted,
+ &decrypted);
+
+ assert_int_equal(W_ERROR_V(werr), W_ERROR_V(WERR_DS_DRA_INVALID_PARAMETER));
+
+ TALLOC_FREE(mem_ctx);
+}
+
+/*
+ * test decryption of fixed buffer (rid decrypt)
+ */
+static void test_drsuapi_zero_rid_decrypt_attribute_value(void **state)
+{
+ uint8_t key[] = { 0xa1, 0xb2, 0xc3, 0xd4,
+ 0xe1, 0xf2, 0x03, 0x14,
+ 0x21, 0x32, 0x43, 0x54,
+ 0x61, 0x72, 0x83, 0x94 };
+
+ uint8_t encrypted_test_data[] = { 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04, 0x05 };
+ const uint32_t rid = 0;
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ WERROR werr;
+
+ const DATA_BLOB key_blob = data_blob_const(key, sizeof(key));
+ const DATA_BLOB encrypted
+ = data_blob_const(encrypted_test_data,
+ sizeof(encrypted_test_data));
+ DATA_BLOB decrypted;
+
+ werr = drsuapi_decrypt_attribute_value(mem_ctx,
+ &key_blob,
+ true,
+ rid,
+ &encrypted,
+ &decrypted);
+
+ assert_int_equal(W_ERROR_V(werr), W_ERROR_V(WERR_DS_DRA_INVALID_PARAMETER));
+
+ TALLOC_FREE(mem_ctx);
+}
+
+/*
+ * test decryption of fixed buffer (bad crc)
+ */
+static void test_drsuapi_bad_crc_decrypt_attribute_value(void **state)
+{
+ uint8_t key[] = { 0xa1, 0xb2, 0xc3, 0xd4,
+ 0xe1, 0xf2, 0x03, 0x14,
+ 0x21, 0x32, 0x43, 0x54,
+ 0x61, 0x72, 0x83, 0x94 };
+
+ uint8_t encrypted_test_data[] = { 0xFF, 0x5C, 0x58, 0x3F,
+ 0xD4, 0x41, 0xCA, 0xB0,
+ 0x14, 0xFE, 0xFB, 0xA6,
+ 0xB0, 0x32, 0x45, 0x45,
+ 0x9D, 0x76, 0x75, 0xD2,
+ 0xFB, 0x34, 0x77, 0xBD,
+ 0x8C, 0x1E, 0x09, 0x1A,
+ 0xF1, 0xAB, 0xD3, 0x0E,
+ 0xBE, 0x80, 0xAB, 0x19, 0xFF };
+
+ const uint32_t rid = 514;
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ WERROR werr;
+
+ const DATA_BLOB key_blob = data_blob_const(key, sizeof(key));
+ const DATA_BLOB encrypted
+ = data_blob_const(encrypted_test_data,
+ sizeof(encrypted_test_data));
+ DATA_BLOB decrypted;
+
+ werr = drsuapi_decrypt_attribute_value(mem_ctx,
+ &key_blob,
+ true,
+ rid,
+ &encrypted,
+ &decrypted);
+
+ assert_int_equal(W_ERROR_V(werr), HRES_ERROR_V(HRES_SEC_E_DECRYPT_FAILURE));
+
+ TALLOC_FREE(mem_ctx);
+}
+
+/*
+ * test decryption of short buffer
+ */
+static void test_drsuapi_short_decrypt_attribute_value(void **state)
+{
+ uint8_t key[] = { 0xa1, 0xb2, 0xc3, 0xd4,
+ 0xe1, 0xf2, 0x03, 0x14,
+ 0x21, 0x32, 0x43, 0x54,
+ 0x61, 0x72, 0x83, 0x94 };
+
+ uint8_t encrypted_test_data[] = { 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04, 0x05 };
+ const uint32_t rid = 514;
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ WERROR werr;
+
+ const DATA_BLOB key_blob = data_blob_const(key, sizeof(key));
+ const DATA_BLOB encrypted
+ = data_blob_const(encrypted_test_data,
+ sizeof(encrypted_test_data));
+ DATA_BLOB decrypted;
+
+ werr = drsuapi_decrypt_attribute_value(mem_ctx,
+ &key_blob,
+ true,
+ rid,
+ &encrypted,
+ &decrypted);
+
+ assert_int_equal(W_ERROR_V(werr), W_ERROR_V(WERR_DS_DRA_INVALID_PARAMETER));
+
+ TALLOC_FREE(mem_ctx);
+}
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(
+ test_drsuapi_rid_encrypt_decrypt_attribute_value),
+ cmocka_unit_test(
+ test_drsuapi_bad_len_rid_encrypt_decrypt_attribute_value),
+ cmocka_unit_test(
+ test_drsuapi_zero_rid_encrypt_decrypt_attribute_value),
+ cmocka_unit_test(
+ test_drsuapi_encrypt_decrypt_attribute_value),
+ cmocka_unit_test(
+ test_drsuapi_decrypt_attribute_value),
+ cmocka_unit_test(
+ test_drsuapi_bad_crc_decrypt_attribute_value),
+ cmocka_unit_test(
+ test_drsuapi_rid_decrypt_attribute_value),
+ cmocka_unit_test(
+ test_drsuapi_zero_rid_decrypt_attribute_value),
+ cmocka_unit_test(
+ test_drsuapi_bad_len_rid_decrypt_attribute_value),
+ cmocka_unit_test(
+ test_drsuapi_short_decrypt_attribute_value),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/libcli/drsuapi/wscript_build b/libcli/drsuapi/wscript_build
new file mode 100644
index 0000000..1aee095
--- /dev/null
+++ b/libcli/drsuapi/wscript_build
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+
+
+bld.SAMBA_SUBSYSTEM('LIBCLI_DRSUAPI',
+ source='repl_decrypt.c',
+ public_deps='LIBCLI_AUTH samdb z'
+ )
+
+bld.SAMBA_BINARY(
+ 'test_repl_decrypt',
+ source='tests/test_repl_decrypt.c',
+ deps='''
+ LIBCLI_DRSUAPI
+ cmocka
+ talloc
+ ''',
+ for_selftest=True,
+ enabled=bld.AD_DC_BUILD_IS_ENABLED()
+)
diff --git a/libcli/echo/echo.c b/libcli/echo/echo.c
new file mode 100644
index 0000000..0f5f7f7
--- /dev/null
+++ b/libcli/echo/echo.c
@@ -0,0 +1,209 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Echo example async client library
+
+ Copyright (C) 2010 Kai Blin <kai@samba.org>
+
+ 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 "replace.h"
+#include "system/network.h"
+#include <tevent.h>
+#include "lib/tsocket/tsocket.h"
+#include "libcli/util/ntstatus.h"
+#include "libcli/echo/libecho.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "libcli/util/error.h"
+
+/*
+ * Following the Samba convention for async functions, set up a state struct
+ * for this set of calls. The state is always called function_name_state for
+ * the set of async functions related to function_name_send().
+ */
+struct echo_request_state {
+ struct tevent_context *ev;
+ ssize_t orig_len;
+ struct tdgram_context *dgram;
+ char *message;
+};
+
+/* Declare callback functions used below. */
+static void echo_request_get_reply(struct tevent_req *subreq);
+static void echo_request_done(struct tevent_req *subreq);
+
+struct tevent_req *echo_request_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *server_addr_string,
+ const char *message)
+{
+ struct tevent_req *req, *subreq;
+ struct echo_request_state *state;
+ struct tsocket_address *local_addr, *server_addr;
+ struct tdgram_context *dgram;
+ int ret;
+
+ /*
+ * Creating the initial tevent_req is the only place where returning
+ * NULL is allowed. Everything after that should return a more
+ * meaningful error using tevent_req_post().
+ */
+ req = tevent_req_create(mem_ctx, &state, struct echo_request_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ /*
+ * We need to dispatch new async functions in the callbacks, hold
+ * on to the event context.
+ */
+ state->ev = ev;
+
+ /* libecho uses connected UDP sockets, take care of this here */
+ ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0,
+ &local_addr);
+ if (ret != 0) {
+ tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
+ return tevent_req_post(req, ev);
+ }
+
+ ret = tsocket_address_inet_from_strings(state, "ip", server_addr_string,
+ ECHO_PORT, &server_addr);
+ if (ret != 0) {
+ tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
+ return tevent_req_post(req, ev);
+ }
+
+ ret = tdgram_inet_udp_socket(local_addr, server_addr, state, &dgram);
+ if (ret != 0) {
+ tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
+ return tevent_req_post(req, ev);
+ }
+
+ state->dgram = dgram;
+ state->orig_len = strlen(message) + 1;
+
+ /* Start of a subrequest for the actual data sending */
+ subreq = tdgram_sendto_send(state, ev, dgram,
+ (const uint8_t *) message,
+ state->orig_len, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * And tell tevent what to call when the subreq is done. Note that the
+ * original req structure is passed into the callback as callback data.
+ * This is used to get to the state struct in callbacks.
+ */
+ tevent_req_set_callback(subreq, echo_request_get_reply, req);
+ return req;
+}
+
+/*
+ * The following two callbacks both demonstrate the way of getting back the
+ * state struct in a callback function.
+ */
+
+static void echo_request_get_reply(struct tevent_req *subreq)
+{
+ /* Get the parent request struct from the callback data */
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ /* And get the state struct from the parent request struct */
+ struct echo_request_state *state = tevent_req_data(req,
+ struct echo_request_state);
+ ssize_t len;
+ int err = 0;
+
+ len = tdgram_sendto_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+
+ if (len == -1 && err != 0) {
+ tevent_req_nterror(req, map_nt_error_from_unix_common(err));
+ return;
+ }
+
+ if (len != state->orig_len) {
+ tevent_req_nterror(req, NT_STATUS_UNEXPECTED_NETWORK_ERROR);
+ return;
+ }
+
+ /* Send off the second subreq here, this time to receive the reply */
+ subreq = tdgram_recvfrom_send(state, state->ev, state->dgram);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+
+ /* And set the new callback */
+ tevent_req_set_callback(subreq, echo_request_done, req);
+ return;
+}
+
+static void echo_request_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct echo_request_state *state = tevent_req_data(req,
+ struct echo_request_state);
+
+ ssize_t len;
+ int err = 0;
+
+ len = tdgram_recvfrom_recv(subreq, &err, state,
+ (uint8_t **)&state->message,
+ NULL);
+ TALLOC_FREE(subreq);
+
+ if (len == -1 && err != 0) {
+ tevent_req_nterror(req, map_nt_error_from_unix_common(err));
+ return;
+ }
+
+ if (len != state->orig_len) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ state->message[len-1] = '\0';
+ /* Once the async function has completed, set tevent_req_done() */
+ tevent_req_done(req);
+}
+
+/*
+ * In the recv function, we usually need to move the data from the state struct
+ * to the memory area owned by the caller. Also, the function
+ * tevent_req_received() is called to take care of freeing the memory still
+ * associated with the request.
+ */
+
+NTSTATUS echo_request_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ char **message)
+{
+ struct echo_request_state *state = tevent_req_data(req,
+ struct echo_request_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ *message = talloc_move(mem_ctx, &state->message);
+ tevent_req_received(req);
+
+ return NT_STATUS_OK;
+}
diff --git a/libcli/echo/libecho.h b/libcli/echo/libecho.h
new file mode 100644
index 0000000..35a0986
--- /dev/null
+++ b/libcli/echo/libecho.h
@@ -0,0 +1,56 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Echo structures and headers, example async client library
+
+ Copyright (C) 2010 Kai Blin <kai@samba.org>
+
+ 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/>.
+*/
+
+#ifndef __LIBECHO_H__
+#define __LIBECHO_H__
+
+/* The echo port is fixed, so just set a constant. */
+#define ECHO_PORT 7
+
+/** Send an echo request to an echo server
+ *
+ *@param mem_ctx talloc memory context to use
+ *@param ev tevent context to use
+ *@param server_address address of the server as a string
+ *@param message echo message to send
+ *@return tevent_req with the active request or NULL on out-of-memory
+ */
+struct tevent_req *echo_request_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *server_address,
+ const char *message);
+
+/** Get the echo response from an echo server
+ *
+ * Once the echo_request_send async request is finished, you can call
+ * this function to collect the echo reply.
+ *
+ *@param req tevent_req struct returned from echo_request_send
+ *@param mem_ctx talloc memory context to use for the reply string
+ *@param message pointer to a string that will be allocated and filled with
+ the echo reply.
+ *@return NTSTATUS code depending on the async request result
+ */
+NTSTATUS echo_request_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ char **message);
+
+#endif /*__LIBECHO_H__*/
diff --git a/libcli/echo/tests/echo.c b/libcli/echo/tests/echo.c
new file mode 100644
index 0000000..e465b99
--- /dev/null
+++ b/libcli/echo/tests/echo.c
@@ -0,0 +1,97 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Example echo torture tests
+
+ Copyright (C) 2010 Kai Blin <kai@samba.org>
+
+ 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 "libcli/resolve/resolve.h"
+#include <tevent.h>
+#include "libcli/util/ntstatus.h"
+#include "libcli/echo/libecho.h"
+
+NTSTATUS torture_libcli_echo_init(TALLOC_CTX *);
+
+/* Basic test function that sends an echo request and checks the reply */
+static bool echo_udp_basic(struct torture_context *tctx, const char *address)
+{
+ struct tevent_req *req;
+ NTSTATUS status;
+ const char *msg_send = "This is a test string\n";
+ char *msg_recv;
+
+ req = echo_request_send(tctx, tctx->ev, address, msg_send);
+ torture_assert(tctx, req != NULL,
+ "echo_request_send returned non-null tevent_req");
+
+ while(tevent_req_is_in_progress(req)) {
+ tevent_loop_once(tctx->ev);
+ }
+
+ status = echo_request_recv(req, tctx, &msg_recv);
+ torture_assert_ntstatus_ok(tctx, status,
+ "echo_request_recv returned ok");
+
+ torture_assert_str_equal(tctx, msg_recv, msg_send,
+ "Echo server echoed request string");
+
+ return true;
+}
+
+/*Test case to set up the environment and perform UDP-based echo tests */
+static bool torture_echo_udp(struct torture_context *tctx)
+{
+ const char *address;
+ struct nbt_name name;
+ NTSTATUS status;
+ bool ret = true;
+
+ make_nbt_name_server(&name,
+ torture_setting_string(tctx, "host", NULL));
+ status = resolve_name_ex(lpcfg_resolve_context(tctx->lp_ctx),
+ 0, 0,
+ &name, tctx,
+ &address, tctx->ev);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to resolve %s - %s\n", name.name,
+ nt_errstr(status));
+ return false;
+ }
+
+ /* All tests are now called here */
+ ret &= echo_udp_basic(tctx, address);
+
+ return ret;
+}
+
+/* Test suite that bundles all the libecho tests */
+NTSTATUS torture_libcli_echo_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite;
+
+ suite = torture_suite_create(ctx, "echo");
+ NT_STATUS_HAVE_NO_MEMORY(suite);
+
+ torture_suite_add_simple_test(suite, "udp", torture_echo_udp);
+
+ suite->description = talloc_strdup(suite, "libcli/echo interface tests");
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/libcli/echo/tests/wscript_build b/libcli/echo/tests/wscript_build
new file mode 100644
index 0000000..366c895
--- /dev/null
+++ b/libcli/echo/tests/wscript_build
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+
+bld.SAMBA_MODULE('TORTURE_LIBCLI_ECHO',
+ source='echo.c',
+ subsystem='smbtorture',
+ init_function='torture_libcli_echo_init',
+ deps='LIBTSOCKET tevent-util LIBCLI_ECHO',
+ internal_module=True);
diff --git a/libcli/echo/wscript_build b/libcli/echo/wscript_build
new file mode 100644
index 0000000..a9de131
--- /dev/null
+++ b/libcli/echo/wscript_build
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+bld.SAMBA_SUBSYSTEM('LIBCLI_ECHO',
+ source='echo.c',
+ deps='LIBTSOCKET tevent-util');
+
+bld.RECURSE('tests')
diff --git a/libcli/http/gensec/basic.c b/libcli/http/gensec/basic.c
new file mode 100644
index 0000000..c7a1bbb
--- /dev/null
+++ b/libcli/http/gensec/basic.c
@@ -0,0 +1,204 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ HTTP library - Basic authentication mechanism gensec module
+
+ Copyright (C) 2014 Samuel Cabrero <samuelcabrero@kernevil.me>
+
+ 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 <tevent.h>
+#include "lib/util/tevent_ntstatus.h"
+#include "auth/auth.h"
+#include "auth/gensec/gensec.h"
+#include "auth/gensec/gensec_internal.h"
+#include "auth/credentials/credentials.h"
+#include "lib/util/base64.h"
+
+_PUBLIC_ NTSTATUS gensec_http_basic_init(TALLOC_CTX *);
+
+struct gensec_http_basic_state {
+ enum {
+ GENSEC_HTTP_BASIC_START,
+ GENSEC_HTTP_BASIC_DONE,
+ GENSEC_HTTP_BASIC_ERROR,
+ } step;
+};
+
+static NTSTATUS gensec_http_basic_client_start(struct gensec_security *gensec)
+{
+ struct gensec_http_basic_state *state;
+
+ state = talloc_zero(gensec, struct gensec_http_basic_state);
+ if (state == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ gensec->private_data = state;
+
+ state->step = GENSEC_HTTP_BASIC_START;
+
+ return NT_STATUS_OK;
+}
+
+struct gensec_http_basic_update_state {
+ NTSTATUS status;
+ DATA_BLOB out;
+};
+
+static NTSTATUS gensec_http_basic_update_internal(struct gensec_security *gensec_ctx,
+ TALLOC_CTX *mem_ctx,
+ const DATA_BLOB in,
+ DATA_BLOB *out);
+
+static struct tevent_req *gensec_http_basic_update_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct gensec_security *gensec_security,
+ const DATA_BLOB in)
+{
+ struct tevent_req *req = NULL;
+ struct gensec_http_basic_update_state *state = NULL;
+ NTSTATUS status;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct gensec_http_basic_update_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ status = gensec_http_basic_update_internal(gensec_security,
+ state, in,
+ &state->out);
+ state->status = status;
+ if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+ }
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+}
+
+static NTSTATUS gensec_http_basic_update_internal(struct gensec_security *gensec_ctx,
+ TALLOC_CTX *mem_ctx,
+ const DATA_BLOB in,
+ DATA_BLOB *out)
+{
+ struct gensec_http_basic_state *state;
+ struct cli_credentials *creds;
+ char *tmp, *b64;
+
+ state = talloc_get_type_abort(gensec_ctx->private_data,
+ struct gensec_http_basic_state);
+ creds = gensec_get_credentials(gensec_ctx);
+
+ switch (gensec_ctx->gensec_role) {
+ case GENSEC_CLIENT:
+ switch (state->step) {
+ case GENSEC_HTTP_BASIC_START:
+ tmp = talloc_asprintf(mem_ctx, "%s\\%s:%s",
+ cli_credentials_get_domain(creds),
+ cli_credentials_get_username(creds),
+ cli_credentials_get_password(creds));
+ if (tmp == NULL) {
+ state->step = GENSEC_HTTP_BASIC_ERROR;
+ return NT_STATUS_NO_MEMORY;
+ }
+ *out = data_blob_string_const(tmp);
+
+ b64 = base64_encode_data_blob(mem_ctx, *out);
+ if (b64 == NULL) {
+ state->step = GENSEC_HTTP_BASIC_ERROR;
+ return NT_STATUS_NO_MEMORY;
+ }
+ TALLOC_FREE(tmp);
+
+ tmp = talloc_asprintf(mem_ctx, "Basic %s", b64);
+ if (tmp == NULL) {
+ state->step = GENSEC_HTTP_BASIC_ERROR;
+ return NT_STATUS_NO_MEMORY;
+ }
+ TALLOC_FREE(b64);
+
+ *out = data_blob_string_const(tmp);
+ state->step = GENSEC_HTTP_BASIC_DONE;
+ return NT_STATUS_OK;
+
+ case GENSEC_HTTP_BASIC_DONE:
+ case GENSEC_HTTP_BASIC_ERROR:
+ default:
+ break;
+ }
+ state->step = GENSEC_HTTP_BASIC_ERROR;
+ return NT_STATUS_INTERNAL_ERROR;
+
+ case GENSEC_SERVER:
+ state->step = GENSEC_HTTP_BASIC_ERROR;
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ state->step = GENSEC_HTTP_BASIC_ERROR;
+ return NT_STATUS_INTERNAL_ERROR;
+}
+
+static NTSTATUS gensec_http_basic_update_recv(struct tevent_req *req,
+ TALLOC_CTX *out_mem_ctx,
+ DATA_BLOB *out)
+{
+ struct gensec_http_basic_update_state *state =
+ tevent_req_data(req,
+ struct gensec_http_basic_update_state);
+ NTSTATUS status;
+
+ *out = data_blob_null;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ *out = state->out;
+ talloc_steal(out_mem_ctx, state->out.data);
+ status = state->status;
+ tevent_req_received(req);
+ return status;
+}
+
+static const struct gensec_security_ops gensec_http_basic_security_ops = {
+ .name = "http_basic",
+ .auth_type = 0,
+ .client_start = gensec_http_basic_client_start,
+ .update_send = gensec_http_basic_update_send,
+ .update_recv = gensec_http_basic_update_recv,
+ .enabled = true,
+ .priority = GENSEC_EXTERNAL,
+};
+
+_PUBLIC_ NTSTATUS gensec_http_basic_init(TALLOC_CTX *ctx)
+{
+ NTSTATUS status;
+
+ status = gensec_register(ctx, &gensec_http_basic_security_ops);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Failed to register '%s' gensec backend!\n",
+ gensec_http_basic_security_ops.name));
+ return status;
+ }
+
+ return status;
+}
diff --git a/libcli/http/gensec/generic.c b/libcli/http/gensec/generic.c
new file mode 100644
index 0000000..2f09b9d
--- /dev/null
+++ b/libcli/http/gensec/generic.c
@@ -0,0 +1,286 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ HTTP library - NTLM authentication mechanism gensec module
+
+ Copyright (C) 2014 Samuel Cabrero <samuelcabrero@kernevil.me>
+
+ 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 <tevent.h>
+#include "lib/util/tevent_ntstatus.h"
+#include "auth/auth.h"
+#include "auth/gensec/gensec.h"
+#include "auth/gensec/gensec_internal.h"
+#include "lib/util/base64.h"
+
+#undef strncasecmp
+
+_PUBLIC_ NTSTATUS gensec_http_generic_init(TALLOC_CTX *);
+
+struct gensec_http_generic_state {
+ struct gensec_security *sub;
+ DATA_BLOB prefix;
+};
+
+static NTSTATUS gensec_http_generic_client_start(struct gensec_security *gensec,
+ const char *prefix_str,
+ const char *mech_oid)
+{
+ NTSTATUS status;
+ struct gensec_http_generic_state *state;
+
+ state = talloc_zero(gensec, struct gensec_http_generic_state);
+ if (state == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ gensec->private_data = state;
+
+ state->prefix = data_blob_string_const(prefix_str);
+
+ status = gensec_subcontext_start(state, gensec, &state->sub);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return gensec_start_mech_by_oid(state->sub, mech_oid);
+}
+
+static NTSTATUS gensec_http_ntlm_client_start(struct gensec_security *gensec)
+{
+ return gensec_http_generic_client_start(gensec, "NTLM",
+ GENSEC_OID_NTLMSSP);
+}
+
+static NTSTATUS gensec_http_negotiate_client_start(struct gensec_security *gensec)
+{
+ return gensec_http_generic_client_start(gensec, "Negotiate",
+ GENSEC_OID_SPNEGO);
+}
+
+struct gensec_http_generic_update_state {
+ struct gensec_security *gensec;
+ DATA_BLOB sub_in;
+ NTSTATUS status;
+ DATA_BLOB out;
+};
+
+static void gensec_http_generic_update_done(struct tevent_req *subreq);
+
+static struct tevent_req *gensec_http_generic_update_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct gensec_security *gensec_ctx,
+ const DATA_BLOB in)
+{
+ struct gensec_http_generic_state *http_generic =
+ talloc_get_type_abort(gensec_ctx->private_data,
+ struct gensec_http_generic_state);
+ struct tevent_req *req = NULL;
+ struct gensec_http_generic_update_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct gensec_http_generic_update_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->gensec = gensec_ctx;
+
+ if (in.length) {
+ int cmp;
+ DATA_BLOB b64b;
+ size_t skip = 0;
+
+ if (in.length < http_generic->prefix.length) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ cmp = strncasecmp((const char *)in.data,
+ (const char *)http_generic->prefix.data,
+ http_generic->prefix.length);
+ if (cmp != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ if (in.length == http_generic->prefix.length) {
+ /*
+ * We expect more data, but the
+ * server just sent the prefix without
+ * a space prefixing base64 data.
+ *
+ * It means the server rejects
+ * the request with.
+ */
+ tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
+ return tevent_req_post(req, ev);
+ }
+
+ if (in.data[http_generic->prefix.length] != ' ') {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+ skip = http_generic->prefix.length + 1;
+
+ b64b = data_blob_const(in.data + skip, in.length - skip);
+ if (b64b.length != 0) {
+ char *b64 = NULL;
+
+ /*
+ * ensure it's terminated with \0' before
+ * passing to base64_decode_data_blob_talloc().
+ */
+ b64 = talloc_strndup(state, (const char *)b64b.data,
+ b64b.length);
+ if (tevent_req_nomem(b64, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->sub_in = base64_decode_data_blob_talloc(state,
+ b64);
+ TALLOC_FREE(b64);
+ if (tevent_req_nomem(state->sub_in.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+ }
+ }
+
+ subreq = gensec_update_send(state, ev,
+ http_generic->sub,
+ state->sub_in);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, gensec_http_generic_update_done, req);
+
+ return req;
+}
+
+static void gensec_http_generic_update_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct gensec_http_generic_update_state *state =
+ tevent_req_data(req,
+ struct gensec_http_generic_update_state);
+ struct gensec_http_generic_state *http_generic =
+ talloc_get_type_abort(state->gensec->private_data,
+ struct gensec_http_generic_state);
+ NTSTATUS status;
+ DATA_BLOB sub_out = data_blob_null;
+ char *b64 = NULL;
+ char *str = NULL;
+ int prefix_length;
+
+ status = gensec_update_recv(subreq, state, &sub_out);
+ TALLOC_FREE(subreq);
+ state->status = status;
+ if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ status = NT_STATUS_OK;
+ }
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (sub_out.length == 0) {
+ tevent_req_done(req);
+ return;
+ }
+
+ b64 = base64_encode_data_blob(state, sub_out);
+ data_blob_free(&sub_out);
+ if (tevent_req_nomem(b64, req)) {
+ return;
+ }
+
+ prefix_length = http_generic->prefix.length;
+ str = talloc_asprintf(state, "%*.*s %s", prefix_length, prefix_length,
+ (const char *)http_generic->prefix.data, b64);
+ TALLOC_FREE(b64);
+ if (tevent_req_nomem(str, req)) {
+ return;
+ }
+
+ state->out = data_blob_string_const(str);
+ tevent_req_done(req);
+}
+
+static NTSTATUS gensec_http_generic_update_recv(struct tevent_req *req,
+ TALLOC_CTX *out_mem_ctx,
+ DATA_BLOB *out)
+{
+ struct gensec_http_generic_update_state *state =
+ tevent_req_data(req,
+ struct gensec_http_generic_update_state);
+ NTSTATUS status;
+
+ *out = data_blob_null;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ *out = state->out;
+ talloc_steal(out_mem_ctx, state->out.data);
+ status = state->status;
+ tevent_req_received(req);
+ return status;
+}
+
+static const struct gensec_security_ops gensec_http_ntlm_security_ops = {
+ .name = "http_ntlm",
+ .auth_type = 0,
+ .client_start = gensec_http_ntlm_client_start,
+ .update_send = gensec_http_generic_update_send,
+ .update_recv = gensec_http_generic_update_recv,
+ .enabled = true,
+ .priority = GENSEC_EXTERNAL,
+};
+
+static const struct gensec_security_ops gensec_http_negotiate_security_ops = {
+ .name = "http_negotiate",
+ .auth_type = 0,
+ .client_start = gensec_http_negotiate_client_start,
+ .update_send = gensec_http_generic_update_send,
+ .update_recv = gensec_http_generic_update_recv,
+ .enabled = true,
+ .priority = GENSEC_EXTERNAL,
+ .glue = true,
+};
+
+_PUBLIC_ NTSTATUS gensec_http_generic_init(TALLOC_CTX *ctx)
+{
+ NTSTATUS status;
+
+ status = gensec_register(ctx, &gensec_http_ntlm_security_ops);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Failed to register '%s' gensec backend!\n",
+ gensec_http_ntlm_security_ops.name));
+ return status;
+ }
+
+ status = gensec_register(ctx, &gensec_http_negotiate_security_ops);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Failed to register '%s' gensec backend!\n",
+ gensec_http_negotiate_security_ops.name));
+ return status;
+ }
+
+ return status;
+}
diff --git a/libcli/http/http.c b/libcli/http/http.c
new file mode 100644
index 0000000..96c573a
--- /dev/null
+++ b/libcli/http/http.c
@@ -0,0 +1,882 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ HTTP library
+
+ Copyright (C) 2013 Samuel Cabrero <samuelcabrero@kernevil.me>
+
+ 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 "lib/util/tevent_ntstatus.h"
+#include "http.h"
+#include "http_internal.h"
+#include "util/tevent_werror.h"
+#include "lib/util/dlinklist.h"
+
+#undef strcasecmp
+
+/**
+ * Determines if a response should have a body.
+ * @return 1 if the response MUST have a body; 0 if the response MUST NOT have
+ * a body. Returns -1 on error.
+ */
+static int http_response_needs_body(struct http_request *req)
+{
+ struct http_header *h = NULL;
+
+ if (!req) return -1;
+
+ for (h = req->headers; h != NULL; h = h->next) {
+ int cmp;
+ int n;
+ char c;
+ unsigned long long v;
+
+ cmp = strcasecmp(h->key, "Content-Length");
+ if (cmp != 0) {
+ continue;
+ }
+
+ n = sscanf(h->value, "%llu%c", &v, &c);
+ if (n != 1) {
+ return -1;
+ }
+
+ req->remaining_content_length = v;
+
+ if (v != 0) {
+ return 1;
+ }
+
+ return 0;
+ }
+
+ return 0;
+}
+
+struct http_read_response_state {
+ enum http_parser_state parser_state;
+ size_t max_headers_size;
+ uint64_t max_content_length;
+ DATA_BLOB buffer;
+ struct http_request *response;
+};
+
+/**
+ * Parses the HTTP headers
+ */
+static enum http_read_status http_parse_headers(struct http_read_response_state *state)
+{
+ enum http_read_status status = HTTP_ALL_DATA_READ;
+ char *ptr = NULL;
+ char *line = NULL;
+ char *key = NULL;
+ char *value = NULL;
+ int n = 0;
+ int ret;
+
+ /* Sanity checks */
+ if (!state || !state->response) {
+ DEBUG(0, ("%s: Invalid Parameter\n", __func__));
+ return HTTP_DATA_CORRUPTED;
+ }
+
+ if (state->buffer.length > state->max_headers_size) {
+ DEBUG(0, ("%s: Headers too long: %zi, maximum length is %zi\n", __func__,
+ state->buffer.length, state->max_headers_size));
+ return HTTP_DATA_TOO_LONG;
+ }
+
+ line = talloc_strndup(state, (char *)state->buffer.data, state->buffer.length);
+ if (!line) {
+ DEBUG(0, ("%s: Memory error\n", __func__));
+ return HTTP_DATA_CORRUPTED;
+ }
+
+ ptr = strstr(line, "\r\n");
+ if (ptr == NULL) {
+ TALLOC_FREE(line);
+ return HTTP_MORE_DATA_EXPECTED;
+ }
+
+ state->response->headers_size += state->buffer.length;
+
+ if (strncmp(line, "\r\n", 2) == 0) {
+ DEBUG(11,("%s: All headers read\n", __func__));
+
+ ret = http_response_needs_body(state->response);
+ switch (ret) {
+ case 1:
+ if (state->response->remaining_content_length <= state->max_content_length) {
+ DEBUG(11, ("%s: Start of read body\n", __func__));
+ state->parser_state = HTTP_READING_BODY;
+ break;
+ }
+ FALL_THROUGH;
+ case 0:
+ DEBUG(11, ("%s: Skipping body for code %d\n", __func__,
+ state->response->response_code));
+ state->parser_state = HTTP_READING_DONE;
+ break;
+ case -1:
+ DEBUG(0, ("%s_: Error in http_response_needs_body\n", __func__));
+ TALLOC_FREE(line);
+ return HTTP_DATA_CORRUPTED;
+ break;
+ }
+
+ TALLOC_FREE(line);
+ return HTTP_ALL_DATA_READ;
+ }
+
+ n = sscanf(line, "%m[^:]: %m[^\r\n]\r\n", &key, &value);
+ if (n != 2) {
+ DEBUG(0, ("%s: Error parsing header '%s'\n", __func__, line));
+ status = HTTP_DATA_CORRUPTED;
+ goto error;
+ }
+
+ if (http_add_header(state->response, &state->response->headers, key, value) == -1) {
+ DEBUG(0, ("%s: Error adding header\n", __func__));
+ status = HTTP_DATA_CORRUPTED;
+ goto error;
+ }
+
+error:
+ free(key);
+ free(value);
+ TALLOC_FREE(line);
+ return status;
+}
+
+/**
+ * Parses the first line of a HTTP response
+ */
+static bool http_parse_response_line(struct http_read_response_state *state)
+{
+ bool status = true;
+ char *protocol;
+ char *msg = NULL;
+ char major;
+ char minor;
+ int code;
+ char *line = NULL;
+ int n;
+
+ /* Sanity checks */
+ if (!state) {
+ DEBUG(0, ("%s: Input parameter is NULL\n", __func__));
+ return false;
+ }
+
+ line = talloc_strndup(state, (char*)state->buffer.data, state->buffer.length);
+ if (!line) {
+ DEBUG(0, ("%s: Memory error\n", __func__));
+ return false;
+ }
+
+ n = sscanf(line, "%m[^/]/%c.%c %d %m[^\r\n]\r\n",
+ &protocol, &major, &minor, &code, &msg);
+
+ DEBUG(11, ("%s: Header parsed(%i): protocol->%s, major->%c, minor->%c, "
+ "code->%d, message->%s\n", __func__, n, protocol, major, minor,
+ code, msg));
+
+ if (n != 5) {
+ DEBUG(0, ("%s: Error parsing header\n", __func__));
+ status = false;
+ goto error;
+ }
+
+ if (major != '1') {
+ DEBUG(0, ("%s: Bad HTTP major number '%c'\n", __func__, major));
+ status = false;
+ goto error;
+ }
+
+ if (code == 0) {
+ DEBUG(0, ("%s: Bad response code '%d'\n", __func__, code));
+ status = false;
+ goto error;
+ }
+
+ if (msg == NULL) {
+ DEBUG(0, ("%s: Error parsing HTTP data\n", __func__));
+ status = false;
+ goto error;
+ }
+
+ state->response->major = major;
+ state->response->minor = minor;
+ state->response->response_code = code;
+ state->response->response_code_line = talloc_strndup(state->response,
+ msg, strlen(msg));
+
+error:
+ free(protocol);
+ free(msg);
+ TALLOC_FREE(line);
+ return status;
+}
+
+/*
+ * Parses header lines from a request or a response into the specified
+ * request object given a buffer.
+ *
+ * Returns
+ * HTTP_DATA_CORRUPTED on error
+ * HTTP_MORE_DATA_EXPECTED when we need to read more headers
+ * HTTP_DATA_TOO_LONG on error
+ * HTTP_ALL_DATA_READ when all headers have been read
+ */
+static enum http_read_status http_parse_firstline(struct http_read_response_state *state)
+{
+ enum http_read_status status = HTTP_ALL_DATA_READ;
+ char *ptr = NULL;
+ char *line;
+
+ /* Sanity checks */
+ if (!state) {
+ DEBUG(0, ("%s: Invalid Parameter\n", __func__));
+ return HTTP_DATA_CORRUPTED;
+ }
+
+ if (state->buffer.length > state->max_headers_size) {
+ DEBUG(0, ("%s: Headers too long: %zi, maximum length is %zi\n", __func__,
+ state->buffer.length, state->max_headers_size));
+ return HTTP_DATA_TOO_LONG;
+ }
+
+ line = talloc_strndup(state, (char *)state->buffer.data, state->buffer.length);
+ if (!line) {
+ DEBUG(0, ("%s: Not enough memory\n", __func__));
+ return HTTP_DATA_CORRUPTED;
+ }
+
+ ptr = strstr(line, "\r\n");
+ if (ptr == NULL) {
+ TALLOC_FREE(line);
+ return HTTP_MORE_DATA_EXPECTED;
+ }
+
+ state->response->headers_size = state->buffer.length;
+ if (!http_parse_response_line(state)) {
+ status = HTTP_DATA_CORRUPTED;
+ }
+
+ /* Next state, read HTTP headers */
+ state->parser_state = HTTP_READING_HEADERS;
+
+ TALLOC_FREE(line);
+ return status;
+}
+
+static enum http_read_status http_read_body(struct http_read_response_state *state)
+{
+ struct http_request *resp = state->response;
+
+ if (state->buffer.length < resp->remaining_content_length) {
+ return HTTP_MORE_DATA_EXPECTED;
+ }
+
+ resp->body = state->buffer;
+ state->buffer = data_blob_null;
+ talloc_steal(resp, resp->body.data);
+ resp->remaining_content_length = 0;
+
+ state->parser_state = HTTP_READING_DONE;
+ return HTTP_ALL_DATA_READ;
+}
+
+static enum http_read_status http_read_trailer(struct http_read_response_state *state)
+{
+ enum http_read_status status = HTTP_DATA_CORRUPTED;
+ /* TODO */
+ return status;
+}
+
+static enum http_read_status http_parse_buffer(struct http_read_response_state *state)
+{
+ if (!state) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return HTTP_DATA_CORRUPTED;
+ }
+
+ switch (state->parser_state) {
+ case HTTP_READING_FIRSTLINE:
+ return http_parse_firstline(state);
+ case HTTP_READING_HEADERS:
+ return http_parse_headers(state);
+ case HTTP_READING_BODY:
+ return http_read_body(state);
+ break;
+ case HTTP_READING_TRAILER:
+ return http_read_trailer(state);
+ break;
+ case HTTP_READING_DONE:
+ /* All read */
+ return HTTP_ALL_DATA_READ;
+ default:
+ DEBUG(0, ("%s: Illegal parser state %d\n", __func__,
+ state->parser_state));
+ break;
+ }
+ return HTTP_DATA_CORRUPTED;
+}
+
+static int http_header_is_valid_value(const char *value)
+{
+ const char *p = NULL;
+
+ /* Sanity checks */
+ if (!value) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return -1;
+ }
+ p = value;
+
+ while ((p = strpbrk(p, "\r\n")) != NULL) {
+ /* Expect only one new line */
+ p += strspn(p, "\r\n");
+ /* Expect a space or tab for continuation */
+ if (*p != ' ' && *p != '\t')
+ return (0);
+ }
+ return 1;
+}
+
+static int http_add_header_internal(TALLOC_CTX *mem_ctx,
+ struct http_header **headers,
+ const char *key, const char *value,
+ bool replace)
+{
+ struct http_header *tail = NULL;
+ struct http_header *h = NULL;
+
+ /* Sanity checks */
+ if (!headers || !key || !value) {
+ DEBUG(0, ("Invalid parameter\n"));
+ return -1;
+ }
+
+
+
+ if (replace) {
+ for (h = *headers; h != NULL; h = h->next) {
+ if (strcasecmp(key, h->key) == 0) {
+ break;
+ }
+ }
+
+ if (h != NULL) {
+ /* Replace header value */
+ if (h->value) {
+ talloc_free(h->value);
+ }
+ h->value = talloc_strdup(h, value);
+ DEBUG(11, ("%s: Replaced HTTP header: key '%s', value '%s'\n",
+ __func__, h->key, h->value));
+ return 0;
+ }
+ }
+
+ /* Add new header */
+ h = talloc(mem_ctx, struct http_header);
+ h->key = talloc_strdup(h, key);
+ h->value = talloc_strdup(h, value);
+ DLIST_ADD_END(*headers, h);
+ tail = DLIST_TAIL(*headers);
+ if (tail != h) {
+ DEBUG(0, ("%s: Error adding header\n", __func__));
+ return -1;
+ }
+ DEBUG(11, ("%s: Added HTTP header: key '%s', value '%s'\n",
+ __func__, h->key, h->value));
+ return 0;
+}
+
+int http_add_header(TALLOC_CTX *mem_ctx,
+ struct http_header **headers,
+ const char *key, const char *value)
+{
+ if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
+ DEBUG(0, ("%s: Dropping illegal header key\n", __func__));
+ return -1;
+ }
+
+ if (!http_header_is_valid_value(value)) {
+ DEBUG(0, ("%s: Dropping illegal header value\n", __func__));
+ return -1;
+ }
+
+ return (http_add_header_internal(mem_ctx, headers, key, value, false));
+}
+
+int http_replace_header(TALLOC_CTX *mem_ctx,
+ struct http_header **headers,
+ const char *key, const char *value)
+{
+ if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
+ DEBUG(0, ("%s: Dropping illegal header key\n", __func__));
+ return -1;
+ }
+
+ if (!http_header_is_valid_value(value)) {
+ DEBUG(0, ("%s: Dropping illegal header value\n", __func__));
+ return -1;
+ }
+
+ return (http_add_header_internal(mem_ctx, headers, key, value, true));
+}
+
+/**
+ * Remove a header from the headers list.
+ *
+ * Returns 0, if the header was successfully removed.
+ * Returns -1, if the header could not be found.
+ */
+int http_remove_header(struct http_header **headers, const char *key)
+{
+ struct http_header *header;
+
+ /* Sanity checks */
+ if (!headers || !key) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return -1;
+ }
+
+ for(header = *headers; header != NULL; header = header->next) {
+ if (strcmp(key, header->key) == 0) {
+ DLIST_REMOVE(*headers, header);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int http_read_response_next_vector(struct tstream_context *stream,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **_vector,
+ size_t *_count)
+{
+ struct http_read_response_state *state;
+ struct iovec *vector;
+
+ /* Sanity checks */
+ if (!stream || !private_data || !_vector || !_count) {
+ DEBUG(0, ("%s: Invalid Parameter\n", __func__));
+ return -1;
+ }
+
+ state = talloc_get_type_abort(private_data, struct http_read_response_state);
+ vector = talloc_array(mem_ctx, struct iovec, 1);
+ if (!vector) {
+ DEBUG(0, ("%s: No more memory\n", __func__));
+ return -1;
+ }
+
+ if (state->buffer.data == NULL) {
+ /* Allocate buffer */
+ state->buffer.data = talloc_zero_array(state, uint8_t, 1);
+ if (!state->buffer.data) {
+ DEBUG(0, ("%s: No more memory\n", __func__));
+ return -1;
+ }
+ state->buffer.length = 1;
+
+ /* Return now, nothing to parse yet */
+ vector[0].iov_base = (void *)(state->buffer.data);
+ vector[0].iov_len = 1;
+ *_vector = vector;
+ *_count = 1;
+ return 0;
+ }
+
+ switch (http_parse_buffer(state)) {
+ case HTTP_ALL_DATA_READ:
+ if (state->parser_state == HTTP_READING_DONE) {
+ /* Full request or response parsed */
+ *_vector = NULL;
+ *_count = 0;
+ } else {
+ /* Free current buffer and allocate new one */
+ TALLOC_FREE(state->buffer.data);
+ state->buffer.data = talloc_zero_array(state, uint8_t, 1);
+ if (!state->buffer.data) {
+ return -1;
+ }
+ state->buffer.length = 1;
+
+ vector[0].iov_base = (void *)(state->buffer.data);
+ vector[0].iov_len = 1;
+ *_vector = vector;
+ *_count = 1;
+ }
+ break;
+ case HTTP_MORE_DATA_EXPECTED:
+ /* TODO Optimize, allocating byte by byte */
+ state->buffer.data = talloc_realloc(state, state->buffer.data,
+ uint8_t, state->buffer.length + 1);
+ if (!state->buffer.data) {
+ return -1;
+ }
+ state->buffer.length++;
+ vector[0].iov_base = (void *)(state->buffer.data +
+ state->buffer.length - 1);
+ vector[0].iov_len = 1;
+ *_vector = vector;
+ *_count = 1;
+ break;
+ case HTTP_DATA_CORRUPTED:
+ case HTTP_REQUEST_CANCELED:
+ case HTTP_DATA_TOO_LONG:
+ return -1;
+ break;
+ default:
+ DEBUG(0, ("%s: Unexpected status\n", __func__));
+ break;
+ }
+ return 0;
+}
+
+
+/**
+ * Reads a HTTP response
+ */
+static void http_read_response_done(struct tevent_req *);
+struct tevent_req *http_read_response_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct http_conn *http_conn,
+ size_t max_content_length)
+{
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ struct http_read_response_state *state;
+
+ DEBUG(11, ("%s: Reading HTTP response\n", __func__));
+
+ /* Sanity checks */
+ if (ev == NULL || http_conn == NULL) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return NULL;
+ }
+
+ req = tevent_req_create(mem_ctx, &state, struct http_read_response_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->max_headers_size = HTTP_MAX_HEADER_SIZE;
+ state->max_content_length = (uint64_t)max_content_length;
+ state->parser_state = HTTP_READING_FIRSTLINE;
+ state->response = talloc_zero(state, struct http_request);
+ if (tevent_req_nomem(state->response, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = tstream_readv_pdu_send(state, ev, http_conn->tstreams.active,
+ http_read_response_next_vector,
+ state);
+ if (tevent_req_nomem(subreq,req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, http_read_response_done, req);
+
+ return req;
+}
+
+static void http_read_response_done(struct tevent_req *subreq)
+{
+ NTSTATUS status;
+ struct tevent_req *req;
+ int ret;
+ int sys_errno;
+
+ if (!subreq) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return;
+ }
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+
+ ret = tstream_readv_pdu_recv(subreq, &sys_errno);
+ DEBUG(11, ("%s: HTTP response read (%d bytes)\n", __func__, ret));
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ status = map_nt_error_from_unix_common(sys_errno);
+ DEBUG(0, ("%s: Failed to read HTTP response: %s\n",
+ __func__, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS http_read_response_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct http_request **response)
+{
+ NTSTATUS status;
+ struct http_read_response_state *state;
+
+ if (!mem_ctx || !response || !req) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ state = tevent_req_data(req, struct http_read_response_state);
+ *response = state->response;
+ talloc_steal(mem_ctx, state->response);
+
+ tevent_req_received(req);
+
+ return NT_STATUS_OK;
+}
+
+static const char *http_method_str(enum http_cmd_type type)
+{
+ const char *method;
+
+ switch (type) {
+ case HTTP_REQ_POST:
+ method = "POST";
+ break;
+ case HTTP_REQ_RPC_IN_DATA:
+ method = "RPC_IN_DATA";
+ break;
+ case HTTP_REQ_RPC_OUT_DATA:
+ method = "RPC_OUT_DATA";
+ break;
+ default:
+ method = NULL;
+ break;
+ }
+
+ return method;
+}
+
+static NTSTATUS http_push_request_line(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *buffer,
+ const struct http_request *req)
+{
+ const char *method;
+ char *str;
+
+ /* Sanity checks */
+ if (!buffer || !req) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ method = http_method_str(req->type);
+ if (method == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ str = talloc_asprintf(mem_ctx, "%s %s HTTP/%c.%c\r\n", method,
+ req->uri, req->major, req->minor);
+ if (str == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ if (!data_blob_append(mem_ctx, buffer, str, strlen(str))) {
+ talloc_free(str);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ talloc_free(str);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS http_push_headers(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob,
+ struct http_request *req)
+{
+ struct http_header *header = NULL;
+ char *header_str = NULL;
+ size_t len;
+
+ /* Sanity checks */
+ if (!blob || !req) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ for (header = req->headers; header != NULL; header = header->next) {
+ header_str = talloc_asprintf(mem_ctx, "%s: %s\r\n",
+ header->key, header->value);
+ if (header_str == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ len = strlen(header_str);
+ if (!data_blob_append(mem_ctx, blob, header_str, len)) {
+ talloc_free(header_str);
+ return NT_STATUS_NO_MEMORY;
+ }
+ talloc_free(header_str);
+ }
+
+ if (!data_blob_append(mem_ctx, blob, "\r\n",2)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS http_push_body(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob,
+ struct http_request *req)
+{
+ /* Sanity checks */
+ if (!blob || !req) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (req->body.length) {
+ if (!data_blob_append(mem_ctx, blob, req->body.data,
+ req->body.length)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+struct http_send_request_state {
+ struct tevent_context *ev;
+ struct loadparm_context *lp_ctx;
+ struct cli_credentials *credentials;
+ struct http_request *request;
+ DATA_BLOB buffer;
+ struct iovec iov;
+ ssize_t nwritten;
+ int sys_errno;
+};
+
+/**
+ * Sends and HTTP request
+ */
+static void http_send_request_done(struct tevent_req *);
+struct tevent_req *http_send_request_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct http_conn *http_conn,
+ struct http_request *request)
+{
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ struct http_send_request_state *state = NULL;
+ NTSTATUS status;
+
+ DEBUG(11, ("%s: Sending HTTP request\n", __func__));
+
+ /* Sanity checks */
+ if (ev == NULL || request == NULL || http_conn == NULL) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return NULL;
+ }
+
+ req = tevent_req_create(mem_ctx, &state, struct http_send_request_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->request = request;
+
+ /* Push the request line */
+ status = http_push_request_line(state, &state->buffer, state->request);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+
+ /* Push the headers */
+ status = http_push_headers(mem_ctx, &state->buffer, request);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+
+ /* Push the body */
+ status = http_push_body(mem_ctx, &state->buffer, request);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+
+ state->iov.iov_base = (char *) state->buffer.data;
+ state->iov.iov_len = state->buffer.length;
+ subreq = tstream_writev_queue_send(state,
+ ev,
+ http_conn->tstreams.active,
+ http_conn->send_queue,
+ &state->iov, 1);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, http_send_request_done, req);
+
+ return req;
+}
+
+static void http_send_request_done(struct tevent_req *subreq)
+{
+ NTSTATUS status;
+ struct tevent_req *req;
+ struct http_send_request_state *state;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct http_send_request_state);
+
+ state->nwritten = tstream_writev_queue_recv(subreq, &state->sys_errno);
+ TALLOC_FREE(subreq);
+ if (state->nwritten == -1 && state->sys_errno != 0) {
+ status = map_nt_error_from_unix_common(state->sys_errno);
+ DEBUG(0, ("%s: Failed to send HTTP request: %s\n",
+ __func__, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS http_send_request_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (!req) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+
+ return NT_STATUS_OK;
+}
diff --git a/libcli/http/http.h b/libcli/http/http.h
new file mode 100644
index 0000000..8941547
--- /dev/null
+++ b/libcli/http/http.h
@@ -0,0 +1,143 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ HTTP library
+
+ Copyright (C) 2013 Samuel Cabrero <samuelcabrero@kernevil.me>
+
+ 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/>.
+*/
+
+#ifndef _HTTP_H_
+#define _HTTP_H_
+
+#include <limits.h>
+#include <sys/uio.h>
+
+#include <tevent.h>
+#include "lib/tsocket/tsocket.h"
+
+/* Response codes */
+#define HTTP_OK 200 /* request completed ok */
+#define HTTP_NOCONTENT 204 /* request does not have content */
+#define HTTP_MOVEPERM 301 /* uri moved permanently */
+#define HTTP_MOVETEMP 302 /* uri moved temporarily */
+#define HTTP_NOTMODIFIED 304 /* page was not modified from last */
+#define HTTP_BADREQUEST 400 /* invalid http request was made */
+#define HTTP_NOTFOUND 404 /* could not find content for uri */
+#define HTTP_BADMETHOD 405 /* method not allowed for this uri */
+#define HTTP_ENTITYTOOLARGE 413 /* */
+#define HTTP_EXPECTATIONFAILED 417 /* can't handle this expectation */
+#define HTTP_INTERNAL 500 /* internal error */
+#define HTTP_NOTIMPLEMENTED 501 /* not implemented */
+#define HTTP_SERVUNAVAIL 503 /* server is not available */
+
+#define HTTP_MAX_HEADER_SIZE 0x1FFFF
+
+struct cli_credentials;
+
+enum http_cmd_type {
+ HTTP_REQ_GET = 1 << 0,
+ HTTP_REQ_POST = 1 << 1,
+ HTTP_REQ_HEAD = 1 << 2,
+ HTTP_REQ_PUT = 1 << 3,
+ HTTP_REQ_DELETE = 1 << 4,
+ HTTP_REQ_OPTIONS = 1 << 5,
+ HTTP_REQ_TRACE = 1 << 6,
+ HTTP_REQ_CONNECT = 1 << 7,
+ HTTP_REQ_PATCH = 1 << 8,
+ HTTP_REQ_RPC_IN_DATA = 1 << 9,
+ HTTP_REQ_RPC_OUT_DATA = 1 << 10,
+};
+
+enum http_auth_method {
+ HTTP_AUTH_BASIC=1,
+ HTTP_AUTH_NTLM,
+ HTTP_AUTH_NEGOTIATE,
+};
+
+struct http_header {
+ struct http_header *next, *prev;
+ char *key;
+ char *value;
+};
+
+struct http_request {
+ enum http_cmd_type type; /* HTTP command type */
+ char major; /* HTTP version major number */
+ char minor; /* HTTP version minor number */
+ char *uri; /* URI after HTTP request was parsed */
+ struct http_header *headers;
+ size_t headers_size;
+ unsigned int response_code; /* HTTP response code */
+ char *response_code_line; /* Readable response */
+ uint64_t remaining_content_length; /* data not represent in body */
+ DATA_BLOB body;
+};
+
+/* HTTP header handling functions */
+int http_remove_header(struct http_header **, const char *);
+int http_add_header(TALLOC_CTX *, struct http_header **, const char *, const char *);
+int http_replace_header(TALLOC_CTX *, struct http_header **, const char *, const char *);
+
+/* HTTP(s) connect */
+
+struct http_conn;
+struct tstream_tls_params;
+
+struct tevent_req *http_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *http_server,
+ uint16_t http_port,
+ struct cli_credentials *credentials,
+ struct tstream_tls_params *tls_params);
+int http_connect_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct http_conn **http_conn);
+
+struct tevent_req *http_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct http_conn *http_conn);
+int http_disconnect_recv(struct tevent_req *req);
+
+struct tevent_queue *http_conn_send_queue(struct http_conn *http_conn);
+struct tstream_context *http_conn_tstream(struct http_conn *http_conn);
+
+/* HTTP request */
+struct tevent_req *http_send_request_send(TALLOC_CTX *,
+ struct tevent_context *,
+ struct http_conn *,
+ struct http_request *);
+NTSTATUS http_send_request_recv(struct tevent_req *);
+
+/* HTTP response */
+struct tevent_req *http_read_response_send(TALLOC_CTX *,
+ struct tevent_context *,
+ struct http_conn *,
+ size_t max_content_length);
+NTSTATUS http_read_response_recv(struct tevent_req *,
+ TALLOC_CTX *,
+ struct http_request **);
+
+/* HTTP authenticated request */
+struct tevent_req *http_send_auth_request_send(TALLOC_CTX *,
+ struct tevent_context *,
+ struct http_conn *,
+ const struct http_request *,
+ struct cli_credentials *,
+ struct loadparm_context *,
+ enum http_auth_method);
+NTSTATUS http_send_auth_request_recv(struct tevent_req *);
+
+#endif /* _HTTP_H_ */
diff --git a/libcli/http/http_auth.c b/libcli/http/http_auth.c
new file mode 100644
index 0000000..3dcf52c
--- /dev/null
+++ b/libcli/http/http_auth.c
@@ -0,0 +1,383 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ HTTP library
+
+ Copyright (C) 2014 Samuel Cabrero <samuelcabrero@kernevil.me>
+
+ 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 "http.h"
+#include "http_internal.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "lib/param/param.h"
+#include "tevent.h"
+#include "auth/gensec/gensec.h"
+#include "auth/credentials/credentials.h"
+#include "lib/util/data_blob.h"
+
+#undef strcasecmp
+#undef strncasecmp
+
+/**
+ * Copy the request headers from src to dst
+ */
+static NTSTATUS http_copy_header(const struct http_request *src,
+ struct http_request *dst)
+{
+ struct http_header *h;
+
+ dst->type = src->type;
+ dst->major = src->major;
+ dst->minor = src->minor;
+ dst->uri = talloc_strdup(dst, src->uri);
+
+ for (h = src->headers; h != NULL; h = h->next) {
+ http_add_header(dst, &dst->headers, h->key, h->value);
+ }
+ dst->headers_size = src->headers_size;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * Retrieve the WWW-Authenticate header from server response based on the
+ * authentication scheme being used.
+ */
+static NTSTATUS http_parse_auth_response(const DATA_BLOB prefix,
+ struct http_request *auth_response,
+ DATA_BLOB *in)
+{
+ struct http_header *h;
+
+ for (h = auth_response->headers; h != NULL; h = h->next) {
+ int cmp;
+
+ cmp = strcasecmp(h->key, "WWW-Authenticate");
+ if (cmp != 0) {
+ continue;
+ }
+
+ cmp = strncasecmp(h->value,
+ (const char *)prefix.data,
+ prefix.length);
+ if (cmp != 0) {
+ continue;
+ }
+
+ *in = data_blob_string_const(h->value);
+ return NT_STATUS_OK;
+ }
+
+ return NT_STATUS_NOT_SUPPORTED;
+}
+
+struct http_auth_state {
+ struct tevent_context *ev;
+
+ struct http_conn *http_conn;
+
+ enum http_auth_method auth;
+ DATA_BLOB prefix;
+
+ struct gensec_security *gensec_ctx;
+ NTSTATUS gensec_status;
+
+ const struct http_request *original_request;
+ struct http_request *next_request;
+ struct http_request *auth_response;
+};
+
+
+static void http_send_auth_request_gensec_done(struct tevent_req *subreq);
+static void http_send_auth_request_http_req_done(struct tevent_req *subreq);
+static void http_send_auth_request_http_rep_done(struct tevent_req *subreq);
+
+struct tevent_req *http_send_auth_request_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct http_conn *http_conn,
+ const struct http_request *original_request,
+ struct cli_credentials *credentials,
+ struct loadparm_context *lp_ctx,
+ enum http_auth_method auth)
+{
+ struct tevent_req *req = NULL;
+ struct http_auth_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+ DATA_BLOB gensec_in = data_blob_null;
+ NTSTATUS status;
+ struct http_header *h = NULL;
+ const char *mech_name = NULL;
+
+ req = tevent_req_create(mem_ctx, &state, struct http_auth_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->http_conn = http_conn;
+ state->auth = auth;
+ state->original_request = original_request;
+
+ status = gensec_init();
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ status = gensec_client_start(state, &state->gensec_ctx,
+ lpcfg_gensec_settings(state, lp_ctx));
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ status = gensec_set_credentials(state->gensec_ctx, credentials);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ for (h = original_request->headers; h != NULL; h = h->next) {
+ int cmp;
+
+ cmp = strcasecmp(h->key, "Host");
+ if (cmp != 0) {
+ continue;
+ }
+
+ status = gensec_set_target_service(state->gensec_ctx, "http");
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ status = gensec_set_target_hostname(state->gensec_ctx, h->value);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+ break;
+ }
+
+ switch (state->auth) {
+ case HTTP_AUTH_BASIC:
+ mech_name = "http_basic";
+ state->prefix = data_blob_string_const("Basic");
+ break;
+ case HTTP_AUTH_NTLM:
+ mech_name = "http_ntlm";
+ state->prefix = data_blob_string_const("NTLM");
+ break;
+ case HTTP_AUTH_NEGOTIATE:
+ mech_name = "http_negotiate";
+ state->prefix = data_blob_string_const("Negotiate");
+ break;
+ default:
+ tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
+ return tevent_req_post(req, ev);
+ }
+
+ status = gensec_start_mech_by_name(state->gensec_ctx, mech_name);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = gensec_update_send(state, state->ev,
+ state->gensec_ctx,
+ gensec_in);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, http_send_auth_request_gensec_done, req);
+
+ return req;
+}
+
+static void http_send_auth_request_gensec_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct http_auth_state *state =
+ tevent_req_data(req,
+ struct http_auth_state);
+ DATA_BLOB gensec_out = data_blob_null;
+ NTSTATUS status;
+ int ret;
+
+ TALLOC_FREE(state->auth_response);
+
+ status = gensec_update_recv(subreq, state, &gensec_out);
+ TALLOC_FREE(subreq);
+ state->gensec_status = status;
+ if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ status = NT_STATUS_OK;
+ }
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ state->next_request = talloc_zero(state, struct http_request);
+ if (tevent_req_nomem(state->next_request, req)) {
+ return;
+ }
+
+ status = http_copy_header(state->original_request, state->next_request);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (!NT_STATUS_IS_OK(state->gensec_status)) {
+ /*
+ * More preprocessing required before we
+ * can include the content.
+ */
+ ret = http_replace_header(state->next_request,
+ &state->next_request->headers,
+ "Content-Length", "0");
+ if (ret != 0) {
+ tevent_req_oom(req);
+ return;
+ }
+ } else {
+ state->next_request->body = state->original_request->body;
+ }
+
+ if (gensec_out.length > 0) {
+ ret = http_add_header(state->next_request,
+ &state->next_request->headers,
+ "Authorization",
+ (char *)gensec_out.data);
+ if (ret != 0) {
+ tevent_req_oom(req);
+ return;
+ }
+ data_blob_free(&gensec_out);
+ }
+
+ subreq = http_send_request_send(state, state->ev,
+ state->http_conn,
+ state->next_request);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ http_send_auth_request_http_req_done,
+ req);
+}
+
+static void http_send_auth_request_http_req_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct http_auth_state *state =
+ tevent_req_data(req,
+ struct http_auth_state);
+ NTSTATUS status;
+
+ TALLOC_FREE(state->next_request);
+
+ status = http_send_request_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ /*
+ * If no more processing required, it is done
+ *
+ * The caller will use http_read_response_send/recv
+ * in order to get the high level response.
+ */
+ if (NT_STATUS_IS_OK(state->gensec_status)) {
+ tevent_req_done(req);
+ return;
+ }
+
+ /*
+ * If more processing required, read the response from server
+ *
+ * We may get an empty RPCH Echo packet from the server
+ * on the "RPC_OUT_DATA" path. We need to consume this
+ * from the socket, but for now we just ignore the bytes.
+ */
+ subreq = http_read_response_send(state, state->ev,
+ state->http_conn,
+ UINT16_MAX);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ http_send_auth_request_http_rep_done,
+ req);
+}
+
+static void http_send_auth_request_http_rep_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct http_auth_state *state =
+ tevent_req_data(req,
+ struct http_auth_state);
+ DATA_BLOB gensec_in = data_blob_null;
+ NTSTATUS status;
+
+ status = http_read_response_recv(subreq, state,
+ &state->auth_response);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ /*
+ * We we asked for up to UINT16_MAX bytes of
+ * content, we don't expect
+ * state->auth_response->remaining_content_length
+ * to be set.
+ *
+ * For now we just ignore any bytes in
+ * state->auth_response->body.
+ */
+ if (state->auth_response->remaining_content_length != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ status = http_parse_auth_response(state->prefix,
+ state->auth_response,
+ &gensec_in);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ subreq = gensec_update_send(state, state->ev,
+ state->gensec_ctx,
+ gensec_in);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, http_send_auth_request_gensec_done, req);
+}
+
+NTSTATUS http_send_auth_request_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+ tevent_req_received(req);
+
+ return NT_STATUS_OK;
+}
diff --git a/libcli/http/http_conn.c b/libcli/http/http_conn.c
new file mode 100644
index 0000000..ac39a0a
--- /dev/null
+++ b/libcli/http/http_conn.c
@@ -0,0 +1,347 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ HTTP library
+
+ Copyright (C) 2019 Ralph Boehme <slow@samba.org>
+
+ 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 "lib/util/tevent_ntstatus.h"
+#include "libcli/dns/dns_lookup.h"
+#include "lib/tsocket/tsocket.h"
+#include "lib/util/util_net.h"
+#include "lib/tls/tls.h"
+#include "lib/util/tevent_unix.h"
+#include "http.h"
+#include "http_internal.h"
+
+struct http_connect_state {
+ struct tevent_context *ev;
+ const char *http_server;
+ const char *http_server_ip;
+ uint16_t http_port;
+ struct tsocket_address *local_address;
+ struct tsocket_address *remote_address;
+ struct cli_credentials *credentials;
+ struct tstream_tls_params *tls_params;
+
+ struct http_conn *http_conn;
+};
+
+static void http_connect_dns_done(struct tevent_req *subreq);
+static void http_connect_tcp_connect(struct tevent_req *req);
+static void http_connect_tcp_done(struct tevent_req *subreq);
+static void http_connect_tls_done(struct tevent_req *subreq);
+
+struct tevent_req *http_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *http_server,
+ uint16_t http_port,
+ struct cli_credentials *credentials,
+ struct tstream_tls_params *tls_params)
+{
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ struct http_connect_state *state = NULL;
+ int ret;
+
+ DBG_DEBUG("Connecting to [%s] over HTTP%s\n",
+ http_server, tls_params != NULL ? "S" : "");
+
+ req = tevent_req_create(mem_ctx, &state, struct http_connect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ *state = (struct http_connect_state) {
+ .ev = ev,
+ .http_port = http_port,
+ .credentials = credentials,
+ .tls_params = tls_params,
+ };
+
+ state->http_server = talloc_strdup(state, http_server);
+ if (tevent_req_nomem(state->http_server, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->http_conn = talloc_zero(state, struct http_conn);
+ if (tevent_req_nomem(state->http_conn, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->http_conn->send_queue = tevent_queue_create(state->http_conn,
+ "HTTP send queue");
+ if (tevent_req_nomem(state->http_conn->send_queue, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ ret = tsocket_address_inet_from_strings(state,
+ "ip",
+ NULL,
+ 0,
+ &state->local_address);
+ if (ret != 0) {
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+
+ if (!is_ipaddress(http_server)) {
+ subreq = dns_lookup_send(state,
+ ev,
+ NULL,
+ http_server,
+ DNS_QCLASS_IN,
+ DNS_QTYPE_A);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, http_connect_dns_done, req);
+ return req;
+ }
+ state->http_server_ip = state->http_server;
+
+ http_connect_tcp_connect(req);
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void http_connect_dns_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct http_connect_state *state = tevent_req_data(
+ req, struct http_connect_state);
+ struct dns_name_packet *dns_reply = NULL;
+ struct dns_res_rec *an = NULL;
+ uint16_t i;
+ int ret;
+
+ ret = dns_lookup_recv(subreq, state, &dns_reply);
+ TALLOC_FREE(subreq);
+ if (ret != 0) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ for (i = 0; i < dns_reply->ancount; i++) {
+ an = &dns_reply->answers[i];
+ if (an->rr_type == DNS_QTYPE_A) {
+ break;
+ }
+ }
+ if (i >= dns_reply->ancount) {
+ tevent_req_error(req, ENOENT);
+ return;
+ }
+
+ state->http_server_ip = talloc_strdup(state, an->rdata.ipv4_record);
+ if (tevent_req_nomem(state->http_server_ip, req)) {
+ return;
+ }
+ http_connect_tcp_connect(req);
+}
+
+static void http_connect_tcp_connect(struct tevent_req *req)
+{
+ struct http_connect_state *state = tevent_req_data(
+ req, struct http_connect_state);
+ struct tevent_req *subreq = NULL;
+ int ret;
+
+ ret = tsocket_address_inet_from_strings(state,
+ "ip",
+ state->http_server_ip,
+ state->http_port,
+ &state->remote_address);
+ if (ret != 0) {
+ int saved_errno = errno;
+
+ DBG_ERR("Cannot create remote socket address, error: %s (%d)\n",
+ strerror(errno), errno);
+ tevent_req_error(req, saved_errno);
+ return;
+ }
+
+ subreq = tstream_inet_tcp_connect_send(state,
+ state->ev,
+ state->local_address,
+ state->remote_address);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, http_connect_tcp_done, req);
+}
+
+static void http_connect_tcp_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct http_connect_state *state = tevent_req_data(
+ req, struct http_connect_state);
+ int error;
+ int ret;
+
+ ret = tstream_inet_tcp_connect_recv(subreq,
+ &error,
+ state->http_conn,
+ &state->http_conn->tstreams.raw,
+ NULL);
+ TALLOC_FREE(subreq);
+ if (ret != 0) {
+ tevent_req_error(req, error);
+ return;
+ }
+
+ state->http_conn->tstreams.active = state->http_conn->tstreams.raw;
+ DBG_DEBUG("Socket connected\n");
+
+ if (state->tls_params == NULL) {
+ tevent_req_done(req);
+ return;
+ }
+
+ DBG_DEBUG("Starting TLS\n");
+
+ subreq = tstream_tls_connect_send(state,
+ state->ev,
+ state->http_conn->tstreams.active,
+ state->tls_params);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, http_connect_tls_done, req);
+}
+
+static void http_connect_tls_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct http_connect_state *state = tevent_req_data(
+ req, struct http_connect_state);
+ int error;
+ int ret;
+
+ ret = tstream_tls_connect_recv(subreq,
+ &error,
+ state->http_conn,
+ &state->http_conn->tstreams.tls);
+ TALLOC_FREE(subreq);
+ if (ret != 0) {
+ tevent_req_error(req, error);
+ return;
+ }
+
+ state->http_conn->tstreams.active = state->http_conn->tstreams.tls;
+
+ DBG_DEBUG("TLS handshake completed\n");
+ tevent_req_done(req);
+}
+
+int http_connect_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct http_conn **http_conn)
+{
+ struct http_connect_state *state = tevent_req_data(
+ req, struct http_connect_state);
+ int error;
+
+ if (tevent_req_is_unix_error(req, &error)) {
+ tevent_req_received(req);
+ return error;
+ }
+
+ *http_conn = talloc_move(mem_ctx, &state->http_conn);
+ tevent_req_received(req);
+
+ return 0;
+}
+
+struct tevent_queue *http_conn_send_queue(struct http_conn *http_conn)
+{
+ return http_conn->send_queue;
+}
+
+struct tstream_context *http_conn_tstream(struct http_conn *http_conn)
+{
+ return http_conn->tstreams.active;
+}
+
+struct http_conn_disconnect_state {
+ struct tevent_context *ev;
+ struct http_conn *http_conn;
+};
+
+static void http_conn_disconnect_done(struct tevent_req *subreq);
+
+struct tevent_req *http_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct http_conn *http_conn)
+{
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ struct http_conn_disconnect_state *state = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct http_conn_disconnect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ *state = (struct http_conn_disconnect_state) {
+ .ev = ev,
+ .http_conn = http_conn,
+ };
+
+ if (http_conn->tstreams.active == NULL) {
+ tevent_req_error(req, ENOTCONN);
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = tstream_disconnect_send(state, ev, http_conn->tstreams.active);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, http_conn_disconnect_done, req);
+
+ return req;
+}
+
+static void http_conn_disconnect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ int ret;
+ int error;
+
+ ret = tstream_disconnect_recv(subreq, &error);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, error);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+int http_disconnect_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_unix(req);
+}
diff --git a/libcli/http/http_internal.h b/libcli/http/http_internal.h
new file mode 100644
index 0000000..ec17f7e
--- /dev/null
+++ b/libcli/http/http_internal.h
@@ -0,0 +1,50 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ HTTP library
+
+ Copyright (C) 2014 Samuel Cabrero <samuelcabrero@kernevil.me>
+
+ 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/>.
+*/
+
+#ifndef _HTTP_INTERNAL_H_
+#define _HTTP_INTERNAL_H_
+
+enum http_parser_state {
+ HTTP_READING_FIRSTLINE,
+ HTTP_READING_HEADERS,
+ HTTP_READING_BODY,
+ HTTP_READING_TRAILER,
+ HTTP_READING_DONE,
+};
+
+enum http_read_status {
+ HTTP_ALL_DATA_READ,
+ HTTP_MORE_DATA_EXPECTED,
+ HTTP_DATA_CORRUPTED,
+ HTTP_REQUEST_CANCELED,
+ HTTP_DATA_TOO_LONG,
+};
+
+struct http_conn {
+ struct tevent_queue *send_queue;
+ struct {
+ struct tstream_context *raw;
+ struct tstream_context *tls;
+ struct tstream_context *active;
+ } tstreams;
+};
+
+#endif /* _HTTP_INTERNAL_H_ */
diff --git a/libcli/http/wscript_build b/libcli/http/wscript_build
new file mode 100644
index 0000000..da8768f
--- /dev/null
+++ b/libcli/http/wscript_build
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+bld.SAMBA_LIBRARY('http',
+ source='http.c http_auth.c http_conn.c',
+ deps='talloc tevent gensec dns_lookup',
+ private_library=True,
+)
+
+bld.SAMBA_MODULE('gensec_http_basic',
+ source='gensec/basic.c',
+ subsystem='gensec',
+ init_function='gensec_http_basic_init',
+ deps='samba-util auth_session'
+)
+
+bld.SAMBA_MODULE('gensec_http_generic',
+ source='gensec/generic.c',
+ subsystem='gensec',
+ init_function='gensec_http_generic_init',
+ deps='samba-util auth_session'
+)
diff --git a/libcli/ldap/ldap_errors.h b/libcli/ldap/ldap_errors.h
new file mode 100644
index 0000000..fa929c6
--- /dev/null
+++ b/libcli/ldap/ldap_errors.h
@@ -0,0 +1,68 @@
+/*
+ Unix SMB/CIFS Implementation.
+ LDAP protocol helper functions for SAMBA
+ Copyright (C) Volker Lendecke 2004
+
+ 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/>.
+
+*/
+
+#ifndef _SMB_LDAP_ERRORS_H_
+#define _SMB_LDAP_ERRORS_H_
+
+#ifndef LDAP_SUCCESS
+enum ldap_result_code {
+ LDAP_SUCCESS = 0,
+ LDAP_OPERATIONS_ERROR = 1,
+ LDAP_PROTOCOL_ERROR = 2,
+ LDAP_TIME_LIMIT_EXCEEDED = 3,
+ LDAP_SIZE_LIMIT_EXCEEDED = 4,
+ LDAP_COMPARE_FALSE = 5,
+ LDAP_COMPARE_TRUE = 6,
+ LDAP_AUTH_METHOD_NOT_SUPPORTED = 7,
+ LDAP_STRONG_AUTH_REQUIRED = 8,
+ LDAP_REFERRAL = 10,
+ LDAP_ADMIN_LIMIT_EXCEEDED = 11,
+ LDAP_UNAVAILABLE_CRITICAL_EXTENSION = 12,
+ LDAP_CONFIDENTIALITY_REQUIRED = 13,
+ LDAP_SASL_BIND_IN_PROGRESS = 14,
+ LDAP_NO_SUCH_ATTRIBUTE = 16,
+ LDAP_UNDEFINED_ATTRIBUTE_TYPE = 17,
+ LDAP_INAPPROPRIATE_MATCHING = 18,
+ LDAP_CONSTRAINT_VIOLATION = 19,
+ LDAP_ATTRIBUTE_OR_VALUE_EXISTS = 20,
+ LDAP_INVALID_ATTRIBUTE_SYNTAX = 21,
+ LDAP_NO_SUCH_OBJECT = 32,
+ LDAP_ALIAS_PROBLEM = 33,
+ LDAP_INVALID_DN_SYNTAX = 34,
+ LDAP_ALIAS_DEREFERENCING_PROBLEM = 36,
+ LDAP_INAPPROPRIATE_AUTHENTICATION = 48,
+ LDAP_INVALID_CREDENTIALS = 49,
+ LDAP_INSUFFICIENT_ACCESS_RIGHTS = 50,
+ LDAP_BUSY = 51,
+ LDAP_UNAVAILABLE = 52,
+ LDAP_UNWILLING_TO_PERFORM = 53,
+ LDAP_LOOP_DETECT = 54,
+ LDAP_NAMING_VIOLATION = 64,
+ LDAP_OBJECT_CLASS_VIOLATION = 65,
+ LDAP_NOT_ALLOWED_ON_NON_LEAF = 66,
+ LDAP_NOT_ALLOWED_ON_RDN = 67,
+ LDAP_ENTRY_ALREADY_EXISTS = 68,
+ LDAP_OBJECT_CLASS_MODS_PROHIBITED = 69,
+ LDAP_AFFECTS_MULTIPLE_DSAS = 71,
+ LDAP_OTHER = 80
+};
+#endif
+
+#endif /* _SMB_LDAP_ERRORS_H_ */
diff --git a/libcli/ldap/ldap_message.c b/libcli/ldap/ldap_message.c
new file mode 100644
index 0000000..1a537e8
--- /dev/null
+++ b/libcli/ldap/ldap_message.c
@@ -0,0 +1,1673 @@
+/*
+ Unix SMB/CIFS implementation.
+ LDAP protocol helper functions for SAMBA
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Volker Lendecke 2004
+ Copyright (C) Stefan Metzmacher 2004
+ Copyright (C) Simo Sorce 2004
+
+ 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 "../lib/util/asn1.h"
+#include "../libcli/ldap/ldap_message.h"
+
+_PUBLIC_ struct ldap_message *new_ldap_message(TALLOC_CTX *mem_ctx)
+{
+ return talloc_zero(mem_ctx, struct ldap_message);
+}
+
+
+static bool add_value_to_attrib(TALLOC_CTX *mem_ctx, struct ldb_val *value,
+ struct ldb_message_element *attrib)
+{
+ attrib->values = talloc_realloc(mem_ctx,
+ attrib->values,
+ DATA_BLOB,
+ attrib->num_values+1);
+ if (attrib->values == NULL)
+ return false;
+
+ attrib->values[attrib->num_values].data = talloc_steal(attrib->values,
+ value->data);
+ attrib->values[attrib->num_values].length = value->length;
+ attrib->num_values += 1;
+ return true;
+}
+
+static bool add_attrib_to_array_talloc(TALLOC_CTX *mem_ctx,
+ const struct ldb_message_element *attrib,
+ struct ldb_message_element **attribs,
+ int *num_attribs)
+{
+ *attribs = talloc_realloc(mem_ctx,
+ *attribs,
+ struct ldb_message_element,
+ *num_attribs+1);
+
+ if (*attribs == NULL)
+ return false;
+
+ (*attribs)[*num_attribs] = *attrib;
+ talloc_steal(*attribs, attrib->values);
+ talloc_steal(*attribs, attrib->name);
+ *num_attribs += 1;
+ return true;
+}
+
+static bool add_mod_to_array_talloc(TALLOC_CTX *mem_ctx,
+ struct ldap_mod *mod,
+ struct ldap_mod **mods,
+ int *num_mods)
+{
+ *mods = talloc_realloc(mem_ctx, *mods, struct ldap_mod, (*num_mods)+1);
+
+ if (*mods == NULL)
+ return false;
+
+ (*mods)[*num_mods] = *mod;
+ *num_mods += 1;
+ return true;
+}
+
+static bool ldap_decode_control_value(void *mem_ctx, DATA_BLOB value,
+ const struct ldap_control_handler *handlers,
+ struct ldb_control *ctrl)
+{
+ int i;
+
+ if (!handlers) {
+ return true;
+ }
+
+ for (i = 0; handlers[i].oid != NULL; i++) {
+ if (strcmp(handlers[i].oid, ctrl->oid) == 0) {
+ if (!handlers[i].decode || !handlers[i].decode(mem_ctx, value, &ctrl->data)) {
+ return false;
+ }
+ break;
+ }
+ }
+ if (handlers[i].oid == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool ldap_decode_control_wrapper(void *mem_ctx, struct asn1_data *data,
+ struct ldb_control *ctrl, DATA_BLOB *value)
+{
+ DATA_BLOB oid;
+
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
+ return false;
+ }
+
+ if (!asn1_read_OctetString(data, mem_ctx, &oid)) {
+ return false;
+ }
+ ctrl->oid = talloc_strndup(mem_ctx, (char *)oid.data, oid.length);
+ if (!ctrl->oid) {
+ return false;
+ }
+
+ if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
+ bool critical;
+ if (!asn1_read_BOOLEAN(data, &critical)) {
+ return false;
+ }
+ ctrl->critical = critical;
+ } else {
+ ctrl->critical = false;
+ }
+
+ ctrl->data = NULL;
+
+ if (!asn1_peek_tag(data, ASN1_OCTET_STRING)) {
+ *value = data_blob(NULL, 0);
+ goto end_tag;
+ }
+
+ if (!asn1_read_OctetString(data, mem_ctx, value)) {
+ return false;
+ }
+
+end_tag:
+ if (!asn1_end_tag(data)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool ldap_encode_control(void *mem_ctx, struct asn1_data *data,
+ const struct ldap_control_handler *handlers,
+ struct ldb_control *ctrl)
+{
+ DATA_BLOB value;
+ int i;
+
+ if (!handlers) {
+ return false;
+ }
+
+ for (i = 0; handlers[i].oid != NULL; i++) {
+ if (!ctrl->oid) {
+ /* not encoding this control, the OID has been
+ * set to NULL indicating it isn't really
+ * here */
+ return true;
+ }
+ if (strcmp(handlers[i].oid, ctrl->oid) == 0) {
+ if (!handlers[i].encode) {
+ if (ctrl->critical) {
+ return false;
+ } else {
+ /* not encoding this control */
+ return true;
+ }
+ }
+ if (!handlers[i].encode(mem_ctx, ctrl->data, &value)) {
+ return false;
+ }
+ break;
+ }
+ }
+ if (handlers[i].oid == NULL) {
+ return false;
+ }
+
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
+ return false;
+ }
+
+ if (!asn1_write_OctetString(data, ctrl->oid, strlen(ctrl->oid))) {
+ return false;
+ }
+
+ if (ctrl->critical) {
+ if (!asn1_write_BOOLEAN(data, ctrl->critical)) {
+ return false;
+ }
+ }
+
+ if (!ctrl->data) {
+ goto pop_tag;
+ }
+
+ if (!asn1_write_OctetString(data, value.data, value.length)) {
+ return false;
+ }
+
+pop_tag:
+ if (!asn1_pop_tag(data)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree)
+{
+ int i;
+
+ switch (tree->operation) {
+ case LDB_OP_AND:
+ case LDB_OP_OR:
+ if (!asn1_push_tag(data, ASN1_CONTEXT(tree->operation==LDB_OP_AND?0:1))) return false;
+ for (i=0; i<tree->u.list.num_elements; i++) {
+ if (!ldap_push_filter(data, tree->u.list.elements[i])) {
+ return false;
+ }
+ }
+ if (!asn1_pop_tag(data)) return false;
+ break;
+
+ case LDB_OP_NOT:
+ if (!asn1_push_tag(data, ASN1_CONTEXT(2))) return false;
+ if (!ldap_push_filter(data, tree->u.isnot.child)) {
+ return false;
+ }
+ if (!asn1_pop_tag(data)) return false;
+ break;
+
+ case LDB_OP_EQUALITY:
+ /* equality test */
+ if (!asn1_push_tag(data, ASN1_CONTEXT(3))) return false;
+ if (!asn1_write_OctetString(data, tree->u.equality.attr,
+ strlen(tree->u.equality.attr))) return false;
+ if (!asn1_write_OctetString(data, tree->u.equality.value.data,
+ tree->u.equality.value.length)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ break;
+
+ case LDB_OP_SUBSTRING:
+ /*
+ SubstringFilter ::= SEQUENCE {
+ type AttributeDescription,
+ -- at least one must be present
+ substrings SEQUENCE OF CHOICE {
+ initial [0] LDAPString,
+ any [1] LDAPString,
+ final [2] LDAPString } }
+ */
+ if (!asn1_push_tag(data, ASN1_CONTEXT(4))) return false;
+ if (!asn1_write_OctetString(data, tree->u.substring.attr, strlen(tree->u.substring.attr))) return false;
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) return false;
+
+ if (tree->u.substring.chunks && tree->u.substring.chunks[0]) {
+ i = 0;
+ if (!tree->u.substring.start_with_wildcard) {
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(0))) return false;
+ if (!asn1_write_DATA_BLOB_LDAPString(data, tree->u.substring.chunks[i])) return false;
+ if (!asn1_pop_tag(data)) return false;
+ i++;
+ }
+ while (tree->u.substring.chunks[i]) {
+ int ctx;
+
+ if (( ! tree->u.substring.chunks[i + 1]) &&
+ (tree->u.substring.end_with_wildcard == 0)) {
+ ctx = 2;
+ } else {
+ ctx = 1;
+ }
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(ctx))) return false;
+ if (!asn1_write_DATA_BLOB_LDAPString(data, tree->u.substring.chunks[i])) return false;
+ if (!asn1_pop_tag(data)) return false;
+ i++;
+ }
+ }
+ if (!asn1_pop_tag(data)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ break;
+
+ case LDB_OP_GREATER:
+ /* greaterOrEqual test */
+ if (!asn1_push_tag(data, ASN1_CONTEXT(5))) return false;
+ if (!asn1_write_OctetString(data, tree->u.comparison.attr,
+ strlen(tree->u.comparison.attr))) return false;
+ if (!asn1_write_OctetString(data, tree->u.comparison.value.data,
+ tree->u.comparison.value.length)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ break;
+
+ case LDB_OP_LESS:
+ /* lessOrEqual test */
+ if (!asn1_push_tag(data, ASN1_CONTEXT(6))) return false;
+ if (!asn1_write_OctetString(data, tree->u.comparison.attr,
+ strlen(tree->u.comparison.attr))) return false;
+ if (!asn1_write_OctetString(data, tree->u.comparison.value.data,
+ tree->u.comparison.value.length)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ break;
+
+ case LDB_OP_PRESENT:
+ /* present test */
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(7))) return false;
+ if (!asn1_write_LDAPString(data, tree->u.present.attr)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ return !asn1_has_error(data);
+
+ case LDB_OP_APPROX:
+ /* approx test */
+ if (!asn1_push_tag(data, ASN1_CONTEXT(8))) return false;
+ if (!asn1_write_OctetString(data, tree->u.comparison.attr,
+ strlen(tree->u.comparison.attr))) return false;
+ if (!asn1_write_OctetString(data, tree->u.comparison.value.data,
+ tree->u.comparison.value.length)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ break;
+
+ case LDB_OP_EXTENDED:
+ /*
+ MatchingRuleAssertion ::= SEQUENCE {
+ matchingRule [1] MatchingRuleID OPTIONAL,
+ type [2] AttributeDescription OPTIONAL,
+ matchValue [3] AssertionValue,
+ dnAttributes [4] BOOLEAN DEFAULT FALSE
+ }
+ */
+ if (!asn1_push_tag(data, ASN1_CONTEXT(9))) return false;
+ if (tree->u.extended.rule_id) {
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(1))) return false;
+ if (!asn1_write_LDAPString(data, tree->u.extended.rule_id)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ }
+ if (tree->u.extended.attr) {
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(2))) return false;
+ if (!asn1_write_LDAPString(data, tree->u.extended.attr)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ }
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(3))) return false;
+ if (!asn1_write_DATA_BLOB_LDAPString(data, &tree->u.extended.value)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(4))) return false;
+ if (!asn1_write_uint8(data, tree->u.extended.dnAttributes)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ break;
+
+ default:
+ return false;
+ }
+ return !asn1_has_error(data);
+}
+
+static bool ldap_encode_response(struct asn1_data *data, struct ldap_Result *result)
+{
+ if (!asn1_write_enumerated(data, result->resultcode)) return false;
+ if (!asn1_write_OctetString(data, result->dn,
+ (result->dn) ? strlen(result->dn) : 0)) return false;
+ if (!asn1_write_OctetString(data, result->errormessage,
+ (result->errormessage) ?
+ strlen(result->errormessage) : 0)) return false;
+ if (result->referral) {
+ if (!asn1_push_tag(data, ASN1_CONTEXT(3))) return false;
+ if (!asn1_write_OctetString(data, result->referral,
+ strlen(result->referral))) return false;
+ if (!asn1_pop_tag(data)) return false;
+ }
+ return true;
+}
+
+_PUBLIC_ bool ldap_encode(struct ldap_message *msg,
+ const struct ldap_control_handler *control_handlers,
+ DATA_BLOB *result, TALLOC_CTX *mem_ctx)
+{
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
+ int i, j;
+
+ if (!data) return false;
+
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
+ if (!asn1_write_Integer(data, msg->messageid)) goto err;
+
+ switch (msg->type) {
+ case LDAP_TAG_BindRequest: {
+ struct ldap_BindRequest *r = &msg->r.BindRequest;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!asn1_write_Integer(data, r->version)) goto err;
+ if (!asn1_write_OctetString(data, r->dn,
+ (r->dn != NULL) ? strlen(r->dn) : 0)) goto err;
+
+ switch (r->mechanism) {
+ case LDAP_AUTH_MECH_SIMPLE:
+ /* context, primitive */
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(0))) goto err;
+ if (!asn1_write(data, r->creds.password,
+ strlen(r->creds.password))) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ case LDAP_AUTH_MECH_SASL:
+ /* context, constructed */
+ if (!asn1_push_tag(data, ASN1_CONTEXT(3))) goto err;
+ if (!asn1_write_OctetString(data, r->creds.SASL.mechanism,
+ strlen(r->creds.SASL.mechanism))) goto err;
+ if (r->creds.SASL.secblob) {
+ if (!asn1_write_OctetString(data, r->creds.SASL.secblob->data,
+ r->creds.SASL.secblob->length)) goto err;
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ default:
+ goto err;
+ }
+
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_BindResponse: {
+ struct ldap_BindResponse *r = &msg->r.BindResponse;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!ldap_encode_response(data, &r->response)) goto err;
+ if (r->SASL.secblob) {
+ if (!asn1_write_ContextSimple(data, 7, r->SASL.secblob)) goto err;
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_UnbindRequest: {
+/* struct ldap_UnbindRequest *r = &msg->r.UnbindRequest; */
+ if (!asn1_push_tag(data, ASN1_APPLICATION_SIMPLE(msg->type))) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_SearchRequest: {
+ struct ldap_SearchRequest *r = &msg->r.SearchRequest;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!asn1_write_OctetString(data, r->basedn, strlen(r->basedn))) goto err;
+ if (!asn1_write_enumerated(data, r->scope)) goto err;
+ if (!asn1_write_enumerated(data, r->deref)) goto err;
+ if (!asn1_write_Integer(data, r->sizelimit)) goto err;
+ if (!asn1_write_Integer(data, r->timelimit)) goto err;
+ if (!asn1_write_BOOLEAN(data, r->attributesonly)) goto err;
+
+ if (!ldap_push_filter(data, r->tree)) {
+ goto err;
+ }
+
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
+ for (i=0; i<r->num_attributes; i++) {
+ if (!asn1_write_OctetString(data, r->attributes[i],
+ strlen(r->attributes[i]))) goto err;
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_SearchResultEntry: {
+ struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!asn1_write_OctetString(data, r->dn, strlen(r->dn))) goto err;
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
+ for (i=0; i<r->num_attributes; i++) {
+ struct ldb_message_element *attr = &r->attributes[i];
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
+ if (!asn1_write_OctetString(data, attr->name,
+ strlen(attr->name))) goto err;
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(1))) goto err;
+ for (j=0; j<attr->num_values; j++) {
+ if (!asn1_write_OctetString(data,
+ attr->values[j].data,
+ attr->values[j].length)) goto err;
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_SearchResultDone: {
+ struct ldap_Result *r = &msg->r.SearchResultDone;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!ldap_encode_response(data, r)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_ModifyRequest: {
+ struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!asn1_write_OctetString(data, r->dn, strlen(r->dn))) goto err;
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
+
+ for (i=0; i<r->num_mods; i++) {
+ struct ldb_message_element *attrib = &r->mods[i].attrib;
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
+ if (!asn1_write_enumerated(data, r->mods[i].type)) goto err;
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
+ if (!asn1_write_OctetString(data, attrib->name,
+ strlen(attrib->name))) goto err;
+ if (!asn1_push_tag(data, ASN1_SET)) goto err;
+ for (j=0; j<attrib->num_values; j++) {
+ if (!asn1_write_OctetString(data,
+ attrib->values[j].data,
+ attrib->values[j].length)) goto err;
+
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ }
+
+ if (!asn1_pop_tag(data)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_ModifyResponse: {
+ struct ldap_Result *r = &msg->r.ModifyResponse;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!ldap_encode_response(data, r)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_AddRequest: {
+ struct ldap_AddRequest *r = &msg->r.AddRequest;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!asn1_write_OctetString(data, r->dn, strlen(r->dn))) goto err;
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
+
+ for (i=0; i<r->num_attributes; i++) {
+ struct ldb_message_element *attrib = &r->attributes[i];
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
+ if (attrib->name == NULL) {
+ goto err;
+ }
+ if (!asn1_write_OctetString(data, attrib->name,
+ strlen(attrib->name))) goto err;
+ if (!asn1_push_tag(data, ASN1_SET)) goto err;
+ for (j=0; j<r->attributes[i].num_values; j++) {
+ if (!asn1_write_OctetString(data,
+ attrib->values[j].data,
+ attrib->values[j].length)) goto err;
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_AddResponse: {
+ struct ldap_Result *r = &msg->r.AddResponse;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!ldap_encode_response(data, r)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_DelRequest: {
+ struct ldap_DelRequest *r = &msg->r.DelRequest;
+ if (!asn1_push_tag(data, ASN1_APPLICATION_SIMPLE(msg->type))) goto err;
+ if (!asn1_write(data, r->dn, strlen(r->dn))) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_DelResponse: {
+ struct ldap_Result *r = &msg->r.DelResponse;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!ldap_encode_response(data, r)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_ModifyDNRequest: {
+ struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!asn1_write_OctetString(data, r->dn, strlen(r->dn))) goto err;
+ if (!asn1_write_OctetString(data, r->newrdn, strlen(r->newrdn))) goto err;
+ if (!asn1_write_BOOLEAN(data, r->deleteolddn)) goto err;
+ if (r->newsuperior) {
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(0))) goto err;
+ if (!asn1_write(data, r->newsuperior,
+ strlen(r->newsuperior))) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_ModifyDNResponse: {
+ struct ldap_Result *r = &msg->r.ModifyDNResponse;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!ldap_encode_response(data, r)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_CompareRequest: {
+ struct ldap_CompareRequest *r = &msg->r.CompareRequest;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!asn1_write_OctetString(data, r->dn, strlen(r->dn))) goto err;
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
+ if (!asn1_write_OctetString(data, r->attribute,
+ strlen(r->attribute))) goto err;
+ if (!asn1_write_OctetString(data, r->value.data,
+ r->value.length)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_CompareResponse: {
+ struct ldap_Result *r = &msg->r.ModifyDNResponse;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!ldap_encode_response(data, r)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_AbandonRequest: {
+ struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
+ if (!asn1_push_tag(data, ASN1_APPLICATION_SIMPLE(msg->type))) goto err;
+ if (!asn1_write_implicit_Integer(data, r->messageid)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_SearchResultReference: {
+ struct ldap_SearchResRef *r = &msg->r.SearchResultReference;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!asn1_write_OctetString(data, r->referral, strlen(r->referral))) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_ExtendedRequest: {
+ struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(0))) goto err;
+ if (!asn1_write(data, r->oid, strlen(r->oid))) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ if (r->value) {
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(1))) goto err;
+ if (!asn1_write(data, r->value->data, r->value->length)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_ExtendedResponse: {
+ struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!ldap_encode_response(data, &r->response)) goto err;
+ if (r->oid) {
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(10))) goto err;
+ if (!asn1_write(data, r->oid, strlen(r->oid))) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ }
+ if (r->value) {
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(11))) goto err;
+ if (!asn1_write(data, r->value->data, r->value->length)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ default:
+ goto err;
+ }
+
+ if (msg->controls != NULL) {
+ if (!asn1_push_tag(data, ASN1_CONTEXT(0))) goto err;
+
+ for (i = 0; msg->controls[i] != NULL; i++) {
+ if (!ldap_encode_control(mem_ctx, data,
+ control_handlers,
+ msg->controls[i])) {
+ DEBUG(0,("Unable to encode control %s\n",
+ msg->controls[i]->oid));
+ goto err;
+ }
+ }
+
+ if (!asn1_pop_tag(data)) goto err;
+ }
+
+ if (!asn1_pop_tag(data)) goto err;
+
+ if (!asn1_extract_blob(data, mem_ctx, result)) {
+ goto err;
+ }
+
+ asn1_free(data);
+
+ return true;
+
+ err:
+
+ asn1_free(data);
+ return false;
+}
+
+static const char *blob2string_talloc(TALLOC_CTX *mem_ctx,
+ DATA_BLOB blob)
+{
+ char *result = talloc_array(mem_ctx, char, blob.length+1);
+ if (result == NULL) {
+ return NULL;
+ }
+ memcpy(result, blob.data, blob.length);
+ result[blob.length] = '\0';
+ return result;
+}
+
+bool asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
+ struct asn1_data *data,
+ const char **result)
+{
+ DATA_BLOB string;
+ if (!asn1_read_OctetString(data, mem_ctx, &string))
+ return false;
+ *result = blob2string_talloc(mem_ctx, string);
+ data_blob_free(&string);
+ return *result ? true : false;
+}
+
+static bool ldap_decode_response(TALLOC_CTX *mem_ctx,
+ struct asn1_data *data,
+ struct ldap_Result *result)
+{
+ if (!asn1_read_enumerated(data, &result->resultcode)) return false;
+ if (!asn1_read_OctetString_talloc(mem_ctx, data, &result->dn)) return false;
+ if (!asn1_read_OctetString_talloc(mem_ctx, data, &result->errormessage)) return false;
+ if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
+ if (!asn1_start_tag(data, ASN1_CONTEXT(3))) return false;
+ if (!asn1_read_OctetString_talloc(mem_ctx, data, &result->referral)) return false;
+ if (!asn1_end_tag(data)) return false;
+ } else {
+ result->referral = NULL;
+ }
+ return true;
+}
+
+static struct ldb_val **ldap_decode_substring(TALLOC_CTX *mem_ctx, struct ldb_val **chunks, int chunk_num, char *value)
+{
+
+ chunks = talloc_realloc(mem_ctx, chunks, struct ldb_val *, chunk_num + 2);
+ if (chunks == NULL) {
+ return NULL;
+ }
+
+ chunks[chunk_num] = talloc(mem_ctx, struct ldb_val);
+ if (chunks[chunk_num] == NULL) {
+ return NULL;
+ }
+
+ chunks[chunk_num]->data = (uint8_t *)talloc_strdup(mem_ctx, value);
+ if (chunks[chunk_num]->data == NULL) {
+ return NULL;
+ }
+ chunks[chunk_num]->length = strlen(value);
+
+ chunks[chunk_num + 1] = NULL;
+
+ return chunks;
+}
+
+
+/*
+ parse the ASN.1 formatted search string into a ldb_parse_tree
+*/
+static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx,
+ struct asn1_data *data)
+{
+ uint8_t filter_tag;
+ struct ldb_parse_tree *ret;
+
+ if (!asn1_peek_uint8(data, &filter_tag)) {
+ return NULL;
+ }
+
+ filter_tag &= 0x1f; /* strip off the asn1 stuff */
+
+ ret = talloc(mem_ctx, struct ldb_parse_tree);
+ if (ret == NULL) return NULL;
+
+ switch(filter_tag) {
+ case 0:
+ case 1:
+ /* AND or OR of one or more filters */
+ ret->operation = (filter_tag == 0)?LDB_OP_AND:LDB_OP_OR;
+ ret->u.list.num_elements = 0;
+ ret->u.list.elements = NULL;
+
+ if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
+ goto failed;
+ }
+
+ while (asn1_tag_remaining(data) > 0) {
+ struct ldb_parse_tree *subtree;
+ subtree = ldap_decode_filter_tree(ret, data);
+ if (subtree == NULL) {
+ goto failed;
+ }
+ ret->u.list.elements =
+ talloc_realloc(ret, ret->u.list.elements,
+ struct ldb_parse_tree *,
+ ret->u.list.num_elements+1);
+ if (ret->u.list.elements == NULL) {
+ goto failed;
+ }
+ talloc_steal(ret->u.list.elements, subtree);
+ ret->u.list.elements[ret->u.list.num_elements] = subtree;
+ ret->u.list.num_elements++;
+ }
+ if (!asn1_end_tag(data)) {
+ goto failed;
+ }
+ break;
+
+ case 2:
+ /* 'not' operation */
+ if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
+ goto failed;
+ }
+
+ ret->operation = LDB_OP_NOT;
+ ret->u.isnot.child = ldap_decode_filter_tree(ret, data);
+ if (ret->u.isnot.child == NULL) {
+ goto failed;
+ }
+ if (!asn1_end_tag(data)) {
+ goto failed;
+ }
+ break;
+
+ case 3: {
+ /* equalityMatch */
+ const char *attrib;
+ DATA_BLOB value;
+
+ if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) goto failed;
+ if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib)) goto failed;
+ if (!asn1_read_OctetString(data, mem_ctx, &value)) goto failed;
+ if (!asn1_end_tag(data)) goto failed;
+ if (asn1_has_error(data) || (attrib == NULL) ||
+ (value.data == NULL)) {
+ goto failed;
+ }
+
+ ret->operation = LDB_OP_EQUALITY;
+ ret->u.equality.attr = talloc_steal(ret, attrib);
+ ret->u.equality.value.data = talloc_steal(ret, value.data);
+ ret->u.equality.value.length = value.length;
+ break;
+ }
+ case 4: {
+ /* substrings */
+ DATA_BLOB attr;
+ uint8_t subs_tag;
+ char *value;
+ int chunk_num = 0;
+
+ if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
+ goto failed;
+ }
+ if (!asn1_read_OctetString(data, mem_ctx, &attr)) {
+ goto failed;
+ }
+
+ ret->operation = LDB_OP_SUBSTRING;
+ ret->u.substring.attr = talloc_strndup(ret, (char *)attr.data, attr.length);
+ if (ret->u.substring.attr == NULL) {
+ goto failed;
+ }
+ ret->u.substring.chunks = NULL;
+ ret->u.substring.start_with_wildcard = 1;
+ ret->u.substring.end_with_wildcard = 1;
+
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
+ goto failed;
+ }
+
+ while (asn1_tag_remaining(data) > 0) {
+ if (!asn1_peek_uint8(data, &subs_tag)) goto failed;
+ subs_tag &= 0x1f; /* strip off the asn1 stuff */
+ if (subs_tag > 2) goto failed;
+
+ if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(subs_tag))) goto failed;
+ if (!asn1_read_LDAPString(data, mem_ctx, &value)) goto failed;
+ if (!asn1_end_tag(data)) goto failed;
+
+ switch (subs_tag) {
+ case 0:
+ if (ret->u.substring.chunks != NULL) {
+ /* initial value found in the middle */
+ goto failed;
+ }
+
+ ret->u.substring.chunks = ldap_decode_substring(ret, NULL, 0, value);
+ if (ret->u.substring.chunks == NULL) {
+ goto failed;
+ }
+
+ ret->u.substring.start_with_wildcard = 0;
+ chunk_num = 1;
+ break;
+
+ case 1:
+ if (ret->u.substring.end_with_wildcard == 0) {
+ /* "any" value found after a "final" value */
+ goto failed;
+ }
+
+ ret->u.substring.chunks = ldap_decode_substring(ret,
+ ret->u.substring.chunks,
+ chunk_num,
+ value);
+ if (ret->u.substring.chunks == NULL) {
+ goto failed;
+ }
+
+ chunk_num++;
+ break;
+
+ case 2:
+ ret->u.substring.chunks = ldap_decode_substring(ret,
+ ret->u.substring.chunks,
+ chunk_num,
+ value);
+ if (ret->u.substring.chunks == NULL) {
+ goto failed;
+ }
+
+ ret->u.substring.end_with_wildcard = 0;
+ break;
+
+ default:
+ goto failed;
+ }
+
+ }
+
+ if (!asn1_end_tag(data)) { /* SEQUENCE */
+ goto failed;
+ }
+
+ if (!asn1_end_tag(data)) {
+ goto failed;
+ }
+ break;
+ }
+ case 5: {
+ /* greaterOrEqual */
+ const char *attrib;
+ DATA_BLOB value;
+
+ if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) goto failed;
+ if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib)) goto failed;
+ if (!asn1_read_OctetString(data, mem_ctx, &value)) goto failed;
+ if (!asn1_end_tag(data)) goto failed;
+ if (asn1_has_error(data) || (attrib == NULL) ||
+ (value.data == NULL)) {
+ goto failed;
+ }
+
+ ret->operation = LDB_OP_GREATER;
+ ret->u.comparison.attr = talloc_steal(ret, attrib);
+ ret->u.comparison.value.data = talloc_steal(ret, value.data);
+ ret->u.comparison.value.length = value.length;
+ break;
+ }
+ case 6: {
+ /* lessOrEqual */
+ const char *attrib;
+ DATA_BLOB value;
+
+ if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) goto failed;
+ if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib)) goto failed;
+ if (!asn1_read_OctetString(data, mem_ctx, &value)) goto failed;
+ if (!asn1_end_tag(data)) goto failed;
+ if (asn1_has_error(data) || (attrib == NULL) ||
+ (value.data == NULL)) {
+ goto failed;
+ }
+
+ ret->operation = LDB_OP_LESS;
+ ret->u.comparison.attr = talloc_steal(ret, attrib);
+ ret->u.comparison.value.data = talloc_steal(ret, value.data);
+ ret->u.comparison.value.length = value.length;
+ break;
+ }
+ case 7: {
+ /* Normal presence, "attribute=*" */
+ char *attr;
+
+ if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(filter_tag))) {
+ goto failed;
+ }
+ if (!asn1_read_LDAPString(data, ret, &attr)) {
+ goto failed;
+ }
+
+ ret->operation = LDB_OP_PRESENT;
+ ret->u.present.attr = talloc_steal(ret, attr);
+
+ if (!asn1_end_tag(data)) {
+ goto failed;
+ }
+ break;
+ }
+ case 8: {
+ /* approx */
+ const char *attrib;
+ DATA_BLOB value;
+
+ if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) goto failed;
+ if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib)) goto failed;
+ if (!asn1_read_OctetString(data, mem_ctx, &value)) goto failed;
+ if (!asn1_end_tag(data)) goto failed;
+ if (asn1_has_error(data) || (attrib == NULL) ||
+ (value.data == NULL)) {
+ goto failed;
+ }
+
+ ret->operation = LDB_OP_APPROX;
+ ret->u.comparison.attr = talloc_steal(ret, attrib);
+ ret->u.comparison.value.data = talloc_steal(ret, value.data);
+ ret->u.comparison.value.length = value.length;
+ break;
+ }
+ case 9: {
+ char *oid = NULL, *attr = NULL, *value;
+ uint8_t dnAttributes;
+ /* an extended search */
+ if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
+ goto failed;
+ }
+
+ /* FIXME: read carefully rfc2251.txt there are a number of 'MUST's
+ we need to check we properly implement --SSS */
+ /* either oid or type must be defined */
+ if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(1))) { /* optional */
+ if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(1))) goto failed;
+ if (!asn1_read_LDAPString(data, ret, &oid)) goto failed;
+ if (!asn1_end_tag(data)) goto failed;
+ }
+ if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(2))) { /* optional */
+ if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(2))) goto failed;
+ if (!asn1_read_LDAPString(data, ret, &attr)) goto failed;
+ if (!asn1_end_tag(data)) goto failed;
+ }
+ if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(3))) goto failed;
+ if (!asn1_read_LDAPString(data, ret, &value)) goto failed;
+ if (!asn1_end_tag(data)) goto failed;
+ /* dnAttributes is marked as BOOLEAN DEFAULT FALSE
+ it is not marked as OPTIONAL but openldap tools
+ do not set this unless it is to be set as TRUE
+ NOTE: openldap tools do not work with AD as it
+ seems that AD always requires the dnAttributes
+ boolean value to be set */
+ if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(4))) {
+ if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(4))) goto failed;
+ if (!asn1_read_uint8(data, &dnAttributes)) goto failed;
+ if (!asn1_end_tag(data)) goto failed;
+ } else {
+ dnAttributes = 0;
+ }
+ if ((oid == NULL && attr == NULL) || (value == NULL)) {
+ goto failed;
+ }
+
+ if (oid) {
+ ret->operation = LDB_OP_EXTENDED;
+
+ /* From the RFC2251: If the type field is
+ absent and matchingRule is present, the matchValue is compared
+ against all attributes in an entry which support that matchingRule
+ */
+ if (attr) {
+ ret->u.extended.attr = talloc_steal(ret, attr);
+ } else {
+ ret->u.extended.attr = talloc_strdup(ret, "*");
+ if (ret->u.extended.attr == NULL) {
+ goto failed;
+ }
+ }
+ ret->u.extended.rule_id = talloc_steal(ret, oid);
+ ret->u.extended.value.data = (uint8_t *)talloc_steal(ret, value);
+ ret->u.extended.value.length = strlen(value);
+ ret->u.extended.dnAttributes = dnAttributes;
+ } else {
+ ret->operation = LDB_OP_EQUALITY;
+ ret->u.equality.attr = talloc_steal(ret, attr);
+ ret->u.equality.value.data = (uint8_t *)talloc_steal(ret, value);
+ ret->u.equality.value.length = strlen(value);
+ }
+ if (!asn1_end_tag(data)) {
+ goto failed;
+ }
+ break;
+ }
+
+ default:
+ goto failed;
+ }
+
+ return ret;
+
+failed:
+ talloc_free(ret);
+ return NULL;
+}
+
+/* Decode a single LDAP attribute, possibly containing multiple values */
+static bool ldap_decode_attrib(TALLOC_CTX *mem_ctx, struct asn1_data *data,
+ struct ldb_message_element *attrib)
+{
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) return false;
+ if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib->name)) return false;
+ if (!asn1_start_tag(data, ASN1_SET)) return false;
+ while (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
+ DATA_BLOB blob;
+ if (!asn1_read_OctetString(data, mem_ctx, &blob)) return false;
+ add_value_to_attrib(mem_ctx, &blob, attrib);
+ }
+ if (!asn1_end_tag(data)) return false;
+ return asn1_end_tag(data);
+}
+
+/* Decode a set of LDAP attributes, as found in the dereference control */
+bool ldap_decode_attribs_bare(TALLOC_CTX *mem_ctx, struct asn1_data *data,
+ struct ldb_message_element **attributes,
+ int *num_attributes)
+{
+ while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
+ struct ldb_message_element attrib;
+ ZERO_STRUCT(attrib);
+ if (!ldap_decode_attrib(mem_ctx, data, &attrib)) return false;
+ add_attrib_to_array_talloc(mem_ctx, &attrib,
+ attributes, num_attributes);
+ }
+ return true;
+}
+
+/* Decode a set of LDAP attributes, as found in a search entry */
+static bool ldap_decode_attribs(TALLOC_CTX *mem_ctx, struct asn1_data *data,
+ struct ldb_message_element **attributes,
+ int *num_attributes)
+{
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) return false;
+ if (!ldap_decode_attribs_bare(mem_ctx, data,
+ attributes, num_attributes)) return false;
+ return asn1_end_tag(data);
+}
+
+/* This routine returns LDAP status codes */
+
+_PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data,
+ const struct ldap_request_limits *limits,
+ const struct ldap_control_handler *control_handlers,
+ struct ldap_message *msg)
+{
+ uint8_t tag;
+
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto prot_err;
+ if (!asn1_read_Integer(data, &msg->messageid)) goto prot_err;
+
+ if (!asn1_peek_uint8(data, &tag)) goto prot_err;
+
+ switch(tag) {
+
+ case ASN1_APPLICATION(LDAP_TAG_BindRequest): {
+ struct ldap_BindRequest *r = &msg->r.BindRequest;
+ msg->type = LDAP_TAG_BindRequest;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!asn1_read_Integer(data, &r->version)) goto prot_err;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->dn)) goto prot_err;
+ if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(0))) {
+ int pwlen;
+ r->creds.password = "";
+ r->mechanism = LDAP_AUTH_MECH_SIMPLE;
+ if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0))) goto prot_err;
+ pwlen = asn1_tag_remaining(data);
+ if (pwlen == -1) {
+ goto prot_err;
+ }
+ if (pwlen != 0) {
+ char *pw = talloc_array(msg, char, pwlen+1);
+ if (!pw) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+ if (!asn1_read(data, pw, pwlen)) goto prot_err;
+ pw[pwlen] = '\0';
+ r->creds.password = pw;
+ }
+ if (!asn1_end_tag(data)) goto prot_err;
+ } else if (asn1_peek_tag(data, ASN1_CONTEXT(3))){
+ if (!asn1_start_tag(data, ASN1_CONTEXT(3))) goto prot_err;
+ r->mechanism = LDAP_AUTH_MECH_SASL;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->creds.SASL.mechanism)) goto prot_err;
+ if (asn1_peek_tag(data, ASN1_OCTET_STRING)) { /* optional */
+ DATA_BLOB tmp_blob = data_blob(NULL, 0);
+ if (!asn1_read_OctetString(data, msg, &tmp_blob)) goto prot_err;
+ r->creds.SASL.secblob = talloc(msg, DATA_BLOB);
+ if (!r->creds.SASL.secblob) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+ *r->creds.SASL.secblob = data_blob_talloc(r->creds.SASL.secblob,
+ tmp_blob.data, tmp_blob.length);
+ data_blob_free(&tmp_blob);
+ } else {
+ r->creds.SASL.secblob = NULL;
+ }
+ if (!asn1_end_tag(data)) goto prot_err;
+ } else {
+ /* Neither Simple nor SASL bind */
+ goto prot_err;
+ }
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_BindResponse): {
+ struct ldap_BindResponse *r = &msg->r.BindResponse;
+ msg->type = LDAP_TAG_BindResponse;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!ldap_decode_response(msg, data, &r->response)) goto prot_err;
+ if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(7))) {
+ DATA_BLOB tmp_blob = data_blob(NULL, 0);
+ if (!asn1_read_ContextSimple(data, msg, 7, &tmp_blob)) goto prot_err;
+ r->SASL.secblob = talloc(msg, DATA_BLOB);
+ if (!r->SASL.secblob) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+ *r->SASL.secblob = data_blob_talloc(r->SASL.secblob,
+ tmp_blob.data, tmp_blob.length);
+ data_blob_free(&tmp_blob);
+ } else {
+ r->SASL.secblob = NULL;
+ }
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION_SIMPLE(LDAP_TAG_UnbindRequest): {
+ msg->type = LDAP_TAG_UnbindRequest;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_SearchRequest): {
+ struct ldap_SearchRequest *r = &msg->r.SearchRequest;
+ int sizelimit, timelimit;
+ const char **attrs = NULL;
+ size_t request_size = asn1_get_length(data);
+ msg->type = LDAP_TAG_SearchRequest;
+ if (request_size > limits->max_search_size) {
+ goto prot_err;
+ }
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->basedn)) goto prot_err;
+ if (!asn1_read_enumerated(data, (int *)(void *)&(r->scope))) goto prot_err;
+ if (!asn1_read_enumerated(data, (int *)(void *)&(r->deref))) goto prot_err;
+ if (!asn1_read_Integer(data, &sizelimit)) goto prot_err;
+ r->sizelimit = sizelimit;
+ if (!asn1_read_Integer(data, &timelimit)) goto prot_err;
+ r->timelimit = timelimit;
+ if (!asn1_read_BOOLEAN(data, &r->attributesonly)) goto prot_err;
+
+ r->tree = ldap_decode_filter_tree(msg, data);
+ if (r->tree == NULL) {
+ goto prot_err;
+ }
+
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto prot_err;
+
+ r->num_attributes = 0;
+ r->attributes = NULL;
+
+ while (asn1_tag_remaining(data) > 0) {
+
+ const char *attr;
+ if (!asn1_read_OctetString_talloc(msg, data,
+ &attr))
+ goto prot_err;
+ if (!add_string_to_array(msg, attr,
+ &attrs,
+ &r->num_attributes))
+ goto prot_err;
+ }
+ r->attributes = attrs;
+
+ if (!asn1_end_tag(data)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_SearchResultEntry): {
+ struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
+ msg->type = LDAP_TAG_SearchResultEntry;
+ r->attributes = NULL;
+ r->num_attributes = 0;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->dn)) goto prot_err;
+ if (!ldap_decode_attribs(msg, data, &r->attributes,
+ &r->num_attributes)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_SearchResultDone): {
+ struct ldap_Result *r = &msg->r.SearchResultDone;
+ msg->type = LDAP_TAG_SearchResultDone;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!ldap_decode_response(msg, data, r)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_SearchResultReference): {
+ struct ldap_SearchResRef *r = &msg->r.SearchResultReference;
+ msg->type = LDAP_TAG_SearchResultReference;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->referral)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_ModifyRequest): {
+ struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
+ msg->type = LDAP_TAG_ModifyRequest;
+ if (!asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_ModifyRequest))) goto prot_err;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->dn)) goto prot_err;
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto prot_err;
+
+ r->num_mods = 0;
+ r->mods = NULL;
+
+ while (asn1_tag_remaining(data) > 0) {
+ struct ldap_mod mod;
+ int v;
+ ZERO_STRUCT(mod);
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto prot_err;
+ if (!asn1_read_enumerated(data, &v)) goto prot_err;
+ mod.type = v;
+ if (!ldap_decode_attrib(msg, data, &mod.attrib)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ if (!add_mod_to_array_talloc(msg, &mod,
+ &r->mods, &r->num_mods)) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+ }
+
+ if (!asn1_end_tag(data)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_ModifyResponse): {
+ struct ldap_Result *r = &msg->r.ModifyResponse;
+ msg->type = LDAP_TAG_ModifyResponse;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!ldap_decode_response(msg, data, r)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_AddRequest): {
+ struct ldap_AddRequest *r = &msg->r.AddRequest;
+ msg->type = LDAP_TAG_AddRequest;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->dn)) goto prot_err;
+
+ r->attributes = NULL;
+ r->num_attributes = 0;
+ if (!ldap_decode_attribs(msg, data, &r->attributes,
+ &r->num_attributes)) goto prot_err;
+
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_AddResponse): {
+ struct ldap_Result *r = &msg->r.AddResponse;
+ msg->type = LDAP_TAG_AddResponse;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!ldap_decode_response(msg, data, r)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest): {
+ struct ldap_DelRequest *r = &msg->r.DelRequest;
+ int len;
+ char *dn;
+ msg->type = LDAP_TAG_DelRequest;
+ if (!asn1_start_tag(data,
+ ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest))) goto prot_err;
+ len = asn1_tag_remaining(data);
+ if (len == -1) {
+ goto prot_err;
+ }
+ dn = talloc_array(msg, char, len+1);
+ if (dn == NULL)
+ break;
+ if (!asn1_read(data, dn, len)) goto prot_err;
+ dn[len] = '\0';
+ r->dn = dn;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_DelResponse): {
+ struct ldap_Result *r = &msg->r.DelResponse;
+ msg->type = LDAP_TAG_DelResponse;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!ldap_decode_response(msg, data, r)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest): {
+ struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
+ msg->type = LDAP_TAG_ModifyDNRequest;
+ if (!asn1_start_tag(data,
+ ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest))) goto prot_err;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->dn)) goto prot_err;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->newrdn)) goto prot_err;
+ if (!asn1_read_BOOLEAN(data, &r->deleteolddn)) goto prot_err;
+ r->newsuperior = NULL;
+ if (asn1_tag_remaining(data) > 0) {
+ int len;
+ char *newsup;
+ if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0))) goto prot_err;
+ len = asn1_tag_remaining(data);
+ if (len == -1) {
+ goto prot_err;
+ }
+ newsup = talloc_array(msg, char, len+1);
+ if (newsup == NULL) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+ if (!asn1_read(data, newsup, len)) goto prot_err;
+ newsup[len] = '\0';
+ r->newsuperior = newsup;
+ if (!asn1_end_tag(data)) goto prot_err;
+ }
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_ModifyDNResponse): {
+ struct ldap_Result *r = &msg->r.ModifyDNResponse;
+ msg->type = LDAP_TAG_ModifyDNResponse;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!ldap_decode_response(msg, data, r)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_CompareRequest): {
+ struct ldap_CompareRequest *r = &msg->r.CompareRequest;
+ msg->type = LDAP_TAG_CompareRequest;
+ if (!asn1_start_tag(data,
+ ASN1_APPLICATION(LDAP_TAG_CompareRequest))) goto prot_err;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->dn)) goto prot_err;
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto prot_err;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->attribute)) goto prot_err;
+ if (!asn1_read_OctetString(data, msg, &r->value)) goto prot_err;
+ if (r->value.data) {
+ talloc_steal(msg, r->value.data);
+ }
+ if (!asn1_end_tag(data)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_CompareResponse): {
+ struct ldap_Result *r = &msg->r.CompareResponse;
+ msg->type = LDAP_TAG_CompareResponse;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!ldap_decode_response(msg, data, r)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION_SIMPLE(LDAP_TAG_AbandonRequest): {
+ struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
+ msg->type = LDAP_TAG_AbandonRequest;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!asn1_read_implicit_Integer(data, &r->messageid)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_ExtendedRequest): {
+ struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
+ DATA_BLOB tmp_blob = data_blob(NULL, 0);
+
+ msg->type = LDAP_TAG_ExtendedRequest;
+ if (!asn1_start_tag(data,tag)) goto prot_err;
+ if (!asn1_read_ContextSimple(data, msg, 0, &tmp_blob)) {
+ goto prot_err;
+ }
+ r->oid = blob2string_talloc(msg, tmp_blob);
+ data_blob_free(&tmp_blob);
+ if (!r->oid) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+
+ if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(1))) {
+ if (!asn1_read_ContextSimple(data, msg, 1, &tmp_blob)) goto prot_err;
+ r->value = talloc(msg, DATA_BLOB);
+ if (!r->value) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+ *r->value = data_blob_talloc(r->value, tmp_blob.data, tmp_blob.length);
+ data_blob_free(&tmp_blob);
+ } else {
+ r->value = NULL;
+ }
+
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_ExtendedResponse): {
+ struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
+ DATA_BLOB tmp_blob = data_blob(NULL, 0);
+
+ msg->type = LDAP_TAG_ExtendedResponse;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!ldap_decode_response(msg, data, &r->response)) goto prot_err;
+
+ if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(10))) {
+ if (!asn1_read_ContextSimple(data, msg, 10, &tmp_blob))
+ goto prot_err;
+ r->oid = blob2string_talloc(msg, tmp_blob);
+ data_blob_free(&tmp_blob);
+ if (!r->oid) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+ } else {
+ r->oid = NULL;
+ }
+
+ if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(11))) {
+ if (!asn1_read_ContextSimple(data, msg, 11, &tmp_blob))
+ goto prot_err;
+ r->value = talloc(msg, DATA_BLOB);
+ if (!r->value) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+ *r->value = data_blob_talloc(r->value, tmp_blob.data, tmp_blob.length);
+ data_blob_free(&tmp_blob);
+ } else {
+ r->value = NULL;
+ }
+
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+ default:
+ goto prot_err;
+ }
+
+ msg->controls = NULL;
+ msg->controls_decoded = NULL;
+
+ if (asn1_peek_tag(data, ASN1_CONTEXT(0))) {
+ int i = 0;
+ struct ldb_control **ctrl = NULL;
+ bool *decoded = NULL;
+
+ if (!asn1_start_tag(data, ASN1_CONTEXT(0))) goto prot_err;
+
+ while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
+ DATA_BLOB value;
+ /* asn1_start_tag(data, ASN1_SEQUENCE(0)); */
+
+ ctrl = talloc_realloc(msg, ctrl, struct ldb_control *, i+2);
+ if (!ctrl) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+
+ decoded = talloc_realloc(msg, decoded, bool, i+1);
+ if (!decoded) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+
+ ctrl[i] = talloc(ctrl, struct ldb_control);
+ if (!ctrl[i]) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+
+ if (!ldap_decode_control_wrapper(ctrl[i], data, ctrl[i], &value)) {
+ goto prot_err;
+ }
+
+ if (!ldap_decode_control_value(ctrl[i], value,
+ control_handlers,
+ ctrl[i])) {
+ if (ctrl[i]->critical) {
+ ctrl[i]->data = NULL;
+ decoded[i] = false;
+ i++;
+ } else {
+ talloc_free(ctrl[i]);
+ ctrl[i] = NULL;
+ }
+ } else {
+ decoded[i] = true;
+ i++;
+ }
+ }
+
+ if (ctrl != NULL) {
+ ctrl[i] = NULL;
+ }
+
+ msg->controls = ctrl;
+ msg->controls_decoded = decoded;
+
+ if (!asn1_end_tag(data)) goto prot_err;
+ }
+
+ if (!asn1_end_tag(data)) goto prot_err;
+ if (asn1_has_error(data) || asn1_has_nesting(data)) {
+ return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
+ }
+ return NT_STATUS_OK;
+
+ prot_err:
+
+ return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
+}
+
+
+/*
+ return NT_STATUS_OK if a blob has enough bytes in it to be a full
+ ldap packet. Set packet_size if true.
+*/
+NTSTATUS ldap_full_packet(struct tstream_context *stream,
+ void *private_data,
+ DATA_BLOB blob,
+ size_t *packet_size)
+{
+ int ret;
+
+ if (blob.length < 6) {
+ /*
+ * We need at least 6 bytes to workout the length
+ * of the pdu.
+ */
+ return STATUS_MORE_ENTRIES;
+ }
+
+ ret = asn1_peek_full_tag(blob, ASN1_SEQUENCE(0), packet_size);
+ if (ret != 0) {
+ return map_nt_error_from_unix_common(ret);
+ }
+ return NT_STATUS_OK;
+}
diff --git a/libcli/ldap/ldap_message.h b/libcli/ldap/ldap_message.h
new file mode 100644
index 0000000..dcbd1e9
--- /dev/null
+++ b/libcli/ldap/ldap_message.h
@@ -0,0 +1,244 @@
+/*
+ Unix SMB/CIFS Implementation.
+ LDAP protocol helper functions for SAMBA
+ Copyright (C) Volker Lendecke 2004
+
+ 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/>.
+
+*/
+
+#ifndef _LIBCLI_LDAP_MESSAGE_H_
+#define _LIBCLI_LDAP_MESSAGE_H_
+
+#include "../libcli/ldap/ldap_errors.h"
+#include <ldb.h>
+
+enum ldap_request_tag {
+ LDAP_TAG_BindRequest = 0,
+ LDAP_TAG_BindResponse = 1,
+ LDAP_TAG_UnbindRequest = 2,
+ LDAP_TAG_SearchRequest = 3,
+ LDAP_TAG_SearchResultEntry = 4,
+ LDAP_TAG_SearchResultDone = 5,
+ LDAP_TAG_ModifyRequest = 6,
+ LDAP_TAG_ModifyResponse = 7,
+ LDAP_TAG_AddRequest = 8,
+ LDAP_TAG_AddResponse = 9,
+ LDAP_TAG_DelRequest = 10,
+ LDAP_TAG_DelResponse = 11,
+ LDAP_TAG_ModifyDNRequest = 12,
+ LDAP_TAG_ModifyDNResponse = 13,
+ LDAP_TAG_CompareRequest = 14,
+ LDAP_TAG_CompareResponse = 15,
+ LDAP_TAG_AbandonRequest = 16,
+ LDAP_TAG_SearchResultReference = 19,
+ LDAP_TAG_ExtendedRequest = 23,
+ LDAP_TAG_ExtendedResponse = 24
+};
+
+enum ldap_auth_mechanism {
+ LDAP_AUTH_MECH_SIMPLE = 0,
+ LDAP_AUTH_MECH_SASL = 3
+};
+
+struct ldap_Result {
+ int resultcode;
+ const char *dn;
+ const char *errormessage;
+ const char *referral;
+};
+
+struct ldap_BindRequest {
+ int version;
+ const char *dn;
+ enum ldap_auth_mechanism mechanism;
+ union {
+ const char *password;
+ struct {
+ const char *mechanism;
+ DATA_BLOB *secblob;/* optional */
+ } SASL;
+ } creds;
+};
+
+struct ldap_BindResponse {
+ struct ldap_Result response;
+ union {
+ DATA_BLOB *secblob;/* optional */
+ } SASL;
+};
+
+struct ldap_UnbindRequest {
+ uint8_t __dummy;
+};
+
+enum ldap_scope {
+ LDAP_SEARCH_SCOPE_BASE = 0,
+ LDAP_SEARCH_SCOPE_SINGLE = 1,
+ LDAP_SEARCH_SCOPE_SUB = 2
+};
+
+enum ldap_deref {
+ LDAP_DEREFERENCE_NEVER = 0,
+ LDAP_DEREFERENCE_IN_SEARCHING = 1,
+ LDAP_DEREFERENCE_FINDING_BASE = 2,
+ LDAP_DEREFERENCE_ALWAYS
+};
+
+struct ldap_SearchRequest {
+ const char *basedn;
+ enum ldap_scope scope;
+ enum ldap_deref deref;
+ uint32_t timelimit;
+ uint32_t sizelimit;
+ bool attributesonly;
+ struct ldb_parse_tree *tree;
+ size_t num_attributes;
+ const char * const *attributes;
+};
+
+struct ldap_SearchResEntry {
+ const char *dn;
+ int num_attributes;
+ struct ldb_message_element *attributes;
+};
+
+struct ldap_SearchResRef {
+ const char *referral;
+};
+
+enum ldap_modify_type {
+ LDAP_MODIFY_NONE = -1,
+ LDAP_MODIFY_ADD = 0,
+ LDAP_MODIFY_DELETE = 1,
+ LDAP_MODIFY_REPLACE = 2
+};
+
+struct ldap_mod {
+ enum ldap_modify_type type;
+ struct ldb_message_element attrib;
+};
+
+struct ldap_ModifyRequest {
+ const char *dn;
+ int num_mods;
+ struct ldap_mod *mods;
+};
+
+struct ldap_AddRequest {
+ const char *dn;
+ int num_attributes;
+ struct ldb_message_element *attributes;
+};
+
+struct ldap_DelRequest {
+ const char *dn;
+};
+
+struct ldap_ModifyDNRequest {
+ const char *dn;
+ const char *newrdn;
+ bool deleteolddn;
+ const char *newsuperior;/* optional */
+};
+
+struct ldap_CompareRequest {
+ const char *dn;
+ const char *attribute;
+ DATA_BLOB value;
+};
+
+struct ldap_AbandonRequest {
+ int messageid;
+};
+
+struct ldap_ExtendedRequest {
+ const char *oid;
+ DATA_BLOB *value;/* optional */
+};
+
+struct ldap_ExtendedResponse {
+ struct ldap_Result response;
+ const char *oid;/* optional */
+ DATA_BLOB *value;/* optional */
+};
+
+union ldap_Request {
+ struct ldap_Result GeneralResult;
+ struct ldap_BindRequest BindRequest;
+ struct ldap_BindResponse BindResponse;
+ struct ldap_UnbindRequest UnbindRequest;
+ struct ldap_SearchRequest SearchRequest;
+ struct ldap_SearchResEntry SearchResultEntry;
+ struct ldap_Result SearchResultDone;
+ struct ldap_SearchResRef SearchResultReference;
+ struct ldap_ModifyRequest ModifyRequest;
+ struct ldap_Result ModifyResponse;
+ struct ldap_AddRequest AddRequest;
+ struct ldap_Result AddResponse;
+ struct ldap_DelRequest DelRequest;
+ struct ldap_Result DelResponse;
+ struct ldap_ModifyDNRequest ModifyDNRequest;
+ struct ldap_Result ModifyDNResponse;
+ struct ldap_CompareRequest CompareRequest;
+ struct ldap_Result CompareResponse;
+ struct ldap_AbandonRequest AbandonRequest;
+ struct ldap_ExtendedRequest ExtendedRequest;
+ struct ldap_ExtendedResponse ExtendedResponse;
+};
+
+
+struct ldap_message {
+ int messageid;
+ enum ldap_request_tag type;
+ union ldap_Request r;
+ struct ldb_control **controls;
+ bool *controls_decoded;
+};
+
+struct ldap_control_handler {
+ const char *oid;
+ bool (*decode)(void *mem_ctx, DATA_BLOB in, void *_out);
+ bool (*encode)(void *mem_ctx, void *in, DATA_BLOB *out);
+};
+
+struct ldap_request_limits {
+ unsigned max_search_size;
+};
+
+struct asn1_data;
+struct tstream_context;
+
+struct ldap_message *new_ldap_message(TALLOC_CTX *mem_ctx);
+NTSTATUS ldap_decode(struct asn1_data *data,
+ const struct ldap_request_limits *limits,
+ const struct ldap_control_handler *control_handlers,
+ struct ldap_message *msg);
+bool ldap_encode(struct ldap_message *msg,
+ const struct ldap_control_handler *control_handlers,
+ DATA_BLOB *result, TALLOC_CTX *mem_ctx);
+NTSTATUS ldap_full_packet(struct tstream_context *stream,
+ void *private_data,
+ DATA_BLOB blob,
+ size_t *packet_size);
+
+bool asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
+ struct asn1_data *data,
+ const char **result);
+
+bool ldap_decode_attribs_bare(TALLOC_CTX *mem_ctx, struct asn1_data *data,
+ struct ldb_message_element **attributes,
+ int *num_attributes);
+
+#endif
diff --git a/libcli/ldap/ldap_ndr.c b/libcli/ldap/ldap_ndr.c
new file mode 100644
index 0000000..4f63bc1
--- /dev/null
+++ b/libcli/ldap/ldap_ndr.c
@@ -0,0 +1,95 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ wrap/unwrap NDR encoded elements for ldap calls
+
+ Copyright (C) Andrew Tridgell 2005
+
+ 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 <ldb.h>
+#include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "libcli/ldap/ldap_ndr.h"
+
+/*
+ encode a NDR uint32 as a ldap filter element
+*/
+char *ldap_encode_ndr_uint32(TALLOC_CTX *mem_ctx, uint32_t value)
+{
+ uint8_t buf[4];
+ struct ldb_val val;
+ SIVAL(buf, 0, value);
+ val.data = buf;
+ val.length = 4;
+ return ldb_binary_encode(mem_ctx, val);
+}
+
+/*
+ encode a NDR dom_sid as a ldap filter element
+*/
+char *ldap_encode_ndr_dom_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+ char *ret;
+ ndr_err = ndr_push_struct_blob(&blob, mem_ctx, sid,
+ (ndr_push_flags_fn_t)ndr_push_dom_sid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return NULL;
+ }
+ ret = ldb_binary_encode(mem_ctx, blob);
+ data_blob_free(&blob);
+ return ret;
+}
+
+
+/*
+ encode a NDR GUID as a ldap filter element
+*/
+char *ldap_encode_ndr_GUID(TALLOC_CTX *mem_ctx, const struct GUID *guid)
+{
+ struct GUID_ndr_buf buf = { .buf = {0}, };
+ DATA_BLOB blob = { .data = buf.buf, .length = sizeof(buf.buf), };
+ NTSTATUS status;
+ char *ret;
+ status = GUID_to_ndr_buf(guid, &buf);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ ret = ldb_binary_encode(mem_ctx, blob);
+ return ret;
+}
+
+/*
+ decode a NDR GUID from a ldap filter element
+*/
+NTSTATUS ldap_decode_ndr_GUID(TALLOC_CTX *mem_ctx, struct ldb_val val, struct GUID *guid)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+
+ blob.data = val.data;
+ blob.length = val.length;
+ ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, guid,
+ (ndr_pull_flags_fn_t)ndr_pull_GUID);
+ talloc_free(val.data);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ return NT_STATUS_OK;
+}
diff --git a/libcli/ldap/ldap_ndr.h b/libcli/ldap/ldap_ndr.h
new file mode 100644
index 0000000..99af081
--- /dev/null
+++ b/libcli/ldap/ldap_ndr.h
@@ -0,0 +1,34 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ wrap/unwrap NDR encoded elements for ldap calls
+
+ Copyright (C) Andrew Tridgell 2005
+
+ 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/>.
+
+*/
+
+#ifndef __LIBCLI_LDAP_LDAP_NDR_H__
+#define __LIBCLI_LDAP_LDAP_NDR_H__
+
+#include "librpc/gen_ndr/ndr_misc.h"
+
+char *ldap_encode_ndr_uint32(TALLOC_CTX *mem_ctx, uint32_t value);
+char *ldap_encode_ndr_dom_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid);
+char *ldap_encode_ndr_GUID(TALLOC_CTX *mem_ctx, const struct GUID *guid);
+NTSTATUS ldap_decode_ndr_GUID(TALLOC_CTX *mem_ctx, struct ldb_val val, struct GUID *guid);
+
+#endif /* __LIBCLI_LDAP_LDAP_NDR_H__ */
+
diff --git a/libcli/ldap/tests/data/10000-or.dat b/libcli/ldap/tests/data/10000-or.dat
new file mode 100644
index 0000000..e2d6de2
--- /dev/null
+++ b/libcli/ldap/tests/data/10000-or.dat
Binary files differ
diff --git a/libcli/ldap/tests/data/ldap-recursive.dat b/libcli/ldap/tests/data/ldap-recursive.dat
new file mode 100644
index 0000000..dd18d85
--- /dev/null
+++ b/libcli/ldap/tests/data/ldap-recursive.dat
Binary files differ
diff --git a/libcli/ldap/tests/data/ldap-starttls-response.dat b/libcli/ldap/tests/data/ldap-starttls-response.dat
new file mode 100644
index 0000000..d4294bf
--- /dev/null
+++ b/libcli/ldap/tests/data/ldap-starttls-response.dat
Binary files differ
diff --git a/libcli/ldap/tests/ldap_message_test.c b/libcli/ldap/tests/ldap_message_test.c
new file mode 100644
index 0000000..bea7b91
--- /dev/null
+++ b/libcli/ldap/tests/ldap_message_test.c
@@ -0,0 +1,345 @@
+/*
+ * Unit tests for ldap_message.
+ *
+ * Copyright (C) Catalyst.NET Ltd 2020
+ *
+ * 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/>.
+ *
+ */
+
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ *
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "lib/util/attr.h"
+#include "includes.h"
+#include "lib/util/asn1.h"
+#include "libcli/ldap/ldap_message.h"
+#include "libcli/ldap/ldap_proto.h"
+
+/*
+ * declare the internal cmocka cm_print so we can output messages in
+ * sub unit format
+ */
+void cm_print_error(const char * const format, ...);
+/*
+ * helper function and macro to compare an ldap error code constant with the
+ * corresponding nt_status code
+ */
+#define NT_STATUS_LDAP_V(code) (0xF2000000 | code)
+static void _assert_ldap_status_equal(
+ int a,
+ NTSTATUS b,
+ const char * const file,
+ const int line)
+{
+ _assert_int_equal(NT_STATUS_LDAP_V(a), NT_STATUS_V(b), file, line);
+}
+
+#define assert_ldap_status_equal(a, b) \
+ _assert_ldap_status_equal((a), (b), __FILE__, __LINE__)
+
+/*
+ * helper function and macro to assert there were no errors in the last
+ * file operation
+ */
+static void _assert_not_ferror(
+ FILE *f,
+ const char * const file,
+ const int line)
+{
+ if (f == NULL || ferror(f)) {
+ cm_print_error("ferror (%d) %s\n", errno, strerror(errno));
+ _fail(file, line);
+ }
+}
+
+#define assert_not_ferror(f) \
+ _assert_not_ferror((f), __FILE__, __LINE__)
+
+struct test_ctx {
+};
+
+static int setup(void **state)
+{
+ struct test_ctx *test_ctx;
+
+ test_ctx = talloc_zero(NULL, struct test_ctx);
+ *state = test_ctx;
+ return 0;
+}
+
+static int teardown(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct test_ctx);
+
+ TALLOC_FREE(test_ctx);
+ return 0;
+}
+
+/*
+ * Test that an empty request is handled correctly
+ */
+static void test_empty_input(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(
+ *state,
+ struct test_ctx);
+ struct asn1_data *asn1;
+ struct ldap_message *ldap_msg;
+ NTSTATUS status;
+ uint8_t *buf = NULL;
+ size_t len = 0;
+ struct ldap_request_limits limits = {
+ .max_search_size = 256000,
+ };
+
+
+ asn1 = asn1_init(test_ctx, ASN1_MAX_TREE_DEPTH);
+ assert_non_null(asn1);
+
+ asn1_load_nocopy(asn1, buf, len);
+
+ ldap_msg = talloc(test_ctx, struct ldap_message);
+ assert_non_null(ldap_msg);
+
+ status = ldap_decode(
+ asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
+ assert_ldap_status_equal(LDAP_PROTOCOL_ERROR, status);
+}
+
+/*
+ * Check that a request is rejected it it's recursion depth exceeds
+ * the maximum value specified. This test uses a very deeply nested query,
+ * 10,000 or clauses.
+ *
+ */
+static void test_recursion_depth_large(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(
+ *state,
+ struct test_ctx);
+ struct asn1_data *asn1;
+ struct ldap_message *ldap_msg;
+ NTSTATUS status;
+ FILE *f = NULL;
+ uint8_t *buffer = NULL;
+ const size_t BUFF_SIZE = 1048576;
+ size_t len;
+ struct ldap_request_limits limits = {
+ .max_search_size = 256000,
+ };
+
+
+ /*
+ * Load a test data file containing 10,000 or clauses in encoded as
+ * an ASN.1 packet.
+ */
+ buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE);
+ f = fopen("./libcli/ldap/tests/data/10000-or.dat", "r");
+ assert_not_ferror(f);
+ len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f);
+ assert_not_ferror(f);
+ assert_true(len > 0);
+
+ asn1 = asn1_init(test_ctx, ASN1_MAX_TREE_DEPTH);
+ assert_non_null(asn1);
+ asn1_load_nocopy(asn1, buffer, len);
+
+ ldap_msg = talloc(test_ctx, struct ldap_message);
+ assert_non_null(ldap_msg);
+
+ status = ldap_decode(
+ asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
+ assert_ldap_status_equal(LDAP_PROTOCOL_ERROR, status);
+}
+
+/*
+ * Check that a request is not rejected it it's recursion depth equals the
+ * maximum value
+ */
+static void test_recursion_depth_equals_max(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(
+ *state,
+ struct test_ctx);
+ struct asn1_data *asn1;
+ struct ldap_message *ldap_msg;
+ NTSTATUS status;
+ FILE *f = NULL;
+ uint8_t *buffer = NULL;
+ const size_t BUFF_SIZE = 1048576;
+ size_t len;
+ int ret;
+ struct ldap_request_limits limits = {
+ .max_search_size = 256000,
+ };
+
+
+ buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE);
+ f = fopen("./libcli/ldap/tests/data/ldap-recursive.dat", "r");
+ assert_not_ferror(f);
+ len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f);
+ assert_not_ferror(f);
+ assert_true(len > 0);
+
+ asn1 = asn1_init(test_ctx, 4);
+ assert_non_null(asn1);
+ asn1_load_nocopy(asn1, buffer, len);
+
+ ldap_msg = talloc(test_ctx, struct ldap_message);
+ assert_non_null(ldap_msg);
+
+ status = ldap_decode(
+ asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
+ assert_true(NT_STATUS_IS_OK(status));
+
+ ret = fclose(f);
+ f = NULL;
+ assert_true(ret == 0);
+}
+
+/*
+ * Check that a request is rejected it it's recursion depth is greater than the
+ * maximum value
+ */
+static void test_recursion_depth_greater_than_max(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(
+ *state,
+ struct test_ctx);
+ struct asn1_data *asn1;
+ struct ldap_message *ldap_msg;
+ NTSTATUS status;
+ FILE *f = NULL;
+ uint8_t *buffer = NULL;
+ const size_t BUFF_SIZE = 1048576;
+ size_t len;
+ int ret;
+ struct ldap_request_limits limits = {
+ .max_search_size = 256000,
+ };
+
+
+ buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE);
+ f = fopen("./libcli/ldap/tests/data/ldap-recursive.dat", "r");
+ assert_not_ferror(f);
+ len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f);
+ assert_not_ferror(f);
+ assert_true(len > 0);
+
+ asn1 = asn1_init(test_ctx, 3);
+ assert_non_null(asn1);
+ asn1_load_nocopy(asn1, buffer, len);
+
+ ldap_msg = talloc(test_ctx, struct ldap_message);
+ assert_non_null(ldap_msg);
+
+ status = ldap_decode(
+ asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
+ assert_ldap_status_equal(LDAP_PROTOCOL_ERROR, status);
+
+ ret = fclose(f);
+ f = NULL;
+ assert_true(ret == 0);
+}
+
+/*
+ * Check we can decode an exop response
+ */
+static void test_decode_exop_response(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(
+ *state,
+ struct test_ctx);
+ struct asn1_data *asn1;
+ struct ldap_message *ldap_msg;
+ NTSTATUS status;
+ FILE *f = NULL;
+ uint8_t *buffer = NULL;
+ const size_t BUFF_SIZE = 1048576;
+ size_t len;
+ int ret;
+ struct ldap_request_limits limits = {
+ .max_search_size = 256000,
+ };
+
+
+ buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE);
+ f = fopen("./libcli/ldap/tests/data/ldap-starttls-response.dat", "r");
+ assert_not_ferror(f);
+ len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f);
+ assert_not_ferror(f);
+ assert_true(len > 0);
+
+ asn1 = asn1_init(test_ctx, 3);
+ assert_non_null(asn1);
+ asn1_load_nocopy(asn1, buffer, len);
+
+ ldap_msg = talloc(test_ctx, struct ldap_message);
+ assert_non_null(ldap_msg);
+
+ status = ldap_decode(
+ asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
+ assert_true(NT_STATUS_IS_OK(status));
+
+ ret = fclose(f);
+ f = NULL;
+ assert_true(ret == 0);
+}
+
+int main(_UNUSED_ int argc, _UNUSED_ const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(
+ test_empty_input,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_recursion_depth_large,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_recursion_depth_equals_max,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_recursion_depth_greater_than_max,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_decode_exop_response,
+ setup,
+ teardown),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/libcli/ldap/wscript_build b/libcli/ldap/wscript_build
new file mode 100644
index 0000000..a646685
--- /dev/null
+++ b/libcli/ldap/wscript_build
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+bld.SAMBA_LIBRARY('cli-ldap-common',
+ source='ldap_message.c ldap_ndr.c',
+ public_deps='samba-errors talloc ldb',
+ private_headers='ldap_message.h ldap_errors.h ldap_ndr.h',
+ deps='samba-util asn1util NDR_SECURITY tevent',
+ private_library=True)
+
+bld.SAMBA_BINARY(
+ 'test_ldap_message',
+ source='tests/ldap_message_test.c',
+ deps='''
+ cmocka
+ talloc
+ ldb
+ samba-util
+ asn1util
+ NDR_SECURITY
+ cli-ldap
+ ''',
+ for_selftest=True
+)
diff --git a/libcli/lsarpc/util_lsarpc.c b/libcli/lsarpc/util_lsarpc.c
new file mode 100644
index 0000000..96c9848
--- /dev/null
+++ b/libcli/lsarpc/util_lsarpc.c
@@ -0,0 +1,359 @@
+/*
+ Unix SMB/CIFS implementation.
+ Authentication utility functions
+ Copyright (C) Sumit Bose 2010
+
+ 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 "../librpc/gen_ndr/ndr_drsblobs.h"
+#include "../librpc/gen_ndr/ndr_lsa.h"
+#include "libcli/lsarpc/util_lsarpc.h"
+
+static NTSTATUS ai_array_2_trust_domain_info_buffer(TALLOC_CTX *mem_ctx,
+ uint32_t count,
+ struct AuthenticationInformationArray *ai,
+ struct lsa_TrustDomainInfoBuffer **_b)
+{
+ NTSTATUS status;
+ struct lsa_TrustDomainInfoBuffer *b;
+ int i;
+
+ b = talloc_array(mem_ctx, struct lsa_TrustDomainInfoBuffer, count);
+ if (b == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for(i = 0; i < count; i++) {
+ size_t size = 0;
+ b[i].last_update_time = ai->array[i].LastUpdateTime;
+ b[i].AuthType = ai->array[i].AuthType;
+ switch(ai->array[i].AuthType) {
+ case TRUST_AUTH_TYPE_NONE:
+ b[i].data.size = 0;
+ b[i].data.data = NULL;
+ break;
+ case TRUST_AUTH_TYPE_NT4OWF:
+ if (ai->array[i].AuthInfo.nt4owf.size != 16) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ b[i].data.data = (uint8_t *)talloc_memdup(b,
+ &ai->array[i].AuthInfo.nt4owf.password.hash,
+ 16);
+ if (b[i].data.data == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ break;
+ case TRUST_AUTH_TYPE_CLEAR:
+ if (!convert_string_talloc(b,
+ CH_UTF16LE, CH_UNIX,
+ ai->array[i].AuthInfo.clear.password,
+ ai->array[i].AuthInfo.clear.size,
+ &b[i].data.data,
+ &size)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ b[i].data.size = size;
+ break;
+ case TRUST_AUTH_TYPE_VERSION:
+ if (ai->array[i].AuthInfo.version.size != 4) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ b[i].data.size = 4;
+ b[i].data.data = (uint8_t *)talloc_memdup(b,
+ &ai->array[i].AuthInfo.version.version, 4);
+ if (b[i].data.data == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ break;
+ default:
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ }
+
+ *_b = b;
+
+ return NT_STATUS_OK;
+
+fail:
+ talloc_free(b);
+ return status;
+}
+
+static NTSTATUS trustauth_inout_blob_2_auth_info(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *inout_blob,
+ uint32_t *count,
+ struct lsa_TrustDomainInfoBuffer **current,
+ struct lsa_TrustDomainInfoBuffer **previous)
+{
+ NTSTATUS status;
+ struct trustAuthInOutBlob iopw;
+ enum ndr_err_code ndr_err;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ndr_err = ndr_pull_struct_blob(inout_blob, tmp_ctx, &iopw,
+ (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ *count = iopw.count;
+
+ status = ai_array_2_trust_domain_info_buffer(mem_ctx, iopw.count,
+ &iopw.current, current);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ if (iopw.previous.count > 0) {
+ status = ai_array_2_trust_domain_info_buffer(mem_ctx, iopw.count,
+ &iopw.previous, previous);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ } else {
+ *previous = NULL;
+ }
+
+ status = NT_STATUS_OK;
+
+done:
+ talloc_free(tmp_ctx);
+ return status;
+}
+
+NTSTATUS auth_blob_2_auth_info(TALLOC_CTX *mem_ctx,
+ DATA_BLOB incoming, DATA_BLOB outgoing,
+ struct lsa_TrustDomainInfoAuthInfo *auth_info)
+{
+ NTSTATUS status;
+
+ if (incoming.length != 0) {
+ status = trustauth_inout_blob_2_auth_info(mem_ctx,
+ &incoming,
+ &auth_info->incoming_count,
+ &auth_info->incoming_current_auth_info,
+ &auth_info->incoming_previous_auth_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ } else {
+ auth_info->incoming_count = 0;
+ auth_info->incoming_current_auth_info = NULL;
+ auth_info->incoming_previous_auth_info = NULL;
+ }
+
+ if (outgoing.length != 0) {
+ status = trustauth_inout_blob_2_auth_info(mem_ctx,
+ &outgoing,
+ &auth_info->outgoing_count,
+ &auth_info->outgoing_current_auth_info,
+ &auth_info->outgoing_previous_auth_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ } else {
+ auth_info->outgoing_count = 0;
+ auth_info->outgoing_current_auth_info = NULL;
+ auth_info->outgoing_previous_auth_info = NULL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS trust_domain_info_buffer_2_ai_array(TALLOC_CTX *mem_ctx,
+ uint32_t count,
+ struct lsa_TrustDomainInfoBuffer *b,
+ struct AuthenticationInformationArray *ai)
+{
+ NTSTATUS status;
+ int i;
+
+ ai->count = count;
+ ai->array = talloc_zero_array(mem_ctx, struct AuthenticationInformation,
+ count);
+ if (ai->array == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for(i = 0; i < count; i++) {
+ size_t size = 0;
+ ai->array[i].LastUpdateTime = b[i].last_update_time;
+ ai->array[i].AuthType = b[i].AuthType;
+ switch(ai->array[i].AuthType) {
+ case TRUST_AUTH_TYPE_NONE:
+ ai->array[i].AuthInfo.none.size = 0;
+ break;
+ case TRUST_AUTH_TYPE_NT4OWF:
+ if (b[i].data.size != 16) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ memcpy(&ai->array[i].AuthInfo.nt4owf.password.hash,
+ b[i].data.data, 16);
+ break;
+ case TRUST_AUTH_TYPE_CLEAR:
+ if (!convert_string_talloc(ai->array,
+ CH_UNIX, CH_UTF16,
+ b[i].data.data,
+ b[i].data.size,
+ &ai->array[i].AuthInfo.clear.password,
+ &size)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ai->array[i].AuthInfo.clear.size = size;
+ break;
+ case TRUST_AUTH_TYPE_VERSION:
+ if (b[i].data.size != 4) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ai->array[i].AuthInfo.version.size = 4;
+ memcpy(&ai->array[i].AuthInfo.version.version,
+ b[i].data.data, 4);
+ break;
+ default:
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ }
+
+ return NT_STATUS_OK;
+
+fail:
+ talloc_free(ai->array);
+ return status;
+}
+
+NTSTATUS auth_info_2_trustauth_inout(TALLOC_CTX *mem_ctx,
+ uint32_t count,
+ struct lsa_TrustDomainInfoBuffer *current,
+ struct lsa_TrustDomainInfoBuffer *previous,
+ struct trustAuthInOutBlob **iopw_out)
+{
+ NTSTATUS status;
+ struct trustAuthInOutBlob *iopw;
+
+ iopw = talloc_zero(mem_ctx, struct trustAuthInOutBlob);
+ if (iopw == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ iopw->count = count;
+ status = trust_domain_info_buffer_2_ai_array(iopw, count, current,
+ &iopw->current);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ if (previous != NULL) {
+ status = trust_domain_info_buffer_2_ai_array(iopw, count,
+ previous,
+ &iopw->previous);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ } else {
+ iopw->previous.count = 0;
+ iopw->previous.array = NULL;
+ }
+
+ *iopw_out = iopw;
+
+ status = NT_STATUS_OK;
+
+done:
+ return status;
+}
+
+static NTSTATUS auth_info_2_trustauth_inout_blob(TALLOC_CTX *mem_ctx,
+ uint32_t count,
+ struct lsa_TrustDomainInfoBuffer *current,
+ struct lsa_TrustDomainInfoBuffer *previous,
+ DATA_BLOB *inout_blob)
+{
+ NTSTATUS status;
+ struct trustAuthInOutBlob *iopw = NULL;
+ enum ndr_err_code ndr_err;
+
+ status = auth_info_2_trustauth_inout(mem_ctx, count, current, previous, &iopw);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ ndr_err = ndr_push_struct_blob(inout_blob, mem_ctx,
+ iopw,
+ (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = NT_STATUS_OK;
+
+done:
+ talloc_free(iopw);
+ return status;
+}
+
+NTSTATUS auth_info_2_auth_blob(TALLOC_CTX *mem_ctx,
+ struct lsa_TrustDomainInfoAuthInfo *auth_info,
+ DATA_BLOB *incoming, DATA_BLOB *outgoing)
+{
+ NTSTATUS status;
+
+ if (auth_info->incoming_count == 0) {
+ incoming->length = 0;
+ incoming->data = NULL;
+ } else {
+ status = auth_info_2_trustauth_inout_blob(mem_ctx,
+ auth_info->incoming_count,
+ auth_info->incoming_current_auth_info,
+ auth_info->incoming_previous_auth_info,
+ incoming);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ if (auth_info->outgoing_count == 0) {
+ outgoing->length = 0;
+ outgoing->data = NULL;
+ } else {
+ status = auth_info_2_trustauth_inout_blob(mem_ctx,
+ auth_info->outgoing_count,
+ auth_info->outgoing_current_auth_info,
+ auth_info->outgoing_previous_auth_info,
+ outgoing);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/libcli/lsarpc/util_lsarpc.h b/libcli/lsarpc/util_lsarpc.h
new file mode 100644
index 0000000..8bfec28
--- /dev/null
+++ b/libcli/lsarpc/util_lsarpc.h
@@ -0,0 +1,38 @@
+/*
+ Unix SMB/CIFS implementation.
+ Authentication utility functions
+ Copyright (C) Sumit Bose 2010
+
+ 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/>.
+*/
+
+#ifndef _LIBCLI_AUTH_UTIL_LSARPC_H_
+#define _LIBCLI_AUTH_UTIL_LSARPC_H_
+
+/* The following definitions come from libcli/auth/util_lsarpc.c */
+struct trustAuthInOutBlob;
+
+NTSTATUS auth_blob_2_auth_info(TALLOC_CTX *mem_ctx,
+ DATA_BLOB incoming, DATA_BLOB outgoing,
+ struct lsa_TrustDomainInfoAuthInfo *auth_info);
+NTSTATUS auth_info_2_trustauth_inout(TALLOC_CTX *mem_ctx,
+ uint32_t count,
+ struct lsa_TrustDomainInfoBuffer *current,
+ struct lsa_TrustDomainInfoBuffer *previous,
+ struct trustAuthInOutBlob **iopw_out);
+NTSTATUS auth_info_2_auth_blob(TALLOC_CTX *mem_ctx,
+ struct lsa_TrustDomainInfoAuthInfo *auth_info,
+ DATA_BLOB *incoming, DATA_BLOB *outgoing);
+
+#endif /* _LIBCLI_AUTH_UTIL_LSARPC_H_ */
diff --git a/libcli/lsarpc/wscript_build b/libcli/lsarpc/wscript_build
new file mode 100644
index 0000000..c613d66
--- /dev/null
+++ b/libcli/lsarpc/wscript_build
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+bld.SAMBA_SUBSYSTEM('UTIL_LSARPC',
+ source='util_lsarpc.c',
+ deps='NDR_LSA NDR_DRSBLOBS');
diff --git a/libcli/named_pipe_auth/npa_tstream.c b/libcli/named_pipe_auth/npa_tstream.c
new file mode 100644
index 0000000..a72519e
--- /dev/null
+++ b/libcli/named_pipe_auth/npa_tstream.c
@@ -0,0 +1,1406 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 2009
+
+ 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 "system/network.h"
+#include "../util/tevent_unix.h"
+#include "../lib/tsocket/tsocket.h"
+#include "../lib/tsocket/tsocket_internal.h"
+#include "../librpc/gen_ndr/ndr_named_pipe_auth.h"
+#include "../libcli/named_pipe_auth/npa_tstream.h"
+#include "../libcli/named_pipe_auth/tstream_u32_read.h"
+#include "../libcli/smb/smb_constants.h"
+
+static const struct tstream_context_ops tstream_npa_ops;
+
+struct tstream_npa {
+ struct tstream_context *unix_stream;
+
+ uint16_t file_type;
+
+ struct iovec pending;
+};
+
+struct tstream_npa_connect_state {
+ struct {
+ struct tevent_context *ev;
+ } caller;
+
+ const char *unix_path;
+ struct tsocket_address *unix_laddr;
+ struct tsocket_address *unix_raddr;
+ struct tstream_context *unix_stream;
+
+ struct named_pipe_auth_req auth_req;
+ DATA_BLOB auth_req_blob;
+ struct iovec auth_req_iov;
+
+ struct named_pipe_auth_rep auth_rep;
+};
+
+static void tstream_npa_connect_unix_done(struct tevent_req *subreq);
+
+struct tevent_req *tstream_npa_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *directory,
+ const char *npipe,
+ enum dcerpc_transport_t transport,
+ const struct tsocket_address *remote_client_addr,
+ const char *remote_client_name_in,
+ const struct tsocket_address *local_server_addr,
+ const char *local_server_name_in,
+ const struct auth_session_info_transport *session_info)
+{
+ struct tevent_req *req;
+ struct tstream_npa_connect_state *state;
+ struct tevent_req *subreq;
+ int ret;
+ enum ndr_err_code ndr_err;
+ char *lower_case_npipe;
+ struct named_pipe_auth_req_info8 *info8;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_npa_connect_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->caller.ev = ev;
+
+ lower_case_npipe = strlower_talloc(state, npipe);
+ if (tevent_req_nomem(lower_case_npipe, req)) {
+ goto post;
+ }
+
+ state->unix_path = talloc_asprintf(state, "%s/%s",
+ directory,
+ lower_case_npipe);
+ talloc_free(lower_case_npipe);
+ if (tevent_req_nomem(state->unix_path, req)) {
+ goto post;
+ }
+
+ ret = tsocket_address_unix_from_path(state,
+ "",
+ &state->unix_laddr);
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ goto post;
+ }
+
+ ret = tsocket_address_unix_from_path(state,
+ state->unix_path,
+ &state->unix_raddr);
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ goto post;
+ }
+
+ ZERO_STRUCT(state->auth_req);
+
+ if (!local_server_addr) {
+ tevent_req_error(req, EINVAL);
+ goto post;
+ }
+
+ state->auth_req.level = 8;
+ info8 = &state->auth_req.info.info8;
+
+ info8->transport = transport;
+ SMB_ASSERT(info8->transport == transport); /* Assert no overflow */
+
+ info8->remote_client_name = remote_client_name_in;
+ info8->remote_client_addr =
+ tsocket_address_inet_addr_string(remote_client_addr, state);
+ if (!info8->remote_client_addr) {
+ /* errno might be EINVAL */
+ tevent_req_error(req, errno);
+ goto post;
+ }
+ info8->remote_client_port =
+ tsocket_address_inet_port(remote_client_addr);
+ if (!info8->remote_client_name) {
+ info8->remote_client_name = info8->remote_client_addr;
+ }
+
+ info8->local_server_name = local_server_name_in;
+ info8->local_server_addr =
+ tsocket_address_inet_addr_string(local_server_addr, state);
+ if (!info8->local_server_addr) {
+ /* errno might be EINVAL */
+ tevent_req_error(req, errno);
+ goto post;
+ }
+ info8->local_server_port =
+ tsocket_address_inet_port(local_server_addr);
+ if (!info8->local_server_name) {
+ info8->local_server_name = info8->local_server_addr;
+ }
+
+ info8->session_info =
+ discard_const_p(struct auth_session_info_transport,
+ session_info);
+
+ if (DEBUGLVL(10)) {
+ NDR_PRINT_DEBUG(named_pipe_auth_req, &state->auth_req);
+ }
+
+ ndr_err = ndr_push_struct_blob(&state->auth_req_blob,
+ state, &state->auth_req,
+ (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ tevent_req_error(req, EINVAL);
+ goto post;
+ }
+
+ state->auth_req_iov.iov_base = (char *) state->auth_req_blob.data;
+ state->auth_req_iov.iov_len = state->auth_req_blob.length;
+
+ subreq = tstream_unix_connect_send(state,
+ state->caller.ev,
+ state->unix_laddr,
+ state->unix_raddr);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq, tstream_npa_connect_unix_done, req);
+
+ return req;
+
+post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tstream_npa_connect_writev_done(struct tevent_req *subreq);
+
+static void tstream_npa_connect_unix_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_npa_connect_state *state =
+ tevent_req_data(req,
+ struct tstream_npa_connect_state);
+ int ret;
+ int sys_errno;
+
+ ret = tstream_unix_connect_recv(subreq, &sys_errno,
+ state, &state->unix_stream);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+
+ subreq = tstream_writev_send(state,
+ state->caller.ev,
+ state->unix_stream,
+ &state->auth_req_iov, 1);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, tstream_npa_connect_writev_done, req);
+}
+
+static void tstream_npa_connect_readv_done(struct tevent_req *subreq);
+
+static void tstream_npa_connect_writev_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_npa_connect_state *state =
+ tevent_req_data(req,
+ struct tstream_npa_connect_state);
+ int ret;
+ int sys_errno;
+
+ ret = tstream_writev_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+
+ subreq = tstream_u32_read_send(
+ state, state->caller.ev, 0x00FFFFFF, state->unix_stream);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, tstream_npa_connect_readv_done, req);
+}
+
+static void tstream_npa_connect_readv_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_npa_connect_state *state =
+ tevent_req_data(req,
+ struct tstream_npa_connect_state);
+ DATA_BLOB in;
+ int err;
+ enum ndr_err_code ndr_err;
+
+ err = tstream_u32_read_recv(subreq, state, &in.data, &in.length);
+ TALLOC_FREE(subreq);
+ if (tevent_req_error(req, err)) {
+ return;
+ }
+
+ DBG_DEBUG("name_pipe_auth_rep(client)[%zu]\n", in.length);
+ dump_data(11, in.data, in.length);
+
+ ndr_err = ndr_pull_struct_blob_all(
+ &in,
+ state,
+ &state->auth_rep,
+ (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_rep);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("ndr_pull_named_pipe_auth_rep failed: %s\n",
+ ndr_map_error2string(ndr_err)));
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ if (DEBUGLVL(10)) {
+ NDR_PRINT_DEBUG(named_pipe_auth_rep, &state->auth_rep);
+ }
+
+ if (state->auth_rep.length < 16) {
+ DEBUG(0, ("req invalid length: %u < 16\n",
+ state->auth_rep.length));
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ if (strcmp(NAMED_PIPE_AUTH_MAGIC, state->auth_rep.magic) != 0) {
+ DEBUG(0, ("req invalid magic: %s != %s\n",
+ state->auth_rep.magic, NAMED_PIPE_AUTH_MAGIC));
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ if (!NT_STATUS_IS_OK(state->auth_rep.status)) {
+ DEBUG(0, ("req failed: %s\n",
+ nt_errstr(state->auth_rep.status)));
+ tevent_req_error(req, EACCES);
+ return;
+ }
+
+ if (state->auth_rep.level != state->auth_req.level) {
+ DEBUG(0, ("req invalid level: %u != %u\n",
+ state->auth_rep.level, state->auth_req.level));
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+int _tstream_npa_connect_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **_stream,
+ uint16_t *_file_type,
+ uint16_t *_device_state,
+ uint64_t *_allocation_size,
+ const char *location)
+{
+ struct tstream_npa_connect_state *state =
+ tevent_req_data(req,
+ struct tstream_npa_connect_state);
+ struct tstream_context *stream;
+ struct tstream_npa *npas;
+ uint16_t device_state = 0;
+ uint64_t allocation_size = 0;
+
+ if (tevent_req_is_unix_error(req, perrno)) {
+ tevent_req_received(req);
+ return -1;
+ }
+
+ stream = tstream_context_create(mem_ctx,
+ &tstream_npa_ops,
+ &npas,
+ struct tstream_npa,
+ location);
+ if (!stream) {
+ *perrno = ENOMEM;
+ tevent_req_received(req);
+ return -1;
+ }
+ ZERO_STRUCTP(npas);
+
+ npas->unix_stream = talloc_move(stream, &state->unix_stream);
+ switch (state->auth_rep.level) {
+ case 8:
+ npas->file_type = state->auth_rep.info.info8.file_type;
+ device_state = state->auth_rep.info.info8.device_state;
+ allocation_size = state->auth_rep.info.info8.allocation_size;
+ break;
+ }
+
+ *_stream = stream;
+ *_file_type = npas->file_type;
+ *_device_state = device_state;
+ *_allocation_size = allocation_size;
+ tevent_req_received(req);
+ return 0;
+}
+
+static ssize_t tstream_npa_pending_bytes(struct tstream_context *stream)
+{
+ struct tstream_npa *npas = tstream_context_data(stream,
+ struct tstream_npa);
+ ssize_t ret;
+
+ if (!npas->unix_stream) {
+ errno = ENOTCONN;
+ return -1;
+ }
+
+ switch (npas->file_type) {
+ case FILE_TYPE_BYTE_MODE_PIPE:
+ ret = tstream_pending_bytes(npas->unix_stream);
+ break;
+
+ case FILE_TYPE_MESSAGE_MODE_PIPE:
+ ret = npas->pending.iov_len;
+ break;
+
+ default:
+ ret = -1;
+ }
+
+ return ret;
+}
+
+struct tstream_npa_readv_state {
+ struct tstream_context *stream;
+
+ struct iovec *vector;
+ size_t count;
+
+ /* the header for message mode */
+ uint8_t hdr[2];
+ bool wait_for_hdr;
+
+ int ret;
+};
+
+static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq);
+static int tstream_npa_readv_next_vector(struct tstream_context *stream,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **_vector,
+ size_t *_count);
+static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq);
+
+static struct tevent_req *tstream_npa_readv_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ struct iovec *vector,
+ size_t count)
+{
+ struct tevent_req *req;
+ struct tstream_npa_readv_state *state;
+ struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
+ struct tevent_req *subreq;
+ off_t ofs;
+ size_t left;
+ uint8_t *pbase;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_npa_readv_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->stream = stream;
+ state->ret = 0;
+
+ if (!npas->unix_stream) {
+ tevent_req_error(req, ENOTCONN);
+ goto post;
+ }
+
+ switch (npas->file_type) {
+ case FILE_TYPE_BYTE_MODE_PIPE:
+ state->vector = vector;
+ state->count = count;
+
+ subreq = tstream_readv_send(state,
+ ev,
+ npas->unix_stream,
+ state->vector,
+ state->count);
+ if (tevent_req_nomem(subreq,req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq,
+ tstream_npa_readv_byte_mode_handler,
+ req);
+
+ return req;
+
+ case FILE_TYPE_MESSAGE_MODE_PIPE:
+ /*
+ * we make a copy of the vector and prepend a header
+ * with the length
+ */
+ state->vector = talloc_array(state, struct iovec, count);
+ if (tevent_req_nomem(state->vector, req)) {
+ goto post;
+ }
+ memcpy(state->vector, vector, sizeof(struct iovec)*count);
+ state->count = count;
+
+ /*
+ * copy the pending buffer first
+ */
+ ofs = 0;
+ left = npas->pending.iov_len;
+ pbase = (uint8_t *)npas->pending.iov_base;
+
+ while (left > 0 && state->count > 0) {
+ uint8_t *base;
+ base = (uint8_t *)state->vector[0].iov_base;
+ if (left < state->vector[0].iov_len) {
+ memcpy(base, pbase + ofs, left);
+
+ base += left;
+ state->vector[0].iov_base = (char *) base;
+ state->vector[0].iov_len -= left;
+
+ ofs += left;
+ left = 0;
+ TALLOC_FREE(pbase);
+ ZERO_STRUCT(npas->pending);
+ break;
+ }
+ memcpy(base, pbase + ofs, state->vector[0].iov_len);
+
+ ofs += state->vector[0].iov_len;
+ left -= state->vector[0].iov_len;
+ state->vector += 1;
+ state->count -= 1;
+
+ if (left == 0) {
+ TALLOC_FREE(pbase);
+ ZERO_STRUCT(npas->pending);
+ break;
+ }
+ }
+
+ if (left > 0) {
+ memmove(pbase, pbase + ofs, left);
+ npas->pending.iov_base = (char *) pbase;
+ npas->pending.iov_len = left;
+ /*
+ * this cannot fail and even if it
+ * fails we can handle it
+ */
+ pbase = talloc_realloc(npas, pbase, uint8_t, left);
+ if (pbase) {
+ npas->pending.iov_base = (char *) pbase;
+ }
+ pbase = NULL;
+ }
+
+ state->ret += ofs;
+
+ if (state->count == 0) {
+ tevent_req_done(req);
+ goto post;
+ }
+
+ ZERO_STRUCT(state->hdr);
+ state->wait_for_hdr = false;
+
+ subreq = tstream_readv_pdu_send(state,
+ ev,
+ npas->unix_stream,
+ tstream_npa_readv_next_vector,
+ state);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq,
+ tstream_npa_readv_msg_mode_handler,
+ req);
+
+ return req;
+ }
+
+ /* this can't happen */
+ tevent_req_error(req, EINVAL);
+ goto post;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_npa_readv_state *state = tevent_req_data(req,
+ struct tstream_npa_readv_state);
+ int ret;
+ int sys_errno;
+
+ ret = tstream_readv_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+
+ state->ret = ret;
+
+ tevent_req_done(req);
+}
+
+static int tstream_npa_readv_next_vector(struct tstream_context *unix_stream,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **_vector,
+ size_t *_count)
+{
+ struct tstream_npa_readv_state *state = talloc_get_type_abort(private_data,
+ struct tstream_npa_readv_state);
+ struct tstream_npa *npas = tstream_context_data(state->stream,
+ struct tstream_npa);
+ struct iovec *vector;
+ size_t count;
+ uint16_t msg_len;
+ size_t left;
+
+ if (state->count == 0) {
+ *_vector = NULL;
+ *_count = 0;
+ return 0;
+ }
+
+ if (!state->wait_for_hdr) {
+ /* we need to get a message header */
+ vector = talloc_array(mem_ctx, struct iovec, 1);
+ if (!vector) {
+ return -1;
+ }
+ ZERO_STRUCT(state->hdr);
+ vector[0].iov_base = (char *) state->hdr;
+ vector[0].iov_len = sizeof(state->hdr);
+
+ count = 1;
+
+ state->wait_for_hdr = true;
+
+ *_vector = vector;
+ *_count = count;
+ return 0;
+ }
+
+ /* and now fill the callers buffers and maybe the pending buffer */
+ state->wait_for_hdr = false;
+
+ msg_len = SVAL(state->hdr, 0);
+
+ if (msg_len == 0) {
+ errno = EIO;
+ return -1;
+ }
+
+ state->wait_for_hdr = false;
+
+ /* +1 because we may need to fill the pending buffer */
+ vector = talloc_array(mem_ctx, struct iovec, state->count + 1);
+ if (!vector) {
+ return -1;
+ }
+
+ count = 0;
+ left = msg_len;
+ while (left > 0 && state->count > 0) {
+ if (left < state->vector[0].iov_len) {
+ uint8_t *base;
+ base = (uint8_t *)state->vector[0].iov_base;
+ vector[count].iov_base = (char *) base;
+ vector[count].iov_len = left;
+ count++;
+ base += left;
+ state->vector[0].iov_base = (char *) base;
+ state->vector[0].iov_len -= left;
+ break;
+ }
+ vector[count] = state->vector[0];
+ count++;
+ left -= state->vector[0].iov_len;
+ state->vector += 1;
+ state->count -= 1;
+ }
+
+ if (left > 0) {
+ /*
+ * if the message is longer than the buffers the caller
+ * requested, we need to consume the rest of the message
+ * into the pending buffer, where the next readv can
+ * be served from.
+ */
+ npas->pending.iov_base = talloc_array(npas, char, left);
+ if (!npas->pending.iov_base) {
+ return -1;
+ }
+ npas->pending.iov_len = left;
+
+ vector[count] = npas->pending;
+ count++;
+ }
+
+ state->ret += (msg_len - left);
+
+ *_vector = vector;
+ *_count = count;
+ return 0;
+}
+
+static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ int ret;
+ int sys_errno;
+
+ ret = tstream_readv_pdu_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+
+ /*
+ * we do not set state->ret here as ret includes the header size.
+ * we set it in tstream_npa_readv_pdu_next_vector()
+ */
+
+ tevent_req_done(req);
+}
+
+static int tstream_npa_readv_recv(struct tevent_req *req,
+ int *perrno)
+{
+ struct tstream_npa_readv_state *state = tevent_req_data(req,
+ struct tstream_npa_readv_state);
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ ret = state->ret;
+ }
+
+ tevent_req_received(req);
+ return ret;
+}
+
+struct tstream_npa_writev_state {
+ const struct iovec *vector;
+ size_t count;
+
+ /* the header for message mode */
+ bool hdr_used;
+ uint8_t hdr[2];
+
+ int ret;
+};
+
+static void tstream_npa_writev_handler(struct tevent_req *subreq);
+
+static struct tevent_req *tstream_npa_writev_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ const struct iovec *vector,
+ size_t count)
+{
+ struct tevent_req *req;
+ struct tstream_npa_writev_state *state;
+ struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
+ struct tevent_req *subreq;
+ size_t msg_len;
+ size_t i;
+ struct iovec *new_vector;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_npa_writev_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->ret = 0;
+
+ if (!npas->unix_stream) {
+ tevent_req_error(req, ENOTCONN);
+ goto post;
+ }
+
+ switch (npas->file_type) {
+ case FILE_TYPE_BYTE_MODE_PIPE:
+ state->hdr_used = false;
+ state->vector = vector;
+ state->count = count;
+ break;
+
+ case FILE_TYPE_MESSAGE_MODE_PIPE:
+ /*
+ * we make a copy of the vector and prepend a header
+ * with the length
+ */
+ new_vector = talloc_array(state, struct iovec, count + 1);
+ if (tevent_req_nomem(new_vector, req)) {
+ goto post;
+ }
+ new_vector[0].iov_base = (char *) state->hdr;
+ new_vector[0].iov_len = sizeof(state->hdr);
+ memcpy(new_vector + 1, vector, sizeof(struct iovec)*count);
+
+ state->hdr_used = true;
+ state->vector = new_vector;
+ state->count = count + 1;
+
+ msg_len = 0;
+ for (i=0; i < count; i++) {
+ /*
+ * overflow check already done in tstream_writev_send
+ */
+ msg_len += vector[i].iov_len;
+ }
+
+ if (msg_len > UINT16_MAX) {
+ tevent_req_error(req, EMSGSIZE);
+ goto post;
+ }
+
+ SSVAL(state->hdr, 0, msg_len);
+ break;
+ }
+
+ subreq = tstream_writev_send(state,
+ ev,
+ npas->unix_stream,
+ state->vector,
+ state->count);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq, tstream_npa_writev_handler, req);
+
+ return req;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tstream_npa_writev_handler(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_npa_writev_state *state = tevent_req_data(req,
+ struct tstream_npa_writev_state);
+ int ret;
+ int sys_errno;
+
+ ret = tstream_writev_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+
+ /*
+ * in message mode we need to hide the length
+ * of the hdr from the caller
+ */
+ if (state->hdr_used) {
+ ret -= sizeof(state->hdr);
+ }
+
+ state->ret = ret;
+
+ tevent_req_done(req);
+}
+
+static int tstream_npa_writev_recv(struct tevent_req *req,
+ int *perrno)
+{
+ struct tstream_npa_writev_state *state = tevent_req_data(req,
+ struct tstream_npa_writev_state);
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ ret = state->ret;
+ }
+
+ tevent_req_received(req);
+ return ret;
+}
+
+struct tstream_npa_disconnect_state {
+ struct tstream_context *stream;
+};
+
+static void tstream_npa_disconnect_handler(struct tevent_req *subreq);
+
+static struct tevent_req *tstream_npa_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream)
+{
+ struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
+ struct tevent_req *req;
+ struct tstream_npa_disconnect_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_npa_disconnect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->stream = stream;
+
+ if (!npas->unix_stream) {
+ tevent_req_error(req, ENOTCONN);
+ goto post;
+ }
+
+ subreq = tstream_disconnect_send(state,
+ ev,
+ npas->unix_stream);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq, tstream_npa_disconnect_handler, req);
+
+ return req;
+
+post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tstream_npa_disconnect_handler(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_npa_disconnect_state *state = tevent_req_data(req,
+ struct tstream_npa_disconnect_state);
+ struct tstream_context *stream = state->stream;
+ struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
+ int ret;
+ int sys_errno;
+
+ ret = tstream_disconnect_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+
+ TALLOC_FREE(npas->unix_stream);
+
+ tevent_req_done(req);
+}
+
+static int tstream_npa_disconnect_recv(struct tevent_req *req,
+ int *perrno)
+{
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+
+ tevent_req_received(req);
+ return ret;
+}
+
+static const struct tstream_context_ops tstream_npa_ops = {
+ .name = "npa",
+
+ .pending_bytes = tstream_npa_pending_bytes,
+
+ .readv_send = tstream_npa_readv_send,
+ .readv_recv = tstream_npa_readv_recv,
+
+ .writev_send = tstream_npa_writev_send,
+ .writev_recv = tstream_npa_writev_recv,
+
+ .disconnect_send = tstream_npa_disconnect_send,
+ .disconnect_recv = tstream_npa_disconnect_recv,
+};
+
+int _tstream_npa_existing_stream(TALLOC_CTX *mem_ctx,
+ struct tstream_context **transport,
+ uint16_t file_type,
+ struct tstream_context **_stream,
+ const char *location)
+{
+ struct tstream_context *stream;
+ struct tstream_npa *npas;
+
+ switch (file_type) {
+ case FILE_TYPE_BYTE_MODE_PIPE:
+ break;
+ case FILE_TYPE_MESSAGE_MODE_PIPE:
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ stream = tstream_context_create(mem_ctx,
+ &tstream_npa_ops,
+ &npas,
+ struct tstream_npa,
+ location);
+ if (!stream) {
+ return -1;
+ }
+
+ *npas = (struct tstream_npa) {
+ .file_type = file_type,
+ .unix_stream = talloc_move(npas, transport),
+ };
+
+ *_stream = stream;
+ return 0;
+}
+
+int _tstream_npa_existing_socket(TALLOC_CTX *mem_ctx,
+ int fd,
+ uint16_t file_type,
+ struct tstream_context **_stream,
+ const char *location)
+{
+ struct tstream_context *transport = NULL;
+ int ret;
+
+ ret = _tstream_bsd_existing_socket(
+ mem_ctx, fd, &transport, location);
+ if (ret == -1) {
+ return -1;
+ }
+ /* as server we want to fail early */
+ tstream_bsd_fail_readv_first_error(transport, true);
+ return _tstream_npa_existing_stream(
+ mem_ctx, &transport, file_type, _stream, location);
+}
+
+struct tstream_npa_accept_state {
+ struct tevent_context *ev;
+ struct tstream_context *plain;
+ uint16_t file_type;
+ uint16_t device_state;
+ uint64_t alloc_size;
+
+ struct named_pipe_auth_req *pipe_request;
+
+ DATA_BLOB npa_blob;
+ struct iovec out_iov;
+
+ /* results */
+ NTSTATUS accept_status;
+ struct tsocket_address *remote_client_addr;
+ struct tsocket_address *local_server_addr;
+};
+
+static void tstream_npa_accept_existing_reply(struct tevent_req *subreq);
+static void tstream_npa_accept_existing_done(struct tevent_req *subreq);
+
+struct tevent_req *tstream_npa_accept_existing_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *plain,
+ uint16_t file_type,
+ uint16_t device_state,
+ uint64_t allocation_size)
+{
+ struct tstream_npa_accept_state *state;
+ struct tevent_req *req, *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_npa_accept_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ switch (file_type) {
+ case FILE_TYPE_BYTE_MODE_PIPE:
+ break;
+ case FILE_TYPE_MESSAGE_MODE_PIPE:
+ break;
+ default:
+ tevent_req_error(req, EINVAL);
+ goto post;
+ }
+
+ state->ev = ev;
+ state->plain = plain;
+ state->file_type = file_type;
+ state->device_state = device_state;
+ state->alloc_size = allocation_size;
+
+ subreq = tstream_u32_read_send(state, ev, 0x00FFFFFF, plain);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+
+ tevent_req_set_callback(subreq,
+ tstream_npa_accept_existing_reply, req);
+
+ return req;
+
+post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tstream_npa_accept_existing_reply(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct tstream_npa_accept_state *state =
+ tevent_req_data(req, struct tstream_npa_accept_state);
+ struct named_pipe_auth_req *pipe_request;
+ struct named_pipe_auth_rep pipe_reply;
+ struct named_pipe_auth_req_info8 i8;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB in, out;
+ int err;
+ int ret;
+
+ err = tstream_u32_read_recv(subreq, state, &in.data, &in.length);
+ if (err != 0) {
+ tevent_req_error(req, err);
+ return;
+ }
+ if (in.length < 8) {
+ tevent_req_error(req, EMSGSIZE);
+ return;
+ }
+
+ if (memcmp(&in.data[4], NAMED_PIPE_AUTH_MAGIC, 4) != 0) {
+ DBG_ERR("Wrong protocol\n");
+#if defined(EPROTONOSUPPORT)
+ err = EPROTONOSUPPORT;
+#elif defined(EPROTO)
+ err = EPROTO;
+#else
+ err = EINVAL;
+#endif
+ tevent_req_error(req, err);
+ return;
+ }
+
+ DBG_DEBUG("Received packet of length %zu\n", in.length);
+ dump_data(11, in.data, in.length);
+
+ ZERO_STRUCT(pipe_reply);
+ pipe_reply.level = 0;
+ pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
+ /*
+ * TODO: check it's a root (uid == 0) pipe
+ */
+
+ pipe_request = talloc(state, struct named_pipe_auth_req);
+ if (!pipe_request) {
+ DEBUG(0, ("Out of memory!\n"));
+ goto reply;
+ }
+ state->pipe_request = pipe_request;
+
+ /* parse the passed credentials */
+ ndr_err = ndr_pull_struct_blob_all(
+ &in,
+ pipe_request,
+ pipe_request,
+ (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_req);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ pipe_reply.status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(2, ("Could not unmarshall named_pipe_auth_req: %s\n",
+ nt_errstr(pipe_reply.status)));
+ goto reply;
+ }
+
+ if (DEBUGLVL(10)) {
+ NDR_PRINT_DEBUG(named_pipe_auth_req, pipe_request);
+ }
+
+ ZERO_STRUCT(i8);
+
+ if (pipe_request->level != 8) {
+ DEBUG(0, ("Unknown level %u\n", pipe_request->level));
+ pipe_reply.level = 0;
+ pipe_reply.status = NT_STATUS_INVALID_LEVEL;
+ goto reply;
+ }
+
+ pipe_reply.level = 8;
+ pipe_reply.status = NT_STATUS_OK;
+ pipe_reply.info.info8.file_type = state->file_type;
+ pipe_reply.info.info8.device_state = state->device_state;
+ pipe_reply.info.info8.allocation_size = state->alloc_size;
+
+ i8 = pipe_request->info.info8;
+ if (i8.local_server_addr == NULL) {
+ pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
+ DEBUG(2, ("Missing local server address\n"));
+ goto reply;
+ }
+ if (i8.remote_client_addr == NULL) {
+ pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
+ DEBUG(2, ("Missing remote client address\n"));
+ goto reply;
+ }
+
+ ret = tsocket_address_inet_from_strings(state,
+ "ip",
+ i8.local_server_addr,
+ i8.local_server_port,
+ &state->local_server_addr);
+ if (ret != 0) {
+ DEBUG(2,
+ ("Invalid local server address[%s:%u] - %s\n",
+ i8.local_server_addr,
+ i8.local_server_port,
+ strerror(errno)));
+ pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
+ goto reply;
+ }
+
+ ret = tsocket_address_inet_from_strings(state,
+ "ip",
+ i8.remote_client_addr,
+ i8.remote_client_port,
+ &state->remote_client_addr);
+ if (ret != 0) {
+ DEBUG(2,
+ ("Invalid remote client address[%s:%u] - %s\n",
+ i8.remote_client_addr,
+ i8.remote_client_port,
+ strerror(errno)));
+ pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
+ goto reply;
+ }
+
+reply:
+ /* create the output */
+ ndr_err = ndr_push_struct_blob(&out, state, &pipe_reply,
+ (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_rep);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(2, ("Error encoding structure: %s\n",
+ ndr_map_error2string(ndr_err)));
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ DEBUG(10, ("named_pipe_auth reply[%u]\n", (unsigned)out.length));
+ dump_data(11, out.data, out.length);
+
+ if (DEBUGLVL(10)) {
+ NDR_PRINT_DEBUG(named_pipe_auth_rep, &pipe_reply);
+ }
+
+ state->accept_status = pipe_reply.status;
+
+ state->out_iov.iov_base = (char *) out.data;
+ state->out_iov.iov_len = out.length;
+
+ subreq = tstream_writev_send(state, state->ev,
+ state->plain,
+ &state->out_iov, 1);
+ if (tevent_req_nomem(subreq, req)) {
+ DEBUG(0, ("no memory for tstream_writev_send\n"));
+ return;
+ }
+
+ tevent_req_set_callback(subreq, tstream_npa_accept_existing_done, req);
+}
+
+static void tstream_npa_accept_existing_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ int sys_errno;
+ int ret;
+
+ ret = tstream_writev_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static struct named_pipe_auth_req_info8 *
+copy_npa_info8(TALLOC_CTX *mem_ctx,
+ const struct named_pipe_auth_req_info8 *src)
+{
+ struct named_pipe_auth_req_info8 *dst = NULL;
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+
+ dst = talloc_zero(mem_ctx, struct named_pipe_auth_req_info8);
+ if (dst == NULL) {
+ return NULL;
+ }
+
+ ndr_err = ndr_push_struct_blob(
+ &blob,
+ dst,
+ src,
+ (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req_info8);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DBG_WARNING("ndr_push_named_pipe_auth_req_info8 failed: %s\n",
+ ndr_errstr(ndr_err));
+ TALLOC_FREE(dst);
+ return NULL;
+ }
+
+ ndr_err = ndr_pull_struct_blob_all(
+ &blob,
+ dst,
+ dst,
+ (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_req_info8);
+ TALLOC_FREE(blob.data);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DBG_WARNING("ndr_push_named_pipe_auth_req_info8 failed: %s\n",
+ ndr_errstr(ndr_err));
+ TALLOC_FREE(dst);
+ return NULL;
+ }
+
+ return dst;
+}
+
+int _tstream_npa_accept_existing_recv(
+ struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **stream,
+ struct named_pipe_auth_req_info8 **info8,
+ enum dcerpc_transport_t *transport,
+ struct tsocket_address **remote_client_addr,
+ char **_remote_client_name,
+ struct tsocket_address **local_server_addr,
+ char **local_server_name,
+ struct auth_session_info_transport **session_info,
+ const char *location)
+{
+ struct tstream_npa_accept_state *state =
+ tevent_req_data(req, struct tstream_npa_accept_state);
+ struct named_pipe_auth_req_info8 *i8 =
+ &state->pipe_request->info.info8;
+ struct tstream_npa *npas;
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret != 0) {
+ DEBUG(2, ("Failed to accept named pipe connection: %s\n",
+ strerror(*perrno)));
+ tevent_req_received(req);
+ return -1;
+ }
+
+ if (!NT_STATUS_IS_OK(state->accept_status)) {
+#if defined(EPROTONOSUPPORT)
+ *perrno = EPROTONOSUPPORT;
+#elif defined(EPROTO)
+ *perrno = EPROTO;
+#else
+ *perrno = EINVAL;
+#endif
+ DEBUG(2, ("Failed to accept named pipe connection: %s => %s\n",
+ nt_errstr(state->accept_status),
+ strerror(*perrno)));
+ tevent_req_received(req);
+ return -1;
+ }
+
+ *stream = tstream_context_create(mem_ctx,
+ &tstream_npa_ops,
+ &npas,
+ struct tstream_npa,
+ location);
+ if (!*stream) {
+ *perrno = ENOMEM;
+ tevent_req_received(req);
+ return -1;
+ }
+ ZERO_STRUCTP(npas);
+ npas->unix_stream = state->plain;
+ npas->file_type = state->file_type;
+
+ if (info8 != NULL) {
+ /*
+ * Make a full copy of "info8" because further down we
+ * talloc_move() away substructures from
+ * state->pipe_request.
+ */
+ struct named_pipe_auth_req_info8 *dst =
+ copy_npa_info8(mem_ctx, i8);
+ if (dst == NULL) {
+ *perrno = ENOMEM;
+ tevent_req_received(req);
+ return -1;
+ }
+ *info8 = dst;
+ }
+
+ if (transport != NULL) {
+ *transport = i8->transport;
+ }
+ if (remote_client_addr != NULL) {
+ *remote_client_addr = talloc_move(
+ mem_ctx, &state->remote_client_addr);
+ }
+ if (_remote_client_name != NULL) {
+ *_remote_client_name = discard_const_p(
+ char,
+ talloc_move(mem_ctx, &i8->remote_client_name));
+ }
+ if (local_server_addr != NULL) {
+ *local_server_addr = talloc_move(
+ mem_ctx, &state->local_server_addr);
+ }
+ if (local_server_name != NULL) {
+ *local_server_name = discard_const_p(
+ char,
+ talloc_move(mem_ctx, &i8->local_server_name));
+ }
+ if (session_info != NULL) {
+ *session_info = talloc_move(mem_ctx, &i8->session_info);
+ }
+
+ tevent_req_received(req);
+ return 0;
+}
diff --git a/libcli/named_pipe_auth/npa_tstream.h b/libcli/named_pipe_auth/npa_tstream.h
new file mode 100644
index 0000000..aa60fe7
--- /dev/null
+++ b/libcli/named_pipe_auth/npa_tstream.h
@@ -0,0 +1,145 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 2009
+
+ 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/>.
+*/
+
+#ifndef NPA_TSTREAM_H
+#define NPA_TSTREAM_H
+
+#include <replace.h>
+#include "librpc/rpc/rpc_common.h"
+
+struct tevent_req;
+struct tevent_context;
+struct auth_session_info_transport;
+struct tsocket_address;
+struct named_pipe_auth_req_info8;
+
+struct tevent_req *tstream_npa_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *directory,
+ const char *npipe,
+ enum dcerpc_transport_t transport,
+ const struct tsocket_address *remote_client_addr,
+ const char *remote_client_name_in,
+ const struct tsocket_address *local_server_addr,
+ const char *local_server_name_in,
+ const struct auth_session_info_transport *session_info);
+int _tstream_npa_connect_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **stream,
+ uint16_t *file_type,
+ uint16_t *device_state,
+ uint64_t *allocation_size,
+ const char *location);
+#define tstream_npa_connect_recv(req, perrno, mem_ctx, stream, f, d, a) \
+ _tstream_npa_connect_recv(req, perrno, mem_ctx, stream, f, d, a, \
+ __location__)
+
+int _tstream_npa_existing_stream(TALLOC_CTX *mem_ctx,
+ struct tstream_context **transport,
+ uint16_t file_type,
+ struct tstream_context **_stream,
+ const char *location);
+#define tstream_npa_existing_stream(mem_ctx, transport, ft, stream) \
+ _tstream_npa_existing_stream(mem_ctx, transport, ft, stream, \
+ __location__)
+
+int _tstream_npa_existing_socket(TALLOC_CTX *mem_ctx,
+ int fd,
+ uint16_t file_type,
+ struct tstream_context **_stream,
+ const char *location);
+#define tstream_npa_existing_socket(mem_ctx, fd, ft, stream) \
+ _tstream_npa_existing_socket(mem_ctx, fd, ft, stream, \
+ __location__)
+
+
+/**
+ * @brief Accepts a connection for authenticated named pipes
+ *
+ * @param[in] mem_ctx The memory context for the operation
+ * @param[in] ev The tevent_context for the operation
+ * @param[in] plain The plain tstream_context of the bsd unix
+ * domain socket.
+ * This must be valid for the whole life of the
+ * resulting npa tstream_context!
+ * @param[in] file_type The file_type, message mode or byte mode
+ * @param[in] device_state The reported device state
+ * @param[in] allocation_size The reported allocation size
+ *
+ * @return the tevent_req handle
+ */
+struct tevent_req *tstream_npa_accept_existing_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *plain,
+ uint16_t file_type,
+ uint16_t device_state,
+ uint64_t allocation_size);
+
+/**
+ * @brief The receive end of the previous async function
+ *
+ * @param[in] req The tevent_req handle
+ * @param[out] perrno Pointer to store the errno in case of error
+ * @param[in] mem_ctx The memory context for the results
+ * @param[out] stream The resulting stream
+ * @param[out] client The resulting client address
+ * @param[out] client_name The resulting client name
+ * @param[out] server The resulting server address
+ * @param[out] server_name The resulting server name
+ * @param[out] info3 The info3 auth for the connecting user.
+ * @param[out] session_key The resulting session key
+ * @param[out] delegated_creds Delegated credentials
+ *
+ * @return 0 if successful, -1 on failure with *perror filled.
+ */
+int _tstream_npa_accept_existing_recv(
+ struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **stream,
+ struct named_pipe_auth_req_info8 **info8,
+ enum dcerpc_transport_t *transport,
+ struct tsocket_address **remote_client_addr,
+ char **_remote_client_name,
+ struct tsocket_address **local_server_addr,
+ char **local_server_name,
+ struct auth_session_info_transport **session_info,
+ const char *location);
+#define tstream_npa_accept_existing_recv(req, perrno, \
+ mem_ctx, stream, \
+ info4, \
+ transport, \
+ remote_client_addr, \
+ remote_client_name, \
+ local_server_addr, \
+ local_server_name, \
+ session_info) \
+ _tstream_npa_accept_existing_recv(req, perrno, \
+ mem_ctx, stream, \
+ info4, \
+ transport, \
+ remote_client_addr, \
+ remote_client_name, \
+ local_server_addr, \
+ local_server_name, \
+ session_info, \
+ __location__)
+
+#endif /* NPA_TSTREAM_H */
diff --git a/libcli/named_pipe_auth/tstream_u32_read.c b/libcli/named_pipe_auth/tstream_u32_read.c
new file mode 100644
index 0000000..c8e95ef
--- /dev/null
+++ b/libcli/named_pipe_auth/tstream_u32_read.c
@@ -0,0 +1,159 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Volker Lendecke 2019
+ *
+ * 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 "replace.h"
+#include "system/filesys.h"
+#include "tstream_u32_read.h"
+#include "lib/util/byteorder.h"
+#include "lib/util/tevent_unix.h"
+
+struct tstream_u32_read_state {
+ size_t max_msglen;
+ size_t buflen;
+ uint8_t *buf;
+};
+
+static int tstream_u32_read_next_vector(struct tstream_context *stream,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **_vector,
+ size_t *_count);
+static void tstream_u32_read_done(struct tevent_req *subreq);
+
+struct tevent_req *tstream_u32_read_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ uint32_t max_msglen,
+ struct tstream_context *stream)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct tstream_u32_read_state *state = NULL;
+
+ req = tevent_req_create(
+ mem_ctx, &state, struct tstream_u32_read_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->max_msglen = max_msglen;
+
+ subreq = tstream_readv_pdu_send(
+ state,
+ ev,
+ stream,
+ tstream_u32_read_next_vector,
+ state);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, tstream_u32_read_done, req);
+ return req;
+}
+
+static int tstream_u32_read_next_vector(struct tstream_context *stream,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **_vector,
+ size_t *_count)
+{
+ struct tstream_u32_read_state *state = talloc_get_type_abort(
+ private_data, struct tstream_u32_read_state);
+ size_t buflen = talloc_get_size(state->buf);
+ struct iovec *vector;
+ uint32_t msg_len;
+ size_t ofs = 0;
+ size_t count;
+
+ if (buflen == 0) {
+ msg_len = 4;
+ state->buf = talloc_array(state, uint8_t, msg_len);
+ if (state->buf == NULL) {
+ return -1;
+ }
+ } else if (buflen == 4) {
+
+ ofs = 4;
+
+ msg_len = RIVAL(state->buf, 0);
+ if ((msg_len == 0) || (msg_len > state->max_msglen)) {
+ errno = EMSGSIZE;
+ return -1;
+ }
+ msg_len += ofs;
+ if (msg_len < ofs) {
+ errno = EMSGSIZE;
+ return -1;
+ }
+
+ state->buf = talloc_realloc(
+ state, state->buf, uint8_t, msg_len);
+ if (state->buf == NULL) {
+ return -1;
+ }
+ } else {
+ *_vector = NULL;
+ *_count = 0;
+ return 0;
+ }
+
+ vector = talloc(mem_ctx, struct iovec);
+ if (vector == NULL) {
+ return -1;
+ }
+ *vector = (struct iovec) {
+ .iov_base = state->buf + ofs, .iov_len = msg_len - ofs,
+ };
+ count = 1;
+
+ *_vector = vector;
+ *_count = count;
+ return 0;
+}
+
+static void tstream_u32_read_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ int ret, err;
+
+ ret = tstream_readv_pdu_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, err);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+int tstream_u32_read_recv(
+ struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **buf,
+ size_t *buflen)
+{
+ struct tstream_u32_read_state *state = tevent_req_data(
+ req, struct tstream_u32_read_state);
+ int err;
+
+ if (tevent_req_is_unix_error(req, &err)) {
+ return err;
+ }
+ *buflen = talloc_get_size(state->buf);
+ *buf = talloc_move(mem_ctx, &state->buf);
+ return 0;
+}
diff --git a/libcli/named_pipe_auth/tstream_u32_read.h b/libcli/named_pipe_auth/tstream_u32_read.h
new file mode 100644
index 0000000..1356ff0
--- /dev/null
+++ b/libcli/named_pipe_auth/tstream_u32_read.h
@@ -0,0 +1,37 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Volker Lendecke 2019
+ *
+ * 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/>.
+ */
+
+#ifndef TSTREAM_U32_READ_H
+#define TSTREAM_U32_READ_H
+
+#include "replace.h"
+#include "tsocket.h"
+
+struct tevent_req *tstream_u32_read_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ uint32_t max_msglen,
+ struct tstream_context *stream);
+int tstream_u32_read_recv(
+ struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **buf,
+ size_t *buflen);
+
+#endif
diff --git a/libcli/named_pipe_auth/wscript_build b/libcli/named_pipe_auth/wscript_build
new file mode 100644
index 0000000..4698699
--- /dev/null
+++ b/libcli/named_pipe_auth/wscript_build
@@ -0,0 +1,9 @@
+#!/usr/bin/env python
+
+
+bld.SAMBA_LIBRARY('npa_tstream',
+ source='npa_tstream.c tstream_u32_read.c',
+ private_library=True,
+ public_deps='NDR_NAMED_PIPE_AUTH tevent LIBTSOCKET'
+ )
+
diff --git a/libcli/nbt/libnbt.h b/libcli/nbt/libnbt.h
new file mode 100644
index 0000000..204484b
--- /dev/null
+++ b/libcli/nbt/libnbt.h
@@ -0,0 +1,377 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ a raw async NBT library
+
+ Copyright (C) Andrew Tridgell 2005
+
+ 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/>.
+*/
+
+#ifndef __LIBNBT_H__
+#define __LIBNBT_H__
+
+#include "librpc/gen_ndr/nbt.h"
+#include "librpc/ndr/libndr.h"
+
+/*
+ possible states for pending requests
+*/
+enum nbt_request_state {NBT_REQUEST_SEND,
+ NBT_REQUEST_WAIT,
+ NBT_REQUEST_DONE,
+ NBT_REQUEST_TIMEOUT,
+ NBT_REQUEST_ERROR};
+
+/*
+ a nbt name request
+*/
+struct nbt_name_request {
+ struct nbt_name_request *next, *prev;
+
+ enum nbt_request_state state;
+
+ NTSTATUS status;
+
+ /* the socket this was on */
+ struct nbt_name_socket *nbtsock;
+
+ /* where to send the request */
+ struct socket_address *dest;
+
+ /* timeout between retries */
+ int timeout;
+
+ /* how many retries to send on timeout */
+ int num_retries;
+
+ /* whether we have received a WACK */
+ bool received_wack;
+
+ /* the timeout event */
+ struct tevent_timer *te;
+
+ /* the name transaction id */
+ uint16_t name_trn_id;
+
+ /* is it a reply? */
+ bool is_reply;
+
+ /* the encoded request */
+ DATA_BLOB encoded;
+
+ /* shall we allow multiple replies? */
+ bool allow_multiple_replies;
+
+ unsigned int num_replies;
+ struct nbt_name_reply {
+ struct nbt_name_packet *packet;
+ struct socket_address *dest;
+ } *replies;
+
+ /* information on what to do on completion */
+ struct {
+ void (*fn)(struct nbt_name_request *);
+ void *private_data;
+ } async;
+};
+
+
+
+/*
+ context structure for operations on name queries
+*/
+struct nbt_name_socket {
+ struct socket_context *sock;
+ struct tevent_context *event_ctx;
+
+ /* a queue of requests pending to be sent */
+ struct nbt_name_request *send_queue;
+
+ /* the fd event */
+ struct tevent_fd *fde;
+
+ /* mapping from name_trn_id to pending event */
+ struct idr_context *idr;
+
+ /* how many requests are waiting for a reply */
+ uint16_t num_pending;
+
+ /* what to do with incoming request packets */
+ struct {
+ void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
+ struct socket_address *);
+ void *private_data;
+ } incoming;
+
+ /* what to do with unexpected replies */
+ struct {
+ void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
+ struct socket_address *);
+ void *private_data;
+ } unexpected;
+};
+
+
+/* a simple name query */
+struct nbt_name_query {
+ struct {
+ struct nbt_name name;
+ const char *dest_addr;
+ uint16_t dest_port;
+ bool broadcast;
+ bool wins_lookup;
+ int timeout; /* in seconds */
+ int retries;
+ } in;
+ struct {
+ const char *reply_from;
+ struct nbt_name name;
+ int16_t num_addrs;
+ const char **reply_addrs;
+ } out;
+};
+
+/* a simple name status query */
+struct nbt_name_status {
+ struct {
+ struct nbt_name name;
+ const char *dest_addr;
+ uint16_t dest_port;
+ int timeout; /* in seconds */
+ int retries;
+ } in;
+ struct {
+ const char *reply_from;
+ struct nbt_name name;
+ struct nbt_rdata_status status;
+ } out;
+};
+
+/* a name registration request */
+struct nbt_name_register {
+ struct {
+ struct nbt_name name;
+ const char *dest_addr;
+ uint16_t dest_port;
+ const char *address;
+ uint16_t nb_flags;
+ bool register_demand;
+ bool broadcast;
+ bool multi_homed;
+ uint32_t ttl;
+ int timeout; /* in seconds */
+ int retries;
+ } in;
+ struct {
+ const char *reply_from;
+ struct nbt_name name;
+ const char *reply_addr;
+ uint8_t rcode;
+ } out;
+};
+
+/* a send 3 times then demand name broadcast name registration */
+struct nbt_name_register_bcast {
+ struct {
+ struct nbt_name name;
+ const char *dest_addr;
+ uint16_t dest_port;
+ const char *address;
+ uint16_t nb_flags;
+ uint32_t ttl;
+ } in;
+};
+
+
+/* wins name register with multiple wins servers to try and multiple
+ addresses to register */
+struct nbt_name_register_wins {
+ struct {
+ struct nbt_name name;
+ const char **wins_servers;
+ uint16_t wins_port;
+ const char **addresses;
+ uint16_t nb_flags;
+ uint32_t ttl;
+ } in;
+ struct {
+ const char *wins_server;
+ uint8_t rcode;
+ } out;
+};
+
+
+
+/* a name refresh request */
+struct nbt_name_refresh {
+ struct {
+ struct nbt_name name;
+ const char *dest_addr;
+ uint16_t dest_port;
+ const char *address;
+ uint16_t nb_flags;
+ bool broadcast;
+ uint32_t ttl;
+ int timeout; /* in seconds */
+ int retries;
+ } in;
+ struct {
+ const char *reply_from;
+ struct nbt_name name;
+ const char *reply_addr;
+ uint8_t rcode;
+ } out;
+};
+
+/* wins name refresh with multiple wins servers to try and multiple
+ addresses to register */
+struct nbt_name_refresh_wins {
+ struct {
+ struct nbt_name name;
+ const char **wins_servers;
+ uint16_t wins_port;
+ const char **addresses;
+ uint16_t nb_flags;
+ uint32_t ttl;
+ } in;
+ struct {
+ const char *wins_server;
+ uint8_t rcode;
+ } out;
+};
+
+
+/* a name release request */
+struct nbt_name_release {
+ struct {
+ struct nbt_name name;
+ const char *dest_addr;
+ uint16_t dest_port;
+ const char *address;
+ uint16_t nb_flags;
+ bool broadcast;
+ int timeout; /* in seconds */
+ int retries;
+ } in;
+ struct {
+ const char *reply_from;
+ struct nbt_name name;
+ const char *reply_addr;
+ uint8_t rcode;
+ } out;
+};
+
+struct nbt_name_socket *nbt_name_socket_init(TALLOC_CTX *mem_ctx,
+ struct tevent_context *event_ctx);
+void nbt_name_socket_handle_response_packet(struct nbt_name_request *req,
+ struct nbt_name_packet *packet,
+ struct socket_address *src);
+struct nbt_name_request *nbt_name_query_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_query *io);
+NTSTATUS nbt_name_query_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_query *io);
+NTSTATUS nbt_name_query(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_query *io);
+struct nbt_name_request *nbt_name_status_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_status *io);
+NTSTATUS nbt_name_status_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_status *io);
+NTSTATUS nbt_name_status(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_status *io);
+
+NTSTATUS nbt_name_dup(TALLOC_CTX *mem_ctx,
+ const struct nbt_name *name,
+ struct nbt_name *newname);
+NTSTATUS nbt_name_to_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct nbt_name *name);
+NTSTATUS nbt_name_from_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, struct nbt_name *name);
+void nbt_choose_called_name(TALLOC_CTX *mem_ctx, struct nbt_name *n, const char *name, int type);
+char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name);
+NTSTATUS nbt_name_register(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_register *io);
+NTSTATUS nbt_name_refresh(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_refresh *io);
+NTSTATUS nbt_name_release(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_release *io);
+NTSTATUS nbt_name_register_wins(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx,
+ struct nbt_name_register_wins *io);
+NTSTATUS nbt_name_refresh_wins(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx,
+ struct nbt_name_refresh_wins *io);
+NTSTATUS nbt_name_register_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_register *io);
+struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_register *io);
+NTSTATUS nbt_name_release_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_release *io);
+
+struct nbt_name_request *nbt_name_release_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_release *io);
+
+NTSTATUS nbt_name_refresh_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_refresh *io);
+
+NTSTATUS nbt_set_incoming_handler(struct nbt_name_socket *nbtsock,
+ void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
+ struct socket_address *),
+ void *private_data);
+NTSTATUS nbt_set_unexpected_handler(struct nbt_name_socket *nbtsock,
+ void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
+ struct socket_address *),
+ void *private_data);
+NTSTATUS nbt_name_reply_send(struct nbt_name_socket *nbtsock,
+ struct socket_address *dest,
+ struct nbt_name_packet *request);
+
+
+NDR_SCALAR_PTR_PROTO(wrepl_nbt_name, struct nbt_name)
+NDR_BUFFER_PROTO(nbt_name, struct nbt_name)
+NTSTATUS nbt_rcode_to_ntstatus(uint8_t rcode);
+
+struct tevent_context;
+struct tevent_req;
+struct tevent_req *nbt_name_register_bcast_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct nbt_name_socket *nbtsock,
+ struct nbt_name_register_bcast *io);
+NTSTATUS nbt_name_register_bcast_recv(struct tevent_req *req);
+struct tevent_req *nbt_name_register_wins_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct nbt_name_socket *nbtsock,
+ struct nbt_name_register_wins *io);
+NTSTATUS nbt_name_register_wins_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct nbt_name_register_wins *io);
+struct tevent_req *nbt_name_refresh_wins_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct nbt_name_socket *nbtsock,
+ struct nbt_name_refresh_wins *io);
+NTSTATUS nbt_name_refresh_wins_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct nbt_name_refresh_wins *io);
+
+FILE *startlmhosts(const char *fname);
+bool getlmhostsent(TALLOC_CTX *ctx, FILE *fp, char **pp_name, int *name_type,
+ struct sockaddr_storage *pss);
+void endlmhosts(FILE *fp);
+
+NTSTATUS resolve_lmhosts_file_as_sockaddr(TALLOC_CTX *mem_ctx,
+ const char *lmhosts_file,
+ const char *name,
+ int name_type,
+ struct sockaddr_storage **return_iplist,
+ size_t *return_count);
+
+#endif /* __LIBNBT_H__ */
diff --git a/libcli/nbt/lmhosts.c b/libcli/nbt/lmhosts.c
new file mode 100644
index 0000000..dd06e70
--- /dev/null
+++ b/libcli/nbt/lmhosts.c
@@ -0,0 +1,243 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ manipulate nbt name structures
+
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Jeremy Allison 2007
+ Copyright (C) Andrew Bartlett 2009.
+
+ 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 "lib/util/util_net.h"
+#include "system/filesys.h"
+#include "system/network.h"
+#include "../libcli/nbt/libnbt.h"
+
+/********************************************************
+ Start parsing the lmhosts file.
+*********************************************************/
+
+FILE *startlmhosts(const char *fname)
+{
+ FILE *fp = fopen(fname, "r");
+ if (!fp) {
+ DEBUG(4,("startlmhosts: Can't open lmhosts file %s. "
+ "Error was %s\n",
+ fname, strerror(errno)));
+ return NULL;
+ }
+ return fp;
+}
+
+/********************************************************
+ Parse the next line in the lmhosts file.
+*********************************************************/
+
+bool getlmhostsent(TALLOC_CTX *ctx, FILE *fp, char **pp_name, int *name_type,
+ struct sockaddr_storage *pss)
+{
+ char line[1024];
+
+ *pp_name = NULL;
+
+ while(!feof(fp) && !ferror(fp)) {
+ char *ip = NULL;
+ char *flags = NULL;
+ char *extra = NULL;
+ char *name = NULL;
+ const char *ptr;
+ char *ptr1 = NULL;
+ int count = 0;
+
+ *name_type = -1;
+
+ if (!fgets_slash(NULL,line,sizeof(line),fp)) {
+ continue;
+ }
+
+ if (*line == '#') {
+ continue;
+ }
+
+ ptr = line;
+
+ if (next_token_talloc(ctx, &ptr, &ip, NULL))
+ ++count;
+ if (next_token_talloc(ctx, &ptr, &name, NULL))
+ ++count;
+ if (next_token_talloc(ctx, &ptr, &flags, NULL))
+ ++count;
+ if (next_token_talloc(ctx, &ptr, &extra, NULL))
+ ++count;
+
+ if (count <= 0)
+ continue;
+
+ if (count > 0 && count < 2) {
+ DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",
+ line));
+ continue;
+ }
+
+ if (count >= 4) {
+ DEBUG(0,("getlmhostsent: too many columns "
+ "in lmhosts file (obsolete syntax)\n"));
+ continue;
+ }
+
+ if (!flags) {
+ flags = talloc_strdup(ctx, "");
+ if (!flags) {
+ continue;
+ }
+ }
+
+ DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n",
+ ip, name, flags));
+
+ if (strchr_m(flags,'G') || strchr_m(flags,'S')) {
+ DEBUG(0,("getlmhostsent: group flag "
+ "in lmhosts ignored (obsolete)\n"));
+ continue;
+ }
+
+ if (!interpret_string_addr(pss, ip, AI_NUMERICHOST)) {
+ DEBUG(0,("getlmhostsent: invalid address "
+ "%s.\n", ip));
+ }
+
+ /* Extra feature. If the name ends in '#XX',
+ * where XX is a hex number, then only add that name type. */
+ if((ptr1 = strchr_m(name, '#')) != NULL) {
+ char *endptr;
+ ptr1++;
+
+ *name_type = (int)strtol(ptr1, &endptr, 16);
+ if(!*ptr1 || (endptr == ptr1)) {
+ DEBUG(0,("getlmhostsent: invalid name "
+ "%s containing '#'.\n", name));
+ continue;
+ }
+
+ *(--ptr1) = '\0'; /* Truncate at the '#' */
+ }
+
+ *pp_name = talloc_strdup(ctx, name);
+ if (!*pp_name) {
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+/********************************************************
+ Finish parsing the lmhosts file.
+*********************************************************/
+
+void endlmhosts(FILE *fp)
+{
+ fclose(fp);
+}
+
+/********************************************************
+ Resolve via "lmhosts" method.
+*********************************************************/
+
+NTSTATUS resolve_lmhosts_file_as_sockaddr(TALLOC_CTX *mem_ctx,
+ const char *lmhosts_file,
+ const char *name,
+ int name_type,
+ struct sockaddr_storage **return_iplist,
+ size_t *return_count)
+{
+ /*
+ * "lmhosts" means parse the local lmhosts file.
+ */
+
+ FILE *fp;
+ char *lmhost_name = NULL;
+ int name_type2;
+ struct sockaddr_storage return_ss;
+ NTSTATUS status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+ TALLOC_CTX *ctx = NULL;
+ size_t ret_count = 0;
+ struct sockaddr_storage *iplist = NULL;
+
+ DEBUG(3,("resolve_lmhosts: "
+ "Attempting lmhosts lookup for name %s<0x%x>\n",
+ name, name_type));
+
+ fp = startlmhosts(lmhosts_file);
+
+ if ( fp == NULL )
+ return NT_STATUS_NO_SUCH_FILE;
+
+ ctx = talloc_new(mem_ctx);
+ if (!ctx) {
+ endlmhosts(fp);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ while (getlmhostsent(ctx, fp, &lmhost_name, &name_type2, &return_ss)) {
+
+ if (!strequal(name, lmhost_name)) {
+ TALLOC_FREE(lmhost_name);
+ continue;
+ }
+
+ if ((name_type2 != -1) && (name_type != name_type2)) {
+ TALLOC_FREE(lmhost_name);
+ continue;
+ }
+
+ /* wrap check. */
+ if (ret_count + 1 < ret_count) {
+ TALLOC_FREE(ctx);
+ endlmhosts(fp);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ iplist = talloc_realloc(ctx, iplist,
+ struct sockaddr_storage,
+ ret_count+1);
+
+ if (iplist == NULL) {
+ TALLOC_FREE(ctx);
+ endlmhosts(fp);
+ DEBUG(3,("resolve_lmhosts: talloc_realloc fail !\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ iplist[ret_count] = return_ss;
+ ret_count += 1;
+
+ /* we found something */
+ status = NT_STATUS_OK;
+
+ /* Multiple names only for DC lookup */
+ if (name_type != 0x1c)
+ break;
+ }
+
+ *return_count = ret_count;
+ *return_iplist = talloc_move(mem_ctx, &iplist);
+ TALLOC_FREE(ctx);
+ endlmhosts(fp);
+ return status;
+}
+
diff --git a/libcli/nbt/man/nmblookup4.1.xml b/libcli/nbt/man/nmblookup4.1.xml
new file mode 100644
index 0000000..b6fe48c
--- /dev/null
+++ b/libcli/nbt/man/nmblookup4.1.xml
@@ -0,0 +1,213 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<refentry id="nmblookup4">
+
+<refmeta>
+ <refentrytitle>nmblookup4</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo class="source">Samba</refmiscinfo>
+ <refmiscinfo class="manual">User Commands</refmiscinfo>
+ <refmiscinfo class="version">3.2</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+ <refname>nmblookup4</refname>
+ <refpurpose>NetBIOS over TCP/IP client used to lookup NetBIOS
+ names</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>nmblookup4</command>
+ <arg choice="opt">-M</arg>
+ <arg choice="opt">-R</arg>
+ <arg choice="opt">-S</arg>
+ <arg choice="opt">-r</arg>
+ <arg choice="opt">-A</arg>
+ <arg choice="opt">-h</arg>
+ <arg choice="opt">-B &lt;broadcast address&gt;</arg>
+ <arg choice="opt">-U &lt;unicast address&gt;</arg>
+ <arg choice="opt">-d &lt;debug level&gt;</arg>
+ <arg choice="opt">-s &lt;smb config file&gt;</arg>
+ <arg choice="opt">-i &lt;NetBIOS scope&gt;</arg>
+ <arg choice="opt">-T</arg>
+ <arg choice="opt">-f</arg>
+ <arg choice="req">name</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <citerefentry><refentrytitle>samba</refentrytitle>
+ <manvolnum>7</manvolnum></citerefentry> suite.</para>
+
+ <para><command>nmblookup4</command> is used to query NetBIOS names
+ and map them to IP addresses in a network using NetBIOS over TCP/IP
+ queries. The options allow the name queries to be directed at a
+ particular IP broadcast area or to a particular machine. All queries
+ are done over UDP.</para>
+</refsect1>
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-M</term>
+ <listitem><para>Searches for a master browser by looking
+ up the NetBIOS <replaceable>name</replaceable> with a
+ type of <constant>0x1d</constant>. If <replaceable>
+ name</replaceable> is "-" then it does a lookup on the special name
+ <constant>__MSBROWSE__</constant>. Please note that in order to
+ use the name "-", you need to make sure "-" isn't parsed as an
+ argument, e.g. use :
+ <userinput>nmblookup4 -M -- -</userinput>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-R</term>
+ <listitem><para>Set the recursion desired bit in the packet
+ to do a recursive lookup. This is used when sending a name
+ query to a machine running a WINS server and the user wishes
+ to query the names in the WINS server. If this bit is unset
+ the normal (broadcast responding) NetBIOS processing code
+ on a machine is used instead. See RFC1001, RFC1002 for details.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-S</term>
+ <listitem><para>Once the name query has returned an IP
+ address then do a node status query as well. A node status
+ query returns the NetBIOS names registered by a host.
+ </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-r</term>
+ <listitem><para>Try and bind to UDP port 137 to send and receive UDP
+ datagrams. The reason for this option is a bug in Windows 95
+ where it ignores the source port of the requesting packet
+ and only replies to UDP port 137. Unfortunately, on most UNIX
+ systems root privilege is needed to bind to this port, and
+ in addition, if the <citerefentry><refentrytitle>nmbd</refentrytitle>
+ <manvolnum>8</manvolnum></citerefentry> daemon is running on this machine it also binds to this port.
+ </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-A</term>
+ <listitem><para>Interpret <replaceable>name</replaceable> as
+ an IP Address and do a node status query on this address.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-B &lt;broadcast address&gt;</term>
+ <listitem><para>Send the query to the given broadcast address. Without
+ this option the default behavior of nmblookup4 is to send the
+ query to the broadcast address of the network interfaces as
+ either auto-detected or defined in the <ulink
+ url="smb.conf.5.html#INTERFACES"><parameter>interfaces</parameter>
+ </ulink> parameter of the <citerefentry><refentrytitle>smb.conf</refentrytitle>
+ <manvolnum>5</manvolnum></citerefentry> file.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-U &lt;unicast address&gt;</term>
+ <listitem><para>Do a unicast query to the specified address or
+ host <replaceable>unicast address</replaceable>. This option
+ (along with the <parameter>-R</parameter> option) is needed to
+ query a WINS server.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-T</term>
+ <listitem><para>This causes any IP addresses found in the
+ lookup to be looked up via a reverse DNS lookup into a
+ DNS name, and printed out before each</para>
+
+ <para><emphasis>IP address .... NetBIOS name</emphasis></para>
+
+ <para> pair that is the normal output.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-f</term>
+ <listitem><para>
+ Show which flags apply to the name that has been looked up. Possible
+ answers are zero or more of: Response, Authoritative,
+ Truncated, Recursion_Desired, Recursion_Available, Broadcast.
+ </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>name</term>
+ <listitem><para>This is the NetBIOS name being queried. Depending
+ upon the previous options this may be a NetBIOS name or IP address.
+ If a NetBIOS name then the different name types may be specified
+ by appending '#&lt;type&gt;' to the name. This name may also be
+ '*', which will return all registered names within a broadcast
+ area.</para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+
+<refsect1>
+ <title>EXAMPLES</title>
+
+ <para><command>nmblookup4</command> can be used to query
+ a WINS server (in the same way <command>nslookup</command> is
+ used to query DNS servers). To query a WINS server, <command>nmblookup4</command>
+ must be called like this:</para>
+
+ <para><command>nmblookup4 -U server -R 'name'</command></para>
+
+ <para>For example, running :</para>
+
+ <para><command>nmblookup4 -U samba.org -R 'IRIX#1B'</command></para>
+
+ <para>would query the WINS server samba.org for the domain
+ master browser (1B name type) for the IRIX workgroup.</para>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 3 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><citerefentry><refentrytitle>nmbd</refentrytitle>
+ <manvolnum>8</manvolnum></citerefentry>, <citerefentry><refentrytitle>samba</refentrytitle>
+ <manvolnum>7</manvolnum></citerefentry>, and <citerefentry><refentrytitle>smb.conf</refentrytitle>
+ <manvolnum>5</manvolnum></citerefentry>.</para>
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>The original Samba software and related utilities
+ were created by Andrew Tridgell. Samba is now developed
+ by the Samba Team as an Open Source project similar
+ to the way the Linux kernel is developed.</para>
+
+ <para>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter. The conversion to DocBook
+ XML 4.2 for Samba 3.0 was done by Alexander Bokovoy.</para>
+</refsect1>
+
+</refentry>
diff --git a/libcli/nbt/namequery.c b/libcli/nbt/namequery.c
new file mode 100644
index 0000000..49ab10c
--- /dev/null
+++ b/libcli/nbt/namequery.c
@@ -0,0 +1,234 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ make nbt name query requests
+
+ Copyright (C) Andrew Tridgell 2005
+
+ 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 "../libcli/nbt/libnbt.h"
+#include "../libcli/nbt/nbt_proto.h"
+#include "lib/socket/socket.h"
+
+/**
+ send a nbt name query
+*/
+_PUBLIC_ struct nbt_name_request *nbt_name_query_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_query *io)
+{
+ struct nbt_name_request *req;
+ struct nbt_name_packet *packet;
+ struct socket_address *dest;
+
+ packet = talloc_zero(nbtsock, struct nbt_name_packet);
+ if (packet == NULL) return NULL;
+
+ packet->qdcount = 1;
+ packet->operation = NBT_OPCODE_QUERY;
+ if (io->in.broadcast) {
+ packet->operation |= NBT_FLAG_BROADCAST;
+ }
+ if (io->in.wins_lookup) {
+ packet->operation |= NBT_FLAG_RECURSION_DESIRED;
+ }
+
+ packet->questions = talloc_array(packet, struct nbt_name_question, 1);
+ if (packet->questions == NULL) goto failed;
+
+ packet->questions[0].name = io->in.name;
+ packet->questions[0].question_type = NBT_QTYPE_NETBIOS;
+ packet->questions[0].question_class = NBT_QCLASS_IP;
+
+ dest = socket_address_from_strings(packet, nbtsock->sock->backend_name,
+ io->in.dest_addr, io->in.dest_port);
+ if (dest == NULL) goto failed;
+ req = nbt_name_request_send(nbtsock, nbtsock, dest, packet,
+ io->in.timeout, io->in.retries, false);
+ if (req == NULL) goto failed;
+
+ talloc_free(packet);
+ return req;
+
+failed:
+ talloc_free(packet);
+ return NULL;
+}
+
+/**
+ wait for a name query reply
+*/
+_PUBLIC_ NTSTATUS nbt_name_query_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_query *io)
+{
+ NTSTATUS status;
+ struct nbt_name_packet *packet;
+ int i;
+
+ status = nbt_name_request_recv(req);
+ if (!NT_STATUS_IS_OK(status) ||
+ req->num_replies == 0) {
+ talloc_free(req);
+ return status;
+ }
+
+ packet = req->replies[0].packet;
+ io->out.reply_from = talloc_steal(mem_ctx, req->replies[0].dest->addr);
+
+ if ((packet->operation & NBT_RCODE) != 0) {
+ status = nbt_rcode_to_ntstatus(packet->operation & NBT_RCODE);
+ talloc_free(req);
+ return status;
+ }
+
+ if (packet->ancount != 1 ||
+ packet->answers[0].rr_type != NBT_QTYPE_NETBIOS ||
+ packet->answers[0].rr_class != NBT_QCLASS_IP) {
+ talloc_free(req);
+ return status;
+ }
+
+ io->out.name = packet->answers[0].name;
+ io->out.num_addrs = packet->answers[0].rdata.netbios.length / 6;
+ io->out.reply_addrs = talloc_array(mem_ctx, const char *, io->out.num_addrs+1);
+ if (io->out.reply_addrs == NULL) {
+ talloc_free(req);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0;i<io->out.num_addrs;i++) {
+ io->out.reply_addrs[i] = talloc_steal(io->out.reply_addrs,
+ packet->answers[0].rdata.netbios.addresses[i].ipaddr);
+ }
+ io->out.reply_addrs[i] = NULL;
+
+ talloc_steal(mem_ctx, io->out.name.name);
+ talloc_steal(mem_ctx, io->out.name.scope);
+
+ talloc_free(req);
+
+ return NT_STATUS_OK;
+}
+
+/**
+ wait for a name query reply
+*/
+_PUBLIC_ NTSTATUS nbt_name_query(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_query *io)
+{
+ struct nbt_name_request *req = nbt_name_query_send(nbtsock, io);
+ return nbt_name_query_recv(req, mem_ctx, io);
+}
+
+
+/**
+ send a nbt name status
+*/
+_PUBLIC_ struct nbt_name_request *nbt_name_status_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_status *io)
+{
+ struct nbt_name_request *req;
+ struct nbt_name_packet *packet;
+ struct socket_address *dest;
+
+ packet = talloc_zero(nbtsock, struct nbt_name_packet);
+ if (packet == NULL) return NULL;
+
+ packet->qdcount = 1;
+ packet->operation = NBT_OPCODE_QUERY;
+
+ packet->questions = talloc_array(packet, struct nbt_name_question, 1);
+ if (packet->questions == NULL) goto failed;
+
+ packet->questions[0].name = io->in.name;
+ packet->questions[0].question_type = NBT_QTYPE_STATUS;
+ packet->questions[0].question_class = NBT_QCLASS_IP;
+
+ dest = socket_address_from_strings(packet, nbtsock->sock->backend_name,
+ io->in.dest_addr, io->in.dest_port);
+ if (dest == NULL) goto failed;
+ req = nbt_name_request_send(nbtsock, nbtsock, dest, packet,
+ io->in.timeout, io->in.retries, false);
+ if (req == NULL) goto failed;
+
+ talloc_free(packet);
+ return req;
+
+failed:
+ talloc_free(packet);
+ return NULL;
+}
+
+/**
+ wait for a name status reply
+*/
+_PUBLIC_ NTSTATUS nbt_name_status_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_status *io)
+{
+ NTSTATUS status;
+ struct nbt_name_packet *packet;
+ int i;
+
+ status = nbt_name_request_recv(req);
+ if (!NT_STATUS_IS_OK(status) ||
+ req->num_replies == 0) {
+ talloc_free(req);
+ return status;
+ }
+
+ packet = req->replies[0].packet;
+ io->out.reply_from = talloc_steal(mem_ctx, req->replies[0].dest->addr);
+
+ if ((packet->operation & NBT_RCODE) != 0) {
+ status = nbt_rcode_to_ntstatus(packet->operation & NBT_RCODE);
+ talloc_free(req);
+ return status;
+ }
+
+ if (packet->ancount != 1 ||
+ packet->answers[0].rr_type != NBT_QTYPE_STATUS ||
+ packet->answers[0].rr_class != NBT_QCLASS_IP) {
+ talloc_free(req);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ io->out.name = packet->answers[0].name;
+ talloc_steal(mem_ctx, io->out.name.name);
+ talloc_steal(mem_ctx, io->out.name.scope);
+
+ io->out.status = packet->answers[0].rdata.status;
+ talloc_steal(mem_ctx, io->out.status.names);
+ for (i=0;i<io->out.status.num_names;i++) {
+ talloc_steal(io->out.status.names, io->out.status.names[i].name);
+ }
+
+
+ talloc_free(req);
+
+ return NT_STATUS_OK;
+}
+
+/**
+ wait for a name status reply
+*/
+_PUBLIC_ NTSTATUS nbt_name_status(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_status *io)
+{
+ struct nbt_name_request *req = nbt_name_status_send(nbtsock, io);
+ return nbt_name_status_recv(req, mem_ctx, io);
+}
+
+
diff --git a/libcli/nbt/namerefresh.c b/libcli/nbt/namerefresh.c
new file mode 100644
index 0000000..b3aef76
--- /dev/null
+++ b/libcli/nbt/namerefresh.c
@@ -0,0 +1,347 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ send out a name refresh request
+
+ Copyright (C) Andrew Tridgell 2005
+
+ 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 <tevent.h>
+#include "../libcli/nbt/libnbt.h"
+#include "../libcli/nbt/nbt_proto.h"
+#include "lib/socket/socket.h"
+#include "lib/util/tevent_ntstatus.h"
+
+/*
+ send a nbt name refresh request
+*/
+struct nbt_name_request *nbt_name_refresh_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_refresh *io)
+{
+ struct nbt_name_request *req;
+ struct nbt_name_packet *packet;
+ struct socket_address *dest;
+
+ packet = talloc_zero(nbtsock, struct nbt_name_packet);
+ if (packet == NULL) return NULL;
+
+ packet->qdcount = 1;
+ packet->arcount = 1;
+ packet->operation = NBT_OPCODE_REFRESH;
+ if (io->in.broadcast) {
+ packet->operation |= NBT_FLAG_BROADCAST;
+ }
+
+ packet->questions = talloc_array(packet, struct nbt_name_question, 1);
+ if (packet->questions == NULL) goto failed;
+
+ packet->questions[0].name = io->in.name;
+ packet->questions[0].question_type = NBT_QTYPE_NETBIOS;
+ packet->questions[0].question_class = NBT_QCLASS_IP;
+
+ packet->additional = talloc_array(packet, struct nbt_res_rec, 1);
+ if (packet->additional == NULL) goto failed;
+
+ packet->additional[0].name = io->in.name;
+ packet->additional[0].rr_type = NBT_QTYPE_NETBIOS;
+ packet->additional[0].rr_class = NBT_QCLASS_IP;
+ packet->additional[0].ttl = io->in.ttl;
+ packet->additional[0].rdata.netbios.length = 6;
+ packet->additional[0].rdata.netbios.addresses = talloc_array(packet->additional,
+ struct nbt_rdata_address, 1);
+ if (packet->additional[0].rdata.netbios.addresses == NULL) goto failed;
+ packet->additional[0].rdata.netbios.addresses[0].nb_flags = io->in.nb_flags;
+ packet->additional[0].rdata.netbios.addresses[0].ipaddr =
+ talloc_strdup(packet->additional, io->in.address);
+
+ dest = socket_address_from_strings(nbtsock,
+ nbtsock->sock->backend_name,
+ io->in.dest_addr, io->in.dest_port);
+ if (dest == NULL) goto failed;
+ req = nbt_name_request_send(nbtsock, nbtsock, dest, packet,
+ io->in.timeout, io->in.retries, false);
+ if (req == NULL) goto failed;
+
+ talloc_free(packet);
+ return req;
+
+failed:
+ talloc_free(packet);
+ return NULL;
+}
+
+/*
+ wait for a refresh reply
+*/
+_PUBLIC_ NTSTATUS nbt_name_refresh_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_refresh *io)
+{
+ NTSTATUS status;
+ struct nbt_name_packet *packet;
+
+ status = nbt_name_request_recv(req);
+ if (!NT_STATUS_IS_OK(status) ||
+ req->num_replies == 0) {
+ talloc_free(req);
+ return status;
+ }
+
+ packet = req->replies[0].packet;
+ io->out.reply_from = talloc_steal(mem_ctx, req->replies[0].dest->addr);
+
+ if (packet->ancount != 1 ||
+ packet->answers[0].rr_type != NBT_QTYPE_NETBIOS ||
+ packet->answers[0].rr_class != NBT_QCLASS_IP) {
+ talloc_free(req);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ io->out.rcode = packet->operation & NBT_RCODE;
+ io->out.name = packet->answers[0].name;
+ if (packet->answers[0].rdata.netbios.length < 6) {
+ talloc_free(req);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ io->out.reply_addr = talloc_steal(mem_ctx,
+ packet->answers[0].rdata.netbios.addresses[0].ipaddr);
+ talloc_steal(mem_ctx, io->out.name.name);
+ talloc_steal(mem_ctx, io->out.name.scope);
+
+ talloc_free(req);
+
+ return NT_STATUS_OK;
+}
+
+/*
+ synchronous name refresh request
+*/
+_PUBLIC_ NTSTATUS nbt_name_refresh(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_refresh *io)
+{
+ struct nbt_name_request *req = nbt_name_refresh_send(nbtsock, io);
+ return nbt_name_refresh_recv(req, mem_ctx, io);
+}
+
+
+
+/**
+ a wins name refresh with multiple WINS servers and multiple
+ addresses to refresh. Try each WINS server in turn, until we get a
+ reply for each address
+*/
+struct nbt_name_refresh_wins_state {
+ struct nbt_name_socket *nbtsock;
+ struct nbt_name_refresh *io;
+ char **wins_servers;
+ uint16_t wins_port;
+ char **addresses;
+ int address_idx;
+};
+
+static void nbt_name_refresh_wins_handler(struct nbt_name_request *subreq);
+
+/**
+ the async send call for a multi-server WINS refresh
+*/
+_PUBLIC_ struct tevent_req *nbt_name_refresh_wins_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct nbt_name_socket *nbtsock,
+ struct nbt_name_refresh_wins *io)
+{
+ struct tevent_req *req;
+ struct nbt_name_refresh_wins_state *state;
+ struct nbt_name_request *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct nbt_name_refresh_wins_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->io = talloc(state, struct nbt_name_refresh);
+ if (tevent_req_nomem(state->io, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (io->in.wins_servers == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ if (io->in.wins_servers[0] == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ if (io->in.addresses == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ if (io->in.addresses[0] == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ state->wins_port = io->in.wins_port;
+ state->wins_servers = str_list_copy(state, io->in.wins_servers);
+ if (tevent_req_nomem(state->wins_servers, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->addresses = str_list_copy(state, io->in.addresses);
+ if (tevent_req_nomem(state->addresses, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->io->in.name = io->in.name;
+ state->io->in.dest_addr = state->wins_servers[0];
+ state->io->in.dest_port = state->wins_port;
+ state->io->in.address = io->in.addresses[0];
+ state->io->in.nb_flags = io->in.nb_flags;
+ state->io->in.broadcast = false;
+ state->io->in.ttl = io->in.ttl;
+ state->io->in.timeout = 2;
+ state->io->in.retries = 2;
+
+ state->nbtsock = nbtsock;
+ state->address_idx = 0;
+
+ subreq = nbt_name_refresh_send(nbtsock, state->io);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq->async.fn = nbt_name_refresh_wins_handler;
+ subreq->async.private_data = req;
+
+ return req;
+}
+
+static void nbt_name_refresh_wins_handler(struct nbt_name_request *subreq)
+{
+ struct tevent_req *req =
+ talloc_get_type_abort(subreq->async.private_data,
+ struct tevent_req);
+ struct nbt_name_refresh_wins_state *state =
+ tevent_req_data(req,
+ struct nbt_name_refresh_wins_state);
+ NTSTATUS status;
+
+ status = nbt_name_refresh_recv(subreq, state, state->io);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ /* the refresh timed out - try the next WINS server */
+ state->wins_servers++;
+ if (state->wins_servers[0] == NULL) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ state->address_idx = 0;
+ state->io->in.dest_addr = state->wins_servers[0];
+ state->io->in.dest_port = state->wins_port;
+ state->io->in.address = state->addresses[0];
+
+ subreq = nbt_name_refresh_send(state->nbtsock, state->io);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ subreq->async.fn = nbt_name_refresh_wins_handler;
+ subreq->async.private_data = req;
+ } else if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ if (state->io->out.rcode == 0 &&
+ state->addresses[state->address_idx+1] != NULL) {
+ /* refresh our next address */
+ state->io->in.address = state->addresses[++(state->address_idx)];
+ subreq = nbt_name_refresh_send(state->nbtsock, state->io);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ subreq->async.fn = nbt_name_refresh_wins_handler;
+ subreq->async.private_data = req;
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+/*
+ multi-homed WINS name refresh - recv side
+*/
+_PUBLIC_ NTSTATUS nbt_name_refresh_wins_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct nbt_name_refresh_wins *io)
+{
+ struct nbt_name_refresh_wins_state *state =
+ tevent_req_data(req,
+ struct nbt_name_refresh_wins_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ io->out.wins_server = talloc_move(mem_ctx, &state->wins_servers[0]);
+ io->out.rcode = state->io->out.rcode;
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+/*
+ multi-homed WINS refresh - sync interface
+*/
+_PUBLIC_ NTSTATUS nbt_name_refresh_wins(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx,
+ struct nbt_name_refresh_wins *io)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *subreq;
+ NTSTATUS status;
+
+ /*
+ * TODO: create a temporary event context
+ */
+ ev = nbtsock->event_ctx;
+
+ subreq = nbt_name_refresh_wins_send(frame, ev, nbtsock, io);
+ if (subreq == NULL) {
+ talloc_free(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!tevent_req_poll(subreq, ev)) {
+ status = map_nt_error_from_unix_common(errno);
+ talloc_free(frame);
+ return status;
+ }
+
+ status = nbt_name_refresh_wins_recv(subreq, mem_ctx, io);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(frame);
+ return status;
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
diff --git a/libcli/nbt/nameregister.c b/libcli/nbt/nameregister.c
new file mode 100644
index 0000000..8e8271d
--- /dev/null
+++ b/libcli/nbt/nameregister.c
@@ -0,0 +1,514 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ send out a name registration request
+
+ Copyright (C) Andrew Tridgell 2005
+
+ 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 <tevent.h>
+#include "../libcli/nbt/libnbt.h"
+#include "../libcli/nbt/nbt_proto.h"
+#include "lib/socket/socket.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
+#include "../lib/util/tevent_ntstatus.h"
+
+/*
+ send a nbt name registration request
+*/
+struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_register *io)
+{
+ struct nbt_name_request *req;
+ struct nbt_name_packet *packet;
+ struct socket_address *dest;
+
+ packet = talloc_zero(nbtsock, struct nbt_name_packet);
+ if (packet == NULL) return NULL;
+
+ packet->qdcount = 1;
+ packet->arcount = 1;
+ if (io->in.multi_homed) {
+ packet->operation = NBT_OPCODE_MULTI_HOME_REG;
+ } else {
+ packet->operation = NBT_OPCODE_REGISTER;
+ }
+ if (io->in.broadcast) {
+ packet->operation |= NBT_FLAG_BROADCAST;
+ }
+ if (io->in.register_demand) {
+ packet->operation |= NBT_FLAG_RECURSION_DESIRED;
+ }
+
+ packet->questions = talloc_array(packet, struct nbt_name_question, 1);
+ if (packet->questions == NULL) goto failed;
+
+ packet->questions[0].name = io->in.name;
+ packet->questions[0].question_type = NBT_QTYPE_NETBIOS;
+ packet->questions[0].question_class = NBT_QCLASS_IP;
+
+ packet->additional = talloc_array(packet, struct nbt_res_rec, 1);
+ if (packet->additional == NULL) goto failed;
+
+ packet->additional[0].name = io->in.name;
+ packet->additional[0].rr_type = NBT_QTYPE_NETBIOS;
+ packet->additional[0].rr_class = NBT_QCLASS_IP;
+ packet->additional[0].ttl = io->in.ttl;
+ packet->additional[0].rdata.netbios.length = 6;
+ packet->additional[0].rdata.netbios.addresses = talloc_array(packet->additional,
+ struct nbt_rdata_address, 1);
+ if (packet->additional[0].rdata.netbios.addresses == NULL) goto failed;
+ packet->additional[0].rdata.netbios.addresses[0].nb_flags = io->in.nb_flags;
+ packet->additional[0].rdata.netbios.addresses[0].ipaddr =
+ talloc_strdup(packet->additional, io->in.address);
+ if (packet->additional[0].rdata.netbios.addresses[0].ipaddr == NULL) goto failed;
+
+ dest = socket_address_from_strings(packet, nbtsock->sock->backend_name,
+ io->in.dest_addr, io->in.dest_port);
+ if (dest == NULL) goto failed;
+ req = nbt_name_request_send(nbtsock, nbtsock, dest, packet,
+ io->in.timeout, io->in.retries, false);
+ if (req == NULL) goto failed;
+
+ talloc_free(packet);
+ return req;
+
+failed:
+ talloc_free(packet);
+ return NULL;
+}
+
+/*
+ wait for a registration reply
+*/
+_PUBLIC_ NTSTATUS nbt_name_register_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_register *io)
+{
+ NTSTATUS status;
+ struct nbt_name_packet *packet;
+
+ status = nbt_name_request_recv(req);
+ if (!NT_STATUS_IS_OK(status) ||
+ req->num_replies == 0) {
+ talloc_free(req);
+ return status;
+ }
+
+ packet = req->replies[0].packet;
+ io->out.reply_from = talloc_steal(mem_ctx, req->replies[0].dest->addr);
+
+ if (packet->ancount != 1 ||
+ packet->answers[0].rr_type != NBT_QTYPE_NETBIOS ||
+ packet->answers[0].rr_class != NBT_QCLASS_IP) {
+ talloc_free(req);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ io->out.rcode = packet->operation & NBT_RCODE;
+ io->out.name = packet->answers[0].name;
+ if (packet->answers[0].rdata.netbios.length < 6) {
+ talloc_free(req);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ io->out.reply_addr = talloc_steal(mem_ctx,
+ packet->answers[0].rdata.netbios.addresses[0].ipaddr);
+ talloc_steal(mem_ctx, io->out.name.name);
+ talloc_steal(mem_ctx, io->out.name.scope);
+
+ talloc_free(req);
+
+ return NT_STATUS_OK;
+}
+
+/*
+ synchronous name registration request
+*/
+_PUBLIC_ NTSTATUS nbt_name_register(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_register *io)
+{
+ struct nbt_name_request *req = nbt_name_register_send(nbtsock, io);
+ return nbt_name_register_recv(req, mem_ctx, io);
+}
+
+
+/*
+ a 4 step broadcast registration. 3 lots of name registration requests, followed by
+ a name registration demand
+*/
+struct nbt_name_register_bcast_state {
+ struct nbt_name_socket *nbtsock;
+ struct nbt_name_register io;
+};
+
+static void nbt_name_register_bcast_handler(struct nbt_name_request *subreq);
+
+/*
+ the async send call for a 4 stage name registration
+*/
+_PUBLIC_ struct tevent_req *nbt_name_register_bcast_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct nbt_name_socket *nbtsock,
+ struct nbt_name_register_bcast *io)
+{
+ struct tevent_req *req;
+ struct nbt_name_register_bcast_state *state;
+ struct nbt_name_request *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct nbt_name_register_bcast_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->io.in.name = io->in.name;
+ state->io.in.dest_addr = io->in.dest_addr;
+ state->io.in.dest_port = io->in.dest_port;
+ state->io.in.address = io->in.address;
+ state->io.in.nb_flags = io->in.nb_flags;
+ state->io.in.register_demand = false;
+ state->io.in.broadcast = true;
+ state->io.in.multi_homed = false;
+ state->io.in.ttl = io->in.ttl;
+ state->io.in.timeout = 1;
+ state->io.in.retries = 2;
+
+ state->nbtsock = nbtsock;
+
+ subreq = nbt_name_register_send(nbtsock, &state->io);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq->async.fn = nbt_name_register_bcast_handler;
+ subreq->async.private_data = req;
+
+ return req;
+}
+
+static void nbt_name_register_bcast_handler(struct nbt_name_request *subreq)
+{
+ struct tevent_req *req =
+ talloc_get_type_abort(subreq->async.private_data,
+ struct tevent_req);
+ struct nbt_name_register_bcast_state *state =
+ tevent_req_data(req,
+ struct nbt_name_register_bcast_state);
+ NTSTATUS status;
+
+ status = nbt_name_register_recv(subreq, state, &state->io);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ if (state->io.in.register_demand == true) {
+ tevent_req_done(req);
+ return;
+ }
+
+ /* the registration timed out - good, send the demand */
+ state->io.in.register_demand = true;
+ state->io.in.retries = 0;
+
+ subreq = nbt_name_register_send(state->nbtsock, &state->io);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+
+ subreq->async.fn = nbt_name_register_bcast_handler;
+ subreq->async.private_data = req;
+ return;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ DEBUG(3,("Name registration conflict from %s for %s with ip %s - rcode %d\n",
+ state->io.out.reply_from,
+ nbt_name_string(state, &state->io.out.name),
+ state->io.out.reply_addr,
+ state->io.out.rcode));
+
+ tevent_req_nterror(req, NT_STATUS_CONFLICTING_ADDRESSES);
+}
+
+/*
+ broadcast 4 part name register - recv
+*/
+_PUBLIC_ NTSTATUS nbt_name_register_bcast_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+/*
+ broadcast 4 part name register - sync interface
+*/
+NTSTATUS nbt_name_register_bcast(struct nbt_name_socket *nbtsock,
+ struct nbt_name_register_bcast *io)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *subreq;
+ NTSTATUS status;
+
+ /*
+ * TODO: create a temporary event context
+ */
+ ev = nbtsock->event_ctx;
+
+ subreq = nbt_name_register_bcast_send(frame, ev, nbtsock, io);
+ if (subreq == NULL) {
+ talloc_free(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!tevent_req_poll(subreq, ev)) {
+ status = map_nt_error_from_unix_common(errno);
+ talloc_free(frame);
+ return status;
+ }
+
+ status = nbt_name_register_bcast_recv(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(frame);
+ return status;
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+
+/*
+ a wins name register with multiple WINS servers and multiple
+ addresses to register. Try each WINS server in turn, until we get a
+ reply for each address
+*/
+struct nbt_name_register_wins_state {
+ struct nbt_name_socket *nbtsock;
+ struct nbt_name_register io;
+ char **wins_servers;
+ uint16_t wins_port;
+ char **addresses;
+ uint32_t address_idx;
+};
+
+static void nbt_name_register_wins_handler(struct nbt_name_request *subreq);
+
+/*
+ the async send call for a multi-server WINS register
+*/
+_PUBLIC_ struct tevent_req *nbt_name_register_wins_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct nbt_name_socket *nbtsock,
+ struct nbt_name_register_wins *io)
+{
+ struct tevent_req *req;
+ struct nbt_name_register_wins_state *state;
+ struct nbt_name_request *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct nbt_name_register_wins_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (io->in.wins_servers == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ if (io->in.wins_servers[0] == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ if (io->in.addresses == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ if (io->in.addresses[0] == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ state->wins_port = io->in.wins_port;
+ state->wins_servers = str_list_copy(state, io->in.wins_servers);
+ if (tevent_req_nomem(state->wins_servers, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->addresses = str_list_copy(state, io->in.addresses);
+ if (tevent_req_nomem(state->addresses, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->io.in.name = io->in.name;
+ state->io.in.dest_addr = state->wins_servers[0];
+ state->io.in.dest_port = state->wins_port;
+ state->io.in.address = io->in.addresses[0];
+ state->io.in.nb_flags = io->in.nb_flags;
+ state->io.in.broadcast = false;
+ state->io.in.register_demand = false;
+ state->io.in.multi_homed = (io->in.nb_flags & NBT_NM_GROUP)?false:true;
+ state->io.in.ttl = io->in.ttl;
+ state->io.in.timeout = 3;
+ state->io.in.retries = 2;
+
+ state->nbtsock = nbtsock;
+ state->address_idx = 0;
+
+ subreq = nbt_name_register_send(nbtsock, &state->io);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq->async.fn = nbt_name_register_wins_handler;
+ subreq->async.private_data = req;
+
+ return req;
+}
+
+/*
+ state handler for WINS multi-homed multi-server name register
+*/
+static void nbt_name_register_wins_handler(struct nbt_name_request *subreq)
+{
+ struct tevent_req *req =
+ talloc_get_type_abort(subreq->async.private_data,
+ struct tevent_req);
+ struct nbt_name_register_wins_state *state =
+ tevent_req_data(req,
+ struct nbt_name_register_wins_state);
+ NTSTATUS status;
+
+ status = nbt_name_register_recv(subreq, state, &state->io);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ /* the register timed out - try the next WINS server */
+ state->wins_servers++;
+ if (state->wins_servers[0] == NULL) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ state->address_idx = 0;
+ state->io.in.dest_addr = state->wins_servers[0];
+ state->io.in.dest_port = state->wins_port;
+ state->io.in.address = state->addresses[0];
+
+ subreq = nbt_name_register_send(state->nbtsock, &state->io);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+
+ subreq->async.fn = nbt_name_register_wins_handler;
+ subreq->async.private_data = req;
+ return;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ if (state->io.out.rcode == 0 &&
+ state->addresses[state->address_idx+1] != NULL) {
+ /* register our next address */
+ state->io.in.address = state->addresses[++(state->address_idx)];
+
+ subreq = nbt_name_register_send(state->nbtsock, &state->io);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+
+ subreq->async.fn = nbt_name_register_wins_handler;
+ subreq->async.private_data = req;
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+/*
+ multi-homed WINS name register - recv side
+*/
+_PUBLIC_ NTSTATUS nbt_name_register_wins_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct nbt_name_register_wins *io)
+{
+ struct nbt_name_register_wins_state *state =
+ tevent_req_data(req,
+ struct nbt_name_register_wins_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ io->out.wins_server = talloc_move(mem_ctx, &state->wins_servers[0]);
+ io->out.rcode = state->io.out.rcode;
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+/*
+ multi-homed WINS register - sync interface
+*/
+_PUBLIC_ NTSTATUS nbt_name_register_wins(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx,
+ struct nbt_name_register_wins *io)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *subreq;
+ NTSTATUS status;
+
+ /*
+ * TODO: create a temporary event context
+ */
+ ev = nbtsock->event_ctx;
+
+ subreq = nbt_name_register_wins_send(frame, ev, nbtsock, io);
+ if (subreq == NULL) {
+ talloc_free(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!tevent_req_poll(subreq, ev)) {
+ status = map_nt_error_from_unix_common(errno);
+ talloc_free(frame);
+ return status;
+ }
+
+ status = nbt_name_register_wins_recv(subreq, mem_ctx, io);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(frame);
+ return status;
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
diff --git a/libcli/nbt/namerelease.c b/libcli/nbt/namerelease.c
new file mode 100644
index 0000000..68c8252
--- /dev/null
+++ b/libcli/nbt/namerelease.c
@@ -0,0 +1,134 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ send out a name release request
+
+ Copyright (C) Andrew Tridgell 2005
+
+ 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 "../libcli/nbt/libnbt.h"
+#include "../libcli/nbt/nbt_proto.h"
+#include "lib/socket/socket.h"
+
+/*
+ send a nbt name release request
+*/
+_PUBLIC_ struct nbt_name_request *nbt_name_release_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_release *io)
+{
+ struct nbt_name_request *req;
+ struct nbt_name_packet *packet;
+ struct socket_address *dest;
+
+ packet = talloc_zero(nbtsock, struct nbt_name_packet);
+ if (packet == NULL) return NULL;
+
+ packet->qdcount = 1;
+ packet->arcount = 1;
+ packet->operation = NBT_OPCODE_RELEASE;
+ if (io->in.broadcast) {
+ packet->operation |= NBT_FLAG_BROADCAST;
+ }
+
+ packet->questions = talloc_array(packet, struct nbt_name_question, 1);
+ if (packet->questions == NULL) goto failed;
+
+ packet->questions[0].name = io->in.name;
+ packet->questions[0].question_type = NBT_QTYPE_NETBIOS;
+ packet->questions[0].question_class = NBT_QCLASS_IP;
+
+ packet->additional = talloc_array(packet, struct nbt_res_rec, 1);
+ if (packet->additional == NULL) goto failed;
+
+ packet->additional[0].name = io->in.name;
+ packet->additional[0].rr_type = NBT_QTYPE_NETBIOS;
+ packet->additional[0].rr_class = NBT_QCLASS_IP;
+ packet->additional[0].ttl = 0;
+ packet->additional[0].rdata.netbios.length = 6;
+ packet->additional[0].rdata.netbios.addresses = talloc_array(packet->additional,
+ struct nbt_rdata_address, 1);
+ if (packet->additional[0].rdata.netbios.addresses == NULL) goto failed;
+ packet->additional[0].rdata.netbios.addresses[0].nb_flags = io->in.nb_flags;
+ packet->additional[0].rdata.netbios.addresses[0].ipaddr =
+ talloc_strdup(packet->additional, io->in.address);
+
+ dest = socket_address_from_strings(packet, nbtsock->sock->backend_name,
+ io->in.dest_addr, io->in.dest_port);
+ if (dest == NULL) goto failed;
+ req = nbt_name_request_send(nbtsock, nbtsock, dest, packet,
+ io->in.timeout, io->in.retries, false);
+ if (req == NULL) goto failed;
+
+ talloc_free(packet);
+ return req;
+
+failed:
+ talloc_free(packet);
+ return NULL;
+}
+
+/*
+ wait for a release reply
+*/
+_PUBLIC_ NTSTATUS nbt_name_release_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_release *io)
+{
+ NTSTATUS status;
+ struct nbt_name_packet *packet;
+
+ status = nbt_name_request_recv(req);
+ if (!NT_STATUS_IS_OK(status) ||
+ req->num_replies == 0) {
+ talloc_free(req);
+ return status;
+ }
+
+ packet = req->replies[0].packet;
+ io->out.reply_from = talloc_steal(mem_ctx, req->replies[0].dest->addr);
+
+ if (packet->ancount != 1 ||
+ packet->answers[0].rr_type != NBT_QTYPE_NETBIOS ||
+ packet->answers[0].rr_class != NBT_QCLASS_IP) {
+ talloc_free(req);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ io->out.rcode = packet->operation & NBT_RCODE;
+ io->out.name = packet->answers[0].name;
+ if (packet->answers[0].rdata.netbios.length < 6) {
+ talloc_free(req);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ io->out.reply_addr = talloc_steal(mem_ctx,
+ packet->answers[0].rdata.netbios.addresses[0].ipaddr);
+ talloc_steal(mem_ctx, io->out.name.name);
+ talloc_steal(mem_ctx, io->out.name.scope);
+
+ talloc_free(req);
+
+ return NT_STATUS_OK;
+}
+
+/*
+ synchronous name release request
+*/
+_PUBLIC_ NTSTATUS nbt_name_release(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_release *io)
+{
+ struct nbt_name_request *req = nbt_name_release_send(nbtsock, io);
+ return nbt_name_release_recv(req, mem_ctx, io);
+}
diff --git a/libcli/nbt/nbt_proto.h b/libcli/nbt/nbt_proto.h
new file mode 100644
index 0000000..e6ee46b
--- /dev/null
+++ b/libcli/nbt/nbt_proto.h
@@ -0,0 +1,65 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ manipulate nbt name structures
+
+ Copyright (C) Andrew Tridgell 2005
+
+ 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/>.
+*/
+
+#ifndef _____LIBCLI_NBT_NBT_PROTO_H__
+#define _____LIBCLI_NBT_NBT_PROTO_H__
+
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2)
+/* This file was automatically generated by mkproto.pl. DO NOT EDIT */
+
+/* this file contains prototypes for functions that are private
+ * to this subsystem or library. These functions should not be
+ * used outside this particular subsystem! */
+
+
+/* The following definitions come from ../libcli/nbt/nbtsocket.c */
+
+struct nbt_name_request *nbt_name_request_send(TALLOC_CTX *mem_ctx,
+ struct nbt_name_socket *nbtsock,
+ struct socket_address *dest,
+ struct nbt_name_packet *request,
+ int timeout, int retries,
+ bool allow_multiple_replies);
+NTSTATUS nbt_name_request_recv(struct nbt_name_request *req);
+
+/* The following definitions come from ../libcli/nbt/namequery.c */
+
+
+/* The following definitions come from ../libcli/nbt/nameregister.c */
+
+struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_register *io);
+NTSTATUS nbt_name_register_bcast(struct nbt_name_socket *nbtsock,
+ struct nbt_name_register_bcast *io);
+
+/* The following definitions come from ../libcli/nbt/namerefresh.c */
+
+struct nbt_name_request *nbt_name_refresh_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_refresh *io);
+
+/* The following definitions come from ../libcli/nbt/namerelease.c */
+
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2)
+
+#endif /* _____LIBCLI_NBT_NBT_PROTO_H__ */
+
diff --git a/libcli/nbt/nbtname.c b/libcli/nbt/nbtname.c
new file mode 100644
index 0000000..a2b0d34
--- /dev/null
+++ b/libcli/nbt/nbtname.c
@@ -0,0 +1,486 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ manipulate nbt name structures
+
+ Copyright (C) Andrew Tridgell 2005
+
+ 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/>.
+*/
+
+/*
+ see rfc1002 for the detailed format of compressed names
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "system/locale.h"
+#include "lib/util/util_net.h"
+#include "libcli/nbt/libnbt.h"
+
+/*
+ decompress a 'compressed' name component
+ */
+static bool decompress_name(char *name, enum nbt_name_type *type)
+{
+ int i;
+ for (i=0;name[2*i];i++) {
+ uint8_t c1 = name[2*i];
+ uint8_t c2 = name[1+(2*i)];
+ if (c1 < 'A' || c1 > 'P' ||
+ c2 < 'A' || c2 > 'P') {
+ return false;
+ }
+ name[i] = ((c1-'A')<<4) | (c2-'A');
+ }
+ name[i] = 0;
+ if (i == 16) {
+ *type = (enum nbt_name_type)(name[15]);
+ name[15] = 0;
+ i--;
+ } else {
+ *type = NBT_NAME_CLIENT;
+ }
+
+ /* trim trailing spaces */
+ for (;i>0 && name[i-1]==' ';i--) {
+ name[i-1] = 0;
+ }
+
+ return true;
+}
+
+
+/*
+ compress a name component
+ */
+static uint8_t *compress_name(TALLOC_CTX *mem_ctx,
+ const uint8_t *name, enum nbt_name_type type)
+{
+ uint8_t *cname;
+ int i;
+ uint8_t pad_char;
+
+ if (strlen((const char *)name) > 15) {
+ return NULL;
+ }
+
+ cname = talloc_array(mem_ctx, uint8_t, 33);
+ if (cname == NULL) return NULL;
+
+ for (i=0;name[i];i++) {
+ cname[2*i] = 'A' + (name[i]>>4);
+ cname[1+2*i] = 'A' + (name[i]&0xF);
+ }
+ if (strcmp((const char *)name, "*") == 0) {
+ pad_char = 0;
+ } else {
+ pad_char = ' ';
+ }
+ for (;i<15;i++) {
+ cname[2*i] = 'A' + (pad_char>>4);
+ cname[1+2*i] = 'A' + (pad_char&0xF);
+ }
+
+ pad_char = type;
+ cname[2*i] = 'A' + (pad_char>>4);
+ cname[1+2*i] = 'A' + (pad_char&0xF);
+
+ cname[32] = 0;
+ return cname;
+}
+
+
+/**
+ pull a nbt name from the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_name(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct nbt_name *r)
+{
+ uint8_t *scope;
+ char *cname;
+ const char *s;
+ bool ok;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ NDR_CHECK(ndr_pull_nbt_string(ndr, ndr_flags, &s));
+
+ scope = (uint8_t *)strchr(s, '.');
+ if (scope) {
+ *scope = 0;
+ r->scope = talloc_strdup(ndr->current_mem_ctx, (const char *)&scope[1]);
+ NDR_ERR_HAVE_NO_MEMORY(r->scope);
+ } else {
+ r->scope = NULL;
+ }
+
+ cname = discard_const_p(char, s);
+
+ /* the first component is limited to 16 bytes in the DOS charset,
+ which is 32 in the 'compressed' form */
+ if (strlen(cname) > 32) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "NBT NAME cname > 32");
+ }
+
+ /* decompress the first component */
+ ok = decompress_name(cname, &r->type);
+ if (!ok) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "NBT NAME failed to decompress");
+ }
+
+ r->name = talloc_strdup(ndr->current_mem_ctx, cname);
+ NDR_ERR_HAVE_NO_MEMORY(r->name);
+
+ talloc_free(cname);
+
+ return NDR_ERR_SUCCESS;
+}
+
+/**
+ push a nbt name to the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_name(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct nbt_name *r)
+{
+ uint8_t *cname, *fullname;
+ enum ndr_err_code ndr_err;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (strlen(r->name) > 15) {
+ return ndr_push_error(ndr, NDR_ERR_STRING,
+ "nbt_name longer as 15 chars: %s",
+ r->name);
+ }
+
+ cname = compress_name(ndr, (const uint8_t *)r->name, r->type);
+ NDR_ERR_HAVE_NO_MEMORY(cname);
+
+ if (r->scope) {
+ fullname = (uint8_t *)talloc_asprintf(ndr, "%s.%s", cname, r->scope);
+ NDR_ERR_HAVE_NO_MEMORY(fullname);
+ talloc_free(cname);
+ } else {
+ fullname = cname;
+ }
+
+ ndr_err = ndr_push_nbt_string(ndr, ndr_flags, (const char *)fullname);
+
+ return ndr_err;
+}
+
+
+/**
+ copy a nbt name structure
+*/
+_PUBLIC_ NTSTATUS nbt_name_dup(TALLOC_CTX *mem_ctx,
+ const struct nbt_name *name,
+ struct nbt_name *newname)
+{
+ *newname = *name;
+ newname->name = talloc_strdup(mem_ctx, newname->name);
+ NT_STATUS_HAVE_NO_MEMORY(newname->name);
+ newname->scope = talloc_strdup(mem_ctx, newname->scope);
+ if (name->scope) {
+ NT_STATUS_HAVE_NO_MEMORY(newname->scope);
+ }
+ return NT_STATUS_OK;
+}
+
+/**
+ push a nbt name into a blob
+*/
+_PUBLIC_ NTSTATUS nbt_name_to_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct nbt_name *name)
+{
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_push_struct_blob(blob, mem_ctx, name, (ndr_push_flags_fn_t)ndr_push_nbt_name);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+ pull a nbt name from a blob
+*/
+_PUBLIC_ NTSTATUS nbt_name_from_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, struct nbt_name *name)
+{
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_pull_struct_blob(blob, mem_ctx, name,
+ (ndr_pull_flags_fn_t)ndr_pull_nbt_name);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/**
+ choose a name to use when calling a server in a NBT session request.
+ we use heuristics to see if the name we have been given is a IP
+ address, or a too-long name. If it is then use *SMBSERVER, or a
+ truncated name
+*/
+_PUBLIC_ void nbt_choose_called_name(TALLOC_CTX *mem_ctx,
+ struct nbt_name *n, const char *name, int type)
+{
+ n->scope = NULL;
+ n->type = type;
+
+ if ((name == NULL) || is_ipaddress(name)) {
+ n->name = "*SMBSERVER";
+ return;
+ }
+ if (strlen(name) > 15) {
+ const char *p = strchr(name, '.');
+ char *s;
+ if (p - name > 15) {
+ n->name = "*SMBSERVER";
+ return;
+ }
+ s = talloc_strndup(mem_ctx, name, PTR_DIFF(p, name));
+ n->name = talloc_strdup_upper(mem_ctx, s);
+ return;
+ }
+
+ n->name = talloc_strdup_upper(mem_ctx, name);
+}
+
+
+/*
+ escape a string into a form containing only a small set of characters,
+ the rest is hex encoded. This is similar to URL encoding
+*/
+static const char *nbt_hex_encode(TALLOC_CTX *mem_ctx, const char *s)
+{
+ int i, len;
+ char *ret;
+ const char *valid_chars = "_-.$@ ";
+#define NBT_CHAR_ALLOW(c) (isalnum((unsigned char)c) || strchr(valid_chars, c))
+
+ for (len=i=0;s[i];i++,len++) {
+ if (!NBT_CHAR_ALLOW(s[i])) {
+ len += 2;
+ }
+ }
+
+ ret = talloc_array(mem_ctx, char, len+1);
+ if (ret == NULL) return NULL;
+
+ for (len=i=0;s[i];i++) {
+ if (NBT_CHAR_ALLOW(s[i])) {
+ ret[len++] = s[i];
+ } else {
+ snprintf(&ret[len], 4, "%%%02x", (unsigned char)s[i]);
+ len += 3;
+ }
+ }
+ ret[len] = 0;
+
+ return ret;
+}
+
+
+/**
+ form a string for a NBT name
+*/
+_PUBLIC_ char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ char *ret;
+ if (name->scope) {
+ ret = talloc_asprintf(mem_ctx, "%s<%02x>-%s",
+ nbt_hex_encode(tmp_ctx, name->name),
+ name->type,
+ nbt_hex_encode(tmp_ctx, name->scope));
+ } else {
+ ret = talloc_asprintf(mem_ctx, "%s<%02x>",
+ nbt_hex_encode(tmp_ctx, name->name),
+ name->type);
+ }
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+/**
+ pull a nbt name, WINS Replication uses another on wire format for nbt name
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_wrepl_nbt_name(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct nbt_name **_r)
+{
+ struct nbt_name *r;
+ uint8_t *namebuf;
+ uint32_t namebuf_len;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &namebuf_len));
+ if (namebuf_len < 1 || namebuf_len > 255) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, "value (%"PRIu32") out of range (1 - 255)", namebuf_len);
+ }
+ NDR_PULL_ALLOC_N(ndr, namebuf, namebuf_len);
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, namebuf, namebuf_len));
+
+ if ((namebuf_len % 4) == 0) {
+ /*
+ * [MS-WINSRA] — v20091104 was wrong
+ * regarding section "2.2.10.1 Name Record"
+ *
+ * If the name buffer is already 4 byte aligned
+ * Windows (at least 2003 SP1 and 2008) add 4 extra
+ * bytes. This can happen when the name has a scope.
+ */
+ uint32_t pad;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &pad));
+ }
+
+ NDR_PULL_ALLOC(ndr, r);
+
+ /* oh wow, what a nasty bug in windows ... */
+ if (namebuf[0] == 0x1b && namebuf_len >= 16) {
+ namebuf[0] = namebuf[15];
+ namebuf[15] = 0x1b;
+ }
+
+ if (namebuf_len < 17) {
+ r->type = 0x00;
+
+ r->name = talloc_strndup(r, (char *)namebuf, namebuf_len);
+ if (!r->name) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "out of memory");
+
+ r->scope= NULL;
+
+ talloc_free(namebuf);
+ *_r = r;
+ return NDR_ERR_SUCCESS;
+ }
+
+ r->type = namebuf[15];
+
+ namebuf[15] = '\0';
+ trim_string((char *)namebuf, NULL, " ");
+ r->name = talloc_strdup(r, (char *)namebuf);
+ if (!r->name) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "out of memory");
+
+ if (namebuf_len > 17) {
+ r->scope = talloc_strndup(r, (char *)(namebuf+16), namebuf_len-17);
+ if (!r->scope) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "out of memory");
+ } else {
+ r->scope = NULL;
+ }
+
+ talloc_free(namebuf);
+ *_r = r;
+ return NDR_ERR_SUCCESS;
+}
+
+/**
+ push a nbt name, WINS Replication uses another on wire format for nbt name
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_wrepl_nbt_name(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct nbt_name *r)
+{
+ uint8_t *namebuf;
+ uint32_t namebuf_len;
+ uint32_t _name_len;
+ uint32_t scope_len = 0;
+
+ if (r == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER,
+ "wrepl_nbt_name NULL pointer");
+ }
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ _name_len = strlen(r->name);
+ if (_name_len > 15) {
+ return ndr_push_error(ndr, NDR_ERR_STRING,
+ "wrepl_nbt_name longer as 15 chars: %s",
+ r->name);
+ }
+
+ if (r->scope) {
+ scope_len = strlen(r->scope);
+ }
+ if (scope_len > 238) {
+ return ndr_push_error(ndr, NDR_ERR_STRING,
+ "wrepl_nbt_name scope longer as 238 chars: %s",
+ r->scope);
+ }
+
+ namebuf = (uint8_t *)talloc_asprintf(ndr, "%-15s%c%s",
+ r->name, 'X',
+ (r->scope?r->scope:""));
+ if (!namebuf) return ndr_push_error(ndr, NDR_ERR_ALLOC, "out of memory");
+
+ namebuf_len = strlen((char *)namebuf) + 1;
+
+ /*
+ * we need to set the type here, and use a place-holder in the talloc_asprintf()
+ * as the type can be 0x00, and then the namebuf_len = strlen(namebuf); would give wrong results
+ */
+ namebuf[15] = r->type;
+
+ /* oh wow, what a nasty bug in windows ... */
+ if (r->type == 0x1b) {
+ namebuf[15] = namebuf[0];
+ namebuf[0] = 0x1b;
+ }
+
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, namebuf_len));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, namebuf, namebuf_len));
+
+ if ((namebuf_len % 4) == 0) {
+ /*
+ * [MS-WINSRA] — v20091104 was wrong
+ * regarding section "2.2.10.1 Name Record"
+ *
+ * If the name buffer is already 4 byte aligned
+ * Windows (at least 2003 SP1 and 2008) add 4 extra
+ * bytes. This can happen when the name has a scope.
+ */
+ NDR_CHECK(ndr_push_zero(ndr, 4));
+ }
+
+ talloc_free(namebuf);
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wrepl_nbt_name(struct ndr_print *ndr, const char *name, const struct nbt_name *r)
+{
+ char *s = nbt_name_string(ndr, r);
+ ndr_print_string(ndr, name, s);
+ talloc_free(s);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_qtype(struct ndr_push *ndr, ndr_flags_type ndr_flags, enum nbt_qtype r)
+{
+ /* For WACK replies, we need to send NBT_QTYPE_NETBIOS on the wire. */
+ NDR_CHECK(ndr_push_enum_uint16(ndr, NDR_SCALARS, (r == NBT_QTYPE_WACK) ? NBT_QTYPE_NETBIOS : r));
+ return NDR_ERR_SUCCESS;
+}
diff --git a/libcli/nbt/nbtsocket.c b/libcli/nbt/nbtsocket.c
new file mode 100644
index 0000000..47e73cf
--- /dev/null
+++ b/libcli/nbt/nbtsocket.c
@@ -0,0 +1,566 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ low level socket handling for nbt requests
+
+ Copyright (C) Andrew Tridgell 2005
+
+ 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 "lib/events/events.h"
+#include "../lib/util/dlinklist.h"
+#include "../libcli/nbt/libnbt.h"
+#include "../libcli/nbt/nbt_proto.h"
+#include "lib/socket/socket.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
+#include "param/param.h"
+#include "lib/util/idtree_random.h"
+
+#define NBT_MAX_REPLIES 1000
+
+/*
+ destroy a pending request
+*/
+static int nbt_name_request_destructor(struct nbt_name_request *req)
+{
+ if (req->state == NBT_REQUEST_SEND) {
+ DLIST_REMOVE(req->nbtsock->send_queue, req);
+ }
+ if (req->state == NBT_REQUEST_WAIT) {
+ req->nbtsock->num_pending--;
+ }
+ if (req->name_trn_id != 0 && !req->is_reply) {
+ idr_remove(req->nbtsock->idr, req->name_trn_id);
+ req->name_trn_id = 0;
+ }
+ TALLOC_FREE(req->te);
+ if (req->nbtsock->send_queue == NULL) {
+ TEVENT_FD_NOT_WRITEABLE(req->nbtsock->fde);
+ }
+ if (req->nbtsock->num_pending == 0 &&
+ req->nbtsock->incoming.handler == NULL) {
+ TEVENT_FD_NOT_READABLE(req->nbtsock->fde);
+ }
+ return 0;
+}
+
+
+/*
+ handle send events on a nbt name socket
+*/
+static void nbt_name_socket_send(struct nbt_name_socket *nbtsock)
+{
+ struct nbt_name_request *req;
+ TALLOC_CTX *tmp_ctx = talloc_new(nbtsock);
+ NTSTATUS status;
+
+ while ((req = nbtsock->send_queue)) {
+ size_t len;
+
+ len = req->encoded.length;
+ status = socket_sendto(nbtsock->sock, &req->encoded, &len,
+ req->dest);
+ if (NT_STATUS_IS_ERR(status)) goto failed;
+
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ DLIST_REMOVE(nbtsock->send_queue, req);
+ req->state = NBT_REQUEST_WAIT;
+ if (req->is_reply) {
+ talloc_free(req);
+ } else {
+ TEVENT_FD_READABLE(nbtsock->fde);
+ nbtsock->num_pending++;
+ }
+ }
+
+ TEVENT_FD_NOT_WRITEABLE(nbtsock->fde);
+ talloc_free(tmp_ctx);
+ return;
+
+failed:
+ DLIST_REMOVE(nbtsock->send_queue, req);
+ nbt_name_request_destructor(req);
+ req->status = status;
+ req->state = NBT_REQUEST_ERROR;
+ talloc_free(tmp_ctx);
+ if (req->async.fn) {
+ req->async.fn(req);
+ } else if (req->is_reply) {
+ talloc_free(req);
+ }
+ return;
+}
+
+
+/*
+ handle a request timeout
+*/
+static void nbt_name_socket_timeout(struct tevent_context *ev, struct tevent_timer *te,
+ struct timeval t, void *private_data)
+{
+ struct nbt_name_request *req = talloc_get_type(private_data,
+ struct nbt_name_request);
+
+ if (req->num_retries != 0) {
+ req->num_retries--;
+ req->te = tevent_add_timer(req->nbtsock->event_ctx, req,
+ timeval_add(&t, req->timeout, 0),
+ nbt_name_socket_timeout, req);
+ if (req->state != NBT_REQUEST_SEND) {
+ req->state = NBT_REQUEST_SEND;
+ DLIST_ADD_END(req->nbtsock->send_queue, req);
+ }
+ TEVENT_FD_WRITEABLE(req->nbtsock->fde);
+ return;
+ }
+
+ nbt_name_request_destructor(req);
+ if (req->num_replies == 0) {
+ req->state = NBT_REQUEST_TIMEOUT;
+ req->status = NT_STATUS_IO_TIMEOUT;
+ } else {
+ req->state = NBT_REQUEST_DONE;
+ req->status = NT_STATUS_OK;
+ }
+ if (req->async.fn) {
+ req->async.fn(req);
+ } else if (req->is_reply) {
+ talloc_free(req);
+ }
+}
+
+
+
+/**
+ handle recv events on a nbt name socket
+*/
+static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(nbtsock);
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+ struct socket_address *src;
+ DATA_BLOB blob;
+ size_t nread, dsize;
+ struct nbt_name_packet *packet;
+ struct nbt_name_request *req;
+
+ status = socket_pending(nbtsock->sock, &dsize);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ /*
+ * Given a zero length, data_blob_talloc() returns the
+ * NULL blob {NULL, 0}.
+ *
+ * We only want to error return here on a real out of memory condition
+ * (i.e. dsize != 0, so the UDP packet has data, but the return of the
+ * allocation failed, so blob.data==NULL).
+ *
+ * Given an actual zero length UDP packet having blob.data == NULL
+ * isn't an out of memory error condition, that's the defined semantics
+ * of data_blob_talloc() when asked for zero bytes.
+ *
+ * We still need to continue to do the zero-length socket_recvfrom()
+ * read in order to clear the "read pending" condition on the socket.
+ */
+ blob = data_blob_talloc(tmp_ctx, NULL, dsize);
+ if (blob.data == NULL && dsize != 0) {
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ status = socket_recvfrom(nbtsock->sock, blob.data, blob.length, &nread,
+ tmp_ctx, &src);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ packet = talloc(tmp_ctx, struct nbt_name_packet);
+ if (packet == NULL) {
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ /* parse the request */
+ ndr_err = ndr_pull_struct_blob(&blob, packet, packet,
+ (ndr_pull_flags_fn_t)ndr_pull_nbt_name_packet);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(2,("Failed to parse incoming NBT name packet - %s\n",
+ nt_errstr(status)));
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ if (DEBUGLVL(10)) {
+ DEBUG(10,("Received nbt packet of length %d from %s:%d\n",
+ (int)blob.length, src->addr, src->port));
+ NDR_PRINT_DEBUG(nbt_name_packet, packet);
+ }
+
+ /* if its not a reply then pass it off to the incoming request
+ handler, if any */
+ if (!(packet->operation & NBT_FLAG_REPLY)) {
+ if (nbtsock->incoming.handler) {
+ nbtsock->incoming.handler(nbtsock, packet, src);
+ }
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ /* find the matching request */
+ req = (struct nbt_name_request *)idr_find(nbtsock->idr,
+ packet->name_trn_id);
+ if (req == NULL) {
+ if (nbtsock->unexpected.handler) {
+ nbtsock->unexpected.handler(nbtsock, packet, src);
+ } else {
+ DEBUG(10,("Failed to match request for incoming name packet id 0x%04x on %p\n",
+ packet->name_trn_id, nbtsock));
+ }
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ talloc_steal(req, packet);
+ talloc_steal(req, src);
+ talloc_free(tmp_ctx);
+ nbt_name_socket_handle_response_packet(req, packet, src);
+}
+
+void nbt_name_socket_handle_response_packet(struct nbt_name_request *req,
+ struct nbt_name_packet *packet,
+ struct socket_address *src)
+{
+ /* if this is a WACK response, this we need to go back to waiting,
+ but perhaps increase the timeout */
+ if ((packet->operation & NBT_OPCODE) == NBT_OPCODE_WACK) {
+ uint32_t ttl;
+ if (req->received_wack || packet->ancount < 1) {
+ nbt_name_request_destructor(req);
+ req->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ req->state = NBT_REQUEST_ERROR;
+ goto done;
+ }
+ talloc_free(req->te);
+ /* we know we won't need any more retries - the server
+ has received our request */
+ req->num_retries = 0;
+ req->received_wack = true;
+ /*
+ * there is a timeout in the packet,
+ * it is 5 + 4 * num_old_addresses
+ *
+ * although w2k3 screws it up
+ * and uses num_old_addresses = 0
+ *
+ * so we better fallback to the maximum
+ * of num_old_addresses = 25 if we got
+ * a timeout of less than 9s (5 + 4*1)
+ * or more than 105s (5 + 4*25).
+ */
+ ttl = packet->answers[0].ttl;
+ if ((ttl < (5 + 4*1)) || (ttl > (5 + 4*25))) {
+ ttl = 5 + 4*25;
+ }
+ req->timeout = ttl;
+ req->te = tevent_add_timer(req->nbtsock->event_ctx, req,
+ timeval_current_ofs(req->timeout, 0),
+ nbt_name_socket_timeout, req);
+ return;
+ }
+
+
+ req->replies = talloc_realloc(req, req->replies, struct nbt_name_reply, req->num_replies+1);
+ if (req->replies == NULL) {
+ nbt_name_request_destructor(req);
+ req->state = NBT_REQUEST_ERROR;
+ req->status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ talloc_steal(req, src);
+ req->replies[req->num_replies].dest = src;
+ talloc_steal(req, packet);
+ req->replies[req->num_replies].packet = packet;
+ req->num_replies++;
+
+ /* if we don't want multiple replies then we are done */
+ if (req->allow_multiple_replies &&
+ req->num_replies < NBT_MAX_REPLIES) {
+ return;
+ }
+
+ nbt_name_request_destructor(req);
+ req->state = NBT_REQUEST_DONE;
+ req->status = NT_STATUS_OK;
+
+done:
+ if (req->async.fn) {
+ req->async.fn(req);
+ }
+}
+
+/*
+ handle fd events on a nbt_name_socket
+*/
+static void nbt_name_socket_handler(struct tevent_context *ev, struct tevent_fd *fde,
+ uint16_t flags, void *private_data)
+{
+ struct nbt_name_socket *nbtsock = talloc_get_type(private_data,
+ struct nbt_name_socket);
+ if (flags & TEVENT_FD_WRITE) {
+ nbt_name_socket_send(nbtsock);
+ }
+ if (flags & TEVENT_FD_READ) {
+ nbt_name_socket_recv(nbtsock);
+ }
+}
+
+
+/*
+ initialise a nbt_name_socket. The event_ctx is optional, if provided
+ then operations will use that event context
+*/
+_PUBLIC_ struct nbt_name_socket *nbt_name_socket_init(TALLOC_CTX *mem_ctx,
+ struct tevent_context *event_ctx)
+{
+ struct nbt_name_socket *nbtsock;
+ NTSTATUS status;
+
+ nbtsock = talloc(mem_ctx, struct nbt_name_socket);
+ if (nbtsock == NULL) goto failed;
+
+ nbtsock->event_ctx = event_ctx;
+ if (nbtsock->event_ctx == NULL) goto failed;
+
+ status = socket_create(nbtsock, "ip", SOCKET_TYPE_DGRAM,
+ &nbtsock->sock, 0);
+ if (!NT_STATUS_IS_OK(status)) goto failed;
+
+ socket_set_option(nbtsock->sock, "SO_BROADCAST", "1");
+
+ nbtsock->idr = idr_init(nbtsock);
+ if (nbtsock->idr == NULL) goto failed;
+
+ nbtsock->send_queue = NULL;
+ nbtsock->num_pending = 0;
+ nbtsock->incoming.handler = NULL;
+ nbtsock->unexpected.handler = NULL;
+
+ nbtsock->fde = tevent_add_fd(nbtsock->event_ctx, nbtsock,
+ socket_get_fd(nbtsock->sock), 0,
+ nbt_name_socket_handler, nbtsock);
+
+ return nbtsock;
+
+failed:
+ talloc_free(nbtsock);
+ return NULL;
+}
+
+/*
+ send off a nbt name request
+*/
+struct nbt_name_request *nbt_name_request_send(TALLOC_CTX *mem_ctx,
+ struct nbt_name_socket *nbtsock,
+ struct socket_address *dest,
+ struct nbt_name_packet *request,
+ int timeout, int retries,
+ bool allow_multiple_replies)
+{
+ struct nbt_name_request *req;
+ int id;
+ enum ndr_err_code ndr_err;
+
+ req = talloc_zero(mem_ctx, struct nbt_name_request);
+ if (req == NULL) goto failed;
+
+ req->nbtsock = nbtsock;
+ req->allow_multiple_replies = allow_multiple_replies;
+ req->state = NBT_REQUEST_SEND;
+ req->is_reply = false;
+ req->timeout = timeout;
+ req->num_retries = retries;
+ req->dest = socket_address_copy(req, dest);
+ if (req->dest == NULL) goto failed;
+
+ /* we select a random transaction id unless the user supplied one */
+ if (request->name_trn_id == 0) {
+ id = idr_get_new_random(
+ req->nbtsock->idr, req, 1, UINT16_MAX);
+ } else {
+ if (idr_find(req->nbtsock->idr, request->name_trn_id)) goto failed;
+ id = idr_get_new_above(req->nbtsock->idr, req, request->name_trn_id,
+ UINT16_MAX);
+ }
+ if (id == -1) goto failed;
+
+ request->name_trn_id = id;
+ req->name_trn_id = id;
+
+ req->te = tevent_add_timer(nbtsock->event_ctx, req,
+ timeval_current_ofs(req->timeout, 0),
+ nbt_name_socket_timeout, req);
+
+ talloc_set_destructor(req, nbt_name_request_destructor);
+
+ ndr_err = ndr_push_struct_blob(&req->encoded, req,
+ request,
+ (ndr_push_flags_fn_t)ndr_push_nbt_name_packet);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) goto failed;
+
+ DLIST_ADD_END(nbtsock->send_queue, req);
+
+ if (DEBUGLVL(10)) {
+ DEBUG(10,("Queueing nbt packet to %s:%d\n",
+ req->dest->addr, req->dest->port));
+ NDR_PRINT_DEBUG(nbt_name_packet, request);
+ }
+
+ TEVENT_FD_WRITEABLE(nbtsock->fde);
+
+ return req;
+
+failed:
+ talloc_free(req);
+ return NULL;
+}
+
+
+/*
+ send off a nbt name reply
+*/
+_PUBLIC_ NTSTATUS nbt_name_reply_send(struct nbt_name_socket *nbtsock,
+ struct socket_address *dest,
+ struct nbt_name_packet *request)
+{
+ struct nbt_name_request *req;
+ enum ndr_err_code ndr_err;
+
+ req = talloc_zero(nbtsock, struct nbt_name_request);
+ NT_STATUS_HAVE_NO_MEMORY(req);
+
+ req->nbtsock = nbtsock;
+ req->dest = socket_address_copy(req, dest);
+ if (req->dest == NULL) goto failed;
+ req->state = NBT_REQUEST_SEND;
+ req->is_reply = true;
+
+ talloc_set_destructor(req, nbt_name_request_destructor);
+
+ if (DEBUGLVL(10)) {
+ NDR_PRINT_DEBUG(nbt_name_packet, request);
+ }
+
+ ndr_err = ndr_push_struct_blob(&req->encoded, req,
+ request,
+ (ndr_push_flags_fn_t)ndr_push_nbt_name_packet);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(req);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ DLIST_ADD_END(nbtsock->send_queue, req);
+
+ TEVENT_FD_WRITEABLE(nbtsock->fde);
+
+ return NT_STATUS_OK;
+
+failed:
+ talloc_free(req);
+ return NT_STATUS_NO_MEMORY;
+}
+
+/*
+ wait for a nbt request to complete
+*/
+NTSTATUS nbt_name_request_recv(struct nbt_name_request *req)
+{
+ if (!req) return NT_STATUS_NO_MEMORY;
+
+ while (req->state < NBT_REQUEST_DONE) {
+ if (tevent_loop_once(req->nbtsock->event_ctx) != 0) {
+ req->state = NBT_REQUEST_ERROR;
+ req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+ break;
+ }
+ }
+ return req->status;
+}
+
+
+/*
+ setup a handler for incoming requests
+*/
+_PUBLIC_ NTSTATUS nbt_set_incoming_handler(struct nbt_name_socket *nbtsock,
+ void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
+ struct socket_address *),
+ void *private_data)
+{
+ nbtsock->incoming.handler = handler;
+ nbtsock->incoming.private_data = private_data;
+ TEVENT_FD_READABLE(nbtsock->fde);
+ return NT_STATUS_OK;
+}
+
+/*
+ setup a handler for unexpected requests
+*/
+NTSTATUS nbt_set_unexpected_handler(struct nbt_name_socket *nbtsock,
+ void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
+ struct socket_address *),
+ void *private_data)
+{
+ nbtsock->unexpected.handler = handler;
+ nbtsock->unexpected.private_data = private_data;
+ TEVENT_FD_READABLE(nbtsock->fde);
+ return NT_STATUS_OK;
+}
+
+/*
+ turn a NBT rcode into a NTSTATUS
+*/
+_PUBLIC_ NTSTATUS nbt_rcode_to_ntstatus(uint8_t rcode)
+{
+ size_t i;
+ struct {
+ enum nbt_rcode rcode;
+ NTSTATUS status;
+ } map[] = {
+ { NBT_RCODE_FMT, NT_STATUS_INVALID_PARAMETER },
+ { NBT_RCODE_SVR, NT_STATUS_SERVER_DISABLED },
+ { NBT_RCODE_NAM, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { NBT_RCODE_IMP, NT_STATUS_NOT_SUPPORTED },
+ { NBT_RCODE_RFS, NT_STATUS_ACCESS_DENIED },
+ { NBT_RCODE_ACT, NT_STATUS_ADDRESS_ALREADY_EXISTS },
+ { NBT_RCODE_CFT, NT_STATUS_CONFLICTING_ADDRESSES }
+ };
+ for (i=0;i<ARRAY_SIZE(map);i++) {
+ if (map[i].rcode == rcode) {
+ return map[i].status;
+ }
+ }
+ return NT_STATUS_UNSUCCESSFUL;
+}
diff --git a/libcli/nbt/pynbt.c b/libcli/nbt/pynbt.c
new file mode 100644
index 0000000..e0a72fa
--- /dev/null
+++ b/libcli/nbt/pynbt.c
@@ -0,0 +1,447 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright © Jelmer Vernooij <jelmer@samba.org> 2008
+
+ 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 "lib/replace/system/python.h"
+#include "includes.h"
+#include "python/py3compat.h"
+#include "libcli/util/pyerrors.h"
+#include "python/modules.h"
+#include "../libcli/nbt/libnbt.h"
+#include "lib/events/events.h"
+
+void initnetbios(void);
+
+extern PyTypeObject nbt_node_Type;
+
+typedef struct {
+ PyObject_HEAD
+ TALLOC_CTX *mem_ctx;
+ struct nbt_name_socket *socket;
+} nbt_node_Object;
+
+static void py_nbt_node_dealloc(nbt_node_Object *self)
+{
+ talloc_free(self->mem_ctx);
+ Py_TYPE(self)->tp_free(self);
+}
+
+static PyObject *py_nbt_node_init(PyTypeObject *self, PyObject *args, PyObject *kwargs)
+{
+ struct tevent_context *ev;
+ nbt_node_Object *ret = PyObject_New(nbt_node_Object, &nbt_node_Type);
+
+ ret->mem_ctx = talloc_new(NULL);
+ if (ret->mem_ctx == NULL)
+ return NULL;
+
+ ev = s4_event_context_init(ret->mem_ctx);
+ ret->socket = nbt_name_socket_init(ret->mem_ctx, ev);
+ return (PyObject *)ret;
+}
+
+static bool PyObject_AsDestinationTuple(PyObject *obj, const char **dest_addr, uint16_t *dest_port)
+{
+ if (PyUnicode_Check(obj)) {
+ *dest_addr = PyUnicode_AsUTF8(obj);
+ *dest_port = NBT_NAME_SERVICE_PORT;
+ return true;
+ }
+
+ if (PyTuple_Check(obj)) {
+ if (PyTuple_Size(obj) < 1) {
+ PyErr_SetString(PyExc_TypeError, "Destination tuple size invalid");
+ return false;
+ }
+
+ if (!PyUnicode_Check(PyTuple_GetItem(obj, 0))) {
+ PyErr_SetString(PyExc_TypeError, "Destination tuple first element not string");
+ return false;
+ }
+
+ *dest_addr = PyUnicode_AsUTF8(obj);
+
+ if (PyTuple_Size(obj) == 1) {
+ *dest_port = NBT_NAME_SERVICE_PORT;
+ return true;
+ } else if (PyLong_Check(PyTuple_GetItem(obj, 1))) {
+ *dest_port = PyLong_AsLong(PyTuple_GetItem(obj, 1));
+ return true;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "Destination tuple second element not a port");
+ return false;
+ }
+ }
+
+ PyErr_SetString(PyExc_TypeError, "Destination tuple second element not a port");
+ return false;
+}
+
+static bool PyObject_AsNBTName(PyObject *obj, struct nbt_name_socket *name_socket, struct nbt_name *name)
+{
+ if (PyTuple_Check(obj)) {
+ if (PyTuple_Size(obj) == 2) {
+ name->name = PyUnicode_AsUTF8(PyTuple_GetItem(obj, 0));
+ if (name->name == NULL) {
+ goto err;
+ }
+ name->type = PyLong_AsLong(PyTuple_GetItem(obj, 1));
+ if (name->type == -1 && PyErr_Occurred()) {
+ goto err;
+ }
+ name->scope = NULL;
+ return true;
+ } else if (PyTuple_Size(obj) == 3) {
+ name->name = PyUnicode_AsUTF8(PyTuple_GetItem(obj, 0));
+ if (name->name == NULL) {
+ goto err;
+ }
+ name->scope = PyUnicode_AsUTF8(PyTuple_GetItem(obj, 1));
+ if (name->scope == NULL) {
+ goto err;
+ }
+ name->type = PyLong_AsLong(PyTuple_GetItem(obj, 2));
+ if (name->type == -1 && PyErr_Occurred()) {
+ goto err;
+ }
+ return true;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "Invalid tuple size");
+ return false;
+ }
+ }
+
+ if (PyUnicode_Check(obj)) {
+ /* FIXME: Parse string to be able to interpret things like RHONWYN<02> ? */
+ name->name = PyUnicode_AsUTF8(obj);
+ if (name->name == NULL) {
+ goto err;
+ }
+ name->scope = NULL;
+ name->type = 0;
+ return true;
+ }
+err:
+ PyErr_SetString(PyExc_TypeError, "Invalid type for object");
+ return false;
+}
+
+static PyObject *PyObject_FromNBTName(struct nbt_name_socket *name_socket,
+ struct nbt_name *name)
+{
+ if (name->scope) {
+ return Py_BuildValue("(ssi)", name->name, name->scope, name->type);
+ } else {
+ return Py_BuildValue("(si)", name->name, name->type);
+ }
+}
+
+static PyObject *py_nbt_name_query(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ nbt_node_Object *node = (nbt_node_Object *)self;
+ PyObject *ret, *reply_addrs, *py_dest, *py_name;
+ struct nbt_name_query io;
+ NTSTATUS status;
+ int i;
+
+ const char *kwnames[] = { "name", "dest", "broadcast", "wins", "timeout",
+ "retries", NULL };
+ io.in.broadcast = true;
+ io.in.wins_lookup = false;
+ io.in.timeout = 0;
+ io.in.retries = 3;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|bbii:query_name",
+ discard_const_p(char *, kwnames),
+ &py_name, &py_dest,
+ &io.in.broadcast, &io.in.wins_lookup,
+ &io.in.timeout, &io.in.retries)) {
+ return NULL;
+ }
+
+ if (!PyObject_AsDestinationTuple(py_dest, &io.in.dest_addr, &io.in.dest_port))
+ return NULL;
+
+ if (!PyObject_AsNBTName(py_name, node->socket, &io.in.name))
+ return NULL;
+
+ status = nbt_name_query(node->socket, NULL, &io);
+
+ if (NT_STATUS_IS_ERR(status)) {
+ PyErr_SetNTSTATUS(status);
+ return NULL;
+ }
+
+ ret = PyTuple_New(3);
+ if (ret == NULL)
+ return NULL;
+ PyTuple_SetItem(ret, 0, PyUnicode_FromString(io.out.reply_from));
+
+ py_name = PyObject_FromNBTName(node->socket, &io.out.name);
+ if (py_name == NULL)
+ return NULL;
+
+ PyTuple_SetItem(ret, 1, py_name);
+
+ reply_addrs = PyList_New(io.out.num_addrs);
+ if (reply_addrs == NULL) {
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+ for (i = 0; i < io.out.num_addrs; i++) {
+ PyList_SetItem(reply_addrs, i, PyUnicode_FromString(io.out.reply_addrs[i]));
+ }
+
+ PyTuple_SetItem(ret, 2, reply_addrs);
+ return ret;
+}
+
+static PyObject *py_nbt_name_status(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ nbt_node_Object *node = (nbt_node_Object *)self;
+ PyObject *ret, *py_dest, *py_name, *py_names;
+ struct nbt_name_status io;
+ int i;
+ NTSTATUS status;
+
+ const char *kwnames[] = { "name", "dest", "timeout", "retries", NULL };
+
+ io.in.timeout = 0;
+ io.in.retries = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|ii:name_status",
+ discard_const_p(char *, kwnames),
+ &py_name, &py_dest,
+ &io.in.timeout, &io.in.retries)) {
+ return NULL;
+ }
+
+ if (!PyObject_AsDestinationTuple(py_dest, &io.in.dest_addr, &io.in.dest_port))
+ return NULL;
+
+ if (!PyObject_AsNBTName(py_name, node->socket, &io.in.name))
+ return NULL;
+
+ status = nbt_name_status(node->socket, NULL, &io);
+
+ if (NT_STATUS_IS_ERR(status)) {
+ PyErr_SetNTSTATUS(status);
+ return NULL;
+ }
+
+ ret = PyTuple_New(3);
+ if (ret == NULL)
+ return NULL;
+ PyTuple_SetItem(ret, 0, PyUnicode_FromString(io.out.reply_from));
+
+ py_name = PyObject_FromNBTName(node->socket, &io.out.name);
+ if (py_name == NULL)
+ return NULL;
+
+ PyTuple_SetItem(ret, 1, py_name);
+
+ py_names = PyList_New(io.out.status.num_names);
+
+ for (i = 0; i < io.out.status.num_names; i++) {
+ PyList_SetItem(py_names, i, Py_BuildValue("(sii)",
+ io.out.status.names[i].name,
+ io.out.status.names[i].nb_flags,
+ io.out.status.names[i].type));
+ }
+
+ PyTuple_SetItem(ret, 2, py_names);
+
+ return ret;
+}
+
+static PyObject *py_nbt_name_register(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ nbt_node_Object *node = (nbt_node_Object *)self;
+ PyObject *ret, *py_dest, *py_name;
+ struct nbt_name_register io;
+ NTSTATUS status;
+
+ const char *kwnames[] = { "name", "address", "dest", "register_demand", "broadcast",
+ "multi_homed", "ttl", "timeout", "retries", NULL };
+
+ io.in.broadcast = true;
+ io.in.multi_homed = true;
+ io.in.register_demand = true;
+ io.in.ttl = 0;
+ io.in.timeout = 0;
+ io.in.retries = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OsO|bbbiii:query_name",
+ discard_const_p(char *, kwnames),
+ &py_name, &io.in.address, &py_dest,
+ &io.in.register_demand,
+ &io.in.broadcast, &io.in.multi_homed,
+ &io.in.ttl, &io.in.timeout, &io.in.retries)) {
+ return NULL;
+ }
+
+ if (!PyObject_AsDestinationTuple(py_dest, &io.in.dest_addr, &io.in.dest_port))
+ return NULL;
+
+ if (!PyObject_AsNBTName(py_name, node->socket, &io.in.name))
+ return NULL;
+
+ status = nbt_name_register(node->socket, NULL, &io);
+
+ if (NT_STATUS_IS_ERR(status)) {
+ PyErr_SetNTSTATUS(status);
+ return NULL;
+ }
+
+ ret = PyTuple_New(4);
+ if (ret == NULL)
+ return NULL;
+ PyTuple_SetItem(ret, 0, PyUnicode_FromString(io.out.reply_from));
+
+ py_name = PyObject_FromNBTName(node->socket, &io.out.name);
+ if (py_name == NULL)
+ return NULL;
+
+ PyTuple_SetItem(ret, 1, py_name);
+
+ PyTuple_SetItem(ret, 2, PyUnicode_FromString(io.out.reply_addr));
+
+ PyTuple_SetItem(ret, 3, PyLong_FromLong(io.out.rcode));
+
+ return ret;
+}
+
+static PyObject *py_nbt_name_refresh(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ nbt_node_Object *node = (nbt_node_Object *)self;
+ PyObject *ret, *py_dest, *py_name;
+ struct nbt_name_refresh io;
+ NTSTATUS status;
+
+ const char *kwnames[] = { "name", "address", "dest", "nb_flags", "broadcast",
+ "ttl", "timeout", "retries", NULL };
+
+ io.in.broadcast = true;
+ io.in.nb_flags = 0;
+ io.in.ttl = 0;
+ io.in.timeout = 0;
+ io.in.retries = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OsO|ibiii:query_name",
+ discard_const_p(char *, kwnames),
+ &py_name, &io.in.address, &py_dest,
+ &io.in.nb_flags,
+ &io.in.broadcast,
+ &io.in.ttl, &io.in.timeout, &io.in.retries)) {
+ return NULL;
+ }
+
+ if (!PyObject_AsDestinationTuple(py_dest, &io.in.dest_addr, &io.in.dest_port))
+ return NULL;
+
+ if (!PyObject_AsNBTName(py_name, node->socket, &io.in.name))
+ return NULL;
+
+ status = nbt_name_refresh(node->socket, NULL, &io);
+
+ if (NT_STATUS_IS_ERR(status)) {
+ PyErr_SetNTSTATUS(status);
+ return NULL;
+ }
+
+ ret = PyTuple_New(3);
+ if (ret == NULL)
+ return NULL;
+ PyTuple_SetItem(ret, 0, PyUnicode_FromString(io.out.reply_from));
+
+ py_name = PyObject_FromNBTName(node->socket, &io.out.name);
+ if (py_name == NULL)
+ return NULL;
+
+ PyTuple_SetItem(ret, 1, py_name);
+
+ PyTuple_SetItem(ret, 2, PyUnicode_FromString(io.out.reply_addr));
+
+ PyTuple_SetItem(ret, 3, PyLong_FromLong(io.out.rcode));
+
+ return ret;
+}
+
+static PyObject *py_nbt_name_release(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ Py_RETURN_NONE; /* FIXME */
+}
+
+static PyMethodDef py_nbt_methods[] = {
+ { "query_name", PY_DISCARD_FUNC_SIG(PyCFunction, py_nbt_name_query),
+ METH_VARARGS|METH_KEYWORDS,
+ "S.query_name(name, dest, broadcast=True, wins=False, timeout=0, retries=3) -> (reply_from, name, reply_addr)\n"
+ "Query for a NetBIOS name" },
+ { "register_name", PY_DISCARD_FUNC_SIG(PyCFunction,
+ py_nbt_name_register),
+ METH_VARARGS|METH_KEYWORDS,
+ "S.register_name(name, address, dest, register_demand=True, broadcast=True, multi_homed=True, ttl=0, timeout=0, retries=0) -> (reply_from, name, reply_addr, rcode)\n"
+ "Register a new name" },
+ { "release_name", PY_DISCARD_FUNC_SIG(PyCFunction, py_nbt_name_release),
+ METH_VARARGS|METH_KEYWORDS, "S.release_name(name, address, dest, nb_flags=0, broadcast=true, timeout=0, retries=3) -> (reply_from, name, reply_addr, rcode)\n"
+ "release a previously registered name" },
+ { "refresh_name", PY_DISCARD_FUNC_SIG(PyCFunction, py_nbt_name_refresh),
+ METH_VARARGS|METH_KEYWORDS, "S.refresh_name(name, address, dest, nb_flags=0, broadcast=True, ttl=0, timeout=0, retries=0) -> (reply_from, name, reply_addr, rcode)\n"
+ "release a previously registered name" },
+ { "name_status", PY_DISCARD_FUNC_SIG(PyCFunction, py_nbt_name_status),
+ METH_VARARGS|METH_KEYWORDS,
+ "S.name_status(name, dest, timeout=0, retries=0) -> (reply_from, name, status)\n"
+ "Find the status of a name" },
+
+ {0}
+};
+
+PyTypeObject nbt_node_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "netbios.Node",
+ .tp_basicsize = sizeof(nbt_node_Object),
+ .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+ .tp_new = py_nbt_node_init,
+ .tp_dealloc = (destructor)py_nbt_node_dealloc,
+ .tp_methods = py_nbt_methods,
+ .tp_doc = "Node()\n"
+ "Create a new NetBIOS node\n"
+};
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "netbios",
+ .m_doc = "NetBIOS over TCP/IP support",
+ .m_size = -1,
+ .m_methods = NULL,
+};
+
+MODULE_INIT_FUNC(netbios)
+{
+ PyObject *mod = NULL;
+ if (PyType_Ready(&nbt_node_Type) < 0)
+ return mod;
+
+ mod = PyModule_Create(&moduledef);
+
+
+ Py_INCREF((PyObject *)&nbt_node_Type);
+ PyModule_AddObject(mod, "Node", (PyObject *)&nbt_node_Type);
+ return mod;
+}
diff --git a/libcli/nbt/tools/nmblookup.c b/libcli/nbt/tools/nmblookup.c
new file mode 100644
index 0000000..6ca38fa
--- /dev/null
+++ b/libcli/nbt/tools/nmblookup.c
@@ -0,0 +1,477 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ NBT client - used to lookup netbios names
+
+ Copyright (C) Andrew Tridgell 1994-2005
+ Copyright (C) Jelmer Vernooij 2003 (Conversion to popt)
+
+ 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 "lib/cmdline/cmdline.h"
+#include "lib/socket/socket.h"
+#include "lib/events/events.h"
+#include "system/network.h"
+#include "system/locale.h"
+#include "lib/socket/netif.h"
+#include "librpc/gen_ndr/nbt.h"
+#include "../libcli/nbt/libnbt.h"
+#include "param/param.h"
+
+#include <string.h>
+
+#define MAX_NETBIOSNAME_LEN 16
+
+/* command line options */
+static struct {
+ const char *broadcast_address;
+ const char *unicast_address;
+ bool find_master;
+ bool wins_lookup;
+ bool node_status;
+ bool root_port;
+ bool lookup_by_ip;
+ bool case_sensitive;
+} options;
+
+/*
+ clean any binary from a node name
+*/
+static const char *clean_name(TALLOC_CTX *mem_ctx, const char *name)
+{
+ char *ret = talloc_strdup(mem_ctx, name);
+ int i;
+ for (i=0;ret[i];i++) {
+ if (!isprint((unsigned char)ret[i])) ret[i] = '.';
+ }
+ return ret;
+}
+
+/*
+ turn a node status flags field into a string
+*/
+static char *node_status_flags(TALLOC_CTX *mem_ctx, uint16_t flags)
+{
+ char *ret;
+ const char *group = " ";
+ const char *type = "B";
+
+ if (flags & NBT_NM_GROUP) {
+ group = "<GROUP>";
+ }
+
+ switch (flags & NBT_NM_OWNER_TYPE) {
+ case NBT_NODE_B:
+ type = "B";
+ break;
+ case NBT_NODE_P:
+ type = "P";
+ break;
+ case NBT_NODE_M:
+ type = "M";
+ break;
+ case NBT_NODE_H:
+ type = "H";
+ break;
+ }
+
+ ret = talloc_asprintf(mem_ctx, "%s %s", group, type);
+
+ if (flags & NBT_NM_DEREGISTER) {
+ ret = talloc_asprintf_append_buffer(ret, " <DEREGISTERING>");
+ }
+ if (flags & NBT_NM_CONFLICT) {
+ ret = talloc_asprintf_append_buffer(ret, " <CONFLICT>");
+ }
+ if (flags & NBT_NM_ACTIVE) {
+ ret = talloc_asprintf_append_buffer(ret, " <ACTIVE>");
+ }
+ if (flags & NBT_NM_PERMANENT) {
+ ret = talloc_asprintf_append_buffer(ret, " <PERMANENT>");
+ }
+
+ return ret;
+}
+
+/* do a single node status */
+static bool do_node_status(struct nbt_name_socket *nbtsock,
+ const char *addr, uint16_t port)
+{
+ struct nbt_name_status io;
+ NTSTATUS status;
+
+ io.in.name.name = "*";
+ io.in.name.type = NBT_NAME_CLIENT;
+ io.in.name.scope = NULL;
+ io.in.dest_addr = addr;
+ io.in.dest_port = port;
+ io.in.timeout = 1;
+ io.in.retries = 2;
+
+ status = nbt_name_status(nbtsock, nbtsock, &io);
+ if (NT_STATUS_IS_OK(status)) {
+ int i;
+ printf("Node status reply from %s\n",
+ io.out.reply_from);
+ for (i=0;i<io.out.status.num_names;i++) {
+ d_printf("\t%-16s <%02x> %s\n",
+ clean_name(nbtsock, io.out.status.names[i].name),
+ io.out.status.names[i].type,
+ node_status_flags(nbtsock, io.out.status.names[i].nb_flags));
+ }
+ printf("\n\tMAC Address = %02X-%02X-%02X-%02X-%02X-%02X\n",
+ io.out.status.statistics.unit_id[0],
+ io.out.status.statistics.unit_id[1],
+ io.out.status.statistics.unit_id[2],
+ io.out.status.statistics.unit_id[3],
+ io.out.status.statistics.unit_id[4],
+ io.out.status.statistics.unit_id[5]);
+ return true;
+ }
+
+ return false;
+}
+
+/* do a single node query */
+static NTSTATUS do_node_query(struct nbt_name_socket *nbtsock,
+ const char *addr,
+ uint16_t port,
+ const char *node_name,
+ enum nbt_name_type node_type,
+ bool broadcast)
+{
+ struct nbt_name_query io;
+ NTSTATUS status;
+ int i;
+
+ io.in.name.name = node_name;
+ io.in.name.type = node_type;
+ io.in.name.scope = NULL;
+ io.in.dest_addr = addr;
+ io.in.dest_port = port;
+ io.in.broadcast = broadcast;
+ io.in.wins_lookup = options.wins_lookup;
+ io.in.timeout = 1;
+ io.in.retries = 2;
+
+ status = nbt_name_query(nbtsock, nbtsock, &io);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ for (i=0;i<io.out.num_addrs;i++) {
+ printf("%s %s<%02x>\n",
+ io.out.reply_addrs[i],
+ io.out.name.name,
+ io.out.name.type);
+ }
+ if (options.node_status && io.out.num_addrs > 0) {
+ do_node_status(nbtsock, io.out.reply_addrs[0], port);
+ }
+
+ return status;
+}
+
+
+static bool process_one(struct loadparm_context *lp_ctx, struct tevent_context *ev,
+ struct interface *ifaces, const char *name, int nbt_port)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ enum nbt_name_type node_type = NBT_NAME_CLIENT;
+ char *node_name, *p;
+ struct socket_address *all_zero_addr;
+ struct nbt_name_socket *nbtsock;
+ NTSTATUS status = NT_STATUS_OK;
+ size_t nbt_len;
+ bool ret = true;
+
+ if (!options.case_sensitive) {
+ name = strupper_talloc(tmp_ctx, name);
+ }
+
+ if (options.find_master) {
+ node_type = NBT_NAME_MASTER;
+ if (*name == '-' || *name == '_') {
+ name = "\01\02__MSBROWSE__\02";
+ node_type = NBT_NAME_MS;
+ }
+ }
+
+ p = strchr(name, '#');
+ if (p) {
+ node_name = talloc_strndup(tmp_ctx, name, PTR_DIFF(p,name));
+ node_type = (enum nbt_name_type)strtol(p+1, NULL, 16);
+ } else {
+ node_name = talloc_strdup(tmp_ctx, name);
+ }
+
+ nbt_len = strlen(node_name);
+ if (nbt_len > MAX_NETBIOSNAME_LEN - 1) {
+ printf("The specified netbios name [%s] is too long.\n",
+ node_name);
+ talloc_free(tmp_ctx);
+ return false;
+ }
+
+ nbtsock = nbt_name_socket_init(tmp_ctx, ev);
+
+ if (options.root_port) {
+ all_zero_addr = socket_address_from_strings(tmp_ctx, nbtsock->sock->backend_name,
+ "0.0.0.0", NBT_NAME_SERVICE_PORT);
+
+ if (!all_zero_addr) {
+ talloc_free(tmp_ctx);
+ return false;
+ }
+
+ status = socket_listen(nbtsock->sock, all_zero_addr, 0, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to bind to local port 137 - %s\n", nt_errstr(status));
+ talloc_free(tmp_ctx);
+ return false;
+ }
+ }
+
+ if (options.lookup_by_ip) {
+ ret = do_node_status(nbtsock, name, nbt_port);
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ if (options.broadcast_address) {
+ status = do_node_query(nbtsock, options.broadcast_address, nbt_port,
+ node_name, node_type, true);
+ } else if (options.unicast_address) {
+ status = do_node_query(nbtsock, options.unicast_address,
+ nbt_port, node_name, node_type, false);
+ } else {
+ int i, num_interfaces;
+
+ num_interfaces = iface_list_count(ifaces);
+ for (i=0;i<num_interfaces;i++) {
+ const char *bcast = iface_list_n_bcast(ifaces, i);
+ if (bcast == NULL) continue;
+ status = do_node_query(nbtsock, bcast, nbt_port,
+ node_name, node_type, true);
+ if (NT_STATUS_IS_OK(status)) break;
+ }
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Lookup failed - %s\n", nt_errstr(status));
+ ret = false;
+ }
+
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+/*
+ main program
+*/
+int main(int argc, const char *argv[])
+{
+ bool ret = true;
+ struct interface *ifaces;
+ struct tevent_context *ev;
+ poptContext pc;
+ int opt;
+ struct loadparm_context *lp_ctx = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+ bool ok;
+ enum {
+ OPT_BROADCAST_ADDRESS = 1000,
+ OPT_UNICAST_ADDRESS,
+ OPT_FIND_MASTER,
+ OPT_WINS_LOOKUP,
+ OPT_NODE_STATUS,
+ OPT_ROOT_PORT,
+ OPT_LOOKUP_BY_IP,
+ OPT_CASE_SENSITIVE
+ };
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {
+ .longName = "broadcast",
+ .shortName = 'B',
+ .argInfo = POPT_ARG_STRING,
+ .arg = NULL,
+ .val = OPT_BROADCAST_ADDRESS,
+ .descrip = "Specify address to use for broadcasts",
+ .argDescrip = "BROADCAST-ADDRESS"
+ },
+ {
+ .longName = "unicast",
+ .shortName = 'U',
+ .argInfo = POPT_ARG_STRING,
+ .arg = NULL,
+ .val = OPT_UNICAST_ADDRESS,
+ .descrip = "Specify address to use for unicast",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "master-browser",
+ .shortName = 'M',
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = OPT_FIND_MASTER,
+ .descrip = "Search for a master browser",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "wins",
+ .shortName = 'W',
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = OPT_WINS_LOOKUP,
+ .descrip = "Do a WINS lookup",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "status",
+ .shortName = 'S',
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = OPT_NODE_STATUS,
+ .descrip = "Lookup node status as well",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "root-port",
+ .shortName = 'r',
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = OPT_ROOT_PORT,
+ .descrip = "Use root port 137 (Win95 only replies to this)",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "lookup-by-ip",
+ .shortName = 'A',
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = OPT_LOOKUP_BY_IP,
+ .descrip = "Do a node status on <name> as an IP Address",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "case-sensitive",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = OPT_CASE_SENSITIVE,
+ .descrip = "Don't uppercase the name before sending",
+ .argDescrip = NULL
+ },
+ POPT_COMMON_SAMBA
+ POPT_COMMON_VERSION
+ POPT_TABLEEND
+ };
+
+ mem_ctx = talloc_init("nmblookup.c/main");
+ if (mem_ctx == NULL) {
+ exit(ENOMEM);
+ }
+
+ ok = samba_cmdline_init(mem_ctx,
+ SAMBA_CMDLINE_CONFIG_CLIENT,
+ false /* require_smbconf */);
+ if (!ok) {
+ DBG_ERR("Failed to init cmdline parser!\n");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ pc = samba_popt_get_context(getprogname(),
+ argc,
+ argv,
+ long_options,
+ POPT_CONTEXT_KEEP_FIRST);
+ if (pc == NULL) {
+ DBG_ERR("Failed to setup popt context!\n");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ poptSetOtherOptionHelp(pc, "<NODE> ...");
+
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch(opt) {
+ case OPT_BROADCAST_ADDRESS:
+ options.broadcast_address = poptGetOptArg(pc);
+ break;
+ case OPT_UNICAST_ADDRESS:
+ options.unicast_address = poptGetOptArg(pc);
+ break;
+ case OPT_FIND_MASTER:
+ options.find_master = true;
+ break;
+ case OPT_WINS_LOOKUP:
+ options.wins_lookup = true;
+ break;
+ case OPT_NODE_STATUS:
+ options.node_status = true;
+ break;
+ case OPT_ROOT_PORT:
+ options.root_port = true;
+ break;
+ case OPT_LOOKUP_BY_IP:
+ options.lookup_by_ip = true;
+ break;
+ case OPT_CASE_SENSITIVE:
+ options.case_sensitive = true;
+ break;
+ case POPT_ERROR_BADOPT:
+ fprintf(stderr, "\nInvalid option %s: %s\n\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ poptPrintUsage(pc, stderr, 0);
+ exit(1);
+ }
+ }
+
+ /* swallow argv[0] */
+ poptGetArg(pc);
+
+ if(!poptPeekArg(pc)) {
+ poptPrintUsage(pc, stderr, 0);
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ lp_ctx = samba_cmdline_get_lp_ctx();
+
+ load_interface_list(mem_ctx, lp_ctx, &ifaces);
+
+ ev = s4_event_context_init(mem_ctx);
+
+ while (poptPeekArg(pc)) {
+ const char *name = poptGetArg(pc);
+
+ ret &= process_one(lp_ctx,
+ ev,
+ ifaces,
+ name,
+ lpcfg_nbt_port(lp_ctx));
+ }
+
+ poptFreeContext(pc);
+ TALLOC_FREE(mem_ctx);
+
+ if (!ret) {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/libcli/nbt/wscript_build b/libcli/nbt/wscript_build
new file mode 100644
index 0000000..0e2a13f
--- /dev/null
+++ b/libcli/nbt/wscript_build
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+
+bld.SAMBA_SUBSYSTEM('NDR_NBT_BUF',
+ source='nbtname.c',
+ deps='talloc',
+ autoproto='nbtname.h'
+ )
+
+bld.SAMBA_SUBSYSTEM('lmhosts',
+ source='lmhosts.c',
+ deps='replace talloc'
+ )
+
+bld.SAMBA_LIBRARY('cli-nbt',
+ source='nbtsocket.c namequery.c nameregister.c namerefresh.c namerelease.c',
+ public_deps='ndr ndr_nbt tevent tevent-util NDR_SECURITY samba_socket samba-util lmhosts',
+ private_library=True
+ )
+
+bld.SAMBA_BINARY('nmblookup' + bld.env.suffix4,
+ source='tools/nmblookup.c',
+ manpages='man/nmblookup4.1',
+ deps='samba-hostconfig samba-util cli-nbt popt CMDLINE_S4 netif LIBCLI_RESOLVE',
+ install=False,
+ )
+
+bld.SAMBA_PYTHON('python_netbios',
+ source='pynbt.c',
+ public_deps='cli-nbt DYNCONFIG samba-hostconfig',
+ realname='samba/netbios.so'
+ )
+
diff --git a/libcli/netlogon/netlogon.c b/libcli/netlogon/netlogon.c
new file mode 100644
index 0000000..15e8087
--- /dev/null
+++ b/libcli/netlogon/netlogon.c
@@ -0,0 +1,285 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ CLDAP server structures
+
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008
+
+ 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 "../libcli/netlogon/netlogon.h"
+
+NTSTATUS push_netlogon_samlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
+ struct netlogon_samlogon_response *response)
+{
+ enum ndr_err_code ndr_err;
+ if (response->ntver == NETLOGON_NT_VERSION_1) {
+ ndr_err = ndr_push_struct_blob(data, mem_ctx,
+ &response->data.nt4,
+ (ndr_push_flags_fn_t)ndr_push_NETLOGON_SAM_LOGON_RESPONSE_NT40);
+ } else if (response->ntver & NETLOGON_NT_VERSION_5EX) {
+ ndr_err = ndr_push_struct_blob(data, mem_ctx,
+ &response->data.nt5_ex,
+ (ndr_push_flags_fn_t)ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags);
+ } else if (response->ntver & NETLOGON_NT_VERSION_5) {
+ ndr_err = ndr_push_struct_blob(data, mem_ctx,
+ &response->data.nt5,
+ (ndr_push_flags_fn_t)ndr_push_NETLOGON_SAM_LOGON_RESPONSE);
+ } else {
+ DEBUG(0, ("Asked to push unknown netlogon response type 0x%02x\n", response->ntver));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(2,("failed to push netlogon response of type 0x%02x\n",
+ response->ntver));
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pull_netlogon_samlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
+ struct netlogon_samlogon_response *response)
+{
+ uint32_t ntver;
+ enum ndr_err_code ndr_err;
+
+ if (data->length < 8) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ /* lmnttoken */
+ if (SVAL(data->data, data->length - 4) != 0xffff) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ /* lm20token */
+ if (SVAL(data->data, data->length - 2) != 0xffff) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ ntver = IVAL(data->data, data->length - 8);
+
+ if (ntver == NETLOGON_NT_VERSION_1) {
+ ndr_err = ndr_pull_struct_blob_all(data, mem_ctx,
+ &response->data.nt4,
+ (ndr_pull_flags_fn_t)ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_NT40);
+ response->ntver = NETLOGON_NT_VERSION_1;
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(NETLOGON_SAM_LOGON_RESPONSE_NT40,
+ &response->data.nt4);
+ }
+
+ } else if (ntver & NETLOGON_NT_VERSION_5EX) {
+ struct ndr_pull *ndr;
+ ndr = ndr_pull_init_blob(data, mem_ctx);
+ if (!ndr) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ ndr_err = ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags(
+ ndr, NDR_SCALARS|NDR_BUFFERS, &response->data.nt5_ex,
+ ntver);
+ if (ndr->offset < ndr->data_size) {
+ TALLOC_FREE(ndr);
+ /*
+ * We need to handle a bug in IPA (at least <= 4.1.2).
+ *
+ * They include the ip address information without setting
+ * NETLOGON_NT_VERSION_5EX_WITH_IP, while using
+ * ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX instead of
+ * ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags.
+ */
+ ndr_err = ndr_pull_struct_blob_all(data, mem_ctx,
+ &response->data.nt5,
+ (ndr_pull_flags_fn_t)ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_EX);
+ }
+ response->ntver = NETLOGON_NT_VERSION_5EX;
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(NETLOGON_SAM_LOGON_RESPONSE_EX,
+ &response->data.nt5_ex);
+ }
+
+ } else if (ntver & NETLOGON_NT_VERSION_5) {
+ ndr_err = ndr_pull_struct_blob_all(data, mem_ctx,
+ &response->data.nt5,
+ (ndr_pull_flags_fn_t)ndr_pull_NETLOGON_SAM_LOGON_RESPONSE);
+ response->ntver = NETLOGON_NT_VERSION_5;
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(NETLOGON_SAM_LOGON_RESPONSE,
+ &response->data.nt5);
+ }
+ } else {
+ DEBUG(2,("failed to parse netlogon response of type 0x%02x - unknown response type\n",
+ ntver));
+ dump_data(10, data->data, data->length);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(2,("failed to parse netlogon response of type 0x%02x\n",
+ ntver));
+ dump_data(10, data->data, data->length);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ return NT_STATUS_OK;
+}
+
+void map_netlogon_samlogon_response(struct netlogon_samlogon_response *response)
+{
+ struct NETLOGON_SAM_LOGON_RESPONSE_EX response_5_ex;
+ switch (response->ntver) {
+ case NETLOGON_NT_VERSION_5EX:
+ break;
+ case NETLOGON_NT_VERSION_5:
+ ZERO_STRUCT(response_5_ex);
+ response_5_ex.command = response->data.nt5.command;
+ response_5_ex.pdc_name = response->data.nt5.pdc_name;
+ response_5_ex.user_name = response->data.nt5.user_name;
+ response_5_ex.domain_name = response->data.nt5.domain_name;
+ response_5_ex.domain_uuid = response->data.nt5.domain_uuid;
+ response_5_ex.forest = response->data.nt5.forest;
+ response_5_ex.dns_domain = response->data.nt5.dns_domain;
+ response_5_ex.pdc_dns_name = response->data.nt5.pdc_dns_name;
+ response_5_ex.sockaddr.pdc_ip = response->data.nt5.pdc_ip;
+ response_5_ex.server_type = response->data.nt5.server_type;
+ response_5_ex.nt_version = response->data.nt5.nt_version;
+ response_5_ex.lmnt_token = response->data.nt5.lmnt_token;
+ response_5_ex.lm20_token = response->data.nt5.lm20_token;
+ response->ntver = NETLOGON_NT_VERSION_5EX;
+ response->data.nt5_ex = response_5_ex;
+ break;
+
+ case NETLOGON_NT_VERSION_1:
+ ZERO_STRUCT(response_5_ex);
+ response_5_ex.command = response->data.nt4.command;
+ response_5_ex.pdc_name = response->data.nt4.pdc_name;
+ response_5_ex.user_name = response->data.nt4.user_name;
+ response_5_ex.domain_name = response->data.nt4.domain_name;
+ response_5_ex.nt_version = response->data.nt4.nt_version;
+ response_5_ex.lmnt_token = response->data.nt4.lmnt_token;
+ response_5_ex.lm20_token = response->data.nt4.lm20_token;
+ response->ntver = NETLOGON_NT_VERSION_5EX;
+ response->data.nt5_ex = response_5_ex;
+ break;
+ }
+ return;
+}
+
+NTSTATUS push_nbt_netlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
+ struct nbt_netlogon_response *response)
+{
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+ switch (response->response_type) {
+ case NETLOGON_GET_PDC:
+ ndr_err = ndr_push_struct_blob(data, mem_ctx,
+ &response->data.get_pdc,
+ (ndr_push_flags_fn_t)ndr_push_nbt_netlogon_response_from_pdc);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(0,("Failed to parse netlogon packet of length %d: %s\n",
+ (int)data->length, nt_errstr(status)));
+ if (DEBUGLVL(10)) {
+ (void)file_save("netlogon.dat", data->data, data->length);
+ }
+ return status;
+ }
+ status = NT_STATUS_OK;
+ break;
+ case NETLOGON_SAMLOGON:
+ status = push_netlogon_samlogon_response(
+ data, mem_ctx,
+ &response->data.samlogon);
+ break;
+ case NETLOGON_RESPONSE2:
+ ndr_err = ndr_push_struct_blob(data, mem_ctx,
+ &response->data.response2,
+ (ndr_push_flags_fn_t)ndr_push_nbt_netlogon_response2);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ status = NT_STATUS_OK;
+ break;
+ default:
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ break;
+ }
+
+ return status;
+}
+
+
+NTSTATUS pull_nbt_netlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
+ struct nbt_netlogon_response *response)
+{
+ NTSTATUS status;
+ enum netlogon_command command;
+ enum ndr_err_code ndr_err;
+ if (data->length < 4) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ command = SVAL(data->data, 0);
+
+ switch (command) {
+ case NETLOGON_RESPONSE_FROM_PDC:
+ ndr_err = ndr_pull_struct_blob_all(data, mem_ctx,
+ &response->data.get_pdc,
+ (ndr_pull_flags_fn_t)ndr_pull_nbt_netlogon_response_from_pdc);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(0,("Failed to parse netlogon packet of length %d: %s\n",
+ (int)data->length, nt_errstr(status)));
+ if (DEBUGLVL(10)) {
+ (void)file_save("netlogon.dat", data->data, data->length);
+ }
+ return status;
+ }
+ status = NT_STATUS_OK;
+ response->response_type = NETLOGON_GET_PDC;
+ break;
+ case LOGON_RESPONSE2:
+ ndr_err = ndr_pull_struct_blob(data, mem_ctx, &response->data.response2,
+ (ndr_pull_flags_fn_t)ndr_pull_nbt_netlogon_response2);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ status = NT_STATUS_OK;
+ response->response_type = NETLOGON_RESPONSE2;
+ break;
+ case LOGON_SAM_LOGON_RESPONSE:
+ case LOGON_SAM_LOGON_PAUSE_RESPONSE:
+ case LOGON_SAM_LOGON_USER_UNKNOWN:
+ case LOGON_SAM_LOGON_RESPONSE_EX:
+ case LOGON_SAM_LOGON_PAUSE_RESPONSE_EX:
+ case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
+ status = pull_netlogon_samlogon_response(
+ data, mem_ctx,
+ &response->data.samlogon);
+ response->response_type = NETLOGON_SAMLOGON;
+ break;
+
+ /* These levels are queries, not responses */
+ case LOGON_PRIMARY_QUERY:
+ case LOGON_REQUEST:
+ case NETLOGON_ANNOUNCE_UAS:
+ case LOGON_SAM_LOGON_REQUEST:
+ default:
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ return status;
+
+}
diff --git a/libcli/netlogon/netlogon.h b/libcli/netlogon/netlogon.h
new file mode 100644
index 0000000..0bf2a4c
--- /dev/null
+++ b/libcli/netlogon/netlogon.h
@@ -0,0 +1,41 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ CLDAP server structures
+
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008
+
+ 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/>.
+*/
+
+#ifndef __LIBCLI_NETLOGON_H__
+#define __LIBCLI_NETLOGON_H__
+
+#include "librpc/gen_ndr/ndr_nbt.h"
+
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/gen_ndr/ndr_security.h"
+
+struct nbt_netlogon_response
+{
+ enum {NETLOGON_GET_PDC, NETLOGON_SAMLOGON, NETLOGON_RESPONSE2} response_type;
+ union {
+ struct nbt_netlogon_response_from_pdc get_pdc;
+ struct netlogon_samlogon_response samlogon;
+ struct nbt_netlogon_response2 response2;
+ } data;
+};
+
+#include "../libcli/netlogon/netlogon_proto.h"
+#endif /* __CLDAP_SERVER_PROTO_H__ */
diff --git a/libcli/netlogon/netlogon_proto.h b/libcli/netlogon/netlogon_proto.h
new file mode 100644
index 0000000..53c7d00
--- /dev/null
+++ b/libcli/netlogon/netlogon_proto.h
@@ -0,0 +1,28 @@
+#ifndef _____LIBCLI_NETLOGON_PROTO_H__
+#define _____LIBCLI_NETLOGON_PROTO_H__
+
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2)
+/* This file was automatically generated by mkproto.pl. DO NOT EDIT */
+
+/* this file contains prototypes for functions that are private
+ * to this subsystem or library. These functions should not be
+ * used outside this particular subsystem! */
+
+
+/* The following definitions come from ../libcli/netlogon.c */
+
+NTSTATUS push_netlogon_samlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
+ struct netlogon_samlogon_response *response);
+NTSTATUS pull_netlogon_samlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
+ struct netlogon_samlogon_response *response);
+void map_netlogon_samlogon_response(struct netlogon_samlogon_response *response);
+NTSTATUS push_nbt_netlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
+ struct nbt_netlogon_response *response);
+NTSTATUS pull_nbt_netlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
+ struct nbt_netlogon_response *response);
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2)
+
+#endif /* _____LIBCLI_NETLOGON_PROTO_H__ */
+
diff --git a/libcli/netlogon/wscript_build b/libcli/netlogon/wscript_build
new file mode 100644
index 0000000..ab49599
--- /dev/null
+++ b/libcli/netlogon/wscript_build
@@ -0,0 +1,6 @@
+#!/usr/bin/env python
+
+bld.SAMBA_SUBSYSTEM('LIBCLI_NETLOGON',
+ source='netlogon.c',
+ public_deps='samba-util ndr_nbt'
+ )
diff --git a/libcli/registry/util_reg.c b/libcli/registry/util_reg.c
new file mode 100644
index 0000000..3139fc3
--- /dev/null
+++ b/libcli/registry/util_reg.c
@@ -0,0 +1,138 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Registry helper routines
+ * Copyright (C) Volker Lendecke 2006
+ * Copyright (C) Guenther Deschner 2009
+ * Copyright (C) Jelmer Vernooij 2003-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 "../librpc/gen_ndr/ndr_misc.h"
+#include "../libcli/registry/util_reg.h"
+
+/**
+ * @file
+ * @brief Registry utility functions
+ */
+
+static const struct {
+ uint32_t id;
+ const char *name;
+} reg_value_types[] = {
+ { REG_NONE, "REG_NONE" },
+ { REG_SZ, "REG_SZ" },
+ { REG_EXPAND_SZ, "REG_EXPAND_SZ" },
+ { REG_BINARY, "REG_BINARY" },
+ { REG_DWORD, "REG_DWORD" },
+ { REG_DWORD_BIG_ENDIAN, "REG_DWORD_BIG_ENDIAN" },
+ { REG_LINK, "REG_LINK" },
+ { REG_MULTI_SZ, "REG_MULTI_SZ" },
+ { REG_RESOURCE_LIST, "REG_RESOURCE_LIST" },
+ { REG_FULL_RESOURCE_DESCRIPTOR, "REG_FULL_RESOURCE_DESCRIPTOR" },
+ { REG_RESOURCE_REQUIREMENTS_LIST, "REG_RESOURCE_REQUIREMENTS_LIST" },
+ { REG_QWORD, "REG_QWORD" },
+
+ { 0, NULL }
+};
+
+/** Return string description of registry value type */
+_PUBLIC_ const char *str_regtype(int type)
+{
+ unsigned int i;
+ for (i = 0; reg_value_types[i].name; i++) {
+ if (reg_value_types[i].id == type)
+ return reg_value_types[i].name;
+ }
+
+ return "Unknown";
+}
+
+/** Return registry value type for string description */
+_PUBLIC_ int regtype_by_string(const char *str)
+{
+ unsigned int i;
+ for (i = 0; reg_value_types[i].name; i++) {
+ if (strequal(reg_value_types[i].name, str))
+ return reg_value_types[i].id;
+ }
+
+ return -1;
+}
+
+/*******************************************************************
+ push a string in unix charset into a REG_SZ UCS2 null terminated blob
+ ********************************************************************/
+
+bool push_reg_sz(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, const char *s)
+{
+ union winreg_Data data;
+ enum ndr_err_code ndr_err;
+ data.string = s;
+ ndr_err = ndr_push_union_blob(blob, mem_ctx, &data, REG_SZ,
+ (ndr_push_flags_fn_t)ndr_push_winreg_Data);
+ return NDR_ERR_CODE_IS_SUCCESS(ndr_err);
+}
+
+/*******************************************************************
+ push a string_array in unix charset into a REG_MULTI_SZ UCS2 double-null
+ terminated blob
+ ********************************************************************/
+
+bool push_reg_multi_sz(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, const char **a)
+{
+ union winreg_Data data;
+ enum ndr_err_code ndr_err;
+ data.string_array = a;
+ ndr_err = ndr_push_union_blob(blob, mem_ctx, &data, REG_MULTI_SZ,
+ (ndr_push_flags_fn_t)ndr_push_winreg_Data);
+ return NDR_ERR_CODE_IS_SUCCESS(ndr_err);
+}
+
+/*******************************************************************
+ pull a string in unix charset out of a REG_SZ UCS2 null terminated blob
+ ********************************************************************/
+
+bool pull_reg_sz(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, const char **s)
+{
+ union winreg_Data data;
+ enum ndr_err_code ndr_err;
+ ndr_err = ndr_pull_union_blob(blob, mem_ctx, &data, REG_SZ,
+ (ndr_pull_flags_fn_t)ndr_pull_winreg_Data);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return false;
+ }
+ *s = data.string;
+ return true;
+}
+
+/*******************************************************************
+ pull a string_array in unix charset out of a REG_MULTI_SZ UCS2 double-null
+ terminated blob
+ ********************************************************************/
+
+bool pull_reg_multi_sz(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *blob, const char ***a)
+{
+ union winreg_Data data;
+ enum ndr_err_code ndr_err;
+ ndr_err = ndr_pull_union_blob(blob, mem_ctx, &data, REG_MULTI_SZ,
+ (ndr_pull_flags_fn_t)ndr_pull_winreg_Data);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return false;
+ }
+ *a = data.string_array;
+ return true;
+}
diff --git a/libcli/registry/util_reg.h b/libcli/registry/util_reg.h
new file mode 100644
index 0000000..0250b45
--- /dev/null
+++ b/libcli/registry/util_reg.h
@@ -0,0 +1,32 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Registry helper routines
+ * Copyright (C) Volker Lendecke 2006
+ * Copyright (C) Guenther Deschner 2009
+ * Copyright (C) Jelmer Vernooij 2003-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/>.
+ */
+
+#ifndef __LIBCLI_REGISTRY_UTIL_REG_H__
+#define __LIBCLI_REGISTRY_UTIL_REG_H__
+
+const char *str_regtype(int type);
+int regtype_by_string(const char *str);
+bool push_reg_sz(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, const char *s);
+bool push_reg_multi_sz(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, const char **a);
+bool pull_reg_sz(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, const char **s);
+bool pull_reg_multi_sz(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, const char ***a);
+
+#endif /* __LIBCLI_REGISTRY_UTIL_REG_H__ */
diff --git a/libcli/registry/wscript_build b/libcli/registry/wscript_build
new file mode 100644
index 0000000..ec3fdd3
--- /dev/null
+++ b/libcli/registry/wscript_build
@@ -0,0 +1,5 @@
+
+bld.SAMBA_LIBRARY('util_reg',
+ source='util_reg.c',
+ deps='ndr',
+ private_library=True)
diff --git a/libcli/samsync/decrypt.c b/libcli/samsync/decrypt.c
new file mode 100644
index 0000000..77ef932
--- /dev/null
+++ b/libcli/samsync/decrypt.c
@@ -0,0 +1,209 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Extract the user/system database from a remote SamSync server
+
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
+ Copyright (C) Guenther Deschner <gd@samba.org> 2008
+
+ 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 "../libcli/auth/libcli_auth.h"
+#include "../libcli/samsync/samsync.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "lib/crypto/gnutls_helpers.h"
+
+/**
+ * Decrypt and extract the user's passwords.
+ *
+ * The writes decrypted (no longer 'RID encrypted' or arcfour encrypted)
+ * passwords back into the structure
+ */
+
+static NTSTATUS fix_user(TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState *creds,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM *delta)
+{
+
+ uint32_t rid = delta->delta_id_union.rid;
+ struct netr_DELTA_USER *user = delta->delta_union.user;
+ struct samr_Password lm_hash;
+ struct samr_Password nt_hash;
+ int rc;
+
+ /* Note that win2000 may send us all zeros
+ * for the hashes if it doesn't
+ * think this channel is secure enough. */
+ if (user->lm_password_present) {
+ if (!all_zero(user->lmpassword.hash, 16)) {
+ rc = sam_rid_crypt(rid, user->lmpassword.hash,
+ lm_hash.hash, SAMBA_GNUTLS_DECRYPT);
+ if (rc != 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ } else {
+ memset(lm_hash.hash, '\0', sizeof(lm_hash.hash));
+ }
+ user->lmpassword = lm_hash;
+ }
+
+ if (user->nt_password_present) {
+ if (!all_zero(user->ntpassword.hash, 16)) {
+ rc = sam_rid_crypt(rid, user->ntpassword.hash,
+ nt_hash.hash, SAMBA_GNUTLS_DECRYPT);
+ if (rc != 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ } else {
+ memset(nt_hash.hash, '\0', sizeof(nt_hash.hash));
+ }
+ user->ntpassword = nt_hash;
+ }
+
+ if (user->user_private_info.SensitiveData) {
+ DATA_BLOB data;
+ struct netr_USER_KEYS keys;
+ enum ndr_err_code ndr_err;
+ NTSTATUS status;
+
+ data.data = user->user_private_info.SensitiveData;
+ data.length = user->user_private_info.DataLength;
+
+ status = netlogon_creds_arcfour_crypt(creds,
+ data.data,
+ data.length);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ user->user_private_info.SensitiveData = data.data;
+ user->user_private_info.DataLength = data.length;
+
+ ndr_err = ndr_pull_struct_blob(&data, mem_ctx, &keys,
+ (ndr_pull_flags_fn_t)ndr_pull_netr_USER_KEYS);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ dump_data(10, data.data, data.length);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ /* Note that win2000 may send us all zeros
+ * for the hashes if it doesn't
+ * think this channel is secure enough. */
+ if (keys.keys.keys2.lmpassword.length == 16) {
+ if (!all_zero(keys.keys.keys2.lmpassword.pwd.hash,
+ 16)) {
+ rc = sam_rid_crypt(rid,
+ keys.keys.keys2.lmpassword.pwd.hash,
+ lm_hash.hash, SAMBA_GNUTLS_DECRYPT);
+ if (rc != 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ } else {
+ memset(lm_hash.hash, '\0', sizeof(lm_hash.hash));
+ }
+ user->lmpassword = lm_hash;
+ user->lm_password_present = true;
+ }
+ if (keys.keys.keys2.ntpassword.length == 16) {
+ if (!all_zero(keys.keys.keys2.ntpassword.pwd.hash,
+ 16)) {
+ rc = sam_rid_crypt(rid,
+ keys.keys.keys2.ntpassword.pwd.hash,
+ nt_hash.hash, SAMBA_GNUTLS_DECRYPT);
+ if (rc != 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ } else {
+ memset(nt_hash.hash, '\0', sizeof(nt_hash.hash));
+ }
+ user->ntpassword = nt_hash;
+ user->nt_password_present = true;
+ }
+ /* TODO: rid decrypt history fields */
+ }
+ return NT_STATUS_OK;
+}
+
+/**
+ * Decrypt and extract the secrets
+ *
+ * The writes decrypted secrets back into the structure
+ */
+static NTSTATUS fix_secret(TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState *creds,
+ enum netr_SamDatabaseID database,
+ struct netr_DELTA_ENUM *delta)
+{
+ struct netr_DELTA_SECRET *secret = delta->delta_union.secret;
+ NTSTATUS status;
+
+ status = netlogon_creds_arcfour_crypt(creds,
+ secret->current_cipher.cipher_data,
+ secret->current_cipher.maxlen);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = netlogon_creds_arcfour_crypt(creds,
+ secret->old_cipher.cipher_data,
+ secret->old_cipher.maxlen);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * Fix up the delta, dealing with encryption issues so that the final
+ * callback need only do the printing or application logic
+ */
+
+NTSTATUS samsync_fix_delta(TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState *creds,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM *delta)
+{
+ NTSTATUS status = NT_STATUS_OK;
+
+ switch (delta->delta_type) {
+ case NETR_DELTA_USER:
+
+ status = fix_user(mem_ctx,
+ creds,
+ database_id,
+ delta);
+ break;
+ case NETR_DELTA_SECRET:
+
+ status = fix_secret(mem_ctx,
+ creds,
+ database_id,
+ delta);
+ break;
+ default:
+ break;
+ }
+
+ return status;
+}
+
diff --git a/libcli/samsync/samsync.h b/libcli/samsync/samsync.h
new file mode 100644
index 0000000..0cd55e4
--- /dev/null
+++ b/libcli/samsync/samsync.h
@@ -0,0 +1,36 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Extract the user/system database from a remote SamSync server
+
+ Copyright (C) Guenther Deschner <gd@samba.org> 2008
+
+ 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/>.
+*/
+
+#ifndef __SAMSYNC_SAMSYNC_H__
+#define __SAMSYNC_SAMSYNC_H__
+
+struct netlogon_creds_CredentialState;
+
+/**
+ * Fix up the delta, dealing with encryption issues so that the final
+ * callback need only do the printing or application logic
+ */
+NTSTATUS samsync_fix_delta(TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState *creds,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM *delta);
+
+#endif /* __SAMSYNC_SAMSYNC_H__ */
diff --git a/libcli/samsync/wscript_build b/libcli/samsync/wscript_build
new file mode 100644
index 0000000..767f7da
--- /dev/null
+++ b/libcli/samsync/wscript_build
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+
+
+bld.SAMBA_SUBSYSTEM('LIBCLI_SAMSYNC',
+ source='decrypt.c',
+ public_deps='LIBCLI_AUTH'
+ )
+
diff --git a/libcli/security/access_check.c b/libcli/security/access_check.c
new file mode 100644
index 0000000..e3dfe3d
--- /dev/null
+++ b/libcli/security/access_check.c
@@ -0,0 +1,958 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Gerald Carter 2005
+ Copyright (C) Volker Lendecke 2007
+ Copyright (C) Jeremy Allison 2008
+ Copyright (C) Andrew Bartlett 2010
+
+ 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 "replace.h"
+#include "lib/util/debug.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/conditional_ace.h"
+#include "libcli/security/conditional_ace.h"
+
+/* Map generic access rights to object specific rights. This technique is
+ used to give meaning to assigning read, write, execute and all access to
+ objects. Each type of object has its own mapping of generic to object
+ specific access rights. */
+
+void se_map_generic(uint32_t *access_mask, const struct generic_mapping *mapping)
+{
+ uint32_t old_mask = *access_mask;
+
+ if (*access_mask & GENERIC_READ_ACCESS) {
+ *access_mask &= ~GENERIC_READ_ACCESS;
+ *access_mask |= mapping->generic_read;
+ }
+
+ if (*access_mask & GENERIC_WRITE_ACCESS) {
+ *access_mask &= ~GENERIC_WRITE_ACCESS;
+ *access_mask |= mapping->generic_write;
+ }
+
+ if (*access_mask & GENERIC_EXECUTE_ACCESS) {
+ *access_mask &= ~GENERIC_EXECUTE_ACCESS;
+ *access_mask |= mapping->generic_execute;
+ }
+
+ if (*access_mask & GENERIC_ALL_ACCESS) {
+ *access_mask &= ~GENERIC_ALL_ACCESS;
+ *access_mask |= mapping->generic_all;
+ }
+
+ if (old_mask != *access_mask) {
+ DEBUG(10, ("se_map_generic(): mapped mask 0x%08x to 0x%08x\n",
+ old_mask, *access_mask));
+ }
+}
+
+/* Map generic access rights to object specific rights for all the ACE's
+ * in a security_acl.
+ */
+
+void security_acl_map_generic(struct security_acl *sa,
+ const struct generic_mapping *mapping)
+{
+ unsigned int i;
+
+ if (!sa) {
+ return;
+ }
+
+ for (i = 0; i < sa->num_aces; i++) {
+ se_map_generic(&sa->aces[i].access_mask, mapping);
+ }
+}
+
+/* Map standard access rights to object specific rights. This technique is
+ used to give meaning to assigning read, write, execute and all access to
+ objects. Each type of object has its own mapping of standard to object
+ specific access rights. */
+
+void se_map_standard(uint32_t *access_mask, const struct standard_mapping *mapping)
+{
+ uint32_t old_mask = *access_mask;
+
+ if (*access_mask & SEC_STD_READ_CONTROL) {
+ *access_mask &= ~SEC_STD_READ_CONTROL;
+ *access_mask |= mapping->std_read;
+ }
+
+ if (*access_mask & (SEC_STD_DELETE|SEC_STD_WRITE_DAC|SEC_STD_WRITE_OWNER|SEC_STD_SYNCHRONIZE)) {
+ *access_mask &= ~(SEC_STD_DELETE|SEC_STD_WRITE_DAC|SEC_STD_WRITE_OWNER|SEC_STD_SYNCHRONIZE);
+ *access_mask |= mapping->std_all;
+ }
+
+ if (old_mask != *access_mask) {
+ DEBUG(10, ("se_map_standard(): mapped mask 0x%08x to 0x%08x\n",
+ old_mask, *access_mask));
+ }
+}
+
+enum ace_callback_result {
+ ACE_CALLBACK_DENY,
+ ACE_CALLBACK_ALLOW,
+ ACE_CALLBACK_SKIP, /* do not apply this ACE */
+ ACE_CALLBACK_INVALID /* we don't want to process the conditional ACE */
+};
+
+
+static enum ace_callback_result check_callback_ace_allow(
+ const struct security_ace *ace,
+ const struct security_token *token,
+ const struct security_descriptor *sd)
+{
+ bool ok;
+ int result;
+
+ switch (token->evaluate_claims) {
+ case CLAIMS_EVALUATION_ALWAYS:
+ break;
+
+ case CLAIMS_EVALUATION_INVALID_STATE:
+ DBG_WARNING("Refusing to evaluate ACL with "
+ "conditional ACE against security "
+ "token with CLAIMS_EVALUATION_INVALID_STATE\n");
+ return ACE_CALLBACK_INVALID;
+ case CLAIMS_EVALUATION_NEVER:
+ default:
+ /*
+ * We are asked to pretend we never understood this
+ * ACE type.
+ *
+ * By returning SKIP, this ACE will not adjust any
+ * permission bits making it an effective no-op, which
+ * was the default behaviour up to Samba 4.19.
+ */
+ return ACE_CALLBACK_SKIP;
+ }
+
+ if (ace->type != SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK &&
+ ace->type != SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT) {
+ /* This indicates a programming error */
+ DBG_ERR("bad conditional allow ACE type: %u\n", ace->type);
+ return ACE_CALLBACK_INVALID;
+ }
+
+ /*
+ * Until we discover otherwise, we assume all callback ACEs
+ * are conditional ACEs.
+ */
+ ok = access_check_conditional_ace(ace, token, sd, &result);
+ if (!ok) {
+ /*
+ * An error in processing the conditional ACE is
+ * treated as UNKNOWN, which amounts to a DENY/SKIP
+ * result.
+ *
+ * This is different from the INVALID result which
+ * means we should not be thinking about conditional
+ * ACES at all, and will abort the whole access check.
+ */
+ DBG_WARNING("callback ACE was not a valid conditional ACE\n");
+ return ACE_CALLBACK_SKIP;
+ }
+ if (result == ACE_CONDITION_TRUE) {
+ return ACE_CALLBACK_ALLOW;
+ }
+ /* UNKNOWN means do not allow */
+ return ACE_CALLBACK_SKIP;
+}
+
+
+static enum ace_callback_result check_callback_ace_deny(
+ const struct security_ace *ace,
+ const struct security_token *token,
+ const struct security_descriptor *sd)
+{
+ bool ok;
+ int result;
+
+ switch (token->evaluate_claims) {
+ case CLAIMS_EVALUATION_ALWAYS:
+ break;
+
+ case CLAIMS_EVALUATION_INVALID_STATE:
+ DBG_WARNING("Refusing to evaluate ACL with "
+ "conditional ACE against security "
+ "token with CLAIMS_EVALUATION_INVALID_STATE\n");
+ return ACE_CALLBACK_INVALID;
+ case CLAIMS_EVALUATION_NEVER:
+ default:
+ /*
+ * We are asked to pretend we never understood this
+ * ACE type.
+ */
+ return ACE_CALLBACK_SKIP;
+ }
+
+ if (ace->type != SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK &&
+ ace->type != SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT) {
+ DBG_ERR("bad conditional deny ACE type: %u\n", ace->type);
+ return ACE_CALLBACK_INVALID;
+ }
+
+ /*
+ * Until we discover otherwise, we assume all callback ACEs
+ * are conditional ACEs.
+ */
+ ok = access_check_conditional_ace(ace, token, sd, &result);
+ if (!ok) {
+ /*
+ * An error in processing the conditional ACE is
+ * treated as UNKNOWN, which means DENY.
+ */
+ DBG_WARNING("callback ACE was not a valid conditional ACE\n");
+ return ACE_CALLBACK_DENY;
+ }
+ if (result != ACE_CONDITION_FALSE) {
+ /* UNKNOWN means deny */
+ return ACE_CALLBACK_DENY;
+ }
+ return ACE_CALLBACK_SKIP;
+}
+
+
+/*
+ perform a SEC_FLAG_MAXIMUM_ALLOWED access check
+*/
+static uint32_t access_check_max_allowed(const struct security_descriptor *sd,
+ const struct security_token *token,
+ enum implicit_owner_rights implicit_owner_rights)
+{
+ uint32_t denied = 0, granted = 0;
+ bool am_owner = false;
+ bool have_owner_rights_ace = false;
+ unsigned i;
+
+ if (sd->dacl == NULL) {
+ if (security_token_has_sid(token, sd->owner_sid)) {
+ switch (implicit_owner_rights) {
+ case IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS:
+ granted |= SEC_STD_WRITE_DAC;
+ FALL_THROUGH;
+ case IMPLICIT_OWNER_READ_CONTROL_RIGHTS:
+ granted |= SEC_STD_READ_CONTROL;
+ break;
+ }
+ }
+ return granted;
+ }
+
+ if (security_token_has_sid(token, sd->owner_sid)) {
+ /*
+ * Check for explicit owner rights: if there are none, we remove
+ * the default owner right SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL
+ * from remaining_access. Otherwise we just process the
+ * explicitly granted rights when processing the ACEs.
+ */
+ am_owner = true;
+
+ for (i=0; i < sd->dacl->num_aces; i++) {
+ struct security_ace *ace = &sd->dacl->aces[i];
+
+ if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+ continue;
+ }
+
+ have_owner_rights_ace = dom_sid_equal(
+ &ace->trustee, &global_sid_Owner_Rights);
+ if (have_owner_rights_ace) {
+ break;
+ }
+ }
+ }
+
+ if (am_owner && !have_owner_rights_ace) {
+ switch (implicit_owner_rights) {
+ case IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS:
+ granted |= SEC_STD_WRITE_DAC;
+ FALL_THROUGH;
+ case IMPLICIT_OWNER_READ_CONTROL_RIGHTS:
+ granted |= SEC_STD_READ_CONTROL;
+ break;
+ }
+ }
+
+ for (i = 0;i<sd->dacl->num_aces; i++) {
+ struct security_ace *ace = &sd->dacl->aces[i];
+ bool is_owner_rights_ace = false;
+
+ if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+ continue;
+ }
+
+ if (am_owner) {
+ is_owner_rights_ace = dom_sid_equal(
+ &ace->trustee, &global_sid_Owner_Rights);
+ }
+
+ if (!is_owner_rights_ace &&
+ !security_token_has_sid(token, &ace->trustee))
+ {
+ continue;
+ }
+
+ switch (ace->type) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED:
+ granted |= ace->access_mask;
+ break;
+ case SEC_ACE_TYPE_ACCESS_DENIED:
+ case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
+ denied |= ~granted & ace->access_mask;
+ break;
+
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK:
+ {
+ enum ace_callback_result allow =
+ check_callback_ace_allow(ace, token, sd);
+ if (allow == ACE_CALLBACK_INVALID) {
+ return 0;
+ }
+ if (allow == ACE_CALLBACK_ALLOW) {
+ granted |= ace->access_mask;
+ }
+ break;
+ }
+
+ case SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK:
+ {
+ enum ace_callback_result deny =
+ check_callback_ace_deny(ace, token, sd);
+ if (deny == ACE_CALLBACK_INVALID) {
+ return 0;
+ }
+ if (deny == ACE_CALLBACK_DENY) {
+ denied |= ~granted & ace->access_mask;
+ }
+ break;
+ }
+
+ default: /* Other ACE types not handled/supported */
+ break;
+ }
+ }
+
+ return granted & ~denied;
+}
+
+
+
+static NTSTATUS se_access_check_implicit_owner(const struct security_descriptor *sd,
+ const struct security_token *token,
+ uint32_t access_desired,
+ uint32_t *access_granted,
+ enum implicit_owner_rights implicit_owner_rights)
+{
+ uint32_t i;
+ uint32_t bits_remaining;
+ uint32_t explicitly_denied_bits = 0;
+ bool am_owner = false;
+ bool have_owner_rights_ace = false;
+
+ switch (token->evaluate_claims) {
+ case CLAIMS_EVALUATION_INVALID_STATE:
+ if (token->num_local_claims > 0 ||
+ token->num_user_claims > 0 ||
+ token->num_device_claims > 0 ||
+ token->num_device_sids > 0) {
+ DBG_WARNING("Refusing to evaluate token with claims or device SIDs but also "
+ "with CLAIMS_EVALUATION_INVALID_STATE\n");
+ return NT_STATUS_INVALID_TOKEN;
+ }
+ break;
+ case CLAIMS_EVALUATION_ALWAYS:
+ case CLAIMS_EVALUATION_NEVER:
+ break;
+ }
+
+ *access_granted = access_desired;
+ bits_remaining = access_desired;
+
+ /* handle the maximum allowed flag */
+ if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) {
+ uint32_t orig_access_desired = access_desired;
+
+ access_desired |= access_check_max_allowed(sd, token, implicit_owner_rights);
+ access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED;
+ *access_granted = access_desired;
+ bits_remaining = access_desired;
+
+ DEBUG(10,("se_access_check: MAX desired = 0x%x, granted = 0x%x, remaining = 0x%x\n",
+ orig_access_desired,
+ *access_granted,
+ bits_remaining));
+ }
+
+ /* a NULL dacl allows access */
+ if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl == NULL) {
+ *access_granted = access_desired;
+ return NT_STATUS_OK;
+ }
+
+ if (sd->dacl == NULL) {
+ goto done;
+ }
+
+ if (security_token_has_sid(token, sd->owner_sid)) {
+ /*
+ * Check for explicit owner rights: if there are none, we remove
+ * the default owner right SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL
+ * from remaining_access. Otherwise we just process the
+ * explicitly granted rights when processing the ACEs.
+ */
+ am_owner = true;
+
+ for (i=0; i < sd->dacl->num_aces; i++) {
+ struct security_ace *ace = &sd->dacl->aces[i];
+
+ if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+ continue;
+ }
+
+ have_owner_rights_ace = dom_sid_equal(
+ &ace->trustee, &global_sid_Owner_Rights);
+ if (have_owner_rights_ace) {
+ break;
+ }
+ }
+ }
+ if (am_owner && !have_owner_rights_ace) {
+ switch (implicit_owner_rights) {
+ case IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS:
+ bits_remaining &= ~SEC_STD_WRITE_DAC;
+ FALL_THROUGH;
+ case IMPLICIT_OWNER_READ_CONTROL_RIGHTS:
+ bits_remaining &= ~SEC_STD_READ_CONTROL;
+ break;
+ }
+ }
+
+ /* check each ace in turn. */
+ for (i=0; bits_remaining && i < sd->dacl->num_aces; i++) {
+ struct security_ace *ace = &sd->dacl->aces[i];
+ bool is_owner_rights_ace = false;
+
+ if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+ continue;
+ }
+
+ if (am_owner) {
+ is_owner_rights_ace = dom_sid_equal(
+ &ace->trustee, &global_sid_Owner_Rights);
+ }
+
+ if (!is_owner_rights_ace &&
+ !security_token_has_sid(token, &ace->trustee))
+ {
+ continue;
+ }
+
+ switch (ace->type) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED:
+ bits_remaining &= ~ace->access_mask;
+ break;
+ case SEC_ACE_TYPE_ACCESS_DENIED:
+ case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
+ explicitly_denied_bits |= (bits_remaining & ace->access_mask);
+ break;
+
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK:
+ {
+ enum ace_callback_result allow =
+ check_callback_ace_allow(ace, token, sd);
+ if (allow == ACE_CALLBACK_INVALID) {
+ return NT_STATUS_INVALID_ACE_CONDITION;
+ }
+ if (allow == ACE_CALLBACK_ALLOW) {
+ bits_remaining &= ~ace->access_mask;
+ }
+ break;
+ }
+
+ case SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK:
+ case SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT:
+ {
+ enum ace_callback_result deny =
+ check_callback_ace_deny(ace, token, sd);
+ if (deny == ACE_CALLBACK_INVALID) {
+ return NT_STATUS_INVALID_ACE_CONDITION;
+ }
+ if (deny == ACE_CALLBACK_DENY) {
+ explicitly_denied_bits |= (bits_remaining & ace->access_mask);
+ }
+ break;
+ }
+
+ default: /* Other ACE types not handled/supported */
+ break;
+ }
+ }
+
+ /* Explicitly denied bits always override */
+ bits_remaining |= explicitly_denied_bits;
+
+ /*
+ * We check privileges here because they override even DENY entries.
+ */
+
+ /* Does the user have the privilege to gain SEC_PRIV_SECURITY? */
+ if (bits_remaining & SEC_FLAG_SYSTEM_SECURITY) {
+ if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
+ bits_remaining &= ~SEC_FLAG_SYSTEM_SECURITY;
+ } else {
+ return NT_STATUS_PRIVILEGE_NOT_HELD;
+ }
+ }
+
+ if ((bits_remaining & SEC_STD_WRITE_OWNER) &&
+ security_token_has_privilege(token, SEC_PRIV_TAKE_OWNERSHIP)) {
+ bits_remaining &= ~(SEC_STD_WRITE_OWNER);
+ }
+
+done:
+ if (bits_remaining != 0) {
+ *access_granted = bits_remaining;
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ The main entry point for access checking. If returning ACCESS_DENIED
+ this function returns the denied bits in the uint32_t pointed
+ to by the access_granted pointer.
+*/
+NTSTATUS se_access_check(const struct security_descriptor *sd,
+ const struct security_token *token,
+ uint32_t access_desired,
+ uint32_t *access_granted)
+{
+ return se_access_check_implicit_owner(sd,
+ token,
+ access_desired,
+ access_granted,
+ IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS);
+}
+
+/*
+ The main entry point for access checking FOR THE FILE SERVER ONLY !
+ If returning ACCESS_DENIED this function returns the denied bits in
+ the uint32_t pointed to by the access_granted pointer.
+*/
+NTSTATUS se_file_access_check(const struct security_descriptor *sd,
+ const struct security_token *token,
+ bool priv_open_requested,
+ uint32_t access_desired,
+ uint32_t *access_granted)
+{
+ uint32_t bits_remaining;
+ NTSTATUS status;
+
+ if (!priv_open_requested) {
+ /* Fall back to generic se_access_check(). */
+ return se_access_check_implicit_owner(sd,
+ token,
+ access_desired,
+ access_granted,
+ IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS);
+ }
+
+ /*
+ * We need to handle the maximum allowed flag
+ * outside of se_access_check(), as we need to
+ * add in the access allowed by the privileges
+ * as well.
+ */
+
+ if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) {
+ uint32_t orig_access_desired = access_desired;
+
+ access_desired |= access_check_max_allowed(sd, token, true);
+ access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED;
+
+ if (security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
+ access_desired |= SEC_RIGHTS_PRIV_BACKUP;
+ }
+
+ if (security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
+ access_desired |= SEC_RIGHTS_PRIV_RESTORE;
+ }
+
+ DEBUG(10,("se_file_access_check: MAX desired = 0x%x "
+ "mapped to 0x%x\n",
+ orig_access_desired,
+ access_desired));
+ }
+
+ status = se_access_check_implicit_owner(sd,
+ token,
+ access_desired,
+ access_granted,
+ IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS);
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ return status;
+ }
+
+ bits_remaining = *access_granted;
+
+ /* Check if we should override with privileges. */
+ if ((bits_remaining & SEC_RIGHTS_PRIV_BACKUP) &&
+ security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
+ bits_remaining &= ~(SEC_RIGHTS_PRIV_BACKUP);
+ }
+ if ((bits_remaining & SEC_RIGHTS_PRIV_RESTORE) &&
+ security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
+ bits_remaining &= ~(SEC_RIGHTS_PRIV_RESTORE);
+ }
+ if (bits_remaining != 0) {
+ *access_granted = bits_remaining;
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static const struct GUID *get_ace_object_type(const struct security_ace *ace)
+{
+ if (ace->object.object.flags & SEC_ACE_OBJECT_TYPE_PRESENT) {
+ return &ace->object.object.type.type;
+ }
+
+ return NULL;
+}
+
+/**
+ * Evaluates access rights specified in a object-specific ACE for an AD object.
+ * This logic corresponds to MS-ADTS 5.1.3.3.3 Checking Object-Specific Access.
+ * @param[in] ace - the ACE being processed
+ * @param[in/out] tree - remaining_access gets updated for the tree
+ * @param[out] grant_access - set to true if the ACE grants sufficient access
+ * rights to the object/attribute
+ * @returns NT_STATUS_OK, unless access was denied
+ */
+static NTSTATUS check_object_specific_access(const struct security_ace *ace,
+ struct object_tree *tree,
+ bool *grant_access)
+{
+ struct object_tree *node = NULL;
+ const struct GUID *type = NULL;
+
+ *grant_access = false;
+
+ /* if no tree was supplied, we can't do object-specific access checks */
+ if (!tree) {
+ return NT_STATUS_OK;
+ }
+
+ /* Get the ObjectType GUID this ACE applies to */
+ type = get_ace_object_type(ace);
+
+ /*
+ * If the ACE doesn't have a type, then apply it to the whole tree, i.e.
+ * treat 'OA' ACEs as 'A' and 'OD' as 'D'
+ */
+ if (!type) {
+ node = tree;
+ } else {
+
+ /* skip it if the ACE's ObjectType GUID is not in the tree */
+ node = get_object_tree_by_GUID(tree, type);
+ if (!node) {
+ return NT_STATUS_OK;
+ }
+ }
+
+ if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ||
+ ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT) {
+ /* apply the access rights to this node, and any children */
+ object_tree_modify_access(node, ace->access_mask);
+
+ /*
+ * Currently all nodes in the tree request the same access mask,
+ * so we can use any node to check if processing this ACE now
+ * means the requested access has been granted
+ */
+ if (node->remaining_access == 0) {
+ *grant_access = true;
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * As per 5.1.3.3.4 Checking Control Access Right-Based Access,
+ * if the CONTROL_ACCESS right is present, then we can grant
+ * access and stop any further access checks
+ */
+ if (ace->access_mask & SEC_ADS_CONTROL_ACCESS) {
+ *grant_access = true;
+ return NT_STATUS_OK;
+ }
+ } else {
+
+ /* this ACE denies access to the requested object/attribute */
+ if (node->remaining_access & ace->access_mask){
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+ return NT_STATUS_OK;
+}
+
+
+NTSTATUS sec_access_check_ds_implicit_owner(const struct security_descriptor *sd,
+ const struct security_token *token,
+ uint32_t access_desired,
+ uint32_t *access_granted,
+ struct object_tree *tree,
+ const struct dom_sid *replace_sid,
+ enum implicit_owner_rights implicit_owner_rights)
+{
+ uint32_t i;
+ uint32_t bits_remaining;
+
+ *access_granted = access_desired;
+ bits_remaining = access_desired;
+
+ /* handle the maximum allowed flag */
+ if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) {
+ access_desired |= access_check_max_allowed(sd, token, implicit_owner_rights);
+ access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED;
+ *access_granted = access_desired;
+ bits_remaining = access_desired;
+ }
+
+ if (access_desired & SEC_FLAG_SYSTEM_SECURITY) {
+ if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
+ bits_remaining &= ~SEC_FLAG_SYSTEM_SECURITY;
+ } else {
+ return NT_STATUS_PRIVILEGE_NOT_HELD;
+ }
+ }
+
+ /* the owner always gets SEC_STD_WRITE_DAC and SEC_STD_READ_CONTROL */
+ if ((bits_remaining & (SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL)) &&
+ security_token_has_sid(token, sd->owner_sid)) {
+ switch (implicit_owner_rights) {
+ case IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS:
+ bits_remaining &= ~SEC_STD_WRITE_DAC;
+ FALL_THROUGH;
+ case IMPLICIT_OWNER_READ_CONTROL_RIGHTS:
+ bits_remaining &= ~SEC_STD_READ_CONTROL;
+ break;
+ }
+ }
+
+ /* SEC_PRIV_TAKE_OWNERSHIP grants SEC_STD_WRITE_OWNER */
+ if ((bits_remaining & (SEC_STD_WRITE_OWNER)) &&
+ security_token_has_privilege(token, SEC_PRIV_TAKE_OWNERSHIP)) {
+ bits_remaining &= ~(SEC_STD_WRITE_OWNER);
+ }
+
+ /* a NULL dacl allows access */
+ if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl == NULL) {
+ *access_granted = access_desired;
+ return NT_STATUS_OK;
+ }
+
+ if (sd->dacl == NULL) {
+ goto done;
+ }
+
+ /* check each ace in turn. */
+ for (i=0; bits_remaining && i < sd->dacl->num_aces; i++) {
+ const struct dom_sid *trustee;
+ const struct security_ace *ace = &sd->dacl->aces[i];
+ NTSTATUS status;
+ bool grant_access = false;
+
+ if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+ continue;
+ }
+
+ if (dom_sid_equal(&ace->trustee, &global_sid_Self) && replace_sid) {
+ trustee = replace_sid;
+ } else {
+ trustee = &ace->trustee;
+ }
+
+ if (!security_token_has_sid(token, trustee)) {
+ continue;
+ }
+
+ switch (ace->type) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED:
+ if (tree) {
+ object_tree_modify_access(tree, ace->access_mask);
+ }
+
+ bits_remaining &= ~ace->access_mask;
+ break;
+ case SEC_ACE_TYPE_ACCESS_DENIED:
+ if (bits_remaining & ace->access_mask) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ break;
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK:
+ {
+ enum ace_callback_result allow =
+ check_callback_ace_allow(ace, token, sd);
+ if (allow == ACE_CALLBACK_INVALID) {
+ return NT_STATUS_INVALID_ACE_CONDITION;
+ }
+ if (allow == ACE_CALLBACK_ALLOW) {
+ bits_remaining &= ~ace->access_mask;
+ }
+ break;
+ }
+
+ case SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK:
+ {
+ enum ace_callback_result deny =
+ check_callback_ace_deny(ace, token, sd);
+ if (deny == ACE_CALLBACK_INVALID) {
+ return NT_STATUS_INVALID_ACE_CONDITION;
+ }
+ if (deny == ACE_CALLBACK_DENY) {
+ if (bits_remaining & ace->access_mask) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+ break;
+ }
+
+ case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT:
+ status = check_object_specific_access(ace, tree,
+ &grant_access);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (grant_access) {
+ return NT_STATUS_OK;
+ }
+ break;
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT:
+ {
+ /*
+ * if the callback says ALLOW, we treat this as a
+ * SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT.
+ *
+ * Otherwise we act as if this ACE does not exist.
+ */
+ enum ace_callback_result allow =
+ check_callback_ace_allow(ace, token, sd);
+ if (allow == ACE_CALLBACK_INVALID) {
+ return NT_STATUS_INVALID_ACE_CONDITION;
+ }
+ if (allow != ACE_CALLBACK_ALLOW) {
+ break;
+ }
+
+ status = check_object_specific_access(ace, tree,
+ &grant_access);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (grant_access) {
+ return NT_STATUS_OK;
+ }
+ break;
+ }
+ case SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT:
+ {
+ /*
+ * ACCESS_DENIED_OBJECT ACEs can't grant access --
+ * they either don't match the object and slide
+ * harmlessly past or they return
+ * NT_STATUS_ACCESS_DENIED.
+ *
+ * ACCESS_DENIED_CALLBACK_OBJECT ACEs add another way
+ * of not applying, and another way of failing.
+ */
+ enum ace_callback_result deny =
+ check_callback_ace_deny(ace, token, sd);
+ if (deny == ACE_CALLBACK_INVALID) {
+ return NT_STATUS_INVALID_ACE_CONDITION;
+ }
+ if (deny != ACE_CALLBACK_DENY) {
+ break;
+ }
+ status = check_object_specific_access(ace, tree,
+ &grant_access);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ break;
+ }
+ default: /* Other ACE types not handled/supported */
+ break;
+ }
+ }
+
+done:
+ if (bits_remaining != 0) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * @brief Perform directoryservice (DS) related access checks for a given user
+ *
+ * Perform DS access checks for the user represented by its security_token, on
+ * the provided security descriptor. If an tree associating GUID and access
+ * required is provided then object access (OA) are checked as well. *
+ * @param[in] sd The security descriptor against which the required
+ * access are requested
+ *
+ * @param[in] token The security_token associated with the user to
+ * test
+ *
+ * @param[in] access_desired A bitfield of rights that must be granted for the
+ * given user in the specified SD.
+ *
+ * If one
+ * of the entry in the tree grants all the requested rights for the given GUID
+ * FIXME
+ * tree can be null if not null it's the
+ * Lots of code duplication, it will be united in just one
+ * function eventually */
+
+NTSTATUS sec_access_check_ds(const struct security_descriptor *sd,
+ const struct security_token *token,
+ uint32_t access_desired,
+ uint32_t *access_granted,
+ struct object_tree *tree,
+ struct dom_sid *replace_sid)
+{
+ return sec_access_check_ds_implicit_owner(sd,
+ token,
+ access_desired,
+ access_granted,
+ tree,
+ replace_sid,
+ IMPLICIT_OWNER_READ_CONTROL_RIGHTS);
+}
diff --git a/libcli/security/access_check.h b/libcli/security/access_check.h
new file mode 100644
index 0000000..7c424b9
--- /dev/null
+++ b/libcli/security/access_check.h
@@ -0,0 +1,100 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Gerald Carter 2005
+ Copyright (C) Volker Lendecke 2007
+ Copyright (C) Jeremy Allison 2008
+ Copyright (C) Andrew Bartlett 2010
+
+ 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/>.
+*/
+#ifndef _ACCESS_CHECK_H_
+#define _ACCESS_CHECK_H_
+
+#include "librpc/gen_ndr/security.h"
+
+/* Map generic access rights to object specific rights. This technique is
+ used to give meaning to assigning read, write, execute and all access to
+ objects. Each type of object has its own mapping of generic to object
+ specific access rights. */
+
+void se_map_generic(uint32_t *access_mask, const struct generic_mapping *mapping);
+
+/* Map generic access rights to object specific rights for all the ACE's
+ * in a security_acl.
+ */
+void security_acl_map_generic(struct security_acl *sa,
+ const struct generic_mapping *mapping);
+
+/* Map standard access rights to object specific rights. This technique is
+ used to give meaning to assigning read, write, execute and all access to
+ objects. Each type of object has its own mapping of standard to object
+ specific access rights. */
+void se_map_standard(uint32_t *access_mask, const struct standard_mapping *mapping);
+
+/*
+ The main entry point for access checking. If returning ACCESS_DENIED
+ this function returns the denied bits in the uint32_t pointed
+ to by the access_granted pointer.
+*/
+NTSTATUS se_access_check(const struct security_descriptor *sd,
+ const struct security_token *token,
+ uint32_t access_desired,
+ uint32_t *access_granted);
+
+/*
+ The main entry point for access checking FOR THE FILE SERVER ONLY !
+ If returning ACCESS_DENIED this function returns the denied bits in
+ the uint32_t pointed to by the access_granted pointer.
+*/
+NTSTATUS se_file_access_check(const struct security_descriptor *sd,
+ const struct security_token *token,
+ bool priv_open_requested,
+ uint32_t access_desired,
+ uint32_t *access_granted);
+
+NTSTATUS sec_access_check_ds_implicit_owner(const struct security_descriptor *sd,
+ const struct security_token *token,
+ uint32_t access_desired,
+ uint32_t *access_granted,
+ struct object_tree *tree,
+ const struct dom_sid *replace_sid,
+ enum implicit_owner_rights implicit_owner_rights);
+
+/* modified access check for the purposes of DS security
+ * Lots of code duplication, it will be united in just one
+ * function eventually */
+
+NTSTATUS sec_access_check_ds(const struct security_descriptor *sd,
+ const struct security_token *token,
+ uint32_t access_desired,
+ uint32_t *access_granted,
+ struct object_tree *tree,
+ struct dom_sid *replace_sid);
+
+bool insert_in_object_tree(TALLOC_CTX *mem_ctx,
+ const struct GUID *guid,
+ uint32_t init_access,
+ struct object_tree *root,
+ struct object_tree **new_node_out);
+
+/* search by GUID */
+struct object_tree *get_object_tree_by_GUID(struct object_tree *root,
+ const struct GUID *guid);
+
+/* Change the granted access per each ACE */
+void object_tree_modify_access(struct object_tree *root,
+ uint32_t access_mask);
+#endif
diff --git a/libcli/security/claims-conversions.c b/libcli/security/claims-conversions.c
new file mode 100644
index 0000000..ccf1375
--- /dev/null
+++ b/libcli/security/claims-conversions.c
@@ -0,0 +1,1216 @@
+/*
+ * Unix SMB implementation.
+ * Utility functions for converting between claims formats.
+ *
+ * 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 "replace.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/ndr_conditional_ace.h"
+#include "libcli/security/claims-conversions.h"
+#include "lib/util/debug.h"
+#include "lib/util/stable_sort.h"
+
+#include "librpc/gen_ndr/conditional_ace.h"
+#include "librpc/gen_ndr/claims.h"
+
+/*
+ * We support three formats for claims, all slightly different.
+ *
+ * 1. MS-ADTS 2.2.18.* claims sets, blobs, arrays, or whatever, which
+ * are used in the PAC.
+ *
+ * 2. MS-DTYP 2.4.10.1 CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1
+ * structures, used in security tokens and resource SACL ACEs.
+ *
+ * 3. MS-DTYP 2.4.4.17 Conditional ACE tokens.
+ *
+ * The types don't map perfectly onto each other -- in particular,
+ * Conditional ACEs don't have unsigned integer or boolean types, but
+ * do have short integer types which the other forms don't.
+ *
+ * We don't support the format used by the Win32 API function
+ * AddResourceAttributeAce(), which is called CLAIM_SECURITY_ATTRIBUTE_V1.
+ * Nobody has ever used that function in public, and the format is not used
+ * on the wire.
+ */
+
+
+static bool claim_v1_string_to_ace_string(
+ TALLOC_CTX *mem_ctx,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset,
+ struct ace_condition_token *result)
+{
+ char *s = talloc_strdup(mem_ctx,
+ claim->values[offset].string_value);
+ if (s == NULL) {
+ return false;
+ }
+
+ result->type = CONDITIONAL_ACE_TOKEN_UNICODE;
+ result->data.unicode.value = s;
+ return true;
+}
+
+
+static bool claim_v1_octet_string_to_ace_octet_string(
+ TALLOC_CTX *mem_ctx,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset,
+ struct ace_condition_token *result)
+{
+ DATA_BLOB *v = NULL;
+ DATA_BLOB w = data_blob_null;
+
+ v = claim->values[offset].octet_value;
+
+ if (v->length > CONDITIONAL_ACE_MAX_LENGTH) {
+ DBG_WARNING("claim has octet string of unexpected length %zu "
+ "(expected range 1 - %u)\n",
+ v->length, CONDITIONAL_ACE_MAX_LENGTH);
+ return false;
+ }
+ if (v->length != 0) {
+ w = data_blob_talloc(mem_ctx, v->data, v->length);
+ if (w.data == NULL) {
+ return false;
+ }
+ }
+
+ result->type = CONDITIONAL_ACE_TOKEN_OCTET_STRING;
+ result->data.bytes = w;
+ return true;
+}
+
+
+static bool blob_string_sid_to_sid(DATA_BLOB *blob,
+ struct dom_sid *sid)
+{
+ /*
+ * Resource ACE claim SIDs are stored as SID strings in
+ * CLAIM_SECURITY_ATTRIBUTE_OCTET_STRING_RELATIVE blobs. These are in
+ * ACEs, which means we don't quite know who wrote them, and it is
+ * unspecified whether the blob should contain a terminating NUL byte.
+ * Therefore we accept either form, copying into a temporary buffer if
+ * there is no '\0'. Apart from this special case, we don't accept
+ * SIDs that are shorter than the blob.
+ *
+ * It doesn't seem like SDDL short SIDs ("WD") are accepted here. This
+ * isn't SDDL.
+ */
+ bool ok;
+ size_t len = blob->length;
+ char buf[DOM_SID_STR_BUFLEN + 1]; /* 191 + 1 */
+ const char *end = NULL;
+ char *str = NULL;
+
+ if (len < 5 || len >= DOM_SID_STR_BUFLEN) {
+ return false;
+ }
+ if (blob->data[len - 1] == '\0') {
+ str = (char *)blob->data;
+ len--;
+ } else {
+ memcpy(buf, blob->data, len);
+ buf[len] = 0;
+ str = buf;
+ }
+
+ ok = dom_sid_parse_endp(str, sid, &end);
+ if (!ok) {
+ return false;
+ }
+
+ if (end - str != len) {
+ return false;
+ }
+ return true;
+}
+
+
+static bool claim_v1_sid_to_ace_sid(
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset,
+ struct ace_condition_token *result)
+{
+ /*
+ * In the _V1 struct, SIDs are stored as octet string blobs,
+ * as *SID strings*.
+ *
+ * In the conditional ACE they are stored as struct dom_sid.
+ *
+ * There are no SIDs in ADTS claims, but there can be in
+ * resource ACEs.
+ */
+ DATA_BLOB *v = NULL;
+ bool ok;
+
+ v = claim->values[offset].sid_value;
+
+ ok = blob_string_sid_to_sid(v, &result->data.sid.sid);
+ if (! ok) {
+ DBG_WARNING("claim has invalid SID string of length %zu.\n",
+ v->length);
+ return false;
+ }
+
+ result->type = CONDITIONAL_ACE_TOKEN_SID;
+ return true;
+}
+
+
+static bool claim_v1_int_to_ace_int(
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset,
+ struct ace_condition_token *result)
+{
+ int64_t v = *claim->values[offset].int_value;
+ result->type = CONDITIONAL_ACE_TOKEN_INT64;
+ result->data.int64.base = CONDITIONAL_ACE_INT_BASE_10;
+ result->data.int64.value = v;
+
+ /*
+ * The sign flag (and the base flag above) determines how the
+ * ACE token will be displayed if converted to SDDL. These
+ * values are not likely to end up as SDDL, but we might as
+ * well get it right. A negative flag means it will be
+ * displayed with a minus sign, and a positive flag means a
+ * plus sign is shown. The none flag means no + or -.
+ */
+ if (v < 0) {
+ result->data.int64.sign = CONDITIONAL_ACE_INT_SIGN_NEGATIVE;
+ } else {
+ result->data.int64.sign = CONDITIONAL_ACE_INT_SIGN_NONE;
+ }
+
+ return true;
+}
+
+
+static bool claim_v1_unsigned_int_to_ace_int(
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset,
+ struct ace_condition_token *result)
+{
+ uint64_t v = *claim->values[offset].uint_value;
+ if (v > INT64_MAX) {
+ /*
+ * The unsigned value can't be represented in a
+ * conditional ACE type.
+ *
+ * XXX or can it? does the positive flag make it
+ * unsigned?
+ */
+ return false;
+ }
+ result->type = CONDITIONAL_ACE_TOKEN_INT64;
+ result->data.int64.base = CONDITIONAL_ACE_INT_BASE_10;
+ result->data.int64.sign = CONDITIONAL_ACE_INT_SIGN_POSITIVE;
+ result->data.int64.value = v;
+ return true;
+}
+
+
+static bool claim_v1_bool_to_ace_int(
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset,
+ struct ace_condition_token *result)
+{
+ uint64_t v = *claim->values[offset].uint_value;
+ result->type = CONDITIONAL_ACE_TOKEN_INT64;
+ result->data.int64.base = CONDITIONAL_ACE_INT_BASE_10;
+ result->data.int64.sign = CONDITIONAL_ACE_INT_SIGN_NONE;
+ result->data.int64.value = v ? 1 : 0;
+ return true;
+}
+
+
+static bool claim_v1_offset_to_ace_token(
+ TALLOC_CTX *mem_ctx,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset,
+ struct ace_condition_token *result)
+{
+ /*
+ * A claim structure has an array of claims of a certain type,
+ * and this converts a single one into a conditional ACE token.
+ *
+ * For example, if offset is 3, claim->values[3] will be
+ * turned into *result.
+ *
+ * conditional ace token will have flags to indicate that it
+ * comes from a claim attribute, and whether or not that
+ * attribute should be compared case-sensitively (only
+ * affecting unicode strings).
+ *
+ * The CLAIM_SECURITY_ATTRIBUTE_CASE_SENSITIVE (from the
+ * claim_flags enum in security.idl) is used for both.
+ */
+ uint8_t f = claim->flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
+ result->flags = f | CONDITIONAL_ACE_FLAG_TOKEN_FROM_ATTR;
+
+ if (claim->values[offset].int_value == NULL) {
+ return false;
+ }
+ switch (claim->value_type) {
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
+ return claim_v1_int_to_ace_int(claim, offset, result);
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
+ return claim_v1_unsigned_int_to_ace_int(claim, offset, result);
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
+ return claim_v1_string_to_ace_string(mem_ctx, claim, offset,
+ result);
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_SID:
+ return claim_v1_sid_to_ace_sid(claim, offset, result);
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN:
+ return claim_v1_bool_to_ace_int(claim, offset, result);
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:
+ return claim_v1_octet_string_to_ace_octet_string(mem_ctx,
+ claim,
+ offset,
+ result);
+ default:
+ return false;
+ }
+}
+
+
+static bool claim_v1_copy(
+ TALLOC_CTX *mem_ctx,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *dest,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *src);
+
+
+
+bool claim_v1_to_ace_composite_unchecked(
+ TALLOC_CTX *mem_ctx,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ struct ace_condition_token *result)
+{
+ /*
+ * This converts a claim object into a conditional ACE
+ * composite without checking whether it is a valid and sorted
+ * claim. It is called in two places:
+ *
+ * 1. claim_v1_to_ace_token() below (which does do those
+ * checks, and is the function you want).
+ *
+ * 2. sddl_resource_attr_from_claim() in which a resource
+ * attribute claim needs to pass through a conditional ACE
+ * composite structure on its way to becoming SDDL. In that
+ * case we don't want to check validity.
+ */
+ size_t i;
+ struct ace_condition_token *tokens = NULL;
+ bool ok;
+
+ tokens = talloc_array(mem_ctx,
+ struct ace_condition_token,
+ claim->value_count);
+ if (tokens == NULL) {
+ return false;
+ }
+
+ for (i = 0; i < claim->value_count; i++) {
+ ok = claim_v1_offset_to_ace_token(tokens,
+ claim,
+ i,
+ &tokens[i]);
+ if (! ok) {
+ TALLOC_FREE(tokens);
+ return false;
+ }
+ }
+
+ result->type = CONDITIONAL_ACE_TOKEN_COMPOSITE;
+ result->data.composite.tokens = tokens;
+ result->data.composite.n_members = claim->value_count;
+ result->flags = claim->flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
+ return true;
+}
+
+
+bool claim_v1_to_ace_token(TALLOC_CTX *mem_ctx,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ struct ace_condition_token *result)
+{
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim_copy = NULL;
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *sorted_claim = NULL;
+ NTSTATUS status;
+ bool ok;
+ bool case_sensitive = claim->flags & \
+ CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
+
+ if (claim->value_count < 1 ||
+ claim->value_count >= CONDITIONAL_ACE_MAX_TOKENS) {
+ DBG_WARNING("rejecting claim with %"PRIu32" tokens\n",
+ claim->value_count);
+ return false;
+ }
+ /*
+ * if there is one, we return a single thing of that type; if
+ * there are many, we return a composite.
+ */
+
+ if (claim->value_count == 1) {
+ return claim_v1_offset_to_ace_token(mem_ctx,
+ claim,
+ 0,
+ result);
+ }
+
+ if (claim->flags & CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED) {
+ /*
+ * We can avoid making a sorted copy.
+ *
+ * This is normal case for wire claims, where the
+ * sorting and duplicate checking happens earlier in
+ * token_claims_to_claims_v1().
+ */
+ sorted_claim = claim;
+ } else {
+ /*
+ * This is presumably a resource attribute ACE, which
+ * is stored in the ACE as struct
+ * CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1, and we don't
+ * really want to mutate that copy -- even if there
+ * aren't currently realistic pathways that read an
+ * ACE, trigger this, and write it back (outside of
+ * tests).
+ */
+ claim_copy = talloc(mem_ctx, struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1);
+ if (claim_copy == NULL) {
+ return false;
+ }
+
+ ok = claim_v1_copy(claim_copy, claim_copy, claim);
+ if (!ok) {
+ TALLOC_FREE(claim_copy);
+ return false;
+ }
+
+ status = claim_v1_check_and_sort(claim_copy, claim_copy,
+ case_sensitive);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("resource attribute claim sort failed with %s\n",
+ nt_errstr(status));
+ TALLOC_FREE(claim_copy);
+ return false;
+ }
+ sorted_claim = claim_copy;
+ }
+ ok = claim_v1_to_ace_composite_unchecked(mem_ctx, sorted_claim, result);
+ if (! ok) {
+ TALLOC_FREE(claim_copy);
+ return false;
+ }
+
+ /*
+ * The multiple values will get turned into a composite
+ * literal in the conditional ACE. Each element of the
+ * composite will have flags set by
+ * claim_v1_offset_to_ace_token(), but they also need to be
+ * set here (at least the _FROM_ATTR flag) or the child values
+ * will not be reached.
+ */
+ result->flags |= (
+ CONDITIONAL_ACE_FLAG_TOKEN_FROM_ATTR |
+ CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED);
+
+ return true;
+}
+
+
+
+static bool ace_int_to_claim_v1_int(TALLOC_CTX *mem_ctx,
+ const struct ace_condition_token *tok,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset)
+{
+ int64_t *v = talloc(mem_ctx, int64_t);
+ if (v == NULL) {
+ return false;
+ }
+ *v = tok->data.int64.value;
+ claim->values[offset].int_value = v;
+ return true;
+}
+
+
+static bool ace_string_to_claim_v1_string(TALLOC_CTX *mem_ctx,
+ const struct ace_condition_token *tok,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset)
+{
+ const char *s = talloc_strdup(mem_ctx,
+ tok->data.unicode.value);
+ if (s == NULL) {
+ return false;
+ }
+ claim->values[offset].string_value = s;
+ return true;
+
+}
+
+
+static bool ace_sid_to_claim_v1_sid(TALLOC_CTX *mem_ctx,
+ const struct ace_condition_token *tok,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset)
+{
+ /* claim_v1 sid is an "S-1-*" string data blob, not struct dom_sid. */
+ char *s = NULL;
+
+ DATA_BLOB *blob = NULL;
+ blob = talloc(mem_ctx, DATA_BLOB);
+ if (blob == NULL) {
+ return false;
+ }
+ s = dom_sid_string(blob, &tok->data.sid.sid);
+ if (s == NULL) {
+ TALLOC_FREE(blob);
+ return false;
+ }
+ *blob = data_blob_string_const(s);
+ claim->values[offset].sid_value = blob;
+ return true;
+}
+
+static bool ace_octet_string_to_claim_v1_octet_string(
+ TALLOC_CTX *mem_ctx,
+ const struct ace_condition_token *tok,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset)
+{
+ DATA_BLOB *v = talloc(mem_ctx, DATA_BLOB);
+ if (v == NULL) {
+ return false;
+ }
+
+ *v = data_blob_talloc(v,
+ tok->data.bytes.data,
+ tok->data.bytes.length);
+ if (v->data == NULL) {
+ return false;
+ }
+
+ claim->values[offset].octet_value = v;
+ return true;
+}
+
+
+
+static bool ace_token_to_claim_v1_offset(TALLOC_CTX *mem_ctx,
+ const struct ace_condition_token *tok,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset)
+{
+ /*
+ * A claim structure has an array of claims of a certain type,
+ * and this converts a single one into a conditional ACE token.
+ *
+ * For example, if offset is 3, claim->values[3] will be
+ * turned into *result.
+ */
+ if (offset >= claim->value_count) {
+ return false;
+ }
+ switch (claim->value_type) {
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
+ return ace_int_to_claim_v1_int(mem_ctx, tok, claim, offset);
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
+ return ace_string_to_claim_v1_string(mem_ctx, tok, claim, offset);
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_SID:
+ return ace_sid_to_claim_v1_sid(mem_ctx, tok, claim, offset);
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:
+ return ace_octet_string_to_claim_v1_octet_string(mem_ctx,
+ tok,
+ claim,
+ offset);
+ default:
+ /*bool unimplemented, because unreachable */
+ return false;
+ }
+}
+
+
+bool ace_token_to_claim_v1(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const struct ace_condition_token *tok,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 **claim,
+ uint32_t flags)
+{
+ size_t i;
+ bool ok;
+ bool is_comp = false;
+ int claim_type = -1;
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *_claim = NULL;
+ uint32_t value_count;
+
+ if (name == NULL || claim == NULL || tok == NULL) {
+ return false;
+ }
+ *claim = NULL;
+
+ if (tok->type == CONDITIONAL_ACE_TOKEN_COMPOSITE) {
+ is_comp = true;
+ /* there must be values, all of the same type */
+ if (tok->data.composite.n_members == 0) {
+ DBG_WARNING("Empty ACE composite list\n");
+ return false;
+ }
+ if (tok->data.composite.n_members > 1) {
+ for (i = 1; i < tok->data.composite.n_members; i++) {
+ if (tok->data.composite.tokens[i].type !=
+ tok->data.composite.tokens[0].type) {
+ DBG_WARNING(
+ "ACE composite list has varying "
+ "types (at least %u and %u)\n",
+ tok->data.composite.tokens[i].type,
+ tok->data.composite.tokens[0].type);
+ return false;
+ }
+ }
+ }
+ value_count = tok->data.composite.n_members;
+
+ switch (tok->data.composite.tokens[0].type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64;
+ break;
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING;
+ break;
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING;
+ break;
+ case CONDITIONAL_ACE_TOKEN_SID:
+ claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_SID;
+ break;
+ default:
+ /* reject nested composites, no uint or bool. */
+ DBG_WARNING("ACE composite list has invalid type %u\n",
+ tok->data.composite.tokens[0].type);
+ return false;
+ }
+ } else {
+ value_count = 1;
+ switch(tok->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64;
+ break;
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING;
+ break;
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING;
+ break;
+ case CONDITIONAL_ACE_TOKEN_SID:
+ claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_SID;
+ break;
+ default:
+ /*
+ * no way of creating bool or uint values,
+ * composite is handled above.
+ */
+ DBG_WARNING("ACE token has invalid type %u\n",
+ tok->data.composite.tokens[0].type);
+ return false;
+ }
+ }
+
+ _claim = talloc(mem_ctx, struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1);
+ if (_claim == NULL) {
+ return false;
+ }
+
+ _claim->value_count = value_count;
+ _claim->value_type = claim_type;
+ _claim->flags = flags;
+ _claim->name = talloc_strdup(mem_ctx, name);
+ if (_claim->name == NULL) {
+ TALLOC_FREE(_claim);
+ return false;
+ }
+ /*
+ * The values array is actually an array of pointers to
+ * values, even when the values are ints or bools.
+ */
+ _claim->values = talloc_array(_claim, union claim_values, value_count);
+ if (_claim->values == NULL) {
+ TALLOC_FREE(_claim);
+ return false;
+ }
+ if (! is_comp) {
+ /* there is one value, not a list */
+ ok = ace_token_to_claim_v1_offset(_claim,
+ tok,
+ _claim,
+ 0);
+ if (! ok) {
+ TALLOC_FREE(_claim);
+ return false;
+ }
+ } else {
+ /* a composite list of values */
+ for (i = 0; i < value_count; i++) {
+ struct ace_condition_token *t = &tok->data.composite.tokens[i];
+ ok = ace_token_to_claim_v1_offset(mem_ctx,
+ t,
+ _claim,
+ i);
+ if (! ok) {
+ TALLOC_FREE(_claim);
+ return false;
+ }
+ }
+ }
+
+
+ if (_claim->value_type == CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64) {
+ /*
+ * Conditional ACE tokens don't have a UINT type but
+ * claims do. Windows tends to use UINT types in
+ * claims when it can, so so do we.
+ */
+ bool could_be_uint = true;
+ for (i = 0; i < value_count; i++) {
+ if (*_claim->values[i].int_value < 0) {
+ could_be_uint = false;
+ break;
+ }
+ }
+ if (could_be_uint) {
+ _claim->value_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64;
+ }
+ }
+
+ *claim = _claim;
+ return true;
+}
+
+
+
+static bool claim_v1_copy(
+ TALLOC_CTX *mem_ctx,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *dest,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *src)
+{
+ DATA_BLOB blob = {0};
+ enum ndr_err_code ndr_err;
+
+ /*
+ * FIXME, could be more efficient! but copying these
+ * structures is fiddly, and it might be worth coming up
+ * with a better API for adding claims.
+ */
+
+ ndr_err = ndr_push_struct_blob(
+ &blob, mem_ctx, src,
+ (ndr_push_flags_fn_t)ndr_push_CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return false;
+ }
+
+ ndr_err = ndr_pull_struct_blob(
+ &blob, mem_ctx, dest,
+ (ndr_pull_flags_fn_t)ndr_pull_CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(blob.data);
+ return false;
+ }
+ TALLOC_FREE(blob.data);
+ return true;
+}
+
+
+
+bool add_claim_to_token(TALLOC_CTX *mem_ctx,
+ struct security_token *token,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ const char *claim_type)
+{
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *tmp = NULL;
+ NTSTATUS status;
+ uint32_t *n = NULL;
+ bool ok;
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 **list = NULL;
+ if (strcmp(claim_type, "device") == 0) {
+ n = &token->num_device_claims;
+ list = &token->device_claims;
+ } else if (strcmp(claim_type, "local") == 0) {
+ n = &token->num_local_claims;
+ list = &token->local_claims;
+ } else if (strcmp(claim_type, "user") == 0) {
+ n = &token->num_user_claims;
+ list = &token->user_claims;
+ } else {
+ return false;
+ }
+ if ((*n) == UINT32_MAX) {
+ return false;
+ }
+
+ tmp = talloc_realloc(mem_ctx,
+ *list,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1,
+ (*n) + 1);
+ if (tmp == NULL) {
+ return false;
+ }
+
+ ok = claim_v1_copy(mem_ctx, &tmp[*n], claim);
+ if (! ok ) {
+ TALLOC_FREE(tmp);
+ return false;
+ }
+
+ status = claim_v1_check_and_sort(tmp, &tmp[*n],
+ claim->flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("resource attribute claim sort failed with %s\n",
+ nt_errstr(status));
+ TALLOC_FREE(tmp);
+ return false;
+ }
+
+ (*n)++;
+ *list = tmp;
+ return true;
+}
+
+
+static NTSTATUS claim_v1_check_and_sort_boolean(
+ TALLOC_CTX *mem_ctx,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim)
+{
+ /*
+ * There are so few valid orders in a boolean claim that we can
+ * enumerate them all.
+ */
+ switch (claim->value_count) {
+ case 0:
+ return NT_STATUS_OK;
+ case 1:
+ if (*claim->values[0].uint_value == 0 ||
+ *claim->values[0].uint_value == 1) {
+ return NT_STATUS_OK;
+ }
+ break;
+ case 2:
+ if (*claim->values[0].uint_value == 1) {
+ /* switch the order. */
+ *claim->values[0].uint_value = *claim->values[1].uint_value;
+ *claim->values[1].uint_value = 1;
+ }
+ if (*claim->values[0].uint_value == 0 &&
+ *claim->values[1].uint_value == 1) {
+ return NT_STATUS_OK;
+ }
+ break;
+ default:
+ /* 3 or more must have duplicates. */
+ break;
+ }
+ return NT_STATUS_INVALID_PARAMETER;
+}
+
+
+struct claim_sort_context {
+ uint16_t value_type;
+ bool failed;
+ bool case_sensitive;
+};
+
+static int claim_sort_cmp(const union claim_values *lhs,
+ const union claim_values *rhs,
+ struct claim_sort_context *ctx)
+{
+ /*
+ * These comparisons have to match those used in
+ * conditional_ace.c.
+ */
+ int cmp;
+
+ switch (ctx->value_type) {
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
+ {
+ /*
+ * We sort as signed integers, even for uint64,
+ * because a) we don't actually care about the true
+ * order, just uniqueness, and b) the conditional ACEs
+ * only know of signed values.
+ */
+ int64_t a, b;
+ if (ctx->value_type == CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64) {
+ a = *lhs->int_value;
+ b = *rhs->int_value;
+ } else {
+ a = (int64_t)*lhs->uint_value;
+ b = (int64_t)*rhs->uint_value;
+ }
+ if (a < b) {
+ return -1;
+ }
+ if (a == b) {
+ return 0;
+ }
+ return 1;
+ }
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
+ {
+ const char *a = lhs->string_value;
+ const char *b = rhs->string_value;
+ if (ctx->case_sensitive) {
+ return strcmp(a, b);
+ }
+ return strcasecmp_m(a, b);
+ }
+
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_SID:
+ {
+ /*
+ * The blobs in a claim are "S-1-.." strings, not struct
+ * dom_sid as used in conditional ACEs, and to sort them the
+ * same as ACEs we need to make temporary structs.
+ *
+ * We don't accept SID claims over the wire -- these
+ * are resource attribute ACEs only.
+ */
+ struct dom_sid a, b;
+ bool lhs_ok, rhs_ok;
+
+ lhs_ok = blob_string_sid_to_sid(lhs->sid_value, &a);
+ rhs_ok = blob_string_sid_to_sid(rhs->sid_value, &b);
+ if (!(lhs_ok && rhs_ok)) {
+ ctx->failed = true;
+ return -1;
+ }
+ cmp = dom_sid_compare(&a, &b);
+ return cmp;
+ }
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:
+ {
+ const DATA_BLOB *a = lhs->octet_value;
+ const DATA_BLOB *b = rhs->octet_value;
+ return data_blob_cmp(a, b);
+ }
+ default:
+ ctx->failed = true;
+ break;
+ }
+ return -1;
+}
+
+
+NTSTATUS claim_v1_check_and_sort(TALLOC_CTX *mem_ctx,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ bool case_sensitive)
+{
+ bool ok;
+ uint32_t i;
+ struct claim_sort_context sort_ctx = {
+ .failed = false,
+ .value_type = claim->value_type,
+ .case_sensitive = case_sensitive
+ };
+
+ /*
+ * It could be that the values array contains a NULL pointer, in which
+ * case we don't need to worry about what type it is.
+ */
+ for (i = 0; i < claim->value_count; i++) {
+ if (claim->values[i].int_value == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ if (claim->value_type == CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN) {
+ NTSTATUS status = claim_v1_check_and_sort_boolean(mem_ctx, claim);
+ if (NT_STATUS_IS_OK(status)) {
+ claim->flags |= CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED;
+ }
+ return status;
+ }
+
+ ok = stable_sort_talloc_r(mem_ctx,
+ claim->values,
+ claim->value_count,
+ sizeof(union claim_values),
+ (samba_compare_with_context_fn_t)claim_sort_cmp,
+ &sort_ctx);
+ if (!ok) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (sort_ctx.failed) {
+ /* this failure probably means a bad SID string */
+ DBG_WARNING("claim sort of %"PRIu32" members, type %"PRIu16" failed\n",
+ claim->value_count,
+ claim->value_type);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ for (i = 1; i < claim->value_count; i++) {
+ int cmp = claim_sort_cmp(&claim->values[i - 1],
+ &claim->values[i],
+ &sort_ctx);
+ if (cmp == 0) {
+ DBG_WARNING("duplicate values in claim\n");
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ if (cmp > 0) {
+ DBG_ERR("claim sort failed!\n");
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+ if (case_sensitive) {
+ claim->flags |= CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
+ }
+ claim->flags |= CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED;
+ return NT_STATUS_OK;
+}
+
+
+NTSTATUS token_claims_to_claims_v1(TALLOC_CTX *mem_ctx,
+ const struct CLAIMS_SET *claims_set,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 **out_claims,
+ uint32_t *out_n_claims)
+{
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claims = NULL;
+ uint32_t n_claims = 0;
+ uint32_t expected_n_claims = 0;
+ uint32_t i;
+ NTSTATUS status;
+
+ if (out_claims == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ if (out_n_claims == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ *out_claims = NULL;
+ *out_n_claims = 0;
+
+ if (claims_set == NULL) {
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * The outgoing number of claims is (at most) the sum of the
+ * claims_counts of each claims_array.
+ */
+ for (i = 0; i < claims_set->claims_array_count; ++i) {
+ uint32_t count = claims_set->claims_arrays[i].claims_count;
+ expected_n_claims += count;
+ if (expected_n_claims < count) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ claims = talloc_array(mem_ctx,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1,
+ expected_n_claims);
+ if (claims == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < claims_set->claims_array_count; ++i) {
+ const struct CLAIMS_ARRAY *claims_array = &claims_set->claims_arrays[i];
+ uint32_t j;
+
+ switch (claims_array->claims_source_type) {
+ case CLAIMS_SOURCE_TYPE_AD:
+ case CLAIMS_SOURCE_TYPE_CERTIFICATE:
+ break;
+ default:
+ /* Ignore any claims of a type we don’t recognize. */
+ continue;
+ }
+
+ for (j = 0; j < claims_array->claims_count; ++j) {
+ const struct CLAIM_ENTRY *claim_entry = &claims_array->claim_entries[j];
+ const char *name = NULL;
+ union claim_values *claim_values = NULL;
+ uint32_t n_values;
+ enum security_claim_value_type value_type;
+
+ switch (claim_entry->type) {
+ case CLAIM_TYPE_INT64:
+ {
+ const struct CLAIM_INT64 *values = &claim_entry->values.claim_int64;
+ uint32_t k;
+ int64_t *claim_values_int64 = NULL;
+
+ n_values = values->value_count;
+ value_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64;
+
+ claim_values = talloc_array(claims,
+ union claim_values,
+ n_values);
+ if (claim_values == NULL) {
+ talloc_free(claims);
+ return NT_STATUS_NO_MEMORY;
+ }
+ claim_values_int64 = talloc_array(claims,
+ int64_t,
+ n_values);
+ if (claim_values_int64 == NULL) {
+ talloc_free(claims);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (k = 0; k < n_values; ++k) {
+ claim_values_int64[k] = values->values[k];
+ claim_values[k].int_value = &claim_values_int64[k];
+ }
+
+ break;
+ }
+ case CLAIM_TYPE_UINT64:
+ case CLAIM_TYPE_BOOLEAN:
+ {
+ const struct CLAIM_UINT64 *values = &claim_entry->values.claim_uint64;
+ uint32_t k;
+ uint64_t *claim_values_uint64 = NULL;
+
+ n_values = values->value_count;
+ value_type = (claim_entry->type == CLAIM_TYPE_UINT64)
+ ? CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64
+ : CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN;
+
+ claim_values = talloc_array(claims,
+ union claim_values,
+ n_values);
+ if (claim_values == NULL) {
+ talloc_free(claims);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ claim_values_uint64 = talloc_array(claims,
+ uint64_t,
+ n_values);
+ if (claim_values_uint64 == NULL) {
+ talloc_free(claims);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (k = 0; k < n_values; ++k) {
+ claim_values_uint64[k] = values->values[k];
+ claim_values[k].uint_value = &claim_values_uint64[k];
+ }
+
+ break;
+ }
+ case CLAIM_TYPE_STRING:
+ {
+ const struct CLAIM_STRING *values = &claim_entry->values.claim_string;
+ uint32_t k, m;
+ bool seen_empty = false;
+ n_values = values->value_count;
+ value_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING;
+
+ claim_values = talloc_array(claims,
+ union claim_values,
+ n_values);
+ if (claim_values == NULL) {
+ talloc_free(claims);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ m = 0;
+ for (k = 0; k < n_values; ++k) {
+ const char *string_value = NULL;
+
+ if (values->values[k] != NULL) {
+ string_value = talloc_strdup(claim_values, values->values[k]);
+ if (string_value == NULL) {
+ talloc_free(claims);
+ return NT_STATUS_NO_MEMORY;
+ }
+ claim_values[m].string_value = string_value;
+ m++;
+ } else {
+ /*
+ * We allow one NULL string
+ * per claim, but not two,
+ * because two would be a
+ * duplicate, and we don't
+ * want those (duplicates in
+ * actual values are checked
+ * later).
+ */
+ if (seen_empty) {
+ talloc_free(claims);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ seen_empty = true;
+ }
+ }
+ n_values = m;
+ break;
+ }
+ default:
+ /*
+ * Other claim types are unsupported — just skip
+ * them.
+ */
+ continue;
+ }
+
+ if (claim_entry->id != NULL) {
+ name = talloc_strdup(claims, claim_entry->id);
+ if (name == NULL) {
+ talloc_free(claims);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ claims[n_claims] = (struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1) {
+ .name = name,
+ .value_type = value_type,
+ .flags = 0,
+ .value_count = n_values,
+ .values = claim_values,
+ };
+
+ status = claim_v1_check_and_sort(claims, &claims[n_claims],
+ false);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(claims);
+ DBG_WARNING("claim sort and uniqueness test failed with %s\n",
+ nt_errstr(status));
+ return status;
+ }
+ n_claims++;
+ }
+ }
+ *out_claims = claims;
+ *out_n_claims = n_claims;
+
+ return NT_STATUS_OK;
+}
diff --git a/libcli/security/claims-conversions.h b/libcli/security/claims-conversions.h
new file mode 100644
index 0000000..78d8e91
--- /dev/null
+++ b/libcli/security/claims-conversions.h
@@ -0,0 +1,60 @@
+/*
+ * Unix SMB implementation.
+ * Utility functions for converting between claims formats.
+ *
+ * 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/>.
+ */
+
+#ifndef LIBCLI_SECURITY_CLAIMS_CONVERSIONS_H
+#define LIBCLI_SECURITY_CLAIMS_CONVERSIONS_H
+
+#include "replace.h"
+#include <talloc.h>
+#include "libcli/util/ntstatus.h"
+
+struct CLAIMS_SET;
+struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1;
+struct ace_condition_token;
+struct security_token;
+
+bool claim_v1_to_ace_token(TALLOC_CTX *mem_ctx,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ struct ace_condition_token *result);
+
+bool ace_token_to_claim_v1(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const struct ace_condition_token *tok,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 **claim,
+ uint32_t flags);
+
+bool add_claim_to_token(TALLOC_CTX *mem_ctx,
+ struct security_token *token,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ const char *claim_type);
+
+NTSTATUS token_claims_to_claims_v1(TALLOC_CTX *mem_ctx,
+ const struct CLAIMS_SET *claims_set,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 **out_claims,
+ uint32_t *out_n_claims);
+
+bool claim_v1_to_ace_composite_unchecked(TALLOC_CTX *mem_ctx,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ struct ace_condition_token *result);
+
+NTSTATUS claim_v1_check_and_sort(
+ TALLOC_CTX *mem_ctx,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ bool case_sensitive);
+
+#endif /* LIBCLI_SECURITY_CLAIMS_CONVERSIONS_H */
diff --git a/libcli/security/conditional_ace.c b/libcli/security/conditional_ace.c
new file mode 100644
index 0000000..158c8ec
--- /dev/null
+++ b/libcli/security/conditional_ace.c
@@ -0,0 +1,2550 @@
+/*
+ * Unix SMB implementation.
+ * Functions for understanding conditional ACEs
+ *
+ * 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 "replace.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/ndr_conditional_ace.h"
+#include "librpc/gen_ndr/conditional_ace.h"
+#include "libcli/security/security.h"
+#include "libcli/security/conditional_ace.h"
+#include "libcli/security/claims-conversions.h"
+#include "lib/util/tsort.h"
+#include "lib/util/debug.h"
+#include "lib/util/bytearray.h"
+#include "lib/util/talloc_stack.h"
+#include "util/discard.h"
+#include "lib/util/stable_sort.h"
+/*
+ * Conditional ACE logic truth tables.
+ *
+ * Conditional ACES use a ternary logic, with "unknown" as well as true and
+ * false. The ultimate meaning of unknown depends on the context; in a deny
+ * ace, unknown means yes, in an allow ace, unknown means no. That is, we
+ * treat unknown results with maximum suspicion.
+ *
+ * AND true false unknown
+ * true T F ?
+ * false F F F
+ * unknown ? F ?
+ *
+ * OR true false unknown
+ * true T T T
+ * false T F ?
+ * unknown T ? ?
+ *
+ * NOT
+ * true F
+ * false T
+ * unknown ?
+ *
+ * This can be summed up by saying unknown values taint the result except in
+ * the cases where short circuit evaluation could apply (true OR anything,
+ * false AND anything, which hold their value).
+ *
+ * What counts as unknown
+ *
+ * - NULL attributes.
+ * - certain comparisons between incompatible types
+ *
+ * What counts as false
+ *
+ * - zero
+ * - empty strings
+ *
+ * An error means the entire expression is unknown.
+ */
+
+
+static bool check_integer_range(const struct ace_condition_token *tok)
+{
+ int64_t val = tok->data.int64.value;
+ switch (tok->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ if (val < -128 || val > 127) {
+ return false;
+ }
+ break;
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ if (val < INT16_MIN || val > INT16_MAX) {
+ return false;
+ }
+ break;
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ if (val < INT32_MIN || val > INT32_MAX) {
+ return false;
+ }
+ break;
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ /* val has these limits naturally */
+ break;
+ default:
+ return false;
+ }
+
+ if (tok->data.int64.base != CONDITIONAL_ACE_INT_BASE_8 &&
+ tok->data.int64.base != CONDITIONAL_ACE_INT_BASE_10 &&
+ tok->data.int64.base != CONDITIONAL_ACE_INT_BASE_16) {
+ return false;
+ }
+ if (tok->data.int64.sign != CONDITIONAL_ACE_INT_SIGN_POSITIVE &&
+ tok->data.int64.sign != CONDITIONAL_ACE_INT_SIGN_NEGATIVE &&
+ tok->data.int64.sign != CONDITIONAL_ACE_INT_SIGN_NONE) {
+ return false;
+ }
+ return true;
+}
+
+
+static ssize_t pull_integer(TALLOC_CTX *mem_ctx,
+ uint8_t *data, size_t length,
+ struct ace_condition_int *tok)
+{
+ ssize_t bytes_used;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB v = data_blob_const(data, length);
+ struct ndr_pull *ndr = ndr_pull_init_blob(&v, mem_ctx);
+ if (ndr == NULL) {
+ return -1;
+ }
+ ndr_err = ndr_pull_ace_condition_int(ndr, NDR_SCALARS|NDR_BUFFERS, tok);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(ndr);
+ return -1;
+ }
+ bytes_used = ndr->offset;
+ TALLOC_FREE(ndr);
+ return bytes_used;
+}
+
+static ssize_t push_integer(uint8_t *data, size_t available,
+ const struct ace_condition_int *tok)
+{
+ enum ndr_err_code ndr_err;
+ DATA_BLOB v;
+ ndr_err = ndr_push_struct_blob(&v, NULL,
+ tok,
+ (ndr_push_flags_fn_t)ndr_push_ace_condition_int);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return -1;
+ }
+ if (available < v.length) {
+ talloc_free(v.data);
+ return -1;
+ }
+ memcpy(data, v.data, v.length);
+ talloc_free(v.data);
+ return v.length;
+}
+
+
+static ssize_t pull_unicode(TALLOC_CTX *mem_ctx,
+ uint8_t *data, size_t length,
+ struct ace_condition_unicode *tok)
+{
+ ssize_t bytes_used;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB v = data_blob_const(data, length);
+ struct ndr_pull *ndr = ndr_pull_init_blob(&v, mem_ctx);
+ if (ndr == NULL) {
+ return -1;
+ }
+ ndr_err = ndr_pull_ace_condition_unicode(ndr, NDR_SCALARS|NDR_BUFFERS, tok);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(ndr);
+ return -1;
+ }
+ bytes_used = ndr->offset;
+ TALLOC_FREE(ndr);
+ return bytes_used;
+}
+
+static ssize_t push_unicode(uint8_t *data, size_t available,
+ const struct ace_condition_unicode *tok)
+{
+ enum ndr_err_code ndr_err;
+ DATA_BLOB v;
+ ndr_err = ndr_push_struct_blob(&v, NULL,
+ tok,
+ (ndr_push_flags_fn_t)ndr_push_ace_condition_unicode);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return -1;
+ }
+ if (available < v.length) {
+ talloc_free(v.data);
+ return -1;
+ }
+ memcpy(data, v.data, v.length);
+ talloc_free(v.data);
+ return v.length;
+}
+
+
+static ssize_t pull_bytes(TALLOC_CTX *mem_ctx,
+ uint8_t *data, size_t length,
+ DATA_BLOB *tok)
+{
+ ssize_t bytes_used;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB v = data_blob_const(data, length);
+ struct ndr_pull *ndr = ndr_pull_init_blob(&v, mem_ctx);
+ if (ndr == NULL) {
+ return -1;
+ }
+ ndr_err = ndr_pull_DATA_BLOB(ndr, NDR_SCALARS|NDR_BUFFERS, tok);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(ndr);
+ return -1;
+ }
+ bytes_used = ndr->offset;
+ talloc_free(ndr);
+ return bytes_used;
+}
+
+static ssize_t push_bytes(uint8_t *data, size_t available,
+ const DATA_BLOB *tok)
+{
+ size_t offset;
+ enum ndr_err_code ndr_err;
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct ndr_push *ndr = ndr_push_init_ctx(frame);
+ if (ndr == NULL) {
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ ndr_err = ndr_push_DATA_BLOB(ndr, NDR_SCALARS|NDR_BUFFERS, *tok);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (available < ndr->offset) {
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ memcpy(data, ndr->data, ndr->offset);
+ offset = ndr->offset;
+ TALLOC_FREE(frame);
+ return offset;
+}
+
+static ssize_t pull_sid(TALLOC_CTX *mem_ctx,
+ uint8_t *data, size_t length,
+ struct ace_condition_sid *tok)
+{
+ ssize_t bytes_used;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB v = data_blob_const(data, length);
+ struct ndr_pull *ndr = ndr_pull_init_blob(&v, mem_ctx);
+ if (ndr == NULL) {
+ return -1;
+ }
+ ndr->flags |= LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES;
+
+ ndr_err = ndr_pull_ace_condition_sid(ndr, NDR_SCALARS|NDR_BUFFERS, tok);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(ndr);
+ return -1;
+ }
+ bytes_used = ndr->offset;
+ TALLOC_FREE(ndr);
+ return bytes_used;
+}
+
+static ssize_t push_sid(uint8_t *data, size_t available,
+ const struct ace_condition_sid *tok)
+{
+ enum ndr_err_code ndr_err;
+ DATA_BLOB v;
+ ndr_err = ndr_push_struct_blob(&v, NULL,
+ tok,
+ (ndr_push_flags_fn_t)ndr_push_ace_condition_sid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return -1;
+ }
+ if (available < v.length) {
+ talloc_free(v.data);
+ return -1;
+ }
+ memcpy(data, v.data, v.length);
+ talloc_free(v.data);
+ return v.length;
+}
+
+
+static ssize_t pull_composite(TALLOC_CTX *mem_ctx,
+ uint8_t *data, size_t length,
+ struct ace_condition_composite *tok)
+{
+ size_t i, j;
+ size_t alloc_length;
+ size_t byte_size;
+ struct ace_condition_token *tokens = NULL;
+ if (length < 4) {
+ return -1;
+ }
+ byte_size = PULL_LE_U32(data, 0);
+ if (byte_size > length - 4) {
+ return -1;
+ }
+ /*
+ * There is a list of other literal tokens (possibly including nested
+ * composites), which we will store in an array.
+ *
+ * This array can *only* be literals.
+ */
+ alloc_length = byte_size;
+ tokens = talloc_array(mem_ctx,
+ struct ace_condition_token,
+ alloc_length);
+ if (tokens == NULL) {
+ return -1;
+ }
+ byte_size += 4;
+ i = 4;
+ j = 0;
+ while (i < byte_size) {
+ struct ace_condition_token *el = &tokens[j];
+ ssize_t consumed;
+ uint8_t *el_data = NULL;
+ size_t available;
+ bool ok;
+ *el = (struct ace_condition_token) { .type = data[i] };
+ i++;
+
+ el_data = data + i;
+ available = byte_size - i;
+
+ switch (el->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ consumed = pull_integer(mem_ctx,
+ el_data,
+ available,
+ &el->data.int64);
+ ok = check_integer_range(el);
+ if (! ok) {
+ goto error;
+ }
+ break;
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ consumed = pull_unicode(mem_ctx,
+ el_data,
+ available,
+ &el->data.unicode);
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ consumed = pull_bytes(mem_ctx,
+ el_data,
+ available,
+ &el->data.bytes);
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_SID:
+ consumed = pull_sid(mem_ctx,
+ el_data,
+ available,
+ &el->data.sid);
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ DBG_ERR("recursive composite tokens in conditional "
+ "ACEs are not currently supported\n");
+ goto error;
+ default:
+ goto error;
+ }
+
+ if (consumed < 0 || consumed + i > length) {
+ goto error;
+ }
+ i += consumed;
+ j++;
+ if (j == UINT16_MAX) {
+ talloc_free(tokens);
+ return -1;
+ }
+ if (j == alloc_length) {
+ struct ace_condition_token *new_tokens = NULL;
+
+ alloc_length += 5;
+ new_tokens = talloc_realloc(mem_ctx,
+ tokens,
+ struct ace_condition_token,
+ alloc_length);
+
+ if (new_tokens == NULL) {
+ goto error;
+ }
+ tokens = new_tokens;
+ }
+ }
+ tok->n_members = j;
+ tok->tokens = tokens;
+ return byte_size;
+error:
+ talloc_free(tokens);
+ return -1;
+}
+
+
+static ssize_t push_composite(uint8_t *data, size_t length,
+ const struct ace_condition_composite *tok)
+{
+ size_t i;
+ uint8_t *byte_length_ptr;
+ size_t used = 0;
+ if (length < 4) {
+ return -1;
+ }
+ /*
+ * We have no idea what the eventual length will be, so we keep a
+ * pointer to write it in at the end.
+ */
+ byte_length_ptr = data;
+ PUSH_LE_U32(data, 0, 0);
+ used = 4;
+
+ for (i = 0; i < tok->n_members && used < length; i++) {
+ struct ace_condition_token *el = &tok->tokens[i];
+ ssize_t consumed;
+ uint8_t *el_data = NULL;
+ size_t available;
+ bool ok;
+ data[used] = el->type;
+ used++;
+ if (used == length) {
+ /*
+ * used == length is not expected here; the token
+ * types that only have an opcode and no data are not
+ * literals that can be in composites.
+ */
+ return -1;
+ }
+ el_data = data + used;
+ available = length - used;
+
+ switch (el->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ ok = check_integer_range(el);
+ if (! ok) {
+ return -1;
+ }
+ consumed = push_integer(el_data,
+ available,
+ &el->data.int64);
+ break;
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ consumed = push_unicode(el_data,
+ available,
+ &el->data.unicode);
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ consumed = push_bytes(el_data,
+ available,
+ &el->data.bytes);
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_SID:
+ consumed = push_sid(el_data,
+ available,
+ &el->data.sid);
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ consumed = push_composite(el_data,
+ available,
+ &el->data.composite);
+ break;
+
+ default:
+ return -1;
+ }
+
+ if (consumed < 0) {
+ return -1;
+ }
+ used += consumed;
+ }
+ if (used > length) {
+ return -1;
+ }
+
+ PUSH_LE_U32(byte_length_ptr, 0, used - 4);
+ return used;
+}
+
+static ssize_t pull_end_padding(uint8_t *data, size_t length)
+{
+ /*
+ * We just check that we have the right kind of number of zero
+ * bytes. The blob must end on a multiple of 4. One zero byte
+ * has already been swallowed as tok->type, which sends us
+ * here, so we expect 1 or two more -- total padding is 0, 1,
+ * 2, or 3.
+ *
+ * zero is also called CONDITIONAL_ACE_TOKEN_INVALID_OR_PADDING.
+ */
+ ssize_t i;
+ if (length > 2) {
+ return -1;
+ }
+ for (i = 0; i < length; i++) {
+ if (data[i] != 0) {
+ return -1;
+ }
+ }
+ return length;
+}
+
+
+struct ace_condition_script *parse_conditional_ace(TALLOC_CTX *mem_ctx,
+ DATA_BLOB data)
+{
+ size_t i, j;
+ struct ace_condition_token *tokens = NULL;
+ size_t alloc_length;
+ struct ace_condition_script *program = NULL;
+
+ if (data.length < 4 ||
+ data.data[0] != 'a' ||
+ data.data[1] != 'r' ||
+ data.data[2] != 't' ||
+ data.data[3] != 'x') {
+ /*
+ * lacks the "artx" conditional ace identifier magic.
+ * NULL returns will deny access.
+ */
+ return NULL;
+ }
+ if (data.length > CONDITIONAL_ACE_MAX_LENGTH ||
+ (data.length & 3) != 0) {
+ /*
+ * >= 64k or non-multiples of 4 are not possible in the ACE
+ * wire format.
+ */
+ return NULL;
+ }
+
+ program = talloc(mem_ctx, struct ace_condition_script);
+ if (program == NULL) {
+ return NULL;
+ }
+
+ /*
+ * We will normally end up with fewer than data.length tokens, as
+ * values are stored in multiple bytes (all integers are 10 bytes,
+ * strings and attributes are utf16 + length, SIDs are SID-size +
+ * length, etc). But operators are one byte, so something like
+ * !(!(!(!(!(!(x)))))) -- where each '!(..)' is one byte -- will bring
+ * the number of tokens close to the number of bytes.
+ *
+ * This is all to say we're guessing a token length that hopes to
+ * avoid reallocs without wasting too much up front.
+ */
+ alloc_length = data.length / 2 + 1;
+ tokens = talloc_array(program,
+ struct ace_condition_token,
+ alloc_length);
+ if (tokens == NULL) {
+ TALLOC_FREE(program);
+ return NULL;
+ }
+
+ i = 4;
+ j = 0;
+ while(i < data.length) {
+ struct ace_condition_token *tok = &tokens[j];
+ ssize_t consumed = 0;
+ uint8_t *tok_data = NULL;
+ size_t available;
+ bool ok;
+ tok->type = data.data[i];
+ tok->flags = 0;
+ i++;
+ tok_data = data.data + i;
+ available = data.length - i;
+
+ switch (tok->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ consumed = pull_integer(program,
+ tok_data,
+ available,
+ &tok->data.int64);
+ ok = check_integer_range(tok);
+ if (! ok) {
+ goto fail;
+ }
+ break;
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ /*
+ * The next four are pulled as unicode, but are
+ * processed as user attribute look-ups.
+ */
+ case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
+ case CONDITIONAL_ACE_USER_ATTRIBUTE:
+ case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
+ case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
+ consumed = pull_unicode(program,
+ tok_data,
+ available,
+ &tok->data.unicode);
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ consumed = pull_bytes(program,
+ tok_data,
+ available,
+ &tok->data.bytes);
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_SID:
+ consumed = pull_sid(program,
+ tok_data,
+ available,
+ &tok->data.sid);
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ consumed = pull_composite(program,
+ tok_data,
+ available,
+ &tok->data.composite);
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
+ /*
+ * these require a SID or composite SID list operand,
+ * and we could check that now in most cases.
+ */
+ break;
+ /* binary relational operators */
+ case CONDITIONAL_ACE_TOKEN_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_LESS_THAN:
+ case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
+ case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_ANY_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
+ /* unary logical operators */
+ case CONDITIONAL_ACE_TOKEN_EXISTS:
+ case CONDITIONAL_ACE_TOKEN_NOT_EXISTS:
+ case CONDITIONAL_ACE_TOKEN_NOT:
+ /* binary logical operators */
+ case CONDITIONAL_ACE_TOKEN_AND:
+ case CONDITIONAL_ACE_TOKEN_OR:
+ break;
+ case CONDITIONAL_ACE_TOKEN_INVALID_OR_PADDING:
+ /* this is only valid at the end */
+ consumed = pull_end_padding(tok_data,
+ available);
+ j--; /* don't add this token */
+ break;
+ default:
+ goto fail;
+ }
+
+ if (consumed < 0) {
+ goto fail;
+ }
+ if (consumed + i < i || consumed + i > data.length) {
+ goto fail;
+ }
+ i += consumed;
+ j++;
+ if (j == alloc_length) {
+ alloc_length *= 2;
+ tokens = talloc_realloc(program,
+ tokens,
+ struct ace_condition_token,
+ alloc_length);
+ if (tokens == NULL) {
+ goto fail;
+ }
+ }
+ }
+ program->length = j;
+ program->tokens = talloc_realloc(program,
+ tokens,
+ struct ace_condition_token,
+ program->length + 1);
+ if (program->tokens == NULL) {
+ goto fail;
+ }
+ /*
+ * When interpreting the program we will need a stack, which in the
+ * very worst case can be as deep as the program is long.
+ */
+ program->stack = talloc_array(program,
+ struct ace_condition_token,
+ program->length + 1);
+ if (program->stack == NULL) {
+ goto fail;
+ }
+
+ return program;
+ fail:
+ talloc_free(program);
+ return NULL;
+ }
+
+
+static bool claim_lookup_internal(
+ TALLOC_CTX *mem_ctx,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ struct ace_condition_token *result)
+{
+ bool ok = claim_v1_to_ace_token(mem_ctx, claim, result);
+ return ok;
+}
+
+
+static bool resource_claim_lookup(
+ TALLOC_CTX *mem_ctx,
+ const struct ace_condition_token *op,
+ const struct security_descriptor *sd,
+ struct ace_condition_token *result)
+{
+ /*
+ * For a @Resource.attr, the claims come from a resource ACE
+ * in the object's SACL. That's why we need a security descriptor.
+ *
+ * If there is no matching resource ACE, a NULL result is returned,
+ * which should compare UNKNOWN to anything. The NULL will have the
+ * CONDITIONAL_ACE_FLAG_NULL_MEANS_ERROR flag set if it seems failure
+ * is not simply due to the sought claim not existing. This is useful for
+ * the Exists and Not_Exists operators.
+ */
+ size_t i;
+ struct ace_condition_unicode name;
+
+ result->type = CONDITIONAL_ACE_SAMBA_RESULT_NULL;
+
+ if (op->type != CONDITIONAL_ACE_RESOURCE_ATTRIBUTE) {
+ /* what are we even doing here? */
+ result->type = CONDITIONAL_ACE_SAMBA_RESULT_ERROR;
+ return false;
+ }
+
+ name = op->data.resource_attr;
+
+ if (sd->sacl == NULL) {
+ DBG_NOTICE("Resource attribute ACE '%s' not found, "
+ "because there is no SACL\n",
+ name.value);
+ return true;
+ }
+
+ for (i = 0; i < sd->sacl->num_aces; i++) {
+ struct security_ace *ace = &sd->sacl->aces[i];
+ bool ok;
+
+ if (ace->type != SEC_ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE) {
+ continue;
+ }
+ if (strcasecmp_m(name.value,
+ ace->coda.claim.name) != 0) {
+ continue;
+ }
+ /* this is the one */
+ ok = claim_lookup_internal(mem_ctx, &ace->coda.claim, result);
+ if (ok) {
+ return true;
+ }
+ }
+ DBG_NOTICE("Resource attribute ACE '%s' not found.\n",
+ name.value);
+ return false;
+}
+
+
+static bool token_claim_lookup(
+ TALLOC_CTX *mem_ctx,
+ const struct security_token *token,
+ const struct ace_condition_token *op,
+ struct ace_condition_token *result)
+{
+ /*
+ * The operator has an attribute name; if there is a claim of
+ * the right type with that name, that is returned as the result.
+ *
+ * XXX what happens otherwise? NULL result?
+ */
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claims = NULL;
+ size_t num_claims;
+ bool ok;
+ const struct ace_condition_unicode *name = NULL;
+ size_t i;
+
+ result->type = CONDITIONAL_ACE_SAMBA_RESULT_NULL;
+
+ switch (op->type) {
+ case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
+ claims = token->local_claims;
+ num_claims = token->num_local_claims;
+ name = &op->data.local_attr;
+ break;
+ case CONDITIONAL_ACE_USER_ATTRIBUTE:
+ claims = token->user_claims;
+ num_claims = token->num_user_claims;
+ name = &op->data.user_attr;
+ break;
+ case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
+ claims = token->device_claims;
+ num_claims = token->num_device_claims;
+ name = &op->data.device_attr;
+ break;
+ default:
+ DBG_WARNING("Conditional ACE claim lookup got bad arg type %u\n",
+ op->type);
+ result->type = CONDITIONAL_ACE_SAMBA_RESULT_ERROR;
+ return false;
+ }
+
+ if (num_claims == 0) {
+ DBG_NOTICE("There are no type %u claims\n", op->type);
+ return false;
+ }
+ if (claims == NULL) {
+ DBG_ERR("Type %u claim list unexpectedly NULL!\n", op->type);
+ result->type = CONDITIONAL_ACE_SAMBA_RESULT_ERROR;
+ return false;
+ }
+ /*
+ * Loop backwards: a later claim will override an earlier one with the
+ * same name.
+ */
+ for (i = num_claims - 1; i < num_claims; i--) {
+ if (claims[i].name == NULL) {
+ DBG_ERR("claim %zu has no name!\n", i);
+ continue;
+ }
+ if (strcasecmp_m(claims[i].name, name->value) == 0) {
+ /* this is the one */
+ ok = claim_lookup_internal(mem_ctx, &claims[i], result);
+ return ok;
+ }
+ }
+ DBG_NOTICE("Claim not found\n");
+ return false;
+}
+
+
+
+
+static bool member_lookup(
+ const struct security_token *token,
+ const struct ace_condition_token *op,
+ const struct ace_condition_token *arg,
+ struct ace_condition_token *result)
+{
+ /*
+ * We need to compare the lists of SIDs in the token with the
+ * SID[s] in the argument. There are 8 combinations of
+ * operation, depending on whether we want to match all or any
+ * of the SIDs, whether we're using the device SIDs or user
+ * SIDs, and whether the operator name starts with "Not_".
+ *
+ * _MEMBER_OF User has all operand SIDs
+ * _DEVICE_MEMBER_OF Device has all operand SIDs
+ * _MEMBER_OF_ANY User has one or more operand SIDs
+ * _DEVICE_MEMBER_OF_ANY Device has one or more operand SIDs
+ *
+ * NOT_* has the effect of !(the operator without NOT_).
+ *
+ * The operand can either be a composite of SIDs or a single SID.
+ * This adds an additional branch.
+ */
+ bool match = false;
+ bool it_is_a_not_op;
+ bool it_is_an_any_op;
+ bool it_is_a_device_op;
+ bool arg_is_a_single_sid;
+ struct dom_sid *sid_array = NULL;
+ size_t num_sids, i, j;
+ const struct dom_sid *sid = NULL;
+
+ result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL;
+ result->data.result.value = ACE_CONDITION_UNKNOWN;
+
+ switch (arg->type) {
+ case CONDITIONAL_ACE_TOKEN_SID:
+ arg_is_a_single_sid = true;
+ break;
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ arg_is_a_single_sid = false;
+ break;
+ default:
+ DBG_WARNING("Conditional ACE Member_Of got bad arg type %u\n",
+ arg->type);
+ return false;
+ }
+
+ switch (op->type) {
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
+ it_is_a_not_op = true;
+ it_is_a_device_op = false;
+ break;
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
+ it_is_a_not_op = true;
+ it_is_a_device_op = true;
+ break;
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
+ it_is_a_not_op = false;
+ it_is_a_device_op = false;
+ break;
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
+ it_is_a_not_op = false;
+ it_is_a_device_op = true;
+ break;
+ default:
+ DBG_WARNING("Conditional ACE Member_Of got bad op type %u\n",
+ op->type);
+ return false;
+ }
+
+ switch (op->type) {
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
+ it_is_an_any_op = true;
+ break;
+ default:
+ it_is_an_any_op = false;
+ }
+
+ if (it_is_a_device_op) {
+ sid_array = token->device_sids;
+ num_sids = token->num_device_sids;
+ } else {
+ sid_array = token->sids;
+ num_sids = token->num_sids;
+ }
+
+ if (arg_is_a_single_sid) {
+ /*
+ * In this case the any and all operations are the
+ * same.
+ */
+ sid = &arg->data.sid.sid;
+ match = false;
+ for (i = 0; i < num_sids; i++) {
+ match = dom_sid_equal(sid, &sid_array[i]);
+ if (match) {
+ break;
+ }
+ }
+ if (it_is_a_not_op) {
+ match = ! match;
+ }
+ if (match) {
+ result->data.result.value = ACE_CONDITION_TRUE;
+ } else {
+ result->data.result.value = ACE_CONDITION_FALSE;
+ }
+ return true;
+ }
+
+ /* This is a composite list (hopefully of SIDs) */
+ if (arg->data.composite.n_members == 0) {
+ DBG_WARNING("Conditional ACE Member_Of argument is empty\n");
+ return false;
+ }
+
+ for (j = 0; j < arg->data.composite.n_members; j++) {
+ const struct ace_condition_token *member =
+ &arg->data.composite.tokens[j];
+ if (member->type != CONDITIONAL_ACE_TOKEN_SID) {
+ DBG_WARNING("Conditional ACE Member_Of argument contains "
+ "non-sid element [%zu]: %u\n",
+ j, member->type);
+ return false;
+ }
+ sid = &member->data.sid.sid;
+ match = false;
+ for (i = 0; i < num_sids; i++) {
+ match = dom_sid_equal(sid, &sid_array[i]);
+ if (match) {
+ break;
+ }
+ }
+ if (it_is_an_any_op) {
+ if (match) {
+ /* we have matched one SID, which is enough */
+ goto apply_not;
+ }
+ } else { /* an all op */
+ if (! match) {
+ /* failing one is enough */
+ goto apply_not;
+ }
+ }
+ }
+ /*
+ * Reaching the end of that loop means either:
+ * 1. it was an ALL op and we never failed to find one, or
+ * 2. it was an ANY op, and we didn't find one.
+ */
+ match = !it_is_an_any_op;
+
+ apply_not:
+ if (it_is_a_not_op) {
+ match = ! match;
+ }
+ if (match) {
+ result->data.result.value = ACE_CONDITION_TRUE;
+ } else {
+ result->data.result.value = ACE_CONDITION_FALSE;
+ }
+
+ return true;
+}
+
+
+static bool ternary_value(
+ const struct ace_condition_token *arg,
+ struct ace_condition_token *result)
+{
+ /*
+ * Find the truth value of the argument, stored in the result token.
+ *
+ * A return value of false means the operation is invalid, and the
+ * result is undefined.
+ */
+ if (arg->type == CONDITIONAL_ACE_SAMBA_RESULT_BOOL) {
+ /* pass through */
+ *result = *arg;
+ return true;
+ }
+
+ result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL;
+ result->data.result.value = ACE_CONDITION_UNKNOWN;
+
+ if (IS_INT_TOKEN(arg)) {
+ /* zero is false */
+ if (arg->data.int64.value == 0) {
+ result->data.result.value = ACE_CONDITION_FALSE;
+ } else {
+ result->data.result.value = ACE_CONDITION_TRUE;
+ }
+ return true;
+ }
+ if (arg->type == CONDITIONAL_ACE_TOKEN_UNICODE) {
+ /* empty is false */
+ if (arg->data.unicode.value[0] == '\0') {
+ result->data.result.value = ACE_CONDITION_FALSE;
+ } else {
+ result->data.result.value = ACE_CONDITION_TRUE;
+ }
+ return true;
+ }
+
+ /*
+ * everything else in UNKNOWN. This includes NULL values (i.e. an
+ * unsuccessful look-up).
+ */
+ result->data.result.value = ACE_CONDITION_UNKNOWN;
+ return true;
+}
+
+static bool not_operator(
+ const struct ace_condition_token *arg,
+ struct ace_condition_token *result)
+{
+ bool ok;
+ if (IS_LITERAL_TOKEN(arg)) {
+ /*
+ * Logic operators don't work on literals.
+ */
+ return false;
+ }
+
+ ok = ternary_value(arg, result);
+ if (! ok) {
+ return false;
+ }
+ if (result->data.result.value == ACE_CONDITION_FALSE) {
+ result->data.result.value = ACE_CONDITION_TRUE;
+ } else if (result->data.result.value == ACE_CONDITION_TRUE) {
+ result->data.result.value = ACE_CONDITION_FALSE;
+ }
+ /* unknown stays unknown */
+ return true;
+}
+
+
+static bool unary_logic_operator(
+ TALLOC_CTX *mem_ctx,
+ const struct security_token *token,
+ const struct ace_condition_token *op,
+ const struct ace_condition_token *arg,
+ const struct security_descriptor *sd,
+ struct ace_condition_token *result)
+{
+
+ bool ok;
+ bool found;
+ struct ace_condition_token claim = {
+ .type = CONDITIONAL_ACE_SAMBA_RESULT_ERROR
+ };
+ if (op->type == CONDITIONAL_ACE_TOKEN_NOT) {
+ return not_operator(arg, result);
+ }
+ result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL;
+ result->data.result.value = ACE_CONDITION_UNKNOWN;
+
+ /*
+ * Not_Exists and Exists require the same work, except we negate the
+ * answer in one case. From [MS-DTYP] 2.4.4.17.7:
+ *
+ * If the type of the operand is "Local Attribute"
+ * If the value is non-null return TRUE
+ * Else return FALSE
+ * Else if the type of the operand is "Resource Attribute"
+ * Return TRUE if value is non-null; FALSE otherwise.
+ * Else return Error
+ */
+ switch (op->type) {
+ case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
+ ok = token_claim_lookup(mem_ctx, token, arg, &claim);
+ /*
+ * "not ok" usually means a failure to find the attribute,
+ * which is the false condition and not an error.
+ *
+ * XXX or do we need an extra flag?
+ */
+ break;
+ case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
+ ok = resource_claim_lookup(mem_ctx, arg, sd, &claim);
+ break;
+ default:
+ return false;
+ }
+
+ /*
+ *
+ */
+
+ if (claim.type != CONDITIONAL_ACE_SAMBA_RESULT_NULL) {
+ found = true;
+ } else if (ok) {
+ found = false;
+ } else {
+ return false;
+ }
+
+
+
+ if (op->type == CONDITIONAL_ACE_TOKEN_NOT_EXISTS) {
+ found = ! found;
+ } else if (op->type != CONDITIONAL_ACE_TOKEN_EXISTS) {
+ /* should not get here */
+ return false;
+ }
+
+ result->data.result.value = found ? ACE_CONDITION_TRUE: ACE_CONDITION_FALSE;
+ return true;
+}
+
+
+
+static bool binary_logic_operator(
+ const struct security_token *token,
+ const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ struct ace_condition_token *result)
+{
+ struct ace_condition_token at, bt;
+ int a, b;
+ bool ok;
+
+ result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL;
+ result->data.result.value = ACE_CONDITION_UNKNOWN;
+
+ if (IS_LITERAL_TOKEN(lhs) || IS_LITERAL_TOKEN(rhs)) {
+ /*
+ * Logic operators don't work on literals.
+ */
+ return false;
+ }
+
+ ok = ternary_value(lhs, &at);
+ if (! ok) {
+ return false;
+ }
+ ok = ternary_value(rhs, &bt);
+ if (! ok) {
+ return false;
+ }
+ a = at.data.result.value;
+ b = bt.data.result.value;
+
+ if (op->type == CONDITIONAL_ACE_TOKEN_AND) {
+ /*
+ * AND true false unknown
+ * true T F ?
+ * false F F F
+ * unknown ? F ?
+ *
+ * unknown unless BOTH true or EITHER false
+ */
+ if (a == ACE_CONDITION_TRUE &&
+ b == ACE_CONDITION_TRUE) {
+ result->data.result.value = ACE_CONDITION_TRUE;
+ return true;
+ }
+ if (a == ACE_CONDITION_FALSE ||
+ b == ACE_CONDITION_FALSE) {
+ result->data.result.value = ACE_CONDITION_FALSE;
+ return true;
+ }
+ /*
+ * Neither value is False, so the result is Unknown,
+ * as set at the start of this function.
+ */
+ return true;
+ }
+ /*
+ * OR true false unknown
+ * true T T T
+ * false T F ?
+ * unknown T ? ?
+ *
+ * unknown unless EITHER true or BOTH false
+ */
+ if (a == ACE_CONDITION_TRUE ||
+ b == ACE_CONDITION_TRUE) {
+ result->data.result.value = ACE_CONDITION_TRUE;
+ return true;
+ }
+ if (a == ACE_CONDITION_FALSE &&
+ b == ACE_CONDITION_FALSE) {
+ result->data.result.value = ACE_CONDITION_FALSE;
+ return true;
+ }
+ return true;
+}
+
+
+static bool tokens_are_comparable(const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs)
+{
+ uint64_t n;
+ /*
+ * we can't compare different types *unless* they are both
+ * integers, or one is a bool and the other is an integer 0 or
+ * 1, and the operator is == or != (or NULL, which for convenience,
+ * is treated as ==).
+ */
+ //XXX actually it says "literal integers", do we need to check flags?
+ if (lhs->type == rhs->type) {
+ return true;
+ }
+
+ if (IS_INT_TOKEN(lhs) && IS_INT_TOKEN(rhs)) {
+ /* don't block e.g. comparing an int32 to an int64 */
+ return true;
+ }
+
+ /* is it == or != */
+ if (op != NULL &&
+ op->type != CONDITIONAL_ACE_TOKEN_EQUAL &&
+ op->type != CONDITIONAL_ACE_TOKEN_NOT_EQUAL) {
+ return false;
+ }
+ /* is one a bool and the other an int? */
+ if (IS_INT_TOKEN(lhs) && IS_BOOL_TOKEN(rhs)) {
+ n = lhs->data.int64.value;
+ } else if (IS_INT_TOKEN(rhs) && IS_BOOL_TOKEN(lhs)) {
+ n = rhs->data.int64.value;
+ } else {
+ return false;
+ }
+ if (n == 0 || n == 1) {
+ return true;
+ }
+ return false;
+}
+
+
+static bool cmp_to_result(const struct ace_condition_token *op,
+ struct ace_condition_token *result,
+ int cmp)
+{
+ bool answer;
+ switch (op->type) {
+ case CONDITIONAL_ACE_TOKEN_EQUAL:
+ answer = cmp == 0;
+ break;
+ case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
+ answer = cmp != 0;
+ break;
+ case CONDITIONAL_ACE_TOKEN_LESS_THAN:
+ answer = cmp < 0;
+ break;
+ case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
+ answer = cmp <= 0;
+ break;
+ case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
+ answer = cmp > 0;
+ break;
+ case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
+ answer = cmp >= 0;
+ break;
+ default:
+ result->data.result.value = ACE_CONDITION_UNKNOWN;
+ return false;
+ }
+ result->data.result.value = \
+ answer ? ACE_CONDITION_TRUE : ACE_CONDITION_FALSE;
+ return true;
+}
+
+
+
+static bool compare_unicode(const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ int *cmp)
+{
+ struct ace_condition_unicode a = lhs->data.unicode;
+ struct ace_condition_unicode b = rhs->data.unicode;
+ /*
+ * Comparison is case-insensitive UNLESS the claim structure
+ * has the case-sensitive flag, which is passed through as a
+ * flag on the token. Usually only the LHS is a claim value,
+ * but in the event that they both are, we allow either to
+ * request case-sensitivity.
+ *
+ * For greater than and less than, the sort order is utf-8 order,
+ * which is not exactly what Windows does, but we don't sort like
+ * Windows does anywhere else either.
+ */
+ uint8_t flags = lhs->flags | rhs->flags;
+ if (flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE) {
+ *cmp = strcmp(a.value, b.value);
+ } else {
+ *cmp = strcasecmp_m(a.value, b.value);
+ }
+ return true;
+}
+
+
+static bool compare_bytes(const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ int *cmp)
+{
+ DATA_BLOB a = lhs->data.bytes;
+ DATA_BLOB b = rhs->data.bytes;
+ *cmp = data_blob_cmp(&a, &b);
+ return true;
+}
+
+
+static bool compare_sids(const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ int *cmp)
+{
+ *cmp = dom_sid_compare(&lhs->data.sid.sid,
+ &rhs->data.sid.sid);
+ return true;
+}
+
+
+static bool compare_ints(const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ int *cmp)
+{
+ int64_t a = lhs->data.int64.value;
+ int64_t b = rhs->data.int64.value;
+
+ if (a < b) {
+ *cmp = -1;
+ } else if (a == b) {
+ *cmp = 0;
+ } else {
+ *cmp = 1;
+ }
+ return true;
+}
+
+
+static bool compare_bools(const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ int *cmp)
+{
+ bool ok;
+ struct ace_condition_token a, b;
+ *cmp = -1;
+
+ if (IS_LITERAL_TOKEN(lhs)) {
+ /*
+ * we can compare a boolean LHS to a literal RHS, but not
+ * vice versa
+ */
+ return false;
+ }
+ ok = ternary_value(lhs, &a);
+ if (! ok) {
+ return false;
+ }
+ ok = ternary_value(rhs, &b);
+ if (! ok) {
+ return false;
+ }
+ if (a.data.result.value == ACE_CONDITION_UNKNOWN ||
+ b.data.result.value == ACE_CONDITION_UNKNOWN) {
+ return false;
+ }
+
+ switch (op->type) {
+ case CONDITIONAL_ACE_TOKEN_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
+ *cmp = a.data.result.value - b.data.result.value;
+ break;
+ default:
+ /* we are not allowing non-equality comparisons with bools */
+ return false;
+ }
+ return true;
+}
+
+
+static bool simple_relational_operator(const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ int *cmp);
+
+
+struct composite_sort_context {
+ bool failed;
+};
+
+static int composite_sort_cmp(const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ struct composite_sort_context *ctx)
+{
+ bool ok;
+ int cmp = -1;
+ /*
+ * simple_relational_operator uses the operator token only to
+ * decide whether the comparison is allowed for the type. In
+ * particular, boolean result and composite arguments can only
+ * be used with equality operators. We want those to fail (we
+ * should not see them here, remembering that claim booleans
+ * become composite integers), so we use a non-equality op.
+ */
+ static const struct ace_condition_token op = {
+ .type = CONDITIONAL_ACE_TOKEN_LESS_THAN
+ };
+
+ ok = simple_relational_operator(&op, lhs, rhs, &cmp);
+ if (ok) {
+ return cmp;
+ }
+ /*
+ * This sort isn't going to work out, but the sort function
+ * will only find out at the end.
+ */
+ ctx->failed = true;
+ return cmp;
+}
+
+
+/*
+ * Return a sorted copy of the composite tokens array.
+ *
+ * The copy is shallow, so the actual string pointers are the same, which is
+ * fine for the purposes of comparison.
+ */
+
+static struct ace_condition_token *composite_sorted_copy(
+ TALLOC_CTX *mem_ctx,
+ const struct ace_condition_composite *c,
+ bool case_sensitive)
+{
+ struct ace_condition_token *copy = NULL;
+ bool ok;
+ size_t i;
+ struct composite_sort_context sort_ctx = {
+ .failed = false
+ };
+
+ /*
+ * Case sensitivity is a bit tricky. Each token can have a flag saying
+ * it should be sorted case-sensitively and when comparing two tokens,
+ * we should respect this flag on either side. The flag can only come
+ * from claims (including resource attribute ACEs), and as there is only
+ * one flag per claim, it must apply the same to all members (in fact we
+ * don't set it on the members, only the composite). So to be sure we
+ * sort in the way we want, we might need to set the flag on all the
+ * members of the copy *before* sorting it.
+ *
+ * When it comes to comparing two composites, we want to be
+ * case-sensitive if either side has the flag. This can have odd
+ * effects. Think of these RA claims:
+ *
+ * (RA;;;;;WD;("foo",TS,0,"a","A"))
+ * (RA;;;;;WD;("bar",TS,2,"a","A")) <-- 2 is the case-sensitive flag
+ * (RA;;;;;WD;("baz",TS,0,"a"))
+ *
+ * (@Resource.foo == @Resource.bar) is true
+ * (@Resource.bar == @Resource.foo) is true
+ * (@Resource.bar == @Resource.bar) is true
+ * (@Resource.foo == @Resource.foo) is an error (duplicate values on LHS)
+ * (@Resource.baz == @Resource.foo) is true (RHS case-folds down)
+ * (@Resource.baz == @Resource.bar) is false
+ * (@Resource.bar == {"A", "a"}) is true
+ * (@Resource.baz == {"A", "a"}) is true
+ * (@Resource.foo == {"A", "a"}) is an error
+ */
+ copy = talloc_array(mem_ctx, struct ace_condition_token, c->n_members);
+ if (copy == NULL) {
+ return NULL;
+ }
+ memcpy(copy, c->tokens, sizeof(struct ace_condition_token) * c->n_members);
+
+ if (case_sensitive) {
+ for (i = 0; i < c->n_members; i++) {
+ c->tokens[i].flags |= CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
+ }
+ }
+
+ ok = stable_sort_talloc_r(mem_ctx,
+ copy,
+ c->n_members,
+ sizeof(struct ace_condition_token),
+ (samba_compare_with_context_fn_t)composite_sort_cmp,
+ &sort_ctx);
+
+ if (!ok || sort_ctx.failed) {
+ DBG_NOTICE("composite sort of %"PRIu32" members failed\n",
+ c->n_members);
+ TALLOC_FREE(copy);
+ return NULL;
+ }
+ return copy;
+}
+
+
+/*
+ * This is a helper for compare composites.
+ */
+static bool compare_composites_via_sort(const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ int *cmp)
+{
+ const struct ace_condition_composite *lc = &lhs->data.composite;
+ const struct ace_condition_composite *rc = &rhs->data.composite;
+ size_t i;
+ TALLOC_CTX *tmp_ctx = NULL;
+ bool ok;
+ int cmp_pair;
+ bool case_sensitive, rhs_case_sensitive;
+ bool rhs_sorted;
+ struct ace_condition_token *ltok = lc->tokens;
+ struct ace_condition_token *rtok = rc->tokens;
+ static const struct ace_condition_token eq = {
+ .type = CONDITIONAL_ACE_TOKEN_EQUAL
+ };
+ *cmp = -1;
+ if (lc->n_members == 0 ||
+ rc->n_members < lc->n_members) {
+ /* we should not have got this far */
+ return false;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return false;
+ }
+
+ case_sensitive = lhs->flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
+ rhs_case_sensitive = rhs->flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
+ rhs_sorted = rhs->flags & CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED;
+
+ if (lc->tokens[0].type != CONDITIONAL_ACE_TOKEN_UNICODE) {
+ /*
+ * All LHS tokens are the same type (because it is a
+ * claim), and that type is not one that cares about
+ * case, so nor do we.
+ */
+ case_sensitive = false;
+ } else if (case_sensitive == rhs_case_sensitive) {
+ /* phew, no extra work */
+ } else if (case_sensitive) {
+ /* trigger a sorted copy */
+ rhs_sorted = false;
+ } else if (rhs_case_sensitive) {
+ /*
+ * Do we need to rescan for uniqueness, given the new
+ * comparison function? No! The strings were already
+ * unique in the looser comparison, and now they can
+ * only be more so. The number of unique values can't
+ * change, just their order.
+ */
+ case_sensitive = true;
+ ltok = composite_sorted_copy(tmp_ctx, lc, case_sensitive);
+ if (ltok == NULL) {
+ DBG_WARNING("sort of LHS failed\n");
+ goto error;
+ }
+ }
+
+ if (! rhs_sorted) {
+ /*
+ * we need an RHS sorted copy (it's a literal, or
+ * there was a case sensitivity disagreement).
+ */
+ rtok = composite_sorted_copy(tmp_ctx, rc, case_sensitive);
+ if (rtok == NULL) {
+ DBG_WARNING("sort of RHS failed\n");
+ goto error;
+ }
+ }
+ /*
+ * Each member of LHS must match one or more members of RHS.
+ * Each member of RHS must match at least one of LHS.
+ *
+ * If they are the same length we can compare directly, so let's get
+ * rid of duplicates in RHS. This can only happen with literal
+ * composites.
+ */
+ if (rc->n_members > lc->n_members) {
+ size_t gap = 0;
+ for (i = 1; i < rc->n_members; i++) {
+ ok = simple_relational_operator(&eq,
+ &rtok[i - 1],
+ &rtok[i],
+ &cmp_pair);
+ if (! ok) {
+ goto error;
+ }
+ if (cmp_pair == 0) {
+ gap++;
+ }
+ if (gap != 0) {
+ rtok[i - gap] = rtok[i];
+ }
+ }
+ if (rc->n_members - lc->n_members != gap) {
+ /*
+ * There were too many or too few duplicates to account
+ * for the difference, and no further comparison is
+ * necessary.
+ */
+ goto not_equal;
+ }
+ }
+ /*
+ * OK, now we know LHS and RHS are the same length and sorted in the
+ * same way, so we can just iterate over them and check each pair.
+ */
+
+ for (i = 0; i < lc->n_members; i++) {
+ ok = simple_relational_operator(&eq,
+ &ltok[i],
+ &rtok[i],
+ &cmp_pair);
+ if (! ok){
+ goto error;
+ }
+ if (cmp_pair != 0) {
+ goto not_equal;
+ }
+ }
+
+ *cmp = 0;
+
+not_equal:
+ TALLOC_FREE(tmp_ctx);
+ return true;
+error:
+ TALLOC_FREE(tmp_ctx);
+ return false;
+}
+
+
+static bool composite_is_comparable(const struct ace_condition_token *tok,
+ const struct ace_condition_token *comp)
+{
+ /*
+ * Are all members of the composite comparable to the token?
+ */
+ size_t i;
+ const struct ace_condition_composite *rc = &comp->data.composite;
+ size_t n = rc->n_members;
+
+ if ((comp->flags & CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED) &&
+ n > 1) {
+ /*
+ * all members are known to be the same type, so we
+ * can just check one.
+ */
+ n = 1;
+ }
+
+ for (i = 0; i < n; i++) {
+ if (! tokens_are_comparable(NULL,
+ tok,
+ &rc->tokens[i])) {
+ DBG_NOTICE("token type %u != composite type %u\n",
+ tok->type, rc->tokens[i].type);
+ return false;
+ }
+ }
+ return true;
+}
+
+
+static bool compare_composites(const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ int *cmp)
+{
+ /*
+ * This is for comparing multivalued sets, which includes
+ * conditional ACE composites and claim sets. Because these
+ * are sets, there are no < and > operations, just equality or
+ * otherwise.
+ *
+ * Claims are true sets, while composites are multisets --
+ * duplicate values are allowed -- but these are reduced to
+ * sets in evaluation, and the number of duplicates has no
+ * effect in comparisons. Resource attribute ACEs live in an
+ * intermediate state -- they can contain duplicates on the
+ * wire and as ACE structures, but as soon as they are
+ * evaluated as claims their values must be unique. Windows
+ * will treat RA ACEs with duplicate values as not existing,
+ * rather than as UNKNOWN (This is significant for the Exists
+ * operator). Claims can have a case-sensitive flags set,
+ * meaning they must be compared case-sensitively.
+ *
+ * Some good news is that the LHS of a comparison must always
+ * be a claim. That means we can assume it has unique values
+ * when it comes to pairwise comparisons. Using the magic of
+ * flags, we try to check this only once per claim.
+ *
+ * Conditional ACE composites, which can have duplicates (and
+ * mixed types), can only be on the RHS.
+ *
+ * To summarise:
+ *
+ * {a, b} vs {a, b} equal
+ * { } vs { } equal
+ * {a, b} vs {b, a} equal
+ * {a, b} vs {a, c} not equal
+ * {a, b} vs {a, a, b} equal
+ * {b, a} vs {a, b, a} equal
+ * {a, b} vs {a, a, b, c} not equal
+ * {a, b, a} vs {a, b} should not happen, error
+ * {a, b, a} vs {a, b, a} should not happen, error
+ *
+ * mixed types:
+ * {1, 2} vs {1, "2"} error
+ * {1, "2"} vs {1, "2"} should not happen, error
+ *
+ * case sensitivity (*{ }* indicates case-sensitive flag):
+ *
+ * {"a", "b"} vs {"a", "B"} equal
+ * {"a", "b"} vs *{"a", "B"}* not equal
+ * *{"a", "b"}* vs {"a", "B"} not equal
+ * *{"a", "A"}* vs {"a", "A"} equal (if RHS is composite)
+ * {"a", "A"} vs *{"a", "A"}* impossible (LHS is not unique)
+ * *{"a"}* vs {"a", "A"} not equal
+ *
+ * The naive approach is of course O(n * m) with an additional O(n²)
+ * if the LHS values are not known to be unique (that is, in resource
+ * attribute claims). We want to avoid that with big sets.
+ */
+ const struct ace_condition_composite *lc = &lhs->data.composite;
+ const struct ace_condition_composite *rc = &rhs->data.composite;
+ bool ok;
+
+ if (!(lhs->flags & CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED)) {
+ /*
+ * The LHS needs to be a claim, and it should have gone
+ * through claim_v1_check_and_sort() to get here.
+ */
+ *cmp = -1;
+ return false;
+ }
+
+ /* if one or both are empty, the answer is easy */
+ if (lc->n_members == 0) {
+ if (rc->n_members == 0) {
+ *cmp = 0;
+ return true;
+ }
+ *cmp = -1;
+ return true;
+ }
+ if (rc->n_members == 0) {
+ *cmp = -1;
+ return true;
+ }
+
+ /*
+ * LHS must be a claim, so it must be unique, so if there are
+ * fewer members on the RHS, we know they can't be equal.
+ *
+ * If you think about it too much, you might think this is
+ * affected by case sensitivity, but it isn't. One side can be
+ * infected by case-sensitivity by the other, but that can't
+ * shrink the number of elements on the RHS -- it can only
+ * make a literal {"a", "A"} have effective length 2 rather
+ * than 1.
+ *
+ * On the other hand, if the RHS is case sensitive, it must be
+ * a claim and unique in its own terms, and its finer-grained
+ * distinctions can't collapse members of the case sensitive
+ * LHS.
+ */
+ if (lc->n_members > rc->n_members) {
+ *cmp = -1;
+ return composite_is_comparable(&lc->tokens[0], rhs);
+ }
+
+ /*
+ * It *could* be that RHS is also unique and we know it. In that
+ * case we can short circuit if RHS has more members. This is
+ * the case when both sides are claims.
+ *
+ * This is also not affected by case-senstivity.
+ */
+ if (lc->n_members < rc->n_members &&
+ (rhs->flags & CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED)) {
+ *cmp = -1;
+ return composite_is_comparable(&lc->tokens[0], rhs);
+ }
+
+ ok = compare_composites_via_sort(lhs, rhs, cmp);
+ if (! ok) {
+ return false;
+ }
+ return true;
+}
+
+
+static bool simple_relational_operator(const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ int *cmp)
+
+{
+ if (lhs->type != rhs->type) {
+ if (! tokens_are_comparable(op, lhs, rhs)) {
+ return false;
+ }
+ }
+ switch (lhs->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ if (rhs->type == CONDITIONAL_ACE_SAMBA_RESULT_BOOL) {
+ return compare_bools(op, lhs, rhs, cmp);
+ }
+ return compare_ints(op, lhs, rhs, cmp);
+ case CONDITIONAL_ACE_SAMBA_RESULT_BOOL:
+ return compare_bools(op, lhs, rhs, cmp);
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ return compare_unicode(op, lhs, rhs, cmp);
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ return compare_bytes(op, lhs, rhs, cmp);
+ case CONDITIONAL_ACE_TOKEN_SID:
+ return compare_sids(op, lhs, rhs, cmp);
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ return compare_composites(op, lhs, rhs, cmp);
+ case CONDITIONAL_ACE_SAMBA_RESULT_NULL:
+ /* leave the result unknown */
+ return false;
+ default:
+ DBG_ERR("did not expect ace type %u\n", lhs->type);
+ return false;
+ }
+
+ return false;
+}
+
+
+static bool find_in_composite(const struct ace_condition_token *tok,
+ struct ace_condition_composite candidates,
+ bool *answer)
+{
+ size_t i;
+ int cmp;
+ bool ok;
+ const struct ace_condition_token equals = {
+ .type = CONDITIONAL_ACE_TOKEN_EQUAL
+ };
+
+ *answer = false;
+
+ for (i = 0; i < candidates.n_members; i++) {
+ ok = simple_relational_operator(&equals,
+ tok,
+ &candidates.tokens[i],
+ &cmp);
+ if (! ok) {
+ return false;
+ }
+ if (cmp == 0) {
+ *answer = true;
+ return true;
+ }
+ }
+ return true;
+}
+
+
+static bool contains_operator(const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ bool *answer)
+{
+ size_t i;
+ bool ok;
+ int cmp;
+ const struct ace_condition_token equals = {
+ .type = CONDITIONAL_ACE_TOKEN_EQUAL
+ };
+
+ /*
+ * All the required objects must be identical to something in
+ * candidates. But what do we mean by *identical*? We'll use
+ * the equality operator to decide that.
+ *
+ * Both the lhs or rhs can be solitary objects or composites.
+ * This makes it a bit fiddlier.
+ *
+ * NOTE: this operator does not take advantage of the
+ * CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED flag. It could, but it
+ * doesn't.
+ */
+ if (lhs->type == CONDITIONAL_ACE_TOKEN_COMPOSITE) {
+ struct ace_condition_composite candidates = lhs->data.composite;
+ struct ace_condition_composite required;
+ if (rhs->type != CONDITIONAL_ACE_TOKEN_COMPOSITE) {
+ return find_in_composite(rhs, candidates, answer);
+ }
+ required = rhs->data.composite;
+ if (required.n_members == 0) {
+ return false;
+ }
+ for (i = 0; i < required.n_members; i++) {
+ const struct ace_condition_token *t = &required.tokens[i];
+ ok = find_in_composite(t, candidates, answer);
+ if (! ok) {
+ return false;
+ }
+ if (! *answer) {
+ /*
+ * one required item was not there,
+ * *answer is false
+ */
+ return true;
+ }
+ }
+ /* all required items are there, *answer will be true */
+ return true;
+ }
+ /* LHS is a single item */
+ if (rhs->type == CONDITIONAL_ACE_TOKEN_COMPOSITE) {
+ /*
+ * There could be more than one RHS member that is
+ * equal to the single LHS value, so it doesn't help
+ * to compare lengths or anything.
+ */
+ struct ace_condition_composite required = rhs->data.composite;
+ if (required.n_members == 0) {
+ return false;
+ }
+ for (i = 0; i < required.n_members; i++) {
+ ok = simple_relational_operator(&equals,
+ lhs,
+ &required.tokens[i],
+ &cmp);
+ if (! ok) {
+ return false;
+ }
+ if (cmp != 0) {
+ /*
+ * one required item was not there,
+ * *answer is false
+ */
+ *answer = false;
+ return true;
+ }
+ }
+ *answer = true;
+ return true;
+ }
+ /* LHS and RHS are both single */
+ ok = simple_relational_operator(&equals,
+ lhs,
+ rhs,
+ &cmp);
+ if (! ok) {
+ return false;
+ }
+ *answer = (cmp == 0);
+ return true;
+}
+
+
+static bool any_of_operator(const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ bool *answer)
+{
+ size_t i;
+ bool ok;
+ int cmp;
+ const struct ace_condition_token equals = {
+ .type = CONDITIONAL_ACE_TOKEN_EQUAL
+ };
+
+ /*
+ * There has to be *some* overlap between the LHS and RHS.
+ * Both sides can be solitary objects or composites.
+ *
+ * We can exploit this symmetry.
+ */
+ if (lhs->type != CONDITIONAL_ACE_TOKEN_COMPOSITE) {
+ const struct ace_condition_token *tmp = lhs;
+ lhs = rhs;
+ rhs = tmp;
+ }
+ if (lhs->type != CONDITIONAL_ACE_TOKEN_COMPOSITE) {
+ /* both singles */
+ ok = simple_relational_operator(&equals,
+ lhs,
+ rhs,
+ &cmp);
+ if (! ok) {
+ return false;
+ }
+ *answer = (cmp == 0);
+ return true;
+ }
+ if (rhs->type != CONDITIONAL_ACE_TOKEN_COMPOSITE) {
+ return find_in_composite(rhs, lhs->data.composite, answer);
+ }
+ /* both are composites */
+ if (lhs->data.composite.n_members == 0) {
+ return false;
+ }
+ for (i = 0; i < lhs->data.composite.n_members; i++) {
+ ok = find_in_composite(&lhs->data.composite.tokens[i],
+ rhs->data.composite,
+ answer);
+ if (! ok) {
+ return false;
+ }
+ if (*answer) {
+ /* We have found one match, which is enough. */
+ return true;
+ }
+ }
+ return true;
+}
+
+
+static bool composite_relational_operator(const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ struct ace_condition_token *result)
+{
+ bool ok, answer;
+ switch(op->type) {
+ case CONDITIONAL_ACE_TOKEN_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
+ ok = contains_operator(lhs, rhs, &answer);
+ break;
+ case CONDITIONAL_ACE_TOKEN_ANY_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
+ ok = any_of_operator(lhs, rhs, &answer);
+ break;
+ default:
+ return false;
+ }
+ if (!ok) {
+ return false;
+ }
+
+ /* negate the NOTs */
+ if (op->type == CONDITIONAL_ACE_TOKEN_NOT_CONTAINS ||
+ op->type == CONDITIONAL_ACE_TOKEN_NOT_ANY_OF)
+ {
+ answer = !answer;
+ }
+
+ if (answer) {
+ result->data.result.value = ACE_CONDITION_TRUE;
+ } else {
+ result->data.result.value = ACE_CONDITION_FALSE;
+ }
+ return true;
+}
+
+
+static bool relational_operator(
+ const struct security_token *token,
+ const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ struct ace_condition_token *result)
+{
+ int cmp;
+ bool ok;
+ result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL;
+ result->data.result.value = ACE_CONDITION_UNKNOWN;
+
+ if ((lhs->flags & CONDITIONAL_ACE_FLAG_TOKEN_FROM_ATTR) == 0) {
+ /* LHS was not derived from an attribute */
+ return false;
+ }
+
+ /*
+ * This first nested switch is ensuring that >, >=, <, <= are
+ * not being tried on tokens that are not numbers, strings, or
+ * octet strings. Equality operators are available for all types.
+ */
+ switch (lhs->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ break;
+ default:
+ switch(op->type) {
+ case CONDITIONAL_ACE_TOKEN_LESS_THAN:
+ case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
+ case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
+ return false;
+ default:
+ break;
+ }
+ }
+
+ /*
+ * Dispatch according to operator type.
+ */
+ switch (op->type) {
+ case CONDITIONAL_ACE_TOKEN_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_LESS_THAN:
+ case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
+ case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
+ ok = simple_relational_operator(op,
+ lhs,
+ rhs,
+ &cmp);
+ if (ok) {
+ ok = cmp_to_result(op, result, cmp);
+ }
+ return ok;
+
+ case CONDITIONAL_ACE_TOKEN_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_ANY_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
+ return composite_relational_operator(op,
+ lhs,
+ rhs,
+ result);
+ default:
+ return false;
+ }
+}
+
+
+int run_conditional_ace(TALLOC_CTX *mem_ctx,
+ const struct security_token *token,
+ struct ace_condition_script *program,
+ const struct security_descriptor *sd)
+{
+ size_t i;
+ size_t depth = 0;
+ struct ace_condition_token *lhs = NULL;
+ struct ace_condition_token *rhs = NULL;
+ struct ace_condition_token result = {};
+ bool ok;
+
+ for (i = 0; i < program->length; i++) {
+ struct ace_condition_token *tok = &program->tokens[i];
+ switch (tok->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ case CONDITIONAL_ACE_TOKEN_SID:
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ /* just plonk these literals on the stack */
+ program->stack[depth] = *tok;
+ depth++;
+ break;
+
+ case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
+ case CONDITIONAL_ACE_USER_ATTRIBUTE:
+ case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
+ ok = token_claim_lookup(mem_ctx, token, tok, &result);
+ if (! ok) {
+ goto error;
+ }
+ program->stack[depth] = result;
+ depth++;
+ break;
+
+ case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
+ ok = resource_claim_lookup(mem_ctx,
+ tok,
+ sd,
+ &result);
+ if (! ok) {
+ goto error;
+ }
+ program->stack[depth] = result;
+ depth++;
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
+ if (depth == 0) {
+ goto error;
+ }
+ depth--;
+ lhs = &program->stack[depth];
+ ok = member_lookup(token, tok, lhs, &result);
+ if (! ok) {
+ goto error;
+ }
+ program->stack[depth] = result;
+ depth++;
+ break;
+ /* binary relational operators */
+ case CONDITIONAL_ACE_TOKEN_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_LESS_THAN:
+ case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
+ case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_ANY_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
+ if (depth < 2) {
+ goto error;
+ }
+ depth--;
+ rhs = &program->stack[depth];
+ depth--;
+ lhs = &program->stack[depth];
+ ok = relational_operator(token, tok, lhs, rhs, &result);
+ if (! ok) {
+ goto error;
+ }
+ program->stack[depth] = result;
+ depth++;
+ break;
+ /* unary logical operators */
+ case CONDITIONAL_ACE_TOKEN_EXISTS:
+ case CONDITIONAL_ACE_TOKEN_NOT_EXISTS:
+ case CONDITIONAL_ACE_TOKEN_NOT:
+ if (depth == 0) {
+ goto error;
+ }
+ depth--;
+ lhs = &program->stack[depth];
+ ok = unary_logic_operator(mem_ctx, token, tok, lhs, sd, &result);
+ if (!ok) {
+ goto error;
+ }
+ program->stack[depth] = result;
+ depth++;
+ break;
+ /* binary logical operators */
+ case CONDITIONAL_ACE_TOKEN_AND:
+ case CONDITIONAL_ACE_TOKEN_OR:
+ if (depth < 2) {
+ goto error;
+ }
+ depth--;
+ rhs = &program->stack[depth];
+ depth--;
+ lhs = &program->stack[depth];
+ ok = binary_logic_operator(token, tok, lhs, rhs, &result);
+ if (! ok) {
+ goto error;
+ }
+ program->stack[depth] = result;
+ depth++;
+ break;
+ default:
+ goto error;
+ }
+ }
+ /*
+ * The evaluation should have left a single result value (true, false,
+ * or unknown) on the stack. If not, the expression was malformed.
+ */
+ if (depth != 1) {
+ goto error;
+ }
+ result = program->stack[0];
+ if (result.type != CONDITIONAL_ACE_SAMBA_RESULT_BOOL) {
+ goto error;
+ }
+
+ return result.data.result.value;
+
+ error:
+ /*
+ * the result of an error is always UNKNOWN, which should be
+ * interpreted pessimistically, not allowing access.
+ */
+ return ACE_CONDITION_UNKNOWN;
+}
+
+
+/** access_check_conditional_ace()
+ *
+ * Run the conditional ACE from the blob form. Return false if it is
+ * not a valid conditional ACE, true if it is, even if there is some
+ * other error in running it. The *result parameter is set to
+ * ACE_CONDITION_FALSE, ACE_CONDITION_TRUE, or ACE_CONDITION_UNKNOWN.
+ *
+ * ACE_CONDITION_UNKNOWN should be treated pessimistically, as if it were
+ * TRUE for deny ACEs, and FALSE for allow ACEs.
+ *
+ * @param[in] ace - the ACE being processed.
+ * @param[in] token - the security token the ACE is processing.
+ * @param[out] result - a ternary result value.
+ *
+ * @return true if it is a valid conditional ACE.
+ */
+
+bool access_check_conditional_ace(const struct security_ace *ace,
+ const struct security_token *token,
+ const struct security_descriptor *sd,
+ int *result)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ struct ace_condition_script *program = NULL;
+ program = parse_conditional_ace(tmp_ctx, ace->coda.conditions);
+ if (program == NULL) {
+ *result = ACE_CONDITION_UNKNOWN;
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ *result = run_conditional_ace(tmp_ctx, token, program, sd);
+
+ TALLOC_FREE(tmp_ctx);
+ return true;
+}
+
+
+bool conditional_ace_encode_binary(TALLOC_CTX *mem_ctx,
+ struct ace_condition_script *program,
+ DATA_BLOB *dest)
+{
+ size_t i, j, alloc_size, required_size;
+ uint8_t *data = NULL;
+ uint8_t *new_data = NULL;
+ *dest = (DATA_BLOB){NULL, 0};
+
+ alloc_size = CONDITIONAL_ACE_MAX_LENGTH;
+ data = talloc_array(mem_ctx,
+ uint8_t,
+ alloc_size);
+ if (data == NULL) {
+ return false;
+ }
+
+ data[0] = 'a';
+ data[1] = 'r';
+ data[2] = 't';
+ data[3] = 'x';
+
+ j = 4;
+ for (i = 0; i < program->length; i++) {
+ struct ace_condition_token *tok = &program->tokens[i];
+ ssize_t consumed;
+ bool ok;
+ /*
+ * In all cases we write the token type byte.
+ */
+ data[j] = tok->type;
+ j++;
+ if (j >= alloc_size) {
+ DBG_ERR("program exceeds %zu bytes\n", alloc_size);
+ goto error;
+ }
+
+ switch (tok->type) {
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_LESS_THAN:
+ case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
+ case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_ANY_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
+ case CONDITIONAL_ACE_TOKEN_EXISTS:
+ case CONDITIONAL_ACE_TOKEN_NOT_EXISTS:
+ case CONDITIONAL_ACE_TOKEN_NOT:
+ case CONDITIONAL_ACE_TOKEN_AND:
+ case CONDITIONAL_ACE_TOKEN_OR:
+ /*
+ * All of these are simple operators that operate on
+ * the stack. We have already added the tok->type and
+ * there's nothing else to do.
+ */
+ continue;
+
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ ok = check_integer_range(tok);
+ if (! ok) {
+ goto error;
+ }
+ consumed = push_integer(data + j,
+ alloc_size - j,
+ &tok->data.int64);
+ break;
+ case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
+ case CONDITIONAL_ACE_USER_ATTRIBUTE:
+ case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
+ case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ consumed = push_unicode(data + j,
+ alloc_size - j,
+ &tok->data.unicode);
+ break;
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ consumed = push_bytes(data + j,
+ alloc_size - j,
+ &tok->data.bytes);
+ break;
+ case CONDITIONAL_ACE_TOKEN_SID:
+ consumed = push_sid(data + j,
+ alloc_size - j,
+ &tok->data.sid);
+ break;
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ consumed = push_composite(data + j,
+ alloc_size - j,
+ &tok->data.composite);
+ break;
+
+ default:
+ DBG_ERR("unknown token 0x%02x at position %zu\n",
+ tok->type, i);
+ goto error;
+ }
+ if (consumed == -1) {
+ DBG_ERR("program exceeds %zu bytes\n", alloc_size);
+ goto error;
+ }
+ j += consumed;
+ if (j >= alloc_size) {
+ DBG_ERR("program exceeds %zu bytes\n", alloc_size);
+ goto error;
+ }
+ }
+ /* align to a 4 byte boundary */
+ required_size = (j + 3) & ~((size_t)3);
+ if (required_size > alloc_size) {
+ DBG_ERR("program exceeds %zu bytes\n", alloc_size);
+ goto error;
+ }
+ while (j < required_size) {
+ data[j] = 0;
+ j++;
+ }
+ new_data = talloc_realloc(mem_ctx,
+ data,
+ uint8_t,
+ required_size);
+ if (new_data == NULL) {
+ goto error;
+ }
+ data = new_data;
+
+ (*dest).data = data;
+ (*dest).length = j;
+ return true;
+ error:
+ TALLOC_FREE(data);
+ return false;
+}
diff --git a/libcli/security/conditional_ace.h b/libcli/security/conditional_ace.h
new file mode 100644
index 0000000..e592056
--- /dev/null
+++ b/libcli/security/conditional_ace.h
@@ -0,0 +1,97 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Copyright © Catalyst
+
+ 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/>.
+*/
+
+#ifndef _CONDITIONAL_ACE_H_
+#define _CONDITIONAL_ACE_H_
+
+#include <talloc.h>
+#include "lib/util/data_blob.h"
+
+#include "librpc/gen_ndr/conditional_ace.h"
+
+
+struct ace_condition_script *parse_conditional_ace(TALLOC_CTX *mem_ctx,
+ DATA_BLOB data);
+
+int run_conditional_ace(TALLOC_CTX *mem_ctx,
+ const struct security_token *token,
+ struct ace_condition_script *program,
+ const struct security_descriptor *sd);
+
+
+bool access_check_conditional_ace(const struct security_ace *ace,
+ const struct security_token *token,
+ const struct security_descriptor *sd,
+ int *result);
+
+bool conditional_ace_encode_binary(TALLOC_CTX *mem_ctx,
+ struct ace_condition_script *program,
+ DATA_BLOB *dest);
+
+struct ace_condition_script * ace_conditions_compile_sddl(TALLOC_CTX *mem_ctx,
+ const enum ace_condition_flags ace_condition_flags,
+ const char *sddl,
+ const char **message,
+ size_t *message_offset,
+ size_t *consumed_length);
+
+char *debug_conditional_ace(TALLOC_CTX *mem_ctx,
+ struct ace_condition_script *program);
+
+char *sddl_from_conditional_ace(TALLOC_CTX *mem_ctx,
+ struct ace_condition_script *program);
+
+#define IS_INT_TOKEN(x) \
+ (((x)->type) == CONDITIONAL_ACE_TOKEN_INT64 || \
+ unlikely(((x)->type) == CONDITIONAL_ACE_TOKEN_INT32 || \
+ ((x)->type) == CONDITIONAL_ACE_TOKEN_INT16 || \
+ ((x)->type) == CONDITIONAL_ACE_TOKEN_INT8) \
+ )
+
+#define IS_BOOL_TOKEN(x) \
+ (((x)->type) == CONDITIONAL_ACE_SAMBA_RESULT_BOOL)
+
+#define IS_DERIVED_TOKEN(x) \
+ ((((x)->flags) & CONDITIONAL_ACE_FLAG_TOKEN_FROM_ATTR) == 0)
+
+#define IS_LITERAL_TOKEN(x) \
+ ((IS_INT_TOKEN(x) || \
+ ((x)->type) == CONDITIONAL_ACE_TOKEN_UNICODE || \
+ ((x)->type) == CONDITIONAL_ACE_TOKEN_OCTET_STRING || \
+ ((x)->type) == CONDITIONAL_ACE_TOKEN_SID || \
+ ((x)->type) == CONDITIONAL_ACE_TOKEN_COMPOSITE) && \
+ (! IS_DERIVED_TOKEN(x)))
+
+struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *parse_sddl_literal_as_claim(
+ TALLOC_CTX *mem_ctx,
+ const char *name,
+ const char *str);
+
+struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *sddl_decode_resource_attr (
+ TALLOC_CTX *mem_ctx,
+ const char *str,
+ size_t *length);
+
+char *sddl_resource_attr_from_claim(
+ TALLOC_CTX *mem_ctx,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim);
+
+
+#endif /*_CONDITIONAL_ACE_H_*/
diff --git a/libcli/security/create_descriptor.c b/libcli/security/create_descriptor.c
new file mode 100644
index 0000000..4db23be
--- /dev/null
+++ b/libcli/security/create_descriptor.c
@@ -0,0 +1,666 @@
+/*
+ Copyright (C) Nadezhda Ivanova 2009
+
+ 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/>.
+*/
+
+/*
+ * Name: create_descriptor
+ *
+ * Component: routines for calculating and creating security descriptors
+ * as described in MS-DTYP 2.5.3.x
+ *
+ * Description:
+ *
+ *
+ * Author: Nadezhda Ivanova
+ */
+#include "replace.h"
+#include "lib/util/debug.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_security.h"
+
+/* Todos:
+ * build the security token dacl as follows:
+ * SYSTEM: GA, OWNER: GA, LOGIN_SID:GW|GE
+ * Need session id information for the login SID. Probably
+ * the best place for this is during token creation
+ *
+ * Implement SD Invariants
+ * ACE sorting rules
+ * LDAP_SERVER_SD_FLAGS_OID control
+ * ADTS 7.1.3.3 needs to be clarified
+ */
+
+/* the mapping function for generic rights for DS.(GA,GR,GW,GX)
+ * The mapping function is passed as an argument to the
+ * descriptor calculating routine and depends on the security
+ * manager that calls the calculating routine.
+ * TODO: need similar mappings for the file system and
+ * registry security managers in order to make this code
+ * generic for all security managers
+ */
+
+uint32_t map_generic_rights_ds(uint32_t access_mask)
+{
+ if (access_mask & SEC_GENERIC_ALL) {
+ access_mask |= SEC_ADS_GENERIC_ALL;
+ access_mask &= ~SEC_GENERIC_ALL;
+ }
+
+ if (access_mask & SEC_GENERIC_EXECUTE) {
+ access_mask |= SEC_ADS_GENERIC_EXECUTE;
+ access_mask &= ~SEC_GENERIC_EXECUTE;
+ }
+
+ if (access_mask & SEC_GENERIC_WRITE) {
+ access_mask |= SEC_ADS_GENERIC_WRITE;
+ access_mask &= ~SEC_GENERIC_WRITE;
+ }
+
+ if (access_mask & SEC_GENERIC_READ) {
+ access_mask |= SEC_ADS_GENERIC_READ;
+ access_mask &= ~SEC_GENERIC_READ;
+ }
+
+ return access_mask;
+}
+
+/* Not sure what this has to be,
+* and it does not seem to have any influence */
+static bool object_in_list(const struct GUID *object_list, const struct GUID *object)
+{
+ size_t i;
+
+ if (object_list == NULL) {
+ return true;
+ }
+
+ if (GUID_all_zero(object)) {
+ return true;
+ }
+
+ for (i=0; ; i++) {
+ if (GUID_all_zero(&object_list[i])) {
+ return false;
+ }
+ if (!GUID_equal(&object_list[i], object)) {
+ continue;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/* returns true if the ACE gontains generic information
+ * that needs to be processed additionally */
+
+static bool desc_ace_has_generic(const struct security_ace *ace)
+{
+ if (ace->access_mask & SEC_GENERIC_ALL || ace->access_mask & SEC_GENERIC_READ ||
+ ace->access_mask & SEC_GENERIC_WRITE || ace->access_mask & SEC_GENERIC_EXECUTE) {
+ return true;
+ }
+ if (dom_sid_equal(&ace->trustee, &global_sid_Creator_Owner) ||
+ dom_sid_equal(&ace->trustee, &global_sid_Creator_Group)) {
+ return true;
+ }
+ return false;
+}
+
+/* creates an ace in which the generic information is expanded */
+
+static void desc_expand_generic(struct security_ace *new_ace,
+ struct dom_sid *owner,
+ struct dom_sid *group)
+{
+ new_ace->access_mask = map_generic_rights_ds(new_ace->access_mask);
+ if (dom_sid_equal(&new_ace->trustee, &global_sid_Creator_Owner)) {
+ new_ace->trustee = *owner;
+ }
+ if (dom_sid_equal(&new_ace->trustee, &global_sid_Creator_Group)) {
+ new_ace->trustee = *group;
+ }
+ new_ace->flags = 0x0;
+}
+
+static struct security_acl *calculate_inherited_from_parent(TALLOC_CTX *mem_ctx,
+ struct security_acl *acl,
+ bool is_container,
+ struct dom_sid *owner,
+ struct dom_sid *group,
+ struct GUID *object_list)
+{
+ uint32_t i;
+ struct security_acl *tmp_acl = NULL;
+
+ if (!acl) {
+ return NULL;
+ }
+ tmp_acl = talloc_zero(mem_ctx, struct security_acl);
+ if (!tmp_acl) {
+ return NULL;
+ }
+
+ for (i=0; i < acl->num_aces; i++) {
+ const struct security_ace *ace = &acl->aces[i];
+ const struct GUID *inherited_object = NULL;
+ const struct GUID *inherited_property = NULL;
+ struct security_ace *tmp_ace = NULL;
+ bool applies = false;
+ bool inherited_only = false;
+ bool expand_ace = false;
+ bool expand_only = false;
+
+ if (is_container && (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
+ applies = true;
+ } else if (!is_container && (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT)) {
+ applies = true;
+ }
+
+ if (!applies) {
+ /*
+ * If the ace doesn't apply to the
+ * current node, we should only keep
+ * it as SEC_ACE_FLAG_OBJECT_INHERIT
+ * on a container. We'll add
+ * SEC_ACE_FLAG_INHERITED_ACE
+ * and SEC_ACE_FLAG_INHERIT_ONLY below.
+ *
+ * Otherwise we should completely ignore it.
+ */
+ if (!(ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT)) {
+ continue;
+ }
+ }
+
+ switch (ace->type) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED:
+ case SEC_ACE_TYPE_ACCESS_DENIED:
+ case SEC_ACE_TYPE_SYSTEM_AUDIT:
+ case SEC_ACE_TYPE_SYSTEM_ALARM:
+ case SEC_ACE_TYPE_ALLOWED_COMPOUND:
+ break;
+
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT:
+ case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
+ case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT:
+ case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT:
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT:
+ case SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT:
+ case SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK_OBJECT:
+ if (ace->object.object.flags & SEC_ACE_OBJECT_TYPE_PRESENT) {
+ inherited_property = &ace->object.object.type.type;
+ }
+ if (ace->object.object.flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT) {
+ inherited_object = &ace->object.object.inherited_type.inherited_type;
+ }
+
+ if (inherited_object != NULL && !object_in_list(object_list, inherited_object)) {
+ /*
+ * An explicit object class schemaId is given,
+ * but doesn't belong to the current object.
+ */
+ applies = false;
+ }
+
+ break;
+
+ case SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK:
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK:
+ case SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK:
+ break;
+ case SEC_ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE:
+ break;
+ case SEC_ACE_TYPE_SYSTEM_ALARM_CALLBACK:
+ case SEC_ACE_TYPE_SYSTEM_ALARM_CALLBACK_OBJECT:
+ case SEC_ACE_TYPE_SYSTEM_MANDATORY_LABEL:
+ case SEC_ACE_TYPE_SYSTEM_SCOPED_POLICY_ID:
+ default:
+ DBG_WARNING("ACE type %d is not handled\n", ace->type);
+ TALLOC_FREE(tmp_acl);
+ return NULL;
+ }
+
+ if (ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
+ if (!applies) {
+ /*
+ * If the ACE doesn't apply to
+ * the current object, we should
+ * ignore it as it should not be
+ * inherited any further
+ */
+ continue;
+ }
+ /*
+ * We should only keep the expanded version
+ * of the ACE on the current object.
+ */
+ expand_ace = true;
+ expand_only = true;
+ } else if (applies) {
+ /*
+ * We check if should also add
+ * the expanded version of the ACE
+ * in addition, in case we should
+ * expand generic access bits or
+ * special sids.
+ *
+ * In that case we need to
+ * keep the original ACE with
+ * SEC_ACE_FLAG_INHERIT_ONLY.
+ */
+ expand_ace = desc_ace_has_generic(ace);
+ if (expand_ace) {
+ inherited_only = true;
+ }
+ } else {
+ /*
+ * If the ACE doesn't apply
+ * to the current object,
+ * we need to keep it with
+ * SEC_ACE_FLAG_INHERIT_ONLY
+ * in order to apply them to
+ * grandchildren
+ */
+ inherited_only = true;
+ }
+
+ if (expand_ace) {
+ tmp_acl->aces = talloc_realloc(tmp_acl,
+ tmp_acl->aces,
+ struct security_ace,
+ tmp_acl->num_aces+1);
+ if (tmp_acl->aces == NULL) {
+ TALLOC_FREE(tmp_acl);
+ return NULL;
+ }
+
+ tmp_ace = &tmp_acl->aces[tmp_acl->num_aces];
+ tmp_acl->num_aces++;
+
+ *tmp_ace = *ace;
+
+ /*
+ * Expand generic access bits as well as special
+ * sids.
+ */
+ desc_expand_generic(tmp_ace, owner, group);
+
+ /*
+ * Expanded ACEs are marked as inherited,
+ * but never inherited any further to
+ * grandchildren.
+ */
+ tmp_ace->flags |= SEC_ACE_FLAG_INHERITED_ACE;
+ tmp_ace->flags &= ~SEC_ACE_FLAG_CONTAINER_INHERIT;
+ tmp_ace->flags &= ~SEC_ACE_FLAG_OBJECT_INHERIT;
+ tmp_ace->flags &= ~SEC_ACE_FLAG_NO_PROPAGATE_INHERIT;
+
+ /*
+ * Expanded ACEs never have an explicit
+ * object class schemaId, so clear it
+ * if present.
+ */
+ if (inherited_object != NULL) {
+ tmp_ace->object.object.flags &= ~SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT;
+ }
+
+ /*
+ * If the ACE had an explicit object class
+ * schemaId, but no attribute/propertySet
+ * we need to downgrade the _OBJECT variants
+ * to the normal ones.
+ */
+ if (inherited_property == NULL) {
+ switch (tmp_ace->type) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED:
+ case SEC_ACE_TYPE_ACCESS_DENIED:
+ case SEC_ACE_TYPE_SYSTEM_AUDIT:
+ case SEC_ACE_TYPE_SYSTEM_ALARM:
+ case SEC_ACE_TYPE_ALLOWED_COMPOUND:
+ break;
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT:
+ tmp_ace->type = SEC_ACE_TYPE_ACCESS_ALLOWED;
+ break;
+ case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
+ tmp_ace->type = SEC_ACE_TYPE_ACCESS_DENIED;
+ break;
+ case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT:
+ tmp_ace->type = SEC_ACE_TYPE_SYSTEM_ALARM;
+ break;
+ case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT:
+ tmp_ace->type = SEC_ACE_TYPE_SYSTEM_AUDIT;
+ break;
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT:
+ tmp_ace->type = SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK;
+ break;
+ case SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT:
+ tmp_ace->type = SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK;
+ break;
+ case SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK_OBJECT:
+ tmp_ace->type = SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK;
+ break;
+ default:
+ /*
+ * SEC_ACE_TYPE_SYSTEM_ALARM_CALLBACK_OBJECT
+ * is reserved.
+ */
+ break;
+ }
+ }
+
+ if (expand_only) {
+ continue;
+ }
+ }
+
+ tmp_acl->aces = talloc_realloc(tmp_acl,
+ tmp_acl->aces,
+ struct security_ace,
+ tmp_acl->num_aces+1);
+ if (tmp_acl->aces == NULL) {
+ TALLOC_FREE(tmp_acl);
+ return NULL;
+ }
+
+ tmp_ace = &tmp_acl->aces[tmp_acl->num_aces];
+ tmp_acl->num_aces++;
+
+ *tmp_ace = *ace;
+ tmp_ace->flags |= SEC_ACE_FLAG_INHERITED_ACE;
+
+ if (inherited_only) {
+ tmp_ace->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+ } else {
+ tmp_ace->flags &= ~SEC_ACE_FLAG_INHERIT_ONLY;
+ }
+
+ if (ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
+ tmp_ace->flags &= ~SEC_ACE_FLAG_CONTAINER_INHERIT;
+ tmp_ace->flags &= ~SEC_ACE_FLAG_OBJECT_INHERIT;
+ tmp_ace->flags &= ~SEC_ACE_FLAG_NO_PROPAGATE_INHERIT;
+ }
+ }
+ if (tmp_acl->num_aces == 0) {
+ TALLOC_FREE(tmp_acl);
+ return NULL;
+ }
+ if (acl) {
+ tmp_acl->revision = acl->revision;
+ }
+ return tmp_acl;
+}
+
+static struct security_acl *process_user_acl(TALLOC_CTX *mem_ctx,
+ struct security_acl *acl,
+ bool is_container,
+ struct dom_sid *owner,
+ struct dom_sid *group,
+ struct GUID *object_list,
+ bool is_protected)
+{
+ uint32_t i;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ struct security_acl *tmp_acl = talloc_zero(tmp_ctx, struct security_acl);
+ struct security_acl *new_acl;
+
+ if (!acl)
+ return NULL;
+
+ if (!tmp_acl)
+ return NULL;
+
+ tmp_acl->revision = acl->revision;
+ DBG_DEBUG("acl revision %d\n", acl->revision);
+
+ for (i=0; i < acl->num_aces; i++){
+ struct security_ace *ace = &acl->aces[i];
+ /* Remove ID flags from user-provided ACEs
+ * if we break inheritance, ignore them otherwise */
+ if (ace->flags & SEC_ACE_FLAG_INHERITED_ACE) {
+ if (is_protected) {
+ ace->flags &= ~SEC_ACE_FLAG_INHERITED_ACE;
+ } else {
+ continue;
+ }
+ }
+
+ if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY &&
+ !(ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT ||
+ ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT))
+ continue;
+
+ tmp_acl->aces = talloc_realloc(tmp_acl,
+ tmp_acl->aces,
+ struct security_ace,
+ tmp_acl->num_aces+1);
+ tmp_acl->aces[tmp_acl->num_aces] = *ace;
+ tmp_acl->num_aces++;
+ if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+ continue;
+ }
+ /* if the ACE contains CO, CG, GA, GE, GR or GW, and is inheritable
+ * it has to be expanded to two aces, the original as IO,
+ * and another one where these are translated */
+ if (desc_ace_has_generic(ace)) {
+ if (!(ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
+ desc_expand_generic(&tmp_acl->aces[tmp_acl->num_aces-1],
+ owner,
+ group);
+ } else {
+ /*The original ACE becomes read only */
+ tmp_acl->aces[tmp_acl->num_aces-1].flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+ tmp_acl->aces = talloc_realloc(tmp_acl, tmp_acl->aces,
+ struct security_ace,
+ tmp_acl->num_aces+1);
+ /* add a new ACE with expanded generic info */
+ tmp_acl->aces[tmp_acl->num_aces] = *ace;
+ desc_expand_generic(&tmp_acl->aces[tmp_acl->num_aces],
+ owner,
+ group);
+ tmp_acl->num_aces++;
+ }
+ }
+ }
+ new_acl = security_acl_dup(mem_ctx,tmp_acl);
+
+ if (new_acl)
+ new_acl->revision = acl->revision;
+
+ talloc_free(tmp_ctx);
+ return new_acl;
+}
+
+static void cr_descr_log_descriptor(struct security_descriptor *sd,
+ const char *message,
+ int level)
+{
+ if (sd) {
+ DEBUG(level,("%s: %s\n", message,
+ ndr_print_struct_string(0,(ndr_print_fn_t)ndr_print_security_descriptor,
+ "", sd)));
+ }
+ else {
+ DEBUG(level,("%s: NULL\n", message));
+ }
+}
+
+#if 0
+static void cr_descr_log_acl(struct security_acl *acl,
+ const char *message,
+ int level)
+{
+ if (acl) {
+ DEBUG(level,("%s: %s\n", message,
+ ndr_print_struct_string(0,(ndr_print_fn_t)ndr_print_security_acl,
+ "", acl)));
+ }
+ else {
+ DEBUG(level,("%s: NULL\n", message));
+ }
+}
+#endif
+
+static bool compute_acl(struct security_descriptor *parent_sd,
+ struct security_descriptor *creator_sd,
+ bool is_container,
+ uint32_t inherit_flags,
+ struct GUID *object_list,
+ uint32_t (*generic_map)(uint32_t access_mask),
+ struct security_token *token,
+ struct security_descriptor *new_sd) /* INOUT argument */
+{
+ struct security_acl *user_dacl, *user_sacl, *inherited_dacl, *inherited_sacl;
+ int level = 10;
+
+ if (!parent_sd || !(inherit_flags & SEC_DACL_AUTO_INHERIT)) {
+ inherited_dacl = NULL;
+ } else if (creator_sd && (creator_sd->type & SEC_DESC_DACL_PROTECTED)) {
+ inherited_dacl = NULL;
+ } else {
+ inherited_dacl = calculate_inherited_from_parent(new_sd,
+ parent_sd->dacl,
+ is_container,
+ new_sd->owner_sid,
+ new_sd->group_sid,
+ object_list);
+ }
+
+
+ if (!parent_sd || !(inherit_flags & SEC_SACL_AUTO_INHERIT)) {
+ inherited_sacl = NULL;
+ } else if (creator_sd && (creator_sd->type & SEC_DESC_SACL_PROTECTED)) {
+ inherited_sacl = NULL;
+ } else {
+ inherited_sacl = calculate_inherited_from_parent(new_sd,
+ parent_sd->sacl,
+ is_container,
+ new_sd->owner_sid,
+ new_sd->group_sid,
+ object_list);
+ }
+
+ if (!creator_sd || (inherit_flags & SEC_DEFAULT_DESCRIPTOR)) {
+ user_dacl = NULL;
+ user_sacl = NULL;
+ } else {
+ user_dacl = process_user_acl(new_sd,
+ creator_sd->dacl,
+ is_container,
+ new_sd->owner_sid,
+ new_sd->group_sid,
+ object_list,
+ creator_sd->type & SEC_DESC_DACL_PROTECTED);
+ user_sacl = process_user_acl(new_sd,
+ creator_sd->sacl,
+ is_container,
+ new_sd->owner_sid,
+ new_sd->group_sid,
+ object_list,
+ creator_sd->type & SEC_DESC_SACL_PROTECTED);
+ }
+ cr_descr_log_descriptor(parent_sd, __location__"parent_sd", level);
+ cr_descr_log_descriptor(creator_sd,__location__ "creator_sd", level);
+
+ new_sd->dacl = security_acl_concatenate(new_sd, user_dacl, inherited_dacl);
+ if (new_sd->dacl) {
+ new_sd->type |= SEC_DESC_DACL_PRESENT;
+ }
+ if (inherited_dacl) {
+ new_sd->type |= SEC_DESC_DACL_AUTO_INHERITED;
+ }
+
+ new_sd->sacl = security_acl_concatenate(new_sd, user_sacl, inherited_sacl);
+ if (new_sd->sacl) {
+ new_sd->type |= SEC_DESC_SACL_PRESENT;
+ }
+ if (inherited_sacl) {
+ new_sd->type |= SEC_DESC_SACL_AUTO_INHERITED;
+ }
+ /* This is a hack to handle the fact that
+ * apprantly any AI flag provided by the user is preserved */
+ if (creator_sd)
+ new_sd->type |= creator_sd->type;
+ cr_descr_log_descriptor(new_sd, __location__"final sd", level);
+ return true;
+}
+
+struct security_descriptor *create_security_descriptor(TALLOC_CTX *mem_ctx,
+ struct security_descriptor *parent_sd,
+ struct security_descriptor *creator_sd,
+ bool is_container,
+ struct GUID *object_list,
+ uint32_t inherit_flags,
+ struct security_token *token,
+ struct dom_sid *default_owner, /* valid only for DS, NULL for the other RSs */
+ struct dom_sid *default_group, /* valid only for DS, NULL for the other RSs */
+ uint32_t (*generic_map)(uint32_t access_mask))
+{
+ struct security_descriptor *new_sd;
+ struct dom_sid *new_owner = NULL;
+ struct dom_sid *new_group = NULL;
+
+ new_sd = security_descriptor_initialise(mem_ctx);
+ if (!new_sd) {
+ return NULL;
+ }
+
+ if (!creator_sd || !creator_sd->owner_sid) {
+ if ((inherit_flags & SEC_OWNER_FROM_PARENT) && parent_sd) {
+ new_owner = parent_sd->owner_sid;
+ } else if (!default_owner) {
+ new_owner = &token->sids[PRIMARY_USER_SID_INDEX];
+ } else {
+ new_owner = default_owner;
+ new_sd->type |= SEC_DESC_OWNER_DEFAULTED;
+ }
+ } else {
+ new_owner = creator_sd->owner_sid;
+ }
+
+ if (!creator_sd || !creator_sd->group_sid){
+ if ((inherit_flags & SEC_GROUP_FROM_PARENT) && parent_sd) {
+ new_group = parent_sd->group_sid;
+ } else if (!default_group && token->num_sids > PRIMARY_GROUP_SID_INDEX) {
+ new_group = &token->sids[PRIMARY_GROUP_SID_INDEX];
+ } else if (!default_group) {
+ /* This will happen only for anonymous, which has no other groups */
+ new_group = &token->sids[PRIMARY_USER_SID_INDEX];
+ } else {
+ new_group = default_group;
+ new_sd->type |= SEC_DESC_GROUP_DEFAULTED;
+ }
+ } else {
+ new_group = creator_sd->group_sid;
+ }
+
+ new_sd->owner_sid = talloc_memdup(new_sd, new_owner, sizeof(struct dom_sid));
+ new_sd->group_sid = talloc_memdup(new_sd, new_group, sizeof(struct dom_sid));
+ if (!new_sd->owner_sid || !new_sd->group_sid){
+ talloc_free(new_sd);
+ return NULL;
+ }
+
+ if (!compute_acl(parent_sd, creator_sd,
+ is_container, inherit_flags, object_list,
+ generic_map,token,new_sd)){
+ talloc_free(new_sd);
+ return NULL;
+ }
+
+ return new_sd;
+}
diff --git a/libcli/security/display_sec.c b/libcli/security/display_sec.c
new file mode 100644
index 0000000..be89a33
--- /dev/null
+++ b/libcli/security/display_sec.c
@@ -0,0 +1,274 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Luke Kenneth Casson Leighton 1996 - 1999
+
+ 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 "replace.h"
+#include "libcli/security/security.h"
+#include "librpc/ndr/libndr.h"
+#include "libcli/security/display_sec.h"
+
+/****************************************************************************
+convert a security permissions into a string
+****************************************************************************/
+
+char *get_sec_mask_str(TALLOC_CTX *ctx, uint32_t type)
+{
+ char *typestr = talloc_strdup(ctx, "");
+
+ if (type & SEC_GENERIC_ALL) {
+ talloc_asprintf_addbuf(&typestr, "Generic all access ");
+ }
+ if (type & SEC_GENERIC_EXECUTE) {
+ talloc_asprintf_addbuf(&typestr, "Generic execute access");
+ }
+ if (type & SEC_GENERIC_WRITE) {
+ talloc_asprintf_addbuf(&typestr, "Generic write access ");
+ }
+ if (type & SEC_GENERIC_READ) {
+ talloc_asprintf_addbuf(&typestr, "Generic read access ");
+ }
+ if (type & SEC_FLAG_MAXIMUM_ALLOWED) {
+ talloc_asprintf_addbuf(&typestr, "MAXIMUM_ALLOWED_ACCESS ");
+ }
+ if (type & SEC_FLAG_SYSTEM_SECURITY) {
+ talloc_asprintf_addbuf(&typestr, "SYSTEM_SECURITY_ACCESS ");
+ }
+ if (type & SEC_STD_SYNCHRONIZE) {
+ talloc_asprintf_addbuf(&typestr, "SYNCHRONIZE_ACCESS ");
+ }
+ if (type & SEC_STD_WRITE_OWNER) {
+ talloc_asprintf_addbuf(&typestr, "WRITE_OWNER_ACCESS ");
+ }
+ if (type & SEC_STD_WRITE_DAC) {
+ talloc_asprintf_addbuf(&typestr, "WRITE_DAC_ACCESS ");
+ }
+ if (type & SEC_STD_READ_CONTROL) {
+ talloc_asprintf_addbuf(&typestr, "READ_CONTROL_ACCESS ");
+ }
+ if (type & SEC_STD_DELETE) {
+ talloc_asprintf_addbuf(&typestr, "DELETE_ACCESS ");
+ }
+
+ printf("\t\tSpecific bits: 0x%lx\n", (unsigned long)type&SEC_MASK_SPECIFIC);
+
+ return typestr;
+}
+
+/****************************************************************************
+ display sec_access structure
+ ****************************************************************************/
+void display_sec_access(uint32_t *info)
+{
+ char *mask_str = get_sec_mask_str(NULL, *info);
+ printf("\t\tPermissions: 0x%x: %s\n", *info, mask_str ? mask_str : "");
+ talloc_free(mask_str);
+}
+
+/****************************************************************************
+ display sec_ace flags
+ ****************************************************************************/
+void display_sec_ace_flags(uint8_t flags)
+{
+ if (flags & SEC_ACE_FLAG_OBJECT_INHERIT)
+ printf("SEC_ACE_FLAG_OBJECT_INHERIT ");
+ if (flags & SEC_ACE_FLAG_CONTAINER_INHERIT)
+ printf(" SEC_ACE_FLAG_CONTAINER_INHERIT ");
+ if (flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)
+ printf("SEC_ACE_FLAG_NO_PROPAGATE_INHERIT ");
+ if (flags & SEC_ACE_FLAG_INHERIT_ONLY)
+ printf("SEC_ACE_FLAG_INHERIT_ONLY ");
+ if (flags & SEC_ACE_FLAG_INHERITED_ACE)
+ printf("SEC_ACE_FLAG_INHERITED_ACE ");
+/* if (flags & SEC_ACE_FLAG_VALID_INHERIT)
+ printf("SEC_ACE_FLAG_VALID_INHERIT "); */
+ if (flags & SEC_ACE_FLAG_SUCCESSFUL_ACCESS)
+ printf("SEC_ACE_FLAG_SUCCESSFUL_ACCESS ");
+ if (flags & SEC_ACE_FLAG_FAILED_ACCESS)
+ printf("SEC_ACE_FLAG_FAILED_ACCESS ");
+
+ printf("\n");
+}
+
+/****************************************************************************
+ display sec_ace object
+ ****************************************************************************/
+static void disp_sec_ace_object(struct security_ace_object *object)
+{
+ char *str;
+ if (object->flags & SEC_ACE_OBJECT_TYPE_PRESENT) {
+ str = GUID_string(NULL, &object->type.type);
+ if (str == NULL) return;
+ printf("Object type: SEC_ACE_OBJECT_TYPE_PRESENT\n");
+ printf("Object GUID: %s\n", str);
+ talloc_free(str);
+ }
+ if (object->flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT) {
+ str = GUID_string(NULL, &object->inherited_type.inherited_type);
+ if (str == NULL) return;
+ printf("Object type: SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT\n");
+ printf("Object GUID: %s\n", str);
+ talloc_free(str);
+ }
+}
+
+/****************************************************************************
+ display sec_ace structure
+ ****************************************************************************/
+void display_sec_ace(struct security_ace *ace)
+{
+ struct dom_sid_buf sid_str;
+
+ printf("\tACE\n\t\ttype: ");
+ switch (ace->type) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED:
+ printf("ACCESS ALLOWED");
+ break;
+ case SEC_ACE_TYPE_ACCESS_DENIED:
+ printf("ACCESS DENIED");
+ break;
+ case SEC_ACE_TYPE_SYSTEM_AUDIT:
+ printf("SYSTEM AUDIT");
+ break;
+ case SEC_ACE_TYPE_SYSTEM_ALARM:
+ printf("SYSTEM ALARM");
+ break;
+#define ACE_CASE(x) case x: printf(#x); break
+ ACE_CASE(SEC_ACE_TYPE_ALLOWED_COMPOUND);
+ ACE_CASE(SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT);
+ ACE_CASE(SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
+ ACE_CASE(SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT);
+ ACE_CASE(SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT);
+ ACE_CASE(SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK);
+ ACE_CASE(SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK);
+ ACE_CASE(SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT);
+ ACE_CASE(SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT);
+ ACE_CASE(SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK);
+ ACE_CASE(SEC_ACE_TYPE_SYSTEM_ALARM_CALLBACK);
+ ACE_CASE(SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK_OBJECT);
+ ACE_CASE(SEC_ACE_TYPE_SYSTEM_ALARM_CALLBACK_OBJECT);
+#undef ACE_CASE
+ default:
+ printf("????");
+ break;
+ }
+
+ printf(" (%d) flags: 0x%02x ", ace->type, ace->flags);
+ display_sec_ace_flags(ace->flags);
+ display_sec_access(&ace->access_mask);
+ printf("\t\tSID: %s\n\n", dom_sid_str_buf(&ace->trustee, &sid_str));
+
+ if (sec_ace_object(ace->type)) {
+ disp_sec_ace_object(&ace->object.object);
+ }
+
+}
+
+/****************************************************************************
+ display sec_acl structure
+ ****************************************************************************/
+void display_sec_acl(struct security_acl *sec_acl)
+{
+ uint32_t i;
+
+ printf("\tACL\tNum ACEs:\t%u\trevision:\t%x\n",
+ sec_acl->num_aces, sec_acl->revision);
+ printf("\t---\n");
+
+ if (sec_acl->size != 0 && sec_acl->num_aces != 0) {
+ for (i = 0; i < sec_acl->num_aces; i++) {
+ display_sec_ace(&sec_acl->aces[i]);
+ }
+ }
+}
+
+void display_acl_type(uint16_t type)
+{
+ printf("type: 0x%04x: ", type);
+
+ if (type & SEC_DESC_OWNER_DEFAULTED) /* 0x0001 */
+ printf("SEC_DESC_OWNER_DEFAULTED ");
+ if (type & SEC_DESC_GROUP_DEFAULTED) /* 0x0002 */
+ printf("SEC_DESC_GROUP_DEFAULTED ");
+ if (type & SEC_DESC_DACL_PRESENT) /* 0x0004 */
+ printf("SEC_DESC_DACL_PRESENT ");
+ if (type & SEC_DESC_DACL_DEFAULTED) /* 0x0008 */
+ printf("SEC_DESC_DACL_DEFAULTED ");
+ if (type & SEC_DESC_SACL_PRESENT) /* 0x0010 */
+ printf("SEC_DESC_SACL_PRESENT ");
+ if (type & SEC_DESC_SACL_DEFAULTED) /* 0x0020 */
+ printf("SEC_DESC_SACL_DEFAULTED ");
+ if (type & SEC_DESC_DACL_TRUSTED) /* 0x0040 */
+ printf("SEC_DESC_DACL_TRUSTED ");
+ if (type & SEC_DESC_SERVER_SECURITY) /* 0x0080 */
+ printf("SEC_DESC_SERVER_SECURITY ");
+ if (type & SEC_DESC_DACL_AUTO_INHERIT_REQ) /* 0x0100 */
+ printf("SEC_DESC_DACL_AUTO_INHERIT_REQ ");
+ if (type & SEC_DESC_SACL_AUTO_INHERIT_REQ) /* 0x0200 */
+ printf("SEC_DESC_SACL_AUTO_INHERIT_REQ ");
+ if (type & SEC_DESC_DACL_AUTO_INHERITED) /* 0x0400 */
+ printf("SEC_DESC_DACL_AUTO_INHERITED ");
+ if (type & SEC_DESC_SACL_AUTO_INHERITED) /* 0x0800 */
+ printf("SEC_DESC_SACL_AUTO_INHERITED ");
+ if (type & SEC_DESC_DACL_PROTECTED) /* 0x1000 */
+ printf("SEC_DESC_DACL_PROTECTED ");
+ if (type & SEC_DESC_SACL_PROTECTED) /* 0x2000 */
+ printf("SEC_DESC_SACL_PROTECTED ");
+ if (type & SEC_DESC_RM_CONTROL_VALID) /* 0x4000 */
+ printf("SEC_DESC_RM_CONTROL_VALID ");
+ if (type & SEC_DESC_SELF_RELATIVE) /* 0x8000 */
+ printf("SEC_DESC_SELF_RELATIVE ");
+
+ printf("\n");
+}
+
+/****************************************************************************
+ display sec_desc structure
+ ****************************************************************************/
+void display_sec_desc(struct security_descriptor *sec)
+{
+ struct dom_sid_buf sid_str;
+
+ if (!sec) {
+ printf("NULL\n");
+ return;
+ }
+
+ printf("revision: %d\n", sec->revision);
+ display_acl_type(sec->type);
+
+ if (sec->sacl) {
+ printf("SACL\n");
+ display_sec_acl(sec->sacl);
+ }
+
+ if (sec->dacl) {
+ printf("DACL\n");
+ display_sec_acl(sec->dacl);
+ }
+
+ if (sec->owner_sid) {
+ printf("\tOwner SID:\t%s\n",
+ dom_sid_str_buf(sec->owner_sid, &sid_str));
+ }
+
+ if (sec->group_sid) {
+ printf("\tGroup SID:\t%s\n",
+ dom_sid_str_buf(sec->group_sid, &sid_str));
+ }
+}
diff --git a/libcli/security/display_sec.h b/libcli/security/display_sec.h
new file mode 100644
index 0000000..336e04c
--- /dev/null
+++ b/libcli/security/display_sec.h
@@ -0,0 +1,34 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Luke Kenneth Casson Leighton 1996 - 1999
+
+ 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/>.
+*/
+
+#ifndef _LIBCLI_SECURITY_DISPLAY_SEC_H
+#define _LIBCLI_SECURITY_DISPLAY_SEC_H
+
+/* The following definitions come from libcli/security/display_sec.c */
+
+char *get_sec_mask_str(TALLOC_CTX *ctx, uint32_t type);
+void display_sec_access(uint32_t *info);
+void display_sec_ace_flags(uint8_t flags);
+void display_sec_ace(struct security_ace *ace);
+void display_sec_acl(struct security_acl *sec_acl);
+void display_acl_type(uint16_t type);
+void display_sec_desc(struct security_descriptor *sec);
+
+#endif /* _LIBCLI_SECURITY_DISPLAY_SEC_H */
diff --git a/libcli/security/dom_sid.c b/libcli/security/dom_sid.c
new file mode 100644
index 0000000..eaece2a
--- /dev/null
+++ b/libcli/security/dom_sid.c
@@ -0,0 +1,582 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Copyright (C) Stefan (metze) Metzmacher 2002-2004
+ Copyright (C) Andrew Tridgell 1992-2004
+ Copyright (C) Jeremy Allison 1999
+
+ 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 "replace.h"
+#include "lib/util/data_blob.h"
+#include "system/locale.h"
+#include "lib/util/debug.h"
+#include "lib/util/util.h"
+#include "librpc/gen_ndr/security.h"
+#include "dom_sid.h"
+#include "lib/util/smb_strtox.h"
+
+/*****************************************************************
+ Compare the auth portion of two sids.
+*****************************************************************/
+
+int dom_sid_compare_auth(const struct dom_sid *sid1,
+ const struct dom_sid *sid2)
+{
+ int i;
+
+ if (sid1 == sid2)
+ return 0;
+ if (!sid1)
+ return -1;
+ if (!sid2)
+ return 1;
+
+ if (sid1->sid_rev_num != sid2->sid_rev_num)
+ return sid1->sid_rev_num - sid2->sid_rev_num;
+
+ for (i = 0; i < 6; i++)
+ if (sid1->id_auth[i] != sid2->id_auth[i])
+ return sid1->id_auth[i] - sid2->id_auth[i];
+
+ return 0;
+}
+
+/*****************************************************************
+ Compare two sids.
+*****************************************************************/
+
+int dom_sid_compare(const struct dom_sid *sid1, const struct dom_sid *sid2)
+{
+ int i;
+
+ if (sid1 == sid2)
+ return 0;
+ if (!sid1)
+ return -1;
+ if (!sid2)
+ return 1;
+
+ /* Compare most likely different rids, first: i.e start at end */
+ if (sid1->num_auths != sid2->num_auths)
+ return sid1->num_auths - sid2->num_auths;
+
+ for (i = sid1->num_auths-1; i >= 0; --i) {
+ if (sid1->sub_auths[i] < sid2->sub_auths[i]) {
+ return -1;
+ }
+ if (sid1->sub_auths[i] > sid2->sub_auths[i]) {
+ return 1;
+ }
+ }
+
+ return dom_sid_compare_auth(sid1, sid2);
+}
+
+/*****************************************************************
+ Compare two sids.
+*****************************************************************/
+
+bool dom_sid_equal(const struct dom_sid *sid1, const struct dom_sid *sid2)
+{
+ return dom_sid_compare(sid1, sid2) == 0;
+}
+
+/*****************************************************************
+ Add a rid to the end of a sid
+*****************************************************************/
+
+bool sid_append_rid(struct dom_sid *sid, uint32_t rid)
+{
+ if (sid->num_auths < ARRAY_SIZE(sid->sub_auths)) {
+ sid->sub_auths[sid->num_auths++] = rid;
+ return true;
+ }
+ return false;
+}
+
+/*
+ See if 2 SIDs are in the same domain
+ this just compares the leading sub-auths
+*/
+int dom_sid_compare_domain(const struct dom_sid *sid1,
+ const struct dom_sid *sid2)
+{
+ int n, i;
+
+ n = MIN(sid1->num_auths, sid2->num_auths);
+
+ for (i = n-1; i >= 0; --i) {
+ if (sid1->sub_auths[i] < sid2->sub_auths[i]) {
+ return -1;
+ }
+ if (sid1->sub_auths[i] > sid2->sub_auths[i]) {
+ return 1;
+ }
+ }
+
+ return dom_sid_compare_auth(sid1, sid2);
+}
+
+/*****************************************************************
+ Convert a string to a SID. Returns True on success, False on fail.
+ Return the first character not parsed in endp.
+*****************************************************************/
+#define AUTHORITY_MASK (~(0xffffffffffffULL))
+
+bool dom_sid_parse_endp(const char *sidstr,struct dom_sid *sidout,
+ const char **endp)
+{
+ const char *p;
+ char *q = NULL;
+ char *end = NULL;
+ uint64_t conv;
+ int error = 0;
+
+ *sidout = (struct dom_sid) {};
+
+ if ((sidstr[0] != 'S' && sidstr[0] != 's') || sidstr[1] != '-') {
+ goto format_error;
+ }
+
+ /* Get the revision number. */
+ p = sidstr + 2;
+
+ if (!isdigit((unsigned char)*p)) {
+ goto format_error;
+ }
+
+ conv = smb_strtoul(p, &q, 10, &error, SMB_STR_STANDARD);
+ if (error != 0 || (*q != '-') || conv > UINT8_MAX || q - p > 4) {
+ goto format_error;
+ }
+ sidout->sid_rev_num = (uint8_t) conv;
+ q++;
+
+ if (!isdigit((unsigned char)*q)) {
+ goto format_error;
+ }
+ while (q[0] == '0' && isdigit((unsigned char)q[1])) {
+ /*
+ * strtoull will think this is octal, which is not how SIDs
+ * work! So let's walk along until there are no leading zeros
+ * (or a single zero).
+ */
+ q++;
+ }
+
+ /* get identauth */
+ conv = smb_strtoull(q, &end, 0, &error, SMB_STR_STANDARD);
+ if (conv & AUTHORITY_MASK || error != 0) {
+ goto format_error;
+ }
+ if (conv >= (1ULL << 48) || end - q > 15) {
+ /*
+ * This identauth looks like a big number, but resolves to a
+ * small number after rounding.
+ */
+ goto format_error;
+ }
+
+ /* NOTE - the conv value is in big-endian format. */
+ sidout->id_auth[0] = (conv & 0xff0000000000ULL) >> 40;
+ sidout->id_auth[1] = (conv & 0x00ff00000000ULL) >> 32;
+ sidout->id_auth[2] = (conv & 0x0000ff000000ULL) >> 24;
+ sidout->id_auth[3] = (conv & 0x000000ff0000ULL) >> 16;
+ sidout->id_auth[4] = (conv & 0x00000000ff00ULL) >> 8;
+ sidout->id_auth[5] = (conv & 0x0000000000ffULL);
+
+ sidout->num_auths = 0;
+ q = end;
+ if (*q != '-') {
+ /* Just id_auth, no subauths */
+ goto done;
+ }
+
+ q++;
+
+ while (true) {
+ if (!isdigit((unsigned char)*q)) {
+ goto format_error;
+ }
+ while (q[0] == '0' && isdigit((unsigned char)q[1])) {
+ /*
+ * strtoull will think this is octal, which is not how
+ * SIDs work! So let's walk along until there are no
+ * leading zeros (or a single zero).
+ */
+ q++;
+ }
+ conv = smb_strtoull(q, &end, 0, &error, SMB_STR_STANDARD);
+ if (conv > UINT32_MAX || error != 0 || end - q > 12) {
+ /*
+ * This sub-auth is greater than 4294967295,
+ * and hence invalid. Windows will treat it as
+ * 4294967295, while we prefer to refuse (old
+ * versions of Samba will wrap, arriving at
+ * another number altogether).
+ */
+ DBG_NOTICE("bad sub-auth in %s\n", sidstr);
+ goto format_error;
+ }
+
+ if (!sid_append_rid(sidout, conv)) {
+ DEBUG(3, ("Too many sid auths in %s\n", sidstr));
+ return false;
+ }
+
+ q = end;
+ if (*q != '-') {
+ break;
+ }
+ q += 1;
+ }
+done:
+ if (endp != NULL) {
+ *endp = q;
+ }
+ return true;
+
+format_error:
+ DEBUG(3, ("string_to_sid: SID %s is not in a valid format\n", sidstr));
+ return false;
+}
+
+bool string_to_sid(struct dom_sid *sidout, const char *sidstr)
+{
+ return dom_sid_parse(sidstr, sidout);
+}
+
+bool dom_sid_parse(const char *sidstr, struct dom_sid *ret)
+{
+ return dom_sid_parse_endp(sidstr, ret, NULL);
+}
+
+/*
+ convert a string to a dom_sid, returning a talloc'd dom_sid
+*/
+struct dom_sid *dom_sid_parse_talloc(TALLOC_CTX *mem_ctx, const char *sidstr)
+{
+ struct dom_sid *ret;
+ ret = talloc(mem_ctx, struct dom_sid);
+ if (!ret) {
+ return NULL;
+ }
+ if (!dom_sid_parse(sidstr, ret)) {
+ talloc_free(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+/*
+ convert a string to a dom_sid, returning a talloc'd dom_sid
+*/
+struct dom_sid *dom_sid_parse_length(TALLOC_CTX *mem_ctx, const DATA_BLOB *sid)
+{
+ char p[sid->length+1];
+ memcpy(p, sid->data, sid->length);
+ p[sid->length] = '\0';
+ return dom_sid_parse_talloc(mem_ctx, p);
+}
+
+/*
+ copy a dom_sid structure
+*/
+struct dom_sid *dom_sid_dup(TALLOC_CTX *mem_ctx, const struct dom_sid *dom_sid)
+{
+ struct dom_sid *ret;
+
+ if (!dom_sid) {
+ return NULL;
+ }
+
+ ret = talloc(mem_ctx, struct dom_sid);
+ if (!ret) {
+ return NULL;
+ }
+ sid_copy(ret, dom_sid);
+
+ return ret;
+}
+
+/*
+ add a rid to a domain dom_sid to make a full dom_sid. This function
+ returns a new sid in the supplied memory context
+*/
+struct dom_sid *dom_sid_add_rid(TALLOC_CTX *mem_ctx,
+ const struct dom_sid *domain_sid,
+ uint32_t rid)
+{
+ struct dom_sid *sid;
+
+ sid = dom_sid_dup(mem_ctx, domain_sid);
+ if (!sid) return NULL;
+
+ if (!sid_append_rid(sid, rid)) {
+ talloc_free(sid);
+ return NULL;
+ }
+
+ return sid;
+}
+
+/*
+ Split up a SID into its domain and RID part
+*/
+NTSTATUS dom_sid_split_rid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
+ struct dom_sid **domain, uint32_t *rid)
+{
+ if (sid->num_auths == 0) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (domain) {
+ if (!(*domain = dom_sid_dup(mem_ctx, sid))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*domain)->num_auths -= 1;
+ }
+
+ if (rid) {
+ *rid = sid->sub_auths[sid->num_auths - 1];
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ return true if the 2nd sid is in the domain given by the first sid
+*/
+bool dom_sid_in_domain(const struct dom_sid *domain_sid,
+ const struct dom_sid *sid)
+{
+ int i;
+
+ if (!domain_sid || !sid) {
+ return false;
+ }
+
+ if (sid->num_auths < 2) {
+ return false;
+ }
+
+ if (domain_sid->num_auths != (sid->num_auths - 1)) {
+ return false;
+ }
+
+ for (i = domain_sid->num_auths-1; i >= 0; --i) {
+ if (domain_sid->sub_auths[i] != sid->sub_auths[i]) {
+ return false;
+ }
+ }
+
+ return dom_sid_compare_auth(domain_sid, sid) == 0;
+}
+
+bool dom_sid_has_account_domain(const struct dom_sid *sid)
+{
+ if (sid == NULL) {
+ return false;
+ }
+
+ if (sid->sid_rev_num != 1) {
+ return false;
+ }
+ if (sid->num_auths != 5) {
+ return false;
+ }
+ if (sid->id_auth[5] != 5) {
+ return false;
+ }
+ if (sid->id_auth[4] != 0) {
+ return false;
+ }
+ if (sid->id_auth[3] != 0) {
+ return false;
+ }
+ if (sid->id_auth[2] != 0) {
+ return false;
+ }
+ if (sid->id_auth[1] != 0) {
+ return false;
+ }
+ if (sid->id_auth[0] != 0) {
+ return false;
+ }
+ if (sid->sub_auths[0] != 21) {
+ return false;
+ }
+
+ return true;
+}
+
+bool dom_sid_is_valid_account_domain(const struct dom_sid *sid)
+{
+ /*
+ * We expect S-1-5-21-9-8-7, but we don't
+ * allow S-1-5-21-0-0-0 as this is used
+ * for claims and compound identities.
+ *
+ * With this structure:
+ *
+ * struct dom_sid {
+ * uint8_t sid_rev_num;
+ * int8_t num_auths; [range(0,15)]
+ * uint8_t id_auth[6];
+ * uint32_t sub_auths[15];
+ * }
+ *
+ * S-1-5-21-9-8-7 looks like this:
+ * {1, 4, {0,0,0,0,0,5}, {21,9,8,7,0,0,0,0,0,0,0,0,0,0,0}};
+ */
+ if (sid == NULL) {
+ return false;
+ }
+
+ if (sid->sid_rev_num != 1) {
+ return false;
+ }
+ if (sid->num_auths != 4) {
+ return false;
+ }
+ if (sid->id_auth[5] != 5) {
+ return false;
+ }
+ if (sid->id_auth[4] != 0) {
+ return false;
+ }
+ if (sid->id_auth[3] != 0) {
+ return false;
+ }
+ if (sid->id_auth[2] != 0) {
+ return false;
+ }
+ if (sid->id_auth[1] != 0) {
+ return false;
+ }
+ if (sid->id_auth[0] != 0) {
+ return false;
+ }
+ if (sid->sub_auths[0] != 21) {
+ return false;
+ }
+ if (sid->sub_auths[1] == 0) {
+ return false;
+ }
+ if (sid->sub_auths[2] == 0) {
+ return false;
+ }
+ if (sid->sub_auths[3] == 0) {
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ Convert a dom_sid to a string, printing into a buffer. Return the
+ string length. If it overflows, return the string length that would
+ result (buflen needs to be +1 for the terminating 0).
+*/
+static int dom_sid_string_buf(const struct dom_sid *sid, char *buf, int buflen)
+{
+ int i, ofs, ret;
+ uint64_t ia;
+
+ if (!sid) {
+ return strlcpy(buf, "(NULL SID)", buflen);
+ }
+
+ ia = ((uint64_t)sid->id_auth[5]) +
+ ((uint64_t)sid->id_auth[4] << 8 ) +
+ ((uint64_t)sid->id_auth[3] << 16) +
+ ((uint64_t)sid->id_auth[2] << 24) +
+ ((uint64_t)sid->id_auth[1] << 32) +
+ ((uint64_t)sid->id_auth[0] << 40);
+
+ ret = snprintf(buf, buflen, "S-%"PRIu8"-", sid->sid_rev_num);
+ if (ret < 0) {
+ return ret;
+ }
+ ofs = ret;
+
+ if (ia >= UINT32_MAX) {
+ ret = snprintf(buf+ofs, MAX(buflen-ofs, 0), "0x%"PRIx64, ia);
+ } else {
+ ret = snprintf(buf+ofs, MAX(buflen-ofs, 0), "%"PRIu64, ia);
+ }
+ if (ret < 0) {
+ return ret;
+ }
+ ofs += ret;
+
+ for (i = 0; i < sid->num_auths; i++) {
+ ret = snprintf(
+ buf+ofs,
+ MAX(buflen-ofs, 0),
+ "-%"PRIu32,
+ sid->sub_auths[i]);
+ if (ret < 0) {
+ return ret;
+ }
+ ofs += ret;
+ }
+ return ofs;
+}
+
+/*
+ convert a dom_sid to a string
+*/
+char *dom_sid_string(TALLOC_CTX *mem_ctx, const struct dom_sid *sid)
+{
+ char buf[DOM_SID_STR_BUFLEN];
+ char *result;
+ int len;
+
+ len = dom_sid_string_buf(sid, buf, sizeof(buf));
+
+ if ((len < 0) || (len+1 > sizeof(buf))) {
+ return talloc_strdup(mem_ctx, "(SID ERR)");
+ }
+
+ /*
+ * Avoid calling strlen (via talloc_strdup), we already have
+ * the length
+ */
+ result = (char *)talloc_memdup(mem_ctx, buf, len+1);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ /*
+ * beautify the talloc_report output
+ */
+ talloc_set_name_const(result, result);
+ return result;
+}
+
+char *dom_sid_str_buf(const struct dom_sid *sid, struct dom_sid_buf *dst)
+{
+ int ret;
+ ret = dom_sid_string_buf(sid, dst->buf, sizeof(dst->buf));
+ if ((ret < 0) || (ret >= sizeof(dst->buf))) {
+ strlcpy(dst->buf, "(INVALID SID)", sizeof(dst->buf));
+ }
+ return dst->buf;
+}
diff --git a/libcli/security/dom_sid.h b/libcli/security/dom_sid.h
new file mode 100644
index 0000000..343001e
--- /dev/null
+++ b/libcli/security/dom_sid.h
@@ -0,0 +1,155 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Copyright (C) Stefan (metze) Metzmacher 2002-2004
+ Copyright (C) Andrew Tridgell 1992-2004
+ Copyright (C) Jeremy Allison 1999
+
+ 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/>.
+*/
+
+#ifndef _DOM_SID_H_
+#define _DOM_SID_H_
+
+#include "replace.h"
+#include <talloc.h>
+#include "lib/util/data_blob.h"
+#include "librpc/gen_ndr/security.h"
+
+/* Some well-known SIDs */
+extern const struct dom_sid global_sid_World_Domain;
+extern const struct dom_sid global_sid_World;
+extern const struct dom_sid global_sid_Local_Authority;
+extern const struct dom_sid global_sid_Creator_Owner_Domain;
+extern const struct dom_sid global_sid_NT_Authority;
+extern const struct dom_sid global_sid_Enterprise_DCs;
+extern const struct dom_sid global_sid_System;
+extern const struct dom_sid global_sid_NULL;
+extern const struct dom_sid global_sid_Self;
+extern const struct dom_sid global_sid_Authenticated_Users;
+extern const struct dom_sid global_sid_Network;
+extern const struct dom_sid global_sid_Asserted_Identity;
+extern const struct dom_sid global_sid_Asserted_Identity_Service;
+extern const struct dom_sid global_sid_Asserted_Identity_Authentication_Authority;
+extern const struct dom_sid global_sid_Creator_Owner;
+extern const struct dom_sid global_sid_Creator_Group;
+extern const struct dom_sid global_sid_Owner_Rights;
+extern const struct dom_sid global_sid_Anonymous;
+extern const struct dom_sid global_sid_Compounded_Authentication;
+extern const struct dom_sid global_sid_Claims_Valid;
+extern const struct dom_sid global_sid_Builtin;
+extern const struct dom_sid global_sid_Builtin_Administrators;
+extern const struct dom_sid global_sid_Builtin_Users;
+extern const struct dom_sid global_sid_Builtin_Guests;
+extern const struct dom_sid global_sid_Builtin_Power_Users;
+extern const struct dom_sid global_sid_Builtin_Account_Operators;
+extern const struct dom_sid global_sid_Builtin_Server_Operators;
+extern const struct dom_sid global_sid_Builtin_Print_Operators;
+extern const struct dom_sid global_sid_Builtin_Backup_Operators;
+extern const struct dom_sid global_sid_Builtin_Replicator;
+extern const struct dom_sid global_sid_Builtin_PreWin2kAccess;
+extern const struct dom_sid global_sid_Unix_Users;
+extern const struct dom_sid global_sid_Unix_Groups;
+extern const struct dom_sid global_sid_Unix_NFS;
+extern const struct dom_sid global_sid_Unix_NFS_Users;
+extern const struct dom_sid global_sid_Unix_NFS_Groups;
+extern const struct dom_sid global_sid_Unix_NFS_Mode;
+extern const struct dom_sid global_sid_Unix_NFS_Other;
+extern const struct dom_sid global_sid_Samba_SMB3;
+
+extern const struct dom_sid global_sid_Samba_NPA_Flags;
+#define SAMBA_NPA_FLAGS_NEED_IDLE 1
+#define SAMBA_NPA_FLAGS_WINBIND_OFF 2
+
+struct auth_SidAttr;
+enum lsa_SidType;
+
+NTSTATUS dom_sid_lookup_predefined_name(const char *name,
+ const struct dom_sid **sid,
+ enum lsa_SidType *type,
+ const struct dom_sid **authority_sid,
+ const char **authority_name);
+NTSTATUS dom_sid_lookup_predefined_sid(const struct dom_sid *sid,
+ const char **name,
+ enum lsa_SidType *type,
+ const struct dom_sid **authority_sid,
+ const char **authority_name);
+bool dom_sid_lookup_is_predefined_domain(const char *domain);
+
+int dom_sid_compare_auth(const struct dom_sid *sid1,
+ const struct dom_sid *sid2);
+int dom_sid_compare(const struct dom_sid *sid1, const struct dom_sid *sid2);
+int dom_sid_compare_domain(const struct dom_sid *sid1,
+ const struct dom_sid *sid2);
+bool dom_sid_equal(const struct dom_sid *sid1, const struct dom_sid *sid2);
+bool sid_append_rid(struct dom_sid *sid, uint32_t rid);
+bool string_to_sid(struct dom_sid *sidout, const char *sidstr);
+bool dom_sid_parse_endp(const char *sidstr,struct dom_sid *sidout,
+ const char **endp);
+bool dom_sid_parse(const char *sidstr, struct dom_sid *ret);
+struct dom_sid *dom_sid_parse_talloc(TALLOC_CTX *mem_ctx, const char *sidstr);
+struct dom_sid *dom_sid_parse_length(TALLOC_CTX *mem_ctx, const DATA_BLOB *sid);
+struct dom_sid *dom_sid_dup(TALLOC_CTX *mem_ctx, const struct dom_sid *dom_sid);
+struct dom_sid *dom_sid_add_rid(TALLOC_CTX *mem_ctx,
+ const struct dom_sid *domain_sid,
+ uint32_t rid);
+NTSTATUS dom_sid_split_rid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
+ struct dom_sid **domain, uint32_t *rid);
+bool dom_sid_in_domain(const struct dom_sid *domain_sid,
+ const struct dom_sid *sid);
+bool dom_sid_has_account_domain(const struct dom_sid *sid);
+bool dom_sid_is_valid_account_domain(const struct dom_sid *sid);
+
+#define DOM_SID_STR_BUFLEN (15*11+25)
+char *dom_sid_string(TALLOC_CTX *mem_ctx, const struct dom_sid *sid);
+
+struct dom_sid_buf { char buf[DOM_SID_STR_BUFLEN]; };
+char *dom_sid_str_buf(const struct dom_sid *sid, struct dom_sid_buf *dst);
+
+const char *sid_type_lookup(uint32_t sid_type);
+const struct security_token *get_system_token(void);
+bool sid_compose(struct dom_sid *dst, const struct dom_sid *domain_sid, uint32_t rid);
+bool sid_split_rid(struct dom_sid *sid, uint32_t *rid);
+bool sid_peek_rid(const struct dom_sid *sid, uint32_t *rid);
+bool sid_peek_check_rid(const struct dom_sid *exp_dom_sid, const struct dom_sid *sid, uint32_t *rid);
+void sid_copy(struct dom_sid *dst, const struct dom_sid *src);
+ssize_t sid_parse(const uint8_t *inbuf, size_t len, struct dom_sid *sid);
+NTSTATUS add_sid_to_array(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
+ struct dom_sid **sids, uint32_t *num);
+NTSTATUS add_sid_to_array_unique(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
+ struct dom_sid **sids, uint32_t *num_sids);
+NTSTATUS add_sid_to_array_attrs(TALLOC_CTX *mem_ctx,
+ const struct dom_sid *sid, uint32_t attrs,
+ struct auth_SidAttr **sids, uint32_t *num);
+NTSTATUS add_sid_to_array_attrs_unique(TALLOC_CTX *mem_ctx,
+ const struct dom_sid *sid, uint32_t attrs,
+ struct auth_SidAttr **sids, uint32_t *num_sids);
+void del_sid_from_array(const struct dom_sid *sid, struct dom_sid **sids,
+ uint32_t *num);
+bool add_rid_to_array_unique(TALLOC_CTX *mem_ctx,
+ uint32_t rid, uint32_t **pp_rids, size_t *p_num);
+bool is_null_sid(const struct dom_sid *sid);
+bool sids_contains_sid(const struct dom_sid *sids,
+ const uint32_t num_sids,
+ const struct dom_sid *sid);
+bool sid_attrs_contains_sid(const struct auth_SidAttr *sids,
+ const uint32_t num_sids,
+ const struct dom_sid *sid);
+bool sids_contains_sid_attrs(const struct auth_SidAttr *sids,
+ const uint32_t num_sids,
+ const struct dom_sid *sid,
+ uint32_t attrs);
+
+#endif /*_DOM_SID_H_*/
diff --git a/libcli/security/object_tree.c b/libcli/security/object_tree.c
new file mode 100644
index 0000000..70b1ea0
--- /dev/null
+++ b/libcli/security/object_tree.c
@@ -0,0 +1,127 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ security access checking routines
+
+ Copyright (C) Nadezhda Ivanova 2009
+
+ 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/>.
+*/
+
+/*
+ * Description: Contains data handler functions for
+ * the object tree that must be constructed to perform access checks.
+ * The object tree is an unbalanced tree of depth 3, indexed by
+ * object type guid. Perhaps a different data structure
+ * should be considered later to improve performance
+ *
+ * Author: Nadezhda Ivanova
+ */
+#include "replace.h"
+#include "libcli/security/security.h"
+#include "librpc/ndr/libndr.h"
+
+/* Adds a new node to the object tree. If attributeSecurityGUID is not zero and
+ * has already been added to the tree, the new node is added as a child of that node
+ * In all other cases as a child of the root
+ */
+
+bool insert_in_object_tree(TALLOC_CTX *mem_ctx,
+ const struct GUID *guid,
+ uint32_t init_access,
+ struct object_tree *root,
+ struct object_tree **new_node_out)
+{
+ struct object_tree *new_node;
+
+ if (!guid || GUID_all_zero(guid)){
+ return true;
+ }
+
+ if (!root) {
+ root = talloc_zero(mem_ctx, struct object_tree);
+ if (!root) {
+ return false;
+ }
+ new_node = root;
+ } else {
+ int i;
+
+ for (i = 0; i < root->num_of_children; i++) {
+ if (GUID_equal(&root->children[i].guid, guid)) {
+ new_node = &root->children[i];
+ new_node->remaining_access |= init_access;
+ *new_node_out = new_node;
+ return true;
+ }
+ }
+
+ root->children = talloc_realloc(mem_ctx, root->children,
+ struct object_tree,
+ root->num_of_children + 1);
+ if (!root->children) {
+ return false;
+ }
+ new_node = &root->children[root->num_of_children];
+ root->num_of_children++;
+ }
+
+ new_node->children = NULL;
+ new_node->guid = *guid;
+ new_node->remaining_access = init_access;
+ new_node->num_of_children = 0;
+
+ *new_node_out = new_node;
+ return true;
+}
+
+/* search by GUID */
+struct object_tree *get_object_tree_by_GUID(struct object_tree *root,
+ const struct GUID *guid)
+{
+ struct object_tree *result = NULL;
+ int i;
+
+ if (!root || GUID_equal(&root->guid, guid)) {
+ result = root;
+ return result;
+ }
+ for (i = 0; i < root->num_of_children; i++) {
+ if ((result = get_object_tree_by_GUID(&root->children[i], guid)))
+ break;
+ }
+ return result;
+}
+
+/**
+ * @brief Modify the tree to mark specified access rights as granted
+ *
+ * This function will modify the root and the child of the tree pointed by
+ * root, so that for each tree element the bits set in access_mask are
+ * marked as granted.
+ *
+ * @param[in] root An object_tree structure that we want to modify
+ *
+ * @param[in] access_mask A bitfield of access right that we want to mark as
+ * granted in the whole tree.
+ */
+void object_tree_modify_access(struct object_tree *root,
+ uint32_t access_mask)
+{
+ int i;
+ root->remaining_access &= ~access_mask;
+ for (i = 0; i < root->num_of_children; i++) {
+ object_tree_modify_access(&root->children[i], access_mask);
+ }
+}
diff --git a/libcli/security/privileges.c b/libcli/security/privileges.c
new file mode 100644
index 0000000..33debdc
--- /dev/null
+++ b/libcli/security/privileges.c
@@ -0,0 +1,498 @@
+/*
+ Unix SMB/CIFS implementation.
+ Privileges handling functions
+ Copyright (C) Jean François Micouleau 1998-2001
+ Copyright (C) Simo Sorce 2002-2003
+ Copyright (C) Gerald (Jerry) Carter 2005
+ Copyright (C) Michael Adam 2007
+ Copyright (C) Andrew Bartlett 2010
+ Copyright (C) Andrew Tridgell 2004
+
+ 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/>.
+*/
+
+/*
+ * Basic privileges functions (mask-operations and conversion
+ * functions between the different formats (se_priv, privset, luid)
+ * moved here * from lib/privileges.c to minimize linker deps.
+ *
+ * generally SID- and LUID-related code is left in lib/privileges.c
+ *
+ * some extra functions to hide privs array from lib/privileges.c
+ */
+
+#include "replace.h"
+#include "libcli/security/privileges.h"
+#include "libcli/security/privileges_private.h"
+#include "librpc/gen_ndr/security.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/debug.h"
+
+/* The use of strcasecmp here is safe, all the comparison strings are ASCII */
+#undef strcasecmp
+
+#define NUM_SHORT_LIST_PRIVS 9
+
+static const struct {
+ enum sec_privilege luid;
+ uint64_t privilege_mask;
+ const char *name;
+ const char *description;
+} privs[] = {
+
+ {SEC_PRIV_MACHINE_ACCOUNT, SEC_PRIV_MACHINE_ACCOUNT_BIT, "SeMachineAccountPrivilege", "Add machines to domain"},
+ {SEC_PRIV_TAKE_OWNERSHIP, SEC_PRIV_TAKE_OWNERSHIP_BIT, "SeTakeOwnershipPrivilege", "Take ownership of files or other objects"},
+ {SEC_PRIV_BACKUP, SEC_PRIV_BACKUP_BIT, "SeBackupPrivilege", "Back up files and directories"},
+ {SEC_PRIV_RESTORE, SEC_PRIV_RESTORE_BIT, "SeRestorePrivilege", "Restore files and directories"},
+ {SEC_PRIV_REMOTE_SHUTDOWN, SEC_PRIV_REMOTE_SHUTDOWN_BIT, "SeRemoteShutdownPrivilege", "Force shutdown from a remote system"},
+
+ {SEC_PRIV_PRINT_OPERATOR, SEC_PRIV_PRINT_OPERATOR_BIT, "SePrintOperatorPrivilege", "Manage printers"},
+ {SEC_PRIV_ADD_USERS, SEC_PRIV_ADD_USERS_BIT, "SeAddUsersPrivilege", "Add users and groups to the domain"},
+ {SEC_PRIV_DISK_OPERATOR, SEC_PRIV_DISK_OPERATOR_BIT, "SeDiskOperatorPrivilege", "Manage disk shares"},
+ {SEC_PRIV_SECURITY, SEC_PRIV_SECURITY_BIT, "SeSecurityPrivilege", "System security"},
+
+
+ /* The list from here on is not displayed in the code from
+ * source3, and is after index NUM_SHORT_LIST_PRIVS for that
+ * reason */
+
+ {SEC_PRIV_SYSTEMTIME,
+ SEC_PRIV_SYSTEMTIME_BIT,
+ "SeSystemtimePrivilege",
+ "Set the system clock"},
+
+ {SEC_PRIV_SHUTDOWN,
+ SEC_PRIV_SHUTDOWN_BIT,
+ "SeShutdownPrivilege",
+ "Shutdown the system"},
+
+ {SEC_PRIV_DEBUG,
+ SEC_PRIV_DEBUG_BIT,
+ "SeDebugPrivilege",
+ "Debug processes"},
+
+ {SEC_PRIV_SYSTEM_ENVIRONMENT,
+ SEC_PRIV_SYSTEM_ENVIRONMENT_BIT,
+ "SeSystemEnvironmentPrivilege",
+ "Modify system environment"},
+
+ {SEC_PRIV_SYSTEM_PROFILE,
+ SEC_PRIV_SYSTEM_PROFILE_BIT,
+ "SeSystemProfilePrivilege",
+ "Profile the system"},
+
+ {SEC_PRIV_PROFILE_SINGLE_PROCESS,
+ SEC_PRIV_PROFILE_SINGLE_PROCESS_BIT,
+ "SeProfileSingleProcessPrivilege",
+ "Profile one process"},
+
+ {SEC_PRIV_INCREASE_BASE_PRIORITY,
+ SEC_PRIV_INCREASE_BASE_PRIORITY_BIT,
+ "SeIncreaseBasePriorityPrivilege",
+ "Increase base priority"},
+
+ {SEC_PRIV_LOAD_DRIVER,
+ SEC_PRIV_LOAD_DRIVER_BIT,
+ "SeLoadDriverPrivilege",
+ "Load drivers"},
+
+ {SEC_PRIV_CREATE_PAGEFILE,
+ SEC_PRIV_CREATE_PAGEFILE_BIT,
+ "SeCreatePagefilePrivilege",
+ "Create page files"},
+
+ {SEC_PRIV_INCREASE_QUOTA,
+ SEC_PRIV_INCREASE_QUOTA_BIT,
+ "SeIncreaseQuotaPrivilege",
+ "Increase quota"},
+
+ {SEC_PRIV_CHANGE_NOTIFY,
+ SEC_PRIV_CHANGE_NOTIFY_BIT,
+ "SeChangeNotifyPrivilege",
+ "Register for change notify"},
+
+ {SEC_PRIV_UNDOCK,
+ SEC_PRIV_UNDOCK_BIT,
+ "SeUndockPrivilege",
+ "Undock devices"},
+
+ {SEC_PRIV_MANAGE_VOLUME,
+ SEC_PRIV_MANAGE_VOLUME_BIT,
+ "SeManageVolumePrivilege",
+ "Manage system volumes"},
+
+ {SEC_PRIV_IMPERSONATE,
+ SEC_PRIV_IMPERSONATE_BIT,
+ "SeImpersonatePrivilege",
+ "Impersonate users"},
+
+ {SEC_PRIV_CREATE_GLOBAL,
+ SEC_PRIV_CREATE_GLOBAL_BIT,
+ "SeCreateGlobalPrivilege",
+ "Create global"},
+
+ {SEC_PRIV_ENABLE_DELEGATION,
+ SEC_PRIV_ENABLE_DELEGATION_BIT,
+ "SeEnableDelegationPrivilege",
+ "Enable Delegation"},
+};
+
+/* These are rights, not privileges, and should not be confused. The
+ * names are very similar, and they are quite similar in behaviour,
+ * but they are not to be enumerated as a system-wide list or have an
+ * LUID value */
+static const struct {
+ uint32_t right_mask;
+ const char *name;
+ const char *description;
+} rights[] = {
+ {LSA_POLICY_MODE_INTERACTIVE,
+ "SeInteractiveLogonRight",
+ "Interactive logon"},
+
+ {LSA_POLICY_MODE_NETWORK,
+ "SeNetworkLogonRight",
+ "Network logon"},
+
+ {LSA_POLICY_MODE_REMOTE_INTERACTIVE,
+ "SeRemoteInteractiveLogonRight",
+ "Remote Interactive logon"}
+};
+
+/*
+ return a privilege mask given a privilege id
+*/
+uint64_t sec_privilege_mask(enum sec_privilege privilege)
+{
+ size_t i;
+ for (i=0;i<ARRAY_SIZE(privs);i++) {
+ if (privs[i].luid == privilege) {
+ return privs[i].privilege_mask;
+ }
+ }
+
+ return 0;
+}
+
+/***************************************************************************
+ put all valid privileges into a mask
+****************************************************************************/
+
+void se_priv_put_all_privileges(uint64_t *privilege_mask)
+{
+ size_t i;
+
+ *privilege_mask = 0;
+ for ( i=0; i<ARRAY_SIZE(privs); i++ ) {
+ *privilege_mask |= privs[i].privilege_mask;
+ }
+}
+
+/*********************************************************************
+ Lookup the uint64_t bitmask value for a privilege name
+*********************************************************************/
+
+bool se_priv_from_name( const char *name, uint64_t *privilege_mask )
+{
+ size_t i;
+ for ( i=0; i<ARRAY_SIZE(privs); i++ ) {
+ if ( strequal( privs[i].name, name ) ) {
+ *privilege_mask = privs[i].privilege_mask;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+const char* get_privilege_dispname( const char *name )
+{
+ size_t i;
+
+ if (!name) {
+ return NULL;
+ }
+
+ for ( i=0; i<ARRAY_SIZE(privs); i++ ) {
+ if ( strequal( privs[i].name, name ) ) {
+ return privs[i].description;
+ }
+ }
+
+ return NULL;
+}
+
+/*******************************************************************
+ return the number of elements in the 'short' privilege array (traditional source3 behaviour)
+*******************************************************************/
+
+int num_privileges_in_short_list( void )
+{
+ return NUM_SHORT_LIST_PRIVS;
+}
+
+/****************************************************************************
+ add a privilege to a privilege array
+ ****************************************************************************/
+
+static bool privilege_set_add(PRIVILEGE_SET *priv_set, struct lsa_LUIDAttribute set)
+{
+ struct lsa_LUIDAttribute *new_set;
+
+ /* we can allocate memory to add the new privilege */
+
+ new_set = talloc_realloc(priv_set->mem_ctx, priv_set->set, struct lsa_LUIDAttribute, priv_set->count + 1);
+ if ( !new_set ) {
+ DEBUG(0,("privilege_set_add: failed to allocate memory!\n"));
+ return false;
+ }
+
+ new_set[priv_set->count].luid.high = set.luid.high;
+ new_set[priv_set->count].luid.low = set.luid.low;
+ new_set[priv_set->count].attribute = set.attribute;
+
+ priv_set->count++;
+ priv_set->set = new_set;
+
+ return true;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+bool se_priv_to_privilege_set( PRIVILEGE_SET *set, uint64_t privilege_mask )
+{
+ size_t i;
+ struct lsa_LUIDAttribute luid;
+
+ luid.attribute = 0;
+ luid.luid.high = 0;
+
+ for ( i=0; i<ARRAY_SIZE(privs); i++ ) {
+ if ((privilege_mask & privs[i].privilege_mask) == 0)
+ continue;
+
+ luid.luid.high = 0;
+ luid.luid.low = privs[i].luid;
+
+ if ( !privilege_set_add( set, luid ) )
+ return false;
+ }
+
+ return true;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+bool privilege_set_to_se_priv( uint64_t *privilege_mask, struct lsa_PrivilegeSet *privset )
+{
+ uint32_t i;
+
+ ZERO_STRUCTP( privilege_mask );
+
+ for ( i=0; i<privset->count; i++ ) {
+ uint64_t r;
+
+ /* sanity check for invalid privilege. we really
+ only care about the low 32 bits */
+
+ if ( privset->set[i].luid.high != 0 )
+ return false;
+
+ r = sec_privilege_mask(privset->set[i].luid.low);
+ if (r) {
+ *privilege_mask |= r;
+ }
+ }
+
+ return true;
+}
+
+/*
+ map a privilege id to the wire string constant
+*/
+const char *sec_privilege_name(enum sec_privilege privilege)
+{
+ size_t i;
+ for (i=0;i<ARRAY_SIZE(privs);i++) {
+ if (privs[i].luid == privilege) {
+ return privs[i].name;
+ }
+ }
+ return NULL;
+}
+
+/*
+ map a privilege id to a privilege display name. Return NULL if not found
+
+ TODO: this should use language mappings
+*/
+const char *sec_privilege_display_name(enum sec_privilege privilege, uint16_t *language)
+{
+ size_t i;
+ for (i=0;i<ARRAY_SIZE(privs);i++) {
+ if (privs[i].luid == privilege) {
+ return privs[i].description;
+ }
+ }
+ return NULL;
+}
+
+/*
+ map a privilege name to a privilege id. Return SEC_PRIV_INVALID if not found
+*/
+enum sec_privilege sec_privilege_id(const char *name)
+{
+ size_t i;
+ for (i=0;i<ARRAY_SIZE(privs);i++) {
+ if (strcasecmp(privs[i].name, name) == 0) {
+ return privs[i].luid;
+ }
+ }
+ return SEC_PRIV_INVALID;
+}
+
+/*
+ map a 'right' name to it's bitmap value. Return 0 if not found
+*/
+uint32_t sec_right_bit(const char *name)
+{
+ size_t i;
+ for (i=0;i<ARRAY_SIZE(rights);i++) {
+ if (strcasecmp(rights[i].name, name) == 0) {
+ return rights[i].right_mask;
+ }
+ }
+ return 0;
+}
+
+/*
+ assist in walking the table of privileges - return the LUID (low 32 bits) by index
+*/
+enum sec_privilege sec_privilege_from_index(int idx)
+{
+ if (idx >= 0 && (unsigned)idx<ARRAY_SIZE(privs)) {
+ return privs[idx].luid;
+ }
+ return SEC_PRIV_INVALID;
+}
+
+/*
+ assist in walking the table of privileges - return the string constant by index
+*/
+const char *sec_privilege_name_from_index(int idx)
+{
+ if (idx >= 0 && (unsigned)idx<ARRAY_SIZE(privs)) {
+ return privs[idx].name;
+ }
+ return NULL;
+}
+
+
+
+/*
+ return true if a security_token has a particular privilege bit set
+*/
+bool security_token_has_privilege(const struct security_token *token, enum sec_privilege privilege)
+{
+ uint64_t mask;
+
+ if (!token) {
+ return false;
+ }
+
+ mask = sec_privilege_mask(privilege);
+ if (mask == 0) {
+ return false;
+ }
+
+ if (token->privilege_mask & mask) {
+ return true;
+ }
+ return false;
+}
+
+bool security_token_system_privilege(const struct security_token *token)
+{
+ if (token == NULL) {
+ return false;
+ }
+
+ if (token->privilege_mask == (uint64_t)~0) {
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ set a bit in the privilege mask
+*/
+void security_token_set_privilege(struct security_token *token, enum sec_privilege privilege)
+{
+ /* Relies on the fact that an invalid privilege will return 0, so won't change this */
+ token->privilege_mask |= sec_privilege_mask(privilege);
+}
+
+/*
+ set a bit in the rights mask
+*/
+void security_token_set_right_bit(struct security_token *token, uint32_t right_bit)
+{
+ token->rights_mask |= right_bit;
+}
+
+char *security_token_debug_privileges(TALLOC_CTX *mem_ctx,
+ const struct security_token *token)
+{
+ char *s = NULL;
+
+ s = talloc_asprintf(mem_ctx,
+ " Privileges (0x%16" PRIX64 "):\n",
+ token->privilege_mask);
+
+ if (token->privilege_mask) {
+ size_t idx = 0;
+ size_t i = 0;
+ for (idx = 0; idx<ARRAY_SIZE(privs); idx++) {
+ if (token->privilege_mask & privs[idx].privilege_mask) {
+ talloc_asprintf_addbuf(
+ &s,
+ " Privilege[%3zu]: %s\n",
+ i++,
+ privs[idx].name);
+ }
+ }
+ }
+
+ talloc_asprintf_addbuf(&s,
+ " Rights (0x%16" PRIX32 "):\n",
+ token->rights_mask);
+
+ if (token->rights_mask) {
+ size_t idx = 0;
+ size_t i = 0;
+ for (idx = 0; idx<ARRAY_SIZE(rights); idx++) {
+ if (token->rights_mask & rights[idx].right_mask) {
+ talloc_asprintf_addbuf(&s,
+ " Right[%3zu]: %s\n",
+ i++,
+ rights[idx].name);
+ }
+ }
+ }
+
+ return s;
+}
diff --git a/libcli/security/privileges.h b/libcli/security/privileges.h
new file mode 100644
index 0000000..e9dab11
--- /dev/null
+++ b/libcli/security/privileges.h
@@ -0,0 +1,116 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Paul Ashton 1997
+ Copyright (C) Simo Sorce 2003
+ Copyright (C) Gerald (Jerry) Carter 2005
+ Copyright (C) Andrew Bartlett 2010
+
+ 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/>.
+*/
+
+#ifndef PRIVILEGES_H
+#define PRIVILEGES_H
+
+#include "lib/util/data_blob.h"
+#include "lib/util/time.h"
+#include "../librpc/gen_ndr/lsa.h"
+#include "../librpc/gen_ndr/security.h"
+
+/* common privilege bitmask defines */
+
+#define SE_ALL_PRIVS (uint64_t)-1
+
+/*
+ * These are used in Lsa replies (srv_lsa_nt.c)
+ */
+
+typedef struct {
+ TALLOC_CTX *mem_ctx;
+ bool ext_ctx;
+ uint32_t count;
+ uint32_t control;
+ struct lsa_LUIDAttribute *set;
+} PRIVILEGE_SET;
+
+const char* get_privilege_dispname( const char *name );
+
+/*******************************************************************
+ return the number of elements in the 'short' privilege array (traditional source3 behaviour)
+*******************************************************************/
+
+int num_privileges_in_short_list( void );
+
+/*
+ map a privilege id to the wire string constant
+*/
+const char *sec_privilege_name(enum sec_privilege privilege);
+
+/*
+ map a privilege id to a privilege display name. Return NULL if not found
+
+ TODO: this should use language mappings
+*/
+const char *sec_privilege_display_name(enum sec_privilege privilege, uint16_t *language);
+
+/*
+ map a privilege name to a privilege id. Return -1 if not found
+*/
+enum sec_privilege sec_privilege_id(const char *name);
+
+/*
+ map a 'right' name to it's bitmap value. Return 0 if not found
+*/
+uint32_t sec_right_bit(const char *name);
+
+/*
+ assist in walking the table of privileges - return the LUID (low 32 bits) by index
+*/
+enum sec_privilege sec_privilege_from_index(int idx);
+
+/*
+ assist in walking the table of privileges - return the string constant by index
+*/
+const char *sec_privilege_name_from_index(int idx);
+
+/*
+ return true if a security_token has a particular privilege bit set
+*/
+bool security_token_has_privilege(const struct security_token *token, enum sec_privilege privilege);
+
+
+/**
+ * @brief Check if the security token has system privileges.
+ *
+ * @param[in] token The token to check.
+ *
+ * @return True if the token has system privileges, false if not.
+ */
+bool security_token_system_privilege(const struct security_token *token);
+
+/*
+ set a bit in the privilege mask
+*/
+void security_token_set_privilege(struct security_token *token, enum sec_privilege privilege);
+/*
+ set a bit in the rights mask
+*/
+void security_token_set_right_bit(struct security_token *token, uint32_t right_bit);
+
+char *security_token_debug_privileges(TALLOC_CTX *mem_ctx,
+ const struct security_token *token);
+
+#endif /* PRIVILEGES_H */
diff --git a/libcli/security/privileges_private.h b/libcli/security/privileges_private.h
new file mode 100644
index 0000000..eec5ba3
--- /dev/null
+++ b/libcli/security/privileges_private.h
@@ -0,0 +1,41 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup
+ Copyright (C) Andrew Bartlett 2010
+
+ 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/>.
+*/
+
+/*********************************************************************
+ Lookup the privilege mask for a privilege name
+*********************************************************************/
+bool se_priv_from_name( const char *name, uint64_t *privilege_mask );
+
+/***************************************************************************
+ return a privilege mask given a privilege id
+****************************************************************************/
+uint64_t sec_privilege_mask(enum sec_privilege privilege);
+
+/***************************************************************************
+ put all privileges into a mask
+****************************************************************************/
+
+void se_priv_put_all_privileges(uint64_t *privilege_mask);
+
+/****************************************************************************
+ Convert PRIVILEGE_SET to a privilege bitmap and back again
+****************************************************************************/
+
+bool se_priv_to_privilege_set( PRIVILEGE_SET *set, uint64_t privilege_mask );
+bool privilege_set_to_se_priv( uint64_t *privilege_mask, struct lsa_PrivilegeSet *privset );
diff --git a/libcli/security/pysecurity.c b/libcli/security/pysecurity.c
new file mode 100644
index 0000000..037d43c
--- /dev/null
+++ b/libcli/security/pysecurity.c
@@ -0,0 +1,96 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2011
+
+ 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 "lib/replace/system/python.h"
+#include "python/py3compat.h"
+#include "includes.h"
+#include "python/modules.h"
+#include "libcli/util/pyerrors.h"
+#include "libcli/security/security.h"
+#include "pytalloc.h"
+
+static PyObject *py_se_access_check(PyObject *module, PyObject *args, PyObject *kwargs)
+{
+ NTSTATUS nt_status;
+ const char * const kwnames[] = { "security_descriptor", "token", "access_desired", NULL };
+ PyObject *py_sec_desc = NULL;
+ PyObject *py_security_token = NULL;
+ struct security_descriptor *security_descriptor;
+ struct security_token *security_token;
+ unsigned int access_desired; /* This is an unsigned int, not uint32_t,
+ * because that's what we need for the
+ * python PyArg_ParseTupleAndKeywords */
+ uint32_t access_granted;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOI",
+ discard_const_p(char *, kwnames),
+ &py_sec_desc, &py_security_token, &access_desired)) {
+ return NULL;
+ }
+
+ security_descriptor = pytalloc_get_type(py_sec_desc, struct security_descriptor);
+ if (!security_descriptor) {
+ PyErr_Format(PyExc_TypeError,
+ "Expected dcerpc.security.descriptor for security_descriptor argument got %s",
+ pytalloc_get_name(py_sec_desc));
+ return NULL;
+ }
+
+ security_token = pytalloc_get_type(py_security_token, struct security_token);
+ if (!security_token) {
+ PyErr_Format(PyExc_TypeError,
+ "Expected dcerpc.security.token for token argument, got %s",
+ pytalloc_get_name(py_sec_desc));
+ return NULL;
+ }
+
+ nt_status = se_access_check(security_descriptor, security_token, access_desired, &access_granted);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ PyErr_NTSTATUS_IS_ERR_RAISE(nt_status);
+ }
+
+ return PyLong_FromLong(access_granted);
+}
+
+static PyMethodDef py_security_methods[] = {
+ { "access_check", PY_DISCARD_FUNC_SIG(PyCFunction,
+ py_se_access_check),
+ METH_VARARGS|METH_KEYWORDS,
+ "access_check(security_descriptor, token, access_desired) -> access_granted. Raises NT_STATUS on error, including on access check failure, returns access granted bitmask"},
+ {0},
+};
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "security",
+ .m_doc = "Security support.",
+ .m_size = -1,
+ .m_methods = py_security_methods,
+};
+
+MODULE_INIT_FUNC(security)
+{
+ PyObject *m;
+
+ m = PyModule_Create(&moduledef);
+ if (m == NULL)
+ return NULL;
+
+ return m;
+}
diff --git a/libcli/security/sddl.c b/libcli/security/sddl.c
new file mode 100644
index 0000000..d1f7707
--- /dev/null
+++ b/libcli/security/sddl.c
@@ -0,0 +1,1341 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ security descriptor description language functions
+
+ Copyright (C) Andrew Tridgell 2005
+
+ 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 "replace.h"
+#include "lib/util/debug.h"
+#include "libcli/security/security.h"
+#include "libcli/security/conditional_ace.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "lib/util/smb_strtox.h"
+#include "libcli/security/sddl.h"
+#include "system/locale.h"
+#include "lib/util/util_str_hex.h"
+
+
+struct sddl_transition_state {
+ const struct dom_sid *machine_sid;
+ const struct dom_sid *domain_sid;
+ const struct dom_sid *forest_sid;
+};
+
+struct flag_map {
+ const char *name;
+ uint32_t flag;
+};
+
+static bool sddl_map_flag(
+ const struct flag_map *map,
+ const char *str,
+ size_t *plen,
+ uint32_t *pflag)
+{
+ while (map->name != NULL) {
+ size_t len = strlen(map->name);
+ int cmp = strncmp(map->name, str, len);
+
+ if (cmp == 0) {
+ *plen = len;
+ *pflag = map->flag;
+ return true;
+ }
+ map += 1;
+ }
+ return false;
+}
+
+/*
+ map a series of letter codes into a uint32_t
+*/
+static bool sddl_map_flags(const struct flag_map *map, const char *str,
+ uint32_t *pflags, size_t *plen,
+ bool unknown_flag_is_part_of_next_thing)
+{
+ const char *str0 = str;
+ if (plen != NULL) {
+ *plen = 0;
+ }
+ *pflags = 0;
+ while (str[0] != '\0' && isupper((unsigned char)str[0])) {
+ size_t len;
+ uint32_t flags;
+ bool found;
+
+ found = sddl_map_flag(map, str, &len, &flags);
+ if (!found) {
+ break;
+ }
+
+ *pflags |= flags;
+ if (plen != NULL) {
+ *plen += len;
+ }
+ str += len;
+ }
+ /*
+ * For ACL flags, unknown_flag_is_part_of_next_thing is set,
+ * and we expect some more stuff that isn't flags.
+ *
+ * For ACE flags, unknown_flag_is_part_of_next_thing is unset,
+ * and the flags have been tokenised into their own little
+ * string. We don't expect anything here, even whitespace.
+ */
+ if (*str == '\0' || unknown_flag_is_part_of_next_thing) {
+ return true;
+ }
+ DBG_WARNING("Unknown flag - '%s' in '%s'\n", str, str0);
+ return false;
+}
+
+
+/*
+ a mapping between the 2 letter SID codes and sid strings
+*/
+static const struct {
+ const char *code;
+ const char *sid;
+ uint32_t machine_rid;
+ uint32_t domain_rid;
+ uint32_t forest_rid;
+} sid_codes[] = {
+ { .code = "WD", .sid = SID_WORLD },
+
+ { .code = "CO", .sid = SID_CREATOR_OWNER },
+ { .code = "CG", .sid = SID_CREATOR_GROUP },
+ { .code = "OW", .sid = SID_OWNER_RIGHTS },
+
+ { .code = "NU", .sid = SID_NT_NETWORK },
+ { .code = "IU", .sid = SID_NT_INTERACTIVE },
+ { .code = "SU", .sid = SID_NT_SERVICE },
+ { .code = "AN", .sid = SID_NT_ANONYMOUS },
+ { .code = "ED", .sid = SID_NT_ENTERPRISE_DCS },
+ { .code = "PS", .sid = SID_NT_SELF },
+ { .code = "AU", .sid = SID_NT_AUTHENTICATED_USERS },
+ { .code = "RC", .sid = SID_NT_RESTRICTED },
+ { .code = "SY", .sid = SID_NT_SYSTEM },
+ { .code = "LS", .sid = SID_NT_LOCAL_SERVICE },
+ { .code = "NS", .sid = SID_NT_NETWORK_SERVICE },
+ { .code = "WR", .sid = SID_SECURITY_RESTRICTED_CODE },
+
+ { .code = "BA", .sid = SID_BUILTIN_ADMINISTRATORS },
+ { .code = "BU", .sid = SID_BUILTIN_USERS },
+ { .code = "BG", .sid = SID_BUILTIN_GUESTS },
+ { .code = "PU", .sid = SID_BUILTIN_POWER_USERS },
+ { .code = "AO", .sid = SID_BUILTIN_ACCOUNT_OPERATORS },
+ { .code = "SO", .sid = SID_BUILTIN_SERVER_OPERATORS },
+ { .code = "PO", .sid = SID_BUILTIN_PRINT_OPERATORS },
+ { .code = "BO", .sid = SID_BUILTIN_BACKUP_OPERATORS },
+ { .code = "RE", .sid = SID_BUILTIN_REPLICATOR },
+ { .code = "RU", .sid = SID_BUILTIN_PREW2K },
+ { .code = "RD", .sid = SID_BUILTIN_REMOTE_DESKTOP_USERS },
+ { .code = "NO", .sid = SID_BUILTIN_NETWORK_CONF_OPERATORS },
+
+ { .code = "MU", .sid = SID_BUILTIN_PERFMON_USERS },
+ { .code = "LU", .sid = SID_BUILTIN_PERFLOG_USERS },
+ { .code = "IS", .sid = SID_BUILTIN_IUSERS },
+ { .code = "CY", .sid = SID_BUILTIN_CRYPTO_OPERATORS },
+ { .code = "ER", .sid = SID_BUILTIN_EVENT_LOG_READERS },
+ { .code = "CD", .sid = SID_BUILTIN_CERT_SERV_DCOM_ACCESS },
+ { .code = "RA", .sid = SID_BUILTIN_RDS_REMOTE_ACCESS_SERVERS },
+ { .code = "ES", .sid = SID_BUILTIN_RDS_ENDPOINT_SERVERS },
+ { .code = "MS", .sid = SID_BUILTIN_RDS_MANAGEMENT_SERVERS },
+ { .code = "HA", .sid = SID_BUILTIN_HYPER_V_ADMINS },
+ { .code = "AA", .sid = SID_BUILTIN_ACCESS_CONTROL_ASSISTANCE_OPS },
+ { .code = "RM", .sid = SID_BUILTIN_REMOTE_MANAGEMENT_USERS },
+
+ { .code = "UD", .sid = SID_USER_MODE_DRIVERS },
+
+ { .code = "AC", .sid = SID_SECURITY_BUILTIN_PACKAGE_ANY_PACKAGE },
+
+ { .code = "LW", .sid = SID_SECURITY_MANDATORY_LOW },
+ { .code = "ME", .sid = SID_SECURITY_MANDATORY_MEDIUM },
+ { .code = "MP", .sid = SID_SECURITY_MANDATORY_MEDIUM_PLUS },
+ { .code = "HI", .sid = SID_SECURITY_MANDATORY_HIGH },
+ { .code = "SI", .sid = SID_SECURITY_MANDATORY_SYSTEM },
+
+ { .code = "AS", .sid = SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY },
+ { .code = "SS", .sid = SID_SERVICE_ASSERTED_IDENTITY },
+
+ { .code = "RO", .forest_rid = DOMAIN_RID_ENTERPRISE_READONLY_DCS },
+
+ { .code = "LA", .machine_rid = DOMAIN_RID_ADMINISTRATOR },
+ { .code = "LG", .machine_rid = DOMAIN_RID_GUEST },
+
+ { .code = "DA", .domain_rid = DOMAIN_RID_ADMINS },
+ { .code = "DU", .domain_rid = DOMAIN_RID_USERS },
+ { .code = "DG", .domain_rid = DOMAIN_RID_GUESTS },
+ { .code = "DC", .domain_rid = DOMAIN_RID_DOMAIN_MEMBERS },
+ { .code = "DD", .domain_rid = DOMAIN_RID_DCS },
+ { .code = "CA", .domain_rid = DOMAIN_RID_CERT_ADMINS },
+ { .code = "SA", .forest_rid = DOMAIN_RID_SCHEMA_ADMINS },
+ { .code = "EA", .forest_rid = DOMAIN_RID_ENTERPRISE_ADMINS },
+ { .code = "PA", .domain_rid = DOMAIN_RID_POLICY_ADMINS },
+
+ { .code = "CN", .domain_rid = DOMAIN_RID_CLONEABLE_CONTROLLERS },
+
+ { .code = "AP", .domain_rid = DOMAIN_RID_PROTECTED_USERS },
+ { .code = "KA", .domain_rid = DOMAIN_RID_KEY_ADMINS },
+ { .code = "EK", .forest_rid = DOMAIN_RID_ENTERPRISE_KEY_ADMINS },
+
+ { .code = "RS", .domain_rid = DOMAIN_RID_RAS_SERVERS }
+};
+
+/*
+ decode a SID
+ It can either be a special 2 letter code, or in S-* format
+*/
+static struct dom_sid *sddl_transition_decode_sid(TALLOC_CTX *mem_ctx, const char **sddlp,
+ struct sddl_transition_state *state)
+{
+ const char *sddl = (*sddlp);
+ size_t i;
+
+ /* see if its in the numeric format */
+ if (strncasecmp(sddl, "S-", 2) == 0) {
+ struct dom_sid *sid = NULL;
+ char *sid_str = NULL;
+ const char *end = NULL;
+ bool ok;
+ size_t len = strspn(sddl + 2, "-0123456789ABCDEFabcdefxX") + 2;
+ if (len < 5) { /* S-1-x */
+ return NULL;
+ }
+ if (sddl[len - 1] == 'D' && sddl[len] == ':') {
+ /*
+ * we have run into the "D:" dacl marker, mistaking it
+ * for a hex digit. There is no other way for this
+ * pair to occur at the end of a SID in SDDL.
+ */
+ len--;
+ }
+
+ sid_str = talloc_strndup(mem_ctx, sddl, len);
+ if (sid_str == NULL) {
+ return NULL;
+ }
+ if (sid_str[0] == 's') {
+ /*
+ * In SDDL, but not in the dom_sid parsers, a
+ * lowercase "s-1-1-0" is accepted.
+ */
+ sid_str[0] = 'S';
+ }
+ sid = talloc(mem_ctx, struct dom_sid);
+ if (sid == NULL) {
+ TALLOC_FREE(sid_str);
+ return NULL;
+ };
+ ok = dom_sid_parse_endp(sid_str, sid, &end);
+ if (!ok) {
+ DBG_WARNING("could not parse SID '%s'\n", sid_str);
+ TALLOC_FREE(sid_str);
+ TALLOC_FREE(sid);
+ return NULL;
+ }
+ if (end - sid_str != len) {
+ DBG_WARNING("trailing junk after SID '%s'\n", sid_str);
+ TALLOC_FREE(sid_str);
+ TALLOC_FREE(sid);
+ return NULL;
+ }
+ TALLOC_FREE(sid_str);
+ (*sddlp) += len;
+ return sid;
+ }
+
+ /* now check for one of the special codes */
+ for (i=0;i<ARRAY_SIZE(sid_codes);i++) {
+ if (strncmp(sid_codes[i].code, sddl, 2) == 0) break;
+ }
+ if (i == ARRAY_SIZE(sid_codes)) {
+ DEBUG(1,("Unknown sddl sid code '%2.2s'\n", sddl));
+ return NULL;
+ }
+
+ (*sddlp) += 2;
+
+
+ if (sid_codes[i].machine_rid != 0) {
+ return dom_sid_add_rid(mem_ctx, state->machine_sid,
+ sid_codes[i].machine_rid);
+ }
+
+ if (sid_codes[i].domain_rid != 0) {
+ return dom_sid_add_rid(mem_ctx, state->domain_sid,
+ sid_codes[i].domain_rid);
+ }
+
+ if (sid_codes[i].forest_rid != 0) {
+ return dom_sid_add_rid(mem_ctx, state->forest_sid,
+ sid_codes[i].forest_rid);
+ }
+
+ return dom_sid_parse_talloc(mem_ctx, sid_codes[i].sid);
+}
+
+struct dom_sid *sddl_decode_sid(TALLOC_CTX *mem_ctx, const char **sddlp,
+ const struct dom_sid *domain_sid)
+{
+ struct sddl_transition_state state = {
+ /*
+ * TODO: verify .machine_rid values really belong
+ * to the machine_sid on a member, once
+ * we pass machine_sid from the caller...
+ */
+ .machine_sid = domain_sid,
+ .domain_sid = domain_sid,
+ .forest_sid = domain_sid,
+ };
+ return sddl_transition_decode_sid(mem_ctx, sddlp, &state);
+}
+
+
+static const struct flag_map ace_types[] = {
+ { "AU", SEC_ACE_TYPE_SYSTEM_AUDIT },
+ { "AL", SEC_ACE_TYPE_SYSTEM_ALARM },
+ { "OA", SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT },
+ { "OD", SEC_ACE_TYPE_ACCESS_DENIED_OBJECT },
+ { "OU", SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT },
+ { "OL", SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT },
+ { "A", SEC_ACE_TYPE_ACCESS_ALLOWED },
+ { "D", SEC_ACE_TYPE_ACCESS_DENIED },
+
+ { "XA", SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK },
+ { "XD", SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK },
+ { "ZA", SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT },
+ /*
+ * SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT exists but has
+ * no SDDL flag.
+ *
+ * ZA and XU are switched in [MS-DTYP] as of version 36.0,
+ * but this should be corrected in later versions.
+ */
+ { "XU", SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK },
+
+ { "RA", SEC_ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE },
+ { NULL, 0 }
+};
+
+static const struct flag_map ace_flags[] = {
+ { "OI", SEC_ACE_FLAG_OBJECT_INHERIT },
+ { "CI", SEC_ACE_FLAG_CONTAINER_INHERIT },
+ { "NP", SEC_ACE_FLAG_NO_PROPAGATE_INHERIT },
+ { "IO", SEC_ACE_FLAG_INHERIT_ONLY },
+ { "ID", SEC_ACE_FLAG_INHERITED_ACE },
+ { "SA", SEC_ACE_FLAG_SUCCESSFUL_ACCESS },
+ { "FA", SEC_ACE_FLAG_FAILED_ACCESS },
+ { NULL, 0 },
+};
+
+static const struct flag_map ace_access_mask[] = {
+ { "CC", SEC_ADS_CREATE_CHILD },
+ { "DC", SEC_ADS_DELETE_CHILD },
+ { "LC", SEC_ADS_LIST },
+ { "SW", SEC_ADS_SELF_WRITE },
+ { "RP", SEC_ADS_READ_PROP },
+ { "WP", SEC_ADS_WRITE_PROP },
+ { "DT", SEC_ADS_DELETE_TREE },
+ { "LO", SEC_ADS_LIST_OBJECT },
+ { "CR", SEC_ADS_CONTROL_ACCESS },
+ { "SD", SEC_STD_DELETE },
+ { "RC", SEC_STD_READ_CONTROL },
+ { "WD", SEC_STD_WRITE_DAC },
+ { "WO", SEC_STD_WRITE_OWNER },
+ { "GA", SEC_GENERIC_ALL },
+ { "GX", SEC_GENERIC_EXECUTE },
+ { "GW", SEC_GENERIC_WRITE },
+ { "GR", SEC_GENERIC_READ },
+ { NULL, 0 }
+};
+
+static const struct flag_map decode_ace_access_mask[] = {
+ { "FA", FILE_GENERIC_ALL },
+ { "FR", FILE_GENERIC_READ },
+ { "FW", FILE_GENERIC_WRITE },
+ { "FX", FILE_GENERIC_EXECUTE },
+ { NULL, 0 },
+};
+
+
+static char *sddl_match_file_rights(TALLOC_CTX *mem_ctx,
+ uint32_t flags)
+{
+ int i;
+
+ /* try to find an exact match */
+ for (i=0;decode_ace_access_mask[i].name;i++) {
+ if (decode_ace_access_mask[i].flag == flags) {
+ return talloc_strdup(mem_ctx,
+ decode_ace_access_mask[i].name);
+ }
+ }
+ return NULL;
+}
+
+static bool sddl_decode_access(const char *str, uint32_t *pmask)
+{
+ const char *str0 = str;
+ char *end = NULL;
+ uint32_t mask = 0;
+ unsigned long long numeric_mask;
+ int err;
+ /*
+ * The access mask can be a number or a series of flags.
+ *
+ * Canonically the number is expressed in hexadecimal (with 0x), but
+ * per MS-DTYP and Windows behaviour, octal and decimal numbers are
+ * also accepted.
+ *
+ * Windows has two behaviours we choose not to replicate:
+ *
+ * 1. numbers exceeding 0xffffffff are truncated at that point,
+ * turning on all access flags.
+ *
+ * 2. negative numbers are accepted, so e.g. -2 becomes 0xfffffffe.
+ */
+ numeric_mask = smb_strtoull(str, &end, 0, &err, SMB_STR_STANDARD);
+ if (err == 0) {
+ if (numeric_mask > UINT32_MAX) {
+ DBG_WARNING("Bad numeric flag value - %llu in %s\n",
+ numeric_mask, str0);
+ return false;
+ }
+ if (end - str > sizeof("037777777777")) {
+ /* here's the tricky thing: if a number is big
+ * enough to overflow the uint64, it might end
+ * up small enough to fit in the uint32, and
+ * we'd miss that it overflowed. So we count
+ * the digits -- any more than 12 (for
+ * "037777777777") is too long for 32 bits,
+ * and the shortest 64-bit wrapping string is
+ * 19 (for "0x1" + 16 zeros).
+ */
+ DBG_WARNING("Bad numeric flag value in '%s'\n", str0);
+ return false;
+ }
+ if (*end != '\0') {
+ DBG_WARNING("Bad characters in '%s'\n", str0);
+ return false;
+ }
+ *pmask = numeric_mask;
+ return true;
+ }
+ /* It's not a positive number, so we'll look for flags */
+
+ while ((str[0] != '\0') &&
+ (isupper((unsigned char)str[0]) || str[0] == ' ')) {
+ uint32_t flags = 0;
+ size_t len = 0;
+ bool found;
+ while (str[0] == ' ') {
+ /*
+ * Following Windows we accept spaces between flags
+ * but not after flags. Not tabs, though, never tabs.
+ */
+ str++;
+ if (str[0] == '\0') {
+ DBG_WARNING("trailing whitespace in flags "
+ "- '%s'\n", str0);
+ return false;
+ }
+ }
+ found = sddl_map_flag(
+ ace_access_mask, str, &len, &flags);
+ found |= sddl_map_flag(
+ decode_ace_access_mask, str, &len, &flags);
+ if (!found) {
+ DEBUG(1, ("Unknown flag - %s in %s\n", str, str0));
+ return false;
+ }
+ mask |= flags;
+ str += len;
+ }
+ if (*str != '\0') {
+ DBG_WARNING("Bad characters in '%s'\n", str0);
+ return false;
+ }
+ *pmask = mask;
+ return true;
+}
+
+
+static bool sddl_decode_guid(const char *str, struct GUID *guid)
+{
+ if (strlen(str) != 36) {
+ return false;
+ }
+ return parse_guid_string(str, guid);
+}
+
+
+
+static DATA_BLOB sddl_decode_conditions(TALLOC_CTX *mem_ctx,
+ const enum ace_condition_flags ace_condition_flags,
+ const char *conditions,
+ size_t *length,
+ const char **msg,
+ size_t *msg_offset)
+{
+ DATA_BLOB blob = {0};
+ struct ace_condition_script *script = NULL;
+ script = ace_conditions_compile_sddl(mem_ctx,
+ ace_condition_flags,
+ conditions,
+ msg,
+ msg_offset,
+ length);
+ if (script != NULL) {
+ bool ok = conditional_ace_encode_binary(mem_ctx,
+ script,
+ &blob);
+ if (! ok) {
+ DBG_ERR("could not blobify '%s'\n", conditions);
+ }
+ }
+ return blob;
+}
+
+
+/*
+ decode an ACE
+ return true on success, false on failure
+ note that this routine modifies the string
+*/
+static bool sddl_decode_ace(TALLOC_CTX *mem_ctx,
+ struct security_ace *ace,
+ const enum ace_condition_flags ace_condition_flags,
+ char **sddl_copy,
+ struct sddl_transition_state *state,
+ const char **msg, size_t *msg_offset)
+{
+ const char *tok[7];
+ const char *s;
+ uint32_t v;
+ struct dom_sid *sid;
+ bool ok;
+ size_t len;
+ size_t count = 0;
+ char *str = *sddl_copy;
+ bool has_extra_data = false;
+ ZERO_STRUCTP(ace);
+
+ *msg_offset = 1;
+ if (*str != '(') {
+ *msg = talloc_strdup(mem_ctx, "Not an ACE");
+ return false;
+ }
+ str++;
+ /*
+ * First we split apart the 6 (or 7) tokens.
+ *
+ * 0. ace type
+ * 1. ace flags
+ * 2. access mask
+ * 3. object guid
+ * 4. inherit guid
+ * 5. sid
+ *
+ * 6/extra_data rare optional extra data
+ */
+ tok[0] = str;
+ while (*str != '\0') {
+ if (*str == ';') {
+ *str = '\0';
+ str++;
+ count++;
+ tok[count] = str;
+ if (count == 6) {
+ /*
+ * this looks like a conditional ACE
+ * or resource ACE, but we can't say
+ * for sure until we look at the ACE
+ * type (tok[0]), after the loop.
+ */
+ has_extra_data = true;
+ break;
+ }
+ continue;
+ }
+ /*
+ * we are not expecting a ')' in the 6 sections of an
+ * ordinary ACE, except ending the last one.
+ */
+ if (*str == ')') {
+ count++;
+ *str = '\0';
+ str++;
+ break;
+ }
+ str++;
+ }
+ if (count != 6) {
+ /* we hit the '\0' or ')' before all of ';;;;;)' */
+ *msg = talloc_asprintf(mem_ctx,
+ "malformed ACE with only %zu ';'",
+ MIN(count - 1, count));
+ return false;
+ }
+
+ /* parse ace type */
+ ok = sddl_map_flag(ace_types, tok[0], &len, &v);
+ if (!ok) {
+ *msg = talloc_asprintf(mem_ctx,
+ "Unknown ACE type - %s", tok[0]);
+ return false;
+ }
+ if (tok[0][len] != '\0') {
+ *msg = talloc_asprintf(mem_ctx,
+ "Garbage after ACE type - %s", tok[0]);
+ return false;
+ }
+
+ ace->type = v;
+
+ /*
+ * Only callback and resource aces should have trailing data.
+ */
+ if (sec_ace_callback(ace->type)) {
+ if (! has_extra_data) {
+ *msg = talloc_strdup(
+ mem_ctx,
+ "callback ACE has no trailing data");
+ *msg_offset = str - *sddl_copy;
+ return false;
+ }
+ } else if (sec_ace_resource(ace->type)) {
+ if (! has_extra_data) {
+ *msg = talloc_strdup(
+ mem_ctx,
+ "resource attribute ACE has no trailing data");
+ *msg_offset = str - *sddl_copy;
+ return false;
+ }
+ } else if (has_extra_data) {
+ *msg = talloc_strdup(
+ mem_ctx,
+ "ACE has trailing section but is not a "
+ "callback or resource ACE");
+ *msg_offset = str - *sddl_copy;
+ return false;
+ }
+
+ /* ace flags */
+ if (!sddl_map_flags(ace_flags, tok[1], &v, NULL, false)) {
+ *msg = talloc_strdup(mem_ctx,
+ "could not parse flags");
+ *msg_offset = tok[1] - *sddl_copy;
+ return false;
+ }
+ ace->flags = v;
+
+ /* access mask */
+ ok = sddl_decode_access(tok[2], &ace->access_mask);
+ if (!ok) {
+ *msg = talloc_strdup(mem_ctx,
+ "could not parse access string");
+ *msg_offset = tok[2] - *sddl_copy;
+ return false;
+ }
+
+ /* object */
+ if (tok[3][0] != 0) {
+ ok = sddl_decode_guid(tok[3], &ace->object.object.type.type);
+ if (!ok) {
+ *msg = talloc_strdup(mem_ctx,
+ "could not parse object GUID");
+ *msg_offset = tok[3] - *sddl_copy;
+ return false;
+ }
+ ace->object.object.flags |= SEC_ACE_OBJECT_TYPE_PRESENT;
+ }
+
+ /* inherit object */
+ if (tok[4][0] != 0) {
+ ok = sddl_decode_guid(tok[4],
+ &ace->object.object.inherited_type.inherited_type);
+ if (!ok) {
+ *msg = talloc_strdup(
+ mem_ctx,
+ "could not parse inherited object GUID");
+ *msg_offset = tok[4] - *sddl_copy;
+ return false;
+ }
+ ace->object.object.flags |= SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT;
+ }
+
+ /* trustee */
+ s = tok[5];
+ sid = sddl_transition_decode_sid(mem_ctx, &s, state);
+ if (sid == NULL) {
+ *msg = talloc_strdup(
+ mem_ctx,
+ "could not parse trustee SID");
+ *msg_offset = tok[5] - *sddl_copy;
+ return false;
+ }
+ ace->trustee = *sid;
+ talloc_free(sid);
+ if (*s != '\0') {
+ *msg = talloc_strdup(
+ mem_ctx,
+ "garbage after trustee SID");
+ *msg_offset = s - *sddl_copy;
+ return false;
+ }
+
+ if (sec_ace_callback(ace->type)) {
+ /*
+ * This is either a conditional ACE or some unknown
+ * type of callback ACE that will be rejected by the
+ * conditional ACE compiler.
+ */
+ size_t length;
+ DATA_BLOB conditions = {0};
+ s = tok[6];
+
+ conditions = sddl_decode_conditions(mem_ctx,
+ ace_condition_flags,
+ s,
+ &length,
+ msg,
+ msg_offset);
+ if (conditions.data == NULL) {
+ DBG_NOTICE("Conditional ACE compilation failure at %zu: %s\n",
+ *msg_offset, *msg);
+ *msg_offset += s - *sddl_copy;
+ return false;
+ }
+ ace->coda.conditions = conditions;
+
+ /*
+ * We have found the end of the conditions, and the
+ * next character should be the ')' to end the ACE.
+ */
+ if (s[length] != ')') {
+ *msg = talloc_strdup(
+ mem_ctx,
+ "Conditional ACE has trailing bytes"
+ " or lacks ')'");
+ *msg_offset = s + length - *sddl_copy;
+ return false;
+ }
+ str = discard_const_p(char, s + length + 1);
+ } else if (sec_ace_resource(ace->type)) {
+ size_t length;
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim = NULL;
+
+ if (! dom_sid_equal(&ace->trustee, &global_sid_World)) {
+ /* these are just the rules */
+ *msg = talloc_strdup(
+ mem_ctx,
+ "Resource Attribute ACE trustee must be "
+ "'S-1-1-0' or 'WD'.");
+ *msg_offset = tok[5] - *sddl_copy;
+ return false;
+ }
+
+ s = tok[6];
+ claim = sddl_decode_resource_attr(mem_ctx, s, &length);
+ if (claim == NULL) {
+ *msg = talloc_strdup(
+ mem_ctx,
+ "Resource Attribute ACE parse failure");
+ *msg_offset = s - *sddl_copy;
+ return false;
+ }
+ ace->coda.claim = *claim;
+
+ /*
+ * We want a ')' to end the ACE.
+ */
+ if (s[length] != ')') {
+ *msg = talloc_strdup(
+ mem_ctx,
+ "Resource Attribute ACE has trailing bytes"
+ " or lacks ')'");
+ *msg_offset = s + length - *sddl_copy;
+ return false;
+ }
+ str = discard_const_p(char, s + length + 1);
+ }
+
+ *sddl_copy = str;
+ return true;
+}
+
+static const struct flag_map acl_flags[] = {
+ { "P", SEC_DESC_DACL_PROTECTED },
+ { "AR", SEC_DESC_DACL_AUTO_INHERIT_REQ },
+ { "AI", SEC_DESC_DACL_AUTO_INHERITED },
+ { NULL, 0 }
+};
+
+/*
+ decode an ACL
+*/
+static struct security_acl *sddl_decode_acl(struct security_descriptor *sd,
+ const enum ace_condition_flags ace_condition_flags,
+ const char **sddlp, uint32_t *flags,
+ struct sddl_transition_state *state,
+ const char **msg, size_t *msg_offset)
+{
+ const char *sddl = *sddlp;
+ char *sddl_copy = NULL;
+ char *aces_start = NULL;
+ struct security_acl *acl;
+ size_t len;
+ *flags = 0;
+
+ acl = talloc_zero(sd, struct security_acl);
+ if (acl == NULL) {
+ return NULL;
+ }
+ acl->revision = SECURITY_ACL_REVISION_ADS;
+
+ if (isupper((unsigned char)sddl[0]) && sddl[1] == ':') {
+ /* its an empty ACL */
+ return acl;
+ }
+
+ /* work out the ACL flags */
+ if (!sddl_map_flags(acl_flags, sddl, flags, &len, true)) {
+ *msg = talloc_strdup(sd, "bad ACL flags");
+ *msg_offset = 0;
+ talloc_free(acl);
+ return NULL;
+ }
+ sddl += len;
+
+ if (sddl[0] != '(') {
+ /*
+ * it is empty apart from the flags
+ * (or the flags are bad, and we will find out when
+ * we try to parse the next bit as a top-level fragment)
+ */
+ *sddlp = sddl;
+ return acl;
+ }
+
+ /*
+ * now the ACEs
+ *
+ * For this we make a copy of the rest of the SDDL, which the ACE
+ * tokeniser will mutilate by putting '\0' where it finds ';'.
+ *
+ * We need to copy the rest of the SDDL string because it is not
+ * possible in general to find where an ACL ends if there are
+ * conditional ACEs.
+ */
+
+ sddl_copy = talloc_strdup(acl, sddl);
+ if (sddl_copy == NULL) {
+ TALLOC_FREE(acl);
+ return NULL;
+ }
+ aces_start = sddl_copy;
+
+ while (*sddl_copy == '(') {
+ bool ok;
+ if (acl->num_aces > UINT16_MAX / 16) {
+ /*
+ * We can't fit this many ACEs in a wire ACL
+ * which has a 16 bit size field (and 16 is
+ * the minimal size of an ACE with no subauths).
+ */
+ talloc_free(acl);
+ return NULL;
+ }
+
+ acl->aces = talloc_realloc(acl, acl->aces, struct security_ace,
+ acl->num_aces+1);
+ if (acl->aces == NULL) {
+ talloc_free(acl);
+ return NULL;
+ }
+ ok = sddl_decode_ace(acl->aces, &acl->aces[acl->num_aces],
+ ace_condition_flags,
+ &sddl_copy, state, msg, msg_offset);
+ if (!ok) {
+ *msg_offset += sddl_copy - aces_start;
+ talloc_steal(sd, *msg);
+ talloc_free(acl);
+ return NULL;
+ }
+ acl->num_aces++;
+ }
+ sddl += sddl_copy - aces_start;
+ TALLOC_FREE(aces_start);
+ (*sddlp) = sddl;
+ return acl;
+}
+
+/*
+ * Decode a security descriptor in SDDL format, catching compilation
+ * error messages, if any.
+ *
+ * The message will be a direct talloc child of mem_ctx or NULL.
+ */
+struct security_descriptor *sddl_decode_err_msg(TALLOC_CTX *mem_ctx, const char *sddl,
+ const struct dom_sid *domain_sid,
+ const enum ace_condition_flags ace_condition_flags,
+ const char **msg, size_t *msg_offset)
+{
+ struct sddl_transition_state state = {
+ /*
+ * TODO: verify .machine_rid values really belong
+ * to the machine_sid on a member, once
+ * we pass machine_sid from the caller...
+ */
+ .machine_sid = domain_sid,
+ .domain_sid = domain_sid,
+ .forest_sid = domain_sid,
+ };
+ const char *start = sddl;
+ struct security_descriptor *sd = NULL;
+
+ if (msg == NULL || msg_offset == NULL) {
+ DBG_ERR("Programmer misbehaviour: use sddl_decode() "
+ "or provide msg pointers.\n");
+ return NULL;
+ }
+ *msg = NULL;
+ *msg_offset = 0;
+
+ sd = talloc_zero(mem_ctx, struct security_descriptor);
+ if (sd == NULL) {
+ return NULL;
+ }
+ sd->revision = SECURITY_DESCRIPTOR_REVISION_1;
+ sd->type = SEC_DESC_SELF_RELATIVE;
+
+ while (*sddl) {
+ uint32_t flags;
+ char c = sddl[0];
+ if (sddl[1] != ':') {
+ *msg = talloc_strdup(mem_ctx,
+ "expected '[OGDS]:' section start "
+ "(or the previous section ended prematurely)");
+ goto failed;
+ }
+ sddl += 2;
+ switch (c) {
+ case 'D':
+ if (sd->dacl != NULL) goto failed;
+ sd->dacl = sddl_decode_acl(sd, ace_condition_flags, &sddl, &flags, &state, msg, msg_offset);
+ if (sd->dacl == NULL) goto failed;
+ sd->type |= flags | SEC_DESC_DACL_PRESENT;
+ break;
+ case 'S':
+ if (sd->sacl != NULL) goto failed;
+ sd->sacl = sddl_decode_acl(sd, ace_condition_flags, &sddl, &flags, &state, msg, msg_offset);
+ if (sd->sacl == NULL) goto failed;
+ /* this relies on the SEC_DESC_SACL_* flags being
+ 1 bit shifted from the SEC_DESC_DACL_* flags */
+ sd->type |= (flags<<1) | SEC_DESC_SACL_PRESENT;
+ break;
+ case 'O':
+ if (sd->owner_sid != NULL) goto failed;
+ sd->owner_sid = sddl_transition_decode_sid(sd, &sddl, &state);
+ if (sd->owner_sid == NULL) goto failed;
+ break;
+ case 'G':
+ if (sd->group_sid != NULL) goto failed;
+ sd->group_sid = sddl_transition_decode_sid(sd, &sddl, &state);
+ if (sd->group_sid == NULL) goto failed;
+ break;
+ default:
+ *msg = talloc_strdup(mem_ctx, "unexpected character (expected [OGDS])");
+ goto failed;
+ }
+ }
+ return sd;
+failed:
+ if (*msg != NULL) {
+ *msg = talloc_steal(mem_ctx, *msg);
+ }
+ /*
+ * The actual message (*msg) might still be NULL, but the
+ * offset at least provides a clue.
+ */
+ *msg_offset += sddl - start;
+
+ if (*msg_offset > strlen(sddl)) {
+ /*
+ * It's not that we *don't* trust our pointer difference
+ * arithmetic, just that we *shouldn't*. Let's render it
+ * harmless, before Python tries printing 18 quadrillion
+ * spaces.
+ */
+ DBG_WARNING("sddl error message offset %zu is too big\n",
+ *msg_offset);
+ *msg_offset = 0;
+ }
+ DEBUG(2,("Badly formatted SDDL '%s'\n", sddl));
+ talloc_free(sd);
+ return NULL;
+}
+
+
+/*
+ decode a security descriptor in SDDL format
+*/
+struct security_descriptor *sddl_decode(TALLOC_CTX *mem_ctx, const char *sddl,
+ const struct dom_sid *domain_sid)
+{
+ const char *msg = NULL;
+ size_t msg_offset = 0;
+ struct security_descriptor *sd = sddl_decode_err_msg(mem_ctx,
+ sddl,
+ domain_sid,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ &msg,
+ &msg_offset);
+ if (sd == NULL) {
+ DBG_NOTICE("could not decode '%s'\n", sddl);
+ if (msg != NULL) {
+ DBG_NOTICE(" %*c\n",
+ (int)msg_offset, '^');
+ DBG_NOTICE("error '%s'\n", msg);
+ talloc_free(discard_const(msg));
+ }
+ }
+ return sd;
+}
+
+/*
+ turn a set of flags into a string
+*/
+static char *sddl_flags_to_string(TALLOC_CTX *mem_ctx, const struct flag_map *map,
+ uint32_t flags, bool check_all)
+{
+ int i;
+ char *s;
+
+ /* try to find an exact match */
+ for (i=0;map[i].name;i++) {
+ if (map[i].flag == flags) {
+ return talloc_strdup(mem_ctx, map[i].name);
+ }
+ }
+
+ s = talloc_strdup(mem_ctx, "");
+
+ /* now by bits */
+ for (i=0;map[i].name;i++) {
+ if ((flags & map[i].flag) != 0) {
+ s = talloc_asprintf_append_buffer(s, "%s", map[i].name);
+ if (s == NULL) goto failed;
+ flags &= ~map[i].flag;
+ }
+ }
+
+ if (check_all && flags != 0) {
+ goto failed;
+ }
+
+ return s;
+
+failed:
+ talloc_free(s);
+ return NULL;
+}
+
+/*
+ encode a sid in SDDL format
+*/
+static char *sddl_transition_encode_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
+ struct sddl_transition_state *state)
+{
+ bool in_machine = dom_sid_in_domain(state->machine_sid, sid);
+ bool in_domain = dom_sid_in_domain(state->domain_sid, sid);
+ bool in_forest = dom_sid_in_domain(state->forest_sid, sid);
+ struct dom_sid_buf buf;
+ const char *sidstr = dom_sid_str_buf(sid, &buf);
+ uint32_t rid = 0;
+ size_t i;
+
+ if (sid->num_auths > 1) {
+ rid = sid->sub_auths[sid->num_auths-1];
+ }
+
+ for (i=0;i<ARRAY_SIZE(sid_codes);i++) {
+ /* seen if its a well known sid */
+ if (sid_codes[i].sid != NULL) {
+ int cmp;
+
+ cmp = strcmp(sidstr, sid_codes[i].sid);
+ if (cmp != 0) {
+ continue;
+ }
+
+ return talloc_strdup(mem_ctx, sid_codes[i].code);
+ }
+
+ if (rid == 0) {
+ continue;
+ }
+
+ if (in_machine && sid_codes[i].machine_rid == rid) {
+ return talloc_strdup(mem_ctx, sid_codes[i].code);
+ }
+ if (in_domain && sid_codes[i].domain_rid == rid) {
+ return talloc_strdup(mem_ctx, sid_codes[i].code);
+ }
+ if (in_forest && sid_codes[i].forest_rid == rid) {
+ return talloc_strdup(mem_ctx, sid_codes[i].code);
+ }
+ }
+
+ return talloc_strdup(mem_ctx, sidstr);
+}
+
+char *sddl_encode_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
+ const struct dom_sid *domain_sid)
+{
+ struct sddl_transition_state state = {
+ /*
+ * TODO: verify .machine_rid values really belong
+ * to the machine_sid on a member, once
+ * we pass machine_sid from the caller...
+ */
+ .machine_sid = domain_sid,
+ .domain_sid = domain_sid,
+ .forest_sid = domain_sid,
+ };
+ return sddl_transition_encode_sid(mem_ctx, sid, &state);
+}
+
+
+
+/*
+ encode an ACE in SDDL format
+*/
+static char *sddl_transition_encode_ace(TALLOC_CTX *mem_ctx, const struct security_ace *ace,
+ struct sddl_transition_state *state)
+{
+ char *sddl = NULL;
+ TALLOC_CTX *tmp_ctx;
+ struct GUID_txt_buf object_buf, iobject_buf;
+ const char *sddl_type="", *sddl_flags="", *sddl_mask="",
+ *sddl_object="", *sddl_iobject="", *sddl_trustee="";
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return NULL;
+ }
+
+ sddl_type = sddl_flags_to_string(tmp_ctx, ace_types, ace->type, true);
+ if (sddl_type == NULL) {
+ goto failed;
+ }
+
+ sddl_flags = sddl_flags_to_string(tmp_ctx, ace_flags, ace->flags,
+ true);
+ if (sddl_flags == NULL) {
+ goto failed;
+ }
+
+ sddl_mask = sddl_flags_to_string(tmp_ctx, ace_access_mask,
+ ace->access_mask, true);
+ if (sddl_mask == NULL) {
+ sddl_mask = sddl_match_file_rights(tmp_ctx,
+ ace->access_mask);
+ if (sddl_mask == NULL) {
+ sddl_mask = talloc_asprintf(tmp_ctx, "0x%x",
+ ace->access_mask);
+ }
+ if (sddl_mask == NULL) {
+ goto failed;
+ }
+ }
+
+ if (sec_ace_object(ace->type)) {
+ const struct security_ace_object *object = &ace->object.object;
+
+ if (ace->object.object.flags & SEC_ACE_OBJECT_TYPE_PRESENT) {
+ sddl_object = GUID_buf_string(
+ &object->type.type, &object_buf);
+ }
+
+ if (ace->object.object.flags &
+ SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT) {
+ sddl_iobject = GUID_buf_string(
+ &object->inherited_type.inherited_type,
+ &iobject_buf);
+ }
+ }
+ sddl_trustee = sddl_transition_encode_sid(tmp_ctx, &ace->trustee, state);
+ if (sddl_trustee == NULL) {
+ goto failed;
+ }
+
+ if (sec_ace_callback(ace->type)) {
+ /* encode the conditional part */
+ struct ace_condition_script *s = NULL;
+ const char *sddl_conditions = NULL;
+
+ s = parse_conditional_ace(tmp_ctx, ace->coda.conditions);
+
+ if (s == NULL) {
+ goto failed;
+ }
+
+ sddl_conditions = sddl_from_conditional_ace(tmp_ctx, s);
+ if (sddl_conditions == NULL) {
+ goto failed;
+ }
+
+ sddl = talloc_asprintf(mem_ctx, "%s;%s;%s;%s;%s;%s;%s",
+ sddl_type, sddl_flags, sddl_mask,
+ sddl_object, sddl_iobject,
+ sddl_trustee, sddl_conditions);
+ } else if (sec_ace_resource(ace->type)) {
+ /* encode the resource part */
+ const char *coda = NULL;
+ coda = sddl_resource_attr_from_claim(tmp_ctx,
+ &ace->coda.claim);
+
+ if (coda == NULL) {
+ DBG_WARNING("resource ACE has invalid claim\n");
+ goto failed;
+ }
+ sddl = talloc_asprintf(mem_ctx, "%s;%s;%s;%s;%s;%s;%s",
+ sddl_type, sddl_flags, sddl_mask,
+ sddl_object, sddl_iobject,
+ sddl_trustee, coda);
+ } else {
+ sddl = talloc_asprintf(mem_ctx, "%s;%s;%s;%s;%s;%s",
+ sddl_type, sddl_flags, sddl_mask,
+ sddl_object, sddl_iobject, sddl_trustee);
+ }
+failed:
+ talloc_free(tmp_ctx);
+ return sddl;
+}
+
+char *sddl_encode_ace(TALLOC_CTX *mem_ctx, const struct security_ace *ace,
+ const struct dom_sid *domain_sid)
+{
+ struct sddl_transition_state state = {
+ /*
+ * TODO: verify .machine_rid values really belong
+ * to the machine_sid on a member, once
+ * we pass machine_sid from the caller...
+ */
+ .machine_sid = domain_sid,
+ .domain_sid = domain_sid,
+ .forest_sid = domain_sid,
+ };
+ return sddl_transition_encode_ace(mem_ctx, ace, &state);
+}
+
+/*
+ encode an ACL in SDDL format
+*/
+static char *sddl_encode_acl(TALLOC_CTX *mem_ctx, const struct security_acl *acl,
+ uint32_t flags, struct sddl_transition_state *state)
+{
+ char *sddl;
+ uint32_t i;
+
+ /* add any ACL flags */
+ sddl = sddl_flags_to_string(mem_ctx, acl_flags, flags, false);
+ if (sddl == NULL) goto failed;
+
+ /* now the ACEs, encoded in braces */
+ for (i=0;i<acl->num_aces;i++) {
+ char *ace = sddl_transition_encode_ace(sddl, &acl->aces[i], state);
+ if (ace == NULL) goto failed;
+ sddl = talloc_asprintf_append_buffer(sddl, "(%s)", ace);
+ if (sddl == NULL) goto failed;
+ talloc_free(ace);
+ }
+
+ return sddl;
+
+failed:
+ talloc_free(sddl);
+ return NULL;
+}
+
+
+/*
+ encode a security descriptor to SDDL format
+*/
+char *sddl_encode(TALLOC_CTX *mem_ctx, const struct security_descriptor *sd,
+ const struct dom_sid *domain_sid)
+{
+ struct sddl_transition_state state = {
+ /*
+ * TODO: verify .machine_rid values really belong
+ * to the machine_sid on a member, once
+ * we pass machine_sid from the caller...
+ */
+ .machine_sid = domain_sid,
+ .domain_sid = domain_sid,
+ .forest_sid = domain_sid,
+ };
+ char *sddl;
+ TALLOC_CTX *tmp_ctx;
+
+ /* start with a blank string */
+ sddl = talloc_strdup(mem_ctx, "");
+ if (sddl == NULL) goto failed;
+
+ tmp_ctx = talloc_new(sddl);
+ if (tmp_ctx == NULL) {
+ goto failed;
+ }
+
+ if (sd->owner_sid != NULL) {
+ char *sid = sddl_transition_encode_sid(tmp_ctx, sd->owner_sid, &state);
+ if (sid == NULL) goto failed;
+ sddl = talloc_asprintf_append_buffer(sddl, "O:%s", sid);
+ if (sddl == NULL) goto failed;
+ }
+
+ if (sd->group_sid != NULL) {
+ char *sid = sddl_transition_encode_sid(tmp_ctx, sd->group_sid, &state);
+ if (sid == NULL) goto failed;
+ sddl = talloc_asprintf_append_buffer(sddl, "G:%s", sid);
+ if (sddl == NULL) goto failed;
+ }
+
+ if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl != NULL) {
+ char *acl = sddl_encode_acl(tmp_ctx, sd->dacl, sd->type, &state);
+ if (acl == NULL) goto failed;
+ sddl = talloc_asprintf_append_buffer(sddl, "D:%s", acl);
+ if (sddl == NULL) goto failed;
+ }
+
+ if ((sd->type & SEC_DESC_SACL_PRESENT) && sd->sacl != NULL) {
+ char *acl = sddl_encode_acl(tmp_ctx, sd->sacl, sd->type>>1, &state);
+ if (acl == NULL) goto failed;
+ sddl = talloc_asprintf_append_buffer(sddl, "S:%s", acl);
+ if (sddl == NULL) goto failed;
+ }
+
+ talloc_free(tmp_ctx);
+ return sddl;
+
+failed:
+ talloc_free(sddl);
+ return NULL;
+}
diff --git a/libcli/security/sddl.h b/libcli/security/sddl.h
new file mode 100644
index 0000000..03c8a27
--- /dev/null
+++ b/libcli/security/sddl.h
@@ -0,0 +1,47 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Copyright (C) 2009 Jelmer Vernooij <jelmer@samba.org>
+
+ 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/>.
+*/
+
+#ifndef __SDDL_H__
+#define __SDDL_H__
+
+#include <talloc.h>
+#include "lib/util/data_blob.h"
+
+#include "librpc/gen_ndr/conditional_ace.h"
+#include "librpc/gen_ndr/security.h"
+
+struct security_descriptor *sddl_decode(TALLOC_CTX *mem_ctx, const char *sddl,
+ const struct dom_sid *domain_sid);
+struct security_descriptor *sddl_decode_err_msg(TALLOC_CTX *mem_ctx, const char *sddl,
+ const struct dom_sid *domain_sid,
+ const enum ace_condition_flags ace_condition_flags,
+ const char **msg, size_t *msg_offset);
+char *sddl_encode(TALLOC_CTX *mem_ctx, const struct security_descriptor *sd,
+ const struct dom_sid *domain_sid);
+char *sddl_encode_ace(TALLOC_CTX *mem_ctx, const struct security_ace *ace,
+ const struct dom_sid *domain_sid);
+
+struct dom_sid *sddl_decode_sid(TALLOC_CTX *mem_ctx, const char **sddlp,
+ const struct dom_sid *domain_sid);
+
+char *sddl_encode_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
+ const struct dom_sid *domain_sid);
+
+#endif /* __SDDL_H__ */
diff --git a/libcli/security/sddl_conditional_ace.c b/libcli/security/sddl_conditional_ace.c
new file mode 100644
index 0000000..e9d83b7
--- /dev/null
+++ b/libcli/security/sddl_conditional_ace.c
@@ -0,0 +1,3476 @@
+/*
+ * Unix SMB implementation.
+ * Functions for understanding conditional ACEs
+ *
+ * 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 "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/conditional_ace.h"
+#include "libcli/security/security.h"
+#include "libcli/security/conditional_ace.h"
+#include "libcli/security/claims-conversions.h"
+#include "lib/util/tsort.h"
+#include "lib/util/bytearray.h"
+
+
+/* We're only dealing with utf-8 here. Honestly. */
+#undef strncasecmp
+
+
+#define SDDL_FLAG_EXPECTING_UNARY_OP 1
+#define SDDL_FLAG_EXPECTING_BINARY_OP 2
+#define SDDL_FLAG_EXPECTING_BINARY_LOGIC_OP 4
+#define SDDL_FLAG_EXPECTING_LOCAL_ATTR 8
+#define SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR 16
+#define SDDL_FLAG_EXPECTING_LITERAL 32
+#define SDDL_FLAG_EXPECTING_PAREN 64
+#define SDDL_FLAG_EXPECTING_PAREN_LITERAL 128
+#define SDDL_FLAG_NOT_EXPECTING_END_PAREN 256
+
+#define SDDL_FLAG_DEVICE 512
+
+#define SDDL_FLAG_IS_UNARY_OP (1 << 20)
+#define SDDL_FLAG_IS_BINARY_OP (1 << 21)
+
+
+#define SDDL_FLAGS_EXPR_START (SDDL_FLAG_EXPECTING_UNARY_OP | \
+ SDDL_FLAG_EXPECTING_LOCAL_ATTR | \
+ SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR | \
+ SDDL_FLAG_EXPECTING_PAREN)
+
+#define SDDL_FLAGS_MEMBER_OP (SDDL_FLAG_EXPECTING_LITERAL | \
+ SDDL_FLAG_EXPECTING_PAREN_LITERAL | \
+ SDDL_FLAG_IS_UNARY_OP)
+
+#define SDDL_FLAGS_RELATIONAL_OP (SDDL_FLAG_EXPECTING_LITERAL | \
+ SDDL_FLAG_EXPECTING_PAREN_LITERAL | \
+ SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR | \
+ SDDL_FLAG_IS_BINARY_OP)
+
+#define SDDL_FLAGS_CONTAINS_OP (SDDL_FLAG_EXPECTING_LITERAL | \
+ SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR | \
+ SDDL_FLAG_IS_BINARY_OP)
+
+#define SDDL_FLAGS_EXISTS_OP (SDDL_FLAG_EXPECTING_LOCAL_ATTR | \
+ SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR | \
+ SDDL_FLAG_IS_UNARY_OP)
+
+#define SDDL_FLAGS_LOGIC_OP (SDDL_FLAG_EXPECTING_LOCAL_ATTR | \
+ SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR | \
+ SDDL_FLAG_EXPECTING_PAREN | \
+ SDDL_FLAG_EXPECTING_UNARY_OP | \
+ SDDL_FLAG_IS_BINARY_OP)
+
+#define SDDL_FLAGS_ATTRIBUTE (SDDL_FLAG_EXPECTING_BINARY_OP | \
+ SDDL_FLAG_EXPECTING_BINARY_LOGIC_OP)
+
+#define SDDL_FLAGS_LITERAL SDDL_FLAG_EXPECTING_BINARY_LOGIC_OP
+
+#define SDDL_FLAGS_PAREN_END (SDDL_FLAG_EXPECTING_BINARY_LOGIC_OP | \
+ SDDL_FLAG_EXPECTING_BINARY_OP)
+
+enum {
+ SDDL_NOT_AN_OP = 0,
+ SDDL_PRECEDENCE_EXISTS,
+ SDDL_PRECEDENCE_COMMON,
+ SDDL_PRECEDENCE_NOT,
+ SDDL_PRECEDENCE_AND,
+ SDDL_PRECEDENCE_OR,
+ SDDL_PRECEDENCE_PAREN_END,
+ SDDL_PRECEDENCE_PAREN_START,
+};
+
+struct ace_condition_sddl_compiler_context {
+ TALLOC_CTX *mem_ctx;
+ const uint8_t *sddl;
+ uint32_t length;
+ uint32_t offset;
+ uint32_t stack_depth;
+ uint32_t max_program_length;
+ uint32_t approx_size;
+ struct ace_condition_script *program;
+ struct ace_condition_token *stack;
+ struct ace_condition_token *target;
+ uint32_t *target_len;
+ const char *message;
+ uint32_t message_offset;
+ struct dom_sid *domain_sid;
+ uint32_t state;
+ uint8_t last_token_type;
+ bool allow_device;
+};
+
+struct sddl_data {
+ const char *name;
+ uint32_t flags;
+ uint8_t op_precedence;
+ uint8_t nargs;
+};
+
+static const struct sddl_data sddl_strings[256] = {
+ /* operators */
+ [CONDITIONAL_ACE_TOKEN_MEMBER_OF] = {
+ "Member_of",
+ SDDL_FLAGS_MEMBER_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 1
+ },
+ [CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF] = {
+ "Device_Member_of",
+ SDDL_FLAGS_MEMBER_OP|SDDL_FLAG_DEVICE,
+ SDDL_PRECEDENCE_COMMON,
+ 1
+ },
+ [CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY] = {
+ /* [MS-DTYP] says "_Any", but windows prefers '_any' */
+ "Member_of_any",
+ SDDL_FLAGS_MEMBER_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 1
+ },
+ [CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY] = {
+ "Device_Member_of_Any",
+ SDDL_FLAGS_MEMBER_OP|SDDL_FLAG_DEVICE,
+ SDDL_PRECEDENCE_COMMON,
+ 1
+ },
+ [CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF] = {
+ "Not_Member_of",
+ SDDL_FLAGS_MEMBER_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 1
+ },
+ [CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF] = {
+ "Not_Device_Member_of",
+ SDDL_FLAGS_MEMBER_OP|SDDL_FLAG_DEVICE,
+ SDDL_PRECEDENCE_COMMON,
+ 1
+ },
+ [CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY] = {
+ "Not_Member_of_Any",
+ SDDL_FLAGS_MEMBER_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 1
+ },
+ [CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY] = {
+ "Not_Device_Member_of_Any",
+ SDDL_FLAGS_MEMBER_OP|SDDL_FLAG_DEVICE,
+ SDDL_PRECEDENCE_COMMON,
+ 1
+ },
+ [CONDITIONAL_ACE_TOKEN_EQUAL] = {
+ "==",
+ SDDL_FLAGS_RELATIONAL_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_NOT_EQUAL] = {
+ "!=",
+ SDDL_FLAGS_RELATIONAL_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_LESS_THAN] = {
+ "<",
+ SDDL_FLAGS_RELATIONAL_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL] = {
+ "<=",
+ SDDL_FLAGS_RELATIONAL_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_GREATER_THAN] = {
+ ">",
+ SDDL_FLAGS_RELATIONAL_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL] = {
+ ">=",
+ SDDL_FLAGS_RELATIONAL_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_CONTAINS] = {
+ "Contains",
+ SDDL_FLAGS_CONTAINS_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_ANY_OF] = {
+ "Any_of",
+ SDDL_FLAGS_CONTAINS_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_NOT_CONTAINS] = {
+ "Not_Contains",
+ SDDL_FLAGS_CONTAINS_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_NOT_ANY_OF] = {
+ "Not_Any_of",
+ SDDL_FLAGS_CONTAINS_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_AND] = {
+ "&&",
+ SDDL_FLAGS_LOGIC_OP,
+ SDDL_PRECEDENCE_AND,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_OR] = {
+ "||",
+ SDDL_FLAGS_LOGIC_OP,
+ SDDL_PRECEDENCE_OR,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_NOT] = {
+ "!",
+ (SDDL_FLAG_EXPECTING_PAREN |
+ SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR |
+ SDDL_FLAG_IS_UNARY_OP),
+ SDDL_PRECEDENCE_NOT,
+ 1
+ },
+ [CONDITIONAL_ACE_TOKEN_EXISTS] = {
+ "Exists",
+ SDDL_FLAGS_EXISTS_OP,
+ SDDL_PRECEDENCE_EXISTS,
+ 1
+ },
+ [CONDITIONAL_ACE_TOKEN_NOT_EXISTS] = {
+ "Not_Exists",
+ SDDL_FLAGS_EXISTS_OP,
+ SDDL_PRECEDENCE_EXISTS,
+ 1
+ },
+ /* pseudo-operator pseudo-tokens */
+ [CONDITIONAL_ACE_SAMBA_SDDL_PAREN] = {
+ "(",
+ 0,
+ SDDL_PRECEDENCE_PAREN_START,
+ 0
+ },
+ [CONDITIONAL_ACE_SAMBA_SDDL_PAREN_END] = {
+ ")",
+ SDDL_FLAGS_PAREN_END,
+ SDDL_PRECEDENCE_PAREN_END,
+ 0
+ },
+
+ /*
+ * non-operators.
+ * The names here are only used for error messages.
+ *
+ * some of them will never actually be encountered (e.g. 8-bit
+ * integers).
+ */
+ [CONDITIONAL_ACE_TOKEN_INT8] = {
+ .name = "8-bit integer",
+ .flags = SDDL_FLAGS_LITERAL,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_TOKEN_INT16] = {
+ "16-bit integer",
+ SDDL_FLAGS_LITERAL,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_TOKEN_INT32] = {
+ "32-bit integer",
+ SDDL_FLAGS_LITERAL,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_TOKEN_INT64] = {
+ "64-bit integer",
+ SDDL_FLAGS_LITERAL,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+
+ [CONDITIONAL_ACE_TOKEN_UNICODE] = {
+ "unicode",
+ SDDL_FLAGS_LITERAL,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_TOKEN_OCTET_STRING] = {
+ "byte string",
+ SDDL_FLAGS_LITERAL,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_TOKEN_COMPOSITE] = {
+ "composite list",
+ SDDL_FLAGS_LITERAL,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_TOKEN_SID] = {
+ "SID",
+ SDDL_FLAGS_LITERAL,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_LOCAL_ATTRIBUTE] = {
+ "local attribute",
+ SDDL_FLAGS_ATTRIBUTE,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_USER_ATTRIBUTE] = {
+ "user attribute",
+ SDDL_FLAGS_ATTRIBUTE,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_RESOURCE_ATTRIBUTE] = {
+ "resource attribute",
+ SDDL_FLAGS_ATTRIBUTE,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_DEVICE_ATTRIBUTE] = {
+ "device attribute",
+ SDDL_FLAGS_ATTRIBUTE|SDDL_FLAG_DEVICE,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_SAMBA_RESULT_BOOL] = {
+ "boolean result",
+ 0,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_SAMBA_RESULT_NULL] = {
+ "null result",
+ 0,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_SAMBA_RESULT_ERROR] = {
+ "error result",
+ 0,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+};
+
+struct sddl_attr_type{
+ const char *name;
+ uint8_t code;
+};
+
+/*
+ * These are the prefixes for non-local attribute types. [MS-DTYP]
+ * styles them in title case ("@User."), but Windows itself seems to
+ * prefer all-caps, so that is how we render them.
+ */
+static const struct sddl_attr_type sddl_attr_types[] = {
+ {"USER.", CONDITIONAL_ACE_USER_ATTRIBUTE},
+ {"RESOURCE.", CONDITIONAL_ACE_RESOURCE_ATTRIBUTE},
+ {"DEVICE.", CONDITIONAL_ACE_DEVICE_ATTRIBUTE},
+};
+
+
+struct sddl_write_context {
+ TALLOC_CTX *mem_ctx;
+ char *sddl;
+ size_t len;
+ size_t alloc_len;
+};
+
+static bool sddl_write(struct sddl_write_context *ctx,
+ const char *s)
+{
+ size_t len = strlen(s);
+ if (ctx->alloc_len - ctx->len <= len ||
+ ctx->sddl == NULL) {
+ size_t old = ctx->alloc_len;
+ ctx->alloc_len = old + MAX(old / 2, len + 50);
+ if (ctx->alloc_len <= old ||
+ ctx->alloc_len - ctx->len <= len) {
+ return false;
+ }
+ ctx->sddl = talloc_realloc(ctx->mem_ctx, ctx->sddl,
+ char, ctx->alloc_len);
+
+ if (ctx->sddl == NULL) {
+ return false;
+ }
+ }
+ memcpy(ctx->sddl + ctx->len, s, len);
+ ctx->len += len;
+ ctx->sddl[ctx->len] = 0;
+ return true;
+}
+
+/*
+ * This is a helper function to create a representation of a
+ * conditional ACE. This is not SDDL, more like a disassembly,
+ * but it uses some of the same tables.
+ */
+char *debug_conditional_ace(TALLOC_CTX *mem_ctx,
+ struct ace_condition_script *program)
+{
+ size_t i;
+ size_t depth = 0;
+ char stack[] = " ";
+ char line[120];
+ struct sddl_write_context ctx = {
+ .mem_ctx = mem_ctx
+ };
+
+ for (i = 0; i < program->length; i++) {
+ struct ace_condition_token *tok = &program->tokens[i];
+ struct sddl_data s = sddl_strings[tok->type];
+ char hex[21];
+ char *utf8 = NULL;
+ int utf8_len;
+ char type;
+ char nom[40];
+ snprintf(nom, sizeof(nom), "\033[1;33m%20s\033[0m", s.name);
+ switch (tok->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ if (tok->data.int64.sign > 3 ||
+ tok->data.int64.base > 3) {
+ goto error;
+ }
+ snprintf(line, sizeof(line),
+ "%s %"PRIi64" %c%c\n",
+ nom,
+ tok->data.int64.value,
+ "?+-_"[tok->data.int64.sign],
+ "?odh"[tok->data.int64.base]
+ );
+ type = 'i';
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
+ snprintf(line, sizeof(line),
+ "%s bool\n",
+ nom
+ );
+ type = 'b';
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_LESS_THAN:
+ case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
+ case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_ANY_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
+ case CONDITIONAL_ACE_TOKEN_AND:
+ case CONDITIONAL_ACE_TOKEN_OR:
+ snprintf(line, sizeof(line),
+ "%s bool\n",
+ nom
+ );
+ type = 'b';
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_EXISTS:
+ case CONDITIONAL_ACE_TOKEN_NOT_EXISTS:
+ case CONDITIONAL_ACE_TOKEN_NOT:
+ snprintf(line, sizeof(line),
+ "%s bool\n",
+ nom
+ );
+ type = 'b';
+ break;
+
+ case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
+ case CONDITIONAL_ACE_USER_ATTRIBUTE:
+ case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
+ case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
+ snprintf(line, sizeof(line),
+ "%s.%s (any type)\n",
+ nom,
+ tok->data.unicode.value
+ );
+ type = '?';
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ snprintf(line, sizeof(line),
+ "%s.%s (any type)\n",
+ nom,
+ tok->data.unicode.value
+ );
+ type = 'u';
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ utf8_len = MIN(tok->data.bytes.length, 9);
+ hex_encode_buf(hex, tok->data.bytes.data, utf8_len);
+
+ snprintf(line, sizeof(line),
+ "%s %.*s (%d)\n",
+ nom, utf8_len * 2, hex, utf8_len);
+ type = 'o';
+ break;
+ case CONDITIONAL_ACE_TOKEN_SID:
+ utf8 = sddl_encode_sid(mem_ctx,
+ &tok->data.sid.sid,
+ NULL);
+ snprintf(line, sizeof(line),
+ "%s (%s)\n",
+ nom, utf8);
+ type = 'S';
+ break;
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ snprintf(line, sizeof(line),
+ "%s %"PRIu32" direct members\n",
+ nom, tok->data.composite.n_members);
+ type = 'C';
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_INVALID_OR_PADDING:
+ snprintf(line, sizeof(line),
+ "%s\n", nom);
+ type = '0';
+ break;
+ default:
+ snprintf(line, sizeof(line),
+ "unknown opcode %#02x\n", tok->type);
+ type = '!';
+ break;
+ }
+
+ if (s.nargs > depth) {
+ snprintf(nom, sizeof(nom),
+ "UNDER: -%zu", s.nargs - depth);
+ depth = 0;
+ sddl_write(&ctx, nom);
+ } else if (depth >= strlen(stack)) {
+ snprintf(nom, sizeof(nom),
+ "depth %zu", s.nargs - depth);
+ depth -= (s.nargs - 1);
+ sddl_write(&ctx, nom);
+ } else {
+ depth -= s.nargs;
+ stack[depth] = type;
+ depth++;
+ if (depth < strlen(stack)) {
+ stack[depth] = ' ';
+ }
+ sddl_write(&ctx, stack);
+ }
+ sddl_write(&ctx, line);
+ }
+ if (depth == 1 && stack[0] == 'b') {
+ snprintf(line, sizeof(line),
+ "\033[1;32mGOOD: finishes on a single bool\033[0m\n");
+ } else {
+ snprintf(line, sizeof(line),
+ "\033[1;31mBAD: should finish with a bool\033[0m\n");
+ }
+ sddl_write(&ctx, line);
+ return ctx.sddl;
+
+ error:
+ TALLOC_FREE(ctx.sddl);
+ return NULL;
+}
+
+
+struct sddl_node {
+ struct ace_condition_token *tok;
+ struct sddl_node *lhs;
+ struct sddl_node *rhs;
+ bool wants_parens;
+};
+
+static bool sddl_write_int(struct sddl_write_context *ctx,
+ const struct ace_condition_token *tok)
+{
+ int64_t v = tok->data.int64.value;
+ uint8_t sign = tok->data.int64.sign;
+ uint8_t base = tok->data.int64.base;
+ char buf[26]; /* oct(1<<63) + sign + \0 */
+ char sign_char;
+ if (sign > CONDITIONAL_ACE_INT_SIGN_NONE ||
+ base > CONDITIONAL_ACE_INT_BASE_16) {
+ return false;
+ }
+
+ /*
+ * we have 9 combinations of base/sign (+ some invalid combinations of
+ * actual sign vs claimed sign).
+ */
+ if (sign == CONDITIONAL_ACE_INT_SIGN_NONE) {
+ /* octal and hex will end up unsigned! */
+ if (base == CONDITIONAL_ACE_INT_BASE_8) {
+ snprintf(buf, sizeof(buf), "0%"PRIo64, v);
+ } else if (base == CONDITIONAL_ACE_INT_BASE_10) {
+ snprintf(buf, sizeof(buf), "%"PRId64, v);
+ } else {
+ snprintf(buf, sizeof(buf), "0x%"PRIx64, v);
+ }
+ return sddl_write(ctx, buf);
+ }
+ if (sign == CONDITIONAL_ACE_INT_SIGN_POSITIVE && v < 0) {
+ return false;
+ }
+ if (sign == CONDITIONAL_ACE_INT_SIGN_NEGATIVE && v > 0) {
+ /* note we allow "-0", because we will parse it. */
+ return false;
+ }
+ sign_char = (sign == CONDITIONAL_ACE_INT_SIGN_NEGATIVE) ? '-' : '+';
+ /*
+ * We can use "%+ld" for the decimal sign (except -0), but
+ * "%+lx" and "%+lo" are invalid because %o and %x are
+ * unsigned.
+ */
+ if (base == CONDITIONAL_ACE_INT_BASE_10) {
+ if (v == 0) {
+ snprintf(buf, sizeof(buf), "%c0", sign_char);
+ } else {
+ snprintf(buf, sizeof(buf), "%+"PRId64, v);
+ }
+ return sddl_write(ctx, buf);
+ }
+
+ if (v == INT64_MIN) {
+ /*
+ * llabs(INT64_MIN) will be undefined.
+ * The lengths we must go to to round trip!
+ */
+ if (base == CONDITIONAL_ACE_INT_BASE_8) {
+ return sddl_write(ctx, "-01000000000000000000000");
+ }
+ return sddl_write(ctx, "-0x8000000000000000");
+ }
+
+ if (base == CONDITIONAL_ACE_INT_BASE_8) {
+ snprintf(buf, sizeof(buf), "%c0%llo", sign_char, llabs(v));
+ } else {
+ snprintf(buf, sizeof(buf), "%c0x%llx", sign_char, llabs(v));
+ }
+ return sddl_write(ctx, buf);
+}
+
+
+static bool sddl_should_escape_utf16(uint16_t c)
+{
+ if (c <= ' ' || c > 126) {
+ return true;
+ }
+
+ switch (c) {
+ case '!':
+ case '"':
+ case '&':
+ case '(':
+ case ')':
+ case '<':
+ case '=':
+ case '>':
+ case '|':
+ case '%':
+ return true;
+ }
+
+ return false;
+}
+
+static bool sddl_encode_attr_name(TALLOC_CTX *mem_ctx,
+ const char *src,
+ char **dest,
+ size_t *dest_len)
+{
+ size_t i, j;
+ bool ok;
+ uint16_t *utf16 = NULL;
+ char *escaped = NULL;
+ size_t utf16_byte_len;
+ size_t utf16_len;
+ size_t src_len = strlen(src);
+ size_t escapees;
+ size_t required;
+ *dest = NULL;
+
+ /*
+ * Writing the string escapes can only really happen in
+ * utf-16.
+ */
+ ok = convert_string_talloc(mem_ctx,
+ CH_UTF8, CH_UTF16LE,
+ src, src_len,
+ &utf16, &utf16_byte_len);
+ if (!ok) {
+ return false;
+ }
+ utf16_len = utf16_byte_len / 2;
+
+ escapees = 0;
+ for (i = 0; i < utf16_len; i++) {
+ uint16_t c = utf16[i];
+ if (sddl_should_escape_utf16(c)) {
+ escapees++;
+ }
+ if (c == 0) {
+ /* we can't have '\0' (or "%0000") in a name. */
+ TALLOC_FREE(utf16);
+ return false;
+ }
+ }
+
+ required = src_len + escapees * 5;
+ escaped = talloc_size(mem_ctx, required + 1);
+ if (escaped == NULL) {
+ TALLOC_FREE(utf16);
+ return false;
+ }
+
+ if (escapees == 0) {
+ /* there is nothing to escape: the original string is fine */
+ memcpy(escaped, src, src_len);
+ escaped[src_len] = '\0';
+ *dest = escaped;
+ *dest_len = src_len;
+ TALLOC_FREE(utf16);
+ return true;
+ }
+
+ for (i = 0, j = 0; i < utf16_len && j < required; i++) {
+ uint16_t c = utf16[i];
+ if (sddl_should_escape_utf16(c)) {
+ if (j + 5 >= required) {
+ TALLOC_FREE(escaped);
+ TALLOC_FREE(utf16);
+ return false;
+ }
+ snprintf(escaped + j, 6, "%%%04x", c);
+ j += 5;
+ } else {
+ escaped[j] = c;
+ j++;
+ }
+ }
+ escaped[j] = '\0';
+
+ *dest = escaped;
+ *dest_len = j;
+
+ TALLOC_FREE(utf16);
+ return true;
+}
+
+static bool sddl_write_attr(struct sddl_write_context *ctx,
+ struct ace_condition_token *tok)
+{
+ char *name = NULL;
+ size_t name_len;
+ size_t i;
+ bool ok = sddl_encode_attr_name(ctx->mem_ctx,
+ tok->data.local_attr.value,
+ &name, &name_len);
+ if (!ok) {
+ return false;
+ }
+ for (i = 0; i < ARRAY_SIZE(sddl_attr_types); i++) {
+ struct sddl_attr_type x = sddl_attr_types[i];
+ if (x.code == tok->type) {
+ ok = sddl_write(ctx, "@");
+ if (! ok) {
+ return false;
+ }
+ ok = sddl_write(ctx, x.name);
+ if (! ok) {
+ return false;
+ }
+ break;
+ }
+ }
+
+ ok = sddl_write(ctx, name);
+ talloc_free(name);
+ return ok;
+}
+
+
+static bool sddl_write_unicode(struct sddl_write_context *ctx,
+ const struct ace_condition_token *tok)
+{
+ char *quoted = NULL;
+ bool ok;
+ /*
+ * We rely on tok->data.unicode.value being
+ * nul-terminated.
+ */
+ if (strchr(tok->data.unicode.value, '"') != NULL) {
+ /*
+ * There is a double quote in this string, but SDDL
+ * has no mechanism for escaping these (or anything
+ * else) in unicode strings.
+ *
+ * The only thing to do is fail.
+ *
+ * This cannot happen with an ACE created from SDDL,
+ * because the same no-escapes rule applies on the way
+ * in.
+ */
+ return false;
+ }
+
+ quoted = talloc_asprintf(ctx->mem_ctx, "\"%s\"",
+ tok->data.unicode.value);
+ if (quoted == NULL) {
+ return false;
+ }
+ ok = sddl_write(ctx, quoted);
+ TALLOC_FREE(quoted);
+ return ok;
+}
+
+static bool sddl_write_octet_string(struct sddl_write_context *ctx,
+ const struct ace_condition_token *tok)
+{
+ bool ok;
+ char *hex = hex_encode_talloc(ctx->mem_ctx,
+ tok->data.bytes.data,
+ tok->data.bytes.length);
+ ok = sddl_write(ctx, "#");
+ if (!ok) {
+ return false;
+ }
+ ok = sddl_write(ctx, hex);
+ talloc_free(hex);
+ return ok;
+}
+
+/*
+ * For octet strings, the Resource attribute ACE SDDL differs from conditional
+ * ACE SDDL, lacking the leading '#'.
+ */
+static bool sddl_write_ra_octet_string(struct sddl_write_context *ctx,
+ const struct ace_condition_token *tok)
+{
+ bool ok;
+ char *hex = hex_encode_talloc(ctx->mem_ctx,
+ tok->data.bytes.data,
+ tok->data.bytes.length);
+ ok = sddl_write(ctx, hex);
+ talloc_free(hex);
+ return ok;
+}
+
+
+static bool sddl_write_sid(struct sddl_write_context *ctx,
+ const struct ace_condition_token *tok)
+{
+ bool ok;
+ char *sddl = NULL;
+ char *sid = sddl_encode_sid(ctx->mem_ctx,
+ &tok->data.sid.sid,
+ NULL);
+ if (sid == NULL) {
+ return false;
+ }
+ sddl = talloc_asprintf(ctx->mem_ctx, "SID(%s)", sid);
+ if (sddl == NULL) {
+ talloc_free(sid);
+ return false;
+ }
+ ok = sddl_write(ctx, sddl);
+ talloc_free(sid);
+ talloc_free(sddl);
+ return ok;
+}
+
+static bool sddl_write_composite(struct sddl_write_context *ctx,
+ struct ace_condition_token *tok)
+{
+ /*
+ * Looks like {1, 2, 3, "four", {"woah, nesting", {6}}, SID(BA)}.
+ */
+ struct ace_condition_composite *c = &tok->data.composite;
+ uint32_t i;
+ bool ok;
+ ok = sddl_write(ctx, "{");
+ if (!ok) {
+ return false;
+ }
+ for (i = 0; i < c->n_members; i++) {
+ struct ace_condition_token *t = &c->tokens[i];
+ if (i > 0) {
+ ok = sddl_write(ctx, ", ");
+ if (!ok) {
+ return false;
+ }
+ }
+ switch (t->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ ok = sddl_write_int(ctx, t);
+ break;
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ ok = sddl_write_unicode(ctx, t);
+ break;
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ ok = sddl_write_octet_string(ctx, t);
+ break;
+ case CONDITIONAL_ACE_TOKEN_SID:
+ ok = sddl_write_sid(ctx, t);
+ break;
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ return false;
+ default:
+ return false;
+ }
+ if (!ok) {
+ return false;
+ }
+ }
+ ok = sddl_write(ctx, "}");
+ return ok;
+}
+
+static bool sddl_write_node(struct sddl_write_context *ctx,
+ struct sddl_node *node)
+{
+ struct ace_condition_token *tok = node->tok;
+ switch (tok->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ return sddl_write_int(ctx, tok);
+
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_LESS_THAN:
+ case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
+ case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_ANY_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
+ case CONDITIONAL_ACE_TOKEN_AND:
+ case CONDITIONAL_ACE_TOKEN_OR:
+ case CONDITIONAL_ACE_TOKEN_EXISTS:
+ case CONDITIONAL_ACE_TOKEN_NOT_EXISTS:
+ case CONDITIONAL_ACE_TOKEN_NOT:
+ return sddl_write(ctx, sddl_strings[tok->type].name);
+
+ case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
+ case CONDITIONAL_ACE_USER_ATTRIBUTE:
+ case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
+ case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
+ return sddl_write_attr(ctx, tok);
+
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ return sddl_write_unicode(ctx, tok);
+
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ return sddl_write_octet_string(ctx, tok);
+
+ case CONDITIONAL_ACE_TOKEN_SID:
+ return sddl_write_sid(ctx, tok);
+
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ return sddl_write_composite(ctx, tok);
+
+ case CONDITIONAL_ACE_TOKEN_INVALID_OR_PADDING:
+ /*
+ * This is only expected at the very end, which we
+ * can't (and don't need to) check here, but we can at
+ * least ensure it's the end of a sub-expression.
+ */
+ return (node->rhs == NULL);
+ default:
+ return false;
+ }
+ /* not expecting to get here */
+ return false;
+}
+
+
+static inline bool sddl_wants_outer_parens(struct sddl_node *node)
+{
+ /*
+ * Binary ops (having a LHS) are always parenthesised "(a == 2)"
+ *
+ * Member-of ops are too, for some reason.
+ */
+ return (node->lhs != NULL ||
+ node->tok->type == CONDITIONAL_ACE_TOKEN_MEMBER_OF ||
+ node->tok->type == CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF ||
+ node->tok->type == CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY ||
+ node->tok->type == CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY ||
+ node->tok->type == CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF ||
+ node->tok->type == CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF ||
+ node->tok->type == CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY ||
+ node->tok->type == CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY);
+}
+
+
+static inline bool sddl_wants_inner_parens(struct sddl_node *node,
+ struct sddl_node *child)
+{
+ /*
+ * logical operators are serialised with parentheses around their
+ * arguments (for NOT it is obligatory).
+ */
+ if (node->tok->type != CONDITIONAL_ACE_TOKEN_NOT &&
+ node->tok->type != CONDITIONAL_ACE_TOKEN_AND &&
+ node->tok->type != CONDITIONAL_ACE_TOKEN_OR) {
+ return false;
+ }
+ if (sddl_wants_outer_parens(child)) {
+ return false;
+ }
+ return true;
+}
+
+
+static void sddl_tree_resolve_parens(struct sddl_node *node)
+{
+ if (sddl_wants_outer_parens(node)) {
+ node->wants_parens = true;
+ }
+ if (node->lhs != NULL) {
+ bool p = sddl_wants_inner_parens(node, node->lhs);
+ node->lhs->wants_parens = p;
+ sddl_tree_resolve_parens(node->lhs);
+ }
+ if (node->rhs != NULL) {
+ bool p = sddl_wants_inner_parens(node, node->rhs);
+ node->rhs->wants_parens = p;
+ sddl_tree_resolve_parens(node->rhs);
+ }
+}
+
+static bool sddl_tree_to_sddl(struct sddl_write_context *ctx,
+ struct sddl_node *node)
+{
+ bool ok;
+ if (node->wants_parens) {
+ ok = sddl_write(ctx, "(");
+ if (! ok) {
+ return false;
+ }
+ }
+
+ if (node->lhs != NULL) {
+ ok = sddl_tree_to_sddl(ctx, node->lhs);
+ if (! ok) {
+ return false;
+ }
+ ok = sddl_write(ctx, " ");
+ if (!ok) {
+ return false;
+ }
+ }
+
+ ok = sddl_write_node(ctx, node);
+ if (!ok) {
+ return false;
+ }
+ if (node->rhs != NULL) {
+ /* NOT is a special case: "!(x)", not "! (x)" */
+ if (node->tok->type != CONDITIONAL_ACE_TOKEN_NOT) {
+ ok = sddl_write(ctx, " ");
+ if (!ok) {
+ return false;
+ }
+ }
+
+ ok = sddl_tree_to_sddl(ctx, node->rhs);
+ if (! ok) {
+ return false;
+ }
+ }
+ if (node->wants_parens) {
+ ok = sddl_write(ctx, ")");
+ if (!ok) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
+ * Convert conditional ACE conditions into SDDL conditions.
+ *
+ * @param mem_ctx
+ * @param program
+ * @return a string or NULL on error.
+ */
+char *sddl_from_conditional_ace(TALLOC_CTX *mem_ctx,
+ struct ace_condition_script *program)
+{
+ size_t i;
+ char *sddl = NULL;
+ struct sddl_node *nodes = NULL;
+ struct sddl_node **trees = NULL;
+ size_t n_trees = 0;
+ struct ace_condition_token *tok = NULL;
+ struct sddl_data s;
+ bool ok;
+ struct sddl_write_context ctx = {
+ .mem_ctx = mem_ctx
+ };
+
+ if (program->length == 0) {
+ /*
+ * The empty program is a special case.
+ */
+ return talloc_strdup(mem_ctx, "()");
+ }
+ nodes = talloc_zero_array(mem_ctx,
+ struct sddl_node,
+ program->length);
+ if (nodes == NULL) {
+ talloc_free(sddl);
+ return NULL;
+ }
+ trees = talloc_array(mem_ctx,
+ struct sddl_node*,
+ program->length);
+ if (trees == NULL) {
+ talloc_free(sddl);
+ talloc_free(nodes);
+ return NULL;
+ }
+
+ /*
+ * This loop constructs a tree, which we then traverse to get the
+ * SDDL. Consider this transformation:
+ *
+ * {A, B, ==, C, D, ==, &&} => "((A == B) && (C == D))"
+ *
+ * We keep an array of sub-trees, and add to it in sequence. When the
+ * thing we're adding takes arguments, we pop those off the tree list.
+ * So it would go through this sequence:
+ *
+ * len items
+ * 1: A
+ * 2: A, B
+ * 1: ==(A, B)
+ * 2: ==(A, B), C
+ * 3: ==(A, B), C, D
+ * 2: ==(A, B), ==(C, D)
+ * 1 &&(==(A, B), ==(C, D))
+ *
+ * Without building a tree it would be difficult to know how many
+ * parentheses to put before A.
+ *
+ * (A == B == C) should become
+ * {A B == C ==} which should be the same as
+ * ((A == B) == C)
+ */
+
+ for (i = 0; i < program->length; i++) {
+ tok = &program->tokens[i];
+ s = sddl_strings[tok->type];
+ nodes[i].tok = tok;
+ if (s.nargs > n_trees) {
+ goto error;
+ }
+ if (s.nargs >= 1) {
+ /*
+ * Read this note if you're trying to follow
+ * [MS-DTYP]. MS-DTYP uses 'LHS' to describe the
+ * operand of unary operators even though they are
+ * always displayed on the right of the operator. It
+ * makes everything much simpler to use rhs
+ * instead.
+ */
+ n_trees--;
+ nodes[i].rhs = trees[n_trees];
+
+ if (s.nargs == 2) {
+ n_trees--;
+ nodes[i].lhs = trees[n_trees];
+ }
+ }
+ trees[n_trees] = &nodes[i];
+ n_trees++;
+ }
+
+ if (n_trees != 1) {
+ goto error;
+ }
+
+ /*
+ * First we walk the tree to work out where to put parentheses (to
+ * match the canonical Windows representation).
+ *
+ * Doing it in the same traverse as the writing would be possible but
+ * trickier to get right.
+ */
+ sddl_tree_resolve_parens(trees[0]);
+ trees[0]->wants_parens = true;
+
+ /*
+ * Clamber over the tree, writing the string.
+ */
+ ok = sddl_tree_to_sddl(&ctx, trees[0]);
+
+ if (! ok) {
+ goto error;
+ }
+
+ talloc_free(trees);
+ talloc_free(nodes);
+ return ctx.sddl;
+
+ error:
+ talloc_free(sddl);
+ talloc_free(trees);
+ talloc_free(nodes);
+ return NULL;
+}
+
+
+
+static void comp_error(struct ace_condition_sddl_compiler_context *comp,
+ const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+
+static void comp_error(struct ace_condition_sddl_compiler_context *comp,
+ const char *fmt, ...)
+{
+ char *msg = NULL;
+ va_list ap;
+ va_start(ap, fmt);
+ msg = talloc_vasprintf(comp->mem_ctx, fmt, ap);
+ va_end(ap);
+ if (msg == NULL) {
+ goto fail;
+ }
+
+ if (comp->message == NULL) {
+ /*
+ * Previously unset message; prepend the position.
+ *
+ * This is the common case.
+ */
+ comp->message_offset = comp->offset;
+ comp->message = msg;
+ return;
+ }
+ /*
+ * There's a message already so we'll try to append.
+ * This is unlikely to happen.
+ */
+ comp->message = talloc_asprintf(comp->mem_ctx,
+ "%s AND THEN %s",
+ comp->message,
+ msg);
+ TALLOC_FREE(msg);
+ if (comp->message == NULL) {
+ goto fail;
+ }
+ DBG_NOTICE("%s\n", comp->message);
+ return;
+fail:
+ comp->message = talloc_strdup(comp->mem_ctx,
+ "failed to set error message");
+ DBG_WARNING("%s\n", comp->message);
+}
+
+
+
+
+/*
+conditional-ace = "(" conditional-ace-type ";" [ace-flag-string] ";" ace-rights
+";" [object- guid] ";" [inherit-object-guid] ";" sid-string ";" "(" cond-expr
+")" ")"
+
+wspace = 1*(%x09-0D / %x20)
+
+literal-SID = "SID(" sid-string ")"
+
+term = [wspace] (memberof-op / exists-op / rel-op / contains-op / anyof-op /
+attr-name / rel- op2) [wspace]
+
+cond-expr = term / term [wspace] ("||" / "&&" ) [wspace] cond-expr / (["!"]
+[wspace] "(" cond-expr ")")
+
+memberof-op = ( "Member_of" / "Not_Member_of" / "Member_of_Any" /
+"Not_Member_of_Any" / "Device_Member_of" / "Device_Member_of_Any" /
+"Not_Device_Member_of" / "Not_Device_Member_of_Any" ) wspace sid-array
+
+exists-op = ( "Exists" / "Not_Exists") wspace attr-name
+
+rel-op = attr-name [wspace] ("<" / "<=" / ">" / ">=") [wspace] (attr-name2 /
+value) ; only scalars
+
+rel-op2 = attr-name [wspace] ("==" / "!=") [wspace] ( attr-name2 / value-array )
+; scalar or list
+
+contains-op = attr-name wspace ("Contains" / "Not_Contains") wspace (attr-name2
+/ value- array)
+
+anyof-op = attr-name wspace ("Any_of" / "Not_Any_of") wspace (attr-name2 /
+value-array)
+
+
+attr-name1 = attr-char1 *(attr-char1 / "@")
+
+attr-char1 = 1*(ALPHA / DIGIT / ":" / "." / "/" / "_")
+
+
+
+attr-name2 = ("@user." / "@device." / "@resource.") 1*attr-char2
+; new prefixed name form
+attr-char2 = attr-char1 / lit-char
+attr-name = attr-name1 / attr-name2
+ */
+
+
+
+static inline bool is_wspace(uint8_t c)
+{
+ /* wspace := %x09-0D | %x20 */
+ return (c == ' ' || c == '\x09' || c == '\x0A' ||
+ c == '\x0B' || c == '\x0C' || c == '\x0D');
+}
+
+static inline bool is_attr_char1(uint8_t c)
+{
+ /*
+ * attr-char1 = 1*(ALPHA / DIGIT / ":" / "." / "/" / "_")
+ * (ALPHA and DIGIT being ASCII only).
+ *
+ * These are used for local attributes, which we don't really
+ * expect to see in Samba AD.
+ *
+ * One example is "WIN://SYSAPPID", which is used in conditional ACEs
+ * that seem to relate to software installers; another is
+ * "APPID://PATH", used by Windows Applocker.
+ */
+ return (((c >= 'a') && (c <= 'z')) ||
+ ((c >= 'A') && (c <= 'Z')) ||
+ ((c >= '0') && (c <= '9')) ||
+ c == ':' || c == '.' || c == '/' || c == '_');
+}
+
+
+static ssize_t read_attr2_string(
+ struct ace_condition_sddl_compiler_context *comp,
+ struct ace_condition_unicode *dest)
+{
+ /*
+ * our SDDL is utf-8, but we need to convert to utf-16 and
+ * parse the escapes, then back to utf-8, because that's how
+ * the claims will appear.
+ *
+ * attr_char2 is used for attribute names that follow "@Class."
+ * specifiers. They can consume 5 characters to specify a single code
+ * unit, using "%1234" style escapes. Certain characters must be
+ * encoded this way, while others must be literal values. Because the
+ * %1234 refers to a utf-16 code unit, we really need to do the work
+ * in that codespace.
+ */
+ bool ok;
+ uint16_t *utf16 = NULL;
+ size_t utf16_byte_len;
+ size_t utf16_chars;
+ size_t utf8_len;
+ size_t src_len;
+ ssize_t i, j;
+ ssize_t max_len = comp->length - comp->offset;
+ const uint8_t *src = comp->sddl + comp->offset;
+
+ for (i = 0; i < max_len; i++) {
+ uint8_t c = src[i];
+ /*
+ * A double‐byte that must be escaped but isn't tells us that
+ * the attribute name has ended.
+ *
+ * The exception is '%', which must also be escaped
+ * (as "%0025"), but is obviously still expected in
+ * the escaped string.
+ */
+ if (strchr("!&()><=| \"", c) != NULL || is_wspace(c)) {
+ break;
+ }
+ }
+ if (i == max_len) {
+ /* too long, because we need at least one ')' */
+ comp_error(comp, "interminable attribute name");
+ return -1;
+ }
+ if (i == 0) {
+ /* too short! like "User.>= 4" */
+ comp_error(comp, "empty attribute name");
+ return -1;
+ }
+
+ if (unlikely(i > CONDITIONAL_ACE_MAX_LENGTH)) {
+ /*
+ * This is imprecise; the limit for the whole ACL is 64k.
+ * However there could be many escapes in the SDDL name which
+ * would reduce down to single utf16 code units in the
+ * compiled string.
+ */
+ comp_error(comp, "attribute is way too long (%zu)", i);
+ return -1;
+ }
+
+ src_len = i;
+
+ ok = convert_string_talloc(comp->mem_ctx,
+ CH_UTF8, CH_UTF16LE,
+ src, src_len,
+ &utf16, &utf16_byte_len);
+ if (!ok) {
+ comp_error(comp, "could not convert to utf-16");
+ return -1;
+ }
+ /*
+ * utf16_byte_len is in bytes, we want to count uint16s.
+ */
+ utf16_chars = utf16_byte_len / 2;
+
+ /* now the escapes. */
+ for (i = 0, j = 0;
+ j < utf16_chars && i < utf16_chars;
+ j++) {
+ uint16_t c = utf16[i];
+ if (c == '%') {
+ uint16_t v = 0;
+ size_t end = i + 5;
+ /*
+ * we need to read 4 hex characters.
+ * hex_byte() won't help because that is 8-bit.
+ */
+ if (end > utf16_chars) {
+ comp_error(comp,
+ "insufficient room for %% escape");
+ talloc_free(utf16);
+ return -1;
+ }
+ for (i++; i < end; i++) {
+ v <<= 4;
+ c = utf16[i];
+ if (c >= '0' && c <= '9') {
+ v += c - '0';
+ } else if (c >= 'A' && c <= 'F') {
+ v += c - 'A' + 10;
+ } else if (c >= 'a' && c <= 'f') {
+ v += c - 'a' + 10;
+ } else {
+ comp_error(comp, "invalid %% escape");
+ talloc_free(utf16);
+ return -1;
+ }
+ }
+ /*
+ * from MS-DTYP 2.5.1.1 Syntax (text, not ABNF), some
+ * characters must be literals, not escaped.
+ */
+ if ((v >= '0' && v <= '9') ||
+ (v >= 'A' && v <= 'Z') ||
+ (v >= 'a' && v <= 'z') ||
+ (v < 127 &&
+ strchr("#$'*+-;?@[\\]^_`{}~:/.", v) != NULL)) {
+ comp_error(comp, "invalid %% escape: "
+ "'%%%04x' should be literal '%c'",
+ v, v);
+ talloc_free(utf16);
+ return -1;
+ }
+ utf16[j] = v;
+ continue;
+ }
+ /*
+ * Note the characters "!&()><=|% \"" must be escaped per
+ * [MS-DTYP], but as we found the bounds of this string using
+ * those in utf-8 at the top of this function, we are not
+ * going to find them in the utf-16 now.
+ *
+ * Also, per [MS-DTYP], un-escaped whitespace is allowed, but
+ * effectively disallowed by Samba.
+ */
+ utf16[j] = utf16[i];
+ i++;
+ }
+
+ ok = convert_string_talloc(comp->mem_ctx,
+ CH_UTF16LE, CH_UTF8,
+ utf16, j * 2,
+ &dest->value, &utf8_len);
+ TALLOC_FREE(utf16);
+ if (!ok) {
+ comp_error(comp, "could not convert to utf-16");
+ return -1;
+ }
+
+ /* returning bytes consumed, not necessarily the length of token */
+ return src_len;
+}
+
+
+
+static bool eat_whitespace(struct ace_condition_sddl_compiler_context *comp,
+ bool trailing)
+{
+ /*
+ * Advance the offset to the first non-whitespace character.
+ *
+ * If trailing is false, there has to be something before the end of
+ * the string.
+ */
+ while (comp->offset < comp->length) {
+ if (! is_wspace(comp->sddl[comp->offset])) {
+ break;
+ }
+ comp->offset++;
+ }
+ if ((!trailing) && comp->offset == comp->length) {
+ comp_error(comp, "input ends unexpectedly");
+ return false;
+ }
+ return true;
+}
+
+static bool pop_sddl_token(struct ace_condition_sddl_compiler_context *comp,
+ struct ace_condition_token *token);
+
+static bool write_sddl_token(struct ace_condition_sddl_compiler_context *comp,
+ struct ace_condition_token token);
+
+static bool pop_write_sddl_token(
+ struct ace_condition_sddl_compiler_context *comp);
+
+
+static bool flush_stack_tokens(struct ace_condition_sddl_compiler_context *comp,
+ uint8_t type)
+{
+ bool ok;
+ uint8_t precedence = sddl_strings[type].op_precedence;
+ if (precedence == SDDL_PRECEDENCE_PAREN_START) {
+ /* paren has a special role */
+ return true;
+ }
+ /*
+ * Any operators on the top of the stack that have a "higher"
+ * precedence (tighter binding) to this one get popped off and written
+ * to the output. "higher" is in quotes because it means lower enum
+ * value.
+ *
+ * This works for binary operators, for example, with "(a == b == c)"
+ * (which is equivalent to "((a == b) == c)" via the left-to-right
+ * rule), we have:
+ * TOKEN dest PROGRAM STACK
+ * (
+ * a p
+ * == s a
+ * b p a ==
+ * == s a b ==
+ * flush stack
+ * s->p a b == ==
+ * c p a b ==
+ * ) a b == c ==
+ * flush stack
+ * a b == c ==
+ *
+ * but it is not right for unary operators, as in "(!(!(Exists
+ * a)))". As it turns out though, >= works for the unary
+ * operators and syntactic rules we have.
+ */
+ while (comp->stack_depth > 0) {
+ struct ace_condition_token *op =
+ &comp->stack[comp->stack_depth - 1];
+ if(sddl_strings[op->type].op_precedence > precedence) {
+ break;
+ }
+ if(sddl_strings[op->type].op_precedence == precedence &&
+ sddl_strings[op->type].flags & SDDL_FLAG_IS_UNARY_OP) {
+ break;
+ }
+
+ ok = pop_write_sddl_token(comp);
+ if (! ok) {
+ comp_error(comp,
+ "could not flush '%s' to program",
+ sddl_strings[op->type].name);
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool push_sddl_token(struct ace_condition_sddl_compiler_context *comp,
+ struct ace_condition_token token)
+{
+ if (comp->stack_depth >= CONDITIONAL_ACE_MAX_TOKENS - 1) {
+ comp_error(comp, "excessive recursion");
+ return false;
+ }
+ if (sddl_strings[token.type].op_precedence == SDDL_NOT_AN_OP) {
+ comp_error(comp,
+ "wrong kind of token for the SDDL stack: %s",
+ sddl_strings[token.type].name);
+ return false;
+ }
+ /*
+ * Any operators on the top of the stack that have a "greater" or
+ * equal precedence to this one get popped off and written to the
+ * output.
+ */
+ flush_stack_tokens(comp, token.type);
+
+ token.data.op.sddl_position = comp->offset;
+
+ comp->stack[comp->stack_depth] = token;
+ comp->stack_depth++;
+ if (token.type != CONDITIONAL_ACE_SAMBA_SDDL_PAREN) {
+ comp->last_token_type = token.type;
+ }
+ return true;
+}
+
+static bool pop_sddl_token(struct ace_condition_sddl_compiler_context *comp,
+ struct ace_condition_token *token)
+{
+ if (comp->stack_depth == 0) {
+ comp_error(comp, "misbalanced expression");
+ return false;
+ }
+ comp->stack_depth--;
+ *token = comp->stack[comp->stack_depth];
+ return true;
+}
+
+
+static bool write_sddl_token(struct ace_condition_sddl_compiler_context *comp,
+ struct ace_condition_token token)
+{
+ /*
+ * This is adding a token to the program. Normally it will be to the
+ * main program list, but if we are constructing a composite list, then
+ * will be redirected there (via comp->target).
+ *
+ * We also conservatively track the overall size, so we don't waste
+ * time compiling something that is way too big.
+ */
+ DBG_INFO("writing %"PRIu32" %x %s\n",
+ *comp->target_len,
+ token.type,
+ sddl_strings[token.type].name);
+ comp->approx_size++;
+ if (comp->approx_size > CONDITIONAL_ACE_MAX_TOKENS) {
+ comp_error(comp, "program is too long "
+ "(over %d tokens)",
+ CONDITIONAL_ACE_MAX_TOKENS);
+ return false;
+ }
+ if (token.type != CONDITIONAL_ACE_SAMBA_SDDL_PAREN) {
+ comp->last_token_type = token.type;
+ }
+ comp->target[*comp->target_len] = token;
+ (*comp->target_len)++;
+ return true;
+}
+
+static bool pop_write_sddl_token(
+ struct ace_condition_sddl_compiler_context *comp)
+{
+ bool ok;
+ struct ace_condition_token token = {};
+ ok = pop_sddl_token(comp, &token);
+ if (!ok) {
+ comp_error(comp, "could not pop from op stack");
+ return false;
+ }
+ if (comp->target != comp->program->tokens) {
+ comp_error(comp, "compiler is seriously confused");
+ return false;
+ }
+
+ ok = write_sddl_token(comp, token);
+ if (!ok) {
+ comp_error(comp,
+ "could not write '%s' to program",
+ sddl_strings[token.type].name);
+ return false;
+ }
+ DBG_INFO(" written '%s'\n", sddl_strings[token.type].name);
+ return true;
+}
+
+
+
+static bool parse_expression(struct ace_condition_sddl_compiler_context *comp);
+static bool parse_composite(struct ace_condition_sddl_compiler_context *comp);
+
+
+
+
+static bool parse_oppy_op(struct ace_condition_sddl_compiler_context *comp)
+{
+ /*
+ * These ones look like operators and are operators.
+ */
+ bool ok;
+ struct ace_condition_token token = {};
+ uint8_t c, d;
+ uint32_t flag = SDDL_FLAG_EXPECTING_BINARY_OP;
+
+ if (comp->offset + 1 >= comp->length) {
+ comp_error(comp, "syntax error");
+ return false;
+ }
+
+ token.data.sddl_op.start = comp->offset;
+
+ /*
+ * These are all one or two characters long, and we always have room
+ * to peek ahead.
+ */
+ c = comp->sddl[comp->offset];
+ d = comp->sddl[comp->offset + 1];
+
+ if (c == '!') {
+ if (d == '=') {
+ comp->offset++;
+ token.type = CONDITIONAL_ACE_TOKEN_NOT_EQUAL;
+
+ } else {
+ token.type = CONDITIONAL_ACE_TOKEN_NOT;
+ flag = SDDL_FLAG_EXPECTING_UNARY_OP;
+ }
+ } else if (c == '=' && d == '=') {
+ comp->offset++;
+ token.type = CONDITIONAL_ACE_TOKEN_EQUAL;
+ } else if (c == '>') {
+ if (d == '=') {
+ comp->offset++;
+ token.type = CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL;
+
+ } else {
+ token.type = CONDITIONAL_ACE_TOKEN_GREATER_THAN;
+ }
+ } else if (c == '<') {
+ if (d == '=') {
+ comp->offset++;
+ token.type = CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL;
+
+ } else {
+ token.type = CONDITIONAL_ACE_TOKEN_LESS_THAN;
+ }
+ } else if (c == '&' && d == '&') {
+ comp->offset++;
+ token.type = CONDITIONAL_ACE_TOKEN_AND;
+ flag = SDDL_FLAG_EXPECTING_BINARY_LOGIC_OP;
+ } else if (c == '|' && d == '|') {
+ comp->offset++;
+ token.type = CONDITIONAL_ACE_TOKEN_OR;
+ flag = SDDL_FLAG_EXPECTING_BINARY_LOGIC_OP;
+ } else {
+ comp_error(comp, "unknown operator");
+ return false;
+ }
+
+ if ((comp->state & flag) == 0) {
+ comp_error(comp, "unexpected operator");
+ return false;
+ }
+
+ comp->offset++;
+
+ ok = push_sddl_token(comp, token);
+ if (!ok) {
+ return false;
+ }
+
+ ok = eat_whitespace(comp, true);
+ return ok;
+}
+
+static bool parse_unicode(struct ace_condition_sddl_compiler_context *comp)
+{
+ /*
+ * This looks like "hello" (including the double quotes).
+ *
+ * Fortunately (for now), there is no mechanism for escaping
+ * double quotes in conditional ace strings, so we can simply
+ * look for the second quote without worrying about things
+ * like «\\\"».
+ */
+ struct ace_condition_token token = {};
+ char *s = NULL;
+ const uint8_t *src = NULL;
+ char *utf16 = NULL;
+ size_t len, max_len;
+ bool ok;
+ if (comp->sddl[comp->offset] != '"') {
+ comp_error(comp, "was expecting '\"' for Unicode string");
+ return false;
+ }
+ comp->offset++;
+ src = comp->sddl + comp->offset;
+ max_len = comp->length - comp->offset;
+ /* strnchr */
+ for (len = 0; len < max_len; len++) {
+ if (src[len] == '"') {
+ break;
+ }
+ }
+ if (len == max_len) {
+ comp_error(comp, "unterminated unicode string");
+ return false;
+ }
+
+ /*
+ * Look, this is wasteful, but it probably doesn't matter. We want to
+ * check that the string we're putting into the descriptor is valid,
+ * or we'll see errors down the track.
+ */
+ ok = convert_string_talloc(comp->mem_ctx,
+ CH_UTF8, CH_UTF16LE,
+ src, len,
+ &utf16, NULL);
+ if (!ok) {
+ comp_error(comp, "not valid unicode");
+ return false;
+ }
+ TALLOC_FREE(utf16);
+
+ s = talloc_array_size(comp->mem_ctx, 1, len + 1);
+ if (s == NULL) {
+ comp_error(comp, "allocation error");
+ return false;
+ }
+ memcpy(s, src, len);
+ s[len] = 0;
+ comp->offset += len + 1; /* +1 for the final quote */
+ token.type = CONDITIONAL_ACE_TOKEN_UNICODE;
+ token.data.unicode.value = s;
+
+ return write_sddl_token(comp, token);
+}
+
+
+static bool parse_octet_string(struct ace_condition_sddl_compiler_context *comp)
+{
+ /*
+ * This looks like '#hhhh...', where each 'hh' is hex for a byte, with
+ * the weird and annoying complication that '#' can be used to mean
+ * '0'.
+ */
+ struct ace_condition_token token = {};
+ size_t length, i;
+
+ if (comp->sddl[comp->offset] != '#') {
+ comp_error(comp, "was expecting '#' for octet string");
+ return false;
+ }
+ comp->offset++;
+ length = strspn((const char*)(comp->sddl + comp->offset),
+ "#0123456789abcdefABCDEF");
+
+ if (length & 1) {
+ comp_error(comp, "octet string has odd number of hex digits");
+ return false;
+ }
+
+ length /= 2;
+
+ token.data.bytes = data_blob_talloc_zero(comp->mem_ctx, length);
+ token.type = CONDITIONAL_ACE_TOKEN_OCTET_STRING;
+
+ for (i = 0; i < length; i++) {
+ /*
+ * Why not just strhex_to_str()?
+ *
+ * Because we need to treat '#' as '0' in octet string values,
+ * so all of the following are the same
+ * (equaling {0x10, 0x20, 0x30, 0x0}).
+ *
+ * #10203000
+ * #10203###
+ * #1#2#3###
+ * #10203#00
+ */
+ bool ok;
+ char pair[2];
+ size_t j = comp->offset + i * 2;
+ pair[0] = (comp->sddl[j] == '#') ? '0' : comp->sddl[j];
+ pair[1] = (comp->sddl[j + 1] == '#') ? '0' : comp->sddl[j + 1];
+
+ ok = hex_byte(pair, &token.data.bytes.data[i]);
+ if (!ok) {
+ talloc_free(token.data.bytes.data);
+ comp_error(comp, "inexplicable error in octet string");
+ return false;
+ }
+ }
+ comp->offset += length * 2;
+ return write_sddl_token(comp, token);
+}
+
+
+static bool parse_ra_octet_string(struct ace_condition_sddl_compiler_context *comp)
+{
+ /*
+ * Resource attribute octet strings resemble conditional ace octet
+ * strings, but have some important differences:
+ *
+ * 1. The '#' at the start is optional, and if present is
+ * counted as a zero.
+ *
+ * 2. An odd number of characters is implicitly left-padded with a zero.
+ *
+ * That is, "abc" means "0abc", "#12" means "0012", "f##"
+ * means "0f00", and "##" means 00.
+ */
+ struct ace_condition_token token = {};
+ size_t string_length, bytes_length, i, j;
+ bool ok;
+ char pair[2];
+
+ string_length = strspn((const char*)(comp->sddl + comp->offset),
+ "#0123456789abcdefABCDEF");
+
+ bytes_length = (string_length + 1) / 2;
+
+ if (bytes_length == 0) {
+ comp_error(comp, "zero length octet bytes");
+ return false;
+ }
+
+ token.data.bytes = data_blob_talloc_zero(comp->mem_ctx, bytes_length);
+ if (token.data.bytes.data == NULL) {
+ return false;
+ }
+ token.type = CONDITIONAL_ACE_TOKEN_OCTET_STRING;
+
+ j = comp->offset;
+ i = 0;
+ if (string_length & 1) {
+ /*
+ * An odd number of characters means the first
+ * character gains an implicit 0 for the high nybble.
+ */
+ pair[0] = 0;
+ pair[1] = (comp->sddl[0] == '#') ? '0' : comp->sddl[0];
+
+ ok = hex_byte(pair, &token.data.bytes.data[i]);
+ if (!ok) {
+ goto fail;
+ }
+ j++;
+ i++;
+ }
+
+ for (; i < bytes_length; i++) {
+ /*
+ * Why not just strhex_to_str() ?
+ *
+ * Because we need to treat '#' as '0' in octet string values.
+ */
+ if (comp->length - j < 2) {
+ goto fail;
+ }
+
+ pair[0] = (comp->sddl[j] == '#') ? '0' : comp->sddl[j];
+ pair[1] = (comp->sddl[j + 1] == '#') ? '0' : comp->sddl[j + 1];
+
+ ok = hex_byte(pair, &token.data.bytes.data[i]);
+ if (!ok) {
+ goto fail;
+ }
+ j += 2;
+ }
+ comp->offset = j;
+ return write_sddl_token(comp, token);
+
+fail:
+ comp_error(comp, "inexplicable error in octet string");
+ talloc_free(token.data.bytes.data);
+ return false;
+}
+
+
+static bool parse_sid(struct ace_condition_sddl_compiler_context *comp)
+{
+ struct dom_sid *sid = NULL;
+ const uint8_t *sidstr = NULL;
+ struct ace_condition_token token = {};
+ size_t end;
+ if (comp->length - comp->offset < 7) {
+ /* minimum: "SID(AA)" */
+ comp_error(comp, "no room for a complete SID");
+ return false;
+ }
+ /* conditional ACE SID string */
+ if (comp->sddl[comp->offset ] != 'S' ||
+ comp->sddl[comp->offset + 1] != 'I' ||
+ comp->sddl[comp->offset + 2] != 'D' ||
+ comp->sddl[comp->offset + 3] != '(') {
+ comp_error(comp, "malformed SID() constructor");
+ return false;
+ } else {
+ comp->offset += 4;
+ }
+
+ sidstr = comp->sddl + comp->offset;
+
+ sid = sddl_decode_sid(comp->mem_ctx,
+ (const char **)&sidstr,
+ comp->domain_sid);
+
+ if (sid == NULL) {
+ comp_error(comp, "could not parse SID");
+ return false;
+ }
+ end = sidstr - comp->sddl;
+ if (end >= comp->length || end < comp->offset) {
+ comp_error(comp, "apparent overflow in SID parsing");
+ return false;
+ }
+ comp->offset = end;
+ /*
+ * offset is now at the end of the SID, but we need to account
+ * for the ')'.
+ */
+ if (comp->sddl[comp->offset] != ')') {
+ comp_error(comp, "expected ')' to follow SID");
+ return false;
+ }
+ comp->offset++;
+
+ token.type = CONDITIONAL_ACE_TOKEN_SID;
+ token.data.sid.sid = *sid;
+ return write_sddl_token(comp, token);
+}
+
+
+
+static bool parse_ra_sid(struct ace_condition_sddl_compiler_context *comp)
+{
+ struct dom_sid *sid = NULL;
+ const uint8_t *sidstr = NULL;
+ struct ace_condition_token token = {};
+ size_t end;
+
+ if ((comp->state & SDDL_FLAG_EXPECTING_LITERAL) == 0) {
+ comp_error(comp, "did not expect a SID here");
+ return false;
+ }
+ /*
+ * Here we are parsing a resource attribute ACE which doesn't
+ * have the SID() wrapper around the SID string (unlike a
+ * conditional ACE).
+ *
+ * The resource ACE doesn't need this because there is no
+ * ambiguity with local attribute names, besides which the
+ * type has already been specified earlier in the ACE.
+ */
+ if (comp->length - comp->offset < 2){
+ comp_error(comp, "no room for a complete SID");
+ return false;
+ }
+
+ sidstr = comp->sddl + comp->offset;
+
+ sid = sddl_decode_sid(comp->mem_ctx,
+ (const char **)&sidstr,
+ comp->domain_sid);
+
+ if (sid == NULL) {
+ comp_error(comp, "could not parse SID");
+ return false;
+ }
+ end = sidstr - comp->sddl;
+ if (end >= comp->length || end < comp->offset) {
+ comp_error(comp, "apparent overflow in SID parsing");
+ return false;
+ }
+ comp->offset = end;
+ token.type = CONDITIONAL_ACE_TOKEN_SID;
+ token.data.sid.sid = *sid;
+ return write_sddl_token(comp, token);
+}
+
+
+static bool parse_int(struct ace_condition_sddl_compiler_context *comp)
+{
+ /*
+ * This one is relatively simple. strtoll() does the work.
+ */
+ long long v;
+ struct ace_condition_token token = {};
+ const char *start = (const char *)comp->sddl + comp->offset;
+ char *end = NULL;
+ const char *first_digit = start;
+ size_t len;
+ errno = 0;
+ v = strtoll(start, &end, 0);
+ if (errno != 0) {
+ comp_error(comp, "bad integer: %s", strerror(errno));
+ return false;
+ }
+ len = end - start;
+
+ if (len == 0) {
+ comp_error(comp, "unexpected non-integer");
+ return false;
+ }
+ if (comp->offset + len > comp->length) {
+ comp_error(comp, "impossible integer length: %zu!", len);
+ return false;
+ }
+
+ comp->offset += len;
+
+ /*
+ * Record the base and sign, which are used for recreating the SDDL.
+ *
+ * 'Sign' indicates whether there is a '+' or '-' sign. Base indicates
+ * whether the number was in hex, octal, or decimal. These make no
+ * difference to the evaluation of the ACE, just the display.
+ *
+ * This would not work reliably if eat_whitespace() is not called
+ * before parse_int(), but a) we know it is, and b) we don't *really*
+ * care if we lose these display hints.
+ */
+ if (*start == '-') {
+ token.data.int64.sign = CONDITIONAL_ACE_INT_SIGN_NEGATIVE;
+ first_digit++;
+ } else if (*start == '+') {
+ token.data.int64.sign = CONDITIONAL_ACE_INT_SIGN_POSITIVE;
+ first_digit++;
+ } else {
+ token.data.int64.sign = CONDITIONAL_ACE_INT_SIGN_NONE;
+ }
+ if (*first_digit == '0' && (end - first_digit) > 1) {
+ if ((end - first_digit > 2) &&
+ (first_digit[1] == 'x' ||
+ first_digit[1] == 'X')) {
+ token.data.int64.base = CONDITIONAL_ACE_INT_BASE_16;
+ } else {
+ token.data.int64.base = CONDITIONAL_ACE_INT_BASE_8;
+ }
+ } else {
+ token.data.int64.base = CONDITIONAL_ACE_INT_BASE_10;
+ }
+
+ token.data.int64.value = v;
+ token.type = CONDITIONAL_ACE_TOKEN_INT64;
+ return write_sddl_token(comp, token);
+}
+
+
+static bool parse_uint(struct ace_condition_sddl_compiler_context *comp)
+{
+ struct ace_condition_token *tok = NULL;
+ bool ok = parse_int(comp);
+ if (ok == false) {
+ return false;
+ }
+ /*
+ * check that the token's value is positive.
+ */
+ if (comp->target_len == 0) {
+ return false;
+ }
+ tok = &comp->target[*comp->target_len - 1];
+ if (tok->type != CONDITIONAL_ACE_TOKEN_INT64) {
+ return false;
+ }
+ if (tok->data.int64.value < 0) {
+ comp_error(comp, "invalid resource ACE value for unsigned TU claim");
+ return false;
+ }
+ return true;
+}
+
+
+static bool parse_bool(struct ace_condition_sddl_compiler_context *comp)
+{
+ struct ace_condition_token *tok = NULL;
+ bool ok = parse_int(comp);
+ if (ok == false || comp->target_len == 0) {
+ return false;
+ }
+ /*
+ * check that the token is 0 or 1.
+ */
+ tok = &comp->target[*comp->target_len - 1];
+ if (tok->type != CONDITIONAL_ACE_TOKEN_INT64) {
+ return false;
+ }
+ if (tok->data.int64.value != 0 && tok->data.int64.value != 1) {
+ comp_error(comp, "invalid resource ACE Boolean value");
+ return false;
+ }
+ return true;
+}
+
+
+static bool could_be_an_int(struct ace_condition_sddl_compiler_context *comp)
+{
+ const char *start = (const char*)(comp->sddl + comp->offset);
+ char* end = NULL;
+
+ if ((comp->state & SDDL_FLAG_EXPECTING_LITERAL) == 0) {
+ return false;
+ }
+
+ errno = 0;
+ /*
+ * See, we don't care about the strtoll return value, only
+ * whether it succeeds or not and what it finds at the end. If
+ * it succeeds, parse_int() will do it again for the value.
+ *
+ * Note that an out of range int will raise ERANGE (probably
+ * 34), so it will be read as a local attribute.
+ */
+ strtoll(start, &end, 0);
+ if (errno != 0 ||
+ end == start ||
+ end >= (const char*)comp->sddl + comp->length) {
+ return false;
+ }
+ /*
+ * We know *some* characters form an int, but if we run right
+ * into other attr1 characters (basically, letters), we won't
+ * count it as an int.
+ *
+ * For example, the "17" in "17p" is not an int. The "17" in
+ * "17||" is.
+ */
+ if (is_attr_char1(*end)) {
+ return false;
+ }
+ return true;
+}
+
+
+static bool parse_word(struct ace_condition_sddl_compiler_context *comp)
+{
+ /*
+ * Sometimes a bare word must be a local attribute, while in other
+ * cases it could also be a member-of or exists operator. Sometimes it
+ * could actually be a SID, which we discover when we've read as far
+ * as "SID(". Sometimes it might be a literal integer (attribute
+ * names can also consist entirely of digits).
+ *
+ * When it is an operator name, we have the complication that a match
+ * does not necessarily end the token. Consider "Member_of_Any" which
+ * contains the operator "Member_of". According to [MS-DTYP], a space
+ * is not necessary between the operator and the next token, but it
+ * does seem to be required for Windows 2022.
+ *
+ * Also, "Member_of" et. al. *could* be valid local attributes, which
+ * would make "(Member_of == 123)" a valid expression that we will
+ * fail to parse. This is not much of an issue for Samba AD where
+ * local attributes are not used.
+ *
+ * Operators are matched case-insensitively.
+ *
+ * There's another kind of attribute that starts with a '@', which we
+ * deal with in parse_attr2(). Those ones have full unicode glory;
+ * these ones are ASCII only.
+ */
+ size_t i, j, k;
+ bool ok;
+ uint8_t candidates[8];
+ size_t n_candidates = 0;
+ struct ace_condition_token token = {};
+ bool expecting_unary = comp->state & SDDL_FLAG_EXPECTING_UNARY_OP;
+ bool expecting_binary = comp->state & SDDL_FLAG_EXPECTING_BINARY_OP;
+ bool expecting_attr = comp->state & SDDL_FLAG_EXPECTING_LOCAL_ATTR;
+ bool expecting_literal = comp->state & SDDL_FLAG_EXPECTING_LITERAL;
+ const uint8_t *start = comp->sddl + comp->offset;
+ uint8_t c = start[0];
+ char *s = NULL;
+ if (! is_attr_char1(*start)) {
+ /* we shouldn't get here, because we peeked first */
+ return false;
+ }
+
+ /*
+ * We'll look for a SID first, because it simplifies the rest.
+ */
+ if (expecting_literal &&
+ comp->offset + 4 < comp->length &&
+ start[0] == 'S' &&
+ start[1] == 'I' &&
+ start[2] == 'D' &&
+ start[3] == '(') {
+ /* actually, we are parsing a SID. */
+ return parse_sid(comp);
+ }
+
+ if (expecting_binary || expecting_unary) {
+ /*
+ * Collect up the operators that can possibly be used
+ * here, including only those that start with the
+ * current letter and have the right arity/syntax.
+ *
+ * We don't expect more than 5 (for 'N', beginning the
+ * "Not_..." unary ops), and we'll winnow them down as
+ * we progress through the word.
+ */
+ int uc = toupper(c);
+ for (i = 0; i < 256; i++) {
+ const struct sddl_data *d = &sddl_strings[i];
+ if (sddl_strings[i].op_precedence != SDDL_NOT_AN_OP &&
+ uc == toupper((unsigned char)d->name[0])) {
+ if (d->flags & SDDL_FLAG_IS_UNARY_OP) {
+ if (!expecting_unary) {
+ continue;
+ }
+ } else if (!expecting_binary) {
+ continue;
+ }
+ candidates[n_candidates] = i;
+ n_candidates++;
+ if (n_candidates == ARRAY_SIZE(candidates)) {
+ /* impossible, really. */
+ return false;
+ }
+ }
+ }
+ } else if (could_be_an_int(comp)) {
+ /*
+ * if looks like an integer, and we expect an integer, it is
+ * an integer. If we don't expect an integer, it is a local
+ * attribute with a STUPID NAME. Or an error.
+ */
+ return parse_int(comp);
+ } else if (! expecting_attr) {
+ comp_error(comp, "did not expect this word here");
+ return false;
+ }
+
+ i = 1;
+ while (comp->offset + i < comp->length) {
+ c = start[i];
+ if (! is_attr_char1(c)) {
+ break;
+ }
+ if (n_candidates != 0) {
+ /*
+ * Filter out candidate operators that no longer
+ * match.
+ */
+ int uc = toupper(c);
+ k = 0;
+ for (j = 0; j < n_candidates; j++) {
+ size_t o = candidates[j];
+ uint8_t c2 = sddl_strings[o].name[i];
+ if (uc == toupper(c2)) {
+ candidates[k] = candidates[j];
+ k++;
+ }
+ }
+ n_candidates = k;
+ }
+ i++;
+ }
+
+ /*
+ * We have finished and there is a complete word. If it could be an
+ * operator we'll assume it is one.
+ *
+ * A complication is we could have matched more than one operator, for
+ * example "Member_of" and "Member_of_Any", so we have to look through
+ * the list of candidates for the one that ends.
+ */
+ if (n_candidates != 0) {
+ for (j = 0; j < n_candidates; j++) {
+ size_t o = candidates[j];
+ if (sddl_strings[o].name[i] == '\0') {
+ /* it is this one */
+
+ if (!comp->allow_device &&
+ (sddl_strings[o].flags & SDDL_FLAG_DEVICE))
+ {
+ comp_error(
+ comp,
+ "a device‐relative expression "
+ "will never evaluate to true "
+ "in this context (did you "
+ "intend a user‐relative "
+ "expression?)");
+ return false;
+ }
+
+ token.type = o;
+ token.data.sddl_op.start = comp->offset;
+ comp->offset += i;
+ ok = push_sddl_token(comp, token);
+ return ok;
+ }
+ }
+ }
+ /*
+ * if looks like an integer, and we expect an integer, it is
+ * an integer. If we don't expect an integer, it is a local
+ * attribute with a STUPID NAME.
+ */
+ if (could_be_an_int(comp)) {
+ return parse_int(comp);
+ }
+
+ if (! expecting_attr) {
+ comp_error(comp, "word makes no sense here");
+ return false;
+ }
+ /* it's definitely an attribute name */
+ token.type = CONDITIONAL_ACE_LOCAL_ATTRIBUTE;
+ if (comp->offset + i >= comp->length) {
+ comp_error(comp, "missing trailing ')'?");
+ return false;
+ }
+
+ s = talloc_memdup(comp->mem_ctx, start, i + 1);
+ if (s == NULL) {
+ comp_error(comp, "allocation error");
+ return false;
+ }
+ s[i] = 0;
+ token.data.local_attr.value = s;
+ comp->offset += i;
+ return write_sddl_token(comp, token);
+}
+
+static bool parse_attr2(struct ace_condition_sddl_compiler_context *comp)
+{
+ /*
+ * Attributes in the form @class.attr
+ *
+ * class can be "User", "Device", or "Resource", case insensitive.
+ */
+ size_t i;
+ bool ok;
+ size_t len;
+ struct ace_condition_token token = {};
+
+ if ((comp->state & SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR) == 0) {
+ comp_error(comp, "did not expect @attr here");
+ return false;
+ }
+ if (comp->sddl[comp->offset] != '@') {
+ comp_error(comp, "Expected '@'");
+ return false;
+ }
+ comp->offset++;
+
+ for (i = 0; i < ARRAY_SIZE(sddl_attr_types); i++) {
+ int ret;
+ size_t attr_len = strlen(sddl_attr_types[i].name);
+ if (attr_len >= comp->length - comp->offset) {
+ continue;
+ }
+ ret = strncasecmp(sddl_attr_types[i].name,
+ (const char *) (comp->sddl + comp->offset),
+ attr_len);
+ if (ret == 0) {
+ const uint8_t code = sddl_attr_types[i].code;
+
+ if (!comp->allow_device &&
+ (sddl_strings[code].flags & SDDL_FLAG_DEVICE))
+ {
+ comp_error(comp,
+ "a device attribute is not "
+ "applicable in this context (did "
+ "you intend a user attribute?)");
+ return false;
+ }
+
+ token.type = code;
+ comp->offset += attr_len;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(sddl_attr_types)) {
+ comp_error(comp, "unknown attribute class");
+ return false;
+ }
+
+ /*
+ * Now we are past the class and the '.', and into the
+ * attribute name. The attribute name can be almost
+ * anything, but some characters need to be escaped.
+ */
+
+ len = read_attr2_string(comp, &token.data.unicode);
+ if (len == -1) {
+ /* read_attr2_string has set a message */
+ return false;
+ }
+ ok = write_sddl_token(comp, token);
+ if (! ok) {
+ return false;
+ }
+ comp->offset += len;
+ ok = eat_whitespace(comp, false);
+ return ok;
+}
+
+static bool parse_literal(struct ace_condition_sddl_compiler_context *comp,
+ bool in_composite)
+{
+ uint8_t c = comp->sddl[comp->offset];
+ if (!(comp->state & SDDL_FLAG_EXPECTING_LITERAL)) {
+ comp_error(comp, "did not expect to be parsing a literal now");
+ return false;
+ }
+ switch(c) {
+ case '#':
+ return parse_octet_string(comp);
+ case '"':
+ return parse_unicode(comp);
+ case 'S':
+ return parse_sid(comp);
+ case '{':
+ if (in_composite) {
+ /* nested composites are not supported */
+ return false;
+ } else {
+ return parse_composite(comp);
+ }
+ default:
+ if (strchr("1234567890-+", c) != NULL) {
+ return parse_int(comp);
+ }
+ }
+ if (c > 31 && c < 127) {
+ comp_error(comp,
+ "unexpected byte 0x%02x '%c' parsing literal", c, c);
+ } else {
+ comp_error(comp, "unexpected byte 0x%02x parsing literal", c);
+ }
+ return false;
+}
+
+
+static bool parse_composite(struct ace_condition_sddl_compiler_context *comp)
+{
+ /*
+ * This jumps into a different parser, expecting a comma separated
+ * list of literal values, which might include nested literal
+ * composites.
+ *
+ * To handle the nesting, we redirect the pointers that determine
+ * where write_sddl_token() writes.
+ */
+ bool ok;
+ bool first = true;
+ struct ace_condition_token token = {
+ .type = CONDITIONAL_ACE_TOKEN_COMPOSITE
+ };
+ uint32_t start = comp->offset;
+ size_t alloc_size;
+ struct ace_condition_token *old_target = comp->target;
+ uint32_t *old_target_len = comp->target_len;
+
+ if (comp->sddl[start] != '{') {
+ comp_error(comp, "expected '{' for composite list");
+ return false;
+ }
+ if (!(comp->state & SDDL_FLAG_EXPECTING_LITERAL)) {
+ comp_error(comp, "did not expect '{' for composite list");
+ return false;
+ }
+ comp->offset++; /* past '{' */
+
+ /*
+ * the worst case is one token for every two bytes: {1,1,1}, and we
+ * allocate for that (counting commas and finding '}' gets hard because
+ * string literals).
+ */
+ alloc_size = MIN((comp->length - start) / 2 + 1,
+ CONDITIONAL_ACE_MAX_LENGTH);
+
+ token.data.composite.tokens = talloc_array(
+ comp->mem_ctx,
+ struct ace_condition_token,
+ alloc_size);
+ if (token.data.composite.tokens == NULL) {
+ comp_error(comp, "allocation failure");
+ return false;
+ }
+
+ comp->target = token.data.composite.tokens;
+ comp->target_len = &token.data.composite.n_members;
+
+ /*
+ * in this loop we are looking for:
+ *
+ * a) possible whitespace.
+ * b) a comma (or terminating '}')
+ * c) more possible whitespace
+ * d) a literal
+ *
+ * Failures use a goto to reset comp->target, just in case we ever try
+ * continuing after error.
+ */
+ while (comp->offset < comp->length) {
+ uint8_t c;
+ ok = eat_whitespace(comp, false);
+ if (! ok) {
+ goto fail;
+ }
+ c = comp->sddl[comp->offset];
+ if (c == '}') {
+ comp->offset++;
+ break;
+ }
+ if (!first) {
+ if (c != ',') {
+ comp_error(comp,
+ "malformed composite (expected comma)");
+ goto fail;
+ }
+ comp->offset++;
+
+ ok = eat_whitespace(comp, false);
+ if (! ok) {
+ goto fail;
+ }
+ }
+ first = false;
+ if (*comp->target_len >= alloc_size) {
+ comp_error(comp,
+ "Too many tokens in composite "
+ "(>= %"PRIu32" tokens)",
+ *comp->target_len);
+ goto fail;
+ }
+ ok = parse_literal(comp, true);
+ if (!ok) {
+ goto fail;
+ }
+ }
+ comp->target = old_target;
+ comp->target_len = old_target_len;
+ write_sddl_token(comp, token);
+ return true;
+fail:
+ talloc_free(token.data.composite.tokens);
+ comp->target = old_target;
+ comp->target_len = old_target_len;
+ return false;
+}
+
+
+static bool parse_paren_literal(struct ace_condition_sddl_compiler_context *comp)
+{
+ bool ok;
+ if (comp->sddl[comp->offset] != '(') {
+ comp_error(comp, "expected '('");
+ return false;
+ }
+ comp->offset++;
+ ok = parse_literal(comp, false);
+ if (!ok) {
+ return false;
+ }
+ if (comp->sddl[comp->offset] != ')') {
+ comp_error(comp, "expected ')'");
+ return false;
+ }
+ comp->offset++;
+ return true;
+}
+
+static bool parse_expression(struct ace_condition_sddl_compiler_context *comp)
+{
+ /*
+ * This expects a parenthesised expression.
+ */
+ bool ok;
+ struct ace_condition_token token = {};
+ uint32_t start = comp->offset;
+
+ if (comp->state & SDDL_FLAG_EXPECTING_PAREN_LITERAL) {
+ /*
+ * Syntactically we allow parentheses to wrap a
+ * literal value after a Member_of or >= op, but we
+ * want to remember that it just wants a single
+ * literal, not a general expression.
+ */
+ return parse_paren_literal(comp);
+ }
+
+ if (comp->sddl[start] != '(') {
+ comp_error(comp, "expected '('");
+ return false;
+ }
+
+ if (!(comp->state & SDDL_FLAG_EXPECTING_PAREN)) {
+ comp_error(comp, "did not expect '('");
+ return false;
+ }
+
+ token.type = CONDITIONAL_ACE_SAMBA_SDDL_PAREN;
+ token.data.sddl_op.start = start;
+ ok = push_sddl_token(comp, token);
+ if (!ok) {
+ return false;
+ }
+ comp->offset++; /* over the '(' */
+ comp->state = SDDL_FLAGS_EXPR_START;
+ DBG_INFO("%3"PRIu32": (\n", comp->offset);
+
+ comp->state |= SDDL_FLAG_NOT_EXPECTING_END_PAREN;
+
+ while (comp->offset < comp->length) {
+ uint8_t c;
+ ok = eat_whitespace(comp, false);
+ if (! ok) {
+ return false;
+ }
+ c = comp->sddl[comp->offset];
+ if (c == '(') {
+ ok = parse_expression(comp);
+ } else if (c == ')') {
+ if (comp->state & (SDDL_FLAG_IS_BINARY_OP |
+ SDDL_FLAG_IS_UNARY_OP)) {
+ /*
+ * You can't have "(a ==)" or "(!)"
+ */
+ comp_error(comp,
+ "operator lacks right hand argument");
+ return false;
+ }
+ if (comp->state & SDDL_FLAG_NOT_EXPECTING_END_PAREN) {
+ /*
+ * You can't have "( )"
+ */
+ comp_error(comp, "empty expression");
+ return false;
+ }
+ break;
+ } else if (c == '@') {
+ ok = parse_attr2(comp);
+ } else if (strchr("!<>=&|", c)) {
+ ok = parse_oppy_op(comp);
+ } else if (is_attr_char1(c)) {
+ ok = parse_word(comp);
+ } else if (comp->state & SDDL_FLAG_EXPECTING_LITERAL) {
+ ok = parse_literal(comp, false);
+ } else {
+ if (c > 31 && c < 127) {
+ comp_error(comp,
+ "unexpected byte 0x%02x '%c'", c, c);
+ } else {
+ comp_error(comp, "unexpected byte 0x%02x", c);
+ }
+ ok = false;
+ }
+
+ if (! ok) {
+ return false;
+ }
+ /*
+ * what did we just find? Set what we expect accordingly.
+ */
+ comp->state = sddl_strings[comp->last_token_type].flags;
+ DBG_INFO("%3"PRIu32": %s\n",
+ comp->offset,
+ sddl_strings[comp->last_token_type].name);
+ }
+ ok = eat_whitespace(comp, false);
+ if (!ok) {
+ return false;
+ }
+
+ if (comp->sddl[comp->offset] != ')') {
+ comp_error(comp, "expected ')' to match '(' at %"PRIu32, start);
+ return false;
+ }
+ /*
+ * we won't comp->offset++ until after these other error checks, so
+ * that their messages have consistent locations.
+ */
+ ok = flush_stack_tokens(comp, CONDITIONAL_ACE_SAMBA_SDDL_PAREN_END);
+ if (!ok) {
+ return false;
+ }
+ if (comp->stack_depth == 0) {
+ comp_error(comp, "mysterious nesting error between %"
+ PRIu32" and here",
+ start);
+ return false;
+ }
+ token = comp->stack[comp->stack_depth - 1];
+ if (token.type != CONDITIONAL_ACE_SAMBA_SDDL_PAREN) {
+ comp_error(comp, "nesting error between %"PRIu32" and here",
+ start);
+ return false;
+ }
+ if (token.data.sddl_op.start != start) {
+ comp_error(comp, "')' should match '(' at %"PRIu32
+ ", not %"PRIu32,
+ token.data.sddl_op.start, start);
+ return false;
+ }
+ comp->stack_depth--;
+ DBG_INFO("%3"PRIu32": )\n", comp->offset);
+
+ comp->offset++; /* for the ')' */
+ comp->last_token_type = CONDITIONAL_ACE_SAMBA_SDDL_PAREN_END;
+ comp->state = sddl_strings[comp->last_token_type].flags;
+
+ ok = eat_whitespace(comp, true);
+ return ok;
+}
+
+
+
+static bool init_compiler_context(
+ TALLOC_CTX *mem_ctx,
+ struct ace_condition_sddl_compiler_context *comp,
+ const enum ace_condition_flags ace_condition_flags,
+ const char *sddl,
+ size_t max_length,
+ size_t max_stack)
+{
+ struct ace_condition_script *program = NULL;
+
+ comp->sddl = (const uint8_t*)sddl;
+ comp->mem_ctx = mem_ctx;
+
+ program = talloc_zero(mem_ctx, struct ace_condition_script);
+ if (program == NULL) {
+ return false;
+ }
+ /*
+ * For the moment, we allocate for the worst case up front.
+ */
+ program->tokens = talloc_array(program,
+ struct ace_condition_token,
+ max_length);
+ if (program->tokens == NULL) {
+ TALLOC_FREE(program);
+ return false;
+ }
+ program->stack = talloc_array(program,
+ struct ace_condition_token,
+ max_stack + 1);
+ if (program->stack == NULL) {
+ TALLOC_FREE(program);
+ return false;
+ }
+ comp->program = program;
+ /* we can borrow the program stack for the operator stack */
+ comp->stack = program->stack;
+ comp->target = program->tokens;
+ comp->target_len = &program->length;
+ comp->length = strlen(sddl);
+ comp->state = SDDL_FLAG_EXPECTING_PAREN;
+ comp->allow_device = ace_condition_flags & ACE_CONDITION_FLAG_ALLOW_DEVICE;
+ return true;
+}
+
+/*
+ * Compile SDDL conditional ACE conditions.
+ *
+ * @param mem_ctx
+ * @param sddl - the string to be parsed
+ * @param ace_condition_flags - flags controlling compiler behaviour
+ * @param message - on error, a pointer to a compiler message
+ * @param message_offset - where the error occurred
+ * @param consumed_length - how much of the SDDL was used
+ * @return a struct ace_condition_script (or NULL).
+ */
+struct ace_condition_script * ace_conditions_compile_sddl(
+ TALLOC_CTX *mem_ctx,
+ const enum ace_condition_flags ace_condition_flags,
+ const char *sddl,
+ const char **message,
+ size_t *message_offset,
+ size_t *consumed_length)
+{
+ bool ok;
+ struct ace_condition_sddl_compiler_context comp = {};
+
+ *message = NULL;
+ *message_offset = 0;
+
+ ok = init_compiler_context(mem_ctx,
+ &comp,
+ ace_condition_flags,
+ sddl,
+ CONDITIONAL_ACE_MAX_LENGTH,
+ CONDITIONAL_ACE_MAX_TOKENS);
+ if (!ok) {
+ return NULL;
+ }
+
+ ok = parse_expression(&comp);
+ if (!ok) {
+ goto error;
+ }
+ if (comp.stack_depth != 0) {
+ comp_error(&comp, "incomplete expression");
+ goto error;
+ }
+ if (consumed_length != NULL) {
+ *consumed_length = comp.offset;
+ }
+ *message = comp.message;
+ *message_offset = comp.message_offset;
+ return comp.program;
+ error:
+ *message = comp.message;
+ *message_offset = comp.message_offset;
+ TALLOC_FREE(comp.program);
+ return NULL;
+}
+
+
+
+static bool parse_resource_attr_list(
+ struct ace_condition_sddl_compiler_context *comp,
+ char attr_type_char)
+{
+ /*
+ * This is a bit like parse_composite() above, but with the following
+ * differences:
+ *
+ * - it doesn't want '{...}' around the list.
+ * - if there is just one value, it is not a composite
+ * - all the values must be the expected type.
+ * - there is no nesting.
+ * - SIDs are not written with SID(...) around them.
+ */
+ bool ok;
+ bool first = true;
+ struct ace_condition_token composite = {
+ .type = CONDITIONAL_ACE_TOKEN_COMPOSITE
+ };
+ uint32_t start = comp->offset;
+ size_t alloc_size;
+ struct ace_condition_token *old_target = comp->target;
+ uint32_t *old_target_len = comp->target_len;
+
+ comp->state = SDDL_FLAG_EXPECTING_LITERAL;
+
+ /*
+ * the worst case is one token for every two bytes: {1,1,1}, and we
+ * allocate for that (counting commas and finding '}' gets hard because
+ * string literals).
+ */
+ alloc_size = MIN((comp->length - start) / 2 + 1,
+ CONDITIONAL_ACE_MAX_LENGTH);
+
+ composite.data.composite.tokens = talloc_array(
+ comp->mem_ctx,
+ struct ace_condition_token,
+ alloc_size);
+ if (composite.data.composite.tokens == NULL) {
+ comp_error(comp, "allocation failure");
+ return false;
+ }
+
+ comp->target = composite.data.composite.tokens;
+ comp->target_len = &composite.data.composite.n_members;
+
+ /*
+ * in this loop we are looking for:
+ *
+ * a) possible whitespace.
+ * b) a comma (or terminating ')')
+ * c) more possible whitespace
+ * d) a literal, of the right type (checked after)
+ *
+ * Failures use a goto to reset comp->target, just in case we ever try
+ * continuing after error.
+ */
+ while (comp->offset < comp->length) {
+ uint8_t c;
+ ok = eat_whitespace(comp, false);
+ if (! ok) {
+ goto fail;
+ }
+ c = comp->sddl[comp->offset];
+ if (c == ')') {
+ break;
+ }
+ if (!first) {
+ if (c != ',') {
+ comp_error(comp,
+ "malformed resource attribute ACE "
+ "(expected comma)");
+ goto fail;
+ }
+ comp->offset++;
+
+ ok = eat_whitespace(comp, false);
+ if (! ok) {
+ goto fail;
+ }
+ }
+ first = false;
+ if (*comp->target_len >= alloc_size) {
+ comp_error(comp,
+ "Too many tokens in resource attribute ACE "
+ "(>= %"PRIu32" tokens)",
+ *comp->target_len);
+ goto fail;
+ }
+ switch(attr_type_char) {
+ case 'X':
+ ok = parse_ra_octet_string(comp);
+ break;
+ case 'S':
+ ok = parse_unicode(comp);
+ break;
+ case 'U':
+ ok = parse_uint(comp);
+ break;
+ case 'B':
+ ok = parse_bool(comp);
+ break;
+ case 'I':
+ ok = parse_int(comp);
+ break;
+ case 'D':
+ ok = parse_ra_sid(comp);
+ break;
+ default:
+ /* it's a mystery we got this far */
+ comp_error(comp,
+ "unknown attribute type T%c",
+ attr_type_char);
+ goto fail;
+ }
+ if (!ok) {
+ goto fail;
+ }
+
+ if (*comp->target_len == 0) {
+ goto fail;
+ }
+ }
+ comp->target = old_target;
+ comp->target_len = old_target_len;
+
+ /*
+ * If we only ended up collecting one token into the composite, we
+ * write that instead.
+ */
+ if (composite.data.composite.n_members == 1) {
+ ok = write_sddl_token(comp, composite.data.composite.tokens[0]);
+ talloc_free(composite.data.composite.tokens);
+ } else {
+ ok = write_sddl_token(comp, composite);
+ }
+ if (! ok) {
+ goto fail;
+ }
+
+ return true;
+fail:
+ comp->target = old_target;
+ comp->target_len = old_target_len;
+ TALLOC_FREE(composite.data.composite.tokens);
+ return false;
+}
+
+
+
+struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *sddl_decode_resource_attr (
+ TALLOC_CTX *mem_ctx,
+ const char *str,
+ size_t *length)
+{
+ /*
+ * Resource attribute ACEs define claims in object SACLs. They look like
+ *
+ * "(RA; «flags» ;;;;WD;( «attribute-data» ))"
+ *
+ * attribute-data = DQUOTE 1*attr-char2 DQUOTE "," \
+ * ( TI-attr / TU-attr / TS-attr / TD-attr / TX-attr / TB-attr )
+ * TI-attr = "TI" "," attr-flags *("," int-64)
+ * TU-attr = "TU" "," attr-flags *("," uint-64)
+ * TS-attr = "TS" "," attr-flags *("," char-string)
+ * TD-attr = "TD" "," attr-flags *("," sid-string)
+ * TX-attr = "TX" "," attr-flags *("," octet-string)
+ * TB-attr = "TB" "," attr-flags *("," ( "0" / "1" ) )
+ *
+ * and the data types are *mostly* parsed in the SDDL way,
+ * though there are significant differences for octet-strings.
+ *
+ * At this point we only have the "(«attribute-data»)".
+ *
+ * What we do is set up a conditional ACE compiler to be expecting a
+ * literal, and ask it to parse the strings between the commas. It's a
+ * hack.
+ */
+ bool ok;
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim = NULL;
+ struct ace_condition_sddl_compiler_context comp = {};
+ char attr_type;
+ struct ace_condition_token *tok;
+ uint32_t flags;
+ size_t len;
+ struct ace_condition_unicode attr_name = {};
+
+ ok = init_compiler_context(mem_ctx,
+ &comp,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ str,
+ 3,
+ 3);
+ if (!ok) {
+ return NULL;
+ }
+ if (comp.length < 6 || comp.length > CONDITIONAL_ACE_MAX_LENGTH) {
+ DBG_WARNING("invalid resource attribute: '%s'\n", str);
+ goto error;
+ }
+ /*
+ * Resource attribute ACEs list SIDs in a bare form "S-1-2-3", while
+ * conditional ACEs use a wrapper syntax "SID(S-1-2-3)". As almost
+ * everything is the same, we are reusing the conditional ACE parser,
+ * with a flag set to tell the SID parser which form to expect.
+ */
+
+ /* Most examples on the web have leading whitespace */
+ ok = eat_whitespace(&comp, false);
+ if (!ok) {
+ return NULL;
+ }
+ if (comp.sddl[comp.offset] != '(' ||
+ comp.sddl[comp.offset + 1] != '"') {
+ DBG_WARNING("invalid resource attribute -- expected '(\"'\n");
+ goto error;
+ }
+ comp.offset += 2;
+
+ /*
+ * Read the name. Here we are not reading a token into comp->program,
+ * just into a unicode blob.
+ */
+ len = read_attr2_string(&comp, &attr_name);
+
+ if (len == -1) {
+ DBG_WARNING("invalid resource attr name: %s\n", str);
+ goto error;
+ }
+ comp.offset += len;
+
+ ok = eat_whitespace(&comp, false);
+ if (comp.offset + 6 > comp.length) {
+ DBG_WARNING("invalid resource attribute (too short): '%s'\n",
+ str);
+ goto error;
+ }
+ /*
+ * now we have the name. Next comes '",«T[IUSDXB]»,' followed
+ * by the flags, which are a 32 bit number.
+ */
+ if (comp.sddl[comp.offset] != '"' ||
+ comp.sddl[comp.offset + 1] != ','||
+ comp.sddl[comp.offset + 2] != 'T') {
+ DBG_WARNING("expected '\",T[IUSDXB]' after attr name\n");
+ goto error;
+ }
+ attr_type = comp.sddl[comp.offset + 3];
+
+ if (comp.sddl[comp.offset + 4] != ',') {
+ DBG_WARNING("expected ',' after attr type\n");
+ goto error;
+ }
+ comp.offset += 5;
+ comp.state = SDDL_FLAG_EXPECTING_LITERAL;
+ ok = parse_literal(&comp, false);
+ if (!ok ||
+ comp.program->length != 1) {
+ DBG_WARNING("invalid attr flags: %s\n", str);
+ goto error;
+ }
+
+ tok = &comp.program->tokens[0];
+ if (tok->type != CONDITIONAL_ACE_TOKEN_INT64 ||
+ tok->data.int64.value < 0 ||
+ tok->data.int64.value > UINT32_MAX) {
+ DBG_WARNING("invalid attr flags (want 32 bit int): %s\n", str);
+ goto error;
+ }
+ flags = tok->data.int64.value;
+ if (flags & 0xff00) {
+ DBG_WARNING("invalid attr flags, "
+ "stepping on reserved 0xff00 range: %s\n",
+ str);
+ goto error;
+ }
+ if (comp.offset + 3 > comp.length) {
+ DBG_WARNING("invalid resource attribute (too short): '%s'\n",
+ str);
+ goto error;
+ }
+ if (comp.sddl[comp.offset] != ',') {
+ DBG_WARNING("invalid resource attribute ace\n");
+ goto error;
+ }
+ comp.offset++;
+
+ ok = parse_resource_attr_list(&comp, attr_type);
+ if (!ok || comp.program->length != 2) {
+ DBG_WARNING("invalid attribute type or value: T%c, %s\n",
+ attr_type, str);
+ goto error;
+ }
+ if (comp.sddl[comp.offset] != ')') {
+ DBG_WARNING("expected trailing ')'\n");
+ goto error;
+ }
+ comp.offset++;
+ *length = comp.offset;
+
+ ok = ace_token_to_claim_v1(mem_ctx,
+ attr_name.value,
+ &comp.program->tokens[1],
+ &claim,
+ flags);
+ if (!ok) {
+ goto error;
+ }
+ TALLOC_FREE(comp.program);
+ return claim;
+ error:
+ TALLOC_FREE(comp.program);
+ return NULL;
+}
+
+
+static bool write_resource_attr_from_token(struct sddl_write_context *ctx,
+ const struct ace_condition_token *tok)
+{
+ /*
+ * this is a helper for sddl_resource_attr_from_claim(),
+ * recursing into composites if necessary.
+ */
+ bool ok;
+ char *sid = NULL;
+ size_t i;
+ const struct ace_condition_composite *c = NULL;
+ switch (tok->type) {
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ /*
+ * Note that this includes uint and bool claim types,
+ * but we don't check the validity of the ranges (0|1
+ * and >=0, respectively), rather we trust the claim
+ * to be self-consistent in this regard. Going the
+ * other way, string-to-claim, we do check.
+ */
+ return sddl_write_int(ctx, tok);
+
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ return sddl_write_unicode(ctx, tok);
+
+ case CONDITIONAL_ACE_TOKEN_SID:
+ /* unlike conditional ACE, SID does not have a "SID()" wrapper. */
+ sid = sddl_encode_sid(ctx->mem_ctx, &tok->data.sid.sid, NULL);
+ if (sid == NULL) {
+ return false;
+ }
+ return sddl_write(ctx, sid);
+
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ return sddl_write_ra_octet_string(ctx, tok);
+
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ /*
+ * write each token, separated by commas. If there
+ * were nested composites, this would flatten them,
+ * but that isn't really possible because the token we
+ * are dealing with came from a claim, which has no
+ * facility for nesting.
+ */
+ c = &tok->data.composite;
+ for(i = 0; i < c->n_members; i++) {
+ ok = write_resource_attr_from_token(ctx, &c->tokens[i]);
+ if (!ok) {
+ return false;
+ }
+ if (i != c->n_members - 1) {
+ ok = sddl_write(ctx, ",");
+ if (!ok) {
+ return false;
+ }
+ }
+ }
+ return true;
+ default:
+ /* We really really don't expect to get here */
+ return false;
+ }
+}
+
+char *sddl_resource_attr_from_claim(
+ TALLOC_CTX *mem_ctx,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim)
+{
+ char *s = NULL;
+ char attr_type;
+ bool ok;
+ struct ace_condition_token tok = {};
+ struct sddl_write_context ctx = {};
+ TALLOC_CTX *tmp_ctx = NULL;
+ char *name = NULL;
+ size_t name_len;
+
+ switch(claim->value_type) {
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
+ attr_type = 'I';
+ break;
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
+ attr_type = 'U';
+ break;
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
+ attr_type = 'S';
+ break;
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_SID:
+ attr_type = 'D';
+ break;
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN:
+ attr_type = 'B';
+ break;
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:
+ attr_type = 'X';
+ break;
+ default:
+ return NULL;
+ }
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return NULL;
+ }
+ ctx.mem_ctx = tmp_ctx;
+
+ ok = claim_v1_to_ace_composite_unchecked(tmp_ctx, claim, &tok);
+ if (!ok) {
+ TALLOC_FREE(tmp_ctx);
+ return NULL;
+ }
+
+ /* this will construct the proper string in ctx.sddl */
+ ok = write_resource_attr_from_token(&ctx, &tok);
+ if (!ok) {
+ TALLOC_FREE(tmp_ctx);
+ return NULL;
+ }
+
+ /* escape the claim name */
+ ok = sddl_encode_attr_name(tmp_ctx,
+ claim->name,
+ &name, &name_len);
+
+ if (!ok) {
+ TALLOC_FREE(tmp_ctx);
+ return NULL;
+ }
+
+ s = talloc_asprintf(mem_ctx,
+ "(\"%s\",T%c,0x%x,%s)",
+ name,
+ attr_type,
+ claim->flags,
+ ctx.sddl);
+ TALLOC_FREE(tmp_ctx);
+ return s;
+}
+
+
+struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *parse_sddl_literal_as_claim(
+ TALLOC_CTX *mem_ctx,
+ const char *name,
+ const char *str)
+{
+ /*
+ * For testing purposes (and possibly for client tools), we
+ * want to be able to create claim literals, and we might as
+ * well use the SDDL syntax. So we pretend to be parsing SDDL
+ * for one literal.
+ */
+ bool ok;
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim = NULL;
+ struct ace_condition_sddl_compiler_context comp = {};
+
+ ok = init_compiler_context(mem_ctx,
+ &comp,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ str,
+ 2,
+ 2);
+ if (!ok) {
+ return NULL;
+ }
+
+ comp.state = SDDL_FLAG_EXPECTING_LITERAL;
+ ok = parse_literal(&comp, false);
+
+ if (!ok) {
+ goto error;
+ }
+ if (comp.program->length != 1) {
+ goto error;
+ }
+
+ ok = ace_token_to_claim_v1(mem_ctx,
+ name,
+ &comp.program->tokens[0],
+ &claim,
+ 0);
+ if (!ok) {
+ goto error;
+ }
+ TALLOC_FREE(comp.program);
+ return claim;
+ error:
+ TALLOC_FREE(comp.program);
+ return NULL;
+}
diff --git a/libcli/security/secace.c b/libcli/security/secace.c
new file mode 100644
index 0000000..22bf217
--- /dev/null
+++ b/libcli/security/secace.c
@@ -0,0 +1,204 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * struct security_ace handling functions
+ * Copyright (C) Andrew Tridgell 1992-1998,
+ * Copyright (C) Jeremy R. Allison 1995-2003.
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
+ * Copyright (C) Paul Ashton 1997-1998.
+ *
+ * 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 "replace.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/security.h"
+#include "lib/util/tsort.h"
+
+/**
+ * Check if ACE has OBJECT type.
+ */
+bool sec_ace_object(uint8_t type)
+{
+ if (type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ||
+ type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT ||
+ type == SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT ||
+ type == SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT ||
+ type == SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT ||
+ type == SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT ||
+ type == SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK_OBJECT) {
+ /*
+ * MS-DTYP has a reserved value for
+ * SEC_ACE_TYPE_SYSTEM_ALARM_CALLBACK_OBJECT, but we
+ * don't assume that it will be an object ACE just
+ * because it sounds like one.
+ */
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Check if ACE is a CALLBACK type, which means it will have a blob of data at
+ * the end.
+ */
+bool sec_ace_callback(uint8_t type)
+{
+ if (type == SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK ||
+ type == SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK ||
+ type == SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT ||
+ type == SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT ||
+ type == SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK ||
+ type == SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK_OBJECT) {
+ /*
+ * While SEC_ACE_TYPE_SYSTEM_ALARM_CALLBACK and
+ * SEC_ACE_TYPE_SYSTEM_ALARM_CALLBACK_OBJECT sound like
+ * callback types, they are reserved values in MS-DTYP,
+ * and their eventual use is not defined.
+ */
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Check if an ACE type is resource attribute, which means it will
+ * have a blob of data at the end defining an attribute on the object.
+ * Resource attribute ACEs should only occur in SACLs.
+ */
+bool sec_ace_resource(uint8_t type)
+{
+ return type == SEC_ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE;
+}
+
+bool sec_ace_has_extra_blob(uint8_t type)
+{
+ return sec_ace_callback(type) || sec_ace_resource(type);
+}
+
+
+/*******************************************************************
+ Sets up a struct security_ace structure.
+********************************************************************/
+
+void init_sec_ace(struct security_ace *t, const struct dom_sid *sid, enum security_ace_type type,
+ uint32_t mask, uint8_t flag)
+{
+ t->type = type;
+ t->flags = flag;
+ t->size = ndr_size_dom_sid(sid, 0) + 8;
+ t->access_mask = mask;
+
+ t->trustee = *sid;
+ t->coda.ignored.data = NULL;
+ t->coda.ignored.length = 0;
+}
+
+int nt_ace_inherit_comp(const struct security_ace *a1, const struct security_ace *a2)
+{
+ int a1_inh = a1->flags & SEC_ACE_FLAG_INHERITED_ACE;
+ int a2_inh = a2->flags & SEC_ACE_FLAG_INHERITED_ACE;
+
+ if (a1_inh == a2_inh)
+ return 0;
+
+ if (!a1_inh && a2_inh)
+ return -1;
+ return 1;
+}
+
+/*******************************************************************
+ Comparison function to apply the order explained below in a group.
+*******************************************************************/
+
+int nt_ace_canon_comp( const struct security_ace *a1, const struct security_ace *a2)
+{
+ if ((a1->type == SEC_ACE_TYPE_ACCESS_DENIED) &&
+ (a2->type != SEC_ACE_TYPE_ACCESS_DENIED))
+ return -1;
+
+ if ((a2->type == SEC_ACE_TYPE_ACCESS_DENIED) &&
+ (a1->type != SEC_ACE_TYPE_ACCESS_DENIED))
+ return 1;
+
+ /* Both access denied or access allowed. */
+
+ /* 1. ACEs that apply to the object itself */
+
+ if (!(a1->flags & SEC_ACE_FLAG_INHERIT_ONLY) &&
+ (a2->flags & SEC_ACE_FLAG_INHERIT_ONLY))
+ return -1;
+ else if (!(a2->flags & SEC_ACE_FLAG_INHERIT_ONLY) &&
+ (a1->flags & SEC_ACE_FLAG_INHERIT_ONLY))
+ return 1;
+
+ /* 2. ACEs that apply to a subobject of the object, such as
+ * a property set or property. */
+
+ if (a1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT) &&
+ !(a2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT)))
+ return -1;
+ else if (a2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT) &&
+ !(a1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT)))
+ return 1;
+
+ return 0;
+}
+
+/*******************************************************************
+ Functions to convert a SEC_DESC ACE DACL list into canonical order.
+ JRA.
+
+--- from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/security/order_of_aces_in_a_dacl.asp
+
+The following describes the preferred order:
+
+ To ensure that noninherited ACEs have precedence over inherited ACEs,
+ place all noninherited ACEs in a group before any inherited ACEs.
+ This ordering ensures, for example, that a noninherited access-denied ACE
+ is enforced regardless of any inherited ACE that allows access.
+
+ Within the groups of noninherited ACEs and inherited ACEs, order ACEs according to ACE type, as the following shows:
+ 1. Access-denied ACEs that apply to the object itself
+ 2. Access-denied ACEs that apply to a subobject of the object, such as a property set or property
+ 3. Access-allowed ACEs that apply to the object itself
+ 4. Access-allowed ACEs that apply to a subobject of the object"
+
+********************************************************************/
+
+void dacl_sort_into_canonical_order(struct security_ace *srclist, unsigned int num_aces)
+{
+ unsigned int i;
+
+ if (!srclist || num_aces == 0)
+ return;
+
+ /* Sort so that non-inherited ACE's come first. */
+ TYPESAFE_QSORT(srclist, num_aces, nt_ace_inherit_comp);
+
+ /* Find the boundary between non-inherited ACEs. */
+ for (i = 0; i < num_aces; i++ ) {
+ struct security_ace *curr_ace = &srclist[i];
+
+ if (curr_ace->flags & SEC_ACE_FLAG_INHERITED_ACE)
+ break;
+ }
+
+ /* i now points at entry number of the first inherited ACE. */
+
+ /* Sort the non-inherited ACEs. */
+ TYPESAFE_QSORT(srclist, i, nt_ace_canon_comp);
+
+ /* Now sort the inherited ACEs. */
+ TYPESAFE_QSORT(&srclist[i], num_aces - i, nt_ace_canon_comp);
+}
diff --git a/libcli/security/secace.h b/libcli/security/secace.h
new file mode 100644
index 0000000..879c711
--- /dev/null
+++ b/libcli/security/secace.h
@@ -0,0 +1,40 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Copyright (C) 2009 Jelmer Vernooij <jelmer@samba.org>
+
+ 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/>.
+*/
+
+#ifndef _ACE_H_
+#define _ACE_H_
+
+#include "librpc/gen_ndr/security.h"
+#include "librpc/ndr/libndr.h"
+
+bool sec_ace_object(uint8_t type);
+size_t ndr_subcontext_size_of_ace_coda(const struct security_ace *ace, size_t ace_size, libndr_flags flags);
+bool sec_ace_callback(uint8_t type);
+bool sec_ace_resource(uint8_t type);
+bool sec_ace_has_extra_blob(uint8_t type);
+
+void init_sec_ace(struct security_ace *t, const struct dom_sid *sid, enum security_ace_type type,
+ uint32_t mask, uint8_t flag);
+int nt_ace_inherit_comp( const struct security_ace *a1, const struct security_ace *a2);
+int nt_ace_canon_comp( const struct security_ace *a1, const struct security_ace *a2);
+void dacl_sort_into_canonical_order(struct security_ace *srclist, unsigned int num_aces);
+
+#endif /*_ACE_H_*/
+
diff --git a/libcli/security/secacl.c b/libcli/security/secacl.c
new file mode 100644
index 0000000..6c92a2e
--- /dev/null
+++ b/libcli/security/secacl.c
@@ -0,0 +1,75 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * SEC_ACL handling routines
+ * Copyright (C) Andrew Tridgell 1992-1998,
+ * Copyright (C) Jeremy R. Allison 1995-2003.
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
+ * Copyright (C) Paul Ashton 1997-1998.
+ *
+ * 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 "replace.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/secace.h"
+#include "libcli/security/secacl.h"
+
+#define SEC_ACL_HEADER_SIZE (2 * sizeof(uint16_t) + sizeof(uint32_t))
+
+/*******************************************************************
+ Create a SEC_ACL structure.
+********************************************************************/
+
+struct security_acl *make_sec_acl(
+ TALLOC_CTX *ctx,
+ enum security_acl_revision revision,
+ int num_aces,
+ const struct security_ace *ace_list)
+{
+ struct security_acl *dst;
+ int i;
+
+ dst = talloc(ctx, struct security_acl);
+ if (dst == NULL) {
+ return NULL;
+ }
+
+ dst->revision = revision;
+ dst->num_aces = num_aces;
+ dst->size = SEC_ACL_HEADER_SIZE;
+ dst->aces = NULL;
+
+ /* Now we need to return a non-NULL address for the ace list even
+ if the number of aces required is zero. This is because there
+ is a distinct difference between a NULL ace and an ace with zero
+ entries in it. This is achieved by checking that num_aces is a
+ positive number. */
+
+ if (num_aces == 0) {
+ return dst;
+ }
+
+ dst->aces = talloc_array(dst, struct security_ace, num_aces);
+ if (dst->aces == NULL) {
+ TALLOC_FREE(dst);
+ return NULL;
+ }
+
+ for (i = 0; i < num_aces; i++) {
+ dst->aces[i] = ace_list[i]; /* Structure copy. */
+ dst->size += ace_list[i].size;
+ }
+
+ return dst;
+}
diff --git a/libcli/security/secacl.h b/libcli/security/secacl.h
new file mode 100644
index 0000000..961e2b4
--- /dev/null
+++ b/libcli/security/secacl.h
@@ -0,0 +1,33 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Copyright (C) 2009 Jelmer Vernooij <jelmer@samba.org>
+
+ 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/>.
+*/
+
+#ifndef _SECACL_H_
+#define _SECACL_H_
+
+#include "librpc/gen_ndr/security.h"
+
+struct security_acl *make_sec_acl(
+ TALLOC_CTX *ctx,
+ enum security_acl_revision revision,
+ int num_aces,
+ const struct security_ace *ace_list);
+
+#endif /*_SECACL_H_*/
+
diff --git a/libcli/security/secdesc.c b/libcli/security/secdesc.c
new file mode 100644
index 0000000..cb8037c
--- /dev/null
+++ b/libcli/security/secdesc.c
@@ -0,0 +1,623 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * SEC_DESC handling functions
+ * Copyright (C) Andrew Tridgell 1992-1998,
+ * Copyright (C) Jeremy R. Allison 1995-2003.
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
+ * Copyright (C) Paul Ashton 1997-1998.
+ *
+ * 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 "replace.h"
+#include "lib/util/debug.h"
+#include "lib/util/fault.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/security.h"
+
+/* Map generic permissions to file object specific permissions */
+
+const struct generic_mapping file_generic_mapping = {
+ FILE_GENERIC_READ,
+ FILE_GENERIC_WRITE,
+ FILE_GENERIC_EXECUTE,
+ FILE_GENERIC_ALL
+};
+
+/*******************************************************************
+ Given a security_descriptor return the sec_info.
+********************************************************************/
+
+uint32_t get_sec_info(const struct security_descriptor *sd)
+{
+ uint32_t sec_info = 0;
+
+ SMB_ASSERT(sd);
+
+ if (sd->owner_sid != NULL) {
+ sec_info |= SECINFO_OWNER;
+ }
+ if (sd->group_sid != NULL) {
+ sec_info |= SECINFO_GROUP;
+ }
+ if (sd->sacl != NULL) {
+ sec_info |= SECINFO_SACL;
+ }
+ if (sd->dacl != NULL) {
+ sec_info |= SECINFO_DACL;
+ }
+
+ if (sd->type & SEC_DESC_SACL_PROTECTED) {
+ sec_info |= SECINFO_PROTECTED_SACL;
+ } else if (sd->type & SEC_DESC_SACL_AUTO_INHERITED) {
+ sec_info |= SECINFO_UNPROTECTED_SACL;
+ }
+ if (sd->type & SEC_DESC_DACL_PROTECTED) {
+ sec_info |= SECINFO_PROTECTED_DACL;
+ } else if (sd->type & SEC_DESC_DACL_AUTO_INHERITED) {
+ sec_info |= SECINFO_UNPROTECTED_DACL;
+ }
+
+ return sec_info;
+}
+
+
+/*******************************************************************
+ Merge part of security descriptor old_sec in to the empty sections of
+ security descriptor new_sec.
+********************************************************************/
+
+struct sec_desc_buf *sec_desc_merge_buf(TALLOC_CTX *ctx, struct sec_desc_buf *new_sdb, struct sec_desc_buf *old_sdb)
+{
+ struct dom_sid *owner_sid, *group_sid;
+ struct sec_desc_buf *return_sdb;
+ struct security_acl *dacl, *sacl;
+ struct security_descriptor *psd = NULL;
+ uint16_t secdesc_type;
+ size_t secdesc_size;
+
+ /* Copy over owner and group sids. There seems to be no flag for
+ this so just check the pointer values. */
+
+ owner_sid = new_sdb->sd->owner_sid ? new_sdb->sd->owner_sid :
+ old_sdb->sd->owner_sid;
+
+ group_sid = new_sdb->sd->group_sid ? new_sdb->sd->group_sid :
+ old_sdb->sd->group_sid;
+
+ secdesc_type = new_sdb->sd->type;
+
+ /* Ignore changes to the system ACL. This has the effect of making
+ changes through the security tab audit button not sticking.
+ Perhaps in future Samba could implement these settings somehow. */
+
+ sacl = NULL;
+ secdesc_type &= ~SEC_DESC_SACL_PRESENT;
+
+ /* Copy across discretionary ACL */
+
+ if (secdesc_type & SEC_DESC_DACL_PRESENT) {
+ dacl = new_sdb->sd->dacl;
+ } else {
+ dacl = old_sdb->sd->dacl;
+ }
+
+ /* Create new security descriptor from bits */
+
+ psd = make_sec_desc(ctx, new_sdb->sd->revision, secdesc_type,
+ owner_sid, group_sid, sacl, dacl, &secdesc_size);
+
+ return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
+
+ return(return_sdb);
+}
+
+struct security_descriptor *sec_desc_merge(TALLOC_CTX *ctx, struct security_descriptor *new_sdb, struct security_descriptor *old_sdb)
+{
+ struct dom_sid *owner_sid, *group_sid;
+ struct security_acl *dacl, *sacl;
+ struct security_descriptor *psd = NULL;
+ uint16_t secdesc_type;
+ size_t secdesc_size;
+
+ /* Copy over owner and group sids. There seems to be no flag for
+ this so just check the pointer values. */
+
+ owner_sid = new_sdb->owner_sid ? new_sdb->owner_sid :
+ old_sdb->owner_sid;
+
+ group_sid = new_sdb->group_sid ? new_sdb->group_sid :
+ old_sdb->group_sid;
+
+ secdesc_type = new_sdb->type;
+
+ /* Ignore changes to the system ACL. This has the effect of making
+ changes through the security tab audit button not sticking.
+ Perhaps in future Samba could implement these settings somehow. */
+
+ sacl = NULL;
+ secdesc_type &= ~SEC_DESC_SACL_PRESENT;
+
+ /* Copy across discretionary ACL */
+
+ if (secdesc_type & SEC_DESC_DACL_PRESENT) {
+ dacl = new_sdb->dacl;
+ } else {
+ dacl = old_sdb->dacl;
+ }
+
+ /* Create new security descriptor from bits */
+ psd = make_sec_desc(ctx, new_sdb->revision, secdesc_type,
+ owner_sid, group_sid, sacl, dacl, &secdesc_size);
+
+ return psd;
+}
+
+/*******************************************************************
+ Creates a struct security_descriptor structure
+********************************************************************/
+struct security_descriptor *make_sec_desc(TALLOC_CTX *ctx,
+ enum security_descriptor_revision revision,
+ uint16_t type,
+ const struct dom_sid *owner_sid, const struct dom_sid *grp_sid,
+ struct security_acl *sacl, struct security_acl *dacl, size_t *sd_size)
+{
+ struct security_descriptor *dst;
+
+ if (sd_size != NULL) {
+ *sd_size = 0;
+ }
+
+ dst = security_descriptor_initialise(ctx);
+ if (dst == NULL) {
+ return NULL;
+ }
+
+ dst->revision = revision;
+ dst->type = type;
+
+ if (sacl != NULL) {
+ dst->sacl = security_acl_dup(dst, sacl);
+ if (dst->sacl == NULL) {
+ goto err_sd_free;
+ }
+ dst->type |= SEC_DESC_SACL_PRESENT;
+ }
+
+ if (dacl != NULL) {
+ dst->dacl = security_acl_dup(dst, dacl);
+ if (dst->dacl == NULL) {
+ goto err_sd_free;
+ }
+ dst->type |= SEC_DESC_DACL_PRESENT;
+ }
+
+ if (owner_sid != NULL) {
+ dst->owner_sid = dom_sid_dup(dst, owner_sid);
+ if (dst->owner_sid == NULL) {
+ goto err_sd_free;
+ }
+ }
+
+ if (grp_sid != NULL) {
+ dst->group_sid = dom_sid_dup(dst, grp_sid);
+ if (dst->group_sid == NULL) {
+ goto err_sd_free;
+ }
+ }
+
+ if (sd_size != NULL) {
+ *sd_size = ndr_size_security_descriptor(dst, 0);
+ }
+
+ return dst;
+
+err_sd_free:
+ talloc_free(dst);
+ return NULL;
+}
+
+/*******************************************************************
+ Convert a secdesc into a byte stream
+********************************************************************/
+NTSTATUS marshall_sec_desc(TALLOC_CTX *mem_ctx,
+ const struct security_descriptor *secdesc,
+ uint8_t **data, size_t *len)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_push_struct_blob(
+ &blob, mem_ctx, secdesc,
+ (ndr_push_flags_fn_t)ndr_push_security_descriptor);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("ndr_push_security_descriptor failed: %s\n",
+ ndr_errstr(ndr_err)));
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ *data = blob.data;
+ *len = blob.length;
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Convert a secdesc_buf into a byte stream
+********************************************************************/
+
+NTSTATUS marshall_sec_desc_buf(TALLOC_CTX *mem_ctx,
+ const struct sec_desc_buf *secdesc_buf,
+ uint8_t **data, size_t *len)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_push_struct_blob(
+ &blob, mem_ctx, secdesc_buf,
+ (ndr_push_flags_fn_t)ndr_push_sec_desc_buf);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("ndr_push_sec_desc_buf failed: %s\n",
+ ndr_errstr(ndr_err)));
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ *data = blob.data;
+ *len = blob.length;
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Parse a byte stream into a secdesc
+********************************************************************/
+NTSTATUS unmarshall_sec_desc(TALLOC_CTX *mem_ctx, uint8_t *data, size_t len,
+ struct security_descriptor **psecdesc)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+ struct security_descriptor *result;
+
+ if ((data == NULL) || (len == 0)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ result = talloc_zero(mem_ctx, struct security_descriptor);
+ if (result == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ blob = data_blob_const(data, len);
+
+ ndr_err = ndr_pull_struct_blob(&blob, result, result,
+ (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("ndr_pull_security_descriptor failed: %s\n",
+ ndr_errstr(ndr_err)));
+ TALLOC_FREE(result);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ *psecdesc = result;
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Parse a byte stream into a sec_desc_buf
+********************************************************************/
+
+NTSTATUS unmarshall_sec_desc_buf(TALLOC_CTX *mem_ctx, uint8_t *data, size_t len,
+ struct sec_desc_buf **psecdesc_buf)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+ struct sec_desc_buf *result;
+
+ if ((data == NULL) || (len == 0)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ result = talloc_zero(mem_ctx, struct sec_desc_buf);
+ if (result == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ blob = data_blob_const(data, len);
+
+ ndr_err = ndr_pull_struct_blob(&blob, result, result,
+ (ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("ndr_pull_sec_desc_buf failed: %s\n",
+ ndr_errstr(ndr_err)));
+ TALLOC_FREE(result);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ *psecdesc_buf = result;
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Creates a struct security_descriptor structure with typical defaults.
+********************************************************************/
+
+struct security_descriptor *make_standard_sec_desc(TALLOC_CTX *ctx, const struct dom_sid *owner_sid, const struct dom_sid *grp_sid,
+ struct security_acl *dacl, size_t *sd_size)
+{
+ return make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
+ SEC_DESC_SELF_RELATIVE, owner_sid, grp_sid, NULL,
+ dacl, sd_size);
+}
+
+/*******************************************************************
+ Creates a struct sec_desc_buf structure.
+********************************************************************/
+
+struct sec_desc_buf *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, struct security_descriptor *sec_desc)
+{
+ struct sec_desc_buf *dst;
+
+ if((dst = talloc_zero(ctx, struct sec_desc_buf)) == NULL)
+ return NULL;
+
+ /* max buffer size (allocated size) */
+ dst->sd_size = (uint32_t)len;
+
+ if (sec_desc != NULL) {
+ dst->sd = security_descriptor_copy(ctx, sec_desc);
+ if (dst->sd == NULL) {
+ return NULL;
+ }
+ }
+
+ return dst;
+}
+
+/*
+ * Determine if an struct security_ace is inheritable
+ */
+
+static bool is_inheritable_ace(const struct security_ace *ace,
+ bool container)
+{
+ if (!container) {
+ return ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0);
+ }
+
+ if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
+ return true;
+ }
+
+ if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) &&
+ !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Does a security descriptor have any inheritable components for
+ * the newly created type ?
+ */
+
+bool sd_has_inheritable_components(const struct security_descriptor *parent_ctr, bool container)
+{
+ unsigned int i;
+ const struct security_acl *the_acl = parent_ctr->dacl;
+
+ if (the_acl == NULL) {
+ return false;
+ }
+
+ for (i = 0; i < the_acl->num_aces; i++) {
+ const struct security_ace *ace = &the_acl->aces[i];
+
+ if (is_inheritable_ace(ace, container)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Create a child security descriptor using another security descriptor as
+ the parent container. This child object can either be a container or
+ non-container object. */
+
+NTSTATUS se_create_child_secdesc(TALLOC_CTX *ctx,
+ struct security_descriptor **ppsd,
+ size_t *psize,
+ const struct security_descriptor *parent_ctr,
+ const struct dom_sid *owner_sid,
+ const struct dom_sid *group_sid,
+ bool container)
+{
+ struct security_acl *new_dacl = NULL, *the_acl = NULL;
+ struct security_ace *new_ace_list = NULL;
+ unsigned int new_ace_list_ndx = 0, i;
+ bool set_inherited_flags = (parent_ctr->type & SEC_DESC_DACL_AUTO_INHERITED);
+
+ *ppsd = NULL;
+ *psize = 0;
+
+ /* Currently we only process the dacl when creating the child. The
+ sacl should also be processed but this is left out as sacls are
+ not implemented in Samba at the moment.*/
+
+ the_acl = parent_ctr->dacl;
+
+ if (the_acl->num_aces) {
+ if (2*the_acl->num_aces < the_acl->num_aces) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!(new_ace_list = talloc_array(ctx, struct security_ace,
+ 2*the_acl->num_aces))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ new_ace_list = NULL;
+ }
+
+ for (i = 0; i < the_acl->num_aces; i++) {
+ const struct security_ace *ace = &the_acl->aces[i];
+ struct security_ace *new_ace = &new_ace_list[new_ace_list_ndx];
+ const struct dom_sid *ptrustee = &ace->trustee;
+ const struct dom_sid *creator = NULL;
+ uint8_t new_flags = ace->flags;
+ struct dom_sid_buf sidbuf1, sidbuf2;
+
+ if (!is_inheritable_ace(ace, container)) {
+ continue;
+ }
+
+ /* see the RAW-ACLS inheritance test for details on these rules */
+ if (!container) {
+ new_flags = 0;
+ } else {
+ /*
+ * We need to remove SEC_ACE_FLAG_INHERITED_ACE here
+ * if present because it should only be set if the
+ * parent has the AUTO_INHERITED bit set in the
+ * type/control field. If we don't it will slip through
+ * and create DACLs with incorrectly ordered ACEs
+ * when there are CREATOR_OWNER or CREATOR_GROUP
+ * ACEs.
+ */
+ new_flags &= ~(SEC_ACE_FLAG_INHERIT_ONLY
+ | SEC_ACE_FLAG_INHERITED_ACE);
+
+ if (!(new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
+ new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+ }
+ if (new_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
+ new_flags = 0;
+ }
+ }
+
+ /* The CREATOR sids are special when inherited */
+ if (dom_sid_equal(ptrustee, &global_sid_Creator_Owner)) {
+ creator = &global_sid_Creator_Owner;
+ ptrustee = owner_sid;
+ } else if (dom_sid_equal(ptrustee, &global_sid_Creator_Group)) {
+ creator = &global_sid_Creator_Group;
+ ptrustee = group_sid;
+ }
+
+ if (creator && container &&
+ (new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
+
+ /* First add the regular ACE entry. */
+ init_sec_ace(new_ace, ptrustee, ace->type,
+ ace->access_mask,
+ set_inherited_flags ? SEC_ACE_FLAG_INHERITED_ACE : 0);
+
+ DEBUG(5,("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x"
+ " inherited as %s:%d/0x%02x/0x%08x\n",
+ dom_sid_str_buf(&ace->trustee, &sidbuf1),
+ ace->type, ace->flags, ace->access_mask,
+ dom_sid_str_buf(&new_ace->trustee, &sidbuf2),
+ new_ace->type, new_ace->flags,
+ new_ace->access_mask));
+
+ new_ace_list_ndx++;
+
+ /* Now add the extra creator ACE. */
+ new_ace = &new_ace_list[new_ace_list_ndx];
+
+ ptrustee = creator;
+ new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+
+ } else if (container &&
+ !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
+ ptrustee = &ace->trustee;
+ }
+
+ init_sec_ace(new_ace, ptrustee, ace->type,
+ ace->access_mask, new_flags |
+ (set_inherited_flags ? SEC_ACE_FLAG_INHERITED_ACE : 0));
+
+ DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
+ " inherited as %s:%d/0x%02x/0x%08x\n",
+ dom_sid_str_buf(&ace->trustee, &sidbuf1),
+ ace->type, ace->flags, ace->access_mask,
+ dom_sid_str_buf(&new_ace->trustee, &sidbuf2),
+ new_ace->type, new_ace->flags,
+ new_ace->access_mask));
+
+ new_ace_list_ndx++;
+ }
+
+ /*
+ * remove duplicates
+ */
+ for (i=1; i < new_ace_list_ndx;) {
+ struct security_ace *ai = &new_ace_list[i];
+ unsigned int remaining, j;
+ bool remove_ace = false;
+
+ for (j=0; j < i; j++) {
+ struct security_ace *aj = &new_ace_list[j];
+
+ if (!security_ace_equal(ai, aj)) {
+ continue;
+ }
+
+ remove_ace = true;
+ break;
+ }
+
+ if (!remove_ace) {
+ i++;
+ continue;
+ }
+
+ new_ace_list_ndx--;
+ remaining = new_ace_list_ndx - i;
+ if (remaining == 0) {
+ ZERO_STRUCT(new_ace_list[i]);
+ continue;
+ }
+ memmove(&new_ace_list[i], &new_ace_list[i+1],
+ sizeof(new_ace_list[i]) * remaining);
+ }
+
+ /* Create child security descriptor to return */
+ if (new_ace_list_ndx) {
+ new_dacl = make_sec_acl(ctx,
+ NT4_ACL_REVISION,
+ new_ace_list_ndx,
+ new_ace_list);
+
+ if (!new_dacl) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ *ppsd = make_sec_desc(ctx,
+ SECURITY_DESCRIPTOR_REVISION_1,
+ SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT|
+ (set_inherited_flags ? SEC_DESC_DACL_AUTO_INHERITED : 0),
+ owner_sid,
+ group_sid,
+ NULL,
+ new_dacl,
+ psize);
+ if (!*ppsd) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}
diff --git a/libcli/security/secdesc.h b/libcli/security/secdesc.h
new file mode 100644
index 0000000..ca9376a
--- /dev/null
+++ b/libcli/security/secdesc.h
@@ -0,0 +1,96 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * SEC_DESC handling functions
+ * Copyright (C) Andrew Tridgell 1992-1998,
+ * Copyright (C) Jeremy R. Allison 1995-2003.
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
+ * Copyright (C) Paul Ashton 1997-1998.
+ *
+ * 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/>.
+ */
+
+#ifndef _SECDESC_H_
+#define _SECDESC_H_
+
+/* The following definitions come from libcli/security/secdesc.c */
+#include "librpc/gen_ndr/security.h"
+
+/*******************************************************************
+ Given a security_descriptor return the sec_info.
+********************************************************************/
+uint32_t get_sec_info(const struct security_descriptor *sd);
+
+/*******************************************************************
+ Merge part of security descriptor old_sec in to the empty sections of
+ security descriptor new_sec.
+********************************************************************/
+struct sec_desc_buf *sec_desc_merge_buf(TALLOC_CTX *ctx, struct sec_desc_buf *new_sdb, struct sec_desc_buf *old_sdb);
+struct security_descriptor *sec_desc_merge(TALLOC_CTX *ctx, struct security_descriptor *new_sdb, struct security_descriptor *old_sdb);
+
+/*******************************************************************
+ Creates a struct security_descriptor structure
+********************************************************************/
+struct security_descriptor *make_sec_desc(TALLOC_CTX *ctx,
+ enum security_descriptor_revision revision,
+ uint16_t type,
+ const struct dom_sid *owner_sid, const struct dom_sid *grp_sid,
+ struct security_acl *sacl, struct security_acl *dacl, size_t *sd_size);
+
+/*******************************************************************
+ Convert a secdesc into a byte stream
+********************************************************************/
+NTSTATUS marshall_sec_desc(TALLOC_CTX *mem_ctx,
+ const struct security_descriptor *secdesc,
+ uint8_t **data, size_t *len);
+
+/*******************************************************************
+ Convert a secdesc_buf into a byte stream
+********************************************************************/
+NTSTATUS marshall_sec_desc_buf(TALLOC_CTX *mem_ctx,
+ const struct sec_desc_buf *secdesc_buf,
+ uint8_t **data, size_t *len);
+
+/*******************************************************************
+ Parse a byte stream into a secdesc
+********************************************************************/
+NTSTATUS unmarshall_sec_desc(TALLOC_CTX *mem_ctx, uint8_t *data, size_t len,
+ struct security_descriptor **psecdesc);
+
+/*******************************************************************
+ Parse a byte stream into a sec_desc_buf
+********************************************************************/
+NTSTATUS unmarshall_sec_desc_buf(TALLOC_CTX *mem_ctx, uint8_t *data, size_t len,
+ struct sec_desc_buf **psecdesc_buf);
+
+/*******************************************************************
+ Creates a struct security_descriptor structure with typical defaults.
+********************************************************************/
+struct security_descriptor *make_standard_sec_desc(TALLOC_CTX *ctx, const struct dom_sid *owner_sid, const struct dom_sid *grp_sid,
+ struct security_acl *dacl, size_t *sd_size);
+
+/*******************************************************************
+ Creates a struct sec_desc_buf structure.
+********************************************************************/
+struct sec_desc_buf *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, struct security_descriptor *sec_desc);
+
+bool sd_has_inheritable_components(const struct security_descriptor *parent_ctr, bool container);
+NTSTATUS se_create_child_secdesc(TALLOC_CTX *ctx,
+ struct security_descriptor **ppsd,
+ size_t *psize,
+ const struct security_descriptor *parent_ctr,
+ const struct dom_sid *owner_sid,
+ const struct dom_sid *group_sid,
+ bool container);
+
+#endif /* _SECDESC_H_ */
diff --git a/libcli/security/security.h b/libcli/security/security.h
new file mode 100644
index 0000000..a1c26ed
--- /dev/null
+++ b/libcli/security/security.h
@@ -0,0 +1,121 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 2006
+
+ 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/>.
+*/
+
+#ifndef _LIBCLI_SECURITY_SECURITY_H_
+#define _LIBCLI_SECURITY_SECURITY_H_
+
+#include "lib/util/data_blob.h"
+#include "lib/util/time.h"
+
+#include "librpc/gen_ndr/security.h"
+
+/* File Specific access rights */
+#define FILE_READ_DATA SEC_FILE_READ_DATA
+#define FILE_WRITE_DATA SEC_FILE_WRITE_DATA
+#define FILE_APPEND_DATA SEC_FILE_APPEND_DATA
+#define FILE_READ_EA SEC_FILE_READ_EA /* File and directory */
+#define FILE_WRITE_EA SEC_FILE_WRITE_EA /* File and directory */
+#define FILE_EXECUTE SEC_FILE_EXECUTE
+#define FILE_READ_ATTRIBUTES SEC_FILE_READ_ATTRIBUTE
+#define FILE_WRITE_ATTRIBUTES SEC_FILE_WRITE_ATTRIBUTE
+
+#define FILE_ALL_ACCESS SEC_FILE_ALL
+
+/* Directory specific access rights */
+#define FILE_LIST_DIRECTORY SEC_DIR_LIST
+#define FILE_ADD_FILE SEC_DIR_ADD_FILE
+#define FILE_ADD_SUBDIRECTORY SEC_DIR_ADD_SUBDIR
+#define FILE_TRAVERSE SEC_DIR_TRAVERSE
+#define FILE_DELETE_CHILD SEC_DIR_DELETE_CHILD
+
+/* Generic access masks & rights. */
+#define DELETE_ACCESS SEC_STD_DELETE /* (1L<<16) */
+#define READ_CONTROL_ACCESS SEC_STD_READ_CONTROL /* (1L<<17) */
+#define WRITE_DAC_ACCESS SEC_STD_WRITE_DAC /* (1L<<18) */
+#define WRITE_OWNER_ACCESS SEC_STD_WRITE_OWNER /* (1L<<19) */
+#define SYNCHRONIZE_ACCESS SEC_STD_SYNCHRONIZE /* (1L<<20) */
+
+#define SYSTEM_SECURITY_ACCESS SEC_FLAG_SYSTEM_SECURITY /* (1L<<24) */
+#define MAXIMUM_ALLOWED_ACCESS SEC_FLAG_MAXIMUM_ALLOWED /* (1L<<25) */
+#define GENERIC_ALL_ACCESS SEC_GENERIC_ALL /* (1<<28) */
+#define GENERIC_EXECUTE_ACCESS SEC_GENERIC_EXECUTE /* (1<<29) */
+#define GENERIC_WRITE_ACCESS SEC_GENERIC_WRITE /* (1<<30) */
+#define GENERIC_READ_ACCESS ((unsigned)SEC_GENERIC_READ) /* (((unsigned)1)<<31) */
+
+/* Mapping of generic access rights for files to specific rights. */
+
+/* This maps to 0x1F01FF */
+#define FILE_GENERIC_ALL (STANDARD_RIGHTS_REQUIRED_ACCESS|\
+ SEC_STD_SYNCHRONIZE|\
+ FILE_ALL_ACCESS)
+
+/* This maps to 0x120089 */
+#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ_ACCESS|\
+ FILE_READ_DATA|\
+ FILE_READ_ATTRIBUTES|\
+ FILE_READ_EA|\
+ SYNCHRONIZE_ACCESS)
+
+/* This maps to 0x120116 */
+#define FILE_GENERIC_WRITE (SEC_STD_READ_CONTROL|\
+ FILE_WRITE_DATA|\
+ FILE_WRITE_ATTRIBUTES|\
+ FILE_WRITE_EA|\
+ FILE_APPEND_DATA|\
+ SYNCHRONIZE_ACCESS)
+
+#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE_ACCESS|\
+ FILE_READ_ATTRIBUTES|\
+ FILE_EXECUTE|\
+ SYNCHRONIZE_ACCESS)
+
+/* Share specific rights. */
+#define SHARE_ALL_ACCESS FILE_GENERIC_ALL
+#define SHARE_READ_ONLY (FILE_GENERIC_READ|FILE_EXECUTE)
+
+/**
+ * Remaining access is a bit mask of remaining access rights (bits) that have
+ * to be granted in order to fulfill the requested access.
+ *
+ * The GUID is optional, if specified it restricts this object tree and its
+ * children to object/attributes that inherits from this GUID.
+ * For DS access an object inherits from a GUID if one of its class has this GUID
+ * in the schemaIDGUID attribute.
+ */
+struct object_tree {
+ uint32_t remaining_access;
+ struct GUID guid;
+ int num_of_children;
+ struct object_tree *children;
+};
+
+/* Moved the dom_sid functions to the top level dir with manual proto header */
+#include "libcli/security/dom_sid.h"
+#include "libcli/security/secace.h"
+#include "libcli/security/secacl.h"
+#include "libcli/security/secdesc.h"
+#include "libcli/security/security_descriptor.h"
+#include "libcli/security/security_token.h"
+#include "libcli/security/sddl.h"
+#include "libcli/security/privileges.h"
+#include "libcli/security/access_check.h"
+#include "libcli/security/session.h"
+#include "libcli/security/display_sec.h"
+
+#endif
diff --git a/libcli/security/security_descriptor.c b/libcli/security/security_descriptor.c
new file mode 100644
index 0000000..9b9f16c
--- /dev/null
+++ b/libcli/security/security_descriptor.c
@@ -0,0 +1,908 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ security descriptor utility functions
+
+ Copyright (C) Andrew Tridgell 2004
+
+ 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 "replace.h"
+#include "libcli/security/security.h"
+#include "librpc/ndr/libndr.h"
+
+/*
+ return a blank security descriptor (no owners, dacl or sacl)
+*/
+struct security_descriptor *security_descriptor_initialise(TALLOC_CTX *mem_ctx)
+{
+ struct security_descriptor *sd;
+
+ sd = talloc(mem_ctx, struct security_descriptor);
+ if (!sd) {
+ return NULL;
+ }
+
+ sd->revision = SD_REVISION;
+ /* we mark as self relative, even though it isn't while it remains
+ a pointer in memory because this simplifies the ndr code later.
+ All SDs that we store/emit are in fact SELF_RELATIVE
+ */
+ sd->type = SEC_DESC_SELF_RELATIVE;
+
+ sd->owner_sid = NULL;
+ sd->group_sid = NULL;
+ sd->sacl = NULL;
+ sd->dacl = NULL;
+
+ return sd;
+}
+
+struct security_acl *security_acl_dup(TALLOC_CTX *mem_ctx,
+ const struct security_acl *oacl)
+{
+ struct security_acl *nacl;
+
+ if (oacl == NULL) {
+ return NULL;
+ }
+
+ if (oacl->aces == NULL && oacl->num_aces > 0) {
+ return NULL;
+ }
+
+ nacl = talloc (mem_ctx, struct security_acl);
+ if (nacl == NULL) {
+ return NULL;
+ }
+
+ *nacl = (struct security_acl) {
+ .revision = oacl->revision,
+ .size = oacl->size,
+ .num_aces = oacl->num_aces,
+ };
+ if (nacl->num_aces == 0) {
+ return nacl;
+ }
+
+ nacl->aces = (struct security_ace *)talloc_memdup (nacl, oacl->aces, sizeof(struct security_ace) * oacl->num_aces);
+ if (nacl->aces == NULL) {
+ goto failed;
+ }
+
+ return nacl;
+
+ failed:
+ talloc_free (nacl);
+ return NULL;
+
+}
+
+struct security_acl *security_acl_concatenate(TALLOC_CTX *mem_ctx,
+ const struct security_acl *acl1,
+ const struct security_acl *acl2)
+{
+ struct security_acl *nacl;
+ uint32_t i;
+
+ if (!acl1 && !acl2)
+ return NULL;
+
+ if (!acl1){
+ nacl = security_acl_dup(mem_ctx, acl2);
+ return nacl;
+ }
+
+ if (!acl2){
+ nacl = security_acl_dup(mem_ctx, acl1);
+ return nacl;
+ }
+
+ nacl = talloc (mem_ctx, struct security_acl);
+ if (nacl == NULL) {
+ return NULL;
+ }
+
+ nacl->revision = acl1->revision;
+ nacl->size = acl1->size + acl2->size;
+ nacl->num_aces = acl1->num_aces + acl2->num_aces;
+
+ if (nacl->num_aces == 0)
+ return nacl;
+
+ nacl->aces = (struct security_ace *)talloc_array (mem_ctx, struct security_ace, acl1->num_aces+acl2->num_aces);
+ if ((nacl->aces == NULL) && (nacl->num_aces > 0)) {
+ goto failed;
+ }
+
+ for (i = 0; i < acl1->num_aces; i++)
+ nacl->aces[i] = acl1->aces[i];
+ for (i = 0; i < acl2->num_aces; i++)
+ nacl->aces[i + acl1->num_aces] = acl2->aces[i];
+
+ return nacl;
+
+ failed:
+ talloc_free (nacl);
+ return NULL;
+
+}
+
+/*
+ talloc and copy a security descriptor
+ */
+struct security_descriptor *security_descriptor_copy(TALLOC_CTX *mem_ctx,
+ const struct security_descriptor *osd)
+{
+ struct security_descriptor *nsd;
+
+ nsd = talloc_zero(mem_ctx, struct security_descriptor);
+ if (!nsd) {
+ return NULL;
+ }
+
+ if (osd->owner_sid) {
+ nsd->owner_sid = dom_sid_dup(nsd, osd->owner_sid);
+ if (nsd->owner_sid == NULL) {
+ goto failed;
+ }
+ }
+
+ if (osd->group_sid) {
+ nsd->group_sid = dom_sid_dup(nsd, osd->group_sid);
+ if (nsd->group_sid == NULL) {
+ goto failed;
+ }
+ }
+
+ if (osd->sacl) {
+ nsd->sacl = security_acl_dup(nsd, osd->sacl);
+ if (nsd->sacl == NULL) {
+ goto failed;
+ }
+ }
+
+ if (osd->dacl) {
+ nsd->dacl = security_acl_dup(nsd, osd->dacl);
+ if (nsd->dacl == NULL) {
+ goto failed;
+ }
+ }
+
+ nsd->revision = osd->revision;
+ nsd->type = osd->type;
+
+ return nsd;
+
+ failed:
+ talloc_free(nsd);
+
+ return NULL;
+}
+
+NTSTATUS security_descriptor_for_client(TALLOC_CTX *mem_ctx,
+ const struct security_descriptor *ssd,
+ uint32_t sec_info,
+ uint32_t access_granted,
+ struct security_descriptor **_csd)
+{
+ struct security_descriptor *csd = NULL;
+ uint32_t access_required = 0;
+
+ *_csd = NULL;
+
+ if (sec_info & (SECINFO_OWNER|SECINFO_GROUP)) {
+ access_required |= SEC_STD_READ_CONTROL;
+ }
+ if (sec_info & SECINFO_DACL) {
+ access_required |= SEC_STD_READ_CONTROL;
+ }
+ if (sec_info & SECINFO_SACL) {
+ access_required |= SEC_FLAG_SYSTEM_SECURITY;
+ }
+
+ if (access_required & (~access_granted)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /*
+ * make a copy...
+ */
+ csd = security_descriptor_copy(mem_ctx, ssd);
+ if (csd == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /*
+ * ... and remove everything not wanted
+ */
+
+ if (!(sec_info & SECINFO_OWNER)) {
+ TALLOC_FREE(csd->owner_sid);
+ csd->type &= ~SEC_DESC_OWNER_DEFAULTED;
+ }
+ if (!(sec_info & SECINFO_GROUP)) {
+ TALLOC_FREE(csd->group_sid);
+ csd->type &= ~SEC_DESC_GROUP_DEFAULTED;
+ }
+ if (!(sec_info & SECINFO_DACL)) {
+ TALLOC_FREE(csd->dacl);
+ csd->type &= ~(
+ SEC_DESC_DACL_PRESENT |
+ SEC_DESC_DACL_DEFAULTED|
+ SEC_DESC_DACL_AUTO_INHERIT_REQ |
+ SEC_DESC_DACL_AUTO_INHERITED |
+ SEC_DESC_DACL_PROTECTED |
+ SEC_DESC_DACL_TRUSTED);
+ }
+ if (!(sec_info & SECINFO_SACL)) {
+ TALLOC_FREE(csd->sacl);
+ csd->type &= ~(
+ SEC_DESC_SACL_PRESENT |
+ SEC_DESC_SACL_DEFAULTED |
+ SEC_DESC_SACL_AUTO_INHERIT_REQ |
+ SEC_DESC_SACL_AUTO_INHERITED |
+ SEC_DESC_SACL_PROTECTED |
+ SEC_DESC_SERVER_SECURITY);
+ }
+
+ *_csd = csd;
+ return NT_STATUS_OK;
+}
+
+/*
+ add an ACE to an ACL of a security_descriptor
+*/
+
+static NTSTATUS security_descriptor_acl_add(struct security_descriptor *sd,
+ bool add_to_sacl,
+ const struct security_ace *ace,
+ ssize_t _idx)
+{
+ struct security_acl *acl = NULL;
+ ssize_t idx;
+
+ if (add_to_sacl) {
+ acl = sd->sacl;
+ } else {
+ acl = sd->dacl;
+ }
+
+ if (acl == NULL) {
+ acl = talloc(sd, struct security_acl);
+ if (acl == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ acl->revision = SECURITY_ACL_REVISION_NT4;
+ acl->size = 0;
+ acl->num_aces = 0;
+ acl->aces = NULL;
+ }
+
+ if (_idx < 0) {
+ idx = (acl->num_aces + 1) + _idx;
+ } else {
+ idx = _idx;
+ }
+
+ if (idx < 0) {
+ return NT_STATUS_ARRAY_BOUNDS_EXCEEDED;
+ } else if (idx > acl->num_aces) {
+ return NT_STATUS_ARRAY_BOUNDS_EXCEEDED;
+ }
+
+ acl->aces = talloc_realloc(acl, acl->aces,
+ struct security_ace, acl->num_aces+1);
+ if (acl->aces == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ARRAY_INSERT_ELEMENT(acl->aces, acl->num_aces, *ace, idx);
+ acl->num_aces++;
+
+ if (sec_ace_object(acl->aces[idx].type)) {
+ acl->revision = SECURITY_ACL_REVISION_ADS;
+ }
+
+ if (add_to_sacl) {
+ sd->sacl = acl;
+ sd->type |= SEC_DESC_SACL_PRESENT;
+ } else {
+ sd->dacl = acl;
+ sd->type |= SEC_DESC_DACL_PRESENT;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ add an ACE to the SACL of a security_descriptor
+*/
+
+NTSTATUS security_descriptor_sacl_add(struct security_descriptor *sd,
+ const struct security_ace *ace)
+{
+ return security_descriptor_acl_add(sd, true, ace, -1);
+}
+
+/*
+ insert an ACE at a given index to the SACL of a security_descriptor
+
+ idx can be negative, which means it's related to the new size from the
+ end, so -1 means the ace is appended at the end.
+*/
+
+NTSTATUS security_descriptor_sacl_insert(struct security_descriptor *sd,
+ const struct security_ace *ace,
+ ssize_t idx)
+{
+ return security_descriptor_acl_add(sd, true, ace, idx);
+}
+
+/*
+ add an ACE to the DACL of a security_descriptor
+*/
+
+NTSTATUS security_descriptor_dacl_add(struct security_descriptor *sd,
+ const struct security_ace *ace)
+{
+ return security_descriptor_acl_add(sd, false, ace, -1);
+}
+
+/*
+ insert an ACE at a given index to the DACL of a security_descriptor
+
+ idx can be negative, which means it's related to the new size from the
+ end, so -1 means the ace is appended at the end.
+*/
+
+NTSTATUS security_descriptor_dacl_insert(struct security_descriptor *sd,
+ const struct security_ace *ace,
+ ssize_t idx)
+{
+ return security_descriptor_acl_add(sd, false, ace, idx);
+}
+
+/*
+ delete the ACE corresponding to the given trustee in an ACL of a
+ security_descriptor
+*/
+
+static NTSTATUS security_descriptor_acl_del(struct security_descriptor *sd,
+ bool sacl_del,
+ const struct dom_sid *trustee)
+{
+ uint32_t i;
+ bool found = false;
+ struct security_acl *acl = NULL;
+
+ if (sacl_del) {
+ acl = sd->sacl;
+ } else {
+ acl = sd->dacl;
+ }
+
+ if (acl == NULL) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ /* there can be multiple ace's for one trustee */
+ for (i=0;i<acl->num_aces;i++) {
+ if (dom_sid_equal(trustee, &acl->aces[i].trustee)) {
+ ARRAY_DEL_ELEMENT(acl->aces, i, acl->num_aces);
+ acl->num_aces--;
+ if (acl->num_aces == 0) {
+ acl->aces = NULL;
+ }
+ found = true;
+ --i;
+ }
+ }
+
+ if (!found) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ acl->revision = SECURITY_ACL_REVISION_NT4;
+
+ for (i=0;i<acl->num_aces;i++) {
+ if (sec_ace_object(acl->aces[i].type)) {
+ acl->revision = SECURITY_ACL_REVISION_ADS;
+ break;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ delete the ACE corresponding to the given trustee in the DACL of a
+ security_descriptor
+*/
+
+NTSTATUS security_descriptor_dacl_del(struct security_descriptor *sd,
+ const struct dom_sid *trustee)
+{
+ return security_descriptor_acl_del(sd, false, trustee);
+}
+
+/*
+ delete the ACE corresponding to the given trustee in the SACL of a
+ security_descriptor
+*/
+
+NTSTATUS security_descriptor_sacl_del(struct security_descriptor *sd,
+ const struct dom_sid *trustee)
+{
+ return security_descriptor_acl_del(sd, true, trustee);
+}
+
+/*
+ delete the given ACE in the SACL or DACL of a security_descriptor
+*/
+static NTSTATUS security_descriptor_acl_del_ace(struct security_descriptor *sd,
+ bool sacl_del,
+ const struct security_ace *ace)
+{
+ uint32_t i;
+ bool found = false;
+ struct security_acl *acl = NULL;
+
+ if (sacl_del) {
+ acl = sd->sacl;
+ } else {
+ acl = sd->dacl;
+ }
+
+ if (acl == NULL) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ for (i=0;i<acl->num_aces;i++) {
+ if (security_ace_equal(ace, &acl->aces[i])) {
+ ARRAY_DEL_ELEMENT(acl->aces, i, acl->num_aces);
+ acl->num_aces--;
+ if (acl->num_aces == 0) {
+ acl->aces = NULL;
+ }
+ found = true;
+ i--;
+ }
+ }
+
+ if (!found) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ acl->revision = SECURITY_ACL_REVISION_NT4;
+
+ for (i=0;i<acl->num_aces;i++) {
+ if (sec_ace_object(acl->aces[i].type)) {
+ acl->revision = SECURITY_ACL_REVISION_ADS;
+ break;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS security_descriptor_dacl_del_ace(struct security_descriptor *sd,
+ const struct security_ace *ace)
+{
+ return security_descriptor_acl_del_ace(sd, false, ace);
+}
+
+NTSTATUS security_descriptor_sacl_del_ace(struct security_descriptor *sd,
+ const struct security_ace *ace)
+{
+ return security_descriptor_acl_del_ace(sd, true, ace);
+}
+
+static bool security_ace_object_equal(const struct security_ace_object *object1,
+ const struct security_ace_object *object2)
+{
+ if (object1 == object2) {
+ return true;
+ }
+ if ((object1 == NULL) || (object2 == NULL)) {
+ return false;
+ }
+ if (object1->flags != object2->flags) {
+ return false;
+ }
+ if (object1->flags & SEC_ACE_OBJECT_TYPE_PRESENT
+ && !GUID_equal(&object1->type.type, &object2->type.type)) {
+ return false;
+ }
+ if (object1->flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT
+ && !GUID_equal(&object1->inherited_type.inherited_type,
+ &object2->inherited_type.inherited_type)) {
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool security_ace_claim_equal(const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim1,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim2)
+{
+ uint32_t i;
+
+ if (claim1 == claim2) {
+ return true;
+ }
+ if (claim1 == NULL || claim2 == NULL) {
+ return false;
+ }
+ if (claim1->name != NULL && claim2->name != NULL) {
+ if (strcasecmp_m(claim1->name, claim2->name) != 0) {
+ return false;
+ }
+ } else if (claim1->name != NULL || claim2->name != NULL) {
+ return false;
+ }
+ if (claim1->value_type != claim2->value_type) {
+ return false;
+ }
+ if (claim1->flags != claim2->flags) {
+ return false;
+ }
+ if (claim1->value_count != claim2->value_count) {
+ return false;
+ }
+ for (i = 0; i < claim1->value_count; ++i) {
+ const union claim_values *values1 = claim1->values;
+ const union claim_values *values2 = claim2->values;
+
+ switch (claim1->value_type) {
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
+ if (values1[i].int_value != NULL && values2[i].int_value != NULL) {
+ if (*values1[i].int_value != *values2[i].int_value) {
+ return false;
+ }
+ } else if (values1[i].int_value != NULL || values2[i].int_value != NULL) {
+ return false;
+ }
+ break;
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN:
+ if (values1[i].uint_value != NULL && values2[i].uint_value != NULL) {
+ if (*values1[i].uint_value != *values2[i].uint_value) {
+ return false;
+ }
+ } else if (values1[i].uint_value != NULL || values2[i].uint_value != NULL) {
+ return false;
+ }
+ break;
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
+ if (values1[i].string_value != NULL && values2[i].string_value != NULL) {
+ if (strcasecmp_m(values1[i].string_value, values2[i].string_value) != 0) {
+ return false;
+ }
+ } else if (values1[i].string_value != NULL || values2[i].string_value != NULL) {
+ return false;
+ }
+ break;
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_SID:
+ if (values1[i].sid_value != NULL && values2[i].sid_value != NULL) {
+ if (data_blob_cmp(values1[i].sid_value, values2[i].sid_value) != 0) {
+ return false;
+ }
+ } else if (values1[i].sid_value != NULL || values2[i].sid_value != NULL) {
+ return false;
+ }
+ break;
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:
+ if (values1[i].octet_value != NULL && values2[i].octet_value != NULL) {
+ if (data_blob_cmp(values1[i].octet_value, values2[i].octet_value) != 0) {
+ return false;
+ }
+ } else if (values1[i].octet_value != NULL || values2[i].octet_value != NULL) {
+ return false;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return true;
+}
+
+/*
+ compare two security ace structures
+*/
+bool security_ace_equal(const struct security_ace *ace1,
+ const struct security_ace *ace2)
+{
+ if (ace1 == ace2) {
+ return true;
+ }
+ if ((ace1 == NULL) || (ace2 == NULL)) {
+ return false;
+ }
+ if (ace1->type != ace2->type) {
+ return false;
+ }
+ if (ace1->flags != ace2->flags) {
+ return false;
+ }
+ if (ace1->access_mask != ace2->access_mask) {
+ return false;
+ }
+ if (sec_ace_object(ace1->type) &&
+ !security_ace_object_equal(&ace1->object.object,
+ &ace2->object.object))
+ {
+ return false;
+ }
+ if (!dom_sid_equal(&ace1->trustee, &ace2->trustee)) {
+ return false;
+ }
+
+ if (sec_ace_callback(ace1->type)) {
+ if (data_blob_cmp(&ace1->coda.conditions, &ace2->coda.conditions) != 0) {
+ return false;
+ }
+ } else if (sec_ace_resource(ace1->type)) {
+ if (!security_ace_claim_equal(&ace1->coda.claim, &ace2->coda.claim)) {
+ return false;
+ }
+ } else {
+ /*
+ * Don’t require ace1->coda.ignored to match ace2->coda.ignored.
+ */
+ }
+
+ return true;
+}
+
+
+/*
+ compare two security acl structures
+*/
+bool security_acl_equal(const struct security_acl *acl1,
+ const struct security_acl *acl2)
+{
+ uint32_t i;
+
+ if (acl1 == acl2) return true;
+ if (!acl1 || !acl2) return false;
+ if (acl1->revision != acl2->revision) return false;
+ if (acl1->num_aces != acl2->num_aces) return false;
+
+ for (i=0;i<acl1->num_aces;i++) {
+ if (!security_ace_equal(&acl1->aces[i], &acl2->aces[i])) return false;
+ }
+ return true;
+}
+
+/*
+ compare two security descriptors.
+*/
+bool security_descriptor_equal(const struct security_descriptor *sd1,
+ const struct security_descriptor *sd2)
+{
+ if (sd1 == sd2) return true;
+ if (!sd1 || !sd2) return false;
+ if (sd1->revision != sd2->revision) return false;
+ if (sd1->type != sd2->type) return false;
+
+ if (!dom_sid_equal(sd1->owner_sid, sd2->owner_sid)) return false;
+ if (!dom_sid_equal(sd1->group_sid, sd2->group_sid)) return false;
+ if (!security_acl_equal(sd1->sacl, sd2->sacl)) return false;
+ if (!security_acl_equal(sd1->dacl, sd2->dacl)) return false;
+
+ return true;
+}
+
+/*
+ compare two security descriptors, but allow certain (missing) parts
+ to be masked out of the comparison
+*/
+bool security_descriptor_mask_equal(const struct security_descriptor *sd1,
+ const struct security_descriptor *sd2,
+ uint32_t mask)
+{
+ if (sd1 == sd2) return true;
+ if (!sd1 || !sd2) return false;
+ if (sd1->revision != sd2->revision) return false;
+ if ((sd1->type & mask) != (sd2->type & mask)) return false;
+
+ if (!dom_sid_equal(sd1->owner_sid, sd2->owner_sid)) return false;
+ if (!dom_sid_equal(sd1->group_sid, sd2->group_sid)) return false;
+ if ((mask & SEC_DESC_DACL_PRESENT) && !security_acl_equal(sd1->dacl, sd2->dacl)) return false;
+ if ((mask & SEC_DESC_SACL_PRESENT) && !security_acl_equal(sd1->sacl, sd2->sacl)) return false;
+
+ return true;
+}
+
+
+static struct security_descriptor *security_descriptor_appendv(struct security_descriptor *sd,
+ bool add_ace_to_sacl,
+ va_list ap)
+{
+ const char *sidstr;
+
+ while ((sidstr = va_arg(ap, const char *))) {
+ struct dom_sid *sid;
+ struct security_ace *ace = talloc_zero(sd, struct security_ace);
+ NTSTATUS status;
+
+ if (ace == NULL) {
+ talloc_free(sd);
+ return NULL;
+ }
+ ace->type = va_arg(ap, unsigned int);
+ ace->access_mask = va_arg(ap, unsigned int);
+ ace->flags = va_arg(ap, unsigned int);
+ sid = dom_sid_parse_talloc(ace, sidstr);
+ if (sid == NULL) {
+ talloc_free(sd);
+ return NULL;
+ }
+ ace->trustee = *sid;
+ if (add_ace_to_sacl) {
+ status = security_descriptor_sacl_add(sd, ace);
+ } else {
+ status = security_descriptor_dacl_add(sd, ace);
+ }
+ /* TODO: check: would talloc_free(ace) here be correct? */
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(sd);
+ return NULL;
+ }
+ }
+
+ return sd;
+}
+
+static struct security_descriptor *security_descriptor_createv(TALLOC_CTX *mem_ctx,
+ uint16_t sd_type,
+ const char *owner_sid,
+ const char *group_sid,
+ bool add_ace_to_sacl,
+ va_list ap)
+{
+ struct security_descriptor *sd;
+
+ sd = security_descriptor_initialise(mem_ctx);
+ if (sd == NULL) {
+ return NULL;
+ }
+
+ sd->type |= sd_type;
+
+ if (owner_sid) {
+ sd->owner_sid = dom_sid_parse_talloc(sd, owner_sid);
+ if (sd->owner_sid == NULL) {
+ talloc_free(sd);
+ return NULL;
+ }
+ }
+ if (group_sid) {
+ sd->group_sid = dom_sid_parse_talloc(sd, group_sid);
+ if (sd->group_sid == NULL) {
+ talloc_free(sd);
+ return NULL;
+ }
+ }
+
+ return security_descriptor_appendv(sd, add_ace_to_sacl, ap);
+}
+
+/*
+ create a security descriptor using string SIDs. This is used by the
+ torture code to allow the easy creation of complex ACLs
+ This is a varargs function. The list of DACL ACEs ends with a NULL sid.
+
+ Each ACE contains a set of 4 parameters:
+ SID, ACCESS_TYPE, MASK, FLAGS
+
+ a typical call would be:
+
+ sd = security_descriptor_dacl_create(mem_ctx,
+ sd_type_flags,
+ mysid,
+ mygroup,
+ SID_NT_AUTHENTICATED_USERS,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_ALL,
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ NULL);
+ that would create a sd with one DACL ACE
+*/
+
+struct security_descriptor *security_descriptor_dacl_create(TALLOC_CTX *mem_ctx,
+ uint16_t sd_type,
+ const char *owner_sid,
+ const char *group_sid,
+ ...)
+{
+ struct security_descriptor *sd = NULL;
+ va_list ap;
+ va_start(ap, group_sid);
+ sd = security_descriptor_createv(mem_ctx, sd_type, owner_sid,
+ group_sid, false, ap);
+ va_end(ap);
+
+ return sd;
+}
+
+struct security_descriptor *security_descriptor_sacl_create(TALLOC_CTX *mem_ctx,
+ uint16_t sd_type,
+ const char *owner_sid,
+ const char *group_sid,
+ ...)
+{
+ struct security_descriptor *sd = NULL;
+ va_list ap;
+ va_start(ap, group_sid);
+ sd = security_descriptor_createv(mem_ctx, sd_type, owner_sid,
+ group_sid, true, ap);
+ va_end(ap);
+
+ return sd;
+}
+
+struct security_ace *security_ace_create(TALLOC_CTX *mem_ctx,
+ const char *sid_str,
+ enum security_ace_type type,
+ uint32_t access_mask,
+ uint8_t flags)
+
+{
+ struct security_ace *ace;
+ bool ok;
+
+ ace = talloc_zero(mem_ctx, struct security_ace);
+ if (ace == NULL) {
+ return NULL;
+ }
+
+ ok = dom_sid_parse(sid_str, &ace->trustee);
+ if (!ok) {
+ talloc_free(ace);
+ return NULL;
+ }
+ ace->type = type;
+ ace->access_mask = access_mask;
+ ace->flags = flags;
+
+ return ace;
+}
+
+/*******************************************************************
+ Check for MS NFS ACEs in a sd
+*******************************************************************/
+bool security_descriptor_with_ms_nfs(const struct security_descriptor *psd)
+{
+ uint32_t i;
+
+ if (psd->dacl == NULL) {
+ return false;
+ }
+
+ for (i = 0; i < psd->dacl->num_aces; i++) {
+ if (dom_sid_compare_domain(
+ &global_sid_Unix_NFS,
+ &psd->dacl->aces[i].trustee) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/libcli/security/security_descriptor.h b/libcli/security/security_descriptor.h
new file mode 100644
index 0000000..354bc17
--- /dev/null
+++ b/libcli/security/security_descriptor.h
@@ -0,0 +1,99 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Copyright (C) 2009 Jelmer Vernooij <jelmer@samba.org>
+
+ 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/>.
+*/
+
+#ifndef __SECURITY_DESCRIPTOR_H__
+#define __SECURITY_DESCRIPTOR_H__
+
+#include "librpc/gen_ndr/security.h"
+
+struct security_descriptor *security_descriptor_initialise(TALLOC_CTX *mem_ctx);
+struct security_descriptor *security_descriptor_copy(TALLOC_CTX *mem_ctx,
+ const struct security_descriptor *osd);
+NTSTATUS security_descriptor_for_client(TALLOC_CTX *mem_ctx,
+ const struct security_descriptor *ssd,
+ uint32_t sec_info,
+ uint32_t access_granted,
+ struct security_descriptor **_csd);
+NTSTATUS security_descriptor_sacl_add(struct security_descriptor *sd,
+ const struct security_ace *ace);
+NTSTATUS security_descriptor_sacl_insert(struct security_descriptor *sd,
+ const struct security_ace *ace,
+ ssize_t idx);
+NTSTATUS security_descriptor_dacl_add(struct security_descriptor *sd,
+ const struct security_ace *ace);
+NTSTATUS security_descriptor_dacl_insert(struct security_descriptor *sd,
+ const struct security_ace *ace,
+ ssize_t idx);
+NTSTATUS security_descriptor_dacl_del(struct security_descriptor *sd,
+ const struct dom_sid *trustee);
+NTSTATUS security_descriptor_sacl_del(struct security_descriptor *sd,
+ const struct dom_sid *trustee);
+NTSTATUS security_descriptor_dacl_del_ace(struct security_descriptor *sd,
+ const struct security_ace *ace);
+NTSTATUS security_descriptor_sacl_del_ace(struct security_descriptor *sd,
+ const struct security_ace *ace);
+bool security_ace_equal(const struct security_ace *ace1,
+ const struct security_ace *ace2);
+bool security_acl_equal(const struct security_acl *acl1,
+ const struct security_acl *acl2);
+bool security_descriptor_equal(const struct security_descriptor *sd1,
+ const struct security_descriptor *sd2);
+bool security_descriptor_mask_equal(const struct security_descriptor *sd1,
+ const struct security_descriptor *sd2,
+ uint32_t mask);
+struct security_descriptor *security_descriptor_dacl_create(TALLOC_CTX *mem_ctx,
+ uint16_t sd_type,
+ const char *owner_sid,
+ const char *group_sid,
+ ...);
+struct security_descriptor *security_descriptor_sacl_create(TALLOC_CTX *mem_ctx,
+ uint16_t sd_type,
+ const char *owner_sid,
+ const char *group_sid,
+ ...);
+struct security_ace *security_ace_create(TALLOC_CTX *mem_ctx,
+ const char *sid_str,
+ enum security_ace_type type,
+ uint32_t access_mask,
+ uint8_t flags);
+
+struct security_acl *security_acl_dup(TALLOC_CTX *mem_ctx,
+ const struct security_acl *oacl);
+
+struct security_acl *security_acl_concatenate(TALLOC_CTX *mem_ctx,
+ const struct security_acl *acl1,
+ const struct security_acl *acl2);
+
+uint32_t map_generic_rights_ds(uint32_t access_mask);
+
+struct security_descriptor *create_security_descriptor(TALLOC_CTX *mem_ctx,
+ struct security_descriptor *parent_sd,
+ struct security_descriptor *creator_sd,
+ bool is_container,
+ struct GUID *object_list,
+ uint32_t inherit_flags,
+ struct security_token *token,
+ struct dom_sid *default_owner, /* valid only for DS, NULL for the other RSs */
+ struct dom_sid *default_group, /* valid only for DS, NULL for the other RSs */
+ uint32_t (*generic_map)(uint32_t access_mask));
+
+bool security_descriptor_with_ms_nfs(const struct security_descriptor *psd);
+
+#endif /* __SECURITY_DESCRIPTOR_H__ */
diff --git a/libcli/security/security_token.c b/libcli/security/security_token.c
new file mode 100644
index 0000000..79de6e3
--- /dev/null
+++ b/libcli/security/security_token.c
@@ -0,0 +1,228 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ security descriptor utility functions
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Andrew Bartlett 2010
+ Copyright (C) Stefan Metzmacher 2005
+
+ 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 "replace.h"
+#include <talloc.h>
+#include "lib/util/talloc_stack.h"
+#include "lib/util/debug.h"
+#include "lib/util/fault.h"
+#include "libcli/security/security_token.h"
+#include "libcli/security/dom_sid.h"
+#include "libcli/security/privileges.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "lib/util/talloc_stack.h"
+
+/*
+ return a blank security token
+*/
+struct security_token *security_token_initialise(TALLOC_CTX *mem_ctx,
+ enum claims_evaluation_control evaluate_claims)
+{
+ struct security_token *st = talloc_zero(
+ mem_ctx, struct security_token);
+ st->evaluate_claims = evaluate_claims;
+
+ return st;
+}
+
+/****************************************************************************
+ Duplicate a SID token.
+****************************************************************************/
+
+struct security_token *security_token_duplicate(TALLOC_CTX *mem_ctx, const struct security_token *src)
+{
+ TALLOC_CTX *frame = NULL;
+ struct security_token *dst = NULL;
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+
+ if (src == NULL) {
+ return NULL;
+ }
+
+ frame = talloc_stackframe();
+
+ ndr_err = ndr_push_struct_blob(
+ &blob,
+ frame,
+ src,
+ (ndr_push_flags_fn_t)ndr_push_security_token);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DBG_ERR("Failed to duplicate security_token ndr_push_security_token failed: %s\n",
+ ndr_errstr(ndr_err));
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ dst = talloc_zero(mem_ctx, struct security_token);
+ if (dst == NULL) {
+ DBG_ERR("talloc failed\n");
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ ndr_err = ndr_pull_struct_blob(
+ &blob,
+ dst,
+ dst,
+ (ndr_pull_flags_fn_t)ndr_pull_security_token);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DBG_ERR("Failed to duplicate security_token ndr_pull_security_token "
+ "failed: %s\n",
+ ndr_errstr(ndr_err));
+ TALLOC_FREE(dst);
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ TALLOC_FREE(frame);
+ return dst;
+}
+
+/****************************************************************************
+ prints a struct security_token to debug output.
+****************************************************************************/
+void security_token_debug(int dbg_class, int dbg_lev, const struct security_token *token)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ char *sids = NULL;
+ char *privs = NULL;
+ uint32_t i;
+
+ if (!token) {
+ DEBUGC(dbg_class, dbg_lev, ("Security token: (NULL)\n"));
+ TALLOC_FREE(frame);
+ return;
+ }
+
+ sids = talloc_asprintf(frame,
+ "Security token SIDs (%" PRIu32 "):\n",
+ token->num_sids);
+ for (i = 0; i < token->num_sids; i++) {
+ struct dom_sid_buf sidbuf;
+ talloc_asprintf_addbuf(
+ &sids,
+ " SID[%3" PRIu32 "]: %s\n",
+ i,
+ dom_sid_str_buf(&token->sids[i], &sidbuf));
+ }
+
+ privs = security_token_debug_privileges(frame, token);
+
+ DEBUGC(dbg_class,
+ dbg_lev,
+ ("%s%s", sids ? sids : "(NULL)", privs ? privs : "(NULL)"));
+
+ TALLOC_FREE(frame);
+}
+
+/* These really should be cheaper... */
+
+bool security_token_is_sid(const struct security_token *token, const struct dom_sid *sid)
+{
+ bool ret;
+
+ if (token->sids == NULL) {
+ return false;
+ }
+ ret = dom_sid_equal(&token->sids[PRIMARY_USER_SID_INDEX], sid);
+ return ret;
+}
+
+bool security_token_is_system(const struct security_token *token)
+{
+ return security_token_is_sid(token, &global_sid_System);
+}
+
+bool security_token_is_anonymous(const struct security_token *token)
+{
+ return security_token_is_sid(token, &global_sid_Anonymous);
+}
+
+bool security_token_has_sid(const struct security_token *token, const struct dom_sid *sid)
+{
+ uint32_t i;
+ for (i = 0; i < token->num_sids; i++) {
+ if (dom_sid_equal(&token->sids[i], sid)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+size_t security_token_count_flag_sids(const struct security_token *token,
+ const struct dom_sid *prefix_sid,
+ size_t num_flags,
+ const struct dom_sid **_flag_sid)
+{
+ const size_t num_auths_expected = prefix_sid->num_auths + num_flags;
+ const struct dom_sid *found = NULL;
+ size_t num = 0;
+ uint32_t i;
+
+ SMB_ASSERT(num_auths_expected <= ARRAY_SIZE(prefix_sid->sub_auths));
+
+ for (i = 0; i < token->num_sids; i++) {
+ const struct dom_sid *sid = &token->sids[i];
+ int cmp;
+
+ if (sid->num_auths != num_auths_expected) {
+ continue;
+ }
+
+ cmp = dom_sid_compare_domain(sid, prefix_sid);
+ if (cmp != 0) {
+ continue;
+ }
+
+ num += 1;
+ found = sid;
+ }
+
+ if ((num == 1) && (_flag_sid != NULL)) {
+ *_flag_sid = found;
+ }
+
+ return num;
+}
+
+bool security_token_has_builtin_guests(const struct security_token *token)
+{
+ return security_token_has_sid(token, &global_sid_Builtin_Guests);
+}
+
+bool security_token_has_builtin_administrators(const struct security_token *token)
+{
+ return security_token_has_sid(token, &global_sid_Builtin_Administrators);
+}
+
+bool security_token_has_nt_authenticated_users(const struct security_token *token)
+{
+ return security_token_has_sid(token, &global_sid_Authenticated_Users);
+}
+
+bool security_token_has_enterprise_dcs(const struct security_token *token)
+{
+ return security_token_has_sid(token, &global_sid_Enterprise_DCs);
+}
diff --git a/libcli/security/security_token.h b/libcli/security/security_token.h
new file mode 100644
index 0000000..8baf4cf
--- /dev/null
+++ b/libcli/security/security_token.h
@@ -0,0 +1,74 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ security descriptor utility functions
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Andrew Bartlett 2010
+ Copyright (C) Stefan Metzmacher 2005
+
+ 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/>.
+*/
+
+#ifndef _LIBCLI_SECURITY_SECURITY_TOKEN_H_
+#define _LIBCLI_SECURITY_SECURITY_TOKEN_H_
+
+#include "replace.h"
+#include "lib/util/data_blob.h"
+#include "librpc/gen_ndr/security.h"
+
+#define PRIMARY_USER_SID_INDEX 0
+#define PRIMARY_GROUP_SID_INDEX 1
+#define PRIMARY_SIDS_COUNT 2
+#define REMAINING_SIDS_INDEX 2
+
+/*
+ return a blank security token
+*/
+struct security_token *security_token_initialise(TALLOC_CTX *mem_ctx,
+ enum claims_evaluation_control evaluate_claims);
+
+struct security_token *security_token_duplicate(TALLOC_CTX *mem_ctx, const struct security_token *src);
+
+/****************************************************************************
+ prints a struct security_token to debug output.
+****************************************************************************/
+void security_token_debug(int dbg_class, int dbg_lev, const struct security_token *token);
+
+bool security_token_is_sid(const struct security_token *token, const struct dom_sid *sid);
+
+bool security_token_is_system(const struct security_token *token);
+
+bool security_token_is_anonymous(const struct security_token *token);
+
+bool security_token_has_sid(const struct security_token *token, const struct dom_sid *sid);
+
+/*
+ * Return any of the domain sids found in the token matching "domain"
+ * in _domain_sid, makes most sense if you just found one.
+ */
+size_t security_token_count_flag_sids(const struct security_token *token,
+ const struct dom_sid *prefix_sid,
+ size_t num_flags,
+ const struct dom_sid **_flag_sid);
+
+bool security_token_has_builtin_guests(const struct security_token *token);
+
+bool security_token_has_builtin_administrators(const struct security_token *token);
+
+bool security_token_has_nt_authenticated_users(const struct security_token *token);
+
+bool security_token_has_enterprise_dcs(const struct security_token *token);
+
+#endif
diff --git a/libcli/security/session.c b/libcli/security/session.c
new file mode 100644
index 0000000..8db341d
--- /dev/null
+++ b/libcli/security/session.c
@@ -0,0 +1,74 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ session_info utility functions
+
+ Copyright (C) Andrew Bartlett 2008-2010
+
+ 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 "replace.h"
+#include "libcli/security/security.h"
+#include "libcli/util/werror.h"
+#include "librpc/gen_ndr/auth.h"
+
+enum security_user_level security_session_user_level(struct auth_session_info *session_info,
+ const struct dom_sid *domain_sid)
+{
+ struct security_token *token = NULL;
+ bool authenticated = false;
+ bool guest = false;
+
+ if (!session_info) {
+ return SECURITY_ANONYMOUS;
+ }
+ token = session_info->security_token;
+
+ if (security_token_is_system(token)) {
+ return SECURITY_SYSTEM;
+ }
+
+ if (security_token_is_anonymous(token)) {
+ return SECURITY_ANONYMOUS;
+ }
+
+ authenticated = security_token_has_nt_authenticated_users(token);
+ guest = security_token_has_builtin_guests(token);
+ if (!authenticated) {
+ if (guest) {
+ return SECURITY_GUEST;
+ }
+ return SECURITY_ANONYMOUS;
+ }
+
+ if (security_token_has_builtin_administrators(token)) {
+ return SECURITY_ADMINISTRATOR;
+ }
+
+ if (domain_sid) {
+ struct dom_sid rodc_dcs = { .num_auths = 0 };
+ sid_compose(&rodc_dcs, domain_sid, DOMAIN_RID_READONLY_DCS);
+
+ if (security_token_has_sid(token, &rodc_dcs)) {
+ return SECURITY_RO_DOMAIN_CONTROLLER;
+ }
+ }
+
+ if (security_token_has_enterprise_dcs(token)) {
+ return SECURITY_DOMAIN_CONTROLLER;
+ }
+
+ return SECURITY_USER;
+}
diff --git a/libcli/security/session.h b/libcli/security/session.h
new file mode 100644
index 0000000..31e950e
--- /dev/null
+++ b/libcli/security/session.h
@@ -0,0 +1,44 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ session_info utility functions
+
+ Copyright (C) Andrew Bartlett 2008-2010
+
+ 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/>.
+*/
+
+#ifndef _LIBCLI_SECURITY_SESSION_H_
+#define _LIBCLI_SECURITY_SESSION_H_
+
+enum security_user_level {
+ SECURITY_ANONYMOUS = 0,
+ SECURITY_GUEST = 1,
+ SECURITY_USER = 10,
+ SECURITY_RO_DOMAIN_CONTROLLER = 20,
+ SECURITY_DOMAIN_CONTROLLER = 30,
+ SECURITY_ADMINISTRATOR = 40,
+ SECURITY_SYSTEM = 50
+};
+
+struct cli_credentials;
+struct security_token;
+struct auth_user_info;
+struct auth_user_info_torture;
+struct auth_session_info;
+
+enum security_user_level security_session_user_level(struct auth_session_info *session_info,
+ const struct dom_sid *domain_sid);
+
+#endif
diff --git a/libcli/security/tests/data/conditional_aces.txt b/libcli/security/tests/data/conditional_aces.txt
new file mode 100644
index 0000000..cf7d7a9
--- /dev/null
+++ b/libcli/security/tests/data/conditional_aces.txt
@@ -0,0 +1,83 @@
+D:(XD;;CC;;;S-1-2-3;(@User.Title == @User.Title)) -> D:(XD;;CC;;;S-1-2-3;(@USER.Title == @USER.Title))
+D:(XA;;FX;;;S-1-1-0;(@User.Title == "PM")) -> D:(XA;;FX;;;WD;(@USER.Title == "PM"))
+D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GRGWGX;;;AU)(XA;;FX;;;S-1-1-0;(@User.title == "perambuator"))(A;OICI;GA;;;BA) -> D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GXGWGR;;;AU)(XA;;FX;;;WD;(@USER.title == "perambuator"))(A;OICI;GA;;;BA)
+O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/AuthenticationSilo == "siloname")) -> O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/AuthenticationSilo == "siloname"))
+D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GRGWGX;;;AU)(XA;;FX;;;S-1-1-0;(@User.Title == ""))(A;OICI;GA;;;BA) -> D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GXGWGR;;;AU)(XA;;FX;;;WD;(@USER.Title == ""))(A;OICI;GA;;;BA)
+D:(XA;;CC;;;S-1-2-3;(@User.Title != @User.Title)) -> D:(XA;;CC;;;S-1-2-3;(@USER.Title != @USER.Title))
+D:(XD;;FX;;;S-1-1-0;(@User.Title != "PM")) -> D:(XD;;FX;;;WD;(@USER.Title != "PM"))
+D:(XD;;FX;;;S-1-1-0;(@User.Project Any_of @Resource.Project)) -> D:(XD;;FX;;;WD;(@USER.Project Any_of @RESOURCE.Project))
+D:AI(XA;OICI;FA;;;WD;(OctetStringType==##1#2#3##)) -> D:AI(XA;OICI;FA;;;WD;(OctetStringType == #01020300))
+D:AI(XA;OICI;FA;;;WD;(OctetStringType==#01020300)) -> D:AI(XA;OICI;FA;;;WD;(OctetStringType == #01020300))
+D:(XA;;FR;;;S-1-1-0;(Member_of {SID(S-1-999-777-7-7), SID(BO)} && @Device.Bitlocker)) -> D:(XA;;FR;;;WD;((Member_of {SID(S-1-999-777-7-7), SID(BO)}) && (@DEVICE.Bitlocker)))
+D:(XA;;FX;;;S-1-1-0;(@User.Title=="PM" && (@User.Division=="Finance" || @User.Division =="Sales"))) -> D:(XA;;FX;;;WD;((@USER.Title == "PM") && ((@USER.Division == "Finance") || (@USER.Division == "Sales"))))
+D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GRGWGX;;;AU)(XA;;FX;;;S-1-1-0;(@User.Title == ""))(A;OICI;GA;;;BA) -> D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GXGWGR;;;AU)(XA;;FX;;;WD;(@USER.Title == ""))(A;OICI;GA;;;BA)
+D:(XA;;FX;;;S-1-1-0;(@User.Project Any_of @Resource.Project)) -> D:(XA;;FX;;;WD;(@USER.Project Any_of @RESOURCE.Project))
+D:(XA;;0x1f;;;AA;(@Device.colour == {"orange", "blue"})) -> D:(XA;;CCDCLCSWRP;;;AA;(@DEVICE.colour == {"orange", "blue"}))
+D:(XA;;0x1f;;;AA;(@Device.legs >= 1)) -> D:(XA;;CCDCLCSWRP;;;AA;(@DEVICE.legs >= 1))
+D:(XA;;0x1f;;;AA;(@Device.legs == 1)) -> D:(XA;;CCDCLCSWRP;;;AA;(@DEVICE.legs == 1))
+D:(XA;;0x1f;;;AA;(Device_Member_of{SID(BA)} && Member_of{SID(WD)})) -> D:(XA;;CCDCLCSWRP;;;AA;((Device_Member_of {SID(BA)}) && (Member_of {SID(WD)})))
+D:(XA;;0x1f;;;AA;(Device_Member_of{SID(AA)} || Member_of{SID(WD)})) -> D:(XA;;CCDCLCSWRP;;;AA;((Device_Member_of {SID(AA)}) || (Member_of {SID(WD)})))
+D:(XA;;0x1f;;;AA;(Device_Member_of{SID(BG)} || Member_of{SID(WR)})) -> D:(XA;;CCDCLCSWRP;;;AA;((Device_Member_of {SID(BG)}) || (Member_of {SID(WR)})))
+D:(XA;;0x1ff;;;S-1-222-333;(Member_of_Any{SID(S-1-222-333)})) -> D:(XA;;CCDCLCSWRPWPDTLOCR;;;S-1-222-333;(Member_of_any {SID(S-1-222-333)}))
+O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of{SID(S-1-1-0)})) -> O:WDD:(XA;;CCDCLCSWRPWPDTLOCR;;;WD;(Member_of {SID(WD)}))
+O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of SID(S-1-1-0))) -> O:WDD:(XA;;CCDCLCSWRPWPDTLOCR;;;WD;(Member_of SID(WD)))
+O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of(SID(S-1-1-0)))) -> O:WDD:(XA;;CCDCLCSWRPWPDTLOCR;;;WD;(Member_of SID(WD)))
+O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_Any SID(S-1-1-0))) -> O:WDD:(XA;;CCDCLCSWRPWPDTLOCR;;;WD;(Member_of_any SID(WD)))
+O:S-1-1-0D:(XA;;0x1;;;WD;(Member_of_Any{SID(AS),SID(WD)})) -> O:WDD:(XA;;CC;;;WD;(Member_of_any {SID(AS), SID(WD)}))
+O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-1-0), SID(S-1-222-333)})) -> O:WDD:(XA;;CCDCLCSWRPWPDTLOCR;;;WD;(Member_of_any {SID(WD), SID(S-1-222-333)}))
+O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-1-334), SID(S-1-222-333)})) -> O:WDD:(XA;;CCDCLCSWRPWPDTLOCR;;;WD;(Member_of_any {SID(S-1-1-334), SID(S-1-222-333)}))
+D:(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-222-333)})) -> D:(XA;;CCDCLCSWRPWPDTLOCR;;;WD;(Member_of_any {SID(S-1-222-333)}))
+D:(XA;;0x1f;;;AA;(Member_of{SID(S-1-77-88-99)})) -> D:(XA;;CCDCLCSWRP;;;AA;(Member_of {SID(S-1-77-88-99)}))
+D:(XA;;0x1f;;;AA;(Device_Member_of{SID(BA)})) -> D:(XA;;CCDCLCSWRP;;;AA;(Device_Member_of {SID(BA)}))
+D:(XA;;0x1f;;;AA;(!(! (Member_of{SID(AA)})))) -> D:(XA;;CCDCLCSWRP;;;AA;(!(!(Member_of {SID(AA)}))))
+D:(XA;;0x1f;;;AA;(!(!(!(!(!(! (Member_of{SID(AA)})))))))) -> D:(XA;;CCDCLCSWRP;;;AA;(!(!(!(!(!(!(Member_of {SID(AA)}))))))))
+D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))S:(RA;;;;;WD;("colour",TS,0,"blue")) -> D:(XA;;CCDCLCSWRP;;;AA;(@DEVICE.colour Contains @RESOURCE.colour))S:(RA;;;;;WD;("colour",TS,0x0,"blue"))
+D:(XA;;0x1f;;;AA;(@Device.colour == @Resource.colour))S:(RA;;;;;WD;("colour",TS,0,"blue")) -> D:(XA;;CCDCLCSWRP;;;AA;(@DEVICE.colour == @RESOURCE.colour))S:(RA;;;;;WD;("colour",TS,0x0,"blue"))
+D:(XA;;0x1f;;;AA;(@Device.colour == "blue")) -> D:(XA;;CCDCLCSWRP;;;AA;(@DEVICE.colour == "blue"))
+D:(XA;;0x1f;;;AA;(@User.colour == @Device.colour)) -> D:(XA;;CCDCLCSWRP;;;AA;(@USER.colour == @DEVICE.colour))
+D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))S:(RA;;;;;WD;("colour",TS,0,"blue", "red")) -> D:(XA;;CCDCLCSWRP;;;AA;(@DEVICE.colour Contains @RESOURCE.colour))S:(RA;;;;;WD;("colour",TS,0x0,"blue","red"))
+O:S-1-1-0D:(XA;;0x1ff;;;WD;(member_of{SID(S-1-1-0)})) -> O:WDD:(XA;;CCDCLCSWRPWPDTLOCR;;;WD;(Member_of {SID(WD)}))
+O:S-1-1-0D:(XA;;0x1ff;;;WD;(mEMBER_of{SID(S-1-1-0)})) -> O:WDD:(XA;;CCDCLCSWRPWPDTLOCR;;;WD;(Member_of {SID(WD)}))
+O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_Of{SID(S-1-1-0)})) -> O:WDD:(XA;;CCDCLCSWRPWPDTLOCR;;;WD;(Member_of {SID(WD)}))
+O:S-1-1-0D:(XA;;0x0;;;WD;(Member_Of SID(S-1-1-0))) -> O:WDD:(XA;;;;;WD;(Member_of SID(WD)))
+O:S-1-1-0D:(XA;;0;;;WD;(Member_Of SID(S-1-1-0))) -> O:WDD:(XA;;;;;WD;(Member_of SID(WD)))
+O:S-1-1-0D:(XA;;;;;WD;(Member_Of SID(S-1-1-0))) -> O:WDD:(XA;;;;;WD;(Member_of SID(WD)))
+D:(XD;;FX;;;WD;(@USER.Project Any_of "pink"))
+D:(XD;;FX;;;WD;(@USER.Project Any_of 1))
+D:(XD;;FX;;;WD;(!(@USER.Project Not_Any_of 1)))
+D:(XA;;0x1f;;;AA;(a == 1)) -> D:(XA;;CCDCLCSWRP;;;AA;(a == 1))
+D:(XA;;CC;;;AA;(@User.a == @User.b)) -> D:(XA;;CC;;;AA;(@USER.a == @USER.b))
+D:(XA;;CC;;;AA;(a == @User.a)) -> D:(XA;;CC;;;AA;(a == @USER.a))
+
+D:(XA;;FR;;;S-1-1-0;(@USER.A && @Device.B && @USER.C)) -> D:(XA;;FR;;;WD;(((@USER.A) && (@DEVICE.B)) && (@USER.C)))
+D:(XA;;FR;;;S-1-1-0;(@USER.A && @Device.B || @USER.C)) -> D:(XA;;FR;;;WD;(((@USER.A) && (@DEVICE.B)) || (@USER.C)))
+D:(XA;;FR;;;S-1-1-0;(@USER.A || @Device.B && @USER.C)) -> D:(XA;;FR;;;WD;((@USER.A) || ((@DEVICE.B) && (@USER.C))))
+D:(XA;;FR;;;S-1-1-0;(@USER.A || @Device.B || @USER.C)) -> D:(XA;;FR;;;WD;(((@USER.A) || (@DEVICE.B)) || (@USER.C)))
+
+D:(XA;;FR;;;S-1-1-0;(@Device.Bitlocker && @Device.Bitlocker)) -> D:(XA;;FR;;;WD;((@DEVICE.Bitlocker) && (@DEVICE.Bitlocker)))
+D:(XA;;FR;;;S-1-1-0;(@Device.Bitlocker || @Device.Bitlocker)) -> D:(XA;;FR;;;WD;((@DEVICE.Bitlocker) || (@DEVICE.Bitlocker)))
+D:(XA;;FR;;;S-1-1-0;(@USER.A && @Device.B)) -> D:(XA;;FR;;;WD;((@USER.A) && (@DEVICE.B)))
+D:(XA;;FR;;;S-1-1-0;(@USER.Bitlocker || @Device.Bitlocker)) -> D:(XA;;FR;;;WD;((@USER.Bitlocker) || (@DEVICE.Bitlocker)))
+D:(XA;;;;;WD;(@Device.bb == 0x7fffffffffffffff)) -> D:(XA;;;;;WD;(@DEVICE.bb == 0x7fffffffffffffff))
+D:(XA;;;;;WD;(@Device.bb == 0xffffffff)) -> D:(XA;;;;;WD;(@DEVICE.bb == 0xffffffff))
+D:(XA;;;;;WD;(@Device.bb == 0xfffffffff)) -> D:(XA;;;;;WD;(@DEVICE.bb == 0xfffffffff))
+
+
+# Member_of is supposed to be SID only
+D:(XD;;FX;;;WD;(Member_of {1, 2, 3}))(A;;CR;;;WD)
+D:(XD;;FX;;;WD;(Member_of 3))(A;;CR;;;WD)
+
+# repeated composite values
+D:(XD;;FX;;;WD;(@USER.Project Any_of 1))(A;;CR;;;WD)
+D:(XD;;FX;;;WD;(@USER.Project Any_of {1, 1}))(A;;CR;;;WD)
+D:(XD;;FX;;;WD;(@USER.Project Any_of {"foo", "FOO"}))(A;;CR;;;WD)
+D:(XD;;FX;;;WD;(@USER.Project Any_of {"foo", "foo", "FOO"}))(A;;CR;;;WD)
+
+# composite order
+D:(XD;;FX;;;WD;(@USER.Project Any_of {1, 2, 3}))(A;;CR;;;WD)
+D:(XD;;FX;;;WD;(@USER.Project Any_of {3, 2, 1}))(A;;CR;;;WD)
+D:(XD;;FX;;;WD;(@USER.Project Any_of {1, 1, 1}))(A;;CR;;;WD)
+D:(XD;;FX;;;WD;(@USER.Project Any_of {1, 2, 3, 2, 1}))(A;;CR;;;WD)
+
+D:(XA;;0x1f;;;AA;(@Device.colour == @Resource.colour))S:(RA;;;;;WD;("colour",TS,0,"red", "blue")) -> D:(XA;;CCDCLCSWRP;;;AA;(@DEVICE.colour == @RESOURCE.colour))S:(RA;;;;;WD;("colour",TS,0x0,"red","blue"))
+D:(XA;;CCDCLCSWRP;;;AA;(@RESOURCE.a == @RESOURCE.b))S:(RA;;;;;WD;("a",TS,0x0,"1","2"))(RA;;;;;WD;("b",TS,0x0,"2","1"))
diff --git a/libcli/security/tests/data/conditional_aces.txt.json b/libcli/security/tests/data/conditional_aces.txt.json
new file mode 100644
index 0000000..4c8211c
--- /dev/null
+++ b/libcli/security/tests/data/conditional_aces.txt.json
@@ -0,0 +1 @@
+{"D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GRGWGX;;;AU)(XA;;FX;;;S-1-1-0;(@User.Title == \"\"))(A;OICI;GA;;;BA)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 144, 0, 5, 0, 0, 0, 1, 3, 24, 0, 0, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 34, 2, 0, 0, 1, 3, 20, 0, 0, 0, 0, 16, 1, 1, 0, 0, 0, 0, 0, 5, 7, 0, 0, 0, 0, 3, 20, 0, 0, 0, 0, 224, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 9, 0, 48, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 16, 0, 0, 0, 0, 128, 0, 0, 0, 0, 3, 24, 0, 0, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0], "D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GRGWGX;;;AU)(XA;;FX;;;S-1-1-0;(@User.title == \"perambuator\"))(A;OICI;GA;;;BA)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 164, 0, 5, 0, 0, 0, 1, 3, 24, 0, 0, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 34, 2, 0, 0, 1, 3, 20, 0, 0, 0, 0, 16, 1, 1, 0, 0, 0, 0, 0, 5, 7, 0, 0, 0, 0, 3, 20, 0, 0, 0, 0, 224, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 9, 0, 68, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 116, 0, 105, 0, 116, 0, 108, 0, 101, 0, 16, 22, 0, 0, 0, 112, 0, 101, 0, 114, 0, 97, 0, 109, 0, 98, 0, 117, 0, 97, 0, 116, 0, 111, 0, 114, 0, 128, 0, 0, 3, 24, 0, 0, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0], "D:(XA;;0x1f;;;AA;(!(! (Member_of{SID(AA)}))))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 68, 0, 1, 0, 0, 0, 9, 0, 60, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 137, 162, 162, 0, 0, 0], "D:(XA;;0x1f;;;AA;(!(!(!(!(!(! (Member_of{SID(AA)}))))))))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 137, 162, 162, 162, 162, 162, 162, 0, 0, 0], "D:(XA;;0x1f;;;AA;(@Device.colour == \"blue\"))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 68, 0, 1, 0, 0, 0, 9, 0, 60, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 16, 8, 0, 0, 0, 98, 0, 108, 0, 117, 0, 101, 0, 128, 0], "D:(XA;;0x1f;;;AA;(@Device.colour == @Resource.colour))S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\"))": [1, 0, 20, 128, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 92, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 18, 0, 64, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 20, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 34, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 0, 0, 98, 0, 108, 0, 117, 0, 101, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 250, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 128, 0], "D:(XA;;0x1f;;;AA;(@Device.colour == {\"orange\", \"blue\"}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 92, 0, 1, 0, 0, 0, 9, 0, 84, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 80, 30, 0, 0, 0, 16, 12, 0, 0, 0, 111, 0, 114, 0, 97, 0, 110, 0, 103, 0, 101, 0, 16, 8, 0, 0, 0, 98, 0, 108, 0, 117, 0, 101, 0, 128, 0, 0, 0], "D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\"))": [1, 0, 20, 128, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 92, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 18, 0, 64, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 20, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 34, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 0, 0, 98, 0, 108, 0, 117, 0, 101, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 250, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 134, 0], "D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\", \"red\"))": [1, 0, 20, 128, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 104, 0, 0, 0, 2, 0, 84, 0, 1, 0, 0, 0, 18, 0, 76, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 24, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 38, 0, 0, 0, 48, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 0, 0, 98, 0, 108, 0, 117, 0, 101, 0, 0, 0, 114, 0, 101, 0, 100, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 250, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 134, 0], "D:(XA;;0x1f;;;AA;(@Device.legs == 1))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 9, 0, 56, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 8, 0, 0, 0, 108, 0, 101, 0, 103, 0, 115, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 128, 0, 0, 0], "D:(XA;;0x1f;;;AA;(@Device.legs >= 1))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 9, 0, 56, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 8, 0, 0, 0, 108, 0, 101, 0, 103, 0, 115, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 133, 0, 0, 0], "D:(XA;;0x1f;;;AA;(@User.colour == @Device.colour))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 249, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 128, 0], "D:(XA;;0x1f;;;AA;(Device_Member_of{SID(AA)} || Member_of{SID(WD)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 88, 0, 1, 0, 0, 0, 9, 0, 80, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 138, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 161, 0], "D:(XA;;0x1f;;;AA;(Device_Member_of{SID(BA)} && Member_of{SID(WD)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 88, 0, 1, 0, 0, 0, 9, 0, 80, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 138, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 160, 0], "D:(XA;;0x1f;;;AA;(Device_Member_of{SID(BA)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 9, 0, 56, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 138, 0], "D:(XA;;0x1f;;;AA;(Device_Member_of{SID(BG)} || Member_of{SID(WR)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 88, 0, 1, 0, 0, 0, 9, 0, 80, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 34, 2, 0, 0, 138, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 33, 0, 0, 0, 137, 161, 0], "D:(XA;;0x1f;;;AA;(Member_of{SID(S-1-77-88-99)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 9, 0, 56, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 77, 88, 0, 0, 0, 99, 0, 0, 0, 137, 0], "D:(XA;;0x1f;;;AA;(a == 1))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 248, 2, 0, 0, 0, 97, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 128, 0], "D:(XA;;0x1ff;;;S-1-222-333;(Member_of_Any{SID(S-1-222-333)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 222, 77, 1, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 222, 77, 1, 0, 0, 139, 0], "D:(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-222-333)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 222, 77, 1, 0, 0, 139, 0], "D:(XA;;;;;WD;(@Device.bb == 0x7fffffffffffffff))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 251, 4, 0, 0, 0, 98, 0, 98, 0, 4, 255, 255, 255, 255, 255, 255, 255, 127, 3, 3, 128, 0, 0, 0], "D:(XA;;;;;WD;(@Device.bb == 0xffffffff))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 251, 4, 0, 0, 0, 98, 0, 98, 0, 4, 255, 255, 255, 255, 0, 0, 0, 0, 3, 3, 128, 0, 0, 0], "D:(XA;;;;;WD;(@Device.bb == 0xfffffffff))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 251, 4, 0, 0, 0, 98, 0, 98, 0, 4, 255, 255, 255, 255, 15, 0, 0, 0, 3, 3, 128, 0, 0, 0], "D:(XA;;CC;;;AA;(@User.a == @User.b))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 1, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 97, 0, 249, 2, 0, 0, 0, 98, 0, 128, 0], "D:(XA;;CC;;;AA;(a == @User.a))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 1, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 248, 2, 0, 0, 0, 97, 0, 249, 2, 0, 0, 0, 97, 0, 128, 0], "D:(XA;;CC;;;S-1-2-3;(@User.Title != @User.Title))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 9, 0, 56, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 129, 0], "D:(XA;;FR;;;S-1-1-0;(@Device.Bitlocker && @Device.Bitlocker))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 80, 0, 1, 0, 0, 0, 9, 0, 72, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 160, 0], "D:(XA;;FR;;;S-1-1-0;(@Device.Bitlocker || @Device.Bitlocker))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 80, 0, 1, 0, 0, 0, 9, 0, 72, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 161, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.A && @Device.B && @USER.C))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 65, 0, 251, 2, 0, 0, 0, 66, 0, 160, 249, 2, 0, 0, 0, 67, 0, 160, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.A && @Device.B || @USER.C))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 65, 0, 251, 2, 0, 0, 0, 66, 0, 160, 249, 2, 0, 0, 0, 67, 0, 161, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.A && @Device.B))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 48, 0, 1, 0, 0, 0, 9, 0, 40, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 65, 0, 251, 2, 0, 0, 0, 66, 0, 160, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.A || @Device.B && @USER.C))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 65, 0, 251, 2, 0, 0, 0, 66, 0, 249, 2, 0, 0, 0, 67, 0, 160, 161, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.A || @Device.B || @USER.C))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 65, 0, 251, 2, 0, 0, 0, 66, 0, 161, 249, 2, 0, 0, 0, 67, 0, 161, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.Bitlocker || @Device.Bitlocker))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 80, 0, 1, 0, 0, 0, 9, 0, 72, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 161, 0], "D:(XA;;FR;;;S-1-1-0;(Member_of {SID(S-1-999-777-7-7), SID(BO)} && @Device.Bitlocker))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 108, 0, 1, 0, 0, 0, 9, 0, 100, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 46, 0, 0, 0, 81, 20, 0, 0, 0, 1, 3, 0, 0, 0, 0, 3, 231, 9, 3, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 39, 2, 0, 0, 137, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 160], "D:(XA;;FX;;;S-1-1-0;(@User.Project Any_of @Resource.Project))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 250, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 136, 0], "D:(XA;;FX;;;S-1-1-0;(@User.Title == \"PM\"))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 60, 0, 1, 0, 0, 0, 9, 0, 52, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 16, 4, 0, 0, 0, 80, 0, 77, 0, 128, 0, 0, 0], "D:(XA;;FX;;;S-1-1-0;(@User.Title==\"PM\" && (@User.Division==\"Finance\" || @User.Division ==\"Sales\")))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 140, 0, 1, 0, 0, 0, 9, 0, 132, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 16, 4, 0, 0, 0, 80, 0, 77, 0, 128, 249, 16, 0, 0, 0, 68, 0, 105, 0, 118, 0, 105, 0, 115, 0, 105, 0, 111, 0, 110, 0, 16, 14, 0, 0, 0, 70, 0, 105, 0, 110, 0, 97, 0, 110, 0, 99, 0, 101, 0, 128, 249, 16, 0, 0, 0, 68, 0, 105, 0, 118, 0, 105, 0, 115, 0, 105, 0, 111, 0, 110, 0, 16, 10, 0, 0, 0, 83, 0, 97, 0, 108, 0, 101, 0, 115, 0, 128, 161, 160, 0, 0, 0], "D:(XD;;CC;;;S-1-2-3;(@User.Title == @User.Title))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 10, 0, 56, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 128, 0], "D:(XD;;FX;;;S-1-1-0;(@User.Project Any_of @Resource.Project))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 10, 0, 64, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 250, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 136, 0], "D:(XD;;FX;;;S-1-1-0;(@User.Title != \"PM\"))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 60, 0, 1, 0, 0, 0, 10, 0, 52, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 16, 4, 0, 0, 0, 80, 0, 77, 0, 129, 0, 0, 0], "D:(XD;;FX;;;WD;(!(@USER.Project Not_Any_of 1)))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 10, 0, 56, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 143, 162], "D:(XD;;FX;;;WD;(@USER.Project Any_of \"pink\"))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 68, 0, 1, 0, 0, 0, 10, 0, 60, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 16, 8, 0, 0, 0, 112, 0, 105, 0, 110, 0, 107, 0, 136, 0, 0, 0], "D:(XD;;FX;;;WD;(@USER.Project Any_of 1))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 10, 0, 56, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 136, 0], "D:AI(XA;OICI;FA;;;WD;(OctetStringType==##1#2#3##))": [1, 0, 4, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 80, 0, 1, 0, 0, 0, 9, 3, 72, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 248, 30, 0, 0, 0, 79, 0, 99, 0, 116, 0, 101, 0, 116, 0, 83, 0, 116, 0, 114, 0, 105, 0, 110, 0, 103, 0, 84, 0, 121, 0, 112, 0, 101, 0, 24, 4, 0, 0, 0, 1, 2, 3, 0, 128, 0, 0, 0], "D:AI(XA;OICI;FA;;;WD;(OctetStringType==#01020300))": [1, 0, 4, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 80, 0, 1, 0, 0, 0, 9, 3, 72, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 248, 30, 0, 0, 0, 79, 0, 99, 0, 116, 0, 101, 0, 116, 0, 83, 0, 116, 0, 114, 0, 105, 0, 110, 0, 103, 0, 84, 0, 121, 0, 112, 0, 101, 0, 24, 4, 0, 0, 0, 1, 2, 3, 0, 128, 0, 0, 0], "O:S-1-1-0D:(XA;;0;;;WD;(Member_Of SID(S-1-1-0)))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x0;;;WD;(Member_Of SID(S-1-1-0)))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1;;;WD;(Member_of_Any{SID(AS),SID(WD)}))": [1, 0, 4, 128, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 34, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 18, 1, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 139, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_Of{SID(S-1-1-0)}))": [1, 0, 4, 128, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of SID(S-1-1-0)))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of(SID(S-1-1-0))))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_Any SID(S-1-1-0)))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 139, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-1-0), SID(S-1-222-333)}))": [1, 0, 4, 128, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 34, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 222, 77, 1, 0, 0, 139, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-1-334), SID(S-1-222-333)}))": [1, 0, 4, 128, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 34, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 78, 1, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 222, 77, 1, 0, 0, 139, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of{SID(S-1-1-0)}))": [1, 0, 4, 128, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(mEMBER_of{SID(S-1-1-0)}))": [1, 0, 4, 128, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(member_of{SID(S-1-1-0)}))": [1, 0, 4, 128, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;;;;WD;(Member_Of SID(S-1-1-0)))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/AuthenticationSilo == \"siloname\"))": [1, 0, 4, 128, 136, 0, 0, 0, 148, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 116, 0, 1, 0, 0, 0, 9, 3, 108, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 54, 0, 0, 0, 97, 0, 100, 0, 58, 0, 47, 0, 47, 0, 101, 0, 120, 0, 116, 0, 47, 0, 65, 0, 117, 0, 116, 0, 104, 0, 101, 0, 110, 0, 116, 0, 105, 0, 99, 0, 97, 0, 116, 0, 105, 0, 111, 0, 110, 0, 83, 0, 105, 0, 108, 0, 111, 0, 16, 16, 0, 0, 0, 115, 0, 105, 0, 108, 0, 111, 0, 110, 0, 97, 0, 109, 0, 101, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0]} \ No newline at end of file
diff --git a/libcli/security/tests/data/conditional_aces_case_insensitive.txt b/libcli/security/tests/data/conditional_aces_case_insensitive.txt
new file mode 100644
index 0000000..ee2500d
--- /dev/null
+++ b/libcli/security/tests/data/conditional_aces_case_insensitive.txt
@@ -0,0 +1 @@
+D:AI(XA;OICI;FA;;;WD;(OctetStringType==#abcdef)) -> D:AI(XA;OICI;FA;;;WD;(OctetStringType == #abcdef))
diff --git a/libcli/security/tests/data/conditional_aces_should_fail.txt b/libcli/security/tests/data/conditional_aces_should_fail.txt
new file mode 100644
index 0000000..23eadcf
--- /dev/null
+++ b/libcli/security/tests/data/conditional_aces_should_fail.txt
@@ -0,0 +1,14 @@
+# Lines starting with # are ignored.
+# These SDDL strings are expected to fail.
+D:(XA;;FR;;;S-1-1-0; (Member_of {SID(ernie), SID(BO)} && @Device.Bitlocker)) -> D:(XA;;FR;;;S-1-1-0; (Member_of {SID(ernie), SID(BO)} && @Device.Bitlocker))
+D:(XA;;0x1f;;;AA;(!!! !!! !!! Member_of{SID(BA)})) -> D:(XA;;0x1f;;;AA;(!!! !!! !!! Member_of{SID(BA)}))
+D:(XA;;0x1f;;;AA;(!!! !!! !!! Not_Member_of{SID(AA)})) -> D:(XA;;0x1f;;;AA;(!!! !!! !!! Not_Member_of{SID(AA)}))
+O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_AnySID(S-1-1-0))) -> O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_AnySID(S-1-1-0)))
+D:(XA;;CC;;;S-1-2-3;(@User.Title == !(@User.Title))) -> x
+D:(XA;;0x1f;;;AA;(! Member_of{SID(BA)})) -> x
+# local attributes on the RHS fail (ok on the LHS)
+D:(XA;;0x1f;;;AA;(a == a))
+D:(XA;;;;;WD;(@Device.bb == 055555624677746777766777767))
+D:(XA;;;;;WD;(@Device.bb == 0x624677746777766777767))
+D:(XA;;;;;WD;(@Device.bb == 624677746777766777767))
+D:(XA;;;;;WD;(@Device.bb == 0x10000000000000000))
diff --git a/libcli/security/tests/data/conditional_aces_windows_only.txt b/libcli/security/tests/data/conditional_aces_windows_only.txt
new file mode 100644
index 0000000..182d412
--- /dev/null
+++ b/libcli/security/tests/data/conditional_aces_windows_only.txt
@@ -0,0 +1,14 @@
+# Windows is far less fussy about case in general SDDL
+O:S-1-1-0D:(xd;;;;;WD;(Member_Of SID(S-1-1-0))) -> O:WDD:(XD;;;;;WD;(Member_of SID(WD)))
+O:s-1-1-0D:(xa;;;;;wd;(Member_Of SID(S-1-1-0))) -> O:WDD:(XA;;;;;WD;(Member_of SID(WD)))
+O:s-1-1-0D:(xa;;;;;wd;(member_of sid(s-1-1-0))) -> O:WDD:(XA;;;;;WD;(Member_of SID(WD)))
+O:s-1-1-0D:(xa;;;;;wd;(member_of(sid(s-1-1-0)))) -> O:WDD:(XA;;;;;WD;(Member_of SID(WD)))
+O:s-1-1-0D:(xa;;;;;wd;(member_of((sid(s-1-1-0))))) -> O:WDD:(XA;;;;;WD;(Member_of SID(WD)))
+# spaces in general SDDL
+D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A; OICI; GRGWGX;;;AU)(XA;;FX;;;S-1-1-0;(@User.TEETH == "5"))(A;OICI;GA;;;BA) -> D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GXGWGR;;;AU)(XA;;FX;;;WD;(@USER.TEETH == "5"))(A;OICI;GA;;;BA)
+D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A; OICI; GRGWGX;;;AU)(XA;;FX;;;S-1-1-0;(@User.title == "perambuator"))(A;OICI;GA;;;BA) -> D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GXGWGR;;;AU)(XA;;FX;;;WD;(@USER.title == "perambuator"))(A;OICI;GA;;;BA)
+D:(XA;;FR;;;S-1-1-0; (Member_of {SID(S-1-1-0), SID(BO)} && @Device.Bitlocker)) -> D:(XA;;FR;;;WD;((Member_of {SID(WD), SID(BO)}) && (@DEVICE.Bitlocker)))
+D:(XD;;FX;;;S-1-1-0; (@User.Project Any_of @Resource.Project)) -> D:(XD;;FX;;;WD;(@USER.Project Any_of @RESOURCE.Project))
+# note the odd number of characters in this octet string; implies a leading '0'
+D:AI(XA;OICI;FA;;;WD;(OctetStringType==#1#2#3##)) -> D:AI(XA;OICI;FA;;;WD;(OctetStringType == #01020300))
+D:(XA;;;;;WD;(@Device.bb == 0xffffffffffffffff)) -> D:(XA;;;;;WD;(@DEVICE.bb == 0xffffffffffffffff))
diff --git a/libcli/security/tests/data/export-sddl-fuzz-seeds-as-json b/libcli/security/tests/data/export-sddl-fuzz-seeds-as-json
new file mode 100755
index 0000000..cbff661
--- /dev/null
+++ b/libcli/security/tests/data/export-sddl-fuzz-seeds-as-json
@@ -0,0 +1,49 @@
+#!/usr/bin/python3
+"""USAGE: $ ./export-sddl-fuzz-seeds-as-json DIR [DIR[...]] > x.json
+
+Some of our fuzzers generate SDDL strings with trailing garbage.
+
+This script converts them into the JSON format used by
+windows-sddl-tests.py, though it doesn't parse the SDDL, mapping all
+strings to an empty list. The idea is you can feed this through
+windows-sddl-tests.py or something else to get the correct bytes.
+
+Valid and invalid strings are treated alike, so long as they are
+utf-8. The JSON is un-indented, but structurally equivalent to this:
+
+{
+ "D:P" : [],
+ "yertle" : [],
+ "ł\n¼" : [],
+}
+"""
+from pathlib import Path
+import sys
+import json
+
+
+def main():
+ if {'-h', '--help'}.intersection(sys.argv) or len(sys.argv) < 2:
+ print(__doc__)
+ sys.exit(len(sys.argv) < 2)
+
+ bytes_json = {}
+ for arg in sys.argv[1:]:
+ d = Path(arg)
+ for fn in d.iterdir():
+ with fn.open("rb") as f:
+ b = f.read()
+ # the SDDL string is the nul-terminated portion.
+ if 0 in b:
+ b = b[:b.index(0)]
+ try:
+ s = b.decode()
+ except UnicodeDecodeError:
+ continue
+ bytes_json[s] = []
+
+ out = json.dumps(bytes_json)
+ print(out)
+
+
+main()
diff --git a/libcli/security/tests/data/extract-sddl-seeds b/libcli/security/tests/data/extract-sddl-seeds
new file mode 100755
index 0000000..27ca407
--- /dev/null
+++ b/libcli/security/tests/data/extract-sddl-seeds
@@ -0,0 +1,72 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) Catalyst IT Ltd. 2023
+#
+# 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/>.
+#
+"""USAGE: extract-sddl-seeds SRCDIR SDDLDIR
+
+SRCDIR should have fuzz_security_token_vs_descriptor seeds.
+
+SDDLDIR will end up with SDDL strings representing the security
+descriptors in the seeds, along with 4 trailing bytes representing an
+access mask. This is the format used by the SDDL fuzzers.
+"""
+
+
+import sys
+sys.path.insert(0, "bin/python")
+
+from pathlib import Path
+from hashlib import md5
+from samba.ndr import ndr_unpack, ndr_pack
+from samba.dcerpc.security import token_descriptor_fuzzing_pair
+
+
+def usage(ret):
+ print(__doc__)
+ exit(ret)
+
+
+def main():
+ if {'-h', '--help'}.intersection(sys.argv):
+ usage(0)
+ if len(sys.argv) != 3:
+ usage(1)
+
+ src, dest = sys.argv[1:]
+ sp = Path(src)
+ dp = Path(dest)
+
+ raw_strings = set()
+ sddl_strings = set()
+
+ for filename in sp.iterdir():
+ with open(filename, 'rb') as f:
+ raw_strings.add(f.read())
+
+ for s in raw_strings:
+ pair = ndr_unpack(s)
+ sd = pair.sd.as_sddl()
+ mask = pair.access_desired
+ b = sd.encode() + mask.to_bytes(4, 'little')
+ sddl_strings.add(b)
+
+ for s in sddl_strings:
+ name = md5(s).hexdigest()
+ with open(dp / name, "wb") as f:
+ f.write(s)
+
+
+main()
diff --git a/libcli/security/tests/data/ndr_dumps/fileb5iJt4 b/libcli/security/tests/data/ndr_dumps/fileb5iJt4
new file mode 100644
index 0000000..c0de4da
--- /dev/null
+++ b/libcli/security/tests/data/ndr_dumps/fileb5iJt4
Binary files differ
diff --git a/libcli/security/tests/data/ndr_dumps/fileb8cNVS b/libcli/security/tests/data/ndr_dumps/fileb8cNVS
new file mode 100644
index 0000000..bee598e
--- /dev/null
+++ b/libcli/security/tests/data/ndr_dumps/fileb8cNVS
Binary files differ
diff --git a/libcli/security/tests/data/ndr_dumps/filebI7h5H b/libcli/security/tests/data/ndr_dumps/filebI7h5H
new file mode 100644
index 0000000..c98fe38
--- /dev/null
+++ b/libcli/security/tests/data/ndr_dumps/filebI7h5H
Binary files differ
diff --git a/libcli/security/tests/data/ndr_dumps/filebNdBgt b/libcli/security/tests/data/ndr_dumps/filebNdBgt
new file mode 100644
index 0000000..62e37ae
--- /dev/null
+++ b/libcli/security/tests/data/ndr_dumps/filebNdBgt
Binary files differ
diff --git a/libcli/security/tests/data/ndr_dumps/filebOjK4H b/libcli/security/tests/data/ndr_dumps/filebOjK4H
new file mode 100644
index 0000000..9a040c1
--- /dev/null
+++ b/libcli/security/tests/data/ndr_dumps/filebOjK4H
Binary files differ
diff --git a/libcli/security/tests/data/ndr_dumps/filebzCPTH b/libcli/security/tests/data/ndr_dumps/filebzCPTH
new file mode 100644
index 0000000..ba52884
--- /dev/null
+++ b/libcli/security/tests/data/ndr_dumps/filebzCPTH
Binary files differ
diff --git a/libcli/security/tests/data/oversize-acls.json b/libcli/security/tests/data/oversize-acls.json
new file mode 100644
index 0000000..a4559f3
--- /dev/null
+++ b/libcli/security/tests/data/oversize-acls.json
@@ -0,0 +1,20 @@
+{
+ "D:(A;OICI;FA;;;S-1-5-21-1927343755-967950539-965328874-512)(A;OICI;FA;;;S-1-5-21-1927343755-967950539-965328874-519)(A;;FA;;;BA)(A;OICIIO;FA;;;CO)(A;OICI;FA;;;SY)(A;OICI;0x1200a9;;;AU)(A;OICI;;;;AU)(A;OICI;0x1200a9;;;ED)":
+ [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 4, 0, 208, 0, 8, 0, 0, 0, 0, 3, 36, 0, 255, 1, 31, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 139, 238, 224, 114, 203, 192, 177, 57, 234, 191, 137, 57, 0, 2, 0, 0, 0, 3, 36, 0, 255, 1, 31, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 139, 238, 224, 114, 203, 192, 177, 57, 234, 191, 137, 57, 7, 2, 0, 0, 0, 0, 24, 0, 255, 1, 31, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 11, 20, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 3, 20, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0, 0, 3, 20, 0, 169, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 0, 3, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 0, 3, 20, 0, 169, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 5, 9, 0, 0, 0, 0, 0, 0, 0],
+ "D:(A;OICI;FA;;;S-1-5-21-3372605546-132586199-2553092274-512)(A;OICI;FA;;;S-1-5-21-3372605546-132586199-2553092274-519)(A;;FA;;;BA)(A;OICIIO;FA;;;CO)(A;OICI;FA;;;SY)(A;OICI;0x1200a9;;;AU)(A;OICI;;;;AU)(A;OICI;0x1200a9;;;ED)":
+ [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 4, 0, 208, 0, 8, 0, 0, 0, 0, 3, 36, 0, 255, 1, 31, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 106, 224, 5, 201, 215, 26, 231, 7, 178, 24, 45, 152, 0, 2, 0, 0, 0, 3, 36, 0, 255, 1, 31, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 106, 224, 5, 201, 215, 26, 231, 7, 178, 24, 45, 152, 7, 2, 0, 0, 0, 0, 24, 0, 255, 1, 31, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 11, 20, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 3, 20, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0, 0, 3, 20, 0, 169, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 0, 3, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 0, 3, 20, 0, 169, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 5, 9, 0, 0, 0, 0, 0, 0, 0],
+ "D:(A;OICI;FA;;;S-1-5-21-446349270-2432516025-2131592620-512)(A;OICI;FA;;;S-1-5-21-446349270-2432516025-2131592620-519)(A;;FA;;;BA)(A;OICIIO;FA;;;CO)(A;OICI;FA;;;SY)(A;OICI;0x1200a9;;;AU)(A;OICI;;;;AU)(A;OICI;0x1200a9;;;ED)":
+ [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 4, 0, 208, 0, 8, 0, 0, 0, 0, 3, 36, 0, 255, 1, 31, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 214, 191, 154, 26, 185, 63, 253, 144, 172, 133, 13, 127, 0, 2, 0, 0, 0, 3, 36, 0, 255, 1, 31, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 214, 191, 154, 26, 185, 63, 253, 144, 172, 133, 13, 127, 7, 2, 0, 0, 0, 0, 24, 0, 255, 1, 31, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 11, 20, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 3, 20, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0, 0, 3, 20, 0, 169, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 0, 3, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 0, 3, 20, 0, 169, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 5, 9, 0, 0, 0, 0, 0, 0, 0],
+ "D:(A;OICI;FA;;;S-1-5-21-926620776-2075325327-1127912823-512)(A;OICI;FA;;;S-1-5-21-926620776-2075325327-1127912823-519)(A;;FA;;;BA)(A;OICIIO;FA;;;CO)(A;OICI;FA;;;SY)(A;OICI;0x1200a9;;;AU)(A;OICI;;;;AU)(A;OICI;0x1200a9;;;ED)":
+ [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 4, 0, 208, 0, 8, 0, 0, 0, 0, 3, 36, 0, 255, 1, 31, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 104, 28, 59, 55, 143, 243, 178, 123, 119, 149, 58, 67, 0, 2, 0, 0, 0, 3, 36, 0, 255, 1, 31, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 104, 28, 59, 55, 143, 243, 178, 123, 119, 149, 58, 67, 7, 2, 0, 0, 0, 0, 24, 0, 255, 1, 31, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 11, 20, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 3, 20, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0, 0, 3, 20, 0, 169, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 0, 3, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 0, 3, 20, 0, 169, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 5, 9, 0, 0, 0, 0, 0, 0, 0],
+ "D:P(D;;;;;MP)(D;;;;;MP)":
+ [1, 0, 4, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 4, 0, 56, 0, 2, 0, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ "D:P(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)":
+ [1, 0, 4, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 4, 0, 80, 0, 3, 0, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ "D:P(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)":
+ [1, 0, 4, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 4, 0, 104, 0, 4, 0, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ "D:P(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)":
+ [1, 0, 4, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 4, 0, 176, 0, 7, 0, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ "D:P(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)":
+ [1, 0, 4, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 4, 0, 16, 1, 11, 0, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+}
diff --git a/libcli/security/tests/data/registry-object-rights.json b/libcli/security/tests/data/registry-object-rights.json
new file mode 100644
index 0000000..97a64ea
--- /dev/null
+++ b/libcli/security/tests/data/registry-object-rights.json
@@ -0,0 +1 @@
+{"D:(A;;CCLCRPRC;;;WD)(A;;KA;;;BA)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 2, 0, 0, 0, 0, 0, 20, 0, 21, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0], "D:(A;;CCRPWPRC;;;WD)(A;;KA;;;BA)(A;;KA;;;AO)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 76, 0, 3, 0, 0, 0, 0, 0, 20, 0, 49, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 36, 2, 0, 0], "D:(A;;CCRPWPRC;;;WD)(A;;KA;;;BA)(A;;KA;;;AO)(A;;KA;;;S-1-5-21-1069531106-184984463-4116541046-512)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 112, 0, 4, 0, 0, 0, 0, 0, 20, 0, 49, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 36, 2, 0, 0, 0, 0, 36, 0, 63, 0, 15, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 226, 191, 191, 63, 143, 163, 6, 11, 118, 110, 93, 245, 0, 2, 0, 0], "D:(A;;CCRPWPRC;;;WD)(A;;KA;;;BA)(A;;KA;;;AO)(A;;KA;;;S-1-5-21-1378461354-3939386343-493233828-512)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 112, 0, 4, 0, 0, 0, 0, 0, 20, 0, 49, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 36, 2, 0, 0, 0, 0, 36, 0, 63, 0, 15, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 170, 166, 41, 82, 231, 67, 206, 234, 164, 38, 102, 29, 0, 2, 0, 0], "D:(A;;CCRPWPRC;;;WD)(A;;KA;;;BA)(A;;KA;;;AO)(A;;KA;;;S-1-5-21-3587273675-3237974979-2131186439-512)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 112, 0, 4, 0, 0, 0, 0, 0, 20, 0, 49, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 36, 2, 0, 0, 0, 0, 36, 0, 63, 0, 15, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 203, 115, 209, 213, 195, 147, 255, 192, 7, 83, 7, 127, 0, 2, 0, 0], "D:(A;;CCRPWPRC;;;WD)(A;;KA;;;BA)(A;;KA;;;AO)(A;;KA;;;S-1-5-21-3984653172-1380167674-707033525-512)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 112, 0, 4, 0, 0, 0, 0, 0, 20, 0, 49, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 36, 2, 0, 0, 0, 0, 36, 0, 63, 0, 15, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 116, 251, 128, 237, 250, 175, 67, 82, 181, 121, 36, 42, 0, 2, 0, 0], "D:(A;;CCRPWPRC;;;WD)(A;;KA;;;BA)(A;;KA;;;AO)(A;;KA;;;S-1-5-21-4154349010-984067676-209295477-512)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 112, 0, 4, 0, 0, 0, 0, 0, 20, 0, 49, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 36, 2, 0, 0, 0, 0, 36, 0, 63, 0, 15, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 210, 85, 158, 247, 92, 174, 167, 58, 117, 152, 121, 12, 0, 2, 0, 0], "D:(A;;CCRPWPRC;;;WD)(A;;KA;;;BA)(A;;KA;;;AO)(A;;KA;;;S-1-5-21-536441700-3718478525-2547843259-512)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 112, 0, 4, 0, 0, 0, 0, 0, 20, 0, 49, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 36, 2, 0, 0, 0, 0, 36, 0, 63, 0, 15, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 100, 115, 249, 31, 189, 122, 163, 221, 187, 0, 221, 151, 0, 2, 0, 0], "O:BAG:SYD:(A;;KR;;;WD)(A;;KA;;;BA)(A;;KA;;;SY)": [1, 0, 4, 128, 92, 0, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 3, 0, 0, 0, 0, 0, 20, 0, 25, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 0, 20, 0, 63, 0, 15, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0], "O:S-1-5-21-3984653172-1380167674-707033525-1000G:S-1-22-2-50133D:(A;;0x1f019f;;;S-1-5-21-3984653172-1380167674-707033525-1000)(A;;0x1f019f;;;S-1-22-2-50133)(A;;0x1f019f;;;WD)(A;;KA;;;SY)": [1, 0, 4, 128, 128, 0, 0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 108, 0, 4, 0, 0, 0, 0, 0, 36, 0, 159, 1, 31, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 116, 251, 128, 237, 250, 175, 67, 82, 181, 121, 36, 42, 232, 3, 0, 0, 0, 0, 24, 0, 159, 1, 31, 0, 1, 2, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 213, 195, 0, 0, 0, 0, 20, 0, 159, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 20, 0, 63, 0, 15, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 116, 251, 128, 237, 250, 175, 67, 82, 181, 121, 36, 42, 232, 3, 0, 0, 1, 2, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 213, 195, 0, 0], "O:S-1-5-21-536441700-3718478525-2547843259-1000G:S-1-22-2-50133D:(A;;0x1f019f;;;S-1-5-21-536441700-3718478525-2547843259-1000)(A;;0x1f019f;;;S-1-22-2-50133)(A;;0x1f019f;;;WD)(A;;KA;;;SY)": [1, 0, 4, 128, 128, 0, 0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 108, 0, 4, 0, 0, 0, 0, 0, 36, 0, 159, 1, 31, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 100, 115, 249, 31, 189, 122, 163, 221, 187, 0, 221, 151, 232, 3, 0, 0, 0, 0, 24, 0, 159, 1, 31, 0, 1, 2, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 213, 195, 0, 0, 0, 0, 20, 0, 159, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 20, 0, 63, 0, 15, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 100, 115, 249, 31, 189, 122, 163, 221, 187, 0, 221, 151, 232, 3, 0, 0, 1, 2, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 213, 195, 0, 0]} \ No newline at end of file
diff --git a/libcli/security/tests/data/short-conditional-and-resource-aces-successes.json.gz b/libcli/security/tests/data/short-conditional-and-resource-aces-successes.json.gz
new file mode 100644
index 0000000..e7f8024
--- /dev/null
+++ b/libcli/security/tests/data/short-conditional-and-resource-aces-successes.json.gz
Binary files differ
diff --git a/libcli/security/tests/data/short-conditional-and-resource-aces-tx-int.json.gz b/libcli/security/tests/data/short-conditional-and-resource-aces-tx-int.json.gz
new file mode 100644
index 0000000..e1b6157
--- /dev/null
+++ b/libcli/security/tests/data/short-conditional-and-resource-aces-tx-int.json.gz
Binary files differ
diff --git a/libcli/security/tests/data/short-ordinary-acls-v2.json.gz b/libcli/security/tests/data/short-ordinary-acls-v2.json.gz
new file mode 100644
index 0000000..1f4ef20
--- /dev/null
+++ b/libcli/security/tests/data/short-ordinary-acls-v2.json.gz
Binary files differ
diff --git a/libcli/security/tests/data/short-ordinary-acls.json.gz b/libcli/security/tests/data/short-ordinary-acls.json.gz
new file mode 100644
index 0000000..8554b7c
--- /dev/null
+++ b/libcli/security/tests/data/short-ordinary-acls.json.gz
Binary files differ
diff --git a/libcli/security/tests/test_claim_conversion.c b/libcli/security/tests/test_claim_conversion.c
new file mode 100644
index 0000000..aeb172f
--- /dev/null
+++ b/libcli/security/tests/test_claim_conversion.c
@@ -0,0 +1,171 @@
+/*
+ * Unit tests for conditional ACE SDDL.
+ *
+ * Copyright (C) Catalyst.NET Ltd 2023
+ *
+ * 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 <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include "cmocka.h"
+
+#include "lib/util/attr.h"
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/security.h"
+#include "libcli/security/conditional_ace.h"
+#include "librpc/gen_ndr/conditional_ace.h"
+#include "libcli/security/claims-conversions.h"
+#include "librpc/gen_ndr/ndr_claims.h"
+
+#define debug_message(...) print_message(__VA_ARGS__)
+
+#define debug_fail(x, ...) print_message("\033[1;31m" x "\033[0m", __VA_ARGS__)
+#define debug_ok(x, ...) print_message("\033[1;32m" x "\033[0m", __VA_ARGS__)
+
+#define assert_ntstatus_equal(got, expected, comment) \
+ do { NTSTATUS __got = got, __expected = expected; \
+ if (!NT_STATUS_EQUAL(__got, __expected)) { \
+ print_message(": "#got" was %s, expected %s: %s", \
+ nt_errstr(__got), \
+ nt_errstr(__expected), comment); \
+ fail(); \
+ } \
+ } while(0)
+
+
+
+static DATA_BLOB datablob_from_file(TALLOC_CTX *mem_ctx,
+ const char *filename)
+{
+ DATA_BLOB b = {0};
+ FILE *fh = fopen(filename, "rb");
+ int ret;
+ struct stat s;
+ size_t len;
+ if (fh == NULL) {
+ debug_message("could not open '%s'\n", filename);
+ return b;
+ }
+ ret = fstat(fileno(fh), &s);
+ if (ret != 0) {
+ fclose(fh);
+ return b;
+ }
+ b.data = talloc_array(mem_ctx, uint8_t, s.st_size);
+ if (b.data == NULL) {
+ fclose(fh);
+ return b;
+ }
+ len = fread(b.data, 1, s.st_size, fh);
+ if (ferror(fh) || len != s.st_size) {
+ TALLOC_FREE(b.data);
+ } else {
+ b.length = len;
+ }
+ fclose(fh);
+ return b;
+}
+
+
+static void _test_one_ndr_dump(void **state, const char *name)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ struct CLAIMS_SET claims_set;
+ DATA_BLOB blob;
+ NTSTATUS status;
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *out_claims = NULL;
+ uint32_t out_n_claims = 0;
+ enum ndr_err_code ndr_err;
+ char filename[200];
+ snprintf(filename, sizeof(filename),
+ "libcli/security/tests/data/ndr_dumps/%s", name);
+
+ blob = datablob_from_file(tmp_ctx, filename);
+ ndr_err = ndr_pull_struct_blob(
+ &blob, tmp_ctx, &claims_set,
+ (ndr_pull_flags_fn_t)ndr_pull_CLAIMS_SET);
+ assert_int_equal(ndr_err, NDR_ERR_SUCCESS);
+
+ status = token_claims_to_claims_v1(tmp_ctx,
+ &claims_set,
+ &out_claims,
+ &out_n_claims);
+ assert_ntstatus_equal(status, NT_STATUS_OK, "sigh\n");
+}
+
+
+
+static void test_fileb5iJt4(void **state)
+{
+ _test_one_ndr_dump(state, "fileb5iJt4");
+}
+
+static void test_fileb8cNVS(void **state)
+{
+ _test_one_ndr_dump(state, "fileb8cNVS");
+}
+
+static void test_filebI7h5H(void **state)
+{
+ _test_one_ndr_dump(state, "filebI7h5H");
+}
+
+static void test_filebNdBgt(void **state)
+{
+ _test_one_ndr_dump(state, "filebNdBgt");
+}
+
+static void test_filebOjK4H(void **state)
+{
+ _test_one_ndr_dump(state, "filebOjK4H");
+}
+
+static void test_filebzCPTH(void **state)
+{
+ _test_one_ndr_dump(state, "filebzCPTH");
+}
+
+
+
+
+int main(_UNUSED_ int argc, _UNUSED_ const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_fileb5iJt4),
+ cmocka_unit_test(test_fileb8cNVS),
+ cmocka_unit_test(test_filebI7h5H),
+ cmocka_unit_test(test_filebNdBgt),
+ cmocka_unit_test(test_filebOjK4H),
+ cmocka_unit_test(test_filebzCPTH),
+ };
+ if (isatty(1)) {
+ /*
+ * interactive testers can set debug level
+ * -- just give it a number.
+ */
+ int debug_level = DBGLVL_WARNING;
+ if (argc > 1) {
+ debug_level = atoi(argv[1]);
+ }
+ debuglevel_set(debug_level);
+
+ } else {
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ }
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/libcli/security/tests/test_run_conditional_ace.c b/libcli/security/tests/test_run_conditional_ace.c
new file mode 100644
index 0000000..dc02e33
--- /dev/null
+++ b/libcli/security/tests/test_run_conditional_ace.c
@@ -0,0 +1,730 @@
+/*
+ * Unit tests for conditional ACE SDDL.
+ *
+ * Copyright (C) Catalyst.NET Ltd 2023
+ *
+ * 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 <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include "cmocka.h"
+
+#include "lib/util/attr.h"
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/security.h"
+#include "libcli/security/conditional_ace.h"
+#include "librpc/gen_ndr/conditional_ace.h"
+#include "libcli/security/claims-conversions.h"
+
+#define debug_message(...) print_message(__VA_ARGS__)
+
+#define debug_fail(x, ...) print_message("\033[1;31m" x "\033[0m", __VA_ARGS__)
+#define debug_ok(x, ...) print_message("\033[1;32m" x "\033[0m", __VA_ARGS__)
+
+#define assert_ntstatus_equal(got, expected, comment) \
+ do { NTSTATUS __got = got, __expected = expected; \
+ if (!NT_STATUS_EQUAL(__got, __expected)) { \
+ print_message(": "#got" was %s, expected %s: %s", \
+ nt_errstr(__got), \
+ nt_errstr(__expected), comment); \
+ fail(); \
+ } \
+ } while(0)
+
+
+
+
+/*
+static void print_error_message(const char *sddl,
+ const char *message,
+ size_t message_offset)
+{
+ print_message("%s\n\033[1;33m %*c\033[0m\n", sddl,
+ (int)message_offset, '^');
+ print_message("%s\n", message);
+}
+*/
+static bool fill_token_claims(TALLOC_CTX *mem_ctx,
+ struct security_token *token,
+ const char *claim_type,
+ const char *name,
+ ...)
+{
+ va_list args;
+ va_start(args, name);
+ while (true) {
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim = NULL;
+ const char *str = va_arg(args, const char *);
+ if (str == NULL) {
+ break;
+ }
+ claim = parse_sddl_literal_as_claim(mem_ctx,
+ name,
+ str);
+ if (claim == NULL) {
+ va_end(args);
+ debug_fail("bad claim: %s\n", str);
+ return false;
+ }
+ add_claim_to_token(mem_ctx, token, claim, claim_type);
+ }
+ va_end(args);
+ return true;
+}
+
+
+static bool fill_token_sids(TALLOC_CTX *mem_ctx,
+ struct security_token *token,
+ const char *owner,
+ ...)
+{
+ uint32_t *n = &token->num_sids;
+ struct dom_sid **list = NULL;
+ va_list args;
+ if (strcmp(owner, "device") == 0) {
+ n = &token->num_device_sids;
+ list = &token->device_sids;
+ } else if (strcmp(owner, "user") == 0) {
+ n = &token->num_sids;
+ list = &token->sids;
+ } else {
+ return false;
+ }
+
+ *n = 0;
+ va_start(args, owner);
+ while (true) {
+ struct dom_sid *sid = NULL;
+ const char *str = va_arg(args, const char *);
+ if (str == NULL) {
+ break;
+ }
+
+ sid = sddl_decode_sid(mem_ctx, &str, NULL);
+ if (sid == NULL) {
+ debug_fail("bad SID: %s\n", str);
+ va_end(args);
+ return false;
+ }
+ add_sid_to_array(mem_ctx, sid, list, n);
+ }
+ va_end(args);
+ return true;
+}
+
+
+static void test_device_claims_composite(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ struct security_token token = {
+ .evaluate_claims = CLAIMS_EVALUATION_ALWAYS
+ };
+ bool ok;
+ NTSTATUS status;
+ uint32_t access_granted = 0;
+ struct security_descriptor *sd = NULL;
+ const char *sddl = \
+ "D:(XA;;0x1f;;;AA;(@Device.colour == {\"orange\", \"blue\"}))";
+ ok = fill_token_sids(mem_ctx, &token,
+ "user",
+ "WD", "AA", NULL);
+ assert_true(ok);
+ ok = fill_token_claims(mem_ctx, &token,
+ "device", "colour",
+ "{\"orange\", \"blue\"}",
+ NULL);
+ assert_true(ok);
+ sd = sddl_decode(mem_ctx, sddl, NULL);
+ assert_non_null(sd);
+ status = se_access_check(sd, &token, 0x10, &access_granted);
+ assert_ntstatus_equal(status, NT_STATUS_OK, "access check failed\n");
+}
+
+
+static bool fill_sd(TALLOC_CTX *mem_ctx,
+ struct security_descriptor **sd,
+ const char *sddl)
+{
+ *sd = sddl_decode(mem_ctx, sddl, NULL);
+ return *sd != NULL;
+}
+
+#define USER_SIDS(...) \
+ assert_true(fill_token_sids(mem_ctx, &token, "user", __VA_ARGS__, NULL))
+
+#define DEVICE_SIDS(...) \
+ assert_true( \
+ fill_token_sids(mem_ctx, &token, "device", __VA_ARGS__, NULL))
+
+#define USER_CLAIMS(...) \
+ assert_true( \
+ fill_token_claims(mem_ctx, &token, "user", __VA_ARGS__, NULL))
+
+#define LOCAL_CLAIMS(...) \
+ assert_true(fill_token_claims(mem_ctx, \
+ &token, \
+ "local", \
+ __VA_ARGS__, \
+ NULL))
+
+#define DEVICE_CLAIMS(...) \
+ assert_true(fill_token_claims(mem_ctx, \
+ &token, \
+ "device", \
+ __VA_ARGS__, \
+ NULL))
+
+
+#define SD(sddl) assert_true(fill_sd(mem_ctx, &sd, sddl))
+#define SD_FAIL(sddl) assert_false(fill_sd(mem_ctx, &sd, sddl))
+
+#define ALLOW_CHECK(requested) \
+ do { \
+ NTSTATUS status; \
+ uint32_t access_granted = 0; \
+ status = se_access_check(sd, \
+ &token, \
+ requested, \
+ &access_granted); \
+ assert_ntstatus_equal(status, \
+ NT_STATUS_OK, \
+ "access not granted\n"); \
+ } while (0)
+
+
+#define DENY_CHECK(requested) \
+ do { \
+ NTSTATUS status; \
+ uint32_t access_granted = 0; \
+ status = se_access_check(sd, \
+ &token, \
+ requested, \
+ &access_granted); \
+ assert_ntstatus_equal(status, \
+ NT_STATUS_ACCESS_DENIED, \
+ "not denied\n"); \
+ } while (0)
+
+
+#define INIT() \
+ TALLOC_CTX *mem_ctx = talloc_new(NULL); \
+ struct security_token token = { \
+ .evaluate_claims = CLAIMS_EVALUATION_ALWAYS \
+ }; \
+ struct security_descriptor *sd = NULL;
+
+
+
+static void test_composite_different_order(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == {\"orange\", \"blue\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"blue\", \"orange\"}");
+ /*
+ * Claim arrays are sets, so we assume conditional ACE ones are too.
+ */
+ ALLOW_CHECK(0x10);
+}
+
+static void test_composite_different_order_with_dupes(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == {\"orange\", \"blue\", \"orange\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\", \"orange\"}");
+ DENY_CHECK(0x10);
+}
+
+static void test_composite_different_order_with_dupes_in_composite(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == {\"orange\", \"blue\", \"orange\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_composite_different_order_with_SID_dupes(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == {SID(WD), SID(AA), SID(WD)}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{SID(AA), SID(AA), SID(WD)}");
+ DENY_CHECK(0x10);
+}
+
+static void test_composite_different_order_with_SID_dupes_in_composite(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == {SID(WD), SID(AA), SID(WD)}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{SID(AA), SID(WD)}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_composite_mixed_types(void **state)
+{
+ /*
+ * If the conditional ACE composite has mixed types, it can
+ * never equal a claim, which only has one type.
+ */
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == {2, SID(WD), SID(AA), SID(WD)}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{SID(AA), SID(WD)}");
+ DENY_CHECK(0x10);
+}
+
+static void test_composite_mixed_types_different_last(void **state)
+{
+ /*
+ * If the conditional ACE composite has mixed types, it can
+ * never equal a claim, which only has one type.
+ */
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == {SID(WD), SID(AA), 2}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{SID(AA), SID(WD)}");
+ DENY_CHECK(0x10);
+}
+
+static void test_composite_mixed_types_deny(void **state)
+{
+ /*
+ * If the conditional ACE composite has mixed types, it can
+ * never equal a claim, which only has one type.
+ */
+ INIT()
+ SD("D:(XD;;0x1f;;;AA;(@Device.colour == {2, SID(WD), SID(AA), SID(WD)}))"
+ "(D;;;;;WD)");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{SID(AA), SID(WD)}");
+ DENY_CHECK(0x10);
+}
+
+static void test_different_case(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == {\"OraNgE\", \"BLuE\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_different_case_with_case_sensitive_flag(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == {\"OraNgE\", \"BLuE\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ /* set the flag bit */
+ token.device_claims[0].flags = CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
+ DENY_CHECK(0x10);
+}
+
+
+static void test_claim_name_different_case(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.Colour == {\"orange\", \"blue\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_claim_name_different_case_case_flag(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.Colour == {\"orange\", \"blue\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ /*
+ * The CASE_SENSITIVE flag is for the values, not the names.
+ */
+ token.device_claims[0].flags = CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
+ ALLOW_CHECK(0x10);
+}
+
+static void test_more_values_not_equal(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour != {\"orange\", \"blue\", \"green\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_contains(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Contains {\"orange\", \"blue\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_contains_incomplete(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Contains {\"orange\", \"blue\", \"red\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ DENY_CHECK(0x10);
+}
+
+static void test_any_of(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Any_of {\"orange\", \"blue\", \"red\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_any_of_match_last(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Any_of {\"a\", \"b\", \"blue\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_any_of_1(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Any_of\"blue\"))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_contains_1(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Contains \"blue\"))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_contains_1_fail(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Contains \"pink\"))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ DENY_CHECK(0x10);
+}
+
+static void test_any_of_1_fail(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Any_of \"pink\"))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ DENY_CHECK(0x10);
+}
+
+
+static void test_not_any_of_1_fail(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Not_Any_of\"blue\"))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ DENY_CHECK(0x10);
+}
+
+static void test_not_any_of_composite_1(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Not_Any_of{\"blue\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ DENY_CHECK(0x10);
+}
+
+static void test_not_contains_1_fail(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Not_Contains \"blue\"))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ DENY_CHECK(0x10);
+}
+
+static void test_not_contains_1(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Not_Contains \"pink\"))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_not_any_of_1(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Not_Any_of \"pink\"))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_not_Not_Any_of_1(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(!(@Device.colour Not_Any_of \"pink\")))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ DENY_CHECK(0x10);
+}
+
+static void test_not_Not_Contains_1(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(! (@Device.colour Not_Contains \"blue\")))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+
+static void test_not_not_Not_Member_of(void **state)
+{
+ INIT();
+ SD("D:(XA;;0x1f;;;AA;(!(!(Not_Member_of{SID(BA)}))))");
+ USER_SIDS("WD", "AA");
+ DEVICE_SIDS("BA", "BG");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_not_not_Not_Member_of_fail(void **state)
+{
+ INIT();
+ SD("D:(XA;;0x1f;;;AA;(!(!(Not_Member_of{SID(AA)}))))");
+ USER_SIDS("WD", "AA");
+ DEVICE_SIDS("BA", "BG");
+ DENY_CHECK(0x10);
+}
+
+static void test_not_not_not_not_not_not_not_not_not_not_Not_Member_of(void **state)
+{
+ INIT();
+ SD("D:(XA;;0x1f;;;AA;(!(!(!( !(!(!( !(!(!( "
+ "Not_Member_of{SID(AA)})))))))))))");
+ USER_SIDS("WD", "AA");
+ DEVICE_SIDS("BA", "BG");
+ ALLOW_CHECK(0x10);
+}
+
+
+static void test_Device_Member_of_and_Member_of(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ DEVICE_SIDS("BA", "BG");
+ SD("D:(XA;;0x1f;;;AA;"
+ "(Device_Member_of{SID(BA)} && Member_of{SID(WD)}))");
+ ALLOW_CHECK(0x10);
+}
+
+
+static void test_Device_claim_contains_Resource_claim(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "\"blue\"");
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))"
+ "S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\"))");
+ ALLOW_CHECK(0x10);
+}
+
+
+static void test_device_claim_contains_resource_claim(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "\"blue\"");
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))"
+ "S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\"))");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_device_claim_eq_resource_claim(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "\"blue\"");
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == @Resource.colour))"
+ "S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\"))");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_user_claim_eq_device_claim(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ USER_CLAIMS("colour", "\"blue\"");
+ DEVICE_CLAIMS("colour", "\"blue\"");
+ SD("D:(XA;;0x1f;;;AA;(@User.colour == @Device.colour))");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_device_claim_eq_resource_claim_2(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == {\"orange\", \"blue\"}))");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_resource_ace_multi(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"blue\", \"red\"}");
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))"
+ "S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\", \"red\"))");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_resource_ace_multi_any_of(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "\"blue\"");
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Any_of @Resource.colour))"
+ "S:(RA;;;;;WD;(\"colour\",TS,0,\"grue\", \"blue\", \"red\"))");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_horrible_fuzz_derived_test_3(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA", "IS");
+ SD_FAIL("S:PPD:(XA;OI;0x1;;;IS;(q>))");
+}
+
+static void test_resource_ace_single(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "\"blue\"");
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))"
+ "S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\"))");
+ ALLOW_CHECK(0x10);
+}
+
+
+static void test_user_attr_any_of_missing_resource_and_user_attr(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "\"blue\"");
+ SD("D:(XD;;FX;;;S-1-1-0;(@User.Project Any_of @Resource.Project))");
+ DENY_CHECK(0x10);
+}
+
+static void test_user_attr_any_of_missing_resource_attr(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ USER_CLAIMS("Project", "3");
+ SD("D:(XD;;FX;;;S-1-1-0;(@User.Project Any_of @Resource.Project))");
+ DENY_CHECK(0x10);
+}
+
+static void test_user_attr_any_of_missing_user_attr(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ SD("D:(XD;;FX;;;S-1-1-0;(@User.Project Any_of @Resource.Project))"
+ "S:(RA;;;;;WD;(\"Project\",TX,0,1234))");
+ DENY_CHECK(0x10);
+}
+
+
+int main(_UNUSED_ int argc, _UNUSED_ const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_user_attr_any_of_missing_resource_and_user_attr),
+ cmocka_unit_test(test_user_attr_any_of_missing_resource_attr),
+ cmocka_unit_test(test_user_attr_any_of_missing_user_attr),
+ cmocka_unit_test(test_composite_mixed_types),
+ cmocka_unit_test(test_composite_mixed_types_different_last),
+ cmocka_unit_test(test_composite_mixed_types_deny),
+ cmocka_unit_test(test_composite_different_order_with_SID_dupes),
+ cmocka_unit_test(test_composite_different_order_with_SID_dupes_in_composite),
+ cmocka_unit_test(test_device_claim_eq_resource_claim_2),
+ cmocka_unit_test(test_not_Not_Any_of_1),
+ cmocka_unit_test(test_not_any_of_composite_1),
+ cmocka_unit_test(test_resource_ace_single),
+ cmocka_unit_test(test_horrible_fuzz_derived_test_3),
+ cmocka_unit_test(test_Device_Member_of_and_Member_of),
+ cmocka_unit_test(test_resource_ace_multi),
+ cmocka_unit_test(test_resource_ace_multi_any_of),
+ cmocka_unit_test(test_user_claim_eq_device_claim),
+ cmocka_unit_test(test_device_claim_contains_resource_claim),
+ cmocka_unit_test(test_device_claim_eq_resource_claim),
+ cmocka_unit_test(test_Device_claim_contains_Resource_claim),
+ cmocka_unit_test(test_not_Not_Contains_1),
+ cmocka_unit_test(test_not_not_Not_Member_of_fail),
+ cmocka_unit_test(test_not_not_Not_Member_of),
+ cmocka_unit_test(test_not_not_not_not_not_not_not_not_not_not_Not_Member_of),
+ cmocka_unit_test(test_not_any_of_1_fail),
+ cmocka_unit_test(test_not_any_of_1),
+ cmocka_unit_test(test_not_contains_1),
+ cmocka_unit_test(test_not_contains_1_fail),
+ cmocka_unit_test(test_any_of_1_fail),
+ cmocka_unit_test(test_any_of_1),
+ cmocka_unit_test(test_any_of),
+ cmocka_unit_test(test_any_of_match_last),
+ cmocka_unit_test(test_contains_incomplete),
+ cmocka_unit_test(test_contains),
+ cmocka_unit_test(test_contains_1),
+ cmocka_unit_test(test_contains_1_fail),
+ cmocka_unit_test(test_device_claims_composite),
+ cmocka_unit_test(test_claim_name_different_case),
+ cmocka_unit_test(test_claim_name_different_case_case_flag),
+ cmocka_unit_test(test_different_case_with_case_sensitive_flag),
+ cmocka_unit_test(test_composite_different_order),
+ cmocka_unit_test(test_different_case),
+ cmocka_unit_test(test_composite_different_order_with_dupes),
+ cmocka_unit_test(test_composite_different_order_with_dupes_in_composite),
+ cmocka_unit_test(test_more_values_not_equal),
+ };
+ if (isatty(1)) {
+ /*
+ * interactive testers can set debug level
+ * -- just give it a number.
+ */
+ int debug_level = DBGLVL_WARNING;
+ if (argc > 1) {
+ debug_level = atoi(argv[1]);
+ }
+ debuglevel_set(debug_level);
+
+ } else {
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ }
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/libcli/security/tests/test_sddl_conditional_ace.c b/libcli/security/tests/test_sddl_conditional_ace.c
new file mode 100644
index 0000000..fc9281d
--- /dev/null
+++ b/libcli/security/tests/test_sddl_conditional_ace.c
@@ -0,0 +1,1003 @@
+/*
+ * Unit tests for conditional ACE SDDL.
+ *
+ * Copyright (C) Catalyst.NET Ltd 2023
+ *
+ * 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 <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include "cmocka.h"
+
+#include "lib/util/attr.h"
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/security.h"
+#include "libcli/security/conditional_ace.h"
+#include "librpc/gen_ndr/conditional_ace.h"
+
+/*
+ * Some of the test strings break subunit, so we only print those if
+ * stdout is a terminal.
+ */
+#define debug_message(...) do { \
+ if (isatty(1)) { \
+ print_message(__VA_ARGS__); \
+ } \
+ } while(0)
+
+#define debug_fail(x, ...) debug_message("\033[1;31m" x "\033[0m", __VA_ARGS__)
+#define debug_ok(x, ...) debug_message("\033[1;32m" x "\033[0m", __VA_ARGS__)
+
+#define ACEINT64(x, b, s) CONDITIONAL_ACE_TOKEN_INT64, \
+ (x & 0xff), ((x >> 8) & 0xff), ((x >> 16) & 0xff), \
+ ((x >> 24) & 0xff), (((uint64_t)x >> 32) & 0xff), (((uint64_t)x >> 40) & 0xff), \
+ (((uint64_t)x >> 48) & 0xff), (((uint64_t)x >> 56) & 0xff), b, s
+
+
+static void print_error_message(const char *sddl,
+ const char *message,
+ size_t message_offset)
+{
+ print_message("%s\n\033[1;33m %*c\033[0m\n", sddl,
+ (int)message_offset, '^');
+ print_message("%s\n", message);
+}
+
+static void test_sddl_compile(void **state)
+{
+ /*
+ * Example codes:
+ *
+ * CONDITIONAL_ACE_LOCAL_ATTRIBUTE, 2,0,0,0, 'x',0,
+ * ^attr byte code ^ ^
+ * 32 bit little-endian length |
+ * utf-16, little endian
+ *
+ * CONDITIONAL_ACE_TOKEN_EQUAL
+ * ^ op byte code with no following data
+ */
+ static const char *sddl = "(x==41 &&(x >@device.x ) )";
+ static const uint8_t ace[] = {
+ 'a', 'r', 't', 'x',
+ CONDITIONAL_ACE_LOCAL_ATTRIBUTE, 2, 0, 0, 0, 'x', 0,
+ ACEINT64(41,
+ CONDITIONAL_ACE_INT_SIGN_NONE,
+ CONDITIONAL_ACE_INT_BASE_10),
+ CONDITIONAL_ACE_TOKEN_EQUAL,
+ CONDITIONAL_ACE_LOCAL_ATTRIBUTE, 2, 0, 0, 0, 'x', 0,
+ CONDITIONAL_ACE_DEVICE_ATTRIBUTE, 2, 0, 0, 0, 'x', 0,
+ CONDITIONAL_ACE_TOKEN_GREATER_THAN,
+ CONDITIONAL_ACE_TOKEN_AND, 0,0,0,0,
+ };
+
+ size_t i;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ struct ace_condition_script *s = NULL;
+ const char *message = NULL;
+ size_t message_offset;
+ bool ok;
+ DATA_BLOB compiled;
+ size_t length;
+
+ s = ace_conditions_compile_sddl(mem_ctx,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ sddl,
+ &message,
+ &message_offset,
+ &length);
+ if (message != NULL) {
+ print_error_message(sddl, message, message_offset);
+ }
+ if (s == NULL) {
+ debug_fail("%s\n", sddl);
+ fail();
+ }
+
+ ok = conditional_ace_encode_binary(mem_ctx, s, &compiled);
+ assert_true(ok);
+
+ assert_true(compiled.length <= ARRAY_SIZE(ace));
+ for (i = 0; i < compiled.length; i++) {
+ assert_int_equal(compiled.data[i], ace[i]);
+ }
+}
+
+static void test_sddl_compile2(void **state)
+{
+ /* this one is from Windows, not hand-calculated */
+ static const char *sddl = "(@USER.Project Any_of 1))";
+ static const uint8_t ace[] = ("artx\xf9\x0e\x00\x00\x00P\x00r"
+ "\x00o\x00j\x00""e\x00""c\x00t\x00"
+ "\x04\x01\x00\x00\x00\x00\x00\x00"
+ "\x00\x03\x02\x88\x00");
+ size_t i;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ struct ace_condition_script *s = NULL;
+ const char *message = NULL;
+ size_t message_offset;
+ bool ok;
+ DATA_BLOB compiled;
+ size_t length;
+
+ s = ace_conditions_compile_sddl(mem_ctx,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ sddl,
+ &message,
+ &message_offset,
+ &length);
+ if (message != NULL) {
+ print_error_message(sddl, message, message_offset);
+ }
+ if (s == NULL) {
+ debug_fail("%s\n", sddl);
+ fail();
+ }
+
+ ok = conditional_ace_encode_binary(mem_ctx, s, &compiled);
+ assert_true(ok);
+
+ assert_true(compiled.length <= ARRAY_SIZE(ace));
+ for (i = 0; i < compiled.length; i++) {
+ assert_int_equal(compiled.data[i], ace[i]);
+ }
+}
+
+static void test_full_sddl_compile(void **state)
+{
+ /*
+ * This one is from Windows, and annotated by hand.
+ *
+ * We have the bytes of a full security descriptor, in
+ * "relative" form, which is the same as the its NDR
+ * representation.
+ *
+ * *In general* we can't necessarily assert that Samba's NDR
+ * will be the same as Windows, because they could e.g. put
+ * the two ACLs in the reverse order which is also legitimate
+ * (there are hints this may vary on Windows). But in this
+ * particular case Samba and the Windows 2022 sample agree, so
+ * we can compare the bytes here.
+ *
+ * We can assert that unpacking these bytes as a security
+ * descriptor should succeed and give us exactly the same
+ * descriptor as parsing the SDDL.
+ */
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ struct security_descriptor sec_desc_windows = {};
+ struct security_descriptor *sec_desc_samba = NULL;
+ DATA_BLOB sd_ndr = {};
+ DATA_BLOB sd_win_push = {};
+ DATA_BLOB sd_samba_push = {};
+ bool ok;
+ enum ndr_err_code ndr_err;
+ const char *sddl = "D:(XA;;CCDCLCSWRPWP;;;MP;"\
+ "(@RESOURCE.c))S:(RA;;;;;WD;(\"colOIr\",TU,0xe,29925))";
+
+ uint8_t sd_bytes[] = {
+ 1, /* 0 version */
+ 0, /* 1 reserved */
+ 20, 128, /* 2 control */
+ 0, 0, 0, 0, /* 4 owner (null relative pointer == no owner) */
+ 0, 0, 0, 0, /* 8 group */
+ 20, 0, 0, 0,/* 12 SACL */
+ 92, 0, 0, 0,/* 16 DACL, i.e. pointer to 92 below */
+
+ /* 20 SACL (from pointer above) */
+ 4, /* 20 revision (ADS) */
+ 0, /* 21 reserved */
+ 72, 0, /* 22 size --> takes us to 92 */
+ 1, 0, /* 24 ace count */
+ 0, 0, /* 26 reserved */
+
+ /* now come SACL aces, of which there should be one */
+ 18, /* 28 ace type (SEC_ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE) */
+ 0, /* 29 ace flags */
+ 64, 0, /* 30 ace size (from start of ACE, again adds to ending at 92) */
+ 0, 0, 0, 0, /* 32 mask */
+
+ /* here's the ACE SID */
+ 1, /* 36 revision */
+ 1, /* 37 sub-auth count */
+ 0, 0, 0, 0, 0, 1, /* 38 big endian ident auth */
+ 0, 0, 0, 0, /* 44 the sub-auth (so SID is S-1-1-0 (everyone), mandatory with RA ace) */
+
+ /* here starts the actual claim, at 48 */
+ 20, 0, 0, 0, /* 48 pointer to name (relative to claim, at 68) */
+ 2, 0, /* 52 value type (uint64) */
+ 0, 0, /* 54 reserved */
+ 14, 0, 0, 0, /* 56 flags (case-sensitive|deny-only|disabled-by-default -- the "0xe" in the SDDL) */
+ 1, 0, 0, 0, /* 60 value count */
+ 34, 0, 0, 0, /* 64 array of pointers, 1-long, points to 48 + 34 == 82 */
+ /* 68 utf-16 letters "colOIr\0", indicated by name pointer at 48 */
+ 'c', 0,
+ 'o', 0,
+ 'l', 0,
+ 'O', 0, /* unlike conditional ACE strings, this is nul-terminated. */
+ 'I', 0, /* where does the next thing start: */
+ 'r', 0, /* 6 letters + '\0' * 2 = 14. 68 + 14 = 82 */
+ 0, 0,
+ /* 82 is the value pointed to at 64 above (LE uint64) */
+ 229, 116, 0, 0, 0, 0, 0, 0, /* this equals 229 + 116 * 256 == 29925, as we see in the SDDL. */
+
+ /* 88 the claim has ended. the ace has NEARLY ended, but we need to round up: */
+
+ 0, 0, /* 90 two bytes of padding to get to a multiple of 4. */
+ /* The ace and SACL have ended */
+
+ /* 92 the DACL starts. */
+ 2, /* 92 version (NT) */
+ 0, /* 93 reserved */
+ 40, 0, /* 94 size */
+ 1, 0, /* 96 ace count */
+ 0, 0, /* 98 reserved */
+ /* 100 the DACL aces start */
+ 9, /* 100 ace type (SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK) */
+ 0, /* 101 flags */
+ 32, 0, /* 102 ace size (ending at 132) */
+ 63, 0, 0, 0, /* 104 mask (let's assume CCDCLCSWRPWP as in sddl, not checked, but it's the right number of bits) */
+ /* 108 the ACE sid */
+ 1, /* 108 version */
+ 1, /* 109 sub-auths */
+ 0, 0, 0, 0, 0, 16,/* 110 bigendian 16 identauth */
+ 0, 33, 0, 0, /* 116 sub-auth 1, 33 << 8 == 8448; "S-1-16-8448" == "ML_MEDIUM_PLUS" == "MP" */
+ /* 120 here starts the callback */
+ 97, 114, 116, 120, /* 120 'artx' */
+ 250, /* 124 0xfa CONDITIONAL_ACE_RESOURCE_ATTRIBUTE token */
+ 2, 0, 0, 0, /* 125 length 2 (bytes) */
+ 'c', 0, /* 129 utf-16 "c" -- NOT nul-terminated */
+ 0 /* 131 padding to bring length to a multiple of 4 (132) */
+ };
+ sd_ndr.length = 132;
+ sd_ndr.data = sd_bytes;
+
+ sec_desc_samba = sddl_decode(mem_ctx, sddl, NULL);
+ assert_non_null(sec_desc_samba);
+ ndr_err = ndr_pull_struct_blob(
+ &sd_ndr, mem_ctx, &sec_desc_windows,
+ (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
+
+ assert_true(NDR_ERR_CODE_IS_SUCCESS(ndr_err));
+
+ /*
+ * look, we munge the DACL version byte before comparing,
+ * because Samba currently always does version 4.
+ */
+ sec_desc_windows.dacl->revision = SECURITY_ACL_REVISION_ADS;
+ sd_bytes[92] = SECURITY_ACL_REVISION_ADS;
+
+ /* push the structures back into blobs for 3-way comparisons. */
+ ndr_err = ndr_push_struct_blob(
+ &sd_win_push, mem_ctx,
+ &sec_desc_windows,
+ (ndr_push_flags_fn_t)ndr_push_security_descriptor);
+ assert_true(NDR_ERR_CODE_IS_SUCCESS(ndr_err));
+
+ ndr_err = ndr_push_struct_blob(
+ &sd_samba_push, mem_ctx,
+ sec_desc_samba,
+ (ndr_push_flags_fn_t)ndr_push_security_descriptor);
+ assert_true(NDR_ERR_CODE_IS_SUCCESS(ndr_err));
+
+ assert_int_equal(sd_samba_push.length, sd_win_push.length);
+ assert_int_equal(sd_samba_push.length, sd_ndr.length);
+ assert_memory_equal(sd_samba_push.data,
+ sd_win_push.data,
+ sd_win_push.length);
+ assert_memory_equal(sd_win_push.data,
+ sd_ndr.data,
+ sd_ndr.length);
+
+ ok = security_descriptor_equal(sec_desc_samba, &sec_desc_windows);
+ assert_true(ok);
+ talloc_free(mem_ctx);
+}
+
+
+static void debug_conditional_ace_stderr(TALLOC_CTX *mem_ctx,
+ struct ace_condition_script *program)
+{
+ char * debug_string = debug_conditional_ace(mem_ctx, program);
+
+ if (debug_string != NULL) {
+ fputs(debug_string, stderr);
+ TALLOC_FREE(debug_string);
+ } else {
+ print_message("failed to debug!\n");
+ }
+}
+
+
+static void test_full_sddl_ra_encode(void **state)
+{
+ /*
+ * This is an example from Windows that Samba once had trouble
+ * with.
+ */
+ bool ok;
+ enum ndr_err_code ndr_err;
+ char *sddl = NULL;
+ struct dom_sid domain_sid;
+ uint8_t win_bytes[] = {
+ 0x01, 0x00, 0x14, 0x80, /* descriptor header */
+ 0x00, 0x00, 0x00, 0x00, /* NULL owner pointer */
+ 0x00, 0x00, 0x00, 0x00, /* NULL group pointer */
+ 0x14, 0x00, 0x00, 0x00, /* SACL at 0x14 (20) */
+ 0x58, 0x01, 0x00, 0x00, /* DACL at 0x158 (344) */
+ /* SACL starts here (20) */
+ 0x02, 0x00, /* rev 2, NT */
+ 0x44, 0x01, /* size 0x0144 (324) -- ends at 344 */
+ 0x01, 0x00, /* ace count */
+ 0x00, 0x00, /* reserved */
+ /* ace starts here, 28 */
+ 0x12, 0x00, /* ace type, flags: 0x12(18) is resource attribute */
+ 0x3c, 0x01, /* ACE size 0x13c == 316, from ACE start, end at 344 */
+ 0x00, 0x00, 0x00, 0x00, /*ACE mask */
+ 0x01, 0x01, /* SID S-1-<identauth>-<1 subauth>) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* -1- indent auth */
+ 0x00, 0x00, 0x00, 0x00, /* -0 -> S-1-1-0, world */
+ /* claim starts here, 48 */
+ 0x28, 0x00, 0x00, 0x00, /* pointer to name 40 (from claim start 48) = 88 */
+ 0x10, 0x00, /* type octet string */
+ 0x00, 0x00, /* empty */
+ 0x00, 0x00, 0x00, 0x00, /* zero flags */
+ 0x06, 0x00, 0x00, 0x00, /* value count */
+ /* array of 6 value pointers (at claim + 16, 64) */
+ 0xf2, 0x00, 0x00, 0x00, /* value 0xf2 = 242 from claim (48) == 290 */
+ 0xf8, 0x00, 0x00, 0x00, /* 0xf8, 248 */
+ 0x0d, 0x01, 0x00, 0x00, /* 0x10d, 269 */
+ 0x14, 0x01, 0x00, 0x00, /* 0x114, 276 */
+ 0x1a, 0x01, 0x00, 0x00, /* 0x11a, 282 */
+ 0x21, 0x01, 0x00, 0x00, /* 0x121, 289 */
+ /* here's the name, at 88 */
+ 'c', 0x00,
+ 'o', 0x00,
+ 'l', 0x00,
+ 'O', 0x00,
+ 'I', 0x00,
+ 'r', 0x00, /* the following lines are all \x16 */
+ /* 100 */
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ /* 150 */
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ /* 200 */
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ /* 250 */
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ /* 280 */
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, /* 286 */
+ 'r', 0x00,
+ 0x00, 0x00, /* name is nul-terminated */
+ /* 290, first octet string blob */
+ 0x02, 0x00, 0x00, 0x00, /* length 2 */
+ 0x00, 0x77, /* 2 blob bytes */
+ /* second blob @ 48 + 248 == 296 */
+ 0x11, 0x00, 0x00, 0x00, /* length 0x11 = 17 */
+ 0x00, 0x77, 0x77, 0x71, 0x83, 0x68, 0x96, 0x62, 0x95, 0x93,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+ /* third blob at 269 + 48 == 317 */
+ 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x77, 0x77,
+ /* fourth blob, 276 + 48 == 324 */
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x77,
+ /* fifth blob, 282 + 48 == 330 */
+ 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x77, 0x77,
+ /* last blob 289 + 48 == 337 */
+ 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x77, 0x77,
+ /* claim ends */
+ /* 344 DACL starts */
+ 0x02, 0x00, /* rev 2 (NT) */
+ 0x28, 0x00, /* size 40, ending at 384 */
+ 0x01, 0x00, /* ace count */
+ 0x00, 0x00,
+ /* ACE starts here, 352 */
+ 0x09, 0x00, /* type 9, access allowed callback */
+ 0x20, 0x00, /* size 32 */
+ 0x3f, 0x00, 0x00, 0x00, /*mask */
+ 0x01, 0x01, /* S-1-... (1 subauth) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, /*...-16-...*/
+ 0x00, 0x21, 0x00, 0x00, /* -5356. S-1-16-5376 */
+ 'a', 'r', 't', 'x',
+ 0xfa, /* resource attr */
+ 0x02, 0x00, 0x00, 0x00, /*name is 2 bytes long (i.e. 1 UTF-16) */
+ 'c', 0x00, /* name is "c" */
+ /* here we're at 383, but need to round to a multiple of 4 with zeros: */
+ 0x00
+ };
+ DATA_BLOB win_blob = {
+ .data = win_bytes,
+ .length = sizeof(win_bytes)
+ };
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ struct security_descriptor sec_desc_windows = {};
+ struct security_descriptor *sec_desc_samba = NULL;
+
+ ndr_err = ndr_pull_struct_blob(
+ &win_blob, mem_ctx, &sec_desc_windows,
+ (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
+ assert_true(NDR_ERR_CODE_IS_SUCCESS(ndr_err));
+
+ string_to_sid(&domain_sid, "S-1-2-3");
+ sddl = sddl_encode(mem_ctx, &sec_desc_windows, &domain_sid);
+ assert_non_null(sddl);
+ sec_desc_samba = sddl_decode(mem_ctx, sddl, &domain_sid);
+
+ /* hack the acl revision numbers */
+ sec_desc_windows.dacl->revision = SECURITY_ACL_REVISION_ADS;
+ sec_desc_windows.sacl->revision = SECURITY_ACL_REVISION_ADS;
+ ok = security_descriptor_equal(sec_desc_samba, &sec_desc_windows);
+ assert_true(ok);
+ talloc_free(mem_ctx);
+}
+
+
+static void test_full_sddl_ra_escapes(void **state)
+{
+ /*
+ * This is the security descriptor described in
+ * test_full_sddl_ra_encode(), with SDDL.
+ */
+ enum ndr_err_code ndr_err;
+ const char *sddl = (
+ "D:(XA;;CCDCLCSWRPWP;;;MP;(@RESOURCE.c))S:(RA;;;;;WD;(\""
+ "colOIr%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016"
+ "%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016"
+ "%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016"
+ "%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016"
+ "%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016"
+ "%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016"
+ "%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016"
+ "%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016"
+ "%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016"
+ "%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016"
+ "%0016%0016%0016%0016%0016%0016r\","
+ "TX,0x0,"
+ "0077,00,0077,00,0077,00,00,00,0077,00,0077,"
+ "00,0077,007777,007777,0077,007777,0077,007777,"
+ "007770,0077,00,0077,00,00,00,0077,00,0077,00,"
+ "0077,007777,007777,0077,007777,0077,007777,007777))");
+ uint8_t win_bytes[] = {
+ 0x01, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x9c, 0x02, 0x01, 0x00, 0x00, 0x00, 0x12, 0x00,
+ 0x94, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x26, 0x00, 0x00, 0x00, 0x9e, 0x01, 0x00, 0x00, 0xa4, 0x01,
+ 0x00, 0x00, 0xa9, 0x01, 0x00, 0x00, 0xaf, 0x01, 0x00, 0x00,
+ 0xb4, 0x01, 0x00, 0x00, 0xba, 0x01, 0x00, 0x00, 0xbf, 0x01,
+ 0x00, 0x00, 0xc4, 0x01, 0x00, 0x00, 0xc9, 0x01, 0x00, 0x00,
+ 0xcf, 0x01, 0x00, 0x00, 0xd4, 0x01, 0x00, 0x00, 0xda, 0x01,
+ 0x00, 0x00, 0xdf, 0x01, 0x00, 0x00, 0xe5, 0x01, 0x00, 0x00,
+ 0xec, 0x01, 0x00, 0x00, 0xf3, 0x01, 0x00, 0x00, 0xf9, 0x01,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00,
+ 0x0d, 0x02, 0x00, 0x00, 0x14, 0x02, 0x00, 0x00, 0x1a, 0x02,
+ 0x00, 0x00, 0x1f, 0x02, 0x00, 0x00, 0x25, 0x02, 0x00, 0x00,
+ 0x2a, 0x02, 0x00, 0x00, 0x2f, 0x02, 0x00, 0x00, 0x34, 0x02,
+ 0x00, 0x00, 0x3a, 0x02, 0x00, 0x00, 0x3f, 0x02, 0x00, 0x00,
+ 0x45, 0x02, 0x00, 0x00, 0x4a, 0x02, 0x00, 0x00, 0x50, 0x02,
+ 0x00, 0x00, 0x57, 0x02, 0x00, 0x00, 0x5e, 0x02, 0x00, 0x00,
+ 0x64, 0x02, 0x00, 0x00, 0x6b, 0x02, 0x00, 0x00, 0x71, 0x02,
+ 0x00, 0x00, 0x78, 0x02, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00,
+ 0x6c, 0x00, 0x4f, 0x00, 0x49, 0x00, 0x72, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x72, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x77, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x77, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x77, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x77, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x77, 0x03, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x77, 0x03, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x77, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x77, 0x77, 0x03, 0x00, 0x00, 0x00, 0x00, 0x77, 0x70,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x77, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x77, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x77, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x77, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x77, 0x77, 0x02, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x77, 0x03, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x00, 0x02, 0x00,
+ 0x28, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x20, 0x00,
+ 0x3f, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x21, 0x00, 0x00, 0x61, 0x72, 0x74, 0x78,
+ 0xfa, 0x02, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00};
+ DATA_BLOB win_blob = {
+ .data = win_bytes,
+ .length = sizeof(win_bytes)
+ };
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ struct security_descriptor sec_desc_windows = {};
+ struct security_descriptor *sec_desc_samba = sddl_decode(mem_ctx, sddl,
+ NULL);
+ assert_non_null(sec_desc_samba);
+ ndr_err = ndr_pull_struct_blob(
+ &win_blob, mem_ctx, &sec_desc_windows,
+ (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
+
+ assert_true(NDR_ERR_CODE_IS_SUCCESS(ndr_err));
+}
+
+static void test_round_trips(void **state)
+{
+ /*
+ * These expressions should parse into proper conditional
+ * ACEs, which then encode into an equivalent SDDL string,
+ * which then parses again into the same conditional ACE.
+ */
+ static const char *sddl[] = {
+ "(0>-0)",
+ "(0>+0)",
+ ("(Member_of{SID(AA)})"),
+ ("(a Contains @USER.b == @device.c)"),
+ ("(a == @user.b == @resource.c)"),
+ ("(@Device.bb <= -00624677746777766777767)"),
+ ("(@Device.bb == 0624677746777766777767)"),
+ ("(@Device.%025cɜ == 3)"),
+ ("(17pq == 3||2a==@USER.7)"),
+ ("(x==1 && x >= 2 && @User.Title == @User.shoes || "
+ "Member_of{SID(CD)} && !(Member_of_Any{ 3 }) || "
+ "Device_Member_of{SID(BA), 7, 1, 3} "
+ "|| Exists hooly)"),
+ ("(!(!(!(!(!((!(x==1))))))))"),
+ ("(@User.a == {})"),
+ ("(Member_of{})"),
+ ("(Member_of {SID(S-1-33-5), "
+ "SID(BO)} && @Device.Bitlocker)"),
+ "(@USER.ad://ext/AuthenticationSilo == \"siloname\")",
+ "(@User.Division==\"Finance\" || @User.Division ==\"Sales\")",
+ "(@User.Title == @User.Title)",
+ "(@User.Title == \"PM\")",
+ "(OctetStringType==#01020300)",
+ "(@User.Project Any_of @Resource.Project)",
+ "(@user.x==1 &&(@user.x >@user.x ) )",
+ "(x==1) ",
+ "( x Contains 3)",
+ "( x < 3)",
+ "(x Any_of 3)",
+ "( x == SID(BA))",
+ "((x) == SID(BA))",
+ "(OctetStringType==#1#2#3###))",
+ "(@user.x == 00)",
+ "(@user.x == 01)",
+ "(@user.x == -00)",
+ "(@user.x == -01)",
+ "(@user.x == 0x0)",
+ "(@user.x == 0x1)",
+ "(@user.x == -0x0)",
+ "(@user.x == -0x1)",
+ };
+ size_t i, length;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ bool failed = false;
+ bool ok;
+ for (i = 0; i < ARRAY_SIZE(sddl); i++) {
+ struct ace_condition_script *s1 = NULL;
+ struct ace_condition_script *s2 = NULL;
+ struct ace_condition_script *s3 = NULL;
+ const char *message = NULL;
+ size_t message_offset;
+ const char *resddl1 = NULL;
+ const char *resddl2 = NULL;
+ DATA_BLOB e1, e2, e3;
+ fputs("=======================\n", stderr);
+ s1 = ace_conditions_compile_sddl(mem_ctx,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ sddl[i],
+ &message,
+ &message_offset,
+ &length);
+ if (s1 == NULL) {
+ debug_fail("%s\n", sddl[i]);
+ failed = true;
+ print_error_message(sddl[i], message, message_offset);
+ continue;
+ }
+ if (false) {
+ debug_conditional_ace_stderr(mem_ctx, s1);
+ }
+ ok = conditional_ace_encode_binary(mem_ctx, s1, &e1);
+ if (! ok) {
+ failed = true;
+ debug_fail("%s could not encode\n", sddl[i]);
+ continue;
+ }
+
+ s2 = parse_conditional_ace(mem_ctx, e1);
+ if (s2 == NULL) {
+ debug_fail("%s failed to decode ace\n", sddl[i]);
+ failed = true;
+ continue;
+ }
+
+ ok = conditional_ace_encode_binary(mem_ctx, s2, &e2);
+ if (! ok) {
+ failed = true;
+ debug_fail("%s could not re-encode\n", sddl[i]);
+ continue;
+ }
+ if (data_blob_cmp(&e1, &e2) != 0) {
+ failed = true;
+ }
+
+ resddl1 = sddl_from_conditional_ace(mem_ctx, s1);
+ if (resddl1 == NULL) {
+ failed = true;
+ debug_fail("could not re-make SDDL of %s\n", sddl[i]);
+ continue;
+ }
+ resddl2 = sddl_from_conditional_ace(mem_ctx, s2);
+ if (resddl2 == NULL) {
+ failed = true;
+ debug_fail("could not re-make SDDL of %s\n", sddl[i]);
+ continue;
+ }
+ if (strcmp(resddl1, resddl2) != 0) {
+ print_message("SDDL 2: %s\n", resddl2);
+ failed = true;
+ }
+ print_message("SDDL: '%s' -> '%s'\n", sddl[i], resddl1);
+ s3 = ace_conditions_compile_sddl(mem_ctx,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ resddl1,
+ &message,
+ &message_offset,
+ &length);
+ if (s3 == NULL) {
+ debug_fail("resddl: %s\n", resddl1);
+ failed = true;
+ print_error_message(resddl1, message, message_offset);
+ continue;
+ }
+ ok = conditional_ace_encode_binary(mem_ctx, s3, &e3);
+ if (! ok) {
+ failed = true;
+ debug_fail("%s could not encode\n", resddl1);
+ continue;
+ }
+ if (data_blob_cmp(&e1, &e3) != 0) {
+ debug_fail("'%s' and '%s' compiled differently\n", sddl[i], resddl1);
+ failed = true;
+ }
+ }
+ assert_false(failed);
+}
+
+static void test_a_number_of_valid_strings(void **state)
+{
+ /*
+ * These expressions should parse into proper conditional ACEs.
+ */
+ static const char *sddl[] = {
+ "(@User.TEETH == \"5\")",
+ "(x==1) ",
+ "( x Contains 3)",
+ "( x < 3)",
+ "(x Any_of 3)",
+ "( x == SID(BA))",
+ "(x ANY_Of 3)",
+ "((x) == SID(BA))",
+ "(x==1 && x >= 2)", /* logical consistency not required */
+ };
+ size_t i, length;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ bool failed = false;
+ for (i = 0; i < ARRAY_SIZE(sddl); i++) {
+ struct ace_condition_script *s = NULL;
+ const char *message = NULL;
+ size_t message_offset;
+
+ s = ace_conditions_compile_sddl(mem_ctx,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ sddl[i],
+ &message,
+ &message_offset,
+ &length);
+ if (s == NULL) {
+ debug_fail("%s\n", sddl[i]);
+ failed = true;
+ } else if (length != strlen(sddl[i])) {
+ debug_fail("%s failed to consume whole string\n",
+ sddl[i]);
+ failed = true;
+ }
+ if (message != NULL) {
+ print_error_message(sddl[i], message, message_offset);
+ } else if (s == NULL) {
+ print_message("failed without message\n");
+ }
+ }
+ assert_false(failed);
+}
+
+
+static void test_a_number_of_invalid_strings(void **state)
+{
+ /*
+ * These expressions should fail to parse.
+ */
+ static const char *sddl[] = {
+ /* '!' is only allowed before parens or @attr */
+ "(!!! !!! !!! Not_Member_of{SID(AA)}))",
+ /* overflowing numbers can't be sensibly interpreted */
+ ("(@Device.bb == 055555624677746777766777767)"),
+ ("(@Device.bb == 0x624677746777766777767)"),
+ ("(@Device.bb == 624677746777766777767)"),
+ /* insufficient arguments */
+ "(!)",
+ "(x >)",
+ "(> 3)",
+ /* keyword as local attribute name */
+ "( Member_of Contains 3)",
+ /* no parens */
+ " x < 3",
+ /* wants '==' */
+ "( x = SID(BA))",
+ /* invalid SID strings */
+ "( x == SID(ZZ))",
+ "( x == SID(S-1-))",
+ "( x == SID())",
+ /* literal on LHS */
+ "(\"x\" == \"x\")",
+ /* odd number of digits following '#' */
+ "(OctetStringType==#1#2#3##))",
+ /* empty expression */
+ "()",
+ /* relational op with with complex RHS */
+ "(@Device.bb == (@USER.x < 62))",
+ /* hex‐escapes that should be literals */
+ ("(@Device.%002e == 3)"),
+ ("(@Device.%002f == 3)"),
+ ("(@Device.%003a == 3)"),
+ /* trailing comma in composite */
+ "(Member_of{SID(AA),})",
+ /* missing comma between elements of a composite */
+ "(Member_of{SID(AA) SID(AC)})",
+ /* unexpected comma in composite */
+ "(Member_of{,})",
+ };
+ size_t i, length;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ bool failed_to_fail = false;
+ for (i = 0; i < ARRAY_SIZE(sddl); i++) {
+ struct ace_condition_script *s = NULL;
+ const char *message = NULL;
+ size_t message_offset;
+ s = ace_conditions_compile_sddl(mem_ctx,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ sddl[i],
+ &message,
+ &message_offset,
+ &length);
+ if (s != NULL) {
+ print_message("unexpected success: ");
+ debug_fail("%s\n", sddl[i]);
+ failed_to_fail = true;
+ }
+ if (message != NULL) {
+ print_error_message(sddl[i], message, message_offset);
+ } else if (s == NULL) {
+ print_message("failed without message\n");
+ }
+ }
+ assert_false(failed_to_fail);
+}
+
+
+static void test_a_number_of_invalid_full_sddl_strings(void **state)
+{
+ /*
+ * These ones are complete SDDL sentences and should fail to parse,
+ * with specific message snippets.
+ */
+ static struct {
+ const char *sddl;
+ const char *snippet;
+ ssize_t offset;
+ } cases[] = {
+ {
+ "O:SYG:SYD:(A;;;;ZZ)(XA;OICI;CR;;;WD;(Member_of {WD}))",
+ "malformed ACE with only 4 ';'",
+ 11
+ },
+ {
+ "O:SYG:SYD:QQ(A;;;;ZZ)(XA;OICI;CR;;;WD;(Member_of {WD}))",
+ "expected '[OGDS]:' section start",
+ 10
+ }
+ };
+ size_t i;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ bool failed_to_fail = false;
+ bool message_wrong = false;
+ enum ace_condition_flags ace_condition_flags = \
+ ACE_CONDITION_FLAG_ALLOW_DEVICE;
+ struct dom_sid domain_sid;
+ string_to_sid(&domain_sid, "S-1-2-3");
+
+ for (i = 0; i < ARRAY_SIZE(cases); i++) {
+ struct security_descriptor *sd = NULL;
+ const char *message = NULL;
+ size_t message_offset;
+ sd = sddl_decode_err_msg(mem_ctx,
+ cases[i].sddl,
+ &domain_sid,
+ ace_condition_flags,
+ &message,
+ &message_offset);
+ if (sd != NULL) {
+ print_message("unexpected success: ");
+ debug_fail("%s\n", cases[i].sddl);
+ failed_to_fail = true;
+ }
+ if (cases[i].snippet != NULL) {
+ if (message != NULL) {
+ char *c = strstr(message, cases[i].snippet);
+ print_error_message(cases[i].sddl,
+ message,
+ message_offset);
+ if (c == NULL) {
+ message_wrong = true;
+ print_message("expected '%s'\n",
+ cases[i].snippet);
+ }
+ } else {
+ message_wrong = true;
+ print_error_message(cases[i].sddl,
+ "NO MESSAGE!",
+ message_offset);
+ print_message("expected '%s', got no message!\n",
+ cases[i].snippet);
+ }
+ } else {
+ print_message("no assertion about message, got '%s'\n",
+ message);
+ }
+ if (cases[i].offset >= 0) {
+ if (cases[i].offset != message_offset) {
+ message_wrong = true;
+ print_message("expected offset %zd, got %zu\n",
+ cases[i].offset,
+ message_offset);
+ }
+ } else {
+ print_message("no assertion about offset, got '%zu\n",
+ message_offset);
+ }
+ }
+ assert_false(failed_to_fail);
+ assert_false(message_wrong);
+}
+
+
+static void test_valid_strings_with_trailing_crap(void **state)
+{
+ /*
+ * These expressions should parse even though they have
+ * trailing bytes that look bad.
+ *
+ * ace_conditions_compile_sddl() will return when it has
+ * found a complete expression, and tell us how much it used.
+ */
+ static struct {
+ const char *sddl;
+ size_t length;
+ } pairs[] = {
+ {"(x==1 &&(x < 5 )) )", 18},
+ {"(x==1) &&", 7},
+ {"(x)) ", 3},
+ };
+ size_t i, length;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ bool failed = false;
+ for (i = 0; i < ARRAY_SIZE(pairs); i++) {
+ struct ace_condition_script *s = NULL;
+ const char *message = NULL;
+ size_t message_offset;
+ s = ace_conditions_compile_sddl(mem_ctx,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ pairs[i].sddl,
+ &message,
+ &message_offset,
+ &length);
+
+ if (s == NULL) {
+ debug_fail("%s\n", pairs[i].sddl);
+ failed = true;
+ } else if (pairs[i].length == length) {
+ debug_ok("%s\n", pairs[i].sddl);
+ } else {
+ debug_fail("expected to consume %zu bytes, actual %zu\n",
+ pairs[i].length, length);
+ failed = true;
+ }
+ if (message != NULL) {
+ print_error_message(pairs[i].sddl, message, message_offset);
+ } else if (s == NULL) {
+ print_message("failed without message\n");
+ }
+ }
+ assert_false(failed);
+}
+
+
+int main(_UNUSED_ int argc, _UNUSED_ const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_a_number_of_invalid_full_sddl_strings),
+ cmocka_unit_test(test_full_sddl_ra_encode),
+ cmocka_unit_test(test_full_sddl_ra_escapes),
+ cmocka_unit_test(test_full_sddl_compile),
+ cmocka_unit_test(test_round_trips),
+ cmocka_unit_test(test_a_number_of_invalid_strings),
+ cmocka_unit_test(test_a_number_of_valid_strings),
+ cmocka_unit_test(test_valid_strings_with_trailing_crap),
+ cmocka_unit_test(test_sddl_compile),
+ cmocka_unit_test(test_sddl_compile2),
+ };
+ if (!isatty(1)) {
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ }
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/libcli/security/tests/windows/canonical.txt b/libcli/security/tests/windows/canonical.txt
new file mode 100644
index 0000000..edeae63
--- /dev/null
+++ b/libcli/security/tests/windows/canonical.txt
@@ -0,0 +1,19 @@
+O:S-1-5-21-1225132014-296224811-2507946102-512G:S-1-5-21-1225132014-296224811-2507946102-512D:P -> O:S-1-5-21-1225132014-296224811-2507946102-512G:S-1-5-21-1225132014-296224811-2507946102-512D:P
+D:(A;;GA;;;SY) -> D:(A;;GA;;;SY)
+D:(A;;GA;;;RU) -> D:(A;;GA;;;RU)
+D:(A;;GA;;;LG) -> D:(A;;GA;;;LG)
+D:(A;;0x401200a0;;;LG) -> D:(A;;0x401200a0;;;LG)
+D:S: -> D:S:
+D:PS: -> D:PS:
+D:(A;;GA;;;RD) -> D:(A;;GA;;;RD)
+S:(AU;SA;CR;;;WD)(AU;SA;CR;;;WD) -> S:(AU;SA;CR;;;WD)(AU;SA;CR;;;WD)
+S:(OU;CISA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD) -> S:(OU;CISA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)
+D:(A;;GA;;;S-1-3-4294967295-3-4) -> D:(A;;GA;;;S-1-3-4294967295-3-4)
+D:(A;;GA;;;S-1-5-21-1-2-3-513) -> D:(A;;GA;;;S-1-5-21-1-2-3-513)
+D:(A;;GA;;;S-1-5-21-2447931902-1787058256-3961074038-1201) -> D:(A;;GA;;;S-1-5-21-2447931902-1787058256-3961074038-1201)
+O:S-1-2-512D: -> O:S-1-2-512D:
+D:PARAI(A;;GA;;;SY) -> D:PARAI(A;;GA;;;SY)
+D:P(A;;GA;;;LG)(A;;GX;;;AA) -> D:P(A;;GA;;;LG)(A;;GX;;;AA)
+D:(A;;FA;;;WD) -> D:(A;;FA;;;WD)
+D:(A;;CCDCLCSWRPWPDTLOCR;;;WD) -> D:(A;;CCDCLCSWRPWPDTLOCR;;;WD)
+D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)
diff --git a/libcli/security/tests/windows/conditional_aces.txt.json b/libcli/security/tests/windows/conditional_aces.txt.json
new file mode 100644
index 0000000..4c8211c
--- /dev/null
+++ b/libcli/security/tests/windows/conditional_aces.txt.json
@@ -0,0 +1 @@
+{"D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GRGWGX;;;AU)(XA;;FX;;;S-1-1-0;(@User.Title == \"\"))(A;OICI;GA;;;BA)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 144, 0, 5, 0, 0, 0, 1, 3, 24, 0, 0, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 34, 2, 0, 0, 1, 3, 20, 0, 0, 0, 0, 16, 1, 1, 0, 0, 0, 0, 0, 5, 7, 0, 0, 0, 0, 3, 20, 0, 0, 0, 0, 224, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 9, 0, 48, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 16, 0, 0, 0, 0, 128, 0, 0, 0, 0, 3, 24, 0, 0, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0], "D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GRGWGX;;;AU)(XA;;FX;;;S-1-1-0;(@User.title == \"perambuator\"))(A;OICI;GA;;;BA)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 164, 0, 5, 0, 0, 0, 1, 3, 24, 0, 0, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 34, 2, 0, 0, 1, 3, 20, 0, 0, 0, 0, 16, 1, 1, 0, 0, 0, 0, 0, 5, 7, 0, 0, 0, 0, 3, 20, 0, 0, 0, 0, 224, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 9, 0, 68, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 116, 0, 105, 0, 116, 0, 108, 0, 101, 0, 16, 22, 0, 0, 0, 112, 0, 101, 0, 114, 0, 97, 0, 109, 0, 98, 0, 117, 0, 97, 0, 116, 0, 111, 0, 114, 0, 128, 0, 0, 3, 24, 0, 0, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0], "D:(XA;;0x1f;;;AA;(!(! (Member_of{SID(AA)}))))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 68, 0, 1, 0, 0, 0, 9, 0, 60, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 137, 162, 162, 0, 0, 0], "D:(XA;;0x1f;;;AA;(!(!(!(!(!(! (Member_of{SID(AA)}))))))))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 137, 162, 162, 162, 162, 162, 162, 0, 0, 0], "D:(XA;;0x1f;;;AA;(@Device.colour == \"blue\"))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 68, 0, 1, 0, 0, 0, 9, 0, 60, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 16, 8, 0, 0, 0, 98, 0, 108, 0, 117, 0, 101, 0, 128, 0], "D:(XA;;0x1f;;;AA;(@Device.colour == @Resource.colour))S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\"))": [1, 0, 20, 128, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 92, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 18, 0, 64, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 20, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 34, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 0, 0, 98, 0, 108, 0, 117, 0, 101, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 250, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 128, 0], "D:(XA;;0x1f;;;AA;(@Device.colour == {\"orange\", \"blue\"}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 92, 0, 1, 0, 0, 0, 9, 0, 84, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 80, 30, 0, 0, 0, 16, 12, 0, 0, 0, 111, 0, 114, 0, 97, 0, 110, 0, 103, 0, 101, 0, 16, 8, 0, 0, 0, 98, 0, 108, 0, 117, 0, 101, 0, 128, 0, 0, 0], "D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\"))": [1, 0, 20, 128, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 92, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 18, 0, 64, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 20, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 34, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 0, 0, 98, 0, 108, 0, 117, 0, 101, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 250, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 134, 0], "D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\", \"red\"))": [1, 0, 20, 128, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 104, 0, 0, 0, 2, 0, 84, 0, 1, 0, 0, 0, 18, 0, 76, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 24, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 38, 0, 0, 0, 48, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 0, 0, 98, 0, 108, 0, 117, 0, 101, 0, 0, 0, 114, 0, 101, 0, 100, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 250, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 134, 0], "D:(XA;;0x1f;;;AA;(@Device.legs == 1))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 9, 0, 56, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 8, 0, 0, 0, 108, 0, 101, 0, 103, 0, 115, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 128, 0, 0, 0], "D:(XA;;0x1f;;;AA;(@Device.legs >= 1))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 9, 0, 56, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 8, 0, 0, 0, 108, 0, 101, 0, 103, 0, 115, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 133, 0, 0, 0], "D:(XA;;0x1f;;;AA;(@User.colour == @Device.colour))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 249, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 128, 0], "D:(XA;;0x1f;;;AA;(Device_Member_of{SID(AA)} || Member_of{SID(WD)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 88, 0, 1, 0, 0, 0, 9, 0, 80, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 138, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 161, 0], "D:(XA;;0x1f;;;AA;(Device_Member_of{SID(BA)} && Member_of{SID(WD)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 88, 0, 1, 0, 0, 0, 9, 0, 80, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 138, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 160, 0], "D:(XA;;0x1f;;;AA;(Device_Member_of{SID(BA)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 9, 0, 56, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 138, 0], "D:(XA;;0x1f;;;AA;(Device_Member_of{SID(BG)} || Member_of{SID(WR)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 88, 0, 1, 0, 0, 0, 9, 0, 80, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 34, 2, 0, 0, 138, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 33, 0, 0, 0, 137, 161, 0], "D:(XA;;0x1f;;;AA;(Member_of{SID(S-1-77-88-99)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 9, 0, 56, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 77, 88, 0, 0, 0, 99, 0, 0, 0, 137, 0], "D:(XA;;0x1f;;;AA;(a == 1))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 248, 2, 0, 0, 0, 97, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 128, 0], "D:(XA;;0x1ff;;;S-1-222-333;(Member_of_Any{SID(S-1-222-333)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 222, 77, 1, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 222, 77, 1, 0, 0, 139, 0], "D:(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-222-333)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 222, 77, 1, 0, 0, 139, 0], "D:(XA;;;;;WD;(@Device.bb == 0x7fffffffffffffff))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 251, 4, 0, 0, 0, 98, 0, 98, 0, 4, 255, 255, 255, 255, 255, 255, 255, 127, 3, 3, 128, 0, 0, 0], "D:(XA;;;;;WD;(@Device.bb == 0xffffffff))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 251, 4, 0, 0, 0, 98, 0, 98, 0, 4, 255, 255, 255, 255, 0, 0, 0, 0, 3, 3, 128, 0, 0, 0], "D:(XA;;;;;WD;(@Device.bb == 0xfffffffff))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 251, 4, 0, 0, 0, 98, 0, 98, 0, 4, 255, 255, 255, 255, 15, 0, 0, 0, 3, 3, 128, 0, 0, 0], "D:(XA;;CC;;;AA;(@User.a == @User.b))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 1, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 97, 0, 249, 2, 0, 0, 0, 98, 0, 128, 0], "D:(XA;;CC;;;AA;(a == @User.a))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 1, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 248, 2, 0, 0, 0, 97, 0, 249, 2, 0, 0, 0, 97, 0, 128, 0], "D:(XA;;CC;;;S-1-2-3;(@User.Title != @User.Title))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 9, 0, 56, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 129, 0], "D:(XA;;FR;;;S-1-1-0;(@Device.Bitlocker && @Device.Bitlocker))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 80, 0, 1, 0, 0, 0, 9, 0, 72, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 160, 0], "D:(XA;;FR;;;S-1-1-0;(@Device.Bitlocker || @Device.Bitlocker))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 80, 0, 1, 0, 0, 0, 9, 0, 72, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 161, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.A && @Device.B && @USER.C))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 65, 0, 251, 2, 0, 0, 0, 66, 0, 160, 249, 2, 0, 0, 0, 67, 0, 160, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.A && @Device.B || @USER.C))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 65, 0, 251, 2, 0, 0, 0, 66, 0, 160, 249, 2, 0, 0, 0, 67, 0, 161, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.A && @Device.B))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 48, 0, 1, 0, 0, 0, 9, 0, 40, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 65, 0, 251, 2, 0, 0, 0, 66, 0, 160, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.A || @Device.B && @USER.C))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 65, 0, 251, 2, 0, 0, 0, 66, 0, 249, 2, 0, 0, 0, 67, 0, 160, 161, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.A || @Device.B || @USER.C))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 65, 0, 251, 2, 0, 0, 0, 66, 0, 161, 249, 2, 0, 0, 0, 67, 0, 161, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.Bitlocker || @Device.Bitlocker))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 80, 0, 1, 0, 0, 0, 9, 0, 72, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 161, 0], "D:(XA;;FR;;;S-1-1-0;(Member_of {SID(S-1-999-777-7-7), SID(BO)} && @Device.Bitlocker))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 108, 0, 1, 0, 0, 0, 9, 0, 100, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 46, 0, 0, 0, 81, 20, 0, 0, 0, 1, 3, 0, 0, 0, 0, 3, 231, 9, 3, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 39, 2, 0, 0, 137, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 160], "D:(XA;;FX;;;S-1-1-0;(@User.Project Any_of @Resource.Project))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 250, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 136, 0], "D:(XA;;FX;;;S-1-1-0;(@User.Title == \"PM\"))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 60, 0, 1, 0, 0, 0, 9, 0, 52, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 16, 4, 0, 0, 0, 80, 0, 77, 0, 128, 0, 0, 0], "D:(XA;;FX;;;S-1-1-0;(@User.Title==\"PM\" && (@User.Division==\"Finance\" || @User.Division ==\"Sales\")))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 140, 0, 1, 0, 0, 0, 9, 0, 132, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 16, 4, 0, 0, 0, 80, 0, 77, 0, 128, 249, 16, 0, 0, 0, 68, 0, 105, 0, 118, 0, 105, 0, 115, 0, 105, 0, 111, 0, 110, 0, 16, 14, 0, 0, 0, 70, 0, 105, 0, 110, 0, 97, 0, 110, 0, 99, 0, 101, 0, 128, 249, 16, 0, 0, 0, 68, 0, 105, 0, 118, 0, 105, 0, 115, 0, 105, 0, 111, 0, 110, 0, 16, 10, 0, 0, 0, 83, 0, 97, 0, 108, 0, 101, 0, 115, 0, 128, 161, 160, 0, 0, 0], "D:(XD;;CC;;;S-1-2-3;(@User.Title == @User.Title))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 10, 0, 56, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 128, 0], "D:(XD;;FX;;;S-1-1-0;(@User.Project Any_of @Resource.Project))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 10, 0, 64, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 250, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 136, 0], "D:(XD;;FX;;;S-1-1-0;(@User.Title != \"PM\"))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 60, 0, 1, 0, 0, 0, 10, 0, 52, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 16, 4, 0, 0, 0, 80, 0, 77, 0, 129, 0, 0, 0], "D:(XD;;FX;;;WD;(!(@USER.Project Not_Any_of 1)))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 10, 0, 56, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 143, 162], "D:(XD;;FX;;;WD;(@USER.Project Any_of \"pink\"))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 68, 0, 1, 0, 0, 0, 10, 0, 60, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 16, 8, 0, 0, 0, 112, 0, 105, 0, 110, 0, 107, 0, 136, 0, 0, 0], "D:(XD;;FX;;;WD;(@USER.Project Any_of 1))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 10, 0, 56, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 136, 0], "D:AI(XA;OICI;FA;;;WD;(OctetStringType==##1#2#3##))": [1, 0, 4, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 80, 0, 1, 0, 0, 0, 9, 3, 72, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 248, 30, 0, 0, 0, 79, 0, 99, 0, 116, 0, 101, 0, 116, 0, 83, 0, 116, 0, 114, 0, 105, 0, 110, 0, 103, 0, 84, 0, 121, 0, 112, 0, 101, 0, 24, 4, 0, 0, 0, 1, 2, 3, 0, 128, 0, 0, 0], "D:AI(XA;OICI;FA;;;WD;(OctetStringType==#01020300))": [1, 0, 4, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 80, 0, 1, 0, 0, 0, 9, 3, 72, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 248, 30, 0, 0, 0, 79, 0, 99, 0, 116, 0, 101, 0, 116, 0, 83, 0, 116, 0, 114, 0, 105, 0, 110, 0, 103, 0, 84, 0, 121, 0, 112, 0, 101, 0, 24, 4, 0, 0, 0, 1, 2, 3, 0, 128, 0, 0, 0], "O:S-1-1-0D:(XA;;0;;;WD;(Member_Of SID(S-1-1-0)))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x0;;;WD;(Member_Of SID(S-1-1-0)))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1;;;WD;(Member_of_Any{SID(AS),SID(WD)}))": [1, 0, 4, 128, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 34, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 18, 1, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 139, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_Of{SID(S-1-1-0)}))": [1, 0, 4, 128, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of SID(S-1-1-0)))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of(SID(S-1-1-0))))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_Any SID(S-1-1-0)))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 139, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-1-0), SID(S-1-222-333)}))": [1, 0, 4, 128, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 34, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 222, 77, 1, 0, 0, 139, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-1-334), SID(S-1-222-333)}))": [1, 0, 4, 128, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 34, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 78, 1, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 222, 77, 1, 0, 0, 139, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of{SID(S-1-1-0)}))": [1, 0, 4, 128, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(mEMBER_of{SID(S-1-1-0)}))": [1, 0, 4, 128, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(member_of{SID(S-1-1-0)}))": [1, 0, 4, 128, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;;;;WD;(Member_Of SID(S-1-1-0)))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/AuthenticationSilo == \"siloname\"))": [1, 0, 4, 128, 136, 0, 0, 0, 148, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 116, 0, 1, 0, 0, 0, 9, 3, 108, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 54, 0, 0, 0, 97, 0, 100, 0, 58, 0, 47, 0, 47, 0, 101, 0, 120, 0, 116, 0, 47, 0, 65, 0, 117, 0, 116, 0, 104, 0, 101, 0, 110, 0, 116, 0, 105, 0, 99, 0, 97, 0, 116, 0, 105, 0, 111, 0, 110, 0, 83, 0, 105, 0, 108, 0, 111, 0, 16, 16, 0, 0, 0, 115, 0, 105, 0, 108, 0, 111, 0, 110, 0, 97, 0, 109, 0, 101, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0]} \ No newline at end of file
diff --git a/libcli/security/tests/windows/non_canonical.txt b/libcli/security/tests/windows/non_canonical.txt
new file mode 100644
index 0000000..5506d9b
--- /dev/null
+++ b/libcli/security/tests/windows/non_canonical.txt
@@ -0,0 +1,50 @@
+D:(A;;CC;;;BA)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU) -> D:(A;;CC;;;BA)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPLORC;;;AU)
+D:(A;;RP;;;WD)(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)(A;;RPLCLORC;;;AU)(A;;RPWPCRLCLOCCRCWDWOSW;;;BO)(A;CI;RPWPCRLCLOCCRCWDWOSDSW;;;BA)(A;;RPWPCRLCLOCCDCRCWDWOSDDTSW;;;SY)(A;CI;RPWPCRLCLOCCDCRCWDWOSDDTSW;;;ES)(A;CI;LC;;;RU)(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;;RP;c7407360-20bf-11d0-a768-00aa006e0529;;RU)(OA;CIIO;RPLCLORC;;bf967a9c-0de6-11d0-a285-00aa003049e2;RU)(A;;RPRC;;;RU)(OA;CIIO;RPLCLORC;;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(A;;LCRPLORC;;;ED)(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)(OA;CIIO;RPLCLORC;;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;RU)(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;AU)(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967aba-0de6-11d0-a285-00aa003049e2;ED)(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a9c-0de6-11d0-a285-00aa003049e2;ED)(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a86-0de6-11d0-a285-00aa003049e2;ED)(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;NO)(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)(OA;;CR;e2a36dc9-ae17-47c3-b58b-be34c55ba633;;SU)(OA;;CR;280f369c-67c7-438e-ae98-1d46f3c6f541;;AU)(OA;;CR;ccc2dc7d-a6ad-4a7a-8846-c04e3cc53501;;AU)(OA;;CR;05c74c5e-4deb-43b4-bd9f-86664c2a7fd5;;AU)S:(AU;SA;WDWOWP;;;WD) -> D:(A;;RP;;;WD)(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)(A;;LCRPLORC;;;AU)(A;;CCLCSWRPWPLOCRRCWDWO;;;BO)(A;CI;CCLCSWRPWPLOCRSDRCWDWO;;;BA)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;CI;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;ES)(A;CI;LC;;;RU)(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;;RP;c7407360-20bf-11d0-a768-00aa006e0529;;RU)(OA;CIIO;LCRPLORC;;bf967a9c-0de6-11d0-a285-00aa003049e2;RU)(A;;RPRC;;;RU)(OA;CIIO;LCRPLORC;;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(A;;LCRPLORC;;;ED)(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIO;LCRPLORC;;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;RU)(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;AU)(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967aba-0de6-11d0-a285-00aa003049e2;ED)(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a9c-0de6-11d0-a285-00aa003049e2;ED)(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a86-0de6-11d0-a285-00aa003049e2;ED)(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;NO)(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)(OA;;CR;e2a36dc9-ae17-47c3-b58b-be34c55ba633;;SU)(OA;;CR;280f369c-67c7-438e-ae98-1d46f3c6f541;;AU)(OA;;CR;ccc2dc7d-a6ad-4a7a-8846-c04e3cc53501;;AU)(OA;;CR;05c74c5e-4deb-43b4-bd9f-86664c2a7fd5;;AU)S:(AU;SA;WPWDWO;;;WD)
+D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;AO)(A;;WPRPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPCRLCLORCSDDT;;;CO)(OA;;WP;4c164200-20c0-11d0-a768-00aa006e0529;;CO)(A;;RPLCLORC;;;AU)(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;WD)(A;;CCDC;;;PS)(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)(OA;;RPWP;bf967a7f-0de6-11d0-a285-00aa003049e2;;SY)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;PS)(OA;;RPWP;77B5B886-944A-11d1-AEBD-0000F80367C1;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;CO)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;CO)(OA;;WP;3e0abfd0-126a-11d0-a060-00aa006c33ed;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967950-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967953-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;S-1-5-32-560) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;AO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPDTLOCRSDRC;;;CO)(OA;;WP;4c164200-20c0-11d0-a768-00aa006e0529;;CO)(A;;LCRPLORC;;;AU)(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;WD)(A;;CCDC;;;PS)(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)(OA;;RPWP;bf967a7f-0de6-11d0-a285-00aa003049e2;;SY)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;PS)(OA;;RPWP;77b5b886-944a-11d1-aebd-0000f80367c1;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;CO)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;CO)(OA;;WP;3e0abfd0-126a-11d0-a060-00aa006c33ed;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967950-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967953-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;S-1-5-32-560)
+D:(A;;RPLCLORC;;;BO)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU) -> D:(A;;LCRPLORC;;;BO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPLORC;;;AU)
+D:(A;;WPCRCCDCLCLORCWOWDSDDTSWRP;;;BO)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;AO)(A;;RPWPCRCCDCLCLORCWOWDSDSWDT;;;SY)(A;;RPCRLCLORCSDDT;;;CO)(OA;;WP;4c164200-20c0-11d0-a768-00aa006e0529;;CO)(A;;RPLCLORC;;;AU)(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;WD)(A;;CCDC;;;PS)(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)(OA;;RPWP;bf967a7f-0de6-11d0-a285-00aa003049e2;;SY)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;PS)(OA;;RPWP;77B5B886-944A-11d1-AEBD-0000F80367C1;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;CO)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;CO)(OA;;WP;3e0abfd0-126a-11d0-a060-00aa006c33ed;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967950-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967953-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;AO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPDTLOCRSDRC;;;CO)(OA;;WP;4c164200-20c0-11d0-a768-00aa006e0529;;CO)(A;;LCRPLORC;;;AU)(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;WD)(A;;CCDC;;;PS)(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)(OA;;RPWP;bf967a7f-0de6-11d0-a285-00aa003049e2;;SY)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;PS)(OA;;RPWP;77b5b886-944a-11d1-aebd-0000f80367c1;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;CO)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;CO)(OA;;WP;3e0abfd0-126a-11d0-a060-00aa006c33ed;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967950-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967953-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU)
+D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPLORC;;;AU)
+D:(A;;;;;BO)(A;;;;;AO)(A;;;;;SY)(A;;RPCRLCLORCSDDT;;;CO)(OA;;WP;4c164200-20c0-11d0-a768-00aa006e0529;;CO)(A;;RPLCLORC;;;AU)(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;WD)(A;;CCDC;;;PS)(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)(OA;;RPWP;bf967a7f-0de6-11d0-a285-00aa003049e2;;SY)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;PS)(OA;;RPWP;77B5B886-944A-11d1-AEBD-0000F80367C1;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;CO)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;CO)(OA;;WP;3e0abfd0-126a-11d0-a060-00aa006c33ed;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967950-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967953-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU) -> D:(A;;;;;BO)(A;;;;;AO)(A;;;;;SY)(A;;LCRPDTLOCRSDRC;;;CO)(OA;;WP;4c164200-20c0-11d0-a768-00aa006e0529;;CO)(A;;LCRPLORC;;;AU)(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;WD)(A;;CCDC;;;PS)(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)(OA;;RPWP;bf967a7f-0de6-11d0-a285-00aa003049e2;;SY)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;PS)(OA;;RPWP;77b5b886-944a-11d1-aebd-0000f80367c1;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;CO)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;CO)(OA;;WP;3e0abfd0-126a-11d0-a060-00aa006c33ed;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967950-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967953-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU)
+D:(A;;RPLCLORC;;;AU) -> D:(A;;LCRPLORC;;;AU)
+D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;AO)(A;;RPLCLORC;;;PS)(OA;;CR;ab721a55-1e2f-11d0-9819-00aa0040529b;;AU)(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPLORC;;;AU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;AO)(A;;LCRPLORC;;;PS)(OA;;CR;ab721a55-1e2f-11d0-9819-00aa0040529b;;AU)(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU)
+D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;CO) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPLORC;;;AU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;CO)
+D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU)S:(AU;SA;CRWP;;;WD) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPLORC;;;AU)S:(AU;SA;WPCR;;;WD)
+D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSWRP;;;BO)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;AO)(A;;RPLCLORC;;;PS)(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;PS)(OA;;CR;ab721a54-1e2f-11d0-9819-00aa0040529b;;PS)(OA;;CR;ab721a56-1e2f-11d0-9819-00aa0040529b;;PS)(OA;;RPWP;77B5B886-944A-11d1-AEBD-0000F80367C1;;PS)(OA;;RPWP;E45795B2-9455-11d1-AEBD-0000F80367C1;;PS)(OA;;RPWP;E45795B3-9455-11d1-AEBD-0000F80367C1;;PS)(OA;;RP;037088f8-0ae1-11d2-b422-00a0c968f939;;RD)(OA;;RP;4c164200-20c0-11d0-a768-00aa006e0529;;RD)(OA;;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;;RD)(A;;RC;;;AU)(OA;;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;;AU)(OA;;RP;77B5B886-944A-11d1-AEBD-0000F80367C1;;AU)(OA;;RP;E45795B3-9455-11d1-AEBD-0000F80367C1;;AU)(OA;;RP;e48d0154-bcf8-11d1-8702-00c04fb96050;;AU)(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;WD)(OA;;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;;RD)(OA;;RPWP;bf967a7f-0de6-11d0-a285-00aa003049e2;;SY)(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU)(OA;;WPRP;6db69a1c-9422-11d1-aebd-0000f80367c1;;SU) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;AO)(A;;LCRPLORC;;;PS)(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;PS)(OA;;CR;ab721a54-1e2f-11d0-9819-00aa0040529b;;PS)(OA;;CR;ab721a56-1e2f-11d0-9819-00aa0040529b;;PS)(OA;;RPWP;77b5b886-944a-11d1-aebd-0000f80367c1;;PS)(OA;;RPWP;e45795b2-9455-11d1-aebd-0000f80367c1;;PS)(OA;;RPWP;e45795b3-9455-11d1-aebd-0000f80367c1;;PS)(OA;;RP;037088f8-0ae1-11d2-b422-00a0c968f939;;RD)(OA;;RP;4c164200-20c0-11d0-a768-00aa006e0529;;RD)(OA;;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;;RD)(A;;RC;;;AU)(OA;;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;;AU)(OA;;RP;77b5b886-944a-11d1-aebd-0000f80367c1;;AU)(OA;;RP;e45795b3-9455-11d1-aebd-0000f80367c1;;AU)(OA;;RP;e48d0154-bcf8-11d1-8702-00c04fb96050;;AU)(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;WD)(OA;;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;;RD)(OA;;RPWP;bf967a7f-0de6-11d0-a285-00aa003049e2;;SY)(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU)(OA;;RPWP;6db69a1c-9422-11d1-aebd-0000f80367c1;;SU)
+D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)
+D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU)(A;;LCRPLORC;;;ED) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPLORC;;;AU)(A;;LCRPLORC;;;ED)
+D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)(OA;;CCDC;bf967a86-0de6-11d0-a285-00aa003049e2;;AO)(OA;;CCDC;bf967aba-0de6-11d0-a285-00aa003049e2;;AO)(OA;;CCDC;bf967a9c-0de6-11d0-a285-00aa003049e2;;AO)(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)(A;;RPLCLORC;;;AU)(A;;LCRPLORC;;;ED)(OA;;CCDC;4828CC14-1437-45bc-9B07-AD6F015E5F28;;AO) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BO)(OA;;CCDC;bf967a86-0de6-11d0-a285-00aa003049e2;;AO)(OA;;CCDC;bf967aba-0de6-11d0-a285-00aa003049e2;;AO)(OA;;CCDC;bf967a9c-0de6-11d0-a285-00aa003049e2;;AO)(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)(A;;LCRPLORC;;;AU)(A;;LCRPLORC;;;ED)(OA;;CCDC;4828cc14-1437-45bc-9b07-ad6f015e5f28;;AO)
+D:(A;;RPWPCRCCDCLCLORCWOWDSW;;;BO)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU) -> D:(A;;CCDCLCSWRPWPLOCRRCWDWO;;;BO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPLORC;;;AU)
+D:(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU) -> D:(A;CI;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPLORC;;;AU)
+S:D:P -> D:PS:
+S:D: -> D:S:
+D:(A;;123456789;;;LG) -> D:(A;;0x75bcd15;;;LG)
+D:(A;;01234567;;;LG) -> D:(A;;0x53977;;;LG)
+D:(A;;16;;;LG) -> D:(A;;RP;;;LG)
+D:(A;;17;;;LG) -> D:(A;;CCRP;;;LG)
+D:(A;;0xff;;;LG) -> D:(A;;CCDCLCSWRPWPDTLO;;;LG)
+D:(A;;0xf01ff;;;LG) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;LG)
+D:(A;;0xe00f0000;;;LG) -> D:(A;;SDRCWDWOGXGWGR;;;LG)
+D:ARPAI(A;;GA;;;SY) -> D:PARAI(A;;GA;;;SY)
+D:AIPAR(A;;GA;;;SY) -> D:PARAI(A;;GA;;;SY)
+D:PARP(A;;GA;;;SY) -> D:PAR(A;;GA;;;SY)
+D:PPPPPPPPPPPP(A;;GA;;;SY) -> D:P(A;;GA;;;SY)
+D:(A;;CC;;;S-1-21474836480-32-579) -> D:(A;;CC;;;S-1-0x500000000-32-579)
+D:(A;;GA;;;S-1-5000000000-30-40) -> D:(A;;GA;;;S-1-0x12A05F200-30-40)
+D:(A;;GA;;;S-1-0x2-3-4) -> D:(A;;GA;;;S-1-2-3-4)
+D:(A;;GA;;;S-1-0x20-3-4) -> D:(A;;GA;;;S-1-32-3-4)
+D:(A;;GA;;;S-1-3-0x00000002-3-4) -> D:(A;;GA;;;S-1-3-2-3-4)
+D:(A;;GA;;;S-1-3-0xffffffff-3-4) -> D:(A;;GA;;;S-1-3-4294967295-3-4)
+D:(A;;GA;;;S-1-5-21-0x1-0x2-0x3-513) -> D:(A;;GA;;;S-1-5-21-1-2-3-513)
+D:(A;;GA;;;S-1-5-21-2447931902-1787058256-3961074038-0x4b1) -> D:(A;;GA;;;S-1-5-21-2447931902-1787058256-3961074038-1201)
+O:S-1-2-0x200D: -> O:S-1-2-512D:
+O:S-1-2-0x2D:(A;;GA;;;LG) -> O:S-1-2-2D:(A;;GA;;;LG)
+D:(A;;0x00654321;;;WD)(A;;0x00abc101;;;S-1-5-21-11111111-22222222-33333333-101)(A;;0x00abc102;;;S-1-5-21-11111111-22222222-33333333-102)(A;;0x00abc103;;;S-1-5-21-11111111-22222222-33333333-103)(A;;0x00abc104;;;S-1-5-21-11111111-22222222-33333333-104)(A;;0x00abc105;;;S-1-5-21-11111111-22222222-33333333-105)(A;;0x00abc106;;;S-1-5-21-11111111-22222222-33333333-106)(A;;0x00abc107;;;S-1-5-21-11111111-22222222-33333333-107)(A;;0x00abc108;;;S-1-5-21-11111111-22222222-33333333-108)(A;;0x00abc109;;;S-1-5-21-11111111-22222222-33333333-109)(A;;0x00abc110;;;S-1-5-21-11111111-22222222-33333333-110)(A;;0x00abc111;;;S-1-5-21-11111111-22222222-33333333-111)(A;;0x00abc112;;;S-1-5-21-11111111-22222222-33333333-112)(A;;0x00abc113;;;S-1-5-21-11111111-22222222-33333333-113)(A;;0x00abc114;;;S-1-5-21-11111111-22222222-33333333-114)(A;;0x00abc115;;;S-1-5-21-11111111-22222222-33333333-115)(A;;0x00abc116;;;S-1-5-21-11111111-22222222-33333333-116)(A;;0x00abc117;;;S-1-5-21-11111111-22222222-33333333-117)(A;;0x00abc118;;;S-1-5-21-11111111-22222222-33333333-118)(A;;0x00abc119;;;S-1-5-21-11111111-22222222-33333333-119)(A;;0x00abc120;;;S-1-5-21-11111111-22222222-33333333-120)(A;;0x00abc121;;;S-1-5-21-11111111-22222222-33333333-121)(A;;0x00abc122;;;S-1-5-21-11111111-22222222-33333333-122)(A;;0x00abc123;;;S-1-5-21-11111111-22222222-33333333-123)(A;;0x00abc124;;;S-1-5-21-11111111-22222222-33333333-124)(A;;0x00abc125;;;S-1-5-21-11111111-22222222-33333333-125)(A;;0x00abc126;;;S-1-5-21-11111111-22222222-33333333-126)(A;;0x00abc127;;;S-1-5-21-11111111-22222222-33333333-127)(A;;0x00abc128;;;S-1-5-21-11111111-22222222-33333333-128)(A;;0x00abc129;;;S-1-5-21-11111111-22222222-33333333-129)(A;;0x00abc130;;;S-1-5-21-11111111-22222222-33333333-130)(A;;0x00abc131;;;S-1-5-21-11111111-22222222-33333333-131)(A;;0x00abc132;;;S-1-5-21-11111111-22222222-33333333-132)(A;;0x00abc133;;;S-1-5-21-11111111-22222222-33333333-133)(A;;0x00abc134;;;S-1-5-21-11111111-22222222-33333333-134)(A;;0x00abc135;;;S-1-5-21-11111111-22222222-33333333-135)(A;;0x00abc136;;;S-1-5-21-11111111-22222222-33333333-136)(A;;0x00abc137;;;S-1-5-21-11111111-22222222-33333333-137)(A;;0x00abc138;;;S-1-5-21-11111111-22222222-33333333-138)(A;;0x00abc139;;;S-1-5-21-11111111-22222222-33333333-139)(A;;0x00abc140;;;S-1-5-21-11111111-22222222-33333333-140)(A;;0x00abc141;;;S-1-5-21-11111111-22222222-33333333-141)(A;;0x00abc142;;;S-1-5-21-11111111-22222222-33333333-142)(A;;0x00abc143;;;S-1-5-21-11111111-22222222-33333333-143)(A;;0x00abc144;;;S-1-5-21-11111111-22222222-33333333-144)(A;;0x00abc145;;;S-1-5-21-11111111-22222222-33333333-145)(A;;0x00abc146;;;S-1-5-21-11111111-22222222-33333333-146)(A;;0x00abc147;;;S-1-5-21-11111111-22222222-33333333-147)(A;;0x00abc148;;;S-1-5-21-11111111-22222222-33333333-148)(A;;0x00abc149;;;S-1-5-21-11111111-22222222-33333333-149)(A;;0x00abc150;;;S-1-5-21-11111111-22222222-33333333-150)(A;;0x00abc151;;;S-1-5-21-11111111-22222222-33333333-151)(A;;0x00abc152;;;S-1-5-21-11111111-22222222-33333333-152)(A;;0x00abc153;;;S-1-5-21-11111111-22222222-33333333-153)(A;;0x00abc154;;;S-1-5-21-11111111-22222222-33333333-154)(A;;0x00abc155;;;S-1-5-21-11111111-22222222-33333333-155)(A;;0x00abc156;;;S-1-5-21-11111111-22222222-33333333-156)(A;;0x00abc157;;;S-1-5-21-11111111-22222222-33333333-157)(A;;0x00abc158;;;S-1-5-21-11111111-22222222-33333333-158)(A;;0x00abc159;;;S-1-5-21-11111111-22222222-33333333-159)(A;;0x00abc160;;;S-1-5-21-11111111-22222222-33333333-160)(A;;0x00abc161;;;S-1-5-21-11111111-22222222-33333333-161)(A;;0x00abc162;;;S-1-5-21-11111111-22222222-33333333-162)(A;;0x00abc163;;;S-1-5-21-11111111-22222222-33333333-163)(A;;0x00abc164;;;S-1-5-21-11111111-22222222-33333333-164)(A;;0x00abc165;;;S-1-5-21-11111111-22222222-33333333-165)(A;;0x00abc166;;;S-1-5-21-11111111-22222222-33333333-166)(A;;0x00abc167;;;S-1-5-21-11111111-22222222-33333333-167)(A;;0x00abc168;;;S-1-5-21-11111111-22222222-33333333-168)(A;;0x00abc169;;;S-1-5-21-11111111-22222222-33333333-169)(A;;0x00abc170;;;S-1-5-21-11111111-22222222-33333333-170)(A;;0x00abc171;;;S-1-5-21-11111111-22222222-33333333-171)(A;;0x00abc172;;;S-1-5-21-11111111-22222222-33333333-172)(A;;0x00abc173;;;S-1-5-21-11111111-22222222-33333333-173)(A;;0x00abc174;;;S-1-5-21-11111111-22222222-33333333-174)(A;;0x00abc175;;;S-1-5-21-11111111-22222222-33333333-175)(A;;0x00abc176;;;S-1-5-21-11111111-22222222-33333333-176)(A;;0x00abc177;;;S-1-5-21-11111111-22222222-33333333-177)(A;;0x00abc178;;;S-1-5-21-11111111-22222222-33333333-178)(A;;0x00abc179;;;S-1-5-21-11111111-22222222-33333333-179)(A;;0x00abc180;;;S-1-5-21-11111111-22222222-33333333-180)(A;;0x00abc181;;;S-1-5-21-11111111-22222222-33333333-181)(A;;0x00abc182;;;S-1-5-21-11111111-22222222-33333333-182)(A;;0x00abc183;;;S-1-5-21-11111111-22222222-33333333-183)(A;;0x00abc184;;;S-1-5-21-11111111-22222222-33333333-184)(A;;0x00abc185;;;S-1-5-21-11111111-22222222-33333333-185)(A;;0x00abc186;;;S-1-5-21-11111111-22222222-33333333-186)(A;;0x00abc187;;;S-1-5-21-11111111-22222222-33333333-187)(A;;0x00abc188;;;S-1-5-21-11111111-22222222-33333333-188)(A;;0x00abc189;;;S-1-5-21-11111111-22222222-33333333-189)(A;;0x00abc190;;;S-1-5-21-11111111-22222222-33333333-190)(A;;0x00abc191;;;S-1-5-21-11111111-22222222-33333333-191)(A;;0x00abc192;;;S-1-5-21-11111111-22222222-33333333-192)(A;;0x00abc193;;;S-1-5-21-11111111-22222222-33333333-193)(A;;0x00abc194;;;S-1-5-21-11111111-22222222-33333333-194)(A;;0x00abc195;;;S-1-5-21-11111111-22222222-33333333-195)(A;;0x00abc196;;;S-1-5-21-11111111-22222222-33333333-196)(A;;0x00abc197;;;S-1-5-21-11111111-22222222-33333333-197)(A;;0x00abc198;;;S-1-5-21-11111111-22222222-33333333-198)(A;;0x00abc199;;;S-1-5-21-11111111-22222222-33333333-199)(A;;0x00abc200;;;S-1-5-21-11111111-22222222-33333333-200)(A;;0x00abc201;;;S-1-5-21-11111111-22222222-33333333-201)(A;;0x00abc202;;;S-1-5-21-11111111-22222222-33333333-202)(A;;0x00abc203;;;S-1-5-21-11111111-22222222-33333333-203)(A;;0x00abc204;;;S-1-5-21-11111111-22222222-33333333-204)(A;;0x00abc205;;;S-1-5-21-11111111-22222222-33333333-205)(A;;0x00abc206;;;S-1-5-21-11111111-22222222-33333333-206)(A;;0x00abc207;;;S-1-5-21-11111111-22222222-33333333-207)(A;;0x00abc208;;;S-1-5-21-11111111-22222222-33333333-208)(A;;0x00abc209;;;S-1-5-21-11111111-22222222-33333333-209)(A;;0x00abc210;;;S-1-5-21-11111111-22222222-33333333-210)(A;;0x00abc211;;;S-1-5-21-11111111-22222222-33333333-211)(A;;0x00abc212;;;S-1-5-21-11111111-22222222-33333333-212)(A;;0x00abc213;;;S-1-5-21-11111111-22222222-33333333-213)(A;;0x00abc214;;;S-1-5-21-11111111-22222222-33333333-214)(A;;0x00abc215;;;S-1-5-21-11111111-22222222-33333333-215)(A;;0x00abc216;;;S-1-5-21-11111111-22222222-33333333-216)(A;;0x00abc217;;;S-1-5-21-11111111-22222222-33333333-217)(A;;0x00abc218;;;S-1-5-21-11111111-22222222-33333333-218)(A;;0x00abc219;;;S-1-5-21-11111111-22222222-33333333-219)(A;;0x00abc220;;;S-1-5-21-11111111-22222222-33333333-220)(A;;0x00abc221;;;S-1-5-21-11111111-22222222-33333333-221)(A;;0x00abc222;;;S-1-5-21-11111111-22222222-33333333-222)(A;;0x00abc223;;;S-1-5-21-11111111-22222222-33333333-223)(A;;0x00abc224;;;S-1-5-21-11111111-22222222-33333333-224)(A;;0x00abc225;;;S-1-5-21-11111111-22222222-33333333-225)(A;;0x00abc226;;;S-1-5-21-11111111-22222222-33333333-226)(A;;0x00abc227;;;S-1-5-21-11111111-22222222-33333333-227)(A;;0x00abc228;;;S-1-5-21-11111111-22222222-33333333-228)(A;;0x00abc229;;;S-1-5-21-11111111-22222222-33333333-229)(A;;0x00abc230;;;S-1-5-21-11111111-22222222-33333333-230)(A;;0x00abc231;;;S-1-5-21-11111111-22222222-33333333-231)(A;;0x00abc232;;;S-1-5-21-11111111-22222222-33333333-232)(A;;0x00abc233;;;S-1-5-21-11111111-22222222-33333333-233)(A;;0x00abc234;;;S-1-5-21-11111111-22222222-33333333-234)(A;;0x00abc235;;;S-1-5-21-11111111-22222222-33333333-235)(A;;0x00abc236;;;S-1-5-21-11111111-22222222-33333333-236)(A;;0x00abc237;;;S-1-5-21-11111111-22222222-33333333-237)(A;;0x00abc238;;;S-1-5-21-11111111-22222222-33333333-238)(A;;0x00abc239;;;S-1-5-21-11111111-22222222-33333333-239)(A;;0x00abc240;;;S-1-5-21-11111111-22222222-33333333-240)(A;;0x00abc241;;;S-1-5-21-11111111-22222222-33333333-241)(A;;0x00abc242;;;S-1-5-21-11111111-22222222-33333333-242)(A;;0x00abc243;;;S-1-5-21-11111111-22222222-33333333-243)(A;;0x00abc244;;;S-1-5-21-11111111-22222222-33333333-244)(A;;0x00abc245;;;S-1-5-21-11111111-22222222-33333333-245)(A;;0x00abc246;;;S-1-5-21-11111111-22222222-33333333-246)(A;;0x00abc247;;;S-1-5-21-11111111-22222222-33333333-247)(A;;0x00abc248;;;S-1-5-21-11111111-22222222-33333333-248)(A;;0x00abc249;;;S-1-5-21-11111111-22222222-33333333-249)(A;;0x00abc250;;;S-1-5-21-11111111-22222222-33333333-250)(A;;0x00abc251;;;S-1-5-21-11111111-22222222-33333333-251)(A;;0x00abc252;;;S-1-5-21-11111111-22222222-33333333-252)(A;;0x00abc253;;;S-1-5-21-11111111-22222222-33333333-253)(A;;0x00abc254;;;S-1-5-21-11111111-22222222-33333333-254)(A;;0x00abc255;;;S-1-5-21-11111111-22222222-33333333-255)(A;;0x00abc256;;;S-1-5-21-11111111-22222222-33333333-256)(A;;0x00abc257;;;S-1-5-21-11111111-22222222-33333333-257)(A;;0x00abc258;;;S-1-5-21-11111111-22222222-33333333-258)(A;;0x00abc259;;;S-1-5-21-11111111-22222222-33333333-259)(A;;0x00abc260;;;S-1-5-21-11111111-22222222-33333333-260)(A;;0x00abc261;;;S-1-5-21-11111111-22222222-33333333-261)(A;;0x00abc262;;;S-1-5-21-11111111-22222222-33333333-262)(A;;0x00abc263;;;S-1-5-21-11111111-22222222-33333333-263)(A;;0x00abc264;;;S-1-5-21-11111111-22222222-33333333-264)(A;;0x00abc265;;;S-1-5-21-11111111-22222222-33333333-265)(A;;0x00abc266;;;S-1-5-21-11111111-22222222-33333333-266)(A;;0x00abc267;;;S-1-5-21-11111111-22222222-33333333-267)(A;;0x00abc268;;;S-1-5-21-11111111-22222222-33333333-268)(A;;0x00abc269;;;S-1-5-21-11111111-22222222-33333333-269)(A;;0x00abc270;;;S-1-5-21-11111111-22222222-33333333-270)(A;;0x00abc271;;;S-1-5-21-11111111-22222222-33333333-271)(A;;0x00abc272;;;S-1-5-21-11111111-22222222-33333333-272)(A;;0x00abc273;;;S-1-5-21-11111111-22222222-33333333-273)(A;;0x00abc274;;;S-1-5-21-11111111-22222222-33333333-274)(A;;0x00abc275;;;S-1-5-21-11111111-22222222-33333333-275)(A;;0x00abc276;;;S-1-5-21-11111111-22222222-33333333-276)(A;;0x00abc277;;;S-1-5-21-11111111-22222222-33333333-277)(A;;0x00abc278;;;S-1-5-21-11111111-22222222-33333333-278)(A;;0x00abc279;;;S-1-5-21-11111111-22222222-33333333-279)(A;;0x00abc280;;;S-1-5-21-11111111-22222222-33333333-280)(A;;0x00abc281;;;S-1-5-21-11111111-22222222-33333333-281)(A;;0x00abc282;;;S-1-5-21-11111111-22222222-33333333-282)(A;;0x00abc283;;;S-1-5-21-11111111-22222222-33333333-283)(A;;0x00abc284;;;S-1-5-21-11111111-22222222-33333333-284)(A;;0x00abc285;;;S-1-5-21-11111111-22222222-33333333-285)(A;;0x00abc286;;;S-1-5-21-11111111-22222222-33333333-286)(A;;0x00abc287;;;S-1-5-21-11111111-22222222-33333333-287)(A;;0x00abc288;;;S-1-5-21-11111111-22222222-33333333-288)(A;;0x00abc289;;;S-1-5-21-11111111-22222222-33333333-289)(A;;0x00abc290;;;S-1-5-21-11111111-22222222-33333333-290)(A;;0x00abc291;;;S-1-5-21-11111111-22222222-33333333-291)(A;;0x00abc292;;;S-1-5-21-11111111-22222222-33333333-292)(A;;0x00abc293;;;S-1-5-21-11111111-22222222-33333333-293)(A;;0x00abc294;;;S-1-5-21-11111111-22222222-33333333-294)(A;;0x00abc295;;;S-1-5-21-11111111-22222222-33333333-295)(A;;0x00abc296;;;S-1-5-21-11111111-22222222-33333333-296)(A;;0x00abc297;;;S-1-5-21-11111111-22222222-33333333-297)(A;;0x00abc298;;;S-1-5-21-11111111-22222222-33333333-298)(A;;0x00abc299;;;S-1-5-21-11111111-22222222-33333333-299)(A;;0x00abc300;;;S-1-5-21-11111111-22222222-33333333-300)(A;;0x00abc301;;;S-1-5-21-11111111-22222222-33333333-301)(A;;0x00abc302;;;S-1-5-21-11111111-22222222-33333333-302)(A;;0x00abc303;;;S-1-5-21-11111111-22222222-33333333-303)(A;;0x00abc304;;;S-1-5-21-11111111-22222222-33333333-304)(A;;0x00abc305;;;S-1-5-21-11111111-22222222-33333333-305)(A;;0x00abc306;;;S-1-5-21-11111111-22222222-33333333-306)(A;;0x00abc307;;;S-1-5-21-11111111-22222222-33333333-307)(A;;0x00abc308;;;S-1-5-21-11111111-22222222-33333333-308)(A;;0x00abc309;;;S-1-5-21-11111111-22222222-33333333-309)(A;;0x00abc310;;;S-1-5-21-11111111-22222222-33333333-310)(A;;0x00abc311;;;S-1-5-21-11111111-22222222-33333333-311)(A;;0x00abc312;;;S-1-5-21-11111111-22222222-33333333-312)(A;;0x00abc313;;;S-1-5-21-11111111-22222222-33333333-313)(A;;0x00abc314;;;S-1-5-21-11111111-22222222-33333333-314)(A;;0x00abc315;;;S-1-5-21-11111111-22222222-33333333-315)(A;;0x00abc316;;;S-1-5-21-11111111-22222222-33333333-316)(A;;0x00abc317;;;S-1-5-21-11111111-22222222-33333333-317)(A;;0x00abc318;;;S-1-5-21-11111111-22222222-33333333-318)(A;;0x00abc319;;;S-1-5-21-11111111-22222222-33333333-319)(A;;0x00abc320;;;S-1-5-21-11111111-22222222-33333333-320)(A;;0x00abc321;;;S-1-5-21-11111111-22222222-33333333-321)(A;;0x00abc322;;;S-1-5-21-11111111-22222222-33333333-322)(A;;0x00abc323;;;S-1-5-21-11111111-22222222-33333333-323)(A;;0x00abc324;;;S-1-5-21-11111111-22222222-33333333-324)(A;;0x00abc325;;;S-1-5-21-11111111-22222222-33333333-325)(A;;0x00abc326;;;S-1-5-21-11111111-22222222-33333333-326)(A;;0x00abc327;;;S-1-5-21-11111111-22222222-33333333-327)(A;;0x00abc328;;;S-1-5-21-11111111-22222222-33333333-328)(A;;0x00abc329;;;S-1-5-21-11111111-22222222-33333333-329)(A;;0x00abc330;;;S-1-5-21-11111111-22222222-33333333-330)(A;;0x00abc331;;;S-1-5-21-11111111-22222222-33333333-331)(A;;0x00abc332;;;S-1-5-21-11111111-22222222-33333333-332)(A;;0x00abc333;;;S-1-5-21-11111111-22222222-33333333-333)(A;;0x00abc334;;;S-1-5-21-11111111-22222222-33333333-334)(A;;0x00abc335;;;S-1-5-21-11111111-22222222-33333333-335)(A;;0x00abc336;;;S-1-5-21-11111111-22222222-33333333-336)(A;;0x00abc337;;;S-1-5-21-11111111-22222222-33333333-337)(A;;0x00abc338;;;S-1-5-21-11111111-22222222-33333333-338)(A;;0x00abc339;;;S-1-5-21-11111111-22222222-33333333-339)(A;;0x00abc340;;;S-1-5-21-11111111-22222222-33333333-340)(A;;0x00abc341;;;S-1-5-21-11111111-22222222-33333333-341)(A;;0x00abc342;;;S-1-5-21-11111111-22222222-33333333-342)(A;;0x00abc343;;;S-1-5-21-11111111-22222222-33333333-343)(A;;0x00abc344;;;S-1-5-21-11111111-22222222-33333333-344)(A;;0x00abc345;;;S-1-5-21-11111111-22222222-33333333-345)(A;;0x00abc346;;;S-1-5-21-11111111-22222222-33333333-346)(A;;0x00abc347;;;S-1-5-21-11111111-22222222-33333333-347)(A;;0x00abc348;;;S-1-5-21-11111111-22222222-33333333-348)(A;;0x00abc349;;;S-1-5-21-11111111-22222222-33333333-349)(A;;0x00abc350;;;S-1-5-21-11111111-22222222-33333333-350)(A;;0x00abc351;;;S-1-5-21-11111111-22222222-33333333-351)(A;;0x00abc352;;;S-1-5-21-11111111-22222222-33333333-352)(A;;0x00abc353;;;S-1-5-21-11111111-22222222-33333333-353)(A;;0x00abc354;;;S-1-5-21-11111111-22222222-33333333-354)(A;;0x00abc355;;;S-1-5-21-11111111-22222222-33333333-355)(A;;0x00abc356;;;S-1-5-21-11111111-22222222-33333333-356)(A;;0x00abc357;;;S-1-5-21-11111111-22222222-33333333-357)(A;;0x00abc358;;;S-1-5-21-11111111-22222222-33333333-358)(A;;0x00abc359;;;S-1-5-21-11111111-22222222-33333333-359)(A;;0x00abc360;;;S-1-5-21-11111111-22222222-33333333-360)(A;;0x00abc361;;;S-1-5-21-11111111-22222222-33333333-361)(A;;0x00abc362;;;S-1-5-21-11111111-22222222-33333333-362)(A;;0x00abc363;;;S-1-5-21-11111111-22222222-33333333-363)(A;;0x00abc364;;;S-1-5-21-11111111-22222222-33333333-364)(A;;0x00abc365;;;S-1-5-21-11111111-22222222-33333333-365)(A;;0x00abc366;;;S-1-5-21-11111111-22222222-33333333-366)(A;;0x00abc367;;;S-1-5-21-11111111-22222222-33333333-367)(A;;0x00abc368;;;S-1-5-21-11111111-22222222-33333333-368)(A;;0x00abc369;;;S-1-5-21-11111111-22222222-33333333-369)(A;;0x00abc370;;;S-1-5-21-11111111-22222222-33333333-370)(A;;0x00abc371;;;S-1-5-21-11111111-22222222-33333333-371)(A;;0x00abc372;;;S-1-5-21-11111111-22222222-33333333-372)(A;;0x00abc373;;;S-1-5-21-11111111-22222222-33333333-373)(A;;0x00abc374;;;S-1-5-21-11111111-22222222-33333333-374)(A;;0x00abc375;;;S-1-5-21-11111111-22222222-33333333-375)(A;;0x00abc376;;;S-1-5-21-11111111-22222222-33333333-376)(A;;0x00abc377;;;S-1-5-21-11111111-22222222-33333333-377)(A;;0x00abc378;;;S-1-5-21-11111111-22222222-33333333-378)(A;;0x00abc379;;;S-1-5-21-11111111-22222222-33333333-379)(A;;0x00abc380;;;S-1-5-21-11111111-22222222-33333333-380)(A;;0x00abc381;;;S-1-5-21-11111111-22222222-33333333-381)(A;;0x00abc382;;;S-1-5-21-11111111-22222222-33333333-382)(A;;0x00abc383;;;S-1-5-21-11111111-22222222-33333333-383)(A;;0x00abc384;;;S-1-5-21-11111111-22222222-33333333-384)(A;;0x00abc385;;;S-1-5-21-11111111-22222222-33333333-385)(A;;0x00abc386;;;S-1-5-21-11111111-22222222-33333333-386)(A;;0x00abc387;;;S-1-5-21-11111111-22222222-33333333-387)(A;;0x00abc388;;;S-1-5-21-11111111-22222222-33333333-388)(A;;0x00abc389;;;S-1-5-21-11111111-22222222-33333333-389)(A;;0x00abc390;;;S-1-5-21-11111111-22222222-33333333-390)(A;;0x00abc391;;;S-1-5-21-11111111-22222222-33333333-391)(A;;0x00abc392;;;S-1-5-21-11111111-22222222-33333333-392)(A;;0x00abc393;;;S-1-5-21-11111111-22222222-33333333-393)(A;;0x00abc394;;;S-1-5-21-11111111-22222222-33333333-394)(A;;0x00abc395;;;S-1-5-21-11111111-22222222-33333333-395)(A;;0x00abc396;;;S-1-5-21-11111111-22222222-33333333-396)(A;;0x00abc397;;;S-1-5-21-11111111-22222222-33333333-397)(A;;0x00abc398;;;S-1-5-21-11111111-22222222-33333333-398)(A;;0x00abc399;;;S-1-5-21-11111111-22222222-33333333-399)(A;;0x00abc400;;;S-1-5-21-11111111-22222222-33333333-400)(A;;0x00abc401;;;S-1-5-21-11111111-22222222-33333333-401)(A;;0x00abc402;;;S-1-5-21-11111111-22222222-33333333-402)(A;;0x00abc403;;;S-1-5-21-11111111-22222222-33333333-403)(A;;0x00abc404;;;S-1-5-21-11111111-22222222-33333333-404)(A;;0x00abc405;;;S-1-5-21-11111111-22222222-33333333-405)(A;;0x00abc406;;;S-1-5-21-11111111-22222222-33333333-406)(A;;0x00abc407;;;S-1-5-21-11111111-22222222-33333333-407)(A;;0x00abc408;;;S-1-5-21-11111111-22222222-33333333-408)(A;;0x00abc409;;;S-1-5-21-11111111-22222222-33333333-409)(A;;0x00abc410;;;S-1-5-21-11111111-22222222-33333333-410)(A;;0x00abc411;;;S-1-5-21-11111111-22222222-33333333-411)(A;;0x00abc412;;;S-1-5-21-11111111-22222222-33333333-412)(A;;0x00abc413;;;S-1-5-21-11111111-22222222-33333333-413)(A;;0x00abc414;;;S-1-5-21-11111111-22222222-33333333-414)(A;;0x00abc415;;;S-1-5-21-11111111-22222222-33333333-415)(A;;0x00abc416;;;S-1-5-21-11111111-22222222-33333333-416)(A;;0x00abc417;;;S-1-5-21-11111111-22222222-33333333-417)(A;;0x00abc418;;;S-1-5-21-11111111-22222222-33333333-418)(A;;0x00abc419;;;S-1-5-21-11111111-22222222-33333333-419)(A;;0x00abc420;;;S-1-5-21-11111111-22222222-33333333-420)(A;;0x00abc421;;;S-1-5-21-11111111-22222222-33333333-421)(A;;0x00abc422;;;S-1-5-21-11111111-22222222-33333333-422)(A;;0x00abc423;;;S-1-5-21-11111111-22222222-33333333-423)(A;;0x00abc424;;;S-1-5-21-11111111-22222222-33333333-424)(A;;0x00abc425;;;S-1-5-21-11111111-22222222-33333333-425)(A;;0x00abc426;;;S-1-5-21-11111111-22222222-33333333-426)(A;;0x00abc427;;;S-1-5-21-11111111-22222222-33333333-427)(A;;0x00abc428;;;S-1-5-21-11111111-22222222-33333333-428)(A;;0x00abc429;;;S-1-5-21-11111111-22222222-33333333-429)(A;;0x00abc430;;;S-1-5-21-11111111-22222222-33333333-430)(A;;0x00abc431;;;S-1-5-21-11111111-22222222-33333333-431)(A;;0x00abc432;;;S-1-5-21-11111111-22222222-33333333-432)(A;;0x00abc433;;;S-1-5-21-11111111-22222222-33333333-433)(A;;0x00abc434;;;S-1-5-21-11111111-22222222-33333333-434)(A;;0x00abc435;;;S-1-5-21-11111111-22222222-33333333-435)(A;;0x00abc436;;;S-1-5-21-11111111-22222222-33333333-436)(A;;0x00abc437;;;S-1-5-21-11111111-22222222-33333333-437)(A;;0x00abc438;;;S-1-5-21-11111111-22222222-33333333-438)(A;;0x00abc439;;;S-1-5-21-11111111-22222222-33333333-439)(A;;0x00abc440;;;S-1-5-21-11111111-22222222-33333333-440)(A;;0x00abc441;;;S-1-5-21-11111111-22222222-33333333-441)(A;;0x00abc442;;;S-1-5-21-11111111-22222222-33333333-442)(A;;0x00abc443;;;S-1-5-21-11111111-22222222-33333333-443)(A;;0x00abc444;;;S-1-5-21-11111111-22222222-33333333-444)(A;;0x00abc445;;;S-1-5-21-11111111-22222222-33333333-445)(A;;0x00abc446;;;S-1-5-21-11111111-22222222-33333333-446)(A;;0x00abc447;;;S-1-5-21-11111111-22222222-33333333-447)(A;;0x00abc448;;;S-1-5-21-11111111-22222222-33333333-448)(A;;0x00abc449;;;S-1-5-21-11111111-22222222-33333333-449)(A;;0x00abc450;;;S-1-5-21-11111111-22222222-33333333-450)(A;;0x00abc451;;;S-1-5-21-11111111-22222222-33333333-451)(A;;0x00abc452;;;S-1-5-21-11111111-22222222-33333333-452)(A;;0x00abc453;;;S-1-5-21-11111111-22222222-33333333-453)(A;;0x00abc454;;;S-1-5-21-11111111-22222222-33333333-454)(A;;0x00abc455;;;S-1-5-21-11111111-22222222-33333333-455)(A;;0x00abc456;;;S-1-5-21-11111111-22222222-33333333-456)(A;;0x00abc457;;;S-1-5-21-11111111-22222222-33333333-457)(A;;0x00abc458;;;S-1-5-21-11111111-22222222-33333333-458)(A;;0x00abc459;;;S-1-5-21-11111111-22222222-33333333-459)(A;;0x00abc460;;;S-1-5-21-11111111-22222222-33333333-460)(A;;0x00abc461;;;S-1-5-21-11111111-22222222-33333333-461)(A;;0x00abc462;;;S-1-5-21-11111111-22222222-33333333-462)(A;;0x00abc463;;;S-1-5-21-11111111-22222222-33333333-463)(A;;0x00abc464;;;S-1-5-21-11111111-22222222-33333333-464)(A;;0x00abc465;;;S-1-5-21-11111111-22222222-33333333-465)(A;;0x00abc466;;;S-1-5-21-11111111-22222222-33333333-466)(A;;0x00abc467;;;S-1-5-21-11111111-22222222-33333333-467)(A;;0x00abc468;;;S-1-5-21-11111111-22222222-33333333-468)(A;;0x00abc469;;;S-1-5-21-11111111-22222222-33333333-469)(A;;0x00abc470;;;S-1-5-21-11111111-22222222-33333333-470)(A;;0x00abc471;;;S-1-5-21-11111111-22222222-33333333-471)(A;;0x00abc472;;;S-1-5-21-11111111-22222222-33333333-472)(A;;0x00abc473;;;S-1-5-21-11111111-22222222-33333333-473)(A;;0x00abc474;;;S-1-5-21-11111111-22222222-33333333-474)(A;;0x00abc475;;;S-1-5-21-11111111-22222222-33333333-475)(A;;0x00abc476;;;S-1-5-21-11111111-22222222-33333333-476)(A;;0x00abc477;;;S-1-5-21-11111111-22222222-33333333-477)(A;;0x00abc478;;;S-1-5-21-11111111-22222222-33333333-478)(A;;0x00abc479;;;S-1-5-21-11111111-22222222-33333333-479)(A;;0x00abc480;;;S-1-5-21-11111111-22222222-33333333-480)(A;;0x00abc481;;;S-1-5-21-11111111-22222222-33333333-481)(A;;0x00abc482;;;S-1-5-21-11111111-22222222-33333333-482)(A;;0x00abc483;;;S-1-5-21-11111111-22222222-33333333-483)(A;;0x00abc484;;;S-1-5-21-11111111-22222222-33333333-484)(A;;0x00abc485;;;S-1-5-21-11111111-22222222-33333333-485)(A;;0x00abc486;;;S-1-5-21-11111111-22222222-33333333-486)(A;;0x00abc487;;;S-1-5-21-11111111-22222222-33333333-487)(A;;0x00abc488;;;S-1-5-21-11111111-22222222-33333333-488)(A;;0x00abc489;;;S-1-5-21-11111111-22222222-33333333-489)(A;;0x00abc490;;;S-1-5-21-11111111-22222222-33333333-490)(A;;0x00abc491;;;S-1-5-21-11111111-22222222-33333333-491)(A;;0x00abc492;;;S-1-5-21-11111111-22222222-33333333-492)(A;;0x00abc493;;;S-1-5-21-11111111-22222222-33333333-493)(A;;0x00abc494;;;S-1-5-21-11111111-22222222-33333333-494)(A;;0x00abc495;;;S-1-5-21-11111111-22222222-33333333-495)(A;;0x00abc496;;;S-1-5-21-11111111-22222222-33333333-496)(A;;0x00abc497;;;S-1-5-21-11111111-22222222-33333333-497)(A;;0x00abc498;;;S-1-5-21-11111111-22222222-33333333-498)(A;;0x00abc499;;;S-1-5-21-11111111-22222222-33333333-499)(A;;0x00abc500;;;S-1-5-21-11111111-22222222-33333333-500)(A;;0x00abc501;;;S-1-5-21-11111111-22222222-33333333-501)(A;;0x00abc502;;;S-1-5-21-11111111-22222222-33333333-502)(A;;0x00abc503;;;S-1-5-21-11111111-22222222-33333333-503)(A;;0x00abc504;;;S-1-5-21-11111111-22222222-33333333-504)(A;;0x00abc505;;;S-1-5-21-11111111-22222222-33333333-505)(A;;0x00abc506;;;S-1-5-21-11111111-22222222-33333333-506)(A;;0x00abc507;;;S-1-5-21-11111111-22222222-33333333-507)(A;;0x00abc508;;;S-1-5-21-11111111-22222222-33333333-508)(A;;0x00abc509;;;S-1-5-21-11111111-22222222-33333333-509)(A;;0x00abc510;;;S-1-5-21-11111111-22222222-33333333-510)(A;;0x00abc511;;;S-1-5-21-11111111-22222222-33333333-511)(A;;0x00abc512;;;S-1-5-21-11111111-22222222-33333333-512)(A;;0x00abc513;;;S-1-5-21-11111111-22222222-33333333-513)(A;;0x00abc514;;;S-1-5-21-11111111-22222222-33333333-514)(A;;0x00abc515;;;S-1-5-21-11111111-22222222-33333333-515)(A;;0x00abc516;;;S-1-5-21-11111111-22222222-33333333-516)(A;;0x00abc517;;;S-1-5-21-11111111-22222222-33333333-517)(A;;0x00abc518;;;S-1-5-21-11111111-22222222-33333333-518)(A;;0x00abc519;;;S-1-5-21-11111111-22222222-33333333-519)(A;;0x00abc520;;;S-1-5-21-11111111-22222222-33333333-520)(A;;0x00abc521;;;S-1-5-21-11111111-22222222-33333333-521)(A;;0x00abc522;;;S-1-5-21-11111111-22222222-33333333-522)(A;;0x00abc523;;;S-1-5-21-11111111-22222222-33333333-523)(A;;0x00abc524;;;S-1-5-21-11111111-22222222-33333333-524)(A;;0x00abc525;;;S-1-5-21-11111111-22222222-33333333-525)(A;;0x00abc526;;;S-1-5-21-11111111-22222222-33333333-526)(A;;0x00abc527;;;S-1-5-21-11111111-22222222-33333333-527)(A;;0x00abc528;;;S-1-5-21-11111111-22222222-33333333-528)(A;;0x00abc529;;;S-1-5-21-11111111-22222222-33333333-529)(A;;0x00abc530;;;S-1-5-21-11111111-22222222-33333333-530)(A;;0x00abc531;;;S-1-5-21-11111111-22222222-33333333-531)(A;;0x00abc532;;;S-1-5-21-11111111-22222222-33333333-532)(A;;0x00abc533;;;S-1-5-21-11111111-22222222-33333333-533)(A;;0x00abc534;;;S-1-5-21-11111111-22222222-33333333-534)(A;;0x00abc535;;;S-1-5-21-11111111-22222222-33333333-535)(A;;0x00abc536;;;S-1-5-21-11111111-22222222-33333333-536)(A;;0x00abc537;;;S-1-5-21-11111111-22222222-33333333-537)(A;;0x00abc538;;;S-1-5-21-11111111-22222222-33333333-538)(A;;0x00abc539;;;S-1-5-21-11111111-22222222-33333333-539)(A;;0x00abc540;;;S-1-5-21-11111111-22222222-33333333-540)(A;;0x00abc541;;;S-1-5-21-11111111-22222222-33333333-541)(A;;0x00abc542;;;S-1-5-21-11111111-22222222-33333333-542)(A;;0x00abc543;;;S-1-5-21-11111111-22222222-33333333-543)(A;;0x00abc544;;;S-1-5-21-11111111-22222222-33333333-544)(A;;0x00abc545;;;S-1-5-21-11111111-22222222-33333333-545)(A;;0x00abc546;;;S-1-5-21-11111111-22222222-33333333-546)(A;;0x00abc547;;;S-1-5-21-11111111-22222222-33333333-547)(A;;0x00abc548;;;S-1-5-21-11111111-22222222-33333333-548)(A;;0x00abc549;;;S-1-5-21-11111111-22222222-33333333-549)(A;;0x00abc550;;;S-1-5-21-11111111-22222222-33333333-550)(A;;0x00abc551;;;S-1-5-21-11111111-22222222-33333333-551)(A;;0x00abc552;;;S-1-5-21-11111111-22222222-33333333-552)(A;;0x00abc553;;;S-1-5-21-11111111-22222222-33333333-553)(A;;0x00abc554;;;S-1-5-21-11111111-22222222-33333333-554)(A;;0x00abc555;;;S-1-5-21-11111111-22222222-33333333-555)(A;;0x00abc556;;;S-1-5-21-11111111-22222222-33333333-556)(A;;0x00abc557;;;S-1-5-21-11111111-22222222-33333333-557)(A;;0x00abc558;;;S-1-5-21-11111111-22222222-33333333-558)(A;;0x00abc559;;;S-1-5-21-11111111-22222222-33333333-559)(A;;0x00abc560;;;S-1-5-21-11111111-22222222-33333333-560)(A;;0x00abc561;;;S-1-5-21-11111111-22222222-33333333-561)(A;;0x00abc562;;;S-1-5-21-11111111-22222222-33333333-562)(A;;0x00abc563;;;S-1-5-21-11111111-22222222-33333333-563)(A;;0x00abc564;;;S-1-5-21-11111111-22222222-33333333-564)(A;;0x00abc565;;;S-1-5-21-11111111-22222222-33333333-565)(A;;0x00abc566;;;S-1-5-21-11111111-22222222-33333333-566)(A;;0x00abc567;;;S-1-5-21-11111111-22222222-33333333-567)(A;;0x00abc568;;;S-1-5-21-11111111-22222222-33333333-568)(A;;0x00abc569;;;S-1-5-21-11111111-22222222-33333333-569)(A;;0x00abc570;;;S-1-5-21-11111111-22222222-33333333-570)(A;;0x00abc571;;;S-1-5-21-11111111-22222222-33333333-571)(A;;0x00abc572;;;S-1-5-21-11111111-22222222-33333333-572)(A;;0x00abc573;;;S-1-5-21-11111111-22222222-33333333-573)(A;;0x00abc574;;;S-1-5-21-11111111-22222222-33333333-574)(A;;0x00abc575;;;S-1-5-21-11111111-22222222-33333333-575)(A;;0x00abc576;;;S-1-5-21-11111111-22222222-33333333-576)(A;;0x00abc577;;;S-1-5-21-11111111-22222222-33333333-577)(A;;0x00abc578;;;S-1-5-21-11111111-22222222-33333333-578)(A;;0x00abc579;;;S-1-5-21-11111111-22222222-33333333-579)(A;;0x00abc580;;;S-1-5-21-11111111-22222222-33333333-580)(A;;0x00abc581;;;S-1-5-21-11111111-22222222-33333333-581)(A;;0x00abc582;;;S-1-5-21-11111111-22222222-33333333-582)(A;;0x00abc583;;;S-1-5-21-11111111-22222222-33333333-583)(A;;0x00abc584;;;S-1-5-21-11111111-22222222-33333333-584)(A;;0x00abc585;;;S-1-5-21-11111111-22222222-33333333-585)(A;;0x00abc586;;;S-1-5-21-11111111-22222222-33333333-586)(A;;0x00abc587;;;S-1-5-21-11111111-22222222-33333333-587)(A;;0x00abc588;;;S-1-5-21-11111111-22222222-33333333-588)(A;;0x00abc589;;;S-1-5-21-11111111-22222222-33333333-589)(A;;0x00abc590;;;S-1-5-21-11111111-22222222-33333333-590)(A;;0x00abc591;;;S-1-5-21-11111111-22222222-33333333-591)(A;;0x00abc592;;;S-1-5-21-11111111-22222222-33333333-592)(A;;0x00abc593;;;S-1-5-21-11111111-22222222-33333333-593)(A;;0x00abc594;;;S-1-5-21-11111111-22222222-33333333-594)(A;;0x00abc595;;;S-1-5-21-11111111-22222222-33333333-595)(A;;0x00abc596;;;S-1-5-21-11111111-22222222-33333333-596)(A;;0x00abc597;;;S-1-5-21-11111111-22222222-33333333-597)(A;;0x00abc598;;;S-1-5-21-11111111-22222222-33333333-598)(A;;0x00abc599;;;S-1-5-21-11111111-22222222-33333333-599)(A;;0x00abc600;;;S-1-5-21-11111111-22222222-33333333-600) -> D:(A;;0x654321;;;WD)(A;;0xabc101;;;S-1-5-21-11111111-22222222-33333333-101)(A;;0xabc102;;;S-1-5-21-11111111-22222222-33333333-102)(A;;0xabc103;;;S-1-5-21-11111111-22222222-33333333-103)(A;;0xabc104;;;S-1-5-21-11111111-22222222-33333333-104)(A;;0xabc105;;;S-1-5-21-11111111-22222222-33333333-105)(A;;0xabc106;;;S-1-5-21-11111111-22222222-33333333-106)(A;;0xabc107;;;S-1-5-21-11111111-22222222-33333333-107)(A;;0xabc108;;;S-1-5-21-11111111-22222222-33333333-108)(A;;0xabc109;;;S-1-5-21-11111111-22222222-33333333-109)(A;;0xabc110;;;S-1-5-21-11111111-22222222-33333333-110)(A;;0xabc111;;;S-1-5-21-11111111-22222222-33333333-111)(A;;0xabc112;;;S-1-5-21-11111111-22222222-33333333-112)(A;;0xabc113;;;S-1-5-21-11111111-22222222-33333333-113)(A;;0xabc114;;;S-1-5-21-11111111-22222222-33333333-114)(A;;0xabc115;;;S-1-5-21-11111111-22222222-33333333-115)(A;;0xabc116;;;S-1-5-21-11111111-22222222-33333333-116)(A;;0xabc117;;;S-1-5-21-11111111-22222222-33333333-117)(A;;0xabc118;;;S-1-5-21-11111111-22222222-33333333-118)(A;;0xabc119;;;S-1-5-21-11111111-22222222-33333333-119)(A;;0xabc120;;;S-1-5-21-11111111-22222222-33333333-120)(A;;0xabc121;;;S-1-5-21-11111111-22222222-33333333-121)(A;;0xabc122;;;S-1-5-21-11111111-22222222-33333333-122)(A;;0xabc123;;;S-1-5-21-11111111-22222222-33333333-123)(A;;0xabc124;;;S-1-5-21-11111111-22222222-33333333-124)(A;;0xabc125;;;S-1-5-21-11111111-22222222-33333333-125)(A;;0xabc126;;;S-1-5-21-11111111-22222222-33333333-126)(A;;0xabc127;;;S-1-5-21-11111111-22222222-33333333-127)(A;;0xabc128;;;S-1-5-21-11111111-22222222-33333333-128)(A;;0xabc129;;;S-1-5-21-11111111-22222222-33333333-129)(A;;0xabc130;;;S-1-5-21-11111111-22222222-33333333-130)(A;;0xabc131;;;S-1-5-21-11111111-22222222-33333333-131)(A;;0xabc132;;;S-1-5-21-11111111-22222222-33333333-132)(A;;0xabc133;;;S-1-5-21-11111111-22222222-33333333-133)(A;;0xabc134;;;S-1-5-21-11111111-22222222-33333333-134)(A;;0xabc135;;;S-1-5-21-11111111-22222222-33333333-135)(A;;0xabc136;;;S-1-5-21-11111111-22222222-33333333-136)(A;;0xabc137;;;S-1-5-21-11111111-22222222-33333333-137)(A;;0xabc138;;;S-1-5-21-11111111-22222222-33333333-138)(A;;0xabc139;;;S-1-5-21-11111111-22222222-33333333-139)(A;;0xabc140;;;S-1-5-21-11111111-22222222-33333333-140)(A;;0xabc141;;;S-1-5-21-11111111-22222222-33333333-141)(A;;0xabc142;;;S-1-5-21-11111111-22222222-33333333-142)(A;;0xabc143;;;S-1-5-21-11111111-22222222-33333333-143)(A;;0xabc144;;;S-1-5-21-11111111-22222222-33333333-144)(A;;0xabc145;;;S-1-5-21-11111111-22222222-33333333-145)(A;;0xabc146;;;S-1-5-21-11111111-22222222-33333333-146)(A;;0xabc147;;;S-1-5-21-11111111-22222222-33333333-147)(A;;0xabc148;;;S-1-5-21-11111111-22222222-33333333-148)(A;;0xabc149;;;S-1-5-21-11111111-22222222-33333333-149)(A;;0xabc150;;;S-1-5-21-11111111-22222222-33333333-150)(A;;0xabc151;;;S-1-5-21-11111111-22222222-33333333-151)(A;;0xabc152;;;S-1-5-21-11111111-22222222-33333333-152)(A;;0xabc153;;;S-1-5-21-11111111-22222222-33333333-153)(A;;0xabc154;;;S-1-5-21-11111111-22222222-33333333-154)(A;;0xabc155;;;S-1-5-21-11111111-22222222-33333333-155)(A;;0xabc156;;;S-1-5-21-11111111-22222222-33333333-156)(A;;0xabc157;;;S-1-5-21-11111111-22222222-33333333-157)(A;;0xabc158;;;S-1-5-21-11111111-22222222-33333333-158)(A;;0xabc159;;;S-1-5-21-11111111-22222222-33333333-159)(A;;0xabc160;;;S-1-5-21-11111111-22222222-33333333-160)(A;;0xabc161;;;S-1-5-21-11111111-22222222-33333333-161)(A;;0xabc162;;;S-1-5-21-11111111-22222222-33333333-162)(A;;0xabc163;;;S-1-5-21-11111111-22222222-33333333-163)(A;;0xabc164;;;S-1-5-21-11111111-22222222-33333333-164)(A;;0xabc165;;;S-1-5-21-11111111-22222222-33333333-165)(A;;0xabc166;;;S-1-5-21-11111111-22222222-33333333-166)(A;;0xabc167;;;S-1-5-21-11111111-22222222-33333333-167)(A;;0xabc168;;;S-1-5-21-11111111-22222222-33333333-168)(A;;0xabc169;;;S-1-5-21-11111111-22222222-33333333-169)(A;;0xabc170;;;S-1-5-21-11111111-22222222-33333333-170)(A;;0xabc171;;;S-1-5-21-11111111-22222222-33333333-171)(A;;0xabc172;;;S-1-5-21-11111111-22222222-33333333-172)(A;;0xabc173;;;S-1-5-21-11111111-22222222-33333333-173)(A;;0xabc174;;;S-1-5-21-11111111-22222222-33333333-174)(A;;0xabc175;;;S-1-5-21-11111111-22222222-33333333-175)(A;;0xabc176;;;S-1-5-21-11111111-22222222-33333333-176)(A;;0xabc177;;;S-1-5-21-11111111-22222222-33333333-177)(A;;0xabc178;;;S-1-5-21-11111111-22222222-33333333-178)(A;;0xabc179;;;S-1-5-21-11111111-22222222-33333333-179)(A;;0xabc180;;;S-1-5-21-11111111-22222222-33333333-180)(A;;0xabc181;;;S-1-5-21-11111111-22222222-33333333-181)(A;;0xabc182;;;S-1-5-21-11111111-22222222-33333333-182)(A;;0xabc183;;;S-1-5-21-11111111-22222222-33333333-183)(A;;0xabc184;;;S-1-5-21-11111111-22222222-33333333-184)(A;;0xabc185;;;S-1-5-21-11111111-22222222-33333333-185)(A;;0xabc186;;;S-1-5-21-11111111-22222222-33333333-186)(A;;0xabc187;;;S-1-5-21-11111111-22222222-33333333-187)(A;;0xabc188;;;S-1-5-21-11111111-22222222-33333333-188)(A;;0xabc189;;;S-1-5-21-11111111-22222222-33333333-189)(A;;0xabc190;;;S-1-5-21-11111111-22222222-33333333-190)(A;;0xabc191;;;S-1-5-21-11111111-22222222-33333333-191)(A;;0xabc192;;;S-1-5-21-11111111-22222222-33333333-192)(A;;0xabc193;;;S-1-5-21-11111111-22222222-33333333-193)(A;;0xabc194;;;S-1-5-21-11111111-22222222-33333333-194)(A;;0xabc195;;;S-1-5-21-11111111-22222222-33333333-195)(A;;0xabc196;;;S-1-5-21-11111111-22222222-33333333-196)(A;;0xabc197;;;S-1-5-21-11111111-22222222-33333333-197)(A;;0xabc198;;;S-1-5-21-11111111-22222222-33333333-198)(A;;0xabc199;;;S-1-5-21-11111111-22222222-33333333-199)(A;;0xabc200;;;S-1-5-21-11111111-22222222-33333333-200)(A;;0xabc201;;;S-1-5-21-11111111-22222222-33333333-201)(A;;0xabc202;;;S-1-5-21-11111111-22222222-33333333-202)(A;;0xabc203;;;S-1-5-21-11111111-22222222-33333333-203)(A;;0xabc204;;;S-1-5-21-11111111-22222222-33333333-204)(A;;0xabc205;;;S-1-5-21-11111111-22222222-33333333-205)(A;;0xabc206;;;S-1-5-21-11111111-22222222-33333333-206)(A;;0xabc207;;;S-1-5-21-11111111-22222222-33333333-207)(A;;0xabc208;;;S-1-5-21-11111111-22222222-33333333-208)(A;;0xabc209;;;S-1-5-21-11111111-22222222-33333333-209)(A;;0xabc210;;;S-1-5-21-11111111-22222222-33333333-210)(A;;0xabc211;;;S-1-5-21-11111111-22222222-33333333-211)(A;;0xabc212;;;S-1-5-21-11111111-22222222-33333333-212)(A;;0xabc213;;;S-1-5-21-11111111-22222222-33333333-213)(A;;0xabc214;;;S-1-5-21-11111111-22222222-33333333-214)(A;;0xabc215;;;S-1-5-21-11111111-22222222-33333333-215)(A;;0xabc216;;;S-1-5-21-11111111-22222222-33333333-216)(A;;0xabc217;;;S-1-5-21-11111111-22222222-33333333-217)(A;;0xabc218;;;S-1-5-21-11111111-22222222-33333333-218)(A;;0xabc219;;;S-1-5-21-11111111-22222222-33333333-219)(A;;0xabc220;;;S-1-5-21-11111111-22222222-33333333-220)(A;;0xabc221;;;S-1-5-21-11111111-22222222-33333333-221)(A;;0xabc222;;;S-1-5-21-11111111-22222222-33333333-222)(A;;0xabc223;;;S-1-5-21-11111111-22222222-33333333-223)(A;;0xabc224;;;S-1-5-21-11111111-22222222-33333333-224)(A;;0xabc225;;;S-1-5-21-11111111-22222222-33333333-225)(A;;0xabc226;;;S-1-5-21-11111111-22222222-33333333-226)(A;;0xabc227;;;S-1-5-21-11111111-22222222-33333333-227)(A;;0xabc228;;;S-1-5-21-11111111-22222222-33333333-228)(A;;0xabc229;;;S-1-5-21-11111111-22222222-33333333-229)(A;;0xabc230;;;S-1-5-21-11111111-22222222-33333333-230)(A;;0xabc231;;;S-1-5-21-11111111-22222222-33333333-231)(A;;0xabc232;;;S-1-5-21-11111111-22222222-33333333-232)(A;;0xabc233;;;S-1-5-21-11111111-22222222-33333333-233)(A;;0xabc234;;;S-1-5-21-11111111-22222222-33333333-234)(A;;0xabc235;;;S-1-5-21-11111111-22222222-33333333-235)(A;;0xabc236;;;S-1-5-21-11111111-22222222-33333333-236)(A;;0xabc237;;;S-1-5-21-11111111-22222222-33333333-237)(A;;0xabc238;;;S-1-5-21-11111111-22222222-33333333-238)(A;;0xabc239;;;S-1-5-21-11111111-22222222-33333333-239)(A;;0xabc240;;;S-1-5-21-11111111-22222222-33333333-240)(A;;0xabc241;;;S-1-5-21-11111111-22222222-33333333-241)(A;;0xabc242;;;S-1-5-21-11111111-22222222-33333333-242)(A;;0xabc243;;;S-1-5-21-11111111-22222222-33333333-243)(A;;0xabc244;;;S-1-5-21-11111111-22222222-33333333-244)(A;;0xabc245;;;S-1-5-21-11111111-22222222-33333333-245)(A;;0xabc246;;;S-1-5-21-11111111-22222222-33333333-246)(A;;0xabc247;;;S-1-5-21-11111111-22222222-33333333-247)(A;;0xabc248;;;S-1-5-21-11111111-22222222-33333333-248)(A;;0xabc249;;;S-1-5-21-11111111-22222222-33333333-249)(A;;0xabc250;;;S-1-5-21-11111111-22222222-33333333-250)(A;;0xabc251;;;S-1-5-21-11111111-22222222-33333333-251)(A;;0xabc252;;;S-1-5-21-11111111-22222222-33333333-252)(A;;0xabc253;;;S-1-5-21-11111111-22222222-33333333-253)(A;;0xabc254;;;S-1-5-21-11111111-22222222-33333333-254)(A;;0xabc255;;;S-1-5-21-11111111-22222222-33333333-255)(A;;0xabc256;;;S-1-5-21-11111111-22222222-33333333-256)(A;;0xabc257;;;S-1-5-21-11111111-22222222-33333333-257)(A;;0xabc258;;;S-1-5-21-11111111-22222222-33333333-258)(A;;0xabc259;;;S-1-5-21-11111111-22222222-33333333-259)(A;;0xabc260;;;S-1-5-21-11111111-22222222-33333333-260)(A;;0xabc261;;;S-1-5-21-11111111-22222222-33333333-261)(A;;0xabc262;;;S-1-5-21-11111111-22222222-33333333-262)(A;;0xabc263;;;S-1-5-21-11111111-22222222-33333333-263)(A;;0xabc264;;;S-1-5-21-11111111-22222222-33333333-264)(A;;0xabc265;;;S-1-5-21-11111111-22222222-33333333-265)(A;;0xabc266;;;S-1-5-21-11111111-22222222-33333333-266)(A;;0xabc267;;;S-1-5-21-11111111-22222222-33333333-267)(A;;0xabc268;;;S-1-5-21-11111111-22222222-33333333-268)(A;;0xabc269;;;S-1-5-21-11111111-22222222-33333333-269)(A;;0xabc270;;;S-1-5-21-11111111-22222222-33333333-270)(A;;0xabc271;;;S-1-5-21-11111111-22222222-33333333-271)(A;;0xabc272;;;S-1-5-21-11111111-22222222-33333333-272)(A;;0xabc273;;;S-1-5-21-11111111-22222222-33333333-273)(A;;0xabc274;;;S-1-5-21-11111111-22222222-33333333-274)(A;;0xabc275;;;S-1-5-21-11111111-22222222-33333333-275)(A;;0xabc276;;;S-1-5-21-11111111-22222222-33333333-276)(A;;0xabc277;;;S-1-5-21-11111111-22222222-33333333-277)(A;;0xabc278;;;S-1-5-21-11111111-22222222-33333333-278)(A;;0xabc279;;;S-1-5-21-11111111-22222222-33333333-279)(A;;0xabc280;;;S-1-5-21-11111111-22222222-33333333-280)(A;;0xabc281;;;S-1-5-21-11111111-22222222-33333333-281)(A;;0xabc282;;;S-1-5-21-11111111-22222222-33333333-282)(A;;0xabc283;;;S-1-5-21-11111111-22222222-33333333-283)(A;;0xabc284;;;S-1-5-21-11111111-22222222-33333333-284)(A;;0xabc285;;;S-1-5-21-11111111-22222222-33333333-285)(A;;0xabc286;;;S-1-5-21-11111111-22222222-33333333-286)(A;;0xabc287;;;S-1-5-21-11111111-22222222-33333333-287)(A;;0xabc288;;;S-1-5-21-11111111-22222222-33333333-288)(A;;0xabc289;;;S-1-5-21-11111111-22222222-33333333-289)(A;;0xabc290;;;S-1-5-21-11111111-22222222-33333333-290)(A;;0xabc291;;;S-1-5-21-11111111-22222222-33333333-291)(A;;0xabc292;;;S-1-5-21-11111111-22222222-33333333-292)(A;;0xabc293;;;S-1-5-21-11111111-22222222-33333333-293)(A;;0xabc294;;;S-1-5-21-11111111-22222222-33333333-294)(A;;0xabc295;;;S-1-5-21-11111111-22222222-33333333-295)(A;;0xabc296;;;S-1-5-21-11111111-22222222-33333333-296)(A;;0xabc297;;;S-1-5-21-11111111-22222222-33333333-297)(A;;0xabc298;;;S-1-5-21-11111111-22222222-33333333-298)(A;;0xabc299;;;S-1-5-21-11111111-22222222-33333333-299)(A;;0xabc300;;;S-1-5-21-11111111-22222222-33333333-300)(A;;0xabc301;;;S-1-5-21-11111111-22222222-33333333-301)(A;;0xabc302;;;S-1-5-21-11111111-22222222-33333333-302)(A;;0xabc303;;;S-1-5-21-11111111-22222222-33333333-303)(A;;0xabc304;;;S-1-5-21-11111111-22222222-33333333-304)(A;;0xabc305;;;S-1-5-21-11111111-22222222-33333333-305)(A;;0xabc306;;;S-1-5-21-11111111-22222222-33333333-306)(A;;0xabc307;;;S-1-5-21-11111111-22222222-33333333-307)(A;;0xabc308;;;S-1-5-21-11111111-22222222-33333333-308)(A;;0xabc309;;;S-1-5-21-11111111-22222222-33333333-309)(A;;0xabc310;;;S-1-5-21-11111111-22222222-33333333-310)(A;;0xabc311;;;S-1-5-21-11111111-22222222-33333333-311)(A;;0xabc312;;;S-1-5-21-11111111-22222222-33333333-312)(A;;0xabc313;;;S-1-5-21-11111111-22222222-33333333-313)(A;;0xabc314;;;S-1-5-21-11111111-22222222-33333333-314)(A;;0xabc315;;;S-1-5-21-11111111-22222222-33333333-315)(A;;0xabc316;;;S-1-5-21-11111111-22222222-33333333-316)(A;;0xabc317;;;S-1-5-21-11111111-22222222-33333333-317)(A;;0xabc318;;;S-1-5-21-11111111-22222222-33333333-318)(A;;0xabc319;;;S-1-5-21-11111111-22222222-33333333-319)(A;;0xabc320;;;S-1-5-21-11111111-22222222-33333333-320)(A;;0xabc321;;;S-1-5-21-11111111-22222222-33333333-321)(A;;0xabc322;;;S-1-5-21-11111111-22222222-33333333-322)(A;;0xabc323;;;S-1-5-21-11111111-22222222-33333333-323)(A;;0xabc324;;;S-1-5-21-11111111-22222222-33333333-324)(A;;0xabc325;;;S-1-5-21-11111111-22222222-33333333-325)(A;;0xabc326;;;S-1-5-21-11111111-22222222-33333333-326)(A;;0xabc327;;;S-1-5-21-11111111-22222222-33333333-327)(A;;0xabc328;;;S-1-5-21-11111111-22222222-33333333-328)(A;;0xabc329;;;S-1-5-21-11111111-22222222-33333333-329)(A;;0xabc330;;;S-1-5-21-11111111-22222222-33333333-330)(A;;0xabc331;;;S-1-5-21-11111111-22222222-33333333-331)(A;;0xabc332;;;S-1-5-21-11111111-22222222-33333333-332)(A;;0xabc333;;;S-1-5-21-11111111-22222222-33333333-333)(A;;0xabc334;;;S-1-5-21-11111111-22222222-33333333-334)(A;;0xabc335;;;S-1-5-21-11111111-22222222-33333333-335)(A;;0xabc336;;;S-1-5-21-11111111-22222222-33333333-336)(A;;0xabc337;;;S-1-5-21-11111111-22222222-33333333-337)(A;;0xabc338;;;S-1-5-21-11111111-22222222-33333333-338)(A;;0xabc339;;;S-1-5-21-11111111-22222222-33333333-339)(A;;0xabc340;;;S-1-5-21-11111111-22222222-33333333-340)(A;;0xabc341;;;S-1-5-21-11111111-22222222-33333333-341)(A;;0xabc342;;;S-1-5-21-11111111-22222222-33333333-342)(A;;0xabc343;;;S-1-5-21-11111111-22222222-33333333-343)(A;;0xabc344;;;S-1-5-21-11111111-22222222-33333333-344)(A;;0xabc345;;;S-1-5-21-11111111-22222222-33333333-345)(A;;0xabc346;;;S-1-5-21-11111111-22222222-33333333-346)(A;;0xabc347;;;S-1-5-21-11111111-22222222-33333333-347)(A;;0xabc348;;;S-1-5-21-11111111-22222222-33333333-348)(A;;0xabc349;;;S-1-5-21-11111111-22222222-33333333-349)(A;;0xabc350;;;S-1-5-21-11111111-22222222-33333333-350)(A;;0xabc351;;;S-1-5-21-11111111-22222222-33333333-351)(A;;0xabc352;;;S-1-5-21-11111111-22222222-33333333-352)(A;;0xabc353;;;S-1-5-21-11111111-22222222-33333333-353)(A;;0xabc354;;;S-1-5-21-11111111-22222222-33333333-354)(A;;0xabc355;;;S-1-5-21-11111111-22222222-33333333-355)(A;;0xabc356;;;S-1-5-21-11111111-22222222-33333333-356)(A;;0xabc357;;;S-1-5-21-11111111-22222222-33333333-357)(A;;0xabc358;;;S-1-5-21-11111111-22222222-33333333-358)(A;;0xabc359;;;S-1-5-21-11111111-22222222-33333333-359)(A;;0xabc360;;;S-1-5-21-11111111-22222222-33333333-360)(A;;0xabc361;;;S-1-5-21-11111111-22222222-33333333-361)(A;;0xabc362;;;S-1-5-21-11111111-22222222-33333333-362)(A;;0xabc363;;;S-1-5-21-11111111-22222222-33333333-363)(A;;0xabc364;;;S-1-5-21-11111111-22222222-33333333-364)(A;;0xabc365;;;S-1-5-21-11111111-22222222-33333333-365)(A;;0xabc366;;;S-1-5-21-11111111-22222222-33333333-366)(A;;0xabc367;;;S-1-5-21-11111111-22222222-33333333-367)(A;;0xabc368;;;S-1-5-21-11111111-22222222-33333333-368)(A;;0xabc369;;;S-1-5-21-11111111-22222222-33333333-369)(A;;0xabc370;;;S-1-5-21-11111111-22222222-33333333-370)(A;;0xabc371;;;S-1-5-21-11111111-22222222-33333333-371)(A;;0xabc372;;;S-1-5-21-11111111-22222222-33333333-372)(A;;0xabc373;;;S-1-5-21-11111111-22222222-33333333-373)(A;;0xabc374;;;S-1-5-21-11111111-22222222-33333333-374)(A;;0xabc375;;;S-1-5-21-11111111-22222222-33333333-375)(A;;0xabc376;;;S-1-5-21-11111111-22222222-33333333-376)(A;;0xabc377;;;S-1-5-21-11111111-22222222-33333333-377)(A;;0xabc378;;;S-1-5-21-11111111-22222222-33333333-378)(A;;0xabc379;;;S-1-5-21-11111111-22222222-33333333-379)(A;;0xabc380;;;S-1-5-21-11111111-22222222-33333333-380)(A;;0xabc381;;;S-1-5-21-11111111-22222222-33333333-381)(A;;0xabc382;;;S-1-5-21-11111111-22222222-33333333-382)(A;;0xabc383;;;S-1-5-21-11111111-22222222-33333333-383)(A;;0xabc384;;;S-1-5-21-11111111-22222222-33333333-384)(A;;0xabc385;;;S-1-5-21-11111111-22222222-33333333-385)(A;;0xabc386;;;S-1-5-21-11111111-22222222-33333333-386)(A;;0xabc387;;;S-1-5-21-11111111-22222222-33333333-387)(A;;0xabc388;;;S-1-5-21-11111111-22222222-33333333-388)(A;;0xabc389;;;S-1-5-21-11111111-22222222-33333333-389)(A;;0xabc390;;;S-1-5-21-11111111-22222222-33333333-390)(A;;0xabc391;;;S-1-5-21-11111111-22222222-33333333-391)(A;;0xabc392;;;S-1-5-21-11111111-22222222-33333333-392)(A;;0xabc393;;;S-1-5-21-11111111-22222222-33333333-393)(A;;0xabc394;;;S-1-5-21-11111111-22222222-33333333-394)(A;;0xabc395;;;S-1-5-21-11111111-22222222-33333333-395)(A;;0xabc396;;;S-1-5-21-11111111-22222222-33333333-396)(A;;0xabc397;;;S-1-5-21-11111111-22222222-33333333-397)(A;;0xabc398;;;S-1-5-21-11111111-22222222-33333333-398)(A;;0xabc399;;;S-1-5-21-11111111-22222222-33333333-399)(A;;0xabc400;;;S-1-5-21-11111111-22222222-33333333-400)(A;;0xabc401;;;S-1-5-21-11111111-22222222-33333333-401)(A;;0xabc402;;;S-1-5-21-11111111-22222222-33333333-402)(A;;0xabc403;;;S-1-5-21-11111111-22222222-33333333-403)(A;;0xabc404;;;S-1-5-21-11111111-22222222-33333333-404)(A;;0xabc405;;;S-1-5-21-11111111-22222222-33333333-405)(A;;0xabc406;;;S-1-5-21-11111111-22222222-33333333-406)(A;;0xabc407;;;S-1-5-21-11111111-22222222-33333333-407)(A;;0xabc408;;;S-1-5-21-11111111-22222222-33333333-408)(A;;0xabc409;;;S-1-5-21-11111111-22222222-33333333-409)(A;;0xabc410;;;S-1-5-21-11111111-22222222-33333333-410)(A;;0xabc411;;;S-1-5-21-11111111-22222222-33333333-411)(A;;0xabc412;;;S-1-5-21-11111111-22222222-33333333-412)(A;;0xabc413;;;S-1-5-21-11111111-22222222-33333333-413)(A;;0xabc414;;;S-1-5-21-11111111-22222222-33333333-414)(A;;0xabc415;;;S-1-5-21-11111111-22222222-33333333-415)(A;;0xabc416;;;S-1-5-21-11111111-22222222-33333333-416)(A;;0xabc417;;;S-1-5-21-11111111-22222222-33333333-417)(A;;0xabc418;;;S-1-5-21-11111111-22222222-33333333-418)(A;;0xabc419;;;S-1-5-21-11111111-22222222-33333333-419)(A;;0xabc420;;;S-1-5-21-11111111-22222222-33333333-420)(A;;0xabc421;;;S-1-5-21-11111111-22222222-33333333-421)(A;;0xabc422;;;S-1-5-21-11111111-22222222-33333333-422)(A;;0xabc423;;;S-1-5-21-11111111-22222222-33333333-423)(A;;0xabc424;;;S-1-5-21-11111111-22222222-33333333-424)(A;;0xabc425;;;S-1-5-21-11111111-22222222-33333333-425)(A;;0xabc426;;;S-1-5-21-11111111-22222222-33333333-426)(A;;0xabc427;;;S-1-5-21-11111111-22222222-33333333-427)(A;;0xabc428;;;S-1-5-21-11111111-22222222-33333333-428)(A;;0xabc429;;;S-1-5-21-11111111-22222222-33333333-429)(A;;0xabc430;;;S-1-5-21-11111111-22222222-33333333-430)(A;;0xabc431;;;S-1-5-21-11111111-22222222-33333333-431)(A;;0xabc432;;;S-1-5-21-11111111-22222222-33333333-432)(A;;0xabc433;;;S-1-5-21-11111111-22222222-33333333-433)(A;;0xabc434;;;S-1-5-21-11111111-22222222-33333333-434)(A;;0xabc435;;;S-1-5-21-11111111-22222222-33333333-435)(A;;0xabc436;;;S-1-5-21-11111111-22222222-33333333-436)(A;;0xabc437;;;S-1-5-21-11111111-22222222-33333333-437)(A;;0xabc438;;;S-1-5-21-11111111-22222222-33333333-438)(A;;0xabc439;;;S-1-5-21-11111111-22222222-33333333-439)(A;;0xabc440;;;S-1-5-21-11111111-22222222-33333333-440)(A;;0xabc441;;;S-1-5-21-11111111-22222222-33333333-441)(A;;0xabc442;;;S-1-5-21-11111111-22222222-33333333-442)(A;;0xabc443;;;S-1-5-21-11111111-22222222-33333333-443)(A;;0xabc444;;;S-1-5-21-11111111-22222222-33333333-444)(A;;0xabc445;;;S-1-5-21-11111111-22222222-33333333-445)(A;;0xabc446;;;S-1-5-21-11111111-22222222-33333333-446)(A;;0xabc447;;;S-1-5-21-11111111-22222222-33333333-447)(A;;0xabc448;;;S-1-5-21-11111111-22222222-33333333-448)(A;;0xabc449;;;S-1-5-21-11111111-22222222-33333333-449)(A;;0xabc450;;;S-1-5-21-11111111-22222222-33333333-450)(A;;0xabc451;;;S-1-5-21-11111111-22222222-33333333-451)(A;;0xabc452;;;S-1-5-21-11111111-22222222-33333333-452)(A;;0xabc453;;;S-1-5-21-11111111-22222222-33333333-453)(A;;0xabc454;;;S-1-5-21-11111111-22222222-33333333-454)(A;;0xabc455;;;S-1-5-21-11111111-22222222-33333333-455)(A;;0xabc456;;;S-1-5-21-11111111-22222222-33333333-456)(A;;0xabc457;;;S-1-5-21-11111111-22222222-33333333-457)(A;;0xabc458;;;S-1-5-21-11111111-22222222-33333333-458)(A;;0xabc459;;;S-1-5-21-11111111-22222222-33333333-459)(A;;0xabc460;;;S-1-5-21-11111111-22222222-33333333-460)(A;;0xabc461;;;S-1-5-21-11111111-22222222-33333333-461)(A;;0xabc462;;;S-1-5-21-11111111-22222222-33333333-462)(A;;0xabc463;;;S-1-5-21-11111111-22222222-33333333-463)(A;;0xabc464;;;S-1-5-21-11111111-22222222-33333333-464)(A;;0xabc465;;;S-1-5-21-11111111-22222222-33333333-465)(A;;0xabc466;;;S-1-5-21-11111111-22222222-33333333-466)(A;;0xabc467;;;S-1-5-21-11111111-22222222-33333333-467)(A;;0xabc468;;;S-1-5-21-11111111-22222222-33333333-468)(A;;0xabc469;;;S-1-5-21-11111111-22222222-33333333-469)(A;;0xabc470;;;S-1-5-21-11111111-22222222-33333333-470)(A;;0xabc471;;;S-1-5-21-11111111-22222222-33333333-471)(A;;0xabc472;;;S-1-5-21-11111111-22222222-33333333-472)(A;;0xabc473;;;S-1-5-21-11111111-22222222-33333333-473)(A;;0xabc474;;;S-1-5-21-11111111-22222222-33333333-474)(A;;0xabc475;;;S-1-5-21-11111111-22222222-33333333-475)(A;;0xabc476;;;S-1-5-21-11111111-22222222-33333333-476)(A;;0xabc477;;;S-1-5-21-11111111-22222222-33333333-477)(A;;0xabc478;;;S-1-5-21-11111111-22222222-33333333-478)(A;;0xabc479;;;S-1-5-21-11111111-22222222-33333333-479)(A;;0xabc480;;;S-1-5-21-11111111-22222222-33333333-480)(A;;0xabc481;;;S-1-5-21-11111111-22222222-33333333-481)(A;;0xabc482;;;S-1-5-21-11111111-22222222-33333333-482)(A;;0xabc483;;;S-1-5-21-11111111-22222222-33333333-483)(A;;0xabc484;;;S-1-5-21-11111111-22222222-33333333-484)(A;;0xabc485;;;S-1-5-21-11111111-22222222-33333333-485)(A;;0xabc486;;;S-1-5-21-11111111-22222222-33333333-486)(A;;0xabc487;;;S-1-5-21-11111111-22222222-33333333-487)(A;;0xabc488;;;S-1-5-21-11111111-22222222-33333333-488)(A;;0xabc489;;;S-1-5-21-11111111-22222222-33333333-489)(A;;0xabc490;;;S-1-5-21-11111111-22222222-33333333-490)(A;;0xabc491;;;S-1-5-21-11111111-22222222-33333333-491)(A;;0xabc492;;;S-1-5-21-11111111-22222222-33333333-492)(A;;0xabc493;;;S-1-5-21-11111111-22222222-33333333-493)(A;;0xabc494;;;S-1-5-21-11111111-22222222-33333333-494)(A;;0xabc495;;;S-1-5-21-11111111-22222222-33333333-495)(A;;0xabc496;;;S-1-5-21-11111111-22222222-33333333-496)(A;;0xabc497;;;S-1-5-21-11111111-22222222-33333333-497)(A;;0xabc498;;;S-1-5-21-11111111-22222222-33333333-498)(A;;0xabc499;;;S-1-5-21-11111111-22222222-33333333-499)(A;;0xabc500;;;S-1-5-21-11111111-22222222-33333333-500)(A;;0xabc501;;;S-1-5-21-11111111-22222222-33333333-501)(A;;0xabc502;;;S-1-5-21-11111111-22222222-33333333-502)(A;;0xabc503;;;S-1-5-21-11111111-22222222-33333333-503)(A;;0xabc504;;;S-1-5-21-11111111-22222222-33333333-504)(A;;0xabc505;;;S-1-5-21-11111111-22222222-33333333-505)(A;;0xabc506;;;S-1-5-21-11111111-22222222-33333333-506)(A;;0xabc507;;;S-1-5-21-11111111-22222222-33333333-507)(A;;0xabc508;;;S-1-5-21-11111111-22222222-33333333-508)(A;;0xabc509;;;S-1-5-21-11111111-22222222-33333333-509)(A;;0xabc510;;;S-1-5-21-11111111-22222222-33333333-510)(A;;0xabc511;;;S-1-5-21-11111111-22222222-33333333-511)(A;;0xabc512;;;S-1-5-21-11111111-22222222-33333333-512)(A;;0xabc513;;;S-1-5-21-11111111-22222222-33333333-513)(A;;0xabc514;;;S-1-5-21-11111111-22222222-33333333-514)(A;;0xabc515;;;S-1-5-21-11111111-22222222-33333333-515)(A;;0xabc516;;;S-1-5-21-11111111-22222222-33333333-516)(A;;0xabc517;;;S-1-5-21-11111111-22222222-33333333-517)(A;;0xabc518;;;S-1-5-21-11111111-22222222-33333333-518)(A;;0xabc519;;;S-1-5-21-11111111-22222222-33333333-519)(A;;0xabc520;;;S-1-5-21-11111111-22222222-33333333-520)(A;;0xabc521;;;S-1-5-21-11111111-22222222-33333333-521)(A;;0xabc522;;;S-1-5-21-11111111-22222222-33333333-522)(A;;0xabc523;;;S-1-5-21-11111111-22222222-33333333-523)(A;;0xabc524;;;S-1-5-21-11111111-22222222-33333333-524)(A;;0xabc525;;;S-1-5-21-11111111-22222222-33333333-525)(A;;0xabc526;;;S-1-5-21-11111111-22222222-33333333-526)(A;;0xabc527;;;S-1-5-21-11111111-22222222-33333333-527)(A;;0xabc528;;;S-1-5-21-11111111-22222222-33333333-528)(A;;0xabc529;;;S-1-5-21-11111111-22222222-33333333-529)(A;;0xabc530;;;S-1-5-21-11111111-22222222-33333333-530)(A;;0xabc531;;;S-1-5-21-11111111-22222222-33333333-531)(A;;0xabc532;;;S-1-5-21-11111111-22222222-33333333-532)(A;;0xabc533;;;S-1-5-21-11111111-22222222-33333333-533)(A;;0xabc534;;;S-1-5-21-11111111-22222222-33333333-534)(A;;0xabc535;;;S-1-5-21-11111111-22222222-33333333-535)(A;;0xabc536;;;S-1-5-21-11111111-22222222-33333333-536)(A;;0xabc537;;;S-1-5-21-11111111-22222222-33333333-537)(A;;0xabc538;;;S-1-5-21-11111111-22222222-33333333-538)(A;;0xabc539;;;S-1-5-21-11111111-22222222-33333333-539)(A;;0xabc540;;;S-1-5-21-11111111-22222222-33333333-540)(A;;0xabc541;;;S-1-5-21-11111111-22222222-33333333-541)(A;;0xabc542;;;S-1-5-21-11111111-22222222-33333333-542)(A;;0xabc543;;;S-1-5-21-11111111-22222222-33333333-543)(A;;0xabc544;;;S-1-5-21-11111111-22222222-33333333-544)(A;;0xabc545;;;S-1-5-21-11111111-22222222-33333333-545)(A;;0xabc546;;;S-1-5-21-11111111-22222222-33333333-546)(A;;0xabc547;;;S-1-5-21-11111111-22222222-33333333-547)(A;;0xabc548;;;S-1-5-21-11111111-22222222-33333333-548)(A;;0xabc549;;;S-1-5-21-11111111-22222222-33333333-549)(A;;0xabc550;;;S-1-5-21-11111111-22222222-33333333-550)(A;;0xabc551;;;S-1-5-21-11111111-22222222-33333333-551)(A;;0xabc552;;;S-1-5-21-11111111-22222222-33333333-552)(A;;0xabc553;;;S-1-5-21-11111111-22222222-33333333-553)(A;;0xabc554;;;S-1-5-21-11111111-22222222-33333333-554)(A;;0xabc555;;;S-1-5-21-11111111-22222222-33333333-555)(A;;0xabc556;;;S-1-5-21-11111111-22222222-33333333-556)(A;;0xabc557;;;S-1-5-21-11111111-22222222-33333333-557)(A;;0xabc558;;;S-1-5-21-11111111-22222222-33333333-558)(A;;0xabc559;;;S-1-5-21-11111111-22222222-33333333-559)(A;;0xabc560;;;S-1-5-21-11111111-22222222-33333333-560)(A;;0xabc561;;;S-1-5-21-11111111-22222222-33333333-561)(A;;0xabc562;;;S-1-5-21-11111111-22222222-33333333-562)(A;;0xabc563;;;S-1-5-21-11111111-22222222-33333333-563)(A;;0xabc564;;;S-1-5-21-11111111-22222222-33333333-564)(A;;0xabc565;;;S-1-5-21-11111111-22222222-33333333-565)(A;;0xabc566;;;S-1-5-21-11111111-22222222-33333333-566)(A;;0xabc567;;;S-1-5-21-11111111-22222222-33333333-567)(A;;0xabc568;;;S-1-5-21-11111111-22222222-33333333-568)(A;;0xabc569;;;S-1-5-21-11111111-22222222-33333333-569)(A;;0xabc570;;;S-1-5-21-11111111-22222222-33333333-570)(A;;0xabc571;;;S-1-5-21-11111111-22222222-33333333-571)(A;;0xabc572;;;S-1-5-21-11111111-22222222-33333333-572)(A;;0xabc573;;;S-1-5-21-11111111-22222222-33333333-573)(A;;0xabc574;;;S-1-5-21-11111111-22222222-33333333-574)(A;;0xabc575;;;S-1-5-21-11111111-22222222-33333333-575)(A;;0xabc576;;;S-1-5-21-11111111-22222222-33333333-576)(A;;0xabc577;;;S-1-5-21-11111111-22222222-33333333-577)(A;;0xabc578;;;S-1-5-21-11111111-22222222-33333333-578)(A;;0xabc579;;;S-1-5-21-11111111-22222222-33333333-579)(A;;0xabc580;;;S-1-5-21-11111111-22222222-33333333-580)(A;;0xabc581;;;S-1-5-21-11111111-22222222-33333333-581)(A;;0xabc582;;;S-1-5-21-11111111-22222222-33333333-582)(A;;0xabc583;;;S-1-5-21-11111111-22222222-33333333-583)(A;;0xabc584;;;S-1-5-21-11111111-22222222-33333333-584)(A;;0xabc585;;;S-1-5-21-11111111-22222222-33333333-585)(A;;0xabc586;;;S-1-5-21-11111111-22222222-33333333-586)(A;;0xabc587;;;S-1-5-21-11111111-22222222-33333333-587)(A;;0xabc588;;;S-1-5-21-11111111-22222222-33333333-588)(A;;0xabc589;;;S-1-5-21-11111111-22222222-33333333-589)(A;;0xabc590;;;S-1-5-21-11111111-22222222-33333333-590)(A;;0xabc591;;;S-1-5-21-11111111-22222222-33333333-591)(A;;0xabc592;;;S-1-5-21-11111111-22222222-33333333-592)(A;;0xabc593;;;S-1-5-21-11111111-22222222-33333333-593)(A;;0xabc594;;;S-1-5-21-11111111-22222222-33333333-594)(A;;0xabc595;;;S-1-5-21-11111111-22222222-33333333-595)(A;;0xabc596;;;S-1-5-21-11111111-22222222-33333333-596)(A;;0xabc597;;;S-1-5-21-11111111-22222222-33333333-597)(A;;0xabc598;;;S-1-5-21-11111111-22222222-33333333-598)(A;;0xabc599;;;S-1-5-21-11111111-22222222-33333333-599)(A;;0xabc600;;;S-1-5-21-11111111-22222222-33333333-600)
+D:AI(A;CI;RP LCLORC;;;AU) -> D:AI(A;CI;LCRPLORC;;;AU)
+D:AI(A;CI;RP LCLO RC;;;AU) -> D:AI(A;CI;LCRPLORC;;;AU)
+D:(A;; GA;;;LG) -> D:(A;;GA;;;LG)
+D:(A;; 0x75bcd15;;;LG) -> D:(A;;0x75bcd15;;;LG)
+D:(A;;0x001f01ff;;;WD)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1001)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1002)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1003)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1004)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1005)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1006)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1007)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1008)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1009)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1010)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1011)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1012)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1013)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1014)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1015)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1016)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1017)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1018)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1019)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1020)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1021)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1022)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1023)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1024)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1025)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1026)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1027)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1028)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1029)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1030)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1031)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1032)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1033)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1034)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1035)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1036)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1037)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1038)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1039)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1040)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1041)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1042)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1043)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1044)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1045)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1046)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1047)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1048)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1049)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1050)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1051)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1052)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1053)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1054)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1055)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1056)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1057)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1058)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1059)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1060)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1061)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1062)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1063)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1064)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1065)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1066)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1067)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1068)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1069)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1070)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1071)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1072)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1073)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1074)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1075)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1076)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1077)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1078)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1079)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1080)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1081)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1082)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1083)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1084)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1085)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1086)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1087)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1088)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1089)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1090)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1091)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1092)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1093)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1094)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1095)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1096)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1097)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1098)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1099)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1100)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1101)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1102)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1103)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1104)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1105)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1106)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1107)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1108)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1109)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1110)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1111)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1112)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1113)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1114)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1115)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1116)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1117)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1118)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1119)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1120)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1121)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1122)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1123)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1124)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1125)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1126)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1127)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1128)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1129)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1130)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1131)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1132)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1133)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1134)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1135)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1136)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1137)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1138)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1139)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1140)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1141)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1142)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1143)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1144)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1145)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1146)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1147)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1148)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1149)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1150)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1151)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1152)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1153)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1154)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1155)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1156)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1157)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1158)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1159)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1160)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1161)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1162)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1163)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1164)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1165)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1166)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1167)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1168)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1169)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1170)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1171)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1172)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1173)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1174)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1175)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1176)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1177)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1178)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1179)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1180)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1181)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1182)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1183)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1184)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1185)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1186)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1187)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1188)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1189)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1190)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1191)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1192)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1193)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1194)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1195)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1196)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1197)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1198)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1199)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1200) -> D:(A;;FA;;;WD)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1001)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1002)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1003)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1004)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1005)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1006)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1007)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1008)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1009)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1010)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1011)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1012)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1013)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1014)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1015)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1016)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1017)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1018)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1019)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1020)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1021)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1022)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1023)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1024)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1025)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1026)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1027)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1028)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1029)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1030)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1031)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1032)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1033)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1034)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1035)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1036)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1037)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1038)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1039)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1040)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1041)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1042)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1043)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1044)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1045)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1046)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1047)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1048)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1049)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1050)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1051)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1052)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1053)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1054)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1055)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1056)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1057)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1058)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1059)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1060)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1061)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1062)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1063)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1064)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1065)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1066)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1067)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1068)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1069)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1070)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1071)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1072)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1073)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1074)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1075)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1076)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1077)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1078)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1079)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1080)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1081)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1082)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1083)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1084)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1085)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1086)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1087)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1088)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1089)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1090)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1091)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1092)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1093)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1094)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1095)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1096)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1097)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1098)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1099)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1100)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1101)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1102)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1103)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1104)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1105)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1106)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1107)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1108)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1109)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1110)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1111)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1112)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1113)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1114)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1115)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1116)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1117)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1118)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1119)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1120)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1121)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1122)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1123)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1124)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1125)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1126)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1127)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1128)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1129)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1130)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1131)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1132)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1133)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1134)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1135)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1136)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1137)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1138)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1139)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1140)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1141)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1142)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1143)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1144)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1145)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1146)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1147)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1148)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1149)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1150)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1151)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1152)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1153)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1154)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1155)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1156)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1157)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1158)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1159)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1160)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1161)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1162)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1163)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1164)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1165)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1166)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1167)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1168)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1169)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1170)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1171)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1172)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1173)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1174)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1175)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1176)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1177)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1178)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1179)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1180)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1181)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1182)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1183)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1184)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1185)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1186)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1187)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1188)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1189)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1190)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1191)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1192)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1193)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1194)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1195)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1196)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1197)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1198)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1199)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1200)
+O:S-1-5-21-2212615479-2695158682-2101375468-512G:S-1-5-21-2212615479-2695158682-2101375468-513D:P(A;OICI;0x001f01ff;;;S-1-5-21-2212615479-2695158682-2101375468-512)(A;OICI;0x001f01ff;;;S-1-5-21-2212615479-2695158682-2101375468-519)(A;OICIIO;0x001f01ff;;;CO)(A;OICI;0x001f01ff;;;S-1-5-21-2212615479-2695158682-2101375468-512)(A;OICI;0x001f01ff;;;SY)(A;OICI;0x001200a9;;;AU)(A;OICI;0x001200a9;;;ED)S:AI(OU;CIIDSA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)(OU;CIIDSA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD) -> O:S-1-5-21-2212615479-2695158682-2101375468-512G:S-1-5-21-2212615479-2695158682-2101375468-513D:P(A;OICI;FA;;;S-1-5-21-2212615479-2695158682-2101375468-512)(A;OICI;FA;;;S-1-5-21-2212615479-2695158682-2101375468-519)(A;OICIIO;FA;;;CO)(A;OICI;FA;;;S-1-5-21-2212615479-2695158682-2101375468-512)(A;OICI;FA;;;SY)(A;OICI;0x1200a9;;;AU)(A;OICI;0x1200a9;;;ED)S:AI(OU;CIIDSA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)(OU;CIIDSA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)
+O:LAG:BAD:P(A;OICI;0x1f01ff;;;BA) -> O:LAG:BAD:P(A;OICI;FA;;;BA)
+O:LAG:BAD:(A;;0x1ff;;;WD) -> O:LAG:BAD:(A;;CCDCLCSWRPWPDTLOCR;;;WD)
+D:(A;;FAGX;;;SY) -> D:(A;;0x201f01ff;;;SY)
diff --git a/libcli/security/tests/windows/should_fail.txt b/libcli/security/tests/windows/should_fail.txt
new file mode 100644
index 0000000..35a813d
--- /dev/null
+++ b/libcli/security/tests/windows/should_fail.txt
@@ -0,0 +1,47 @@
+Z:(A;;GA;;;SY) -> Z:(A;;GA;;;SY)
+D:(Antlers;;GA;;;SY) -> D:(Antlers;;GA;;;SY)
+Q:(A;;GA;;;RU) -> Q:(A;;GA;;;RU)
+d:(A;;GA;;;LG) -> d:(A;;GA;;;LG)
+D:((A;;GA;;;LG)) -> D:((A;;GA;;;LG))
+D:(A;;GA;;) -> D:(A;;GA;;)
+D :S: -> D :S:
+S:(AU;SA;CROOO;;;WD)(AU;SA;CR;;;WD) -> S:(AU;SA;CROOO;;;WD)(AU;SA;CR;;;WD)
+D:(A;;GA;;;S-1-0x1313131313131-513) -> D:(A;;GA;;;S-1-0x1313131313131-513)
+D:(A;;GA;a;;S-1-5-21-2447931902-1787058256-0x3961074038-1201) -> D:(A;;GA;a;;S-1-5-21-2447931902-1787058256-0x3961074038-1201)
+D:(A;;GA;a;;S-1-5-21-2447931902-1787058256-0xec193176-1201) -> D:(A;;GA;a;;S-1-5-21-2447931902-1787058256-0xec193176-1201)
+S:(OOU;CISA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD) -> S:(OOU;CISA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)
+S:(OU;CISA;WP;f30e3bbe-9ff0-11d1-b603-00potato7c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-00chips7c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD) -> S:(OU;CISA;WP;f30e3bbe-9ff0-11d1-b603-00potato7c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-00chips7c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)
+D:P:S: -> D:P:S:
+D:(Ā;;GA;;;LG) -> D:(Ā;;GA;;;LG)
+D:(A;;123456789 ;;;LG) -> D:(A;;123456789 ;;;LG)
+D:(A;;0x75bcd15 ;;;LG) -> D:(A;;0x75bcd15 ;;;LG)
+D:(A;; 0x75bcd15;;;LG -> D:(A;; 0x75bcd15;;;LG
+D:(A;;0x 75bcd15;;;LG) -> D:(A;;0x 75bcd15;;;LG)
+D:(A;;GA ;;;LG) -> D:(A;;GA ;;;LG)
+D:(A;;RP ;;;LG) -> D:(A;;RP ;;;LG)
+D:(A;;GA;;;LG;) -> D:(A;;GA;;;LG;)
+D:(A;;GA;;;LG;;) -> D:(A;;GA;;;LG;;)
+D:(A;;GA) -> D:(A;;GA)
+D:(A;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;) -> D:(A;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;)
+D:(A;;GA;;;S-1-3-4 ) -> D:(A;;GA;;;S-1-3-4 )
+D:(A;;GA; f30e3bbf-9ff0-11d1-b603-0000f80367c1;;WD) -> D:(A;;GA; f30e3bbf-9ff0-11d1-b603-0000f80367c1;;WD)
+D:(A;;GA;f30e3bbf-9ff0-11d1-b603-0000f80367c1 ;;WD) -> D:(A;;GA;f30e3bbf-9ff0-11d1-b603-0000f80367c1 ;;WD)
+D:(A;;GA;; f30e3bbf-9ff0-11d1-b603-0000f80367c1;WD) -> D:(A;;GA;; f30e3bbf-9ff0-11d1-b603-0000f80367c1;WD)
+D:(A;;GA;;f30e3bbf-9ff0-11d1-b603-0000f80367c1 ;WD) -> D:(A;;GA;;f30e3bbf-9ff0-11d1-b603-0000f80367c1 ;WD)
+D:(A;;GA;;{f30e3bbf-9ff0-11d1-b603-0000f80367c1};WD) -> D:(A;;GA;;{f30e3bbf-9ff0-11d1-b603-0000f80367c1};WD)
+D:(A;;GA;;0123456789abcdef;WD) -> D:(A;;GA;;0123456789abcdef;WD)
+D:(A;;GA;;0123456789abcdef0123456789abcdef;WD) -> D:(A;;GA;;0123456789abcdef0123456789abcdef;WD)
+D:AI(A;CI;RP LCLOR C;;;AU) -> D:AI(A;CI;RP LCLOR C;;;AU)
+D:AI(A;CI;RP LC LORC;;;AU) -> D:AI(A;CI;RP LC LORC;;;AU)
+D:AI(A;CI;RP LC LORC;;;AU) -> D:AI(A;CI;RP LC LORC;;;AU)
+O:S -> O:S
+O:S- -> O:S-
+O:S-1 -> O:S-1
+O:S-10 -> O:S-10
+O:S-0 -> O:S-0
+O:S-1- -> O:S-1-
+O:S-0x1 -> O:S-0x1
+O:S-0x1- -> O:S-0x1-
+O: -> O:
+O:XX -> O:XX
+D:(D:()D:())D:(A;;0x75bcd15;;;LG)) -> D:(D:()D:())D:(A;;0x75bcd15;;;LG))
diff --git a/libcli/security/tests/windows/windows-sddl-tests.c b/libcli/security/tests/windows/windows-sddl-tests.c
new file mode 100644
index 0000000..3857aef
--- /dev/null
+++ b/libcli/security/tests/windows/windows-sddl-tests.c
@@ -0,0 +1,341 @@
+/*
+ * Test Windows SDDL handling.
+ *
+ * Copyright (c) 2023 Douglas Bagnall <dbagnall@samba.org>
+ *
+ * GPLv3+.
+ *
+ * This can be compiled on Windows under Cygwin, like this:
+ *
+ *
+ * gcc -o windows-sddl-tests windows-sddl-tests.c \
+ * C:/Windows/System32/advapi32.dll -ladvapi32
+ *
+ *
+ * then run like this:
+ *
+ * ./windows-sddl-tests.exe
+ *
+ *
+ * That will show you a mix of success and failure.
+ *
+ * To run the tests in python/samba/tests/sddl.py, edit the method
+ * _test_write_test_strings(), removing the leading underscore so it starts
+ * with "test_". Then running
+ *
+ * make test TESTS='sddl\\b'
+ *
+ * will write some files into /tmp, containing lines like this:
+ *
+ * D:(A;;GA;;;RU) -> D:(A;;GA;;;RU)
+ *
+ * Copy these files to Windows. Then in Cygwin, run this:
+ *
+ * ./windows-sddl-tests.exe -i non_canonical.txt canonical.txt [...]
+ *
+ * and the part of each line before the " -> " will be fed into the SDDL
+ * parser, and back through the serialiser, which should result in the string
+ * after the " -> ". These are the tests that sddl.py does.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <windows.h>
+#include <sddl.h>
+
+#define RED "\033[1;31m"
+#define GREEN "\033[1;32m"
+#define AMBER "\033[33m"
+#define CYAN "\033[1;36m"
+#define C_NORMAL "\033[0m"
+
+/*
+ * Note that the SIDs SA, CA, RS, EA, PA, RO, and CN cannot be set by
+ * an ordinary local Administrator (error 1337, invalid SID). For this
+ * reason we use other SIDs instead/as well, so the list differs from
+ * the python/samba/tests/sddl.py list, which it is otherwise based on.
+ */
+const char *strings[] = {
+ "D:(A;;CC;;;BA)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU)",
+
+ "D:(A;;GA;;;RU)",
+
+ "D:(A;;GA;;;LG)",
+
+ ("D:(A;;RP;;;WD)"
+ "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)"
+ "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)"
+ "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)"
+ "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)"
+ "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)"
+ "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)"
+ "(A;;RPLCLORC;;;AU)"
+ "(A;;RPWPCRLCLOCCRCWDWOSW;;;BO)"
+ "(A;CI;RPWPCRLCLOCCRCWDWOSDSW;;;BA)"
+ "(A;;RPWPCRLCLOCCDCRCWDWOSDDTSW;;;SY)"
+ "(A;CI;RPWPCRLCLOCCDCRCWDWOSDDTSW;;;ES)"
+ "(A;CI;LC;;;RU)"
+ "(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;bf967aba-0de6-11d0-a285-00aa003049e2;RU)"
+ "(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)"
+ "(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)"
+ "(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;bf967aba-0de6-11d0-a285-00aa003049e2;RU)"
+ "(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)"
+ "(OA;;RP;c7407360-20bf-11d0-a768-00aa006e0529;;RU)"
+ "(OA;CIIO;RPLCLORC;;bf967a9c-0de6-11d0-a285-00aa003049e2;RU)"
+ "(A;;RPRC;;;RU)"
+ "(OA;CIIO;RPLCLORC;;bf967aba-0de6-11d0-a285-00aa003049e2;RU)"
+ "(A;;LCRPLORC;;;ED)"
+ "(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)"
+ "(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)"
+ "(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)"
+ "(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)"
+ "(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)"
+ "(OA;CIIO;RPLCLORC;;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)"
+ "(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;RU)"
+ "(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;AU)"
+ "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967aba-0de6-11d0-a285-00aa003049e2;ED)"
+ "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a9c-0de6-11d0-a285-00aa003049e2;ED)"
+ "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a86-0de6-11d0-a285-00aa003049e2;ED)"
+ "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;NO)"
+ "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)"
+ "(OA;;CR;e2a36dc9-ae17-47c3-b58b-be34c55ba633;;SU)"
+ "(OA;;CR;280f369c-67c7-438e-ae98-1d46f3c6f541;;AU)"
+ "(OA;;CR;ccc2dc7d-a6ad-4a7a-8846-c04e3cc53501;;AU)"
+ "(OA;;CR;05c74c5e-4deb-43b4-bd9f-86664c2a7fd5;;AU)S:(AU;SA;WDWOWP;;;WD)"),
+
+ ("S:(AU;SA;CR;;;WD)"
+ "(AU;SA;CR;;;WD)"),
+
+ ("S:""(OU;CISA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)"
+ "(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)"),
+
+ ("D:(A;;RPLCLORC;;;BO)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPLCLORC;;;AU)"),
+
+ ("D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;AO)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPCRLCLORCSDDT;;;CO)"
+ "(OA;;WP;4c164200-20c0-11d0-a768-00aa006e0529;;CO)"
+ "(A;;RPLCLORC;;;AU)"
+ "(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;WD)"
+ "(A;;CCDC;;;PS)"
+ "(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)"
+ "(OA;;RPWP;bf967a7f-0de6-11d0-a285-00aa003049e2;;SY)"
+ "(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;PS)"
+ "(OA;;RPWP;77B5B886-944A-11d1-AEBD-0000F80367C1;;PS)"
+ "(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;PS)"
+ "(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;CO)"
+ "(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;CO)"
+ "(OA;;WP;3e0abfd0-126a-11d0-a060-00aa006c33ed;bf967a86-0de6-11d0-a285-00aa003049e2;CO)"
+ "(OA;;WP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967a86-0de6-11d0-a285-00aa003049e2;CO)"
+ "(OA;;WP;bf967950-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)"
+ "(OA;;WP;bf967953-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)"
+ "(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU)"),
+
+ ("D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPLCLORC;;;AU)"),
+
+ ("D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPLCLORC;;;AU)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;AO)"
+ "(A;;RPLCLORC;;;PS)"
+ "(OA;;CR;ab721a55-1e2f-11d0-9819-00aa0040529b;;AU)"
+ "(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU)"),
+
+ ("D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPLCLORC;;;AU)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;CO)"),
+
+ ("D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPLCLORC;;;AU)S:(AU;SA;CRWP;;;WD)"),
+
+ ("D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;AO)"
+ "(A;;RPLCLORC;;;PS)"
+ "(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;PS)"
+ "(OA;;CR;ab721a54-1e2f-11d0-9819-00aa0040529b;;PS)"
+ "(OA;;CR;ab721a56-1e2f-11d0-9819-00aa0040529b;;PS)"
+ "(OA;;RPWP;77B5B886-944A-11d1-AEBD-0000F80367C1;;PS)"
+ "(OA;;RPWP;E45795B2-9455-11d1-AEBD-0000F80367C1;;PS)"
+ "(OA;;RPWP;E45795B3-9455-11d1-AEBD-0000F80367C1;;PS)"
+ "(OA;;RP;037088f8-0ae1-11d2-b422-00a0c968f939;;RD)"
+ "(OA;;RP;4c164200-20c0-11d0-a768-00aa006e0529;;RD)"
+ "(OA;;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;;RD)"
+ "(A;;RC;;;AU)"
+ "(OA;;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;;AU)"
+ "(OA;;RP;77B5B886-944A-11d1-AEBD-0000F80367C1;;AU)"
+ "(OA;;RP;E45795B3-9455-11d1-AEBD-0000F80367C1;;AU)"
+ "(OA;;RP;e48d0154-bcf8-11d1-8702-00c04fb96050;;AU)"
+ "(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;WD)"
+ "(OA;;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;;RD)"
+ "(OA;;RPWP;bf967a7f-0de6-11d0-a285-00aa003049e2;;SY)"
+ "(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU)"
+ "(OA;;WPRP;6db69a1c-9422-11d1-aebd-0000f80367c1;;SU)"),
+
+ "D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)",
+
+ ("D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPLCLORC;;;AU)"
+ "(A;;LCRPLORC;;;ED)"),
+
+ ("D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)"
+ "(OA;;CCDC;bf967a86-0de6-11d0-a285-00aa003049e2;;AO)"
+ "(OA;;CCDC;bf967aba-0de6-11d0-a285-00aa003049e2;;AO)"
+ "(OA;;CCDC;bf967a9c-0de6-11d0-a285-00aa003049e2;;AO)"
+ "(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)"
+ "(A;;RPLCLORC;;;AU)"
+ "(A;;LCRPLORC;;;ED)"
+ "(OA;;CCDC;4828CC14-1437-45bc-9B07-AD6F015E5F28;;AO)"),
+
+ ("D:(A;;RPWPCRCCDCLCLORCWOWDSW;;;BO)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPLCLORC;;;AU)"),
+
+ ("D:(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPLCLORC;;;AU)"),
+
+ "D:S:",
+ "D:PS:",
+ NULL
+};
+
+
+static int test_pair(const char *s, const char *canonical)
+{
+ PSECURITY_DESCRIPTOR sd = NULL;
+ ULONG len;
+ char *return_string = NULL;
+ ULONG return_len;
+ int ok = ConvertStringSecurityDescriptorToSecurityDescriptorA(s,
+ 1,
+ &sd,
+ &len);
+ if (!ok) {
+ int e = GetLastError();
+ const char *ename = NULL;
+ switch(e) {
+ case 1337:
+ ename = " invalid sid";
+ break;
+ case 1336:
+ ename = " insufficient privs/SACL vs DACL/something something";
+ break;
+ case 1804:
+ ename = " invalid datatype";
+ break;
+ default:
+ ename = "";
+ }
+
+ printf(RED "not ok:" AMBER " %d%s" C_NORMAL ": %s\n",
+ e, ename, s);
+ return e;
+ }
+ if (sd == NULL) {
+ printf(RED "NULL sd" C_NORMAL": %s\n", s);
+ return -1;
+ }
+
+ ok = ConvertSecurityDescriptorToStringSecurityDescriptorA(
+ sd,
+ 1,
+ ~BACKUP_SECURITY_INFORMATION,
+ &return_string,
+ &return_len);
+ if (strncmp(return_string, canonical, return_len) != 0) {
+ printf(RED "return differs:" AMBER " %u vs %u" C_NORMAL "\n",
+ len, return_len);
+ printf(RED "original:" C_NORMAL ": %s\n", s);
+ printf(RED "returned:" C_NORMAL ": %s\n", return_string);
+ return -2;
+ }
+ printf(GREEN "GOOD" C_NORMAL ": %s\n", s);
+ if (strncmp(return_string, s, return_len) != 0) {
+ printf(CYAN "original:" C_NORMAL ": %s\n", s);
+ printf(CYAN "returned:" C_NORMAL ": %s\n", return_string);
+ return -2;
+ }
+ return 0;
+}
+
+
+int test_from_files(int argc, const char *argv[])
+{
+ size_t i, j;
+ static char buf[100000];
+
+ for (i = 0; i < argc; i++) {
+ char *orig = NULL;
+ char *canon = NULL;
+ size_t len;
+ FILE *f = fopen(argv[i], "r");
+ if (f == NULL) {
+ printf(RED "bad filename? %s\n" C_NORMAL,
+ argv[i]);
+ }
+ len = fread(buf, 1, sizeof(buf), f);
+
+ if (len >= sizeof(buf) - 1 || len == 0) {
+ printf(RED "couldn't read %s\n" C_NORMAL, argv[i]);
+ continue;
+ }
+ printf(CYAN "%s\n" C_NORMAL, argv[i]);
+ buf[len] = 0;
+ orig = buf;
+ for (j = 0; j < len; j++) {
+ char c = buf[j];
+ if (c == '\n') {
+ buf[j] = 0;
+ if (j != 0 && buf[j - 1] == '\r') {
+ buf[j - 1] = 0;
+ }
+ if (orig && canon) {
+ test_pair(orig, canon);
+ canon = NULL;
+ } else {
+ printf(RED "bad pair %s -> %s\n" C_NORMAL,
+ orig, canon);
+ }
+ orig = buf + j + 1;
+ } else if (c == ' ' && j + 4 < len &&
+ buf[j + 1] == '-' &&
+ buf[j + 2] == '>' &&
+ buf[j + 3] == ' ') {
+ buf[j] = 0;
+ canon = buf + j + 4;
+ }
+ }
+ }
+}
+
+int main(int argc, const char *argv[])
+{
+ uint32_t i;
+ if (argc < 2) {
+ for (i = 0; strings[i] != NULL; i++) {
+ test_pair(strings[i], strings[i]);
+ }
+ } else if (strncmp("-i", argv[1], 2) == 0) {
+ return test_from_files(argc - 2, argv + 2);
+ } else {
+ for (i = 1; i < argc; i++) {
+ test_pair(argv[i], argv[i]);
+ }
+ }
+ return 0;
+}
diff --git a/libcli/security/tests/windows/windows-sddl-tests.py b/libcli/security/tests/windows/windows-sddl-tests.py
new file mode 100644
index 0000000..38acb44
--- /dev/null
+++ b/libcli/security/tests/windows/windows-sddl-tests.py
@@ -0,0 +1,181 @@
+# Test SDDL strings on Windows
+#
+#
+# Copyright (c) 2023 Catalyst IT
+#
+# GPLv3+.
+#
+# This uses the Python win32 module to access
+# ConvertStringSecurityDescriptorToSecurityDescriptor and the like. To
+# install this, you need to go
+#
+# pip install pywin32
+#
+# or something like that.
+
+import argparse
+from difflib import SequenceMatcher
+from collections import defaultdict
+import sys
+import json
+
+try:
+ import win32security as w
+except ImportError:
+ print("This test script is meant to be run on Windows using the pywin32 module.")
+ print("To install this module, try:\n")
+ print("pip install pywin32")
+ sys.exit(1)
+
+
+# This is necessary for ANSI colour escapes to work in Powershell.
+import os
+os.system('')
+
+RED = "\033[1;31m"
+GREEN = "\033[1;32m"
+DARK_YELLOW = "\033[0;33m"
+C_NORMAL = "\033[0m"
+
+def c_RED(s):
+ return f"{RED}{s}{C_NORMAL}"
+def c_GREEN(s):
+ return f"{GREEN}{s}{C_NORMAL}"
+def c_DY(s):
+ return f"{DARK_YELLOW}{s}{C_NORMAL}"
+
+
+def read_strings(files):
+ """Try to read as JSON a JSON dictionary first, then secondly in the bespoke
+ sddl-in -> sddl-out
+ format used by other Samba SDDL test programs on Windows.
+ """
+ pairs = []
+ for filename in files:
+ with open(filename) as f:
+ try:
+ data = json.load(f)
+ print(f"loading {filename} as JSON")
+ for k, v in data.items():
+ if not v or not isinstance(v, str):
+ v = k
+ pairs.append((k, v))
+ continue
+ except json.JSONDecodeError:
+ pass
+
+ print(f"loading {filename} as 'a -> b' style")
+ f.seek(0)
+ for line in f:
+ line = line.rstrip()
+ if line.startswith('#') or line == '':
+ continue
+ # note: if the line does not have ' -> ', we expect a
+ # perfect round trip.
+ o, _, c = line.partition(' -> ')
+ if c == '':
+ c = o
+ pairs.append((o, c))
+
+ return pairs
+
+
+def colourdiff(a, b):
+ out = []
+ a = a.replace(' ', '␠')
+ b = b.replace(' ', '␠')
+
+ s = SequenceMatcher(None, a, b)
+ for op, al, ar, bl, br in s.get_opcodes():
+ if op == 'equal':
+ out.append(a[al: ar])
+ elif op == 'delete':
+ out.append(c_RED(a[al: ar]))
+ elif op == 'insert':
+ out.append(c_GREEN(b[bl: br]))
+ elif op == 'replace':
+ out.append(c_RED(a[al: ar]))
+ out.append(c_GREEN(b[bl: br]))
+ else:
+ print(f'unknown op {op}!')
+
+ return ''.join(out)
+
+
+def no_print(*args, **kwargs):
+ pass
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--export-bytes', const='sddl_bytes.json', nargs='?',
+ help='write JSON file containing SD bytes')
+ parser.add_argument('--quiet', action='store_true',
+ help='avoid printing to stdout')
+ parser.add_argument('files', nargs='+', help='read these files')
+
+ args = parser.parse_args()
+
+ if args.quiet:
+ global print
+ print = no_print
+
+ cases = read_strings(args.files)
+ parseable_cases = []
+ unparseable_cases = []
+ unserializeable_cases = []
+ round_trip_failures = []
+ exceptions = defaultdict(list)
+ bytes_json = {}
+
+ print(f"{len(set(cases))}/{len(cases)} unique pairs, "
+ f"{len(set(x[0] for x in cases))}/{len(cases)} unique strings")
+
+ for a, b in sorted(set(cases)):
+ try:
+ sd = w.ConvertStringSecurityDescriptorToSecurityDescriptor(a, 1)
+ except Exception as e:
+ print(a)
+ exceptions[f"{e} parse"].append(a)
+ print(c_RED(e))
+ unparseable_cases.append(a)
+ continue
+
+ parseable_cases.append(a)
+
+ try:
+ # maybe 0xffff is an incorrect guess -- it gives use v2 (NT), not v4 (AD)
+ c = w.ConvertSecurityDescriptorToStringSecurityDescriptor(sd, 1, 0xffff)
+ except Exception as e:
+ print(f"could not serialize '{sd}': {e}")
+ print(f" derived from '{a}'")
+ exceptions[f"{e} serialize"].append(a)
+ unserializeable_cases.append(a)
+ continue
+
+ if args.export_bytes:
+ bytes_json[c] = list(bytes(sd))
+
+ if c != b:
+ round_trip_failures.append((a, b, c))
+ exceptions["mismatch"].append(a)
+ #print(f"{c_GREEN(a)} -> {c_DY(c)}")
+ print(colourdiff(b, c))
+ print(c_DY(f"{b} -> {c}"))
+
+ for k, v in exceptions.items():
+ print(f"{k}: {len(v)}")
+
+ print(f"{len(unparseable_cases)} failed to parse")
+ print(f"{len(parseable_cases)} successfully parsed")
+ print(f"{len(unserializeable_cases)} of these failed to re-serialize")
+ print(f"{len(round_trip_failures)} of these failed to round trip")
+ #for p in parseable_cases:
+ # print(f"«{c_GREEN(p)}»")
+
+ if args.export_bytes:
+ with open(args.export_bytes, 'w') as f:
+ json.dump(bytes_json, f)
+ print(f"wrote bytes to {args.export_bytes}")
+
+main()
diff --git a/libcli/security/tests/windows/windows_is_fussy.txt b/libcli/security/tests/windows/windows_is_fussy.txt
new file mode 100644
index 0000000..b058a67
--- /dev/null
+++ b/libcli/security/tests/windows/windows_is_fussy.txt
@@ -0,0 +1 @@
+D:(A;;RP;;;WD)(AU;SA;CR;;;BA)(AU;SA;CR;;;DU) -> D:(A;;RP;;;WD)(AU;SA;CR;;;BA)(AU;SA;CR;;;DU)
diff --git a/libcli/security/tests/windows/windows_is_less_fussy.txt b/libcli/security/tests/windows/windows_is_less_fussy.txt
new file mode 100644
index 0000000..17e2e5b
--- /dev/null
+++ b/libcli/security/tests/windows/windows_is_less_fussy.txt
@@ -0,0 +1,23 @@
+D:(A;;GA;;; LG) -> D:(A;;GA;;;LG)
+D: (A;;GA;;;LG) -> D:(A;;GA;;;LG)
+D: AI(A;;GA;;;LG) -> D:AI(A;;GA;;;LG)
+D:(a;;GA;;;LG) -> D:(A;;GA;;;LG)
+D:(A;;GA;;;lg) -> D:(A;;GA;;;LG)
+D:(A;;ga;;;LG) -> D:(A;;GA;;;LG)
+D: S: -> D:S:
+D: P(A;;GA;;;LG) -> D:P(A;;GA;;;LG)
+D:P (A;;GA;;;LG) -> D:P(A;;GA;;;LG)
+D:P(A;;GA;;;LG) (A;;GX;;;AA) -> D:P(A;;GA;;;LG)(A;;GX;;;AA)
+D:(A; ;GA;;;LG) -> D:(A;;GA;;;LG)
+D:AI (A;;GA;;;LG) -> D:AI(A;;GA;;;LG)
+D:(A;;GA;;; WD) -> D:(A;;GA;;;WD)
+D:(A;;GA;;;WD ) -> D:(A;;GA;;;WD)
+D:(A;;GA;;; S-1-3-4) -> D:(A;;GA;;;OW)
+D:(A;;GA;; ;S-1-3-4) -> D:(A;;GA;;;OW)
+D:(A;;GA; ;;S-1-3-4) -> D:(A;;GA;;;OW)
+D:(A;;GA;;; S-1-333-4) -> D:(A;;GA;;;S-1-333-4)
+D:(A;;GA; ;;S-1-333-4) -> D:(A;;GA;;;S-1-333-4)
+ O:AA -> O:AA
+ O:AA -> O:AA
+ O:AA G:WD -> O:AAG:WD
+O:S- 1- 2-3 -> O:S-1-2-3
diff --git a/libcli/security/tests/windows/windows_is_weird.txt b/libcli/security/tests/windows/windows_is_weird.txt
new file mode 100644
index 0000000..7c9d265
--- /dev/null
+++ b/libcli/security/tests/windows/windows_is_weird.txt
@@ -0,0 +1,10 @@
+D:(A;;0x123456789;;;LG) -> D:(A;;0xffffffff;;;LG)
+D:(A;;CC;;;S-0x1-0-0-579) -> D:(A;;CC;;;S-1-0-0-1401)
+O:S-0x1-20-0-579 -> O:S-1-32-0-1401
+D:(A;;GA;;;S-1-3-4294967296-3-4) -> D:(A;;GA;;;S-1-3-4294967295-3-4)
+D:(A;;GA;;;S-1-3-0x100000000-3-4) -> D:(A;;GA;;;S-1-3-4294967295-3-4)
+D:(A;;GA;;;S-1-5-21-0x1313131313131-513) -> D:(A;;GA;;;S-1-5-21-4294967295-513)
+D:(A;;-99;;;LG) -> D:(A;;0xffffff9d;;;LG)
+D:(A;;-0xffffff55;;;LG) -> D:(A;;CCDCSWWPLO;;;LG)
+D:(A;;-9876543210;;;LG) -> D:(A;;CC;;;LG)
+D:(A;;100000000000000000000000;;;LG) -> D:(A;;0xffffffff;;;LG)
diff --git a/libcli/security/util_sid.c b/libcli/security/util_sid.c
new file mode 100644
index 0000000..54a2fc3
--- /dev/null
+++ b/libcli/security/util_sid.c
@@ -0,0 +1,1117 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Luke Kenneth Caseson Leighton 1998-1999
+ Copyright (C) Jeremy Allison 1999
+ Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Simo Sorce 2002
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
+ Copyright (C) Andrew Bartlett 2010
+
+ 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 "replace.h"
+#include "lib/util/samba_util.h"
+#include "../librpc/gen_ndr/ndr_security.h"
+#include "../librpc/gen_ndr/netlogon.h"
+#include "../libcli/security/security.h"
+#include "auth/auth.h"
+
+
+#undef strcasecmp
+#undef strncasecmp
+
+/*
+ * Some useful sids, more well known sids can be found at
+ * http://support.microsoft.com/kb/243330/EN-US/
+ */
+
+
+/* S-1-1 */
+const struct dom_sid global_sid_World_Domain = /* Everyone domain */
+{ 1, 0, {0,0,0,0,0,1}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-1-0 */
+const struct dom_sid global_sid_World = /* Everyone */
+{ 1, 1, {0,0,0,0,0,1}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-2 */
+const struct dom_sid global_sid_Local_Authority = /* Local Authority */
+{ 1, 0, {0,0,0,0,0,2}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-3 */
+const struct dom_sid global_sid_Creator_Owner_Domain = /* Creator Owner domain */
+{ 1, 0, {0,0,0,0,0,3}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5 */
+const struct dom_sid global_sid_NT_Authority = /* NT Authority */
+{ 1, 0, {0,0,0,0,0,5}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-18 */
+const struct dom_sid global_sid_System = /* System */
+{ 1, 1, {0,0,0,0,0,5}, {18,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-0-0 */
+const struct dom_sid global_sid_NULL = /* NULL sid */
+{ 1, 1, {0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-10 */
+const struct dom_sid global_sid_Self = /* SELF */
+{ 1, 1, {0,0,0,0,0,5}, {10,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-11 */
+const struct dom_sid global_sid_Authenticated_Users = /* All authenticated rids */
+{ 1, 1, {0,0,0,0,0,5}, {11,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+#if 0
+/* for documentation S-1-5-12 */
+const struct dom_sid global_sid_Restricted = /* Restricted Code */
+{ 1, 1, {0,0,0,0,0,5}, {12,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+#endif
+
+/* S-1-18 */
+const struct dom_sid global_sid_Asserted_Identity = /* Asserted Identity */
+{ 1, 0, {0,0,0,0,0,18}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-18-1 */
+const struct dom_sid global_sid_Asserted_Identity_Authentication_Authority = /* Asserted Identity Authentication Authority */
+{ 1, 1, {0,0,0,0,0,18}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-18-2 */
+const struct dom_sid global_sid_Asserted_Identity_Service = /* Asserted Identity Service */
+{ 1, 1, {0,0,0,0,0,18}, {2,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+
+/* S-1-5-2 */
+const struct dom_sid global_sid_Network = /* Network rids */
+{ 1, 1, {0,0,0,0,0,5}, {2,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+
+/* S-1-3 */
+const struct dom_sid global_sid_Creator_Owner = /* Creator Owner */
+{ 1, 1, {0,0,0,0,0,3}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-3-1 */
+const struct dom_sid global_sid_Creator_Group = /* Creator Group */
+{ 1, 1, {0,0,0,0,0,3}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-3-4 */
+const struct dom_sid global_sid_Owner_Rights = /* Owner Rights */
+{ 1, 1, {0,0,0,0,0,3}, {4,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-7 */
+const struct dom_sid global_sid_Anonymous = /* Anonymous login */
+{ 1, 1, {0,0,0,0,0,5}, {7,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-9 */
+const struct dom_sid global_sid_Enterprise_DCs = /* Enterprise DCs */
+{ 1, 1, {0,0,0,0,0,5}, {9,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-21-0-0-0-496 */
+const struct dom_sid global_sid_Compounded_Authentication = /* Compounded Authentication */
+{1, 5, {0,0,0,0,0,5}, {21,0,0,0,496,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-21-0-0-0-497 */
+const struct dom_sid global_sid_Claims_Valid = /* Claims Valid */
+{1, 5, {0,0,0,0,0,5}, {21,0,0,0,497,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32 */
+const struct dom_sid global_sid_Builtin = /* Local well-known domain */
+{ 1, 1, {0,0,0,0,0,5}, {32,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32-544 */
+const struct dom_sid global_sid_Builtin_Administrators = /* Builtin administrators */
+{ 1, 2, {0,0,0,0,0,5}, {32,544,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32-545 */
+const struct dom_sid global_sid_Builtin_Users = /* Builtin users */
+{ 1, 2, {0,0,0,0,0,5}, {32,545,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32-546 */
+const struct dom_sid global_sid_Builtin_Guests = /* Builtin guest users */
+{ 1, 2, {0,0,0,0,0,5}, {32,546,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32-547 */
+const struct dom_sid global_sid_Builtin_Power_Users = /* Builtin power users */
+{ 1, 2, {0,0,0,0,0,5}, {32,547,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32-548 */
+const struct dom_sid global_sid_Builtin_Account_Operators = /* Builtin account operators */
+{ 1, 2, {0,0,0,0,0,5}, {32,548,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32-549 */
+const struct dom_sid global_sid_Builtin_Server_Operators = /* Builtin server operators */
+{ 1, 2, {0,0,0,0,0,5}, {32,549,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32-550 */
+const struct dom_sid global_sid_Builtin_Print_Operators = /* Builtin print operators */
+{ 1, 2, {0,0,0,0,0,5}, {32,550,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32-551 */
+const struct dom_sid global_sid_Builtin_Backup_Operators = /* Builtin backup operators */
+{ 1, 2, {0,0,0,0,0,5}, {32,551,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32-552 */
+const struct dom_sid global_sid_Builtin_Replicator = /* Builtin replicator */
+{ 1, 2, {0,0,0,0,0,5}, {32,552,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32-554 */
+const struct dom_sid global_sid_Builtin_PreWin2kAccess = /* Builtin pre win2k access */
+{ 1, 2, {0,0,0,0,0,5}, {32,554,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+
+/* S-1-22-1 */
+const struct dom_sid global_sid_Unix_Users = /* Unmapped Unix users */
+{ 1, 1, {0,0,0,0,0,22}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-22-2 */
+const struct dom_sid global_sid_Unix_Groups = /* Unmapped Unix groups */
+{ 1, 1, {0,0,0,0,0,22}, {2,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+
+/*
+ * http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
+ */
+/* S-1-5-88 */
+const struct dom_sid global_sid_Unix_NFS = /* MS NFS and Apple style */
+{ 1, 1, {0,0,0,0,0,5}, {88,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-88-1 */
+const struct dom_sid global_sid_Unix_NFS_Users = /* Unix uid, MS NFS and Apple style */
+{ 1, 2, {0,0,0,0,0,5}, {88,1,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-88-2 */
+const struct dom_sid global_sid_Unix_NFS_Groups = /* Unix gid, MS NFS and Apple style */
+{ 1, 2, {0,0,0,0,0,5}, {88,2,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-88-3 */
+const struct dom_sid global_sid_Unix_NFS_Mode = /* Unix mode */
+{ 1, 2, {0,0,0,0,0,5}, {88,3,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* Unused, left here for documentary purposes */
+#if 0
+const struct dom_sid global_sid_Unix_NFS_Other = /* Unix other, MS NFS and Apple style */
+{ 1, 2, {0,0,0,0,0,5}, {88,4,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+#endif
+
+/* Information passing via security token */
+const struct dom_sid global_sid_Samba_SMB3 =
+{1, 1, {0,0,0,0,0,22}, {1397571891, }};
+
+const struct dom_sid global_sid_Samba_NPA_Flags = {1,
+ 1,
+ {0, 0, 0, 0, 0, 22},
+ {
+ 2041152804,
+ }};
+
+/* Unused, left here for documentary purposes */
+#if 0
+#define SECURITY_NULL_SID_AUTHORITY 0
+#define SECURITY_WORLD_SID_AUTHORITY 1
+#define SECURITY_LOCAL_SID_AUTHORITY 2
+#define SECURITY_CREATOR_SID_AUTHORITY 3
+#define SECURITY_NT_AUTHORITY 5
+#endif
+
+static struct dom_sid system_sid_array[1] =
+{ { 1, 1, {0,0,0,0,0,5}, {18,0,0,0,0,0,0,0,0,0,0,0,0,0,0}} };
+static const struct security_token system_token = {
+ .num_sids = ARRAY_SIZE(system_sid_array),
+ .sids = system_sid_array,
+ .privilege_mask = SE_ALL_PRIVS
+};
+
+/****************************************************************************
+ Lookup string names for SID types.
+****************************************************************************/
+
+const char *sid_type_lookup(uint32_t sid_type)
+{
+ switch (sid_type) {
+ case SID_NAME_USE_NONE:
+ return "None";
+ break;
+ case SID_NAME_USER:
+ return "User";
+ break;
+ case SID_NAME_DOM_GRP:
+ return "Domain Group";
+ break;
+ case SID_NAME_DOMAIN:
+ return "Domain";
+ break;
+ case SID_NAME_ALIAS:
+ return "Local Group";
+ break;
+ case SID_NAME_WKN_GRP:
+ return "Well-known Group";
+ break;
+ case SID_NAME_DELETED:
+ return "Deleted Account";
+ break;
+ case SID_NAME_INVALID:
+ return "Invalid Account";
+ break;
+ case SID_NAME_UNKNOWN:
+ return "UNKNOWN";
+ break;
+ case SID_NAME_COMPUTER:
+ return "Computer";
+ break;
+ case SID_NAME_LABEL:
+ return "Mandatory Label";
+ break;
+ }
+
+ /* Default return */
+ return "SID *TYPE* is INVALID";
+}
+
+/**************************************************************************
+ Create the SYSTEM token.
+***************************************************************************/
+
+const struct security_token *get_system_token(void)
+{
+ return &system_token;
+}
+
+bool sid_compose(struct dom_sid *dst, const struct dom_sid *domain_sid, uint32_t rid)
+{
+ sid_copy(dst, domain_sid);
+ return sid_append_rid(dst, rid);
+}
+
+/*****************************************************************
+ Removes the last rid from the end of a sid
+*****************************************************************/
+
+bool sid_split_rid(struct dom_sid *sid, uint32_t *rid)
+{
+ if (sid->num_auths > 0) {
+ sid->num_auths--;
+ if (rid != NULL) {
+ *rid = sid->sub_auths[sid->num_auths];
+ }
+ return true;
+ }
+ return false;
+}
+
+/*****************************************************************
+ Return the last rid from the end of a sid
+*****************************************************************/
+
+bool sid_peek_rid(const struct dom_sid *sid, uint32_t *rid)
+{
+ if (!sid || !rid)
+ return false;
+
+ if (sid->num_auths > 0) {
+ *rid = sid->sub_auths[sid->num_auths - 1];
+ return true;
+ }
+ return false;
+}
+
+/*****************************************************************
+ Return the last rid from the end of a sid
+ and check the sid against the exp_dom_sid
+*****************************************************************/
+
+bool sid_peek_check_rid(const struct dom_sid *exp_dom_sid, const struct dom_sid *sid, uint32_t *rid)
+{
+ if (!exp_dom_sid || !sid || !rid)
+ return false;
+
+ if (sid->num_auths != (exp_dom_sid->num_auths+1)) {
+ return false;
+ }
+
+ if (dom_sid_compare_domain(exp_dom_sid, sid)!=0){
+ *rid=(-1);
+ return false;
+ }
+
+ return sid_peek_rid(sid, rid);
+}
+
+/*****************************************************************
+ Copies a sid
+*****************************************************************/
+
+void sid_copy(struct dom_sid *dst, const struct dom_sid *src)
+{
+ int i;
+
+ *dst = (struct dom_sid) {
+ .sid_rev_num = src->sid_rev_num,
+ .num_auths = src->num_auths,
+ };
+
+ memcpy(&dst->id_auth[0], &src->id_auth[0], sizeof(src->id_auth));
+
+ for (i = 0; i < src->num_auths; i++)
+ dst->sub_auths[i] = src->sub_auths[i];
+}
+
+/*****************************************************************
+ Parse a on-the-wire SID to a struct dom_sid.
+*****************************************************************/
+
+ssize_t sid_parse(const uint8_t *inbuf, size_t len, struct dom_sid *sid)
+{
+ DATA_BLOB in = data_blob_const(inbuf, len);
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_pull_struct_blob_all(
+ &in, NULL, sid, (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return -1;
+ }
+ return ndr_size_dom_sid(sid, 0);
+}
+
+/********************************************************************
+ Add SID to an array of SIDs
+********************************************************************/
+
+NTSTATUS add_sid_to_array(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
+ struct dom_sid **sids, uint32_t *num)
+{
+ struct dom_sid *tmp;
+
+ if ((*num) == UINT32_MAX) {
+ return NT_STATUS_INTEGER_OVERFLOW;
+ }
+
+ tmp = talloc_realloc(mem_ctx, *sids, struct dom_sid, (*num)+1);
+ if (tmp == NULL) {
+ *num = 0;
+ return NT_STATUS_NO_MEMORY;
+ }
+ *sids = tmp;
+
+ sid_copy(&((*sids)[*num]), sid);
+ *num += 1;
+
+ return NT_STATUS_OK;
+}
+
+
+/********************************************************************
+ Add SID to an array of SIDs ensuring that it is not already there
+********************************************************************/
+
+NTSTATUS add_sid_to_array_unique(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
+ struct dom_sid **sids, uint32_t *num_sids)
+{
+ bool contains;
+
+ contains = sids_contains_sid(*sids, *num_sids, sid);
+ if (contains) {
+ return NT_STATUS_OK;
+ }
+
+ return add_sid_to_array(mem_ctx, sid, sids, num_sids);
+}
+
+/**
+ * Appends a SID and attribute to an array of auth_SidAttr.
+ *
+ * @param [in] mem_ctx Talloc memory context on which to allocate the array.
+ * @param [in] sid The SID to append.
+ * @param [in] attrs SE_GROUP_* flags to go with the SID.
+ * @param [inout] sids A pointer to the auth_SidAttr array.
+ * @param [inout] num A pointer to the size of the auth_SidArray array.
+ * @returns NT_STATUS_OK on success.
+ */
+NTSTATUS add_sid_to_array_attrs(TALLOC_CTX *mem_ctx,
+ const struct dom_sid *sid, uint32_t attrs,
+ struct auth_SidAttr **sids, uint32_t *num)
+{
+ struct auth_SidAttr *tmp = NULL;
+
+ if ((*num) == UINT32_MAX) {
+ return NT_STATUS_INTEGER_OVERFLOW;
+ }
+
+ tmp = talloc_realloc(mem_ctx, *sids, struct auth_SidAttr, (*num)+1);
+ if (tmp == NULL) {
+ *num = 0;
+ return NT_STATUS_NO_MEMORY;
+ }
+ *sids = tmp;
+
+ sid_copy(&((*sids)[*num].sid), sid);
+ (*sids)[*num].attrs = attrs;
+ *num += 1;
+
+ return NT_STATUS_OK;
+}
+
+
+/**
+ * Appends a SID and attribute to an array of auth_SidAttr,
+ * ensuring that it is not already there.
+ *
+ * @param [in] mem_ctx Talloc memory context on which to allocate the array.
+ * @param [in] sid The SID to append.
+ * @param [in] attrs SE_GROUP_* flags to go with the SID.
+ * @param [inout] sids A pointer to the auth_SidAttr array.
+ * @param [inout] num_sids A pointer to the size of the auth_SidArray array.
+ * @returns NT_STATUS_OK on success.
+ */
+NTSTATUS add_sid_to_array_attrs_unique(TALLOC_CTX *mem_ctx,
+ const struct dom_sid *sid, uint32_t attrs,
+ struct auth_SidAttr **sids, uint32_t *num_sids)
+{
+ bool contains;
+
+ contains = sids_contains_sid_attrs(*sids, *num_sids, sid, attrs);
+ if (contains) {
+ return NT_STATUS_OK;
+ }
+
+ return add_sid_to_array_attrs(mem_ctx, sid, attrs, sids, num_sids);
+}
+
+/********************************************************************
+ Remove SID from an array
+********************************************************************/
+
+void del_sid_from_array(const struct dom_sid *sid, struct dom_sid **sids,
+ uint32_t *num)
+{
+ struct dom_sid *sid_list = *sids;
+ uint32_t i;
+
+ for ( i=0; i<*num; i++ ) {
+
+ /* if we find the SID, then decrement the count
+ and break out of the loop */
+
+ if (dom_sid_equal(sid, &sid_list[i])) {
+ *num -= 1;
+ break;
+ }
+ }
+
+ /* This loop will copy the remainder of the array
+ if i < num of sids in the array */
+
+ for ( ; i<*num; i++ ) {
+ sid_copy( &sid_list[i], &sid_list[i+1] );
+ }
+}
+
+bool add_rid_to_array_unique(TALLOC_CTX *mem_ctx,
+ uint32_t rid, uint32_t **pp_rids, size_t *p_num)
+{
+ size_t i;
+
+ for (i=0; i<*p_num; i++) {
+ if ((*pp_rids)[i] == rid)
+ return true;
+ }
+
+ *pp_rids = talloc_realloc(mem_ctx, *pp_rids, uint32_t, *p_num+1);
+
+ if (*pp_rids == NULL) {
+ *p_num = 0;
+ return false;
+ }
+
+ (*pp_rids)[*p_num] = rid;
+ *p_num += 1;
+ return true;
+}
+
+bool is_null_sid(const struct dom_sid *sid)
+{
+ static const struct dom_sid null_sid = {0};
+ return dom_sid_equal(sid, &null_sid);
+}
+
+/**
+ * Return true if an array of SIDs contains a certain SID.
+ *
+ * @param [in] sids The SID array.
+ * @param [in] num_sids The size of the SID array.
+ * @param [in] sid The SID in question.
+ * @returns true if the array contains the SID.
+ */
+bool sids_contains_sid(const struct dom_sid *sids,
+ const uint32_t num_sids,
+ const struct dom_sid *sid)
+{
+ uint32_t i;
+
+ for (i = 0; i < num_sids; i++) {
+ if (dom_sid_equal(&sids[i], sid)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Return true if an array of auth_SidAttr contains a certain SID.
+ *
+ * @param [in] sids The auth_SidAttr array.
+ * @param [in] num_sids The size of the auth_SidArray array.
+ * @param [in] sid The SID in question.
+ * @returns true if the array contains the SID.
+ */
+bool sid_attrs_contains_sid(const struct auth_SidAttr *sids,
+ const uint32_t num_sids,
+ const struct dom_sid *sid)
+{
+ uint32_t i;
+
+ for (i = 0; i < num_sids; i++) {
+ if (dom_sid_equal(&sids[i].sid, sid)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Return true if an array of auth_SidAttr contains a certain SID with certain
+ * attributes.
+ *
+ * @param [in] sids The auth_SidAttr array.
+ * @param [in] num_sids The size of the auth_SidArray array.
+ * @param [in] sid The SID in question.
+ * @param [in] attrs The attributes of the SID.
+ * @returns true if the array contains the SID.
+ */
+bool sids_contains_sid_attrs(const struct auth_SidAttr *sids,
+ const uint32_t num_sids,
+ const struct dom_sid *sid,
+ uint32_t attrs)
+{
+ uint32_t i;
+
+ for (i = 0; i < num_sids; i++) {
+ if (attrs != sids[i].attrs) {
+ continue;
+ }
+ if (!dom_sid_equal(&sids[i].sid, sid)) {
+ continue;
+ }
+
+ return true;
+ }
+ return false;
+}
+
+/*
+ * See [MS-LSAT] 3.1.1.1.1 Predefined Translation Database and Corresponding View
+ */
+struct predefined_name_mapping {
+ const char *name;
+ enum lsa_SidType type;
+ struct dom_sid sid;
+};
+
+struct predefined_domain_mapping {
+ const char *domain;
+ struct dom_sid sid;
+ size_t num_names;
+ const struct predefined_name_mapping *names;
+};
+
+/* S-1-${AUTHORITY} */
+#define _SID0(authority) \
+ { 1, 0, {0,0,0,0,0,authority}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}
+/* S-1-${AUTHORITY}-${SUB1} */
+#define _SID1(authority,sub1) \
+ { 1, 1, {0,0,0,0,0,authority}, {sub1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}
+/* S-1-${AUTHORITY}-${SUB1}-${SUB2} */
+#define _SID2(authority,sub1,sub2) \
+ { 1, 2, {0,0,0,0,0,authority}, {sub1,sub2,0,0,0,0,0,0,0,0,0,0,0,0,0}}
+
+/*
+ * S-1-0
+ */
+static const struct predefined_name_mapping predefined_names_S_1_0[] = {
+ {
+ .name = "NULL SID",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(0, 0), /* S-1-0-0 */
+ },
+};
+
+/*
+ * S-1-1
+ */
+static const struct predefined_name_mapping predefined_names_S_1_1[] = {
+ {
+ .name = "Everyone",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(1, 0), /* S-1-1-0 */
+ },
+};
+
+/*
+ * S-1-2
+ */
+static const struct predefined_name_mapping predefined_names_S_1_2[] = {
+ {
+ .name = "LOCAL",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(2, 0), /* S-1-2-0 */
+ },
+};
+
+/*
+ * S-1-3
+ */
+static const struct predefined_name_mapping predefined_names_S_1_3[] = {
+ {
+ .name = "CREATOR OWNER",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(3, 0), /* S-1-3-0 */
+ },
+ {
+ .name = "CREATOR GROUP",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(3, 1), /* S-1-3-1 */
+ },
+ {
+ .name = "CREATOR OWNER SERVER",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(3, 0), /* S-1-3-2 */
+ },
+ {
+ .name = "CREATOR GROUP SERVER",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(3, 1), /* S-1-3-3 */
+ },
+ {
+ .name = "OWNER RIGHTS",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(3, 4), /* S-1-3-4 */
+ },
+};
+
+/*
+ * S-1-5 only 'NT Pseudo Domain'
+ */
+static const struct predefined_name_mapping predefined_names_S_1_5p[] = {
+ {
+ .name = "NT Pseudo Domain",
+ .type = SID_NAME_DOMAIN,
+ .sid = _SID0(5), /* S-1-5 */
+ },
+};
+
+/*
+ * S-1-5 'NT AUTHORITY'
+ */
+static const struct predefined_name_mapping predefined_names_S_1_5a[] = {
+ {
+ .name = "DIALUP",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 1), /* S-1-5-1 */
+ },
+ {
+ .name = "NETWORK",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 2), /* S-1-5-2 */
+ },
+ {
+ .name = "BATCH",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 3), /* S-1-5-3 */
+ },
+ {
+ .name = "INTERACTIVE",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 4), /* S-1-5-4 */
+ },
+ {
+ .name = "SERVICE",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 6), /* S-1-5-6 */
+ },
+ {
+ .name = "ANONYMOUS LOGON",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 7), /* S-1-5-7 */
+ },
+ {
+ .name = "PROXY",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 8), /* S-1-5-8 */
+ },
+ {
+ .name = "ENTERPRISE DOMAIN CONTROLLERS",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 9), /* S-1-5-9 */
+ },
+ {
+ .name = "SELF",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 10), /* S-1-5-10 */
+ },
+ {
+ .name = "Authenticated Users",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 11), /* S-1-5-11 */
+ },
+ {
+ .name = "RESTRICTED",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 12), /* S-1-5-12 */
+ },
+ {
+ .name = "TERMINAL SERVER USER",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 13), /* S-1-5-13 */
+ },
+ {
+ .name = "REMOTE INTERACTIVE LOGON",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 14), /* S-1-5-14 */
+ },
+ {
+ .name = "This Organization",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 15), /* S-1-5-15 */
+ },
+ {
+ .name = "IUSR",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 17), /* S-1-5-17 */
+ },
+ {
+ .name = "SYSTEM",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 18), /* S-1-5-18 */
+ },
+ {
+ .name = "LOCAL SERVICE",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 19), /* S-1-5-19 */
+ },
+ {
+ .name = "NETWORK SERVICE",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 20), /* S-1-5-20 */
+ },
+ {
+ .name = "WRITE RESTRICTED",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 33), /* S-1-5-33 */
+ },
+ {
+ .name = "Other Organization",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 1000), /* S-1-5-1000 */
+ },
+};
+
+/*
+ * S-1-5-32
+ */
+static const struct predefined_name_mapping predefined_names_S_1_5_32[] = {
+ {
+ .name = "BUILTIN",
+ .type = SID_NAME_DOMAIN,
+ .sid = _SID1(5, 32), /* S-1-5-32 */
+ },
+};
+
+/*
+ * S-1-5-64
+ */
+static const struct predefined_name_mapping predefined_names_S_1_5_64[] = {
+ {
+ .name = "NTLM Authentication",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID2(5, 64, 10), /* S-1-5-64-10 */
+ },
+ {
+ .name = "SChannel Authentication",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID2(5, 64, 14), /* S-1-5-64-14 */
+ },
+ {
+ .name = "Digest Authentication",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID2(5, 64, 21), /* S-1-5-64-21 */
+ },
+};
+
+/*
+ * S-1-7
+ */
+static const struct predefined_name_mapping predefined_names_S_1_7[] = {
+ {
+ .name = "Internet$",
+ .type = SID_NAME_DOMAIN,
+ .sid = _SID0(7), /* S-1-7 */
+ },
+};
+
+/*
+ * S-1-16
+ */
+static const struct predefined_name_mapping predefined_names_S_1_16[] = {
+ {
+ .name = "Mandatory Label",
+ .type = SID_NAME_DOMAIN,
+ .sid = _SID0(16), /* S-1-16 */
+ },
+ {
+ .name = "Untrusted Mandatory Level",
+ .type = SID_NAME_LABEL,
+ .sid = _SID1(16, 0), /* S-1-16-0 */
+ },
+ {
+ .name = "Low Mandatory Level",
+ .type = SID_NAME_LABEL,
+ .sid = _SID1(16, 4096), /* S-1-16-4096 */
+ },
+ {
+ .name = "Medium Mandatory Level",
+ .type = SID_NAME_LABEL,
+ .sid = _SID1(16, 8192), /* S-1-16-8192 */
+ },
+ {
+ .name = "High Mandatory Level",
+ .type = SID_NAME_LABEL,
+ .sid = _SID1(16, 12288), /* S-1-16-12288 */
+ },
+ {
+ .name = "System Mandatory Level",
+ .type = SID_NAME_LABEL,
+ .sid = _SID1(16, 16384), /* S-1-16-16384 */
+ },
+ {
+ .name = "Protected Process Mandatory Level",
+ .type = SID_NAME_LABEL,
+ .sid = _SID1(16, 20480), /* S-1-16-20480 */
+ },
+};
+
+static const struct predefined_domain_mapping predefined_domains[] = {
+ {
+ .domain = "",
+ .sid = _SID0(0), /* S-1-0 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_0),
+ .names = predefined_names_S_1_0,
+ },
+ {
+ .domain = "",
+ .sid = _SID0(1), /* S-1-1 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_1),
+ .names = predefined_names_S_1_1,
+ },
+ {
+ .domain = "",
+ .sid = _SID0(2), /* S-1-2 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_2),
+ .names = predefined_names_S_1_2,
+ },
+ {
+ .domain = "",
+ .sid = _SID0(3), /* S-1-3 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_3),
+ .names = predefined_names_S_1_3,
+ },
+ {
+ .domain = "",
+ .sid = _SID0(3), /* S-1-3 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_3),
+ .names = predefined_names_S_1_3,
+ },
+ /*
+ * S-1-5 is split here
+ *
+ * 'NT Pseudo Domain' has precedence before 'NT AUTHORITY'.
+ *
+ * In a LookupSids with multiple sids e.g. S-1-5 and S-1-5-7
+ * the domain section (struct lsa_DomainInfo) gets
+ * 'NT Pseudo Domain' with S-1-5. If asked in reversed order
+ * S-1-5-7 and then S-1-5, you get struct lsa_DomainInfo
+ * with 'NT AUTHORITY' and S-1-5.
+ */
+ {
+ .domain = "NT Pseudo Domain",
+ .sid = _SID0(5), /* S-1-5 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_5p),
+ .names = predefined_names_S_1_5p,
+ },
+ {
+ .domain = "NT AUTHORITY",
+ .sid = _SID0(5), /* S-1-5 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_5a),
+ .names = predefined_names_S_1_5a,
+ },
+ {
+ .domain = "BUILTIN",
+ .sid = _SID1(5, 32), /* S-1-5-32 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_5_32),
+ .names = predefined_names_S_1_5_32,
+ },
+ /*
+ * 'NT AUTHORITY' again with S-1-5-64 this time
+ */
+ {
+ .domain = "NT AUTHORITY",
+ .sid = _SID1(5, 64), /* S-1-5-64 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_5_64),
+ .names = predefined_names_S_1_5_64,
+ },
+ {
+ .domain = "Internet$",
+ .sid = _SID0(7), /* S-1-7 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_7),
+ .names = predefined_names_S_1_7,
+ },
+ {
+ .domain = "Mandatory Label",
+ .sid = _SID0(16), /* S-1-16 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_16),
+ .names = predefined_names_S_1_16,
+ },
+};
+
+NTSTATUS dom_sid_lookup_predefined_name(const char *name,
+ const struct dom_sid **sid,
+ enum lsa_SidType *type,
+ const struct dom_sid **authority_sid,
+ const char **authority_name)
+{
+ size_t di;
+ const char *domain = "";
+ size_t domain_len = 0;
+ const char *p;
+ bool match;
+
+ *sid = NULL;
+ *type = SID_NAME_UNKNOWN;
+ *authority_sid = NULL;
+ *authority_name = NULL;
+
+ if (name == NULL) {
+ name = "";
+ }
+
+ p = strchr(name, '\\');
+ if (p != NULL) {
+ domain = name;
+ domain_len = PTR_DIFF(p, domain);
+ name = p + 1;
+ }
+
+ match = strequal(name, "");
+ if (match) {
+ /*
+ * Strange, but that's what W2012R2 does.
+ */
+ name = "BUILTIN";
+ }
+
+ for (di = 0; di < ARRAY_SIZE(predefined_domains); di++) {
+ const struct predefined_domain_mapping *d =
+ &predefined_domains[di];
+ size_t ni;
+
+ if (domain_len != 0) {
+ int cmp;
+
+ cmp = strncasecmp(d->domain, domain, domain_len);
+ if (cmp != 0) {
+ continue;
+ }
+ }
+
+ for (ni = 0; ni < d->num_names; ni++) {
+ const struct predefined_name_mapping *n =
+ &d->names[ni];
+
+ match = strequal(n->name, name);
+ if (!match) {
+ continue;
+ }
+
+ *sid = &n->sid;
+ *type = n->type;
+ *authority_sid = &d->sid;
+ *authority_name = d->domain;
+ return NT_STATUS_OK;
+ }
+ }
+
+ return NT_STATUS_NONE_MAPPED;
+}
+
+bool dom_sid_lookup_is_predefined_domain(const char *domain)
+{
+ size_t di;
+ bool match;
+
+ if (domain == NULL) {
+ domain = "";
+ }
+
+ match = strequal(domain, "");
+ if (match) {
+ /*
+ * Strange, but that's what W2012R2 does.
+ */
+ domain = "BUILTIN";
+ }
+
+ for (di = 0; di < ARRAY_SIZE(predefined_domains); di++) {
+ const struct predefined_domain_mapping *d =
+ &predefined_domains[di];
+ int cmp;
+
+ cmp = strcasecmp(d->domain, domain);
+ if (cmp != 0) {
+ continue;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+NTSTATUS dom_sid_lookup_predefined_sid(const struct dom_sid *sid,
+ const char **name,
+ enum lsa_SidType *type,
+ const struct dom_sid **authority_sid,
+ const char **authority_name)
+{
+ size_t di;
+ bool match_domain = false;
+
+ *name = NULL;
+ *type = SID_NAME_UNKNOWN;
+ *authority_sid = NULL;
+ *authority_name = NULL;
+
+ if (sid == NULL) {
+ return NT_STATUS_INVALID_SID;
+ }
+
+ for (di = 0; di < ARRAY_SIZE(predefined_domains); di++) {
+ const struct predefined_domain_mapping *d =
+ &predefined_domains[di];
+ size_t ni;
+ int cmp;
+
+ cmp = dom_sid_compare_auth(&d->sid, sid);
+ if (cmp != 0) {
+ continue;
+ }
+
+ match_domain = true;
+
+ for (ni = 0; ni < d->num_names; ni++) {
+ const struct predefined_name_mapping *n =
+ &d->names[ni];
+
+ cmp = dom_sid_compare(&n->sid, sid);
+ if (cmp != 0) {
+ continue;
+ }
+
+ *name = n->name;
+ *type = n->type;
+ *authority_sid = &d->sid;
+ *authority_name = d->domain;
+ return NT_STATUS_OK;
+ }
+ }
+
+ if (!match_domain) {
+ return NT_STATUS_INVALID_SID;
+ }
+
+ return NT_STATUS_NONE_MAPPED;
+}
diff --git a/libcli/security/wscript_build b/libcli/security/wscript_build
new file mode 100644
index 0000000..db8a9b9
--- /dev/null
+++ b/libcli/security/wscript_build
@@ -0,0 +1,64 @@
+#!/usr/bin/env python
+
+
+bld.SAMBA_LIBRARY('samba-security',
+ source=['dom_sid.c',
+ 'display_sec.c', 'secace.c', 'secacl.c',
+ 'security_descriptor.c', 'sddl.c', 'privileges.c',
+ 'security_token.c', 'access_check.c',
+ 'object_tree.c', 'create_descriptor.c',
+ 'util_sid.c', 'session.c', 'secdesc.c',
+ 'conditional_ace.c', 'sddl_conditional_ace.c',
+ 'claims-conversions.c'],
+ private_library=True,
+ deps='stable_sort talloc ndr NDR_SECURITY NDR_CONDITIONAL_ACE')
+
+pytalloc_util = bld.pyembed_libname('pytalloc-util')
+bld.SAMBA_PYTHON('pysecurity',
+ source='pysecurity.c',
+ deps='samba-security %s' % pytalloc_util,
+ realname='samba/security.so'
+ )
+
+bld.SAMBA_BINARY(
+ 'test_sddl_conditional_ace',
+ source='tests/test_sddl_conditional_ace.c',
+ deps='''
+ cmocka
+ talloc
+ samba-util
+ asn1util
+ NDR_SECURITY
+ samba-security
+ ''',
+ for_selftest=True
+)
+
+bld.SAMBA_BINARY(
+ 'test_run_conditional_ace',
+ source='tests/test_run_conditional_ace.c',
+ deps='''
+ cmocka
+ talloc
+ samba-util
+ asn1util
+ NDR_SECURITY
+ samba-security
+ ''',
+ for_selftest=True
+)
+
+bld.SAMBA_BINARY(
+ 'test_claim_conversion',
+ source='tests/test_claim_conversion.c',
+ deps='''
+ cmocka
+ talloc
+ samba-util
+ asn1util
+ NDR_SECURITY
+ NDR_CLAIMS
+ samba-security
+ ''',
+ for_selftest=True
+)
diff --git a/libcli/smb/py_reparse_symlink.c b/libcli/smb/py_reparse_symlink.c
new file mode 100644
index 0000000..5626e27
--- /dev/null
+++ b/libcli/smb/py_reparse_symlink.c
@@ -0,0 +1,198 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Volker Lendecke 2022
+ *
+ * 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 "lib/replace/system/python.h"
+#include "replace.h"
+#include "python/modules.h"
+#include "python/py3compat.h"
+#include "libcli/util/pyerrors.h"
+#include "reparse.h"
+#include "lib/util/iov_buf.h"
+#include "smb_constants.h"
+
+static PyObject *py_reparse_put(PyObject *module, PyObject *args)
+{
+ char *reparse = NULL;
+ Py_ssize_t reparse_len;
+ unsigned long long tag = 0;
+ unsigned reserved = 0;
+ uint8_t *buf = NULL;
+ ssize_t buflen;
+ PyObject *result = NULL;
+ struct reparse_data_buffer reparse_buf = {};
+ bool ok;
+
+ ok = PyArg_ParseTuple(
+ args,
+ "Kk"PYARG_BYTES_LEN":put",
+ &tag,
+ &reserved,
+ &reparse,
+ &reparse_len);
+ if (!ok) {
+ return NULL;
+ }
+
+ reparse_buf.tag = tag;
+ reparse_buf.parsed.raw.data = (uint8_t *)reparse;
+ reparse_buf.parsed.raw.length = reparse_len;
+ reparse_buf.parsed.raw.reserved = reserved;
+
+ buflen = reparse_data_buffer_marshall(&reparse_buf, NULL, 0);
+ if (buflen == -1) {
+ errno = EINVAL;
+ PyErr_SetFromErrno(PyExc_RuntimeError);
+ return NULL;
+ }
+ buf = talloc_array(NULL, uint8_t, buflen);
+ if (buf == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ reparse_data_buffer_marshall(&reparse_buf, buf, buflen);
+
+ result = PyBytes_FromStringAndSize((char *)buf, buflen);
+ TALLOC_FREE(buf);
+ return result;
+}
+
+static PyObject *py_reparse_symlink_put(PyObject *module, PyObject *args)
+{
+ int unparsed = 0;
+ int flags = 0;
+ struct reparse_data_buffer reparse = {
+ .tag = IO_REPARSE_TAG_SYMLINK,
+ };
+ struct symlink_reparse_struct *lnk = &reparse.parsed.lnk;
+ uint8_t stackbuf[1024];
+ uint8_t *buf = stackbuf;
+ ssize_t buflen = sizeof(stackbuf);
+ PyObject *result = NULL;
+ bool ok;
+
+ ok = PyArg_ParseTuple(args,
+ "ssii:symlink_put",
+ &lnk->substitute_name,
+ &lnk->print_name,
+ &unparsed,
+ &flags);
+ if (!ok) {
+ return NULL;
+ }
+ lnk->unparsed_path_length = unparsed;
+ lnk->flags = flags;
+
+ buflen = reparse_data_buffer_marshall(&reparse, buf, buflen);
+
+ if ((buflen > 0) && ((size_t)buflen > sizeof(stackbuf))) {
+ buf = malloc(buflen);
+ buflen = reparse_data_buffer_marshall(&reparse, buf, buflen);
+ }
+
+ if (buflen == -1) {
+ PyErr_NoMemory();
+ } else {
+ result = PyBytes_FromStringAndSize((char *)buf, buflen);
+ }
+
+ if (buf != stackbuf) {
+ free(buf);
+ }
+
+ return result;
+}
+
+static PyObject *py_reparse_symlink_get(PyObject *module, PyObject *args)
+{
+ char *buf = NULL;
+ Py_ssize_t buflen;
+ struct reparse_data_buffer *syml = NULL;
+ struct symlink_reparse_struct *lnk = NULL;
+ PyObject *result = NULL;
+ NTSTATUS status;
+ bool ok;
+
+ ok = PyArg_ParseTuple(args, PYARG_BYTES_LEN ":get", &buf, &buflen);
+ if (!ok) {
+ return NULL;
+ }
+
+ syml = talloc(NULL, struct reparse_data_buffer);
+ if (syml == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ status = reparse_data_buffer_parse(syml, syml, (uint8_t *)buf, buflen);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(syml);
+ PyErr_SetNTSTATUS(status);
+ return NULL;
+ }
+
+ if (syml->tag != IO_REPARSE_TAG_SYMLINK) {
+ TALLOC_FREE(syml);
+ PyErr_SetNTSTATUS(NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return NULL;
+ }
+ lnk = &syml->parsed.lnk;
+
+ result = Py_BuildValue("ssII",
+ lnk->substitute_name,
+ lnk->print_name,
+ (unsigned)lnk->unparsed_path_length,
+ (unsigned)lnk->flags);
+
+ TALLOC_FREE(syml);
+ return result;
+}
+
+static PyMethodDef py_reparse_symlink_methods[] = {
+ { "put",
+ PY_DISCARD_FUNC_SIG(PyCFunction, py_reparse_put),
+ METH_VARARGS,
+ "Create a reparse point blob"},
+ { "symlink_put",
+ PY_DISCARD_FUNC_SIG(PyCFunction, py_reparse_symlink_put),
+ METH_VARARGS,
+ "Create a reparse symlink blob"},
+ { "symlink_get",
+ PY_DISCARD_FUNC_SIG(PyCFunction, py_reparse_symlink_get),
+ METH_VARARGS,
+ "Parse a reparse symlink blob"},
+ {0},
+};
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "reparse_symlink",
+ .m_doc = "[un]marshall reparse symlink blobs",
+ .m_size = -1,
+ .m_methods = py_reparse_symlink_methods,
+};
+
+MODULE_INIT_FUNC(reparse_symlink)
+{
+ PyObject *m;
+
+ m = PyModule_Create(&moduledef);
+ if (m == NULL)
+ return NULL;
+
+ return m;
+}
diff --git a/libcli/smb/read_smb.c b/libcli/smb/read_smb.c
new file mode 100644
index 0000000..a40f702
--- /dev/null
+++ b/libcli/smb/read_smb.c
@@ -0,0 +1,114 @@
+/*
+ Unix SMB/CIFS implementation.
+ Infrastructure for async SMB client requests
+ Copyright (C) Volker Lendecke 2008
+
+ 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 "system/network.h"
+#include "lib/async_req/async_sock.h"
+#include "read_smb.h"
+#include "lib/util/tevent_unix.h"
+#include "libcli/smb/smb_constants.h"
+
+/*
+ * Read an smb packet asynchronously, discard keepalives
+ */
+
+struct read_smb_state {
+ struct tevent_context *ev;
+ int fd;
+ uint8_t *buf;
+};
+
+static ssize_t read_smb_more(uint8_t *buf, size_t buflen, void *private_data);
+static void read_smb_done(struct tevent_req *subreq);
+
+struct tevent_req *read_smb_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ int fd)
+{
+ struct tevent_req *result, *subreq;
+ struct read_smb_state *state;
+
+ result = tevent_req_create(mem_ctx, &state, struct read_smb_state);
+ if (result == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->fd = fd;
+
+ subreq = read_packet_send(state, ev, fd, 4, read_smb_more, NULL);
+ if (subreq == NULL) {
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, read_smb_done, result);
+ return result;
+ fail:
+ TALLOC_FREE(result);
+ return NULL;
+}
+
+static ssize_t read_smb_more(uint8_t *buf, size_t buflen, void *private_data)
+{
+ if (buflen > 4) {
+ return 0; /* We've been here, we're done */
+ }
+ return smb_len_tcp(buf);
+}
+
+static void read_smb_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct read_smb_state *state = tevent_req_data(
+ req, struct read_smb_state);
+ ssize_t len;
+ int err;
+
+ len = read_packet_recv(subreq, state, &state->buf, &err);
+ TALLOC_FREE(subreq);
+ if (len == -1) {
+ tevent_req_error(req, err);
+ return;
+ }
+
+ if (CVAL(state->buf, 0) == NBSSkeepalive) {
+ subreq = read_packet_send(state, state->ev, state->fd, 4,
+ read_smb_more, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, read_smb_done, req);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+ssize_t read_smb_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ uint8_t **pbuf, int *perrno)
+{
+ struct read_smb_state *state = tevent_req_data(
+ req, struct read_smb_state);
+
+ if (tevent_req_is_unix_error(req, perrno)) {
+ tevent_req_received(req);
+ return -1;
+ }
+ *pbuf = talloc_move(mem_ctx, &state->buf);
+ tevent_req_received(req);
+ return talloc_get_size(*pbuf);
+}
diff --git a/libcli/smb/read_smb.h b/libcli/smb/read_smb.h
new file mode 100644
index 0000000..1df2dc2
--- /dev/null
+++ b/libcli/smb/read_smb.h
@@ -0,0 +1,33 @@
+/*
+ Unix SMB/CIFS implementation.
+ Infrastructure for async SMB client requests
+ Copyright (C) Volker Lendecke 2008
+
+ 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/>.
+*/
+
+#ifndef __LIBSMB_READ_SMB_H
+#define __LIBSMB_READ_SMB_H
+
+struct tevent_context;
+struct tevent_req;
+
+struct tevent_req *read_smb_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ int fd);
+
+ssize_t read_smb_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ uint8_t **pbuf, int *perrno);
+
+#endif
diff --git a/libcli/smb/reparse.c b/libcli/smb/reparse.c
new file mode 100644
index 0000000..49ecc77
--- /dev/null
+++ b/libcli/smb/reparse.c
@@ -0,0 +1,567 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * 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 "replace.h"
+#include "libcli/smb/reparse.h"
+#include "lib/util/iov_buf.h"
+#include "libcli/smb/smb_constants.h"
+#include "libcli/util/error.h"
+#include "lib/util/debug.h"
+#include "lib/util/bytearray.h"
+#include "lib/util/talloc_stack.h"
+#include "lib/util/charset/charset.h"
+#include "smb_util.h"
+
+static NTSTATUS reparse_buffer_check(const uint8_t *in_data,
+ size_t in_len,
+ uint32_t *reparse_tag,
+ const uint8_t **_reparse_data,
+ size_t *_reparse_data_length)
+{
+ uint16_t reparse_data_length;
+
+ if (in_len == 0) {
+ DBG_DEBUG("in_len=0\n");
+ return NT_STATUS_INVALID_BUFFER_SIZE;
+ }
+ if (in_len < 8) {
+ DBG_DEBUG("in_len=%zu\n", in_len);
+ return NT_STATUS_IO_REPARSE_DATA_INVALID;
+ }
+
+ reparse_data_length = PULL_LE_U16(in_data, 4);
+
+ if (reparse_data_length > (in_len - 8)) {
+ DBG_DEBUG("in_len=%zu, reparse_data_length=%" PRIu16 "\n",
+ in_len,
+ reparse_data_length);
+ return NT_STATUS_IO_REPARSE_DATA_INVALID;
+ }
+
+ *reparse_tag = PULL_LE_U32(in_data, 0);
+ *_reparse_data = in_data + 8;
+ *_reparse_data_length = reparse_data_length;
+
+ return NT_STATUS_OK;
+}
+
+static int nfs_reparse_buffer_parse(TALLOC_CTX *mem_ctx,
+ struct nfs_reparse_data_buffer *dst,
+ const uint8_t *src,
+ size_t srclen)
+{
+ uint64_t type;
+
+ if (srclen < 8) {
+ DBG_DEBUG("srclen=%zu too short\n", srclen);
+ return EINVAL;
+ }
+
+ type = PULL_LE_U64(src, 0);
+
+ switch (type) {
+ case NFS_SPECFILE_CHR:
+ FALL_THROUGH;
+ case NFS_SPECFILE_BLK:
+ if (srclen < 16) {
+ DBG_DEBUG("srclen %zu too short for type %" PRIx64 "\n",
+ srclen,
+ type);
+ return EINVAL;
+ }
+ dst->data.dev.major = PULL_LE_U32(src, 8);
+ dst->data.dev.minor = PULL_LE_U32(src, 12);
+ break;
+ case NFS_SPECFILE_LNK: {
+ bool ok;
+
+ ok = convert_string_talloc(mem_ctx,
+ CH_UTF16,
+ CH_UNIX,
+ src + 8,
+ srclen - 8,
+ &dst->data.lnk_target,
+ NULL);
+ if (!ok) {
+ return errno;
+ }
+ break;
+ }
+ case NFS_SPECFILE_FIFO:
+ break; /* empty, no data */
+ case NFS_SPECFILE_SOCK:
+ break; /* empty, no data */
+ default:
+ DBG_DEBUG("Unknown NFS reparse type %" PRIx64 "\n", type);
+ return EINVAL;
+ }
+
+ dst->type = type;
+
+ return 0;
+}
+
+static int symlink_reparse_buffer_parse(TALLOC_CTX *mem_ctx,
+ struct symlink_reparse_struct *dst,
+ const uint8_t *src,
+ size_t srclen)
+{
+ uint16_t reparse_data_length;
+ uint16_t substitute_name_offset, substitute_name_length;
+ uint16_t print_name_offset, print_name_length;
+ bool ok;
+
+ if (srclen < 20) {
+ DBG_DEBUG("srclen = %zu, expected >= 20\n", srclen);
+ return EINVAL;
+ }
+ if (PULL_LE_U32(src, 0) != IO_REPARSE_TAG_SYMLINK) {
+ DBG_DEBUG("Got ReparseTag %8.8x, expected %8.8x\n",
+ PULL_LE_U32(src, 0),
+ IO_REPARSE_TAG_SYMLINK);
+ return EINVAL;
+ }
+
+ reparse_data_length = PULL_LE_U16(src, 4);
+ substitute_name_offset = PULL_LE_U16(src, 8);
+ substitute_name_length = PULL_LE_U16(src, 10);
+ print_name_offset = PULL_LE_U16(src, 12);
+ print_name_length = PULL_LE_U16(src, 14);
+
+ if (reparse_data_length < 12) {
+ DBG_DEBUG("reparse_data_length = %"PRIu16", expected >= 12\n",
+ reparse_data_length);
+ return EINVAL;
+ }
+ if (smb_buffer_oob(srclen - 8, reparse_data_length, 0)) {
+ DBG_DEBUG("reparse_data_length (%"PRIu16") too large for "
+ "src_len (%zu)\n",
+ reparse_data_length,
+ srclen);
+ return EINVAL;
+ }
+ if (smb_buffer_oob(reparse_data_length - 12, substitute_name_offset,
+ substitute_name_length)) {
+ DBG_DEBUG("substitute_name (%"PRIu16"/%"PRIu16") does not fit "
+ "in reparse_data_length (%"PRIu16")\n",
+ substitute_name_offset,
+ substitute_name_length,
+ reparse_data_length - 12);
+ return EINVAL;
+ }
+ if (smb_buffer_oob(reparse_data_length - 12, print_name_offset,
+ print_name_length)) {
+ DBG_DEBUG("print_name (%"PRIu16"/%"PRIu16") does not fit in "
+ "reparse_data_length (%"PRIu16")\n",
+ print_name_offset,
+ print_name_length,
+ reparse_data_length - 12);
+ return EINVAL;
+ }
+
+ *dst = (struct symlink_reparse_struct) {
+ .unparsed_path_length = PULL_LE_U16(src, 6),
+ .flags = PULL_LE_U32(src, 16),
+ };
+
+ ok = convert_string_talloc(mem_ctx,
+ CH_UTF16,
+ CH_UNIX,
+ src + 20 + substitute_name_offset,
+ substitute_name_length,
+ &dst->substitute_name,
+ NULL);
+ if (!ok) {
+ int ret = errno;
+ DBG_DEBUG("convert_string_talloc for substitute_name "
+ "failed\n");
+ return ret;
+ }
+
+ ok = convert_string_talloc(mem_ctx,
+ CH_UTF16,
+ CH_UNIX,
+ src + 20 + print_name_offset,
+ print_name_length,
+ &dst->print_name,
+ NULL);
+ if (!ok) {
+ int ret = errno;
+ DBG_DEBUG("convert_string_talloc for print_name failed\n");
+ TALLOC_FREE(dst->substitute_name);
+ return ret;
+ }
+
+ return 0;
+}
+
+NTSTATUS reparse_data_buffer_parse(TALLOC_CTX *mem_ctx,
+ struct reparse_data_buffer *dst,
+ const uint8_t *buf,
+ size_t buflen)
+{
+ const uint8_t *reparse_data;
+ size_t reparse_data_length;
+ NTSTATUS status;
+ int ret;
+
+ status = reparse_buffer_check(buf,
+ buflen,
+ &dst->tag,
+ &reparse_data,
+ &reparse_data_length);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ switch (dst->tag) {
+ case IO_REPARSE_TAG_SYMLINK:
+ ret = symlink_reparse_buffer_parse(mem_ctx,
+ &dst->parsed.lnk,
+ buf,
+ buflen);
+ if (ret != 0) {
+ return map_nt_error_from_unix_common(ret);
+ }
+ break;
+ case IO_REPARSE_TAG_NFS:
+ ret = nfs_reparse_buffer_parse(mem_ctx,
+ &dst->parsed.nfs,
+ reparse_data,
+ reparse_data_length);
+ if (ret != 0) {
+ return map_nt_error_from_unix_common(ret);
+ }
+ break;
+ default:
+ dst->parsed.raw.data = talloc_memdup(mem_ctx,
+ reparse_data,
+ reparse_data_length);
+ if (dst->parsed.raw.data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ dst->parsed.raw.length = reparse_data_length;
+ dst->parsed.raw.reserved = PULL_LE_U16(buf, 6);
+ break;
+ }
+
+ return NT_STATUS_OK;
+}
+
+char *reparse_data_buffer_str(TALLOC_CTX *mem_ctx,
+ const struct reparse_data_buffer *dst)
+{
+ char *s = talloc_strdup(mem_ctx, "");
+
+ switch (dst->tag) {
+ case IO_REPARSE_TAG_SYMLINK: {
+ const struct symlink_reparse_struct *lnk = &dst->parsed.lnk;
+ talloc_asprintf_addbuf(&s,
+ "0x%" PRIx32
+ " (IO_REPARSE_TAG_SYMLINK)\n",
+ dst->tag);
+ talloc_asprintf_addbuf(&s,
+ "unparsed=%" PRIu16 "\n",
+ lnk->unparsed_path_length);
+ talloc_asprintf_addbuf(&s,
+ "substitute_name=%s\n",
+ lnk->substitute_name);
+ talloc_asprintf_addbuf(&s, "print_name=%s\n", lnk->print_name);
+ talloc_asprintf_addbuf(&s, "flags=%" PRIu32 "\n", lnk->flags);
+ break;
+ }
+ case IO_REPARSE_TAG_NFS: {
+ const struct nfs_reparse_data_buffer *nfs = &dst->parsed.nfs;
+
+ talloc_asprintf_addbuf(&s,
+ "0x%" PRIx32 " (IO_REPARSE_TAG_NFS)\n",
+ dst->tag);
+
+ switch (nfs->type) {
+ case NFS_SPECFILE_FIFO:
+ talloc_asprintf_addbuf(&s,
+ " 0x%" PRIx64
+ " (NFS_SPECFILE_FIFO)\n",
+ nfs->type);
+ break;
+ case NFS_SPECFILE_SOCK:
+ talloc_asprintf_addbuf(&s,
+ " 0x%" PRIx64
+ " (NFS_SPECFILE_SOCK)\n",
+ nfs->type);
+ break;
+ case NFS_SPECFILE_LNK:
+ talloc_asprintf_addbuf(&s,
+ " 0x%" PRIx64
+ " (NFS_SPECFILE_LNK)\n",
+ nfs->type);
+ talloc_asprintf_addbuf(&s,
+ " -> %s\n ",
+ nfs->data.lnk_target);
+ break;
+ case NFS_SPECFILE_BLK:
+ talloc_asprintf_addbuf(&s,
+ " 0x%" PRIx64
+ " (NFS_SPECFILE_BLK)\n",
+ nfs->type);
+ talloc_asprintf_addbuf(&s,
+ " %" PRIu32 "/%" PRIu32 "\n",
+ nfs->data.dev.major,
+ nfs->data.dev.minor);
+ break;
+ case NFS_SPECFILE_CHR:
+ talloc_asprintf_addbuf(&s,
+ " 0x%" PRIx64
+ " (NFS_SPECFILE_CHR)\n",
+ nfs->type);
+ talloc_asprintf_addbuf(&s,
+ " %" PRIu32 "/%" PRIu32 "\n",
+ nfs->data.dev.major,
+ nfs->data.dev.minor);
+ break;
+ default:
+ talloc_asprintf_addbuf(&s,
+ " 0x%" PRIu64
+ " (Unknown type)\n",
+ nfs->type);
+ break;
+ }
+ break;
+ }
+ default:
+ talloc_asprintf_addbuf(&s, "%" PRIu32 "\n", dst->tag);
+ break;
+ }
+ return s;
+}
+
+static ssize_t reparse_buffer_marshall(uint32_t reparse_tag,
+ uint16_t reserved,
+ const struct iovec *iov,
+ int iovlen,
+ uint8_t *buf,
+ size_t buflen)
+{
+ ssize_t reparse_data_length = iov_buflen(iov, iovlen);
+ size_t needed;
+
+ if (reparse_data_length == -1) {
+ return -1;
+ }
+ if (reparse_data_length > UINT16_MAX) {
+ return -1;
+ }
+
+ needed = reparse_data_length + 8;
+ if (needed < reparse_data_length) {
+ return -1;
+ }
+
+ if (buflen >= needed) {
+ PUSH_LE_U32(buf, 0, reparse_tag);
+ PUSH_LE_U16(buf, 4, reparse_data_length);
+ PUSH_LE_U16(buf, 6, reserved);
+ iov_buf(iov, iovlen, buf + 8, buflen - 8);
+ }
+
+ return needed;
+}
+
+static ssize_t
+reparse_data_buffer_marshall_syml(const struct symlink_reparse_struct *src,
+ uint8_t *buf,
+ size_t buflen)
+{
+ uint8_t sbuf[12];
+ struct iovec iov[3];
+ const char *print_name = src->print_name;
+ uint8_t *subst_utf16 = NULL;
+ uint8_t *print_utf16 = NULL;
+ size_t subst_len = 0;
+ size_t print_len = 0;
+ ssize_t ret = -1;
+ bool ok;
+
+ if (src->substitute_name == NULL) {
+ return -1;
+ }
+ if (src->print_name == NULL) {
+ print_name = src->substitute_name;
+ }
+
+ iov[0] = (struct iovec){
+ .iov_base = sbuf,
+ .iov_len = sizeof(sbuf),
+ };
+
+ ok = convert_string_talloc(talloc_tos(),
+ CH_UNIX,
+ CH_UTF16,
+ src->substitute_name,
+ strlen(src->substitute_name),
+ &subst_utf16,
+ &subst_len);
+ if (!ok) {
+ goto fail;
+ }
+ if (subst_len > UINT16_MAX) {
+ goto fail;
+ }
+ iov[1] = (struct iovec){
+ .iov_base = subst_utf16,
+ .iov_len = subst_len,
+ };
+
+ ok = convert_string_talloc(talloc_tos(),
+ CH_UNIX,
+ CH_UTF16,
+ print_name,
+ strlen(print_name),
+ &print_utf16,
+ &print_len);
+ if (!ok) {
+ goto fail;
+ }
+ if (print_len > UINT16_MAX) {
+ goto fail;
+ }
+ iov[2] = (struct iovec){
+ .iov_base = print_utf16,
+ .iov_len = print_len,
+ };
+
+ PUSH_LE_U16(sbuf, 0, 0); /* SubstituteNameOffset */
+ PUSH_LE_U16(sbuf, 2, subst_len); /* SubstituteNameLength */
+ PUSH_LE_U16(sbuf, 4, subst_len); /* PrintNameOffset */
+ PUSH_LE_U16(sbuf, 6, print_len); /* PrintNameLength */
+ PUSH_LE_U32(sbuf, 8, src->flags); /* Flags */
+
+ ret = reparse_buffer_marshall(IO_REPARSE_TAG_SYMLINK,
+ src->unparsed_path_length,
+ iov,
+ ARRAY_SIZE(iov),
+ buf,
+ buflen);
+
+fail:
+ TALLOC_FREE(subst_utf16);
+ TALLOC_FREE(print_utf16);
+ return ret;
+}
+
+static ssize_t
+reparse_data_buffer_marshall_nfs(const struct nfs_reparse_data_buffer *src,
+ uint8_t *buf,
+ size_t buflen)
+{
+ uint8_t typebuf[8];
+ uint8_t devbuf[8];
+ struct iovec iov[2] = {};
+ size_t iovlen;
+ uint8_t *lnk_utf16 = NULL;
+ size_t lnk_len = 0;
+ ssize_t ret;
+
+ PUSH_LE_U64(typebuf, 0, src->type);
+ iov[0] = (struct iovec){
+ .iov_base = typebuf,
+ .iov_len = sizeof(typebuf),
+ };
+ iovlen = 1;
+
+ switch (src->type) {
+ case NFS_SPECFILE_LNK: {
+ bool ok = convert_string_talloc(talloc_tos(),
+ CH_UNIX,
+ CH_UTF16,
+ src->data.lnk_target,
+ strlen(src->data.lnk_target),
+ &lnk_utf16,
+ &lnk_len);
+ if (!ok) {
+ return -1;
+ }
+ iov[1] = (struct iovec){
+ .iov_base = lnk_utf16,
+ .iov_len = lnk_len,
+ };
+ iovlen = 2;
+ break;
+ }
+ case NFS_SPECFILE_CHR:
+ FALL_THROUGH;
+ case NFS_SPECFILE_BLK:
+ PUSH_LE_U32(devbuf, 0, src->data.dev.major);
+ PUSH_LE_U32(devbuf, 4, src->data.dev.minor);
+ iov[1] = (struct iovec){
+ .iov_base = devbuf,
+ .iov_len = sizeof(devbuf),
+ };
+ iovlen = 2;
+ break;
+ default:
+ break;
+ /* Nothing to do for NFS_SPECFILE_FIFO and _SOCK */
+ }
+
+ ret = reparse_buffer_marshall(IO_REPARSE_TAG_NFS,
+ 0,
+ iov,
+ iovlen,
+ buf,
+ buflen);
+ TALLOC_FREE(lnk_utf16);
+ return ret;
+}
+
+ssize_t reparse_data_buffer_marshall(const struct reparse_data_buffer *src,
+ uint8_t *buf,
+ size_t buflen)
+{
+ ssize_t ret = -1;
+
+ switch (src->tag) {
+ case IO_REPARSE_TAG_SYMLINK:
+
+ ret = reparse_data_buffer_marshall_syml(&src->parsed.lnk,
+ buf,
+ buflen);
+ break;
+
+ case IO_REPARSE_TAG_NFS:
+
+ ret = reparse_data_buffer_marshall_nfs(&src->parsed.nfs,
+ buf,
+ buflen);
+ break;
+
+ default: {
+ struct iovec iov = {
+ .iov_base = src->parsed.raw.data,
+ .iov_len = src->parsed.raw.length,
+ };
+ ret = reparse_buffer_marshall(src->tag,
+ src->parsed.raw.reserved,
+ &iov,
+ 1,
+ buf,
+ buflen);
+ }
+ }
+
+ return ret;
+}
diff --git a/libcli/smb/reparse.h b/libcli/smb/reparse.h
new file mode 100644
index 0000000..23274bf
--- /dev/null
+++ b/libcli/smb/reparse.h
@@ -0,0 +1,77 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * 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/>.
+ */
+
+#ifndef __LIBCLI_SMB_REPARSE_H__
+#define __LIBCLI_SMB_REPARSE_H__
+
+#include <talloc.h>
+#include "replace.h"
+#include "libcli/util/ntstatus.h"
+
+struct symlink_reparse_struct {
+ uint16_t unparsed_path_length; /* reserved for the reparse point */
+ char *substitute_name;
+ char *print_name;
+ uint32_t flags;
+};
+
+struct nfs_reparse_data_buffer {
+ uint64_t type;
+
+ union {
+ char *lnk_target; /* NFS_SPECFILE_LNK */
+ struct {
+ uint32_t major;
+ uint32_t minor;
+ } dev; /* NFS_SPECFILE_[CHR|BLK] */
+
+ /* NFS_SPECFILE_[FIFO|SOCK] have no data */
+ } data;
+};
+
+struct reparse_data_buffer {
+ uint32_t tag;
+
+ union {
+ /* IO_REPARSE_TAG_NFS */
+ struct nfs_reparse_data_buffer nfs;
+
+ /* IO_REPARSE_TAG_SYMLINK */
+ struct symlink_reparse_struct lnk;
+
+ /* Unknown reparse tag */
+ struct {
+ uint16_t length;
+ uint16_t reserved;
+ uint8_t *data;
+ } raw;
+
+ } parsed;
+};
+
+NTSTATUS reparse_data_buffer_parse(TALLOC_CTX *mem_ctx,
+ struct reparse_data_buffer *dst,
+ const uint8_t *buf,
+ size_t buflen);
+char *reparse_data_buffer_str(TALLOC_CTX *mem_ctx,
+ const struct reparse_data_buffer *dst);
+
+ssize_t reparse_data_buffer_marshall(const struct reparse_data_buffer *src,
+ uint8_t *buf,
+ size_t buflen);
+
+#endif
diff --git a/libcli/smb/smb1cli_close.c b/libcli/smb/smb1cli_close.c
new file mode 100644
index 0000000..00baa58
--- /dev/null
+++ b/libcli/smb/smb1cli_close.c
@@ -0,0 +1,188 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Gregor Beck 2013
+ Copyright (C) Stefan Metzmacher 2013
+
+ 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb1cli_close_state {
+ uint16_t vwv[3];
+};
+
+static void smb1cli_close_done(struct tevent_req *subreq);
+
+/**
+ * Send an asynchronous SMB_COM_CLOSE request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee442151.aspx">MS-CIFS 2.2.4.5.1</a>
+ * @see smb1cli_close_recv(), smb1cli_close()
+ *
+ * @param[in] mem_ctx The memory context for the result.
+ * @param[in] ev The event context to work on.
+ * @param[in] conn The smb connection.
+ * @param[in] timeout_msec If positive a timeout for the request.
+ * @param[in] pid The process identifier.
+ * @param[in] tcon The smb tree connect.
+ * @param[in] session The smb session.
+ * @param[in] fnum The file id of the file to be closed.
+ * @param[in] last_modified If not 0 or 0xFFFFFFFF request to set modification time to this number of seconds since January 1, 1970.
+ *
+ * @return a tevent_req or NULL.
+ */
+struct tevent_req *smb1cli_close_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint16_t fnum,
+ uint32_t last_modified)
+{
+ struct tevent_req *req, *subreq;
+ struct smb1cli_close_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct smb1cli_close_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ SSVAL(state->vwv+0, 0, fnum);
+ SIVALS(state->vwv+1, 0, last_modified);
+
+ subreq = smb1cli_req_send(state, ev, conn, SMBclose,
+ 0, 0, /* *_flags */
+ 0, 0, /* *_flags2 */
+ timeout_msec, pid, tcon, session,
+ ARRAY_SIZE(state->vwv), state->vwv,
+ 0, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb1cli_close_done, req);
+ return req;
+}
+
+static void smb1cli_close_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb1cli_close_state *state = tevent_req_data(
+ req, struct smb1cli_close_state);
+ NTSTATUS status;
+ static const struct smb1cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .wct = 0x00
+ },
+ };
+
+ status = smb1cli_req_recv(subreq, state,
+ NULL, /* recv_iov */
+ NULL, /* phdr */
+ NULL, /* wct */
+ NULL, /* vwv */
+ NULL, /* pvwv_offset */
+ NULL, /* num_bytes */
+ NULL, /* bytes */
+ NULL, /* pbytes_offset */
+ NULL, /* inbuf */
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+/**
+ * Receive the response to an asynchronous SMB_COM_CLOSE request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee441667.aspx">MS-CIFS 2.2.4.5.2</a>
+ *
+ * @param req A tevent_req created with smb1cli_close_send()
+ *
+ * @return NT_STATUS_OK on success
+ */
+NTSTATUS smb1cli_close_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+/**
+ * Send an synchronous SMB_COM_CLOSE request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee441493.aspx">MS-CIFS 2.2.4.5</a>
+ * @see smb1cli_close_send(), smb1cli_close_recv()
+ *
+ * @param[in] conn The smb connection.
+ * @param[in] timeout_msec If positive a timeout for the request.
+ * @param[in] pid The process identifier.
+ * @param[in] tcon The smb tree connect.
+ * @param[in] session The smb session.
+ * @param[in] fnum The file id of the file to be closed.
+ * @param[in] last_modified If not 0 or 0xFFFFFFFF request to set modification time to this number of seconds since J
+ *
+ * @return NT_STATUS_OK on success.
+ */
+NTSTATUS smb1cli_close(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint16_t fnum,
+ uint32_t last_modified)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ struct tevent_req *req;
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ req = smb1cli_close_send(frame, ev, conn,
+ timeout_msec, pid, tcon, session,
+ fnum, last_modified);
+ if (req == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto done;
+ }
+
+ status = smb1cli_close_recv(req);
+done:
+ talloc_free(frame);
+ return status;
+}
diff --git a/libcli/smb/smb1cli_create.c b/libcli/smb/smb1cli_create.c
new file mode 100644
index 0000000..fc1e16b
--- /dev/null
+++ b/libcli/smb/smb1cli_create.c
@@ -0,0 +1,296 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Gregor Beck 2013
+ Copyright (C) Stefan Metzmacher 2013
+
+ 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb1cli_ntcreatex_state {
+ uint16_t vwv[24];
+ uint16_t fnum;
+};
+
+static void smb1cli_ntcreatex_done(struct tevent_req *subreq);
+
+/**
+ * Send an asynchronous SMB_COM_NT_CREATE_ANDX request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee442175.aspx">MS-CIFS 2.2.4.64.1</a>
+ * @see smb1cli_ntcreatex_recv(), smb1cli_ntcreatex()
+ *
+ * @param[in] mem_ctx The memory context for the result.
+ * @param[in] ev The event context to work on.
+ * @param[in] conn The smb connection.
+ * @param[in] timeout_msec If positive a timeout for the request.
+ * @param[in] pid The process identifier
+ * @param[in] tcon The smb tree connect.
+ * @param[in] session The smb session.
+ * @param[in] fname The name of the file or directory to be opened or created.
+ * @param[in] CreatFlags
+ * @param[in] RootDirectoryFid The file id of an opened root directory fname is based on. 0 means root of the share.
+ * @param[in] DesiredAccess A field of flags that indicate standard, specific, and generic access rights to be requested.
+ * @param[in] AllocationSize Number of Bytes to allocate if the file is to be created or overwritten.
+ * @param[in] FileAttributes <a href="http://msdn.microsoft.com/en-us/library/ee878573.aspx">Extended file attributes</a>
+ * @param[in] ShareAccess A field that specifies how the file should be shared with other processes.
+ * @param[in] CreateDisposition A value that represents the action to take if the file already exists or if the file is a new file and does not already exist.
+ * @param[in] CreateOptions A field of flag options to use if creating a file or directory.
+ * @param[in] ImpersonationLevel
+ * @param[in] SecurityFlags
+ *
+ * @return a tevent_req or NULL
+ */
+struct tevent_req *smb1cli_ntcreatex_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const char *fname,
+ uint32_t CreatFlags,
+ uint32_t RootDirectoryFid,
+ uint32_t DesiredAccess,
+ uint64_t AllocationSize,
+ uint32_t FileAttributes,
+ uint32_t ShareAccess,
+ uint32_t CreateDisposition,
+ uint32_t CreateOptions,
+ uint32_t ImpersonationLevel,
+ uint8_t SecurityFlags)
+{
+ struct tevent_req *req, *subreq;
+ struct smb1cli_ntcreatex_state *state;
+ uint8_t *bytes;
+ size_t converted_len;
+
+ req = tevent_req_create(mem_ctx, &state, struct smb1cli_ntcreatex_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ SCVAL(state->vwv+0, 0, 0xFF);
+ SCVAL(state->vwv+0, 1, 0);
+ SSVAL(state->vwv+1, 0, 0);
+ SCVAL(state->vwv+2, 0, 0);
+ SIVAL(state->vwv+3, 1, CreatFlags);
+ SIVAL(state->vwv+5, 1, RootDirectoryFid);
+ SIVAL(state->vwv+7, 1, DesiredAccess);
+ SBVAL(state->vwv+9, 1, AllocationSize);
+ SIVAL(state->vwv+13, 1, FileAttributes);
+ SIVAL(state->vwv+15, 1, ShareAccess);
+ SIVAL(state->vwv+17, 1, CreateDisposition);
+ SIVAL(state->vwv+19, 1, CreateOptions);
+ SIVAL(state->vwv+21, 1, ImpersonationLevel);
+ SCVAL(state->vwv+23, 1, SecurityFlags);
+
+ bytes = talloc_array(state, uint8_t, 0);
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(conn),
+ fname, strlen(fname)+1,
+ &converted_len);
+
+ /* sigh. this copes with broken netapp filer behaviour */
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(conn), "", 1, NULL);
+
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ SSVAL(state->vwv+2, 1, converted_len);
+
+ subreq = smb1cli_req_send(state, ev, conn, SMBntcreateX,
+ 0, 0, /* *_flags */
+ 0, 0, /* *_flags2 */
+ timeout_msec, pid, tcon, session,
+ ARRAY_SIZE(state->vwv), state->vwv,
+ talloc_get_size(bytes), bytes);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb1cli_ntcreatex_done, req);
+
+ return req;
+}
+
+static void smb1cli_ntcreatex_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb1cli_ntcreatex_state *state = tevent_req_data(
+ req, struct smb1cli_ntcreatex_state);
+ struct iovec *recv_iov = NULL;
+ uint8_t wct;
+ uint16_t *vwv;
+ NTSTATUS status;
+ static const struct smb1cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .wct = 0x22
+ },
+ {
+ /*
+ * This is the broken version see from
+ * [MS-SMB]:
+ * Windows-based SMB servers send 50 (0x32) words in the extended
+ * response although they set the WordCount field to 0x2A.
+ *
+ * And Samba does the same...
+ */
+ .status = NT_STATUS_OK,
+ .wct = 0x2a
+ },
+ {
+ .status = NT_STATUS_OK,
+ .wct = 0x32
+ },
+ };
+
+ status = smb1cli_req_recv(subreq, state,
+ &recv_iov,
+ NULL, /* phdr */
+ &wct,
+ &vwv,
+ NULL, /* pvwv_offset */
+ NULL, /* num_bytes */
+ NULL, /* bytes */
+ NULL, /* pbytes_offset */
+ NULL, /* inbuf */
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ state->fnum = SVAL(vwv+2, 1);
+ tevent_req_done(req);
+}
+
+/**
+ * Receive the response to an asynchronous SMB_COM_NT_CREATE_ANDX request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee441612.aspx">MS-CIFS 2.2.4.64.2</a>
+ *
+ * @param[in] req A tevent request created with smb1cli_ntcreatex_send()
+ * @param[out] pfnum The file id of the opened file or directory.
+ *
+ * @return NT_STATUS_OK on success
+ */
+NTSTATUS smb1cli_ntcreatex_recv(struct tevent_req *req, uint16_t *pfnum)
+{
+ struct smb1cli_ntcreatex_state *state = tevent_req_data(
+ req, struct smb1cli_ntcreatex_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ *pfnum = state->fnum;
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+
+/**
+ * Send a synchronous SMB_COM_NT_CREATE_ANDX request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee442091.aspx">MS-CIFS 2.2.4.64</a>
+ * @see smb1cli_ntcreatex_send() smb1cli_ntcreatex_recv()
+ *
+ * @param[in] conn The smb connection.
+ * @param[in] timeout_msec If positive a timeout for the request.
+ * @param[in] pid The process identifier
+ * @param[in] tcon The smb tree connect.
+ * @param[in] session The smb session.
+ * @param[in] fname The name of the file or directory to be opened or created.
+ * @param[in] CreatFlags
+ * @param[in] RootDirectoryFid The file id of an opened root directory fname is based on. 0 means root of the share.
+ * @param[in] DesiredAccess A field of flags that indicate standard, specific, and generic access rights to be requested.
+ * @param[in] AllocationSize Number of Bytes to allocate if the file is to be created or overwritten.
+ * @param[in] FileAttributes <a href="http://msdn.microsoft.com/en-us/library/ee878573.aspx">Extended file attributes</a>
+ * @param[in] ShareAccess A field that specifies how the file should be shared with other processes.
+ * @param[in] CreateDisposition A value that represents the action to take if the file already exists or if the file is a new file and does not already exist.
+ * @param[in] CreateOptions A field of flag options to use if creating a file or directory.
+ * @param[in] ImpersonationLevel
+ * @param[in] SecurityFlags
+ * @param[out] pfnum The file id representing the file or directory created or opened.
+ *
+ * @return NT_STATUS_OK on success
+ */
+NTSTATUS smb1cli_ntcreatex(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const char *fname,
+ uint32_t CreatFlags,
+ uint32_t RootDirectoryFid,
+ uint32_t DesiredAccess,
+ uint64_t AllocationSize,
+ uint32_t FileAttributes,
+ uint32_t ShareAccess,
+ uint32_t CreateDisposition,
+ uint32_t CreateOptions,
+ uint32_t ImpersonationLevel,
+ uint8_t SecurityFlags,
+ uint16_t *pfnum)
+{
+ TALLOC_CTX *frame = NULL;
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_OK;
+
+ frame = talloc_stackframe();
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ req = smb1cli_ntcreatex_send(frame, ev, conn,
+ timeout_msec,
+ pid, tcon, session,
+ fname, CreatFlags, RootDirectoryFid,
+ DesiredAccess, AllocationSize,
+ FileAttributes, ShareAccess,
+ CreateDisposition, CreateOptions,
+ ImpersonationLevel, SecurityFlags);
+ if (req == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+
+ status = smb1cli_ntcreatex_recv(req, pfnum);
+fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb1cli_echo.c b/libcli/smb/smb1cli_echo.c
new file mode 100644
index 0000000..10dff2d
--- /dev/null
+++ b/libcli/smb/smb1cli_echo.c
@@ -0,0 +1,169 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Stefan Metzmacher 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb1cli_echo_state {
+ uint16_t vwv[1];
+ DATA_BLOB data;
+ uint16_t num_echos;
+};
+
+static void smb1cli_echo_done(struct tevent_req *subreq);
+
+struct tevent_req *smb1cli_echo_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint16_t num_echos,
+ DATA_BLOB data)
+{
+ struct tevent_req *req, *subreq;
+ struct smb1cli_echo_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct smb1cli_echo_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ SSVAL(state->vwv, 0, num_echos);
+ state->data = data;
+ state->num_echos = num_echos;
+
+ subreq = smb1cli_req_send(state, ev, conn, SMBecho,
+ 0, 0, /* *_flags */
+ 0, 0, /* *_flags2 */
+ timeout_msec,
+ 0, /* pid */
+ NULL, /* tcon */
+ NULL, /* session */
+ ARRAY_SIZE(state->vwv), state->vwv,
+ data.length, data.data);
+ if (subreq == NULL) {
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, smb1cli_echo_done, req);
+ return req;
+ fail:
+ TALLOC_FREE(req);
+ return NULL;
+}
+
+static void smb1cli_echo_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb1cli_echo_state *state = tevent_req_data(
+ req, struct smb1cli_echo_state);
+ NTSTATUS status;
+ uint32_t num_bytes;
+ uint8_t *bytes;
+ struct iovec *recv_iov;
+ struct smb1cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .wct = 1,
+ },
+ };
+
+ status = smb1cli_req_recv(subreq, state,
+ &recv_iov,
+ NULL, /* phdr */
+ NULL, /* pwct */
+ NULL, /* pvwv */
+ NULL, /* pvwv_offset */
+ &num_bytes,
+ &bytes,
+ NULL, /* pbytes_offset */
+ NULL, /* pinbuf */
+ expected, ARRAY_SIZE(expected));
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ if (num_bytes != state->data.length) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (memcmp(bytes, state->data.data, num_bytes) != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ /* TODO: do we want to verify the sequence number? */
+
+ state->num_echos -=1;
+ if (state->num_echos == 0) {
+ tevent_req_done(req);
+ return;
+ }
+
+ if (!smbXcli_req_set_pending(subreq)) {
+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+}
+
+/**
+ * Get the result out from an echo request
+ * @param[in] req The async_req from smb1cli_echo_send
+ * @retval Did the server reply correctly?
+ */
+
+NTSTATUS smb1cli_echo_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS smb1cli_echo(struct smbXcli_conn *conn, uint32_t timeout_msec,
+ uint16_t num_echos, DATA_BLOB data)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb1cli_echo_send(frame, ev, conn, timeout_msec, num_echos, data);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb1cli_echo_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb1cli_read.c b/libcli/smb/smb1cli_read.c
new file mode 100644
index 0000000..877aab5
--- /dev/null
+++ b/libcli/smb/smb1cli_read.c
@@ -0,0 +1,241 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Gregor Beck 2013
+
+ 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb1cli_readx_state {
+ uint32_t size;
+ uint16_t vwv[12];
+ uint32_t received;
+ uint8_t *buf;
+ bool out_valid;
+};
+
+static void smb1cli_readx_done(struct tevent_req *subreq);
+
+/**
+ * Send an asynchrounus SMB_COM_READ_ANDX request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee441839.aspx">MS-CIFS 2.2.4.42.1</a>,
+ * <a href="http://msdn.microsoft.com/en-us/library/ff470250.aspx">MS-SMB 2.2.4.2.1</a>
+ * @see smb1cli_readx_recv()
+ * @todo fix API (min/max size, timeout)
+ *
+ * @param[in] mem_ctx The memory context for the result.
+ * @param[in] ev The event context to work on.
+ * @param[in] conn The smb connection.
+ * @param[in] timeout_msec If positive a timeout for the request.
+ * @param[in] pid The process identifier
+ * @param[in] tcon The smb tree connect.
+ * @param[in] session The smb session.
+ * @param[in] fnum The file id of the file the data should be read from.
+ * @param[in] offset The offset in bytes from the begin of file where to start reading.
+ * @param[in] size The number of bytes to read.
+ *
+ * @return a tevent_req or NULL
+ */
+struct tevent_req *smb1cli_readx_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint16_t fnum,
+ uint64_t offset,
+ uint32_t size)
+{
+ NTSTATUS status;
+ struct tevent_req *req, *subreq;
+ struct smb1cli_readx_state *state;
+ uint8_t wct = 10;
+
+ req = tevent_req_create(mem_ctx, &state, struct smb1cli_readx_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->size = size;
+
+ SCVAL(state->vwv + 0, 0, 0xFF);
+ SCVAL(state->vwv + 0, 1, 0);
+ SSVAL(state->vwv + 1, 0, 0);
+ SSVAL(state->vwv + 2, 0, fnum);
+ SIVAL(state->vwv + 3, 0, offset);
+ SSVAL(state->vwv + 5, 0, size);
+ SSVAL(state->vwv + 6, 0, size);
+ SSVAL(state->vwv + 7, 0, (size >> 16));
+ SSVAL(state->vwv + 8, 0, 0);
+ SSVAL(state->vwv + 9, 0, 0);
+
+ if (smb1cli_conn_capabilities(conn) & CAP_LARGE_FILES) {
+ SIVAL(state->vwv + 10, 0,
+ (((uint64_t)offset)>>32) & 0xffffffff);
+ wct = 12;
+ } else {
+ if ((((uint64_t)offset) & 0xffffffff00000000LL) != 0) {
+ DEBUG(10, ("smb1cli_readx_send got large offset where "
+ "the server does not support it\n"));
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+ }
+
+ subreq = smb1cli_req_create(state, ev, conn, SMBreadX,
+ 0, 0, /* *_flags */
+ 0, 0, /* *_flags2 */
+ timeout_msec, pid, tcon, session,
+ wct, state->vwv,
+ 0, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb1cli_readx_done, req);
+
+ status = smb1cli_req_chain_submit(&subreq, 1);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void smb1cli_readx_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb1cli_readx_state *state = tevent_req_data(
+ req, struct smb1cli_readx_state);
+ struct iovec *recv_iov = NULL;
+ uint8_t wct;
+ uint16_t *vwv;
+ uint32_t num_bytes;
+ uint8_t *bytes;
+ uint16_t data_offset;
+ uint32_t bytes_offset;
+ NTSTATUS status;
+ static const struct smb1cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .wct = 0x0C
+ },
+ {
+ .status = STATUS_BUFFER_OVERFLOW,
+ .wct = 0x0C
+ },
+ };
+
+ status = smb1cli_req_recv(subreq, state,
+ &recv_iov,
+ NULL, /* phdr */
+ &wct,
+ &vwv,
+ NULL, /* pvwv_offset */
+ &num_bytes,
+ &bytes,
+ &bytes_offset,
+ NULL, /* inbuf */
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+ /* no error */
+ } else {
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ }
+
+ /* size is the number of bytes the server returned.
+ * Might be zero. */
+ state->received = SVAL(vwv + 5, 0);
+ state->received |= (((unsigned int)SVAL(vwv + 7, 0)) << 16);
+
+ if (state->received > state->size) {
+ DEBUG(5,("server returned more than we wanted!\n"));
+ tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
+ return;
+ }
+
+ /*
+ * bcc field must be valid for small reads, for large reads the 16-bit
+ * bcc field can't be correct.
+ */
+ if ((state->received < 0xffff) && (state->received > num_bytes)) {
+ DEBUG(5, ("server announced more bytes than sent\n"));
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ data_offset = SVAL(vwv+6, 0);
+ if (data_offset < bytes_offset) {
+ DEBUG(5, ("server returned invalid read&x data offset\n"));
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ if (smb_buffer_oob(num_bytes, data_offset - bytes_offset, state->received)) {
+ DEBUG(5, ("server returned invalid read&x data offset\n"));
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ state->buf = bytes + (data_offset - bytes_offset);
+
+ state->out_valid = true;
+
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+/**
+ * Receive the response to an asynchronous SMB_COM_READ_ANDX request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee441872.aspx">MS-CIFS 2.2.4.42.2</a>,
+ * <a href="http://msdn.microsoft.com/en-us/library/ff470017.aspx">MS-SMB 2.2.4.2.2</a>
+ *
+ * @warning rcvbuf is talloced from the request, so better make sure that you
+ * copy it away before you talloc_free(req). rcvbuf is NOT a talloc_ctx of its
+ * own, so do not talloc_move it!
+ *
+ * @param[in] req A tevent request created with smb1cli_readx_send()
+ * @param[out] received The number of bytes received.
+ * @param[out] rcvbuf Pointer to the bytes received.
+ *
+ * @return NT_STATUS_OK or STATUS_BUFFER_OVERFLOW on success.
+ */
+NTSTATUS smb1cli_readx_recv(struct tevent_req *req,
+ uint32_t *received,
+ uint8_t **rcvbuf)
+{
+ struct smb1cli_readx_state *state = tevent_req_data(
+ req, struct smb1cli_readx_state);
+ NTSTATUS status = NT_STATUS_OK;
+
+ if (tevent_req_is_nterror(req, &status) && !state->out_valid) {
+ *received = 0;
+ *rcvbuf = NULL;
+ return status;
+ }
+ *received = state->received;
+ *rcvbuf = state->buf;
+ return status;
+}
diff --git a/libcli/smb/smb1cli_session.c b/libcli/smb/smb1cli_session.c
new file mode 100644
index 0000000..a8ad9b8
--- /dev/null
+++ b/libcli/smb/smb1cli_session.c
@@ -0,0 +1,821 @@
+/*
+ Unix SMB/CIFS implementation.
+ client connect/disconnect routines
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Andrew Bartlett 2001-2003
+ Copyright (C) Volker Lendecke 2011
+ Copyright (C) Jeremy Allison 2011
+ Copyright (C) Stefan Metzmacher 2016
+
+ 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 "system/network.h"
+#include "../lib/util/tevent_ntstatus.h"
+#include "../libcli/smb/smb_common.h"
+#include "../libcli/smb/smbXcli_base.h"
+
+
+struct smb1cli_session_setup_lm21_state {
+ struct smbXcli_session *session;
+ uint16_t vwv[10];
+ struct iovec *recv_iov;
+ uint16_t out_session_id;
+ uint16_t out_action;
+ char *out_native_os;
+ char *out_native_lm;
+};
+
+static void smb1cli_session_setup_lm21_done(struct tevent_req *subreq);
+
+struct tevent_req *smb1cli_session_setup_lm21_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_session *session,
+ uint16_t in_buf_size,
+ uint16_t in_mpx_max,
+ uint16_t in_vc_num,
+ uint32_t in_sess_key,
+ const char *in_user,
+ const char *in_domain,
+ const DATA_BLOB in_apassword,
+ const char *in_native_os,
+ const char *in_native_lm)
+{
+ struct tevent_req *req = NULL;
+ struct smb1cli_session_setup_lm21_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+ uint16_t *vwv = NULL;
+ uint8_t *bytes = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb1cli_session_setup_lm21_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->session = session;
+ vwv = state->vwv;
+
+ if (in_user == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (in_domain == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (in_apassword.length > UINT16_MAX) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (in_native_os == NULL && in_native_lm != NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ SCVAL(vwv+0, 0, 0xff);
+ SCVAL(vwv+0, 1, 0);
+ SSVAL(vwv+1, 0, 0);
+ SSVAL(vwv+2, 0, in_buf_size);
+ SSVAL(vwv+3, 0, in_mpx_max);
+ SSVAL(vwv+4, 0, in_vc_num);
+ SIVAL(vwv+5, 0, in_sess_key);
+ SSVAL(vwv+7, 0, in_apassword.length);
+ SSVAL(vwv+8, 0, 0); /* reserved */
+ SSVAL(vwv+9, 0, 0); /* reserved */
+
+ bytes = talloc_array(state, uint8_t,
+ in_apassword.length);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+ if (in_apassword.length != 0) {
+ memcpy(bytes,
+ in_apassword.data,
+ in_apassword.length);
+ }
+
+ bytes = smb_bytes_push_str(bytes,
+ smbXcli_conn_use_unicode(conn),
+ in_user, strlen(in_user)+1,
+ NULL);
+ bytes = smb_bytes_push_str(bytes,
+ smbXcli_conn_use_unicode(conn),
+ in_domain, strlen(in_domain)+1,
+ NULL);
+ if (in_native_os != NULL) {
+ bytes = smb_bytes_push_str(bytes,
+ smbXcli_conn_use_unicode(conn),
+ in_native_os, strlen(in_native_os)+1,
+ NULL);
+ }
+ if (in_native_lm != NULL) {
+ bytes = smb_bytes_push_str(bytes,
+ smbXcli_conn_use_unicode(conn),
+ in_native_lm, strlen(in_native_lm)+1,
+ NULL);
+ }
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = smb1cli_req_send(state, ev, conn,
+ SMBsesssetupX,
+ 0, /* additional_flags */
+ 0, /* clear_flags */
+ 0, /* additional_flags2 */
+ 0, /* clear_flags2 */
+ timeout_msec,
+ pid,
+ NULL, /* tcon */
+ session,
+ 10, /* wct */
+ vwv,
+ talloc_get_size(bytes),
+ bytes);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb1cli_session_setup_lm21_done, req);
+
+ return req;
+}
+
+static void smb1cli_session_setup_lm21_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb1cli_session_setup_lm21_state *state =
+ tevent_req_data(req,
+ struct smb1cli_session_setup_lm21_state);
+ NTSTATUS status;
+ uint8_t *inhdr = NULL;
+ uint8_t wct;
+ uint16_t *vwv = NULL;
+ uint32_t num_bytes;
+ uint8_t *bytes = NULL;
+ const uint8_t *p = NULL;
+ size_t ret = 0;
+ uint16_t flags2;
+ bool use_unicode = false;
+ struct smb1cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .wct = 3,
+ },
+ };
+
+ status = smb1cli_req_recv(subreq, state,
+ &state->recv_iov,
+ &inhdr,
+ &wct,
+ &vwv,
+ NULL, /* pvwv_offset */
+ &num_bytes,
+ &bytes,
+ NULL, /* pbytes_offset */
+ NULL, /* pinbuf */
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ flags2 = SVAL(inhdr, HDR_FLG2);
+ if (flags2 & FLAGS2_UNICODE_STRINGS) {
+ use_unicode = true;
+ }
+
+ state->out_session_id = SVAL(inhdr, HDR_UID);
+ state->out_action = SVAL(vwv+2, 0);
+
+ p = bytes;
+
+ status = smb_bytes_pull_str(state, &state->out_native_os,
+ use_unicode, bytes, num_bytes,
+ p, &ret);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_pull_str(state, &state->out_native_lm,
+ use_unicode, bytes, num_bytes,
+ p, &ret);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ smb1cli_session_set_id(state->session, state->out_session_id);
+ smb1cli_session_set_action(state->session, state->out_action);
+
+ tevent_req_done(req);
+}
+
+NTSTATUS smb1cli_session_setup_lm21_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ char **out_native_os,
+ char **out_native_lm)
+{
+ struct smb1cli_session_setup_lm21_state *state =
+ tevent_req_data(req,
+ struct smb1cli_session_setup_lm21_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ if (out_native_os != NULL) {
+ *out_native_os = talloc_move(mem_ctx, &state->out_native_os);
+ }
+
+ if (out_native_lm != NULL) {
+ *out_native_lm = talloc_move(mem_ctx, &state->out_native_lm);
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+struct smb1cli_session_setup_nt1_state {
+ struct smbXcli_session *session;
+ uint16_t vwv[13];
+ struct iovec *recv_iov;
+ uint8_t *inbuf;
+ uint16_t out_session_id;
+ uint16_t out_action;
+ char *out_native_os;
+ char *out_native_lm;
+ char *out_primary_domain;
+};
+
+static void smb1cli_session_setup_nt1_done(struct tevent_req *subreq);
+
+struct tevent_req *smb1cli_session_setup_nt1_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_session *session,
+ uint16_t in_buf_size,
+ uint16_t in_mpx_max,
+ uint16_t in_vc_num,
+ uint32_t in_sess_key,
+ const char *in_user,
+ const char *in_domain,
+ const DATA_BLOB in_apassword,
+ const DATA_BLOB in_upassword,
+ uint32_t in_capabilities,
+ const char *in_native_os,
+ const char *in_native_lm)
+{
+ struct tevent_req *req = NULL;
+ struct smb1cli_session_setup_nt1_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+ uint16_t *vwv = NULL;
+ uint8_t *bytes = NULL;
+ size_t align_upassword = 0;
+ size_t apassword_ofs = 0;
+ size_t upassword_ofs = 0;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb1cli_session_setup_nt1_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->session = session;
+ vwv = state->vwv;
+
+ if (in_user == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (in_domain == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (in_apassword.length > UINT16_MAX) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (in_upassword.length > UINT16_MAX) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (in_native_os == NULL && in_native_lm != NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ SCVAL(vwv+0, 0, 0xff);
+ SCVAL(vwv+0, 1, 0);
+ SSVAL(vwv+1, 0, 0);
+ SSVAL(vwv+2, 0, in_buf_size);
+ SSVAL(vwv+3, 0, in_mpx_max);
+ SSVAL(vwv+4, 0, in_vc_num);
+ SIVAL(vwv+5, 0, in_sess_key);
+ SSVAL(vwv+7, 0, in_apassword.length);
+ SSVAL(vwv+8, 0, in_upassword.length);
+ SSVAL(vwv+9, 0, 0); /* reserved */
+ SSVAL(vwv+10, 0, 0); /* reserved */
+ SIVAL(vwv+11, 0, in_capabilities);
+
+ if (in_apassword.length == 0 && in_upassword.length > 0) {
+ /*
+ * This is plaintext auth with a unicode password,
+ * we need to align the buffer.
+ *
+ * This is what smbclient and Windows XP send as
+ * a client. And what smbd expects.
+ *
+ * But it doesn't follow [MS-CIFS] (v20160714)
+ * 2.2.4.53.1 SMB_COM_SESSION_SETUP_ANDX Request:
+ *
+ * ...
+ *
+ * If SMB_FLAGS2_UNICODE is set (1), the value of OEMPasswordLen
+ * MUST be 0x0000 and the password MUST be encoded using
+ * UTF-16LE Unicode. Padding MUST NOT be added to
+ * align this plaintext Unicode string to a word boundary.
+ *
+ * ...
+ */
+ uint16_t security_mode = smb1cli_conn_server_security_mode(conn);
+
+ if (!(security_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) {
+ align_upassword = 1;
+ }
+ }
+
+ bytes = talloc_array(state, uint8_t,
+ in_apassword.length +
+ align_upassword +
+ in_upassword.length);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+ if (in_apassword.length != 0) {
+ memcpy(bytes + apassword_ofs,
+ in_apassword.data,
+ in_apassword.length);
+ upassword_ofs += in_apassword.length;
+ }
+ if (align_upassword != 0) {
+ memset(bytes + upassword_ofs, 0, align_upassword);
+ upassword_ofs += align_upassword;
+ }
+ if (in_upassword.length != 0) {
+ memcpy(bytes + upassword_ofs,
+ in_upassword.data,
+ in_upassword.length);
+ }
+
+ bytes = smb_bytes_push_str(bytes,
+ smbXcli_conn_use_unicode(conn),
+ in_user, strlen(in_user)+1,
+ NULL);
+ bytes = smb_bytes_push_str(bytes,
+ smbXcli_conn_use_unicode(conn),
+ in_domain, strlen(in_domain)+1,
+ NULL);
+ if (in_native_os != NULL) {
+ bytes = smb_bytes_push_str(bytes,
+ smbXcli_conn_use_unicode(conn),
+ in_native_os, strlen(in_native_os)+1,
+ NULL);
+ }
+ if (in_native_lm != NULL) {
+ bytes = smb_bytes_push_str(bytes,
+ smbXcli_conn_use_unicode(conn),
+ in_native_lm, strlen(in_native_lm)+1,
+ NULL);
+ }
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = smb1cli_req_send(state, ev, conn,
+ SMBsesssetupX,
+ 0, /* additional_flags */
+ 0, /* clear_flags */
+ 0, /* additional_flags2 */
+ 0, /* clear_flags2 */
+ timeout_msec,
+ pid,
+ NULL, /* tcon */
+ session,
+ 13, /* wct */
+ vwv,
+ talloc_get_size(bytes),
+ bytes);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb1cli_session_setup_nt1_done, req);
+
+ return req;
+}
+
+static void smb1cli_session_setup_nt1_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb1cli_session_setup_nt1_state *state =
+ tevent_req_data(req,
+ struct smb1cli_session_setup_nt1_state);
+ NTSTATUS status;
+ uint8_t *inhdr = NULL;
+ uint8_t wct;
+ uint16_t *vwv = NULL;
+ uint32_t num_bytes;
+ uint8_t *bytes = NULL;
+ const uint8_t *p = NULL;
+ size_t ret = 0;
+ uint16_t flags2;
+ bool use_unicode = false;
+ struct smb1cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .wct = 3,
+ },
+ };
+
+ status = smb1cli_req_recv(subreq, state,
+ &state->recv_iov,
+ &inhdr,
+ &wct,
+ &vwv,
+ NULL, /* pvwv_offset */
+ &num_bytes,
+ &bytes,
+ NULL, /* pbytes_offset */
+ &state->inbuf,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ flags2 = SVAL(inhdr, HDR_FLG2);
+ if (flags2 & FLAGS2_UNICODE_STRINGS) {
+ use_unicode = true;
+ }
+
+ state->out_session_id = SVAL(inhdr, HDR_UID);
+ state->out_action = SVAL(vwv+2, 0);
+
+ p = bytes;
+
+ status = smb_bytes_pull_str(state, &state->out_native_os,
+ use_unicode, bytes, num_bytes,
+ p, &ret);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_pull_str(state, &state->out_native_lm,
+ use_unicode, bytes, num_bytes,
+ p, &ret);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_pull_str(state, &state->out_primary_domain,
+ use_unicode, bytes, num_bytes,
+ p, &ret);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ smb1cli_session_set_id(state->session, state->out_session_id);
+ smb1cli_session_set_action(state->session, state->out_action);
+
+ tevent_req_done(req);
+}
+
+NTSTATUS smb1cli_session_setup_nt1_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **precv_iov,
+ const uint8_t **precv_inbuf,
+ char **out_native_os,
+ char **out_native_lm,
+ char **out_primary_domain)
+{
+ struct smb1cli_session_setup_nt1_state *state =
+ tevent_req_data(req,
+ struct smb1cli_session_setup_nt1_state);
+ NTSTATUS status;
+ struct iovec *recv_iov = NULL;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ recv_iov = talloc_move(mem_ctx, &state->recv_iov);
+ if (precv_iov != NULL) {
+ *precv_iov = recv_iov;
+ }
+ if (precv_inbuf != NULL) {
+ *precv_inbuf = state->inbuf;
+ }
+
+ if (out_native_os != NULL) {
+ *out_native_os = talloc_move(mem_ctx, &state->out_native_os);
+ }
+
+ if (out_native_lm != NULL) {
+ *out_native_lm = talloc_move(mem_ctx, &state->out_native_lm);
+ }
+
+ if (out_primary_domain != NULL) {
+ *out_primary_domain = talloc_move(mem_ctx,
+ &state->out_primary_domain);
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+struct smb1cli_session_setup_ext_state {
+ struct smbXcli_session *session;
+ uint16_t vwv[12];
+ struct iovec *recv_iov;
+ uint8_t *inbuf;
+ NTSTATUS status;
+ uint16_t out_session_id;
+ uint16_t out_action;
+ DATA_BLOB out_security_blob;
+ char *out_native_os;
+ char *out_native_lm;
+};
+
+static void smb1cli_session_setup_ext_done(struct tevent_req *subreq);
+
+struct tevent_req *smb1cli_session_setup_ext_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_session *session,
+ uint16_t in_buf_size,
+ uint16_t in_mpx_max,
+ uint16_t in_vc_num,
+ uint32_t in_sess_key,
+ const DATA_BLOB in_security_blob,
+ uint32_t in_capabilities,
+ const char *in_native_os,
+ const char *in_native_lm)
+{
+ struct tevent_req *req = NULL;
+ struct smb1cli_session_setup_ext_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+ uint16_t *vwv = NULL;
+ uint8_t *bytes = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb1cli_session_setup_ext_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->session = session;
+ vwv = state->vwv;
+
+ if (in_security_blob.length > UINT16_MAX) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (in_native_os == NULL && in_native_lm != NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ SCVAL(vwv+0, 0, 0xff);
+ SCVAL(vwv+0, 1, 0);
+ SSVAL(vwv+1, 0, 0);
+ SSVAL(vwv+2, 0, in_buf_size);
+ SSVAL(vwv+3, 0, in_mpx_max);
+ SSVAL(vwv+4, 0, in_vc_num);
+ SIVAL(vwv+5, 0, in_sess_key);
+ SSVAL(vwv+7, 0, in_security_blob.length);
+ SSVAL(vwv+8, 0, 0); /* reserved */
+ SSVAL(vwv+9, 0, 0); /* reserved */
+ SIVAL(vwv+10, 0, in_capabilities);
+
+ bytes = talloc_array(state, uint8_t,
+ in_security_blob.length);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+ if (in_security_blob.length != 0) {
+ memcpy(bytes,
+ in_security_blob.data,
+ in_security_blob.length);
+ }
+
+ if (in_native_os != NULL) {
+ bytes = smb_bytes_push_str(bytes,
+ smbXcli_conn_use_unicode(conn),
+ in_native_os, strlen(in_native_os)+1,
+ NULL);
+ }
+ if (in_native_lm != NULL) {
+ bytes = smb_bytes_push_str(bytes,
+ smbXcli_conn_use_unicode(conn),
+ in_native_lm, strlen(in_native_lm)+1,
+ NULL);
+ }
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = smb1cli_req_send(state, ev, conn,
+ SMBsesssetupX,
+ 0, /* additional_flags */
+ 0, /* clear_flags */
+ 0, /* additional_flags2 */
+ 0, /* clear_flags2 */
+ timeout_msec,
+ pid,
+ NULL, /* tcon */
+ session,
+ 12, /* wct */
+ vwv,
+ talloc_get_size(bytes),
+ bytes);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb1cli_session_setup_ext_done, req);
+
+ return req;
+}
+
+static void smb1cli_session_setup_ext_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb1cli_session_setup_ext_state *state =
+ tevent_req_data(req,
+ struct smb1cli_session_setup_ext_state);
+ NTSTATUS status;
+ uint8_t *inhdr = NULL;
+ uint8_t wct;
+ uint16_t *vwv = NULL;
+ uint32_t num_bytes;
+ uint8_t *bytes = NULL;
+ const uint8_t *p = NULL;
+ size_t ret = 0;
+ uint16_t flags2;
+ uint16_t out_security_blob_length = 0;
+ bool use_unicode = false;
+ struct smb1cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .wct = 4,
+ },
+ {
+ .status = NT_STATUS_MORE_PROCESSING_REQUIRED,
+ .wct = 4,
+ },
+ };
+
+ status = smb1cli_req_recv(subreq, state,
+ &state->recv_iov,
+ &inhdr,
+ &wct,
+ &vwv,
+ NULL, /* pvwv_offset */
+ &num_bytes,
+ &bytes,
+ NULL, /* pbytes_offset */
+ &state->inbuf,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ state->status = status;
+ if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ status = NT_STATUS_OK;
+ }
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ flags2 = SVAL(inhdr, HDR_FLG2);
+ if (flags2 & FLAGS2_UNICODE_STRINGS) {
+ use_unicode = true;
+ }
+
+ state->out_session_id = SVAL(inhdr, HDR_UID);
+ state->out_action = SVAL(vwv+2, 0);
+ out_security_blob_length = SVAL(vwv+3, 0);
+
+ if (out_security_blob_length > num_bytes) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ p = bytes;
+
+ /*
+ * Note: this points into state->recv_iov!
+ */
+ state->out_security_blob = data_blob_const(p, out_security_blob_length);
+ p += out_security_blob_length;
+
+ status = smb_bytes_pull_str(state, &state->out_native_os,
+ use_unicode, bytes, num_bytes,
+ p, &ret);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_pull_str(state, &state->out_native_lm,
+ use_unicode, bytes, num_bytes,
+ p, &ret);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ /* p += ret; */
+
+ smb1cli_session_set_id(state->session, state->out_session_id);
+ smb1cli_session_set_action(state->session, state->out_action);
+
+ tevent_req_done(req);
+}
+
+NTSTATUS smb1cli_session_setup_ext_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **precv_iov,
+ const uint8_t **precv_inbuf,
+ DATA_BLOB *out_security_blob,
+ char **out_native_os,
+ char **out_native_lm)
+{
+ struct smb1cli_session_setup_ext_state *state =
+ tevent_req_data(req,
+ struct smb1cli_session_setup_ext_state);
+ NTSTATUS status;
+ struct iovec *recv_iov = NULL;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ recv_iov = talloc_move(mem_ctx, &state->recv_iov);
+ if (precv_iov != NULL) {
+ *precv_iov = recv_iov;
+ }
+ if (precv_inbuf != NULL) {
+ *precv_inbuf = state->inbuf;
+ }
+
+ *out_security_blob = state->out_security_blob;
+
+ if (out_native_os != NULL) {
+ *out_native_os = talloc_move(mem_ctx, &state->out_native_os);
+ }
+
+ if (out_native_lm != NULL) {
+ *out_native_lm = talloc_move(mem_ctx, &state->out_native_lm);
+ }
+
+ /*
+ * Return the status from the server:
+ * NT_STATUS_MORE_PROCESSING_REQUIRED or
+ * NT_STATUS_OK.
+ */
+ status = state->status;
+ tevent_req_received(req);
+ return status;
+}
diff --git a/libcli/smb/smb1cli_trans.c b/libcli/smb/smb1cli_trans.c
new file mode 100644
index 0000000..99021ce
--- /dev/null
+++ b/libcli/smb/smb1cli_trans.c
@@ -0,0 +1,908 @@
+/*
+ Unix SMB/CIFS implementation.
+ client transaction calls
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ 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 "system/network.h"
+#include "../lib/util/tevent_ntstatus.h"
+#include "../libcli/smb/smb_common.h"
+#include "../libcli/smb/smbXcli_base.h"
+
+struct trans_recvblob {
+ uint8_t *data;
+ uint32_t max, total, received;
+};
+
+struct smb1cli_trans_state {
+ struct smbXcli_conn *conn;
+ struct tevent_context *ev;
+ uint8_t cmd;
+ uint8_t additional_flags;
+ uint8_t clear_flags;
+ uint16_t additional_flags2;
+ uint16_t clear_flags2;
+ uint32_t timeout_msec;
+ uint16_t mid;
+ uint32_t pid;
+ struct smbXcli_tcon *tcon;
+ struct smbXcli_session *session;
+ const char *pipe_name;
+ uint8_t *pipe_name_conv;
+ size_t pipe_name_conv_len;
+ uint16_t fid;
+ uint16_t function;
+ int flags;
+ uint16_t *setup;
+ uint8_t num_setup, max_setup;
+ uint8_t *param;
+ uint32_t num_param, param_sent;
+ uint8_t *data;
+ uint32_t num_data, data_sent;
+
+ uint8_t num_rsetup;
+ uint16_t *rsetup;
+ struct trans_recvblob rparam;
+ struct trans_recvblob rdata;
+ uint16_t recv_flags2;
+
+ struct iovec iov[6];
+ uint8_t pad[4];
+ uint8_t zero_pad[4];
+ uint16_t vwv[32];
+
+ NTSTATUS status;
+
+ struct tevent_req *primary_subreq;
+};
+
+static void smb1cli_trans_cleanup_primary(struct smb1cli_trans_state *state)
+{
+ if (state->primary_subreq) {
+ smb1cli_req_set_mid(state->primary_subreq, 0);
+ smbXcli_req_unset_pending(state->primary_subreq);
+ TALLOC_FREE(state->primary_subreq);
+ }
+}
+
+static int smb1cli_trans_state_destructor(struct smb1cli_trans_state *state)
+{
+ smb1cli_trans_cleanup_primary(state);
+ return 0;
+}
+
+static NTSTATUS smb1cli_pull_trans(uint8_t *inhdr,
+ uint8_t wct,
+ uint16_t *vwv,
+ uint32_t vwv_ofs,
+ uint32_t num_bytes,
+ uint8_t *bytes,
+ uint32_t bytes_ofs,
+ uint8_t smb_cmd, bool expect_first_reply,
+ uint8_t *pnum_setup, uint16_t **psetup,
+ uint32_t *ptotal_param, uint32_t *pnum_param,
+ uint32_t *pparam_disp, uint8_t **pparam,
+ uint32_t *ptotal_data, uint32_t *pnum_data,
+ uint32_t *pdata_disp, uint8_t **pdata)
+{
+ uint32_t param_ofs, data_ofs;
+ uint8_t expected_num_setup;
+ uint32_t max_bytes = UINT32_MAX - bytes_ofs;
+ uint32_t bytes_end;
+
+ if (num_bytes > max_bytes) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ bytes_end = bytes_ofs + num_bytes;
+
+ if (expect_first_reply) {
+ if ((wct != 0) || (num_bytes != 0)) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ return NT_STATUS_OK;
+ }
+
+ switch (smb_cmd) {
+ case SMBtrans:
+ case SMBtrans2:
+ if (wct < 10) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ expected_num_setup = wct - 10;
+ *ptotal_param = SVAL(vwv + 0, 0);
+ *ptotal_data = SVAL(vwv + 1, 0);
+ *pnum_param = SVAL(vwv + 3, 0);
+ param_ofs = SVAL(vwv + 4, 0);
+ *pparam_disp = SVAL(vwv + 5, 0);
+ *pnum_data = SVAL(vwv + 6, 0);
+ data_ofs = SVAL(vwv + 7, 0);
+ *pdata_disp = SVAL(vwv + 8, 0);
+ *pnum_setup = CVAL(vwv + 9, 0);
+ if (expected_num_setup < (*pnum_setup)) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ *psetup = vwv + 10;
+
+ break;
+ case SMBnttrans:
+ if (wct < 18) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ expected_num_setup = wct - 18;
+ *ptotal_param = IVAL(vwv, 3);
+ *ptotal_data = IVAL(vwv, 7);
+ *pnum_param = IVAL(vwv, 11);
+ param_ofs = IVAL(vwv, 15);
+ *pparam_disp = IVAL(vwv, 19);
+ *pnum_data = IVAL(vwv, 23);
+ data_ofs = IVAL(vwv, 27);
+ *pdata_disp = IVAL(vwv, 31);
+ *pnum_setup = CVAL(vwv, 35);
+ if (expected_num_setup < (*pnum_setup)) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ *psetup = vwv + 18;
+ break;
+
+ default:
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ /*
+ * Check for buffer overflows. data_ofs needs to be checked against
+ * the incoming buffer length, data_disp against the total
+ * length. Likewise for param_ofs/param_disp.
+ */
+
+ if (smb_buffer_oob(bytes_end, param_ofs, *pnum_param)
+ || smb_buffer_oob(*ptotal_param, *pparam_disp, *pnum_param)
+ || smb_buffer_oob(bytes_end, data_ofs, *pnum_data)
+ || smb_buffer_oob(*ptotal_data, *pdata_disp, *pnum_data)) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ *pparam = (uint8_t *)inhdr + param_ofs;
+ *pdata = (uint8_t *)inhdr + data_ofs;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS smb1cli_trans_pull_blob(TALLOC_CTX *mem_ctx,
+ struct trans_recvblob *blob,
+ uint32_t total, uint32_t thistime,
+ uint8_t *buf, uint32_t displacement)
+{
+ if (blob->data == NULL) {
+ if (total > blob->max) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ blob->total = total;
+ blob->data = talloc_array(mem_ctx, uint8_t, total);
+ if (blob->data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (total > blob->total) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ if (thistime) {
+ memcpy(blob->data + displacement, buf, thistime);
+ blob->received += thistime;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static void smb1cli_trans_format(struct smb1cli_trans_state *state,
+ uint8_t *pwct,
+ int *piov_count)
+{
+ uint8_t wct = 0;
+ struct iovec *iov = state->iov;
+ uint8_t *pad = state->pad;
+ uint16_t *vwv = state->vwv;
+ uint32_t param_offset;
+ uint32_t this_param = 0;
+ uint32_t param_pad;
+ uint32_t data_offset;
+ uint32_t this_data = 0;
+ uint32_t data_pad;
+ uint32_t useable_space;
+ uint8_t cmd;
+ uint32_t max_trans = smb1cli_conn_max_xmit(state->conn);
+
+ cmd = state->cmd;
+
+ if ((state->param_sent != 0) || (state->data_sent != 0)) {
+ /* The secondary commands are one after the primary ones */
+ cmd += 1;
+ }
+
+ param_offset = MIN_SMB_SIZE;
+
+ switch (cmd) {
+ case SMBtrans:
+ if (smbXcli_conn_use_unicode(state->conn)) {
+ pad[0] = 0;
+ iov[0].iov_base = (void *)pad;
+ iov[0].iov_len = 1;
+ param_offset += 1;
+ iov += 1;
+ }
+ iov[0].iov_base = (void *)state->pipe_name_conv;
+ iov[0].iov_len = state->pipe_name_conv_len;
+ wct = 14 + state->num_setup;
+ param_offset += iov[0].iov_len;
+ iov += 1;
+ break;
+ case SMBtrans2:
+ pad[0] = 0;
+ pad[1] = 'D'; /* Copy this from "old" 3.0 behaviour */
+ pad[2] = ' ';
+ iov[0].iov_base = (void *)pad;
+ iov[0].iov_len = 3;
+ wct = 14 + state->num_setup;
+ param_offset += 3;
+ iov += 1;
+ break;
+ case SMBtranss:
+ wct = 8;
+ break;
+ case SMBtranss2:
+ wct = 9;
+ break;
+ case SMBnttrans:
+ wct = 19 + state->num_setup;
+ break;
+ case SMBnttranss:
+ wct = 18;
+ break;
+ }
+
+ param_offset += wct * sizeof(uint16_t);
+ useable_space = max_trans - param_offset;
+
+ param_pad = param_offset % 4;
+ if (param_pad > 0) {
+ param_pad = MIN(param_pad, useable_space);
+ iov[0].iov_base = (void *)state->zero_pad;
+ iov[0].iov_len = param_pad;
+ iov += 1;
+ param_offset += param_pad;
+ }
+ useable_space = max_trans - param_offset;
+
+ if (state->param_sent < state->num_param) {
+ this_param = MIN(state->num_param - state->param_sent,
+ useable_space);
+ iov[0].iov_base = (void *)(state->param + state->param_sent);
+ iov[0].iov_len = this_param;
+ iov += 1;
+ }
+
+ data_offset = param_offset + this_param;
+ useable_space = max_trans - data_offset;
+
+ data_pad = data_offset % 4;
+ if (data_pad > 0) {
+ data_pad = MIN(data_pad, useable_space);
+ iov[0].iov_base = (void *)state->zero_pad;
+ iov[0].iov_len = data_pad;
+ iov += 1;
+ data_offset += data_pad;
+ }
+ useable_space = max_trans - data_offset;
+
+ if (state->data_sent < state->num_data) {
+ this_data = MIN(state->num_data - state->data_sent,
+ useable_space);
+ iov[0].iov_base = (void *)(state->data + state->data_sent);
+ iov[0].iov_len = this_data;
+ iov += 1;
+ }
+
+ DEBUG(10, ("num_setup=%u, max_setup=%u, "
+ "param_total=%u, this_param=%u, max_param=%u, "
+ "data_total=%u, this_data=%u, max_data=%u, "
+ "param_offset=%u, param_pad=%u, param_disp=%u, "
+ "data_offset=%u, data_pad=%u, data_disp=%u\n",
+ (unsigned)state->num_setup, (unsigned)state->max_setup,
+ (unsigned)state->num_param, (unsigned)this_param,
+ (unsigned)state->rparam.max,
+ (unsigned)state->num_data, (unsigned)this_data,
+ (unsigned)state->rdata.max,
+ (unsigned)param_offset, (unsigned)param_pad,
+ (unsigned)state->param_sent,
+ (unsigned)data_offset, (unsigned)data_pad,
+ (unsigned)state->data_sent));
+
+ switch (cmd) {
+ case SMBtrans:
+ case SMBtrans2:
+ SSVAL(vwv + 0, 0, state->num_param);
+ SSVAL(vwv + 1, 0, state->num_data);
+ SSVAL(vwv + 2, 0, state->rparam.max);
+ SSVAL(vwv + 3, 0, state->rdata.max);
+ SCVAL(vwv + 4, 0, state->max_setup);
+ SCVAL(vwv + 4, 1, 0); /* reserved */
+ SSVAL(vwv + 5, 0, state->flags);
+ SIVAL(vwv + 6, 0, 0); /* timeout */
+ SSVAL(vwv + 8, 0, 0); /* reserved */
+ SSVAL(vwv + 9, 0, this_param);
+ SSVAL(vwv +10, 0, param_offset);
+ SSVAL(vwv +11, 0, this_data);
+ SSVAL(vwv +12, 0, data_offset);
+ SCVAL(vwv +13, 0, state->num_setup);
+ SCVAL(vwv +13, 1, 0); /* reserved */
+ if (state->num_setup > 0) {
+ memcpy(vwv + 14, state->setup,
+ sizeof(uint16_t) * state->num_setup);
+ }
+ break;
+ case SMBtranss:
+ case SMBtranss2:
+ SSVAL(vwv + 0, 0, state->num_param);
+ SSVAL(vwv + 1, 0, state->num_data);
+ SSVAL(vwv + 2, 0, this_param);
+ SSVAL(vwv + 3, 0, param_offset);
+ SSVAL(vwv + 4, 0, state->param_sent);
+ SSVAL(vwv + 5, 0, this_data);
+ SSVAL(vwv + 6, 0, data_offset);
+ SSVAL(vwv + 7, 0, state->data_sent);
+ if (cmd == SMBtranss2) {
+ SSVAL(vwv + 8, 0, state->fid);
+ }
+ break;
+ case SMBnttrans:
+ SCVAL(vwv + 0, 0, state->max_setup);
+ SSVAL(vwv + 0, 1, 0); /* reserved */
+ SIVAL(vwv + 1, 1, state->num_param);
+ SIVAL(vwv + 3, 1, state->num_data);
+ SIVAL(vwv + 5, 1, state->rparam.max);
+ SIVAL(vwv + 7, 1, state->rdata.max);
+ SIVAL(vwv + 9, 1, this_param);
+ SIVAL(vwv +11, 1, param_offset);
+ SIVAL(vwv +13, 1, this_data);
+ SIVAL(vwv +15, 1, data_offset);
+ SCVAL(vwv +17, 1, state->num_setup);
+ SSVAL(vwv +18, 0, state->function);
+ memcpy(vwv + 19, state->setup,
+ sizeof(uint16_t) * state->num_setup);
+ break;
+ case SMBnttranss:
+ SSVAL(vwv + 0, 0, 0); /* reserved */
+ SCVAL(vwv + 1, 0, 0); /* reserved */
+ SIVAL(vwv + 1, 1, state->num_param);
+ SIVAL(vwv + 3, 1, state->num_data);
+ SIVAL(vwv + 5, 1, this_param);
+ SIVAL(vwv + 7, 1, param_offset);
+ SIVAL(vwv + 9, 1, state->param_sent);
+ SIVAL(vwv +11, 1, this_data);
+ SIVAL(vwv +13, 1, data_offset);
+ SIVAL(vwv +15, 1, state->data_sent);
+ SCVAL(vwv +17, 1, 0); /* reserved */
+ break;
+ }
+
+ state->param_sent += this_param;
+ state->data_sent += this_data;
+
+ *pwct = wct;
+ *piov_count = iov - state->iov;
+}
+
+static bool smb1cli_trans_cancel(struct tevent_req *req);
+static void smb1cli_trans_done(struct tevent_req *subreq);
+
+struct tevent_req *smb1cli_trans_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct smbXcli_conn *conn, uint8_t cmd,
+ uint8_t additional_flags, uint8_t clear_flags,
+ uint16_t additional_flags2, uint16_t clear_flags2,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const char *pipe_name, uint16_t fid, uint16_t function, int flags,
+ uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
+ uint8_t *param, uint32_t num_param, uint32_t max_param,
+ uint8_t *data, uint32_t num_data, uint32_t max_data)
+{
+ struct tevent_req *req, *subreq;
+ struct smb1cli_trans_state *state;
+ int iov_count;
+ uint8_t wct;
+ NTSTATUS status;
+ charset_t charset;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb1cli_trans_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if ((cmd == SMBtrans) || (cmd == SMBtrans2)) {
+ if ((num_param > 0xffff) || (max_param > 0xffff)
+ || (num_data > 0xffff) || (max_data > 0xffff)) {
+ DEBUG(3, ("Attempt to send invalid trans2 request "
+ "(setup %u, params %u/%u, data %u/%u)\n",
+ (unsigned)num_setup,
+ (unsigned)num_param, (unsigned)max_param,
+ (unsigned)num_data, (unsigned)max_data));
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+ }
+
+ /*
+ * The largest wct will be for nttrans (19+num_setup). Make sure we
+ * don't overflow state->vwv in smb1cli_trans_format.
+ */
+
+ if ((num_setup + 19) > ARRAY_SIZE(state->vwv)) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ state->conn = conn;
+ state->ev = ev;
+ state->cmd = cmd;
+ state->additional_flags = additional_flags;
+ state->clear_flags = clear_flags;
+ state->additional_flags2 = additional_flags2;
+ state->clear_flags2 = clear_flags2;
+ state->timeout_msec = timeout_msec;
+ state->flags = flags;
+ state->num_rsetup = 0;
+ state->rsetup = NULL;
+ state->pid = pid;
+ state->tcon = tcon;
+ state->session = session;
+ ZERO_STRUCT(state->rparam);
+ ZERO_STRUCT(state->rdata);
+
+ if (smbXcli_conn_use_unicode(conn)) {
+ charset = CH_UTF16LE;
+ } else {
+ charset = CH_DOS;
+ }
+
+ if ((pipe_name != NULL)
+ && (!convert_string_talloc(state, CH_UNIX, charset,
+ pipe_name, strlen(pipe_name) + 1,
+ &state->pipe_name_conv,
+ &state->pipe_name_conv_len))) {
+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+ return tevent_req_post(req, ev);
+ }
+ state->fid = fid; /* trans2 */
+ state->function = function; /* nttrans */
+
+ state->setup = setup;
+ state->num_setup = num_setup;
+ state->max_setup = max_setup;
+
+ state->param = param;
+ state->num_param = num_param;
+ state->param_sent = 0;
+ state->rparam.max = max_param;
+
+ state->data = data;
+ state->num_data = num_data;
+ state->data_sent = 0;
+ state->rdata.max = max_data;
+
+ smb1cli_trans_format(state, &wct, &iov_count);
+
+ subreq = smb1cli_req_create(state, ev, conn, cmd,
+ state->additional_flags,
+ state->clear_flags,
+ state->additional_flags2,
+ state->clear_flags2,
+ state->timeout_msec,
+ state->pid,
+ state->tcon,
+ state->session,
+ wct, state->vwv,
+ iov_count, state->iov);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ status = smb1cli_req_chain_submit(&subreq, 1);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, state->ev);
+ }
+ tevent_req_set_callback(subreq, smb1cli_trans_done, req);
+
+ /*
+ * Now get the MID of the primary request
+ * and mark it as persistent. This means
+ * we will able to send and receive multiple
+ * SMB pdus using this MID in both directions
+ * (including correct SMB signing).
+ */
+ state->mid = smb1cli_req_mid(subreq);
+ smb1cli_req_set_mid(subreq, state->mid);
+ state->primary_subreq = subreq;
+ talloc_set_destructor(state, smb1cli_trans_state_destructor);
+
+ tevent_req_set_cancel_fn(req, smb1cli_trans_cancel);
+
+ return req;
+}
+
+static bool smb1cli_trans_cancel(struct tevent_req *req)
+{
+ struct smb1cli_trans_state *state =
+ tevent_req_data(req,
+ struct smb1cli_trans_state);
+
+ if (state->primary_subreq == NULL) {
+ return false;
+ }
+
+ return tevent_req_cancel(state->primary_subreq);
+}
+
+static void smb1cli_trans_done2(struct tevent_req *subreq);
+
+static void smb1cli_trans_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb1cli_trans_state *state =
+ tevent_req_data(req,
+ struct smb1cli_trans_state);
+ NTSTATUS status;
+ bool sent_all;
+ struct iovec *recv_iov = NULL;
+ uint8_t *inhdr;
+ uint8_t wct;
+ uint16_t *vwv;
+ uint32_t vwv_ofs;
+ uint32_t num_bytes;
+ uint8_t *bytes;
+ uint32_t bytes_ofs;
+ uint8_t num_setup = 0;
+ uint16_t *setup = NULL;
+ uint32_t total_param = 0;
+ uint32_t num_param = 0;
+ uint32_t param_disp = 0;
+ uint32_t total_data = 0;
+ uint32_t num_data = 0;
+ uint32_t data_disp = 0;
+ uint8_t *param = NULL;
+ uint8_t *data = NULL;
+
+ status = smb1cli_req_recv(subreq, state,
+ &recv_iov,
+ &inhdr,
+ &wct,
+ &vwv,
+ &vwv_ofs,
+ &num_bytes,
+ &bytes,
+ &bytes_ofs,
+ NULL, /* pinbuf */
+ NULL, 0); /* expected */
+ /*
+ * Do not TALLOC_FREE(subreq) here, we might receive more than
+ * one response for the same mid.
+ */
+
+ /*
+ * We can receive something like STATUS_MORE_ENTRIES, so don't use
+ * !NT_STATUS_IS_OK(status) here.
+ */
+
+ if (NT_STATUS_IS_ERR(status)) {
+ goto fail;
+ }
+
+ if (recv_iov == NULL) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto fail;
+ }
+ state->status = status;
+
+ sent_all = ((state->param_sent == state->num_param)
+ && (state->data_sent == state->num_data));
+
+ status = smb1cli_pull_trans(
+ inhdr, wct, vwv, vwv_ofs,
+ num_bytes, bytes, bytes_ofs,
+ state->cmd, !sent_all, &num_setup, &setup,
+ &total_param, &num_param, &param_disp, &param,
+ &total_data, &num_data, &data_disp, &data);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ if (!sent_all) {
+ int iov_count;
+ struct tevent_req *subreq2;
+
+ smb1cli_trans_format(state, &wct, &iov_count);
+
+ subreq2 = smb1cli_req_create(state, state->ev, state->conn,
+ state->cmd + 1,
+ state->additional_flags,
+ state->clear_flags,
+ state->additional_flags2,
+ state->clear_flags2,
+ state->timeout_msec,
+ state->pid,
+ state->tcon,
+ state->session,
+ wct, state->vwv,
+ iov_count, state->iov);
+ if (tevent_req_nomem(subreq2, req)) {
+ return;
+ }
+ smb1cli_req_set_mid(subreq2, state->mid);
+
+ status = smb1cli_req_chain_submit(&subreq2, 1);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+ tevent_req_set_callback(subreq2, smb1cli_trans_done2, req);
+
+ return;
+ }
+
+ status = smb1cli_trans_pull_blob(
+ state, &state->rparam, total_param, num_param, param,
+ param_disp);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status)));
+ goto fail;
+ }
+
+ status = smb1cli_trans_pull_blob(
+ state, &state->rdata, total_data, num_data, data,
+ data_disp);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status)));
+ goto fail;
+ }
+
+ if ((state->rparam.total == state->rparam.received)
+ && (state->rdata.total == state->rdata.received)) {
+ state->recv_flags2 = SVAL(inhdr, HDR_FLG2);
+ smb1cli_trans_cleanup_primary(state);
+ tevent_req_done(req);
+ return;
+ }
+
+ TALLOC_FREE(recv_iov);
+
+ return;
+
+ fail:
+ smb1cli_trans_cleanup_primary(state);
+ tevent_req_nterror(req, status);
+}
+
+static void smb1cli_trans_done2(struct tevent_req *subreq2)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq2,
+ struct tevent_req);
+ struct smb1cli_trans_state *state =
+ tevent_req_data(req,
+ struct smb1cli_trans_state);
+ NTSTATUS status;
+ bool sent_all;
+ uint32_t seqnum;
+
+ /*
+ * First backup the seqnum of the secondary request
+ * and attach it to the primary request.
+ */
+ seqnum = smb1cli_req_seqnum(subreq2);
+ smb1cli_req_set_seqnum(state->primary_subreq, seqnum);
+
+ /* This was a one way request */
+ status = smb1cli_req_recv(subreq2, state,
+ NULL, /* recv_iov */
+ NULL, /* phdr */
+ NULL, /* pwct */
+ NULL, /* pvwv */
+ NULL, /* pvwv_offset */
+ NULL, /* pnum_bytes */
+ NULL, /* pbytes */
+ NULL, /* pbytes_offset */
+ NULL, /* pinbuf */
+ NULL, 0); /* expected */
+ TALLOC_FREE(subreq2);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ sent_all = ((state->param_sent == state->num_param)
+ && (state->data_sent == state->num_data));
+
+ if (!sent_all) {
+ uint8_t wct;
+ int iov_count;
+
+ smb1cli_trans_format(state, &wct, &iov_count);
+
+ subreq2 = smb1cli_req_create(state, state->ev, state->conn,
+ state->cmd + 1,
+ state->additional_flags,
+ state->clear_flags,
+ state->additional_flags2,
+ state->clear_flags2,
+ state->timeout_msec,
+ state->pid,
+ state->tcon,
+ state->session,
+ wct, state->vwv,
+ iov_count, state->iov);
+ if (tevent_req_nomem(subreq2, req)) {
+ return;
+ }
+ smb1cli_req_set_mid(subreq2, state->mid);
+
+ status = smb1cli_req_chain_submit(&subreq2, 1);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+ tevent_req_set_callback(subreq2, smb1cli_trans_done2, req);
+ return;
+ }
+
+ return;
+
+ fail:
+ smb1cli_trans_cleanup_primary(state);
+ tevent_req_nterror(req, status);
+}
+
+NTSTATUS smb1cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ uint16_t *recv_flags2,
+ uint16_t **setup, uint8_t min_setup,
+ uint8_t *num_setup,
+ uint8_t **param, uint32_t min_param,
+ uint32_t *num_param,
+ uint8_t **data, uint32_t min_data,
+ uint32_t *num_data)
+{
+ struct smb1cli_trans_state *state =
+ tevent_req_data(req,
+ struct smb1cli_trans_state);
+ NTSTATUS status;
+
+ smb1cli_trans_cleanup_primary(state);
+
+ if (tevent_req_is_nterror(req, &status)) {
+ if (!NT_STATUS_IS_ERR(status)) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ tevent_req_received(req);
+ return status;
+ }
+
+ if ((state->num_rsetup < min_setup)
+ || (state->rparam.total < min_param)
+ || (state->rdata.total < min_data)) {
+ tevent_req_received(req);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ if (recv_flags2 != NULL) {
+ *recv_flags2 = state->recv_flags2;
+ }
+
+ if (setup != NULL) {
+ *setup = talloc_move(mem_ctx, &state->rsetup);
+ *num_setup = state->num_rsetup;
+ } else {
+ TALLOC_FREE(state->rsetup);
+ }
+
+ if (param != NULL) {
+ *param = talloc_move(mem_ctx, &state->rparam.data);
+ *num_param = state->rparam.total;
+ } else {
+ TALLOC_FREE(state->rparam.data);
+ }
+
+ if (data != NULL) {
+ *data = talloc_move(mem_ctx, &state->rdata.data);
+ *num_data = state->rdata.total;
+ } else {
+ TALLOC_FREE(state->rdata.data);
+ }
+
+ status = state->status;
+ tevent_req_received(req);
+ return status;
+}
+
+NTSTATUS smb1cli_trans(TALLOC_CTX *mem_ctx, struct smbXcli_conn *conn,
+ uint8_t trans_cmd,
+ uint8_t additional_flags, uint8_t clear_flags,
+ uint16_t additional_flags2, uint16_t clear_flags2,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const char *pipe_name, uint16_t fid, uint16_t function,
+ int flags,
+ uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
+ uint8_t *param, uint32_t num_param, uint32_t max_param,
+ uint8_t *data, uint32_t num_data, uint32_t max_data,
+ uint16_t *recv_flags2,
+ uint16_t **rsetup, uint8_t min_rsetup, uint8_t *num_rsetup,
+ uint8_t **rparam, uint32_t min_rparam, uint32_t *num_rparam,
+ uint8_t **rdata, uint32_t min_rdata, uint32_t *num_rdata)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER_MIX;
+ goto fail;
+ }
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+
+ req = smb1cli_trans_send(frame, ev, conn, trans_cmd,
+ additional_flags, clear_flags,
+ additional_flags2, clear_flags2,
+ timeout_msec,
+ pid, tcon, session,
+ pipe_name, fid, function, flags,
+ setup, num_setup, max_setup,
+ param, num_param, max_param,
+ data, num_data, max_data);
+ if (req == NULL) {
+ goto fail;
+ }
+
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+
+ status = smb1cli_trans_recv(req, mem_ctx, recv_flags2,
+ rsetup, min_rsetup, num_rsetup,
+ rparam, min_rparam, num_rparam,
+ rdata, min_rdata, num_rdata);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb1cli_write.c b/libcli/smb/smb1cli_write.c
new file mode 100644
index 0000000..d5bc57a
--- /dev/null
+++ b/libcli/smb/smb1cli_write.c
@@ -0,0 +1,284 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Gregor Beck 2013
+
+ 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb1cli_writex_state {
+ uint32_t size;
+ uint16_t vwv[14];
+ uint32_t written;
+ uint16_t available;
+ uint8_t pad;
+ struct iovec iov[2];
+};
+
+static void smb1cli_writex_done(struct tevent_req *subreq);
+
+/**
+ * Send an asynchrounus SMB_COM_WRITE_ANDX request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee441954.aspx">MS-CIFS 2.2.4.43.1</a>
+ * @see smb1cli_writex_recv(), smb1cli_writex()
+ *
+ * @param[in] mem_ctx The memory context for the result.
+ * @param[in] ev The event context to work on.
+ * @param[in] conn The smb connection.
+ * @param[in] timeout_msec If positive a timeout for the request.
+ * @param[in] pid The process identifier
+ * @param[in] tcon The smb tree connect.
+ * @param[in] session The smb session.
+ * @param[in] fnum The file id of the file the data should be written to.
+ * @param[in] mode A bitfield containing the write mode.
+ * @param[in] buf The data to be written to the file.
+ * @param[in] offset The offset in bytes from the begin of file where to write.
+ * @param[in] size The number of bytes to write.
+ *
+ * @return a tevent_req or NULL
+ */
+struct tevent_req *smb1cli_writex_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint16_t fnum,
+ uint16_t mode,
+ const uint8_t *buf,
+ uint64_t offset,
+ uint32_t size)
+{
+ struct tevent_req *req, *subreq;
+ struct smb1cli_writex_state *state;
+ bool bigoffset = ((smb1cli_conn_capabilities(conn) & CAP_LARGE_FILES) != 0);
+ uint8_t wct = bigoffset ? 14 : 12;
+ uint16_t *vwv;
+ uint16_t data_offset =
+ smb1cli_req_wct_ofs(NULL, 0) /* reqs_before */
+ + 1 /* the wct field */
+ + wct * 2 /* vwv */
+ + 2 /* num_bytes field */
+ + 1; /* pad */
+ NTSTATUS status;
+
+ req = tevent_req_create(mem_ctx, &state, struct smb1cli_writex_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->size = size;
+
+ vwv = state->vwv;
+
+ SCVAL(vwv+0, 0, 0xFF);
+ SCVAL(vwv+0, 1, 0);
+ SSVAL(vwv+1, 0, 0);
+ SSVAL(vwv+2, 0, fnum);
+ SIVAL(vwv+3, 0, offset);
+ SIVAL(vwv+5, 0, 0);
+ SSVAL(vwv+7, 0, mode);
+ SSVAL(vwv+8, 0, 0);
+ SSVAL(vwv+9, 0, (state->size>>16));
+ SSVAL(vwv+10, 0, state->size);
+ SSVAL(vwv+11, 0, data_offset);
+
+ if (bigoffset) {
+ SIVAL(vwv+12, 0, (((uint64_t)offset)>>32) & 0xffffffff);
+ }
+
+ state->pad = 0;
+ state->iov[0].iov_base = (void *)&state->pad;
+ state->iov[0].iov_len = 1;
+ state->iov[1].iov_base = discard_const_p(void, buf);
+ state->iov[1].iov_len = state->size;
+
+ subreq = smb1cli_req_create(state, ev, conn, SMBwriteX,
+ 0, 0, /* *_flags */
+ 0, 0, /* *_flags2 */
+ timeout_msec, pid, tcon, session,
+ wct, vwv,
+ ARRAY_SIZE(state->iov), state->iov);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb1cli_writex_done, req);
+
+ status = smb1cli_req_chain_submit(&subreq, 1);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void smb1cli_writex_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb1cli_writex_state *state = tevent_req_data(
+ req, struct smb1cli_writex_state);
+ struct iovec *recv_iov = NULL;
+ uint8_t wct;
+ uint16_t *vwv;
+ NTSTATUS status;
+ static const struct smb1cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .wct = 0x06
+ },
+ };
+
+ status = smb1cli_req_recv(subreq, state,
+ &recv_iov,
+ NULL, /* phdr */
+ &wct,
+ &vwv,
+ NULL, /* pvwv_offset */
+ NULL, /* num_bytes */
+ NULL, /* bytes */
+ NULL, /* pbytes_offset */
+ NULL, /* inbuf */
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ state->written = SVAL(vwv+2, 0);
+ if (state->size > UINT16_MAX) {
+ /*
+ * It is important that we only set the
+ * high bits only if we asked for a large write.
+ *
+ * OS/2 print shares get this wrong and may send
+ * invalid values.
+ *
+ * See bug #5326.
+ */
+ state->written |= SVAL(vwv+4, 0)<<16;
+ }
+ state->available = SVAL(vwv+3, 0);
+
+ tevent_req_done(req);
+}
+
+/**
+ * Receive the response to an asynchronous SMB_COM_WRITE_ANDX request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee441673.aspx">MS-CIFS:2.2.4.43.2</a>
+ *
+ *
+ * @param[in] req req A tevent request created with smb1cli_writex_send()
+ * @param[out] pwritten The number of bytes written to the file.
+ * @param[out] pavailable Valid if writing to a named pipe or IO device.
+ *
+ * @return NT_STATUS_OK on success.
+ */
+NTSTATUS smb1cli_writex_recv(struct tevent_req *req, uint32_t *pwritten, uint16_t *pavailable)
+{
+ struct smb1cli_writex_state *state = tevent_req_data(
+ req, struct smb1cli_writex_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ if (pwritten != NULL) {
+ *pwritten = state->written;
+ }
+ if (pavailable != NULL) {
+ *pavailable = state->available;
+ }
+ return NT_STATUS_OK;
+}
+
+/**
+ * Send an synchrounus SMB_COM_WRITE_ANDX request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee441848.aspx">MS-CIFS 2.2.4.43</a>
+ * @see smb1cli_writex_send(), smb1cli_writex_recv()
+ *
+ * @param[in] conn The smb connection.
+ * @param[in] timeout_msec If positive a timeout for the request.
+ * @param[in] pid The process identifier
+ * @param[in] tcon The smb tree connect.
+ * @param[in] session The smb session.
+ * @param[in] fnum The file id of the file the data should be written to.
+ * @param[in] mode A bitfield containing the write mode.
+ * @param[in] buf The data to be written to the file.
+ * @param[in] offset The offset in bytes from the begin of file where to write.
+ * @param[in] size The number of bytes to write.
+ * @param[out] pwritten The number of bytes written to the file.
+ * @param[out] pavailable Valid if writing to a named pipe or IO device.
+ *
+ * @return NT_STATUS_OK on success.
+ */
+NTSTATUS smb1cli_writex(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint16_t fnum,
+ uint16_t mode,
+ const uint8_t *buf,
+ uint64_t offset,
+ uint32_t size,
+ uint32_t *pwritten,
+ uint16_t *pavailable)
+{
+ TALLOC_CTX *frame = NULL;
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_OK;
+
+ frame = talloc_stackframe();
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ req = smb1cli_writex_send(frame, ev, conn,
+ timeout_msec,
+ pid, tcon, session,
+ fnum, mode, buf, offset, size);
+ if (req == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto done;
+ }
+
+ status = smb1cli_writex_recv(req, pwritten, pavailable);
+done:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2_constants.h b/libcli/smb/smb2_constants.h
new file mode 100644
index 0000000..a41be63
--- /dev/null
+++ b/libcli/smb/smb2_constants.h
@@ -0,0 +1,317 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 client library header
+
+ Copyright (C) Andrew Tridgell 2005
+
+ 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/>.
+*/
+
+#ifndef __LIBCLI_SMB2_SMB2_CONSTANTS_H__
+#define __LIBCLI_SMB2_SMB2_CONSTANTS_H__
+
+/* offsets into SMB2_TRANSFORM header elements */
+#define SMB2_TF_PROTOCOL_ID 0x00 /* 4 bytes */
+#define SMB2_TF_SIGNATURE 0x04 /* 16 bytes */
+#define SMB2_TF_NONCE 0x14 /* 16 bytes */
+#define SMB2_TF_MSG_SIZE 0x24 /* 4 bytes */
+#define SMB2_TF_RESERVED 0x28 /* 2 bytes */
+#define SMB2_TF_FLAGS 0x2A /* 2 bytes */
+#define SMB2_TF_SESSION_ID 0x2C /* 8 bytes */
+
+#define SMB2_TF_HDR_SIZE 0x34 /* 52 bytes */
+
+#define SMB2_TF_MAGIC 0x424D53FD /* 0xFD 'S' 'M' 'B' */
+
+#define SMB2_TF_FLAGS_ENCRYPTED 0x0001
+
+/* offsets into header elements for a sync SMB2 request */
+#define SMB2_HDR_PROTOCOL_ID 0x00
+#define SMB2_HDR_LENGTH 0x04
+#define SMB2_HDR_CREDIT_CHARGE 0x06
+#define SMB2_HDR_EPOCH SMB2_HDR_CREDIT_CHARGE /* TODO: remove this */
+#define SMB2_HDR_STATUS 0x08
+#define SMB2_HDR_CHANNEL_SEQUENCE SMB2_HDR_STATUS /* in requests */
+#define SMB2_HDR_OPCODE 0x0c
+#define SMB2_HDR_CREDIT 0x0e
+#define SMB2_HDR_FLAGS 0x10
+#define SMB2_HDR_NEXT_COMMAND 0x14
+#define SMB2_HDR_MESSAGE_ID 0x18
+#define SMB2_HDR_PID 0x20
+#define SMB2_HDR_TID 0x24
+#define SMB2_HDR_SESSION_ID 0x28
+#define SMB2_HDR_SIGNATURE 0x30 /* 16 bytes */
+#define SMB2_HDR_BODY 0x40
+
+/* offsets into header elements for an async SMB2 request */
+#define SMB2_HDR_ASYNC_ID 0x20
+
+/* header flags */
+#define SMB2_HDR_FLAG_REDIRECT 0x01
+#define SMB2_HDR_FLAG_ASYNC 0x02
+#define SMB2_HDR_FLAG_CHAINED 0x04
+#define SMB2_HDR_FLAG_SIGNED 0x08
+#define SMB2_HDR_FLAG_PRIORITY_MASK 0x70
+#define SMB2_HDR_FLAG_DFS 0x10000000
+#define SMB2_HDR_FLAG_REPLAY_OPERATION 0x20000000
+
+#define SMB2_PRIORITY_MASK_TO_VALUE(__m) (((__m) & SMB2_HDR_FLAG_PRIORITY_MASK) >> 4)
+#define SMB2_PRIORITY_VALUE_TO_MASK(__v) (((__v) << 4) & SMB2_HDR_FLAG_PRIORITY_MASK)
+
+/* SMB2 opcodes */
+#define SMB2_OP_NEGPROT 0x00
+#define SMB2_OP_SESSSETUP 0x01
+#define SMB2_OP_LOGOFF 0x02
+#define SMB2_OP_TCON 0x03
+#define SMB2_OP_TDIS 0x04
+#define SMB2_OP_CREATE 0x05
+#define SMB2_OP_CLOSE 0x06
+#define SMB2_OP_FLUSH 0x07
+#define SMB2_OP_READ 0x08
+#define SMB2_OP_WRITE 0x09
+#define SMB2_OP_LOCK 0x0a
+#define SMB2_OP_IOCTL 0x0b
+#define SMB2_OP_CANCEL 0x0c
+#define SMB2_OP_KEEPALIVE 0x0d
+#define SMB2_OP_QUERY_DIRECTORY 0x0e
+#define SMB2_OP_NOTIFY 0x0f
+#define SMB2_OP_GETINFO 0x10
+#define SMB2_OP_SETINFO 0x11
+#define SMB2_OP_BREAK 0x12
+
+#define SMB2_MAGIC 0x424D53FE /* 0xFE 'S' 'M' 'B' */
+
+/* SMB2 negotiate dialects */
+#define SMB2_DIALECT_REVISION_000 0x0000 /* early beta dialect */
+#define SMB2_DIALECT_REVISION_202 0x0202
+#define SMB2_DIALECT_REVISION_210 0x0210
+#define SMB2_DIALECT_REVISION_222 0x0222
+#define SMB2_DIALECT_REVISION_224 0x0224
+#define SMB3_DIALECT_REVISION_300 0x0300
+#define SMB3_DIALECT_REVISION_302 0x0302
+#define SMB3_DIALECT_REVISION_310 0x0310
+#define SMB3_DIALECT_REVISION_311 0x0311
+#define SMB2_DIALECT_REVISION_2FF 0x02FF
+
+/* SMB2 negotiate security_mode */
+#define SMB2_NEGOTIATE_SIGNING_ENABLED 0x01
+#define SMB2_NEGOTIATE_SIGNING_REQUIRED 0x02
+
+/* SMB2 global capabilities */
+#define SMB2_CAP_DFS 0x00000001
+#define SMB2_CAP_LEASING 0x00000002 /* only in dialect >= 0x210 */
+#define SMB2_CAP_LARGE_MTU 0x00000004 /* only in dialect >= 0x210 */
+#define SMB2_CAP_MULTI_CHANNEL 0x00000008 /* only in dialect >= 0x222 */
+#define SMB2_CAP_PERSISTENT_HANDLES 0x00000010 /* only in dialect >= 0x222 */
+#define SMB2_CAP_DIRECTORY_LEASING 0x00000020 /* only in dialect >= 0x222 */
+#define SMB2_CAP_ENCRYPTION 0x00000040 /* only in dialect >= 0x222 */
+
+/* so we can spot new caps as added */
+#define SMB2_CAP_ALL (\
+ SMB2_CAP_DFS | \
+ SMB2_CAP_LEASING | \
+ SMB2_CAP_LARGE_MTU | \
+ SMB2_CAP_MULTI_CHANNEL | \
+ SMB2_CAP_PERSISTENT_HANDLES | \
+ SMB2_CAP_DIRECTORY_LEASING | \
+ SMB2_CAP_ENCRYPTION)
+
+/* Types of SMB2 Negotiate Contexts - only in dialect >= 0x310 */
+#define SMB2_PREAUTH_INTEGRITY_CAPABILITIES 0x0001
+#define SMB2_ENCRYPTION_CAPABILITIES 0x0002
+#define SMB2_COMPRESSION_CAPABILITIES 0x0003
+#define SMB2_NETNAME_NEGOTIATE_CONTEXT_ID 0x0005
+#define SMB2_TRANSPORT_CAPABILITIES 0x0006
+#define SMB2_RDMA_TRANSFORM_CAPABILITIES 0x0007
+#define SMB2_SIGNING_CAPABILITIES 0x0008
+#define SMB2_POSIX_EXTENSIONS_AVAILABLE 0x0100
+
+/* Values for the SMB2_PREAUTH_INTEGRITY_CAPABILITIES Context (>= 0x310) */
+#define SMB2_PREAUTH_INTEGRITY_SHA512 0x0001
+
+/* Values for the SMB2_SIGNING_CAPABILITIES Context (>= 0x311) */
+#define SMB2_SIGNING_INVALID_ALGO 0xffff /* only used internally */
+#define SMB2_SIGNING_MD5_SMB1 0xfffe /* internally for SMB1 */
+#define SMB2_SIGNING_HMAC_SHA256 0x0000 /* default <= 0x210 */
+#define SMB2_SIGNING_AES128_CMAC 0x0001 /* default >= 0x224 */
+#define SMB2_SIGNING_AES128_GMAC 0x0002 /* only in dialect >= 0x311 */
+
+/* Values for the SMB2_ENCRYPTION_CAPABILITIES Context (>= 0x311) */
+#define SMB2_ENCRYPTION_INVALID_ALGO 0xffff /* only used internally */
+#define SMB2_ENCRYPTION_NONE 0x0000 /* only used internally */
+#define SMB2_ENCRYPTION_AES128_CCM 0x0001 /* only in dialect >= 0x224 */
+#define SMB2_ENCRYPTION_AES128_GCM 0x0002 /* only in dialect >= 0x311 */
+#define SMB2_ENCRYPTION_AES256_CCM 0x0003 /* only in dialect >= 0x311 */
+#define SMB2_ENCRYPTION_AES256_GCM 0x0004 /* only in dialect >= 0x311 */
+#define SMB2_NONCE_HIGH_MAX(nonce_len_bytes) ((uint64_t)(\
+ ((nonce_len_bytes) >= 16) ? UINT64_MAX : \
+ ((nonce_len_bytes) <= 8) ? 0 : \
+ (((uint64_t)1 << (((nonce_len_bytes) - 8)*8)) - 1) \
+ ))
+
+/* Values for the SMB2_TRANSPORT_CAPABILITIES Context (>= 0x311) */
+#define SMB2_ACCEPT_TRANSPORT_LEVEL_SECURITY 0x0001
+
+/* Values for the SMB2_RDMA_TRANSFORM_CAPABILITIES Context (>= 0x311) */
+#define SMB2_RDMA_TRANSFORM_NONE 0x0000
+#define SMB2_RDMA_TRANSFORM_ENCRYPTION 0x0001
+#define SMB2_RDMA_TRANSFORM_SIGNING 0x0002
+
+/* SMB2 session (request) flags */
+#define SMB2_SESSION_FLAG_BINDING 0x01
+/* SMB2_SESSION_FLAG_ENCRYPT_DATA 0x04 only in dialect >= 0x310 */
+
+/* SMB2 session (response) flags */
+#define SMB2_SESSION_FLAG_IS_GUEST 0x0001
+#define SMB2_SESSION_FLAG_IS_NULL 0x0002
+#define SMB2_SESSION_FLAG_ENCRYPT_DATA 0x0004 /* in dialect >= 0x224 */
+
+/* SMB2 tree connect (request) flags */
+#define SMB2_SHAREFLAG_CLUSTER_RECONNECT 0x0001 /* only in dialect >= 0x310 */
+
+/* SMB2 sharetype flags */
+#define SMB2_SHARE_TYPE_DISK 0x1
+#define SMB2_SHARE_TYPE_PIPE 0x2
+#define SMB2_SHARE_TYPE_PRINT 0x3
+
+/* SMB2 share flags */
+#define SMB2_SHAREFLAG_MANUAL_CACHING 0x0000
+#define SMB2_SHAREFLAG_AUTO_CACHING 0x0010
+#define SMB2_SHAREFLAG_VDO_CACHING 0x0020
+#define SMB2_SHAREFLAG_NO_CACHING 0x0030
+#define SMB2_SHAREFLAG_DFS 0x0001
+#define SMB2_SHAREFLAG_DFS_ROOT 0x0002
+#define SMB2_SHAREFLAG_RESTRICT_EXCLUSIVE_OPENS 0x0100
+#define SMB2_SHAREFLAG_FORCE_SHARED_DELETE 0x0200
+#define SMB2_SHAREFLAG_ALLOW_NAMESPACE_CACHING 0x0400
+#define SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM 0x0800
+#define SMB2_SHAREFLAG_FORCE_LEVELII_OPLOCKS 0x1000
+#define SMB2_SHAREFLAG_ENABLE_HASH_V1 0x2000
+#define SMB2_SHAREFLAG_ENABLE_HASH_V2 0x4000
+#define SMB2_SHAREFLAG_ENCRYPT_DATA 0x8000
+#define SMB2_SHAREFLAG_IDENTITY_REMOTING 0x00040000
+#define SMB2_SHAREFLAG_COMPRESS_DATA 0x00100000
+#define SMB2_SHAREFLAG_ISOLATED_TRANSPORT 0x00200000
+
+/* SMB2 share capabilities */
+#define SMB2_SHARE_CAP_DFS 0x8
+#define SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY 0x10 /* in dialect >= 0x222 */
+#define SMB2_SHARE_CAP_SCALEOUT 0x20 /* in dialect >= 0x222 */
+#define SMB2_SHARE_CAP_CLUSTER 0x40 /* in dialect >= 0x222 */
+#define SMB2_SHARE_CAP_ASYMMETRIC 0x80 /* in dialect >= 0x302 */
+
+/* SMB2 create security flags */
+#define SMB2_SECURITY_DYNAMIC_TRACKING 0x01
+#define SMB2_SECURITY_EFFECTIVE_ONLY 0x02
+
+/* SMB2 lock flags */
+#define SMB2_LOCK_FLAG_NONE 0x00000000
+#define SMB2_LOCK_FLAG_SHARED 0x00000001
+#define SMB2_LOCK_FLAG_EXCLUSIVE 0x00000002
+#define SMB2_LOCK_FLAG_UNLOCK 0x00000004
+#define SMB2_LOCK_FLAG_FAIL_IMMEDIATELY 0x00000010
+#define SMB2_LOCK_FLAG_ALL_MASK 0x00000017
+
+/* SMB2 requested oplock levels */
+#define SMB2_OPLOCK_LEVEL_NONE 0x00
+#define SMB2_OPLOCK_LEVEL_II 0x01
+#define SMB2_OPLOCK_LEVEL_EXCLUSIVE 0x08
+#define SMB2_OPLOCK_LEVEL_BATCH 0x09
+#define SMB2_OPLOCK_LEVEL_LEASE 0xFF
+
+/* SMB2 lease bits */
+#define SMB2_LEASE_NONE 0x00
+
+/* SMB2 lease flags */
+#define SMB2_LEASE_FLAG_BREAK_IN_PROGRESS 0x00000002
+#define SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET 0x00000004
+
+/* SMB2 lease break flags */
+#define SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED 0x01
+
+/* SMB2 impersonation levels */
+#define SMB2_IMPERSONATION_ANONYMOUS 0x00
+#define SMB2_IMPERSONATION_IDENTIFICATION 0x01
+#define SMB2_IMPERSONATION_IMPERSONATION 0x02
+#define SMB2_IMPERSONATION_DELEGATE 0x03
+
+/* SMB2 create tags */
+#define SMB2_CREATE_TAG_EXTA "ExtA"
+#define SMB2_CREATE_TAG_MXAC "MxAc"
+#define SMB2_CREATE_TAG_SECD "SecD"
+#define SMB2_CREATE_TAG_DHNQ "DHnQ"
+#define SMB2_CREATE_TAG_DHNC "DHnC"
+#define SMB2_CREATE_TAG_ALSI "AlSi"
+#define SMB2_CREATE_TAG_TWRP "TWrp"
+#define SMB2_CREATE_TAG_QFID "QFid"
+#define SMB2_CREATE_TAG_RQLS "RqLs"
+#define SMB2_CREATE_TAG_DH2Q "DH2Q"
+#define SMB2_CREATE_TAG_DH2C "DH2C"
+#define SMB2_CREATE_TAG_AAPL "AAPL"
+#define SMB2_CREATE_TAG_APP_INSTANCE_ID "\x45\xBC\xA6\x6A\xEF\xA7\xF7\x4A\x90\x08\xFA\x46\x2E\x14\x4D\x74"
+#define SVHDX_OPEN_DEVICE_CONTEXT "\x9C\xCB\xCF\x9E\x04\xC1\xE6\x43\x98\x0E\x15\x8D\xA1\xF6\xEC\x83"
+#define SMB2_CREATE_TAG_POSIX "\x93\xAD\x25\x50\x9C\xB4\x11\xE7\xB4\x23\x83\xDE\x96\x8B\xCD\x7C"
+
+/* SMB2 notify flags */
+#define SMB2_WATCH_TREE 0x0001
+
+/* SMB2 Create ignore some more create_options */
+#define SMB2_CREATE_OPTIONS_NOT_SUPPORTED_MASK (NTCREATEX_OPTIONS_TREE_CONNECTION | \
+ NTCREATEX_OPTIONS_OPFILTER)
+
+/*
+ SMB2 uses different level numbers for the same old SMB trans2 search levels
+*/
+#define SMB2_FIND_DIRECTORY_INFO 0x01
+#define SMB2_FIND_FULL_DIRECTORY_INFO 0x02
+#define SMB2_FIND_BOTH_DIRECTORY_INFO 0x03
+#define SMB2_FIND_NAME_INFO 0x0C
+#define SMB2_FIND_ID_BOTH_DIRECTORY_INFO 0x25
+#define SMB2_FIND_ID_FULL_DIRECTORY_INFO 0x26
+
+/* SMB2 UNIX Extensions. */
+#define SMB2_FIND_POSIX_INFORMATION 0x64
+
+/* flags for SMB2 find */
+#define SMB2_CONTINUE_FLAG_RESTART 0x01
+#define SMB2_CONTINUE_FLAG_SINGLE 0x02
+#define SMB2_CONTINUE_FLAG_INDEX 0x04
+#define SMB2_CONTINUE_FLAG_REOPEN 0x10
+
+/* get/setinfo classes, see [MS-SMB2] 2.2.37 and 2.2.39 */
+#define SMB2_0_INFO_FILE 0x01
+#define SMB2_0_INFO_FILESYSTEM 0x02
+#define SMB2_0_INFO_SECURITY 0x03
+#define SMB2_0_INFO_QUOTA 0x04
+
+#define SMB2_CLOSE_FLAGS_FULL_INFORMATION (0x01)
+
+#define SMB2_READFLAG_READ_UNBUFFERED 0x01
+
+#define SMB2_WRITEFLAG_WRITE_THROUGH 0x00000001
+#define SMB2_WRITEFLAG_WRITE_UNBUFFERED 0x00000002
+
+/* 2.2.31 SMB2 IOCTL Request */
+#define SMB2_IOCTL_FLAG_IS_FSCTL 0x00000001
+
+/*
+ * Flags for durable handle v2 requests
+ */
+#define SMB2_DHANDLE_FLAG_PERSISTENT 0x00000002
+
+/* The AES CCM nonce N of 15 - L octets. Where L=4 */
+#define SMB2_AES_128_CCM_NONCE_SIZE 11
+
+#endif
diff --git a/libcli/smb/smb2_create_blob.c b/libcli/smb/smb2_create_blob.c
new file mode 100644
index 0000000..57c7a9d
--- /dev/null
+++ b/libcli/smb/smb2_create_blob.c
@@ -0,0 +1,227 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 Create Context Blob handling
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Stefan Metzmacher 2008-2009
+
+ 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 "../libcli/smb/smb_common.h"
+
+static size_t smb2_create_blob_padding(uint32_t offset, size_t n)
+{
+ if ((offset & (n-1)) == 0) return 0;
+ return n - (offset & (n-1));
+}
+
+/*
+ parse a set of SMB2 create blobs
+*/
+NTSTATUS smb2_create_blob_parse(TALLOC_CTX *mem_ctx, const DATA_BLOB buffer,
+ struct smb2_create_blobs *blobs)
+{
+ const uint8_t *data = buffer.data;
+ uint32_t remaining = buffer.length;
+
+ while (remaining > 0) {
+ uint32_t next;
+ uint32_t name_offset, name_length;
+ uint32_t data_offset;
+ uint32_t data_length;
+ char *tag;
+ DATA_BLOB b;
+ NTSTATUS status;
+
+ if (remaining < 16) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ next = IVAL(data, 0);
+ name_offset = SVAL(data, 4);
+ name_length = SVAL(data, 6);
+#if 0
+ reserved = SVAL(data, 8);
+#endif
+ data_offset = SVAL(data, 10);
+ data_length = IVAL(data, 12);
+
+ if ((next & 0x7) != 0 ||
+ next > remaining ||
+ name_offset != 16 ||
+ name_length < 4 ||
+ name_offset + name_length > remaining ||
+ (data_offset & 0x7) != 0 ||
+ (data_offset && (data_offset < name_offset + name_length)) ||
+ (data_offset > remaining) ||
+ (data_offset + (uint64_t)data_length > remaining)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ tag = talloc_strndup(mem_ctx, (const char *)data + name_offset, name_length);
+ if (tag == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ b = data_blob_const(data+data_offset, data_length);
+ status = smb2_create_blob_add(mem_ctx, blobs, tag, b);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ talloc_free(tag);
+
+ if (next == 0) break;
+
+ remaining -= next;
+ data += next;
+
+ if (remaining < 16) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ add a blob to a smb2_create attribute blob
+*/
+static NTSTATUS smb2_create_blob_push_one(TALLOC_CTX *mem_ctx, DATA_BLOB *buffer,
+ const struct smb2_create_blob *blob,
+ bool last)
+{
+ uint32_t ofs = buffer->length;
+ size_t tag_length = strlen(blob->tag);
+ size_t blob_offset = 0;
+ size_t blob_pad = 0;
+ size_t next_offset = 0;
+ size_t next_pad = 0;
+ bool ok;
+
+ blob_offset = 0x10 + tag_length;
+ blob_pad = smb2_create_blob_padding(blob_offset, 8);
+ next_offset = blob_offset + blob_pad + blob->data.length;
+ if (!last) {
+ next_pad = smb2_create_blob_padding(next_offset, 8);
+ }
+
+ ok = data_blob_realloc(mem_ctx, buffer,
+ buffer->length + next_offset + next_pad);
+ if (!ok) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (last) {
+ SIVAL(buffer->data, ofs+0x00, 0);
+ } else {
+ SIVAL(buffer->data, ofs+0x00, next_offset + next_pad);
+ }
+ SSVAL(buffer->data, ofs+0x04, 0x10); /* offset of tag */
+ SIVAL(buffer->data, ofs+0x06, tag_length); /* tag length */
+ SSVAL(buffer->data, ofs+0x0A, blob_offset + blob_pad); /* offset of data */
+ SIVAL(buffer->data, ofs+0x0C, blob->data.length);
+ memcpy(buffer->data+ofs+0x10, blob->tag, tag_length);
+ if (blob_pad > 0) {
+ memset(buffer->data+ofs+blob_offset, 0, blob_pad);
+ blob_offset += blob_pad;
+ }
+ memcpy(buffer->data+ofs+blob_offset, blob->data.data, blob->data.length);
+ if (next_pad > 0) {
+ memset(buffer->data+ofs+next_offset, 0, next_pad);
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ create a buffer of a set of create blobs
+*/
+NTSTATUS smb2_create_blob_push(TALLOC_CTX *mem_ctx, DATA_BLOB *buffer,
+ const struct smb2_create_blobs blobs)
+{
+ uint32_t i;
+ NTSTATUS status;
+
+ *buffer = (DATA_BLOB) { 0 };
+ for (i=0; i < blobs.num_blobs; i++) {
+ bool last = false;
+ const struct smb2_create_blob *c;
+
+ if ((i + 1) == blobs.num_blobs) {
+ last = true;
+ }
+
+ c = &blobs.blobs[i];
+ status = smb2_create_blob_push_one(mem_ctx, buffer, c, last);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ return NT_STATUS_OK;
+}
+
+
+NTSTATUS smb2_create_blob_add(TALLOC_CTX *mem_ctx, struct smb2_create_blobs *b,
+ const char *tag, DATA_BLOB data)
+{
+ struct smb2_create_blob *array;
+
+ array = talloc_realloc(mem_ctx, b->blobs,
+ struct smb2_create_blob,
+ b->num_blobs + 1);
+ NT_STATUS_HAVE_NO_MEMORY(array);
+ b->blobs = array;
+
+ b->blobs[b->num_blobs].tag = talloc_strdup(b->blobs, tag);
+ NT_STATUS_HAVE_NO_MEMORY(b->blobs[b->num_blobs].tag);
+
+ if (data.data) {
+ b->blobs[b->num_blobs].data = data_blob_talloc(b->blobs,
+ data.data,
+ data.length);
+ NT_STATUS_HAVE_NO_MEMORY(b->blobs[b->num_blobs].data.data);
+ } else {
+ b->blobs[b->num_blobs].data = data_blob_null;
+ }
+
+ b->num_blobs += 1;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * return the first blob with the given tag
+ */
+struct smb2_create_blob *smb2_create_blob_find(const struct smb2_create_blobs *b,
+ const char *tag)
+{
+ uint32_t i;
+
+ if (b == NULL) {
+ return NULL;
+ }
+
+ for (i=0; i < b->num_blobs; i++) {
+ if (strcmp(b->blobs[i].tag, tag) == 0) {
+ return &b->blobs[i];
+ }
+ }
+
+ return NULL;
+}
diff --git a/libcli/smb/smb2_create_blob.h b/libcli/smb/smb2_create_blob.h
new file mode 100644
index 0000000..642695a
--- /dev/null
+++ b/libcli/smb/smb2_create_blob.h
@@ -0,0 +1,75 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 Create Context Blob handling
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Stefan Metzmacher 2008-2009
+
+ 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/>.
+*/
+
+#ifndef _LIBCLI_SMB_SMB2_CREATE_BLOB_H_
+#define _LIBCLI_SMB_SMB2_CREATE_BLOB_H_
+
+#include "replace.h"
+#include "lib/util/data_blob.h"
+#include "lib/util/time.h"
+#include "libcli/util/ntstatus.h"
+
+struct smb2_create_blob {
+ char *tag;
+ DATA_BLOB data;
+};
+
+struct smb2_create_blobs {
+ uint32_t num_blobs;
+ struct smb2_create_blob *blobs;
+};
+
+struct smb_create_returns {
+ uint8_t oplock_level;
+ uint8_t flags;
+ uint32_t create_action;
+ NTTIME creation_time;
+ NTTIME last_access_time;
+ NTTIME last_write_time;
+ NTTIME change_time;
+ uint64_t allocation_size;
+ uint64_t end_of_file;
+ uint32_t file_attributes;
+};
+
+/*
+ parse a set of SMB2 create blobs
+*/
+NTSTATUS smb2_create_blob_parse(TALLOC_CTX *mem_ctx, const DATA_BLOB buffer,
+ struct smb2_create_blobs *blobs);
+
+/*
+ create a buffer of a set of create blobs
+*/
+NTSTATUS smb2_create_blob_push(TALLOC_CTX *mem_ctx, DATA_BLOB *buffer,
+ const struct smb2_create_blobs blobs);
+
+NTSTATUS smb2_create_blob_add(TALLOC_CTX *mem_ctx, struct smb2_create_blobs *b,
+ const char *tag, DATA_BLOB data);
+
+/*
+ * return the first blob with the given tag
+ */
+struct smb2_create_blob *smb2_create_blob_find(const struct smb2_create_blobs *b,
+ const char *tag);
+
+#endif /* _LIBCLI_SMB_SMB2_CREATE_BLOB_H_ */
diff --git a/libcli/smb/smb2_create_ctx.h b/libcli/smb/smb2_create_ctx.h
new file mode 100644
index 0000000..7e7bf22
--- /dev/null
+++ b/libcli/smb/smb2_create_ctx.h
@@ -0,0 +1,47 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 create context specific stuff
+
+ Copyright (C) Ralph Boehme 2014
+
+ 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/>.
+*/
+
+#ifndef __LIBCLI_SMB2_CREATE_CTX_H__
+#define __LIBCLI_SMB2_CREATE_CTX_H__
+
+/* http://opensource.apple.com/source/smb/smb-697.1.1/kernel/netsmb/smb_2.h */
+
+/* "AAPL" Context Command Codes */
+#define SMB2_CRTCTX_AAPL_SERVER_QUERY 1
+#define SMB2_CRTCTX_AAPL_RESOLVE_ID 2
+
+/* "AAPL" Server Query request/response bitmap */
+#define SMB2_CRTCTX_AAPL_SERVER_CAPS 1
+#define SMB2_CRTCTX_AAPL_VOLUME_CAPS 2
+#define SMB2_CRTCTX_AAPL_MODEL_INFO 4
+
+/* "AAPL" Client/Server Capabilities bitmap */
+#define SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR 1
+#define SMB2_CRTCTX_AAPL_SUPPORTS_OSX_COPYFILE 2
+#define SMB2_CRTCTX_AAPL_UNIX_BASED 4
+#define SMB2_CRTCTX_AAPL_SUPPORTS_NFS_ACE 8
+
+/* "AAPL" Volume Capabilities bitmap */
+#define SMB2_CRTCTX_AAPL_SUPPORT_RESOLVE_ID 1
+#define SMB2_CRTCTX_AAPL_CASE_SENSITIVE 2
+#define SMB2_CRTCTX_AAPL_FULL_SYNC 4
+
+#endif
diff --git a/libcli/smb/smb2_lease.c b/libcli/smb/smb2_lease.c
new file mode 100644
index 0000000..fc641ff
--- /dev/null
+++ b/libcli/smb/smb2_lease.c
@@ -0,0 +1,102 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 Lease context handling
+
+ Copyright (C) Stefan Metzmacher 2012
+ Copyright (C) Volker Lendecke 2013
+
+ 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 "../libcli/smb/smb_common.h"
+
+ssize_t smb2_lease_pull(const uint8_t *buf, size_t len,
+ struct smb2_lease *lease)
+{
+ int version;
+
+ switch (len) {
+ case 32:
+ version = 1;
+ break;
+ case 52:
+ version = 2;
+ break;
+ default:
+ return -1;
+ }
+
+ memcpy(&lease->lease_key, buf, 16);
+ lease->lease_state = IVAL(buf, 16);
+ lease->lease_flags = IVAL(buf, 20);
+ lease->lease_duration = BVAL(buf, 24);
+ lease->lease_version = version;
+
+ switch (version) {
+ case 1:
+ ZERO_STRUCT(lease->parent_lease_key);
+ lease->lease_epoch = 0;
+ break;
+ case 2:
+ memcpy(&lease->parent_lease_key, buf+32, 16);
+ lease->lease_epoch = SVAL(buf, 48);
+ break;
+ }
+
+ return len;
+}
+
+bool smb2_lease_push(const struct smb2_lease *lease, uint8_t *buf, size_t len)
+{
+ int version;
+
+ switch (len) {
+ case 32:
+ version = 1;
+ break;
+ case 52:
+ version = 2;
+ break;
+ default:
+ return false;
+ }
+
+ memcpy(&buf[0], &lease->lease_key, 16);
+ SIVAL(buf, 16, lease->lease_state);
+ SIVAL(buf, 20, lease->lease_flags);
+ SBVAL(buf, 24, lease->lease_duration);
+
+ if (version == 2) {
+ memcpy(&buf[32], &lease->parent_lease_key, 16);
+ SIVAL(buf, 48, lease->lease_epoch);
+ }
+
+ return true;
+}
+
+bool smb2_lease_key_equal(const struct smb2_lease_key *k1,
+ const struct smb2_lease_key *k2)
+{
+ return ((k1->data[0] == k2->data[0]) && (k1->data[1] == k2->data[1]));
+}
+
+bool smb2_lease_equal(const struct GUID *g1,
+ const struct smb2_lease_key *k1,
+ const struct GUID *g2,
+ const struct smb2_lease_key *k2)
+{
+ return GUID_equal(g1, g2) && smb2_lease_key_equal(k1, k2);
+}
diff --git a/libcli/smb/smb2_lease.h b/libcli/smb/smb2_lease.h
new file mode 100644
index 0000000..2e6faf7
--- /dev/null
+++ b/libcli/smb/smb2_lease.h
@@ -0,0 +1,43 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 Lease context handling
+
+ Copyright (C) Stefan Metzmacher 2012
+ Copyright (C) Volker Lendecke 2013
+
+ 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/>.
+*/
+
+#ifndef _LIBCLI_SMB_SMB2_LEASE_H_
+#define _LIBCLI_SMB_SMB2_LEASE_H_
+
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/gen_ndr/smb2_lease_struct.h"
+
+/*
+ * Parse a smb2 lease create context. Return -1 on error, buffer.length on
+ * success. V1 and V2 differ only by length of buffer.length
+ */
+ssize_t smb2_lease_pull(const uint8_t *buf, size_t len,
+ struct smb2_lease *lease);
+bool smb2_lease_push(const struct smb2_lease *lease, uint8_t *buf, size_t len);
+bool smb2_lease_key_equal(const struct smb2_lease_key *k1,
+ const struct smb2_lease_key *k2);
+bool smb2_lease_equal(const struct GUID *g1,
+ const struct smb2_lease_key *k1,
+ const struct GUID *g2,
+ const struct smb2_lease_key *k2);
+
+#endif /* _LIBCLI_SMB_SMB2_LEASE_H_ */
diff --git a/libcli/smb/smb2_lock.h b/libcli/smb/smb2_lock.h
new file mode 100644
index 0000000..f0e0535
--- /dev/null
+++ b/libcli/smb/smb2_lock.h
@@ -0,0 +1,32 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Volker Lendecke 2019
+ *
+ * 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/>.
+ */
+
+#ifndef __LIBCLI_SMB_SMB2_LOCK_H__
+#define __LIBCLI_SMB_SMB2_LOCK_H__
+
+#include "replace.h"
+
+struct smb2_lock_element {
+ uint64_t offset;
+ uint64_t length;
+ uint32_t flags;
+ uint32_t reserved;
+};
+
+#endif
diff --git a/libcli/smb/smb2_negotiate_context.c b/libcli/smb/smb2_negotiate_context.c
new file mode 100644
index 0000000..9ec20bc
--- /dev/null
+++ b/libcli/smb/smb2_negotiate_context.c
@@ -0,0 +1,203 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 2014
+
+ 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 "../libcli/smb/smb_common.h"
+#include "libcli/smb/smb2_negotiate_context.h"
+
+static size_t smb2_negotiate_context_padding(uint32_t offset, size_t n)
+{
+ if ((offset & (n-1)) == 0) return 0;
+ return n - (offset & (n-1));
+}
+
+/*
+ parse a set of SMB2 create contexts
+*/
+NTSTATUS smb2_negotiate_context_parse(TALLOC_CTX *mem_ctx, const DATA_BLOB buffer,
+ uint16_t expected_count,
+ struct smb2_negotiate_contexts *contexts)
+{
+ const uint8_t *data = buffer.data;
+ uint32_t remaining = buffer.length;
+ uint16_t idx;
+
+ for (idx = 0; idx < expected_count; idx++) {
+ uint16_t data_length;
+ uint16_t type;
+ NTSTATUS status;
+ size_t pad;
+ uint32_t next_offset;
+
+ if (remaining < 8) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ type = SVAL(data, 0x00);
+ data_length = SVAL(data, 0x02);
+#if 0
+ reserved = IVAL(data, 0x04);
+#endif
+
+ next_offset = 0x08 + data_length;
+ if (remaining < next_offset) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = smb2_negotiate_context_add(
+ mem_ctx, contexts, type, data+0x08, data_length);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (contexts->num_contexts == expected_count) {
+ break;
+ }
+
+ remaining -= next_offset;
+ data += next_offset;
+
+ if (remaining == 0) {
+ break;
+ }
+
+ pad = smb2_negotiate_context_padding(next_offset, 8);
+ if (remaining < pad) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ remaining -= pad;
+ data += pad;
+ }
+
+ if (contexts->num_contexts != expected_count) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ add a context to a smb2_negotiate attribute context
+*/
+static NTSTATUS smb2_negotiate_context_push_one(TALLOC_CTX *mem_ctx, DATA_BLOB *buffer,
+ const struct smb2_negotiate_context *context,
+ bool last)
+{
+ uint32_t ofs = buffer->length;
+ size_t next_offset = 0;
+ size_t next_pad = 0;
+ bool ok;
+
+ if (context->data.length > UINT16_MAX) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ next_offset = 0x08 + context->data.length;
+ if (!last) {
+ next_pad = smb2_negotiate_context_padding(next_offset, 8);
+ }
+
+ ok = data_blob_realloc(mem_ctx, buffer,
+ buffer->length + next_offset + next_pad);
+ if (!ok) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ SSVAL(buffer->data, ofs+0x00, context->type);
+ SIVAL(buffer->data, ofs+0x02, context->data.length);
+ SIVAL(buffer->data, ofs+0x04, 0);
+ memcpy(buffer->data+ofs+0x08, context->data.data, context->data.length);
+ if (next_pad > 0) {
+ memset(buffer->data+ofs+next_offset, 0, next_pad);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ create a buffer of a set of create contexts
+*/
+NTSTATUS smb2_negotiate_context_push(TALLOC_CTX *mem_ctx, DATA_BLOB *buffer,
+ const struct smb2_negotiate_contexts contexts)
+{
+ uint32_t i;
+ NTSTATUS status;
+
+ *buffer = data_blob(NULL, 0);
+ for (i=0; i < contexts.num_contexts; i++) {
+ bool last = false;
+ const struct smb2_negotiate_context *c;
+
+ if ((i + 1) == contexts.num_contexts) {
+ last = true;
+ }
+
+ c = &contexts.contexts[i];
+ status = smb2_negotiate_context_push_one(mem_ctx, buffer, c, last);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2_negotiate_context_add(TALLOC_CTX *mem_ctx,
+ struct smb2_negotiate_contexts *c,
+ uint16_t type,
+ const uint8_t *buf,
+ size_t buflen)
+{
+ struct smb2_negotiate_context *array;
+
+ array = talloc_realloc(mem_ctx, c->contexts,
+ struct smb2_negotiate_context,
+ c->num_contexts + 1);
+ NT_STATUS_HAVE_NO_MEMORY(array);
+ c->contexts = array;
+
+ c->contexts[c->num_contexts].type = type;
+
+ if (buf != NULL) {
+ c->contexts[c->num_contexts].data = data_blob_talloc(
+ c->contexts, buf, buflen);
+ NT_STATUS_HAVE_NO_MEMORY(c->contexts[c->num_contexts].data.data);
+ } else {
+ c->contexts[c->num_contexts].data = data_blob_null;
+ }
+
+ c->num_contexts += 1;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * return the first blob with the given tag
+ */
+struct smb2_negotiate_context *smb2_negotiate_context_find(const struct smb2_negotiate_contexts *c,
+ uint16_t type)
+{
+ uint32_t i;
+
+ for (i=0; i < c->num_contexts; i++) {
+ if (c->contexts[i].type == type) {
+ return &c->contexts[i];
+ }
+ }
+
+ return NULL;
+}
diff --git a/libcli/smb/smb2_negotiate_context.h b/libcli/smb/smb2_negotiate_context.h
new file mode 100644
index 0000000..645fb64
--- /dev/null
+++ b/libcli/smb/smb2_negotiate_context.h
@@ -0,0 +1,92 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 2014
+
+ 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/>.
+*/
+
+#ifndef _LIBCLI_SMB_SMB2_NEGOTIATE_BLOB_H_
+#define _LIBCLI_SMB_SMB2_NEGOTIATE_BLOB_H_
+
+struct smb2_negotiate_context {
+ uint16_t type;
+ DATA_BLOB data;
+};
+
+struct smb2_negotiate_contexts {
+ uint16_t num_contexts;
+ struct smb2_negotiate_context *contexts;
+};
+
+/*
+ parse a set of SMB2 negotiate contexts
+*/
+NTSTATUS smb2_negotiate_context_parse(TALLOC_CTX *mem_ctx, const DATA_BLOB buffer,
+ uint16_t expected_count,
+ struct smb2_negotiate_contexts *contexts);
+
+/*
+ negotiate a buffer of a set of negotiate contexts
+*/
+NTSTATUS smb2_negotiate_context_push(TALLOC_CTX *mem_ctx, DATA_BLOB *buffer,
+ const struct smb2_negotiate_contexts contexts);
+
+NTSTATUS smb2_negotiate_context_add(TALLOC_CTX *mem_ctx,
+ struct smb2_negotiate_contexts *c,
+ uint16_t type,
+ const uint8_t *buf,
+ size_t buflen);
+
+/*
+ * return the first context with the given tag
+ */
+struct smb2_negotiate_context *smb2_negotiate_context_find(const struct smb2_negotiate_contexts *b,
+ uint16_t type);
+#define WINDOWS_CLIENT_PURE_SMB2_NEGPROT_INITIAL_CREDIT_ASK 31
+
+struct smb3_signing_capabilities {
+#define SMB3_SIGNING_CAPABILITIES_MAX_ALGOS 3
+ uint16_t num_algos;
+ uint16_t algos[SMB3_SIGNING_CAPABILITIES_MAX_ALGOS];
+};
+
+struct smb3_encryption_capabilities {
+#define SMB3_ENCRYTION_CAPABILITIES_MAX_ALGOS 4
+ uint16_t num_algos;
+ uint16_t algos[SMB3_ENCRYTION_CAPABILITIES_MAX_ALGOS];
+};
+
+struct smb311_capabilities {
+ struct smb3_signing_capabilities signing;
+ struct smb3_encryption_capabilities encryption;
+};
+
+const char *smb3_signing_algorithm_name(uint16_t algo);
+const char *smb3_encryption_algorithm_name(uint16_t algo);
+
+struct smb311_capabilities smb311_capabilities_parse(const char *role,
+ const char * const *signing_algos,
+ const char * const *encryption_algos);
+
+NTSTATUS smb311_capabilities_check(const struct smb311_capabilities *c,
+ const char *debug_prefix,
+ int debug_lvl,
+ NTSTATUS error_status,
+ const char *role,
+ enum protocol_types protocol,
+ uint16_t sign_algo,
+ uint16_t cipher_algo);
+
+#endif /* _LIBCLI_SMB_SMB2_NEGOTIATE_BLOB_H_ */
diff --git a/libcli/smb/smb2_posix.c b/libcli/smb/smb2_posix.c
new file mode 100644
index 0000000..60be321
--- /dev/null
+++ b/libcli/smb/smb2_posix.c
@@ -0,0 +1,51 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * SMB2 Posix context handling
+ *
+ * Copyright (C) Jeremy Allison 2019
+ *
+ * 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 "replace.h"
+#include "libcli/smb/smb2_posix.h"
+#include "libcli/smb/smb2_constants.h"
+#include "lib/util/byteorder.h"
+
+NTSTATUS make_smb2_posix_create_ctx(
+ TALLOC_CTX *mem_ctx,
+ struct smb2_create_blobs **crb,
+ mode_t mode)
+{
+ struct smb2_create_blobs *cblobs = NULL;
+ uint8_t linear_mode[4];
+ DATA_BLOB blob = { .data=linear_mode, .length=sizeof(linear_mode) };
+ NTSTATUS status;
+
+ cblobs = talloc_zero(mem_ctx, struct smb2_create_blobs);
+ if (cblobs == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ SIVAL(&linear_mode,0, unix_perms_to_wire(mode & ~S_IFMT));
+
+ status = smb2_create_blob_add(
+ cblobs, cblobs, SMB2_CREATE_TAG_POSIX, blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(cblobs);
+ return status;
+ }
+ *crb = cblobs;
+ return NT_STATUS_OK;
+}
diff --git a/libcli/smb/smb2_posix.h b/libcli/smb/smb2_posix.h
new file mode 100644
index 0000000..0751814
--- /dev/null
+++ b/libcli/smb/smb2_posix.h
@@ -0,0 +1,36 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * SMB2 Posix context handling
+ *
+ * Copyright (C) Jeremy Allison 2019
+ *
+ * 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/>.
+ */
+
+#ifndef _LIBCLI_SMB_SMB2_POSIX_H_
+#define _LIBCLI_SMB_SMB2_POSIX_H_
+
+#include "replace.h"
+#include "system/filesys.h"
+#include <talloc.h>
+#include "libcli/smb/smb2_create_blob.h"
+#include "libcli/smb/smb_util.h"
+
+NTSTATUS make_smb2_posix_create_ctx(
+ TALLOC_CTX *mem_ctx,
+ struct smb2_create_blobs **crb,
+ mode_t mode);
+
+#endif /* _LIBCLI_SMB_SMB2_POSIX_H_ */
diff --git a/libcli/smb/smb2_signing.c b/libcli/smb/smb2_signing.c
new file mode 100644
index 0000000..94ff51f
--- /dev/null
+++ b/libcli/smb/smb2_signing.c
@@ -0,0 +1,1110 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB2 signing
+
+ Copyright (C) Stefan Metzmacher 2009
+
+ 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 "system/filesys.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#define SMB2_SIGNING_KEY_GNUTLS_TYPES 1
+#include "../libcli/smb/smb_common.h"
+#include "../lib/crypto/crypto.h"
+#include "lib/util/iov_buf.h"
+
+#include "lib/crypto/gnutls_helpers.h"
+
+void smb2_signing_derivations_fill_const_stack(struct smb2_signing_derivations *ds,
+ enum protocol_types protocol,
+ const DATA_BLOB preauth_hash)
+{
+ *ds = (struct smb2_signing_derivations) { .signing = NULL, };
+
+ if (protocol >= PROTOCOL_SMB3_11) {
+ struct smb2_signing_derivation *d = NULL;
+
+ SMB_ASSERT(preauth_hash.length != 0);
+
+ d = &ds->__signing;
+ ds->signing = d;
+ d->label = data_blob_string_const_null("SMBSigningKey");
+ d->context = preauth_hash;
+
+ d = &ds->__cipher_c2s;
+ ds->cipher_c2s = d;
+ d->label = data_blob_string_const_null("SMBC2SCipherKey");
+ d->context = preauth_hash;
+
+ d = &ds->__cipher_s2c;
+ ds->cipher_s2c = d;
+ d->label = data_blob_string_const_null("SMBS2CCipherKey");
+ d->context = preauth_hash;
+
+ d = &ds->__application;
+ ds->application = d;
+ d->label = data_blob_string_const_null("SMBAppKey");
+ d->context = preauth_hash;
+
+ } else if (protocol >= PROTOCOL_SMB3_00) {
+ struct smb2_signing_derivation *d = NULL;
+
+ d = &ds->__signing;
+ ds->signing = d;
+ d->label = data_blob_string_const_null("SMB2AESCMAC");
+ d->context = data_blob_string_const_null("SmbSign");
+
+ d = &ds->__cipher_c2s;
+ ds->cipher_c2s = d;
+ d->label = data_blob_string_const_null("SMB2AESCCM");
+ d->context = data_blob_string_const_null("ServerIn ");
+
+ d = &ds->__cipher_s2c;
+ ds->cipher_s2c = d;
+ d->label = data_blob_string_const_null("SMB2AESCCM");
+ d->context = data_blob_string_const_null("ServerOut");
+
+ d = &ds->__application;
+ ds->application = d;
+ d->label = data_blob_string_const_null("SMB2APP");
+ d->context = data_blob_string_const_null("SmbRpc");
+ }
+}
+
+static int smb2_signing_key_destructor(struct smb2_signing_key *key)
+{
+ if (key->hmac_hnd != NULL) {
+ gnutls_hmac_deinit(key->hmac_hnd, NULL);
+ key->hmac_hnd = NULL;
+ }
+
+ if (key->cipher_hnd != NULL) {
+ gnutls_aead_cipher_deinit(key->cipher_hnd);
+ key->cipher_hnd = NULL;
+ }
+
+ return 0;
+}
+
+NTSTATUS smb2_signing_key_copy(TALLOC_CTX *mem_ctx,
+ const struct smb2_signing_key *src,
+ struct smb2_signing_key **_dst)
+{
+ struct smb2_signing_key *dst = NULL;
+
+ dst = talloc_zero(mem_ctx, struct smb2_signing_key);
+ if (dst == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ talloc_set_destructor(dst, smb2_signing_key_destructor);
+
+ dst->sign_algo_id = src->sign_algo_id;
+ dst->cipher_algo_id = src->cipher_algo_id;
+
+ if (src->blob.length == 0) {
+ *_dst = dst;
+ return NT_STATUS_OK;
+ }
+
+ dst->blob = data_blob_talloc_zero(dst, src->blob.length);
+ if (dst->blob.length == 0) {
+ TALLOC_FREE(dst);
+ return NT_STATUS_NO_MEMORY;
+ }
+ talloc_keep_secret(dst->blob.data);
+ memcpy(dst->blob.data, src->blob.data, dst->blob.length);
+
+ *_dst = dst;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS smb2_signing_key_create(TALLOC_CTX *mem_ctx,
+ uint16_t sign_algo_id,
+ uint16_t cipher_algo_id,
+ const DATA_BLOB *master_key,
+ const struct smb2_signing_derivation *d,
+ struct smb2_signing_key **_key)
+{
+ struct smb2_signing_key *key = NULL;
+ size_t in_key_length = 16;
+ size_t out_key_length = 16;
+ NTSTATUS status;
+
+ if (sign_algo_id != SMB2_SIGNING_INVALID_ALGO) {
+ SMB_ASSERT(cipher_algo_id == SMB2_ENCRYPTION_INVALID_ALGO);
+ }
+ if (cipher_algo_id != SMB2_ENCRYPTION_INVALID_ALGO) {
+ SMB_ASSERT(sign_algo_id == SMB2_SIGNING_INVALID_ALGO);
+ }
+
+ key = talloc_zero(mem_ctx, struct smb2_signing_key);
+ if (key == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ talloc_set_destructor(key, smb2_signing_key_destructor);
+
+ key->sign_algo_id = sign_algo_id;
+ key->cipher_algo_id = cipher_algo_id;
+
+ if (master_key == NULL) {
+ SMB_ASSERT(d == NULL);
+
+ *_key = key;
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * Per default use the full key.
+ */
+ in_key_length = out_key_length = master_key->length;
+ switch (sign_algo_id) {
+ case SMB2_SIGNING_INVALID_ALGO:
+ /*
+ * This means we're processing cipher_algo_id below
+ */
+ break;
+ case SMB2_SIGNING_MD5_SMB1:
+ SMB_ASSERT(d == NULL);
+ break;
+ case SMB2_SIGNING_HMAC_SHA256:
+ case SMB2_SIGNING_AES128_CMAC:
+ case SMB2_SIGNING_AES128_GMAC:
+ /*
+ * signing keys are padded or truncated to
+ * 16 bytes.
+ *
+ * Even with master_key->length = 0,
+ * we need to use 16 zeros.
+ */
+ in_key_length = out_key_length = 16;
+ break;
+ default:
+ DBG_ERR("sign_algo_id[%u] not supported\n", sign_algo_id);
+ return NT_STATUS_HMAC_NOT_SUPPORTED;
+ }
+ switch (cipher_algo_id) {
+ case SMB2_ENCRYPTION_INVALID_ALGO:
+ /*
+ * This means we're processing sign_algo_id above
+ */
+ break;
+ case SMB2_ENCRYPTION_NONE:
+ /*
+ * No encryption negotiated.
+ */
+ break;
+ case SMB2_ENCRYPTION_AES128_CCM:
+ case SMB2_ENCRYPTION_AES128_GCM:
+ /*
+ * encryption keys are padded or truncated to
+ * 16 bytes.
+ */
+ if (master_key->length == 0) {
+ DBG_ERR("cipher_algo_id[%u] without key\n",
+ cipher_algo_id);
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+ in_key_length = out_key_length = 16;
+ break;
+ case SMB2_ENCRYPTION_AES256_CCM:
+ case SMB2_ENCRYPTION_AES256_GCM:
+ /*
+ * AES256 uses the available input and
+ * generated a 32 byte encryption key.
+ */
+ if (master_key->length == 0) {
+ DBG_ERR("cipher_algo_id[%u] without key\n",
+ cipher_algo_id);
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+ out_key_length = 32;
+ break;
+ default:
+ DBG_ERR("cipher_algo_id[%u] not supported\n", cipher_algo_id);
+ return NT_STATUS_FWP_INCOMPATIBLE_CIPHER_CONFIG;
+ }
+
+ if (out_key_length == 0) {
+ *_key = key;
+ return NT_STATUS_OK;
+ }
+
+ key->blob = data_blob_talloc_zero(key, out_key_length);
+ if (key->blob.length == 0) {
+ TALLOC_FREE(key);
+ return NT_STATUS_NO_MEMORY;
+ }
+ talloc_keep_secret(key->blob.data);
+ memcpy(key->blob.data,
+ master_key->data,
+ MIN(key->blob.length, master_key->length));
+
+ if (d == NULL) {
+ *_key = key;
+ return NT_STATUS_OK;
+ }
+
+ status = samba_gnutls_sp800_108_derive_key(key->blob.data,
+ in_key_length,
+ NULL,
+ 0,
+ d->label.data,
+ d->label.length,
+ d->context.data,
+ d->context.length,
+ GNUTLS_MAC_SHA256,
+ key->blob.data,
+ out_key_length);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(key);
+ return status;
+ }
+
+ *_key = key;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2_signing_key_sign_create(TALLOC_CTX *mem_ctx,
+ uint16_t sign_algo_id,
+ const DATA_BLOB *master_key,
+ const struct smb2_signing_derivation *d,
+ struct smb2_signing_key **_key)
+{
+ return smb2_signing_key_create(mem_ctx,
+ sign_algo_id,
+ SMB2_ENCRYPTION_INVALID_ALGO,
+ master_key,
+ d,
+ _key);
+}
+
+NTSTATUS smb2_signing_key_cipher_create(TALLOC_CTX *mem_ctx,
+ uint16_t cipher_algo_id,
+ const DATA_BLOB *master_key,
+ const struct smb2_signing_derivation *d,
+ struct smb2_signing_key **_key)
+{
+ return smb2_signing_key_create(mem_ctx,
+ SMB2_SIGNING_INVALID_ALGO,
+ cipher_algo_id,
+ master_key,
+ d,
+ _key);
+}
+
+bool smb2_signing_key_valid(const struct smb2_signing_key *key)
+{
+ if (key == NULL) {
+ return false;
+ }
+
+ if (key->blob.length == 0 || key->blob.data == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
+static NTSTATUS smb2_signing_gmac(gnutls_aead_cipher_hd_t cipher_hnd,
+ const uint8_t *iv, size_t iv_size,
+ const giovec_t *auth_iov, uint8_t auth_iovcnt,
+ uint8_t *tag, size_t _tag_size)
+{
+ size_t tag_size = _tag_size;
+ int rc;
+
+ rc = gnutls_aead_cipher_encryptv2(cipher_hnd,
+ iv, iv_size,
+ auth_iov, auth_iovcnt,
+ NULL, 0,
+ tag, &tag_size);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS smb2_signing_calc_signature(struct smb2_signing_key *signing_key,
+ uint16_t sign_algo_id,
+ const struct iovec *vector,
+ int count,
+ uint8_t signature[16])
+{
+ const uint8_t *hdr = (uint8_t *)vector[0].iov_base;
+ uint16_t opcode;
+ uint32_t flags;
+ uint64_t msg_id;
+ static const uint8_t zero_sig[16] = { 0, };
+ gnutls_mac_algorithm_t hmac_algo = GNUTLS_MAC_UNKNOWN;
+ int i;
+
+ /*
+ * We expect
+ * - SMB2 HDR
+ * - SMB2 BODY FIXED
+ * - (optional) SMB2 BODY DYN
+ * - (optional) PADDING
+ */
+ SMB_ASSERT(count >= 2);
+ SMB_ASSERT(vector[0].iov_len == SMB2_HDR_BODY);
+ SMB_ASSERT(count <= 4);
+
+ opcode = SVAL(hdr, SMB2_HDR_OPCODE);
+ flags = IVAL(hdr, SMB2_HDR_FLAGS);
+ if (flags & SMB2_HDR_FLAG_REDIRECT) {
+ NTSTATUS pdu_status = NT_STATUS(IVAL(hdr, SMB2_HDR_STATUS));
+ if (NT_STATUS_EQUAL(pdu_status, NT_STATUS_PENDING)) {
+ DBG_ERR("opcode[%u] NT_STATUS_PENDING\n", opcode);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ if (opcode == SMB2_OP_CANCEL) {
+ DBG_ERR("SMB2_OP_CANCEL response should not be signed\n");
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ }
+ msg_id = BVAL(hdr, SMB2_HDR_MESSAGE_ID);
+ if (msg_id == 0) {
+ if (opcode != SMB2_OP_CANCEL ||
+ sign_algo_id >= SMB2_SIGNING_AES128_GMAC)
+ {
+ DBG_ERR("opcode[%u] msg_id == 0\n", opcode);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ /*
+ * Legacy algorithms allow MID 0
+ * for cancel requests
+ */
+ }
+ if (msg_id == UINT64_MAX) {
+ DBG_ERR("opcode[%u] msg_id == UINT64_MAX\n", opcode);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ switch (sign_algo_id) {
+ case SMB2_SIGNING_AES128_GMAC: {
+ gnutls_cipher_algorithm_t algo = GNUTLS_CIPHER_AES_128_GCM;
+ uint32_t key_size = gnutls_cipher_get_key_size(algo);
+ uint32_t iv_size = gnutls_cipher_get_iv_size(algo);
+ size_t tag_size = gnutls_cipher_get_tag_size(algo);
+ gnutls_datum_t key = {
+ .data = signing_key->blob.data,
+ .size = MIN(signing_key->blob.length, key_size),
+ };
+ uint64_t high_bits = 0;
+ uint8_t iv[AES_BLOCK_SIZE] = {0};
+ giovec_t auth_iov[count+1];
+ size_t auth_iovcnt = 0;
+ NTSTATUS status;
+ int rc;
+
+ high_bits = flags & SMB2_HDR_FLAG_REDIRECT;
+ if (opcode == SMB2_OP_CANCEL) {
+ high_bits |= SMB2_HDR_FLAG_ASYNC;
+ }
+ SBVAL(iv, 0, msg_id);
+ SBVAL(iv, 8, high_bits);
+
+ if (signing_key->cipher_hnd == NULL) {
+ rc = gnutls_aead_cipher_init(&signing_key->cipher_hnd,
+ algo,
+ &key);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+ }
+
+ SMB_ASSERT(key_size == 16);
+ SMB_ASSERT(iv_size == 12);
+ SMB_ASSERT(tag_size == 16);
+
+ auth_iov[auth_iovcnt++] = (giovec_t) {
+ .iov_base = discard_const_p(uint8_t, hdr),
+ .iov_len = SMB2_HDR_SIGNATURE,
+ };
+ auth_iov[auth_iovcnt++] = (giovec_t) {
+ .iov_base = discard_const_p(uint8_t, zero_sig),
+ .iov_len = 16,
+ };
+ for (i=1; i < count; i++) {
+ auth_iov[auth_iovcnt++] = (giovec_t) {
+ .iov_base = discard_const_p(uint8_t, vector[i].iov_base),
+ .iov_len = vector[i].iov_len,
+ };
+ }
+
+ status = smb2_signing_gmac(signing_key->cipher_hnd,
+ iv,
+ iv_size,
+ auth_iov,
+ auth_iovcnt,
+ signature,
+ tag_size);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+ } break;
+
+ case SMB2_SIGNING_AES128_CMAC:
+ hmac_algo = GNUTLS_MAC_AES_CMAC_128;
+ break;
+ case SMB2_SIGNING_HMAC_SHA256:
+ hmac_algo = GNUTLS_MAC_SHA256;
+ break;
+
+ default:
+ return NT_STATUS_HMAC_NOT_SUPPORTED;
+ }
+
+ if (hmac_algo != GNUTLS_MAC_UNKNOWN) {
+ uint8_t digest[gnutls_hmac_get_len(hmac_algo)];
+ gnutls_datum_t key = {
+ .data = signing_key->blob.data,
+ .size = MIN(signing_key->blob.length, 16),
+ };
+ int rc;
+
+ if (signing_key->hmac_hnd == NULL) {
+ rc = gnutls_hmac_init(&signing_key->hmac_hnd,
+ hmac_algo,
+ key.data,
+ key.size);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+ }
+
+ rc = gnutls_hmac(signing_key->hmac_hnd, hdr, SMB2_HDR_SIGNATURE);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+ rc = gnutls_hmac(signing_key->hmac_hnd, zero_sig, 16);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+
+ for (i = 1; i < count; i++) {
+ rc = gnutls_hmac(signing_key->hmac_hnd,
+ vector[i].iov_base,
+ vector[i].iov_len);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+ }
+ gnutls_hmac_output(signing_key->hmac_hnd, digest);
+ memcpy(signature, digest, 16);
+ ZERO_ARRAY(digest);
+ return NT_STATUS_OK;
+ }
+
+ return NT_STATUS_HMAC_NOT_SUPPORTED;
+}
+
+NTSTATUS smb2_signing_sign_pdu(struct smb2_signing_key *signing_key,
+ struct iovec *vector,
+ int count)
+{
+ uint16_t sign_algo_id;
+ uint8_t *hdr;
+ uint64_t session_id;
+ uint8_t res[16];
+ NTSTATUS status;
+
+ /*
+ * We expect
+ * - SMB2 HDR
+ * - SMB2 BODY FIXED
+ * - (optional) SMB2 BODY DYN
+ * - (optional) PADDING
+ */
+ SMB_ASSERT(count >= 2);
+ SMB_ASSERT(vector[0].iov_len == SMB2_HDR_BODY);
+ SMB_ASSERT(count <= 4);
+
+ hdr = (uint8_t *)vector[0].iov_base;
+
+ session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
+ if (session_id == 0) {
+ /*
+ * do not sign messages with a zero session_id.
+ * See MS-SMB2 3.2.4.1.1
+ */
+ return NT_STATUS_OK;
+ }
+
+ if (!smb2_signing_key_valid(signing_key)) {
+ DBG_WARNING("No signing key for SMB2 signing\n");
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ memset(hdr + SMB2_HDR_SIGNATURE, 0, 16);
+
+ SIVAL(hdr, SMB2_HDR_FLAGS, IVAL(hdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_SIGNED);
+
+ sign_algo_id = signing_key->sign_algo_id;
+
+ status = smb2_signing_calc_signature(signing_key,
+ sign_algo_id,
+ vector,
+ count,
+ res);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("smb2_signing_calc_signature(sign_algo_id=%u) - %s\n",
+ (unsigned)sign_algo_id, nt_errstr(status));
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_ERROR)) {
+ smb_panic(__location__);
+ }
+ return status;
+ }
+
+ DEBUG(5,("signed SMB2 message (sign_algo_id=%u)\n",
+ (unsigned)sign_algo_id));
+
+ memcpy(hdr + SMB2_HDR_SIGNATURE, res, 16);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2_signing_check_pdu(struct smb2_signing_key *signing_key,
+ const struct iovec *vector,
+ int count)
+{
+ uint16_t sign_algo_id;
+ const uint8_t *hdr;
+ const uint8_t *sig;
+ uint64_t session_id;
+ uint8_t res[16];
+ NTSTATUS status;
+
+ /*
+ * We expect
+ * - SMB2 HDR
+ * - SMB2 BODY FIXED
+ * - (optional) SMB2 BODY DYN
+ * - (optional) PADDING
+ */
+ SMB_ASSERT(count >= 2);
+ SMB_ASSERT(vector[0].iov_len == SMB2_HDR_BODY);
+ SMB_ASSERT(count <= 4);
+
+ hdr = (const uint8_t *)vector[0].iov_base;
+
+ session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
+ if (session_id == 0) {
+ /*
+ * do not sign messages with a zero session_id.
+ * See MS-SMB2 3.2.4.1.1
+ */
+ return NT_STATUS_OK;
+ }
+
+ if (!smb2_signing_key_valid(signing_key)) {
+ /* we don't have the session key yet */
+ return NT_STATUS_OK;
+ }
+
+ sig = hdr+SMB2_HDR_SIGNATURE;
+
+ sign_algo_id = signing_key->sign_algo_id;
+
+ status = smb2_signing_calc_signature(signing_key,
+ sign_algo_id,
+ vector,
+ count,
+ res);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("smb2_signing_calc_signature(sign_algo_id=%u) - %s\n",
+ (unsigned)sign_algo_id, nt_errstr(status));
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_ERROR)) {
+ status = NT_STATUS_ACCESS_DENIED;
+ }
+ return status;
+ }
+
+ if (!mem_equal_const_time(res, sig, 16)) {
+ DEBUG(0,("Bad SMB2 (sign_algo_id=%u) signature for message\n",
+ (unsigned)sign_algo_id));
+ dump_data(0, sig, 16);
+ dump_data(0, res, 16);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2_signing_encrypt_pdu(struct smb2_signing_key *encryption_key,
+ struct iovec *vector,
+ int count)
+{
+ bool use_encryptv2 = false;
+ uint16_t cipher_id;
+ uint8_t *tf;
+ size_t a_total;
+ ssize_t m_total;
+ uint32_t iv_size = 0;
+ uint32_t key_size = 0;
+ size_t tag_size = 0;
+ gnutls_cipher_algorithm_t algo = 0;
+ gnutls_datum_t key;
+ gnutls_datum_t iv;
+ NTSTATUS status;
+ int rc;
+
+ if (count < 1) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (vector[0].iov_len != SMB2_TF_HDR_SIZE) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ tf = (uint8_t *)vector[0].iov_base;
+
+ if (!smb2_signing_key_valid(encryption_key)) {
+ DBG_WARNING("No encryption key for SMB2 signing\n");
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ cipher_id = encryption_key->cipher_algo_id;
+
+ a_total = SMB2_TF_HDR_SIZE - SMB2_TF_NONCE;
+
+ m_total = iov_buflen(&vector[1], count-1);
+ if (m_total == -1) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ SSVAL(tf, SMB2_TF_FLAGS, SMB2_TF_FLAGS_ENCRYPTED);
+ SIVAL(tf, SMB2_TF_MSG_SIZE, m_total);
+
+ switch (cipher_id) {
+ case SMB2_ENCRYPTION_AES128_CCM:
+ algo = GNUTLS_CIPHER_AES_128_CCM;
+ iv_size = SMB2_AES_128_CCM_NONCE_SIZE;
+#ifdef ALLOW_GNUTLS_AEAD_CIPHER_ENCRYPTV2_AES_CCM
+ use_encryptv2 = true;
+#endif
+ break;
+ case SMB2_ENCRYPTION_AES128_GCM:
+ algo = GNUTLS_CIPHER_AES_128_GCM;
+ iv_size = gnutls_cipher_get_iv_size(algo);
+ use_encryptv2 = true;
+ break;
+ case SMB2_ENCRYPTION_AES256_CCM:
+ algo = GNUTLS_CIPHER_AES_256_CCM;
+ iv_size = SMB2_AES_128_CCM_NONCE_SIZE;
+#ifdef ALLOW_GNUTLS_AEAD_CIPHER_ENCRYPTV2_AES_CCM
+ use_encryptv2 = true;
+#endif
+ break;
+ case SMB2_ENCRYPTION_AES256_GCM:
+ algo = GNUTLS_CIPHER_AES_256_GCM;
+ iv_size = gnutls_cipher_get_iv_size(algo);
+ use_encryptv2 = true;
+ break;
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ key_size = gnutls_cipher_get_key_size(algo);
+ tag_size = gnutls_cipher_get_tag_size(algo);
+
+ if (key_size != encryption_key->blob.length) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (tag_size != 16) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ key = (gnutls_datum_t) {
+ .data = encryption_key->blob.data,
+ .size = key_size,
+ };
+
+ iv = (gnutls_datum_t) {
+ .data = tf + SMB2_TF_NONCE,
+ .size = iv_size,
+ };
+
+ if (encryption_key->cipher_hnd == NULL) {
+ rc = gnutls_aead_cipher_init(&encryption_key->cipher_hnd,
+ algo,
+ &key);
+ if (rc < 0) {
+ status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
+ goto out;
+ }
+ }
+
+ memset(tf + SMB2_TF_NONCE + iv_size,
+ 0,
+ 16 - iv_size);
+
+ if (use_encryptv2) {
+ uint8_t tag[tag_size];
+ giovec_t auth_iov[1];
+
+ auth_iov[0] = (giovec_t) {
+ .iov_base = tf + SMB2_TF_NONCE,
+ .iov_len = a_total,
+ };
+
+ rc = gnutls_aead_cipher_encryptv2(encryption_key->cipher_hnd,
+ iv.data,
+ iv.size,
+ auth_iov,
+ 1,
+ &vector[1],
+ count - 1,
+ tag,
+ &tag_size);
+ if (rc < 0) {
+ status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
+ goto out;
+ }
+
+ memcpy(tf + SMB2_TF_SIGNATURE, tag, tag_size);
+ } else
+ {
+ size_t ptext_size = m_total;
+ uint8_t *ptext = NULL;
+ size_t ctext_size = m_total + tag_size;
+ uint8_t *ctext = NULL;
+ size_t len = 0;
+ int i;
+ TALLOC_CTX *tmp_ctx = NULL;
+
+ /*
+ * If we come from python bindings, we don't have a stackframe
+ * around, so use the NULL context.
+ *
+ * This is fine as we make sure we free the memory.
+ */
+ if (talloc_stackframe_exists()) {
+ tmp_ctx = talloc_tos();
+ }
+
+ ptext = talloc_size(tmp_ctx, ptext_size);
+ if (ptext == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ ctext = talloc_size(tmp_ctx, ctext_size);
+ if (ctext == NULL) {
+ TALLOC_FREE(ptext);
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ for (i = 1; i < count; i++) {
+ if (vector[i].iov_base != NULL) {
+ memcpy(ptext + len,
+ vector[i].iov_base,
+ vector[i].iov_len);
+ }
+
+ len += vector[i].iov_len;
+ if (len > ptext_size) {
+ TALLOC_FREE(ptext);
+ TALLOC_FREE(ctext);
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto out;
+ }
+ }
+
+ rc = gnutls_aead_cipher_encrypt(encryption_key->cipher_hnd,
+ iv.data,
+ iv.size,
+ tf + SMB2_TF_NONCE,
+ a_total,
+ tag_size,
+ ptext,
+ ptext_size,
+ ctext,
+ &ctext_size);
+ if (rc < 0 || ctext_size != m_total + tag_size) {
+ TALLOC_FREE(ptext);
+ TALLOC_FREE(ctext);
+ status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
+ goto out;
+ }
+
+ len = 0;
+ for (i = 1; i < count; i++) {
+ if (vector[i].iov_base != NULL) {
+ memcpy(vector[i].iov_base,
+ ctext + len,
+ vector[i].iov_len);
+ }
+
+ len += vector[i].iov_len;
+ }
+
+ memcpy(tf + SMB2_TF_SIGNATURE, ctext + m_total, tag_size);
+
+ TALLOC_FREE(ptext);
+ TALLOC_FREE(ctext);
+ }
+
+ DBG_INFO("Encrypted SMB2 message\n");
+
+ status = NT_STATUS_OK;
+out:
+ return status;
+}
+
+NTSTATUS smb2_signing_decrypt_pdu(struct smb2_signing_key *decryption_key,
+ struct iovec *vector,
+ int count)
+{
+ bool use_encryptv2 = false;
+ uint16_t cipher_id;
+ uint8_t *tf;
+ uint16_t flags;
+ size_t a_total;
+ ssize_t m_total;
+ uint32_t msg_size = 0;
+ uint32_t iv_size = 0;
+ uint32_t key_size = 0;
+ size_t tag_size = 0;
+ gnutls_cipher_algorithm_t algo = 0;
+ gnutls_datum_t key;
+ gnutls_datum_t iv;
+ NTSTATUS status;
+ int rc;
+
+ if (count < 1) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (vector[0].iov_len != SMB2_TF_HDR_SIZE) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ tf = (uint8_t *)vector[0].iov_base;
+
+ if (!smb2_signing_key_valid(decryption_key)) {
+ DBG_WARNING("No decryption key for SMB2 signing\n");
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ cipher_id = decryption_key->cipher_algo_id;
+
+ a_total = SMB2_TF_HDR_SIZE - SMB2_TF_NONCE;
+
+ m_total = iov_buflen(&vector[1], count-1);
+ if (m_total == -1) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ flags = SVAL(tf, SMB2_TF_FLAGS);
+ msg_size = IVAL(tf, SMB2_TF_MSG_SIZE);
+
+ if (flags != SMB2_TF_FLAGS_ENCRYPTED) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (msg_size != m_total) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ switch (cipher_id) {
+ case SMB2_ENCRYPTION_AES128_CCM:
+ algo = GNUTLS_CIPHER_AES_128_CCM;
+ iv_size = SMB2_AES_128_CCM_NONCE_SIZE;
+#ifdef ALLOW_GNUTLS_AEAD_CIPHER_ENCRYPTV2_AES_CCM
+ use_encryptv2 = true;
+#endif
+ break;
+ case SMB2_ENCRYPTION_AES128_GCM:
+ algo = GNUTLS_CIPHER_AES_128_GCM;
+ iv_size = gnutls_cipher_get_iv_size(algo);
+ use_encryptv2 = true;
+ break;
+ case SMB2_ENCRYPTION_AES256_CCM:
+ algo = GNUTLS_CIPHER_AES_256_CCM;
+ iv_size = SMB2_AES_128_CCM_NONCE_SIZE;
+#ifdef ALLOW_GNUTLS_AEAD_CIPHER_ENCRYPTV2_AES_CCM
+ use_encryptv2 = true;
+#endif
+ break;
+ case SMB2_ENCRYPTION_AES256_GCM:
+ algo = GNUTLS_CIPHER_AES_256_GCM;
+ iv_size = gnutls_cipher_get_iv_size(algo);
+ use_encryptv2 = true;
+ break;
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ key_size = gnutls_cipher_get_key_size(algo);
+ tag_size = gnutls_cipher_get_tag_size(algo);
+
+ if (key_size != decryption_key->blob.length) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (tag_size != 16) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ key = (gnutls_datum_t) {
+ .data = decryption_key->blob.data,
+ .size = key_size,
+ };
+
+ iv = (gnutls_datum_t) {
+ .data = tf + SMB2_TF_NONCE,
+ .size = iv_size,
+ };
+
+ if (decryption_key->cipher_hnd == NULL) {
+ rc = gnutls_aead_cipher_init(&decryption_key->cipher_hnd,
+ algo,
+ &key);
+ if (rc < 0) {
+ status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
+ goto out;
+ }
+ }
+
+ if (use_encryptv2) {
+ giovec_t auth_iov[1];
+
+ auth_iov[0] = (giovec_t) {
+ .iov_base = tf + SMB2_TF_NONCE,
+ .iov_len = a_total,
+ };
+
+ rc = gnutls_aead_cipher_decryptv2(decryption_key->cipher_hnd,
+ iv.data,
+ iv.size,
+ auth_iov,
+ 1,
+ &vector[1],
+ count - 1,
+ tf + SMB2_TF_SIGNATURE,
+ tag_size);
+ if (rc < 0) {
+ status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
+ goto out;
+ }
+ } else
+ {
+ size_t ctext_size = m_total + tag_size;
+ uint8_t *ctext = NULL;
+ size_t ptext_size = m_total;
+ uint8_t *ptext = NULL;
+ size_t len = 0;
+ int i;
+ TALLOC_CTX *tmp_ctx = NULL;
+
+ /*
+ * If we come from python bindings, we don't have a stackframe
+ * around, so use the NULL context.
+ *
+ * This is fine as we make sure we free the memory.
+ */
+ if (talloc_stackframe_exists()) {
+ tmp_ctx = talloc_tos();
+ }
+
+ /* GnuTLS doesn't have a iovec API for decryption yet */
+
+ ptext = talloc_size(tmp_ctx, ptext_size);
+ if (ptext == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ ctext = talloc_size(tmp_ctx, ctext_size);
+ if (ctext == NULL) {
+ TALLOC_FREE(ptext);
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+
+ for (i = 1; i < count; i++) {
+ memcpy(ctext + len,
+ vector[i].iov_base,
+ vector[i].iov_len);
+
+ len += vector[i].iov_len;
+ }
+ if (len != m_total) {
+ TALLOC_FREE(ptext);
+ TALLOC_FREE(ctext);
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto out;
+ }
+
+ memcpy(ctext + len,
+ tf + SMB2_TF_SIGNATURE,
+ tag_size);
+
+ /* This function will verify the tag */
+ rc = gnutls_aead_cipher_decrypt(decryption_key->cipher_hnd,
+ iv.data,
+ iv.size,
+ tf + SMB2_TF_NONCE,
+ a_total,
+ tag_size,
+ ctext,
+ ctext_size,
+ ptext,
+ &ptext_size);
+ if (rc < 0) {
+ TALLOC_FREE(ptext);
+ TALLOC_FREE(ctext);
+ status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
+ goto out;
+ }
+ if (ptext_size != m_total) {
+ TALLOC_FREE(ptext);
+ TALLOC_FREE(ctext);
+ rc = GNUTLS_E_SHORT_MEMORY_BUFFER;
+ status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
+ goto out;
+ }
+
+ len = 0;
+ for (i = 1; i < count; i++) {
+ memcpy(vector[i].iov_base,
+ ptext + len,
+ vector[i].iov_len);
+
+ len += vector[i].iov_len;
+ }
+
+ TALLOC_FREE(ptext);
+ TALLOC_FREE(ctext);
+ }
+
+ DBG_INFO("Decrypted SMB2 message\n");
+
+ status = NT_STATUS_OK;
+out:
+ return status;
+}
diff --git a/libcli/smb/smb2_signing.h b/libcli/smb/smb2_signing.h
new file mode 100644
index 0000000..2b8eef9
--- /dev/null
+++ b/libcli/smb/smb2_signing.h
@@ -0,0 +1,102 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB2 signing
+
+ Copyright (C) Stefan Metzmacher 2009
+
+ 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/>.
+*/
+
+#ifndef _LIBCLI_SMB_SMB2_SIGNING_H_
+#define _LIBCLI_SMB_SMB2_SIGNING_H_
+
+#include <gnutls/gnutls.h>
+
+#include "lib/util/data_blob.h"
+
+#include "libcli/smb/smb_constants.h"
+#include "libcli/util/ntstatus.h"
+
+struct iovec;
+
+struct smb2_signing_derivation {
+ DATA_BLOB label;
+ DATA_BLOB context;
+};
+
+struct smb2_signing_derivations {
+ struct smb2_signing_derivation __signing;
+ const struct smb2_signing_derivation *signing;
+ struct smb2_signing_derivation __cipher_c2s;
+ const struct smb2_signing_derivation *cipher_c2s;
+ struct smb2_signing_derivation __cipher_s2c;
+ const struct smb2_signing_derivation *cipher_s2c;
+ struct smb2_signing_derivation __application;
+ const struct smb2_signing_derivation *application;
+};
+
+void smb2_signing_derivations_fill_const_stack(struct smb2_signing_derivations *ds,
+ enum protocol_types protocol,
+ const DATA_BLOB preauth_hash);
+
+struct smb2_signing_key {
+ DATA_BLOB blob;
+ uint16_t sign_algo_id;
+ union {
+#ifdef SMB2_SIGNING_KEY_GNUTLS_TYPES
+ gnutls_hmac_hd_t hmac_hnd;
+#endif
+ void *__hmac_hnd;
+ };
+ uint16_t cipher_algo_id;
+ union {
+#ifdef SMB2_SIGNING_KEY_GNUTLS_TYPES
+ gnutls_aead_cipher_hd_t cipher_hnd;
+#endif
+ void *__cipher_hnd;
+ };
+};
+
+NTSTATUS smb2_signing_key_copy(TALLOC_CTX *mem_ctx,
+ const struct smb2_signing_key *src,
+ struct smb2_signing_key **_dst);
+NTSTATUS smb2_signing_key_sign_create(TALLOC_CTX *mem_ctx,
+ uint16_t sign_algo_id,
+ const DATA_BLOB *master_key,
+ const struct smb2_signing_derivation *d,
+ struct smb2_signing_key **_key);
+NTSTATUS smb2_signing_key_cipher_create(TALLOC_CTX *mem_ctx,
+ uint16_t cipher_algo_id,
+ const DATA_BLOB *master_key,
+ const struct smb2_signing_derivation *d,
+ struct smb2_signing_key **_key);
+
+bool smb2_signing_key_valid(const struct smb2_signing_key *key);
+
+NTSTATUS smb2_signing_sign_pdu(struct smb2_signing_key *signing_key,
+ struct iovec *vector,
+ int count);
+
+NTSTATUS smb2_signing_check_pdu(struct smb2_signing_key *signing_key,
+ const struct iovec *vector,
+ int count);
+
+NTSTATUS smb2_signing_encrypt_pdu(struct smb2_signing_key *encryption_key,
+ struct iovec *vector,
+ int count);
+NTSTATUS smb2_signing_decrypt_pdu(struct smb2_signing_key *decryption_key,
+ struct iovec *vector,
+ int count);
+
+#endif /* _LIBCLI_SMB_SMB2_SIGNING_H_ */
diff --git a/libcli/smb/smb2cli_close.c b/libcli/smb/smb2cli_close.c
new file mode 100644
index 0000000..5e31056
--- /dev/null
+++ b/libcli/smb/smb2cli_close.c
@@ -0,0 +1,136 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Volker Lendecke 2011
+
+ 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb2cli_close_state {
+ uint8_t fixed[24];
+};
+
+static void smb2cli_close_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_close_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t flags,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_close_state *state;
+ uint8_t *fixed;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_close_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ fixed = state->fixed;
+ SSVAL(fixed, 0, 24);
+ SSVAL(fixed, 2, flags);
+ SBVAL(fixed, 8, fid_persistent);
+ SBVAL(fixed, 16, fid_volatile);
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_CLOSE,
+ 0, 0, /* flags */
+ timeout_msec,
+ tcon,
+ session,
+ state->fixed, sizeof(state->fixed),
+ NULL, 0, /* dyn* */
+ 0); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_close_done, req);
+ return req;
+}
+
+static void smb2cli_close_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ NTSTATUS status;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x3C
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, NULL, NULL,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_close_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS smb2cli_close(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t flags,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_close_send(frame, ev, conn, timeout_msec,
+ session, tcon, flags,
+ fid_persistent, fid_volatile);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_close_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_create.c b/libcli/smb/smb2cli_create.c
new file mode 100644
index 0000000..e740365
--- /dev/null
+++ b/libcli/smb/smb2cli_create.c
@@ -0,0 +1,580 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Volker Lendecke 2011
+
+ 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+#include "smb2_create_blob.h"
+#include "reparse.h"
+
+struct smb2cli_create_state {
+ enum protocol_types protocol; /* for symlink error response parser */
+ uint8_t *name_utf16;
+ size_t name_utf16_len;
+ uint8_t fixed[56];
+
+ uint64_t fid_persistent;
+ uint64_t fid_volatile;
+ struct smb_create_returns cr;
+ struct smb2_create_blobs blobs;
+ struct symlink_reparse_struct *symlink;
+ struct tevent_req *subreq;
+};
+
+static void smb2cli_create_done(struct tevent_req *subreq);
+static bool smb2cli_create_cancel(struct tevent_req *req);
+
+struct tevent_req *smb2cli_create_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ const char *filename,
+ uint8_t oplock_level, /* SMB2_OPLOCK_LEVEL_* */
+ uint32_t impersonation_level, /* SMB2_IMPERSONATION_* */
+ uint32_t desired_access,
+ uint32_t file_attributes,
+ uint32_t share_access,
+ uint32_t create_disposition,
+ uint32_t create_options,
+ struct smb2_create_blobs *blobs)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_create_state *state;
+ uint8_t *fixed;
+ DATA_BLOB blob;
+ NTSTATUS status;
+ size_t blobs_offset;
+ uint8_t *dyn;
+ size_t dyn_len;
+ size_t max_dyn_len;
+ uint32_t additional_flags = 0;
+ uint32_t clear_flags = 0;
+ bool ok;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_create_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->protocol = smbXcli_conn_protocol(conn);
+
+ ok = convert_string_talloc(
+ state,
+ CH_UNIX,
+ CH_UTF16,
+ filename,
+ strlen(filename),
+ &state->name_utf16,
+ &state->name_utf16_len);
+ if (!ok) {
+ tevent_req_oom(req);
+ return tevent_req_post(req, ev);
+ }
+
+ if (strlen(filename) == 0) {
+ TALLOC_FREE(state->name_utf16);
+ state->name_utf16_len = 0;
+ }
+
+ fixed = state->fixed;
+
+ SSVAL(fixed, 0, 57);
+ SCVAL(fixed, 3, oplock_level);
+ SIVAL(fixed, 4, impersonation_level);
+ SIVAL(fixed, 24, desired_access);
+ SIVAL(fixed, 28, file_attributes);
+ SIVAL(fixed, 32, share_access);
+ SIVAL(fixed, 36, create_disposition);
+ SIVAL(fixed, 40, create_options);
+
+ SSVAL(fixed, 44, SMB2_HDR_BODY + 56);
+ SSVAL(fixed, 46, state->name_utf16_len);
+
+ blob = data_blob_null;
+
+ if (blobs != NULL) {
+ status = smb2_create_blob_push(state, &blob, *blobs);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+ }
+
+ blobs_offset = state->name_utf16_len;
+ blobs_offset = ((blobs_offset + 3) & ~3);
+
+ if (blob.length > 0) {
+ blobs_offset = ((blobs_offset + 7) & ~7);
+ SIVAL(fixed, 48, blobs_offset + SMB2_HDR_BODY + 56);
+ SIVAL(fixed, 52, blob.length);
+ }
+
+ dyn_len = MAX(1, blobs_offset + blob.length);
+ dyn = talloc_zero_array(state, uint8_t, dyn_len);
+ if (tevent_req_nomem(dyn, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (state->name_utf16 != NULL) {
+ memcpy(dyn, state->name_utf16, state->name_utf16_len);
+ }
+
+ if (blob.data != NULL) {
+ memcpy(dyn + blobs_offset,
+ blob.data, blob.length);
+ data_blob_free(&blob);
+ }
+
+ if (smbXcli_conn_dfs_supported(conn) &&
+ smbXcli_tcon_is_dfs_share(tcon))
+ {
+ additional_flags |= SMB2_HDR_FLAG_DFS;
+ }
+
+ /*
+ * We use max_dyn_len = 0
+ * as we don't explicitly ask for any output length.
+ *
+ * But it's still possible for the server to return
+ * large create blobs.
+ */
+ max_dyn_len = 0;
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_CREATE,
+ additional_flags, clear_flags,
+ timeout_msec,
+ tcon,
+ session,
+ state->fixed, sizeof(state->fixed),
+ dyn, dyn_len,
+ max_dyn_len);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_create_done, req);
+
+ state->subreq = subreq;
+ tevent_req_set_cancel_fn(req, smb2cli_create_cancel);
+
+ return req;
+}
+
+static bool smb2cli_create_cancel(struct tevent_req *req)
+{
+ struct smb2cli_create_state *state = tevent_req_data(req,
+ struct smb2cli_create_state);
+ return tevent_req_cancel(state->subreq);
+}
+
+/*
+ * [MS-SMB2] 2.2.2.2.1 Symbolic Link Error Response
+ */
+
+static NTSTATUS smb2cli_parse_symlink_error_response(
+ TALLOC_CTX *mem_ctx,
+ const uint8_t *buf,
+ size_t buflen,
+ struct symlink_reparse_struct **psymlink)
+{
+ struct symlink_reparse_struct *symlink = NULL;
+ struct reparse_data_buffer reparse_buf = {
+ .tag = 0,
+ };
+ uint32_t symlink_length, error_tag;
+ NTSTATUS status;
+
+ if (buflen < 8) {
+ DBG_DEBUG("buffer too short: %zu bytes\n", buflen);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ symlink_length = IVAL(buf, 0);
+ if (symlink_length != (buflen-4)) {
+ DBG_DEBUG("symlink_length=%"PRIu32", (buflen-4)=%zu\n",
+ symlink_length, buflen-4);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ error_tag = IVAL(buf, 4);
+ if (error_tag != SYMLINK_ERROR_TAG) {
+ DBG_DEBUG("error_tag=%"PRIu32", expected 0x%x\n",
+ error_tag,
+ SYMLINK_ERROR_TAG);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ symlink = talloc(mem_ctx, struct symlink_reparse_struct);
+ if (symlink == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = reparse_data_buffer_parse(symlink,
+ &reparse_buf,
+ buf + 8,
+ buflen - 8);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_DEBUG("reparse_data_buffer_parse() failed: %s\n",
+ nt_errstr(status));
+ TALLOC_FREE(symlink);
+ return status;
+ }
+
+ if (reparse_buf.tag != IO_REPARSE_TAG_SYMLINK) {
+ DBG_DEBUG("Got tag 0x%" PRIx32 ", "
+ "expected IO_REPARSE_TAG_SYMLINK\n",
+ reparse_buf.tag);
+ TALLOC_FREE(symlink);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ *symlink = reparse_buf.parsed.lnk;
+ *psymlink = symlink;
+ return NT_STATUS_OK;
+}
+
+/*
+ * [MS-SMB2] 2.2.2 ErrorData
+ *
+ * This is in theory a broad API, but as right now we only have a
+ * single [MS-SMB2] 2.2.2.2.1 symlink error response we can return
+ * just this.
+ */
+static NTSTATUS smb2cli_create_error_data_parse(
+ enum protocol_types protocol,
+ uint8_t error_context_count,
+ uint32_t byte_count,
+ const uint8_t *buf,
+ size_t buflen,
+ TALLOC_CTX *mem_ctx,
+ struct symlink_reparse_struct **_symlink)
+{
+ struct symlink_reparse_struct *symlink = NULL;
+ uint32_t error_data_length, error_id;
+ NTSTATUS status;
+
+ if (protocol != PROTOCOL_SMB3_11) {
+ if (error_context_count != 0) {
+ DBG_DEBUG("Got error_context_count=%"PRIu8"\n",
+ error_context_count);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ status = smb2cli_parse_symlink_error_response(
+ mem_ctx, buf, buflen, &symlink);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ *_symlink = symlink;
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * The STOPPED_ON_SYMLINK that I've seen coming from W2k16 has
+ * just a single array element in the [MS-SMB2] 2.2.2
+ * ErrorData array. We'll need to adapt this if there actually
+ * comes an array of multiple ErrorData elements.
+ */
+
+ if (error_context_count != 1) {
+ DBG_DEBUG("Got error_context_count=%"PRIu8"\n",
+ error_context_count);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ if (byte_count != buflen) {
+ DBG_DEBUG("bytecount=%"PRIu32", "
+ "buflen=%zu\n",
+ byte_count,
+ buflen);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ if (buflen < 8) {
+ DBG_DEBUG("buflen=%zu\n", buflen);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ error_data_length = IVAL(buf, 0);
+ if (error_data_length != (buflen - 8)) {
+ DBG_DEBUG("error_data_length=%"PRIu32", expected %zu\n",
+ error_data_length,
+ buflen - 8);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ error_id = IVAL(buf, 4);
+ if (error_id != 0) {
+ DBG_DEBUG("error_id=%"PRIu32", expected 0\n", error_id);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ status = smb2cli_parse_symlink_error_response(
+ mem_ctx, buf + 8, buflen - 8, &symlink);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_DEBUG("smb2cli_parse_symlink_error_response failed: %s\n",
+ nt_errstr(status));
+ return status;
+ }
+
+ *_symlink = symlink;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS smb2cli_create_unparsed_unix_len(
+ size_t unparsed_utf16_len,
+ uint8_t *name_utf16,
+ size_t name_utf16_len,
+ size_t *_unparsed_unix_len)
+{
+ uint8_t *unparsed_utf16 = NULL;
+ uint8_t *unparsed_unix = NULL;
+ size_t unparsed_unix_len = 0;
+ bool ok;
+
+ if (unparsed_utf16_len > name_utf16_len) {
+ DBG_DEBUG("unparsed_utf16_len=%zu, name_utf16_len=%zu\n",
+ unparsed_utf16_len,
+ name_utf16_len);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ if (unparsed_utf16_len == 0) {
+ *_unparsed_unix_len = 0;
+ return NT_STATUS_OK;
+ }
+
+ unparsed_utf16 = name_utf16 + name_utf16_len - unparsed_utf16_len;
+
+ ok = convert_string_talloc(
+ talloc_tos(),
+ CH_UTF16,
+ CH_UNIX,
+ unparsed_utf16,
+ unparsed_utf16_len,
+ &unparsed_unix,
+ &unparsed_unix_len);
+ if (!ok) {
+ NTSTATUS status = map_nt_error_from_unix_common(errno);
+ DBG_DEBUG("convert_string_talloc failed: %s\n",
+ strerror(errno));
+ return status;
+ }
+ *_unparsed_unix_len = unparsed_unix_len;
+ return NT_STATUS_OK;
+}
+
+static void smb2cli_create_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb2cli_create_state *state =
+ tevent_req_data(req,
+ struct smb2cli_create_state);
+ NTSTATUS status;
+ struct iovec *iov;
+ uint8_t *body;
+ uint32_t offset, length;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x59
+ },
+ {
+ .status = NT_STATUS_STOPPED_ON_SYMLINK,
+ .body_size = 0x9,
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, state, &iov,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
+ uint16_t error_context_count = CVAL(iov[1].iov_base, 2);
+ uint32_t byte_count = IVAL(iov[1].iov_base, 4);
+ size_t unparsed_unix_len = 0;
+
+ NTSTATUS symlink_status;
+
+ symlink_status = smb2cli_create_error_data_parse(
+ state->protocol,
+ error_context_count,
+ byte_count,
+ iov[2].iov_base,
+ iov[2].iov_len,
+ state,
+ &state->symlink);
+ if (tevent_req_nterror(req, symlink_status)) {
+ return;
+ }
+
+ /*
+ * Our callers want to know the unparsed length in
+ * unix encoding.
+ */
+ symlink_status = smb2cli_create_unparsed_unix_len(
+ state->symlink->unparsed_path_length,
+ state->name_utf16,
+ state->name_utf16_len,
+ &unparsed_unix_len);
+ if (tevent_req_nterror(req, symlink_status)) {
+ return;
+ }
+ state->symlink->unparsed_path_length = unparsed_unix_len;
+ }
+
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ body = (uint8_t *)iov[1].iov_base;
+
+ state->cr.oplock_level = CVAL(body, 2);
+ state->cr.flags = CVAL(body, 3);
+ state->cr.create_action = IVAL(body, 4);
+ state->cr.creation_time = BVAL(body, 8);
+ state->cr.last_access_time = BVAL(body, 16);
+ state->cr.last_write_time = BVAL(body, 24);
+ state->cr.change_time = BVAL(body, 32);
+ state->cr.allocation_size = BVAL(body, 40);
+ state->cr.end_of_file = BVAL(body, 48);
+ state->cr.file_attributes = IVAL(body, 56);
+ state->fid_persistent = BVAL(body, 64);
+ state->fid_volatile = BVAL(body, 72);
+
+ offset = IVAL(body, 80);
+ length = IVAL(body, 84);
+
+ if ((offset != 0) && (length != 0)) {
+ if ((offset != SMB2_HDR_BODY + 88) ||
+ (length > iov[2].iov_len)) {
+ tevent_req_nterror(
+ req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ status = smb2_create_blob_parse(
+ state, data_blob_const(iov[2].iov_base, length),
+ &state->blobs);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ }
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_create_recv(struct tevent_req *req,
+ uint64_t *fid_persistent,
+ uint64_t *fid_volatile,
+ struct smb_create_returns *cr,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_create_blobs *blobs,
+ struct symlink_reparse_struct **psymlink)
+{
+ struct smb2cli_create_state *state =
+ tevent_req_data(req,
+ struct smb2cli_create_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) &&
+ (psymlink != NULL)) {
+ *psymlink = talloc_move(mem_ctx, &state->symlink);
+ }
+ tevent_req_received(req);
+ return status;
+ }
+ *fid_persistent = state->fid_persistent;
+ *fid_volatile = state->fid_volatile;
+ if (cr) {
+ *cr = state->cr;
+ }
+ if (blobs) {
+ blobs->num_blobs = state->blobs.num_blobs;
+ blobs->blobs = talloc_move(mem_ctx, &state->blobs.blobs);
+ }
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_create(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ const char *filename,
+ uint8_t oplock_level, /* SMB2_OPLOCK_LEVEL_* */
+ uint32_t impersonation_level, /* SMB2_IMPERSONATION_* */
+ uint32_t desired_access,
+ uint32_t file_attributes,
+ uint32_t share_access,
+ uint32_t create_disposition,
+ uint32_t create_options,
+ struct smb2_create_blobs *blobs,
+ uint64_t *fid_persistent,
+ uint64_t *fid_volatile,
+ struct smb_create_returns *cr,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_create_blobs *ret_blobs,
+ struct symlink_reparse_struct **psymlink)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_create_send(frame, ev, conn, timeout_msec,
+ session, tcon,
+ filename, oplock_level,
+ impersonation_level, desired_access,
+ file_attributes, share_access,
+ create_disposition, create_options,
+ blobs);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_create_recv(
+ req,
+ fid_persistent,
+ fid_volatile,
+ cr,
+ mem_ctx,
+ ret_blobs,
+ psymlink);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_echo.c b/libcli/smb/smb2cli_echo.c
new file mode 100644
index 0000000..39c592c
--- /dev/null
+++ b/libcli/smb/smb2cli_echo.c
@@ -0,0 +1,122 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Stefan Metzmacher 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb2cli_echo_state {
+ uint8_t fixed[0x4];
+};
+
+static void smb2cli_echo_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_echo_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_echo_state *state;
+ uint8_t *fixed;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_echo_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ fixed = state->fixed;
+ SSVAL(fixed, 0, 4);
+ SSVAL(fixed, 2, 0);
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_KEEPALIVE,
+ 0, 0, /* flags */
+ timeout_msec,
+ NULL, /* tcon */
+ NULL, /* session */
+ state->fixed, sizeof(state->fixed),
+ NULL, 0, /* dyn* */
+ 0); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_echo_done, req);
+ return req;
+}
+
+static void smb2cli_echo_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ NTSTATUS status;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x04
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, NULL, NULL,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_echo_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS smb2cli_echo(struct smbXcli_conn *conn,
+ uint32_t timeout_msec)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_echo_send(frame, ev, conn, timeout_msec);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_echo_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_flush.c b/libcli/smb/smb2cli_flush.c
new file mode 100644
index 0000000..f014720
--- /dev/null
+++ b/libcli/smb/smb2cli_flush.c
@@ -0,0 +1,133 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Volker Lendecke 2011
+
+ 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb2cli_flush_state {
+ uint8_t fixed[24];
+};
+
+static void smb2cli_flush_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_flush_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_flush_state *state;
+ uint8_t *fixed;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_flush_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ fixed = state->fixed;
+ SSVAL(fixed, 0, 24);
+ SBVAL(fixed, 8, fid_persistent);
+ SBVAL(fixed, 16, fid_volatile);
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_FLUSH,
+ 0, 0, /* flags */
+ timeout_msec,
+ tcon,
+ session,
+ state->fixed, sizeof(state->fixed),
+ NULL, 0, /* dyn* */
+ 0); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_flush_done, req);
+ return req;
+}
+
+static void smb2cli_flush_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ NTSTATUS status;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x04
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, NULL, NULL,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_flush_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS smb2cli_flush(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_flush_send(frame, ev, conn, timeout_msec,
+ session, tcon,
+ fid_persistent, fid_volatile);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_flush_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_ioctl.c b/libcli/smb/smb2cli_ioctl.c
new file mode 100644
index 0000000..2c1d76c
--- /dev/null
+++ b/libcli/smb/smb2cli_ioctl.c
@@ -0,0 +1,519 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Stefan Metzmacher 2011
+
+ 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+#include "librpc/gen_ndr/ndr_ioctl.h"
+
+struct smb2cli_ioctl_state {
+ uint8_t fixed[0x38];
+ uint8_t dyn_pad[1];
+ uint32_t max_input_length;
+ uint32_t max_output_length;
+ struct iovec *recv_iov;
+ bool out_valid;
+ DATA_BLOB out_input_buffer;
+ DATA_BLOB out_output_buffer;
+ uint32_t ctl_code;
+};
+
+static void smb2cli_ioctl_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_ioctl_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile,
+ uint32_t in_ctl_code,
+ uint32_t in_max_input_length,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_max_output_length,
+ const DATA_BLOB *in_output_buffer,
+ uint32_t in_flags)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_ioctl_state *state;
+ uint8_t *fixed;
+ uint8_t *dyn;
+ size_t dyn_len;
+ uint32_t input_buffer_offset = 0;
+ uint32_t input_buffer_length = 0;
+ uint32_t output_buffer_offset = 0;
+ uint32_t output_buffer_length = 0;
+ uint32_t pad_length = 0;
+ uint64_t tmp64;
+ uint32_t max_dyn_len = 0;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_ioctl_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ctl_code = in_ctl_code;
+ state->max_input_length = in_max_input_length;
+ state->max_output_length = in_max_output_length;
+
+ tmp64 = in_max_input_length;
+ tmp64 += in_max_output_length;
+ if (tmp64 > UINT32_MAX) {
+ max_dyn_len = UINT32_MAX;
+ } else {
+ max_dyn_len = tmp64;
+ }
+
+ if (in_input_buffer) {
+ input_buffer_offset = SMB2_HDR_BODY+0x38;
+ input_buffer_length = in_input_buffer->length;
+ }
+
+ if (in_output_buffer) {
+ output_buffer_offset = SMB2_HDR_BODY+0x38;
+ output_buffer_length = in_output_buffer->length;
+ if (input_buffer_length > 0 && output_buffer_length > 0) {
+ uint32_t tmp;
+ output_buffer_offset += input_buffer_length;
+ tmp = output_buffer_offset;
+ output_buffer_offset = NDR_ROUND(output_buffer_offset, 8);
+ pad_length = output_buffer_offset - tmp;
+ }
+ }
+
+ fixed = state->fixed;
+
+ SSVAL(fixed, 0x00, 0x39);
+ SSVAL(fixed, 0x02, 0); /* reserved */
+ SIVAL(fixed, 0x04, in_ctl_code);
+ SBVAL(fixed, 0x08, in_fid_persistent);
+ SBVAL(fixed, 0x10, in_fid_volatile);
+ SIVAL(fixed, 0x18, input_buffer_offset);
+ SIVAL(fixed, 0x1C, input_buffer_length);
+ SIVAL(fixed, 0x20, in_max_input_length);
+ SIVAL(fixed, 0x24, output_buffer_offset);
+ SIVAL(fixed, 0x28, output_buffer_length);
+ SIVAL(fixed, 0x2C, in_max_output_length);
+ SIVAL(fixed, 0x30, in_flags);
+ SIVAL(fixed, 0x34, 0); /* reserved */
+
+ if (input_buffer_length > 0 && output_buffer_length > 0) {
+ size_t avail = UINT32_MAX - (input_buffer_length + pad_length);
+ size_t ofs = output_buffer_offset - input_buffer_offset;
+
+ if (avail < output_buffer_length) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ dyn_len = input_buffer_length + output_buffer_length + pad_length;
+
+ dyn = talloc_zero_array(state, uint8_t, dyn_len);
+ if (tevent_req_nomem(dyn, req)) {
+ return tevent_req_post(req, ev);
+ }
+ memcpy(dyn, in_input_buffer->data,
+ in_input_buffer->length);
+ memcpy(dyn + ofs, in_output_buffer->data,
+ in_output_buffer->length);
+ } else if (input_buffer_length > 0) {
+ dyn = in_input_buffer->data;
+ dyn_len = in_input_buffer->length;
+ } else if (output_buffer_length > 0) {
+ dyn = in_output_buffer->data;
+ dyn_len = in_output_buffer->length;
+ } else {
+ dyn = state->dyn_pad;
+ dyn_len = sizeof(state->dyn_pad);
+ }
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_IOCTL,
+ 0, 0, /* flags */
+ timeout_msec,
+ tcon,
+ session,
+ state->fixed, sizeof(state->fixed),
+ dyn, dyn_len,
+ max_dyn_len);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_ioctl_done, req);
+ return req;
+}
+
+static void smb2cli_ioctl_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb2cli_ioctl_state *state =
+ tevent_req_data(req,
+ struct smb2cli_ioctl_state);
+ NTSTATUS status;
+ NTSTATUS error;
+ struct iovec *iov;
+ uint8_t *fixed;
+ DATA_BLOB dyn_buffer = data_blob_null;
+ uint32_t dyn_ofs = SMB2_HDR_BODY + 0x30;
+ uint32_t input_min_offset;
+ uint32_t input_buffer_offset;
+ uint32_t input_buffer_length;
+ uint32_t input_next_offset;
+ uint32_t output_min_offset;
+ uint32_t output_buffer_offset;
+ uint32_t output_buffer_length;
+ uint32_t output_next_offset;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x31
+ },
+ {
+ .status = STATUS_BUFFER_OVERFLOW,
+ .body_size = 0x31
+ },
+ {
+ /*
+ * We need to make sure that
+ * a response with NT_STATUS_FILE_CLOSED
+ * without signing generates NT_STATUS_ACCESS_DENIED
+ * if the request was signed.
+ */
+ .status = NT_STATUS_FILE_CLOSED,
+ .body_size = 0x09,
+ },
+ {
+ /*
+ * a normal error
+ */
+ .status = NT_STATUS_INVALID_PARAMETER,
+ .body_size = 0x09
+ },
+ {
+ /*
+ * a special case for FSCTL_SRV_COPYCHUNK_*
+ */
+ .status = NT_STATUS_INVALID_PARAMETER,
+ .body_size = 0x31
+ },
+ };
+
+ status = smb2cli_req_recv(subreq, state, &iov,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ switch (state->ctl_code) {
+ case FSCTL_SRV_COPYCHUNK:
+ case FSCTL_SRV_COPYCHUNK_WRITE:
+ break;
+ default:
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ if (iov[1].iov_len != 0x30) {
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ } else if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+ /* no error */
+ } else {
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ }
+
+ /*
+ * At this stage we're sure that got a body size of 0x31,
+ * either with NT_STATUS_OK, STATUS_BUFFER_OVERFLOW or
+ * NT_STATUS_INVALID_PARAMETER.
+ */
+
+ state->recv_iov = iov;
+ fixed = (uint8_t *)iov[1].iov_base;
+ dyn_buffer = data_blob_const((uint8_t *)iov[2].iov_base,
+ iov[2].iov_len);
+
+ input_buffer_offset = IVAL(fixed, 0x18);
+ input_buffer_length = IVAL(fixed, 0x1C);
+ output_buffer_offset = IVAL(fixed, 0x20);
+ output_buffer_length = IVAL(fixed, 0x24);
+
+ input_min_offset = dyn_ofs;
+ input_next_offset = dyn_ofs;
+ error = smb2cli_parse_dyn_buffer(dyn_ofs,
+ dyn_buffer,
+ input_min_offset,
+ input_buffer_offset,
+ input_buffer_length,
+ state->max_input_length,
+ &input_next_offset,
+ &state->out_input_buffer);
+ if (tevent_req_nterror(req, error)) {
+ return;
+ }
+
+ /*
+ * If output data is returned, the output offset MUST be set to
+ * InputOffset + InputCount rounded up to a multiple of 8.
+ */
+ output_min_offset = NDR_ROUND(input_next_offset, 8);
+ output_next_offset = 0; /* this variable is completely ignored */
+ error = smb2cli_parse_dyn_buffer(dyn_ofs,
+ dyn_buffer,
+ output_min_offset,
+ output_buffer_offset,
+ output_buffer_length,
+ state->max_output_length,
+ &output_next_offset,
+ &state->out_output_buffer);
+ if (tevent_req_nterror(req, error)) {
+ return;
+ }
+
+ state->out_valid = true;
+
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_ioctl_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *out_input_buffer,
+ DATA_BLOB *out_output_buffer)
+{
+ struct smb2cli_ioctl_state *state =
+ tevent_req_data(req,
+ struct smb2cli_ioctl_state);
+ NTSTATUS status = NT_STATUS_OK;
+
+ if (tevent_req_is_nterror(req, &status) && !state->out_valid) {
+ if (out_input_buffer) {
+ *out_input_buffer = data_blob_null;
+ }
+ if (out_output_buffer) {
+ *out_output_buffer = data_blob_null;
+ }
+ tevent_req_received(req);
+ return status;
+ }
+
+ talloc_steal(mem_ctx, state->recv_iov);
+ if (out_input_buffer) {
+ *out_input_buffer = state->out_input_buffer;
+ }
+ if (out_output_buffer) {
+ *out_output_buffer = state->out_output_buffer;
+ }
+
+ tevent_req_received(req);
+ return status;
+}
+
+NTSTATUS smb2cli_ioctl(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile,
+ uint32_t in_ctl_code,
+ uint32_t in_max_input_length,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_max_output_length,
+ const DATA_BLOB *in_output_buffer,
+ uint32_t in_flags,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *out_input_buffer,
+ DATA_BLOB *out_output_buffer)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER_MIX;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_ioctl_send(frame, ev, conn, timeout_msec,
+ session, tcon,
+ in_fid_persistent,
+ in_fid_volatile,
+ in_ctl_code,
+ in_max_input_length,
+ in_input_buffer,
+ in_max_output_length,
+ in_output_buffer,
+ in_flags);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_ioctl_recv(req, mem_ctx,
+ out_input_buffer,
+ out_output_buffer);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct smb2cli_ioctl_pipe_wait_state {
+ DATA_BLOB in_blob;
+ DATA_BLOB out_blob;
+};
+
+static void smb2cli_ioctl_pipe_wait_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_ioctl_pipe_wait_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ const char *pipe_name,
+ uint64_t pipe_wait_timeout)
+{
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ struct smb2cli_ioctl_pipe_wait_state *state = NULL;
+ struct fsctl_pipe_wait fsctl = {0};
+ enum ndr_err_code err;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_ioctl_pipe_wait_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->out_blob = data_blob_string_const("");
+
+ fsctl.pipe_name = pipe_name;
+ fsctl.timeout = pipe_wait_timeout;
+ fsctl.timeout_specified = pipe_wait_timeout > 0 ? 1 : 0;
+
+ err = ndr_push_struct_blob(&state->in_blob, mem_ctx, &fsctl,
+ (ndr_push_flags_fn_t)ndr_push_fsctl_pipe_wait);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ return NULL;
+ }
+
+ subreq = smb2cli_ioctl_send(mem_ctx, ev, conn, timeout_msec,
+ session, tcon,
+ UINT64_MAX, UINT64_MAX,
+ FSCTL_PIPE_WAIT,
+ 0, &state->in_blob,
+ 0, &state->out_blob,
+ SMB2_IOCTL_FLAG_IS_FSCTL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(subreq, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_ioctl_pipe_wait_done, req);
+
+ return req;
+}
+
+static void smb2cli_ioctl_pipe_wait_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb2cli_ioctl_pipe_wait_state *state = tevent_req_data(
+ req, struct smb2cli_ioctl_pipe_wait_state);
+ NTSTATUS status;
+
+ status = smb2cli_ioctl_recv(subreq, state, NULL, NULL);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+
+NTSTATUS smb2cli_ioctl_pipe_wait_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_ioctl_pipe_wait(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ const char *pipe_name,
+ uint64_t pipe_wait_timeout)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev = NULL;
+ struct tevent_req *req = NULL;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER_MIX;
+ goto fail;
+ }
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+
+ req = smb2cli_ioctl_pipe_wait_send(frame, ev, conn, timeout_msec,
+ session, tcon,
+ pipe_name, pipe_wait_timeout);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+
+ status = smb2cli_ioctl_pipe_wait_recv(req);
+
+fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_notify.c b/libcli/smb/smb2cli_notify.c
new file mode 100644
index 0000000..9026a6b
--- /dev/null
+++ b/libcli/smb/smb2cli_notify.c
@@ -0,0 +1,236 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Volker Lendecke 2017
+
+ 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+#include "librpc/gen_ndr/ndr_notify.h"
+
+struct smb2cli_notify_state {
+ uint8_t fixed[32];
+
+ struct iovec *recv_iov;
+ uint8_t *data;
+ uint32_t data_length;
+
+ struct tevent_req *subreq;
+ struct tevent_req *timeout_subreq;
+};
+
+static void smb2cli_notify_done(struct tevent_req *subreq);
+static void smb2cli_notify_timedout(struct tevent_req *subreq);
+static bool smb2cli_notify_cancel(struct tevent_req *req);
+
+struct tevent_req *smb2cli_notify_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t output_buffer_length,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint32_t completion_filter,
+ bool recursive)
+{
+ struct tevent_req *req;
+ struct smb2cli_notify_state *state;
+ uint8_t *fixed;
+ uint16_t watch_tree;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_notify_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ watch_tree = recursive ? SMB2_WATCH_TREE : 0;
+ fixed = state->fixed;
+ SSVAL(fixed, 0, 32);
+ SSVAL(fixed, 2, watch_tree);
+ SIVAL(fixed, 4, output_buffer_length);
+ SBVAL(fixed, 8, fid_persistent);
+ SBVAL(fixed, 16, fid_volatile);
+ SIVAL(fixed, 24, completion_filter);
+ SIVAL(fixed, 28, 0); /* reserved */
+
+ state->subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_NOTIFY,
+ 0, 0, /* flags */
+ 0, /* timeout_msec */
+ tcon,
+ session,
+ state->fixed, sizeof(state->fixed),
+ NULL, 0, /* dyn* */
+ 0); /* max_dyn_len */
+ if (tevent_req_nomem(state->subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(state->subreq, smb2cli_notify_done, req);
+
+ if (timeout_msec != 0) {
+ state->timeout_subreq = tevent_wakeup_send(
+ state, ev, timeval_current_ofs_msec(timeout_msec));
+ if (tevent_req_nomem(state->timeout_subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(
+ state->timeout_subreq, smb2cli_notify_timedout, req);
+ }
+
+ tevent_req_set_cancel_fn(req, smb2cli_notify_cancel);
+
+ return req;
+}
+
+static bool smb2cli_notify_cancel(struct tevent_req *req)
+{
+ struct smb2cli_notify_state *state = tevent_req_data(
+ req, struct smb2cli_notify_state);
+ bool ok;
+
+ TALLOC_FREE(state->timeout_subreq);
+
+ ok = tevent_req_cancel(state->subreq);
+ return ok;
+}
+
+static void smb2cli_notify_timedout(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb2cli_notify_state *state = tevent_req_data(
+ req, struct smb2cli_notify_state);
+ bool ok;
+
+ ok = tevent_wakeup_recv(subreq);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return;
+ }
+
+ ok = tevent_req_cancel(state->subreq);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return;
+ }
+}
+
+static void smb2cli_notify_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb2cli_notify_state *state = tevent_req_data(
+ req, struct smb2cli_notify_state);
+ NTSTATUS status;
+ struct iovec *iov;
+ uint16_t data_offset;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x09
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, state, &iov,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) {
+ status = NT_STATUS_IO_TIMEOUT;
+ }
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ data_offset = SVAL(iov[1].iov_base, 2);
+ state->data_length = IVAL(iov[1].iov_base, 4);
+
+ if ((data_offset != SMB2_HDR_BODY + 8) ||
+ (state->data_length > iov[2].iov_len)) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ state->recv_iov = iov;
+ state->data = (uint8_t *)iov[2].iov_base;
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ uint8_t **data, uint32_t *data_length)
+{
+ struct smb2cli_notify_state *state = tevent_req_data(
+ req, struct smb2cli_notify_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ talloc_steal(mem_ctx, state->recv_iov);
+ *data_length = state->data_length;
+ *data = state->data;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_notify(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t output_buffer_length,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint32_t completion_filter,
+ bool recursive,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **data,
+ uint32_t *data_length)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_notify_send(frame, ev, conn, timeout_msec,
+ session, tcon, output_buffer_length,
+ fid_persistent, fid_volatile,
+ completion_filter, recursive);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_notify_recv(req, mem_ctx, data, data_length);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_query_directory.c b/libcli/smb/smb2cli_query_directory.c
new file mode 100644
index 0000000..e6321ff
--- /dev/null
+++ b/libcli/smb/smb2cli_query_directory.c
@@ -0,0 +1,210 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Volker Lendecke 2011
+
+ 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb2cli_query_directory_state {
+ uint8_t fixed[32];
+ uint8_t dyn_pad[1];
+ struct iovec *recv_iov;
+ uint8_t *data;
+ uint32_t data_length;
+};
+
+static void smb2cli_query_directory_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_query_directory_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t level,
+ uint8_t flags,
+ uint32_t file_index,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ const char *mask,
+ uint32_t outbuf_len)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_query_directory_state *state;
+ uint8_t *fixed;
+ uint8_t *dyn;
+ size_t dyn_len;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_query_directory_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (!convert_string_talloc(state, CH_UNIX, CH_UTF16,
+ mask, strlen(mask),
+ &dyn, &dyn_len)) {
+ tevent_req_oom(req);
+ return tevent_req_post(req, ev);
+ }
+
+ if (strlen(mask) == 0) {
+ TALLOC_FREE(dyn);
+ dyn_len = 0;
+ }
+
+ fixed = state->fixed;
+ SSVAL(fixed, 0, 33);
+ SCVAL(fixed, 2, level);
+ SCVAL(fixed, 3, flags);
+ SIVAL(fixed, 4, file_index);
+ SBVAL(fixed, 8, fid_persistent);
+ SBVAL(fixed, 16, fid_volatile);
+ SSVAL(fixed, 24, SMB2_HDR_BODY + 32);
+ SSVAL(fixed, 26, dyn_len);
+ SIVAL(fixed, 28, outbuf_len);
+
+ if (dyn_len == 0) {
+ dyn = state->dyn_pad;
+ dyn_len = sizeof(state->dyn_pad);
+ }
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_QUERY_DIRECTORY,
+ 0, 0, /* flags */
+ timeout_msec,
+ tcon,
+ session,
+ state->fixed, sizeof(state->fixed),
+ dyn, dyn_len,
+ outbuf_len); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_query_directory_done, req);
+ return req;
+}
+
+static void smb2cli_query_directory_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb2cli_query_directory_state *state =
+ tevent_req_data(req,
+ struct smb2cli_query_directory_state);
+ NTSTATUS status;
+ struct iovec *iov;
+ uint16_t data_offset;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x09
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, state, &iov,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ data_offset = SVAL(iov[1].iov_base, 2);
+ state->data_length = IVAL(iov[1].iov_base, 4);
+
+ if ((data_offset != SMB2_HDR_BODY + 8) ||
+ (state->data_length > iov[2].iov_len)) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ state->recv_iov = iov;
+ state->data = (uint8_t *)iov[2].iov_base;
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_query_directory_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **data,
+ uint32_t *data_length)
+{
+ struct smb2cli_query_directory_state *state =
+ tevent_req_data(req,
+ struct smb2cli_query_directory_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ talloc_steal(mem_ctx, state->recv_iov);
+ *data_length = state->data_length;
+ *data = state->data;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_query_directory(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t level,
+ uint8_t flags,
+ uint32_t file_index,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ const char *mask,
+ uint32_t outbuf_len,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **data,
+ uint32_t *data_length)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_query_directory_send(frame, ev, conn, timeout_msec,
+ session, tcon,
+ level, flags,
+ file_index, fid_persistent,
+ fid_volatile, mask, outbuf_len);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_query_directory_recv(req, mem_ctx,
+ data, data_length);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_query_info.c b/libcli/smb/smb2cli_query_info.c
new file mode 100644
index 0000000..d499611
--- /dev/null
+++ b/libcli/smb/smb2cli_query_info.c
@@ -0,0 +1,266 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Stefan Metzmacher 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb2cli_query_info_state {
+ uint8_t fixed[0x28];
+ uint8_t dyn_pad[1];
+ uint32_t max_output_length;
+ struct iovec *recv_iov;
+ DATA_BLOB out_output_buffer;
+ bool out_valid;
+};
+
+static void smb2cli_query_info_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_query_info_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t in_info_type,
+ uint8_t in_file_info_class,
+ uint32_t in_max_output_length,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_additional_info,
+ uint32_t in_flags,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_query_info_state *state;
+ uint8_t *fixed;
+ uint8_t *dyn;
+ size_t dyn_len;
+ uint16_t input_buffer_offset = 0;
+ uint32_t input_buffer_length = 0;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_query_info_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->max_output_length = in_max_output_length;
+
+ if (in_input_buffer) {
+ input_buffer_offset = SMB2_HDR_BODY+0x28;
+ input_buffer_length = in_input_buffer->length;
+ }
+
+ fixed = state->fixed;
+
+ SSVAL(fixed, 0x00, 0x29);
+ SCVAL(fixed, 0x02, in_info_type);
+ SCVAL(fixed, 0x03, in_file_info_class); /* reserved */
+ SIVAL(fixed, 0x04, in_max_output_length);
+ SSVAL(fixed, 0x08, input_buffer_offset);
+ SSVAL(fixed, 0x0A, 0); /* reserved */
+ SIVAL(fixed, 0x0C, input_buffer_length);
+ SIVAL(fixed, 0x10, in_additional_info);
+ SIVAL(fixed, 0x14, in_flags);
+ SBVAL(fixed, 0x18, in_fid_persistent);
+ SBVAL(fixed, 0x20, in_fid_volatile);
+
+ if (input_buffer_length > 0) {
+ dyn = in_input_buffer->data;
+ dyn_len = in_input_buffer->length;
+ } else {
+ dyn = state->dyn_pad;
+ dyn_len = sizeof(state->dyn_pad);
+ }
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_GETINFO,
+ 0, 0, /* flags */
+ timeout_msec,
+ tcon,
+ session,
+ state->fixed, sizeof(state->fixed),
+ dyn, dyn_len,
+ in_max_output_length); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_query_info_done, req);
+ return req;
+}
+
+static void smb2cli_query_info_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb2cli_query_info_state *state =
+ tevent_req_data(req,
+ struct smb2cli_query_info_state);
+ NTSTATUS status;
+ struct iovec *iov;
+ uint8_t *fixed;
+ uint8_t *dyn;
+ size_t dyn_len;
+ uint32_t dyn_ofs = SMB2_HDR_BODY + 0x08;
+ uint32_t output_buffer_offset;
+ uint32_t output_buffer_length;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x09
+ },
+ {
+ .status = STATUS_BUFFER_OVERFLOW,
+ .body_size = 0x09
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, state, &iov,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+ /* no error */
+ } else {
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ }
+
+ state->recv_iov = iov;
+ fixed = (uint8_t *)iov[1].iov_base;
+ dyn = (uint8_t *)iov[2].iov_base;
+ dyn_len = iov[2].iov_len;
+
+ output_buffer_offset = SVAL(fixed, 0x02);
+ output_buffer_length = IVAL(fixed, 0x04);
+
+ if ((output_buffer_offset > 0) && (output_buffer_length > 0)) {
+ if (output_buffer_offset != dyn_ofs) {
+ tevent_req_nterror(
+ req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (output_buffer_length > dyn_len) {
+ tevent_req_nterror(
+ req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (output_buffer_length > state->max_output_length) {
+ tevent_req_nterror(
+ req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ state->out_output_buffer.data = dyn;
+ state->out_output_buffer.length = output_buffer_length;
+ }
+
+ state->out_valid = true;
+
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_query_info_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *out_output_buffer)
+{
+ struct smb2cli_query_info_state *state =
+ tevent_req_data(req,
+ struct smb2cli_query_info_state);
+ NTSTATUS status = NT_STATUS_OK;
+
+ if (tevent_req_is_nterror(req, &status) && !state->out_valid) {
+ if (out_output_buffer) {
+ *out_output_buffer = data_blob_null;
+ }
+ tevent_req_received(req);
+ return status;
+ }
+
+ talloc_steal(mem_ctx, state->recv_iov);
+ if (out_output_buffer) {
+ *out_output_buffer = state->out_output_buffer;
+ }
+
+ tevent_req_received(req);
+ return status;
+}
+
+NTSTATUS smb2cli_query_info(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t in_info_type,
+ uint8_t in_file_info_class,
+ uint32_t in_max_output_length,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_additional_info,
+ uint32_t in_flags,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *out_output_buffer)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER_MIX;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_query_info_send(frame, ev,
+ conn, timeout_msec,
+ session, tcon,
+ in_info_type,
+ in_file_info_class,
+ in_max_output_length,
+ in_input_buffer,
+ in_additional_info,
+ in_flags,
+ in_fid_persistent,
+ in_fid_volatile);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_query_info_recv(req, mem_ctx,
+ out_output_buffer);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_read.c b/libcli/smb/smb2cli_read.c
new file mode 100644
index 0000000..c7f4874
--- /dev/null
+++ b/libcli/smb/smb2cli_read.c
@@ -0,0 +1,218 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Volker Lendecke 2011
+
+ 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb2cli_read_state {
+ uint8_t fixed[48];
+ uint8_t dyn_pad[1];
+ struct iovec *recv_iov;
+ uint8_t *data;
+ uint32_t data_length;
+ bool out_valid;
+};
+
+static void smb2cli_read_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_read_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t length,
+ uint64_t offset,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint64_t minimum_count,
+ uint64_t remaining_bytes)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_read_state *state;
+ uint8_t *fixed;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_read_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ fixed = state->fixed;
+
+ SSVAL(fixed, 0, 49);
+ SIVAL(fixed, 4, length);
+ SBVAL(fixed, 8, offset);
+ SBVAL(fixed, 16, fid_persistent);
+ SBVAL(fixed, 24, fid_volatile);
+ SBVAL(fixed, 32, minimum_count);
+ SBVAL(fixed, 40, remaining_bytes);
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_READ,
+ 0, 0, /* flags */
+ timeout_msec,
+ tcon,
+ session,
+ state->fixed, sizeof(state->fixed),
+ state->dyn_pad, sizeof(state->dyn_pad),
+ length); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_read_done, req);
+ return req;
+}
+
+static void smb2cli_read_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb2cli_read_state *state =
+ tevent_req_data(req,
+ struct smb2cli_read_state);
+ NTSTATUS status;
+ NTSTATUS error;
+ struct iovec *iov;
+ const uint8_t dyn_ofs = SMB2_HDR_BODY + 0x10;
+ DATA_BLOB dyn_buffer = data_blob_null;
+ uint8_t data_offset;
+ DATA_BLOB data_buffer = data_blob_null;
+ uint32_t next_offset = 0; /* this variable is completely ignored */
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = STATUS_BUFFER_OVERFLOW,
+ .body_size = 0x11
+ },
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x11
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, state, &iov,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+ /* no error */
+ } else {
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ }
+
+ data_offset = CVAL(iov[1].iov_base, 2);
+ state->data_length = IVAL(iov[1].iov_base, 4);
+
+ dyn_buffer = data_blob_const((uint8_t *)iov[2].iov_base,
+ iov[2].iov_len);
+
+ error = smb2cli_parse_dyn_buffer(dyn_ofs,
+ dyn_buffer,
+ dyn_ofs, /* min_offset */
+ data_offset,
+ state->data_length,
+ dyn_buffer.length, /* max_length */
+ &next_offset,
+ &data_buffer);
+ if (tevent_req_nterror(req, error)) {
+ return;
+ }
+
+ state->recv_iov = iov;
+ state->data = data_buffer.data;
+
+ state->out_valid = true;
+
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ uint8_t **data, uint32_t *data_length)
+{
+ struct smb2cli_read_state *state =
+ tevent_req_data(req,
+ struct smb2cli_read_state);
+ NTSTATUS status = NT_STATUS_OK;
+
+ if (tevent_req_is_nterror(req, &status) && !state->out_valid) {
+ *data_length = 0;
+ *data = NULL;
+ tevent_req_received(req);
+ return status;
+ }
+ talloc_steal(mem_ctx, state->recv_iov);
+ *data_length = state->data_length;
+ *data = state->data;
+ tevent_req_received(req);
+ return status;
+}
+
+NTSTATUS smb2cli_read(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t length,
+ uint64_t offset,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint64_t minimum_count,
+ uint64_t remaining_bytes,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **data,
+ uint32_t *data_length)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_read_send(frame, ev,
+ conn, timeout_msec, session, tcon,
+ length, offset,
+ fid_persistent, fid_volatile,
+ minimum_count, remaining_bytes);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_read_recv(req, mem_ctx, data, data_length);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_session.c b/libcli/smb/smb2cli_session.c
new file mode 100644
index 0000000..65a604a
--- /dev/null
+++ b/libcli/smb/smb2cli_session.c
@@ -0,0 +1,350 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Volker Lendecke 2011
+
+ 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 "system/network.h"
+#include "../lib/util/tevent_ntstatus.h"
+#include "../libcli/smb/smb_common.h"
+#include "../libcli/smb/smbXcli_base.h"
+
+struct smb2cli_session_setup_state {
+ struct smbXcli_session *session;
+ uint8_t fixed[24];
+ uint8_t dyn_pad[1];
+ struct iovec *recv_iov;
+ DATA_BLOB out_security_buffer;
+ NTSTATUS status;
+};
+
+static void smb2cli_session_setup_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_session_setup_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ uint8_t in_flags,
+ uint32_t in_capabilities,
+ uint32_t in_channel,
+ uint64_t in_previous_session_id,
+ const DATA_BLOB *in_security_buffer)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_session_setup_state *state;
+ uint8_t *buf;
+ uint8_t *dyn;
+ size_t dyn_len;
+ uint8_t security_mode;
+ uint16_t security_buffer_offset = 0;
+ uint16_t security_buffer_length = 0;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_session_setup_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (session == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+ state->session = session;
+ security_mode = smb2cli_session_security_mode(session);
+
+ if (in_security_buffer) {
+ if (in_security_buffer->length > UINT16_MAX) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+ security_buffer_offset = SMB2_HDR_BODY + 24;
+ security_buffer_length = in_security_buffer->length;
+ }
+
+ buf = state->fixed;
+
+ SSVAL(buf, 0, 25);
+ SCVAL(buf, 2, in_flags);
+ SCVAL(buf, 3, security_mode);
+ SIVAL(buf, 4, in_capabilities);
+ SIVAL(buf, 8, in_channel);
+ SSVAL(buf, 12, security_buffer_offset);
+ SSVAL(buf, 14, security_buffer_length);
+ SBVAL(buf, 16, in_previous_session_id);
+
+ if (security_buffer_length > 0) {
+ dyn = in_security_buffer->data;
+ dyn_len = in_security_buffer->length;
+ } else {
+ dyn = state->dyn_pad;;
+ dyn_len = sizeof(state->dyn_pad);
+ }
+
+ subreq = smb2cli_req_send(state, ev,
+ conn, SMB2_OP_SESSSETUP,
+ 0, 0, /* flags */
+ timeout_msec,
+ NULL, /* tcon */
+ session,
+ state->fixed, sizeof(state->fixed),
+ dyn, dyn_len,
+ UINT16_MAX); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_session_setup_done, req);
+ return req;
+}
+
+static void smb2cli_session_setup_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb2cli_session_setup_state *state =
+ tevent_req_data(req,
+ struct smb2cli_session_setup_state);
+ NTSTATUS status;
+ NTSTATUS preauth_status;
+ uint64_t current_session_id;
+ uint64_t session_id;
+ uint16_t session_flags;
+ uint16_t expected_offset = 0;
+ uint16_t security_buffer_offset;
+ uint16_t security_buffer_length;
+ uint8_t *security_buffer_data = NULL;
+ struct iovec sent_iov[3];
+ const uint8_t *hdr;
+ const uint8_t *body;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_MORE_PROCESSING_REQUIRED,
+ .body_size = 0x09
+ },
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x09
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, state, &state->recv_iov,
+ expected, ARRAY_SIZE(expected));
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ smb2cli_req_get_sent_iov(subreq, sent_iov);
+ preauth_status = smb2cli_session_update_preauth(state->session, sent_iov);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, preauth_status)) {
+ return;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ preauth_status = smb2cli_session_update_preauth(state->session,
+ state->recv_iov);
+ if (tevent_req_nterror(req, preauth_status)) {
+ return;
+ }
+ }
+
+ hdr = (const uint8_t *)state->recv_iov[0].iov_base;
+ body = (const uint8_t *)state->recv_iov[1].iov_base;
+
+ session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
+ session_flags = SVAL(body, 2);
+
+ security_buffer_offset = SVAL(body, 4);
+ security_buffer_length = SVAL(body, 6);
+
+ if (security_buffer_length > 0) {
+ expected_offset = SMB2_HDR_BODY + 8;
+ }
+ if (security_buffer_offset != 0) {
+ security_buffer_data = (uint8_t *)state->recv_iov[2].iov_base;
+ expected_offset = SMB2_HDR_BODY + 8;
+ }
+
+ if (security_buffer_offset != expected_offset) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ if (security_buffer_length > state->recv_iov[2].iov_len) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ state->out_security_buffer.data = security_buffer_data;
+ state->out_security_buffer.length = security_buffer_length;
+
+ current_session_id = smb2cli_session_current_id(state->session);
+ if (current_session_id == 0) {
+ /* A new session was requested */
+ current_session_id = session_id;
+ }
+
+ if (current_session_id != session_id) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ smb2cli_session_set_id_and_flags(state->session,
+ session_id, session_flags);
+
+ state->status = status;
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_session_setup_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **recv_iov,
+ DATA_BLOB *out_security_buffer)
+{
+ struct smb2cli_session_setup_state *state =
+ tevent_req_data(req,
+ struct smb2cli_session_setup_state);
+ NTSTATUS status;
+ struct iovec *_tmp;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ if (recv_iov == NULL) {
+ recv_iov = &_tmp;
+ }
+
+ *recv_iov = talloc_move(mem_ctx, &state->recv_iov);
+
+ *out_security_buffer = state->out_security_buffer;
+
+ /*
+ * Return the status from the server:
+ * NT_STATUS_MORE_PROCESSING_REQUIRED or
+ * NT_STATUS_OK.
+ */
+ status = state->status;
+ tevent_req_received(req);
+ return status;
+}
+
+struct smb2cli_logoff_state {
+ uint8_t fixed[4];
+};
+
+static void smb2cli_logoff_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_logoff_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_logoff_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_logoff_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ SSVAL(state->fixed, 0, 4);
+
+ subreq = smb2cli_req_send(state, ev,
+ conn, SMB2_OP_LOGOFF,
+ 0, 0, /* flags */
+ timeout_msec,
+ NULL, /* tcon */
+ session,
+ state->fixed, sizeof(state->fixed),
+ NULL, 0, /* dyn* */
+ 0); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_logoff_done, req);
+ return req;
+}
+
+static void smb2cli_logoff_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb2cli_logoff_state *state =
+ tevent_req_data(req,
+ struct smb2cli_logoff_state);
+ NTSTATUS status;
+ struct iovec *iov;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x04
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, state, &iov,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_logoff_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS smb2cli_logoff(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_logoff_send(frame, ev, conn, timeout_msec, session);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_logoff_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_set_info.c b/libcli/smb/smb2cli_set_info.c
new file mode 100644
index 0000000..6871370
--- /dev/null
+++ b/libcli/smb/smb2cli_set_info.c
@@ -0,0 +1,183 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Stefan Metzmacher 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb2cli_set_info_state {
+ uint8_t fixed[0x20];
+ uint8_t dyn_pad[1];
+};
+
+static void smb2cli_set_info_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_set_info_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t in_info_type,
+ uint8_t in_file_info_class,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_additional_info,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_set_info_state *state;
+ uint8_t *fixed;
+ uint8_t *dyn;
+ size_t dyn_len;
+ uint16_t input_buffer_offset = 0;
+ uint32_t input_buffer_length = 0;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_set_info_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (in_input_buffer) {
+ input_buffer_offset = SMB2_HDR_BODY+0x20;
+ input_buffer_length = in_input_buffer->length;
+ }
+
+ fixed = state->fixed;
+
+ SSVAL(fixed, 0x00, 0x21);
+ SCVAL(fixed, 0x02, in_info_type);
+ SCVAL(fixed, 0x03, in_file_info_class);
+ SIVAL(fixed, 0x04, input_buffer_length);
+ SSVAL(fixed, 0x08, input_buffer_offset);
+ SSVAL(fixed, 0x0A, 0); /* reserved */
+ SIVAL(fixed, 0x0C, in_additional_info);
+ SBVAL(fixed, 0x10, in_fid_persistent);
+ SBVAL(fixed, 0x18, in_fid_volatile);
+
+ if (input_buffer_length > 0) {
+ dyn = in_input_buffer->data;
+ dyn_len = in_input_buffer->length;
+ } else {
+ dyn = state->dyn_pad;
+ dyn_len = sizeof(state->dyn_pad);
+ }
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_SETINFO,
+ 0, 0, /* flags */
+ timeout_msec,
+ tcon,
+ session,
+ state->fixed, sizeof(state->fixed),
+ dyn, dyn_len,
+ 0); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_set_info_done, req);
+ return req;
+}
+
+static void smb2cli_set_info_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ NTSTATUS status;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x02
+ },
+ };
+
+ status = smb2cli_req_recv(subreq, NULL, NULL,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_set_info_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_set_info(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t in_info_type,
+ uint8_t in_file_info_class,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_additional_info,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER_MIX;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_set_info_send(frame, ev,
+ conn, timeout_msec,
+ session, tcon,
+ in_info_type,
+ in_file_info_class,
+ in_input_buffer,
+ in_additional_info,
+ in_fid_persistent,
+ in_fid_volatile);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_set_info_recv(req);
+
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_tcon.c b/libcli/smb/smb2cli_tcon.c
new file mode 100644
index 0000000..d5e4fc3
--- /dev/null
+++ b/libcli/smb/smb2cli_tcon.c
@@ -0,0 +1,461 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Volker Lendecke 2011
+
+ 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 "system/network.h"
+#include "../lib/util/tevent_ntstatus.h"
+#include "../libcli/smb/smb_common.h"
+#include "../libcli/smb/smbXcli_base.h"
+
+struct smb2cli_raw_tcon_state {
+ struct smbXcli_session *session;
+ struct smbXcli_tcon *tcon;
+ uint8_t fixed[8];
+ uint8_t dyn_pad[1];
+};
+
+static void smb2cli_raw_tcon_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_raw_tcon_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t additional_flags,
+ uint32_t clear_flags,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t tcon_flags,
+ const char *unc)
+{
+ struct tevent_req *req = NULL;
+ struct smb2cli_raw_tcon_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+ uint8_t *fixed = NULL;
+ uint8_t *dyn = NULL;
+ size_t dyn_len;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_raw_tcon_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->session = session;
+ state->tcon = tcon;
+
+ if (!convert_string_talloc(state, CH_UNIX, CH_UTF16,
+ unc, strlen(unc),
+ &dyn, &dyn_len)) {
+ tevent_req_oom(req);
+ return tevent_req_post(req, ev);
+ }
+
+ if (strlen(unc) == 0) {
+ TALLOC_FREE(dyn);
+ dyn_len = 0;
+ }
+
+ fixed = state->fixed;
+ SSVAL(fixed, 0, 9);
+ if (smbXcli_conn_protocol(conn) >= PROTOCOL_SMB3_11) {
+ SSVAL(fixed, 2, tcon_flags);
+ } else {
+ SSVAL(fixed, 2, 0); /* Reserved */
+ }
+ SSVAL(fixed, 4, SMB2_HDR_BODY + 8);
+ SSVAL(fixed, 6, dyn_len);
+
+ if (dyn_len == 0) {
+ dyn = state->dyn_pad;
+ dyn_len = sizeof(state->dyn_pad);
+ }
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_TCON,
+ additional_flags, clear_flags,
+ timeout_msec,
+ NULL, /* tcon */
+ session,
+ state->fixed, sizeof(state->fixed),
+ dyn, dyn_len,
+ 0); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_raw_tcon_done, req);
+
+ return req;
+}
+
+static void smb2cli_raw_tcon_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb2cli_raw_tcon_state *state = tevent_req_data(
+ req, struct smb2cli_raw_tcon_state);
+ NTSTATUS status;
+ struct iovec *iov;
+ uint8_t *body;
+ uint32_t tcon_id;
+ uint8_t share_type;
+ uint32_t share_flags;
+ uint32_t share_capabilities;
+ uint32_t maximal_access;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x10
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, state, &iov,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ tcon_id = IVAL(iov[0].iov_base, SMB2_HDR_TID);
+
+ body = (uint8_t *)iov[1].iov_base;
+ share_type = CVAL(body, 0x02);
+ share_flags = IVAL(body, 0x04);
+ share_capabilities = IVAL(body, 0x08);
+ maximal_access = IVAL(body, 0x0C);
+
+ smb2cli_tcon_set_values(state->tcon,
+ state->session,
+ tcon_id,
+ share_type,
+ share_flags,
+ share_capabilities,
+ maximal_access);
+
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_raw_tcon_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS smb2cli_raw_tcon(struct smbXcli_conn *conn,
+ uint32_t additional_flags,
+ uint32_t clear_flags,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t tcon_flags,
+ const char *unc)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_raw_tcon_send(frame, ev, conn,
+ additional_flags, clear_flags,
+ timeout_msec, session, tcon,
+ tcon_flags, unc);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_raw_tcon_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct smb2cli_tcon_state {
+ struct tevent_context *ev;
+ struct smbXcli_conn *conn;
+ uint32_t timeout_msec;
+ struct smbXcli_session *session;
+ struct smbXcli_tcon *tcon;
+ uint8_t fixed[8];
+ uint8_t dyn_pad[1];
+};
+
+static void smb2cli_tcon_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_tcon_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t flags,
+ const char *unc)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_tcon_state *state;
+ uint32_t additional_flags = 0;
+ uint32_t clear_flags = 0;
+
+ req = tevent_req_create(mem_ctx, &state, struct smb2cli_tcon_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->conn = conn;
+ state->timeout_msec = timeout_msec;
+ state->session = session;
+ state->tcon = tcon;
+
+ if (smbXcli_session_is_authenticated(state->session)) {
+ additional_flags |= SMB2_HDR_FLAG_SIGNED;
+ }
+
+ subreq = smb2cli_raw_tcon_send(state,
+ state->ev,
+ state->conn,
+ additional_flags,
+ clear_flags,
+ state->timeout_msec,
+ state->session,
+ state->tcon,
+ flags,
+ unc);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_tcon_done, req);
+
+ return req;
+}
+
+static void smb2cli_tcon_validate(struct tevent_req *subreq);
+
+static void smb2cli_tcon_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb2cli_tcon_state *state = tevent_req_data(
+ req, struct smb2cli_tcon_state);
+ NTSTATUS status;
+
+ status = smb2cli_raw_tcon_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (!smbXcli_session_is_authenticated(state->session)) {
+ tevent_req_done(req);
+ return;
+ }
+
+ if (smbXcli_conn_protocol(state->conn) >= PROTOCOL_SMB3_11) {
+ tevent_req_done(req);
+ return;
+ }
+
+ subreq = smb2cli_validate_negotiate_info_send(state, state->ev,
+ state->conn,
+ state->timeout_msec,
+ state->session,
+ state->tcon);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, smb2cli_tcon_validate, req);
+}
+
+static void smb2cli_tcon_validate(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb2cli_tcon_state *state = tevent_req_data(
+ req, struct smb2cli_tcon_state);
+ NTSTATUS status;
+
+ status = smb2cli_validate_negotiate_info_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ smb2cli_tcon_set_values(state->tcon, NULL,
+ UINT32_MAX, 0, 0, 0, 0);
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_tcon_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS smb2cli_tcon(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t flags,
+ const char *unc)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_tcon_send(frame, ev, conn,
+ timeout_msec, session, tcon,
+ flags, unc);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_tcon_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct smb2cli_tdis_state {
+ struct smbXcli_tcon *tcon;
+ uint8_t fixed[4];
+};
+
+static void smb2cli_tdis_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_tdis_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_tdis_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_tdis_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->tcon = tcon;
+
+ SSVAL(state->fixed, 0, 4);
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_TDIS,
+ 0, 0, /* flags */
+ timeout_msec,
+ tcon, session,
+ state->fixed, sizeof(state->fixed),
+ NULL, 0, /* dyn* */
+ 0); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_tdis_done, req);
+ return req;
+}
+
+static void smb2cli_tdis_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb2cli_tdis_state *state =
+ tevent_req_data(req,
+ struct smb2cli_tdis_state);
+ NTSTATUS status;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x04
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, NULL, NULL,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ smb2cli_tcon_set_values(state->tcon, NULL,
+ UINT32_MAX, 0, 0, 0, 0);
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_tdis_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS smb2cli_tdis(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_tdis_send(frame, ev, conn,
+ timeout_msec, session, tcon);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_tdis_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_write.c b/libcli/smb/smb2cli_write.c
new file mode 100644
index 0000000..6d0a0aa
--- /dev/null
+++ b/libcli/smb/smb2cli_write.c
@@ -0,0 +1,183 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Volker Lendecke 2011
+
+ 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb2cli_write_state {
+ uint8_t fixed[48];
+ uint8_t dyn_pad[1];
+ uint32_t written;
+};
+
+static void smb2cli_write_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_write_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t length,
+ uint64_t offset,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint32_t remaining_bytes,
+ uint32_t flags,
+ const uint8_t *data)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_write_state *state;
+ uint8_t *fixed;
+ const uint8_t *dyn;
+ size_t dyn_len;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_write_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ fixed = state->fixed;
+
+ SSVAL(fixed, 0, 49);
+ SSVAL(fixed, 2, SMB2_HDR_BODY + 48);
+ SIVAL(fixed, 4, length);
+ SBVAL(fixed, 8, offset);
+ SBVAL(fixed, 16, fid_persistent);
+ SBVAL(fixed, 24, fid_volatile);
+ SIVAL(fixed, 36, remaining_bytes);
+ SIVAL(fixed, 44, flags);
+
+ if (length > 0) {
+ dyn = data;
+ dyn_len = length;
+ } else {
+ dyn = state->dyn_pad;;
+ dyn_len = sizeof(state->dyn_pad);
+ }
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_WRITE,
+ 0, 0, /* flags */
+ timeout_msec,
+ tcon,
+ session,
+ state->fixed, sizeof(state->fixed),
+ dyn, dyn_len,
+ 0); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_write_done, req);
+ return req;
+}
+
+static void smb2cli_write_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb2cli_write_state *state =
+ tevent_req_data(req,
+ struct smb2cli_write_state);
+ NTSTATUS status;
+ struct iovec *iov;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x11
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, state, &iov,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ state->written = IVAL(iov[1].iov_base, 4);
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_write_recv(struct tevent_req *req, uint32_t *written)
+{
+ struct smb2cli_write_state *state =
+ tevent_req_data(req,
+ struct smb2cli_write_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+ if (written) {
+ *written = state->written;
+ }
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_write(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t length,
+ uint64_t offset,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint32_t remaining_bytes,
+ uint32_t flags,
+ const uint8_t *data,
+ uint32_t *written)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_write_send(frame, ev, conn, timeout_msec,
+ session, tcon,
+ length, offset,
+ fid_persistent, fid_volatile,
+ remaining_bytes, flags, data);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_write_recv(req, written);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
new file mode 100644
index 0000000..a52a615
--- /dev/null
+++ b/libcli/smb/smbXcli_base.c
@@ -0,0 +1,7034 @@
+/*
+ Unix SMB/CIFS implementation.
+ Infrastructure for async SMB client requests
+ Copyright (C) Volker Lendecke 2008
+ Copyright (C) Stefan Metzmacher 2011
+
+ 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 "system/network.h"
+#include "../lib/async_req/async_sock.h"
+#include "../lib/util/tevent_ntstatus.h"
+#include "../lib/util/tevent_unix.h"
+#include "lib/util/util_net.h"
+#include "lib/util/dlinklist.h"
+#include "lib/util/iov_buf.h"
+#include "../libcli/smb/smb_common.h"
+#include "../libcli/smb/smb_seal.h"
+#include "../libcli/smb/smb_signing.h"
+#include "../libcli/smb/read_smb.h"
+#include "smbXcli_base.h"
+#include "librpc/ndr/libndr.h"
+#include "libcli/smb/smb2_negotiate_context.h"
+#include "libcli/smb/smb2_signing.h"
+
+#include "lib/crypto/gnutls_helpers.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+struct smbXcli_conn;
+struct smbXcli_req;
+struct smbXcli_session;
+struct smbXcli_tcon;
+
+struct smbXcli_conn {
+ int sock_fd;
+ struct sockaddr_storage local_ss;
+ struct sockaddr_storage remote_ss;
+ const char *remote_name;
+
+ struct tevent_queue *outgoing;
+ struct tevent_req **pending;
+ struct tevent_req *read_smb_req;
+ struct tevent_req *suicide_req;
+
+ enum protocol_types min_protocol;
+ enum protocol_types max_protocol;
+ enum protocol_types protocol;
+ bool allow_signing;
+ bool desire_signing;
+ bool mandatory_signing;
+
+ /*
+ * The incoming dispatch function should return:
+ * - NT_STATUS_RETRY, if more incoming PDUs are expected.
+ * - NT_STATUS_OK, if no more processing is desired, e.g.
+ * the dispatch function called
+ * tevent_req_done().
+ * - All other return values disconnect the connection.
+ */
+ NTSTATUS (*dispatch_incoming)(struct smbXcli_conn *conn,
+ TALLOC_CTX *tmp_mem,
+ uint8_t *inbuf);
+
+ struct {
+ struct {
+ uint32_t capabilities;
+ uint32_t max_xmit;
+ } client;
+
+ struct {
+ uint32_t capabilities;
+ uint32_t max_xmit;
+ uint16_t max_mux;
+ uint16_t security_mode;
+ bool readbraw;
+ bool writebraw;
+ bool lockread;
+ bool writeunlock;
+ uint32_t session_key;
+ struct GUID guid;
+ DATA_BLOB gss_blob;
+ uint8_t challenge[8];
+ const char *workgroup;
+ const char *name;
+ int time_zone;
+ NTTIME system_time;
+ } server;
+
+ uint32_t capabilities;
+ uint32_t max_xmit;
+
+ uint16_t mid;
+
+ struct smb1_signing_state *signing;
+ struct smb_trans_enc_state *trans_enc;
+
+ struct tevent_req *read_braw_req;
+ } smb1;
+
+ struct {
+ struct {
+ uint32_t capabilities;
+ uint16_t security_mode;
+ struct GUID guid;
+ struct smb311_capabilities smb3_capabilities;
+ } client;
+
+ struct {
+ uint32_t capabilities;
+ uint16_t security_mode;
+ struct GUID guid;
+ uint32_t max_trans_size;
+ uint32_t max_read_size;
+ uint32_t max_write_size;
+ NTTIME system_time;
+ NTTIME start_time;
+ DATA_BLOB gss_blob;
+ uint16_t sign_algo;
+ uint16_t cipher;
+ bool smb311_posix;
+ } server;
+
+ uint64_t mid;
+ uint16_t cur_credits;
+ uint16_t max_credits;
+
+ uint32_t cc_chunk_len;
+ uint32_t cc_max_chunks;
+
+ uint8_t io_priority;
+
+ bool force_channel_sequence;
+
+ uint8_t preauth_sha512[64];
+ } smb2;
+
+ struct smbXcli_session *sessions;
+};
+
+struct smb2cli_session {
+ uint64_t session_id;
+ uint16_t session_flags;
+ struct smb2_signing_key *application_key;
+ struct smb2_signing_key *signing_key;
+ bool should_sign;
+ bool should_encrypt;
+ struct smb2_signing_key *encryption_key;
+ struct smb2_signing_key *decryption_key;
+ uint64_t nonce_high_random;
+ uint64_t nonce_high_max;
+ uint64_t nonce_high;
+ uint64_t nonce_low;
+ uint16_t channel_sequence;
+ bool replay_active;
+ bool require_signed_response;
+};
+
+struct smbXcli_session {
+ struct smbXcli_session *prev, *next;
+ struct smbXcli_conn *conn;
+
+ struct {
+ uint16_t session_id;
+ uint16_t action;
+ DATA_BLOB application_key;
+ bool protected_key;
+ } smb1;
+
+ struct smb2cli_session *smb2;
+
+ struct {
+ struct smb2_signing_key *signing_key;
+ uint8_t preauth_sha512[64];
+ } smb2_channel;
+
+ /*
+ * this should be a short term hack
+ * until the upper layers have implemented
+ * re-authentication.
+ */
+ bool disconnect_expired;
+};
+
+struct smbXcli_tcon {
+ bool is_smb1;
+ uint32_t fs_attributes;
+
+ struct {
+ uint16_t tcon_id;
+ uint16_t optional_support;
+ uint32_t maximal_access;
+ uint32_t guest_maximal_access;
+ char *service;
+ char *fs_type;
+ } smb1;
+
+ struct {
+ uint32_t tcon_id;
+ uint8_t type;
+ uint32_t flags;
+ uint32_t capabilities;
+ uint32_t maximal_access;
+ bool should_sign;
+ bool should_encrypt;
+ } smb2;
+};
+
+struct smbXcli_req_state {
+ struct tevent_context *ev;
+ struct smbXcli_conn *conn;
+ struct smbXcli_session *session; /* maybe NULL */
+ struct smbXcli_tcon *tcon; /* maybe NULL */
+
+ uint8_t length_hdr[4];
+
+ bool one_way;
+
+ uint8_t *inbuf;
+
+ struct tevent_req *write_req;
+
+ struct timeval endtime;
+
+ struct {
+ /* Space for the header including the wct */
+ uint8_t hdr[HDR_VWV];
+
+ /*
+ * For normal requests, smb1cli_req_send chooses a mid.
+ * SecondaryV trans requests need to use the mid of the primary
+ * request, so we need a place to store it.
+ * Assume it is set if != 0.
+ */
+ uint16_t mid;
+
+ uint16_t *vwv;
+ uint8_t bytecount_buf[2];
+
+#define MAX_SMB_IOV 10
+ /* length_hdr, hdr, words, byte_count, buffers */
+ struct iovec iov[1 + 3 + MAX_SMB_IOV];
+ int iov_count;
+
+ bool one_way_seqnum;
+ uint32_t seqnum;
+ struct tevent_req **chained_requests;
+
+ uint8_t recv_cmd;
+ NTSTATUS recv_status;
+ /* always an array of 3 talloc elements */
+ struct iovec *recv_iov;
+ } smb1;
+
+ struct {
+ const uint8_t *fixed;
+ uint16_t fixed_len;
+ const uint8_t *dyn;
+ uint32_t dyn_len;
+
+ uint8_t transform[SMB2_TF_HDR_SIZE];
+ uint8_t hdr[SMB2_HDR_BODY];
+ uint8_t pad[7]; /* padding space for compounding */
+
+ /*
+ * always an array of 3 talloc elements
+ * (without a SMB2_TRANSFORM header!)
+ *
+ * HDR, BODY, DYN
+ */
+ struct iovec *recv_iov;
+
+ /*
+ * the expected max for the response dyn_len
+ */
+ uint32_t max_dyn_len;
+
+ uint16_t credit_charge;
+
+ bool should_sign;
+ bool should_encrypt;
+ uint64_t encryption_session_id;
+
+ bool signing_skipped;
+ bool require_signed_response;
+ bool notify_async;
+ bool got_async;
+ uint16_t cancel_flags;
+ uint64_t cancel_mid;
+ uint64_t cancel_aid;
+ } smb2;
+};
+
+static int smbXcli_conn_destructor(struct smbXcli_conn *conn)
+{
+ /*
+ * NT_STATUS_OK, means we do not notify the callers
+ */
+ smbXcli_conn_disconnect(conn, NT_STATUS_OK);
+
+ while (conn->sessions) {
+ conn->sessions->conn = NULL;
+ DLIST_REMOVE(conn->sessions, conn->sessions);
+ }
+
+ if (conn->smb1.trans_enc) {
+ TALLOC_FREE(conn->smb1.trans_enc);
+ }
+
+ return 0;
+}
+
+struct smbXcli_conn *smbXcli_conn_create(TALLOC_CTX *mem_ctx,
+ int fd,
+ const char *remote_name,
+ enum smb_signing_setting signing_state,
+ uint32_t smb1_capabilities,
+ struct GUID *client_guid,
+ uint32_t smb2_capabilities,
+ const struct smb311_capabilities *smb3_capabilities)
+{
+ struct smbXcli_conn *conn = NULL;
+ void *ss = NULL;
+ struct sockaddr *sa = NULL;
+ socklen_t sa_length;
+ int ret;
+
+ if (smb3_capabilities != NULL) {
+ const struct smb3_signing_capabilities *sign_algos =
+ &smb3_capabilities->signing;
+ const struct smb3_encryption_capabilities *ciphers =
+ &smb3_capabilities->encryption;
+
+ SMB_ASSERT(sign_algos->num_algos <= SMB3_SIGNING_CAPABILITIES_MAX_ALGOS);
+ SMB_ASSERT(ciphers->num_algos <= SMB3_ENCRYTION_CAPABILITIES_MAX_ALGOS);
+ }
+
+ conn = talloc_zero(mem_ctx, struct smbXcli_conn);
+ if (!conn) {
+ return NULL;
+ }
+
+ ret = set_blocking(fd, false);
+ if (ret < 0) {
+ goto error;
+ }
+ conn->sock_fd = fd;
+
+ conn->remote_name = talloc_strdup(conn, remote_name);
+ if (conn->remote_name == NULL) {
+ goto error;
+ }
+
+ ss = (void *)&conn->local_ss;
+ sa = (struct sockaddr *)ss;
+ sa_length = sizeof(conn->local_ss);
+ ret = getsockname(fd, sa, &sa_length);
+ if (ret == -1) {
+ goto error;
+ }
+ ss = (void *)&conn->remote_ss;
+ sa = (struct sockaddr *)ss;
+ sa_length = sizeof(conn->remote_ss);
+ ret = getpeername(fd, sa, &sa_length);
+ if (ret == -1) {
+ goto error;
+ }
+
+ conn->outgoing = tevent_queue_create(conn, "smbXcli_outgoing");
+ if (conn->outgoing == NULL) {
+ goto error;
+ }
+ conn->pending = NULL;
+
+ conn->min_protocol = PROTOCOL_NONE;
+ conn->max_protocol = PROTOCOL_NONE;
+ conn->protocol = PROTOCOL_NONE;
+
+ switch (signing_state) {
+ case SMB_SIGNING_OFF:
+ /* never */
+ conn->allow_signing = false;
+ conn->desire_signing = false;
+ conn->mandatory_signing = false;
+ break;
+ case SMB_SIGNING_DEFAULT:
+ case SMB_SIGNING_IF_REQUIRED:
+ /* if the server requires it */
+ conn->allow_signing = true;
+ conn->desire_signing = false;
+ conn->mandatory_signing = false;
+ break;
+ case SMB_SIGNING_DESIRED:
+ /* if the server desires it */
+ conn->allow_signing = true;
+ conn->desire_signing = true;
+ conn->mandatory_signing = false;
+ break;
+ case SMB_SIGNING_IPC_DEFAULT:
+ case SMB_SIGNING_REQUIRED:
+ /* always */
+ conn->allow_signing = true;
+ conn->desire_signing = true;
+ conn->mandatory_signing = true;
+ break;
+ }
+
+ conn->smb1.client.capabilities = smb1_capabilities;
+ conn->smb1.client.max_xmit = UINT16_MAX;
+
+ conn->smb1.capabilities = conn->smb1.client.capabilities;
+ conn->smb1.max_xmit = 1024;
+
+ conn->smb1.mid = 1;
+
+ /* initialise signing */
+ conn->smb1.signing = smb1_signing_init(conn,
+ conn->allow_signing,
+ conn->desire_signing,
+ conn->mandatory_signing);
+ if (!conn->smb1.signing) {
+ goto error;
+ }
+
+ conn->smb2.client.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
+ if (conn->mandatory_signing) {
+ conn->smb2.client.security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
+ }
+ if (client_guid) {
+ conn->smb2.client.guid = *client_guid;
+ }
+ conn->smb2.client.capabilities = smb2_capabilities;
+ if (smb3_capabilities != NULL) {
+ conn->smb2.client.smb3_capabilities = *smb3_capabilities;
+ }
+
+ conn->smb2.cur_credits = 1;
+ conn->smb2.max_credits = 0;
+ conn->smb2.io_priority = 1;
+
+ /*
+ * Samba and Windows servers accept a maximum of 16 MiB with a maximum
+ * chunk length of 1 MiB.
+ */
+ conn->smb2.cc_chunk_len = 1024 * 1024;
+ conn->smb2.cc_max_chunks = 16;
+
+ talloc_set_destructor(conn, smbXcli_conn_destructor);
+ return conn;
+
+ error:
+ TALLOC_FREE(conn);
+ return NULL;
+}
+
+bool smbXcli_conn_is_connected(struct smbXcli_conn *conn)
+{
+ if (conn == NULL) {
+ return false;
+ }
+
+ if (conn->sock_fd == -1) {
+ return false;
+ }
+
+ return true;
+}
+
+enum protocol_types smbXcli_conn_protocol(struct smbXcli_conn *conn)
+{
+ return conn->protocol;
+}
+
+bool smbXcli_conn_use_unicode(struct smbXcli_conn *conn)
+{
+ if (conn->protocol >= PROTOCOL_SMB2_02) {
+ return true;
+ }
+
+ if (conn->smb1.capabilities & CAP_UNICODE) {
+ return true;
+ }
+
+ return false;
+}
+
+bool smbXcli_conn_signing_mandatory(struct smbXcli_conn *conn)
+{
+ return conn->mandatory_signing;
+}
+
+bool smbXcli_conn_have_posix(struct smbXcli_conn *conn)
+{
+ if (conn->protocol >= PROTOCOL_SMB3_11) {
+ return conn->smb2.server.smb311_posix;
+ }
+ if (conn->protocol <= PROTOCOL_NT1) {
+ return (conn->smb1.capabilities & CAP_UNIX);
+ }
+ return false;
+}
+
+/*
+ * [MS-SMB] 2.2.2.3.5 - SMB1 support for passing through
+ * query/set commands to the file system
+ */
+bool smbXcli_conn_support_passthrough(struct smbXcli_conn *conn)
+{
+ if (conn->protocol >= PROTOCOL_SMB2_02) {
+ return true;
+ }
+
+ if (conn->smb1.capabilities & CAP_W2K_SMBS) {
+ return true;
+ }
+
+ return false;
+}
+
+void smbXcli_conn_set_sockopt(struct smbXcli_conn *conn, const char *options)
+{
+ set_socket_options(conn->sock_fd, options);
+}
+
+const struct sockaddr_storage *smbXcli_conn_local_sockaddr(struct smbXcli_conn *conn)
+{
+ return &conn->local_ss;
+}
+
+const struct sockaddr_storage *smbXcli_conn_remote_sockaddr(struct smbXcli_conn *conn)
+{
+ return &conn->remote_ss;
+}
+
+const char *smbXcli_conn_remote_name(struct smbXcli_conn *conn)
+{
+ return conn->remote_name;
+}
+
+uint16_t smbXcli_conn_max_requests(struct smbXcli_conn *conn)
+{
+ if (conn->protocol >= PROTOCOL_SMB2_02) {
+ /*
+ * TODO...
+ */
+ return 1;
+ }
+
+ return conn->smb1.server.max_mux;
+}
+
+NTTIME smbXcli_conn_server_system_time(struct smbXcli_conn *conn)
+{
+ if (conn->protocol >= PROTOCOL_SMB2_02) {
+ return conn->smb2.server.system_time;
+ }
+
+ return conn->smb1.server.system_time;
+}
+
+const DATA_BLOB *smbXcli_conn_server_gss_blob(struct smbXcli_conn *conn)
+{
+ if (conn->protocol >= PROTOCOL_SMB2_02) {
+ return &conn->smb2.server.gss_blob;
+ }
+
+ return &conn->smb1.server.gss_blob;
+}
+
+const struct GUID *smbXcli_conn_server_guid(struct smbXcli_conn *conn)
+{
+ if (conn->protocol >= PROTOCOL_SMB2_02) {
+ return &conn->smb2.server.guid;
+ }
+
+ return &conn->smb1.server.guid;
+}
+
+bool smbXcli_conn_get_force_channel_sequence(struct smbXcli_conn *conn)
+{
+ return conn->smb2.force_channel_sequence;
+}
+
+void smbXcli_conn_set_force_channel_sequence(struct smbXcli_conn *conn,
+ bool v)
+{
+ conn->smb2.force_channel_sequence = v;
+}
+
+struct smbXcli_conn_samba_suicide_state {
+ struct smbXcli_conn *conn;
+ struct iovec iov;
+ uint8_t buf[9];
+ struct tevent_req *write_req;
+};
+
+static void smbXcli_conn_samba_suicide_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state);
+static void smbXcli_conn_samba_suicide_done(struct tevent_req *subreq);
+
+struct tevent_req *smbXcli_conn_samba_suicide_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint8_t exitcode)
+{
+ struct tevent_req *req, *subreq;
+ struct smbXcli_conn_samba_suicide_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smbXcli_conn_samba_suicide_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->conn = conn;
+ SIVAL(state->buf, 4, SMB_SUICIDE_PACKET);
+ SCVAL(state->buf, 8, exitcode);
+ _smb_setlen_nbt(state->buf, sizeof(state->buf)-4);
+
+ if (conn->suicide_req != NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ state->iov.iov_base = state->buf;
+ state->iov.iov_len = sizeof(state->buf);
+
+ subreq = writev_send(state, ev, conn->outgoing, conn->sock_fd,
+ false, &state->iov, 1);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smbXcli_conn_samba_suicide_done, req);
+ state->write_req = subreq;
+
+ tevent_req_set_cleanup_fn(req, smbXcli_conn_samba_suicide_cleanup);
+
+ /*
+ * We need to use tevent_req_defer_callback()
+ * in order to allow smbXcli_conn_disconnect()
+ * to do a safe cleanup.
+ */
+ tevent_req_defer_callback(req, ev);
+ conn->suicide_req = req;
+
+ return req;
+}
+
+static void smbXcli_conn_samba_suicide_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state)
+{
+ struct smbXcli_conn_samba_suicide_state *state = tevent_req_data(
+ req, struct smbXcli_conn_samba_suicide_state);
+
+ TALLOC_FREE(state->write_req);
+
+ if (state->conn == NULL) {
+ return;
+ }
+
+ if (state->conn->suicide_req == req) {
+ state->conn->suicide_req = NULL;
+ }
+ state->conn = NULL;
+}
+
+static void smbXcli_conn_samba_suicide_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smbXcli_conn_samba_suicide_state *state = tevent_req_data(
+ req, struct smbXcli_conn_samba_suicide_state);
+ ssize_t nwritten;
+ int err;
+
+ state->write_req = NULL;
+
+ nwritten = writev_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (nwritten == -1) {
+ /* here, we need to notify all pending requests */
+ NTSTATUS status = map_nt_error_from_unix_common(err);
+ smbXcli_conn_disconnect(state->conn, status);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+NTSTATUS smbXcli_conn_samba_suicide_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS smbXcli_conn_samba_suicide(struct smbXcli_conn *conn,
+ uint8_t exitcode)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+ bool ok;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER_MIX;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smbXcli_conn_samba_suicide_send(frame, ev, conn, exitcode);
+ if (req == NULL) {
+ goto fail;
+ }
+ ok = tevent_req_poll_ntstatus(req, ev, &status);
+ if (!ok) {
+ goto fail;
+ }
+ status = smbXcli_conn_samba_suicide_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+uint32_t smb1cli_conn_capabilities(struct smbXcli_conn *conn)
+{
+ return conn->smb1.capabilities;
+}
+
+uint32_t smb1cli_conn_max_xmit(struct smbXcli_conn *conn)
+{
+ return conn->smb1.max_xmit;
+}
+
+bool smb1cli_conn_req_possible(struct smbXcli_conn *conn)
+{
+ size_t pending = talloc_array_length(conn->pending);
+ uint16_t possible = conn->smb1.server.max_mux;
+
+ if (pending >= possible) {
+ return false;
+ }
+
+ return true;
+}
+
+uint32_t smb1cli_conn_server_session_key(struct smbXcli_conn *conn)
+{
+ return conn->smb1.server.session_key;
+}
+
+const uint8_t *smb1cli_conn_server_challenge(struct smbXcli_conn *conn)
+{
+ return conn->smb1.server.challenge;
+}
+
+uint16_t smb1cli_conn_server_security_mode(struct smbXcli_conn *conn)
+{
+ return conn->smb1.server.security_mode;
+}
+
+bool smb1cli_conn_server_readbraw(struct smbXcli_conn *conn)
+{
+ return conn->smb1.server.readbraw;
+}
+
+bool smb1cli_conn_server_writebraw(struct smbXcli_conn *conn)
+{
+ return conn->smb1.server.writebraw;
+}
+
+bool smb1cli_conn_server_lockread(struct smbXcli_conn *conn)
+{
+ return conn->smb1.server.lockread;
+}
+
+bool smb1cli_conn_server_writeunlock(struct smbXcli_conn *conn)
+{
+ return conn->smb1.server.writeunlock;
+}
+
+int smb1cli_conn_server_time_zone(struct smbXcli_conn *conn)
+{
+ return conn->smb1.server.time_zone;
+}
+
+bool smb1cli_conn_activate_signing(struct smbXcli_conn *conn,
+ const DATA_BLOB user_session_key,
+ const DATA_BLOB response)
+{
+ return smb1_signing_activate(conn->smb1.signing,
+ user_session_key,
+ response);
+}
+
+bool smb1cli_conn_check_signing(struct smbXcli_conn *conn,
+ const uint8_t *buf, uint32_t seqnum)
+{
+ const uint8_t *hdr = buf + NBT_HDR_SIZE;
+ size_t len = smb_len_nbt(buf);
+
+ return smb1_signing_check_pdu(conn->smb1.signing, hdr, len, seqnum);
+}
+
+bool smb1cli_conn_signing_is_active(struct smbXcli_conn *conn)
+{
+ return smb1_signing_is_active(conn->smb1.signing);
+}
+
+void smb1cli_conn_set_encryption(struct smbXcli_conn *conn,
+ struct smb_trans_enc_state *es)
+{
+ /* Replace the old state, if any. */
+ if (conn->smb1.trans_enc) {
+ TALLOC_FREE(conn->smb1.trans_enc);
+ }
+ conn->smb1.trans_enc = es;
+}
+
+bool smb1cli_conn_encryption_on(struct smbXcli_conn *conn)
+{
+ return common_encryption_on(conn->smb1.trans_enc);
+}
+
+
+static NTSTATUS smb1cli_pull_raw_error(const uint8_t *hdr)
+{
+ uint32_t flags2 = SVAL(hdr, HDR_FLG2);
+ NTSTATUS status = NT_STATUS(IVAL(hdr, HDR_RCLS));
+
+ if (NT_STATUS_IS_OK(status)) {
+ return NT_STATUS_OK;
+ }
+
+ if (flags2 & FLAGS2_32_BIT_ERROR_CODES) {
+ return status;
+ }
+
+ return NT_STATUS_DOS(CVAL(hdr, HDR_RCLS), SVAL(hdr, HDR_ERR));
+}
+
+/**
+ * Is the SMB command able to hold an AND_X successor
+ * @param[in] cmd The SMB command in question
+ * @retval Can we add a chained request after "cmd"?
+ */
+bool smb1cli_is_andx_req(uint8_t cmd)
+{
+ switch (cmd) {
+ case SMBtconX:
+ case SMBlockingX:
+ case SMBopenX:
+ case SMBreadX:
+ case SMBwriteX:
+ case SMBsesssetupX:
+ case SMBulogoffX:
+ case SMBntcreateX:
+ return true;
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static uint16_t smb1cli_alloc_mid(struct smbXcli_conn *conn)
+{
+ size_t num_pending = talloc_array_length(conn->pending);
+ uint16_t result;
+
+ if (conn->protocol == PROTOCOL_NONE) {
+ /*
+ * This is what windows sends on the SMB1 Negprot request
+ * and some vendors reuse the SMB1 MID as SMB2 sequence number.
+ */
+ return 0;
+ }
+
+ while (true) {
+ size_t i;
+
+ result = conn->smb1.mid++;
+ if ((result == 0) || (result == 0xffff)) {
+ continue;
+ }
+
+ for (i=0; i<num_pending; i++) {
+ if (result == smb1cli_req_mid(conn->pending[i])) {
+ break;
+ }
+ }
+
+ if (i == num_pending) {
+ return result;
+ }
+ }
+}
+
+static NTSTATUS smbXcli_req_cancel_write_req(struct tevent_req *req)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+ struct smbXcli_conn *conn = state->conn;
+ size_t num_pending = talloc_array_length(conn->pending);
+ ssize_t ret;
+ int err;
+ bool ok;
+
+ if (state->write_req == NULL) {
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * Check if it's possible to cancel the request.
+ * If the result is true it's not too late.
+ * See writev_cancel().
+ */
+ ok = tevent_req_cancel(state->write_req);
+ if (ok) {
+ TALLOC_FREE(state->write_req);
+
+ if (conn->protocol >= PROTOCOL_SMB2_02) {
+ /*
+ * SMB2 has a sane signing state.
+ */
+ return NT_STATUS_OK;
+ }
+
+ if (num_pending > 1) {
+ /*
+ * We have more pending requests following us. This
+ * means the signing state will be broken for them.
+ *
+ * As a solution we could add the requests directly to
+ * our outgoing queue and do the signing in the trigger
+ * function and then use writev_send() without passing a
+ * queue. That way we'll only sign packets we're most
+ * likely send to the wire.
+ */
+ return NT_STATUS_REQUEST_OUT_OF_SEQUENCE;
+ }
+
+ /*
+ * If we're the only request that's
+ * pending, we're able to recover the signing
+ * state.
+ */
+ smb1_signing_cancel_reply(conn->smb1.signing,
+ state->smb1.one_way_seqnum);
+ return NT_STATUS_OK;
+ }
+
+ ret = writev_recv(state->write_req, &err);
+ TALLOC_FREE(state->write_req);
+ if (ret == -1) {
+ return map_nt_error_from_unix_common(err);
+ }
+
+ return NT_STATUS_OK;
+}
+
+void smbXcli_req_unset_pending(struct tevent_req *req)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+ struct smbXcli_conn *conn = state->conn;
+ size_t num_pending = talloc_array_length(conn->pending);
+ size_t i;
+ NTSTATUS cancel_status;
+
+ cancel_status = smbXcli_req_cancel_write_req(req);
+
+ if (state->smb1.mid != 0) {
+ /*
+ * This is a [nt]trans[2] request which waits
+ * for more than one reply.
+ */
+ if (!NT_STATUS_IS_OK(cancel_status)) {
+ /*
+ * If the write_req cancel didn't work
+ * we can't use the connection anymore.
+ */
+ smbXcli_conn_disconnect(conn, cancel_status);
+ return;
+ }
+ return;
+ }
+
+ tevent_req_set_cleanup_fn(req, NULL);
+
+ if (num_pending == 1) {
+ /*
+ * The pending read_smb tevent_req is a child of
+ * conn->pending. So if nothing is pending anymore, we need to
+ * delete the socket read fde.
+ */
+ /* TODO: smbXcli_conn_cancel_read_req */
+ TALLOC_FREE(conn->pending);
+ conn->read_smb_req = NULL;
+
+ if (!NT_STATUS_IS_OK(cancel_status)) {
+ /*
+ * If the write_req cancel didn't work
+ * we can't use the connection anymore.
+ */
+ smbXcli_conn_disconnect(conn, cancel_status);
+ return;
+ }
+ return;
+ }
+
+ for (i=0; i<num_pending; i++) {
+ if (req == conn->pending[i]) {
+ break;
+ }
+ }
+ if (i == num_pending) {
+ /*
+ * Something's seriously broken. Just returning here is the
+ * right thing nevertheless, the point of this routine is to
+ * remove ourselves from conn->pending.
+ */
+
+ if (!NT_STATUS_IS_OK(cancel_status)) {
+ /*
+ * If the write_req cancel didn't work
+ * we can't use the connection anymore.
+ */
+ smbXcli_conn_disconnect(conn, cancel_status);
+ return;
+ }
+ return;
+ }
+
+ /*
+ * Remove ourselves from the conn->pending array
+ */
+ for (; i < (num_pending - 1); i++) {
+ conn->pending[i] = conn->pending[i+1];
+ }
+
+ /*
+ * No NULL check here, we're shrinking by sizeof(void *), and
+ * talloc_realloc just adjusts the size for this.
+ */
+ conn->pending = talloc_realloc(NULL, conn->pending, struct tevent_req *,
+ num_pending - 1);
+
+ if (!NT_STATUS_IS_OK(cancel_status)) {
+ /*
+ * If the write_req cancel didn't work
+ * we can't use the connection anymore.
+ */
+ smbXcli_conn_disconnect(conn, cancel_status);
+ return;
+ }
+ return;
+}
+
+static void smbXcli_req_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+ struct smbXcli_conn *conn = state->conn;
+ NTSTATUS cancel_status;
+
+ switch (req_state) {
+ case TEVENT_REQ_RECEIVED:
+ /*
+ * Make sure we really remove it from
+ * the pending array on destruction.
+ *
+ * smbXcli_req_unset_pending() calls
+ * smbXcli_req_cancel_write_req() internal
+ */
+ state->smb1.mid = 0;
+ smbXcli_req_unset_pending(req);
+ return;
+ default:
+ cancel_status = smbXcli_req_cancel_write_req(req);
+ if (!NT_STATUS_IS_OK(cancel_status)) {
+ /*
+ * If the write_req cancel didn't work
+ * we can't use the connection anymore.
+ */
+ smbXcli_conn_disconnect(conn, cancel_status);
+ return;
+ }
+ return;
+ }
+}
+
+static bool smb1cli_req_cancel(struct tevent_req *req);
+static bool smb2cli_req_cancel(struct tevent_req *req);
+
+static bool smbXcli_req_cancel(struct tevent_req *req)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+
+ if (!smbXcli_conn_is_connected(state->conn)) {
+ return false;
+ }
+
+ if (state->conn->protocol == PROTOCOL_NONE) {
+ return false;
+ }
+
+ if (state->conn->protocol >= PROTOCOL_SMB2_02) {
+ return smb2cli_req_cancel(req);
+ }
+
+ return smb1cli_req_cancel(req);
+}
+
+static bool smbXcli_conn_receive_next(struct smbXcli_conn *conn);
+
+bool smbXcli_req_set_pending(struct tevent_req *req)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+ struct smbXcli_conn *conn;
+ struct tevent_req **pending;
+ size_t num_pending;
+
+ conn = state->conn;
+
+ if (!smbXcli_conn_is_connected(conn)) {
+ return false;
+ }
+
+ num_pending = talloc_array_length(conn->pending);
+
+ pending = talloc_realloc(conn, conn->pending, struct tevent_req *,
+ num_pending+1);
+ if (pending == NULL) {
+ return false;
+ }
+ pending[num_pending] = req;
+ conn->pending = pending;
+ tevent_req_set_cleanup_fn(req, smbXcli_req_cleanup);
+ tevent_req_set_cancel_fn(req, smbXcli_req_cancel);
+
+ if (!smbXcli_conn_receive_next(conn)) {
+ /*
+ * the caller should notify the current request
+ *
+ * And all other pending requests get notified
+ * by smbXcli_conn_disconnect().
+ */
+ smbXcli_req_unset_pending(req);
+ smbXcli_conn_disconnect(conn, NT_STATUS_NO_MEMORY);
+ return false;
+ }
+
+ return true;
+}
+
+static void smbXcli_conn_received(struct tevent_req *subreq);
+
+static bool smbXcli_conn_receive_next(struct smbXcli_conn *conn)
+{
+ size_t num_pending = talloc_array_length(conn->pending);
+ struct tevent_req *req;
+ struct smbXcli_req_state *state;
+
+ if (conn->read_smb_req != NULL) {
+ return true;
+ }
+
+ if (num_pending == 0) {
+ if (conn->smb2.mid < UINT64_MAX) {
+ /* no more pending requests, so we are done for now */
+ return true;
+ }
+
+ /*
+ * If there are no more SMB2 requests possible,
+ * because we are out of message ids,
+ * we need to disconnect.
+ */
+ smbXcli_conn_disconnect(conn, NT_STATUS_CONNECTION_ABORTED);
+ return true;
+ }
+
+ req = conn->pending[0];
+ state = tevent_req_data(req, struct smbXcli_req_state);
+
+ /*
+ * We're the first ones, add the read_smb request that waits for the
+ * answer from the server
+ */
+ conn->read_smb_req = read_smb_send(conn->pending,
+ state->ev,
+ conn->sock_fd);
+ if (conn->read_smb_req == NULL) {
+ return false;
+ }
+ tevent_req_set_callback(conn->read_smb_req, smbXcli_conn_received, conn);
+ return true;
+}
+
+void smbXcli_conn_disconnect(struct smbXcli_conn *conn, NTSTATUS status)
+{
+ struct smbXcli_session *session;
+ int sock_fd = conn->sock_fd;
+
+ tevent_queue_stop(conn->outgoing);
+
+ conn->sock_fd = -1;
+
+ session = conn->sessions;
+ if (talloc_array_length(conn->pending) == 0) {
+ /*
+ * if we do not have pending requests
+ * there is no need to update the channel_sequence
+ */
+ session = NULL;
+ }
+ for (; session; session = session->next) {
+ smb2cli_session_increment_channel_sequence(session);
+ }
+
+ if (conn->suicide_req != NULL) {
+ /*
+ * smbXcli_conn_samba_suicide_send()
+ * used tevent_req_defer_callback() already.
+ */
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(conn->suicide_req, status);
+ }
+ conn->suicide_req = NULL;
+ }
+
+ /*
+ * Cancel all pending requests. We do not do a for-loop walking
+ * conn->pending because that array changes in
+ * smbXcli_req_unset_pending.
+ */
+ while (conn->pending != NULL &&
+ talloc_array_length(conn->pending) > 0) {
+ struct tevent_req *req;
+ struct smbXcli_req_state *state;
+ struct tevent_req **chain;
+ size_t num_chained;
+ size_t i;
+
+ req = conn->pending[0];
+ state = tevent_req_data(req, struct smbXcli_req_state);
+
+ if (state->smb1.chained_requests == NULL) {
+ bool in_progress;
+
+ /*
+ * We're dead. No point waiting for trans2
+ * replies.
+ */
+ state->smb1.mid = 0;
+
+ smbXcli_req_unset_pending(req);
+
+ if (NT_STATUS_IS_OK(status)) {
+ /* do not notify the callers */
+ continue;
+ }
+
+ in_progress = tevent_req_is_in_progress(req);
+ if (!in_progress) {
+ /*
+ * already finished
+ */
+ continue;
+ }
+
+ /*
+ * we need to defer the callback, because we may notify
+ * more then one caller.
+ */
+ tevent_req_defer_callback(req, state->ev);
+ tevent_req_nterror(req, status);
+ continue;
+ }
+
+ chain = talloc_move(conn, &state->smb1.chained_requests);
+ num_chained = talloc_array_length(chain);
+
+ for (i=0; i<num_chained; i++) {
+ bool in_progress;
+
+ req = chain[i];
+ state = tevent_req_data(req, struct smbXcli_req_state);
+
+ /*
+ * We're dead. No point waiting for trans2
+ * replies.
+ */
+ state->smb1.mid = 0;
+
+ smbXcli_req_unset_pending(req);
+
+ if (NT_STATUS_IS_OK(status)) {
+ /* do not notify the callers */
+ continue;
+ }
+
+ in_progress = tevent_req_is_in_progress(req);
+ if (!in_progress) {
+ /*
+ * already finished
+ */
+ continue;
+ }
+
+ /*
+ * we need to defer the callback, because we may notify
+ * more than one caller.
+ */
+ tevent_req_defer_callback(req, state->ev);
+ tevent_req_nterror(req, status);
+ }
+ TALLOC_FREE(chain);
+ }
+
+ if (sock_fd != -1) {
+ close(sock_fd);
+ }
+}
+
+/*
+ * Fetch a smb request's mid. Only valid after the request has been sent by
+ * smb1cli_req_send().
+ */
+uint16_t smb1cli_req_mid(struct tevent_req *req)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+
+ if (state->smb1.mid != 0) {
+ return state->smb1.mid;
+ }
+
+ return SVAL(state->smb1.hdr, HDR_MID);
+}
+
+void smb1cli_req_set_mid(struct tevent_req *req, uint16_t mid)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+
+ state->smb1.mid = mid;
+}
+
+uint32_t smb1cli_req_seqnum(struct tevent_req *req)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+
+ return state->smb1.seqnum;
+}
+
+void smb1cli_req_set_seqnum(struct tevent_req *req, uint32_t seqnum)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+
+ state->smb1.seqnum = seqnum;
+}
+
+static size_t smbXcli_iov_len(const struct iovec *iov, int count)
+{
+ ssize_t ret = iov_buflen(iov, count);
+
+ /* Ignore the overflow case for now ... */
+ return ret;
+}
+
+static void smb1cli_req_flags(enum protocol_types protocol,
+ uint32_t smb1_capabilities,
+ uint8_t smb_command,
+ uint8_t additional_flags,
+ uint8_t clear_flags,
+ uint8_t *_flags,
+ uint16_t additional_flags2,
+ uint16_t clear_flags2,
+ uint16_t *_flags2)
+{
+ uint8_t flags = 0;
+ uint16_t flags2 = 0;
+
+ if (protocol >= PROTOCOL_LANMAN1) {
+ flags |= FLAG_CASELESS_PATHNAMES;
+ flags |= FLAG_CANONICAL_PATHNAMES;
+ }
+
+ if (protocol >= PROTOCOL_LANMAN2) {
+ flags2 |= FLAGS2_LONG_PATH_COMPONENTS;
+ flags2 |= FLAGS2_EXTENDED_ATTRIBUTES;
+ }
+
+ if (protocol >= PROTOCOL_NT1) {
+ flags2 |= FLAGS2_IS_LONG_NAME;
+
+ if (smb1_capabilities & CAP_UNICODE) {
+ flags2 |= FLAGS2_UNICODE_STRINGS;
+ }
+ if (smb1_capabilities & CAP_STATUS32) {
+ flags2 |= FLAGS2_32_BIT_ERROR_CODES;
+ }
+ if (smb1_capabilities & CAP_EXTENDED_SECURITY) {
+ flags2 |= FLAGS2_EXTENDED_SECURITY;
+ }
+ }
+
+ flags |= additional_flags;
+ flags &= ~clear_flags;
+ flags2 |= additional_flags2;
+ flags2 &= ~clear_flags2;
+
+ *_flags = flags;
+ *_flags2 = flags2;
+}
+
+static void smb1cli_req_cancel_done(struct tevent_req *subreq);
+
+static bool smb1cli_req_cancel(struct tevent_req *req)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+ uint8_t flags;
+ uint16_t flags2;
+ uint32_t pid;
+ uint16_t mid;
+ struct tevent_req *subreq;
+ NTSTATUS status;
+
+ flags = CVAL(state->smb1.hdr, HDR_FLG);
+ flags2 = SVAL(state->smb1.hdr, HDR_FLG2);
+ pid = SVAL(state->smb1.hdr, HDR_PID);
+ pid |= SVAL(state->smb1.hdr, HDR_PIDHIGH)<<16;
+ mid = SVAL(state->smb1.hdr, HDR_MID);
+
+ subreq = smb1cli_req_create(state, state->ev,
+ state->conn,
+ SMBntcancel,
+ flags, 0,
+ flags2, 0,
+ 0, /* timeout */
+ pid,
+ state->tcon,
+ state->session,
+ 0, NULL, /* vwv */
+ 0, NULL); /* bytes */
+ if (subreq == NULL) {
+ return false;
+ }
+ smb1cli_req_set_mid(subreq, mid);
+
+ status = smb1cli_req_chain_submit(&subreq, 1);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(subreq);
+ return false;
+ }
+ smb1cli_req_set_mid(subreq, 0);
+
+ tevent_req_set_callback(subreq, smb1cli_req_cancel_done, NULL);
+
+ return true;
+}
+
+static void smb1cli_req_cancel_done(struct tevent_req *subreq)
+{
+ /* we do not care about the result */
+ TALLOC_FREE(subreq);
+}
+
+struct tevent_req *smb1cli_req_create(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint8_t smb_command,
+ uint8_t additional_flags,
+ uint8_t clear_flags,
+ uint16_t additional_flags2,
+ uint16_t clear_flags2,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint8_t wct, uint16_t *vwv,
+ int iov_count,
+ struct iovec *bytes_iov)
+{
+ struct tevent_req *req;
+ struct smbXcli_req_state *state;
+ uint8_t flags = 0;
+ uint16_t flags2 = 0;
+ uint16_t uid = 0;
+ uint16_t tid = 0;
+ ssize_t num_bytes;
+
+ if (iov_count > MAX_SMB_IOV) {
+ /*
+ * Should not happen :-)
+ */
+ return NULL;
+ }
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smbXcli_req_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->conn = conn;
+ state->session = session;
+ state->tcon = tcon;
+
+ if (session) {
+ uid = session->smb1.session_id;
+ }
+
+ if (tcon) {
+ tid = tcon->smb1.tcon_id;
+
+ if (tcon->fs_attributes & FILE_CASE_SENSITIVE_SEARCH) {
+ clear_flags |= FLAG_CASELESS_PATHNAMES;
+ } else {
+ /* Default setting, case insensitive. */
+ additional_flags |= FLAG_CASELESS_PATHNAMES;
+ }
+
+ if (smbXcli_conn_dfs_supported(conn) &&
+ smbXcli_tcon_is_dfs_share(tcon))
+ {
+ additional_flags2 |= FLAGS2_DFS_PATHNAMES;
+ }
+ }
+
+ state->smb1.recv_cmd = 0xFF;
+ state->smb1.recv_status = NT_STATUS_INTERNAL_ERROR;
+ state->smb1.recv_iov = talloc_zero_array(state, struct iovec, 3);
+ if (state->smb1.recv_iov == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+
+ smb1cli_req_flags(conn->protocol,
+ conn->smb1.capabilities,
+ smb_command,
+ additional_flags,
+ clear_flags,
+ &flags,
+ additional_flags2,
+ clear_flags2,
+ &flags2);
+
+ SIVAL(state->smb1.hdr, 0, SMB_MAGIC);
+ SCVAL(state->smb1.hdr, HDR_COM, smb_command);
+ SIVAL(state->smb1.hdr, HDR_RCLS, NT_STATUS_V(NT_STATUS_OK));
+ SCVAL(state->smb1.hdr, HDR_FLG, flags);
+ SSVAL(state->smb1.hdr, HDR_FLG2, flags2);
+ SSVAL(state->smb1.hdr, HDR_PIDHIGH, pid >> 16);
+ SSVAL(state->smb1.hdr, HDR_TID, tid);
+ SSVAL(state->smb1.hdr, HDR_PID, pid);
+ SSVAL(state->smb1.hdr, HDR_UID, uid);
+ SSVAL(state->smb1.hdr, HDR_MID, 0); /* this comes later */
+ SCVAL(state->smb1.hdr, HDR_WCT, wct);
+
+ state->smb1.vwv = vwv;
+
+ num_bytes = iov_buflen(bytes_iov, iov_count);
+ if (num_bytes == -1) {
+ /*
+ * I'd love to add a check for num_bytes<=UINT16_MAX here, but
+ * the smbclient->samba connections can lie and transfer more.
+ */
+ TALLOC_FREE(req);
+ return NULL;
+ }
+
+ SSVAL(state->smb1.bytecount_buf, 0, num_bytes);
+
+ state->smb1.iov[0].iov_base = (void *)state->length_hdr;
+ state->smb1.iov[0].iov_len = sizeof(state->length_hdr);
+ state->smb1.iov[1].iov_base = (void *)state->smb1.hdr;
+ state->smb1.iov[1].iov_len = sizeof(state->smb1.hdr);
+ state->smb1.iov[2].iov_base = (void *)state->smb1.vwv;
+ state->smb1.iov[2].iov_len = wct * sizeof(uint16_t);
+ state->smb1.iov[3].iov_base = (void *)state->smb1.bytecount_buf;
+ state->smb1.iov[3].iov_len = sizeof(uint16_t);
+
+ if (iov_count != 0) {
+ memcpy(&state->smb1.iov[4], bytes_iov,
+ iov_count * sizeof(*bytes_iov));
+ }
+ state->smb1.iov_count = iov_count + 4;
+
+ if (timeout_msec > 0) {
+ state->endtime = timeval_current_ofs_msec(timeout_msec);
+ if (!tevent_req_set_endtime(req, ev, state->endtime)) {
+ return req;
+ }
+ }
+
+ switch (smb_command) {
+ case SMBtranss:
+ case SMBtranss2:
+ case SMBnttranss:
+ state->one_way = true;
+ break;
+ case SMBntcancel:
+ state->one_way = true;
+ state->smb1.one_way_seqnum = true;
+ break;
+ case SMBlockingX:
+ if ((wct == 8) &&
+ (CVAL(vwv+3, 0) == LOCKING_ANDX_OPLOCK_RELEASE)) {
+ state->one_way = true;
+ }
+ break;
+ }
+
+ return req;
+}
+
+static NTSTATUS smb1cli_conn_signv(struct smbXcli_conn *conn,
+ struct iovec *iov, int iov_count,
+ uint32_t *seqnum,
+ bool one_way_seqnum)
+{
+ TALLOC_CTX *frame = NULL;
+ NTSTATUS status;
+ uint8_t *buf;
+
+ /*
+ * Obvious optimization: Make cli_calculate_sign_mac work with struct
+ * iovec directly. MD5Update would do that just fine.
+ */
+
+ if (iov_count < 4) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ if (iov[0].iov_len != NBT_HDR_SIZE) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ if (iov[1].iov_len != (MIN_SMB_SIZE-sizeof(uint16_t))) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ if (iov[2].iov_len > (0xFF * sizeof(uint16_t))) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ if (iov[3].iov_len != sizeof(uint16_t)) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ frame = talloc_stackframe();
+
+ buf = iov_concat(frame, &iov[1], iov_count - 1);
+ if (buf == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *seqnum = smb1_signing_next_seqnum(conn->smb1.signing,
+ one_way_seqnum);
+ status = smb1_signing_sign_pdu(conn->smb1.signing,
+ buf,
+ talloc_get_size(buf),
+ *seqnum);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ memcpy(iov[1].iov_base, buf, iov[1].iov_len);
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+static void smb1cli_req_writev_done(struct tevent_req *subreq);
+static NTSTATUS smb1cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
+ TALLOC_CTX *tmp_mem,
+ uint8_t *inbuf);
+
+static NTSTATUS smb1cli_req_writev_submit(struct tevent_req *req,
+ struct smbXcli_req_state *state,
+ struct iovec *iov, int iov_count)
+{
+ struct tevent_req *subreq;
+ NTSTATUS status;
+ uint8_t cmd;
+ uint16_t mid;
+ ssize_t nbtlen;
+
+ if (!smbXcli_conn_is_connected(state->conn)) {
+ return NT_STATUS_CONNECTION_DISCONNECTED;
+ }
+
+ if (state->conn->protocol > PROTOCOL_NT1) {
+ DBG_ERR("called for dialect[%s] server[%s]\n",
+ smb_protocol_types_string(state->conn->protocol),
+ smbXcli_conn_remote_name(state->conn));
+ return NT_STATUS_REVISION_MISMATCH;
+ }
+
+ if (iov_count < 4) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ if (iov[0].iov_len != NBT_HDR_SIZE) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ if (iov[1].iov_len != (MIN_SMB_SIZE-sizeof(uint16_t))) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ if (iov[2].iov_len > (0xFF * sizeof(uint16_t))) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ if (iov[3].iov_len != sizeof(uint16_t)) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ cmd = CVAL(iov[1].iov_base, HDR_COM);
+ if (cmd == SMBreadBraw) {
+ if (smbXcli_conn_has_async_calls(state->conn)) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ state->conn->smb1.read_braw_req = req;
+ }
+
+ if (state->smb1.mid != 0) {
+ mid = state->smb1.mid;
+ } else {
+ mid = smb1cli_alloc_mid(state->conn);
+ }
+ SSVAL(iov[1].iov_base, HDR_MID, mid);
+
+ nbtlen = iov_buflen(&iov[1], iov_count-1);
+ if ((nbtlen == -1) || (nbtlen > 0x1FFFF)) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ _smb_setlen_nbt(iov[0].iov_base, nbtlen);
+
+ status = smb1cli_conn_signv(state->conn, iov, iov_count,
+ &state->smb1.seqnum,
+ state->smb1.one_way_seqnum);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /*
+ * If we supported multiple encryption contexts
+ * here we'd look up based on tid.
+ */
+ if (common_encryption_on(state->conn->smb1.trans_enc)) {
+ char *buf, *enc_buf;
+
+ buf = (char *)iov_concat(talloc_tos(), iov, iov_count);
+ if (buf == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ status = common_encrypt_buffer(state->conn->smb1.trans_enc,
+ (char *)buf, &enc_buf);
+ TALLOC_FREE(buf);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Error in encrypting client message: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+ buf = (char *)talloc_memdup(state, enc_buf,
+ smb_len_nbt(enc_buf)+4);
+ SAFE_FREE(enc_buf);
+ if (buf == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ iov[0].iov_base = (void *)buf;
+ iov[0].iov_len = talloc_get_size(buf);
+ iov_count = 1;
+ }
+
+ if (state->conn->dispatch_incoming == NULL) {
+ state->conn->dispatch_incoming = smb1cli_conn_dispatch_incoming;
+ }
+
+ if (!smbXcli_req_set_pending(req)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ tevent_req_set_cancel_fn(req, smbXcli_req_cancel);
+
+ subreq = writev_send(state, state->ev, state->conn->outgoing,
+ state->conn->sock_fd, false, iov, iov_count);
+ if (subreq == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ tevent_req_set_callback(subreq, smb1cli_req_writev_done, req);
+ state->write_req = subreq;
+
+ return NT_STATUS_OK;
+}
+
+struct tevent_req *smb1cli_req_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint8_t smb_command,
+ uint8_t additional_flags,
+ uint8_t clear_flags,
+ uint16_t additional_flags2,
+ uint16_t clear_flags2,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint8_t wct, uint16_t *vwv,
+ uint32_t num_bytes,
+ const uint8_t *bytes)
+{
+ struct tevent_req *req;
+ struct iovec iov;
+ NTSTATUS status;
+
+ iov.iov_base = discard_const_p(void, bytes);
+ iov.iov_len = num_bytes;
+
+ req = smb1cli_req_create(mem_ctx, ev, conn, smb_command,
+ additional_flags, clear_flags,
+ additional_flags2, clear_flags2,
+ timeout_msec,
+ pid, tcon, session,
+ wct, vwv, 1, &iov);
+ if (req == NULL) {
+ return NULL;
+ }
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+ status = smb1cli_req_chain_submit(&req, 1);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+ return req;
+}
+
+static void smb1cli_req_writev_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+ ssize_t nwritten;
+ int err;
+
+ state->write_req = NULL;
+
+ nwritten = writev_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (nwritten == -1) {
+ /* here, we need to notify all pending requests */
+ NTSTATUS status = map_nt_error_from_unix_common(err);
+ smbXcli_conn_disconnect(state->conn, status);
+ return;
+ }
+
+ if (state->one_way) {
+ state->inbuf = NULL;
+ tevent_req_done(req);
+ return;
+ }
+}
+
+static void smbXcli_conn_received(struct tevent_req *subreq)
+{
+ struct smbXcli_conn *conn =
+ tevent_req_callback_data(subreq,
+ struct smbXcli_conn);
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ uint8_t *inbuf;
+ ssize_t received;
+ int err;
+
+ if (subreq != conn->read_smb_req) {
+ DEBUG(1, ("Internal error: cli_smb_received called with "
+ "unexpected subreq\n"));
+ smbXcli_conn_disconnect(conn, NT_STATUS_INTERNAL_ERROR);
+ TALLOC_FREE(frame);
+ return;
+ }
+ conn->read_smb_req = NULL;
+
+ received = read_smb_recv(subreq, frame, &inbuf, &err);
+ TALLOC_FREE(subreq);
+ if (received == -1) {
+ status = map_nt_error_from_unix_common(err);
+ smbXcli_conn_disconnect(conn, status);
+ TALLOC_FREE(frame);
+ return;
+ }
+
+ status = conn->dispatch_incoming(conn, frame, inbuf);
+ TALLOC_FREE(frame);
+ if (NT_STATUS_IS_OK(status)) {
+ /*
+ * We should not do any more processing
+ * as the dispatch function called
+ * tevent_req_done().
+ */
+ return;
+ }
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
+ /*
+ * We got an error, so notify all pending requests
+ */
+ smbXcli_conn_disconnect(conn, status);
+ return;
+ }
+
+ /*
+ * We got NT_STATUS_RETRY, so we may ask for a
+ * next incoming pdu.
+ */
+ if (!smbXcli_conn_receive_next(conn)) {
+ smbXcli_conn_disconnect(conn, NT_STATUS_NO_MEMORY);
+ }
+}
+
+static NTSTATUS smb1cli_inbuf_parse_chain(uint8_t *buf, TALLOC_CTX *mem_ctx,
+ struct iovec **piov, int *pnum_iov)
+{
+ struct iovec *iov;
+ size_t num_iov;
+ size_t buflen;
+ size_t taken;
+ size_t remaining;
+ uint8_t *hdr;
+ uint8_t cmd;
+ uint32_t wct_ofs;
+ NTSTATUS status;
+ size_t min_size = MIN_SMB_SIZE;
+
+ buflen = smb_len_tcp(buf);
+ taken = 0;
+
+ hdr = buf + NBT_HDR_SIZE;
+
+ status = smb1cli_pull_raw_error(hdr);
+ if (NT_STATUS_IS_ERR(status)) {
+ /*
+ * This is an ugly hack to support OS/2
+ * which skips the byte_count in the DATA block
+ * on some error responses.
+ *
+ * See bug #9096
+ */
+ min_size -= sizeof(uint16_t);
+ }
+
+ if (buflen < min_size) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ /*
+ * This returns iovec elements in the following order:
+ *
+ * - SMB header
+ *
+ * - Parameter Block
+ * - Data Block
+ *
+ * - Parameter Block
+ * - Data Block
+ *
+ * - Parameter Block
+ * - Data Block
+ */
+ num_iov = 1;
+
+ iov = talloc_array(mem_ctx, struct iovec, num_iov);
+ if (iov == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ iov[0].iov_base = hdr;
+ iov[0].iov_len = HDR_WCT;
+ taken += HDR_WCT;
+
+ cmd = CVAL(hdr, HDR_COM);
+ wct_ofs = HDR_WCT;
+
+ while (true) {
+ size_t len = buflen - taken;
+ struct iovec *cur;
+ struct iovec *iov_tmp;
+ uint8_t wct;
+ uint32_t bcc_ofs;
+ uint16_t bcc;
+ size_t needed;
+
+ /*
+ * we need at least WCT
+ */
+ needed = sizeof(uint8_t);
+ if (len < needed) {
+ DEBUG(10, ("%s: %d bytes left, expected at least %d\n",
+ __location__, (int)len, (int)needed));
+ goto inval;
+ }
+
+ /*
+ * Now we check if the specified words are there
+ */
+ wct = CVAL(hdr, wct_ofs);
+ needed += wct * sizeof(uint16_t);
+ if (len < needed) {
+ DEBUG(10, ("%s: %d bytes left, expected at least %d\n",
+ __location__, (int)len, (int)needed));
+ goto inval;
+ }
+
+ if ((num_iov == 1) &&
+ (len == needed) &&
+ NT_STATUS_IS_ERR(status))
+ {
+ /*
+ * This is an ugly hack to support OS/2
+ * which skips the byte_count in the DATA block
+ * on some error responses.
+ *
+ * See bug #9096
+ */
+ iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec,
+ num_iov + 2);
+ if (iov_tmp == NULL) {
+ TALLOC_FREE(iov);
+ return NT_STATUS_NO_MEMORY;
+ }
+ iov = iov_tmp;
+ cur = &iov[num_iov];
+ num_iov += 2;
+
+ cur[0].iov_len = 0;
+ cur[0].iov_base = hdr + (wct_ofs + sizeof(uint8_t));
+ cur[1].iov_len = 0;
+ cur[1].iov_base = cur[0].iov_base;
+
+ taken += needed;
+ break;
+ }
+
+ /*
+ * we need at least BCC
+ */
+ needed += sizeof(uint16_t);
+ if (len < needed) {
+ DEBUG(10, ("%s: %d bytes left, expected at least %d\n",
+ __location__, (int)len, (int)needed));
+ goto inval;
+ }
+
+ /*
+ * Now we check if the specified bytes are there
+ */
+ bcc_ofs = wct_ofs + sizeof(uint8_t) + wct * sizeof(uint16_t);
+ bcc = SVAL(hdr, bcc_ofs);
+ needed += bcc * sizeof(uint8_t);
+ if (len < needed) {
+ DEBUG(10, ("%s: %d bytes left, expected at least %d\n",
+ __location__, (int)len, (int)needed));
+ goto inval;
+ }
+
+ /*
+ * we allocate 2 iovec structures for words and bytes
+ */
+ iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec,
+ num_iov + 2);
+ if (iov_tmp == NULL) {
+ TALLOC_FREE(iov);
+ return NT_STATUS_NO_MEMORY;
+ }
+ iov = iov_tmp;
+ cur = &iov[num_iov];
+ num_iov += 2;
+
+ cur[0].iov_len = wct * sizeof(uint16_t);
+ cur[0].iov_base = hdr + (wct_ofs + sizeof(uint8_t));
+ cur[1].iov_len = bcc * sizeof(uint8_t);
+ cur[1].iov_base = hdr + (bcc_ofs + sizeof(uint16_t));
+
+ taken += needed;
+
+ if (!smb1cli_is_andx_req(cmd)) {
+ /*
+ * If the current command does not have AndX chanining
+ * we are done.
+ */
+ break;
+ }
+
+ if (wct == 0 && bcc == 0) {
+ /*
+ * An empty response also ends the chain,
+ * most likely with an error.
+ */
+ break;
+ }
+
+ if (wct < 2) {
+ DEBUG(10, ("%s: wct[%d] < 2 for cmd[0x%02X]\n",
+ __location__, (int)wct, (int)cmd));
+ goto inval;
+ }
+ cmd = CVAL(cur[0].iov_base, 0);
+ if (cmd == 0xFF) {
+ /*
+ * If it is the end of the chain we are also done.
+ */
+ break;
+ }
+ wct_ofs = SVAL(cur[0].iov_base, 2);
+
+ if (wct_ofs < taken) {
+ goto inval;
+ }
+ if (wct_ofs > buflen) {
+ goto inval;
+ }
+
+ /*
+ * we consumed everything up to the start of the next
+ * parameter block.
+ */
+ taken = wct_ofs;
+ }
+
+ remaining = buflen - taken;
+
+ if (remaining > 0 && num_iov >= 3) {
+ /*
+ * The last DATA block gets the remaining
+ * bytes, this is needed to support
+ * CAP_LARGE_WRITEX and CAP_LARGE_READX.
+ */
+ iov[num_iov-1].iov_len += remaining;
+ }
+
+ *piov = iov;
+ *pnum_iov = num_iov;
+ return NT_STATUS_OK;
+
+inval:
+ TALLOC_FREE(iov);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+}
+
+static NTSTATUS smb1cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
+ TALLOC_CTX *tmp_mem,
+ uint8_t *inbuf)
+{
+ struct tevent_req *req;
+ struct smbXcli_req_state *state;
+ NTSTATUS status;
+ size_t num_pending;
+ size_t i;
+ uint8_t cmd;
+ uint16_t mid;
+ bool oplock_break;
+ uint8_t *inhdr = inbuf + NBT_HDR_SIZE;
+ size_t len = smb_len_tcp(inbuf);
+ struct iovec *iov = NULL;
+ int num_iov = 0;
+ struct tevent_req **chain = NULL;
+ size_t num_chained = 0;
+ size_t num_responses = 0;
+
+ if (conn->smb1.read_braw_req != NULL) {
+ req = conn->smb1.read_braw_req;
+ conn->smb1.read_braw_req = NULL;
+ state = tevent_req_data(req, struct smbXcli_req_state);
+
+ smbXcli_req_unset_pending(req);
+
+ if (state->smb1.recv_iov == NULL) {
+ /*
+ * For requests with more than
+ * one response, we have to readd the
+ * recv_iov array.
+ */
+ state->smb1.recv_iov = talloc_zero_array(state,
+ struct iovec,
+ 3);
+ if (tevent_req_nomem(state->smb1.recv_iov, req)) {
+ return NT_STATUS_OK;
+ }
+ }
+
+ state->smb1.recv_iov[0].iov_base = (void *)(inhdr);
+ state->smb1.recv_iov[0].iov_len = len;
+ ZERO_STRUCT(state->smb1.recv_iov[1]);
+ ZERO_STRUCT(state->smb1.recv_iov[2]);
+
+ state->smb1.recv_cmd = SMBreadBraw;
+ state->smb1.recv_status = NT_STATUS_OK;
+ state->inbuf = talloc_move(state->smb1.recv_iov, &inbuf);
+
+ tevent_req_done(req);
+ return NT_STATUS_OK;
+ }
+
+ if ((IVAL(inhdr, 0) != SMB_MAGIC) /* 0xFF"SMB" */
+ && (SVAL(inhdr, 0) != 0x45ff)) /* 0xFF"E" */ {
+ DEBUG(10, ("Got non-SMB PDU\n"));
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ /*
+ * If we supported multiple encryption contexts
+ * here we'd look up based on tid.
+ */
+ if (common_encryption_on(conn->smb1.trans_enc)
+ && (CVAL(inbuf, 0) == 0)) {
+ uint16_t enc_ctx_num;
+
+ status = get_enc_ctx_num(inbuf, &enc_ctx_num);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("get_enc_ctx_num returned %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ if (enc_ctx_num != conn->smb1.trans_enc->enc_ctx_num) {
+ DEBUG(10, ("wrong enc_ctx %d, expected %d\n",
+ enc_ctx_num,
+ conn->smb1.trans_enc->enc_ctx_num));
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ status = common_decrypt_buffer(conn->smb1.trans_enc,
+ (char *)inbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("common_decrypt_buffer returned %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+ inhdr = inbuf + NBT_HDR_SIZE;
+ len = smb_len_nbt(inbuf);
+ }
+
+ mid = SVAL(inhdr, HDR_MID);
+ num_pending = talloc_array_length(conn->pending);
+
+ for (i=0; i<num_pending; i++) {
+ if (mid == smb1cli_req_mid(conn->pending[i])) {
+ break;
+ }
+ }
+ if (i == num_pending) {
+ /* Dump unexpected reply */
+ return NT_STATUS_RETRY;
+ }
+
+ oplock_break = false;
+
+ if (mid == 0xffff) {
+ /*
+ * Paranoia checks that this is really an oplock break request.
+ */
+ oplock_break = (len == 51); /* hdr + 8 words */
+ oplock_break &= ((CVAL(inhdr, HDR_FLG) & FLAG_REPLY) == 0);
+ oplock_break &= (CVAL(inhdr, HDR_COM) == SMBlockingX);
+ oplock_break &= (SVAL(inhdr, HDR_VWV+VWV(6)) == 0);
+ oplock_break &= (SVAL(inhdr, HDR_VWV+VWV(7)) == 0);
+
+ if (!oplock_break) {
+ /* Dump unexpected reply */
+ return NT_STATUS_RETRY;
+ }
+ }
+
+ req = conn->pending[i];
+ state = tevent_req_data(req, struct smbXcli_req_state);
+
+ if (!oplock_break /* oplock breaks are not signed */
+ && !smb1_signing_check_pdu(conn->smb1.signing,
+ inhdr, len, state->smb1.seqnum+1)) {
+ DEBUG(10, ("cli_check_sign_mac failed\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ status = smb1cli_inbuf_parse_chain(inbuf, tmp_mem,
+ &iov, &num_iov);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10,("smb1cli_inbuf_parse_chain - %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ cmd = CVAL(inhdr, HDR_COM);
+ status = smb1cli_pull_raw_error(inhdr);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED) &&
+ (state->session != NULL) && state->session->disconnect_expired)
+ {
+ /*
+ * this should be a short term hack
+ * until the upper layers have implemented
+ * re-authentication.
+ */
+ return status;
+ }
+
+ if (state->smb1.chained_requests == NULL) {
+ if (num_iov != 3) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ smbXcli_req_unset_pending(req);
+
+ if (state->smb1.recv_iov == NULL) {
+ /*
+ * For requests with more than
+ * one response, we have to readd the
+ * recv_iov array.
+ */
+ state->smb1.recv_iov = talloc_zero_array(state,
+ struct iovec,
+ 3);
+ if (tevent_req_nomem(state->smb1.recv_iov, req)) {
+ return NT_STATUS_OK;
+ }
+ }
+
+ state->smb1.recv_cmd = cmd;
+ state->smb1.recv_status = status;
+ state->inbuf = talloc_move(state->smb1.recv_iov, &inbuf);
+
+ state->smb1.recv_iov[0] = iov[0];
+ state->smb1.recv_iov[1] = iov[1];
+ state->smb1.recv_iov[2] = iov[2];
+
+ if (talloc_array_length(conn->pending) == 0) {
+ tevent_req_done(req);
+ return NT_STATUS_OK;
+ }
+
+ tevent_req_defer_callback(req, state->ev);
+ tevent_req_done(req);
+ return NT_STATUS_RETRY;
+ }
+
+ chain = talloc_move(tmp_mem, &state->smb1.chained_requests);
+ num_chained = talloc_array_length(chain);
+ num_responses = (num_iov - 1)/2;
+
+ if (num_responses > num_chained) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ for (i=0; i<num_chained; i++) {
+ size_t iov_idx = 1 + (i*2);
+ struct iovec *cur = &iov[iov_idx];
+ uint8_t *inbuf_ref;
+
+ req = chain[i];
+ state = tevent_req_data(req, struct smbXcli_req_state);
+
+ smbXcli_req_unset_pending(req);
+
+ /*
+ * as we finish multiple requests here
+ * we need to defer the callbacks as
+ * they could destroy our current stack state.
+ */
+ tevent_req_defer_callback(req, state->ev);
+
+ if (i >= num_responses) {
+ tevent_req_nterror(req, NT_STATUS_REQUEST_ABORTED);
+ continue;
+ }
+
+ if (state->smb1.recv_iov == NULL) {
+ /*
+ * For requests with more than
+ * one response, we have to readd the
+ * recv_iov array.
+ */
+ state->smb1.recv_iov = talloc_zero_array(state,
+ struct iovec,
+ 3);
+ if (tevent_req_nomem(state->smb1.recv_iov, req)) {
+ continue;
+ }
+ }
+
+ state->smb1.recv_cmd = cmd;
+
+ if (i == (num_responses - 1)) {
+ /*
+ * The last request in the chain gets the status
+ */
+ state->smb1.recv_status = status;
+ } else {
+ cmd = CVAL(cur[0].iov_base, 0);
+ state->smb1.recv_status = NT_STATUS_OK;
+ }
+
+ state->inbuf = inbuf;
+
+ /*
+ * Note: here we use talloc_reference() in a way
+ * that does not expose it to the caller.
+ */
+ inbuf_ref = talloc_reference(state->smb1.recv_iov, inbuf);
+ if (tevent_req_nomem(inbuf_ref, req)) {
+ continue;
+ }
+
+ /* copy the related buffers */
+ state->smb1.recv_iov[0] = iov[0];
+ state->smb1.recv_iov[1] = cur[0];
+ state->smb1.recv_iov[2] = cur[1];
+
+ tevent_req_done(req);
+ }
+
+ return NT_STATUS_RETRY;
+}
+
+NTSTATUS smb1cli_req_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **piov,
+ uint8_t **phdr,
+ uint8_t *pwct,
+ uint16_t **pvwv,
+ uint32_t *pvwv_offset,
+ uint32_t *pnum_bytes,
+ uint8_t **pbytes,
+ uint32_t *pbytes_offset,
+ uint8_t **pinbuf,
+ const struct smb1cli_req_expected_response *expected,
+ size_t num_expected)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+ NTSTATUS status = NT_STATUS_OK;
+ struct iovec *recv_iov = NULL;
+ uint8_t *hdr = NULL;
+ uint8_t wct = 0;
+ uint32_t vwv_offset = 0;
+ uint16_t *vwv = NULL;
+ uint32_t num_bytes = 0;
+ uint32_t bytes_offset = 0;
+ uint8_t *bytes = NULL;
+ size_t i;
+ bool found_status = false;
+ bool found_size = false;
+
+ if (piov != NULL) {
+ *piov = NULL;
+ }
+ if (phdr != NULL) {
+ *phdr = 0;
+ }
+ if (pwct != NULL) {
+ *pwct = 0;
+ }
+ if (pvwv != NULL) {
+ *pvwv = NULL;
+ }
+ if (pvwv_offset != NULL) {
+ *pvwv_offset = 0;
+ }
+ if (pnum_bytes != NULL) {
+ *pnum_bytes = 0;
+ }
+ if (pbytes != NULL) {
+ *pbytes = NULL;
+ }
+ if (pbytes_offset != NULL) {
+ *pbytes_offset = 0;
+ }
+ if (pinbuf != NULL) {
+ *pinbuf = NULL;
+ }
+
+ if (state->inbuf != NULL) {
+ recv_iov = state->smb1.recv_iov;
+ state->smb1.recv_iov = NULL;
+ if (state->smb1.recv_cmd != SMBreadBraw) {
+ hdr = (uint8_t *)recv_iov[0].iov_base;
+ wct = recv_iov[1].iov_len/2;
+ vwv = (uint16_t *)recv_iov[1].iov_base;
+ vwv_offset = PTR_DIFF(vwv, hdr);
+ num_bytes = recv_iov[2].iov_len;
+ bytes = (uint8_t *)recv_iov[2].iov_base;
+ bytes_offset = PTR_DIFF(bytes, hdr);
+ }
+ }
+
+ if (tevent_req_is_nterror(req, &status)) {
+ for (i=0; i < num_expected; i++) {
+ if (NT_STATUS_EQUAL(status, expected[i].status)) {
+ found_status = true;
+ break;
+ }
+ }
+
+ if (found_status) {
+ return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+ }
+
+ return status;
+ }
+
+ if (num_expected == 0) {
+ found_status = true;
+ found_size = true;
+ }
+
+ status = state->smb1.recv_status;
+
+ for (i=0; i < num_expected; i++) {
+ if (!NT_STATUS_EQUAL(status, expected[i].status)) {
+ continue;
+ }
+
+ found_status = true;
+ if (expected[i].wct == 0) {
+ found_size = true;
+ break;
+ }
+
+ if (expected[i].wct == wct) {
+ found_size = true;
+ break;
+ }
+ }
+
+ if (!found_status) {
+ return status;
+ }
+
+ if (!found_size) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ if (piov != NULL) {
+ *piov = talloc_move(mem_ctx, &recv_iov);
+ }
+
+ if (phdr != NULL) {
+ *phdr = hdr;
+ }
+ if (pwct != NULL) {
+ *pwct = wct;
+ }
+ if (pvwv != NULL) {
+ *pvwv = vwv;
+ }
+ if (pvwv_offset != NULL) {
+ *pvwv_offset = vwv_offset;
+ }
+ if (pnum_bytes != NULL) {
+ *pnum_bytes = num_bytes;
+ }
+ if (pbytes != NULL) {
+ *pbytes = bytes;
+ }
+ if (pbytes_offset != NULL) {
+ *pbytes_offset = bytes_offset;
+ }
+ if (pinbuf != NULL) {
+ *pinbuf = state->inbuf;
+ }
+
+ return status;
+}
+
+size_t smb1cli_req_wct_ofs(struct tevent_req **reqs, int num_reqs)
+{
+ size_t wct_ofs;
+ int i;
+
+ wct_ofs = HDR_WCT;
+
+ for (i=0; i<num_reqs; i++) {
+ struct smbXcli_req_state *state;
+ state = tevent_req_data(reqs[i], struct smbXcli_req_state);
+ wct_ofs += smbXcli_iov_len(state->smb1.iov+2,
+ state->smb1.iov_count-2);
+ wct_ofs = (wct_ofs + 3) & ~3;
+ }
+ return wct_ofs;
+}
+
+NTSTATUS smb1cli_req_chain_submit(struct tevent_req **reqs, int num_reqs)
+{
+ struct smbXcli_req_state *first_state =
+ tevent_req_data(reqs[0],
+ struct smbXcli_req_state);
+ struct smbXcli_req_state *state;
+ size_t wct_offset;
+ size_t chain_padding = 0;
+ int i, iovlen;
+ struct iovec *iov = NULL;
+ struct iovec *this_iov;
+ NTSTATUS status;
+ ssize_t nbt_len;
+
+ if (num_reqs == 1) {
+ return smb1cli_req_writev_submit(reqs[0], first_state,
+ first_state->smb1.iov,
+ first_state->smb1.iov_count);
+ }
+
+ iovlen = 0;
+ for (i=0; i<num_reqs; i++) {
+ if (!tevent_req_is_in_progress(reqs[i])) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ state = tevent_req_data(reqs[i], struct smbXcli_req_state);
+
+ if (state->smb1.iov_count < 4) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (i == 0) {
+ /*
+ * The NBT and SMB header
+ */
+ iovlen += 2;
+ } else {
+ /*
+ * Chain padding
+ */
+ iovlen += 1;
+ }
+
+ /*
+ * words and bytes
+ */
+ iovlen += state->smb1.iov_count - 2;
+ }
+
+ iov = talloc_zero_array(first_state, struct iovec, iovlen);
+ if (iov == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ first_state->smb1.chained_requests = (struct tevent_req **)talloc_memdup(
+ first_state, reqs, sizeof(*reqs) * num_reqs);
+ if (first_state->smb1.chained_requests == NULL) {
+ TALLOC_FREE(iov);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ wct_offset = HDR_WCT;
+ this_iov = iov;
+
+ for (i=0; i<num_reqs; i++) {
+ size_t next_padding = 0;
+ uint16_t *vwv;
+
+ state = tevent_req_data(reqs[i], struct smbXcli_req_state);
+
+ if (i < num_reqs-1) {
+ if (!smb1cli_is_andx_req(CVAL(state->smb1.hdr, HDR_COM))
+ || CVAL(state->smb1.hdr, HDR_WCT) < 2) {
+ TALLOC_FREE(iov);
+ TALLOC_FREE(first_state->smb1.chained_requests);
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ }
+
+ wct_offset += smbXcli_iov_len(state->smb1.iov+2,
+ state->smb1.iov_count-2) + 1;
+ if ((wct_offset % 4) != 0) {
+ next_padding = 4 - (wct_offset % 4);
+ }
+ wct_offset += next_padding;
+ vwv = state->smb1.vwv;
+
+ if (i < num_reqs-1) {
+ struct smbXcli_req_state *next_state =
+ tevent_req_data(reqs[i+1],
+ struct smbXcli_req_state);
+ SCVAL(vwv+0, 0, CVAL(next_state->smb1.hdr, HDR_COM));
+ SCVAL(vwv+0, 1, 0);
+ SSVAL(vwv+1, 0, wct_offset);
+ } else if (smb1cli_is_andx_req(CVAL(state->smb1.hdr, HDR_COM))) {
+ /* properly end the chain */
+ SCVAL(vwv+0, 0, 0xff);
+ SCVAL(vwv+0, 1, 0xff);
+ SSVAL(vwv+1, 0, 0);
+ }
+
+ if (i == 0) {
+ /*
+ * The NBT and SMB header
+ */
+ this_iov[0] = state->smb1.iov[0];
+ this_iov[1] = state->smb1.iov[1];
+ this_iov += 2;
+ } else {
+ /*
+ * This one is a bit subtle. We have to add
+ * chain_padding bytes between the requests, and we
+ * have to also include the wct field of the
+ * subsequent requests. We use the subsequent header
+ * for the padding, it contains the wct field in its
+ * last byte.
+ */
+ this_iov[0].iov_len = chain_padding+1;
+ this_iov[0].iov_base = (void *)&state->smb1.hdr[
+ sizeof(state->smb1.hdr) - this_iov[0].iov_len];
+ memset(this_iov[0].iov_base, 0, this_iov[0].iov_len-1);
+ this_iov += 1;
+ }
+
+ /*
+ * copy the words and bytes
+ */
+ memcpy(this_iov, state->smb1.iov+2,
+ sizeof(struct iovec) * (state->smb1.iov_count-2));
+ this_iov += state->smb1.iov_count - 2;
+ chain_padding = next_padding;
+ }
+
+ nbt_len = iov_buflen(&iov[1], iovlen-1);
+ if ((nbt_len == -1) || (nbt_len > first_state->conn->smb1.max_xmit)) {
+ TALLOC_FREE(iov);
+ TALLOC_FREE(first_state->smb1.chained_requests);
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ status = smb1cli_req_writev_submit(reqs[0], first_state, iov, iovlen);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(iov);
+ TALLOC_FREE(first_state->smb1.chained_requests);
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+struct tevent_queue *smbXcli_conn_send_queue(struct smbXcli_conn *conn)
+{
+ return conn->outgoing;
+}
+
+bool smbXcli_conn_has_async_calls(struct smbXcli_conn *conn)
+{
+ return ((tevent_queue_length(conn->outgoing) != 0)
+ || (talloc_array_length(conn->pending) != 0));
+}
+
+bool smbXcli_conn_dfs_supported(struct smbXcli_conn *conn)
+{
+ if (conn->protocol >= PROTOCOL_SMB2_02) {
+ return (smb2cli_conn_server_capabilities(conn) & SMB2_CAP_DFS);
+ }
+
+ return (smb1cli_conn_capabilities(conn) & CAP_DFS);
+}
+
+bool smb2cli_conn_req_possible(struct smbXcli_conn *conn, uint32_t *max_dyn_len)
+{
+ uint16_t credits = 1;
+
+ if (conn->smb2.cur_credits == 0) {
+ if (max_dyn_len != NULL) {
+ *max_dyn_len = 0;
+ }
+ return false;
+ }
+
+ if (conn->smb2.server.capabilities & SMB2_CAP_LARGE_MTU) {
+ credits = conn->smb2.cur_credits;
+ }
+
+ if (max_dyn_len != NULL) {
+ *max_dyn_len = credits * 65536;
+ }
+
+ return true;
+}
+
+uint32_t smb2cli_conn_server_capabilities(struct smbXcli_conn *conn)
+{
+ return conn->smb2.server.capabilities;
+}
+
+uint16_t smb2cli_conn_server_security_mode(struct smbXcli_conn *conn)
+{
+ return conn->smb2.server.security_mode;
+}
+
+uint16_t smb2cli_conn_server_signing_algo(struct smbXcli_conn *conn)
+{
+ return conn->smb2.server.sign_algo;
+}
+
+uint16_t smb2cli_conn_server_encryption_algo(struct smbXcli_conn *conn)
+{
+ return conn->smb2.server.cipher;
+}
+
+uint32_t smb2cli_conn_max_trans_size(struct smbXcli_conn *conn)
+{
+ return conn->smb2.server.max_trans_size;
+}
+
+uint32_t smb2cli_conn_max_read_size(struct smbXcli_conn *conn)
+{
+ return conn->smb2.server.max_read_size;
+}
+
+uint32_t smb2cli_conn_max_write_size(struct smbXcli_conn *conn)
+{
+ return conn->smb2.server.max_write_size;
+}
+
+void smb2cli_conn_set_max_credits(struct smbXcli_conn *conn,
+ uint16_t max_credits)
+{
+ conn->smb2.max_credits = max_credits;
+}
+
+uint16_t smb2cli_conn_get_cur_credits(struct smbXcli_conn *conn)
+{
+ return conn->smb2.cur_credits;
+}
+
+uint8_t smb2cli_conn_get_io_priority(struct smbXcli_conn *conn)
+{
+ if (conn->protocol < PROTOCOL_SMB3_11) {
+ return 0;
+ }
+
+ return conn->smb2.io_priority;
+}
+
+void smb2cli_conn_set_io_priority(struct smbXcli_conn *conn,
+ uint8_t io_priority)
+{
+ conn->smb2.io_priority = io_priority;
+}
+
+uint32_t smb2cli_conn_cc_chunk_len(struct smbXcli_conn *conn)
+{
+ return conn->smb2.cc_chunk_len;
+}
+
+void smb2cli_conn_set_cc_chunk_len(struct smbXcli_conn *conn,
+ uint32_t chunk_len)
+{
+ conn->smb2.cc_chunk_len = chunk_len;
+}
+
+uint32_t smb2cli_conn_cc_max_chunks(struct smbXcli_conn *conn)
+{
+ return conn->smb2.cc_max_chunks;
+}
+
+void smb2cli_conn_set_cc_max_chunks(struct smbXcli_conn *conn,
+ uint32_t max_chunks)
+{
+ conn->smb2.cc_max_chunks = max_chunks;
+}
+
+static void smb2cli_req_cancel_done(struct tevent_req *subreq);
+
+static bool smb2cli_req_cancel(struct tevent_req *req)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+ struct smbXcli_tcon *tcon = state->tcon;
+ struct smbXcli_session *session = state->session;
+ uint8_t *fixed = state->smb2.pad;
+ uint16_t fixed_len = 4;
+ struct tevent_req *subreq;
+ struct smbXcli_req_state *substate;
+ NTSTATUS status;
+
+ if (state->smb2.cancel_mid == UINT64_MAX) {
+ /*
+ * We already send a cancel,
+ * make sure we don't do it
+ * twice, otherwise we may
+ * expose the same NONCE for
+ * AES-128-GMAC signing
+ */
+ return true;
+ }
+
+ SSVAL(fixed, 0, 0x04);
+ SSVAL(fixed, 2, 0);
+
+ subreq = smb2cli_req_create(state, state->ev,
+ state->conn,
+ SMB2_OP_CANCEL,
+ 0, 0, /* flags */
+ 0, /* timeout */
+ tcon, session,
+ fixed, fixed_len,
+ NULL, 0, 0);
+ if (subreq == NULL) {
+ return false;
+ }
+ substate = tevent_req_data(subreq, struct smbXcli_req_state);
+
+ substate->smb2.cancel_mid = BVAL(state->smb2.hdr, SMB2_HDR_MESSAGE_ID);
+
+ SIVAL(substate->smb2.hdr, SMB2_HDR_FLAGS, state->smb2.cancel_flags);
+ SBVAL(substate->smb2.hdr, SMB2_HDR_MESSAGE_ID, state->smb2.cancel_mid);
+ SBVAL(substate->smb2.hdr, SMB2_HDR_ASYNC_ID, state->smb2.cancel_aid);
+
+ /*
+ * remember that we don't send a cancel again
+ */
+ state->smb2.cancel_mid = UINT64_MAX;
+
+ status = smb2cli_req_compound_submit(&subreq, 1);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(subreq);
+ return false;
+ }
+
+ tevent_req_set_callback(subreq, smb2cli_req_cancel_done, NULL);
+
+ return true;
+}
+
+static void smb2cli_req_cancel_done(struct tevent_req *subreq)
+{
+ /* we do not care about the result */
+ TALLOC_FREE(subreq);
+}
+
+struct timeval smbXcli_req_endtime(struct tevent_req *req)
+{
+ struct smbXcli_req_state *state = tevent_req_data(
+ req, struct smbXcli_req_state);
+
+ return state->endtime;
+}
+
+struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint16_t cmd,
+ uint32_t additional_flags,
+ uint32_t clear_flags,
+ uint32_t timeout_msec,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const uint8_t *fixed,
+ uint16_t fixed_len,
+ const uint8_t *dyn,
+ uint32_t dyn_len,
+ uint32_t max_dyn_len)
+{
+ struct tevent_req *req;
+ struct smbXcli_req_state *state;
+ uint32_t flags = 0;
+ uint32_t tid = 0;
+ uint64_t uid = 0;
+ bool use_channel_sequence = conn->smb2.force_channel_sequence;
+ uint16_t channel_sequence = 0;
+ bool use_replay_flag = false;
+ enum protocol_types proto = smbXcli_conn_protocol(conn);
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smbXcli_req_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if ((proto > PROTOCOL_NONE) && (proto < PROTOCOL_SMB2_02)) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return req;
+ }
+
+ state->ev = ev;
+ state->conn = conn;
+ state->session = session;
+ state->tcon = tcon;
+
+ if (conn->smb2.server.capabilities & SMB2_CAP_PERSISTENT_HANDLES) {
+ use_channel_sequence = true;
+ } else if (conn->smb2.server.capabilities & SMB2_CAP_MULTI_CHANNEL) {
+ use_channel_sequence = true;
+ }
+
+ if (smbXcli_conn_protocol(conn) >= PROTOCOL_SMB3_00) {
+ use_replay_flag = true;
+ }
+
+ if (smbXcli_conn_protocol(conn) >= PROTOCOL_SMB3_11) {
+ flags |= SMB2_PRIORITY_VALUE_TO_MASK(conn->smb2.io_priority);
+ }
+
+ if (session) {
+ uid = session->smb2->session_id;
+
+ if (use_channel_sequence) {
+ channel_sequence = session->smb2->channel_sequence;
+ }
+
+ if (use_replay_flag && session->smb2->replay_active) {
+ additional_flags |= SMB2_HDR_FLAG_REPLAY_OPERATION;
+ }
+
+ state->smb2.should_sign = session->smb2->should_sign;
+ state->smb2.should_encrypt = session->smb2->should_encrypt;
+ state->smb2.require_signed_response =
+ session->smb2->require_signed_response;
+
+ if (cmd == SMB2_OP_SESSSETUP &&
+ !smb2_signing_key_valid(session->smb2_channel.signing_key) &&
+ smb2_signing_key_valid(session->smb2->signing_key))
+ {
+ /*
+ * a session bind needs to be signed
+ */
+ state->smb2.should_sign = true;
+ }
+
+ if (cmd == SMB2_OP_SESSSETUP &&
+ !smb2_signing_key_valid(session->smb2_channel.signing_key)) {
+ state->smb2.should_encrypt = false;
+ }
+
+ if (additional_flags & SMB2_HDR_FLAG_SIGNED) {
+ if (!smb2_signing_key_valid(session->smb2_channel.signing_key)) {
+ tevent_req_nterror(req, NT_STATUS_NO_USER_SESSION_KEY);
+ return req;
+ }
+
+ additional_flags &= ~SMB2_HDR_FLAG_SIGNED;
+ state->smb2.should_sign = true;
+ }
+ }
+
+ if (tcon) {
+ tid = tcon->smb2.tcon_id;
+
+ if (tcon->smb2.should_sign) {
+ state->smb2.should_sign = true;
+ }
+ if (tcon->smb2.should_encrypt) {
+ state->smb2.should_encrypt = true;
+ }
+ }
+
+ if (state->smb2.should_encrypt) {
+ state->smb2.should_sign = false;
+ }
+
+ state->smb2.recv_iov = talloc_zero_array(state, struct iovec, 3);
+ if (tevent_req_nomem(state->smb2.recv_iov, req)) {
+ return req;
+ }
+
+ flags |= additional_flags;
+ flags &= ~clear_flags;
+
+ state->smb2.fixed = fixed;
+ state->smb2.fixed_len = fixed_len;
+ state->smb2.dyn = dyn;
+ state->smb2.dyn_len = dyn_len;
+ state->smb2.max_dyn_len = max_dyn_len;
+
+ if (state->smb2.should_encrypt) {
+ SIVAL(state->smb2.transform, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
+ SBVAL(state->smb2.transform, SMB2_TF_SESSION_ID, uid);
+ }
+
+ SIVAL(state->smb2.hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
+ SSVAL(state->smb2.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
+ SSVAL(state->smb2.hdr, SMB2_HDR_OPCODE, cmd);
+ SSVAL(state->smb2.hdr, SMB2_HDR_CHANNEL_SEQUENCE, channel_sequence);
+ SIVAL(state->smb2.hdr, SMB2_HDR_FLAGS, flags);
+ SIVAL(state->smb2.hdr, SMB2_HDR_PID, 0); /* reserved */
+ SIVAL(state->smb2.hdr, SMB2_HDR_TID, tid);
+ SBVAL(state->smb2.hdr, SMB2_HDR_SESSION_ID, uid);
+
+ switch (cmd) {
+ case SMB2_OP_CANCEL:
+ state->one_way = true;
+ break;
+ case SMB2_OP_BREAK:
+ /*
+ * If this is a dummy request, it will have
+ * UINT64_MAX as message id.
+ * If we send on break acknowledgement,
+ * this gets overwritten later.
+ */
+ SBVAL(state->smb2.hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
+ break;
+ }
+
+ if (timeout_msec > 0) {
+ state->endtime = timeval_current_ofs_msec(timeout_msec);
+ if (!tevent_req_set_endtime(req, ev, state->endtime)) {
+ return req;
+ }
+ }
+
+ return req;
+}
+
+void smb2cli_req_set_notify_async(struct tevent_req *req)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+
+ state->smb2.notify_async = true;
+}
+
+static void smb2cli_req_writev_done(struct tevent_req *subreq);
+static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
+ TALLOC_CTX *tmp_mem,
+ uint8_t *inbuf);
+
+NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs,
+ int num_reqs)
+{
+ struct smbXcli_req_state *state;
+ struct tevent_req *subreq;
+ struct iovec *iov;
+ int i, num_iov, nbt_len;
+ int tf_iov = -1;
+ struct smb2_signing_key *encryption_key = NULL;
+ uint64_t encryption_session_id = 0;
+ uint64_t nonce_high = UINT64_MAX;
+ uint64_t nonce_low = UINT64_MAX;
+
+ /*
+ * 1 for the nbt length, optional TRANSFORM
+ * per request: HDR, fixed, dyn, padding
+ * -1 because the last one does not need padding
+ */
+
+ iov = talloc_array(reqs[0], struct iovec, 1 + 1 + 4*num_reqs - 1);
+ if (iov == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ num_iov = 1;
+ nbt_len = 0;
+
+ /*
+ * the session of the first request that requires encryption
+ * specifies the encryption key.
+ */
+ for (i=0; i<num_reqs; i++) {
+ if (!tevent_req_is_in_progress(reqs[i])) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ state = tevent_req_data(reqs[i], struct smbXcli_req_state);
+
+ if (!smbXcli_conn_is_connected(state->conn)) {
+ return NT_STATUS_CONNECTION_DISCONNECTED;
+ }
+
+ if ((state->conn->protocol != PROTOCOL_NONE) &&
+ (state->conn->protocol < PROTOCOL_SMB2_02)) {
+ return NT_STATUS_REVISION_MISMATCH;
+ }
+
+ if (state->session == NULL) {
+ continue;
+ }
+
+ if (!state->smb2.should_encrypt) {
+ continue;
+ }
+
+ encryption_key = state->session->smb2->encryption_key;
+ if (!smb2_signing_key_valid(encryption_key)) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ encryption_session_id = state->session->smb2->session_id;
+
+ state->session->smb2->nonce_low += 1;
+ if (state->session->smb2->nonce_low == 0) {
+ state->session->smb2->nonce_high += 1;
+ state->session->smb2->nonce_low += 1;
+ }
+
+ /*
+ * CCM and GCM algorithms must never have their
+ * nonce wrap, or the security of the whole
+ * communication and the keys is destroyed.
+ * We must drop the connection once we have
+ * transferred too much data.
+ *
+ * NOTE: We assume nonces greater than 8 bytes.
+ */
+ if (state->session->smb2->nonce_high >=
+ state->session->smb2->nonce_high_max)
+ {
+ return NT_STATUS_ENCRYPTION_FAILED;
+ }
+
+ nonce_high = state->session->smb2->nonce_high_random;
+ nonce_high += state->session->smb2->nonce_high;
+ nonce_low = state->session->smb2->nonce_low;
+
+ tf_iov = num_iov;
+ iov[num_iov].iov_base = state->smb2.transform;
+ iov[num_iov].iov_len = sizeof(state->smb2.transform);
+ num_iov += 1;
+
+ SBVAL(state->smb2.transform, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
+ SBVAL(state->smb2.transform, SMB2_TF_NONCE,
+ nonce_low);
+ SBVAL(state->smb2.transform, SMB2_TF_NONCE+8,
+ nonce_high);
+ SBVAL(state->smb2.transform, SMB2_TF_SESSION_ID,
+ encryption_session_id);
+
+ nbt_len += SMB2_TF_HDR_SIZE;
+ break;
+ }
+
+ for (i=0; i<num_reqs; i++) {
+ int hdr_iov;
+ size_t reqlen;
+ bool ret;
+ uint16_t opcode;
+ uint64_t avail;
+ uint16_t charge;
+ uint16_t credits;
+ uint64_t mid;
+ struct smb2_signing_key *signing_key = NULL;
+
+ if (!tevent_req_is_in_progress(reqs[i])) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ state = tevent_req_data(reqs[i], struct smbXcli_req_state);
+
+ if (!smbXcli_conn_is_connected(state->conn)) {
+ return NT_STATUS_CONNECTION_DISCONNECTED;
+ }
+
+ if ((state->conn->protocol != PROTOCOL_NONE) &&
+ (state->conn->protocol < PROTOCOL_SMB2_02)) {
+ return NT_STATUS_REVISION_MISMATCH;
+ }
+
+ opcode = SVAL(state->smb2.hdr, SMB2_HDR_OPCODE);
+ if (opcode == SMB2_OP_CANCEL) {
+ goto skip_credits;
+ }
+
+ avail = UINT64_MAX - state->conn->smb2.mid;
+ if (avail < 1) {
+ return NT_STATUS_CONNECTION_ABORTED;
+ }
+
+ if (state->conn->smb2.server.capabilities & SMB2_CAP_LARGE_MTU) {
+ uint32_t max_dyn_len = 1;
+
+ max_dyn_len = MAX(max_dyn_len, state->smb2.dyn_len);
+ max_dyn_len = MAX(max_dyn_len, state->smb2.max_dyn_len);
+
+ charge = (max_dyn_len - 1)/ 65536 + 1;
+ } else {
+ charge = 1;
+ }
+
+ charge = MAX(state->smb2.credit_charge, charge);
+
+ avail = MIN(avail, state->conn->smb2.cur_credits);
+ if (avail < charge) {
+ DBG_ERR("Insufficient credits. "
+ "%"PRIu64" available, %"PRIu16" needed\n",
+ avail, charge);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ credits = 0;
+ if (state->conn->smb2.max_credits > state->conn->smb2.cur_credits) {
+ credits = state->conn->smb2.max_credits -
+ state->conn->smb2.cur_credits;
+ }
+ if (state->conn->smb2.max_credits >= state->conn->smb2.cur_credits) {
+ credits += 1;
+ }
+
+ mid = state->conn->smb2.mid;
+ state->conn->smb2.mid += charge;
+ state->conn->smb2.cur_credits -= charge;
+
+ if (state->conn->smb2.server.capabilities & SMB2_CAP_LARGE_MTU) {
+ SSVAL(state->smb2.hdr, SMB2_HDR_CREDIT_CHARGE, charge);
+ }
+ SSVAL(state->smb2.hdr, SMB2_HDR_CREDIT, credits);
+ SBVAL(state->smb2.hdr, SMB2_HDR_MESSAGE_ID, mid);
+
+ state->smb2.cancel_flags = SVAL(state->smb2.hdr, SMB2_HDR_FLAGS);
+ state->smb2.cancel_flags &= ~SMB2_HDR_FLAG_CHAINED;
+ if (state->conn->smb2.server.sign_algo >= SMB2_SIGNING_AES128_GMAC) {
+ state->smb2.cancel_mid = mid;
+ } else {
+ state->smb2.cancel_mid = 0;
+ }
+ state->smb2.cancel_aid = 0;
+
+skip_credits:
+ if (state->session && encryption_key == NULL) {
+ /*
+ * We prefer the channel signing key if it is
+ * already there.
+ */
+ if (state->smb2.should_sign) {
+ signing_key = state->session->smb2_channel.signing_key;
+ }
+
+ /*
+ * If it is a channel binding, we already have the main
+ * signing key and try that one.
+ */
+ if (signing_key != NULL &&
+ !smb2_signing_key_valid(signing_key)) {
+ signing_key = state->session->smb2->signing_key;
+ }
+
+ /*
+ * If we do not have any session key yet, we skip the
+ * signing of SMB2_OP_SESSSETUP requests.
+ */
+ if (signing_key != NULL &&
+ !smb2_signing_key_valid(signing_key)) {
+ signing_key = NULL;
+ }
+ }
+
+ hdr_iov = num_iov;
+ iov[num_iov].iov_base = state->smb2.hdr;
+ iov[num_iov].iov_len = sizeof(state->smb2.hdr);
+ num_iov += 1;
+
+ iov[num_iov].iov_base = discard_const(state->smb2.fixed);
+ iov[num_iov].iov_len = state->smb2.fixed_len;
+ num_iov += 1;
+
+ if (state->smb2.dyn != NULL) {
+ iov[num_iov].iov_base = discard_const(state->smb2.dyn);
+ iov[num_iov].iov_len = state->smb2.dyn_len;
+ num_iov += 1;
+ }
+
+ reqlen = sizeof(state->smb2.hdr);
+ reqlen += state->smb2.fixed_len;
+ reqlen += state->smb2.dyn_len;
+
+ if (i < num_reqs-1) {
+ if ((reqlen % 8) > 0) {
+ uint8_t pad = 8 - (reqlen % 8);
+ iov[num_iov].iov_base = state->smb2.pad;
+ iov[num_iov].iov_len = pad;
+ num_iov += 1;
+ reqlen += pad;
+ }
+ SIVAL(state->smb2.hdr, SMB2_HDR_NEXT_COMMAND, reqlen);
+ }
+
+ state->smb2.encryption_session_id = encryption_session_id;
+
+ if (signing_key != NULL) {
+ NTSTATUS status;
+
+ status = smb2_signing_sign_pdu(signing_key,
+ &iov[hdr_iov], num_iov - hdr_iov);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ nbt_len += reqlen;
+
+ ret = smbXcli_req_set_pending(reqs[i]);
+ if (!ret) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ state = tevent_req_data(reqs[0], struct smbXcli_req_state);
+ _smb_setlen_tcp(state->length_hdr, nbt_len);
+ iov[0].iov_base = state->length_hdr;
+ iov[0].iov_len = sizeof(state->length_hdr);
+
+ if (encryption_key != NULL) {
+ NTSTATUS status;
+ size_t buflen = nbt_len - SMB2_TF_HDR_SIZE;
+ uint8_t *buf;
+ int vi;
+
+ buf = talloc_array(iov, uint8_t, buflen);
+ if (buf == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /*
+ * We copy the buffers before encrypting them,
+ * this is at least currently needed for the
+ * to keep state->smb2.hdr.
+ *
+ * Also the callers may expect there buffers
+ * to be const.
+ */
+ for (vi = tf_iov + 1; vi < num_iov; vi++) {
+ struct iovec *v = &iov[vi];
+ const uint8_t *o = (const uint8_t *)v->iov_base;
+
+ memcpy(buf, o, v->iov_len);
+ v->iov_base = (void *)buf;
+ buf += v->iov_len;
+ }
+
+ status = smb2_signing_encrypt_pdu(encryption_key,
+ &iov[tf_iov], num_iov - tf_iov);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ if (state->conn->dispatch_incoming == NULL) {
+ state->conn->dispatch_incoming = smb2cli_conn_dispatch_incoming;
+ }
+
+ subreq = writev_send(state, state->ev, state->conn->outgoing,
+ state->conn->sock_fd, false, iov, num_iov);
+ if (subreq == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ tevent_req_set_callback(subreq, smb2cli_req_writev_done, reqs[0]);
+ state->write_req = subreq;
+
+ return NT_STATUS_OK;
+}
+
+void smb2cli_req_set_credit_charge(struct tevent_req *req, uint16_t charge)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+
+ state->smb2.credit_charge = charge;
+}
+
+struct tevent_req *smb2cli_req_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint16_t cmd,
+ uint32_t additional_flags,
+ uint32_t clear_flags,
+ uint32_t timeout_msec,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const uint8_t *fixed,
+ uint16_t fixed_len,
+ const uint8_t *dyn,
+ uint32_t dyn_len,
+ uint32_t max_dyn_len)
+{
+ struct tevent_req *req;
+ NTSTATUS status;
+
+ req = smb2cli_req_create(mem_ctx, ev, conn, cmd,
+ additional_flags, clear_flags,
+ timeout_msec,
+ tcon, session,
+ fixed, fixed_len,
+ dyn, dyn_len,
+ max_dyn_len);
+ if (req == NULL) {
+ return NULL;
+ }
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+ status = smb2cli_req_compound_submit(&req, 1);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+ return req;
+}
+
+static void smb2cli_req_writev_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+ ssize_t nwritten;
+ int err;
+
+ state->write_req = NULL;
+
+ nwritten = writev_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (nwritten == -1) {
+ /* here, we need to notify all pending requests */
+ NTSTATUS status = map_nt_error_from_unix_common(err);
+ smbXcli_conn_disconnect(state->conn, status);
+ return;
+ }
+}
+
+static struct smbXcli_session* smbXcli_session_by_uid(struct smbXcli_conn *conn,
+ uint64_t uid)
+{
+ struct smbXcli_session *s = conn->sessions;
+
+ for (; s; s = s->next) {
+ if (s->smb2->session_id != uid) {
+ continue;
+ }
+ break;
+ }
+
+ return s;
+}
+
+static NTSTATUS smb2cli_inbuf_parse_compound(struct smbXcli_conn *conn,
+ uint8_t *buf,
+ size_t buflen,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **piov,
+ size_t *pnum_iov)
+{
+ struct iovec *iov;
+ int num_iov = 0;
+ size_t taken = 0;
+ uint8_t *first_hdr = buf;
+ size_t verified_buflen = 0;
+ uint8_t *tf = NULL;
+ size_t tf_len = 0;
+
+ iov = talloc_array(mem_ctx, struct iovec, num_iov);
+ if (iov == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ while (taken < buflen) {
+ size_t len = buflen - taken;
+ uint8_t *hdr = first_hdr + taken;
+ struct iovec *cur;
+ size_t full_size;
+ size_t next_command_ofs;
+ uint16_t body_size;
+ struct iovec *iov_tmp;
+
+ if (verified_buflen > taken) {
+ len = verified_buflen - taken;
+ } else {
+ tf = NULL;
+ tf_len = 0;
+ }
+
+ if (len < 4) {
+ DEBUG(10, ("%d bytes left, expected at least %d\n",
+ (int)len, 4));
+ goto inval;
+ }
+ if (IVAL(hdr, 0) == SMB2_TF_MAGIC) {
+ struct smbXcli_session *s;
+ uint64_t uid;
+ struct iovec tf_iov[2];
+ size_t enc_len;
+ NTSTATUS status;
+
+ if (len < SMB2_TF_HDR_SIZE) {
+ DEBUG(10, ("%d bytes left, expected at least %d\n",
+ (int)len, SMB2_TF_HDR_SIZE));
+ goto inval;
+ }
+ tf = hdr;
+ tf_len = SMB2_TF_HDR_SIZE;
+ taken += tf_len;
+
+ hdr = first_hdr + taken;
+ enc_len = IVAL(tf, SMB2_TF_MSG_SIZE);
+ uid = BVAL(tf, SMB2_TF_SESSION_ID);
+
+ if (len < SMB2_TF_HDR_SIZE + enc_len) {
+ DEBUG(10, ("%d bytes left, expected at least %d\n",
+ (int)len,
+ (int)(SMB2_TF_HDR_SIZE + enc_len)));
+ goto inval;
+ }
+
+ s = smbXcli_session_by_uid(conn, uid);
+ if (s == NULL) {
+ DEBUG(10, ("unknown session_id %llu\n",
+ (unsigned long long)uid));
+ goto inval;
+ }
+
+ tf_iov[0].iov_base = (void *)tf;
+ tf_iov[0].iov_len = tf_len;
+ tf_iov[1].iov_base = (void *)hdr;
+ tf_iov[1].iov_len = enc_len;
+
+ status = smb2_signing_decrypt_pdu(s->smb2->decryption_key,
+ tf_iov, 2);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(iov);
+ return status;
+ }
+
+ verified_buflen = taken + enc_len;
+ len = enc_len;
+ }
+
+ /*
+ * We need the header plus the body length field
+ */
+
+ if (len < SMB2_HDR_BODY + 2) {
+ DEBUG(10, ("%d bytes left, expected at least %d\n",
+ (int)len, SMB2_HDR_BODY));
+ goto inval;
+ }
+ if (IVAL(hdr, 0) != SMB2_MAGIC) {
+ DEBUG(10, ("Got non-SMB2 PDU: %x\n",
+ IVAL(hdr, 0)));
+ goto inval;
+ }
+ if (SVAL(hdr, 4) != SMB2_HDR_BODY) {
+ DEBUG(10, ("Got HDR len %d, expected %d\n",
+ SVAL(hdr, 4), SMB2_HDR_BODY));
+ goto inval;
+ }
+
+ full_size = len;
+ next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
+ body_size = SVAL(hdr, SMB2_HDR_BODY);
+
+ if (next_command_ofs != 0) {
+ if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
+ goto inval;
+ }
+ if (next_command_ofs > full_size) {
+ goto inval;
+ }
+ full_size = next_command_ofs;
+ }
+ if (body_size < 2) {
+ goto inval;
+ }
+ body_size &= 0xfffe;
+
+ if (body_size > (full_size - SMB2_HDR_BODY)) {
+ goto inval;
+ }
+
+ iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec,
+ num_iov + 4);
+ if (iov_tmp == NULL) {
+ TALLOC_FREE(iov);
+ return NT_STATUS_NO_MEMORY;
+ }
+ iov = iov_tmp;
+ cur = &iov[num_iov];
+ num_iov += 4;
+
+ cur[0].iov_base = tf;
+ cur[0].iov_len = tf_len;
+ cur[1].iov_base = hdr;
+ cur[1].iov_len = SMB2_HDR_BODY;
+ cur[2].iov_base = hdr + SMB2_HDR_BODY;
+ cur[2].iov_len = body_size;
+ cur[3].iov_base = hdr + SMB2_HDR_BODY + body_size;
+ cur[3].iov_len = full_size - (SMB2_HDR_BODY + body_size);
+
+ taken += full_size;
+ }
+
+ *piov = iov;
+ *pnum_iov = num_iov;
+ return NT_STATUS_OK;
+
+inval:
+ TALLOC_FREE(iov);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+}
+
+static struct tevent_req *smb2cli_conn_find_pending(struct smbXcli_conn *conn,
+ uint64_t mid)
+{
+ size_t num_pending = talloc_array_length(conn->pending);
+ size_t i;
+
+ for (i=0; i<num_pending; i++) {
+ struct tevent_req *req = conn->pending[i];
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+
+ if (mid == BVAL(state->smb2.hdr, SMB2_HDR_MESSAGE_ID)) {
+ return req;
+ }
+ }
+ return NULL;
+}
+
+static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
+ TALLOC_CTX *tmp_mem,
+ uint8_t *inbuf)
+{
+ struct tevent_req *req;
+ struct smbXcli_req_state *state = NULL;
+ struct iovec *iov = NULL;
+ size_t i, num_iov = 0;
+ NTSTATUS status;
+ bool defer = true;
+ struct smbXcli_session *last_session = NULL;
+ size_t inbuf_len = smb_len_tcp(inbuf);
+
+ status = smb2cli_inbuf_parse_compound(conn,
+ inbuf + NBT_HDR_SIZE,
+ inbuf_len,
+ tmp_mem,
+ &iov, &num_iov);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ for (i=0; i<num_iov; i+=4) {
+ uint8_t *inbuf_ref = NULL;
+ struct iovec *cur = &iov[i];
+ uint8_t *inhdr = (uint8_t *)cur[1].iov_base;
+ uint16_t opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
+ uint32_t flags = IVAL(inhdr, SMB2_HDR_FLAGS);
+ uint64_t mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
+ uint16_t req_opcode;
+ uint32_t req_flags;
+ uint16_t credits = SVAL(inhdr, SMB2_HDR_CREDIT);
+ uint32_t new_credits;
+ struct smbXcli_session *session = NULL;
+ struct smb2_signing_key *signing_key = NULL;
+ bool was_encrypted = false;
+
+ new_credits = conn->smb2.cur_credits;
+ new_credits += credits;
+ if (new_credits > UINT16_MAX) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ conn->smb2.cur_credits += credits;
+
+ req = smb2cli_conn_find_pending(conn, mid);
+ if (req == NULL) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ state = tevent_req_data(req, struct smbXcli_req_state);
+
+ req_opcode = SVAL(state->smb2.hdr, SMB2_HDR_OPCODE);
+ if (opcode != req_opcode) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ req_flags = SVAL(state->smb2.hdr, SMB2_HDR_FLAGS);
+
+ if (!(flags & SMB2_HDR_FLAG_REDIRECT)) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ status = NT_STATUS(IVAL(inhdr, SMB2_HDR_STATUS));
+ if ((flags & SMB2_HDR_FLAG_ASYNC) &&
+ NT_STATUS_EQUAL(status, NT_STATUS_PENDING)) {
+ uint64_t async_id = BVAL(inhdr, SMB2_HDR_ASYNC_ID);
+
+ if (state->smb2.got_async) {
+ /* We only expect one STATUS_PENDING response */
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ state->smb2.got_async = true;
+
+ /*
+ * async interim responses are not signed,
+ * even if the SMB2_HDR_FLAG_SIGNED flag
+ * is set.
+ */
+ state->smb2.cancel_flags |= SMB2_HDR_FLAG_ASYNC;
+ state->smb2.cancel_aid = async_id;
+
+ if (state->smb2.notify_async) {
+ tevent_req_defer_callback(req, state->ev);
+ tevent_req_notify_callback(req);
+ }
+ continue;
+ }
+
+ session = state->session;
+ if (req_flags & SMB2_HDR_FLAG_CHAINED) {
+ session = last_session;
+ }
+ last_session = session;
+
+ if (flags & SMB2_HDR_FLAG_SIGNED) {
+ uint64_t uid = BVAL(inhdr, SMB2_HDR_SESSION_ID);
+
+ if (session == NULL) {
+ session = smbXcli_session_by_uid(state->conn,
+ uid);
+ }
+
+ if (session == NULL) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ last_session = session;
+ signing_key = session->smb2_channel.signing_key;
+ }
+
+ if (opcode == SMB2_OP_SESSSETUP) {
+ /*
+ * We prefer the channel signing key, if it is
+ * already there.
+ *
+ * If we do not have a channel signing key yet,
+ * we try the main signing key, if it is not
+ * the final response.
+ */
+ if (signing_key != NULL &&
+ !smb2_signing_key_valid(signing_key) &&
+ !NT_STATUS_IS_OK(status)) {
+ signing_key = session->smb2->signing_key;
+ }
+
+ if (signing_key != NULL &&
+ !smb2_signing_key_valid(signing_key)) {
+ /*
+ * If we do not have a session key to
+ * verify the signature, we defer the
+ * signing check to the caller.
+ *
+ * The caller gets NT_STATUS_OK, it
+ * has to call
+ * smb2cli_session_set_session_key()
+ * or
+ * smb2cli_session_set_channel_key()
+ * which will check the signature
+ * with the channel signing key.
+ */
+ signing_key = NULL;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ /*
+ * Only check the signature of the last response
+ * of a successful session auth. This matches
+ * Windows behaviour for NTLM auth and reauth.
+ */
+ state->smb2.require_signed_response = false;
+ }
+ }
+
+ if (state->smb2.should_sign ||
+ state->smb2.require_signed_response)
+ {
+ if (!(flags & SMB2_HDR_FLAG_SIGNED)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ if (!smb2_signing_key_valid(signing_key) &&
+ state->smb2.require_signed_response) {
+ signing_key = session->smb2_channel.signing_key;
+ }
+
+ if (cur[0].iov_len == SMB2_TF_HDR_SIZE) {
+ const uint8_t *tf = (const uint8_t *)cur[0].iov_base;
+ uint64_t uid = BVAL(tf, SMB2_TF_SESSION_ID);
+
+ /*
+ * If the response was encrypted in a SMB2_TRANSFORM
+ * pdu, which belongs to the correct session,
+ * we do not need to do signing checks
+ *
+ * It could be the session the response belongs to
+ * or the session that was used to encrypt the
+ * SMB2_TRANSFORM request.
+ */
+ if ((session && session->smb2->session_id == uid) ||
+ (state->smb2.encryption_session_id == uid)) {
+ signing_key = NULL;
+ was_encrypted = true;
+ }
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) {
+ /*
+ * if the server returns NT_STATUS_USER_SESSION_DELETED
+ * the response is not signed and we should
+ * propagate the NT_STATUS_USER_SESSION_DELETED
+ * status to the caller.
+ */
+ state->smb2.signing_skipped = true;
+ signing_key = NULL;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_REQUEST_OUT_OF_SEQUENCE)) {
+ /*
+ * if the server returns
+ * NT_STATUS_REQUEST_OUT_OF_SEQUENCE for a session setup
+ * request, the response is not signed and we should
+ * propagate the NT_STATUS_REQUEST_OUT_OF_SEQUENCE
+ * status to the caller
+ */
+ if (opcode == SMB2_OP_SESSSETUP) {
+ state->smb2.signing_skipped = true;
+ signing_key = NULL;
+ }
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
+ /*
+ * if the server returns NT_STATUS_NOT_SUPPORTED
+ * for a session setup request, the response is not
+ * signed and we should propagate the NT_STATUS_NOT_SUPPORTED
+ * status to the caller.
+ */
+ if (opcode == SMB2_OP_SESSSETUP) {
+ state->smb2.signing_skipped = true;
+ signing_key = NULL;
+ }
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ /*
+ * if the server returns
+ * NT_STATUS_ACCESS_DENIED for a session setup
+ * request, the response is not signed and we should
+ * propagate the NT_STATUS_ACCESS_DENIED
+ * status to the caller without disconnecting
+ * the connection because we where not able to
+ * verify the response signature.
+ */
+ if (opcode == SMB2_OP_SESSSETUP) {
+ state->smb2.signing_skipped = true;
+ signing_key = NULL;
+ }
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ /*
+ * if the server returns
+ * NT_STATUS_INVALID_PARAMETER
+ * the response might not be encrypted.
+ */
+ if (state->smb2.should_encrypt && !was_encrypted) {
+ state->smb2.signing_skipped = true;
+ signing_key = NULL;
+ }
+ }
+
+ if (state->smb2.should_encrypt && !was_encrypted) {
+ if (!state->smb2.signing_skipped) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ /*
+ * if the server returns
+ * NT_STATUS_NETWORK_NAME_DELETED
+ * NT_STATUS_FILE_CLOSED
+ * NT_STATUS_INVALID_PARAMETER
+ * the response might not be signed
+ * as this happens before the signing checks.
+ *
+ * If server echos the signature (or all zeros)
+ * we should report the status from the server
+ * to the caller.
+ */
+ if (signing_key) {
+ bool cmp;
+
+ cmp = mem_equal_const_time(inhdr+SMB2_HDR_SIGNATURE,
+ state->smb2.hdr+SMB2_HDR_SIGNATURE,
+ 16);
+ if (cmp) {
+ state->smb2.signing_skipped = true;
+ signing_key = NULL;
+ }
+ }
+ if (signing_key) {
+ bool zero;
+ zero = all_zero(inhdr+SMB2_HDR_SIGNATURE, 16);
+ if (zero) {
+ state->smb2.signing_skipped = true;
+ signing_key = NULL;
+ }
+ }
+ }
+
+ if (signing_key) {
+ NTSTATUS signing_status;
+
+ signing_status = smb2_signing_check_pdu(signing_key,
+ &cur[1], 3);
+ if (!NT_STATUS_IS_OK(signing_status)) {
+ /*
+ * If the signing check fails, we disconnect
+ * the connection.
+ */
+ return signing_status;
+ }
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED) &&
+ (session != NULL) && session->disconnect_expired)
+ {
+ /*
+ * this should be a short term hack
+ * until the upper layers have implemented
+ * re-authentication.
+ */
+ return status;
+ }
+
+ smbXcli_req_unset_pending(req);
+
+ /*
+ * There might be more than one response
+ * we need to defer the notifications
+ */
+ if ((num_iov == 5) && (talloc_array_length(conn->pending) == 0)) {
+ defer = false;
+ }
+
+ if (defer) {
+ tevent_req_defer_callback(req, state->ev);
+ }
+
+ /*
+ * Note: here we use talloc_reference() in a way
+ * that does not expose it to the caller.
+ */
+ inbuf_ref = talloc_reference(state->smb2.recv_iov, inbuf);
+ if (tevent_req_nomem(inbuf_ref, req)) {
+ continue;
+ }
+
+ /* copy the related buffers */
+ state->smb2.recv_iov[0] = cur[1];
+ state->smb2.recv_iov[1] = cur[2];
+ state->smb2.recv_iov[2] = cur[3];
+
+ tevent_req_done(req);
+ }
+
+ if (defer) {
+ return NT_STATUS_RETRY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct iovec **piov,
+ const struct smb2cli_req_expected_response *expected,
+ size_t num_expected)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+ NTSTATUS status;
+ size_t body_size;
+ bool found_status = false;
+ bool found_size = false;
+ size_t i;
+
+ if (piov != NULL) {
+ *piov = NULL;
+ }
+
+ if (tevent_req_is_in_progress(req) && state->smb2.got_async) {
+ return NT_STATUS_PENDING;
+ }
+
+ if (tevent_req_is_nterror(req, &status)) {
+ for (i=0; i < num_expected; i++) {
+ if (NT_STATUS_EQUAL(status, expected[i].status)) {
+ return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+ }
+ }
+
+ return status;
+ }
+
+ if (num_expected == 0) {
+ found_status = true;
+ found_size = true;
+ }
+
+ status = NT_STATUS(IVAL(state->smb2.recv_iov[0].iov_base, SMB2_HDR_STATUS));
+ body_size = SVAL(state->smb2.recv_iov[1].iov_base, 0);
+
+ for (i=0; i < num_expected; i++) {
+ if (!NT_STATUS_EQUAL(status, expected[i].status)) {
+ continue;
+ }
+
+ found_status = true;
+ if (expected[i].body_size == 0) {
+ found_size = true;
+ break;
+ }
+
+ if (expected[i].body_size == body_size) {
+ found_size = true;
+ break;
+ }
+ }
+
+ if (!found_status) {
+ return status;
+ }
+
+ if (state->smb2.signing_skipped) {
+ if (num_expected > 0) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ if (!NT_STATUS_IS_ERR(status)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ if (!found_size) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ if (piov != NULL) {
+ *piov = talloc_move(mem_ctx, &state->smb2.recv_iov);
+ }
+
+ return status;
+}
+
+NTSTATUS smb2cli_req_get_sent_iov(struct tevent_req *req,
+ struct iovec *sent_iov)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+
+ if (tevent_req_is_in_progress(req)) {
+ return NT_STATUS_PENDING;
+ }
+
+ sent_iov[0].iov_base = state->smb2.hdr;
+ sent_iov[0].iov_len = sizeof(state->smb2.hdr);
+
+ sent_iov[1].iov_base = discard_const(state->smb2.fixed);
+ sent_iov[1].iov_len = state->smb2.fixed_len;
+
+ if (state->smb2.dyn != NULL) {
+ sent_iov[2].iov_base = discard_const(state->smb2.dyn);
+ sent_iov[2].iov_len = state->smb2.dyn_len;
+ } else {
+ sent_iov[2].iov_base = NULL;
+ sent_iov[2].iov_len = 0;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static const struct {
+ enum protocol_types proto;
+ const char *smb1_name;
+} smb1cli_prots[] = {
+ {PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"},
+ {PROTOCOL_COREPLUS, "MICROSOFT NETWORKS 1.03"},
+ {PROTOCOL_LANMAN1, "MICROSOFT NETWORKS 3.0"},
+ {PROTOCOL_LANMAN1, "LANMAN1.0"},
+ {PROTOCOL_LANMAN2, "LM1.2X002"},
+ {PROTOCOL_LANMAN2, "DOS LANMAN2.1"},
+ {PROTOCOL_LANMAN2, "LANMAN2.1"},
+ {PROTOCOL_LANMAN2, "Samba"},
+ {PROTOCOL_NT1, "NT LANMAN 1.0"},
+ {PROTOCOL_NT1, "NT LM 0.12"},
+ {PROTOCOL_SMB2_02, "SMB 2.002"},
+ {PROTOCOL_SMB2_10, "SMB 2.???"},
+};
+
+static const struct {
+ enum protocol_types proto;
+ uint16_t smb2_dialect;
+} smb2cli_prots[] = {
+ {PROTOCOL_SMB2_02, SMB2_DIALECT_REVISION_202},
+ {PROTOCOL_SMB2_10, SMB2_DIALECT_REVISION_210},
+ {PROTOCOL_SMB3_00, SMB3_DIALECT_REVISION_300},
+ {PROTOCOL_SMB3_02, SMB3_DIALECT_REVISION_302},
+ {PROTOCOL_SMB3_11, SMB3_DIALECT_REVISION_311},
+};
+
+struct smbXcli_negprot_state {
+ struct smbXcli_conn *conn;
+ struct tevent_context *ev;
+ struct smb2_negotiate_contexts *in_ctx;
+ struct smb2_negotiate_contexts *out_ctx;
+ uint32_t timeout_msec;
+
+ struct {
+ uint8_t fixed[36];
+ } smb2;
+};
+
+static void smbXcli_negprot_invalid_done(struct tevent_req *subreq);
+static struct tevent_req *smbXcli_negprot_smb1_subreq(struct smbXcli_negprot_state *state);
+static void smbXcli_negprot_smb1_done(struct tevent_req *subreq);
+static struct tevent_req *smbXcli_negprot_smb2_subreq(struct smbXcli_negprot_state *state);
+static void smbXcli_negprot_smb2_done(struct tevent_req *subreq);
+static NTSTATUS smbXcli_negprot_dispatch_incoming(struct smbXcli_conn *conn,
+ TALLOC_CTX *frame,
+ uint8_t *inbuf);
+
+struct tevent_req *smbXcli_negprot_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ enum protocol_types min_protocol,
+ enum protocol_types max_protocol,
+ uint16_t max_credits,
+ struct smb2_negotiate_contexts *in_ctx)
+{
+ struct tevent_req *req, *subreq;
+ struct smbXcli_negprot_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smbXcli_negprot_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->conn = conn;
+ state->ev = ev;
+ state->in_ctx = in_ctx;
+ state->timeout_msec = timeout_msec;
+
+ if (min_protocol == PROTOCOL_NONE) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (max_protocol == PROTOCOL_NONE) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (min_protocol > max_protocol) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ conn->min_protocol = min_protocol;
+ conn->max_protocol = max_protocol;
+ conn->protocol = PROTOCOL_NONE;
+
+ if (max_protocol >= PROTOCOL_SMB2_02) {
+ conn->smb2.max_credits = max_credits;
+ }
+
+ if ((min_protocol < PROTOCOL_SMB2_02) &&
+ (max_protocol < PROTOCOL_SMB2_02)) {
+ /*
+ * SMB1 only...
+ */
+ conn->dispatch_incoming = smb1cli_conn_dispatch_incoming;
+
+ subreq = smbXcli_negprot_smb1_subreq(state);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smbXcli_negprot_smb1_done, req);
+ return req;
+ }
+
+ if ((min_protocol >= PROTOCOL_SMB2_02) &&
+ (max_protocol >= PROTOCOL_SMB2_02)) {
+ /*
+ * SMB2 only...
+ */
+ conn->dispatch_incoming = smb2cli_conn_dispatch_incoming;
+
+ subreq = smbXcli_negprot_smb2_subreq(state);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smbXcli_negprot_smb2_done, req);
+ return req;
+ }
+
+ /*
+ * We send an SMB1 negprot with the SMB2 dialects
+ * and expect a SMB1 or a SMB2 response.
+ *
+ * smbXcli_negprot_dispatch_incoming() will fix the
+ * callback to match protocol of the response.
+ */
+ conn->dispatch_incoming = smbXcli_negprot_dispatch_incoming;
+
+ subreq = smbXcli_negprot_smb1_subreq(state);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smbXcli_negprot_invalid_done, req);
+ return req;
+}
+
+static void smbXcli_negprot_invalid_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ NTSTATUS status;
+
+ /*
+ * we just want the low level error
+ */
+ status = tevent_req_simple_recv_ntstatus(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ /* this should never happen */
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+}
+
+static struct tevent_req *smbXcli_negprot_smb1_subreq(struct smbXcli_negprot_state *state)
+{
+ size_t i;
+ DATA_BLOB bytes = data_blob_null;
+ uint8_t flags;
+ uint16_t flags2;
+
+ /* setup the protocol strings */
+ for (i=0; i < ARRAY_SIZE(smb1cli_prots); i++) {
+ uint8_t c = 2;
+ bool ok;
+
+ if (smb1cli_prots[i].proto < state->conn->min_protocol) {
+ continue;
+ }
+
+ if (smb1cli_prots[i].proto > state->conn->max_protocol) {
+ continue;
+ }
+
+ ok = data_blob_append(state, &bytes, &c, sizeof(c));
+ if (!ok) {
+ return NULL;
+ }
+
+ /*
+ * We know it is already ascii and
+ * we want NULL termination.
+ */
+ ok = data_blob_append(state, &bytes,
+ smb1cli_prots[i].smb1_name,
+ strlen(smb1cli_prots[i].smb1_name)+1);
+ if (!ok) {
+ return NULL;
+ }
+ }
+
+ smb1cli_req_flags(state->conn->max_protocol,
+ state->conn->smb1.client.capabilities,
+ SMBnegprot,
+ 0, 0, &flags,
+ 0, 0, &flags2);
+
+ return smb1cli_req_send(state, state->ev, state->conn,
+ SMBnegprot,
+ flags, ~flags,
+ flags2, ~flags2,
+ state->timeout_msec,
+ 0xFFFE, 0, NULL, /* pid, tid, session */
+ 0, NULL, /* wct, vwv */
+ bytes.length, bytes.data);
+}
+
+static void smbXcli_negprot_smb1_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smbXcli_negprot_state *state =
+ tevent_req_data(req,
+ struct smbXcli_negprot_state);
+ struct smbXcli_conn *conn = state->conn;
+ struct iovec *recv_iov = NULL;
+ uint8_t *inhdr = NULL;
+ uint8_t wct;
+ uint16_t *vwv;
+ uint32_t num_bytes;
+ uint8_t *bytes;
+ NTSTATUS status;
+ uint16_t protnum;
+ size_t i;
+ size_t num_prots = 0;
+ uint8_t flags;
+ uint32_t client_capabilities = conn->smb1.client.capabilities;
+ uint32_t both_capabilities;
+ uint32_t server_capabilities = 0;
+ uint32_t capabilities;
+ uint32_t client_max_xmit = conn->smb1.client.max_xmit;
+ uint32_t server_max_xmit = 0;
+ uint32_t max_xmit;
+ uint32_t server_max_mux = 0;
+ uint16_t server_security_mode = 0;
+ uint32_t server_session_key = 0;
+ bool server_readbraw = false;
+ bool server_writebraw = false;
+ bool server_lockread = false;
+ bool server_writeunlock = false;
+ struct GUID server_guid = GUID_zero();
+ DATA_BLOB server_gss_blob = data_blob_null;
+ uint8_t server_challenge[8];
+ char *server_workgroup = NULL;
+ char *server_name = NULL;
+ int server_time_zone = 0;
+ NTTIME server_system_time = 0;
+ static const struct smb1cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .wct = 0x11, /* NT1 */
+ },
+ {
+ .status = NT_STATUS_OK,
+ .wct = 0x0D, /* LM */
+ },
+ {
+ .status = NT_STATUS_OK,
+ .wct = 0x01, /* CORE */
+ }
+ };
+
+ ZERO_STRUCT(server_challenge);
+
+ status = smb1cli_req_recv(subreq, state,
+ &recv_iov,
+ &inhdr,
+ &wct,
+ &vwv,
+ NULL, /* pvwv_offset */
+ &num_bytes,
+ &bytes,
+ NULL, /* pbytes_offset */
+ NULL, /* pinbuf */
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ if (inhdr == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return;
+ }
+
+ flags = CVAL(inhdr, HDR_FLG);
+
+ protnum = SVAL(vwv, 0);
+
+ for (i=0; i < ARRAY_SIZE(smb1cli_prots); i++) {
+ if (smb1cli_prots[i].proto < state->conn->min_protocol) {
+ continue;
+ }
+
+ if (smb1cli_prots[i].proto > state->conn->max_protocol) {
+ continue;
+ }
+
+ if (protnum != num_prots) {
+ num_prots++;
+ continue;
+ }
+
+ conn->protocol = smb1cli_prots[i].proto;
+ break;
+ }
+
+ if (conn->protocol == PROTOCOL_NONE) {
+ DBG_ERR("No compatible protocol selected by server.\n");
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if ((conn->protocol < PROTOCOL_NT1) && conn->mandatory_signing) {
+ DEBUG(0,("smbXcli_negprot: SMB signing is mandatory "
+ "and the selected protocol level doesn't support it.\n"));
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+
+ if (flags & FLAG_SUPPORT_LOCKREAD) {
+ server_lockread = true;
+ server_writeunlock = true;
+ }
+
+ if (conn->protocol >= PROTOCOL_NT1) {
+ const char *client_signing = NULL;
+ bool server_mandatory = false;
+ bool server_allowed = false;
+ const char *server_signing = NULL;
+ bool ok;
+ uint8_t key_len;
+
+ if (wct != 0x11) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ /* NT protocol */
+ server_security_mode = CVAL(vwv + 1, 0);
+ server_max_mux = SVAL(vwv + 1, 1);
+ server_max_xmit = IVAL(vwv + 3, 1);
+ server_session_key = IVAL(vwv + 7, 1);
+ server_time_zone = SVALS(vwv + 15, 1);
+ server_time_zone *= 60;
+ /* this time arrives in real GMT */
+ server_system_time = BVAL(vwv + 11, 1);
+ server_capabilities = IVAL(vwv + 9, 1);
+
+ key_len = CVAL(vwv + 16, 1);
+
+ if (server_capabilities & CAP_RAW_MODE) {
+ server_readbraw = true;
+ server_writebraw = true;
+ }
+ if (server_capabilities & CAP_LOCK_AND_READ) {
+ server_lockread = true;
+ }
+
+ if (server_capabilities & CAP_EXTENDED_SECURITY) {
+ DATA_BLOB blob1, blob2;
+
+ if (num_bytes < 16) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ blob1 = data_blob_const(bytes, 16);
+ status = GUID_from_data_blob(&blob1, &server_guid);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ blob1 = data_blob_const(bytes+16, num_bytes-16);
+ blob2 = data_blob_dup_talloc(state, blob1);
+ if (blob1.length > 0 &&
+ tevent_req_nomem(blob2.data, req)) {
+ return;
+ }
+ server_gss_blob = blob2;
+ } else {
+ DATA_BLOB blob1, blob2;
+
+ if (num_bytes < key_len) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (key_len != 0 && key_len != 8) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (key_len == 8) {
+ memcpy(server_challenge, bytes, 8);
+ }
+
+ blob1 = data_blob_const(bytes+key_len, num_bytes-key_len);
+ blob2 = data_blob_const(bytes+key_len, num_bytes-key_len);
+ if (blob1.length > 0) {
+ size_t len;
+
+ len = utf16_null_terminated_len_n(blob1.data,
+ blob1.length);
+ blob1.length = len;
+
+ ok = convert_string_talloc(state,
+ CH_UTF16LE,
+ CH_UNIX,
+ blob1.data,
+ blob1.length,
+ &server_workgroup,
+ &len);
+ if (!ok) {
+ status = map_nt_error_from_unix_common(errno);
+ tevent_req_nterror(req, status);
+ return;
+ }
+ }
+
+ blob2.data += blob1.length;
+ blob2.length -= blob1.length;
+ if (blob2.length > 0) {
+ size_t len;
+
+ ok = convert_string_talloc(state,
+ CH_UTF16LE,
+ CH_UNIX,
+ blob2.data,
+ blob2.length,
+ &server_name,
+ &len);
+ if (!ok) {
+ status = map_nt_error_from_unix_common(errno);
+ tevent_req_nterror(req, status);
+ return;
+ }
+ }
+ }
+
+ client_signing = "disabled";
+ if (conn->allow_signing) {
+ client_signing = "allowed";
+ }
+ if (conn->mandatory_signing) {
+ client_signing = "required";
+ }
+
+ server_signing = "not supported";
+ if (server_security_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
+ server_signing = "supported";
+ server_allowed = true;
+ } else if (conn->mandatory_signing) {
+ /*
+ * We have mandatory signing as client
+ * lets assume the server will look at our
+ * FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED
+ * flag in the session setup
+ */
+ server_signing = "not announced";
+ server_allowed = true;
+ }
+ if (server_security_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) {
+ server_signing = "required";
+ server_mandatory = true;
+ }
+
+ ok = smb1_signing_set_negotiated(conn->smb1.signing,
+ server_allowed,
+ server_mandatory);
+ if (!ok) {
+ DEBUG(1,("cli_negprot: SMB signing is required, "
+ "but client[%s] and server[%s] mismatch\n",
+ client_signing, server_signing));
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+
+ } else if (conn->protocol >= PROTOCOL_LANMAN1) {
+ DATA_BLOB blob1;
+ uint8_t key_len;
+ time_t t;
+
+ if (wct != 0x0D) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ server_security_mode = SVAL(vwv + 1, 0);
+ server_max_xmit = SVAL(vwv + 2, 0);
+ server_max_mux = SVAL(vwv + 3, 0);
+ server_readbraw = ((SVAL(vwv + 5, 0) & 0x1) != 0);
+ server_writebraw = ((SVAL(vwv + 5, 0) & 0x2) != 0);
+ server_session_key = IVAL(vwv + 6, 0);
+ server_time_zone = SVALS(vwv + 10, 0);
+ server_time_zone *= 60;
+ /* this time is converted to GMT by make_unix_date */
+ t = pull_dos_date((const uint8_t *)(vwv + 8), server_time_zone);
+ unix_to_nt_time(&server_system_time, t);
+ key_len = SVAL(vwv + 11, 0);
+
+ if (num_bytes < key_len) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (key_len != 0 && key_len != 8) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (key_len == 8) {
+ memcpy(server_challenge, bytes, 8);
+ }
+
+ blob1 = data_blob_const(bytes+key_len, num_bytes-key_len);
+ if (blob1.length > 0) {
+ size_t len;
+ bool ok;
+
+ len = utf16_null_terminated_len_n(blob1.data,
+ blob1.length);
+ blob1.length = len;
+
+ ok = convert_string_talloc(state,
+ CH_DOS,
+ CH_UNIX,
+ blob1.data,
+ blob1.length,
+ &server_workgroup,
+ &len);
+ if (!ok) {
+ status = map_nt_error_from_unix_common(errno);
+ tevent_req_nterror(req, status);
+ return;
+ }
+ }
+
+ } else {
+ /* the old core protocol */
+ server_time_zone = get_time_zone(time(NULL));
+ server_max_xmit = 1024;
+ server_max_mux = 1;
+ }
+
+ if (server_max_xmit < 1024) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (server_max_mux < 1) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ /*
+ * Now calculate the negotiated capabilities
+ * based on the mask for:
+ * - client only flags
+ * - flags used in both directions
+ * - server only flags
+ */
+ both_capabilities = client_capabilities & server_capabilities;
+ capabilities = client_capabilities & SMB_CAP_CLIENT_MASK;
+ capabilities |= both_capabilities & SMB_CAP_BOTH_MASK;
+ capabilities |= server_capabilities & SMB_CAP_SERVER_MASK;
+
+ max_xmit = MIN(client_max_xmit, server_max_xmit);
+
+ conn->smb1.server.capabilities = server_capabilities;
+ conn->smb1.capabilities = capabilities;
+
+ conn->smb1.server.max_xmit = server_max_xmit;
+ conn->smb1.max_xmit = max_xmit;
+
+ conn->smb1.server.max_mux = server_max_mux;
+
+ conn->smb1.server.security_mode = server_security_mode;
+
+ conn->smb1.server.readbraw = server_readbraw;
+ conn->smb1.server.writebraw = server_writebraw;
+ conn->smb1.server.lockread = server_lockread;
+ conn->smb1.server.writeunlock = server_writeunlock;
+
+ conn->smb1.server.session_key = server_session_key;
+
+ talloc_steal(conn, server_gss_blob.data);
+ conn->smb1.server.gss_blob = server_gss_blob;
+ conn->smb1.server.guid = server_guid;
+ memcpy(conn->smb1.server.challenge, server_challenge, 8);
+ conn->smb1.server.workgroup = talloc_move(conn, &server_workgroup);
+ conn->smb1.server.name = talloc_move(conn, &server_name);
+
+ conn->smb1.server.time_zone = server_time_zone;
+ conn->smb1.server.system_time = server_system_time;
+
+ tevent_req_done(req);
+}
+
+static size_t smbXcli_padding_helper(uint32_t offset, size_t n)
+{
+ if ((offset & (n-1)) == 0) return 0;
+ return n - (offset & (n-1));
+}
+
+static struct tevent_req *smbXcli_negprot_smb2_subreq(struct smbXcli_negprot_state *state)
+{
+ size_t i;
+ uint8_t *buf;
+ uint16_t dialect_count = 0;
+ DATA_BLOB dyn = data_blob_null;
+
+ for (i=0; i < ARRAY_SIZE(smb2cli_prots); i++) {
+ bool ok;
+ uint8_t val[2];
+
+ if (smb2cli_prots[i].proto < state->conn->min_protocol) {
+ continue;
+ }
+
+ if (smb2cli_prots[i].proto > state->conn->max_protocol) {
+ continue;
+ }
+
+ SSVAL(val, 0, smb2cli_prots[i].smb2_dialect);
+
+ ok = data_blob_append(state, &dyn, val, sizeof(val));
+ if (!ok) {
+ return NULL;
+ }
+
+ dialect_count++;
+ }
+
+ buf = state->smb2.fixed;
+ SSVAL(buf, 0, 36);
+ SSVAL(buf, 2, dialect_count);
+ SSVAL(buf, 4, state->conn->smb2.client.security_mode);
+ SSVAL(buf, 6, 0); /* Reserved */
+ if (state->conn->max_protocol >= PROTOCOL_SMB3_00) {
+ SIVAL(buf, 8, state->conn->smb2.client.capabilities);
+ } else {
+ SIVAL(buf, 8, 0); /* Capabilities */
+ }
+ if (state->conn->max_protocol >= PROTOCOL_SMB2_10) {
+ NTSTATUS status;
+ struct GUID_ndr_buf guid_buf = { .buf = {0}, };
+
+ status = GUID_to_ndr_buf(&state->conn->smb2.client.guid,
+ &guid_buf);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ memcpy(buf+12, guid_buf.buf, 16); /* ClientGuid */
+ } else {
+ memset(buf+12, 0, 16); /* ClientGuid */
+ }
+
+ if (state->conn->max_protocol >= PROTOCOL_SMB3_11) {
+ const struct smb3_signing_capabilities *client_sign_algos =
+ &state->conn->smb2.client.smb3_capabilities.signing;
+ const struct smb3_encryption_capabilities *client_ciphers =
+ &state->conn->smb2.client.smb3_capabilities.encryption;
+ NTSTATUS status;
+ struct smb2_negotiate_contexts c = { .num_contexts = 0, };
+ uint8_t *netname_utf16 = NULL;
+ size_t netname_utf16_len = 0;
+ uint32_t offset;
+ DATA_BLOB b;
+ uint8_t p[38];
+ const uint8_t zeros[8] = {0, };
+ size_t pad;
+ bool ok;
+
+ SSVAL(p, 0, 1); /* HashAlgorithmCount */
+ SSVAL(p, 2, 32); /* SaltLength */
+ SSVAL(p, 4, SMB2_PREAUTH_INTEGRITY_SHA512);
+ generate_random_buffer(p + 6, 32);
+
+ status = smb2_negotiate_context_add(
+ state, &c, SMB2_PREAUTH_INTEGRITY_CAPABILITIES, p, 38);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+
+ if (client_ciphers->num_algos > 0) {
+ size_t ofs = 0;
+ SSVAL(p, ofs, client_ciphers->num_algos);
+ ofs += 2;
+
+ for (i = 0; i < client_ciphers->num_algos; i++) {
+ size_t next_ofs = ofs + 2;
+ SMB_ASSERT(next_ofs < ARRAY_SIZE(p));
+ SSVAL(p, ofs, client_ciphers->algos[i]);
+ ofs = next_ofs;
+ }
+
+ status = smb2_negotiate_context_add(
+ state, &c, SMB2_ENCRYPTION_CAPABILITIES, p, ofs);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ }
+
+ if (client_sign_algos->num_algos > 0) {
+ size_t ofs = 0;
+ SSVAL(p, ofs, client_sign_algos->num_algos);
+ ofs += 2;
+
+ for (i = 0; i < client_sign_algos->num_algos; i++) {
+ size_t next_ofs = ofs + 2;
+ SMB_ASSERT(next_ofs < ARRAY_SIZE(p));
+ SSVAL(p, ofs, client_sign_algos->algos[i]);
+ ofs = next_ofs;
+ }
+
+ status = smb2_negotiate_context_add(
+ state, &c, SMB2_SIGNING_CAPABILITIES, p, ofs);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ }
+
+ ok = convert_string_talloc(state, CH_UNIX, CH_UTF16,
+ state->conn->remote_name,
+ strlen(state->conn->remote_name),
+ &netname_utf16, &netname_utf16_len);
+ if (!ok) {
+ return NULL;
+ }
+
+ status = smb2_negotiate_context_add(state, &c,
+ SMB2_NETNAME_NEGOTIATE_CONTEXT_ID,
+ netname_utf16, netname_utf16_len);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+
+ if (state->in_ctx != NULL) {
+ struct smb2_negotiate_contexts *ctxs = state->in_ctx;
+
+ for (i=0; i<ctxs->num_contexts; i++) {
+ struct smb2_negotiate_context *ctx =
+ &ctxs->contexts[i];
+
+ status = smb2_negotiate_context_add(
+ state,
+ &c,
+ ctx->type,
+ ctx->data.data,
+ ctx->data.length);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ }
+ }
+
+ status = smb2_negotiate_context_push(state, &b, c);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+
+ offset = SMB2_HDR_BODY + sizeof(state->smb2.fixed) + dyn.length;
+ pad = smbXcli_padding_helper(offset, 8);
+
+ ok = data_blob_append(state, &dyn, zeros, pad);
+ if (!ok) {
+ return NULL;
+ }
+ offset += pad;
+
+ ok = data_blob_append(state, &dyn, b.data, b.length);
+ if (!ok) {
+ return NULL;
+ }
+
+ SIVAL(buf, 28, offset); /* NegotiateContextOffset */
+ SSVAL(buf, 32, c.num_contexts); /* NegotiateContextCount */
+ SSVAL(buf, 34, 0); /* Reserved */
+ } else {
+ SBVAL(buf, 28, 0); /* Reserved/ClientStartTime */
+ }
+
+ return smb2cli_req_send(state, state->ev,
+ state->conn, SMB2_OP_NEGPROT,
+ 0, 0, /* flags */
+ state->timeout_msec,
+ NULL, NULL, /* tcon, session */
+ state->smb2.fixed, sizeof(state->smb2.fixed),
+ dyn.data, dyn.length,
+ UINT16_MAX); /* max_dyn_len */
+}
+
+static NTSTATUS smbXcli_negprot_smb3_check_capabilities(struct tevent_req *req);
+
+static void smbXcli_negprot_smb2_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smbXcli_negprot_state *state =
+ tevent_req_data(req,
+ struct smbXcli_negprot_state);
+ struct smbXcli_conn *conn = state->conn;
+ size_t security_offset, security_length;
+ DATA_BLOB blob;
+ NTSTATUS status;
+ struct iovec *iov = NULL;
+ uint8_t *body;
+ size_t i;
+ uint16_t dialect_revision;
+ uint32_t negotiate_context_offset = 0;
+ uint16_t negotiate_context_count = 0;
+ DATA_BLOB negotiate_context_blob = data_blob_null;
+ size_t avail;
+ size_t ctx_ofs;
+ size_t needed;
+ struct smb2_negotiate_context *preauth = NULL;
+ uint16_t hash_count;
+ uint16_t salt_length;
+ uint16_t hash_selected;
+ gnutls_hash_hd_t hash_hnd = NULL;
+ struct smb2_negotiate_context *sign_algo = NULL;
+ struct smb2_negotiate_context *cipher = NULL;
+ struct smb2_negotiate_context *posix = NULL;
+ struct iovec sent_iov[3] = {{0}, {0}, {0}};
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x41
+ }
+ };
+ int rc;
+
+ status = smb2cli_req_recv(subreq, state, &iov,
+ expected, ARRAY_SIZE(expected));
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ if (iov == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return;
+ }
+
+ body = (uint8_t *)iov[1].iov_base;
+
+ dialect_revision = SVAL(body, 4);
+
+ for (i=0; i < ARRAY_SIZE(smb2cli_prots); i++) {
+ if (smb2cli_prots[i].proto < state->conn->min_protocol) {
+ continue;
+ }
+
+ if (smb2cli_prots[i].proto > state->conn->max_protocol) {
+ continue;
+ }
+
+ if (smb2cli_prots[i].smb2_dialect != dialect_revision) {
+ continue;
+ }
+
+ conn->protocol = smb2cli_prots[i].proto;
+ break;
+ }
+
+ if (conn->protocol == PROTOCOL_NONE) {
+ TALLOC_FREE(subreq);
+
+ if (state->conn->min_protocol >= PROTOCOL_SMB2_02) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (dialect_revision != SMB2_DIALECT_REVISION_2FF) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ /* make sure we do not loop forever */
+ state->conn->min_protocol = PROTOCOL_SMB2_02;
+
+ /*
+ * send a SMB2 negprot, in order to negotiate
+ * the SMB2 dialect.
+ */
+ subreq = smbXcli_negprot_smb2_subreq(state);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, smbXcli_negprot_smb2_done, req);
+ return;
+ }
+
+ conn->smb2.server.security_mode = SVAL(body, 2);
+ if (conn->protocol >= PROTOCOL_SMB3_11) {
+ negotiate_context_count = SVAL(body, 6);
+ }
+
+ blob = data_blob_const(body + 8, 16);
+ status = GUID_from_data_blob(&blob, &conn->smb2.server.guid);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ conn->smb2.server.capabilities = IVAL(body, 24);
+ conn->smb2.server.max_trans_size= IVAL(body, 28);
+ conn->smb2.server.max_read_size = IVAL(body, 32);
+ conn->smb2.server.max_write_size= IVAL(body, 36);
+ conn->smb2.server.system_time = BVAL(body, 40);
+ conn->smb2.server.start_time = BVAL(body, 48);
+
+ if (conn->smb2.server.max_trans_size == 0 ||
+ conn->smb2.server.max_read_size == 0 ||
+ conn->smb2.server.max_write_size == 0) {
+ /*
+ * We can't connect to servers we can't
+ * do any operations on.
+ */
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ security_offset = SVAL(body, 56);
+ security_length = SVAL(body, 58);
+
+ if (security_offset == 0) {
+ /*
+ * Azure sends security_offset = 0 and security_length = 0
+ *
+ * We just set security_offset to the expected value
+ * in order to allow the further logic to work
+ * as before.
+ */
+ if (security_length != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ security_offset = SMB2_HDR_BODY + iov[1].iov_len;
+ }
+
+ if (security_offset != SMB2_HDR_BODY + iov[1].iov_len) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (security_length > iov[2].iov_len) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ conn->smb2.server.gss_blob = data_blob_talloc(conn,
+ iov[2].iov_base,
+ security_length);
+ if (tevent_req_nomem(conn->smb2.server.gss_blob.data, req)) {
+ return;
+ }
+
+ if (conn->protocol >= PROTOCOL_SMB3_00) {
+ conn->smb2.server.sign_algo = SMB2_SIGNING_AES128_CMAC;
+ } else {
+ conn->smb2.server.sign_algo = SMB2_SIGNING_HMAC_SHA256;
+ }
+
+ if (conn->protocol < PROTOCOL_SMB3_11) {
+ TALLOC_FREE(subreq);
+
+ if (conn->smb2.server.capabilities & SMB2_CAP_ENCRYPTION) {
+ conn->smb2.server.cipher = SMB2_ENCRYPTION_AES128_CCM;
+ }
+
+ status = smbXcli_negprot_smb3_check_capabilities(req);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+ return;
+ }
+
+ /*
+ * Here we are now at SMB3_11, so encryption should be
+ * negotiated via context, not capabilities.
+ */
+
+ if (conn->smb2.server.capabilities & SMB2_CAP_ENCRYPTION) {
+ /*
+ * Server set SMB2_CAP_ENCRYPTION capability,
+ * but *SHOULD* not, not *MUST* not. Just mask it off.
+ * NetApp seems to do this:
+ * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13009
+ */
+ conn->smb2.server.capabilities &= ~SMB2_CAP_ENCRYPTION;
+ }
+
+ negotiate_context_offset = IVAL(body, 60);
+ if (negotiate_context_offset < security_offset) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ ctx_ofs = negotiate_context_offset - security_offset;
+ if (ctx_ofs > iov[2].iov_len) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ avail = iov[2].iov_len - security_length;
+ needed = iov[2].iov_len - ctx_ofs;
+ if (needed > avail) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ negotiate_context_blob.data = (uint8_t *)iov[2].iov_base;
+ negotiate_context_blob.length = iov[2].iov_len;
+
+ negotiate_context_blob.data += ctx_ofs;
+ negotiate_context_blob.length -= ctx_ofs;
+
+ state->out_ctx = talloc_zero(state, struct smb2_negotiate_contexts);
+ if (tevent_req_nomem(state->out_ctx, req)) {
+ return;
+ }
+
+ status = smb2_negotiate_context_parse(state->out_ctx,
+ negotiate_context_blob,
+ negotiate_context_count,
+ state->out_ctx);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ preauth = smb2_negotiate_context_find(
+ state->out_ctx, SMB2_PREAUTH_INTEGRITY_CAPABILITIES);
+ if (preauth == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (preauth->data.length < 6) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ hash_count = SVAL(preauth->data.data, 0);
+ salt_length = SVAL(preauth->data.data, 2);
+ hash_selected = SVAL(preauth->data.data, 4);
+
+ if (hash_count != 1) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (preauth->data.length != (6 + salt_length)) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (hash_selected != SMB2_PREAUTH_INTEGRITY_SHA512) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ sign_algo = smb2_negotiate_context_find(
+ state->out_ctx, SMB2_SIGNING_CAPABILITIES);
+ if (sign_algo != NULL) {
+ const struct smb3_signing_capabilities *client_sign_algos =
+ &state->conn->smb2.client.smb3_capabilities.signing;
+ bool found_selected = false;
+ uint16_t sign_algo_count;
+ uint16_t sign_algo_selected;
+
+ if (client_sign_algos->num_algos == 0) {
+ /*
+ * We didn't ask for SMB2_ENCRYPTION_CAPABILITIES
+ */
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (sign_algo->data.length < 2) {
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ sign_algo_count = SVAL(sign_algo->data.data, 0);
+ if (sign_algo_count != 1) {
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (sign_algo->data.length < (2 + 2 * sign_algo_count)) {
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ sign_algo_selected = SVAL(sign_algo->data.data, 2);
+
+ for (i = 0; i < client_sign_algos->num_algos; i++) {
+ if (client_sign_algos->algos[i] == sign_algo_selected) {
+ /*
+ * We found a match
+ */
+ found_selected = true;
+ break;
+ }
+ }
+
+ if (!found_selected) {
+ /*
+ * The server send a sign_algo we didn't offer.
+ */
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ conn->smb2.server.sign_algo = sign_algo_selected;
+ }
+
+ cipher = smb2_negotiate_context_find(
+ state->out_ctx, SMB2_ENCRYPTION_CAPABILITIES);
+ if (cipher != NULL) {
+ const struct smb3_encryption_capabilities *client_ciphers =
+ &state->conn->smb2.client.smb3_capabilities.encryption;
+ bool found_selected = false;
+ uint16_t cipher_count;
+ uint16_t cipher_selected;
+
+ if (client_ciphers->num_algos == 0) {
+ /*
+ * We didn't ask for SMB2_ENCRYPTION_CAPABILITIES
+ */
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (cipher->data.length < 2) {
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ cipher_count = SVAL(cipher->data.data, 0);
+ if (cipher_count != 1) {
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (cipher->data.length < (2 + 2 * cipher_count)) {
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ cipher_selected = SVAL(cipher->data.data, 2);
+
+ for (i = 0; i < client_ciphers->num_algos; i++) {
+ if (cipher_selected == SMB2_ENCRYPTION_NONE) {
+ /*
+ * encryption not supported
+ */
+ found_selected = true;
+ break;
+ }
+ if (client_ciphers->algos[i] == cipher_selected) {
+ /*
+ * We found a match
+ */
+ found_selected = true;
+ break;
+ }
+ }
+
+ if (!found_selected) {
+ /*
+ * The server send a cipher we didn't offer.
+ */
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ conn->smb2.server.cipher = cipher_selected;
+ }
+
+ posix = smb2_negotiate_context_find(
+ state->out_ctx, SMB2_POSIX_EXTENSIONS_AVAILABLE);
+ if (posix != NULL) {
+ DATA_BLOB posix_blob = data_blob_const(
+ SMB2_CREATE_TAG_POSIX, strlen(SMB2_CREATE_TAG_POSIX));
+ int cmp = data_blob_cmp(&posix->data, &posix_blob);
+
+ conn->smb2.server.smb311_posix = (cmp == 0);
+ }
+
+
+ /* First we hash the request */
+ smb2cli_req_get_sent_iov(subreq, sent_iov);
+
+ rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_SHA512);
+ if (rc < 0) {
+ tevent_req_nterror(req,
+ gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED));
+ return;
+ }
+
+ rc = gnutls_hash(hash_hnd,
+ conn->smb2.preauth_sha512,
+ sizeof(conn->smb2.preauth_sha512));
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ tevent_req_nterror(req,
+ gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED));
+ return;
+ }
+ for (i = 0; i < 3; i++) {
+ rc = gnutls_hash(hash_hnd,
+ sent_iov[i].iov_base,
+ sent_iov[i].iov_len);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ tevent_req_nterror(req,
+ gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED));
+ return;
+ }
+ }
+
+ /* This resets the hash state */
+ gnutls_hash_output(hash_hnd, conn->smb2.preauth_sha512);
+ TALLOC_FREE(subreq);
+
+ /* And now we hash the response */
+ rc = gnutls_hash(hash_hnd,
+ conn->smb2.preauth_sha512,
+ sizeof(conn->smb2.preauth_sha512));
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ tevent_req_nterror(req,
+ gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED));
+ return;
+ }
+ for (i = 0; i < 3; i++) {
+ rc = gnutls_hash(hash_hnd,
+ iov[i].iov_base,
+ iov[i].iov_len);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ tevent_req_nterror(req,
+ gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED));
+ return;
+ }
+ }
+ gnutls_hash_deinit(hash_hnd, conn->smb2.preauth_sha512);
+ if (rc < 0) {
+ tevent_req_nterror(req,
+ NT_STATUS_UNSUCCESSFUL);
+ return;
+ }
+
+ status = smbXcli_negprot_smb3_check_capabilities(req);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static NTSTATUS smbXcli_negprot_smb3_check_capabilities(struct tevent_req *req)
+{
+ struct smbXcli_negprot_state *state =
+ tevent_req_data(req,
+ struct smbXcli_negprot_state);
+ struct smbXcli_conn *conn = state->conn;
+
+ return smb311_capabilities_check(&conn->smb2.client.smb3_capabilities,
+ "smbXcli_negprot",
+ DBGLVL_ERR,
+ NT_STATUS_ACCESS_DENIED,
+ "client",
+ conn->protocol,
+ conn->smb2.server.sign_algo,
+ conn->smb2.server.cipher);
+}
+
+static NTSTATUS smbXcli_negprot_dispatch_incoming(struct smbXcli_conn *conn,
+ TALLOC_CTX *tmp_mem,
+ uint8_t *inbuf)
+{
+ size_t num_pending = talloc_array_length(conn->pending);
+ struct tevent_req *subreq;
+ struct smbXcli_req_state *substate;
+ struct tevent_req *req;
+ uint32_t protocol_magic;
+ size_t inbuf_len = smb_len_nbt(inbuf);
+
+ if (num_pending != 1) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (inbuf_len < 4) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ subreq = conn->pending[0];
+ substate = tevent_req_data(subreq, struct smbXcli_req_state);
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+
+ protocol_magic = IVAL(inbuf, 4);
+
+ switch (protocol_magic) {
+ case SMB_MAGIC:
+ tevent_req_set_callback(subreq, smbXcli_negprot_smb1_done, req);
+ conn->dispatch_incoming = smb1cli_conn_dispatch_incoming;
+ return smb1cli_conn_dispatch_incoming(conn, tmp_mem, inbuf);
+
+ case SMB2_MAGIC:
+ if (substate->smb2.recv_iov == NULL) {
+ /*
+ * For the SMB1 negprot we have move it.
+ */
+ substate->smb2.recv_iov = substate->smb1.recv_iov;
+ substate->smb1.recv_iov = NULL;
+ }
+
+ /*
+ * we got an SMB2 answer, which consumed sequence number 0
+ * so we need to use 1 as the next one.
+ *
+ * we also need to set the current credits to 0
+ * as we consumed the initial one. The SMB2 answer
+ * hopefully grant us a new credit.
+ */
+ conn->smb2.mid = 1;
+ conn->smb2.cur_credits = 0;
+ tevent_req_set_callback(subreq, smbXcli_negprot_smb2_done, req);
+ conn->dispatch_incoming = smb2cli_conn_dispatch_incoming;
+ return smb2cli_conn_dispatch_incoming(conn, tmp_mem, inbuf);
+ }
+
+ DEBUG(10, ("Got non-SMB PDU\n"));
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+}
+
+NTSTATUS smbXcli_negprot_recv(
+ struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_negotiate_contexts **out_ctx)
+{
+ struct smbXcli_negprot_state *state = tevent_req_data(
+ req, struct smbXcli_negprot_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ if (out_ctx != NULL) {
+ *out_ctx = talloc_move(mem_ctx, &state->out_ctx);
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smbXcli_negprot(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ enum protocol_types min_protocol,
+ enum protocol_types max_protocol,
+ struct smb2_negotiate_contexts *in_ctx,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_negotiate_contexts **out_ctx)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+ bool ok;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER_MIX;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smbXcli_negprot_send(
+ frame,
+ ev,
+ conn,
+ timeout_msec,
+ min_protocol,
+ max_protocol,
+ WINDOWS_CLIENT_PURE_SMB2_NEGPROT_INITIAL_CREDIT_ASK,
+ in_ctx);
+ if (req == NULL) {
+ goto fail;
+ }
+ ok = tevent_req_poll_ntstatus(req, ev, &status);
+ if (!ok) {
+ goto fail;
+ }
+ status = smbXcli_negprot_recv(req, mem_ctx, out_ctx);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct smb2cli_validate_negotiate_info_state {
+ struct smbXcli_conn *conn;
+ DATA_BLOB in_input_buffer;
+ DATA_BLOB in_output_buffer;
+ DATA_BLOB out_input_buffer;
+ DATA_BLOB out_output_buffer;
+ uint16_t dialect;
+};
+
+static void smb2cli_validate_negotiate_info_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_validate_negotiate_info_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon)
+{
+ struct tevent_req *req;
+ struct smb2cli_validate_negotiate_info_state *state;
+ uint8_t *buf;
+ uint16_t dialect_count = 0;
+ struct tevent_req *subreq;
+ bool _save_should_sign;
+ size_t i;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_validate_negotiate_info_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->conn = conn;
+
+ state->in_input_buffer = data_blob_talloc_zero(state,
+ 4 + 16 + 1 + 1 + 2);
+ if (tevent_req_nomem(state->in_input_buffer.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+ buf = state->in_input_buffer.data;
+
+ if (state->conn->max_protocol >= PROTOCOL_SMB3_00) {
+ SIVAL(buf, 0, conn->smb2.client.capabilities);
+ } else {
+ SIVAL(buf, 0, 0); /* Capabilities */
+ }
+ if (state->conn->max_protocol >= PROTOCOL_SMB2_10) {
+ NTSTATUS status;
+ struct GUID_ndr_buf guid_buf = { .buf = {0}, };
+
+ status = GUID_to_ndr_buf(&conn->smb2.client.guid,
+ &guid_buf);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ memcpy(buf+4, guid_buf.buf, 16); /* ClientGuid */
+ } else {
+ memset(buf+4, 0, 16); /* ClientGuid */
+ }
+ if (state->conn->min_protocol >= PROTOCOL_SMB2_02) {
+ SCVAL(buf, 20, conn->smb2.client.security_mode);
+ } else {
+ SCVAL(buf, 20, 0);
+ }
+ SCVAL(buf, 21, 0); /* reserved */
+
+ for (i=0; i < ARRAY_SIZE(smb2cli_prots); i++) {
+ bool ok;
+ size_t ofs;
+
+ if (smb2cli_prots[i].proto < state->conn->min_protocol) {
+ continue;
+ }
+
+ if (smb2cli_prots[i].proto > state->conn->max_protocol) {
+ continue;
+ }
+
+ if (smb2cli_prots[i].proto == state->conn->protocol) {
+ state->dialect = smb2cli_prots[i].smb2_dialect;
+ }
+
+ ofs = state->in_input_buffer.length;
+ ok = data_blob_realloc(state, &state->in_input_buffer,
+ ofs + 2);
+ if (!ok) {
+ tevent_req_oom(req);
+ return tevent_req_post(req, ev);
+ }
+
+ buf = state->in_input_buffer.data;
+ SSVAL(buf, ofs, smb2cli_prots[i].smb2_dialect);
+
+ dialect_count++;
+ }
+ buf = state->in_input_buffer.data;
+ SSVAL(buf, 22, dialect_count);
+
+ _save_should_sign = smb2cli_tcon_is_signing_on(tcon);
+ smb2cli_tcon_should_sign(tcon, true);
+ subreq = smb2cli_ioctl_send(state, ev, conn,
+ timeout_msec, session, tcon,
+ UINT64_MAX, /* in_fid_persistent */
+ UINT64_MAX, /* in_fid_volatile */
+ FSCTL_VALIDATE_NEGOTIATE_INFO,
+ 0, /* in_max_input_length */
+ &state->in_input_buffer,
+ 24, /* in_max_output_length */
+ &state->in_output_buffer,
+ SMB2_IOCTL_FLAG_IS_FSCTL);
+ smb2cli_tcon_should_sign(tcon, _save_should_sign);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq,
+ smb2cli_validate_negotiate_info_done,
+ req);
+
+ return req;
+}
+
+static void smb2cli_validate_negotiate_info_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb2cli_validate_negotiate_info_state *state =
+ tevent_req_data(req,
+ struct smb2cli_validate_negotiate_info_state);
+ NTSTATUS status;
+ const uint8_t *buf;
+ uint32_t capabilities;
+ DATA_BLOB guid_blob;
+ struct GUID server_guid;
+ uint16_t security_mode;
+ uint16_t dialect;
+
+ status = smb2cli_ioctl_recv(subreq, state,
+ &state->out_input_buffer,
+ &state->out_output_buffer);
+ TALLOC_FREE(subreq);
+
+ /*
+ * This response must be signed correctly for
+ * these "normal" error codes to be processed.
+ * If the packet wasn't signed correctly we will get
+ * NT_STATUS_ACCESS_DENIED or NT_STATUS_HMAC_NOT_SUPPORTED,
+ * or NT_STATUS_INVALID_NETWORK_RESPONSE
+ * from smb2_signing_check_pdu().
+ *
+ * We must never ignore the above errors here.
+ */
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED)) {
+ /*
+ * The response was signed, but not supported
+ *
+ * Older Windows and Samba releases return
+ * NT_STATUS_FILE_CLOSED.
+ */
+ tevent_req_done(req);
+ return;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_DEVICE_REQUEST)) {
+ /*
+ * The response was signed, but not supported
+ *
+ * This is returned by the NTVFS based Samba 4.x file server
+ * for file shares.
+ */
+ tevent_req_done(req);
+ return;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_FS_DRIVER_REQUIRED)) {
+ /*
+ * The response was signed, but not supported
+ *
+ * This is returned by the NTVFS based Samba 4.x file server
+ * for ipc shares.
+ */
+ tevent_req_done(req);
+ return;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
+ /*
+ * The response was signed, but not supported
+ *
+ * This might be returned by older Windows versions or by
+ * NetApp SMB server implementations.
+ *
+ * See
+ *
+ * https://blogs.msdn.microsoft.com/openspecification/2012/06/28/smb3-secure-dialect-negotiation/
+ *
+ */
+ tevent_req_done(req);
+ return;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ /*
+ * The response was signed, but not supported
+ *
+ * This might be returned by NetApp Ontap 7.3.7 SMB server
+ * implementations.
+ *
+ * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14607
+ *
+ */
+ tevent_req_done(req);
+ return;
+ }
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (state->out_output_buffer.length != 24) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ buf = state->out_output_buffer.data;
+
+ capabilities = IVAL(buf, 0);
+ guid_blob = data_blob_const(buf + 4, 16);
+ status = GUID_from_data_blob(&guid_blob, &server_guid);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ security_mode = CVAL(buf, 20);
+ dialect = SVAL(buf, 22);
+
+ if (capabilities != state->conn->smb2.server.capabilities) {
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+
+ if (!GUID_equal(&server_guid, &state->conn->smb2.server.guid)) {
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+
+ if (security_mode != state->conn->smb2.server.security_mode) {
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+
+ if (dialect != state->dialect) {
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_validate_negotiate_info_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+static int smbXcli_session_destructor(struct smbXcli_session *session)
+{
+ if (session->conn == NULL) {
+ return 0;
+ }
+
+ DLIST_REMOVE(session->conn->sessions, session);
+ return 0;
+}
+
+struct smbXcli_session *smbXcli_session_create(TALLOC_CTX *mem_ctx,
+ struct smbXcli_conn *conn)
+{
+ struct smbXcli_session *session;
+ NTSTATUS status;
+
+ session = talloc_zero(mem_ctx, struct smbXcli_session);
+ if (session == NULL) {
+ return NULL;
+ }
+ session->smb2 = talloc_zero(session, struct smb2cli_session);
+ if (session->smb2 == NULL) {
+ talloc_free(session);
+ return NULL;
+ }
+ talloc_set_destructor(session, smbXcli_session_destructor);
+
+ status = smb2_signing_key_sign_create(session->smb2,
+ conn->smb2.server.sign_algo,
+ NULL, /* no master key */
+ NULL, /* derivations */
+ &session->smb2->signing_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(session);
+ return NULL;
+ }
+
+ DLIST_ADD_END(conn->sessions, session);
+ session->conn = conn;
+
+ status = smb2_signing_key_sign_create(session,
+ conn->smb2.server.sign_algo,
+ NULL, /* no master key */
+ NULL, /* derivations */
+ &session->smb2_channel.signing_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(session);
+ return NULL;
+ }
+
+ memcpy(session->smb2_channel.preauth_sha512,
+ conn->smb2.preauth_sha512,
+ sizeof(session->smb2_channel.preauth_sha512));
+
+ return session;
+}
+
+struct smbXcli_session *smbXcli_session_shallow_copy(TALLOC_CTX *mem_ctx,
+ struct smbXcli_session *src)
+{
+ struct smbXcli_session *session;
+ struct timespec ts;
+ NTTIME nt;
+
+ session = talloc_zero(mem_ctx, struct smbXcli_session);
+ if (session == NULL) {
+ return NULL;
+ }
+ session->smb2 = talloc_zero(session, struct smb2cli_session);
+ if (session->smb2 == NULL) {
+ talloc_free(session);
+ return NULL;
+ }
+
+ /*
+ * Note we keep a pointer to the session keys of the
+ * main session and rely on the caller to free the
+ * shallow copy first!
+ */
+ session->conn = src->conn;
+ *session->smb2 = *src->smb2;
+ session->smb2_channel = src->smb2_channel;
+ session->disconnect_expired = src->disconnect_expired;
+
+ /*
+ * This is only supposed to be called in test code
+ * but we should not reuse nonces!
+ *
+ * Add the current timestamp as NTTIME to nonce_high
+ * and set nonce_low to a value we can recognize in captures.
+ */
+ clock_gettime_mono(&ts);
+ nt = unix_timespec_to_nt_time(ts);
+ nt &= session->smb2->nonce_high_max;
+ if (nt == session->smb2->nonce_high_max || nt < UINT8_MAX) {
+ talloc_free(session);
+ return NULL;
+ }
+ session->smb2->nonce_high += nt;
+ session->smb2->nonce_low = UINT32_MAX;
+
+ DLIST_ADD_END(src->conn->sessions, session);
+ talloc_set_destructor(session, smbXcli_session_destructor);
+
+ return session;
+}
+
+bool smbXcli_session_is_guest(struct smbXcli_session *session)
+{
+ if (session == NULL) {
+ return false;
+ }
+
+ if (session->conn == NULL) {
+ return false;
+ }
+
+ if (session->conn->mandatory_signing) {
+ return false;
+ }
+
+ if (session->conn->protocol >= PROTOCOL_SMB2_02) {
+ if (session->smb2->session_flags & SMB2_SESSION_FLAG_IS_GUEST) {
+ return true;
+ }
+ return false;
+ }
+
+ if (session->smb1.action & SMB_SETUP_GUEST) {
+ return true;
+ }
+
+ return false;
+}
+
+bool smbXcli_session_is_authenticated(struct smbXcli_session *session)
+{
+ const DATA_BLOB *application_key;
+
+ if (session == NULL) {
+ return false;
+ }
+
+ if (session->conn == NULL) {
+ return false;
+ }
+
+ /*
+ * If we have an application key we had a session key negotiated
+ * at auth time.
+ */
+ if (session->conn->protocol >= PROTOCOL_SMB2_02) {
+ if (!smb2_signing_key_valid(session->smb2->application_key)) {
+ return false;
+ }
+ application_key = &session->smb2->application_key->blob;
+ } else {
+ application_key = &session->smb1.application_key;
+ }
+
+ if (application_key->length == 0) {
+ return false;
+ }
+
+ return true;
+}
+
+NTSTATUS smb2cli_session_signing_key(struct smbXcli_session *session,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *key)
+{
+ const struct smb2_signing_key *sig = NULL;
+
+ if (session->conn == NULL) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ /*
+ * Use channel signing key if there is one, otherwise fallback
+ * to session.
+ */
+
+ if (smb2_signing_key_valid(session->smb2_channel.signing_key)) {
+ sig = session->smb2_channel.signing_key;
+ } else if (smb2_signing_key_valid(session->smb2->signing_key)) {
+ sig = session->smb2->signing_key;
+ } else {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ *key = data_blob_dup_talloc(mem_ctx, sig->blob);
+ if (key->data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_session_encryption_key(struct smbXcli_session *session,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *key)
+{
+ if (session->conn == NULL) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ if (session->conn->protocol < PROTOCOL_SMB3_00) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ if (!smb2_signing_key_valid(session->smb2->encryption_key)) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ *key = data_blob_dup_talloc(mem_ctx, session->smb2->encryption_key->blob);
+ if (key->data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_session_decryption_key(struct smbXcli_session *session,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *key)
+{
+ if (session->conn == NULL) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ if (session->conn->protocol < PROTOCOL_SMB3_00) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ if (!smb2_signing_key_valid(session->smb2->decryption_key)) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ *key = data_blob_dup_talloc(mem_ctx, session->smb2->decryption_key->blob);
+ if (key->data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smbXcli_session_application_key(struct smbXcli_session *session,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *key)
+{
+ const DATA_BLOB *application_key;
+
+ *key = data_blob_null;
+
+ if (session->conn == NULL) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ if (session->conn->protocol >= PROTOCOL_SMB2_02) {
+ if (!smb2_signing_key_valid(session->smb2->application_key)) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+ application_key = &session->smb2->application_key->blob;
+ } else {
+ application_key = &session->smb1.application_key;
+ }
+
+ if (application_key->length == 0) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ *key = data_blob_dup_talloc(mem_ctx, *application_key);
+ if (key->data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+void smbXcli_session_set_disconnect_expired(struct smbXcli_session *session)
+{
+ session->disconnect_expired = true;
+}
+
+uint16_t smb1cli_session_current_id(struct smbXcli_session *session)
+{
+ return session->smb1.session_id;
+}
+
+void smb1cli_session_set_id(struct smbXcli_session *session,
+ uint16_t session_id)
+{
+ session->smb1.session_id = session_id;
+}
+
+void smb1cli_session_set_action(struct smbXcli_session *session,
+ uint16_t action)
+{
+ session->smb1.action = action;
+}
+
+NTSTATUS smb1cli_session_set_session_key(struct smbXcli_session *session,
+ const DATA_BLOB _session_key)
+{
+ struct smbXcli_conn *conn = session->conn;
+ uint8_t session_key[16];
+
+ if (conn == NULL) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (session->smb1.application_key.length != 0) {
+ /*
+ * TODO: do not allow this...
+ *
+ * return NT_STATUS_INVALID_PARAMETER_MIX;
+ */
+ data_blob_clear_free(&session->smb1.application_key);
+ session->smb1.protected_key = false;
+ }
+
+ if (_session_key.length == 0) {
+ return NT_STATUS_OK;
+ }
+
+ ZERO_STRUCT(session_key);
+ memcpy(session_key, _session_key.data,
+ MIN(_session_key.length, sizeof(session_key)));
+
+ session->smb1.application_key = data_blob_talloc(session,
+ session_key,
+ sizeof(session_key));
+ ZERO_STRUCT(session_key);
+ if (session->smb1.application_key.data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ session->smb1.protected_key = false;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb1cli_session_protect_session_key(struct smbXcli_session *session)
+{
+ NTSTATUS status;
+
+ if (session->smb1.protected_key) {
+ /* already protected */
+ return NT_STATUS_OK;
+ }
+
+ if (session->smb1.application_key.length != 16) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ status = smb1_key_derivation(session->smb1.application_key.data,
+ session->smb1.application_key.length,
+ session->smb1.application_key.data);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ session->smb1.protected_key = true;
+
+ return NT_STATUS_OK;
+}
+
+uint8_t smb2cli_session_security_mode(struct smbXcli_session *session)
+{
+ struct smbXcli_conn *conn = session->conn;
+ uint8_t security_mode = 0;
+
+ if (conn == NULL) {
+ return security_mode;
+ }
+
+ security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
+ if (conn->mandatory_signing) {
+ security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
+ }
+ if (session->smb2->should_sign) {
+ security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
+ }
+
+ return security_mode;
+}
+
+uint64_t smb2cli_session_current_id(struct smbXcli_session *session)
+{
+ return session->smb2->session_id;
+}
+
+uint16_t smb2cli_session_get_flags(struct smbXcli_session *session)
+{
+ return session->smb2->session_flags;
+}
+
+void smb2cli_session_set_id_and_flags(struct smbXcli_session *session,
+ uint64_t session_id,
+ uint16_t session_flags)
+{
+ session->smb2->session_id = session_id;
+ session->smb2->session_flags = session_flags;
+}
+
+void smb2cli_session_increment_channel_sequence(struct smbXcli_session *session)
+{
+ session->smb2->channel_sequence += 1;
+}
+
+uint16_t smb2cli_session_reset_channel_sequence(struct smbXcli_session *session,
+ uint16_t channel_sequence)
+{
+ uint16_t prev_cs;
+
+ prev_cs = session->smb2->channel_sequence;
+ session->smb2->channel_sequence = channel_sequence;
+
+ return prev_cs;
+}
+
+uint16_t smb2cli_session_current_channel_sequence(struct smbXcli_session *session)
+{
+ return session->smb2->channel_sequence;
+}
+
+void smb2cli_session_start_replay(struct smbXcli_session *session)
+{
+ session->smb2->replay_active = true;
+}
+
+void smb2cli_session_stop_replay(struct smbXcli_session *session)
+{
+ session->smb2->replay_active = false;
+}
+
+void smb2cli_session_require_signed_response(struct smbXcli_session *session,
+ bool require_signed_response)
+{
+ session->smb2->require_signed_response = require_signed_response;
+}
+
+NTSTATUS smb2cli_session_update_preauth(struct smbXcli_session *session,
+ const struct iovec *iov)
+{
+ gnutls_hash_hd_t hash_hnd = NULL;
+ size_t i;
+ int rc;
+
+ if (session->conn == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (session->conn->protocol < PROTOCOL_SMB3_11) {
+ return NT_STATUS_OK;
+ }
+
+ if (smb2_signing_key_valid(session->smb2_channel.signing_key)) {
+ return NT_STATUS_OK;
+ }
+
+ rc = gnutls_hash_init(&hash_hnd,
+ GNUTLS_DIG_SHA512);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+
+ rc = gnutls_hash(hash_hnd,
+ session->smb2_channel.preauth_sha512,
+ sizeof(session->smb2_channel.preauth_sha512));
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+ for (i = 0; i < 3; i++) {
+ rc = gnutls_hash(hash_hnd,
+ iov[i].iov_base,
+ iov[i].iov_len);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+ }
+ gnutls_hash_deinit(hash_hnd, session->smb2_channel.preauth_sha512);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
+ const DATA_BLOB _session_key,
+ const struct iovec *recv_iov)
+{
+ struct smbXcli_conn *conn = session->conn;
+ uint16_t no_sign_flags = 0;
+ bool check_signature = true;
+ uint32_t hdr_flags;
+ NTSTATUS status;
+ struct smb2_signing_derivations derivations = {
+ .signing = NULL,
+ };
+ DATA_BLOB preauth_hash = data_blob_null;
+ size_t nonce_size = 0;
+
+ if (conn == NULL) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (recv_iov[0].iov_len != SMB2_HDR_BODY) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (!conn->mandatory_signing) {
+ /*
+ * only allow guest sessions without
+ * mandatory signing.
+ *
+ * If we try an authentication with username != ""
+ * and the server let us in without verifying the
+ * password we don't have a negotiated session key
+ * for signing.
+ */
+ no_sign_flags = SMB2_SESSION_FLAG_IS_GUEST;
+ }
+
+ if (session->smb2->session_flags & no_sign_flags) {
+ session->smb2->should_sign = false;
+ return NT_STATUS_OK;
+ }
+
+ if (smb2_signing_key_valid(session->smb2->signing_key)) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (conn->protocol >= PROTOCOL_SMB3_11) {
+ preauth_hash = data_blob_const(session->smb2_channel.preauth_sha512,
+ sizeof(session->smb2_channel.preauth_sha512));
+ }
+
+ smb2_signing_derivations_fill_const_stack(&derivations,
+ conn->protocol,
+ preauth_hash);
+
+ status = smb2_signing_key_sign_create(session->smb2,
+ conn->smb2.server.sign_algo,
+ &_session_key,
+ derivations.signing,
+ &session->smb2->signing_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = smb2_signing_key_cipher_create(session->smb2,
+ conn->smb2.server.cipher,
+ &_session_key,
+ derivations.cipher_c2s,
+ &session->smb2->encryption_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = smb2_signing_key_cipher_create(session->smb2,
+ conn->smb2.server.cipher,
+ &_session_key,
+ derivations.cipher_s2c,
+ &session->smb2->decryption_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = smb2_signing_key_sign_create(session->smb2,
+ conn->smb2.server.sign_algo,
+ &_session_key,
+ derivations.application,
+ &session->smb2->application_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = smb2_signing_key_copy(session,
+ session->smb2->signing_key,
+ &session->smb2_channel.signing_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ check_signature = conn->mandatory_signing;
+
+ hdr_flags = IVAL(recv_iov[0].iov_base, SMB2_HDR_FLAGS);
+ if (hdr_flags & SMB2_HDR_FLAG_SIGNED) {
+ /*
+ * Sadly some vendors don't sign the
+ * final SMB2 session setup response
+ *
+ * At least Windows and Samba are always doing this
+ * if there's a session key available.
+ *
+ * We only check the signature if it's mandatory
+ * or SMB2_HDR_FLAG_SIGNED is provided.
+ */
+ check_signature = true;
+ }
+
+ if (conn->protocol >= PROTOCOL_SMB3_11) {
+ check_signature = true;
+ }
+
+ if (check_signature) {
+ status = smb2_signing_check_pdu(session->smb2_channel.signing_key,
+ recv_iov, 3);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ session->smb2->should_sign = false;
+ session->smb2->should_encrypt = false;
+
+ if (conn->desire_signing) {
+ session->smb2->should_sign = true;
+ }
+
+ if (conn->smb2.server.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
+ session->smb2->should_sign = true;
+ }
+
+ if (session->smb2->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA) {
+ session->smb2->should_encrypt = true;
+ }
+
+ if (conn->protocol < PROTOCOL_SMB3_00) {
+ session->smb2->should_encrypt = false;
+ }
+
+ if (conn->smb2.server.cipher == 0) {
+ session->smb2->should_encrypt = false;
+ }
+
+ /*
+ * CCM and GCM algorithms must never have their
+ * nonce wrap, or the security of the whole
+ * communication and the keys is destroyed.
+ * We must drop the connection once we have
+ * transferred too much data.
+ *
+ * NOTE: We assume nonces greater than 8 bytes.
+ */
+ generate_nonce_buffer((uint8_t *)&session->smb2->nonce_high_random,
+ sizeof(session->smb2->nonce_high_random));
+ switch (conn->smb2.server.cipher) {
+ case SMB2_ENCRYPTION_AES128_CCM:
+ nonce_size = SMB2_AES_128_CCM_NONCE_SIZE;
+ break;
+ case SMB2_ENCRYPTION_AES128_GCM:
+ nonce_size = gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_GCM);
+ break;
+ case SMB2_ENCRYPTION_AES256_CCM:
+ nonce_size = SMB2_AES_128_CCM_NONCE_SIZE;
+ break;
+ case SMB2_ENCRYPTION_AES256_GCM:
+ nonce_size = gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_256_GCM);
+ break;
+ default:
+ nonce_size = 0;
+ break;
+ }
+ session->smb2->nonce_high_max = SMB2_NONCE_HIGH_MAX(nonce_size);
+ session->smb2->nonce_high = 0;
+ session->smb2->nonce_low = 0;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_session_create_channel(TALLOC_CTX *mem_ctx,
+ struct smbXcli_session *session1,
+ struct smbXcli_conn *conn,
+ struct smbXcli_session **_session2)
+{
+ struct smbXcli_session *session2;
+ NTSTATUS status;
+
+ if (!smb2_signing_key_valid(session1->smb2->signing_key)) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (conn == NULL) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ session2 = talloc_zero(mem_ctx, struct smbXcli_session);
+ if (session2 == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ session2->smb2 = talloc_reference(session2, session1->smb2);
+ if (session2->smb2 == NULL) {
+ talloc_free(session2);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ talloc_set_destructor(session2, smbXcli_session_destructor);
+ DLIST_ADD_END(conn->sessions, session2);
+ session2->conn = conn;
+
+ status = smb2_signing_key_sign_create(session2,
+ conn->smb2.server.sign_algo,
+ NULL, /* no master key */
+ NULL, /* derivations */
+ &session2->smb2_channel.signing_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(session2);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ memcpy(session2->smb2_channel.preauth_sha512,
+ conn->smb2.preauth_sha512,
+ sizeof(session2->smb2_channel.preauth_sha512));
+
+ *_session2 = session2;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_session_set_channel_key(struct smbXcli_session *session,
+ const DATA_BLOB _channel_key,
+ const struct iovec *recv_iov)
+{
+ struct smbXcli_conn *conn = session->conn;
+ uint8_t channel_key[16];
+ NTSTATUS status;
+ struct _derivation {
+ DATA_BLOB label;
+ DATA_BLOB context;
+ };
+ struct {
+ struct _derivation signing;
+ } derivation = {
+ .signing.label.length = 0,
+ };
+
+ if (conn == NULL) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (smb2_signing_key_valid(session->smb2_channel.signing_key)) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (conn->protocol >= PROTOCOL_SMB3_11) {
+ struct _derivation *d;
+ DATA_BLOB p;
+
+ p = data_blob_const(session->smb2_channel.preauth_sha512,
+ sizeof(session->smb2_channel.preauth_sha512));
+
+ d = &derivation.signing;
+ d->label = data_blob_string_const_null("SMBSigningKey");
+ d->context = p;
+ } else if (conn->protocol >= PROTOCOL_SMB3_00) {
+ struct _derivation *d;
+
+ d = &derivation.signing;
+ d->label = data_blob_string_const_null("SMB2AESCMAC");
+ d->context = data_blob_string_const_null("SmbSign");
+ }
+
+ ZERO_STRUCT(channel_key);
+ memcpy(channel_key, _channel_key.data,
+ MIN(_channel_key.length, sizeof(channel_key)));
+
+ session->smb2_channel.signing_key->blob =
+ data_blob_talloc(session->smb2_channel.signing_key,
+ channel_key,
+ sizeof(channel_key));
+ if (!smb2_signing_key_valid(session->smb2_channel.signing_key)) {
+ ZERO_STRUCT(channel_key);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (conn->protocol >= PROTOCOL_SMB3_00) {
+ struct _derivation *d = &derivation.signing;
+
+ status = samba_gnutls_sp800_108_derive_key(
+ channel_key,
+ sizeof(channel_key),
+ NULL,
+ 0,
+ d->label.data,
+ d->label.length,
+ d->context.data,
+ d->context.length,
+ GNUTLS_MAC_SHA256,
+ session->smb2_channel.signing_key->blob.data,
+ session->smb2_channel.signing_key->blob.length);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ ZERO_STRUCT(channel_key);
+
+ status = smb2_signing_check_pdu(session->smb2_channel.signing_key,
+ recv_iov, 3);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_session_encryption_on(struct smbXcli_session *session)
+{
+ if (!session->smb2->should_sign) {
+ /*
+ * We need required signing on the session
+ * in order to prevent man in the middle attacks.
+ */
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (session->smb2->should_encrypt) {
+ return NT_STATUS_OK;
+ }
+
+ if (session->conn->protocol < PROTOCOL_SMB3_00) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ if (session->conn->smb2.server.cipher == 0) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ if (!smb2_signing_key_valid(session->smb2->signing_key)) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+ session->smb2->should_encrypt = true;
+ return NT_STATUS_OK;
+}
+
+uint16_t smb2cli_session_get_encryption_cipher(struct smbXcli_session *session)
+{
+ if (session->conn->protocol < PROTOCOL_SMB3_00) {
+ return 0;
+ }
+
+ if (!session->smb2->should_encrypt) {
+ return 0;
+ }
+
+ return session->conn->smb2.server.cipher;
+}
+
+struct smbXcli_tcon *smbXcli_tcon_create(TALLOC_CTX *mem_ctx)
+{
+ struct smbXcli_tcon *tcon;
+
+ tcon = talloc_zero(mem_ctx, struct smbXcli_tcon);
+ if (tcon == NULL) {
+ return NULL;
+ }
+
+ return tcon;
+}
+
+/*
+ * Return a deep structure copy of a struct smbXcli_tcon *
+ */
+
+struct smbXcli_tcon *smbXcli_tcon_copy(TALLOC_CTX *mem_ctx,
+ const struct smbXcli_tcon *tcon_in)
+{
+ struct smbXcli_tcon *tcon;
+
+ tcon = talloc_memdup(mem_ctx, tcon_in, sizeof(struct smbXcli_tcon));
+ if (tcon == NULL) {
+ return NULL;
+ }
+
+ /* Deal with the SMB1 strings. */
+ if (tcon_in->smb1.service != NULL) {
+ tcon->smb1.service = talloc_strdup(tcon, tcon_in->smb1.service);
+ if (tcon->smb1.service == NULL) {
+ TALLOC_FREE(tcon);
+ return NULL;
+ }
+ }
+ if (tcon->smb1.fs_type != NULL) {
+ tcon->smb1.fs_type = talloc_strdup(tcon, tcon_in->smb1.fs_type);
+ if (tcon->smb1.fs_type == NULL) {
+ TALLOC_FREE(tcon);
+ return NULL;
+ }
+ }
+ return tcon;
+}
+
+void smbXcli_tcon_set_fs_attributes(struct smbXcli_tcon *tcon,
+ uint32_t fs_attributes)
+{
+ tcon->fs_attributes = fs_attributes;
+}
+
+uint32_t smbXcli_tcon_get_fs_attributes(struct smbXcli_tcon *tcon)
+{
+ return tcon->fs_attributes;
+}
+
+bool smbXcli_tcon_is_dfs_share(struct smbXcli_tcon *tcon)
+{
+ if (tcon == NULL) {
+ return false;
+ }
+
+ if (tcon->is_smb1) {
+ if (tcon->smb1.optional_support & SMB_SHARE_IN_DFS) {
+ return true;
+ }
+
+ return false;
+ }
+
+ if (tcon->smb2.capabilities & SMB2_SHARE_CAP_DFS) {
+ return true;
+ }
+
+ return false;
+}
+
+uint16_t smb1cli_tcon_current_id(struct smbXcli_tcon *tcon)
+{
+ return tcon->smb1.tcon_id;
+}
+
+void smb1cli_tcon_set_id(struct smbXcli_tcon *tcon, uint16_t tcon_id)
+{
+ tcon->is_smb1 = true;
+ tcon->smb1.tcon_id = tcon_id;
+}
+
+bool smb1cli_tcon_set_values(struct smbXcli_tcon *tcon,
+ uint16_t tcon_id,
+ uint16_t optional_support,
+ uint32_t maximal_access,
+ uint32_t guest_maximal_access,
+ const char *service,
+ const char *fs_type)
+{
+ tcon->is_smb1 = true;
+ tcon->fs_attributes = 0;
+ tcon->smb1.tcon_id = tcon_id;
+ tcon->smb1.optional_support = optional_support;
+ tcon->smb1.maximal_access = maximal_access;
+ tcon->smb1.guest_maximal_access = guest_maximal_access;
+
+ TALLOC_FREE(tcon->smb1.service);
+ tcon->smb1.service = talloc_strdup(tcon, service);
+ if (service != NULL && tcon->smb1.service == NULL) {
+ return false;
+ }
+
+ TALLOC_FREE(tcon->smb1.fs_type);
+ tcon->smb1.fs_type = talloc_strdup(tcon, fs_type);
+ if (fs_type != NULL && tcon->smb1.fs_type == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
+uint32_t smb2cli_tcon_current_id(struct smbXcli_tcon *tcon)
+{
+ return tcon->smb2.tcon_id;
+}
+
+void smb2cli_tcon_set_id(struct smbXcli_tcon *tcon, uint32_t tcon_id)
+{
+ tcon->smb2.tcon_id = tcon_id;
+}
+
+uint32_t smb2cli_tcon_capabilities(struct smbXcli_tcon *tcon)
+{
+ return tcon->smb2.capabilities;
+}
+
+uint32_t smb2cli_tcon_flags(struct smbXcli_tcon *tcon)
+{
+ return tcon->smb2.flags;
+}
+
+void smb2cli_tcon_set_values(struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint32_t tcon_id,
+ uint8_t type,
+ uint32_t flags,
+ uint32_t capabilities,
+ uint32_t maximal_access)
+{
+ tcon->is_smb1 = false;
+ tcon->fs_attributes = 0;
+ tcon->smb2.tcon_id = tcon_id;
+ tcon->smb2.type = type;
+ tcon->smb2.flags = flags;
+ tcon->smb2.capabilities = capabilities;
+ tcon->smb2.maximal_access = maximal_access;
+
+ tcon->smb2.should_sign = false;
+ tcon->smb2.should_encrypt = false;
+
+ if (session == NULL) {
+ return;
+ }
+
+ tcon->smb2.should_sign = session->smb2->should_sign;
+ tcon->smb2.should_encrypt = session->smb2->should_encrypt;
+
+ if (flags & SMB2_SHAREFLAG_ENCRYPT_DATA) {
+ tcon->smb2.should_encrypt = true;
+ }
+}
+
+void smb2cli_tcon_should_sign(struct smbXcli_tcon *tcon,
+ bool should_sign)
+{
+ tcon->smb2.should_sign = should_sign;
+}
+
+bool smb2cli_tcon_is_signing_on(struct smbXcli_tcon *tcon)
+{
+ if (tcon->smb2.should_encrypt) {
+ return true;
+ }
+
+ return tcon->smb2.should_sign;
+}
+
+void smb2cli_tcon_should_encrypt(struct smbXcli_tcon *tcon,
+ bool should_encrypt)
+{
+ tcon->smb2.should_encrypt = should_encrypt;
+}
+
+bool smb2cli_tcon_is_encryption_on(struct smbXcli_tcon *tcon)
+{
+ return tcon->smb2.should_encrypt;
+}
+
+void smb2cli_conn_set_mid(struct smbXcli_conn *conn, uint64_t mid)
+{
+ conn->smb2.mid = mid;
+}
+
+uint64_t smb2cli_conn_get_mid(struct smbXcli_conn *conn)
+{
+ return conn->smb2.mid;
+}
+
+NTSTATUS smb2cli_parse_dyn_buffer(uint32_t dyn_offset,
+ const DATA_BLOB dyn_buffer,
+ uint32_t min_offset,
+ uint32_t buffer_offset,
+ uint32_t buffer_length,
+ uint32_t max_length,
+ uint32_t *next_offset,
+ DATA_BLOB *buffer)
+{
+ uint32_t offset;
+ bool oob;
+
+ *buffer = data_blob_null;
+ *next_offset = dyn_offset;
+
+ if (buffer_offset == 0) {
+ /*
+ * If the offset is 0, we better ignore
+ * the buffer_length field.
+ */
+ return NT_STATUS_OK;
+ }
+
+ if (buffer_length == 0) {
+ /*
+ * If the length is 0, we better ignore
+ * the buffer_offset field.
+ */
+ return NT_STATUS_OK;
+ }
+
+ if ((buffer_offset % 8) != 0) {
+ /*
+ * The offset needs to be 8 byte aligned.
+ */
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ /*
+ * We used to enforce buffer_offset to be
+ * an exact match of the expected minimum,
+ * but the NetApp Ontap 7.3.7 SMB server
+ * gets the padding wrong and aligns the
+ * input_buffer_offset by a value of 8.
+ *
+ * So we just enforce that the offset is
+ * not lower than the expected value.
+ */
+ SMB_ASSERT(min_offset >= dyn_offset);
+ if (buffer_offset < min_offset) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ /*
+ * Make [input|output]_buffer_offset relative to "dyn_buffer"
+ */
+ offset = buffer_offset - dyn_offset;
+ oob = smb_buffer_oob(dyn_buffer.length, offset, buffer_length);
+ if (oob) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ /*
+ * Give the caller a hint what we consumed,
+ * the caller may need to add possible padding.
+ */
+ *next_offset = buffer_offset + buffer_length;
+
+ if (max_length == 0) {
+ /*
+ * If max_input_length is 0 we ignore the
+ * input_buffer_length, because Windows 2008 echos the
+ * DCERPC request from the requested input_buffer to
+ * the response input_buffer.
+ *
+ * We just use the same logic also for max_output_length...
+ */
+ buffer_length = 0;
+ }
+
+ if (buffer_length > max_length) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ *buffer = (DATA_BLOB) {
+ .data = dyn_buffer.data + offset,
+ .length = buffer_length,
+ };
+ return NT_STATUS_OK;
+}
diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h
new file mode 100644
index 0000000..25ccd84
--- /dev/null
+++ b/libcli/smb/smbXcli_base.h
@@ -0,0 +1,969 @@
+/*
+ Unix SMB/CIFS implementation.
+ Infrastructure for async SMB client requests
+ Copyright (C) Volker Lendecke 2008
+ Copyright (C) Stefan Metzmacher 2011
+
+ 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/>.
+*/
+
+#ifndef _SMBXCLI_BASE_H_
+#define _SMBXCLI_BASE_H_
+
+#define SMB_SUICIDE_PACKET 0x74697865
+
+#include "replace.h"
+#include <tevent.h>
+#include "libcli/smb/smb_constants.h"
+#include "libcli/util/ntstatus.h"
+#include "lib/util/time.h"
+#include "lib/util/data_blob.h"
+
+struct smbXcli_conn;
+struct smbXcli_session;
+struct smbXcli_tcon;
+struct smb_trans_enc_state;
+struct GUID;
+struct iovec;
+struct smb2_create_blobs;
+struct smb_create_returns;
+struct smb311_capabilities;
+
+struct smbXcli_conn *smbXcli_conn_create(TALLOC_CTX *mem_ctx,
+ int fd,
+ const char *remote_name,
+ enum smb_signing_setting signing_state,
+ uint32_t smb1_capabilities,
+ struct GUID *client_guid,
+ uint32_t smb2_capabilities,
+ const struct smb311_capabilities *smb3_capabilities);
+
+bool smbXcli_conn_is_connected(struct smbXcli_conn *conn);
+void smbXcli_conn_disconnect(struct smbXcli_conn *conn, NTSTATUS status);
+
+struct tevent_queue *smbXcli_conn_send_queue(struct smbXcli_conn *conn);
+bool smbXcli_conn_has_async_calls(struct smbXcli_conn *conn);
+
+bool smbXcli_conn_dfs_supported(struct smbXcli_conn *conn);
+
+enum protocol_types smbXcli_conn_protocol(struct smbXcli_conn *conn);
+bool smbXcli_conn_use_unicode(struct smbXcli_conn *conn);
+bool smbXcli_conn_signing_mandatory(struct smbXcli_conn *conn);
+bool smbXcli_conn_have_posix(struct smbXcli_conn *conn);
+bool smbXcli_conn_support_passthrough(struct smbXcli_conn *conn);
+
+void smbXcli_conn_set_sockopt(struct smbXcli_conn *conn, const char *options);
+const struct sockaddr_storage *smbXcli_conn_local_sockaddr(struct smbXcli_conn *conn);
+const struct sockaddr_storage *smbXcli_conn_remote_sockaddr(struct smbXcli_conn *conn);
+const char *smbXcli_conn_remote_name(struct smbXcli_conn *conn);
+
+uint16_t smbXcli_conn_max_requests(struct smbXcli_conn *conn);
+NTTIME smbXcli_conn_server_system_time(struct smbXcli_conn *conn);
+const DATA_BLOB *smbXcli_conn_server_gss_blob(struct smbXcli_conn *conn);
+const struct GUID *smbXcli_conn_server_guid(struct smbXcli_conn *conn);
+bool smbXcli_conn_get_force_channel_sequence(struct smbXcli_conn *conn);
+void smbXcli_conn_set_force_channel_sequence(struct smbXcli_conn *conn,
+ bool v);
+
+
+struct tevent_req *smbXcli_conn_samba_suicide_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint8_t exitcode);
+NTSTATUS smbXcli_conn_samba_suicide_recv(struct tevent_req *req);
+NTSTATUS smbXcli_conn_samba_suicide(struct smbXcli_conn *conn,
+ uint8_t exitcode);
+
+void smbXcli_req_unset_pending(struct tevent_req *req);
+bool smbXcli_req_set_pending(struct tevent_req *req);
+struct timeval smbXcli_req_endtime(struct tevent_req *req);
+
+uint32_t smb1cli_conn_capabilities(struct smbXcli_conn *conn);
+uint32_t smb1cli_conn_max_xmit(struct smbXcli_conn *conn);
+bool smb1cli_conn_req_possible(struct smbXcli_conn *conn);
+uint32_t smb1cli_conn_server_session_key(struct smbXcli_conn *conn);
+const uint8_t *smb1cli_conn_server_challenge(struct smbXcli_conn *conn);
+uint16_t smb1cli_conn_server_security_mode(struct smbXcli_conn *conn);
+bool smb1cli_conn_server_readbraw(struct smbXcli_conn *conn);
+bool smb1cli_conn_server_writebraw(struct smbXcli_conn *conn);
+bool smb1cli_conn_server_lockread(struct smbXcli_conn *conn);
+bool smb1cli_conn_server_writeunlock(struct smbXcli_conn *conn);
+int smb1cli_conn_server_time_zone(struct smbXcli_conn *conn);
+
+bool smb1cli_conn_activate_signing(struct smbXcli_conn *conn,
+ const DATA_BLOB user_session_key,
+ const DATA_BLOB response);
+bool smb1cli_conn_check_signing(struct smbXcli_conn *conn,
+ const uint8_t *buf, uint32_t seqnum);
+bool smb1cli_conn_signing_is_active(struct smbXcli_conn *conn);
+
+void smb1cli_conn_set_encryption(struct smbXcli_conn *conn,
+ struct smb_trans_enc_state *es);
+bool smb1cli_conn_encryption_on(struct smbXcli_conn *conn);
+
+bool smb1cli_is_andx_req(uint8_t cmd);
+size_t smb1cli_req_wct_ofs(struct tevent_req **reqs, int num_reqs);
+
+uint16_t smb1cli_req_mid(struct tevent_req *req);
+void smb1cli_req_set_mid(struct tevent_req *req, uint16_t mid);
+
+uint32_t smb1cli_req_seqnum(struct tevent_req *req);
+void smb1cli_req_set_seqnum(struct tevent_req *req, uint32_t seqnum);
+
+struct smb1cli_req_expected_response {
+ NTSTATUS status;
+ uint8_t wct;
+};
+
+struct tevent_req *smb1cli_req_create(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint8_t smb_command,
+ uint8_t additional_flags,
+ uint8_t clear_flags,
+ uint16_t additional_flags2,
+ uint16_t clear_flags2,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint8_t wct, uint16_t *vwv,
+ int iov_count,
+ struct iovec *bytes_iov);
+NTSTATUS smb1cli_req_chain_submit(struct tevent_req **reqs, int num_reqs);
+
+struct tevent_req *smb1cli_req_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint8_t smb_command,
+ uint8_t additional_flags,
+ uint8_t clear_flags,
+ uint16_t additional_flags2,
+ uint16_t clear_flags2,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint8_t wct, uint16_t *vwv,
+ uint32_t num_bytes,
+ const uint8_t *bytes);
+NTSTATUS smb1cli_req_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **piov,
+ uint8_t **phdr,
+ uint8_t *pwct,
+ uint16_t **pvwv,
+ uint32_t *pvwv_offset,
+ uint32_t *pnum_bytes,
+ uint8_t **pbytes,
+ uint32_t *pbytes_offset,
+ uint8_t **pinbuf,
+ const struct smb1cli_req_expected_response *expected,
+ size_t num_expected);
+
+struct tevent_req *smb1cli_trans_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct smbXcli_conn *conn, uint8_t cmd,
+ uint8_t additional_flags, uint8_t clear_flags,
+ uint16_t additional_flags2, uint16_t clear_flags2,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const char *pipe_name, uint16_t fid, uint16_t function, int flags,
+ uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
+ uint8_t *param, uint32_t num_param, uint32_t max_param,
+ uint8_t *data, uint32_t num_data, uint32_t max_data);
+NTSTATUS smb1cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ uint16_t *recv_flags2,
+ uint16_t **setup, uint8_t min_setup,
+ uint8_t *num_setup,
+ uint8_t **param, uint32_t min_param,
+ uint32_t *num_param,
+ uint8_t **data, uint32_t min_data,
+ uint32_t *num_data);
+NTSTATUS smb1cli_trans(TALLOC_CTX *mem_ctx, struct smbXcli_conn *conn,
+ uint8_t trans_cmd,
+ uint8_t additional_flags, uint8_t clear_flags,
+ uint16_t additional_flags2, uint16_t clear_flags2,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const char *pipe_name, uint16_t fid, uint16_t function,
+ int flags,
+ uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
+ uint8_t *param, uint32_t num_param, uint32_t max_param,
+ uint8_t *data, uint32_t num_data, uint32_t max_data,
+ uint16_t *recv_flags2,
+ uint16_t **rsetup, uint8_t min_rsetup, uint8_t *num_rsetup,
+ uint8_t **rparam, uint32_t min_rparam, uint32_t *num_rparam,
+ uint8_t **rdata, uint32_t min_rdata, uint32_t *num_rdata);
+
+struct tevent_req *smb1cli_echo_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint16_t num_echos,
+ DATA_BLOB data);
+NTSTATUS smb1cli_echo_recv(struct tevent_req *req);
+NTSTATUS smb1cli_echo(struct smbXcli_conn *conn, uint32_t timeout_msec,
+ uint16_t num_echos, DATA_BLOB data);
+
+struct tevent_req *smb1cli_session_setup_lm21_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_session *session,
+ uint16_t in_buf_size,
+ uint16_t in_mpx_max,
+ uint16_t in_vc_num,
+ uint32_t in_sess_key,
+ const char *in_user,
+ const char *in_domain,
+ const DATA_BLOB in_password,
+ const char *in_native_os,
+ const char *in_native_lm);
+NTSTATUS smb1cli_session_setup_lm21_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ char **out_native_os,
+ char **out_native_lm);
+struct tevent_req *smb1cli_session_setup_nt1_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_session *session,
+ uint16_t in_buf_size,
+ uint16_t in_mpx_max,
+ uint16_t in_vc_num,
+ uint32_t in_sess_key,
+ const char *in_user,
+ const char *in_domain,
+ const DATA_BLOB in_apassword,
+ const DATA_BLOB in_upassword,
+ uint32_t in_capabilities,
+ const char *in_native_os,
+ const char *in_native_lm);
+NTSTATUS smb1cli_session_setup_nt1_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **precv_iov,
+ const uint8_t **precv_inbuf,
+ char **out_native_os,
+ char **out_native_lm,
+ char **out_primary_domain);
+struct tevent_req *smb1cli_session_setup_ext_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_session *session,
+ uint16_t in_buf_size,
+ uint16_t in_mpx_max,
+ uint16_t in_vc_num,
+ uint32_t in_sess_key,
+ const DATA_BLOB in_security_blob,
+ uint32_t in_capabilities,
+ const char *in_native_os,
+ const char *in_native_lm);
+NTSTATUS smb1cli_session_setup_ext_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **precv_iov,
+ const uint8_t **precv_inbuf,
+ DATA_BLOB *out_security_blob,
+ char **out_native_os,
+ char **out_native_lm);
+
+struct tevent_req *smb1cli_ntcreatex_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const char *fname,
+ uint32_t CreatFlags,
+ uint32_t RootDirectoryFid,
+ uint32_t DesiredAccess,
+ uint64_t AllocationSize,
+ uint32_t FileAttributes,
+ uint32_t ShareAccess,
+ uint32_t CreateDisposition,
+ uint32_t CreateOptions,
+ uint32_t ImpersonationLevel,
+ uint8_t SecurityFlags);
+NTSTATUS smb1cli_ntcreatex_recv(struct tevent_req *req, uint16_t *pfnum);
+NTSTATUS smb1cli_ntcreatex(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const char *fname,
+ uint32_t CreatFlags,
+ uint32_t RootDirectoryFid,
+ uint32_t DesiredAccess,
+ uint64_t AllocationSize,
+ uint32_t FileAttributes,
+ uint32_t ShareAccess,
+ uint32_t CreateDisposition,
+ uint32_t CreateOptions,
+ uint32_t ImpersonationLevel,
+ uint8_t SecurityFlags,
+ uint16_t *pfnum);
+struct tevent_req *smb1cli_close_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint16_t fnum,
+ uint32_t last_modified);
+NTSTATUS smb1cli_close_recv(struct tevent_req *req);
+NTSTATUS smb1cli_close(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint16_t fnum,
+ uint32_t last_modified);
+struct tevent_req *smb1cli_writex_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint16_t fnum,
+ uint16_t mode,
+ const uint8_t *buf,
+ uint64_t offset,
+ uint32_t size);
+NTSTATUS smb1cli_writex_recv(struct tevent_req *req,
+ uint32_t *pwritten,
+ uint16_t *pavailable);
+NTSTATUS smb1cli_writex(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint16_t fnum,
+ uint16_t mode,
+ const uint8_t *buf,
+ uint64_t offset,
+ uint32_t size,
+ uint32_t *pwritten,
+ uint16_t *pavailable);
+struct tevent_req *smb1cli_readx_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint16_t fnum,
+ uint64_t offset,
+ uint32_t size);
+NTSTATUS smb1cli_readx_recv(struct tevent_req *req,
+ uint32_t *received,
+ uint8_t **rcvbuf);
+
+bool smb2cli_conn_req_possible(struct smbXcli_conn *conn, uint32_t *max_dyn_len);
+uint32_t smb2cli_conn_server_capabilities(struct smbXcli_conn *conn);
+uint16_t smb2cli_conn_server_security_mode(struct smbXcli_conn *conn);
+uint16_t smb2cli_conn_server_signing_algo(struct smbXcli_conn *conn);
+uint16_t smb2cli_conn_server_encryption_algo(struct smbXcli_conn *conn);
+uint32_t smb2cli_conn_max_trans_size(struct smbXcli_conn *conn);
+uint32_t smb2cli_conn_max_read_size(struct smbXcli_conn *conn);
+uint32_t smb2cli_conn_max_write_size(struct smbXcli_conn *conn);
+void smb2cli_conn_set_max_credits(struct smbXcli_conn *conn,
+ uint16_t max_credits);
+uint16_t smb2cli_conn_get_cur_credits(struct smbXcli_conn *conn);
+uint8_t smb2cli_conn_get_io_priority(struct smbXcli_conn *conn);
+void smb2cli_conn_set_io_priority(struct smbXcli_conn *conn,
+ uint8_t io_priority);
+uint32_t smb2cli_conn_cc_chunk_len(struct smbXcli_conn *conn);
+void smb2cli_conn_set_cc_chunk_len(struct smbXcli_conn *conn,
+ uint32_t chunk_len);
+uint32_t smb2cli_conn_cc_max_chunks(struct smbXcli_conn *conn);
+void smb2cli_conn_set_cc_max_chunks(struct smbXcli_conn *conn,
+ uint32_t max_chunks);
+void smb2cli_conn_set_mid(struct smbXcli_conn *conn, uint64_t mid);
+uint64_t smb2cli_conn_get_mid(struct smbXcli_conn *conn);
+
+NTSTATUS smb2cli_parse_dyn_buffer(uint32_t dyn_offset,
+ const DATA_BLOB dyn_buffer,
+ uint32_t min_offset,
+ uint32_t buffer_offset,
+ uint32_t buffer_length,
+ uint32_t max_length,
+ uint32_t *next_offset,
+ DATA_BLOB *buffer);
+
+struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint16_t cmd,
+ uint32_t additional_flags,
+ uint32_t clear_flags,
+ uint32_t timeout_msec,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const uint8_t *fixed,
+ uint16_t fixed_len,
+ const uint8_t *dyn,
+ uint32_t dyn_len,
+ uint32_t max_dyn_len);
+void smb2cli_req_set_notify_async(struct tevent_req *req);
+NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs,
+ int num_reqs);
+void smb2cli_req_set_credit_charge(struct tevent_req *req, uint16_t charge);
+
+struct smb2cli_req_expected_response {
+ NTSTATUS status;
+ uint16_t body_size;
+};
+
+struct tevent_req *smb2cli_req_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint16_t cmd,
+ uint32_t additional_flags,
+ uint32_t clear_flags,
+ uint32_t timeout_msec,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const uint8_t *fixed,
+ uint16_t fixed_len,
+ const uint8_t *dyn,
+ uint32_t dyn_len,
+ uint32_t max_dyn_len);
+NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct iovec **piov,
+ const struct smb2cli_req_expected_response *expected,
+ size_t num_expected);
+
+/*
+ * This expects an iov[3] array, that is filled with references to
+ * the buffers used for the sending the requests into the socket.
+ *
+ * This can only be called after smb2cli_req_recv(subreq) before
+ * the TALLOC_FREE(subreq).
+ */
+NTSTATUS smb2cli_req_get_sent_iov(struct tevent_req *req,
+ struct iovec *sent_iov);
+
+struct smb2_negotiate_contexts;
+struct tevent_req *smbXcli_negprot_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ enum protocol_types min_protocol,
+ enum protocol_types max_protocol,
+ uint16_t max_credits,
+ struct smb2_negotiate_contexts *in_ctx);
+NTSTATUS smbXcli_negprot_recv(
+ struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_negotiate_contexts **out_ctx);
+NTSTATUS smbXcli_negprot(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ enum protocol_types min_protocol,
+ enum protocol_types max_protocol,
+ struct smb2_negotiate_contexts *in_ctx,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_negotiate_contexts **out_ctx);
+
+struct tevent_req *smb2cli_validate_negotiate_info_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon);
+NTSTATUS smb2cli_validate_negotiate_info_recv(struct tevent_req *req);
+
+struct smbXcli_session *smbXcli_session_create(TALLOC_CTX *mem_ctx,
+ struct smbXcli_conn *conn);
+struct smbXcli_session *smbXcli_session_shallow_copy(TALLOC_CTX *mem_ctx,
+ struct smbXcli_session *src);
+bool smbXcli_session_is_guest(struct smbXcli_session *session);
+bool smbXcli_session_is_authenticated(struct smbXcli_session *session);
+NTSTATUS smb2cli_session_signing_key(struct smbXcli_session *session,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *key);
+NTSTATUS smb2cli_session_encryption_key(struct smbXcli_session *session,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *key);
+NTSTATUS smb2cli_session_decryption_key(struct smbXcli_session *session,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *key);
+NTSTATUS smbXcli_session_application_key(struct smbXcli_session *session,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *key);
+void smbXcli_session_set_disconnect_expired(struct smbXcli_session *session);
+uint16_t smb1cli_session_current_id(struct smbXcli_session* session);
+void smb1cli_session_set_id(struct smbXcli_session* session,
+ uint16_t session_id);
+void smb1cli_session_set_action(struct smbXcli_session *session,
+ uint16_t action);
+NTSTATUS smb1cli_session_set_session_key(struct smbXcli_session *session,
+ const DATA_BLOB _session_key);
+NTSTATUS smb1cli_session_protect_session_key(struct smbXcli_session *session);
+uint8_t smb2cli_session_security_mode(struct smbXcli_session *session);
+uint64_t smb2cli_session_current_id(struct smbXcli_session *session);
+uint16_t smb2cli_session_get_flags(struct smbXcli_session *session);
+void smb2cli_session_set_id_and_flags(struct smbXcli_session *session,
+ uint64_t session_id,
+ uint16_t session_flags);
+void smb2cli_session_increment_channel_sequence(struct smbXcli_session *session);
+uint16_t smb2cli_session_reset_channel_sequence(struct smbXcli_session *session,
+ uint16_t channel_sequence);
+uint16_t smb2cli_session_current_channel_sequence(struct smbXcli_session *session);
+void smb2cli_session_start_replay(struct smbXcli_session *session);
+void smb2cli_session_stop_replay(struct smbXcli_session *session);
+void smb2cli_session_require_signed_response(struct smbXcli_session *session,
+ bool require_signed_response);
+NTSTATUS smb2cli_session_update_preauth(struct smbXcli_session *session,
+ const struct iovec *iov);
+NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
+ const DATA_BLOB session_key,
+ const struct iovec *recv_iov);
+NTSTATUS smb2cli_session_create_channel(TALLOC_CTX *mem_ctx,
+ struct smbXcli_session *session1,
+ struct smbXcli_conn *conn,
+ struct smbXcli_session **_session2);
+NTSTATUS smb2cli_session_set_channel_key(struct smbXcli_session *session,
+ const DATA_BLOB channel_key,
+ const struct iovec *recv_iov);
+NTSTATUS smb2cli_session_encryption_on(struct smbXcli_session *session);
+uint16_t smb2cli_session_get_encryption_cipher(struct smbXcli_session *session);
+
+struct smbXcli_tcon *smbXcli_tcon_create(TALLOC_CTX *mem_ctx);
+struct smbXcli_tcon *smbXcli_tcon_copy(TALLOC_CTX *mem_ctx,
+ const struct smbXcli_tcon *tcon_in);
+void smbXcli_tcon_set_fs_attributes(struct smbXcli_tcon *tcon,
+ uint32_t fs_attributes);
+uint32_t smbXcli_tcon_get_fs_attributes(struct smbXcli_tcon *tcon);
+bool smbXcli_tcon_is_dfs_share(struct smbXcli_tcon *tcon);
+uint16_t smb1cli_tcon_current_id(struct smbXcli_tcon *tcon);
+void smb1cli_tcon_set_id(struct smbXcli_tcon *tcon, uint16_t tcon_id);
+bool smb1cli_tcon_set_values(struct smbXcli_tcon *tcon,
+ uint16_t tcon_id,
+ uint16_t optional_support,
+ uint32_t maximal_access,
+ uint32_t guest_maximal_access,
+ const char *service,
+ const char *fs_type);
+uint32_t smb2cli_tcon_current_id(struct smbXcli_tcon *tcon);
+void smb2cli_tcon_set_id(struct smbXcli_tcon *tcon, uint32_t tcon_id);
+uint32_t smb2cli_tcon_capabilities(struct smbXcli_tcon *tcon);
+uint32_t smb2cli_tcon_flags(struct smbXcli_tcon *tcon);
+void smb2cli_tcon_set_values(struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint32_t tcon_id,
+ uint8_t type,
+ uint32_t flags,
+ uint32_t capabilities,
+ uint32_t maximal_access);
+void smb2cli_tcon_should_sign(struct smbXcli_tcon *tcon,
+ bool should_sign);
+bool smb2cli_tcon_is_signing_on(struct smbXcli_tcon *tcon);
+void smb2cli_tcon_should_encrypt(struct smbXcli_tcon *tcon,
+ bool should_encrypt);
+bool smb2cli_tcon_is_encryption_on(struct smbXcli_tcon *tcon);
+
+struct tevent_req *smb2cli_session_setup_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ uint8_t in_flags,
+ uint32_t in_capabilities,
+ uint32_t in_channel,
+ uint64_t in_previous_session_id,
+ const DATA_BLOB *in_security_buffer);
+NTSTATUS smb2cli_session_setup_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **recv_iov,
+ DATA_BLOB *out_security_buffer);
+
+struct tevent_req *smb2cli_logoff_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session);
+NTSTATUS smb2cli_logoff_recv(struct tevent_req *req);
+NTSTATUS smb2cli_logoff(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session);
+
+/* smb2cli_raw_tcon* should only be used in tests! */
+struct tevent_req *smb2cli_raw_tcon_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t additional_flags,
+ uint32_t clear_flags,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t tcon_flags,
+ const char *unc);
+NTSTATUS smb2cli_raw_tcon_recv(struct tevent_req *req);
+NTSTATUS smb2cli_raw_tcon(struct smbXcli_conn *conn,
+ uint32_t additional_flags,
+ uint32_t clear_flags,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t tcon_flags,
+ const char *unc);
+struct tevent_req *smb2cli_tcon_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t flags,
+ const char *unc);
+NTSTATUS smb2cli_tcon_recv(struct tevent_req *req);
+NTSTATUS smb2cli_tcon(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t flags,
+ const char *unc);
+
+struct tevent_req *smb2cli_tdis_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon);
+NTSTATUS smb2cli_tdis_recv(struct tevent_req *req);
+NTSTATUS smb2cli_tdis(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon);
+
+struct symlink_reparse_struct;
+
+struct tevent_req *smb2cli_create_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ const char *filename,
+ uint8_t oplock_level, /* SMB2_OPLOCK_LEVEL_* */
+ uint32_t impersonation_level, /* SMB2_IMPERSONATION_* */
+ uint32_t desired_access,
+ uint32_t file_attributes,
+ uint32_t share_access,
+ uint32_t create_disposition,
+ uint32_t create_options,
+ struct smb2_create_blobs *blobs);
+NTSTATUS smb2cli_create_recv(struct tevent_req *req,
+ uint64_t *fid_persistent,
+ uint64_t *fid_volatile,
+ struct smb_create_returns *cr,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_create_blobs *blobs,
+ struct symlink_reparse_struct **psymlink);
+NTSTATUS smb2cli_create(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ const char *filename,
+ uint8_t oplock_level, /* SMB2_OPLOCK_LEVEL_* */
+ uint32_t impersonation_level, /* SMB2_IMPERSONATION_* */
+ uint32_t desired_access,
+ uint32_t file_attributes,
+ uint32_t share_access,
+ uint32_t create_disposition,
+ uint32_t create_options,
+ struct smb2_create_blobs *blobs,
+ uint64_t *fid_persistent,
+ uint64_t *fid_volatile,
+ struct smb_create_returns *cr,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_create_blobs *ret_blobs,
+ struct symlink_reparse_struct **psymlink);
+
+struct tevent_req *smb2cli_close_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t flags,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile);
+NTSTATUS smb2cli_close_recv(struct tevent_req *req);
+NTSTATUS smb2cli_close(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t flags,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile);
+
+struct tevent_req *smb2cli_read_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t length,
+ uint64_t offset,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint64_t minimum_count,
+ uint64_t remaining_bytes);
+NTSTATUS smb2cli_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ uint8_t **data, uint32_t *data_length);
+NTSTATUS smb2cli_read(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t length,
+ uint64_t offset,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint64_t minimum_count,
+ uint64_t remaining_bytes,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **data,
+ uint32_t *data_length);
+
+struct tevent_req *smb2cli_write_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t length,
+ uint64_t offset,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint32_t remaining_bytes,
+ uint32_t flags,
+ const uint8_t *data);
+NTSTATUS smb2cli_write_recv(struct tevent_req *req,
+ uint32_t *written);
+NTSTATUS smb2cli_write(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t length,
+ uint64_t offset,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint32_t remaining_bytes,
+ uint32_t flags,
+ const uint8_t *data,
+ uint32_t *written);
+
+struct tevent_req *smb2cli_flush_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile);
+NTSTATUS smb2cli_flush_recv(struct tevent_req *req);
+NTSTATUS smb2cli_flush(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile);
+
+struct tevent_req *smb2cli_set_info_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t in_info_type,
+ uint8_t in_file_info_class,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_additional_info,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile);
+NTSTATUS smb2cli_set_info_recv(struct tevent_req *req);
+NTSTATUS smb2cli_set_info(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t in_info_type,
+ uint8_t in_file_info_class,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_additional_info,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile);
+
+struct tevent_req *smb2cli_query_info_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t in_info_type,
+ uint8_t in_file_info_class,
+ uint32_t in_max_output_length,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_additional_info,
+ uint32_t in_flags,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile);
+NTSTATUS smb2cli_query_info_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *out_output_buffer);
+NTSTATUS smb2cli_query_info(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t in_info_type,
+ uint8_t in_file_info_class,
+ uint32_t in_max_output_length,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_additional_info,
+ uint32_t in_flags,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *out_output_buffer);
+
+struct tevent_req *smb2cli_query_directory_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t level,
+ uint8_t flags,
+ uint32_t file_index,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ const char *mask,
+ uint32_t outbuf_len);
+NTSTATUS smb2cli_query_directory_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **data,
+ uint32_t *data_length);
+NTSTATUS smb2cli_query_directory(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t level,
+ uint8_t flags,
+ uint32_t file_index,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ const char *mask,
+ uint32_t outbuf_len,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **data,
+ uint32_t *data_length);
+
+struct tevent_req *smb2cli_notify_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t output_buffer_length,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint32_t completion_filter,
+ bool recursive);
+NTSTATUS smb2cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ uint8_t **data, uint32_t *data_length);
+NTSTATUS smb2cli_notify(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t output_buffer_length,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint32_t completion_filter,
+ bool recursive,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **data,
+ uint32_t *data_length);
+
+struct tevent_req *smb2cli_ioctl_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile,
+ uint32_t in_ctl_code,
+ uint32_t in_max_input_length,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_max_output_length,
+ const DATA_BLOB *in_output_buffer,
+ uint32_t in_flags);
+NTSTATUS smb2cli_ioctl_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *out_input_buffer,
+ DATA_BLOB *out_output_buffer);
+NTSTATUS smb2cli_ioctl(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile,
+ uint32_t in_ctl_code,
+ uint32_t in_max_input_length,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_max_output_length,
+ const DATA_BLOB *in_output_buffer,
+ uint32_t in_flags,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *out_input_buffer,
+ DATA_BLOB *out_output_buffer);
+
+struct tevent_req *smb2cli_echo_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec);
+NTSTATUS smb2cli_echo_recv(struct tevent_req *req);
+NTSTATUS smb2cli_echo(struct smbXcli_conn *conn,
+ uint32_t timeout_msec);
+
+struct tevent_req *smb2cli_ioctl_pipe_wait_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ const char *pipe_name,
+ uint64_t pipe_wait_timeout);
+
+NTSTATUS smb2cli_ioctl_pipe_wait_recv(struct tevent_req *req);
+
+NTSTATUS smb2cli_ioctl_pipe_wait(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ const char *pipe_name,
+ uint64_t pipe_wait_timeout);
+
+#endif /* _SMBXCLI_BASE_H_ */
diff --git a/libcli/smb/smb_common.h b/libcli/smb/smb_common.h
new file mode 100644
index 0000000..0117570
--- /dev/null
+++ b/libcli/smb/smb_common.h
@@ -0,0 +1,34 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB and SMB2 common header
+
+ Copyright (C) Stefan Metzmacher 2009
+
+ 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/>.
+*/
+
+#ifndef __LIBCLI_SMB_SMB_COMMON_H__
+#define __LIBCLI_SMB_SMB_COMMON_H__
+
+#include "libcli/smb/smb_constants.h"
+#include "libcli/smb/smb2_constants.h"
+#include "libcli/smb/smb2_create_blob.h"
+#include "libcli/smb/smb2_lease.h"
+#include "libcli/smb/smb2_lock.h"
+#include "libcli/smb/smb2_signing.h"
+#include "libcli/smb/smb_util.h"
+#include "libcli/smb/smb_unix_ext.h"
+
+#endif
diff --git a/libcli/smb/smb_constants.h b/libcli/smb/smb_constants.h
new file mode 100644
index 0000000..1d55a55
--- /dev/null
+++ b/libcli/smb/smb_constants.h
@@ -0,0 +1,649 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB parameters and setup, plus a whole lot more.
+
+ Copyright (C) Andrew Tridgell 2011
+
+ 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/>.
+*/
+
+#ifndef _SMB_CONSTANTS_H
+#define _SMB_CONSTANTS_H
+
+/*
+ * Netbios over TCP (rfc 1002)
+ */
+#define NBSSmessage 0x00 /* session message */
+#define NBSSrequest 0x81 /* session request */
+#define NBSSpositive 0x82 /* positive session response */
+#define NBSSnegative 0x83 /* negative session response */
+#define NBSSretarget 0x84 /* retarget session response */
+#define NBSSkeepalive 0x85 /* keepalive */
+
+#define SMB_MAGIC 0x424D53FF /* 0xFF 'S' 'M' 'B' */
+
+/* the basic packet size, assuming no words or bytes. Does not include the NBT header */
+#define MIN_SMB_SIZE 35
+
+/* when using NBT encapsulation every packet has a 4 byte header */
+#define NBT_HDR_SIZE 4
+
+/* offsets into message header for common items - NOTE: These have
+ changed from being offsets from the base of the NBT packet to the base of the SMB packet.
+ this has reduced all these values by 4
+*/
+#define HDR_COM 4
+#define HDR_RCLS 5
+#define HDR_REH 6
+#define HDR_ERR 7
+#define HDR_FLG 9
+#define HDR_FLG2 10
+#define HDR_PIDHIGH 12
+#define HDR_SS_FIELD 14
+#define HDR_TID 24
+#define HDR_PID 26
+#define HDR_UID 28
+#define HDR_MID 30
+#define HDR_WCT 32
+#define HDR_VWV 33
+
+/* Macros for accessing SMB protocol elements */
+#define VWV(vwv) ((vwv)*2)
+
+#define smb_len_nbt(buf) (RIVAL(buf, 0) & 0x1FFFF)
+#define _smb_setlen_nbt(buf,len) RSIVAL(buf, 0, (len) & 0x1FFFF)
+#define smb_setlen_nbt(buf, len) do { \
+ _smb_setlen_nbt(buf, len); \
+ SIVAL(buf, 4, SMB_MAGIC); \
+} while (0)
+
+#define smb_len_tcp(buf) (RIVAL(buf, 0) & 0xFFFFFF)
+#define _smb_setlen_tcp(buf,len) RSIVAL(buf, 0, (len) & 0xFFFFFF)
+#define smb_setlen_tcp(buf, len) do { \
+ _smb_setlen_tcp(buf, len); \
+ SIVAL(buf, 4, SMB_MAGIC); \
+} while (0)
+
+/* protocol types. It assumes that higher protocols include lower protocols
+ as subsets. */
+enum protocol_types {
+ PROTOCOL_DEFAULT=-1,
+ PROTOCOL_NONE=0,
+ PROTOCOL_CORE,
+ PROTOCOL_COREPLUS,
+ PROTOCOL_LANMAN1,
+ PROTOCOL_LANMAN2,
+ PROTOCOL_NT1,
+ PROTOCOL_SMB2_02,
+ PROTOCOL_SMB2_10,
+ PROTOCOL_SMB3_00,
+ PROTOCOL_SMB3_02,
+ PROTOCOL_SMB3_11
+};
+#define PROTOCOL_LATEST PROTOCOL_SMB3_11
+
+enum smb_signing_setting {
+ SMB_SIGNING_IPC_DEFAULT = -2, /* Only used in C code */
+ SMB_SIGNING_DEFAULT = -1,
+ SMB_SIGNING_OFF = 0,
+ SMB_SIGNING_IF_REQUIRED = 1,
+ SMB_SIGNING_DESIRED = 2,
+ SMB_SIGNING_REQUIRED = 3,
+};
+
+/* This MUST align with 'enum smb_signing_setting' */
+enum smb_encryption_setting {
+ SMB_ENCRYPTION_DEFAULT = SMB_SIGNING_DEFAULT,
+ SMB_ENCRYPTION_OFF = SMB_SIGNING_OFF,
+ SMB_ENCRYPTION_IF_REQUIRED = SMB_SIGNING_IF_REQUIRED,
+ SMB_ENCRYPTION_DESIRED = SMB_SIGNING_DESIRED,
+ SMB_ENCRYPTION_REQUIRED = SMB_SIGNING_REQUIRED,
+};
+
+/* types of buffers in core SMB protocol */
+#define SMB_DATA_BLOCK 0x1
+#define SMB_ASCII4 0x4
+
+/* flag defines. CIFS spec 3.1.1 */
+#define FLAG_SUPPORT_LOCKREAD 0x01
+#define FLAG_CLIENT_BUF_AVAIL 0x02
+#define FLAG_RESERVED 0x04
+#define FLAG_CASELESS_PATHNAMES 0x08
+#define FLAG_CANONICAL_PATHNAMES 0x10
+#define FLAG_REQUEST_OPLOCK 0x20
+#define FLAG_REQUEST_BATCH_OPLOCK 0x40
+#define FLAG_REPLY 0x80
+
+/* the complete */
+#define SMBmkdir 0x00 /* create directory */
+#define SMBrmdir 0x01 /* delete directory */
+#define SMBopen 0x02 /* open file */
+#define SMBcreate 0x03 /* create file */
+#define SMBclose 0x04 /* close file */
+#define SMBflush 0x05 /* flush file */
+#define SMBunlink 0x06 /* delete file */
+#define SMBmv 0x07 /* rename file */
+#define SMBgetatr 0x08 /* get file attributes */
+#define SMBsetatr 0x09 /* set file attributes */
+#define SMBread 0x0A /* read from file */
+#define SMBwrite 0x0B /* write to file */
+#define SMBlock 0x0C /* lock byte range */
+#define SMBunlock 0x0D /* unlock byte range */
+#define SMBctemp 0x0E /* create temporary file */
+#define SMBmknew 0x0F /* make new file */
+#define SMBcheckpath 0x10 /* check directory path */
+#define SMBexit 0x11 /* process exit */
+#define SMBlseek 0x12 /* seek */
+#define SMBtcon 0x70 /* tree connect */
+#define SMBtconX 0x75 /* tree connect and X*/
+#define SMBtdis 0x71 /* tree disconnect */
+#define SMBnegprot 0x72 /* negotiate protocol */
+#define SMBdskattr 0x80 /* get disk attributes */
+#define SMBsearch 0x81 /* search directory */
+#define SMBsplopen 0xC0 /* open print spool file */
+#define SMBsplwr 0xC1 /* write to print spool file */
+#define SMBsplclose 0xC2 /* close print spool file */
+#define SMBsplretq 0xC3 /* return print queue */
+#define SMBsends 0xD0 /* send single block message */
+#define SMBsendb 0xD1 /* send broadcast message */
+#define SMBfwdname 0xD2 /* forward user name */
+#define SMBcancelf 0xD3 /* cancel forward */
+#define SMBgetmac 0xD4 /* get machine name */
+#define SMBsendstrt 0xD5 /* send start of multi-block message */
+#define SMBsendend 0xD6 /* send end of multi-block message */
+#define SMBsendtxt 0xD7 /* send text of multi-block message */
+
+/* Core+ protocol */
+#define SMBlockread 0x13 /* Lock a range and read */
+#define SMBwriteunlock 0x14 /* Unlock a range then write */
+#define SMBreadbraw 0x1a /* read a block of data with no smb header */
+#define SMBwritebraw 0x1d /* write a block of data with no smb header */
+#define SMBwritec 0x20 /* secondary write request */
+#define SMBwriteclose 0x2c /* write a file then close it */
+
+/* dos extended protocol */
+#define SMBreadBraw 0x1A /* read block raw */
+#define SMBreadBmpx 0x1B /* read block multiplexed */
+#define SMBreadBs 0x1C /* read block (secondary response) */
+#define SMBwriteBraw 0x1D /* write block raw */
+#define SMBwriteBmpx 0x1E /* write block multiplexed */
+#define SMBwriteBs 0x1F /* write block (secondary request) */
+#define SMBwriteC 0x20 /* write complete response */
+#define SMBsetattrE 0x22 /* set file attributes expanded */
+#define SMBgetattrE 0x23 /* get file attributes expanded */
+#define SMBlockingX 0x24 /* lock/unlock byte ranges and X */
+#define SMBtrans 0x25 /* transaction - name, bytes in/out */
+#define SMBtranss 0x26 /* transaction (secondary request/response) */
+#define SMBioctl 0x27 /* IOCTL */
+#define SMBioctls 0x28 /* IOCTL (secondary request/response) */
+#define SMBcopy 0x29 /* copy */
+#define SMBmove 0x2A /* move */
+#define SMBecho 0x2B /* echo */
+#define SMBopenX 0x2D /* open and X */
+#define SMBreadX 0x2E /* read and X */
+#define SMBwriteX 0x2F /* write and X */
+#define SMBsesssetupX 0x73 /* Session Set Up & X (including User Logon) */
+#define SMBffirst 0x82 /* find first */
+#define SMBfunique 0x83 /* find unique */
+#define SMBfclose 0x84 /* find close */
+#define SMBinvalid 0xFE /* invalid command */
+
+/* Extended 2.0 protocol */
+#define SMBtrans2 0x32 /* TRANS2 protocol set */
+#define SMBtranss2 0x33 /* TRANS2 protocol set, secondary command */
+#define SMBfindclose 0x34 /* Terminate a TRANSACT2_FINDFIRST */
+#define SMBfindnclose 0x35 /* Terminate a TRANSACT2_FINDNOTIFYFIRST */
+#define SMBulogoffX 0x74 /* user logoff */
+
+/* NT SMB extensions. */
+#define SMBnttrans 0xA0 /* NT transact */
+#define SMBnttranss 0xA1 /* NT transact secondary */
+#define SMBntcreateX 0xA2 /* NT create and X */
+#define SMBntcancel 0xA4 /* NT cancel */
+#define SMBntrename 0xA5 /* NT rename */
+
+/* used to indicate end of chain */
+#define SMB_CHAIN_NONE 0xFF
+
+/* Sercurity mode bits. */
+#define NEGOTIATE_SECURITY_USER_LEVEL 0x01
+#define NEGOTIATE_SECURITY_CHALLENGE_RESPONSE 0x02
+#define NEGOTIATE_SECURITY_SIGNATURES_ENABLED 0x04
+#define NEGOTIATE_SECURITY_SIGNATURES_REQUIRED 0x08
+
+/*
+ * The negotiated buffer size for non LARGE_READX/WRITEX
+ * should be limited to uint16_t and has to be at least
+ * 500, which is the default for MinClientBufferSize on Windows.
+ */
+#define SMB_BUFFER_SIZE_MIN 500
+#define SMB_BUFFER_SIZE_MAX 65535
+
+/* Capabilities. see ftp.microsoft.com/developr/drg/cifs/cifs/cifs4.txt */
+
+#define CAP_RAW_MODE 0x00000001
+#define CAP_MPX_MODE 0x00000002
+#define CAP_UNICODE 0x00000004
+#define CAP_LARGE_FILES 0x00000008
+#define CAP_NT_SMBS 0x00000010
+#define CAP_RPC_REMOTE_APIS 0x00000020
+#define CAP_STATUS32 0x00000040
+#define CAP_LEVEL_II_OPLOCKS 0x00000080
+#define CAP_LOCK_AND_READ 0x00000100
+#define CAP_NT_FIND 0x00000200
+#define CAP_DFS 0x00001000
+#define CAP_W2K_SMBS 0x00002000
+#define CAP_LARGE_READX 0x00004000
+#define CAP_LARGE_WRITEX 0x00008000
+#define CAP_LWIO 0x00010000
+#define CAP_UNIX 0x00800000 /* Capabilities for UNIX extensions. Created by HP. */
+#define CAP_DYNAMIC_REAUTH 0x20000000
+#define CAP_EXTENDED_SECURITY 0x80000000
+
+#define SMB_CAP_BOTH_MASK ( \
+ CAP_UNICODE | \
+ CAP_NT_SMBS | \
+ CAP_STATUS32 | \
+ CAP_LEVEL_II_OPLOCKS | \
+ CAP_EXTENDED_SECURITY | \
+ 0)
+#define SMB_CAP_SERVER_MASK ( \
+ CAP_RAW_MODE | \
+ CAP_MPX_MODE | \
+ CAP_LARGE_FILES | \
+ CAP_RPC_REMOTE_APIS | \
+ CAP_LOCK_AND_READ | \
+ CAP_NT_FIND | \
+ CAP_DFS | \
+ CAP_W2K_SMBS | \
+ CAP_LARGE_READX | \
+ CAP_LARGE_WRITEX | \
+ CAP_LWIO | \
+ CAP_UNIX | \
+ 0)
+#define SMB_CAP_CLIENT_MASK ( \
+ CAP_DYNAMIC_REAUTH | \
+ 0)
+/*
+ * Older Samba releases (<= 3.6.x)
+ * expect the client to send CAP_LARGE_READX
+ * in order to let the client use large reads.
+ */
+#define SMB_CAP_LEGACY_CLIENT_MASK ( \
+ SMB_CAP_CLIENT_MASK | \
+ CAP_LARGE_READX | \
+ CAP_LARGE_WRITEX | \
+ 0)
+
+/*
+ * The action flags in the SMB session setup response
+ */
+#define SMB_SETUP_GUEST 0x0001
+#define SMB_SETUP_USE_LANMAN_KEY 0x0002
+
+/* Client-side offline caching policy types */
+enum csc_policy {
+ CSC_POLICY_MANUAL=0,
+ CSC_POLICY_DOCUMENTS=1,
+ CSC_POLICY_PROGRAMS=2,
+ CSC_POLICY_DISABLE=3
+};
+
+/* TCONX Flag (smb_vwv2). [MS-SMB] 2.2.4.7.1 */
+#define TCONX_FLAG_DISCONNECT_TID 0x0001
+#define TCONX_FLAG_EXTENDED_SIGNATURES 0x0004
+#define TCONX_FLAG_EXTENDED_RESPONSE 0x0008
+
+/* this is used on a TConX. [MS-SMB] 2.2.4.7.2 */
+#define SMB_SUPPORT_SEARCH_BITS 0x0001
+#define SMB_SHARE_IN_DFS 0x0002
+#define SMB_CSC_MASK 0x000C
+#define SMB_CSC_POLICY_SHIFT 2
+#define SMB_UNIQUE_FILE_NAME 0x0010
+#define SMB_EXTENDED_SIGNATURES 0x0020
+
+/* NT Flags2 bits - cifs6.txt section 3.1.2 */
+#define FLAGS2_LONG_PATH_COMPONENTS 0x0001
+#define FLAGS2_EXTENDED_ATTRIBUTES 0x0002
+#define FLAGS2_SMB_SECURITY_SIGNATURES 0x0004
+#define FLAGS2_COMPRESSED 0x0008 /* MS-SMB */
+#define FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED 0x0010
+#define FLAGS2_IS_LONG_NAME 0x0040
+#define FLAGS2_REPARSE_PATH 0x0400 /* MS-SMB @GMT- path. */
+#define FLAGS2_EXTENDED_SECURITY 0x0800
+#define FLAGS2_DFS_PATHNAMES 0x1000
+#define FLAGS2_READ_PERMIT_EXECUTE 0x2000
+#define FLAGS2_32_BIT_ERROR_CODES 0x4000
+#define FLAGS2_UNICODE_STRINGS 0x8000
+
+/* FileAttributes (search attributes) field */
+#define FILE_ATTRIBUTE_INVALID 0x0000L
+#define FILE_ATTRIBUTE_READONLY 0x0001L
+#define FILE_ATTRIBUTE_HIDDEN 0x0002L
+#define FILE_ATTRIBUTE_SYSTEM 0x0004L
+#define FILE_ATTRIBUTE_VOLUME 0x0008L
+#define FILE_ATTRIBUTE_DIRECTORY 0x0010L
+#define FILE_ATTRIBUTE_ARCHIVE 0x0020L
+#define FILE_ATTRIBUTE_DEVICE 0x0040L
+#define FILE_ATTRIBUTE_NORMAL 0x0080L
+#define FILE_ATTRIBUTE_TEMPORARY 0x0100L
+#define FILE_ATTRIBUTE_SPARSE 0x0200L
+#define FILE_ATTRIBUTE_REPARSE_POINT 0x0400L
+#define FILE_ATTRIBUTE_COMPRESSED 0x0800L
+#define FILE_ATTRIBUTE_OFFLINE 0x1000L
+#define FILE_ATTRIBUTE_NONINDEXED 0x2000L
+#define FILE_ATTRIBUTE_ENCRYPTED 0x4000L
+#define FILE_ATTRIBUTE_ALL_MASK 0x7FFFL
+
+#define SAMBA_ATTRIBUTES_MASK (FILE_ATTRIBUTE_READONLY|\
+ FILE_ATTRIBUTE_HIDDEN|\
+ FILE_ATTRIBUTE_SYSTEM|\
+ FILE_ATTRIBUTE_DIRECTORY|\
+ FILE_ATTRIBUTE_ARCHIVE|\
+ FILE_ATTRIBUTE_OFFLINE)
+
+/* File type flags */
+#define FILE_TYPE_DISK 0
+#define FILE_TYPE_BYTE_MODE_PIPE 1
+#define FILE_TYPE_MESSAGE_MODE_PIPE 2
+#define FILE_TYPE_PRINTER 3
+#define FILE_TYPE_COMM_DEVICE 4
+#define FILE_TYPE_UNKNOWN 0xFFFF
+
+/* Lock types. */
+#define LOCKING_ANDX_EXCLUSIVE_LOCK 0x00
+#define LOCKING_ANDX_SHARED_LOCK 0x01
+#define LOCKING_ANDX_OPLOCK_RELEASE 0x02
+#define LOCKING_ANDX_CHANGE_LOCKTYPE 0x04
+#define LOCKING_ANDX_CANCEL_LOCK 0x08
+#define LOCKING_ANDX_LARGE_FILES 0x10
+
+/*
+ * Bits we test with.
+ */
+
+#define OPLOCK_NONE 0
+#define OPLOCK_EXCLUSIVE 1
+#define OPLOCK_BATCH 2
+#define OPLOCK_LEVEL_II 4
+
+#define CORE_OPLOCK_GRANTED (1<<5)
+#define EXTENDED_OPLOCK_GRANTED (1<<15)
+
+/*
+ * Return values for oplock types.
+ */
+
+#define NO_OPLOCK_RETURN 0
+#define EXCLUSIVE_OPLOCK_RETURN 1
+#define BATCH_OPLOCK_RETURN 2
+#define LEVEL_II_OPLOCK_RETURN 3
+
+/* oplock levels sent in oplock break */
+#define OPLOCK_BREAK_TO_NONE 0
+#define OPLOCK_BREAK_TO_LEVEL_II 1
+
+/* Filesystem Attributes. */
+#define FILE_CASE_SENSITIVE_SEARCH 0x00000001
+#define FILE_CASE_PRESERVED_NAMES 0x00000002
+#define FILE_UNICODE_ON_DISK 0x00000004
+/* According to cifs9f, this is 4, not 8 */
+/* According to testing, this actually sets the security attribute! */
+#define FILE_PERSISTENT_ACLS 0x00000008
+#define FILE_FILE_COMPRESSION 0x00000010
+#define FILE_VOLUME_QUOTAS 0x00000020
+#define FILE_SUPPORTS_SPARSE_FILES 0x00000040
+#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080
+#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100
+#define FS_LFN_APIS 0x00004000
+#define FILE_VOLUME_IS_COMPRESSED 0x00008000
+#define FILE_SUPPORTS_OBJECT_IDS 0x00010000
+#define FILE_SUPPORTS_ENCRYPTION 0x00020000
+#define FILE_NAMED_STREAMS 0x00040000
+#define FILE_READ_ONLY_VOLUME 0x00080000
+#define FILE_SUPPORTS_BLOCK_REFCOUNTING 0x08000000
+
+/* ShareAccess field. */
+#define FILE_SHARE_NONE 0 /* Cannot be used in bitmask. */
+#define FILE_SHARE_READ 1
+#define FILE_SHARE_WRITE 2
+#define FILE_SHARE_DELETE 4
+
+/* Flags - combined with attributes. */
+#define FILE_FLAG_WRITE_THROUGH 0x80000000L
+#define FILE_FLAG_NO_BUFFERING 0x20000000L
+#define FILE_FLAG_RANDOM_ACCESS 0x10000000L
+#define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000L
+#define FILE_FLAG_DELETE_ON_CLOSE 0x04000000L
+#define FILE_FLAG_BACKUP_SEMANTICS 0x02000000L
+#define FILE_FLAG_POSIX_SEMANTICS 0x01000000L
+
+/* CreateDisposition field. */
+#define FILE_SUPERSEDE 0 /* File exists overwrite/supersede. File not exist create. */
+#define FILE_OPEN 1 /* File exists open. File not exist fail. */
+#define FILE_CREATE 2 /* File exists fail. File not exist create. */
+#define FILE_OPEN_IF 3 /* File exists open. File not exist create. */
+#define FILE_OVERWRITE 4 /* File exists overwrite. File not exist fail. */
+#define FILE_OVERWRITE_IF 5 /* File exists overwrite. File not exist create. */
+
+/* CreateOptions field. */
+#define FILE_DIRECTORY_FILE 0x0001
+#define FILE_WRITE_THROUGH 0x0002
+#define FILE_SEQUENTIAL_ONLY 0x0004
+#define FILE_NO_INTERMEDIATE_BUFFERING 0x0008
+#define FILE_SYNCHRONOUS_IO_ALERT 0x0010 /* may be ignored */
+#define FILE_SYNCHRONOUS_IO_NONALERT 0x0020 /* may be ignored */
+#define FILE_NON_DIRECTORY_FILE 0x0040
+#define FILE_CREATE_TREE_CONNECTION 0x0080 /* ignore, should be zero */
+#define FILE_COMPLETE_IF_OPLOCKED 0x0100 /* ignore, should be zero */
+#define FILE_NO_EA_KNOWLEDGE 0x0200
+#define FILE_EIGHT_DOT_THREE_ONLY 0x0400 /* aka OPEN_FOR_RECOVERY: ignore, should be zero */
+#define FILE_RANDOM_ACCESS 0x0800
+#define FILE_DELETE_ON_CLOSE 0x1000
+#define FILE_OPEN_BY_FILE_ID 0x2000
+#define FILE_OPEN_FOR_BACKUP_INTENT 0x4000
+#define FILE_NO_COMPRESSION 0x8000
+#define FILE_RESERVER_OPFILTER 0x00100000 /* ignore, should be zero */
+#define FILE_OPEN_REPARSE_POINT 0x00200000
+#define FILE_OPEN_NO_RECALL 0x00400000
+#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 /* ignore should be zero */
+
+/* Responses when opening a file. */
+#define FILE_WAS_SUPERSEDED 0
+#define FILE_WAS_OPENED 1
+#define FILE_WAS_CREATED 2
+#define FILE_WAS_OVERWRITTEN 3
+
+/* These are the trans subcommands */
+#define TRANSACT_SETNAMEDPIPEHANDLESTATE 0x01
+#define TRANSACT_DCERPCCMD 0x26
+#define TRANSACT_WAITNAMEDPIPEHANDLESTATE 0x53
+
+/* These are the TRANS2 sub commands */
+#define TRANSACT2_OPEN 0
+#define TRANSACT2_FINDFIRST 1
+#define TRANSACT2_FINDNEXT 2
+#define TRANSACT2_QFSINFO 3
+#define TRANSACT2_SETFSINFO 4
+#define TRANSACT2_QPATHINFO 5
+#define TRANSACT2_SETPATHINFO 6
+#define TRANSACT2_QFILEINFO 7
+#define TRANSACT2_SETFILEINFO 8
+#define TRANSACT2_FSCTL 9
+#define TRANSACT2_IOCTL 0xA
+#define TRANSACT2_FINDNOTIFYFIRST 0xB
+#define TRANSACT2_FINDNOTIFYNEXT 0xC
+#define TRANSACT2_MKDIR 0xD
+#define TRANSACT2_SESSION_SETUP 0xE
+#define TRANSACT2_GET_DFS_REFERRAL 0x10
+#define TRANSACT2_REPORT_DFS_INCONSISTANCY 0x11
+
+/* These are the NT transact sub commands. */
+#define NT_TRANSACT_CREATE 1
+#define NT_TRANSACT_IOCTL 2
+#define NT_TRANSACT_SET_SECURITY_DESC 3
+#define NT_TRANSACT_NOTIFY_CHANGE 4
+#define NT_TRANSACT_RENAME 5
+#define NT_TRANSACT_QUERY_SECURITY_DESC 6
+#define NT_TRANSACT_GET_USER_QUOTA 7
+#define NT_TRANSACT_SET_USER_QUOTA 8
+
+/* ioctl codes */
+#define IOCTL_QUERY_JOB_INFO 0x530060
+
+/* filesystem control codes */
+#define FSCTL_METHOD_BUFFERED 0x00000000
+#define FSCTL_METHOD_IN_DIRECT 0x00000001
+#define FSCTL_METHOD_OUT_DIRECT 0x00000002
+#define FSCTL_METHOD_NEITHER 0x00000003
+
+#define FSCTL_ACCESS_ANY 0x00000000
+#define FSCTL_ACCESS_READ 0x00004000
+#define FSCTL_ACCESS_WRITE 0x00008000
+
+#define IOCTL_DEV_TYPE_MASK 0xFFFF0000
+
+#define FSCTL_DFS 0x00060000
+#define FSCTL_DFS_GET_REFERRALS (FSCTL_DFS | FSCTL_ACCESS_ANY | 0x0194 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_DFS_GET_REFERRALS_EX (FSCTL_DFS | FSCTL_ACCESS_ANY | 0x01B0 | FSCTL_METHOD_BUFFERED)
+
+#define FSCTL_FILESYSTEM 0x00090000
+#define FSCTL_REQUEST_OPLOCK_LEVEL_1 (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0000 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_REQUEST_OPLOCK_LEVEL_2 (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0004 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_REQUEST_BATCH_OPLOCK (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0008 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_OPLOCK_BREAK_ACKNOWLEDGE (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x000C | FSCTL_METHOD_BUFFERED)
+#define FSCTL_OPBATCH_ACK_CLOSE_PENDING (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0010 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_OPLOCK_BREAK_NOTIFY (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0014 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_GET_COMPRESSION (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x003C | FSCTL_METHOD_BUFFERED)
+#define FSCTL_SET_COMPRESSION (FSCTL_FILESYSTEM | FSCTL_ACCESS_READ \
+ | FSCTL_ACCESS_WRITE | 0x0040 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_FILESYS_GET_STATISTICS (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0060 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_GET_NTFS_VOLUME_DATA (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0064 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_IS_VOLUME_DIRTY (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0078 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_FIND_FILES_BY_SID (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x008C | FSCTL_METHOD_NEITHER)
+#define FSCTL_SET_OBJECT_ID (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0098 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_GET_OBJECT_ID (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x009C | FSCTL_METHOD_BUFFERED)
+#define FSCTL_DELETE_OBJECT_ID (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00A0 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_SET_REPARSE_POINT (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00A4 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_GET_REPARSE_POINT (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00A8 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_DELETE_REPARSE_POINT (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00AC | FSCTL_METHOD_BUFFERED)
+#define FSCTL_SET_OBJECT_ID_EXTENDED (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00BC | FSCTL_METHOD_BUFFERED)
+#define FSCTL_CREATE_OR_GET_OBJECT_ID (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00C0 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_SET_SPARSE (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00C4 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_SET_ZERO_DATA (FSCTL_FILESYSTEM | FSCTL_ACCESS_WRITE | 0x00C8 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_SET_ZERO_ON_DEALLOCATION (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0194 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_READ_FILE_USN_DATA (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00EB | FSCTL_METHOD_BUFFERED)
+#define FSCTL_WRITE_USN_CLOSE_RECORD (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00EF | FSCTL_METHOD_BUFFERED)
+#define FSCTL_QUERY_ALLOCATED_RANGES (FSCTL_FILESYSTEM | FSCTL_ACCESS_READ | 0x00CC | FSCTL_METHOD_NEITHER)
+#define FSCTL_QUERY_ON_DISK_VOLUME_INFO (FSCTL_FILESYSTEM | FSCTL_ACCESS_WRITE | 0x013C | FSCTL_METHOD_BUFFERED)
+#define FSCTL_QUERY_SPARING_INFO (FSCTL_FILESYSTEM | FSCTL_ACCESS_WRITE | 0x0138 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_FILE_LEVEL_TRIM (FSCTL_FILESYSTEM | FSCTL_ACCESS_WRITE | 0x0208 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_OFFLOAD_READ (FSCTL_FILESYSTEM | FSCTL_ACCESS_READ | 0x0264 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_OFFLOAD_WRITE (FSCTL_FILESYSTEM | FSCTL_ACCESS_WRITE | 0x0268 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_SET_INTEGRITY_INFORMATION (FSCTL_FILESYSTEM | FSCTL_ACCESS_READ \
+ | FSCTL_ACCESS_WRITE | 0x0280 | FSCTL_METHOD_BUFFERED)
+/* this one is really FSCTL_DUPLICATE_EXTENTS_TO_FILE in the MS docs: */
+#define FSCTL_DUP_EXTENTS_TO_FILE (FSCTL_FILESYSTEM | FSCTL_ACCESS_WRITE | 0x0344 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_DUPLICATE_EXTENTS_TO_FILE_EX (FSCTL_FILESYSTEM | FSCTL_ACCESS_WRITE | 0x03E8 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_STORAGE_QOS_CONTROL (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0350 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_SVHDX_SYNC_TUNNEL_REQUEST (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0304 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_QUERY_SHARED_VIRTUAL_DISK_SUPPORT (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0300 | FSCTL_METHOD_BUFFERED)
+
+#define FSCTL_NAMED_PIPE 0x00110000
+#define FSCTL_PIPE_PEEK (FSCTL_NAMED_PIPE | FSCTL_ACCESS_READ | 0x000C | FSCTL_METHOD_BUFFERED)
+#define FSCTL_NAMED_PIPE_READ_WRITE (FSCTL_NAMED_PIPE | FSCTL_ACCESS_READ \
+ | FSCTL_ACCESS_WRITE | 0x0014 | FSCTL_METHOD_NEITHER)
+#define FSCTL_PIPE_TRANSCEIVE FSCTL_NAMED_PIPE_READ_WRITE /* SMB2 function name */
+#define FSCTL_PIPE_WAIT (FSCTL_NAMED_PIPE | FSCTL_ACCESS_ANY | 0x0018 | FSCTL_METHOD_BUFFERED)
+
+#define FSCTL_NETWORK_FILESYSTEM 0x00140000
+#define FSCTL_GET_SHADOW_COPY_DATA (FSCTL_NETWORK_FILESYSTEM | FSCTL_ACCESS_READ | 0x0064 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_SRV_ENUM_SNAPS FSCTL_GET_SHADOW_COPY_DATA /* SMB2 function name */
+#define FSCTL_SRV_REQUEST_RESUME_KEY (FSCTL_NETWORK_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0078 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_SRV_COPYCHUNK (FSCTL_NETWORK_FILESYSTEM | FSCTL_ACCESS_READ | 0x00F0 | FSCTL_METHOD_OUT_DIRECT)
+#define FSCTL_SRV_COPYCHUNK_WRITE (FSCTL_NETWORK_FILESYSTEM | FSCTL_ACCESS_WRITE | 0x00F0 | FSCTL_METHOD_OUT_DIRECT)
+#define FSCTL_SRV_READ_HASH (FSCTL_NETWORK_FILESYSTEM | FSCTL_ACCESS_READ| 0x01B8 | FSCTL_METHOD_NEITHER)
+#define FSCTL_LMR_REQ_RESILIENCY (FSCTL_NETWORK_FILESYSTEM | FSCTL_ACCESS_ANY | 0x01D4 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_LMR_SET_LINK_TRACKING_INFORMATION \
+ (FSCTL_NETWORK_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00EC | FSCTL_METHOD_BUFFERED)
+#define FSCTL_QUERY_NETWORK_INTERFACE_INFO \
+ (FSCTL_NETWORK_FILESYSTEM | FSCTL_ACCESS_ANY | 0x01FC | FSCTL_METHOD_BUFFERED)
+
+/*
+ * FSCTL_VALIDATE_NEGOTIATE_INFO_224 was used used in
+ * Windows 8 server beta with SMB 2.24
+ */
+#define FSCTL_VALIDATE_NEGOTIATE_INFO_224 \
+ (FSCTL_NETWORK_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0200 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_VALIDATE_NEGOTIATE_INFO (FSCTL_NETWORK_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0204 | FSCTL_METHOD_BUFFERED)
+
+/*
+ * For testing various details we use special codes via
+ * smbtorture in order to test failures
+ */
+#define FSCTL_SMBTORTURE 0x83840000
+#define FSCTL_SMBTORTURE_FORCE_UNACKED_TIMEOUT \
+ (FSCTL_SMBTORTURE | FSCTL_ACCESS_WRITE | 0x0000 | FSCTL_METHOD_NEITHER)
+#define FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8 \
+ (FSCTL_SMBTORTURE | FSCTL_ACCESS_WRITE | 0x0010 | FSCTL_METHOD_NEITHER)
+#define FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8 \
+ (FSCTL_SMBTORTURE | FSCTL_ACCESS_WRITE | 0x0020 | FSCTL_METHOD_NEITHER)
+#define FSCTL_SMBTORTURE_FSP_ASYNC_SLEEP \
+ (FSCTL_SMBTORTURE | FSCTL_ACCESS_WRITE | 0x0040 | FSCTL_METHOD_NEITHER)
+
+/*
+ * A few values from [MS-FSCC] 2.1.2.1 Reparse Tags
+ */
+
+#define IO_REPARSE_TAG_RESERVED_ZERO 0x00000000
+#define IO_REPARSE_TAG_SYMLINK 0xA000000C
+#define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003
+#define IO_REPARSE_TAG_HSM 0xC0000004
+#define IO_REPARSE_TAG_SIS 0x80000007
+#define IO_REPARSE_TAG_DFS 0x8000000A
+#define IO_REPARSE_TAG_NFS 0x80000014
+
+/*
+ * Sub-types for IO_REPARSE_TAG_NFS from [MS-FSCC] 2.1.2.6 Network
+ * File System (NFS) Reparse Data Buffer
+ */
+#define NFS_SPECFILE_LNK 0x00000000014B4E4C
+#define NFS_SPECFILE_CHR 0x0000000000524843
+#define NFS_SPECFILE_BLK 0x00000000004B4C42
+#define NFS_SPECFILE_FIFO 0x000000004F464946
+#define NFS_SPECFILE_SOCK 0x000000004B434F53
+
+/*
+ * Flag from [MS-FSCC] 2.1.2.4 Symbolic Link Reparse Data Buffer
+ */
+#define SYMLINK_FLAG_RELATIVE 0x00000001
+
+/*
+ * Symlink error tag from [MS-SMB2] 2.2.2.2.1 Symbolic Link Error Response
+ */
+#define SYMLINK_ERROR_TAG 0x4C4D5953
+
+/*
+ * Flags according to answer from Dochelp:
+ * https://lists.samba.org/archive/cifs-protocol/2022-November/003909.html
+ */
+#define SYMLINK_ADMIN 0x20000000 /* The symlink creator is an admin */
+#define SYMLINK_UNTRUSTED 0x10000000 /* The symlink creator is untrusted */
+#define SYMLINK_TRUST_UNKNOWN 0x00000000 /* The symlink creator is unknown/legacy */
+
+#define SYMLINK_TRUST_MASK 0x30000000 /* Encodes the redirection trust level (maps to REDIRECTION_TRUST_LEVEL) */
+#define SYMLINK_TRUST_SHIFT 28 /* Bits to shift to convert to/from REDIRECTION_TRUST_LEVEL */
+
+#endif /* _SMB_CONSTANTS_H */
diff --git a/libcli/smb/smb_seal.c b/libcli/smb/smb_seal.c
new file mode 100644
index 0000000..079744c
--- /dev/null
+++ b/libcli/smb/smb_seal.c
@@ -0,0 +1,220 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB Transport encryption (sealing) code.
+ Copyright (C) Jeremy Allison 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 "smb_common.h"
+#ifdef HAVE_KRB5
+#include "lib/krb5_wrap/krb5_samba.h"
+#endif
+#include "auth/gensec/gensec.h"
+#include "libcli/smb/smb_seal.h"
+
+#undef malloc
+
+/******************************************************************************
+ Pull out the encryption context for this packet. 0 means global context.
+******************************************************************************/
+
+NTSTATUS get_enc_ctx_num(const uint8_t *buf, uint16_t *p_enc_ctx_num)
+{
+ if (smb_len_nbt(buf) < 8) {
+ return NT_STATUS_INVALID_BUFFER_SIZE;
+ }
+
+ if (buf[4] == 0xFF) {
+ if (buf[5] == 'S' && buf [6] == 'M' && buf[7] == 'B') {
+ /* Not an encrypted buffer. */
+ return NT_STATUS_NOT_FOUND;
+ }
+ if (buf[5] == 'E') {
+ *p_enc_ctx_num = SVAL(buf,6);
+ return NT_STATUS_OK;
+ }
+ }
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+}
+
+/*******************************************************************
+ Set the length and marker of an encrypted smb packet.
+********************************************************************/
+
+static void smb_set_enclen(char *buf,int len,uint16_t enc_ctx_num)
+{
+ _smb_setlen_tcp(buf,len);
+
+ SCVAL(buf,4,0xFF);
+ SCVAL(buf,5,'E');
+ SSVAL(buf,6,enc_ctx_num);
+}
+
+/******************************************************************************
+ Generic code for client and server.
+ Is encryption turned on ?
+******************************************************************************/
+
+bool common_encryption_on(struct smb_trans_enc_state *es)
+{
+ return ((es != NULL) && es->enc_on);
+}
+
+/******************************************************************************
+ Generic code for client and server.
+ GENSEC decrypt an incoming buffer.
+******************************************************************************/
+
+static NTSTATUS common_gensec_decrypt_buffer(struct gensec_security *gensec,
+ char *buf)
+{
+ NTSTATUS status;
+ size_t buf_len = smb_len_nbt(buf) + 4; /* Don't forget the 4 length bytes. */
+ DATA_BLOB in_buf, out_buf;
+ TALLOC_CTX *frame;
+
+ if (buf_len < 8) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ frame = talloc_stackframe();
+
+ in_buf = data_blob_const(buf + 8, buf_len - 8);
+
+ status = gensec_unwrap(gensec, frame, &in_buf, &out_buf);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("common_gensec_decrypt_buffer: gensec_unwrap failed. Error %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ if (out_buf.length > in_buf.length) {
+ DEBUG(0,("common_gensec_decrypt_buffer: gensec_unwrap size (%u) too large (%u) !\n",
+ (unsigned int)out_buf.length,
+ (unsigned int)in_buf.length ));
+ TALLOC_FREE(frame);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ memcpy(buf + 8, out_buf.data, out_buf.length);
+
+ /* Reset the length and overwrite the header. */
+ smb_setlen_nbt(buf, out_buf.length + 4);
+
+ TALLOC_FREE(frame);
+
+ return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Generic code for client and server.
+ NTLM encrypt an outgoing buffer. Return the encrypted pointer in ppbuf_out.
+******************************************************************************/
+
+static NTSTATUS common_gensec_encrypt_buffer(struct gensec_security *gensec,
+ uint16_t enc_ctx_num,
+ char *buf,
+ char **ppbuf_out)
+{
+ NTSTATUS status;
+ DATA_BLOB in_buf, out_buf;
+ size_t buf_len = smb_len_nbt(buf) + 4; /* Don't forget the 4 length bytes. */
+ TALLOC_CTX *frame;
+
+ *ppbuf_out = NULL;
+
+ if (buf_len < 8) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+ in_buf = data_blob_const(buf + 8, buf_len - 8);
+
+ frame = talloc_stackframe();
+
+ status = gensec_wrap(gensec, frame, &in_buf, &out_buf);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("common_gensec_encrypt_buffer: gensec_wrap failed. Error %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ *ppbuf_out = (char *)malloc(out_buf.length + 8); /* We know this can't wrap. */
+ if (!*ppbuf_out) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ memcpy(*ppbuf_out+8, out_buf.data, out_buf.length);
+ smb_set_enclen(*ppbuf_out, out_buf.length + 4, enc_ctx_num);
+
+ TALLOC_FREE(frame);
+
+ return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Generic code for client and server.
+ Encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
+******************************************************************************/
+
+NTSTATUS common_encrypt_buffer(struct smb_trans_enc_state *es, char *buffer, char **buf_out)
+{
+ if (!common_encryption_on(es)) {
+ /* Not encrypting. */
+ *buf_out = buffer;
+ return NT_STATUS_OK;
+ }
+
+ return common_gensec_encrypt_buffer(es->gensec_security, es->enc_ctx_num, buffer, buf_out);
+}
+
+/******************************************************************************
+ Generic code for client and server.
+ Decrypt an incoming SMB buffer. Replaces the data within it.
+ New data must be less than or equal to the current length.
+******************************************************************************/
+
+NTSTATUS common_decrypt_buffer(struct smb_trans_enc_state *es, char *buf)
+{
+ if (!common_encryption_on(es)) {
+ /* Not decrypting. */
+ return NT_STATUS_OK;
+ }
+
+ return common_gensec_decrypt_buffer(es->gensec_security, buf);
+}
+
+/******************************************************************************
+ Free an encryption-allocated buffer.
+******************************************************************************/
+
+void common_free_enc_buffer(struct smb_trans_enc_state *es, char *buf)
+{
+ uint16_t enc_ctx_num;
+
+ if (!common_encryption_on(es)) {
+ return;
+ }
+
+ if (!NT_STATUS_IS_OK(get_enc_ctx_num((const uint8_t *)buf,
+ &enc_ctx_num))) {
+ return;
+ }
+
+ SAFE_FREE(buf);
+}
diff --git a/libcli/smb/smb_seal.h b/libcli/smb/smb_seal.h
new file mode 100644
index 0000000..f47f904
--- /dev/null
+++ b/libcli/smb/smb_seal.h
@@ -0,0 +1,37 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB Transport encryption code.
+ Copyright (C) Jeremy Allison 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/>.
+*/
+
+#ifndef _HEADER_SMB_CRYPT_H
+#define _HEADER_SMB_CRYPT_H
+
+struct smb_trans_enc_state {
+ uint16_t enc_ctx_num;
+ bool enc_on;
+ struct gensec_security *gensec_security;
+};
+
+/* The following definitions come from smb_seal.c */
+
+NTSTATUS get_enc_ctx_num(const uint8_t *buf, uint16_t *p_enc_ctx_num);
+bool common_encryption_on(struct smb_trans_enc_state *es);
+NTSTATUS common_encrypt_buffer(struct smb_trans_enc_state *es, char *buffer, char **buf_out);
+NTSTATUS common_decrypt_buffer(struct smb_trans_enc_state *es, char *buf);
+void common_free_enc_buffer(struct smb_trans_enc_state *es, char *buf);
+
+#endif /* _HEADER_SMB_CRYPT_H */
diff --git a/libcli/smb/smb_signing.c b/libcli/smb/smb_signing.c
new file mode 100644
index 0000000..d50c963
--- /dev/null
+++ b/libcli/smb/smb_signing.c
@@ -0,0 +1,552 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB Signing Code
+ Copyright (C) Jeremy Allison 2003.
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
+ Copyright (C) Stefan Metzmacher 2009
+
+ 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 "smb_common.h"
+#include "smb_signing.h"
+
+#include "lib/crypto/gnutls_helpers.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+/* Used by the SMB1 signing functions. */
+
+struct smb1_signing_state {
+ /* is signing locally allowed */
+ bool allowed;
+
+ /* is signing locally desired */
+ bool desired;
+
+ /* is signing locally mandatory */
+ bool mandatory;
+
+ /* is signing negotiated by the peer */
+ bool negotiated;
+
+ bool active; /* Have I ever seen a validly signed packet? */
+
+ /* mac_key.length > 0 means signing is started */
+ DATA_BLOB mac_key;
+
+ /* the next expected seqnum */
+ uint32_t seqnum;
+
+ TALLOC_CTX *mem_ctx;
+ void *(*alloc_fn)(TALLOC_CTX *mem_ctx, size_t len);
+ void (*free_fn)(TALLOC_CTX *mem_ctx, void *ptr);
+};
+
+static void smb1_signing_reset_info(struct smb1_signing_state *si)
+{
+ si->active = false;
+ si->seqnum = 0;
+
+ if (si->free_fn) {
+ si->free_fn(si->mem_ctx, si->mac_key.data);
+ } else {
+ talloc_free(si->mac_key.data);
+ }
+ si->mac_key.data = NULL;
+ si->mac_key.length = 0;
+}
+
+struct smb1_signing_state *smb1_signing_init_ex(TALLOC_CTX *mem_ctx,
+ bool allowed,
+ bool desired,
+ bool mandatory,
+ void *(*alloc_fn)(TALLOC_CTX *, size_t),
+ void (*free_fn)(TALLOC_CTX *, void *))
+{
+ struct smb1_signing_state *si;
+
+ if (alloc_fn) {
+ void *p = alloc_fn(mem_ctx, sizeof(struct smb1_signing_state));
+ if (p == NULL) {
+ return NULL;
+ }
+ memset(p, 0, sizeof(struct smb1_signing_state));
+ si = (struct smb1_signing_state *)p;
+ si->mem_ctx = mem_ctx;
+ si->alloc_fn = alloc_fn;
+ si->free_fn = free_fn;
+ } else {
+ si = talloc_zero(mem_ctx, struct smb1_signing_state);
+ if (si == NULL) {
+ return NULL;
+ }
+ }
+
+ if (mandatory) {
+ desired = true;
+ }
+
+ if (desired) {
+ allowed = true;
+ }
+
+ si->allowed = allowed;
+ si->desired = desired;
+ si->mandatory = mandatory;
+
+ return si;
+}
+
+struct smb1_signing_state *smb1_signing_init(TALLOC_CTX *mem_ctx,
+ bool allowed,
+ bool desired,
+ bool mandatory)
+{
+ return smb1_signing_init_ex(mem_ctx, allowed, desired, mandatory,
+ NULL, NULL);
+}
+
+static bool smb1_signing_good(struct smb1_signing_state *si,
+ bool good, uint32_t seq)
+{
+ if (good) {
+ if (!si->active) {
+ si->active = true;
+ }
+ return true;
+ }
+
+ if (!si->mandatory && !si->active) {
+ /* Non-mandatory signing - just turn off if this is the first bad packet.. */
+ DBG_INFO("signing negotiated but not required and peer\n"
+ "isn't sending correct signatures. Turning off.\n");
+ smb1_signing_reset_info(si);
+ return true;
+ }
+
+ /* Mandatory signing or bad packet after signing started - fail and disconnect. */
+ DBG_ERR("BAD SIG: seq %u\n", (unsigned int)seq);
+ return false;
+}
+
+static NTSTATUS smb1_signing_md5(const DATA_BLOB *mac_key,
+ const uint8_t *hdr, size_t len,
+ uint32_t seq_number,
+ uint8_t calc_md5_mac[16])
+{
+ const size_t offset_end_of_sig = (HDR_SS_FIELD + 8);
+ uint8_t sequence_buf[8];
+ gnutls_hash_hd_t hash_hnd = NULL;
+ int rc;
+
+ /*
+ * Firstly put the sequence number into the first 4 bytes.
+ * and zero out the next 4 bytes.
+ *
+ * We do this here, to avoid modifying the packet.
+ */
+
+ DBG_DEBUG("sequence number %u\n", seq_number );
+
+ SIVAL(sequence_buf, 0, seq_number);
+ SIVAL(sequence_buf, 4, 0);
+
+ /*
+ * Calculate the 16 byte MAC - but don't alter the data in the
+ * incoming packet.
+ *
+ * This makes for a bit of fussing about, but it's not too bad.
+ */
+ rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+ /* Initialise with the key. */
+ rc = gnutls_hash(hash_hnd, mac_key->data, mac_key->length);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+ /* Copy in the first bit of the SMB header. */
+ rc = gnutls_hash(hash_hnd, hdr, HDR_SS_FIELD);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+ /* Copy in the sequence number, instead of the signature. */
+ rc = gnutls_hash(hash_hnd, sequence_buf, sizeof(sequence_buf));
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+ /* Copy in the rest of the packet in, skipping the signature. */
+ rc = gnutls_hash(hash_hnd, hdr + offset_end_of_sig, len - offset_end_of_sig);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+
+ gnutls_hash_deinit(hash_hnd, calc_md5_mac);
+
+ return NT_STATUS_OK;
+}
+
+uint32_t smb1_signing_next_seqnum(struct smb1_signing_state *si, bool oneway)
+{
+ uint32_t seqnum;
+
+ if (si->mac_key.length == 0) {
+ return 0;
+ }
+
+ seqnum = si->seqnum;
+ if (oneway) {
+ si->seqnum += 1;
+ } else {
+ si->seqnum += 2;
+ }
+
+ return seqnum;
+}
+
+void smb1_signing_cancel_reply(struct smb1_signing_state *si, bool oneway)
+{
+ if (si->mac_key.length == 0) {
+ return;
+ }
+
+ if (oneway) {
+ si->seqnum -= 1;
+ } else {
+ si->seqnum -= 2;
+ }
+}
+
+NTSTATUS smb1_signing_sign_pdu(struct smb1_signing_state *si,
+ uint8_t *outhdr, size_t len,
+ uint32_t seqnum)
+{
+ uint8_t calc_md5_mac[16];
+ uint8_t com;
+ uint8_t flags;
+
+ if (si->mac_key.length == 0) {
+ if (!si->negotiated) {
+ return NT_STATUS_OK;
+ }
+ }
+
+ /* JRA Paranioa test - we should be able to get rid of this... */
+ if (len < (HDR_SS_FIELD + 8)) {
+ DBG_WARNING("Logic error. "
+ "Can't check signature on short packet! smb_len = %u\n",
+ (unsigned)len);
+ abort();
+ }
+
+ com = SVAL(outhdr, HDR_COM);
+ flags = SVAL(outhdr, HDR_FLG);
+
+ if (!(flags & FLAG_REPLY)) {
+ uint16_t flags2 = SVAL(outhdr, HDR_FLG2);
+ /*
+ * If this is a request, specify what is
+ * supported or required by the client
+ */
+ if (si->negotiated && si->desired) {
+ flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
+ }
+ if (si->negotiated && si->mandatory) {
+ flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED;
+ }
+ SSVAL(outhdr, HDR_FLG2, flags2);
+ }
+
+ if (si->mac_key.length == 0) {
+ /* I wonder what BSRSPYL stands for - but this is what MS
+ actually sends! */
+ if (com == SMBsesssetupX) {
+ memcpy(calc_md5_mac, "BSRSPYL ", 8);
+ } else {
+ memset(calc_md5_mac, 0, 8);
+ }
+ } else {
+ NTSTATUS status;
+
+ status = smb1_signing_md5(&si->mac_key,
+ outhdr,
+ len,
+ seqnum,
+ calc_md5_mac);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ DBG_DEBUG("sent SMB signature of\n");
+ dump_data(10, calc_md5_mac, 8);
+
+ memcpy(&outhdr[HDR_SS_FIELD], calc_md5_mac, 8);
+
+/* outhdr[HDR_SS_FIELD+2]=0;
+ Uncomment this to test if the remote server actually verifies signatures...*/
+
+ return NT_STATUS_OK;
+}
+
+bool smb1_signing_check_pdu(struct smb1_signing_state *si,
+ const uint8_t *inhdr, size_t len,
+ uint32_t seqnum)
+{
+ bool good;
+ uint8_t calc_md5_mac[16];
+ const uint8_t *reply_sent_mac;
+ NTSTATUS status;
+
+ if (si->mac_key.length == 0) {
+ return true;
+ }
+
+ if (len < (HDR_SS_FIELD + 8)) {
+ DBG_WARNING("Can't check signature "
+ "on short packet! smb_len = %u\n",
+ (unsigned)len);
+ return false;
+ }
+
+ status = smb1_signing_md5(&si->mac_key,
+ inhdr,
+ len,
+ seqnum,
+ calc_md5_mac);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("Failed to calculate signing mac: %s\n",
+ nt_errstr(status));
+ return false;
+ }
+
+ reply_sent_mac = &inhdr[HDR_SS_FIELD];
+ good = mem_equal_const_time(reply_sent_mac, calc_md5_mac, 8);
+
+ if (!good) {
+ int i;
+ const int sign_range = 5;
+
+ DBG_INFO("BAD SIG: wanted SMB signature of\n");
+ dump_data(5, calc_md5_mac, 8);
+
+ DBG_INFO("BAD SIG: got SMB signature of\n");
+ dump_data(5, reply_sent_mac, 8);
+
+ for (i = -sign_range; i < sign_range; i++) {
+ smb1_signing_md5(&si->mac_key, inhdr, len,
+ seqnum+i, calc_md5_mac);
+ if (mem_equal_const_time(reply_sent_mac, calc_md5_mac, 8)) {
+ DBG_ERR("out of seq. seq num %u matches. "
+ "We were expecting seq %u\n",
+ (unsigned int)seqnum+i,
+ (unsigned int)seqnum);
+ break;
+ }
+ }
+ } else {
+ DBG_DEBUG("seq %u: got good SMB signature of\n",
+ (unsigned int)seqnum);
+ dump_data(10, reply_sent_mac, 8);
+ }
+
+ return smb1_signing_good(si, good, seqnum);
+}
+
+bool smb1_signing_activate(struct smb1_signing_state *si,
+ const DATA_BLOB user_session_key,
+ const DATA_BLOB response)
+{
+ size_t len;
+ off_t ofs;
+
+ if (!user_session_key.length) {
+ return false;
+ }
+
+ if (!si->negotiated) {
+ return false;
+ }
+
+ if (si->active) {
+ return false;
+ }
+
+ if (si->mac_key.length > 0) {
+ return false;
+ }
+
+ smb1_signing_reset_info(si);
+
+ len = response.length + user_session_key.length;
+ if (si->alloc_fn) {
+ si->mac_key.data = (uint8_t *)si->alloc_fn(si->mem_ctx, len);
+ if (si->mac_key.data == NULL) {
+ return false;
+ }
+ } else {
+ si->mac_key.data = (uint8_t *)talloc_size(si, len);
+ if (si->mac_key.data == NULL) {
+ return false;
+ }
+ }
+ si->mac_key.length = len;
+
+ ofs = 0;
+ memcpy(&si->mac_key.data[ofs], user_session_key.data, user_session_key.length);
+
+ DBG_DEBUG("user_session_key\n");
+ dump_data(10, user_session_key.data, user_session_key.length);
+
+ if (response.length) {
+ ofs = user_session_key.length;
+ memcpy(&si->mac_key.data[ofs], response.data, response.length);
+ DBG_DEBUG("response_data\n");
+ dump_data(10, response.data, response.length);
+ } else {
+ DBG_DEBUG("NULL response_data\n");
+ }
+
+ dump_data_pw("smb1_signing_activate: mac key is:\n",
+ si->mac_key.data, si->mac_key.length);
+
+ /* Initialise the sequence number */
+ si->seqnum = 2;
+
+ return true;
+}
+
+bool smb1_signing_is_active(struct smb1_signing_state *si)
+{
+ return si->active;
+}
+
+bool smb1_signing_is_desired(struct smb1_signing_state *si)
+{
+ return si->desired;
+}
+
+bool smb1_signing_is_mandatory(struct smb1_signing_state *si)
+{
+ return si->mandatory;
+}
+
+bool smb1_signing_set_negotiated(struct smb1_signing_state *si,
+ bool allowed, bool mandatory)
+{
+ if (si->active) {
+ return true;
+ }
+
+ if (mandatory) {
+ allowed = true;
+ }
+
+ if (!si->allowed && mandatory) {
+ return false;
+ }
+
+ if (si->mandatory && !allowed) {
+ return false;
+ }
+
+ if (si->mandatory) {
+ si->negotiated = true;
+ return true;
+ }
+
+ if (mandatory) {
+ si->negotiated = true;
+ return true;
+ }
+
+ if (!si->desired) {
+ si->negotiated = false;
+ return true;
+ }
+
+ if (si->desired && allowed) {
+ si->negotiated = true;
+ return true;
+ }
+
+ si->negotiated = false;
+ return true;
+}
+
+bool smb1_signing_is_negotiated(struct smb1_signing_state *si)
+{
+ return si->negotiated;
+}
+
+NTSTATUS smb1_key_derivation(const uint8_t *KI,
+ size_t KI_len,
+ uint8_t KO[16])
+{
+ int rc;
+ static const uint8_t SSKeyHash[256] = {
+ 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79,
+ 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75,
+ 0x72, 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x55,
+ 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x79, 0x07,
+ 0x6e, 0x28, 0x2e, 0x69, 0x88, 0x10, 0xb3, 0xdb,
+ 0x01, 0x55, 0x72, 0xfb, 0x74, 0x14, 0xfb, 0xc4,
+ 0xc5, 0xaf, 0x3b, 0x41, 0x65, 0x32, 0x17, 0xba,
+ 0xa3, 0x29, 0x08, 0xc1, 0xde, 0x16, 0x61, 0x7e,
+ 0x66, 0x98, 0xa4, 0x0b, 0xfe, 0x06, 0x83, 0x53,
+ 0x4d, 0x05, 0xdf, 0x6d, 0xa7, 0x51, 0x10, 0x73,
+ 0xc5, 0x50, 0xdc, 0x5e, 0xf8, 0x21, 0x46, 0xaa,
+ 0x96, 0x14, 0x33, 0xd7, 0x52, 0xeb, 0xaf, 0x1f,
+ 0xbf, 0x36, 0x6c, 0xfc, 0xb7, 0x1d, 0x21, 0x19,
+ 0x81, 0xd0, 0x6b, 0xfa, 0x77, 0xad, 0xbe, 0x18,
+ 0x78, 0xcf, 0x10, 0xbd, 0xd8, 0x78, 0xf7, 0xd3,
+ 0xc6, 0xdf, 0x43, 0x32, 0x19, 0xd3, 0x9b, 0xa8,
+ 0x4d, 0x9e, 0xaa, 0x41, 0xaf, 0xcb, 0xc6, 0xb9,
+ 0x34, 0xe7, 0x48, 0x25, 0xd4, 0x88, 0xc4, 0x51,
+ 0x60, 0x38, 0xd9, 0x62, 0xe8, 0x8d, 0x5b, 0x83,
+ 0x92, 0x7f, 0xb5, 0x0e, 0x1c, 0x2d, 0x06, 0x91,
+ 0xc3, 0x75, 0xb3, 0xcc, 0xf8, 0xf7, 0x92, 0x91,
+ 0x0b, 0x3d, 0xa1, 0x10, 0x5b, 0xd5, 0x0f, 0xa8,
+ 0x3f, 0x5d, 0x13, 0x83, 0x0a, 0x6b, 0x72, 0x93,
+ 0x14, 0x59, 0xd5, 0xab, 0xde, 0x26, 0x15, 0x6d,
+ 0x60, 0x67, 0x71, 0x06, 0x6e, 0x3d, 0x0d, 0xa7,
+ 0xcb, 0x70, 0xe9, 0x08, 0x5c, 0x99, 0xfa, 0x0a,
+ 0x5f, 0x3d, 0x44, 0xa3, 0x8b, 0xc0, 0x8d, 0xda,
+ 0xe2, 0x68, 0xd0, 0x0d, 0xcd, 0x7f, 0x3d, 0xf8,
+ 0x73, 0x7e, 0x35, 0x7f, 0x07, 0x02, 0x0a, 0xb5,
+ 0xe9, 0xb7, 0x87, 0xfb, 0xa1, 0xbf, 0xcb, 0x32,
+ 0x31, 0x66, 0x09, 0x48, 0x88, 0xcc, 0x18, 0xa3,
+ 0xb2, 0x1f, 0x1f, 0x1b, 0x90, 0x4e, 0xd7, 0xe1
+ };
+
+ /* The callers passing down KI_len of 16 so no need to limit to 64 */
+ rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
+ KI,
+ KI_len,
+ SSKeyHash,
+ sizeof(SSKeyHash),
+ KO);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/libcli/smb/smb_signing.h b/libcli/smb/smb_signing.h
new file mode 100644
index 0000000..9f2f3c1
--- /dev/null
+++ b/libcli/smb/smb_signing.h
@@ -0,0 +1,58 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB Signing Code
+ Copyright (C) Jeremy Allison 2003.
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
+ Copyright (C) Stefan Metzmacher 2009
+
+ 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/>.
+*/
+
+#ifndef _SMB_SIGNING_H_
+#define _SMB_SIGNING_H_
+
+struct smb1_signing_state;
+
+struct smb1_signing_state *smb1_signing_init(TALLOC_CTX *mem_ctx,
+ bool allowed,
+ bool desired,
+ bool mandatory);
+struct smb1_signing_state *smb1_signing_init_ex(TALLOC_CTX *mem_ctx,
+ bool allowed,
+ bool desired,
+ bool mandatory,
+ void *(*alloc_fn)(TALLOC_CTX *, size_t),
+ void (*free_fn)(TALLOC_CTX *, void *));
+uint32_t smb1_signing_next_seqnum(struct smb1_signing_state *si, bool oneway);
+void smb1_signing_cancel_reply(struct smb1_signing_state *si, bool oneway);
+NTSTATUS smb1_signing_sign_pdu(struct smb1_signing_state *si,
+ uint8_t *outhdr, size_t len,
+ uint32_t seqnum);
+bool smb1_signing_check_pdu(struct smb1_signing_state *si,
+ const uint8_t *inhdr, size_t len,
+ uint32_t seqnum);
+bool smb1_signing_activate(struct smb1_signing_state *si,
+ const DATA_BLOB user_session_key,
+ const DATA_BLOB response);
+bool smb1_signing_is_active(struct smb1_signing_state *si);
+bool smb1_signing_is_desired(struct smb1_signing_state *si);
+bool smb1_signing_is_mandatory(struct smb1_signing_state *si);
+bool smb1_signing_set_negotiated(struct smb1_signing_state *si,
+ bool allowed, bool mandatory);
+bool smb1_signing_is_negotiated(struct smb1_signing_state *si);
+NTSTATUS smb1_key_derivation(const uint8_t *KI,
+ size_t KI_len,
+ uint8_t KO[16]);
+
+#endif /* _SMB_SIGNING_H_ */
diff --git a/libcli/smb/smb_unix_ext.h b/libcli/smb/smb_unix_ext.h
new file mode 100644
index 0000000..2f2357d
--- /dev/null
+++ b/libcli/smb/smb_unix_ext.h
@@ -0,0 +1,458 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB transaction2 handling
+
+ Copyright (C) James Peach 2007
+ Copyright (C) Jeremy Allison 1994-2002.
+
+ Extensively modified by Andrew Tridgell, 1995
+
+ 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/>.
+*/
+
+#ifndef __SMB_UNIX_EXT_H__
+#define __SMB_UNIX_EXT_H__
+
+/* UNIX CIFS Extensions - created by HP */
+/*
+ * UNIX CIFS Extensions have the range 0x200 - 0x2FF reserved.
+ * Supposedly Microsoft have agreed to this.
+ */
+
+#define MIN_UNIX_INFO_LEVEL 0x200
+#define MAX_UNIX_INFO_LEVEL 0x2FF
+
+#define SMB_QUERY_FILE_UNIX_BASIC 0x200 /* UNIX File Info*/
+#define SMB_SET_FILE_UNIX_BASIC 0x200
+#define SMB_SET_FILE_UNIX_INFO2 0x20B /* UNIX File Info2 */
+
+#define SMB_MODE_NO_CHANGE 0xFFFFFFFF /* file mode value which */
+ /* means "don't change it" */
+#define SMB_UID_NO_CHANGE 0xFFFFFFFF
+#define SMB_GID_NO_CHANGE 0xFFFFFFFF
+
+#define SMB_SIZE_NO_CHANGE_LO 0xFFFFFFFF
+#define SMB_SIZE_NO_CHANGE_HI 0xFFFFFFFF
+
+#define SMB_TIME_NO_CHANGE_LO 0xFFFFFFFF
+#define SMB_TIME_NO_CHANGE_HI 0xFFFFFFFF
+
+/*
+Offset Size Name
+0 LARGE_INTEGER EndOfFile File size
+8 LARGE_INTEGER Blocks Number of bytes used on disk (st_blocks).
+16 LARGE_INTEGER CreationTime Creation time
+24 LARGE_INTEGER LastAccessTime Last access time
+32 LARGE_INTEGER LastModificationTime Last modification time
+40 LARGE_INTEGER Uid Numeric user id for the owner
+48 LARGE_INTEGER Gid Numeric group id of owner
+56 ULONG Type Enumeration specifying the pathname type:
+ 0 -- File
+ 1 -- Directory
+ 2 -- Symbolic link
+ 3 -- Character device
+ 4 -- Block device
+ 5 -- FIFO (named pipe)
+ 6 -- Unix domain socket
+
+60 LARGE_INTEGER devmajor Major device number if type is device
+68 LARGE_INTEGER devminor Minor device number if type is device
+76 LARGE_INTEGER uniqueid This is a server-assigned unique id for the file. The client
+ will typically map this onto an inode number. The scope of
+ uniqueness is the share.
+84 LARGE_INTEGER permissions Standard UNIX file permissions - see below.
+92 LARGE_INTEGER nlinks The number of directory entries that map to this entry
+ (number of hard links)
+
+100 - end.
+*/
+
+#define SMB_FILE_UNIX_BASIC_SIZE 100
+
+/* UNIX filetype mappings. */
+
+#define UNIX_TYPE_FILE 0
+#define UNIX_TYPE_DIR 1
+#define UNIX_TYPE_SYMLINK 2
+#define UNIX_TYPE_CHARDEV 3
+#define UNIX_TYPE_BLKDEV 4
+#define UNIX_TYPE_FIFO 5
+#define UNIX_TYPE_SOCKET 6
+#define UNIX_TYPE_UNKNOWN 0xFFFFFFFF
+
+/*
+ * Oh this is fun. "Standard UNIX permissions" has no
+ * meaning in POSIX. We need to define the mapping onto
+ * and off the wire as this was not done in the original HP
+ * spec. JRA.
+ */
+
+#define UNIX_X_OTH 0000001
+#define UNIX_W_OTH 0000002
+#define UNIX_R_OTH 0000004
+#define UNIX_X_GRP 0000010
+#define UNIX_W_GRP 0000020
+#define UNIX_R_GRP 0000040
+#define UNIX_X_USR 0000100
+#define UNIX_W_USR 0000200
+#define UNIX_R_USR 0000400
+#define UNIX_STICKY 0001000
+#define UNIX_SET_GID 0002000
+#define UNIX_SET_UID 0004000
+
+/* Masks for the above */
+#define UNIX_OTH_MASK 0000007
+#define UNIX_GRP_MASK 0000070
+#define UNIX_USR_MASK 0000700
+#define UNIX_PERM_MASK 0000777
+#define UNIX_EXTRA_MASK 0007000
+#define UNIX_ALL_MASK 0007777
+
+/* Flags for chflags (CIFS_UNIX_EXTATTR_CAP capability) and
+ * SMB_QUERY_FILE_UNIX_INFO2.
+ */
+#define EXT_SECURE_DELETE 0x00000001
+#define EXT_ENABLE_UNDELETE 0x00000002
+#define EXT_SYNCHRONOUS 0x00000004
+#define EXT_IMMUTABLE 0x00000008
+#define EXT_OPEN_APPEND_ONLY 0x00000010
+#define EXT_DO_NOT_BACKUP 0x00000020
+#define EXT_NO_UPDATE_ATIME 0x00000040
+#define EXT_HIDDEN 0x00000080
+
+#define SMB_QUERY_FILE_UNIX_LINK 0x201
+#define SMB_SET_FILE_UNIX_LINK 0x201
+#define SMB_SET_FILE_UNIX_HLINK 0x203
+/* SMB_QUERY_POSIX_ACL 0x204 see below */
+#define SMB_QUERY_XATTR 0x205 /* need for non-user XATTRs */
+#define SMB_QUERY_ATTR_FLAGS 0x206 /* chflags, chattr */
+#define SMB_SET_ATTR_FLAGS 0x206
+#define SMB_QUERY_POSIX_PERMISSION 0x207
+/* Only valid for qfileinfo */
+#define SMB_QUERY_POSIX_LOCK 0x208
+/* Only valid for setfileinfo */
+#define SMB_SET_POSIX_LOCK 0x208
+
+/* The set info levels for POSIX path operations. */
+#define SMB_POSIX_PATH_OPEN 0x209
+#define SMB_POSIX_PATH_UNLINK 0x20A
+
+#define SMB_QUERY_FILE_UNIX_INFO2 0x20B /* UNIX File Info2 */
+#define SMB_SET_FILE_UNIX_INFO2 0x20B
+
+/*
+SMB_QUERY_FILE_UNIX_INFO2 is SMB_QUERY_FILE_UNIX_BASIC with create
+time and file flags appended. The corresponding info level for
+findfirst/findnext is SMB_FIND_FILE_UNIX_INFO2.
+ Size Offset Value
+ ---------------------
+ 0 LARGE_INTEGER EndOfFile File size
+ 8 LARGE_INTEGER Blocks Number of blocks used on disk
+ 16 LARGE_INTEGER ChangeTime Attribute change time
+ 24 LARGE_INTEGER LastAccessTime Last access time
+ 32 LARGE_INTEGER LastModificationTime Last modification time
+ 40 LARGE_INTEGER Uid Numeric user id for the owner
+ 48 LARGE_INTEGER Gid Numeric group id of owner
+ 56 ULONG Type Enumeration specifying the file type
+ 60 LARGE_INTEGER devmajor Major device number if type is device
+ 68 LARGE_INTEGER devminor Minor device number if type is device
+ 76 LARGE_INTEGER uniqueid This is a server-assigned unique id
+ 84 LARGE_INTEGER permissions Standard UNIX permissions
+ 92 LARGE_INTEGER nlinks Number of hard links
+ 100 LARGE_INTEGER CreationTime Create/birth time
+ 108 ULONG FileFlags File flags enumeration
+ 112 ULONG FileFlagsMask Mask of valid flags
+*/
+
+/* Transact 2 Find First levels */
+#define SMB_FIND_FILE_UNIX 0x202
+#define SMB_FIND_FILE_UNIX_INFO2 0x20B /* UNIX File Info2 */
+
+#define SMB_FILE_UNIX_INFO2_SIZE 116
+
+/*
+ Info level for TRANS2_QFSINFO - returns version of CIFS UNIX extensions, plus
+ 64-bits worth of capability fun :-).
+ Use the same info level for TRANS2_SETFSINFO
+*/
+
+#define SMB_QUERY_CIFS_UNIX_INFO 0x200
+#define SMB_SET_CIFS_UNIX_INFO 0x200
+
+/* Returns or sets the following.
+
+ UINT16 major version number
+ UINT16 minor version number
+ LARGE_INTEGER capability bitfield
+
+*/
+
+#define CIFS_UNIX_MAJOR_VERSION 1
+#define CIFS_UNIX_MINOR_VERSION 0
+
+#define CIFS_UNIX_FCNTL_LOCKS_CAP 0x1
+#define CIFS_UNIX_POSIX_ACLS_CAP 0x2
+#define CIFS_UNIX_XATTTR_CAP 0x4 /* for support of other xattr
+ namespaces such as system,
+ security and trusted */
+#define CIFS_UNIX_EXTATTR_CAP 0x8 /* for support of chattr
+ (chflags) and lsattr */
+#define CIFS_UNIX_POSIX_PATHNAMES_CAP 0x10 /* Use POSIX pathnames on the wire. */
+#define CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP 0x20 /* We can cope with POSIX open/mkdir/unlink etc. */
+#define CIFS_UNIX_LARGE_READ_CAP 0x40 /* We can cope with 24 bit reads in readX. */
+#define CIFS_UNIX_LARGE_WRITE_CAP 0x80 /* We can cope with 24 bit writes in writeX. */
+#define CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP 0x100 /* We can do SPNEGO negotiations for encryption. */
+#define CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP 0x200 /* We *must* SPNEGO negotiations for encryption. */
+
+#define SMB_QUERY_POSIX_FS_INFO 0x201
+
+/* Returns FILE_SYSTEM_POSIX_INFO struct as follows
+ (NB For undefined values return -1 in that field)
+ le32 OptimalTransferSize; bsize on some os, iosize on other os, This
+ is a hint to the client about best size. Server
+ can return -1 if no preference, ie if SMB
+ negotiated size is adequate for optimal
+ read/write performance
+ le32 BlockSize; (often 512 bytes) NB: BlockSize * TotalBlocks = disk space
+ le64 TotalBlocks; redundant with other infolevels but easy to ret here
+ le64 BlocksAvail; although redundant, easy to return
+ le64 UserBlocksAvail; bavail
+ le64 TotalFileNodes;
+ le64 FreeFileNodes;
+ le64 FileSysIdentifier; fsid
+ (NB statfs field Namelen comes from FILE_SYSTEM_ATTRIBUTE_INFO call)
+ (NB statfs field flags can come from FILE_SYSTEM_DEVICE_INFO call)
+*/
+
+#define SMB_QUERY_POSIX_WHO_AM_I 0x202 /* QFS Info */
+/* returns:
+ __u32 flags; 0 = Authenticated user 1 = GUEST
+ __u32 mask; which flags bits server understands ie 0x0001
+ __u64 unix_user_id;
+ __u64 unix_user_gid;
+ __u32 number_of_supplementary_gids; may be zero
+ __u32 number_of_sids; may be zero
+ __u32 length_of_sid_array; in bytes - may be zero
+ __u32 pad; reserved - MBZ
+ __u64 gid_array[0]; may be empty
+ __u8 * psid_list may be empty
+*/
+
+/* ... more as we think of them :-). */
+
+/* SMB POSIX ACL definitions. */
+/* Wire format is (all little endian) :
+
+[2 bytes] - Version number.
+[2 bytes] - Number of ACE entries to follow.
+[2 bytes] - Number of default ACE entries to follow.
+-------------------------------------
+^
+|
+ACE entries
+|
+v
+-------------------------------------
+^
+|
+Default ACE entries
+|
+v
+-------------------------------------
+
+Where an ACE entry looks like :
+
+[1 byte] - Entry type.
+
+Entry types are :
+
+ACL_USER_OBJ 0x01
+ACL_USER 0x02
+ACL_GROUP_OBJ 0x04
+ACL_GROUP 0x08
+ACL_MASK 0x10
+ACL_OTHER 0x20
+
+[1 byte] - permissions (perm_t)
+
+perm_t types are :
+
+ACL_READ 0x04
+ACL_WRITE 0x02
+ACL_EXECUTE 0x01
+
+[8 bytes] - uid/gid to apply this permission to.
+
+In the same format as the uid/gid fields in the other
+UNIX extensions definitions. Use 0xFFFFFFFFFFFFFFFF for
+the MASK and OTHER entry types.
+
+If the Number of ACE entries for either file or default ACE's
+is set to 0xFFFF this means ignore this kind of ACE (and the
+number of entries sent will be zero.
+
+*/
+
+#define SMB_QUERY_POSIX_WHOAMI 0x202
+
+enum smb_whoami_flags {
+ SMB_WHOAMI_GUEST = 0x1 /* Logged in as (or squashed to) guest */
+};
+
+/* Mask of which WHOAMI bits are valid. This should make it easier for clients
+ * to cope with servers that have different sets of WHOAMI flags (as more get
+ * added).
+ */
+#define SMB_WHOAMI_MASK 0x00000001
+
+/*
+ SMBWhoami - Query the user mapping performed by the server for the
+ connected tree. This is a subcommand of the TRANS2_QFSINFO.
+
+ Returns:
+ 4 bytes unsigned - mapping flags (smb_whoami_flags)
+ 4 bytes unsigned - flags mask
+
+ 8 bytes unsigned - primary UID
+ 8 bytes unsigned - primary GID
+ 4 bytes unsigned - number of supplementary GIDs
+ 4 bytes unsigned - number of SIDs
+ 4 bytes unsigned - SID list byte count
+ 4 bytes - pad / reserved (must be zero)
+
+ 8 bytes unsigned[] - list of GIDs (may be empty)
+ struct dom_sid[] - list of SIDs (may be empty)
+*/
+
+/*
+ * The following trans2 is done between client and server
+ * as a FSINFO call to set up the encryption state for transport
+ * encryption.
+ * This is a subcommand of the TRANS2_QFSINFO.
+ *
+ * The request looks like :
+ *
+ * [data block] -> SPNEGO framed GSSAPI request.
+ *
+ * The reply looks like :
+ *
+ * [data block] -> SPNEGO framed GSSAPI reply - if error
+ * is NT_STATUS_OK then we're done, if it's
+ * NT_STATUS_MORE_PROCESSING_REQUIRED then the
+ * client needs to keep going. If it's an
+ * error it can be any NT_STATUS error.
+ *
+ */
+
+#define SMB_REQUEST_TRANSPORT_ENCRYPTION 0x203 /* QFSINFO */
+#define SMB_ENCRYPTION_GSSAPI 0x8000
+
+/* The query/set info levels for POSIX ACLs. */
+#define SMB_QUERY_POSIX_ACL 0x204
+#define SMB_SET_POSIX_ACL 0x204
+
+/* Current on the wire ACL version. */
+#define SMB_POSIX_ACL_VERSION 1
+
+/* ACE entry type. */
+#define SMB_POSIX_ACL_USER_OBJ 0x01
+#define SMB_POSIX_ACL_USER 0x02
+#define SMB_POSIX_ACL_GROUP_OBJ 0x04
+#define SMB_POSIX_ACL_GROUP 0x08
+#define SMB_POSIX_ACL_MASK 0x10
+#define SMB_POSIX_ACL_OTHER 0x20
+
+/* perm_t types. */
+#define SMB_POSIX_ACL_READ 0x04
+#define SMB_POSIX_ACL_WRITE 0x02
+#define SMB_POSIX_ACL_EXECUTE 0x01
+
+#define SMB_POSIX_ACL_HEADER_SIZE 6
+#define SMB_POSIX_ACL_ENTRY_SIZE 10
+
+#define SMB_POSIX_IGNORE_ACE_ENTRIES 0xFFFF
+
+/* Definition of data block of SMB_SET_POSIX_LOCK */
+/*
+ [2 bytes] lock_type - 0 = Read, 1 = Write, 2 = Unlock
+ [2 bytes] lock_flags - 1 = Wait (only valid for setlock)
+ [4 bytes] pid = locking context.
+ [8 bytes] start = unsigned 64 bits.
+ [8 bytes] length = unsigned 64 bits.
+*/
+
+#define POSIX_LOCK_TYPE_OFFSET 0
+#define POSIX_LOCK_FLAGS_OFFSET 2
+#define POSIX_LOCK_PID_OFFSET 4
+#define POSIX_LOCK_START_OFFSET 8
+#define POSIX_LOCK_LEN_OFFSET 16
+#define POSIX_LOCK_DATA_SIZE 24
+
+#define POSIX_LOCK_FLAG_NOWAIT 0
+#define POSIX_LOCK_FLAG_WAIT 1
+
+#define POSIX_LOCK_TYPE_READ 0
+#define POSIX_LOCK_TYPE_WRITE 1
+#define POSIX_LOCK_TYPE_UNLOCK 2
+
+/* SMB_POSIX_PATH_OPEN "open_mode" definitions. */
+#define SMB_O_RDONLY 0x1
+#define SMB_O_WRONLY 0x2
+#define SMB_O_RDWR 0x4
+
+#define SMB_ACCMODE 0x7
+
+#define SMB_O_CREAT 0x10
+#define SMB_O_EXCL 0x20
+#define SMB_O_TRUNC 0x40
+#define SMB_O_APPEND 0x80
+#define SMB_O_SYNC 0x100
+#define SMB_O_DIRECTORY 0x200
+#define SMB_O_NOFOLLOW 0x400
+#define SMB_O_DIRECT 0x800
+
+/* Definition of request data block for SMB_POSIX_PATH_OPEN */
+/*
+ [4 bytes] flags (as smb_ntcreate_Flags).
+ [4 bytes] open_mode - SMB_O_xxx flags above.
+ [8 bytes] mode_t (permissions) - same encoding as "Standard UNIX permissions" above in SMB_SET_FILE_UNIX_BASIC.
+ [2 bytes] ret_info_level - optimization. Info level to be returned.
+*/
+
+/* Definition of reply data block for SMB_POSIX_PATH_OPEN */
+
+#define SMB_NO_INFO_LEVEL_RETURNED 0xFFFF
+
+/*
+ [2 bytes] - flags field. Identical to flags reply for oplock response field in SMBNTCreateX)
+ [2 bytes] - FID returned.
+ [4 bytes] - CreateAction (same as in NTCreateX response).
+ [2 bytes] - reply info level - as requested or 0xFFFF if not available.
+ [2 bytes] - padding (must be zero)
+ [n bytes] - info level reply - if available.
+*/
+
+/* Definition of request data block for SMB_POSIX_UNLINK */
+/*
+ [2 bytes] flags (defined below).
+*/
+
+#define SMB_POSIX_UNLINK_FILE_TARGET 0
+#define SMB_POSIX_UNLINK_DIRECTORY_TARGET 1
+
+#define INFO_LEVEL_IS_UNIX(level) ((((level) >= MIN_UNIX_INFO_LEVEL) && \
+ ((level) <= MAX_UNIX_INFO_LEVEL)) || \
+ ((level) == SMB2_FILE_POSIX_INFORMATION_INTERNAL))
+
+#endif /* __SMB_UNIX_EXT_H__ */
diff --git a/libcli/smb/smb_util.h b/libcli/smb/smb_util.h
new file mode 100644
index 0000000..f2cc0fb
--- /dev/null
+++ b/libcli/smb/smb_util.h
@@ -0,0 +1,57 @@
+/*
+ Unix SMB/CIFS implementation.
+ client file operations
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Jeremy Allison 2001-2002
+ Copyright (C) James Myers 2003
+
+ 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 "replace.h"
+#include "system/filesys.h"
+#include "smb_constants.h"
+#include <talloc.h>
+#include "libcli/util/ntstatus.h"
+
+#ifndef _SMB_UTIL_H
+#define _SMB_UTIL_H
+
+const char *smb_protocol_types_string(enum protocol_types protocol);
+char *attrib_string(TALLOC_CTX *mem_ctx, uint32_t attrib);
+uint32_t unix_perms_to_wire(mode_t perms);
+mode_t wire_perms_to_unix(uint32_t perms);
+mode_t unix_filetype_from_wire(uint32_t wire_type);
+
+bool smb_buffer_oob(uint32_t bufsize, uint32_t offset, uint32_t length);
+
+uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2,
+ const char *str, size_t str_len,
+ size_t *pconverted_size);
+uint8_t *smb_bytes_push_bytes(uint8_t *buf, uint8_t prefix,
+ const uint8_t *bytes, size_t num_bytes);
+uint8_t *trans2_bytes_push_str(uint8_t *buf, bool ucs2,
+ const char *str, size_t str_len,
+ size_t *pconverted_size);
+uint8_t *trans2_bytes_push_bytes(uint8_t *buf,
+ const uint8_t *bytes, size_t num_bytes);
+NTSTATUS smb_bytes_pull_str(TALLOC_CTX *mem_ctx, char **_str, bool ucs2,
+ const uint8_t *buf, size_t buf_len,
+ const uint8_t *position,
+ size_t *_consumed);
+
+enum smb_signing_setting smb_signing_setting_translate(const char *str);
+enum smb_encryption_setting smb_encryption_setting_translate(const char *str);
+
+#endif /* _SMB_UTIL_H */
diff --git a/libcli/smb/test_smb1cli_session.c b/libcli/smb/test_smb1cli_session.c
new file mode 100644
index 0000000..6a526c9
--- /dev/null
+++ b/libcli/smb/test_smb1cli_session.c
@@ -0,0 +1,216 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "replace.h"
+#include <talloc.h>
+#include "libcli/util/ntstatus.h"
+#include "smb_constants.h"
+#include "smb_util.h"
+
+static const uint8_t smb1_session_setup_bytes[] = {
+ 0xA1, 0x82, 0x01, 0x02, 0x30, 0x81, 0xFF, 0xA0,
+ 0x03, 0x0A, 0x01, 0x01, 0xA1, 0x0C, 0x06, 0x0A,
+ 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02,
+ 0x02, 0x0A, 0xA2, 0x81, 0xE9, 0x04, 0x81, 0xE6,
+ 0x4E, 0x54, 0x4C, 0x4D, 0x53, 0x53, 0x50, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x15, 0x82, 0x89, 0x62,
+ 0xF6, 0x65, 0xAB, 0x23, 0x47, 0xBC, 0x4D, 0x21,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x98, 0x00, 0x98, 0x00, 0x4E, 0x00, 0x00, 0x00,
+ 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F,
+ 0x53, 0x00, 0x41, 0x00, 0x4D, 0x00, 0x42, 0x00,
+ 0x41, 0x00, 0x44, 0x00, 0x4F, 0x00, 0x4D, 0x00,
+ 0x41, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x02, 0x00,
+ 0x16, 0x00, 0x53, 0x00, 0x41, 0x00, 0x4D, 0x00,
+ 0x42, 0x00, 0x41, 0x00, 0x44, 0x00, 0x4F, 0x00,
+ 0x4D, 0x00, 0x41, 0x00, 0x49, 0x00, 0x4E, 0x00,
+ 0x01, 0x00, 0x0E, 0x00, 0x4C, 0x00, 0x4F, 0x00,
+ 0x43, 0x00, 0x41, 0x00, 0x4C, 0x00, 0x44, 0x00,
+ 0x43, 0x00, 0x04, 0x00, 0x22, 0x00, 0x73, 0x00,
+ 0x61, 0x00, 0x6D, 0x00, 0x62, 0x00, 0x61, 0x00,
+ 0x2E, 0x00, 0x65, 0x00, 0x78, 0x00, 0x61, 0x00,
+ 0x6D, 0x00, 0x70, 0x00, 0x6C, 0x00, 0x65, 0x00,
+ 0x2E, 0x00, 0x63, 0x00, 0x6F, 0x00, 0x6D, 0x00,
+ 0x03, 0x00, 0x32, 0x00, 0x6C, 0x00, 0x6F, 0x00,
+ 0x63, 0x00, 0x61, 0x00, 0x6C, 0x00, 0x64, 0x00,
+ 0x63, 0x00, 0x2E, 0x00, 0x73, 0x00, 0x61, 0x00,
+ 0x6D, 0x00, 0x62, 0x00, 0x61, 0x00, 0x2E, 0x00,
+ 0x65, 0x00, 0x78, 0x00, 0x61, 0x00, 0x6D, 0x00,
+ 0x70, 0x00, 0x6C, 0x00, 0x65, 0x00, 0x2E, 0x00,
+ 0x63, 0x00, 0x6F, 0x00, 0x6D, 0x00, 0x07, 0x00,
+ 0x08, 0x00, 0x0C, 0x40, 0xA3, 0xC3, 0x5B, 0xE0,
+ 0xD2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55,
+ 0x00, 0x6E, 0x00, 0x69, 0x00, 0x78, 0x00, 0x00,
+ 0x00, 0x53, 0x00, 0x61, 0x00, 0x6D, 0x00, 0x62,
+ 0x00, 0x61, 0x00, 0x20, 0x00, 0x34, 0x00, 0x2E,
+ 0x00, 0x37, 0x00, 0x2E, 0x00, 0x30, 0x00, 0x70,
+ 0x00, 0x72, 0x00, 0x65, 0x00, 0x31, 0x00, 0x2D,
+ 0x00, 0x44, 0x00, 0x45, 0x00, 0x56, 0x00, 0x45,
+ 0x00, 0x4C, 0x00, 0x4F, 0x00, 0x50, 0x00, 0x45,
+ 0x00, 0x52, 0x00, 0x42, 0x00, 0x55, 0x00, 0x49,
+ 0x00, 0x4C, 0x00, 0x44, 0x00, 0x00, 0x00, 0x53,
+ 0x00, 0x41, 0x00, 0x4D, 0x00, 0x42, 0x00, 0x41,
+ 0x00, 0x44, 0x00, 0x4F, 0x00, 0x4D, 0x00, 0x41,
+ 0x00, 0x49, 0x00, 0x4E, 0x00, 0x00, 0x00
+};
+
+static void test_smb_bytes_pull_str(void **state)
+{
+ NTSTATUS status;
+ const uint8_t *bytes = smb1_session_setup_bytes;
+ const size_t num_bytes = sizeof(smb1_session_setup_bytes);
+ const uint8_t *p = NULL;
+ size_t ret = 0;
+ size_t out_security_blob_length = 262;
+ bool use_unicode = true;
+ char *str = NULL;
+
+ p = bytes;
+ p += out_security_blob_length;
+
+ status = smb_bytes_pull_str(NULL, &str, use_unicode,
+ bytes, num_bytes,
+ p, &ret);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_string_equal(str, "Unix");
+ assert_int_equal(ret, 0x0b);
+ TALLOC_FREE(str);
+
+ p += ret;
+ status = smb_bytes_pull_str(NULL, &str, use_unicode,
+ bytes, num_bytes,
+ p, &ret);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_string_equal(str, "Samba 4.7.0pre1-DEVELOPERBUILD");
+ assert_int_equal(ret, 0x3e);
+ TALLOC_FREE(str);
+
+ p += ret;
+ status = smb_bytes_pull_str(NULL, &str, use_unicode,
+ bytes, num_bytes,
+ p, &ret);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_string_equal(str, "SAMBADOMAIN");
+ assert_int_equal(ret, 0x18);
+ TALLOC_FREE(str);
+
+ p += ret;
+ status = smb_bytes_pull_str(NULL, &str, use_unicode,
+ bytes, num_bytes,
+ p, &ret);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_string_equal(str, "");
+ assert_int_equal(ret, 0x00);
+ TALLOC_FREE(str);
+}
+
+static void test_smb_bytes_pull_str_no_unicode(void **state)
+{
+ NTSTATUS status;
+ const uint8_t *bytes = smb1_session_setup_bytes;
+ const size_t num_bytes = sizeof(smb1_session_setup_bytes);
+ const uint8_t *p = NULL;
+ size_t ret = 0;
+ size_t out_security_blob_length = 262;
+ bool use_unicode = false;
+ char *str = NULL;
+
+ p = bytes;
+ p += out_security_blob_length;
+
+ status = smb_bytes_pull_str(NULL, &str, use_unicode,
+ bytes, num_bytes,
+ p, &ret);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_string_equal(str, "");
+ assert_int_equal(ret, 0x01);
+ TALLOC_FREE(str);
+}
+
+static void test_smb_bytes_pull_str_wrong_offset(void **state)
+{
+ NTSTATUS status;
+ const uint8_t *bytes = smb1_session_setup_bytes;
+ const size_t num_bytes = sizeof(smb1_session_setup_bytes);
+ const uint8_t *p = NULL;
+ size_t ret = 0;
+ size_t out_security_blob_length = 261;
+ bool use_unicode = true;
+ char *str = NULL;
+
+ bytes += 1;
+ p = bytes;
+ p += out_security_blob_length;
+
+ status = smb_bytes_pull_str(NULL, &str, use_unicode,
+ bytes, num_bytes,
+ p, &ret);
+ assert_true(NT_STATUS_IS_OK(status));
+
+ assert_string_equal(str, "\xE5\x94\x80\xE6\xB8\x80\xE6\xA4\x80\xE7\xA0\x80");
+ assert_int_equal(ret, 0x0a);
+ TALLOC_FREE(str);
+}
+
+static void test_smb_bytes_pull_str_invalid_offset(void **state)
+{
+ NTSTATUS status;
+ const uint8_t *bytes = smb1_session_setup_bytes;
+ const size_t num_bytes = sizeof(smb1_session_setup_bytes);
+ const uint8_t *p = NULL;
+ size_t ret = 0;
+ bool use_unicode = true;
+ char *str = NULL;
+ intptr_t bytes_address = (intptr_t)bytes;
+
+ /* Warning: array subscript is below array bounds */
+ p = (const uint8_t *)(bytes_address - 1);
+ status = smb_bytes_pull_str(NULL, &str, use_unicode,
+ bytes, num_bytes,
+ p, &ret);
+ assert_int_equal(NT_STATUS_V(status),
+ NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
+
+ p = bytes + num_bytes;
+ status = smb_bytes_pull_str(NULL, &str, use_unicode,
+ bytes, num_bytes,
+ p, &ret);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_string_equal(str, "");
+ assert_int_equal(ret, 0x00);
+ TALLOC_FREE(str);
+
+ p = bytes + num_bytes - 1;
+ status = smb_bytes_pull_str(NULL, &str, use_unicode,
+ bytes, num_bytes,
+ p, &ret);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_string_equal(str, "");
+ assert_int_equal(ret, 0x01);
+ TALLOC_FREE(str);
+
+ /* Warning: array subscript is above array bounds */
+ p = (const uint8_t *)(bytes_address + num_bytes + 1);
+ status = smb_bytes_pull_str(NULL, &str, use_unicode,
+ bytes, num_bytes,
+ p, &ret);
+ assert_int_equal(NT_STATUS_V(status),
+ NT_STATUS_V(NT_STATUS_BUFFER_TOO_SMALL));
+}
+
+int main(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_smb_bytes_pull_str),
+ cmocka_unit_test(test_smb_bytes_pull_str_no_unicode),
+ cmocka_unit_test(test_smb_bytes_pull_str_wrong_offset),
+ cmocka_unit_test(test_smb_bytes_pull_str_invalid_offset),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/libcli/smb/test_util_translate.c b/libcli/smb/test_util_translate.c
new file mode 100644
index 0000000..b300af5
--- /dev/null
+++ b/libcli/smb/test_util_translate.c
@@ -0,0 +1,83 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2020 Andreas Schneider <asn@samba.org>
+ *
+ * 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 <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "lib/replace/replace.h"
+#include <talloc.h>
+
+#include "libcli/smb/util.c"
+
+static void test_smb_signing_setting_translate(void **state)
+{
+ enum smb_signing_setting signing_state;
+
+ signing_state = smb_signing_setting_translate("wurst");
+ assert_int_equal(signing_state, SMB_SIGNING_REQUIRED);
+
+ signing_state = smb_signing_setting_translate("off");
+ assert_int_equal(signing_state, SMB_SIGNING_OFF);
+
+ signing_state = smb_signing_setting_translate("if_required");
+ assert_int_equal(signing_state, SMB_SIGNING_IF_REQUIRED);
+
+ signing_state = smb_signing_setting_translate("mandatory");
+ assert_int_equal(signing_state, SMB_SIGNING_REQUIRED);
+
+}
+
+static void test_smb_encryption_setting_translate(void **state)
+{
+ enum smb_encryption_setting encryption_state;
+
+ encryption_state = smb_encryption_setting_translate("wurst");
+ assert_int_equal(encryption_state, SMB_ENCRYPTION_REQUIRED);
+
+ encryption_state = smb_encryption_setting_translate("off");
+ assert_int_equal(encryption_state, SMB_ENCRYPTION_OFF);
+
+ encryption_state = smb_encryption_setting_translate("if_required");
+ assert_int_equal(encryption_state, SMB_ENCRYPTION_IF_REQUIRED);
+
+ encryption_state = smb_encryption_setting_translate("mandatory");
+ assert_int_equal(encryption_state, SMB_ENCRYPTION_REQUIRED);
+
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_smb_signing_setting_translate),
+ cmocka_unit_test(test_smb_encryption_setting_translate),
+ };
+
+ if (argc == 2) {
+ cmocka_set_test_filter(argv[1]);
+ }
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ rc = cmocka_run_group_tests(tests, NULL, NULL);
+
+ return rc;
+}
diff --git a/libcli/smb/tstream_smbXcli_np.c b/libcli/smb/tstream_smbXcli_np.c
new file mode 100644
index 0000000..0248300
--- /dev/null
+++ b/libcli/smb/tstream_smbXcli_np.c
@@ -0,0 +1,1399 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 2010
+
+ 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 "system/network.h"
+#include "../lib/util/tevent_ntstatus.h"
+#include "../lib/tsocket/tsocket.h"
+#include "../lib/tsocket/tsocket_internal.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+#include "tstream_smbXcli_np.h"
+#include "libcli/security/security.h"
+
+static const struct tstream_context_ops tstream_smbXcli_np_ops;
+
+#define TSTREAM_SMBXCLI_NP_DESIRED_ACCESS ( \
+ SEC_STD_READ_CONTROL | \
+ SEC_FILE_READ_DATA | \
+ SEC_FILE_WRITE_DATA | \
+ SEC_FILE_APPEND_DATA | \
+ SEC_FILE_READ_EA | \
+ SEC_FILE_WRITE_EA | \
+ SEC_FILE_READ_ATTRIBUTE | \
+ SEC_FILE_WRITE_ATTRIBUTE | \
+0)
+
+struct tstream_smbXcli_np_ref;
+
+struct tstream_smbXcli_np {
+ struct smbXcli_conn *conn;
+ struct tstream_smbXcli_np_ref *conn_ref;
+ struct smbXcli_session *session;
+ struct tstream_smbXcli_np_ref *session_ref;
+ struct smbXcli_tcon *tcon;
+ struct tstream_smbXcli_np_ref *tcon_ref;
+ uint16_t pid;
+ unsigned int timeout;
+
+ const char *npipe;
+ bool is_smb1;
+ uint16_t fnum;
+ uint64_t fid_persistent;
+ uint64_t fid_volatile;
+ uint32_t max_data;
+
+ struct {
+ bool active;
+ struct tevent_req *read_req;
+ struct tevent_req *write_req;
+ uint16_t setup[2];
+ } trans;
+
+ struct {
+ off_t ofs;
+ size_t left;
+ uint8_t *buf;
+ } read, write;
+};
+
+struct tstream_smbXcli_np_ref {
+ struct tstream_smbXcli_np *cli_nps;
+};
+
+static int tstream_smbXcli_np_destructor(struct tstream_smbXcli_np *cli_nps)
+{
+ NTSTATUS status;
+
+ if (cli_nps->conn_ref != NULL) {
+ cli_nps->conn_ref->cli_nps = NULL;
+ TALLOC_FREE(cli_nps->conn_ref);
+ }
+
+ if (cli_nps->session_ref != NULL) {
+ cli_nps->session_ref->cli_nps = NULL;
+ TALLOC_FREE(cli_nps->session_ref);
+ }
+
+ if (cli_nps->tcon_ref != NULL) {
+ cli_nps->tcon_ref->cli_nps = NULL;
+ TALLOC_FREE(cli_nps->tcon_ref);
+ }
+
+ if (!smbXcli_conn_is_connected(cli_nps->conn)) {
+ return 0;
+ }
+
+ /*
+ * TODO: do not use a sync call with a destructor!!!
+ *
+ * This only happens, if a caller does talloc_free(),
+ * while the everything was still ok.
+ *
+ * If we get an unexpected failure within a normal
+ * operation, we already do an async cli_close_send()/_recv().
+ *
+ * Once we've fixed all callers to call
+ * tstream_disconnect_send()/_recv(), this will
+ * never be called.
+ *
+ * We use a maximum timeout of 1 second == 1000 msec.
+ */
+ cli_nps->timeout = MIN(cli_nps->timeout, 1000);
+
+ if (cli_nps->is_smb1) {
+ status = smb1cli_close(cli_nps->conn,
+ cli_nps->timeout,
+ cli_nps->pid,
+ cli_nps->tcon,
+ cli_nps->session,
+ cli_nps->fnum, UINT32_MAX);
+ } else {
+ status = smb2cli_close(cli_nps->conn,
+ cli_nps->timeout,
+ cli_nps->session,
+ cli_nps->tcon,
+ 0, /* flags */
+ cli_nps->fid_persistent,
+ cli_nps->fid_volatile);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("tstream_smbXcli_np_destructor: cli_close "
+ "failed on pipe %s. Error was %s\n",
+ cli_nps->npipe, nt_errstr(status)));
+ }
+ /*
+ * We can't do much on failure
+ */
+ return 0;
+}
+
+static int tstream_smbXcli_np_ref_destructor(struct tstream_smbXcli_np_ref *ref)
+{
+ if (ref->cli_nps == NULL) {
+ return 0;
+ }
+
+ if (ref->cli_nps->conn == NULL) {
+ return 0;
+ }
+
+ ref->cli_nps->conn = NULL;
+ ref->cli_nps->session = NULL;
+ ref->cli_nps->tcon = NULL;
+
+ TALLOC_FREE(ref->cli_nps->conn_ref);
+ TALLOC_FREE(ref->cli_nps->session_ref);
+ TALLOC_FREE(ref->cli_nps->tcon_ref);
+
+ return 0;
+};
+
+static struct tevent_req *tstream_smbXcli_np_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream);
+static int tstream_smbXcli_np_disconnect_recv(struct tevent_req *req,
+ int *perrno);
+
+struct tstream_smbXcli_np_open_state {
+ struct smbXcli_conn *conn;
+ struct smbXcli_session *session;
+ struct smbXcli_tcon *tcon;
+ uint16_t pid;
+ unsigned int timeout;
+
+ bool is_smb1;
+ uint16_t fnum;
+ uint64_t fid_persistent;
+ uint64_t fid_volatile;
+ const char *npipe;
+};
+
+static void tstream_smbXcli_np_open_done(struct tevent_req *subreq);
+
+struct tevent_req *tstream_smbXcli_np_open_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t pid,
+ unsigned int timeout,
+ const char *npipe)
+{
+ struct tevent_req *req;
+ struct tstream_smbXcli_np_open_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_smbXcli_np_open_state);
+ if (!req) {
+ return NULL;
+ }
+ state->conn = conn;
+ state->tcon = tcon;
+ state->session = session;
+ state->pid = pid;
+ state->timeout = timeout;
+
+ state->npipe = talloc_strdup(state, npipe);
+ if (tevent_req_nomem(state->npipe, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (smbXcli_conn_protocol(conn) < PROTOCOL_SMB2_02) {
+ state->is_smb1 = true;
+ }
+
+ if (state->is_smb1) {
+ const char *smb1_npipe;
+
+ /*
+ * Windows and newer Samba versions allow
+ * the pipe name without leading backslash,
+ * but we should better behave like windows clients
+ */
+ smb1_npipe = talloc_asprintf(state, "\\%s", state->npipe);
+ if (tevent_req_nomem(smb1_npipe, req)) {
+ return tevent_req_post(req, ev);
+ }
+ subreq = smb1cli_ntcreatex_send(state, ev, state->conn,
+ state->timeout,
+ state->pid,
+ state->tcon,
+ state->session,
+ smb1_npipe,
+ 0, /* CreatFlags */
+ 0, /* RootDirectoryFid */
+ TSTREAM_SMBXCLI_NP_DESIRED_ACCESS,
+ 0, /* AllocationSize */
+ 0, /* FileAttributes */
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OPEN, /* CreateDisposition */
+ 0, /* CreateOptions */
+ 2, /* NTCREATEX_IMPERSONATION_IMPERSONATION */
+ 0); /* SecurityFlags */
+ } else {
+ subreq = smb2cli_create_send(state, ev, state->conn,
+ state->timeout, state->session,
+ state->tcon,
+ npipe,
+ SMB2_OPLOCK_LEVEL_NONE,
+ SMB2_IMPERSONATION_IMPERSONATION,
+ TSTREAM_SMBXCLI_NP_DESIRED_ACCESS,
+ 0, /* file_attributes */
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OPEN,
+ 0, /* create_options */
+ NULL); /* blobs */
+ }
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, tstream_smbXcli_np_open_done, req);
+
+ return req;
+}
+
+static void tstream_smbXcli_np_open_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct tstream_smbXcli_np_open_state *state =
+ tevent_req_data(req, struct tstream_smbXcli_np_open_state);
+ NTSTATUS status;
+
+ if (state->is_smb1) {
+ status = smb1cli_ntcreatex_recv(subreq, &state->fnum);
+ } else {
+ status = smb2cli_create_recv(
+ subreq,
+ &state->fid_persistent,
+ &state->fid_volatile,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ }
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS _tstream_smbXcli_np_open_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **_stream,
+ const char *location)
+{
+ struct tstream_smbXcli_np_open_state *state =
+ tevent_req_data(req, struct tstream_smbXcli_np_open_state);
+ struct tstream_context *stream;
+ struct tstream_smbXcli_np *cli_nps;
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ stream = tstream_context_create(mem_ctx,
+ &tstream_smbXcli_np_ops,
+ &cli_nps,
+ struct tstream_smbXcli_np,
+ location);
+ if (!stream) {
+ tevent_req_received(req);
+ return NT_STATUS_NO_MEMORY;
+ }
+ ZERO_STRUCTP(cli_nps);
+
+ cli_nps->conn_ref = talloc_zero(state->conn,
+ struct tstream_smbXcli_np_ref);
+ if (cli_nps->conn_ref == NULL) {
+ TALLOC_FREE(cli_nps);
+ tevent_req_received(req);
+ return NT_STATUS_NO_MEMORY;
+ }
+ cli_nps->conn_ref->cli_nps = cli_nps;
+
+ cli_nps->session_ref = talloc_zero(state->session,
+ struct tstream_smbXcli_np_ref);
+ if (cli_nps->session_ref == NULL) {
+ TALLOC_FREE(cli_nps);
+ tevent_req_received(req);
+ return NT_STATUS_NO_MEMORY;
+ }
+ cli_nps->session_ref->cli_nps = cli_nps;
+
+ cli_nps->tcon_ref = talloc_zero(state->tcon,
+ struct tstream_smbXcli_np_ref);
+ if (cli_nps->tcon_ref == NULL) {
+ TALLOC_FREE(cli_nps);
+ tevent_req_received(req);
+ return NT_STATUS_NO_MEMORY;
+ }
+ cli_nps->tcon_ref->cli_nps = cli_nps;
+
+ cli_nps->conn = state->conn;
+ cli_nps->session = state->session;
+ cli_nps->tcon = state->tcon;
+ cli_nps->pid = state->pid;
+ cli_nps->timeout = state->timeout;
+ cli_nps->npipe = talloc_move(cli_nps, &state->npipe);
+ cli_nps->is_smb1 = state->is_smb1;
+ cli_nps->fnum = state->fnum;
+ cli_nps->fid_persistent = state->fid_persistent;
+ cli_nps->fid_volatile = state->fid_volatile;
+ cli_nps->max_data = TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE;
+
+ talloc_set_destructor(cli_nps, tstream_smbXcli_np_destructor);
+ talloc_set_destructor(cli_nps->conn_ref,
+ tstream_smbXcli_np_ref_destructor);
+ talloc_set_destructor(cli_nps->session_ref,
+ tstream_smbXcli_np_ref_destructor);
+ talloc_set_destructor(cli_nps->tcon_ref,
+ tstream_smbXcli_np_ref_destructor);
+
+ cli_nps->trans.active = false;
+ cli_nps->trans.read_req = NULL;
+ cli_nps->trans.write_req = NULL;
+ SSVAL(cli_nps->trans.setup+0, 0, TRANSACT_DCERPCCMD);
+ SSVAL(cli_nps->trans.setup+1, 0, cli_nps->fnum);
+
+ *_stream = stream;
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+static ssize_t tstream_smbXcli_np_pending_bytes(struct tstream_context *stream)
+{
+ struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
+ struct tstream_smbXcli_np);
+
+ if (!smbXcli_conn_is_connected(cli_nps->conn)) {
+ errno = ENOTCONN;
+ return -1;
+ }
+
+ return cli_nps->read.left;
+}
+
+bool tstream_is_smbXcli_np(struct tstream_context *stream)
+{
+ struct tstream_smbXcli_np *cli_nps =
+ talloc_get_type(_tstream_context_data(stream),
+ struct tstream_smbXcli_np);
+
+ if (!cli_nps) {
+ return false;
+ }
+
+ return true;
+}
+
+NTSTATUS tstream_smbXcli_np_use_trans(struct tstream_context *stream)
+{
+ struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
+ struct tstream_smbXcli_np);
+
+ if (cli_nps->trans.read_req) {
+ return NT_STATUS_PIPE_BUSY;
+ }
+
+ if (cli_nps->trans.write_req) {
+ return NT_STATUS_PIPE_BUSY;
+ }
+
+ if (cli_nps->trans.active) {
+ return NT_STATUS_PIPE_BUSY;
+ }
+
+ cli_nps->trans.active = true;
+
+ return NT_STATUS_OK;
+}
+
+void tstream_smbXcli_np_set_max_data(struct tstream_context *stream,
+ uint32_t max_data)
+{
+ struct tstream_smbXcli_np *cli_nps = tstream_context_data(
+ stream, struct tstream_smbXcli_np);
+
+ cli_nps->max_data = max_data;
+}
+
+unsigned int tstream_smbXcli_np_set_timeout(struct tstream_context *stream,
+ unsigned int timeout)
+{
+ struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
+ struct tstream_smbXcli_np);
+ unsigned int old_timeout = cli_nps->timeout;
+
+ cli_nps->timeout = timeout;
+ return old_timeout;
+}
+
+struct tstream_smbXcli_np_writev_state {
+ struct tstream_context *stream;
+ struct tevent_context *ev;
+
+ struct iovec *vector;
+ size_t count;
+
+ int ret;
+
+ struct {
+ int val;
+ const char *location;
+ } error;
+};
+
+static int tstream_smbXcli_np_writev_state_destructor(struct tstream_smbXcli_np_writev_state *state)
+{
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream,
+ struct tstream_smbXcli_np);
+
+ cli_nps->trans.write_req = NULL;
+
+ return 0;
+}
+
+static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req);
+
+static struct tevent_req *tstream_smbXcli_np_writev_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ const struct iovec *vector,
+ size_t count)
+{
+ struct tevent_req *req;
+ struct tstream_smbXcli_np_writev_state *state;
+ struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
+ struct tstream_smbXcli_np);
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_smbXcli_np_writev_state);
+ if (!req) {
+ return NULL;
+ }
+ state->stream = stream;
+ state->ev = ev;
+ state->ret = 0;
+
+ talloc_set_destructor(state, tstream_smbXcli_np_writev_state_destructor);
+
+ if (!smbXcli_conn_is_connected(cli_nps->conn)) {
+ tevent_req_error(req, ENOTCONN);
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * we make a copy of the vector so we can change the structure
+ */
+ state->vector = talloc_array(state, struct iovec, count);
+ if (tevent_req_nomem(state->vector, req)) {
+ return tevent_req_post(req, ev);
+ }
+ memcpy(state->vector, vector, sizeof(struct iovec) * count);
+ state->count = count;
+
+ tstream_smbXcli_np_writev_write_next(req);
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void tstream_smbXcli_np_readv_trans_start(struct tevent_req *req);
+static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq);
+
+static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req)
+{
+ struct tstream_smbXcli_np_writev_state *state =
+ tevent_req_data(req,
+ struct tstream_smbXcli_np_writev_state);
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream,
+ struct tstream_smbXcli_np);
+ struct tevent_req *subreq;
+ size_t i;
+ size_t left = 0;
+
+ for (i=0; i < state->count; i++) {
+ left += state->vector[i].iov_len;
+ }
+
+ if (left == 0) {
+ TALLOC_FREE(cli_nps->write.buf);
+ tevent_req_done(req);
+ return;
+ }
+
+ cli_nps->write.ofs = 0;
+ cli_nps->write.left = MIN(left, cli_nps->max_data);
+ cli_nps->write.buf = talloc_realloc(cli_nps, cli_nps->write.buf,
+ uint8_t, cli_nps->write.left);
+ if (tevent_req_nomem(cli_nps->write.buf, req)) {
+ return;
+ }
+
+ /*
+ * copy the pending buffer first
+ */
+ while (cli_nps->write.left > 0 && state->count > 0) {
+ uint8_t *base = (uint8_t *)state->vector[0].iov_base;
+ size_t len = MIN(cli_nps->write.left, state->vector[0].iov_len);
+
+ memcpy(cli_nps->write.buf + cli_nps->write.ofs, base, len);
+
+ base += len;
+ state->vector[0].iov_base = base;
+ state->vector[0].iov_len -= len;
+
+ cli_nps->write.ofs += len;
+ cli_nps->write.left -= len;
+
+ if (state->vector[0].iov_len == 0) {
+ state->vector += 1;
+ state->count -= 1;
+ }
+
+ state->ret += len;
+ }
+
+ if (cli_nps->trans.active && state->count == 0) {
+ cli_nps->trans.active = false;
+ cli_nps->trans.write_req = req;
+ return;
+ }
+
+ if (cli_nps->trans.read_req && state->count == 0) {
+ cli_nps->trans.write_req = req;
+ tstream_smbXcli_np_readv_trans_start(cli_nps->trans.read_req);
+ return;
+ }
+
+ if (cli_nps->is_smb1) {
+ subreq = smb1cli_writex_send(state, state->ev,
+ cli_nps->conn,
+ cli_nps->timeout,
+ cli_nps->pid,
+ cli_nps->tcon,
+ cli_nps->session,
+ cli_nps->fnum,
+ 8, /* 8 means message mode. */
+ cli_nps->write.buf,
+ 0, /* offset */
+ cli_nps->write.ofs); /* size */
+ } else {
+ subreq = smb2cli_write_send(state, state->ev,
+ cli_nps->conn,
+ cli_nps->timeout,
+ cli_nps->session,
+ cli_nps->tcon,
+ cli_nps->write.ofs, /* length */
+ 0, /* offset */
+ cli_nps->fid_persistent,
+ cli_nps->fid_volatile,
+ 0, /* remaining_bytes */
+ 0, /* flags */
+ cli_nps->write.buf);
+ }
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ tstream_smbXcli_np_writev_write_done,
+ req);
+}
+
+static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req *req,
+ int error,
+ const char *location);
+
+static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct tstream_smbXcli_np_writev_state *state =
+ tevent_req_data(req, struct tstream_smbXcli_np_writev_state);
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream,
+ struct tstream_smbXcli_np);
+ uint32_t written;
+ NTSTATUS status;
+
+ if (cli_nps->is_smb1) {
+ status = smb1cli_writex_recv(subreq, &written, NULL);
+ } else {
+ status = smb2cli_write_recv(subreq, &written);
+ }
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tstream_smbXcli_np_writev_disconnect_now(req, EPIPE, __location__);
+ return;
+ }
+
+ if (written != cli_nps->write.ofs) {
+ tstream_smbXcli_np_writev_disconnect_now(req, EIO, __location__);
+ return;
+ }
+
+ tstream_smbXcli_np_writev_write_next(req);
+}
+
+static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req *subreq);
+
+static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req *req,
+ int error,
+ const char *location)
+{
+ struct tstream_smbXcli_np_writev_state *state =
+ tevent_req_data(req,
+ struct tstream_smbXcli_np_writev_state);
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream,
+ struct tstream_smbXcli_np);
+ struct tevent_req *subreq;
+
+ state->error.val = error;
+ state->error.location = location;
+
+ if (!smbXcli_conn_is_connected(cli_nps->conn)) {
+ /* return the original error */
+ _tevent_req_error(req, state->error.val, state->error.location);
+ return;
+ }
+
+ subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
+ state->stream);
+ if (subreq == NULL) {
+ /* return the original error */
+ _tevent_req_error(req, state->error.val, state->error.location);
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ tstream_smbXcli_np_writev_disconnect_done,
+ req);
+}
+
+static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct tstream_smbXcli_np_writev_state *state =
+ tevent_req_data(req, struct tstream_smbXcli_np_writev_state);
+ int error;
+
+ tstream_smbXcli_np_disconnect_recv(subreq, &error);
+ TALLOC_FREE(subreq);
+
+ /* return the original error */
+ _tevent_req_error(req, state->error.val, state->error.location);
+}
+
+static int tstream_smbXcli_np_writev_recv(struct tevent_req *req,
+ int *perrno)
+{
+ struct tstream_smbXcli_np_writev_state *state =
+ tevent_req_data(req,
+ struct tstream_smbXcli_np_writev_state);
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ ret = state->ret;
+ }
+
+ tevent_req_received(req);
+ return ret;
+}
+
+struct tstream_smbXcli_np_readv_state {
+ struct tstream_context *stream;
+ struct tevent_context *ev;
+
+ struct iovec *vector;
+ size_t count;
+
+ int ret;
+
+ struct {
+ struct tevent_immediate *im;
+ } trans;
+
+ struct {
+ int val;
+ const char *location;
+ } error;
+};
+
+static int tstream_smbXcli_np_readv_state_destructor(struct tstream_smbXcli_np_readv_state *state)
+{
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream,
+ struct tstream_smbXcli_np);
+
+ cli_nps->trans.read_req = NULL;
+
+ return 0;
+}
+
+static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req);
+
+static struct tevent_req *tstream_smbXcli_np_readv_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ struct iovec *vector,
+ size_t count)
+{
+ struct tevent_req *req;
+ struct tstream_smbXcli_np_readv_state *state;
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(stream, struct tstream_smbXcli_np);
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_smbXcli_np_readv_state);
+ if (!req) {
+ return NULL;
+ }
+ state->stream = stream;
+ state->ev = ev;
+ state->ret = 0;
+
+ talloc_set_destructor(state, tstream_smbXcli_np_readv_state_destructor);
+
+ if (!smbXcli_conn_is_connected(cli_nps->conn)) {
+ tevent_req_error(req, ENOTCONN);
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * we make a copy of the vector so we can change the structure
+ */
+ state->vector = talloc_array(state, struct iovec, count);
+ if (tevent_req_nomem(state->vector, req)) {
+ return tevent_req_post(req, ev);
+ }
+ memcpy(state->vector, vector, sizeof(struct iovec) * count);
+ state->count = count;
+
+ tstream_smbXcli_np_readv_read_next(req);
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq);
+
+static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req)
+{
+ struct tstream_smbXcli_np_readv_state *state =
+ tevent_req_data(req,
+ struct tstream_smbXcli_np_readv_state);
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream,
+ struct tstream_smbXcli_np);
+ struct tevent_req *subreq;
+
+ /*
+ * copy the pending buffer first
+ */
+ while (cli_nps->read.left > 0 && state->count > 0) {
+ uint8_t *base = (uint8_t *)state->vector[0].iov_base;
+ size_t len = MIN(cli_nps->read.left, state->vector[0].iov_len);
+
+ memcpy(base, cli_nps->read.buf + cli_nps->read.ofs, len);
+
+ base += len;
+ state->vector[0].iov_base = base;
+ state->vector[0].iov_len -= len;
+
+ cli_nps->read.ofs += len;
+ cli_nps->read.left -= len;
+
+ if (state->vector[0].iov_len == 0) {
+ state->vector += 1;
+ state->count -= 1;
+ }
+
+ state->ret += len;
+ }
+
+ if (cli_nps->read.left == 0) {
+ TALLOC_FREE(cli_nps->read.buf);
+ }
+
+ if (state->count == 0) {
+ tevent_req_done(req);
+ return;
+ }
+
+ if (cli_nps->trans.active) {
+ cli_nps->trans.active = false;
+ cli_nps->trans.read_req = req;
+ return;
+ }
+
+ if (cli_nps->trans.write_req) {
+ cli_nps->trans.read_req = req;
+ tstream_smbXcli_np_readv_trans_start(req);
+ return;
+ }
+
+ if (cli_nps->is_smb1) {
+ subreq = smb1cli_readx_send(state, state->ev,
+ cli_nps->conn,
+ cli_nps->timeout,
+ cli_nps->pid,
+ cli_nps->tcon,
+ cli_nps->session,
+ cli_nps->fnum,
+ 0, /* offset */
+ cli_nps->max_data);
+ } else {
+ subreq = smb2cli_read_send(state, state->ev,
+ cli_nps->conn,
+ cli_nps->timeout,
+ cli_nps->session,
+ cli_nps->tcon,
+ cli_nps->max_data, /* length */
+ 0, /* offset */
+ cli_nps->fid_persistent,
+ cli_nps->fid_volatile,
+ 0, /* minimum_count */
+ 0); /* remaining_bytes */
+ }
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ tstream_smbXcli_np_readv_read_done,
+ req);
+}
+
+static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq);
+
+static void tstream_smbXcli_np_readv_trans_start(struct tevent_req *req)
+{
+ struct tstream_smbXcli_np_readv_state *state =
+ tevent_req_data(req,
+ struct tstream_smbXcli_np_readv_state);
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream,
+ struct tstream_smbXcli_np);
+ struct tevent_req *subreq;
+
+ state->trans.im = tevent_create_immediate(state);
+ if (tevent_req_nomem(state->trans.im, req)) {
+ return;
+ }
+
+ if (cli_nps->is_smb1) {
+ subreq = smb1cli_trans_send(state, state->ev,
+ cli_nps->conn, SMBtrans,
+ 0, 0, /* *_flags */
+ 0, 0, /* *_flags2 */
+ cli_nps->timeout,
+ cli_nps->pid,
+ cli_nps->tcon,
+ cli_nps->session,
+ "\\PIPE\\",
+ 0, 0, 0,
+ cli_nps->trans.setup, 2,
+ 0,
+ NULL, 0, 0,
+ cli_nps->write.buf,
+ cli_nps->write.ofs,
+ cli_nps->max_data);
+ } else {
+ DATA_BLOB in_input_buffer = data_blob_null;
+ DATA_BLOB in_output_buffer = data_blob_null;
+
+ in_input_buffer = data_blob_const(cli_nps->write.buf,
+ cli_nps->write.ofs);
+
+ subreq = smb2cli_ioctl_send(state, state->ev,
+ cli_nps->conn,
+ cli_nps->timeout,
+ cli_nps->session,
+ cli_nps->tcon,
+ cli_nps->fid_persistent,
+ cli_nps->fid_volatile,
+ FSCTL_NAMED_PIPE_READ_WRITE,
+ 0, /* in_max_input_length */
+ &in_input_buffer,
+ /* in_max_output_length */
+ cli_nps->max_data,
+ &in_output_buffer,
+ SMB2_IOCTL_FLAG_IS_FSCTL);
+ }
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ tstream_smbXcli_np_readv_trans_done,
+ req);
+}
+
+static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req,
+ int error,
+ const char *location);
+static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data);
+
+static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct tstream_smbXcli_np_readv_state *state =
+ tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream, struct tstream_smbXcli_np);
+ uint8_t *rcvbuf;
+ uint32_t received;
+ NTSTATUS status;
+
+ if (cli_nps->is_smb1) {
+ status = smb1cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
+ NULL, 0, NULL,
+ &rcvbuf, 0, &received);
+ } else {
+ DATA_BLOB out_input_buffer = data_blob_null;
+ DATA_BLOB out_output_buffer = data_blob_null;
+
+ status = smb2cli_ioctl_recv(subreq, state,
+ &out_input_buffer,
+ &out_output_buffer);
+
+ /* Note that rcvbuf is not a talloc pointer here */
+ rcvbuf = out_output_buffer.data;
+ received = out_output_buffer.length;
+ }
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+ /*
+ * STATUS_BUFFER_OVERFLOW means that there's
+ * more data to read when the named pipe is used
+ * in message mode (which is the case here).
+ *
+ * But we hide this from the caller.
+ */
+ status = NT_STATUS_OK;
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
+ return;
+ }
+
+ if (received > cli_nps->max_data) {
+ tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
+ return;
+ }
+
+ if (received == 0) {
+ tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
+ return;
+ }
+
+ cli_nps->read.ofs = 0;
+ cli_nps->read.left = received;
+ cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
+ if (cli_nps->read.buf == NULL) {
+ TALLOC_FREE(subreq);
+ tevent_req_oom(req);
+ return;
+ }
+ memcpy(cli_nps->read.buf, rcvbuf, received);
+
+ if (cli_nps->trans.write_req == NULL) {
+ tstream_smbXcli_np_readv_read_next(req);
+ return;
+ }
+
+ tevent_schedule_immediate(state->trans.im, state->ev,
+ tstream_smbXcli_np_readv_trans_next, req);
+
+ tevent_req_done(cli_nps->trans.write_req);
+}
+
+static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct tevent_req *req =
+ talloc_get_type_abort(private_data,
+ struct tevent_req);
+
+ tstream_smbXcli_np_readv_read_next(req);
+}
+
+static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct tstream_smbXcli_np_readv_state *state =
+ tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream, struct tstream_smbXcli_np);
+ uint8_t *rcvbuf;
+ uint32_t received;
+ NTSTATUS status;
+
+ /*
+ * We must free subreq in this function as there is
+ * a timer event attached to it.
+ */
+
+ if (cli_nps->is_smb1) {
+ status = smb1cli_readx_recv(subreq, &received, &rcvbuf);
+ } else {
+ status = smb2cli_read_recv(subreq, state, &rcvbuf, &received);
+ }
+ /*
+ * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
+ * child of that.
+ */
+ if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+ /*
+ * STATUS_BUFFER_OVERFLOW means that there's
+ * more data to read when the named pipe is used
+ * in message mode (which is the case here).
+ *
+ * But we hide this from the caller.
+ */
+ status = NT_STATUS_OK;
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(subreq);
+ tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
+ return;
+ }
+
+ if (received > cli_nps->max_data) {
+ TALLOC_FREE(subreq);
+ tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
+ return;
+ }
+
+ if (received == 0) {
+ TALLOC_FREE(subreq);
+ tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
+ return;
+ }
+
+ cli_nps->read.ofs = 0;
+ cli_nps->read.left = received;
+ cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
+ if (cli_nps->read.buf == NULL) {
+ TALLOC_FREE(subreq);
+ tevent_req_oom(req);
+ return;
+ }
+ memcpy(cli_nps->read.buf, rcvbuf, received);
+ TALLOC_FREE(subreq);
+
+ tstream_smbXcli_np_readv_read_next(req);
+}
+
+static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req *subreq);
+
+static void tstream_smbXcli_np_readv_error(struct tevent_req *req);
+
+static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req,
+ int error,
+ const char *location)
+{
+ struct tstream_smbXcli_np_readv_state *state =
+ tevent_req_data(req,
+ struct tstream_smbXcli_np_readv_state);
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream,
+ struct tstream_smbXcli_np);
+ struct tevent_req *subreq;
+
+ state->error.val = error;
+ state->error.location = location;
+
+ if (!smbXcli_conn_is_connected(cli_nps->conn)) {
+ /* return the original error */
+ tstream_smbXcli_np_readv_error(req);
+ return;
+ }
+
+ subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
+ state->stream);
+ if (subreq == NULL) {
+ /* return the original error */
+ tstream_smbXcli_np_readv_error(req);
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ tstream_smbXcli_np_readv_disconnect_done,
+ req);
+}
+
+static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ int error;
+
+ tstream_smbXcli_np_disconnect_recv(subreq, &error);
+ TALLOC_FREE(subreq);
+
+ tstream_smbXcli_np_readv_error(req);
+}
+
+static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data);
+
+static void tstream_smbXcli_np_readv_error(struct tevent_req *req)
+{
+ struct tstream_smbXcli_np_readv_state *state =
+ tevent_req_data(req,
+ struct tstream_smbXcli_np_readv_state);
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream,
+ struct tstream_smbXcli_np);
+
+ if (cli_nps->trans.write_req == NULL) {
+ /* return the original error */
+ _tevent_req_error(req, state->error.val, state->error.location);
+ return;
+ }
+
+ if (state->trans.im == NULL) {
+ /* return the original error */
+ _tevent_req_error(req, state->error.val, state->error.location);
+ return;
+ }
+
+ tevent_schedule_immediate(state->trans.im, state->ev,
+ tstream_smbXcli_np_readv_error_trigger, req);
+
+ /* return the original error for writev */
+ _tevent_req_error(cli_nps->trans.write_req,
+ state->error.val, state->error.location);
+}
+
+static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct tevent_req *req =
+ talloc_get_type_abort(private_data,
+ struct tevent_req);
+ struct tstream_smbXcli_np_readv_state *state =
+ tevent_req_data(req,
+ struct tstream_smbXcli_np_readv_state);
+
+ /* return the original error */
+ _tevent_req_error(req, state->error.val, state->error.location);
+}
+
+static int tstream_smbXcli_np_readv_recv(struct tevent_req *req,
+ int *perrno)
+{
+ struct tstream_smbXcli_np_readv_state *state =
+ tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ ret = state->ret;
+ }
+
+ tevent_req_received(req);
+ return ret;
+}
+
+struct tstream_smbXcli_np_disconnect_state {
+ struct tstream_context *stream;
+ struct tevent_req *subreq;
+};
+
+static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq);
+static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state);
+
+static struct tevent_req *tstream_smbXcli_np_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream)
+{
+ struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
+ struct tstream_smbXcli_np);
+ struct tevent_req *req;
+ struct tstream_smbXcli_np_disconnect_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_smbXcli_np_disconnect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->stream = stream;
+
+ if (!smbXcli_conn_is_connected(cli_nps->conn)) {
+ tevent_req_error(req, ENOTCONN);
+ return tevent_req_post(req, ev);
+ }
+
+ if (cli_nps->is_smb1) {
+ subreq = smb1cli_close_send(state, ev, cli_nps->conn,
+ cli_nps->timeout,
+ cli_nps->pid,
+ cli_nps->tcon,
+ cli_nps->session,
+ cli_nps->fnum, UINT32_MAX);
+ } else {
+ subreq = smb2cli_close_send(state, ev, cli_nps->conn,
+ cli_nps->timeout,
+ cli_nps->session,
+ cli_nps->tcon,
+ 0, /* flags */
+ cli_nps->fid_persistent,
+ cli_nps->fid_volatile);
+ }
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, tstream_smbXcli_np_disconnect_done, req);
+ state->subreq = subreq;
+
+ tevent_req_set_cleanup_fn(req, tstream_smbXcli_np_disconnect_cleanup);
+
+ /*
+ * Make sure we don't send any requests anymore.
+ */
+ cli_nps->conn = NULL;
+
+ return req;
+}
+
+static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_smbXcli_np_disconnect_state *state =
+ tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state);
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream, struct tstream_smbXcli_np);
+ NTSTATUS status;
+
+ state->subreq = NULL;
+
+ if (cli_nps->is_smb1) {
+ status = smb1cli_close_recv(subreq);
+ } else {
+ status = smb2cli_close_recv(subreq);
+ }
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_error(req, EPIPE);
+ return;
+ }
+
+ cli_nps->conn = NULL;
+ cli_nps->session = NULL;
+ cli_nps->tcon = NULL;
+
+ tevent_req_done(req);
+}
+
+static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq);
+
+static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state)
+{
+ struct tstream_smbXcli_np_disconnect_state *state =
+ tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state);
+ struct tstream_smbXcli_np *cli_nps = NULL;
+
+ if (state->subreq == NULL) {
+ return;
+ }
+
+ cli_nps = tstream_context_data(state->stream, struct tstream_smbXcli_np);
+
+ if (cli_nps->tcon == NULL) {
+ return;
+ }
+
+ /*
+ * We're no longer interested in the result
+ * any more, but need to make sure that the close
+ * request arrives at the server if the smb connection,
+ * session and tcon are still alive.
+ *
+ * We move the low level request to the tcon,
+ * which means that it stays as long as the tcon
+ * is available.
+ */
+ talloc_steal(cli_nps->tcon, state->subreq);
+ tevent_req_set_callback(state->subreq,
+ tstream_smbXcli_np_disconnect_free,
+ NULL);
+ state->subreq = NULL;
+
+ cli_nps->conn = NULL;
+ cli_nps->session = NULL;
+ cli_nps->tcon = NULL;
+}
+
+static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq)
+{
+ TALLOC_FREE(subreq);
+}
+
+static int tstream_smbXcli_np_disconnect_recv(struct tevent_req *req,
+ int *perrno)
+{
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+
+ tevent_req_received(req);
+ return ret;
+}
+
+static const struct tstream_context_ops tstream_smbXcli_np_ops = {
+ .name = "smbXcli_np",
+
+ .pending_bytes = tstream_smbXcli_np_pending_bytes,
+
+ .readv_send = tstream_smbXcli_np_readv_send,
+ .readv_recv = tstream_smbXcli_np_readv_recv,
+
+ .writev_send = tstream_smbXcli_np_writev_send,
+ .writev_recv = tstream_smbXcli_np_writev_recv,
+
+ .disconnect_send = tstream_smbXcli_np_disconnect_send,
+ .disconnect_recv = tstream_smbXcli_np_disconnect_recv,
+};
diff --git a/libcli/smb/tstream_smbXcli_np.h b/libcli/smb/tstream_smbXcli_np.h
new file mode 100644
index 0000000..d7a4e3c
--- /dev/null
+++ b/libcli/smb/tstream_smbXcli_np.h
@@ -0,0 +1,75 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 2010
+
+ 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/>.
+*/
+
+#ifndef _CLI_NP_TSTREAM_H_
+#define _CLI_NP_TSTREAM_H_
+
+struct tevent_context;
+struct tevent_req;
+struct tstream_context;
+struct smbXcli_conn;
+struct smbXcli_session;
+struct smbXcli_tcon;
+
+struct tevent_req *tstream_smbXcli_np_open_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t pid,
+ unsigned int timeout,
+ const char *npipe);
+NTSTATUS _tstream_smbXcli_np_open_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **_stream,
+ const char *location);
+#define tstream_smbXcli_np_open_recv(req, mem_ctx, stream) \
+ _tstream_smbXcli_np_open_recv(req, mem_ctx, stream, __location__)
+
+bool tstream_is_smbXcli_np(struct tstream_context *stream);
+
+NTSTATUS tstream_smbXcli_np_use_trans(struct tstream_context *stream);
+
+unsigned int tstream_smbXcli_np_set_timeout(struct tstream_context *stream,
+ unsigned int timeout);
+
+/*
+ * Windows uses 4280 (the max xmit/recv size negotiated on DCERPC).
+ * This is fits into the max_xmit negotiated at the SMB layer.
+ *
+ * On the sending side they may use SMBtranss if the request does not
+ * fit into a single SMBtrans call.
+ *
+ * Windows uses 1024 as max data size of a SMBtrans request and then
+ * possibly reads the rest of the DCERPC fragment (up to 3256 bytes)
+ * via a SMBreadX.
+ *
+ * For now we just ask for the full 4280 bytes (max data size) in the SMBtrans
+ * request to get the whole fragment at once (like samba 3.5.x and below did.
+ *
+ * It is important that we use do SMBwriteX with the size of a full fragment,
+ * otherwise we may get NT_STATUS_PIPE_BUSY on the SMBtrans request
+ * from NT4 servers. (See bug #8195)
+ */
+#define TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE 4280
+
+void tstream_smbXcli_np_set_max_data(struct tstream_context *stream,
+ uint32_t max_data);
+
+#endif /* _CLI_NP_TSTREAM_H_ */
diff --git a/libcli/smb/util.c b/libcli/smb/util.c
new file mode 100644
index 0000000..baae532
--- /dev/null
+++ b/libcli/smb/util.c
@@ -0,0 +1,716 @@
+/*
+ Unix SMB/CIFS implementation.
+ client file operations
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Jeremy Allison 2001-2002
+ Copyright (C) James Myers 2003
+
+ 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 "libcli/smb/smb_common.h"
+#include "system/filesys.h"
+#include "lib/param/loadparm.h"
+#include "lib/param/param.h"
+#include "libcli/smb/smb2_negotiate_context.h"
+
+const char *smb_protocol_types_string(enum protocol_types protocol)
+{
+ switch (protocol) {
+ case PROTOCOL_DEFAULT:
+ return "DEFAULT";
+ case PROTOCOL_NONE:
+ return "NONE";
+ case PROTOCOL_CORE:
+ return "CORE";
+ case PROTOCOL_COREPLUS:
+ return "COREPLUS";
+ case PROTOCOL_LANMAN1:
+ return "LANMAN1";
+ case PROTOCOL_LANMAN2:
+ return "LANMAN2";
+ case PROTOCOL_NT1:
+ return "NT1";
+ case PROTOCOL_SMB2_02:
+ return "SMB2_02";
+ case PROTOCOL_SMB2_10:
+ return "SMB2_10";
+ case PROTOCOL_SMB3_00:
+ return "SMB3_00";
+ case PROTOCOL_SMB3_02:
+ return "SMB3_02";
+ case PROTOCOL_SMB3_11:
+ return "SMB3_11";
+ }
+
+ return "Invalid protocol_types value";
+}
+
+/**
+ Return a string representing a CIFS attribute for a file.
+**/
+char *attrib_string(TALLOC_CTX *mem_ctx, uint32_t attrib)
+{
+ size_t i, len;
+ static const struct {
+ char c;
+ uint16_t attr;
+ } attr_strs[] = {
+ {'V', FILE_ATTRIBUTE_VOLUME},
+ {'D', FILE_ATTRIBUTE_DIRECTORY},
+ {'A', FILE_ATTRIBUTE_ARCHIVE},
+ {'H', FILE_ATTRIBUTE_HIDDEN},
+ {'S', FILE_ATTRIBUTE_SYSTEM},
+ {'N', FILE_ATTRIBUTE_NORMAL},
+ {'R', FILE_ATTRIBUTE_READONLY},
+ {'d', FILE_ATTRIBUTE_DEVICE},
+ {'t', FILE_ATTRIBUTE_TEMPORARY},
+ {'s', FILE_ATTRIBUTE_SPARSE},
+ {'r', FILE_ATTRIBUTE_REPARSE_POINT},
+ {'c', FILE_ATTRIBUTE_COMPRESSED},
+ {'o', FILE_ATTRIBUTE_OFFLINE},
+ {'n', FILE_ATTRIBUTE_NONINDEXED},
+ {'e', FILE_ATTRIBUTE_ENCRYPTED}
+ };
+ char *ret;
+
+ ret = talloc_array(mem_ctx, char, ARRAY_SIZE(attr_strs)+1);
+ if (!ret) {
+ return NULL;
+ }
+
+ for (len=i=0; i<ARRAY_SIZE(attr_strs); i++) {
+ if (attrib & attr_strs[i].attr) {
+ ret[len++] = attr_strs[i].c;
+ }
+ }
+
+ ret[len] = 0;
+
+ talloc_set_name_const(ret, ret);
+
+ return ret;
+}
+
+/****************************************************************************
+ Map standard UNIX permissions onto wire representations.
+****************************************************************************/
+
+uint32_t unix_perms_to_wire(mode_t perms)
+{
+ unsigned int ret = 0;
+
+ ret |= ((perms & S_IXOTH) ? UNIX_X_OTH : 0);
+ ret |= ((perms & S_IWOTH) ? UNIX_W_OTH : 0);
+ ret |= ((perms & S_IROTH) ? UNIX_R_OTH : 0);
+ ret |= ((perms & S_IXGRP) ? UNIX_X_GRP : 0);
+ ret |= ((perms & S_IWGRP) ? UNIX_W_GRP : 0);
+ ret |= ((perms & S_IRGRP) ? UNIX_R_GRP : 0);
+ ret |= ((perms & S_IXUSR) ? UNIX_X_USR : 0);
+ ret |= ((perms & S_IWUSR) ? UNIX_W_USR : 0);
+ ret |= ((perms & S_IRUSR) ? UNIX_R_USR : 0);
+#ifdef S_ISVTX
+ ret |= ((perms & S_ISVTX) ? UNIX_STICKY : 0);
+#endif
+#ifdef S_ISGID
+ ret |= ((perms & S_ISGID) ? UNIX_SET_GID : 0);
+#endif
+#ifdef S_ISUID
+ ret |= ((perms & S_ISUID) ? UNIX_SET_UID : 0);
+#endif
+ return ret;
+}
+
+/****************************************************************************
+ Map wire permissions to standard UNIX.
+****************************************************************************/
+
+mode_t wire_perms_to_unix(uint32_t perms)
+{
+ mode_t ret = (mode_t)0;
+
+ ret |= ((perms & UNIX_X_OTH) ? S_IXOTH : 0);
+ ret |= ((perms & UNIX_W_OTH) ? S_IWOTH : 0);
+ ret |= ((perms & UNIX_R_OTH) ? S_IROTH : 0);
+ ret |= ((perms & UNIX_X_GRP) ? S_IXGRP : 0);
+ ret |= ((perms & UNIX_W_GRP) ? S_IWGRP : 0);
+ ret |= ((perms & UNIX_R_GRP) ? S_IRGRP : 0);
+ ret |= ((perms & UNIX_X_USR) ? S_IXUSR : 0);
+ ret |= ((perms & UNIX_W_USR) ? S_IWUSR : 0);
+ ret |= ((perms & UNIX_R_USR) ? S_IRUSR : 0);
+#ifdef S_ISVTX
+ ret |= ((perms & UNIX_STICKY) ? S_ISVTX : 0);
+#endif
+#ifdef S_ISGID
+ ret |= ((perms & UNIX_SET_GID) ? S_ISGID : 0);
+#endif
+#ifdef S_ISUID
+ ret |= ((perms & UNIX_SET_UID) ? S_ISUID : 0);
+#endif
+ return ret;
+}
+
+/****************************************************************************
+ Return the file type from the wire filetype for UNIX extensions.
+****************************************************************************/
+
+mode_t unix_filetype_from_wire(uint32_t wire_type)
+{
+ switch (wire_type) {
+ case UNIX_TYPE_FILE:
+ return S_IFREG;
+ case UNIX_TYPE_DIR:
+ return S_IFDIR;
+#ifdef S_IFLNK
+ case UNIX_TYPE_SYMLINK:
+ return S_IFLNK;
+#endif
+#ifdef S_IFCHR
+ case UNIX_TYPE_CHARDEV:
+ return S_IFCHR;
+#endif
+#ifdef S_IFBLK
+ case UNIX_TYPE_BLKDEV:
+ return S_IFBLK;
+#endif
+#ifdef S_IFIFO
+ case UNIX_TYPE_FIFO:
+ return S_IFIFO;
+#endif
+#ifdef S_IFSOCK
+ case UNIX_TYPE_SOCKET:
+ return S_IFSOCK;
+#endif
+ default:
+ return (mode_t)0;
+ }
+}
+
+bool smb_buffer_oob(uint32_t bufsize, uint32_t offset, uint32_t length)
+{
+ if ((offset + length < offset) || (offset + length < length)) {
+ /* wrap */
+ return true;
+ }
+ if ((offset > bufsize) || (offset + length > bufsize)) {
+ /* overflow */
+ return true;
+ }
+ return false;
+}
+
+/***********************************************************
+ Common function for pushing strings, used by smb_bytes_push_str()
+ and trans_bytes_push_str(). Only difference is the align_odd
+ parameter setting.
+***********************************************************/
+
+static uint8_t *internal_bytes_push_str(uint8_t *buf, bool ucs2,
+ const char *str, size_t str_len,
+ bool align_odd,
+ size_t *pconverted_size)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ size_t buflen;
+ char *converted;
+ size_t converted_size;
+
+ /*
+ * This check prevents us from
+ * (re)alloc buf on a NULL TALLOC_CTX.
+ */
+ if (buf == NULL) {
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ buflen = talloc_get_size(buf);
+
+ if (ucs2 &&
+ ((align_odd && (buflen % 2 == 0)) ||
+ (!align_odd && (buflen % 2 == 1)))) {
+ /*
+ * We're pushing into an SMB buffer, align odd
+ */
+ buf = talloc_realloc(NULL, buf, uint8_t, buflen + 1);
+ if (buf == NULL) {
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+ buf[buflen] = '\0';
+ buflen += 1;
+ }
+
+ if (!convert_string_talloc(frame, CH_UNIX,
+ ucs2 ? CH_UTF16LE : CH_DOS,
+ str, str_len, &converted,
+ &converted_size)) {
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ buf = talloc_realloc(NULL, buf, uint8_t,
+ buflen + converted_size);
+ if (buf == NULL) {
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ memcpy(buf + buflen, converted, converted_size);
+
+ TALLOC_FREE(converted);
+
+ if (pconverted_size) {
+ *pconverted_size = converted_size;
+ }
+
+ TALLOC_FREE(frame);
+ return buf;
+}
+
+/***********************************************************
+ Push a string into an SMB buffer, with odd byte alignment
+ if it's a UCS2 string.
+***********************************************************/
+
+uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2,
+ const char *str, size_t str_len,
+ size_t *pconverted_size)
+{
+ return internal_bytes_push_str(buf, ucs2, str, str_len,
+ true, pconverted_size);
+}
+
+uint8_t *smb_bytes_push_bytes(uint8_t *buf, uint8_t prefix,
+ const uint8_t *bytes, size_t num_bytes)
+{
+ size_t buflen;
+
+ /*
+ * This check prevents us from
+ * (re)alloc buf on a NULL TALLOC_CTX.
+ */
+ if (buf == NULL) {
+ return NULL;
+ }
+ buflen = talloc_get_size(buf);
+
+ buf = talloc_realloc(NULL, buf, uint8_t,
+ buflen + 1 + num_bytes);
+ if (buf == NULL) {
+ return NULL;
+ }
+ buf[buflen] = prefix;
+ memcpy(&buf[buflen+1], bytes, num_bytes);
+ return buf;
+}
+
+/***********************************************************
+ Same as smb_bytes_push_str(), but without the odd byte
+ align for ucs2 (we're pushing into a param or data block).
+ static for now, although this will probably change when
+ other modules use async trans calls.
+***********************************************************/
+
+uint8_t *trans2_bytes_push_str(uint8_t *buf, bool ucs2,
+ const char *str, size_t str_len,
+ size_t *pconverted_size)
+{
+ return internal_bytes_push_str(buf, ucs2, str, str_len,
+ false, pconverted_size);
+}
+
+uint8_t *trans2_bytes_push_bytes(uint8_t *buf,
+ const uint8_t *bytes, size_t num_bytes)
+{
+ size_t buflen;
+
+ if (buf == NULL) {
+ return NULL;
+ }
+ buflen = talloc_get_size(buf);
+
+ buf = talloc_realloc(NULL, buf, uint8_t,
+ buflen + num_bytes);
+ if (buf == NULL) {
+ return NULL;
+ }
+ memcpy(&buf[buflen], bytes, num_bytes);
+ return buf;
+}
+
+static NTSTATUS internal_bytes_pull_str(TALLOC_CTX *mem_ctx, char **_str,
+ bool ucs2, bool align_odd,
+ const uint8_t *buf, size_t buf_len,
+ const uint8_t *position,
+ size_t *p_consumed)
+{
+ size_t pad = 0;
+ size_t offset;
+ char *str = NULL;
+ size_t str_len = 0;
+ bool ok;
+
+ *_str = NULL;
+ if (p_consumed != NULL) {
+ *p_consumed = 0;
+ }
+
+ if (position < buf) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ offset = PTR_DIFF(position, buf);
+ if (offset > buf_len) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if (ucs2 &&
+ ((align_odd && (offset % 2 == 0)) ||
+ (!align_odd && (offset % 2 == 1)))) {
+ pad += 1;
+ offset += 1;
+ }
+
+ if (offset > buf_len) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ buf_len -= offset;
+ buf += offset;
+
+ if (ucs2) {
+ buf_len = utf16_null_terminated_len_n(buf, buf_len);
+ } else {
+ size_t tmp = strnlen((const char *)buf, buf_len);
+ if (tmp < buf_len) {
+ tmp += 1;
+ }
+ buf_len = tmp;
+ }
+
+ ok = convert_string_talloc(mem_ctx,
+ ucs2 ? CH_UTF16LE : CH_DOS,
+ CH_UNIX,
+ buf, buf_len,
+ &str, &str_len);
+ if (!ok) {
+ return map_nt_error_from_unix_common(errno);
+ }
+
+ if (p_consumed != NULL) {
+ *p_consumed = buf_len + pad;
+ }
+ *_str = str;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb_bytes_pull_str(TALLOC_CTX *mem_ctx, char **_str, bool ucs2,
+ const uint8_t *buf, size_t buf_len,
+ const uint8_t *position,
+ size_t *_consumed)
+{
+ return internal_bytes_pull_str(mem_ctx, _str, ucs2, true,
+ buf, buf_len, position, _consumed);
+}
+
+/**
+ * @brief Translate SMB signing settings as string to an enum.
+ *
+ * @param[in] str The string to translate.
+ *
+ * @return A corresponding enum @smb_signing_setting translated from the string.
+ */
+enum smb_signing_setting smb_signing_setting_translate(const char *str)
+{
+ enum smb_signing_setting signing_state = SMB_SIGNING_REQUIRED;
+ int32_t val = lpcfg_parse_enum_vals("client signing", str);
+
+ if (val != INT32_MIN) {
+ signing_state = val;
+ }
+
+ return signing_state;
+}
+
+/**
+ * @brief Translate SMB encryption settings as string to an enum.
+ *
+ * @param[in] str The string to translate.
+ *
+ * @return A corresponding enum @smb_encryption_setting translated from the
+ * string.
+ */
+enum smb_encryption_setting smb_encryption_setting_translate(const char *str)
+{
+ enum smb_encryption_setting encryption_state = SMB_ENCRYPTION_REQUIRED;
+ int32_t val = lpcfg_parse_enum_vals("client smb encrypt", str);
+
+ if (val != INT32_MIN) {
+ encryption_state = val;
+ }
+
+ return encryption_state;
+}
+
+static const struct enum_list enum_smb3_signing_algorithms[] = {
+ {SMB2_SIGNING_AES128_GMAC, "AES-128-GMAC"},
+ {SMB2_SIGNING_AES128_CMAC, "AES-128-CMAC"},
+ {SMB2_SIGNING_HMAC_SHA256, "HMAC-SHA256"},
+ {-1, NULL}
+};
+
+const char *smb3_signing_algorithm_name(uint16_t algo)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(enum_smb3_signing_algorithms); i++) {
+ if (enum_smb3_signing_algorithms[i].value != algo) {
+ continue;
+ }
+
+ return enum_smb3_signing_algorithms[i].name;
+ }
+
+ return NULL;
+}
+
+static const struct enum_list enum_smb3_encryption_algorithms[] = {
+ {SMB2_ENCRYPTION_AES128_GCM, "AES-128-GCM"},
+ {SMB2_ENCRYPTION_AES128_CCM, "AES-128-CCM"},
+ {SMB2_ENCRYPTION_AES256_GCM, "AES-256-GCM"},
+ {SMB2_ENCRYPTION_AES256_CCM, "AES-256-CCM"},
+ {-1, NULL}
+};
+
+const char *smb3_encryption_algorithm_name(uint16_t algo)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(enum_smb3_encryption_algorithms); i++) {
+ if (enum_smb3_encryption_algorithms[i].value != algo) {
+ continue;
+ }
+
+ return enum_smb3_encryption_algorithms[i].name;
+ }
+
+ return NULL;
+}
+
+static int32_t parse_enum_val(const struct enum_list *e,
+ const char *param_name,
+ const char *param_value)
+{
+ struct parm_struct parm = {
+ .label = param_name,
+ .type = P_LIST,
+ .p_class = P_GLOBAL,
+ .enum_list = e,
+ };
+ int32_t ret = INT32_MIN;
+ bool ok;
+
+ ok = lp_set_enum_parm(&parm, param_value, &ret);
+ if (!ok) {
+ return INT32_MIN;
+ }
+
+ return ret;
+}
+
+struct smb311_capabilities smb311_capabilities_parse(const char *role,
+ const char * const *signing_algos,
+ const char * const *encryption_algos)
+{
+ struct smb311_capabilities c = {
+ .signing = {
+ .num_algos = 0,
+ },
+ .encryption = {
+ .num_algos = 0,
+ },
+ };
+ char sign_param[64] = { 0, };
+ char enc_param[64] = { 0, };
+ size_t ai;
+
+ snprintf(sign_param, sizeof(sign_param),
+ "%s smb3 signing algorithms", role);
+ snprintf(enc_param, sizeof(enc_param),
+ "%s smb3 encryption algorithms", role);
+
+ for (ai = 0; signing_algos != NULL && signing_algos[ai] != NULL; ai++) {
+ const char *algoname = signing_algos[ai];
+ int32_t v32;
+ uint16_t algo;
+ size_t di;
+ bool ignore = false;
+
+ if (c.signing.num_algos >= SMB3_ENCRYTION_CAPABILITIES_MAX_ALGOS) {
+ DBG_ERR("WARNING: Ignoring trailing value '%s' for parameter '%s'\n",
+ algoname, sign_param);
+ continue;
+ }
+
+ v32 = parse_enum_val(enum_smb3_signing_algorithms,
+ sign_param, algoname);
+ if (v32 == INT32_MAX) {
+ continue;
+ }
+ algo = v32;
+
+ for (di = 0; di < c.signing.num_algos; di++) {
+ if (algo != c.signing.algos[di]) {
+ continue;
+ }
+
+ ignore = true;
+ break;
+ }
+
+ if (ignore) {
+ DBG_ERR("WARNING: Ignoring duplicate value '%s' for parameter '%s'\n",
+ algoname, sign_param);
+ continue;
+ }
+
+ c.signing.algos[c.signing.num_algos] = algo;
+ c.signing.num_algos += 1;
+ }
+
+ for (ai = 0; encryption_algos != NULL && encryption_algos[ai] != NULL; ai++) {
+ const char *algoname = encryption_algos[ai];
+ int32_t v32;
+ uint16_t algo;
+ size_t di;
+ bool ignore = false;
+
+ if (c.encryption.num_algos >= SMB3_ENCRYTION_CAPABILITIES_MAX_ALGOS) {
+ DBG_ERR("WARNING: Ignoring trailing value '%s' for parameter '%s'\n",
+ algoname, enc_param);
+ continue;
+ }
+
+ v32 = parse_enum_val(enum_smb3_encryption_algorithms,
+ enc_param, algoname);
+ if (v32 == INT32_MAX) {
+ continue;
+ }
+ algo = v32;
+
+ for (di = 0; di < c.encryption.num_algos; di++) {
+ if (algo != c.encryption.algos[di]) {
+ continue;
+ }
+
+ ignore = true;
+ break;
+ }
+
+ if (ignore) {
+ DBG_ERR("WARNING: Ignoring duplicate value '%s' for parameter '%s'\n",
+ algoname, enc_param);
+ continue;
+ }
+
+ c.encryption.algos[c.encryption.num_algos] = algo;
+ c.encryption.num_algos += 1;
+ }
+
+ return c;
+}
+
+NTSTATUS smb311_capabilities_check(const struct smb311_capabilities *c,
+ const char *debug_prefix,
+ int debug_lvl,
+ NTSTATUS error_status,
+ const char *role,
+ enum protocol_types protocol,
+ uint16_t sign_algo,
+ uint16_t cipher_algo)
+{
+ const struct smb3_signing_capabilities *sign_algos =
+ &c->signing;
+ const struct smb3_encryption_capabilities *ciphers =
+ &c->encryption;
+ bool found_signing = false;
+ bool found_encryption = false;
+ size_t i;
+
+ for (i = 0; i < sign_algos->num_algos; i++) {
+ if (sign_algo == sign_algos->algos[i]) {
+ /*
+ * We found a match
+ */
+ found_signing = true;
+ break;
+ }
+ }
+
+ for (i = 0; i < ciphers->num_algos; i++) {
+ if (cipher_algo == SMB2_ENCRYPTION_NONE) {
+ /*
+ * encryption not supported, we'll error out later
+ */
+ found_encryption = true;
+ break;
+ }
+
+ if (cipher_algo == ciphers->algos[i]) {
+ /*
+ * We found a match
+ */
+ found_encryption = true;
+ break;
+ }
+ }
+
+ if (!found_signing) {
+ /*
+ * We negotiated a signing algo we don't allow,
+ * most likely for SMB < 3.1.1
+ */
+ DEBUG(debug_lvl,("%s: "
+ "SMB3 signing algorithm[%u][%s] on dialect[%s] "
+ "not allowed by '%s smb3 signing algorithms' - %s.\n",
+ debug_prefix,
+ sign_algo,
+ smb3_signing_algorithm_name(sign_algo),
+ smb_protocol_types_string(protocol),
+ role,
+ nt_errstr(error_status)));
+ return error_status;
+ }
+
+ if (!found_encryption) {
+ /*
+ * We negotiated a cipher we don't allow,
+ * most likely for SMB 3.0 and 3.0.2
+ */
+ DEBUG(debug_lvl,("%s: "
+ "SMB3 encryption algorithm[%u][%s] on dialect[%s] "
+ "not allowed by '%s smb3 encryption algorithms' - %s.\n",
+ debug_prefix,
+ cipher_algo,
+ smb3_encryption_algorithm_name(cipher_algo),
+ smb_protocol_types_string(protocol),
+ role,
+ nt_errstr(error_status)));
+ return error_status;
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/libcli/smb/wscript b/libcli/smb/wscript
new file mode 100644
index 0000000..9849284
--- /dev/null
+++ b/libcli/smb/wscript
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+
+
+def build(bld):
+ bld.SAMBA_LIBRARY('smb_transport',
+ source='''
+ read_smb.c
+ ''',
+ deps='LIBASYNC_REQ',
+ public_deps='talloc tevent',
+ private_library=True,
+ private_headers='''
+ read_smb.h
+ ''',
+ )
+
+ bld.SAMBA_LIBRARY('cli_smb_common',
+ source='''
+ smb_signing.c
+ smb_seal.c
+ smb2_negotiate_context.c
+ smb2_create_blob.c smb2_signing.c
+ smb2_lease.c
+ util.c
+ smbXcli_base.c
+ smb1cli_trans.c
+ smb1cli_echo.c
+ smb1cli_create.c
+ smb1cli_session.c
+ smb1cli_close.c
+ smb1cli_write.c
+ smb1cli_read.c
+ smb2cli_session.c
+ smb2cli_tcon.c
+ smb2cli_create.c
+ smb2cli_close.c
+ smb2cli_read.c
+ smb2cli_write.c
+ smb2cli_flush.c
+ smb2cli_set_info.c
+ smb2cli_query_info.c
+ smb2cli_notify.c
+ smb2cli_query_directory.c
+ smb2cli_ioctl.c
+ smb2cli_echo.c
+ smb2_posix.c
+ tstream_smbXcli_np.c
+ reparse.c
+ ''',
+ deps='''
+ LIBCRYPTO gnutls NDR_SMB2_LEASE_STRUCT samba-errors gensec krb5samba
+ smb_transport GNUTLS_HELPERS NDR_IOCTL
+ ''',
+ public_deps='talloc samba-util iov_buf',
+ private_library=True,
+ private_headers='''
+ smb_common.h
+ smb2_constants.h
+ smb_constants.h
+ smb_signing.h
+ smb_seal.h
+ smb2_create_blob.h
+ smb2_signing.h
+ smb2_lease.h
+ smb_util.h
+ smb_unix_ext.h
+ smb_posix.h
+ tstream_smbXcli_np.h
+ ''',
+ )
+
+ bld.SAMBA_BINARY('test_smb1cli_session',
+ source='test_smb1cli_session.c',
+ deps='cmocka cli_smb_common',
+ for_selftest=True)
+
+ bld.SAMBA_BINARY('test_util_translate',
+ source='test_util_translate.c',
+ deps='cmocka cli_smb_common',
+ for_selftest=True)
+
+ bld.SAMBA_PYTHON('py_reparse_symlink',
+ source='py_reparse_symlink.c',
+ deps='cli_smb_common',
+ realname='samba/reparse_symlink.so'
+ )
diff --git a/libcli/smbreadline/smbreadline.c b/libcli/smbreadline/smbreadline.c
new file mode 100644
index 0000000..0a95c63
--- /dev/null
+++ b/libcli/smbreadline/smbreadline.c
@@ -0,0 +1,184 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba readline wrapper implementation
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Andrew Tridgell 2001
+
+ 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 "../lib/util/select.h"
+#include "system/filesys.h"
+#include "system/select.h"
+#include "system/readline.h"
+#include "libcli/smbreadline/smbreadline.h"
+
+#undef malloc
+
+#ifdef HAVE_LIBREADLINE
+# ifdef HAVE_READLINE_READLINE_H
+# include <readline/readline.h>
+# ifdef HAVE_READLINE_HISTORY_H
+# include <readline/history.h>
+# endif
+# else
+# ifdef HAVE_READLINE_H
+# include <readline.h>
+# ifdef HAVE_HISTORY_H
+# include <history.h>
+# endif
+# else
+# undef HAVE_LIBREADLINE
+# endif
+# endif
+#endif
+
+static bool smb_rl_done;
+
+#ifdef HAVE_LIBREADLINE
+/*
+ * MacOS/X does not have rl_done in readline.h, but
+ * readline.so has it
+ */
+extern int rl_done;
+#endif
+
+void smb_readline_done(void)
+{
+ smb_rl_done = true;
+#ifdef HAVE_LIBREADLINE
+ rl_done = 1;
+#endif
+}
+
+/****************************************************************************
+ Display the prompt and wait for input. Call callback() regularly
+****************************************************************************/
+
+static char *smb_readline_replacement(const char *prompt, void (*callback)(void),
+ char **(completion_fn)(const char *text, int start, int end))
+{
+ char *line = NULL;
+ int fd = fileno(stdin);
+ char *ret;
+
+ /* Prompt might be NULL in non-interactive mode. */
+ if (prompt) {
+ printf("%s", prompt);
+ fflush(stdout);
+ }
+
+ line = (char *)malloc(BUFSIZ);
+ if (!line) {
+ return NULL;
+ }
+
+ while (!smb_rl_done) {
+ struct pollfd pfd;
+
+ ZERO_STRUCT(pfd);
+ pfd.fd = fd;
+ pfd.events = POLLIN|POLLHUP;
+
+ if (sys_poll_intr(&pfd, 1, 5000) == 1) {
+ ret = fgets(line, BUFSIZ, stdin);
+ if (ret == 0) {
+ SAFE_FREE(line);
+ }
+ return ret;
+ }
+ if (callback) {
+ callback();
+ }
+ }
+ SAFE_FREE(line);
+ return NULL;
+}
+
+/****************************************************************************
+ Display the prompt and wait for input. Call callback() regularly.
+****************************************************************************/
+
+char *smb_readline(const char *prompt, void (*callback)(void),
+ char **(completion_fn)(const char *text, int start, int end))
+{
+ char *ret;
+ bool interactive;
+
+ interactive = isatty(fileno(stdin)) || getenv("CLI_FORCE_INTERACTIVE");
+ if (!interactive) {
+ return smb_readline_replacement(NULL, callback, completion_fn);
+ }
+
+#ifdef HAVE_LIBREADLINE
+
+ /* Aargh! Readline does bizarre things with the terminal width
+ that mucks up expect(1). Set CLI_NO_READLINE in the environment
+ to force readline not to be used. */
+
+ if (getenv("CLI_NO_READLINE"))
+ return smb_readline_replacement(prompt, callback, completion_fn);
+
+ if (completion_fn) {
+ /* The callback prototype has changed slightly between
+ different versions of Readline, so the same function
+ works in all of them to date, but we get compiler
+ warnings in some. */
+ rl_attempted_completion_function = RL_COMPLETION_CAST completion_fn;
+
+ /*
+ * We only want sensible characters as the word-break chars
+ * for the most part. This allows us to tab through a path.
+ */
+ rl_basic_word_break_characters = " \t\n";
+ }
+
+#ifdef HAVE_DECL_RL_EVENT_HOOK
+ if (callback)
+ rl_event_hook = (rl_hook_func_t *)callback;
+#endif
+ ret = readline(prompt);
+ if (ret && *ret)
+ add_history(ret);
+
+#else
+ ret = smb_readline_replacement(prompt, callback, completion_fn);
+#endif
+
+ return ret;
+}
+
+/****************************************************************************
+ * return line buffer text
+ ****************************************************************************/
+const char *smb_readline_get_line_buffer(void)
+{
+#if defined(HAVE_LIBREADLINE)
+ return rl_line_buffer;
+#else
+ return NULL;
+#endif
+}
+
+
+/****************************************************************************
+ * set completion append character
+ ***************************************************************************/
+void smb_readline_ca_char(char c)
+{
+#if defined(HAVE_LIBREADLINE)
+ rl_completion_append_character = c;
+#endif
+}
diff --git a/libcli/smbreadline/smbreadline.h b/libcli/smbreadline/smbreadline.h
new file mode 100644
index 0000000..9adc4b3
--- /dev/null
+++ b/libcli/smbreadline/smbreadline.h
@@ -0,0 +1,30 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba readline wrapper implementation
+ Copyright (C) Simo Sorce 2001
+ Copyright (C) Andrew Tridgell 2001
+
+ 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/>.
+*/
+
+#ifndef __SMBREADLINE_H__
+#define __SMBREADLINE_H__
+
+char *smb_readline(const char *prompt, void (*callback)(void),
+ char **(completion_fn)(const char *text, int start, int end));
+const char *smb_readline_get_line_buffer(void);
+void smb_readline_ca_char(char c);
+void smb_readline_done(void);
+
+#endif /* __SMBREADLINE_H__ */
diff --git a/libcli/smbreadline/wscript_build b/libcli/smbreadline/wscript_build
new file mode 100644
index 0000000..17699ea
--- /dev/null
+++ b/libcli/smbreadline/wscript_build
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+
+
+termlib=bld.env.READLINE_TERMLIB or ''
+
+bld.SAMBA_SUBSYSTEM('SMBREADLINE',
+ source='smbreadline.c',
+ deps=termlib + ' readline talloc')
diff --git a/libcli/smbreadline/wscript_configure b/libcli/smbreadline/wscript_configure
new file mode 100644
index 0000000..912ff53
--- /dev/null
+++ b/libcli/smbreadline/wscript_configure
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+
+
+conf.CHECK_HEADERS('readline.h history.h readline/readline.h readline/history.h')
+for termlib in ['ncurses', 'curses', 'termcap', 'terminfo', 'termlib', 'tinfo']:
+ if conf.CHECK_FUNCS_IN('tgetent', termlib):
+ conf.env['READLINE_TERMLIB'] = termlib
+ break
+
+#
+# Check if we need to work around readline/readline.h
+# deprecated declarations
+#
+if conf.CONFIG_SET('HAVE_READLINE_READLINE_H'):
+ if not conf.CHECK_CODE('''
+ #include <readline/readline.h>
+ int main() {return 0;}
+ ''',
+ define='HAVE_WORKING_READLINE_READLINE_WITH_STRICT_PROTO',
+ cflags=conf.env['WERROR_CFLAGS'] +
+ ['-Wstrict-prototypes',
+ '-Werror=strict-prototypes'],
+ msg='for compiling <readline/readline.h> with strict prototypes',
+ addmain=False):
+ conf.CHECK_CODE('''
+ #define _FUNCTION_DEF
+ #include <readline/readline.h>
+ int main() {return 0;}
+ ''',
+ cflags=conf.env['WERROR_CFLAGS'] +
+ ['-Wstrict-prototypes',
+ '-Werror=strict-prototypes'],
+ msg='for workaround to <readline/readline.h> strict prototypes issue',
+ define='HAVE_READLINE_READLINE_WORKAROUND',
+ addmain=False)
+
+conf.CHECK_CODE('''
+#ifdef HAVE_READLINE_READLINE_H
+# ifdef HAVE_READLINE_READLINE_WORKAROUND
+# define _FUNCTION_DEF
+# endif
+# include <readline/readline.h>
+# ifdef HAVE_READLINE_HISTORY_H
+# include <readline/history.h>
+# endif
+#else
+# ifdef HAVE_READLINE_H
+# include <readline.h>
+# ifdef HAVE_HISTORY_H
+# include <history.h>
+# endif
+# endif
+#endif
+int main(void) {rl_completion_t f; return 0;}
+''',
+'HAVE_RL_COMPLETION_FUNC_T', execute=False, addmain=False,
+msg='Checking for rl_completion_t')
+
+conf.CHECK_CODE('''
+#ifdef HAVE_READLINE_READLINE_H
+# ifdef HAVE_READLINE_READLINE_WORKAROUND
+# define _FUNCTION_DEF
+# endif
+# include <readline/readline.h>
+# ifdef HAVE_READLINE_HISTORY_H
+# include <readline/history.h>
+# endif
+#else
+# ifdef HAVE_READLINE_H
+# include <readline.h>
+# ifdef HAVE_HISTORY_H
+# include <history.h>
+# endif
+# endif
+#endif
+int main(void) {CPPFunction f; return 0;}
+''',
+'HAVE_CPPFUNCTION', execute=False, addmain=False,
+msg='Checking for CPPFunction')
+
+if conf.CHECK_FUNCS_IN('rl_completion_matches', 'readline'):
+ conf.DEFINE('HAVE_NEW_LIBREADLINE', 1)
+
+if conf.CHECK_FUNCS_IN('history_list', 'readline'):
+ conf.DEFINE('HAVE_HISTORY_LIST', 1)
diff --git a/libcli/tstream_binding_handle/tstream_binding_handle.c b/libcli/tstream_binding_handle/tstream_binding_handle.c
new file mode 100644
index 0000000..76f54a7
--- /dev/null
+++ b/libcli/tstream_binding_handle/tstream_binding_handle.c
@@ -0,0 +1,341 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Ralph Boehme 2016
+
+ 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 <tevent.h>
+#include "libcli/tstream_binding_handle/tstream_binding_handle.h"
+#include "system/filesys.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "lib/tsocket/tsocket.h"
+#include "lib/util/debug.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "libcli/smb/tstream_smbXcli_np.h"
+
+struct tstream_bh_state {
+ struct tstream_context *stream;
+ struct tevent_queue *write_queue;
+ const struct ndr_interface_table *table;
+ uint32_t request_timeout;
+ size_t call_initial_read_size;
+ tstream_read_pdu_blob_full_fn_t *complete_pdu_fn;
+ void *complete_pdu_fn_private;
+};
+
+static bool tstream_bh_is_connected(struct dcerpc_binding_handle *h)
+{
+ struct tstream_bh_state *hs = dcerpc_binding_handle_data(
+ h, struct tstream_bh_state);
+ ssize_t ret;
+
+ if (hs->stream == NULL) {
+ return false;
+ }
+
+ ret = tstream_pending_bytes(hs->stream);
+ if (ret == -1) {
+ return false;
+ }
+
+ return true;
+}
+
+static uint32_t tstream_bh_set_timeout(struct dcerpc_binding_handle *h,
+ uint32_t timeout)
+{
+ struct tstream_bh_state *hs = dcerpc_binding_handle_data(
+ h, struct tstream_bh_state);
+ uint32_t old;
+
+ old = hs->request_timeout;
+ hs->request_timeout = timeout;
+
+ return old;
+}
+
+struct tstream_bh_disconnect_state {
+ struct tstream_bh_state *hs;
+};
+
+static void tstream_bh_disconnect_done(struct tevent_req *subreq);
+
+static struct tevent_req *tstream_bh_disconnect_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct dcerpc_binding_handle *h)
+{
+ struct tstream_bh_state *hs = dcerpc_binding_handle_data(
+ h, struct tstream_bh_state);
+ struct tevent_req *req = NULL;
+ struct tstream_bh_disconnect_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+ bool ok;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_bh_disconnect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->hs = hs;
+
+ ok = tstream_bh_is_connected(h);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = tstream_disconnect_send(state, ev, hs->stream);
+ if (tevent_req_nomem(subreq, req)) {
+ tevent_req_post(req, ev);
+ return req;
+ }
+ tevent_req_set_callback(subreq, tstream_bh_disconnect_done, req);
+
+ return req;
+}
+
+static void tstream_bh_disconnect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct tstream_bh_disconnect_state *state = tevent_req_data(
+ req, struct tstream_bh_disconnect_state);
+ int ret, err;
+
+ ret = tstream_disconnect_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (ret != 0) {
+ DBG_ERR("tstream_bh_disconnect failed [%s]\n", strerror(err));
+ tevent_req_nterror(req, map_nt_error_from_unix_common(err));
+ return;
+ }
+
+ state->hs->stream = NULL;
+}
+
+static NTSTATUS tstream_bh_disconnect_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+struct tstream_bh_call_state {
+ struct tevent_context *ev;
+ struct tstream_context *stream;
+ struct tstream_bh_state *hs;
+ struct iovec out_data;
+ DATA_BLOB in_data;
+};
+
+static void tstream_bh_call_writev_done(struct tevent_req *subreq);
+static void tstream_bh_call_read_pdu_done(struct tevent_req *subreq);
+
+static struct tevent_req *tstream_bh_call_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct dcerpc_binding_handle *h,
+ const struct GUID *object,
+ uint32_t opnum,
+ uint32_t in_flags,
+ const uint8_t *out_data,
+ size_t out_length)
+{
+ struct tstream_bh_state *hs = dcerpc_binding_handle_data(
+ h, struct tstream_bh_state);
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ struct tstream_bh_call_state* state = NULL;
+ struct timeval timeout;
+ bool ok;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_bh_call_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ *state = (struct tstream_bh_call_state) {
+ .ev = ev,
+ .stream = hs->stream,
+ .hs = hs,
+ .out_data = {
+ .iov_base = discard_const_p(uint8_t, out_data),
+ .iov_len = out_length,
+ },
+ };
+
+ ok = tstream_bh_is_connected(h);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
+ return tevent_req_post(req, ev);
+ }
+
+ if (tstream_is_smbXcli_np(hs->stream)) {
+ tstream_smbXcli_np_use_trans(hs->stream);
+ }
+ if (tevent_queue_length(hs->write_queue) > 0) {
+ tevent_req_nterror(req, NT_STATUS_PIPE_BUSY);
+ }
+
+ timeout = timeval_current_ofs(hs->request_timeout, 0);
+
+ subreq = tstream_writev_queue_send(state, ev,
+ state->stream,
+ hs->write_queue,
+ &state->out_data, 1);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ if (!tevent_req_set_endtime(subreq, ev, timeout)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, tstream_bh_call_writev_done, req);
+
+ subreq = tstream_read_pdu_blob_send(state,
+ ev,
+ hs->stream,
+ hs->call_initial_read_size,
+ hs->complete_pdu_fn,
+ hs->complete_pdu_fn_private);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ if (!tevent_req_set_endtime(subreq, ev, timeout)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, tstream_bh_call_read_pdu_done, req);
+
+ return req;
+}
+
+static void tstream_bh_call_writev_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct tstream_bh_call_state *state = tevent_req_data(
+ req, struct tstream_bh_call_state);
+ int ret, err;
+
+ ret = tstream_writev_queue_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ state->hs->stream = NULL;
+ tevent_req_nterror(req, map_nt_error_from_unix_common(err));
+ return;
+ }
+}
+
+static void tstream_bh_call_read_pdu_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct tstream_bh_call_state *state = tevent_req_data(
+ req, struct tstream_bh_call_state);
+ NTSTATUS status;
+
+ status = tstream_read_pdu_blob_recv(subreq, state, &state->in_data);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ state->hs->stream = NULL;
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static NTSTATUS tstream_bh_call_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **in_data,
+ size_t *in_length,
+ uint32_t *in_flags)
+{
+ NTSTATUS status;
+ struct tstream_bh_call_state *state = tevent_req_data(
+ req, struct tstream_bh_call_state);
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ *in_data = talloc_move(mem_ctx, &state->in_data.data);
+ *in_length = state->in_data.length;
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+static const struct dcerpc_binding_handle_ops tstream_bh_ops = {
+ .name = "tstream_binding_handle",
+ .is_connected = tstream_bh_is_connected,
+ .set_timeout = tstream_bh_set_timeout,
+ .raw_call_send = tstream_bh_call_send,
+ .raw_call_recv = tstream_bh_call_recv,
+ .disconnect_send = tstream_bh_disconnect_send,
+ .disconnect_recv = tstream_bh_disconnect_recv,
+};
+
+struct dcerpc_binding_handle *tstream_binding_handle_create(
+ TALLOC_CTX *mem_ctx,
+ const struct ndr_interface_table *table,
+ struct tstream_context **stream,
+ size_t call_initial_read_size,
+ tstream_read_pdu_blob_full_fn_t *complete_pdu_fn,
+ void *complete_pdu_fn_private,
+ uint32_t max_data)
+{
+ struct dcerpc_binding_handle *h = NULL;
+ struct tstream_bh_state *hs = NULL;
+
+ h = dcerpc_binding_handle_create(mem_ctx,
+ &tstream_bh_ops,
+ NULL,
+ table,
+ &hs,
+ struct tstream_bh_state,
+ __location__);
+ if (h == NULL) {
+ return NULL;
+ }
+
+ hs->table = table;
+ hs->stream = talloc_move(hs, stream);
+ hs->call_initial_read_size = call_initial_read_size;
+ hs->complete_pdu_fn = complete_pdu_fn;
+ hs->complete_pdu_fn_private = complete_pdu_fn_private;
+
+ hs->write_queue = tevent_queue_create(hs, "write_queue");
+ if (hs->write_queue == NULL) {
+ TALLOC_FREE(h);
+ return NULL;
+ }
+
+ if (max_data > 0) {
+ tstream_smbXcli_np_set_max_data(hs->stream, max_data);
+ }
+
+ return h;
+}
diff --git a/libcli/tstream_binding_handle/tstream_binding_handle.h b/libcli/tstream_binding_handle/tstream_binding_handle.h
new file mode 100644
index 0000000..e540737
--- /dev/null
+++ b/libcli/tstream_binding_handle/tstream_binding_handle.h
@@ -0,0 +1,37 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Ralph Boehme 2016
+
+ 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/>.
+*/
+
+#ifndef _TSTREAM_BINDING_HANDLE_H_
+#define _TSTREAM_BINDING_HANDLE_H_
+
+#include <talloc.h>
+#include "librpc/rpc/dcerpc.h"
+#include "librpc/rpc/rpc_common.h"
+#include "libcli/util/tstream.h"
+
+struct dcerpc_binding_handle *tstream_binding_handle_create(
+ TALLOC_CTX *mem_ctx,
+ const struct ndr_interface_table *table,
+ struct tstream_context **stream,
+ size_t call_initial_read_size,
+ tstream_read_pdu_blob_full_fn_t *complete_pdu_fn,
+ void *complete_pdu_fn_private,
+ uint32_t max_data);
+
+#endif /* _TSTREAM_BINDING_HANDLE_H_ */
diff --git a/libcli/tstream_binding_handle/wscript_build b/libcli/tstream_binding_handle/wscript_build
new file mode 100644
index 0000000..622ed70
--- /dev/null
+++ b/libcli/tstream_binding_handle/wscript_build
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+bld.SAMBA_SUBSYSTEM('tstream_binding_handle',
+ source='tstream_binding_handle.c',
+ deps='tevent LIBTSOCKET')
diff --git a/libcli/util/doserr.c b/libcli/util/doserr.c
new file mode 100644
index 0000000..c30abc8
--- /dev/null
+++ b/libcli/util/doserr.c
@@ -0,0 +1,147 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * DOS error routines
+ * Copyright (C) Tim Potter 2002.
+ *
+ * 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/>.
+ */
+
+/* DOS error codes. please read doserr.h */
+
+#include "replace.h"
+#include "libcli/util/werror.h"
+#include "libcli/util/hresult.h"
+
+struct werror_code_struct {
+ const char *dos_errstr;
+ WERROR werror;
+};
+
+struct werror_str_struct {
+ WERROR werror;
+ const char *friendly_errstr;
+};
+
+static const struct werror_code_struct special_errs[] =
+{
+ { "WERR_DNS_ERROR_NOT_ALLOWED_ON_ACTIVE_SKD", WERR_DNS_ERROR_NOT_ALLOWED_ON_ACTIVE_SKD },
+ { "WERR_DNS_ERROR_INVALID_NSEC3_PARAMETERS", WERR_DNS_ERROR_INVALID_NSEC3_PARAMETERS },
+ { "WERR_DNS_ERROR_DNSSEC_IS_DISABLED", WERR_DNS_ERROR_DNSSEC_IS_DISABLED },
+ { "WERR_DNS_ERROR_NOT_ALLOWED_ON_UNSIGNED_ZONE", WERR_DNS_ERROR_NOT_ALLOWED_ON_UNSIGNED_ZONE },
+ { "WERR_DNS_ERROR_KSP_DOES_NOT_SUPPORT_PROTECTION", WERR_DNS_ERROR_KSP_DOES_NOT_SUPPORT_PROTECTION },
+ { "WERR_DNS_ERROR_BAD_KEYMASTER", WERR_DNS_ERROR_BAD_KEYMASTER },
+ { "WERR_USER_APC", WERR_USER_APC },
+ { "WERR_DNS_ERROR_UNEXPECTED_DATA_PROTECTION_ERROR", WERR_DNS_ERROR_UNEXPECTED_DATA_PROTECTION_ERROR },
+ { "WERR_WAIT_2", WERR_WAIT_2 },
+ { "WERR_WAIT_3", WERR_WAIT_3 },
+ { "WERR_WAIT_1", WERR_WAIT_1 },
+ { "WERR_DNS_ERROR_NSEC3_NAME_COLLISION", WERR_DNS_ERROR_NSEC3_NAME_COLLISION },
+ { "WERR_DNS_ERROR_KSP_NOT_ACCESSIBLE", WERR_DNS_ERROR_KSP_NOT_ACCESSIBLE },
+ { "WERR_DNS_ERROR_ROLLOVER_NOT_POKEABLE", WERR_DNS_ERROR_ROLLOVER_NOT_POKEABLE },
+ { "WERR_DNS_ERROR_INVALID_KEY_SIZE", WERR_DNS_ERROR_INVALID_KEY_SIZE },
+ { "WERR_DNS_ERROR_ROLLOVER_ALREADY_QUEUED", WERR_DNS_ERROR_ROLLOVER_ALREADY_QUEUED },
+ { "WERR_DNS_ERROR_UNKNOWN_SIGNING_PARAMETER_VERSION", WERR_DNS_ERROR_UNKNOWN_SIGNING_PARAMETER_VERSION },
+ { "WERR_DNS_ERROR_INVALID_INITIAL_ROLLOVER_OFFSET", WERR_DNS_ERROR_INVALID_INITIAL_ROLLOVER_OFFSET },
+ { "WERR_DNS_ERROR_SIGNING_KEY_NOT_ACCESSIBLE", WERR_DNS_ERROR_SIGNING_KEY_NOT_ACCESSIBLE },
+ { "WERR_DNS_REQUEST_PENDING", WERR_DNS_REQUEST_PENDING },
+ { "WERR_LOG_HARD_ERROR", WERR_LOG_HARD_ERROR },
+ { "WERR_DNS_ERROR_NOT_ALLOWED_ON_ZSK", WERR_DNS_ERROR_NOT_ALLOWED_ON_ZSK },
+ { "WERR_OK", WERR_OK },
+ { "WERR_DNS_ERROR_KEYMASTER_REQUIRED", WERR_DNS_ERROR_KEYMASTER_REQUIRED },
+ { "WERR_STATUS_MORE_ENTRIES", WERR_STATUS_MORE_ENTRIES },
+ { "WERR_DS_INVALID_ATTRIBUTE_SYNTAX", WERR_DS_INVALID_ATTRIBUTE_SYNTAX },
+ { "WERR_ALERTED", WERR_ALERTED },
+ { "WERR_DNS_ERROR_UNSUPPORTED_ALGORITHM", WERR_DNS_ERROR_UNSUPPORTED_ALGORITHM },
+ { "WERR_DNS_ERROR_INVALID_NSEC3_ITERATION_COUNT", WERR_DNS_ERROR_INVALID_NSEC3_ITERATION_COUNT },
+ { "WERR_DNS_ERROR_INVALID_XML", WERR_DNS_ERROR_INVALID_XML },
+ { "WERR_DNS_ERROR_DELEGATION_REQUIRED", WERR_DNS_ERROR_DELEGATION_REQUIRED },
+ { "WERR_ABANDONED_WAIT_63", WERR_ABANDONED_WAIT_63 },
+ { "WERR_DNS_ERROR_UNEXPECTED_CNG_ERROR", WERR_DNS_ERROR_UNEXPECTED_CNG_ERROR },
+ { "WERR_DNS_ERROR_DNAME_COLLISION", WERR_DNS_ERROR_DNAME_COLLISION },
+ { "WERR_DNS_ERROR_INVALID_POLICY_TABLE", WERR_DNS_ERROR_INVALID_POLICY_TABLE },
+ { "WERR_DNS_ERROR_NO_VALID_TRUST_ANCHORS", WERR_DNS_ERROR_NO_VALID_TRUST_ANCHORS },
+ { "WERR_MULTIPLE_FAULT_VIOLATION", WERR_MULTIPLE_FAULT_VIOLATION },
+ { "WERR_DNS_ERROR_INVALID_ROLLOVER_PERIOD", WERR_DNS_ERROR_INVALID_ROLLOVER_PERIOD },
+ { "WERR_DNS_ERROR_INVALID_SIGNATURE_VALIDITY_PERIOD", WERR_DNS_ERROR_INVALID_SIGNATURE_VALIDITY_PERIOD },
+ { "WERR_DNS_ERROR_NOT_ENOUGH_SIGNING_KEY_DESCRIPTORS", WERR_DNS_ERROR_NOT_ENOUGH_SIGNING_KEY_DESCRIPTORS },
+ { "WERR_INVALID_PRIMARY_GROUP", WERR_INVALID_PRIMARY_GROUP },
+ { "WERR_KERNEL_APC", WERR_KERNEL_APC },
+ { "WERR_DNS_ERROR_NOT_ALLOWED_UNDER_DNAME", WERR_DNS_ERROR_NOT_ALLOWED_UNDER_DNAME },
+ { "WERR_DNS_ERROR_TOO_MANY_SKDS", WERR_DNS_ERROR_TOO_MANY_SKDS },
+ { "WERR_DNS_ERROR_NODE_IS_DNMAE", WERR_DNS_ERROR_NODE_IS_DNAME },
+ { "WERR_DNS_ERROR_NODE_IS_DNAME", WERR_DNS_ERROR_NODE_IS_DNAME },
+ { "WERR_SERVICE_NOTIFICATION", WERR_SERVICE_NOTIFICATION },
+ { "WERR_WAIT_63", WERR_WAIT_63 },
+ { "WERR_DNS_ERROR_STANDBY_KEY_NOT_PRESENT", WERR_DNS_ERROR_STANDBY_KEY_NOT_PRESENT },
+ { "WERR_DNS_ERROR_ALIAS_LOOP", WERR_DNS_ERROR_ALIAS_LOOP },
+ { "WERR_DNS_ERROR_ROLLOVER_IN_PROGRESS", WERR_DNS_ERROR_ROLLOVER_IN_PROGRESS },
+ { "WERR_DNS_ERROR_NOT_ALLOWED_ON_SIGNED_ZONE", WERR_DNS_ERROR_NOT_ALLOWED_ON_SIGNED_ZONE },
+ { 0, W_ERROR(0) }
+};
+
+/*****************************************************************************
+ returns a windows error message. not amazingly helpful, but better than a number.
+ *****************************************************************************/
+const char *win_errstr(WERROR werror)
+{
+ static char msg[40];
+ int idx = 0;
+
+ while (special_errs[idx].dos_errstr != NULL) {
+ if (W_ERROR_V(special_errs[idx].werror) ==
+ W_ERROR_V(werror))
+ return special_errs[idx].dos_errstr;
+ idx++;
+ }
+
+ idx = 0;
+
+ switch W_ERROR_V(werror) {
+#include "werror_gen.c"
+ default:
+ break;
+ }
+
+ /*
+ * WERROR codes are 16-bit only, if the
+ * upper 16-bit are not 0, it's likely
+ * an HRESULT.
+ *
+ * E.g. we should display HRES_SEC_E_WRONG_PRINCIPAL instead of
+ * 'DOS code 0x80090322'
+ */
+ if ((W_ERROR_V(werror) & 0xFFFF0000) != 0) {
+ HRESULT hres = HRES_ERROR(W_ERROR_V(werror));
+ return hresult_errstr(hres);
+ }
+
+ slprintf(msg, sizeof(msg), "DOS code 0x%08x", W_ERROR_V(werror));
+
+ return msg;
+}
+
+/*****************************************************************************
+ Get friendly error string for WERRORs
+ *****************************************************************************/
+
+const char *get_friendly_werror_msg(WERROR werror)
+{
+ switch W_ERROR_V(werror) {
+#include "werror_friendly_gen.c"
+ default:
+ break;
+ }
+
+ return win_errstr(werror);
+}
diff --git a/libcli/util/doserr.h b/libcli/util/doserr.h
new file mode 100644
index 0000000..b57ac5d
--- /dev/null
+++ b/libcli/util/doserr.h
@@ -0,0 +1,176 @@
+/*
+ Unix SMB/CIFS implementation.
+ DOS error code constants
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) John H Terpstra 1996-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Paul Ashton 1998-2000
+ Copyright (C) Gerald (Jerry) Carter 2005
+
+ 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/>.
+*/
+
+#ifndef _DOSERR_H
+#define _DOSERR_H
+
+/* Error classes */
+
+#define ERRDOS 0x01 /* Error is from the core DOS operating system set. */
+#define ERRSRV 0x02 /* Error is generated by the server network file manager.*/
+#define ERRHRD 0x03 /* Error is an hardware error. */
+#define ERRCMD 0xFF /* Command was not in the "SMB" format. */
+
+/* SMB X/Open error codes for the ERRDOS error class */
+#define ERRsuccess 0 /* No error */
+#define ERRbadfunc 1 /* Invalid function (or system call) */
+#define ERRbadfile 2 /* File not found (pathname error) */
+#define ERRbadpath 3 /* Directory not found */
+#define ERRnofids 4 /* Too many open files */
+#define ERRnoaccess 5 /* Access denied */
+#define ERRbadfid 6 /* Invalid fid */
+#define ERRbadmcb 7 /* Memory control blocks destroyed. */
+#define ERRnomem 8 /* Out of memory */
+#define ERRbadmem 9 /* Invalid memory block address */
+#define ERRbadenv 10 /* Invalid environment */
+#define ERRbadformat 11 /* Bad Format */
+#define ERRbadaccess 12 /* Invalid open mode */
+#define ERRbaddata 13 /* Invalid data (only from ioctl call) */
+#define ERRres 14 /* reserved */
+#define ERRbaddrive 15 /* Invalid drive */
+#define ERRremcd 16 /* Attempt to delete current directory */
+#define ERRdiffdevice 17 /* rename/move across different filesystems */
+#define ERRnofiles 18 /* no more files found in file search */
+#define ERRgeneral 31 /* General failure */
+#define ERRbadshare 32 /* Share mode on file conflict with open mode */
+#define ERRlock 33 /* Lock request conflicts with existing lock */
+#define ERRunsup 50 /* Request unsupported, returned by Win 95, RJS 20Jun98 */
+#define ERRnetnamedel 64 /* Network name deleted or not available */
+#define ERRnosuchshare 67 /* You specified an invalid share name */
+#define ERRfilexists 80 /* File in operation already exists */
+#define ERRinvalidparam 87
+#define ERRcannotopen 110 /* Cannot open the file specified */
+#define ERRbufferoverflow 111
+#define ERRinsufficientbuffer 122
+#define ERRinvalidname 123 /* Invalid name */
+#define ERRunknownlevel 124
+#define ERRnotlocked 158 /* This region is not locked by this locking context. */
+#define ERRinvalidpath 161
+#define ERRcancelviolation 173
+#define ERRnoatomiclocks 174
+#define ERRrename 183
+#define ERRbadpipe 230 /* Named pipe invalid */
+#define ERRpipebusy 231 /* All instances of pipe are busy */
+#define ERRpipeclosing 232 /* named pipe close in progress */
+#define ERRnotconnected 233 /* No process on other end of named pipe */
+#define ERRmoredata 234 /* More data to be returned */
+#define ERReainconsistent 255 /* from EMC */
+#define ERRnomoreitems 259
+#define ERRbaddirectory 267 /* Invalid directory name in a path. */
+#define ERReasnotsupported 282 /* Extended attributes */
+#define ERRlogonfailure 1326 /* Unknown username or bad password */
+#define ERRbuftoosmall 2123
+#define ERRunknownipc 2142
+#define ERRnosuchprintjob 2151
+#define ERRinvgroup 2455
+
+/* here's a special one from observing NT */
+#define ERRnoipc 66 /* don't support ipc */
+
+/* These errors seem to be only returned by the NT printer driver system */
+#define ERRdriveralreadyinstalled 1795 /* ERROR_PRINTER_DRIVER_ALREADY_INSTALLED */
+#define ERRunknownprinterport 1796 /* ERROR_UNKNOWN_PORT */
+#define ERRunknownprinterdriver 1797 /* ERROR_UNKNOWN_PRINTER_DRIVER */
+#define ERRunknownprintprocessor 1798 /* ERROR_UNKNOWN_PRINTPROCESSOR */
+#define ERRinvalidseparatorfile 1799 /* ERROR_INVALID_SEPARATOR_FILE */
+#define ERRinvalidjobpriority 1800 /* ERROR_INVALID_PRIORITY */
+#define ERRinvalidprintername 1801 /* ERROR_INVALID_PRINTER_NAME */
+#define ERRprinteralreadyexists 1802 /* ERROR_PRINTER_ALREADY_EXISTS */
+#define ERRinvalidprintercommand 1803 /* ERROR_INVALID_PRINTER_COMMAND */
+#define ERRinvaliddatatype 1804 /* ERROR_INVALID_DATATYPE */
+#define ERRinvalidenvironment 1805 /* ERROR_INVALID_ENVIRONMENT */
+
+#define ERRunknownprintmonitor 3000 /* ERROR_UNKNOWN_PRINT_MONITOR */
+#define ERRprinterdriverinuse 3001 /* ERROR_PRINTER_DRIVER_IN_USE */
+#define ERRspoolfilenotfound 3002 /* ERROR_SPOOL_FILE_NOT_FOUND */
+#define ERRnostartdoc 3003 /* ERROR_SPL_NO_STARTDOC */
+#define ERRnoaddjob 3004 /* ERROR_SPL_NO_ADDJOB */
+#define ERRprintprocessoralreadyinstalled 3005 /* ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED */
+#define ERRprintmonitoralreadyinstalled 3006 /* ERROR_PRINT_MONITOR_ALREADY_INSTALLED */
+#define ERRinvalidprintmonitor 3007 /* ERROR_INVALID_PRINT_MONITOR */
+#define ERRprintmonitorinuse 3008 /* ERROR_PRINT_MONITOR_IN_USE */
+#define ERRprinterhasjobsqueued 3009 /* ERROR_PRINTER_HAS_JOBS_QUEUED */
+
+/* Error codes for the ERRSRV class */
+
+#define ERRerror 1 /* Non specific error code */
+#define ERRbadpw 2 /* Bad password */
+#define ERRbadtype 3 /* reserved */
+#define ERRaccess 4 /* No permissions to do the requested operation */
+#define ERRinvnid 5 /* tid invalid */
+#define ERRinvnetname 6 /* Invalid servername */
+#define ERRinvdevice 7 /* Invalid device */
+#define ERRqfull 49 /* Print queue full */
+#define ERRqtoobig 50 /* Queued item too big */
+#define ERRinvpfid 52 /* Invalid print file in smb_fid */
+#define ERRsmbcmd 64 /* Unrecognised command */
+#define ERRsrverror 65 /* smb server internal error */
+#define ERRfilespecs 67 /* fid and pathname invalid combination */
+#define ERRbadlink 68 /* reserved */
+#define ERRbadpermits 69 /* Access specified for a file is not valid */
+#define ERRbadpid 70 /* reserved */
+#define ERRsetattrmode 71 /* attribute mode invalid */
+#define ERRpaused 81 /* Message server paused */
+#define ERRmsgoff 82 /* Not receiving messages */
+#define ERRnoroom 83 /* No room for message */
+#define ERRrmuns 87 /* too many remote usernames */
+#define ERRtimeout 88 /* operation timed out */
+#define ERRnoresource 89 /* No resources currently available for request. */
+#define ERRtoomanyuids 90 /* too many userids */
+#define ERRbaduid 91 /* bad userid */
+#define ERRuseMPX 250 /* temporarily unable to use raw mode, use MPX mode */
+#define ERRuseSTD 251 /* temporarily unable to use raw mode, use standard mode */
+#define ERRcontMPX 252 /* resume MPX mode */
+#define ERRbadPW /* reserved */
+#define ERRnosupport 0xFFFF
+#define ERRunknownsmb 22 /* from NT 3.5 response */
+
+/* Error codes for the ERRHRD class */
+
+#define ERRnowrite 19 /* read only media */
+#define ERRbadunit 20 /* Unknown device */
+#define ERRnotready 21 /* Drive not ready */
+#define ERRbadcmd 22 /* Unknown command */
+#define ERRdata 23 /* Data (CRC) error */
+#define ERRbadreq 24 /* Bad request structure length */
+#define ERRseek 25
+#define ERRbadmedia 26
+#define ERRbadsector 27
+#define ERRnopaper 28
+#define ERRwrite 29 /* write fault */
+#define ERRread 30 /* read fault */
+#define ERRgeneral 31 /* General hardware failure */
+#define ERRwrongdisk 34
+#define ERRFCBunavail 35
+#define ERRsharebufexc 36 /* share buffer exceeded */
+#define ERRdiskfull 39
+
+#ifndef NERR_BASE
+#define NERR_BASE (2100)
+#endif
+
+#ifndef FRS_ERR_BASE
+#define FRS_ERR_BASE (8000)
+#endif
+
+#endif /* _DOSERR_H */
diff --git a/libcli/util/errmap_unix.c b/libcli/util/errmap_unix.c
new file mode 100644
index 0000000..16c7b49
--- /dev/null
+++ b/libcli/util/errmap_unix.c
@@ -0,0 +1,297 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * error mapping functions
+ * Copyright (C) Andrew Tridgell 2001
+ * Copyright (C) Andrew Bartlett 2001
+ * Copyright (C) Tim Potter 2000
+ *
+ * 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"
+
+/* Mapping between Unix, and NT error numbers */
+
+static const struct {
+ int unix_error;
+ NTSTATUS nt_error;
+} unix_nt_errmap[] = {
+ { EAGAIN, STATUS_MORE_ENTRIES },
+ { EINTR, STATUS_MORE_ENTRIES },
+ { ENOBUFS, STATUS_MORE_ENTRIES },
+#ifdef EWOULDBLOCK
+ { EWOULDBLOCK, STATUS_MORE_ENTRIES },
+#endif
+ { EINPROGRESS, NT_STATUS_MORE_PROCESSING_REQUIRED },
+ { EPERM, NT_STATUS_ACCESS_DENIED },
+ { EACCES, NT_STATUS_ACCESS_DENIED },
+ { ENOENT, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { ENOTDIR, NT_STATUS_NOT_A_DIRECTORY },
+ { EIO, NT_STATUS_IO_DEVICE_ERROR },
+ { EBADF, NT_STATUS_INVALID_HANDLE },
+ { EINVAL, NT_STATUS_INVALID_PARAMETER },
+ { EEXIST, NT_STATUS_OBJECT_NAME_COLLISION},
+ { ENFILE, NT_STATUS_TOO_MANY_OPENED_FILES },
+ { EMFILE, NT_STATUS_TOO_MANY_OPENED_FILES },
+ { ENOSPC, NT_STATUS_DISK_FULL },
+ { ENOTSOCK, NT_STATUS_INVALID_HANDLE },
+ { EFAULT, NT_STATUS_INVALID_PARAMETER },
+ { EMSGSIZE, NT_STATUS_INVALID_BUFFER_SIZE },
+ { ENOMEM, NT_STATUS_NO_MEMORY },
+ { EISDIR, NT_STATUS_FILE_IS_A_DIRECTORY},
+#ifdef EPIPE
+ { EPIPE, NT_STATUS_CONNECTION_DISCONNECTED },
+#endif
+ { EBUSY, NT_STATUS_SHARING_VIOLATION },
+ { ENOSYS, NT_STATUS_INVALID_SYSTEM_SERVICE },
+#ifdef EOPNOTSUPP
+ { EOPNOTSUPP, NT_STATUS_NOT_SUPPORTED},
+#endif
+ { EMLINK, NT_STATUS_TOO_MANY_LINKS },
+ { ENOSYS, NT_STATUS_NOT_SUPPORTED },
+#ifdef ELOOP
+ { ELOOP, NT_STATUS_OBJECT_PATH_NOT_FOUND },
+#endif
+#ifdef ENODATA
+ { ENODATA, NT_STATUS_NOT_FOUND },
+#endif
+#ifdef EFTYPE
+ { EFTYPE, NT_STATUS_OBJECT_PATH_NOT_FOUND },
+#endif
+#ifdef EDQUOT
+ { EDQUOT, NT_STATUS_DISK_FULL }, /* Windows apps need this, not NT_STATUS_QUOTA_EXCEEDED */
+#endif
+#ifdef ENOTEMPTY
+ { ENOTEMPTY, NT_STATUS_DIRECTORY_NOT_EMPTY },
+#endif
+#ifdef EXDEV
+ { EXDEV, NT_STATUS_NOT_SAME_DEVICE },
+#endif
+#ifdef EROFS
+ { EROFS, NT_STATUS_MEDIA_WRITE_PROTECTED },
+#endif
+#ifdef ENAMETOOLONG
+ { ENAMETOOLONG, NT_STATUS_NAME_TOO_LONG },
+#endif
+#ifdef EFBIG
+ { EFBIG, NT_STATUS_DISK_FULL },
+#endif
+#ifdef EADDRINUSE
+ { EADDRINUSE, NT_STATUS_ADDRESS_ALREADY_ASSOCIATED},
+#endif
+#ifdef ENETUNREACH
+ { ENETUNREACH, NT_STATUS_NETWORK_UNREACHABLE},
+#endif
+#ifdef EHOSTUNREACH
+ { EHOSTUNREACH, NT_STATUS_HOST_UNREACHABLE},
+#endif
+#ifdef ECONNREFUSED
+ { ECONNREFUSED, NT_STATUS_CONNECTION_REFUSED},
+#endif
+#ifdef EADDRNOTAVAIL
+ { EADDRNOTAVAIL,NT_STATUS_ADDRESS_NOT_ASSOCIATED },
+#endif
+#ifdef ETIMEDOUT
+ { ETIMEDOUT, NT_STATUS_IO_TIMEOUT},
+#endif
+#ifdef ESOCKTNOSUPPORT
+ { ESOCKTNOSUPPORT,NT_STATUS_INVALID_PARAMETER_MIX },
+#endif
+#ifdef EAFNOSUPPORT
+ { EAFNOSUPPORT, NT_STATUS_INVALID_PARAMETER_MIX },
+#endif
+#ifdef ECONNABORTED
+ { ECONNABORTED, NT_STATUS_CONNECTION_ABORTED},
+#endif
+#ifdef ECONNRESET
+ { ECONNRESET, NT_STATUS_CONNECTION_RESET},
+#endif
+#ifdef ENOPROTOOPT
+ { ENOPROTOOPT, NT_STATUS_INVALID_PARAMETER_MIX },
+#endif
+#ifdef ENODEV
+ { ENODEV, NT_STATUS_NO_SUCH_DEVICE },
+#endif
+#ifdef ENOATTR
+ { ENOATTR, NT_STATUS_NOT_FOUND },
+#endif
+#ifdef ECANCELED
+ { ECANCELED, NT_STATUS_CANCELLED},
+#endif
+#ifdef ENOTSUP
+ { ENOTSUP, NT_STATUS_NOT_SUPPORTED},
+#endif
+
+ { 0, NT_STATUS_UNSUCCESSFUL }
+};
+
+
+/*********************************************************************
+ Map an NT error code from a Unix error code.
+*********************************************************************/
+NTSTATUS map_nt_error_from_unix_common(int unix_error)
+{
+ size_t i;
+
+ /* Look through list */
+ for (i=0;i<ARRAY_SIZE(unix_nt_errmap);i++) {
+ if (unix_nt_errmap[i].unix_error == unix_error) {
+ return unix_nt_errmap[i].nt_error;
+ }
+ }
+
+ /* Default return */
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+/* Return a UNIX errno from a NT status code */
+static const struct {
+ NTSTATUS status;
+ int error;
+} nt_errno_map[] = {
+ {NT_STATUS_ACCESS_VIOLATION, EACCES},
+ {NT_STATUS_INVALID_HANDLE, EBADF},
+ {NT_STATUS_ACCESS_DENIED, EACCES},
+ {NT_STATUS_OBJECT_NAME_NOT_FOUND, ENOENT},
+ {NT_STATUS_OBJECT_PATH_NOT_FOUND, ENOENT},
+ {NT_STATUS_SHARING_VIOLATION, EBUSY},
+ {NT_STATUS_OBJECT_PATH_INVALID, ENOTDIR},
+ {NT_STATUS_OBJECT_NAME_COLLISION, EEXIST},
+ {NT_STATUS_PATH_NOT_COVERED, ENOENT},
+ {NT_STATUS_UNSUCCESSFUL, EINVAL},
+ {NT_STATUS_NOT_IMPLEMENTED, ENOSYS},
+ {NT_STATUS_IN_PAGE_ERROR, EFAULT},
+ {NT_STATUS_BAD_NETWORK_NAME, ENOENT},
+#ifdef EDQUOT
+ {NT_STATUS_PAGEFILE_QUOTA, EDQUOT},
+ {NT_STATUS_QUOTA_EXCEEDED, EDQUOT},
+ {NT_STATUS_REGISTRY_QUOTA_LIMIT, EDQUOT},
+ {NT_STATUS_LICENSE_QUOTA_EXCEEDED, EDQUOT},
+#endif
+#ifdef ETIME
+ {NT_STATUS_TIMER_NOT_CANCELED, ETIME},
+#endif
+ {NT_STATUS_INVALID_PARAMETER, EINVAL},
+ {NT_STATUS_NO_SUCH_DEVICE, ENODEV},
+ {NT_STATUS_NO_SUCH_FILE, ENOENT},
+#ifdef ENODATA
+ {NT_STATUS_END_OF_FILE, ENODATA},
+#endif
+#ifdef ENOMEDIUM
+ {NT_STATUS_NO_MEDIA_IN_DEVICE, ENOMEDIUM},
+ {NT_STATUS_NO_MEDIA, ENOMEDIUM},
+#endif
+ {NT_STATUS_NONEXISTENT_SECTOR, ESPIPE},
+ {NT_STATUS_NO_MEMORY, ENOMEM},
+ {NT_STATUS_CONFLICTING_ADDRESSES, EADDRINUSE},
+ {NT_STATUS_NOT_MAPPED_VIEW, EINVAL},
+ {NT_STATUS_UNABLE_TO_FREE_VM, EADDRINUSE},
+ {NT_STATUS_ACCESS_DENIED, EACCES},
+ {NT_STATUS_BUFFER_TOO_SMALL, ENOBUFS},
+ {NT_STATUS_WRONG_PASSWORD, EACCES},
+ {NT_STATUS_LOGON_FAILURE, EACCES},
+ {NT_STATUS_INVALID_WORKSTATION, EACCES},
+ {NT_STATUS_INVALID_LOGON_HOURS, EACCES},
+ {NT_STATUS_PASSWORD_EXPIRED, EACCES},
+ {NT_STATUS_ACCOUNT_DISABLED, EACCES},
+ {NT_STATUS_DISK_FULL, ENOSPC},
+ {NT_STATUS_INVALID_PIPE_STATE, EPIPE},
+ {NT_STATUS_PIPE_BUSY, EPIPE},
+ {NT_STATUS_PIPE_DISCONNECTED, EPIPE},
+ {NT_STATUS_PIPE_NOT_AVAILABLE, ENOSYS},
+ {NT_STATUS_FILE_IS_A_DIRECTORY, EISDIR},
+ {NT_STATUS_NOT_SUPPORTED, ENOSYS},
+ {NT_STATUS_NOT_A_DIRECTORY, ENOTDIR},
+ {NT_STATUS_DIRECTORY_NOT_EMPTY, ENOTEMPTY},
+ {NT_STATUS_NETWORK_UNREACHABLE, ENETUNREACH},
+ {NT_STATUS_HOST_UNREACHABLE, EHOSTUNREACH},
+ {NT_STATUS_CONNECTION_ABORTED, ECONNABORTED},
+ {NT_STATUS_CONNECTION_REFUSED, ECONNREFUSED},
+ {NT_STATUS_TOO_MANY_LINKS, EMLINK},
+ {NT_STATUS_NETWORK_BUSY, EBUSY},
+ {NT_STATUS_DEVICE_DOES_NOT_EXIST, ENODEV},
+#ifdef ELIBACC
+ {NT_STATUS_DLL_NOT_FOUND, ELIBACC},
+#endif
+ {NT_STATUS_PIPE_BROKEN, EPIPE},
+ {NT_STATUS_REMOTE_NOT_LISTENING, ECONNREFUSED},
+ {NT_STATUS_NETWORK_ACCESS_DENIED, EACCES},
+ {NT_STATUS_TOO_MANY_OPENED_FILES, EMFILE},
+#ifdef EPROTO
+ {NT_STATUS_DEVICE_PROTOCOL_ERROR, EPROTO},
+#endif
+ {NT_STATUS_FLOAT_OVERFLOW, ERANGE},
+ {NT_STATUS_FLOAT_UNDERFLOW, ERANGE},
+ {NT_STATUS_INTEGER_OVERFLOW, ERANGE},
+ {NT_STATUS_MEDIA_WRITE_PROTECTED, EROFS},
+ {NT_STATUS_PIPE_CONNECTED, EISCONN},
+ {NT_STATUS_MEMORY_NOT_ALLOCATED, EFAULT},
+ {NT_STATUS_FLOAT_INEXACT_RESULT, ERANGE},
+ {NT_STATUS_ILL_FORMED_PASSWORD, EACCES},
+ {NT_STATUS_PASSWORD_RESTRICTION, EACCES},
+ {NT_STATUS_ACCOUNT_RESTRICTION, EACCES},
+ {NT_STATUS_PORT_CONNECTION_REFUSED, ECONNREFUSED},
+ {NT_STATUS_NAME_TOO_LONG, ENAMETOOLONG},
+ {NT_STATUS_REMOTE_DISCONNECT, ESHUTDOWN},
+ {NT_STATUS_CONNECTION_DISCONNECTED, ECONNABORTED},
+ {NT_STATUS_CONNECTION_RESET, ENETRESET},
+#ifdef ENOTUNIQ
+ {NT_STATUS_IP_ADDRESS_CONFLICT1, ENOTUNIQ},
+ {NT_STATUS_IP_ADDRESS_CONFLICT2, ENOTUNIQ},
+#endif
+ {NT_STATUS_PORT_MESSAGE_TOO_LONG, EMSGSIZE},
+ {NT_STATUS_PROTOCOL_UNREACHABLE, ENOPROTOOPT},
+ {NT_STATUS_ADDRESS_ALREADY_EXISTS, EADDRINUSE},
+ {NT_STATUS_PORT_UNREACHABLE, EHOSTUNREACH},
+ {NT_STATUS_IO_TIMEOUT, ETIMEDOUT},
+ {NT_STATUS_RETRY, EAGAIN},
+#ifdef ENOTUNIQ
+ {NT_STATUS_DUPLICATE_NAME, ENOTUNIQ},
+#endif
+#ifdef ECOMM
+ {NT_STATUS_NET_WRITE_FAULT, ECOMM},
+#endif
+#ifdef EXDEV
+ {NT_STATUS_NOT_SAME_DEVICE, EXDEV},
+#endif
+#ifdef ECANCELED
+ {NT_STATUS_CANCELLED, ECANCELED},
+#endif
+};
+
+/*********************************************************************
+ Map a Unix error code from a NT error code.
+*********************************************************************/
+int map_errno_from_nt_status(NTSTATUS status)
+{
+ size_t i;
+
+ DBG_DEBUG("32 bit codes: code=%08x\n", NT_STATUS_V(status));
+
+ /* Status codes without this bit set are not errors */
+
+ if (!(NT_STATUS_V(status) & 0xc0000000)) {
+ return 0;
+ }
+
+ for (i=0;i<ARRAY_SIZE(nt_errno_map);i++) {
+ if (NT_STATUS_V(nt_errno_map[i].status) ==
+ NT_STATUS_V(status)) {
+ return nt_errno_map[i].error;
+ }
+ }
+
+ /* for all other cases - a default code */
+ return EINVAL;
+}
diff --git a/libcli/util/error.h b/libcli/util/error.h
new file mode 100644
index 0000000..c908292
--- /dev/null
+++ b/libcli/util/error.h
@@ -0,0 +1,59 @@
+/*
+ Unix SMB/CIFS implementation.
+ Error handling code
+
+ 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/>.
+*/
+
+#ifndef _SAMBA_ERROR_H_
+#define _SAMBA_ERROR_H_
+
+#include "libcli/util/werror.h"
+#include "libcli/util/doserr.h"
+#include "libcli/util/ntstatus.h"
+#include "libcli/util/hresult.h"
+
+/*****************************************************************************
+convert a NT status code to a dos class/code
+ *****************************************************************************/
+void ntstatus_to_dos(NTSTATUS ntstatus, uint8_t *eclass, uint32_t *ecode);
+
+/*****************************************************************************
+convert a WERROR to a NT status32 code
+ *****************************************************************************/
+NTSTATUS werror_to_ntstatus(WERROR error);
+
+/*****************************************************************************
+convert a NTSTATUS to a WERROR
+ *****************************************************************************/
+WERROR ntstatus_to_werror(NTSTATUS error);
+
+/*********************************************************************
+ Map an NT error code from a Unix error code.
+*********************************************************************/
+NTSTATUS map_nt_error_from_unix_common(int unix_error);
+
+/*********************************************************************
+ Map a Unix error code from a NT error code.
+*********************************************************************/
+int map_errno_from_nt_status(NTSTATUS status);
+
+NTSTATUS nt_status_squash(NTSTATUS nt_status);
+
+/*****************************************************************************
+convert a Unix error to a WERROR
+ *****************************************************************************/
+WERROR unix_to_werror(int unix_error);
+
+#endif /* _SAMBA_ERROR_H */
diff --git a/libcli/util/errormap.c b/libcli/util/errormap.c
new file mode 100644
index 0000000..4907cec
--- /dev/null
+++ b/libcli/util/errormap.c
@@ -0,0 +1,1246 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * error mapping functions
+ * Copyright (C) Andrew Tridgell 2001
+ * Copyright (C) Andrew Bartlett 2001
+ * Copyright (C) Tim Potter 2000
+ *
+ * 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"
+
+/* This map was extracted by the ERRMAPEXTRACT smbtorture command.
+ The setup was a Samba HEAD (2002-01-03) PDC and an Win2k member
+ workstation. The PDC was modified (by using the 'name_to_nt_status'
+ authentication module) to convert the username (in hex) into the
+ corresponding NTSTATUS error return.
+
+ By opening two nbt sessions to the Win2k workstation, one negotiating
+ DOS and one negotiating NT errors it was possible to extract the
+ error mapping. (Because the server only supplies NT errors, the
+ NT4 workstation had to use its own error tables to convert these
+ to dos errors).
+
+ Some errors show up as 'squashed' because the NT error connection
+ got back a different error to the one it sent, so a mapping could
+ not be determined (a guess has been made in this case, to map the
+ error as squashed). This is done mainly to prevent users from getting
+ NT_STATUS_WRONG_PASSWORD and NT_STATUS_NO_SUCH_USER errors (they get
+ NT_STATUS_LOGON_FAILURE instead.
+
+ -- abartlet (2002-01-03)
+*/
+
+/* NT status -> dos error map */
+static const struct {
+ uint8_t dos_class;
+ uint32_t dos_code;
+ NTSTATUS ntstatus;
+} ntstatus_to_dos_map[] = {
+/*
+ * Not an official error, as only bit 0x80000000, not bits 0xC0000000 are set.
+ */
+ {ERRDOS, ERRmoredata, STATUS_BUFFER_OVERFLOW},
+ {ERRDOS, ERRnofiles, STATUS_NO_MORE_FILES},
+ {ERRDOS, ERRbadfile, STATUS_INVALID_EA_NAME},
+ {ERRDOS, ERRnofiles, NT_STATUS_NO_MORE_ENTRIES},
+ {ERRDOS, ERRgeneral, NT_STATUS_UNSUCCESSFUL},
+ {ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED},
+ {ERRDOS, 87, NT_STATUS_INVALID_INFO_CLASS},
+ {ERRDOS, 24, NT_STATUS_INFO_LENGTH_MISMATCH},
+ {ERRHRD, ERRgeneral, NT_STATUS_ACCESS_VIOLATION},
+ {ERRHRD, ERRgeneral, NT_STATUS_IN_PAGE_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA},
+ {ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_INITIAL_STACK},
+ {ERRDOS, 193, NT_STATUS_BAD_INITIAL_PC},
+ {ERRDOS, 87, NT_STATUS_INVALID_CID},
+ {ERRHRD, ERRgeneral, NT_STATUS_TIMER_NOT_CANCELED},
+ {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_PARAMETER},
+ {ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_DEVICE},
+ {ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE},
+ {ERRDOS, ERRbadfunc, NT_STATUS_INVALID_DEVICE_REQUEST},
+ {ERRDOS, 38, NT_STATUS_END_OF_FILE},
+ {ERRDOS, 34, NT_STATUS_WRONG_VOLUME},
+ {ERRDOS, 21, NT_STATUS_NO_MEDIA_IN_DEVICE},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_MEDIA},
+ {ERRDOS, 27, NT_STATUS_NONEXISTENT_SECTOR},
+/** Session setup succeeded. This shouldn't happen...*/
+/** Session setup succeeded. This shouldn't happen...*/
+/** NT error on DOS connection! (NT_STATUS_OK) */
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_MORE_PROCESSING_REQUIRED to NT_STATUS_OK
+ during the session setup }
+*/
+#if 0
+ {SUCCESS, 0, NT_STATUS_OK},
+#endif
+ {ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY},
+ {ERRDOS, 487, NT_STATUS_CONFLICTING_ADDRESSES},
+ {ERRDOS, 487, NT_STATUS_NOT_MAPPED_VIEW},
+ {ERRDOS, 87, NT_STATUS_UNABLE_TO_FREE_VM},
+ {ERRDOS, 87, NT_STATUS_UNABLE_TO_DELETE_SECTION},
+ {ERRDOS, 2142, NT_STATUS_INVALID_SYSTEM_SERVICE},
+ {ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_INSTRUCTION},
+ {ERRDOS, ERRnoaccess, NT_STATUS_INVALID_LOCK_SEQUENCE},
+ {ERRDOS, ERRnoaccess, NT_STATUS_INVALID_VIEW_SIZE},
+ {ERRDOS, 193, NT_STATUS_INVALID_FILE_FOR_SECTION},
+ {ERRDOS, ERRnoaccess, NT_STATUS_ALREADY_COMMITTED},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_ACCESS_DENIED to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE
+ during the session setup }
+*/
+ {ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED},
+ {ERRDOS, 111, NT_STATUS_BUFFER_TOO_SMALL},
+ {ERRDOS, ERRbadfid, NT_STATUS_OBJECT_TYPE_MISMATCH},
+ {ERRHRD, ERRgeneral, NT_STATUS_NONCONTINUABLE_EXCEPTION},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_DISPOSITION},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNWIND},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_STACK},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_UNWIND_TARGET},
+ {ERRDOS, 158, NT_STATUS_NOT_LOCKED},
+ {ERRHRD, ERRgeneral, NT_STATUS_PARITY_ERROR},
+ {ERRDOS, 487, NT_STATUS_UNABLE_TO_DECOMMIT_VM},
+ {ERRDOS, 487, NT_STATUS_NOT_COMMITTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_PORT_ATTRIBUTES},
+ {ERRHRD, ERRgeneral, NT_STATUS_PORT_MESSAGE_TOO_LONG},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_MIX},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_QUOTA_LOWER},
+ {ERRHRD, ERRgeneral, NT_STATUS_DISK_CORRUPT_ERROR},
+ {ERRDOS, ERRinvalidname, NT_STATUS_OBJECT_NAME_INVALID},
+ {ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND},
+ {ERRDOS, 183, NT_STATUS_OBJECT_NAME_COLLISION},
+ {ERRHRD, ERRgeneral, NT_STATUS_HANDLE_NOT_WAITABLE},
+ {ERRDOS, ERRbadfid, NT_STATUS_PORT_DISCONNECTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_DEVICE_ALREADY_ATTACHED},
+ {ERRDOS, ERRinvalidpath, NT_STATUS_OBJECT_PATH_INVALID},
+ {ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND},
+ {ERRDOS, ERRinvalidpath, NT_STATUS_OBJECT_PATH_SYNTAX_BAD},
+ {ERRHRD, ERRgeneral, NT_STATUS_DATA_OVERRUN},
+ {ERRHRD, ERRgeneral, NT_STATUS_DATA_LATE_ERROR},
+ {ERRDOS, 23, NT_STATUS_DATA_ERROR},
+ {ERRDOS, 23, NT_STATUS_CRC_ERROR},
+ {ERRDOS, ERRnomem, NT_STATUS_SECTION_TOO_BIG},
+ {ERRDOS, ERRnoaccess, NT_STATUS_PORT_CONNECTION_REFUSED},
+ {ERRDOS, ERRbadfid, NT_STATUS_INVALID_PORT_HANDLE},
+ {ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION},
+ {ERRHRD, ERRgeneral, NT_STATUS_QUOTA_EXCEEDED},
+ {ERRDOS, 87, NT_STATUS_INVALID_PAGE_PROTECTION},
+ {ERRDOS, 288, NT_STATUS_MUTANT_NOT_OWNED},
+ {ERRDOS, 298, NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED},
+ {ERRDOS, 87, NT_STATUS_PORT_ALREADY_SET},
+ {ERRDOS, 87, NT_STATUS_SECTION_NOT_IMAGE},
+ {ERRDOS, 156, NT_STATUS_SUSPEND_COUNT_EXCEEDED},
+ {ERRDOS, ERRnoaccess, NT_STATUS_THREAD_IS_TERMINATING},
+ {ERRDOS, 87, NT_STATUS_BAD_WORKING_SET_LIMIT},
+ {ERRDOS, 87, NT_STATUS_INCOMPATIBLE_FILE_MAP},
+ {ERRDOS, 87, NT_STATUS_SECTION_PROTECTION},
+ {ERRDOS, ERReasnotsupported, NT_STATUS_EAS_NOT_SUPPORTED},
+ {ERRDOS, 255, NT_STATUS_EA_TOO_LARGE},
+ {ERRHRD, ERRgeneral, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_EAS_ON_FILE},
+ {ERRHRD, ERRgeneral, NT_STATUS_EA_CORRUPT_ERROR},
+ {ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT},
+ {ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED},
+ {ERRDOS, ERRnoaccess, NT_STATUS_DELETE_PENDING},
+ {ERRDOS, ERRunsup, NT_STATUS_CTL_FILE_NOT_SUPPORTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNKNOWN_REVISION},
+ {ERRHRD, ERRgeneral, NT_STATUS_REVISION_MISMATCH},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_OWNER},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_PRIMARY_GROUP},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_IMPERSONATION_TOKEN},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANT_DISABLE_MANDATORY},
+ {ERRDOS, 2215, NT_STATUS_NO_LOGON_SERVERS},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_LOGON_SESSION},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PRIVILEGE},
+ {ERRDOS, ERRnoaccess, NT_STATUS_PRIVILEGE_NOT_HELD},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACCOUNT_NAME},
+ {ERRHRD, ERRgeneral, NT_STATUS_USER_EXISTS},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_NO_SUCH_USER to NT_STATUS_LOGON_FAILURE
+ during the session setup }
+*/
+ {ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER},
+ {ERRHRD, ERRgeneral, NT_STATUS_GROUP_EXISTS},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_GROUP},
+ {ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_GROUP},
+ {ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_GROUP},
+ {ERRHRD, ERRgeneral, NT_STATUS_LAST_ADMIN},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_WRONG_PASSWORD to NT_STATUS_LOGON_FAILURE
+ during the session setup }
+*/
+ {ERRSRV, ERRbadpw, NT_STATUS_WRONG_PASSWORD},
+ {ERRSRV, ERRbaduid, NT_STATUS_USER_SESSION_DELETED},
+ {ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_PASSWORD},
+ {ERRHRD, ERRgeneral, NT_STATUS_PASSWORD_RESTRICTION},
+ {ERRDOS, ERRnoaccess, NT_STATUS_LOGON_FAILURE},
+ {ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION},
+ {ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS},
+ {ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION},
+ {ERRSRV, 2242, NT_STATUS_PASSWORD_EXPIRED},
+ {ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED},
+ {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_LUIDS_EXHAUSTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_SUB_AUTHORITY},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACL},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_SID},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_SECURITY_DESCR},
+ {ERRDOS, 127, NT_STATUS_PROCEDURE_NOT_FOUND},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_FORMAT},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_TOKEN},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_INHERITANCE_ACL},
+ {ERRDOS, 158, NT_STATUS_RANGE_NOT_LOCKED},
+ {ERRDOS, 112, NT_STATUS_DISK_FULL},
+ {ERRHRD, ERRgeneral, NT_STATUS_SERVER_DISABLED},
+ {ERRHRD, ERRgeneral, NT_STATUS_SERVER_NOT_DISABLED},
+ {ERRDOS, 68, NT_STATUS_TOO_MANY_GUIDS_REQUESTED},
+ {ERRDOS, 259, NT_STATUS_GUIDS_EXHAUSTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_ID_AUTHORITY},
+ {ERRDOS, 259, NT_STATUS_AGENTS_EXHAUSTED},
+ {ERRDOS, 154, NT_STATUS_INVALID_VOLUME_LABEL},
+ {ERRDOS, ERRres, NT_STATUS_SECTION_NOT_EXTENDED},
+ {ERRDOS, 487, NT_STATUS_NOT_MAPPED_DATA},
+ {ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_DATA_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_TYPE_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_NAME_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_ARRAY_BOUNDS_EXCEEDED},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DENORMAL_OPERAND},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DIVIDE_BY_ZERO},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INEXACT_RESULT},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INVALID_OPERATION},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_OVERFLOW},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_STACK_CHECK},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_UNDERFLOW},
+ {ERRHRD, ERRgeneral, NT_STATUS_INTEGER_DIVIDE_BY_ZERO},
+ {ERRDOS, 534, NT_STATUS_INTEGER_OVERFLOW},
+ {ERRHRD, ERRgeneral, NT_STATUS_PRIVILEGED_INSTRUCTION},
+ {ERRDOS, ERRnomem, NT_STATUS_TOO_MANY_PAGING_FILES},
+ {ERRHRD, ERRgeneral, NT_STATUS_FILE_INVALID},
+ {ERRHRD, ERRgeneral, NT_STATUS_ALLOTTED_SPACE_EXCEEDED},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_INSUFFICIENT_RESOURCES to NT_STATUS_INSUFF_SERVER_RESOURCES
+ during the session setup }
+*/
+ {ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES},
+ {ERRDOS, ERRbadpath, NT_STATUS_DFS_EXIT_PATH_FOUND},
+ {ERRDOS, 23, NT_STATUS_DEVICE_DATA_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_CONNECTED},
+ {ERRDOS, 21, NT_STATUS_DEVICE_POWER_FAILURE},
+ {ERRDOS, 487, NT_STATUS_FREE_VM_NOT_AT_BASE},
+ {ERRDOS, 487, NT_STATUS_MEMORY_NOT_ALLOCATED},
+ {ERRHRD, ERRgeneral, NT_STATUS_WORKING_SET_QUOTA},
+ {ERRDOS, 19, NT_STATUS_MEDIA_WRITE_PROTECTED},
+ {ERRDOS, 21, NT_STATUS_DEVICE_NOT_READY},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_GROUP_ATTRIBUTES},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_IMPERSONATION_LEVEL},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANT_OPEN_ANONYMOUS},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_VALIDATION_CLASS},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_TOKEN_TYPE},
+ {ERRDOS, 87, NT_STATUS_BAD_MASTER_BOOT_RECORD},
+ {ERRHRD, ERRgeneral, NT_STATUS_INSTRUCTION_MISALIGNMENT},
+ {ERRDOS, ERRpipebusy, NT_STATUS_INSTANCE_NOT_AVAILABLE},
+ {ERRDOS, ERRpipebusy, NT_STATUS_PIPE_NOT_AVAILABLE},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PIPE_STATE},
+ {ERRDOS, ERRpipebusy, NT_STATUS_PIPE_BUSY},
+ {ERRDOS, ERRbadfunc, NT_STATUS_ILLEGAL_FUNCTION},
+ {ERRDOS, ERRnotconnected, NT_STATUS_PIPE_DISCONNECTED},
+ {ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_CLOSING},
+ {ERRHRD, ERRgeneral, NT_STATUS_PIPE_CONNECTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_PIPE_LISTENING},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_READ_MODE},
+ {ERRDOS, 121, NT_STATUS_IO_TIMEOUT},
+ {ERRDOS, 38, NT_STATUS_FILE_FORCED_CLOSED},
+ {ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STARTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STOPPED},
+ {ERRHRD, ERRgeneral, NT_STATUS_COULD_NOT_INTERPRET},
+ {ERRDOS, ERRnoaccess, NT_STATUS_FILE_IS_A_DIRECTORY},
+ {ERRDOS, ERRunsup, NT_STATUS_NOT_SUPPORTED},
+ {ERRDOS, 51, NT_STATUS_REMOTE_NOT_LISTENING},
+ {ERRDOS, 52, NT_STATUS_DUPLICATE_NAME},
+ {ERRDOS, 53, NT_STATUS_BAD_NETWORK_PATH},
+ {ERRDOS, 54, NT_STATUS_NETWORK_BUSY},
+ {ERRDOS, 55, NT_STATUS_DEVICE_DOES_NOT_EXIST},
+ {ERRDOS, 56, NT_STATUS_TOO_MANY_COMMANDS},
+ {ERRDOS, 57, NT_STATUS_ADAPTER_HARDWARE_ERROR},
+ {ERRDOS, 58, NT_STATUS_INVALID_NETWORK_RESPONSE},
+ {ERRDOS, 59, NT_STATUS_UNEXPECTED_NETWORK_ERROR},
+ {ERRDOS, 60, NT_STATUS_BAD_REMOTE_ADAPTER},
+ {ERRDOS, 61, NT_STATUS_PRINT_QUEUE_FULL},
+ {ERRDOS, 62, NT_STATUS_NO_SPOOL_SPACE},
+ {ERRDOS, 63, NT_STATUS_PRINT_CANCELLED},
+ {ERRDOS, 64, NT_STATUS_NETWORK_NAME_DELETED},
+ {ERRDOS, 65, NT_STATUS_NETWORK_ACCESS_DENIED},
+ {ERRDOS, 66, NT_STATUS_BAD_DEVICE_TYPE},
+ {ERRDOS, ERRnosuchshare, NT_STATUS_BAD_NETWORK_NAME},
+ {ERRDOS, 68, NT_STATUS_TOO_MANY_NAMES},
+ {ERRDOS, 69, NT_STATUS_TOO_MANY_SESSIONS},
+ {ERRDOS, 70, NT_STATUS_SHARING_PAUSED},
+ {ERRDOS, 71, NT_STATUS_REQUEST_NOT_ACCEPTED},
+ {ERRDOS, 72, NT_STATUS_REDIRECTOR_PAUSED},
+ {ERRDOS, 88, NT_STATUS_NET_WRITE_FAULT},
+ {ERRHRD, ERRgeneral, NT_STATUS_PROFILING_AT_LIMIT},
+ {ERRDOS, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE},
+ {ERRDOS, ERRnoaccess, NT_STATUS_FILE_RENAMED},
+ {ERRDOS, 240, NT_STATUS_VIRTUAL_CIRCUIT_CLOSED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SECURITY_ON_OBJECT},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANT_WAIT},
+ {ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_EMPTY},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANT_ACCESS_DOMAIN_INFO},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANT_TERMINATE_SELF},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_SERVER_STATE},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_STATE},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_ROLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_DOMAIN},
+ {ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_EXISTS},
+ {ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_LIMIT_EXCEEDED},
+ {ERRDOS, 300, NT_STATUS_OPLOCK_NOT_GRANTED},
+ {ERRDOS, 301, NT_STATUS_INVALID_OPLOCK_PROTOCOL},
+ {ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_CORRUPTION},
+ {ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_GENERIC_NOT_MAPPED},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_DESCRIPTOR_FORMAT},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_USER_BUFFER},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_IO_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_CREATE_ERR},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_MAP_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_EXTEND_ERR},
+ {ERRHRD, ERRgeneral, NT_STATUS_NOT_LOGON_PROCESS},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_EXISTS},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_1},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_2},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_3},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_4},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_5},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_6},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_7},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_8},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_9},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_10},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_11},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_12},
+ {ERRDOS, ERRbadpath, NT_STATUS_REDIRECTOR_NOT_STARTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_REDIRECTOR_STARTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PACKAGE},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_FUNCTION_TABLE},
+ {ERRDOS, 203, NT_STATUS(0xc0000100)},
+ {ERRDOS, 145, NT_STATUS_DIRECTORY_NOT_EMPTY},
+ {ERRHRD, ERRgeneral, NT_STATUS_FILE_CORRUPT_ERROR},
+ {ERRDOS, ERRbaddirectory, NT_STATUS_NOT_A_DIRECTORY},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_LOGON_SESSION_STATE},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_COLLISION},
+ {ERRDOS, 206, NT_STATUS_NAME_TOO_LONG},
+ {ERRDOS, 2401, NT_STATUS_FILES_OPEN},
+ {ERRDOS, 2404, NT_STATUS_CONNECTION_IN_USE},
+ {ERRHRD, ERRgeneral, NT_STATUS_MESSAGE_NOT_FOUND},
+ {ERRDOS, ERRnoaccess, NT_STATUS_PROCESS_IS_TERMINATING},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_LOGON_TYPE},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_GUID_TRANSLATION},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANNOT_IMPERSONATE},
+ {ERRHRD, ERRgeneral, NT_STATUS_IMAGE_ALREADY_LOADED},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_PRESENT},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_NOT_EXIST},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_ALREADY_OWNED},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_LID_OWNER},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_COMMAND},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_LID},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_SELECTOR},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_LDT},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_SIZE},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_OFFSET},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_DESCRIPTOR},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NE_FORMAT},
+ {ERRHRD, ERRgeneral, NT_STATUS_RXACT_INVALID_STATE},
+ {ERRHRD, ERRgeneral, NT_STATUS_RXACT_COMMIT_FAILURE},
+ {ERRHRD, ERRgeneral, NT_STATUS_MAPPED_FILE_SIZE_ZERO},
+ {ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANCELLED},
+ {ERRDOS, ERRnoaccess, NT_STATUS_CANNOT_DELETE},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_COMPUTER_NAME},
+ {ERRDOS, ERRnoaccess, NT_STATUS_FILE_DELETED},
+ {ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_ACCOUNT},
+ {ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_GROUP},
+ {ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_USER},
+ {ERRHRD, ERRgeneral, NT_STATUS_MEMBERS_PRIMARY_GROUP},
+ {ERRDOS, ERRbadfid, NT_STATUS_FILE_CLOSED},
+ {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_THREADS},
+ {ERRHRD, ERRgeneral, NT_STATUS_THREAD_NOT_IN_PROCESS},
+ {ERRHRD, ERRgeneral, NT_STATUS_TOKEN_ALREADY_IN_USE},
+ {ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA_EXCEEDED},
+ {ERRHRD, ERRgeneral, NT_STATUS_COMMITMENT_LIMIT},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_LE_FORMAT},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NOT_MZ},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_PROTECT},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_WIN_16},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOGON_SERVER_CONFLICT},
+ {ERRHRD, ERRgeneral, NT_STATUS_TIME_DIFFERENCE_AT_DC},
+ {ERRHRD, ERRgeneral, NT_STATUS_SYNCHRONIZATION_REQUIRED},
+ {ERRDOS, 126, NT_STATUS_DLL_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_OPEN_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_IO_PRIVILEGE_FAILED},
+ {ERRDOS, 182, NT_STATUS_ORDINAL_NOT_FOUND},
+ {ERRDOS, 127, NT_STATUS_ENTRYPOINT_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_CONTROL_C_EXIT},
+ {ERRDOS, 64, NT_STATUS_LOCAL_DISCONNECT},
+ {ERRDOS, 64, NT_STATUS_REMOTE_DISCONNECT},
+ {ERRDOS, 51, NT_STATUS_REMOTE_RESOURCES},
+ {ERRDOS, 59, NT_STATUS_LINK_FAILED},
+ {ERRDOS, 59, NT_STATUS_LINK_TIMEOUT},
+ {ERRDOS, 59, NT_STATUS_INVALID_CONNECTION},
+ {ERRDOS, 59, NT_STATUS_INVALID_ADDRESS},
+ {ERRHRD, ERRgeneral, NT_STATUS_DLL_INIT_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_MISSING_SYSTEMFILE},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNHANDLED_EXCEPTION},
+ {ERRHRD, ERRgeneral, NT_STATUS_APP_INIT_FAILURE},
+ {ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_CREATE_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_PAGEFILE},
+ {ERRDOS, ERRunknownlevel, NT_STATUS_INVALID_LEVEL},
+ {ERRDOS, 86, NT_STATUS_WRONG_PASSWORD_CORE},
+ {ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_FLOAT_CONTEXT},
+ {ERRDOS, 109, NT_STATUS_PIPE_BROKEN},
+ {ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_CORRUPT},
+ {ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_IO_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_EVENT_PAIR},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_VOLUME},
+ {ERRHRD, ERRgeneral, NT_STATUS_SERIAL_NO_DEVICE_INITED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_ALIAS},
+ {ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_ALIAS},
+ {ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_ALIAS},
+ {ERRHRD, ERRgeneral, NT_STATUS_ALIAS_EXISTS},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOGON_NOT_GRANTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SECRETS},
+ {ERRHRD, ERRgeneral, NT_STATUS_SECRET_TOO_LONG},
+ {ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_FULLSCREEN_MODE},
+ {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_CONTEXT_IDS},
+ {ERRDOS, ERRnoaccess, NT_STATUS_LOGON_TYPE_NOT_GRANTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NOT_REGISTRY_FILE},
+ {ERRHRD, ERRgeneral, NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED},
+ {ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_FT_MISSING_MEMBER},
+ {ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_SERVICE_ENTRY},
+ {ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_CHARACTER},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNMAPPABLE_CHARACTER},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNDEFINED_CHARACTER},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_VOLUME},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_WRONG_CYLINDER},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_UNKNOWN_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_BAD_REGISTERS},
+ {ERRHRD, ERRgeneral, NT_STATUS_DISK_RECALIBRATE_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_DISK_OPERATION_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_DISK_RESET_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_SHARED_IRQ_BUSY},
+ {ERRHRD, ERRgeneral, NT_STATUS_FT_ORPHANING},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000016e)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000016f)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc0000170)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc0000171)},
+ {ERRHRD, ERRgeneral, NT_STATUS_PARTITION_FAILURE},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_BLOCK_LENGTH},
+ {ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_PARTITIONED},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_LOCK_MEDIA},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_UNLOAD_MEDIA},
+ {ERRHRD, ERRgeneral, NT_STATUS_EOM_OVERFLOW},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_MEDIA},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc0000179)},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_MEMBER},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_MEMBER},
+ {ERRHRD, ERRgeneral, NT_STATUS_KEY_DELETED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_LOG_SPACE},
+ {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SIDS},
+ {ERRHRD, ERRgeneral, NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED},
+ {ERRHRD, ERRgeneral, NT_STATUS_KEY_HAS_CHILDREN},
+ {ERRHRD, ERRgeneral, NT_STATUS_CHILD_MUST_BE_VOLATILE},
+ {ERRDOS, 87, NT_STATUS_DEVICE_CONFIGURATION_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_DRIVER_INTERNAL_ERROR},
+ {ERRDOS, 22, NT_STATUS_INVALID_DEVICE_STATE},
+ {ERRHRD, ERRgeneral, NT_STATUS_IO_DEVICE_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_DEVICE_PROTOCOL_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_BACKUP_CONTROLLER},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOG_FILE_FULL},
+ {ERRDOS, 19, NT_STATUS_TOO_LATE},
+ {ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_LSA_SECRET},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_NO_TRUST_SAM_ACCOUNT to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE
+ during the session setup }
+*/
+ {ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_SAM_ACCOUNT},
+ {ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_DOMAIN_FAILURE},
+ {ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE},
+ {ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CORRUPT},
+ {ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_CANT_START},
+ {ERRDOS, ERRnoaccess, NT_STATUS_TRUST_FAILURE},
+ {ERRHRD, ERRgeneral, NT_STATUS_MUTANT_LIMIT_EXCEEDED},
+ {ERRDOS, ERRinvgroup, NT_STATUS_NETLOGON_NOT_STARTED},
+ {ERRSRV, 2239, NT_STATUS_ACCOUNT_EXPIRED},
+ {ERRHRD, ERRgeneral, NT_STATUS_POSSIBLE_DEADLOCK},
+ {ERRHRD, ERRgeneral, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT},
+ {ERRHRD, ERRgeneral, NT_STATUS_REMOTE_SESSION_LIMIT},
+ {ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CHANGED},
+ {ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT},
+ {ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT},
+ {ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_DOMAIN_TRUST_INCONSISTENT to NT_STATUS_LOGON_FAILURE
+ during the session setup }
+*/
+ {ERRDOS, ERRnoaccess, NT_STATUS_DOMAIN_TRUST_INCONSISTENT},
+ {ERRHRD, ERRgeneral, NT_STATUS_FS_DRIVER_REQUIRED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_USER_SESSION_KEY},
+ {ERRDOS, 59, NT_STATUS_USER_SESSION_DELETED},
+ {ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_LANG_NOT_FOUND},
+ {ERRDOS, ERRnomem, NT_STATUS_INSUFF_SERVER_RESOURCES},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_BUFFER_SIZE},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_COMPONENT},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_WILDCARD},
+ {ERRDOS, 68, NT_STATUS_TOO_MANY_ADDRESSES},
+ {ERRDOS, 52, NT_STATUS_ADDRESS_ALREADY_EXISTS},
+ {ERRDOS, 64, NT_STATUS_ADDRESS_CLOSED},
+ {ERRDOS, 64, NT_STATUS_CONNECTION_DISCONNECTED},
+ {ERRDOS, 64, NT_STATUS_CONNECTION_RESET},
+ {ERRDOS, 68, NT_STATUS_TOO_MANY_NODES},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_ABORTED},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_TIMED_OUT},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_NO_RELEASE},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_NO_MATCH},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_RESPONDED},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_ID},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_TYPE},
+ {ERRDOS, ERRunsup, NT_STATUS_NOT_SERVER_SESSION},
+ {ERRDOS, ERRunsup, NT_STATUS_NOT_CLIENT_SESSION},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANNOT_LOAD_REGISTRY_FILE},
+ {ERRHRD, ERRgeneral, NT_STATUS_DEBUG_ATTACH_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_SYSTEM_PROCESS_TERMINATED},
+ {ERRHRD, ERRgeneral, NT_STATUS_DATA_NOT_ACCEPTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_BROWSER_SERVERS_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_VDM_HARD_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_DRIVER_CANCEL_TIMEOUT},
+ {ERRHRD, ERRgeneral, NT_STATUS_REPLY_MESSAGE_MISMATCH},
+ {ERRHRD, ERRgeneral, NT_STATUS_MAPPED_ALIGNMENT},
+ {ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOST_WRITEBEHIND_DATA},
+ {ERRHRD, ERRgeneral, NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID},
+ {ERRSRV, 2242, NT_STATUS_PASSWORD_MUST_CHANGE},
+ {ERRHRD, ERRgeneral, NT_STATUS_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_NOT_TINY_STREAM},
+ {ERRHRD, ERRgeneral, NT_STATUS_RECOVERY_FAILURE},
+ {ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW_READ},
+ {ERRHRD, ERRgeneral, NT_STATUS_FAIL_CHECK},
+ {ERRHRD, ERRgeneral, NT_STATUS_DUPLICATE_OBJECTID},
+ {ERRHRD, ERRgeneral, NT_STATUS_OBJECTID_EXISTS},
+ {ERRHRD, ERRgeneral, NT_STATUS_CONVERT_TO_LARGE},
+ {ERRHRD, ERRgeneral, NT_STATUS_RETRY},
+ {ERRHRD, ERRgeneral, NT_STATUS_FOUND_OUT_OF_SCOPE},
+ {ERRHRD, ERRgeneral, NT_STATUS_ALLOCATE_BUCKET},
+ {ERRHRD, ERRgeneral, NT_STATUS_PROPSET_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_MARSHALL_OVERFLOW},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_VARIANT},
+ {ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND},
+ {ERRDOS, ERRnoaccess, NT_STATUS_ACCOUNT_LOCKED_OUT},
+ {ERRDOS, ERRbadfid, NT_STATUS_HANDLE_NOT_CLOSABLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_REFUSED},
+ {ERRHRD, ERRgeneral, NT_STATUS_GRACEFUL_DISCONNECT},
+ {ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_ALREADY_ASSOCIATED},
+ {ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_NOT_ASSOCIATED},
+ {ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_INVALID},
+ {ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ACTIVE},
+ {ERRHRD, ERRgeneral, NT_STATUS_NETWORK_UNREACHABLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_HOST_UNREACHABLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_PROTOCOL_UNREACHABLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_PORT_UNREACHABLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_REQUEST_ABORTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ABORTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_COMPRESSION_BUFFER},
+ {ERRHRD, ERRgeneral, NT_STATUS_USER_MAPPED_FILE},
+ {ERRHRD, ERRgeneral, NT_STATUS_AUDIT_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_TIMER_RESOLUTION_NOT_SET},
+ {ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_COUNT_LIMIT},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOGIN_TIME_RESTRICTION},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOGIN_WKSTA_RESTRICTION},
+ {ERRDOS, 193, NT_STATUS_IMAGE_MP_UP_MISMATCH},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000024a)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000024b)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000024c)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000024d)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000024e)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000024f)},
+ {ERRHRD, ERRgeneral, NT_STATUS_INSUFFICIENT_LOGON_INFO},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_DLL_ENTRYPOINT},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_SERVICE_ENTRYPOINT},
+ {ERRHRD, ERRgeneral, NT_STATUS_LPC_REPLY_LOST},
+ {ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT1},
+ {ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT2},
+ {ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_QUOTA_LIMIT},
+ {ERRSRV, ERRbadtype, NT_STATUS_PATH_NOT_COVERED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_CALLBACK_ACTIVE},
+ {ERRHRD, ERRgeneral, NT_STATUS_LICENSE_QUOTA_EXCEEDED},
+ {ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_SHORT},
+ {ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_RECENT},
+ {ERRHRD, ERRgeneral, NT_STATUS_PWD_HISTORY_CONFLICT},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000025d)},
+ {ERRHRD, ERRgeneral, NT_STATUS_PLUGPLAY_NO_DEVICE},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNSUPPORTED_COMPRESSION},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_HW_PROFILE},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH},
+ {ERRDOS, 182, NT_STATUS_DRIVER_ORDINAL_NOT_FOUND},
+ {ERRDOS, 127, NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND},
+ {ERRDOS, 288, NT_STATUS_RESOURCE_NOT_OWNED},
+ {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LINKS},
+ {ERRHRD, ERRgeneral, NT_STATUS_QUOTA_LIST_INCONSISTENT},
+ {ERRHRD, ERRgeneral, NT_STATUS_FILE_IS_OFFLINE},
+ {ERRDOS, 21, NT_STATUS(0xc000026e)},
+ {ERRDOS, 161, NT_STATUS(0xc0000281)},
+ {ERRDOS, ERRnoaccess, NT_STATUS(0xc000028a)},
+ {ERRDOS, ERRnoaccess, NT_STATUS(0xc000028b)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000028c)},
+ {ERRDOS, ERRnoaccess, NT_STATUS(0xc000028d)},
+ {ERRDOS, ERRnoaccess, NT_STATUS(0xc000028e)},
+ {ERRDOS, ERRnoaccess, NT_STATUS(0xc000028f)},
+ {ERRDOS, ERRnoaccess, NT_STATUS(0xc0000290)},
+ {ERRDOS, ERRbadfunc, NT_STATUS(0xc000029c)},
+};
+
+/* errmap NTSTATUS->Win32 */
+static const struct {
+ NTSTATUS ntstatus;
+ WERROR werror;
+} ntstatus_to_werror_map[] = {
+ {NT_STATUS(0x103), W_ERROR(0x3e5)},
+ {NT_STATUS(0x105), W_ERROR(0xea)},
+ {NT_STATUS(0x106), W_ERROR(0x514)},
+ {NT_STATUS(0x107), W_ERROR(0x515)},
+ {NT_STATUS(0x10c), W_ERROR(0x3fe)},
+ {NT_STATUS(0x10d), W_ERROR(0x516)},
+ {NT_STATUS(0x121), W_ERROR(0x2009)},
+ {NT_STATUS(0xc0000001), W_ERROR(0x1f)},
+ {NT_STATUS(0xc0000002), W_ERROR(0x1)},
+ {NT_STATUS(0xc0000003), W_ERROR(0x57)},
+ {NT_STATUS(0xc0000004), W_ERROR(0x18)},
+ {NT_STATUS(0xc0000005), W_ERROR(0x3e6)},
+ {NT_STATUS(0xc0000006), W_ERROR(0x3e7)},
+ {NT_STATUS(0xc0000007), W_ERROR(0x5ae)},
+ {NT_STATUS(0xc0000008), W_ERROR(0x6)},
+ {NT_STATUS(0xc0000009), W_ERROR(0x3e9)},
+ {NT_STATUS(0xc000000a), W_ERROR(0xc1)},
+ {NT_STATUS(0xc000000b), W_ERROR(0x57)},
+ {NT_STATUS(0xc000000d), W_ERROR(0x57)},
+ {NT_STATUS(0xc000000e), W_ERROR(0x2)},
+ {NT_STATUS(0xc000000f), W_ERROR(0x2)},
+ {NT_STATUS(0xc0000010), W_ERROR(0x1)},
+ {NT_STATUS(0xc0000011), W_ERROR(0x26)},
+ {NT_STATUS(0xc0000012), W_ERROR(0x22)},
+ {NT_STATUS(0xc0000013), W_ERROR(0x15)},
+ {NT_STATUS(0xc0000014), W_ERROR(0x6f9)},
+ {NT_STATUS(0xc0000015), W_ERROR(0x1b)},
+ {NT_STATUS(0xc0000016), W_ERROR(0xea)},
+ {NT_STATUS(0xc0000017), W_ERROR(0x8)},
+ {NT_STATUS(0xc0000018), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc0000019), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc000001a), W_ERROR(0x57)},
+ {NT_STATUS(0xc000001b), W_ERROR(0x57)},
+ {NT_STATUS(0xc000001c), W_ERROR(0x1)},
+ {NT_STATUS(0xc000001d), W_ERROR(0xc000001d)},
+ {NT_STATUS(0xc000001e), W_ERROR(0x5)},
+ {NT_STATUS(0xc000001f), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000020), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000021), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000022), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000023), W_ERROR(0x7a)},
+ {NT_STATUS(0xc0000024), W_ERROR(0x6)},
+ {NT_STATUS(0xc0000025), W_ERROR(0xc0000025)},
+ {NT_STATUS(0xc0000026), W_ERROR(0xc0000026)},
+ {NT_STATUS(0xc000002a), W_ERROR(0x9e)},
+ {NT_STATUS(0xc000002b), W_ERROR(0xc000002b)},
+ {NT_STATUS(0xc000002c), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc000002d), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc0000030), W_ERROR(0x57)},
+ {NT_STATUS(0xc0000032), W_ERROR(0x571)},
+ {NT_STATUS(0xc0000033), W_ERROR(0x7b)},
+ {NT_STATUS(0xc0000034), W_ERROR(0x2)},
+ {NT_STATUS(0xc0000035), W_ERROR(0xb7)},
+ {NT_STATUS(0xc0000037), W_ERROR(0x6)},
+ {NT_STATUS(0xc0000039), W_ERROR(0xa1)},
+ {NT_STATUS(0xc000003a), W_ERROR(0x3)},
+ {NT_STATUS(0xc000003b), W_ERROR(0xa1)},
+ {NT_STATUS(0xc000003c), W_ERROR(0x45d)},
+ {NT_STATUS(0xc000003d), W_ERROR(0x45d)},
+ {NT_STATUS(0xc000003e), W_ERROR(0x17)},
+ {NT_STATUS(0xc000003f), W_ERROR(0x17)},
+ {NT_STATUS(0xc0000040), W_ERROR(0x8)},
+ {NT_STATUS(0xc0000041), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000042), W_ERROR(0x6)},
+ {NT_STATUS(0xc0000043), W_ERROR(0x20)},
+ {NT_STATUS(0xc0000044), W_ERROR(0x718)},
+ {NT_STATUS(0xc0000045), W_ERROR(0x57)},
+ {NT_STATUS(0xc0000046), W_ERROR(0x120)},
+ {NT_STATUS(0xc0000047), W_ERROR(0x12a)},
+ {NT_STATUS(0xc0000048), W_ERROR(0x57)},
+ {NT_STATUS(0xc0000049), W_ERROR(0x57)},
+ {NT_STATUS(0xc000004a), W_ERROR(0x9c)},
+ {NT_STATUS(0xc000004b), W_ERROR(0x5)},
+ {NT_STATUS(0xc000004c), W_ERROR(0x57)},
+ {NT_STATUS(0xc000004d), W_ERROR(0x57)},
+ {NT_STATUS(0xc000004e), W_ERROR(0x57)},
+ {NT_STATUS(0xc000004f), W_ERROR(0x11a)},
+ {NT_STATUS(0xc0000050), W_ERROR(0xff)},
+ {NT_STATUS(0xc0000051), W_ERROR(0x570)},
+ {NT_STATUS(0xc0000052), W_ERROR(0x570)},
+ {NT_STATUS(0xc0000053), W_ERROR(0x570)},
+ {NT_STATUS(0xc0000054), W_ERROR(0x21)},
+ {NT_STATUS(0xc0000055), W_ERROR(0x21)},
+ {NT_STATUS(0xc0000056), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000057), W_ERROR(0x32)},
+ {NT_STATUS(0xc0000058), W_ERROR(0x519)},
+ {NT_STATUS(0xc0000059), W_ERROR(0x51a)},
+ {NT_STATUS(0xc000005a), W_ERROR(0x51b)},
+ {NT_STATUS(0xc000005b), W_ERROR(0x51c)},
+ {NT_STATUS(0xc000005c), W_ERROR(0x51d)},
+ {NT_STATUS(0xc000005d), W_ERROR(0x51e)},
+ {NT_STATUS(0xc000005e), W_ERROR(0x51f)},
+ {NT_STATUS(0xc000005f), W_ERROR(0x520)},
+ {NT_STATUS(0xc0000060), W_ERROR(0x521)},
+ {NT_STATUS(0xc0000061), W_ERROR(0x522)},
+ {NT_STATUS(0xc0000062), W_ERROR(0x523)},
+ {NT_STATUS(0xc0000063), W_ERROR(0x524)},
+ {NT_STATUS(0xc0000064), W_ERROR(0x525)},
+ {NT_STATUS(0xc0000065), W_ERROR(0x526)},
+ {NT_STATUS(0xc0000066), W_ERROR(0x527)},
+ {NT_STATUS(0xc0000067), W_ERROR(0x528)},
+ {NT_STATUS(0xc0000068), W_ERROR(0x529)},
+ {NT_STATUS(0xc0000069), W_ERROR(0x52a)},
+ {NT_STATUS(0xc000006a), W_ERROR(0x56)},
+ {NT_STATUS(0xc000006b), W_ERROR(0x52c)},
+ {NT_STATUS(0xc000006c), W_ERROR(0x52d)},
+ {NT_STATUS(0xc000006d), W_ERROR(0x52e)},
+ {NT_STATUS(0xc000006e), W_ERROR(0x52f)},
+ {NT_STATUS(0xc000006f), W_ERROR(0x530)},
+ {NT_STATUS(0xc0000070), W_ERROR(0x531)},
+ {NT_STATUS(0xc0000071), W_ERROR(0x532)},
+ {NT_STATUS(0xc0000072), W_ERROR(0x533)},
+ {NT_STATUS(0xc0000073), W_ERROR(0x534)},
+ {NT_STATUS(0xc0000074), W_ERROR(0x535)},
+ {NT_STATUS(0xc0000075), W_ERROR(0x536)},
+ {NT_STATUS(0xc0000076), W_ERROR(0x537)},
+ {NT_STATUS(0xc0000077), W_ERROR(0x538)},
+ {NT_STATUS(0xc0000078), W_ERROR(0x539)},
+ {NT_STATUS(0xc0000079), W_ERROR(0x53a)},
+ {NT_STATUS(0xc000007a), W_ERROR(0x7f)},
+ {NT_STATUS(0xc000007b), W_ERROR(0xc1)},
+ {NT_STATUS(0xc000007c), W_ERROR(0x3f0)},
+ {NT_STATUS(0xc000007d), W_ERROR(0x53c)},
+ {NT_STATUS(0xc000007e), W_ERROR(0x9e)},
+ {NT_STATUS(0xc000007f), W_ERROR(0x70)},
+ {NT_STATUS(0xc0000080), W_ERROR(0x53d)},
+ {NT_STATUS(0xc0000081), W_ERROR(0x53e)},
+ {NT_STATUS(0xc0000082), W_ERROR(0x44)},
+ {NT_STATUS(0xc0000083), W_ERROR(0x103)},
+ {NT_STATUS(0xc0000084), W_ERROR(0x53f)},
+ {NT_STATUS(0xc0000085), W_ERROR(0x103)},
+ {NT_STATUS(0xc0000086), W_ERROR(0x9a)},
+ {NT_STATUS(0xc0000087), W_ERROR(0xe)},
+ {NT_STATUS(0xc0000088), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc0000089), W_ERROR(0x714)},
+ {NT_STATUS(0xc000008a), W_ERROR(0x715)},
+ {NT_STATUS(0xc000008b), W_ERROR(0x716)},
+ {NT_STATUS(0xc000008c), W_ERROR(0xc000008c)},
+ {NT_STATUS(0xc000008d), W_ERROR(0xc000008d)},
+ {NT_STATUS(0xc000008e), W_ERROR(0xc000008e)},
+ {NT_STATUS(0xc000008f), W_ERROR(0xc000008f)},
+ {NT_STATUS(0xc0000090), W_ERROR(0xc0000090)},
+ {NT_STATUS(0xc0000091), W_ERROR(0xc0000091)},
+ {NT_STATUS(0xc0000092), W_ERROR(0xc0000092)},
+ {NT_STATUS(0xc0000093), W_ERROR(0xc0000093)},
+ {NT_STATUS(0xc0000094), W_ERROR(0xc0000094)},
+ {NT_STATUS(0xc0000095), W_ERROR(0x216)},
+ {NT_STATUS(0xc0000096), W_ERROR(0xc0000096)},
+ {NT_STATUS(0xc0000097), W_ERROR(0x8)},
+ {NT_STATUS(0xc0000098), W_ERROR(0x3ee)},
+ {NT_STATUS(0xc0000099), W_ERROR(0x540)},
+ {NT_STATUS(0xc000009a), W_ERROR(0x5aa)},
+ {NT_STATUS(0xc000009b), W_ERROR(0x3)},
+ {NT_STATUS(0xc000009c), W_ERROR(0x17)},
+ {NT_STATUS(0xc000009d), W_ERROR(0x48f)},
+ {NT_STATUS(0xc000009e), W_ERROR(0x15)},
+ {NT_STATUS(0xc000009f), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc00000a0), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc00000a1), W_ERROR(0x5ad)},
+ {NT_STATUS(0xc00000a2), W_ERROR(0x13)},
+ {NT_STATUS(0xc00000a3), W_ERROR(0x15)},
+ {NT_STATUS(0xc00000a4), W_ERROR(0x541)},
+ {NT_STATUS(0xc00000a5), W_ERROR(0x542)},
+ {NT_STATUS(0xc00000a6), W_ERROR(0x543)},
+ {NT_STATUS(0xc00000a7), W_ERROR(0x544)},
+ {NT_STATUS(0xc00000a8), W_ERROR(0x545)},
+ {NT_STATUS(0xc00000a9), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000ab), W_ERROR(0xe7)},
+ {NT_STATUS(0xc00000ac), W_ERROR(0xe7)},
+ {NT_STATUS(0xc00000ad), W_ERROR(0xe6)},
+ {NT_STATUS(0xc00000ae), W_ERROR(0xe7)},
+ {NT_STATUS(0xc00000af), W_ERROR(0x1)},
+ {NT_STATUS(0xc00000b0), W_ERROR(0xe9)},
+ {NT_STATUS(0xc00000b1), W_ERROR(0xe8)},
+ {NT_STATUS(0xc00000b2), W_ERROR(0x217)},
+ {NT_STATUS(0xc00000b3), W_ERROR(0x218)},
+ {NT_STATUS(0xc00000b4), W_ERROR(0xe6)},
+ {NT_STATUS(0xc00000b5), W_ERROR(0x79)},
+ {NT_STATUS(0xc00000b6), W_ERROR(0x26)},
+ {NT_STATUS(0xc00000ba), W_ERROR(0x5)},
+ {NT_STATUS(0xc00000bb), W_ERROR(0x32)},
+ {NT_STATUS(0xc00000bc), W_ERROR(0x33)},
+ {NT_STATUS(0xc00000bd), W_ERROR(0x34)},
+ {NT_STATUS(0xc00000be), W_ERROR(0x35)},
+ {NT_STATUS(0xc00000bf), W_ERROR(0x36)},
+ {NT_STATUS(0xc00000c0), W_ERROR(0x37)},
+ {NT_STATUS(0xc00000c1), W_ERROR(0x38)},
+ {NT_STATUS(0xc00000c2), W_ERROR(0x39)},
+ {NT_STATUS(0xc00000c3), W_ERROR(0x3a)},
+ {NT_STATUS(0xc00000c4), W_ERROR(0x3b)},
+ {NT_STATUS(0xc00000c5), W_ERROR(0x3c)},
+ {NT_STATUS(0xc00000c6), W_ERROR(0x3d)},
+ {NT_STATUS(0xc00000c7), W_ERROR(0x3e)},
+ {NT_STATUS(0xc00000c8), W_ERROR(0x3f)},
+ {NT_STATUS(0xc00000c9), W_ERROR(0x40)},
+ {NT_STATUS(0xc00000ca), W_ERROR(0x41)},
+ {NT_STATUS(0xc00000cb), W_ERROR(0x42)},
+ {NT_STATUS(0xc00000cc), W_ERROR(0x43)},
+ {NT_STATUS(0xc00000cd), W_ERROR(0x44)},
+ {NT_STATUS(0xc00000ce), W_ERROR(0x45)},
+ {NT_STATUS(0xc00000cf), W_ERROR(0x46)},
+ {NT_STATUS(0xc00000d0), W_ERROR(0x47)},
+ {NT_STATUS(0xc00000d1), W_ERROR(0x48)},
+ {NT_STATUS(0xc00000d2), W_ERROR(0x58)},
+ {NT_STATUS(0xc00000d4), W_ERROR(0x11)},
+ {NT_STATUS(0xc00000d5), W_ERROR(0x5)},
+ {NT_STATUS(0xc00000d6), W_ERROR(0xf0)},
+ {NT_STATUS(0xc00000d7), W_ERROR(0x546)},
+ {NT_STATUS(0xc00000d9), W_ERROR(0xe8)},
+ {NT_STATUS(0xc00000da), W_ERROR(0x547)},
+ {NT_STATUS(0xc00000dc), W_ERROR(0x548)},
+ {NT_STATUS(0xc00000dd), W_ERROR(0x549)},
+ {NT_STATUS(0xc00000de), W_ERROR(0x54a)},
+ {NT_STATUS(0xc00000df), W_ERROR(0x54b)},
+ {NT_STATUS(0xc00000e0), W_ERROR(0x54c)},
+ {NT_STATUS(0xc00000e1), W_ERROR(0x54d)},
+ {NT_STATUS(0xc00000e2), W_ERROR(0x12c)},
+ {NT_STATUS(0xc00000e3), W_ERROR(0x12d)},
+ {NT_STATUS(0xc00000e4), W_ERROR(0x54e)},
+ {NT_STATUS(0xc00000e5), W_ERROR(0x54f)},
+ {NT_STATUS(0xc00000e6), W_ERROR(0x550)},
+ {NT_STATUS(0xc00000e7), W_ERROR(0x551)},
+ {NT_STATUS(0xc00000e8), W_ERROR(0x6f8)},
+ {NT_STATUS(0xc00000ed), W_ERROR(0x552)},
+ {NT_STATUS(0xc00000ee), W_ERROR(0x553)},
+ {NT_STATUS(0xc00000ef), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f0), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f1), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f2), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f3), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f4), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f5), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f6), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f7), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f8), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f9), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000fa), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000fb), W_ERROR(0x3)},
+ {NT_STATUS(0xc00000fd), W_ERROR(0x3e9)},
+ {NT_STATUS(0xc00000fe), W_ERROR(0x554)},
+ {NT_STATUS(0xc0000100), W_ERROR(0xcb)},
+ {NT_STATUS(0xc0000101), W_ERROR(0x91)},
+ {NT_STATUS(0xc0000102), W_ERROR(0x570)},
+ {NT_STATUS(0xc0000103), W_ERROR(0x10b)},
+ {NT_STATUS(0xc0000104), W_ERROR(0x555)},
+ {NT_STATUS(0xc0000105), W_ERROR(0x556)},
+ {NT_STATUS(0xc0000106), W_ERROR(0xce)},
+ {NT_STATUS(0xc0000107), W_ERROR(0x961)},
+ {NT_STATUS(0xc0000108), W_ERROR(0x964)},
+ {NT_STATUS(0xc000010a), W_ERROR(0x5)},
+ {NT_STATUS(0xc000010b), W_ERROR(0x557)},
+ {NT_STATUS(0xc000010d), W_ERROR(0x558)},
+ {NT_STATUS(0xc000010e), W_ERROR(0x420)},
+ {NT_STATUS(0xc0000117), W_ERROR(0x5a4)},
+ {NT_STATUS(0xc000011b), W_ERROR(0xc1)},
+ {NT_STATUS(0xc000011c), W_ERROR(0x559)},
+ {NT_STATUS(0xc000011d), W_ERROR(0x55a)},
+ {NT_STATUS(0xc000011e), W_ERROR(0x3ee)},
+ {NT_STATUS(0xc000011f), W_ERROR(0x4)},
+ {NT_STATUS(0xc0000120), W_ERROR(0x3e3)},
+ {NT_STATUS(0xc0000121), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000122), W_ERROR(0x4ba)},
+ {NT_STATUS(0xc0000123), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000124), W_ERROR(0x55b)},
+ {NT_STATUS(0xc0000125), W_ERROR(0x55c)},
+ {NT_STATUS(0xc0000126), W_ERROR(0x55d)},
+ {NT_STATUS(0xc0000127), W_ERROR(0x55e)},
+ {NT_STATUS(0xc0000128), W_ERROR(0x6)},
+ {NT_STATUS(0xc000012b), W_ERROR(0x55f)},
+ {NT_STATUS(0xc000012d), W_ERROR(0x5af)},
+ {NT_STATUS(0xc000012e), W_ERROR(0xc1)},
+ {NT_STATUS(0xc000012f), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000130), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000131), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000133), W_ERROR(0x576)},
+ {NT_STATUS(0xc0000135), W_ERROR(0x7e)},
+ {NT_STATUS(0xc0000138), W_ERROR(0xb6)},
+ {NT_STATUS(0xc0000139), W_ERROR(0x7f)},
+ {NT_STATUS(0xc000013b), W_ERROR(0x40)},
+ {NT_STATUS(0xc000013c), W_ERROR(0x40)},
+ {NT_STATUS(0xc000013d), W_ERROR(0x33)},
+ {NT_STATUS(0xc000013e), W_ERROR(0x3b)},
+ {NT_STATUS(0xc000013f), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000140), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000141), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000142), W_ERROR(0x45a)},
+ {NT_STATUS(0xc0000148), W_ERROR(0x7c)},
+ {NT_STATUS(0xc0000149), W_ERROR(0x56)},
+ {NT_STATUS(0xc000014b), W_ERROR(0x6d)},
+ {NT_STATUS(0xc000014c), W_ERROR(0x3f1)},
+ {NT_STATUS(0xc000014d), W_ERROR(0x3f8)},
+ {NT_STATUS(0xc000014f), W_ERROR(0x3ed)},
+ {NT_STATUS(0xc0000150), W_ERROR(0x45e)},
+ {NT_STATUS(0xc0000151), W_ERROR(0x560)},
+ {NT_STATUS(0xc0000152), W_ERROR(0x561)},
+ {NT_STATUS(0xc0000153), W_ERROR(0x562)},
+ {NT_STATUS(0xc0000154), W_ERROR(0x563)},
+ {NT_STATUS(0xc0000155), W_ERROR(0x564)},
+ {NT_STATUS(0xc0000156), W_ERROR(0x565)},
+ {NT_STATUS(0xc0000157), W_ERROR(0x566)},
+ {NT_STATUS(0xc0000158), W_ERROR(0x567)},
+ {NT_STATUS(0xc0000159), W_ERROR(0x3ef)},
+ {NT_STATUS(0xc000015a), W_ERROR(0x568)},
+ {NT_STATUS(0xc000015b), W_ERROR(0x569)},
+ {NT_STATUS(0xc000015c), W_ERROR(0x3f9)},
+ {NT_STATUS(0xc000015d), W_ERROR(0x56a)},
+ {NT_STATUS(0xc000015f), W_ERROR(0x45d)},
+ {NT_STATUS(0xc0000162), W_ERROR(0x459)},
+ {NT_STATUS(0xc0000165), W_ERROR(0x462)},
+ {NT_STATUS(0xc0000166), W_ERROR(0x463)},
+ {NT_STATUS(0xc0000167), W_ERROR(0x464)},
+ {NT_STATUS(0xc0000168), W_ERROR(0x465)},
+ {NT_STATUS(0xc0000169), W_ERROR(0x466)},
+ {NT_STATUS(0xc000016a), W_ERROR(0x467)},
+ {NT_STATUS(0xc000016b), W_ERROR(0x468)},
+ {NT_STATUS(0xc000016c), W_ERROR(0x45f)},
+ {NT_STATUS(0xc000016d), W_ERROR(0x45d)},
+ {NT_STATUS(0xc0000172), W_ERROR(0x451)},
+ {NT_STATUS(0xc0000173), W_ERROR(0x452)},
+ {NT_STATUS(0xc0000174), W_ERROR(0x453)},
+ {NT_STATUS(0xc0000175), W_ERROR(0x454)},
+ {NT_STATUS(0xc0000176), W_ERROR(0x455)},
+ {NT_STATUS(0xc0000177), W_ERROR(0x469)},
+ {NT_STATUS(0xc0000178), W_ERROR(0x458)},
+ {NT_STATUS(0xc000017a), W_ERROR(0x56b)},
+ {NT_STATUS(0xc000017b), W_ERROR(0x56c)},
+ {NT_STATUS(0xc000017c), W_ERROR(0x3fa)},
+ {NT_STATUS(0xc000017d), W_ERROR(0x3fb)},
+ {NT_STATUS(0xc000017e), W_ERROR(0x56d)},
+ {NT_STATUS(0xc000017f), W_ERROR(0x56e)},
+ {NT_STATUS(0xc0000180), W_ERROR(0x3fc)},
+ {NT_STATUS(0xc0000181), W_ERROR(0x3fd)},
+ {NT_STATUS(0xc0000182), W_ERROR(0x57)},
+ {NT_STATUS(0xc0000183), W_ERROR(0x45d)},
+ {NT_STATUS(0xc0000184), W_ERROR(0x16)},
+ {NT_STATUS(0xc0000185), W_ERROR(0x45d)},
+ {NT_STATUS(0xc0000186), W_ERROR(0x45d)},
+ {NT_STATUS(0xc0000188), W_ERROR(0x5de)},
+ {NT_STATUS(0xc0000189), W_ERROR(0x13)},
+ {NT_STATUS(0xc000018a), W_ERROR(0x6fa)},
+ {NT_STATUS(0xc000018b), W_ERROR(0x6fb)},
+ {NT_STATUS(0xc000018c), W_ERROR(0x6fc)},
+ {NT_STATUS(0xc000018d), W_ERROR(0x6fd)},
+ {NT_STATUS(0xc000018e), W_ERROR(0x5dc)},
+ {NT_STATUS(0xc000018f), W_ERROR(0x5dd)},
+ {NT_STATUS(0xc0000190), W_ERROR(0x6fe)},
+ {NT_STATUS(0xc0000192), W_ERROR(0x700)},
+ {NT_STATUS(0xc0000193), W_ERROR(0x701)},
+ {NT_STATUS(0xc0000194), W_ERROR(0x46b)},
+ {NT_STATUS(0xc0000195), W_ERROR(0x4c3)},
+ {NT_STATUS(0xc0000196), W_ERROR(0x4c4)},
+ {NT_STATUS(0xc0000197), W_ERROR(0x5df)},
+ {NT_STATUS(0xc0000198), W_ERROR(0x70f)},
+ {NT_STATUS(0xc0000199), W_ERROR(0x710)},
+ {NT_STATUS(0xc000019a), W_ERROR(0x711)},
+ {NT_STATUS(0xc000019b), W_ERROR(0x712)},
+ {NT_STATUS(0xc0000202), W_ERROR(0x572)},
+ {NT_STATUS(0xc0000203), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000204), W_ERROR(0x717)},
+ {NT_STATUS(0xc0000205), W_ERROR(0x46a)},
+ {NT_STATUS(0xc0000206), W_ERROR(0x6f8)},
+ {NT_STATUS(0xc0000207), W_ERROR(0x4be)},
+ {NT_STATUS(0xc0000208), W_ERROR(0x4be)},
+ {NT_STATUS(0xc0000209), W_ERROR(0x44)},
+ {NT_STATUS(0xc000020a), W_ERROR(0x34)},
+ {NT_STATUS(0xc000020b), W_ERROR(0x40)},
+ {NT_STATUS(0xc000020c), W_ERROR(0x40)},
+ {NT_STATUS(0xc000020d), W_ERROR(0x40)},
+ {NT_STATUS(0xc000020e), W_ERROR(0x44)},
+ {NT_STATUS(0xc000020f), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000210), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000211), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000212), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000213), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000214), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000215), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000216), W_ERROR(0x32)},
+ {NT_STATUS(0xc0000217), W_ERROR(0x32)},
+ {NT_STATUS(0xc000021c), W_ERROR(0x17e6)},
+ {NT_STATUS(0xc0000220), W_ERROR(0x46c)},
+ {NT_STATUS(0xc0000221), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000224), W_ERROR(0x773)},
+ {NT_STATUS(0xc0000225), W_ERROR(0x490)},
+ {NT_STATUS(0xc000022a), W_ERROR(0xc000022a)},
+ {NT_STATUS(0xc000022b), W_ERROR(0xc000022b)},
+ {NT_STATUS(0xc000022d), W_ERROR(0x4d5)},
+ {NT_STATUS(0xc0000230), W_ERROR(0x492)},
+ {NT_STATUS(0xc0000233), W_ERROR(0x774)},
+ {NT_STATUS(0xc0000234), W_ERROR(0x775)},
+ {NT_STATUS(0xc0000235), W_ERROR(0x6)},
+ {NT_STATUS(0xc0000236), W_ERROR(0x4c9)},
+ {NT_STATUS(0xc0000237), W_ERROR(0x4ca)},
+ {NT_STATUS(0xc0000238), W_ERROR(0x4cb)},
+ {NT_STATUS(0xc0000239), W_ERROR(0x4cc)},
+ {NT_STATUS(0xc000023a), W_ERROR(0x4cd)},
+ {NT_STATUS(0xc000023b), W_ERROR(0x4ce)},
+ {NT_STATUS(0xc000023c), W_ERROR(0x4cf)},
+ {NT_STATUS(0xc000023d), W_ERROR(0x4d0)},
+ {NT_STATUS(0xc000023e), W_ERROR(0x4d1)},
+ {NT_STATUS(0xc000023f), W_ERROR(0x4d2)},
+ {NT_STATUS(0xc0000240), W_ERROR(0x4d3)},
+ {NT_STATUS(0xc0000241), W_ERROR(0x4d4)},
+ {NT_STATUS(0xc0000243), W_ERROR(0x4c8)},
+ {NT_STATUS(0xc0000246), W_ERROR(0x4d6)},
+ {NT_STATUS(0xc0000247), W_ERROR(0x4d7)},
+ {NT_STATUS(0xc0000248), W_ERROR(0x4d8)},
+ {NT_STATUS(0xc0000249), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000253), W_ERROR(0x54f)},
+ {NT_STATUS(0xc0000257), W_ERROR(0x4d0)},
+ {NT_STATUS(0xc0000259), W_ERROR(0x573)},
+ {NT_STATUS(0xc000025e), W_ERROR(0x422)},
+ {NT_STATUS(0xc0000262), W_ERROR(0xb6)},
+ {NT_STATUS(0xc0000263), W_ERROR(0x7f)},
+ {NT_STATUS(0xc0000264), W_ERROR(0x120)},
+ {NT_STATUS(0xc0000265), W_ERROR(0x476)},
+ {NT_STATUS(0xc0000267), W_ERROR(0x10fe)},
+ {NT_STATUS(0xc000026c), W_ERROR(0x7d1)},
+ {NT_STATUS(0xc000026d), W_ERROR(0x4b1)},
+ {NT_STATUS(0xc000026e), W_ERROR(0x15)},
+ {NT_STATUS(0xc0000272), W_ERROR(0x491)},
+ {NT_STATUS(0xc0000275), W_ERROR(0x1126)},
+ {NT_STATUS(0xc0000276), W_ERROR(0x1129)},
+ {NT_STATUS(0xc0000277), W_ERROR(0x112a)},
+ {NT_STATUS(0xc0000278), W_ERROR(0x1128)},
+ {NT_STATUS(0xc0000279), W_ERROR(0x780)},
+ {NT_STATUS(0xc0000280), W_ERROR(0x781)},
+ {NT_STATUS(0xc0000281), W_ERROR(0xa1)},
+ {NT_STATUS(0xc0000283), W_ERROR(0x488)},
+ {NT_STATUS(0xc0000284), W_ERROR(0x489)},
+ {NT_STATUS(0xc0000285), W_ERROR(0x48a)},
+ {NT_STATUS(0xc0000286), W_ERROR(0x48b)},
+ {NT_STATUS(0xc0000287), W_ERROR(0x48c)},
+ {NT_STATUS(0xc000028a), W_ERROR(0x5)},
+ {NT_STATUS(0xc000028b), W_ERROR(0x5)},
+ {NT_STATUS(0xc000028d), W_ERROR(0x5)},
+ {NT_STATUS(0xc000028e), W_ERROR(0x5)},
+ {NT_STATUS(0xc000028f), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000290), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000291), W_ERROR(0x1777)},
+ {NT_STATUS(0xc0000292), W_ERROR(0x1778)},
+ {NT_STATUS(0xc0000293), W_ERROR(0x1772)},
+ {NT_STATUS(0xc0000295), W_ERROR(0x1068)},
+ {NT_STATUS(0xc0000296), W_ERROR(0x1069)},
+ {NT_STATUS(0xc0000297), W_ERROR(0x106a)},
+ {NT_STATUS(0xc0000298), W_ERROR(0x106b)},
+ {NT_STATUS(0xc0000299), W_ERROR(0x201a)},
+ {NT_STATUS(0xc000029a), W_ERROR(0x201b)},
+ {NT_STATUS(0xc000029b), W_ERROR(0x201c)},
+ {NT_STATUS(0xc000029c), W_ERROR(0x1)},
+ {NT_STATUS(0xc000029d), W_ERROR(0x10ff)},
+ {NT_STATUS(0xc000029e), W_ERROR(0x1100)},
+ {NT_STATUS(0xc000029f), W_ERROR(0x494)},
+ {NT_STATUS(0xc00002a1), W_ERROR(0x200a)},
+ {NT_STATUS(0xc00002a2), W_ERROR(0x200b)},
+ {NT_STATUS(0xc00002a3), W_ERROR(0x200c)},
+ {NT_STATUS(0xc00002a4), W_ERROR(0x200d)},
+ {NT_STATUS(0xc00002a5), W_ERROR(0x200e)},
+ {NT_STATUS(0xc00002a6), W_ERROR(0x200f)},
+ {NT_STATUS(0xc00002a7), W_ERROR(0x2010)},
+ {NT_STATUS(0xc00002a8), W_ERROR(0x2011)},
+ {NT_STATUS(0xc00002a9), W_ERROR(0x2012)},
+ {NT_STATUS(0xc00002aa), W_ERROR(0x2013)},
+ {NT_STATUS(0xc00002ab), W_ERROR(0x2014)},
+ {NT_STATUS(0xc00002ac), W_ERROR(0x2015)},
+ {NT_STATUS(0xc00002ad), W_ERROR(0x2016)},
+ {NT_STATUS(0xc00002ae), W_ERROR(0x2017)},
+ {NT_STATUS(0xc00002af), W_ERROR(0x2018)},
+ {NT_STATUS(0xc00002b0), W_ERROR(0x2019)},
+ {NT_STATUS(0xc00002b1), W_ERROR(0x211e)},
+ {NT_STATUS(0xc00002b2), W_ERROR(0x1127)},
+ {NT_STATUS(0xc00002b6), W_ERROR(0x651)},
+ {NT_STATUS(0xc00002b7), W_ERROR(0x49a)},
+ {NT_STATUS(0xc00002b8), W_ERROR(0x49b)},
+ {NT_STATUS(0xc00002c1), W_ERROR(0x2024)},
+ {NT_STATUS(0xc00002c3), W_ERROR(0x575)},
+ {NT_STATUS(0xc00002c5), W_ERROR(0x3e6)},
+ {NT_STATUS(0xc00002c6), W_ERROR(0x1075)},
+ {NT_STATUS(0xc00002c7), W_ERROR(0x1076)},
+ {NT_STATUS(0xc00002ca), W_ERROR(0x10e8)},
+ {NT_STATUS(0xc00002cb), W_ERROR(0x2138)},
+ {NT_STATUS(0xc00002cc), W_ERROR(0x4e3)},
+ {NT_STATUS(0xc00002cd), W_ERROR(0x2139)},
+ {NT_STATUS(0xc00002cf), W_ERROR(0x49d)},
+ {NT_STATUS(0xc00002d0), W_ERROR(0x213a)},
+ {NT_STATUS(0xc00002d4), W_ERROR(0x2141)},
+ {NT_STATUS(0xc00002d5), W_ERROR(0x2142)},
+ {NT_STATUS(0xc00002d6), W_ERROR(0x2143)},
+ {NT_STATUS(0xc00002d7), W_ERROR(0x2144)},
+ {NT_STATUS(0xc00002d8), W_ERROR(0x2145)},
+ {NT_STATUS(0xc00002d9), W_ERROR(0x2146)},
+ {NT_STATUS(0xc00002da), W_ERROR(0x2147)},
+ {NT_STATUS(0xc00002db), W_ERROR(0x2148)},
+ {NT_STATUS(0xc00002dc), W_ERROR(0x2149)},
+ {NT_STATUS(0xc00002dd), W_ERROR(0x32)},
+ {NT_STATUS(0xc00002df), W_ERROR(0x2151)},
+ {NT_STATUS(0xc00002e0), W_ERROR(0x2152)},
+ {NT_STATUS(0xc00002e1), W_ERROR(0x2153)},
+ {NT_STATUS(0xc00002e2), W_ERROR(0x2154)},
+ {NT_STATUS(0xc00002e3), W_ERROR(0x215d)},
+ {NT_STATUS(0xc00002e4), W_ERROR(0x2163)},
+ {NT_STATUS(0xc00002e5), W_ERROR(0x2164)},
+ {NT_STATUS(0xc00002e6), W_ERROR(0x2165)},
+ {NT_STATUS(0xc00002e7), W_ERROR(0x216d)},
+ {NT_STATUS(0xc00002fe), W_ERROR(0x45b)},
+ {NT_STATUS(0xc00002ff), W_ERROR(0x4e7)},
+ {NT_STATUS(0xc0000300), W_ERROR(0x4e6)},
+ {NT_STATUS(0x80000001), W_ERROR(0x80000001)},
+ {NT_STATUS(0x80000002), W_ERROR(0x3e6)},
+ {NT_STATUS(0x80000003), W_ERROR(0x80000003)},
+ {NT_STATUS(0x80000004), W_ERROR(0x80000004)},
+ {NT_STATUS(0x80000005), W_ERROR(0xea)},
+ {NT_STATUS(0x80000006), W_ERROR(0x12)},
+ {NT_STATUS(0x8000000b), W_ERROR(0x56f)},
+ {NT_STATUS(0x8000000d), W_ERROR(0x12b)},
+ {NT_STATUS(0x8000000e), W_ERROR(0x1c)},
+ {NT_STATUS(0x8000000f), W_ERROR(0x15)},
+ {NT_STATUS(0x80000010), W_ERROR(0x15)},
+ {NT_STATUS(0x80000011), W_ERROR(0xaa)},
+ {NT_STATUS(0x80000012), W_ERROR(0x103)},
+ {NT_STATUS(0x80000013), W_ERROR(0xfe)},
+ {NT_STATUS(0x80000014), W_ERROR(0xff)},
+ {NT_STATUS(0x80000015), W_ERROR(0xff)},
+ {NT_STATUS(0x80000016), W_ERROR(0x456)},
+ {NT_STATUS(0x8000001a), W_ERROR(0x103)},
+ {NT_STATUS(0x8000001b), W_ERROR(0x44d)},
+ {NT_STATUS(0x8000001c), W_ERROR(0x456)},
+ {NT_STATUS(0x8000001d), W_ERROR(0x457)},
+ {NT_STATUS(0x8000001e), W_ERROR(0x44c)},
+ {NT_STATUS(0x8000001f), W_ERROR(0x44e)},
+ {NT_STATUS(0x80000021), W_ERROR(0x44f)},
+ {NT_STATUS(0x80000022), W_ERROR(0x450)},
+ {NT_STATUS(0x80000025), W_ERROR(0x962)},
+ {NT_STATUS(0x80000288), W_ERROR(0x48d)},
+ {NT_STATUS(0x80000289), W_ERROR(0x48e)},
+ {NT_STATUS_OK, WERR_OK}};
+
+static const struct {
+ WERROR werror;
+ NTSTATUS ntstatus;
+} werror_to_ntstatus_map[] = {
+ { W_ERROR(0x5), NT_STATUS_ACCESS_DENIED },
+ { WERR_OK, NT_STATUS_OK }
+};
+
+
+/*****************************************************************************
+convert a NT status code to a dos class/code
+ *****************************************************************************/
+void ntstatus_to_dos(NTSTATUS ntstatus, uint8_t *eclass, uint32_t *ecode)
+{
+ int i;
+ if (NT_STATUS_IS_OK(ntstatus)) {
+ *eclass = 0;
+ *ecode = 0;
+ return;
+ }
+ if (NT_STATUS_IS_DOS(ntstatus)) {
+ *eclass = NT_STATUS_DOS_CLASS(ntstatus);
+ *ecode = NT_STATUS_DOS_CODE(ntstatus);
+ return;
+ }
+ for (i=0; NT_STATUS_V(ntstatus_to_dos_map[i].ntstatus); i++) {
+ if (NT_STATUS_V(ntstatus) ==
+ NT_STATUS_V(ntstatus_to_dos_map[i].ntstatus)) {
+ *eclass = ntstatus_to_dos_map[i].dos_class;
+ *ecode = ntstatus_to_dos_map[i].dos_code;
+ return;
+ }
+ }
+ *eclass = ERRHRD;
+ *ecode = ERRgeneral;
+}
+
+
+/*****************************************************************************
+convert a WERROR to a NT status32 code
+ *****************************************************************************/
+NTSTATUS werror_to_ntstatus(WERROR error)
+{
+ int i;
+ if (W_ERROR_IS_OK(error)) return NT_STATUS_OK;
+
+ for (i=0; !W_ERROR_IS_OK(werror_to_ntstatus_map[i].werror); i++) {
+ if (W_ERROR_V(error) ==
+ W_ERROR_V(werror_to_ntstatus_map[i].werror)) {
+ return werror_to_ntstatus_map[i].ntstatus;
+ }
+ }
+
+ for (i=0; NT_STATUS_V(ntstatus_to_werror_map[i].ntstatus); i++) {
+ if (W_ERROR_V(error) ==
+ W_ERROR_V(ntstatus_to_werror_map[i].werror)) {
+ return ntstatus_to_werror_map[i].ntstatus;
+ }
+ }
+
+ /* just guess ... */
+ return NT_STATUS(W_ERROR_V(error) | 0xc0000000);
+}
+
+/*****************************************************************************
+convert a NTSTATUS to a WERROR
+ *****************************************************************************/
+WERROR ntstatus_to_werror(NTSTATUS error)
+{
+ int i;
+ if (NT_STATUS_IS_OK(error)) return WERR_OK;
+ for (i=0; NT_STATUS_V(ntstatus_to_werror_map[i].ntstatus); i++) {
+ if (NT_STATUS_V(error) ==
+ NT_STATUS_V(ntstatus_to_werror_map[i].ntstatus)) {
+ return ntstatus_to_werror_map[i].werror;
+ }
+ }
+
+ /* a lame guess */
+ return W_ERROR(NT_STATUS_V(error) & 0xffff);
+}
+
+/* Convert a Unix error code to a WERROR. */
+WERROR unix_to_werror(int unix_error)
+{
+ return ntstatus_to_werror(map_nt_error_from_unix_common(unix_error));
+}
diff --git a/libcli/util/hresult_err_table.txt b/libcli/util/hresult_err_table.txt
new file mode 100644
index 0000000..d04dff9
--- /dev/null
+++ b/libcli/util/hresult_err_table.txt
@@ -0,0 +1,20520 @@
+Errors retrieved from https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/705fb797-2175-4a90-b5a3-3918024b10b8.
+Licence retrieved from https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/1bc92ddf-b79e-413c-bbaa-99a5281a6c90:
+
+Intellectual Property Rights Notice for Open Specifications Documentation
+
+ - Technical Documentation. Microsoft publishes Open Specifications documentation (“this documentation”) for protocols, file formats, data portability, computer languages, and standards support. Additionally, overview documents cover inter-protocol relationships and interactions.
+
+ - Copyrights. This documentation is covered by Microsoft copyrights. Regardless of any other terms that are contained in the terms of use for the Microsoft website that hosts this documentation, you can make copies of it in order to develop implementations of the technologies that are described in this documentation and can distribute portions of it in your implementations that use these technologies or in your documentation as necessary to properly document the implementation. You can also distribute in your implementation, with or without modification, any schemas, IDLs, or code samples that are included in the documentation. This permission also applies to any documents that are referenced in the Open Specifications documentation.
+
+ - No Trade Secrets. Microsoft does not claim any trade secret rights in this documentation.
+
+ - Patents. Microsoft has patents that might cover your implementations of the technologies described in the Open Specifications documentation. Neither this notice nor Microsoft's delivery of this documentation grants any licenses under those patents or any other Microsoft patents. However, a given Open Specifications document might be covered by the Microsoft Open Specifications Promise or the Microsoft Community Promise. If you would prefer a written license, or if the technologies described in this documentation are not covered by the Open Specifications Promise or Community Promise, as applicable, patent licenses are available by contacting iplg@microsoft.com.
+
+ - License Programs. To see all of the protocols in scope under a specific license program and the associated patents, visit the Patent Map.
+
+ - Trademarks. The names of companies and products contained in this documentation might be covered by trademarks or similar intellectual property rights. This notice does not grant any licenses under those rights. For a list of Microsoft trademarks, visit www.microsoft.com/trademarks.
+
+ - Fictitious Names. The example companies, organizations, products, domain names, email addresses, logos, people, places, and events that are depicted in this documentation are fictitious. No association with any real company, organization, product, domain name, email address, logo, person, place, or event is intended or should be inferred.
+
+Reservation of Rights. All other rights are reserved, and this notice does not grant any rights other than as specifically described above, whether by implication, estoppel, or otherwise.
+
+Tools. The Open Specifications documentation does not require the use of Microsoft programming tools or programming environments in order for you to develop an implementation. If you have access to Microsoft programming tools and environments, you are free to take advantage of them. Certain Open Specifications documents are intended for use in conjunction with publicly available standards specifications and network programming art and, as such, assume that the reader either is familiar with the aforementioned material or has immediate access to it.
+
+===========
+
+0x00030200
+
+STG_S_CONVERTED
+
+
+The underlying file was converted to compound file format.
+
+0x00030201
+
+STG_S_BLOCK
+
+
+The storage operation should block until more data is available.
+
+0x00030202
+
+STG_S_RETRYNOW
+
+
+The storage operation should retry immediately.
+
+0x00030203
+
+STG_S_MONITORING
+
+
+The notified event sink will not influence the storage operation.
+
+0x00030204
+
+STG_S_MULTIPLEOPENS
+
+
+Multiple opens prevent consolidated (commit succeeded).
+
+0x00030205
+
+STG_S_CONSOLIDATIONFAILED
+
+
+Consolidation of the storage file failed (commit succeeded).
+
+0x00030206
+
+STG_S_CANNOTCONSOLIDATE
+
+
+Consolidation of the storage file is inappropriate (commit succeeded).
+
+0x00040000
+
+OLE_S_USEREG
+
+
+Use the registry database to provide the requested information.
+
+0x00040001
+
+OLE_S_STATIC
+
+
+Success, but static.
+
+0x00040002
+
+OLE_S_MAC_CLIPFORMAT
+
+
+Macintosh clipboard format.
+
+0x00040100
+
+DRAGDROP_S_DROP
+
+
+Successful drop took place.
+
+0x00040101
+
+DRAGDROP_S_CANCEL
+
+
+Drag-drop operation canceled.
+
+0x00040102
+
+DRAGDROP_S_USEDEFAULTCURSORS
+
+
+Use the default cursor.
+
+0x00040130
+
+DATA_S_SAMEFORMATETC
+
+
+Data has same FORMATETC.
+
+0x00040140
+
+VIEW_S_ALREADY_FROZEN
+
+
+View is already frozen.
+
+0x00040170
+
+CACHE_S_FORMATETC_NOTSUPPORTED
+
+
+FORMATETC not supported.
+
+0x00040171
+
+CACHE_S_SAMECACHE
+
+
+Same cache.
+
+0x00040172
+
+CACHE_S_SOMECACHES_NOTUPDATED
+
+
+Some caches are not updated.
+
+0x00040180
+
+OLEOBJ_S_INVALIDVERB
+
+
+Invalid verb for OLE object.
+
+0x00040181
+
+OLEOBJ_S_CANNOT_DOVERB_NOW
+
+
+Verb number is valid but verb cannot be done now.
+
+0x00040182
+
+OLEOBJ_S_INVALIDHWND
+
+
+Invalid window handle passed.
+
+0x000401A0
+
+INPLACE_S_TRUNCATED
+
+
+Message is too long; some of it had to be truncated before displaying.
+
+0x000401C0
+
+CONVERT10_S_NO_PRESENTATION
+
+
+Unable to convert OLESTREAM to IStorage.
+
+0x000401E2
+
+MK_S_REDUCED_TO_SELF
+
+
+Moniker reduced to itself.
+
+0x000401E4
+
+MK_S_ME
+
+
+Common prefix is this moniker.
+
+0x000401E5
+
+MK_S_HIM
+
+
+Common prefix is input moniker.
+
+0x000401E6
+
+MK_S_US
+
+
+Common prefix is both monikers.
+
+0x000401E7
+
+MK_S_MONIKERALREADYREGISTERED
+
+
+Moniker is already registered in running object table.
+
+0x00040200
+
+EVENT_S_SOME_SUBSCRIBERS_FAILED
+
+
+An event was able to invoke some, but not all, of the subscribers.
+
+0x00040202
+
+EVENT_S_NOSUBSCRIBERS
+
+
+An event was delivered, but there were no subscribers.
+
+0x00041300
+
+SCHED_S_TASK_READY
+
+
+The task is ready to run at its next scheduled time.
+
+0x00041301
+
+SCHED_S_TASK_RUNNING
+
+
+The task is currently running.
+
+0x00041302
+
+SCHED_S_TASK_DISABLED
+
+
+The task will not run at the scheduled times because it has been disabled.
+
+0x00041303
+
+SCHED_S_TASK_HAS_NOT_RUN
+
+
+The task has not yet run.
+
+0x00041304
+
+SCHED_S_TASK_NO_MORE_RUNS
+
+
+There are no more runs scheduled for this task.
+
+0x00041305
+
+SCHED_S_TASK_NOT_SCHEDULED
+
+
+One or more of the properties that are needed to run this task on a schedule have not been set.
+
+0x00041306
+
+SCHED_S_TASK_TERMINATED
+
+
+The last run of the task was terminated by the user.
+
+0x00041307
+
+SCHED_S_TASK_NO_VALID_TRIGGERS
+
+
+Either the task has no triggers, or the existing triggers are disabled or not set.
+
+0x00041308
+
+SCHED_S_EVENT_TRIGGER
+
+
+Event triggers do not have set run times.
+
+0x0004131B
+
+SCHED_S_SOME_TRIGGERS_FAILED
+
+
+The task is registered, but not all specified triggers will start the task.
+
+0x0004131C
+
+SCHED_S_BATCH_LOGON_PROBLEM
+
+
+The task is registered, but it might fail to start. Batch logon privilege needs to be enabled for the task principal.
+
+0x0004D000
+
+XACT_S_ASYNC
+
+
+An asynchronous operation was specified. The operation has begun, but its outcome is not known yet.
+
+0x0004D002
+
+XACT_S_READONLY
+
+
+The method call succeeded because the transaction was read-only.
+
+0x0004D003
+
+XACT_S_SOMENORETAIN
+
+
+The transaction was successfully aborted. However, this is a coordinated transaction, and a number of enlisted resources were aborted outright because they could not support abort-retaining semantics.
+
+0x0004D004
+
+XACT_S_OKINFORM
+
+
+No changes were made during this call, but the sink wants another chance to look if any other sinks make further changes.
+
+0x0004D005
+
+XACT_S_MADECHANGESCONTENT
+
+
+The sink is content and wants the transaction to proceed. Changes were made to one or more resources during this call.
+
+0x0004D006
+
+XACT_S_MADECHANGESINFORM
+
+
+The sink is for the moment and wants the transaction to proceed, but if other changes are made following this return by other event sinks, this sink wants another chance to look.
+
+0x0004D007
+
+XACT_S_ALLNORETAIN
+
+
+The transaction was successfully aborted. However, the abort was nonretaining.
+
+0x0004D008
+
+XACT_S_ABORTING
+
+
+An abort operation was already in progress.
+
+0x0004D009
+
+XACT_S_SINGLEPHASE
+
+
+The resource manager has performed a single-phase commit of the transaction.
+
+0x0004D00A
+
+XACT_S_LOCALLY_OK
+
+
+The local transaction has not aborted.
+
+0x0004D010
+
+XACT_S_LASTRESOURCEMANAGER
+
+
+The resource manager has requested to be the coordinator (last resource manager) for the transaction.
+
+0x00080012
+
+CO_S_NOTALLINTERFACES
+
+
+Not all the requested interfaces were available.
+
+0x00080013
+
+CO_S_MACHINENAMENOTFOUND
+
+
+The specified machine name was not found in the cache.
+
+0x00090312
+
+SEC_I_CONTINUE_NEEDED
+
+
+The function completed successfully, but it must be called again to complete the context.
+
+0x00090313
+
+SEC_I_COMPLETE_NEEDED
+
+
+The function completed successfully, but CompleteToken must be called.
+
+0x00090314
+
+SEC_I_COMPLETE_AND_CONTINUE
+
+
+The function completed successfully, but both CompleteToken and this function must be called to complete the context.
+
+0x00090315
+
+SEC_I_LOCAL_LOGON
+
+
+The logon was completed, but no network authority was available. The logon was made using locally known information.
+
+0x00090317
+
+SEC_I_CONTEXT_EXPIRED
+
+
+The context has expired and can no longer be used.
+
+0x00090320
+
+SEC_I_INCOMPLETE_CREDENTIALS
+
+
+The credentials supplied were not complete and could not be verified. Additional information can be returned from the context.
+
+0x00090321
+
+SEC_I_RENEGOTIATE
+
+
+The context data must be renegotiated with the peer.
+
+0x00090323
+
+SEC_I_NO_LSA_CONTEXT
+
+
+There is no LSA mode context associated with this context.
+
+0x0009035C
+
+SEC_I_SIGNATURE_NEEDED
+
+
+A signature operation must be performed before the user can authenticate.
+
+0x00091012
+
+CRYPT_I_NEW_PROTECTION_REQUIRED
+
+
+The protected data needs to be reprotected.
+
+0x000D0000
+
+NS_S_CALLPENDING
+
+
+The requested operation is pending completion.
+
+0x000D0001
+
+NS_S_CALLABORTED
+
+
+The requested operation was aborted by the client.
+
+0x000D0002
+
+NS_S_STREAM_TRUNCATED
+
+
+The stream was purposefully stopped before completion.
+
+0x000D0BC8
+
+NS_S_REBUFFERING
+
+
+The requested operation has caused the source to rebuffer.
+
+0x000D0BC9
+
+NS_S_DEGRADING_QUALITY
+
+
+The requested operation has caused the source to degrade codec quality.
+
+0x000D0BDB
+
+NS_S_TRANSCRYPTOR_EOF
+
+
+The transcryptor object has reached end of file.
+
+0x000D0FE8
+
+NS_S_WMP_UI_VERSIONMISMATCH
+
+
+An upgrade is needed for the theme manager to correctly show this skin. Skin reports version: %.1f.
+
+0x000D0FE9
+
+NS_S_WMP_EXCEPTION
+
+
+An error occurred in one of the UI components.
+
+0x000D1040
+
+NS_S_WMP_LOADED_GIF_IMAGE
+
+
+Successfully loaded a GIF file.
+
+0x000D1041
+
+NS_S_WMP_LOADED_PNG_IMAGE
+
+
+Successfully loaded a PNG file.
+
+0x000D1042
+
+NS_S_WMP_LOADED_BMP_IMAGE
+
+
+Successfully loaded a BMP file.
+
+0x000D1043
+
+NS_S_WMP_LOADED_JPG_IMAGE
+
+
+Successfully loaded a JPG file.
+
+0x000D104F
+
+NS_S_WMG_FORCE_DROP_FRAME
+
+
+Drop this frame.
+
+0x000D105F
+
+NS_S_WMR_ALREADYRENDERED
+
+
+The specified stream has already been rendered.
+
+0x000D1060
+
+NS_S_WMR_PINTYPEPARTIALMATCH
+
+
+The specified type partially matches this pin type.
+
+0x000D1061
+
+NS_S_WMR_PINTYPEFULLMATCH
+
+
+The specified type fully matches this pin type.
+
+0x000D1066
+
+NS_S_WMG_ADVISE_DROP_FRAME
+
+
+The timestamp is late compared to the current render position. Advise dropping this frame.
+
+0x000D1067
+
+NS_S_WMG_ADVISE_DROP_TO_KEYFRAME
+
+
+The timestamp is severely late compared to the current render position. Advise dropping everything up to the next key frame.
+
+0x000D10DB
+
+NS_S_NEED_TO_BUY_BURN_RIGHTS
+
+
+No burn rights. You will be prompted to buy burn rights when you try to burn this file to an audio CD.
+
+0x000D10FE
+
+NS_S_WMPCORE_PLAYLISTCLEARABORT
+
+
+Failed to clear playlist because it was aborted by user.
+
+0x000D10FF
+
+NS_S_WMPCORE_PLAYLISTREMOVEITEMABORT
+
+
+Failed to remove item in the playlist since it was aborted by user.
+
+0x000D1102
+
+NS_S_WMPCORE_PLAYLIST_CREATION_PENDING
+
+
+Playlist is being generated asynchronously.
+
+0x000D1103
+
+NS_S_WMPCORE_MEDIA_VALIDATION_PENDING
+
+
+Validation of the media is pending.
+
+0x000D1104
+
+NS_S_WMPCORE_PLAYLIST_REPEAT_SECONDARY_SEGMENTS_IGNORED
+
+
+Encountered more than one Repeat block during ASX processing.
+
+0x000D1105
+
+NS_S_WMPCORE_COMMAND_NOT_AVAILABLE
+
+
+Current state of WMP disallows calling this method or property.
+
+0x000D1106
+
+NS_S_WMPCORE_PLAYLIST_NAME_AUTO_GENERATED
+
+
+Name for the playlist has been auto generated.
+
+0x000D1107
+
+NS_S_WMPCORE_PLAYLIST_IMPORT_MISSING_ITEMS
+
+
+The imported playlist does not contain all items from the original.
+
+0x000D1108
+
+NS_S_WMPCORE_PLAYLIST_COLLAPSED_TO_SINGLE_MEDIA
+
+
+The M3U playlist has been ignored because it only contains one item.
+
+0x000D1109
+
+NS_S_WMPCORE_MEDIA_CHILD_PLAYLIST_OPEN_PENDING
+
+
+The open for the child playlist associated with this media is pending.
+
+0x000D110A
+
+NS_S_WMPCORE_MORE_NODES_AVAIABLE
+
+
+More nodes support the interface requested, but the array for returning them is full.
+
+0x000D1135
+
+NS_S_WMPBR_SUCCESS
+
+
+Backup or Restore successful!.
+
+0x000D1136
+
+NS_S_WMPBR_PARTIALSUCCESS
+
+
+Transfer complete with limitations.
+
+0x000D1144
+
+NS_S_WMPEFFECT_TRANSPARENT
+
+
+Request to the effects control to change transparency status to transparent.
+
+0x000D1145
+
+NS_S_WMPEFFECT_OPAQUE
+
+
+Request to the effects control to change transparency status to opaque.
+
+0x000D114E
+
+NS_S_OPERATION_PENDING
+
+
+The requested application pane is performing an operation and will not be released.
+
+0x000D1359
+
+NS_S_TRACK_BUY_REQUIRES_ALBUM_PURCHASE
+
+
+The file is only available for purchase when you buy the entire album.
+
+0x000D135E
+
+NS_S_NAVIGATION_COMPLETE_WITH_ERRORS
+
+
+There were problems completing the requested navigation. There are identifiers missing in the catalog.
+
+0x000D1361
+
+NS_S_TRACK_ALREADY_DOWNLOADED
+
+
+Track already downloaded.
+
+0x000D1519
+
+NS_S_PUBLISHING_POINT_STARTED_WITH_FAILED_SINKS
+
+
+The publishing point successfully started, but one or more of the requested data writer plug-ins failed.
+
+0x000D2726
+
+NS_S_DRM_LICENSE_ACQUIRED
+
+
+Status message: The license was acquired.
+
+0x000D2727
+
+NS_S_DRM_INDIVIDUALIZED
+
+
+Status message: The security upgrade has been completed.
+
+0x000D2746
+
+NS_S_DRM_MONITOR_CANCELLED
+
+
+Status message: License monitoring has been canceled.
+
+0x000D2747
+
+NS_S_DRM_ACQUIRE_CANCELLED
+
+
+Status message: License acquisition has been canceled.
+
+0x000D276E
+
+NS_S_DRM_BURNABLE_TRACK
+
+
+The track is burnable and had no playlist burn limit.
+
+0x000D276F
+
+NS_S_DRM_BURNABLE_TRACK_WITH_PLAYLIST_RESTRICTION
+
+
+The track is burnable but has a playlist burn limit.
+
+0x000D27DE
+
+NS_S_DRM_NEEDS_INDIVIDUALIZATION
+
+
+A security upgrade is required to perform the operation on this media file.
+
+0x000D2AF8
+
+NS_S_REBOOT_RECOMMENDED
+
+
+Installation was successful; however, some file cleanup is not complete. For best results, restart your computer.
+
+0x000D2AF9
+
+NS_S_REBOOT_REQUIRED
+
+
+Installation was successful; however, some file cleanup is not complete. To continue, you must restart your computer.
+
+0x000D2F09
+
+NS_S_EOSRECEDING
+
+
+EOS hit during rewinding.
+
+0x000D2F0D
+
+NS_S_CHANGENOTICE
+
+
+Internal.
+
+0x001F0001
+
+ERROR_FLT_IO_COMPLETE
+
+
+The IO was completed by a filter.
+
+0x00262307
+
+ERROR_GRAPHICS_MODE_NOT_PINNED
+
+
+No mode is pinned on the specified VidPN source or target.
+
+0x0026231E
+
+ERROR_GRAPHICS_NO_PREFERRED_MODE
+
+
+Specified mode set does not specify preference for one of its modes.
+
+0x0026234B
+
+ERROR_GRAPHICS_DATASET_IS_EMPTY
+
+
+Specified data set (for example, mode set, frequency range set, descriptor set, and topology) is empty.
+
+0x0026234C
+
+ERROR_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET
+
+
+Specified data set (for example, mode set, frequency range set, descriptor set, and topology) does not contain any more elements.
+
+0x00262351
+
+ERROR_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED
+
+
+Specified content transformation is not pinned on the specified VidPN present path.
+
+0x00300100
+
+PLA_S_PROPERTY_IGNORED
+
+
+Property value will be ignored.
+
+0x00340001
+
+ERROR_NDIS_INDICATION_REQUIRED
+
+
+The request will be completed later by a Network Driver Interface Specification (NDIS) status indication.
+
+0x0DEAD100
+
+TRK_S_OUT_OF_SYNC
+
+
+The VolumeSequenceNumber of a MOVE_NOTIFICATION request is incorrect.
+
+0x0DEAD102
+
+TRK_VOLUME_NOT_FOUND
+
+
+The VolumeID in a request was not found in the server's ServerVolumeTable.
+
+0x0DEAD103
+
+TRK_VOLUME_NOT_OWNED
+
+
+A notification was sent to the LnkSvrMessage method, but the RequestMachine for the request was not the VolumeOwner for a VolumeID in the request.
+
+0x0DEAD107
+
+TRK_S_NOTIFICATION_QUOTA_EXCEEDED
+
+
+The server received a MOVE_NOTIFICATION request, but the FileTable size limit has already been reached.
+
+0x400D004F
+
+NS_I_TIGER_START
+
+
+The Title Server %1 is running.
+
+0x400D0051
+
+NS_I_CUB_START
+
+
+Content Server %1 (%2) is starting.
+
+0x400D0052
+
+NS_I_CUB_RUNNING
+
+
+Content Server %1 (%2) is running.
+
+0x400D0054
+
+NS_I_DISK_START
+
+
+Disk %1 ( %2 ) on Content Server %3, is running.
+
+0x400D0056
+
+NS_I_DISK_REBUILD_STARTED
+
+
+Started rebuilding disk %1 ( %2 ) on Content Server %3.
+
+0x400D0057
+
+NS_I_DISK_REBUILD_FINISHED
+
+
+Finished rebuilding disk %1 ( %2 ) on Content Server %3.
+
+0x400D0058
+
+NS_I_DISK_REBUILD_ABORTED
+
+
+Aborted rebuilding disk %1 ( %2 ) on Content Server %3.
+
+0x400D0059
+
+NS_I_LIMIT_FUNNELS
+
+
+A NetShow administrator at network location %1 set the data stream limit to %2 streams.
+
+0x400D005A
+
+NS_I_START_DISK
+
+
+A NetShow administrator at network location %1 started disk %2.
+
+0x400D005B
+
+NS_I_STOP_DISK
+
+
+A NetShow administrator at network location %1 stopped disk %2.
+
+0x400D005C
+
+NS_I_STOP_CUB
+
+
+A NetShow administrator at network location %1 stopped Content Server %2.
+
+0x400D005D
+
+NS_I_KILL_USERSESSION
+
+
+A NetShow administrator at network location %1 aborted user session %2 from the system.
+
+0x400D005E
+
+NS_I_KILL_CONNECTION
+
+
+A NetShow administrator at network location %1 aborted obsolete connection %2 from the system.
+
+0x400D005F
+
+NS_I_REBUILD_DISK
+
+
+A NetShow administrator at network location %1 started rebuilding disk %2.
+
+0x400D0069
+
+MCMADM_I_NO_EVENTS
+
+
+Event initialization failed, there will be no MCM events.
+
+0x400D006E
+
+NS_I_LOGGING_FAILED
+
+
+The logging operation failed.
+
+0x400D0070
+
+NS_I_LIMIT_BANDWIDTH
+
+
+A NetShow administrator at network location %1 set the maximum bandwidth limit to %2 bps.
+
+0x400D0191
+
+NS_I_CUB_UNFAIL_LINK
+
+
+Content Server %1 (%2) has established its link to Content Server %3.
+
+0x400D0193
+
+NS_I_RESTRIPE_START
+
+
+Restripe operation has started.
+
+0x400D0194
+
+NS_I_RESTRIPE_DONE
+
+
+Restripe operation has completed.
+
+0x400D0196
+
+NS_I_RESTRIPE_DISK_OUT
+
+
+Content disk %1 (%2) on Content Server %3 has been restriped out.
+
+0x400D0197
+
+NS_I_RESTRIPE_CUB_OUT
+
+
+Content server %1 (%2) has been restriped out.
+
+0x400D0198
+
+NS_I_DISK_STOP
+
+
+Disk %1 ( %2 ) on Content Server %3, has been offlined.
+
+0x400D14BE
+
+NS_I_PLAYLIST_CHANGE_RECEDING
+
+
+The playlist change occurred while receding.
+
+0x400D2EFF
+
+NS_I_RECONNECTED
+
+
+The client is reconnected.
+
+0x400D2F01
+
+NS_I_NOLOG_STOP
+
+
+Forcing a switch to a pending header on start.
+
+0x400D2F03
+
+NS_I_EXISTING_PACKETIZER
+
+
+There is already an existing packetizer plugin for the stream.
+
+0x400D2F04
+
+NS_I_MANUAL_PROXY
+
+
+The proxy setting is manual.
+
+0x40262009
+
+ERROR_GRAPHICS_DRIVER_MISMATCH
+
+
+The kernel driver detected a version mismatch between it and the user mode driver.
+
+0x4026242F
+
+ERROR_GRAPHICS_UNKNOWN_CHILD_STATUS
+
+
+Child device presence was not reliably detected.
+
+0x40262437
+
+ERROR_GRAPHICS_LEADLINK_START_DEFERRED
+
+
+Starting the lead-link adapter has been deferred temporarily.
+
+0x40262439
+
+ERROR_GRAPHICS_POLLING_TOO_FREQUENTLY
+
+
+The display adapter is being polled for children too frequently at the same polling level.
+
+0x4026243A
+
+ERROR_GRAPHICS_START_DEFERRED
+
+
+Starting the adapter has been deferred temporarily.
+
+0x8000000A
+
+E_PENDING
+
+
+The data necessary to complete this operation is not yet available.
+
+0x80004001
+
+E_NOTIMPL
+
+
+Not implemented.
+
+0x80004002
+
+E_NOINTERFACE
+
+
+No such interface supported.
+
+0x80004003
+
+E_POINTER
+
+
+Invalid pointer.
+
+0x80004004
+
+E_ABORT
+
+
+Operation aborted.
+
+0x80004005
+
+E_FAIL
+
+
+Unspecified error.
+
+0x80004006
+
+CO_E_INIT_TLS
+
+
+Thread local storage failure.
+
+0x80004007
+
+CO_E_INIT_SHARED_ALLOCATOR
+
+
+Get shared memory allocator failure.
+
+0x80004008
+
+CO_E_INIT_MEMORY_ALLOCATOR
+
+
+Get memory allocator failure.
+
+0x80004009
+
+CO_E_INIT_CLASS_CACHE
+
+
+Unable to initialize class cache.
+
+0x8000400A
+
+CO_E_INIT_RPC_CHANNEL
+
+
+Unable to initialize remote procedure call (RPC) services.
+
+0x8000400B
+
+CO_E_INIT_TLS_SET_CHANNEL_CONTROL
+
+
+Cannot set thread local storage channel control.
+
+0x8000400C
+
+CO_E_INIT_TLS_CHANNEL_CONTROL
+
+
+Could not allocate thread local storage channel control.
+
+0x8000400D
+
+CO_E_INIT_UNACCEPTED_USER_ALLOCATOR
+
+
+The user-supplied memory allocator is unacceptable.
+
+0x8000400E
+
+CO_E_INIT_SCM_MUTEX_EXISTS
+
+
+The OLE service mutex already exists.
+
+0x8000400F
+
+CO_E_INIT_SCM_FILE_MAPPING_EXISTS
+
+
+The OLE service file mapping already exists.
+
+0x80004010
+
+CO_E_INIT_SCM_MAP_VIEW_OF_FILE
+
+
+Unable to map view of file for OLE service.
+
+0x80004011
+
+CO_E_INIT_SCM_EXEC_FAILURE
+
+
+Failure attempting to launch OLE service.
+
+0x80004012
+
+CO_E_INIT_ONLY_SINGLE_THREADED
+
+
+There was an attempt to call CoInitialize a second time while single-threaded.
+
+0x80004013
+
+CO_E_CANT_REMOTE
+
+
+A Remote activation was necessary but was not allowed.
+
+0x80004014
+
+CO_E_BAD_SERVER_NAME
+
+
+A Remote activation was necessary, but the server name provided was invalid.
+
+0x80004015
+
+CO_E_WRONG_SERVER_IDENTITY
+
+
+The class is configured to run as a security ID different from the caller.
+
+0x80004016
+
+CO_E_OLE1DDE_DISABLED
+
+
+Use of OLE1 services requiring Dynamic Data Exchange (DDE) Windows is disabled.
+
+0x80004017
+
+CO_E_RUNAS_SYNTAX
+
+
+A RunAs specification must be <domain name>\<user name> or simply <user name>.
+
+0x80004018
+
+CO_E_CREATEPROCESS_FAILURE
+
+
+The server process could not be started. The path name might be incorrect.
+
+0x80004019
+
+CO_E_RUNAS_CREATEPROCESS_FAILURE
+
+
+The server process could not be started as the configured identity. The path name might be incorrect or unavailable.
+
+0x8000401A
+
+CO_E_RUNAS_LOGON_FAILURE
+
+
+The server process could not be started because the configured identity is incorrect. Check the user name and password.
+
+0x8000401B
+
+CO_E_LAUNCH_PERMSSION_DENIED
+
+
+The client is not allowed to launch this server.
+
+0x8000401C
+
+CO_E_START_SERVICE_FAILURE
+
+
+The service providing this server could not be started.
+
+0x8000401D
+
+CO_E_REMOTE_COMMUNICATION_FAILURE
+
+
+This computer was unable to communicate with the computer providing the server.
+
+0x8000401E
+
+CO_E_SERVER_START_TIMEOUT
+
+
+The server did not respond after being launched.
+
+0x8000401F
+
+CO_E_CLSREG_INCONSISTENT
+
+
+The registration information for this server is inconsistent or incomplete.
+
+0x80004020
+
+CO_E_IIDREG_INCONSISTENT
+
+
+The registration information for this interface is inconsistent or incomplete.
+
+0x80004021
+
+CO_E_NOT_SUPPORTED
+
+
+The operation attempted is not supported.
+
+0x80004022
+
+CO_E_RELOAD_DLL
+
+
+A DLL must be loaded.
+
+0x80004023
+
+CO_E_MSI_ERROR
+
+
+A Microsoft Software Installer error was encountered.
+
+0x80004024
+
+CO_E_ATTEMPT_TO_CREATE_OUTSIDE_CLIENT_CONTEXT
+
+
+The specified activation could not occur in the client context as specified.
+
+0x80004025
+
+CO_E_SERVER_PAUSED
+
+
+Activations on the server are paused.
+
+0x80004026
+
+CO_E_SERVER_NOT_PAUSED
+
+
+Activations on the server are not paused.
+
+0x80004027
+
+CO_E_CLASS_DISABLED
+
+
+The component or application containing the component has been disabled.
+
+0x80004028
+
+CO_E_CLRNOTAVAILABLE
+
+
+The common language runtime is not available.
+
+0x80004029
+
+CO_E_ASYNC_WORK_REJECTED
+
+
+The thread-pool rejected the submitted asynchronous work.
+
+0x8000402A
+
+CO_E_SERVER_INIT_TIMEOUT
+
+
+The server started, but it did not finish initializing in a timely fashion.
+
+0x8000402B
+
+CO_E_NO_SECCTX_IN_ACTIVATE
+
+
+Unable to complete the call because there is no COM+ security context inside IObjectControl.Activate.
+
+0x80004030
+
+CO_E_TRACKER_CONFIG
+
+
+The provided tracker configuration is invalid.
+
+0x80004031
+
+CO_E_THREADPOOL_CONFIG
+
+
+The provided thread pool configuration is invalid.
+
+0x80004032
+
+CO_E_SXS_CONFIG
+
+
+The provided side-by-side configuration is invalid.
+
+0x80004033
+
+CO_E_MALFORMED_SPN
+
+
+The server principal name (SPN) obtained during security negotiation is malformed.
+
+0x8000FFFF
+
+E_UNEXPECTED
+
+
+Catastrophic failure.
+
+0x80010001
+
+RPC_E_CALL_REJECTED
+
+
+Call was rejected by callee.
+
+0x80010002
+
+RPC_E_CALL_CANCELED
+
+
+Call was canceled by the message filter.
+
+0x80010003
+
+RPC_E_CANTPOST_INSENDCALL
+
+
+The caller is dispatching an intertask SendMessage call and cannot call out via PostMessage.
+
+0x80010004
+
+RPC_E_CANTCALLOUT_INASYNCCALL
+
+
+The caller is dispatching an asynchronous call and cannot make an outgoing call on behalf of this call.
+
+0x80010005
+
+RPC_E_CANTCALLOUT_INEXTERNALCALL
+
+
+It is illegal to call out while inside message filter.
+
+0x80010006
+
+RPC_E_CONNECTION_TERMINATED
+
+
+The connection terminated or is in a bogus state and can no longer be used. Other connections are still valid.
+
+0x80010007
+
+RPC_E_SERVER_DIED
+
+
+The callee (the server, not the server application) is not available and disappeared; all connections are invalid. The call might have executed.
+
+0x80010008
+
+RPC_E_CLIENT_DIED
+
+
+The caller (client) disappeared while the callee (server) was processing a call.
+
+0x80010009
+
+RPC_E_INVALID_DATAPACKET
+
+
+The data packet with the marshaled parameter data is incorrect.
+
+0x8001000A
+
+RPC_E_CANTTRANSMIT_CALL
+
+
+The call was not transmitted properly; the message queue was full and was not emptied after yielding.
+
+0x8001000B
+
+RPC_E_CLIENT_CANTMARSHAL_DATA
+
+
+The client RPC caller cannot marshal the parameter data due to errors (such as low memory).
+
+0x8001000C
+
+RPC_E_CLIENT_CANTUNMARSHAL_DATA
+
+
+The client RPC caller cannot unmarshal the return data due to errors (such as low memory).
+
+0x8001000D
+
+RPC_E_SERVER_CANTMARSHAL_DATA
+
+
+The server RPC callee cannot marshal the return data due to errors (such as low memory).
+
+0x8001000E
+
+RPC_E_SERVER_CANTUNMARSHAL_DATA
+
+
+The server RPC callee cannot unmarshal the parameter data due to errors (such as low memory).
+
+0x8001000F
+
+RPC_E_INVALID_DATA
+
+
+Received data is invalid. The data might be server or client data.
+
+0x80010010
+
+RPC_E_INVALID_PARAMETER
+
+
+A particular parameter is invalid and cannot be (un)marshaled.
+
+0x80010011
+
+RPC_E_CANTCALLOUT_AGAIN
+
+
+There is no second outgoing call on same channel in DDE conversation.
+
+0x80010012
+
+RPC_E_SERVER_DIED_DNE
+
+
+The callee (the server, not the server application) is not available and disappeared; all connections are invalid. The call did not execute.
+
+0x80010100
+
+RPC_E_SYS_CALL_FAILED
+
+
+System call failed.
+
+0x80010101
+
+RPC_E_OUT_OF_RESOURCES
+
+
+Could not allocate some required resource (such as memory or events)
+
+0x80010102
+
+RPC_E_ATTEMPTED_MULTITHREAD
+
+
+Attempted to make calls on more than one thread in single-threaded mode.
+
+0x80010103
+
+RPC_E_NOT_REGISTERED
+
+
+The requested interface is not registered on the server object.
+
+0x80010104
+
+RPC_E_FAULT
+
+
+RPC could not call the server or could not return the results of calling the server.
+
+0x80010105
+
+RPC_E_SERVERFAULT
+
+
+The server threw an exception.
+
+0x80010106
+
+RPC_E_CHANGED_MODE
+
+
+Cannot change thread mode after it is set.
+
+0x80010107
+
+RPC_E_INVALIDMETHOD
+
+
+The method called does not exist on the server.
+
+0x80010108
+
+RPC_E_DISCONNECTED
+
+
+The object invoked has disconnected from its clients.
+
+0x80010109
+
+RPC_E_RETRY
+
+
+The object invoked chose not to process the call now. Try again later.
+
+0x8001010A
+
+RPC_E_SERVERCALL_RETRYLATER
+
+
+The message filter indicated that the application is busy.
+
+0x8001010B
+
+RPC_E_SERVERCALL_REJECTED
+
+
+The message filter rejected the call.
+
+0x8001010C
+
+RPC_E_INVALID_CALLDATA
+
+
+A call control interface was called with invalid data.
+
+0x8001010D
+
+RPC_E_CANTCALLOUT_ININPUTSYNCCALL
+
+
+An outgoing call cannot be made because the application is dispatching an input-synchronous call.
+
+0x8001010E
+
+RPC_E_WRONG_THREAD
+
+
+The application called an interface that was marshaled for a different thread.
+
+0x8001010F
+
+RPC_E_THREAD_NOT_INIT
+
+
+CoInitialize has not been called on the current thread.
+
+0x80010110
+
+RPC_E_VERSION_MISMATCH
+
+
+The version of OLE on the client and server machines does not match.
+
+0x80010111
+
+RPC_E_INVALID_HEADER
+
+
+OLE received a packet with an invalid header.
+
+0x80010112
+
+RPC_E_INVALID_EXTENSION
+
+
+OLE received a packet with an invalid extension.
+
+0x80010113
+
+RPC_E_INVALID_IPID
+
+
+The requested object or interface does not exist.
+
+0x80010114
+
+RPC_E_INVALID_OBJECT
+
+
+The requested object does not exist.
+
+0x80010115
+
+RPC_S_CALLPENDING
+
+
+OLE has sent a request and is waiting for a reply.
+
+0x80010116
+
+RPC_S_WAITONTIMER
+
+
+OLE is waiting before retrying a request.
+
+0x80010117
+
+RPC_E_CALL_COMPLETE
+
+
+Call context cannot be accessed after call completed.
+
+0x80010118
+
+RPC_E_UNSECURE_CALL
+
+
+Impersonate on unsecure calls is not supported.
+
+0x80010119
+
+RPC_E_TOO_LATE
+
+
+Security must be initialized before any interfaces are marshaled or unmarshaled. It cannot be changed after initialized.
+
+0x8001011A
+
+RPC_E_NO_GOOD_SECURITY_PACKAGES
+
+
+No security packages are installed on this machine, the user is not logged on, or there are no compatible security packages between the client and server.
+
+0x8001011B
+
+RPC_E_ACCESS_DENIED
+
+
+Access is denied.
+
+0x8001011C
+
+RPC_E_REMOTE_DISABLED
+
+
+Remote calls are not allowed for this process.
+
+0x8001011D
+
+RPC_E_INVALID_OBJREF
+
+
+The marshaled interface data packet (OBJREF) has an invalid or unknown format.
+
+0x8001011E
+
+RPC_E_NO_CONTEXT
+
+
+No context is associated with this call. This happens for some custom marshaled calls and on the client side of the call.
+
+0x8001011F
+
+RPC_E_TIMEOUT
+
+
+This operation returned because the time-out period expired.
+
+0x80010120
+
+RPC_E_NO_SYNC
+
+
+There are no synchronize objects to wait on.
+
+0x80010121
+
+RPC_E_FULLSIC_REQUIRED
+
+
+Full subject issuer chain Secure Sockets Layer (SSL) principal name expected from the server.
+
+0x80010122
+
+RPC_E_INVALID_STD_NAME
+
+
+Principal name is not a valid Microsoft standard (msstd) name.
+
+0x80010123
+
+CO_E_FAILEDTOIMPERSONATE
+
+
+Unable to impersonate DCOM client.
+
+0x80010124
+
+CO_E_FAILEDTOGETSECCTX
+
+
+Unable to obtain server's security context.
+
+0x80010125
+
+CO_E_FAILEDTOOPENTHREADTOKEN
+
+
+Unable to open the access token of the current thread.
+
+0x80010126
+
+CO_E_FAILEDTOGETTOKENINFO
+
+
+Unable to obtain user information from an access token.
+
+0x80010127
+
+CO_E_TRUSTEEDOESNTMATCHCLIENT
+
+
+The client who called IAccessControl::IsAccessPermitted was not the trustee provided to the method.
+
+0x80010128
+
+CO_E_FAILEDTOQUERYCLIENTBLANKET
+
+
+Unable to obtain the client's security blanket.
+
+0x80010129
+
+CO_E_FAILEDTOSETDACL
+
+
+Unable to set a discretionary access control list (ACL) into a security descriptor.
+
+0x8001012A
+
+CO_E_ACCESSCHECKFAILED
+
+
+The system function AccessCheck returned false.
+
+0x8001012B
+
+CO_E_NETACCESSAPIFAILED
+
+
+Either NetAccessDel or NetAccessAdd returned an error code.
+
+0x8001012C
+
+CO_E_WRONGTRUSTEENAMESYNTAX
+
+
+One of the trustee strings provided by the user did not conform to the <Domain>\<Name> syntax and it was not the *" string".
+
+0x8001012D
+
+CO_E_INVALIDSID
+
+
+One of the security identifiers provided by the user was invalid.
+
+0x8001012E
+
+CO_E_CONVERSIONFAILED
+
+
+Unable to convert a wide character trustee string to a multiple-byte trustee string.
+
+0x8001012F
+
+CO_E_NOMATCHINGSIDFOUND
+
+
+Unable to find a security identifier that corresponds to a trustee string provided by the user.
+
+0x80010130
+
+CO_E_LOOKUPACCSIDFAILED
+
+
+The system function LookupAccountSID failed.
+
+0x80010131
+
+CO_E_NOMATCHINGNAMEFOUND
+
+
+Unable to find a trustee name that corresponds to a security identifier provided by the user.
+
+0x80010132
+
+CO_E_LOOKUPACCNAMEFAILED
+
+
+The system function LookupAccountName failed.
+
+0x80010133
+
+CO_E_SETSERLHNDLFAILED
+
+
+Unable to set or reset a serialization handle.
+
+0x80010134
+
+CO_E_FAILEDTOGETWINDIR
+
+
+Unable to obtain the Windows directory.
+
+0x80010135
+
+CO_E_PATHTOOLONG
+
+
+Path too long.
+
+0x80010136
+
+CO_E_FAILEDTOGENUUID
+
+
+Unable to generate a UUID.
+
+0x80010137
+
+CO_E_FAILEDTOCREATEFILE
+
+
+Unable to create file.
+
+0x80010138
+
+CO_E_FAILEDTOCLOSEHANDLE
+
+
+Unable to close a serialization handle or a file handle.
+
+0x80010139
+
+CO_E_EXCEEDSYSACLLIMIT
+
+
+The number of access control entries (ACEs) in an ACL exceeds the system limit.
+
+0x8001013A
+
+CO_E_ACESINWRONGORDER
+
+
+Not all the DENY_ACCESS ACEs are arranged in front of the GRANT_ACCESS ACEs in the stream.
+
+0x8001013B
+
+CO_E_INCOMPATIBLESTREAMVERSION
+
+
+The version of ACL format in the stream is not supported by this implementation of IAccessControl.
+
+0x8001013C
+
+CO_E_FAILEDTOOPENPROCESSTOKEN
+
+
+Unable to open the access token of the server process.
+
+0x8001013D
+
+CO_E_DECODEFAILED
+
+
+Unable to decode the ACL in the stream provided by the user.
+
+0x8001013F
+
+CO_E_ACNOTINITIALIZED
+
+
+The COM IAccessControl object is not initialized.
+
+0x80010140
+
+CO_E_CANCEL_DISABLED
+
+
+Call Cancellation is disabled.
+
+0x8001FFFF
+
+RPC_E_UNEXPECTED
+
+
+An internal error occurred.
+
+0x80020001
+
+DISP_E_UNKNOWNINTERFACE
+
+
+Unknown interface.
+
+0x80020003
+
+DISP_E_MEMBERNOTFOUND
+
+
+Member not found.
+
+0x80020004
+
+DISP_E_PARAMNOTFOUND
+
+
+Parameter not found.
+
+0x80020005
+
+DISP_E_TYPEMISMATCH
+
+
+Type mismatch.
+
+0x80020006
+
+DISP_E_UNKNOWNNAME
+
+
+Unknown name.
+
+0x80020007
+
+DISP_E_NONAMEDARGS
+
+
+No named arguments.
+
+0x80020008
+
+DISP_E_BADVARTYPE
+
+
+Bad variable type.
+
+0x80020009
+
+DISP_E_EXCEPTION
+
+
+Exception occurred.
+
+0x8002000A
+
+DISP_E_OVERFLOW
+
+
+Out of present range.
+
+0x8002000B
+
+DISP_E_BADINDEX
+
+
+Invalid index.
+
+0x8002000C
+
+DISP_E_UNKNOWNLCID
+
+
+Unknown language.
+
+0x8002000D
+
+DISP_E_ARRAYISLOCKED
+
+
+Memory is locked.
+
+0x8002000E
+
+DISP_E_BADPARAMCOUNT
+
+
+Invalid number of parameters.
+
+0x8002000F
+
+DISP_E_PARAMNOTOPTIONAL
+
+
+Parameter not optional.
+
+0x80020010
+
+DISP_E_BADCALLEE
+
+
+Invalid callee.
+
+0x80020011
+
+DISP_E_NOTACOLLECTION
+
+
+Does not support a collection.
+
+0x80020012
+
+DISP_E_DIVBYZERO
+
+
+Division by zero.
+
+0x80020013
+
+DISP_E_BUFFERTOOSMALL
+
+
+Buffer too small.
+
+0x80028016
+
+TYPE_E_BUFFERTOOSMALL
+
+
+Buffer too small.
+
+0x80028017
+
+TYPE_E_FIELDNOTFOUND
+
+
+Field name not defined in the record.
+
+0x80028018
+
+TYPE_E_INVDATAREAD
+
+
+Old format or invalid type library.
+
+0x80028019
+
+TYPE_E_UNSUPFORMAT
+
+
+Old format or invalid type library.
+
+0x8002801C
+
+TYPE_E_REGISTRYACCESS
+
+
+Error accessing the OLE registry.
+
+0x8002801D
+
+TYPE_E_LIBNOTREGISTERED
+
+
+Library not registered.
+
+0x80028027
+
+TYPE_E_UNDEFINEDTYPE
+
+
+Bound to unknown type.
+
+0x80028028
+
+TYPE_E_QUALIFIEDNAMEDISALLOWED
+
+
+Qualified name disallowed.
+
+0x80028029
+
+TYPE_E_INVALIDSTATE
+
+
+Invalid forward reference, or reference to uncompiled type.
+
+0x8002802A
+
+TYPE_E_WRONGTYPEKIND
+
+
+Type mismatch.
+
+0x8002802B
+
+TYPE_E_ELEMENTNOTFOUND
+
+
+Element not found.
+
+0x8002802C
+
+TYPE_E_AMBIGUOUSNAME
+
+
+Ambiguous name.
+
+0x8002802D
+
+TYPE_E_NAMECONFLICT
+
+
+Name already exists in the library.
+
+0x8002802E
+
+TYPE_E_UNKNOWNLCID
+
+
+Unknown language code identifier (LCID).
+
+0x8002802F
+
+TYPE_E_DLLFUNCTIONNOTFOUND
+
+
+Function not defined in specified DLL.
+
+0x800288BD
+
+TYPE_E_BADMODULEKIND
+
+
+Wrong module kind for the operation.
+
+0x800288C5
+
+TYPE_E_SIZETOOBIG
+
+
+Size cannot exceed 64 KB.
+
+0x800288C6
+
+TYPE_E_DUPLICATEID
+
+
+Duplicate ID in inheritance hierarchy.
+
+0x800288CF
+
+TYPE_E_INVALIDID
+
+
+Incorrect inheritance depth in standard OLE hmember.
+
+0x80028CA0
+
+TYPE_E_TYPEMISMATCH
+
+
+Type mismatch.
+
+0x80028CA1
+
+TYPE_E_OUTOFBOUNDS
+
+
+Invalid number of arguments.
+
+0x80028CA2
+
+TYPE_E_IOERROR
+
+
+I/O error.
+
+0x80028CA3
+
+TYPE_E_CANTCREATETMPFILE
+
+
+Error creating unique .tmp file.
+
+0x80029C4A
+
+TYPE_E_CANTLOADLIBRARY
+
+
+Error loading type library or DLL.
+
+0x80029C83
+
+TYPE_E_INCONSISTENTPROPFUNCS
+
+
+Inconsistent property functions.
+
+0x80029C84
+
+TYPE_E_CIRCULARTYPE
+
+
+Circular dependency between types and modules.
+
+0x80030001
+
+STG_E_INVALIDFUNCTION
+
+
+Unable to perform requested operation.
+
+0x80030002
+
+STG_E_FILENOTFOUND
+
+
+%1 could not be found.
+
+0x80030003
+
+STG_E_PATHNOTFOUND
+
+
+The path %1 could not be found.
+
+0x80030004
+
+STG_E_TOOMANYOPENFILES
+
+
+There are insufficient resources to open another file.
+
+0x80030005
+
+STG_E_ACCESSDENIED
+
+
+Access denied.
+
+0x80030006
+
+STG_E_INVALIDHANDLE
+
+
+Attempted an operation on an invalid object.
+
+0x80030008
+
+STG_E_INSUFFICIENTMEMORY
+
+
+There is insufficient memory available to complete operation.
+
+0x80030009
+
+STG_E_INVALIDPOINTER
+
+
+Invalid pointer error.
+
+0x80030012
+
+STG_E_NOMOREFILES
+
+
+There are no more entries to return.
+
+0x80030013
+
+STG_E_DISKISWRITEPROTECTED
+
+
+Disk is write-protected.
+
+0x80030019
+
+STG_E_SEEKERROR
+
+
+An error occurred during a seek operation.
+
+0x8003001D
+
+STG_E_WRITEFAULT
+
+
+A disk error occurred during a write operation.
+
+0x8003001E
+
+STG_E_READFAULT
+
+
+A disk error occurred during a read operation.
+
+0x80030020
+
+STG_E_SHAREVIOLATION
+
+
+A share violation has occurred.
+
+0x80030021
+
+STG_E_LOCKVIOLATION
+
+
+A lock violation has occurred.
+
+0x80030050
+
+STG_E_FILEALREADYEXISTS
+
+
+%1 already exists.
+
+0x80030057
+
+STG_E_INVALIDPARAMETER
+
+
+Invalid parameter error.
+
+0x80030070
+
+STG_E_MEDIUMFULL
+
+
+There is insufficient disk space to complete operation.
+
+0x800300F0
+
+STG_E_PROPSETMISMATCHED
+
+
+Illegal write of non-simple property to simple property set.
+
+0x800300FA
+
+STG_E_ABNORMALAPIEXIT
+
+
+An application programming interface (API) call exited abnormally.
+
+0x800300FB
+
+STG_E_INVALIDHEADER
+
+
+The file %1 is not a valid compound file.
+
+0x800300FC
+
+STG_E_INVALIDNAME
+
+
+The name %1 is not valid.
+
+0x800300FD
+
+STG_E_UNKNOWN
+
+
+An unexpected error occurred.
+
+0x800300FE
+
+STG_E_UNIMPLEMENTEDFUNCTION
+
+
+That function is not implemented.
+
+0x800300FF
+
+STG_E_INVALIDFLAG
+
+
+Invalid flag error.
+
+0x80030100
+
+STG_E_INUSE
+
+
+Attempted to use an object that is busy.
+
+0x80030101
+
+STG_E_NOTCURRENT
+
+
+The storage has been changed since the last commit.
+
+0x80030102
+
+STG_E_REVERTED
+
+
+Attempted to use an object that has ceased to exist.
+
+0x80030103
+
+STG_E_CANTSAVE
+
+
+Cannot save.
+
+0x80030104
+
+STG_E_OLDFORMAT
+
+
+The compound file %1 was produced with an incompatible version of storage.
+
+0x80030105
+
+STG_E_OLDDLL
+
+
+The compound file %1 was produced with a newer version of storage.
+
+0x80030106
+
+STG_E_SHAREREQUIRED
+
+
+Share.exe or equivalent is required for operation.
+
+0x80030107
+
+STG_E_NOTFILEBASEDSTORAGE
+
+
+Illegal operation called on non-file based storage.
+
+0x80030108
+
+STG_E_EXTANTMARSHALLINGS
+
+
+Illegal operation called on object with extant marshalings.
+
+0x80030109
+
+STG_E_DOCFILECORRUPT
+
+
+The docfile has been corrupted.
+
+0x80030110
+
+STG_E_BADBASEADDRESS
+
+
+OLE32.DLL has been loaded at the wrong address.
+
+0x80030111
+
+STG_E_DOCFILETOOLARGE
+
+
+The compound file is too large for the current implementation.
+
+0x80030112
+
+STG_E_NOTSIMPLEFORMAT
+
+
+The compound file was not created with the STGM_SIMPLE flag.
+
+0x80030201
+
+STG_E_INCOMPLETE
+
+
+The file download was aborted abnormally. The file is incomplete.
+
+0x80030202
+
+STG_E_TERMINATED
+
+
+The file download has been terminated.
+
+0x80030305
+
+STG_E_STATUS_COPY_PROTECTION_FAILURE
+
+
+Generic Copy Protection Error.
+
+0x80030306
+
+STG_E_CSS_AUTHENTICATION_FAILURE
+
+
+Copy Protection Error—DVD CSS Authentication failed.
+
+0x80030307
+
+STG_E_CSS_KEY_NOT_PRESENT
+
+
+Copy Protection Error—The given sector does not have a valid CSS key.
+
+0x80030308
+
+STG_E_CSS_KEY_NOT_ESTABLISHED
+
+
+Copy Protection Error—DVD session key not established.
+
+0x80030309
+
+STG_E_CSS_SCRAMBLED_SECTOR
+
+
+Copy Protection Error—The read failed because the sector is encrypted.
+
+0x8003030A
+
+STG_E_CSS_REGION_MISMATCH
+
+
+Copy Protection Error—The current DVD's region does not correspond to the region setting of the drive.
+
+0x8003030B
+
+STG_E_RESETS_EXHAUSTED
+
+
+Copy Protection Error—The drive's region setting might be permanent or the number of user resets has been exhausted.
+
+0x80040000
+
+OLE_E_OLEVERB
+
+
+Invalid OLEVERB structure.
+
+0x80040001
+
+OLE_E_ADVF
+
+
+Invalid advise flags.
+
+0x80040002
+
+OLE_E_ENUM_NOMORE
+
+
+Cannot enumerate any more because the associated data is missing.
+
+0x80040003
+
+OLE_E_ADVISENOTSUPPORTED
+
+
+This implementation does not take advises.
+
+0x80040004
+
+OLE_E_NOCONNECTION
+
+
+There is no connection for this connection ID.
+
+0x80040005
+
+OLE_E_NOTRUNNING
+
+
+Need to run the object to perform this operation.
+
+0x80040006
+
+OLE_E_NOCACHE
+
+
+There is no cache to operate on.
+
+0x80040007
+
+OLE_E_BLANK
+
+
+Uninitialized object.
+
+0x80040008
+
+OLE_E_CLASSDIFF
+
+
+Linked object's source class has changed.
+
+0x80040009
+
+OLE_E_CANT_GETMONIKER
+
+
+Not able to get the moniker of the object.
+
+0x8004000A
+
+OLE_E_CANT_BINDTOSOURCE
+
+
+Not able to bind to the source.
+
+0x8004000B
+
+OLE_E_STATIC
+
+
+Object is static; operation not allowed.
+
+0x8004000C
+
+OLE_E_PROMPTSAVECANCELLED
+
+
+User canceled out of the Save dialog box.
+
+0x8004000D
+
+OLE_E_INVALIDRECT
+
+
+Invalid rectangle.
+
+0x8004000E
+
+OLE_E_WRONGCOMPOBJ
+
+
+compobj.dll is too old for the ole2.dll initialized.
+
+0x8004000F
+
+OLE_E_INVALIDHWND
+
+
+Invalid window handle.
+
+0x80040010
+
+OLE_E_NOT_INPLACEACTIVE
+
+
+Object is not in any of the inplace active states.
+
+0x80040011
+
+OLE_E_CANTCONVERT
+
+
+Not able to convert object.
+
+0x80040012
+
+OLE_E_NOSTORAGE
+
+
+Not able to perform the operation because object is not given storage yet.
+
+0x80040064
+
+DV_E_FORMATETC
+
+
+Invalid FORMATETC structure.
+
+0x80040065
+
+DV_E_DVTARGETDEVICE
+
+
+Invalid DVTARGETDEVICE structure.
+
+0x80040066
+
+DV_E_STGMEDIUM
+
+
+Invalid STDGMEDIUM structure.
+
+0x80040067
+
+DV_E_STATDATA
+
+
+Invalid STATDATA structure.
+
+0x80040068
+
+DV_E_LINDEX
+
+
+Invalid lindex.
+
+0x80040069
+
+DV_E_TYMED
+
+
+Invalid TYMED structure.
+
+0x8004006A
+
+DV_E_CLIPFORMAT
+
+
+Invalid clipboard format.
+
+0x8004006B
+
+DV_E_DVASPECT
+
+
+Invalid aspects.
+
+0x8004006C
+
+DV_E_DVTARGETDEVICE_SIZE
+
+
+The tdSize parameter of the DVTARGETDEVICE structure is invalid.
+
+0x8004006D
+
+DV_E_NOIVIEWOBJECT
+
+
+Object does not support IViewObject interface.
+
+0x80040100
+
+DRAGDROP_E_NOTREGISTERED
+
+
+Trying to revoke a drop target that has not been registered.
+
+0x80040101
+
+DRAGDROP_E_ALREADYREGISTERED
+
+
+This window has already been registered as a drop target.
+
+0x80040102
+
+DRAGDROP_E_INVALIDHWND
+
+
+Invalid window handle.
+
+0x80040110
+
+CLASS_E_NOAGGREGATION
+
+
+Class does not support aggregation (or class object is remote).
+
+0x80040111
+
+CLASS_E_CLASSNOTAVAILABLE
+
+
+ClassFactory cannot supply requested class.
+
+0x80040112
+
+CLASS_E_NOTLICENSED
+
+
+Class is not licensed for use.
+
+0x80040140
+
+VIEW_E_DRAW
+
+
+Error drawing view.
+
+0x80040150
+
+REGDB_E_READREGDB
+
+
+Could not read key from registry.
+
+0x80040151
+
+REGDB_E_WRITEREGDB
+
+
+Could not write key to registry.
+
+0x80040152
+
+REGDB_E_KEYMISSING
+
+
+Could not find the key in the registry.
+
+0x80040153
+
+REGDB_E_INVALIDVALUE
+
+
+Invalid value for registry.
+
+0x80040154
+
+REGDB_E_CLASSNOTREG
+
+
+Class not registered.
+
+0x80040155
+
+REGDB_E_IIDNOTREG
+
+
+Interface not registered.
+
+0x80040156
+
+REGDB_E_BADTHREADINGMODEL
+
+
+Threading model entry is not valid.
+
+0x80040160
+
+CAT_E_CATIDNOEXIST
+
+
+CATID does not exist.
+
+0x80040161
+
+CAT_E_NODESCRIPTION
+
+
+Description not found.
+
+0x80040164
+
+CS_E_PACKAGE_NOTFOUND
+
+
+No package in the software installation data in Active Directory meets this criteria.
+
+0x80040165
+
+CS_E_NOT_DELETABLE
+
+
+Deleting this will break the referential integrity of the software installation data in Active Directory.
+
+0x80040166
+
+CS_E_CLASS_NOTFOUND
+
+
+The CLSID was not found in the software installation data in Active Directory.
+
+0x80040167
+
+CS_E_INVALID_VERSION
+
+
+The software installation data in Active Directory is corrupt.
+
+0x80040168
+
+CS_E_NO_CLASSSTORE
+
+
+There is no software installation data in Active Directory.
+
+0x80040169
+
+CS_E_OBJECT_NOTFOUND
+
+
+There is no software installation data object in Active Directory.
+
+0x8004016A
+
+CS_E_OBJECT_ALREADY_EXISTS
+
+
+The software installation data object in Active Directory already exists.
+
+0x8004016B
+
+CS_E_INVALID_PATH
+
+
+The path to the software installation data in Active Directory is not correct.
+
+0x8004016C
+
+CS_E_NETWORK_ERROR
+
+
+A network error interrupted the operation.
+
+0x8004016D
+
+CS_E_ADMIN_LIMIT_EXCEEDED
+
+
+The size of this object exceeds the maximum size set by the administrator.
+
+0x8004016E
+
+CS_E_SCHEMA_MISMATCH
+
+
+The schema for the software installation data in Active Directory does not match the required schema.
+
+0x8004016F
+
+CS_E_INTERNAL_ERROR
+
+
+An error occurred in the software installation data in Active Directory.
+
+0x80040170
+
+CACHE_E_NOCACHE_UPDATED
+
+
+Cache not updated.
+
+0x80040180
+
+OLEOBJ_E_NOVERBS
+
+
+No verbs for OLE object.
+
+0x80040181
+
+OLEOBJ_E_INVALIDVERB
+
+
+Invalid verb for OLE object.
+
+0x800401A0
+
+INPLACE_E_NOTUNDOABLE
+
+
+Undo is not available.
+
+0x800401A1
+
+INPLACE_E_NOTOOLSPACE
+
+
+Space for tools is not available.
+
+0x800401C0
+
+CONVERT10_E_OLESTREAM_GET
+
+
+OLESTREAM Get method failed.
+
+0x800401C1
+
+CONVERT10_E_OLESTREAM_PUT
+
+
+OLESTREAM Put method failed.
+
+0x800401C2
+
+CONVERT10_E_OLESTREAM_FMT
+
+
+Contents of the OLESTREAM not in correct format.
+
+0x800401C3
+
+CONVERT10_E_OLESTREAM_BITMAP_TO_DIB
+
+
+There was an error in a Windows GDI call while converting the bitmap to a device-independent bitmap (DIB).
+
+0x800401C4
+
+CONVERT10_E_STG_FMT
+
+
+Contents of the IStorage not in correct format.
+
+0x800401C5
+
+CONVERT10_E_STG_NO_STD_STREAM
+
+
+Contents of IStorage is missing one of the standard streams.
+
+0x800401C6
+
+CONVERT10_E_STG_DIB_TO_BITMAP
+
+
+There was an error in a Windows Graphics Device Interface (GDI) call while converting the DIB to a bitmap.
+
+0x800401D0
+
+CLIPBRD_E_CANT_OPEN
+
+
+OpenClipboard failed.
+
+0x800401D1
+
+CLIPBRD_E_CANT_EMPTY
+
+
+EmptyClipboard failed.
+
+0x800401D2
+
+CLIPBRD_E_CANT_SET
+
+
+SetClipboard failed.
+
+0x800401D3
+
+CLIPBRD_E_BAD_DATA
+
+
+Data on clipboard is invalid.
+
+0x800401D4
+
+CLIPBRD_E_CANT_CLOSE
+
+
+CloseClipboard failed.
+
+0x800401E0
+
+MK_E_CONNECTMANUALLY
+
+
+Moniker needs to be connected manually.
+
+0x800401E1
+
+MK_E_EXCEEDEDDEADLINE
+
+
+Operation exceeded deadline.
+
+0x800401E2
+
+MK_E_NEEDGENERIC
+
+
+Moniker needs to be generic.
+
+0x800401E3
+
+MK_E_UNAVAILABLE
+
+
+Operation unavailable.
+
+0x800401E4
+
+MK_E_SYNTAX
+
+
+Invalid syntax.
+
+0x800401E5
+
+MK_E_NOOBJECT
+
+
+No object for moniker.
+
+0x800401E6
+
+MK_E_INVALIDEXTENSION
+
+
+Bad extension for file.
+
+0x800401E7
+
+MK_E_INTERMEDIATEINTERFACENOTSUPPORTED
+
+
+Intermediate operation failed.
+
+0x800401E8
+
+MK_E_NOTBINDABLE
+
+
+Moniker is not bindable.
+
+0x800401E9
+
+MK_E_NOTBOUND
+
+
+Moniker is not bound.
+
+0x800401EA
+
+MK_E_CANTOPENFILE
+
+
+Moniker cannot open file.
+
+0x800401EB
+
+MK_E_MUSTBOTHERUSER
+
+
+User input required for operation to succeed.
+
+0x800401EC
+
+MK_E_NOINVERSE
+
+
+Moniker class has no inverse.
+
+0x800401ED
+
+MK_E_NOSTORAGE
+
+
+Moniker does not refer to storage.
+
+0x800401EE
+
+MK_E_NOPREFIX
+
+
+No common prefix.
+
+0x800401EF
+
+MK_E_ENUMERATION_FAILED
+
+
+Moniker could not be enumerated.
+
+0x800401F0
+
+CO_E_NOTINITIALIZED
+
+
+CoInitialize has not been called.
+
+0x800401F1
+
+CO_E_ALREADYINITIALIZED
+
+
+CoInitialize has already been called.
+
+0x800401F2
+
+CO_E_CANTDETERMINECLASS
+
+
+Class of object cannot be determined.
+
+0x800401F3
+
+CO_E_CLASSSTRING
+
+
+Invalid class string.
+
+0x800401F4
+
+CO_E_IIDSTRING
+
+
+Invalid interface string.
+
+0x800401F5
+
+CO_E_APPNOTFOUND
+
+
+Application not found.
+
+0x800401F6
+
+CO_E_APPSINGLEUSE
+
+
+Application cannot be run more than once.
+
+0x800401F7
+
+CO_E_ERRORINAPP
+
+
+Some error in application.
+
+0x800401F8
+
+CO_E_DLLNOTFOUND
+
+
+DLL for class not found.
+
+0x800401F9
+
+CO_E_ERRORINDLL
+
+
+Error in the DLL.
+
+0x800401FA
+
+CO_E_WRONGOSFORAPP
+
+
+Wrong operating system or operating system version for application.
+
+0x800401FB
+
+CO_E_OBJNOTREG
+
+
+Object is not registered.
+
+0x800401FC
+
+CO_E_OBJISREG
+
+
+Object is already registered.
+
+0x800401FD
+
+CO_E_OBJNOTCONNECTED
+
+
+Object is not connected to server.
+
+0x800401FE
+
+CO_E_APPDIDNTREG
+
+
+Application was launched, but it did not register a class factory.
+
+0x800401FF
+
+CO_E_RELEASED
+
+
+Object has been released.
+
+0x80040201
+
+EVENT_E_ALL_SUBSCRIBERS_FAILED
+
+
+An event was unable to invoke any of the subscribers.
+
+0x80040203
+
+EVENT_E_QUERYSYNTAX
+
+
+A syntax error occurred trying to evaluate a query string.
+
+0x80040204
+
+EVENT_E_QUERYFIELD
+
+
+An invalid field name was used in a query string.
+
+0x80040205
+
+EVENT_E_INTERNALEXCEPTION
+
+
+An unexpected exception was raised.
+
+0x80040206
+
+EVENT_E_INTERNALERROR
+
+
+An unexpected internal error was detected.
+
+0x80040207
+
+EVENT_E_INVALID_PER_USER_SID
+
+
+The owner security identifier (SID) on a per-user subscription does not exist.
+
+0x80040208
+
+EVENT_E_USER_EXCEPTION
+
+
+A user-supplied component or subscriber raised an exception.
+
+0x80040209
+
+EVENT_E_TOO_MANY_METHODS
+
+
+An interface has too many methods to fire events from.
+
+0x8004020A
+
+EVENT_E_MISSING_EVENTCLASS
+
+
+A subscription cannot be stored unless its event class already exists.
+
+0x8004020B
+
+EVENT_E_NOT_ALL_REMOVED
+
+
+Not all the objects requested could be removed.
+
+0x8004020C
+
+EVENT_E_COMPLUS_NOT_INSTALLED
+
+
+COM+ is required for this operation, but it is not installed.
+
+0x8004020D
+
+EVENT_E_CANT_MODIFY_OR_DELETE_UNCONFIGURED_OBJECT
+
+
+Cannot modify or delete an object that was not added using the COM+ Administrative SDK.
+
+0x8004020E
+
+EVENT_E_CANT_MODIFY_OR_DELETE_CONFIGURED_OBJECT
+
+
+Cannot modify or delete an object that was added using the COM+ Administrative SDK.
+
+0x8004020F
+
+EVENT_E_INVALID_EVENT_CLASS_PARTITION
+
+
+The event class for this subscription is in an invalid partition.
+
+0x80040210
+
+EVENT_E_PER_USER_SID_NOT_LOGGED_ON
+
+
+The owner of the PerUser subscription is not logged on to the system specified.
+
+0x80041309
+
+SCHED_E_TRIGGER_NOT_FOUND
+
+
+Trigger not found.
+
+0x8004130A
+
+SCHED_E_TASK_NOT_READY
+
+
+One or more of the properties that are needed to run this task have not been set.
+
+0x8004130B
+
+SCHED_E_TASK_NOT_RUNNING
+
+
+There is no running instance of the task.
+
+0x8004130C
+
+SCHED_E_SERVICE_NOT_INSTALLED
+
+
+The Task Scheduler service is not installed on this computer.
+
+0x8004130D
+
+SCHED_E_CANNOT_OPEN_TASK
+
+
+The task object could not be opened.
+
+0x8004130E
+
+SCHED_E_INVALID_TASK
+
+
+The object is either an invalid task object or is not a task object.
+
+0x8004130F
+
+SCHED_E_ACCOUNT_INFORMATION_NOT_SET
+
+
+No account information could be found in the Task Scheduler security database for the task indicated.
+
+0x80041310
+
+SCHED_E_ACCOUNT_NAME_NOT_FOUND
+
+
+Unable to establish existence of the account specified.
+
+0x80041311
+
+SCHED_E_ACCOUNT_DBASE_CORRUPT
+
+
+Corruption was detected in the Task Scheduler security database; the database has been reset.
+
+0x80041312
+
+SCHED_E_NO_SECURITY_SERVICES
+
+
+Task Scheduler security services are available only on Windows NT operating system.
+
+0x80041313
+
+SCHED_E_UNKNOWN_OBJECT_VERSION
+
+
+The task object version is either unsupported or invalid.
+
+0x80041314
+
+SCHED_E_UNSUPPORTED_ACCOUNT_OPTION
+
+
+The task has been configured with an unsupported combination of account settings and run-time options.
+
+0x80041315
+
+SCHED_E_SERVICE_NOT_RUNNING
+
+
+The Task Scheduler service is not running.
+
+0x80041316
+
+SCHED_E_UNEXPECTEDNODE
+
+
+The task XML contains an unexpected node.
+
+0x80041317
+
+SCHED_E_NAMESPACE
+
+
+The task XML contains an element or attribute from an unexpected namespace.
+
+0x80041318
+
+SCHED_E_INVALIDVALUE
+
+
+The task XML contains a value that is incorrectly formatted or out of range.
+
+0x80041319
+
+SCHED_E_MISSINGNODE
+
+
+The task XML is missing a required element or attribute.
+
+0x8004131A
+
+SCHED_E_MALFORMEDXML
+
+
+The task XML is malformed.
+
+0x8004131D
+
+SCHED_E_TOO_MANY_NODES
+
+
+The task XML contains too many nodes of the same type.
+
+0x8004131E
+
+SCHED_E_PAST_END_BOUNDARY
+
+
+The task cannot be started after the trigger's end boundary.
+
+0x8004131F
+
+SCHED_E_ALREADY_RUNNING
+
+
+An instance of this task is already running.
+
+0x80041320
+
+SCHED_E_USER_NOT_LOGGED_ON
+
+
+The task will not run because the user is not logged on.
+
+0x80041321
+
+SCHED_E_INVALID_TASK_HASH
+
+
+The task image is corrupt or has been tampered with.
+
+0x80041322
+
+SCHED_E_SERVICE_NOT_AVAILABLE
+
+
+The Task Scheduler service is not available.
+
+0x80041323
+
+SCHED_E_SERVICE_TOO_BUSY
+
+
+The Task Scheduler service is too busy to handle your request. Try again later.
+
+0x80041324
+
+SCHED_E_TASK_ATTEMPTED
+
+
+The Task Scheduler service attempted to run the task, but the task did not run due to one of the constraints in the task definition.
+
+0x8004D000
+
+XACT_E_ALREADYOTHERSINGLEPHASE
+
+
+Another single phase resource manager has already been enlisted in this transaction.
+
+0x8004D001
+
+XACT_E_CANTRETAIN
+
+
+A retaining commit or abort is not supported.
+
+0x8004D002
+
+XACT_E_COMMITFAILED
+
+
+The transaction failed to commit for an unknown reason. The transaction was aborted.
+
+0x8004D003
+
+XACT_E_COMMITPREVENTED
+
+
+Cannot call commit on this transaction object because the calling application did not initiate the transaction.
+
+0x8004D004
+
+XACT_E_HEURISTICABORT
+
+
+Instead of committing, the resource heuristically aborted.
+
+0x8004D005
+
+XACT_E_HEURISTICCOMMIT
+
+
+Instead of aborting, the resource heuristically committed.
+
+0x8004D006
+
+XACT_E_HEURISTICDAMAGE
+
+
+Some of the states of the resource were committed while others were aborted, likely because of heuristic decisions.
+
+0x8004D007
+
+XACT_E_HEURISTICDANGER
+
+
+Some of the states of the resource might have been committed while others were aborted, likely because of heuristic decisions.
+
+0x8004D008
+
+XACT_E_ISOLATIONLEVEL
+
+
+The requested isolation level is not valid or supported.
+
+0x8004D009
+
+XACT_E_NOASYNC
+
+
+The transaction manager does not support an asynchronous operation for this method.
+
+0x8004D00A
+
+XACT_E_NOENLIST
+
+
+Unable to enlist in the transaction.
+
+0x8004D00B
+
+XACT_E_NOISORETAIN
+
+
+The requested semantics of retention of isolation across retaining commit and abort boundaries cannot be supported by this transaction implementation, or isoFlags was not equal to 0.
+
+0x8004D00C
+
+XACT_E_NORESOURCE
+
+
+There is no resource presently associated with this enlistment.
+
+0x8004D00D
+
+XACT_E_NOTCURRENT
+
+
+The transaction failed to commit due to the failure of optimistic concurrency control in at least one of the resource managers.
+
+0x8004D00E
+
+XACT_E_NOTRANSACTION
+
+
+The transaction has already been implicitly or explicitly committed or aborted.
+
+0x8004D00F
+
+XACT_E_NOTSUPPORTED
+
+
+An invalid combination of flags was specified.
+
+0x8004D010
+
+XACT_E_UNKNOWNRMGRID
+
+
+The resource manager ID is not associated with this transaction or the transaction manager.
+
+0x8004D011
+
+XACT_E_WRONGSTATE
+
+
+This method was called in the wrong state.
+
+0x8004D012
+
+XACT_E_WRONGUOW
+
+
+The indicated unit of work does not match the unit of work expected by the resource manager.
+
+0x8004D013
+
+XACT_E_XTIONEXISTS
+
+
+An enlistment in a transaction already exists.
+
+0x8004D014
+
+XACT_E_NOIMPORTOBJECT
+
+
+An import object for the transaction could not be found.
+
+0x8004D015
+
+XACT_E_INVALIDCOOKIE
+
+
+The transaction cookie is invalid.
+
+0x8004D016
+
+XACT_E_INDOUBT
+
+
+The transaction status is in doubt. A communication failure occurred, or a transaction manager or resource manager has failed.
+
+0x8004D017
+
+XACT_E_NOTIMEOUT
+
+
+A time-out was specified, but time-outs are not supported.
+
+0x8004D018
+
+XACT_E_ALREADYINPROGRESS
+
+
+The requested operation is already in progress for the transaction.
+
+0x8004D019
+
+XACT_E_ABORTED
+
+
+The transaction has already been aborted.
+
+0x8004D01A
+
+XACT_E_LOGFULL
+
+
+The Transaction Manager returned a log full error.
+
+0x8004D01B
+
+XACT_E_TMNOTAVAILABLE
+
+
+The transaction manager is not available.
+
+0x8004D01C
+
+XACT_E_CONNECTION_DOWN
+
+
+A connection with the transaction manager was lost.
+
+0x8004D01D
+
+XACT_E_CONNECTION_DENIED
+
+
+A request to establish a connection with the transaction manager was denied.
+
+0x8004D01E
+
+XACT_E_REENLISTTIMEOUT
+
+
+Resource manager reenlistment to determine transaction status timed out.
+
+0x8004D01F
+
+XACT_E_TIP_CONNECT_FAILED
+
+
+The transaction manager failed to establish a connection with another Transaction Internet Protocol (TIP) transaction manager.
+
+0x8004D020
+
+XACT_E_TIP_PROTOCOL_ERROR
+
+
+The transaction manager encountered a protocol error with another TIP transaction manager.
+
+0x8004D021
+
+XACT_E_TIP_PULL_FAILED
+
+
+The transaction manager could not propagate a transaction from another TIP transaction manager.
+
+0x8004D022
+
+XACT_E_DEST_TMNOTAVAILABLE
+
+
+The transaction manager on the destination machine is not available.
+
+0x8004D023
+
+XACT_E_TIP_DISABLED
+
+
+The transaction manager has disabled its support for TIP.
+
+0x8004D024
+
+XACT_E_NETWORK_TX_DISABLED
+
+
+The transaction manager has disabled its support for remote or network transactions.
+
+0x8004D025
+
+XACT_E_PARTNER_NETWORK_TX_DISABLED
+
+
+The partner transaction manager has disabled its support for remote or network transactions.
+
+0x8004D026
+
+XACT_E_XA_TX_DISABLED
+
+
+The transaction manager has disabled its support for XA transactions.
+
+0x8004D027
+
+XACT_E_UNABLE_TO_READ_DTC_CONFIG
+
+
+Microsoft Distributed Transaction Coordinator (MSDTC) was unable to read its configuration information.
+
+0x8004D028
+
+XACT_E_UNABLE_TO_LOAD_DTC_PROXY
+
+
+MSDTC was unable to load the DTC proxy DLL.
+
+0x8004D029
+
+XACT_E_ABORTING
+
+
+The local transaction has aborted.
+
+0x8004D080
+
+XACT_E_CLERKNOTFOUND
+
+
+The specified CRM clerk was not found. It might have completed before it could be held.
+
+0x8004D081
+
+XACT_E_CLERKEXISTS
+
+
+The specified CRM clerk does not exist.
+
+0x8004D082
+
+XACT_E_RECOVERYINPROGRESS
+
+
+Recovery of the CRM log file is still in progress.
+
+0x8004D083
+
+XACT_E_TRANSACTIONCLOSED
+
+
+The transaction has completed, and the log records have been discarded from the log file. They are no longer available.
+
+0x8004D084
+
+XACT_E_INVALIDLSN
+
+
+lsnToRead is outside of the current limits of the log
+
+0x8004D085
+
+XACT_E_REPLAYREQUEST
+
+
+The COM+ Compensating Resource Manager has records it wishes to replay.
+
+0x8004D100
+
+XACT_E_CONNECTION_REQUEST_DENIED
+
+
+The request to connect to the specified transaction coordinator was denied.
+
+0x8004D101
+
+XACT_E_TOOMANY_ENLISTMENTS
+
+
+The maximum number of enlistments for the specified transaction has been reached.
+
+0x8004D102
+
+XACT_E_DUPLICATE_GUID
+
+
+A resource manager with the same identifier is already registered with the specified transaction coordinator.
+
+0x8004D103
+
+XACT_E_NOTSINGLEPHASE
+
+
+The prepare request given was not eligible for single-phase optimizations.
+
+0x8004D104
+
+XACT_E_RECOVERYALREADYDONE
+
+
+RecoveryComplete has already been called for the given resource manager.
+
+0x8004D105
+
+XACT_E_PROTOCOL
+
+
+The interface call made was incorrect for the current state of the protocol.
+
+0x8004D106
+
+XACT_E_RM_FAILURE
+
+
+The xa_open call failed for the XA resource.
+
+0x8004D107
+
+XACT_E_RECOVERY_FAILED
+
+
+The xa_recover call failed for the XA resource.
+
+0x8004D108
+
+XACT_E_LU_NOT_FOUND
+
+
+The logical unit of work specified cannot be found.
+
+0x8004D109
+
+XACT_E_DUPLICATE_LU
+
+
+The specified logical unit of work already exists.
+
+0x8004D10A
+
+XACT_E_LU_NOT_CONNECTED
+
+
+Subordinate creation failed. The specified logical unit of work was not connected.
+
+0x8004D10B
+
+XACT_E_DUPLICATE_TRANSID
+
+
+A transaction with the given identifier already exists.
+
+0x8004D10C
+
+XACT_E_LU_BUSY
+
+
+The resource is in use.
+
+0x8004D10D
+
+XACT_E_LU_NO_RECOVERY_PROCESS
+
+
+The LU Recovery process is down.
+
+0x8004D10E
+
+XACT_E_LU_DOWN
+
+
+The remote session was lost.
+
+0x8004D10F
+
+XACT_E_LU_RECOVERING
+
+
+The resource is currently recovering.
+
+0x8004D110
+
+XACT_E_LU_RECOVERY_MISMATCH
+
+
+There was a mismatch in driving recovery.
+
+0x8004D111
+
+XACT_E_RM_UNAVAILABLE
+
+
+An error occurred with the XA resource.
+
+0x8004E002
+
+CONTEXT_E_ABORTED
+
+
+The root transaction wanted to commit, but the transaction aborted.
+
+0x8004E003
+
+CONTEXT_E_ABORTING
+
+
+The COM+ component on which the method call was made has a transaction that has already aborted or is in the process of aborting.
+
+0x8004E004
+
+CONTEXT_E_NOCONTEXT
+
+
+There is no Microsoft Transaction Server (MTS) object context.
+
+0x8004E005
+
+CONTEXT_E_WOULD_DEADLOCK
+
+
+The component is configured to use synchronization, and this method call would cause a deadlock to occur.
+
+0x8004E006
+
+CONTEXT_E_SYNCH_TIMEOUT
+
+
+The component is configured to use synchronization, and a thread has timed out waiting to enter the context.
+
+0x8004E007
+
+CONTEXT_E_OLDREF
+
+
+You made a method call on a COM+ component that has a transaction that has already committed or aborted.
+
+0x8004E00C
+
+CONTEXT_E_ROLENOTFOUND
+
+
+The specified role was not configured for the application.
+
+0x8004E00F
+
+CONTEXT_E_TMNOTAVAILABLE
+
+
+COM+ was unable to talk to the MSDTC.
+
+0x8004E021
+
+CO_E_ACTIVATIONFAILED
+
+
+An unexpected error occurred during COM+ activation.
+
+0x8004E022
+
+CO_E_ACTIVATIONFAILED_EVENTLOGGED
+
+
+COM+ activation failed. Check the event log for more information.
+
+0x8004E023
+
+CO_E_ACTIVATIONFAILED_CATALOGERROR
+
+
+COM+ activation failed due to a catalog or configuration error.
+
+0x8004E024
+
+CO_E_ACTIVATIONFAILED_TIMEOUT
+
+
+COM+ activation failed because the activation could not be completed in the specified amount of time.
+
+0x8004E025
+
+CO_E_INITIALIZATIONFAILED
+
+
+COM+ activation failed because an initialization function failed. Check the event log for more information.
+
+0x8004E026
+
+CONTEXT_E_NOJIT
+
+
+The requested operation requires that just-in-time (JIT) be in the current context, and it is not.
+
+0x8004E027
+
+CONTEXT_E_NOTRANSACTION
+
+
+The requested operation requires that the current context have a transaction, and it does not.
+
+0x8004E028
+
+CO_E_THREADINGMODEL_CHANGED
+
+
+The components threading model has changed after install into a COM+ application. Re-install component.
+
+0x8004E029
+
+CO_E_NOIISINTRINSICS
+
+
+Internet Information Services (IIS) intrinsics not available. Start your work with IIS.
+
+0x8004E02A
+
+CO_E_NOCOOKIES
+
+
+An attempt to write a cookie failed.
+
+0x8004E02B
+
+CO_E_DBERROR
+
+
+An attempt to use a database generated a database-specific error.
+
+0x8004E02C
+
+CO_E_NOTPOOLED
+
+
+The COM+ component you created must use object pooling to work.
+
+0x8004E02D
+
+CO_E_NOTCONSTRUCTED
+
+
+The COM+ component you created must use object construction to work correctly.
+
+0x8004E02E
+
+CO_E_NOSYNCHRONIZATION
+
+
+The COM+ component requires synchronization, and it is not configured for it.
+
+0x8004E02F
+
+CO_E_ISOLEVELMISMATCH
+
+
+The TxIsolation Level property for the COM+ component being created is stronger than the TxIsolationLevel for the root.
+
+0x8004E030
+
+CO_E_CALL_OUT_OF_TX_SCOPE_NOT_ALLOWED
+
+
+The component attempted to make a cross-context call between invocations of EnterTransactionScope and ExitTransactionScope. This is not allowed. Cross-context calls cannot be made while inside a transaction scope.
+
+0x8004E031
+
+CO_E_EXIT_TRANSACTION_SCOPE_NOT_CALLED
+
+
+The component made a call to EnterTransactionScope, but did not make a corresponding call to ExitTransactionScope before returning.
+
+0x80070005
+
+E_ACCESSDENIED
+
+
+General access denied error.
+
+0x8007000E
+
+E_OUTOFMEMORY
+
+
+The server does not have enough memory for the new channel.
+
+0x80070032
+
+ERROR_NOT_SUPPORTED
+
+
+The server cannot support a client request for a dynamic virtual channel.
+
+0x80070057
+
+E_INVALIDARG
+
+
+One or more arguments are invalid.
+
+0x80070070
+
+ERROR_DISK_FULL
+
+
+There is not enough space on the disk.
+
+0x80080001
+
+CO_E_CLASS_CREATE_FAILED
+
+
+Attempt to create a class object failed.
+
+0x80080002
+
+CO_E_SCM_ERROR
+
+
+OLE service could not bind object.
+
+0x80080003
+
+CO_E_SCM_RPC_FAILURE
+
+
+RPC communication failed with OLE service.
+
+0x80080004
+
+CO_E_BAD_PATH
+
+
+Bad path to object.
+
+0x80080005
+
+CO_E_SERVER_EXEC_FAILURE
+
+
+Server execution failed.
+
+0x80080006
+
+CO_E_OBJSRV_RPC_FAILURE
+
+
+OLE service could not communicate with the object server.
+
+0x80080007
+
+MK_E_NO_NORMALIZED
+
+
+Moniker path could not be normalized.
+
+0x80080008
+
+CO_E_SERVER_STOPPING
+
+
+Object server is stopping when OLE service contacts it.
+
+0x80080009
+
+MEM_E_INVALID_ROOT
+
+
+An invalid root block pointer was specified.
+
+0x80080010
+
+MEM_E_INVALID_LINK
+
+
+An allocation chain contained an invalid link pointer.
+
+0x80080011
+
+MEM_E_INVALID_SIZE
+
+
+The requested allocation size was too large.
+
+0x80080015
+
+CO_E_MISSING_DISPLAYNAME
+
+
+The activation requires a display name to be present under the class identifier (CLSID) key.
+
+0x80080016
+
+CO_E_RUNAS_VALUE_MUST_BE_AAA
+
+
+The activation requires that the RunAs value for the application is Activate As Activator.
+
+0x80080017
+
+CO_E_ELEVATION_DISABLED
+
+
+The class is not configured to support elevated activation.
+
+0x80090001
+
+NTE_BAD_UID
+
+
+Bad UID.
+
+0x80090002
+
+NTE_BAD_HASH
+
+
+Bad hash.
+
+0x80090003
+
+NTE_BAD_KEY
+
+
+Bad key.
+
+0x80090004
+
+NTE_BAD_LEN
+
+
+Bad length.
+
+0x80090005
+
+NTE_BAD_DATA
+
+
+Bad data.
+
+0x80090006
+
+NTE_BAD_SIGNATURE
+
+
+Invalid signature.
+
+0x80090007
+
+NTE_BAD_VER
+
+
+Bad version of provider.
+
+0x80090008
+
+NTE_BAD_ALGID
+
+
+Invalid algorithm specified.
+
+0x80090009
+
+NTE_BAD_FLAGS
+
+
+Invalid flags specified.
+
+0x8009000A
+
+NTE_BAD_TYPE
+
+
+Invalid type specified.
+
+0x8009000B
+
+NTE_BAD_KEY_STATE
+
+
+Key not valid for use in specified state.
+
+0x8009000C
+
+NTE_BAD_HASH_STATE
+
+
+Hash not valid for use in specified state.
+
+0x8009000D
+
+NTE_NO_KEY
+
+
+Key does not exist.
+
+0x8009000E
+
+NTE_NO_MEMORY
+
+
+Insufficient memory available for the operation.
+
+0x8009000F
+
+NTE_EXISTS
+
+
+Object already exists.
+
+0x80090010
+
+NTE_PERM
+
+
+Access denied.
+
+0x80090011
+
+NTE_NOT_FOUND
+
+
+Object was not found.
+
+0x80090012
+
+NTE_DOUBLE_ENCRYPT
+
+
+Data already encrypted.
+
+0x80090013
+
+NTE_BAD_PROVIDER
+
+
+Invalid provider specified.
+
+0x80090014
+
+NTE_BAD_PROV_TYPE
+
+
+Invalid provider type specified.
+
+0x80090015
+
+NTE_BAD_PUBLIC_KEY
+
+
+Provider's public key is invalid.
+
+0x80090016
+
+NTE_BAD_KEYSET
+
+
+Key set does not exist.
+
+0x80090017
+
+NTE_PROV_TYPE_NOT_DEF
+
+
+Provider type not defined.
+
+0x80090018
+
+NTE_PROV_TYPE_ENTRY_BAD
+
+
+The provider type, as registered, is invalid.
+
+0x80090019
+
+NTE_KEYSET_NOT_DEF
+
+
+The key set is not defined.
+
+0x8009001A
+
+NTE_KEYSET_ENTRY_BAD
+
+
+The key set, as registered, is invalid.
+
+0x8009001B
+
+NTE_PROV_TYPE_NO_MATCH
+
+
+Provider type does not match registered value.
+
+0x8009001C
+
+NTE_SIGNATURE_FILE_BAD
+
+
+The digital signature file is corrupt.
+
+0x8009001D
+
+NTE_PROVIDER_DLL_FAIL
+
+
+Provider DLL failed to initialize correctly.
+
+0x8009001E
+
+NTE_PROV_DLL_NOT_FOUND
+
+
+Provider DLL could not be found.
+
+0x8009001F
+
+NTE_BAD_KEYSET_PARAM
+
+
+The keyset parameter is invalid.
+
+0x80090020
+
+NTE_FAIL
+
+
+An internal error occurred.
+
+0x80090021
+
+NTE_SYS_ERR
+
+
+A base error occurred.
+
+0x80090022
+
+NTE_SILENT_CONTEXT
+
+
+Provider could not perform the action because the context was acquired as silent.
+
+0x80090023
+
+NTE_TOKEN_KEYSET_STORAGE_FULL
+
+
+The security token does not have storage space available for an additional container.
+
+0x80090024
+
+NTE_TEMPORARY_PROFILE
+
+
+The profile for the user is a temporary profile.
+
+0x80090025
+
+NTE_FIXEDPARAMETER
+
+
+The key parameters could not be set because the configuration service provider (CSP) uses fixed parameters.
+
+0x80090026
+
+NTE_INVALID_HANDLE
+
+
+The supplied handle is invalid.
+
+0x80090027
+
+NTE_INVALID_PARAMETER
+
+
+The parameter is incorrect.
+
+0x80090028
+
+NTE_BUFFER_TOO_SMALL
+
+
+The buffer supplied to a function was too small.
+
+0x80090029
+
+NTE_NOT_SUPPORTED
+
+
+The requested operation is not supported.
+
+0x8009002A
+
+NTE_NO_MORE_ITEMS
+
+
+No more data is available.
+
+0x8009002B
+
+NTE_BUFFERS_OVERLAP
+
+
+The supplied buffers overlap incorrectly.
+
+0x8009002C
+
+NTE_DECRYPTION_FAILURE
+
+
+The specified data could not be decrypted.
+
+0x8009002D
+
+NTE_INTERNAL_ERROR
+
+
+An internal consistency check failed.
+
+0x8009002E
+
+NTE_UI_REQUIRED
+
+
+This operation requires input from the user.
+
+0x8009002F
+
+NTE_HMAC_NOT_SUPPORTED
+
+
+The cryptographic provider does not support Hash Message Authentication Code (HMAC).
+
+0x80090300
+
+SEC_E_INSUFFICIENT_MEMORY
+
+
+Not enough memory is available to complete this request.
+
+0x80090301
+
+SEC_E_INVALID_HANDLE
+
+
+The handle specified is invalid.
+
+0x80090302
+
+SEC_E_UNSUPPORTED_FUNCTION
+
+
+The function requested is not supported.
+
+0x80090303
+
+SEC_E_TARGET_UNKNOWN
+
+
+The specified target is unknown or unreachable.
+
+0x80090304
+
+SEC_E_INTERNAL_ERROR
+
+
+The Local Security Authority (LSA) cannot be contacted.
+
+0x80090305
+
+SEC_E_SECPKG_NOT_FOUND
+
+
+The requested security package does not exist.
+
+0x80090306
+
+SEC_E_NOT_OWNER
+
+
+The caller is not the owner of the desired credentials.
+
+0x80090307
+
+SEC_E_CANNOT_INSTALL
+
+
+The security package failed to initialize and cannot be installed.
+
+0x80090308
+
+SEC_E_INVALID_TOKEN
+
+
+The token supplied to the function is invalid.
+
+0x80090309
+
+SEC_E_CANNOT_PACK
+
+
+The security package is not able to marshal the logon buffer, so the logon attempt has failed.
+
+0x8009030A
+
+SEC_E_QOP_NOT_SUPPORTED
+
+
+The per-message quality of protection is not supported by the security package.
+
+0x8009030B
+
+SEC_E_NO_IMPERSONATION
+
+
+The security context does not allow impersonation of the client.
+
+0x8009030C
+
+SEC_E_LOGON_DENIED
+
+
+The logon attempt failed.
+
+0x8009030D
+
+SEC_E_UNKNOWN_CREDENTIALS
+
+
+The credentials supplied to the package were not recognized.
+
+0x8009030E
+
+SEC_E_NO_CREDENTIALS
+
+
+No credentials are available in the security package.
+
+0x8009030F
+
+SEC_E_MESSAGE_ALTERED
+
+
+The message or signature supplied for verification has been altered.
+
+0x80090310
+
+SEC_E_OUT_OF_SEQUENCE
+
+
+The message supplied for verification is out of sequence.
+
+0x80090311
+
+SEC_E_NO_AUTHENTICATING_AUTHORITY
+
+
+No authority could be contacted for authentication.
+
+0x80090316
+
+SEC_E_BAD_PKGID
+
+
+The requested security package does not exist.
+
+0x80090317
+
+SEC_E_CONTEXT_EXPIRED
+
+
+The context has expired and can no longer be used.
+
+0x80090318
+
+SEC_E_INCOMPLETE_MESSAGE
+
+
+The supplied message is incomplete. The signature was not verified.
+
+0x80090320
+
+SEC_E_INCOMPLETE_CREDENTIALS
+
+
+The credentials supplied were not complete and could not be verified. The context could not be initialized.
+
+0x80090321
+
+SEC_E_BUFFER_TOO_SMALL
+
+
+The buffers supplied to a function was too small.
+
+0x80090322
+
+SEC_E_WRONG_PRINCIPAL
+
+
+The target principal name is incorrect.
+
+0x80090324
+
+SEC_E_TIME_SKEW
+
+
+The clocks on the client and server machines are skewed.
+
+0x80090325
+
+SEC_E_UNTRUSTED_ROOT
+
+
+The certificate chain was issued by an authority that is not trusted.
+
+0x80090326
+
+SEC_E_ILLEGAL_MESSAGE
+
+
+The message received was unexpected or badly formatted.
+
+0x80090327
+
+SEC_E_CERT_UNKNOWN
+
+
+An unknown error occurred while processing the certificate.
+
+0x80090328
+
+SEC_E_CERT_EXPIRED
+
+
+The received certificate has expired.
+
+0x80090329
+
+SEC_E_ENCRYPT_FAILURE
+
+
+The specified data could not be encrypted.
+
+0x80090330
+
+SEC_E_DECRYPT_FAILURE
+
+
+The specified data could not be decrypted.
+
+0x80090331
+
+SEC_E_ALGORITHM_MISMATCH
+
+
+The client and server cannot communicate because they do not possess a common algorithm.
+
+0x80090332
+
+SEC_E_SECURITY_QOS_FAILED
+
+
+The security context could not be established due to a failure in the requested quality of service (for example, mutual authentication or delegation).
+
+0x80090333
+
+SEC_E_UNFINISHED_CONTEXT_DELETED
+
+
+A security context was deleted before the context was completed. This is considered a logon failure.
+
+0x80090334
+
+SEC_E_NO_TGT_REPLY
+
+
+The client is trying to negotiate a context and the server requires user-to-user but did not send a ticket granting ticket (TGT) reply.
+
+0x80090335
+
+SEC_E_NO_IP_ADDRESSES
+
+
+Unable to accomplish the requested task because the local machine does not have an IP addresses.
+
+0x80090336
+
+SEC_E_WRONG_CREDENTIAL_HANDLE
+
+
+The supplied credential handle does not match the credential associated with the security context.
+
+0x80090337
+
+SEC_E_CRYPTO_SYSTEM_INVALID
+
+
+The cryptographic system or checksum function is invalid because a required function is unavailable.
+
+0x80090338
+
+SEC_E_MAX_REFERRALS_EXCEEDED
+
+
+The number of maximum ticket referrals has been exceeded.
+
+0x80090339
+
+SEC_E_MUST_BE_KDC
+
+
+The local machine must be a Kerberos domain controller (KDC), and it is not.
+
+0x8009033A
+
+SEC_E_STRONG_CRYPTO_NOT_SUPPORTED
+
+
+The other end of the security negotiation requires strong cryptographics, but it is not supported on the local machine.
+
+0x8009033B
+
+SEC_E_TOO_MANY_PRINCIPALS
+
+
+The KDC reply contained more than one principal name.
+
+0x8009033C
+
+SEC_E_NO_PA_DATA
+
+
+Expected to find PA data for a hint of what etype to use, but it was not found.
+
+0x8009033D
+
+SEC_E_PKINIT_NAME_MISMATCH
+
+
+The client certificate does not contain a valid user principal name (UPN), or does not match the client name in the logon request. Contact your administrator.
+
+0x8009033E
+
+SEC_E_SMARTCARD_LOGON_REQUIRED
+
+
+Smart card logon is required and was not used.
+
+0x8009033F
+
+SEC_E_SHUTDOWN_IN_PROGRESS
+
+
+A system shutdown is in progress.
+
+0x80090340
+
+SEC_E_KDC_INVALID_REQUEST
+
+
+An invalid request was sent to the KDC.
+
+0x80090341
+
+SEC_E_KDC_UNABLE_TO_REFER
+
+
+The KDC was unable to generate a referral for the service requested.
+
+0x80090342
+
+SEC_E_KDC_UNKNOWN_ETYPE
+
+
+The encryption type requested is not supported by the KDC.
+
+0x80090343
+
+SEC_E_UNSUPPORTED_PREAUTH
+
+
+An unsupported pre-authentication mechanism was presented to the Kerberos package.
+
+0x80090345
+
+SEC_E_DELEGATION_REQUIRED
+
+
+The requested operation cannot be completed. The computer must be trusted for delegation, and the current user account must be configured to allow delegation.
+
+0x80090346
+
+SEC_E_BAD_BINDINGS
+
+
+Client's supplied Security Support Provider Interface (SSPI) channel bindings were incorrect.
+
+0x80090347
+
+SEC_E_MULTIPLE_ACCOUNTS
+
+
+The received certificate was mapped to multiple accounts.
+
+0x80090348
+
+SEC_E_NO_KERB_KEY
+
+
+No Kerberos key was found.
+
+0x80090349
+
+SEC_E_CERT_WRONG_USAGE
+
+
+The certificate is not valid for the requested usage.
+
+0x80090350
+
+SEC_E_DOWNGRADE_DETECTED
+
+
+The system detected a possible attempt to compromise security. Ensure that you can contact the server that authenticated you.
+
+0x80090351
+
+SEC_E_SMARTCARD_CERT_REVOKED
+
+
+The smart card certificate used for authentication has been revoked. Contact your system administrator. The event log might contain additional information.
+
+0x80090352
+
+SEC_E_ISSUING_CA_UNTRUSTED
+
+
+An untrusted certification authority (CA) was detected while processing the smart card certificate used for authentication. Contact your system administrator.
+
+0x80090353
+
+SEC_E_REVOCATION_OFFLINE_C
+
+
+The revocation status of the smart card certificate used for authentication could not be determined. Contact your system administrator.
+
+0x80090354
+
+SEC_E_PKINIT_CLIENT_FAILURE
+
+
+The smart card certificate used for authentication was not trusted. Contact your system administrator.
+
+0x80090355
+
+SEC_E_SMARTCARD_CERT_EXPIRED
+
+
+The smart card certificate used for authentication has expired. Contact your system administrator.
+
+0x80090356
+
+SEC_E_NO_S4U_PROT_SUPPORT
+
+
+The Kerberos subsystem encountered an error. A service for user protocol requests was made against a domain controller that does not support services for users.
+
+0x80090357
+
+SEC_E_CROSSREALM_DELEGATION_FAILURE
+
+
+An attempt was made by this server to make a Kerberos-constrained delegation request for a target outside the server's realm. This is not supported and indicates a misconfiguration on this server's allowed-to-delegate-to list. Contact your administrator.
+
+0x80090358
+
+SEC_E_REVOCATION_OFFLINE_KDC
+
+
+The revocation status of the domain controller certificate used for smart card authentication could not be determined. The system event log contains additional information. Contact your system administrator.
+
+0x80090359
+
+SEC_E_ISSUING_CA_UNTRUSTED_KDC
+
+
+An untrusted CA was detected while processing the domain controller certificate used for authentication. The system event log contains additional information. Contact your system administrator.
+
+0x8009035A
+
+SEC_E_KDC_CERT_EXPIRED
+
+
+The domain controller certificate used for smart card logon has expired. Contact your system administrator with the contents of your system event log.
+
+0x8009035B
+
+SEC_E_KDC_CERT_REVOKED
+
+
+The domain controller certificate used for smart card logon has been revoked. Contact your system administrator with the contents of your system event log.
+
+0x8009035D
+
+SEC_E_INVALID_PARAMETER
+
+
+One or more of the parameters passed to the function were invalid.
+
+0x8009035E
+
+SEC_E_DELEGATION_POLICY
+
+
+The client policy does not allow credential delegation to the target server.
+
+0x8009035F
+
+SEC_E_POLICY_NLTM_ONLY
+
+
+The client policy does not allow credential delegation to the target server with NLTM only authentication.
+
+0x80091001
+
+CRYPT_E_MSG_ERROR
+
+
+An error occurred while performing an operation on a cryptographic message.
+
+0x80091002
+
+CRYPT_E_UNKNOWN_ALGO
+
+
+Unknown cryptographic algorithm.
+
+0x80091003
+
+CRYPT_E_OID_FORMAT
+
+
+The object identifier is poorly formatted.
+
+0x80091004
+
+CRYPT_E_INVALID_MSG_TYPE
+
+
+Invalid cryptographic message type.
+
+0x80091005
+
+CRYPT_E_UNEXPECTED_ENCODING
+
+
+Unexpected cryptographic message encoding.
+
+0x80091006
+
+CRYPT_E_AUTH_ATTR_MISSING
+
+
+The cryptographic message does not contain an expected authenticated attribute.
+
+0x80091007
+
+CRYPT_E_HASH_VALUE
+
+
+The hash value is not correct.
+
+0x80091008
+
+CRYPT_E_INVALID_INDEX
+
+
+The index value is not valid.
+
+0x80091009
+
+CRYPT_E_ALREADY_DECRYPTED
+
+
+The content of the cryptographic message has already been decrypted.
+
+0x8009100A
+
+CRYPT_E_NOT_DECRYPTED
+
+
+The content of the cryptographic message has not been decrypted yet.
+
+0x8009100B
+
+CRYPT_E_RECIPIENT_NOT_FOUND
+
+
+The enveloped-data message does not contain the specified recipient.
+
+0x8009100C
+
+CRYPT_E_CONTROL_TYPE
+
+
+Invalid control type.
+
+0x8009100D
+
+CRYPT_E_ISSUER_SERIALNUMBER
+
+
+Invalid issuer or serial number.
+
+0x8009100E
+
+CRYPT_E_SIGNER_NOT_FOUND
+
+
+Cannot find the original signer.
+
+0x8009100F
+
+CRYPT_E_ATTRIBUTES_MISSING
+
+
+The cryptographic message does not contain all of the requested attributes.
+
+0x80091010
+
+CRYPT_E_STREAM_MSG_NOT_READY
+
+
+The streamed cryptographic message is not ready to return data.
+
+0x80091011
+
+CRYPT_E_STREAM_INSUFFICIENT_DATA
+
+
+The streamed cryptographic message requires more data to complete the decode operation.
+
+0x80092001
+
+CRYPT_E_BAD_LEN
+
+
+The length specified for the output data was insufficient.
+
+0x80092002
+
+CRYPT_E_BAD_ENCODE
+
+
+An error occurred during the encode or decode operation.
+
+0x80092003
+
+CRYPT_E_FILE_ERROR
+
+
+An error occurred while reading or writing to a file.
+
+0x80092004
+
+CRYPT_E_NOT_FOUND
+
+
+Cannot find object or property.
+
+0x80092005
+
+CRYPT_E_EXISTS
+
+
+The object or property already exists.
+
+0x80092006
+
+CRYPT_E_NO_PROVIDER
+
+
+No provider was specified for the store or object.
+
+0x80092007
+
+CRYPT_E_SELF_SIGNED
+
+
+The specified certificate is self-signed.
+
+0x80092008
+
+CRYPT_E_DELETED_PREV
+
+
+The previous certificate or certificate revocation list (CRL) context was deleted.
+
+0x80092009
+
+CRYPT_E_NO_MATCH
+
+
+Cannot find the requested object.
+
+0x8009200A
+
+CRYPT_E_UNEXPECTED_MSG_TYPE
+
+
+The certificate does not have a property that references a private key.
+
+0x8009200B
+
+CRYPT_E_NO_KEY_PROPERTY
+
+
+Cannot find the certificate and private key for decryption.
+
+0x8009200C
+
+CRYPT_E_NO_DECRYPT_CERT
+
+
+Cannot find the certificate and private key to use for decryption.
+
+0x8009200D
+
+CRYPT_E_BAD_MSG
+
+
+Not a cryptographic message or the cryptographic message is not formatted correctly.
+
+0x8009200E
+
+CRYPT_E_NO_SIGNER
+
+
+The signed cryptographic message does not have a signer for the specified signer index.
+
+0x8009200F
+
+CRYPT_E_PENDING_CLOSE
+
+
+Final closure is pending until additional frees or closes.
+
+0x80092010
+
+CRYPT_E_REVOKED
+
+
+The certificate is revoked.
+
+0x80092011
+
+CRYPT_E_NO_REVOCATION_DLL
+
+
+No DLL or exported function was found to verify revocation.
+
+0x80092012
+
+CRYPT_E_NO_REVOCATION_CHECK
+
+
+The revocation function was unable to check revocation for the certificate.
+
+0x80092013
+
+CRYPT_E_REVOCATION_OFFLINE
+
+
+The revocation function was unable to check revocation because the revocation server was offline.
+
+0x80092014
+
+CRYPT_E_NOT_IN_REVOCATION_DATABASE
+
+
+The certificate is not in the revocation server's database.
+
+0x80092020
+
+CRYPT_E_INVALID_NUMERIC_STRING
+
+
+The string contains a non-numeric character.
+
+0x80092021
+
+CRYPT_E_INVALID_PRINTABLE_STRING
+
+
+The string contains a nonprintable character.
+
+0x80092022
+
+CRYPT_E_INVALID_IA5_STRING
+
+
+The string contains a character not in the 7-bit ASCII character set.
+
+0x80092023
+
+CRYPT_E_INVALID_X500_STRING
+
+
+The string contains an invalid X500 name attribute key, object identifier (OID), value, or delimiter.
+
+0x80092024
+
+CRYPT_E_NOT_CHAR_STRING
+
+
+The dwValueType for the CERT_NAME_VALUE is not one of the character strings. Most likely it is either a CERT_RDN_ENCODED_BLOB or CERT_TDN_OCTED_STRING.
+
+0x80092025
+
+CRYPT_E_FILERESIZED
+
+
+The Put operation cannot continue. The file needs to be resized. However, there is already a signature present. A complete signing operation must be done.
+
+0x80092026
+
+CRYPT_E_SECURITY_SETTINGS
+
+
+The cryptographic operation failed due to a local security option setting.
+
+0x80092027
+
+CRYPT_E_NO_VERIFY_USAGE_DLL
+
+
+No DLL or exported function was found to verify subject usage.
+
+0x80092028
+
+CRYPT_E_NO_VERIFY_USAGE_CHECK
+
+
+The called function was unable to perform a usage check on the subject.
+
+0x80092029
+
+CRYPT_E_VERIFY_USAGE_OFFLINE
+
+
+The called function was unable to complete the usage check because the server was offline.
+
+0x8009202A
+
+CRYPT_E_NOT_IN_CTL
+
+
+The subject was not found in a certificate trust list (CTL).
+
+0x8009202B
+
+CRYPT_E_NO_TRUSTED_SIGNER
+
+
+None of the signers of the cryptographic message or certificate trust list is trusted.
+
+0x8009202C
+
+CRYPT_E_MISSING_PUBKEY_PARA
+
+
+The public key's algorithm parameters are missing.
+
+0x80093000
+
+CRYPT_E_OSS_ERROR
+
+
+OSS Certificate encode/decode error code base.
+
+0x80093001
+
+OSS_MORE_BUF
+
+
+OSS ASN.1 Error: Output Buffer is too small.
+
+0x80093002
+
+OSS_NEGATIVE_UINTEGER
+
+
+OSS ASN.1 Error: Signed integer is encoded as a unsigned integer.
+
+0x80093003
+
+OSS_PDU_RANGE
+
+
+OSS ASN.1 Error: Unknown ASN.1 data type.
+
+0x80093004
+
+OSS_MORE_INPUT
+
+
+OSS ASN.1 Error: Output buffer is too small; the decoded data has been truncated.
+
+0x80093005
+
+OSS_DATA_ERROR
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x80093006
+
+OSS_BAD_ARG
+
+
+OSS ASN.1 Error: Invalid argument.
+
+0x80093007
+
+OSS_BAD_VERSION
+
+
+OSS ASN.1 Error: Encode/Decode version mismatch.
+
+0x80093008
+
+OSS_OUT_MEMORY
+
+
+OSS ASN.1 Error: Out of memory.
+
+0x80093009
+
+OSS_PDU_MISMATCH
+
+
+OSS ASN.1 Error: Encode/Decode error.
+
+0x8009300A
+
+OSS_LIMITED
+
+
+OSS ASN.1 Error: Internal error.
+
+0x8009300B
+
+OSS_BAD_PTR
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x8009300C
+
+OSS_BAD_TIME
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x8009300D
+
+OSS_INDEFINITE_NOT_SUPPORTED
+
+
+OSS ASN.1 Error: Unsupported BER indefinite-length encoding.
+
+0x8009300E
+
+OSS_MEM_ERROR
+
+
+OSS ASN.1 Error: Access violation.
+
+0x8009300F
+
+OSS_BAD_TABLE
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x80093010
+
+OSS_TOO_LONG
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x80093011
+
+OSS_CONSTRAINT_VIOLATED
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x80093012
+
+OSS_FATAL_ERROR
+
+
+OSS ASN.1 Error: Internal error.
+
+0x80093013
+
+OSS_ACCESS_SERIALIZATION_ERROR
+
+
+OSS ASN.1 Error: Multithreading conflict.
+
+0x80093014
+
+OSS_NULL_TBL
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x80093015
+
+OSS_NULL_FCN
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x80093016
+
+OSS_BAD_ENCRULES
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x80093017
+
+OSS_UNAVAIL_ENCRULES
+
+
+OSS ASN.1 Error: Encode/Decode function not implemented.
+
+0x80093018
+
+OSS_CANT_OPEN_TRACE_WINDOW
+
+
+OSS ASN.1 Error: Trace file error.
+
+0x80093019
+
+OSS_UNIMPLEMENTED
+
+
+OSS ASN.1 Error: Function not implemented.
+
+0x8009301A
+
+OSS_OID_DLL_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x8009301B
+
+OSS_CANT_OPEN_TRACE_FILE
+
+
+OSS ASN.1 Error: Trace file error.
+
+0x8009301C
+
+OSS_TRACE_FILE_ALREADY_OPEN
+
+
+OSS ASN.1 Error: Trace file error.
+
+0x8009301D
+
+OSS_TABLE_MISMATCH
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x8009301E
+
+OSS_TYPE_NOT_SUPPORTED
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x8009301F
+
+OSS_REAL_DLL_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x80093020
+
+OSS_REAL_CODE_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x80093021
+
+OSS_OUT_OF_RANGE
+
+
+OSS ASN.1 Error: Program link error.
+
+0x80093022
+
+OSS_COPIER_DLL_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x80093023
+
+OSS_CONSTRAINT_DLL_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x80093024
+
+OSS_COMPARATOR_DLL_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x80093025
+
+OSS_COMPARATOR_CODE_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x80093026
+
+OSS_MEM_MGR_DLL_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x80093027
+
+OSS_PDV_DLL_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x80093028
+
+OSS_PDV_CODE_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x80093029
+
+OSS_API_DLL_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x8009302A
+
+OSS_BERDER_DLL_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x8009302B
+
+OSS_PER_DLL_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x8009302C
+
+OSS_OPEN_TYPE_ERROR
+
+
+OSS ASN.1 Error: Program link error.
+
+0x8009302D
+
+OSS_MUTEX_NOT_CREATED
+
+
+OSS ASN.1 Error: System resource error.
+
+0x8009302E
+
+OSS_CANT_CLOSE_TRACE_FILE
+
+
+OSS ASN.1 Error: Trace file error.
+
+0x80093100
+
+CRYPT_E_ASN1_ERROR
+
+
+ASN1 Certificate encode/decode error code base.
+
+0x80093101
+
+CRYPT_E_ASN1_INTERNAL
+
+
+ASN1 internal encode or decode error.
+
+0x80093102
+
+CRYPT_E_ASN1_EOD
+
+
+ASN1 unexpected end of data.
+
+0x80093103
+
+CRYPT_E_ASN1_CORRUPT
+
+
+ASN1 corrupted data.
+
+0x80093104
+
+CRYPT_E_ASN1_LARGE
+
+
+ASN1 value too large.
+
+0x80093105
+
+CRYPT_E_ASN1_CONSTRAINT
+
+
+ASN1 constraint violated.
+
+0x80093106
+
+CRYPT_E_ASN1_MEMORY
+
+
+ASN1 out of memory.
+
+0x80093107
+
+CRYPT_E_ASN1_OVERFLOW
+
+
+ASN1 buffer overflow.
+
+0x80093108
+
+CRYPT_E_ASN1_BADPDU
+
+
+ASN1 function not supported for this protocol data unit (PDU).
+
+0x80093109
+
+CRYPT_E_ASN1_BADARGS
+
+
+ASN1 bad arguments to function call.
+
+0x8009310A
+
+CRYPT_E_ASN1_BADREAL
+
+
+ASN1 bad real value.
+
+0x8009310B
+
+CRYPT_E_ASN1_BADTAG
+
+
+ASN1 bad tag value met.
+
+0x8009310C
+
+CRYPT_E_ASN1_CHOICE
+
+
+ASN1 bad choice value.
+
+0x8009310D
+
+CRYPT_E_ASN1_RULE
+
+
+ASN1 bad encoding rule.
+
+0x8009310E
+
+CRYPT_E_ASN1_UTF8
+
+
+ASN1 bad Unicode (UTF8).
+
+0x80093133
+
+CRYPT_E_ASN1_PDU_TYPE
+
+
+ASN1 bad PDU type.
+
+0x80093134
+
+CRYPT_E_ASN1_NYI
+
+
+ASN1 not yet implemented.
+
+0x80093201
+
+CRYPT_E_ASN1_EXTENDED
+
+
+ASN1 skipped unknown extensions.
+
+0x80093202
+
+CRYPT_E_ASN1_NOEOD
+
+
+ASN1 end of data expected.
+
+0x80094001
+
+CERTSRV_E_BAD_REQUESTSUBJECT
+
+
+The request subject name is invalid or too long.
+
+0x80094002
+
+CERTSRV_E_NO_REQUEST
+
+
+The request does not exist.
+
+0x80094003
+
+CERTSRV_E_BAD_REQUESTSTATUS
+
+
+The request's current status does not allow this operation.
+
+0x80094004
+
+CERTSRV_E_PROPERTY_EMPTY
+
+
+The requested property value is empty.
+
+0x80094005
+
+CERTSRV_E_INVALID_CA_CERTIFICATE
+
+
+The CA's certificate contains invalid data.
+
+0x80094006
+
+CERTSRV_E_SERVER_SUSPENDED
+
+
+Certificate service has been suspended for a database restore operation.
+
+0x80094007
+
+CERTSRV_E_ENCODING_LENGTH
+
+
+The certificate contains an encoded length that is potentially incompatible with older enrollment software.
+
+0x80094008
+
+CERTSRV_E_ROLECONFLICT
+
+
+The operation is denied. The user has multiple roles assigned, and the CA is configured to enforce role separation.
+
+0x80094009
+
+CERTSRV_E_RESTRICTEDOFFICER
+
+
+The operation is denied. It can only be performed by a certificate manager that is allowed to manage certificates for the current requester.
+
+0x8009400A
+
+CERTSRV_E_KEY_ARCHIVAL_NOT_CONFIGURED
+
+
+Cannot archive private key. The CA is not configured for key archival.
+
+0x8009400B
+
+CERTSRV_E_NO_VALID_KRA
+
+
+Cannot archive private key. The CA could not verify one or more key recovery certificates.
+
+0x8009400C
+
+CERTSRV_E_BAD_REQUEST_KEY_ARCHIVAL
+
+
+The request is incorrectly formatted. The encrypted private key must be in an unauthenticated attribute in an outermost signature.
+
+0x8009400D
+
+CERTSRV_E_NO_CAADMIN_DEFINED
+
+
+At least one security principal must have the permission to manage this CA.
+
+0x8009400E
+
+CERTSRV_E_BAD_RENEWAL_CERT_ATTRIBUTE
+
+
+The request contains an invalid renewal certificate attribute.
+
+0x8009400F
+
+CERTSRV_E_NO_DB_SESSIONS
+
+
+An attempt was made to open a CA database session, but there are already too many active sessions. The server needs to be configured to allow additional sessions.
+
+0x80094010
+
+CERTSRV_E_ALIGNMENT_FAULT
+
+
+A memory reference caused a data alignment fault.
+
+0x80094011
+
+CERTSRV_E_ENROLL_DENIED
+
+
+The permissions on this CA do not allow the current user to enroll for certificates.
+
+0x80094012
+
+CERTSRV_E_TEMPLATE_DENIED
+
+
+The permissions on the certificate template do not allow the current user to enroll for this type of certificate.
+
+0x80094013
+
+CERTSRV_E_DOWNLEVEL_DC_SSL_OR_UPGRADE
+
+
+The contacted domain controller cannot support signed Lightweight Directory Access Protocol (LDAP) traffic. Update the domain controller or configure Certificate Services to use SSL for Active Directory access.
+
+0x80094800
+
+CERTSRV_E_UNSUPPORTED_CERT_TYPE
+
+
+The requested certificate template is not supported by this CA.
+
+0x80094801
+
+CERTSRV_E_NO_CERT_TYPE
+
+
+The request contains no certificate template information.
+
+0x80094802
+
+CERTSRV_E_TEMPLATE_CONFLICT
+
+
+The request contains conflicting template information.
+
+0x80094803
+
+CERTSRV_E_SUBJECT_ALT_NAME_REQUIRED
+
+
+The request is missing a required Subject Alternate name extension.
+
+0x80094804
+
+CERTSRV_E_ARCHIVED_KEY_REQUIRED
+
+
+The request is missing a required private key for archival by the server.
+
+0x80094805
+
+CERTSRV_E_SMIME_REQUIRED
+
+
+The request is missing a required SMIME capabilities extension.
+
+0x80094806
+
+CERTSRV_E_BAD_RENEWAL_SUBJECT
+
+
+The request was made on behalf of a subject other than the caller. The certificate template must be configured to require at least one signature to authorize the request.
+
+0x80094807
+
+CERTSRV_E_BAD_TEMPLATE_VERSION
+
+
+The request template version is newer than the supported template version.
+
+0x80094808
+
+CERTSRV_E_TEMPLATE_POLICY_REQUIRED
+
+
+The template is missing a required signature policy attribute.
+
+0x80094809
+
+CERTSRV_E_SIGNATURE_POLICY_REQUIRED
+
+
+The request is missing required signature policy information.
+
+0x8009480A
+
+CERTSRV_E_SIGNATURE_COUNT
+
+
+The request is missing one or more required signatures.
+
+0x8009480B
+
+CERTSRV_E_SIGNATURE_REJECTED
+
+
+One or more signatures did not include the required application or issuance policies. The request is missing one or more required valid signatures.
+
+0x8009480C
+
+CERTSRV_E_ISSUANCE_POLICY_REQUIRED
+
+
+The request is missing one or more required signature issuance policies.
+
+0x8009480D
+
+CERTSRV_E_SUBJECT_UPN_REQUIRED
+
+
+The UPN is unavailable and cannot be added to the Subject Alternate name.
+
+0x8009480E
+
+CERTSRV_E_SUBJECT_DIRECTORY_GUID_REQUIRED
+
+
+The Active Directory GUID is unavailable and cannot be added to the Subject Alternate name.
+
+0x8009480F
+
+CERTSRV_E_SUBJECT_DNS_REQUIRED
+
+
+The Domain Name System (DNS) name is unavailable and cannot be added to the Subject Alternate name.
+
+0x80094810
+
+CERTSRV_E_ARCHIVED_KEY_UNEXPECTED
+
+
+The request includes a private key for archival by the server, but key archival is not enabled for the specified certificate template.
+
+0x80094811
+
+CERTSRV_E_KEY_LENGTH
+
+
+The public key does not meet the minimum size required by the specified certificate template.
+
+0x80094812
+
+CERTSRV_E_SUBJECT_EMAIL_REQUIRED
+
+
+The email name is unavailable and cannot be added to the Subject or Subject Alternate name.
+
+0x80094813
+
+CERTSRV_E_UNKNOWN_CERT_TYPE
+
+
+One or more certificate templates to be enabled on this CA could not be found.
+
+0x80094814
+
+CERTSRV_E_CERT_TYPE_OVERLAP
+
+
+The certificate template renewal period is longer than the certificate validity period. The template should be reconfigured or the CA certificate renewed.
+
+0x80094815
+
+CERTSRV_E_TOO_MANY_SIGNATURES
+
+
+The certificate template requires too many return authorization (RA) signatures. Only one RA signature is allowed.
+
+0x80094816
+
+CERTSRV_E_RENEWAL_BAD_PUBLIC_KEY
+
+
+The key used in a renewal request does not match one of the certificates being renewed.
+
+0x80094817
+
+CERTSRV_E_INVALID_EK
+
+
+The endorsement key certificate is not valid.
+
+0x8009481A
+
+CERTSRV_E_KEY_ATTESTATION
+
+
+Key attestation did not succeed.
+
+0x80095000
+
+XENROLL_E_KEY_NOT_EXPORTABLE
+
+
+The key is not exportable.
+
+0x80095001
+
+XENROLL_E_CANNOT_ADD_ROOT_CERT
+
+
+You cannot add the root CA certificate into your local store.
+
+0x80095002
+
+XENROLL_E_RESPONSE_KA_HASH_NOT_FOUND
+
+
+The key archival hash attribute was not found in the response.
+
+0x80095003
+
+XENROLL_E_RESPONSE_UNEXPECTED_KA_HASH
+
+
+An unexpected key archival hash attribute was found in the response.
+
+0x80095004
+
+XENROLL_E_RESPONSE_KA_HASH_MISMATCH
+
+
+There is a key archival hash mismatch between the request and the response.
+
+0x80095005
+
+XENROLL_E_KEYSPEC_SMIME_MISMATCH
+
+
+Signing certificate cannot include SMIME extension.
+
+0x80096001
+
+TRUST_E_SYSTEM_ERROR
+
+
+A system-level error occurred while verifying trust.
+
+0x80096002
+
+TRUST_E_NO_SIGNER_CERT
+
+
+The certificate for the signer of the message is invalid or not found.
+
+0x80096003
+
+TRUST_E_COUNTER_SIGNER
+
+
+One of the counter signatures was invalid.
+
+0x80096004
+
+TRUST_E_CERT_SIGNATURE
+
+
+The signature of the certificate cannot be verified.
+
+0x80096005
+
+TRUST_E_TIME_STAMP
+
+
+The time-stamp signature or certificate could not be verified or is malformed.
+
+0x80096010
+
+TRUST_E_BAD_DIGEST
+
+
+The digital signature of the object did not verify.
+
+0x80096019
+
+TRUST_E_BASIC_CONSTRAINTS
+
+
+A certificate's basic constraint extension has not been observed.
+
+0x8009601E
+
+TRUST_E_FINANCIAL_CRITERIA
+
+
+The certificate does not meet or contain the Authenticode financial extensions.
+
+0x80097001
+
+MSSIPOTF_E_OUTOFMEMRANGE
+
+
+Tried to reference a part of the file outside the proper range.
+
+0x80097002
+
+MSSIPOTF_E_CANTGETOBJECT
+
+
+Could not retrieve an object from the file.
+
+0x80097003
+
+MSSIPOTF_E_NOHEADTABLE
+
+
+Could not find the head table in the file.
+
+0x80097004
+
+MSSIPOTF_E_BAD_MAGICNUMBER
+
+
+The magic number in the head table is incorrect.
+
+0x80097005
+
+MSSIPOTF_E_BAD_OFFSET_TABLE
+
+
+The offset table has incorrect values.
+
+0x80097006
+
+MSSIPOTF_E_TABLE_TAGORDER
+
+
+Duplicate table tags or the tags are out of alphabetical order.
+
+0x80097007
+
+MSSIPOTF_E_TABLE_LONGWORD
+
+
+A table does not start on a long word boundary.
+
+0x80097008
+
+MSSIPOTF_E_BAD_FIRST_TABLE_PLACEMENT
+
+
+First table does not appear after header information.
+
+0x80097009
+
+MSSIPOTF_E_TABLES_OVERLAP
+
+
+Two or more tables overlap.
+
+0x8009700A
+
+MSSIPOTF_E_TABLE_PADBYTES
+
+
+Too many pad bytes between tables, or pad bytes are not 0.
+
+0x8009700B
+
+MSSIPOTF_E_FILETOOSMALL
+
+
+File is too small to contain the last table.
+
+0x8009700C
+
+MSSIPOTF_E_TABLE_CHECKSUM
+
+
+A table checksum is incorrect.
+
+0x8009700D
+
+MSSIPOTF_E_FILE_CHECKSUM
+
+
+The file checksum is incorrect.
+
+0x80097010
+
+MSSIPOTF_E_FAILED_POLICY
+
+
+The signature does not have the correct attributes for the policy.
+
+0x80097011
+
+MSSIPOTF_E_FAILED_HINTS_CHECK
+
+
+The file did not pass the hints check.
+
+0x80097012
+
+MSSIPOTF_E_NOT_OPENTYPE
+
+
+The file is not an OpenType file.
+
+0x80097013
+
+MSSIPOTF_E_FILE
+
+
+Failed on a file operation (such as open, map, read, or write).
+
+0x80097014
+
+MSSIPOTF_E_CRYPT
+
+
+A call to a CryptoAPI function failed.
+
+0x80097015
+
+MSSIPOTF_E_BADVERSION
+
+
+There is a bad version number in the file.
+
+0x80097016
+
+MSSIPOTF_E_DSIG_STRUCTURE
+
+
+The structure of the DSIG table is incorrect.
+
+0x80097017
+
+MSSIPOTF_E_PCONST_CHECK
+
+
+A check failed in a partially constant table.
+
+0x80097018
+
+MSSIPOTF_E_STRUCTURE
+
+
+Some kind of structural error.
+
+0x80097019
+
+ERROR_CRED_REQUIRES_CONFIRMATION
+
+
+The requested credential requires confirmation.
+
+0x800B0001
+
+TRUST_E_PROVIDER_UNKNOWN
+
+
+Unknown trust provider.
+
+0x800B0002
+
+TRUST_E_ACTION_UNKNOWN
+
+
+The trust verification action specified is not supported by the specified trust provider.
+
+0x800B0003
+
+TRUST_E_SUBJECT_FORM_UNKNOWN
+
+
+The form specified for the subject is not one supported or known by the specified trust provider.
+
+0x800B0004
+
+TRUST_E_SUBJECT_NOT_TRUSTED
+
+
+The subject is not trusted for the specified action.
+
+0x800B0005
+
+DIGSIG_E_ENCODE
+
+
+Error due to problem in ASN.1 encoding process.
+
+0x800B0006
+
+DIGSIG_E_DECODE
+
+
+Error due to problem in ASN.1 decoding process.
+
+0x800B0007
+
+DIGSIG_E_EXTENSIBILITY
+
+
+Reading/writing extensions where attributes are appropriate, and vice versa.
+
+0x800B0008
+
+DIGSIG_E_CRYPTO
+
+
+Unspecified cryptographic failure.
+
+0x800B0009
+
+PERSIST_E_SIZEDEFINITE
+
+
+The size of the data could not be determined.
+
+0x800B000A
+
+PERSIST_E_SIZEINDEFINITE
+
+
+The size of the indefinite-sized data could not be determined.
+
+0x800B000B
+
+PERSIST_E_NOTSELFSIZING
+
+
+This object does not read and write self-sizing data.
+
+0x800B0100
+
+TRUST_E_NOSIGNATURE
+
+
+No signature was present in the subject.
+
+0x800B0101
+
+CERT_E_EXPIRED
+
+
+A required certificate is not within its validity period when verifying against the current system clock or the time stamp in the signed file.
+
+0x800B0102
+
+CERT_E_VALIDITYPERIODNESTING
+
+
+The validity periods of the certification chain do not nest correctly.
+
+0x800B0103
+
+CERT_E_ROLE
+
+
+A certificate that can only be used as an end entity is being used as a CA or vice versa.
+
+0x800B0104
+
+CERT_E_PATHLENCONST
+
+
+A path length constraint in the certification chain has been violated.
+
+0x800B0105
+
+CERT_E_CRITICAL
+
+
+A certificate contains an unknown extension that is marked "critical".
+
+0x800B0106
+
+CERT_E_PURPOSE
+
+
+A certificate is being used for a purpose other than the ones specified by its CA.
+
+0x800B0107
+
+CERT_E_ISSUERCHAINING
+
+
+A parent of a given certificate did not issue that child certificate.
+
+0x800B0108
+
+CERT_E_MALFORMED
+
+
+A certificate is missing or has an empty value for an important field, such as a subject or issuer name.
+
+0x800B0109
+
+CERT_E_UNTRUSTEDROOT
+
+
+A certificate chain processed, but terminated in a root certificate that is not trusted by the trust provider.
+
+0x800B010A
+
+CERT_E_CHAINING
+
+
+A certificate chain could not be built to a trusted root authority.
+
+0x800B010B
+
+TRUST_E_FAIL
+
+
+Generic trust failure.
+
+0x800B010C
+
+CERT_E_REVOKED
+
+
+A certificate was explicitly revoked by its issuer. If the certificate is Microsoft Windows PCA 2010, then the driver was signed by a certificate no longer recognized by Windows.
+
+0x800B010D
+
+CERT_E_UNTRUSTEDTESTROOT
+
+
+The certification path terminates with the test root that is not trusted with the current policy settings.
+
+0x800B010E
+
+CERT_E_REVOCATION_FAILURE
+
+
+The revocation process could not continue—the certificates could not be checked.
+
+0x800B010F
+
+CERT_E_CN_NO_MATCH
+
+
+The certificate's CN name does not match the passed value.
+
+0x800B0110
+
+CERT_E_WRONG_USAGE
+
+
+The certificate is not valid for the requested usage.
+
+0x800B0111
+
+TRUST_E_EXPLICIT_DISTRUST
+
+
+The certificate was explicitly marked as untrusted by the user.
+
+0x800B0112
+
+CERT_E_UNTRUSTEDCA
+
+
+A certification chain processed correctly, but one of the CA certificates is not trusted by the policy provider.
+
+0x800B0113
+
+CERT_E_INVALID_POLICY
+
+
+The certificate has invalid policy.
+
+0x800B0114
+
+CERT_E_INVALID_NAME
+
+
+The certificate has an invalid name. The name is not included in the permitted list or is explicitly excluded.
+
+0x800D0003
+
+NS_W_SERVER_BANDWIDTH_LIMIT
+
+
+The maximum filebitrate value specified is greater than the server's configured maximum bandwidth.
+
+0x800D0004
+
+NS_W_FILE_BANDWIDTH_LIMIT
+
+
+The maximum bandwidth value specified is less than the maximum filebitrate.
+
+0x800D0060
+
+NS_W_UNKNOWN_EVENT
+
+
+Unknown %1 event encountered.
+
+0x800D0199
+
+NS_I_CATATONIC_FAILURE
+
+
+Disk %1 ( %2 ) on Content Server %3, will be failed because it is catatonic.
+
+0x800D019A
+
+NS_I_CATATONIC_AUTO_UNFAIL
+
+
+Disk %1 ( %2 ) on Content Server %3, auto online from catatonic state.
+
+0x800F0000
+
+SPAPI_E_EXPECTED_SECTION_NAME
+
+
+A non-empty line was encountered in the INF before the start of a section.
+
+0x800F0001
+
+SPAPI_E_BAD_SECTION_NAME_LINE
+
+
+A section name marker in the information file (INF) is not complete or does not exist on a line by itself.
+
+0x800F0002
+
+SPAPI_E_SECTION_NAME_TOO_LONG
+
+
+An INF section was encountered whose name exceeds the maximum section name length.
+
+0x800F0003
+
+SPAPI_E_GENERAL_SYNTAX
+
+
+The syntax of the INF is invalid.
+
+0x800F0100
+
+SPAPI_E_WRONG_INF_STYLE
+
+
+The style of the INF is different than what was requested.
+
+0x800F0101
+
+SPAPI_E_SECTION_NOT_FOUND
+
+
+The required section was not found in the INF.
+
+0x800F0102
+
+SPAPI_E_LINE_NOT_FOUND
+
+
+The required line was not found in the INF.
+
+0x800F0103
+
+SPAPI_E_NO_BACKUP
+
+
+The files affected by the installation of this file queue have not been backed up for uninstall.
+
+0x800F0200
+
+SPAPI_E_NO_ASSOCIATED_CLASS
+
+
+The INF or the device information set or element does not have an associated install class.
+
+0x800F0201
+
+SPAPI_E_CLASS_MISMATCH
+
+
+The INF or the device information set or element does not match the specified install class.
+
+0x800F0202
+
+SPAPI_E_DUPLICATE_FOUND
+
+
+An existing device was found that is a duplicate of the device being manually installed.
+
+0x800F0203
+
+SPAPI_E_NO_DRIVER_SELECTED
+
+
+There is no driver selected for the device information set or element.
+
+0x800F0204
+
+SPAPI_E_KEY_DOES_NOT_EXIST
+
+
+The requested device registry key does not exist.
+
+0x800F0205
+
+SPAPI_E_INVALID_DEVINST_NAME
+
+
+The device instance name is invalid.
+
+0x800F0206
+
+SPAPI_E_INVALID_CLASS
+
+
+The install class is not present or is invalid.
+
+0x800F0207
+
+SPAPI_E_DEVINST_ALREADY_EXISTS
+
+
+The device instance cannot be created because it already exists.
+
+0x800F0208
+
+SPAPI_E_DEVINFO_NOT_REGISTERED
+
+
+The operation cannot be performed on a device information element that has not been registered.
+
+0x800F0209
+
+SPAPI_E_INVALID_REG_PROPERTY
+
+
+The device property code is invalid.
+
+0x800F020A
+
+SPAPI_E_NO_INF
+
+
+The INF from which a driver list is to be built does not exist.
+
+0x800F020B
+
+SPAPI_E_NO_SUCH_DEVINST
+
+
+The device instance does not exist in the hardware tree.
+
+0x800F020C
+
+SPAPI_E_CANT_LOAD_CLASS_ICON
+
+
+The icon representing this install class cannot be loaded.
+
+0x800F020D
+
+SPAPI_E_INVALID_CLASS_INSTALLER
+
+
+The class installer registry entry is invalid.
+
+0x800F020E
+
+SPAPI_E_DI_DO_DEFAULT
+
+
+The class installer has indicated that the default action should be performed for this installation request.
+
+0x800F020F
+
+SPAPI_E_DI_NOFILECOPY
+
+
+The operation does not require any files to be copied.
+
+0x800F0210
+
+SPAPI_E_INVALID_HWPROFILE
+
+
+The specified hardware profile does not exist.
+
+0x800F0211
+
+SPAPI_E_NO_DEVICE_SELECTED
+
+
+There is no device information element currently selected for this device information set.
+
+0x800F0212
+
+SPAPI_E_DEVINFO_LIST_LOCKED
+
+
+The operation cannot be performed because the device information set is locked.
+
+0x800F0213
+
+SPAPI_E_DEVINFO_DATA_LOCKED
+
+
+The operation cannot be performed because the device information element is locked.
+
+0x800F0214
+
+SPAPI_E_DI_BAD_PATH
+
+
+The specified path does not contain any applicable device INFs.
+
+0x800F0215
+
+SPAPI_E_NO_CLASSINSTALL_PARAMS
+
+
+No class installer parameters have been set for the device information set or element.
+
+0x800F0216
+
+SPAPI_E_FILEQUEUE_LOCKED
+
+
+The operation cannot be performed because the file queue is locked.
+
+0x800F0217
+
+SPAPI_E_BAD_SERVICE_INSTALLSECT
+
+
+A service installation section in this INF is invalid.
+
+0x800F0218
+
+SPAPI_E_NO_CLASS_DRIVER_LIST
+
+
+There is no class driver list for the device information element.
+
+0x800F0219
+
+SPAPI_E_NO_ASSOCIATED_SERVICE
+
+
+The installation failed because a function driver was not specified for this device instance.
+
+0x800F021A
+
+SPAPI_E_NO_DEFAULT_DEVICE_INTERFACE
+
+
+There is presently no default device interface designated for this interface class.
+
+0x800F021B
+
+SPAPI_E_DEVICE_INTERFACE_ACTIVE
+
+
+The operation cannot be performed because the device interface is currently active.
+
+0x800F021C
+
+SPAPI_E_DEVICE_INTERFACE_REMOVED
+
+
+The operation cannot be performed because the device interface has been removed from the system.
+
+0x800F021D
+
+SPAPI_E_BAD_INTERFACE_INSTALLSECT
+
+
+An interface installation section in this INF is invalid.
+
+0x800F021E
+
+SPAPI_E_NO_SUCH_INTERFACE_CLASS
+
+
+This interface class does not exist in the system.
+
+0x800F021F
+
+SPAPI_E_INVALID_REFERENCE_STRING
+
+
+The reference string supplied for this interface device is invalid.
+
+0x800F0220
+
+SPAPI_E_INVALID_MACHINENAME
+
+
+The specified machine name does not conform to Universal Naming Convention (UNCs).
+
+0x800F0221
+
+SPAPI_E_REMOTE_COMM_FAILURE
+
+
+A general remote communication error occurred.
+
+0x800F0222
+
+SPAPI_E_MACHINE_UNAVAILABLE
+
+
+The machine selected for remote communication is not available at this time.
+
+0x800F0223
+
+SPAPI_E_NO_CONFIGMGR_SERVICES
+
+
+The Plug and Play service is not available on the remote machine.
+
+0x800F0224
+
+SPAPI_E_INVALID_PROPPAGE_PROVIDER
+
+
+The property page provider registry entry is invalid.
+
+0x800F0225
+
+SPAPI_E_NO_SUCH_DEVICE_INTERFACE
+
+
+The requested device interface is not present in the system.
+
+0x800F0226
+
+SPAPI_E_DI_POSTPROCESSING_REQUIRED
+
+
+The device's co-installer has additional work to perform after installation is complete.
+
+0x800F0227
+
+SPAPI_E_INVALID_COINSTALLER
+
+
+The device's co-installer is invalid.
+
+0x800F0228
+
+SPAPI_E_NO_COMPAT_DRIVERS
+
+
+There are no compatible drivers for this device.
+
+0x800F0229
+
+SPAPI_E_NO_DEVICE_ICON
+
+
+There is no icon that represents this device or device type.
+
+0x800F022A
+
+SPAPI_E_INVALID_INF_LOGCONFIG
+
+
+A logical configuration specified in this INF is invalid.
+
+0x800F022B
+
+SPAPI_E_DI_DONT_INSTALL
+
+
+The class installer has denied the request to install or upgrade this device.
+
+0x800F022C
+
+SPAPI_E_INVALID_FILTER_DRIVER
+
+
+One of the filter drivers installed for this device is invalid.
+
+0x800F022D
+
+SPAPI_E_NON_WINDOWS_NT_DRIVER
+
+
+The driver selected for this device does not support Windows XP operating system.
+
+0x800F022E
+
+SPAPI_E_NON_WINDOWS_DRIVER
+
+
+The driver selected for this device does not support Windows.
+
+0x800F022F
+
+SPAPI_E_NO_CATALOG_FOR_OEM_INF
+
+
+The third-party INF does not contain digital signature information.
+
+0x800F0230
+
+SPAPI_E_DEVINSTALL_QUEUE_NONNATIVE
+
+
+An invalid attempt was made to use a device installation file queue for verification of digital signatures relative to other platforms.
+
+0x800F0231
+
+SPAPI_E_NOT_DISABLEABLE
+
+
+The device cannot be disabled.
+
+0x800F0232
+
+SPAPI_E_CANT_REMOVE_DEVINST
+
+
+The device could not be dynamically removed.
+
+0x800F0233
+
+SPAPI_E_INVALID_TARGET
+
+
+Cannot copy to specified target.
+
+0x800F0234
+
+SPAPI_E_DRIVER_NONNATIVE
+
+
+Driver is not intended for this platform.
+
+0x800F0235
+
+SPAPI_E_IN_WOW64
+
+
+Operation not allowed in WOW64.
+
+0x800F0236
+
+SPAPI_E_SET_SYSTEM_RESTORE_POINT
+
+
+The operation involving unsigned file copying was rolled back, so that a system restore point could be set.
+
+0x800F0237
+
+SPAPI_E_INCORRECTLY_COPIED_INF
+
+
+An INF was copied into the Windows INF directory in an improper manner.
+
+0x800F0238
+
+SPAPI_E_SCE_DISABLED
+
+
+The Security Configuration Editor (SCE) APIs have been disabled on this embedded product.
+
+0x800F0239
+
+SPAPI_E_UNKNOWN_EXCEPTION
+
+
+An unknown exception was encountered.
+
+0x800F023A
+
+SPAPI_E_PNP_REGISTRY_ERROR
+
+
+A problem was encountered when accessing the Plug and Play registry database.
+
+0x800F023B
+
+SPAPI_E_REMOTE_REQUEST_UNSUPPORTED
+
+
+The requested operation is not supported for a remote machine.
+
+0x800F023C
+
+SPAPI_E_NOT_AN_INSTALLED_OEM_INF
+
+
+The specified file is not an installed original equipment manufacturer (OEM) INF.
+
+0x800F023D
+
+SPAPI_E_INF_IN_USE_BY_DEVICES
+
+
+One or more devices are presently installed using the specified INF.
+
+0x800F023E
+
+SPAPI_E_DI_FUNCTION_OBSOLETE
+
+
+The requested device install operation is obsolete.
+
+0x800F023F
+
+SPAPI_E_NO_AUTHENTICODE_CATALOG
+
+
+A file could not be verified because it does not have an associated catalog signed via Authenticode.
+
+0x800F0240
+
+SPAPI_E_AUTHENTICODE_DISALLOWED
+
+
+Authenticode signature verification is not supported for the specified INF.
+
+0x800F0241
+
+SPAPI_E_AUTHENTICODE_TRUSTED_PUBLISHER
+
+
+The INF was signed with an Authenticode catalog from a trusted publisher.
+
+0x800F0242
+
+SPAPI_E_AUTHENTICODE_TRUST_NOT_ESTABLISHED
+
+
+The publisher of an Authenticode-signed catalog has not yet been established as trusted.
+
+0x800F0243
+
+SPAPI_E_AUTHENTICODE_PUBLISHER_NOT_TRUSTED
+
+
+The publisher of an Authenticode-signed catalog was not established as trusted.
+
+0x800F0244
+
+SPAPI_E_SIGNATURE_OSATTRIBUTE_MISMATCH
+
+
+The software was tested for compliance with Windows logo requirements on a different version of Windows and might not be compatible with this version.
+
+0x800F0245
+
+SPAPI_E_ONLY_VALIDATE_VIA_AUTHENTICODE
+
+
+The file can be validated only by a catalog signed via Authenticode.
+
+0x800F0246
+
+SPAPI_E_DEVICE_INSTALLER_NOT_READY
+
+
+One of the installers for this device cannot perform the installation at this time.
+
+0x800F0247
+
+SPAPI_E_DRIVER_STORE_ADD_FAILED
+
+
+A problem was encountered while attempting to add the driver to the store.
+
+0x800F0248
+
+SPAPI_E_DEVICE_INSTALL_BLOCKED
+
+
+The installation of this device is forbidden by system policy. Contact your system administrator.
+
+0x800F0249
+
+SPAPI_E_DRIVER_INSTALL_BLOCKED
+
+
+The installation of this driver is forbidden by system policy. Contact your system administrator.
+
+0x800F024A
+
+SPAPI_E_WRONG_INF_TYPE
+
+
+The specified INF is the wrong type for this operation.
+
+0x800F024B
+
+SPAPI_E_FILE_HASH_NOT_IN_CATALOG
+
+
+The hash for the file is not present in the specified catalog file. The file is likely corrupt or the victim of tampering.
+
+0x800F024C
+
+SPAPI_E_DRIVER_STORE_DELETE_FAILED
+
+
+A problem was encountered while attempting to delete the driver from the store.
+
+0x800F0300
+
+SPAPI_E_UNRECOVERABLE_STACK_OVERFLOW
+
+
+An unrecoverable stack overflow was encountered.
+
+0x800F1000
+
+SPAPI_E_ERROR_NOT_INSTALLED
+
+
+No installed components were detected.
+
+0x80100001
+
+SCARD_F_INTERNAL_ERROR
+
+
+An internal consistency check failed.
+
+0x80100002
+
+SCARD_E_CANCELLED
+
+
+The action was canceled by an SCardCancel request.
+
+0x80100003
+
+SCARD_E_INVALID_HANDLE
+
+
+The supplied handle was invalid.
+
+0x80100004
+
+SCARD_E_INVALID_PARAMETER
+
+
+One or more of the supplied parameters could not be properly interpreted.
+
+0x80100005
+
+SCARD_E_INVALID_TARGET
+
+
+Registry startup information is missing or invalid.
+
+0x80100006
+
+SCARD_E_NO_MEMORY
+
+
+Not enough memory available to complete this command.
+
+0x80100007
+
+SCARD_F_WAITED_TOO_LONG
+
+
+An internal consistency timer has expired.
+
+0x80100008
+
+SCARD_E_INSUFFICIENT_BUFFER
+
+
+The data buffer to receive returned data is too small for the returned data.
+
+0x80100009
+
+SCARD_E_UNKNOWN_READER
+
+
+The specified reader name is not recognized.
+
+0x8010000A
+
+SCARD_E_TIMEOUT
+
+
+The user-specified time-out value has expired.
+
+0x8010000B
+
+SCARD_E_SHARING_VIOLATION
+
+
+The smart card cannot be accessed because of other connections outstanding.
+
+0x8010000C
+
+SCARD_E_NO_SMARTCARD
+
+
+The operation requires a smart card, but no smart card is currently in the device.
+
+0x8010000D
+
+SCARD_E_UNKNOWN_CARD
+
+
+The specified smart card name is not recognized.
+
+0x8010000E
+
+SCARD_E_CANT_DISPOSE
+
+
+The system could not dispose of the media in the requested manner.
+
+0x8010000F
+
+SCARD_E_PROTO_MISMATCH
+
+
+The requested protocols are incompatible with the protocol currently in use with the smart card.
+
+0x80100010
+
+SCARD_E_NOT_READY
+
+
+The reader or smart card is not ready to accept commands.
+
+0x80100011
+
+SCARD_E_INVALID_VALUE
+
+
+One or more of the supplied parameters values could not be properly interpreted.
+
+0x80100012
+
+SCARD_E_SYSTEM_CANCELLED
+
+
+The action was canceled by the system, presumably to log off or shut down.
+
+0x80100013
+
+SCARD_F_COMM_ERROR
+
+
+An internal communications error has been detected.
+
+0x80100014
+
+SCARD_F_UNKNOWN_ERROR
+
+
+An internal error has been detected, but the source is unknown.
+
+0x80100015
+
+SCARD_E_INVALID_ATR
+
+
+An automatic terminal recognition (ATR) obtained from the registry is not a valid ATR string.
+
+0x80100016
+
+SCARD_E_NOT_TRANSACTED
+
+
+An attempt was made to end a nonexistent transaction.
+
+0x80100017
+
+SCARD_E_READER_UNAVAILABLE
+
+
+The specified reader is not currently available for use.
+
+0x80100018
+
+SCARD_P_SHUTDOWN
+
+
+The operation has been aborted to allow the server application to exit.
+
+0x80100019
+
+SCARD_E_PCI_TOO_SMALL
+
+
+The peripheral component interconnect (PCI) Receive buffer was too small.
+
+0x8010001A
+
+SCARD_E_READER_UNSUPPORTED
+
+
+The reader driver does not meet minimal requirements for support.
+
+0x8010001B
+
+SCARD_E_DUPLICATE_READER
+
+
+The reader driver did not produce a unique reader name.
+
+0x8010001C
+
+SCARD_E_CARD_UNSUPPORTED
+
+
+The smart card does not meet minimal requirements for support.
+
+0x8010001D
+
+SCARD_E_NO_SERVICE
+
+
+The smart card resource manager is not running.
+
+0x8010001E
+
+SCARD_E_SERVICE_STOPPED
+
+
+The smart card resource manager has shut down.
+
+0x8010001F
+
+SCARD_E_UNEXPECTED
+
+
+An unexpected card error has occurred.
+
+0x80100020
+
+SCARD_E_ICC_INSTALLATION
+
+
+No primary provider can be found for the smart card.
+
+0x80100021
+
+SCARD_E_ICC_CREATEORDER
+
+
+The requested order of object creation is not supported.
+
+0x80100022
+
+SCARD_E_UNSUPPORTED_FEATURE
+
+
+This smart card does not support the requested feature.
+
+0x80100023
+
+SCARD_E_DIR_NOT_FOUND
+
+
+The identified directory does not exist in the smart card.
+
+0x80100024
+
+SCARD_E_FILE_NOT_FOUND
+
+
+The identified file does not exist in the smart card.
+
+0x80100025
+
+SCARD_E_NO_DIR
+
+
+The supplied path does not represent a smart card directory.
+
+0x80100026
+
+SCARD_E_NO_FILE
+
+
+The supplied path does not represent a smart card file.
+
+0x80100027
+
+SCARD_E_NO_ACCESS
+
+
+Access is denied to this file.
+
+0x80100028
+
+SCARD_E_WRITE_TOO_MANY
+
+
+The smart card does not have enough memory to store the information.
+
+0x80100029
+
+SCARD_E_BAD_SEEK
+
+
+There was an error trying to set the smart card file object pointer.
+
+0x8010002A
+
+SCARD_E_INVALID_CHV
+
+
+The supplied PIN is incorrect.
+
+0x8010002B
+
+SCARD_E_UNKNOWN_RES_MNG
+
+
+An unrecognized error code was returned from a layered component.
+
+0x8010002C
+
+SCARD_E_NO_SUCH_CERTIFICATE
+
+
+The requested certificate does not exist.
+
+0x8010002D
+
+SCARD_E_CERTIFICATE_UNAVAILABLE
+
+
+The requested certificate could not be obtained.
+
+0x8010002E
+
+SCARD_E_NO_READERS_AVAILABLE
+
+
+Cannot find a smart card reader.
+
+0x8010002F
+
+SCARD_E_COMM_DATA_LOST
+
+
+A communications error with the smart card has been detected. Retry the operation.
+
+0x80100030
+
+SCARD_E_NO_KEY_CONTAINER
+
+
+The requested key container does not exist on the smart card.
+
+0x80100031
+
+SCARD_E_SERVER_TOO_BUSY
+
+
+The smart card resource manager is too busy to complete this operation.
+
+0x80100065
+
+SCARD_W_UNSUPPORTED_CARD
+
+
+The reader cannot communicate with the smart card, due to ATR configuration conflicts.
+
+0x80100066
+
+SCARD_W_UNRESPONSIVE_CARD
+
+
+The smart card is not responding to a reset.
+
+0x80100067
+
+SCARD_W_UNPOWERED_CARD
+
+
+Power has been removed from the smart card, so that further communication is not possible.
+
+0x80100068
+
+SCARD_W_RESET_CARD
+
+
+The smart card has been reset, so any shared state information is invalid.
+
+0x80100069
+
+SCARD_W_REMOVED_CARD
+
+
+The smart card has been removed, so that further communication is not possible.
+
+0x8010006A
+
+SCARD_W_SECURITY_VIOLATION
+
+
+Access was denied because of a security violation.
+
+0x8010006B
+
+SCARD_W_WRONG_CHV
+
+
+The card cannot be accessed because the wrong PIN was presented.
+
+0x8010006C
+
+SCARD_W_CHV_BLOCKED
+
+
+The card cannot be accessed because the maximum number of PIN entry attempts has been reached.
+
+0x8010006D
+
+SCARD_W_EOF
+
+
+The end of the smart card file has been reached.
+
+0x8010006E
+
+SCARD_W_CANCELLED_BY_USER
+
+
+The action was canceled by the user.
+
+0x8010006F
+
+SCARD_W_CARD_NOT_AUTHENTICATED
+
+
+No PIN was presented to the smart card.
+
+0x80110401
+
+COMADMIN_E_OBJECTERRORS
+
+
+Errors occurred accessing one or more objects—the ErrorInfo collection contains more detail.
+
+0x80110402
+
+COMADMIN_E_OBJECTINVALID
+
+
+One or more of the object's properties are missing or invalid.
+
+0x80110403
+
+COMADMIN_E_KEYMISSING
+
+
+The object was not found in the catalog.
+
+0x80110404
+
+COMADMIN_E_ALREADYINSTALLED
+
+
+The object is already registered.
+
+0x80110407
+
+COMADMIN_E_APP_FILE_WRITEFAIL
+
+
+An error occurred writing to the application file.
+
+0x80110408
+
+COMADMIN_E_APP_FILE_READFAIL
+
+
+An error occurred reading the application file.
+
+0x80110409
+
+COMADMIN_E_APP_FILE_VERSION
+
+
+Invalid version number in application file.
+
+0x8011040A
+
+COMADMIN_E_BADPATH
+
+
+The file path is invalid.
+
+0x8011040B
+
+COMADMIN_E_APPLICATIONEXISTS
+
+
+The application is already installed.
+
+0x8011040C
+
+COMADMIN_E_ROLEEXISTS
+
+
+The role already exists.
+
+0x8011040D
+
+COMADMIN_E_CANTCOPYFILE
+
+
+An error occurred copying the file.
+
+0x8011040F
+
+COMADMIN_E_NOUSER
+
+
+One or more users are not valid.
+
+0x80110410
+
+COMADMIN_E_INVALIDUSERIDS
+
+
+One or more users in the application file are not valid.
+
+0x80110411
+
+COMADMIN_E_NOREGISTRYCLSID
+
+
+The component's CLSID is missing or corrupt.
+
+0x80110412
+
+COMADMIN_E_BADREGISTRYPROGID
+
+
+The component's programmatic ID is missing or corrupt.
+
+0x80110413
+
+COMADMIN_E_AUTHENTICATIONLEVEL
+
+
+Unable to set required authentication level for update request.
+
+0x80110414
+
+COMADMIN_E_USERPASSWDNOTVALID
+
+
+The identity or password set on the application is not valid.
+
+0x80110418
+
+COMADMIN_E_CLSIDORIIDMISMATCH
+
+
+Application file CLSIDs or instance identifiers (IIDs) do not match corresponding DLLs.
+
+0x80110419
+
+COMADMIN_E_REMOTEINTERFACE
+
+
+Interface information is either missing or changed.
+
+0x8011041A
+
+COMADMIN_E_DLLREGISTERSERVER
+
+
+DllRegisterServer failed on component install.
+
+0x8011041B
+
+COMADMIN_E_NOSERVERSHARE
+
+
+No server file share available.
+
+0x8011041D
+
+COMADMIN_E_DLLLOADFAILED
+
+
+DLL could not be loaded.
+
+0x8011041E
+
+COMADMIN_E_BADREGISTRYLIBID
+
+
+The registered TypeLib ID is not valid.
+
+0x8011041F
+
+COMADMIN_E_APPDIRNOTFOUND
+
+
+Application install directory not found.
+
+0x80110423
+
+COMADMIN_E_REGISTRARFAILED
+
+
+Errors occurred while in the component registrar.
+
+0x80110424
+
+COMADMIN_E_COMPFILE_DOESNOTEXIST
+
+
+The file does not exist.
+
+0x80110425
+
+COMADMIN_E_COMPFILE_LOADDLLFAIL
+
+
+The DLL could not be loaded.
+
+0x80110426
+
+COMADMIN_E_COMPFILE_GETCLASSOBJ
+
+
+GetClassObject failed in the DLL.
+
+0x80110427
+
+COMADMIN_E_COMPFILE_CLASSNOTAVAIL
+
+
+The DLL does not support the components listed in the TypeLib.
+
+0x80110428
+
+COMADMIN_E_COMPFILE_BADTLB
+
+
+The TypeLib could not be loaded.
+
+0x80110429
+
+COMADMIN_E_COMPFILE_NOTINSTALLABLE
+
+
+The file does not contain components or component information.
+
+0x8011042A
+
+COMADMIN_E_NOTCHANGEABLE
+
+
+Changes to this object and its subobjects have been disabled.
+
+0x8011042B
+
+COMADMIN_E_NOTDELETEABLE
+
+
+The delete function has been disabled for this object.
+
+0x8011042C
+
+COMADMIN_E_SESSION
+
+
+The server catalog version is not supported.
+
+0x8011042D
+
+COMADMIN_E_COMP_MOVE_LOCKED
+
+
+The component move was disallowed because the source or destination application is either a system application or currently locked against changes.
+
+0x8011042E
+
+COMADMIN_E_COMP_MOVE_BAD_DEST
+
+
+The component move failed because the destination application no longer exists.
+
+0x80110430
+
+COMADMIN_E_REGISTERTLB
+
+
+The system was unable to register the TypeLib.
+
+0x80110433
+
+COMADMIN_E_SYSTEMAPP
+
+
+This operation cannot be performed on the system application.
+
+0x80110434
+
+COMADMIN_E_COMPFILE_NOREGISTRAR
+
+
+The component registrar referenced in this file is not available.
+
+0x80110435
+
+COMADMIN_E_COREQCOMPINSTALLED
+
+
+A component in the same DLL is already installed.
+
+0x80110436
+
+COMADMIN_E_SERVICENOTINSTALLED
+
+
+The service is not installed.
+
+0x80110437
+
+COMADMIN_E_PROPERTYSAVEFAILED
+
+
+One or more property settings are either invalid or in conflict with each other.
+
+0x80110438
+
+COMADMIN_E_OBJECTEXISTS
+
+
+The object you are attempting to add or rename already exists.
+
+0x80110439
+
+COMADMIN_E_COMPONENTEXISTS
+
+
+The component already exists.
+
+0x8011043B
+
+COMADMIN_E_REGFILE_CORRUPT
+
+
+The registration file is corrupt.
+
+0x8011043C
+
+COMADMIN_E_PROPERTY_OVERFLOW
+
+
+The property value is too large.
+
+0x8011043E
+
+COMADMIN_E_NOTINREGISTRY
+
+
+Object was not found in registry.
+
+0x8011043F
+
+COMADMIN_E_OBJECTNOTPOOLABLE
+
+
+This object cannot be pooled.
+
+0x80110446
+
+COMADMIN_E_APPLID_MATCHES_CLSID
+
+
+A CLSID with the same GUID as the new application ID is already installed on this machine.
+
+0x80110447
+
+COMADMIN_E_ROLE_DOES_NOT_EXIST
+
+
+A role assigned to a component, interface, or method did not exist in the application.
+
+0x80110448
+
+COMADMIN_E_START_APP_NEEDS_COMPONENTS
+
+
+You must have components in an application to start the application.
+
+0x80110449
+
+COMADMIN_E_REQUIRES_DIFFERENT_PLATFORM
+
+
+This operation is not enabled on this platform.
+
+0x8011044A
+
+COMADMIN_E_CAN_NOT_EXPORT_APP_PROXY
+
+
+Application proxy is not exportable.
+
+0x8011044B
+
+COMADMIN_E_CAN_NOT_START_APP
+
+
+Failed to start application because it is either a library application or an application proxy.
+
+0x8011044C
+
+COMADMIN_E_CAN_NOT_EXPORT_SYS_APP
+
+
+System application is not exportable.
+
+0x8011044D
+
+COMADMIN_E_CANT_SUBSCRIBE_TO_COMPONENT
+
+
+Cannot subscribe to this component (the component might have been imported).
+
+0x8011044E
+
+COMADMIN_E_EVENTCLASS_CANT_BE_SUBSCRIBER
+
+
+An event class cannot also be a subscriber component.
+
+0x8011044F
+
+COMADMIN_E_LIB_APP_PROXY_INCOMPATIBLE
+
+
+Library applications and application proxies are incompatible.
+
+0x80110450
+
+COMADMIN_E_BASE_PARTITION_ONLY
+
+
+This function is valid for the base partition only.
+
+0x80110451
+
+COMADMIN_E_START_APP_DISABLED
+
+
+You cannot start an application that has been disabled.
+
+0x80110457
+
+COMADMIN_E_CAT_DUPLICATE_PARTITION_NAME
+
+
+The specified partition name is already in use on this computer.
+
+0x80110458
+
+COMADMIN_E_CAT_INVALID_PARTITION_NAME
+
+
+The specified partition name is invalid. Check that the name contains at least one visible character.
+
+0x80110459
+
+COMADMIN_E_CAT_PARTITION_IN_USE
+
+
+The partition cannot be deleted because it is the default partition for one or more users.
+
+0x8011045A
+
+COMADMIN_E_FILE_PARTITION_DUPLICATE_FILES
+
+
+The partition cannot be exported because one or more components in the partition have the same file name.
+
+0x8011045B
+
+COMADMIN_E_CAT_IMPORTED_COMPONENTS_NOT_ALLOWED
+
+
+Applications that contain one or more imported components cannot be installed into a nonbase partition.
+
+0x8011045C
+
+COMADMIN_E_AMBIGUOUS_APPLICATION_NAME
+
+
+The application name is not unique and cannot be resolved to an application ID.
+
+0x8011045D
+
+COMADMIN_E_AMBIGUOUS_PARTITION_NAME
+
+
+The partition name is not unique and cannot be resolved to a partition ID.
+
+0x80110472
+
+COMADMIN_E_REGDB_NOTINITIALIZED
+
+
+The COM+ registry database has not been initialized.
+
+0x80110473
+
+COMADMIN_E_REGDB_NOTOPEN
+
+
+The COM+ registry database is not open.
+
+0x80110474
+
+COMADMIN_E_REGDB_SYSTEMERR
+
+
+The COM+ registry database detected a system error.
+
+0x80110475
+
+COMADMIN_E_REGDB_ALREADYRUNNING
+
+
+The COM+ registry database is already running.
+
+0x80110480
+
+COMADMIN_E_MIG_VERSIONNOTSUPPORTED
+
+
+This version of the COM+ registry database cannot be migrated.
+
+0x80110481
+
+COMADMIN_E_MIG_SCHEMANOTFOUND
+
+
+The schema version to be migrated could not be found in the COM+ registry database.
+
+0x80110482
+
+COMADMIN_E_CAT_BITNESSMISMATCH
+
+
+There was a type mismatch between binaries.
+
+0x80110483
+
+COMADMIN_E_CAT_UNACCEPTABLEBITNESS
+
+
+A binary of unknown or invalid type was provided.
+
+0x80110484
+
+COMADMIN_E_CAT_WRONGAPPBITNESS
+
+
+There was a type mismatch between a binary and an application.
+
+0x80110485
+
+COMADMIN_E_CAT_PAUSE_RESUME_NOT_SUPPORTED
+
+
+The application cannot be paused or resumed.
+
+0x80110486
+
+COMADMIN_E_CAT_SERVERFAULT
+
+
+The COM+ catalog server threw an exception during execution.
+
+0x80110600
+
+COMQC_E_APPLICATION_NOT_QUEUED
+
+
+Only COM+ applications marked "queued" can be invoked using the "queue" moniker.
+
+0x80110601
+
+COMQC_E_NO_QUEUEABLE_INTERFACES
+
+
+At least one interface must be marked "queued" to create a queued component instance with the "queue" moniker.
+
+0x80110602
+
+COMQC_E_QUEUING_SERVICE_NOT_AVAILABLE
+
+
+Message Queuing is required for the requested operation and is not installed.
+
+0x80110603
+
+COMQC_E_NO_IPERSISTSTREAM
+
+
+Unable to marshal an interface that does not support IPersistStream.
+
+0x80110604
+
+COMQC_E_BAD_MESSAGE
+
+
+The message is improperly formatted or was damaged in transit.
+
+0x80110605
+
+COMQC_E_UNAUTHENTICATED
+
+
+An unauthenticated message was received by an application that accepts only authenticated messages.
+
+0x80110606
+
+COMQC_E_UNTRUSTED_ENQUEUER
+
+
+The message was requeued or moved by a user not in the QC Trusted User "role".
+
+0x80110701
+
+MSDTC_E_DUPLICATE_RESOURCE
+
+
+Cannot create a duplicate resource of type Distributed Transaction Coordinator.
+
+0x80110808
+
+COMADMIN_E_OBJECT_PARENT_MISSING
+
+
+One of the objects being inserted or updated does not belong to a valid parent collection.
+
+0x80110809
+
+COMADMIN_E_OBJECT_DOES_NOT_EXIST
+
+
+One of the specified objects cannot be found.
+
+0x8011080A
+
+COMADMIN_E_APP_NOT_RUNNING
+
+
+The specified application is not currently running.
+
+0x8011080B
+
+COMADMIN_E_INVALID_PARTITION
+
+
+The partitions specified are not valid.
+
+0x8011080D
+
+COMADMIN_E_SVCAPP_NOT_POOLABLE_OR_RECYCLABLE
+
+
+COM+ applications that run as Windows NT service cannot be pooled or recycled.
+
+0x8011080E
+
+COMADMIN_E_USER_IN_SET
+
+
+One or more users are already assigned to a local partition set.
+
+0x8011080F
+
+COMADMIN_E_CANTRECYCLELIBRARYAPPS
+
+
+Library applications cannot be recycled.
+
+0x80110811
+
+COMADMIN_E_CANTRECYCLESERVICEAPPS
+
+
+Applications running as Windows NT services cannot be recycled.
+
+0x80110812
+
+COMADMIN_E_PROCESSALREADYRECYCLED
+
+
+The process has already been recycled.
+
+0x80110813
+
+COMADMIN_E_PAUSEDPROCESSMAYNOTBERECYCLED
+
+
+A paused process cannot be recycled.
+
+0x80110814
+
+COMADMIN_E_CANTMAKEINPROCSERVICE
+
+
+Library applications cannot be Windows NT services.
+
+0x80110815
+
+COMADMIN_E_PROGIDINUSEBYCLSID
+
+
+The ProgID provided to the copy operation is invalid. The ProgID is in use by another registered CLSID.
+
+0x80110816
+
+COMADMIN_E_DEFAULT_PARTITION_NOT_IN_SET
+
+
+The partition specified as the default is not a member of the partition set.
+
+0x80110817
+
+COMADMIN_E_RECYCLEDPROCESSMAYNOTBEPAUSED
+
+
+A recycled process cannot be paused.
+
+0x80110818
+
+COMADMIN_E_PARTITION_ACCESSDENIED
+
+
+Access to the specified partition is denied.
+
+0x80110819
+
+COMADMIN_E_PARTITION_MSI_ONLY
+
+
+Only application files (*.msi files) can be installed into partitions.
+
+0x8011081A
+
+COMADMIN_E_LEGACYCOMPS_NOT_ALLOWED_IN_1_0_FORMAT
+
+
+Applications containing one or more legacy components cannot be exported to 1.0 format.
+
+0x8011081B
+
+COMADMIN_E_LEGACYCOMPS_NOT_ALLOWED_IN_NONBASE_PARTITIONS
+
+
+Legacy components cannot exist in nonbase partitions.
+
+0x8011081C
+
+COMADMIN_E_COMP_MOVE_SOURCE
+
+
+A component cannot be moved (or copied) from the System Application, an application proxy, or a nonchangeable application.
+
+0x8011081D
+
+COMADMIN_E_COMP_MOVE_DEST
+
+
+A component cannot be moved (or copied) to the System Application, an application proxy or a nonchangeable application.
+
+0x8011081E
+
+COMADMIN_E_COMP_MOVE_PRIVATE
+
+
+A private component cannot be moved (or copied) to a library application or to the base partition.
+
+0x8011081F
+
+COMADMIN_E_BASEPARTITION_REQUIRED_IN_SET
+
+
+The Base Application Partition exists in all partition sets and cannot be removed.
+
+0x80110820
+
+COMADMIN_E_CANNOT_ALIAS_EVENTCLASS
+
+
+Alas, Event Class components cannot be aliased.
+
+0x80110821
+
+COMADMIN_E_PRIVATE_ACCESSDENIED
+
+
+Access is denied because the component is private.
+
+0x80110822
+
+COMADMIN_E_SAFERINVALID
+
+
+The specified SAFER level is invalid.
+
+0x80110823
+
+COMADMIN_E_REGISTRY_ACCESSDENIED
+
+
+The specified user cannot write to the system registry.
+
+0x80110824
+
+COMADMIN_E_PARTITIONS_DISABLED
+
+
+COM+ partitions are currently disabled.
+
+0x801F0001
+
+ERROR_FLT_NO_HANDLER_DEFINED
+
+
+A handler was not defined by the filter for this operation.
+
+0x801F0002
+
+ERROR_FLT_CONTEXT_ALREADY_DEFINED
+
+
+A context is already defined for this object.
+
+0x801F0003
+
+ERROR_FLT_INVALID_ASYNCHRONOUS_REQUEST
+
+
+Asynchronous requests are not valid for this operation.
+
+0x801F0004
+
+ERROR_FLT_DISALLOW_FAST_IO
+
+
+Disallow the Fast IO path for this operation.
+
+0x801F0005
+
+ERROR_FLT_INVALID_NAME_REQUEST
+
+
+An invalid name request was made. The name requested cannot be retrieved at this time.
+
+0x801F0006
+
+ERROR_FLT_NOT_SAFE_TO_POST_OPERATION
+
+
+Posting this operation to a worker thread for further processing is not safe at this time because it could lead to a system deadlock.
+
+0x801F0007
+
+ERROR_FLT_NOT_INITIALIZED
+
+
+The Filter Manager was not initialized when a filter tried to register. Be sure that the Filter Manager is being loaded as a driver.
+
+0x801F0008
+
+ERROR_FLT_FILTER_NOT_READY
+
+
+The filter is not ready for attachment to volumes because it has not finished initializing (FltStartFiltering has not been called).
+
+0x801F0009
+
+ERROR_FLT_POST_OPERATION_CLEANUP
+
+
+The filter must clean up any operation-specific context at this time because it is being removed from the system before the operation is completed by the lower drivers.
+
+0x801F000A
+
+ERROR_FLT_INTERNAL_ERROR
+
+
+The Filter Manager had an internal error from which it cannot recover; therefore, the operation has been failed. This is usually the result of a filter returning an invalid value from a preoperation callback.
+
+0x801F000B
+
+ERROR_FLT_DELETING_OBJECT
+
+
+The object specified for this action is in the process of being deleted; therefore, the action requested cannot be completed at this time.
+
+0x801F000C
+
+ERROR_FLT_MUST_BE_NONPAGED_POOL
+
+
+Nonpaged pool must be used for this type of context.
+
+0x801F000D
+
+ERROR_FLT_DUPLICATE_ENTRY
+
+
+A duplicate handler definition has been provided for an operation.
+
+0x801F000E
+
+ERROR_FLT_CBDQ_DISABLED
+
+
+The callback data queue has been disabled.
+
+0x801F000F
+
+ERROR_FLT_DO_NOT_ATTACH
+
+
+Do not attach the filter to the volume at this time.
+
+0x801F0010
+
+ERROR_FLT_DO_NOT_DETACH
+
+
+Do not detach the filter from the volume at this time.
+
+0x801F0011
+
+ERROR_FLT_INSTANCE_ALTITUDE_COLLISION
+
+
+An instance already exists at this altitude on the volume specified.
+
+0x801F0012
+
+ERROR_FLT_INSTANCE_NAME_COLLISION
+
+
+An instance already exists with this name on the volume specified.
+
+0x801F0013
+
+ERROR_FLT_FILTER_NOT_FOUND
+
+
+The system could not find the filter specified.
+
+0x801F0014
+
+ERROR_FLT_VOLUME_NOT_FOUND
+
+
+The system could not find the volume specified.
+
+0x801F0015
+
+ERROR_FLT_INSTANCE_NOT_FOUND
+
+
+The system could not find the instance specified.
+
+0x801F0016
+
+ERROR_FLT_CONTEXT_ALLOCATION_NOT_FOUND
+
+
+No registered context allocation definition was found for the given request.
+
+0x801F0017
+
+ERROR_FLT_INVALID_CONTEXT_REGISTRATION
+
+
+An invalid parameter was specified during context registration.
+
+0x801F0018
+
+ERROR_FLT_NAME_CACHE_MISS
+
+
+The name requested was not found in the Filter Manager name cache and could not be retrieved from the file system.
+
+0x801F0019
+
+ERROR_FLT_NO_DEVICE_OBJECT
+
+
+The requested device object does not exist for the given volume.
+
+0x801F001A
+
+ERROR_FLT_VOLUME_ALREADY_MOUNTED
+
+
+The specified volume is already mounted.
+
+0x801F001B
+
+ERROR_FLT_ALREADY_ENLISTED
+
+
+The specified Transaction Context is already enlisted in a transaction.
+
+0x801F001C
+
+ERROR_FLT_CONTEXT_ALREADY_LINKED
+
+
+The specified context is already attached to another object.
+
+0x801F0020
+
+ERROR_FLT_NO_WAITER_FOR_REPLY
+
+
+No waiter is present for the filter's reply to this message.
+
+0x80260001
+
+ERROR_HUNG_DISPLAY_DRIVER_THREAD
+
+
+{Display Driver Stopped Responding} The %hs display driver has stopped working normally. Save your work and reboot the system to restore full display functionality. The next time you reboot the machine a dialog will be displayed giving you a chance to report this failure to Microsoft.
+
+0x80261001
+
+ERROR_MONITOR_NO_DESCRIPTOR
+
+
+Monitor descriptor could not be obtained.
+
+0x80261002
+
+ERROR_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT
+
+
+Format of the obtained monitor descriptor is not supported by this release.
+
+0x80263001
+
+DWM_E_COMPOSITIONDISABLED
+
+
+{Desktop Composition is Disabled} The operation could not be completed because desktop composition is disabled.
+
+0x80263002
+
+DWM_E_REMOTING_NOT_SUPPORTED
+
+
+{Some Desktop Composition APIs Are Not Supported While Remoting} Some desktop composition APIs are not supported while remoting. The operation is not supported while running in a remote session.
+
+0x80263003
+
+DWM_E_NO_REDIRECTION_SURFACE_AVAILABLE
+
+
+{No DWM Redirection Surface is Available} The Desktop Window Manager (DWM) was unable to provide a redirection surface to complete the DirectX present.
+
+0x80263004
+
+DWM_E_NOT_QUEUING_PRESENTS
+
+
+{DWM Is Not Queuing Presents for the Specified Window} The window specified is not currently using queued presents.
+
+0x80280000
+
+TPM_E_ERROR_MASK
+
+
+This is an error mask to convert Trusted Platform Module (TPM) hardware errors to Win32 errors.
+
+0x80280001
+
+TPM_E_AUTHFAIL
+
+
+Authentication failed.
+
+0x80280002
+
+TPM_E_BADINDEX
+
+
+The index to a Platform Configuration Register (PCR), DIR, or other register is incorrect.
+
+0x80280003
+
+TPM_E_BAD_PARAMETER
+
+
+One or more parameters are bad.
+
+0x80280004
+
+TPM_E_AUDITFAILURE
+
+
+An operation completed successfully but the auditing of that operation failed.
+
+0x80280005
+
+TPM_E_CLEAR_DISABLED
+
+
+The clear disable flag is set and all clear operations now require physical access.
+
+0x80280006
+
+TPM_E_DEACTIVATED
+
+
+The TPM is deactivated.
+
+0x80280007
+
+TPM_E_DISABLED
+
+
+The TPM is disabled.
+
+0x80280008
+
+TPM_E_DISABLED_CMD
+
+
+The target command has been disabled.
+
+0x80280009
+
+TPM_E_FAIL
+
+
+The operation failed.
+
+0x8028000A
+
+TPM_E_BAD_ORDINAL
+
+
+The ordinal was unknown or inconsistent.
+
+0x8028000B
+
+TPM_E_INSTALL_DISABLED
+
+
+The ability to install an owner is disabled.
+
+0x8028000C
+
+TPM_E_INVALID_KEYHANDLE
+
+
+The key handle cannot be interpreted.
+
+0x8028000D
+
+TPM_E_KEYNOTFOUND
+
+
+The key handle points to an invalid key.
+
+0x8028000E
+
+TPM_E_INAPPROPRIATE_ENC
+
+
+Unacceptable encryption scheme.
+
+0x8028000F
+
+TPM_E_MIGRATEFAIL
+
+
+Migration authorization failed.
+
+0x80280010
+
+TPM_E_INVALID_PCR_INFO
+
+
+PCR information could not be interpreted.
+
+0x80280011
+
+TPM_E_NOSPACE
+
+
+No room to load key.
+
+0x80280012
+
+TPM_E_NOSRK
+
+
+There is no storage root key (SRK) set.
+
+0x80280013
+
+TPM_E_NOTSEALED_BLOB
+
+
+An encrypted blob is invalid or was not created by this TPM.
+
+0x80280014
+
+TPM_E_OWNER_SET
+
+
+There is already an owner.
+
+0x80280015
+
+TPM_E_RESOURCES
+
+
+The TPM has insufficient internal resources to perform the requested action.
+
+0x80280016
+
+TPM_E_SHORTRANDOM
+
+
+A random string was too short.
+
+0x80280017
+
+TPM_E_SIZE
+
+
+The TPM does not have the space to perform the operation.
+
+0x80280018
+
+TPM_E_WRONGPCRVAL
+
+
+The named PCR value does not match the current PCR value.
+
+0x80280019
+
+TPM_E_BAD_PARAM_SIZE
+
+
+The paramSize argument to the command has the incorrect value.
+
+0x8028001A
+
+TPM_E_SHA_THREAD
+
+
+There is no existing SHA-1 thread.
+
+0x8028001B
+
+TPM_E_SHA_ERROR
+
+
+The calculation is unable to proceed because the existing SHA-1 thread has already encountered an error.
+
+0x8028001C
+
+TPM_E_FAILEDSELFTEST
+
+
+Self-test has failed and the TPM has shut down.
+
+0x8028001D
+
+TPM_E_AUTH2FAIL
+
+
+The authorization for the second key in a two-key function failed authorization.
+
+0x8028001E
+
+TPM_E_BADTAG
+
+
+The tag value sent to for a command is invalid.
+
+0x8028001F
+
+TPM_E_IOERROR
+
+
+An I/O error occurred transmitting information to the TPM.
+
+0x80280020
+
+TPM_E_ENCRYPT_ERROR
+
+
+The encryption process had a problem.
+
+0x80280021
+
+TPM_E_DECRYPT_ERROR
+
+
+The decryption process did not complete.
+
+0x80280022
+
+TPM_E_INVALID_AUTHHANDLE
+
+
+An invalid handle was used.
+
+0x80280023
+
+TPM_E_NO_ENDORSEMENT
+
+
+The TPM does not have an endorsement key (EK) installed.
+
+0x80280024
+
+TPM_E_INVALID_KEYUSAGE
+
+
+The usage of a key is not allowed.
+
+0x80280025
+
+TPM_E_WRONG_ENTITYTYPE
+
+
+The submitted entity type is not allowed.
+
+0x80280026
+
+TPM_E_INVALID_POSTINIT
+
+
+The command was received in the wrong sequence relative to TPM_Init and a subsequent TPM_Startup.
+
+0x80280027
+
+TPM_E_INAPPROPRIATE_SIG
+
+
+Signed data cannot include additional DER information.
+
+0x80280028
+
+TPM_E_BAD_KEY_PROPERTY
+
+
+The key properties in TPM_KEY_PARMs are not supported by this TPM.
+
+0x80280029
+
+TPM_E_BAD_MIGRATION
+
+
+The migration properties of this key are incorrect.
+
+0x8028002A
+
+TPM_E_BAD_SCHEME
+
+
+The signature or encryption scheme for this key is incorrect or not permitted in this situation.
+
+0x8028002B
+
+TPM_E_BAD_DATASIZE
+
+
+The size of the data (or blob) parameter is bad or inconsistent with the referenced key.
+
+0x8028002C
+
+TPM_E_BAD_MODE
+
+
+A mode parameter is bad, such as capArea or subCapArea for TPM_GetCapability, physicalPresence parameter for TPM_PhysicalPresence, or migrationType for TPM_CreateMigrationBlob.
+
+0x8028002D
+
+TPM_E_BAD_PRESENCE
+
+
+Either the physicalPresence or physicalPresenceLock bits have the wrong value.
+
+0x8028002E
+
+TPM_E_BAD_VERSION
+
+
+The TPM cannot perform this version of the capability.
+
+0x8028002F
+
+TPM_E_NO_WRAP_TRANSPORT
+
+
+The TPM does not allow for wrapped transport sessions.
+
+0x80280030
+
+TPM_E_AUDITFAIL_UNSUCCESSFUL
+
+
+TPM audit construction failed and the underlying command was returning a failure code also.
+
+0x80280031
+
+TPM_E_AUDITFAIL_SUCCESSFUL
+
+
+TPM audit construction failed and the underlying command was returning success.
+
+0x80280032
+
+TPM_E_NOTRESETABLE
+
+
+Attempt to reset a PCR that does not have the resettable attribute.
+
+0x80280033
+
+TPM_E_NOTLOCAL
+
+
+Attempt to reset a PCR register that requires locality and the locality modifier not part of command transport.
+
+0x80280034
+
+TPM_E_BAD_TYPE
+
+
+Make identity blob not properly typed.
+
+0x80280035
+
+TPM_E_INVALID_RESOURCE
+
+
+When saving context identified resource type does not match actual resource.
+
+0x80280036
+
+TPM_E_NOTFIPS
+
+
+The TPM is attempting to execute a command only available when in Federal Information Processing Standards (FIPS) mode.
+
+0x80280037
+
+TPM_E_INVALID_FAMILY
+
+
+The command is attempting to use an invalid family ID.
+
+0x80280038
+
+TPM_E_NO_NV_PERMISSION
+
+
+The permission to manipulate the NV storage is not available.
+
+0x80280039
+
+TPM_E_REQUIRES_SIGN
+
+
+The operation requires a signed command.
+
+0x8028003A
+
+TPM_E_KEY_NOTSUPPORTED
+
+
+Wrong operation to load an NV key.
+
+0x8028003B
+
+TPM_E_AUTH_CONFLICT
+
+
+NV_LoadKey blob requires both owner and blob authorization.
+
+0x8028003C
+
+TPM_E_AREA_LOCKED
+
+
+The NV area is locked and not writable.
+
+0x8028003D
+
+TPM_E_BAD_LOCALITY
+
+
+The locality is incorrect for the attempted operation.
+
+0x8028003E
+
+TPM_E_READ_ONLY
+
+
+The NV area is read-only and cannot be written to.
+
+0x8028003F
+
+TPM_E_PER_NOWRITE
+
+
+There is no protection on the write to the NV area.
+
+0x80280040
+
+TPM_E_FAMILYCOUNT
+
+
+The family count value does not match.
+
+0x80280041
+
+TPM_E_WRITE_LOCKED
+
+
+The NV area has already been written to.
+
+0x80280042
+
+TPM_E_BAD_ATTRIBUTES
+
+
+The NV area attributes conflict.
+
+0x80280043
+
+TPM_E_INVALID_STRUCTURE
+
+
+The structure tag and version are invalid or inconsistent.
+
+0x80280044
+
+TPM_E_KEY_OWNER_CONTROL
+
+
+The key is under control of the TPM owner and can only be evicted by the TPM owner.
+
+0x80280045
+
+TPM_E_BAD_COUNTER
+
+
+The counter handle is incorrect.
+
+0x80280046
+
+TPM_E_NOT_FULLWRITE
+
+
+The write is not a complete write of the area.
+
+0x80280047
+
+TPM_E_CONTEXT_GAP
+
+
+The gap between saved context counts is too large.
+
+0x80280048
+
+TPM_E_MAXNVWRITES
+
+
+The maximum number of NV writes without an owner has been exceeded.
+
+0x80280049
+
+TPM_E_NOOPERATOR
+
+
+No operator AuthData value is set.
+
+0x8028004A
+
+TPM_E_RESOURCEMISSING
+
+
+The resource pointed to by context is not loaded.
+
+0x8028004B
+
+TPM_E_DELEGATE_LOCK
+
+
+The delegate administration is locked.
+
+0x8028004C
+
+TPM_E_DELEGATE_FAMILY
+
+
+Attempt to manage a family other then the delegated family.
+
+0x8028004D
+
+TPM_E_DELEGATE_ADMIN
+
+
+Delegation table management not enabled.
+
+0x8028004E
+
+TPM_E_TRANSPORT_NOTEXCLUSIVE
+
+
+There was a command executed outside an exclusive transport session.
+
+0x8028004F
+
+TPM_E_OWNER_CONTROL
+
+
+Attempt to context save an owner evict controlled key.
+
+0x80280050
+
+TPM_E_DAA_RESOURCES
+
+
+The DAA command has no resources available to execute the command.
+
+0x80280051
+
+TPM_E_DAA_INPUT_DATA0
+
+
+The consistency check on DAA parameter inputData0 has failed.
+
+0x80280052
+
+TPM_E_DAA_INPUT_DATA1
+
+
+The consistency check on DAA parameter inputData1 has failed.
+
+0x80280053
+
+TPM_E_DAA_ISSUER_SETTINGS
+
+
+The consistency check on DAA_issuerSettings has failed.
+
+0x80280054
+
+TPM_E_DAA_TPM_SETTINGS
+
+
+The consistency check on DAA_tpmSpecific has failed.
+
+0x80280055
+
+TPM_E_DAA_STAGE
+
+
+The atomic process indicated by the submitted DAA command is not the expected process.
+
+0x80280056
+
+TPM_E_DAA_ISSUER_VALIDITY
+
+
+The issuer's validity check has detected an inconsistency.
+
+0x80280057
+
+TPM_E_DAA_WRONG_W
+
+
+The consistency check on w has failed.
+
+0x80280058
+
+TPM_E_BAD_HANDLE
+
+
+The handle is incorrect.
+
+0x80280059
+
+TPM_E_BAD_DELEGATE
+
+
+Delegation is not correct.
+
+0x8028005A
+
+TPM_E_BADCONTEXT
+
+
+The context blob is invalid.
+
+0x8028005B
+
+TPM_E_TOOMANYCONTEXTS
+
+
+Too many contexts held by the TPM.
+
+0x8028005C
+
+TPM_E_MA_TICKET_SIGNATURE
+
+
+Migration authority signature validation failure.
+
+0x8028005D
+
+TPM_E_MA_DESTINATION
+
+
+Migration destination not authenticated.
+
+0x8028005E
+
+TPM_E_MA_SOURCE
+
+
+Migration source incorrect.
+
+0x8028005F
+
+TPM_E_MA_AUTHORITY
+
+
+Incorrect migration authority.
+
+0x80280061
+
+TPM_E_PERMANENTEK
+
+
+Attempt to revoke the EK and the EK is not revocable.
+
+0x80280062
+
+TPM_E_BAD_SIGNATURE
+
+
+Bad signature of CMK ticket.
+
+0x80280063
+
+TPM_E_NOCONTEXTSPACE
+
+
+There is no room in the context list for additional contexts.
+
+0x80280400
+
+TPM_E_COMMAND_BLOCKED
+
+
+The command was blocked.
+
+0x80280401
+
+TPM_E_INVALID_HANDLE
+
+
+The specified handle was not found.
+
+0x80280402
+
+TPM_E_DUPLICATE_VHANDLE
+
+
+The TPM returned a duplicate handle and the command needs to be resubmitted.
+
+0x80280403
+
+TPM_E_EMBEDDED_COMMAND_BLOCKED
+
+
+The command within the transport was blocked.
+
+0x80280404
+
+TPM_E_EMBEDDED_COMMAND_UNSUPPORTED
+
+
+The command within the transport is not supported.
+
+0x80280800
+
+TPM_E_RETRY
+
+
+The TPM is too busy to respond to the command immediately, but the command could be resubmitted at a later time.
+
+0x80280801
+
+TPM_E_NEEDS_SELFTEST
+
+
+SelfTestFull has not been run.
+
+0x80280802
+
+TPM_E_DOING_SELFTEST
+
+
+The TPM is currently executing a full self-test.
+
+0x80280803
+
+TPM_E_DEFEND_LOCK_RUNNING
+
+
+The TPM is defending against dictionary attacks and is in a time-out period.
+
+0x80284001
+
+TBS_E_INTERNAL_ERROR
+
+
+An internal software error has been detected.
+
+0x80284002
+
+TBS_E_BAD_PARAMETER
+
+
+One or more input parameters are bad.
+
+0x80284003
+
+TBS_E_INVALID_OUTPUT_POINTER
+
+
+A specified output pointer is bad.
+
+0x80284004
+
+TBS_E_INVALID_CONTEXT
+
+
+The specified context handle does not refer to a valid context.
+
+0x80284005
+
+TBS_E_INSUFFICIENT_BUFFER
+
+
+A specified output buffer is too small.
+
+0x80284006
+
+TBS_E_IOERROR
+
+
+An error occurred while communicating with the TPM.
+
+0x80284007
+
+TBS_E_INVALID_CONTEXT_PARAM
+
+
+One or more context parameters are invalid.
+
+0x80284008
+
+TBS_E_SERVICE_NOT_RUNNING
+
+
+The TPM Base Services (TBS) is not running and could not be started.
+
+0x80284009
+
+TBS_E_TOO_MANY_TBS_CONTEXTS
+
+
+A new context could not be created because there are too many open contexts.
+
+0x8028400A
+
+TBS_E_TOO_MANY_RESOURCES
+
+
+A new virtual resource could not be created because there are too many open virtual resources.
+
+0x8028400B
+
+TBS_E_SERVICE_START_PENDING
+
+
+The TBS service has been started but is not yet running.
+
+0x8028400C
+
+TBS_E_PPI_NOT_SUPPORTED
+
+
+The physical presence interface is not supported.
+
+0x8028400D
+
+TBS_E_COMMAND_CANCELED
+
+
+The command was canceled.
+
+0x8028400E
+
+TBS_E_BUFFER_TOO_LARGE
+
+
+The input or output buffer is too large.
+
+0x80290100
+
+TPMAPI_E_INVALID_STATE
+
+
+The command buffer is not in the correct state.
+
+0x80290101
+
+TPMAPI_E_NOT_ENOUGH_DATA
+
+
+The command buffer does not contain enough data to satisfy the request.
+
+0x80290102
+
+TPMAPI_E_TOO_MUCH_DATA
+
+
+The command buffer cannot contain any more data.
+
+0x80290103
+
+TPMAPI_E_INVALID_OUTPUT_POINTER
+
+
+One or more output parameters was null or invalid.
+
+0x80290104
+
+TPMAPI_E_INVALID_PARAMETER
+
+
+One or more input parameters are invalid.
+
+0x80290105
+
+TPMAPI_E_OUT_OF_MEMORY
+
+
+Not enough memory was available to satisfy the request.
+
+0x80290106
+
+TPMAPI_E_BUFFER_TOO_SMALL
+
+
+The specified buffer was too small.
+
+0x80290107
+
+TPMAPI_E_INTERNAL_ERROR
+
+
+An internal error was detected.
+
+0x80290108
+
+TPMAPI_E_ACCESS_DENIED
+
+
+The caller does not have the appropriate rights to perform the requested operation.
+
+0x80290109
+
+TPMAPI_E_AUTHORIZATION_FAILED
+
+
+The specified authorization information was invalid.
+
+0x8029010A
+
+TPMAPI_E_INVALID_CONTEXT_HANDLE
+
+
+The specified context handle was not valid.
+
+0x8029010B
+
+TPMAPI_E_TBS_COMMUNICATION_ERROR
+
+
+An error occurred while communicating with the TBS.
+
+0x8029010C
+
+TPMAPI_E_TPM_COMMAND_ERROR
+
+
+The TPM returned an unexpected result.
+
+0x8029010D
+
+TPMAPI_E_MESSAGE_TOO_LARGE
+
+
+The message was too large for the encoding scheme.
+
+0x8029010E
+
+TPMAPI_E_INVALID_ENCODING
+
+
+The encoding in the binary large object (BLOB) was not recognized.
+
+0x8029010F
+
+TPMAPI_E_INVALID_KEY_SIZE
+
+
+The key size is not valid.
+
+0x80290110
+
+TPMAPI_E_ENCRYPTION_FAILED
+
+
+The encryption operation failed.
+
+0x80290111
+
+TPMAPI_E_INVALID_KEY_PARAMS
+
+
+The key parameters structure was not valid.
+
+0x80290112
+
+TPMAPI_E_INVALID_MIGRATION_AUTHORIZATION_BLOB
+
+
+The requested supplied data does not appear to be a valid migration authorization BLOB.
+
+0x80290113
+
+TPMAPI_E_INVALID_PCR_INDEX
+
+
+The specified PCR index was invalid.
+
+0x80290114
+
+TPMAPI_E_INVALID_DELEGATE_BLOB
+
+
+The data given does not appear to be a valid delegate BLOB.
+
+0x80290115
+
+TPMAPI_E_INVALID_CONTEXT_PARAMS
+
+
+One or more of the specified context parameters was not valid.
+
+0x80290116
+
+TPMAPI_E_INVALID_KEY_BLOB
+
+
+The data given does not appear to be a valid key BLOB.
+
+0x80290117
+
+TPMAPI_E_INVALID_PCR_DATA
+
+
+The specified PCR data was invalid.
+
+0x80290118
+
+TPMAPI_E_INVALID_OWNER_AUTH
+
+
+The format of the owner authorization data was invalid.
+
+0x80290200
+
+TBSIMP_E_BUFFER_TOO_SMALL
+
+
+The specified buffer was too small.
+
+0x80290201
+
+TBSIMP_E_CLEANUP_FAILED
+
+
+The context could not be cleaned up.
+
+0x80290202
+
+TBSIMP_E_INVALID_CONTEXT_HANDLE
+
+
+The specified context handle is invalid.
+
+0x80290203
+
+TBSIMP_E_INVALID_CONTEXT_PARAM
+
+
+An invalid context parameter was specified.
+
+0x80290204
+
+TBSIMP_E_TPM_ERROR
+
+
+An error occurred while communicating with the TPM.
+
+0x80290205
+
+TBSIMP_E_HASH_BAD_KEY
+
+
+No entry with the specified key was found.
+
+0x80290206
+
+TBSIMP_E_DUPLICATE_VHANDLE
+
+
+The specified virtual handle matches a virtual handle already in use.
+
+0x80290207
+
+TBSIMP_E_INVALID_OUTPUT_POINTER
+
+
+The pointer to the returned handle location was null or invalid.
+
+0x80290208
+
+TBSIMP_E_INVALID_PARAMETER
+
+
+One or more parameters are invalid.
+
+0x80290209
+
+TBSIMP_E_RPC_INIT_FAILED
+
+
+The RPC subsystem could not be initialized.
+
+0x8029020A
+
+TBSIMP_E_SCHEDULER_NOT_RUNNING
+
+
+The TBS scheduler is not running.
+
+0x8029020B
+
+TBSIMP_E_COMMAND_CANCELED
+
+
+The command was canceled.
+
+0x8029020C
+
+TBSIMP_E_OUT_OF_MEMORY
+
+
+There was not enough memory to fulfill the request.
+
+0x8029020D
+
+TBSIMP_E_LIST_NO_MORE_ITEMS
+
+
+The specified list is empty, or the iteration has reached the end of the list.
+
+0x8029020E
+
+TBSIMP_E_LIST_NOT_FOUND
+
+
+The specified item was not found in the list.
+
+0x8029020F
+
+TBSIMP_E_NOT_ENOUGH_SPACE
+
+
+The TPM does not have enough space to load the requested resource.
+
+0x80290210
+
+TBSIMP_E_NOT_ENOUGH_TPM_CONTEXTS
+
+
+There are too many TPM contexts in use.
+
+0x80290211
+
+TBSIMP_E_COMMAND_FAILED
+
+
+The TPM command failed.
+
+0x80290212
+
+TBSIMP_E_UNKNOWN_ORDINAL
+
+
+The TBS does not recognize the specified ordinal.
+
+0x80290213
+
+TBSIMP_E_RESOURCE_EXPIRED
+
+
+The requested resource is no longer available.
+
+0x80290214
+
+TBSIMP_E_INVALID_RESOURCE
+
+
+The resource type did not match.
+
+0x80290215
+
+TBSIMP_E_NOTHING_TO_UNLOAD
+
+
+No resources can be unloaded.
+
+0x80290216
+
+TBSIMP_E_HASH_TABLE_FULL
+
+
+No new entries can be added to the hash table.
+
+0x80290217
+
+TBSIMP_E_TOO_MANY_TBS_CONTEXTS
+
+
+A new TBS context could not be created because there are too many open contexts.
+
+0x80290218
+
+TBSIMP_E_TOO_MANY_RESOURCES
+
+
+A new virtual resource could not be created because there are too many open virtual resources.
+
+0x80290219
+
+TBSIMP_E_PPI_NOT_SUPPORTED
+
+
+The physical presence interface is not supported.
+
+0x8029021A
+
+TBSIMP_E_TPM_INCOMPATIBLE
+
+
+TBS is not compatible with the version of TPM found on the system.
+
+0x80290300
+
+TPM_E_PPI_ACPI_FAILURE
+
+
+A general error was detected when attempting to acquire the BIOS response to a physical presence command.
+
+0x80290301
+
+TPM_E_PPI_USER_ABORT
+
+
+The user failed to confirm the TPM operation request.
+
+0x80290302
+
+TPM_E_PPI_BIOS_FAILURE
+
+
+The BIOS failure prevented the successful execution of the requested TPM operation (for example, invalid TPM operation request, BIOS communication error with the TPM).
+
+0x80290303
+
+TPM_E_PPI_NOT_SUPPORTED
+
+
+The BIOS does not support the physical presence interface.
+
+0x80300002
+
+PLA_E_DCS_NOT_FOUND
+
+
+A Data Collector Set was not found.
+
+0x80300045
+
+PLA_E_TOO_MANY_FOLDERS
+
+
+Unable to start Data Collector Set because there are too many folders.
+
+0x80300070
+
+PLA_E_NO_MIN_DISK
+
+
+Not enough free disk space to start Data Collector Set.
+
+0x803000AA
+
+PLA_E_DCS_IN_USE
+
+
+Data Collector Set is in use.
+
+0x803000B7
+
+PLA_E_DCS_ALREADY_EXISTS
+
+
+Data Collector Set already exists.
+
+0x80300101
+
+PLA_E_PROPERTY_CONFLICT
+
+
+Property value conflict.
+
+0x80300102
+
+PLA_E_DCS_SINGLETON_REQUIRED
+
+
+The current configuration for this Data Collector Set requires that it contain exactly one Data Collector.
+
+0x80300103
+
+PLA_E_CREDENTIALS_REQUIRED
+
+
+A user account is required to commit the current Data Collector Set properties.
+
+0x80300104
+
+PLA_E_DCS_NOT_RUNNING
+
+
+Data Collector Set is not running.
+
+0x80300105
+
+PLA_E_CONFLICT_INCL_EXCL_API
+
+
+A conflict was detected in the list of include and exclude APIs. Do not specify the same API in both the include list and the exclude list.
+
+0x80300106
+
+PLA_E_NETWORK_EXE_NOT_VALID
+
+
+The executable path specified refers to a network share or UNC path.
+
+0x80300107
+
+PLA_E_EXE_ALREADY_CONFIGURED
+
+
+The executable path specified is already configured for API tracing.
+
+0x80300108
+
+PLA_E_EXE_PATH_NOT_VALID
+
+
+The executable path specified does not exist. Verify that the specified path is correct.
+
+0x80300109
+
+PLA_E_DC_ALREADY_EXISTS
+
+
+Data Collector already exists.
+
+0x8030010A
+
+PLA_E_DCS_START_WAIT_TIMEOUT
+
+
+The wait for the Data Collector Set start notification has timed out.
+
+0x8030010B
+
+PLA_E_DC_START_WAIT_TIMEOUT
+
+
+The wait for the Data Collector to start has timed out.
+
+0x8030010C
+
+PLA_E_REPORT_WAIT_TIMEOUT
+
+
+The wait for the report generation tool to finish has timed out.
+
+0x8030010D
+
+PLA_E_NO_DUPLICATES
+
+
+Duplicate items are not allowed.
+
+0x8030010E
+
+PLA_E_EXE_FULL_PATH_REQUIRED
+
+
+When specifying the executable to trace, you must specify a full path to the executable and not just a file name.
+
+0x8030010F
+
+PLA_E_INVALID_SESSION_NAME
+
+
+The session name provided is invalid.
+
+0x80300110
+
+PLA_E_PLA_CHANNEL_NOT_ENABLED
+
+
+The Event Log channel Microsoft-Windows-Diagnosis-PLA/Operational must be enabled to perform this operation.
+
+0x80300111
+
+PLA_E_TASKSCHED_CHANNEL_NOT_ENABLED
+
+
+The Event Log channel Microsoft-Windows-TaskScheduler must be enabled to perform this operation.
+
+0x80310000
+
+FVE_E_LOCKED_VOLUME
+
+
+The volume must be unlocked before it can be used.
+
+0x80310001
+
+FVE_E_NOT_ENCRYPTED
+
+
+The volume is fully decrypted and no key is available.
+
+0x80310002
+
+FVE_E_NO_TPM_BIOS
+
+
+The firmware does not support using a TPM during boot.
+
+0x80310003
+
+FVE_E_NO_MBR_METRIC
+
+
+The firmware does not use a TPM to perform initial program load (IPL) measurement.
+
+0x80310004
+
+FVE_E_NO_BOOTSECTOR_METRIC
+
+
+The master boot record (MBR) is not TPM-aware.
+
+0x80310005
+
+FVE_E_NO_BOOTMGR_METRIC
+
+
+The BOOTMGR is not being measured by the TPM.
+
+0x80310006
+
+FVE_E_WRONG_BOOTMGR
+
+
+The BOOTMGR component does not perform expected TPM measurements.
+
+0x80310007
+
+FVE_E_SECURE_KEY_REQUIRED
+
+
+No secure key protection mechanism has been defined.
+
+0x80310008
+
+FVE_E_NOT_ACTIVATED
+
+
+This volume has not been provisioned for encryption.
+
+0x80310009
+
+FVE_E_ACTION_NOT_ALLOWED
+
+
+Requested action was denied by the full-volume encryption (FVE) control engine.
+
+0x8031000A
+
+FVE_E_AD_SCHEMA_NOT_INSTALLED
+
+
+The Active Directory forest does not contain the required attributes and classes to host FVE or TPM information.
+
+0x8031000B
+
+FVE_E_AD_INVALID_DATATYPE
+
+
+The type of data obtained from Active Directory was not expected.
+
+0x8031000C
+
+FVE_E_AD_INVALID_DATASIZE
+
+
+The size of the data obtained from Active Directory was not expected.
+
+0x8031000D
+
+FVE_E_AD_NO_VALUES
+
+
+The attribute read from Active Directory has no (zero) values.
+
+0x8031000E
+
+FVE_E_AD_ATTR_NOT_SET
+
+
+The attribute was not set.
+
+0x8031000F
+
+FVE_E_AD_GUID_NOT_FOUND
+
+
+The specified GUID could not be found.
+
+0x80310010
+
+FVE_E_BAD_INFORMATION
+
+
+The control block for the encrypted volume is not valid.
+
+0x80310011
+
+FVE_E_TOO_SMALL
+
+
+Not enough free space remaining on volume to allow encryption.
+
+0x80310012
+
+FVE_E_SYSTEM_VOLUME
+
+
+The volume cannot be encrypted because it is required to boot the operating system.
+
+0x80310013
+
+FVE_E_FAILED_WRONG_FS
+
+
+The volume cannot be encrypted because the file system is not supported.
+
+0x80310014
+
+FVE_E_FAILED_BAD_FS
+
+
+The file system is inconsistent. Run CHKDSK.
+
+0x80310015
+
+FVE_E_NOT_SUPPORTED
+
+
+This volume cannot be encrypted.
+
+0x80310016
+
+FVE_E_BAD_DATA
+
+
+Data supplied is malformed.
+
+0x80310017
+
+FVE_E_VOLUME_NOT_BOUND
+
+
+Volume is not bound to the system.
+
+0x80310018
+
+FVE_E_TPM_NOT_OWNED
+
+
+TPM must be owned before a volume can be bound to it.
+
+0x80310019
+
+FVE_E_NOT_DATA_VOLUME
+
+
+The volume specified is not a data volume.
+
+0x8031001A
+
+FVE_E_AD_INSUFFICIENT_BUFFER
+
+
+The buffer supplied to a function was insufficient to contain the returned data.
+
+0x8031001B
+
+FVE_E_CONV_READ
+
+
+A read operation failed while converting the volume.
+
+0x8031001C
+
+FVE_E_CONV_WRITE
+
+
+A write operation failed while converting the volume.
+
+0x8031001D
+
+FVE_E_KEY_REQUIRED
+
+
+One or more key protection mechanisms are required for this volume.
+
+0x8031001E
+
+FVE_E_CLUSTERING_NOT_SUPPORTED
+
+
+Cluster configurations are not supported.
+
+0x8031001F
+
+FVE_E_VOLUME_BOUND_ALREADY
+
+
+The volume is already bound to the system.
+
+0x80310020
+
+FVE_E_OS_NOT_PROTECTED
+
+
+The boot OS volume is not being protected via FVE.
+
+0x80310021
+
+FVE_E_PROTECTION_DISABLED
+
+
+All protection mechanisms are effectively disabled (clear key exists).
+
+0x80310022
+
+FVE_E_RECOVERY_KEY_REQUIRED
+
+
+A recovery key protection mechanism is required.
+
+0x80310023
+
+FVE_E_FOREIGN_VOLUME
+
+
+This volume cannot be bound to a TPM.
+
+0x80310024
+
+FVE_E_OVERLAPPED_UPDATE
+
+
+The control block for the encrypted volume was updated by another thread. Try again.
+
+0x80310025
+
+FVE_E_TPM_SRK_AUTH_NOT_ZERO
+
+
+The SRK authentication of the TPM is not zero and, therefore, is not compatible.
+
+0x80310026
+
+FVE_E_FAILED_SECTOR_SIZE
+
+
+The volume encryption algorithm cannot be used on this sector size.
+
+0x80310027
+
+FVE_E_FAILED_AUTHENTICATION
+
+
+BitLocker recovery authentication failed.
+
+0x80310028
+
+FVE_E_NOT_OS_VOLUME
+
+
+The volume specified is not the boot OS volume.
+
+0x80310029
+
+FVE_E_AUTOUNLOCK_ENABLED
+
+
+Auto-unlock information for data volumes is present on the boot OS volume.
+
+0x8031002A
+
+FVE_E_WRONG_BOOTSECTOR
+
+
+The system partition boot sector does not perform TPM measurements.
+
+0x8031002B
+
+FVE_E_WRONG_SYSTEM_FS
+
+
+The system partition file system must be NTFS.
+
+0x8031002C
+
+FVE_E_POLICY_PASSWORD_REQUIRED
+
+
+Group policy requires a recovery password before encryption can begin.
+
+0x8031002D
+
+FVE_E_CANNOT_SET_FVEK_ENCRYPTED
+
+
+The volume encryption algorithm and key cannot be set on an encrypted volume.
+
+0x8031002E
+
+FVE_E_CANNOT_ENCRYPT_NO_KEY
+
+
+A key must be specified before encryption can begin.
+
+0x80310030
+
+FVE_E_BOOTABLE_CDDVD
+
+
+A bootable CD/DVD is in the system. Remove the CD/DVD and reboot the system.
+
+0x80310031
+
+FVE_E_PROTECTOR_EXISTS
+
+
+An instance of this key protector already exists on the volume.
+
+0x80310032
+
+FVE_E_RELATIVE_PATH
+
+
+The file cannot be saved to a relative path.
+
+0x80320001
+
+FWP_E_CALLOUT_NOT_FOUND
+
+
+The callout does not exist.
+
+0x80320002
+
+FWP_E_CONDITION_NOT_FOUND
+
+
+The filter condition does not exist.
+
+0x80320003
+
+FWP_E_FILTER_NOT_FOUND
+
+
+The filter does not exist.
+
+0x80320004
+
+FWP_E_LAYER_NOT_FOUND
+
+
+The layer does not exist.
+
+0x80320005
+
+FWP_E_PROVIDER_NOT_FOUND
+
+
+The provider does not exist.
+
+0x80320006
+
+FWP_E_PROVIDER_CONTEXT_NOT_FOUND
+
+
+The provider context does not exist.
+
+0x80320007
+
+FWP_E_SUBLAYER_NOT_FOUND
+
+
+The sublayer does not exist.
+
+0x80320008
+
+FWP_E_NOT_FOUND
+
+
+The object does not exist.
+
+0x80320009
+
+FWP_E_ALREADY_EXISTS
+
+
+An object with that GUID or LUID already exists.
+
+0x8032000A
+
+FWP_E_IN_USE
+
+
+The object is referenced by other objects and, therefore, cannot be deleted.
+
+0x8032000B
+
+FWP_E_DYNAMIC_SESSION_IN_PROGRESS
+
+
+The call is not allowed from within a dynamic session.
+
+0x8032000C
+
+FWP_E_WRONG_SESSION
+
+
+The call was made from the wrong session and, therefore, cannot be completed.
+
+0x8032000D
+
+FWP_E_NO_TXN_IN_PROGRESS
+
+
+The call must be made from within an explicit transaction.
+
+0x8032000E
+
+FWP_E_TXN_IN_PROGRESS
+
+
+The call is not allowed from within an explicit transaction.
+
+0x8032000F
+
+FWP_E_TXN_ABORTED
+
+
+The explicit transaction has been forcibly canceled.
+
+0x80320010
+
+FWP_E_SESSION_ABORTED
+
+
+The session has been canceled.
+
+0x80320011
+
+FWP_E_INCOMPATIBLE_TXN
+
+
+The call is not allowed from within a read-only transaction.
+
+0x80320012
+
+FWP_E_TIMEOUT
+
+
+The call timed out while waiting to acquire the transaction lock.
+
+0x80320013
+
+FWP_E_NET_EVENTS_DISABLED
+
+
+Collection of network diagnostic events is disabled.
+
+0x80320014
+
+FWP_E_INCOMPATIBLE_LAYER
+
+
+The operation is not supported by the specified layer.
+
+0x80320015
+
+FWP_E_KM_CLIENTS_ONLY
+
+
+The call is allowed for kernel-mode callers only.
+
+0x80320016
+
+FWP_E_LIFETIME_MISMATCH
+
+
+The call tried to associate two objects with incompatible lifetimes.
+
+0x80320017
+
+FWP_E_BUILTIN_OBJECT
+
+
+The object is built in and, therefore, cannot be deleted.
+
+0x80320018
+
+FWP_E_TOO_MANY_BOOTTIME_FILTERS
+
+
+The maximum number of boot-time filters has been reached.
+
+0x80320019
+
+FWP_E_NOTIFICATION_DROPPED
+
+
+A notification could not be delivered because a message queue is at its maximum capacity.
+
+0x8032001A
+
+FWP_E_TRAFFIC_MISMATCH
+
+
+The traffic parameters do not match those for the security association context.
+
+0x8032001B
+
+FWP_E_INCOMPATIBLE_SA_STATE
+
+
+The call is not allowed for the current security association state.
+
+0x8032001C
+
+FWP_E_NULL_POINTER
+
+
+A required pointer is null.
+
+0x8032001D
+
+FWP_E_INVALID_ENUMERATOR
+
+
+An enumerator is not valid.
+
+0x8032001E
+
+FWP_E_INVALID_FLAGS
+
+
+The flags field contains an invalid value.
+
+0x8032001F
+
+FWP_E_INVALID_NET_MASK
+
+
+A network mask is not valid.
+
+0x80320020
+
+FWP_E_INVALID_RANGE
+
+
+An FWP_RANGE is not valid.
+
+0x80320021
+
+FWP_E_INVALID_INTERVAL
+
+
+The time interval is not valid.
+
+0x80320022
+
+FWP_E_ZERO_LENGTH_ARRAY
+
+
+An array that must contain at least one element that is zero-length.
+
+0x80320023
+
+FWP_E_NULL_DISPLAY_NAME
+
+
+The displayData.name field cannot be null.
+
+0x80320024
+
+FWP_E_INVALID_ACTION_TYPE
+
+
+The action type is not one of the allowed action types for a filter.
+
+0x80320025
+
+FWP_E_INVALID_WEIGHT
+
+
+The filter weight is not valid.
+
+0x80320026
+
+FWP_E_MATCH_TYPE_MISMATCH
+
+
+A filter condition contains a match type that is not compatible with the operands.
+
+0x80320027
+
+FWP_E_TYPE_MISMATCH
+
+
+An FWP_VALUE or FWPM_CONDITION_VALUE is of the wrong type.
+
+0x80320028
+
+FWP_E_OUT_OF_BOUNDS
+
+
+An integer value is outside the allowed range.
+
+0x80320029
+
+FWP_E_RESERVED
+
+
+A reserved field is nonzero.
+
+0x8032002A
+
+FWP_E_DUPLICATE_CONDITION
+
+
+A filter cannot contain multiple conditions operating on a single field.
+
+0x8032002B
+
+FWP_E_DUPLICATE_KEYMOD
+
+
+A policy cannot contain the same keying module more than once.
+
+0x8032002C
+
+FWP_E_ACTION_INCOMPATIBLE_WITH_LAYER
+
+
+The action type is not compatible with the layer.
+
+0x8032002D
+
+FWP_E_ACTION_INCOMPATIBLE_WITH_SUBLAYER
+
+
+The action type is not compatible with the sublayer.
+
+0x8032002E
+
+FWP_E_CONTEXT_INCOMPATIBLE_WITH_LAYER
+
+
+The raw context or the provider context is not compatible with the layer.
+
+0x8032002F
+
+FWP_E_CONTEXT_INCOMPATIBLE_WITH_CALLOUT
+
+
+The raw context or the provider context is not compatible with the callout.
+
+0x80320030
+
+FWP_E_INCOMPATIBLE_AUTH_METHOD
+
+
+The authentication method is not compatible with the policy type.
+
+0x80320031
+
+FWP_E_INCOMPATIBLE_DH_GROUP
+
+
+The Diffie-Hellman group is not compatible with the policy type.
+
+0x80320032
+
+FWP_E_EM_NOT_SUPPORTED
+
+
+An Internet Key Exchange (IKE) policy cannot contain an Extended Mode policy.
+
+0x80320033
+
+FWP_E_NEVER_MATCH
+
+
+The enumeration template or subscription will never match any objects.
+
+0x80320034
+
+FWP_E_PROVIDER_CONTEXT_MISMATCH
+
+
+The provider context is of the wrong type.
+
+0x80320035
+
+FWP_E_INVALID_PARAMETER
+
+
+The parameter is incorrect.
+
+0x80320036
+
+FWP_E_TOO_MANY_SUBLAYERS
+
+
+The maximum number of sublayers has been reached.
+
+0x80320037
+
+FWP_E_CALLOUT_NOTIFICATION_FAILED
+
+
+The notification function for a callout returned an error.
+
+0x80320038
+
+FWP_E_INCOMPATIBLE_AUTH_CONFIG
+
+
+The IPsec authentication configuration is not compatible with the authentication type.
+
+0x80320039
+
+FWP_E_INCOMPATIBLE_CIPHER_CONFIG
+
+
+The IPsec cipher configuration is not compatible with the cipher type.
+
+0x80340002
+
+ERROR_NDIS_INTERFACE_CLOSING
+
+
+The binding to the network interface is being closed.
+
+0x80340004
+
+ERROR_NDIS_BAD_VERSION
+
+
+An invalid version was specified.
+
+0x80340005
+
+ERROR_NDIS_BAD_CHARACTERISTICS
+
+
+An invalid characteristics table was used.
+
+0x80340006
+
+ERROR_NDIS_ADAPTER_NOT_FOUND
+
+
+Failed to find the network interface, or the network interface is not ready.
+
+0x80340007
+
+ERROR_NDIS_OPEN_FAILED
+
+
+Failed to open the network interface.
+
+0x80340008
+
+ERROR_NDIS_DEVICE_FAILED
+
+
+The network interface has encountered an internal unrecoverable failure.
+
+0x80340009
+
+ERROR_NDIS_MULTICAST_FULL
+
+
+The multicast list on the network interface is full.
+
+0x8034000A
+
+ERROR_NDIS_MULTICAST_EXISTS
+
+
+An attempt was made to add a duplicate multicast address to the list.
+
+0x8034000B
+
+ERROR_NDIS_MULTICAST_NOT_FOUND
+
+
+At attempt was made to remove a multicast address that was never added.
+
+0x8034000C
+
+ERROR_NDIS_REQUEST_ABORTED
+
+
+The network interface aborted the request.
+
+0x8034000D
+
+ERROR_NDIS_RESET_IN_PROGRESS
+
+
+The network interface cannot process the request because it is being reset.
+
+0x8034000F
+
+ERROR_NDIS_INVALID_PACKET
+
+
+An attempt was made to send an invalid packet on a network interface.
+
+0x80340010
+
+ERROR_NDIS_INVALID_DEVICE_REQUEST
+
+
+The specified request is not a valid operation for the target device.
+
+0x80340011
+
+ERROR_NDIS_ADAPTER_NOT_READY
+
+
+The network interface is not ready to complete this operation.
+
+0x80340014
+
+ERROR_NDIS_INVALID_LENGTH
+
+
+The length of the buffer submitted for this operation is not valid.
+
+0x80340015
+
+ERROR_NDIS_INVALID_DATA
+
+
+The data used for this operation is not valid.
+
+0x80340016
+
+ERROR_NDIS_BUFFER_TOO_SHORT
+
+
+The length of the buffer submitted for this operation is too small.
+
+0x80340017
+
+ERROR_NDIS_INVALID_OID
+
+
+The network interface does not support this OID.
+
+0x80340018
+
+ERROR_NDIS_ADAPTER_REMOVED
+
+
+The network interface has been removed.
+
+0x80340019
+
+ERROR_NDIS_UNSUPPORTED_MEDIA
+
+
+The network interface does not support this media type.
+
+0x8034001A
+
+ERROR_NDIS_GROUP_ADDRESS_IN_USE
+
+
+An attempt was made to remove a token ring group address that is in use by other components.
+
+0x8034001B
+
+ERROR_NDIS_FILE_NOT_FOUND
+
+
+An attempt was made to map a file that cannot be found.
+
+0x8034001C
+
+ERROR_NDIS_ERROR_READING_FILE
+
+
+An error occurred while the NDIS tried to map the file.
+
+0x8034001D
+
+ERROR_NDIS_ALREADY_MAPPED
+
+
+An attempt was made to map a file that is already mapped.
+
+0x8034001E
+
+ERROR_NDIS_RESOURCE_CONFLICT
+
+
+An attempt to allocate a hardware resource failed because the resource is used by another component.
+
+0x8034001F
+
+ERROR_NDIS_MEDIA_DISCONNECTED
+
+
+The I/O operation failed because network media is disconnected or the wireless access point is out of range.
+
+0x80340022
+
+ERROR_NDIS_INVALID_ADDRESS
+
+
+The network address used in the request is invalid.
+
+0x8034002A
+
+ERROR_NDIS_PAUSED
+
+
+The offload operation on the network interface has been paused.
+
+0x8034002B
+
+ERROR_NDIS_INTERFACE_NOT_FOUND
+
+
+The network interface was not found.
+
+0x8034002C
+
+ERROR_NDIS_UNSUPPORTED_REVISION
+
+
+The revision number specified in the structure is not supported.
+
+0x8034002D
+
+ERROR_NDIS_INVALID_PORT
+
+
+The specified port does not exist on this network interface.
+
+0x8034002E
+
+ERROR_NDIS_INVALID_PORT_STATE
+
+
+The current state of the specified port on this network interface does not support the requested operation.
+
+0x803400BB
+
+ERROR_NDIS_NOT_SUPPORTED
+
+
+The network interface does not support this request.
+
+0x80342000
+
+ERROR_NDIS_DOT11_AUTO_CONFIG_ENABLED
+
+
+The wireless local area network (LAN) interface is in auto-configuration mode and does not support the requested parameter change operation.
+
+0x80342001
+
+ERROR_NDIS_DOT11_MEDIA_IN_USE
+
+
+The wireless LAN interface is busy and cannot perform the requested operation.
+
+0x80342002
+
+ERROR_NDIS_DOT11_POWER_STATE_INVALID
+
+
+The wireless LAN interface is shutting down and does not support the requested operation.
+
+0x8DEAD01B
+
+TRK_E_NOT_FOUND
+
+
+A requested object was not found.
+
+0x8DEAD01C
+
+TRK_E_VOLUME_QUOTA_EXCEEDED
+
+
+The server received a CREATE_VOLUME subrequest of a SYNC_VOLUMES request, but the ServerVolumeTable size limit for the RequestMachine has already been reached.
+
+0x8DEAD01E
+
+TRK_SERVER_TOO_BUSY
+
+
+The server is busy, and the client should retry the request at a later time.
+
+0xC0090001
+
+ERROR_AUDITING_DISABLED
+
+
+The specified event is currently not being audited.
+
+0xC0090002
+
+ERROR_ALL_SIDS_FILTERED
+
+
+The SID filtering operation removed all SIDs.
+
+0xC0090003
+
+ERROR_BIZRULES_NOT_ENABLED
+
+
+Business rule scripts are disabled for the calling application.
+
+0xC00D0005
+
+NS_E_NOCONNECTION
+
+
+There is no connection established with the Windows Media server. The operation failed.
+
+0xC00D0006
+
+NS_E_CANNOTCONNECT
+
+
+Unable to establish a connection to the server.
+
+0xC00D0007
+
+NS_E_CANNOTDESTROYTITLE
+
+
+Unable to destroy the title.
+
+0xC00D0008
+
+NS_E_CANNOTRENAMETITLE
+
+
+Unable to rename the title.
+
+0xC00D0009
+
+NS_E_CANNOTOFFLINEDISK
+
+
+Unable to offline disk.
+
+0xC00D000A
+
+NS_E_CANNOTONLINEDISK
+
+
+Unable to online disk.
+
+0xC00D000B
+
+NS_E_NOREGISTEREDWALKER
+
+
+There is no file parser registered for this type of file.
+
+0xC00D000C
+
+NS_E_NOFUNNEL
+
+
+There is no data connection established.
+
+0xC00D000D
+
+NS_E_NO_LOCALPLAY
+
+
+Failed to load the local play DLL.
+
+0xC00D000E
+
+NS_E_NETWORK_BUSY
+
+
+The network is busy.
+
+0xC00D000F
+
+NS_E_TOO_MANY_SESS
+
+
+The server session limit was exceeded.
+
+0xC00D0010
+
+NS_E_ALREADY_CONNECTED
+
+
+The network connection already exists.
+
+0xC00D0011
+
+NS_E_INVALID_INDEX
+
+
+Index %1 is invalid.
+
+0xC00D0012
+
+NS_E_PROTOCOL_MISMATCH
+
+
+There is no protocol or protocol version supported by both the client and the server.
+
+0xC00D0013
+
+NS_E_TIMEOUT
+
+
+The server, a computer set up to offer multimedia content to other computers, could not handle your request for multimedia content in a timely manner. Please try again later.
+
+0xC00D0014
+
+NS_E_NET_WRITE
+
+
+Error writing to the network.
+
+0xC00D0015
+
+NS_E_NET_READ
+
+
+Error reading from the network.
+
+0xC00D0016
+
+NS_E_DISK_WRITE
+
+
+Error writing to a disk.
+
+0xC00D0017
+
+NS_E_DISK_READ
+
+
+Error reading from a disk.
+
+0xC00D0018
+
+NS_E_FILE_WRITE
+
+
+Error writing to a file.
+
+0xC00D0019
+
+NS_E_FILE_READ
+
+
+Error reading from a file.
+
+0xC00D001A
+
+NS_E_FILE_NOT_FOUND
+
+
+The system cannot find the file specified.
+
+0xC00D001B
+
+NS_E_FILE_EXISTS
+
+
+The file already exists.
+
+0xC00D001C
+
+NS_E_INVALID_NAME
+
+
+The file name, directory name, or volume label syntax is incorrect.
+
+0xC00D001D
+
+NS_E_FILE_OPEN_FAILED
+
+
+Failed to open a file.
+
+0xC00D001E
+
+NS_E_FILE_ALLOCATION_FAILED
+
+
+Unable to allocate a file.
+
+0xC00D001F
+
+NS_E_FILE_INIT_FAILED
+
+
+Unable to initialize a file.
+
+0xC00D0020
+
+NS_E_FILE_PLAY_FAILED
+
+
+Unable to play a file.
+
+0xC00D0021
+
+NS_E_SET_DISK_UID_FAILED
+
+
+Could not set the disk UID.
+
+0xC00D0022
+
+NS_E_INDUCED
+
+
+An error was induced for testing purposes.
+
+0xC00D0023
+
+NS_E_CCLINK_DOWN
+
+
+Two Content Servers failed to communicate.
+
+0xC00D0024
+
+NS_E_INTERNAL
+
+
+An unknown error occurred.
+
+0xC00D0025
+
+NS_E_BUSY
+
+
+The requested resource is in use.
+
+0xC00D0026
+
+NS_E_UNRECOGNIZED_STREAM_TYPE
+
+
+The specified protocol is not recognized. Be sure that the file name and syntax, such as slashes, are correct for the protocol.
+
+0xC00D0027
+
+NS_E_NETWORK_SERVICE_FAILURE
+
+
+The network service provider failed.
+
+0xC00D0028
+
+NS_E_NETWORK_RESOURCE_FAILURE
+
+
+An attempt to acquire a network resource failed.
+
+0xC00D0029
+
+NS_E_CONNECTION_FAILURE
+
+
+The network connection has failed.
+
+0xC00D002A
+
+NS_E_SHUTDOWN
+
+
+The session is being terminated locally.
+
+0xC00D002B
+
+NS_E_INVALID_REQUEST
+
+
+The request is invalid in the current state.
+
+0xC00D002C
+
+NS_E_INSUFFICIENT_BANDWIDTH
+
+
+There is insufficient bandwidth available to fulfill the request.
+
+0xC00D002D
+
+NS_E_NOT_REBUILDING
+
+
+The disk is not rebuilding.
+
+0xC00D002E
+
+NS_E_LATE_OPERATION
+
+
+An operation requested for a particular time could not be carried out on schedule.
+
+0xC00D002F
+
+NS_E_INVALID_DATA
+
+
+Invalid or corrupt data was encountered.
+
+0xC00D0030
+
+NS_E_FILE_BANDWIDTH_LIMIT
+
+
+The bandwidth required to stream a file is higher than the maximum file bandwidth allowed on the server.
+
+0xC00D0031
+
+NS_E_OPEN_FILE_LIMIT
+
+
+The client cannot have any more files open simultaneously.
+
+0xC00D0032
+
+NS_E_BAD_CONTROL_DATA
+
+
+The server received invalid data from the client on the control connection.
+
+0xC00D0033
+
+NS_E_NO_STREAM
+
+
+There is no stream available.
+
+0xC00D0034
+
+NS_E_STREAM_END
+
+
+There is no more data in the stream.
+
+0xC00D0035
+
+NS_E_SERVER_NOT_FOUND
+
+
+The specified server could not be found.
+
+0xC00D0036
+
+NS_E_DUPLICATE_NAME
+
+
+The specified name is already in use.
+
+0xC00D0037
+
+NS_E_DUPLICATE_ADDRESS
+
+
+The specified address is already in use.
+
+0xC00D0038
+
+NS_E_BAD_MULTICAST_ADDRESS
+
+
+The specified address is not a valid multicast address.
+
+0xC00D0039
+
+NS_E_BAD_ADAPTER_ADDRESS
+
+
+The specified adapter address is invalid.
+
+0xC00D003A
+
+NS_E_BAD_DELIVERY_MODE
+
+
+The specified delivery mode is invalid.
+
+0xC00D003B
+
+NS_E_INVALID_CHANNEL
+
+
+The specified station does not exist.
+
+0xC00D003C
+
+NS_E_INVALID_STREAM
+
+
+The specified stream does not exist.
+
+0xC00D003D
+
+NS_E_INVALID_ARCHIVE
+
+
+The specified archive could not be opened.
+
+0xC00D003E
+
+NS_E_NOTITLES
+
+
+The system cannot find any titles on the server.
+
+0xC00D003F
+
+NS_E_INVALID_CLIENT
+
+
+The system cannot find the client specified.
+
+0xC00D0040
+
+NS_E_INVALID_BLACKHOLE_ADDRESS
+
+
+The Blackhole Address is not initialized.
+
+0xC00D0041
+
+NS_E_INCOMPATIBLE_FORMAT
+
+
+The station does not support the stream format.
+
+0xC00D0042
+
+NS_E_INVALID_KEY
+
+
+The specified key is not valid.
+
+0xC00D0043
+
+NS_E_INVALID_PORT
+
+
+The specified port is not valid.
+
+0xC00D0044
+
+NS_E_INVALID_TTL
+
+
+The specified TTL is not valid.
+
+0xC00D0045
+
+NS_E_STRIDE_REFUSED
+
+
+The request to fast forward or rewind could not be fulfilled.
+
+0xC00D0046
+
+NS_E_MMSAUTOSERVER_CANTFINDWALKER
+
+
+Unable to load the appropriate file parser.
+
+0xC00D0047
+
+NS_E_MAX_BITRATE
+
+
+Cannot exceed the maximum bandwidth limit.
+
+0xC00D0048
+
+NS_E_LOGFILEPERIOD
+
+
+Invalid value for LogFilePeriod.
+
+0xC00D0049
+
+NS_E_MAX_CLIENTS
+
+
+Cannot exceed the maximum client limit.
+
+0xC00D004A
+
+NS_E_LOG_FILE_SIZE
+
+
+The maximum log file size has been reached.
+
+0xC00D004B
+
+NS_E_MAX_FILERATE
+
+
+Cannot exceed the maximum file rate.
+
+0xC00D004C
+
+NS_E_WALKER_UNKNOWN
+
+
+Unknown file type.
+
+0xC00D004D
+
+NS_E_WALKER_SERVER
+
+
+The specified file, %1, cannot be loaded onto the specified server, %2.
+
+0xC00D004E
+
+NS_E_WALKER_USAGE
+
+
+There was a usage error with file parser.
+
+0xC00D0050
+
+NS_E_TIGER_FAIL
+
+
+The Title Server %1 has failed.
+
+0xC00D0053
+
+NS_E_CUB_FAIL
+
+
+Content Server %1 (%2) has failed.
+
+0xC00D0055
+
+NS_E_DISK_FAIL
+
+
+Disk %1 ( %2 ) on Content Server %3, has failed.
+
+0xC00D0060
+
+NS_E_MAX_FUNNELS_ALERT
+
+
+The NetShow data stream limit of %1 streams was reached.
+
+0xC00D0061
+
+NS_E_ALLOCATE_FILE_FAIL
+
+
+The NetShow Video Server was unable to allocate a %1 block file named %2.
+
+0xC00D0062
+
+NS_E_PAGING_ERROR
+
+
+A Content Server was unable to page a block.
+
+0xC00D0063
+
+NS_E_BAD_BLOCK0_VERSION
+
+
+Disk %1 has unrecognized control block version %2.
+
+0xC00D0064
+
+NS_E_BAD_DISK_UID
+
+
+Disk %1 has incorrect uid %2.
+
+0xC00D0065
+
+NS_E_BAD_FSMAJOR_VERSION
+
+
+Disk %1 has unsupported file system major version %2.
+
+0xC00D0066
+
+NS_E_BAD_STAMPNUMBER
+
+
+Disk %1 has bad stamp number in control block.
+
+0xC00D0067
+
+NS_E_PARTIALLY_REBUILT_DISK
+
+
+Disk %1 is partially reconstructed.
+
+0xC00D0068
+
+NS_E_ENACTPLAN_GIVEUP
+
+
+EnactPlan gives up.
+
+0xC00D006A
+
+MCMADM_E_REGKEY_NOT_FOUND
+
+
+The key was not found in the registry.
+
+0xC00D006B
+
+NS_E_NO_FORMATS
+
+
+The publishing point cannot be started because the server does not have the appropriate stream formats. Use the Multicast Announcement Wizard to create a new announcement for this publishing point.
+
+0xC00D006C
+
+NS_E_NO_REFERENCES
+
+
+No reference URLs were found in an ASX file.
+
+0xC00D006D
+
+NS_E_WAVE_OPEN
+
+
+Error opening wave device, the device might be in use.
+
+0xC00D006F
+
+NS_E_CANNOTCONNECTEVENTS
+
+
+Unable to establish a connection to the NetShow event monitor service.
+
+0xC00D0071
+
+NS_E_NO_DEVICE
+
+
+No device driver is present on the system.
+
+0xC00D0072
+
+NS_E_NO_SPECIFIED_DEVICE
+
+
+No specified device driver is present.
+
+0xC00D00C8
+
+NS_E_MONITOR_GIVEUP
+
+
+Netshow Events Monitor is not operational and has been disconnected.
+
+0xC00D00C9
+
+NS_E_REMIRRORED_DISK
+
+
+Disk %1 is remirrored.
+
+0xC00D00CA
+
+NS_E_INSUFFICIENT_DATA
+
+
+Insufficient data found.
+
+0xC00D00CB
+
+NS_E_ASSERT
+
+
+1 failed in file %2 line %3.
+
+0xC00D00CC
+
+NS_E_BAD_ADAPTER_NAME
+
+
+The specified adapter name is invalid.
+
+0xC00D00CD
+
+NS_E_NOT_LICENSED
+
+
+The application is not licensed for this feature.
+
+0xC00D00CE
+
+NS_E_NO_SERVER_CONTACT
+
+
+Unable to contact the server.
+
+0xC00D00CF
+
+NS_E_TOO_MANY_TITLES
+
+
+Maximum number of titles exceeded.
+
+0xC00D00D0
+
+NS_E_TITLE_SIZE_EXCEEDED
+
+
+Maximum size of a title exceeded.
+
+0xC00D00D1
+
+NS_E_UDP_DISABLED
+
+
+UDP protocol not enabled. Not trying %1!ls!.
+
+0xC00D00D2
+
+NS_E_TCP_DISABLED
+
+
+TCP protocol not enabled. Not trying %1!ls!.
+
+0xC00D00D3
+
+NS_E_HTTP_DISABLED
+
+
+HTTP protocol not enabled. Not trying %1!ls!.
+
+0xC00D00D4
+
+NS_E_LICENSE_EXPIRED
+
+
+The product license has expired.
+
+0xC00D00D5
+
+NS_E_TITLE_BITRATE
+
+
+Source file exceeds the per title maximum bitrate. See NetShow Theater documentation for more information.
+
+0xC00D00D6
+
+NS_E_EMPTY_PROGRAM_NAME
+
+
+The program name cannot be empty.
+
+0xC00D00D7
+
+NS_E_MISSING_CHANNEL
+
+
+Station %1 does not exist.
+
+0xC00D00D8
+
+NS_E_NO_CHANNELS
+
+
+You need to define at least one station before this operation can complete.
+
+0xC00D00D9
+
+NS_E_INVALID_INDEX2
+
+
+The index specified is invalid.
+
+0xC00D0190
+
+NS_E_CUB_FAIL_LINK
+
+
+Content Server %1 (%2) has failed its link to Content Server %3.
+
+0xC00D0192
+
+NS_E_BAD_CUB_UID
+
+
+Content Server %1 (%2) has incorrect uid %3.
+
+0xC00D0195
+
+NS_E_GLITCH_MODE
+
+
+Server unreliable because multiple components failed.
+
+0xC00D019B
+
+NS_E_NO_MEDIA_PROTOCOL
+
+
+Content Server %1 (%2) is unable to communicate with the Media System Network Protocol.
+
+0xC00D07F1
+
+NS_E_NOTHING_TO_DO
+
+
+Nothing to do.
+
+0xC00D07F2
+
+NS_E_NO_MULTICAST
+
+
+Not receiving data from the server.
+
+0xC00D0BB8
+
+NS_E_INVALID_INPUT_FORMAT
+
+
+The input media format is invalid.
+
+0xC00D0BB9
+
+NS_E_MSAUDIO_NOT_INSTALLED
+
+
+The MSAudio codec is not installed on this system.
+
+0xC00D0BBA
+
+NS_E_UNEXPECTED_MSAUDIO_ERROR
+
+
+An unexpected error occurred with the MSAudio codec.
+
+0xC00D0BBB
+
+NS_E_INVALID_OUTPUT_FORMAT
+
+
+The output media format is invalid.
+
+0xC00D0BBC
+
+NS_E_NOT_CONFIGURED
+
+
+The object must be fully configured before audio samples can be processed.
+
+0xC00D0BBD
+
+NS_E_PROTECTED_CONTENT
+
+
+You need a license to perform the requested operation on this media file.
+
+0xC00D0BBE
+
+NS_E_LICENSE_REQUIRED
+
+
+You need a license to perform the requested operation on this media file.
+
+0xC00D0BBF
+
+NS_E_TAMPERED_CONTENT
+
+
+This media file is corrupted or invalid. Contact the content provider for a new file.
+
+0xC00D0BC0
+
+NS_E_LICENSE_OUTOFDATE
+
+
+The license for this media file has expired. Get a new license or contact the content provider for further assistance.
+
+0xC00D0BC1
+
+NS_E_LICENSE_INCORRECT_RIGHTS
+
+
+You are not allowed to open this file. Contact the content provider for further assistance.
+
+0xC00D0BC2
+
+NS_E_AUDIO_CODEC_NOT_INSTALLED
+
+
+The requested audio codec is not installed on this system.
+
+0xC00D0BC3
+
+NS_E_AUDIO_CODEC_ERROR
+
+
+An unexpected error occurred with the audio codec.
+
+0xC00D0BC4
+
+NS_E_VIDEO_CODEC_NOT_INSTALLED
+
+
+The requested video codec is not installed on this system.
+
+0xC00D0BC5
+
+NS_E_VIDEO_CODEC_ERROR
+
+
+An unexpected error occurred with the video codec.
+
+0xC00D0BC6
+
+NS_E_INVALIDPROFILE
+
+
+The Profile is invalid.
+
+0xC00D0BC7
+
+NS_E_INCOMPATIBLE_VERSION
+
+
+A new version of the SDK is needed to play the requested content.
+
+0xC00D0BCA
+
+NS_E_OFFLINE_MODE
+
+
+The requested URL is not available in offline mode.
+
+0xC00D0BCB
+
+NS_E_NOT_CONNECTED
+
+
+The requested URL cannot be accessed because there is no network connection.
+
+0xC00D0BCC
+
+NS_E_TOO_MUCH_DATA
+
+
+The encoding process was unable to keep up with the amount of supplied data.
+
+0xC00D0BCD
+
+NS_E_UNSUPPORTED_PROPERTY
+
+
+The given property is not supported.
+
+0xC00D0BCE
+
+NS_E_8BIT_WAVE_UNSUPPORTED
+
+
+Windows Media Player cannot copy the files to the CD because they are 8-bit. Convert the files to 16-bit, 44-kHz stereo files by using Sound Recorder or another audio-processing program, and then try again.
+
+0xC00D0BCF
+
+NS_E_NO_MORE_SAMPLES
+
+
+There are no more samples in the current range.
+
+0xC00D0BD0
+
+NS_E_INVALID_SAMPLING_RATE
+
+
+The given sampling rate is invalid.
+
+0xC00D0BD1
+
+NS_E_MAX_PACKET_SIZE_TOO_SMALL
+
+
+The given maximum packet size is too small to accommodate this profile.)
+
+0xC00D0BD2
+
+NS_E_LATE_PACKET
+
+
+The packet arrived too late to be of use.
+
+0xC00D0BD3
+
+NS_E_DUPLICATE_PACKET
+
+
+The packet is a duplicate of one received before.
+
+0xC00D0BD4
+
+NS_E_SDK_BUFFERTOOSMALL
+
+
+Supplied buffer is too small.
+
+0xC00D0BD5
+
+NS_E_INVALID_NUM_PASSES
+
+
+The wrong number of preprocessing passes was used for the stream's output type.
+
+0xC00D0BD6
+
+NS_E_ATTRIBUTE_READ_ONLY
+
+
+An attempt was made to add, modify, or delete a read only attribute.
+
+0xC00D0BD7
+
+NS_E_ATTRIBUTE_NOT_ALLOWED
+
+
+An attempt was made to add attribute that is not allowed for the given media type.
+
+0xC00D0BD8
+
+NS_E_INVALID_EDL
+
+
+The EDL provided is invalid.
+
+0xC00D0BD9
+
+NS_E_DATA_UNIT_EXTENSION_TOO_LARGE
+
+
+The Data Unit Extension data was too large to be used.
+
+0xC00D0BDA
+
+NS_E_CODEC_DMO_ERROR
+
+
+An unexpected error occurred with a DMO codec.
+
+0xC00D0BDC
+
+NS_E_FEATURE_DISABLED_BY_GROUP_POLICY
+
+
+This feature has been disabled by group policy.
+
+0xC00D0BDD
+
+NS_E_FEATURE_DISABLED_IN_SKU
+
+
+This feature is disabled in this SKU.
+
+0xC00D0FA0
+
+NS_E_NO_CD
+
+
+There is no CD in the CD drive. Insert a CD, and then try again.
+
+0xC00D0FA1
+
+NS_E_CANT_READ_DIGITAL
+
+
+Windows Media Player could not use digital playback to play the CD. To switch to analog playback, on the Tools menu, click Options, and then click the Devices tab. Double-click the CD drive, and then in the Playback area, click Analog. For additional assistance, click Web Help.
+
+0xC00D0FA2
+
+NS_E_DEVICE_DISCONNECTED
+
+
+Windows Media Player no longer detects a connected portable device. Reconnect your portable device, and then try synchronizing the file again.
+
+0xC00D0FA3
+
+NS_E_DEVICE_NOT_SUPPORT_FORMAT
+
+
+Windows Media Player cannot play the file. The portable device does not support the specified file type.
+
+0xC00D0FA4
+
+NS_E_SLOW_READ_DIGITAL
+
+
+Windows Media Player could not use digital playback to play the CD. The Player has automatically switched the CD drive to analog playback. To switch back to digital CD playback, use the Devices tab. For additional assistance, click Web Help.
+
+0xC00D0FA5
+
+NS_E_MIXER_INVALID_LINE
+
+
+An invalid line error occurred in the mixer.
+
+0xC00D0FA6
+
+NS_E_MIXER_INVALID_CONTROL
+
+
+An invalid control error occurred in the mixer.
+
+0xC00D0FA7
+
+NS_E_MIXER_INVALID_VALUE
+
+
+An invalid value error occurred in the mixer.
+
+0xC00D0FA8
+
+NS_E_MIXER_UNKNOWN_MMRESULT
+
+
+An unrecognized MMRESULT occurred in the mixer.
+
+0xC00D0FA9
+
+NS_E_USER_STOP
+
+
+User has stopped the operation.
+
+0xC00D0FAA
+
+NS_E_MP3_FORMAT_NOT_FOUND
+
+
+Windows Media Player cannot rip the track because a compatible MP3 encoder is not installed on your computer. Install a compatible MP3 encoder or choose a different format to rip to (such as Windows Media Audio).
+
+0xC00D0FAB
+
+NS_E_CD_READ_ERROR_NO_CORRECTION
+
+
+Windows Media Player cannot read the CD. The disc might be dirty or damaged. Turn on error correction, and then try again.
+
+0xC00D0FAC
+
+NS_E_CD_READ_ERROR
+
+
+Windows Media Player cannot read the CD. The disc might be dirty or damaged or the CD drive might be malfunctioning.
+
+0xC00D0FAD
+
+NS_E_CD_SLOW_COPY
+
+
+For best performance, do not play CD tracks while ripping them.
+
+0xC00D0FAE
+
+NS_E_CD_COPYTO_CD
+
+
+It is not possible to directly burn tracks from one CD to another CD. You must first rip the tracks from the CD to your computer, and then burn the files to a blank CD.
+
+0xC00D0FAF
+
+NS_E_MIXER_NODRIVER
+
+
+Could not open a sound mixer driver.
+
+0xC00D0FB0
+
+NS_E_REDBOOK_ENABLED_WHILE_COPYING
+
+
+Windows Media Player cannot rip tracks from the CD correctly because the CD drive settings in Device Manager do not match the CD drive settings in the Player.
+
+0xC00D0FB1
+
+NS_E_CD_REFRESH
+
+
+Windows Media Player is busy reading the CD.
+
+0xC00D0FB2
+
+NS_E_CD_DRIVER_PROBLEM
+
+
+Windows Media Player could not use digital playback to play the CD. The Player has automatically switched the CD drive to analog playback. To switch back to digital CD playback, use the Devices tab. For additional assistance, click Web Help.
+
+0xC00D0FB3
+
+NS_E_WONT_DO_DIGITAL
+
+
+Windows Media Player could not use digital playback to play the CD. The Player has automatically switched the CD drive to analog playback. To switch back to digital CD playback, use the Devices tab. For additional assistance, click Web Help.
+
+0xC00D0FB4
+
+NS_E_WMPXML_NOERROR
+
+
+A call was made to GetParseError on the XML parser but there was no error to retrieve.
+
+0xC00D0FB5
+
+NS_E_WMPXML_ENDOFDATA
+
+
+The XML Parser ran out of data while parsing.
+
+0xC00D0FB6
+
+NS_E_WMPXML_PARSEERROR
+
+
+A generic parse error occurred in the XML parser but no information is available.
+
+0xC00D0FB7
+
+NS_E_WMPXML_ATTRIBUTENOTFOUND
+
+
+A call get GetNamedAttribute or GetNamedAttributeIndex on the XML parser resulted in the index not being found.
+
+0xC00D0FB8
+
+NS_E_WMPXML_PINOTFOUND
+
+
+A call was made go GetNamedPI on the XML parser, but the requested Processing Instruction was not found.
+
+0xC00D0FB9
+
+NS_E_WMPXML_EMPTYDOC
+
+
+Persist was called on the XML parser, but the parser has no data to persist.
+
+0xC00D0FBA
+
+NS_E_WMP_PATH_ALREADY_IN_LIBRARY
+
+
+This file path is already in the library.
+
+0xC00D0FBE
+
+NS_E_WMP_FILESCANALREADYSTARTED
+
+
+Windows Media Player is already searching for files to add to your library. Wait for the current process to finish before attempting to search again.
+
+0xC00D0FBF
+
+NS_E_WMP_HME_INVALIDOBJECTID
+
+
+Windows Media Player is unable to find the media you are looking for.
+
+0xC00D0FC0
+
+NS_E_WMP_MF_CODE_EXPIRED
+
+
+A component of Windows Media Player is out-of-date. If you are running a pre-release version of Windows, try upgrading to a more recent version.
+
+0xC00D0FC1
+
+NS_E_WMP_HME_NOTSEARCHABLEFORITEMS
+
+
+This container does not support search on items.
+
+0xC00D0FC7
+
+NS_E_WMP_ADDTOLIBRARY_FAILED
+
+
+Windows Media Player encountered a problem while adding one or more files to the library. For additional assistance, click Web Help.
+
+0xC00D0FC8
+
+NS_E_WMP_WINDOWSAPIFAILURE
+
+
+A Windows API call failed but no error information was available.
+
+0xC00D0FC9
+
+NS_E_WMP_RECORDING_NOT_ALLOWED
+
+
+This file does not have burn rights. If you obtained this file from an online store, go to the online store to get burn rights.
+
+0xC00D0FCA
+
+NS_E_DEVICE_NOT_READY
+
+
+Windows Media Player no longer detects a connected portable device. Reconnect your portable device, and then try to sync the file again.
+
+0xC00D0FCB
+
+NS_E_DAMAGED_FILE
+
+
+Windows Media Player cannot play the file because it is corrupted.
+
+0xC00D0FCC
+
+NS_E_MPDB_GENERIC
+
+
+Windows Media Player encountered an error while attempting to access information in the library. Try restarting the Player.
+
+0xC00D0FCD
+
+NS_E_FILE_FAILED_CHECKS
+
+
+The file cannot be added to the library because it is smaller than the "Skip files smaller than" setting. To add the file, change the setting on the Library tab. For additional assistance, click Web Help.
+
+0xC00D0FCE
+
+NS_E_MEDIA_LIBRARY_FAILED
+
+
+Windows Media Player cannot create the library. You must be logged on as an administrator or a member of the Administrators group to install the Player. For more information, contact your system administrator.
+
+0xC00D0FCF
+
+NS_E_SHARING_VIOLATION
+
+
+The file is already in use. Close other programs that might be using the file, or stop playing the file, and then try again.
+
+0xC00D0FD0
+
+NS_E_NO_ERROR_STRING_FOUND
+
+
+Windows Media Player has encountered an unknown error.
+
+0xC00D0FD1
+
+NS_E_WMPOCX_NO_REMOTE_CORE
+
+
+The Windows Media Player ActiveX control cannot connect to remote media services, but will continue with local media services.
+
+0xC00D0FD2
+
+NS_E_WMPOCX_NO_ACTIVE_CORE
+
+
+The requested method or property is not available because the Windows Media Player ActiveX control has not been properly activated.
+
+0xC00D0FD3
+
+NS_E_WMPOCX_NOT_RUNNING_REMOTELY
+
+
+The Windows Media Player ActiveX control is not running in remote mode.
+
+0xC00D0FD4
+
+NS_E_WMPOCX_NO_REMOTE_WINDOW
+
+
+An error occurred while trying to get the remote Windows Media Player window.
+
+0xC00D0FD5
+
+NS_E_WMPOCX_ERRORMANAGERNOTAVAILABLE
+
+
+Windows Media Player has encountered an unknown error.
+
+0xC00D0FD6
+
+NS_E_PLUGIN_NOTSHUTDOWN
+
+
+Windows Media Player was not closed properly. A damaged or incompatible plug-in might have caused the problem to occur. As a precaution, all optional plug-ins have been disabled.
+
+0xC00D0FD7
+
+NS_E_WMP_CANNOT_FIND_FOLDER
+
+
+Windows Media Player cannot find the specified path. Verify that the path is typed correctly. If it is, the path does not exist in the specified location, or the computer where the path is located is not available.
+
+0xC00D0FD8
+
+NS_E_WMP_STREAMING_RECORDING_NOT_ALLOWED
+
+
+Windows Media Player cannot save a file that is being streamed.
+
+0xC00D0FD9
+
+NS_E_WMP_PLUGINDLL_NOTFOUND
+
+
+Windows Media Player cannot find the selected plug-in. The Player will try to remove it from the menu. To use this plug-in, install it again.
+
+0xC00D0FDA
+
+NS_E_NEED_TO_ASK_USER
+
+
+Action requires input from the user.
+
+0xC00D0FDB
+
+NS_E_WMPOCX_PLAYER_NOT_DOCKED
+
+
+The Windows Media Player ActiveX control must be in a docked state for this action to be performed.
+
+0xC00D0FDC
+
+NS_E_WMP_EXTERNAL_NOTREADY
+
+
+The Windows Media Player external object is not ready.
+
+0xC00D0FDD
+
+NS_E_WMP_MLS_STALE_DATA
+
+
+Windows Media Player cannot perform the requested action. Your computer's time and date might not be set correctly.
+
+0xC00D0FDE
+
+NS_E_WMP_UI_SUBCONTROLSNOTSUPPORTED
+
+
+The control (%s) does not support creation of sub-controls, yet (%d) sub-controls have been specified.
+
+0xC00D0FDF
+
+NS_E_WMP_UI_VERSIONMISMATCH
+
+
+Version mismatch: (%.1f required, %.1f found).
+
+0xC00D0FE0
+
+NS_E_WMP_UI_NOTATHEMEFILE
+
+
+The layout manager was given valid XML that wasn't a theme file.
+
+0xC00D0FE1
+
+NS_E_WMP_UI_SUBELEMENTNOTFOUND
+
+
+The %s subelement could not be found on the %s object.
+
+0xC00D0FE2
+
+NS_E_WMP_UI_VERSIONPARSE
+
+
+An error occurred parsing the version tag. Valid version tags are of the form: <?wmp version='1.0'?>.
+
+0xC00D0FE3
+
+NS_E_WMP_UI_VIEWIDNOTFOUND
+
+
+The view specified in for the 'currentViewID' property (%s) was not found in this theme file.
+
+0xC00D0FE4
+
+NS_E_WMP_UI_PASSTHROUGH
+
+
+This error used internally for hit testing.
+
+0xC00D0FE5
+
+NS_E_WMP_UI_OBJECTNOTFOUND
+
+
+Attributes were specified for the %s object, but the object was not available to send them to.
+
+0xC00D0FE6
+
+NS_E_WMP_UI_SECONDHANDLER
+
+
+The %s event already has a handler, the second handler was ignored.
+
+0xC00D0FE7
+
+NS_E_WMP_UI_NOSKININZIP
+
+
+No .wms file found in skin archive.
+
+0xC00D0FEA
+
+NS_E_WMP_URLDOWNLOADFAILED
+
+
+Windows Media Player encountered a problem while downloading the file. For additional assistance, click Web Help.
+
+0xC00D0FEB
+
+NS_E_WMPOCX_UNABLE_TO_LOAD_SKIN
+
+
+The Windows Media Player ActiveX control cannot load the requested uiMode and cannot roll back to the existing uiMode.
+
+0xC00D0FEC
+
+NS_E_WMP_INVALID_SKIN
+
+
+Windows Media Player encountered a problem with the skin file. The skin file might not be valid.
+
+0xC00D0FED
+
+NS_E_WMP_SENDMAILFAILED
+
+
+Windows Media Player cannot send the link because your email program is not responding. Verify that your email program is configured properly, and then try again. For more information about email, see Windows Help.
+
+0xC00D0FEE
+
+NS_E_WMP_LOCKEDINSKINMODE
+
+
+Windows Media Player cannot switch to full mode because your computer administrator has locked this skin.
+
+0xC00D0FEF
+
+NS_E_WMP_FAILED_TO_SAVE_FILE
+
+
+Windows Media Player encountered a problem while saving the file. For additional assistance, click Web Help.
+
+0xC00D0FF0
+
+NS_E_WMP_SAVEAS_READONLY
+
+
+Windows Media Player cannot overwrite a read-only file. Try using a different file name.
+
+0xC00D0FF1
+
+NS_E_WMP_FAILED_TO_SAVE_PLAYLIST
+
+
+Windows Media Player encountered a problem while creating or saving the playlist. For additional assistance, click Web Help.
+
+0xC00D0FF2
+
+NS_E_WMP_FAILED_TO_OPEN_WMD
+
+
+Windows Media Player cannot open the Windows Media Download file. The file might be damaged.
+
+0xC00D0FF3
+
+NS_E_WMP_CANT_PLAY_PROTECTED
+
+
+The file cannot be added to the library because it is a protected DVR-MS file. This content cannot be played back by Windows Media Player.
+
+0xC00D0FF4
+
+NS_E_SHARING_STATE_OUT_OF_SYNC
+
+
+Media sharing has been turned off because a required Windows setting or component has changed. For additional assistance, click Web Help.
+
+0xC00D0FFA
+
+NS_E_WMPOCX_REMOTE_PLAYER_ALREADY_RUNNING
+
+
+Exclusive Services launch failed because the Windows Media Player is already running.
+
+0xC00D1004
+
+NS_E_WMP_RBC_JPGMAPPINGIMAGE
+
+
+JPG Images are not recommended for use as a mappingImage.
+
+0xC00D1005
+
+NS_E_WMP_JPGTRANSPARENCY
+
+
+JPG Images are not recommended when using a transparencyColor.
+
+0xC00D1009
+
+NS_E_WMP_INVALID_MAX_VAL
+
+
+The Max property cannot be less than Min property.
+
+0xC00D100A
+
+NS_E_WMP_INVALID_MIN_VAL
+
+
+The Min property cannot be greater than Max property.
+
+0xC00D100E
+
+NS_E_WMP_CS_JPGPOSITIONIMAGE
+
+
+JPG Images are not recommended for use as a positionImage.
+
+0xC00D100F
+
+NS_E_WMP_CS_NOTEVENLYDIVISIBLE
+
+
+The (%s) image's size is not evenly divisible by the positionImage's size.
+
+0xC00D1018
+
+NS_E_WMPZIP_NOTAZIPFILE
+
+
+The ZIP reader opened a file and its signature did not match that of the ZIP files.
+
+0xC00D1019
+
+NS_E_WMPZIP_CORRUPT
+
+
+The ZIP reader has detected that the file is corrupted.
+
+0xC00D101A
+
+NS_E_WMPZIP_FILENOTFOUND
+
+
+GetFileStream, SaveToFile, or SaveTemp file was called on the ZIP reader with a file name that was not found in the ZIP file.
+
+0xC00D1022
+
+NS_E_WMP_IMAGE_FILETYPE_UNSUPPORTED
+
+
+Image type not supported.
+
+0xC00D1023
+
+NS_E_WMP_IMAGE_INVALID_FORMAT
+
+
+Image file might be corrupt.
+
+0xC00D1024
+
+NS_E_WMP_GIF_UNEXPECTED_ENDOFFILE
+
+
+Unexpected end of file. GIF file might be corrupt.
+
+0xC00D1025
+
+NS_E_WMP_GIF_INVALID_FORMAT
+
+
+Invalid GIF file.
+
+0xC00D1026
+
+NS_E_WMP_GIF_BAD_VERSION_NUMBER
+
+
+Invalid GIF version. Only 87a or 89a supported.
+
+0xC00D1027
+
+NS_E_WMP_GIF_NO_IMAGE_IN_FILE
+
+
+No images found in GIF file.
+
+0xC00D1028
+
+NS_E_WMP_PNG_INVALIDFORMAT
+
+
+Invalid PNG image file format.
+
+0xC00D1029
+
+NS_E_WMP_PNG_UNSUPPORTED_BITDEPTH
+
+
+PNG bitdepth not supported.
+
+0xC00D102A
+
+NS_E_WMP_PNG_UNSUPPORTED_COMPRESSION
+
+
+Compression format defined in PNG file not supported,
+
+0xC00D102B
+
+NS_E_WMP_PNG_UNSUPPORTED_FILTER
+
+
+Filter method defined in PNG file not supported.
+
+0xC00D102C
+
+NS_E_WMP_PNG_UNSUPPORTED_INTERLACE
+
+
+Interlace method defined in PNG file not supported.
+
+0xC00D102D
+
+NS_E_WMP_PNG_UNSUPPORTED_BAD_CRC
+
+
+Bad CRC in PNG file.
+
+0xC00D102E
+
+NS_E_WMP_BMP_INVALID_BITMASK
+
+
+Invalid bitmask in BMP file.
+
+0xC00D102F
+
+NS_E_WMP_BMP_TOPDOWN_DIB_UNSUPPORTED
+
+
+Topdown DIB not supported.
+
+0xC00D1030
+
+NS_E_WMP_BMP_BITMAP_NOT_CREATED
+
+
+Bitmap could not be created.
+
+0xC00D1031
+
+NS_E_WMP_BMP_COMPRESSION_UNSUPPORTED
+
+
+Compression format defined in BMP not supported.
+
+0xC00D1032
+
+NS_E_WMP_BMP_INVALID_FORMAT
+
+
+Invalid Bitmap format.
+
+0xC00D1033
+
+NS_E_WMP_JPG_JERR_ARITHCODING_NOTIMPL
+
+
+JPEG Arithmetic coding not supported.
+
+0xC00D1034
+
+NS_E_WMP_JPG_INVALID_FORMAT
+
+
+Invalid JPEG format.
+
+0xC00D1035
+
+NS_E_WMP_JPG_BAD_DCTSIZE
+
+
+Invalid JPEG format.
+
+0xC00D1036
+
+NS_E_WMP_JPG_BAD_VERSION_NUMBER
+
+
+Internal version error. Unexpected JPEG library version.
+
+0xC00D1037
+
+NS_E_WMP_JPG_BAD_PRECISION
+
+
+Internal JPEG Library error. Unsupported JPEG data precision.
+
+0xC00D1038
+
+NS_E_WMP_JPG_CCIR601_NOTIMPL
+
+
+JPEG CCIR601 not supported.
+
+0xC00D1039
+
+NS_E_WMP_JPG_NO_IMAGE_IN_FILE
+
+
+No image found in JPEG file.
+
+0xC00D103A
+
+NS_E_WMP_JPG_READ_ERROR
+
+
+Could not read JPEG file.
+
+0xC00D103B
+
+NS_E_WMP_JPG_FRACT_SAMPLE_NOTIMPL
+
+
+JPEG Fractional sampling not supported.
+
+0xC00D103C
+
+NS_E_WMP_JPG_IMAGE_TOO_BIG
+
+
+JPEG image too large. Maximum image size supported is 65500 X 65500.
+
+0xC00D103D
+
+NS_E_WMP_JPG_UNEXPECTED_ENDOFFILE
+
+
+Unexpected end of file reached in JPEG file.
+
+0xC00D103E
+
+NS_E_WMP_JPG_SOF_UNSUPPORTED
+
+
+Unsupported JPEG SOF marker found.
+
+0xC00D103F
+
+NS_E_WMP_JPG_UNKNOWN_MARKER
+
+
+Unknown JPEG marker found.
+
+0xC00D1044
+
+NS_E_WMP_FAILED_TO_OPEN_IMAGE
+
+
+Windows Media Player cannot display the picture file. The player either does not support the picture type or the picture is corrupted.
+
+0xC00D1049
+
+NS_E_WMP_DAI_SONGTOOSHORT
+
+
+Windows Media Player cannot compute a Digital Audio Id for the song. It is too short.
+
+0xC00D104A
+
+NS_E_WMG_RATEUNAVAILABLE
+
+
+Windows Media Player cannot play the file at the requested speed.
+
+0xC00D104B
+
+NS_E_WMG_PLUGINUNAVAILABLE
+
+
+The rendering or digital signal processing plug-in cannot be instantiated.
+
+0xC00D104C
+
+NS_E_WMG_CANNOTQUEUE
+
+
+The file cannot be queued for seamless playback.
+
+0xC00D104D
+
+NS_E_WMG_PREROLLLICENSEACQUISITIONNOTALLOWED
+
+
+Windows Media Player cannot download media usage rights for a file in the playlist.
+
+0xC00D104E
+
+NS_E_WMG_UNEXPECTEDPREROLLSTATUS
+
+
+Windows Media Player encountered an error while trying to queue a file.
+
+0xC00D1051
+
+NS_E_WMG_INVALID_COPP_CERTIFICATE
+
+
+Windows Media Player cannot play the protected file. The Player cannot verify that the connection to your video card is secure. Try installing an updated device driver for your video card.
+
+0xC00D1052
+
+NS_E_WMG_COPP_SECURITY_INVALID
+
+
+Windows Media Player cannot play the protected file. The Player detected that the connection to your hardware might not be secure.
+
+0xC00D1053
+
+NS_E_WMG_COPP_UNSUPPORTED
+
+
+Windows Media Player output link protection is unsupported on this system.
+
+0xC00D1054
+
+NS_E_WMG_INVALIDSTATE
+
+
+Operation attempted in an invalid graph state.
+
+0xC00D1055
+
+NS_E_WMG_SINKALREADYEXISTS
+
+
+A renderer cannot be inserted in a stream while one already exists.
+
+0xC00D1056
+
+NS_E_WMG_NOSDKINTERFACE
+
+
+The Windows Media SDK interface needed to complete the operation does not exist at this time.
+
+0xC00D1057
+
+NS_E_WMG_NOTALLOUTPUTSRENDERED
+
+
+Windows Media Player cannot play a portion of the file because it requires a codec that either could not be downloaded or that is not supported by the Player.
+
+0xC00D1058
+
+NS_E_WMG_FILETRANSFERNOTALLOWED
+
+
+File transfer streams are not allowed in the standalone Player.
+
+0xC00D1059
+
+NS_E_WMR_UNSUPPORTEDSTREAM
+
+
+Windows Media Player cannot play the file. The Player does not support the format you are trying to play.
+
+0xC00D105A
+
+NS_E_WMR_PINNOTFOUND
+
+
+An operation was attempted on a pin that does not exist in the DirectShow filter graph.
+
+0xC00D105B
+
+NS_E_WMR_WAITINGONFORMATSWITCH
+
+
+Specified operation cannot be completed while waiting for a media format change from the SDK.
+
+0xC00D105C
+
+NS_E_WMR_NOSOURCEFILTER
+
+
+Specified operation cannot be completed because the source filter does not exist.
+
+0xC00D105D
+
+NS_E_WMR_PINTYPENOMATCH
+
+
+The specified type does not match this pin.
+
+0xC00D105E
+
+NS_E_WMR_NOCALLBACKAVAILABLE
+
+
+The WMR Source Filter does not have a callback available.
+
+0xC00D1062
+
+NS_E_WMR_SAMPLEPROPERTYNOTSET
+
+
+The specified property has not been set on this sample.
+
+0xC00D1063
+
+NS_E_WMR_CANNOT_RENDER_BINARY_STREAM
+
+
+A plug-in is required to correctly play the file. To determine if the plug-in is available to download, click Web Help.
+
+0xC00D1064
+
+NS_E_WMG_LICENSE_TAMPERED
+
+
+Windows Media Player cannot play the file because your media usage rights are corrupted. If you previously backed up your media usage rights, try restoring them.
+
+0xC00D1065
+
+NS_E_WMR_WILLNOT_RENDER_BINARY_STREAM
+
+
+Windows Media Player cannot play protected files that contain binary streams.
+
+0xC00D1068
+
+NS_E_WMX_UNRECOGNIZED_PLAYLIST_FORMAT
+
+
+Windows Media Player cannot play the playlist because it is not valid.
+
+0xC00D1069
+
+NS_E_ASX_INVALIDFORMAT
+
+
+Windows Media Player cannot play the playlist because it is not valid.
+
+0xC00D106A
+
+NS_E_ASX_INVALIDVERSION
+
+
+A later version of Windows Media Player might be required to play this playlist.
+
+0xC00D106B
+
+NS_E_ASX_INVALID_REPEAT_BLOCK
+
+
+The format of a REPEAT loop within the current playlist file is not valid.
+
+0xC00D106C
+
+NS_E_ASX_NOTHING_TO_WRITE
+
+
+Windows Media Player cannot save the playlist because it does not contain any items.
+
+0xC00D106D
+
+NS_E_URLLIST_INVALIDFORMAT
+
+
+Windows Media Player cannot play the playlist because it is not valid.
+
+0xC00D106E
+
+NS_E_WMX_ATTRIBUTE_DOES_NOT_EXIST
+
+
+The specified attribute does not exist.
+
+0xC00D106F
+
+NS_E_WMX_ATTRIBUTE_ALREADY_EXISTS
+
+
+The specified attribute already exists.
+
+0xC00D1070
+
+NS_E_WMX_ATTRIBUTE_UNRETRIEVABLE
+
+
+Cannot retrieve the specified attribute.
+
+0xC00D1071
+
+NS_E_WMX_ITEM_DOES_NOT_EXIST
+
+
+The specified item does not exist in the current playlist.
+
+0xC00D1072
+
+NS_E_WMX_ITEM_TYPE_ILLEGAL
+
+
+Items of the specified type cannot be created within the current playlist.
+
+0xC00D1073
+
+NS_E_WMX_ITEM_UNSETTABLE
+
+
+The specified item cannot be set in the current playlist.
+
+0xC00D1074
+
+NS_E_WMX_PLAYLIST_EMPTY
+
+
+Windows Media Player cannot perform the requested action because the playlist does not contain any items.
+
+0xC00D1075
+
+NS_E_MLS_SMARTPLAYLIST_FILTER_NOT_REGISTERED
+
+
+The specified auto playlist contains a filter type that is either not valid or is not installed on this computer.
+
+0xC00D1076
+
+NS_E_WMX_INVALID_FORMAT_OVER_NESTING
+
+
+Windows Media Player cannot play the file because the associated playlist contains too many nested playlists.
+
+0xC00D107C
+
+NS_E_WMPCORE_NOSOURCEURLSTRING
+
+
+Windows Media Player cannot find the file. Verify that the path is typed correctly. If it is, the file might not exist in the specified location, or the computer where the file is stored might not be available.
+
+0xC00D107D
+
+NS_E_WMPCORE_COCREATEFAILEDFORGITOBJECT
+
+
+Failed to create the Global Interface Table.
+
+0xC00D107E
+
+NS_E_WMPCORE_FAILEDTOGETMARSHALLEDEVENTHANDLERINTERFACE
+
+
+Failed to get the marshaled graph event handler interface.
+
+0xC00D107F
+
+NS_E_WMPCORE_BUFFERTOOSMALL
+
+
+Buffer is too small for copying media type.
+
+0xC00D1080
+
+NS_E_WMPCORE_UNAVAILABLE
+
+
+The current state of the Player does not allow this operation.
+
+0xC00D1081
+
+NS_E_WMPCORE_INVALIDPLAYLISTMODE
+
+
+The playlist manager does not understand the current play mode (for example, shuffle or normal).
+
+0xC00D1086
+
+NS_E_WMPCORE_ITEMNOTINPLAYLIST
+
+
+Windows Media Player cannot play the file because it is not in the current playlist.
+
+0xC00D1087
+
+NS_E_WMPCORE_PLAYLISTEMPTY
+
+
+There are no items in the playlist. Add items to the playlist, and then try again.
+
+0xC00D1088
+
+NS_E_WMPCORE_NOBROWSER
+
+
+The web page cannot be displayed because no web browser is installed on your computer.
+
+0xC00D1089
+
+NS_E_WMPCORE_UNRECOGNIZED_MEDIA_URL
+
+
+Windows Media Player cannot find the specified file. Verify the path is typed correctly. If it is, the file does not exist in the specified location, or the computer where the file is stored is not available.
+
+0xC00D108A
+
+NS_E_WMPCORE_GRAPH_NOT_IN_LIST
+
+
+Graph with the specified URL was not found in the prerolled graph list.
+
+0xC00D108B
+
+NS_E_WMPCORE_PLAYLIST_EMPTY_OR_SINGLE_MEDIA
+
+
+Windows Media Player cannot perform the requested operation because there is only one item in the playlist.
+
+0xC00D108C
+
+NS_E_WMPCORE_ERRORSINKNOTREGISTERED
+
+
+An error sink was never registered for the calling object.
+
+0xC00D108D
+
+NS_E_WMPCORE_ERRORMANAGERNOTAVAILABLE
+
+
+The error manager is not available to respond to errors.
+
+0xC00D108E
+
+NS_E_WMPCORE_WEBHELPFAILED
+
+
+The Web Help URL cannot be opened.
+
+0xC00D108F
+
+NS_E_WMPCORE_MEDIA_ERROR_RESUME_FAILED
+
+
+Could not resume playing next item in playlist.
+
+0xC00D1090
+
+NS_E_WMPCORE_NO_REF_IN_ENTRY
+
+
+Windows Media Player cannot play the file because the associated playlist does not contain any items or the playlist is not valid.
+
+0xC00D1091
+
+NS_E_WMPCORE_WMX_LIST_ATTRIBUTE_NAME_EMPTY
+
+
+An empty string for playlist attribute name was found.
+
+0xC00D1092
+
+NS_E_WMPCORE_WMX_LIST_ATTRIBUTE_NAME_ILLEGAL
+
+
+A playlist attribute name that is not valid was found.
+
+0xC00D1093
+
+NS_E_WMPCORE_WMX_LIST_ATTRIBUTE_VALUE_EMPTY
+
+
+An empty string for a playlist attribute value was found.
+
+0xC00D1094
+
+NS_E_WMPCORE_WMX_LIST_ATTRIBUTE_VALUE_ILLEGAL
+
+
+An illegal value for a playlist attribute was found.
+
+0xC00D1095
+
+NS_E_WMPCORE_WMX_LIST_ITEM_ATTRIBUTE_NAME_EMPTY
+
+
+An empty string for a playlist item attribute name was found.
+
+0xC00D1096
+
+NS_E_WMPCORE_WMX_LIST_ITEM_ATTRIBUTE_NAME_ILLEGAL
+
+
+An illegal value for a playlist item attribute name was found.
+
+0xC00D1097
+
+NS_E_WMPCORE_WMX_LIST_ITEM_ATTRIBUTE_VALUE_EMPTY
+
+
+An illegal value for a playlist item attribute was found.
+
+0xC00D1098
+
+NS_E_WMPCORE_LIST_ENTRY_NO_REF
+
+
+The playlist does not contain any items.
+
+0xC00D1099
+
+NS_E_WMPCORE_MISNAMED_FILE
+
+
+Windows Media Player cannot play the file. The file is either corrupted or the Player does not support the format you are trying to play.
+
+0xC00D109A
+
+NS_E_WMPCORE_CODEC_NOT_TRUSTED
+
+
+The codec downloaded for this file does not appear to be properly signed, so it cannot be installed.
+
+0xC00D109B
+
+NS_E_WMPCORE_CODEC_NOT_FOUND
+
+
+Windows Media Player cannot play the file. One or more codecs required to play the file could not be found.
+
+0xC00D109C
+
+NS_E_WMPCORE_CODEC_DOWNLOAD_NOT_ALLOWED
+
+
+Windows Media Player cannot play the file because a required codec is not installed on your computer. To try downloading the codec, turn on the "Download codecs automatically" option.
+
+0xC00D109D
+
+NS_E_WMPCORE_ERROR_DOWNLOADING_PLAYLIST
+
+
+Windows Media Player encountered a problem while downloading the playlist. For additional assistance, click Web Help.
+
+0xC00D109E
+
+NS_E_WMPCORE_FAILED_TO_BUILD_PLAYLIST
+
+
+Failed to build the playlist.
+
+0xC00D109F
+
+NS_E_WMPCORE_PLAYLIST_ITEM_ALTERNATE_NONE
+
+
+Playlist has no alternates to switch into.
+
+0xC00D10A0
+
+NS_E_WMPCORE_PLAYLIST_ITEM_ALTERNATE_EXHAUSTED
+
+
+No more playlist alternates available to switch to.
+
+0xC00D10A1
+
+NS_E_WMPCORE_PLAYLIST_ITEM_ALTERNATE_NAME_NOT_FOUND
+
+
+Could not find the name of the alternate playlist to switch into.
+
+0xC00D10A2
+
+NS_E_WMPCORE_PLAYLIST_ITEM_ALTERNATE_MORPH_FAILED
+
+
+Failed to switch to an alternate for this media.
+
+0xC00D10A3
+
+NS_E_WMPCORE_PLAYLIST_ITEM_ALTERNATE_INIT_FAILED
+
+
+Failed to initialize an alternate for the media.
+
+0xC00D10A4
+
+NS_E_WMPCORE_MEDIA_ALTERNATE_REF_EMPTY
+
+
+No URL specified for the roll over Refs in the playlist file.
+
+0xC00D10A5
+
+NS_E_WMPCORE_PLAYLIST_NO_EVENT_NAME
+
+
+Encountered a playlist with no name.
+
+0xC00D10A6
+
+NS_E_WMPCORE_PLAYLIST_EVENT_ATTRIBUTE_ABSENT
+
+
+A required attribute in the event block of the playlist was not found.
+
+0xC00D10A7
+
+NS_E_WMPCORE_PLAYLIST_EVENT_EMPTY
+
+
+No items were found in the event block of the playlist.
+
+0xC00D10A8
+
+NS_E_WMPCORE_PLAYLIST_STACK_EMPTY
+
+
+No playlist was found while returning from a nested playlist.
+
+0xC00D10A9
+
+NS_E_WMPCORE_CURRENT_MEDIA_NOT_ACTIVE
+
+
+The media item is not active currently.
+
+0xC00D10AB
+
+NS_E_WMPCORE_USER_CANCEL
+
+
+Windows Media Player cannot perform the requested action because you chose to cancel it.
+
+0xC00D10AC
+
+NS_E_WMPCORE_PLAYLIST_REPEAT_EMPTY
+
+
+Windows Media Player encountered a problem with the playlist. The format of the playlist is not valid.
+
+0xC00D10AD
+
+NS_E_WMPCORE_PLAYLIST_REPEAT_START_MEDIA_NONE
+
+
+Media object corresponding to start of a playlist repeat block was not found.
+
+0xC00D10AE
+
+NS_E_WMPCORE_PLAYLIST_REPEAT_END_MEDIA_NONE
+
+
+Media object corresponding to the end of a playlist repeat block was not found.
+
+0xC00D10AF
+
+NS_E_WMPCORE_INVALID_PLAYLIST_URL
+
+
+The playlist URL supplied to the playlist manager is not valid.
+
+0xC00D10B0
+
+NS_E_WMPCORE_MISMATCHED_RUNTIME
+
+
+Windows Media Player cannot play the file because it is corrupted.
+
+0xC00D10B1
+
+NS_E_WMPCORE_PLAYLIST_IMPORT_FAILED_NO_ITEMS
+
+
+Windows Media Player cannot add the playlist to the library because the playlist does not contain any items.
+
+0xC00D10B2
+
+NS_E_WMPCORE_VIDEO_TRANSFORM_FILTER_INSERTION
+
+
+An error has occurred that could prevent the changing of the video contrast on this media.
+
+0xC00D10B3
+
+NS_E_WMPCORE_MEDIA_UNAVAILABLE
+
+
+Windows Media Player cannot play the file. If the file is located on the Internet, connect to the Internet. If the file is located on a removable storage card, insert the storage card.
+
+0xC00D10B4
+
+NS_E_WMPCORE_WMX_ENTRYREF_NO_REF
+
+
+The playlist contains an ENTRYREF for which no href was parsed. Check the syntax of playlist file.
+
+0xC00D10B5
+
+NS_E_WMPCORE_NO_PLAYABLE_MEDIA_IN_PLAYLIST
+
+
+Windows Media Player cannot play any items in the playlist. To find information about the problem, click the Now Playing tab, and then click the icon next to each file in the List pane.
+
+0xC00D10B6
+
+NS_E_WMPCORE_PLAYLIST_EMPTY_NESTED_PLAYLIST_SKIPPED_ITEMS
+
+
+Windows Media Player cannot play some or all of the items in the playlist because the playlist is nested.
+
+0xC00D10B7
+
+NS_E_WMPCORE_BUSY
+
+
+Windows Media Player cannot play the file at this time. Try again later.
+
+0xC00D10B8
+
+NS_E_WMPCORE_MEDIA_CHILD_PLAYLIST_UNAVAILABLE
+
+
+There is no child playlist available for this media item at this time.
+
+0xC00D10B9
+
+NS_E_WMPCORE_MEDIA_NO_CHILD_PLAYLIST
+
+
+There is no child playlist for this media item.
+
+0xC00D10BA
+
+NS_E_WMPCORE_FILE_NOT_FOUND
+
+
+Windows Media Player cannot find the file. The link from the item in the library to its associated digital media file might be broken. To fix the problem, try repairing the link or removing the item from the library.
+
+0xC00D10BB
+
+NS_E_WMPCORE_TEMP_FILE_NOT_FOUND
+
+
+The temporary file was not found.
+
+0xC00D10BC
+
+NS_E_WMDM_REVOKED
+
+
+Windows Media Player cannot sync the file because the device needs to be updated.
+
+0xC00D10BD
+
+NS_E_DDRAW_GENERIC
+
+
+Windows Media Player cannot play the video because there is a problem with your video card.
+
+0xC00D10BE
+
+NS_E_DISPLAY_MODE_CHANGE_FAILED
+
+
+Windows Media Player failed to change the screen mode for full-screen video playback.
+
+0xC00D10BF
+
+NS_E_PLAYLIST_CONTAINS_ERRORS
+
+
+Windows Media Player cannot play one or more files. For additional information, right-click an item that cannot be played, and then click Error Details.
+
+0xC00D10C0
+
+NS_E_CHANGING_PROXY_NAME
+
+
+Cannot change the proxy name if the proxy setting is not set to custom.
+
+0xC00D10C1
+
+NS_E_CHANGING_PROXY_PORT
+
+
+Cannot change the proxy port if the proxy setting is not set to custom.
+
+0xC00D10C2
+
+NS_E_CHANGING_PROXY_EXCEPTIONLIST
+
+
+Cannot change the proxy exception list if the proxy setting is not set to custom.
+
+0xC00D10C3
+
+NS_E_CHANGING_PROXYBYPASS
+
+
+Cannot change the proxy bypass flag if the proxy setting is not set to custom.
+
+0xC00D10C4
+
+NS_E_CHANGING_PROXY_PROTOCOL_NOT_FOUND
+
+
+Cannot find the specified protocol.
+
+0xC00D10C5
+
+NS_E_GRAPH_NOAUDIOLANGUAGE
+
+
+Cannot change the language settings. Either the graph has no audio or the audio only supports one language.
+
+0xC00D10C6
+
+NS_E_GRAPH_NOAUDIOLANGUAGESELECTED
+
+
+The graph has no audio language selected.
+
+0xC00D10C7
+
+NS_E_CORECD_NOTAMEDIACD
+
+
+This is not a media CD.
+
+0xC00D10C8
+
+NS_E_WMPCORE_MEDIA_URL_TOO_LONG
+
+
+Windows Media Player cannot play the file because the URL is too long.
+
+0xC00D10C9
+
+NS_E_WMPFLASH_CANT_FIND_COM_SERVER
+
+
+To play the selected item, you must install the Macromedia Flash Player. To download the Macromedia Flash Player, go to the Adobe website.
+
+0xC00D10CA
+
+NS_E_WMPFLASH_INCOMPATIBLEVERSION
+
+
+To play the selected item, you must install a later version of the Macromedia Flash Player. To download the Macromedia Flash Player, go to the Adobe website.
+
+0xC00D10CB
+
+NS_E_WMPOCXGRAPH_IE_DISALLOWS_ACTIVEX_CONTROLS
+
+
+Windows Media Player cannot play the file because your Internet security settings prohibit the use of ActiveX controls.
+
+0xC00D10CC
+
+NS_E_NEED_CORE_REFERENCE
+
+
+The use of this method requires an existing reference to the Player object.
+
+0xC00D10CD
+
+NS_E_MEDIACD_READ_ERROR
+
+
+Windows Media Player cannot play the CD. The disc might be dirty or damaged.
+
+0xC00D10CE
+
+NS_E_IE_DISALLOWS_ACTIVEX_CONTROLS
+
+
+Windows Media Player cannot play the file because your Internet security settings prohibit the use of ActiveX controls.
+
+0xC00D10CF
+
+NS_E_FLASH_PLAYBACK_NOT_ALLOWED
+
+
+Flash playback has been turned off in Windows Media Player.
+
+0xC00D10D0
+
+NS_E_UNABLE_TO_CREATE_RIP_LOCATION
+
+
+Windows Media Player cannot rip the CD because a valid rip location cannot be created.
+
+0xC00D10D1
+
+NS_E_WMPCORE_SOME_CODECS_MISSING
+
+
+Windows Media Player cannot play the file because a required codec is not installed on your computer.
+
+0xC00D10D2
+
+NS_E_WMP_RIP_FAILED
+
+
+Windows Media Player cannot rip one or more tracks from the CD.
+
+0xC00D10D3
+
+NS_E_WMP_FAILED_TO_RIP_TRACK
+
+
+Windows Media Player encountered a problem while ripping the track from the CD. For additional assistance, click Web Help.
+
+0xC00D10D4
+
+NS_E_WMP_ERASE_FAILED
+
+
+Windows Media Player encountered a problem while erasing the disc. For additional assistance, click Web Help.
+
+0xC00D10D5
+
+NS_E_WMP_FORMAT_FAILED
+
+
+Windows Media Player encountered a problem while formatting the device. For additional assistance, click Web Help.
+
+0xC00D10D6
+
+NS_E_WMP_CANNOT_BURN_NON_LOCAL_FILE
+
+
+This file cannot be burned to a CD because it is not located on your computer.
+
+0xC00D10D7
+
+NS_E_WMP_FILE_TYPE_CANNOT_BURN_TO_AUDIO_CD
+
+
+It is not possible to burn this file type to an audio CD. Windows Media Player can burn the following file types to an audio CD: WMA, MP3, or WAV.
+
+0xC00D10D8
+
+NS_E_WMP_FILE_DOES_NOT_FIT_ON_CD
+
+
+This file is too large to fit on a disc.
+
+0xC00D10D9
+
+NS_E_WMP_FILE_NO_DURATION
+
+
+It is not possible to determine if this file can fit on a disc because Windows Media Player cannot detect the length of the file. Playing the file before burning might enable the Player to detect the file length.
+
+0xC00D10DA
+
+NS_E_PDA_FAILED_TO_BURN
+
+
+Windows Media Player encountered a problem while burning the file to the disc. For additional assistance, click Web Help.
+
+0xC00D10DC
+
+NS_E_FAILED_DOWNLOAD_ABORT_BURN
+
+
+Windows Media Player cannot burn the audio CD because some items in the list that you chose to buy could not be downloaded from the online store.
+
+0xC00D10DD
+
+NS_E_WMPCORE_DEVICE_DRIVERS_MISSING
+
+
+Windows Media Player cannot play the file. Try using Windows Update or Device Manager to update the device drivers for your audio and video cards. For information about using Windows Update or Device Manager, see Windows Help.
+
+0xC00D1126
+
+NS_E_WMPIM_USEROFFLINE
+
+
+Windows Media Player has detected that you are not connected to the Internet. Connect to the Internet, and then try again.
+
+0xC00D1127
+
+NS_E_WMPIM_USERCANCELED
+
+
+The attempt to connect to the Internet was canceled.
+
+0xC00D1128
+
+NS_E_WMPIM_DIALUPFAILED
+
+
+The attempt to connect to the Internet failed.
+
+0xC00D1129
+
+NS_E_WINSOCK_ERROR_STRING
+
+
+Windows Media Player has encountered an unknown network error.
+
+0xC00D1130
+
+NS_E_WMPBR_NOLISTENER
+
+
+No window is currently listening to Backup and Restore events.
+
+0xC00D1131
+
+NS_E_WMPBR_BACKUPCANCEL
+
+
+Your media usage rights were not backed up because the backup was canceled.
+
+0xC00D1132
+
+NS_E_WMPBR_RESTORECANCEL
+
+
+Your media usage rights were not restored because the restoration was canceled.
+
+0xC00D1133
+
+NS_E_WMPBR_ERRORWITHURL
+
+
+An error occurred while backing up or restoring your media usage rights. A required web page cannot be displayed.
+
+0xC00D1134
+
+NS_E_WMPBR_NAMECOLLISION
+
+
+Your media usage rights were not backed up because the backup was canceled.
+
+0xC00D1137
+
+NS_E_WMPBR_DRIVE_INVALID
+
+
+Windows Media Player cannot restore your media usage rights from the specified location. Choose another location, and then try again.
+
+0xC00D1138
+
+NS_E_WMPBR_BACKUPRESTOREFAILED
+
+
+Windows Media Player cannot backup or restore your media usage rights.
+
+0xC00D1158
+
+NS_E_WMP_CONVERT_FILE_FAILED
+
+
+Windows Media Player cannot add the file to the library.
+
+0xC00D1159
+
+NS_E_WMP_CONVERT_NO_RIGHTS_ERRORURL
+
+
+Windows Media Player cannot add the file to the library because the content provider prohibits it. For assistance, contact the company that provided the file.
+
+0xC00D115A
+
+NS_E_WMP_CONVERT_NO_RIGHTS_NOERRORURL
+
+
+Windows Media Player cannot add the file to the library because the content provider prohibits it. For assistance, contact the company that provided the file.
+
+0xC00D115B
+
+NS_E_WMP_CONVERT_FILE_CORRUPT
+
+
+Windows Media Player cannot add the file to the library. The file might not be valid.
+
+0xC00D115C
+
+NS_E_WMP_CONVERT_PLUGIN_UNAVAILABLE_ERRORURL
+
+
+Windows Media Player cannot add the file to the library. The plug-in required to add the file is not installed properly. For assistance, click Web Help to display the website of the company that provided the file.
+
+0xC00D115D
+
+NS_E_WMP_CONVERT_PLUGIN_UNAVAILABLE_NOERRORURL
+
+
+Windows Media Player cannot add the file to the library. The plug-in required to add the file is not installed properly. For assistance, contact the company that provided the file.
+
+0xC00D115E
+
+NS_E_WMP_CONVERT_PLUGIN_UNKNOWN_FILE_OWNER
+
+
+Windows Media Player cannot add the file to the library. The plug-in required to add the file is not installed properly. For assistance, contact the company that provided the file.
+
+0xC00D1160
+
+NS_E_DVD_DISC_COPY_PROTECT_OUTPUT_NS
+
+
+Windows Media Player cannot play this DVD. Try installing an updated driver for your video card or obtaining a newer video card.
+
+0xC00D1161
+
+NS_E_DVD_DISC_COPY_PROTECT_OUTPUT_FAILED
+
+
+This DVD's resolution exceeds the maximum allowed by your component video outputs. Try reducing your screen resolution to 640 x 480, or turn off analog component outputs and use a VGA connection to your monitor.
+
+0xC00D1162
+
+NS_E_DVD_NO_SUBPICTURE_STREAM
+
+
+Windows Media Player cannot display subtitles or highlights in DVD menus. Reinstall the DVD decoder or contact the DVD drive manufacturer to obtain an updated decoder.
+
+0xC00D1163
+
+NS_E_DVD_COPY_PROTECT
+
+
+Windows Media Player cannot play this DVD because there is a problem with digital copy protection between your DVD drive, decoder, and video card. Try installing an updated driver for your video card.
+
+0xC00D1164
+
+NS_E_DVD_AUTHORING_PROBLEM
+
+
+Windows Media Player cannot play the DVD. The disc was created in a manner that the Player does not support.
+
+0xC00D1165
+
+NS_E_DVD_INVALID_DISC_REGION
+
+
+Windows Media Player cannot play the DVD because the disc prohibits playback in your region of the world. You must obtain a disc that is intended for your geographic region.
+
+0xC00D1166
+
+NS_E_DVD_COMPATIBLE_VIDEO_CARD
+
+
+Windows Media Player cannot play the DVD because your video card does not support DVD playback.
+
+0xC00D1167
+
+NS_E_DVD_MACROVISION
+
+
+Windows Media Player cannot play this DVD because it is not possible to turn on analog copy protection on the output display. Try installing an updated driver for your video card.
+
+0xC00D1168
+
+NS_E_DVD_SYSTEM_DECODER_REGION
+
+
+Windows Media Player cannot play the DVD because the region assigned to your DVD drive does not match the region assigned to your DVD decoder.
+
+0xC00D1169
+
+NS_E_DVD_DISC_DECODER_REGION
+
+
+Windows Media Player cannot play the DVD because the disc prohibits playback in your region of the world. You must obtain a disc that is intended for your geographic region.
+
+0xC00D116A
+
+NS_E_DVD_NO_VIDEO_STREAM
+
+
+Windows Media Player cannot play DVD video. You might need to adjust your Windows display settings. Open display settings in Control Panel, and then try lowering your screen resolution and color quality settings.
+
+0xC00D116B
+
+NS_E_DVD_NO_AUDIO_STREAM
+
+
+Windows Media Player cannot play DVD audio. Verify that your sound card is set up correctly, and then try again.
+
+0xC00D116C
+
+NS_E_DVD_GRAPH_BUILDING
+
+
+Windows Media Player cannot play DVD video. Close any open files and quit any other programs, and then try again. If the problem persists, restart your computer.
+
+0xC00D116D
+
+NS_E_DVD_NO_DECODER
+
+
+Windows Media Player cannot play the DVD because a compatible DVD decoder is not installed on your computer.
+
+0xC00D116E
+
+NS_E_DVD_PARENTAL
+
+
+Windows Media Player cannot play the scene because it has a parental rating higher than the rating that you are authorized to view.
+
+0xC00D116F
+
+NS_E_DVD_CANNOT_JUMP
+
+
+Windows Media Player cannot skip to the requested location on the DVD.
+
+0xC00D1170
+
+NS_E_DVD_DEVICE_CONTENTION
+
+
+Windows Media Player cannot play the DVD because it is currently in use by another program. Quit the other program that is using the DVD, and then try again.
+
+0xC00D1171
+
+NS_E_DVD_NO_VIDEO_MEMORY
+
+
+Windows Media Player cannot play DVD video. You might need to adjust your Windows display settings. Open display settings in Control Panel, and then try lowering your screen resolution and color quality settings.
+
+0xC00D1172
+
+NS_E_DVD_CANNOT_COPY_PROTECTED
+
+
+Windows Media Player cannot rip the DVD because it is copy protected.
+
+0xC00D1173
+
+NS_E_DVD_REQUIRED_PROPERTY_NOT_SET
+
+
+One of more of the required properties has not been set.
+
+0xC00D1174
+
+NS_E_DVD_INVALID_TITLE_CHAPTER
+
+
+The specified title and/or chapter number does not exist on this DVD.
+
+0xC00D1176
+
+NS_E_NO_CD_BURNER
+
+
+Windows Media Player cannot burn the files because the Player cannot find a burner. If the burner is connected properly, try using Windows Update to install the latest device driver.
+
+0xC00D1177
+
+NS_E_DEVICE_IS_NOT_READY
+
+
+Windows Media Player does not detect storage media in the selected device. Insert storage media into the device, and then try again.
+
+0xC00D1178
+
+NS_E_PDA_UNSUPPORTED_FORMAT
+
+
+Windows Media Player cannot sync this file. The Player might not support the file type.
+
+0xC00D1179
+
+NS_E_NO_PDA
+
+
+Windows Media Player does not detect a portable device. Connect your portable device, and then try again.
+
+0xC00D117A
+
+NS_E_PDA_UNSPECIFIED_ERROR
+
+
+Windows Media Player encountered an error while communicating with the device. The storage card on the device might be full, the device might be turned off, or the device might not allow playlists or folders to be created on it.
+
+0xC00D117B
+
+NS_E_MEMSTORAGE_BAD_DATA
+
+
+Windows Media Player encountered an error while burning a CD.
+
+0xC00D117C
+
+NS_E_PDA_FAIL_SELECT_DEVICE
+
+
+Windows Media Player encountered an error while communicating with a portable device or CD drive.
+
+0xC00D117D
+
+NS_E_PDA_FAIL_READ_WAVE_FILE
+
+
+Windows Media Player cannot open the WAV file.
+
+0xC00D117E
+
+NS_E_IMAPI_LOSSOFSTREAMING
+
+
+Windows Media Player failed to burn all the files to the CD. Select a slower recording speed, and then try again.
+
+0xC00D117F
+
+NS_E_PDA_DEVICE_FULL
+
+
+There is not enough storage space on the portable device to complete this operation. Delete some unneeded files on the portable device, and then try again.
+
+0xC00D1180
+
+NS_E_FAIL_LAUNCH_ROXIO_PLUGIN
+
+
+Windows Media Player cannot burn the files. Verify that your burner is connected properly, and then try again. If the problem persists, reinstall the Player.
+
+0xC00D1181
+
+NS_E_PDA_DEVICE_FULL_IN_SESSION
+
+
+Windows Media Player did not sync some files to the device because there is not enough storage space on the device.
+
+0xC00D1182
+
+NS_E_IMAPI_MEDIUM_INVALIDTYPE
+
+
+The disc in the burner is not valid. Insert a blank disc into the burner, and then try again.
+
+0xC00D1183
+
+NS_E_PDA_MANUALDEVICE
+
+
+Windows Media Player cannot perform the requested action because the device does not support sync.
+
+0xC00D1184
+
+NS_E_PDA_PARTNERSHIPNOTEXIST
+
+
+To perform the requested action, you must first set up sync with the device.
+
+0xC00D1185
+
+NS_E_PDA_CANNOT_CREATE_ADDITIONAL_SYNC_RELATIONSHIP
+
+
+You have already created sync partnerships with 16 devices. To create a new sync partnership, you must first end an existing partnership.
+
+0xC00D1186
+
+NS_E_PDA_NO_TRANSCODE_OF_DRM
+
+
+Windows Media Player cannot sync the file because protected files cannot be converted to the required quality level or file format.
+
+0xC00D1187
+
+NS_E_PDA_TRANSCODECACHEFULL
+
+
+The folder that stores converted files is full. Either empty the folder or increase its size, and then try again.
+
+0xC00D1188
+
+NS_E_PDA_TOO_MANY_FILE_COLLISIONS
+
+
+There are too many files with the same name in the folder on the device. Change the file name or sync to a different folder.
+
+0xC00D1189
+
+NS_E_PDA_CANNOT_TRANSCODE
+
+
+Windows Media Player cannot convert the file to the format required by the device.
+
+0xC00D118A
+
+NS_E_PDA_TOO_MANY_FILES_IN_DIRECTORY
+
+
+You have reached the maximum number of files your device allows in a folder. If your device supports playback from subfolders, try creating subfolders on the device and storing some files in them.
+
+0xC00D118B
+
+NS_E_PROCESSINGSHOWSYNCWIZARD
+
+
+Windows Media Player is already trying to start the Device Setup Wizard.
+
+0xC00D118C
+
+NS_E_PDA_TRANSCODE_NOT_PERMITTED
+
+
+Windows Media Player cannot convert this file format. If an updated version of the codec used to compress this file is available, install it and then try to sync the file again.
+
+0xC00D118D
+
+NS_E_PDA_INITIALIZINGDEVICES
+
+
+Windows Media Player is busy setting up devices. Try again later.
+
+0xC00D118E
+
+NS_E_PDA_OBSOLETE_SP
+
+
+Your device is using an outdated driver that is no longer supported by Windows Media Player. For additional assistance, click Web Help.
+
+0xC00D118F
+
+NS_E_PDA_TITLE_COLLISION
+
+
+Windows Media Player cannot sync the file because a file with the same name already exists on the device. Change the file name or try to sync the file to a different folder.
+
+0xC00D1190
+
+NS_E_PDA_DEVICESUPPORTDISABLED
+
+
+Automatic and manual sync have been turned off temporarily. To sync to a device, restart Windows Media Player.
+
+0xC00D1191
+
+NS_E_PDA_NO_LONGER_AVAILABLE
+
+
+This device is not available. Connect the device to the computer, and then try again.
+
+0xC00D1192
+
+NS_E_PDA_ENCODER_NOT_RESPONDING
+
+
+Windows Media Player cannot sync the file because an error occurred while converting the file to another quality level or format. If the problem persists, remove the file from the list of files to sync.
+
+0xC00D1193
+
+NS_E_PDA_CANNOT_SYNC_FROM_LOCATION
+
+
+Windows Media Player cannot sync the file to your device. The file might be stored in a location that is not supported. Copy the file from its current location to your hard disk, add it to your library, and then try to sync the file again.
+
+0xC00D1194
+
+NS_E_WMP_PROTOCOL_PROBLEM
+
+
+Windows Media Player cannot open the specified URL. Verify that the Player is configured to use all available protocols, and then try again.
+
+0xC00D1195
+
+NS_E_WMP_NO_DISK_SPACE
+
+
+Windows Media Player cannot perform the requested action because there is not enough storage space on your computer. Delete some unneeded files on your hard disk, and then try again.
+
+0xC00D1196
+
+NS_E_WMP_LOGON_FAILURE
+
+
+The server denied access to the file. Verify that you are using the correct user name and password.
+
+0xC00D1197
+
+NS_E_WMP_CANNOT_FIND_FILE
+
+
+Windows Media Player cannot find the file. If you are trying to play, burn, or sync an item that is in your library, the item might point to a file that has been moved, renamed, or deleted.
+
+0xC00D1198
+
+NS_E_WMP_SERVER_INACCESSIBLE
+
+
+Windows Media Player cannot connect to the server. The server name might not be correct, the server might not be available, or your proxy settings might not be correct.
+
+0xC00D1199
+
+NS_E_WMP_UNSUPPORTED_FORMAT
+
+
+Windows Media Player cannot play the file. The Player might not support the file type or might not support the codec that was used to compress the file.
+
+0xC00D119A
+
+NS_E_WMP_DSHOW_UNSUPPORTED_FORMAT
+
+
+Windows Media Player cannot play the file. The Player might not support the file type or a required codec might not be installed on your computer.
+
+0xC00D119B
+
+NS_E_WMP_PLAYLIST_EXISTS
+
+
+Windows Media Player cannot create the playlist because the name already exists. Type a different playlist name.
+
+0xC00D119C
+
+NS_E_WMP_NONMEDIA_FILES
+
+
+Windows Media Player cannot delete the playlist because it contains items that are not digital media files. Any digital media files in the playlist were deleted.
+
+0xC00D119D
+
+NS_E_WMP_INVALID_ASX
+
+
+The playlist cannot be opened because it is stored in a shared folder on another computer. If possible, move the playlist to the playlists folder on your computer.
+
+0xC00D119E
+
+NS_E_WMP_ALREADY_IN_USE
+
+
+Windows Media Player is already in use. Stop playing any items, close all Player dialog boxes, and then try again.
+
+0xC00D119F
+
+NS_E_WMP_IMAPI_FAILURE
+
+
+Windows Media Player encountered an error while burning. Verify that the burner is connected properly and that the disc is clean and not damaged.
+
+0xC00D11A0
+
+NS_E_WMP_WMDM_FAILURE
+
+
+Windows Media Player has encountered an unknown error with your portable device. Reconnect your portable device, and then try again.
+
+0xC00D11A1
+
+NS_E_WMP_CODEC_NEEDED_WITH_4CC
+
+
+A codec is required to play this file. To determine if this codec is available to download from the web, click Web Help.
+
+0xC00D11A2
+
+NS_E_WMP_CODEC_NEEDED_WITH_FORMATTAG
+
+
+An audio codec is needed to play this file. To determine if this codec is available to download from the web, click Web Help.
+
+0xC00D11A3
+
+NS_E_WMP_MSSAP_NOT_AVAILABLE
+
+
+To play the file, you must install the latest Windows service pack. To install the service pack from the Windows Update website, click Web Help.
+
+0xC00D11A4
+
+NS_E_WMP_WMDM_INTERFACEDEAD
+
+
+Windows Media Player no longer detects a portable device. Reconnect your portable device, and then try again.
+
+0xC00D11A5
+
+NS_E_WMP_WMDM_NOTCERTIFIED
+
+
+Windows Media Player cannot sync the file because the portable device does not support protected files.
+
+0xC00D11A6
+
+NS_E_WMP_WMDM_LICENSE_NOTEXIST
+
+
+This file does not have sync rights. If you obtained this file from an online store, go to the online store to get sync rights.
+
+0xC00D11A7
+
+NS_E_WMP_WMDM_LICENSE_EXPIRED
+
+
+Windows Media Player cannot sync the file because the sync rights have expired. Go to the content provider's online store to get new sync rights.
+
+0xC00D11A8
+
+NS_E_WMP_WMDM_BUSY
+
+
+The portable device is already in use. Wait until the current task finishes or quit other programs that might be using the portable device, and then try again.
+
+0xC00D11A9
+
+NS_E_WMP_WMDM_NORIGHTS
+
+
+Windows Media Player cannot sync the file because the content provider or device prohibits it. You might be able to resolve this problem by going to the content provider's online store to get sync rights.
+
+0xC00D11AA
+
+NS_E_WMP_WMDM_INCORRECT_RIGHTS
+
+
+The content provider has not granted you the right to sync this file. Go to the content provider's online store to get sync rights.
+
+0xC00D11AB
+
+NS_E_WMP_IMAPI_GENERIC
+
+
+Windows Media Player cannot burn the files to the CD. Verify that the disc is clean and not damaged. If necessary, select a slower recording speed or try a different brand of blank discs.
+
+0xC00D11AD
+
+NS_E_WMP_IMAPI_DEVICE_NOTPRESENT
+
+
+Windows Media Player cannot burn the files. Verify that the burner is connected properly, and then try again.
+
+0xC00D11AE
+
+NS_E_WMP_IMAPI_DEVICE_BUSY
+
+
+Windows Media Player cannot burn the files. Verify that the burner is connected properly and that the disc is clean and not damaged. If the burner is already in use, wait until the current task finishes or quit other programs that might be using the burner.
+
+0xC00D11AF
+
+NS_E_WMP_IMAPI_LOSS_OF_STREAMING
+
+
+Windows Media Player cannot burn the files to the CD.
+
+0xC00D11B0
+
+NS_E_WMP_SERVER_UNAVAILABLE
+
+
+Windows Media Player cannot play the file. The server might not be available or there might be a problem with your network or firewall settings.
+
+0xC00D11B1
+
+NS_E_WMP_FILE_OPEN_FAILED
+
+
+Windows Media Player encountered a problem while playing the file. For additional assistance, click Web Help.
+
+0xC00D11B2
+
+NS_E_WMP_VERIFY_ONLINE
+
+
+Windows Media Player must connect to the Internet to verify the file's media usage rights. Connect to the Internet, and then try again.
+
+0xC00D11B3
+
+NS_E_WMP_SERVER_NOT_RESPONDING
+
+
+Windows Media Player cannot play the file because a network error occurred. The server might not be available. Verify that you are connected to the network and that your proxy settings are correct.
+
+0xC00D11B4
+
+NS_E_WMP_DRM_CORRUPT_BACKUP
+
+
+Windows Media Player cannot restore your media usage rights because it could not find any backed up rights on your computer.
+
+0xC00D11B5
+
+NS_E_WMP_DRM_LICENSE_SERVER_UNAVAILABLE
+
+
+Windows Media Player cannot download media usage rights because the server is not available (for example, the server might be busy or not online).
+
+0xC00D11B6
+
+NS_E_WMP_NETWORK_FIREWALL
+
+
+Windows Media Player cannot play the file. A network firewall might be preventing the Player from opening the file by using the UDP transport protocol. If you typed a URL in the Open URL dialog box, try using a different transport protocol (for example, "http:").
+
+0xC00D11B7
+
+NS_E_WMP_NO_REMOVABLE_MEDIA
+
+
+Insert the removable media, and then try again.
+
+0xC00D11B8
+
+NS_E_WMP_PROXY_CONNECT_TIMEOUT
+
+
+Windows Media Player cannot play the file because the proxy server is not responding. The proxy server might be temporarily unavailable or your Player proxy settings might not be valid.
+
+0xC00D11B9
+
+NS_E_WMP_NEED_UPGRADE
+
+
+To play the file, you might need to install a later version of Windows Media Player. On the Help menu, click Check for Updates, and then follow the instructions. For additional assistance, click Web Help.
+
+0xC00D11BA
+
+NS_E_WMP_AUDIO_HW_PROBLEM
+
+
+Windows Media Player cannot play the file because there is a problem with your sound device. There might not be a sound device installed on your computer, it might be in use by another program, or it might not be functioning properly.
+
+0xC00D11BB
+
+NS_E_WMP_INVALID_PROTOCOL
+
+
+Windows Media Player cannot play the file because the specified protocol is not supported. If you typed a URL in the Open URL dialog box, try using a different transport protocol (for example, "http:" or "rtsp:").
+
+0xC00D11BC
+
+NS_E_WMP_INVALID_LIBRARY_ADD
+
+
+Windows Media Player cannot add the file to the library because the file format is not supported.
+
+0xC00D11BD
+
+NS_E_WMP_MMS_NOT_SUPPORTED
+
+
+Windows Media Player cannot play the file because the specified protocol is not supported. If you typed a URL in the Open URL dialog box, try using a different transport protocol (for example, "mms:").
+
+0xC00D11BE
+
+NS_E_WMP_NO_PROTOCOLS_SELECTED
+
+
+Windows Media Player cannot play the file because there are no streaming protocols selected. Select one or more protocols, and then try again.
+
+0xC00D11BF
+
+NS_E_WMP_GOFULLSCREEN_FAILED
+
+
+Windows Media Player cannot switch to Full Screen. You might need to adjust your Windows display settings. Open display settings in Control Panel, and then try setting Hardware acceleration to Full.
+
+0xC00D11C0
+
+NS_E_WMP_NETWORK_ERROR
+
+
+Windows Media Player cannot play the file because a network error occurred. The server might not be available (for example, the server is busy or not online) or you might not be connected to the network.
+
+0xC00D11C1
+
+NS_E_WMP_CONNECT_TIMEOUT
+
+
+Windows Media Player cannot play the file because the server is not responding. Verify that you are connected to the network, and then try again later.
+
+0xC00D11C2
+
+NS_E_WMP_MULTICAST_DISABLED
+
+
+Windows Media Player cannot play the file because the multicast protocol is not enabled. On the Tools menu, click Options, click the Network tab, and then select the Multicast check box. For additional assistance, click Web Help.
+
+0xC00D11C3
+
+NS_E_WMP_SERVER_DNS_TIMEOUT
+
+
+Windows Media Player cannot play the file because a network problem occurred. Verify that you are connected to the network, and then try again later.
+
+0xC00D11C4
+
+NS_E_WMP_PROXY_NOT_FOUND
+
+
+Windows Media Player cannot play the file because the network proxy server cannot be found. Verify that your proxy settings are correct, and then try again.
+
+0xC00D11C5
+
+NS_E_WMP_TAMPERED_CONTENT
+
+
+Windows Media Player cannot play the file because it is corrupted.
+
+0xC00D11C6
+
+NS_E_WMP_OUTOFMEMORY
+
+
+Your computer is running low on memory. Quit other programs, and then try again.
+
+0xC00D11C7
+
+NS_E_WMP_AUDIO_CODEC_NOT_INSTALLED
+
+
+Windows Media Player cannot play, burn, rip, or sync the file because a required audio codec is not installed on your computer.
+
+0xC00D11C8
+
+NS_E_WMP_VIDEO_CODEC_NOT_INSTALLED
+
+
+Windows Media Player cannot play the file because the required video codec is not installed on your computer.
+
+0xC00D11C9
+
+NS_E_WMP_IMAPI_DEVICE_INVALIDTYPE
+
+
+Windows Media Player cannot burn the files. If the burner is busy, wait for the current task to finish. If necessary, verify that the burner is connected properly and that you have installed the latest device driver.
+
+0xC00D11CA
+
+NS_E_WMP_DRM_DRIVER_AUTH_FAILURE
+
+
+Windows Media Player cannot play the protected file because there is a problem with your sound device. Try installing a new device driver or use a different sound device.
+
+0xC00D11CB
+
+NS_E_WMP_NETWORK_RESOURCE_FAILURE
+
+
+Windows Media Player encountered a network error. Restart the Player.
+
+0xC00D11CC
+
+NS_E_WMP_UPGRADE_APPLICATION
+
+
+Windows Media Player is not installed properly. Reinstall the Player.
+
+0xC00D11CD
+
+NS_E_WMP_UNKNOWN_ERROR
+
+
+Windows Media Player encountered an unknown error. For additional assistance, click Web Help.
+
+0xC00D11CE
+
+NS_E_WMP_INVALID_KEY
+
+
+Windows Media Player cannot play the file because the required codec is not valid.
+
+0xC00D11CF
+
+NS_E_WMP_CD_ANOTHER_USER
+
+
+The CD drive is in use by another user. Wait for the task to complete, and then try again.
+
+0xC00D11D0
+
+NS_E_WMP_DRM_NEEDS_AUTHORIZATION
+
+
+Windows Media Player cannot play, sync, or burn the protected file because a problem occurred with the Windows Media Digital Rights Management (DRM) system. You might need to connect to the Internet to update your DRM components. For additional assistance, click Web Help.
+
+0xC00D11D1
+
+NS_E_WMP_BAD_DRIVER
+
+
+Windows Media Player cannot play the file because there might be a problem with your sound or video device. Try installing an updated device driver.
+
+0xC00D11D2
+
+NS_E_WMP_ACCESS_DENIED
+
+
+Windows Media Player cannot access the file. The file might be in use, you might not have access to the computer where the file is stored, or your proxy settings might not be correct.
+
+0xC00D11D3
+
+NS_E_WMP_LICENSE_RESTRICTS
+
+
+The content provider prohibits this action. Go to the content provider's online store to get new media usage rights.
+
+0xC00D11D4
+
+NS_E_WMP_INVALID_REQUEST
+
+
+Windows Media Player cannot perform the requested action at this time.
+
+0xC00D11D5
+
+NS_E_WMP_CD_STASH_NO_SPACE
+
+
+Windows Media Player cannot burn the files because there is not enough free disk space to store the temporary files. Delete some unneeded files on your hard disk, and then try again.
+
+0xC00D11D6
+
+NS_E_WMP_DRM_NEW_HARDWARE
+
+
+Your media usage rights have become corrupted or are no longer valid. This might happen if you have replaced hardware components in your computer.
+
+0xC00D11D7
+
+NS_E_WMP_DRM_INVALID_SIG
+
+
+The required Windows Media Digital Rights Management (DRM) component cannot be validated. You might be able resolve the problem by reinstalling the Player.
+
+0xC00D11D8
+
+NS_E_WMP_DRM_CANNOT_RESTORE
+
+
+You have exceeded your restore limit for the day. Try restoring your media usage rights tomorrow.
+
+0xC00D11D9
+
+NS_E_WMP_BURN_DISC_OVERFLOW
+
+
+Some files might not fit on the CD. The required space cannot be calculated accurately because some files might be missing duration information. To ensure the calculation is accurate, play the files that are missing duration information.
+
+0xC00D11DA
+
+NS_E_WMP_DRM_GENERIC_LICENSE_FAILURE
+
+
+Windows Media Player cannot verify the file's media usage rights. If you obtained this file from an online store, go to the online store to get the necessary rights.
+
+0xC00D11DB
+
+NS_E_WMP_DRM_NO_SECURE_CLOCK
+
+
+It is not possible to sync because this device's internal clock is not set correctly. To set the clock, select the option to set the device clock on the Privacy tab of the Options dialog box, connect to the Internet, and then sync the device again. For additional assistance, click Web Help.
+
+0xC00D11DC
+
+NS_E_WMP_DRM_NO_RIGHTS
+
+
+Windows Media Player cannot play, burn, rip, or sync the protected file because you do not have the appropriate rights.
+
+0xC00D11DD
+
+NS_E_WMP_DRM_INDIV_FAILED
+
+
+Windows Media Player encountered an error during upgrade.
+
+0xC00D11DE
+
+NS_E_WMP_SERVER_NONEWCONNECTIONS
+
+
+Windows Media Player cannot connect to the server because it is not accepting any new connections. This could be because it has reached its maximum connection limit. Please try again later.
+
+0xC00D11DF
+
+NS_E_WMP_MULTIPLE_ERROR_IN_PLAYLIST
+
+
+A number of queued files cannot be played. To find information about the problem, click the Now Playing tab, and then click the icon next to each file in the List pane.
+
+0xC00D11E0
+
+NS_E_WMP_IMAPI2_ERASE_FAIL
+
+
+Windows Media Player encountered an error while erasing the rewritable CD or DVD. Verify that the CD or DVD burner is connected properly and that the disc is clean and not damaged.
+
+0xC00D11E1
+
+NS_E_WMP_IMAPI2_ERASE_DEVICE_BUSY
+
+
+Windows Media Player cannot erase the rewritable CD or DVD. Verify that the CD or DVD burner is connected properly and that the disc is clean and not damaged. If the burner is already in use, wait until the current task finishes or quit other programs that might be using the burner.
+
+0xC00D11E2
+
+NS_E_WMP_DRM_COMPONENT_FAILURE
+
+
+A Windows Media Digital Rights Management (DRM) component encountered a problem. If you are trying to use a file that you obtained from an online store, try going to the online store and getting the appropriate usage rights.
+
+0xC00D11E3
+
+NS_E_WMP_DRM_NO_DEVICE_CERT
+
+
+It is not possible to obtain device's certificate. Please contact the device manufacturer for a firmware update or for other steps to resolve this problem.
+
+0xC00D11E4
+
+NS_E_WMP_SERVER_SECURITY_ERROR
+
+
+Windows Media Player encountered an error when connecting to the server. The security information from the server could not be validated.
+
+0xC00D11E5
+
+NS_E_WMP_AUDIO_DEVICE_LOST
+
+
+An audio device was disconnected or reconfigured. Verify that the audio device is connected, and then try to play the item again.
+
+0xC00D11E6
+
+NS_E_WMP_IMAPI_MEDIA_INCOMPATIBLE
+
+
+Windows Media Player could not complete burning because the disc is not compatible with your drive. Try inserting a different kind of recordable media or use a disc that supports a write speed that is compatible with your drive.
+
+0xC00D11EE
+
+NS_E_SYNCWIZ_DEVICE_FULL
+
+
+Windows Media Player cannot save the sync settings because your device is full. Delete some unneeded files on your device and then try again.
+
+0xC00D11EF
+
+NS_E_SYNCWIZ_CANNOT_CHANGE_SETTINGS
+
+
+It is not possible to change sync settings at this time. Try again later.
+
+0xC00D11F0
+
+NS_E_TRANSCODE_DELETECACHEERROR
+
+
+Windows Media Player cannot delete these files currently. If the Player is synchronizing, wait until it is complete and then try again.
+
+0xC00D11F8
+
+NS_E_CD_NO_BUFFERS_READ
+
+
+Windows Media Player could not use digital mode to read the CD. The Player has automatically switched the CD drive to analog mode. To switch back to digital mode, use the Devices tab. For additional assistance, click Web Help.
+
+0xC00D11F9
+
+NS_E_CD_EMPTY_TRACK_QUEUE
+
+
+No CD track was specified for playback.
+
+0xC00D11FA
+
+NS_E_CD_NO_READER
+
+
+The CD filter was not able to create the CD reader.
+
+0xC00D11FB
+
+NS_E_CD_ISRC_INVALID
+
+
+Invalid ISRC code.
+
+0xC00D11FC
+
+NS_E_CD_MEDIA_CATALOG_NUMBER_INVALID
+
+
+Invalid Media Catalog Number.
+
+0xC00D11FD
+
+NS_E_SLOW_READ_DIGITAL_WITH_ERRORCORRECTION
+
+
+Windows Media Player cannot play audio CDs correctly because the CD drive is slow and error correction is turned on. To increase performance, turn off playback error correction for this drive.
+
+0xC00D11FE
+
+NS_E_CD_SPEEDDETECT_NOT_ENOUGH_READS
+
+
+Windows Media Player cannot estimate the CD drive's playback speed because the CD track is too short.
+
+0xC00D11FF
+
+NS_E_CD_QUEUEING_DISABLED
+
+
+Cannot queue the CD track because queuing is not enabled.
+
+0xC00D1202
+
+NS_E_WMP_DRM_ACQUIRING_LICENSE
+
+
+Windows Media Player cannot download additional media usage rights until the current download is complete.
+
+0xC00D1203
+
+NS_E_WMP_DRM_LICENSE_EXPIRED
+
+
+The media usage rights for this file have expired or are no longer valid. If you obtained the file from an online store, sign in to the store, and then try again.
+
+0xC00D1204
+
+NS_E_WMP_DRM_LICENSE_NOTACQUIRED
+
+
+Windows Media Player cannot download the media usage rights for the file. If you obtained the file from an online store, sign in to the store, and then try again.
+
+0xC00D1205
+
+NS_E_WMP_DRM_LICENSE_NOTENABLED
+
+
+The media usage rights for this file are not yet valid. To see when they will become valid, right-click the file in the library, click Properties, and then click the Media Usage Rights tab.
+
+0xC00D1206
+
+NS_E_WMP_DRM_LICENSE_UNUSABLE
+
+
+The media usage rights for this file are not valid. If you obtained this file from an online store, contact the store for assistance.
+
+0xC00D1207
+
+NS_E_WMP_DRM_LICENSE_CONTENT_REVOKED
+
+
+The content provider has revoked the media usage rights for this file. If you obtained this file from an online store, ask the store if a new version of the file is available.
+
+0xC00D1208
+
+NS_E_WMP_DRM_LICENSE_NOSAP
+
+
+The media usage rights for this file require a feature that is not supported in your current version of Windows Media Player or your current version of Windows. Try installing the latest version of the Player. If you obtained this file from an online store, contact the store for further assistance.
+
+0xC00D1209
+
+NS_E_WMP_DRM_UNABLE_TO_ACQUIRE_LICENSE
+
+
+Windows Media Player cannot download media usage rights at this time. Try again later.
+
+0xC00D120A
+
+NS_E_WMP_LICENSE_REQUIRED
+
+
+Windows Media Player cannot play, burn, or sync the file because the media usage rights are missing. If you obtained the file from an online store, sign in to the store, and then try again.
+
+0xC00D120B
+
+NS_E_WMP_PROTECTED_CONTENT
+
+
+Windows Media Player cannot play, burn, or sync the file because the media usage rights are missing. If you obtained the file from an online store, sign in to the store, and then try again.
+
+0xC00D122A
+
+NS_E_WMP_POLICY_VALUE_NOT_CONFIGURED
+
+
+Windows Media Player cannot read a policy. This can occur when the policy does not exist in the registry or when the registry cannot be read.
+
+0xC00D1234
+
+NS_E_PDA_CANNOT_SYNC_FROM_INTERNET
+
+
+Windows Media Player cannot sync content streamed directly from the Internet. If possible, download the file to your computer, and then try to sync the file.
+
+0xC00D1235
+
+NS_E_PDA_CANNOT_SYNC_INVALID_PLAYLIST
+
+
+This playlist is not valid or is corrupted. Create a new playlist using Windows Media Player, then sync the new playlist instead.
+
+0xC00D1236
+
+NS_E_PDA_FAILED_TO_SYNCHRONIZE_FILE
+
+
+Windows Media Player encountered a problem while synchronizing the file to the device. For additional assistance, click Web Help.
+
+0xC00D1237
+
+NS_E_PDA_SYNC_FAILED
+
+
+Windows Media Player encountered an error while synchronizing to the device.
+
+0xC00D1238
+
+NS_E_PDA_DELETE_FAILED
+
+
+Windows Media Player cannot delete a file from the device.
+
+0xC00D1239
+
+NS_E_PDA_FAILED_TO_RETRIEVE_FILE
+
+
+Windows Media Player cannot copy a file from the device to your library.
+
+0xC00D123A
+
+NS_E_PDA_DEVICE_NOT_RESPONDING
+
+
+Windows Media Player cannot communicate with the device because the device is not responding. Try reconnecting the device, resetting the device, or contacting the device manufacturer for updated firmware.
+
+0xC00D123B
+
+NS_E_PDA_FAILED_TO_TRANSCODE_PHOTO
+
+
+Windows Media Player cannot sync the picture to the device because a problem occurred while converting the file to another quality level or format. The original file might be damaged or corrupted.
+
+0xC00D123C
+
+NS_E_PDA_FAILED_TO_ENCRYPT_TRANSCODED_FILE
+
+
+Windows Media Player cannot convert the file. The file might have been encrypted by the Encrypted File System (EFS). Try decrypting the file first and then synchronizing it. For information about how to decrypt a file, see Windows Help and Support.
+
+0xC00D123D
+
+NS_E_PDA_CANNOT_TRANSCODE_TO_AUDIO
+
+
+Your device requires that this file be converted in order to play on the device. However, the device either does not support playing audio, or Windows Media Player cannot convert the file to an audio format that is supported by the device.
+
+0xC00D123E
+
+NS_E_PDA_CANNOT_TRANSCODE_TO_VIDEO
+
+
+Your device requires that this file be converted in order to play on the device. However, the device either does not support playing video, or Windows Media Player cannot convert the file to a video format that is supported by the device.
+
+0xC00D123F
+
+NS_E_PDA_CANNOT_TRANSCODE_TO_IMAGE
+
+
+Your device requires that this file be converted in order to play on the device. However, the device either does not support displaying pictures, or Windows Media Player cannot convert the file to a picture format that is supported by the device.
+
+0xC00D1240
+
+NS_E_PDA_RETRIEVED_FILE_FILENAME_TOO_LONG
+
+
+Windows Media Player cannot sync the file to your computer because the file name is too long. Try renaming the file on the device.
+
+0xC00D1241
+
+NS_E_PDA_CEWMDM_DRM_ERROR
+
+
+Windows Media Player cannot sync the file because the device is not responding. This typically occurs when there is a problem with the device firmware. For additional assistance, click Web Help.
+
+0xC00D1242
+
+NS_E_INCOMPLETE_PLAYLIST
+
+
+Incomplete playlist.
+
+0xC00D1243
+
+NS_E_PDA_SYNC_RUNNING
+
+
+It is not possible to perform the requested action because sync is in progress. You can either stop sync or wait for it to complete, and then try again.
+
+0xC00D1244
+
+NS_E_PDA_SYNC_LOGIN_ERROR
+
+
+Windows Media Player cannot sync the subscription content because you are not signed in to the online store that provided it. Sign in to the online store, and then try again.
+
+0xC00D1245
+
+NS_E_PDA_TRANSCODE_CODEC_NOT_FOUND
+
+
+Windows Media Player cannot convert the file to the format required by the device. One or more codecs required to convert the file could not be found.
+
+0xC00D1246
+
+NS_E_CANNOT_SYNC_DRM_TO_NON_JANUS_DEVICE
+
+
+It is not possible to sync subscription files to this device.
+
+0xC00D1247
+
+NS_E_CANNOT_SYNC_PREVIOUS_SYNC_RUNNING
+
+
+Your device is operating slowly or is not responding. Until the device responds, it is not possible to sync again. To return the device to normal operation, try disconnecting it from the computer or resetting it.
+
+0xC00D125C
+
+NS_E_WMP_HWND_NOTFOUND
+
+
+The Windows Media Player download manager cannot function properly because the Player main window cannot be found. Try restarting the Player.
+
+0xC00D125D
+
+NS_E_BKGDOWNLOAD_WRONG_NO_FILES
+
+
+Windows Media Player encountered a download that has the wrong number of files. This might occur if another program is trying to create jobs with the same signature as the Player.
+
+0xC00D125E
+
+NS_E_BKGDOWNLOAD_COMPLETECANCELLEDJOB
+
+
+Windows Media Player tried to complete a download that was already canceled. The file will not be available.
+
+0xC00D125F
+
+NS_E_BKGDOWNLOAD_CANCELCOMPLETEDJOB
+
+
+Windows Media Player tried to cancel a download that was already completed. The file will not be removed.
+
+0xC00D1260
+
+NS_E_BKGDOWNLOAD_NOJOBPOINTER
+
+
+Windows Media Player is trying to access a download that is not valid.
+
+0xC00D1261
+
+NS_E_BKGDOWNLOAD_INVALIDJOBSIGNATURE
+
+
+This download was not created by Windows Media Player.
+
+0xC00D1262
+
+NS_E_BKGDOWNLOAD_FAILED_TO_CREATE_TEMPFILE
+
+
+The Windows Media Player download manager cannot create a temporary file name. This might occur if the path is not valid or if the disk is full.
+
+0xC00D1263
+
+NS_E_BKGDOWNLOAD_PLUGIN_FAILEDINITIALIZE
+
+
+The Windows Media Player download manager plug-in cannot start. This might occur if the system is out of resources.
+
+0xC00D1264
+
+NS_E_BKGDOWNLOAD_PLUGIN_FAILEDTOMOVEFILE
+
+
+The Windows Media Player download manager cannot move the file.
+
+0xC00D1265
+
+NS_E_BKGDOWNLOAD_CALLFUNCFAILED
+
+
+The Windows Media Player download manager cannot perform a task because the system has no resources to allocate.
+
+0xC00D1266
+
+NS_E_BKGDOWNLOAD_CALLFUNCTIMEOUT
+
+
+The Windows Media Player download manager cannot perform a task because the task took too long to run.
+
+0xC00D1267
+
+NS_E_BKGDOWNLOAD_CALLFUNCENDED
+
+
+The Windows Media Player download manager cannot perform a task because the Player is terminating the service. The task will be recovered when the Player restarts.
+
+0xC00D1268
+
+NS_E_BKGDOWNLOAD_WMDUNPACKFAILED
+
+
+The Windows Media Player download manager cannot expand a WMD file. The file will be deleted and the operation will not be completed successfully.
+
+0xC00D1269
+
+NS_E_BKGDOWNLOAD_FAILEDINITIALIZE
+
+
+The Windows Media Player download manager cannot start. This might occur if the system is out of resources.
+
+0xC00D126A
+
+NS_E_INTERFACE_NOT_REGISTERED_IN_GIT
+
+
+Windows Media Player cannot access a required functionality. This might occur if the wrong system files or Player DLLs are loaded.
+
+0xC00D126B
+
+NS_E_BKGDOWNLOAD_INVALID_FILE_NAME
+
+
+Windows Media Player cannot get the file name of the requested download. The requested download will be canceled.
+
+0xC00D128E
+
+NS_E_IMAGE_DOWNLOAD_FAILED
+
+
+Windows Media Player encountered an error while downloading an image.
+
+0xC00D12C0
+
+NS_E_WMP_UDRM_NOUSERLIST
+
+
+Windows Media Player cannot update your media usage rights because the Player cannot verify the list of activated users of this computer.
+
+0xC00D12C1
+
+NS_E_WMP_DRM_NOT_ACQUIRING
+
+
+Windows Media Player is trying to acquire media usage rights for a file that is no longer being used. Rights acquisition will stop.
+
+0xC00D12F2
+
+NS_E_WMP_BSTR_TOO_LONG
+
+
+The parameter is not valid.
+
+0xC00D12FC
+
+NS_E_WMP_AUTOPLAY_INVALID_STATE
+
+
+The state is not valid for this request.
+
+0xC00D1306
+
+NS_E_WMP_COMPONENT_REVOKED
+
+
+Windows Media Player cannot play this file until you complete the software component upgrade. After the component has been upgraded, try to play the file again.
+
+0xC00D1324
+
+NS_E_CURL_NOTSAFE
+
+
+The URL is not safe for the operation specified.
+
+0xC00D1325
+
+NS_E_CURL_INVALIDCHAR
+
+
+The URL contains one or more characters that are not valid.
+
+0xC00D1326
+
+NS_E_CURL_INVALIDHOSTNAME
+
+
+The URL contains a host name that is not valid.
+
+0xC00D1327
+
+NS_E_CURL_INVALIDPATH
+
+
+The URL contains a path that is not valid.
+
+0xC00D1328
+
+NS_E_CURL_INVALIDSCHEME
+
+
+The URL contains a scheme that is not valid.
+
+0xC00D1329
+
+NS_E_CURL_INVALIDURL
+
+
+The URL is not valid.
+
+0xC00D132B
+
+NS_E_CURL_CANTWALK
+
+
+Windows Media Player cannot play the file. If you clicked a link on a web page, the link might not be valid.
+
+0xC00D132C
+
+NS_E_CURL_INVALIDPORT
+
+
+The URL port is not valid.
+
+0xC00D132D
+
+NS_E_CURLHELPER_NOTADIRECTORY
+
+
+The URL is not a directory.
+
+0xC00D132E
+
+NS_E_CURLHELPER_NOTAFILE
+
+
+The URL is not a file.
+
+0xC00D132F
+
+NS_E_CURL_CANTDECODE
+
+
+The URL contains characters that cannot be decoded. The URL might be truncated or incomplete.
+
+0xC00D1330
+
+NS_E_CURLHELPER_NOTRELATIVE
+
+
+The specified URL is not a relative URL.
+
+0xC00D1331
+
+NS_E_CURL_INVALIDBUFFERSIZE
+
+
+The buffer is smaller than the size specified.
+
+0xC00D1356
+
+NS_E_SUBSCRIPTIONSERVICE_PLAYBACK_DISALLOWED
+
+
+The content provider has not granted you the right to play this file. Go to the content provider's online store to get play rights.
+
+0xC00D1357
+
+NS_E_CANNOT_BUY_OR_DOWNLOAD_FROM_MULTIPLE_SERVICES
+
+
+Windows Media Player cannot purchase or download content from multiple online stores.
+
+0xC00D1358
+
+NS_E_CANNOT_BUY_OR_DOWNLOAD_CONTENT
+
+
+The file cannot be purchased or downloaded. The file might not be available from the online store.
+
+0xC00D135A
+
+NS_E_NOT_CONTENT_PARTNER_TRACK
+
+
+The provider of this file cannot be identified.
+
+0xC00D135B
+
+NS_E_TRACK_DOWNLOAD_REQUIRES_ALBUM_PURCHASE
+
+
+The file is only available for download when you buy the entire album.
+
+0xC00D135C
+
+NS_E_TRACK_DOWNLOAD_REQUIRES_PURCHASE
+
+
+You must buy the file before you can download it.
+
+0xC00D135D
+
+NS_E_TRACK_PURCHASE_MAXIMUM_EXCEEDED
+
+
+You have exceeded the maximum number of files that can be purchased in a single transaction.
+
+0xC00D135F
+
+NS_E_SUBSCRIPTIONSERVICE_LOGIN_FAILED
+
+
+Windows Media Player cannot sign in to the online store. Verify that you are using the correct user name and password. If the problem persists, the store might be temporarily unavailable.
+
+0xC00D1360
+
+NS_E_SUBSCRIPTIONSERVICE_DOWNLOAD_TIMEOUT
+
+
+Windows Media Player cannot download this item because the server is not responding. The server might be temporarily unavailable or the Internet connection might be lost.
+
+0xC00D1362
+
+NS_E_CONTENT_PARTNER_STILL_INITIALIZING
+
+
+Content Partner still initializing.
+
+0xC00D1363
+
+NS_E_OPEN_CONTAINING_FOLDER_FAILED
+
+
+The folder could not be opened. The folder might have been moved or deleted.
+
+0xC00D136A
+
+NS_E_ADVANCEDEDIT_TOO_MANY_PICTURES
+
+
+Windows Media Player could not add all of the images to the file because the images exceeded the 7 megabyte (MB) limit.
+
+0xC00D1388
+
+NS_E_REDIRECT
+
+
+The client redirected to another server.
+
+0xC00D1389
+
+NS_E_STALE_PRESENTATION
+
+
+The streaming media description is no longer current.
+
+0xC00D138A
+
+NS_E_NAMESPACE_WRONG_PERSIST
+
+
+It is not possible to create a persistent namespace node under a transient parent node.
+
+0xC00D138B
+
+NS_E_NAMESPACE_WRONG_TYPE
+
+
+It is not possible to store a value in a namespace node that has a different value type.
+
+0xC00D138C
+
+NS_E_NAMESPACE_NODE_CONFLICT
+
+
+It is not possible to remove the root namespace node.
+
+0xC00D138D
+
+NS_E_NAMESPACE_NODE_NOT_FOUND
+
+
+The specified namespace node could not be found.
+
+0xC00D138E
+
+NS_E_NAMESPACE_BUFFER_TOO_SMALL
+
+
+The buffer supplied to hold namespace node string is too small.
+
+0xC00D138F
+
+NS_E_NAMESPACE_TOO_MANY_CALLBACKS
+
+
+The callback list on a namespace node is at the maximum size.
+
+0xC00D1390
+
+NS_E_NAMESPACE_DUPLICATE_CALLBACK
+
+
+It is not possible to register an already-registered callback on a namespace node.
+
+0xC00D1391
+
+NS_E_NAMESPACE_CALLBACK_NOT_FOUND
+
+
+Cannot find the callback in the namespace when attempting to remove the callback.
+
+0xC00D1392
+
+NS_E_NAMESPACE_NAME_TOO_LONG
+
+
+The namespace node name exceeds the allowed maximum length.
+
+0xC00D1393
+
+NS_E_NAMESPACE_DUPLICATE_NAME
+
+
+Cannot create a namespace node that already exists.
+
+0xC00D1394
+
+NS_E_NAMESPACE_EMPTY_NAME
+
+
+The namespace node name cannot be a null string.
+
+0xC00D1395
+
+NS_E_NAMESPACE_INDEX_TOO_LARGE
+
+
+Finding a child namespace node by index failed because the index exceeded the number of children.
+
+0xC00D1396
+
+NS_E_NAMESPACE_BAD_NAME
+
+
+The namespace node name is invalid.
+
+0xC00D1397
+
+NS_E_NAMESPACE_WRONG_SECURITY
+
+
+It is not possible to store a value in a namespace node that has a different security type.
+
+0xC00D13EC
+
+NS_E_CACHE_ARCHIVE_CONFLICT
+
+
+The archive request conflicts with other requests in progress.
+
+0xC00D13ED
+
+NS_E_CACHE_ORIGIN_SERVER_NOT_FOUND
+
+
+The specified origin server cannot be found.
+
+0xC00D13EE
+
+NS_E_CACHE_ORIGIN_SERVER_TIMEOUT
+
+
+The specified origin server is not responding.
+
+0xC00D13EF
+
+NS_E_CACHE_NOT_BROADCAST
+
+
+The internal code for HTTP status code 412 Precondition Failed due to not broadcast type.
+
+0xC00D13F0
+
+NS_E_CACHE_CANNOT_BE_CACHED
+
+
+The internal code for HTTP status code 403 Forbidden due to not cacheable.
+
+0xC00D13F1
+
+NS_E_CACHE_NOT_MODIFIED
+
+
+The internal code for HTTP status code 304 Not Modified.
+
+0xC00D1450
+
+NS_E_CANNOT_REMOVE_PUBLISHING_POINT
+
+
+It is not possible to remove a cache or proxy publishing point.
+
+0xC00D1451
+
+NS_E_CANNOT_REMOVE_PLUGIN
+
+
+It is not possible to remove the last instance of a type of plug-in.
+
+0xC00D1452
+
+NS_E_WRONG_PUBLISHING_POINT_TYPE
+
+
+Cache and proxy publishing points do not support this property or method.
+
+0xC00D1453
+
+NS_E_UNSUPPORTED_LOAD_TYPE
+
+
+The plug-in does not support the specified load type.
+
+0xC00D1454
+
+NS_E_INVALID_PLUGIN_LOAD_TYPE_CONFIGURATION
+
+
+The plug-in does not support any load types. The plug-in must support at least one load type.
+
+0xC00D1455
+
+NS_E_INVALID_PUBLISHING_POINT_NAME
+
+
+The publishing point name is invalid.
+
+0xC00D1456
+
+NS_E_TOO_MANY_MULTICAST_SINKS
+
+
+Only one multicast data writer plug-in can be enabled for a publishing point.
+
+0xC00D1457
+
+NS_E_PUBLISHING_POINT_INVALID_REQUEST_WHILE_STARTED
+
+
+The requested operation cannot be completed while the publishing point is started.
+
+0xC00D1458
+
+NS_E_MULTICAST_PLUGIN_NOT_ENABLED
+
+
+A multicast data writer plug-in must be enabled in order for this operation to be completed.
+
+0xC00D1459
+
+NS_E_INVALID_OPERATING_SYSTEM_VERSION
+
+
+This feature requires Windows Server 2003, Enterprise Edition.
+
+0xC00D145A
+
+NS_E_PUBLISHING_POINT_REMOVED
+
+
+The requested operation cannot be completed because the specified publishing point has been removed.
+
+0xC00D145B
+
+NS_E_INVALID_PUSH_PUBLISHING_POINT_START_REQUEST
+
+
+Push publishing points are started when the encoder starts pushing the stream. This publishing point cannot be started by the server administrator.
+
+0xC00D145C
+
+NS_E_UNSUPPORTED_LANGUAGE
+
+
+The specified language is not supported.
+
+0xC00D145D
+
+NS_E_WRONG_OS_VERSION
+
+
+Windows Media Services will only run on Windows Server 2003, Standard Edition and Windows Server 2003, Enterprise Edition.
+
+0xC00D145E
+
+NS_E_PUBLISHING_POINT_STOPPED
+
+
+The operation cannot be completed because the publishing point has been stopped.
+
+0xC00D14B4
+
+NS_E_PLAYLIST_ENTRY_ALREADY_PLAYING
+
+
+The playlist entry is already playing.
+
+0xC00D14B5
+
+NS_E_EMPTY_PLAYLIST
+
+
+The playlist or directory you are requesting does not contain content.
+
+0xC00D14B6
+
+NS_E_PLAYLIST_PARSE_FAILURE
+
+
+The server was unable to parse the requested playlist file.
+
+0xC00D14B7
+
+NS_E_PLAYLIST_UNSUPPORTED_ENTRY
+
+
+The requested operation is not supported for this type of playlist entry.
+
+0xC00D14B8
+
+NS_E_PLAYLIST_ENTRY_NOT_IN_PLAYLIST
+
+
+Cannot jump to a playlist entry that is not inserted in the playlist.
+
+0xC00D14B9
+
+NS_E_PLAYLIST_ENTRY_SEEK
+
+
+Cannot seek to the desired playlist entry.
+
+0xC00D14BA
+
+NS_E_PLAYLIST_RECURSIVE_PLAYLISTS
+
+
+Cannot play recursive playlist.
+
+0xC00D14BB
+
+NS_E_PLAYLIST_TOO_MANY_NESTED_PLAYLISTS
+
+
+The number of nested playlists exceeded the limit the server can handle.
+
+0xC00D14BC
+
+NS_E_PLAYLIST_SHUTDOWN
+
+
+Cannot execute the requested operation because the playlist has been shut down by the Media Server.
+
+0xC00D14BD
+
+NS_E_PLAYLIST_END_RECEDING
+
+
+The playlist has ended while receding.
+
+0xC00D1518
+
+NS_E_DATAPATH_NO_SINK
+
+
+The data path does not have an associated data writer plug-in.
+
+0xC00D151A
+
+NS_E_INVALID_PUSH_TEMPLATE
+
+
+The specified push template is invalid.
+
+0xC00D151B
+
+NS_E_INVALID_PUSH_PUBLISHING_POINT
+
+
+The specified push publishing point is invalid.
+
+0xC00D151C
+
+NS_E_CRITICAL_ERROR
+
+
+The requested operation cannot be performed because the server or publishing point is in a critical error state.
+
+0xC00D151D
+
+NS_E_NO_NEW_CONNECTIONS
+
+
+The content cannot be played because the server is not currently accepting connections. Try connecting at a later time.
+
+0xC00D151E
+
+NS_E_WSX_INVALID_VERSION
+
+
+The version of this playlist is not supported by the server.
+
+0xC00D151F
+
+NS_E_HEADER_MISMATCH
+
+
+The command does not apply to the current media header user by a server component.
+
+0xC00D1520
+
+NS_E_PUSH_DUPLICATE_PUBLISHING_POINT_NAME
+
+
+The specified publishing point name is already in use.
+
+0xC00D157C
+
+NS_E_NO_SCRIPT_ENGINE
+
+
+There is no script engine available for this file.
+
+0xC00D157D
+
+NS_E_PLUGIN_ERROR_REPORTED
+
+
+The plug-in has reported an error. See the Troubleshooting tab or the NT Application Event Log for details.
+
+0xC00D157E
+
+NS_E_SOURCE_PLUGIN_NOT_FOUND
+
+
+No enabled data source plug-in is available to access the requested content.
+
+0xC00D157F
+
+NS_E_PLAYLIST_PLUGIN_NOT_FOUND
+
+
+No enabled playlist parser plug-in is available to access the requested content.
+
+0xC00D1580
+
+NS_E_DATA_SOURCE_ENUMERATION_NOT_SUPPORTED
+
+
+The data source plug-in does not support enumeration.
+
+0xC00D1581
+
+NS_E_MEDIA_PARSER_INVALID_FORMAT
+
+
+The server cannot stream the selected file because it is either damaged or corrupt. Select a different file.
+
+0xC00D1582
+
+NS_E_SCRIPT_DEBUGGER_NOT_INSTALLED
+
+
+The plug-in cannot be enabled because a compatible script debugger is not installed on this system. Install a script debugger, or disable the script debugger option on the general tab of the plug-in's properties page and try again.
+
+0xC00D1583
+
+NS_E_FEATURE_REQUIRES_ENTERPRISE_SERVER
+
+
+The plug-in cannot be loaded because it requires Windows Server 2003, Enterprise Edition.
+
+0xC00D1584
+
+NS_E_WIZARD_RUNNING
+
+
+Another wizard is currently running. Please close the other wizard or wait until it finishes before attempting to run this wizard again.
+
+0xC00D1585
+
+NS_E_INVALID_LOG_URL
+
+
+Invalid log URL. Multicast logging URL must look like "http://servername/isapibackend.dll".
+
+0xC00D1586
+
+NS_E_INVALID_MTU_RANGE
+
+
+Invalid MTU specified. The valid range for maximum packet size is between 36 and 65507 bytes.
+
+0xC00D1587
+
+NS_E_INVALID_PLAY_STATISTICS
+
+
+Invalid play statistics for logging.
+
+0xC00D1588
+
+NS_E_LOG_NEED_TO_BE_SKIPPED
+
+
+The log needs to be skipped.
+
+0xC00D1589
+
+NS_E_HTTP_TEXT_DATACONTAINER_SIZE_LIMIT_EXCEEDED
+
+
+The size of the data exceeded the limit the WMS HTTP Download Data Source plugin can handle.
+
+0xC00D158A
+
+NS_E_PORT_IN_USE
+
+
+One usage of each socket address (protocol/network address/port) is permitted. Verify that other services or applications are not attempting to use the same port and then try to enable the plug-in again.
+
+0xC00D158B
+
+NS_E_PORT_IN_USE_HTTP
+
+
+One usage of each socket address (protocol/network address/port) is permitted. Verify that other services (such as IIS) or applications are not attempting to use the same port and then try to enable the plug-in again.
+
+0xC00D158C
+
+NS_E_HTTP_TEXT_DATACONTAINER_INVALID_SERVER_RESPONSE
+
+
+The WMS HTTP Download Data Source plugin was unable to receive the remote server's response.
+
+0xC00D158D
+
+NS_E_ARCHIVE_REACH_QUOTA
+
+
+The archive plug-in has reached its quota.
+
+0xC00D158E
+
+NS_E_ARCHIVE_ABORT_DUE_TO_BCAST
+
+
+The archive plug-in aborted because the source was from broadcast.
+
+0xC00D158F
+
+NS_E_ARCHIVE_GAP_DETECTED
+
+
+The archive plug-in detected an interrupt in the source.
+
+0xC00D1590
+
+NS_E_AUTHORIZATION_FILE_NOT_FOUND
+
+
+The system cannot find the file specified.
+
+0xC00D1B58
+
+NS_E_BAD_MARKIN
+
+
+The mark-in time should be greater than 0 and less than the mark-out time.
+
+0xC00D1B59
+
+NS_E_BAD_MARKOUT
+
+
+The mark-out time should be greater than the mark-in time and less than the file duration.
+
+0xC00D1B5A
+
+NS_E_NOMATCHING_MEDIASOURCE
+
+
+No matching media type is found in the source %1.
+
+0xC00D1B5B
+
+NS_E_UNSUPPORTED_SOURCETYPE
+
+
+The specified source type is not supported.
+
+0xC00D1B5C
+
+NS_E_TOO_MANY_AUDIO
+
+
+It is not possible to specify more than one audio input.
+
+0xC00D1B5D
+
+NS_E_TOO_MANY_VIDEO
+
+
+It is not possible to specify more than two video inputs.
+
+0xC00D1B5E
+
+NS_E_NOMATCHING_ELEMENT
+
+
+No matching element is found in the list.
+
+0xC00D1B5F
+
+NS_E_MISMATCHED_MEDIACONTENT
+
+
+The profile's media types must match the media types defined for the session.
+
+0xC00D1B60
+
+NS_E_CANNOT_DELETE_ACTIVE_SOURCEGROUP
+
+
+It is not possible to remove an active source while encoding.
+
+0xC00D1B61
+
+NS_E_AUDIODEVICE_BUSY
+
+
+It is not possible to open the specified audio capture device because it is currently in use.
+
+0xC00D1B62
+
+NS_E_AUDIODEVICE_UNEXPECTED
+
+
+It is not possible to open the specified audio capture device because an unexpected error has occurred.
+
+0xC00D1B63
+
+NS_E_AUDIODEVICE_BADFORMAT
+
+
+The audio capture device does not support the specified audio format.
+
+0xC00D1B64
+
+NS_E_VIDEODEVICE_BUSY
+
+
+It is not possible to open the specified video capture device because it is currently in use.
+
+0xC00D1B65
+
+NS_E_VIDEODEVICE_UNEXPECTED
+
+
+It is not possible to open the specified video capture device because an unexpected error has occurred.
+
+0xC00D1B66
+
+NS_E_INVALIDCALL_WHILE_ENCODER_RUNNING
+
+
+This operation is not allowed while encoding.
+
+0xC00D1B67
+
+NS_E_NO_PROFILE_IN_SOURCEGROUP
+
+
+No profile is set for the source.
+
+0xC00D1B68
+
+NS_E_VIDEODRIVER_UNSTABLE
+
+
+The video capture driver returned an unrecoverable error. It is now in an unstable state.
+
+0xC00D1B69
+
+NS_E_VIDCAPSTARTFAILED
+
+
+It was not possible to start the video device.
+
+0xC00D1B6A
+
+NS_E_VIDSOURCECOMPRESSION
+
+
+The video source does not support the requested output format or color depth.
+
+0xC00D1B6B
+
+NS_E_VIDSOURCESIZE
+
+
+The video source does not support the requested capture size.
+
+0xC00D1B6C
+
+NS_E_ICMQUERYFORMAT
+
+
+It was not possible to obtain output information from the video compressor.
+
+0xC00D1B6D
+
+NS_E_VIDCAPCREATEWINDOW
+
+
+It was not possible to create a video capture window.
+
+0xC00D1B6E
+
+NS_E_VIDCAPDRVINUSE
+
+
+There is already a stream active on this video device.
+
+0xC00D1B6F
+
+NS_E_NO_MEDIAFORMAT_IN_SOURCE
+
+
+No media format is set in source.
+
+0xC00D1B70
+
+NS_E_NO_VALID_OUTPUT_STREAM
+
+
+Cannot find a valid output stream from the source.
+
+0xC00D1B71
+
+NS_E_NO_VALID_SOURCE_PLUGIN
+
+
+It was not possible to find a valid source plug-in for the specified source.
+
+0xC00D1B72
+
+NS_E_NO_ACTIVE_SOURCEGROUP
+
+
+No source is currently active.
+
+0xC00D1B73
+
+NS_E_NO_SCRIPT_STREAM
+
+
+No script stream is set in the current source.
+
+0xC00D1B74
+
+NS_E_INVALIDCALL_WHILE_ARCHIVAL_RUNNING
+
+
+This operation is not allowed while archiving.
+
+0xC00D1B75
+
+NS_E_INVALIDPACKETSIZE
+
+
+The setting for the maximum packet size is not valid.
+
+0xC00D1B76
+
+NS_E_PLUGIN_CLSID_INVALID
+
+
+The plug-in CLSID specified is not valid.
+
+0xC00D1B77
+
+NS_E_UNSUPPORTED_ARCHIVETYPE
+
+
+This archive type is not supported.
+
+0xC00D1B78
+
+NS_E_UNSUPPORTED_ARCHIVEOPERATION
+
+
+This archive operation is not supported.
+
+0xC00D1B79
+
+NS_E_ARCHIVE_FILENAME_NOTSET
+
+
+The local archive file name was not set.
+
+0xC00D1B7A
+
+NS_E_SOURCEGROUP_NOTPREPARED
+
+
+The source is not yet prepared.
+
+0xC00D1B7B
+
+NS_E_PROFILE_MISMATCH
+
+
+Profiles on the sources do not match.
+
+0xC00D1B7C
+
+NS_E_INCORRECTCLIPSETTINGS
+
+
+The specified crop values are not valid.
+
+0xC00D1B7D
+
+NS_E_NOSTATSAVAILABLE
+
+
+No statistics are available at this time.
+
+0xC00D1B7E
+
+NS_E_NOTARCHIVING
+
+
+The encoder is not archiving.
+
+0xC00D1B7F
+
+NS_E_INVALIDCALL_WHILE_ENCODER_STOPPED
+
+
+This operation is only allowed during encoding.
+
+0xC00D1B80
+
+NS_E_NOSOURCEGROUPS
+
+
+This SourceGroupCollection doesn't contain any SourceGroups.
+
+0xC00D1B81
+
+NS_E_INVALIDINPUTFPS
+
+
+This source does not have a frame rate of 30 fps. Therefore, it is not possible to apply the inverse telecine filter to the source.
+
+0xC00D1B82
+
+NS_E_NO_DATAVIEW_SUPPORT
+
+
+It is not possible to display your source or output video in the Video panel.
+
+0xC00D1B83
+
+NS_E_CODEC_UNAVAILABLE
+
+
+One or more codecs required to open this content could not be found.
+
+0xC00D1B84
+
+NS_E_ARCHIVE_SAME_AS_INPUT
+
+
+The archive file has the same name as an input file. Change one of the names before continuing.
+
+0xC00D1B85
+
+NS_E_SOURCE_NOTSPECIFIED
+
+
+The source has not been set up completely.
+
+0xC00D1B86
+
+NS_E_NO_REALTIME_TIMECOMPRESSION
+
+
+It is not possible to apply time compression to a broadcast session.
+
+0xC00D1B87
+
+NS_E_UNSUPPORTED_ENCODER_DEVICE
+
+
+It is not possible to open this device.
+
+0xC00D1B88
+
+NS_E_UNEXPECTED_DISPLAY_SETTINGS
+
+
+It is not possible to start encoding because the display size or color has changed since the current session was defined. Restore the previous settings or create a new session.
+
+0xC00D1B89
+
+NS_E_NO_AUDIODATA
+
+
+No audio data has been received for several seconds. Check the audio source and restart the encoder.
+
+0xC00D1B8A
+
+NS_E_INPUTSOURCE_PROBLEM
+
+
+One or all of the specified sources are not working properly. Check that the sources are configured correctly.
+
+0xC00D1B8B
+
+NS_E_WME_VERSION_MISMATCH
+
+
+The supplied configuration file is not supported by this version of the encoder.
+
+0xC00D1B8C
+
+NS_E_NO_REALTIME_PREPROCESS
+
+
+It is not possible to use image preprocessing with live encoding.
+
+0xC00D1B8D
+
+NS_E_NO_REPEAT_PREPROCESS
+
+
+It is not possible to use two-pass encoding when the source is set to loop.
+
+0xC00D1B8E
+
+NS_E_CANNOT_PAUSE_LIVEBROADCAST
+
+
+It is not possible to pause encoding during a broadcast.
+
+0xC00D1B8F
+
+NS_E_DRM_PROFILE_NOT_SET
+
+
+A DRM profile has not been set for the current session.
+
+0xC00D1B90
+
+NS_E_DUPLICATE_DRMPROFILE
+
+
+The profile ID is already used by a DRM profile. Specify a different profile ID.
+
+0xC00D1B91
+
+NS_E_INVALID_DEVICE
+
+
+The setting of the selected device does not support control for playing back tapes.
+
+0xC00D1B92
+
+NS_E_SPEECHEDL_ON_NON_MIXEDMODE
+
+
+You must specify a mixed voice and audio mode in order to use an optimization definition file.
+
+0xC00D1B93
+
+NS_E_DRM_PASSWORD_TOO_LONG
+
+
+The specified password is too long. Type a password with fewer than 8 characters.
+
+0xC00D1B94
+
+NS_E_DEVCONTROL_FAILED_SEEK
+
+
+It is not possible to seek to the specified mark-in point.
+
+0xC00D1B95
+
+NS_E_INTERLACE_REQUIRE_SAMESIZE
+
+
+When you choose to maintain the interlacing in your video, the output video size must match the input video size.
+
+0xC00D1B96
+
+NS_E_TOO_MANY_DEVICECONTROL
+
+
+Only one device control plug-in can control a device.
+
+0xC00D1B97
+
+NS_E_NO_MULTIPASS_FOR_LIVEDEVICE
+
+
+You must also enable storing content to hard disk temporarily in order to use two-pass encoding with the input device.
+
+0xC00D1B98
+
+NS_E_MISSING_AUDIENCE
+
+
+An audience is missing from the output stream configuration.
+
+0xC00D1B99
+
+NS_E_AUDIENCE_CONTENTTYPE_MISMATCH
+
+
+All audiences in the output tree must have the same content type.
+
+0xC00D1B9A
+
+NS_E_MISSING_SOURCE_INDEX
+
+
+A source index is missing from the output stream configuration.
+
+0xC00D1B9B
+
+NS_E_NUM_LANGUAGE_MISMATCH
+
+
+The same source index in different audiences should have the same number of languages.
+
+0xC00D1B9C
+
+NS_E_LANGUAGE_MISMATCH
+
+
+The same source index in different audiences should have the same languages.
+
+0xC00D1B9D
+
+NS_E_VBRMODE_MISMATCH
+
+
+The same source index in different audiences should use the same VBR encoding mode.
+
+0xC00D1B9E
+
+NS_E_INVALID_INPUT_AUDIENCE_INDEX
+
+
+The bit rate index specified is not valid.
+
+0xC00D1B9F
+
+NS_E_INVALID_INPUT_LANGUAGE
+
+
+The specified language is not valid.
+
+0xC00D1BA0
+
+NS_E_INVALID_INPUT_STREAM
+
+
+The specified source type is not valid.
+
+0xC00D1BA1
+
+NS_E_EXPECT_MONO_WAV_INPUT
+
+
+The source must be a mono channel .wav file.
+
+0xC00D1BA2
+
+NS_E_INPUT_WAVFORMAT_MISMATCH
+
+
+All the source .wav files must have the same format.
+
+0xC00D1BA3
+
+NS_E_RECORDQ_DISK_FULL
+
+
+The hard disk being used for temporary storage of content has reached the minimum allowed disk space. Create more space on the hard disk and restart encoding.
+
+0xC00D1BA4
+
+NS_E_NO_PAL_INVERSE_TELECINE
+
+
+It is not possible to apply the inverse telecine feature to PAL content.
+
+0xC00D1BA5
+
+NS_E_ACTIVE_SG_DEVICE_DISCONNECTED
+
+
+A capture device in the current active source is no longer available.
+
+0xC00D1BA6
+
+NS_E_ACTIVE_SG_DEVICE_CONTROL_DISCONNECTED
+
+
+A device used in the current active source for device control is no longer available.
+
+0xC00D1BA7
+
+NS_E_NO_FRAMES_SUBMITTED_TO_ANALYZER
+
+
+No frames have been submitted to the analyzer for analysis.
+
+0xC00D1BA8
+
+NS_E_INPUT_DOESNOT_SUPPORT_SMPTE
+
+
+The source video does not support time codes.
+
+0xC00D1BA9
+
+NS_E_NO_SMPTE_WITH_MULTIPLE_SOURCEGROUPS
+
+
+It is not possible to generate a time code when there are multiple sources in a session.
+
+0xC00D1BAA
+
+NS_E_BAD_CONTENTEDL
+
+
+The voice codec optimization definition file cannot be found or is corrupted.
+
+0xC00D1BAB
+
+NS_E_INTERLACEMODE_MISMATCH
+
+
+The same source index in different audiences should have the same interlace mode.
+
+0xC00D1BAC
+
+NS_E_NONSQUAREPIXELMODE_MISMATCH
+
+
+The same source index in different audiences should have the same nonsquare pixel mode.
+
+0xC00D1BAD
+
+NS_E_SMPTEMODE_MISMATCH
+
+
+The same source index in different audiences should have the same time code mode.
+
+0xC00D1BAE
+
+NS_E_END_OF_TAPE
+
+
+Either the end of the tape has been reached or there is no tape. Check the device and tape.
+
+0xC00D1BAF
+
+NS_E_NO_MEDIA_IN_AUDIENCE
+
+
+No audio or video input has been specified.
+
+0xC00D1BB0
+
+NS_E_NO_AUDIENCES
+
+
+The profile must contain a bit rate.
+
+0xC00D1BB1
+
+NS_E_NO_AUDIO_COMPAT
+
+
+You must specify at least one audio stream to be compatible with Windows Media Player 7.1.
+
+0xC00D1BB2
+
+NS_E_INVALID_VBR_COMPAT
+
+
+Using a VBR encoding mode is not compatible with Windows Media Player 7.1.
+
+0xC00D1BB3
+
+NS_E_NO_PROFILE_NAME
+
+
+You must specify a profile name.
+
+0xC00D1BB4
+
+NS_E_INVALID_VBR_WITH_UNCOMP
+
+
+It is not possible to use a VBR encoding mode with uncompressed audio or video.
+
+0xC00D1BB5
+
+NS_E_MULTIPLE_VBR_AUDIENCES
+
+
+It is not possible to use MBR encoding with VBR encoding.
+
+0xC00D1BB6
+
+NS_E_UNCOMP_COMP_COMBINATION
+
+
+It is not possible to mix uncompressed and compressed content in a session.
+
+0xC00D1BB7
+
+NS_E_MULTIPLE_AUDIO_CODECS
+
+
+All audiences must use the same audio codec.
+
+0xC00D1BB8
+
+NS_E_MULTIPLE_AUDIO_FORMATS
+
+
+All audiences should use the same audio format to be compatible with Windows Media Player 7.1.
+
+0xC00D1BB9
+
+NS_E_AUDIO_BITRATE_STEPDOWN
+
+
+The audio bit rate for an audience with a higher total bit rate must be greater than one with a lower total bit rate.
+
+0xC00D1BBA
+
+NS_E_INVALID_AUDIO_PEAKRATE
+
+
+The audio peak bit rate setting is not valid.
+
+0xC00D1BBB
+
+NS_E_INVALID_AUDIO_PEAKRATE_2
+
+
+The audio peak bit rate setting must be greater than the audio bit rate setting.
+
+0xC00D1BBC
+
+NS_E_INVALID_AUDIO_BUFFERMAX
+
+
+The setting for the maximum buffer size for audio is not valid.
+
+0xC00D1BBD
+
+NS_E_MULTIPLE_VIDEO_CODECS
+
+
+All audiences must use the same video codec.
+
+0xC00D1BBE
+
+NS_E_MULTIPLE_VIDEO_SIZES
+
+
+All audiences should use the same video size to be compatible with Windows Media Player 7.1.
+
+0xC00D1BBF
+
+NS_E_INVALID_VIDEO_BITRATE
+
+
+The video bit rate setting is not valid.
+
+0xC00D1BC0
+
+NS_E_VIDEO_BITRATE_STEPDOWN
+
+
+The video bit rate for an audience with a higher total bit rate must be greater than one with a lower total bit rate.
+
+0xC00D1BC1
+
+NS_E_INVALID_VIDEO_PEAKRATE
+
+
+The video peak bit rate setting is not valid.
+
+0xC00D1BC2
+
+NS_E_INVALID_VIDEO_PEAKRATE_2
+
+
+The video peak bit rate setting must be greater than the video bit rate setting.
+
+0xC00D1BC3
+
+NS_E_INVALID_VIDEO_WIDTH
+
+
+The video width setting is not valid.
+
+0xC00D1BC4
+
+NS_E_INVALID_VIDEO_HEIGHT
+
+
+The video height setting is not valid.
+
+0xC00D1BC5
+
+NS_E_INVALID_VIDEO_FPS
+
+
+The video frame rate setting is not valid.
+
+0xC00D1BC6
+
+NS_E_INVALID_VIDEO_KEYFRAME
+
+
+The video key frame setting is not valid.
+
+0xC00D1BC7
+
+NS_E_INVALID_VIDEO_IQUALITY
+
+
+The video image quality setting is not valid.
+
+0xC00D1BC8
+
+NS_E_INVALID_VIDEO_CQUALITY
+
+
+The video codec quality setting is not valid.
+
+0xC00D1BC9
+
+NS_E_INVALID_VIDEO_BUFFER
+
+
+The video buffer setting is not valid.
+
+0xC00D1BCA
+
+NS_E_INVALID_VIDEO_BUFFERMAX
+
+
+The setting for the maximum buffer size for video is not valid.
+
+0xC00D1BCB
+
+NS_E_INVALID_VIDEO_BUFFERMAX_2
+
+
+The value of the video maximum buffer size setting must be greater than the video buffer size setting.
+
+0xC00D1BCC
+
+NS_E_INVALID_VIDEO_WIDTH_ALIGN
+
+
+The alignment of the video width is not valid.
+
+0xC00D1BCD
+
+NS_E_INVALID_VIDEO_HEIGHT_ALIGN
+
+
+The alignment of the video height is not valid.
+
+0xC00D1BCE
+
+NS_E_MULTIPLE_SCRIPT_BITRATES
+
+
+All bit rates must have the same script bit rate.
+
+0xC00D1BCF
+
+NS_E_INVALID_SCRIPT_BITRATE
+
+
+The script bit rate specified is not valid.
+
+0xC00D1BD0
+
+NS_E_MULTIPLE_FILE_BITRATES
+
+
+All bit rates must have the same file transfer bit rate.
+
+0xC00D1BD1
+
+NS_E_INVALID_FILE_BITRATE
+
+
+The file transfer bit rate is not valid.
+
+0xC00D1BD2
+
+NS_E_SAME_AS_INPUT_COMBINATION
+
+
+All audiences in a profile should either be same as input or have video width and height specified.
+
+0xC00D1BD3
+
+NS_E_SOURCE_CANNOT_LOOP
+
+
+This source type does not support looping.
+
+0xC00D1BD4
+
+NS_E_INVALID_FOLDDOWN_COEFFICIENTS
+
+
+The fold-down value needs to be between -144 and 0.
+
+0xC00D1BD5
+
+NS_E_DRMPROFILE_NOTFOUND
+
+
+The specified DRM profile does not exist in the system.
+
+0xC00D1BD6
+
+NS_E_INVALID_TIMECODE
+
+
+The specified time code is not valid.
+
+0xC00D1BD7
+
+NS_E_NO_AUDIO_TIMECOMPRESSION
+
+
+It is not possible to apply time compression to a video-only session.
+
+0xC00D1BD8
+
+NS_E_NO_TWOPASS_TIMECOMPRESSION
+
+
+It is not possible to apply time compression to a session that is using two-pass encoding.
+
+0xC00D1BD9
+
+NS_E_TIMECODE_REQUIRES_VIDEOSTREAM
+
+
+It is not possible to generate a time code for an audio-only session.
+
+0xC00D1BDA
+
+NS_E_NO_MBR_WITH_TIMECODE
+
+
+It is not possible to generate a time code when you are encoding content at multiple bit rates.
+
+0xC00D1BDB
+
+NS_E_INVALID_INTERLACEMODE
+
+
+The video codec selected does not support maintaining interlacing in video.
+
+0xC00D1BDC
+
+NS_E_INVALID_INTERLACE_COMPAT
+
+
+Maintaining interlacing in video is not compatible with Windows Media Player 7.1.
+
+0xC00D1BDD
+
+NS_E_INVALID_NONSQUAREPIXEL_COMPAT
+
+
+Allowing nonsquare pixel output is not compatible with Windows Media Player 7.1.
+
+0xC00D1BDE
+
+NS_E_INVALID_SOURCE_WITH_DEVICE_CONTROL
+
+
+Only capture devices can be used with device control.
+
+0xC00D1BDF
+
+NS_E_CANNOT_GENERATE_BROADCAST_INFO_FOR_QUALITYVBR
+
+
+It is not possible to generate the stream format file if you are using quality-based VBR encoding for the audio or video stream. Instead use the Windows Media file generated after encoding to create the announcement file.
+
+0xC00D1BE0
+
+NS_E_EXCEED_MAX_DRM_PROFILE_LIMIT
+
+
+It is not possible to create a DRM profile because the maximum number of profiles has been reached. You must delete some DRM profiles before creating new ones.
+
+0xC00D1BE1
+
+NS_E_DEVICECONTROL_UNSTABLE
+
+
+The device is in an unstable state. Check that the device is functioning properly and a tape is in place.
+
+0xC00D1BE2
+
+NS_E_INVALID_PIXEL_ASPECT_RATIO
+
+
+The pixel aspect ratio value must be between 1 and 255.
+
+0xC00D1BE3
+
+NS_E_AUDIENCE__LANGUAGE_CONTENTTYPE_MISMATCH
+
+
+All streams with different languages in the same audience must have same properties.
+
+0xC00D1BE4
+
+NS_E_INVALID_PROFILE_CONTENTTYPE
+
+
+The profile must contain at least one audio or video stream.
+
+0xC00D1BE5
+
+NS_E_TRANSFORM_PLUGIN_NOT_FOUND
+
+
+The transform plug-in could not be found.
+
+0xC00D1BE6
+
+NS_E_TRANSFORM_PLUGIN_INVALID
+
+
+The transform plug-in is not valid. It might be damaged or you might not have the required permissions to access the plug-in.
+
+0xC00D1BE7
+
+NS_E_EDL_REQUIRED_FOR_DEVICE_MULTIPASS
+
+
+To use two-pass encoding, you must enable device control and setup an edit decision list (EDL) that has at least one entry.
+
+0xC00D1BE8
+
+NS_E_INVALID_VIDEO_WIDTH_FOR_INTERLACED_ENCODING
+
+
+When you choose to maintain the interlacing in your video, the output video size must be a multiple of 4.
+
+0xC00D1BE9
+
+NS_E_MARKIN_UNSUPPORTED
+
+
+Markin/Markout is unsupported with this source type.
+
+0xC00D2711
+
+NS_E_DRM_INVALID_APPLICATION
+
+
+A problem has occurred in the Digital Rights Management component. Contact product support for this application.
+
+0xC00D2712
+
+NS_E_DRM_LICENSE_STORE_ERROR
+
+
+License storage is not working. Contact Microsoft product support.
+
+0xC00D2713
+
+NS_E_DRM_SECURE_STORE_ERROR
+
+
+Secure storage is not working. Contact Microsoft product support.
+
+0xC00D2714
+
+NS_E_DRM_LICENSE_STORE_SAVE_ERROR
+
+
+License acquisition did not work. Acquire a new license or contact the content provider for further assistance.
+
+0xC00D2715
+
+NS_E_DRM_SECURE_STORE_UNLOCK_ERROR
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2716
+
+NS_E_DRM_INVALID_CONTENT
+
+
+The media file is corrupted. Contact the content provider to get a new file.
+
+0xC00D2717
+
+NS_E_DRM_UNABLE_TO_OPEN_LICENSE
+
+
+The license is corrupted. Acquire a new license.
+
+0xC00D2718
+
+NS_E_DRM_INVALID_LICENSE
+
+
+The license is corrupted or invalid. Acquire a new license
+
+0xC00D2719
+
+NS_E_DRM_INVALID_MACHINE
+
+
+Licenses cannot be copied from one computer to another. Use License Management to transfer licenses, or get a new license for the media file.
+
+0xC00D271B
+
+NS_E_DRM_ENUM_LICENSE_FAILED
+
+
+License storage is not working. Contact Microsoft product support.
+
+0xC00D271C
+
+NS_E_DRM_INVALID_LICENSE_REQUEST
+
+
+The media file is corrupted. Contact the content provider to get a new file.
+
+0xC00D271D
+
+NS_E_DRM_UNABLE_TO_INITIALIZE
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D271E
+
+NS_E_DRM_UNABLE_TO_ACQUIRE_LICENSE
+
+
+The license could not be acquired. Try again later.
+
+0xC00D271F
+
+NS_E_DRM_INVALID_LICENSE_ACQUIRED
+
+
+License acquisition did not work. Acquire a new license or contact the content provider for further assistance.
+
+0xC00D2720
+
+NS_E_DRM_NO_RIGHTS
+
+
+The requested operation cannot be performed on this file.
+
+0xC00D2721
+
+NS_E_DRM_KEY_ERROR
+
+
+The requested action cannot be performed because a problem occurred with the Windows Media Digital Rights Management (DRM) components on your computer.
+
+0xC00D2722
+
+NS_E_DRM_ENCRYPT_ERROR
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2723
+
+NS_E_DRM_DECRYPT_ERROR
+
+
+The media file is corrupted. Contact the content provider to get a new file.
+
+0xC00D2725
+
+NS_E_DRM_LICENSE_INVALID_XML
+
+
+The license is corrupted. Acquire a new license.
+
+0xC00D2728
+
+NS_E_DRM_NEEDS_INDIVIDUALIZATION
+
+
+A security upgrade is required to perform the operation on this media file.
+
+0xC00D2729
+
+NS_E_DRM_ALREADY_INDIVIDUALIZED
+
+
+You already have the latest security components. No upgrade is necessary at this time.
+
+0xC00D272A
+
+NS_E_DRM_ACTION_NOT_QUERIED
+
+
+The application cannot perform this action. Contact product support for this application.
+
+0xC00D272B
+
+NS_E_DRM_ACQUIRING_LICENSE
+
+
+You cannot begin a new license acquisition process until the current one has been completed.
+
+0xC00D272C
+
+NS_E_DRM_INDIVIDUALIZING
+
+
+You cannot begin a new security upgrade until the current one has been completed.
+
+0xC00D272D
+
+NS_E_BACKUP_RESTORE_FAILURE
+
+
+Failure in Backup-Restore.
+
+0xC00D272E
+
+NS_E_BACKUP_RESTORE_BAD_REQUEST_ID
+
+
+Bad Request ID in Backup-Restore.
+
+0xC00D272F
+
+NS_E_DRM_PARAMETERS_MISMATCHED
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2730
+
+NS_E_DRM_UNABLE_TO_CREATE_LICENSE_OBJECT
+
+
+A license cannot be created for this media file. Reinstall the application.
+
+0xC00D2731
+
+NS_E_DRM_UNABLE_TO_CREATE_INDI_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2732
+
+NS_E_DRM_UNABLE_TO_CREATE_ENCRYPT_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2733
+
+NS_E_DRM_UNABLE_TO_CREATE_DECRYPT_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2734
+
+NS_E_DRM_UNABLE_TO_CREATE_PROPERTIES_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2735
+
+NS_E_DRM_UNABLE_TO_CREATE_BACKUP_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2736
+
+NS_E_DRM_INDIVIDUALIZE_ERROR
+
+
+The security upgrade failed. Try again later.
+
+0xC00D2737
+
+NS_E_DRM_LICENSE_OPEN_ERROR
+
+
+License storage is not working. Contact Microsoft product support.
+
+0xC00D2738
+
+NS_E_DRM_LICENSE_CLOSE_ERROR
+
+
+License storage is not working. Contact Microsoft product support.
+
+0xC00D2739
+
+NS_E_DRM_GET_LICENSE_ERROR
+
+
+License storage is not working. Contact Microsoft product support.
+
+0xC00D273A
+
+NS_E_DRM_QUERY_ERROR
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D273B
+
+NS_E_DRM_REPORT_ERROR
+
+
+A problem has occurred in the Digital Rights Management component. Contact product support for this application.
+
+0xC00D273C
+
+NS_E_DRM_GET_LICENSESTRING_ERROR
+
+
+License storage is not working. Contact Microsoft product support.
+
+0xC00D273D
+
+NS_E_DRM_GET_CONTENTSTRING_ERROR
+
+
+The media file is corrupted. Contact the content provider to get a new file.
+
+0xC00D273E
+
+NS_E_DRM_MONITOR_ERROR
+
+
+A problem has occurred in the Digital Rights Management component. Try again later.
+
+0xC00D273F
+
+NS_E_DRM_UNABLE_TO_SET_PARAMETER
+
+
+The application has made an invalid call to the Digital Rights Management component. Contact product support for this application.
+
+0xC00D2740
+
+NS_E_DRM_INVALID_APPDATA
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2741
+
+NS_E_DRM_INVALID_APPDATA_VERSION
+
+
+A problem has occurred in the Digital Rights Management component. Contact product support for this application.
+
+0xC00D2742
+
+NS_E_DRM_BACKUP_EXISTS
+
+
+Licenses are already backed up in this location.
+
+0xC00D2743
+
+NS_E_DRM_BACKUP_CORRUPT
+
+
+One or more backed-up licenses are missing or corrupt.
+
+0xC00D2744
+
+NS_E_DRM_BACKUPRESTORE_BUSY
+
+
+You cannot begin a new backup process until the current process has been completed.
+
+0xC00D2745
+
+NS_E_BACKUP_RESTORE_BAD_DATA
+
+
+Bad Data sent to Backup-Restore.
+
+0xC00D2748
+
+NS_E_DRM_LICENSE_UNUSABLE
+
+
+The license is invalid. Contact the content provider for further assistance.
+
+0xC00D2749
+
+NS_E_DRM_INVALID_PROPERTY
+
+
+A required property was not set by the application. Contact product support for this application.
+
+0xC00D274A
+
+NS_E_DRM_SECURE_STORE_NOT_FOUND
+
+
+A problem has occurred in the Digital Rights Management component of this application. Try to acquire a license again.
+
+0xC00D274B
+
+NS_E_DRM_CACHED_CONTENT_ERROR
+
+
+A license cannot be found for this media file. Use License Management to transfer a license for this file from the original computer, or acquire a new license.
+
+0xC00D274C
+
+NS_E_DRM_INDIVIDUALIZATION_INCOMPLETE
+
+
+A problem occurred during the security upgrade. Try again later.
+
+0xC00D274D
+
+NS_E_DRM_DRIVER_AUTH_FAILURE
+
+
+Certified driver components are required to play this media file. Contact Windows Update to see whether updated drivers are available for your hardware.
+
+0xC00D274E
+
+NS_E_DRM_NEED_UPGRADE_MSSAP
+
+
+One or more of the Secure Audio Path components were not found or an entry point in those components was not found.
+
+0xC00D274F
+
+NS_E_DRM_REOPEN_CONTENT
+
+
+Status message: Reopen the file.
+
+0xC00D2750
+
+NS_E_DRM_DRIVER_DIGIOUT_FAILURE
+
+
+Certain driver functionality is required to play this media file. Contact Windows Update to see whether updated drivers are available for your hardware.
+
+0xC00D2751
+
+NS_E_DRM_INVALID_SECURESTORE_PASSWORD
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2752
+
+NS_E_DRM_APPCERT_REVOKED
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2753
+
+NS_E_DRM_RESTORE_FRAUD
+
+
+You cannot restore your license(s).
+
+0xC00D2754
+
+NS_E_DRM_HARDWARE_INCONSISTENT
+
+
+The licenses for your media files are corrupted. Contact Microsoft product support.
+
+0xC00D2755
+
+NS_E_DRM_SDMI_TRIGGER
+
+
+To transfer this media file, you must upgrade the application.
+
+0xC00D2756
+
+NS_E_DRM_SDMI_NOMORECOPIES
+
+
+You cannot make any more copies of this media file.
+
+0xC00D2757
+
+NS_E_DRM_UNABLE_TO_CREATE_HEADER_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2758
+
+NS_E_DRM_UNABLE_TO_CREATE_KEYS_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2759
+
+NS_E_DRM_LICENSE_NOTACQUIRED
+
+
+Unable to obtain license.
+
+0xC00D275A
+
+NS_E_DRM_UNABLE_TO_CREATE_CODING_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D275B
+
+NS_E_DRM_UNABLE_TO_CREATE_STATE_DATA_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D275C
+
+NS_E_DRM_BUFFER_TOO_SMALL
+
+
+The buffer supplied is not sufficient.
+
+0xC00D275D
+
+NS_E_DRM_UNSUPPORTED_PROPERTY
+
+
+The property requested is not supported.
+
+0xC00D275E
+
+NS_E_DRM_ERROR_BAD_NET_RESP
+
+
+The specified server cannot perform the requested operation.
+
+0xC00D275F
+
+NS_E_DRM_STORE_NOTALLSTORED
+
+
+Some of the licenses could not be stored.
+
+0xC00D2760
+
+NS_E_DRM_SECURITY_COMPONENT_SIGNATURE_INVALID
+
+
+The Digital Rights Management security upgrade component could not be validated. Contact Microsoft product support.
+
+0xC00D2761
+
+NS_E_DRM_INVALID_DATA
+
+
+Invalid or corrupt data was encountered.
+
+0xC00D2762
+
+NS_E_DRM_POLICY_DISABLE_ONLINE
+
+
+The Windows Media Digital Rights Management system cannot perform the requested action because your computer or network administrator has enabled the group policy Prevent Windows Media DRM Internet Access. For assistance, contact your administrator.
+
+0xC00D2763
+
+NS_E_DRM_UNABLE_TO_CREATE_AUTHENTICATION_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2764
+
+NS_E_DRM_NOT_CONFIGURED
+
+
+Not all of the necessary properties for DRM have been set.
+
+0xC00D2765
+
+NS_E_DRM_DEVICE_ACTIVATION_CANCELED
+
+
+The portable device does not have the security required to copy protected files to it. To obtain the additional security, try to copy the file to your portable device again. When a message appears, click OK.
+
+0xC00D2766
+
+NS_E_BACKUP_RESTORE_TOO_MANY_RESETS
+
+
+Too many resets in Backup-Restore.
+
+0xC00D2767
+
+NS_E_DRM_DEBUGGING_NOT_ALLOWED
+
+
+Running this process under a debugger while using DRM content is not allowed.
+
+0xC00D2768
+
+NS_E_DRM_OPERATION_CANCELED
+
+
+The user canceled the DRM operation.
+
+0xC00D2769
+
+NS_E_DRM_RESTRICTIONS_NOT_RETRIEVED
+
+
+The license you are using has assocaited output restrictions. This license is unusable until these restrictions are queried.
+
+0xC00D276A
+
+NS_E_DRM_UNABLE_TO_CREATE_PLAYLIST_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D276B
+
+NS_E_DRM_UNABLE_TO_CREATE_PLAYLIST_BURN_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D276C
+
+NS_E_DRM_UNABLE_TO_CREATE_DEVICE_REGISTRATION_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D276D
+
+NS_E_DRM_UNABLE_TO_CREATE_METERING_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2770
+
+NS_E_DRM_TRACK_EXCEEDED_PLAYLIST_RESTICTION
+
+
+The specified track has exceeded it's specified playlist burn limit in this playlist.
+
+0xC00D2771
+
+NS_E_DRM_TRACK_EXCEEDED_TRACKBURN_RESTRICTION
+
+
+The specified track has exceeded it's track burn limit.
+
+0xC00D2772
+
+NS_E_DRM_UNABLE_TO_GET_DEVICE_CERT
+
+
+A problem has occurred in obtaining the device's certificate. Contact Microsoft product support.
+
+0xC00D2773
+
+NS_E_DRM_UNABLE_TO_GET_SECURE_CLOCK
+
+
+A problem has occurred in obtaining the device's secure clock. Contact Microsoft product support.
+
+0xC00D2774
+
+NS_E_DRM_UNABLE_TO_SET_SECURE_CLOCK
+
+
+A problem has occurred in setting the device's secure clock. Contact Microsoft product support.
+
+0xC00D2775
+
+NS_E_DRM_UNABLE_TO_GET_SECURE_CLOCK_FROM_SERVER
+
+
+A problem has occurred in obtaining the secure clock from server. Contact Microsoft product support.
+
+0xC00D2776
+
+NS_E_DRM_POLICY_METERING_DISABLED
+
+
+This content requires the metering policy to be enabled.
+
+0xC00D2777
+
+NS_E_DRM_TRANSFER_CHAINED_LICENSES_UNSUPPORTED
+
+
+Transfer of chained licenses unsupported.
+
+0xC00D2778
+
+NS_E_DRM_SDK_VERSIONMISMATCH
+
+
+The Digital Rights Management component is not installed properly. Reinstall the Player.
+
+0xC00D2779
+
+NS_E_DRM_LIC_NEEDS_DEVICE_CLOCK_SET
+
+
+The file could not be transferred because the device clock is not set.
+
+0xC00D277A
+
+NS_E_LICENSE_HEADER_MISSING_URL
+
+
+The content header is missing an acquisition URL.
+
+0xC00D277B
+
+NS_E_DEVICE_NOT_WMDRM_DEVICE
+
+
+The current attached device does not support WMDRM.
+
+0xC00D277C
+
+NS_E_DRM_INVALID_APPCERT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D277D
+
+NS_E_DRM_PROTOCOL_FORCEFUL_TERMINATION_ON_PETITION
+
+
+The client application has been forcefully terminated during a DRM petition.
+
+0xC00D277E
+
+NS_E_DRM_PROTOCOL_FORCEFUL_TERMINATION_ON_CHALLENGE
+
+
+The client application has been forcefully terminated during a DRM challenge.
+
+0xC00D277F
+
+NS_E_DRM_CHECKPOINT_FAILED
+
+
+Secure storage protection error. Restore your licenses from a previous backup and try again.
+
+0xC00D2780
+
+NS_E_DRM_BB_UNABLE_TO_INITIALIZE
+
+
+A problem has occurred in the Digital Rights Management root of trust. Contact Microsoft product support.
+
+0xC00D2781
+
+NS_E_DRM_UNABLE_TO_LOAD_HARDWARE_ID
+
+
+A problem has occurred in retrieving the Digital Rights Management machine identification. Contact Microsoft product support.
+
+0xC00D2782
+
+NS_E_DRM_UNABLE_TO_OPEN_DATA_STORE
+
+
+A problem has occurred in opening the Digital Rights Management data storage file. Contact Microsoft product.
+
+0xC00D2783
+
+NS_E_DRM_DATASTORE_CORRUPT
+
+
+The Digital Rights Management data storage is not functioning properly. Contact Microsoft product support.
+
+0xC00D2784
+
+NS_E_DRM_UNABLE_TO_CREATE_INMEMORYSTORE_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2785
+
+NS_E_DRM_STUBLIB_REQUIRED
+
+
+A secured library is required to access the requested functionality.
+
+0xC00D2786
+
+NS_E_DRM_UNABLE_TO_CREATE_CERTIFICATE_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2787
+
+NS_E_DRM_MIGRATION_TARGET_NOT_ONLINE
+
+
+A problem has occurred in the Digital Rights Management component during license migration. Contact Microsoft product support.
+
+0xC00D2788
+
+NS_E_DRM_INVALID_MIGRATION_IMAGE
+
+
+A problem has occurred in the Digital Rights Management component during license migration. Contact Microsoft product support.
+
+0xC00D2789
+
+NS_E_DRM_MIGRATION_TARGET_STATES_CORRUPTED
+
+
+A problem has occurred in the Digital Rights Management component during license migration. Contact Microsoft product support.
+
+0xC00D278A
+
+NS_E_DRM_MIGRATION_IMPORTER_NOT_AVAILABLE
+
+
+A problem has occurred in the Digital Rights Management component during license migration. Contact Microsoft product support.
+
+0xC00D278B
+
+NS_DRM_E_MIGRATION_UPGRADE_WITH_DIFF_SID
+
+
+A problem has occurred in the Digital Rights Management component during license migration. Contact Microsoft product support.
+
+0xC00D278C
+
+NS_DRM_E_MIGRATION_SOURCE_MACHINE_IN_USE
+
+
+The Digital Rights Management component is in use during license migration. Contact Microsoft product support.
+
+0xC00D278D
+
+NS_DRM_E_MIGRATION_TARGET_MACHINE_LESS_THAN_LH
+
+
+Licenses are being migrated to a machine running XP or downlevel OS. This operation can only be performed on Windows Vista or a later OS. Contact Microsoft product support.
+
+0xC00D278E
+
+NS_DRM_E_MIGRATION_IMAGE_ALREADY_EXISTS
+
+
+Migration Image already exists. Contact Microsoft product support.
+
+0xC00D278F
+
+NS_E_DRM_HARDWAREID_MISMATCH
+
+
+The requested action cannot be performed because a hardware configuration change has been detected by the Windows Media Digital Rights Management (DRM) components on your computer.
+
+0xC00D2790
+
+NS_E_INVALID_DRMV2CLT_STUBLIB
+
+
+The wrong stublib has been linked to an application or DLL using drmv2clt.dll.
+
+0xC00D2791
+
+NS_E_DRM_MIGRATION_INVALID_LEGACYV2_DATA
+
+
+The legacy V2 data being imported is invalid.
+
+0xC00D2792
+
+NS_E_DRM_MIGRATION_LICENSE_ALREADY_EXISTS
+
+
+The license being imported already exists.
+
+0xC00D2793
+
+NS_E_DRM_MIGRATION_INVALID_LEGACYV2_SST_PASSWORD
+
+
+The password of the Legacy V2 SST entry being imported is incorrect.
+
+0xC00D2794
+
+NS_E_DRM_MIGRATION_NOT_SUPPORTED
+
+
+Migration is not supported by the plugin.
+
+0xC00D2795
+
+NS_E_DRM_UNABLE_TO_CREATE_MIGRATION_IMPORTER_OBJECT
+
+
+A migration importer cannot be created for this media file. Reinstall the application.
+
+0xC00D2796
+
+NS_E_DRM_CHECKPOINT_MISMATCH
+
+
+The requested action cannot be performed because a problem occurred with the Windows Media Digital Rights Management (DRM) components on your computer.
+
+0xC00D2797
+
+NS_E_DRM_CHECKPOINT_CORRUPT
+
+
+The requested action cannot be performed because a problem occurred with the Windows Media Digital Rights Management (DRM) components on your computer.
+
+0xC00D2798
+
+NS_E_REG_FLUSH_FAILURE
+
+
+The requested action cannot be performed because a problem occurred with the Windows Media Digital Rights Management (DRM) components on your computer.
+
+0xC00D2799
+
+NS_E_HDS_KEY_MISMATCH
+
+
+The requested action cannot be performed because a problem occurred with the Windows Media Digital Rights Management (DRM) components on your computer.
+
+0xC00D279A
+
+NS_E_DRM_MIGRATION_OPERATION_CANCELLED
+
+
+Migration was canceled by the user.
+
+0xC00D279B
+
+NS_E_DRM_MIGRATION_OBJECT_IN_USE
+
+
+Migration object is already in use and cannot be called until the current operation completes.
+
+0xC00D279C
+
+NS_E_DRM_MALFORMED_CONTENT_HEADER
+
+
+The content header does not comply with DRM requirements and cannot be used.
+
+0xC00D27D8
+
+NS_E_DRM_LICENSE_EXPIRED
+
+
+The license for this file has expired and is no longer valid. Contact your content provider for further assistance.
+
+0xC00D27D9
+
+NS_E_DRM_LICENSE_NOTENABLED
+
+
+The license for this file is not valid yet, but will be at a future date.
+
+0xC00D27DA
+
+NS_E_DRM_LICENSE_APPSECLOW
+
+
+The license for this file requires a higher level of security than the player you are currently using has. Try using a different player or download a newer version of your current player.
+
+0xC00D27DB
+
+NS_E_DRM_STORE_NEEDINDI
+
+
+The license cannot be stored as it requires security upgrade of Digital Rights Management component.
+
+0xC00D27DC
+
+NS_E_DRM_STORE_NOTALLOWED
+
+
+Your machine does not meet the requirements for storing the license.
+
+0xC00D27DD
+
+NS_E_DRM_LICENSE_APP_NOTALLOWED
+
+
+The license for this file requires an upgraded version of your player or a different player.
+
+0xC00D27DF
+
+NS_E_DRM_LICENSE_CERT_EXPIRED
+
+
+The license server's certificate expired. Make sure your system clock is set correctly. Contact your content provider for further assistance.
+
+0xC00D27E0
+
+NS_E_DRM_LICENSE_SECLOW
+
+
+The license for this file requires a higher level of security than the player you are currently using has. Try using a different player or download a newer version of your current player.
+
+0xC00D27E1
+
+NS_E_DRM_LICENSE_CONTENT_REVOKED
+
+
+The content owner for the license you just acquired is no longer supporting their content. Contact the content owner for a newer version of the content.
+
+0xC00D27E2
+
+NS_E_DRM_DEVICE_NOT_REGISTERED
+
+
+The content owner for the license you just acquired requires your device to register to the current machine.
+
+0xC00D280A
+
+NS_E_DRM_LICENSE_NOSAP
+
+
+The license for this file requires a feature that is not supported in your current player or operating system. You can try with newer version of your current player or contact your content provider for further assistance.
+
+0xC00D280B
+
+NS_E_DRM_LICENSE_NOSVP
+
+
+The license for this file requires a feature that is not supported in your current player or operating system. You can try with newer version of your current player or contact your content provider for further assistance.
+
+0xC00D280C
+
+NS_E_DRM_LICENSE_NOWDM
+
+
+The license for this file requires Windows Driver Model (WDM) audio drivers. Contact your sound card manufacturer for further assistance.
+
+0xC00D280D
+
+NS_E_DRM_LICENSE_NOTRUSTEDCODEC
+
+
+The license for this file requires a higher level of security than the player you are currently using has. Try using a different player or download a newer version of your current player.
+
+0xC00D280E
+
+NS_E_DRM_SOURCEID_NOT_SUPPORTED
+
+
+The license for this file is not supported by your current player. You can try with newer version of your current player or contact your content provider for further assistance.
+
+0xC00D283D
+
+NS_E_DRM_NEEDS_UPGRADE_TEMPFILE
+
+
+An updated version of your media player is required to play the selected content.
+
+0xC00D283E
+
+NS_E_DRM_NEED_UPGRADE_PD
+
+
+A new version of the Digital Rights Management component is required. Contact product support for this application to get the latest version.
+
+0xC00D283F
+
+NS_E_DRM_SIGNATURE_FAILURE
+
+
+Failed to either create or verify the content header.
+
+0xC00D2840
+
+NS_E_DRM_LICENSE_SERVER_INFO_MISSING
+
+
+Could not read the necessary information from the system registry.
+
+0xC00D2841
+
+NS_E_DRM_BUSY
+
+
+The DRM subsystem is currently locked by another application or user. Try again later.
+
+0xC00D2842
+
+NS_E_DRM_PD_TOO_MANY_DEVICES
+
+
+There are too many target devices registered on the portable media.
+
+0xC00D2843
+
+NS_E_DRM_INDIV_FRAUD
+
+
+The security upgrade cannot be completed because the allowed number of daily upgrades has been exceeded. Try again tomorrow.
+
+0xC00D2844
+
+NS_E_DRM_INDIV_NO_CABS
+
+
+The security upgrade cannot be completed because the server is unable to perform the operation. Try again later.
+
+0xC00D2845
+
+NS_E_DRM_INDIV_SERVICE_UNAVAILABLE
+
+
+The security upgrade cannot be performed because the server is not available. Try again later.
+
+0xC00D2846
+
+NS_E_DRM_RESTORE_SERVICE_UNAVAILABLE
+
+
+Windows Media Player cannot restore your licenses because the server is not available. Try again later.
+
+0xC00D2847
+
+NS_E_DRM_CLIENT_CODE_EXPIRED
+
+
+Windows Media Player cannot play the protected file. Verify that your computer's date is set correctly. If it is correct, on the Help menu, click Check for Player Updates to install the latest version of the Player.
+
+0xC00D2848
+
+NS_E_DRM_NO_UPLINK_LICENSE
+
+
+The chained license cannot be created because the referenced uplink license does not exist.
+
+0xC00D2849
+
+NS_E_DRM_INVALID_KID
+
+
+The specified KID is invalid.
+
+0xC00D284A
+
+NS_E_DRM_LICENSE_INITIALIZATION_ERROR
+
+
+License initialization did not work. Contact Microsoft product support.
+
+0xC00D284C
+
+NS_E_DRM_CHAIN_TOO_LONG
+
+
+The uplink license of a chained license cannot itself be a chained license.
+
+0xC00D284D
+
+NS_E_DRM_UNSUPPORTED_ALGORITHM
+
+
+The specified encryption algorithm is unsupported.
+
+0xC00D284E
+
+NS_E_DRM_LICENSE_DELETION_ERROR
+
+
+License deletion did not work. Contact Microsoft product support.
+
+0xC00D28A0
+
+NS_E_DRM_INVALID_CERTIFICATE
+
+
+The client's certificate is corrupted or the signature cannot be verified.
+
+0xC00D28A1
+
+NS_E_DRM_CERTIFICATE_REVOKED
+
+
+The client's certificate has been revoked.
+
+0xC00D28A2
+
+NS_E_DRM_LICENSE_UNAVAILABLE
+
+
+There is no license available for the requested action.
+
+0xC00D28A3
+
+NS_E_DRM_DEVICE_LIMIT_REACHED
+
+
+The maximum number of devices in use has been reached. Unable to open additional devices.
+
+0xC00D28A4
+
+NS_E_DRM_UNABLE_TO_VERIFY_PROXIMITY
+
+
+The proximity detection procedure could not confirm that the receiver is near the transmitter in the network.
+
+0xC00D28A5
+
+NS_E_DRM_MUST_REGISTER
+
+
+The client must be registered before executing the intended operation.
+
+0xC00D28A6
+
+NS_E_DRM_MUST_APPROVE
+
+
+The client must be approved before executing the intended operation.
+
+0xC00D28A7
+
+NS_E_DRM_MUST_REVALIDATE
+
+
+The client must be revalidated before executing the intended operation.
+
+0xC00D28A8
+
+NS_E_DRM_INVALID_PROXIMITY_RESPONSE
+
+
+The response to the proximity detection challenge is invalid.
+
+0xC00D28A9
+
+NS_E_DRM_INVALID_SESSION
+
+
+The requested session is invalid.
+
+0xC00D28AA
+
+NS_E_DRM_DEVICE_NOT_OPEN
+
+
+The device must be opened before it can be used to receive content.
+
+0xC00D28AB
+
+NS_E_DRM_DEVICE_ALREADY_REGISTERED
+
+
+Device registration failed because the device is already registered.
+
+0xC00D28AC
+
+NS_E_DRM_UNSUPPORTED_PROTOCOL_VERSION
+
+
+Unsupported WMDRM-ND protocol version.
+
+0xC00D28AD
+
+NS_E_DRM_UNSUPPORTED_ACTION
+
+
+The requested action is not supported.
+
+0xC00D28AE
+
+NS_E_DRM_CERTIFICATE_SECURITY_LEVEL_INADEQUATE
+
+
+The certificate does not have an adequate security level for the requested action.
+
+0xC00D28AF
+
+NS_E_DRM_UNABLE_TO_OPEN_PORT
+
+
+Unable to open the specified port for receiving Proximity messages.
+
+0xC00D28B0
+
+NS_E_DRM_BAD_REQUEST
+
+
+The message format is invalid.
+
+0xC00D28B1
+
+NS_E_DRM_INVALID_CRL
+
+
+The Certificate Revocation List is invalid or corrupted.
+
+0xC00D28B2
+
+NS_E_DRM_ATTRIBUTE_TOO_LONG
+
+
+The length of the attribute name or value is too long.
+
+0xC00D28B3
+
+NS_E_DRM_EXPIRED_LICENSEBLOB
+
+
+The license blob passed in the cardea request is expired.
+
+0xC00D28B4
+
+NS_E_DRM_INVALID_LICENSEBLOB
+
+
+The license blob passed in the cardea request is invalid. Contact Microsoft product support.
+
+0xC00D28B5
+
+NS_E_DRM_INCLUSION_LIST_REQUIRED
+
+
+The requested operation cannot be performed because the license does not contain an inclusion list.
+
+0xC00D28B6
+
+NS_E_DRM_DRMV2CLT_REVOKED
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D28B7
+
+NS_E_DRM_RIV_TOO_SMALL
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2904
+
+NS_E_OUTPUT_PROTECTION_LEVEL_UNSUPPORTED
+
+
+Windows Media Player does not support the level of output protection required by the content.
+
+0xC00D2905
+
+NS_E_COMPRESSED_DIGITAL_VIDEO_PROTECTION_LEVEL_UNSUPPORTED
+
+
+Windows Media Player does not support the level of protection required for compressed digital video.
+
+0xC00D2906
+
+NS_E_UNCOMPRESSED_DIGITAL_VIDEO_PROTECTION_LEVEL_UNSUPPORTED
+
+
+Windows Media Player does not support the level of protection required for uncompressed digital video.
+
+0xC00D2907
+
+NS_E_ANALOG_VIDEO_PROTECTION_LEVEL_UNSUPPORTED
+
+
+Windows Media Player does not support the level of protection required for analog video.
+
+0xC00D2908
+
+NS_E_COMPRESSED_DIGITAL_AUDIO_PROTECTION_LEVEL_UNSUPPORTED
+
+
+Windows Media Player does not support the level of protection required for compressed digital audio.
+
+0xC00D2909
+
+NS_E_UNCOMPRESSED_DIGITAL_AUDIO_PROTECTION_LEVEL_UNSUPPORTED
+
+
+Windows Media Player does not support the level of protection required for uncompressed digital audio.
+
+0xC00D290A
+
+NS_E_OUTPUT_PROTECTION_SCHEME_UNSUPPORTED
+
+
+Windows Media Player does not support the scheme of output protection required by the content.
+
+0xC00D2AFA
+
+NS_E_REBOOT_RECOMMENDED
+
+
+Installation was not successful and some file cleanup is not complete. For best results, restart your computer.
+
+0xC00D2AFB
+
+NS_E_REBOOT_REQUIRED
+
+
+Installation was not successful. To continue, you must restart your computer.
+
+0xC00D2AFC
+
+NS_E_SETUP_INCOMPLETE
+
+
+Installation was not successful.
+
+0xC00D2AFD
+
+NS_E_SETUP_DRM_MIGRATION_FAILED
+
+
+Setup cannot migrate the Windows Media Digital Rights Management (DRM) components.
+
+0xC00D2AFE
+
+NS_E_SETUP_IGNORABLE_FAILURE
+
+
+Some skin or playlist components cannot be installed.
+
+0xC00D2AFF
+
+NS_E_SETUP_DRM_MIGRATION_FAILED_AND_IGNORABLE_FAILURE
+
+
+Setup cannot migrate the Windows Media Digital Rights Management (DRM) components. In addition, some skin or playlist components cannot be installed.
+
+0xC00D2B00
+
+NS_E_SETUP_BLOCKED
+
+
+Installation is blocked because your computer does not meet one or more of the setup requirements.
+
+0xC00D2EE0
+
+NS_E_UNKNOWN_PROTOCOL
+
+
+The specified protocol is not supported.
+
+0xC00D2EE1
+
+NS_E_REDIRECT_TO_PROXY
+
+
+The client is redirected to a proxy server.
+
+0xC00D2EE2
+
+NS_E_INTERNAL_SERVER_ERROR
+
+
+The server encountered an unexpected condition which prevented it from fulfilling the request.
+
+0xC00D2EE3
+
+NS_E_BAD_REQUEST
+
+
+The request could not be understood by the server.
+
+0xC00D2EE4
+
+NS_E_ERROR_FROM_PROXY
+
+
+The proxy experienced an error while attempting to contact the media server.
+
+0xC00D2EE5
+
+NS_E_PROXY_TIMEOUT
+
+
+The proxy did not receive a timely response while attempting to contact the media server.
+
+0xC00D2EE6
+
+NS_E_SERVER_UNAVAILABLE
+
+
+The server is currently unable to handle the request due to a temporary overloading or maintenance of the server.
+
+0xC00D2EE7
+
+NS_E_REFUSED_BY_SERVER
+
+
+The server is refusing to fulfill the requested operation.
+
+0xC00D2EE8
+
+NS_E_INCOMPATIBLE_SERVER
+
+
+The server is not a compatible streaming media server.
+
+0xC00D2EE9
+
+NS_E_MULTICAST_DISABLED
+
+
+The content cannot be streamed because the Multicast protocol has been disabled.
+
+0xC00D2EEA
+
+NS_E_INVALID_REDIRECT
+
+
+The server redirected the player to an invalid location.
+
+0xC00D2EEB
+
+NS_E_ALL_PROTOCOLS_DISABLED
+
+
+The content cannot be streamed because all protocols have been disabled.
+
+0xC00D2EEC
+
+NS_E_MSBD_NO_LONGER_SUPPORTED
+
+
+The MSBD protocol is no longer supported. Please use HTTP to connect to the Windows Media stream.
+
+0xC00D2EED
+
+NS_E_PROXY_NOT_FOUND
+
+
+The proxy server could not be located. Please check your proxy server configuration.
+
+0xC00D2EEE
+
+NS_E_CANNOT_CONNECT_TO_PROXY
+
+
+Unable to establish a connection to the proxy server. Please check your proxy server configuration.
+
+0xC00D2EEF
+
+NS_E_SERVER_DNS_TIMEOUT
+
+
+Unable to locate the media server. The operation timed out.
+
+0xC00D2EF0
+
+NS_E_PROXY_DNS_TIMEOUT
+
+
+Unable to locate the proxy server. The operation timed out.
+
+0xC00D2EF1
+
+NS_E_CLOSED_ON_SUSPEND
+
+
+Media closed because Windows was shut down.
+
+0xC00D2EF2
+
+NS_E_CANNOT_READ_PLAYLIST_FROM_MEDIASERVER
+
+
+Unable to read the contents of a playlist file from a media server.
+
+0xC00D2EF3
+
+NS_E_SESSION_NOT_FOUND
+
+
+Session not found.
+
+0xC00D2EF4
+
+NS_E_REQUIRE_STREAMING_CLIENT
+
+
+Content requires a streaming media client.
+
+0xC00D2EF5
+
+NS_E_PLAYLIST_ENTRY_HAS_CHANGED
+
+
+A command applies to a previous playlist entry.
+
+0xC00D2EF6
+
+NS_E_PROXY_ACCESSDENIED
+
+
+The proxy server is denying access. The username and/or password might be incorrect.
+
+0xC00D2EF7
+
+NS_E_PROXY_SOURCE_ACCESSDENIED
+
+
+The proxy could not provide valid authentication credentials to the media server.
+
+0xC00D2EF8
+
+NS_E_NETWORK_SINK_WRITE
+
+
+The network sink failed to write data to the network.
+
+0xC00D2EF9
+
+NS_E_FIREWALL
+
+
+Packets are not being received from the server. The packets might be blocked by a filtering device, such as a network firewall.
+
+0xC00D2EFA
+
+NS_E_MMS_NOT_SUPPORTED
+
+
+The MMS protocol is not supported. Please use HTTP or RTSP to connect to the Windows Media stream.
+
+0xC00D2EFB
+
+NS_E_SERVER_ACCESSDENIED
+
+
+The Windows Media server is denying access. The username and/or password might be incorrect.
+
+0xC00D2EFC
+
+NS_E_RESOURCE_GONE
+
+
+The Publishing Point or file on the Windows Media Server is no longer available.
+
+0xC00D2EFD
+
+NS_E_NO_EXISTING_PACKETIZER
+
+
+There is no existing packetizer plugin for a stream.
+
+0xC00D2EFE
+
+NS_E_BAD_SYNTAX_IN_SERVER_RESPONSE
+
+
+The response from the media server could not be understood. This might be caused by an incompatible proxy server or media server.
+
+0xC00D2F00
+
+NS_E_RESET_SOCKET_CONNECTION
+
+
+The Windows Media Server reset the network connection.
+
+0xC00D2F02
+
+NS_E_TOO_MANY_HOPS
+
+
+The request could not reach the media server (too many hops).
+
+0xC00D2F05
+
+NS_E_TOO_MUCH_DATA_FROM_SERVER
+
+
+The server is sending too much data. The connection has been terminated.
+
+0xC00D2F06
+
+NS_E_CONNECT_TIMEOUT
+
+
+It was not possible to establish a connection to the media server in a timely manner. The media server might be down for maintenance, or it might be necessary to use a proxy server to access this media server.
+
+0xC00D2F07
+
+NS_E_PROXY_CONNECT_TIMEOUT
+
+
+It was not possible to establish a connection to the proxy server in a timely manner. Please check your proxy server configuration.
+
+0xC00D2F08
+
+NS_E_SESSION_INVALID
+
+
+Session not found.
+
+0xC00D2F0A
+
+NS_E_PACKETSINK_UNKNOWN_FEC_STREAM
+
+
+Unknown packet sink stream.
+
+0xC00D2F0B
+
+NS_E_PUSH_CANNOTCONNECT
+
+
+Unable to establish a connection to the server. Ensure Windows Media Services is started and the HTTP Server control protocol is properly enabled.
+
+0xC00D2F0C
+
+NS_E_INCOMPATIBLE_PUSH_SERVER
+
+
+The Server service that received the HTTP push request is not a compatible version of Windows Media Services (WMS). This error might indicate the push request was received by IIS instead of WMS. Ensure WMS is started and has the HTTP Server control protocol properly enabled and try again.
+
+0xC00D32C8
+
+NS_E_END_OF_PLAYLIST
+
+
+The playlist has reached its end.
+
+0xC00D32C9
+
+NS_E_USE_FILE_SOURCE
+
+
+Use file source.
+
+0xC00D32CA
+
+NS_E_PROPERTY_NOT_FOUND
+
+
+The property was not found.
+
+0xC00D32CC
+
+NS_E_PROPERTY_READ_ONLY
+
+
+The property is read only.
+
+0xC00D32CD
+
+NS_E_TABLE_KEY_NOT_FOUND
+
+
+The table key was not found.
+
+0xC00D32CF
+
+NS_E_INVALID_QUERY_OPERATOR
+
+
+Invalid query operator.
+
+0xC00D32D0
+
+NS_E_INVALID_QUERY_PROPERTY
+
+
+Invalid query property.
+
+0xC00D32D2
+
+NS_E_PROPERTY_NOT_SUPPORTED
+
+
+The property is not supported.
+
+0xC00D32D4
+
+NS_E_SCHEMA_CLASSIFY_FAILURE
+
+
+Schema classification failure.
+
+0xC00D32D5
+
+NS_E_METADATA_FORMAT_NOT_SUPPORTED
+
+
+The metadata format is not supported.
+
+0xC00D32D6
+
+NS_E_METADATA_NO_EDITING_CAPABILITY
+
+
+Cannot edit the metadata.
+
+0xC00D32D7
+
+NS_E_METADATA_CANNOT_SET_LOCALE
+
+
+Cannot set the locale id.
+
+0xC00D32D8
+
+NS_E_METADATA_LANGUAGE_NOT_SUPORTED
+
+
+The language is not supported in the format.
+
+0xC00D32D9
+
+NS_E_METADATA_NO_RFC1766_NAME_FOR_LOCALE
+
+
+There is no RFC1766 name translation for the supplied locale id.
+
+0xC00D32DA
+
+NS_E_METADATA_NOT_AVAILABLE
+
+
+The metadata (or metadata item) is not available.
+
+0xC00D32DB
+
+NS_E_METADATA_CACHE_DATA_NOT_AVAILABLE
+
+
+The cached metadata (or metadata item) is not available.
+
+0xC00D32DC
+
+NS_E_METADATA_INVALID_DOCUMENT_TYPE
+
+
+The metadata document is invalid.
+
+0xC00D32DD
+
+NS_E_METADATA_IDENTIFIER_NOT_AVAILABLE
+
+
+The metadata content identifier is not available.
+
+0xC00D32DE
+
+NS_E_METADATA_CANNOT_RETRIEVE_FROM_OFFLINE_CACHE
+
+
+Cannot retrieve metadata from the offline metadata cache.
+
+0xC0261003
+
+ERROR_MONITOR_INVALID_DESCRIPTOR_CHECKSUM
+
+
+Checksum of the obtained monitor descriptor is invalid.
+
+0xC0261004
+
+ERROR_MONITOR_INVALID_STANDARD_TIMING_BLOCK
+
+
+Monitor descriptor contains an invalid standard timing block.
+
+0xC0261005
+
+ERROR_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED
+
+
+Windows Management Instrumentation (WMI) data block registration failed for one of the MSMonitorClass WMI subclasses.
+
+0xC0261006
+
+ERROR_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK
+
+
+Provided monitor descriptor block is either corrupted or does not contain the monitor's detailed serial number.
+
+0xC0261007
+
+ERROR_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK
+
+
+Provided monitor descriptor block is either corrupted or does not contain the monitor's user-friendly name.
+
+0xC0261008
+
+ERROR_MONITOR_NO_MORE_DESCRIPTOR_DATA
+
+
+There is no monitor descriptor data at the specified (offset, size) region.
+
+0xC0261009
+
+ERROR_MONITOR_INVALID_DETAILED_TIMING_BLOCK
+
+
+Monitor descriptor contains an invalid detailed timing block.
+
+0xC0262000
+
+ERROR_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER
+
+
+Exclusive mode ownership is needed to create unmanaged primary allocation.
+
+0xC0262001
+
+ERROR_GRAPHICS_INSUFFICIENT_DMA_BUFFER
+
+
+The driver needs more direct memory access (DMA) buffer space to complete the requested operation.
+
+0xC0262002
+
+ERROR_GRAPHICS_INVALID_DISPLAY_ADAPTER
+
+
+Specified display adapter handle is invalid.
+
+0xC0262003
+
+ERROR_GRAPHICS_ADAPTER_WAS_RESET
+
+
+Specified display adapter and all of its state has been reset.
+
+0xC0262004
+
+ERROR_GRAPHICS_INVALID_DRIVER_MODEL
+
+
+The driver stack does not match the expected driver model.
+
+0xC0262005
+
+ERROR_GRAPHICS_PRESENT_MODE_CHANGED
+
+
+Present happened but ended up into the changed desktop mode.
+
+0xC0262006
+
+ERROR_GRAPHICS_PRESENT_OCCLUDED
+
+
+Nothing to present due to desktop occlusion.
+
+0xC0262007
+
+ERROR_GRAPHICS_PRESENT_DENIED
+
+
+Not able to present due to denial of desktop access.
+
+0xC0262008
+
+ERROR_GRAPHICS_CANNOTCOLORCONVERT
+
+
+Not able to present with color conversion.
+
+0xC0262100
+
+ERROR_GRAPHICS_NO_VIDEO_MEMORY
+
+
+Not enough video memory available to complete the operation.
+
+0xC0262101
+
+ERROR_GRAPHICS_CANT_LOCK_MEMORY
+
+
+Could not probe and lock the underlying memory of an allocation.
+
+0xC0262102
+
+ERROR_GRAPHICS_ALLOCATION_BUSY
+
+
+The allocation is currently busy.
+
+0xC0262103
+
+ERROR_GRAPHICS_TOO_MANY_REFERENCES
+
+
+An object being referenced has reach the maximum reference count already and cannot be referenced further.
+
+0xC0262104
+
+ERROR_GRAPHICS_TRY_AGAIN_LATER
+
+
+A problem could not be solved due to some currently existing condition. The problem should be tried again later.
+
+0xC0262105
+
+ERROR_GRAPHICS_TRY_AGAIN_NOW
+
+
+A problem could not be solved due to some currently existing condition. The problem should be tried again immediately.
+
+0xC0262106
+
+ERROR_GRAPHICS_ALLOCATION_INVALID
+
+
+The allocation is invalid.
+
+0xC0262107
+
+ERROR_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE
+
+
+No more unswizzling apertures are currently available.
+
+0xC0262108
+
+ERROR_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED
+
+
+The current allocation cannot be unswizzled by an aperture.
+
+0xC0262109
+
+ERROR_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION
+
+
+The request failed because a pinned allocation cannot be evicted.
+
+0xC0262110
+
+ERROR_GRAPHICS_INVALID_ALLOCATION_USAGE
+
+
+The allocation cannot be used from its current segment location for the specified operation.
+
+0xC0262111
+
+ERROR_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION
+
+
+A locked allocation cannot be used in the current command buffer.
+
+0xC0262112
+
+ERROR_GRAPHICS_ALLOCATION_CLOSED
+
+
+The allocation being referenced has been closed permanently.
+
+0xC0262113
+
+ERROR_GRAPHICS_INVALID_ALLOCATION_INSTANCE
+
+
+An invalid allocation instance is being referenced.
+
+0xC0262114
+
+ERROR_GRAPHICS_INVALID_ALLOCATION_HANDLE
+
+
+An invalid allocation handle is being referenced.
+
+0xC0262115
+
+ERROR_GRAPHICS_WRONG_ALLOCATION_DEVICE
+
+
+The allocation being referenced does not belong to the current device.
+
+0xC0262116
+
+ERROR_GRAPHICS_ALLOCATION_CONTENT_LOST
+
+
+The specified allocation lost its content.
+
+0xC0262200
+
+ERROR_GRAPHICS_GPU_EXCEPTION_ON_DEVICE
+
+
+Graphics processing unit (GPU) exception is detected on the given device. The device is not able to be scheduled.
+
+0xC0262300
+
+ERROR_GRAPHICS_INVALID_VIDPN_TOPOLOGY
+
+
+Specified video present network (VidPN) topology is invalid.
+
+0xC0262301
+
+ERROR_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED
+
+
+Specified VidPN topology is valid but is not supported by this model of the display adapter.
+
+0xC0262302
+
+ERROR_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED
+
+
+Specified VidPN topology is valid but is not supported by the display adapter at this time, due to current allocation of its resources.
+
+0xC0262303
+
+ERROR_GRAPHICS_INVALID_VIDPN
+
+
+Specified VidPN handle is invalid.
+
+0xC0262304
+
+ERROR_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE
+
+
+Specified video present source is invalid.
+
+0xC0262305
+
+ERROR_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET
+
+
+Specified video present target is invalid.
+
+0xC0262306
+
+ERROR_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED
+
+
+Specified VidPN modality is not supported (for example, at least two of the pinned modes are not cofunctional).
+
+0xC0262308
+
+ERROR_GRAPHICS_INVALID_VIDPN_SOURCEMODESET
+
+
+Specified VidPN source mode set is invalid.
+
+0xC0262309
+
+ERROR_GRAPHICS_INVALID_VIDPN_TARGETMODESET
+
+
+Specified VidPN target mode set is invalid.
+
+0xC026230A
+
+ERROR_GRAPHICS_INVALID_FREQUENCY
+
+
+Specified video signal frequency is invalid.
+
+0xC026230B
+
+ERROR_GRAPHICS_INVALID_ACTIVE_REGION
+
+
+Specified video signal active region is invalid.
+
+0xC026230C
+
+ERROR_GRAPHICS_INVALID_TOTAL_REGION
+
+
+Specified video signal total region is invalid.
+
+0xC0262310
+
+ERROR_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE
+
+
+Specified video present source mode is invalid.
+
+0xC0262311
+
+ERROR_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE
+
+
+Specified video present target mode is invalid.
+
+0xC0262312
+
+ERROR_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET
+
+
+Pinned mode must remain in the set on VidPN's cofunctional modality enumeration.
+
+0xC0262313
+
+ERROR_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY
+
+
+Specified video present path is already in the VidPN topology.
+
+0xC0262314
+
+ERROR_GRAPHICS_MODE_ALREADY_IN_MODESET
+
+
+Specified mode is already in the mode set.
+
+0xC0262315
+
+ERROR_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET
+
+
+Specified video present source set is invalid.
+
+0xC0262316
+
+ERROR_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET
+
+
+Specified video present target set is invalid.
+
+0xC0262317
+
+ERROR_GRAPHICS_SOURCE_ALREADY_IN_SET
+
+
+Specified video present source is already in the video present source set.
+
+0xC0262318
+
+ERROR_GRAPHICS_TARGET_ALREADY_IN_SET
+
+
+Specified video present target is already in the video present target set.
+
+0xC0262319
+
+ERROR_GRAPHICS_INVALID_VIDPN_PRESENT_PATH
+
+
+Specified VidPN present path is invalid.
+
+0xC026231A
+
+ERROR_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY
+
+
+Miniport has no recommendation for augmentation of the specified VidPN topology.
+
+0xC026231B
+
+ERROR_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET
+
+
+Specified monitor frequency range set is invalid.
+
+0xC026231C
+
+ERROR_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE
+
+
+Specified monitor frequency range is invalid.
+
+0xC026231D
+
+ERROR_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET
+
+
+Specified frequency range is not in the specified monitor frequency range set.
+
+0xC026231F
+
+ERROR_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET
+
+
+Specified frequency range is already in the specified monitor frequency range set.
+
+0xC0262320
+
+ERROR_GRAPHICS_STALE_MODESET
+
+
+Specified mode set is stale. Reacquire the new mode set.
+
+0xC0262321
+
+ERROR_GRAPHICS_INVALID_MONITOR_SOURCEMODESET
+
+
+Specified monitor source mode set is invalid.
+
+0xC0262322
+
+ERROR_GRAPHICS_INVALID_MONITOR_SOURCE_MODE
+
+
+Specified monitor source mode is invalid.
+
+0xC0262323
+
+ERROR_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN
+
+
+Miniport does not have any recommendation regarding the request to provide a functional VidPN given the current display adapter configuration.
+
+0xC0262324
+
+ERROR_GRAPHICS_MODE_ID_MUST_BE_UNIQUE
+
+
+ID of the specified mode is already used by another mode in the set.
+
+0xC0262325
+
+ERROR_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION
+
+
+System failed to determine a mode that is supported by both the display adapter and the monitor connected to it.
+
+0xC0262326
+
+ERROR_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES
+
+
+Number of video present targets must be greater than or equal to the number of video present sources.
+
+0xC0262327
+
+ERROR_GRAPHICS_PATH_NOT_IN_TOPOLOGY
+
+
+Specified present path is not in the VidPN topology.
+
+0xC0262328
+
+ERROR_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE
+
+
+Display adapter must have at least one video present source.
+
+0xC0262329
+
+ERROR_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET
+
+
+Display adapter must have at least one video present target.
+
+0xC026232A
+
+ERROR_GRAPHICS_INVALID_MONITORDESCRIPTORSET
+
+
+Specified monitor descriptor set is invalid.
+
+0xC026232B
+
+ERROR_GRAPHICS_INVALID_MONITORDESCRIPTOR
+
+
+Specified monitor descriptor is invalid.
+
+0xC026232C
+
+ERROR_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET
+
+
+Specified descriptor is not in the specified monitor descriptor set.
+
+0xC026232D
+
+ERROR_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET
+
+
+Specified descriptor is already in the specified monitor descriptor set.
+
+0xC026232E
+
+ERROR_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE
+
+
+ID of the specified monitor descriptor is already used by another descriptor in the set.
+
+0xC026232F
+
+ERROR_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE
+
+
+Specified video present target subset type is invalid.
+
+0xC0262330
+
+ERROR_GRAPHICS_RESOURCES_NOT_RELATED
+
+
+Two or more of the specified resources are not related to each other, as defined by the interface semantics.
+
+0xC0262331
+
+ERROR_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE
+
+
+ID of the specified video present source is already used by another source in the set.
+
+0xC0262332
+
+ERROR_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE
+
+
+ID of the specified video present target is already used by another target in the set.
+
+0xC0262333
+
+ERROR_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET
+
+
+Specified VidPN source cannot be used because there is no available VidPN target to connect it to.
+
+0xC0262334
+
+ERROR_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER
+
+
+Newly arrived monitor could not be associated with a display adapter.
+
+0xC0262335
+
+ERROR_GRAPHICS_NO_VIDPNMGR
+
+
+Display adapter in question does not have an associated VidPN manager.
+
+0xC0262336
+
+ERROR_GRAPHICS_NO_ACTIVE_VIDPN
+
+
+VidPN manager of the display adapter in question does not have an active VidPN.
+
+0xC0262337
+
+ERROR_GRAPHICS_STALE_VIDPN_TOPOLOGY
+
+
+Specified VidPN topology is stale. Re-acquire the new topology.
+
+0xC0262338
+
+ERROR_GRAPHICS_MONITOR_NOT_CONNECTED
+
+
+There is no monitor connected on the specified video present target.
+
+0xC0262339
+
+ERROR_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY
+
+
+Specified source is not part of the specified VidPN topology.
+
+0xC026233A
+
+ERROR_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE
+
+
+Specified primary surface size is invalid.
+
+0xC026233B
+
+ERROR_GRAPHICS_INVALID_VISIBLEREGION_SIZE
+
+
+Specified visible region size is invalid.
+
+0xC026233C
+
+ERROR_GRAPHICS_INVALID_STRIDE
+
+
+Specified stride is invalid.
+
+0xC026233D
+
+ERROR_GRAPHICS_INVALID_PIXELFORMAT
+
+
+Specified pixel format is invalid.
+
+0xC026233E
+
+ERROR_GRAPHICS_INVALID_COLORBASIS
+
+
+Specified color basis is invalid.
+
+0xC026233F
+
+ERROR_GRAPHICS_INVALID_PIXELVALUEACCESSMODE
+
+
+Specified pixel value access mode is invalid.
+
+0xC0262340
+
+ERROR_GRAPHICS_TARGET_NOT_IN_TOPOLOGY
+
+
+Specified target is not part of the specified VidPN topology.
+
+0xC0262341
+
+ERROR_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT
+
+
+Failed to acquire display mode management interface.
+
+0xC0262342
+
+ERROR_GRAPHICS_VIDPN_SOURCE_IN_USE
+
+
+Specified VidPN source is already owned by a display mode manager (DMM) client and cannot be used until that client releases it.
+
+0xC0262343
+
+ERROR_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN
+
+
+Specified VidPN is active and cannot be accessed.
+
+0xC0262344
+
+ERROR_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL
+
+
+Specified VidPN present path importance ordinal is invalid.
+
+0xC0262345
+
+ERROR_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION
+
+
+Specified VidPN present path content geometry transformation is invalid.
+
+0xC0262346
+
+ERROR_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED
+
+
+Specified content geometry transformation is not supported on the respective VidPN present path.
+
+0xC0262347
+
+ERROR_GRAPHICS_INVALID_GAMMA_RAMP
+
+
+Specified gamma ramp is invalid.
+
+0xC0262348
+
+ERROR_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED
+
+
+Specified gamma ramp is not supported on the respective VidPN present path.
+
+0xC0262349
+
+ERROR_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED
+
+
+Multisampling is not supported on the respective VidPN present path.
+
+0xC026234A
+
+ERROR_GRAPHICS_MODE_NOT_IN_MODESET
+
+
+Specified mode is not in the specified mode set.
+
+0xC026234D
+
+ERROR_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON
+
+
+Specified VidPN topology recommendation reason is invalid.
+
+0xC026234E
+
+ERROR_GRAPHICS_INVALID_PATH_CONTENT_TYPE
+
+
+Specified VidPN present path content type is invalid.
+
+0xC026234F
+
+ERROR_GRAPHICS_INVALID_COPYPROTECTION_TYPE
+
+
+Specified VidPN present path copy protection type is invalid.
+
+0xC0262350
+
+ERROR_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS
+
+
+No more than one unassigned mode set can exist at any given time for a given VidPN source or target.
+
+0xC0262352
+
+ERROR_GRAPHICS_INVALID_SCANLINE_ORDERING
+
+
+The specified scan line ordering type is invalid.
+
+0xC0262353
+
+ERROR_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED
+
+
+Topology changes are not allowed for the specified VidPN.
+
+0xC0262354
+
+ERROR_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS
+
+
+All available importance ordinals are already used in the specified topology.
+
+0xC0262355
+
+ERROR_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT
+
+
+Specified primary surface has a different private format attribute than the current primary surface.
+
+0xC0262356
+
+ERROR_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM
+
+
+Specified mode pruning algorithm is invalid.
+
+0xC0262400
+
+ERROR_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED
+
+
+Specified display adapter child device already has an external device connected to it.
+
+0xC0262401
+
+ERROR_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED
+
+
+The display adapter child device does not support reporting a descriptor.
+
+0xC0262430
+
+ERROR_GRAPHICS_NOT_A_LINKED_ADAPTER
+
+
+The display adapter is not linked to any other adapters.
+
+0xC0262431
+
+ERROR_GRAPHICS_LEADLINK_NOT_ENUMERATED
+
+
+Lead adapter in a linked configuration was not enumerated yet.
+
+0xC0262432
+
+ERROR_GRAPHICS_CHAINLINKS_NOT_ENUMERATED
+
+
+Some chain adapters in a linked configuration were not enumerated yet.
+
+0xC0262433
+
+ERROR_GRAPHICS_ADAPTER_CHAIN_NOT_READY
+
+
+The chain of linked adapters is not ready to start because of an unknown failure.
+
+0xC0262434
+
+ERROR_GRAPHICS_CHAINLINKS_NOT_STARTED
+
+
+An attempt was made to start a lead link display adapter when the chain links were not started yet.
+
+0xC0262435
+
+ERROR_GRAPHICS_CHAINLINKS_NOT_POWERED_ON
+
+
+An attempt was made to turn on a lead link display adapter when the chain links were turned off.
+
+0xC0262436
+
+ERROR_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE
+
+
+The adapter link was found to be in an inconsistent state. Not all adapters are in an expected PNP or power state.
+
+0xC0262438
+
+ERROR_GRAPHICS_NOT_POST_DEVICE_DRIVER
+
+
+The driver trying to start is not the same as the driver for the posted display adapter.
+
+0xC0262500
+
+ERROR_GRAPHICS_OPM_NOT_SUPPORTED
+
+
+The driver does not support Output Protection Manager (OPM).
+
+0xC0262501
+
+ERROR_GRAPHICS_COPP_NOT_SUPPORTED
+
+
+The driver does not support Certified Output Protection Protocol (COPP).
+
+0xC0262502
+
+ERROR_GRAPHICS_UAB_NOT_SUPPORTED
+
+
+The driver does not support a user-accessible bus (UAB).
+
+0xC0262503
+
+ERROR_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS
+
+
+The specified encrypted parameters are invalid.
+
+0xC0262504
+
+ERROR_GRAPHICS_OPM_PARAMETER_ARRAY_TOO_SMALL
+
+
+An array passed to a function cannot hold all of the data that the function wants to put in it.
+
+0xC0262505
+
+ERROR_GRAPHICS_OPM_NO_VIDEO_OUTPUTS_EXIST
+
+
+The GDI display device passed to this function does not have any active video outputs.
+
+0xC0262506
+
+ERROR_GRAPHICS_PVP_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME
+
+
+The protected video path (PVP) cannot find an actual GDI display device that corresponds to the passed-in GDI display device name.
+
+0xC0262507
+
+ERROR_GRAPHICS_PVP_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP
+
+
+This function failed because the GDI display device passed to it was not attached to the Windows desktop.
+
+0xC0262508
+
+ERROR_GRAPHICS_PVP_MIRRORING_DEVICES_NOT_SUPPORTED
+
+
+The PVP does not support mirroring display devices because they do not have video outputs.
+
+0xC026250A
+
+ERROR_GRAPHICS_OPM_INVALID_POINTER
+
+
+The function failed because an invalid pointer parameter was passed to it. A pointer parameter is invalid if it is null, it points to an invalid address, it points to a kernel mode address, or it is not correctly aligned.
+
+0xC026250B
+
+ERROR_GRAPHICS_OPM_INTERNAL_ERROR
+
+
+An internal error caused this operation to fail.
+
+0xC026250C
+
+ERROR_GRAPHICS_OPM_INVALID_HANDLE
+
+
+The function failed because the caller passed in an invalid OPM user mode handle.
+
+0xC026250D
+
+ERROR_GRAPHICS_PVP_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE
+
+
+This function failed because the GDI device passed to it did not have any monitors associated with it.
+
+0xC026250E
+
+ERROR_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH
+
+
+A certificate could not be returned because the certificate buffer passed to the function was too small.
+
+0xC026250F
+
+ERROR_GRAPHICS_OPM_SPANNING_MODE_ENABLED
+
+
+A video output could not be created because the frame buffer is in spanning mode.
+
+0xC0262510
+
+ERROR_GRAPHICS_OPM_THEATER_MODE_ENABLED
+
+
+A video output could not be created because the frame buffer is in theater mode.
+
+0xC0262511
+
+ERROR_GRAPHICS_PVP_HFS_FAILED
+
+
+The function call failed because the display adapter's hardware functionality scan failed to validate the graphics hardware.
+
+0xC0262512
+
+ERROR_GRAPHICS_OPM_INVALID_SRM
+
+
+The High-Bandwidth Digital Content Protection (HDCP) System Renewability Message (SRM) passed to this function did not comply with section 5 of the HDCP 1.1 specification.
+
+0xC0262513
+
+ERROR_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP
+
+
+The video output cannot enable the HDCP system because it does not support it.
+
+0xC0262514
+
+ERROR_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP
+
+
+The video output cannot enable analog copy protection because it does not support it.
+
+0xC0262515
+
+ERROR_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA
+
+
+The video output cannot enable the Content Generation Management System Analog (CGMS-A) protection technology because it does not support it.
+
+0xC0262516
+
+ERROR_GRAPHICS_OPM_HDCP_SRM_NEVER_SET
+
+
+IOPMVideoOutput's GetInformation() method cannot return the version of the SRM being used because the application never successfully passed an SRM to the video output.
+
+0xC0262517
+
+ERROR_GRAPHICS_OPM_RESOLUTION_TOO_HIGH
+
+
+IOPMVideoOutput's Configure() method cannot enable the specified output protection technology because the output's screen resolution is too high.
+
+0xC0262518
+
+ERROR_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE
+
+
+IOPMVideoOutput's Configure() method cannot enable HDCP because the display adapter's HDCP hardware is already being used by other physical outputs.
+
+0xC0262519
+
+ERROR_GRAPHICS_OPM_VIDEO_OUTPUT_NO_LONGER_EXISTS
+
+
+The operating system asynchronously destroyed this OPM video output because the operating system's state changed. This error typically occurs because the monitor physical device object (PDO) associated with this video output was removed, the monitor PDO associated with this video output was stopped, the video output's session became a nonconsole session or the video output's desktop became an inactive desktop.
+
+0xC026251A
+
+ERROR_GRAPHICS_OPM_SESSION_TYPE_CHANGE_IN_PROGRESS
+
+
+IOPMVideoOutput's methods cannot be called when a session is changing its type. There are currently three types of sessions: console, disconnected and remote (remote desktop protocol [RDP] or Independent Computing Architecture [ICA]).
+
+0xC0262580
+
+ERROR_GRAPHICS_I2C_NOT_SUPPORTED
+
+
+The monitor connected to the specified video output does not have an I2C bus.
+
+0xC0262581
+
+ERROR_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST
+
+
+No device on the I2C bus has the specified address.
+
+0xC0262582
+
+ERROR_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA
+
+
+An error occurred while transmitting data to the device on the I2C bus.
+
+0xC0262583
+
+ERROR_GRAPHICS_I2C_ERROR_RECEIVING_DATA
+
+
+An error occurred while receiving data from the device on the I2C bus.
+
+0xC0262584
+
+ERROR_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED
+
+
+The monitor does not support the specified Virtual Control Panel (VCP) code.
+
+0xC0262585
+
+ERROR_GRAPHICS_DDCCI_INVALID_DATA
+
+
+The data received from the monitor is invalid.
+
+0xC0262586
+
+ERROR_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE
+
+
+A function call failed because a monitor returned an invalid Timing Status byte when the operating system used the Display Data Channel Command Interface (DDC/CI) Get Timing Report and Timing Message command to get a timing report from a monitor.
+
+0xC0262587
+
+ERROR_GRAPHICS_MCA_INVALID_CAPABILITIES_STRING
+
+
+The monitor returned a DDC/CI capabilities string that did not comply with the ACCESS.bus 3.0, DDC/CI 1.1 or MCCS 2 Revision 1 specification.
+
+0xC0262588
+
+ERROR_GRAPHICS_MCA_INTERNAL_ERROR
+
+
+An internal Monitor Configuration API error occurred.
+
+0xC0262589
+
+ERROR_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND
+
+
+An operation failed because a DDC/CI message had an invalid value in its command field.
+
+0xC026258A
+
+ERROR_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH
+
+
+This error occurred because a DDC/CI message length field contained an invalid value.
+
+0xC026258B
+
+ERROR_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM
+
+
+This error occurred because the value in a DDC/CI message checksum field did not match the message's computed checksum value. This error implies that the data was corrupted while it was being transmitted from a monitor to a computer.
+
+0xC02625D6
+
+ERROR_GRAPHICS_PMEA_INVALID_MONITOR
+
+
+The HMONITOR no longer exists, is not attached to the desktop, or corresponds to a mirroring device.
+
+0xC02625D7
+
+ERROR_GRAPHICS_PMEA_INVALID_D3D_DEVICE
+
+
+The Direct3D (D3D) device's GDI display device no longer exists, is not attached to the desktop, or is a mirroring display device.
+
+0xC02625D8
+
+ERROR_GRAPHICS_DDCCI_CURRENT_CURRENT_VALUE_GREATER_THAN_MAXIMUM_VALUE
+
+
+A continuous VCP code's current value is greater than its maximum value. This error code indicates that a monitor returned an invalid value.
+
+0xC02625D9
+
+ERROR_GRAPHICS_MCA_INVALID_VCP_VERSION
+
+
+The monitor's VCP Version (0xDF) VCP code returned an invalid version value.
+
+0xC02625DA
+
+ERROR_GRAPHICS_MCA_MONITOR_VIOLATES_MCCS_SPECIFICATION
+
+
+The monitor does not comply with the Monitor Control Command Set (MCCS) specification it claims to support.
+
+0xC02625DB
+
+ERROR_GRAPHICS_MCA_MCCS_VERSION_MISMATCH
+
+
+The MCCS version in a monitor's mccs_ver capability does not match the MCCS version the monitor reports when the VCP Version (0xDF) VCP code is used.
+
+0xC02625DC
+
+ERROR_GRAPHICS_MCA_UNSUPPORTED_MCCS_VERSION
+
+
+The Monitor Configuration API only works with monitors that support the MCCS 1.0 specification, the MCCS 2.0 specification, or the MCCS 2.0 Revision 1 specification.
+
+0xC02625DE
+
+ERROR_GRAPHICS_MCA_INVALID_TECHNOLOGY_TYPE_RETURNED
+
+
+The monitor returned an invalid monitor technology type. CRT, plasma, and LCD (TFT) are examples of monitor technology types. This error implies that the monitor violated the MCCS 2.0 or MCCS 2.0 Revision 1 specification.
+
+0xC02625DF
+
+ERROR_GRAPHICS_MCA_UNSUPPORTED_COLOR_TEMPERATURE
+
+
+The SetMonitorColorTemperature() caller passed a color temperature to it that the current monitor did not support. CRT, plasma, and LCD (TFT) are examples of monitor technology types. This error implies that the monitor violated the MCCS 2.0 or MCCS 2.0 Revision 1 specification.
+
+0xC02625E0
+
+ERROR_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED
+
+
+This function can be used only if a program is running in the local console session. It cannot be used if the program is running on a remote desktop session or on a terminal server session.
diff --git a/libcli/util/nterr.c b/libcli/util/nterr.c
new file mode 100644
index 0000000..cfe89f2
--- /dev/null
+++ b/libcli/util/nterr.c
@@ -0,0 +1,377 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ *
+ * Copyright (C) Luke Kenneth Casson Leighton 1997-2001.
+ * Copyright (C) Andrew Bartlett
+ * Copyright (C) Andrew Tridgell
+ *
+ * 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/>.
+ */
+
+/* NT error codes. please read nterr.h */
+
+#include "includes.h"
+#include "../libcli/ldap/ldap_errors.h"
+#undef strcasecmp
+
+#if !defined(N_)
+#define N_(string) string
+#endif
+
+#define DOS_CODE(class, code) { #class ":" #code, NT_STATUS_DOS(class, code) }
+#define LDAP_CODE(code) { #code, NT_STATUS_LDAP(code) }
+
+typedef struct
+{
+ const char *nt_errstr;
+ NTSTATUS nt_errcode;
+} nt_err_code_struct;
+
+#include "nterr_gen.c"
+
+/* Errors which aren't in the generated code because they're not in the
+ * same table as the other ones. */
+static const nt_err_code_struct special_errs[] =
+{
+ { "STATUS_NO_MORE_FILES", STATUS_NO_MORE_FILES },
+ { "STATUS_INVALID_EA_NAME", STATUS_INVALID_EA_NAME },
+ { "STATUS_BUFFER_OVERFLOW", STATUS_BUFFER_OVERFLOW },
+ { "STATUS_MORE_ENTRIES", STATUS_MORE_ENTRIES },
+ { "STATUS_SOME_UNMAPPED", STATUS_SOME_UNMAPPED },
+ { "NT_STATUS_ERROR_DS_OBJ_STRING_NAME_EXISTS", NT_STATUS_ERROR_DS_OBJ_STRING_NAME_EXISTS },
+ { "NT_STATUS_ERROR_DS_INCOMPATIBLE_VERSION", NT_STATUS_ERROR_DS_INCOMPATIBLE_VERSION },
+ { "NT_STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP", NT_STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP },
+ { "NT_STATUS_ABIOS_NOT_PRESENT", NT_STATUS_ABIOS_NOT_PRESENT },
+ { "NT_STATUS_ABIOS_LID_NOT_EXIST", NT_STATUS_ABIOS_LID_NOT_EXIST },
+ { "NT_STATUS_ABIOS_LID_ALREADY_OWNED", NT_STATUS_ABIOS_LID_ALREADY_OWNED },
+ { "NT_STATUS_ABIOS_NOT_LID_OWNER", NT_STATUS_ABIOS_NOT_LID_OWNER },
+ { "NT_STATUS_ABIOS_INVALID_COMMAND", NT_STATUS_ABIOS_INVALID_COMMAND },
+ { "NT_STATUS_ABIOS_INVALID_LID", NT_STATUS_ABIOS_INVALID_LID },
+ { "NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE", NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE },
+ { "NT_STATUS_ABIOS_INVALID_SELECTOR", NT_STATUS_ABIOS_INVALID_SELECTOR },
+ { "NT_STATUS_HANDLE_NOT_WAITABLE", NT_STATUS_HANDLE_NOT_WAITABLE },
+ { "NT_STATUS_DEVICE_POWER_FAILURE", NT_STATUS_DEVICE_POWER_FAILURE },
+ { "NT_STATUS_VHD_SHARED", NT_STATUS_VHD_SHARED },
+ { "NT_STATUS_SMB_BAD_CLUSTER_DIALECT", NT_STATUS_SMB_BAD_CLUSTER_DIALECT },
+ { "NT_STATUS_NO_SUCH_JOB", NT_STATUS_NO_SUCH_JOB },
+
+ DOS_CODE(ERRDOS, ERRsuccess),
+ DOS_CODE(ERRDOS, ERRbadfunc),
+ DOS_CODE(ERRDOS, ERRbadfile),
+ DOS_CODE(ERRDOS, ERRbadpath),
+ DOS_CODE(ERRDOS, ERRnofids),
+ DOS_CODE(ERRDOS, ERRnoaccess),
+ DOS_CODE(ERRDOS, ERRbadfid),
+ DOS_CODE(ERRDOS, ERRbadmcb),
+ DOS_CODE(ERRDOS, ERRnomem),
+ DOS_CODE(ERRDOS, ERRbadmem),
+ DOS_CODE(ERRDOS, ERRbadenv),
+ DOS_CODE(ERRDOS, ERRbadaccess),
+ DOS_CODE(ERRDOS, ERRbaddata),
+ DOS_CODE(ERRDOS, ERRres),
+ DOS_CODE(ERRDOS, ERRbaddrive),
+ DOS_CODE(ERRDOS, ERRremcd),
+ DOS_CODE(ERRDOS, ERRdiffdevice),
+ DOS_CODE(ERRDOS, ERRnofiles),
+ DOS_CODE(ERRDOS, ERRgeneral),
+ DOS_CODE(ERRDOS, ERRbadshare),
+ DOS_CODE(ERRDOS, ERRlock),
+ DOS_CODE(ERRDOS, ERRunsup),
+ DOS_CODE(ERRDOS, ERRnetnamedel),
+ DOS_CODE(ERRDOS, ERRnosuchshare),
+ DOS_CODE(ERRDOS, ERRfilexists),
+ DOS_CODE(ERRDOS, ERRinvalidparam),
+ DOS_CODE(ERRDOS, ERRcannotopen),
+ DOS_CODE(ERRDOS, ERRinsufficientbuffer),
+ DOS_CODE(ERRDOS, ERRinvalidname),
+ DOS_CODE(ERRDOS, ERRunknownlevel),
+ DOS_CODE(ERRDOS, ERRnotlocked),
+ DOS_CODE(ERRDOS, ERRinvalidpath),
+ DOS_CODE(ERRDOS, ERRcancelviolation),
+ DOS_CODE(ERRDOS, ERRnoatomiclocks),
+ DOS_CODE(ERRDOS, ERRrename),
+ DOS_CODE(ERRDOS, ERRbadpipe),
+ DOS_CODE(ERRDOS, ERRpipebusy),
+ DOS_CODE(ERRDOS, ERRpipeclosing),
+ DOS_CODE(ERRDOS, ERRnotconnected),
+ DOS_CODE(ERRDOS, ERRmoredata),
+ DOS_CODE(ERRDOS, ERRnomoreitems),
+ DOS_CODE(ERRDOS, ERRbaddirectory),
+ DOS_CODE(ERRDOS, ERReasnotsupported),
+ DOS_CODE(ERRDOS, ERRlogonfailure),
+ DOS_CODE(ERRDOS, ERRbuftoosmall),
+ DOS_CODE(ERRDOS, ERRunknownipc),
+ DOS_CODE(ERRDOS, ERRnosuchprintjob),
+ DOS_CODE(ERRDOS, ERRinvgroup),
+ DOS_CODE(ERRDOS, ERRnoipc),
+ DOS_CODE(ERRDOS, ERRdriveralreadyinstalled),
+ DOS_CODE(ERRDOS, ERRunknownprinterport),
+ DOS_CODE(ERRDOS, ERRunknownprinterdriver),
+ DOS_CODE(ERRDOS, ERRunknownprintprocessor),
+ DOS_CODE(ERRDOS, ERRinvalidseparatorfile),
+ DOS_CODE(ERRDOS, ERRinvalidjobpriority),
+ DOS_CODE(ERRDOS, ERRinvalidprintername),
+ DOS_CODE(ERRDOS, ERRprinteralreadyexists),
+ DOS_CODE(ERRDOS, ERRinvalidprintercommand),
+ DOS_CODE(ERRDOS, ERRinvaliddatatype),
+ DOS_CODE(ERRDOS, ERRinvalidenvironment),
+ DOS_CODE(ERRDOS, ERRunknownprintmonitor),
+ DOS_CODE(ERRDOS, ERRprinterdriverinuse),
+ DOS_CODE(ERRDOS, ERRspoolfilenotfound),
+ DOS_CODE(ERRDOS, ERRnostartdoc),
+ DOS_CODE(ERRDOS, ERRnoaddjob),
+ DOS_CODE(ERRDOS, ERRprintprocessoralreadyinstalled),
+ DOS_CODE(ERRDOS, ERRprintmonitoralreadyinstalled),
+ DOS_CODE(ERRDOS, ERRinvalidprintmonitor),
+ DOS_CODE(ERRDOS, ERRprintmonitorinuse),
+ DOS_CODE(ERRDOS, ERRprinterhasjobsqueued),
+ DOS_CODE(ERRDOS, ERReainconsistent),
+
+ DOS_CODE(ERRSRV, ERRerror),
+ DOS_CODE(ERRSRV, ERRbadpw),
+ DOS_CODE(ERRSRV, ERRbadtype),
+ DOS_CODE(ERRSRV, ERRaccess),
+ DOS_CODE(ERRSRV, ERRinvnid),
+ DOS_CODE(ERRSRV, ERRinvnetname),
+ DOS_CODE(ERRSRV, ERRinvdevice),
+ DOS_CODE(ERRSRV, ERRqfull),
+ DOS_CODE(ERRSRV, ERRqtoobig),
+ DOS_CODE(ERRSRV, ERRinvpfid),
+ DOS_CODE(ERRSRV, ERRsmbcmd),
+ DOS_CODE(ERRSRV, ERRsrverror),
+ DOS_CODE(ERRSRV, ERRfilespecs),
+ DOS_CODE(ERRSRV, ERRbadlink),
+ DOS_CODE(ERRSRV, ERRbadpermits),
+ DOS_CODE(ERRSRV, ERRbadpid),
+ DOS_CODE(ERRSRV, ERRsetattrmode),
+ DOS_CODE(ERRSRV, ERRpaused),
+ DOS_CODE(ERRSRV, ERRmsgoff),
+ DOS_CODE(ERRSRV, ERRnoroom),
+ DOS_CODE(ERRSRV, ERRrmuns),
+ DOS_CODE(ERRSRV, ERRtimeout),
+ DOS_CODE(ERRSRV, ERRnoresource),
+ DOS_CODE(ERRSRV, ERRtoomanyuids),
+ DOS_CODE(ERRSRV, ERRbaduid),
+ DOS_CODE(ERRSRV, ERRuseMPX),
+ DOS_CODE(ERRSRV, ERRuseSTD),
+ DOS_CODE(ERRSRV, ERRcontMPX),
+ DOS_CODE(ERRSRV, ERRnosupport),
+ DOS_CODE(ERRSRV, ERRunknownsmb),
+
+ DOS_CODE(ERRHRD, ERRnowrite),
+ DOS_CODE(ERRHRD, ERRbadunit),
+ DOS_CODE(ERRHRD, ERRnotready),
+ DOS_CODE(ERRHRD, ERRbadcmd),
+ DOS_CODE(ERRHRD, ERRdata),
+ DOS_CODE(ERRHRD, ERRbadreq),
+ DOS_CODE(ERRHRD, ERRseek),
+ DOS_CODE(ERRHRD, ERRbadmedia),
+ DOS_CODE(ERRHRD, ERRbadsector),
+ DOS_CODE(ERRHRD, ERRnopaper),
+ DOS_CODE(ERRHRD, ERRwrite),
+ DOS_CODE(ERRHRD, ERRread),
+ DOS_CODE(ERRHRD, ERRgeneral),
+ DOS_CODE(ERRHRD, ERRwrongdisk),
+ DOS_CODE(ERRHRD, ERRFCBunavail),
+ DOS_CODE(ERRHRD, ERRsharebufexc),
+ DOS_CODE(ERRHRD, ERRdiskfull),
+
+ LDAP_CODE(LDAP_SUCCESS),
+ LDAP_CODE(LDAP_OPERATIONS_ERROR),
+ LDAP_CODE(LDAP_PROTOCOL_ERROR),
+ LDAP_CODE(LDAP_TIME_LIMIT_EXCEEDED),
+ LDAP_CODE(LDAP_SIZE_LIMIT_EXCEEDED),
+ LDAP_CODE(LDAP_COMPARE_FALSE),
+ LDAP_CODE(LDAP_COMPARE_TRUE),
+ LDAP_CODE(LDAP_AUTH_METHOD_NOT_SUPPORTED),
+ LDAP_CODE(LDAP_STRONG_AUTH_REQUIRED),
+ LDAP_CODE(LDAP_REFERRAL),
+ LDAP_CODE(LDAP_ADMIN_LIMIT_EXCEEDED),
+ LDAP_CODE(LDAP_UNAVAILABLE_CRITICAL_EXTENSION),
+ LDAP_CODE(LDAP_CONFIDENTIALITY_REQUIRED),
+ LDAP_CODE(LDAP_SASL_BIND_IN_PROGRESS),
+ LDAP_CODE(LDAP_NO_SUCH_ATTRIBUTE),
+ LDAP_CODE(LDAP_UNDEFINED_ATTRIBUTE_TYPE),
+ LDAP_CODE(LDAP_INAPPROPRIATE_MATCHING),
+ LDAP_CODE(LDAP_CONSTRAINT_VIOLATION),
+ LDAP_CODE(LDAP_ATTRIBUTE_OR_VALUE_EXISTS),
+ LDAP_CODE(LDAP_INVALID_ATTRIBUTE_SYNTAX),
+ LDAP_CODE(LDAP_NO_SUCH_OBJECT),
+ LDAP_CODE(LDAP_ALIAS_PROBLEM),
+ LDAP_CODE(LDAP_INVALID_DN_SYNTAX),
+ LDAP_CODE(LDAP_ALIAS_DEREFERENCING_PROBLEM),
+ LDAP_CODE(LDAP_INAPPROPRIATE_AUTHENTICATION),
+ LDAP_CODE(LDAP_INVALID_CREDENTIALS),
+ LDAP_CODE(LDAP_INSUFFICIENT_ACCESS_RIGHTS),
+ LDAP_CODE(LDAP_BUSY),
+ LDAP_CODE(LDAP_UNAVAILABLE),
+ LDAP_CODE(LDAP_UNWILLING_TO_PERFORM),
+ LDAP_CODE(LDAP_LOOP_DETECT),
+ LDAP_CODE(LDAP_NAMING_VIOLATION),
+ LDAP_CODE(LDAP_OBJECT_CLASS_VIOLATION),
+ LDAP_CODE(LDAP_NOT_ALLOWED_ON_NON_LEAF),
+ LDAP_CODE(LDAP_NOT_ALLOWED_ON_RDN),
+ LDAP_CODE(LDAP_ENTRY_ALREADY_EXISTS),
+ LDAP_CODE(LDAP_OBJECT_CLASS_MODS_PROHIBITED),
+ LDAP_CODE(LDAP_AFFECTS_MULTIPLE_DSAS),
+ LDAP_CODE(LDAP_OTHER),
+
+ { NULL, NT_STATUS(0) }
+};
+
+/*****************************************************************************
+ Returns an NT_STATUS constant as a string for inclusion in autogen C code.
+ *****************************************************************************/
+
+const char *get_nt_error_c_code(TALLOC_CTX *mem_ctx, NTSTATUS nt_code)
+{
+ char *result;
+ int idx = 0;
+
+ while (special_errs[idx].nt_errstr != NULL) {
+ if (NT_STATUS_V(special_errs[idx].nt_errcode) ==
+ NT_STATUS_V(nt_code)) {
+ result = talloc_strdup(mem_ctx, special_errs[idx].nt_errstr);
+ return result;
+ }
+ idx++;
+ }
+
+ idx = 0;
+
+ while (nt_errs[idx].nt_errstr != NULL) {
+ if (NT_STATUS_V(nt_errs[idx].nt_errcode) ==
+ NT_STATUS_V(nt_code)) {
+ result = talloc_strdup(mem_ctx, nt_errs[idx].nt_errstr);
+ return result;
+ }
+ idx++;
+ }
+
+ result = talloc_asprintf(mem_ctx, "NT_STATUS(0x%08x)",
+ NT_STATUS_V(nt_code));
+ return result;
+}
+
+/*****************************************************************************
+ Returns the NT_STATUS constant matching the string supplied (as an NTSTATUS)
+ *****************************************************************************/
+
+NTSTATUS nt_status_string_to_code(const char *nt_status_str)
+{
+ int idx = 0;
+
+ while (special_errs[idx].nt_errstr != NULL) {
+ if (strcasecmp(special_errs[idx].nt_errstr, nt_status_str) == 0) {
+ return special_errs[idx].nt_errcode;
+ }
+ idx++;
+ }
+
+ idx = 0;
+
+ while (nt_errs[idx].nt_errstr != NULL) {
+ if (strcasecmp(nt_errs[idx].nt_errstr, nt_status_str) == 0) {
+ return nt_errs[idx].nt_errcode;
+ }
+ idx++;
+ }
+
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+/**
+ * Squash an NT_STATUS in line with security requirements.
+ * In an attempt to avoid giving the whole game away when users
+ * are authenticating, NT replaces both NT_STATUS_NO_SUCH_USER and
+ * NT_STATUS_WRONG_PASSWORD with NT_STATUS_LOGON_FAILURE in certain situations
+ * (session setups in particular).
+ *
+ * @param nt_status NTSTATUS input for squashing.
+ * @return the 'squashed' nt_status
+ **/
+
+NTSTATUS nt_status_squash(NTSTATUS nt_status)
+{
+ if NT_STATUS_IS_OK(nt_status) {
+ return nt_status;
+ } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) {
+ /* Match WinXP and don't give the game away */
+ return NT_STATUS_LOGON_FAILURE;
+
+ } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) {
+ /* Match WinXP and don't give the game away */
+ return NT_STATUS_LOGON_FAILURE;
+ } else {
+ return nt_status;
+ }
+}
+
+/*****************************************************************************
+ Returns an NT error message. not amazingly helpful, but better than a number.
+ *****************************************************************************/
+
+const char *nt_errstr(NTSTATUS nt_code)
+{
+ static char msg[20];
+ int idx = 0;
+
+ while (special_errs[idx].nt_errstr != NULL) {
+ if (NT_STATUS_V(special_errs[idx].nt_errcode) ==
+ NT_STATUS_V(nt_code)) {
+ return special_errs[idx].nt_errstr;
+ }
+ idx++;
+ }
+
+ idx = 0;
+
+ while (nt_errs[idx].nt_errstr != NULL) {
+ if (NT_STATUS_V(nt_errs[idx].nt_errcode) ==
+ NT_STATUS_V(nt_code)) {
+ return nt_errs[idx].nt_errstr;
+ }
+ idx++;
+ }
+
+ /*
+ * This should not really happen, we should have all error codes
+ * available. We have a problem that this might get wrongly
+ * overwritten by later calls in the same DEBUG statement.
+ */
+
+ snprintf(msg, sizeof(msg), "NT code 0x%08x", NT_STATUS_V(nt_code));
+ return msg;
+}
+
+/************************************************************************
+ Print friendlier version of NT error code
+ ***********************************************************************/
+
+const char *get_friendly_nt_error_msg(NTSTATUS nt_code)
+{
+ int idx = 0;
+
+ while (nt_err_desc[idx].nt_errstr != NULL) {
+ if (NT_STATUS_V(nt_err_desc[idx].nt_errcode) == NT_STATUS_V(nt_code)) {
+ return nt_err_desc[idx].nt_errstr;
+ }
+ idx++;
+ }
+
+ /* fall back to NT_STATUS_XXX string */
+
+ return nt_errstr(nt_code);
+}
diff --git a/libcli/util/ntstatus.h b/libcli/util/ntstatus.h
new file mode 100644
index 0000000..566d75f
--- /dev/null
+++ b/libcli/util/ntstatus.h
@@ -0,0 +1,199 @@
+/*
+ Unix SMB/CIFS implementation.
+ NT error code constants
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) John H Terpstra 1996-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Paul Ashton 1998-2000
+
+ 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/>.
+*/
+
+#ifndef _NTSTATUS_H
+#define _NTSTATUS_H
+
+#include <stdint.h>
+
+#include "libcli/util/ntstatus_gen.h"
+
+/* the following rather strange looking definitions of NTSTATUS
+ are there in order to catch common coding errors where different error types
+ are mixed up. This is especially important as we slowly convert Samba
+ from using bool for internal functions
+*/
+
+#if defined(HAVE_IMMEDIATE_STRUCTURES)
+typedef struct {uint32_t v;} NTSTATUS;
+#define NT_STATUS(x) ((NTSTATUS) { x })
+#define NT_STATUS_V(x) ((x).v)
+#else
+typedef uint32_t NTSTATUS;
+#define NT_STATUS(x) (x)
+#define NT_STATUS_V(x) (x)
+#endif
+
+/* Win32 status codes. */
+#define ERROR_INVALID_PARAMETER NT_STATUS(0x0057)
+#define ERROR_INSUFFICIENT_BUFFER NT_STATUS(0x007a)
+#define NT_STATUS_ERROR_DS_OBJ_STRING_NAME_EXISTS NT_STATUS(0x2071)
+#define NT_STATUS_ERROR_DS_INCOMPATIBLE_VERSION NT_STATUS(0x2177)
+#define NT_STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP NT_STATUS(0xC05D0000)
+
+/* Other error codes that aren't in the list we use */
+#define STATUS_MORE_ENTRIES NT_STATUS_MORE_ENTRIES
+#define STATUS_BUFFER_OVERFLOW NT_STATUS_BUFFER_OVERFLOW
+#define STATUS_NO_MORE_FILES NT_STATUS_NO_MORE_FILES
+#define STATUS_INVALID_EA_NAME NT_STATUS_INVALID_EA_NAME
+#define STATUS_SOME_UNMAPPED NT_STATUS_SOME_NOT_MAPPED
+
+#define NT_STATUS_ABIOS_NOT_PRESENT NT_STATUS(0xC0000000 | 0x010f)
+#define NT_STATUS_ABIOS_LID_NOT_EXIST NT_STATUS(0xC0000000 | 0x0110)
+#define NT_STATUS_ABIOS_LID_ALREADY_OWNED NT_STATUS(0xC0000000 | 0x0111)
+#define NT_STATUS_ABIOS_NOT_LID_OWNER NT_STATUS(0xC0000000 | 0x0112)
+#define NT_STATUS_ABIOS_INVALID_COMMAND NT_STATUS(0xC0000000 | 0x0113)
+#define NT_STATUS_ABIOS_INVALID_LID NT_STATUS(0xC0000000 | 0x0114)
+#define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE NT_STATUS(0xC0000000 | 0x0115)
+#define NT_STATUS_ABIOS_INVALID_SELECTOR NT_STATUS(0xC0000000 | 0x0116)
+
+#define NT_STATUS_HANDLE_NOT_WAITABLE NT_STATUS(0xC0000000 | 0x0036)
+#define NT_STATUS_DEVICE_POWER_FAILURE NT_STATUS(0xC0000000 | 0x009e)
+#define NT_STATUS_VHD_SHARED NT_STATUS(0xC05CFF0A)
+#define NT_STATUS_SMB_BAD_CLUSTER_DIALECT NT_STATUS(0xC05D0001)
+#define NT_STATUS_NO_SUCH_JOB NT_STATUS(0xC0000000 | 0xEDE)
+
+/*
+ --------------
+ / \
+ / REST \
+ / IN \
+ / PEACE \
+ / \
+ | NT_STATUS_NOPROBLEMO |
+ | |
+ | |
+ | 4 September |
+ | |
+ | 2001 |
+ *| * * * | *
+ _________)/\\_//(\/(/\)/\//\/\///|_)_______
+*/
+
+/* I use NT_STATUS_FOOBAR when I have no idea what error code to use -
+ * this means we need a torture test */
+#define NT_STATUS_FOOBAR NT_STATUS_UNSUCCESSFUL
+
+/*****************************************************************************
+ returns an NT error message. not amazingly helpful, but better than a number.
+ *****************************************************************************/
+const char *nt_errstr(NTSTATUS nt_code);
+
+/************************************************************************
+ Print friendlier version of NT error code
+ ***********************************************************************/
+const char *get_friendly_nt_error_msg(NTSTATUS nt_code);
+
+/*****************************************************************************
+ returns an NT_STATUS constant as a string for inclusion in autogen C code
+ *****************************************************************************/
+const char *get_nt_error_c_code(void *mem_ctx, NTSTATUS nt_code);
+
+/*****************************************************************************
+ returns the NT_STATUS constant matching the string supplied (as an NTSTATUS)
+ *****************************************************************************/
+NTSTATUS nt_status_string_to_code(const char *nt_status_str);
+
+/* we need these here for openchange */
+#ifndef likely
+#define likely(x) (x)
+#endif
+#ifndef unlikely
+#define unlikely(x) (x)
+#endif
+
+#define NT_STATUS_IS_OK(x) (likely(NT_STATUS_V(x) == 0))
+#define NT_STATUS_IS_ERR(x) (unlikely((NT_STATUS_V(x) & 0xc0000000) == 0xc0000000))
+#define NT_STATUS_EQUAL(x,y) (NT_STATUS_V(x) == NT_STATUS_V(y))
+
+/*
+ * These macros (with the embedded return) are considered poor coding
+ * style per README.Coding
+ *
+ * Please do not use them in new code, and do not rely on them in
+ * projects external to Samba as they will go away at some point.
+ */
+
+#define NT_STATUS_HAVE_NO_MEMORY(x) do { \
+ if (unlikely(!(x))) { \
+ return NT_STATUS_NO_MEMORY;\
+ }\
+} while (0)
+
+/* This variant is for when you want to free a local
+ temporary memory context in the error path */
+#define NT_STATUS_HAVE_NO_MEMORY_AND_FREE(x, ctx) do { \
+ if (!(x)) {\
+ talloc_free(ctx); \
+ return NT_STATUS_NO_MEMORY;\
+ }\
+} while (0)
+
+#define NT_STATUS_IS_OK_RETURN(x) do { \
+ if (NT_STATUS_IS_OK(x)) {\
+ return x;\
+ }\
+} while (0)
+
+#define NT_STATUS_NOT_OK_RETURN(x) do { \
+ if (!NT_STATUS_IS_OK(x)) {\
+ return x;\
+ }\
+} while (0)
+
+#define NT_STATUS_NOT_OK_RETURN_AND_FREE(x, ctx) do { \
+ if (!NT_STATUS_IS_OK(x)) {\
+ talloc_free(ctx); \
+ return x;\
+ }\
+} while (0)
+
+#define NT_STATUS_IS_ERR_RETURN(x) do { \
+ if (NT_STATUS_IS_ERR(x)) {\
+ return x;\
+ }\
+} while (0)
+
+#define NT_STATUS_NOT_ERR_RETURN(x) do { \
+ if (!NT_STATUS_IS_ERR(x)) {\
+ return x;\
+ }\
+} while (0)
+
+/* this defines special NTSTATUS codes to represent DOS errors. I
+ have chosen this macro to produce status codes in the invalid
+ NTSTATUS range */
+#define NT_STATUS_DOS(class, code) NT_STATUS(0xF1000000 | ((class)<<16) | code)
+#define NT_STATUS_IS_DOS(status) ((NT_STATUS_V(status) & 0xFF000000) == 0xF1000000)
+#define NT_STATUS_DOS_CLASS(status) ((NT_STATUS_V(status) >> 16) & 0xFF)
+#define NT_STATUS_DOS_CODE(status) (NT_STATUS_V(status) & 0xFFFF)
+
+/* define ldap error codes as NTSTATUS codes */
+#define NT_STATUS_LDAP(code) NT_STATUS(0xF2000000 | code)
+#define NT_STATUS_IS_LDAP(status) ((NT_STATUS_V(status) & 0xFF000000) == 0xF2000000)
+#define NT_STATUS_LDAP_CODE(status) (NT_STATUS_V(status) & ~0xFF000000)
+
+#define NT_STATUS_IS_RPC(status) \
+ (((NT_STATUS_V(status) & 0xFFFF) == 0xC0020000) || \
+ ((NT_STATUS_V(status) & 0xFFFF) == 0xC0030000))
+
+#endif /* _NTSTATUS_H */
diff --git a/libcli/util/ntstatus_err_table.txt b/libcli/util/ntstatus_err_table.txt
new file mode 100644
index 0000000..195e5ae
--- /dev/null
+++ b/libcli/util/ntstatus_err_table.txt
@@ -0,0 +1,12629 @@
+Errors retrieved from https://msdn.microsoft.com/en-us/library/cc704588.aspx.
+License retrieved from https://msdn.microsoft.com/en-us/library/cc231196.aspx:
+
+Intellectual Property Rights Notice for Open Specifications Documentation
+
+ - Technical Documentation. Microsoft publishes Open Specifications documentation (“this documentation”) for protocols, file formats, data portability, computer languages, and standards support. Additionally, overview documents cover inter-protocol relationships and interactions.
+
+ - Copyrights. This documentation is covered by Microsoft copyrights. Regardless of any other terms that are contained in the terms of use for the Microsoft website that hosts this documentation, you can make copies of it in order to develop implementations of the technologies that are described in this documentation and can distribute portions of it in your implementations that use these technologies or in your documentation as necessary to properly document the implementation. You can also distribute in your implementation, with or without modification, any schemas, IDLs, or code samples that are included in the documentation. This permission also applies to any documents that are referenced in the Open Specifications documentation.
+
+ - No Trade Secrets. Microsoft does not claim any trade secret rights in this documentation.
+
+ - Patents. Microsoft has patents that might cover your implementations of the technologies described in the Open Specifications documentation. Neither this notice nor Microsoft's delivery of this documentation grants any licenses under those patents or any other Microsoft patents. However, a given Open Specifications document might be covered by the Microsoft Open Specifications Promise or the Microsoft Community Promise. If you would prefer a written license, or if the technologies described in this documentation are not covered by the Open Specifications Promise or Community Promise, as applicable, patent licenses are available by contacting iplg@microsoft.com.
+
+ - Trademarks. The names of companies and products contained in this documentation might be covered by trademarks or similar intellectual property rights. This notice does not grant any licenses under those rights. For a list of Microsoft trademarks, visit www.microsoft.com/trademarks.
+
+ - Fictitious Names. The example companies, organizations, products, domain names, email addresses, logos, people, places, and events that are depicted in this documentation are fictitious. No association with any real company, organization, product, domain name, email address, logo, person, place, or event is intended or should be inferred.
+
+Reservation of Rights. All other rights are reserved, and this notice does not grant any rights other than as specifically described above, whether by implication, estoppel, or otherwise.
+
+Tools. The Open Specifications documentation does not require the use of Microsoft programming tools or programming environments in order for you to develop an implementation. If you have access to Microsoft programming tools and environments, you are free to take advantage of them. Certain Open Specifications documents are intended for use in conjunction with publicly available standards specifications and network programming art and, as such, assume that the reader either is familiar with the aforementioned material or has immediate access to it.
+
+===========
+
+0x00000000
+
+STATUS_SUCCESS
+
+
+The operation completed successfully.
+
+0x00000000
+
+STATUS_WAIT_0
+
+
+The caller specified WaitAny for WaitType and one of the dispatcher objects in the Object array has been set to the signaled state.
+
+0x00000001
+
+STATUS_WAIT_1
+
+
+The caller specified WaitAny for WaitType and one of the dispatcher objects in the Object array has been set to the signaled state.
+
+0x00000002
+
+STATUS_WAIT_2
+
+
+The caller specified WaitAny for WaitType and one of the dispatcher objects in the Object array has been set to the signaled state.
+
+0x00000003
+
+STATUS_WAIT_3
+
+
+The caller specified WaitAny for WaitType and one of the dispatcher objects in the Object array has been set to the signaled state.
+
+0x0000003F
+
+STATUS_WAIT_63
+
+
+The caller specified WaitAny for WaitType and one of the dispatcher objects in the Object array has been set to the signaled state.
+
+0x00000080
+
+STATUS_ABANDONED
+
+
+The caller attempted to wait for a mutex that has been abandoned.
+
+0x00000080
+
+STATUS_ABANDONED_WAIT_0
+
+
+The caller attempted to wait for a mutex that has been abandoned.
+
+0x000000BF
+
+STATUS_ABANDONED_WAIT_63
+
+
+The caller attempted to wait for a mutex that has been abandoned.
+
+0x000000C0
+
+STATUS_USER_APC
+
+
+A user-mode APC was delivered before the given Interval expired.
+
+0x00000101
+
+STATUS_ALERTED
+
+
+The delay completed because the thread was alerted.
+
+0x00000102
+
+STATUS_TIMEOUT
+
+
+The given Timeout interval expired.
+
+0x00000103
+
+STATUS_PENDING
+
+
+The operation that was requested is pending completion.
+
+0x00000104
+
+STATUS_REPARSE
+
+
+A reparse should be performed by the Object Manager because the name of the file resulted in a symbolic link.
+
+0x00000105
+
+STATUS_MORE_ENTRIES
+
+
+Returned by enumeration APIs to indicate more information is available to successive calls.
+
+0x00000106
+
+STATUS_NOT_ALL_ASSIGNED
+
+
+Indicates not all privileges or groups that are referenced are assigned to the caller. This allows, for example, all privileges to be disabled without having to know exactly which privileges are assigned.
+
+0x00000107
+
+STATUS_SOME_NOT_MAPPED
+
+
+Some of the information to be translated has not been translated.
+
+0x00000108
+
+STATUS_OPLOCK_BREAK_IN_PROGRESS
+
+
+An open/create operation completed while an opportunistic lock (oplock) break is underway.
+
+0x00000109
+
+STATUS_VOLUME_MOUNTED
+
+
+A new volume has been mounted by a file system.
+
+0x0000010A
+
+STATUS_RXACT_COMMITTED
+
+
+This success level status indicates that the transaction state already exists for the registry subtree but that a transaction commit was previously aborted. The commit has now been completed.
+
+0x0000010B
+
+STATUS_NOTIFY_CLEANUP
+
+
+Indicates that a notify change request has been completed due to closing the handle that made the notify change request.
+
+0x0000010C
+
+STATUS_NOTIFY_ENUM_DIR
+
+
+Indicates that a notify change request is being completed and that the information is not being returned in the caller's buffer. The caller now needs to enumerate the files to find the changes.
+
+0x0000010D
+
+STATUS_NO_QUOTAS_FOR_ACCOUNT
+
+
+{No Quotas} No system quota limits are specifically set for this account.
+
+0x0000010E
+
+STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED
+
+
+{Connect Failure on Primary Transport} An attempt was made to connect to the remote server %hs on the primary transport, but the connection failed. The computer WAS able to connect on a secondary transport.
+
+0x00000110
+
+STATUS_PAGE_FAULT_TRANSITION
+
+
+The page fault was a transition fault.
+
+0x00000111
+
+STATUS_PAGE_FAULT_DEMAND_ZERO
+
+
+The page fault was a demand zero fault.
+
+0x00000112
+
+STATUS_PAGE_FAULT_COPY_ON_WRITE
+
+
+The page fault was a demand zero fault.
+
+0x00000113
+
+STATUS_PAGE_FAULT_GUARD_PAGE
+
+
+The page fault was a demand zero fault.
+
+0x00000114
+
+STATUS_PAGE_FAULT_PAGING_FILE
+
+
+The page fault was satisfied by reading from a secondary storage device.
+
+0x00000115
+
+STATUS_CACHE_PAGE_LOCKED
+
+
+The cached page was locked during operation.
+
+0x00000116
+
+STATUS_CRASH_DUMP
+
+
+The crash dump exists in a paging file.
+
+0x00000117
+
+STATUS_BUFFER_ALL_ZEROS
+
+
+The specified buffer contains all zeros.
+
+0x00000118
+
+STATUS_REPARSE_OBJECT
+
+
+A reparse should be performed by the Object Manager because the name of the file resulted in a symbolic link.
+
+0x00000119
+
+STATUS_RESOURCE_REQUIREMENTS_CHANGED
+
+
+The device has succeeded a query-stop and its resource requirements have changed.
+
+0x00000120
+
+STATUS_TRANSLATION_COMPLETE
+
+
+The translator has translated these resources into the global space and no additional translations should be performed.
+
+0x00000121
+
+STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY
+
+
+The directory service evaluated group memberships locally, because it was unable to contact a global catalog server.
+
+0x00000122
+
+STATUS_NOTHING_TO_TERMINATE
+
+
+A process being terminated has no threads to terminate.
+
+0x00000123
+
+STATUS_PROCESS_NOT_IN_JOB
+
+
+The specified process is not part of a job.
+
+0x00000124
+
+STATUS_PROCESS_IN_JOB
+
+
+The specified process is part of a job.
+
+0x00000125
+
+STATUS_VOLSNAP_HIBERNATE_READY
+
+
+{Volume Shadow Copy Service} The system is now ready for hibernation.
+
+0x00000126
+
+STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY
+
+
+A file system or file system filter driver has successfully completed an FsFilter operation.
+
+0x00000127
+
+STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED
+
+
+The specified interrupt vector was already connected.
+
+0x00000128
+
+STATUS_INTERRUPT_STILL_CONNECTED
+
+
+The specified interrupt vector is still connected.
+
+0x00000129
+
+STATUS_PROCESS_CLONED
+
+
+The current process is a cloned process.
+
+0x0000012A
+
+STATUS_FILE_LOCKED_WITH_ONLY_READERS
+
+
+The file was locked and all users of the file can only read.
+
+0x0000012B
+
+STATUS_FILE_LOCKED_WITH_WRITERS
+
+
+The file was locked and at least one user of the file can write.
+
+0x00000202
+
+STATUS_RESOURCEMANAGER_READ_ONLY
+
+
+The specified ResourceManager made no changes or updates to the resource under this transaction.
+
+0x00000367
+
+STATUS_WAIT_FOR_OPLOCK
+
+
+An operation is blocked and waiting for an oplock.
+
+0x00010001
+
+DBG_EXCEPTION_HANDLED
+
+
+Debugger handled the exception.
+
+0x00010002
+
+DBG_CONTINUE
+
+
+The debugger continued.
+
+0x001C0001
+
+STATUS_FLT_IO_COMPLETE
+
+
+The IO was completed by a filter.
+
+0xC0000467
+
+STATUS_FILE_NOT_AVAILABLE
+
+
+The file is temporarily unavailable.
+
+0xC0000480
+
+STATUS_SHARE_UNAVAILABLE
+
+
+The share is temporarily unavailable.
+
+0xC0000721
+
+STATUS_CALLBACK_RETURNED_THREAD_AFFINITY
+
+
+A threadpool worker thread entered a callback at thread affinity %p and exited at affinity %p.
+
+This is unexpected, indicating that the callback missed restoring the priority.
+
+0x40000000
+
+STATUS_OBJECT_NAME_EXISTS
+
+
+{Object Exists} An attempt was made to create an object but the object name already exists.
+
+0x40000001
+
+STATUS_THREAD_WAS_SUSPENDED
+
+
+{Thread Suspended} A thread termination occurred while the thread was suspended. The thread resumed, and termination proceeded.
+
+0x40000002
+
+STATUS_WORKING_SET_LIMIT_RANGE
+
+
+{Working Set Range Error} An attempt was made to set the working set minimum or maximum to values that are outside the allowable range.
+
+0x40000003
+
+STATUS_IMAGE_NOT_AT_BASE
+
+
+{Image Relocated} An image file could not be mapped at the address that is specified in the image file. Local fixes must be performed on this image.
+
+0x40000004
+
+STATUS_RXACT_STATE_CREATED
+
+
+This informational level status indicates that a specified registry subtree transaction state did not yet exist and had to be created.
+
+0x40000005
+
+STATUS_SEGMENT_NOTIFICATION
+
+
+{Segment Load} A virtual DOS machine (VDM) is loading, unloading, or moving an MS-DOS or Win16 program segment image. An exception is raised so that a debugger can load, unload, or track symbols and breakpoints within these 16-bit segments.
+
+0x40000006
+
+STATUS_LOCAL_USER_SESSION_KEY
+
+
+{Local Session Key} A user session key was requested for a local remote procedure call (RPC) connection. The session key that is returned is a constant value and not unique to this connection.
+
+0x40000007
+
+STATUS_BAD_CURRENT_DIRECTORY
+
+
+{Invalid Current Directory} The process cannot switch to the startup current directory %hs. Select OK to set the current directory to %hs, or select CANCEL to exit.
+
+0x40000008
+
+STATUS_SERIAL_MORE_WRITES
+
+
+{Serial IOCTL Complete} A serial I/O operation was completed by another write to a serial port. (The IOCTL_SERIAL_XOFF_COUNTER reached zero.)
+
+0x40000009
+
+STATUS_REGISTRY_RECOVERED
+
+
+{Registry Recovery} One of the files that contains the system registry data had to be recovered by using a log or alternate copy. The recovery was successful.
+
+0x4000000A
+
+STATUS_FT_READ_RECOVERY_FROM_BACKUP
+
+
+{Redundant Read} To satisfy a read request, the Windows NT operating system fault-tolerant file system successfully read the requested data from a redundant copy. This was done because the file system encountered a failure on a member of the fault-tolerant volume but was unable to reassign the failing area of the device.
+
+0x4000000B
+
+STATUS_FT_WRITE_RECOVERY
+
+
+{Redundant Write} To satisfy a write request, the Windows NT fault-tolerant file system successfully wrote a redundant copy of the information. This was done because the file system encountered a failure on a member of the fault-tolerant volume but was unable to reassign the failing area of the device.
+
+0x4000000C
+
+STATUS_SERIAL_COUNTER_TIMEOUT
+
+
+{Serial IOCTL Timeout} A serial I/O operation completed because the time-out period expired. (The IOCTL_SERIAL_XOFF_COUNTER had not reached zero.)
+
+0x4000000D
+
+STATUS_NULL_LM_PASSWORD
+
+
+{Password Too Complex} The Windows password is too complex to be converted to a LAN Manager password. The LAN Manager password that returned is a NULL string.
+
+0x4000000E
+
+STATUS_IMAGE_MACHINE_TYPE_MISMATCH
+
+
+{Machine Type Mismatch} The image file %hs is valid but is for a machine type other than the current machine. Select OK to continue, or CANCEL to fail the DLL load.
+
+0x4000000F
+
+STATUS_RECEIVE_PARTIAL
+
+
+{Partial Data Received} The network transport returned partial data to its client. The remaining data will be sent later.
+
+0x40000010
+
+STATUS_RECEIVE_EXPEDITED
+
+
+{Expedited Data Received} The network transport returned data to its client that was marked as expedited by the remote system.
+
+0x40000011
+
+STATUS_RECEIVE_PARTIAL_EXPEDITED
+
+
+{Partial Expedited Data Received} The network transport returned partial data to its client and this data was marked as expedited by the remote system. The remaining data will be sent later.
+
+0x40000012
+
+STATUS_EVENT_DONE
+
+
+{TDI Event Done} The TDI indication has completed successfully.
+
+0x40000013
+
+STATUS_EVENT_PENDING
+
+
+{TDI Event Pending} The TDI indication has entered the pending state.
+
+0x40000014
+
+STATUS_CHECKING_FILE_SYSTEM
+
+
+Checking file system on %wZ.
+
+0x40000015
+
+STATUS_FATAL_APP_EXIT
+
+
+{Fatal Application Exit} %hs
+
+0x40000016
+
+STATUS_PREDEFINED_HANDLE
+
+
+The specified registry key is referenced by a predefined handle.
+
+0x40000017
+
+STATUS_WAS_UNLOCKED
+
+
+{Page Unlocked} The page protection of a locked page was changed to 'No Access' and the page was unlocked from memory and from the process.
+
+0x40000018
+
+STATUS_SERVICE_NOTIFICATION
+
+
+%hs
+
+0x40000019
+
+STATUS_WAS_LOCKED
+
+
+{Page Locked} One of the pages to lock was already locked.
+
+0x4000001A
+
+STATUS_LOG_HARD_ERROR
+
+
+Application popup: %1 : %2
+
+0x4000001B
+
+STATUS_ALREADY_WIN32
+
+
+A Win32 process already exists.
+
+0x4000001C
+
+STATUS_WX86_UNSIMULATE
+
+
+An exception status code that is used by the Win32 x86 emulation subsystem.
+
+0x4000001D
+
+STATUS_WX86_CONTINUE
+
+
+An exception status code that is used by the Win32 x86 emulation subsystem.
+
+0x4000001E
+
+STATUS_WX86_SINGLE_STEP
+
+
+An exception status code that is used by the Win32 x86 emulation subsystem.
+
+0x4000001F
+
+STATUS_WX86_BREAKPOINT
+
+
+An exception status code that is used by the Win32 x86 emulation subsystem.
+
+0x40000020
+
+STATUS_WX86_EXCEPTION_CONTINUE
+
+
+An exception status code that is used by the Win32 x86 emulation subsystem.
+
+0x40000021
+
+STATUS_WX86_EXCEPTION_LASTCHANCE
+
+
+An exception status code that is used by the Win32 x86 emulation subsystem.
+
+0x40000022
+
+STATUS_WX86_EXCEPTION_CHAIN
+
+
+An exception status code that is used by the Win32 x86 emulation subsystem.
+
+0x40000023
+
+STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE
+
+
+{Machine Type Mismatch} The image file %hs is valid but is for a machine type other than the current machine.
+
+0x40000024
+
+STATUS_NO_YIELD_PERFORMED
+
+
+A yield execution was performed and no thread was available to run.
+
+0x40000025
+
+STATUS_TIMER_RESUME_IGNORED
+
+
+The resume flag to a timer API was ignored.
+
+0x40000026
+
+STATUS_ARBITRATION_UNHANDLED
+
+
+The arbiter has deferred arbitration of these resources to its parent.
+
+0x40000027
+
+STATUS_CARDBUS_NOT_SUPPORTED
+
+
+The device has detected a CardBus card in its slot.
+
+0x40000028
+
+STATUS_WX86_CREATEWX86TIB
+
+
+An exception status code that is used by the Win32 x86 emulation subsystem.
+
+0x40000029
+
+STATUS_MP_PROCESSOR_MISMATCH
+
+
+The CPUs in this multiprocessor system are not all the same revision level. To use all processors, the operating system restricts itself to the features of the least capable processor in the system. If problems occur with this system, contact the CPU manufacturer to see if this mix of processors is supported.
+
+0x4000002A
+
+STATUS_HIBERNATED
+
+
+The system was put into hibernation.
+
+0x4000002B
+
+STATUS_RESUME_HIBERNATION
+
+
+The system was resumed from hibernation.
+
+0x4000002C
+
+STATUS_FIRMWARE_UPDATED
+
+
+Windows has detected that the system firmware (BIOS) was updated [previous firmware date = %2, current firmware date %3].
+
+0x4000002D
+
+STATUS_DRIVERS_LEAKING_LOCKED_PAGES
+
+
+A device driver is leaking locked I/O pages and is causing system degradation. The system has automatically enabled the tracking code to try and catch the culprit.
+
+0x4000002E
+
+STATUS_MESSAGE_RETRIEVED
+
+
+The ALPC message being canceled has already been retrieved from the queue on the other side.
+
+0x4000002F
+
+STATUS_SYSTEM_POWERSTATE_TRANSITION
+
+
+The system power state is transitioning from %2 to %3.
+
+0x40000030
+
+STATUS_ALPC_CHECK_COMPLETION_LIST
+
+
+The receive operation was successful. Check the ALPC completion list for the received message.
+
+0x40000031
+
+STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION
+
+
+The system power state is transitioning from %2 to %3 but could enter %4.
+
+0x40000032
+
+STATUS_ACCESS_AUDIT_BY_POLICY
+
+
+Access to %1 is monitored by policy rule %2.
+
+0x40000033
+
+STATUS_ABANDON_HIBERFILE
+
+
+A valid hibernation file has been invalidated and should be abandoned.
+
+0x40000034
+
+STATUS_BIZRULES_NOT_ENABLED
+
+
+Business rule scripts are disabled for the calling application.
+
+0x40000294
+
+STATUS_WAKE_SYSTEM
+
+
+The system has awoken.
+
+0x40000370
+
+STATUS_DS_SHUTTING_DOWN
+
+
+The directory service is shutting down.
+
+0x40010001
+
+DBG_REPLY_LATER
+
+
+Debugger will reply later.
+
+0x40010002
+
+DBG_UNABLE_TO_PROVIDE_HANDLE
+
+
+Debugger cannot provide a handle.
+
+0x40010003
+
+DBG_TERMINATE_THREAD
+
+
+Debugger terminated the thread.
+
+0x40010004
+
+DBG_TERMINATE_PROCESS
+
+
+Debugger terminated the process.
+
+0x40010005
+
+DBG_CONTROL_C
+
+
+Debugger obtained control of C.
+
+0x40010006
+
+DBG_PRINTEXCEPTION_C
+
+
+Debugger printed an exception on control C.
+
+0x40010007
+
+DBG_RIPEXCEPTION
+
+
+Debugger received a RIP exception.
+
+0x40010008
+
+DBG_CONTROL_BREAK
+
+
+Debugger received a control break.
+
+0x40010009
+
+DBG_COMMAND_EXCEPTION
+
+
+Debugger command communication exception.
+
+0x40020056
+
+RPC_NT_UUID_LOCAL_ONLY
+
+
+A UUID that is valid only on this computer has been allocated.
+
+0x400200AF
+
+RPC_NT_SEND_INCOMPLETE
+
+
+Some data remains to be sent in the request buffer.
+
+0x400A0004
+
+STATUS_CTX_CDM_CONNECT
+
+
+The Client Drive Mapping Service has connected on Terminal Connection.
+
+0x400A0005
+
+STATUS_CTX_CDM_DISCONNECT
+
+
+The Client Drive Mapping Service has disconnected on Terminal Connection.
+
+0x4015000D
+
+STATUS_SXS_RELEASE_ACTIVATION_CONTEXT
+
+
+A kernel mode component is releasing a reference on an activation context.
+
+0x40190034
+
+STATUS_RECOVERY_NOT_NEEDED
+
+
+The transactional resource manager is already consistent. Recovery is not needed.
+
+0x40190035
+
+STATUS_RM_ALREADY_STARTED
+
+
+The transactional resource manager has already been started.
+
+0x401A000C
+
+STATUS_LOG_NO_RESTART
+
+
+The log service encountered a log stream with no restart area.
+
+0x401B00EC
+
+STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST
+
+
+{Display Driver Recovered From Failure} The %hs display driver has detected a failure and recovered from it. Some graphical operations might have failed. The next time you restart the machine, a dialog box appears, giving you an opportunity to upload data about this failure to Microsoft.
+
+0x401E000A
+
+STATUS_GRAPHICS_PARTIAL_DATA_POPULATED
+
+
+The specified buffer is not big enough to contain the entire requested dataset. Partial data is populated up to the size of the buffer.
+
+The caller needs to provide a buffer of the size as specified in the partially populated buffer's content (interface specific).
+
+0x401E0117
+
+STATUS_GRAPHICS_DRIVER_MISMATCH
+
+
+The kernel driver detected a version mismatch between it and the user mode driver.
+
+0x401E0307
+
+STATUS_GRAPHICS_MODE_NOT_PINNED
+
+
+No mode is pinned on the specified VidPN source/target.
+
+0x401E031E
+
+STATUS_GRAPHICS_NO_PREFERRED_MODE
+
+
+The specified mode set does not specify a preference for one of its modes.
+
+0x401E034B
+
+STATUS_GRAPHICS_DATASET_IS_EMPTY
+
+
+The specified dataset (for example, mode set, frequency range set, descriptor set, or topology) is empty.
+
+0x401E034C
+
+STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET
+
+
+The specified dataset (for example, mode set, frequency range set, descriptor set, or topology) does not contain any more elements.
+
+0x401E0351
+
+STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED
+
+
+The specified content transformation is not pinned on the specified VidPN present path.
+
+0x401E042F
+
+STATUS_GRAPHICS_UNKNOWN_CHILD_STATUS
+
+
+The child device presence was not reliably detected.
+
+0x401E0437
+
+STATUS_GRAPHICS_LEADLINK_START_DEFERRED
+
+
+Starting the lead adapter in a linked configuration has been temporarily deferred.
+
+0x401E0439
+
+STATUS_GRAPHICS_POLLING_TOO_FREQUENTLY
+
+
+The display adapter is being polled for children too frequently at the same polling level.
+
+0x401E043A
+
+STATUS_GRAPHICS_START_DEFERRED
+
+
+Starting the adapter has been temporarily deferred.
+
+0x40230001
+
+STATUS_NDIS_INDICATION_REQUIRED
+
+
+The request will be completed later by an NDIS status indication.
+
+0x80000001
+
+STATUS_GUARD_PAGE_VIOLATION
+
+
+{EXCEPTION} Guard Page Exception A page of memory that marks the end of a data structure, such as a stack or an array, has been accessed.
+
+0x80000002
+
+STATUS_DATATYPE_MISALIGNMENT
+
+
+{EXCEPTION} Alignment Fault A data type misalignment was detected in a load or store instruction.
+
+0x80000003
+
+STATUS_BREAKPOINT
+
+
+{EXCEPTION} Breakpoint A breakpoint has been reached.
+
+0x80000004
+
+STATUS_SINGLE_STEP
+
+
+{EXCEPTION} Single Step A single step or trace operation has just been completed.
+
+0x80000005
+
+STATUS_BUFFER_OVERFLOW
+
+
+{Buffer Overflow} The data was too large to fit into the specified buffer.
+
+0x80000006
+
+STATUS_NO_MORE_FILES
+
+
+{No More Files} No more files were found which match the file specification.
+
+0x80000007
+
+STATUS_WAKE_SYSTEM_DEBUGGER
+
+
+{Kernel Debugger Awakened} The system debugger was awakened by an interrupt.
+
+0x8000000A
+
+STATUS_HANDLES_CLOSED
+
+
+{Handles Closed} Handles to objects have been automatically closed because of the requested operation.
+
+0x8000000B
+
+STATUS_NO_INHERITANCE
+
+
+{Non-Inheritable ACL} An access control list (ACL) contains no components that can be inherited.
+
+0x8000000C
+
+STATUS_GUID_SUBSTITUTION_MADE
+
+
+{GUID Substitution} During the translation of a globally unique identifier (GUID) to a Windows security ID (SID), no administratively defined GUID prefix was found. A substitute prefix was used, which will not compromise system security. However, this might provide a more restrictive access than intended.
+
+0x8000000D
+
+STATUS_PARTIAL_COPY
+
+
+Because of protection conflicts, not all the requested bytes could be copied.
+
+0x8000000E
+
+STATUS_DEVICE_PAPER_EMPTY
+
+
+{Out of Paper} The printer is out of paper.
+
+0x8000000F
+
+STATUS_DEVICE_POWERED_OFF
+
+
+{Device Power Is Off} The printer power has been turned off.
+
+0x80000010
+
+STATUS_DEVICE_OFF_LINE
+
+
+{Device Offline} The printer has been taken offline.
+
+0x80000011
+
+STATUS_DEVICE_BUSY
+
+
+{Device Busy} The device is currently busy.
+
+0x80000012
+
+STATUS_NO_MORE_EAS
+
+
+{No More EAs} No more extended attributes (EAs) were found for the file.
+
+0x80000013
+
+STATUS_INVALID_EA_NAME
+
+
+{Illegal EA} The specified extended attribute (EA) name contains at least one illegal character.
+
+0x80000014
+
+STATUS_EA_LIST_INCONSISTENT
+
+
+{Inconsistent EA List} The extended attribute (EA) list is inconsistent.
+
+0x80000015
+
+STATUS_INVALID_EA_FLAG
+
+
+{Invalid EA Flag} An invalid extended attribute (EA) flag was set.
+
+0x80000016
+
+STATUS_VERIFY_REQUIRED
+
+
+{Verifying Disk} The media has changed and a verify operation is in progress; therefore, no reads or writes can be performed to the device, except those that are used in the verify operation.
+
+0x80000017
+
+STATUS_EXTRANEOUS_INFORMATION
+
+
+{Too Much Information} The specified access control list (ACL) contained more information than was expected.
+
+0x80000018
+
+STATUS_RXACT_COMMIT_NECESSARY
+
+
+This warning level status indicates that the transaction state already exists for the registry subtree, but that a transaction commit was previously aborted. The commit has NOT been completed but has not been rolled back either; therefore, it can still be committed, if needed.
+
+0x8000001A
+
+STATUS_NO_MORE_ENTRIES
+
+
+{No More Entries} No more entries are available from an enumeration operation.
+
+0x8000001B
+
+STATUS_FILEMARK_DETECTED
+
+
+{Filemark Found} A filemark was detected.
+
+0x8000001C
+
+STATUS_MEDIA_CHANGED
+
+
+{Media Changed} The media has changed.
+
+0x8000001D
+
+STATUS_BUS_RESET
+
+
+{I/O Bus Reset} An I/O bus reset was detected.
+
+0x8000001E
+
+STATUS_END_OF_MEDIA
+
+
+{End of Media} The end of the media was encountered.
+
+0x8000001F
+
+STATUS_BEGINNING_OF_MEDIA
+
+
+The beginning of a tape or partition has been detected.
+
+0x80000020
+
+STATUS_MEDIA_CHECK
+
+
+{Media Changed} The media might have changed.
+
+0x80000021
+
+STATUS_SETMARK_DETECTED
+
+
+A tape access reached a set mark.
+
+0x80000022
+
+STATUS_NO_DATA_DETECTED
+
+
+During a tape access, the end of the data written is reached.
+
+0x80000023
+
+STATUS_REDIRECTOR_HAS_OPEN_HANDLES
+
+
+The redirector is in use and cannot be unloaded.
+
+0x80000024
+
+STATUS_SERVER_HAS_OPEN_HANDLES
+
+
+The server is in use and cannot be unloaded.
+
+0x80000025
+
+STATUS_ALREADY_DISCONNECTED
+
+
+The specified connection has already been disconnected.
+
+0x80000026
+
+STATUS_LONGJUMP
+
+
+A long jump has been executed.
+
+0x80000027
+
+STATUS_CLEANER_CARTRIDGE_INSTALLED
+
+
+A cleaner cartridge is present in the tape library.
+
+0x80000028
+
+STATUS_PLUGPLAY_QUERY_VETOED
+
+
+The Plug and Play query operation was not successful.
+
+0x80000029
+
+STATUS_UNWIND_CONSOLIDATE
+
+
+A frame consolidation has been executed.
+
+0x8000002A
+
+STATUS_REGISTRY_HIVE_RECOVERED
+
+
+{Registry Hive Recovered} The registry hive (file): %hs was corrupted and it has been recovered. Some data might have been lost.
+
+0x8000002B
+
+STATUS_DLL_MIGHT_BE_INSECURE
+
+
+The application is attempting to run executable code from the module %hs. This might be insecure. An alternative, %hs, is available. Should the application use the secure module %hs?
+
+0x8000002C
+
+STATUS_DLL_MIGHT_BE_INCOMPATIBLE
+
+
+The application is loading executable code from the module %hs. This is secure but might be incompatible with previous releases of the operating system. An alternative, %hs, is available. Should the application use the secure module %hs?
+
+0x8000002D
+
+STATUS_STOPPED_ON_SYMLINK
+
+
+The create operation stopped after reaching a symbolic link.
+
+0x80000288
+
+STATUS_DEVICE_REQUIRES_CLEANING
+
+
+The device has indicated that cleaning is necessary.
+
+0x80000289
+
+STATUS_DEVICE_DOOR_OPEN
+
+
+The device has indicated that its door is open. Further operations require it closed and secured.
+
+0x80000803
+
+STATUS_DATA_LOST_REPAIR
+
+
+Windows discovered a corruption in the file %hs. This file has now been repaired. Check if any data in the file was lost because of the corruption.
+
+0x80010001
+
+DBG_EXCEPTION_NOT_HANDLED
+
+
+Debugger did not handle the exception.
+
+0x80130001
+
+STATUS_CLUSTER_NODE_ALREADY_UP
+
+
+The cluster node is already up.
+
+0x80130002
+
+STATUS_CLUSTER_NODE_ALREADY_DOWN
+
+
+The cluster node is already down.
+
+0x80130003
+
+STATUS_CLUSTER_NETWORK_ALREADY_ONLINE
+
+
+The cluster network is already online.
+
+0x80130004
+
+STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE
+
+
+The cluster network is already offline.
+
+0x80130005
+
+STATUS_CLUSTER_NODE_ALREADY_MEMBER
+
+
+The cluster node is already a member of the cluster.
+
+0x80190009
+
+STATUS_COULD_NOT_RESIZE_LOG
+
+
+The log could not be set to the requested size.
+
+0x80190029
+
+STATUS_NO_TXF_METADATA
+
+
+There is no transaction metadata on the file.
+
+0x80190031
+
+STATUS_CANT_RECOVER_WITH_HANDLE_OPEN
+
+
+The file cannot be recovered because there is a handle still open on it.
+
+0x80190041
+
+STATUS_TXF_METADATA_ALREADY_PRESENT
+
+
+Transaction metadata is already present on this file and cannot be superseded.
+
+0x80190042
+
+STATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET
+
+
+A transaction scope could not be entered because the scope handler has not been initialized.
+
+0x801B00EB
+
+STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED
+
+
+{Display Driver Stopped Responding and recovered} The %hs display driver has stopped working normally. The recovery had been performed.
+
+0x801C0001
+
+STATUS_FLT_BUFFER_TOO_SMALL
+
+
+{Buffer too small} The buffer is too small to contain the entry. No information has been written to the buffer.
+
+0x80210001
+
+STATUS_FVE_PARTIAL_METADATA
+
+
+Volume metadata read or write is incomplete.
+
+0x80210002
+
+STATUS_FVE_TRANSIENT_STATE
+
+
+BitLocker encryption keys were ignored because the volume was in a transient state.
+
+0xC0000001
+
+STATUS_UNSUCCESSFUL
+
+
+{Operation Failed} The requested operation was unsuccessful.
+
+0xC0000002
+
+STATUS_NOT_IMPLEMENTED
+
+
+{Not Implemented} The requested operation is not implemented.
+
+0xC0000003
+
+STATUS_INVALID_INFO_CLASS
+
+
+{Invalid Parameter} The specified information class is not a valid information class for the specified object.
+
+0xC0000004
+
+STATUS_INFO_LENGTH_MISMATCH
+
+
+The specified information record length does not match the length that is required for the specified information class.
+
+0xC0000005
+
+STATUS_ACCESS_VIOLATION
+
+
+The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.
+
+0xC0000006
+
+STATUS_IN_PAGE_ERROR
+
+
+The instruction at 0x%08lx referenced memory at 0x%08lx. The required data was not placed into memory because of an I/O error status of 0x%08lx.
+
+0xC0000007
+
+STATUS_PAGEFILE_QUOTA
+
+
+The page file quota for the process has been exhausted.
+
+0xC0000008
+
+STATUS_INVALID_HANDLE
+
+
+An invalid HANDLE was specified.
+
+0xC0000009
+
+STATUS_BAD_INITIAL_STACK
+
+
+An invalid initial stack was specified in a call to NtCreateThread.
+
+0xC000000A
+
+STATUS_BAD_INITIAL_PC
+
+
+An invalid initial start address was specified in a call to NtCreateThread.
+
+0xC000000B
+
+STATUS_INVALID_CID
+
+
+An invalid client ID was specified.
+
+0xC000000C
+
+STATUS_TIMER_NOT_CANCELED
+
+
+An attempt was made to cancel or set a timer that has an associated APC and the specified thread is not the thread that originally set the timer with an associated APC routine.
+
+0xC000000D
+
+STATUS_INVALID_PARAMETER
+
+
+An invalid parameter was passed to a service or function.
+
+0xC000000E
+
+STATUS_NO_SUCH_DEVICE
+
+
+A device that does not exist was specified.
+
+0xC000000F
+
+STATUS_NO_SUCH_FILE
+
+
+{File Not Found} The file %hs does not exist.
+
+0xC0000010
+
+STATUS_INVALID_DEVICE_REQUEST
+
+
+The specified request is not a valid operation for the target device.
+
+0xC0000011
+
+STATUS_END_OF_FILE
+
+
+The end-of-file marker has been reached. There is no valid data in the file beyond this marker.
+
+0xC0000012
+
+STATUS_WRONG_VOLUME
+
+
+{Wrong Volume} The wrong volume is in the drive. Insert volume %hs into drive %hs.
+
+0xC0000013
+
+STATUS_NO_MEDIA_IN_DEVICE
+
+
+{No Disk} There is no disk in the drive. Insert a disk into drive %hs.
+
+0xC0000014
+
+STATUS_UNRECOGNIZED_MEDIA
+
+
+{Unknown Disk Format} The disk in drive %hs is not formatted properly. Check the disk, and reformat it, if needed.
+
+0xC0000015
+
+STATUS_NONEXISTENT_SECTOR
+
+
+{Sector Not Found} The specified sector does not exist.
+
+0xC0000016
+
+STATUS_MORE_PROCESSING_REQUIRED
+
+
+{Still Busy} The specified I/O request packet (IRP) cannot be disposed of because the I/O operation is not complete.
+
+0xC0000017
+
+STATUS_NO_MEMORY
+
+
+{Not Enough Quota} Not enough virtual memory or paging file quota is available to complete the specified operation.
+
+0xC0000018
+
+STATUS_CONFLICTING_ADDRESSES
+
+
+{Conflicting Address Range} The specified address range conflicts with the address space.
+
+0xC0000019
+
+STATUS_NOT_MAPPED_VIEW
+
+
+The address range to unmap is not a mapped view.
+
+0xC000001A
+
+STATUS_UNABLE_TO_FREE_VM
+
+
+The virtual memory cannot be freed.
+
+0xC000001B
+
+STATUS_UNABLE_TO_DELETE_SECTION
+
+
+The specified section cannot be deleted.
+
+0xC000001C
+
+STATUS_INVALID_SYSTEM_SERVICE
+
+
+An invalid system service was specified in a system service call.
+
+0xC000001D
+
+STATUS_ILLEGAL_INSTRUCTION
+
+
+{EXCEPTION} Illegal Instruction An attempt was made to execute an illegal instruction.
+
+0xC000001E
+
+STATUS_INVALID_LOCK_SEQUENCE
+
+
+{Invalid Lock Sequence} An attempt was made to execute an invalid lock sequence.
+
+0xC000001F
+
+STATUS_INVALID_VIEW_SIZE
+
+
+{Invalid Mapping} An attempt was made to create a view for a section that is bigger than the section.
+
+0xC0000020
+
+STATUS_INVALID_FILE_FOR_SECTION
+
+
+{Bad File} The attributes of the specified mapping file for a section of memory cannot be read.
+
+0xC0000021
+
+STATUS_ALREADY_COMMITTED
+
+
+{Already Committed} The specified address range is already committed.
+
+0xC0000022
+
+STATUS_ACCESS_DENIED
+
+
+{Access Denied} A process has requested access to an object but has not been granted those access rights.
+
+0xC0000023
+
+STATUS_BUFFER_TOO_SMALL
+
+
+{Buffer Too Small} The buffer is too small to contain the entry. No information has been written to the buffer.
+
+0xC0000024
+
+STATUS_OBJECT_TYPE_MISMATCH
+
+
+{Wrong Type} There is a mismatch between the type of object that is required by the requested operation and the type of object that is specified in the request.
+
+0xC0000025
+
+STATUS_NONCONTINUABLE_EXCEPTION
+
+
+{EXCEPTION} Cannot Continue Windows cannot continue from this exception.
+
+0xC0000026
+
+STATUS_INVALID_DISPOSITION
+
+
+An invalid exception disposition was returned by an exception handler.
+
+0xC0000027
+
+STATUS_UNWIND
+
+
+Unwind exception code.
+
+0xC0000028
+
+STATUS_BAD_STACK
+
+
+An invalid or unaligned stack was encountered during an unwind operation.
+
+0xC0000029
+
+STATUS_INVALID_UNWIND_TARGET
+
+
+An invalid unwind target was encountered during an unwind operation.
+
+0xC000002A
+
+STATUS_NOT_LOCKED
+
+
+An attempt was made to unlock a page of memory that was not locked.
+
+0xC000002B
+
+STATUS_PARITY_ERROR
+
+
+A device parity error on an I/O operation.
+
+0xC000002C
+
+STATUS_UNABLE_TO_DECOMMIT_VM
+
+
+An attempt was made to decommit uncommitted virtual memory.
+
+0xC000002D
+
+STATUS_NOT_COMMITTED
+
+
+An attempt was made to change the attributes on memory that has not been committed.
+
+0xC000002E
+
+STATUS_INVALID_PORT_ATTRIBUTES
+
+
+Invalid object attributes specified to NtCreatePort or invalid port attributes specified to NtConnectPort.
+
+0xC000002F
+
+STATUS_PORT_MESSAGE_TOO_LONG
+
+
+The length of the message that was passed to NtRequestPort or NtRequestWaitReplyPort is longer than the maximum message that is allowed by the port.
+
+0xC0000030
+
+STATUS_INVALID_PARAMETER_MIX
+
+
+An invalid combination of parameters was specified.
+
+0xC0000031
+
+STATUS_INVALID_QUOTA_LOWER
+
+
+An attempt was made to lower a quota limit below the current usage.
+
+0xC0000032
+
+STATUS_DISK_CORRUPT_ERROR
+
+
+{Corrupt Disk} The file system structure on the disk is corrupt and unusable. Run the Chkdsk utility on the volume %hs.
+
+0xC0000033
+
+STATUS_OBJECT_NAME_INVALID
+
+
+The object name is invalid.
+
+0xC0000034
+
+STATUS_OBJECT_NAME_NOT_FOUND
+
+
+The object name is not found.
+
+0xC0000035
+
+STATUS_OBJECT_NAME_COLLISION
+
+
+The object name already exists.
+
+0xC0000037
+
+STATUS_PORT_DISCONNECTED
+
+
+An attempt was made to send a message to a disconnected communication port.
+
+0xC0000038
+
+STATUS_DEVICE_ALREADY_ATTACHED
+
+
+An attempt was made to attach to a device that was already attached to another device.
+
+0xC0000039
+
+STATUS_OBJECT_PATH_INVALID
+
+
+The object path component was not a directory object.
+
+0xC000003A
+
+STATUS_OBJECT_PATH_NOT_FOUND
+
+
+{Path Not Found} The path %hs does not exist.
+
+0xC000003B
+
+STATUS_OBJECT_PATH_SYNTAX_BAD
+
+
+The object path component was not a directory object.
+
+0xC000003C
+
+STATUS_DATA_OVERRUN
+
+
+{Data Overrun} A data overrun error occurred.
+
+0xC000003D
+
+STATUS_DATA_LATE_ERROR
+
+
+{Data Late} A data late error occurred.
+
+0xC000003E
+
+STATUS_DATA_ERROR
+
+
+{Data Error} An error occurred in reading or writing data.
+
+0xC000003F
+
+STATUS_CRC_ERROR
+
+
+{Bad CRC} A cyclic redundancy check (CRC) checksum error occurred.
+
+0xC0000040
+
+STATUS_SECTION_TOO_BIG
+
+
+{Section Too Large} The specified section is too big to map the file.
+
+0xC0000041
+
+STATUS_PORT_CONNECTION_REFUSED
+
+
+The NtConnectPort request is refused.
+
+0xC0000042
+
+STATUS_INVALID_PORT_HANDLE
+
+
+The type of port handle is invalid for the operation that is requested.
+
+0xC0000043
+
+STATUS_SHARING_VIOLATION
+
+
+A file cannot be opened because the share access flags are incompatible.
+
+0xC0000044
+
+STATUS_QUOTA_EXCEEDED
+
+
+Insufficient quota exists to complete the operation.
+
+0xC0000045
+
+STATUS_INVALID_PAGE_PROTECTION
+
+
+The specified page protection was not valid.
+
+0xC0000046
+
+STATUS_MUTANT_NOT_OWNED
+
+
+An attempt to release a mutant object was made by a thread that was not the owner of the mutant object.
+
+0xC0000047
+
+STATUS_SEMAPHORE_LIMIT_EXCEEDED
+
+
+An attempt was made to release a semaphore such that its maximum count would have been exceeded.
+
+0xC0000048
+
+STATUS_PORT_ALREADY_SET
+
+
+An attempt was made to set the DebugPort or ExceptionPort of a process, but a port already exists in the process, or an attempt was made to set the CompletionPort of a file but a port was already set in the file, or an attempt was made to set the associated completion port of an ALPC port but it is already set.
+
+0xC0000049
+
+STATUS_SECTION_NOT_IMAGE
+
+
+An attempt was made to query image information on a section that does not map an image.
+
+0xC000004A
+
+STATUS_SUSPEND_COUNT_EXCEEDED
+
+
+An attempt was made to suspend a thread whose suspend count was at its maximum.
+
+0xC000004B
+
+STATUS_THREAD_IS_TERMINATING
+
+
+An attempt was made to suspend a thread that has begun termination.
+
+0xC000004C
+
+STATUS_BAD_WORKING_SET_LIMIT
+
+
+An attempt was made to set the working set limit to an invalid value (for example, the minimum greater than maximum).
+
+0xC000004D
+
+STATUS_INCOMPATIBLE_FILE_MAP
+
+
+A section was created to map a file that is not compatible with an already existing section that maps the same file.
+
+0xC000004E
+
+STATUS_SECTION_PROTECTION
+
+
+A view to a section specifies a protection that is incompatible with the protection of the initial view.
+
+0xC000004F
+
+STATUS_EAS_NOT_SUPPORTED
+
+
+An operation involving EAs failed because the file system does not support EAs.
+
+0xC0000050
+
+STATUS_EA_TOO_LARGE
+
+
+An EA operation failed because the EA set is too large.
+
+0xC0000051
+
+STATUS_NONEXISTENT_EA_ENTRY
+
+
+An EA operation failed because the name or EA index is invalid.
+
+0xC0000052
+
+STATUS_NO_EAS_ON_FILE
+
+
+The file for which EAs were requested has no EAs.
+
+0xC0000053
+
+STATUS_EA_CORRUPT_ERROR
+
+
+The EA is corrupt and cannot be read.
+
+0xC0000054
+
+STATUS_FILE_LOCK_CONFLICT
+
+
+A requested read/write cannot be granted due to a conflicting file lock.
+
+0xC0000055
+
+STATUS_LOCK_NOT_GRANTED
+
+
+A requested file lock cannot be granted due to other existing locks.
+
+0xC0000056
+
+STATUS_DELETE_PENDING
+
+
+A non-close operation has been requested of a file object that has a delete pending.
+
+0xC0000057
+
+STATUS_CTL_FILE_NOT_SUPPORTED
+
+
+An attempt was made to set the control attribute on a file. This attribute is not supported in the destination file system.
+
+0xC0000058
+
+STATUS_UNKNOWN_REVISION
+
+
+Indicates a revision number that was encountered or specified is not one that is known by the service. It might be a more recent revision than the service is aware of.
+
+0xC0000059
+
+STATUS_REVISION_MISMATCH
+
+
+Indicates that two revision levels are incompatible.
+
+0xC000005A
+
+STATUS_INVALID_OWNER
+
+
+Indicates a particular security ID cannot be assigned as the owner of an object.
+
+0xC000005B
+
+STATUS_INVALID_PRIMARY_GROUP
+
+
+Indicates a particular security ID cannot be assigned as the primary group of an object.
+
+0xC000005C
+
+STATUS_NO_IMPERSONATION_TOKEN
+
+
+An attempt has been made to operate on an impersonation token by a thread that is not currently impersonating a client.
+
+0xC000005D
+
+STATUS_CANT_DISABLE_MANDATORY
+
+
+A mandatory group cannot be disabled.
+
+0xC000005E
+
+STATUS_NO_LOGON_SERVERS
+
+
+No logon servers are currently available to service the logon request.
+
+0xC000005F
+
+STATUS_NO_SUCH_LOGON_SESSION
+
+
+A specified logon session does not exist. It might already have been terminated.
+
+0xC0000060
+
+STATUS_NO_SUCH_PRIVILEGE
+
+
+A specified privilege does not exist.
+
+0xC0000061
+
+STATUS_PRIVILEGE_NOT_HELD
+
+
+A required privilege is not held by the client.
+
+0xC0000062
+
+STATUS_INVALID_ACCOUNT_NAME
+
+
+The name provided is not a properly formed account name.
+
+0xC0000063
+
+STATUS_USER_EXISTS
+
+
+The specified account already exists.
+
+0xC0000064
+
+STATUS_NO_SUCH_USER
+
+
+The specified account does not exist.
+
+0xC0000065
+
+STATUS_GROUP_EXISTS
+
+
+The specified group already exists.
+
+0xC0000066
+
+STATUS_NO_SUCH_GROUP
+
+
+The specified group does not exist.
+
+0xC0000067
+
+STATUS_MEMBER_IN_GROUP
+
+
+The specified user account is already in the specified group account. Also used to indicate a group cannot be deleted because it contains a member.
+
+0xC0000068
+
+STATUS_MEMBER_NOT_IN_GROUP
+
+
+The specified user account is not a member of the specified group account.
+
+0xC0000069
+
+STATUS_LAST_ADMIN
+
+
+Indicates the requested operation would disable or delete the last remaining administration account. This is not allowed to prevent creating a situation in which the system cannot be administrated.
+
+0xC000006A
+
+STATUS_WRONG_PASSWORD
+
+
+When trying to update a password, this return status indicates that the value provided as the current password is not correct.
+
+0xC000006B
+
+STATUS_ILL_FORMED_PASSWORD
+
+
+When trying to update a password, this return status indicates that the value provided for the new password contains values that are not allowed in passwords.
+
+0xC000006C
+
+STATUS_PASSWORD_RESTRICTION
+
+
+When trying to update a password, this status indicates that some password update rule has been violated. For example, the password might not meet length criteria.
+
+0xC000006D
+
+STATUS_LOGON_FAILURE
+
+
+The attempted logon is invalid. This is either due to a bad username or authentication information.
+
+0xC000006E
+
+STATUS_ACCOUNT_RESTRICTION
+
+
+Indicates a referenced user name and authentication information are valid, but some user account restriction has prevented successful authentication (such as time-of-day restrictions).
+
+0xC000006F
+
+STATUS_INVALID_LOGON_HOURS
+
+
+The user account has time restrictions and cannot be logged onto at this time.
+
+0xC0000070
+
+STATUS_INVALID_WORKSTATION
+
+
+The user account is restricted so that it cannot be used to log on from the source workstation.
+
+0xC0000071
+
+STATUS_PASSWORD_EXPIRED
+
+
+The user account password has expired.
+
+0xC0000072
+
+STATUS_ACCOUNT_DISABLED
+
+
+The referenced account is currently disabled and cannot be logged on to.
+
+0xC0000073
+
+STATUS_NONE_MAPPED
+
+
+None of the information to be translated has been translated.
+
+0xC0000074
+
+STATUS_TOO_MANY_LUIDS_REQUESTED
+
+
+The number of LUIDs requested cannot be allocated with a single allocation.
+
+0xC0000075
+
+STATUS_LUIDS_EXHAUSTED
+
+
+Indicates there are no more LUIDs to allocate.
+
+0xC0000076
+
+STATUS_INVALID_SUB_AUTHORITY
+
+
+Indicates the sub-authority value is invalid for the particular use.
+
+0xC0000077
+
+STATUS_INVALID_ACL
+
+
+Indicates the ACL structure is not valid.
+
+0xC0000078
+
+STATUS_INVALID_SID
+
+
+Indicates the SID structure is not valid.
+
+0xC0000079
+
+STATUS_INVALID_SECURITY_DESCR
+
+
+Indicates the SECURITY_DESCRIPTOR structure is not valid.
+
+0xC000007A
+
+STATUS_PROCEDURE_NOT_FOUND
+
+
+Indicates the specified procedure address cannot be found in the DLL.
+
+0xC000007B
+
+STATUS_INVALID_IMAGE_FORMAT
+
+
+{Bad Image} %hs is either not designed to run on Windows or it contains an error. Try installing the program again using the original installation media or contact your system administrator or the software vendor for support.
+
+0xC000007C
+
+STATUS_NO_TOKEN
+
+
+An attempt was made to reference a token that does not exist. This is typically done by referencing the token that is associated with a thread when the thread is not impersonating a client.
+
+0xC000007D
+
+STATUS_BAD_INHERITANCE_ACL
+
+
+Indicates that an attempt to build either an inherited ACL or ACE was not successful. This can be caused by a number of things. One of the more probable causes is the replacement of a CreatorId with a SID that did not fit into the ACE or ACL.
+
+0xC000007E
+
+STATUS_RANGE_NOT_LOCKED
+
+
+The range specified in NtUnlockFile was not locked.
+
+0xC000007F
+
+STATUS_DISK_FULL
+
+
+An operation failed because the disk was full.
+
+0xC0000080
+
+STATUS_SERVER_DISABLED
+
+
+The GUID allocation server is disabled at the moment.
+
+0xC0000081
+
+STATUS_SERVER_NOT_DISABLED
+
+
+The GUID allocation server is enabled at the moment.
+
+0xC0000082
+
+STATUS_TOO_MANY_GUIDS_REQUESTED
+
+
+Too many GUIDs were requested from the allocation server at once.
+
+0xC0000083
+
+STATUS_GUIDS_EXHAUSTED
+
+
+The GUIDs could not be allocated because the Authority Agent was exhausted.
+
+0xC0000084
+
+STATUS_INVALID_ID_AUTHORITY
+
+
+The value provided was an invalid value for an identifier authority.
+
+0xC0000085
+
+STATUS_AGENTS_EXHAUSTED
+
+
+No more authority agent values are available for the particular identifier authority value.
+
+0xC0000086
+
+STATUS_INVALID_VOLUME_LABEL
+
+
+An invalid volume label has been specified.
+
+0xC0000087
+
+STATUS_SECTION_NOT_EXTENDED
+
+
+A mapped section could not be extended.
+
+0xC0000088
+
+STATUS_NOT_MAPPED_DATA
+
+
+Specified section to flush does not map a data file.
+
+0xC0000089
+
+STATUS_RESOURCE_DATA_NOT_FOUND
+
+
+Indicates the specified image file did not contain a resource section.
+
+0xC000008A
+
+STATUS_RESOURCE_TYPE_NOT_FOUND
+
+
+Indicates the specified resource type cannot be found in the image file.
+
+0xC000008B
+
+STATUS_RESOURCE_NAME_NOT_FOUND
+
+
+Indicates the specified resource name cannot be found in the image file.
+
+0xC000008C
+
+STATUS_ARRAY_BOUNDS_EXCEEDED
+
+
+{EXCEPTION} Array bounds exceeded.
+
+0xC000008D
+
+STATUS_FLOAT_DENORMAL_OPERAND
+
+
+{EXCEPTION} Floating-point denormal operand.
+
+0xC000008E
+
+STATUS_FLOAT_DIVIDE_BY_ZERO
+
+
+{EXCEPTION} Floating-point division by zero.
+
+0xC000008F
+
+STATUS_FLOAT_INEXACT_RESULT
+
+
+{EXCEPTION} Floating-point inexact result.
+
+0xC0000090
+
+STATUS_FLOAT_INVALID_OPERATION
+
+
+{EXCEPTION} Floating-point invalid operation.
+
+0xC0000091
+
+STATUS_FLOAT_OVERFLOW
+
+
+{EXCEPTION} Floating-point overflow.
+
+0xC0000092
+
+STATUS_FLOAT_STACK_CHECK
+
+
+{EXCEPTION} Floating-point stack check.
+
+0xC0000093
+
+STATUS_FLOAT_UNDERFLOW
+
+
+{EXCEPTION} Floating-point underflow.
+
+0xC0000094
+
+STATUS_INTEGER_DIVIDE_BY_ZERO
+
+
+{EXCEPTION} Integer division by zero.
+
+0xC0000095
+
+STATUS_INTEGER_OVERFLOW
+
+
+{EXCEPTION} Integer overflow.
+
+0xC0000096
+
+STATUS_PRIVILEGED_INSTRUCTION
+
+
+{EXCEPTION} Privileged instruction.
+
+0xC0000097
+
+STATUS_TOO_MANY_PAGING_FILES
+
+
+An attempt was made to install more paging files than the system supports.
+
+0xC0000098
+
+STATUS_FILE_INVALID
+
+
+The volume for a file has been externally altered such that the opened file is no longer valid.
+
+0xC0000099
+
+STATUS_ALLOTTED_SPACE_EXCEEDED
+
+
+When a block of memory is allotted for future updates, such as the memory allocated to hold discretionary access control and primary group information, successive updates might exceed the amount of memory originally allotted. Because a quota might already have been charged to several processes that have handles to the object, it is not reasonable to alter the size of the allocated memory. Instead, a request that requires more memory than has been allotted must fail and the STATUS_ALLOTTED_SPACE_EXCEEDED error returned.
+
+0xC000009A
+
+STATUS_INSUFFICIENT_RESOURCES
+
+
+Insufficient system resources exist to complete the API.
+
+0xC000009B
+
+STATUS_DFS_EXIT_PATH_FOUND
+
+
+An attempt has been made to open a DFS exit path control file.
+
+0xC000009C
+
+STATUS_DEVICE_DATA_ERROR
+
+
+There are bad blocks (sectors) on the hard disk.
+
+0xC000009D
+
+STATUS_DEVICE_NOT_CONNECTED
+
+
+There is bad cabling, non-termination, or the controller is not able to obtain access to the hard disk.
+
+0xC000009F
+
+STATUS_FREE_VM_NOT_AT_BASE
+
+
+Virtual memory cannot be freed because the base address is not the base of the region and a region size of zero was specified.
+
+0xC00000A0
+
+STATUS_MEMORY_NOT_ALLOCATED
+
+
+An attempt was made to free virtual memory that is not allocated.
+
+0xC00000A1
+
+STATUS_WORKING_SET_QUOTA
+
+
+The working set is not big enough to allow the requested pages to be locked.
+
+0xC00000A2
+
+STATUS_MEDIA_WRITE_PROTECTED
+
+
+{Write Protect Error} The disk cannot be written to because it is write-protected. Remove the write protection from the volume %hs in drive %hs.
+
+0xC00000A3
+
+STATUS_DEVICE_NOT_READY
+
+
+{Drive Not Ready} The drive is not ready for use; its door might be open. Check drive %hs and make sure that a disk is inserted and that the drive door is closed.
+
+0xC00000A4
+
+STATUS_INVALID_GROUP_ATTRIBUTES
+
+
+The specified attributes are invalid or are incompatible with the attributes for the group as a whole.
+
+0xC00000A5
+
+STATUS_BAD_IMPERSONATION_LEVEL
+
+
+A specified impersonation level is invalid. Also used to indicate that a required impersonation level was not provided.
+
+0xC00000A6
+
+STATUS_CANT_OPEN_ANONYMOUS
+
+
+An attempt was made to open an anonymous-level token. Anonymous tokens cannot be opened.
+
+0xC00000A7
+
+STATUS_BAD_VALIDATION_CLASS
+
+
+The validation information class requested was invalid.
+
+0xC00000A8
+
+STATUS_BAD_TOKEN_TYPE
+
+
+The type of a token object is inappropriate for its attempted use.
+
+0xC00000A9
+
+STATUS_BAD_MASTER_BOOT_RECORD
+
+
+The type of a token object is inappropriate for its attempted use.
+
+0xC00000AA
+
+STATUS_INSTRUCTION_MISALIGNMENT
+
+
+An attempt was made to execute an instruction at an unaligned address and the host system does not support unaligned instruction references.
+
+0xC00000AB
+
+STATUS_INSTANCE_NOT_AVAILABLE
+
+
+The maximum named pipe instance count has been reached.
+
+0xC00000AC
+
+STATUS_PIPE_NOT_AVAILABLE
+
+
+An instance of a named pipe cannot be found in the listening state.
+
+0xC00000AD
+
+STATUS_INVALID_PIPE_STATE
+
+
+The named pipe is not in the connected or closing state.
+
+0xC00000AE
+
+STATUS_PIPE_BUSY
+
+
+The specified pipe is set to complete operations and there are current I/O operations queued so that it cannot be changed to queue operations.
+
+0xC00000AF
+
+STATUS_ILLEGAL_FUNCTION
+
+
+The specified handle is not open to the server end of the named pipe.
+
+0xC00000B0
+
+STATUS_PIPE_DISCONNECTED
+
+
+The specified named pipe is in the disconnected state.
+
+0xC00000B1
+
+STATUS_PIPE_CLOSING
+
+
+The specified named pipe is in the closing state.
+
+0xC00000B2
+
+STATUS_PIPE_CONNECTED
+
+
+The specified named pipe is in the connected state.
+
+0xC00000B3
+
+STATUS_PIPE_LISTENING
+
+
+The specified named pipe is in the listening state.
+
+0xC00000B4
+
+STATUS_INVALID_READ_MODE
+
+
+The specified named pipe is not in message mode.
+
+0xC00000B5
+
+STATUS_IO_TIMEOUT
+
+
+{Device Timeout} The specified I/O operation on %hs was not completed before the time-out period expired.
+
+0xC00000B6
+
+STATUS_FILE_FORCED_CLOSED
+
+
+The specified file has been closed by another process.
+
+0xC00000B7
+
+STATUS_PROFILING_NOT_STARTED
+
+
+Profiling is not started.
+
+0xC00000B8
+
+STATUS_PROFILING_NOT_STOPPED
+
+
+Profiling is not stopped.
+
+0xC00000B9
+
+STATUS_COULD_NOT_INTERPRET
+
+
+The passed ACL did not contain the minimum required information.
+
+0xC00000BA
+
+STATUS_FILE_IS_A_DIRECTORY
+
+
+The file that was specified as a target is a directory, and the caller specified that it could be anything but a directory.
+
+0xC00000BB
+
+STATUS_NOT_SUPPORTED
+
+
+The request is not supported.
+
+0xC00000BC
+
+STATUS_REMOTE_NOT_LISTENING
+
+
+This remote computer is not listening.
+
+0xC00000BD
+
+STATUS_DUPLICATE_NAME
+
+
+A duplicate name exists on the network.
+
+0xC00000BE
+
+STATUS_BAD_NETWORK_PATH
+
+
+The network path cannot be located.
+
+0xC00000BF
+
+STATUS_NETWORK_BUSY
+
+
+The network is busy.
+
+0xC00000C0
+
+STATUS_DEVICE_DOES_NOT_EXIST
+
+
+This device does not exist.
+
+0xC00000C1
+
+STATUS_TOO_MANY_COMMANDS
+
+
+The network BIOS command limit has been reached.
+
+0xC00000C2
+
+STATUS_ADAPTER_HARDWARE_ERROR
+
+
+An I/O adapter hardware error has occurred.
+
+0xC00000C3
+
+STATUS_INVALID_NETWORK_RESPONSE
+
+
+The network responded incorrectly.
+
+0xC00000C4
+
+STATUS_UNEXPECTED_NETWORK_ERROR
+
+
+An unexpected network error occurred.
+
+0xC00000C5
+
+STATUS_BAD_REMOTE_ADAPTER
+
+
+The remote adapter is not compatible.
+
+0xC00000C6
+
+STATUS_PRINT_QUEUE_FULL
+
+
+The print queue is full.
+
+0xC00000C7
+
+STATUS_NO_SPOOL_SPACE
+
+
+Space to store the file that is waiting to be printed is not available on the server.
+
+0xC00000C8
+
+STATUS_PRINT_CANCELLED
+
+
+The requested print file has been canceled.
+
+0xC00000C9
+
+STATUS_NETWORK_NAME_DELETED
+
+
+The network name was deleted.
+
+0xC00000CA
+
+STATUS_NETWORK_ACCESS_DENIED
+
+
+Network access is denied.
+
+0xC00000CB
+
+STATUS_BAD_DEVICE_TYPE
+
+
+{Incorrect Network Resource Type} The specified device type (LPT, for example) conflicts with the actual device type on the remote resource.
+
+0xC00000CC
+
+STATUS_BAD_NETWORK_NAME
+
+
+{Network Name Not Found} The specified share name cannot be found on the remote server.
+
+0xC00000CD
+
+STATUS_TOO_MANY_NAMES
+
+
+The name limit for the network adapter card of the local computer was exceeded.
+
+0xC00000CE
+
+STATUS_TOO_MANY_SESSIONS
+
+
+The network BIOS session limit was exceeded.
+
+0xC00000CF
+
+STATUS_SHARING_PAUSED
+
+
+File sharing has been temporarily paused.
+
+0xC00000D0
+
+STATUS_REQUEST_NOT_ACCEPTED
+
+
+No more connections can be made to this remote computer at this time because the computer has already accepted the maximum number of connections.
+
+0xC00000D1
+
+STATUS_REDIRECTOR_PAUSED
+
+
+Print or disk redirection is temporarily paused.
+
+0xC00000D2
+
+STATUS_NET_WRITE_FAULT
+
+
+A network data fault occurred.
+
+0xC00000D3
+
+STATUS_PROFILING_AT_LIMIT
+
+
+The number of active profiling objects is at the maximum and no more can be started.
+
+0xC00000D4
+
+STATUS_NOT_SAME_DEVICE
+
+
+{Incorrect Volume} The destination file of a rename request is located on a different device than the source of the rename request.
+
+0xC00000D5
+
+STATUS_FILE_RENAMED
+
+
+The specified file has been renamed and thus cannot be modified.
+
+0xC00000D6
+
+STATUS_VIRTUAL_CIRCUIT_CLOSED
+
+
+{Network Request Timeout} The session with a remote server has been disconnected because the time-out interval for a request has expired.
+
+0xC00000D7
+
+STATUS_NO_SECURITY_ON_OBJECT
+
+
+Indicates an attempt was made to operate on the security of an object that does not have security associated with it.
+
+0xC00000D8
+
+STATUS_CANT_WAIT
+
+
+Used to indicate that an operation cannot continue without blocking for I/O.
+
+0xC00000D9
+
+STATUS_PIPE_EMPTY
+
+
+Used to indicate that a read operation was done on an empty pipe.
+
+0xC00000DA
+
+STATUS_CANT_ACCESS_DOMAIN_INFO
+
+
+Configuration information could not be read from the domain controller, either because the machine is unavailable or access has been denied.
+
+0xC00000DB
+
+STATUS_CANT_TERMINATE_SELF
+
+
+Indicates that a thread attempted to terminate itself by default (called NtTerminateThread with NULL) and it was the last thread in the current process.
+
+0xC00000DC
+
+STATUS_INVALID_SERVER_STATE
+
+
+Indicates the Sam Server was in the wrong state to perform the desired operation.
+
+0xC00000DD
+
+STATUS_INVALID_DOMAIN_STATE
+
+
+Indicates the domain was in the wrong state to perform the desired operation.
+
+0xC00000DE
+
+STATUS_INVALID_DOMAIN_ROLE
+
+
+This operation is only allowed for the primary domain controller of the domain.
+
+0xC00000DF
+
+STATUS_NO_SUCH_DOMAIN
+
+
+The specified domain did not exist.
+
+0xC00000E0
+
+STATUS_DOMAIN_EXISTS
+
+
+The specified domain already exists.
+
+0xC00000E1
+
+STATUS_DOMAIN_LIMIT_EXCEEDED
+
+
+An attempt was made to exceed the limit on the number of domains per server for this release.
+
+0xC00000E2
+
+STATUS_OPLOCK_NOT_GRANTED
+
+
+An error status returned when the opportunistic lock (oplock) request is denied.
+
+0xC00000E3
+
+STATUS_INVALID_OPLOCK_PROTOCOL
+
+
+An error status returned when an invalid opportunistic lock (oplock) acknowledgment is received by a file system.
+
+0xC00000E4
+
+STATUS_INTERNAL_DB_CORRUPTION
+
+
+This error indicates that the requested operation cannot be completed due to a catastrophic media failure or an on-disk data structure corruption.
+
+0xC00000E5
+
+STATUS_INTERNAL_ERROR
+
+
+An internal error occurred.
+
+0xC00000E6
+
+STATUS_GENERIC_NOT_MAPPED
+
+
+Indicates generic access types were contained in an access mask which should already be mapped to non-generic access types.
+
+0xC00000E7
+
+STATUS_BAD_DESCRIPTOR_FORMAT
+
+
+Indicates a security descriptor is not in the necessary format (absolute or self-relative).
+
+0xC00000E8
+
+STATUS_INVALID_USER_BUFFER
+
+
+An access to a user buffer failed at an expected point in time. This code is defined because the caller does not want to accept STATUS_ACCESS_VIOLATION in its filter.
+
+0xC00000E9
+
+STATUS_UNEXPECTED_IO_ERROR
+
+
+If an I/O error that is not defined in the standard FsRtl filter is returned, it is converted to the following error, which is guaranteed to be in the filter. In this case, information is lost; however, the filter correctly handles the exception.
+
+0xC00000EA
+
+STATUS_UNEXPECTED_MM_CREATE_ERR
+
+
+If an MM error that is not defined in the standard FsRtl filter is returned, it is converted to one of the following errors, which are guaranteed to be in the filter. In this case, information is lost; however, the filter correctly handles the exception.
+
+0xC00000EB
+
+STATUS_UNEXPECTED_MM_MAP_ERROR
+
+
+If an MM error that is not defined in the standard FsRtl filter is returned, it is converted to one of the following errors, which are guaranteed to be in the filter. In this case, information is lost; however, the filter correctly handles the exception.
+
+0xC00000EC
+
+STATUS_UNEXPECTED_MM_EXTEND_ERR
+
+
+If an MM error that is not defined in the standard FsRtl filter is returned, it is converted to one of the following errors, which are guaranteed to be in the filter. In this case, information is lost; however, the filter correctly handles the exception.
+
+0xC00000ED
+
+STATUS_NOT_LOGON_PROCESS
+
+
+The requested action is restricted for use by logon processes only. The calling process has not registered as a logon process.
+
+0xC00000EE
+
+STATUS_LOGON_SESSION_EXISTS
+
+
+An attempt has been made to start a new session manager or LSA logon session by using an ID that is already in use.
+
+0xC00000EF
+
+STATUS_INVALID_PARAMETER_1
+
+
+An invalid parameter was passed to a service or function as the first argument.
+
+0xC00000F0
+
+STATUS_INVALID_PARAMETER_2
+
+
+An invalid parameter was passed to a service or function as the second argument.
+
+0xC00000F1
+
+STATUS_INVALID_PARAMETER_3
+
+
+An invalid parameter was passed to a service or function as the third argument.
+
+0xC00000F2
+
+STATUS_INVALID_PARAMETER_4
+
+
+An invalid parameter was passed to a service or function as the fourth argument.
+
+0xC00000F3
+
+STATUS_INVALID_PARAMETER_5
+
+
+An invalid parameter was passed to a service or function as the fifth argument.
+
+0xC00000F4
+
+STATUS_INVALID_PARAMETER_6
+
+
+An invalid parameter was passed to a service or function as the sixth argument.
+
+0xC00000F5
+
+STATUS_INVALID_PARAMETER_7
+
+
+An invalid parameter was passed to a service or function as the seventh argument.
+
+0xC00000F6
+
+STATUS_INVALID_PARAMETER_8
+
+
+An invalid parameter was passed to a service or function as the eighth argument.
+
+0xC00000F7
+
+STATUS_INVALID_PARAMETER_9
+
+
+An invalid parameter was passed to a service or function as the ninth argument.
+
+0xC00000F8
+
+STATUS_INVALID_PARAMETER_10
+
+
+An invalid parameter was passed to a service or function as the tenth argument.
+
+0xC00000F9
+
+STATUS_INVALID_PARAMETER_11
+
+
+An invalid parameter was passed to a service or function as the eleventh argument.
+
+0xC00000FA
+
+STATUS_INVALID_PARAMETER_12
+
+
+An invalid parameter was passed to a service or function as the twelfth argument.
+
+0xC00000FB
+
+STATUS_REDIRECTOR_NOT_STARTED
+
+
+An attempt was made to access a network file, but the network software was not yet started.
+
+0xC00000FC
+
+STATUS_REDIRECTOR_STARTED
+
+
+An attempt was made to start the redirector, but the redirector has already been started.
+
+0xC00000FD
+
+STATUS_STACK_OVERFLOW
+
+
+A new guard page for the stack cannot be created.
+
+0xC00000FE
+
+STATUS_NO_SUCH_PACKAGE
+
+
+A specified authentication package is unknown.
+
+0xC00000FF
+
+STATUS_BAD_FUNCTION_TABLE
+
+
+A malformed function table was encountered during an unwind operation.
+
+0xC0000100
+
+STATUS_VARIABLE_NOT_FOUND
+
+
+Indicates the specified environment variable name was not found in the specified environment block.
+
+0xC0000101
+
+STATUS_DIRECTORY_NOT_EMPTY
+
+
+Indicates that the directory trying to be deleted is not empty.
+
+0xC0000102
+
+STATUS_FILE_CORRUPT_ERROR
+
+
+{Corrupt File} The file or directory %hs is corrupt and unreadable. Run the Chkdsk utility.
+
+0xC0000103
+
+STATUS_NOT_A_DIRECTORY
+
+
+A requested opened file is not a directory.
+
+0xC0000104
+
+STATUS_BAD_LOGON_SESSION_STATE
+
+
+The logon session is not in a state that is consistent with the requested operation.
+
+0xC0000105
+
+STATUS_LOGON_SESSION_COLLISION
+
+
+An internal LSA error has occurred. An authentication package has requested the creation of a logon session but the ID of an already existing logon session has been specified.
+
+0xC0000106
+
+STATUS_NAME_TOO_LONG
+
+
+A specified name string is too long for its intended use.
+
+0xC0000107
+
+STATUS_FILES_OPEN
+
+
+The user attempted to force close the files on a redirected drive, but there were opened files on the drive, and the user did not specify a sufficient level of force.
+
+0xC0000108
+
+STATUS_CONNECTION_IN_USE
+
+
+The user attempted to force close the files on a redirected drive, but there were opened directories on the drive, and the user did not specify a sufficient level of force.
+
+0xC0000109
+
+STATUS_MESSAGE_NOT_FOUND
+
+
+RtlFindMessage could not locate the requested message ID in the message table resource.
+
+0xC000010A
+
+STATUS_PROCESS_IS_TERMINATING
+
+
+An attempt was made to duplicate an object handle into or out of an exiting process.
+
+0xC000010B
+
+STATUS_INVALID_LOGON_TYPE
+
+
+Indicates an invalid value has been provided for the LogonType requested.
+
+0xC000010C
+
+STATUS_NO_GUID_TRANSLATION
+
+
+Indicates that an attempt was made to assign protection to a file system file or directory and one of the SIDs in the security descriptor could not be translated into a GUID that could be stored by the file system. This causes the protection attempt to fail, which might cause a file creation attempt to fail.
+
+0xC000010D
+
+STATUS_CANNOT_IMPERSONATE
+
+
+Indicates that an attempt has been made to impersonate via a named pipe that has not yet been read from.
+
+0xC000010E
+
+STATUS_IMAGE_ALREADY_LOADED
+
+
+Indicates that the specified image is already loaded.
+
+0xC0000117
+
+STATUS_NO_LDT
+
+
+Indicates that an attempt was made to change the size of the LDT for a process that has no LDT.
+
+0xC0000118
+
+STATUS_INVALID_LDT_SIZE
+
+
+Indicates that an attempt was made to grow an LDT by setting its size, or that the size was not an even number of selectors.
+
+0xC0000119
+
+STATUS_INVALID_LDT_OFFSET
+
+
+Indicates that the starting value for the LDT information was not an integral multiple of the selector size.
+
+0xC000011A
+
+STATUS_INVALID_LDT_DESCRIPTOR
+
+
+Indicates that the user supplied an invalid descriptor when trying to set up LDT descriptors.
+
+0xC000011B
+
+STATUS_INVALID_IMAGE_NE_FORMAT
+
+
+The specified image file did not have the correct format. It appears to be NE format.
+
+0xC000011C
+
+STATUS_RXACT_INVALID_STATE
+
+
+Indicates that the transaction state of a registry subtree is incompatible with the requested operation. For example, a request has been made to start a new transaction with one already in progress, or a request has been made to apply a transaction when one is not currently in progress.
+
+0xC000011D
+
+STATUS_RXACT_COMMIT_FAILURE
+
+
+Indicates an error has occurred during a registry transaction commit. The database has been left in an unknown, but probably inconsistent, state. The state of the registry transaction is left as COMMITTING.
+
+0xC000011E
+
+STATUS_MAPPED_FILE_SIZE_ZERO
+
+
+An attempt was made to map a file of size zero with the maximum size specified as zero.
+
+0xC000011F
+
+STATUS_TOO_MANY_OPENED_FILES
+
+
+Too many files are opened on a remote server. This error should only be returned by the Windows redirector on a remote drive.
+
+0xC0000120
+
+STATUS_CANCELLED
+
+
+The I/O request was canceled.
+
+0xC0000121
+
+STATUS_CANNOT_DELETE
+
+
+An attempt has been made to remove a file or directory that cannot be deleted.
+
+0xC0000122
+
+STATUS_INVALID_COMPUTER_NAME
+
+
+Indicates a name that was specified as a remote computer name is syntactically invalid.
+
+0xC0000123
+
+STATUS_FILE_DELETED
+
+
+An I/O request other than close was performed on a file after it was deleted, which can only happen to a request that did not complete before the last handle was closed via NtClose.
+
+0xC0000124
+
+STATUS_SPECIAL_ACCOUNT
+
+
+Indicates an operation that is incompatible with built-in accounts has been attempted on a built-in (special) SAM account. For example, built-in accounts cannot be deleted.
+
+0xC0000125
+
+STATUS_SPECIAL_GROUP
+
+
+The operation requested cannot be performed on the specified group because it is a built-in special group.
+
+0xC0000126
+
+STATUS_SPECIAL_USER
+
+
+The operation requested cannot be performed on the specified user because it is a built-in special user.
+
+0xC0000127
+
+STATUS_MEMBERS_PRIMARY_GROUP
+
+
+Indicates a member cannot be removed from a group because the group is currently the member's primary group.
+
+0xC0000128
+
+STATUS_FILE_CLOSED
+
+
+An I/O request other than close and several other special case operations was attempted using a file object that had already been closed.
+
+0xC0000129
+
+STATUS_TOO_MANY_THREADS
+
+
+Indicates a process has too many threads to perform the requested action. For example, assignment of a primary token can be performed only when a process has zero or one threads.
+
+0xC000012A
+
+STATUS_THREAD_NOT_IN_PROCESS
+
+
+An attempt was made to operate on a thread within a specific process, but the specified thread is not in the specified process.
+
+0xC000012B
+
+STATUS_TOKEN_ALREADY_IN_USE
+
+
+An attempt was made to establish a token for use as a primary token but the token is already in use. A token can only be the primary token of one process at a time.
+
+0xC000012C
+
+STATUS_PAGEFILE_QUOTA_EXCEEDED
+
+
+The page file quota was exceeded.
+
+0xC000012D
+
+STATUS_COMMITMENT_LIMIT
+
+
+{Out of Virtual Memory} Your system is low on virtual memory. To ensure that Windows runs correctly, increase the size of your virtual memory paging file. For more information, see Help.
+
+0xC000012E
+
+STATUS_INVALID_IMAGE_LE_FORMAT
+
+
+The specified image file did not have the correct format: it appears to be LE format.
+
+0xC000012F
+
+STATUS_INVALID_IMAGE_NOT_MZ
+
+
+The specified image file did not have the correct format: it did not have an initial MZ.
+
+0xC0000130
+
+STATUS_INVALID_IMAGE_PROTECT
+
+
+The specified image file did not have the correct format: it did not have a proper e_lfarlc in the MZ header.
+
+0xC0000131
+
+STATUS_INVALID_IMAGE_WIN_16
+
+
+The specified image file did not have the correct format: it appears to be a 16-bit Windows image.
+
+0xC0000132
+
+STATUS_LOGON_SERVER_CONFLICT
+
+
+The Netlogon service cannot start because another Netlogon service running in the domain conflicts with the specified role.
+
+0xC0000133
+
+STATUS_TIME_DIFFERENCE_AT_DC
+
+
+The time at the primary domain controller is different from the time at the backup domain controller or member server by too large an amount.
+
+0xC0000134
+
+STATUS_SYNCHRONIZATION_REQUIRED
+
+
+On applicable Windows Server releases, the SAM database is significantly out of synchronization with the copy on the domain controller. A complete synchronization is required.
+
+0xC0000135
+
+STATUS_DLL_NOT_FOUND
+
+
+{Unable To Locate Component} This application has failed to start because %hs was not found. Reinstalling the application might fix this problem.
+
+0xC0000136
+
+STATUS_OPEN_FAILED
+
+
+The NtCreateFile API failed. This error should never be returned to an application; it is a place holder for the Windows LAN Manager Redirector to use in its internal error-mapping routines.
+
+0xC0000137
+
+STATUS_IO_PRIVILEGE_FAILED
+
+
+{Privilege Failed} The I/O permissions for the process could not be changed.
+
+0xC0000138
+
+STATUS_ORDINAL_NOT_FOUND
+
+
+{Ordinal Not Found} The ordinal %ld could not be located in the dynamic link library %hs.
+
+0xC0000139
+
+STATUS_ENTRYPOINT_NOT_FOUND
+
+
+{Entry Point Not Found} The procedure entry point %hs could not be located in the dynamic link library %hs.
+
+0xC000013A
+
+STATUS_CONTROL_C_EXIT
+
+
+{Application Exit by CTRL+C} The application terminated as a result of a CTRL+C.
+
+0xC000013B
+
+STATUS_LOCAL_DISCONNECT
+
+
+{Virtual Circuit Closed} The network transport on your computer has closed a network connection. There might or might not be I/O requests outstanding.
+
+0xC000013C
+
+STATUS_REMOTE_DISCONNECT
+
+
+{Virtual Circuit Closed} The network transport on a remote computer has closed a network connection. There might or might not be I/O requests outstanding.
+
+0xC000013D
+
+STATUS_REMOTE_RESOURCES
+
+
+{Insufficient Resources on Remote Computer} The remote computer has insufficient resources to complete the network request. For example, the remote computer might not have enough available memory to carry out the request at this time.
+
+0xC000013E
+
+STATUS_LINK_FAILED
+
+
+{Virtual Circuit Closed} An existing connection (virtual circuit) has been broken at the remote computer. There is probably something wrong with the network software protocol or the network hardware on the remote computer.
+
+0xC000013F
+
+STATUS_LINK_TIMEOUT
+
+
+{Virtual Circuit Closed} The network transport on your computer has closed a network connection because it had to wait too long for a response from the remote computer.
+
+0xC0000140
+
+STATUS_INVALID_CONNECTION
+
+
+The connection handle that was given to the transport was invalid.
+
+0xC0000141
+
+STATUS_INVALID_ADDRESS
+
+
+The address handle that was given to the transport was invalid.
+
+0xC0000142
+
+STATUS_DLL_INIT_FAILED
+
+
+{DLL Initialization Failed} Initialization of the dynamic link library %hs failed. The process is terminating abnormally.
+
+0xC0000143
+
+STATUS_MISSING_SYSTEMFILE
+
+
+{Missing System File} The required system file %hs is bad or missing.
+
+0xC0000144
+
+STATUS_UNHANDLED_EXCEPTION
+
+
+{Application Error} The exception %s (0x%08lx) occurred in the application at location 0x%08lx.
+
+0xC0000145
+
+STATUS_APP_INIT_FAILURE
+
+
+{Application Error} The application failed to initialize properly (0x%lx). Click OK to terminate the application.
+
+0xC0000146
+
+STATUS_PAGEFILE_CREATE_FAILED
+
+
+{Unable to Create Paging File} The creation of the paging file %hs failed (%lx). The requested size was %ld.
+
+0xC0000147
+
+STATUS_NO_PAGEFILE
+
+
+{No Paging File Specified} No paging file was specified in the system configuration.
+
+0xC0000148
+
+STATUS_INVALID_LEVEL
+
+
+{Incorrect System Call Level} An invalid level was passed into the specified system call.
+
+0xC0000149
+
+STATUS_WRONG_PASSWORD_CORE
+
+
+{Incorrect Password to LAN Manager Server} You specified an incorrect password to a LAN Manager 2.x or MS-NET server.
+
+0xC000014A
+
+STATUS_ILLEGAL_FLOAT_CONTEXT
+
+
+{EXCEPTION} A real-mode application issued a floating-point instruction and floating-point hardware is not present.
+
+0xC000014B
+
+STATUS_PIPE_BROKEN
+
+
+The pipe operation has failed because the other end of the pipe has been closed.
+
+0xC000014C
+
+STATUS_REGISTRY_CORRUPT
+
+
+{The Registry Is Corrupt} The structure of one of the files that contains registry data is corrupt; the image of the file in memory is corrupt; or the file could not be recovered because the alternate copy or log was absent or corrupt.
+
+0xC000014D
+
+STATUS_REGISTRY_IO_FAILED
+
+
+An I/O operation initiated by the Registry failed and cannot be recovered. The registry could not read in, write out, or flush one of the files that contain the system's image of the registry.
+
+0xC000014E
+
+STATUS_NO_EVENT_PAIR
+
+
+An event pair synchronization operation was performed using the thread-specific client/server event pair object, but no event pair object was associated with the thread.
+
+0xC000014F
+
+STATUS_UNRECOGNIZED_VOLUME
+
+
+The volume does not contain a recognized file system. Be sure that all required file system drivers are loaded and that the volume is not corrupt.
+
+0xC0000150
+
+STATUS_SERIAL_NO_DEVICE_INITED
+
+
+No serial device was successfully initialized. The serial driver will unload.
+
+0xC0000151
+
+STATUS_NO_SUCH_ALIAS
+
+
+The specified local group does not exist.
+
+0xC0000152
+
+STATUS_MEMBER_NOT_IN_ALIAS
+
+
+The specified account name is not a member of the group.
+
+0xC0000153
+
+STATUS_MEMBER_IN_ALIAS
+
+
+The specified account name is already a member of the group.
+
+0xC0000154
+
+STATUS_ALIAS_EXISTS
+
+
+The specified local group already exists.
+
+0xC0000155
+
+STATUS_LOGON_NOT_GRANTED
+
+
+A requested type of logon (for example, interactive, network, and service) is not granted by the local security policy of the target system. Ask the system administrator to grant the necessary form of logon.
+
+0xC0000156
+
+STATUS_TOO_MANY_SECRETS
+
+
+The maximum number of secrets that can be stored in a single system was exceeded. The length and number of secrets is limited to satisfy U.S. State Department export restrictions.
+
+0xC0000157
+
+STATUS_SECRET_TOO_LONG
+
+
+The length of a secret exceeds the maximum allowable length. The length and number of secrets is limited to satisfy U.S. State Department export restrictions.
+
+0xC0000158
+
+STATUS_INTERNAL_DB_ERROR
+
+
+The local security authority (LSA) database contains an internal inconsistency.
+
+0xC0000159
+
+STATUS_FULLSCREEN_MODE
+
+
+The requested operation cannot be performed in full-screen mode.
+
+0xC000015A
+
+STATUS_TOO_MANY_CONTEXT_IDS
+
+
+During a logon attempt, the user's security context accumulated too many security IDs. This is a very unusual situation. Remove the user from some global or local groups to reduce the number of security IDs to incorporate into the security context.
+
+0xC000015B
+
+STATUS_LOGON_TYPE_NOT_GRANTED
+
+
+A user has requested a type of logon (for example, interactive or network) that has not been granted. An administrator has control over who can logon interactively and through the network.
+
+0xC000015C
+
+STATUS_NOT_REGISTRY_FILE
+
+
+The system has attempted to load or restore a file into the registry, and the specified file is not in the format of a registry file.
+
+0xC000015D
+
+STATUS_NT_CROSS_ENCRYPTION_REQUIRED
+
+
+An attempt was made to change a user password in the security account manager without providing the necessary Windows cross-encrypted password.
+
+0xC000015E
+
+STATUS_DOMAIN_CTRLR_CONFIG_ERROR
+
+
+A domain server has an incorrect configuration.
+
+0xC000015F
+
+STATUS_FT_MISSING_MEMBER
+
+
+An attempt was made to explicitly access the secondary copy of information via a device control to the fault tolerance driver and the secondary copy is not present in the system.
+
+0xC0000160
+
+STATUS_ILL_FORMED_SERVICE_ENTRY
+
+
+A configuration registry node that represents a driver service entry was ill-formed and did not contain the required value entries.
+
+0xC0000161
+
+STATUS_ILLEGAL_CHARACTER
+
+
+An illegal character was encountered. For a multibyte character set, this includes a lead byte without a succeeding trail byte. For the Unicode character set this includes the characters 0xFFFF and 0xFFFE.
+
+0xC0000162
+
+STATUS_UNMAPPABLE_CHARACTER
+
+
+No mapping for the Unicode character exists in the target multibyte code page.
+
+0xC0000163
+
+STATUS_UNDEFINED_CHARACTER
+
+
+The Unicode character is not defined in the Unicode character set that is installed on the system.
+
+0xC0000164
+
+STATUS_FLOPPY_VOLUME
+
+
+The paging file cannot be created on a floppy disk.
+
+0xC0000165
+
+STATUS_FLOPPY_ID_MARK_NOT_FOUND
+
+
+{Floppy Disk Error} While accessing a floppy disk, an ID address mark was not found.
+
+0xC0000166
+
+STATUS_FLOPPY_WRONG_CYLINDER
+
+
+{Floppy Disk Error} While accessing a floppy disk, the track address from the sector ID field was found to be different from the track address that is maintained by the controller.
+
+0xC0000167
+
+STATUS_FLOPPY_UNKNOWN_ERROR
+
+
+{Floppy Disk Error} The floppy disk controller reported an error that is not recognized by the floppy disk driver.
+
+0xC0000168
+
+STATUS_FLOPPY_BAD_REGISTERS
+
+
+{Floppy Disk Error} While accessing a floppy-disk, the controller returned inconsistent results via its registers.
+
+0xC0000169
+
+STATUS_DISK_RECALIBRATE_FAILED
+
+
+{Hard Disk Error} While accessing the hard disk, a recalibrate operation failed, even after retries.
+
+0xC000016A
+
+STATUS_DISK_OPERATION_FAILED
+
+
+{Hard Disk Error} While accessing the hard disk, a disk operation failed even after retries.
+
+0xC000016B
+
+STATUS_DISK_RESET_FAILED
+
+
+{Hard Disk Error} While accessing the hard disk, a disk controller reset was needed, but even that failed.
+
+0xC000016C
+
+STATUS_SHARED_IRQ_BUSY
+
+
+An attempt was made to open a device that was sharing an interrupt request (IRQ) with other devices. At least one other device that uses that IRQ was already opened. Two concurrent opens of devices that share an IRQ and only work via interrupts is not supported for the particular bus type that the devices use.
+
+0xC000016D
+
+STATUS_FT_ORPHANING
+
+
+{FT Orphaning} A disk that is part of a fault-tolerant volume can no longer be accessed.
+
+0xC000016E
+
+STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT
+
+
+The basic input/output system (BIOS) failed to connect a system interrupt to the device or bus for which the device is connected.
+
+0xC0000172
+
+STATUS_PARTITION_FAILURE
+
+
+The tape could not be partitioned.
+
+0xC0000173
+
+STATUS_INVALID_BLOCK_LENGTH
+
+
+When accessing a new tape of a multi-volume partition, the current blocksize is incorrect.
+
+0xC0000174
+
+STATUS_DEVICE_NOT_PARTITIONED
+
+
+The tape partition information could not be found when loading a tape.
+
+0xC0000175
+
+STATUS_UNABLE_TO_LOCK_MEDIA
+
+
+An attempt to lock the eject media mechanism failed.
+
+0xC0000176
+
+STATUS_UNABLE_TO_UNLOAD_MEDIA
+
+
+An attempt to unload media failed.
+
+0xC0000177
+
+STATUS_EOM_OVERFLOW
+
+
+The physical end of tape was detected.
+
+0xC0000178
+
+STATUS_NO_MEDIA
+
+
+{No Media} There is no media in the drive. Insert media into drive %hs.
+
+0xC000017A
+
+STATUS_NO_SUCH_MEMBER
+
+
+A member could not be added to or removed from the local group because the member does not exist.
+
+0xC000017B
+
+STATUS_INVALID_MEMBER
+
+
+A new member could not be added to a local group because the member has the wrong account type.
+
+0xC000017C
+
+STATUS_KEY_DELETED
+
+
+An illegal operation was attempted on a registry key that has been marked for deletion.
+
+0xC000017D
+
+STATUS_NO_LOG_SPACE
+
+
+The system could not allocate the required space in a registry log.
+
+0xC000017E
+
+STATUS_TOO_MANY_SIDS
+
+
+Too many SIDs have been specified.
+
+0xC000017F
+
+STATUS_LM_CROSS_ENCRYPTION_REQUIRED
+
+
+An attempt was made to change a user password in the security account manager without providing the necessary LM cross-encrypted password.
+
+0xC0000180
+
+STATUS_KEY_HAS_CHILDREN
+
+
+An attempt was made to create a symbolic link in a registry key that already has subkeys or values.
+
+0xC0000181
+
+STATUS_CHILD_MUST_BE_VOLATILE
+
+
+An attempt was made to create a stable subkey under a volatile parent key.
+
+0xC0000182
+
+STATUS_DEVICE_CONFIGURATION_ERROR
+
+
+The I/O device is configured incorrectly or the configuration parameters to the driver are incorrect.
+
+0xC0000183
+
+STATUS_DRIVER_INTERNAL_ERROR
+
+
+An error was detected between two drivers or within an I/O driver.
+
+0xC0000184
+
+STATUS_INVALID_DEVICE_STATE
+
+
+The device is not in a valid state to perform this request.
+
+0xC0000185
+
+STATUS_IO_DEVICE_ERROR
+
+
+The I/O device reported an I/O error.
+
+0xC0000186
+
+STATUS_DEVICE_PROTOCOL_ERROR
+
+
+A protocol error was detected between the driver and the device.
+
+0xC0000187
+
+STATUS_BACKUP_CONTROLLER
+
+
+This operation is only allowed for the primary domain controller of the domain.
+
+0xC0000188
+
+STATUS_LOG_FILE_FULL
+
+
+The log file space is insufficient to support this operation.
+
+0xC0000189
+
+STATUS_TOO_LATE
+
+
+A write operation was attempted to a volume after it was dismounted.
+
+0xC000018A
+
+STATUS_NO_TRUST_LSA_SECRET
+
+
+The workstation does not have a trust secret for the primary domain in the local LSA database.
+
+0xC000018B
+
+STATUS_NO_TRUST_SAM_ACCOUNT
+
+
+On applicable Windows Server releases, the SAM database does not have a computer account for this workstation trust relationship.
+
+0xC000018C
+
+STATUS_TRUSTED_DOMAIN_FAILURE
+
+
+The logon request failed because the trust relationship between the primary domain and the trusted domain failed.
+
+0xC000018D
+
+STATUS_TRUSTED_RELATIONSHIP_FAILURE
+
+
+The logon request failed because the trust relationship between this workstation and the primary domain failed.
+
+0xC000018E
+
+STATUS_EVENTLOG_FILE_CORRUPT
+
+
+The Eventlog log file is corrupt.
+
+0xC000018F
+
+STATUS_EVENTLOG_CANT_START
+
+
+No Eventlog log file could be opened. The Eventlog service did not start.
+
+0xC0000190
+
+STATUS_TRUST_FAILURE
+
+
+The network logon failed. This might be because the validation authority cannot be reached.
+
+0xC0000191
+
+STATUS_MUTANT_LIMIT_EXCEEDED
+
+
+An attempt was made to acquire a mutant such that its maximum count would have been exceeded.
+
+0xC0000192
+
+STATUS_NETLOGON_NOT_STARTED
+
+
+An attempt was made to logon, but the NetLogon service was not started.
+
+0xC0000193
+
+STATUS_ACCOUNT_EXPIRED
+
+
+The user account has expired.
+
+0xC0000194
+
+STATUS_POSSIBLE_DEADLOCK
+
+
+{EXCEPTION} Possible deadlock condition.
+
+0xC0000195
+
+STATUS_NETWORK_CREDENTIAL_CONFLICT
+
+
+Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the server or shared resource and try again.
+
+0xC0000196
+
+STATUS_REMOTE_SESSION_LIMIT
+
+
+An attempt was made to establish a session to a network server, but there are already too many sessions established to that server.
+
+0xC0000197
+
+STATUS_EVENTLOG_FILE_CHANGED
+
+
+The log file has changed between reads.
+
+0xC0000198
+
+STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT
+
+
+The account used is an interdomain trust account. Use your global user account or local user account to access this server.
+
+0xC0000199
+
+STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
+
+
+The account used is a computer account. Use your global user account or local user account to access this server.
+
+0xC000019A
+
+STATUS_NOLOGON_SERVER_TRUST_ACCOUNT
+
+
+The account used is a server trust account. Use your global user account or local user account to access this server.
+
+0xC000019B
+
+STATUS_DOMAIN_TRUST_INCONSISTENT
+
+
+The name or SID of the specified domain is inconsistent with the trust information for that domain.
+
+0xC000019C
+
+STATUS_FS_DRIVER_REQUIRED
+
+
+A volume has been accessed for which a file system driver is required that has not yet been loaded.
+
+0xC000019D
+
+STATUS_IMAGE_ALREADY_LOADED_AS_DLL
+
+
+Indicates that the specified image is already loaded as a DLL.
+
+0xC000019E
+
+STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING
+
+
+Short name settings cannot be changed on this volume due to the global registry setting.
+
+0xC000019F
+
+STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME
+
+
+Short names are not enabled on this volume.
+
+0xC00001A0
+
+STATUS_SECURITY_STREAM_IS_INCONSISTENT
+
+
+The security stream for the given volume is in an inconsistent state. Please run CHKDSK on the volume.
+
+0xC00001A1
+
+STATUS_INVALID_LOCK_RANGE
+
+
+A requested file lock operation cannot be processed due to an invalid byte range.
+
+0xC00001A2
+
+STATUS_INVALID_ACE_CONDITION
+
+
+The specified access control entry (ACE) contains an invalid condition.
+
+0xC00001A3
+
+STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT
+
+
+The subsystem needed to support the image type is not present.
+
+0xC00001A4
+
+STATUS_NOTIFICATION_GUID_ALREADY_DEFINED
+
+
+The specified file already has a notification GUID associated with it.
+
+0xC0000201
+
+STATUS_NETWORK_OPEN_RESTRICTION
+
+
+A remote open failed because the network open restrictions were not satisfied.
+
+0xC0000202
+
+STATUS_NO_USER_SESSION_KEY
+
+
+There is no user session key for the specified logon session.
+
+0xC0000203
+
+STATUS_USER_SESSION_DELETED
+
+
+The remote user session has been deleted.
+
+0xC0000204
+
+STATUS_RESOURCE_LANG_NOT_FOUND
+
+
+Indicates the specified resource language ID cannot be found in the image file.
+
+0xC0000205
+
+STATUS_INSUFF_SERVER_RESOURCES
+
+
+Insufficient server resources exist to complete the request.
+
+0xC0000206
+
+STATUS_INVALID_BUFFER_SIZE
+
+
+The size of the buffer is invalid for the specified operation.
+
+0xC0000207
+
+STATUS_INVALID_ADDRESS_COMPONENT
+
+
+The transport rejected the specified network address as invalid.
+
+0xC0000208
+
+STATUS_INVALID_ADDRESS_WILDCARD
+
+
+The transport rejected the specified network address due to invalid use of a wildcard.
+
+0xC0000209
+
+STATUS_TOO_MANY_ADDRESSES
+
+
+The transport address could not be opened because all the available addresses are in use.
+
+0xC000020A
+
+STATUS_ADDRESS_ALREADY_EXISTS
+
+
+The transport address could not be opened because it already exists.
+
+0xC000020B
+
+STATUS_ADDRESS_CLOSED
+
+
+The transport address is now closed.
+
+0xC000020C
+
+STATUS_CONNECTION_DISCONNECTED
+
+
+The transport connection is now disconnected.
+
+0xC000020D
+
+STATUS_CONNECTION_RESET
+
+
+The transport connection has been reset.
+
+0xC000020E
+
+STATUS_TOO_MANY_NODES
+
+
+The transport cannot dynamically acquire any more nodes.
+
+0xC000020F
+
+STATUS_TRANSACTION_ABORTED
+
+
+The transport aborted a pending transaction.
+
+0xC0000210
+
+STATUS_TRANSACTION_TIMED_OUT
+
+
+The transport timed out a request that is waiting for a response.
+
+0xC0000211
+
+STATUS_TRANSACTION_NO_RELEASE
+
+
+The transport did not receive a release for a pending response.
+
+0xC0000212
+
+STATUS_TRANSACTION_NO_MATCH
+
+
+The transport did not find a transaction that matches the specific token.
+
+0xC0000213
+
+STATUS_TRANSACTION_RESPONDED
+
+
+The transport had previously responded to a transaction request.
+
+0xC0000214
+
+STATUS_TRANSACTION_INVALID_ID
+
+
+The transport does not recognize the specified transaction request ID.
+
+0xC0000215
+
+STATUS_TRANSACTION_INVALID_TYPE
+
+
+The transport does not recognize the specified transaction request type.
+
+0xC0000216
+
+STATUS_NOT_SERVER_SESSION
+
+
+The transport can only process the specified request on the server side of a session.
+
+0xC0000217
+
+STATUS_NOT_CLIENT_SESSION
+
+
+The transport can only process the specified request on the client side of a session.
+
+0xC0000218
+
+STATUS_CANNOT_LOAD_REGISTRY_FILE
+
+
+{Registry File Failure} The registry cannot load the hive (file): %hs or its log or alternate. It is corrupt, absent, or not writable.
+
+0xC0000219
+
+STATUS_DEBUG_ATTACH_FAILED
+
+
+{Unexpected Failure in DebugActiveProcess} An unexpected failure occurred while processing a DebugActiveProcess API request. Choosing OK will terminate the process, and choosing Cancel will ignore the error.
+
+0xC000021A
+
+STATUS_SYSTEM_PROCESS_TERMINATED
+
+
+{Fatal System Error} The %hs system process terminated unexpectedly with a status of 0x%08x (0x%08x 0x%08x). The system has been shut down.
+
+0xC000021B
+
+STATUS_DATA_NOT_ACCEPTED
+
+
+{Data Not Accepted} The TDI client could not handle the data received during an indication.
+
+0xC000021C
+
+STATUS_NO_BROWSER_SERVERS_FOUND
+
+
+{Unable to Retrieve Browser Server List} The list of servers for this workgroup is not currently available.
+
+0xC000021D
+
+STATUS_VDM_HARD_ERROR
+
+
+NTVDM encountered a hard error.
+
+0xC000021E
+
+STATUS_DRIVER_CANCEL_TIMEOUT
+
+
+{Cancel Timeout} The driver %hs failed to complete a canceled I/O request in the allotted time.
+
+0xC000021F
+
+STATUS_REPLY_MESSAGE_MISMATCH
+
+
+{Reply Message Mismatch} An attempt was made to reply to an LPC message, but the thread specified by the client ID in the message was not waiting on that message.
+
+0xC0000220
+
+STATUS_MAPPED_ALIGNMENT
+
+
+{Mapped View Alignment Incorrect} An attempt was made to map a view of a file, but either the specified base address or the offset into the file were not aligned on the proper allocation granularity.
+
+0xC0000221
+
+STATUS_IMAGE_CHECKSUM_MISMATCH
+
+
+{Bad Image Checksum} The image %hs is possibly corrupt. The header checksum does not match the computed checksum.
+
+0xC0000222
+
+STATUS_LOST_WRITEBEHIND_DATA
+
+
+{Delayed Write Failed} Windows was unable to save all the data for the file %hs. The data has been lost. This error might be caused by a failure of your computer hardware or network connection. Try to save this file elsewhere.
+
+0xC0000223
+
+STATUS_CLIENT_SERVER_PARAMETERS_INVALID
+
+
+The parameters passed to the server in the client/server shared memory window were invalid. Too much data might have been put in the shared memory window.
+
+0xC0000224
+
+STATUS_PASSWORD_MUST_CHANGE
+
+
+The user password must be changed before logging on the first time.
+
+0xC0000225
+
+STATUS_NOT_FOUND
+
+
+The object was not found.
+
+0xC0000226
+
+STATUS_NOT_TINY_STREAM
+
+
+The stream is not a tiny stream.
+
+0xC0000227
+
+STATUS_RECOVERY_FAILURE
+
+
+A transaction recovery failed.
+
+0xC0000228
+
+STATUS_STACK_OVERFLOW_READ
+
+
+The request must be handled by the stack overflow code.
+
+0xC0000229
+
+STATUS_FAIL_CHECK
+
+
+A consistency check failed.
+
+0xC000022A
+
+STATUS_DUPLICATE_OBJECTID
+
+
+The attempt to insert the ID in the index failed because the ID is already in the index.
+
+0xC000022B
+
+STATUS_OBJECTID_EXISTS
+
+
+The attempt to set the object ID failed because the object already has an ID.
+
+0xC000022C
+
+STATUS_CONVERT_TO_LARGE
+
+
+Internal OFS status codes indicating how an allocation operation is handled. Either it is retried after the containing oNode is moved or the extent stream is converted to a large stream.
+
+0xC000022D
+
+STATUS_RETRY
+
+
+The request needs to be retried.
+
+0xC000022E
+
+STATUS_FOUND_OUT_OF_SCOPE
+
+
+The attempt to find the object found an object on the volume that matches by ID; however, it is out of the scope of the handle that is used for the operation.
+
+0xC000022F
+
+STATUS_ALLOCATE_BUCKET
+
+
+The bucket array must be grown. Retry the transaction after doing so.
+
+0xC0000230
+
+STATUS_PROPSET_NOT_FOUND
+
+
+The specified property set does not exist on the object.
+
+0xC0000231
+
+STATUS_MARSHALL_OVERFLOW
+
+
+The user/kernel marshaling buffer has overflowed.
+
+0xC0000232
+
+STATUS_INVALID_VARIANT
+
+
+The supplied variant structure contains invalid data.
+
+0xC0000233
+
+STATUS_DOMAIN_CONTROLLER_NOT_FOUND
+
+
+A domain controller for this domain was not found.
+
+0xC0000234
+
+STATUS_ACCOUNT_LOCKED_OUT
+
+
+The user account has been automatically locked because too many invalid logon attempts or password change attempts have been requested.
+
+0xC0000235
+
+STATUS_HANDLE_NOT_CLOSABLE
+
+
+NtClose was called on a handle that was protected from close via NtSetInformationObject.
+
+0xC0000236
+
+STATUS_CONNECTION_REFUSED
+
+
+The transport-connection attempt was refused by the remote system.
+
+0xC0000237
+
+STATUS_GRACEFUL_DISCONNECT
+
+
+The transport connection was gracefully closed.
+
+0xC0000238
+
+STATUS_ADDRESS_ALREADY_ASSOCIATED
+
+
+The transport endpoint already has an address associated with it.
+
+0xC0000239
+
+STATUS_ADDRESS_NOT_ASSOCIATED
+
+
+An address has not yet been associated with the transport endpoint.
+
+0xC000023A
+
+STATUS_CONNECTION_INVALID
+
+
+An operation was attempted on a nonexistent transport connection.
+
+0xC000023B
+
+STATUS_CONNECTION_ACTIVE
+
+
+An invalid operation was attempted on an active transport connection.
+
+0xC000023C
+
+STATUS_NETWORK_UNREACHABLE
+
+
+The remote network is not reachable by the transport.
+
+0xC000023D
+
+STATUS_HOST_UNREACHABLE
+
+
+The remote system is not reachable by the transport.
+
+0xC000023E
+
+STATUS_PROTOCOL_UNREACHABLE
+
+
+The remote system does not support the transport protocol.
+
+0xC000023F
+
+STATUS_PORT_UNREACHABLE
+
+
+No service is operating at the destination port of the transport on the remote system.
+
+0xC0000240
+
+STATUS_REQUEST_ABORTED
+
+
+The request was aborted.
+
+0xC0000241
+
+STATUS_CONNECTION_ABORTED
+
+
+The transport connection was aborted by the local system.
+
+0xC0000242
+
+STATUS_BAD_COMPRESSION_BUFFER
+
+
+The specified buffer contains ill-formed data.
+
+0xC0000243
+
+STATUS_USER_MAPPED_FILE
+
+
+The requested operation cannot be performed on a file with a user mapped section open.
+
+0xC0000244
+
+STATUS_AUDIT_FAILED
+
+
+{Audit Failed} An attempt to generate a security audit failed.
+
+0xC0000245
+
+STATUS_TIMER_RESOLUTION_NOT_SET
+
+
+The timer resolution was not previously set by the current process.
+
+0xC0000246
+
+STATUS_CONNECTION_COUNT_LIMIT
+
+
+A connection to the server could not be made because the limit on the number of concurrent connections for this account has been reached.
+
+0xC0000247
+
+STATUS_LOGIN_TIME_RESTRICTION
+
+
+Attempting to log on during an unauthorized time of day for this account.
+
+0xC0000248
+
+STATUS_LOGIN_WKSTA_RESTRICTION
+
+
+The account is not authorized to log on from this station.
+
+0xC0000249
+
+STATUS_IMAGE_MP_UP_MISMATCH
+
+
+{UP/MP Image Mismatch} The image %hs has been modified for use on a uniprocessor system, but you are running it on a multiprocessor machine. Reinstall the image file.
+
+0xC0000250
+
+STATUS_INSUFFICIENT_LOGON_INFO
+
+
+There is insufficient account information to log you on.
+
+0xC0000251
+
+STATUS_BAD_DLL_ENTRYPOINT
+
+
+{Invalid DLL Entrypoint} The dynamic link library %hs is not written correctly. The stack pointer has been left in an inconsistent state. The entry point should be declared as WINAPI or STDCALL. Select YES to fail the DLL load. Select NO to continue execution. Selecting NO might cause the application to operate incorrectly.
+
+0xC0000252
+
+STATUS_BAD_SERVICE_ENTRYPOINT
+
+
+{Invalid Service Callback Entrypoint} The %hs service is not written correctly. The stack pointer has been left in an inconsistent state. The callback entry point should be declared as WINAPI or STDCALL. Selecting OK will cause the service to continue operation. However, the service process might operate incorrectly.
+
+0xC0000253
+
+STATUS_LPC_REPLY_LOST
+
+
+The server received the messages but did not send a reply.
+
+0xC0000254
+
+STATUS_IP_ADDRESS_CONFLICT1
+
+
+There is an IP address conflict with another system on the network.
+
+0xC0000255
+
+STATUS_IP_ADDRESS_CONFLICT2
+
+
+There is an IP address conflict with another system on the network.
+
+0xC0000256
+
+STATUS_REGISTRY_QUOTA_LIMIT
+
+
+{Low On Registry Space} The system has reached the maximum size that is allowed for the system part of the registry. Additional storage requests will be ignored.
+
+0xC0000257
+
+STATUS_PATH_NOT_COVERED
+
+
+The contacted server does not support the indicated part of the DFS namespace.
+
+0xC0000258
+
+STATUS_NO_CALLBACK_ACTIVE
+
+
+A callback return system service cannot be executed when no callback is active.
+
+0xC0000259
+
+STATUS_LICENSE_QUOTA_EXCEEDED
+
+
+The service being accessed is licensed for a particular number of connections. No more connections can be made to the service at this time because the service has already accepted the maximum number of connections.
+
+0xC000025A
+
+STATUS_PWD_TOO_SHORT
+
+
+The password provided is too short to meet the policy of your user account. Choose a longer password.
+
+0xC000025B
+
+STATUS_PWD_TOO_RECENT
+
+
+The policy of your user account does not allow you to change passwords too frequently. This is done to prevent users from changing back to a familiar, but potentially discovered, password. If you feel your password has been compromised, contact your administrator immediately to have a new one assigned.
+
+0xC000025C
+
+STATUS_PWD_HISTORY_CONFLICT
+
+
+You have attempted to change your password to one that you have used in the past. The policy of your user account does not allow this. Select a password that you have not previously used.
+
+0xC000025E
+
+STATUS_PLUGPLAY_NO_DEVICE
+
+
+You have attempted to load a legacy device driver while its device instance had been disabled.
+
+0xC000025F
+
+STATUS_UNSUPPORTED_COMPRESSION
+
+
+The specified compression format is unsupported.
+
+0xC0000260
+
+STATUS_INVALID_HW_PROFILE
+
+
+The specified hardware profile configuration is invalid.
+
+0xC0000261
+
+STATUS_INVALID_PLUGPLAY_DEVICE_PATH
+
+
+The specified Plug and Play registry device path is invalid.
+
+0xC0000262
+
+STATUS_DRIVER_ORDINAL_NOT_FOUND
+
+
+{Driver Entry Point Not Found} The %hs device driver could not locate the ordinal %ld in driver %hs.
+
+0xC0000263
+
+STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
+
+
+{Driver Entry Point Not Found} The %hs device driver could not locate the entry point %hs in driver %hs.
+
+0xC0000264
+
+STATUS_RESOURCE_NOT_OWNED
+
+
+{Application Error} The application attempted to release a resource it did not own. Click OK to terminate the application.
+
+0xC0000265
+
+STATUS_TOO_MANY_LINKS
+
+
+An attempt was made to create more links on a file than the file system supports.
+
+0xC0000266
+
+STATUS_QUOTA_LIST_INCONSISTENT
+
+
+The specified quota list is internally inconsistent with its descriptor.
+
+0xC0000267
+
+STATUS_FILE_IS_OFFLINE
+
+
+The specified file has been relocated to offline storage.
+
+0xC0000268
+
+STATUS_EVALUATION_EXPIRATION
+
+
+{Windows Evaluation Notification} The evaluation period for this installation of Windows has expired. This system will shutdown in 1 hour. To restore access to this installation of Windows, upgrade this installation by using a licensed distribution of this product.
+
+0xC0000269
+
+STATUS_ILLEGAL_DLL_RELOCATION
+
+
+{Illegal System DLL Relocation} The system DLL %hs was relocated in memory. The application will not run properly. The relocation occurred because the DLL %hs occupied an address range that is reserved for Windows system DLLs. The vendor supplying the DLL should be contacted for a new DLL.
+
+0xC000026A
+
+STATUS_LICENSE_VIOLATION
+
+
+{License Violation} The system has detected tampering with your registered product type. This is a violation of your software license. Tampering with the product type is not permitted.
+
+0xC000026B
+
+STATUS_DLL_INIT_FAILED_LOGOFF
+
+
+{DLL Initialization Failed} The application failed to initialize because the window station is shutting down.
+
+0xC000026C
+
+STATUS_DRIVER_UNABLE_TO_LOAD
+
+
+{Unable to Load Device Driver} %hs device driver could not be loaded. Error Status was 0x%x.
+
+0xC000026D
+
+STATUS_DFS_UNAVAILABLE
+
+
+DFS is unavailable on the contacted server.
+
+0xC000026E
+
+STATUS_VOLUME_DISMOUNTED
+
+
+An operation was attempted to a volume after it was dismounted.
+
+0xC000026F
+
+STATUS_WX86_INTERNAL_ERROR
+
+
+An internal error occurred in the Win32 x86 emulation subsystem.
+
+0xC0000270
+
+STATUS_WX86_FLOAT_STACK_CHECK
+
+
+Win32 x86 emulation subsystem floating-point stack check.
+
+0xC0000271
+
+STATUS_VALIDATE_CONTINUE
+
+
+The validation process needs to continue on to the next step.
+
+0xC0000272
+
+STATUS_NO_MATCH
+
+
+There was no match for the specified key in the index.
+
+0xC0000273
+
+STATUS_NO_MORE_MATCHES
+
+
+There are no more matches for the current index enumeration.
+
+0xC0000275
+
+STATUS_NOT_A_REPARSE_POINT
+
+
+The NTFS file or directory is not a reparse point.
+
+0xC0000276
+
+STATUS_IO_REPARSE_TAG_INVALID
+
+
+The Windows I/O reparse tag passed for the NTFS reparse point is invalid.
+
+0xC0000277
+
+STATUS_IO_REPARSE_TAG_MISMATCH
+
+
+The Windows I/O reparse tag does not match the one that is in the NTFS reparse point.
+
+0xC0000278
+
+STATUS_IO_REPARSE_DATA_INVALID
+
+
+The user data passed for the NTFS reparse point is invalid.
+
+0xC0000279
+
+STATUS_IO_REPARSE_TAG_NOT_HANDLED
+
+
+The layered file system driver for this I/O tag did not handle it when needed.
+
+0xC0000280
+
+STATUS_REPARSE_POINT_NOT_RESOLVED
+
+
+The NTFS symbolic link could not be resolved even though the initial file name is valid.
+
+0xC0000281
+
+STATUS_DIRECTORY_IS_A_REPARSE_POINT
+
+
+The NTFS directory is a reparse point.
+
+0xC0000282
+
+STATUS_RANGE_LIST_CONFLICT
+
+
+The range could not be added to the range list because of a conflict.
+
+0xC0000283
+
+STATUS_SOURCE_ELEMENT_EMPTY
+
+
+The specified medium changer source element contains no media.
+
+0xC0000284
+
+STATUS_DESTINATION_ELEMENT_FULL
+
+
+The specified medium changer destination element already contains media.
+
+0xC0000285
+
+STATUS_ILLEGAL_ELEMENT_ADDRESS
+
+
+The specified medium changer element does not exist.
+
+0xC0000286
+
+STATUS_MAGAZINE_NOT_PRESENT
+
+
+The specified element is contained in a magazine that is no longer present.
+
+0xC0000287
+
+STATUS_REINITIALIZATION_NEEDED
+
+
+The device requires re-initialization due to hardware errors.
+
+0xC000028A
+
+STATUS_ENCRYPTION_FAILED
+
+
+The file encryption attempt failed.
+
+0xC000028B
+
+STATUS_DECRYPTION_FAILED
+
+
+The file decryption attempt failed.
+
+0xC000028C
+
+STATUS_RANGE_NOT_FOUND
+
+
+The specified range could not be found in the range list.
+
+0xC000028D
+
+STATUS_NO_RECOVERY_POLICY
+
+
+There is no encryption recovery policy configured for this system.
+
+0xC000028E
+
+STATUS_NO_EFS
+
+
+The required encryption driver is not loaded for this system.
+
+0xC000028F
+
+STATUS_WRONG_EFS
+
+
+The file was encrypted with a different encryption driver than is currently loaded.
+
+0xC0000290
+
+STATUS_NO_USER_KEYS
+
+
+There are no EFS keys defined for the user.
+
+0xC0000291
+
+STATUS_FILE_NOT_ENCRYPTED
+
+
+The specified file is not encrypted.
+
+0xC0000292
+
+STATUS_NOT_EXPORT_FORMAT
+
+
+The specified file is not in the defined EFS export format.
+
+0xC0000293
+
+STATUS_FILE_ENCRYPTED
+
+
+The specified file is encrypted and the user does not have the ability to decrypt it.
+
+0xC0000295
+
+STATUS_WMI_GUID_NOT_FOUND
+
+
+The GUID passed was not recognized as valid by a WMI data provider.
+
+0xC0000296
+
+STATUS_WMI_INSTANCE_NOT_FOUND
+
+
+The instance name passed was not recognized as valid by a WMI data provider.
+
+0xC0000297
+
+STATUS_WMI_ITEMID_NOT_FOUND
+
+
+The data item ID passed was not recognized as valid by a WMI data provider.
+
+0xC0000298
+
+STATUS_WMI_TRY_AGAIN
+
+
+The WMI request could not be completed and should be retried.
+
+0xC0000299
+
+STATUS_SHARED_POLICY
+
+
+The policy object is shared and can only be modified at the root.
+
+0xC000029A
+
+STATUS_POLICY_OBJECT_NOT_FOUND
+
+
+The policy object does not exist when it should.
+
+0xC000029B
+
+STATUS_POLICY_ONLY_IN_DS
+
+
+The requested policy information only lives in the Ds.
+
+0xC000029C
+
+STATUS_VOLUME_NOT_UPGRADED
+
+
+The volume must be upgraded to enable this feature.
+
+0xC000029D
+
+STATUS_REMOTE_STORAGE_NOT_ACTIVE
+
+
+The remote storage service is not operational at this time.
+
+0xC000029E
+
+STATUS_REMOTE_STORAGE_MEDIA_ERROR
+
+
+The remote storage service encountered a media error.
+
+0xC000029F
+
+STATUS_NO_TRACKING_SERVICE
+
+
+The tracking (workstation) service is not running.
+
+0xC00002A0
+
+STATUS_SERVER_SID_MISMATCH
+
+
+The server process is running under a SID that is different from the SID that is required by client.
+
+0xC00002A1
+
+STATUS_DS_NO_ATTRIBUTE_OR_VALUE
+
+
+The specified directory service attribute or value does not exist.
+
+0xC00002A2
+
+STATUS_DS_INVALID_ATTRIBUTE_SYNTAX
+
+
+The attribute syntax specified to the directory service is invalid.
+
+0xC00002A3
+
+STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED
+
+
+The attribute type specified to the directory service is not defined.
+
+0xC00002A4
+
+STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS
+
+
+The specified directory service attribute or value already exists.
+
+0xC00002A5
+
+STATUS_DS_BUSY
+
+
+The directory service is busy.
+
+0xC00002A6
+
+STATUS_DS_UNAVAILABLE
+
+
+The directory service is unavailable.
+
+0xC00002A7
+
+STATUS_DS_NO_RIDS_ALLOCATED
+
+
+The directory service was unable to allocate a relative identifier.
+
+0xC00002A8
+
+STATUS_DS_NO_MORE_RIDS
+
+
+The directory service has exhausted the pool of relative identifiers.
+
+0xC00002A9
+
+STATUS_DS_INCORRECT_ROLE_OWNER
+
+
+The requested operation could not be performed because the directory service is not the master for that type of operation.
+
+0xC00002AA
+
+STATUS_DS_RIDMGR_INIT_ERROR
+
+
+The directory service was unable to initialize the subsystem that allocates relative identifiers.
+
+0xC00002AB
+
+STATUS_DS_OBJ_CLASS_VIOLATION
+
+
+The requested operation did not satisfy one or more constraints that are associated with the class of the object.
+
+0xC00002AC
+
+STATUS_DS_CANT_ON_NON_LEAF
+
+
+The directory service can perform the requested operation only on a leaf object.
+
+0xC00002AD
+
+STATUS_DS_CANT_ON_RDN
+
+
+The directory service cannot perform the requested operation on the Relatively Defined Name (RDN) attribute of an object.
+
+0xC00002AE
+
+STATUS_DS_CANT_MOD_OBJ_CLASS
+
+
+The directory service detected an attempt to modify the object class of an object.
+
+0xC00002AF
+
+STATUS_DS_CROSS_DOM_MOVE_FAILED
+
+
+An error occurred while performing a cross domain move operation.
+
+0xC00002B0
+
+STATUS_DS_GC_NOT_AVAILABLE
+
+
+Unable to contact the global catalog server.
+
+0xC00002B1
+
+STATUS_DIRECTORY_SERVICE_REQUIRED
+
+
+The requested operation requires a directory service, and none was available.
+
+0xC00002B2
+
+STATUS_REPARSE_ATTRIBUTE_CONFLICT
+
+
+The reparse attribute cannot be set because it is incompatible with an existing attribute.
+
+0xC00002B3
+
+STATUS_CANT_ENABLE_DENY_ONLY
+
+
+A group marked "use for deny only" cannot be enabled.
+
+0xC00002B4
+
+STATUS_FLOAT_MULTIPLE_FAULTS
+
+
+{EXCEPTION} Multiple floating-point faults.
+
+0xC00002B5
+
+STATUS_FLOAT_MULTIPLE_TRAPS
+
+
+{EXCEPTION} Multiple floating-point traps.
+
+0xC00002B6
+
+STATUS_DEVICE_REMOVED
+
+
+The device has been removed.
+
+0xC00002B7
+
+STATUS_JOURNAL_DELETE_IN_PROGRESS
+
+
+The volume change journal is being deleted.
+
+0xC00002B8
+
+STATUS_JOURNAL_NOT_ACTIVE
+
+
+The volume change journal is not active.
+
+0xC00002B9
+
+STATUS_NOINTERFACE
+
+
+The requested interface is not supported.
+
+0xC00002C1
+
+STATUS_DS_ADMIN_LIMIT_EXCEEDED
+
+
+A directory service resource limit has been exceeded.
+
+0xC00002C2
+
+STATUS_DRIVER_FAILED_SLEEP
+
+
+{System Standby Failed} The driver %hs does not support standby mode. Updating this driver allows the system to go to standby mode.
+
+0xC00002C3
+
+STATUS_MUTUAL_AUTHENTICATION_FAILED
+
+
+Mutual Authentication failed. The server password is out of date at the domain controller.
+
+0xC00002C4
+
+STATUS_CORRUPT_SYSTEM_FILE
+
+
+The system file %1 has become corrupt and has been replaced.
+
+0xC00002C5
+
+STATUS_DATATYPE_MISALIGNMENT_ERROR
+
+
+{EXCEPTION} Alignment Error A data type misalignment error was detected in a load or store instruction.
+
+0xC00002C6
+
+STATUS_WMI_READ_ONLY
+
+
+The WMI data item or data block is read-only.
+
+0xC00002C7
+
+STATUS_WMI_SET_FAILURE
+
+
+The WMI data item or data block could not be changed.
+
+0xC00002C8
+
+STATUS_COMMITMENT_MINIMUM
+
+
+{Virtual Memory Minimum Too Low} Your system is low on virtual memory. Windows is increasing the size of your virtual memory paging file. During this process, memory requests for some applications might be denied. For more information, see Help.
+
+0xC00002C9
+
+STATUS_REG_NAT_CONSUMPTION
+
+
+{EXCEPTION} Register NaT consumption faults. A NaT value is consumed on a non-speculative instruction.
+
+0xC00002CA
+
+STATUS_TRANSPORT_FULL
+
+
+The transport element of the medium changer contains media, which is causing the operation to fail.
+
+0xC00002CB
+
+STATUS_DS_SAM_INIT_FAILURE
+
+
+Security Accounts Manager initialization failed because of the following error: %hs Error Status: 0x%x. Click OK to shut down this system and restart in Directory Services Restore Mode. Check the event log for more detailed information.
+
+0xC00002CC
+
+STATUS_ONLY_IF_CONNECTED
+
+
+This operation is supported only when you are connected to the server.
+
+0xC00002CD
+
+STATUS_DS_SENSITIVE_GROUP_VIOLATION
+
+
+Only an administrator can modify the membership list of an administrative group.
+
+0xC00002CE
+
+STATUS_PNP_RESTART_ENUMERATION
+
+
+A device was removed so enumeration must be restarted.
+
+0xC00002CF
+
+STATUS_JOURNAL_ENTRY_DELETED
+
+
+The journal entry has been deleted from the journal.
+
+0xC00002D0
+
+STATUS_DS_CANT_MOD_PRIMARYGROUPID
+
+
+Cannot change the primary group ID of a domain controller account.
+
+0xC00002D1
+
+STATUS_SYSTEM_IMAGE_BAD_SIGNATURE
+
+
+{Fatal System Error} The system image %s is not properly signed. The file has been replaced with the signed file. The system has been shut down.
+
+0xC00002D2
+
+STATUS_PNP_REBOOT_REQUIRED
+
+
+The device will not start without a reboot.
+
+0xC00002D3
+
+STATUS_POWER_STATE_INVALID
+
+
+The power state of the current device cannot support this request.
+
+0xC00002D4
+
+STATUS_DS_INVALID_GROUP_TYPE
+
+
+The specified group type is invalid.
+
+0xC00002D5
+
+STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN
+
+
+In a mixed domain, no nesting of a global group if the group is security enabled.
+
+0xC00002D6
+
+STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN
+
+
+In a mixed domain, cannot nest local groups with other local groups, if the group is security enabled.
+
+0xC00002D7
+
+STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER
+
+
+A global group cannot have a local group as a member.
+
+0xC00002D8
+
+STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER
+
+
+A global group cannot have a universal group as a member.
+
+0xC00002D9
+
+STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER
+
+
+A universal group cannot have a local group as a member.
+
+0xC00002DA
+
+STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER
+
+
+A global group cannot have a cross-domain member.
+
+0xC00002DB
+
+STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER
+
+
+A local group cannot have another cross-domain local group as a member.
+
+0xC00002DC
+
+STATUS_DS_HAVE_PRIMARY_MEMBERS
+
+
+Cannot change to a security-disabled group because primary members are in this group.
+
+0xC00002DD
+
+STATUS_WMI_NOT_SUPPORTED
+
+
+The WMI operation is not supported by the data block or method.
+
+0xC00002DE
+
+STATUS_INSUFFICIENT_POWER
+
+
+There is not enough power to complete the requested operation.
+
+0xC00002DF
+
+STATUS_SAM_NEED_BOOTKEY_PASSWORD
+
+
+The Security Accounts Manager needs to get the boot password.
+
+0xC00002E0
+
+STATUS_SAM_NEED_BOOTKEY_FLOPPY
+
+
+The Security Accounts Manager needs to get the boot key from the floppy disk.
+
+0xC00002E1
+
+STATUS_DS_CANT_START
+
+
+The directory service cannot start.
+
+0xC00002E2
+
+STATUS_DS_INIT_FAILURE
+
+
+The directory service could not start because of the following error: %hs Error Status: 0x%x. Click OK to shut down this system and restart in Directory Services Restore Mode. Check the event log for more detailed information.
+
+0xC00002E3
+
+STATUS_SAM_INIT_FAILURE
+
+
+The Security Accounts Manager initialization failed because of the following error: %hs Error Status: 0x%x. Click OK to shut down this system and restart in Safe Mode. Check the event log for more detailed information.
+
+0xC00002E4
+
+STATUS_DS_GC_REQUIRED
+
+
+The requested operation can be performed only on a global catalog server.
+
+0xC00002E5
+
+STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY
+
+
+A local group can only be a member of other local groups in the same domain.
+
+0xC00002E6
+
+STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS
+
+
+Foreign security principals cannot be members of universal groups.
+
+0xC00002E7
+
+STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED
+
+
+Your computer could not be joined to the domain. You have exceeded the maximum number of computer accounts you are allowed to create in this domain. Contact your system administrator to have this limit reset or increased.
+
+0xC00002E9
+
+STATUS_CURRENT_DOMAIN_NOT_ALLOWED
+
+
+This operation cannot be performed on the current domain.
+
+0xC00002EA
+
+STATUS_CANNOT_MAKE
+
+
+The directory or file cannot be created.
+
+0xC00002EB
+
+STATUS_SYSTEM_SHUTDOWN
+
+
+The system is in the process of shutting down.
+
+0xC00002EC
+
+STATUS_DS_INIT_FAILURE_CONSOLE
+
+
+Directory Services could not start because of the following error: %hs Error Status: 0x%x. Click OK to shut down the system. You can use the recovery console to diagnose the system further.
+
+0xC00002ED
+
+STATUS_DS_SAM_INIT_FAILURE_CONSOLE
+
+
+Security Accounts Manager initialization failed because of the following error: %hs Error Status: 0x%x. Click OK to shut down the system. You can use the recovery console to diagnose the system further.
+
+0xC00002EE
+
+STATUS_UNFINISHED_CONTEXT_DELETED
+
+
+A security context was deleted before the context was completed. This is considered a logon failure.
+
+0xC00002EF
+
+STATUS_NO_TGT_REPLY
+
+
+The client is trying to negotiate a context and the server requires user-to-user but did not send a TGT reply.
+
+0xC00002F0
+
+STATUS_OBJECTID_NOT_FOUND
+
+
+An object ID was not found in the file.
+
+0xC00002F1
+
+STATUS_NO_IP_ADDRESSES
+
+
+Unable to accomplish the requested task because the local machine does not have any IP addresses.
+
+0xC00002F2
+
+STATUS_WRONG_CREDENTIAL_HANDLE
+
+
+The supplied credential handle does not match the credential that is associated with the security context.
+
+0xC00002F3
+
+STATUS_CRYPTO_SYSTEM_INVALID
+
+
+The crypto system or checksum function is invalid because a required function is unavailable.
+
+0xC00002F4
+
+STATUS_MAX_REFERRALS_EXCEEDED
+
+
+The number of maximum ticket referrals has been exceeded.
+
+0xC00002F5
+
+STATUS_MUST_BE_KDC
+
+
+The local machine must be a Kerberos KDC (domain controller) and it is not.
+
+0xC00002F6
+
+STATUS_STRONG_CRYPTO_NOT_SUPPORTED
+
+
+The other end of the security negotiation requires strong crypto but it is not supported on the local machine.
+
+0xC00002F7
+
+STATUS_TOO_MANY_PRINCIPALS
+
+
+The KDC reply contained more than one principal name.
+
+0xC00002F8
+
+STATUS_NO_PA_DATA
+
+
+Expected to find PA data for a hint of what etype to use, but it was not found.
+
+0xC00002F9
+
+STATUS_PKINIT_NAME_MISMATCH
+
+
+The client certificate does not contain a valid UPN, or does not match the client name in the logon request. Contact your administrator.
+
+0xC00002FA
+
+STATUS_SMARTCARD_LOGON_REQUIRED
+
+
+Smart card logon is required and was not used.
+
+0xC00002FB
+
+STATUS_KDC_INVALID_REQUEST
+
+
+An invalid request was sent to the KDC.
+
+0xC00002FC
+
+STATUS_KDC_UNABLE_TO_REFER
+
+
+The KDC was unable to generate a referral for the service requested.
+
+0xC00002FD
+
+STATUS_KDC_UNKNOWN_ETYPE
+
+
+The encryption type requested is not supported by the KDC.
+
+0xC00002FE
+
+STATUS_SHUTDOWN_IN_PROGRESS
+
+
+A system shutdown is in progress.
+
+0xC00002FF
+
+STATUS_SERVER_SHUTDOWN_IN_PROGRESS
+
+
+The server machine is shutting down.
+
+0xC0000300
+
+STATUS_NOT_SUPPORTED_ON_SBS
+
+
+This operation is not supported on a computer running Windows Server 2003 operating system for Small Business Server.
+
+0xC0000301
+
+STATUS_WMI_GUID_DISCONNECTED
+
+
+The WMI GUID is no longer available.
+
+0xC0000302
+
+STATUS_WMI_ALREADY_DISABLED
+
+
+Collection or events for the WMI GUID is already disabled.
+
+0xC0000303
+
+STATUS_WMI_ALREADY_ENABLED
+
+
+Collection or events for the WMI GUID is already enabled.
+
+0xC0000304
+
+STATUS_MFT_TOO_FRAGMENTED
+
+
+The master file table on the volume is too fragmented to complete this operation.
+
+0xC0000305
+
+STATUS_COPY_PROTECTION_FAILURE
+
+
+Copy protection failure.
+
+0xC0000306
+
+STATUS_CSS_AUTHENTICATION_FAILURE
+
+
+Copy protection error—DVD CSS Authentication failed.
+
+0xC0000307
+
+STATUS_CSS_KEY_NOT_PRESENT
+
+
+Copy protection error—The specified sector does not contain a valid key.
+
+0xC0000308
+
+STATUS_CSS_KEY_NOT_ESTABLISHED
+
+
+Copy protection error—DVD session key not established.
+
+0xC0000309
+
+STATUS_CSS_SCRAMBLED_SECTOR
+
+
+Copy protection error—The read failed because the sector is encrypted.
+
+0xC000030A
+
+STATUS_CSS_REGION_MISMATCH
+
+
+Copy protection error—The region of the specified DVD does not correspond to the region setting of the drive.
+
+0xC000030B
+
+STATUS_CSS_RESETS_EXHAUSTED
+
+
+Copy protection error—The region setting of the drive might be permanent.
+
+0xC0000320
+
+STATUS_PKINIT_FAILURE
+
+
+The Kerberos protocol encountered an error while validating the KDC certificate during smart card logon. There is more information in the system event log.
+
+0xC0000321
+
+STATUS_SMARTCARD_SUBSYSTEM_FAILURE
+
+
+The Kerberos protocol encountered an error while attempting to use the smart card subsystem.
+
+0xC0000322
+
+STATUS_NO_KERB_KEY
+
+
+The target server does not have acceptable Kerberos credentials.
+
+0xC0000350
+
+STATUS_HOST_DOWN
+
+
+The transport determined that the remote system is down.
+
+0xC0000351
+
+STATUS_UNSUPPORTED_PREAUTH
+
+
+An unsupported pre-authentication mechanism was presented to the Kerberos package.
+
+0xC0000352
+
+STATUS_EFS_ALG_BLOB_TOO_BIG
+
+
+The encryption algorithm that is used on the source file needs a bigger key buffer than the one that is used on the destination file.
+
+0xC0000353
+
+STATUS_PORT_NOT_SET
+
+
+An attempt to remove a processes DebugPort was made, but a port was not already associated with the process.
+
+0xC0000354
+
+STATUS_DEBUGGER_INACTIVE
+
+
+An attempt to do an operation on a debug port failed because the port is in the process of being deleted.
+
+0xC0000355
+
+STATUS_DS_VERSION_CHECK_FAILURE
+
+
+This version of Windows is not compatible with the behavior version of the directory forest, domain, or domain controller.
+
+0xC0000356
+
+STATUS_AUDITING_DISABLED
+
+
+The specified event is currently not being audited.
+
+0xC0000357
+
+STATUS_PRENT4_MACHINE_ACCOUNT
+
+
+The machine account was created prior to Windows NT 4.0 operating system. The account needs to be recreated.
+
+0xC0000358
+
+STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER
+
+
+An account group cannot have a universal group as a member.
+
+0xC0000359
+
+STATUS_INVALID_IMAGE_WIN_32
+
+
+The specified image file did not have the correct format; it appears to be a 32-bit Windows image.
+
+0xC000035A
+
+STATUS_INVALID_IMAGE_WIN_64
+
+
+The specified image file did not have the correct format; it appears to be a 64-bit Windows image.
+
+0xC000035B
+
+STATUS_BAD_BINDINGS
+
+
+The client's supplied SSPI channel bindings were incorrect.
+
+0xC000035C
+
+STATUS_NETWORK_SESSION_EXPIRED
+
+
+The client session has expired; so the client must re-authenticate to continue accessing the remote resources.
+
+0xC000035D
+
+STATUS_APPHELP_BLOCK
+
+
+The AppHelp dialog box canceled; thus preventing the application from starting.
+
+0xC000035E
+
+STATUS_ALL_SIDS_FILTERED
+
+
+The SID filtering operation removed all SIDs.
+
+0xC000035F
+
+STATUS_NOT_SAFE_MODE_DRIVER
+
+
+The driver was not loaded because the system is starting in safe mode.
+
+0xC0000361
+
+STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT
+
+
+Access to %1 has been restricted by your Administrator by the default software restriction policy level.
+
+0xC0000362
+
+STATUS_ACCESS_DISABLED_BY_POLICY_PATH
+
+
+Access to %1 has been restricted by your Administrator by location with policy rule %2 placed on path %3.
+
+0xC0000363
+
+STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER
+
+
+Access to %1 has been restricted by your Administrator by software publisher policy.
+
+0xC0000364
+
+STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
+
+
+Access to %1 has been restricted by your Administrator by policy rule %2.
+
+0xC0000365
+
+STATUS_FAILED_DRIVER_ENTRY
+
+
+The driver was not loaded because it failed its initialization call.
+
+0xC0000366
+
+STATUS_DEVICE_ENUMERATION_ERROR
+
+
+The device encountered an error while applying power or reading the device configuration. This might be caused by a failure of your hardware or by a poor connection.
+
+0xC0000368
+
+STATUS_MOUNT_POINT_NOT_RESOLVED
+
+
+The create operation failed because the name contained at least one mount point that resolves to a volume to which the specified device object is not attached.
+
+0xC0000369
+
+STATUS_INVALID_DEVICE_OBJECT_PARAMETER
+
+
+The device object parameter is either not a valid device object or is not attached to the volume that is specified by the file name.
+
+0xC000036A
+
+STATUS_MCA_OCCURED
+
+
+A machine check error has occurred. Check the system event log for additional information.
+
+0xC000036B
+
+STATUS_DRIVER_BLOCKED_CRITICAL
+
+
+Driver %2 has been blocked from loading.
+
+0xC000036C
+
+STATUS_DRIVER_BLOCKED
+
+
+Driver %2 has been blocked from loading.
+
+0xC000036D
+
+STATUS_DRIVER_DATABASE_ERROR
+
+
+There was error [%2] processing the driver database.
+
+0xC000036E
+
+STATUS_SYSTEM_HIVE_TOO_LARGE
+
+
+System hive size has exceeded its limit.
+
+0xC000036F
+
+STATUS_INVALID_IMPORT_OF_NON_DLL
+
+
+A dynamic link library (DLL) referenced a module that was neither a DLL nor the process's executable image.
+
+0xC0000371
+
+STATUS_NO_SECRETS
+
+
+The local account store does not contain secret material for the specified account.
+
+0xC0000372
+
+STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY
+
+
+Access to %1 has been restricted by your Administrator by policy rule %2.
+
+0xC0000373
+
+STATUS_FAILED_STACK_SWITCH
+
+
+The system was not able to allocate enough memory to perform a stack switch.
+
+0xC0000374
+
+STATUS_HEAP_CORRUPTION
+
+
+A heap has been corrupted.
+
+0xC0000380
+
+STATUS_SMARTCARD_WRONG_PIN
+
+
+An incorrect PIN was presented to the smart card.
+
+0xC0000381
+
+STATUS_SMARTCARD_CARD_BLOCKED
+
+
+The smart card is blocked.
+
+0xC0000382
+
+STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED
+
+
+No PIN was presented to the smart card.
+
+0xC0000383
+
+STATUS_SMARTCARD_NO_CARD
+
+
+No smart card is available.
+
+0xC0000384
+
+STATUS_SMARTCARD_NO_KEY_CONTAINER
+
+
+The requested key container does not exist on the smart card.
+
+0xC0000385
+
+STATUS_SMARTCARD_NO_CERTIFICATE
+
+
+The requested certificate does not exist on the smart card.
+
+0xC0000386
+
+STATUS_SMARTCARD_NO_KEYSET
+
+
+The requested keyset does not exist.
+
+0xC0000387
+
+STATUS_SMARTCARD_IO_ERROR
+
+
+A communication error with the smart card has been detected.
+
+0xC0000388
+
+STATUS_DOWNGRADE_DETECTED
+
+
+The system detected a possible attempt to compromise security. Ensure that you can contact the server that authenticated you.
+
+0xC0000389
+
+STATUS_SMARTCARD_CERT_REVOKED
+
+
+The smart card certificate used for authentication has been revoked. Contact your system administrator. There might be additional information in the event log.
+
+0xC000038A
+
+STATUS_ISSUING_CA_UNTRUSTED
+
+
+An untrusted certificate authority was detected while processing the smart card certificate that is used for authentication. Contact your system administrator.
+
+0xC000038B
+
+STATUS_REVOCATION_OFFLINE_C
+
+
+The revocation status of the smart card certificate that is used for authentication could not be determined. Contact your system administrator.
+
+0xC000038C
+
+STATUS_PKINIT_CLIENT_FAILURE
+
+
+The smart card certificate used for authentication was not trusted. Contact your system administrator.
+
+0xC000038D
+
+STATUS_SMARTCARD_CERT_EXPIRED
+
+
+The smart card certificate used for authentication has expired. Contact your system administrator.
+
+0xC000038E
+
+STATUS_DRIVER_FAILED_PRIOR_UNLOAD
+
+
+The driver could not be loaded because a previous version of the driver is still in memory.
+
+0xC000038F
+
+STATUS_SMARTCARD_SILENT_CONTEXT
+
+
+The smart card provider could not perform the action because the context was acquired as silent.
+
+0xC0000401
+
+STATUS_PER_USER_TRUST_QUOTA_EXCEEDED
+
+
+The delegated trust creation quota of the current user has been exceeded.
+
+0xC0000402
+
+STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED
+
+
+The total delegated trust creation quota has been exceeded.
+
+0xC0000403
+
+STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED
+
+
+The delegated trust deletion quota of the current user has been exceeded.
+
+0xC0000404
+
+STATUS_DS_NAME_NOT_UNIQUE
+
+
+The requested name already exists as a unique identifier.
+
+0xC0000405
+
+STATUS_DS_DUPLICATE_ID_FOUND
+
+
+The requested object has a non-unique identifier and cannot be retrieved.
+
+0xC0000406
+
+STATUS_DS_GROUP_CONVERSION_ERROR
+
+
+The group cannot be converted due to attribute restrictions on the requested group type.
+
+0xC0000407
+
+STATUS_VOLSNAP_PREPARE_HIBERNATE
+
+
+{Volume Shadow Copy Service} Wait while the Volume Shadow Copy Service prepares volume %hs for hibernation.
+
+0xC0000408
+
+STATUS_USER2USER_REQUIRED
+
+
+Kerberos sub-protocol User2User is required.
+
+0xC0000409
+
+STATUS_STACK_BUFFER_OVERRUN
+
+
+The system detected an overrun of a stack-based buffer in this application. This overrun could potentially allow a malicious user to gain control of this application.
+
+0xC000040A
+
+STATUS_NO_S4U_PROT_SUPPORT
+
+
+The Kerberos subsystem encountered an error. A service for user protocol request was made against a domain controller which does not support service for user.
+
+0xC000040B
+
+STATUS_CROSSREALM_DELEGATION_FAILURE
+
+
+An attempt was made by this server to make a Kerberos constrained delegation request for a target that is outside the server realm. This action is not supported and the resulting error indicates a misconfiguration on the allowed-to-delegate-to list for this server. Contact your administrator.
+
+0xC000040C
+
+STATUS_REVOCATION_OFFLINE_KDC
+
+
+The revocation status of the domain controller certificate used for smart card authentication could not be determined. There is additional information in the system event log. Contact your system administrator.
+
+0xC000040D
+
+STATUS_ISSUING_CA_UNTRUSTED_KDC
+
+
+An untrusted certificate authority was detected while processing the domain controller certificate used for authentication. There is additional information in the system event log. Contact your system administrator.
+
+0xC000040E
+
+STATUS_KDC_CERT_EXPIRED
+
+
+The domain controller certificate used for smart card logon has expired. Contact your system administrator with the contents of your system event log.
+
+0xC000040F
+
+STATUS_KDC_CERT_REVOKED
+
+
+The domain controller certificate used for smart card logon has been revoked. Contact your system administrator with the contents of your system event log.
+
+0xC0000410
+
+STATUS_PARAMETER_QUOTA_EXCEEDED
+
+
+Data present in one of the parameters is more than the function can operate on.
+
+0xC0000411
+
+STATUS_HIBERNATION_FAILURE
+
+
+The system has failed to hibernate (The error code is %hs). Hibernation will be disabled until the system is restarted.
+
+0xC0000412
+
+STATUS_DELAY_LOAD_FAILED
+
+
+An attempt to delay-load a .dll or get a function address in a delay-loaded .dll failed.
+
+0xC0000413
+
+STATUS_AUTHENTICATION_FIREWALL_FAILED
+
+
+Logon Failure: The machine you are logging onto is protected by an authentication firewall. The specified account is not allowed to authenticate to the machine.
+
+0xC0000414
+
+STATUS_VDM_DISALLOWED
+
+
+%hs is a 16-bit application. You do not have permissions to execute 16-bit applications. Check your permissions with your system administrator.
+
+0xC0000415
+
+STATUS_HUNG_DISPLAY_DRIVER_THREAD
+
+
+{Display Driver Stopped Responding} The %hs display driver has stopped working normally. Save your work and reboot the system to restore full display functionality. The next time you reboot the machine a dialog will be displayed giving you a chance to report this failure to Microsoft.
+
+0xC0000416
+
+STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE
+
+
+The Desktop heap encountered an error while allocating session memory. There is more information in the system event log.
+
+0xC0000417
+
+STATUS_INVALID_CRUNTIME_PARAMETER
+
+
+An invalid parameter was passed to a C runtime function.
+
+0xC0000418
+
+STATUS_NTLM_BLOCKED
+
+
+The authentication failed because NTLM was blocked.
+
+0xC0000419
+
+STATUS_DS_SRC_SID_EXISTS_IN_FOREST
+
+
+The source object's SID already exists in destination forest.
+
+0xC000041A
+
+STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST
+
+
+The domain name of the trusted domain already exists in the forest.
+
+0xC000041B
+
+STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST
+
+
+The flat name of the trusted domain already exists in the forest.
+
+0xC000041C
+
+STATUS_INVALID_USER_PRINCIPAL_NAME
+
+
+The User Principal Name (UPN) is invalid.
+
+0xC0000420
+
+STATUS_ASSERTION_FAILURE
+
+
+There has been an assertion failure.
+
+0xC0000421
+
+STATUS_VERIFIER_STOP
+
+
+Application verifier has found an error in the current process.
+
+0xC0000423
+
+STATUS_CALLBACK_POP_STACK
+
+
+A user mode unwind is in progress.
+
+0xC0000424
+
+STATUS_INCOMPATIBLE_DRIVER_BLOCKED
+
+
+%2 has been blocked from loading due to incompatibility with this system. Contact your software vendor for a compatible version of the driver.
+
+0xC0000425
+
+STATUS_HIVE_UNLOADED
+
+
+Illegal operation attempted on a registry key which has already been unloaded.
+
+0xC0000426
+
+STATUS_COMPRESSION_DISABLED
+
+
+Compression is disabled for this volume.
+
+0xC0000427
+
+STATUS_FILE_SYSTEM_LIMITATION
+
+
+The requested operation could not be completed due to a file system limitation.
+
+0xC0000428
+
+STATUS_INVALID_IMAGE_HASH
+
+
+The hash for image %hs cannot be found in the system catalogs. The image is likely corrupt or the victim of tampering.
+
+0xC0000429
+
+STATUS_NOT_CAPABLE
+
+
+The implementation is not capable of performing the request.
+
+0xC000042A
+
+STATUS_REQUEST_OUT_OF_SEQUENCE
+
+
+The requested operation is out of order with respect to other operations.
+
+0xC000042B
+
+STATUS_IMPLEMENTATION_LIMIT
+
+
+An operation attempted to exceed an implementation-defined limit.
+
+0xC000042C
+
+STATUS_ELEVATION_REQUIRED
+
+
+The requested operation requires elevation.
+
+0xC000042D
+
+STATUS_NO_SECURITY_CONTEXT
+
+
+The required security context does not exist.
+
+0xC000042E
+
+STATUS_PKU2U_CERT_FAILURE
+
+
+The PKU2U protocol encountered an error while attempting to utilize the associated certificates.
+
+0xC0000432
+
+STATUS_BEYOND_VDL
+
+
+The operation was attempted beyond the valid data length of the file.
+
+0xC0000433
+
+STATUS_ENCOUNTERED_WRITE_IN_PROGRESS
+
+
+The attempted write operation encountered a write already in progress for some portion of the range.
+
+0xC0000434
+
+STATUS_PTE_CHANGED
+
+
+The page fault mappings changed in the middle of processing a fault so the operation must be retried.
+
+0xC0000435
+
+STATUS_PURGE_FAILED
+
+
+The attempt to purge this file from memory failed to purge some or all the data from memory.
+
+0xC0000440
+
+STATUS_CRED_REQUIRES_CONFIRMATION
+
+
+The requested credential requires confirmation.
+
+0xC0000441
+
+STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE
+
+
+The remote server sent an invalid response for a file being opened with Client Side Encryption.
+
+0xC0000442
+
+STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER
+
+
+Client Side Encryption is not supported by the remote server even though it claims to support it.
+
+0xC0000443
+
+STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE
+
+
+File is encrypted and should be opened in Client Side Encryption mode.
+
+0xC0000444
+
+STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE
+
+
+A new encrypted file is being created and a $EFS needs to be provided.
+
+0xC0000445
+
+STATUS_CS_ENCRYPTION_FILE_NOT_CSE
+
+
+The SMB client requested a CSE FSCTL on a non-CSE file.
+
+0xC0000446
+
+STATUS_INVALID_LABEL
+
+
+Indicates a particular Security ID cannot be assigned as the label of an object.
+
+0xC0000450
+
+STATUS_DRIVER_PROCESS_TERMINATED
+
+
+The process hosting the driver for this device has terminated.
+
+0xC0000451
+
+STATUS_AMBIGUOUS_SYSTEM_DEVICE
+
+
+The requested system device cannot be identified due to multiple indistinguishable devices potentially matching the identification criteria.
+
+0xC0000452
+
+STATUS_SYSTEM_DEVICE_NOT_FOUND
+
+
+The requested system device cannot be found.
+
+0xC0000453
+
+STATUS_RESTART_BOOT_APPLICATION
+
+
+This boot application must be restarted.
+
+0xC0000454
+
+STATUS_INSUFFICIENT_NVRAM_RESOURCES
+
+
+Insufficient NVRAM resources exist to complete the API. A reboot might be required.
+
+0xC0000460
+
+STATUS_NO_RANGES_PROCESSED
+
+
+No ranges for the specified operation were able to be processed.
+
+0xC0000463
+
+STATUS_DEVICE_FEATURE_NOT_SUPPORTED
+
+
+The storage device does not support Offload Write.
+
+0xC0000464
+
+STATUS_DEVICE_UNREACHABLE
+
+
+Data cannot be moved because the source device cannot communicate with the destination device.
+
+0xC0000465
+
+STATUS_INVALID_TOKEN
+
+
+The token representing the data is invalid or expired.
+
+0xC0000466
+
+STATUS_SERVER_UNAVAILABLE
+
+
+The file server is temporarily unavailable.
+
+0xC0000500
+
+STATUS_INVALID_TASK_NAME
+
+
+The specified task name is invalid.
+
+0xC0000501
+
+STATUS_INVALID_TASK_INDEX
+
+
+The specified task index is invalid.
+
+0xC0000502
+
+STATUS_THREAD_ALREADY_IN_TASK
+
+
+The specified thread is already joining a task.
+
+0xC0000503
+
+STATUS_CALLBACK_BYPASS
+
+
+A callback has requested to bypass native code.
+
+0xC0000602
+
+STATUS_FAIL_FAST_EXCEPTION
+
+
+A fail fast exception occurred. Exception handlers will not be invoked and the process will be terminated immediately.
+
+0xC0000603
+
+STATUS_IMAGE_CERT_REVOKED
+
+
+Windows cannot verify the digital signature for this file. The signing certificate for this file has been revoked.
+
+0xC0000700
+
+STATUS_PORT_CLOSED
+
+
+The ALPC port is closed.
+
+0xC0000701
+
+STATUS_MESSAGE_LOST
+
+
+The ALPC message requested is no longer available.
+
+0xC0000702
+
+STATUS_INVALID_MESSAGE
+
+
+The ALPC message supplied is invalid.
+
+0xC0000703
+
+STATUS_REQUEST_CANCELED
+
+
+The ALPC message has been canceled.
+
+0xC0000704
+
+STATUS_RECURSIVE_DISPATCH
+
+
+Invalid recursive dispatch attempt.
+
+0xC0000705
+
+STATUS_LPC_RECEIVE_BUFFER_EXPECTED
+
+
+No receive buffer has been supplied in a synchronous request.
+
+0xC0000706
+
+STATUS_LPC_INVALID_CONNECTION_USAGE
+
+
+The connection port is used in an invalid context.
+
+0xC0000707
+
+STATUS_LPC_REQUESTS_NOT_ALLOWED
+
+
+The ALPC port does not accept new request messages.
+
+0xC0000708
+
+STATUS_RESOURCE_IN_USE
+
+
+The resource requested is already in use.
+
+0xC0000709
+
+STATUS_HARDWARE_MEMORY_ERROR
+
+
+The hardware has reported an uncorrectable memory error.
+
+0xC000070A
+
+STATUS_THREADPOOL_HANDLE_EXCEPTION
+
+
+Status 0x%08x was returned, waiting on handle 0x%x for wait 0x%p, in waiter 0x%p.
+
+0xC000070B
+
+STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED
+
+
+After a callback to 0x%p(0x%p), a completion call to Set event(0x%p) failed with status 0x%08x.
+
+0xC000070C
+
+STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED
+
+
+After a callback to 0x%p(0x%p), a completion call to ReleaseSemaphore(0x%p, %d) failed with status 0x%08x.
+
+0xC000070D
+
+STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED
+
+
+After a callback to 0x%p(0x%p), a completion call to ReleaseMutex(%p) failed with status 0x%08x.
+
+0xC000070E
+
+STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED
+
+
+After a callback to 0x%p(0x%p), a completion call to FreeLibrary(%p) failed with status 0x%08x.
+
+0xC000070F
+
+STATUS_THREADPOOL_RELEASED_DURING_OPERATION
+
+
+The thread pool 0x%p was released while a thread was posting a callback to 0x%p(0x%p) to it.
+
+0xC0000710
+
+STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING
+
+
+A thread pool worker thread is impersonating a client, after a callback to 0x%p(0x%p). This is unexpected, indicating that the callback is missing a call to revert the impersonation.
+
+0xC0000711
+
+STATUS_APC_RETURNED_WHILE_IMPERSONATING
+
+
+A thread pool worker thread is impersonating a client, after executing an APC. This is unexpected, indicating that the APC is missing a call to revert the impersonation.
+
+0xC0000712
+
+STATUS_PROCESS_IS_PROTECTED
+
+
+Either the target process, or the target thread's containing process, is a protected process.
+
+0xC0000713
+
+STATUS_MCA_EXCEPTION
+
+
+A thread is getting dispatched with MCA EXCEPTION because of MCA.
+
+0xC0000714
+
+STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE
+
+
+The client certificate account mapping is not unique.
+
+0xC0000715
+
+STATUS_SYMLINK_CLASS_DISABLED
+
+
+The symbolic link cannot be followed because its type is disabled.
+
+0xC0000716
+
+STATUS_INVALID_IDN_NORMALIZATION
+
+
+Indicates that the specified string is not valid for IDN normalization.
+
+0xC0000717
+
+STATUS_NO_UNICODE_TRANSLATION
+
+
+No mapping for the Unicode character exists in the target multi-byte code page.
+
+0xC0000718
+
+STATUS_ALREADY_REGISTERED
+
+
+The provided callback is already registered.
+
+0xC0000719
+
+STATUS_CONTEXT_MISMATCH
+
+
+The provided context did not match the target.
+
+0xC000071A
+
+STATUS_PORT_ALREADY_HAS_COMPLETION_LIST
+
+
+The specified port already has a completion list.
+
+0xC000071B
+
+STATUS_CALLBACK_RETURNED_THREAD_PRIORITY
+
+
+A threadpool worker thread entered a callback at thread base priority 0x%x and exited at priority 0x%x.
+
+This is unexpected, indicating that the callback missed restoring the priority.
+
+0xC000071C
+
+STATUS_INVALID_THREAD
+
+
+An invalid thread, handle %p, is specified for this operation. Possibly, a threadpool worker thread was specified.
+
+0xC000071D
+
+STATUS_CALLBACK_RETURNED_TRANSACTION
+
+
+A threadpool worker thread entered a callback, which left transaction state.
+
+This is unexpected, indicating that the callback missed clearing the transaction.
+
+0xC000071E
+
+STATUS_CALLBACK_RETURNED_LDR_LOCK
+
+
+A threadpool worker thread entered a callback, which left the loader lock held.
+
+This is unexpected, indicating that the callback missed releasing the lock.
+
+0xC000071F
+
+STATUS_CALLBACK_RETURNED_LANG
+
+
+A threadpool worker thread entered a callback, which left with preferred languages set.
+
+This is unexpected, indicating that the callback missed clearing them.
+
+0xC0000720
+
+STATUS_CALLBACK_RETURNED_PRI_BACK
+
+
+A threadpool worker thread entered a callback, which left with background priorities set.
+
+This is unexpected, indicating that the callback missed restoring the original priorities.
+
+0xC0000800
+
+STATUS_DISK_REPAIR_DISABLED
+
+
+The attempted operation required self healing to be enabled.
+
+0xC0000801
+
+STATUS_DS_DOMAIN_RENAME_IN_PROGRESS
+
+
+The directory service cannot perform the requested operation because a domain rename operation is in progress.
+
+0xC0000802
+
+STATUS_DISK_QUOTA_EXCEEDED
+
+
+An operation failed because the storage quota was exceeded.
+
+0xC0000804
+
+STATUS_CONTENT_BLOCKED
+
+
+An operation failed because the content was blocked.
+
+0xC0000805
+
+STATUS_BAD_CLUSTERS
+
+
+The operation could not be completed due to bad clusters on disk.
+
+0xC0000806
+
+STATUS_VOLUME_DIRTY
+
+
+The operation could not be completed because the volume is dirty. Please run the Chkdsk utility and try again.
+
+0xC0000901
+
+STATUS_FILE_CHECKED_OUT
+
+
+This file is checked out or locked for editing by another user.
+
+0xC0000902
+
+STATUS_CHECKOUT_REQUIRED
+
+
+The file must be checked out before saving changes.
+
+0xC0000903
+
+STATUS_BAD_FILE_TYPE
+
+
+The file type being saved or retrieved has been blocked.
+
+0xC0000904
+
+STATUS_FILE_TOO_LARGE
+
+
+The file size exceeds the limit allowed and cannot be saved.
+
+0xC0000905
+
+STATUS_FORMS_AUTH_REQUIRED
+
+
+Access Denied. Before opening files in this location, you must first browse to the e.g. site and select the option to log on automatically.
+
+0xC0000906
+
+STATUS_VIRUS_INFECTED
+
+
+The operation did not complete successfully because the file contains a virus.
+
+0xC0000907
+
+STATUS_VIRUS_DELETED
+
+
+This file contains a virus and cannot be opened. Due to the nature of this virus, the file has been removed from this location.
+
+0xC0000908
+
+STATUS_BAD_MCFG_TABLE
+
+
+The resources required for this device conflict with the MCFG table.
+
+0xC0000909
+
+STATUS_CANNOT_BREAK_OPLOCK
+
+
+The operation did not complete successfully because it would cause an oplock to be broken. The caller has requested that existing oplocks not be broken.
+
+0xC0009898
+
+STATUS_WOW_ASSERTION
+
+
+WOW Assertion Error.
+
+0xC000A000
+
+STATUS_INVALID_SIGNATURE
+
+
+The cryptographic signature is invalid.
+
+0xC000A001
+
+STATUS_HMAC_NOT_SUPPORTED
+
+
+The cryptographic provider does not support HMAC.
+
+0xC000A010
+
+STATUS_IPSEC_QUEUE_OVERFLOW
+
+
+The IPsec queue overflowed.
+
+0xC000A011
+
+STATUS_ND_QUEUE_OVERFLOW
+
+
+The neighbor discovery queue overflowed.
+
+0xC000A012
+
+STATUS_HOPLIMIT_EXCEEDED
+
+
+An Internet Control Message Protocol (ICMP) hop limit exceeded error was received.
+
+0xC000A013
+
+STATUS_PROTOCOL_NOT_SUPPORTED
+
+
+The protocol is not installed on the local machine.
+
+0xC000A080
+
+STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED
+
+
+{Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. This error might be caused by network connectivity issues. Try to save this file elsewhere.
+
+0xC000A081
+
+STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR
+
+
+{Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. This error was returned by the server on which the file exists. Try to save this file elsewhere.
+
+0xC000A082
+
+STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR
+
+
+{Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. This error might be caused if the device has been removed or the media is write-protected.
+
+0xC000A083
+
+STATUS_XML_PARSE_ERROR
+
+
+Windows was unable to parse the requested XML data.
+
+0xC000A084
+
+STATUS_XMLDSIG_ERROR
+
+
+An error was encountered while processing an XML digital signature.
+
+0xC000A085
+
+STATUS_WRONG_COMPARTMENT
+
+
+This indicates that the caller made the connection request in the wrong routing compartment.
+
+0xC000A086
+
+STATUS_AUTHIP_FAILURE
+
+
+This indicates that there was an AuthIP failure when attempting to connect to the remote host.
+
+0xC000A087
+
+STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS
+
+
+OID mapped groups cannot have members.
+
+0xC000A088
+
+STATUS_DS_OID_NOT_FOUND
+
+
+The specified OID cannot be found.
+
+0xC000A100
+
+STATUS_HASH_NOT_SUPPORTED
+
+
+Hash generation for the specified version and hash type is not enabled on server.
+
+0xC000A101
+
+STATUS_HASH_NOT_PRESENT
+
+
+The hash requests is not present or not up to date with the current file contents.
+
+0xC000A2A1
+
+STATUS_OFFLOAD_READ_FLT_NOT_SUPPORTED
+
+
+A file system filter on the server has not opted in for Offload Read support.
+
+0xC000A2A2
+
+STATUS_OFFLOAD_WRITE_FLT_NOT_SUPPORTED
+
+
+A file system filter on the server has not opted in for Offload Write support.
+
+0xC000A2A3
+
+STATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED
+
+
+Offload read operations cannot be performed on:
+
+ Compressed files
+
+ Sparse files
+
+ Encrypted files
+
+ File system metadata files
+
+0xC000A2A4
+
+STATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED
+
+
+Offload write operations cannot be performed on:
+
+ Compressed files
+
+ Sparse files
+
+ Encrypted files
+
+ File system metadata files
+
+0xC0010001
+
+DBG_NO_STATE_CHANGE
+
+
+The debugger did not perform a state change.
+
+0xC0010002
+
+DBG_APP_NOT_IDLE
+
+
+The debugger found that the application is not idle.
+
+0xC0020001
+
+RPC_NT_INVALID_STRING_BINDING
+
+
+The string binding is invalid.
+
+0xC0020002
+
+RPC_NT_WRONG_KIND_OF_BINDING
+
+
+The binding handle is not the correct type.
+
+0xC0020003
+
+RPC_NT_INVALID_BINDING
+
+
+The binding handle is invalid.
+
+0xC0020004
+
+RPC_NT_PROTSEQ_NOT_SUPPORTED
+
+
+The RPC protocol sequence is not supported.
+
+0xC0020005
+
+RPC_NT_INVALID_RPC_PROTSEQ
+
+
+The RPC protocol sequence is invalid.
+
+0xC0020006
+
+RPC_NT_INVALID_STRING_UUID
+
+
+The string UUID is invalid.
+
+0xC0020007
+
+RPC_NT_INVALID_ENDPOINT_FORMAT
+
+
+The endpoint format is invalid.
+
+0xC0020008
+
+RPC_NT_INVALID_NET_ADDR
+
+
+The network address is invalid.
+
+0xC0020009
+
+RPC_NT_NO_ENDPOINT_FOUND
+
+
+No endpoint was found.
+
+0xC002000A
+
+RPC_NT_INVALID_TIMEOUT
+
+
+The time-out value is invalid.
+
+0xC002000B
+
+RPC_NT_OBJECT_NOT_FOUND
+
+
+The object UUID was not found.
+
+0xC002000C
+
+RPC_NT_ALREADY_REGISTERED
+
+
+The object UUID has already been registered.
+
+0xC002000D
+
+RPC_NT_TYPE_ALREADY_REGISTERED
+
+
+The type UUID has already been registered.
+
+0xC002000E
+
+RPC_NT_ALREADY_LISTENING
+
+
+The RPC server is already listening.
+
+0xC002000F
+
+RPC_NT_NO_PROTSEQS_REGISTERED
+
+
+No protocol sequences have been registered.
+
+0xC0020010
+
+RPC_NT_NOT_LISTENING
+
+
+The RPC server is not listening.
+
+0xC0020011
+
+RPC_NT_UNKNOWN_MGR_TYPE
+
+
+The manager type is unknown.
+
+0xC0020012
+
+RPC_NT_UNKNOWN_IF
+
+
+The interface is unknown.
+
+0xC0020013
+
+RPC_NT_NO_BINDINGS
+
+
+There are no bindings.
+
+0xC0020014
+
+RPC_NT_NO_PROTSEQS
+
+
+There are no protocol sequences.
+
+0xC0020015
+
+RPC_NT_CANT_CREATE_ENDPOINT
+
+
+The endpoint cannot be created.
+
+0xC0020016
+
+RPC_NT_OUT_OF_RESOURCES
+
+
+Insufficient resources are available to complete this operation.
+
+0xC0020017
+
+RPC_NT_SERVER_UNAVAILABLE
+
+
+The RPC server is unavailable.
+
+0xC0020018
+
+RPC_NT_SERVER_TOO_BUSY
+
+
+The RPC server is too busy to complete this operation.
+
+0xC0020019
+
+RPC_NT_INVALID_NETWORK_OPTIONS
+
+
+The network options are invalid.
+
+0xC002001A
+
+RPC_NT_NO_CALL_ACTIVE
+
+
+No RPCs are active on this thread.
+
+0xC002001B
+
+RPC_NT_CALL_FAILED
+
+
+The RPC failed.
+
+0xC002001C
+
+RPC_NT_CALL_FAILED_DNE
+
+
+The RPC failed and did not execute.
+
+0xC002001D
+
+RPC_NT_PROTOCOL_ERROR
+
+
+An RPC protocol error occurred.
+
+0xC002001F
+
+RPC_NT_UNSUPPORTED_TRANS_SYN
+
+
+The RPC server does not support the transfer syntax.
+
+0xC0020021
+
+RPC_NT_UNSUPPORTED_TYPE
+
+
+The type UUID is not supported.
+
+0xC0020022
+
+RPC_NT_INVALID_TAG
+
+
+The tag is invalid.
+
+0xC0020023
+
+RPC_NT_INVALID_BOUND
+
+
+The array bounds are invalid.
+
+0xC0020024
+
+RPC_NT_NO_ENTRY_NAME
+
+
+The binding does not contain an entry name.
+
+0xC0020025
+
+RPC_NT_INVALID_NAME_SYNTAX
+
+
+The name syntax is invalid.
+
+0xC0020026
+
+RPC_NT_UNSUPPORTED_NAME_SYNTAX
+
+
+The name syntax is not supported.
+
+0xC0020028
+
+RPC_NT_UUID_NO_ADDRESS
+
+
+No network address is available to construct a UUID.
+
+0xC0020029
+
+RPC_NT_DUPLICATE_ENDPOINT
+
+
+The endpoint is a duplicate.
+
+0xC002002A
+
+RPC_NT_UNKNOWN_AUTHN_TYPE
+
+
+The authentication type is unknown.
+
+0xC002002B
+
+RPC_NT_MAX_CALLS_TOO_SMALL
+
+
+The maximum number of calls is too small.
+
+0xC002002C
+
+RPC_NT_STRING_TOO_LONG
+
+
+The string is too long.
+
+0xC002002D
+
+RPC_NT_PROTSEQ_NOT_FOUND
+
+
+The RPC protocol sequence was not found.
+
+0xC002002E
+
+RPC_NT_PROCNUM_OUT_OF_RANGE
+
+
+The procedure number is out of range.
+
+0xC002002F
+
+RPC_NT_BINDING_HAS_NO_AUTH
+
+
+The binding does not contain any authentication information.
+
+0xC0020030
+
+RPC_NT_UNKNOWN_AUTHN_SERVICE
+
+
+The authentication service is unknown.
+
+0xC0020031
+
+RPC_NT_UNKNOWN_AUTHN_LEVEL
+
+
+The authentication level is unknown.
+
+0xC0020032
+
+RPC_NT_INVALID_AUTH_IDENTITY
+
+
+The security context is invalid.
+
+0xC0020033
+
+RPC_NT_UNKNOWN_AUTHZ_SERVICE
+
+
+The authorization service is unknown.
+
+0xC0020034
+
+EPT_NT_INVALID_ENTRY
+
+
+The entry is invalid.
+
+0xC0020035
+
+EPT_NT_CANT_PERFORM_OP
+
+
+The operation cannot be performed.
+
+0xC0020036
+
+EPT_NT_NOT_REGISTERED
+
+
+No more endpoints are available from the endpoint mapper.
+
+0xC0020037
+
+RPC_NT_NOTHING_TO_EXPORT
+
+
+No interfaces have been exported.
+
+0xC0020038
+
+RPC_NT_INCOMPLETE_NAME
+
+
+The entry name is incomplete.
+
+0xC0020039
+
+RPC_NT_INVALID_VERS_OPTION
+
+
+The version option is invalid.
+
+0xC002003A
+
+RPC_NT_NO_MORE_MEMBERS
+
+
+There are no more members.
+
+0xC002003B
+
+RPC_NT_NOT_ALL_OBJS_UNEXPORTED
+
+
+There is nothing to unexport.
+
+0xC002003C
+
+RPC_NT_INTERFACE_NOT_FOUND
+
+
+The interface was not found.
+
+0xC002003D
+
+RPC_NT_ENTRY_ALREADY_EXISTS
+
+
+The entry already exists.
+
+0xC002003E
+
+RPC_NT_ENTRY_NOT_FOUND
+
+
+The entry was not found.
+
+0xC002003F
+
+RPC_NT_NAME_SERVICE_UNAVAILABLE
+
+
+The name service is unavailable.
+
+0xC0020040
+
+RPC_NT_INVALID_NAF_ID
+
+
+The network address family is invalid.
+
+0xC0020041
+
+RPC_NT_CANNOT_SUPPORT
+
+
+The requested operation is not supported.
+
+0xC0020042
+
+RPC_NT_NO_CONTEXT_AVAILABLE
+
+
+No security context is available to allow impersonation.
+
+0xC0020043
+
+RPC_NT_INTERNAL_ERROR
+
+
+An internal error occurred in the RPC.
+
+0xC0020044
+
+RPC_NT_ZERO_DIVIDE
+
+
+The RPC server attempted to divide an integer by zero.
+
+0xC0020045
+
+RPC_NT_ADDRESS_ERROR
+
+
+An addressing error occurred in the RPC server.
+
+0xC0020046
+
+RPC_NT_FP_DIV_ZERO
+
+
+A floating point operation at the RPC server caused a divide by zero.
+
+0xC0020047
+
+RPC_NT_FP_UNDERFLOW
+
+
+A floating point underflow occurred at the RPC server.
+
+0xC0020048
+
+RPC_NT_FP_OVERFLOW
+
+
+A floating point overflow occurred at the RPC server.
+
+0xC0020049
+
+RPC_NT_CALL_IN_PROGRESS
+
+
+An RPC is already in progress for this thread.
+
+0xC002004A
+
+RPC_NT_NO_MORE_BINDINGS
+
+
+There are no more bindings.
+
+0xC002004B
+
+RPC_NT_GROUP_MEMBER_NOT_FOUND
+
+
+The group member was not found.
+
+0xC002004C
+
+EPT_NT_CANT_CREATE
+
+
+The endpoint mapper database entry could not be created.
+
+0xC002004D
+
+RPC_NT_INVALID_OBJECT
+
+
+The object UUID is the nil UUID.
+
+0xC002004F
+
+RPC_NT_NO_INTERFACES
+
+
+No interfaces have been registered.
+
+0xC0020050
+
+RPC_NT_CALL_CANCELLED
+
+
+The RPC was canceled.
+
+0xC0020051
+
+RPC_NT_BINDING_INCOMPLETE
+
+
+The binding handle does not contain all the required information.
+
+0xC0020052
+
+RPC_NT_COMM_FAILURE
+
+
+A communications failure occurred during an RPC.
+
+0xC0020053
+
+RPC_NT_UNSUPPORTED_AUTHN_LEVEL
+
+
+The requested authentication level is not supported.
+
+0xC0020054
+
+RPC_NT_NO_PRINC_NAME
+
+
+No principal name was registered.
+
+0xC0020055
+
+RPC_NT_NOT_RPC_ERROR
+
+
+The error specified is not a valid Windows RPC error code.
+
+0xC0020057
+
+RPC_NT_SEC_PKG_ERROR
+
+
+A security package-specific error occurred.
+
+0xC0020058
+
+RPC_NT_NOT_CANCELLED
+
+
+The thread was not canceled.
+
+0xC0020062
+
+RPC_NT_INVALID_ASYNC_HANDLE
+
+
+Invalid asynchronous RPC handle.
+
+0xC0020063
+
+RPC_NT_INVALID_ASYNC_CALL
+
+
+Invalid asynchronous RPC call handle for this operation.
+
+0xC0020064
+
+RPC_NT_PROXY_ACCESS_DENIED
+
+
+Access to the HTTP proxy is denied.
+
+0xC0030001
+
+RPC_NT_NO_MORE_ENTRIES
+
+
+The list of RPC servers available for auto-handle binding has been exhausted.
+
+0xC0030002
+
+RPC_NT_SS_CHAR_TRANS_OPEN_FAIL
+
+
+The file designated by DCERPCCHARTRANS cannot be opened.
+
+0xC0030003
+
+RPC_NT_SS_CHAR_TRANS_SHORT_FILE
+
+
+The file containing the character translation table has fewer than 512 bytes.
+
+0xC0030004
+
+RPC_NT_SS_IN_NULL_CONTEXT
+
+
+A null context handle is passed as an [in] parameter.
+
+0xC0030005
+
+RPC_NT_SS_CONTEXT_MISMATCH
+
+
+The context handle does not match any known context handles.
+
+0xC0030006
+
+RPC_NT_SS_CONTEXT_DAMAGED
+
+
+The context handle changed during a call.
+
+0xC0030007
+
+RPC_NT_SS_HANDLES_MISMATCH
+
+
+The binding handles passed to an RPC do not match.
+
+0xC0030008
+
+RPC_NT_SS_CANNOT_GET_CALL_HANDLE
+
+
+The stub is unable to get the call handle.
+
+0xC0030009
+
+RPC_NT_NULL_REF_POINTER
+
+
+A null reference pointer was passed to the stub.
+
+0xC003000A
+
+RPC_NT_ENUM_VALUE_OUT_OF_RANGE
+
+
+The enumeration value is out of range.
+
+0xC003000B
+
+RPC_NT_BYTE_COUNT_TOO_SMALL
+
+
+The byte count is too small.
+
+0xC003000C
+
+RPC_NT_BAD_STUB_DATA
+
+
+The stub received bad data.
+
+0xC0030059
+
+RPC_NT_INVALID_ES_ACTION
+
+
+Invalid operation on the encoding/decoding handle.
+
+0xC003005A
+
+RPC_NT_WRONG_ES_VERSION
+
+
+Incompatible version of the serializing package.
+
+0xC003005B
+
+RPC_NT_WRONG_STUB_VERSION
+
+
+Incompatible version of the RPC stub.
+
+0xC003005C
+
+RPC_NT_INVALID_PIPE_OBJECT
+
+
+The RPC pipe object is invalid or corrupt.
+
+0xC003005D
+
+RPC_NT_INVALID_PIPE_OPERATION
+
+
+An invalid operation was attempted on an RPC pipe object.
+
+0xC003005E
+
+RPC_NT_WRONG_PIPE_VERSION
+
+
+Unsupported RPC pipe version.
+
+0xC003005F
+
+RPC_NT_PIPE_CLOSED
+
+
+The RPC pipe object has already been closed.
+
+0xC0030060
+
+RPC_NT_PIPE_DISCIPLINE_ERROR
+
+
+The RPC call completed before all pipes were processed.
+
+0xC0030061
+
+RPC_NT_PIPE_EMPTY
+
+
+No more data is available from the RPC pipe.
+
+0xC0040035
+
+STATUS_PNP_BAD_MPS_TABLE
+
+
+A device is missing in the system BIOS MPS table. This device will not be used. Contact your system vendor for a system BIOS update.
+
+0xC0040036
+
+STATUS_PNP_TRANSLATION_FAILED
+
+
+A translator failed to translate resources.
+
+0xC0040037
+
+STATUS_PNP_IRQ_TRANSLATION_FAILED
+
+
+An IRQ translator failed to translate resources.
+
+0xC0040038
+
+STATUS_PNP_INVALID_ID
+
+
+Driver %2 returned an invalid ID for a child device (%3).
+
+0xC0040039
+
+STATUS_IO_REISSUE_AS_CACHED
+
+
+Reissue the given operation as a cached I/O operation
+
+0xC00A0001
+
+STATUS_CTX_WINSTATION_NAME_INVALID
+
+
+Session name %1 is invalid.
+
+0xC00A0002
+
+STATUS_CTX_INVALID_PD
+
+
+The protocol driver %1 is invalid.
+
+0xC00A0003
+
+STATUS_CTX_PD_NOT_FOUND
+
+
+The protocol driver %1 was not found in the system path.
+
+0xC00A0006
+
+STATUS_CTX_CLOSE_PENDING
+
+
+A close operation is pending on the terminal connection.
+
+0xC00A0007
+
+STATUS_CTX_NO_OUTBUF
+
+
+No free output buffers are available.
+
+0xC00A0008
+
+STATUS_CTX_MODEM_INF_NOT_FOUND
+
+
+The MODEM.INF file was not found.
+
+0xC00A0009
+
+STATUS_CTX_INVALID_MODEMNAME
+
+
+The modem (%1) was not found in the MODEM.INF file.
+
+0xC00A000A
+
+STATUS_CTX_RESPONSE_ERROR
+
+
+The modem did not accept the command sent to it. Verify that the configured modem name matches the attached modem.
+
+0xC00A000B
+
+STATUS_CTX_MODEM_RESPONSE_TIMEOUT
+
+
+The modem did not respond to the command sent to it. Verify that the modem cable is properly attached and the modem is turned on.
+
+0xC00A000C
+
+STATUS_CTX_MODEM_RESPONSE_NO_CARRIER
+
+
+Carrier detection has failed or the carrier has been dropped due to disconnection.
+
+0xC00A000D
+
+STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE
+
+
+A dial tone was not detected within the required time. Verify that the phone cable is properly attached and functional.
+
+0xC00A000E
+
+STATUS_CTX_MODEM_RESPONSE_BUSY
+
+
+A busy signal was detected at a remote site on callback.
+
+0xC00A000F
+
+STATUS_CTX_MODEM_RESPONSE_VOICE
+
+
+A voice was detected at a remote site on callback.
+
+0xC00A0010
+
+STATUS_CTX_TD_ERROR
+
+
+Transport driver error.
+
+0xC00A0012
+
+STATUS_CTX_LICENSE_CLIENT_INVALID
+
+
+The client you are using is not licensed to use this system. Your logon request is denied.
+
+0xC00A0013
+
+STATUS_CTX_LICENSE_NOT_AVAILABLE
+
+
+The system has reached its licensed logon limit. Try again later.
+
+0xC00A0014
+
+STATUS_CTX_LICENSE_EXPIRED
+
+
+The system license has expired. Your logon request is denied.
+
+0xC00A0015
+
+STATUS_CTX_WINSTATION_NOT_FOUND
+
+
+The specified session cannot be found.
+
+0xC00A0016
+
+STATUS_CTX_WINSTATION_NAME_COLLISION
+
+
+The specified session name is already in use.
+
+0xC00A0017
+
+STATUS_CTX_WINSTATION_BUSY
+
+
+The requested operation cannot be completed because the terminal connection is currently processing a connect, disconnect, reset, or delete operation.
+
+0xC00A0018
+
+STATUS_CTX_BAD_VIDEO_MODE
+
+
+An attempt has been made to connect to a session whose video mode is not supported by the current client.
+
+0xC00A0022
+
+STATUS_CTX_GRAPHICS_INVALID
+
+
+The application attempted to enable DOS graphics mode. DOS graphics mode is not supported.
+
+0xC00A0024
+
+STATUS_CTX_NOT_CONSOLE
+
+
+The requested operation can be performed only on the system console. This is most often the result of a driver or system DLL requiring direct console access.
+
+0xC00A0026
+
+STATUS_CTX_CLIENT_QUERY_TIMEOUT
+
+
+The client failed to respond to the server connect message.
+
+0xC00A0027
+
+STATUS_CTX_CONSOLE_DISCONNECT
+
+
+Disconnecting the console session is not supported.
+
+0xC00A0028
+
+STATUS_CTX_CONSOLE_CONNECT
+
+
+Reconnecting a disconnected session to the console is not supported.
+
+0xC00A002A
+
+STATUS_CTX_SHADOW_DENIED
+
+
+The request to control another session remotely was denied.
+
+0xC00A002B
+
+STATUS_CTX_WINSTATION_ACCESS_DENIED
+
+
+A process has requested access to a session, but has not been granted those access rights.
+
+0xC00A002E
+
+STATUS_CTX_INVALID_WD
+
+
+The terminal connection driver %1 is invalid.
+
+0xC00A002F
+
+STATUS_CTX_WD_NOT_FOUND
+
+
+The terminal connection driver %1 was not found in the system path.
+
+0xC00A0030
+
+STATUS_CTX_SHADOW_INVALID
+
+
+The requested session cannot be controlled remotely. You cannot control your own session, a session that is trying to control your session, a session that has no user logged on, or other sessions from the console.
+
+0xC00A0031
+
+STATUS_CTX_SHADOW_DISABLED
+
+
+The requested session is not configured to allow remote control.
+
+0xC00A0032
+
+STATUS_RDP_PROTOCOL_ERROR
+
+
+The RDP protocol component %2 detected an error in the protocol stream and has disconnected the client.
+
+0xC00A0033
+
+STATUS_CTX_CLIENT_LICENSE_NOT_SET
+
+
+Your request to connect to this terminal server has been rejected. Your terminal server client license number has not been entered for this copy of the terminal client. Contact your system administrator for help in entering a valid, unique license number for this terminal server client. Click OK to continue.
+
+0xC00A0034
+
+STATUS_CTX_CLIENT_LICENSE_IN_USE
+
+
+Your request to connect to this terminal server has been rejected. Your terminal server client license number is currently being used by another user. Contact your system administrator to obtain a new copy of the terminal server client with a valid, unique license number. Click OK to continue.
+
+0xC00A0035
+
+STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE
+
+
+The remote control of the console was terminated because the display mode was changed. Changing the display mode in a remote control session is not supported.
+
+0xC00A0036
+
+STATUS_CTX_SHADOW_NOT_RUNNING
+
+
+Remote control could not be terminated because the specified session is not currently being remotely controlled.
+
+0xC00A0037
+
+STATUS_CTX_LOGON_DISABLED
+
+
+Your interactive logon privilege has been disabled. Contact your system administrator.
+
+0xC00A0038
+
+STATUS_CTX_SECURITY_LAYER_ERROR
+
+
+The terminal server security layer detected an error in the protocol stream and has disconnected the client.
+
+0xC00A0039
+
+STATUS_TS_INCOMPATIBLE_SESSIONS
+
+
+The target session is incompatible with the current session.
+
+0xC00B0001
+
+STATUS_MUI_FILE_NOT_FOUND
+
+
+The resource loader failed to find an MUI file.
+
+0xC00B0002
+
+STATUS_MUI_INVALID_FILE
+
+
+The resource loader failed to load an MUI file because the file failed to pass validation.
+
+0xC00B0003
+
+STATUS_MUI_INVALID_RC_CONFIG
+
+
+The RC manifest is corrupted with garbage data, is an unsupported version, or is missing a required item.
+
+0xC00B0004
+
+STATUS_MUI_INVALID_LOCALE_NAME
+
+
+The RC manifest has an invalid culture name.
+
+0xC00B0005
+
+STATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME
+
+
+The RC manifest has and invalid ultimate fallback name.
+
+0xC00B0006
+
+STATUS_MUI_FILE_NOT_LOADED
+
+
+The resource loader cache does not have a loaded MUI entry.
+
+0xC00B0007
+
+STATUS_RESOURCE_ENUM_USER_STOP
+
+
+The user stopped resource enumeration.
+
+0xC0130001
+
+STATUS_CLUSTER_INVALID_NODE
+
+
+The cluster node is not valid.
+
+0xC0130002
+
+STATUS_CLUSTER_NODE_EXISTS
+
+
+The cluster node already exists.
+
+0xC0130003
+
+STATUS_CLUSTER_JOIN_IN_PROGRESS
+
+
+A node is in the process of joining the cluster.
+
+0xC0130004
+
+STATUS_CLUSTER_NODE_NOT_FOUND
+
+
+The cluster node was not found.
+
+0xC0130005
+
+STATUS_CLUSTER_LOCAL_NODE_NOT_FOUND
+
+
+The cluster local node information was not found.
+
+0xC0130006
+
+STATUS_CLUSTER_NETWORK_EXISTS
+
+
+The cluster network already exists.
+
+0xC0130007
+
+STATUS_CLUSTER_NETWORK_NOT_FOUND
+
+
+The cluster network was not found.
+
+0xC0130008
+
+STATUS_CLUSTER_NETINTERFACE_EXISTS
+
+
+The cluster network interface already exists.
+
+0xC0130009
+
+STATUS_CLUSTER_NETINTERFACE_NOT_FOUND
+
+
+The cluster network interface was not found.
+
+0xC013000A
+
+STATUS_CLUSTER_INVALID_REQUEST
+
+
+The cluster request is not valid for this object.
+
+0xC013000B
+
+STATUS_CLUSTER_INVALID_NETWORK_PROVIDER
+
+
+The cluster network provider is not valid.
+
+0xC013000C
+
+STATUS_CLUSTER_NODE_DOWN
+
+
+The cluster node is down.
+
+0xC013000D
+
+STATUS_CLUSTER_NODE_UNREACHABLE
+
+
+The cluster node is not reachable.
+
+0xC013000E
+
+STATUS_CLUSTER_NODE_NOT_MEMBER
+
+
+The cluster node is not a member of the cluster.
+
+0xC013000F
+
+STATUS_CLUSTER_JOIN_NOT_IN_PROGRESS
+
+
+A cluster join operation is not in progress.
+
+0xC0130010
+
+STATUS_CLUSTER_INVALID_NETWORK
+
+
+The cluster network is not valid.
+
+0xC0130011
+
+STATUS_CLUSTER_NO_NET_ADAPTERS
+
+
+No network adapters are available.
+
+0xC0130012
+
+STATUS_CLUSTER_NODE_UP
+
+
+The cluster node is up.
+
+0xC0130013
+
+STATUS_CLUSTER_NODE_PAUSED
+
+
+The cluster node is paused.
+
+0xC0130014
+
+STATUS_CLUSTER_NODE_NOT_PAUSED
+
+
+The cluster node is not paused.
+
+0xC0130015
+
+STATUS_CLUSTER_NO_SECURITY_CONTEXT
+
+
+No cluster security context is available.
+
+0xC0130016
+
+STATUS_CLUSTER_NETWORK_NOT_INTERNAL
+
+
+The cluster network is not configured for internal cluster communication.
+
+0xC0130017
+
+STATUS_CLUSTER_POISONED
+
+
+The cluster node has been poisoned.
+
+0xC0140001
+
+STATUS_ACPI_INVALID_OPCODE
+
+
+An attempt was made to run an invalid AML opcode.
+
+0xC0140002
+
+STATUS_ACPI_STACK_OVERFLOW
+
+
+The AML interpreter stack has overflowed.
+
+0xC0140003
+
+STATUS_ACPI_ASSERT_FAILED
+
+
+An inconsistent state has occurred.
+
+0xC0140004
+
+STATUS_ACPI_INVALID_INDEX
+
+
+An attempt was made to access an array outside its bounds.
+
+0xC0140005
+
+STATUS_ACPI_INVALID_ARGUMENT
+
+
+A required argument was not specified.
+
+0xC0140006
+
+STATUS_ACPI_FATAL
+
+
+A fatal error has occurred.
+
+0xC0140007
+
+STATUS_ACPI_INVALID_SUPERNAME
+
+
+An invalid SuperName was specified.
+
+0xC0140008
+
+STATUS_ACPI_INVALID_ARGTYPE
+
+
+An argument with an incorrect type was specified.
+
+0xC0140009
+
+STATUS_ACPI_INVALID_OBJTYPE
+
+
+An object with an incorrect type was specified.
+
+0xC014000A
+
+STATUS_ACPI_INVALID_TARGETTYPE
+
+
+A target with an incorrect type was specified.
+
+0xC014000B
+
+STATUS_ACPI_INCORRECT_ARGUMENT_COUNT
+
+
+An incorrect number of arguments was specified.
+
+0xC014000C
+
+STATUS_ACPI_ADDRESS_NOT_MAPPED
+
+
+An address failed to translate.
+
+0xC014000D
+
+STATUS_ACPI_INVALID_EVENTTYPE
+
+
+An incorrect event type was specified.
+
+0xC014000E
+
+STATUS_ACPI_HANDLER_COLLISION
+
+
+A handler for the target already exists.
+
+0xC014000F
+
+STATUS_ACPI_INVALID_DATA
+
+
+Invalid data for the target was specified.
+
+0xC0140010
+
+STATUS_ACPI_INVALID_REGION
+
+
+An invalid region for the target was specified.
+
+0xC0140011
+
+STATUS_ACPI_INVALID_ACCESS_SIZE
+
+
+An attempt was made to access a field outside the defined range.
+
+0xC0140012
+
+STATUS_ACPI_ACQUIRE_GLOBAL_LOCK
+
+
+The global system lock could not be acquired.
+
+0xC0140013
+
+STATUS_ACPI_ALREADY_INITIALIZED
+
+
+An attempt was made to reinitialize the ACPI subsystem.
+
+0xC0140014
+
+STATUS_ACPI_NOT_INITIALIZED
+
+
+The ACPI subsystem has not been initialized.
+
+0xC0140015
+
+STATUS_ACPI_INVALID_MUTEX_LEVEL
+
+
+An incorrect mutex was specified.
+
+0xC0140016
+
+STATUS_ACPI_MUTEX_NOT_OWNED
+
+
+The mutex is not currently owned.
+
+0xC0140017
+
+STATUS_ACPI_MUTEX_NOT_OWNER
+
+
+An attempt was made to access the mutex by a process that was not the owner.
+
+0xC0140018
+
+STATUS_ACPI_RS_ACCESS
+
+
+An error occurred during an access to region space.
+
+0xC0140019
+
+STATUS_ACPI_INVALID_TABLE
+
+
+An attempt was made to use an incorrect table.
+
+0xC0140020
+
+STATUS_ACPI_REG_HANDLER_FAILED
+
+
+The registration of an ACPI event failed.
+
+0xC0140021
+
+STATUS_ACPI_POWER_REQUEST_FAILED
+
+
+An ACPI power object failed to transition state.
+
+0xC0150001
+
+STATUS_SXS_SECTION_NOT_FOUND
+
+
+The requested section is not present in the activation context.
+
+0xC0150002
+
+STATUS_SXS_CANT_GEN_ACTCTX
+
+
+Windows was unble to process the application binding information. Refer to the system event log for further information.
+
+0xC0150003
+
+STATUS_SXS_INVALID_ACTCTXDATA_FORMAT
+
+
+The application binding data format is invalid.
+
+0xC0150004
+
+STATUS_SXS_ASSEMBLY_NOT_FOUND
+
+
+The referenced assembly is not installed on the system.
+
+0xC0150005
+
+STATUS_SXS_MANIFEST_FORMAT_ERROR
+
+
+The manifest file does not begin with the required tag and format information.
+
+0xC0150006
+
+STATUS_SXS_MANIFEST_PARSE_ERROR
+
+
+The manifest file contains one or more syntax errors.
+
+0xC0150007
+
+STATUS_SXS_ACTIVATION_CONTEXT_DISABLED
+
+
+The application attempted to activate a disabled activation context.
+
+0xC0150008
+
+STATUS_SXS_KEY_NOT_FOUND
+
+
+The requested lookup key was not found in any active activation context.
+
+0xC0150009
+
+STATUS_SXS_VERSION_CONFLICT
+
+
+A component version required by the application conflicts with another component version that is already active.
+
+0xC015000A
+
+STATUS_SXS_WRONG_SECTION_TYPE
+
+
+The type requested activation context section does not match the query API used.
+
+0xC015000B
+
+STATUS_SXS_THREAD_QUERIES_DISABLED
+
+
+Lack of system resources has required isolated activation to be disabled for the current thread of execution.
+
+0xC015000C
+
+STATUS_SXS_ASSEMBLY_MISSING
+
+
+The referenced assembly could not be found.
+
+0xC015000E
+
+STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET
+
+
+An attempt to set the process default activation context failed because the process default activation context was already set.
+
+0xC015000F
+
+STATUS_SXS_EARLY_DEACTIVATION
+
+
+The activation context being deactivated is not the most recently activated one.
+
+0xC0150010
+
+STATUS_SXS_INVALID_DEACTIVATION
+
+
+The activation context being deactivated is not active for the current thread of execution.
+
+0xC0150011
+
+STATUS_SXS_MULTIPLE_DEACTIVATION
+
+
+The activation context being deactivated has already been deactivated.
+
+0xC0150012
+
+STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY
+
+
+The activation context of the system default assembly could not be generated.
+
+0xC0150013
+
+STATUS_SXS_PROCESS_TERMINATION_REQUESTED
+
+
+A component used by the isolation facility has requested that the process be terminated.
+
+0xC0150014
+
+STATUS_SXS_CORRUPT_ACTIVATION_STACK
+
+
+The activation context activation stack for the running thread of execution is corrupt.
+
+0xC0150015
+
+STATUS_SXS_CORRUPTION
+
+
+The application isolation metadata for this process or thread has become corrupt.
+
+0xC0150016
+
+STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE
+
+
+The value of an attribute in an identity is not within the legal range.
+
+0xC0150017
+
+STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME
+
+
+The name of an attribute in an identity is not within the legal range.
+
+0xC0150018
+
+STATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE
+
+
+An identity contains two definitions for the same attribute.
+
+0xC0150019
+
+STATUS_SXS_IDENTITY_PARSE_ERROR
+
+
+The identity string is malformed. This might be due to a trailing comma, more than two unnamed attributes, a missing attribute name, or a missing attribute value.
+
+0xC015001A
+
+STATUS_SXS_COMPONENT_STORE_CORRUPT
+
+
+The component store has become corrupted.
+
+0xC015001B
+
+STATUS_SXS_FILE_HASH_MISMATCH
+
+
+A component's file does not match the verification information present in the component manifest.
+
+0xC015001C
+
+STATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT
+
+
+The identities of the manifests are identical, but their contents are different.
+
+0xC015001D
+
+STATUS_SXS_IDENTITIES_DIFFERENT
+
+
+The component identities are different.
+
+0xC015001E
+
+STATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT
+
+
+The assembly is not a deployment.
+
+0xC015001F
+
+STATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY
+
+
+The file is not a part of the assembly.
+
+0xC0150020
+
+STATUS_ADVANCED_INSTALLER_FAILED
+
+
+An advanced installer failed during setup or servicing.
+
+0xC0150021
+
+STATUS_XML_ENCODING_MISMATCH
+
+
+The character encoding in the XML declaration did not match the encoding used in the document.
+
+0xC0150022
+
+STATUS_SXS_MANIFEST_TOO_BIG
+
+
+The size of the manifest exceeds the maximum allowed.
+
+0xC0150023
+
+STATUS_SXS_SETTING_NOT_REGISTERED
+
+
+The setting is not registered.
+
+0xC0150024
+
+STATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE
+
+
+One or more required transaction members are not present.
+
+0xC0150025
+
+STATUS_SMI_PRIMITIVE_INSTALLER_FAILED
+
+
+The SMI primitive installer failed during setup or servicing.
+
+0xC0150026
+
+STATUS_GENERIC_COMMAND_FAILED
+
+
+A generic command executable returned a result that indicates failure.
+
+0xC0150027
+
+STATUS_SXS_FILE_HASH_MISSING
+
+
+A component is missing file verification information in its manifest.
+
+0xC0190001
+
+STATUS_TRANSACTIONAL_CONFLICT
+
+
+The function attempted to use a name that is reserved for use by another transaction.
+
+0xC0190002
+
+STATUS_INVALID_TRANSACTION
+
+
+The transaction handle associated with this operation is invalid.
+
+0xC0190003
+
+STATUS_TRANSACTION_NOT_ACTIVE
+
+
+The requested operation was made in the context of a transaction that is no longer active.
+
+0xC0190004
+
+STATUS_TM_INITIALIZATION_FAILED
+
+
+The transaction manager was unable to be successfully initialized. Transacted operations are not supported.
+
+0xC0190005
+
+STATUS_RM_NOT_ACTIVE
+
+
+Transaction support within the specified file system resource manager was not started or was shut down due to an error.
+
+0xC0190006
+
+STATUS_RM_METADATA_CORRUPT
+
+
+The metadata of the resource manager has been corrupted. The resource manager will not function.
+
+0xC0190007
+
+STATUS_TRANSACTION_NOT_JOINED
+
+
+The resource manager attempted to prepare a transaction that it has not successfully joined.
+
+0xC0190008
+
+STATUS_DIRECTORY_NOT_RM
+
+
+The specified directory does not contain a file system resource manager.
+
+0xC019000A
+
+STATUS_TRANSACTIONS_UNSUPPORTED_REMOTE
+
+
+The remote server or share does not support transacted file operations.
+
+0xC019000B
+
+STATUS_LOG_RESIZE_INVALID_SIZE
+
+
+The requested log size for the file system resource manager is invalid.
+
+0xC019000C
+
+STATUS_REMOTE_FILE_VERSION_MISMATCH
+
+
+The remote server sent mismatching version number or Fid for a file opened with transactions.
+
+0xC019000F
+
+STATUS_CRM_PROTOCOL_ALREADY_EXISTS
+
+
+The resource manager tried to register a protocol that already exists.
+
+0xC0190010
+
+STATUS_TRANSACTION_PROPAGATION_FAILED
+
+
+The attempt to propagate the transaction failed.
+
+0xC0190011
+
+STATUS_CRM_PROTOCOL_NOT_FOUND
+
+
+The requested propagation protocol was not registered as a CRM.
+
+0xC0190012
+
+STATUS_TRANSACTION_SUPERIOR_EXISTS
+
+
+The transaction object already has a superior enlistment, and the caller attempted an operation that would have created a new superior. Only a single superior enlistment is allowed.
+
+0xC0190013
+
+STATUS_TRANSACTION_REQUEST_NOT_VALID
+
+
+The requested operation is not valid on the transaction object in its current state.
+
+0xC0190014
+
+STATUS_TRANSACTION_NOT_REQUESTED
+
+
+The caller has called a response API, but the response is not expected because the transaction manager did not issue the corresponding request to the caller.
+
+0xC0190015
+
+STATUS_TRANSACTION_ALREADY_ABORTED
+
+
+It is too late to perform the requested operation, because the transaction has already been aborted.
+
+0xC0190016
+
+STATUS_TRANSACTION_ALREADY_COMMITTED
+
+
+It is too late to perform the requested operation, because the transaction has already been committed.
+
+0xC0190017
+
+STATUS_TRANSACTION_INVALID_MARSHALL_BUFFER
+
+
+The buffer passed in to NtPushTransaction or NtPullTransaction is not in a valid format.
+
+0xC0190018
+
+STATUS_CURRENT_TRANSACTION_NOT_VALID
+
+
+The current transaction context associated with the thread is not a valid handle to a transaction object.
+
+0xC0190019
+
+STATUS_LOG_GROWTH_FAILED
+
+
+An attempt to create space in the transactional resource manager's log failed. The failure status has been recorded in the event log.
+
+0xC0190021
+
+STATUS_OBJECT_NO_LONGER_EXISTS
+
+
+The object (file, stream, or link) that corresponds to the handle has been deleted by a transaction savepoint rollback.
+
+0xC0190022
+
+STATUS_STREAM_MINIVERSION_NOT_FOUND
+
+
+The specified file miniversion was not found for this transacted file open.
+
+0xC0190023
+
+STATUS_STREAM_MINIVERSION_NOT_VALID
+
+
+The specified file miniversion was found but has been invalidated. The most likely cause is a transaction savepoint rollback.
+
+0xC0190024
+
+STATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION
+
+
+A miniversion can be opened only in the context of the transaction that created it.
+
+0xC0190025
+
+STATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT
+
+
+It is not possible to open a miniversion with modify access.
+
+0xC0190026
+
+STATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS
+
+
+It is not possible to create any more miniversions for this stream.
+
+0xC0190028
+
+STATUS_HANDLE_NO_LONGER_VALID
+
+
+The handle has been invalidated by a transaction. The most likely cause is the presence of memory mapping on a file or an open handle when the transaction ended or rolled back to savepoint.
+
+0xC0190030
+
+STATUS_LOG_CORRUPTION_DETECTED
+
+
+The log data is corrupt.
+
+0xC0190032
+
+STATUS_RM_DISCONNECTED
+
+
+The transaction outcome is unavailable because the resource manager responsible for it is disconnected.
+
+0xC0190033
+
+STATUS_ENLISTMENT_NOT_SUPERIOR
+
+
+The request was rejected because the enlistment in question is not a superior enlistment.
+
+0xC0190036
+
+STATUS_FILE_IDENTITY_NOT_PERSISTENT
+
+
+The file cannot be opened in a transaction because its identity depends on the outcome of an unresolved transaction.
+
+0xC0190037
+
+STATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY
+
+
+The operation cannot be performed because another transaction is depending on this property not changing.
+
+0xC0190038
+
+STATUS_CANT_CROSS_RM_BOUNDARY
+
+
+The operation would involve a single file with two transactional resource managers and is, therefore, not allowed.
+
+0xC0190039
+
+STATUS_TXF_DIR_NOT_EMPTY
+
+
+The $Txf directory must be empty for this operation to succeed.
+
+0xC019003A
+
+STATUS_INDOUBT_TRANSACTIONS_EXIST
+
+
+The operation would leave a transactional resource manager in an inconsistent state and is therefore not allowed.
+
+0xC019003B
+
+STATUS_TM_VOLATILE
+
+
+The operation could not be completed because the transaction manager does not have a log.
+
+0xC019003C
+
+STATUS_ROLLBACK_TIMER_EXPIRED
+
+
+A rollback could not be scheduled because a previously scheduled rollback has already executed or been queued for execution.
+
+0xC019003D
+
+STATUS_TXF_ATTRIBUTE_CORRUPT
+
+
+The transactional metadata attribute on the file or directory %hs is corrupt and unreadable.
+
+0xC019003E
+
+STATUS_EFS_NOT_ALLOWED_IN_TRANSACTION
+
+
+The encryption operation could not be completed because a transaction is active.
+
+0xC019003F
+
+STATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED
+
+
+This object is not allowed to be opened in a transaction.
+
+0xC0190040
+
+STATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE
+
+
+Memory mapping (creating a mapped section) a remote file under a transaction is not supported.
+
+0xC0190043
+
+STATUS_TRANSACTION_REQUIRED_PROMOTION
+
+
+Promotion was required to allow the resource manager to enlist, but the transaction was set to disallow it.
+
+0xC0190044
+
+STATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION
+
+
+This file is open for modification in an unresolved transaction and can be opened for execute only by a transacted reader.
+
+0xC0190045
+
+STATUS_TRANSACTIONS_NOT_FROZEN
+
+
+The request to thaw frozen transactions was ignored because transactions were not previously frozen.
+
+0xC0190046
+
+STATUS_TRANSACTION_FREEZE_IN_PROGRESS
+
+
+Transactions cannot be frozen because a freeze is already in progress.
+
+0xC0190047
+
+STATUS_NOT_SNAPSHOT_VOLUME
+
+
+The target volume is not a snapshot volume. This operation is valid only on a volume mounted as a snapshot.
+
+0xC0190048
+
+STATUS_NO_SAVEPOINT_WITH_OPEN_FILES
+
+
+The savepoint operation failed because files are open on the transaction, which is not permitted.
+
+0xC0190049
+
+STATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION
+
+
+The sparse operation could not be completed because a transaction is active on the file.
+
+0xC019004A
+
+STATUS_TM_IDENTITY_MISMATCH
+
+
+The call to create a transaction manager object failed because the Tm Identity that is stored in the log file does not match the Tm Identity that was passed in as an argument.
+
+0xC019004B
+
+STATUS_FLOATED_SECTION
+
+
+I/O was attempted on a section object that has been floated as a result of a transaction ending. There is no valid data.
+
+0xC019004C
+
+STATUS_CANNOT_ACCEPT_TRANSACTED_WORK
+
+
+The transactional resource manager cannot currently accept transacted work due to a transient condition, such as low resources.
+
+0xC019004D
+
+STATUS_CANNOT_ABORT_TRANSACTIONS
+
+
+The transactional resource manager had too many transactions outstanding that could not be aborted. The transactional resource manager has been shut down.
+
+0xC019004E
+
+STATUS_TRANSACTION_NOT_FOUND
+
+
+The specified transaction was unable to be opened because it was not found.
+
+0xC019004F
+
+STATUS_RESOURCEMANAGER_NOT_FOUND
+
+
+The specified resource manager was unable to be opened because it was not found.
+
+0xC0190050
+
+STATUS_ENLISTMENT_NOT_FOUND
+
+
+The specified enlistment was unable to be opened because it was not found.
+
+0xC0190051
+
+STATUS_TRANSACTIONMANAGER_NOT_FOUND
+
+
+The specified transaction manager was unable to be opened because it was not found.
+
+0xC0190052
+
+STATUS_TRANSACTIONMANAGER_NOT_ONLINE
+
+
+The specified resource manager was unable to create an enlistment because its associated transaction manager is not online.
+
+0xC0190053
+
+STATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION
+
+
+The specified transaction manager was unable to create the objects contained in its log file in the Ob namespace. Therefore, the transaction manager was unable to recover.
+
+0xC0190054
+
+STATUS_TRANSACTION_NOT_ROOT
+
+
+The call to create a superior enlistment on this transaction object could not be completed because the transaction object specified for the enlistment is a subordinate branch of the transaction. Only the root of the transaction can be enlisted as a superior.
+
+0xC0190055
+
+STATUS_TRANSACTION_OBJECT_EXPIRED
+
+
+Because the associated transaction manager or resource manager has been closed, the handle is no longer valid.
+
+0xC0190056
+
+STATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION
+
+
+The compression operation could not be completed because a transaction is active on the file.
+
+0xC0190057
+
+STATUS_TRANSACTION_RESPONSE_NOT_ENLISTED
+
+
+The specified operation could not be performed on this superior enlistment because the enlistment was not created with the corresponding completion response in the NotificationMask.
+
+0xC0190058
+
+STATUS_TRANSACTION_RECORD_TOO_LONG
+
+
+The specified operation could not be performed because the record to be logged was too long. This can occur because either there are too many enlistments on this transaction or the combined RecoveryInformation being logged on behalf of those enlistments is too long.
+
+0xC0190059
+
+STATUS_NO_LINK_TRACKING_IN_TRANSACTION
+
+
+The link-tracking operation could not be completed because a transaction is active.
+
+0xC019005A
+
+STATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION
+
+
+This operation cannot be performed in a transaction.
+
+0xC019005B
+
+STATUS_TRANSACTION_INTEGRITY_VIOLATED
+
+
+The kernel transaction manager had to abort or forget the transaction because it blocked forward progress.
+
+0xC0190060
+
+STATUS_EXPIRED_HANDLE
+
+
+The handle is no longer properly associated with its transaction. It might have been opened in a transactional resource manager that was subsequently forced to restart. Please close the handle and open a new one.
+
+0xC0190061
+
+STATUS_TRANSACTION_NOT_ENLISTED
+
+
+The specified operation could not be performed because the resource manager is not enlisted in the transaction.
+
+0xC01A0001
+
+STATUS_LOG_SECTOR_INVALID
+
+
+The log service found an invalid log sector.
+
+0xC01A0002
+
+STATUS_LOG_SECTOR_PARITY_INVALID
+
+
+The log service encountered a log sector with invalid block parity.
+
+0xC01A0003
+
+STATUS_LOG_SECTOR_REMAPPED
+
+
+The log service encountered a remapped log sector.
+
+0xC01A0004
+
+STATUS_LOG_BLOCK_INCOMPLETE
+
+
+The log service encountered a partial or incomplete log block.
+
+0xC01A0005
+
+STATUS_LOG_INVALID_RANGE
+
+
+The log service encountered an attempt to access data outside the active log range.
+
+0xC01A0006
+
+STATUS_LOG_BLOCKS_EXHAUSTED
+
+
+The log service user-log marshaling buffers are exhausted.
+
+0xC01A0007
+
+STATUS_LOG_READ_CONTEXT_INVALID
+
+
+The log service encountered an attempt to read from a marshaling area with an invalid read context.
+
+0xC01A0008
+
+STATUS_LOG_RESTART_INVALID
+
+
+The log service encountered an invalid log restart area.
+
+0xC01A0009
+
+STATUS_LOG_BLOCK_VERSION
+
+
+The log service encountered an invalid log block version.
+
+0xC01A000A
+
+STATUS_LOG_BLOCK_INVALID
+
+
+The log service encountered an invalid log block.
+
+0xC01A000B
+
+STATUS_LOG_READ_MODE_INVALID
+
+
+The log service encountered an attempt to read the log with an invalid read mode.
+
+0xC01A000D
+
+STATUS_LOG_METADATA_CORRUPT
+
+
+The log service encountered a corrupted metadata file.
+
+0xC01A000E
+
+STATUS_LOG_METADATA_INVALID
+
+
+The log service encountered a metadata file that could not be created by the log file system.
+
+0xC01A000F
+
+STATUS_LOG_METADATA_INCONSISTENT
+
+
+The log service encountered a metadata file with inconsistent data.
+
+0xC01A0010
+
+STATUS_LOG_RESERVATION_INVALID
+
+
+The log service encountered an attempt to erroneously allocate or dispose reservation space.
+
+0xC01A0011
+
+STATUS_LOG_CANT_DELETE
+
+
+The log service cannot delete the log file or the file system container.
+
+0xC01A0012
+
+STATUS_LOG_CONTAINER_LIMIT_EXCEEDED
+
+
+The log service has reached the maximum allowable containers allocated to a log file.
+
+0xC01A0013
+
+STATUS_LOG_START_OF_LOG
+
+
+The log service has attempted to read or write backward past the start of the log.
+
+0xC01A0014
+
+STATUS_LOG_POLICY_ALREADY_INSTALLED
+
+
+The log policy could not be installed because a policy of the same type is already present.
+
+0xC01A0015
+
+STATUS_LOG_POLICY_NOT_INSTALLED
+
+
+The log policy in question was not installed at the time of the request.
+
+0xC01A0016
+
+STATUS_LOG_POLICY_INVALID
+
+
+The installed set of policies on the log is invalid.
+
+0xC01A0017
+
+STATUS_LOG_POLICY_CONFLICT
+
+
+A policy on the log in question prevented the operation from completing.
+
+0xC01A0018
+
+STATUS_LOG_PINNED_ARCHIVE_TAIL
+
+
+The log space cannot be reclaimed because the log is pinned by the archive tail.
+
+0xC01A0019
+
+STATUS_LOG_RECORD_NONEXISTENT
+
+
+The log record is not a record in the log file.
+
+0xC01A001A
+
+STATUS_LOG_RECORDS_RESERVED_INVALID
+
+
+The number of reserved log records or the adjustment of the number of reserved log records is invalid.
+
+0xC01A001B
+
+STATUS_LOG_SPACE_RESERVED_INVALID
+
+
+The reserved log space or the adjustment of the log space is invalid.
+
+0xC01A001C
+
+STATUS_LOG_TAIL_INVALID
+
+
+A new or existing archive tail or the base of the active log is invalid.
+
+0xC01A001D
+
+STATUS_LOG_FULL
+
+
+The log space is exhausted.
+
+0xC01A001E
+
+STATUS_LOG_MULTIPLEXED
+
+
+The log is multiplexed; no direct writes to the physical log are allowed.
+
+0xC01A001F
+
+STATUS_LOG_DEDICATED
+
+
+The operation failed because the log is dedicated.
+
+0xC01A0020
+
+STATUS_LOG_ARCHIVE_NOT_IN_PROGRESS
+
+
+The operation requires an archive context.
+
+0xC01A0021
+
+STATUS_LOG_ARCHIVE_IN_PROGRESS
+
+
+Log archival is in progress.
+
+0xC01A0022
+
+STATUS_LOG_EPHEMERAL
+
+
+The operation requires a nonephemeral log, but the log is ephemeral.
+
+0xC01A0023
+
+STATUS_LOG_NOT_ENOUGH_CONTAINERS
+
+
+The log must have at least two containers before it can be read from or written to.
+
+0xC01A0024
+
+STATUS_LOG_CLIENT_ALREADY_REGISTERED
+
+
+A log client has already registered on the stream.
+
+0xC01A0025
+
+STATUS_LOG_CLIENT_NOT_REGISTERED
+
+
+A log client has not been registered on the stream.
+
+0xC01A0026
+
+STATUS_LOG_FULL_HANDLER_IN_PROGRESS
+
+
+A request has already been made to handle the log full condition.
+
+0xC01A0027
+
+STATUS_LOG_CONTAINER_READ_FAILED
+
+
+The log service encountered an error when attempting to read from a log container.
+
+0xC01A0028
+
+STATUS_LOG_CONTAINER_WRITE_FAILED
+
+
+The log service encountered an error when attempting to write to a log container.
+
+0xC01A0029
+
+STATUS_LOG_CONTAINER_OPEN_FAILED
+
+
+The log service encountered an error when attempting to open a log container.
+
+0xC01A002A
+
+STATUS_LOG_CONTAINER_STATE_INVALID
+
+
+The log service encountered an invalid container state when attempting a requested action.
+
+0xC01A002B
+
+STATUS_LOG_STATE_INVALID
+
+
+The log service is not in the correct state to perform a requested action.
+
+0xC01A002C
+
+STATUS_LOG_PINNED
+
+
+The log space cannot be reclaimed because the log is pinned.
+
+0xC01A002D
+
+STATUS_LOG_METADATA_FLUSH_FAILED
+
+
+The log metadata flush failed.
+
+0xC01A002E
+
+STATUS_LOG_INCONSISTENT_SECURITY
+
+
+Security on the log and its containers is inconsistent.
+
+0xC01A002F
+
+STATUS_LOG_APPENDED_FLUSH_FAILED
+
+
+Records were appended to the log or reservation changes were made, but the log could not be flushed.
+
+0xC01A0030
+
+STATUS_LOG_PINNED_RESERVATION
+
+
+The log is pinned due to reservation consuming most of the log space. Free some reserved records to make space available.
+
+0xC01B00EA
+
+STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD
+
+
+{Display Driver Stopped Responding} The %hs display driver has stopped working normally. Save your work and reboot the system to restore full display functionality. The next time you reboot the computer, a dialog box will allow you to upload data about this failure to Microsoft.
+
+0xC01C0001
+
+STATUS_FLT_NO_HANDLER_DEFINED
+
+
+A handler was not defined by the filter for this operation.
+
+0xC01C0002
+
+STATUS_FLT_CONTEXT_ALREADY_DEFINED
+
+
+A context is already defined for this object.
+
+0xC01C0003
+
+STATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST
+
+
+Asynchronous requests are not valid for this operation.
+
+0xC01C0004
+
+STATUS_FLT_DISALLOW_FAST_IO
+
+
+This is an internal error code used by the filter manager to determine if a fast I/O operation should be forced down the input/output request packet (IRP) path. Minifilters should never return this value.
+
+0xC01C0005
+
+STATUS_FLT_INVALID_NAME_REQUEST
+
+
+An invalid name request was made. The name requested cannot be retrieved at this time.
+
+0xC01C0006
+
+STATUS_FLT_NOT_SAFE_TO_POST_OPERATION
+
+
+Posting this operation to a worker thread for further processing is not safe at this time because it could lead to a system deadlock.
+
+0xC01C0007
+
+STATUS_FLT_NOT_INITIALIZED
+
+
+The Filter Manager was not initialized when a filter tried to register. Make sure that the Filter Manager is loaded as a driver.
+
+0xC01C0008
+
+STATUS_FLT_FILTER_NOT_READY
+
+
+The filter is not ready for attachment to volumes because it has not finished initializing (FltStartFiltering has not been called).
+
+0xC01C0009
+
+STATUS_FLT_POST_OPERATION_CLEANUP
+
+
+The filter must clean up any operation-specific context at this time because it is being removed from the system before the operation is completed by the lower drivers.
+
+0xC01C000A
+
+STATUS_FLT_INTERNAL_ERROR
+
+
+The Filter Manager had an internal error from which it cannot recover; therefore, the operation has failed. This is usually the result of a filter returning an invalid value from a pre-operation callback.
+
+0xC01C000B
+
+STATUS_FLT_DELETING_OBJECT
+
+
+The object specified for this action is in the process of being deleted; therefore, the action requested cannot be completed at this time.
+
+0xC01C000C
+
+STATUS_FLT_MUST_BE_NONPAGED_POOL
+
+
+A nonpaged pool must be used for this type of context.
+
+0xC01C000D
+
+STATUS_FLT_DUPLICATE_ENTRY
+
+
+A duplicate handler definition has been provided for an operation.
+
+0xC01C000E
+
+STATUS_FLT_CBDQ_DISABLED
+
+
+The callback data queue has been disabled.
+
+0xC01C000F
+
+STATUS_FLT_DO_NOT_ATTACH
+
+
+Do not attach the filter to the volume at this time.
+
+0xC01C0010
+
+STATUS_FLT_DO_NOT_DETACH
+
+
+Do not detach the filter from the volume at this time.
+
+0xC01C0011
+
+STATUS_FLT_INSTANCE_ALTITUDE_COLLISION
+
+
+An instance already exists at this altitude on the volume specified.
+
+0xC01C0012
+
+STATUS_FLT_INSTANCE_NAME_COLLISION
+
+
+An instance already exists with this name on the volume specified.
+
+0xC01C0013
+
+STATUS_FLT_FILTER_NOT_FOUND
+
+
+The system could not find the filter specified.
+
+0xC01C0014
+
+STATUS_FLT_VOLUME_NOT_FOUND
+
+
+The system could not find the volume specified.
+
+0xC01C0015
+
+STATUS_FLT_INSTANCE_NOT_FOUND
+
+
+The system could not find the instance specified.
+
+0xC01C0016
+
+STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND
+
+
+No registered context allocation definition was found for the given request.
+
+0xC01C0017
+
+STATUS_FLT_INVALID_CONTEXT_REGISTRATION
+
+
+An invalid parameter was specified during context registration.
+
+0xC01C0018
+
+STATUS_FLT_NAME_CACHE_MISS
+
+
+The name requested was not found in the Filter Manager name cache and could not be retrieved from the file system.
+
+0xC01C0019
+
+STATUS_FLT_NO_DEVICE_OBJECT
+
+
+The requested device object does not exist for the given volume.
+
+0xC01C001A
+
+STATUS_FLT_VOLUME_ALREADY_MOUNTED
+
+
+The specified volume is already mounted.
+
+0xC01C001B
+
+STATUS_FLT_ALREADY_ENLISTED
+
+
+The specified transaction context is already enlisted in a transaction.
+
+0xC01C001C
+
+STATUS_FLT_CONTEXT_ALREADY_LINKED
+
+
+The specified context is already attached to another object.
+
+0xC01C0020
+
+STATUS_FLT_NO_WAITER_FOR_REPLY
+
+
+No waiter is present for the filter's reply to this message.
+
+0xC01D0001
+
+STATUS_MONITOR_NO_DESCRIPTOR
+
+
+A monitor descriptor could not be obtained.
+
+0xC01D0002
+
+STATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT
+
+
+This release does not support the format of the obtained monitor descriptor.
+
+0xC01D0003
+
+STATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM
+
+
+The checksum of the obtained monitor descriptor is invalid.
+
+0xC01D0004
+
+STATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK
+
+
+The monitor descriptor contains an invalid standard timing block.
+
+0xC01D0005
+
+STATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED
+
+
+WMI data-block registration failed for one of the MSMonitorClass WMI subclasses.
+
+0xC01D0006
+
+STATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK
+
+
+The provided monitor descriptor block is either corrupted or does not contain the monitor's detailed serial number.
+
+0xC01D0007
+
+STATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK
+
+
+The provided monitor descriptor block is either corrupted or does not contain the monitor's user-friendly name.
+
+0xC01D0008
+
+STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA
+
+
+There is no monitor descriptor data at the specified (offset or size) region.
+
+0xC01D0009
+
+STATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK
+
+
+The monitor descriptor contains an invalid detailed timing block.
+
+0xC01D000A
+
+STATUS_MONITOR_INVALID_MANUFACTURE_DATE
+
+
+Monitor descriptor contains invalid manufacture date.
+
+0xC01E0000
+
+STATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER
+
+
+Exclusive mode ownership is needed to create an unmanaged primary allocation.
+
+0xC01E0001
+
+STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER
+
+
+The driver needs more DMA buffer space to complete the requested operation.
+
+0xC01E0002
+
+STATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER
+
+
+The specified display adapter handle is invalid.
+
+0xC01E0003
+
+STATUS_GRAPHICS_ADAPTER_WAS_RESET
+
+
+The specified display adapter and all of its state have been reset.
+
+0xC01E0004
+
+STATUS_GRAPHICS_INVALID_DRIVER_MODEL
+
+
+The driver stack does not match the expected driver model.
+
+0xC01E0005
+
+STATUS_GRAPHICS_PRESENT_MODE_CHANGED
+
+
+Present happened but ended up into the changed desktop mode.
+
+0xC01E0006
+
+STATUS_GRAPHICS_PRESENT_OCCLUDED
+
+
+Nothing to present due to desktop occlusion.
+
+0xC01E0007
+
+STATUS_GRAPHICS_PRESENT_DENIED
+
+
+Not able to present due to denial of desktop access.
+
+0xC01E0008
+
+STATUS_GRAPHICS_CANNOTCOLORCONVERT
+
+
+Not able to present with color conversion.
+
+0xC01E000B
+
+STATUS_GRAPHICS_PRESENT_REDIRECTION_DISABLED
+
+
+Present redirection is disabled (desktop windowing management subsystem is off).
+
+0xC01E000C
+
+STATUS_GRAPHICS_PRESENT_UNOCCLUDED
+
+
+Previous exclusive VidPn source owner has released its ownership
+
+0xC01E0100
+
+STATUS_GRAPHICS_NO_VIDEO_MEMORY
+
+
+Not enough video memory is available to complete the operation.
+
+0xC01E0101
+
+STATUS_GRAPHICS_CANT_LOCK_MEMORY
+
+
+Could not probe and lock the underlying memory of an allocation.
+
+0xC01E0102
+
+STATUS_GRAPHICS_ALLOCATION_BUSY
+
+
+The allocation is currently busy.
+
+0xC01E0103
+
+STATUS_GRAPHICS_TOO_MANY_REFERENCES
+
+
+An object being referenced has already reached the maximum reference count and cannot be referenced further.
+
+0xC01E0104
+
+STATUS_GRAPHICS_TRY_AGAIN_LATER
+
+
+A problem could not be solved due to an existing condition. Try again later.
+
+0xC01E0105
+
+STATUS_GRAPHICS_TRY_AGAIN_NOW
+
+
+A problem could not be solved due to an existing condition. Try again now.
+
+0xC01E0106
+
+STATUS_GRAPHICS_ALLOCATION_INVALID
+
+
+The allocation is invalid.
+
+0xC01E0107
+
+STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE
+
+
+No more unswizzling apertures are currently available.
+
+0xC01E0108
+
+STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED
+
+
+The current allocation cannot be unswizzled by an aperture.
+
+0xC01E0109
+
+STATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION
+
+
+The request failed because a pinned allocation cannot be evicted.
+
+0xC01E0110
+
+STATUS_GRAPHICS_INVALID_ALLOCATION_USAGE
+
+
+The allocation cannot be used from its current segment location for the specified operation.
+
+0xC01E0111
+
+STATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION
+
+
+A locked allocation cannot be used in the current command buffer.
+
+0xC01E0112
+
+STATUS_GRAPHICS_ALLOCATION_CLOSED
+
+
+The allocation being referenced has been closed permanently.
+
+0xC01E0113
+
+STATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE
+
+
+An invalid allocation instance is being referenced.
+
+0xC01E0114
+
+STATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE
+
+
+An invalid allocation handle is being referenced.
+
+0xC01E0115
+
+STATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE
+
+
+The allocation being referenced does not belong to the current device.
+
+0xC01E0116
+
+STATUS_GRAPHICS_ALLOCATION_CONTENT_LOST
+
+
+The specified allocation lost its content.
+
+0xC01E0200
+
+STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE
+
+
+A GPU exception was detected on the given device. The device cannot be scheduled.
+
+0xC01E0300
+
+STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY
+
+
+The specified VidPN topology is invalid.
+
+0xC01E0301
+
+STATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED
+
+
+The specified VidPN topology is valid but is not supported by this model of the display adapter.
+
+0xC01E0302
+
+STATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED
+
+
+The specified VidPN topology is valid but is not currently supported by the display adapter due to allocation of its resources.
+
+0xC01E0303
+
+STATUS_GRAPHICS_INVALID_VIDPN
+
+
+The specified VidPN handle is invalid.
+
+0xC01E0304
+
+STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE
+
+
+The specified video present source is invalid.
+
+0xC01E0305
+
+STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET
+
+
+The specified video present target is invalid.
+
+0xC01E0306
+
+STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED
+
+
+The specified VidPN modality is not supported (for example, at least two of the pinned modes are not co-functional).
+
+0xC01E0308
+
+STATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET
+
+
+The specified VidPN source mode set is invalid.
+
+0xC01E0309
+
+STATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET
+
+
+The specified VidPN target mode set is invalid.
+
+0xC01E030A
+
+STATUS_GRAPHICS_INVALID_FREQUENCY
+
+
+The specified video signal frequency is invalid.
+
+0xC01E030B
+
+STATUS_GRAPHICS_INVALID_ACTIVE_REGION
+
+
+The specified video signal active region is invalid.
+
+0xC01E030C
+
+STATUS_GRAPHICS_INVALID_TOTAL_REGION
+
+
+The specified video signal total region is invalid.
+
+0xC01E0310
+
+STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE
+
+
+The specified video present source mode is invalid.
+
+0xC01E0311
+
+STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE
+
+
+The specified video present target mode is invalid.
+
+0xC01E0312
+
+STATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET
+
+
+The pinned mode must remain in the set on the VidPN's co-functional modality enumeration.
+
+0xC01E0313
+
+STATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY
+
+
+The specified video present path is already in the VidPN's topology.
+
+0xC01E0314
+
+STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET
+
+
+The specified mode is already in the mode set.
+
+0xC01E0315
+
+STATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET
+
+
+The specified video present source set is invalid.
+
+0xC01E0316
+
+STATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET
+
+
+The specified video present target set is invalid.
+
+0xC01E0317
+
+STATUS_GRAPHICS_SOURCE_ALREADY_IN_SET
+
+
+The specified video present source is already in the video present source set.
+
+0xC01E0318
+
+STATUS_GRAPHICS_TARGET_ALREADY_IN_SET
+
+
+The specified video present target is already in the video present target set.
+
+0xC01E0319
+
+STATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH
+
+
+The specified VidPN present path is invalid.
+
+0xC01E031A
+
+STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY
+
+
+The miniport has no recommendation for augmenting the specified VidPN's topology.
+
+0xC01E031B
+
+STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET
+
+
+The specified monitor frequency range set is invalid.
+
+0xC01E031C
+
+STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE
+
+
+The specified monitor frequency range is invalid.
+
+0xC01E031D
+
+STATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET
+
+
+The specified frequency range is not in the specified monitor frequency range set.
+
+0xC01E031F
+
+STATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET
+
+
+The specified frequency range is already in the specified monitor frequency range set.
+
+0xC01E0320
+
+STATUS_GRAPHICS_STALE_MODESET
+
+
+The specified mode set is stale. Reacquire the new mode set.
+
+0xC01E0321
+
+STATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET
+
+
+The specified monitor source mode set is invalid.
+
+0xC01E0322
+
+STATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE
+
+
+The specified monitor source mode is invalid.
+
+0xC01E0323
+
+STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN
+
+
+The miniport does not have a recommendation regarding the request to provide a functional VidPN given the current display adapter configuration.
+
+0xC01E0324
+
+STATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE
+
+
+The ID of the specified mode is being used by another mode in the set.
+
+0xC01E0325
+
+STATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION
+
+
+The system failed to determine a mode that is supported by both the display adapter and the monitor connected to it.
+
+0xC01E0326
+
+STATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES
+
+
+The number of video present targets must be greater than or equal to the number of video present sources.
+
+0xC01E0327
+
+STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY
+
+
+The specified present path is not in the VidPN's topology.
+
+0xC01E0328
+
+STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE
+
+
+The display adapter must have at least one video present source.
+
+0xC01E0329
+
+STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET
+
+
+The display adapter must have at least one video present target.
+
+0xC01E032A
+
+STATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET
+
+
+The specified monitor descriptor set is invalid.
+
+0xC01E032B
+
+STATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR
+
+
+The specified monitor descriptor is invalid.
+
+0xC01E032C
+
+STATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET
+
+
+The specified descriptor is not in the specified monitor descriptor set.
+
+0xC01E032D
+
+STATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET
+
+
+The specified descriptor is already in the specified monitor descriptor set.
+
+0xC01E032E
+
+STATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE
+
+
+The ID of the specified monitor descriptor is being used by another descriptor in the set.
+
+0xC01E032F
+
+STATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE
+
+
+The specified video present target subset type is invalid.
+
+0xC01E0330
+
+STATUS_GRAPHICS_RESOURCES_NOT_RELATED
+
+
+Two or more of the specified resources are not related to each other, as defined by the interface semantics.
+
+0xC01E0331
+
+STATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE
+
+
+The ID of the specified video present source is being used by another source in the set.
+
+0xC01E0332
+
+STATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE
+
+
+The ID of the specified video present target is being used by another target in the set.
+
+0xC01E0333
+
+STATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET
+
+
+The specified VidPN source cannot be used because there is no available VidPN target to connect it to.
+
+0xC01E0334
+
+STATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER
+
+
+The newly arrived monitor could not be associated with a display adapter.
+
+0xC01E0335
+
+STATUS_GRAPHICS_NO_VIDPNMGR
+
+
+The particular display adapter does not have an associated VidPN manager.
+
+0xC01E0336
+
+STATUS_GRAPHICS_NO_ACTIVE_VIDPN
+
+
+The VidPN manager of the particular display adapter does not have an active VidPN.
+
+0xC01E0337
+
+STATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY
+
+
+The specified VidPN topology is stale; obtain the new topology.
+
+0xC01E0338
+
+STATUS_GRAPHICS_MONITOR_NOT_CONNECTED
+
+
+No monitor is connected on the specified video present target.
+
+0xC01E0339
+
+STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY
+
+
+The specified source is not part of the specified VidPN's topology.
+
+0xC01E033A
+
+STATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE
+
+
+The specified primary surface size is invalid.
+
+0xC01E033B
+
+STATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE
+
+
+The specified visible region size is invalid.
+
+0xC01E033C
+
+STATUS_GRAPHICS_INVALID_STRIDE
+
+
+The specified stride is invalid.
+
+0xC01E033D
+
+STATUS_GRAPHICS_INVALID_PIXELFORMAT
+
+
+The specified pixel format is invalid.
+
+0xC01E033E
+
+STATUS_GRAPHICS_INVALID_COLORBASIS
+
+
+The specified color basis is invalid.
+
+0xC01E033F
+
+STATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE
+
+
+The specified pixel value access mode is invalid.
+
+0xC01E0340
+
+STATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY
+
+
+The specified target is not part of the specified VidPN's topology.
+
+0xC01E0341
+
+STATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT
+
+
+Failed to acquire the display mode management interface.
+
+0xC01E0342
+
+STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE
+
+
+The specified VidPN source is already owned by a DMM client and cannot be used until that client releases it.
+
+0xC01E0343
+
+STATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN
+
+
+The specified VidPN is active and cannot be accessed.
+
+0xC01E0344
+
+STATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL
+
+
+The specified VidPN's present path importance ordinal is invalid.
+
+0xC01E0345
+
+STATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION
+
+
+The specified VidPN's present path content geometry transformation is invalid.
+
+0xC01E0346
+
+STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED
+
+
+The specified content geometry transformation is not supported on the respective VidPN present path.
+
+0xC01E0347
+
+STATUS_GRAPHICS_INVALID_GAMMA_RAMP
+
+
+The specified gamma ramp is invalid.
+
+0xC01E0348
+
+STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED
+
+
+The specified gamma ramp is not supported on the respective VidPN present path.
+
+0xC01E0349
+
+STATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED
+
+
+Multisampling is not supported on the respective VidPN present path.
+
+0xC01E034A
+
+STATUS_GRAPHICS_MODE_NOT_IN_MODESET
+
+
+The specified mode is not in the specified mode set.
+
+0xC01E034D
+
+STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON
+
+
+The specified VidPN topology recommendation reason is invalid.
+
+0xC01E034E
+
+STATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE
+
+
+The specified VidPN present path content type is invalid.
+
+0xC01E034F
+
+STATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE
+
+
+The specified VidPN present path copy protection type is invalid.
+
+0xC01E0350
+
+STATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS
+
+
+Only one unassigned mode set can exist at any one time for a particular VidPN source or target.
+
+0xC01E0352
+
+STATUS_GRAPHICS_INVALID_SCANLINE_ORDERING
+
+
+The specified scan line ordering type is invalid.
+
+0xC01E0353
+
+STATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED
+
+
+The topology changes are not allowed for the specified VidPN.
+
+0xC01E0354
+
+STATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS
+
+
+All available importance ordinals are being used in the specified topology.
+
+0xC01E0355
+
+STATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT
+
+
+The specified primary surface has a different private-format attribute than the current primary surface.
+
+0xC01E0356
+
+STATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM
+
+
+The specified mode-pruning algorithm is invalid.
+
+0xC01E0357
+
+STATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN
+
+
+The specified monitor-capability origin is invalid.
+
+0xC01E0358
+
+STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT
+
+
+The specified monitor-frequency range constraint is invalid.
+
+0xC01E0359
+
+STATUS_GRAPHICS_MAX_NUM_PATHS_REACHED
+
+
+The maximum supported number of present paths has been reached.
+
+0xC01E035A
+
+STATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION
+
+
+The miniport requested that augmentation be canceled for the specified source of the specified VidPN's topology.
+
+0xC01E035B
+
+STATUS_GRAPHICS_INVALID_CLIENT_TYPE
+
+
+The specified client type was not recognized.
+
+0xC01E035C
+
+STATUS_GRAPHICS_CLIENTVIDPN_NOT_SET
+
+
+The client VidPN is not set on this adapter (for example, no user mode-initiated mode changes have taken place on this adapter).
+
+0xC01E0400
+
+STATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED
+
+
+The specified display adapter child device already has an external device connected to it.
+
+0xC01E0401
+
+STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED
+
+
+The display adapter child device does not support reporting a descriptor.
+
+0xC01E0430
+
+STATUS_GRAPHICS_NOT_A_LINKED_ADAPTER
+
+
+The display adapter is not linked to any other adapters.
+
+0xC01E0431
+
+STATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED
+
+
+The lead adapter in a linked configuration was not enumerated yet.
+
+0xC01E0432
+
+STATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED
+
+
+Some chain adapters in a linked configuration have not yet been enumerated.
+
+0xC01E0433
+
+STATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY
+
+
+The chain of linked adapters is not ready to start because of an unknown failure.
+
+0xC01E0434
+
+STATUS_GRAPHICS_CHAINLINKS_NOT_STARTED
+
+
+An attempt was made to start a lead link display adapter when the chain links had not yet started.
+
+0xC01E0435
+
+STATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON
+
+
+An attempt was made to turn on a lead link display adapter when the chain links were turned off.
+
+0xC01E0436
+
+STATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE
+
+
+The adapter link was found in an inconsistent state. Not all adapters are in an expected PNP/power state.
+
+0xC01E0438
+
+STATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER
+
+
+The driver trying to start is not the same as the driver for the posted display adapter.
+
+0xC01E043B
+
+STATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED
+
+
+An operation is being attempted that requires the display adapter to be in a quiescent state.
+
+0xC01E0500
+
+STATUS_GRAPHICS_OPM_NOT_SUPPORTED
+
+
+The driver does not support OPM.
+
+0xC01E0501
+
+STATUS_GRAPHICS_COPP_NOT_SUPPORTED
+
+
+The driver does not support COPP.
+
+0xC01E0502
+
+STATUS_GRAPHICS_UAB_NOT_SUPPORTED
+
+
+The driver does not support UAB.
+
+0xC01E0503
+
+STATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS
+
+
+The specified encrypted parameters are invalid.
+
+0xC01E0504
+
+STATUS_GRAPHICS_OPM_PARAMETER_ARRAY_TOO_SMALL
+
+
+An array passed to a function cannot hold all of the data that the function wants to put in it.
+
+0xC01E0505
+
+STATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST
+
+
+The GDI display device passed to this function does not have any active protected outputs.
+
+0xC01E0506
+
+STATUS_GRAPHICS_PVP_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME
+
+
+The PVP cannot find an actual GDI display device that corresponds to the passed-in GDI display device name.
+
+0xC01E0507
+
+STATUS_GRAPHICS_PVP_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP
+
+
+This function failed because the GDI display device passed to it was not attached to the Windows desktop.
+
+0xC01E0508
+
+STATUS_GRAPHICS_PVP_MIRRORING_DEVICES_NOT_SUPPORTED
+
+
+The PVP does not support mirroring display devices because they do not have any protected outputs.
+
+0xC01E050A
+
+STATUS_GRAPHICS_OPM_INVALID_POINTER
+
+
+The function failed because an invalid pointer parameter was passed to it. A pointer parameter is invalid if it is null, is not correctly aligned, or it points to an invalid address or a kernel mode address.
+
+0xC01E050B
+
+STATUS_GRAPHICS_OPM_INTERNAL_ERROR
+
+
+An internal error caused an operation to fail.
+
+0xC01E050C
+
+STATUS_GRAPHICS_OPM_INVALID_HANDLE
+
+
+The function failed because the caller passed in an invalid OPM user-mode handle.
+
+0xC01E050D
+
+STATUS_GRAPHICS_PVP_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE
+
+
+This function failed because the GDI device passed to it did not have any monitors associated with it.
+
+0xC01E050E
+
+STATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH
+
+
+A certificate could not be returned because the certificate buffer passed to the function was too small.
+
+0xC01E050F
+
+STATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED
+
+
+DxgkDdiOpmCreateProtectedOutput() could not create a protected output because the video present yarget is in spanning mode.
+
+0xC01E0510
+
+STATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED
+
+
+DxgkDdiOpmCreateProtectedOutput() could not create a protected output because the video present target is in theater mode.
+
+0xC01E0511
+
+STATUS_GRAPHICS_PVP_HFS_FAILED
+
+
+The function call failed because the display adapter's hardware functionality scan (HFS) failed to validate the graphics hardware.
+
+0xC01E0512
+
+STATUS_GRAPHICS_OPM_INVALID_SRM
+
+
+The HDCP SRM passed to this function did not comply with section 5 of the HDCP 1.1 specification.
+
+0xC01E0513
+
+STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP
+
+
+The protected output cannot enable the HDCP system because it does not support it.
+
+0xC01E0514
+
+STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP
+
+
+The protected output cannot enable analog copy protection because it does not support it.
+
+0xC01E0515
+
+STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA
+
+
+The protected output cannot enable the CGMS-A protection technology because it does not support it.
+
+0xC01E0516
+
+STATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET
+
+
+DxgkDdiOPMGetInformation() cannot return the version of the SRM being used because the application never successfully passed an SRM to the protected output.
+
+0xC01E0517
+
+STATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH
+
+
+DxgkDdiOPMConfigureProtectedOutput() cannot enable the specified output protection technology because the output's screen resolution is too high.
+
+0xC01E0518
+
+STATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE
+
+
+DxgkDdiOPMConfigureProtectedOutput() cannot enable HDCP because other physical outputs are using the display adapter's HDCP hardware.
+
+0xC01E051A
+
+STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS
+
+
+The operating system asynchronously destroyed this OPM-protected output because the operating system state changed. This error typically occurs because the monitor PDO associated with this protected output was removed or stopped, the protected output's session became a nonconsole session, or the protected output's desktop became inactive.
+
+0xC01E051B
+
+STATUS_GRAPHICS_OPM_SESSION_TYPE_CHANGE_IN_PROGRESS
+
+
+OPM functions cannot be called when a session is changing its type. Three types of sessions currently exist: console, disconnected, and remote (RDP or ICA).
+
+0xC01E051C
+
+STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS
+
+
+The DxgkDdiOPMGetCOPPCompatibleInformation, DxgkDdiOPMGetInformation, or DxgkDdiOPMConfigureProtectedOutput function failed. This error is returned only if a protected output has OPM semantics.
+
+DxgkDdiOPMGetCOPPCompatibleInformation always returns this error if a protected output has OPM semantics.
+
+DxgkDdiOPMGetInformation returns this error code if the caller requested COPP-specific information.
+
+DxgkDdiOPMConfigureProtectedOutput returns this error when the caller tries to use a COPP-specific command.
+
+0xC01E051D
+
+STATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST
+
+
+The DxgkDdiOPMGetInformation and DxgkDdiOPMGetCOPPCompatibleInformation functions return this error code if the passed-in sequence number is not the expected sequence number or the passed-in OMAC value is invalid.
+
+0xC01E051E
+
+STATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR
+
+
+The function failed because an unexpected error occurred inside a display driver.
+
+0xC01E051F
+
+STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS
+
+
+The DxgkDdiOPMGetCOPPCompatibleInformation, DxgkDdiOPMGetInformation, or DxgkDdiOPMConfigureProtectedOutput function failed. This error is returned only if a protected output has COPP semantics.
+
+DxgkDdiOPMGetCOPPCompatibleInformation returns this error code if the caller requested OPM-specific information.
+
+DxgkDdiOPMGetInformation always returns this error if a protected output has COPP semantics.
+
+DxgkDdiOPMConfigureProtectedOutput returns this error when the caller tries to use an OPM-specific command.
+
+0xC01E0520
+
+STATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED
+
+
+The DxgkDdiOPMGetCOPPCompatibleInformation and DxgkDdiOPMConfigureProtectedOutput functions return this error if the display driver does not support the DXGKMDT_OPM_GET_ACP_AND_CGMSA_SIGNALING and DXGKMDT_OPM_SET_ACP_AND_CGMSA_SIGNALING GUIDs.
+
+0xC01E0521
+
+STATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST
+
+
+The DxgkDdiOPMConfigureProtectedOutput function returns this error code if the passed-in sequence number is not the expected sequence number or the passed-in OMAC value is invalid.
+
+0xC01E0580
+
+STATUS_GRAPHICS_I2C_NOT_SUPPORTED
+
+
+The monitor connected to the specified video output does not have an I2C bus.
+
+0xC01E0581
+
+STATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST
+
+
+No device on the I2C bus has the specified address.
+
+0xC01E0582
+
+STATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA
+
+
+An error occurred while transmitting data to the device on the I2C bus.
+
+0xC01E0583
+
+STATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA
+
+
+An error occurred while receiving data from the device on the I2C bus.
+
+0xC01E0584
+
+STATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED
+
+
+The monitor does not support the specified VCP code.
+
+0xC01E0585
+
+STATUS_GRAPHICS_DDCCI_INVALID_DATA
+
+
+The data received from the monitor is invalid.
+
+0xC01E0586
+
+STATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE
+
+
+A function call failed because a monitor returned an invalid timing status byte when the operating system used the DDC/CI get timing report and timing message command to get a timing report from a monitor.
+
+0xC01E0587
+
+STATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING
+
+
+A monitor returned a DDC/CI capabilities string that did not comply with the ACCESS.bus 3.0, DDC/CI 1.1, or MCCS 2 Revision 1 specification.
+
+0xC01E0588
+
+STATUS_GRAPHICS_MCA_INTERNAL_ERROR
+
+
+An internal error caused an operation to fail.
+
+0xC01E0589
+
+STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND
+
+
+An operation failed because a DDC/CI message had an invalid value in its command field.
+
+0xC01E058A
+
+STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH
+
+
+This error occurred because a DDC/CI message had an invalid value in its length field.
+
+0xC01E058B
+
+STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM
+
+
+This error occurred because the value in a DDC/CI message's checksum field did not match the message's computed checksum value. This error implies that the data was corrupted while it was being transmitted from a monitor to a computer.
+
+0xC01E058C
+
+STATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE
+
+
+This function failed because an invalid monitor handle was passed to it.
+
+0xC01E058D
+
+STATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS
+
+
+The operating system asynchronously destroyed the monitor that corresponds to this handle because the operating system's state changed. This error typically occurs because the monitor PDO associated with this handle was removed or stopped, or a display mode change occurred. A display mode change occurs when Windows sends a WM_DISPLAYCHANGE message to applications.
+
+0xC01E05E0
+
+STATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED
+
+
+This function can be used only if a program is running in the local console session. It cannot be used if a program is running on a remote desktop session or on a terminal server session.
+
+0xC01E05E1
+
+STATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME
+
+
+This function cannot find an actual GDI display device that corresponds to the specified GDI display device name.
+
+0xC01E05E2
+
+STATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP
+
+
+The function failed because the specified GDI display device was not attached to the Windows desktop.
+
+0xC01E05E3
+
+STATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED
+
+
+This function does not support GDI mirroring display devices because GDI mirroring display devices do not have any physical monitors associated with them.
+
+0xC01E05E4
+
+STATUS_GRAPHICS_INVALID_POINTER
+
+
+The function failed because an invalid pointer parameter was passed to it. A pointer parameter is invalid if it is null, is not correctly aligned, or points to an invalid address or to a kernel mode address.
+
+0xC01E05E5
+
+STATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE
+
+
+This function failed because the GDI device passed to it did not have a monitor associated with it.
+
+0xC01E05E6
+
+STATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL
+
+
+An array passed to the function cannot hold all of the data that the function must copy into the array.
+
+0xC01E05E7
+
+STATUS_GRAPHICS_INTERNAL_ERROR
+
+
+An internal error caused an operation to fail.
+
+0xC01E05E8
+
+STATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS
+
+
+The function failed because the current session is changing its type. This function cannot be called when the current session is changing its type. Three types of sessions currently exist: console, disconnected, and remote (RDP or ICA).
+
+0xC0210000
+
+STATUS_FVE_LOCKED_VOLUME
+
+
+The volume must be unlocked before it can be used.
+
+0xC0210001
+
+STATUS_FVE_NOT_ENCRYPTED
+
+
+The volume is fully decrypted and no key is available.
+
+0xC0210002
+
+STATUS_FVE_BAD_INFORMATION
+
+
+The control block for the encrypted volume is not valid.
+
+0xC0210003
+
+STATUS_FVE_TOO_SMALL
+
+
+Not enough free space remains on the volume to allow encryption.
+
+0xC0210004
+
+STATUS_FVE_FAILED_WRONG_FS
+
+
+The partition cannot be encrypted because the file system is not supported.
+
+0xC0210005
+
+STATUS_FVE_FAILED_BAD_FS
+
+
+The file system is inconsistent. Run the Check Disk utility.
+
+0xC0210006
+
+STATUS_FVE_FS_NOT_EXTENDED
+
+
+The file system does not extend to the end of the volume.
+
+0xC0210007
+
+STATUS_FVE_FS_MOUNTED
+
+
+This operation cannot be performed while a file system is mounted on the volume.
+
+0xC0210008
+
+STATUS_FVE_NO_LICENSE
+
+
+BitLocker Drive Encryption is not included with this version of Windows.
+
+0xC0210009
+
+STATUS_FVE_ACTION_NOT_ALLOWED
+
+
+The requested action was denied by the FVE control engine.
+
+0xC021000A
+
+STATUS_FVE_BAD_DATA
+
+
+The data supplied is malformed.
+
+0xC021000B
+
+STATUS_FVE_VOLUME_NOT_BOUND
+
+
+The volume is not bound to the system.
+
+0xC021000C
+
+STATUS_FVE_NOT_DATA_VOLUME
+
+
+The volume specified is not a data volume.
+
+0xC021000D
+
+STATUS_FVE_CONV_READ_ERROR
+
+
+A read operation failed while converting the volume.
+
+0xC021000E
+
+STATUS_FVE_CONV_WRITE_ERROR
+
+
+A write operation failed while converting the volume.
+
+0xC021000F
+
+STATUS_FVE_OVERLAPPED_UPDATE
+
+
+The control block for the encrypted volume was updated by another thread. Try again.
+
+0xC0210010
+
+STATUS_FVE_FAILED_SECTOR_SIZE
+
+
+The volume encryption algorithm cannot be used on this sector size.
+
+0xC0210011
+
+STATUS_FVE_FAILED_AUTHENTICATION
+
+
+BitLocker recovery authentication failed.
+
+0xC0210012
+
+STATUS_FVE_NOT_OS_VOLUME
+
+
+The volume specified is not the boot operating system volume.
+
+0xC0210013
+
+STATUS_FVE_KEYFILE_NOT_FOUND
+
+
+The BitLocker startup key or recovery password could not be read from external media.
+
+0xC0210014
+
+STATUS_FVE_KEYFILE_INVALID
+
+
+The BitLocker startup key or recovery password file is corrupt or invalid.
+
+0xC0210015
+
+STATUS_FVE_KEYFILE_NO_VMK
+
+
+The BitLocker encryption key could not be obtained from the startup key or the recovery password.
+
+0xC0210016
+
+STATUS_FVE_TPM_DISABLED
+
+
+The TPM is disabled.
+
+0xC0210017
+
+STATUS_FVE_TPM_SRK_AUTH_NOT_ZERO
+
+
+The authorization data for the SRK of the TPM is not zero.
+
+0xC0210018
+
+STATUS_FVE_TPM_INVALID_PCR
+
+
+The system boot information changed or the TPM locked out access to BitLocker encryption keys until the computer is restarted.
+
+0xC0210019
+
+STATUS_FVE_TPM_NO_VMK
+
+
+The BitLocker encryption key could not be obtained from the TPM.
+
+0xC021001A
+
+STATUS_FVE_PIN_INVALID
+
+
+The BitLocker encryption key could not be obtained from the TPM and PIN.
+
+0xC021001B
+
+STATUS_FVE_AUTH_INVALID_APPLICATION
+
+
+A boot application hash does not match the hash computed when BitLocker was turned on.
+
+0xC021001C
+
+STATUS_FVE_AUTH_INVALID_CONFIG
+
+
+The Boot Configuration Data (BCD) settings are not supported or have changed because BitLocker was enabled.
+
+0xC021001D
+
+STATUS_FVE_DEBUGGER_ENABLED
+
+
+Boot debugging is enabled. Run Windows Boot Configuration Data Store Editor (bcdedit.exe) to turn it off.
+
+0xC021001E
+
+STATUS_FVE_DRY_RUN_FAILED
+
+
+The BitLocker encryption key could not be obtained.
+
+0xC021001F
+
+STATUS_FVE_BAD_METADATA_POINTER
+
+
+The metadata disk region pointer is incorrect.
+
+0xC0210020
+
+STATUS_FVE_OLD_METADATA_COPY
+
+
+The backup copy of the metadata is out of date.
+
+0xC0210021
+
+STATUS_FVE_REBOOT_REQUIRED
+
+
+No action was taken because a system restart is required.
+
+0xC0210022
+
+STATUS_FVE_RAW_ACCESS
+
+
+No action was taken because BitLocker Drive Encryption is in RAW access mode.
+
+0xC0210023
+
+STATUS_FVE_RAW_BLOCKED
+
+
+BitLocker Drive Encryption cannot enter RAW access mode for this volume.
+
+0xC0210026
+
+STATUS_FVE_NO_FEATURE_LICENSE
+
+
+This feature of BitLocker Drive Encryption is not included with this version of Windows.
+
+0xC0210027
+
+STATUS_FVE_POLICY_USER_DISABLE_RDV_NOT_ALLOWED
+
+
+Group policy does not permit turning off BitLocker Drive Encryption on roaming data volumes.
+
+0xC0210028
+
+STATUS_FVE_CONV_RECOVERY_FAILED
+
+
+Bitlocker Drive Encryption failed to recover from aborted conversion. This could be due to either all conversion logs being corrupted or the media being write-protected.
+
+0xC0210029
+
+STATUS_FVE_VIRTUALIZED_SPACE_TOO_BIG
+
+
+The requested virtualization size is too big.
+
+0xC0210030
+
+STATUS_FVE_VOLUME_TOO_SMALL
+
+
+The drive is too small to be protected using BitLocker Drive Encryption.
+
+0xC0220001
+
+STATUS_FWP_CALLOUT_NOT_FOUND
+
+
+The callout does not exist.
+
+0xC0220002
+
+STATUS_FWP_CONDITION_NOT_FOUND
+
+
+The filter condition does not exist.
+
+0xC0220003
+
+STATUS_FWP_FILTER_NOT_FOUND
+
+
+The filter does not exist.
+
+0xC0220004
+
+STATUS_FWP_LAYER_NOT_FOUND
+
+
+The layer does not exist.
+
+0xC0220005
+
+STATUS_FWP_PROVIDER_NOT_FOUND
+
+
+The provider does not exist.
+
+0xC0220006
+
+STATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND
+
+
+The provider context does not exist.
+
+0xC0220007
+
+STATUS_FWP_SUBLAYER_NOT_FOUND
+
+
+The sublayer does not exist.
+
+0xC0220008
+
+STATUS_FWP_NOT_FOUND
+
+
+The object does not exist.
+
+0xC0220009
+
+STATUS_FWP_ALREADY_EXISTS
+
+
+An object with that GUID or LUID already exists.
+
+0xC022000A
+
+STATUS_FWP_IN_USE
+
+
+The object is referenced by other objects and cannot be deleted.
+
+0xC022000B
+
+STATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS
+
+
+The call is not allowed from within a dynamic session.
+
+0xC022000C
+
+STATUS_FWP_WRONG_SESSION
+
+
+The call was made from the wrong session and cannot be completed.
+
+0xC022000D
+
+STATUS_FWP_NO_TXN_IN_PROGRESS
+
+
+The call must be made from within an explicit transaction.
+
+0xC022000E
+
+STATUS_FWP_TXN_IN_PROGRESS
+
+
+The call is not allowed from within an explicit transaction.
+
+0xC022000F
+
+STATUS_FWP_TXN_ABORTED
+
+
+The explicit transaction has been forcibly canceled.
+
+0xC0220010
+
+STATUS_FWP_SESSION_ABORTED
+
+
+The session has been canceled.
+
+0xC0220011
+
+STATUS_FWP_INCOMPATIBLE_TXN
+
+
+The call is not allowed from within a read-only transaction.
+
+0xC0220012
+
+STATUS_FWP_TIMEOUT
+
+
+The call timed out while waiting to acquire the transaction lock.
+
+0xC0220013
+
+STATUS_FWP_NET_EVENTS_DISABLED
+
+
+The collection of network diagnostic events is disabled.
+
+0xC0220014
+
+STATUS_FWP_INCOMPATIBLE_LAYER
+
+
+The operation is not supported by the specified layer.
+
+0xC0220015
+
+STATUS_FWP_KM_CLIENTS_ONLY
+
+
+The call is allowed for kernel-mode callers only.
+
+0xC0220016
+
+STATUS_FWP_LIFETIME_MISMATCH
+
+
+The call tried to associate two objects with incompatible lifetimes.
+
+0xC0220017
+
+STATUS_FWP_BUILTIN_OBJECT
+
+
+The object is built-in and cannot be deleted.
+
+0xC0220018
+
+STATUS_FWP_TOO_MANY_BOOTTIME_FILTERS
+
+
+The maximum number of boot-time filters has been reached.
+
+0xC0220018
+
+STATUS_FWP_TOO_MANY_CALLOUTS
+
+
+The maximum number of callouts has been reached.
+
+0xC0220019
+
+STATUS_FWP_NOTIFICATION_DROPPED
+
+
+A notification could not be delivered because a message queue has reached maximum capacity.
+
+0xC022001A
+
+STATUS_FWP_TRAFFIC_MISMATCH
+
+
+The traffic parameters do not match those for the security association context.
+
+0xC022001B
+
+STATUS_FWP_INCOMPATIBLE_SA_STATE
+
+
+The call is not allowed for the current security association state.
+
+0xC022001C
+
+STATUS_FWP_NULL_POINTER
+
+
+A required pointer is null.
+
+0xC022001D
+
+STATUS_FWP_INVALID_ENUMERATOR
+
+
+An enumerator is not valid.
+
+0xC022001E
+
+STATUS_FWP_INVALID_FLAGS
+
+
+The flags field contains an invalid value.
+
+0xC022001F
+
+STATUS_FWP_INVALID_NET_MASK
+
+
+A network mask is not valid.
+
+0xC0220020
+
+STATUS_FWP_INVALID_RANGE
+
+
+An FWP_RANGE is not valid.
+
+0xC0220021
+
+STATUS_FWP_INVALID_INTERVAL
+
+
+The time interval is not valid.
+
+0xC0220022
+
+STATUS_FWP_ZERO_LENGTH_ARRAY
+
+
+An array that must contain at least one element has a zero length.
+
+0xC0220023
+
+STATUS_FWP_NULL_DISPLAY_NAME
+
+
+The displayData.name field cannot be null.
+
+0xC0220024
+
+STATUS_FWP_INVALID_ACTION_TYPE
+
+
+The action type is not one of the allowed action types for a filter.
+
+0xC0220025
+
+STATUS_FWP_INVALID_WEIGHT
+
+
+The filter weight is not valid.
+
+0xC0220026
+
+STATUS_FWP_MATCH_TYPE_MISMATCH
+
+
+A filter condition contains a match type that is not compatible with the operands.
+
+0xC0220027
+
+STATUS_FWP_TYPE_MISMATCH
+
+
+An FWP_VALUE or FWPM_CONDITION_VALUE is of the wrong type.
+
+0xC0220028
+
+STATUS_FWP_OUT_OF_BOUNDS
+
+
+An integer value is outside the allowed range.
+
+0xC0220029
+
+STATUS_FWP_RESERVED
+
+
+A reserved field is nonzero.
+
+0xC022002A
+
+STATUS_FWP_DUPLICATE_CONDITION
+
+
+A filter cannot contain multiple conditions operating on a single field.
+
+0xC022002B
+
+STATUS_FWP_DUPLICATE_KEYMOD
+
+
+A policy cannot contain the same keying module more than once.
+
+0xC022002C
+
+STATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER
+
+
+The action type is not compatible with the layer.
+
+0xC022002D
+
+STATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER
+
+
+The action type is not compatible with the sublayer.
+
+0xC022002E
+
+STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER
+
+
+The raw context or the provider context is not compatible with the layer.
+
+0xC022002F
+
+STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT
+
+
+The raw context or the provider context is not compatible with the callout.
+
+0xC0220030
+
+STATUS_FWP_INCOMPATIBLE_AUTH_METHOD
+
+
+The authentication method is not compatible with the policy type.
+
+0xC0220031
+
+STATUS_FWP_INCOMPATIBLE_DH_GROUP
+
+
+The Diffie-Hellman group is not compatible with the policy type.
+
+0xC0220032
+
+STATUS_FWP_EM_NOT_SUPPORTED
+
+
+An IKE policy cannot contain an Extended Mode policy.
+
+0xC0220033
+
+STATUS_FWP_NEVER_MATCH
+
+
+The enumeration template or subscription will never match any objects.
+
+0xC0220034
+
+STATUS_FWP_PROVIDER_CONTEXT_MISMATCH
+
+
+The provider context is of the wrong type.
+
+0xC0220035
+
+STATUS_FWP_INVALID_PARAMETER
+
+
+The parameter is incorrect.
+
+0xC0220036
+
+STATUS_FWP_TOO_MANY_SUBLAYERS
+
+
+The maximum number of sublayers has been reached.
+
+0xC0220037
+
+STATUS_FWP_CALLOUT_NOTIFICATION_FAILED
+
+
+The notification function for a callout returned an error.
+
+0xC0220038
+
+STATUS_FWP_INCOMPATIBLE_AUTH_CONFIG
+
+
+The IPsec authentication configuration is not compatible with the authentication type.
+
+0xC0220039
+
+STATUS_FWP_INCOMPATIBLE_CIPHER_CONFIG
+
+
+The IPsec cipher configuration is not compatible with the cipher type.
+
+0xC022003C
+
+STATUS_FWP_DUPLICATE_AUTH_METHOD
+
+
+A policy cannot contain the same auth method more than once.
+
+0xC0220100
+
+STATUS_FWP_TCPIP_NOT_READY
+
+
+The TCP/IP stack is not ready.
+
+0xC0220101
+
+STATUS_FWP_INJECT_HANDLE_CLOSING
+
+
+The injection handle is being closed by another thread.
+
+0xC0220102
+
+STATUS_FWP_INJECT_HANDLE_STALE
+
+
+The injection handle is stale.
+
+0xC0220103
+
+STATUS_FWP_CANNOT_PEND
+
+
+The classify cannot be pended.
+
+0xC0230002
+
+STATUS_NDIS_CLOSING
+
+
+The binding to the network interface is being closed.
+
+0xC0230004
+
+STATUS_NDIS_BAD_VERSION
+
+
+An invalid version was specified.
+
+0xC0230005
+
+STATUS_NDIS_BAD_CHARACTERISTICS
+
+
+An invalid characteristics table was used.
+
+0xC0230006
+
+STATUS_NDIS_ADAPTER_NOT_FOUND
+
+
+Failed to find the network interface or the network interface is not ready.
+
+0xC0230007
+
+STATUS_NDIS_OPEN_FAILED
+
+
+Failed to open the network interface.
+
+0xC0230008
+
+STATUS_NDIS_DEVICE_FAILED
+
+
+The network interface has encountered an internal unrecoverable failure.
+
+0xC0230009
+
+STATUS_NDIS_MULTICAST_FULL
+
+
+The multicast list on the network interface is full.
+
+0xC023000A
+
+STATUS_NDIS_MULTICAST_EXISTS
+
+
+An attempt was made to add a duplicate multicast address to the list.
+
+0xC023000B
+
+STATUS_NDIS_MULTICAST_NOT_FOUND
+
+
+At attempt was made to remove a multicast address that was never added.
+
+0xC023000C
+
+STATUS_NDIS_REQUEST_ABORTED
+
+
+The network interface aborted the request.
+
+0xC023000D
+
+STATUS_NDIS_RESET_IN_PROGRESS
+
+
+The network interface cannot process the request because it is being reset.
+
+0xC023000F
+
+STATUS_NDIS_INVALID_PACKET
+
+
+An attempt was made to send an invalid packet on a network interface.
+
+0xC0230010
+
+STATUS_NDIS_INVALID_DEVICE_REQUEST
+
+
+The specified request is not a valid operation for the target device.
+
+0xC0230011
+
+STATUS_NDIS_ADAPTER_NOT_READY
+
+
+The network interface is not ready to complete this operation.
+
+0xC0230014
+
+STATUS_NDIS_INVALID_LENGTH
+
+
+The length of the buffer submitted for this operation is not valid.
+
+0xC0230015
+
+STATUS_NDIS_INVALID_DATA
+
+
+The data used for this operation is not valid.
+
+0xC0230016
+
+STATUS_NDIS_BUFFER_TOO_SHORT
+
+
+The length of the submitted buffer for this operation is too small.
+
+0xC0230017
+
+STATUS_NDIS_INVALID_OID
+
+
+The network interface does not support this object identifier.
+
+0xC0230018
+
+STATUS_NDIS_ADAPTER_REMOVED
+
+
+The network interface has been removed.
+
+0xC0230019
+
+STATUS_NDIS_UNSUPPORTED_MEDIA
+
+
+The network interface does not support this media type.
+
+0xC023001A
+
+STATUS_NDIS_GROUP_ADDRESS_IN_USE
+
+
+An attempt was made to remove a token ring group address that is in use by other components.
+
+0xC023001B
+
+STATUS_NDIS_FILE_NOT_FOUND
+
+
+An attempt was made to map a file that cannot be found.
+
+0xC023001C
+
+STATUS_NDIS_ERROR_READING_FILE
+
+
+An error occurred while NDIS tried to map the file.
+
+0xC023001D
+
+STATUS_NDIS_ALREADY_MAPPED
+
+
+An attempt was made to map a file that is already mapped.
+
+0xC023001E
+
+STATUS_NDIS_RESOURCE_CONFLICT
+
+
+An attempt to allocate a hardware resource failed because the resource is used by another component.
+
+0xC023001F
+
+STATUS_NDIS_MEDIA_DISCONNECTED
+
+
+The I/O operation failed because the network media is disconnected or the wireless access point is out of range.
+
+0xC0230022
+
+STATUS_NDIS_INVALID_ADDRESS
+
+
+The network address used in the request is invalid.
+
+0xC023002A
+
+STATUS_NDIS_PAUSED
+
+
+The offload operation on the network interface has been paused.
+
+0xC023002B
+
+STATUS_NDIS_INTERFACE_NOT_FOUND
+
+
+The network interface was not found.
+
+0xC023002C
+
+STATUS_NDIS_UNSUPPORTED_REVISION
+
+
+The revision number specified in the structure is not supported.
+
+0xC023002D
+
+STATUS_NDIS_INVALID_PORT
+
+
+The specified port does not exist on this network interface.
+
+0xC023002E
+
+STATUS_NDIS_INVALID_PORT_STATE
+
+
+The current state of the specified port on this network interface does not support the requested operation.
+
+0xC023002F
+
+STATUS_NDIS_LOW_POWER_STATE
+
+
+The miniport adapter is in a lower power state.
+
+0xC02300BB
+
+STATUS_NDIS_NOT_SUPPORTED
+
+
+The network interface does not support this request.
+
+0xC023100F
+
+STATUS_NDIS_OFFLOAD_POLICY
+
+
+The TCP connection is not offloadable because of a local policy setting.
+
+0xC0231012
+
+STATUS_NDIS_OFFLOAD_CONNECTION_REJECTED
+
+
+The TCP connection is not offloadable by the Chimney offload target.
+
+0xC0231013
+
+STATUS_NDIS_OFFLOAD_PATH_REJECTED
+
+
+The IP Path object is not in an offloadable state.
+
+0xC0232000
+
+STATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED
+
+
+The wireless LAN interface is in auto-configuration mode and does not support the requested parameter change operation.
+
+0xC0232001
+
+STATUS_NDIS_DOT11_MEDIA_IN_USE
+
+
+The wireless LAN interface is busy and cannot perform the requested operation.
+
+0xC0232002
+
+STATUS_NDIS_DOT11_POWER_STATE_INVALID
+
+
+The wireless LAN interface is power down and does not support the requested operation.
+
+0xC0232003
+
+STATUS_NDIS_PM_WOL_PATTERN_LIST_FULL
+
+
+The list of wake on LAN patterns is full.
+
+0xC0232004
+
+STATUS_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL
+
+
+The list of low power protocol offloads is full.
+
+0xC0360001
+
+STATUS_IPSEC_BAD_SPI
+
+
+The SPI in the packet does not match a valid IPsec SA.
+
+0xC0360002
+
+STATUS_IPSEC_SA_LIFETIME_EXPIRED
+
+
+The packet was received on an IPsec SA whose lifetime has expired.
+
+0xC0360003
+
+STATUS_IPSEC_WRONG_SA
+
+
+The packet was received on an IPsec SA that does not match the packet characteristics.
+
+0xC0360004
+
+STATUS_IPSEC_REPLAY_CHECK_FAILED
+
+
+The packet sequence number replay check failed.
+
+0xC0360005
+
+STATUS_IPSEC_INVALID_PACKET
+
+
+The IPsec header and/or trailer in the packet is invalid.
+
+0xC0360006
+
+STATUS_IPSEC_INTEGRITY_CHECK_FAILED
+
+
+The IPsec integrity check failed.
+
+0xC0360007
+
+STATUS_IPSEC_CLEAR_TEXT_DROP
+
+
+IPsec dropped a clear text packet.
+
+0xC0360008
+
+STATUS_IPSEC_AUTH_FIREWALL_DROP
+
+
+IPsec dropped an incoming ESP packet in authenticated firewall mode. This drop is benign.
+
+0xC0360009
+
+STATUS_IPSEC_THROTTLE_DROP
+
+
+IPsec dropped a packet due to DOS throttle.
+
+0xC0368000
+
+STATUS_IPSEC_DOSP_BLOCK
+
+
+IPsec Dos Protection matched an explicit block rule.
+
+0xC0368001
+
+STATUS_IPSEC_DOSP_RECEIVED_MULTICAST
+
+
+IPsec Dos Protection received an IPsec specific multicast packet which is not allowed.
+
+0xC0368002
+
+STATUS_IPSEC_DOSP_INVALID_PACKET
+
+
+IPsec Dos Protection received an incorrectly formatted packet.
+
+0xC0368003
+
+STATUS_IPSEC_DOSP_STATE_LOOKUP_FAILED
+
+
+IPsec Dos Protection failed to lookup state.
+
+0xC0368004
+
+STATUS_IPSEC_DOSP_MAX_ENTRIES
+
+
+IPsec Dos Protection failed to create state because there are already maximum number of entries allowed by policy.
+
+0xC0368005
+
+STATUS_IPSEC_DOSP_KEYMOD_NOT_ALLOWED
+
+
+IPsec Dos Protection received an IPsec negotiation packet for a keying module which is not allowed by policy.
+
+0xC0368006
+
+STATUS_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES
+
+
+IPsec Dos Protection failed to create per internal IP ratelimit queue because there is already maximum number of queues allowed by policy.
+
+0xC038005B
+
+STATUS_VOLMGR_MIRROR_NOT_SUPPORTED
+
+
+The system does not support mirrored volumes.
+
+0xC038005C
+
+STATUS_VOLMGR_RAID5_NOT_SUPPORTED
+
+
+The system does not support RAID-5 volumes.
+
+0xC03A0014
+
+STATUS_VIRTDISK_PROVIDER_NOT_FOUND
+
+
+A virtual disk support provider for the specified file was not found.
+
+0xC03A0015
+
+STATUS_VIRTDISK_NOT_VIRTUAL_DISK
+
+
+The specified disk is not a virtual disk.
+
+0xC03A0016
+
+STATUS_VHD_PARENT_VHD_ACCESS_DENIED
+
+
+The chain of virtual hard disks is inaccessible. The process has not been granted access rights to the parent virtual hard disk for the differencing disk.
+
+0xC03A0017
+
+STATUS_VHD_CHILD_PARENT_SIZE_MISMATCH
+
+
+The chain of virtual hard disks is corrupted. There is a mismatch in the virtual sizes of the parent virtual hard disk and differencing disk.
+
+0xC03A0018
+
+STATUS_VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED
+
+
+The chain of virtual hard disks is corrupted. A differencing disk is indicated in its own parent chain.
+
+0xC03A0019
+
+STATUS_VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT
+
+
+The chain of virtual hard disks is inaccessible. There was an error opening a virtual hard disk further up the chain.
diff --git a/libcli/util/tstream.c b/libcli/util/tstream.c
new file mode 100644
index 0000000..95e31ca
--- /dev/null
+++ b/libcli/util/tstream.c
@@ -0,0 +1,205 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Stefan Metzmacher 2009
+ *
+ * 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 <tevent.h>
+#include "system/filesys.h"
+#include "system/network.h"
+#include "../lib/tsocket/tsocket.h"
+#include "../libcli/util/tstream.h"
+#include "../lib/util/tevent_ntstatus.h"
+
+struct tstream_read_pdu_blob_state {
+ /* this structs are owned by the caller */
+ struct {
+ struct tevent_context *ev;
+ struct tstream_context *stream;
+ tstream_read_pdu_blob_full_fn_t *full_fn;
+ void *full_private;
+ } caller;
+
+ DATA_BLOB pdu_blob;
+ struct iovec tmp_vector;
+};
+
+static void tstream_read_pdu_blob_done(struct tevent_req *subreq);
+
+struct tevent_req *tstream_read_pdu_blob_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ size_t initial_read_size,
+ tstream_read_pdu_blob_full_fn_t *full_fn,
+ void *full_private)
+{
+ struct tevent_req *req;
+ struct tstream_read_pdu_blob_state *state;
+ struct tevent_req *subreq;
+ uint8_t *buf;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_read_pdu_blob_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->caller.ev = ev;
+ state->caller.stream = stream;
+ state->caller.full_fn = full_fn;
+ state->caller.full_private = full_private;
+
+ if (initial_read_size == 0) {
+ tevent_req_error(req, EINVAL);
+ return tevent_req_post(req, ev);
+ }
+
+ buf = talloc_array(state, uint8_t, initial_read_size);
+ if (tevent_req_nomem(buf, req)) {
+ return tevent_req_post(req, ev);
+ }
+ state->pdu_blob.data = buf;
+ state->pdu_blob.length = initial_read_size;
+
+ state->tmp_vector.iov_base = (char *) buf;
+ state->tmp_vector.iov_len = initial_read_size;
+
+ subreq = tstream_readv_send(state, ev, stream, &state->tmp_vector, 1);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, tstream_read_pdu_blob_done, req);
+
+ return req;
+}
+
+static void tstream_read_pdu_blob_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_read_pdu_blob_state *state =
+ tevent_req_data(req,
+ struct tstream_read_pdu_blob_state);
+ ssize_t ret;
+ int sys_errno;
+ size_t old_buf_size = state->pdu_blob.length;
+ size_t new_buf_size = 0;
+ size_t pdu_size = 0;
+ NTSTATUS status;
+ uint8_t *buf;
+
+ ret = tstream_readv_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ status = map_nt_error_from_unix_common(sys_errno);
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ status = state->caller.full_fn(state->caller.stream,
+ state->caller.full_private,
+ state->pdu_blob, &pdu_size);
+ if (NT_STATUS_IS_OK(status)) {
+ tevent_req_done(req);
+ return;
+ } else if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
+ /* more to get */
+ if (pdu_size > 0) {
+ new_buf_size = pdu_size;
+ } else {
+ /* we don't know the size yet, so get one more byte */
+ new_buf_size = old_buf_size + 1;
+ }
+ } else if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ 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;
+ }
+ state->pdu_blob.data = buf;
+ state->pdu_blob.length = new_buf_size;
+
+ state->tmp_vector.iov_base = (char *) (buf + old_buf_size);
+ state->tmp_vector.iov_len = new_buf_size - old_buf_size;
+
+ subreq = tstream_readv_send(state,
+ state->caller.ev,
+ state->caller.stream,
+ &state->tmp_vector,
+ 1);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, tstream_read_pdu_blob_done, req);
+}
+
+NTSTATUS tstream_read_pdu_blob_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *pdu_blob)
+{
+ struct tstream_read_pdu_blob_state *state = tevent_req_data(req,
+ struct tstream_read_pdu_blob_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ *pdu_blob = state->pdu_blob;
+ talloc_steal(mem_ctx, pdu_blob->data);
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tstream_full_request_u32(struct tstream_context *stream,
+ void *private_data,
+ DATA_BLOB blob, size_t *size)
+{
+ if (blob.length < 4) {
+ return STATUS_MORE_ENTRIES;
+ }
+ *size = 4 + RIVAL(blob.data, 0);
+ if (*size > blob.length) {
+ return STATUS_MORE_ENTRIES;
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tstream_full_request_u16(struct tstream_context *stream,
+ void *private_data,
+ DATA_BLOB blob, size_t *size)
+{
+ if (blob.length < 2) {
+ return STATUS_MORE_ENTRIES;
+ }
+ *size = 2 + RSVAL(blob.data, 0);
+ if (*size > blob.length) {
+ return STATUS_MORE_ENTRIES;
+ }
+ return NT_STATUS_OK;
+}
diff --git a/libcli/util/tstream.h b/libcli/util/tstream.h
new file mode 100644
index 0000000..cf66abe
--- /dev/null
+++ b/libcli/util/tstream.h
@@ -0,0 +1,123 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Stefan Metzmacher 2009
+ *
+ * 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/>.
+ */
+
+#ifndef _LIBCLI_UTIL_TSTREAM_H_
+#define _LIBCLI_UTIL_TSTREAM_H_
+
+/**
+ * @brief The function which will report the size of the full pdu.
+ *
+ * @param[in] stream The tstream_context to operate on
+ *
+ * @param[in] private_data Some private data which could be used.
+ *
+ * @param[in] blob The received blob to get the size from.
+ *
+ * @param[out] packet_size The pointer to store the size of the full pdu.
+ *
+ * @return NT_STATUS_OK on success, STATUS_MORE_ENTRIES if there
+ * are more entries.
+ */
+typedef NTSTATUS tstream_read_pdu_blob_full_fn_t(struct tstream_context *stream,
+ void *private_data,
+ DATA_BLOB blob,
+ size_t *packet_size);
+
+/**
+ * @brief A helper function to read a full PDU from a stream
+ *
+ * This function is designed for simple PDUs and as compat layer
+ * for the Samba4 packet interface.
+ *
+ * tstream_readv_pdu_send() is a more powerful interface,
+ * which is part of the main (non samba specific) tsocket code.
+ *
+ * @param[in] mem_ctx The memory context for the result.
+ *
+ * @param[in] ev The event context the operation should work on.
+ *
+ * @param[in] stream The stream to read data from.
+ *
+ * @param[in] initial_read_size The initial byte count that is needed to workout
+ * the full pdu size.
+ *
+ * @param[in] full_fn The callback function that will report the size
+ * of the full pdu.
+ *
+ * @param[in] full_private The private data for the callback function.
+ *
+ * @return The async request handle. NULL on fatal error.
+ *
+ * @see tstream_read_pdu_blob_recv()
+ * @see tstream_readv_pdu_send()
+ * @see tstream_readv_pdu_queue_send()
+ *
+ */
+struct tevent_req *tstream_read_pdu_blob_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ size_t initial_read_size,
+ tstream_read_pdu_blob_full_fn_t *full_fn,
+ void *full_private);
+/**
+ * @brief Receive the result of the tstream_read_pdu_blob_send() call.
+ *
+ * @param[in] req The tevent request from tstream_read_pdu_blob_send().
+ *
+ * @param[in] mem_ctx The memory context for returned pdu DATA_BLOB.
+ *
+ * @param[in] pdu_blob The DATA_BLOB with the full pdu.
+ *
+ * @return The NTSTATUS result, NT_STATUS_OK on success
+ * and others on failure.
+ *
+ * @see tstream_read_pdu_blob_send()
+ */
+NTSTATUS tstream_read_pdu_blob_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *pdu_blob);
+
+/**
+ * @brief Get a PDU size with a 32 bit size header field
+ *
+ * Work out if a packet is complete for protocols that use a 32 bit
+ * network byte order length.
+ *
+ * @see tstream_read_pdu_blob_send()
+ * @see tstream_read_pdu_blob_recv()
+ */
+NTSTATUS tstream_full_request_u32(struct tstream_context *stream,
+ void *private_data,
+ DATA_BLOB blob, size_t *size);
+
+/**
+ * @brief Get a PDU size with a 16 bit size header field
+ *
+ * Work out if a packet is complete for protocols that use a 16 bit
+ * network byte order length.
+ *
+ * @see tstream_read_pdu_blob_send()
+ * @see tstream_read_pdu_blob_recv()
+ */
+NTSTATUS tstream_full_request_u16(struct tstream_context *stream,
+ void *private_data,
+ DATA_BLOB blob, size_t *size);
+
+
+#endif /* _LIBCLI_UTIL_TSTREAM_H_ */
diff --git a/libcli/util/werror.h b/libcli/util/werror.h
new file mode 100644
index 0000000..365e6d9
--- /dev/null
+++ b/libcli/util/werror.h
@@ -0,0 +1,171 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup, plus a whole lot more.
+
+ Copyright (C) Andrew Tridgell 2001
+
+ 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/>.
+*/
+
+#ifndef _WERROR_H_
+#define _WERROR_H_
+
+#include <stdint.h>
+
+/* the following rather strange looking definitions of NTSTATUS and WERROR
+ and there in order to catch common coding errors where different error types
+ are mixed up. This is especially important as we slowly convert Samba
+ from using bool for internal functions
+*/
+
+#if defined(HAVE_IMMEDIATE_STRUCTURES)
+typedef struct {uint32_t w;} WERROR;
+#define W_ERROR(x) ((WERROR) { x })
+#define W_ERROR_V(x) ((x).w)
+#else
+typedef uint32_t WERROR;
+#define W_ERROR(x) (x)
+#define W_ERROR_V(x) (x)
+#endif
+
+#include "libcli/util/werror_gen.h"
+
+#define W_ERROR_IS_OK(x) (W_ERROR_V(x) == 0)
+#define W_ERROR_EQUAL(x,y) (W_ERROR_V(x) == W_ERROR_V(y))
+
+#define W_ERROR_HAVE_NO_MEMORY(x) do { \
+ if (!(x)) {\
+ return WERR_NOT_ENOUGH_MEMORY;\
+ }\
+} while (0)
+
+#define W_ERROR_HAVE_NO_MEMORY_AND_FREE(x, ctx) do { \
+ if (!(x)) {\
+ talloc_free(ctx); \
+ return WERR_NOT_ENOUGH_MEMORY;\
+ }\
+} while (0)
+
+#define W_ERROR_IS_OK_RETURN(x) do { \
+ if (W_ERROR_IS_OK(x)) {\
+ return x;\
+ }\
+} while (0)
+
+#define W_ERROR_NOT_OK_RETURN(x) do { \
+ if (!W_ERROR_IS_OK(x)) {\
+ return x;\
+ }\
+} while (0)
+
+#define W_ERROR_NOT_OK_GOTO_DONE(x) do { \
+ if (!W_ERROR_IS_OK(x)) {\
+ goto done;\
+ }\
+} while (0)
+
+#define W_ERROR_NOT_OK_GOTO(x, y) do {\
+ if (!W_ERROR_IS_OK(x)) {\
+ goto y;\
+ }\
+} while(0)
+
+/* these are win32 error codes. There are only a few places where
+ these matter for Samba, primarily in the NT printing code */
+#define WERR_OK W_ERROR(0x00000000)
+#define WERR_STATUS_MORE_ENTRIES W_ERROR(0x00000105)
+
+#define WERR_MULTIPLE_FAULT_VIOLATION W_ERROR(0x00000280)
+#define WERR_SERVICE_NOTIFICATION W_ERROR(0x000002CC)
+#define WERR_LOG_HARD_ERROR W_ERROR(0x000002CE)
+#define WERR_WAIT_1 W_ERROR(0x000002DB)
+#define WERR_WAIT_2 W_ERROR(0x000002DC)
+#define WERR_WAIT_3 W_ERROR(0x000002DD)
+#define WERR_WAIT_63 W_ERROR(0x000002DE)
+#define WERR_ABANDONED_WAIT_63 W_ERROR(0x000002E0)
+#define WERR_USER_APC W_ERROR(0x000002E1)
+#define WERR_KERNEL_APC W_ERROR(0x000002E2)
+#define WERR_ALERTED W_ERROR(0x000002E3)
+#define WERR_INVALID_PRIMARY_GROUP W_ERROR(0x0000051C)
+
+#define WERR_DS_DRA_SECRETS_DENIED W_ERROR(0x000021B6)
+
+#define WERR_DNS_ERROR_KEYMASTER_REQUIRED W_ERROR(0x0000238D)
+#define WERR_DNS_ERROR_NOT_ALLOWED_ON_SIGNED_ZONE W_ERROR(0x0000238E)
+#define WERR_DNS_ERROR_INVALID_NSEC3_PARAMETERS W_ERROR(0x0000238F)
+#define WERR_DNS_ERROR_NOT_ENOUGH_SIGNING_KEY_DESCRIPTORS W_ERROR(0x00002390)
+#define WERR_DNS_ERROR_UNSUPPORTED_ALGORITHM W_ERROR(0x00002391)
+#define WERR_DNS_ERROR_INVALID_KEY_SIZE W_ERROR(0x00002392)
+#define WERR_DNS_ERROR_SIGNING_KEY_NOT_ACCESSIBLE W_ERROR(0x00002393)
+#define WERR_DNS_ERROR_KSP_DOES_NOT_SUPPORT_PROTECTION W_ERROR(0x00002394)
+#define WERR_DNS_ERROR_UNEXPECTED_DATA_PROTECTION_ERROR W_ERROR(0x00002395)
+#define WERR_DNS_ERROR_UNEXPECTED_CNG_ERROR W_ERROR(0x00002396)
+#define WERR_DNS_ERROR_UNKNOWN_SIGNING_PARAMETER_VERSION W_ERROR(0x00002397)
+#define WERR_DNS_ERROR_KSP_NOT_ACCESSIBLE W_ERROR(0x00002398)
+#define WERR_DNS_ERROR_TOO_MANY_SKDS W_ERROR(0x00002399)
+#define WERR_DNS_ERROR_INVALID_ROLLOVER_PERIOD W_ERROR(0x0000239A)
+#define WERR_DNS_ERROR_INVALID_INITIAL_ROLLOVER_OFFSET W_ERROR(0x0000239B)
+#define WERR_DNS_ERROR_ROLLOVER_IN_PROGRESS W_ERROR(0x0000239C)
+#define WERR_DNS_ERROR_STANDBY_KEY_NOT_PRESENT W_ERROR(0x0000239D)
+#define WERR_DNS_ERROR_NOT_ALLOWED_ON_ZSK W_ERROR(0x0000239E)
+#define WERR_DNS_ERROR_NOT_ALLOWED_ON_ACTIVE_SKD W_ERROR(0x0000239F)
+#define WERR_DNS_ERROR_ROLLOVER_ALREADY_QUEUED W_ERROR(0x000023A0)
+#define WERR_DNS_ERROR_NOT_ALLOWED_ON_UNSIGNED_ZONE W_ERROR(0x000023A1)
+#define WERR_DNS_ERROR_BAD_KEYMASTER W_ERROR(0x000023A2)
+#define WERR_DNS_ERROR_INVALID_SIGNATURE_VALIDITY_PERIOD W_ERROR(0x000023A3)
+#define WERR_DNS_ERROR_INVALID_NSEC3_ITERATION_COUNT W_ERROR(0x000023A4)
+#define WERR_DNS_ERROR_DNSSEC_IS_DISABLED W_ERROR(0x000023A5)
+#define WERR_DNS_ERROR_INVALID_XML W_ERROR(0x000023A6)
+#define WERR_DNS_ERROR_NO_VALID_TRUST_ANCHORS W_ERROR(0x000023A7)
+#define WERR_DNS_ERROR_ROLLOVER_NOT_POKEABLE W_ERROR(0x000023A8)
+#define WERR_DNS_ERROR_NSEC3_NAME_COLLISION W_ERROR(0x000023A9)
+
+#define WERR_DNS_REQUEST_PENDING W_ERROR(0x00002522)
+#define WERR_DNS_ERROR_NOT_ALLOWED_UNDER_DNAME W_ERROR(0x00002562)
+#define WERR_DNS_ERROR_DELEGATION_REQUIRED W_ERROR(0x00002563)
+#define WERR_DNS_ERROR_INVALID_POLICY_TABLE W_ERROR(0x00002564)
+#define WERR_DNS_ERROR_NODE_IS_DNMAE WERR_DNS_ERROR_NODE_IS_DNAME
+#define WERR_DNS_ERROR_NODE_IS_DNAME W_ERROR(0x000025F8) /* Used to be: "WERR_DNS_ERROR_NODE_IS_DNMAE" */
+#define WERR_DNS_ERROR_DNAME_COLLISION W_ERROR(0x000025F9)
+#define WERR_DNS_ERROR_ALIAS_LOOP W_ERROR(0x000025FA)
+
+/* Configuration Manager Errors */
+/* Basically Win32 errors meanings are specific to the \ntsvcs pipe */
+#define WERR_CM_INVALID_POINTER W_ERROR(3)
+#define WERR_CM_BUFFER_SMALL W_ERROR(26)
+#define WERR_CM_NO_MORE_HW_PROFILES W_ERROR(35)
+#define WERR_CM_NO_SUCH_VALUE W_ERROR(37)
+
+/* DFS errors */
+
+#ifndef NERR_BASE
+#define NERR_BASE (2100)
+#endif
+
+#ifndef MAX_NERR
+#define MAX_NERR (NERR_BASE+899)
+#endif
+
+/* Generic error code aliases */
+#define WERR_FOOBAR WERR_GEN_FAILURE
+
+/*****************************************************************************
+ returns a windows error message. not amazingly helpful, but better than a number.
+ *****************************************************************************/
+const char *win_errstr(WERROR werror);
+
+const char *get_friendly_werror_msg(WERROR werror);
+
+
+#endif
diff --git a/libcli/util/werror_err_table.txt b/libcli/util/werror_err_table.txt
new file mode 100644
index 0000000..5796afc
--- /dev/null
+++ b/libcli/util/werror_err_table.txt
@@ -0,0 +1,18949 @@
+Errors retrieved from https://msdn.microsoft.com/en-us/library/cc231199.aspx.
+License retrieved from https://msdn.microsoft.com/en-us/library/cc231196.aspx:
+
+Intellectual Property Rights Notice for Open Specifications Documentation
+
+ - Technical Documentation. Microsoft publishes Open Specifications documentation (“this documentation”) for protocols, file formats, data portability, computer languages, and standards support. Additionally, overview documents cover inter-protocol relationships and interactions.
+
+ - Copyrights. This documentation is covered by Microsoft copyrights. Regardless of any other terms that are contained in the terms of use for the Microsoft website that hosts this documentation, you can make copies of it in order to develop implementations of the technologies that are described in this documentation and can distribute portions of it in your implementations that use these technologies or in your documentation as necessary to properly document the implementation. You can also distribute in your implementation, with or without modification, any schemas, IDLs, or code samples that are included in the documentation. This permission also applies to any documents that are referenced in the Open Specifications documentation.
+
+ - No Trade Secrets. Microsoft does not claim any trade secret rights in this documentation.
+
+ - Patents. Microsoft has patents that might cover your implementations of the technologies described in the Open Specifications documentation. Neither this notice nor Microsoft's delivery of this documentation grants any licenses under those patents or any other Microsoft patents. However, a given Open Specifications document might be covered by the Microsoft Open Specifications Promise or the Microsoft Community Promise. If you would prefer a written license, or if the technologies described in this documentation are not covered by the Open Specifications Promise or Community Promise, as applicable, patent licenses are available by contacting iplg@microsoft.com.
+
+ - Trademarks. The names of companies and products contained in this documentation might be covered by trademarks or similar intellectual property rights. This notice does not grant any licenses under those rights. For a list of Microsoft trademarks, visit www.microsoft.com/trademarks.
+
+ - Fictitious Names. The example companies, organizations, products, domain names, email addresses, logos, people, places, and events that are depicted in this documentation are fictitious. No association with any real company, organization, product, domain name, email address, logo, person, place, or event is intended or should be inferred.
+
+Reservation of Rights. All other rights are reserved, and this notice does not grant any rights other than as specifically described above, whether by implication, estoppel, or otherwise.
+
+Tools. The Open Specifications documentation does not require the use of Microsoft programming tools or programming environments in order for you to develop an implementation. If you have access to Microsoft programming tools and environments, you are free to take advantage of them. Certain Open Specifications documents are intended for use in conjunction with publicly available standards specifications and network programming art and, as such, assume that the reader either is familiar with the aforementioned material or has immediate access to it.
+
+===========
+
+0x00000000
+
+ERROR_SUCCESS
+
+
+The operation completed successfully.
+
+0x00000000
+
+NERR_Success
+
+
+The operation completed successfully.
+
+0x00000001
+
+ERROR_INVALID_FUNCTION
+
+
+Incorrect function.
+
+0x00000002
+
+ERROR_FILE_NOT_FOUND
+
+
+The system cannot find the file specified.
+
+0x00000003
+
+ERROR_PATH_NOT_FOUND
+
+
+The system cannot find the path specified.
+
+0x00000004
+
+ERROR_TOO_MANY_OPEN_FILES
+
+
+The system cannot open the file.
+
+0x00000005
+
+ERROR_ACCESS_DENIED
+
+
+Access is denied.
+
+0x00000006
+
+ERROR_INVALID_HANDLE
+
+
+The handle is invalid.
+
+0x00000007
+
+ERROR_ARENA_TRASHED
+
+
+The storage control blocks were destroyed.
+
+0x00000008
+
+ERROR_NOT_ENOUGH_MEMORY
+
+
+Not enough storage is available to process this command.
+
+0x00000009
+
+ERROR_INVALID_BLOCK
+
+
+The storage control block address is invalid.
+
+0x0000000A
+
+ERROR_BAD_ENVIRONMENT
+
+
+The environment is incorrect.
+
+0x0000000B
+
+ERROR_BAD_FORMAT
+
+
+An attempt was made to load a program with an incorrect format.
+
+0x0000000C
+
+ERROR_INVALID_ACCESS
+
+
+The access code is invalid.
+
+0x0000000D
+
+ERROR_INVALID_DATA
+
+
+The data is invalid.
+
+0x0000000E
+
+ERROR_OUTOFMEMORY
+
+
+Not enough storage is available to complete this operation.
+
+0x0000000F
+
+ERROR_INVALID_DRIVE
+
+
+The system cannot find the drive specified.
+
+0x00000010
+
+ERROR_CURRENT_DIRECTORY
+
+
+The directory cannot be removed.
+
+0x00000011
+
+ERROR_NOT_SAME_DEVICE
+
+
+The system cannot move the file to a different disk drive.
+
+0x00000012
+
+ERROR_NO_MORE_FILES
+
+
+There are no more files.
+
+0x00000013
+
+ERROR_WRITE_PROTECT
+
+
+The media is write-protected.
+
+0x00000014
+
+ERROR_BAD_UNIT
+
+
+The system cannot find the device specified.
+
+0x00000015
+
+ERROR_NOT_READY
+
+
+The device is not ready.
+
+0x00000016
+
+ERROR_BAD_COMMAND
+
+
+The device does not recognize the command.
+
+0x00000017
+
+ERROR_CRC
+
+
+Data error (cyclic redundancy check).
+
+0x00000018
+
+ERROR_BAD_LENGTH
+
+
+The program issued a command but the command length is incorrect.
+
+0x00000019
+
+ERROR_SEEK
+
+
+The drive cannot locate a specific area or track on the disk.
+
+0x0000001A
+
+ERROR_NOT_DOS_DISK
+
+
+The specified disk cannot be accessed.
+
+0x0000001B
+
+ERROR_SECTOR_NOT_FOUND
+
+
+The drive cannot find the sector requested.
+
+0x0000001C
+
+ERROR_OUT_OF_PAPER
+
+
+The printer is out of paper.
+
+0x0000001D
+
+ERROR_WRITE_FAULT
+
+
+The system cannot write to the specified device.
+
+0x0000001E
+
+ERROR_READ_FAULT
+
+
+The system cannot read from the specified device.
+
+0x0000001F
+
+ERROR_GEN_FAILURE
+
+
+A device attached to the system is not functioning.
+
+0x00000020
+
+ERROR_SHARING_VIOLATION
+
+
+The process cannot access the file because it is being used by another process.
+
+0x00000021
+
+ERROR_LOCK_VIOLATION
+
+
+The process cannot access the file because another process has locked a portion of the file.
+
+0x00000022
+
+ERROR_WRONG_DISK
+
+
+The wrong disk is in the drive. Insert %2 (Volume Serial Number: %3) into drive %1.
+
+0x00000024
+
+ERROR_SHARING_BUFFER_EXCEEDED
+
+
+Too many files opened for sharing.
+
+0x00000026
+
+ERROR_HANDLE_EOF
+
+
+Reached the end of the file.
+
+0x00000027
+
+ERROR_HANDLE_DISK_FULL
+
+
+The disk is full.
+
+0x00000032
+
+ERROR_NOT_SUPPORTED
+
+
+The request is not supported.
+
+0x00000033
+
+ERROR_REM_NOT_LIST
+
+
+Windows cannot find the network path. Verify that the network path is correct and the destination computer is not busy or turned off. If Windows still cannot find the network path, contact your network administrator.
+
+0x00000034
+
+ERROR_DUP_NAME
+
+
+You were not connected because a duplicate name exists on the network. Go to System in Control Panel to change the computer name, and then try again.
+
+0x00000035
+
+ERROR_BAD_NETPATH
+
+
+The network path was not found.
+
+0x00000036
+
+ERROR_NETWORK_BUSY
+
+
+The network is busy.
+
+0x00000037
+
+ERROR_DEV_NOT_EXIST
+
+
+The specified network resource or device is no longer available.
+
+0x00000038
+
+ERROR_TOO_MANY_CMDS
+
+
+The network BIOS command limit has been reached.
+
+0x00000039
+
+ERROR_ADAP_HDW_ERR
+
+
+A network adapter hardware error occurred.
+
+0x0000003A
+
+ERROR_BAD_NET_RESP
+
+
+The specified server cannot perform the requested operation.
+
+0x0000003B
+
+ERROR_UNEXP_NET_ERR
+
+
+An unexpected network error occurred.
+
+0x0000003C
+
+ERROR_BAD_REM_ADAP
+
+
+The remote adapter is not compatible.
+
+0x0000003D
+
+ERROR_PRINTQ_FULL
+
+
+The print queue is full.
+
+0x0000003E
+
+ERROR_NO_SPOOL_SPACE
+
+
+Space to store the file waiting to be printed is not available on the server.
+
+0x0000003F
+
+ERROR_PRINT_CANCELLED
+
+
+Your file waiting to be printed was deleted.
+
+0x00000040
+
+ERROR_NETNAME_DELETED
+
+
+The specified network name is no longer available.
+
+0x00000041
+
+ERROR_NETWORK_ACCESS_DENIED
+
+
+Network access is denied.
+
+0x00000042
+
+ERROR_BAD_DEV_TYPE
+
+
+The network resource type is not correct.
+
+0x00000043
+
+ERROR_BAD_NET_NAME
+
+
+The network name cannot be found.
+
+0x00000044
+
+ERROR_TOO_MANY_NAMES
+
+
+The name limit for the local computer network adapter card was exceeded.
+
+0x00000045
+
+ERROR_TOO_MANY_SESS
+
+
+The network BIOS session limit was exceeded.
+
+0x00000046
+
+ERROR_SHARING_PAUSED
+
+
+The remote server has been paused or is in the process of being started.
+
+0x00000047
+
+ERROR_REQ_NOT_ACCEP
+
+
+No more connections can be made to this remote computer at this time because the computer has accepted the maximum number of connections.
+
+0x00000048
+
+ERROR_REDIR_PAUSED
+
+
+The specified printer or disk device has been paused.
+
+0x00000050
+
+ERROR_FILE_EXISTS
+
+
+The file exists.
+
+0x00000052
+
+ERROR_CANNOT_MAKE
+
+
+The directory or file cannot be created.
+
+0x00000053
+
+ERROR_FAIL_I24
+
+
+Fail on INT 24.
+
+0x00000054
+
+ERROR_OUT_OF_STRUCTURES
+
+
+Storage to process this request is not available.
+
+0x00000055
+
+ERROR_ALREADY_ASSIGNED
+
+
+The local device name is already in use.
+
+0x00000056
+
+ERROR_INVALID_PASSWORD
+
+
+The specified network password is not correct.
+
+0x00000057
+
+ERROR_INVALID_PARAMETER
+
+
+The parameter is incorrect.
+
+0x00000058
+
+ERROR_NET_WRITE_FAULT
+
+
+A write fault occurred on the network.
+
+0x00000059
+
+ERROR_NO_PROC_SLOTS
+
+
+The system cannot start another process at this time.
+
+0x00000064
+
+ERROR_TOO_MANY_SEMAPHORES
+
+
+Cannot create another system semaphore.
+
+0x00000065
+
+ERROR_EXCL_SEM_ALREADY_OWNED
+
+
+The exclusive semaphore is owned by another process.
+
+0x00000066
+
+ERROR_SEM_IS_SET
+
+
+The semaphore is set and cannot be closed.
+
+0x00000067
+
+ERROR_TOO_MANY_SEM_REQUESTS
+
+
+The semaphore cannot be set again.
+
+0x00000068
+
+ERROR_INVALID_AT_INTERRUPT_TIME
+
+
+Cannot request exclusive semaphores at interrupt time.
+
+0x00000069
+
+ERROR_SEM_OWNER_DIED
+
+
+The previous ownership of this semaphore has ended.
+
+0x0000006A
+
+ERROR_SEM_USER_LIMIT
+
+
+Insert the disk for drive %1.
+
+0x0000006B
+
+ERROR_DISK_CHANGE
+
+
+The program stopped because an alternate disk was not inserted.
+
+0x0000006C
+
+ERROR_DRIVE_LOCKED
+
+
+The disk is in use or locked by another process.
+
+0x0000006D
+
+ERROR_BROKEN_PIPE
+
+
+The pipe has been ended.
+
+0x0000006E
+
+ERROR_OPEN_FAILED
+
+
+The system cannot open the device or file specified.
+
+0x0000006F
+
+ERROR_BUFFER_OVERFLOW
+
+
+The file name is too long.
+
+0x00000070
+
+ERROR_DISK_FULL
+
+
+There is not enough space on the disk.
+
+0x00000071
+
+ERROR_NO_MORE_SEARCH_HANDLES
+
+
+No more internal file identifiers are available.
+
+0x00000072
+
+ERROR_INVALID_TARGET_HANDLE
+
+
+The target internal file identifier is incorrect.
+
+0x00000075
+
+ERROR_INVALID_CATEGORY
+
+
+The Input Output Control (IOCTL) call made by the application program is not correct.
+
+0x00000076
+
+ERROR_INVALID_VERIFY_SWITCH
+
+
+The verify-on-write switch parameter value is not correct.
+
+0x00000077
+
+ERROR_BAD_DRIVER_LEVEL
+
+
+The system does not support the command requested.
+
+0x00000078
+
+ERROR_CALL_NOT_IMPLEMENTED
+
+
+This function is not supported on this system.
+
+0x00000079
+
+ERROR_SEM_TIMEOUT
+
+
+The semaphore time-out period has expired.
+
+0x0000007A
+
+ERROR_INSUFFICIENT_BUFFER
+
+
+The data area passed to a system call is too small.
+
+0x0000007B
+
+ERROR_INVALID_NAME
+
+
+The file name, directory name, or volume label syntax is incorrect.
+
+0x0000007C
+
+ERROR_INVALID_LEVEL
+
+
+The system call level is not correct.
+
+0x0000007D
+
+ERROR_NO_VOLUME_LABEL
+
+
+The disk has no volume label.
+
+0x0000007E
+
+ERROR_MOD_NOT_FOUND
+
+
+The specified module could not be found.
+
+0x0000007F
+
+ERROR_PROC_NOT_FOUND
+
+
+The specified procedure could not be found.
+
+0x00000080
+
+ERROR_WAIT_NO_CHILDREN
+
+
+There are no child processes to wait for.
+
+0x00000081
+
+ERROR_CHILD_NOT_COMPLETE
+
+
+The %1 application cannot be run in Win32 mode.
+
+0x00000082
+
+ERROR_DIRECT_ACCESS_HANDLE
+
+
+Attempt to use a file handle to an open disk partition for an operation other than raw disk I/O.
+
+0x00000083
+
+ERROR_NEGATIVE_SEEK
+
+
+An attempt was made to move the file pointer before the beginning of the file.
+
+0x00000084
+
+ERROR_SEEK_ON_DEVICE
+
+
+The file pointer cannot be set on the specified device or file.
+
+0x00000085
+
+ERROR_IS_JOIN_TARGET
+
+
+A JOIN or SUBST command cannot be used for a drive that contains previously joined drives.
+
+0x00000086
+
+ERROR_IS_JOINED
+
+
+An attempt was made to use a JOIN or SUBST command on a drive that has already been joined.
+
+0x00000087
+
+ERROR_IS_SUBSTED
+
+
+An attempt was made to use a JOIN or SUBST command on a drive that has already been substituted.
+
+0x00000088
+
+ERROR_NOT_JOINED
+
+
+The system tried to delete the JOIN of a drive that is not joined.
+
+0x00000089
+
+ERROR_NOT_SUBSTED
+
+
+The system tried to delete the substitution of a drive that is not substituted.
+
+0x0000008A
+
+ERROR_JOIN_TO_JOIN
+
+
+The system tried to join a drive to a directory on a joined drive.
+
+0x0000008B
+
+ERROR_SUBST_TO_SUBST
+
+
+The system tried to substitute a drive to a directory on a substituted drive.
+
+0x0000008C
+
+ERROR_JOIN_TO_SUBST
+
+
+The system tried to join a drive to a directory on a substituted drive.
+
+0x0000008D
+
+ERROR_SUBST_TO_JOIN
+
+
+The system tried to SUBST a drive to a directory on a joined drive.
+
+0x0000008E
+
+ERROR_BUSY_DRIVE
+
+
+The system cannot perform a JOIN or SUBST at this time.
+
+0x0000008F
+
+ERROR_SAME_DRIVE
+
+
+The system cannot join or substitute a drive to or for a directory on the same drive.
+
+0x00000090
+
+ERROR_DIR_NOT_ROOT
+
+
+The directory is not a subdirectory of the root directory.
+
+0x00000091
+
+ERROR_DIR_NOT_EMPTY
+
+
+The directory is not empty.
+
+0x00000092
+
+ERROR_IS_SUBST_PATH
+
+
+The path specified is being used in a substitute.
+
+0x00000093
+
+ERROR_IS_JOIN_PATH
+
+
+Not enough resources are available to process this command.
+
+0x00000094
+
+ERROR_PATH_BUSY
+
+
+The path specified cannot be used at this time.
+
+0x00000095
+
+ERROR_IS_SUBST_TARGET
+
+
+An attempt was made to join or substitute a drive for which a directory on the drive is the target of a previous substitute.
+
+0x00000096
+
+ERROR_SYSTEM_TRACE
+
+
+System trace information was not specified in your CONFIG.SYS file, or tracing is disallowed.
+
+0x00000097
+
+ERROR_INVALID_EVENT_COUNT
+
+
+The number of specified semaphore events for DosMuxSemWait is not correct.
+
+0x00000098
+
+ERROR_TOO_MANY_MUXWAITERS
+
+
+DosMuxSemWait did not execute; too many semaphores are already set.
+
+0x00000099
+
+ERROR_INVALID_LIST_FORMAT
+
+
+The DosMuxSemWait list is not correct.
+
+0x0000009A
+
+ERROR_LABEL_TOO_LONG
+
+
+The volume label you entered exceeds the label character limit of the destination file system.
+
+0x0000009B
+
+ERROR_TOO_MANY_TCBS
+
+
+Cannot create another thread.
+
+0x0000009C
+
+ERROR_SIGNAL_REFUSED
+
+
+The recipient process has refused the signal.
+
+0x0000009D
+
+ERROR_DISCARDED
+
+
+The segment is already discarded and cannot be locked.
+
+0x0000009E
+
+ERROR_NOT_LOCKED
+
+
+The segment is already unlocked.
+
+0x0000009F
+
+ERROR_BAD_THREADID_ADDR
+
+
+The address for the thread ID is not correct.
+
+0x000000A0
+
+ERROR_BAD_ARGUMENTS
+
+
+One or more arguments are not correct.
+
+0x000000A1
+
+ERROR_BAD_PATHNAME
+
+
+The specified path is invalid.
+
+0x000000A2
+
+ERROR_SIGNAL_PENDING
+
+
+A signal is already pending.
+
+0x000000A4
+
+ERROR_MAX_THRDS_REACHED
+
+
+No more threads can be created in the system.
+
+0x000000A7
+
+ERROR_LOCK_FAILED
+
+
+Unable to lock a region of a file.
+
+0x000000AA
+
+ERROR_BUSY
+
+
+The requested resource is in use.
+
+0x000000AD
+
+ERROR_CANCEL_VIOLATION
+
+
+A lock request was not outstanding for the supplied cancel region.
+
+0x000000AE
+
+ERROR_ATOMIC_LOCKS_NOT_SUPPORTED
+
+
+The file system does not support atomic changes to the lock type.
+
+0x000000B4
+
+ERROR_INVALID_SEGMENT_NUMBER
+
+
+The system detected a segment number that was not correct.
+
+0x000000B6
+
+ERROR_INVALID_ORDINAL
+
+
+The operating system cannot run %1.
+
+0x000000B7
+
+ERROR_ALREADY_EXISTS
+
+
+Cannot create a file when that file already exists.
+
+0x000000BA
+
+ERROR_INVALID_FLAG_NUMBER
+
+
+The flag passed is not correct.
+
+0x000000BB
+
+ERROR_SEM_NOT_FOUND
+
+
+The specified system semaphore name was not found.
+
+0x000000BC
+
+ERROR_INVALID_STARTING_CODESEG
+
+
+The operating system cannot run %1.
+
+0x000000BD
+
+ERROR_INVALID_STACKSEG
+
+
+The operating system cannot run %1.
+
+0x000000BE
+
+ERROR_INVALID_MODULETYPE
+
+
+The operating system cannot run %1.
+
+0x000000BF
+
+ERROR_INVALID_EXE_SIGNATURE
+
+
+Cannot run %1 in Win32 mode.
+
+0x000000C0
+
+ERROR_EXE_MARKED_INVALID
+
+
+The operating system cannot run %1.
+
+0x000000C1
+
+ERROR_BAD_EXE_FORMAT
+
+
+%1 is not a valid Win32 application.
+
+0x000000C2
+
+ERROR_ITERATED_DATA_EXCEEDS_64k
+
+
+The operating system cannot run %1.
+
+0x000000C3
+
+ERROR_INVALID_MINALLOCSIZE
+
+
+The operating system cannot run %1.
+
+0x000000C4
+
+ERROR_DYNLINK_FROM_INVALID_RING
+
+
+The operating system cannot run this application program.
+
+0x000000C5
+
+ERROR_IOPL_NOT_ENABLED
+
+
+The operating system is not presently configured to run this application.
+
+0x000000C6
+
+ERROR_INVALID_SEGDPL
+
+
+The operating system cannot run %1.
+
+0x000000C7
+
+ERROR_AUTODATASEG_EXCEEDS_64k
+
+
+The operating system cannot run this application program.
+
+0x000000C8
+
+ERROR_RING2SEG_MUST_BE_MOVABLE
+
+
+The code segment cannot be greater than or equal to 64 KB.
+
+0x000000C9
+
+ERROR_RELOC_CHAIN_XEEDS_SEGLIM
+
+
+The operating system cannot run %1.
+
+0x000000CA
+
+ERROR_INFLOOP_IN_RELOC_CHAIN
+
+
+The operating system cannot run %1.
+
+0x000000CB
+
+ERROR_ENVVAR_NOT_FOUND
+
+
+The system could not find the environment option that was entered.
+
+0x000000CD
+
+ERROR_NO_SIGNAL_SENT
+
+
+No process in the command subtree has a signal handler.
+
+0x000000CE
+
+ERROR_FILENAME_EXCED_RANGE
+
+
+The file name or extension is too long.
+
+0x000000CF
+
+ERROR_RING2_STACK_IN_USE
+
+
+The ring 2 stack is in use.
+
+0x000000D0
+
+ERROR_META_EXPANSION_TOO_LONG
+
+
+The asterisk (*) or question mark (?) global file name characters are entered incorrectly, or too many global file name characters are specified.
+
+0x000000D1
+
+ERROR_INVALID_SIGNAL_NUMBER
+
+
+The signal being posted is not correct.
+
+0x000000D2
+
+ERROR_THREAD_1_INACTIVE
+
+
+The signal handler cannot be set.
+
+0x000000D4
+
+ERROR_LOCKED
+
+
+The segment is locked and cannot be reallocated.
+
+0x000000D6
+
+ERROR_TOO_MANY_MODULES
+
+
+Too many dynamic-link modules are attached to this program or dynamic-link module.
+
+0x000000D7
+
+ERROR_NESTING_NOT_ALLOWED
+
+
+Cannot nest calls to LoadModule.
+
+0x000000D8
+
+ERROR_EXE_MACHINE_TYPE_MISMATCH
+
+
+This version of %1 is not compatible with the version of Windows you're running. Check your computer's system information to see whether you need an x86 (32-bit) or x64 (64-bit) version of the program, and then contact the software publisher.
+
+0x000000D9
+
+ERROR_EXE_CANNOT_MODIFY_SIGNED_BINARY
+
+
+The image file %1 is signed, unable to modify.
+
+0x000000DA
+
+ERROR_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY
+
+
+The image file %1 is strong signed, unable to modify.
+
+0x000000DC
+
+ERROR_FILE_CHECKED_OUT
+
+
+This file is checked out or locked for editing by another user.
+
+0x000000DD
+
+ERROR_CHECKOUT_REQUIRED
+
+
+The file must be checked out before saving changes.
+
+0x000000DE
+
+ERROR_BAD_FILE_TYPE
+
+
+The file type being saved or retrieved has been blocked.
+
+0x000000DF
+
+ERROR_FILE_TOO_LARGE
+
+
+The file size exceeds the limit allowed and cannot be saved.
+
+0x000000E0
+
+ERROR_FORMS_AUTH_REQUIRED
+
+
+Access denied. Before opening files in this location, you must first browse to the website and select the option to sign in automatically.
+
+0x000000E1
+
+ERROR_VIRUS_INFECTED
+
+
+Operation did not complete successfully because the file contains a virus.
+
+0x000000E2
+
+ERROR_VIRUS_DELETED
+
+
+This file contains a virus and cannot be opened. Due to the nature of this virus, the file has been removed from this location.
+
+0x000000E5
+
+ERROR_PIPE_LOCAL
+
+
+The pipe is local.
+
+0x000000E6
+
+ERROR_BAD_PIPE
+
+
+The pipe state is invalid.
+
+0x000000E7
+
+ERROR_PIPE_BUSY
+
+
+All pipe instances are busy.
+
+0x000000E8
+
+ERROR_NO_DATA
+
+
+The pipe is being closed.
+
+0x000000E9
+
+ERROR_PIPE_NOT_CONNECTED
+
+
+No process is on the other end of the pipe.
+
+0x000000EA
+
+ERROR_MORE_DATA
+
+
+More data is available.
+
+0x000000F0
+
+ERROR_VC_DISCONNECTED
+
+
+The session was canceled.
+
+0x000000FE
+
+ERROR_INVALID_EA_NAME
+
+
+The specified extended attribute name was invalid.
+
+0x000000FF
+
+ERROR_EA_LIST_INCONSISTENT
+
+
+The extended attributes are inconsistent.
+
+0x00000102
+
+WAIT_TIMEOUT
+
+
+The wait operation timed out.
+
+0x00000103
+
+ERROR_NO_MORE_ITEMS
+
+
+No more data is available.
+
+0x0000010A
+
+ERROR_CANNOT_COPY
+
+
+The copy functions cannot be used.
+
+0x0000010B
+
+ERROR_DIRECTORY
+
+
+The directory name is invalid.
+
+0x00000113
+
+ERROR_EAS_DIDNT_FIT
+
+
+The extended attributes did not fit in the buffer.
+
+0x00000114
+
+ERROR_EA_FILE_CORRUPT
+
+
+The extended attribute file on the mounted file system is corrupt.
+
+0x00000115
+
+ERROR_EA_TABLE_FULL
+
+
+The extended attribute table file is full.
+
+0x00000116
+
+ERROR_INVALID_EA_HANDLE
+
+
+The specified extended attribute handle is invalid.
+
+0x0000011A
+
+ERROR_EAS_NOT_SUPPORTED
+
+
+The mounted file system does not support extended attributes.
+
+0x00000120
+
+ERROR_NOT_OWNER
+
+
+Attempt to release mutex not owned by caller.
+
+0x0000012A
+
+ERROR_TOO_MANY_POSTS
+
+
+Too many posts were made to a semaphore.
+
+0x0000012B
+
+ERROR_PARTIAL_COPY
+
+
+Only part of a ReadProcessMemory or WriteProcessMemory request was completed.
+
+0x0000012C
+
+ERROR_OPLOCK_NOT_GRANTED
+
+
+The oplock request is denied.
+
+0x0000012D
+
+ERROR_INVALID_OPLOCK_PROTOCOL
+
+
+An invalid oplock acknowledgment was received by the system.
+
+0x0000012E
+
+ERROR_DISK_TOO_FRAGMENTED
+
+
+The volume is too fragmented to complete this operation.
+
+0x0000012F
+
+ERROR_DELETE_PENDING
+
+
+The file cannot be opened because it is in the process of being deleted.
+
+0x0000013D
+
+ERROR_MR_MID_NOT_FOUND
+
+
+The system cannot find message text for message number 0x%1 in the message file for %2.
+
+0x0000013E
+
+ERROR_SCOPE_NOT_FOUND
+
+
+The scope specified was not found.
+
+0x0000015E
+
+ERROR_FAIL_NOACTION_REBOOT
+
+
+No action was taken because a system reboot is required.
+
+0x0000015F
+
+ERROR_FAIL_SHUTDOWN
+
+
+The shutdown operation failed.
+
+0x00000160
+
+ERROR_FAIL_RESTART
+
+
+The restart operation failed.
+
+0x00000161
+
+ERROR_MAX_SESSIONS_REACHED
+
+
+The maximum number of sessions has been reached.
+
+0x00000190
+
+ERROR_THREAD_MODE_ALREADY_BACKGROUND
+
+
+The thread is already in background processing mode.
+
+0x00000191
+
+ERROR_THREAD_MODE_NOT_BACKGROUND
+
+
+The thread is not in background processing mode.
+
+0x00000192
+
+ERROR_PROCESS_MODE_ALREADY_BACKGROUND
+
+
+The process is already in background processing mode.
+
+0x00000193
+
+ERROR_PROCESS_MODE_NOT_BACKGROUND
+
+
+The process is not in background processing mode.
+
+0x000001E7
+
+ERROR_INVALID_ADDRESS
+
+
+Attempt to access invalid address.
+
+0x000001F4
+
+ERROR_USER_PROFILE_LOAD
+
+
+User profile cannot be loaded.
+
+0x00000216
+
+ERROR_ARITHMETIC_OVERFLOW
+
+
+Arithmetic result exceeded 32 bits.
+
+0x00000217
+
+ERROR_PIPE_CONNECTED
+
+
+There is a process on the other end of the pipe.
+
+0x00000218
+
+ERROR_PIPE_LISTENING
+
+
+Waiting for a process to open the other end of the pipe.
+
+0x00000219
+
+ERROR_VERIFIER_STOP
+
+
+Application verifier has found an error in the current process.
+
+0x0000021A
+
+ERROR_ABIOS_ERROR
+
+
+An error occurred in the ABIOS subsystem.
+
+0x0000021B
+
+ERROR_WX86_WARNING
+
+
+A warning occurred in the WX86 subsystem.
+
+0x0000021C
+
+ERROR_WX86_ERROR
+
+
+An error occurred in the WX86 subsystem.
+
+0x0000021D
+
+ERROR_TIMER_NOT_CANCELED
+
+
+An attempt was made to cancel or set a timer that has an associated asynchronous procedure call (APC) and the subject thread is not the thread that originally set the timer with an associated APC routine.
+
+0x0000021E
+
+ERROR_UNWIND
+
+
+Unwind exception code.
+
+0x0000021F
+
+ERROR_BAD_STACK
+
+
+An invalid or unaligned stack was encountered during an unwind operation.
+
+0x00000220
+
+ERROR_INVALID_UNWIND_TARGET
+
+
+An invalid unwind target was encountered during an unwind operation.
+
+0x00000221
+
+ERROR_INVALID_PORT_ATTRIBUTES
+
+
+Invalid object attributes specified to NtCreatePort or invalid port attributes specified to NtConnectPort.
+
+0x00000222
+
+ERROR_PORT_MESSAGE_TOO_LONG
+
+
+Length of message passed to NtRequestPort or NtRequestWaitReplyPort was longer than the maximum message allowed by the port.
+
+0x00000223
+
+ERROR_INVALID_QUOTA_LOWER
+
+
+An attempt was made to lower a quota limit below the current usage.
+
+0x00000224
+
+ERROR_DEVICE_ALREADY_ATTACHED
+
+
+An attempt was made to attach to a device that was already attached to another device.
+
+0x00000225
+
+ERROR_INSTRUCTION_MISALIGNMENT
+
+
+An attempt was made to execute an instruction at an unaligned address, and the host system does not support unaligned instruction references.
+
+0x00000226
+
+ERROR_PROFILING_NOT_STARTED
+
+
+Profiling not started.
+
+0x00000227
+
+ERROR_PROFILING_NOT_STOPPED
+
+
+Profiling not stopped.
+
+0x00000228
+
+ERROR_COULD_NOT_INTERPRET
+
+
+The passed ACL did not contain the minimum required information.
+
+0x00000229
+
+ERROR_PROFILING_AT_LIMIT
+
+
+The number of active profiling objects is at the maximum and no more can be started.
+
+0x0000022A
+
+ERROR_CANT_WAIT
+
+
+Used to indicate that an operation cannot continue without blocking for I/O.
+
+0x0000022B
+
+ERROR_CANT_TERMINATE_SELF
+
+
+Indicates that a thread attempted to terminate itself by default (called NtTerminateThread with NULL) and it was the last thread in the current process.
+
+0x0000022C
+
+ERROR_UNEXPECTED_MM_CREATE_ERR
+
+
+If an MM error is returned that is not defined in the standard FsRtl filter, it is converted to one of the following errors that is guaranteed to be in the filter. In this case, information is lost; however, the filter correctly handles the exception.
+
+0x0000022D
+
+ERROR_UNEXPECTED_MM_MAP_ERROR
+
+
+If an MM error is returned that is not defined in the standard FsRtl filter, it is converted to one of the following errors that is guaranteed to be in the filter. In this case, information is lost; however, the filter correctly handles the exception.
+
+0x0000022E
+
+ERROR_UNEXPECTED_MM_EXTEND_ERR
+
+
+If an MM error is returned that is not defined in the standard FsRtl filter, it is converted to one of the following errors that is guaranteed to be in the filter. In this case, information is lost; however, the filter correctly handles the exception.
+
+0x0000022F
+
+ERROR_BAD_FUNCTION_TABLE
+
+
+A malformed function table was encountered during an unwind operation.
+
+0x00000230
+
+ERROR_NO_GUID_TRANSLATION
+
+
+Indicates that an attempt was made to assign protection to a file system file or directory and one of the SIDs in the security descriptor could not be translated into a GUID that could be stored by the file system. This causes the protection attempt to fail, which might cause a file creation attempt to fail.
+
+0x00000231
+
+ERROR_INVALID_LDT_SIZE
+
+
+Indicates that an attempt was made to grow a local domain table (LDT) by setting its size, or that the size was not an even number of selectors.
+
+0x00000233
+
+ERROR_INVALID_LDT_OFFSET
+
+
+Indicates that the starting value for the LDT information was not an integral multiple of the selector size.
+
+0x00000234
+
+ERROR_INVALID_LDT_DESCRIPTOR
+
+
+Indicates that the user supplied an invalid descriptor when trying to set up LDT descriptors.
+
+0x00000235
+
+ERROR_TOO_MANY_THREADS
+
+
+Indicates a process has too many threads to perform the requested action. For example, assignment of a primary token can be performed only when a process has zero or one threads.
+
+0x00000236
+
+ERROR_THREAD_NOT_IN_PROCESS
+
+
+An attempt was made to operate on a thread within a specific process, but the thread specified is not in the process specified.
+
+0x00000237
+
+ERROR_PAGEFILE_QUOTA_EXCEEDED
+
+
+Page file quota was exceeded.
+
+0x00000238
+
+ERROR_LOGON_SERVER_CONFLICT
+
+
+The Netlogon service cannot start because another Netlogon service running in the domain conflicts with the specified role.
+
+0x00000239
+
+ERROR_SYNCHRONIZATION_REQUIRED
+
+
+On applicable Windows Server releases, the Security Accounts Manager (SAM) database is significantly out of synchronization with the copy on the domain controller. A complete synchronization is required.
+
+0x0000023A
+
+ERROR_NET_OPEN_FAILED
+
+
+The NtCreateFile API failed. This error should never be returned to an application, it is a place holder for the Windows LAN Manager Redirector to use in its internal error mapping routines.
+
+0x0000023B
+
+ERROR_IO_PRIVILEGE_FAILED
+
+
+{Privilege Failed} The I/O permissions for the process could not be changed.
+
+0x0000023C
+
+ERROR_CONTROL_C_EXIT
+
+
+{Application Exit by CTRL+C} The application terminated as a result of a CTRL+C.
+
+0x0000023D
+
+ERROR_MISSING_SYSTEMFILE
+
+
+{Missing System File} The required system file %hs is bad or missing.
+
+0x0000023E
+
+ERROR_UNHANDLED_EXCEPTION
+
+
+{Application Error} The exception %s (0x%08lx) occurred in the application at location 0x%08lx.
+
+0x0000023F
+
+ERROR_APP_INIT_FAILURE
+
+
+{Application Error} The application failed to initialize properly (0x%lx). Click OK to terminate the application.
+
+0x00000240
+
+ERROR_PAGEFILE_CREATE_FAILED
+
+
+{Unable to Create Paging File} The creation of the paging file %hs failed (%lx). The requested size was %ld.
+
+0x00000241
+
+ERROR_INVALID_IMAGE_HASH
+
+
+The hash for the image cannot be found in the system catalogs. The image is likely corrupt or the victim of tampering.
+
+0x00000242
+
+ERROR_NO_PAGEFILE
+
+
+{No Paging File Specified} No paging file was specified in the system configuration.
+
+0x00000243
+
+ERROR_ILLEGAL_FLOAT_CONTEXT
+
+
+{EXCEPTION} A real-mode application issued a floating-point instruction, and floating-point hardware is not present.
+
+0x00000244
+
+ERROR_NO_EVENT_PAIR
+
+
+An event pair synchronization operation was performed using the thread-specific client/server event pair object, but no event pair object was associated with the thread.
+
+0x00000245
+
+ERROR_DOMAIN_CTRLR_CONFIG_ERROR
+
+
+A domain server has an incorrect configuration.
+
+0x00000246
+
+ERROR_ILLEGAL_CHARACTER
+
+
+An illegal character was encountered. For a multibyte character set, this includes a lead byte without a succeeding trail byte. For the Unicode character set, this includes the characters 0xFFFF and 0xFFFE.
+
+0x00000247
+
+ERROR_UNDEFINED_CHARACTER
+
+
+The Unicode character is not defined in the Unicode character set installed on the system.
+
+0x00000248
+
+ERROR_FLOPPY_VOLUME
+
+
+The paging file cannot be created on a floppy disk.
+
+0x00000249
+
+ERROR_BIOS_FAILED_TO_CONNECT_INTERRUPT
+
+
+The system bios failed to connect a system interrupt to the device or bus for which the device is connected.
+
+0x0000024A
+
+ERROR_BACKUP_CONTROLLER
+
+
+This operation is only allowed for the primary domain controller (PDC) of the domain.
+
+0x0000024B
+
+ERROR_MUTANT_LIMIT_EXCEEDED
+
+
+An attempt was made to acquire a mutant such that its maximum count would have been exceeded.
+
+0x0000024C
+
+ERROR_FS_DRIVER_REQUIRED
+
+
+A volume has been accessed for which a file system driver is required that has not yet been loaded.
+
+0x0000024D
+
+ERROR_CANNOT_LOAD_REGISTRY_FILE
+
+
+{Registry File Failure} The registry cannot load the hive (file): %hs or its log or alternate. It is corrupt, absent, or not writable.
+
+0x0000024E
+
+ERROR_DEBUG_ATTACH_FAILED
+
+
+{Unexpected Failure in DebugActiveProcess} An unexpected failure occurred while processing a DebugActiveProcess API request. Choosing OK will terminate the process, and choosing Cancel will ignore the error.
+
+0x0000024F
+
+ERROR_SYSTEM_PROCESS_TERMINATED
+
+
+{Fatal System Error} The %hs system process terminated unexpectedly with a status of 0x%08x (0x%08x 0x%08x). The system has been shut down.
+
+0x00000250
+
+ERROR_DATA_NOT_ACCEPTED
+
+
+{Data Not Accepted} The transport driver interface (TDI) client could not handle the data received during an indication.
+
+0x00000251
+
+ERROR_VDM_HARD_ERROR
+
+
+The NT Virtual DOS Machine (NTVDM) encountered a hard error.
+
+0x00000252
+
+ERROR_DRIVER_CANCEL_TIMEOUT
+
+
+{Cancel Timeout} The driver %hs failed to complete a canceled I/O request in the allotted time.
+
+0x00000253
+
+ERROR_REPLY_MESSAGE_MISMATCH
+
+
+{Reply Message Mismatch} An attempt was made to reply to a local procedure call (LPC) message, but the thread specified by the client ID in the message was not waiting on that message.
+
+0x00000254
+
+ERROR_LOST_WRITEBEHIND_DATA
+
+
+{Delayed Write Failed} Windows was unable to save all the data for the file %hs. The data has been lost. This error might be caused by a failure of your computer hardware or network connection. Try to save this file elsewhere.
+
+0x00000255
+
+ERROR_CLIENT_SERVER_PARAMETERS_INVALID
+
+
+The parameters passed to the server in the client/server shared memory window were invalid. Too much data might have been put in the shared memory window.
+
+0x00000256
+
+ERROR_NOT_TINY_STREAM
+
+
+The stream is not a tiny stream.
+
+0x00000257
+
+ERROR_STACK_OVERFLOW_READ
+
+
+The request must be handled by the stack overflow code.
+
+0x00000258
+
+ERROR_CONVERT_TO_LARGE
+
+
+Internal OFS status codes indicating how an allocation operation is handled. Either it is retried after the containing onode is moved or the extent stream is converted to a large stream.
+
+0x00000259
+
+ERROR_FOUND_OUT_OF_SCOPE
+
+
+The attempt to find the object found an object matching by ID on the volume but it is out of the scope of the handle used for the operation.
+
+0x0000025A
+
+ERROR_ALLOCATE_BUCKET
+
+
+The bucket array must be grown. Retry transaction after doing so.
+
+0x0000025B
+
+ERROR_MARSHALL_OVERFLOW
+
+
+The user/kernel marshaling buffer has overflowed.
+
+0x0000025C
+
+ERROR_INVALID_VARIANT
+
+
+The supplied variant structure contains invalid data.
+
+0x0000025D
+
+ERROR_BAD_COMPRESSION_BUFFER
+
+
+The specified buffer contains ill-formed data.
+
+0x0000025E
+
+ERROR_AUDIT_FAILED
+
+
+{Audit Failed} An attempt to generate a security audit failed.
+
+0x0000025F
+
+ERROR_TIMER_RESOLUTION_NOT_SET
+
+
+The timer resolution was not previously set by the current process.
+
+0x00000260
+
+ERROR_INSUFFICIENT_LOGON_INFO
+
+
+There is insufficient account information to log you on.
+
+0x00000261
+
+ERROR_BAD_DLL_ENTRYPOINT
+
+
+{Invalid DLL Entrypoint} The dynamic link library %hs is not written correctly. The stack pointer has been left in an inconsistent state. The entry point should be declared as WINAPI or STDCALL. Select YES to fail the DLL load. Select NO to continue execution. Selecting NO can cause the application to operate incorrectly.
+
+0x00000262
+
+ERROR_BAD_SERVICE_ENTRYPOINT
+
+
+{Invalid Service Callback Entrypoint} The %hs service is not written correctly. The stack pointer has been left in an inconsistent state. The callback entry point should be declared as WINAPI or STDCALL. Selecting OK will cause the service to continue operation. However, the service process might operate incorrectly.
+
+0x00000263
+
+ERROR_IP_ADDRESS_CONFLICT1
+
+
+There is an IP address conflict with another system on the network.
+
+0x00000264
+
+ERROR_IP_ADDRESS_CONFLICT2
+
+
+There is an IP address conflict with another system on the network.
+
+0x00000265
+
+ERROR_REGISTRY_QUOTA_LIMIT
+
+
+{Low On Registry Space} The system has reached the maximum size allowed for the system part of the registry. Additional storage requests will be ignored.
+
+0x00000266
+
+ERROR_NO_CALLBACK_ACTIVE
+
+
+A callback return system service cannot be executed when no callback is active.
+
+0x00000267
+
+ERROR_PWD_TOO_SHORT
+
+
+The password provided is too short to meet the policy of your user account. Choose a longer password.
+
+0x00000268
+
+ERROR_PWD_TOO_RECENT
+
+
+The policy of your user account does not allow you to change passwords too frequently. This is done to prevent users from changing back to a familiar, but potentially discovered, password. If you feel your password has been compromised, contact your administrator immediately to have a new one assigned.
+
+0x00000269
+
+ERROR_PWD_HISTORY_CONFLICT
+
+
+You have attempted to change your password to one that you have used in the past. The policy of your user account does not allow this. Select a password that you have not previously used.
+
+0x0000026A
+
+ERROR_UNSUPPORTED_COMPRESSION
+
+
+The specified compression format is unsupported.
+
+0x0000026B
+
+ERROR_INVALID_HW_PROFILE
+
+
+The specified hardware profile configuration is invalid.
+
+0x0000026C
+
+ERROR_INVALID_PLUGPLAY_DEVICE_PATH
+
+
+The specified Plug and Play registry device path is invalid.
+
+0x0000026D
+
+ERROR_QUOTA_LIST_INCONSISTENT
+
+
+The specified quota list is internally inconsistent with its descriptor.
+
+0x0000026E
+
+ERROR_EVALUATION_EXPIRATION
+
+
+{Windows Evaluation Notification} The evaluation period for this installation of Windows has expired. This system will shut down in 1 hour. To restore access to this installation of Windows, upgrade this installation using a licensed distribution of this product.
+
+0x0000026F
+
+ERROR_ILLEGAL_DLL_RELOCATION
+
+
+{Illegal System DLL Relocation} The system DLL %hs was relocated in memory. The application will not run properly. The relocation occurred because the DLL %hs occupied an address range reserved for Windows system DLLs. The vendor supplying the DLL should be contacted for a new DLL.
+
+0x00000270
+
+ERROR_DLL_INIT_FAILED_LOGOFF
+
+
+{DLL Initialization Failed} The application failed to initialize because the window station is shutting down.
+
+0x00000271
+
+ERROR_VALIDATE_CONTINUE
+
+
+The validation process needs to continue on to the next step.
+
+0x00000272
+
+ERROR_NO_MORE_MATCHES
+
+
+There are no more matches for the current index enumeration.
+
+0x00000273
+
+ERROR_RANGE_LIST_CONFLICT
+
+
+The range could not be added to the range list because of a conflict.
+
+0x00000274
+
+ERROR_SERVER_SID_MISMATCH
+
+
+The server process is running under a SID different than that required by the client.
+
+0x00000275
+
+ERROR_CANT_ENABLE_DENY_ONLY
+
+
+A group marked use for deny only cannot be enabled.
+
+0x00000276
+
+ERROR_FLOAT_MULTIPLE_FAULTS
+
+
+{EXCEPTION} Multiple floating point faults.
+
+0x00000277
+
+ERROR_FLOAT_MULTIPLE_TRAPS
+
+
+{EXCEPTION} Multiple floating point traps.
+
+0x00000278
+
+ERROR_NOINTERFACE
+
+
+The requested interface is not supported.
+
+0x00000279
+
+ERROR_DRIVER_FAILED_SLEEP
+
+
+{System Standby Failed} The driver %hs does not support standby mode. Updating this driver might allow the system to go to standby mode.
+
+0x0000027A
+
+ERROR_CORRUPT_SYSTEM_FILE
+
+
+The system file %1 has become corrupt and has been replaced.
+
+0x0000027B
+
+ERROR_COMMITMENT_MINIMUM
+
+
+{Virtual Memory Minimum Too Low} Your system is low on virtual memory. Windows is increasing the size of your virtual memory paging file. During this process, memory requests for some applications might be denied. For more information, see Help.
+
+0x0000027C
+
+ERROR_PNP_RESTART_ENUMERATION
+
+
+A device was removed so enumeration must be restarted.
+
+0x0000027D
+
+ERROR_SYSTEM_IMAGE_BAD_SIGNATURE
+
+
+{Fatal System Error} The system image %s is not properly signed. The file has been replaced with the signed file. The system has been shut down.
+
+0x0000027E
+
+ERROR_PNP_REBOOT_REQUIRED
+
+
+Device will not start without a reboot.
+
+0x0000027F
+
+ERROR_INSUFFICIENT_POWER
+
+
+There is not enough power to complete the requested operation.
+
+0x00000281
+
+ERROR_SYSTEM_SHUTDOWN
+
+
+The system is in the process of shutting down.
+
+0x00000282
+
+ERROR_PORT_NOT_SET
+
+
+An attempt to remove a process DebugPort was made, but a port was not already associated with the process.
+
+0x00000283
+
+ERROR_DS_VERSION_CHECK_FAILURE
+
+
+This version of Windows is not compatible with the behavior version of directory forest, domain, or domain controller.
+
+0x00000284
+
+ERROR_RANGE_NOT_FOUND
+
+
+The specified range could not be found in the range list.
+
+0x00000286
+
+ERROR_NOT_SAFE_MODE_DRIVER
+
+
+The driver was not loaded because the system is booting into safe mode.
+
+0x00000287
+
+ERROR_FAILED_DRIVER_ENTRY
+
+
+The driver was not loaded because it failed its initialization call.
+
+0x00000288
+
+ERROR_DEVICE_ENUMERATION_ERROR
+
+
+The device encountered an error while applying power or reading the device configuration. This might be caused by a failure of your hardware or by a poor connection.
+
+0x00000289
+
+ERROR_MOUNT_POINT_NOT_RESOLVED
+
+
+The create operation failed because the name contained at least one mount point that resolves to a volume to which the specified device object is not attached.
+
+0x0000028A
+
+ERROR_INVALID_DEVICE_OBJECT_PARAMETER
+
+
+The device object parameter is either not a valid device object or is not attached to the volume specified by the file name.
+
+0x0000028B
+
+ERROR_MCA_OCCURED
+
+
+A machine check error has occurred. Check the system event log for additional information.
+
+0x0000028C
+
+ERROR_DRIVER_DATABASE_ERROR
+
+
+There was an error [%2] processing the driver database.
+
+0x0000028D
+
+ERROR_SYSTEM_HIVE_TOO_LARGE
+
+
+The system hive size has exceeded its limit.
+
+0x0000028E
+
+ERROR_DRIVER_FAILED_PRIOR_UNLOAD
+
+
+The driver could not be loaded because a previous version of the driver is still in memory.
+
+0x0000028F
+
+ERROR_VOLSNAP_PREPARE_HIBERNATE
+
+
+{Volume Shadow Copy Service} Wait while the Volume Shadow Copy Service prepares volume %hs for hibernation.
+
+0x00000290
+
+ERROR_HIBERNATION_FAILURE
+
+
+The system has failed to hibernate (the error code is %hs). Hibernation will be disabled until the system is restarted.
+
+0x00000299
+
+ERROR_FILE_SYSTEM_LIMITATION
+
+
+The requested operation could not be completed due to a file system limitation.
+
+0x0000029C
+
+ERROR_ASSERTION_FAILURE
+
+
+An assertion failure has occurred.
+
+0x0000029D
+
+ERROR_ACPI_ERROR
+
+
+An error occurred in the Advanced Configuration and Power Interface (ACPI) subsystem.
+
+0x0000029E
+
+ERROR_WOW_ASSERTION
+
+
+WOW assertion error.
+
+0x0000029F
+
+ERROR_PNP_BAD_MPS_TABLE
+
+
+A device is missing in the system BIOS MultiProcessor Specification (MPS) table. This device will not be used. Contact your system vendor for system BIOS update.
+
+0x000002A0
+
+ERROR_PNP_TRANSLATION_FAILED
+
+
+A translator failed to translate resources.
+
+0x000002A1
+
+ERROR_PNP_IRQ_TRANSLATION_FAILED
+
+
+An interrupt request (IRQ) translator failed to translate resources.
+
+0x000002A2
+
+ERROR_PNP_INVALID_ID
+
+
+Driver %2 returned invalid ID for a child device (%3).
+
+0x000002A3
+
+ERROR_WAKE_SYSTEM_DEBUGGER
+
+
+{Kernel Debugger Awakened} the system debugger was awakened by an interrupt.
+
+0x000002A4
+
+ERROR_HANDLES_CLOSED
+
+
+{Handles Closed} Handles to objects have been automatically closed because of the requested operation.
+
+0x000002A5
+
+ERROR_EXTRANEOUS_INFORMATION
+
+
+{Too Much Information} The specified ACL contained more information than was expected.
+
+0x000002A6
+
+ERROR_RXACT_COMMIT_NECESSARY
+
+
+This warning level status indicates that the transaction state already exists for the registry subtree, but that a transaction commit was previously aborted. The commit has NOT been completed, but it has not been rolled back either (so it can still be committed if desired).
+
+0x000002A7
+
+ERROR_MEDIA_CHECK
+
+
+{Media Changed} The media might have changed.
+
+0x000002A8
+
+ERROR_GUID_SUBSTITUTION_MADE
+
+
+{GUID Substitution} During the translation of a GUID to a Windows SID, no administratively defined GUID prefix was found. A substitute prefix was used, which will not compromise system security. However, this might provide more restrictive access than intended.
+
+0x000002A9
+
+ERROR_STOPPED_ON_SYMLINK
+
+
+The create operation stopped after reaching a symbolic link.
+
+0x000002AA
+
+ERROR_LONGJUMP
+
+
+A long jump has been executed.
+
+0x000002AB
+
+ERROR_PLUGPLAY_QUERY_VETOED
+
+
+The Plug and Play query operation was not successful.
+
+0x000002AC
+
+ERROR_UNWIND_CONSOLIDATE
+
+
+A frame consolidation has been executed.
+
+0x000002AD
+
+ERROR_REGISTRY_HIVE_RECOVERED
+
+
+{Registry Hive Recovered} Registry hive (file): %hs was corrupted and it has been recovered. Some data might have been lost.
+
+0x000002AE
+
+ERROR_DLL_MIGHT_BE_INSECURE
+
+
+The application is attempting to run executable code from the module %hs. This might be insecure. An alternative, %hs, is available. Should the application use the secure module %hs?
+
+0x000002AF
+
+ERROR_DLL_MIGHT_BE_INCOMPATIBLE
+
+
+The application is loading executable code from the module %hs. This is secure, but might be incompatible with previous releases of the operating system. An alternative, %hs, is available. Should the application use the secure module %hs?
+
+0x000002B0
+
+ERROR_DBG_EXCEPTION_NOT_HANDLED
+
+
+Debugger did not handle the exception.
+
+0x000002B1
+
+ERROR_DBG_REPLY_LATER
+
+
+Debugger will reply later.
+
+0x000002B2
+
+ERROR_DBG_UNABLE_TO_PROVIDE_HANDLE
+
+
+Debugger cannot provide handle.
+
+0x000002B3
+
+ERROR_DBG_TERMINATE_THREAD
+
+
+Debugger terminated thread.
+
+0x000002B4
+
+ERROR_DBG_TERMINATE_PROCESS
+
+
+Debugger terminated process.
+
+0x000002B5
+
+ERROR_DBG_CONTROL_C
+
+
+Debugger got control C.
+
+0x000002B6
+
+ERROR_DBG_PRINTEXCEPTION_C
+
+
+Debugger printed exception on control C.
+
+0x000002B7
+
+ERROR_DBG_RIPEXCEPTION
+
+
+Debugger received Routing Information Protocol (RIP) exception.
+
+0x000002B8
+
+ERROR_DBG_CONTROL_BREAK
+
+
+Debugger received control break.
+
+0x000002B9
+
+ERROR_DBG_COMMAND_EXCEPTION
+
+
+Debugger command communication exception.
+
+0x000002BA
+
+ERROR_OBJECT_NAME_EXISTS
+
+
+{Object Exists} An attempt was made to create an object and the object name already existed.
+
+0x000002BB
+
+ERROR_THREAD_WAS_SUSPENDED
+
+
+{Thread Suspended} A thread termination occurred while the thread was suspended. The thread was resumed and termination proceeded.
+
+0x000002BC
+
+ERROR_IMAGE_NOT_AT_BASE
+
+
+{Image Relocated} An image file could not be mapped at the address specified in the image file. Local fixes must be performed on this image.
+
+0x000002BD
+
+ERROR_RXACT_STATE_CREATED
+
+
+This informational level status indicates that a specified registry subtree transaction state did not yet exist and had to be created.
+
+0x000002BE
+
+ERROR_SEGMENT_NOTIFICATION
+
+
+{Segment Load} A virtual DOS machine (VDM) is loading, unloading, or moving an MS-DOS or Win16 program segment image. An exception is raised so a debugger can load, unload, or track symbols and breakpoints within these 16-bit segments.
+
+0x000002BF
+
+ERROR_BAD_CURRENT_DIRECTORY
+
+
+{Invalid Current Directory} The process cannot switch to the startup current directory %hs. Select OK to set current directory to %hs, or select CANCEL to exit.
+
+0x000002C0
+
+ERROR_FT_READ_RECOVERY_FROM_BACKUP
+
+
+{Redundant Read} To satisfy a read request, the NT fault-tolerant file system successfully read the requested data from a redundant copy. This was done because the file system encountered a failure on a member of the fault-tolerant volume, but it was unable to reassign the failing area of the device.
+
+0x000002C1
+
+ERROR_FT_WRITE_RECOVERY
+
+
+{Redundant Write} To satisfy a write request, the Windows NT operating system fault-tolerant file system successfully wrote a redundant copy of the information. This was done because the file system encountered a failure on a member of the fault-tolerant volume, but it was not able to reassign the failing area of the device.
+
+0x000002C2
+
+ERROR_IMAGE_MACHINE_TYPE_MISMATCH
+
+
+{Machine Type Mismatch} The image file %hs is valid, but is for a machine type other than the current machine. Select OK to continue, or CANCEL to fail the DLL load.
+
+0x000002C3
+
+ERROR_RECEIVE_PARTIAL
+
+
+{Partial Data Received} The network transport returned partial data to its client. The remaining data will be sent later.
+
+0x000002C4
+
+ERROR_RECEIVE_EXPEDITED
+
+
+{Expedited Data Received} The network transport returned data to its client that was marked as expedited by the remote system.
+
+0x000002C5
+
+ERROR_RECEIVE_PARTIAL_EXPEDITED
+
+
+{Partial Expedited Data Received} The network transport returned partial data to its client and this data was marked as expedited by the remote system. The remaining data will be sent later.
+
+0x000002C6
+
+ERROR_EVENT_DONE
+
+
+{TDI Event Done} The TDI indication has completed successfully.
+
+0x000002C7
+
+ERROR_EVENT_PENDING
+
+
+{TDI Event Pending} The TDI indication has entered the pending state.
+
+0x000002C8
+
+ERROR_CHECKING_FILE_SYSTEM
+
+
+Checking file system on %wZ.
+
+0x000002C9
+
+ERROR_FATAL_APP_EXIT
+
+
+{Fatal Application Exit} %hs.
+
+0x000002CA
+
+ERROR_PREDEFINED_HANDLE
+
+
+The specified registry key is referenced by a predefined handle.
+
+0x000002CB
+
+ERROR_WAS_UNLOCKED
+
+
+{Page Unlocked} The page protection of a locked page was changed to 'No Access' and the page was unlocked from memory and from the process.
+
+0x000002CD
+
+ERROR_WAS_LOCKED
+
+
+{Page Locked} One of the pages to lock was already locked.
+
+0x000002CF
+
+ERROR_ALREADY_WIN32
+
+
+The value already corresponds with a Win 32 error code.
+
+0x000002D0
+
+ERROR_IMAGE_MACHINE_TYPE_MISMATCH_EXE
+
+
+{Machine Type Mismatch} The image file %hs is valid, but is for a machine type other than the current machine.
+
+0x000002D1
+
+ERROR_NO_YIELD_PERFORMED
+
+
+A yield execution was performed and no thread was available to run.
+
+0x000002D2
+
+ERROR_TIMER_RESUME_IGNORED
+
+
+The resume flag to a timer API was ignored.
+
+0x000002D3
+
+ERROR_ARBITRATION_UNHANDLED
+
+
+The arbiter has deferred arbitration of these resources to its parent.
+
+0x000002D4
+
+ERROR_CARDBUS_NOT_SUPPORTED
+
+
+The inserted CardBus device cannot be started because of a configuration error on %hs"."
+
+0x000002D5
+
+ERROR_MP_PROCESSOR_MISMATCH
+
+
+The CPUs in this multiprocessor system are not all the same revision level. To use all processors the operating system restricts itself to the features of the least capable processor in the system. If problems occur with this system, contact the CPU manufacturer to see if this mix of processors is supported.
+
+0x000002D6
+
+ERROR_HIBERNATED
+
+
+The system was put into hibernation.
+
+0x000002D7
+
+ERROR_RESUME_HIBERNATION
+
+
+The system was resumed from hibernation.
+
+0x000002D8
+
+ERROR_FIRMWARE_UPDATED
+
+
+Windows has detected that the system firmware (BIOS) was updated (previous firmware date = %2, current firmware date %3).
+
+0x000002D9
+
+ERROR_DRIVERS_LEAKING_LOCKED_PAGES
+
+
+A device driver is leaking locked I/O pages, causing system degradation. The system has automatically enabled a tracking code to try and catch the culprit.
+
+0x000002DA
+
+ERROR_WAKE_SYSTEM
+
+
+The system has awoken.
+
+0x000002DF
+
+ERROR_ABANDONED_WAIT_0
+
+
+The call failed because the handle associated with it was closed.
+
+0x000002E4
+
+ERROR_ELEVATION_REQUIRED
+
+
+The requested operation requires elevation.
+
+0x000002E5
+
+ERROR_REPARSE
+
+
+A reparse should be performed by the object manager because the name of the file resulted in a symbolic link.
+
+0x000002E6
+
+ERROR_OPLOCK_BREAK_IN_PROGRESS
+
+
+An open/create operation completed while an oplock break is underway.
+
+0x000002E7
+
+ERROR_VOLUME_MOUNTED
+
+
+A new volume has been mounted by a file system.
+
+0x000002E8
+
+ERROR_RXACT_COMMITTED
+
+
+This success level status indicates that the transaction state already exists for the registry subtree, but that a transaction commit was previously aborted. The commit has now been completed.
+
+0x000002E9
+
+ERROR_NOTIFY_CLEANUP
+
+
+This indicates that a notify change request has been completed due to closing the handle which made the notify change request.
+
+0x000002EA
+
+ERROR_PRIMARY_TRANSPORT_CONNECT_FAILED
+
+
+{Connect Failure on Primary Transport} An attempt was made to connect to the remote server %hs on the primary transport, but the connection failed. The computer was able to connect on a secondary transport.
+
+0x000002EB
+
+ERROR_PAGE_FAULT_TRANSITION
+
+
+Page fault was a transition fault.
+
+0x000002EC
+
+ERROR_PAGE_FAULT_DEMAND_ZERO
+
+
+Page fault was a demand zero fault.
+
+0x000002ED
+
+ERROR_PAGE_FAULT_COPY_ON_WRITE
+
+
+Page fault was a demand zero fault.
+
+0x000002EE
+
+ERROR_PAGE_FAULT_GUARD_PAGE
+
+
+Page fault was a demand zero fault.
+
+0x000002EF
+
+ERROR_PAGE_FAULT_PAGING_FILE
+
+
+Page fault was satisfied by reading from a secondary storage device.
+
+0x000002F0
+
+ERROR_CACHE_PAGE_LOCKED
+
+
+Cached page was locked during operation.
+
+0x000002F1
+
+ERROR_CRASH_DUMP
+
+
+Crash dump exists in paging file.
+
+0x000002F2
+
+ERROR_BUFFER_ALL_ZEROS
+
+
+Specified buffer contains all zeros.
+
+0x000002F3
+
+ERROR_REPARSE_OBJECT
+
+
+A reparse should be performed by the object manager because the name of the file resulted in a symbolic link.
+
+0x000002F4
+
+ERROR_RESOURCE_REQUIREMENTS_CHANGED
+
+
+The device has succeeded a query-stop and its resource requirements have changed.
+
+0x000002F5
+
+ERROR_TRANSLATION_COMPLETE
+
+
+The translator has translated these resources into the global space and no further translations should be performed.
+
+0x000002F6
+
+ERROR_NOTHING_TO_TERMINATE
+
+
+A process being terminated has no threads to terminate.
+
+0x000002F7
+
+ERROR_PROCESS_NOT_IN_JOB
+
+
+The specified process is not part of a job.
+
+0x000002F8
+
+ERROR_PROCESS_IN_JOB
+
+
+The specified process is part of a job.
+
+0x000002F9
+
+ERROR_VOLSNAP_HIBERNATE_READY
+
+
+{Volume Shadow Copy Service} The system is now ready for hibernation.
+
+0x000002FA
+
+ERROR_FSFILTER_OP_COMPLETED_SUCCESSFULLY
+
+
+A file system or file system filter driver has successfully completed an FsFilter operation.
+
+0x000002FB
+
+ERROR_INTERRUPT_VECTOR_ALREADY_CONNECTED
+
+
+The specified interrupt vector was already connected.
+
+0x000002FC
+
+ERROR_INTERRUPT_STILL_CONNECTED
+
+
+The specified interrupt vector is still connected.
+
+0x000002FD
+
+ERROR_WAIT_FOR_OPLOCK
+
+
+An operation is blocked waiting for an oplock.
+
+0x000002FE
+
+ERROR_DBG_EXCEPTION_HANDLED
+
+
+Debugger handled exception.
+
+0x000002FF
+
+ERROR_DBG_CONTINUE
+
+
+Debugger continued.
+
+0x00000300
+
+ERROR_CALLBACK_POP_STACK
+
+
+An exception occurred in a user mode callback and the kernel callback frame should be removed.
+
+0x00000301
+
+ERROR_COMPRESSION_DISABLED
+
+
+Compression is disabled for this volume.
+
+0x00000302
+
+ERROR_CANTFETCHBACKWARDS
+
+
+The data provider cannot fetch backward through a result set.
+
+0x00000303
+
+ERROR_CANTSCROLLBACKWARDS
+
+
+The data provider cannot scroll backward through a result set.
+
+0x00000304
+
+ERROR_ROWSNOTRELEASED
+
+
+The data provider requires that previously fetched data is released before asking for more data.
+
+0x00000305
+
+ERROR_BAD_ACCESSOR_FLAGS
+
+
+The data provider was not able to interpret the flags set for a column binding in an accessor.
+
+0x00000306
+
+ERROR_ERRORS_ENCOUNTERED
+
+
+One or more errors occurred while processing the request.
+
+0x00000307
+
+ERROR_NOT_CAPABLE
+
+
+The implementation is not capable of performing the request.
+
+0x00000308
+
+ERROR_REQUEST_OUT_OF_SEQUENCE
+
+
+The client of a component requested an operation that is not valid given the state of the component instance.
+
+0x00000309
+
+ERROR_VERSION_PARSE_ERROR
+
+
+A version number could not be parsed.
+
+0x0000030A
+
+ERROR_BADSTARTPOSITION
+
+
+The iterator's start position is invalid.
+
+0x0000030B
+
+ERROR_MEMORY_HARDWARE
+
+
+The hardware has reported an uncorrectable memory error.
+
+0x0000030C
+
+ERROR_DISK_REPAIR_DISABLED
+
+
+The attempted operation required self-healing to be enabled.
+
+0x0000030D
+
+ERROR_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE
+
+
+The Desktop heap encountered an error while allocating session memory. There is more information in the system event log.
+
+0x0000030E
+
+ERROR_SYSTEM_POWERSTATE_TRANSITION
+
+
+The system power state is transitioning from %2 to %3.
+
+0x0000030F
+
+ERROR_SYSTEM_POWERSTATE_COMPLEX_TRANSITION
+
+
+The system power state is transitioning from %2 to %3 but could enter %4.
+
+0x00000310
+
+ERROR_MCA_EXCEPTION
+
+
+A thread is getting dispatched with MCA EXCEPTION because of MCA.
+
+0x00000311
+
+ERROR_ACCESS_AUDIT_BY_POLICY
+
+
+Access to %1 is monitored by policy rule %2.
+
+0x00000312
+
+ERROR_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY
+
+
+Access to %1 has been restricted by your administrator by policy rule %2.
+
+0x00000313
+
+ERROR_ABANDON_HIBERFILE
+
+
+A valid hibernation file has been invalidated and should be abandoned.
+
+0x00000314
+
+ERROR_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED
+
+
+{Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. This error can be caused by network connectivity issues. Try to save this file elsewhere.
+
+0x00000315
+
+ERROR_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR
+
+
+{Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. This error was returned by the server on which the file exists. Try to save this file elsewhere.
+
+0x00000316
+
+ERROR_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR
+
+
+{Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. This error can be caused if the device has been removed or the media is write-protected.
+
+0x000003E2
+
+ERROR_EA_ACCESS_DENIED
+
+
+Access to the extended attribute was denied.
+
+0x000003E3
+
+ERROR_OPERATION_ABORTED
+
+
+The I/O operation has been aborted because of either a thread exit or an application request.
+
+0x000003E4
+
+ERROR_IO_INCOMPLETE
+
+
+Overlapped I/O event is not in a signaled state.
+
+0x000003E5
+
+ERROR_IO_PENDING
+
+
+Overlapped I/O operation is in progress.
+
+0x000003E6
+
+ERROR_NOACCESS
+
+
+Invalid access to memory location.
+
+0x000003E7
+
+ERROR_SWAPERROR
+
+
+Error performing in-page operation.
+
+0x000003E9
+
+ERROR_STACK_OVERFLOW
+
+
+Recursion too deep; the stack overflowed.
+
+0x000003EA
+
+ERROR_INVALID_MESSAGE
+
+
+The window cannot act on the sent message.
+
+0x000003EB
+
+ERROR_CAN_NOT_COMPLETE
+
+
+Cannot complete this function.
+
+0x000003EC
+
+ERROR_INVALID_FLAGS
+
+
+Invalid flags.
+
+0x000003ED
+
+ERROR_UNRECOGNIZED_VOLUME
+
+
+The volume does not contain a recognized file system. Be sure that all required file system drivers are loaded and that the volume is not corrupted.
+
+0x000003EE
+
+ERROR_FILE_INVALID
+
+
+The volume for a file has been externally altered so that the opened file is no longer valid.
+
+0x000003EF
+
+ERROR_FULLSCREEN_MODE
+
+
+The requested operation cannot be performed in full-screen mode.
+
+0x000003F0
+
+ERROR_NO_TOKEN
+
+
+An attempt was made to reference a token that does not exist.
+
+0x000003F1
+
+ERROR_BADDB
+
+
+The configuration registry database is corrupt.
+
+0x000003F2
+
+ERROR_BADKEY
+
+
+The configuration registry key is invalid.
+
+0x000003F3
+
+ERROR_CANTOPEN
+
+
+The configuration registry key could not be opened.
+
+0x000003F4
+
+ERROR_CANTREAD
+
+
+The configuration registry key could not be read.
+
+0x000003F5
+
+ERROR_CANTWRITE
+
+
+The configuration registry key could not be written.
+
+0x000003F6
+
+ERROR_REGISTRY_RECOVERED
+
+
+One of the files in the registry database had to be recovered by use of a log or alternate copy. The recovery was successful.
+
+0x000003F7
+
+ERROR_REGISTRY_CORRUPT
+
+
+The registry is corrupted. The structure of one of the files containing registry data is corrupted, or the system's memory image of the file is corrupted, or the file could not be recovered because the alternate copy or log was absent or corrupted.
+
+0x000003F8
+
+ERROR_REGISTRY_IO_FAILED
+
+
+An I/O operation initiated by the registry failed and cannot be recovered. The registry could not read in, write out, or flush one of the files that contain the system's image of the registry.
+
+0x000003F9
+
+ERROR_NOT_REGISTRY_FILE
+
+
+The system attempted to load or restore a file into the registry, but the specified file is not in a registry file format.
+
+0x000003FA
+
+ERROR_KEY_DELETED
+
+
+Illegal operation attempted on a registry key that has been marked for deletion.
+
+0x000003FB
+
+ERROR_NO_LOG_SPACE
+
+
+System could not allocate the required space in a registry log.
+
+0x000003FC
+
+ERROR_KEY_HAS_CHILDREN
+
+
+Cannot create a symbolic link in a registry key that already has subkeys or values.
+
+0x000003FD
+
+ERROR_CHILD_MUST_BE_VOLATILE
+
+
+Cannot create a stable subkey under a volatile parent key.
+
+0x000003FE
+
+ERROR_NOTIFY_ENUM_DIR
+
+
+A notify change request is being completed and the information is not being returned in the caller's buffer. The caller now needs to enumerate the files to find the changes.
+
+0x0000041B
+
+ERROR_DEPENDENT_SERVICES_RUNNING
+
+
+A stop control has been sent to a service that other running services are dependent on.
+
+0x0000041C
+
+ERROR_INVALID_SERVICE_CONTROL
+
+
+The requested control is not valid for this service.
+
+0x0000041D
+
+ERROR_SERVICE_REQUEST_TIMEOUT
+
+
+The service did not respond to the start or control request in a timely fashion.
+
+0x0000041E
+
+ERROR_SERVICE_NO_THREAD
+
+
+A thread could not be created for the service.
+
+0x0000041F
+
+ERROR_SERVICE_DATABASE_LOCKED
+
+
+The service database is locked.
+
+0x00000420
+
+ERROR_SERVICE_ALREADY_RUNNING
+
+
+An instance of the service is already running.
+
+0x00000421
+
+ERROR_INVALID_SERVICE_ACCOUNT
+
+
+The account name is invalid or does not exist, or the password is invalid for the account name specified.
+
+0x00000422
+
+ERROR_SERVICE_DISABLED
+
+
+The service cannot be started, either because it is disabled or because it has no enabled devices associated with it.
+
+0x00000423
+
+ERROR_CIRCULAR_DEPENDENCY
+
+
+Circular service dependency was specified.
+
+0x00000424
+
+ERROR_SERVICE_DOES_NOT_EXIST
+
+
+The specified service does not exist as an installed service.
+
+0x00000425
+
+ERROR_SERVICE_CANNOT_ACCEPT_CTRL
+
+
+The service cannot accept control messages at this time.
+
+0x00000426
+
+ERROR_SERVICE_NOT_ACTIVE
+
+
+The service has not been started.
+
+0x00000427
+
+ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
+
+
+The service process could not connect to the service controller.
+
+0x00000428
+
+ERROR_EXCEPTION_IN_SERVICE
+
+
+An exception occurred in the service when handling the control request.
+
+0x00000429
+
+ERROR_DATABASE_DOES_NOT_EXIST
+
+
+The database specified does not exist.
+
+0x0000042A
+
+ERROR_SERVICE_SPECIFIC_ERROR
+
+
+The service has returned a service-specific error code.
+
+0x0000042B
+
+ERROR_PROCESS_ABORTED
+
+
+The process terminated unexpectedly.
+
+0x0000042C
+
+ERROR_SERVICE_DEPENDENCY_FAIL
+
+
+The dependency service or group failed to start.
+
+0x0000042D
+
+ERROR_SERVICE_LOGON_FAILED
+
+
+The service did not start due to a logon failure.
+
+0x0000042E
+
+ERROR_SERVICE_START_HANG
+
+
+After starting, the service stopped responding in a start-pending state.
+
+0x0000042F
+
+ERROR_INVALID_SERVICE_LOCK
+
+
+The specified service database lock is invalid.
+
+0x00000430
+
+ERROR_SERVICE_MARKED_FOR_DELETE
+
+
+The specified service has been marked for deletion.
+
+0x00000431
+
+ERROR_SERVICE_EXISTS
+
+
+The specified service already exists.
+
+0x00000432
+
+ERROR_ALREADY_RUNNING_LKG
+
+
+The system is currently running with the last-known-good configuration.
+
+0x00000433
+
+ERROR_SERVICE_DEPENDENCY_DELETED
+
+
+The dependency service does not exist or has been marked for deletion.
+
+0x00000434
+
+ERROR_BOOT_ALREADY_ACCEPTED
+
+
+The current boot has already been accepted for use as the last-known-good control set.
+
+0x00000435
+
+ERROR_SERVICE_NEVER_STARTED
+
+
+No attempts to start the service have been made since the last boot.
+
+0x00000436
+
+ERROR_DUPLICATE_SERVICE_NAME
+
+
+The name is already in use as either a service name or a service display name.
+
+0x00000437
+
+ERROR_DIFFERENT_SERVICE_ACCOUNT
+
+
+The account specified for this service is different from the account specified for other services running in the same process.
+
+0x00000438
+
+ERROR_CANNOT_DETECT_DRIVER_FAILURE
+
+
+Failure actions can only be set for Win32 services, not for drivers.
+
+0x00000439
+
+ERROR_CANNOT_DETECT_PROCESS_ABORT
+
+
+This service runs in the same process as the service control manager. Therefore, the service control manager cannot take action if this service's process terminates unexpectedly.
+
+0x0000043A
+
+ERROR_NO_RECOVERY_PROGRAM
+
+
+No recovery program has been configured for this service.
+
+0x0000043B
+
+ERROR_SERVICE_NOT_IN_EXE
+
+
+The executable program that this service is configured to run in does not implement the service.
+
+0x0000043C
+
+ERROR_NOT_SAFEBOOT_SERVICE
+
+
+This service cannot be started in Safe Mode.
+
+0x0000044C
+
+ERROR_END_OF_MEDIA
+
+
+The physical end of the tape has been reached.
+
+0x0000044D
+
+ERROR_FILEMARK_DETECTED
+
+
+A tape access reached a filemark.
+
+0x0000044E
+
+ERROR_BEGINNING_OF_MEDIA
+
+
+The beginning of the tape or a partition was encountered.
+
+0x0000044F
+
+ERROR_SETMARK_DETECTED
+
+
+A tape access reached the end of a set of files.
+
+0x00000450
+
+ERROR_NO_DATA_DETECTED
+
+
+No more data is on the tape.
+
+0x00000451
+
+ERROR_PARTITION_FAILURE
+
+
+Tape could not be partitioned.
+
+0x00000452
+
+ERROR_INVALID_BLOCK_LENGTH
+
+
+When accessing a new tape of a multivolume partition, the current block size is incorrect.
+
+0x00000453
+
+ERROR_DEVICE_NOT_PARTITIONED
+
+
+Tape partition information could not be found when loading a tape.
+
+0x00000454
+
+ERROR_UNABLE_TO_LOCK_MEDIA
+
+
+Unable to lock the media eject mechanism.
+
+0x00000455
+
+ERROR_UNABLE_TO_UNLOAD_MEDIA
+
+
+Unable to unload the media.
+
+0x00000456
+
+ERROR_MEDIA_CHANGED
+
+
+The media in the drive might have changed.
+
+0x00000457
+
+ERROR_BUS_RESET
+
+
+The I/O bus was reset.
+
+0x00000458
+
+ERROR_NO_MEDIA_IN_DRIVE
+
+
+No media in drive.
+
+0x00000459
+
+ERROR_NO_UNICODE_TRANSLATION
+
+
+No mapping for the Unicode character exists in the target multibyte code page.
+
+0x0000045A
+
+ERROR_DLL_INIT_FAILED
+
+
+A DLL initialization routine failed.
+
+0x0000045B
+
+ERROR_SHUTDOWN_IN_PROGRESS
+
+
+A system shutdown is in progress.
+
+0x0000045C
+
+ERROR_NO_SHUTDOWN_IN_PROGRESS
+
+
+Unable to abort the system shutdown because no shutdown was in progress.
+
+0x0000045D
+
+ERROR_IO_DEVICE
+
+
+The request could not be performed because of an I/O device error.
+
+0x0000045E
+
+ERROR_SERIAL_NO_DEVICE
+
+
+No serial device was successfully initialized. The serial driver will unload.
+
+0x0000045F
+
+ERROR_IRQ_BUSY
+
+
+Unable to open a device that was sharing an IRQ with other devices. At least one other device that uses that IRQ was already opened.
+
+0x00000460
+
+ERROR_MORE_WRITES
+
+
+A serial I/O operation was completed by another write to the serial port. (The IOCTL_SERIAL_XOFF_COUNTER reached zero.)
+
+0x00000461
+
+ERROR_COUNTER_TIMEOUT
+
+
+A serial I/O operation completed because the time-out period expired. (The IOCTL_SERIAL_XOFF_COUNTER did not reach zero.)
+
+0x00000462
+
+ERROR_FLOPPY_ID_MARK_NOT_FOUND
+
+
+No ID address mark was found on the floppy disk.
+
+0x00000463
+
+ERROR_FLOPPY_WRONG_CYLINDER
+
+
+Mismatch between the floppy disk sector ID field and the floppy disk controller track address.
+
+0x00000464
+
+ERROR_FLOPPY_UNKNOWN_ERROR
+
+
+The floppy disk controller reported an error that is not recognized by the floppy disk driver.
+
+0x00000465
+
+ERROR_FLOPPY_BAD_REGISTERS
+
+
+The floppy disk controller returned inconsistent results in its registers.
+
+0x00000466
+
+ERROR_DISK_RECALIBRATE_FAILED
+
+
+While accessing the hard disk, a recalibrate operation failed, even after retries.
+
+0x00000467
+
+ERROR_DISK_OPERATION_FAILED
+
+
+While accessing the hard disk, a disk operation failed even after retries.
+
+0x00000468
+
+ERROR_DISK_RESET_FAILED
+
+
+While accessing the hard disk, a disk controller reset was needed, but that also failed.
+
+0x00000469
+
+ERROR_EOM_OVERFLOW
+
+
+Physical end of tape encountered.
+
+0x0000046A
+
+ERROR_NOT_ENOUGH_SERVER_MEMORY
+
+
+Not enough server storage is available to process this command.
+
+0x0000046B
+
+ERROR_POSSIBLE_DEADLOCK
+
+
+A potential deadlock condition has been detected.
+
+0x0000046C
+
+ERROR_MAPPED_ALIGNMENT
+
+
+The base address or the file offset specified does not have the proper alignment.
+
+0x00000474
+
+ERROR_SET_POWER_STATE_VETOED
+
+
+An attempt to change the system power state was vetoed by another application or driver.
+
+0x00000475
+
+ERROR_SET_POWER_STATE_FAILED
+
+
+The system BIOS failed an attempt to change the system power state.
+
+0x00000476
+
+ERROR_TOO_MANY_LINKS
+
+
+An attempt was made to create more links on a file than the file system supports.
+
+0x0000047E
+
+ERROR_OLD_WIN_VERSION
+
+
+The specified program requires a newer version of Windows.
+
+0x0000047F
+
+ERROR_APP_WRONG_OS
+
+
+The specified program is not a Windows or MS-DOS program.
+
+0x00000480
+
+ERROR_SINGLE_INSTANCE_APP
+
+
+Cannot start more than one instance of the specified program.
+
+0x00000481
+
+ERROR_RMODE_APP
+
+
+The specified program was written for an earlier version of Windows.
+
+0x00000482
+
+ERROR_INVALID_DLL
+
+
+One of the library files needed to run this application is damaged.
+
+0x00000483
+
+ERROR_NO_ASSOCIATION
+
+
+No application is associated with the specified file for this operation.
+
+0x00000484
+
+ERROR_DDE_FAIL
+
+
+An error occurred in sending the command to the application.
+
+0x00000485
+
+ERROR_DLL_NOT_FOUND
+
+
+One of the library files needed to run this application cannot be found.
+
+0x00000486
+
+ERROR_NO_MORE_USER_HANDLES
+
+
+The current process has used all of its system allowance of handles for Windows manager objects.
+
+0x00000487
+
+ERROR_MESSAGE_SYNC_ONLY
+
+
+The message can be used only with synchronous operations.
+
+0x00000488
+
+ERROR_SOURCE_ELEMENT_EMPTY
+
+
+The indicated source element has no media.
+
+0x00000489
+
+ERROR_DESTINATION_ELEMENT_FULL
+
+
+The indicated destination element already contains media.
+
+0x0000048A
+
+ERROR_ILLEGAL_ELEMENT_ADDRESS
+
+
+The indicated element does not exist.
+
+0x0000048B
+
+ERROR_MAGAZINE_NOT_PRESENT
+
+
+The indicated element is part of a magazine that is not present.
+
+0x0000048C
+
+ERROR_DEVICE_REINITIALIZATION_NEEDED
+
+
+The indicated device requires re-initialization due to hardware errors.
+
+0x0000048D
+
+ERROR_DEVICE_REQUIRES_CLEANING
+
+
+The device has indicated that cleaning is required before further operations are attempted.
+
+0x0000048E
+
+ERROR_DEVICE_DOOR_OPEN
+
+
+The device has indicated that its door is open.
+
+0x0000048F
+
+ERROR_DEVICE_NOT_CONNECTED
+
+
+The device is not connected.
+
+0x00000490
+
+ERROR_NOT_FOUND
+
+
+Element not found.
+
+0x00000491
+
+ERROR_NO_MATCH
+
+
+There was no match for the specified key in the index.
+
+0x00000492
+
+ERROR_SET_NOT_FOUND
+
+
+The property set specified does not exist on the object.
+
+0x00000493
+
+ERROR_POINT_NOT_FOUND
+
+
+The point passed to GetMouseMovePoints is not in the buffer.
+
+0x00000494
+
+ERROR_NO_TRACKING_SERVICE
+
+
+The tracking (workstation) service is not running.
+
+0x00000495
+
+ERROR_NO_VOLUME_ID
+
+
+The volume ID could not be found.
+
+0x00000497
+
+ERROR_UNABLE_TO_REMOVE_REPLACED
+
+
+Unable to remove the file to be replaced.
+
+0x00000498
+
+ERROR_UNABLE_TO_MOVE_REPLACEMENT
+
+
+Unable to move the replacement file to the file to be replaced. The file to be replaced has retained its original name.
+
+0x00000499
+
+ERROR_UNABLE_TO_MOVE_REPLACEMENT_2
+
+
+Unable to move the replacement file to the file to be replaced. The file to be replaced has been renamed using the backup name.
+
+0x0000049A
+
+ERROR_JOURNAL_DELETE_IN_PROGRESS
+
+
+The volume change journal is being deleted.
+
+0x0000049B
+
+ERROR_JOURNAL_NOT_ACTIVE
+
+
+The volume change journal is not active.
+
+0x0000049C
+
+ERROR_POTENTIAL_FILE_FOUND
+
+
+A file was found, but it might not be the correct file.
+
+0x0000049D
+
+ERROR_JOURNAL_ENTRY_DELETED
+
+
+The journal entry has been deleted from the journal.
+
+0x000004A6
+
+ERROR_SHUTDOWN_IS_SCHEDULED
+
+
+A system shutdown has already been scheduled.
+
+0x000004A7
+
+ERROR_SHUTDOWN_USERS_LOGGED_ON
+
+
+The system shutdown cannot be initiated because there are other users logged on to the computer.
+
+0x000004B0
+
+ERROR_BAD_DEVICE
+
+
+The specified device name is invalid.
+
+0x000004B1
+
+ERROR_CONNECTION_UNAVAIL
+
+
+The device is not currently connected but it is a remembered connection.
+
+0x000004B2
+
+ERROR_DEVICE_ALREADY_REMEMBERED
+
+
+The local device name has a remembered connection to another network resource.
+
+0x000004B3
+
+ERROR_NO_NET_OR_BAD_PATH
+
+
+The network path was either typed incorrectly, does not exist, or the network provider is not currently available. Try retyping the path or contact your network administrator.
+
+0x000004B4
+
+ERROR_BAD_PROVIDER
+
+
+The specified network provider name is invalid.
+
+0x000004B5
+
+ERROR_CANNOT_OPEN_PROFILE
+
+
+Unable to open the network connection profile.
+
+0x000004B6
+
+ERROR_BAD_PROFILE
+
+
+The network connection profile is corrupted.
+
+0x000004B7
+
+ERROR_NOT_CONTAINER
+
+
+Cannot enumerate a noncontainer.
+
+0x000004B8
+
+ERROR_EXTENDED_ERROR
+
+
+An extended error has occurred.
+
+0x000004B9
+
+ERROR_INVALID_GROUPNAME
+
+
+The format of the specified group name is invalid.
+
+0x000004BA
+
+ERROR_INVALID_COMPUTERNAME
+
+
+The format of the specified computer name is invalid.
+
+0x000004BB
+
+ERROR_INVALID_EVENTNAME
+
+
+The format of the specified event name is invalid.
+
+0x000004BC
+
+ERROR_INVALID_DOMAINNAME
+
+
+The format of the specified domain name is invalid.
+
+0x000004BD
+
+ERROR_INVALID_SERVICENAME
+
+
+The format of the specified service name is invalid.
+
+0x000004BE
+
+ERROR_INVALID_NETNAME
+
+
+The format of the specified network name is invalid.
+
+0x000004BF
+
+ERROR_INVALID_SHARENAME
+
+
+The format of the specified share name is invalid.
+
+0x000004C0
+
+ERROR_INVALID_PASSWORDNAME
+
+
+The format of the specified password is invalid.
+
+0x000004C1
+
+ERROR_INVALID_MESSAGENAME
+
+
+The format of the specified message name is invalid.
+
+0x000004C2
+
+ERROR_INVALID_MESSAGEDEST
+
+
+The format of the specified message destination is invalid.
+
+0x000004C3
+
+ERROR_SESSION_CREDENTIAL_CONFLICT
+
+
+Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the server or shared resource and try again.
+
+0x000004C4
+
+ERROR_REMOTE_SESSION_LIMIT_EXCEEDED
+
+
+An attempt was made to establish a session to a network server, but there are already too many sessions established to that server.
+
+0x000004C5
+
+ERROR_DUP_DOMAINNAME
+
+
+The workgroup or domain name is already in use by another computer on the network.
+
+0x000004C6
+
+ERROR_NO_NETWORK
+
+
+The network is not present or not started.
+
+0x000004C7
+
+ERROR_CANCELLED
+
+
+The operation was canceled by the user.
+
+0x000004C8
+
+ERROR_USER_MAPPED_FILE
+
+
+The requested operation cannot be performed on a file with a user-mapped section open.
+
+0x000004C9
+
+ERROR_CONNECTION_REFUSED
+
+
+The remote system refused the network connection.
+
+0x000004CA
+
+ERROR_GRACEFUL_DISCONNECT
+
+
+The network connection was gracefully closed.
+
+0x000004CB
+
+ERROR_ADDRESS_ALREADY_ASSOCIATED
+
+
+The network transport endpoint already has an address associated with it.
+
+0x000004CC
+
+ERROR_ADDRESS_NOT_ASSOCIATED
+
+
+An address has not yet been associated with the network endpoint.
+
+0x000004CD
+
+ERROR_CONNECTION_INVALID
+
+
+An operation was attempted on a nonexistent network connection.
+
+0x000004CE
+
+ERROR_CONNECTION_ACTIVE
+
+
+An invalid operation was attempted on an active network connection.
+
+0x000004CF
+
+ERROR_NETWORK_UNREACHABLE
+
+
+The network location cannot be reached. For information about network troubleshooting, see Windows Help.
+
+0x000004D0
+
+ERROR_HOST_UNREACHABLE
+
+
+The network location cannot be reached. For information about network troubleshooting, see Windows Help.
+
+0x000004D1
+
+ERROR_PROTOCOL_UNREACHABLE
+
+
+The network location cannot be reached. For information about network troubleshooting, see Windows Help.
+
+0x000004D2
+
+ERROR_PORT_UNREACHABLE
+
+
+No service is operating at the destination network endpoint on the remote system.
+
+0x000004D3
+
+ERROR_REQUEST_ABORTED
+
+
+The request was aborted.
+
+0x000004D4
+
+ERROR_CONNECTION_ABORTED
+
+
+The network connection was aborted by the local system.
+
+0x000004D5
+
+ERROR_RETRY
+
+
+The operation could not be completed. A retry should be performed.
+
+0x000004D6
+
+ERROR_CONNECTION_COUNT_LIMIT
+
+
+A connection to the server could not be made because the limit on the number of concurrent connections for this account has been reached.
+
+0x000004D7
+
+ERROR_LOGIN_TIME_RESTRICTION
+
+
+Attempting to log on during an unauthorized time of day for this account.
+
+0x000004D8
+
+ERROR_LOGIN_WKSTA_RESTRICTION
+
+
+The account is not authorized to log on from this station.
+
+0x000004D9
+
+ERROR_INCORRECT_ADDRESS
+
+
+The network address could not be used for the operation requested.
+
+0x000004DA
+
+ERROR_ALREADY_REGISTERED
+
+
+The service is already registered.
+
+0x000004DB
+
+ERROR_SERVICE_NOT_FOUND
+
+
+The specified service does not exist.
+
+0x000004DC
+
+ERROR_NOT_AUTHENTICATED
+
+
+The operation being requested was not performed because the user has not been authenticated.
+
+0x000004DD
+
+ERROR_NOT_LOGGED_ON
+
+
+The operation being requested was not performed because the user has not logged on to the network. The specified service does not exist.
+
+0x000004DE
+
+ERROR_CONTINUE
+
+
+Continue with work in progress.
+
+0x000004DF
+
+ERROR_ALREADY_INITIALIZED
+
+
+An attempt was made to perform an initialization operation when initialization has already been completed.
+
+0x000004E0
+
+ERROR_NO_MORE_DEVICES
+
+
+No more local devices.
+
+0x000004E1
+
+ERROR_NO_SUCH_SITE
+
+
+The specified site does not exist.
+
+0x000004E2
+
+ERROR_DOMAIN_CONTROLLER_EXISTS
+
+
+A domain controller with the specified name already exists.
+
+0x000004E3
+
+ERROR_ONLY_IF_CONNECTED
+
+
+This operation is supported only when you are connected to the server.
+
+0x000004E4
+
+ERROR_OVERRIDE_NOCHANGES
+
+
+The group policy framework should call the extension even if there are no changes.
+
+0x000004E5
+
+ERROR_BAD_USER_PROFILE
+
+
+The specified user does not have a valid profile.
+
+0x000004E6
+
+ERROR_NOT_SUPPORTED_ON_SBS
+
+
+This operation is not supported on a computer running Windows Server 2003 operating system for Small Business Server.
+
+0x000004E7
+
+ERROR_SERVER_SHUTDOWN_IN_PROGRESS
+
+
+The server machine is shutting down.
+
+0x000004E8
+
+ERROR_HOST_DOWN
+
+
+The remote system is not available. For information about network troubleshooting, see Windows Help.
+
+0x000004E9
+
+ERROR_NON_ACCOUNT_SID
+
+
+The security identifier provided is not from an account domain.
+
+0x000004EA
+
+ERROR_NON_DOMAIN_SID
+
+
+The security identifier provided does not have a domain component.
+
+0x000004EB
+
+ERROR_APPHELP_BLOCK
+
+
+AppHelp dialog canceled, thus preventing the application from starting.
+
+0x000004EC
+
+ERROR_ACCESS_DISABLED_BY_POLICY
+
+
+This program is blocked by Group Policy. For more information, contact your system administrator.
+
+0x000004ED
+
+ERROR_REG_NAT_CONSUMPTION
+
+
+A program attempt to use an invalid register value. Normally caused by an uninitialized register. This error is Itanium specific.
+
+0x000004EE
+
+ERROR_CSCSHARE_OFFLINE
+
+
+The share is currently offline or does not exist.
+
+0x000004EF
+
+ERROR_PKINIT_FAILURE
+
+
+The Kerberos protocol encountered an error while validating the KDC certificate during smartcard logon. There is more information in the system event log.
+
+0x000004F0
+
+ERROR_SMARTCARD_SUBSYSTEM_FAILURE
+
+
+The Kerberos protocol encountered an error while attempting to utilize the smartcard subsystem.
+
+0x000004F1
+
+ERROR_DOWNGRADE_DETECTED
+
+
+The system detected a possible attempt to compromise security. Ensure that you can contact the server that authenticated you.
+
+0x000004F7
+
+ERROR_MACHINE_LOCKED
+
+
+The machine is locked and cannot be shut down without the force option.
+
+0x000004F9
+
+ERROR_CALLBACK_SUPPLIED_INVALID_DATA
+
+
+An application-defined callback gave invalid data when called.
+
+0x000004FA
+
+ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED
+
+
+The Group Policy framework should call the extension in the synchronous foreground policy refresh.
+
+0x000004FB
+
+ERROR_DRIVER_BLOCKED
+
+
+This driver has been blocked from loading.
+
+0x000004FC
+
+ERROR_INVALID_IMPORT_OF_NON_DLL
+
+
+A DLL referenced a module that was neither a DLL nor the process's executable image.
+
+0x000004FD
+
+ERROR_ACCESS_DISABLED_WEBBLADE
+
+
+Windows cannot open this program because it has been disabled.
+
+0x000004FE
+
+ERROR_ACCESS_DISABLED_WEBBLADE_TAMPER
+
+
+Windows cannot open this program because the license enforcement system has been tampered with or become corrupted.
+
+0x000004FF
+
+ERROR_RECOVERY_FAILURE
+
+
+A transaction recover failed.
+
+0x00000500
+
+ERROR_ALREADY_FIBER
+
+
+The current thread has already been converted to a fiber.
+
+0x00000501
+
+ERROR_ALREADY_THREAD
+
+
+The current thread has already been converted from a fiber.
+
+0x00000502
+
+ERROR_STACK_BUFFER_OVERRUN
+
+
+The system detected an overrun of a stack-based buffer in this application. This overrun could potentially allow a malicious user to gain control of this application.
+
+0x00000503
+
+ERROR_PARAMETER_QUOTA_EXCEEDED
+
+
+Data present in one of the parameters is more than the function can operate on.
+
+0x00000504
+
+ERROR_DEBUGGER_INACTIVE
+
+
+An attempt to perform an operation on a debug object failed because the object is in the process of being deleted.
+
+0x00000505
+
+ERROR_DELAY_LOAD_FAILED
+
+
+An attempt to delay-load a .dll or get a function address in a delay-loaded .dll failed.
+
+0x00000506
+
+ERROR_VDM_DISALLOWED
+
+
+%1 is a 16-bit application. You do not have permissions to execute 16-bit applications. Check your permissions with your system administrator.
+
+0x00000507
+
+ERROR_UNIDENTIFIED_ERROR
+
+
+Insufficient information exists to identify the cause of failure.
+
+0x00000508
+
+ERROR_INVALID_CRUNTIME_PARAMETER
+
+
+The parameter passed to a C runtime function is incorrect.
+
+0x00000509
+
+ERROR_BEYOND_VDL
+
+
+The operation occurred beyond the valid data length of the file.
+
+0x0000050A
+
+ERROR_INCOMPATIBLE_SERVICE_SID_TYPE
+
+
+The service start failed because one or more services in the same process have an incompatible service SID type setting. A service with a restricted service SID type can only coexist in the same process with other services with a restricted SID type.
+
+0x0000050B
+
+ERROR_DRIVER_PROCESS_TERMINATED
+
+
+The process hosting the driver for this device has been terminated.
+
+0x0000050C
+
+ERROR_IMPLEMENTATION_LIMIT
+
+
+An operation attempted to exceed an implementation-defined limit.
+
+0x0000050D
+
+ERROR_PROCESS_IS_PROTECTED
+
+
+Either the target process, or the target thread's containing process, is a protected process.
+
+0x0000050E
+
+ERROR_SERVICE_NOTIFY_CLIENT_LAGGING
+
+
+The service notification client is lagging too far behind the current state of services in the machine.
+
+0x0000050F
+
+ERROR_DISK_QUOTA_EXCEEDED
+
+
+An operation failed because the storage quota was exceeded.
+
+0x00000510
+
+ERROR_CONTENT_BLOCKED
+
+
+An operation failed because the content was blocked.
+
+0x00000511
+
+ERROR_INCOMPATIBLE_SERVICE_PRIVILEGE
+
+
+A privilege that the service requires to function properly does not exist in the service account configuration. The Services Microsoft Management Console (MMC) snap-in (Services.msc) and the Local Security Settings MMC snap-in (Secpol.msc) can be used to view the service configuration and the account configuration.
+
+0x00000513
+
+ERROR_INVALID_LABEL
+
+
+Indicates a particular SID cannot be assigned as the label of an object.
+
+0x00000514
+
+ERROR_NOT_ALL_ASSIGNED
+
+
+Not all privileges or groups referenced are assigned to the caller.
+
+0x00000515
+
+ERROR_SOME_NOT_MAPPED
+
+
+Some mapping between account names and SIDs was not done.
+
+0x00000516
+
+ERROR_NO_QUOTAS_FOR_ACCOUNT
+
+
+No system quota limits are specifically set for this account.
+
+0x00000517
+
+ERROR_LOCAL_USER_SESSION_KEY
+
+
+No encryption key is available. A well-known encryption key was returned.
+
+0x00000518
+
+ERROR_NULL_LM_PASSWORD
+
+
+The password is too complex to be converted to a LAN Manager password. The LAN Manager password returned is a null string.
+
+0x00000519
+
+ERROR_UNKNOWN_REVISION
+
+
+The revision level is unknown.
+
+0x0000051A
+
+ERROR_REVISION_MISMATCH
+
+
+Indicates two revision levels are incompatible.
+
+0x0000051B
+
+ERROR_INVALID_OWNER
+
+
+This SID cannot be assigned as the owner of this object.
+
+ 0x0000051C
+
+ERROR_INVALID_PRIMARY_GROUP
+
+
+This SID cannot be assigned as the primary group of an object.
+
+0x0000051D
+
+ERROR_NO_IMPERSONATION_TOKEN
+
+
+An attempt has been made to operate on an impersonation token by a thread that is not currently impersonating a client.
+
+0x0000051E
+
+ERROR_CANT_DISABLE_MANDATORY
+
+
+The group cannot be disabled.
+
+0x0000051F
+
+ERROR_NO_LOGON_SERVERS
+
+
+There are currently no logon servers available to service the logon request.
+
+0x00000520
+
+ERROR_NO_SUCH_LOGON_SESSION
+
+
+A specified logon session does not exist. It might already have been terminated.
+
+0x00000521
+
+ERROR_NO_SUCH_PRIVILEGE
+
+
+A specified privilege does not exist.
+
+0x00000522
+
+ERROR_PRIVILEGE_NOT_HELD
+
+
+A required privilege is not held by the client.
+
+0x00000523
+
+ERROR_INVALID_ACCOUNT_NAME
+
+
+The name provided is not a properly formed account name.
+
+0x00000524
+
+ERROR_USER_EXISTS
+
+
+The specified account already exists.
+
+0x00000525
+
+ERROR_NO_SUCH_USER
+
+
+The specified account does not exist.
+
+0x00000526
+
+ERROR_GROUP_EXISTS
+
+
+The specified group already exists.
+
+0x00000527
+
+ERROR_NO_SUCH_GROUP
+
+
+The specified group does not exist.
+
+0x00000528
+
+ERROR_MEMBER_IN_GROUP
+
+
+Either the specified user account is already a member of the specified group, or the specified group cannot be deleted because it contains a member.
+
+0x00000529
+
+ERROR_MEMBER_NOT_IN_GROUP
+
+
+The specified user account is not a member of the specified group account.
+
+0x0000052A
+
+ERROR_LAST_ADMIN
+
+
+The last remaining administration account cannot be disabled or deleted.
+
+0x0000052B
+
+ERROR_WRONG_PASSWORD
+
+
+Unable to update the password. The value provided as the current password is incorrect.
+
+0x0000052C
+
+ERROR_ILL_FORMED_PASSWORD
+
+
+Unable to update the password. The value provided for the new password contains values that are not allowed in passwords.
+
+0x0000052D
+
+ERROR_PASSWORD_RESTRICTION
+
+
+Unable to update the password. The value provided for the new password does not meet the length, complexity, or history requirements of the domain.
+
+0x0000052E
+
+ERROR_LOGON_FAILURE
+
+
+Logon failure: Unknown user name or bad password.
+
+0x0000052F
+
+ERROR_ACCOUNT_RESTRICTION
+
+
+Logon failure: User account restriction. Possible reasons are blank passwords not allowed, logon hour restrictions, or a policy restriction has been enforced.
+
+0x00000530
+
+ERROR_INVALID_LOGON_HOURS
+
+
+Logon failure: Account logon time restriction violation.
+
+0x00000531
+
+ERROR_INVALID_WORKSTATION
+
+
+Logon failure: User not allowed to log on to this computer.
+
+0x00000532
+
+ERROR_PASSWORD_EXPIRED
+
+
+Logon failure: The specified account password has expired.
+
+0x00000533
+
+ERROR_ACCOUNT_DISABLED
+
+
+Logon failure: Account currently disabled.
+
+0x00000534
+
+ERROR_NONE_MAPPED
+
+
+No mapping between account names and SIDs was done.
+
+0x00000535
+
+ERROR_TOO_MANY_LUIDS_REQUESTED
+
+
+Too many local user identifiers (LUIDs) were requested at one time.
+
+0x00000536
+
+ERROR_LUIDS_EXHAUSTED
+
+
+No more LUIDs are available.
+
+0x00000537
+
+ERROR_INVALID_SUB_AUTHORITY
+
+
+The sub-authority part of an SID is invalid for this particular use.
+
+0x00000538
+
+ERROR_INVALID_ACL
+
+
+The ACL structure is invalid.
+
+0x00000539
+
+ERROR_INVALID_SID
+
+
+The SID structure is invalid.
+
+0x0000053A
+
+ERROR_INVALID_SECURITY_DESCR
+
+
+The security descriptor structure is invalid.
+
+0x0000053C
+
+ERROR_BAD_INHERITANCE_ACL
+
+
+The inherited ACL or ACE could not be built.
+
+0x0000053D
+
+ERROR_SERVER_DISABLED
+
+
+The server is currently disabled.
+
+0x0000053E
+
+ERROR_SERVER_NOT_DISABLED
+
+
+The server is currently enabled.
+
+0x0000053F
+
+ERROR_INVALID_ID_AUTHORITY
+
+
+The value provided was an invalid value for an identifier authority.
+
+0x00000540
+
+ERROR_ALLOTTED_SPACE_EXCEEDED
+
+
+No more memory is available for security information updates.
+
+0x00000541
+
+ERROR_INVALID_GROUP_ATTRIBUTES
+
+
+The specified attributes are invalid, or incompatible with the attributes for the group as a whole.
+
+0x00000542
+
+ERROR_BAD_IMPERSONATION_LEVEL
+
+
+Either a required impersonation level was not provided, or the provided impersonation level is invalid.
+
+0x00000543
+
+ERROR_CANT_OPEN_ANONYMOUS
+
+
+Cannot open an anonymous level security token.
+
+0x00000544
+
+ERROR_BAD_VALIDATION_CLASS
+
+
+The validation information class requested was invalid.
+
+0x00000545
+
+ERROR_BAD_TOKEN_TYPE
+
+
+The type of the token is inappropriate for its attempted use.
+
+0x00000546
+
+ERROR_NO_SECURITY_ON_OBJECT
+
+
+Unable to perform a security operation on an object that has no associated security.
+
+0x00000547
+
+ERROR_CANT_ACCESS_DOMAIN_INFO
+
+
+Configuration information could not be read from the domain controller, either because the machine is unavailable, or access has been denied.
+
+0x00000548
+
+ERROR_INVALID_SERVER_STATE
+
+
+The SAM or local security authority (LSA) server was in the wrong state to perform the security operation.
+
+0x00000549
+
+ERROR_INVALID_DOMAIN_STATE
+
+
+The domain was in the wrong state to perform the security operation.
+
+0x0000054A
+
+ERROR_INVALID_DOMAIN_ROLE
+
+
+This operation is only allowed for the PDC of the domain.
+
+0x0000054B
+
+ERROR_NO_SUCH_DOMAIN
+
+
+The specified domain either does not exist or could not be contacted.
+
+0x0000054C
+
+ERROR_DOMAIN_EXISTS
+
+
+The specified domain already exists.
+
+0x0000054D
+
+ERROR_DOMAIN_LIMIT_EXCEEDED
+
+
+An attempt was made to exceed the limit on the number of domains per server.
+
+0x0000054E
+
+ERROR_INTERNAL_DB_CORRUPTION
+
+
+Unable to complete the requested operation because of either a catastrophic media failure or a data structure corruption on the disk.
+
+0x0000054F
+
+ERROR_INTERNAL_ERROR
+
+
+An internal error occurred.
+
+0x00000550
+
+ERROR_GENERIC_NOT_MAPPED
+
+
+Generic access types were contained in an access mask that should already be mapped to nongeneric types.
+
+0x00000551
+
+ERROR_BAD_DESCRIPTOR_FORMAT
+
+
+A security descriptor is not in the right format (absolute or self-relative).
+
+0x00000552
+
+ERROR_NOT_LOGON_PROCESS
+
+
+The requested action is restricted for use by logon processes only. The calling process has not registered as a logon process.
+
+0x00000553
+
+ERROR_LOGON_SESSION_EXISTS
+
+
+Cannot start a new logon session with an ID that is already in use.
+
+0x00000554
+
+ERROR_NO_SUCH_PACKAGE
+
+
+A specified authentication package is unknown.
+
+0x00000555
+
+ERROR_BAD_LOGON_SESSION_STATE
+
+
+The logon session is not in a state that is consistent with the requested operation.
+
+0x00000556
+
+ERROR_LOGON_SESSION_COLLISION
+
+
+The logon session ID is already in use.
+
+0x00000557
+
+ERROR_INVALID_LOGON_TYPE
+
+
+A logon request contained an invalid logon type value.
+
+0x00000558
+
+ERROR_CANNOT_IMPERSONATE
+
+
+Unable to impersonate using a named pipe until data has been read from that pipe.
+
+0x00000559
+
+ERROR_RXACT_INVALID_STATE
+
+
+The transaction state of a registry subtree is incompatible with the requested operation.
+
+0x0000055A
+
+ERROR_RXACT_COMMIT_FAILURE
+
+
+An internal security database corruption has been encountered.
+
+0x0000055B
+
+ERROR_SPECIAL_ACCOUNT
+
+
+Cannot perform this operation on built-in accounts.
+
+0x0000055C
+
+ERROR_SPECIAL_GROUP
+
+
+Cannot perform this operation on this built-in special group.
+
+0x0000055D
+
+ERROR_SPECIAL_USER
+
+
+Cannot perform this operation on this built-in special user.
+
+0x0000055E
+
+ERROR_MEMBERS_PRIMARY_GROUP
+
+
+The user cannot be removed from a group because the group is currently the user's primary group.
+
+0x0000055F
+
+ERROR_TOKEN_ALREADY_IN_USE
+
+
+The token is already in use as a primary token.
+
+0x00000560
+
+ERROR_NO_SUCH_ALIAS
+
+
+The specified local group does not exist.
+
+0x00000561
+
+ERROR_MEMBER_NOT_IN_ALIAS
+
+
+The specified account name is not a member of the group.
+
+0x00000562
+
+ERROR_MEMBER_IN_ALIAS
+
+
+The specified account name is already a member of the group.
+
+0x00000563
+
+ERROR_ALIAS_EXISTS
+
+
+The specified local group already exists.
+
+0x00000564
+
+ERROR_LOGON_NOT_GRANTED
+
+
+Logon failure: The user has not been granted the requested logon type at this computer.
+
+0x00000565
+
+ERROR_TOO_MANY_SECRETS
+
+
+The maximum number of secrets that can be stored in a single system has been exceeded.
+
+0x00000566
+
+ERROR_SECRET_TOO_LONG
+
+
+The length of a secret exceeds the maximum length allowed.
+
+0x00000567
+
+ERROR_INTERNAL_DB_ERROR
+
+
+The local security authority database contains an internal inconsistency.
+
+0x00000568
+
+ERROR_TOO_MANY_CONTEXT_IDS
+
+
+During a logon attempt, the user's security context accumulated too many SIDs.
+
+0x00000569
+
+ERROR_LOGON_TYPE_NOT_GRANTED
+
+
+Logon failure: The user has not been granted the requested logon type at this computer.
+
+0x0000056A
+
+ERROR_NT_CROSS_ENCRYPTION_REQUIRED
+
+
+A cross-encrypted password is necessary to change a user password.
+
+0x0000056B
+
+ERROR_NO_SUCH_MEMBER
+
+
+A member could not be added to or removed from the local group because the member does not exist.
+
+0x0000056C
+
+ERROR_INVALID_MEMBER
+
+
+A new member could not be added to a local group because the member has the wrong account type.
+
+0x0000056D
+
+ERROR_TOO_MANY_SIDS
+
+
+Too many SIDs have been specified.
+
+0x0000056E
+
+ERROR_LM_CROSS_ENCRYPTION_REQUIRED
+
+
+A cross-encrypted password is necessary to change this user password.
+
+0x0000056F
+
+ERROR_NO_INHERITANCE
+
+
+Indicates an ACL contains no inheritable components.
+
+0x00000570
+
+ERROR_FILE_CORRUPT
+
+
+The file or directory is corrupted and unreadable.
+
+0x00000571
+
+ERROR_DISK_CORRUPT
+
+
+The disk structure is corrupted and unreadable.
+
+0x00000572
+
+ERROR_NO_USER_SESSION_KEY
+
+
+There is no user session key for the specified logon session.
+
+0x00000573
+
+ERROR_LICENSE_QUOTA_EXCEEDED
+
+
+The service being accessed is licensed for a particular number of connections. No more connections can be made to the service at this time because the service has accepted the maximum number of connections.
+
+0x00000574
+
+ERROR_WRONG_TARGET_NAME
+
+
+Logon failure: The target account name is incorrect.
+
+0x00000575
+
+ERROR_MUTUAL_AUTH_FAILED
+
+
+Mutual authentication failed. The server's password is out of date at the domain controller.
+
+0x00000576
+
+ERROR_TIME_SKEW
+
+
+There is a time and/or date difference between the client and server.
+
+0x00000577
+
+ERROR_CURRENT_DOMAIN_NOT_ALLOWED
+
+
+This operation cannot be performed on the current domain.
+
+0x00000578
+
+ERROR_INVALID_WINDOW_HANDLE
+
+
+Invalid window handle.
+
+0x00000579
+
+ERROR_INVALID_MENU_HANDLE
+
+
+Invalid menu handle.
+
+0x0000057A
+
+ERROR_INVALID_CURSOR_HANDLE
+
+
+Invalid cursor handle.
+
+0x0000057B
+
+ERROR_INVALID_ACCEL_HANDLE
+
+
+Invalid accelerator table handle.
+
+0x0000057C
+
+ERROR_INVALID_HOOK_HANDLE
+
+
+Invalid hook handle.
+
+0x0000057D
+
+ERROR_INVALID_DWP_HANDLE
+
+
+Invalid handle to a multiple-window position structure.
+
+0x0000057E
+
+ERROR_TLW_WITH_WSCHILD
+
+
+Cannot create a top-level child window.
+
+0x0000057F
+
+ERROR_CANNOT_FIND_WND_CLASS
+
+
+Cannot find window class.
+
+0x00000580
+
+ERROR_WINDOW_OF_OTHER_THREAD
+
+
+Invalid window; it belongs to other thread.
+
+0x00000581
+
+ERROR_HOTKEY_ALREADY_REGISTERED
+
+
+Hot key is already registered.
+
+0x00000582
+
+ERROR_CLASS_ALREADY_EXISTS
+
+
+Class already exists.
+
+0x00000583
+
+ERROR_CLASS_DOES_NOT_EXIST
+
+
+Class does not exist.
+
+0x00000584
+
+ERROR_CLASS_HAS_WINDOWS
+
+
+Class still has open windows.
+
+0x00000585
+
+ERROR_INVALID_INDEX
+
+
+Invalid index.
+
+0x00000586
+
+ERROR_INVALID_ICON_HANDLE
+
+
+Invalid icon handle.
+
+0x00000587
+
+ERROR_PRIVATE_DIALOG_INDEX
+
+
+Using private DIALOG window words.
+
+0x00000588
+
+ERROR_LISTBOX_ID_NOT_FOUND
+
+
+The list box identifier was not found.
+
+0x00000589
+
+ERROR_NO_WILDCARD_CHARACTERS
+
+
+No wildcards were found.
+
+0x0000058A
+
+ERROR_CLIPBOARD_NOT_OPEN
+
+
+Thread does not have a clipboard open.
+
+0x0000058B
+
+ERROR_HOTKEY_NOT_REGISTERED
+
+
+Hot key is not registered.
+
+0x0000058C
+
+ERROR_WINDOW_NOT_DIALOG
+
+
+The window is not a valid dialog window.
+
+0x0000058D
+
+ERROR_CONTROL_ID_NOT_FOUND
+
+
+Control ID not found.
+
+0x0000058E
+
+ERROR_INVALID_COMBOBOX_MESSAGE
+
+
+Invalid message for a combo box because it does not have an edit control.
+
+0x0000058F
+
+ERROR_WINDOW_NOT_COMBOBOX
+
+
+The window is not a combo box.
+
+0x00000590
+
+ERROR_INVALID_EDIT_HEIGHT
+
+
+Height must be less than 256.
+
+0x00000591
+
+ERROR_DC_NOT_FOUND
+
+
+Invalid device context (DC) handle.
+
+0x00000592
+
+ERROR_INVALID_HOOK_FILTER
+
+
+Invalid hook procedure type.
+
+0x00000593
+
+ERROR_INVALID_FILTER_PROC
+
+
+Invalid hook procedure.
+
+0x00000594
+
+ERROR_HOOK_NEEDS_HMOD
+
+
+Cannot set nonlocal hook without a module handle.
+
+0x00000595
+
+ERROR_GLOBAL_ONLY_HOOK
+
+
+This hook procedure can only be set globally.
+
+0x00000596
+
+ERROR_JOURNAL_HOOK_SET
+
+
+The journal hook procedure is already installed.
+
+0x00000597
+
+ERROR_HOOK_NOT_INSTALLED
+
+
+The hook procedure is not installed.
+
+0x00000598
+
+ERROR_INVALID_LB_MESSAGE
+
+
+Invalid message for single-selection list box.
+
+0x00000599
+
+ERROR_SETCOUNT_ON_BAD_LB
+
+
+LB_SETCOUNT sent to non-lazy list box.
+
+0x0000059A
+
+ERROR_LB_WITHOUT_TABSTOPS
+
+
+This list box does not support tab stops.
+
+0x0000059B
+
+ERROR_DESTROY_OBJECT_OF_OTHER_THREAD
+
+
+Cannot destroy object created by another thread.
+
+0x0000059C
+
+ERROR_CHILD_WINDOW_MENU
+
+
+Child windows cannot have menus.
+
+0x0000059D
+
+ERROR_NO_SYSTEM_MENU
+
+
+The window does not have a system menu.
+
+0x0000059E
+
+ERROR_INVALID_MSGBOX_STYLE
+
+
+Invalid message box style.
+
+0x0000059F
+
+ERROR_INVALID_SPI_VALUE
+
+
+Invalid system-wide (SPI_*) parameter.
+
+0x000005A0
+
+ERROR_SCREEN_ALREADY_LOCKED
+
+
+Screen already locked.
+
+0x000005A1
+
+ERROR_HWNDS_HAVE_DIFF_PARENT
+
+
+All handles to windows in a multiple-window position structure must have the same parent.
+
+0x000005A2
+
+ERROR_NOT_CHILD_WINDOW
+
+
+The window is not a child window.
+
+0x000005A3
+
+ERROR_INVALID_GW_COMMAND
+
+
+Invalid GW_* command.
+
+0x000005A4
+
+ERROR_INVALID_THREAD_ID
+
+
+Invalid thread identifier.
+
+0x000005A5
+
+ERROR_NON_MDICHILD_WINDOW
+
+
+Cannot process a message from a window that is not a multiple document interface (MDI) window.
+
+0x000005A6
+
+ERROR_POPUP_ALREADY_ACTIVE
+
+
+Pop-up menu already active.
+
+0x000005A7
+
+ERROR_NO_SCROLLBARS
+
+
+The window does not have scroll bars.
+
+0x000005A8
+
+ERROR_INVALID_SCROLLBAR_RANGE
+
+
+Scroll bar range cannot be greater than MAXLONG.
+
+0x000005A9
+
+ERROR_INVALID_SHOWWIN_COMMAND
+
+
+Cannot show or remove the window in the way specified.
+
+0x000005AA
+
+ERROR_NO_SYSTEM_RESOURCES
+
+
+Insufficient system resources exist to complete the requested service.
+
+0x000005AB
+
+ERROR_NONPAGED_SYSTEM_RESOURCES
+
+
+Insufficient system resources exist to complete the requested service.
+
+0x000005AC
+
+ERROR_PAGED_SYSTEM_RESOURCES
+
+
+Insufficient system resources exist to complete the requested service.
+
+0x000005AD
+
+ERROR_WORKING_SET_QUOTA
+
+
+Insufficient quota to complete the requested service.
+
+0x000005AE
+
+ERROR_PAGEFILE_QUOTA
+
+
+Insufficient quota to complete the requested service.
+
+0x000005AF
+
+ERROR_COMMITMENT_LIMIT
+
+
+The paging file is too small for this operation to complete.
+
+0x000005B0
+
+ERROR_MENU_ITEM_NOT_FOUND
+
+
+A menu item was not found.
+
+0x000005B1
+
+ERROR_INVALID_KEYBOARD_HANDLE
+
+
+Invalid keyboard layout handle.
+
+0x000005B2
+
+ERROR_HOOK_TYPE_NOT_ALLOWED
+
+
+Hook type not allowed.
+
+0x000005B3
+
+ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION
+
+
+This operation requires an interactive window station.
+
+0x000005B4
+
+ERROR_TIMEOUT
+
+
+This operation returned because the time-out period expired.
+
+0x000005B5
+
+ERROR_INVALID_MONITOR_HANDLE
+
+
+Invalid monitor handle.
+
+0x000005B6
+
+ERROR_INCORRECT_SIZE
+
+
+Incorrect size argument.
+
+0x000005B7
+
+ERROR_SYMLINK_CLASS_DISABLED
+
+
+The symbolic link cannot be followed because its type is disabled.
+
+0x000005B8
+
+ERROR_SYMLINK_NOT_SUPPORTED
+
+
+This application does not support the current operation on symbolic links.
+
+0x000005DC
+
+ERROR_EVENTLOG_FILE_CORRUPT
+
+
+The event log file is corrupted.
+
+0x000005DD
+
+ERROR_EVENTLOG_CANT_START
+
+
+No event log file could be opened, so the event logging service did not start.
+
+0x000005DE
+
+ERROR_LOG_FILE_FULL
+
+
+The event log file is full.
+
+0x000005DF
+
+ERROR_EVENTLOG_FILE_CHANGED
+
+
+The event log file has changed between read operations.
+
+0x0000060E
+
+ERROR_INVALID_TASK_NAME
+
+
+The specified task name is invalid.
+
+0x0000060F
+
+ERROR_INVALID_TASK_INDEX
+
+
+The specified task index is invalid.
+
+0x00000610
+
+ERROR_THREAD_ALREADY_IN_TASK
+
+
+The specified thread is already joining a task.
+
+0x00000641
+
+ERROR_INSTALL_SERVICE_FAILURE
+
+
+The Windows Installer service could not be accessed. This can occur if the Windows Installer is not correctly installed. Contact your support personnel for assistance.
+
+0x00000642
+
+ERROR_INSTALL_USEREXIT
+
+
+User canceled installation.
+
+0x00000643
+
+ERROR_INSTALL_FAILURE
+
+
+Fatal error during installation.
+
+0x00000644
+
+ERROR_INSTALL_SUSPEND
+
+
+Installation suspended, incomplete.
+
+0x00000645
+
+ERROR_UNKNOWN_PRODUCT
+
+
+This action is valid only for products that are currently installed.
+
+0x00000646
+
+ERROR_UNKNOWN_FEATURE
+
+
+Feature ID not registered.
+
+0x00000647
+
+ERROR_UNKNOWN_COMPONENT
+
+
+Component ID not registered.
+
+0x00000648
+
+ERROR_UNKNOWN_PROPERTY
+
+
+Unknown property.
+
+0x00000649
+
+ERROR_INVALID_HANDLE_STATE
+
+
+Handle is in an invalid state.
+
+0x0000064A
+
+ERROR_BAD_CONFIGURATION
+
+
+The configuration data for this product is corrupt. Contact your support personnel.
+
+0x0000064B
+
+ERROR_INDEX_ABSENT
+
+
+Component qualifier not present.
+
+0x0000064C
+
+ERROR_INSTALL_SOURCE_ABSENT
+
+
+The installation source for this product is not available. Verify that the source exists and that you can access it.
+
+0x0000064D
+
+ERROR_INSTALL_PACKAGE_VERSION
+
+
+This installation package cannot be installed by the Windows Installer service. You must install a Windows service pack that contains a newer version of the Windows Installer service.
+
+0x0000064E
+
+ERROR_PRODUCT_UNINSTALLED
+
+
+Product is uninstalled.
+
+0x0000064F
+
+ERROR_BAD_QUERY_SYNTAX
+
+
+SQL query syntax invalid or unsupported.
+
+0x00000650
+
+ERROR_INVALID_FIELD
+
+
+Record field does not exist.
+
+0x00000651
+
+ERROR_DEVICE_REMOVED
+
+
+The device has been removed.
+
+0x00000652
+
+ERROR_INSTALL_ALREADY_RUNNING
+
+
+Another installation is already in progress. Complete that installation before proceeding with this install.
+
+0x00000653
+
+ERROR_INSTALL_PACKAGE_OPEN_FAILED
+
+
+This installation package could not be opened. Verify that the package exists and that you can access it, or contact the application vendor to verify that this is a valid Windows Installer package.
+
+0x00000654
+
+ERROR_INSTALL_PACKAGE_INVALID
+
+
+This installation package could not be opened. Contact the application vendor to verify that this is a valid Windows Installer package.
+
+0x00000655
+
+ERROR_INSTALL_UI_FAILURE
+
+
+There was an error starting the Windows Installer service user interface. Contact your support personnel.
+
+0x00000656
+
+ERROR_INSTALL_LOG_FAILURE
+
+
+Error opening installation log file. Verify that the specified log file location exists and that you can write to it.
+
+0x00000657
+
+ERROR_INSTALL_LANGUAGE_UNSUPPORTED
+
+
+The language of this installation package is not supported by your system.
+
+0x00000658
+
+ERROR_INSTALL_TRANSFORM_FAILURE
+
+
+Error applying transforms. Verify that the specified transform paths are valid.
+
+0x00000659
+
+ERROR_INSTALL_PACKAGE_REJECTED
+
+
+This installation is forbidden by system policy. Contact your system administrator.
+
+0x0000065A
+
+ERROR_FUNCTION_NOT_CALLED
+
+
+Function could not be executed.
+
+0x0000065B
+
+ERROR_FUNCTION_FAILED
+
+
+Function failed during execution.
+
+0x0000065C
+
+ERROR_INVALID_TABLE
+
+
+Invalid or unknown table specified.
+
+0x0000065D
+
+ERROR_DATATYPE_MISMATCH
+
+
+Data supplied is of wrong type.
+
+0x0000065E
+
+ERROR_UNSUPPORTED_TYPE
+
+
+Data of this type is not supported.
+
+0x0000065F
+
+ERROR_CREATE_FAILED
+
+
+The Windows Installer service failed to start. Contact your support personnel.
+
+0x00000660
+
+ERROR_INSTALL_TEMP_UNWRITABLE
+
+
+The Temp folder is on a drive that is full or is inaccessible. Free up space on the drive or verify that you have write permission on the Temp folder.
+
+0x00000661
+
+ERROR_INSTALL_PLATFORM_UNSUPPORTED
+
+
+This installation package is not supported by this processor type. Contact your product vendor.
+
+0x00000662
+
+ERROR_INSTALL_NOTUSED
+
+
+Component not used on this computer.
+
+0x00000663
+
+ERROR_PATCH_PACKAGE_OPEN_FAILED
+
+
+This update package could not be opened. Verify that the update package exists and that you can access it, or contact the application vendor to verify that this is a valid Windows Installer update package.
+
+0x00000664
+
+ERROR_PATCH_PACKAGE_INVALID
+
+
+This update package could not be opened. Contact the application vendor to verify that this is a valid Windows Installer update package.
+
+0x00000665
+
+ERROR_PATCH_PACKAGE_UNSUPPORTED
+
+
+This update package cannot be processed by the Windows Installer service. You must install a Windows service pack that contains a newer version of the Windows Installer service.
+
+0x00000666
+
+ERROR_PRODUCT_VERSION
+
+
+Another version of this product is already installed. Installation of this version cannot continue. To configure or remove the existing version of this product, use Add/Remove Programs in Control Panel.
+
+0x00000667
+
+ERROR_INVALID_COMMAND_LINE
+
+
+Invalid command-line argument. Consult the Windows Installer SDK for detailed command line help.
+
+0x00000668
+
+ERROR_INSTALL_REMOTE_DISALLOWED
+
+
+Only administrators have permission to add, remove, or configure server software during a Terminal Services remote session. If you want to install or configure software on the server, contact your network administrator.
+
+0x00000669
+
+ERROR_SUCCESS_REBOOT_INITIATED
+
+
+The requested operation completed successfully. The system will be restarted so the changes can take effect.
+
+0x0000066A
+
+ERROR_PATCH_TARGET_NOT_FOUND
+
+
+The upgrade cannot be installed by the Windows Installer service because the program to be upgraded might be missing, or the upgrade might update a different version of the program. Verify that the program to be upgraded exists on your computer and that you have the correct upgrade.
+
+0x0000066B
+
+ERROR_PATCH_PACKAGE_REJECTED
+
+
+The update package is not permitted by a software restriction policy.
+
+0x0000066C
+
+ERROR_INSTALL_TRANSFORM_REJECTED
+
+
+One or more customizations are not permitted by a software restriction policy.
+
+0x0000066D
+
+ERROR_INSTALL_REMOTE_PROHIBITED
+
+
+The Windows Installer does not permit installation from a Remote Desktop Connection.
+
+0x0000066E
+
+ERROR_PATCH_REMOVAL_UNSUPPORTED
+
+
+Uninstallation of the update package is not supported.
+
+0x0000066F
+
+ERROR_UNKNOWN_PATCH
+
+
+The update is not applied to this product.
+
+0x00000670
+
+ERROR_PATCH_NO_SEQUENCE
+
+
+No valid sequence could be found for the set of updates.
+
+0x00000671
+
+ERROR_PATCH_REMOVAL_DISALLOWED
+
+
+Update removal was disallowed by policy.
+
+0x00000672
+
+ERROR_INVALID_PATCH_XML
+
+
+The XML update data is invalid.
+
+0x00000673
+
+ERROR_PATCH_MANAGED_ADVERTISED_PRODUCT
+
+
+Windows Installer does not permit updating of managed advertised products. At least one feature of the product must be installed before applying the update.
+
+0x00000674
+
+ERROR_INSTALL_SERVICE_SAFEBOOT
+
+
+The Windows Installer service is not accessible in Safe Mode. Try again when your computer is not in Safe Mode or you can use System Restore to return your machine to a previous good state.
+
+0x000006A4
+
+RPC_S_INVALID_STRING_BINDING
+
+
+The string binding is invalid.
+
+0x000006A5
+
+RPC_S_WRONG_KIND_OF_BINDING
+
+
+The binding handle is not the correct type.
+
+0x000006A6
+
+RPC_S_INVALID_BINDING
+
+
+The binding handle is invalid.
+
+0x000006A7
+
+RPC_S_PROTSEQ_NOT_SUPPORTED
+
+
+The RPC protocol sequence is not supported.
+
+0x000006A8
+
+RPC_S_INVALID_RPC_PROTSEQ
+
+
+The RPC protocol sequence is invalid.
+
+0x000006A9
+
+RPC_S_INVALID_STRING_UUID
+
+
+The string UUID is invalid.
+
+0x000006AA
+
+RPC_S_INVALID_ENDPOINT_FORMAT
+
+
+The endpoint format is invalid.
+
+0x000006AB
+
+RPC_S_INVALID_NET_ADDR
+
+
+The network address is invalid.
+
+0x000006AC
+
+RPC_S_NO_ENDPOINT_FOUND
+
+
+No endpoint was found.
+
+0x000006AD
+
+RPC_S_INVALID_TIMEOUT
+
+
+The time-out value is invalid.
+
+0x000006AE
+
+RPC_S_OBJECT_NOT_FOUND
+
+
+The object UUID) was not found.
+
+0x000006AF
+
+RPC_S_ALREADY_REGISTERED
+
+
+The object UUID) has already been registered.
+
+0x000006B0
+
+RPC_S_TYPE_ALREADY_REGISTERED
+
+
+The type UUID has already been registered.
+
+0x000006B1
+
+RPC_S_ALREADY_LISTENING
+
+
+The RPC server is already listening.
+
+0x000006B2
+
+RPC_S_NO_PROTSEQS_REGISTERED
+
+
+No protocol sequences have been registered.
+
+0x000006B3
+
+RPC_S_NOT_LISTENING
+
+
+The RPC server is not listening.
+
+0x000006B4
+
+RPC_S_UNKNOWN_MGR_TYPE
+
+
+The manager type is unknown.
+
+0x000006B5
+
+RPC_S_UNKNOWN_IF
+
+
+The interface is unknown.
+
+0x000006B6
+
+RPC_S_NO_BINDINGS
+
+
+There are no bindings.
+
+0x000006B7
+
+RPC_S_NO_PROTSEQS
+
+
+There are no protocol sequences.
+
+0x000006B8
+
+RPC_S_CANT_CREATE_ENDPOINT
+
+
+The endpoint cannot be created.
+
+0x000006B9
+
+RPC_S_OUT_OF_RESOURCES
+
+
+Not enough resources are available to complete this operation.
+
+0x000006BA
+
+RPC_S_SERVER_UNAVAILABLE
+
+
+The RPC server is unavailable.
+
+0x000006BB
+
+RPC_S_SERVER_TOO_BUSY
+
+
+The RPC server is too busy to complete this operation.
+
+0x000006BC
+
+RPC_S_INVALID_NETWORK_OPTIONS
+
+
+The network options are invalid.
+
+0x000006BD
+
+RPC_S_NO_CALL_ACTIVE
+
+
+There are no RPCs active on this thread.
+
+0x000006BE
+
+RPC_S_CALL_FAILED
+
+
+The RPC failed.
+
+0x000006BF
+
+RPC_S_CALL_FAILED_DNE
+
+
+The RPC failed and did not execute.
+
+0x000006C0
+
+RPC_S_PROTOCOL_ERROR
+
+
+An RPC protocol error occurred.
+
+0x000006C1
+
+RPC_S_PROXY_ACCESS_DENIED
+
+
+Access to the HTTP proxy is denied.
+
+0x000006C2
+
+RPC_S_UNSUPPORTED_TRANS_SYN
+
+
+The transfer syntax is not supported by the RPC server.
+
+0x000006C4
+
+RPC_S_UNSUPPORTED_TYPE
+
+
+The UUID type is not supported.
+
+0x000006C5
+
+RPC_S_INVALID_TAG
+
+
+The tag is invalid.
+
+0x000006C6
+
+RPC_S_INVALID_BOUND
+
+
+The array bounds are invalid.
+
+0x000006C7
+
+RPC_S_NO_ENTRY_NAME
+
+
+The binding does not contain an entry name.
+
+0x000006C8
+
+RPC_S_INVALID_NAME_SYNTAX
+
+
+The name syntax is invalid.
+
+0x000006C9
+
+RPC_S_UNSUPPORTED_NAME_SYNTAX
+
+
+The name syntax is not supported.
+
+0x000006CB
+
+RPC_S_UUID_NO_ADDRESS
+
+
+No network address is available to use to construct a UUID.
+
+0x000006CC
+
+RPC_S_DUPLICATE_ENDPOINT
+
+
+The endpoint is a duplicate.
+
+0x000006CD
+
+RPC_S_UNKNOWN_AUTHN_TYPE
+
+
+The authentication type is unknown.
+
+0x000006CE
+
+RPC_S_MAX_CALLS_TOO_SMALL
+
+
+The maximum number of calls is too small.
+
+0x000006CF
+
+RPC_S_STRING_TOO_LONG
+
+
+The string is too long.
+
+0x000006D0
+
+RPC_S_PROTSEQ_NOT_FOUND
+
+
+The RPC protocol sequence was not found.
+
+0x000006D1
+
+RPC_S_PROCNUM_OUT_OF_RANGE
+
+
+The procedure number is out of range.
+
+0x000006D2
+
+RPC_S_BINDING_HAS_NO_AUTH
+
+
+The binding does not contain any authentication information.
+
+0x000006D3
+
+RPC_S_UNKNOWN_AUTHN_SERVICE
+
+
+The authentication service is unknown.
+
+0x000006D4
+
+RPC_S_UNKNOWN_AUTHN_LEVEL
+
+
+The authentication level is unknown.
+
+0x000006D5
+
+RPC_S_INVALID_AUTH_IDENTITY
+
+
+The security context is invalid.
+
+0x000006D6
+
+RPC_S_UNKNOWN_AUTHZ_SERVICE
+
+
+The authorization service is unknown.
+
+0x000006D7
+
+EPT_S_INVALID_ENTRY
+
+
+The entry is invalid.
+
+0x000006D8
+
+EPT_S_CANT_PERFORM_OP
+
+
+The server endpoint cannot perform the operation.
+
+0x000006D9
+
+EPT_S_NOT_REGISTERED
+
+
+There are no more endpoints available from the endpoint mapper.
+
+0x000006DA
+
+RPC_S_NOTHING_TO_EXPORT
+
+
+No interfaces have been exported.
+
+0x000006DB
+
+RPC_S_INCOMPLETE_NAME
+
+
+The entry name is incomplete.
+
+0x000006DC
+
+RPC_S_INVALID_VERS_OPTION
+
+
+The version option is invalid.
+
+0x000006DD
+
+RPC_S_NO_MORE_MEMBERS
+
+
+There are no more members.
+
+0x000006DE
+
+RPC_S_NOT_ALL_OBJS_UNEXPORTED
+
+
+There is nothing to unexport.
+
+0x000006DF
+
+RPC_S_INTERFACE_NOT_FOUND
+
+
+The interface was not found.
+
+0x000006E0
+
+RPC_S_ENTRY_ALREADY_EXISTS
+
+
+The entry already exists.
+
+0x000006E1
+
+RPC_S_ENTRY_NOT_FOUND
+
+
+The entry is not found.
+
+0x000006E2
+
+RPC_S_NAME_SERVICE_UNAVAILABLE
+
+
+The name service is unavailable.
+
+0x000006E3
+
+RPC_S_INVALID_NAF_ID
+
+
+The network address family is invalid.
+
+0x000006E4
+
+RPC_S_CANNOT_SUPPORT
+
+
+The requested operation is not supported.
+
+0x000006E5
+
+RPC_S_NO_CONTEXT_AVAILABLE
+
+
+No security context is available to allow impersonation.
+
+0x000006E6
+
+RPC_S_INTERNAL_ERROR
+
+
+An internal error occurred in an RPC.
+
+0x000006E7
+
+RPC_S_ZERO_DIVIDE
+
+
+The RPC server attempted an integer division by zero.
+
+0x000006E8
+
+RPC_S_ADDRESS_ERROR
+
+
+An addressing error occurred in the RPC server.
+
+0x000006E9
+
+RPC_S_FP_DIV_ZERO
+
+
+A floating-point operation at the RPC server caused a division by zero.
+
+0x000006EA
+
+RPC_S_FP_UNDERFLOW
+
+
+A floating-point underflow occurred at the RPC server.
+
+0x000006EB
+
+RPC_S_FP_OVERFLOW
+
+
+A floating-point overflow occurred at the RPC server.
+
+0x000006EC
+
+RPC_X_NO_MORE_ENTRIES
+
+
+The list of RPC servers available for the binding of auto handles has been exhausted.
+
+0x000006ED
+
+RPC_X_SS_CHAR_TRANS_OPEN_FAIL
+
+
+Unable to open the character translation table file.
+
+0x000006EE
+
+RPC_X_SS_CHAR_TRANS_SHORT_FILE
+
+
+The file containing the character translation table has fewer than 512 bytes.
+
+0x000006EF
+
+RPC_X_SS_IN_NULL_CONTEXT
+
+
+A null context handle was passed from the client to the host during an RPC.
+
+0x000006F1
+
+RPC_X_SS_CONTEXT_DAMAGED
+
+
+The context handle changed during an RPC.
+
+0x000006F2
+
+RPC_X_SS_HANDLES_MISMATCH
+
+
+The binding handles passed to an RPC do not match.
+
+0x000006F3
+
+RPC_X_SS_CANNOT_GET_CALL_HANDLE
+
+
+The stub is unable to get the RPC handle.
+
+0x000006F4
+
+RPC_X_NULL_REF_POINTER
+
+
+A null reference pointer was passed to the stub.
+
+0x000006F5
+
+RPC_X_ENUM_VALUE_OUT_OF_RANGE
+
+
+The enumeration value is out of range.
+
+0x000006F6
+
+RPC_X_BYTE_COUNT_TOO_SMALL
+
+
+The byte count is too small.
+
+0x000006F7
+
+RPC_X_BAD_STUB_DATA
+
+
+The stub received bad data.
+
+0x000006F8
+
+ERROR_INVALID_USER_BUFFER
+
+
+The supplied user buffer is not valid for the requested operation.
+
+0x000006F9
+
+ERROR_UNRECOGNIZED_MEDIA
+
+
+The disk media is not recognized. It might not be formatted.
+
+0x000006FA
+
+ERROR_NO_TRUST_LSA_SECRET
+
+
+The workstation does not have a trust secret.
+
+0x000006FB
+
+ERROR_NO_TRUST_SAM_ACCOUNT
+
+
+The security database on the server does not have a computer account for this workstation trust relationship.
+
+0x000006FC
+
+ERROR_TRUSTED_DOMAIN_FAILURE
+
+
+The trust relationship between the primary domain and the trusted domain failed.
+
+0x000006FD
+
+ERROR_TRUSTED_RELATIONSHIP_FAILURE
+
+
+The trust relationship between this workstation and the primary domain failed.
+
+0x000006FE
+
+ERROR_TRUST_FAILURE
+
+
+The network logon failed.
+
+0x000006FF
+
+RPC_S_CALL_IN_PROGRESS
+
+
+An RPC is already in progress for this thread.
+
+0x00000700
+
+ERROR_NETLOGON_NOT_STARTED
+
+
+An attempt was made to log on, but the network logon service was not started.
+
+0x00000701
+
+ERROR_ACCOUNT_EXPIRED
+
+
+The user's account has expired.
+
+0x00000702
+
+ERROR_REDIRECTOR_HAS_OPEN_HANDLES
+
+
+The redirector is in use and cannot be unloaded.
+
+0x00000703
+
+ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
+
+
+The specified printer driver is already installed.
+
+0x00000704
+
+ERROR_UNKNOWN_PORT
+
+
+The specified port is unknown.
+
+0x00000705
+
+ERROR_UNKNOWN_PRINTER_DRIVER
+
+
+The printer driver is unknown.
+
+0x00000706
+
+ERROR_UNKNOWN_PRINTPROCESSOR
+
+
+The print processor is unknown.
+
+0x00000707
+
+ERROR_INVALID_SEPARATOR_FILE
+
+
+The specified separator file is invalid.
+
+0x00000708
+
+ERROR_INVALID_PRIORITY
+
+
+The specified priority is invalid.
+
+0x00000709
+
+ERROR_INVALID_PRINTER_NAME
+
+
+The printer name is invalid.
+
+0x0000070A
+
+ERROR_PRINTER_ALREADY_EXISTS
+
+
+The printer already exists.
+
+0x0000070B
+
+ERROR_INVALID_PRINTER_COMMAND
+
+
+The printer command is invalid.
+
+0x0000070C
+
+ERROR_INVALID_DATATYPE
+
+
+The specified data type is invalid.
+
+0x0000070D
+
+ERROR_INVALID_ENVIRONMENT
+
+
+The environment specified is invalid.
+
+0x0000070E
+
+RPC_S_NO_MORE_BINDINGS
+
+
+There are no more bindings.
+
+0x0000070F
+
+ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT
+
+
+The account used is an interdomain trust account. Use your global user account or local user account to access this server.
+
+0x00000710
+
+ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT
+
+
+The account used is a computer account. Use your global user account or local user account to access this server.
+
+0x00000711
+
+ERROR_NOLOGON_SERVER_TRUST_ACCOUNT
+
+
+The account used is a server trust account. Use your global user account or local user account to access this server.
+
+0x00000712
+
+ERROR_DOMAIN_TRUST_INCONSISTENT
+
+
+The name or SID of the domain specified is inconsistent with the trust information for that domain.
+
+0x00000713
+
+ERROR_SERVER_HAS_OPEN_HANDLES
+
+
+The server is in use and cannot be unloaded.
+
+0x00000714
+
+ERROR_RESOURCE_DATA_NOT_FOUND
+
+
+The specified image file did not contain a resource section.
+
+0x00000715
+
+ERROR_RESOURCE_TYPE_NOT_FOUND
+
+
+The specified resource type cannot be found in the image file.
+
+0x00000716
+
+ERROR_RESOURCE_NAME_NOT_FOUND
+
+
+The specified resource name cannot be found in the image file.
+
+0x00000717
+
+ERROR_RESOURCE_LANG_NOT_FOUND
+
+
+The specified resource language ID cannot be found in the image file.
+
+0x00000718
+
+ERROR_NOT_ENOUGH_QUOTA
+
+
+Not enough quota is available to process this command.
+
+0x00000719
+
+RPC_S_NO_INTERFACES
+
+
+No interfaces have been registered.
+
+0x0000071A
+
+RPC_S_CALL_CANCELLED
+
+
+The RPC was canceled.
+
+0x0000071B
+
+RPC_S_BINDING_INCOMPLETE
+
+
+The binding handle does not contain all the required information.
+
+0x0000071C
+
+RPC_S_COMM_FAILURE
+
+
+A communications failure occurred during an RPC.
+
+0x0000071D
+
+RPC_S_UNSUPPORTED_AUTHN_LEVEL
+
+
+The requested authentication level is not supported.
+
+0x0000071E
+
+RPC_S_NO_PRINC_NAME
+
+
+No principal name is registered.
+
+0x0000071F
+
+RPC_S_NOT_RPC_ERROR
+
+
+The error specified is not a valid Windows RPC error code.
+
+0x00000720
+
+RPC_S_UUID_LOCAL_ONLY
+
+
+A UUID that is valid only on this computer has been allocated.
+
+0x00000721
+
+RPC_S_SEC_PKG_ERROR
+
+
+A security package-specific error occurred.
+
+0x00000722
+
+RPC_S_NOT_CANCELLED
+
+
+The thread is not canceled.
+
+0x00000723
+
+RPC_X_INVALID_ES_ACTION
+
+
+Invalid operation on the encoding/decoding handle.
+
+0x00000724
+
+RPC_X_WRONG_ES_VERSION
+
+
+Incompatible version of the serializing package.
+
+0x00000725
+
+RPC_X_WRONG_STUB_VERSION
+
+
+Incompatible version of the RPC stub.
+
+0x00000726
+
+RPC_X_INVALID_PIPE_OBJECT
+
+
+The RPC pipe object is invalid or corrupted.
+
+0x00000727
+
+RPC_X_WRONG_PIPE_ORDER
+
+
+An invalid operation was attempted on an RPC pipe object.
+
+0x00000728
+
+RPC_X_WRONG_PIPE_VERSION
+
+
+Unsupported RPC pipe version.
+
+0x0000076A
+
+RPC_S_GROUP_MEMBER_NOT_FOUND
+
+
+The group member was not found.
+
+0x0000076B
+
+EPT_S_CANT_CREATE
+
+
+The endpoint mapper database entry could not be created.
+
+0x0000076C
+
+RPC_S_INVALID_OBJECT
+
+
+The object UUID is the nil UUID.
+
+0x0000076D
+
+ERROR_INVALID_TIME
+
+
+The specified time is invalid.
+
+0x0000076E
+
+ERROR_INVALID_FORM_NAME
+
+
+The specified form name is invalid.
+
+0x0000076F
+
+ERROR_INVALID_FORM_SIZE
+
+
+The specified form size is invalid.
+
+0x00000770
+
+ERROR_ALREADY_WAITING
+
+
+The specified printer handle is already being waited on.
+
+0x00000771
+
+ERROR_PRINTER_DELETED
+
+
+The specified printer has been deleted.
+
+0x00000772
+
+ERROR_INVALID_PRINTER_STATE
+
+
+The state of the printer is invalid.
+
+0x00000773
+
+ERROR_PASSWORD_MUST_CHANGE
+
+
+The user's password must be changed before logging on the first time.
+
+0x00000774
+
+ERROR_DOMAIN_CONTROLLER_NOT_FOUND
+
+
+Could not find the domain controller for this domain.
+
+0x00000775
+
+ERROR_ACCOUNT_LOCKED_OUT
+
+
+The referenced account is currently locked out and cannot be logged on to.
+
+0x00000776
+
+OR_INVALID_OXID
+
+
+The object exporter specified was not found.
+
+0x00000777
+
+OR_INVALID_OID
+
+
+The object specified was not found.
+
+0x00000778
+
+OR_INVALID_SET
+
+
+The object set specified was not found.
+
+0x00000779
+
+RPC_S_SEND_INCOMPLETE
+
+
+Some data remains to be sent in the request buffer.
+
+0x0000077A
+
+RPC_S_INVALID_ASYNC_HANDLE
+
+
+Invalid asynchronous RPC handle.
+
+0x0000077B
+
+RPC_S_INVALID_ASYNC_CALL
+
+
+Invalid asynchronous RPC call handle for this operation.
+
+0x0000077C
+
+RPC_X_PIPE_CLOSED
+
+
+The RPC pipe object has already been closed.
+
+0x0000077D
+
+RPC_X_PIPE_DISCIPLINE_ERROR
+
+
+The RPC call completed before all pipes were processed.
+
+0x0000077E
+
+RPC_X_PIPE_EMPTY
+
+
+No more data is available from the RPC pipe.
+
+0x0000077F
+
+ERROR_NO_SITENAME
+
+
+No site name is available for this machine.
+
+0x00000780
+
+ERROR_CANT_ACCESS_FILE
+
+
+The file cannot be accessed by the system.
+
+0x00000781
+
+ERROR_CANT_RESOLVE_FILENAME
+
+
+The name of the file cannot be resolved by the system.
+
+0x00000782
+
+RPC_S_ENTRY_TYPE_MISMATCH
+
+
+The entry is not of the expected type.
+
+0x00000783
+
+RPC_S_NOT_ALL_OBJS_EXPORTED
+
+
+Not all object UUIDs could be exported to the specified entry.
+
+0x00000784
+
+RPC_S_INTERFACE_NOT_EXPORTED
+
+
+The interface could not be exported to the specified entry.
+
+0x00000785
+
+RPC_S_PROFILE_NOT_ADDED
+
+
+The specified profile entry could not be added.
+
+0x00000786
+
+RPC_S_PRF_ELT_NOT_ADDED
+
+
+The specified profile element could not be added.
+
+0x00000787
+
+RPC_S_PRF_ELT_NOT_REMOVED
+
+
+The specified profile element could not be removed.
+
+0x00000788
+
+RPC_S_GRP_ELT_NOT_ADDED
+
+
+The group element could not be added.
+
+0x00000789
+
+RPC_S_GRP_ELT_NOT_REMOVED
+
+
+The group element could not be removed.
+
+0x0000078A
+
+ERROR_KM_DRIVER_BLOCKED
+
+
+The printer driver is not compatible with a policy enabled on your computer that blocks Windows NT 4.0 operating system drivers.
+
+0x0000078B
+
+ERROR_CONTEXT_EXPIRED
+
+
+The context has expired and can no longer be used.
+
+0x0000078C
+
+ERROR_PER_USER_TRUST_QUOTA_EXCEEDED
+
+
+The current user's delegated trust creation quota has been exceeded.
+
+0x0000078D
+
+ERROR_ALL_USER_TRUST_QUOTA_EXCEEDED
+
+
+The total delegated trust creation quota has been exceeded.
+
+0x0000078E
+
+ERROR_USER_DELETE_TRUST_QUOTA_EXCEEDED
+
+
+The current user's delegated trust deletion quota has been exceeded.
+
+0x0000078F
+
+ERROR_AUTHENTICATION_FIREWALL_FAILED
+
+
+Logon failure: The machine you are logging on to is protected by an authentication firewall. The specified account is not allowed to authenticate to the machine.
+
+0x00000790
+
+ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED
+
+
+Remote connections to the Print Spooler are blocked by a policy set on your machine.
+
+0x000007D0
+
+ERROR_INVALID_PIXEL_FORMAT
+
+
+The pixel format is invalid.
+
+0x000007D1
+
+ERROR_BAD_DRIVER
+
+
+The specified driver is invalid.
+
+0x000007D2
+
+ERROR_INVALID_WINDOW_STYLE
+
+
+The window style or class attribute is invalid for this operation.
+
+0x000007D3
+
+ERROR_METAFILE_NOT_SUPPORTED
+
+
+The requested metafile operation is not supported.
+
+0x000007D4
+
+ERROR_TRANSFORM_NOT_SUPPORTED
+
+
+The requested transformation operation is not supported.
+
+0x000007D5
+
+ERROR_CLIPPING_NOT_SUPPORTED
+
+
+The requested clipping operation is not supported.
+
+0x000007DA
+
+ERROR_INVALID_CMM
+
+
+The specified color management module is invalid.
+
+0x000007DB
+
+ERROR_INVALID_PROFILE
+
+
+The specified color profile is invalid.
+
+0x000007DC
+
+ERROR_TAG_NOT_FOUND
+
+
+The specified tag was not found.
+
+0x000007DD
+
+ERROR_TAG_NOT_PRESENT
+
+
+A required tag is not present.
+
+0x000007DE
+
+ERROR_DUPLICATE_TAG
+
+
+The specified tag is already present.
+
+0x000007DF
+
+ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE
+
+
+The specified color profile is not associated with any device.
+
+0x000007E0
+
+ERROR_PROFILE_NOT_FOUND
+
+
+The specified color profile was not found.
+
+0x000007E1
+
+ERROR_INVALID_COLORSPACE
+
+
+The specified color space is invalid.
+
+0x000007E2
+
+ERROR_ICM_NOT_ENABLED
+
+
+Image Color Management is not enabled.
+
+0x000007E3
+
+ERROR_DELETING_ICM_XFORM
+
+
+There was an error while deleting the color transform.
+
+0x000007E4
+
+ERROR_INVALID_TRANSFORM
+
+
+The specified color transform is invalid.
+
+0x000007E5
+
+ERROR_COLORSPACE_MISMATCH
+
+
+The specified transform does not match the bitmap's color space.
+
+0x000007E6
+
+ERROR_INVALID_COLORINDEX
+
+
+The specified named color index is not present in the profile.
+
+0x000007E7
+
+ERROR_PROFILE_DOES_NOT_MATCH_DEVICE
+
+
+The specified profile is intended for a device of a different type than the specified device.
+
+0x00000836
+
+NERR_NetNotStarted
+
+
+The workstation driver is not installed.
+
+0x00000837
+
+NERR_UnknownServer
+
+
+The server could not be located.
+
+0x00000838
+
+NERR_ShareMem
+
+
+An internal error occurred. The network cannot access a shared memory segment.
+
+0x00000839
+
+NERR_NoNetworkResource
+
+
+A network resource shortage occurred.
+
+0x0000083A
+
+NERR_RemoteOnly
+
+
+This operation is not supported on workstations.
+
+0x0000083B
+
+NERR_DevNotRedirected
+
+
+The device is not connected.
+
+0x0000083C
+
+ERROR_CONNECTED_OTHER_PASSWORD
+
+
+The network connection was made successfully, but the user had to be prompted for a password other than the one originally specified.
+
+0x0000083D
+
+ERROR_CONNECTED_OTHER_PASSWORD_DEFAULT
+
+
+The network connection was made successfully using default credentials.
+
+0x00000842
+
+NERR_ServerNotStarted
+
+
+The Server service is not started.
+
+0x00000843
+
+NERR_ItemNotFound
+
+
+The queue is empty.
+
+0x00000844
+
+NERR_UnknownDevDir
+
+
+The device or directory does not exist.
+
+0x00000845
+
+NERR_RedirectedPath
+
+
+The operation is invalid on a redirected resource.
+
+0x00000846
+
+NERR_DuplicateShare
+
+
+The name has already been shared.
+
+0x00000847
+
+NERR_NoRoom
+
+
+The server is currently out of the requested resource.
+
+0x00000849
+
+NERR_TooManyItems
+
+
+Requested addition of items exceeds the maximum allowed.
+
+0x0000084A
+
+NERR_InvalidMaxUsers
+
+
+The Peer service supports only two simultaneous users.
+
+0x0000084B
+
+NERR_BufTooSmall
+
+
+The API return buffer is too small.
+
+0x0000084F
+
+NERR_RemoteErr
+
+
+A remote API error occurred.
+
+0x00000853
+
+NERR_LanmanIniError
+
+
+An error occurred when opening or reading the configuration file.
+
+0x00000858
+
+NERR_NetworkError
+
+
+A general network error occurred.
+
+0x00000859
+
+NERR_WkstaInconsistentState
+
+
+The Workstation service is in an inconsistent state. Restart the computer before restarting the Workstation service.
+
+0x0000085A
+
+NERR_WkstaNotStarted
+
+
+The Workstation service has not been started.
+
+0x0000085B
+
+NERR_BrowserNotStarted
+
+
+The requested information is not available.
+
+0x0000085C
+
+NERR_InternalError
+
+
+An internal error occurred.
+
+0x0000085D
+
+NERR_BadTransactConfig
+
+
+The server is not configured for transactions.
+
+0x0000085E
+
+NERR_InvalidAPI
+
+
+The requested API is not supported on the remote server.
+
+0x0000085F
+
+NERR_BadEventName
+
+
+The event name is invalid.
+
+0x00000860
+
+NERR_DupNameReboot
+
+
+The computer name already exists on the network. Change it and reboot the computer.
+
+0x00000862
+
+NERR_CfgCompNotFound
+
+
+The specified component could not be found in the configuration information.
+
+0x00000863
+
+NERR_CfgParamNotFound
+
+
+The specified parameter could not be found in the configuration information.
+
+0x00000865
+
+NERR_LineTooLong
+
+
+A line in the configuration file is too long.
+
+0x00000866
+
+NERR_QNotFound
+
+
+The printer does not exist.
+
+0x00000867
+
+NERR_JobNotFound
+
+
+The print job does not exist.
+
+0x00000868
+
+NERR_DestNotFound
+
+
+The printer destination cannot be found.
+
+0x00000869
+
+NERR_DestExists
+
+
+The printer destination already exists.
+
+0x0000086A
+
+NERR_QExists
+
+
+The print queue already exists.
+
+0x0000086B
+
+NERR_QNoRoom
+
+
+No more printers can be added.
+
+0x0000086C
+
+NERR_JobNoRoom
+
+
+No more print jobs can be added.
+
+0x0000086D
+
+NERR_DestNoRoom
+
+
+No more printer destinations can be added.
+
+0x0000086E
+
+NERR_DestIdle
+
+
+This printer destination is idle and cannot accept control operations.
+
+0x0000086F
+
+NERR_DestInvalidOp
+
+
+This printer destination request contains an invalid control function.
+
+0x00000870
+
+NERR_ProcNoRespond
+
+
+The print processor is not responding.
+
+0x00000871
+
+NERR_SpoolerNotLoaded
+
+
+The spooler is not running.
+
+0x00000872
+
+NERR_DestInvalidState
+
+
+This operation cannot be performed on the print destination in its current state.
+
+0x00000873
+
+NERR_QinvalidState
+
+
+This operation cannot be performed on the print queue in its current state.
+
+0x00000874
+
+NERR_JobInvalidState
+
+
+This operation cannot be performed on the print job in its current state.
+
+0x00000875
+
+NERR_SpoolNoMemory
+
+
+A spooler memory allocation failure occurred.
+
+0x00000876
+
+NERR_DriverNotFound
+
+
+The device driver does not exist.
+
+0x00000877
+
+NERR_DataTypeInvalid
+
+
+The data type is not supported by the print processor.
+
+0x00000878
+
+NERR_ProcNotFound
+
+
+The print processor is not installed.
+
+0x00000884
+
+NERR_ServiceTableLocked
+
+
+The service database is locked.
+
+0x00000885
+
+NERR_ServiceTableFull
+
+
+The service table is full.
+
+0x00000886
+
+NERR_ServiceInstalled
+
+
+The requested service has already been started.
+
+0x00000887
+
+NERR_ServiceEntryLocked
+
+
+The service does not respond to control actions.
+
+0x00000888
+
+NERR_ServiceNotInstalled
+
+
+The service has not been started.
+
+0x00000889
+
+NERR_BadServiceName
+
+
+The service name is invalid.
+
+0x0000088A
+
+NERR_ServiceCtlTimeout
+
+
+The service is not responding to the control function.
+
+0x0000088B
+
+NERR_ServiceCtlBusy
+
+
+The service control is busy.
+
+0x0000088C
+
+NERR_BadServiceProgName
+
+
+The configuration file contains an invalid service program name.
+
+0x0000088D
+
+NERR_ServiceNotCtrl
+
+
+The service could not be controlled in its present state.
+
+0x0000088E
+
+NERR_ServiceKillProc
+
+
+The service ended abnormally.
+
+0x0000088F
+
+NERR_ServiceCtlNotValid
+
+
+The requested pause or stop is not valid for this service.
+
+0x00000890
+
+NERR_NotInDispatchTbl
+
+
+The service control dispatcher could not find the service name in the dispatch table.
+
+0x00000891
+
+NERR_BadControlRecv
+
+
+The service control dispatcher pipe read failed.
+
+0x00000892
+
+NERR_ServiceNotStarting
+
+
+A thread for the new service could not be created.
+
+0x00000898
+
+NERR_AlreadyLoggedOn
+
+
+This workstation is already logged on to the LAN.
+
+0x00000899
+
+NERR_NotLoggedOn
+
+
+The workstation is not logged on to the LAN.
+
+0x0000089A
+
+NERR_BadUsername
+
+
+The user name or group name parameter is invalid.
+
+0x0000089B
+
+NERR_BadPassword
+
+
+The password parameter is invalid.
+
+0x0000089C
+
+NERR_UnableToAddName_W
+
+
+The logon processor did not add the message alias.
+
+0x0000089D
+
+NERR_UnableToAddName_F
+
+
+The logon processor did not add the message alias.
+
+0x0000089E
+
+NERR_UnableToDelName_W
+
+
+The logoff processor did not delete the message alias.
+
+0x0000089F
+
+NERR_UnableToDelName_F
+
+
+The logoff processor did not delete the message alias.
+
+0x000008A1
+
+NERR_LogonsPaused
+
+
+Network logons are paused.
+
+0x000008A2
+
+NERR_LogonServerConflict
+
+
+A centralized logon server conflict occurred.
+
+0x000008A3
+
+NERR_LogonNoUserPath
+
+
+The server is configured without a valid user path.
+
+0x000008A4
+
+NERR_LogonScriptError
+
+
+An error occurred while loading or running the logon script.
+
+0x000008A6
+
+NERR_StandaloneLogon
+
+
+The logon server was not specified. The computer will be logged on as STANDALONE.
+
+0x000008A7
+
+NERR_LogonServerNotFound
+
+
+The logon server could not be found.
+
+0x000008A8
+
+NERR_LogonDomainExists
+
+
+There is already a logon domain for this computer.
+
+0x000008A9
+
+NERR_NonValidatedLogon
+
+
+The logon server could not validate the logon.
+
+0x000008AB
+
+NERR_ACFNotFound
+
+
+The security database could not be found.
+
+0x000008AC
+
+NERR_GroupNotFound
+
+
+The group name could not be found.
+
+0x000008AD
+
+NERR_UserNotFound
+
+
+The user name could not be found.
+
+0x000008AE
+
+NERR_ResourceNotFound
+
+
+The resource name could not be found.
+
+0x000008AF
+
+NERR_GroupExists
+
+
+The group already exists.
+
+0x000008B0
+
+NERR_UserExists
+
+
+The user account already exists.
+
+0x000008B1
+
+NERR_ResourceExists
+
+
+The resource permission list already exists.
+
+0x000008B2
+
+NERR_NotPrimary
+
+
+This operation is allowed only on the PDC of the domain.
+
+0x000008B3
+
+NERR_ACFNotLoaded
+
+
+The security database has not been started.
+
+0x000008B4
+
+NERR_ACFNoRoom
+
+
+There are too many names in the user accounts database.
+
+0x000008B5
+
+NERR_ACFFileIOFail
+
+
+A disk I/O failure occurred.
+
+0x000008B6
+
+NERR_ACFTooManyLists
+
+
+The limit of 64 entries per resource was exceeded.
+
+0x000008B7
+
+NERR_UserLogon
+
+
+Deleting a user with a session is not allowed.
+
+0x000008B8
+
+NERR_ACFNoParent
+
+
+The parent directory could not be located.
+
+0x000008B9
+
+NERR_CanNotGrowSegment
+
+
+Unable to add to the security database session cache segment.
+
+0x000008BA
+
+NERR_SpeGroupOp
+
+
+This operation is not allowed on this special group.
+
+0x000008BB
+
+NERR_NotInCache
+
+
+This user is not cached in the user accounts database session cache.
+
+0x000008BC
+
+NERR_UserInGroup
+
+
+The user already belongs to this group.
+
+0x000008BD
+
+NERR_UserNotInGroup
+
+
+The user does not belong to this group.
+
+0x000008BE
+
+NERR_AccountUndefined
+
+
+This user account is undefined.
+
+0x000008BF
+
+NERR_AccountExpired
+
+
+This user account has expired.
+
+0x000008C0
+
+NERR_InvalidWorkstation
+
+
+The user is not allowed to log on from this workstation.
+
+0x000008C1
+
+NERR_InvalidLogonHours
+
+
+The user is not allowed to log on at this time.
+
+0x000008C2
+
+NERR_PasswordExpired
+
+
+The password of this user has expired.
+
+0x000008C3
+
+NERR_PasswordCantChange
+
+
+The password of this user cannot change.
+
+0x000008C4
+
+NERR_PasswordHistConflict
+
+
+This password cannot be used now.
+
+0x000008C5
+
+NERR_PasswordTooShort
+
+
+The password does not meet the password policy requirements. Check the minimum password length, password complexity, and password history requirements.
+
+0x000008C6
+
+NERR_PasswordTooRecent
+
+
+The password of this user is too recent to change.
+
+0x000008C7
+
+NERR_InvalidDatabase
+
+
+The security database is corrupted.
+
+0x000008C8
+
+NERR_DatabaseUpToDate
+
+
+No updates are necessary to this replicant network or local security database.
+
+0x000008C9
+
+NERR_SyncRequired
+
+
+This replicant database is outdated; synchronization is required.
+
+0x000008CA
+
+NERR_UseNotFound
+
+
+The network connection could not be found.
+
+0x000008CB
+
+NERR_BadAsgType
+
+
+This asg_type is invalid.
+
+0x000008CC
+
+NERR_DeviceIsShared
+
+
+This device is currently being shared.
+
+0x000008DE
+
+NERR_NoComputerName
+
+
+The computer name could not be added as a message alias. The name might already exist on the network.
+
+0x000008DF
+
+NERR_MsgAlreadyStarted
+
+
+The Messenger service is already started.
+
+0x000008E0
+
+NERR_MsgInitFailed
+
+
+The Messenger service failed to start.
+
+0x000008E1
+
+NERR_NameNotFound
+
+
+The message alias could not be found on the network.
+
+0x000008E2
+
+NERR_AlreadyForwarded
+
+
+This message alias has already been forwarded.
+
+0x000008E3
+
+NERR_AddForwarded
+
+
+This message alias has been added but is still forwarded.
+
+0x000008E4
+
+NERR_AlreadyExists
+
+
+This message alias already exists locally.
+
+0x000008E5
+
+NERR_TooManyNames
+
+
+The maximum number of added message aliases has been exceeded.
+
+0x000008E6
+
+NERR_DelComputerName
+
+
+The computer name could not be deleted.
+
+0x000008E7
+
+NERR_LocalForward
+
+
+Messages cannot be forwarded back to the same workstation.
+
+0x000008E8
+
+NERR_GrpMsgProcessor
+
+
+An error occurred in the domain message processor.
+
+0x000008E9
+
+NERR_PausedRemote
+
+
+The message was sent, but the recipient has paused the Messenger service.
+
+0x000008EA
+
+NERR_BadReceive
+
+
+The message was sent but not received.
+
+0x000008EB
+
+NERR_NameInUse
+
+
+The message alias is currently in use. Try again later.
+
+0x000008EC
+
+NERR_MsgNotStarted
+
+
+The Messenger service has not been started.
+
+0x000008ED
+
+NERR_NotLocalName
+
+
+The name is not on the local computer.
+
+0x000008EE
+
+NERR_NoForwardName
+
+
+The forwarded message alias could not be found on the network.
+
+0x000008EF
+
+NERR_RemoteFull
+
+
+The message alias table on the remote station is full.
+
+0x000008F0
+
+NERR_NameNotForwarded
+
+
+Messages for this alias are not currently being forwarded.
+
+0x000008F1
+
+NERR_TruncatedBroadcast
+
+
+The broadcast message was truncated.
+
+0x000008F6
+
+NERR_InvalidDevice
+
+
+This is an invalid device name.
+
+0x000008F7
+
+NERR_WriteFault
+
+
+A write fault occurred.
+
+0x000008F9
+
+NERR_DuplicateName
+
+
+A duplicate message alias exists on the network.
+
+0x000008FA
+
+NERR_DeleteLater
+
+
+This message alias will be deleted later.
+
+0x000008FB
+
+NERR_IncompleteDel
+
+
+The message alias was not successfully deleted from all networks.
+
+0x000008FC
+
+NERR_MultipleNets
+
+
+This operation is not supported on computers with multiple networks.
+
+0x00000906
+
+NERR_NetNameNotFound
+
+
+This shared resource does not exist.
+
+0x00000907
+
+NERR_DeviceNotShared
+
+
+This device is not shared.
+
+0x00000908
+
+NERR_ClientNameNotFound
+
+
+A session does not exist with that computer name.
+
+0x0000090A
+
+NERR_FileIdNotFound
+
+
+There is not an open file with that identification number.
+
+0x0000090B
+
+NERR_ExecFailure
+
+
+A failure occurred when executing a remote administration command.
+
+0x0000090C
+
+NERR_TmpFile
+
+
+A failure occurred when opening a remote temporary file.
+
+0x0000090D
+
+NERR_TooMuchData
+
+
+The data returned from a remote administration command has been truncated to 64 KB.
+
+0x0000090E
+
+NERR_DeviceShareConflict
+
+
+This device cannot be shared as both a spooled and a nonspooled resource.
+
+0x0000090F
+
+NERR_BrowserTableIncomplete
+
+
+The information in the list of servers might be incorrect.
+
+0x00000910
+
+NERR_NotLocalDomain
+
+
+The computer is not active in this domain.
+
+0x00000911
+
+NERR_IsDfsShare
+
+
+The share must be removed from the Distributed File System (DFS) before it can be deleted.
+
+0x0000091B
+
+NERR_DevInvalidOpCode
+
+
+The operation is invalid for this device.
+
+0x0000091C
+
+NERR_DevNotFound
+
+
+This device cannot be shared.
+
+0x0000091D
+
+NERR_DevNotOpen
+
+
+This device was not open.
+
+0x0000091E
+
+NERR_BadQueueDevString
+
+
+This device name list is invalid.
+
+0x0000091F
+
+NERR_BadQueuePriority
+
+
+The queue priority is invalid.
+
+0x00000921
+
+NERR_NoCommDevs
+
+
+There are no shared communication devices.
+
+0x00000922
+
+NERR_QueueNotFound
+
+
+The queue you specified does not exist.
+
+0x00000924
+
+NERR_BadDevString
+
+
+This list of devices is invalid.
+
+0x00000925
+
+NERR_BadDev
+
+
+The requested device is invalid.
+
+0x00000926
+
+NERR_InUseBySpooler
+
+
+This device is already in use by the spooler.
+
+0x00000927
+
+NERR_CommDevInUse
+
+
+This device is already in use as a communication device.
+
+0x0000092F
+
+NERR_InvalidComputer
+
+
+This computer name is invalid.
+
+0x00000932
+
+NERR_MaxLenExceeded
+
+
+The string and prefix specified are too long.
+
+0x00000934
+
+NERR_BadComponent
+
+
+This path component is invalid.
+
+0x00000935
+
+NERR_CantType
+
+
+Could not determine the type of input.
+
+0x0000093A
+
+NERR_TooManyEntries
+
+
+The buffer for types is not big enough.
+
+0x00000942
+
+NERR_ProfileFileTooBig
+
+
+Profile files cannot exceed 64 KB.
+
+0x00000943
+
+NERR_ProfileOffset
+
+
+The start offset is out of range.
+
+0x00000944
+
+NERR_ProfileCleanup
+
+
+The system cannot delete current connections to network resources.
+
+0x00000945
+
+NERR_ProfileUnknownCmd
+
+
+The system was unable to parse the command line in this file.
+
+0x00000946
+
+NERR_ProfileLoadErr
+
+
+An error occurred while loading the profile file.
+
+0x00000947
+
+NERR_ProfileSaveErr
+
+
+Errors occurred while saving the profile file. The profile was partially saved.
+
+0x00000949
+
+NERR_LogOverflow
+
+
+Log file %1 is full.
+
+0x0000094A
+
+NERR_LogFileChanged
+
+
+This log file has changed between reads.
+
+0x0000094B
+
+NERR_LogFileCorrupt
+
+
+Log file %1 is corrupt.
+
+0x0000094C
+
+NERR_SourceIsDir
+
+
+The source path cannot be a directory.
+
+0x0000094D
+
+NERR_BadSource
+
+
+The source path is illegal.
+
+0x0000094E
+
+NERR_BadDest
+
+
+The destination path is illegal.
+
+0x0000094F
+
+NERR_DifferentServers
+
+
+The source and destination paths are on different servers.
+
+0x00000951
+
+NERR_RunSrvPaused
+
+
+The Run server you requested is paused.
+
+0x00000955
+
+NERR_ErrCommRunSrv
+
+
+An error occurred when communicating with a Run server.
+
+0x00000957
+
+NERR_ErrorExecingGhost
+
+
+An error occurred when starting a background process.
+
+0x00000958
+
+NERR_ShareNotFound
+
+
+The shared resource you are connected to could not be found.
+
+0x00000960
+
+NERR_InvalidLana
+
+
+The LAN adapter number is invalid.
+
+0x00000961
+
+NERR_OpenFiles
+
+
+There are open files on the connection.
+
+0x00000962
+
+NERR_ActiveConns
+
+
+Active connections still exist.
+
+0x00000963
+
+NERR_BadPasswordCore
+
+
+This share name or password is invalid.
+
+0x00000964
+
+NERR_DevInUse
+
+
+The device is being accessed by an active process.
+
+0x00000965
+
+NERR_LocalDrive
+
+
+The drive letter is in use locally.
+
+0x0000097E
+
+NERR_AlertExists
+
+
+The specified client is already registered for the specified event.
+
+0x0000097F
+
+NERR_TooManyAlerts
+
+
+The alert table is full.
+
+0x00000980
+
+NERR_NoSuchAlert
+
+
+An invalid or nonexistent alert name was raised.
+
+0x00000981
+
+NERR_BadRecipient
+
+
+The alert recipient is invalid.
+
+0x00000982
+
+NERR_AcctLimitExceeded
+
+
+A user's session with this server has been deleted.
+
+0x00000988
+
+NERR_InvalidLogSeek
+
+
+The log file does not contain the requested record number.
+
+0x00000992
+
+NERR_BadUasConfig
+
+
+The user accounts database is not configured correctly.
+
+0x00000993
+
+NERR_InvalidUASOp
+
+
+This operation is not permitted when the Net Logon service is running.
+
+0x00000994
+
+NERR_LastAdmin
+
+
+This operation is not allowed on the last administrative account.
+
+0x00000995
+
+NERR_DCNotFound
+
+
+Could not find the domain controller for this domain.
+
+0x00000996
+
+NERR_LogonTrackingError
+
+
+Could not set logon information for this user.
+
+0x00000997
+
+NERR_NetlogonNotStarted
+
+
+The Net Logon service has not been started.
+
+0x00000998
+
+NERR_CanNotGrowUASFile
+
+
+Unable to add to the user accounts database.
+
+0x00000999
+
+NERR_TimeDiffAtDC
+
+
+This server's clock is not synchronized with the PDC's clock.
+
+0x0000099A
+
+NERR_PasswordMismatch
+
+
+A password mismatch has been detected.
+
+0x0000099C
+
+NERR_NoSuchServer
+
+
+The server identification does not specify a valid server.
+
+0x0000099D
+
+NERR_NoSuchSession
+
+
+The session identification does not specify a valid session.
+
+0x0000099E
+
+NERR_NoSuchConnection
+
+
+The connection identification does not specify a valid connection.
+
+0x0000099F
+
+NERR_TooManyServers
+
+
+There is no space for another entry in the table of available servers.
+
+0x000009A0
+
+NERR_TooManySessions
+
+
+The server has reached the maximum number of sessions it supports.
+
+0x000009A1
+
+NERR_TooManyConnections
+
+
+The server has reached the maximum number of connections it supports.
+
+0x000009A2
+
+NERR_TooManyFiles
+
+
+The server cannot open more files because it has reached its maximum number.
+
+0x000009A3
+
+NERR_NoAlternateServers
+
+
+There are no alternate servers registered on this server.
+
+0x000009A6
+
+NERR_TryDownLevel
+
+
+Try the down-level (remote admin protocol) version of API instead.
+
+0x000009B0
+
+NERR_UPSDriverNotStarted
+
+
+The uninterruptible power supply (UPS) driver could not be accessed by the UPS service.
+
+0x000009B1
+
+NERR_UPSInvalidConfig
+
+
+The UPS service is not configured correctly.
+
+0x000009B2
+
+NERR_UPSInvalidCommPort
+
+
+The UPS service could not access the specified Comm Port.
+
+0x000009B3
+
+NERR_UPSSignalAsserted
+
+
+The UPS indicated a line fail or low battery situation. Service not started.
+
+0x000009B4
+
+NERR_UPSShutdownFailed
+
+
+The UPS service failed to perform a system shut down.
+
+0x000009C4
+
+NERR_BadDosRetCode
+
+
+The program below returned an MS-DOS error code.
+
+0x000009C5
+
+NERR_ProgNeedsExtraMem
+
+
+The program below needs more memory.
+
+0x000009C6
+
+NERR_BadDosFunction
+
+
+The program below called an unsupported MS-DOS function.
+
+0x000009C7
+
+NERR_RemoteBootFailed
+
+
+The workstation failed to boot.
+
+0x000009C8
+
+NERR_BadFileCheckSum
+
+
+The file below is corrupt.
+
+0x000009C9
+
+NERR_NoRplBootSystem
+
+
+No loader is specified in the boot-block definition file.
+
+0x000009CA
+
+NERR_RplLoadrNetBiosErr
+
+
+NetBIOS returned an error: The network control blocks (NCBs) and Server Message Block (SMB) are dumped above.
+
+0x000009CB
+
+NERR_RplLoadrDiskErr
+
+
+A disk I/O error occurred.
+
+0x000009CC
+
+NERR_ImageParamErr
+
+
+Image parameter substitution failed.
+
+0x000009CD
+
+NERR_TooManyImageParams
+
+
+Too many image parameters cross disk sector boundaries.
+
+0x000009CE
+
+NERR_NonDosFloppyUsed
+
+
+The image was not generated from an MS-DOS disk formatted with /S.
+
+0x000009CF
+
+NERR_RplBootRestart
+
+
+Remote boot will be restarted later.
+
+0x000009D0
+
+NERR_RplSrvrCallFailed
+
+
+The call to the Remoteboot server failed.
+
+0x000009D1
+
+NERR_CantConnectRplSrvr
+
+
+Cannot connect to the Remoteboot server.
+
+0x000009D2
+
+NERR_CantOpenImageFile
+
+
+Cannot open image file on the Remoteboot server.
+
+0x000009D3
+
+NERR_CallingRplSrvr
+
+
+Connecting to the Remoteboot server.
+
+0x000009D4
+
+NERR_StartingRplBoot
+
+
+Connecting to the Remoteboot server.
+
+0x000009D5
+
+NERR_RplBootServiceTerm
+
+
+Remote boot service was stopped, check the error log for the cause of the problem.
+
+0x000009D6
+
+NERR_RplBootStartFailed
+
+
+Remote boot startup failed; check the error log for the cause of the problem.
+
+0x000009D7
+
+NERR_RPL_CONNECTED
+
+
+A second connection to a Remoteboot resource is not allowed.
+
+0x000009F6
+
+NERR_BrowserConfiguredToNotRun
+
+
+The browser service was configured with MaintainServerList=No.
+
+0x00000A32
+
+NERR_RplNoAdaptersStarted
+
+
+Service failed to start because none of the network adapters started with this service.
+
+0x00000A33
+
+NERR_RplBadRegistry
+
+
+Service failed to start due to bad startup information in the registry.
+
+0x00000A34
+
+NERR_RplBadDatabase
+
+
+Service failed to start because its database is absent or corrupt.
+
+0x00000A35
+
+NERR_RplRplfilesShare
+
+
+Service failed to start because the RPLFILES share is absent.
+
+0x00000A36
+
+NERR_RplNotRplServer
+
+
+Service failed to start because the RPLUSER group is absent.
+
+0x00000A37
+
+NERR_RplCannotEnum
+
+
+Cannot enumerate service records.
+
+0x00000A38
+
+NERR_RplWkstaInfoCorrupted
+
+
+Workstation record information has been corrupted.
+
+0x00000A39
+
+NERR_RplWkstaNotFound
+
+
+Workstation record was not found.
+
+0x00000A3A
+
+NERR_RplWkstaNameUnavailable
+
+
+Workstation name is in use by some other workstation.
+
+0x00000A3B
+
+NERR_RplProfileInfoCorrupted
+
+
+Profile record information has been corrupted.
+
+0x00000A3C
+
+NERR_RplProfileNotFound
+
+
+Profile record was not found.
+
+0x00000A3D
+
+NERR_RplProfileNameUnavailable
+
+
+Profile name is in use by some other profile.
+
+0x00000A3E
+
+NERR_RplProfileNotEmpty
+
+
+There are workstations using this profile.
+
+0x00000A3F
+
+NERR_RplConfigInfoCorrupted
+
+
+Configuration record information has been corrupted.
+
+0x00000A40
+
+NERR_RplConfigNotFound
+
+
+Configuration record was not found.
+
+0x00000A41
+
+NERR_RplAdapterInfoCorrupted
+
+
+Adapter ID record information has been corrupted.
+
+0x00000A42
+
+NERR_RplInternal
+
+
+An internal service error has occurred.
+
+0x00000A43
+
+NERR_RplVendorInfoCorrupted
+
+
+Vendor ID record information has been corrupted.
+
+0x00000A44
+
+NERR_RplBootInfoCorrupted
+
+
+Boot block record information has been corrupted.
+
+0x00000A45
+
+NERR_RplWkstaNeedsUserAcct
+
+
+The user account for this workstation record is missing.
+
+0x00000A46
+
+NERR_RplNeedsRPLUSERAcct
+
+
+The RPLUSER local group could not be found.
+
+0x00000A47
+
+NERR_RplBootNotFound
+
+
+Boot block record was not found.
+
+0x00000A48
+
+NERR_RplIncompatibleProfile
+
+
+Chosen profile is incompatible with this workstation.
+
+0x00000A49
+
+NERR_RplAdapterNameUnavailable
+
+
+Chosen network adapter ID is in use by some other workstation.
+
+0x00000A4A
+
+NERR_RplConfigNotEmpty
+
+
+There are profiles using this configuration.
+
+0x00000A4B
+
+NERR_RplBootInUse
+
+
+There are workstations, profiles, or configurations using this boot block.
+
+0x00000A4C
+
+NERR_RplBackupDatabase
+
+
+Service failed to back up the Remoteboot database.
+
+0x00000A4D
+
+NERR_RplAdapterNotFound
+
+
+Adapter record was not found.
+
+0x00000A4E
+
+NERR_RplVendorNotFound
+
+
+Vendor record was not found.
+
+0x00000A4F
+
+NERR_RplVendorNameUnavailable
+
+
+Vendor name is in use by some other vendor record.
+
+0x00000A50
+
+NERR_RplBootNameUnavailable
+
+
+The boot name or vendor ID is in use by some other boot block record.
+
+0x00000A51
+
+NERR_RplConfigNameUnavailable
+
+
+The configuration name is in use by some other configuration.
+
+0x00000A64
+
+NERR_DfsInternalCorruption
+
+
+The internal database maintained by the DFS service is corrupt.
+
+0x00000A65
+
+NERR_DfsVolumeDataCorrupt
+
+
+One of the records in the internal DFS database is corrupt.
+
+0x00000A66
+
+NERR_DfsNoSuchVolume
+
+
+There is no DFS name whose entry path matches the input entry path.
+
+0x00000A67
+
+NERR_DfsVolumeAlreadyExists
+
+
+A root or link with the given name already exists.
+
+0x00000A68
+
+NERR_DfsAlreadyShared
+
+
+The server share specified is already shared in the DFS.
+
+0x00000A69
+
+NERR_DfsNoSuchShare
+
+
+The indicated server share does not support the indicated DFS namespace.
+
+0x00000A6A
+
+NERR_DfsNotALeafVolume
+
+
+The operation is not valid in this portion of the namespace.
+
+0x00000A6B
+
+NERR_DfsLeafVolume
+
+
+The operation is not valid in this portion of the namespace.
+
+0x00000A6C
+
+NERR_DfsVolumeHasMultipleServers
+
+
+The operation is ambiguous because the link has multiple servers.
+
+0x00000A6D
+
+NERR_DfsCantCreateJunctionPoint
+
+
+Unable to create a link.
+
+0x00000A6E
+
+NERR_DfsServerNotDfsAware
+
+
+The server is not DFS-aware.
+
+0x00000A6F
+
+NERR_DfsBadRenamePath
+
+
+The specified rename target path is invalid.
+
+0x00000A70
+
+NERR_DfsVolumeIsOffline
+
+
+The specified DFS link is offline.
+
+0x00000A71
+
+NERR_DfsNoSuchServer
+
+
+The specified server is not a server for this link.
+
+0x00000A72
+
+NERR_DfsCyclicalName
+
+
+A cycle in the DFS name was detected.
+
+0x00000A73
+
+NERR_DfsNotSupportedInServerDfs
+
+
+The operation is not supported on a server-based DFS.
+
+0x00000A74
+
+NERR_DfsDuplicateService
+
+
+This link is already supported by the specified server share.
+
+0x00000A75
+
+NERR_DfsCantRemoveLastServerShare
+
+
+Cannot remove the last server share supporting this root or link.
+
+0x00000A76
+
+NERR_DfsVolumeIsInterDfs
+
+
+The operation is not supported for an inter-DFS link.
+
+0x00000A77
+
+NERR_DfsInconsistent
+
+
+The internal state of the DFS Service has become inconsistent.
+
+0x00000A78
+
+NERR_DfsServerUpgraded
+
+
+The DFS Service has been installed on the specified server.
+
+0x00000A79
+
+NERR_DfsDataIsIdentical
+
+
+The DFS data being reconciled is identical.
+
+0x00000A7A
+
+NERR_DfsCantRemoveDfsRoot
+
+
+The DFS root cannot be deleted. Uninstall DFS if required.
+
+0x00000A7B
+
+NERR_DfsChildOrParentInDfs
+
+
+A child or parent directory of the share is already in a DFS.
+
+0x00000A82
+
+NERR_DfsInternalError
+
+
+DFS internal error.
+
+0x00000A83
+
+NERR_SetupAlreadyJoined
+
+
+This machine is already joined to a domain.
+
+0x00000A84
+
+NERR_SetupNotJoined
+
+
+This machine is not currently joined to a domain.
+
+0x00000A85
+
+NERR_SetupDomainController
+
+
+This machine is a domain controller and cannot be unjoined from a domain.
+
+0x00000A86
+
+NERR_DefaultJoinRequired
+
+
+The destination domain controller does not support creating machine accounts in organizational units (OUs).
+
+0x00000A87
+
+NERR_InvalidWorkgroupName
+
+
+The specified workgroup name is invalid.
+
+0x00000A88
+
+NERR_NameUsesIncompatibleCodePage
+
+
+The specified computer name is incompatible with the default language used on the domain controller.
+
+0x00000A89
+
+NERR_ComputerAccountNotFound
+
+
+The specified computer account could not be found.
+
+0x00000A8A
+
+NERR_PersonalSku
+
+
+This version of Windows cannot be joined to a domain.
+
+0x00000A8D
+
+NERR_PasswordMustChange
+
+
+The password must change at the next logon.
+
+0x00000A8E
+
+NERR_AccountLockedOut
+
+
+The account is locked out.
+
+0x00000A8F
+
+NERR_PasswordTooLong
+
+
+The password is too long.
+
+0x00000A90
+
+NERR_PasswordNotComplexEnough
+
+
+The password does not meet the complexity policy.
+
+0x00000A91
+
+NERR_PasswordFilterError
+
+
+The password does not meet the requirements of the password filter DLLs.
+
+0x00000BB8
+
+ERROR_UNKNOWN_PRINT_MONITOR
+
+
+The specified print monitor is unknown.
+
+0x00000BB9
+
+ERROR_PRINTER_DRIVER_IN_USE
+
+
+The specified printer driver is currently in use.
+
+0x00000BBA
+
+ERROR_SPOOL_FILE_NOT_FOUND
+
+
+The spool file was not found.
+
+0x00000BBB
+
+ERROR_SPL_NO_STARTDOC
+
+
+A StartDocPrinter call was not issued.
+
+0x00000BBC
+
+ERROR_SPL_NO_ADDJOB
+
+
+An AddJob call was not issued.
+
+0x00000BBD
+
+ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED
+
+
+The specified print processor has already been installed.
+
+0x00000BBE
+
+ERROR_PRINT_MONITOR_ALREADY_INSTALLED
+
+
+The specified print monitor has already been installed.
+
+0x00000BBF
+
+ERROR_INVALID_PRINT_MONITOR
+
+
+The specified print monitor does not have the required functions.
+
+0x00000BC0
+
+ERROR_PRINT_MONITOR_IN_USE
+
+
+The specified print monitor is currently in use.
+
+0x00000BC1
+
+ERROR_PRINTER_HAS_JOBS_QUEUED
+
+
+The requested operation is not allowed when there are jobs queued to the printer.
+
+0x00000BC2
+
+ERROR_SUCCESS_REBOOT_REQUIRED
+
+
+The requested operation is successful. Changes will not be effective until the system is rebooted.
+
+0x00000BC3
+
+ERROR_SUCCESS_RESTART_REQUIRED
+
+
+The requested operation is successful. Changes will not be effective until the service is restarted.
+
+0x00000BC4
+
+ERROR_PRINTER_NOT_FOUND
+
+
+No printers were found.
+
+0x00000BC5
+
+ERROR_PRINTER_DRIVER_WARNED
+
+
+The printer driver is known to be unreliable.
+
+0x00000BC6
+
+ERROR_PRINTER_DRIVER_BLOCKED
+
+
+The printer driver is known to harm the system.
+
+0x00000BC7
+
+ERROR_PRINTER_DRIVER_PACKAGE_IN_USE
+
+
+The specified printer driver package is currently in use.
+
+0x00000BC8
+
+ERROR_CORE_DRIVER_PACKAGE_NOT_FOUND
+
+
+Unable to find a core driver package that is required by the printer driver package.
+
+0x00000BC9
+
+ERROR_FAIL_REBOOT_REQUIRED
+
+
+The requested operation failed. A system reboot is required to roll back changes made.
+
+0x00000BCA
+
+ERROR_FAIL_REBOOT_INITIATED
+
+
+The requested operation failed. A system reboot has been initiated to roll back changes made.
+
+0x00000BCB
+ERROR_PRINTER_DRIVER_DOWNLOAD_NEEDED
+
+
+The specified printer driver was not found on the system and needs to be downloaded.
+
+0x00000BCE
+
+ERROR_PRINTER_NOT_SHAREABLE
+
+
+The specified printer cannot be shared.
+
+0x00000F6E
+
+ERROR_IO_REISSUE_AS_CACHED
+
+
+Reissue the given operation as a cached I/O operation.
+
+0x00000FA0
+
+ERROR_WINS_INTERNAL
+
+
+Windows Internet Name Service (WINS) encountered an error while processing the command.
+
+0x00000FA1
+
+ERROR_CAN_NOT_DEL_LOCAL_WINS
+
+
+The local WINS cannot be deleted.
+
+0x00000FA2
+
+ERROR_STATIC_INIT
+
+
+The importation from the file failed.
+
+0x00000FA3
+
+ERROR_INC_BACKUP
+
+
+The backup failed. Was a full backup done before?
+
+0x00000FA4
+
+ERROR_FULL_BACKUP
+
+
+The backup failed. Check the directory to which you are backing the database.
+
+0x00000FA5
+
+ERROR_REC_NON_EXISTENT
+
+
+The name does not exist in the WINS database.
+
+0x00000FA6
+
+ERROR_RPL_NOT_ALLOWED
+
+
+Replication with a nonconfigured partner is not allowed.
+
+0x00000FD2
+
+PEERDIST_ERROR_CONTENTINFO_VERSION_UNSUPPORTED
+
+
+The version of the supplied content information is not supported.
+
+0x00000FD3
+
+PEERDIST_ERROR_CANNOT_PARSE_CONTENTINFO
+
+
+The supplied content information is malformed.
+
+0x00000FD4
+
+PEERDIST_ERROR_MISSING_DATA
+
+
+The requested data cannot be found in local or peer caches.
+
+0x00000FD5
+
+PEERDIST_ERROR_NO_MORE
+
+
+No more data is available or required.
+
+0x00000FD6
+
+PEERDIST_ERROR_NOT_INITIALIZED
+
+
+The supplied object has not been initialized.
+
+0x00000FD7
+
+PEERDIST_ERROR_ALREADY_INITIALIZED
+
+
+The supplied object has already been initialized.
+
+0x00000FD8
+
+PEERDIST_ERROR_SHUTDOWN_IN_PROGRESS
+
+
+A shutdown operation is already in progress.
+
+0x00000FD9
+
+PEERDIST_ERROR_INVALIDATED
+
+
+The supplied object has already been invalidated.
+
+0x00000FDA
+
+PEERDIST_ERROR_ALREADY_EXISTS
+
+
+An element already exists and was not replaced.
+
+0x00000FDB
+
+PEERDIST_ERROR_OPERATION_NOTFOUND
+
+
+Cannot cancel the requested operation as it has already been completed.
+
+0x00000FDC
+
+PEERDIST_ERROR_ALREADY_COMPLETED
+
+
+Cannot perform the requested operation because it has already been carried out.
+
+0x00000FDD
+
+PEERDIST_ERROR_OUT_OF_BOUNDS
+
+
+An operation accessed data beyond the bounds of valid data.
+
+0x00000FDE
+
+PEERDIST_ERROR_VERSION_UNSUPPORTED
+
+
+The requested version is not supported.
+
+0x00000FDF
+
+PEERDIST_ERROR_INVALID_CONFIGURATION
+
+
+A configuration value is invalid.
+
+0x00000FE0
+
+PEERDIST_ERROR_NOT_LICENSED
+
+
+The SKU is not licensed.
+
+0x00000FE1
+
+PEERDIST_ERROR_SERVICE_UNAVAILABLE
+
+
+PeerDist Service is still initializing and will be available shortly.
+
+0x00001004
+
+ERROR_DHCP_ADDRESS_CONFLICT
+
+
+The Dynamic Host Configuration Protocol (DHCP) client has obtained an IP address that is already in use on the network. The local interface will be disabled until the DHCP client can obtain a new address.
+
+0x00001068
+
+ERROR_WMI_GUID_NOT_FOUND
+
+
+The GUID passed was not recognized as valid by a WMI data provider.
+
+0x00001069
+
+ERROR_WMI_INSTANCE_NOT_FOUND
+
+
+The instance name passed was not recognized as valid by a WMI data provider.
+
+0x0000106A
+
+ERROR_WMI_ITEMID_NOT_FOUND
+
+
+The data item ID passed was not recognized as valid by a WMI data provider.
+
+0x0000106B
+
+ERROR_WMI_TRY_AGAIN
+
+
+The WMI request could not be completed and should be retried.
+
+0x0000106C
+
+ERROR_WMI_DP_NOT_FOUND
+
+
+The WMI data provider could not be located.
+
+0x0000106D
+
+ERROR_WMI_UNRESOLVED_INSTANCE_REF
+
+
+The WMI data provider references an instance set that has not been registered.
+
+0x0000106E
+
+ERROR_WMI_ALREADY_ENABLED
+
+
+The WMI data block or event notification has already been enabled.
+
+0x0000106F
+
+ERROR_WMI_GUID_DISCONNECTED
+
+
+The WMI data block is no longer available.
+
+0x00001070
+
+ERROR_WMI_SERVER_UNAVAILABLE
+
+
+The WMI data service is not available.
+
+0x00001071
+
+ERROR_WMI_DP_FAILED
+
+
+The WMI data provider failed to carry out the request.
+
+0x00001072
+
+ERROR_WMI_INVALID_MOF
+
+
+The WMI Managed Object Format (MOF) information is not valid.
+
+0x00001073
+
+ERROR_WMI_INVALID_REGINFO
+
+
+The WMI registration information is not valid.
+
+0x00001074
+
+ERROR_WMI_ALREADY_DISABLED
+
+
+The WMI data block or event notification has already been disabled.
+
+0x00001075
+
+ERROR_WMI_READ_ONLY
+
+
+The WMI data item or data block is read-only.
+
+0x00001076
+
+ERROR_WMI_SET_FAILURE
+
+
+The WMI data item or data block could not be changed.
+
+0x000010CC
+
+ERROR_INVALID_MEDIA
+
+
+The media identifier does not represent a valid medium.
+
+0x000010CD
+
+ERROR_INVALID_LIBRARY
+
+
+The library identifier does not represent a valid library.
+
+0x000010CE
+
+ERROR_INVALID_MEDIA_POOL
+
+
+The media pool identifier does not represent a valid media pool.
+
+0x000010CF
+
+ERROR_DRIVE_MEDIA_MISMATCH
+
+
+The drive and medium are not compatible, or they exist in different libraries.
+
+0x000010D0
+
+ERROR_MEDIA_OFFLINE
+
+
+The medium currently exists in an offline library and must be online to perform this operation.
+
+0x000010D1
+
+ERROR_LIBRARY_OFFLINE
+
+
+The operation cannot be performed on an offline library.
+
+0x000010D2
+
+ERROR_EMPTY
+
+
+The library, drive, or media pool is empty.
+
+0x000010D3
+
+ERROR_NOT_EMPTY
+
+
+The library, drive, or media pool must be empty to perform this operation.
+
+0x000010D4
+
+ERROR_MEDIA_UNAVAILABLE
+
+
+No media is currently available in this media pool or library.
+
+0x000010D5
+
+ERROR_RESOURCE_DISABLED
+
+
+A resource required for this operation is disabled.
+
+0x000010D6
+
+ERROR_INVALID_CLEANER
+
+
+The media identifier does not represent a valid cleaner.
+
+0x000010D7
+
+ERROR_UNABLE_TO_CLEAN
+
+
+The drive cannot be cleaned or does not support cleaning.
+
+0x000010D8
+
+ERROR_OBJECT_NOT_FOUND
+
+
+The object identifier does not represent a valid object.
+
+0x000010D9
+
+ERROR_DATABASE_FAILURE
+
+
+Unable to read from or write to the database.
+
+0x000010DA
+
+ERROR_DATABASE_FULL
+
+
+The database is full.
+
+0x000010DB
+
+ERROR_MEDIA_INCOMPATIBLE
+
+
+The medium is not compatible with the device or media pool.
+
+0x000010DC
+
+ERROR_RESOURCE_NOT_PRESENT
+
+
+The resource required for this operation does not exist.
+
+0x000010DD
+
+ERROR_INVALID_OPERATION
+
+
+The operation identifier is not valid.
+
+0x000010DE
+
+ERROR_MEDIA_NOT_AVAILABLE
+
+
+The media is not mounted or ready for use.
+
+0x000010DF
+
+ERROR_DEVICE_NOT_AVAILABLE
+
+
+The device is not ready for use.
+
+0x000010E0
+
+ERROR_REQUEST_REFUSED
+
+
+The operator or administrator has refused the request.
+
+0x000010E1
+
+ERROR_INVALID_DRIVE_OBJECT
+
+
+The drive identifier does not represent a valid drive.
+
+0x000010E2
+
+ERROR_LIBRARY_FULL
+
+
+Library is full. No slot is available for use.
+
+0x000010E3
+
+ERROR_MEDIUM_NOT_ACCESSIBLE
+
+
+The transport cannot access the medium.
+
+0x000010E4
+
+ERROR_UNABLE_TO_LOAD_MEDIUM
+
+
+Unable to load the medium into the drive.
+
+0x000010E5
+
+ERROR_UNABLE_TO_INVENTORY_DRIVE
+
+
+Unable to retrieve the drive status.
+
+0x000010E6
+
+ERROR_UNABLE_TO_INVENTORY_SLOT
+
+
+Unable to retrieve the slot status.
+
+0x000010E7
+
+ERROR_UNABLE_TO_INVENTORY_TRANSPORT
+
+
+Unable to retrieve status about the transport.
+
+0x000010E8
+
+ERROR_TRANSPORT_FULL
+
+
+Cannot use the transport because it is already in use.
+
+0x000010E9
+
+ERROR_CONTROLLING_IEPORT
+
+
+Unable to open or close the inject/eject port.
+
+0x000010EA
+
+ERROR_UNABLE_TO_EJECT_MOUNTED_MEDIA
+
+
+Unable to eject the medium because it is in a drive.
+
+0x000010EB
+
+ERROR_CLEANER_SLOT_SET
+
+
+A cleaner slot is already reserved.
+
+0x000010EC
+
+ERROR_CLEANER_SLOT_NOT_SET
+
+
+A cleaner slot is not reserved.
+
+0x000010ED
+
+ERROR_CLEANER_CARTRIDGE_SPENT
+
+
+The cleaner cartridge has performed the maximum number of drive cleanings.
+
+0x000010EE
+
+ERROR_UNEXPECTED_OMID
+
+
+Unexpected on-medium identifier.
+
+0x000010EF
+
+ERROR_CANT_DELETE_LAST_ITEM
+
+
+The last remaining item in this group or resource cannot be deleted.
+
+0x000010F0
+
+ERROR_MESSAGE_EXCEEDS_MAX_SIZE
+
+
+The message provided exceeds the maximum size allowed for this parameter.
+
+0x000010F1
+
+ERROR_VOLUME_CONTAINS_SYS_FILES
+
+
+The volume contains system or paging files.
+
+0x000010F2
+
+ERROR_INDIGENOUS_TYPE
+
+
+The media type cannot be removed from this library because at least one drive in the library reports it can support this media type.
+
+0x000010F3
+
+ERROR_NO_SUPPORTING_DRIVES
+
+
+This offline media cannot be mounted on this system because no enabled drives are present that can be used.
+
+0x000010F4
+
+ERROR_CLEANER_CARTRIDGE_INSTALLED
+
+
+A cleaner cartridge is present in the tape library.
+
+0x000010F5
+
+ERROR_IEPORT_FULL
+
+
+Cannot use the IEport because it is not empty.
+
+0x000010FE
+
+ERROR_FILE_OFFLINE
+
+
+The remote storage service was not able to recall the file.
+
+0x000010FF
+
+ERROR_REMOTE_STORAGE_NOT_ACTIVE
+
+
+The remote storage service is not operational at this time.
+
+0x00001100
+
+ERROR_REMOTE_STORAGE_MEDIA_ERROR
+
+
+The remote storage service encountered a media error.
+
+0x00001126
+
+ERROR_NOT_A_REPARSE_POINT
+
+
+The file or directory is not a reparse point.
+
+0x00001127
+
+ERROR_REPARSE_ATTRIBUTE_CONFLICT
+
+
+The reparse point attribute cannot be set because it conflicts with an existing attribute.
+
+0x00001128
+
+ERROR_INVALID_REPARSE_DATA
+
+
+The data present in the reparse point buffer is invalid.
+
+0x00001129
+
+ERROR_REPARSE_TAG_INVALID
+
+
+The tag present in the reparse point buffer is invalid.
+
+0x0000112A
+
+ERROR_REPARSE_TAG_MISMATCH
+
+
+There is a mismatch between the tag specified in the request and the tag present in the reparse point.
+
+0x00001194
+
+ERROR_VOLUME_NOT_SIS_ENABLED
+
+
+Single Instance Storage (SIS) is not available on this volume.
+
+0x00001389
+
+ERROR_DEPENDENT_RESOURCE_EXISTS
+
+
+The operation cannot be completed because other resources depend on this resource.
+
+0x0000138A
+
+ERROR_DEPENDENCY_NOT_FOUND
+
+
+The cluster resource dependency cannot be found.
+
+0x0000138B
+
+ERROR_DEPENDENCY_ALREADY_EXISTS
+
+
+The cluster resource cannot be made dependent on the specified resource because it is already dependent.
+
+0x0000138C
+
+ERROR_RESOURCE_NOT_ONLINE
+
+
+The cluster resource is not online.
+
+0x0000138D
+
+ERROR_HOST_NODE_NOT_AVAILABLE
+
+
+A cluster node is not available for this operation.
+
+0x0000138E
+
+ERROR_RESOURCE_NOT_AVAILABLE
+
+
+The cluster resource is not available.
+
+0x0000138F
+
+ERROR_RESOURCE_NOT_FOUND
+
+
+The cluster resource could not be found.
+
+0x00001390
+
+ERROR_SHUTDOWN_CLUSTER
+
+
+The cluster is being shut down.
+
+0x00001391
+
+ERROR_CANT_EVICT_ACTIVE_NODE
+
+
+A cluster node cannot be evicted from the cluster unless the node is down or it is the last node.
+
+0x00001392
+
+ERROR_OBJECT_ALREADY_EXISTS
+
+
+The object already exists.
+
+0x00001393
+
+ERROR_OBJECT_IN_LIST
+
+
+The object is already in the list.
+
+0x00001394
+
+ERROR_GROUP_NOT_AVAILABLE
+
+
+The cluster group is not available for any new requests.
+
+0x00001395
+
+ERROR_GROUP_NOT_FOUND
+
+
+The cluster group could not be found.
+
+0x00001396
+
+ERROR_GROUP_NOT_ONLINE
+
+
+The operation could not be completed because the cluster group is not online.
+
+0x00001397
+
+ERROR_HOST_NODE_NOT_RESOURCE_OWNER
+
+
+The operation failed because either the specified cluster node is not the owner of the resource, or the node is not a possible owner of the resource.
+
+0x00001398
+
+ERROR_HOST_NODE_NOT_GROUP_OWNER
+
+
+The operation failed because either the specified cluster node is not the owner of the group, or the node is not a possible owner of the group.
+
+0x00001399
+
+ERROR_RESMON_CREATE_FAILED
+
+
+The cluster resource could not be created in the specified resource monitor.
+
+0x0000139A
+
+ERROR_RESMON_ONLINE_FAILED
+
+
+The cluster resource could not be brought online by the resource monitor.
+
+0x0000139B
+
+ERROR_RESOURCE_ONLINE
+
+
+The operation could not be completed because the cluster resource is online.
+
+0x0000139C
+
+ERROR_QUORUM_RESOURCE
+
+
+The cluster resource could not be deleted or brought offline because it is the quorum resource.
+
+0x0000139D
+
+ERROR_NOT_QUORUM_CAPABLE
+
+
+The cluster could not make the specified resource a quorum resource because it is not capable of being a quorum resource.
+
+0x0000139E
+
+ERROR_CLUSTER_SHUTTING_DOWN
+
+
+The cluster software is shutting down.
+
+0x0000139F
+
+ERROR_INVALID_STATE
+
+
+The group or resource is not in the correct state to perform the requested operation.
+
+0x000013A0
+
+ERROR_RESOURCE_PROPERTIES_STORED
+
+
+The properties were stored but not all changes will take effect until the next time the resource is brought online.
+
+0x000013A1
+
+ERROR_NOT_QUORUM_CLASS
+
+
+The cluster could not make the specified resource a quorum resource because it does not belong to a shared storage class.
+
+0x000013A2
+
+ERROR_CORE_RESOURCE
+
+
+The cluster resource could not be deleted because it is a core resource.
+
+0x000013A3
+
+ERROR_QUORUM_RESOURCE_ONLINE_FAILED
+
+
+The quorum resource failed to come online.
+
+0x000013A4
+
+ERROR_QUORUMLOG_OPEN_FAILED
+
+
+The quorum log could not be created or mounted successfully.
+
+0x000013A5
+
+ERROR_CLUSTERLOG_CORRUPT
+
+
+The cluster log is corrupt.
+
+0x000013A6
+
+ERROR_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE
+
+
+The record could not be written to the cluster log because it exceeds the maximum size.
+
+0x000013A7
+
+ERROR_CLUSTERLOG_EXCEEDS_MAXSIZE
+
+
+The cluster log exceeds its maximum size.
+
+0x000013A8
+
+ERROR_CLUSTERLOG_CHKPOINT_NOT_FOUND
+
+
+No checkpoint record was found in the cluster log.
+
+0x000013A9
+
+ERROR_CLUSTERLOG_NOT_ENOUGH_SPACE
+
+
+The minimum required disk space needed for logging is not available.
+
+0x000013AA
+
+ERROR_QUORUM_OWNER_ALIVE
+
+
+The cluster node failed to take control of the quorum resource because the resource is owned by another active node.
+
+0x000013AB
+
+ERROR_NETWORK_NOT_AVAILABLE
+
+
+A cluster network is not available for this operation.
+
+0x000013AC
+
+ERROR_NODE_NOT_AVAILABLE
+
+
+A cluster node is not available for this operation.
+
+0x000013AD
+
+ERROR_ALL_NODES_NOT_AVAILABLE
+
+
+All cluster nodes must be running to perform this operation.
+
+0x000013AE
+
+ERROR_RESOURCE_FAILED
+
+
+A cluster resource failed.
+
+0x000013AF
+
+ERROR_CLUSTER_INVALID_NODE
+
+
+The cluster node is not valid.
+
+0x000013B0
+
+ERROR_CLUSTER_NODE_EXISTS
+
+
+The cluster node already exists.
+
+0x000013B1
+
+ERROR_CLUSTER_JOIN_IN_PROGRESS
+
+
+A node is in the process of joining the cluster.
+
+0x000013B2
+
+ERROR_CLUSTER_NODE_NOT_FOUND
+
+
+The cluster node was not found.
+
+0x000013B3
+
+ERROR_CLUSTER_LOCAL_NODE_NOT_FOUND
+
+
+The cluster local node information was not found.
+
+0x000013B4
+
+ERROR_CLUSTER_NETWORK_EXISTS
+
+
+The cluster network already exists.
+
+0x000013B5
+
+ERROR_CLUSTER_NETWORK_NOT_FOUND
+
+
+The cluster network was not found.
+
+0x000013B6
+
+ERROR_CLUSTER_NETINTERFACE_EXISTS
+
+
+The cluster network interface already exists.
+
+0x000013B7
+
+ERROR_CLUSTER_NETINTERFACE_NOT_FOUND
+
+
+The cluster network interface was not found.
+
+0x000013B8
+
+ERROR_CLUSTER_INVALID_REQUEST
+
+
+The cluster request is not valid for this object.
+
+0x000013B9
+
+ERROR_CLUSTER_INVALID_NETWORK_PROVIDER
+
+
+The cluster network provider is not valid.
+
+0x000013BA
+
+ERROR_CLUSTER_NODE_DOWN
+
+
+The cluster node is down.
+
+0x000013BB
+
+ERROR_CLUSTER_NODE_UNREACHABLE
+
+
+The cluster node is not reachable.
+
+0x000013BC
+
+ERROR_CLUSTER_NODE_NOT_MEMBER
+
+
+The cluster node is not a member of the cluster.
+
+0x000013BD
+
+ERROR_CLUSTER_JOIN_NOT_IN_PROGRESS
+
+
+A cluster join operation is not in progress.
+
+0x000013BE
+
+ERROR_CLUSTER_INVALID_NETWORK
+
+
+The cluster network is not valid.
+
+0x000013C0
+
+ERROR_CLUSTER_NODE_UP
+
+
+The cluster node is up.
+
+0x000013C1
+
+ERROR_CLUSTER_IPADDR_IN_USE
+
+
+The cluster IP address is already in use.
+
+0x000013C2
+
+ERROR_CLUSTER_NODE_NOT_PAUSED
+
+
+The cluster node is not paused.
+
+0x000013C3
+
+ERROR_CLUSTER_NO_SECURITY_CONTEXT
+
+
+No cluster security context is available.
+
+0x000013C4
+
+ERROR_CLUSTER_NETWORK_NOT_INTERNAL
+
+
+The cluster network is not configured for internal cluster communication.
+
+0x000013C5
+
+ERROR_CLUSTER_NODE_ALREADY_UP
+
+
+The cluster node is already up.
+
+0x000013C6
+
+ERROR_CLUSTER_NODE_ALREADY_DOWN
+
+
+The cluster node is already down.
+
+0x000013C7
+
+ERROR_CLUSTER_NETWORK_ALREADY_ONLINE
+
+
+The cluster network is already online.
+
+0x000013C8
+
+ERROR_CLUSTER_NETWORK_ALREADY_OFFLINE
+
+
+The cluster network is already offline.
+
+0x000013C9
+
+ERROR_CLUSTER_NODE_ALREADY_MEMBER
+
+
+The cluster node is already a member of the cluster.
+
+0x000013CA
+
+ERROR_CLUSTER_LAST_INTERNAL_NETWORK
+
+
+The cluster network is the only one configured for internal cluster communication between two or more active cluster nodes. The internal communication capability cannot be removed from the network.
+
+0x000013CB
+
+ERROR_CLUSTER_NETWORK_HAS_DEPENDENTS
+
+
+One or more cluster resources depend on the network to provide service to clients. The client access capability cannot be removed from the network.
+
+0x000013CC
+
+ERROR_INVALID_OPERATION_ON_QUORUM
+
+
+This operation cannot be performed on the cluster resource because it is the quorum resource. This quorum resource cannot be brought offline and its possible owners list cannot be modified.
+
+0x000013CD
+
+ERROR_DEPENDENCY_NOT_ALLOWED
+
+
+The cluster quorum resource is not allowed to have any dependencies.
+
+0x000013CE
+
+ERROR_CLUSTER_NODE_PAUSED
+
+
+The cluster node is paused.
+
+0x000013CF
+
+ERROR_NODE_CANT_HOST_RESOURCE
+
+
+The cluster resource cannot be brought online. The owner node cannot run this resource.
+
+0x000013D0
+
+ERROR_CLUSTER_NODE_NOT_READY
+
+
+The cluster node is not ready to perform the requested operation.
+
+0x000013D1
+
+ERROR_CLUSTER_NODE_SHUTTING_DOWN
+
+
+The cluster node is shutting down.
+
+0x000013D2
+
+ERROR_CLUSTER_JOIN_ABORTED
+
+
+The cluster join operation was aborted.
+
+0x000013D3
+
+ERROR_CLUSTER_INCOMPATIBLE_VERSIONS
+
+
+The cluster join operation failed due to incompatible software versions between the joining node and its sponsor.
+
+0x000013D4
+
+ERROR_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED
+
+
+This resource cannot be created because the cluster has reached the limit on the number of resources it can monitor.
+
+0x000013D5
+
+ERROR_CLUSTER_SYSTEM_CONFIG_CHANGED
+
+
+The system configuration changed during the cluster join or form operation. The join or form operation was aborted.
+
+0x000013D6
+
+ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND
+
+
+The specified resource type was not found.
+
+0x000013D7
+
+ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED
+
+
+The specified node does not support a resource of this type. This might be due to version inconsistencies or due to the absence of the resource DLL on this node.
+
+0x000013D8
+
+ERROR_CLUSTER_RESNAME_NOT_FOUND
+
+
+The specified resource name is not supported by this resource DLL. This might be due to a bad (or changed) name supplied to the resource DLL.
+
+0x000013D9
+
+ERROR_CLUSTER_NO_RPC_PACKAGES_REGISTERED
+
+
+No authentication package could be registered with the RPC server.
+
+0x000013DA
+
+ERROR_CLUSTER_OWNER_NOT_IN_PREFLIST
+
+
+You cannot bring the group online because the owner of the group is not in the preferred list for the group. To change the owner node for the group, move the group.
+
+0x000013DB
+
+ERROR_CLUSTER_DATABASE_SEQMISMATCH
+
+
+The join operation failed because the cluster database sequence number has changed or is incompatible with the locker node. This can happen during a join operation if the cluster database was changing during the join.
+
+0x000013DC
+
+ERROR_RESMON_INVALID_STATE
+
+
+The resource monitor will not allow the fail operation to be performed while the resource is in its current state. This can happen if the resource is in a pending state.
+
+0x000013DD
+
+ERROR_CLUSTER_GUM_NOT_LOCKER
+
+
+A non-locker code received a request to reserve the lock for making global updates.
+
+0x000013DE
+
+ERROR_QUORUM_DISK_NOT_FOUND
+
+
+The quorum disk could not be located by the cluster service.
+
+0x000013DF
+
+ERROR_DATABASE_BACKUP_CORRUPT
+
+
+The backed-up cluster database is possibly corrupt.
+
+0x000013E0
+
+ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT
+
+
+A DFS root already exists in this cluster node.
+
+0x000013E1
+
+ERROR_RESOURCE_PROPERTY_UNCHANGEABLE
+
+
+An attempt to modify a resource property failed because it conflicts with another existing property.
+
+0x00001702
+
+ERROR_CLUSTER_MEMBERSHIP_INVALID_STATE
+
+
+An operation was attempted that is incompatible with the current membership state of the node.
+
+0x00001703
+
+ERROR_CLUSTER_QUORUMLOG_NOT_FOUND
+
+
+The quorum resource does not contain the quorum log.
+
+0x00001704
+
+ERROR_CLUSTER_MEMBERSHIP_HALT
+
+
+The membership engine requested shutdown of the cluster service on this node.
+
+0x00001705
+
+ERROR_CLUSTER_INSTANCE_ID_MISMATCH
+
+
+The join operation failed because the cluster instance ID of the joining node does not match the cluster instance ID of the sponsor node.
+
+0x00001706
+
+ERROR_CLUSTER_NETWORK_NOT_FOUND_FOR_IP
+
+
+A matching cluster network for the specified IP address could not be found.
+
+0x00001707
+
+ERROR_CLUSTER_PROPERTY_DATA_TYPE_MISMATCH
+
+
+The actual data type of the property did not match the expected data type of the property.
+
+0x00001708
+
+ERROR_CLUSTER_EVICT_WITHOUT_CLEANUP
+
+
+The cluster node was evicted from the cluster successfully, but the node was not cleaned up. To determine what clean-up steps failed and how to recover, see the Failover Clustering application event log using Event Viewer.
+
+0x00001709
+
+ERROR_CLUSTER_PARAMETER_MISMATCH
+
+
+Two or more parameter values specified for a resource's properties are in conflict.
+
+0x0000170A
+
+ERROR_NODE_CANNOT_BE_CLUSTERED
+
+
+This computer cannot be made a member of a cluster.
+
+0x0000170B
+
+ERROR_CLUSTER_WRONG_OS_VERSION
+
+
+This computer cannot be made a member of a cluster because it does not have the correct version of Windows installed.
+
+0x0000170C
+
+ERROR_CLUSTER_CANT_CREATE_DUP_CLUSTER_NAME
+
+
+A cluster cannot be created with the specified cluster name because that cluster name is already in use. Specify a different name for the cluster.
+
+0x0000170D
+
+ERROR_CLUSCFG_ALREADY_COMMITTED
+
+
+The cluster configuration action has already been committed.
+
+0x0000170E
+
+ERROR_CLUSCFG_ROLLBACK_FAILED
+
+
+The cluster configuration action could not be rolled back.
+
+0x0000170F
+
+ERROR_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT
+
+
+The drive letter assigned to a system disk on one node conflicted with the drive letter assigned to a disk on another node.
+
+0x00001710
+
+ERROR_CLUSTER_OLD_VERSION
+
+
+One or more nodes in the cluster are running a version of Windows that does not support this operation.
+
+0x00001711
+
+ERROR_CLUSTER_MISMATCHED_COMPUTER_ACCT_NAME
+
+
+The name of the corresponding computer account does not match the network name for this resource.
+
+0x00001712
+
+ERROR_CLUSTER_NO_NET_ADAPTERS
+
+
+No network adapters are available.
+
+0x00001713
+
+ERROR_CLUSTER_POISONED
+
+
+The cluster node has been poisoned.
+
+0x00001714
+
+ERROR_CLUSTER_GROUP_MOVING
+
+
+The group is unable to accept the request because it is moving to another node.
+
+0x00001715
+
+ERROR_CLUSTER_RESOURCE_TYPE_BUSY
+
+
+The resource type cannot accept the request because it is too busy performing another operation.
+
+0x00001716
+
+ERROR_RESOURCE_CALL_TIMED_OUT
+
+
+The call to the cluster resource DLL timed out.
+
+0x00001717
+
+ERROR_INVALID_CLUSTER_IPV6_ADDRESS
+
+
+The address is not valid for an IPv6 Address resource. A global IPv6 address is required, and it must match a cluster network. Compatibility addresses are not permitted.
+
+0x00001718
+
+ERROR_CLUSTER_INTERNAL_INVALID_FUNCTION
+
+
+An internal cluster error occurred. A call to an invalid function was attempted.
+
+0x00001719
+
+ERROR_CLUSTER_PARAMETER_OUT_OF_BOUNDS
+
+
+A parameter value is out of acceptable range.
+
+0x0000171A
+
+ERROR_CLUSTER_PARTIAL_SEND
+
+
+A network error occurred while sending data to another node in the cluster. The number of bytes transmitted was less than required.
+
+0x0000171B
+
+ERROR_CLUSTER_REGISTRY_INVALID_FUNCTION
+
+
+An invalid cluster registry operation was attempted.
+
+0x0000171C
+
+ERROR_CLUSTER_INVALID_STRING_TERMINATION
+
+
+An input string of characters is not properly terminated.
+
+0x0000171D
+
+ERROR_CLUSTER_INVALID_STRING_FORMAT
+
+
+An input string of characters is not in a valid format for the data it represents.
+
+0x0000171E
+
+ERROR_CLUSTER_DATABASE_TRANSACTION_IN_PROGRESS
+
+
+An internal cluster error occurred. A cluster database transaction was attempted while a transaction was already in progress.
+
+0x0000171F
+
+ERROR_CLUSTER_DATABASE_TRANSACTION_NOT_IN_PROGRESS
+
+
+An internal cluster error occurred. There was an attempt to commit a cluster database transaction while no transaction was in progress.
+
+0x00001720
+
+ERROR_CLUSTER_NULL_DATA
+
+
+An internal cluster error occurred. Data was not properly initialized.
+
+0x00001721
+
+ERROR_CLUSTER_PARTIAL_READ
+
+
+An error occurred while reading from a stream of data. An unexpected number of bytes was returned.
+
+0x00001722
+
+ERROR_CLUSTER_PARTIAL_WRITE
+
+
+An error occurred while writing to a stream of data. The required number of bytes could not be written.
+
+0x00001723
+
+ERROR_CLUSTER_CANT_DESERIALIZE_DATA
+
+
+An error occurred while deserializing a stream of cluster data.
+
+0x00001724
+
+ERROR_DEPENDENT_RESOURCE_PROPERTY_CONFLICT
+
+
+One or more property values for this resource are in conflict with one or more property values associated with its dependent resources.
+
+0x00001725
+
+ERROR_CLUSTER_NO_QUORUM
+
+
+A quorum of cluster nodes was not present to form a cluster.
+
+0x00001726
+
+ERROR_CLUSTER_INVALID_IPV6_NETWORK
+
+
+The cluster network is not valid for an IPv6 address resource, or it does not match the configured address.
+
+0x00001727
+
+ERROR_CLUSTER_INVALID_IPV6_TUNNEL_NETWORK
+
+
+The cluster network is not valid for an IPv6 tunnel resource. Check the configuration of the IP Address resource on which the IPv6 tunnel resource depends.
+
+0x00001728
+
+ERROR_QUORUM_NOT_ALLOWED_IN_THIS_GROUP
+
+
+Quorum resource cannot reside in the available storage group.
+
+0x00001770
+
+ERROR_ENCRYPTION_FAILED
+
+
+The specified file could not be encrypted.
+
+0x00001771
+
+ERROR_DECRYPTION_FAILED
+
+
+The specified file could not be decrypted.
+
+0x00001772
+
+ERROR_FILE_ENCRYPTED
+
+
+The specified file is encrypted and the user does not have the ability to decrypt it.
+
+0x00001773
+
+ERROR_NO_RECOVERY_POLICY
+
+
+There is no valid encryption recovery policy configured for this system.
+
+0x00001774
+
+ERROR_NO_EFS
+
+
+The required encryption driver is not loaded for this system.
+
+0x00001775
+
+ERROR_WRONG_EFS
+
+
+The file was encrypted with a different encryption driver than is currently loaded.
+
+0x00001776
+
+ERROR_NO_USER_KEYS
+
+
+There are no Encrypting File System (EFS) keys defined for the user.
+
+0x00001777
+
+ERROR_FILE_NOT_ENCRYPTED
+
+
+The specified file is not encrypted.
+
+0x00001778
+
+ERROR_NOT_EXPORT_FORMAT
+
+
+The specified file is not in the defined EFS export format.
+
+0x00001779
+
+ERROR_FILE_READ_ONLY
+
+
+The specified file is read-only.
+
+0x0000177A
+
+ERROR_DIR_EFS_DISALLOWED
+
+
+The directory has been disabled for encryption.
+
+0x0000177B
+
+ERROR_EFS_SERVER_NOT_TRUSTED
+
+
+The server is not trusted for remote encryption operation.
+
+0x0000177C
+
+ERROR_BAD_RECOVERY_POLICY
+
+
+Recovery policy configured for this system contains invalid recovery certificate.
+
+0x0000177D
+
+ERROR_EFS_ALG_BLOB_TOO_BIG
+
+
+The encryption algorithm used on the source file needs a bigger key buffer than the one on the destination file.
+
+0x0000177E
+
+ERROR_VOLUME_NOT_SUPPORT_EFS
+
+
+The disk partition does not support file encryption.
+
+0x0000177F
+
+ERROR_EFS_DISABLED
+
+
+This machine is disabled for file encryption.
+
+0x00001780
+
+ERROR_EFS_VERSION_NOT_SUPPORT
+
+
+A newer system is required to decrypt this encrypted file.
+
+0x00001781
+
+ERROR_CS_ENCRYPTION_INVALID_SERVER_RESPONSE
+
+
+The remote server sent an invalid response for a file being opened with client-side encryption.
+
+0x00001782
+
+ERROR_CS_ENCRYPTION_UNSUPPORTED_SERVER
+
+
+Client-side encryption is not supported by the remote server even though it claims to support it.
+
+0x00001783
+
+ERROR_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE
+
+
+File is encrypted and should be opened in client-side encryption mode.
+
+0x00001784
+
+ERROR_CS_ENCRYPTION_NEW_ENCRYPTED_FILE
+
+
+A new encrypted file is being created and a $EFS needs to be provided.
+
+0x00001785
+
+ERROR_CS_ENCRYPTION_FILE_NOT_CSE
+
+
+The SMB client requested a client-side extension (CSE) file system control (FSCTL) on a non-CSE file.
+
+0x000017E6
+
+ERROR_NO_BROWSER_SERVERS_FOUND
+
+
+The list of servers for this workgroup is not currently available
+
+0x00001838
+
+SCHED_E_SERVICE_NOT_LOCALSYSTEM
+
+
+The Task Scheduler service must be configured to run in the System account to function properly. Individual tasks can be configured to run in other accounts.
+
+0x000019C8
+
+ERROR_LOG_SECTOR_INVALID
+
+
+The log service encountered an invalid log sector.
+
+0x000019C9
+
+ERROR_LOG_SECTOR_PARITY_INVALID
+
+
+The log service encountered a log sector with invalid block parity.
+
+0x000019CA
+
+ERROR_LOG_SECTOR_REMAPPED
+
+
+The log service encountered a remapped log sector.
+
+0x000019CB
+
+ERROR_LOG_BLOCK_INCOMPLETE
+
+
+The log service encountered a partial or incomplete log block.
+
+0x000019CC
+
+ERROR_LOG_INVALID_RANGE
+
+
+The log service encountered an attempt to access data outside the active log range.
+
+0x000019CD
+
+ERROR_LOG_BLOCKS_EXHAUSTED
+
+
+The log service user marshaling buffers are exhausted.
+
+0x000019CE
+
+ERROR_LOG_READ_CONTEXT_INVALID
+
+
+The log service encountered an attempt to read from a marshaling area with an invalid read context.
+
+0x000019CF
+
+ERROR_LOG_RESTART_INVALID
+
+
+The log service encountered an invalid log restart area.
+
+0x000019D0
+
+ERROR_LOG_BLOCK_VERSION
+
+
+The log service encountered an invalid log block version.
+
+0x000019D1
+
+ERROR_LOG_BLOCK_INVALID
+
+
+The log service encountered an invalid log block.
+
+0x000019D2
+
+ERROR_LOG_READ_MODE_INVALID
+
+
+The log service encountered an attempt to read the log with an invalid read mode.
+
+0x000019D3
+
+ERROR_LOG_NO_RESTART
+
+
+The log service encountered a log stream with no restart area.
+
+0x000019D4
+
+ERROR_LOG_METADATA_CORRUPT
+
+
+The log service encountered a corrupted metadata file.
+
+0x000019D5
+
+ERROR_LOG_METADATA_INVALID
+
+
+The log service encountered a metadata file that could not be created by the log file system.
+
+0x000019D6
+
+ERROR_LOG_METADATA_INCONSISTENT
+
+
+The log service encountered a metadata file with inconsistent data.
+
+0x000019D7
+
+ERROR_LOG_RESERVATION_INVALID
+
+
+The log service encountered an attempt to erroneous allocate or dispose reservation space.
+
+0x000019D8
+
+ERROR_LOG_CANT_DELETE
+
+
+The log service cannot delete a log file or file system container.
+
+0x000019D9
+
+ERROR_LOG_CONTAINER_LIMIT_EXCEEDED
+
+
+The log service has reached the maximum allowable containers allocated to a log file.
+
+0x000019DA
+
+ERROR_LOG_START_OF_LOG
+
+
+The log service has attempted to read or write backward past the start of the log.
+
+0x000019DB
+
+ERROR_LOG_POLICY_ALREADY_INSTALLED
+
+
+The log policy could not be installed because a policy of the same type is already present.
+
+0x000019DC
+
+ERROR_LOG_POLICY_NOT_INSTALLED
+
+
+The log policy in question was not installed at the time of the request.
+
+0x000019DD
+
+ERROR_LOG_POLICY_INVALID
+
+
+The installed set of policies on the log is invalid.
+
+0x000019DE
+
+ERROR_LOG_POLICY_CONFLICT
+
+
+A policy on the log in question prevented the operation from completing.
+
+0x000019DF
+
+ERROR_LOG_PINNED_ARCHIVE_TAIL
+
+
+Log space cannot be reclaimed because the log is pinned by the archive tail.
+
+0x000019E0
+
+ERROR_LOG_RECORD_NONEXISTENT
+
+
+The log record is not a record in the log file.
+
+0x000019E1
+
+ERROR_LOG_RECORDS_RESERVED_INVALID
+
+
+The number of reserved log records or the adjustment of the number of reserved log records is invalid.
+
+0x000019E2
+
+ERROR_LOG_SPACE_RESERVED_INVALID
+
+
+The reserved log space or the adjustment of the log space is invalid.
+
+0x000019E3
+
+ERROR_LOG_TAIL_INVALID
+
+
+A new or existing archive tail or base of the active log is invalid.
+
+0x000019E4
+
+ERROR_LOG_FULL
+
+
+The log space is exhausted.
+
+0x000019E5
+
+ERROR_COULD_NOT_RESIZE_LOG
+
+
+The log could not be set to the requested size.
+
+0x000019E6
+
+ERROR_LOG_MULTIPLEXED
+
+
+The log is multiplexed; no direct writes to the physical log are allowed.
+
+0x000019E7
+
+ERROR_LOG_DEDICATED
+
+
+The operation failed because the log is a dedicated log.
+
+0x000019E8
+
+ERROR_LOG_ARCHIVE_NOT_IN_PROGRESS
+
+
+The operation requires an archive context.
+
+0x000019E9
+
+ERROR_LOG_ARCHIVE_IN_PROGRESS
+
+
+Log archival is in progress.
+
+0x000019EA
+
+ERROR_LOG_EPHEMERAL
+
+
+The operation requires a non-ephemeral log, but the log is ephemeral.
+
+0x000019EB
+
+ERROR_LOG_NOT_ENOUGH_CONTAINERS
+
+
+The log must have at least two containers before it can be read from or written to.
+
+0x000019EC
+
+ERROR_LOG_CLIENT_ALREADY_REGISTERED
+
+
+A log client has already registered on the stream.
+
+0x000019ED
+
+ERROR_LOG_CLIENT_NOT_REGISTERED
+
+
+A log client has not been registered on the stream.
+
+0x000019EE
+
+ERROR_LOG_FULL_HANDLER_IN_PROGRESS
+
+
+A request has already been made to handle the log full condition.
+
+0x000019EF
+
+ERROR_LOG_CONTAINER_READ_FAILED
+
+
+The log service encountered an error when attempting to read from a log container.
+
+0x000019F0
+
+ERROR_LOG_CONTAINER_WRITE_FAILED
+
+
+The log service encountered an error when attempting to write to a log container.
+
+0x000019F1
+
+ERROR_LOG_CONTAINER_OPEN_FAILED
+
+
+The log service encountered an error when attempting to open a log container.
+
+0x000019F2
+
+ERROR_LOG_CONTAINER_STATE_INVALID
+
+
+The log service encountered an invalid container state when attempting a requested action.
+
+0x000019F3
+
+ERROR_LOG_STATE_INVALID
+
+
+The log service is not in the correct state to perform a requested action.
+
+0x000019F4
+
+ERROR_LOG_PINNED
+
+
+The log space cannot be reclaimed because the log is pinned.
+
+0x000019F5
+
+ERROR_LOG_METADATA_FLUSH_FAILED
+
+
+The log metadata flush failed.
+
+0x000019F6
+
+ERROR_LOG_INCONSISTENT_SECURITY
+
+
+Security on the log and its containers is inconsistent.
+
+0x000019F7
+
+ERROR_LOG_APPENDED_FLUSH_FAILED
+
+
+Records were appended to the log or reservation changes were made, but the log could not be flushed.
+
+0x000019F8
+
+ERROR_LOG_PINNED_RESERVATION
+
+
+The log is pinned due to reservation consuming most of the log space. Free some reserved records to make space available.
+
+0x00001A2C
+
+ERROR_INVALID_TRANSACTION
+
+
+The transaction handle associated with this operation is not valid.
+
+0x00001A2D
+
+ERROR_TRANSACTION_NOT_ACTIVE
+
+
+The requested operation was made in the context of a transaction that is no longer active.
+
+0x00001A2E
+
+ERROR_TRANSACTION_REQUEST_NOT_VALID
+
+
+The requested operation is not valid on the transaction object in its current state.
+
+0x00001A2F
+
+ERROR_TRANSACTION_NOT_REQUESTED
+
+
+The caller has called a response API, but the response is not expected because the transaction manager did not issue the corresponding request to the caller.
+
+0x00001A30
+
+ERROR_TRANSACTION_ALREADY_ABORTED
+
+
+It is too late to perform the requested operation because the transaction has already been aborted.
+
+0x00001A31
+
+ERROR_TRANSACTION_ALREADY_COMMITTED
+
+
+It is too late to perform the requested operation because the transaction has already been committed.
+
+0x00001A32
+
+ERROR_TM_INITIALIZATION_FAILED
+
+
+The transaction manager was unable to be successfully initialized. Transacted operations are not supported.
+
+0x00001A33
+
+ERROR_RESOURCEMANAGER_READ_ONLY
+
+
+The specified resource manager made no changes or updates to the resource under this transaction.
+
+0x00001A34
+
+ERROR_TRANSACTION_NOT_JOINED
+
+
+The resource manager has attempted to prepare a transaction that it has not successfully joined.
+
+0x00001A35
+
+ERROR_TRANSACTION_SUPERIOR_EXISTS
+
+
+The transaction object already has a superior enlistment, and the caller attempted an operation that would have created a new superior. Only a single superior enlistment is allowed.
+
+0x00001A36
+
+ERROR_CRM_PROTOCOL_ALREADY_EXISTS
+
+
+The resource manager tried to register a protocol that already exists.
+
+0x00001A37
+
+ERROR_TRANSACTION_PROPAGATION_FAILED
+
+
+The attempt to propagate the transaction failed.
+
+0x00001A38
+
+ERROR_CRM_PROTOCOL_NOT_FOUND
+
+
+The requested propagation protocol was not registered as a CRM.
+
+0x00001A39
+
+ERROR_TRANSACTION_INVALID_MARSHALL_BUFFER
+
+
+The buffer passed in to PushTransaction or PullTransaction is not in a valid format.
+
+0x00001A3A
+
+ERROR_CURRENT_TRANSACTION_NOT_VALID
+
+
+The current transaction context associated with the thread is not a valid handle to a transaction object.
+
+0x00001A3B
+
+ERROR_TRANSACTION_NOT_FOUND
+
+
+The specified transaction object could not be opened because it was not found.
+
+0x00001A3C
+
+ERROR_RESOURCEMANAGER_NOT_FOUND
+
+
+The specified resource manager object could not be opened because it was not found.
+
+0x00001A3D
+
+ERROR_ENLISTMENT_NOT_FOUND
+
+
+The specified enlistment object could not be opened because it was not found.
+
+0x00001A3E
+
+ERROR_TRANSACTIONMANAGER_NOT_FOUND
+
+
+The specified transaction manager object could not be opened because it was not found.
+
+0x00001A3F
+
+ERROR_TRANSACTIONMANAGER_NOT_ONLINE
+
+
+The specified resource manager was unable to create an enlistment because its associated transaction manager is not online.
+
+0x00001A40
+
+ERROR_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION
+
+
+The specified transaction manager was unable to create the objects contained in its log file in the ObjectB namespace. Therefore, the transaction manager was unable to recover.
+
+0x00001A90
+
+ERROR_TRANSACTIONAL_CONFLICT
+
+
+The function attempted to use a name that is reserved for use by another transaction.
+
+0x00001A91
+
+ERROR_RM_NOT_ACTIVE
+
+
+Transaction support within the specified file system resource manager is not started or was shut down due to an error.
+
+0x00001A92
+
+ERROR_RM_METADATA_CORRUPT
+
+
+The metadata of the resource manager has been corrupted. The resource manager will not function.
+
+0x00001A93
+
+ERROR_DIRECTORY_NOT_RM
+
+
+The specified directory does not contain a resource manager.
+
+0x00001A95
+
+ERROR_TRANSACTIONS_UNSUPPORTED_REMOTE
+
+
+The remote server or share does not support transacted file operations.
+
+0x00001A96
+
+ERROR_LOG_RESIZE_INVALID_SIZE
+
+
+The requested log size is invalid.
+
+0x00001A97
+
+ERROR_OBJECT_NO_LONGER_EXISTS
+
+
+The object (file, stream, link) corresponding to the handle has been deleted by a transaction savepoint rollback.
+
+0x00001A98
+
+ERROR_STREAM_MINIVERSION_NOT_FOUND
+
+
+The specified file miniversion was not found for this transacted file open.
+
+0x00001A99
+
+ERROR_STREAM_MINIVERSION_NOT_VALID
+
+
+The specified file miniversion was found but has been invalidated. The most likely cause is a transaction savepoint rollback.
+
+0x00001A9A
+
+ERROR_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION
+
+
+A miniversion can only be opened in the context of the transaction that created it.
+
+0x00001A9B
+
+ERROR_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT
+
+
+It is not possible to open a miniversion with modify access.
+
+0x00001A9C
+
+ERROR_CANT_CREATE_MORE_STREAM_MINIVERSIONS
+
+
+It is not possible to create any more miniversions for this stream.
+
+0x00001A9E
+
+ERROR_REMOTE_FILE_VERSION_MISMATCH
+
+
+The remote server sent mismatching version numbers or FID for a file opened with transactions.
+
+0x00001A9F
+
+ERROR_HANDLE_NO_LONGER_VALID
+
+
+The handle has been invalidated by a transaction. The most likely cause is the presence of memory mapping on a file, or an open handle when the transaction ended or rolled back to savepoint.
+
+0x00001AA0
+
+ERROR_NO_TXF_METADATA
+
+
+There is no transaction metadata on the file.
+
+0x00001AA1
+
+ERROR_LOG_CORRUPTION_DETECTED
+
+
+The log data is corrupt.
+
+0x00001AA2
+
+ERROR_CANT_RECOVER_WITH_HANDLE_OPEN
+
+
+The file cannot be recovered because a handle is still open on it.
+
+0x00001AA3
+
+ERROR_RM_DISCONNECTED
+
+
+The transaction outcome is unavailable because the resource manager responsible for it is disconnected.
+
+0x00001AA4
+
+ERROR_ENLISTMENT_NOT_SUPERIOR
+
+
+The request was rejected because the enlistment in question is not a superior enlistment.
+
+0x00001AA5
+
+ERROR_RECOVERY_NOT_NEEDED
+
+
+The transactional resource manager is already consistent. Recovery is not needed.
+
+0x00001AA6
+
+ERROR_RM_ALREADY_STARTED
+
+
+The transactional resource manager has already been started.
+
+0x00001AA7
+
+ERROR_FILE_IDENTITY_NOT_PERSISTENT
+
+
+The file cannot be opened in a transaction because its identity depends on the outcome of an unresolved transaction.
+
+0x00001AA8
+
+ERROR_CANT_BREAK_TRANSACTIONAL_DEPENDENCY
+
+
+The operation cannot be performed because another transaction is depending on the fact that this property will not change.
+
+0x00001AA9
+
+ERROR_CANT_CROSS_RM_BOUNDARY
+
+
+The operation would involve a single file with two transactional resource managers and is therefore not allowed.
+
+0x00001AAA
+
+ERROR_TXF_DIR_NOT_EMPTY
+
+
+The $Txf directory must be empty for this operation to succeed.
+
+0x00001AAB
+
+ERROR_INDOUBT_TRANSACTIONS_EXIST
+
+
+The operation would leave a transactional resource manager in an inconsistent state and is, therefore, not allowed.
+
+0x00001AAC
+
+ERROR_TM_VOLATILE
+
+
+The operation could not be completed because the transaction manager does not have a log.
+
+0x00001AAD
+
+ERROR_ROLLBACK_TIMER_EXPIRED
+
+
+A rollback could not be scheduled because a previously scheduled rollback has already been executed or is queued for execution.
+
+0x00001AAE
+
+ERROR_TXF_ATTRIBUTE_CORRUPT
+
+
+The transactional metadata attribute on the file or directory is corrupt and unreadable.
+
+0x00001AAF
+
+ERROR_EFS_NOT_ALLOWED_IN_TRANSACTION
+
+
+The encryption operation could not be completed because a transaction is active.
+
+0x00001AB0
+
+ERROR_TRANSACTIONAL_OPEN_NOT_ALLOWED
+
+
+This object is not allowed to be opened in a transaction.
+
+0x00001AB1
+
+ERROR_LOG_GROWTH_FAILED
+
+
+An attempt to create space in the transactional resource manager's log failed. The failure status has been recorded in the event log.
+
+0x00001AB2
+
+ERROR_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE
+
+
+Memory mapping (creating a mapped section) to a remote file under a transaction is not supported.
+
+0x00001AB3
+
+ERROR_TXF_METADATA_ALREADY_PRESENT
+
+
+Transaction metadata is already present on this file and cannot be superseded.
+
+0x00001AB4
+
+ERROR_TRANSACTION_SCOPE_CALLBACKS_NOT_SET
+
+
+A transaction scope could not be entered because the scope handler has not been initialized.
+
+0x00001AB5
+
+ERROR_TRANSACTION_REQUIRED_PROMOTION
+
+
+Promotion was required to allow the resource manager to enlist, but the transaction was set to disallow it.
+
+0x00001AB6
+
+ERROR_CANNOT_EXECUTE_FILE_IN_TRANSACTION
+
+
+This file is open for modification in an unresolved transaction and can be opened for execution only by a transacted reader.
+
+0x00001AB7
+
+ERROR_TRANSACTIONS_NOT_FROZEN
+
+
+The request to thaw frozen transactions was ignored because transactions were not previously frozen.
+
+0x00001AB8
+
+ERROR_TRANSACTION_FREEZE_IN_PROGRESS
+
+
+Transactions cannot be frozen because a freeze is already in progress.
+
+0x00001AB9
+
+ERROR_NOT_SNAPSHOT_VOLUME
+
+
+The target volume is not a snapshot volume. This operation is only valid on a volume mounted as a snapshot.
+
+0x00001ABA
+
+ERROR_NO_SAVEPOINT_WITH_OPEN_FILES
+
+
+The savepoint operation failed because files are open on the transaction. This is not permitted.
+
+0x00001ABB
+
+ERROR_DATA_LOST_REPAIR
+
+
+Windows has discovered corruption in a file, and that file has since been repaired. Data loss might have occurred.
+
+0x00001ABC
+
+ERROR_SPARSE_NOT_ALLOWED_IN_TRANSACTION
+
+
+The sparse operation could not be completed because a transaction is active on the file.
+
+0x00001ABD
+
+ERROR_TM_IDENTITY_MISMATCH
+
+
+The call to create a transaction manager object failed because the Tm Identity stored in the logfile does not match the Tm Identity that was passed in as an argument.
+
+0x00001ABE
+
+ERROR_FLOATED_SECTION
+
+
+I/O was attempted on a section object that has been floated as a result of a transaction ending. There is no valid data.
+
+0x00001ABF
+
+ERROR_CANNOT_ACCEPT_TRANSACTED_WORK
+
+
+The transactional resource manager cannot currently accept transacted work due to a transient condition, such as low resources.
+
+0x00001AC0
+
+ERROR_CANNOT_ABORT_TRANSACTIONS
+
+
+The transactional resource manager had too many transactions outstanding that could not be aborted. The transactional resource manager has been shut down.
+
+0x00001B59
+
+ERROR_CTX_WINSTATION_NAME_INVALID
+
+
+The specified session name is invalid.
+
+0x00001B5A
+
+ERROR_CTX_INVALID_PD
+
+
+The specified protocol driver is invalid.
+
+0x00001B5B
+
+ERROR_CTX_PD_NOT_FOUND
+
+
+The specified protocol driver was not found in the system path.
+
+0x00001B5C
+
+ERROR_CTX_WD_NOT_FOUND
+
+
+The specified terminal connection driver was not found in the system path.
+
+0x00001B5D
+
+ERROR_CTX_CANNOT_MAKE_EVENTLOG_ENTRY
+
+
+A registry key for event logging could not be created for this session.
+
+0x00001B5E
+
+ERROR_CTX_SERVICE_NAME_COLLISION
+
+
+A service with the same name already exists on the system.
+
+0x00001B5F
+
+ERROR_CTX_CLOSE_PENDING
+
+
+A close operation is pending on the session.
+
+0x00001B60
+
+ERROR_CTX_NO_OUTBUF
+
+
+There are no free output buffers available.
+
+0x00001B61
+
+ERROR_CTX_MODEM_INF_NOT_FOUND
+
+
+The MODEM.INF file was not found.
+
+0x00001B62
+
+ERROR_CTX_INVALID_MODEMNAME
+
+
+The modem name was not found in the MODEM.INF file.
+
+0x00001B63
+
+ERROR_CTX_MODEM_RESPONSE_ERROR
+
+
+The modem did not accept the command sent to it. Verify that the configured modem name matches the attached modem.
+
+0x00001B64
+
+ERROR_CTX_MODEM_RESPONSE_TIMEOUT
+
+
+The modem did not respond to the command sent to it. Verify that the modem is properly cabled and turned on.
+
+0x00001B65
+
+ERROR_CTX_MODEM_RESPONSE_NO_CARRIER
+
+
+Carrier detect has failed or carrier has been dropped due to disconnect.
+
+0x00001B66
+
+ERROR_CTX_MODEM_RESPONSE_NO_DIALTONE
+
+
+Dial tone not detected within the required time. Verify that the phone cable is properly attached and functional.
+
+0x00001B67
+
+ERROR_CTX_MODEM_RESPONSE_BUSY
+
+
+Busy signal detected at remote site on callback.
+
+0x00001B68
+
+ERROR_CTX_MODEM_RESPONSE_VOICE
+
+
+Voice detected at remote site on callback.
+
+0x00001B69
+
+ERROR_CTX_TD_ERROR
+
+
+Transport driver error.
+
+0x00001B6E
+
+ERROR_CTX_WINSTATION_NOT_FOUND
+
+
+The specified session cannot be found.
+
+0x00001B6F
+
+ERROR_CTX_WINSTATION_ALREADY_EXISTS
+
+
+The specified session name is already in use.
+
+0x00001B70
+
+ERROR_CTX_WINSTATION_BUSY
+
+
+The requested operation cannot be completed because the terminal connection is currently busy processing a connect, disconnect, reset, or delete operation.
+
+0x00001B71
+
+ERROR_CTX_BAD_VIDEO_MODE
+
+
+An attempt has been made to connect to a session whose video mode is not supported by the current client.
+
+0x00001B7B
+
+ERROR_CTX_GRAPHICS_INVALID
+
+
+The application attempted to enable DOS graphics mode. DOS graphics mode is not supported.
+
+0x00001B7D
+
+ERROR_CTX_LOGON_DISABLED
+
+
+Your interactive logon privilege has been disabled. Contact your administrator.
+
+0x00001B7E
+
+ERROR_CTX_NOT_CONSOLE
+
+
+The requested operation can be performed only on the system console. This is most often the result of a driver or system DLL requiring direct console access.
+
+0x00001B80
+
+ERROR_CTX_CLIENT_QUERY_TIMEOUT
+
+
+The client failed to respond to the server connect message.
+
+0x00001B81
+
+ERROR_CTX_CONSOLE_DISCONNECT
+
+
+Disconnecting the console session is not supported.
+
+0x00001B82
+
+ERROR_CTX_CONSOLE_CONNECT
+
+
+Reconnecting a disconnected session to the console is not supported.
+
+0x00001B84
+
+ERROR_CTX_SHADOW_DENIED
+
+
+The request to control another session remotely was denied.
+
+0x00001B85
+
+ERROR_CTX_WINSTATION_ACCESS_DENIED
+
+
+The requested session access is denied.
+
+0x00001B89
+
+ERROR_CTX_INVALID_WD
+
+
+The specified terminal connection driver is invalid.
+
+0x00001B8A
+
+ERROR_CTX_SHADOW_INVALID
+
+
+The requested session cannot be controlled remotely. This might be because the session is disconnected or does not currently have a user logged on.
+
+0x00001B8B
+
+ERROR_CTX_SHADOW_DISABLED
+
+
+The requested session is not configured to allow remote control.
+
+0x00001B8C
+
+ERROR_CTX_CLIENT_LICENSE_IN_USE
+
+
+Your request to connect to this terminal server has been rejected. Your terminal server client license number is currently being used by another user. Call your system administrator to obtain a unique license number.
+
+0x00001B8D
+
+ERROR_CTX_CLIENT_LICENSE_NOT_SET
+
+
+Your request to connect to this terminal server has been rejected. Your terminal server client license number has not been entered for this copy of the terminal server client. Contact your system administrator.
+
+0x00001B8E
+
+ERROR_CTX_LICENSE_NOT_AVAILABLE
+
+
+The number of connections to this computer is limited and all connections are in use right now. Try connecting later or contact your system administrator.
+
+0x00001B8F
+
+ERROR_CTX_LICENSE_CLIENT_INVALID
+
+
+The client you are using is not licensed to use this system. Your logon request is denied.
+
+0x00001B90
+
+ERROR_CTX_LICENSE_EXPIRED
+
+
+The system license has expired. Your logon request is denied.
+
+0x00001B91
+
+ERROR_CTX_SHADOW_NOT_RUNNING
+
+
+Remote control could not be terminated because the specified session is not currently being remotely controlled.
+
+0x00001B92
+
+ERROR_CTX_SHADOW_ENDED_BY_MODE_CHANGE
+
+
+The remote control of the console was terminated because the display mode was changed. Changing the display mode in a remote control session is not supported.
+
+0x00001B93
+
+ERROR_ACTIVATION_COUNT_EXCEEDED
+
+
+Activation has already been reset the maximum number of times for this installation. Your activation timer will not be cleared.
+
+0x00001B94
+
+ERROR_CTX_WINSTATIONS_DISABLED
+
+
+Remote logons are currently disabled.
+
+0x00001B95
+
+ERROR_CTX_ENCRYPTION_LEVEL_REQUIRED
+
+
+You do not have the proper encryption level to access this session.
+
+0x00001B96
+
+ERROR_CTX_SESSION_IN_USE
+
+
+The user %s\\%s is currently logged on to this computer. Only the current user or an administrator can log on to this computer.
+
+0x00001B97
+
+ERROR_CTX_NO_FORCE_LOGOFF
+
+
+The user %s\\%s is already logged on to the console of this computer. You do not have permission to log in at this time. To resolve this issue, contact %s\\%s and have them log off.
+
+0x00001B98
+
+ERROR_CTX_ACCOUNT_RESTRICTION
+
+
+Unable to log you on because of an account restriction.
+
+0x00001B99
+
+ERROR_RDP_PROTOCOL_ERROR
+
+
+The RDP component %2 detected an error in the protocol stream and has disconnected the client.
+
+0x00001B9A
+
+ERROR_CTX_CDM_CONNECT
+
+
+The Client Drive Mapping Service has connected on terminal connection.
+
+0x00001B9B
+
+ERROR_CTX_CDM_DISCONNECT
+
+
+The Client Drive Mapping Service has disconnected on terminal connection.
+
+0x00001B9C
+
+ERROR_CTX_SECURITY_LAYER_ERROR
+
+
+The terminal server security layer detected an error in the protocol stream and has disconnected the client.
+
+0x00001B9D
+
+ERROR_TS_INCOMPATIBLE_SESSIONS
+
+
+The target session is incompatible with the current session.
+
+0x00001F41
+
+FRS_ERR_INVALID_API_SEQUENCE
+
+
+The file replication service API was called incorrectly.
+
+0x00001F42
+
+FRS_ERR_STARTING_SERVICE
+
+
+The file replication service cannot be started.
+
+0x00001F43
+
+FRS_ERR_STOPPING_SERVICE
+
+
+The file replication service cannot be stopped.
+
+0x00001F44
+
+FRS_ERR_INTERNAL_API
+
+
+The file replication service API terminated the request. The event log might contain more information.
+
+0x00001F45
+
+FRS_ERR_INTERNAL
+
+
+The file replication service terminated the request. The event log might contain more information.
+
+0x00001F46
+
+FRS_ERR_SERVICE_COMM
+
+
+The file replication service cannot be contacted. The event log might contain more information.
+
+0x00001F47
+
+FRS_ERR_INSUFFICIENT_PRIV
+
+
+The file replication service cannot satisfy the request because the user has insufficient privileges. The event log might contain more information.
+
+0x00001F48
+
+FRS_ERR_AUTHENTICATION
+
+
+The file replication service cannot satisfy the request because authenticated RPC is not available. The event log might contain more information.
+
+0x00001F49
+
+FRS_ERR_PARENT_INSUFFICIENT_PRIV
+
+
+The file replication service cannot satisfy the request because the user has insufficient privileges on the domain controller. The event log might contain more information.
+
+0x00001F4A
+
+FRS_ERR_PARENT_AUTHENTICATION
+
+
+The file replication service cannot satisfy the request because authenticated RPC is not available on the domain controller. The event log might contain more information.
+
+0x00001F4B
+
+FRS_ERR_CHILD_TO_PARENT_COMM
+
+
+The file replication service cannot communicate with the file replication service on the domain controller. The event log might contain more information.
+
+0x00001F4C
+
+FRS_ERR_PARENT_TO_CHILD_COMM
+
+
+The file replication service on the domain controller cannot communicate with the file replication service on this computer. The event log might contain more information.
+
+0x00001F4D
+
+FRS_ERR_SYSVOL_POPULATE
+
+
+The file replication service cannot populate the system volume because of an internal error. The event log might contain more information.
+
+0x00001F4E
+
+FRS_ERR_SYSVOL_POPULATE_TIMEOUT
+
+
+The file replication service cannot populate the system volume because of an internal time-out. The event log might contain more information.
+
+0x00001F4F
+
+FRS_ERR_SYSVOL_IS_BUSY
+
+
+The file replication service cannot process the request. The system volume is busy with a previous request.
+
+0x00001F50
+
+FRS_ERR_SYSVOL_DEMOTE
+
+
+The file replication service cannot stop replicating the system volume because of an internal error. The event log might contain more information.
+
+0x00001F51
+
+FRS_ERR_INVALID_SERVICE_PARAMETER
+
+
+The file replication service detected an invalid parameter.
+
+0x00002008
+
+ERROR_DS_NOT_INSTALLED
+
+
+An error occurred while installing the directory service. For more information, see the event log.
+
+0x00002009
+
+ERROR_DS_MEMBERSHIP_EVALUATED_LOCALLY
+
+
+The directory service evaluated group memberships locally.
+
+0x0000200A
+
+ERROR_DS_NO_ATTRIBUTE_OR_VALUE
+
+
+The specified directory service attribute or value does not exist.
+
+0x0000200B
+
+ERROR_DS_INVALID_ATTRIBUTE_SYNTAX
+
+
+The attribute syntax specified to the directory service is invalid.
+
+0x0000200C
+
+ERROR_DS_ATTRIBUTE_TYPE_UNDEFINED
+
+
+The attribute type specified to the directory service is not defined.
+
+0x0000200D
+
+ERROR_DS_ATTRIBUTE_OR_VALUE_EXISTS
+
+
+The specified directory service attribute or value already exists.
+
+0x0000200E
+
+ERROR_DS_BUSY
+
+
+The directory service is busy.
+
+0x0000200F
+
+ERROR_DS_UNAVAILABLE
+
+
+The directory service is unavailable.
+
+0x00002010
+
+ERROR_DS_NO_RIDS_ALLOCATED
+
+
+The directory service was unable to allocate a relative identifier.
+
+0x00002011
+
+ERROR_DS_NO_MORE_RIDS
+
+
+The directory service has exhausted the pool of relative identifiers.
+
+0x00002012
+
+ERROR_DS_INCORRECT_ROLE_OWNER
+
+
+The requested operation could not be performed because the directory service is not the master for that type of operation.
+
+0x00002013
+
+ERROR_DS_RIDMGR_INIT_ERROR
+
+
+The directory service was unable to initialize the subsystem that allocates relative identifiers.
+
+0x00002014
+
+ERROR_DS_OBJ_CLASS_VIOLATION
+
+
+The requested operation did not satisfy one or more constraints associated with the class of the object.
+
+0x00002015
+
+ERROR_DS_CANT_ON_NON_LEAF
+
+
+The directory service can perform the requested operation only on a leaf object.
+
+0x00002016
+
+ERROR_DS_CANT_ON_RDN
+
+
+The directory service cannot perform the requested operation on the relative distinguished name (RDN) attribute of an object.
+
+0x00002017
+
+ERROR_DS_CANT_MOD_OBJ_CLASS
+
+
+The directory service detected an attempt to modify the object class of an object.
+
+0x00002018
+
+ERROR_DS_CROSS_DOM_MOVE_ERROR
+
+
+The requested cross-domain move operation could not be performed.
+
+0x00002019
+
+ERROR_DS_GC_NOT_AVAILABLE
+
+
+Unable to contact the global catalog (GC) server.
+
+0x0000201A
+
+ERROR_SHARED_POLICY
+
+
+The policy object is shared and can only be modified at the root.
+
+0x0000201B
+
+ERROR_POLICY_OBJECT_NOT_FOUND
+
+
+The policy object does not exist.
+
+0x0000201C
+
+ERROR_POLICY_ONLY_IN_DS
+
+
+The requested policy information is only in the directory service.
+
+0x0000201D
+
+ERROR_PROMOTION_ACTIVE
+
+
+A domain controller promotion is currently active.
+
+0x0000201E
+
+ERROR_NO_PROMOTION_ACTIVE
+
+
+A domain controller promotion is not currently active.
+
+0x00002020
+
+ERROR_DS_OPERATIONS_ERROR
+
+
+An operations error occurred.
+
+0x00002021
+
+ERROR_DS_PROTOCOL_ERROR
+
+
+A protocol error occurred.
+
+0x00002022
+
+ERROR_DS_TIMELIMIT_EXCEEDED
+
+
+The time limit for this request was exceeded.
+
+0x00002023
+
+ERROR_DS_SIZELIMIT_EXCEEDED
+
+
+The size limit for this request was exceeded.
+
+0x00002024
+
+ERROR_DS_ADMIN_LIMIT_EXCEEDED
+
+
+The administrative limit for this request was exceeded.
+
+0x00002025
+
+ERROR_DS_COMPARE_FALSE
+
+
+The compare response was false.
+
+0x00002026
+
+ERROR_DS_COMPARE_TRUE
+
+
+The compare response was true.
+
+0x00002027
+
+ERROR_DS_AUTH_METHOD_NOT_SUPPORTED
+
+
+The requested authentication method is not supported by the server.
+
+0x00002028
+
+ERROR_DS_STRONG_AUTH_REQUIRED
+
+
+A more secure authentication method is required for this server.
+
+0x00002029
+
+ERROR_DS_INAPPROPRIATE_AUTH
+
+
+Inappropriate authentication.
+
+0x0000202A
+
+ERROR_DS_AUTH_UNKNOWN
+
+
+The authentication mechanism is unknown.
+
+0x0000202B
+
+ERROR_DS_REFERRAL
+
+
+A referral was returned from the server.
+
+0x0000202C
+
+ERROR_DS_UNAVAILABLE_CRIT_EXTENSION
+
+
+The server does not support the requested critical extension.
+
+0x0000202D
+
+ERROR_DS_CONFIDENTIALITY_REQUIRED
+
+
+This request requires a secure connection.
+
+0x0000202E
+
+ERROR_DS_INAPPROPRIATE_MATCHING
+
+
+Inappropriate matching.
+
+0x0000202F
+
+ERROR_DS_CONSTRAINT_VIOLATION
+
+
+A constraint violation occurred.
+
+0x00002030
+
+ERROR_DS_NO_SUCH_OBJECT
+
+
+There is no such object on the server.
+
+0x00002031
+
+ERROR_DS_ALIAS_PROBLEM
+
+
+There is an alias problem.
+
+0x00002032
+
+ERROR_DS_INVALID_DN_SYNTAX
+
+
+An invalid dn syntax has been specified.
+
+0x00002033
+
+ERROR_DS_IS_LEAF
+
+
+The object is a leaf object.
+
+0x00002034
+
+ERROR_DS_ALIAS_DEREF_PROBLEM
+
+
+There is an alias dereferencing problem.
+
+0x00002035
+
+ERROR_DS_UNWILLING_TO_PERFORM
+
+
+The server is unwilling to process the request.
+
+0x00002036
+
+ERROR_DS_LOOP_DETECT
+
+
+A loop has been detected.
+
+0x00002037
+
+ERROR_DS_NAMING_VIOLATION
+
+
+There is a naming violation.
+
+0x00002038
+
+ERROR_DS_OBJECT_RESULTS_TOO_LARGE
+
+
+The result set is too large.
+
+0x00002039
+
+ERROR_DS_AFFECTS_MULTIPLE_DSAS
+
+
+The operation affects multiple DSAs.
+
+0x0000203A
+
+ERROR_DS_SERVER_DOWN
+
+
+The server is not operational.
+
+0x0000203B
+
+ERROR_DS_LOCAL_ERROR
+
+
+A local error has occurred.
+
+0x0000203C
+
+ERROR_DS_ENCODING_ERROR
+
+
+An encoding error has occurred.
+
+0x0000203D
+
+ERROR_DS_DECODING_ERROR
+
+
+A decoding error has occurred.
+
+0x0000203E
+
+ERROR_DS_FILTER_UNKNOWN
+
+
+The search filter cannot be recognized.
+
+0x0000203F
+
+ERROR_DS_PARAM_ERROR
+
+
+One or more parameters are illegal.
+
+0x00002040
+
+ERROR_DS_NOT_SUPPORTED
+
+
+The specified method is not supported.
+
+0x00002041
+
+ERROR_DS_NO_RESULTS_RETURNED
+
+
+No results were returned.
+
+0x00002042
+
+ERROR_DS_CONTROL_NOT_FOUND
+
+
+The specified control is not supported by the server.
+
+0x00002043
+
+ERROR_DS_CLIENT_LOOP
+
+
+A referral loop was detected by the client.
+
+0x00002044
+
+ERROR_DS_REFERRAL_LIMIT_EXCEEDED
+
+
+The preset referral limit was exceeded.
+
+0x00002045
+
+ERROR_DS_SORT_CONTROL_MISSING
+
+
+The search requires a SORT control.
+
+0x00002046
+
+ERROR_DS_OFFSET_RANGE_ERROR
+
+
+The search results exceed the offset range specified.
+
+0x0000206D
+
+ERROR_DS_ROOT_MUST_BE_NC
+
+
+The root object must be the head of a naming context. The root object cannot have an instantiated parent.
+
+0x0000206E
+
+ERROR_DS_ADD_REPLICA_INHIBITED
+
+
+The add replica operation cannot be performed. The naming context must be writable to create the replica.
+
+0x0000206F
+
+ERROR_DS_ATT_NOT_DEF_IN_SCHEMA
+
+
+A reference to an attribute that is not defined in the schema occurred.
+
+0x00002070
+
+ERROR_DS_MAX_OBJ_SIZE_EXCEEDED
+
+
+The maximum size of an object has been exceeded.
+
+0x00002071
+
+ERROR_DS_OBJ_STRING_NAME_EXISTS
+
+
+An attempt was made to add an object to the directory with a name that is already in use.
+
+0x00002072
+
+ERROR_DS_NO_RDN_DEFINED_IN_SCHEMA
+
+
+An attempt was made to add an object of a class that does not have an RDN defined in the schema.
+
+0x00002073
+
+ERROR_DS_RDN_DOESNT_MATCH_SCHEMA
+
+
+An attempt was made to add an object using an RDN that is not the RDN defined in the schema.
+
+0x00002074
+
+ERROR_DS_NO_REQUESTED_ATTS_FOUND
+
+
+None of the requested attributes were found on the objects.
+
+0x00002075
+
+ERROR_DS_USER_BUFFER_TO_SMALL
+
+
+The user buffer is too small.
+
+0x00002076
+
+ERROR_DS_ATT_IS_NOT_ON_OBJ
+
+
+The attribute specified in the operation is not present on the object.
+
+0x00002077
+
+ERROR_DS_ILLEGAL_MOD_OPERATION
+
+
+Illegal modify operation. Some aspect of the modification is not permitted.
+
+0x00002078
+
+ERROR_DS_OBJ_TOO_LARGE
+
+
+The specified object is too large.
+
+0x00002079
+
+ERROR_DS_BAD_INSTANCE_TYPE
+
+
+The specified instance type is not valid.
+
+0x0000207A
+
+ERROR_DS_MASTERDSA_REQUIRED
+
+
+The operation must be performed at a master DSA.
+
+0x0000207B
+
+ERROR_DS_OBJECT_CLASS_REQUIRED
+
+
+The object class attribute must be specified.
+
+0x0000207C
+
+ERROR_DS_MISSING_REQUIRED_ATT
+
+
+A required attribute is missing.
+
+0x0000207D
+
+ERROR_DS_ATT_NOT_DEF_FOR_CLASS
+
+
+An attempt was made to modify an object to include an attribute that is not legal for its class.
+
+0x0000207E
+
+ERROR_DS_ATT_ALREADY_EXISTS
+
+
+The specified attribute is already present on the object.
+
+0x00002080
+
+ERROR_DS_CANT_ADD_ATT_VALUES
+
+
+The specified attribute is not present, or has no values.
+
+0x00002081
+
+ERROR_DS_SINGLE_VALUE_CONSTRAINT
+
+
+Multiple values were specified for an attribute that can have only one value.
+
+0x00002082
+
+ERROR_DS_RANGE_CONSTRAINT
+
+
+A value for the attribute was not in the acceptable range of values.
+
+0x00002083
+
+ERROR_DS_ATT_VAL_ALREADY_EXISTS
+
+
+The specified value already exists.
+
+0x00002084
+
+ERROR_DS_CANT_REM_MISSING_ATT
+
+
+The attribute cannot be removed because it is not present on the object.
+
+0x00002085
+
+ERROR_DS_CANT_REM_MISSING_ATT_VAL
+
+
+The attribute value cannot be removed because it is not present on the object.
+
+0x00002086
+
+ERROR_DS_ROOT_CANT_BE_SUBREF
+
+
+The specified root object cannot be a subreference.
+
+0x00002087
+
+ERROR_DS_NO_CHAINING
+
+
+Chaining is not permitted.
+
+0x00002088
+
+ERROR_DS_NO_CHAINED_EVAL
+
+
+Chained evaluation is not permitted.
+
+0x00002089
+
+ERROR_DS_NO_PARENT_OBJECT
+
+
+The operation could not be performed because the object's parent is either uninstantiated or deleted.
+
+0x0000208A
+
+ERROR_DS_PARENT_IS_AN_ALIAS
+
+
+Having a parent that is an alias is not permitted. Aliases are leaf objects.
+
+0x0000208B
+
+ERROR_DS_CANT_MIX_MASTER_AND_REPS
+
+
+The object and parent must be of the same type, either both masters or both replicas.
+
+0x0000208C
+
+ERROR_DS_CHILDREN_EXIST
+
+
+The operation cannot be performed because child objects exist. This operation can only be performed on a leaf object.
+
+0x0000208D
+
+ERROR_DS_OBJ_NOT_FOUND
+
+
+Directory object not found.
+
+0x0000208E
+
+ERROR_DS_ALIASED_OBJ_MISSING
+
+
+The aliased object is missing.
+
+0x0000208F
+
+ERROR_DS_BAD_NAME_SYNTAX
+
+
+The object name has bad syntax.
+
+0x00002090
+
+ERROR_DS_ALIAS_POINTS_TO_ALIAS
+
+
+An alias is not permitted to refer to another alias.
+
+0x00002091
+
+ERROR_DS_CANT_DEREF_ALIAS
+
+
+The alias cannot be dereferenced.
+
+0x00002092
+
+ERROR_DS_OUT_OF_SCOPE
+
+
+The operation is out of scope.
+
+0x00002093
+
+ERROR_DS_OBJECT_BEING_REMOVED
+
+
+The operation cannot continue because the object is in the process of being removed.
+
+0x00002094
+
+ERROR_DS_CANT_DELETE_DSA_OBJ
+
+
+The DSA object cannot be deleted.
+
+0x00002095
+
+ERROR_DS_GENERIC_ERROR
+
+
+A directory service error has occurred.
+
+0x00002096
+
+ERROR_DS_DSA_MUST_BE_INT_MASTER
+
+
+The operation can only be performed on an internal master DSA object.
+
+0x00002097
+
+ERROR_DS_CLASS_NOT_DSA
+
+
+The object must be of class DSA.
+
+0x00002098
+
+ERROR_DS_INSUFF_ACCESS_RIGHTS
+
+
+Insufficient access rights to perform the operation.
+
+0x00002099
+
+ERROR_DS_ILLEGAL_SUPERIOR
+
+
+The object cannot be added because the parent is not on the list of possible superiors.
+
+0x0000209A
+
+ERROR_DS_ATTRIBUTE_OWNED_BY_SAM
+
+
+Access to the attribute is not permitted because the attribute is owned by the SAM.
+
+0x0000209B
+
+ERROR_DS_NAME_TOO_MANY_PARTS
+
+
+The name has too many parts.
+
+0x0000209C
+
+ERROR_DS_NAME_TOO_LONG
+
+
+The name is too long.
+
+0x0000209D
+
+ERROR_DS_NAME_VALUE_TOO_LONG
+
+
+The name value is too long.
+
+0x0000209E
+
+ERROR_DS_NAME_UNPARSEABLE
+
+
+The directory service encountered an error parsing a name.
+
+0x0000209F
+
+ERROR_DS_NAME_TYPE_UNKNOWN
+
+
+The directory service cannot get the attribute type for a name.
+
+0x000020A0
+
+ERROR_DS_NOT_AN_OBJECT
+
+
+The name does not identify an object; the name identifies a phantom.
+
+0x000020A1
+
+ERROR_DS_SEC_DESC_TOO_SHORT
+
+
+The security descriptor is too short.
+
+0x000020A2
+
+ERROR_DS_SEC_DESC_INVALID
+
+
+The security descriptor is invalid.
+
+0x000020A3
+
+ERROR_DS_NO_DELETED_NAME
+
+
+Failed to create name for deleted object.
+
+0x000020A4
+
+ERROR_DS_SUBREF_MUST_HAVE_PARENT
+
+
+The parent of a new subreference must exist.
+
+0x000020A5
+
+ERROR_DS_NCNAME_MUST_BE_NC
+
+
+The object must be a naming context.
+
+0x000020A6
+
+ERROR_DS_CANT_ADD_SYSTEM_ONLY
+
+
+It is not permitted to add an attribute that is owned by the system.
+
+0x000020A7
+
+ERROR_DS_CLASS_MUST_BE_CONCRETE
+
+
+The class of the object must be structural; you cannot instantiate an abstract class.
+
+0x000020A8
+
+ERROR_DS_INVALID_DMD
+
+
+The schema object could not be found.
+
+0x000020A9
+
+ERROR_DS_OBJ_GUID_EXISTS
+
+
+A local object with this GUID (dead or alive) already exists.
+
+0x000020AA
+
+ERROR_DS_NOT_ON_BACKLINK
+
+
+The operation cannot be performed on a back link.
+
+0x000020AB
+
+ERROR_DS_NO_CROSSREF_FOR_NC
+
+
+The cross-reference for the specified naming context could not be found.
+
+0x000020AC
+
+ERROR_DS_SHUTTING_DOWN
+
+
+The operation could not be performed because the directory service is shutting down.
+
+0x000020AD
+
+ERROR_DS_UNKNOWN_OPERATION
+
+
+The directory service request is invalid.
+
+0x000020AE
+
+ERROR_DS_INVALID_ROLE_OWNER
+
+
+The role owner attribute could not be read.
+
+0x000020AF
+
+ERROR_DS_COULDNT_CONTACT_FSMO
+
+
+The requested Flexible Single Master Operations (FSMO) operation failed. The current FSMO holder could not be contacted.
+
+0x000020B0
+
+ERROR_DS_CROSS_NC_DN_RENAME
+
+
+Modification of a distinguished name across a naming context is not permitted.
+
+0x000020B1
+
+ERROR_DS_CANT_MOD_SYSTEM_ONLY
+
+
+The attribute cannot be modified because it is owned by the system.
+
+0x000020B2
+
+ERROR_DS_REPLICATOR_ONLY
+
+
+Only the replicator can perform this function.
+
+0x000020B3
+
+ERROR_DS_OBJ_CLASS_NOT_DEFINED
+
+
+The specified class is not defined.
+
+0x000020B4
+
+ERROR_DS_OBJ_CLASS_NOT_SUBCLASS
+
+
+The specified class is not a subclass.
+
+0x000020B5
+
+ERROR_DS_NAME_REFERENCE_INVALID
+
+
+The name reference is invalid.
+
+0x000020B6
+
+ERROR_DS_CROSS_REF_EXISTS
+
+
+A cross-reference already exists.
+
+0x000020B7
+
+ERROR_DS_CANT_DEL_MASTER_CROSSREF
+
+
+It is not permitted to delete a master cross-reference.
+
+0x000020B8
+
+ERROR_DS_SUBTREE_NOTIFY_NOT_NC_HEAD
+
+
+Subtree notifications are only supported on naming context (NC) heads.
+
+0x000020B9
+
+ERROR_DS_NOTIFY_FILTER_TOO_COMPLEX
+
+
+Notification filter is too complex.
+
+0x000020BA
+
+ERROR_DS_DUP_RDN
+
+
+Schema update failed: Duplicate RDN.
+
+0x000020BB
+
+ERROR_DS_DUP_OID
+
+
+Schema update failed: Duplicate OID.
+
+0x000020BC
+
+ERROR_DS_DUP_MAPI_ID
+
+
+Schema update failed: Duplicate Message Application Programming Interface (MAPI) identifier.
+
+0x000020BD
+
+ERROR_DS_DUP_SCHEMA_ID_GUID
+
+
+Schema update failed: Duplicate schema ID GUID.
+
+0x000020BE
+
+ERROR_DS_DUP_LDAP_DISPLAY_NAME
+
+
+Schema update failed: Duplicate LDAP display name.
+
+0x000020BF
+
+ERROR_DS_SEMANTIC_ATT_TEST
+
+
+Schema update failed: Range-Lower less than Range-Upper.
+
+0x000020C0
+
+ERROR_DS_SYNTAX_MISMATCH
+
+
+Schema update failed: Syntax mismatch.
+
+0x000020C1
+
+ERROR_DS_EXISTS_IN_MUST_HAVE
+
+
+Schema deletion failed: Attribute is used in the Must-Contain list.
+
+0x000020C2
+
+ERROR_DS_EXISTS_IN_MAY_HAVE
+
+
+Schema deletion failed: Attribute is used in the May-Contain list.
+
+0x000020C3
+
+ERROR_DS_NONEXISTENT_MAY_HAVE
+
+
+Schema update failed: Attribute in May-Contain list does not exist.
+
+0x000020C4
+
+ERROR_DS_NONEXISTENT_MUST_HAVE
+
+
+Schema update failed: Attribute in the Must-Contain list does not exist.
+
+0x000020C5
+
+ERROR_DS_AUX_CLS_TEST_FAIL
+
+
+Schema update failed: Class in the Aux Class list does not exist or is not an auxiliary class.
+
+0x000020C6
+
+ERROR_DS_NONEXISTENT_POSS_SUP
+
+
+Schema update failed: Class in the Poss-Superiors list does not exist.
+
+0x000020C7
+
+ERROR_DS_SUB_CLS_TEST_FAIL
+
+
+Schema update failed: Class in the subclass of the list does not exist or does not satisfy hierarchy rules.
+
+0x000020C8
+
+ERROR_DS_BAD_RDN_ATT_ID_SYNTAX
+
+
+Schema update failed: Rdn-Att-Id has wrong syntax.
+
+0x000020C9
+
+ERROR_DS_EXISTS_IN_AUX_CLS
+
+
+Schema deletion failed: Class is used as an auxiliary class.
+
+0x000020CA
+
+ERROR_DS_EXISTS_IN_SUB_CLS
+
+
+Schema deletion failed: Class is used as a subclass.
+
+0x000020CB
+
+ERROR_DS_EXISTS_IN_POSS_SUP
+
+
+Schema deletion failed: Class is used as a Poss-Superior.
+
+0x000020CC
+
+ERROR_DS_RECALCSCHEMA_FAILED
+
+
+Schema update failed in recalculating validation cache.
+
+0x000020CD
+
+ERROR_DS_TREE_DELETE_NOT_FINISHED
+
+
+The tree deletion is not finished. The request must be made again to continue deleting the tree.
+
+0x000020CE
+
+ERROR_DS_CANT_DELETE
+
+
+The requested delete operation could not be performed.
+
+0x000020CF
+
+ERROR_DS_ATT_SCHEMA_REQ_ID
+
+
+Cannot read the governs class identifier for the schema record.
+
+0x000020D0
+
+ERROR_DS_BAD_ATT_SCHEMA_SYNTAX
+
+
+The attribute schema has bad syntax.
+
+0x000020D1
+
+ERROR_DS_CANT_CACHE_ATT
+
+
+The attribute could not be cached.
+
+0x000020D2
+
+ERROR_DS_CANT_CACHE_CLASS
+
+
+The class could not be cached.
+
+0x000020D3
+
+ERROR_DS_CANT_REMOVE_ATT_CACHE
+
+
+The attribute could not be removed from the cache.
+
+0x000020D4
+
+ERROR_DS_CANT_REMOVE_CLASS_CACHE
+
+
+The class could not be removed from the cache.
+
+0x000020D5
+
+ERROR_DS_CANT_RETRIEVE_DN
+
+
+The distinguished name attribute could not be read.
+
+0x000020D6
+
+ERROR_DS_MISSING_SUPREF
+
+
+No superior reference has been configured for the directory service. The directory service is, therefore, unable to issue referrals to objects outside this forest.
+
+0x000020D7
+
+ERROR_DS_CANT_RETRIEVE_INSTANCE
+
+
+The instance type attribute could not be retrieved.
+
+0x000020D8
+
+ERROR_DS_CODE_INCONSISTENCY
+
+
+An internal error has occurred.
+
+0x000020D9
+
+ERROR_DS_DATABASE_ERROR
+
+
+A database error has occurred.
+
+0x000020DA
+
+ERROR_DS_GOVERNSID_MISSING
+
+
+The governsID attribute is missing.
+
+0x000020DB
+
+ERROR_DS_MISSING_EXPECTED_ATT
+
+
+An expected attribute is missing.
+
+0x000020DC
+
+ERROR_DS_NCNAME_MISSING_CR_REF
+
+
+The specified naming context is missing a cross-reference.
+
+0x000020DD
+
+ERROR_DS_SECURITY_CHECKING_ERROR
+
+
+A security checking error has occurred.
+
+0x000020DE
+
+ERROR_DS_SCHEMA_NOT_LOADED
+
+
+The schema is not loaded.
+
+0x000020DF
+
+ERROR_DS_SCHEMA_ALLOC_FAILED
+
+
+Schema allocation failed. Check if the machine is running low on memory.
+
+0x000020E0
+
+ERROR_DS_ATT_SCHEMA_REQ_SYNTAX
+
+
+Failed to obtain the required syntax for the attribute schema.
+
+0x000020E1
+
+ERROR_DS_GCVERIFY_ERROR
+
+
+The GC verification failed. The GC is not available or does not support the operation. Some part of the directory is currently not available.
+
+0x000020E2
+
+ERROR_DS_DRA_SCHEMA_MISMATCH
+
+
+The replication operation failed because of a schema mismatch between the servers involved.
+
+0x000020E3
+
+ERROR_DS_CANT_FIND_DSA_OBJ
+
+
+The DSA object could not be found.
+
+0x000020E4
+
+ERROR_DS_CANT_FIND_EXPECTED_NC
+
+
+The naming context could not be found.
+
+0x000020E5
+
+ERROR_DS_CANT_FIND_NC_IN_CACHE
+
+
+The naming context could not be found in the cache.
+
+0x000020E6
+
+ERROR_DS_CANT_RETRIEVE_CHILD
+
+
+The child object could not be retrieved.
+
+0x000020E7
+
+ERROR_DS_SECURITY_ILLEGAL_MODIFY
+
+
+The modification was not permitted for security reasons.
+
+0x000020E8
+
+ERROR_DS_CANT_REPLACE_HIDDEN_REC
+
+
+The operation cannot replace the hidden record.
+
+0x000020E9
+
+ERROR_DS_BAD_HIERARCHY_FILE
+
+
+The hierarchy file is invalid.
+
+0x000020EA
+
+ERROR_DS_BUILD_HIERARCHY_TABLE_FAILED
+
+
+The attempt to build the hierarchy table failed.
+
+0x000020EB
+
+ERROR_DS_CONFIG_PARAM_MISSING
+
+
+The directory configuration parameter is missing from the registry.
+
+0x000020EC
+
+ERROR_DS_COUNTING_AB_INDICES_FAILED
+
+
+The attempt to count the address book indices failed.
+
+0x000020ED
+
+ERROR_DS_HIERARCHY_TABLE_MALLOC_FAILED
+
+
+The allocation of the hierarchy table failed.
+
+0x000020EE
+
+ERROR_DS_INTERNAL_FAILURE
+
+
+The directory service encountered an internal failure.
+
+0x000020EF
+
+ERROR_DS_UNKNOWN_ERROR
+
+
+The directory service encountered an unknown failure.
+
+0x000020F0
+
+ERROR_DS_ROOT_REQUIRES_CLASS_TOP
+
+
+A root object requires a class of "top".
+
+0x000020F1
+
+ERROR_DS_REFUSING_FSMO_ROLES
+
+
+This directory server is shutting down, and cannot take ownership of new floating single-master operation roles.
+
+0x000020F2
+
+ERROR_DS_MISSING_FSMO_SETTINGS
+
+
+The directory service is missing mandatory configuration information and is unable to determine the ownership of floating single-master operation roles.
+
+0x000020F3
+
+ERROR_DS_UNABLE_TO_SURRENDER_ROLES
+
+
+The directory service was unable to transfer ownership of one or more floating single-master operation roles to other servers.
+
+0x000020F4
+
+ERROR_DS_DRA_GENERIC
+
+
+The replication operation failed.
+
+0x000020F5
+
+ERROR_DS_DRA_INVALID_PARAMETER
+
+
+An invalid parameter was specified for this replication operation.
+
+0x000020F6
+
+ERROR_DS_DRA_BUSY
+
+
+The directory service is too busy to complete the replication operation at this time.
+
+0x000020F7
+
+ERROR_DS_DRA_BAD_DN
+
+
+The DN specified for this replication operation is invalid.
+
+0x000020F8
+
+ERROR_DS_DRA_BAD_NC
+
+
+The naming context specified for this replication operation is invalid.
+
+0x000020F9
+
+ERROR_DS_DRA_DN_EXISTS
+
+
+The DN specified for this replication operation already exists.
+
+0x000020FA
+
+ERROR_DS_DRA_INTERNAL_ERROR
+
+
+The replication system encountered an internal error.
+
+0x000020FB
+
+ERROR_DS_DRA_INCONSISTENT_DIT
+
+
+The replication operation encountered a database inconsistency.
+
+0x000020FC
+
+ERROR_DS_DRA_CONNECTION_FAILED
+
+
+The server specified for this replication operation could not be contacted.
+
+0x000020FD
+
+ERROR_DS_DRA_BAD_INSTANCE_TYPE
+
+
+The replication operation encountered an object with an invalid instance type.
+
+0x000020FE
+
+ERROR_DS_DRA_OUT_OF_MEM
+
+
+The replication operation failed to allocate memory.
+
+0x000020FF
+
+ERROR_DS_DRA_MAIL_PROBLEM
+
+
+The replication operation encountered an error with the mail system.
+
+0x00002100
+
+ERROR_DS_DRA_REF_ALREADY_EXISTS
+
+
+The replication reference information for the target server already exists.
+
+0x00002101
+
+ERROR_DS_DRA_REF_NOT_FOUND
+
+
+The replication reference information for the target server does not exist.
+
+0x00002102
+
+ERROR_DS_DRA_OBJ_IS_REP_SOURCE
+
+
+The naming context cannot be removed because it is replicated to another server.
+
+0x00002103
+
+ERROR_DS_DRA_DB_ERROR
+
+
+The replication operation encountered a database error.
+
+0x00002104
+
+ERROR_DS_DRA_NO_REPLICA
+
+
+The naming context is in the process of being removed or is not replicated from the specified server.
+
+0x00002105
+
+ERROR_DS_DRA_ACCESS_DENIED
+
+
+Replication access was denied.
+
+0x00002106
+
+ERROR_DS_DRA_NOT_SUPPORTED
+
+
+The requested operation is not supported by this version of the directory service.
+
+0x00002107
+
+ERROR_DS_DRA_RPC_CANCELLED
+
+
+The replication RPC was canceled.
+
+0x00002108
+
+ERROR_DS_DRA_SOURCE_DISABLED
+
+
+The source server is currently rejecting replication requests.
+
+0x00002109
+
+ERROR_DS_DRA_SINK_DISABLED
+
+
+The destination server is currently rejecting replication requests.
+
+0x0000210A
+
+ERROR_DS_DRA_NAME_COLLISION
+
+
+The replication operation failed due to a collision of object names.
+
+0x0000210B
+
+ERROR_DS_DRA_SOURCE_REINSTALLED
+
+
+The replication source has been reinstalled.
+
+0x0000210C
+
+ERROR_DS_DRA_MISSING_PARENT
+
+
+The replication operation failed because a required parent object is missing.
+
+0x0000210D
+
+ERROR_DS_DRA_PREEMPTED
+
+
+The replication operation was preempted.
+
+0x0000210E
+
+ERROR_DS_DRA_ABANDON_SYNC
+
+
+The replication synchronization attempt was abandoned because of a lack of updates.
+
+0x0000210F
+
+ERROR_DS_DRA_SHUTDOWN
+
+
+The replication operation was terminated because the system is shutting down.
+
+0x00002110
+
+ERROR_DS_DRA_INCOMPATIBLE_PARTIAL_SET
+
+
+A synchronization attempt failed because the destination DC is currently waiting to synchronize new partial attributes from the source. This condition is normal if a recent schema change modified the partial attribute set. The destination partial attribute set is not a subset of the source partial attribute set.
+
+0x00002111
+
+ERROR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA
+
+
+The replication synchronization attempt failed because a master replica attempted to sync from a partial replica.
+
+0x00002112
+
+ERROR_DS_DRA_EXTN_CONNECTION_FAILED
+
+
+The server specified for this replication operation was contacted, but that server was unable to contact an additional server needed to complete the operation.
+
+0x00002113
+
+ERROR_DS_INSTALL_SCHEMA_MISMATCH
+
+
+The version of the directory service schema of the source forest is not compatible with the version of the directory service on this computer.
+
+0x00002114
+
+ERROR_DS_DUP_LINK_ID
+
+
+Schema update failed: An attribute with the same link identifier already exists.
+
+0x00002115
+
+ERROR_DS_NAME_ERROR_RESOLVING
+
+
+Name translation: Generic processing error.
+
+0x00002116
+
+ERROR_DS_NAME_ERROR_NOT_FOUND
+
+
+Name translation: Could not find the name or insufficient right to see name.
+
+0x00002117
+
+ERROR_DS_NAME_ERROR_NOT_UNIQUE
+
+
+Name translation: Input name mapped to more than one output name.
+
+0x00002118
+
+ERROR_DS_NAME_ERROR_NO_MAPPING
+
+
+Name translation: The input name was found but not the associated output format.
+
+0x00002119
+
+ERROR_DS_NAME_ERROR_DOMAIN_ONLY
+
+
+Name translation: Unable to resolve completely, only the domain was found.
+
+0x0000211A
+
+ERROR_DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING
+
+
+Name translation: Unable to perform purely syntactical mapping at the client without going out to the wire.
+
+0x0000211B
+
+ERROR_DS_CONSTRUCTED_ATT_MOD
+
+
+Modification of a constructed attribute is not allowed.
+
+0x0000211C
+
+ERROR_DS_WRONG_OM_OBJ_CLASS
+
+
+The OM-Object-Class specified is incorrect for an attribute with the specified syntax.
+
+0x0000211D
+
+ERROR_DS_DRA_REPL_PENDING
+
+
+The replication request has been posted; waiting for a reply.
+
+0x0000211E
+
+ERROR_DS_DS_REQUIRED
+
+
+The requested operation requires a directory service, and none was available.
+
+0x0000211F
+
+ERROR_DS_INVALID_LDAP_DISPLAY_NAME
+
+
+The LDAP display name of the class or attribute contains non-ASCII characters.
+
+0x00002120
+
+ERROR_DS_NON_BASE_SEARCH
+
+
+The requested search operation is only supported for base searches.
+
+0x00002121
+
+ERROR_DS_CANT_RETRIEVE_ATTS
+
+
+The search failed to retrieve attributes from the database.
+
+0x00002122
+
+ERROR_DS_BACKLINK_WITHOUT_LINK
+
+
+The schema update operation tried to add a backward link attribute that has no corresponding forward link.
+
+0x00002123
+
+ERROR_DS_EPOCH_MISMATCH
+
+
+The source and destination of a cross-domain move do not agree on the object's epoch number. Either the source or the destination does not have the latest version of the object.
+
+0x00002124
+
+ERROR_DS_SRC_NAME_MISMATCH
+
+
+The source and destination of a cross-domain move do not agree on the object's current name. Either the source or the destination does not have the latest version of the object.
+
+0x00002125
+
+ERROR_DS_SRC_AND_DST_NC_IDENTICAL
+
+
+The source and destination for the cross-domain move operation are identical. The caller should use a local move operation instead of a cross-domain move operation.
+
+0x00002126
+
+ERROR_DS_DST_NC_MISMATCH
+
+
+The source and destination for a cross-domain move do not agree on the naming contexts in the forest. Either the source or the destination does not have the latest version of the Partitions container.
+
+0x00002127
+
+ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC
+
+
+The destination of a cross-domain move is not authoritative for the destination naming context.
+
+0x00002128
+
+ERROR_DS_SRC_GUID_MISMATCH
+
+
+The source and destination of a cross-domain move do not agree on the identity of the source object. Either the source or the destination does not have the latest version of the source object.
+
+0x00002129
+
+ERROR_DS_CANT_MOVE_DELETED_OBJECT
+
+
+The object being moved across domains is already known to be deleted by the destination server. The source server does not have the latest version of the source object.
+
+0x0000212A
+
+ERROR_DS_PDC_OPERATION_IN_PROGRESS
+
+
+Another operation that requires exclusive access to the PDC FSMO is already in progress.
+
+0x0000212B
+
+ERROR_DS_CROSS_DOMAIN_CLEANUP_REQD
+
+
+A cross-domain move operation failed because two versions of the moved object exist—one each in the source and destination domains. The destination object needs to be removed to restore the system to a consistent state.
+
+0x0000212C
+
+ERROR_DS_ILLEGAL_XDOM_MOVE_OPERATION
+
+
+This object cannot be moved across domain boundaries either because cross-domain moves for this class are not allowed, or the object has some special characteristics, for example, a trust account or a restricted relative identifier (RID), that prevent its move.
+
+0x0000212D
+
+ERROR_DS_CANT_WITH_ACCT_GROUP_MEMBERSHPS
+
+
+Cannot move objects with memberships across domain boundaries because, once moved, this violates the membership conditions of the account group. Remove the object from any account group memberships and retry.
+
+0x0000212E
+
+ERROR_DS_NC_MUST_HAVE_NC_PARENT
+
+
+A naming context head must be the immediate child of another naming context head, not of an interior node.
+
+0x0000212F
+
+ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE
+
+
+The directory cannot validate the proposed naming context name because it does not hold a replica of the naming context above the proposed naming context. Ensure that the domain naming master role is held by a server that is configured as a GC server, and that the server is up-to-date with its replication partners. (Applies only to Windows 2000 operating system domain naming masters.)
+
+0x00002130
+
+ERROR_DS_DST_DOMAIN_NOT_NATIVE
+
+
+Destination domain must be in native mode.
+
+0x00002131
+
+ERROR_DS_MISSING_INFRASTRUCTURE_CONTAINER
+
+
+The operation cannot be performed because the server does not have an infrastructure container in the domain of interest.
+
+0x00002132
+
+ERROR_DS_CANT_MOVE_ACCOUNT_GROUP
+
+
+Cross-domain moves of nonempty account groups is not allowed.
+
+0x00002133
+
+ERROR_DS_CANT_MOVE_RESOURCE_GROUP
+
+
+Cross-domain moves of nonempty resource groups is not allowed.
+
+0x00002134
+
+ERROR_DS_INVALID_SEARCH_FLAG
+
+
+The search flags for the attribute are invalid. The ambiguous name resolution (ANR) bit is valid only on attributes of Unicode or Teletex strings.
+
+0x00002135
+
+ERROR_DS_NO_TREE_DELETE_ABOVE_NC
+
+
+Tree deletions starting at an object that has an NC head as a descendant are not allowed.
+
+0x00002136
+
+ERROR_DS_COULDNT_LOCK_TREE_FOR_DELETE
+
+
+The directory service failed to lock a tree in preparation for a tree deletion because the tree was in use.
+
+0x00002137
+
+ERROR_DS_COULDNT_IDENTIFY_OBJECTS_FOR_TREE_DELETE
+
+
+The directory service failed to identify the list of objects to delete while attempting a tree deletion.
+
+0x00002138
+
+ERROR_DS_SAM_INIT_FAILURE
+
+
+SAM initialization failed because of the following error: %1. Error Status: 0x%2. Click OK to shut down the system and reboot into Directory Services Restore Mode. Check the event log for detailed information.
+
+0x00002139
+
+ERROR_DS_SENSITIVE_GROUP_VIOLATION
+
+
+Only an administrator can modify the membership list of an administrative group.
+
+0x0000213A
+
+ERROR_DS_CANT_MOD_PRIMARYGROUPID
+
+
+Cannot change the primary group ID of a domain controller account.
+
+0x0000213B
+
+ERROR_DS_ILLEGAL_BASE_SCHEMA_MOD
+
+
+An attempt was made to modify the base schema.
+
+0x0000213C
+
+ERROR_DS_NONSAFE_SCHEMA_CHANGE
+
+
+Adding a new mandatory attribute to an existing class, deleting a mandatory attribute from an existing class, or adding an optional attribute to the special class Top that is not a backlink attribute (directly or through inheritance, for example, by adding or deleting an auxiliary class) is not allowed.
+
+0x0000213D
+
+ERROR_DS_SCHEMA_UPDATE_DISALLOWED
+
+
+Schema update is not allowed on this DC because the DC is not the schema FSMO role owner.
+
+0x0000213E
+
+ERROR_DS_CANT_CREATE_UNDER_SCHEMA
+
+
+An object of this class cannot be created under the schema container. You can only create Attribute-Schema and Class-Schema objects under the schema container.
+
+0x0000213F
+
+ERROR_DS_INSTALL_NO_SRC_SCH_VERSION
+
+
+The replica or child install failed to get the objectVersion attribute on the schema container on the source DC. Either the attribute is missing on the schema container or the credentials supplied do not have permission to read it.
+
+0x00002140
+
+ERROR_DS_INSTALL_NO_SCH_VERSION_IN_INIFILE
+
+
+The replica or child install failed to read the objectVersion attribute in the SCHEMA section of the file schema.ini in the System32 directory.
+
+0x00002141
+
+ERROR_DS_INVALID_GROUP_TYPE
+
+
+The specified group type is invalid.
+
+0x00002142
+
+ERROR_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN
+
+
+You cannot nest global groups in a mixed domain if the group is security-enabled.
+
+0x00002143
+
+ERROR_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN
+
+
+You cannot nest local groups in a mixed domain if the group is security-enabled.
+
+0x00002144
+
+ERROR_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER
+
+
+A global group cannot have a local group as a member.
+
+0x00002145
+
+ERROR_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER
+
+
+A global group cannot have a universal group as a member.
+
+0x00002146
+
+ERROR_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER
+
+
+A universal group cannot have a local group as a member.
+
+0x00002147
+
+ERROR_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER
+
+
+A global group cannot have a cross-domain member.
+
+0x00002148
+
+ERROR_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER
+
+
+A local group cannot have another cross domain local group as a member.
+
+0x00002149
+
+ERROR_DS_HAVE_PRIMARY_MEMBERS
+
+
+A group with primary members cannot change to a security-disabled group.
+
+0x0000214A
+
+ERROR_DS_STRING_SD_CONVERSION_FAILED
+
+
+The schema cache load failed to convert the string default security descriptor (SD) on a class-schema object.
+
+0x0000214B
+
+ERROR_DS_NAMING_MASTER_GC
+
+
+Only DSAs configured to be GC servers should be allowed to hold the domain naming master FSMO role. (Applies only to Windows 2000 servers.)
+
+0x0000214C
+
+ERROR_DS_DNS_LOOKUP_FAILURE
+
+
+The DSA operation is unable to proceed because of a DNS lookup failure.
+
+0x0000214D
+
+ERROR_DS_COULDNT_UPDATE_SPNS
+
+
+While processing a change to the DNS host name for an object, the SPN values could not be kept in sync.
+
+0x0000214E
+
+ERROR_DS_CANT_RETRIEVE_SD
+
+
+The Security Descriptor attribute could not be read.
+
+0x0000214F
+
+ERROR_DS_KEY_NOT_UNIQUE
+
+
+The object requested was not found, but an object with that key was found.
+
+0x00002150
+
+ERROR_DS_WRONG_LINKED_ATT_SYNTAX
+
+
+The syntax of the linked attribute being added is incorrect. Forward links can only have syntax 2.5.5.1, 2.5.5.7, and 2.5.5.14, and backlinks can only have syntax 2.5.5.1.
+
+0x00002151
+
+ERROR_DS_SAM_NEED_BOOTKEY_PASSWORD
+
+
+SAM needs to get the boot password.
+
+0x00002152
+
+ERROR_DS_SAM_NEED_BOOTKEY_FLOPPY
+
+
+SAM needs to get the boot key from the floppy disk.
+
+0x00002153
+
+ERROR_DS_CANT_START
+
+
+Directory Service cannot start.
+
+0x00002154
+
+ERROR_DS_INIT_FAILURE
+
+
+Directory Services could not start.
+
+0x00002155
+
+ERROR_DS_NO_PKT_PRIVACY_ON_CONNECTION
+
+
+The connection between client and server requires packet privacy or better.
+
+0x00002156
+
+ERROR_DS_SOURCE_DOMAIN_IN_FOREST
+
+
+The source domain cannot be in the same forest as the destination.
+
+0x00002157
+
+ERROR_DS_DESTINATION_DOMAIN_NOT_IN_FOREST
+
+
+The destination domain MUST be in the forest.
+
+0x00002158
+
+ERROR_DS_DESTINATION_AUDITING_NOT_ENABLED
+
+
+The operation requires that destination domain auditing be enabled.
+
+0x00002159
+
+ERROR_DS_CANT_FIND_DC_FOR_SRC_DOMAIN
+
+
+The operation could not locate a DC for the source domain.
+
+0x0000215A
+
+ERROR_DS_SRC_OBJ_NOT_GROUP_OR_USER
+
+
+The source object must be a group or user.
+
+0x0000215B
+
+ERROR_DS_SRC_SID_EXISTS_IN_FOREST
+
+
+The source object's SID already exists in the destination forest.
+
+0x0000215C
+
+ERROR_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH
+
+
+The source and destination object must be of the same type.
+
+0x0000215D
+
+ERROR_SAM_INIT_FAILURE
+
+
+SAM initialization failed because of the following error: %1. Error Status: 0x%2. Click OK to shut down the system and reboot into Safe Mode. Check the event log for detailed information.
+
+0x0000215E
+
+ERROR_DS_DRA_SCHEMA_INFO_SHIP
+
+
+Schema information could not be included in the replication request.
+
+0x0000215F
+
+ERROR_DS_DRA_SCHEMA_CONFLICT
+
+
+The replication operation could not be completed due to a schema incompatibility.
+
+0x00002160
+
+ERROR_DS_DRA_EARLIER_SCHEMA_CONFLICT
+
+
+The replication operation could not be completed due to a previous schema incompatibility.
+
+0x00002161
+
+ERROR_DS_DRA_OBJ_NC_MISMATCH
+
+
+The replication update could not be applied because either the source or the destination has not yet received information regarding a recent cross-domain move operation.
+
+0x00002162
+
+ERROR_DS_NC_STILL_HAS_DSAS
+
+
+The requested domain could not be deleted because there exist domain controllers that still host this domain.
+
+0x00002163
+
+ERROR_DS_GC_REQUIRED
+
+
+The requested operation can be performed only on a GC server.
+
+0x00002164
+
+ERROR_DS_LOCAL_MEMBER_OF_LOCAL_ONLY
+
+
+A local group can only be a member of other local groups in the same domain.
+
+0x00002165
+
+ERROR_DS_NO_FPO_IN_UNIVERSAL_GROUPS
+
+
+Foreign security principals cannot be members of universal groups.
+
+0x00002166
+
+ERROR_DS_CANT_ADD_TO_GC
+
+
+The attribute is not allowed to be replicated to the GC because of security reasons.
+
+0x00002167
+
+ERROR_DS_NO_CHECKPOINT_WITH_PDC
+
+
+The checkpoint with the PDC could not be taken because too many modifications are currently being processed.
+
+0x00002168
+
+ERROR_DS_SOURCE_AUDITING_NOT_ENABLED
+
+
+The operation requires that source domain auditing be enabled.
+
+0x00002169
+
+ERROR_DS_CANT_CREATE_IN_NONDOMAIN_NC
+
+
+Security principal objects can only be created inside domain naming contexts.
+
+0x0000216A
+
+ERROR_DS_INVALID_NAME_FOR_SPN
+
+
+An SPN could not be constructed because the provided host name is not in the necessary format.
+
+0x0000216B
+
+ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS
+
+
+A filter was passed that uses constructed attributes.
+
+0x0000216C
+
+ERROR_DS_UNICODEPWD_NOT_IN_QUOTES
+
+
+The unicodePwd attribute value must be enclosed in quotation marks.
+
+0x0000216D
+
+ERROR_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED
+
+
+Your computer could not be joined to the domain. You have exceeded the maximum number of computer accounts you are allowed to create in this domain. Contact your system administrator to have this limit reset or increased.
+
+0x0000216E
+
+ERROR_DS_MUST_BE_RUN_ON_DST_DC
+
+
+For security reasons, the operation must be run on the destination DC.
+
+0x0000216F
+
+ERROR_DS_SRC_DC_MUST_BE_SP4_OR_GREATER
+
+
+For security reasons, the source DC must be NT4SP4 or greater.
+
+0x00002170
+
+ERROR_DS_CANT_TREE_DELETE_CRITICAL_OBJ
+
+
+Critical directory service system objects cannot be deleted during tree deletion operations. The tree deletion might have been partially performed.
+
+0x00002171
+
+ERROR_DS_INIT_FAILURE_CONSOLE
+
+
+Directory Services could not start because of the following error: %1. Error Status: 0x%2. Click OK to shut down the system. You can use the Recovery Console to further diagnose the system.
+
+0x00002172
+
+ERROR_DS_SAM_INIT_FAILURE_CONSOLE
+
+
+SAM initialization failed because of the following error: %1. Error Status: 0x%2. Click OK to shut down the system. You can use the Recovery Console to further diagnose the system.
+
+0x00002173
+
+ERROR_DS_FOREST_VERSION_TOO_HIGH
+
+
+The version of the operating system installed is incompatible with the current forest functional level. You must upgrade to a new version of the operating system before this server can become a domain controller in this forest.
+
+0x00002174
+
+ERROR_DS_DOMAIN_VERSION_TOO_HIGH
+
+
+The version of the operating system installed is incompatible with the current domain functional level. You must upgrade to a new version of the operating system before this server can become a domain controller in this domain.
+
+0x00002175
+
+ERROR_DS_FOREST_VERSION_TOO_LOW
+
+
+The version of the operating system installed on this server no longer supports the current forest functional level. You must raise the forest functional level before this server can become a domain controller in this forest.
+
+0x00002176
+
+ERROR_DS_DOMAIN_VERSION_TOO_LOW
+
+
+The version of the operating system installed on this server no longer supports the current domain functional level. You must raise the domain functional level before this server can become a domain controller in this domain.
+
+0x00002177
+
+ERROR_DS_INCOMPATIBLE_VERSION
+
+
+The version of the operating system installed on this server is incompatible with the functional level of the domain or forest.
+
+0x00002178
+
+ERROR_DS_LOW_DSA_VERSION
+
+
+The functional level of the domain (or forest) cannot be raised to the requested value because one or more domain controllers in the domain (or forest) are at a lower, incompatible functional level.
+
+0x00002179
+
+ERROR_DS_NO_BEHAVIOR_VERSION_IN_MIXEDDOMAIN
+
+
+The forest functional level cannot be raised to the requested value because one or more domains are still in mixed-domain mode. All domains in the forest must be in native mode for you to raise the forest functional level.
+
+0x0000217A
+
+ERROR_DS_NOT_SUPPORTED_SORT_ORDER
+
+
+The sort order requested is not supported.
+
+0x0000217B
+
+ERROR_DS_NAME_NOT_UNIQUE
+
+
+The requested name already exists as a unique identifier.
+
+0x0000217C
+
+ERROR_DS_MACHINE_ACCOUNT_CREATED_PRENT4
+
+
+The machine account was created before Windows NT 4.0. The account needs to be re-created.
+
+0x0000217D
+
+ERROR_DS_OUT_OF_VERSION_STORE
+
+
+The database is out of version store.
+
+0x0000217E
+
+ERROR_DS_INCOMPATIBLE_CONTROLS_USED
+
+
+Unable to continue operation because multiple conflicting controls were used.
+
+0x0000217F
+
+ERROR_DS_NO_REF_DOMAIN
+
+
+Unable to find a valid security descriptor reference domain for this partition.
+
+0x00002180
+
+ERROR_DS_RESERVED_LINK_ID
+
+
+Schema update failed: The link identifier is reserved.
+
+0x00002181
+
+ERROR_DS_LINK_ID_NOT_AVAILABLE
+
+
+Schema update failed: There are no link identifiers available.
+
+0x00002182
+
+ERROR_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER
+
+
+An account group cannot have a universal group as a member.
+
+0x00002183
+
+ERROR_DS_MODIFYDN_DISALLOWED_BY_INSTANCE_TYPE
+
+
+Rename or move operations on naming context heads or read-only objects are not allowed.
+
+0x00002184
+
+ERROR_DS_NO_OBJECT_MOVE_IN_SCHEMA_NC
+
+
+Move operations on objects in the schema naming context are not allowed.
+
+0x00002185
+
+ERROR_DS_MODIFYDN_DISALLOWED_BY_FLAG
+
+
+A system flag has been set on the object that does not allow the object to be moved or renamed.
+
+0x00002186
+
+ERROR_DS_MODIFYDN_WRONG_GRANDPARENT
+
+
+This object is not allowed to change its grandparent container. Moves are not forbidden on this object, but are restricted to sibling containers.
+
+0x00002187
+
+ERROR_DS_NAME_ERROR_TRUST_REFERRAL
+
+
+Unable to resolve completely; a referral to another forest was generated.
+
+0x00002188
+
+ERROR_NOT_SUPPORTED_ON_STANDARD_SERVER
+
+
+The requested action is not supported on a standard server.
+
+0x00002189
+
+ERROR_DS_CANT_ACCESS_REMOTE_PART_OF_AD
+
+
+Could not access a partition of the directory service located on a remote server. Make sure at least one server is running for the partition in question.
+
+0x0000218A
+
+ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE_V2
+
+
+The directory cannot validate the proposed naming context (or partition) name because it does not hold a replica, nor can it contact a replica of the naming context above the proposed naming context. Ensure that the parent naming context is properly registered in the DNS, and at least one replica of this naming context is reachable by the domain naming master.
+
+0x0000218B
+
+ERROR_DS_THREAD_LIMIT_EXCEEDED
+
+
+The thread limit for this request was exceeded.
+
+0x0000218C
+
+ERROR_DS_NOT_CLOSEST
+
+
+The GC server is not in the closest site.
+
+0x0000218D
+
+ERROR_DS_CANT_DERIVE_SPN_WITHOUT_SERVER_REF
+
+
+The directory service cannot derive an SPN with which to mutually authenticate the target server because the corresponding server object in the local DS database has no serverReference attribute.
+
+0x0000218E
+
+ERROR_DS_SINGLE_USER_MODE_FAILED
+
+
+The directory service failed to enter single-user mode.
+
+0x0000218F
+
+ERROR_DS_NTDSCRIPT_SYNTAX_ERROR
+
+
+The directory service cannot parse the script because of a syntax error.
+
+0x00002190
+
+ERROR_DS_NTDSCRIPT_PROCESS_ERROR
+
+
+The directory service cannot process the script because of an error.
+
+0x00002191
+
+ERROR_DS_DIFFERENT_REPL_EPOCHS
+
+
+The directory service cannot perform the requested operation because the servers involved are of different replication epochs (which is usually related to a domain rename that is in progress).
+
+0x00002192
+
+ERROR_DS_DRS_EXTENSIONS_CHANGED
+
+
+The directory service binding must be renegotiated due to a change in the server extensions information.
+
+0x00002193
+
+ERROR_DS_REPLICA_SET_CHANGE_NOT_ALLOWED_ON_DISABLED_CR
+
+
+The operation is not allowed on a disabled cross-reference.
+
+0x00002194
+
+ERROR_DS_NO_MSDS_INTID
+
+
+Schema update failed: No values for msDS-IntId are available.
+
+0x00002195
+
+ERROR_DS_DUP_MSDS_INTID
+
+
+Schema update failed: Duplicate msDS-IntId. Retry the operation.
+
+0x00002196
+
+ERROR_DS_EXISTS_IN_RDNATTID
+
+
+Schema deletion failed: Attribute is used in rDNAttID.
+
+0x00002197
+
+ERROR_DS_AUTHORIZATION_FAILED
+
+
+The directory service failed to authorize the request.
+
+0x00002198
+
+ERROR_DS_INVALID_SCRIPT
+
+
+The directory service cannot process the script because it is invalid.
+
+0x00002199
+
+ERROR_DS_REMOTE_CROSSREF_OP_FAILED
+
+
+The remote create cross-reference operation failed on the domain naming master FSMO. The operation's error is in the extended data.
+
+0x0000219A
+
+ERROR_DS_CROSS_REF_BUSY
+
+
+A cross-reference is in use locally with the same name.
+
+0x0000219B
+
+ERROR_DS_CANT_DERIVE_SPN_FOR_DELETED_DOMAIN
+
+
+The directory service cannot derive an SPN with which to mutually authenticate the target server because the server's domain has been deleted from the forest.
+
+0x0000219C
+
+ERROR_DS_CANT_DEMOTE_WITH_WRITEABLE_NC
+
+
+Writable NCs prevent this DC from demoting.
+
+0x0000219D
+
+ERROR_DS_DUPLICATE_ID_FOUND
+
+
+The requested object has a nonunique identifier and cannot be retrieved.
+
+0x0000219E
+
+ERROR_DS_INSUFFICIENT_ATTR_TO_CREATE_OBJECT
+
+
+Insufficient attributes were given to create an object. This object might not exist because it might have been deleted and the garbage already collected.
+
+0x0000219F
+
+ERROR_DS_GROUP_CONVERSION_ERROR
+
+
+The group cannot be converted due to attribute restrictions on the requested group type.
+
+0x000021A0
+
+ERROR_DS_CANT_MOVE_APP_BASIC_GROUP
+
+
+Cross-domain moves of nonempty basic application groups is not allowed.
+
+0x000021A1
+
+ERROR_DS_CANT_MOVE_APP_QUERY_GROUP
+
+
+Cross-domain moves of nonempty query-based application groups is not allowed.
+
+0x000021A2
+
+ERROR_DS_ROLE_NOT_VERIFIED
+
+
+The FSMO role ownership could not be verified because its directory partition did not replicate successfully with at least one replication partner.
+
+0x000021A3
+
+ERROR_DS_WKO_CONTAINER_CANNOT_BE_SPECIAL
+
+
+The target container for a redirection of a well-known object container cannot already be a special container.
+
+0x000021A4
+
+ERROR_DS_DOMAIN_RENAME_IN_PROGRESS
+
+
+The directory service cannot perform the requested operation because a domain rename operation is in progress.
+
+0x000021A5
+
+ERROR_DS_EXISTING_AD_CHILD_NC
+
+
+The directory service detected a child partition below the requested partition name. The partition hierarchy must be created in a top down method.
+
+0x000021A6
+
+ERROR_DS_REPL_LIFETIME_EXCEEDED
+
+
+The directory service cannot replicate with this server because the time since the last replication with this server has exceeded the tombstone lifetime.
+
+0x000021A7
+
+ERROR_DS_DISALLOWED_IN_SYSTEM_CONTAINER
+
+
+The requested operation is not allowed on an object under the system container.
+
+0x000021A8
+
+ERROR_DS_LDAP_SEND_QUEUE_FULL
+
+
+The LDAP server's network send queue has filled up because the client is not processing the results of its requests fast enough. No more requests will be processed until the client catches up. If the client does not catch up then it will be disconnected.
+
+0x000021A9
+
+ERROR_DS_DRA_OUT_SCHEDULE_WINDOW
+
+
+The scheduled replication did not take place because the system was too busy to execute the request within the schedule window. The replication queue is overloaded. Consider reducing the number of partners or decreasing the scheduled replication frequency.
+
+0x000021AA
+
+ERROR_DS_POLICY_NOT_KNOWN
+
+
+At this time, it cannot be determined if the branch replication policy is available on the hub domain controller. Retry at a later time to account for replication latencies.
+
+0x000021AB
+
+ERROR_NO_SITE_SETTINGS_OBJECT
+
+
+The site settings object for the specified site does not exist.
+
+0x000021AC
+
+ERROR_NO_SECRETS
+
+
+The local account store does not contain secret material for the specified account.
+
+0x000021AD
+
+ERROR_NO_WRITABLE_DC_FOUND
+
+
+Could not find a writable domain controller in the domain.
+
+0x000021AE
+
+ERROR_DS_NO_SERVER_OBJECT
+
+
+The server object for the domain controller does not exist.
+
+0x000021AF
+
+ERROR_DS_NO_NTDSA_OBJECT
+
+
+The NTDS Settings object for the domain controller does not exist.
+
+0x000021B0
+
+ERROR_DS_NON_ASQ_SEARCH
+
+
+The requested search operation is not supported for attribute scoped query (ASQ) searches.
+
+0x000021B1
+
+ERROR_DS_AUDIT_FAILURE
+
+
+A required audit event could not be generated for the operation.
+
+0x000021B2
+
+ERROR_DS_INVALID_SEARCH_FLAG_SUBTREE
+
+
+The search flags for the attribute are invalid. The subtree index bit is valid only on single-valued attributes.
+
+0x000021B3
+
+ERROR_DS_INVALID_SEARCH_FLAG_TUPLE
+
+
+The search flags for the attribute are invalid. The tuple index bit is valid only on attributes of Unicode strings.
+
+0x000021BF
+
+ERROR_DS_DRA_RECYCLED_TARGET
+
+
+The replication operation failed because the target object referenced by a link value is recycled.
+
+0x000021C2
+
+ERROR_DS_HIGH_DSA_VERSION
+
+
+The functional level of the domain (or forest) cannot be lowered to the requested value.
+
+0x000021C7
+
+ERROR_DS_SPN_VALUE_NOT_UNIQUE_IN_FOREST
+
+
+The operation failed because the SPN value provided for addition/modification is not unique forest-wide.
+
+0x000021C8
+
+ERROR_DS_UPN_VALUE_NOT_UNIQUE_IN_FOREST
+
+
+The operation failed because the UPN value provided for addition/modification is not unique forest-wide.
+
+0x00002329
+
+DNS_ERROR_RCODE_FORMAT_ERROR
+
+
+DNS server unable to interpret format.
+
+0x0000232A
+
+DNS_ERROR_RCODE_SERVER_FAILURE
+
+
+DNS server failure.
+
+0x0000232B
+
+DNS_ERROR_RCODE_NAME_ERROR
+
+
+DNS name does not exist.
+
+0x0000232C
+
+DNS_ERROR_RCODE_NOT_IMPLEMENTED
+
+
+DNS request not supported by name server.
+
+0x0000232D
+
+DNS_ERROR_RCODE_REFUSED
+
+
+DNS operation refused.
+
+0x0000232E
+
+DNS_ERROR_RCODE_YXDOMAIN
+
+
+DNS name that should not exist, does exist.
+
+0x0000232F
+
+DNS_ERROR_RCODE_YXRRSET
+
+
+DNS resource record (RR) set that should not exist, does exist.
+
+0x00002330
+
+DNS_ERROR_RCODE_NXRRSET
+
+
+DNS RR set that should to exist, does not exist.
+
+0x00002331
+
+DNS_ERROR_RCODE_NOTAUTH
+
+
+DNS server not authoritative for zone.
+
+0x00002332
+
+DNS_ERROR_RCODE_NOTZONE
+
+
+DNS name in update or prereq is not in zone.
+
+0x00002338
+
+DNS_ERROR_RCODE_BADSIG
+
+
+DNS signature failed to verify.
+
+0x00002339
+
+DNS_ERROR_RCODE_BADKEY
+
+
+DNS bad key.
+
+0x0000233A
+
+DNS_ERROR_RCODE_BADTIME
+
+
+DNS signature validity expired.
+
+0x0000251D
+
+DNS_INFO_NO_RECORDS
+
+
+No records found for given DNS query.
+
+0x0000251E
+
+DNS_ERROR_BAD_PACKET
+
+
+Bad DNS packet.
+
+0x0000251F
+
+DNS_ERROR_NO_PACKET
+
+
+No DNS packet.
+
+0x00002520
+
+DNS_ERROR_RCODE
+
+
+DNS error, check rcode.
+
+0x00002521
+
+DNS_ERROR_UNSECURE_PACKET
+
+
+Unsecured DNS packet.
+
+0x0000254F
+
+DNS_ERROR_INVALID_TYPE
+
+
+Invalid DNS type.
+
+0x00002550
+
+DNS_ERROR_INVALID_IP_ADDRESS
+
+
+Invalid IP address.
+
+0x00002551
+
+DNS_ERROR_INVALID_PROPERTY
+
+
+Invalid property.
+
+0x00002552
+
+DNS_ERROR_TRY_AGAIN_LATER
+
+
+Try DNS operation again later.
+
+0x00002553
+
+DNS_ERROR_NOT_UNIQUE
+
+
+Record for given name and type is not unique.
+
+0x00002554
+
+DNS_ERROR_NON_RFC_NAME
+
+
+DNS name does not comply with RFC specifications.
+
+0x00002555
+
+DNS_STATUS_FQDN
+
+
+DNS name is a fully qualified DNS name.
+
+0x00002556
+
+DNS_STATUS_DOTTED_NAME
+
+
+DNS name is dotted (multilabel).
+
+0x00002557
+
+DNS_STATUS_SINGLE_PART_NAME
+
+
+DNS name is a single-part name.
+
+0x00002558
+
+DNS_ERROR_INVALID_NAME_CHAR
+
+
+DNS name contains an invalid character.
+
+0x00002559
+
+DNS_ERROR_NUMERIC_NAME
+
+
+DNS name is entirely numeric.
+
+0x0000255A
+
+DNS_ERROR_NOT_ALLOWED_ON_ROOT_SERVER
+
+
+The operation requested is not permitted on a DNS root server.
+
+0x0000255B
+
+DNS_ERROR_NOT_ALLOWED_UNDER_DELEGATION
+
+
+The record could not be created because this part of the DNS namespace has been delegated to another server.
+
+0x0000255C
+
+DNS_ERROR_CANNOT_FIND_ROOT_HINTS
+
+
+The DNS server could not find a set of root hints.
+
+0x0000255D
+
+DNS_ERROR_INCONSISTENT_ROOT_HINTS
+
+
+The DNS server found root hints but they were not consistent across all adapters.
+
+0x0000255E
+
+DNS_ERROR_DWORD_VALUE_TOO_SMALL
+
+
+The specified value is too small for this parameter.
+
+0x0000255F
+
+DNS_ERROR_DWORD_VALUE_TOO_LARGE
+
+
+The specified value is too large for this parameter.
+
+0x00002560
+
+DNS_ERROR_BACKGROUND_LOADING
+
+
+This operation is not allowed while the DNS server is loading zones in the background. Try again later.
+
+0x00002561
+
+DNS_ERROR_NOT_ALLOWED_ON_RODC
+
+
+The operation requested is not permitted on against a DNS server running on a read-only DC.
+
+0x00002581
+
+DNS_ERROR_ZONE_DOES_NOT_EXIST
+
+
+DNS zone does not exist.
+
+0x00002582
+
+DNS_ERROR_NO_ZONE_INFO
+
+
+DNS zone information not available.
+
+0x00002583
+
+DNS_ERROR_INVALID_ZONE_OPERATION
+
+
+Invalid operation for DNS zone.
+
+0x00002584
+
+DNS_ERROR_ZONE_CONFIGURATION_ERROR
+
+
+Invalid DNS zone configuration.
+
+0x00002585
+
+DNS_ERROR_ZONE_HAS_NO_SOA_RECORD
+
+
+DNS zone has no start of authority (SOA) record.
+
+0x00002586
+
+DNS_ERROR_ZONE_HAS_NO_NS_RECORDS
+
+
+DNS zone has no Name Server (NS) record.
+
+0x00002587
+
+DNS_ERROR_ZONE_LOCKED
+
+
+DNS zone is locked.
+
+0x00002588
+
+DNS_ERROR_ZONE_CREATION_FAILED
+
+
+DNS zone creation failed.
+
+0x00002589
+
+DNS_ERROR_ZONE_ALREADY_EXISTS
+
+
+DNS zone already exists.
+
+0x0000258A
+
+DNS_ERROR_AUTOZONE_ALREADY_EXISTS
+
+
+DNS automatic zone already exists.
+
+0x0000258B
+
+DNS_ERROR_INVALID_ZONE_TYPE
+
+
+Invalid DNS zone type.
+
+0x0000258C
+
+DNS_ERROR_SECONDARY_REQUIRES_MASTER_IP
+
+
+Secondary DNS zone requires master IP address.
+
+0x0000258D
+
+DNS_ERROR_ZONE_NOT_SECONDARY
+
+
+DNS zone not secondary.
+
+0x0000258E
+
+DNS_ERROR_NEED_SECONDARY_ADDRESSES
+
+
+Need secondary IP address.
+
+0x0000258F
+
+DNS_ERROR_WINS_INIT_FAILED
+
+
+WINS initialization failed.
+
+0x00002590
+
+DNS_ERROR_NEED_WINS_SERVERS
+
+
+Need WINS servers.
+
+0x00002591
+
+DNS_ERROR_NBSTAT_INIT_FAILED
+
+
+NBTSTAT initialization call failed.
+
+0x00002592
+
+DNS_ERROR_SOA_DELETE_INVALID
+
+
+Invalid delete of SOA.
+
+0x00002593
+
+DNS_ERROR_FORWARDER_ALREADY_EXISTS
+
+
+A conditional forwarding zone already exists for that name.
+
+0x00002594
+
+DNS_ERROR_ZONE_REQUIRES_MASTER_IP
+
+
+This zone must be configured with one or more master DNS server IP addresses.
+
+0x00002595
+
+DNS_ERROR_ZONE_IS_SHUTDOWN
+
+
+The operation cannot be performed because this zone is shut down.
+
+0x000025B3
+
+DNS_ERROR_PRIMARY_REQUIRES_DATAFILE
+
+
+The primary DNS zone requires a data file.
+
+0x000025B4
+
+DNS_ERROR_INVALID_DATAFILE_NAME
+
+
+Invalid data file name for the DNS zone.
+
+0x000025B5
+
+DNS_ERROR_DATAFILE_OPEN_FAILURE
+
+
+Failed to open the data file for the DNS zone.
+
+0x000025B6
+
+DNS_ERROR_FILE_WRITEBACK_FAILED
+
+
+Failed to write the data file for the DNS zone.
+
+0x000025B7
+
+DNS_ERROR_DATAFILE_PARSING
+
+
+Failure while reading datafile for DNS zone.
+
+0x000025E5
+
+DNS_ERROR_RECORD_DOES_NOT_EXIST
+
+
+DNS record does not exist.
+
+0x000025E6
+
+DNS_ERROR_RECORD_FORMAT
+
+
+DNS record format error.
+
+0x000025E7
+
+DNS_ERROR_NODE_CREATION_FAILED
+
+
+Node creation failure in DNS.
+
+0x000025E8
+
+DNS_ERROR_UNKNOWN_RECORD_TYPE
+
+
+Unknown DNS record type.
+
+0x000025E9
+
+DNS_ERROR_RECORD_TIMED_OUT
+
+
+DNS record timed out.
+
+0x000025EA
+
+DNS_ERROR_NAME_NOT_IN_ZONE
+
+
+Name not in DNS zone.
+
+0x000025EB
+
+DNS_ERROR_CNAME_LOOP
+
+
+CNAME loop detected.
+
+0x000025EC
+
+DNS_ERROR_NODE_IS_CNAME
+
+
+Node is a CNAME DNS record.
+
+0x000025ED
+
+DNS_ERROR_CNAME_COLLISION
+
+
+A CNAME record already exists for the given name.
+
+0x000025EE
+
+DNS_ERROR_RECORD_ONLY_AT_ZONE_ROOT
+
+
+Record is only at DNS zone root.
+
+0x000025EF
+
+DNS_ERROR_RECORD_ALREADY_EXISTS
+
+
+DNS record already exists.
+
+0x000025F0
+
+DNS_ERROR_SECONDARY_DATA
+
+
+Secondary DNS zone data error.
+
+0x000025F1
+
+DNS_ERROR_NO_CREATE_CACHE_DATA
+
+
+Could not create DNS cache data.
+
+0x000025F2
+
+DNS_ERROR_NAME_DOES_NOT_EXIST
+
+
+DNS name does not exist.
+
+0x000025F3
+
+DNS_WARNING_PTR_CREATE_FAILED
+
+
+Could not create pointer (PTR) record.
+
+0x000025F4
+
+DNS_WARNING_DOMAIN_UNDELETED
+
+
+DNS domain was undeleted.
+
+0x000025F5
+
+DNS_ERROR_DS_UNAVAILABLE
+
+
+The directory service is unavailable.
+
+0x000025F6
+
+DNS_ERROR_DS_ZONE_ALREADY_EXISTS
+
+
+DNS zone already exists in the directory service.
+
+0x000025F7
+
+DNS_ERROR_NO_BOOTFILE_IF_DS_ZONE
+
+
+DNS server not creating or reading the boot file for the directory service integrated DNS zone.
+
+0x00002617
+
+DNS_INFO_AXFR_COMPLETE
+
+
+DNS AXFR (zone transfer) complete.
+
+0x00002618
+
+DNS_ERROR_AXFR
+
+
+DNS zone transfer failed.
+
+0x00002619
+
+DNS_INFO_ADDED_LOCAL_WINS
+
+
+Added local WINS server.
+
+0x00002649
+
+DNS_STATUS_CONTINUE_NEEDED
+
+
+Secure update call needs to continue update request.
+
+0x0000267B
+
+DNS_ERROR_NO_TCPIP
+
+
+TCP/IP network protocol not installed.
+
+0x0000267C
+
+DNS_ERROR_NO_DNS_SERVERS
+
+
+No DNS servers configured for local system.
+
+0x000026AD
+
+DNS_ERROR_DP_DOES_NOT_EXIST
+
+
+The specified directory partition does not exist.
+
+0x000026AE
+
+DNS_ERROR_DP_ALREADY_EXISTS
+
+
+The specified directory partition already exists.
+
+0x000026AF
+
+DNS_ERROR_DP_NOT_ENLISTED
+
+
+This DNS server is not enlisted in the specified directory partition.
+
+0x000026B0
+
+DNS_ERROR_DP_ALREADY_ENLISTED
+
+
+This DNS server is already enlisted in the specified directory partition.
+
+0x000026B1
+
+DNS_ERROR_DP_NOT_AVAILABLE
+
+
+The directory partition is not available at this time. Wait a few minutes and try again.
+
+0x000026B2
+
+DNS_ERROR_DP_FSMO_ERROR
+
+
+The application directory partition operation failed. The domain controller holding the domain naming master role is down or unable to service the request or is not running Windows Server 2003.
+
+0x00002714
+
+WSAEINTR
+
+
+A blocking operation was interrupted by a call to WSACancelBlockingCall.
+
+0x00002719
+
+WSAEBADF
+
+
+The file handle supplied is not valid.
+
+0x0000271D
+
+WSAEACCES
+
+
+An attempt was made to access a socket in a way forbidden by its access permissions.
+
+0x0000271E
+
+WSAEFAULT
+
+
+The system detected an invalid pointer address in attempting to use a pointer argument in a call.
+
+0x00002726
+
+WSAEINVAL
+
+
+An invalid argument was supplied.
+
+0x00002728
+
+WSAEMFILE
+
+
+Too many open sockets.
+
+0x00002733
+
+WSAEWOULDBLOCK
+
+
+A nonblocking socket operation could not be completed immediately.
+
+0x00002734
+
+WSAEINPROGRESS
+
+
+A blocking operation is currently executing.
+
+0x00002735
+
+WSAEALREADY
+
+
+An operation was attempted on a nonblocking socket that already had an operation in progress.
+
+0x00002736
+
+WSAENOTSOCK
+
+
+An operation was attempted on something that is not a socket.
+
+0x00002737
+
+WSAEDESTADDRREQ
+
+
+A required address was omitted from an operation on a socket.
+
+0x00002738
+
+WSAEMSGSIZE
+
+
+A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram into was smaller than the datagram itself.
+
+0x00002739
+
+WSAEPROTOTYPE
+
+
+A protocol was specified in the socket function call that does not support the semantics of the socket type requested.
+
+0x0000273A
+
+WSAENOPROTOOPT
+
+
+An unknown, invalid, or unsupported option or level was specified in a getsockopt or setsockopt call.
+
+0x0000273B
+
+WSAEPROTONOSUPPORT
+
+
+The requested protocol has not been configured into the system, or no implementation for it exists.
+
+0x0000273C
+
+WSAESOCKTNOSUPPORT
+
+
+The support for the specified socket type does not exist in this address family.
+
+0x0000273D
+
+WSAEOPNOTSUPP
+
+
+The attempted operation is not supported for the type of object referenced.
+
+0x0000273E
+
+WSAEPFNOSUPPORT
+
+
+The protocol family has not been configured into the system or no implementation for it exists.
+
+0x0000273F
+
+WSAEAFNOSUPPORT
+
+
+An address incompatible with the requested protocol was used.
+
+0x00002740
+
+WSAEADDRINUSE
+
+
+Only one usage of each socket address (protocol/network address/port) is normally permitted.
+
+0x00002741
+
+WSAEADDRNOTAVAIL
+
+
+The requested address is not valid in its context.
+
+0x00002742
+
+WSAENETDOWN
+
+
+A socket operation encountered a dead network.
+
+0x00002743
+
+WSAENETUNREACH
+
+
+A socket operation was attempted to an unreachable network.
+
+0x00002744
+
+WSAENETRESET
+
+
+The connection has been broken due to keep-alive activity detecting a failure while the operation was in progress.
+
+0x00002745
+
+WSAECONNABORTED
+
+
+An established connection was aborted by the software in your host machine.
+
+0x00002746
+
+WSAECONNRESET
+
+
+An existing connection was forcibly closed by the remote host.
+
+0x00002747
+
+WSAENOBUFS
+
+
+An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.
+
+0x00002748
+
+WSAEISCONN
+
+
+A connect request was made on an already connected socket.
+
+0x00002749
+
+WSAENOTCONN
+
+
+A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied.
+
+0x0000274A
+
+WSAESHUTDOWN
+
+
+A request to send or receive data was disallowed because the socket had already been shut down in that direction with a previous shutdown call.
+
+0x0000274B
+
+WSAETOOMANYREFS
+
+
+Too many references to a kernel object.
+
+0x0000274C
+
+WSAETIMEDOUT
+
+
+A connection attempt failed because the connected party did not properly respond after a period of time, or the established connection failed because the connected host failed to respond.
+
+0x0000274D
+
+WSAECONNREFUSED
+
+
+No connection could be made because the target machine actively refused it.
+
+0x0000274E
+
+WSAELOOP
+
+
+Cannot translate name.
+
+0x0000274F
+
+WSAENAMETOOLONG
+
+
+Name or name component was too long.
+
+0x00002750
+
+WSAEHOSTDOWN
+
+
+A socket operation failed because the destination host was down.
+
+0x00002751
+
+WSAEHOSTUNREACH
+
+
+A socket operation was attempted to an unreachable host.
+
+0x00002752
+
+WSAENOTEMPTY
+
+
+Cannot remove a directory that is not empty.
+
+0x00002753
+
+WSAEPROCLIM
+
+
+A Windows Sockets implementation might have a limit on the number of applications that can use it simultaneously.
+
+0x00002754
+
+WSAEUSERS
+
+
+Ran out of quota.
+
+0x00002755
+
+WSAEDQUOT
+
+
+Ran out of disk quota.
+
+0x00002756
+
+WSAESTALE
+
+
+File handle reference is no longer available.
+
+0x00002757
+
+WSAEREMOTE
+
+
+Item is not available locally.
+
+0x0000276B
+
+WSASYSNOTREADY
+
+
+WSAStartup cannot function at this time because the underlying system it uses to provide network services is currently unavailable.
+
+0x0000276C
+
+WSAVERNOTSUPPORTED
+
+
+The Windows Sockets version requested is not supported.
+
+0x0000276D
+
+WSANOTINITIALISED
+
+
+Either the application has not called WSAStartup, or WSAStartup failed.
+
+0x00002775
+
+WSAEDISCON
+
+
+Returned by WSARecv or WSARecvFrom to indicate that the remote party has initiated a graceful shutdown sequence.
+
+0x00002776
+
+WSAENOMORE
+
+
+No more results can be returned by WSALookupServiceNext.
+
+0x00002777
+
+WSAECANCELLED
+
+
+A call to WSALookupServiceEnd was made while this call was still processing. The call has been canceled.
+
+0x00002778
+
+WSAEINVALIDPROCTABLE
+
+
+The procedure call table is invalid.
+
+0x00002779
+
+WSAEINVALIDPROVIDER
+
+
+The requested service provider is invalid.
+
+0x0000277A
+
+WSAEPROVIDERFAILEDINIT
+
+
+The requested service provider could not be loaded or initialized.
+
+0x0000277B
+
+WSASYSCALLFAILURE
+
+
+A system call that should never fail has failed.
+
+0x0000277C
+
+WSASERVICE_NOT_FOUND
+
+
+No such service is known. The service cannot be found in the specified namespace.
+
+0x0000277D
+
+WSATYPE_NOT_FOUND
+
+
+The specified class was not found.
+
+0x0000277E
+
+WSA_E_NO_MORE
+
+
+No more results can be returned by WSALookupServiceNext.
+
+0x0000277F
+
+WSA_E_CANCELLED
+
+
+A call to WSALookupServiceEnd was made while this call was still processing. The call has been canceled.
+
+0x00002780
+
+WSAEREFUSED
+
+
+A database query failed because it was actively refused.
+
+0x00002AF9
+
+WSAHOST_NOT_FOUND
+
+
+No such host is known.
+
+0x00002AFA
+
+WSATRY_AGAIN
+
+
+This is usually a temporary error during host name resolution and means that the local server did not receive a response from an authoritative server.
+
+0x00002AFB
+
+WSANO_RECOVERY
+
+
+A nonrecoverable error occurred during a database lookup.
+
+0x00002AFC
+
+WSANO_DATA
+
+
+The requested name is valid, but no data of the requested type was found.
+
+0x00002AFD
+
+WSA_QOS_RECEIVERS
+
+
+At least one reserve has arrived.
+
+0x00002AFE
+
+WSA_QOS_SENDERS
+
+
+At least one path has arrived.
+
+0x00002AFF
+
+WSA_QOS_NO_SENDERS
+
+
+There are no senders.
+
+0x00002B00
+
+WSA_QOS_NO_RECEIVERS
+
+
+There are no receivers.
+
+0x00002B01
+
+WSA_QOS_REQUEST_CONFIRMED
+
+
+Reserve has been confirmed.
+
+0x00002B02
+
+WSA_QOS_ADMISSION_FAILURE
+
+
+Error due to lack of resources.
+
+0x00002B03
+
+WSA_QOS_POLICY_FAILURE
+
+
+Rejected for administrative reasons—bad credentials.
+
+0x00002B04
+
+WSA_QOS_BAD_STYLE
+
+
+Unknown or conflicting style.
+
+0x00002B05
+
+WSA_QOS_BAD_OBJECT
+
+
+There is a problem with some part of the filterspec or provider-specific buffer in general.
+
+0x00002B06
+
+WSA_QOS_TRAFFIC_CTRL_ERROR
+
+
+There is a problem with some part of the flowspec.
+
+0x00002B07
+
+WSA_QOS_GENERIC_ERROR
+
+
+General quality of serve (QOS) error.
+
+0x00002B08
+
+WSA_QOS_ESERVICETYPE
+
+
+An invalid or unrecognized service type was found in the flowspec.
+
+0x00002B09
+
+WSA_QOS_EFLOWSPEC
+
+
+An invalid or inconsistent flowspec was found in the QOS structure.
+
+0x00002B0A
+
+WSA_QOS_EPROVSPECBUF
+
+
+Invalid QOS provider-specific buffer.
+
+0x00002B0B
+
+WSA_QOS_EFILTERSTYLE
+
+
+An invalid QOS filter style was used.
+
+0x00002B0C
+
+WSA_QOS_EFILTERTYPE
+
+
+An invalid QOS filter type was used.
+
+0x00002B0D
+
+WSA_QOS_EFILTERCOUNT
+
+
+An incorrect number of QOS FILTERSPECs were specified in the FLOWDESCRIPTOR.
+
+0x00002B0E
+
+WSA_QOS_EOBJLENGTH
+
+
+An object with an invalid ObjectLength field was specified in the QOS provider-specific buffer.
+
+0x00002B0F
+
+WSA_QOS_EFLOWCOUNT
+
+
+An incorrect number of flow descriptors was specified in the QOS structure.
+
+0x00002B10
+
+WSA_QOS_EUNKOWNPSOBJ
+
+
+An unrecognized object was found in the QOS provider-specific buffer.
+
+0x00002B11
+
+WSA_QOS_EPOLICYOBJ
+
+
+An invalid policy object was found in the QOS provider-specific buffer.
+
+0x00002B12
+
+WSA_QOS_EFLOWDESC
+
+
+An invalid QOS flow descriptor was found in the flow descriptor list.
+
+0x00002B13
+
+WSA_QOS_EPSFLOWSPEC
+
+
+An invalid or inconsistent flowspec was found in the QOS provider-specific buffer.
+
+0x00002B14
+
+WSA_QOS_EPSFILTERSPEC
+
+
+An invalid FILTERSPEC was found in the QOS provider-specific buffer.
+
+0x00002B15
+
+WSA_QOS_ESDMODEOBJ
+
+
+An invalid shape discard mode object was found in the QOS provider-specific buffer.
+
+0x00002B16
+
+WSA_QOS_ESHAPERATEOBJ
+
+
+An invalid shaping rate object was found in the QOS provider-specific buffer.
+
+0x00002B17
+
+WSA_QOS_RESERVED_PETYPE
+
+
+A reserved policy element was found in the QOS provider-specific buffer.
+
+0x000032C8
+
+ERROR_IPSEC_QM_POLICY_EXISTS
+
+
+The specified quick mode policy already exists.
+
+0x000032C9
+
+ERROR_IPSEC_QM_POLICY_NOT_FOUND
+
+
+The specified quick mode policy was not found.
+
+0x000032CA
+
+ERROR_IPSEC_QM_POLICY_IN_USE
+
+
+The specified quick mode policy is being used.
+
+0x000032CB
+
+ERROR_IPSEC_MM_POLICY_EXISTS
+
+
+The specified main mode policy already exists.
+
+0x000032CC
+
+ERROR_IPSEC_MM_POLICY_NOT_FOUND
+
+
+The specified main mode policy was not found.
+
+0x000032CD
+
+ERROR_IPSEC_MM_POLICY_IN_USE
+
+
+The specified main mode policy is being used.
+
+0x000032CE
+
+ERROR_IPSEC_MM_FILTER_EXISTS
+
+
+The specified main mode filter already exists.
+
+0x000032CF
+
+ERROR_IPSEC_MM_FILTER_NOT_FOUND
+
+
+The specified main mode filter was not found.
+
+0x000032D0
+
+ERROR_IPSEC_TRANSPORT_FILTER_EXISTS
+
+
+The specified transport mode filter already exists.
+
+0x000032D1
+
+ERROR_IPSEC_TRANSPORT_FILTER_NOT_FOUND
+
+
+The specified transport mode filter does not exist.
+
+0x000032D2
+
+ERROR_IPSEC_MM_AUTH_EXISTS
+
+
+The specified main mode authentication list exists.
+
+0x000032D3
+
+ERROR_IPSEC_MM_AUTH_NOT_FOUND
+
+
+The specified main mode authentication list was not found.
+
+0x000032D4
+
+ERROR_IPSEC_MM_AUTH_IN_USE
+
+
+The specified main mode authentication list is being used.
+
+0x000032D5
+
+ERROR_IPSEC_DEFAULT_MM_POLICY_NOT_FOUND
+
+
+The specified default main mode policy was not found.
+
+0x000032D6
+
+ERROR_IPSEC_DEFAULT_MM_AUTH_NOT_FOUND
+
+
+The specified default main mode authentication list was not found.
+
+0x000032D7
+
+ERROR_IPSEC_DEFAULT_QM_POLICY_NOT_FOUND
+
+
+The specified default quick mode policy was not found.
+
+0x000032D8
+
+ERROR_IPSEC_TUNNEL_FILTER_EXISTS
+
+
+The specified tunnel mode filter exists.
+
+0x000032D9
+
+ERROR_IPSEC_TUNNEL_FILTER_NOT_FOUND
+
+
+The specified tunnel mode filter was not found.
+
+0x000032DA
+
+ERROR_IPSEC_MM_FILTER_PENDING_DELETION
+
+
+The main mode filter is pending deletion.
+
+0x000032DB
+
+ERROR_IPSEC_TRANSPORT_FILTER_ENDING_DELETION
+
+
+The transport filter is pending deletion.
+
+0x000032DC
+
+ERROR_IPSEC_TUNNEL_FILTER_PENDING_DELETION
+
+
+The tunnel filter is pending deletion.
+
+0x000032DD
+
+ERROR_IPSEC_MM_POLICY_PENDING_ELETION
+
+
+The main mode policy is pending deletion.
+
+0x000032DE
+
+ERROR_IPSEC_MM_AUTH_PENDING_DELETION
+
+
+The main mode authentication bundle is pending deletion.
+
+0x000032DF
+
+ERROR_IPSEC_QM_POLICY_PENDING_DELETION
+
+
+The quick mode policy is pending deletion.
+
+0x000032E0
+
+WARNING_IPSEC_MM_POLICY_PRUNED
+
+
+The main mode policy was successfully added, but some of the requested offers are not supported.
+
+0x000032E1
+
+WARNING_IPSEC_QM_POLICY_PRUNED
+
+
+The quick mode policy was successfully added, but some of the requested offers are not supported.
+
+0x000035E8
+
+ERROR_IPSEC_IKE_NEG_STATUS_BEGIN
+
+
+Starts the list of frequencies of various IKE Win32 error codes encountered during negotiations.
+
+0x000035E9
+
+ERROR_IPSEC_IKE_AUTH_FAIL
+
+
+The IKE authentication credentials are unacceptable.
+
+0x000035EA
+
+ERROR_IPSEC_IKE_ATTRIB_FAIL
+
+
+The IKE security attributes are unacceptable.
+
+0x000035EB
+
+ERROR_IPSEC_IKE_NEGOTIATION_PENDING
+
+
+The IKE negotiation is in progress.
+
+0x000035EC
+
+ERROR_IPSEC_IKE_GENERAL_PROCESSING_ERROR
+
+
+General processing error.
+
+0x000035ED
+
+ERROR_IPSEC_IKE_TIMED_OUT
+
+
+Negotiation timed out.
+
+0x000035EE
+
+ERROR_IPSEC_IKE_NO_CERT
+
+
+The IKE failed to find a valid machine certificate. Contact your network security administrator about installing a valid certificate in the appropriate certificate store.
+
+0x000035EF
+
+ERROR_IPSEC_IKE_SA_DELETED
+
+
+The IKE security association (SA) was deleted by a peer before it was completely established.
+
+0x000035F0
+
+ERROR_IPSEC_IKE_SA_REAPED
+
+
+The IKE SA was deleted before it was completely established.
+
+0x000035F1
+
+ERROR_IPSEC_IKE_MM_ACQUIRE_DROP
+
+
+The negotiation request sat in the queue too long.
+
+0x000035F2
+
+ERROR_IPSEC_IKE_QM_ACQUIRE_DROP
+
+
+The negotiation request sat in the queue too long.
+
+0x000035F3
+
+ERROR_IPSEC_IKE_QUEUE_DROP_MM
+
+
+The negotiation request sat in the queue too long.
+
+0x000035F4
+
+ERROR_IPSEC_IKE_QUEUE_DROP_NO_MM
+
+
+The negotiation request sat in the queue too long.
+
+0x000035F5
+
+ERROR_IPSEC_IKE_DROP_NO_RESPONSE
+
+
+There was no response from a peer.
+
+0x000035F6
+
+ERROR_IPSEC_IKE_MM_DELAY_DROP
+
+
+The negotiation took too long.
+
+0x000035F7
+
+ERROR_IPSEC_IKE_QM_DELAY_DROP
+
+
+The negotiation took too long.
+
+0x000035F8
+
+ERROR_IPSEC_IKE_ERROR
+
+
+An unknown error occurred.
+
+0x000035F9
+
+ERROR_IPSEC_IKE_CRL_FAILED
+
+
+The certificate revocation check failed.
+
+0x000035FA
+
+ERROR_IPSEC_IKE_INVALID_KEY_USAGE
+
+
+Invalid certificate key usage.
+
+0x000035FB
+
+ERROR_IPSEC_IKE_INVALID_CERT_TYPE
+
+
+Invalid certificate type.
+
+0x000035FC
+
+ERROR_IPSEC_IKE_NO_PRIVATE_KEY
+
+
+The IKE negotiation failed because the machine certificate used does not have a private key. IPsec certificates require a private key. Contact your network security administrator about a certificate that has a private key.
+
+0x000035FE
+
+ERROR_IPSEC_IKE_DH_FAIL
+
+
+There was a failure in the Diffie-Hellman computation.
+
+0x00003600
+
+ERROR_IPSEC_IKE_INVALID_HEADER
+
+
+Invalid header.
+
+0x00003601
+
+ERROR_IPSEC_IKE_NO_POLICY
+
+
+No policy configured.
+
+0x00003602
+
+ERROR_IPSEC_IKE_INVALID_SIGNATURE
+
+
+Failed to verify signature.
+
+0x00003603
+
+ERROR_IPSEC_IKE_KERBEROS_ERROR
+
+
+Failed to authenticate using Kerberos.
+
+0x00003604
+
+ERROR_IPSEC_IKE_NO_PUBLIC_KEY
+
+
+The peer's certificate did not have a public key.
+
+0x00003605
+
+ERROR_IPSEC_IKE_PROCESS_ERR
+
+
+Error processing the error payload.
+
+0x00003606
+
+ERROR_IPSEC_IKE_PROCESS_ERR_SA
+
+
+Error processing the SA payload.
+
+0x00003607
+
+ERROR_IPSEC_IKE_PROCESS_ERR_PROP
+
+
+Error processing the proposal payload.
+
+0x00003608
+
+ERROR_IPSEC_IKE_PROCESS_ERR_TRANS
+
+
+Error processing the transform payload.
+
+0x00003609
+
+ERROR_IPSEC_IKE_PROCESS_ERR_KE
+
+
+Error processing the key exchange payload.
+
+0x0000360A
+
+ERROR_IPSEC_IKE_PROCESS_ERR_ID
+
+
+Error processing the ID payload.
+
+0x0000360B
+
+ERROR_IPSEC_IKE_PROCESS_ERR_CERT
+
+
+Error processing the certification payload.
+
+0x0000360C
+
+ERROR_IPSEC_IKE_PROCESS_ERR_CERT_REQ
+
+
+Error processing the certificate request payload.
+
+0x0000360D
+
+ERROR_IPSEC_IKE_PROCESS_ERR_HASH
+
+
+Error processing the hash payload.
+
+0x0000360E
+
+ERROR_IPSEC_IKE_PROCESS_ERR_SIG
+
+
+Error processing the signature payload.
+
+0x0000360F
+
+ERROR_IPSEC_IKE_PROCESS_ERR_NONCE
+
+
+Error processing the nonce payload.
+
+0x00003610
+
+ERROR_IPSEC_IKE_PROCESS_ERR_NOTIFY
+
+
+Error processing the notify payload.
+
+0x00003611
+
+ERROR_IPSEC_IKE_PROCESS_ERR_DELETE
+
+
+Error processing the delete payload.
+
+0x00003612
+
+ERROR_IPSEC_IKE_PROCESS_ERR_VENDOR
+
+
+Error processing the VendorId payload.
+
+0x00003613
+
+ERROR_IPSEC_IKE_INVALID_PAYLOAD
+
+
+Invalid payload received.
+
+0x00003614
+
+ERROR_IPSEC_IKE_LOAD_SOFT_SA
+
+
+Soft SA loaded.
+
+0x00003615
+
+ERROR_IPSEC_IKE_SOFT_SA_TORN_DOWN
+
+
+Soft SA torn down.
+
+0x00003616
+
+ERROR_IPSEC_IKE_INVALID_COOKIE
+
+
+Invalid cookie received.
+
+0x00003617
+
+ERROR_IPSEC_IKE_NO_PEER_CERT
+
+
+Peer failed to send valid machine certificate.
+
+0x00003618
+
+ERROR_IPSEC_IKE_PEER_CRL_FAILED
+
+
+Certification revocation check of peer's certificate failed.
+
+0x00003619
+
+ERROR_IPSEC_IKE_POLICY_CHANGE
+
+
+New policy invalidated SAs formed with the old policy.
+
+0x0000361A
+
+ERROR_IPSEC_IKE_NO_MM_POLICY
+
+
+There is no available main mode IKE policy.
+
+0x0000361B
+
+ERROR_IPSEC_IKE_NOTCBPRIV
+
+
+Failed to enabled trusted computer base (TCB) privilege.
+
+0x0000361C
+
+ERROR_IPSEC_IKE_SECLOADFAIL
+
+
+Failed to load SECURITY.DLL.
+
+0x0000361D
+
+ERROR_IPSEC_IKE_FAILSSPINIT
+
+
+Failed to obtain the security function table dispatch address from the SSPI.
+
+0x0000361E
+
+ERROR_IPSEC_IKE_FAILQUERYSSP
+
+
+Failed to query the Kerberos package to obtain the max token size.
+
+0x0000361F
+
+ERROR_IPSEC_IKE_SRVACQFAIL
+
+
+Failed to obtain the Kerberos server credentials for the Internet Security Association and Key Management Protocol (ISAKMP)/ERROR_IPSEC_IKE service. Kerberos authentication will not function. The most likely reason for this is lack of domain membership. This is normal if your computer is a member of a workgroup.
+
+0x00003620
+
+ERROR_IPSEC_IKE_SRVQUERYCRED
+
+
+Failed to determine the SSPI principal name for ISAKMP/ERROR_IPSEC_IKE service (QueryCredentialsAttributes).
+
+0x00003621
+
+ERROR_IPSEC_IKE_GETSPIFAIL
+
+
+Failed to obtain a new service provider interface (SPI) for the inbound SA from the IPsec driver. The most common cause for this is that the driver does not have the correct filter. Check your policy to verify the filters.
+
+0x00003622
+
+ERROR_IPSEC_IKE_INVALID_FILTER
+
+
+Given filter is invalid.
+
+0x00003623
+
+ERROR_IPSEC_IKE_OUT_OF_MEMORY
+
+
+Memory allocation failed.
+
+0x00003624
+
+ERROR_IPSEC_IKE_ADD_UPDATE_KEY_FAILED
+
+
+Failed to add an SA to the IPSec driver. The most common cause for this is if the IKE negotiation took too long to complete. If the problem persists, reduce the load on the faulting machine.
+
+0x00003625
+
+ERROR_IPSEC_IKE_INVALID_POLICY
+
+
+Invalid policy.
+
+0x00003626
+
+ERROR_IPSEC_IKE_UNKNOWN_DOI
+
+
+Invalid digital object identifier (DOI).
+
+0x00003627
+
+ERROR_IPSEC_IKE_INVALID_SITUATION
+
+
+Invalid situation.
+
+0x00003628
+
+ERROR_IPSEC_IKE_DH_FAILURE
+
+
+Diffie-Hellman failure.
+
+0x00003629
+
+ERROR_IPSEC_IKE_INVALID_GROUP
+
+
+Invalid Diffie-Hellman group.
+
+0x0000362A
+
+ERROR_IPSEC_IKE_ENCRYPT
+
+
+Error encrypting payload.
+
+0x0000362B
+
+ERROR_IPSEC_IKE_DECRYPT
+
+
+Error decrypting payload.
+
+0x0000362C
+
+ERROR_IPSEC_IKE_POLICY_MATCH
+
+
+Policy match error.
+
+0x0000362D
+
+ERROR_IPSEC_IKE_UNSUPPORTED_ID
+
+
+Unsupported ID.
+
+0x0000362E
+
+ERROR_IPSEC_IKE_INVALID_HASH
+
+
+Hash verification failed.
+
+0x0000362F
+
+ERROR_IPSEC_IKE_INVALID_HASH_ALG
+
+
+Invalid hash algorithm.
+
+0x00003630
+
+ERROR_IPSEC_IKE_INVALID_HASH_SIZE
+
+
+Invalid hash size.
+
+0x00003631
+
+ERROR_IPSEC_IKE_INVALID_ENCRYPT_ALG
+
+
+Invalid encryption algorithm.
+
+0x00003632
+
+ERROR_IPSEC_IKE_INVALID_AUTH_ALG
+
+
+Invalid authentication algorithm.
+
+0x00003633
+
+ERROR_IPSEC_IKE_INVALID_SIG
+
+
+Invalid certificate signature.
+
+0x00003634
+
+ERROR_IPSEC_IKE_LOAD_FAILED
+
+
+Load failed.
+
+0x00003635
+
+ERROR_IPSEC_IKE_RPC_DELETE
+
+
+Deleted by using an RPC call.
+
+0x00003636
+
+ERROR_IPSEC_IKE_BENIGN_REINIT
+
+
+A temporary state was created to perform reinitialization. This is not a real failure.
+
+0x00003637
+
+ERROR_IPSEC_IKE_INVALID_RESPONDER_LIFETIME_NOTIFY
+
+
+The lifetime value received in the Responder Lifetime Notify is below the Windows 2000 configured minimum value. Fix the policy on the peer machine.
+
+0x00003639
+
+ERROR_IPSEC_IKE_INVALID_CERT_KEYLEN
+
+
+Key length in the certificate is too small for configured security requirements.
+
+0x0000363A
+
+ERROR_IPSEC_IKE_MM_LIMIT
+
+
+Maximum number of established MM SAs to peer exceeded.
+
+0x0000363B
+
+ERROR_IPSEC_IKE_NEGOTIATION_DISABLED
+
+
+The IKE received a policy that disables negotiation.
+
+0x0000363C
+
+ERROR_IPSEC_IKE_QM_LIMIT
+
+
+Reached maximum quick mode limit for the main mode. New main mode will be started.
+
+0x0000363D
+
+ERROR_IPSEC_IKE_MM_EXPIRED
+
+
+Main mode SA lifetime expired or the peer sent a main mode delete.
+
+0x0000363E
+
+ERROR_IPSEC_IKE_PEER_MM_ASSUMED_INVALID
+
+
+Main mode SA assumed to be invalid because peer stopped responding.
+
+0x0000363F
+
+ERROR_IPSEC_IKE_CERT_CHAIN_POLICY_MISMATCH
+
+
+Certificate does not chain to a trusted root in IPsec policy.
+
+0x00003640
+
+ERROR_IPSEC_IKE_UNEXPECTED_MESSAGE_ID
+
+
+Received unexpected message ID.
+
+0x00003641
+
+ERROR_IPSEC_IKE_INVALID_UMATTS
+
+
+Received invalid AuthIP user mode attributes.
+
+0x00003642
+
+ERROR_IPSEC_IKE_DOS_COOKIE_SENT
+
+
+Sent DOS cookie notify to initiator.
+
+0x00003643
+
+ERROR_IPSEC_IKE_SHUTTING_DOWN
+
+
+The IKE service is shutting down.
+
+0x00003644
+
+ERROR_IPSEC_IKE_CGA_AUTH_FAILED
+
+
+Could not verify the binding between the color graphics adapter (CGA) address and the certificate.
+
+0x00003645
+
+ERROR_IPSEC_IKE_PROCESS_ERR_NATOA
+
+
+Error processing the NatOA payload.
+
+0x00003646
+
+ERROR_IPSEC_IKE_INVALID_MM_FOR_QM
+
+
+The parameters of the main mode are invalid for this quick mode.
+
+0x00003647
+
+ERROR_IPSEC_IKE_QM_EXPIRED
+
+
+The quick mode SA was expired by the IPsec driver.
+
+0x00003648
+
+ERROR_IPSEC_IKE_TOO_MANY_FILTERS
+
+
+Too many dynamically added IKEEXT filters were detected.
+
+0x00003649
+
+ERROR_IPSEC_IKE_NEG_STATUS_END
+
+
+Ends the list of frequencies of various IKE Win32 error codes encountered during negotiations.
+
+0x000036B0
+
+ERROR_SXS_SECTION_NOT_FOUND
+
+
+The requested section was not present in the activation context.
+
+0x000036B1
+
+ERROR_SXS_CANT_GEN_ACTCTX
+
+
+The application has failed to start because its side-by-side configuration is incorrect. See the application event log for more detail.
+
+0x000036B2
+
+ERROR_SXS_INVALID_ACTCTXDATA_FORMAT
+
+
+The application binding data format is invalid.
+
+0x000036B3
+
+ERROR_SXS_ASSEMBLY_NOT_FOUND
+
+
+The referenced assembly is not installed on your system.
+
+0x000036B4
+
+ERROR_SXS_MANIFEST_FORMAT_ERROR
+
+
+The manifest file does not begin with the required tag and format information.
+
+0x000036B5
+
+ERROR_SXS_MANIFEST_PARSE_ERROR
+
+
+The manifest file contains one or more syntax errors.
+
+0x000036B6
+
+ERROR_SXS_ACTIVATION_CONTEXT_DISABLED
+
+
+The application attempted to activate a disabled activation context.
+
+0x000036B7
+
+ERROR_SXS_KEY_NOT_FOUND
+
+
+The requested lookup key was not found in any active activation context.
+
+0x000036B8
+
+ERROR_SXS_VERSION_CONFLICT
+
+
+A component version required by the application conflicts with another active component version.
+
+0x000036B9
+
+ERROR_SXS_WRONG_SECTION_TYPE
+
+
+The type requested activation context section does not match the query API used.
+
+0x000036BA
+
+ERROR_SXS_THREAD_QUERIES_DISABLED
+
+
+Lack of system resources has required isolated activation to be disabled for the current thread of execution.
+
+0x000036BB
+
+ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET
+
+
+An attempt to set the process default activation context failed because the process default activation context was already set.
+
+0x000036BC
+
+ERROR_SXS_UNKNOWN_ENCODING_GROUP
+
+
+The encoding group identifier specified is not recognized.
+
+0x000036BD
+
+ERROR_SXS_UNKNOWN_ENCODING
+
+
+The encoding requested is not recognized.
+
+0x000036BE
+
+ERROR_SXS_INVALID_XML_NAMESPACE_URI
+
+
+The manifest contains a reference to an invalid URI.
+
+0x000036BF
+
+ERROR_SXS_ROOT_MANIFEST_DEPENDENCY_OT_INSTALLED
+
+
+The application manifest contains a reference to a dependent assembly that is not installed.
+
+0x000036C0
+
+ERROR_SXS_LEAF_MANIFEST_DEPENDENCY_NOT_INSTALLED
+
+
+The manifest for an assembly used by the application has a reference to a dependent assembly that is not installed.
+
+0x000036C1
+
+ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE
+
+
+The manifest contains an attribute for the assembly identity that is not valid.
+
+0x000036C2
+
+ERROR_SXS_MANIFEST_MISSING_REQUIRED_DEFAULT_NAMESPACE
+
+
+The manifest is missing the required default namespace specification on the assembly element.
+
+0x000036C3
+
+ERROR_SXS_MANIFEST_INVALID_REQUIRED_DEFAULT_NAMESPACE
+
+
+The manifest has a default namespace specified on the assembly element but its value is not urn:schemas-microsoft-com:asm.v1"."
+
+0x000036C4
+
+ERROR_SXS_PRIVATE_MANIFEST_CROSS_PATH_WITH_REPARSE_POINT
+
+
+The private manifest probed has crossed the reparse-point-associated path.
+
+0x000036C5
+
+ERROR_SXS_DUPLICATE_DLL_NAME
+
+
+Two or more components referenced directly or indirectly by the application manifest have files by the same name.
+
+0x000036C6
+
+ERROR_SXS_DUPLICATE_WINDOWCLASS_NAME
+
+
+Two or more components referenced directly or indirectly by the application manifest have window classes with the same name.
+
+0x000036C7
+
+ERROR_SXS_DUPLICATE_CLSID
+
+
+Two or more components referenced directly or indirectly by the application manifest have the same COM server CLSIDs.
+
+0x000036C8
+
+ERROR_SXS_DUPLICATE_IID
+
+
+Two or more components referenced directly or indirectly by the application manifest have proxies for the same COM interface IIDs.
+
+0x000036C9
+
+ERROR_SXS_DUPLICATE_TLBID
+
+
+Two or more components referenced directly or indirectly by the application manifest have the same COM type library TLBIDs.
+
+0x000036CA
+
+ERROR_SXS_DUPLICATE_PROGID
+
+
+Two or more components referenced directly or indirectly by the application manifest have the same COM ProgIDs.
+
+0x000036CB
+
+ERROR_SXS_DUPLICATE_ASSEMBLY_NAME
+
+
+Two or more components referenced directly or indirectly by the application manifest are different versions of the same component, which is not permitted.
+
+0x000036CC
+
+ERROR_SXS_FILE_HASH_MISMATCH
+
+
+A component's file does not match the verification information present in the component manifest.
+
+0x000036CD
+
+ERROR_SXS_POLICY_PARSE_ERROR
+
+
+The policy manifest contains one or more syntax errors.
+
+0x000036CE
+
+ERROR_SXS_XML_E_MISSINGQUOTE
+
+
+Manifest Parse Error: A string literal was expected, but no opening quotation mark was found.
+
+0x000036CF
+
+ERROR_SXS_XML_E_COMMENTSYNTAX
+
+
+Manifest Parse Error: Incorrect syntax was used in a comment.
+
+0x000036D0
+
+ERROR_SXS_XML_E_BADSTARTNAMECHAR
+
+
+Manifest Parse Error: A name started with an invalid character.
+
+0x000036D1
+
+ERROR_SXS_XML_E_BADNAMECHAR
+
+
+Manifest Parse Error: A name contained an invalid character.
+
+0x000036D2
+
+ERROR_SXS_XML_E_BADCHARINSTRING
+
+
+Manifest Parse Error: A string literal contained an invalid character.
+
+0x000036D3
+
+ERROR_SXS_XML_E_XMLDECLSYNTAX
+
+
+Manifest Parse Error: Invalid syntax for an XML declaration.
+
+0x000036D4
+
+ERROR_SXS_XML_E_BADCHARDATA
+
+
+Manifest Parse Error: An Invalid character was found in text content.
+
+0x000036D5
+
+ERROR_SXS_XML_E_MISSINGWHITESPACE
+
+
+Manifest Parse Error: Required white space was missing.
+
+0x000036D6
+
+ERROR_SXS_XML_E_EXPECTINGTAGEND
+
+
+Manifest Parse Error: The angle bracket (>) character was expected.
+
+0x000036D7
+
+ERROR_SXS_XML_E_MISSINGSEMICOLON
+
+
+Manifest Parse Error: A semicolon (;) was expected.
+
+0x000036D8
+
+ERROR_SXS_XML_E_UNBALANCEDPAREN
+
+
+Manifest Parse Error: Unbalanced parentheses.
+
+0x000036D9
+
+ERROR_SXS_XML_E_INTERNALERROR
+
+
+Manifest Parse Error: Internal error.
+
+0x000036DA
+
+ERROR_SXS_XML_E_UNEXPECTED_WHITESPACE
+
+
+Manifest Parse Error: Whitespace is not allowed at this location.
+
+0x000036DB
+
+ERROR_SXS_XML_E_INCOMPLETE_ENCODING
+
+
+Manifest Parse Error: End of file reached in invalid state for current encoding.
+
+0x000036DC
+
+ERROR_SXS_XML_E_MISSING_PAREN
+
+
+Manifest Parse Error: Missing parenthesis.
+
+0x000036DD
+
+ERROR_SXS_XML_E_EXPECTINGCLOSEQUOTE
+
+
+Manifest Parse Error: A single (') or double (") quotation mark is missing.
+
+0x000036DE
+
+ERROR_SXS_XML_E_MULTIPLE_COLONS
+
+
+Manifest Parse Error: Multiple colons are not allowed in a name.
+
+0x000036DF
+
+ERROR_SXS_XML_E_INVALID_DECIMAL
+
+
+Manifest Parse Error: Invalid character for decimal digit.
+
+0x000036E0
+
+ERROR_SXS_XML_E_INVALID_HEXIDECIMAL
+
+
+Manifest Parse Error: Invalid character for hexadecimal digit.
+
+0x000036E1
+
+ERROR_SXS_XML_E_INVALID_UNICODE
+
+
+Manifest Parse Error: Invalid Unicode character value for this platform.
+
+0x000036E2
+
+ERROR_SXS_XML_E_WHITESPACEORQUESTIONMARK
+
+
+Manifest Parse Error: Expecting whitespace or question mark (?).
+
+0x000036E3
+
+ERROR_SXS_XML_E_UNEXPECTEDENDTAG
+
+
+Manifest Parse Error: End tag was not expected at this location.
+
+0x000036E4
+
+ERROR_SXS_XML_E_UNCLOSEDTAG
+
+
+Manifest Parse Error: The following tags were not closed: %1.
+
+0x000036E5
+
+ERROR_SXS_XML_E_DUPLICATEATTRIBUTE
+
+
+Manifest Parse Error: Duplicate attribute.
+
+0x000036E6
+
+ERROR_SXS_XML_E_MULTIPLEROOTS
+
+
+Manifest Parse Error: Only one top-level element is allowed in an XML document.
+
+0x000036E7
+
+ERROR_SXS_XML_E_INVALIDATROOTLEVEL
+
+
+Manifest Parse Error: Invalid at the top level of the document.
+
+0x000036E8
+
+ERROR_SXS_XML_E_BADXMLDECL
+
+
+Manifest Parse Error: Invalid XML declaration.
+
+0x000036E9
+
+ERROR_SXS_XML_E_MISSINGROOT
+
+
+Manifest Parse Error: XML document must have a top-level element.
+
+0x000036EA
+
+ERROR_SXS_XML_E_UNEXPECTEDEOF
+
+
+Manifest Parse Error: Unexpected end of file.
+
+0x000036EB
+
+ERROR_SXS_XML_E_BADPEREFINSUBSET
+
+
+Manifest Parse Error: Parameter entities cannot be used inside markup declarations in an internal subset.
+
+0x000036EC
+
+ERROR_SXS_XML_E_UNCLOSEDSTARTTAG
+
+
+Manifest Parse Error: Element was not closed.
+
+0x000036ED
+
+ERROR_SXS_XML_E_UNCLOSEDENDTAG
+
+
+Manifest Parse Error: End element was missing the angle bracket (>) character.
+
+0x000036EE
+
+ERROR_SXS_XML_E_UNCLOSEDSTRING
+
+
+Manifest Parse Error: A string literal was not closed.
+
+0x000036EF
+
+ERROR_SXS_XML_E_UNCLOSEDCOMMENT
+
+
+Manifest Parse Error: A comment was not closed.
+
+0x000036F0
+
+ERROR_SXS_XML_E_UNCLOSEDDECL
+
+
+Manifest Parse Error: A declaration was not closed.
+
+0x000036F1
+
+ERROR_SXS_XML_E_UNCLOSEDCDATA
+
+
+Manifest Parse Error: A CDATA section was not closed.
+
+0x000036F2
+
+ERROR_SXS_XML_E_RESERVEDNAMESPACE
+
+
+Manifest Parse Error: The namespace prefix is not allowed to start with the reserved string xml"."
+
+0x000036F3
+
+ERROR_SXS_XML_E_INVALIDENCODING
+
+
+Manifest Parse Error: System does not support the specified encoding.
+
+0x000036F4
+
+ERROR_SXS_XML_E_INVALIDSWITCH
+
+
+Manifest Parse Error: Switch from current encoding to specified encoding not supported.
+
+0x000036F5
+
+ERROR_SXS_XML_E_BADXMLCASE
+
+
+Manifest Parse Error: The name "xml" is reserved and must be lowercase.
+
+0x000036F6
+
+ERROR_SXS_XML_E_INVALID_STANDALONE
+
+
+Manifest Parse Error: The stand-alone attribute must have the value "yes" or "no".
+
+0x000036F7
+
+ERROR_SXS_XML_E_UNEXPECTED_STANDALONE
+
+
+Manifest Parse Error: The stand-alone attribute cannot be used in external entities.
+
+0x000036F8
+
+ERROR_SXS_XML_E_INVALID_VERSION
+
+
+Manifest Parse Error: Invalid version number.
+
+0x000036F9
+
+ERROR_SXS_XML_E_MISSINGEQUALS
+
+
+Manifest Parse Error: Missing equal sign (=) between the attribute and the attribute value.
+
+0x000036FA
+
+ERROR_SXS_PROTECTION_RECOVERY_FAILED
+
+
+Assembly Protection Error: Unable to recover the specified assembly.
+
+0x000036FB
+
+ERROR_SXS_PROTECTION_PUBLIC_KEY_OO_SHORT
+
+
+Assembly Protection Error: The public key for an assembly was too short to be allowed.
+
+0x000036FC
+
+ERROR_SXS_PROTECTION_CATALOG_NOT_VALID
+
+
+Assembly Protection Error: The catalog for an assembly is not valid, or does not match the assembly's manifest.
+
+0x000036FD
+
+ERROR_SXS_UNTRANSLATABLE_HRESULT
+
+
+An HRESULT could not be translated to a corresponding Win32 error code.
+
+0x000036FE
+
+ERROR_SXS_PROTECTION_CATALOG_FILE_MISSING
+
+
+Assembly Protection Error: The catalog for an assembly is missing.
+
+0x000036FF
+
+ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE
+
+
+The supplied assembly identity is missing one or more attributes that must be present in this context.
+
+0x00003700
+
+ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE_NAME
+
+
+The supplied assembly identity has one or more attribute names that contain characters not permitted in XML names.
+
+0x00003701
+
+ERROR_SXS_ASSEMBLY_MISSING
+
+
+The referenced assembly could not be found.
+
+0x00003702
+
+ERROR_SXS_CORRUPT_ACTIVATION_STACK
+
+
+The activation context activation stack for the running thread of execution is corrupt.
+
+0x00003703
+
+ERROR_SXS_CORRUPTION
+
+
+The application isolation metadata for this process or thread has become corrupt.
+
+0x00003704
+
+ERROR_SXS_EARLY_DEACTIVATION
+
+
+The activation context being deactivated is not the most recently activated one.
+
+0x00003705
+
+ERROR_SXS_INVALID_DEACTIVATION
+
+
+The activation context being deactivated is not active for the current thread of execution.
+
+0x00003706
+
+ERROR_SXS_MULTIPLE_DEACTIVATION
+
+
+The activation context being deactivated has already been deactivated.
+
+0x00003707
+
+ERROR_SXS_PROCESS_TERMINATION_REQUESTED
+
+
+A component used by the isolation facility has requested to terminate the process.
+
+0x00003708
+
+ERROR_SXS_RELEASE_ACTIVATION_ONTEXT
+
+
+A kernel mode component is releasing a reference on an activation context.
+
+0x00003709
+
+ERROR_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY
+
+
+The activation context of the system default assembly could not be generated.
+
+0x0000370A
+
+ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE
+
+
+The value of an attribute in an identity is not within the legal range.
+
+0x0000370B
+
+ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME
+
+
+The name of an attribute in an identity is not within the legal range.
+
+0x0000370C
+
+ERROR_SXS_IDENTITY_DUPLICATE_ATTRIBUTE
+
+
+An identity contains two definitions for the same attribute.
+
+0x0000370D
+
+ERROR_SXS_IDENTITY_PARSE_ERROR
+
+
+The identity string is malformed. This might be due to a trailing comma, more than two unnamed attributes, a missing attribute name, or a missing attribute value.
+
+0x0000370E
+
+ERROR_MALFORMED_SUBSTITUTION_STRING
+
+
+A string containing localized substitutable content was malformed. Either a dollar sign ($) was followed by something other than a left parenthesis or another dollar sign, or a substitution's right parenthesis was not found.
+
+0x0000370F
+
+ERROR_SXS_INCORRECT_PUBLIC_KEY_OKEN
+
+
+The public key token does not correspond to the public key specified.
+
+0x00003710
+
+ERROR_UNMAPPED_SUBSTITUTION_STRING
+
+
+A substitution string had no mapping.
+
+0x00003711
+
+ERROR_SXS_ASSEMBLY_NOT_LOCKED
+
+
+The component must be locked before making the request.
+
+0x00003712
+
+ERROR_SXS_COMPONENT_STORE_CORRUPT
+
+
+The component store has been corrupted.
+
+0x00003713
+
+ERROR_ADVANCED_INSTALLER_FAILED
+
+
+An advanced installer failed during setup or servicing.
+
+0x00003714
+
+ERROR_XML_ENCODING_MISMATCH
+
+
+The character encoding in the XML declaration did not match the encoding used in the document.
+
+0x00003715
+
+ERROR_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT
+
+
+The identities of the manifests are identical, but the contents are different.
+
+0x00003716
+
+ERROR_SXS_IDENTITIES_DIFFERENT
+
+
+The component identities are different.
+
+0x00003717
+
+ERROR_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT
+
+
+The assembly is not a deployment.
+
+0x00003718
+
+ERROR_SXS_FILE_NOT_PART_OF_ASSEMBLY
+
+
+The file is not a part of the assembly.
+
+0x00003719
+
+ERROR_SXS_MANIFEST_TOO_BIG
+
+
+The size of the manifest exceeds the maximum allowed.
+
+0x0000371A
+
+ERROR_SXS_SETTING_NOT_REGISTERED
+
+
+The setting is not registered.
+
+0x0000371B
+
+ERROR_SXS_TRANSACTION_CLOSURE_INCOMPLETE
+
+
+One or more required members of the transaction are not present.
+
+0x00003A98
+
+ERROR_EVT_INVALID_CHANNEL_PATH
+
+
+The specified channel path is invalid.
+
+0x00003A99
+
+ERROR_EVT_INVALID_QUERY
+
+
+The specified query is invalid.
+
+0x00003A9A
+
+ERROR_EVT_PUBLISHER_METADATA_NOT_FOUND
+
+
+The publisher metadata cannot be found in the resource.
+
+0x00003A9B
+
+ERROR_EVT_EVENT_TEMPLATE_NOT_FOUND
+
+
+The template for an event definition cannot be found in the resource (error = %1).
+
+0x00003A9C
+
+ERROR_EVT_INVALID_PUBLISHER_NAME
+
+
+The specified publisher name is invalid.
+
+0x00003A9D
+
+ERROR_EVT_INVALID_EVENT_DATA
+
+
+The event data raised by the publisher is not compatible with the event template definition in the publisher's manifest.
+
+0x00003A9F
+
+ERROR_EVT_CHANNEL_NOT_FOUND
+
+
+The specified channel could not be found. Check channel configuration.
+
+0x00003AA0
+
+ERROR_EVT_MALFORMED_XML_TEXT
+
+
+The specified XML text was not well-formed. See extended error for more details.
+
+0x00003AA1
+
+ERROR_EVT_SUBSCRIPTION_TO_DIRECT_CHANNEL
+
+
+The caller is trying to subscribe to a direct channel which is not allowed. The events for a direct channel go directly to a log file and cannot be subscribed to.
+
+0x00003AA2
+
+ERROR_EVT_CONFIGURATION_ERROR
+
+
+Configuration error.
+
+0x00003AA3
+
+ERROR_EVT_QUERY_RESULT_STALE
+
+
+The query result is stale or invalid. This might be due to the log being cleared or rolling over after the query result was created. Users should handle this code by releasing the query result object and reissuing the query.
+
+0x00003AA4
+
+ERROR_EVT_QUERY_RESULT_INVALID_POSITION
+
+
+Query result is currently at an invalid position.
+
+0x00003AA5
+
+ERROR_EVT_NON_VALIDATING_MSXML
+
+
+Registered Microsoft XML (MSXML) does not support validation.
+
+0x00003AA6
+
+ERROR_EVT_FILTER_ALREADYSCOPED
+
+
+An expression can only be followed by a change-of-scope operation if it itself evaluates to a node set and is not already part of some other change-of-scope operation.
+
+0x00003AA7
+
+ERROR_EVT_FILTER_NOTELTSET
+
+
+Cannot perform a step operation from a term that does not represent an element set.
+
+0x00003AA8
+
+ERROR_EVT_FILTER_INVARG
+
+
+Left side arguments to binary operators must be either attributes, nodes, or variables and right side arguments must be constants.
+
+0x00003AA9
+
+ERROR_EVT_FILTER_INVTEST
+
+
+A step operation must involve either a node test or, in the case of a predicate, an algebraic expression against which to test each node in the node set identified by the preceding node set can be evaluated.
+
+0x00003AAA
+
+ERROR_EVT_FILTER_INVTYPE
+
+
+This data type is currently unsupported.
+
+0x00003AAB
+
+ERROR_EVT_FILTER_PARSEERR
+
+
+A syntax error occurred at position %1!d!
+
+0x00003AAC
+
+ERROR_EVT_FILTER_UNSUPPORTEDOP
+
+
+This operator is unsupported by this implementation of the filter.
+
+0x00003AAD
+
+ERROR_EVT_FILTER_UNEXPECTEDTOKEN
+
+
+The token encountered was unexpected.
+
+0x00003AAE
+
+ERROR_EVT_INVALID_OPERATION_OVER_ENABLED_DIRECT_CHANNEL
+
+
+The requested operation cannot be performed over an enabled direct channel. The channel must first be disabled before performing the requested operation.
+
+0x00003AAF
+
+ERROR_EVT_INVALID_CHANNEL_PROPERTY_VALUE
+
+
+Channel property %1!s! contains an invalid value. The value has an invalid type, is outside the valid range, cannot be updated, or is not supported by this type of channel.
+
+0x00003AB0
+
+ERROR_EVT_INVALID_PUBLISHER_PROPERTY_VALUE
+
+
+Publisher property %1!s! contains an invalid value. The value has an invalid type, is outside the valid range, cannot be updated, or is not supported by this type of publisher.
+
+0x00003AB1
+
+ERROR_EVT_CHANNEL_CANNOT_ACTIVATE
+
+
+The channel fails to activate.
+
+0x00003AB2
+
+ERROR_EVT_FILTER_TOO_COMPLEX
+
+
+The xpath expression exceeded supported complexity. Simplify it or split it into two or more simple expressions.
+
+0x00003AB3
+
+ERROR_EVT_MESSAGE_NOT_FOUND
+
+
+The message resource is present but the message is not found in the string or message table.
+
+0x00003AB4
+
+ERROR_EVT_MESSAGE_ID_NOT_FOUND
+
+
+The message ID for the desired message could not be found.
+
+0x00003AB5
+
+ERROR_EVT_UNRESOLVED_VALUE_INSERT
+
+
+The substitution string for the insert index (%1) could not be found.
+
+0x00003AB6
+
+ERROR_EVT_UNRESOLVED_PARAMETER_INSERT
+
+
+The description string for the parameter reference (%1) could not be found.
+
+0x00003AB7
+
+ERROR_EVT_MAX_INSERTS_REACHED
+
+
+The maximum number of replacements has been reached.
+
+0x00003AB8
+
+ERROR_EVT_EVENT_DEFINITION_NOT_OUND
+
+
+The event definition could not be found for the event ID (%1).
+
+0x00003AB9
+
+ERROR_EVT_MESSAGE_LOCALE_NOT_FOUND
+
+
+The locale-specific resource for the desired message is not present.
+
+0x00003ABA
+
+ERROR_EVT_VERSION_TOO_OLD
+
+
+The resource is too old to be compatible.
+
+0x00003ABB
+
+ERROR_EVT_VERSION_TOO_NEW
+
+
+The resource is too new to be compatible.
+
+0x00003ABC
+
+ERROR_EVT_CANNOT_OPEN_CHANNEL_OF_QUERY
+
+
+The channel at index %1 of the query cannot be opened.
+
+0x00003ABD
+
+ERROR_EVT_PUBLISHER_DISABLED
+
+
+The publisher has been disabled and its resource is not available. This usually occurs when the publisher is in the process of being uninstalled or upgraded.
+
+0x00003AE8
+
+ERROR_EC_SUBSCRIPTION_CANNOT_ACTIVATE
+
+
+The subscription fails to activate.
+
+0x00003AE9
+
+ERROR_EC_LOG_DISABLED
+
+
+The log of the subscription is in a disabled state and events cannot be forwarded to it. The log must first be enabled before the subscription can be activated.
+
+0x00003AFC
+
+ERROR_MUI_FILE_NOT_FOUND
+
+
+The resource loader failed to find the Multilingual User Interface (MUI) file.
+
+0x00003AFD
+
+ERROR_MUI_INVALID_FILE
+
+
+The resource loader failed to load the MUI file because the file failed to pass validation.
+
+0x00003AFE
+
+ERROR_MUI_INVALID_RC_CONFIG
+
+
+The release candidate (RC) manifest is corrupted with garbage data, is an unsupported version, or is missing a required item.
+
+0x00003AFF
+
+ERROR_MUI_INVALID_LOCALE_NAME
+
+
+The RC manifest has an invalid culture name.
+
+0x00003B00
+
+ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME
+
+
+The RC Manifest has an invalid ultimate fallback name.
+
+0x00003B01
+
+ERROR_MUI_FILE_NOT_LOADED
+
+
+The resource loader cache does not have a loaded MUI entry.
+
+0x00003B02
+
+ERROR_RESOURCE_ENUM_USER_STOP
+
+
+The user stopped resource enumeration.
+
+0x00003B03
+
+ERROR_MUI_INTLSETTINGS_UILANG_NOT_INSTALLED
+
+
+User interface language installation failed.
+
+0x00003B04
+
+ERROR_MUI_INTLSETTINGS_INVALID_LOCALE_NAME
+
+
+Locale installation failed.
+
+0x00003B60
+
+ERROR_MCA_INVALID_CAPABILITIES_STRING
+
+
+The monitor returned a DDC/CI capabilities string that did not comply with the ACCESS.bus 3.0, DDC/CI 1.1, or MCCS 2 Revision 1 specification.
+
+0x00003B61
+
+ERROR_MCA_INVALID_VCP_VERSION
+
+
+The monitor's VCP version (0xDF) VCP code returned an invalid version value.
+
+0x00003B62
+
+ERROR_MCA_MONITOR_VIOLATES_MCCS_SPECIFICATION
+
+
+The monitor does not comply with the MCCS specification it claims to support.
+
+0x00003B63
+
+ERROR_MCA_MCCS_VERSION_MISMATCH
+
+
+The MCCS version in a monitor's mccs_ver capability does not match the MCCS version the monitor reports when the VCP version (0xDF) VCP code is used.
+
+0x00003B64
+
+ERROR_MCA_UNSUPPORTED_MCCS_VERSION
+
+
+The monitor configuration API works only with monitors that support the MCCS 1.0, MCCS 2.0, or MCCS 2.0 Revision 1 specifications.
+
+0x00003B65
+
+ERROR_MCA_INTERNAL_ERROR
+
+
+An internal monitor configuration API error occurred.
+
+0x00003B66
+
+ERROR_MCA_INVALID_TECHNOLOGY_TYPE_RETURNED
+
+
+The monitor returned an invalid monitor technology type. CRT, plasma, and LCD (TFT) are examples of monitor technology types. This error implies that the monitor violated the MCCS 2.0 or MCCS 2.0 Revision 1 specification.
+
+0x00003B67
+
+ERROR_MCA_UNSUPPORTED_COLOR_TEMPERATURE
+
+
+The SetMonitorColorTemperature() caller passed a color temperature to it that the current monitor did not support. CRT, plasma, and LCD (TFT) are examples of monitor technology types. This error implies that the monitor violated the MCCS 2.0 or MCCS 2.0 Revision 1 specification.
+
+0x00003B92
+
+ERROR_AMBIGUOUS_SYSTEM_DEVICE
+
+
+The requested system device cannot be identified due to multiple indistinguishable devices potentially matching the identification criteria.
+
+0x00003BC3
+
+ERROR_SYSTEM_DEVICE_NOT_FOUND
+
+
+The requested system device cannot be found.
diff --git a/libcli/util/wscript_build b/libcli/util/wscript_build
new file mode 100644
index 0000000..340ea42
--- /dev/null
+++ b/libcli/util/wscript_build
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+
+
+bld.SAMBA_LIBRARY('samba-errors',
+ public_headers='error.h ntstatus.h ntstatus_gen.h doserr.h werror.h werror_gen.h hresult.h',
+ private_headers='nterr_private.h',
+ header_path='core',
+ source='doserr.c errormap.c nterr.c errmap_unix.c hresult.c',
+ public_deps='talloc samba-debug',
+ deps='gnutls',
+ # private_library=True,
+ pc_files=[],
+ vnum='1.0.0',
+ )
+
+bld.SAMBA_GENERATOR('hresult_generated',
+ source='../../source4/scripting/bin/gen_hresult.py hresult_err_table.txt ../../source4/scripting/bin/gen_error_common.py',
+ target='hresult.h hresult.c py_hresult.c',
+ group='build_source',
+ rule='${PYTHON} ${SRC[0].abspath(env)} ${SRC[1].abspath(env)} ${TGT[0].abspath(env)} ${TGT[1].abspath(env)} ${TGT[2].abspath(env)}'
+ )
+
+bld.SAMBA_GENERATOR('ntstatus_generated',
+ source='../../source4/scripting/bin/gen_ntstatus.py ntstatus_err_table.txt ../../source4/scripting/bin/gen_error_common.py',
+ target='ntstatus_gen.h nterr_gen.c py_ntstatus.c',
+ group='build_source',
+ rule='${PYTHON} ${SRC[0].abspath(env)} ${SRC[1].abspath(env)} ${TGT[0].abspath(env)} ${TGT[1].abspath(env)} ${TGT[2].abspath(env)}'
+ )
+
+bld.SAMBA_GENERATOR('werror_generated',
+ source='../../source4/scripting/bin/gen_werror.py werror_err_table.txt ../../source4/scripting/bin/gen_error_common.py',
+ target='''
+ werror_gen.h
+ werror_gen.c
+ werror_friendly_gen.c
+ py_werror.c
+ ''',
+ group='build_source',
+ rule='${PYTHON} ${SRC[0].abspath(env)} ${SRC[1].abspath(env)} ${TGT[0].abspath(env)} ${TGT[1].abspath(env)} ${TGT[2].abspath(env)} ${TGT[3].abspath(env)}'
+ )
+
+bld.SAMBA_PYTHON('python_hresult',
+ source='py_hresult.c',
+ deps='samba-errors',
+ realname='samba/hresult.so'
+ )
+
+bld.SAMBA_PYTHON('python_ntstatus',
+ source='py_ntstatus.c',
+ deps='samba-errors',
+ realname='samba/ntstatus.so'
+ )
+
+bld.SAMBA_PYTHON('python_werror',
+ source='py_werror.c',
+ deps='samba-errors',
+ realname='samba/werror.so'
+ )
diff --git a/libcli/wsp/test_wsp_parser.c b/libcli/wsp/test_wsp_parser.c
new file mode 100644
index 0000000..9edebda
--- /dev/null
+++ b/libcli/wsp/test_wsp_parser.c
@@ -0,0 +1,402 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Noel Power
+ *
+ * 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 <setjmp.h>
+#include <cmocka.h>
+#include <talloc.h>
+#include "lib/cmdline/cmdline.h"
+#include "libcli/util/ntstatus.h"
+#include "lib/util/samba_util.h"
+#include "lib/torture/torture.h"
+#include "lib/param/param.h"
+#include "libcli/wsp/wsp_aqs.h"
+#include "bin/default/librpc/gen_ndr/ndr_wsp.h"
+#include "librpc/wsp/wsp_util.h"
+
+/*
+ * some routines to help stringify the parsed AQS
+ * query so we can test parsing
+ */
+
+static bool is_operator_node(t_query *node)
+{
+ if (node->type == eVALUE) {
+ return false;
+ }
+ return true;
+}
+
+static const char *nodetype_as_string(t_nodetype node)
+{
+ const char *result = NULL;
+ switch (node) {
+ case eNOT:
+ result = "NOT";
+ break;
+ case eAND:
+ result = "AND";
+ break;
+ case eOR:
+ result = "OR";
+ break;
+ case eVALUE:
+ default:
+ break;
+ }
+ return result;
+}
+
+static const char *restriction_as_string(TALLOC_CTX *ctx,
+ struct wsp_crestriction *crestriction )
+{
+ const char *result = NULL;
+ if (crestriction->ultype == RTPROPERTY) {
+ struct wsp_cpropertyrestriction *prop_restr =
+ &crestriction->restriction.cpropertyrestriction;
+ struct wsp_cbasestoragevariant *value = &prop_restr->prval;
+ result = variant_as_string(ctx, value, true);
+ } else {
+ struct wsp_ccontentrestriction *cont_restr = NULL;
+ cont_restr = &crestriction->restriction.ccontentrestriction;
+ result = talloc_strdup(ctx, cont_restr->pwcsphrase);
+ }
+ return result;
+}
+
+static const char *prop_name_from_restriction(
+ TALLOC_CTX *ctx,
+ struct wsp_crestriction *restriction)
+{
+ const char *result = NULL;
+ struct wsp_cfullpropspec *prop;
+ if (restriction->ultype == RTCONTENT) {
+ prop = &restriction->restriction.ccontentrestriction.property;
+ } else {
+ prop = &restriction->restriction.cpropertyrestriction.property;
+ }
+ result = prop_from_fullprop(ctx, prop);
+ return result;
+}
+
+static char *print_basic_query(TALLOC_CTX *ctx,
+ struct wsp_crestriction *restriction)
+{
+ const char *op_str = op_as_string(restriction);
+ const char *val_str = restriction_as_string(ctx, restriction);
+ const char *prop_name = prop_name_from_restriction(ctx, restriction);
+ char *res = talloc_asprintf(ctx,
+ "%s %s %s", prop_name, op_str ? op_str : "", val_str);
+ return res;
+}
+
+static char *print_node(TALLOC_CTX *ctx, t_query *node, bool is_rpn)
+{
+ switch(node->type) {
+ case eAND:
+ case eOR:
+ case eNOT:
+ return talloc_asprintf(ctx,
+ " %s ", nodetype_as_string(node->type));
+ break;
+ case eVALUE:
+ default:
+ return print_basic_query(ctx, node->restriction);
+ break;
+ }
+}
+
+/*
+ * Algorithm infix (tree)
+ * Print the infix expression for an expression tree.
+ * Pre : tree is a pointer to an expression tree
+ * Post: the infix expression has been printed
+ * start infix
+ * if (tree not empty)
+ * if (tree token is operator)
+ * print (open parenthesis)
+ * end if
+ * infix (tree left subtree)
+ * print (tree token)
+ * infix (tree right subtree)
+ * if (tree token is operator)
+ * print (close parenthesis)
+ * end if
+ * end if
+ * end infix
+ */
+
+static char *infix(TALLOC_CTX *ctx, t_query *tree)
+{
+ char *sresult = NULL;
+ char *stree = NULL;
+ char *sleft = NULL;
+ char *sright = NULL;
+ if (tree == NULL) {
+ return NULL;
+ }
+
+ if (is_operator_node(tree)) {
+ sresult = talloc_strdup(ctx, "(");
+ SMB_ASSERT(sresult != NULL);
+ }
+ sleft = infix(ctx, tree->left);
+ stree = print_node(ctx, tree, false);
+ sright = infix(ctx, tree->right);
+ sresult = talloc_asprintf(ctx, "%s%s%s%s",
+ sresult ? sresult : "",
+ sleft ? sleft : "",
+ stree? stree : "",
+ sright ? sright : "");
+
+ if (is_operator_node(tree)) {
+ sresult = talloc_asprintf(ctx, "%s)", sresult);
+ SMB_ASSERT(sresult != NULL);
+ }
+ return sresult;
+}
+
+static struct {
+ const char *aqs;
+ const char *stringified;
+} no_col_map_queries [] = {
+
+ /* equals (numeric) */
+ {
+ "System.Size:10241",
+ "System.Size = 10241"
+ },
+ {
+ "System.Size := 10241",
+ "System.Size = 10241"
+ },
+ /* not equals */
+ {
+ "System.Size:!=10241",
+ "System.Size != 10241"
+ },
+ /* equals (string property) */
+ {
+ "ALL:(somestring)",
+ "All = 'somestring'"
+ },
+ {
+ "ALL:=somestring",
+ "All = 'somestring'"
+ },
+ {
+ "ALL:somestring",
+ "All = 'somestring'"
+ },
+ /* not equals (string) */
+ {
+ "ALL:!=somestring",
+ "All != 'somestring'"
+ },
+ /* Greater than */
+ {
+ "System.Size:(>10241)",
+ "System.Size > 10241"
+ },
+ {
+ "System.Size:>10241",
+ "System.Size > 10241"
+ },
+ /* Less than */
+ {
+ "System.Size:(<10241)",
+ "System.Size < 10241"
+ },
+ /* Greater than or equals */
+ {
+ "System.Size:(>=10241)",
+ "System.Size >= 10241"
+ },
+ {
+ "System.Size:>=10241",
+ "System.Size >= 10241"
+ },
+ /* Less than or equals */
+ {
+ "System.Size:(<=10241)",
+ "System.Size <= 10241"
+ },
+ {
+ "System.Size:<=10241",
+ "System.Size <= 10241"
+ },
+ /* equals (in the sense of matches) */
+ {
+ "ALL:($=somestring)",
+ "All equals somestring"
+ },
+ /* starts with */
+ {
+ "ALL:($<somestring)",
+ "All starts with somestring"
+ },
+ /* range */
+ {
+ "System.Size:10241-102401",
+ "(System.Size >= 10241 AND System.Size < 102401)"
+ },
+ {
+ "System.Size:small",
+ "(System.Size >= 10241 AND System.Size < 102401)"
+ },
+ /* NOT */
+ {
+ "NOT System.Size:10241",
+ "( NOT System.Size = 10241)"
+ },
+ /* AND */
+ {
+ "System.Size:(>=10241) AND System.Size:(<102401)",
+ "(System.Size >= 10241 AND System.Size < 102401)"
+ },
+ /* OR */
+ {
+ "System.Kind:picture OR System.Kind:video",
+ "(System.Kind = 'picture' OR System.Kind = 'video')"
+ },
+ /* MULTIPLE LOGICAL */
+ {
+ "System.Kind:picture AND NOT System.Kind:video OR "
+ "System.Kind:movie",
+ "(System.Kind = 'picture' AND (( NOT System.Kind = 'video') OR "
+ "System.Kind = 'movie'))"
+ },
+ /* parenthesized MULTIPLE LOGICAL */
+ {
+ "(System.Kind:picture AND NOT System.Kind:video) OR "
+ "System.Kind:movie",
+ "((System.Kind = 'picture' AND ( NOT System.Kind = 'video')) "
+ "OR System.Kind = 'movie')"
+ },
+};
+
+static char *dump_cols(TALLOC_CTX *ctx, t_select_stmt *select)
+{
+ t_col_list *cols = select->cols;
+ char *res = NULL;
+ if (cols) {
+ int i;
+ for (i = 0; i < cols->num_cols; i++) {
+ if (i == 0) {
+ res = talloc_strdup(ctx,
+ cols->cols[i]);
+ } else {
+ res = talloc_asprintf(ctx,
+ "%s, %s",
+ res, cols->cols[i]);
+ }
+ }
+ }
+ return res;
+}
+
+static void test_wsp_parser(void **state)
+{
+ int i;
+ t_select_stmt *select_stmt = NULL;
+ const char *col_query =
+ "SELECT System.ItemName, System.ItemURL, System.Size WHERE "
+ "System.Kind:picture";
+ char *res = NULL;
+
+ TALLOC_CTX *frame = talloc_stackframe();
+ for (i = 0; i < ARRAY_SIZE(no_col_map_queries); i++) {
+ select_stmt = get_wsp_sql_tree(no_col_map_queries[i].aqs);
+ assert_non_null(select_stmt);
+ assert_null(select_stmt->cols);
+ res = infix(frame, select_stmt->where);
+ DBG_DEBUG("reading query => %s parsed => %s\n",
+ no_col_map_queries[i].aqs,
+ res);
+ assert_string_equal(res, no_col_map_queries[i].stringified);
+ }
+ select_stmt = get_wsp_sql_tree(col_query);
+ res = infix(frame, select_stmt->where);
+ assert_string_equal(res, "System.Kind = 'picture'");
+ assert_non_null(select_stmt->cols);
+ res = dump_cols(frame, select_stmt);
+ assert_string_equal(res,
+ "System.ItemName, System.ItemURL, System.Size");
+ TALLOC_FREE(frame);
+}
+
+int main(int argc, const char *argv[])
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_wsp_parser),
+ };
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_SAMBA
+ POPT_TABLEEND
+ };
+ poptContext pc;
+ int opt;
+ bool ok;
+ struct loadparm_context *lp_ctx = NULL;
+
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ smb_init_locale();
+
+ ok = samba_cmdline_init(frame,
+ SAMBA_CMDLINE_CONFIG_CLIENT,
+ false /* require_smbconf */);
+ if (!ok) {
+ DBG_ERR("Failed to init cmdline parser!\n");
+ TALLOC_FREE(frame);
+ exit(1);
+ }
+
+ lp_ctx = samba_cmdline_get_lp_ctx();
+ if (!lp_ctx) {
+ DBG_ERR("Failed to init cmdline parser!\n");
+ TALLOC_FREE(frame);
+ exit(1);
+ }
+
+ lpcfg_set_cmdline(lp_ctx, "log level", "1");
+
+ pc = samba_popt_get_context(getprogname(),
+ argc,
+ argv,
+ long_options,
+ 0);
+ if (pc == NULL) {
+ DBG_ERR("Failed to setup popt context!\n");
+ TALLOC_FREE(frame);
+ exit(1);
+ }
+
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch(opt) {
+ default:
+ fprintf(stderr, "Unknown Option: %c\n", opt);
+ exit(1);
+ }
+ }
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/libcli/wsp/wscript_build b/libcli/wsp/wscript_build
new file mode 100644
index 0000000..2d34879
--- /dev/null
+++ b/libcli/wsp/wscript_build
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+#default flex recepie doesn't create a header file
+bld.SAMBA_GENERATOR('wsp_flex',
+ source='wsp_aqs_lexer.l',
+ target='wsp_aqs_lexer.h wsp_aqs_lexer.c',
+ group='build_source',
+ rule='${FLEX} --header-file=${TGT[0].abspath(env)} --outfile=${TGT[1].abspath(env)} ${SRC[0].abspath(env)}',
+ enabled=bld.env.with_wsp
+ )
+
+# With centos7-o3 CI job (and gcc 4.8.5) we get
+# an error with -Wstrict-overflow.
+# Same code is good with gcc version
+# gcc 8.5.0 (centos8) and whatever versions of
+# gcc we have in the other XXXX-o3 images.
+# We turn off strict-overflow just for this generated
+# file
+parser_cflags=''
+if bld.CONFIG_SET('HAVE_WNO_STRICT_OVERFLOW'):
+ parser_cflags += ' -Wno-strict-overflow'
+
+bld.SAMBA_SUBSYSTEM('LIBSAMBA_WSP_PARSER',
+ source='wsp_aqs_parser.y',
+ deps='talloc wsp_flex',
+ cflags_end=parser_cflags,
+ enabled=bld.env.with_wsp
+ )
+bld.SAMBA_SUBSYSTEM('LIBSAMBA_WSP',
+ source='wsp_aqs.c wsp_aqs_lexer.c',
+ public_deps='LIBSAMBA_WSP_PARSER',
+ enabled=bld.env.with_wsp
+ )
+
+bld.SAMBA_BINARY('test_wsp_parser',
+ source='test_wsp_parser.c',
+ deps= 'dcerpc CMDLINE_S3 LIBSAMBA_WSP NDR_WSP NDR_WSP_DATA WSP_UTIL cmocka',
+ enabled=bld.env.with_wsp,
+ install=False
+ )
+
diff --git a/libcli/wsp/wsp_aqs.c b/libcli/wsp/wsp_aqs.c
new file mode 100644
index 0000000..acf1229
--- /dev/null
+++ b/libcli/wsp/wsp_aqs.c
@@ -0,0 +1,877 @@
+/*
+ * Window Search Service
+ *
+ * Copyright (c) Noel Power
+ *
+ * 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 "libcli/wsp/wsp_aqs.h"
+#include "libcli/wsp/wsp_aqs_parser.tab.h"
+#include "libcli/wsp/wsp_aqs_lexer.h"
+#include "librpc/wsp/wsp_util.h"
+#include "librpc/gen_ndr/ndr_wsp.h"
+#include <stdio.h>
+#include <stdbool.h>
+
+int yyparse(t_select_stmt **select, yyscan_t scanner);
+
+static void reverse_cols(t_select_stmt *select)
+{
+ int num_elems, fwd, rev;
+ char **cols;
+
+
+ if (!select->cols) {
+ return;
+ }
+ num_elems = select->cols->num_cols;
+ cols = select->cols->cols;
+
+ for(fwd = 0, rev = num_elems - 1; fwd <= rev; fwd++, rev--) {
+ char * tmp = cols[rev];
+ cols[rev] = cols[fwd];
+ cols[fwd] = tmp;
+ }
+
+}
+
+t_select_stmt *get_wsp_sql_tree(const char *expr)
+{
+ t_select_stmt *select = NULL;
+ yyscan_t scanner;
+ YY_BUFFER_STATE state;
+
+ if (yylex_init(&scanner)) {
+ DBG_ERR("couldn't initialize\n");
+ return NULL;
+ }
+
+ state = yy_scan_string(expr, scanner);
+
+ if (yyparse(&select, scanner)) {
+ DBG_ERR("some parse error\n");
+ return NULL;
+ }
+ /*
+ * parsed columns are in reverse order to how they are specified
+ * in the AQS like statement, reverse them again to correct this.
+ */
+ reverse_cols(select);
+
+ yy_delete_buffer(state, scanner);
+
+ yylex_destroy(scanner);
+
+ return select;
+}
+
+
+t_col_list *create_cols(TALLOC_CTX *ctx, const char *col, t_col_list *append_list)
+{
+ t_col_list *cols = append_list;
+ if (!get_prop_info(col)) {
+ DBG_ERR("Unknown property %s\n", col);
+ return NULL;
+ }
+ if (cols == NULL) {
+ cols = talloc_zero(ctx, t_col_list);
+ if (cols == NULL) {
+ DBG_ERR("out of memory\n");
+ return NULL;
+ }
+ cols->num_cols = 0;
+ cols->cols = NULL;
+ DBG_INFO("returning new cols %p with item %s\n", cols, col);
+ }
+ if (col) {
+ int old_index = cols->num_cols;
+ if (old_index == 0) {
+ cols->cols = talloc_array(cols, char*, 1);
+ } else {
+ cols->cols = (char **)talloc_realloc(cols, cols->cols, char*, old_index + 1);
+ }
+ if (!cols->cols) {
+ return NULL; /* can we create a parser error here */
+ }
+ cols->num_cols++;
+ cols->cols[old_index] = talloc_strdup(cols, col);
+ if (cols->cols[old_index] == NULL) {
+ DBG_ERR("out of memory\n");
+ return NULL;
+ }
+
+ }
+ return cols;
+}
+
+t_select_stmt *create_select(TALLOC_CTX *ctx, t_col_list *cols, t_query *where)
+{
+ t_select_stmt *result = talloc_zero(ctx, t_select_stmt);
+ if (result == NULL) {
+ DBG_ERR("out of memory\n");
+ return NULL;
+ }
+ result->cols = cols;
+ result->where = where;
+ return result;
+}
+
+t_basic_restr *create_basic_restr(TALLOC_CTX *ctx,
+ uint32_t prop_type,
+ t_optype op,
+ t_value_holder *values)
+{
+ t_basic_restr *result = talloc_zero(ctx, t_basic_restr);
+ if (result == NULL) {
+ DBG_ERR("out of memory\n");
+ return NULL;
+ }
+ result->prop_type = prop_type;
+ result->op = op;
+ if (values->type == VALUE_RANGE) {
+ t_restr *left_node;
+ t_restr *right_node;
+ t_basic_restr *left_val;
+ t_basic_restr *right_val;
+ if (op != eEQ) {
+ DBG_ERR("Unsupported operation %d\n", op);
+ TALLOC_FREE(result);
+ goto out;
+ }
+
+ if (values->value.value_range->lower == NULL) {
+ DBG_ERR("range lower limit doesn't exist\n");
+ TALLOC_FREE(result);
+ goto out;
+ }
+ /*
+ * detect special case where upper range doesn't exist
+ * and convert to a property value. (this won't happen from
+ * the cmdline directly but only as a result of a range
+ * created 'specially' in code, e.g. special gigantic size
+ * range.
+ */
+ if (values->value.value_range->upper == NULL) {
+ result->op = eGE;
+ result->values = values->value.value_range->lower;
+ goto out;
+ }
+ result->values = talloc_zero(result, t_value_holder);
+ if (result->values == NULL) {
+ DBG_ERR("out of memory\n");
+ TALLOC_FREE(result);
+ goto out;
+ }
+ /*
+ * try create a restriction tree (>=lower AND <upper) to
+ * represent the range
+ */
+ left_val = create_basic_restr(result->values,
+ prop_type,
+ eGE,
+ values->value.value_range->lower);
+
+ right_val = create_basic_restr(result->values,
+ prop_type,
+ eLT,
+ values->value.value_range->upper);
+
+ if (!left_val || !right_val) {
+ DBG_ERR("Failed creating basic_restriction values "
+ "for range\n");
+ TALLOC_FREE(result);
+ goto out;
+ }
+
+ left_node = create_restr(result->values, eVALUE, NULL, NULL, left_val);
+ right_node = create_restr(result->values, eVALUE, NULL, NULL, right_val);
+
+
+ if (!left_node || !right_node) {
+ DBG_ERR("Failed creating restr nodes for range\n");
+ TALLOC_FREE(result);
+ goto out;
+ }
+ result->values->type = RESTR;
+ result->values->value.restr_tree = create_restr(result->values,
+ eAND,
+ left_node,
+ right_node,
+ NULL);
+ if (!result->values->value.restr_tree) {
+ DBG_ERR("Failed creating restr tree for range\n");
+ TALLOC_FREE(result);
+ goto out;
+ }
+ } else {
+ result->values = values;
+ }
+out:
+ return result;
+}
+
+/*
+ * The parser reads numbers as VT_UI8, booleans as VT_BOOL and strings as
+ * VT_LPWSTR
+ */
+typedef bool (*conv_func) (TALLOC_CTX *ctx, t_value_holder *src,
+ struct wsp_cbasestoragevariant *dest,
+ uint16_t dest_type);
+
+/*
+ * default converter #TODO probably should cater for detecting over/underrun
+ * depending on the dest_type we are narrowing to
+ */
+static bool default_convertor(TALLOC_CTX *ctx,
+ t_value_holder *src,
+ struct wsp_cbasestoragevariant *dest,
+ uint16_t dest_type)
+{
+ if (src->type != NUMBER) {
+ return false;
+ }
+ dest->vvalue.vt_ui8 = src->value.number;
+ dest->vtype = dest_type;
+ return true;
+}
+
+static bool convert_string_to_lpwstr_v(TALLOC_CTX *ctx,
+ t_value_holder *src,
+ struct wsp_cbasestoragevariant *dest,
+ uint16_t dest_type)
+{
+ const char *str = src->value.string;
+ set_variant_lpwstr_vector(ctx, dest, &str, 1);
+ return true;
+}
+
+static bool convert_string_to_lpwstr(TALLOC_CTX *ctx,
+ t_value_holder *src,
+ struct wsp_cbasestoragevariant *dest,
+ uint16_t dest_type)
+{
+ const char *str = src->value.string;
+ set_variant_lpwstr(ctx, dest, str);
+ return true;
+}
+
+static bool convert_bool_to_lpwstr(TALLOC_CTX *ctx,
+ t_value_holder *src,
+ struct wsp_cbasestoragevariant *dest,
+ uint16_t dest_type)
+{
+ set_variant_lpwstr(
+ ctx,
+ dest,
+ src->value.boolean ? "true": "false");
+ return true;
+}
+
+static bool convert_string_to_filetime(TALLOC_CTX *ctx,
+ t_value_holder *src,
+ struct wsp_cbasestoragevariant *dest,
+ uint16_t dest_type)
+{
+
+ static const char *fmts[] = {
+ "%FT%TZ",
+ "%FT%T",
+ "%F %T",
+ "%F %R",
+ "%F",
+ };
+ struct tm tm;
+ time_t timeval = 0;
+ int i;
+ ZERO_STRUCT(tm);
+
+ for (i = 0; i < ARRAY_SIZE(fmts); i++) {
+ if (strptime(src->value.string, fmts[i], &tm)) {
+ timeval = timegm(&tm);
+ break;
+ }
+ }
+
+ if (timeval) {
+ NTTIME nt;
+ unix_to_nt_time(&nt, timeval);
+ dest->vtype = VT_FILETIME;
+ dest->vvalue.vt_filetime = nt;
+ return true;
+ }
+ return false;
+}
+
+const struct {
+ uint16_t src_vtype;
+ uint16_t dest_vtype;
+ conv_func convert_type;
+} type_conv_map[] = {
+ {NUMBER, VT_I8, default_convertor},
+ {NUMBER, VT_UI8, default_convertor},
+ {NUMBER, VT_INT, default_convertor},
+ {NUMBER, VT_UINT, default_convertor},
+ {NUMBER, VT_I4, default_convertor},
+ {NUMBER, VT_UI4, default_convertor},
+ {NUMBER, VT_I2, default_convertor},
+ {NUMBER, VT_UI2, default_convertor},
+ {NUMBER, VT_BOOL, default_convertor},
+ {NUMBER, VT_FILETIME, default_convertor},
+ {NUMBER, VT_BOOL, default_convertor},
+ {BOOL, VT_LPWSTR, convert_bool_to_lpwstr},
+ {STRING, VT_LPWSTR, convert_string_to_lpwstr},
+ {STRING, VT_LPWSTR | VT_VECTOR, convert_string_to_lpwstr_v},
+ {STRING, VT_FILETIME, convert_string_to_filetime},
+};
+
+static bool process_prop_value(TALLOC_CTX *ctx,
+ const struct full_propset_info *prop_info,
+ t_value_holder *node_value,
+ struct wsp_cbasestoragevariant *prop_value)
+{
+ int i;
+
+ /* coerce type as required */
+ for (i = 0; i < ARRAY_SIZE(type_conv_map); i++ ) {
+ if (type_conv_map[i].src_vtype == node_value->type &&
+ type_conv_map[i].dest_vtype == prop_info->vtype) {
+ type_conv_map[i].convert_type(ctx,
+ node_value,
+ prop_value,
+ prop_info->vtype);
+ return true;
+ }
+ }
+ return false;
+}
+
+t_basic_query *create_basic_query(TALLOC_CTX *ctx, const char *propname, t_basic_restr *restr)
+{
+ t_basic_query *result = talloc_zero(ctx, t_basic_query);
+ if (result == NULL) {
+ DBG_ERR("out of memory\n");
+ goto out;
+ }
+ result->prop = talloc_strdup(result, propname);
+ result->prop_info = get_propset_info_with_guid(propname, &result->guid);
+
+ if (!result->prop_info) {
+ DBG_ERR("Unknown property %s\n",propname);
+ TALLOC_FREE(result);
+ goto out;
+ }
+ result->basic_restriction = restr;
+out:
+ return result;
+}
+
+static struct wsp_crestriction *create_restriction(TALLOC_CTX *ctx,
+ t_basic_query *query)
+{
+ struct wsp_crestriction *crestriction = NULL;
+ struct wsp_cfullpropspec *prop = NULL;
+ t_basic_restr *restr = NULL;
+ t_value_holder *src = NULL;
+ crestriction = talloc_zero(ctx, struct wsp_crestriction);
+ if (crestriction == NULL) {
+ DBG_ERR("out of memory\n");
+ goto done;
+ }
+
+ restr = query->basic_restriction;
+ src = restr->values;
+
+ if (restr->prop_type == RTNONE) {
+ /* shouldn't end up here */
+ DBG_ERR("Unexpected t_basic_restr type\n");
+ TALLOC_FREE(crestriction);
+ goto done;
+ }
+
+ crestriction->weight = 1000;
+
+ if (restr->prop_type == RTCONTENT) {
+ struct wsp_ccontentrestriction *content = NULL;
+ crestriction->ultype = RTCONTENT;
+ if (src->type != STRING) {
+ DBG_ERR("expected string value for %s\n",
+ query->prop);
+ TALLOC_FREE(crestriction);
+ goto done;
+ }
+ content = &crestriction->restriction.ccontentrestriction;
+ content->pwcsphrase = src->value.string;
+ content->cc = strlen(src->value.string);
+ /*
+ * In the future we might generate the lcid from
+ * environ (or config)
+ */
+ content->lcid = WSP_DEFAULT_LCID;
+ if (restr->op == eEQUALS) {
+ content->ulgeneratemethod = 0;
+ } else {
+ content->ulgeneratemethod = 1;
+ }
+
+ prop = &content->property;
+ } else if (restr->prop_type == RTPROPERTY) {
+ struct wsp_cbasestoragevariant *dest =
+ &crestriction->restriction.cpropertyrestriction.prval;
+ crestriction->ultype = RTPROPERTY;
+ if (!process_prop_value(ctx, query->prop_info, src, dest)) {
+ DBG_ERR("Failed to process value for property %s\n",
+ query->prop);
+ TALLOC_FREE(crestriction);
+ goto done;
+ }
+ crestriction->restriction.cpropertyrestriction.relop =
+ restr->op;
+ prop = &crestriction->restriction.cpropertyrestriction.property;
+ } else {
+ TALLOC_FREE(crestriction);
+ goto done;
+ }
+ prop->guidpropset = query->guid;
+ prop->ulkind = PRSPEC_PROPID;
+ prop->name_or_id.prspec = query->prop_info->id;
+done:
+ return crestriction;
+}
+
+/* expands restr_node into a tree of t_query nodes */
+static void build_query(TALLOC_CTX *ctx, t_query *node, t_restr *restr_node,
+ const char* prop)
+{
+ if (!node) {
+ return;
+ }
+ if (!restr_node) {
+ return;
+ }
+
+ node->type = restr_node->type;
+
+ if (restr_node->left) {
+ node->left = talloc_zero(ctx, t_query);
+ SMB_ASSERT(node->left != NULL);
+ build_query(ctx, node->left, restr_node->left, prop);
+ }
+
+ if (restr_node->right) {
+ node->right = talloc_zero(ctx, t_query);
+ SMB_ASSERT(node->right != NULL);
+ build_query(ctx, node->right, restr_node->right, prop);
+ }
+
+ if (restr_node->type == eVALUE) {
+ node->restriction =
+ create_restriction(ctx,
+ create_basic_query(ctx,
+ prop,
+ restr_node->basic_restr));
+ }
+}
+
+t_query *create_query_node(TALLOC_CTX *ctx, t_nodetype op, t_query *left, t_query *right, t_basic_query *value)
+{
+ t_query *result = talloc_zero(ctx, t_query);
+ if (result == NULL) {
+ return result;
+ }
+ result->type = op;
+ result->left = left;
+ result->right = right;
+ if (op == eVALUE) {
+ t_basic_restr *restr = value->basic_restriction;
+ /* expand restr node */
+ if (restr->values->type == RESTR) {
+ build_query(ctx,
+ result,
+ restr->values->value.restr_tree,
+ value->prop);
+ } else {
+ result->restriction =
+ create_restriction(ctx, value);
+ if (!result->restriction) {
+ TALLOC_FREE(result);
+ }
+ }
+ }
+ return result;
+}
+
+t_restr *create_restr(TALLOC_CTX *ctx, t_nodetype op, t_restr *left, t_restr *right, t_basic_restr *value)
+{
+ t_restr *result = talloc_zero(ctx, t_restr);
+ if (result == NULL) {
+ return result;
+ }
+ result->type = op;
+ result->right = right;
+ result->left = left;
+ result->basic_restr = value;
+ return result;
+}
+
+t_value_holder *create_string_val(TALLOC_CTX* ctx, const char *text)
+{
+ t_value_holder *result =
+ talloc_zero(ctx, t_value_holder);
+ if (result == NULL) {
+ DBG_ERR("out of memory\n");
+ return NULL;
+ }
+ result->value.string = text;
+ result->type = STRING;
+ return result;
+}
+
+t_value_holder *create_num_val(TALLOC_CTX* ctx, int64_t val)
+{
+ t_value_holder *result =
+ talloc_zero(ctx, t_value_holder);
+
+ if (result == NULL) {
+ DBG_ERR("out of memory\n");
+ return NULL;
+ }
+
+ result->type = NUMBER;
+ result->value.number = val;
+ return result;
+}
+
+t_value_holder *create_bool_val(TALLOC_CTX* ctx, bool val)
+{
+ t_value_holder *result =
+ talloc_zero(ctx, t_value_holder);
+
+ if (result == NULL) {
+ DBG_ERR("out of memory\n");
+ return NULL;
+ }
+
+ result->type = BOOL;
+ result->value.boolean = val;
+ return result;
+}
+
+t_value_holder *create_value_range(TALLOC_CTX* ctx,
+ t_value_holder *left,
+ t_value_holder *right)
+{
+ t_value_holder *result =
+ talloc_zero(ctx, t_value_holder);
+
+ if (result == NULL) {
+ DBG_ERR("out of memory\n");
+ return NULL;
+ }
+
+ result->type = VALUE_RANGE;
+ result->value.value_range = talloc_zero(result, struct value_range);
+ if (!result->value.value_range) {
+ TALLOC_FREE(result);
+ goto out;
+ }
+ result->value.value_range->lower = left;
+ result->value.value_range->upper = right;
+out:
+ return result;
+}
+
+static void zero_time(struct tm *tm)
+{
+ tm->tm_hour = 0;
+ tm->tm_min = 0;
+ tm->tm_sec = 0;
+}
+
+typedef bool (*daterange_func) (TALLOC_CTX *ctx, uint64_t *date1,
+ uint64_t *date2);
+
+
+static bool create_date_range(TALLOC_CTX *ctx, uint64_t *date1,
+ uint64_t *date2,
+ int32_t lower_mday_adj,
+ int32_t lower_mon_adj,
+ int32_t upper_mday_adj,
+ int32_t upper_mon_adj)
+{
+ struct tm tm_now;
+ time_t now;
+
+ struct tm tm_tmp;
+ time_t lower;
+ time_t upper;
+
+ time(&now);
+ gmtime_r(&now, &tm_now);
+
+ tm_tmp = tm_now;
+ zero_time(&tm_tmp);
+ tm_tmp.tm_mday += lower_mday_adj;
+ tm_tmp.tm_mon += lower_mon_adj;
+ lower = mktime(&tm_tmp);
+ tm_tmp = tm_now;
+ zero_time(&tm_tmp);
+ tm_tmp.tm_mday += upper_mday_adj;
+ tm_tmp.tm_mon += upper_mon_adj;
+ upper = mktime(&tm_tmp);
+ unix_to_nt_time(date1, lower);
+ unix_to_nt_time(date2, upper);
+ return true;
+}
+
+static void get_now_tm(struct tm *tm_now)
+{
+ time_t now;
+ time(&now);
+ gmtime_r(&now, tm_now);
+}
+
+static bool create_thismonth_range(TALLOC_CTX *ctx, uint64_t *date1,
+ uint64_t *date2)
+{
+ struct tm tm_now;
+ int32_t firstofmonth_adj;
+
+ get_now_tm(&tm_now);
+ firstofmonth_adj = 1 - tm_now.tm_mday;
+ return create_date_range(ctx, date1,
+ date2, firstofmonth_adj,
+ 0, firstofmonth_adj, 1);
+}
+
+static bool create_lastyear_range(TALLOC_CTX *ctx, uint64_t *date1,
+ uint64_t *date2)
+{
+ struct tm tm_now;
+ int32_t firstofmonth_adj;
+ int32_t january_adj;
+ get_now_tm(&tm_now);
+
+ firstofmonth_adj = 1 - tm_now.tm_mday;
+ january_adj = -tm_now.tm_mon;
+ return create_date_range(ctx, date1,
+ date2, firstofmonth_adj,
+ january_adj - 12, firstofmonth_adj, january_adj);
+}
+
+static bool create_thisyear_range(TALLOC_CTX *ctx, uint64_t *date1,
+ uint64_t *date2)
+{
+ struct tm tm_now;
+ int32_t firstofmonth_adj;
+ int32_t january_adj;
+
+ get_now_tm(&tm_now);
+
+ firstofmonth_adj = 1 - tm_now.tm_mday;
+ january_adj = -tm_now.tm_mon;
+ return create_date_range(ctx, date1,
+ date2, firstofmonth_adj,
+ january_adj, firstofmonth_adj, january_adj + 12);
+}
+
+static bool create_lastmonth_range(TALLOC_CTX *ctx, uint64_t *date1,
+ uint64_t *date2)
+{
+ struct tm tm_now;
+ int32_t firstofmonth_adj;
+ get_now_tm(&tm_now);
+
+ firstofmonth_adj = 1 - tm_now.tm_mday;
+ return create_date_range(ctx, date1,
+ date2, firstofmonth_adj,
+ -1, firstofmonth_adj, 0);
+}
+
+static bool create_today_range(TALLOC_CTX *ctx, uint64_t *date1,
+ uint64_t *date2)
+{
+ return create_date_range(ctx, date1,
+ date2, 0, 0, 1, 0);
+}
+
+static bool create_yesterday_range(TALLOC_CTX *ctx, uint64_t *date1,
+ uint64_t *date2)
+{
+ return create_date_range(ctx, date1,
+ date2, -1, 0, 0, 0);
+}
+
+static bool create_thisweek_range(TALLOC_CTX *ctx, uint64_t *date1,
+ uint64_t *date2)
+{
+ struct tm tm_now;
+ time_t now;
+ int32_t startofweek_adj;
+ time(&now);
+ gmtime_r(&now, &tm_now);
+ if (tm_now.tm_wday) {
+ startofweek_adj = 1 - tm_now.tm_wday;
+ } else {
+ startofweek_adj = -6;
+ }
+ /* lower will be the start of this week */
+ return create_date_range(ctx, date1,
+ date2, startofweek_adj,
+ 0, startofweek_adj + 7, 0);
+}
+
+static bool create_lastweek_range(TALLOC_CTX *ctx, uint64_t *date1,
+ uint64_t *date2)
+{
+ struct tm tm_now;
+ time_t now;
+ int32_t startofweek_adj;
+ time(&now);
+ gmtime_r(&now, &tm_now);
+ if (tm_now.tm_wday) {
+ startofweek_adj = 1 - tm_now.tm_wday;
+ } else {
+ startofweek_adj = -6;
+ }
+ /* upper will be the start of this week */
+ return create_date_range(ctx, date1,
+ date2, startofweek_adj - 7,
+ 0,startofweek_adj, 0);
+}
+
+t_value_holder *create_date_range_shortcut(TALLOC_CTX *ctx,
+ daterange_type daterange)
+{
+ int i;
+ static const struct {
+ daterange_type range;
+ daterange_func create_fn;
+ } date_conv_map[] = {
+ {eYESTERDAY, create_yesterday_range},
+ {eTODAY, create_today_range},
+ {eTHISMONTH, create_thismonth_range},
+ {eLASTMONTH, create_lastmonth_range},
+ {eTHISWEEK, create_thisweek_range},
+ {eLASTWEEK, create_lastweek_range},
+ {eTHISYEAR, create_thisyear_range},
+ {eLASTYEAR, create_lastyear_range},
+ };
+ t_value_holder *result = NULL;
+ t_value_holder *lower = NULL;
+ t_value_holder *upper = NULL;
+
+ lower = talloc_zero(ctx, t_value_holder);
+ if (lower == NULL) {
+ DBG_ERR("out of memory\n");
+ goto out;
+ }
+
+ upper = talloc_zero(ctx, t_value_holder);
+ if (upper == NULL) {
+ DBG_ERR("out of memory\n");
+ goto out;
+ }
+
+ result = create_value_range(result, lower, upper);
+
+ if (result == NULL) {
+ TALLOC_FREE(result);
+ goto out;
+ }
+
+ lower->type = NUMBER;
+ upper->type = NUMBER;
+
+ result->value.value_range->lower = lower;
+ result->value.value_range->upper = upper;
+
+ for (i = 0; i < ARRAY_SIZE(date_conv_map); i++) {
+ if (date_conv_map[i].range == daterange) {
+ if (!date_conv_map[i].create_fn(result,
+ &lower->value.number,
+ &upper->value.number)) {
+ TALLOC_FREE(result);
+ break;
+ }
+ break;
+ }
+ }
+out:
+ return result;
+}
+
+t_value_holder *create_size_range_shortcut(TALLOC_CTX *ctx,
+ sizerange_type sizerange)
+{
+ static const struct {
+ sizerange_type range;
+ uint32_t lower;
+ uint32_t upper;
+ } sizes[] = {
+ {eEMPTY, 0x0, 0x1},
+ {eTINY, 0x1, 0x2801},
+ {eSMALL, 0x2801, 0x19001},
+ {eMEDIUM, 0x19001, 0x100001},
+ {eLARGE, 0x100001, 0x10000001},
+ {eHUGE, 0x10000001, 0x80000001},
+ {eGIGANTIC, 0x80000001, 0} /* special case not a range */
+ };
+ int i;
+ t_value_holder *result = NULL;
+ uint32_t lower_size;
+ uint32_t upper_size;
+ bool rangefound = false;
+ t_value_holder *left = NULL;
+ t_value_holder *right = NULL;
+ for (i = 0; i < ARRAY_SIZE(sizes); i++) {
+ if (sizes[i].range == sizerange) {
+ result = talloc_zero(ctx, t_value_holder);
+ if (result == NULL) {
+ DBG_ERR("out of memory\n");
+ return NULL;
+ }
+ lower_size = sizes[i].lower;
+ upper_size = sizes[i].upper;
+ rangefound = true;
+ break;
+ }
+ }
+
+ if (!rangefound) {
+ return NULL;
+ }
+
+ left = talloc_zero(ctx, t_value_holder);
+
+ if (left == NULL) {
+ return NULL;
+ }
+
+ left->type = NUMBER;
+ left->value.number = lower_size;
+
+ if (upper_size) {
+ right = talloc_zero(ctx, t_value_holder);
+ if (right == NULL) {
+ return NULL;
+ }
+ right->type = NUMBER;
+ right->value.number = upper_size;
+ }
+
+ result = create_value_range(ctx, left, right);
+ return result;
+}
diff --git a/libcli/wsp/wsp_aqs.h b/libcli/wsp/wsp_aqs.h
new file mode 100644
index 0000000..b34dd52
--- /dev/null
+++ b/libcli/wsp/wsp_aqs.h
@@ -0,0 +1,166 @@
+/*
+ * Window Search Service
+ *
+ * Copyright (c) Noel Power
+ *
+ * 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/>.
+ */
+
+#ifndef __WSP_AQS_H__
+#define __WSP_AQS_H__
+#include "librpc/gen_ndr/wsp.h"
+
+typedef enum nodetype
+{
+ eAND,
+ eOR,
+ eNOT,
+ eVALUE,
+} t_nodetype;
+
+typedef enum op
+{
+ eLT = PRLT,
+ eLE = PRLE,
+ eGT = PRGT,
+ eGE = PRGE,
+ eEQ = PREQ,
+ eNE = PRNE,
+ eSTARTSWITH,
+ eEQUALS,
+ /*
+ * eMATCHES,
+ *
+ * not sure we can express the above in the grammar without
+ * some custom operator :/
+ */
+} t_optype;
+
+struct restr;
+
+typedef enum {
+ NUMBER,
+ STRING,
+ BOOL,
+ RESTR,
+ VALUE_RANGE,
+} value_type;
+
+typedef enum {
+ eTODAY,
+ eYESTERDAY,
+ eLASTWEEK,
+ eTHISWEEK,
+ eTHISMONTH,
+ eLASTMONTH,
+ eTHISYEAR,
+ eLASTYEAR,
+} daterange_type;
+
+typedef enum {
+ eEMPTY,
+ eTINY,
+ eSMALL,
+ eMEDIUM,
+ eLARGE,
+ eHUGE,
+ eGIGANTIC,
+} sizerange_type;
+
+struct value_range;
+
+typedef struct {
+ value_type type;
+ union {
+ bool boolean;
+ const char *string;
+ uint64_t number;
+ struct restr *restr_tree;
+ struct value_range *value_range;
+ } value;
+} t_value_holder;
+
+struct value_range
+{
+ t_value_holder *lower;
+ t_value_holder *upper;
+};
+typedef struct basic_restr
+{
+ uint32_t prop_type;
+ t_optype op;
+ t_value_holder *values;
+} t_basic_restr;
+
+typedef struct basic_query
+{
+ struct GUID guid;
+ const struct full_propset_info *prop_info;
+ char *prop;
+ t_basic_restr *basic_restriction;
+} t_basic_query;
+
+t_basic_query *create_basic_query(TALLOC_CTX *ctx, const char *prop, t_basic_restr *restr);
+
+typedef struct restr
+{
+ t_nodetype type;
+ struct restr *left;
+ struct restr *right;
+ t_basic_restr *basic_restr;
+} t_restr;
+
+t_restr *create_restr(TALLOC_CTX *ctx, t_nodetype op, t_restr *left, t_restr *right, t_basic_restr *value);
+
+t_basic_restr *create_basic_restr(TALLOC_CTX *ctx,
+ uint32_t prop_type,
+ t_optype op,
+ t_value_holder *values);
+
+typedef struct query
+{
+ t_nodetype type;
+ struct query *left;
+ struct query *right;
+ struct wsp_crestriction *restriction;
+} t_query;
+
+t_query *create_query_node(TALLOC_CTX *ctx, t_nodetype op, t_query *left, t_query *right, t_basic_query *value);
+
+
+typedef struct col_list {
+ int num_cols;
+ char **cols;
+} t_col_list;
+
+typedef struct select_stmt {
+ t_col_list *cols;
+ t_query *where;
+} t_select_stmt;
+
+t_col_list *create_cols(TALLOC_CTX *ctx, const char *col, t_col_list *append_list);
+t_select_stmt *create_select(TALLOC_CTX *ctx, t_col_list *cols, t_query *where);
+
+t_select_stmt *get_wsp_sql_tree(const char *expr);
+t_value_holder *create_string_val(TALLOC_CTX*, const char *text);
+t_value_holder *create_num_val(TALLOC_CTX*, int64_t val);
+t_value_holder *create_bool_val(TALLOC_CTX*, bool val);
+t_value_holder *create_value_range(TALLOC_CTX*,
+ t_value_holder *left,
+ t_value_holder *right);
+t_value_holder *create_date_range_shortcut(TALLOC_CTX *ctx,
+ daterange_type daterange);
+t_value_holder *create_size_range_shortcut(TALLOC_CTX *ctx,
+ sizerange_type size);
+#endif /* __WSP_AQS_H__ */
diff --git a/libcli/wsp/wsp_aqs_lexer.l b/libcli/wsp/wsp_aqs_lexer.l
new file mode 100644
index 0000000..dff4c10
--- /dev/null
+++ b/libcli/wsp/wsp_aqs_lexer.l
@@ -0,0 +1,152 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Window Search Service
+ *
+ * Copyright (c) Noel Power
+ *
+ * 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 "libcli/wsp/wsp_aqs.h"
+#include "libcli/wsp/wsp_aqs_parser.tab.h"
+
+
+#include <stdio.h>
+
+#define YY_NO_INPUT
+
+%}
+
+%option warn nodefault nounput
+
+%option reentrant noyywrap never-interactive nounistd
+%option bison-bridge
+
+LPAREN "("
+RPAREN ")"
+AND "AND"
+OR "OR"
+NOT "NOT"
+EQ "=="
+NE "!="
+GE ">="
+LE "<="
+LESS "<"
+GREATER ">"
+COMMA ","
+WHERE "WHERE"
+SELECT "SELECT"
+PROP_EQUALS ":"
+TRUE "true"
+FALSE "false"
+
+TODAY "today"
+YESTERDAY "yesterday"
+THISWEEK "thisweek"
+LASTWEEK "lastweek"
+THISMONTH "thismonth"
+LASTMONTH "lastmonth"
+THISYEAR "thisyear"
+LASTYEAR "lastyear"
+
+EMPTY "empty"
+TINY "tiny"
+SMALL "small"
+MEDIUM "medium"
+LARGE "large"
+HUGE "huge"
+GIGANTIC "gigantic"
+
+STARTS_WITH "$<"
+EQUALS "$="
+K "K"
+M "M"
+G "G"
+T "T"
+KB "KB"
+MB "MB"
+GB "GB"
+TB "TB"
+RANGE "-"
+
+
+NUMBER [0-9]+
+WS [ \r\n\t]*
+IDENTIFIER [a-z\."A-Z_][a-z\."A-Z_0-9]*
+STRING_LITERAL L?\"(\\.|[^\\"])*\"
+
+%%
+
+{WS} { /* Skip blanks. */ }
+
+{NUMBER} { sscanf(yytext, "%"PRId64, &yylval->num); return TOKEN_NUMBER; }
+
+{AND} { return TOKEN_AND; }
+{OR} { return TOKEN_OR; }
+{NOT} { return TOKEN_NOT; }
+{EQ} { return TOKEN_EQ; }
+{NE} { return TOKEN_NE; }
+{GE} { return TOKEN_GE; }
+{LE} { return TOKEN_LE; }
+{LESS} { return TOKEN_LT; }
+{GREATER} { return TOKEN_GT; }
+{LPAREN} { return TOKEN_LPAREN; }
+{RPAREN} { return TOKEN_RPAREN; }
+{COMMA} { return TOKEN_COMMA; }
+{WHERE} { return TOKEN_WHERE; }
+{SELECT} { return TOKEN_SELECT; }
+{TRUE} { return TOKEN_TRUE; }
+{FALSE} { return TOKEN_FALSE; }
+{PROP_EQUALS} { return TOKEN_PROP_EQUALS; }
+
+{STARTS_WITH} { return TOKEN_STARTS_WITH;}
+{EQUALS} { return TOKEN_EQUALS;}
+
+{K} { return TOKEN_K; }
+{M} { return TOKEN_M; }
+{G} { return TOKEN_G; }
+{T} { return TOKEN_T; }
+{KB} { return TOKEN_KB; }
+{MB} { return TOKEN_MB; }
+{GB} { return TOKEN_GB; }
+{TB} { return TOKEN_TB; }
+{RANGE} { return TOKEN_RANGE; }
+{TODAY} { return TOKEN_TODAY; }
+{YESTERDAY} { return TOKEN_YESTERDAY;}
+{THISWEEK} { return TOKEN_THISWEEK;}
+{LASTWEEK} { return TOKEN_LASTWEEK;}
+{THISMONTH} { return TOKEN_THISMONTH; }
+{LASTMONTH} { return TOKEN_LASTMONTH; }
+{THISYEAR} { return TOKEN_THISYEAR; }
+{LASTYEAR} { return TOKEN_LASTYEAR; }
+{EMPTY} { return TOKEN_EMPTY; }
+{TINY} { return TOKEN_TINY; }
+{SMALL} { return TOKEN_SMALL; }
+{MEDIUM} { return TOKEN_MEDIUM; }
+{LARGE} { return TOKEN_LARGE; }
+{HUGE} { return TOKEN_HUGE; }
+{GIGANTIC} { return TOKEN_GIGANTIC; }
+
+
+{STRING_LITERAL} { yylval->strval = talloc_asprintf(talloc_tos(), "%s", yytext); return TOKEN_STRING_LITERAL; }
+
+{IDENTIFIER} { yylval->strval = talloc_asprintf(talloc_tos(), "%s", yytext); return TOKEN_IDENTIFIER; }
+. { }
+
+%%
+
diff --git a/libcli/wsp/wsp_aqs_parser.y b/libcli/wsp/wsp_aqs_parser.y
new file mode 100644
index 0000000..2b0d7bd
--- /dev/null
+++ b/libcli/wsp/wsp_aqs_parser.y
@@ -0,0 +1,422 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Window Search Service
+ *
+ * Copyright (c) Noel Power
+ *
+ * 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 "libcli/wsp/wsp_aqs.h"
+#include "libcli/wsp/wsp_aqs_parser.tab.h"
+#include "libcli/wsp/wsp_aqs_lexer.h"
+
+static int yyerror(t_select_stmt **stmt, yyscan_t scanner, const char *msg)
+{
+ fprintf(stderr,"Error :%s\n",msg); return 0;
+}
+%}
+%code requires {
+
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+}
+
+%define api.pure
+%lex-param { yyscan_t scanner }
+%parse-param { t_select_stmt **select }
+%parse-param { yyscan_t scanner }
+
+%union {
+ char *strval;
+ int64_t num;
+ t_value_holder *value;
+ t_select_stmt *select_stmt;
+ t_select_stmt *query_stmt;
+ t_basic_restr *bas_rest;
+ t_basic_query *bas_query;
+ t_restr *restr;
+ t_query *query;
+ t_col_list *columns;
+ daterange_type daterange;
+ sizerange_type sizerange;
+ t_optype prop_op;
+}
+
+%left "AND" TOKEN_AND
+%left "OR" TOKEN_OR
+%left "!=" TOKEN_NE
+%left ">=" TOKEN_GE
+%left "<=" TOKEN_LE
+%left "<" TOKEN_LT
+%left ">" TOKEN_GT
+%right "NOT" TOKEN_NOT
+%right "==" TOKEN_EQ
+%right ":" TOKEN_PROP_EQUALS
+
+%right "$<" TOKEN_STARTS_WITH
+%right "$=" TOKEN_EQUALS
+
+%token TOKEN_LPAREN
+%token TOKEN_RPAREN
+%token TOKEN_AND
+%token TOKEN_OR
+%token TOKEN_WHERE
+%token TOKEN_SELECT
+%token TOKEN_TRUE
+%token TOKEN_FALSE
+%token TOKEN_COMMA
+%token TOKEN_STARTS_WITH
+%token TOKEN_EQUALS
+%token TOKEN_MATCHES
+%token TOKEN_K
+%token TOKEN_M
+%token TOKEN_G
+%token TOKEN_T
+%token TOKEN_KB
+%token TOKEN_MB
+%token TOKEN_GB
+%token TOKEN_TB
+%token TOKEN_RANGE
+%token TOKEN_TODAY
+%token TOKEN_YESTERDAY
+%token TOKEN_THISWEEK
+%token TOKEN_LASTWEEK
+%token TOKEN_THISMONTH
+%token TOKEN_LASTMONTH
+%token TOKEN_THISYEAR
+%token TOKEN_LASTYEAR
+%token TOKEN_EMPTY
+%token TOKEN_TINY
+%token TOKEN_SMALL
+%token TOKEN_MEDIUM
+%token TOKEN_LARGE
+%token TOKEN_HUGE
+%token TOKEN_GIGANTIC
+
+%token <num> TOKEN_NUMBER
+%token <strval> TOKEN_IDENTIFIER
+%token <strval> TOKEN_STRING_LITERAL
+
+%type <strval> prop
+%type <bas_rest> basic_restr
+%type <restr> restr
+%type <bas_query> basic_query
+%type <query> query
+%type <columns> cols
+%type <strval> col
+%type <select_stmt> select_stmt
+%type <value> simple_value
+%type <value> value
+%type <daterange> date_shortcut
+%type <prop_op> property_op
+%type <prop_op> content_op
+%type <sizerange> size_shortcut
+
+%%
+
+input:
+ select_stmt {
+ *select = $1;
+ }
+;
+
+select_stmt:
+ TOKEN_SELECT cols[C] TOKEN_WHERE query[Q] {
+ $$ = create_select(talloc_tos(), $C, $Q );
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | query[Q] {
+ $$ = create_select(talloc_tos(), NULL, $Q );
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ ;
+
+cols :
+ col[C] {
+ $$ = create_cols(talloc_tos(), $1, NULL);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | col[C] TOKEN_COMMA cols[CS] {
+ $$ = create_cols(talloc_tos(), $C, $CS);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ ;
+
+col:
+ TOKEN_IDENTIFIER[I] {
+ $$ = $I;
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ ;
+
+query:
+ basic_query {
+ $$ = create_query_node(talloc_tos(), eVALUE, NULL, NULL, $1);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_LPAREN query[Q] TOKEN_RPAREN {
+ $$ = $Q;
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | query[L] TOKEN_AND query[R] {
+ $$ = create_query_node(talloc_tos(), eAND, $L, $R, NULL);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | query[L] TOKEN_OR query[R] {
+ $$ = create_query_node(talloc_tos(), eOR, $L, $R, NULL);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_NOT query[R] {
+ $$ = create_query_node(talloc_tos(), eNOT, NULL, $R, NULL);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ ;
+
+basic_query:
+ prop[P] TOKEN_PROP_EQUALS basic_restr[V] {
+ $$ = create_basic_query(talloc_tos(), $P, $V);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ ;
+
+prop: TOKEN_IDENTIFIER[I] {
+ $$ = $I;
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ ;
+
+basic_restr:
+ value[V] {
+ $$ = create_basic_restr(talloc_tos(), RTPROPERTY, eEQ, $V);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | property_op[P] value[T] {
+ $$ = create_basic_restr(talloc_tos(), RTPROPERTY, $P, $T);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | content_op[P] value[T] {
+ $$ = create_basic_restr(talloc_tos(), RTCONTENT, $P, $T);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_LPAREN restr[R] TOKEN_RPAREN {
+ t_value_holder *holder = talloc_zero(talloc_tos(), t_value_holder);
+ holder->type = RESTR;
+ holder->value.restr_tree = $R;
+ $$ = create_basic_restr(talloc_tos(), RTNONE, eEQ, holder);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ ;
+
+property_op:
+ TOKEN_EQ { $$ = eEQ; }
+ | TOKEN_NE { $$ = eNE; }
+ | TOKEN_GE { $$ = eGE; }
+ | TOKEN_LE { $$ = eLE; }
+ | TOKEN_LT { $$ = eLT; }
+ | TOKEN_GT { $$ = eGT; }
+ ;
+
+content_op:
+ TOKEN_STARTS_WITH { $$ = eSTARTSWITH; }
+ | TOKEN_EQUALS { $$ = eEQUALS; }
+ ;
+
+value:
+ simple_value[V] { $$ = $V;}
+ | simple_value[L] TOKEN_RANGE simple_value[R] {
+ $$ = create_value_range(talloc_tos(), $L, $R);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | date_shortcut[D] {
+ $$ = create_date_range_shortcut(talloc_tos(), $D);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | size_shortcut[S] {
+ $$ = create_size_range_shortcut(talloc_tos(), $S);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ ;
+
+date_shortcut:
+ TOKEN_TODAY { $$ = eTODAY; }
+ | TOKEN_YESTERDAY { $$ = eYESTERDAY; }
+ | TOKEN_THISWEEK { $$ = eTHISWEEK; }
+ | TOKEN_LASTWEEK { $$ = eLASTWEEK; }
+ | TOKEN_THISMONTH { $$ = eTHISMONTH; }
+ | TOKEN_LASTMONTH { $$ = eTHISMONTH; }
+ | TOKEN_THISYEAR { $$ = eTHISYEAR; }
+ | TOKEN_LASTYEAR { $$ = eLASTYEAR; }
+ ;
+
+size_shortcut:
+ TOKEN_EMPTY { $$ = eEMPTY; }
+ | TOKEN_TINY { $$ = eTINY; }
+ | TOKEN_SMALL { $$ = eSMALL; }
+ | TOKEN_MEDIUM { $$ = eMEDIUM; }
+ | TOKEN_LARGE { $$ = eLARGE; }
+ | TOKEN_HUGE { $$ = eHUGE; }
+ | TOKEN_GIGANTIC { $$ = eGIGANTIC; }
+ ;
+
+simple_value:
+ TOKEN_NUMBER[N] {
+ $$ = create_num_val(talloc_tos(), $N);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_NUMBER[N] TOKEN_K {
+ $$ = create_num_val(talloc_tos(), $N * 1024);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_NUMBER[N] TOKEN_M {
+ $$ = create_num_val( talloc_tos(), $N * 1024 * 1024);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_NUMBER[N] TOKEN_G {
+ $$ = create_num_val(talloc_tos(), $N * 1024 * 1024 * 1024);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_NUMBER[N] TOKEN_T {
+ $$ = create_num_val(talloc_tos(),
+ $N * 1024 * 1024 * 1024 * 1024);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_NUMBER[N] TOKEN_KB {
+ $$ = create_num_val(talloc_tos(), $N * 1000);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_NUMBER[N] TOKEN_MB {
+ $$ = create_num_val( talloc_tos(), $N * 1000 * 1000);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_NUMBER[N] TOKEN_GB {
+ $$ = create_num_val(talloc_tos(), $N * 1000 * 1000 * 1000);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_NUMBER[N] TOKEN_TB {
+ $$ = create_num_val(talloc_tos(),
+ $N * 1000 * 1000 * 1000 * 1000);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_TRUE {
+ $$ = create_bool_val(talloc_tos(), true);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_FALSE {
+ $$ = create_num_val(talloc_tos(), false);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_STRING_LITERAL[S] {
+ char *tmp_str = talloc_strdup(talloc_tos(), $S+1);
+ tmp_str[strlen(tmp_str)-1] = '\0';
+ $$ = create_string_val(talloc_tos(), tmp_str);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_IDENTIFIER[I] {
+ $$ = create_string_val(talloc_tos(), $I);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ ;
+
+restr: basic_restr[V] {
+ $$ = create_restr(talloc_tos(), eVALUE, NULL, NULL, $V);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | restr[L] TOKEN_AND restr[R] {
+ $$ = create_restr(talloc_tos(), eAND, $L, $R, NULL);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | restr[L] TOKEN_OR restr[R] {
+ $$ = create_restr(talloc_tos(), eOR, $L, $R, NULL);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ ;
+%%