summaryrefslogtreecommitdiff
path: root/source4/libcli
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2003-08-13 01:53:07 +0000
committerAndrew Tridgell <tridge@samba.org>2003-08-13 01:53:07 +0000
commitef2e26c91b80556af033d3335e55f5dfa6fff31d (patch)
treefaa21bfd7e7b5247250b47c7891dc1a5ebee6be9 /source4/libcli
downloadsamba-ef2e26c91b80556af033d3335e55f5dfa6fff31d.tar.gz
samba-ef2e26c91b80556af033d3335e55f5dfa6fff31d.tar.bz2
samba-ef2e26c91b80556af033d3335e55f5dfa6fff31d.zip
first public release of samba4 code
(This used to be commit b0510b5428b3461aeb9bbe3cc95f62fc73e2b97f)
Diffstat (limited to 'source4/libcli')
-rw-r--r--source4/libcli/.cvsignore3
-rw-r--r--source4/libcli/cliconnect.c207
-rw-r--r--source4/libcli/clideltree.c117
-rw-r--r--source4/libcli/clidfs.c558
-rw-r--r--source4/libcli/clifile.c647
-rw-r--r--source4/libcli/clilist.c313
-rw-r--r--source4/libcli/climessage.c93
-rw-r--r--source4/libcli/clireadwrite.c155
-rw-r--r--source4/libcli/clisecdesc.c121
-rw-r--r--source4/libcli/clitrans2.c221
-rw-r--r--source4/libcli/namecache.c246
-rw-r--r--source4/libcli/namequery.c1333
-rw-r--r--source4/libcli/namequery_dc.c104
-rw-r--r--source4/libcli/nmblib.c1287
-rw-r--r--source4/libcli/ntlmssp.c625
-rw-r--r--source4/libcli/ntlmssp_parse.c303
-rw-r--r--source4/libcli/raw/README5
-rw-r--r--source4/libcli/raw/clikrb5.c399
-rw-r--r--source4/libcli/raw/clioplock.c57
-rw-r--r--source4/libcli/raw/clirewrite.c22
-rw-r--r--source4/libcli/raw/clisession.c444
-rw-r--r--source4/libcli/raw/clisocket.c148
-rw-r--r--source4/libcli/raw/clispnego.c533
-rw-r--r--source4/libcli/raw/clitransport.c218
-rw-r--r--source4/libcli/raw/clitree.c290
-rw-r--r--source4/libcli/raw/raweas.c147
-rw-r--r--source4/libcli/raw/rawfile.c687
-rw-r--r--source4/libcli/raw/rawfileinfo.c527
-rw-r--r--source4/libcli/raw/rawfsinfo.c282
-rw-r--r--source4/libcli/raw/rawioctl.c118
-rw-r--r--source4/libcli/raw/rawnegotiate.c157
-rw-r--r--source4/libcli/raw/rawnotify.c116
-rw-r--r--source4/libcli/raw/rawreadwrite.c321
-rw-r--r--source4/libcli/raw/rawrequest.c1019
-rw-r--r--source4/libcli/raw/rawsearch.c569
-rw-r--r--source4/libcli/raw/rawsetfileinfo.c335
-rw-r--r--source4/libcli/raw/rawtrans.c489
-rw-r--r--source4/libcli/raw/smb_signing.c341
-rw-r--r--source4/libcli/unexpected.c172
-rw-r--r--source4/libcli/util/asn1.c428
-rw-r--r--source4/libcli/util/clierror.c99
-rw-r--r--source4/libcli/util/cliutil.c110
-rw-r--r--source4/libcli/util/credentials.c215
-rw-r--r--source4/libcli/util/doserr.c91
-rw-r--r--source4/libcli/util/errormap.c1546
-rw-r--r--source4/libcli/util/nterr.c715
-rw-r--r--source4/libcli/util/ntlmssp_sign.c226
-rw-r--r--source4/libcli/util/pwd_cache.c72
-rw-r--r--source4/libcli/util/smbdes.c415
-rw-r--r--source4/libcli/util/smbencrypt.c418
-rw-r--r--source4/libcli/util/smberr.c181
51 files changed, 18245 insertions, 0 deletions
diff --git a/source4/libcli/.cvsignore b/source4/libcli/.cvsignore
new file mode 100644
index 0000000000..2588860f65
--- /dev/null
+++ b/source4/libcli/.cvsignore
@@ -0,0 +1,3 @@
+*.po
+*.po32
+
diff --git a/source4/libcli/cliconnect.c b/source4/libcli/cliconnect.c
new file mode 100644
index 0000000000..da8a842dae
--- /dev/null
+++ b/source4/libcli/cliconnect.c
@@ -0,0 +1,207 @@
+/*
+ Unix SMB/CIFS implementation.
+ client connect/disconnect routines
+ Copyright (C) Andrew Tridgell 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ wrapper around cli_sock_connect()
+*/
+BOOL cli_socket_connect(struct cli_state *cli, const char *server, struct in_addr *ip)
+{
+ struct cli_socket *sock;
+
+ sock = cli_sock_init();
+ if (!sock) return False;
+
+ if (!cli_sock_connect_byname(sock, server, 0)) {
+ cli_sock_close(sock);
+ return False;
+ }
+
+ cli->transport = cli_transport_init(sock);
+ if (!cli->transport) {
+ cli_sock_close(sock);
+ return False;
+ }
+
+ return True;
+}
+
+/* wrapper around cli_transport_connect() */
+BOOL cli_transport_establish(struct cli_state *cli,
+ struct nmb_name *calling,
+ struct nmb_name *called)
+{
+ return cli_transport_connect(cli->transport, calling, called);
+}
+
+/* wrapper around smb_raw_negotiate() */
+BOOL cli_negprot(struct cli_state *cli)
+{
+ NTSTATUS status;
+ status = smb_raw_negotiate(cli->transport);
+ return NT_STATUS_IS_OK(status);
+}
+
+/* wrapper around smb_raw_session_setup() */
+BOOL cli_session_setup(struct cli_state *cli,
+ const char *user,
+ const char *password,
+ const char *domain)
+{
+ union smb_sesssetup setup;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+
+ cli->session = cli_session_init(cli->transport);
+ if (!cli->session) return False;
+
+ mem_ctx = talloc_init("cli_session_setup");
+ if (!mem_ctx) return False;
+
+ setup.generic.level = RAW_SESSSETUP_GENERIC;
+ setup.generic.in.sesskey = cli->transport->negotiate.sesskey;
+ setup.generic.in.capabilities = CAP_UNICODE | CAP_STATUS32 |
+ CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
+ CAP_W2K_SMBS | CAP_LARGE_READX | CAP_LARGE_WRITEX;
+ setup.generic.in.password = password;
+ setup.generic.in.user = user;
+ setup.generic.in.domain = domain;
+
+ status = smb_raw_session_setup(cli->session, mem_ctx, &setup);
+
+ cli->session->vuid = setup.generic.out.vuid;
+
+ talloc_destroy(mem_ctx);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+/* wrapper around smb_tree_connect() */
+BOOL cli_send_tconX(struct cli_state *cli, const char *sharename, const char *devtype,
+ const char *password)
+{
+ union smb_tcon tcon;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+
+ cli->tree = cli_tree_init(cli->session);
+ if (!cli->tree) return False;
+
+ cli->tree->reference_count++;
+
+ /* setup a tree connect */
+ tcon.generic.level = RAW_TCON_TCONX;
+ tcon.tconx.in.flags = 0;
+ tcon.tconx.in.password = data_blob(password, strlen(password)+1);
+ tcon.tconx.in.path = sharename;
+ tcon.tconx.in.device = devtype;
+
+ mem_ctx = talloc_init("tcon");
+ if (!mem_ctx) {
+ return False;
+ }
+
+ status = smb_tree_connect(cli->tree, mem_ctx, &tcon);
+
+ cli->tree->tid = tcon.tconx.out.cnum;
+
+ talloc_destroy(mem_ctx);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+
+/*
+ easy way to get to a fully connected cli_state in one call
+*/
+NTSTATUS cli_full_connection(struct cli_state **ret_cli,
+ const char *myname,
+ const char *host,
+ struct in_addr *ip,
+ const char *sharename,
+ const char *devtype,
+ const char *username,
+ const char *domain,
+ const char *password,
+ uint_t flags,
+ BOOL *retry)
+{
+ struct cli_tree *tree;
+ NTSTATUS status;
+
+ *ret_cli = NULL;
+
+ status = cli_tree_full_connection(&tree, myname, host, 0, sharename, devtype,
+ username, domain, password);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ (*ret_cli) = cli_state_init();
+
+ (*ret_cli)->tree = tree;
+ (*ret_cli)->session = tree->session;
+ (*ret_cli)->transport = tree->session->transport;
+ tree->reference_count++;
+
+ return status;
+}
+
+
+/*
+ disconnect the tree
+*/
+BOOL cli_tdis(struct cli_state *cli)
+{
+ NTSTATUS status;
+ status = smb_tree_disconnect(cli->tree);
+ return NT_STATUS_IS_OK(status);
+}
+
+/****************************************************************************
+ Initialise a client state structure.
+****************************************************************************/
+struct cli_state *cli_state_init(void)
+{
+ struct cli_state *cli;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("cli_state");
+ if (!mem_ctx) return NULL;
+
+ cli = talloc_zero(mem_ctx, sizeof(*cli));
+ cli->mem_ctx = mem_ctx;
+
+ return cli;
+}
+
+/****************************************************************************
+ Shutdown a client structure.
+****************************************************************************/
+void cli_shutdown(struct cli_state *cli)
+{
+ if (!cli) return;
+ cli->tree->reference_count++;
+ cli_tree_close(cli->tree);
+ if (cli->mem_ctx) {
+ talloc_destroy(cli->mem_ctx);
+ }
+}
diff --git a/source4/libcli/clideltree.c b/source4/libcli/clideltree.c
new file mode 100644
index 0000000000..8769b8dfa7
--- /dev/null
+++ b/source4/libcli/clideltree.c
@@ -0,0 +1,117 @@
+/*
+ Unix SMB/CIFS implementation.
+ useful function for deleting a whole directory tree
+ Copyright (C) Andrew Tridgell 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+struct delete_state {
+ struct cli_state *cli;
+ int total_deleted;
+ BOOL failed;
+};
+
+/*
+ callback function for torture_deltree()
+*/
+static void delete_fn(file_info *finfo, const char *name, void *state)
+{
+ struct delete_state *dstate = state;
+ char *s, *n;
+ if (strcmp(finfo->name, ".") == 0 ||
+ strcmp(finfo->name, "..") == 0) return;
+
+ n = strdup(name);
+ n[strlen(n)-1] = 0;
+ asprintf(&s, "%s%s", n, finfo->name);
+
+ if (finfo->mode & FILE_ATTRIBUTE_READONLY) {
+ if (!cli_setatr(dstate->cli, s, 0, 0)) {
+ DEBUG(2,("Failed to remove READONLY on %s - %s\n",
+ s, cli_errstr(dstate->cli)));
+ }
+ }
+
+ if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
+ char *s2;
+ asprintf(&s2, "%s\\*", s);
+ cli_unlink(dstate->cli, s2);
+ cli_list(dstate->cli, s2,
+ FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM,
+ delete_fn, state);
+ free(s2);
+ if (!cli_rmdir(dstate->cli, s)) {
+ DEBUG(2,("Failed to delete %s - %s\n",
+ s, cli_errstr(dstate->cli)));
+ dstate->failed = True;
+ }
+ dstate->total_deleted++;
+ } else {
+ if (!cli_unlink(dstate->cli, s)) {
+ DEBUG(2,("Failed to delete %s - %s\n",
+ s, cli_errstr(dstate->cli)));
+ dstate->failed = True;
+ }
+ dstate->total_deleted++;
+ }
+ free(s);
+ free(n);
+}
+
+/*
+ recursively descend a tree deleting all files
+ returns the number of files deleted, or -1 on error
+*/
+int cli_deltree(struct cli_state *cli, const char *dname)
+{
+ char *mask;
+ struct delete_state dstate;
+
+ dstate.cli = cli;
+ dstate.total_deleted = 0;
+ dstate.failed = False;
+
+ /* it might be a file */
+ if (cli_unlink(cli, dname)) {
+ return 1;
+ }
+ if (NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
+ NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_OBJECT_PATH_NOT_FOUND) ||
+ NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_NO_SUCH_FILE)) {
+ return 0;
+ }
+
+ asprintf(&mask, "%s\\*", dname);
+ cli_unlink(cli, mask);
+ cli_list(dstate.cli, mask,
+ FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM,
+ delete_fn, &dstate);
+ free(mask);
+ if (!cli_rmdir(dstate.cli, dname)) {
+ DEBUG(2,("Failed to delete %s - %s\n",
+ dname, cli_errstr(dstate.cli)));
+ return -1;
+ }
+ dstate.total_deleted++;
+
+ if (dstate.failed) {
+ return -1;
+ }
+
+ return dstate.total_deleted;
+}
diff --git a/source4/libcli/clidfs.c b/source4/libcli/clidfs.c
new file mode 100644
index 0000000000..fc24cccf54
--- /dev/null
+++ b/source4/libcli/clidfs.c
@@ -0,0 +1,558 @@
+/*
+ Unix SMB/CIFS implementation.
+ Dfs routines
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+BOOL cli_client_initialize(struct cli_client* context,
+ const char* sockops,
+ char* username, char* password, char* workgroup,
+ int flags)
+{
+ int i;
+ for (i=0; i < DFS_MAX_CLUSTER_SIZE ; i++) {
+ context->cli[i] = cli_raw_initialise();
+ }
+ context->sockops = sockops;
+ context->username = username;
+ context->password = password;
+ context->workgroup = workgroup;
+ context->connection_flags = flags;
+ if (flags & CLI_FULL_CONNECTION_USE_DFS)
+ context->use_dfs = True;
+ context->number_members = DFS_MAX_CLUSTER_SIZE;
+ return True;
+}
+
+/****************************************************************************
+ Interpret a Dfs referral structure.
+ The length of the structure is returned
+ The structure of a Dfs referral depends on the info level.
+****************************************************************************/
+
+static int interpret_referral(struct cli_state *cli,
+ int level,char *p,referral_info *rinfo)
+{
+ char* q;
+ int version, size;
+
+ version = SVAL(p,0);
+ size = SVAL(p,2);
+ rinfo->server_type = SVAL(p,4);
+ rinfo->referral_flags = SVAL(p,6);
+ rinfo->proximity = SVAL(p,8);
+ rinfo->ttl = SVAL(p,10);
+ rinfo->pathOffset = SVAL(p,12);
+ rinfo->altPathOffset = SVAL(p,14);
+ rinfo->nodeOffset = SVAL(p,16);
+ DEBUG(3,("referral version=%d, size=%d, server_type=%d, flags=0x%x, proximity=%d, ttl=%d, pathOffset=%d, altPathOffset=%d, nodeOffset=%d\n",
+ version, size, rinfo->server_type, rinfo->referral_flags,
+ rinfo->proximity, rinfo->ttl, rinfo->pathOffset,
+ rinfo->altPathOffset, rinfo->nodeOffset));
+
+ q = (char*)(p + (rinfo->pathOffset));
+ //printf("p=%p, q=%p, offset=%d\n", p, q, rinfo->pathOffset);
+ //printf("hex=0x%x, string=%s\n", q, q);
+ clistr_pull(cli, rinfo->path, q,
+ sizeof(rinfo->path),
+ -1, STR_TERMINATE);
+ DEBUG(4,("referral path=%s\n", rinfo->path));
+ q = (char*)(p + (rinfo->altPathOffset)/sizeof(char));
+ if (rinfo->altPathOffset > 0)
+ clistr_pull(cli, rinfo->altPath, q,
+ sizeof(rinfo->altPath),
+ -1, STR_TERMINATE);
+ DEBUG(4,("referral alt path=%s\n", rinfo->altPath));
+ q = (char*)(p + (rinfo->nodeOffset)/sizeof(char));
+ if (rinfo->nodeOffset > 0)
+ clistr_pull(cli, rinfo->node, q,
+ sizeof(rinfo->node),
+ -1, STR_TERMINATE);
+ DEBUG(4,("referral node=%s\n", rinfo->node));
+ fstrcpy(rinfo->host, &rinfo->node[1]);
+ p = strchr_m(&rinfo->host[1],'\\');
+ if (!p) {
+ printf("invalid referral node %s\n", rinfo->node);
+ return -1;
+ }
+ *p = 0;
+ rinfo->share = talloc_strdup(cli->mem_ctx, p+1);
+ DEBUG(3,("referral host=%s share=%s\n",
+ rinfo->host, rinfo->share));
+ return size;
+}
+
+#if 0
+int cli_select_dfs_referral(struct cli_state *cli, dfs_info* dinfo)
+{
+ return (int)sys_random()%dinfo->number_referrals;
+}
+
+int cli_get_dfs_referral(struct cli_state *cli,const char *Fname, dfs_info* dinfo)
+{
+ struct smb_trans2 parms;
+ int info_level;
+ char *p;
+ pstring fname;
+ int i;
+ char *rparam=NULL, *rdata=NULL;
+ int param_len, data_len;
+ uint16 setup;
+ pstring param;
+ DATA_BLOB trans_param, trans_data;
+
+ /* NT uses 260, OS/2 uses 2. Both accept 1. */
+ info_level = (cli->capabilities&CAP_NT_SMBS)?260:1;
+
+ pstrcpy(fname,Fname);
+
+ setup = TRANSACT2_GET_DFS_REFERRAL ;
+ SSVAL(param,0,CLI_DFS_MAX_REFERRAL_LEVEL); /* attribute */
+ p = param+2;
+ p += clistr_push(cli, param+2, fname, -1,
+ STR_TERMINATE);
+
+ param_len = PTR_DIFF(p, param);
+ DEBUG(3,("cli_get_dfs_referral: sending request\n"));
+
+ trans_param.length = param_len;
+ trans_param.data = param;
+ trans_data.length = 0;
+ trans_data.data = NULL;
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* Name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ &trans_param, 10, /* param, length, max */
+ &trans_data,
+ cli->max_xmit /* data, length, max */
+ )) {
+ return 0;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len) &&
+ cli_is_dos_error(cli)) {
+ return 0;
+ }
+ //printf("cli_get_dfs_referral: received response, rdata=%p, rparam=%p\n",
+ // rdata, rparam);
+
+ if (cli_is_error(cli) || !rdata)
+ return 0;
+
+ /* parse out some important return info */
+ //printf("cli_get_dfs_referral: valid response\n");
+ p = rdata;
+ dinfo->path_consumed = SVAL(p,0);
+ dinfo->number_referrals = SVAL(p,2);
+ dinfo->referral_flags = SVAL(p,4);
+ DEBUG(3,("cli_get_dfs_referral: path_consumed=%d, # referrals=%d, flags=0x%x\n",
+ dinfo->path_consumed, dinfo->number_referrals,
+ dinfo->referral_flags));
+
+ /* point to the referral bytes */
+ p+=8;
+ for (i=0; i < dinfo->number_referrals; i++) {
+ p += interpret_referral(cli,info_level,p,&dinfo->referrals[i]);
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ DEBUG(3,("received %d Dfs referrals\n",
+ dinfo->number_referrals));
+
+ dinfo->selected_referral = cli_select_dfs_referral(cli, dinfo);
+ DEBUG(3, ("selected Dfs referral %d %s\n",
+ dinfo->selected_referral, dinfo->referrals[dinfo->selected_referral].node));
+
+ return(dinfo->number_referrals);
+}
+#endif
+
+/* check if the server produced Dfs redirect */
+BOOL cli_check_dfs_redirect(struct cli_state* c, char* fname,
+ dfs_info* dinfo)
+{
+ //printf("check_dfs_redirect: error %s\n",
+ // cli_errstr(c));
+ if (cli_is_dos_error(c)) {
+ printf("got dos error\n");
+ return False;
+
+ } else {
+ NTSTATUS status;
+
+ /* Check NT error */
+
+ status = cli_nt_error(c);
+ //printf("got nt error 0x%x\n", status);
+
+ if (NT_STATUS_V(NT_STATUS_PATH_NOT_COVERED) != NT_STATUS_V(status)) {
+ return False;
+ }
+ }
+ /* execute trans2 getdfsreferral */
+ //printf("check_dfs_redirect: process referral\n");
+ //cli_get_dfs_referral(c, fname, dinfo);
+ return True;
+}
+
+int cli_dfs_open_connection(struct cli_client* cluster,
+ char* host, char* share, int flags)
+{
+ int i;
+ BOOL retry;
+ struct cli_state* c;
+
+ // check if already connected
+ for (i=0; i < DFS_MAX_CLUSTER_SIZE; i++) {
+ if (cluster->cli[i]->in_use && strequal(host, cli_state_get_host(cluster->cli[i]))
+ && strequal(share, cli_state_get_share(cluster->cli[i]))) {
+ DEBUG(3,("cli_dfs_open_connection: already connected to \\\\%s\\%s\n", host, share));
+ return i;
+ }
+ }
+ // open connection
+ DEBUG(3,("cli_dfs_open_connection: opening \\\\%s\\%s %s@%s\n",
+ host, share, cluster->username, cluster->workgroup));
+ for (i=0; i < DFS_MAX_CLUSTER_SIZE; i++) {
+ if (!cluster->cli[i]->in_use) {
+ break;
+ }
+ }
+ if (i >= DFS_MAX_CLUSTER_SIZE)
+ return -1;
+
+ c = cluster->cli[i];
+ if (NT_STATUS_IS_ERR(cli_full_connection(&c,
+ NULL, host, NULL, 0,
+ share, "?????",
+ cluster->username, cluster->workgroup,
+ cluster->password, flags,
+ &retry)))
+ return -1;
+ cli_state_set_sockopt(cluster->cli[i], cluster->sockops);
+ cli_state_set_host(cluster->cli[i], host);
+ cli_state_set_share(cluster->cli[i], share);
+ cluster->cli[i]->in_use = True;
+ DEBUG(3,("cli_dfs_open_connection: connected \\\\%s\\%s (%d) %s@%s\n",
+ cli_state_get_host(cluster->cli[i]), cli_state_get_share(cluster->cli[i]), i,
+ cluster->username, cluster->workgroup));
+
+ return i;
+}
+
+/**********************************************************************
+ Parse the pathname of the form \hostname\service\reqpath
+ into the dfs_path structure
+ **********************************************************************/
+
+BOOL cli_parse_dfs_path(char* pathname, struct dfs_path* pdp)
+{
+ pstring pathname_local;
+ char* p,*temp;
+
+ pstrcpy(pathname_local,pathname);
+ p = temp = pathname_local;
+
+ ZERO_STRUCTP(pdp);
+
+ trim_string(temp,"\\","\\");
+ DEBUG(10,("temp in cli_parse_dfs_path: .%s. after trimming \\'s\n",temp));
+
+ /* now tokenize */
+ /* parse out hostname */
+ p = strchr(temp,'\\');
+ if(p == NULL)
+ return False;
+ *p = '\0';
+ pstrcpy(pdp->hostname,temp);
+ DEBUG(10,("hostname: %s\n",pdp->hostname));
+
+ /* parse out servicename */
+ temp = p+1;
+ p = strchr(temp,'\\');
+ if(p == NULL) {
+ pstrcpy(pdp->servicename,temp);
+ pdp->reqpath[0] = '\0';
+ return True;
+ }
+ *p = '\0';
+ pstrcpy(pdp->servicename,temp);
+ DEBUG(10,("servicename: %s\n",pdp->servicename));
+
+ /* rest is reqpath */
+ pstrcpy(pdp->reqpath, p+1);
+
+ DEBUG(10,("rest of the path: %s\n",pdp->reqpath));
+ return True;
+}
+
+char* rebuild_filename(char *referral_fname, struct cli_state* c,
+ char* fname, int path_consumed)
+{
+ const char *template = "\\\\%s\\%s\\%s";
+ struct dfs_path dp;
+
+ // TODO: handle consumed length
+ DEBUG(3,("rebuild_filename: %s, %d consumed of %d\n",
+ fname, path_consumed, strlen(fname)));
+ if (cli_parse_dfs_path(fname, &dp)) {
+ DEBUG(3,("rebuild_filename: reqpath=%s\n",
+ dp.reqpath));
+ asprintf(&referral_fname,
+ template, cli_state_get_host(c),
+ cli_state_get_share(c), dp.reqpath);
+ }
+ else
+ return NULL;
+ DEBUG(3,("rebuild_filename: %s -> %s\n", fname, referral_fname));
+ return referral_fname;
+}
+
+/****************************************************************************
+ Open a file (allowing for Dfs referral).
+****************************************************************************/
+
+int cli_dfs_open(struct cli_client* cluster, int *server,
+ char *fname_src, int flags, int share_mode)
+{
+ int referral_number;
+ dfs_info dinfo;
+ char *referral_fname;
+ int fnum;
+
+ DEBUG(3,("cli_dfs_open: open %s on server %s(%d)\n",
+ fname_src, cli_state_get_host(cluster->cli[*server]), *server));
+ cluster->cli[*server]->dfs_referral = *server;
+ if ((fnum = cli_open(cluster->cli[*server], fname_src, flags, share_mode)) < 0) {
+ if (cli_check_dfs_redirect(cluster->cli[*server], fname_src, &dinfo)) {
+ // choose referral, check if already connected, open if not
+ referral_number = dinfo.selected_referral;
+ DEBUG(3,("cli_dfs_open: redirecting to %s\n", dinfo.referrals[referral_number].node));
+ cluster->cli[*server]->dfs_referral = cli_dfs_open_connection(cluster,
+ dinfo.referrals[referral_number].host,
+ dinfo.referrals[referral_number].share,
+ cluster->connection_flags);
+ *server = cluster->cli[*server]->dfs_referral;
+ if (server < 0)
+ return False;
+ // rebuild file name and retry operation.
+ if (rebuild_filename(referral_fname, cluster->cli[*server], fname_src, dinfo.path_consumed) == NULL)
+ return False;
+ fname_src = referral_fname;
+ DEBUG(3,("cli_dfs_open: Dfs open %s on server %s(%d)\n",
+ fname_src, cli_state_get_host(cluster->cli[*server]), *server));
+ fnum = cli_open(cluster->cli[*server], fname_src, flags, share_mode);
+ }
+ if (cli_is_error(cluster->cli[*server])) {
+ printf("cli_dfs_open: open of %s failed (%s)\n",
+ fname_src, cli_errstr(cluster->cli[*server]));
+ return -1;
+ }
+ }
+ DEBUG(3,("cli_dfs_open: open %s fnum=%d\n",
+ fname_src, fnum));
+ return fnum;
+}
+
+/****************************************************************************
+ Delete a file (allowing for Dfs referral).
+****************************************************************************/
+
+NTSTATUS cli_nt_unlink(struct cli_client* cluster, int *server,
+ char *fname_src, uint16 FileAttributes)
+{
+ int referral_number;
+ dfs_info dinfo;
+ char *referral_fname;
+ struct smb_unlink parms;
+
+ DEBUG(3,("cli_nt_unlink: delete %s on server %s(%d), attributes=0x%x\n",
+ fname_src, cli_state_get_host(cluster->cli[*server]), *server,
+ FileAttributes));
+ cluster->cli[*server]->dfs_referral = *server;
+ parms.in.pattern = fname_src;
+ parms.in.dirtype = FileAttributes;
+ if (NT_STATUS_IS_ERR(cli_raw_unlink(cluster->cli[*server], &parms))) {
+ printf("cli_nt_unlink: delete of %s failed (%s)\n",
+ fname_src, cli_errstr(cluster->cli[*server]));
+ if (cli_check_dfs_redirect(cluster->cli[*server], fname_src, &dinfo)) {
+ // choose referral, check if already connected, open if not
+ referral_number = dinfo.selected_referral;
+ DEBUG(3,("cli_nt_unlink: redirecting to %s\n", dinfo.referrals[referral_number].node));
+ cluster->cli[*server]->dfs_referral = cli_dfs_open_connection(cluster,
+ dinfo.referrals[referral_number].host,
+ dinfo.referrals[referral_number].share,
+ cluster->connection_flags);
+ *server = cluster->cli[*server]->dfs_referral;
+ if (server < 0)
+ return NT_STATUS_INTERNAL_ERROR;
+ // rebuild file name and retry operation.
+ if (rebuild_filename(referral_fname, cluster->cli[*server], fname_src, dinfo.path_consumed) == NULL)
+ return NT_STATUS_INTERNAL_ERROR;
+ fname_src = referral_fname;
+ DEBUG(3,("cli_nt_unlink: Dfs delete %s on server %s(%d)\n",
+ fname_src, cli_state_get_host(cluster->cli[*server]), *server));
+ cli_raw_unlink(cluster->cli[*server], &parms);
+ }
+ if (cli_is_error(cluster->cli[*server])) {
+ printf("cli_nt_unlink: delete of %s failed (%s)\n",
+ fname_src, cli_errstr(cluster->cli[*server]));
+ }
+ }
+ return cli_nt_error(cluster->cli[*server]);
+}
+
+/****************************************************************************
+ Rename a file (allowing for Dfs referral).
+****************************************************************************/
+
+BOOL cli_dfs_rename(struct cli_client* cluster, int *server,
+ char *fname_src, char *fname_dst)
+{
+ int referral_number;
+ dfs_info dinfo;
+ char *referral_fname;
+
+ DEBUG(3,("cli_dfs_rename: rename %s to %s on server %s(%d)\n",
+ fname_src, fname_dst, cli_state_get_host(cluster->cli[*server]), *server));
+ cluster->cli[*server]->dfs_referral = *server;
+ if (!cli_rename(cluster->cli[*server], fname_src, fname_dst)) {
+ if (cli_check_dfs_redirect(cluster->cli[*server], fname_src, &dinfo)) {
+ // choose referral, check if already connected, open if not
+ referral_number = dinfo.selected_referral;
+ DEBUG(3,("cli_dfs_rename: redirecting to %s\n", dinfo.referrals[referral_number].node));
+ cluster->cli[*server]->dfs_referral = cli_dfs_open_connection(cluster,
+ dinfo.referrals[referral_number].host,
+ dinfo.referrals[referral_number].share,
+ cluster->connection_flags);
+ *server = cluster->cli[*server]->dfs_referral;
+ if (server < 0)
+ return False;
+ // rebuild file name and retry operation.
+ if (rebuild_filename(referral_fname, cluster->cli[*server], fname_src, dinfo.path_consumed) == NULL)
+ return False;
+ fname_src = referral_fname;
+ DEBUG(3,("cli_dfs_rename: Dfs rename %s to %s on server %s(%d)\n",
+ fname_src, fname_dst, cli_state_get_host(cluster->cli[*server]), *server));
+ cli_rename(cluster->cli[*server], fname_src, fname_dst);
+ }
+ if (cli_is_error(cluster->cli[*server])) {
+ printf("cli_dfs_rename: rename of %s to %s failed (%s)\n",
+ fname_src, fname_dst, cli_errstr(cluster->cli[*server]));
+ return False;
+ }
+ }
+ return True;
+}
+
+/****************************************************************************
+ Make directory (allowing for Dfs referral).
+****************************************************************************/
+
+BOOL cli_dfs_mkdir(struct cli_client* cluster, int *server,
+ char *fname_src)
+{
+ int referral_number;
+ dfs_info dinfo;
+ char *referral_fname;
+
+ DEBUG(3,("cli_dfs_mkdir: mkdir %s on server %s(%d)\n",
+ fname_src, cli_state_get_host(cluster->cli[*server]), *server));
+ cluster->cli[*server]->dfs_referral = *server;
+ if (!cli_mkdir(cluster->cli[*server], fname_src)) {
+ printf("cli_dfs_mkdir: mkdir of %s failed (%s)\n",
+ fname_src, cli_errstr(cluster->cli[*server]));
+ if (cli_check_dfs_redirect(cluster->cli[*server], fname_src, &dinfo)) {
+ // choose referral, check if already connected, open if not
+ referral_number = dinfo.selected_referral;
+ DEBUG(3,("cli_dfs_mkdir: redirecting to %s\n", dinfo.referrals[referral_number].node));
+ cluster->cli[*server]->dfs_referral = cli_dfs_open_connection(cluster,
+ dinfo.referrals[referral_number].host,
+ dinfo.referrals[referral_number].share,
+ cluster->connection_flags);
+ *server = cluster->cli[*server]->dfs_referral;
+ if (server < 0)
+ return False;
+ // rebuild file name and retry operation.
+ if (rebuild_filename(referral_fname, cluster->cli[*server], fname_src, dinfo.path_consumed) == NULL)
+ return False;
+ fname_src = referral_fname;
+ DEBUG(3,("cli_dfs_mkdir: Dfs mkdir %s on server %s(%d)\n",
+ fname_src, cli_state_get_host(cluster->cli[*server]), *server));
+ cli_mkdir(cluster->cli[*server], fname_src);
+ }
+ if (cli_is_error(cluster->cli[*server])) {
+ printf("cli_dfs_mkdir: mkdir of %s failed (%s)\n",
+ fname_src, cli_errstr(cluster->cli[*server]));
+ return False;
+ }
+ }
+ return True;
+}
+
+/****************************************************************************
+ Remove directory (allowing for Dfs referral).
+****************************************************************************/
+
+BOOL cli_dfs_rmdir(struct cli_client* cluster, int *server,
+ char *fname_src)
+{
+ int referral_number;
+ dfs_info dinfo;
+ char *referral_fname;
+
+ DEBUG(3,("cli_dfs_rmdir: rmdir %s on server %s(%d)\n",
+ fname_src, cli_state_get_host(cluster->cli[*server]), *server));
+ cluster->cli[*server]->dfs_referral = *server;
+ if (!cli_rmdir(cluster->cli[*server], fname_src)) {
+ printf("cli_dfs_rmdir: rmdir of %s failed (%s)\n",
+ fname_src, cli_errstr(cluster->cli[*server]));
+ if (cli_check_dfs_redirect(cluster->cli[*server], fname_src, &dinfo)) {
+ // choose referral, check if already connected, open if not
+ referral_number = dinfo.selected_referral;
+ DEBUG(3,("cli_dfs_rmdir: redirecting to %s\n", dinfo.referrals[referral_number].node));
+ cluster->cli[*server]->dfs_referral = cli_dfs_open_connection(cluster,
+ dinfo.referrals[referral_number].host,
+ dinfo.referrals[referral_number].share,
+ cluster->connection_flags);
+ *server = cluster->cli[*server]->dfs_referral;
+ if (server < 0)
+ return False;
+ // rebuild file name and retry operation.
+ if (rebuild_filename(referral_fname, cluster->cli[*server], fname_src, dinfo.path_consumed) == NULL)
+ return False;
+ fname_src = referral_fname;
+ DEBUG(3,("cli_dfs_rmdir: Dfs rmdir %s on server %s(%d)\n",
+ fname_src, cli_state_get_host(cluster->cli[*server]), *server));
+ cli_rmdir(cluster->cli[*server], fname_src);
+ }
+ if (cli_is_error(cluster->cli[*server])) {
+ printf("cli_dfs_rmdir: rmdir of %s failed (%s)\n",
+ fname_src, cli_errstr(cluster->cli[*server]));
+ return False;
+ }
+ }
+ return True;
+}
diff --git a/source4/libcli/clifile.c b/source4/libcli/clifile.c
new file mode 100644
index 0000000000..c203e4633d
--- /dev/null
+++ b/source4/libcli/clifile.c
@@ -0,0 +1,647 @@
+/*
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Hard/Symlink a file (UNIX extensions).
+****************************************************************************/
+
+static BOOL cli_link_internal(struct cli_state *cli,
+ const char *fname_src,
+ const char *fname_dst, BOOL hard_link)
+{
+ union smb_setfileinfo parms;
+ NTSTATUS status;
+
+ if (hard_link) {
+ parms.generic.level = SMB_SFILEINFO_UNIX_HLINK;
+ parms.unix_hlink.file.fname = fname_src;
+ parms.unix_hlink.in.link_dest = fname_dst;
+ } else {
+ parms.generic.level = SMB_SFILEINFO_UNIX_LINK;
+ parms.unix_link.file.fname = fname_src;
+ parms.unix_link.in.link_dest = fname_dst;
+ }
+
+ status = smb_raw_setpathinfo(cli->tree, &parms);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+/****************************************************************************
+ Map standard UNIX permissions onto wire representations.
+****************************************************************************/
+static uint32 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;
+}
+
+/****************************************************************************
+ Symlink a file (UNIX extensions).
+****************************************************************************/
+BOOL cli_unix_symlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
+{
+ return cli_link_internal(cli, fname_src, fname_dst, False);
+}
+
+/****************************************************************************
+ Hard a file (UNIX extensions).
+****************************************************************************/
+BOOL cli_unix_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
+{
+ return cli_link_internal(cli, fname_src, fname_dst, True);
+}
+
+
+/****************************************************************************
+ Chmod or chown a file internal (UNIX extensions).
+****************************************************************************/
+static BOOL cli_unix_chmod_chown_internal(struct cli_state *cli, const char *fname,
+ uint32 mode, uint32 uid, uint32 gid)
+{
+ union smb_setfileinfo parms;
+ NTSTATUS status;
+
+ parms.generic.level = SMB_SFILEINFO_UNIX_BASIC;
+ parms.unix_basic.file.fname = fname;
+ parms.unix_basic.in.uid = uid;
+ parms.unix_basic.in.gid = gid;
+ parms.unix_basic.in.mode = mode;
+
+ status = smb_raw_setpathinfo(cli->tree, &parms);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+/****************************************************************************
+ chmod a file (UNIX extensions).
+****************************************************************************/
+
+BOOL cli_unix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
+{
+ return cli_unix_chmod_chown_internal(cli, fname,
+ unix_perms_to_wire(mode), SMB_UID_NO_CHANGE, SMB_GID_NO_CHANGE);
+}
+
+/****************************************************************************
+ chown a file (UNIX extensions).
+****************************************************************************/
+BOOL cli_unix_chown(struct cli_state *cli, const char *fname, uid_t uid, gid_t gid)
+{
+ return cli_unix_chmod_chown_internal(cli, fname, SMB_MODE_NO_CHANGE, (uint32)uid, (uint32)gid);
+}
+
+
+/****************************************************************************
+ Rename a file.
+****************************************************************************/
+BOOL cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
+{
+ struct smb_rename parms;
+
+ parms.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
+ parms.in.pattern1 = fname_src;
+ parms.in.pattern2 = fname_dst;
+ return NT_STATUS_IS_OK(smb_raw_rename(cli->tree, &parms));
+}
+
+
+/****************************************************************************
+ Delete a file.
+****************************************************************************/
+BOOL cli_unlink(struct cli_state *cli, const char *fname)
+{
+ struct smb_unlink parms;
+
+ parms.in.pattern = fname;
+ if (strchr(fname, '*')) {
+ parms.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
+ } else {
+ parms.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
+ }
+ return NT_STATUS_IS_OK(smb_raw_unlink(cli->tree, &parms));
+}
+
+/****************************************************************************
+ Create a directory.
+****************************************************************************/
+BOOL cli_mkdir(struct cli_state *cli, const char *dname)
+{
+ union smb_mkdir parms;
+
+ parms.mkdir.level = RAW_MKDIR_MKDIR;
+ parms.mkdir.in.path = dname;
+
+ return NT_STATUS_IS_OK(smb_raw_mkdir(cli->tree, &parms));
+}
+
+
+/****************************************************************************
+ Remove a directory.
+****************************************************************************/
+BOOL cli_rmdir(struct cli_state *cli, const char *dname)
+{
+ struct smb_rmdir parms;
+
+ parms.in.path = dname;
+ return NT_STATUS_IS_OK(smb_raw_rmdir(cli->tree, &parms));
+}
+
+
+/****************************************************************************
+ Set or clear the delete on close flag.
+****************************************************************************/
+BOOL cli_nt_delete_on_close(struct cli_state *cli, int fnum, BOOL flag)
+{
+ union smb_setfileinfo parms;
+ NTSTATUS status;
+
+ parms.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
+ parms.disposition_info.file.fnum = fnum;
+ parms.disposition_info.in.delete_on_close = flag;
+
+ status = smb_raw_setfileinfo(cli->tree, &parms);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+
+/****************************************************************************
+ Create/open a file - exposing the full horror of the NT API :-).
+ Used in CIFS-on-CIFS NTVFS.
+****************************************************************************/
+int cli_nt_create_full(struct cli_state *cli, const char *fname,
+ uint32 CreatFlags, uint32 DesiredAccess,
+ uint32 FileAttributes, uint32 ShareAccess,
+ uint32 CreateDisposition, uint32 CreateOptions,
+ uint8 SecurityFlags)
+{
+ union smb_open open_parms;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+
+ mem_ctx = talloc_init("raw_open");
+ if (!mem_ctx) return -1;
+
+ open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
+ open_parms.ntcreatex.in.flags = CreatFlags;
+ open_parms.ntcreatex.in.root_fid = 0;
+ open_parms.ntcreatex.in.access_mask = DesiredAccess;
+ open_parms.ntcreatex.in.file_attr = FileAttributes;
+ open_parms.ntcreatex.in.alloc_size = 0;
+ open_parms.ntcreatex.in.share_access = ShareAccess;
+ open_parms.ntcreatex.in.open_disposition = CreateDisposition;
+ open_parms.ntcreatex.in.create_options = CreateOptions;
+ open_parms.ntcreatex.in.impersonation = 0;
+ open_parms.ntcreatex.in.security_flags = SecurityFlags;
+ open_parms.ntcreatex.in.fname = fname;
+
+ status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
+ talloc_destroy(mem_ctx);
+
+ if (NT_STATUS_IS_OK(status)) {
+ return open_parms.ntcreatex.out.fnum;
+ }
+
+ return -1;
+}
+
+
+/****************************************************************************
+ Open a file (using SMBopenx)
+ WARNING: if you open with O_WRONLY then getattrE won't work!
+****************************************************************************/
+int cli_open(struct cli_state *cli, const char *fname, int flags, int share_mode)
+{
+ union smb_open open_parms;
+ unsigned openfn=0;
+ unsigned accessmode=0;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+
+ mem_ctx = talloc_init("raw_open");
+ if (!mem_ctx) return -1;
+
+ if (flags & O_CREAT) {
+ openfn |= OPENX_OPEN_FUNC_CREATE;
+ }
+ if (!(flags & O_EXCL)) {
+ if (flags & O_TRUNC) {
+ openfn |= OPENX_OPEN_FUNC_TRUNC;
+ } else {
+ openfn |= OPENX_OPEN_FUNC_OPEN;
+ }
+ }
+
+ accessmode = (share_mode<<OPENX_MODE_DENY_SHIFT);
+
+ if ((flags & O_ACCMODE) == O_RDWR) {
+ accessmode |= OPENX_MODE_ACCESS_RDWR;
+ } else if ((flags & O_ACCMODE) == O_WRONLY) {
+ accessmode |= OPENX_MODE_ACCESS_WRITE;
+ }
+
+#if defined(O_SYNC)
+ if ((flags & O_SYNC) == O_SYNC) {
+ accessmode |= OPENX_MODE_WRITE_THRU;
+ }
+#endif
+
+ if (share_mode == DENY_FCB) {
+ accessmode = OPENX_MODE_ACCESS_FCB | OPENX_MODE_DENY_FCB;
+ }
+
+ open_parms.openx.level = RAW_OPEN_OPENX;
+ open_parms.openx.in.flags = 0;
+ open_parms.openx.in.open_mode = accessmode;
+ open_parms.openx.in.search_attrs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
+ open_parms.openx.in.file_attrs = 0;
+ open_parms.openx.in.write_time = 0;
+ open_parms.openx.in.open_func = openfn;
+ open_parms.openx.in.size = 0;
+ open_parms.openx.in.timeout = 0;
+ open_parms.openx.in.fname = fname;
+
+ status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
+ talloc_destroy(mem_ctx);
+
+ if (NT_STATUS_IS_OK(status)) {
+ return open_parms.openx.out.fnum;
+ }
+
+ return -1;
+}
+
+
+/****************************************************************************
+ Close a file.
+****************************************************************************/
+BOOL cli_close(struct cli_state *cli, int fnum)
+{
+ union smb_close close_parms;
+ NTSTATUS status;
+
+ close_parms.close.level = RAW_CLOSE_CLOSE;
+ close_parms.close.in.fnum = fnum;
+ close_parms.close.in.write_time = 0;
+ status = smb_raw_close(cli->tree, &close_parms);
+ return NT_STATUS_IS_OK(status);
+}
+
+/****************************************************************************
+ send a lock with a specified locktype
+ this is used for testing LOCKING_ANDX_CANCEL_LOCK
+****************************************************************************/
+NTSTATUS cli_locktype(struct cli_state *cli, int fnum,
+ uint32 offset, uint32 len, int timeout, unsigned char locktype)
+{
+ union smb_lock parms;
+ struct smb_lock_entry lock[1];
+ NTSTATUS status;
+
+ parms.lockx.level = RAW_LOCK_LOCKX;
+ parms.lockx.in.fnum = fnum;
+ parms.lockx.in.mode = locktype;
+ parms.lockx.in.timeout = timeout;
+ parms.lockx.in.ulock_cnt = 0;
+ parms.lockx.in.lock_cnt = 1;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = offset;
+ lock[0].count = len;
+ parms.lockx.in.locks = &lock[0];
+
+ status = smb_raw_lock(cli->tree, &parms);
+
+ return status;
+}
+
+
+/****************************************************************************
+ Lock a file.
+****************************************************************************/
+BOOL cli_lock(struct cli_state *cli, int fnum,
+ uint32 offset, uint32 len, int timeout, enum brl_type lock_type)
+{
+ union smb_lock parms;
+ struct smb_lock_entry lock[1];
+ NTSTATUS status;
+
+ parms.lockx.level = RAW_LOCK_LOCKX;
+ parms.lockx.in.fnum = fnum;
+ parms.lockx.in.mode = (lock_type == READ_LOCK? 1 : 0);
+ parms.lockx.in.timeout = timeout;
+ parms.lockx.in.ulock_cnt = 0;
+ parms.lockx.in.lock_cnt = 1;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = offset;
+ lock[0].count = len;
+ parms.lockx.in.locks = &lock[0];
+
+ status = smb_raw_lock(cli->tree, &parms);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+
+/****************************************************************************
+ Unlock a file.
+****************************************************************************/
+BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len)
+{
+ union smb_lock parms;
+ struct smb_lock_entry lock[1];
+ NTSTATUS status;
+
+ parms.lockx.level = RAW_LOCK_LOCKX;
+ parms.lockx.in.fnum = fnum;
+ parms.lockx.in.mode = 0;
+ parms.lockx.in.timeout = 0;
+ parms.lockx.in.ulock_cnt = 1;
+ parms.lockx.in.lock_cnt = 0;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = offset;
+ lock[0].count = len;
+ parms.lockx.in.locks = &lock[0];
+
+ status = smb_raw_lock(cli->tree, &parms);
+ return NT_STATUS_IS_OK(status);
+}
+
+
+/****************************************************************************
+ Lock a file with 64 bit offsets.
+****************************************************************************/
+BOOL cli_lock64(struct cli_state *cli, int fnum,
+ SMB_OFF_T offset, SMB_OFF_T len, int timeout, enum brl_type lock_type)
+{
+ union smb_lock parms;
+ int ltype;
+ struct smb_lock_entry lock[1];
+ NTSTATUS status;
+
+ if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
+ return cli_lock(cli, fnum, offset, len, timeout, lock_type);
+ }
+
+ parms.lockx.level = RAW_LOCK_LOCKX;
+ parms.lockx.in.fnum = fnum;
+
+ ltype = (lock_type == READ_LOCK? 1 : 0);
+ ltype |= LOCKING_ANDX_LARGE_FILES;
+ parms.lockx.in.mode = ltype;
+ parms.lockx.in.timeout = timeout;
+ parms.lockx.in.ulock_cnt = 0;
+ parms.lockx.in.lock_cnt = 1;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = offset;
+ lock[0].count = len;
+ parms.lockx.in.locks = &lock[0];
+
+ status = smb_raw_lock(cli->tree, &parms);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+
+/****************************************************************************
+ Unlock a file with 64 bit offsets.
+****************************************************************************/
+BOOL cli_unlock64(struct cli_state *cli, int fnum, SMB_OFF_T offset, SMB_OFF_T len)
+{
+ union smb_lock parms;
+ struct smb_lock_entry lock[1];
+ NTSTATUS status;
+
+ if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
+ return cli_unlock(cli, fnum, offset, len);
+ }
+
+ parms.lockx.level = RAW_LOCK_LOCKX;
+ parms.lockx.in.fnum = fnum;
+ parms.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ parms.lockx.in.timeout = 0;
+ parms.lockx.in.ulock_cnt = 1;
+ parms.lockx.in.lock_cnt = 0;
+ lock[0].pid = cli->session->pid;
+ lock[0].offset = offset;
+ lock[0].count = len;
+ parms.lockx.in.locks = &lock[0];
+
+ status = smb_raw_lock(cli->tree, &parms);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+
+/****************************************************************************
+ Do a SMBgetattrE call.
+****************************************************************************/
+BOOL cli_getattrE(struct cli_state *cli, int fd,
+ uint16 *attr, size_t *size,
+ time_t *c_time, time_t *a_time, time_t *m_time)
+{
+ union smb_fileinfo parms;
+ NTSTATUS status;
+
+ parms.getattre.level = RAW_FILEINFO_GETATTRE;
+ parms.getattre.in.fnum = fd;
+
+ status = smb_raw_fileinfo(cli->tree, NULL, &parms);
+
+ if (!NT_STATUS_IS_OK(status))
+ return False;
+
+ if (size) {
+ *size = parms.getattre.out.size;
+ }
+
+ if (attr) {
+ *attr = parms.getattre.out.attrib;
+ }
+
+ if (c_time) {
+ *c_time = parms.getattre.out.create_time;
+ }
+
+ if (a_time) {
+ *a_time = &parms.getattre.out.access_time;
+ }
+
+ if (m_time) {
+ *m_time = &parms.getattre.out.write_time;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Do a SMBgetatr call
+****************************************************************************/
+BOOL cli_getatr(struct cli_state *cli, const char *fname,
+ uint16 *attr, size_t *size, time_t *t)
+{
+ union smb_fileinfo parms;
+ NTSTATUS status;
+
+ parms.getattr.level = RAW_FILEINFO_GETATTR;
+ parms.getattr.in.fname = fname;
+
+ status = smb_raw_pathinfo(cli->tree, NULL, &parms);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
+
+ if (size) {
+ *size = parms.getattr.out.size;
+ }
+
+ if (t) {
+ *t = parms.getattr.out.write_time;
+ }
+
+ if (attr) {
+ *attr = parms.getattr.out.attrib;
+ }
+
+ return True;
+}
+
+
+/****************************************************************************
+ Do a SMBsetatr call.
+****************************************************************************/
+BOOL cli_setatr(struct cli_state *cli, const char *fname, uint16 mode, time_t t)
+{
+ union smb_setfileinfo parms;
+ NTSTATUS status;
+
+ parms.setattr.level = RAW_SFILEINFO_SETATTR;
+ parms.setattr.in.attrib = mode;
+ parms.setattr.in.write_time = t;
+ parms.setattr.file.fname = fname;
+
+ status = smb_raw_setpathinfo(cli->tree, &parms);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+
+/****************************************************************************
+ Check for existence of a dir.
+****************************************************************************/
+BOOL cli_chkpath(struct cli_state *cli, const char *path)
+{
+ struct smb_chkpath parms;
+ char *path2;
+ NTSTATUS status;
+
+ path2 = strdup(path);
+ trim_string(path2,NULL,"\\");
+ if (!*path2) {
+ free(path2);
+ path2 = strdup("\\");
+ }
+
+ parms.in.path = path2;
+
+ status = smb_raw_chkpath(cli->tree, &parms);
+
+ free(path2);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+
+/****************************************************************************
+ Query disk space.
+****************************************************************************/
+BOOL cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
+{
+ union smb_fsinfo fsinfo_parms;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+
+ mem_ctx = talloc_init("cli_dskattr");
+
+ fsinfo_parms.dskattr.level = RAW_QFS_DSKATTR;
+ status = smb_raw_fsinfo(cli->tree, mem_ctx, &fsinfo_parms);
+ if (NT_STATUS_IS_OK(status)) {
+ *bsize = fsinfo_parms.dskattr.out.block_size;
+ *total = fsinfo_parms.dskattr.out.units_total;
+ *avail = fsinfo_parms.dskattr.out.units_free;
+ }
+
+ talloc_destroy(mem_ctx);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+
+/****************************************************************************
+ Create and open a temporary file.
+****************************************************************************/
+int cli_ctemp(struct cli_state *cli, const char *path, char **tmp_path)
+{
+ union smb_open open_parms;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+
+ mem_ctx = talloc_init("raw_open");
+ if (!mem_ctx) return -1;
+
+ open_parms.openx.level = RAW_OPEN_CTEMP;
+ open_parms.ctemp.in.attrib = 0;
+ open_parms.ctemp.in.directory = path;
+
+ status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
+ if (tmp_path) {
+ *tmp_path = strdup(open_parms.ctemp.out.name);
+ }
+ talloc_destroy(mem_ctx);
+ if (NT_STATUS_IS_OK(status)) {
+ return open_parms.ctemp.out.fnum;
+ }
+ return -1;
+}
+
diff --git a/source4/libcli/clilist.c b/source4/libcli/clilist.c
new file mode 100644
index 0000000000..620e4382f4
--- /dev/null
+++ b/source4/libcli/clilist.c
@@ -0,0 +1,313 @@
+/*
+ Unix SMB/CIFS implementation.
+ client directory list routines
+ Copyright (C) Andrew Tridgell 1994-2003
+ Copyright (C) James Myers 2003 <myersjj@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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+struct search_private {
+ file_info *dirlist;
+ TALLOC_CTX *mem_ctx;
+ int dirlist_len;
+ int ff_searchcount; /* total received in 1 server trip */
+ int total_received; /* total received all together */
+ int info_level;
+ DATA_BLOB status; /* used for old-style search */
+};
+
+
+/****************************************************************************
+ Interpret a long filename structure.
+****************************************************************************/
+static BOOL interpret_long_filename(int level,
+ union smb_search_data *info,
+ file_info *finfo)
+{
+ file_info finfo2;
+
+ if (!finfo) finfo = &finfo2;
+ ZERO_STRUCTP(finfo);
+
+ finfo->size = info->both_directory_info.size;
+ finfo->ctime = nt_time_to_unix(&info->both_directory_info.create_time);
+ finfo->atime = nt_time_to_unix(&info->both_directory_info.access_time);
+ finfo->mtime = nt_time_to_unix(&info->both_directory_info.write_time);
+ finfo->mode = info->both_directory_info.attrib; /* 32 bit->16 bit attrib */
+ if (info->both_directory_info.short_name.s) {
+ strncpy(finfo->short_name, info->both_directory_info.short_name.s,
+ sizeof(finfo->short_name)-1);
+ }
+ finfo->name = info->both_directory_info.name.s;
+ return True;
+}
+
+/* callback function used for trans2 search */
+static BOOL cli_list_new_callback(void *private, union smb_search_data *file)
+{
+ struct search_private *state = (struct search_private*) private;
+ file_info *tdl;
+
+ /* add file info to the dirlist pool */
+ tdl = talloc_realloc(state->mem_ctx, state->dirlist,
+ state->dirlist_len + sizeof(struct file_info));
+
+ if (!tdl) {
+ return False;
+ }
+ state->dirlist = tdl;
+ state->dirlist_len += sizeof(struct file_info);
+
+ interpret_long_filename(state->info_level, file, &state->dirlist[state->total_received]);
+
+ state->total_received++;
+ state->ff_searchcount++;
+
+ return True;
+}
+
+int cli_list_new(struct cli_state *cli, const char *Mask, uint16 attribute,
+ void (*fn)(file_info *, const char *, void *), void *caller_state)
+{
+ union smb_search_first first_parms;
+ union smb_search_next next_parms;
+ struct search_private state; /* for callbacks */
+ int received = 0;
+ BOOL first = True;
+ int num_received = 0;
+ int max_matches = 512;
+ char *mask;
+ int ff_eos = 0, i, ff_searchcount;
+ int ff_dir_handle=0;
+ int level;
+
+ /* initialize state for search */
+ state.dirlist = NULL;
+ state.mem_ctx = talloc_init("cli_list_new");
+ state.dirlist_len = 0;
+ state.total_received = 0;
+
+ mask = talloc_strdup(state.mem_ctx, Mask);
+
+ if (cli->transport->negotiate.capabilities & CAP_NT_SMBS) {
+ level = RAW_SEARCH_BOTH_DIRECTORY_INFO;
+ } else {
+ level = RAW_SEARCH_STANDARD;
+ }
+
+ while (1) {
+ state.ff_searchcount = 0;
+ if (first) {
+ NTSTATUS status;
+
+ first_parms.t2ffirst.level = level;
+ first_parms.t2ffirst.in.max_count = max_matches;
+ first_parms.t2ffirst.in.search_attrib = attribute;
+ first_parms.t2ffirst.in.pattern = mask;
+ first_parms.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE_IF_END;
+ first_parms.t2ffirst.in.storage_type = 0;
+
+ status = smb_raw_search_first(cli->tree,
+ state.mem_ctx, &first_parms,
+ (void*)&state, cli_list_new_callback);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_destroy(state.mem_ctx);
+ return -1;
+ }
+
+ ff_dir_handle = first_parms.t2ffirst.out.handle;
+ ff_searchcount = first_parms.t2ffirst.out.count;
+ ff_eos = first_parms.t2ffirst.out.end_of_search;
+
+ received = first_parms.t2ffirst.out.count;
+ if (received <= 0) break;
+ if (ff_eos) break;
+ first = False;
+ } else {
+ NTSTATUS status;
+
+ next_parms.t2fnext.level = level;
+ next_parms.t2fnext.in.max_count = max_matches;
+ next_parms.t2fnext.in.last_name = mask;
+ next_parms.t2fnext.in.handle = ff_dir_handle;
+ next_parms.t2fnext.in.resume_key = 0;
+ next_parms.t2fnext.in.flags = FLAG_TRANS2_FIND_CONTINUE | FLAG_TRANS2_FIND_CLOSE_IF_END;
+
+ status = smb_raw_search_next(cli->tree,
+ state.mem_ctx,
+ &next_parms,
+ (void*)&state,
+ cli_list_new_callback);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+ ff_searchcount = next_parms.t2fnext.out.count;
+ ff_eos = next_parms.t2fnext.out.end_of_search;
+ received = next_parms.t2fnext.out.count;
+ if (received <= 0) break;
+ if (ff_eos) break;
+ }
+
+ num_received += received;
+ }
+
+ for (i=0;i<state.total_received;i++) {
+ fn(&state.dirlist[i], Mask, caller_state);
+ }
+
+ talloc_destroy(state.mem_ctx);
+
+ return state.total_received;
+}
+
+/****************************************************************************
+ Interpret a short filename structure.
+ The length of the structure is returned.
+****************************************************************************/
+static BOOL interpret_short_filename(int level,
+ union smb_search_data *info,
+ file_info *finfo)
+{
+ file_info finfo2;
+
+ if (!finfo) finfo = &finfo2;
+ ZERO_STRUCTP(finfo);
+
+ finfo->ctime = info->search.write_time;
+ finfo->atime = info->search.write_time;
+ finfo->mtime = info->search.write_time;
+ finfo->size = info->search.size;
+ finfo->mode = info->search.attrib;
+ finfo->name = info->search.name;
+ return True;
+}
+
+/* callback function used for smb_search */
+static BOOL cli_list_old_callback(void *private, union smb_search_data *file)
+{
+ struct search_private *state = (struct search_private*) private;
+ file_info *tdl;
+
+ /* add file info to the dirlist pool */
+ tdl = talloc_realloc(state->mem_ctx, state->dirlist,
+ state->dirlist_len + sizeof(struct file_info));
+
+ if (!tdl) {
+ return False;
+ }
+ state->dirlist = tdl;
+ state->dirlist_len += sizeof(struct file_info);
+
+ interpret_short_filename(state->info_level, file, &state->dirlist[state->total_received]);
+
+ state->total_received++;
+ state->ff_searchcount++;
+ state->status = file->search.search_id; /* return resume info */
+
+ return True;
+}
+
+int cli_list_old(struct cli_state *cli, const char *Mask, uint16 attribute,
+ void (*fn)(file_info *, const char *, void *), void *caller_state)
+{
+ union smb_search_first first_parms;
+ union smb_search_next next_parms;
+ struct search_private state; /* for callbacks */
+ const int num_asked = 500;
+ int received = 0;
+ BOOL first = True;
+ int num_received = 0;
+ char *mask;
+ int i;
+
+ /* initialize state for search */
+ state.dirlist = NULL;
+ state.mem_ctx = talloc_init("cli_list_old");
+ state.dirlist_len = 0;
+ state.total_received = 0;
+
+ mask = talloc_strdup(state.mem_ctx, Mask);
+
+ while (1) {
+ state.ff_searchcount = 0;
+ if (first) {
+ NTSTATUS status;
+
+ first_parms.search_first.level = RAW_SEARCH_SEARCH;
+ first_parms.search_first.in.max_count = num_asked;
+ first_parms.search_first.in.search_attrib = attribute;
+ first_parms.search_first.in.pattern = mask;
+
+ status = smb_raw_search_first(cli->tree, state.mem_ctx,
+ &first_parms,
+ (void*)&state,
+ cli_list_old_callback);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_destroy(state.mem_ctx);
+ return -1;
+ }
+
+ received = first_parms.search_first.out.count;
+ if (received <= 0) break;
+ first = False;
+ } else {
+ NTSTATUS status;
+
+ next_parms.search_next.level = RAW_SEARCH_SEARCH;
+ next_parms.search_next.in.max_count = num_asked;
+ next_parms.search_next.in.search_attrib = attribute;
+ next_parms.search_next.in.search_id = state.status;
+
+ status = smb_raw_search_next(cli->tree, state.mem_ctx,
+ &next_parms,
+ (void*)&state,
+ cli_list_old_callback);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_destroy(state.mem_ctx);
+ return -1;
+ }
+ received = next_parms.search_next.out.count;
+ if (received <= 0) break;
+ }
+
+ num_received += received;
+ }
+
+ for (i=0;i<state.total_received;i++) {
+ fn(&state.dirlist[i], Mask, caller_state);
+ }
+
+ talloc_destroy(state.mem_ctx);
+
+ return state.total_received;
+}
+
+/****************************************************************************
+ Do a directory listing, calling fn on each file found.
+ This auto-switches between old and new style.
+****************************************************************************/
+
+int cli_list(struct cli_state *cli,const char *Mask,uint16 attribute,
+ void (*fn)(file_info *, const char *, void *), void *state)
+{
+ if (cli->transport->negotiate.protocol <= PROTOCOL_LANMAN1)
+ return cli_list_old(cli, Mask, attribute, fn, state);
+ return cli_list_new(cli, Mask, attribute, fn, state);
+}
diff --git a/source4/libcli/climessage.c b/source4/libcli/climessage.c
new file mode 100644
index 0000000000..ad5d41545b
--- /dev/null
+++ b/source4/libcli/climessage.c
@@ -0,0 +1,93 @@
+/*
+ Unix SMB/CIFS implementation.
+ client message handling routines
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) James J Myers 2003 <myersjj@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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+
+/****************************************************************************
+start a message sequence
+****************************************************************************/
+BOOL cli_message_start(struct cli_state *cli, char *host, char *username,
+ int *grp)
+{
+ struct cli_request *req;
+
+ req = cli_request_setup(cli->tree, SMBsendstrt, 0, 0);
+ cli_req_append_string(req, username, STR_TERMINATE);
+ cli_req_append_string(req, host, STR_TERMINATE);
+ if (!cli_request_send(req) ||
+ !cli_request_receive(req) ||
+ cli_is_error(cli)) {
+ cli_request_destroy(req);
+ return False;
+ }
+
+ *grp = SVAL(req->in.vwv, VWV(0));
+ cli_request_destroy(req);
+
+ return True;
+}
+
+
+/****************************************************************************
+send a message
+****************************************************************************/
+BOOL cli_message_text(struct cli_state *cli, char *msg, int len, int grp)
+{
+ struct cli_request *req;
+
+ req = cli_request_setup(cli->tree, SMBsendtxt, 1, 0);
+ SSVAL(req->out.vwv, VWV(0), grp);
+
+ cli_req_append_bytes(req, msg, len);
+
+ if (!cli_request_send(req) ||
+ !cli_request_receive(req) ||
+ cli_is_error(cli)) {
+ cli_request_destroy(req);
+ return False;
+ }
+
+ cli_request_destroy(req);
+ return True;
+}
+
+/****************************************************************************
+end a message
+****************************************************************************/
+BOOL cli_message_end(struct cli_state *cli, int grp)
+{
+ struct cli_request *req;
+
+ req = cli_request_setup(cli->tree, SMBsendend, 1, 0);
+ SSVAL(req->out.vwv, VWV(0), grp);
+
+ if (!cli_request_send(req) ||
+ !cli_request_receive(req) ||
+ cli_is_error(cli)) {
+ cli_request_destroy(req);
+ return False;
+ }
+
+ cli_request_destroy(req);
+ return True;
+}
+
diff --git a/source4/libcli/clireadwrite.c b/source4/libcli/clireadwrite.c
new file mode 100644
index 0000000000..e1d154b283
--- /dev/null
+++ b/source4/libcli/clireadwrite.c
@@ -0,0 +1,155 @@
+/*
+ Unix SMB/CIFS implementation.
+ client file read/write routines
+ Copyright (C) Andrew Tridgell 1994-1998
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Read size bytes at offset offset using SMBreadX.
+****************************************************************************/
+ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size)
+{
+ union smb_read parms;
+ int readsize;
+ ssize_t total = 0;
+
+ if (size == 0) {
+ return 0;
+ }
+
+ parms.readx.level = RAW_READ_READX;
+ parms.readx.in.fnum = fnum;
+
+ /*
+ * Set readsize to the maximum size we can handle in one readX,
+ * rounded down to a multiple of 1024.
+ */
+ readsize = (cli->transport->negotiate.max_xmit - (MIN_SMB_SIZE+32)) & ~1023;
+
+ while (total < size) {
+ NTSTATUS status;
+
+ readsize = MIN(readsize, size-total);
+
+ parms.readx.in.offset = offset;
+ parms.readx.in.mincnt = readsize;
+ parms.readx.in.maxcnt = readsize;
+ parms.readx.in.remaining = size - total;
+ parms.readx.out.data = buf + total;
+
+ status = smb_raw_read(cli->tree, &parms);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+
+ total += parms.readx.out.nread;
+ offset += parms.readx.out.nread;
+
+ /* If the server returned less than we asked for we're at EOF */
+ if (parms.readx.out.nread < readsize)
+ break;
+ }
+
+ return total;
+}
+
+
+/****************************************************************************
+ write to a file
+ write_mode: 0x0001 disallow write cacheing
+ 0x0002 return bytes remaining
+ 0x0004 use raw named pipe protocol
+ 0x0008 start of message mode named pipe protocol
+****************************************************************************/
+ssize_t cli_write(struct cli_state *cli,
+ int fnum, uint16 write_mode,
+ const char *buf, off_t offset, size_t size)
+{
+ union smb_write parms;
+ int block = (cli->transport->negotiate.max_xmit - (MIN_SMB_SIZE+32)) & ~1023;
+ ssize_t total = 0;
+
+ if (size == 0) {
+ return 0;
+ }
+
+ parms.writex.level = RAW_WRITE_WRITEX;
+ parms.writex.in.fnum = fnum;
+ parms.writex.in.wmode = write_mode;
+ parms.writex.in.remaining = 0;
+
+ while (total < size) {
+ NTSTATUS status;
+
+ block = MIN(block, size - total);
+
+ parms.writex.in.offset = offset;
+ parms.writex.in.count = block;
+ parms.writex.in.data = buf;
+
+ status = smb_raw_write(cli->tree, &parms);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+
+ offset += parms.writex.out.nwritten;
+ total += parms.writex.out.nwritten;
+ buf += parms.writex.out.nwritten;
+ }
+
+ return total;
+}
+
+/****************************************************************************
+ write to a file using a SMBwrite and not bypassing 0 byte writes
+****************************************************************************/
+ssize_t cli_smbwrite(struct cli_state *cli,
+ int fnum, char *buf, off_t offset, size_t size1)
+{
+ union smb_write parms;
+ ssize_t total = 0;
+
+ parms.write.level = RAW_WRITE_WRITE;
+ parms.write.in.remaining = 0;
+
+ do {
+ size_t size = MIN(size1, cli->transport->negotiate.max_xmit - 48);
+
+ parms.write.in.fnum = fnum;
+ parms.write.in.offset = offset;
+ parms.write.in.count = size;
+ parms.write.in.data = buf + total;
+
+ if (NT_STATUS_IS_ERR(smb_raw_write(cli->tree, &parms)))
+ return -1;
+
+ size = parms.write.out.nwritten;
+ if (size == 0)
+ break;
+
+ size1 -= size;
+ total += size;
+ offset += size;
+ } while (size1);
+
+ return total;
+}
diff --git a/source4/libcli/clisecdesc.c b/source4/libcli/clisecdesc.c
new file mode 100644
index 0000000000..66272251ec
--- /dev/null
+++ b/source4/libcli/clisecdesc.c
@@ -0,0 +1,121 @@
+/*
+ Unix SMB/CIFS implementation.
+ client security descriptor functions
+ Copyright (C) Andrew Tridgell 2000
+ Copyright (C) James J Myers 2003 <myersjj@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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ query the security descriptor for a open file
+ ****************************************************************************/
+SEC_DESC *cli_query_secdesc(struct cli_state *cli, int fnum,
+ TALLOC_CTX *mem_ctx)
+{
+ struct smb_nttrans parms;
+ char param[8];
+ DATA_BLOB param_blob;
+ prs_struct pd;
+ SEC_DESC *psd = NULL;
+ NTSTATUS status;
+
+ param_blob.length = 8;
+ param_blob.data = &param[0];
+
+ SIVAL(param, 0, fnum);
+ SSVAL(param, 4, 0x7);
+
+ parms.in.max_param = 1024;
+ parms.in.max_data = 1024;
+ parms.in.max_setup = 0;
+ parms.in.setup_count = 18;
+ parms.in.function = NT_TRANSACT_QUERY_SECURITY_DESC;
+ parms.in.params = param_blob;
+ parms.in.data = data_blob(NULL, 0);
+
+ status = smb_raw_nttrans(cli->tree, mem_ctx, &parms);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1,("Failed to send NT_TRANSACT_QUERY_SECURITY_DESC\n"));
+ goto cleanup;
+ }
+
+ prs_init(&pd, parms.out.data.length, mem_ctx, UNMARSHALL);
+ prs_copy_data_in(&pd, parms.out.data.data, parms.out.data.length);
+ prs_set_offset(&pd,0);
+
+ if (!sec_io_desc("sd data", &psd, &pd, 1)) {
+ DEBUG(1,("Failed to parse secdesc\n"));
+ goto cleanup;
+ }
+
+ cleanup:
+ prs_mem_free(&pd);
+ return psd;
+}
+
+/****************************************************************************
+ set the security descriptor for a open file
+ ****************************************************************************/
+BOOL cli_set_secdesc(struct cli_state *cli, int fnum, SEC_DESC *sd)
+{
+ struct smb_nttrans parms;
+ char param[8];
+ DATA_BLOB param_blob;
+ prs_struct pd;
+ BOOL ret = False;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+
+ mem_ctx = talloc_init("cli_set_secdesc");
+
+ prs_init(&pd, 0, mem_ctx, MARSHALL);
+ prs_give_memory(&pd, NULL, 0, True);
+
+ if (!sec_io_desc("sd data", &sd, &pd, 1)) {
+ DEBUG(1,("Failed to marshall secdesc\n"));
+ goto cleanup;
+ }
+
+ param_blob.length = 8;
+ param_blob.data = &param[0];
+
+ SIVAL(param, 0, fnum);
+ SSVAL(param, 4, 0x7);
+
+ parms.in.max_param = 1000;
+ parms.in.max_data = 1000;
+ parms.in.max_setup = 0;
+ parms.in.setup_count = 18;
+ parms.in.function = NT_TRANSACT_SET_SECURITY_DESC;
+ parms.in.params = param_blob;
+ parms.in.data = data_blob(NULL, 0);
+
+ status = smb_raw_nttrans(cli->tree, mem_ctx, &parms);
+
+ if (NT_STATUS_IS_ERR(status)) {
+ DEBUG(1,("Failed to send NT_TRANSACT_SET_SECURITY_DESC\n"));
+ goto cleanup;
+ }
+ ret = True;
+
+ cleanup:
+ prs_mem_free(&pd);
+ talloc_destroy(mem_ctx);
+ return ret;
+}
diff --git a/source4/libcli/clitrans2.c b/source4/libcli/clitrans2.c
new file mode 100644
index 0000000000..6fd5c2ce28
--- /dev/null
+++ b/source4/libcli/clitrans2.c
@@ -0,0 +1,221 @@
+/*
+ Unix SMB/CIFS implementation.
+ client trans2 calls
+ Copyright (C) James J Myers 2003 <myersjj@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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+send a qpathinfo call
+****************************************************************************/
+BOOL cli_qpathinfo(struct cli_state *cli, const char *fname,
+ time_t *c_time, time_t *a_time, time_t *m_time,
+ size_t *size, uint16 *mode)
+{
+ union smb_fileinfo parms;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+
+ mem_ctx = talloc_init("cli_qpathinfo");
+ if (!mem_ctx) return False;
+
+ parms.standard.level = RAW_FILEINFO_STANDARD;
+ parms.standard.in.fname = fname;
+
+ status = smb_raw_pathinfo(cli->tree, mem_ctx, &parms);
+ talloc_destroy(mem_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
+
+ if (c_time) {
+ *c_time = parms.standard.out.create_time;
+ }
+ if (a_time) {
+ *a_time = parms.standard.out.access_time;
+ }
+ if (m_time) {
+ *m_time = parms.standard.out.write_time;
+ }
+ if (size) {
+ *size = parms.standard.out.size;
+ }
+ if (mode) {
+ *mode = parms.standard.out.attrib;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
+****************************************************************************/
+BOOL cli_qpathinfo2(struct cli_state *cli, const char *fname,
+ time_t *c_time, time_t *a_time, time_t *m_time,
+ time_t *w_time, size_t *size, uint16 *mode,
+ SMB_INO_T *ino)
+{
+ union smb_fileinfo parms;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+
+ mem_ctx = talloc_init("cli_qfilename");
+ if (!mem_ctx) return False;
+
+ parms.all_info.level = RAW_FILEINFO_ALL_INFO;
+ parms.all_info.in.fname = fname;
+
+ status = smb_raw_pathinfo(cli->tree, mem_ctx, &parms);
+ talloc_destroy(mem_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
+
+ if (c_time) {
+ *c_time = nt_time_to_unix(&parms.all_info.out.create_time);
+ }
+ if (a_time) {
+ *a_time = nt_time_to_unix(&parms.all_info.out.access_time);
+ }
+ if (m_time) {
+ *m_time = nt_time_to_unix(&parms.all_info.out.change_time);
+ }
+ if (w_time) {
+ *w_time = nt_time_to_unix(&parms.all_info.out.write_time);
+ }
+ if (size) {
+ *size = parms.all_info.out.size;
+ }
+ if (mode) {
+ *mode = parms.all_info.out.attrib;
+ }
+
+ return True;
+}
+
+
+/****************************************************************************
+send a qfileinfo QUERY_FILE_NAME_INFO call
+****************************************************************************/
+BOOL cli_qfilename(struct cli_state *cli, int fnum,
+ const char **name)
+{
+ union smb_fileinfo parms;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+
+ mem_ctx = talloc_init("cli_qfilename");
+ if (!mem_ctx) return False;
+
+ parms.name_info.level = RAW_FILEINFO_NAME_INFO;
+ parms.name_info.in.fnum = fnum;
+
+ status = smb_raw_fileinfo(cli->tree, mem_ctx, &parms);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_destroy(mem_ctx);
+ *name = NULL;
+ return False;
+ }
+
+ *name = strdup(parms.name_info.out.fname.s);
+
+ talloc_destroy(mem_ctx);
+
+ return True;
+}
+
+
+/****************************************************************************
+send a qfileinfo call
+****************************************************************************/
+BOOL cli_qfileinfo(struct cli_state *cli, int fnum,
+ uint16 *mode, size_t *size,
+ time_t *c_time, time_t *a_time, time_t *m_time,
+ time_t *w_time, SMB_INO_T *ino)
+{
+ union smb_fileinfo parms;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+
+ mem_ctx = talloc_init("cli_qfileinfo");
+ if (!mem_ctx) return False;
+
+ parms.all_info.level = RAW_FILEINFO_ALL_INFO;
+ parms.all_info.in.fnum = fnum;
+
+ status = smb_raw_fileinfo(cli->tree, mem_ctx, &parms);
+ talloc_destroy(mem_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
+
+ if (c_time) {
+ *c_time = nt_time_to_unix(&parms.all_info.out.create_time);
+ }
+ if (a_time) {
+ *a_time = nt_time_to_unix(&parms.all_info.out.access_time);
+ }
+ if (m_time) {
+ *m_time = nt_time_to_unix(&parms.all_info.out.change_time);
+ }
+ if (w_time) {
+ *w_time = nt_time_to_unix(&parms.all_info.out.write_time);
+ }
+ if (mode) {
+ *mode = parms.all_info.out.attrib;
+ }
+ if (size) {
+ *size = (size_t)parms.all_info.out.size;
+ }
+ if (ino) {
+ *ino = 0;
+ }
+
+ return True;
+}
+
+
+/****************************************************************************
+send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call
+****************************************************************************/
+NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname,
+ const char **alt_name)
+{
+ union smb_fileinfo parms;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+
+ parms.alt_name_info.level = RAW_FILEINFO_ALT_NAME_INFO;
+ parms.alt_name_info.in.fname = fname;
+
+ mem_ctx = talloc_init("cli_qpathinfo_alt_name");
+ if (!mem_ctx) return NT_STATUS_NO_MEMORY;
+
+ status = smb_raw_pathinfo(cli->tree, mem_ctx, &parms);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_destroy(mem_ctx);
+ *alt_name = NULL;
+ return cli_nt_error(cli);
+ }
+
+ *alt_name = strdup(parms.alt_name_info.out.fname.s);
+
+ talloc_destroy(mem_ctx);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/libcli/namecache.c b/source4/libcli/namecache.c
new file mode 100644
index 0000000000..9f4796af1a
--- /dev/null
+++ b/source4/libcli/namecache.c
@@ -0,0 +1,246 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ NetBIOS name cache module on top of gencache mechanism.
+
+ Copyright (C) Tim Potter 2002
+ Copyright (C) Rafal Szczesniak 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#define NBTKEY_FMT "NBT/%s#%02X"
+
+
+/**
+ * Initialise namecache system. Function calls gencache
+ * initialisation function to perform necessary actions
+ *
+ * @return true upon successful initialisation of the cache or
+ * false on failure
+ **/
+
+BOOL namecache_enableTODO(void)
+{
+ /*
+ * Check if name caching disabled by setting the name cache
+ * timeout to zero.
+ */
+
+ if (lp_name_cache_timeout() == 0) {
+ DEBUG(5, ("namecache_enable: disabling netbios name cache\n"));
+ return False;
+ }
+
+ /* Init namecache by calling gencache initialisation */
+
+ if (!gencache_init()) {
+ DEBUG(2, ("namecache_enable: Couldn't initialise namecache on top of gencache.\n"));
+ return False;
+ }
+
+ /* I leave it for now, though I don't think we really need this (mimir, 27.09.2002) */
+ DEBUG(5, ("namecache_enable: enabling netbios namecache, timeout %d "
+ "seconds\n", lp_name_cache_timeout()));
+
+ return True;
+}
+
+
+/**
+ * Shutdown namecache. Routine calls gencache close function
+ * to safely close gencache file.
+ *
+ * @return true upon successful shutdown of the cache or
+ * false on failure
+ **/
+
+BOOL namecache_shutdownTODO(void)
+{
+ if (!gencache_shutdown()) {
+ DEBUG(2, ("namecache_shutdown: Couldn't close namecache on top of gencache.\n"));
+ return False;
+ }
+
+ DEBUG(5, ("namecache_shutdown: netbios namecache closed successfully.\n"));
+ return True;
+}
+
+
+/**
+ * Generates a key for netbios name lookups on basis of
+ * netbios name and type.
+ * The caller must free returned key string when finished.
+ *
+ * @param name netbios name string (case insensitive)
+ * @param name_type netbios type of the name being looked up
+ *
+ * @return string consisted of uppercased name and appended
+ * type number
+ */
+
+static char* namecache_key(TALLOC_CTX *mem_ctx, const char *name, int name_type)
+{
+ char *keystr;
+ asprintf(&keystr, NBTKEY_FMT, strupper_talloc(mem_ctx, name), name_type);
+
+ return keystr;
+}
+
+
+/**
+ * Store a name(s) in the name cache
+ *
+ * @param name netbios names array
+ * @param name_type integer netbios name type
+ * @param num_names number of names being stored
+ * @param ip_list array of in_addr structures containing
+ * ip addresses being stored
+ **/
+
+BOOL namecache_store(TALLOC_CTX *mem_ctx, const char *name, int name_type,
+ int num_names, struct in_addr *ip_list)
+{
+ time_t expiry;
+ char *key, *value_string;
+ int i;
+
+ /*
+ * we use gecache call to avoid annoying debug messages about
+ * initialised namecache again and again...
+ */
+ if (!gencache_init()) return False;
+
+ DEBUG(5, ("namecache_store: storing %d address%s for %s#%02x: ",
+ num_names, num_names == 1 ? "": "es", name, name_type));
+
+ for (i = 0; i < num_names; i++)
+ DEBUGADD(5, ("%s%s", inet_ntoa(ip_list[i]),
+ i == (num_names - 1) ? "" : ", "));
+
+ DEBUGADD(5, ("\n"));
+
+ key = namecache_key(mem_ctx, name, name_type);
+
+ /*
+ * Cache pdc location or dc lists for only a little while
+ * otherwise if we lock on to a bad DC we can potentially be
+ * out of action for the entire cache timeout time!
+ */
+
+ if (name_type == 0x1b || name_type == 0x1c)
+ expiry = time(NULL) + 10;
+ else
+ expiry = time(NULL) + lp_name_cache_timeout();
+
+ /*
+ * Generate string representation of ip addresses list
+ * First, store the number of ip addresses and then
+ * place each single ip
+ */
+ ipstr_list_make(&value_string, ip_list, num_names);
+
+ /* set the entry */
+ return (gencache_set(key, value_string, expiry));
+}
+
+
+/**
+ * Look up a name in the cache.
+ *
+ * @param name netbios name to look up for
+ * @param name_type netbios name type of @param name
+ * @param ip_list mallocated list of IP addresses if found in the cache,
+ * NULL otherwise
+ * @param num_names number of entries found
+ *
+ * @return true upon successful fetch or
+ * false if name isn't found in the cache or has expired
+ **/
+
+BOOL namecache_fetch(TALLOC_CTX *mem_ctx, const char *name, int name_type, struct in_addr **ip_list,
+ int *num_names)
+{
+ char *key, *value;
+ time_t timeout;
+
+ *num_names = 0;
+
+ /* exit now if null pointers were passed as they're required further */
+ if (!ip_list || !num_names) return False;
+
+ if (!gencache_init())
+ return False;
+
+ /*
+ * Use gencache interface - lookup the key
+ */
+ key = namecache_key(mem_ctx, name, name_type);
+
+ if (!gencache_get(key, &value, &timeout)) {
+ DEBUG(5, ("no entry for %s#%02X found.\n", name, name_type));
+ SAFE_FREE(key);
+ return False;
+ } else {
+ DEBUG(5, ("name %s#%02X found.\n", name, name_type));
+ }
+
+ /*
+ * Split up the stored value into the list of IP adresses
+ */
+ *num_names = ipstr_list_parse(value, ip_list);
+
+ SAFE_FREE(key);
+ SAFE_FREE(value);
+ return *num_names > 0; /* true only if some ip has been fetched */
+}
+
+
+/**
+ * Delete single namecache entry. Look at the
+ * gencache_iterate definition.
+ *
+ **/
+
+static void flush_netbios_name(const char* key, const char *value, time_t timeout, void* dptr)
+{
+ gencache_del(key);
+ DEBUG(5, ("Deleting entry %s\n", key));
+}
+
+
+/**
+ * Flush all names from the name cache.
+ * It's done by gencache_iterate()
+ *
+ * @return True upon successful deletion or
+ * False in case of an error
+ **/
+
+void namecache_flush(void)
+{
+ if (!gencache_init())
+ return;
+
+ /*
+ * iterate through each NBT cache's entry and flush it
+ * by flush_netbios_name function
+ */
+ gencache_iterate(flush_netbios_name, NULL, "NBT/*");
+ DEBUG(5, ("Namecache flushed\n"));
+}
+
diff --git a/source4/libcli/namequery.c b/source4/libcli/namequery.c
new file mode 100644
index 0000000000..2f6343dcaf
--- /dev/null
+++ b/source4/libcli/namequery.c
@@ -0,0 +1,1333 @@
+/*
+ Unix SMB/CIFS implementation.
+ name query routines
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+/* nmbd.c sets this to True. */
+BOOL global_in_nmbd = False;
+
+/****************************************************************************
+generate a random trn_id
+****************************************************************************/
+static int generate_trn_id(void)
+{
+ static int trn_id;
+
+ if (trn_id == 0) {
+ sys_srandom(getpid());
+ }
+
+ trn_id = sys_random();
+
+ return trn_id % (unsigned)0x7FFF;
+}
+
+
+/****************************************************************************
+ parse a node status response into an array of structures
+****************************************************************************/
+static struct node_status *parse_node_status(char *p, int *num_names)
+{
+ struct node_status *ret;
+ int i;
+
+ *num_names = CVAL(p,0);
+
+ if (*num_names == 0) return NULL;
+
+ ret = (struct node_status *)malloc(sizeof(struct node_status)* (*num_names));
+ if (!ret) return NULL;
+
+ p++;
+ for (i=0;i< *num_names;i++) {
+ StrnCpy(ret[i].name,p,15);
+ trim_string(ret[i].name,NULL," ");
+ ret[i].type = CVAL(p,15);
+ ret[i].flags = p[16];
+ p += 18;
+ DEBUG(10, ("%s#%02x: flags = 0x%02x\n", ret[i].name,
+ ret[i].type, ret[i].flags));
+ }
+ return ret;
+}
+
+
+/****************************************************************************
+do a NBT node status query on an open socket and return an array of
+structures holding the returned names or NULL if the query failed
+**************************************************************************/
+struct node_status *node_status_query(int fd,struct nmb_name *name,
+ struct in_addr to_ip, int *num_names)
+{
+ BOOL found=False;
+ int retries = 2;
+ int retry_time = 2000;
+ struct timeval tval;
+ struct packet_struct p;
+ struct packet_struct *p2;
+ struct nmb_packet *nmb = &p.packet.nmb;
+ struct node_status *ret;
+
+ ZERO_STRUCT(p);
+
+ nmb->header.name_trn_id = generate_trn_id();
+ nmb->header.opcode = 0;
+ nmb->header.response = False;
+ nmb->header.nm_flags.bcast = False;
+ nmb->header.nm_flags.recursion_available = False;
+ nmb->header.nm_flags.recursion_desired = False;
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = False;
+ nmb->header.rcode = 0;
+ nmb->header.qdcount = 1;
+ nmb->header.ancount = 0;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = 0;
+ nmb->question.question_name = *name;
+ nmb->question.question_type = 0x21;
+ nmb->question.question_class = 0x1;
+
+ p.ip = to_ip;
+ p.port = NMB_PORT;
+ p.fd = fd;
+ p.timestamp = time(NULL);
+ p.packet_type = NMB_PACKET;
+
+ GetTimeOfDay(&tval);
+
+ if (!send_packet(&p))
+ return NULL;
+
+ retries--;
+
+ while (1) {
+ struct timeval tval2;
+ GetTimeOfDay(&tval2);
+ if (TvalDiff(&tval,&tval2) > retry_time) {
+ if (!retries)
+ break;
+ if (!found && !send_packet(&p))
+ return NULL;
+ GetTimeOfDay(&tval);
+ retries--;
+ }
+
+ if ((p2=receive_nmb_packet(fd,90,nmb->header.name_trn_id))) {
+ struct nmb_packet *nmb2 = &p2->packet.nmb;
+ debug_nmb_packet(p2);
+
+ if (nmb2->header.opcode != 0 ||
+ nmb2->header.nm_flags.bcast ||
+ nmb2->header.rcode ||
+ !nmb2->header.ancount ||
+ nmb2->answers->rr_type != 0x21) {
+ /* XXXX what do we do with this? could be a
+ redirect, but we'll discard it for the
+ moment */
+ free_packet(p2);
+ continue;
+ }
+
+ ret = parse_node_status(&nmb2->answers->rdata[0], num_names);
+ free_packet(p2);
+ return ret;
+ }
+ }
+
+ return NULL;
+}
+
+
+/****************************************************************************
+find the first type XX name in a node status reply - used for finding
+a servers name given its IP
+return the matched name in *name
+**************************************************************************/
+
+BOOL name_status_find(const char *q_name, int q_type, int type, struct in_addr to_ip, char *name)
+{
+ struct node_status *status = NULL;
+ struct nmb_name nname;
+ int count, i;
+ int sock;
+ BOOL result = False;
+
+ if (lp_disable_netbios()) {
+ DEBUG(5,("name_status_find(%s#%02x): netbios is disabled\n", q_name, q_type));
+ return False;
+ }
+
+ DEBUG(10, ("name_status_find: looking up %s#%02x at %s\n", q_name,
+ q_type, inet_ntoa(to_ip)));
+
+ sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True);
+ if (sock == -1)
+ goto done;
+
+ /* W2K PDC's seem not to respond to '*'#0. JRA */
+ make_nmb_name(&nname, q_name, q_type);
+ status = node_status_query(sock, &nname, to_ip, &count);
+ close(sock);
+ if (!status)
+ goto done;
+
+ for (i=0;i<count;i++) {
+ if (status[i].type == type)
+ break;
+ }
+ if (i == count)
+ goto done;
+
+ pull_ascii(name, status[i].name, 16, 15, STR_TERMINATE);
+ result = True;
+
+ done:
+ SAFE_FREE(status);
+
+ DEBUG(10, ("name_status_find: name %sfound", result ? "" : "not "));
+
+ if (result)
+ DEBUGADD(10, (", ip address is %s", inet_ntoa(to_ip)));
+
+ DEBUG(10, ("\n"));
+
+ return result;
+}
+
+
+/*
+ comparison function used by sort_ip_list
+*/
+int ip_compare(struct in_addr *ip1, struct in_addr *ip2)
+{
+ int max_bits1=0, max_bits2=0;
+ int num_interfaces = iface_count();
+ int i;
+
+ for (i=0;i<num_interfaces;i++) {
+ struct in_addr ip;
+ int bits1, bits2;
+ ip = *iface_n_bcast(i);
+ bits1 = matching_quad_bits((uchar *)&ip1->s_addr, (uchar *)&ip.s_addr);
+ bits2 = matching_quad_bits((uchar *)&ip2->s_addr, (uchar *)&ip.s_addr);
+ max_bits1 = MAX(bits1, max_bits1);
+ max_bits2 = MAX(bits2, max_bits2);
+ }
+
+ /* bias towards directly reachable IPs */
+ if (iface_local(*ip1)) {
+ max_bits1 += 32;
+ }
+ if (iface_local(*ip2)) {
+ max_bits2 += 32;
+ }
+
+ return max_bits2 - max_bits1;
+}
+
+/*
+ sort an IP list so that names that are close to one of our interfaces
+ are at the top. This prevents the problem where a WINS server returns an IP that
+ is not reachable from our subnet as the first match
+*/
+static void sort_ip_list(struct in_addr *iplist, int count)
+{
+ if (count <= 1) {
+ return;
+ }
+
+ qsort(iplist, count, sizeof(struct in_addr), QSORT_CAST ip_compare);
+}
+
+
+/****************************************************************************
+ Do a netbios name query to find someones IP.
+ Returns an array of IP addresses or NULL if none.
+ *count will be set to the number of addresses returned.
+ *timed_out is set if we failed by timing out
+****************************************************************************/
+struct in_addr *name_query(int fd,const char *name,int name_type,
+ BOOL bcast,BOOL recurse,
+ struct in_addr to_ip, int *count, int *flags,
+ BOOL *timed_out)
+{
+ BOOL found=False;
+ int i, retries = 3;
+ int retry_time = bcast?250:2000;
+ struct timeval tval;
+ struct packet_struct p;
+ struct packet_struct *p2;
+ struct nmb_packet *nmb = &p.packet.nmb;
+ struct in_addr *ip_list = NULL;
+
+ if (lp_disable_netbios()) {
+ DEBUG(5,("name_query(%s#%02x): netbios is disabled\n", name, name_type));
+ return NULL;
+ }
+
+ if (timed_out) {
+ *timed_out = False;
+ }
+
+ memset((char *)&p,'\0',sizeof(p));
+ (*count) = 0;
+ (*flags) = 0;
+
+ nmb->header.name_trn_id = generate_trn_id();
+ nmb->header.opcode = 0;
+ nmb->header.response = False;
+ nmb->header.nm_flags.bcast = bcast;
+ nmb->header.nm_flags.recursion_available = False;
+ nmb->header.nm_flags.recursion_desired = recurse;
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = False;
+ nmb->header.rcode = 0;
+ nmb->header.qdcount = 1;
+ nmb->header.ancount = 0;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = 0;
+
+ make_nmb_name(&nmb->question.question_name,name,name_type);
+
+ nmb->question.question_type = 0x20;
+ nmb->question.question_class = 0x1;
+
+ p.ip = to_ip;
+ p.port = NMB_PORT;
+ p.fd = fd;
+ p.timestamp = time(NULL);
+ p.packet_type = NMB_PACKET;
+
+ GetTimeOfDay(&tval);
+
+ if (!send_packet(&p))
+ return NULL;
+
+ retries--;
+
+ while (1) {
+ struct timeval tval2;
+ struct in_addr *tmp_ip_list;
+
+ GetTimeOfDay(&tval2);
+ if (TvalDiff(&tval,&tval2) > retry_time) {
+ if (!retries)
+ break;
+ if (!found && !send_packet(&p))
+ return NULL;
+ GetTimeOfDay(&tval);
+ retries--;
+ }
+
+ if ((p2=receive_nmb_packet(fd,90,nmb->header.name_trn_id))) {
+ struct nmb_packet *nmb2 = &p2->packet.nmb;
+ debug_nmb_packet(p2);
+
+ /* If we get a Negative Name Query Response from a WINS
+ * server, we should report it and give up.
+ */
+ if( 0 == nmb2->header.opcode /* A query response */
+ && !(bcast) /* from a WINS server */
+ && nmb2->header.rcode /* Error returned */
+ ) {
+
+ if (DEBUGLVL(3)) {
+ /* Only executed if DEBUGLEVEL >= 3 */
+ DEBUG(3,("Negative name query response, rcode 0x%02x: ", nmb2->header.rcode ));
+ switch( nmb2->header.rcode ) {
+ case 0x01:
+ DEBUG(3,("Request was invalidly formatted.\n" ));
+ break;
+ case 0x02:
+ DEBUG(3,("Problem with NBNS, cannot process name.\n"));
+ break;
+ case 0x03:
+ DEBUG(3,("The name requested does not exist.\n" ));
+ break;
+ case 0x04:
+ DEBUG(3,("Unsupported request error.\n" ));
+ break;
+ case 0x05:
+ DEBUG(3,("Query refused error.\n" ));
+ break;
+ default:
+ DEBUG(3,("Unrecognized error code.\n" ));
+ break;
+ }
+ }
+ free_packet(p2);
+ return( NULL );
+ }
+
+ if (nmb2->header.opcode != 0 ||
+ nmb2->header.nm_flags.bcast ||
+ nmb2->header.rcode ||
+ !nmb2->header.ancount) {
+ /*
+ * XXXX what do we do with this? Could be a
+ * redirect, but we'll discard it for the
+ * moment.
+ */
+ free_packet(p2);
+ continue;
+ }
+
+ tmp_ip_list = (struct in_addr *)Realloc( ip_list, sizeof( ip_list[0] )
+ * ( (*count) + nmb2->answers->rdlength/6 ) );
+
+ if (!tmp_ip_list) {
+ DEBUG(0,("name_query: Realloc failed.\n"));
+ SAFE_FREE(ip_list);
+ }
+
+ ip_list = tmp_ip_list;
+
+ if (ip_list) {
+ DEBUG(2,("Got a positive name query response from %s ( ", inet_ntoa(p2->ip)));
+ for (i=0;i<nmb2->answers->rdlength/6;i++) {
+ putip((char *)&ip_list[(*count)],&nmb2->answers->rdata[2+i*6]);
+ DEBUGADD(2,("%s ",inet_ntoa(ip_list[(*count)])));
+ (*count)++;
+ }
+ DEBUGADD(2,(")\n"));
+ }
+
+ found=True;
+ retries=0;
+ /* We add the flags back ... */
+ if (nmb2->header.response)
+ (*flags) |= NM_FLAGS_RS;
+ if (nmb2->header.nm_flags.authoritative)
+ (*flags) |= NM_FLAGS_AA;
+ if (nmb2->header.nm_flags.trunc)
+ (*flags) |= NM_FLAGS_TC;
+ if (nmb2->header.nm_flags.recursion_desired)
+ (*flags) |= NM_FLAGS_RD;
+ if (nmb2->header.nm_flags.recursion_available)
+ (*flags) |= NM_FLAGS_RA;
+ if (nmb2->header.nm_flags.bcast)
+ (*flags) |= NM_FLAGS_B;
+ free_packet(p2);
+ /*
+ * If we're doing a unicast lookup we only
+ * expect one reply. Don't wait the full 2
+ * seconds if we got one. JRA.
+ */
+ if(!bcast && found)
+ break;
+ }
+ }
+
+ if (timed_out) {
+ *timed_out = True;
+ }
+
+ /* sort the ip list so we choose close servers first if possible */
+ sort_ip_list(ip_list, *count);
+
+ return ip_list;
+}
+
+/********************************************************
+ Start parsing the lmhosts file.
+*********************************************************/
+
+XFILE *startlmhosts(char *fname)
+{
+ XFILE *fp = x_fopen(fname,O_RDONLY, 0);
+ 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 *mem_ctx,
+ XFILE *fp, pstring name, int *name_type, struct in_addr *ipaddr)
+{
+ pstring line;
+
+ while(!x_feof(fp) && !x_ferror(fp)) {
+ pstring ip,flags,extra;
+ const char *ptr;
+ char *ptr1;
+ int count = 0;
+
+ *name_type = -1;
+
+ if (!fgets_slash(line,sizeof(pstring),fp))
+ continue;
+
+ if (*line == '#')
+ continue;
+
+ pstrcpy(ip,"");
+ pstrcpy(name,"");
+ pstrcpy(flags,"");
+
+ ptr = line;
+
+ if (next_token(&ptr,ip ,NULL,sizeof(ip)))
+ ++count;
+ if (next_token(&ptr,name ,NULL, sizeof(pstring)))
+ ++count;
+ if (next_token(&ptr,flags,NULL, sizeof(flags)))
+ ++count;
+ if (next_token(&ptr,extra,NULL, sizeof(extra)))
+ ++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;
+ }
+
+ 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;
+ }
+
+ *ipaddr = *interpret_addr2(mem_ctx, 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 '#' */
+ }
+
+ return True;
+ }
+
+ return False;
+}
+
+/********************************************************
+ Finish parsing the lmhosts file.
+*********************************************************/
+
+void endlmhosts(XFILE *fp)
+{
+ x_fclose(fp);
+}
+
+
+/********************************************************
+ Resolve via "bcast" method.
+*********************************************************/
+
+BOOL name_resolve_bcast(const char *name, int name_type,
+ struct in_addr **return_ip_list, int *return_count)
+{
+ int sock, i;
+ int num_interfaces = iface_count();
+
+ if (lp_disable_netbios()) {
+ DEBUG(5,("name_resolve_bcast(%s#%02x): netbios is disabled\n", name, name_type));
+ return False;
+ }
+
+ *return_ip_list = NULL;
+ *return_count = 0;
+
+ /*
+ * "bcast" means do a broadcast lookup on all the local interfaces.
+ */
+
+ DEBUG(3,("name_resolve_bcast: Attempting broadcast lookup for name %s<0x%x>\n", name, name_type));
+
+ sock = open_socket_in( SOCK_DGRAM, 0, 3,
+ interpret_addr(lp_socket_address()), True );
+
+ if (sock == -1) return False;
+
+ set_socket_options(sock,"SO_BROADCAST");
+ /*
+ * Lookup the name on all the interfaces, return on
+ * the first successful match.
+ */
+ for( i = num_interfaces-1; i >= 0; i--) {
+ struct in_addr sendto_ip;
+ int flags;
+ /* Done this way to fix compiler error on IRIX 5.x */
+ sendto_ip = *iface_n_bcast(i);
+ *return_ip_list = name_query(sock, name, name_type, True,
+ True, sendto_ip, return_count, &flags, NULL);
+ if(*return_ip_list != NULL) {
+ close(sock);
+ return True;
+ }
+ }
+
+ close(sock);
+ return False;
+}
+
+/********************************************************
+ Resolve via "wins" method.
+*********************************************************/
+BOOL resolve_wins(TALLOC_CTX *mem_ctx, const char *name, int name_type,
+ struct in_addr **return_iplist, int *return_count)
+{
+ int sock, t, i;
+ char **wins_tags;
+ struct in_addr src_ip;
+
+ if (lp_disable_netbios()) {
+ DEBUG(5,("resolve_wins(%s#%02x): netbios is disabled\n", name, name_type));
+ return False;
+ }
+
+ *return_iplist = NULL;
+ *return_count = 0;
+
+ DEBUG(3,("resolve_wins: Attempting wins lookup for name %s<0x%x>\n", name, name_type));
+
+ if (wins_srv_count() < 1) {
+ DEBUG(3,("resolve_wins: WINS server resolution selected and no WINS servers listed.\n"));
+ return False;
+ }
+
+ /* we try a lookup on each of the WINS tags in turn */
+ wins_tags = wins_srv_tags();
+
+ if (!wins_tags) {
+ /* huh? no tags?? give up in disgust */
+ return False;
+ }
+
+ /* the address we will be sending from */
+ src_ip = *interpret_addr2(mem_ctx, lp_socket_address());
+
+ /* in the worst case we will try every wins server with every
+ tag! */
+ for (t=0; wins_tags && wins_tags[t]; t++) {
+ int srv_count = wins_srv_count_tag(wins_tags[t]);
+ for (i=0; i<srv_count; i++) {
+ struct in_addr wins_ip;
+ int flags;
+ BOOL timed_out;
+
+ wins_ip = wins_srv_ip_tag(wins_tags[t], src_ip);
+
+ if (global_in_nmbd && ismyip(wins_ip)) {
+ /* yikes! we'll loop forever */
+ continue;
+ }
+
+ /* skip any that have been unresponsive lately */
+ if (wins_srv_is_dead(wins_ip, src_ip)) {
+ continue;
+ }
+
+ DEBUG(3,("resolve_wins: using WINS server %s and tag '%s'\n", inet_ntoa(wins_ip), wins_tags[t]));
+
+ sock = open_socket_in(SOCK_DGRAM, 0, 3, src_ip.s_addr, True);
+ if (sock == -1) {
+ continue;
+ }
+
+ *return_iplist = name_query(sock,name,name_type, False,
+ True, wins_ip, return_count, &flags,
+ &timed_out);
+ if (*return_iplist != NULL) {
+ goto success;
+ }
+ close(sock);
+
+ if (timed_out) {
+ /* Timed out wating for WINS server to respond. Mark it dead. */
+ wins_srv_died(wins_ip, src_ip);
+ } else {
+ /* The name definately isn't in this
+ group of WINS servers. goto the next group */
+ break;
+ }
+ }
+ }
+
+ wins_srv_tags_free(wins_tags);
+ return False;
+
+success:
+ wins_srv_tags_free(wins_tags);
+ close(sock);
+ return True;
+}
+
+/********************************************************
+ Resolve via "hosts" method.
+*********************************************************/
+
+static BOOL resolve_hosts(const char *name,
+ struct in_addr **return_iplist, int *return_count)
+{
+ /*
+ * "host" means do a localhost, or dns lookup.
+ */
+ struct hostent *hp;
+
+ *return_iplist = NULL;
+ *return_count = 0;
+
+ DEBUG(3,("resolve_hosts: Attempting host lookup for name %s<0x20>\n", name));
+
+ if (((hp = sys_gethostbyname(name)) != NULL) && (hp->h_addr != NULL)) {
+ struct in_addr return_ip;
+ putip((char *)&return_ip,(char *)hp->h_addr);
+ *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr));
+ if(*return_iplist == NULL) {
+ DEBUG(3,("resolve_hosts: malloc fail !\n"));
+ return False;
+ }
+ **return_iplist = return_ip;
+ *return_count = 1;
+ return True;
+ }
+ return False;
+}
+
+/********************************************************
+ Internal interface to resolve a name into an IP address.
+ Use this function if the string is either an IP address, DNS
+ or host name or NetBIOS name. This uses the name switch in the
+ smb.conf to determine the order of name resolution.
+*********************************************************/
+
+static BOOL internal_resolve_name(TALLOC_CTX *mem_ctx, const char *name, int name_type,
+ struct in_addr **return_iplist, int *return_count)
+{
+ char *name_resolve_list;
+ fstring tok;
+ const char *ptr;
+ BOOL allones = (strcmp(name,"255.255.255.255") == 0);
+ BOOL allzeros = (strcmp(name,"0.0.0.0") == 0);
+ BOOL is_address = is_ipaddress(name);
+ BOOL result = False;
+ struct in_addr *nodupes_iplist;
+ int i;
+
+ *return_iplist = NULL;
+ *return_count = 0;
+
+ DEBUG(10, ("internal_resolve_name: looking up %s#%x\n", name, name_type));
+
+ if (allzeros || allones || is_address) {
+ *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr));
+ if(*return_iplist == NULL) {
+ DEBUG(3,("internal_resolve_name: malloc fail !\n"));
+ return False;
+ }
+ if(is_address) {
+ /* if it's in the form of an IP address then get the lib to interpret it */
+ if (((*return_iplist)->s_addr = inet_addr(name)) == 0xFFFFFFFF ){
+ DEBUG(1,("internal_resolve_name: inet_addr failed on %s\n", name));
+ return False;
+ }
+ } else {
+ (*return_iplist)->s_addr = allones ? 0xFFFFFFFF : 0;
+ *return_count = 1;
+ }
+ return True;
+ }
+
+ /* Check netbios name cache */
+
+ if (namecache_fetch(mem_ctx, name, name_type, return_iplist, return_count)) {
+
+ /* This could be a negative response */
+
+ return (*return_count > 0);
+ }
+
+ name_resolve_list = talloc_strdup(mem_ctx, lp_name_resolve_order());
+ ptr = name_resolve_list;
+ if (!ptr || !*ptr)
+ ptr = "host";
+
+ while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
+ if((strequal(tok, "host") || strequal(tok, "hosts"))) {
+ if (name_type == 0x20) {
+ if (resolve_hosts(name, return_iplist, return_count)) {
+ result = True;
+ goto done;
+ }
+ }
+ } else if(strequal( tok, "lmhosts")) {
+ /* REWRITE: add back in? */
+ DEBUG(0,("resolve_name: REWRITE: add lmhosts back?? %s\n", tok));
+ } else if(strequal( tok, "wins")) {
+ /* don't resolve 1D via WINS */
+ if (name_type != 0x1D &&
+ resolve_wins(mem_ctx, name, name_type, return_iplist, return_count)) {
+ result = True;
+ goto done;
+ }
+ } else if(strequal( tok, "bcast")) {
+ if (name_resolve_bcast(name, name_type, return_iplist, return_count)) {
+ result = True;
+ goto done;
+ }
+ } else {
+ DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));
+ }
+ }
+
+ /* All of the resolve_* functions above have returned false. */
+
+ SAFE_FREE(*return_iplist);
+ *return_count = 0;
+
+ return False;
+
+ done:
+
+ /* Remove duplicate entries. Some queries, notably #1c (domain
+ controllers) return the PDC in iplist[0] and then all domain
+ controllers including the PDC in iplist[1..n]. Iterating over
+ the iplist when the PDC is down will cause two sets of timeouts. */
+
+ if (*return_count && (nodupes_iplist = (struct in_addr *)
+ malloc(sizeof(struct in_addr) * (*return_count)))) {
+ int nodupes_count = 0;
+
+ /* Iterate over return_iplist looking for duplicates */
+
+ for (i = 0; i < *return_count; i++) {
+ BOOL is_dupe = False;
+ int j;
+
+ for (j = i + 1; j < *return_count; j++) {
+ if (ip_equal((*return_iplist)[i],
+ (*return_iplist)[j])) {
+ is_dupe = True;
+ break;
+ }
+ }
+
+ if (!is_dupe) {
+
+ /* This one not a duplicate */
+
+ nodupes_iplist[nodupes_count] = (*return_iplist)[i];
+ nodupes_count++;
+ }
+ }
+
+ /* Switcheroo with original list */
+
+ free(*return_iplist);
+
+ *return_iplist = nodupes_iplist;
+ *return_count = nodupes_count;
+ }
+
+ /* Save in name cache */
+ for (i = 0; i < *return_count && DEBUGLEVEL == 100; i++)
+ DEBUG(100, ("Storing name %s of type %d (ip: %s)\n", name,
+ name_type, inet_ntoa((*return_iplist)[i])));
+
+ namecache_store(mem_ctx, name, name_type, *return_count, *return_iplist);
+
+ /* Display some debugging info */
+
+ DEBUG(10, ("internal_resolve_name: returning %d addresses: ",
+ *return_count));
+
+ for (i = 0; i < *return_count; i++)
+ DEBUGADD(10, ("%s ", inet_ntoa((*return_iplist)[i])));
+
+ DEBUG(10, ("\n"));
+
+ return result;
+}
+
+/********************************************************
+ Internal interface to resolve a name into one IP address.
+ Use this function if the string is either an IP address, DNS
+ or host name or NetBIOS name. This uses the name switch in the
+ smb.conf to determine the order of name resolution.
+*********************************************************/
+BOOL resolve_name(TALLOC_CTX *mem_ctx, const char *name, struct in_addr *return_ip, int name_type)
+{
+ struct in_addr *ip_list = NULL;
+ int count = 0;
+
+ if (is_ipaddress(name)) {
+ *return_ip = *interpret_addr2(mem_ctx, name);
+ return True;
+ }
+
+ if (internal_resolve_name(mem_ctx, name, name_type, &ip_list, &count)) {
+ int i;
+ /* only return valid addresses for TCP connections */
+ for (i=0; i<count; i++) {
+ char *ip_str = inet_ntoa(ip_list[i]);
+ if (ip_str &&
+ strcmp(ip_str, "255.255.255.255") != 0 &&
+ strcmp(ip_str, "0.0.0.0") != 0) {
+ *return_ip = ip_list[i];
+ SAFE_FREE(ip_list);
+ return True;
+ }
+ }
+ }
+ SAFE_FREE(ip_list);
+ return False;
+}
+
+/********************************************************
+ Find the IP address of the master browser or DMB for a workgroup.
+*********************************************************/
+
+BOOL find_master_ip(TALLOC_CTX *mem_ctx, const char *group, struct in_addr *master_ip)
+{
+ struct in_addr *ip_list = NULL;
+ int count = 0;
+
+ if (lp_disable_netbios()) {
+ DEBUG(5,("find_master_ip(%s): netbios is disabled\n", group));
+ return False;
+ }
+
+ if (internal_resolve_name(mem_ctx, group, 0x1D, &ip_list, &count)) {
+ *master_ip = ip_list[0];
+ SAFE_FREE(ip_list);
+ return True;
+ }
+ if(internal_resolve_name(mem_ctx, group, 0x1B, &ip_list, &count)) {
+ *master_ip = ip_list[0];
+ SAFE_FREE(ip_list);
+ return True;
+ }
+
+ SAFE_FREE(ip_list);
+ return False;
+}
+
+/********************************************************
+ Lookup a DC name given a Domain name and IP address.
+*********************************************************/
+
+BOOL lookup_dc_name(const char *srcname, const char *domain,
+ struct in_addr *dc_ip, char *ret_name)
+{
+#if !defined(I_HATE_WINDOWS_REPLY_CODE)
+ fstring dc_name;
+ BOOL ret;
+
+ if (lp_disable_netbios()) {
+ DEBUG(5,("lookup_dc_name(%s): netbios is disabled\n", domain));
+ return False;
+ }
+
+ /*
+ * Due to the fact win WinNT *sucks* we must do a node status
+ * query here... JRA.
+ */
+
+ *dc_name = '\0';
+
+ ret = name_status_find(domain, 0x1c, 0x20, *dc_ip, dc_name);
+
+ if(ret && *dc_name) {
+ fstrcpy(ret_name, dc_name);
+ return True;
+ }
+
+ return False;
+
+#else /* defined(I_HATE_WINDOWS_REPLY_CODE) */
+
+JRA - This code is broken with BDC rollover - we need to do a full
+NT GETDC call, UNICODE, NT domain SID and uncle tom cobbley and all...
+
+ int retries = 3;
+ int retry_time = 2000;
+ struct timeval tval;
+ struct packet_struct p;
+ struct dgram_packet *dgram = &p.packet.dgram;
+ char *ptr,*p2;
+ char tmp[4];
+ int len;
+ struct sockaddr_in sock_name;
+ int sock_len = sizeof(sock_name);
+ const char *mailslot = NET_LOGON_MAILSLOT;
+ char *mailslot_name;
+ char buffer[1024];
+ char *bufp;
+ int dgm_id = generate_trn_id();
+ int sock = open_socket_in(SOCK_DGRAM, 0, 3, interpret_addr(lp_socket_address()), True );
+
+ if(sock == -1)
+ return False;
+
+ /* Find out the transient UDP port we have been allocated. */
+ if(getsockname(sock, (struct sockaddr *)&sock_name, &sock_len)<0) {
+ DEBUG(0,("lookup_pdc_name: Failed to get local UDP port. Error was %s\n",
+ strerror(errno)));
+ close(sock);
+ return False;
+ }
+
+ /*
+ * Create the request data.
+ */
+
+ memset(buffer,'\0',sizeof(buffer));
+ bufp = buffer;
+ SSVAL(bufp,0,QUERYFORPDC);
+ bufp += 2;
+ fstrcpy(bufp,srcname);
+ bufp += (strlen(bufp) + 1);
+ slprintf(bufp, sizeof(fstring)-1, "\\MAILSLOT\\NET\\GETDC%d", dgm_id);
+ mailslot_name = bufp;
+ bufp += (strlen(bufp) + 1);
+ bufp = ALIGN2(bufp, buffer);
+ bufp += push_ucs2(NULL, bufp, srcname, sizeof(buffer) - (bufp - buffer), STR_TERMINATE);
+
+ SIVAL(bufp,0,1);
+ SSVAL(bufp,4,0xFFFF);
+ SSVAL(bufp,6,0xFFFF);
+ bufp += 8;
+ len = PTR_DIFF(bufp,buffer);
+
+ memset((char *)&p,'\0',sizeof(p));
+
+ /* DIRECT GROUP or UNIQUE datagram. */
+ dgram->header.msg_type = 0x10;
+ dgram->header.flags.node_type = M_NODE;
+ dgram->header.flags.first = True;
+ dgram->header.flags.more = False;
+ dgram->header.dgm_id = dgm_id;
+ dgram->header.source_ip = *iface_ip(*pdc_ip);
+ dgram->header.source_port = ntohs(sock_name.sin_port);
+ dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
+ dgram->header.packet_offset = 0;
+
+ make_nmb_name(&dgram->source_name,srcname,0);
+ make_nmb_name(&dgram->dest_name,domain,0x1C);
+
+ ptr = &dgram->data[0];
+
+ /* Setup the smb part. */
+ ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
+ memcpy(tmp,ptr,4);
+ set_message(ptr,17,17 + len,True);
+ memcpy(ptr,tmp,4);
+
+ CVAL(ptr,smb_com) = SMBtrans;
+ SSVAL(ptr,smb_vwv1,len);
+ SSVAL(ptr,smb_vwv11,len);
+ SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
+ SSVAL(ptr,smb_vwv13,3);
+ SSVAL(ptr,smb_vwv14,1);
+ SSVAL(ptr,smb_vwv15,1);
+ SSVAL(ptr,smb_vwv16,2);
+ p2 = smb_buf(ptr);
+ pstrcpy(p2,mailslot);
+ p2 = skip_string(p2,1);
+
+ memcpy(p2,buffer,len);
+ p2 += len;
+
+ dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
+
+ p.ip = *pdc_ip;
+ p.port = DGRAM_PORT;
+ p.fd = sock;
+ p.timestamp = time(NULL);
+ p.packet_type = DGRAM_PACKET;
+
+ GetTimeOfDay(&tval);
+
+ if (!send_packet(&p)) {
+ DEBUG(0,("lookup_pdc_name: send_packet failed.\n"));
+ close(sock);
+ return False;
+ }
+
+ retries--;
+
+ while (1) {
+ struct timeval tval2;
+ struct packet_struct *p_ret;
+
+ GetTimeOfDay(&tval2);
+ if (TvalDiff(&tval,&tval2) > retry_time) {
+ if (!retries)
+ break;
+ if (!send_packet(&p)) {
+ DEBUG(0,("lookup_pdc_name: send_packet failed.\n"));
+ close(sock);
+ return False;
+ }
+ GetTimeOfDay(&tval);
+ retries--;
+ }
+
+ if ((p_ret = receive_dgram_packet(sock,90,mailslot_name))) {
+ struct dgram_packet *dgram2 = &p_ret->packet.dgram;
+ char *buf;
+ char *buf2;
+
+ buf = &dgram2->data[0];
+ buf -= 4;
+
+ if (CVAL(buf,smb_com) != SMBtrans) {
+ DEBUG(0,("lookup_pdc_name: datagram type %u != SMBtrans(%u)\n", (unsigned int)
+ CVAL(buf,smb_com), (unsigned int)SMBtrans ));
+ free_packet(p_ret);
+ continue;
+ }
+
+ len = SVAL(buf,smb_vwv11);
+ buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
+
+ if (len <= 0) {
+ DEBUG(0,("lookup_pdc_name: datagram len < 0 (%d)\n", len ));
+ free_packet(p_ret);
+ continue;
+ }
+
+ DEBUG(4,("lookup_pdc_name: datagram reply from %s to %s IP %s for %s of type %d len=%d\n",
+ nmb_namestr(&dgram2->source_name),nmb_namestr(&dgram2->dest_name),
+ inet_ntoa(p_ret->ip), smb_buf(buf),SVAL(buf2,0),len));
+
+ if(SVAL(buf2,0) != QUERYFORPDC_R) {
+ DEBUG(0,("lookup_pdc_name: datagram type (%u) != QUERYFORPDC_R(%u)\n",
+ (unsigned int)SVAL(buf,0), (unsigned int)QUERYFORPDC_R ));
+ free_packet(p_ret);
+ continue;
+ }
+
+ buf2 += 2;
+ /* Note this is safe as it is a bounded strcpy. */
+ fstrcpy(ret_name, buf2);
+ ret_name[sizeof(fstring)-1] = '\0';
+ close(sock);
+ free_packet(p_ret);
+ return True;
+ }
+ }
+
+ close(sock);
+ return False;
+#endif /* defined(I_HATE_WINDOWS_REPLY_CODE) */
+}
+
+/********************************************************
+ Get the IP address list of the primary domain controller
+ for a domain.
+*********************************************************/
+
+BOOL get_pdc_ip(TALLOC_CTX *mem_ctx, const char *domain, struct in_addr *ip)
+{
+ struct in_addr *ip_list;
+ int count;
+ int i = 0;
+
+ /* Look up #1B name */
+
+ if (!internal_resolve_name(mem_ctx, domain, 0x1b, &ip_list, &count))
+ return False;
+
+ /* if we get more than 1 IP back we have to assume it is a
+ multi-homed PDC and not a mess up */
+
+ if ( count > 1 ) {
+ DEBUG(6,("get_pdc_ip: PDC has %d IP addresses!\n", count));
+
+ /* look for a local net */
+ for ( i=0; i<count; i++ ) {
+ if ( is_local_net( ip_list[i] ) )
+ break;
+ }
+
+ /* if we hit then end then just grab the first
+ one from the list */
+
+ if ( i == count )
+ i = 0;
+ }
+
+ *ip = ip_list[i];
+
+ SAFE_FREE(ip_list);
+
+ return True;
+}
+
+/********************************************************
+ Get the IP address list of the domain controllers for
+ a domain.
+*********************************************************/
+
+BOOL get_dc_list(TALLOC_CTX *mem_ctx, const char *domain, struct in_addr **ip_list, int *count, int *ordered)
+{
+
+ *ordered = False;
+
+ /* If it's our domain then use the 'password server' parameter. */
+
+ if (strequal(domain, lp_workgroup())) {
+ char *p;
+ char *pserver = lp_passwordserver(); /* UNIX charset. */
+ fstring name;
+ int num_addresses = 0;
+ int local_count, i, j;
+ struct in_addr *return_iplist = NULL;
+ struct in_addr *auto_ip_list = NULL;
+ BOOL done_auto_lookup = False;
+ int auto_count = 0;
+
+
+ if (!*pserver)
+ return internal_resolve_name(mem_ctx,
+ domain, 0x1C, ip_list, count);
+
+ p = pserver;
+
+ /*
+ * if '*' appears in the "password server" list then add
+ * an auto lookup to the list of manually configured
+ * DC's. If any DC is listed by name, then the list should be
+ * considered to be ordered
+ */
+
+ while (next_token(&p,name,LIST_SEP,sizeof(name))) {
+ if (strequal(name, "*")) {
+ if ( internal_resolve_name(mem_ctx, domain, 0x1C, &auto_ip_list, &auto_count) )
+ num_addresses += auto_count;
+ done_auto_lookup = True;
+ DEBUG(8,("Adding %d DC's from auto lookup\n", auto_count));
+ }
+ else
+ num_addresses++;
+ }
+
+ /* if we have no addresses and haven't done the auto lookup, then
+ just return the list of DC's */
+
+ if ( (num_addresses == 0) && !done_auto_lookup )
+ return internal_resolve_name(mem_ctx, domain, 0x1C, ip_list, count);
+
+ return_iplist = (struct in_addr *)malloc(num_addresses * sizeof(struct in_addr));
+
+ if (return_iplist == NULL) {
+ DEBUG(3,("get_dc_list: malloc fail !\n"));
+ return False;
+ }
+
+ p = pserver;
+ local_count = 0;
+
+ /* fill in the return list now with real IP's */
+
+ while ( (local_count<num_addresses) && next_token(&p,name,LIST_SEP,sizeof(name)) ) {
+ struct in_addr name_ip;
+
+ /* copy any addersses from the auto lookup */
+
+ if ( strequal(name, "*") ) {
+ for ( j=0; j<auto_count; j++ )
+ return_iplist[local_count++] = auto_ip_list[j];
+ continue;
+ }
+
+ /* explicit lookup; resolve_name() will handle names & IP addresses */
+
+ if ( resolve_name( mem_ctx, name, &name_ip, 0x20) ) {
+ return_iplist[local_count++] = name_ip;
+ *ordered = True;
+ }
+
+ }
+
+ SAFE_FREE(auto_ip_list);
+
+ /* need to remove duplicates in the list if we have
+ any explicit password servers */
+
+ if ( *ordered ) {
+ /* one loop to remove duplicates */
+ for ( i=0; i<local_count; i++ ) {
+ if ( is_zero_ip(return_iplist[i]) )
+ continue;
+
+ for ( j=i+1; j<local_count; j++ ) {
+ if ( ip_equal( return_iplist[i], return_iplist[j]) )
+ zero_ip(&return_iplist[j]);
+ }
+ }
+
+ /* one loop to clean up any holes we left */
+ /* first ip should never be a zero_ip() */
+ for (i = 0; i<local_count; ) {
+ if ( is_zero_ip(return_iplist[i]) ) {
+ if (i != local_count-1 )
+ memmove(&return_iplist[i], &return_iplist[i+1],
+ (local_count - i - 1)*sizeof(return_iplist[i]));
+ local_count--;
+ continue;
+ }
+ i++;
+ }
+ }
+
+ *ip_list = return_iplist;
+ *count = local_count;
+
+ DEBUG(8,("get_dc_list: return %d ip addresses\n", *count));
+
+ return (*count != 0);
+ }
+
+ return internal_resolve_name(mem_ctx, domain, 0x1C, ip_list, count);
+}
diff --git a/source4/libcli/namequery_dc.c b/source4/libcli/namequery_dc.c
new file mode 100644
index 0000000000..ffc64139e9
--- /dev/null
+++ b/source4/libcli/namequery_dc.c
@@ -0,0 +1,104 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Winbind daemon connection manager
+
+ Copyright (C) Tim Potter 2001
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#include "includes.h"
+
+
+/*
+ find the DC for a domain using methods appropriate for a RPC domain
+*/
+BOOL rpc_find_dc(const char *domain, fstring srv_name, struct in_addr *ip_out)
+{
+ struct in_addr *ip_list = NULL, dc_ip, exclude_ip;
+ int count, i;
+ BOOL list_ordered;
+ BOOL use_pdc_only;
+
+ zero_ip(&exclude_ip);
+
+ use_pdc_only = must_use_pdc(domain);
+
+ /* Lookup domain controller name */
+
+ if ( use_pdc_only && get_pdc_ip(domain, &dc_ip) ) {
+ DEBUG(10,("rpc_find_dc: Atempting to lookup PDC to avoid sam sync delays\n"));
+
+ if (name_status_find(domain, 0x1c, 0x20, dc_ip, srv_name)) {
+ goto done;
+ }
+ /* Didn't get name, remember not to talk to this DC. */
+ exclude_ip = dc_ip;
+ }
+
+ /* get a list of all domain controllers */
+
+ if (!get_dc_list( domain, &ip_list, &count, &list_ordered) ) {
+ DEBUG(3, ("Could not look up dc's for domain %s\n", domain));
+ return False;
+ }
+
+ /* Remove the entry we've already failed with (should be the PDC). */
+
+ if ( use_pdc_only ) {
+ for (i = 0; i < count; i++) {
+ if (ip_equal( exclude_ip, ip_list[i]))
+ zero_ip(&ip_list[i]);
+ }
+ }
+
+ /* Pick a nice close server, but only if the list was not ordered */
+ if (!list_ordered && (count > 1) ) {
+ qsort(ip_list, count, sizeof(struct in_addr), QSORT_CAST ip_compare);
+ }
+
+ for (i = 0; i < count; i++) {
+ if (is_zero_ip(ip_list[i]))
+ continue;
+
+ if (name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) {
+ dc_ip = ip_list[i];
+ goto done;
+ }
+ }
+
+
+ SAFE_FREE(ip_list);
+
+ return False;
+done:
+ /* We have the netbios name and IP address of a domain controller.
+ Ideally we should sent a SAMLOGON request to determine whether
+ the DC is alive and kicking. If we can catch a dead DC before
+ performing a cli_connect() we can avoid a 30-second timeout. */
+
+ DEBUG(3, ("rpc_find_dc: Returning DC %s (%s) for domain %s\n", srv_name,
+ inet_ntoa(dc_ip), domain));
+
+ *ip_out = dc_ip;
+
+ SAFE_FREE(ip_list);
+
+ return True;
+}
+
diff --git a/source4/libcli/nmblib.c b/source4/libcli/nmblib.c
new file mode 100644
index 0000000000..a875f4652e
--- /dev/null
+++ b/source4/libcli/nmblib.c
@@ -0,0 +1,1287 @@
+/*
+ Unix SMB/CIFS implementation.
+ NBT netbios library routines
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+static const struct opcode_names {
+ const char *nmb_opcode_name;
+ int opcode;
+} nmb_header_opcode_names[] = {
+ {"Query", 0 },
+ {"Registration", 5 },
+ {"Release", 6 },
+ {"WACK", 7 },
+ {"Refresh", 8 },
+ {"Refresh(altcode)", 9 },
+ {"Multi-homed Registration", 15 },
+ {0, -1 }
+};
+
+/****************************************************************************
+ * Lookup a nmb opcode name.
+ ****************************************************************************/
+static const char *lookup_opcode_name( int opcode )
+{
+ const struct opcode_names *op_namep;
+ int i;
+
+ for(i = 0; nmb_header_opcode_names[i].nmb_opcode_name != 0; i++) {
+ op_namep = &nmb_header_opcode_names[i];
+ if(opcode == op_namep->opcode)
+ return op_namep->nmb_opcode_name;
+ }
+ return "<unknown opcode>";
+}
+
+/****************************************************************************
+ print out a res_rec structure
+ ****************************************************************************/
+static void debug_nmb_res_rec(struct res_rec *res, const char *hdr)
+{
+ int i, j;
+
+ DEBUGADD( 4, ( " %s: nmb_name=%s rr_type=%d rr_class=%d ttl=%d\n",
+ hdr,
+ nmb_namestr(&res->rr_name),
+ res->rr_type,
+ res->rr_class,
+ res->ttl ) );
+
+ if( res->rdlength == 0 || res->rdata == NULL )
+ return;
+
+ for (i = 0; i < res->rdlength; i+= 16)
+ {
+ DEBUGADD(4, (" %s %3x char ", hdr, i));
+
+ for (j = 0; j < 16; j++)
+ {
+ uchar x = res->rdata[i+j];
+ if (x < 32 || x > 127) x = '.';
+
+ if (i+j >= res->rdlength) break;
+ DEBUGADD(4, ("%c", x));
+ }
+
+ DEBUGADD(4, (" hex "));
+
+ for (j = 0; j < 16; j++)
+ {
+ if (i+j >= res->rdlength) break;
+ DEBUGADD(4, ("%02X", (uchar)res->rdata[i+j]));
+ }
+
+ DEBUGADD(4, ("\n"));
+ }
+}
+
+/****************************************************************************
+ process a nmb packet
+ ****************************************************************************/
+void debug_nmb_packet(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+
+ if (DEBUGLVL(4)) {
+ DEBUG(4, ("nmb packet from %s(%d) header: id=%d opcode=%s(%d) response=%s\n",
+ inet_ntoa(p->ip), p->port,
+ nmb->header.name_trn_id,
+ lookup_opcode_name(nmb->header.opcode),
+ nmb->header.opcode,
+ BOOLSTR(nmb->header.response)));
+ DEBUG(4, (" header: flags: bcast=%s rec_avail=%s rec_des=%s trunc=%s auth=%s\n",
+ BOOLSTR(nmb->header.nm_flags.bcast),
+ BOOLSTR(nmb->header.nm_flags.recursion_available),
+ BOOLSTR(nmb->header.nm_flags.recursion_desired),
+ BOOLSTR(nmb->header.nm_flags.trunc),
+ BOOLSTR(nmb->header.nm_flags.authoritative)));
+ DEBUG(4, (" header: rcode=%d qdcount=%d ancount=%d nscount=%d arcount=%d\n",
+ nmb->header.rcode,
+ nmb->header.qdcount,
+ nmb->header.ancount,
+ nmb->header.nscount,
+ nmb->header.arcount));
+ }
+
+ if (nmb->header.qdcount)
+ {
+ DEBUGADD( 4, ( " question: q_name=%s q_type=%d q_class=%d\n",
+ nmb_namestr(&nmb->question.question_name),
+ nmb->question.question_type,
+ nmb->question.question_class) );
+ }
+
+ if (nmb->answers && nmb->header.ancount)
+ {
+ debug_nmb_res_rec(nmb->answers,"answers");
+ }
+ if (nmb->nsrecs && nmb->header.nscount)
+ {
+ debug_nmb_res_rec(nmb->nsrecs,"nsrecs");
+ }
+ if (nmb->additional && nmb->header.arcount)
+ {
+ debug_nmb_res_rec(nmb->additional,"additional");
+ }
+}
+
+/*******************************************************************
+ handle "compressed" name pointers
+ ******************************************************************/
+static BOOL handle_name_ptrs(uchar *ubuf,int *offset,int length,
+ BOOL *got_pointer,int *ret)
+{
+ int loop_count=0;
+
+ while ((ubuf[*offset] & 0xC0) == 0xC0) {
+ if (!*got_pointer) (*ret) += 2;
+ (*got_pointer)=True;
+ (*offset) = ((ubuf[*offset] & ~0xC0)<<8) | ubuf[(*offset)+1];
+ if (loop_count++ == 10 || (*offset) < 0 || (*offset)>(length-2)) {
+ return(False);
+ }
+ }
+ return(True);
+}
+
+/*******************************************************************
+ parse a nmb name from "compressed" format to something readable
+ return the space taken by the name, or 0 if the name is invalid
+ ******************************************************************/
+static int parse_nmb_name(char *inbuf,int ofs,int length, struct nmb_name *name)
+{
+ int m,n=0;
+ uchar *ubuf = (uchar *)inbuf;
+ int ret = 0;
+ BOOL got_pointer=False;
+ int loop_count=0;
+ int offset = ofs;
+
+ if (length - offset < 2)
+ return(0);
+
+ /* handle initial name pointers */
+ if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret))
+ return(0);
+
+ m = ubuf[offset];
+
+ if (!m)
+ return(0);
+ if ((m & 0xC0) || offset+m+2 > length)
+ return(0);
+
+ memset((char *)name,'\0',sizeof(*name));
+
+ /* the "compressed" part */
+ if (!got_pointer)
+ ret += m + 2;
+ offset++;
+ while (m > 0) {
+ uchar c1,c2;
+ c1 = ubuf[offset++]-'A';
+ c2 = ubuf[offset++]-'A';
+ if ((c1 & 0xF0) || (c2 & 0xF0) || (n > sizeof(name->name)-1))
+ return(0);
+ name->name[n++] = (c1<<4) | c2;
+ m -= 2;
+ }
+ name->name[n] = 0;
+
+ if (n==16) {
+ /* parse out the name type,
+ its always in the 16th byte of the name */
+ name->name_type = ((uchar)name->name[15]) & 0xff;
+
+ /* remove trailing spaces */
+ name->name[15] = 0;
+ n = 14;
+ while (n && name->name[n]==' ')
+ name->name[n--] = 0;
+ }
+
+ /* now the domain parts (if any) */
+ n = 0;
+ while (ubuf[offset]) {
+ /* we can have pointers within the domain part as well */
+ if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret))
+ return(0);
+
+ m = ubuf[offset];
+ /*
+ * Don't allow null domain parts.
+ */
+ if (!m)
+ return(0);
+ if (!got_pointer)
+ ret += m+1;
+ if (n)
+ name->scope[n++] = '.';
+ if (m+2+offset>length || n+m+1>sizeof(name->scope))
+ return(0);
+ offset++;
+ while (m--)
+ name->scope[n++] = (char)ubuf[offset++];
+
+ /*
+ * Watch for malicious loops.
+ */
+ if (loop_count++ == 10)
+ return 0;
+ }
+ name->scope[n++] = 0;
+
+ return(ret);
+}
+
+
+/*******************************************************************
+ put a compressed nmb name into a buffer. return the length of the
+ compressed name
+
+ compressed names are really weird. The "compression" doubles the
+ size. The idea is that it also means that compressed names conform
+ to the doman name system. See RFC1002.
+ ******************************************************************/
+static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
+{
+ int ret,m;
+ fstring buf1;
+ char *p;
+
+ if (strcmp(name->name,"*") == 0) {
+ /* special case for wildcard name */
+ memset(buf1,'\0',20);
+ buf1[0] = '*';
+ buf1[15] = name->name_type;
+ } else {
+ slprintf(buf1, sizeof(buf1) - 1,"%-15.15s%c",name->name,name->name_type);
+ }
+
+ buf[offset] = 0x20;
+
+ ret = 34;
+
+ for (m=0;m<16;m++) {
+ buf[offset+1+2*m] = 'A' + ((buf1[m]>>4)&0xF);
+ buf[offset+2+2*m] = 'A' + (buf1[m]&0xF);
+ }
+ offset += 33;
+
+ buf[offset] = 0;
+
+ if (name->scope[0]) {
+ /* XXXX this scope handling needs testing */
+ ret += strlen(name->scope) + 1;
+ pstrcpy(&buf[offset+1],name->scope);
+
+ p = &buf[offset+1];
+ while ((p = strchr_m(p,'.'))) {
+ buf[offset] = PTR_DIFF(p,&buf[offset+1]);
+ offset += (buf[offset] + 1);
+ p = &buf[offset+1];
+ }
+ buf[offset] = strlen(&buf[offset+1]);
+ }
+
+ return(ret);
+}
+
+/*******************************************************************
+ useful for debugging messages
+ ******************************************************************/
+char *nmb_namestr(struct nmb_name *n)
+{
+ static int i=0;
+ static fstring ret[4];
+ char *p = ret[i];
+
+ if (!n->scope[0])
+ slprintf(p,sizeof(fstring)-1, "%s<%02x>",n->name,n->name_type);
+ else
+ slprintf(p,sizeof(fstring)-1, "%s<%02x>.%s",n->name,n->name_type,n->scope);
+
+ i = (i+1)%4;
+ return(p);
+}
+
+/*******************************************************************
+ allocate and parse some resource records
+ ******************************************************************/
+static BOOL parse_alloc_res_rec(char *inbuf,int *offset,int length,
+ struct res_rec **recs, int count)
+{
+ int i;
+ *recs = (struct res_rec *)malloc(sizeof(**recs)*count);
+ if (!*recs) return(False);
+
+ memset((char *)*recs,'\0',sizeof(**recs)*count);
+
+ for (i=0;i<count;i++) {
+ int l = parse_nmb_name(inbuf,*offset,length,&(*recs)[i].rr_name);
+ (*offset) += l;
+ if (!l || (*offset)+10 > length) {
+ SAFE_FREE(*recs);
+ return(False);
+ }
+ (*recs)[i].rr_type = RSVAL(inbuf,(*offset));
+ (*recs)[i].rr_class = RSVAL(inbuf,(*offset)+2);
+ (*recs)[i].ttl = RIVAL(inbuf,(*offset)+4);
+ (*recs)[i].rdlength = RSVAL(inbuf,(*offset)+8);
+ (*offset) += 10;
+ if ((*recs)[i].rdlength>sizeof((*recs)[i].rdata) ||
+ (*offset)+(*recs)[i].rdlength > length) {
+ SAFE_FREE(*recs);
+ return(False);
+ }
+ memcpy((*recs)[i].rdata,inbuf+(*offset),(*recs)[i].rdlength);
+ (*offset) += (*recs)[i].rdlength;
+ }
+ return(True);
+}
+
+/*******************************************************************
+ put a resource record into a packet
+ ******************************************************************/
+static int put_res_rec(char *buf,int offset,struct res_rec *recs,int count)
+{
+ int ret=0;
+ int i;
+
+ for (i=0;i<count;i++) {
+ int l = put_nmb_name(buf,offset,&recs[i].rr_name);
+ offset += l;
+ ret += l;
+ RSSVAL(buf,offset,recs[i].rr_type);
+ RSSVAL(buf,offset+2,recs[i].rr_class);
+ RSIVAL(buf,offset+4,recs[i].ttl);
+ RSSVAL(buf,offset+8,recs[i].rdlength);
+ memcpy(buf+offset+10,recs[i].rdata,recs[i].rdlength);
+ offset += 10+recs[i].rdlength;
+ ret += 10+recs[i].rdlength;
+ }
+
+ return(ret);
+}
+
+/*******************************************************************
+ put a compressed name pointer record into a packet
+ ******************************************************************/
+static int put_compressed_name_ptr(uchar *buf,int offset,struct res_rec *rec,int ptr_offset)
+{
+ int ret=0;
+ buf[offset] = (0xC0 | ((ptr_offset >> 8) & 0xFF));
+ buf[offset+1] = (ptr_offset & 0xFF);
+ offset += 2;
+ ret += 2;
+ RSSVAL(buf,offset,rec->rr_type);
+ RSSVAL(buf,offset+2,rec->rr_class);
+ RSIVAL(buf,offset+4,rec->ttl);
+ RSSVAL(buf,offset+8,rec->rdlength);
+ memcpy(buf+offset+10,rec->rdata,rec->rdlength);
+ offset += 10+rec->rdlength;
+ ret += 10+rec->rdlength;
+
+ return(ret);
+}
+
+/*******************************************************************
+ parse a dgram packet. Return False if the packet can't be parsed
+ or is invalid for some reason, True otherwise
+
+ this is documented in section 4.4.1 of RFC1002
+ ******************************************************************/
+static BOOL parse_dgram(char *inbuf,int length,struct dgram_packet *dgram)
+{
+ int offset;
+ int flags;
+
+ memset((char *)dgram,'\0',sizeof(*dgram));
+
+ if (length < 14) return(False);
+
+ dgram->header.msg_type = CVAL(inbuf,0);
+ flags = CVAL(inbuf,1);
+ dgram->header.flags.node_type = (enum node_type)((flags>>2)&3);
+ if (flags & 1) dgram->header.flags.more = True;
+ if (flags & 2) dgram->header.flags.first = True;
+ dgram->header.dgm_id = RSVAL(inbuf,2);
+ putip((char *)&dgram->header.source_ip,inbuf+4);
+ dgram->header.source_port = RSVAL(inbuf,8);
+ dgram->header.dgm_length = RSVAL(inbuf,10);
+ dgram->header.packet_offset = RSVAL(inbuf,12);
+
+ offset = 14;
+
+ if (dgram->header.msg_type == 0x10 ||
+ dgram->header.msg_type == 0x11 ||
+ dgram->header.msg_type == 0x12) {
+ offset += parse_nmb_name(inbuf,offset,length,&dgram->source_name);
+ offset += parse_nmb_name(inbuf,offset,length,&dgram->dest_name);
+ }
+
+ if (offset >= length || (length-offset > sizeof(dgram->data)))
+ return(False);
+
+ dgram->datasize = length-offset;
+ memcpy(dgram->data,inbuf+offset,dgram->datasize);
+
+ return(True);
+}
+
+
+/*******************************************************************
+ parse a nmb packet. Return False if the packet can't be parsed
+ or is invalid for some reason, True otherwise
+ ******************************************************************/
+static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
+{
+ int nm_flags,offset;
+
+ memset((char *)nmb,'\0',sizeof(*nmb));
+
+ if (length < 12) return(False);
+
+ /* parse the header */
+ nmb->header.name_trn_id = RSVAL(inbuf,0);
+
+ DEBUG(10,("parse_nmb: packet id = %d\n", nmb->header.name_trn_id));
+
+ nmb->header.opcode = (CVAL(inbuf,2) >> 3) & 0xF;
+ nmb->header.response = ((CVAL(inbuf,2)>>7)&1)?True:False;
+ nm_flags = ((CVAL(inbuf,2) & 0x7) << 4) + (CVAL(inbuf,3)>>4);
+ nmb->header.nm_flags.bcast = (nm_flags&1)?True:False;
+ nmb->header.nm_flags.recursion_available = (nm_flags&8)?True:False;
+ nmb->header.nm_flags.recursion_desired = (nm_flags&0x10)?True:False;
+ nmb->header.nm_flags.trunc = (nm_flags&0x20)?True:False;
+ nmb->header.nm_flags.authoritative = (nm_flags&0x40)?True:False;
+ nmb->header.rcode = CVAL(inbuf,3) & 0xF;
+ nmb->header.qdcount = RSVAL(inbuf,4);
+ nmb->header.ancount = RSVAL(inbuf,6);
+ nmb->header.nscount = RSVAL(inbuf,8);
+ nmb->header.arcount = RSVAL(inbuf,10);
+
+ if (nmb->header.qdcount) {
+ offset = parse_nmb_name(inbuf,12,length,&nmb->question.question_name);
+ if (!offset) return(False);
+
+ if (length - (12+offset) < 4) return(False);
+ nmb->question.question_type = RSVAL(inbuf,12+offset);
+ nmb->question.question_class = RSVAL(inbuf,12+offset+2);
+
+ offset += 12+4;
+ } else {
+ offset = 12;
+ }
+
+ /* and any resource records */
+ if (nmb->header.ancount &&
+ !parse_alloc_res_rec(inbuf,&offset,length,&nmb->answers,
+ nmb->header.ancount))
+ return(False);
+
+ if (nmb->header.nscount &&
+ !parse_alloc_res_rec(inbuf,&offset,length,&nmb->nsrecs,
+ nmb->header.nscount))
+ return(False);
+
+ if (nmb->header.arcount &&
+ !parse_alloc_res_rec(inbuf,&offset,length,&nmb->additional,
+ nmb->header.arcount))
+ return(False);
+
+ return(True);
+}
+
+/*******************************************************************
+ 'Copy constructor' for an nmb packet
+ ******************************************************************/
+static struct packet_struct *copy_nmb_packet(struct packet_struct *packet)
+{
+ struct nmb_packet *nmb;
+ struct nmb_packet *copy_nmb;
+ struct packet_struct *pkt_copy;
+
+ if(( pkt_copy = (struct packet_struct *)malloc(sizeof(*packet))) == NULL)
+ {
+ DEBUG(0,("copy_nmb_packet: malloc fail.\n"));
+ return NULL;
+ }
+
+ /* Structure copy of entire thing. */
+
+ *pkt_copy = *packet;
+
+ /* Ensure this copy is not locked. */
+ pkt_copy->locked = False;
+
+ /* Ensure this copy has no resource records. */
+ nmb = &packet->packet.nmb;
+ copy_nmb = &pkt_copy->packet.nmb;
+
+ copy_nmb->answers = NULL;
+ copy_nmb->nsrecs = NULL;
+ copy_nmb->additional = NULL;
+
+ /* Now copy any resource records. */
+
+ if (nmb->answers)
+ {
+ if((copy_nmb->answers = (struct res_rec *)
+ malloc(nmb->header.ancount * sizeof(struct res_rec))) == NULL)
+ goto free_and_exit;
+ memcpy((char *)copy_nmb->answers, (char *)nmb->answers,
+ nmb->header.ancount * sizeof(struct res_rec));
+ }
+ if (nmb->nsrecs)
+ {
+ if((copy_nmb->nsrecs = (struct res_rec *)
+ malloc(nmb->header.nscount * sizeof(struct res_rec))) == NULL)
+ goto free_and_exit;
+ memcpy((char *)copy_nmb->nsrecs, (char *)nmb->nsrecs,
+ nmb->header.nscount * sizeof(struct res_rec));
+ }
+ if (nmb->additional)
+ {
+ if((copy_nmb->additional = (struct res_rec *)
+ malloc(nmb->header.arcount * sizeof(struct res_rec))) == NULL)
+ goto free_and_exit;
+ memcpy((char *)copy_nmb->additional, (char *)nmb->additional,
+ nmb->header.arcount * sizeof(struct res_rec));
+ }
+
+ return pkt_copy;
+
+free_and_exit:
+
+ SAFE_FREE(copy_nmb->answers);
+ SAFE_FREE(copy_nmb->nsrecs);
+ SAFE_FREE(copy_nmb->additional);
+ SAFE_FREE(pkt_copy);
+
+ DEBUG(0,("copy_nmb_packet: malloc fail in resource records.\n"));
+ return NULL;
+}
+
+/*******************************************************************
+ 'Copy constructor' for a dgram packet
+ ******************************************************************/
+static struct packet_struct *copy_dgram_packet(struct packet_struct *packet)
+{
+ struct packet_struct *pkt_copy;
+
+ if(( pkt_copy = (struct packet_struct *)malloc(sizeof(*packet))) == NULL)
+ {
+ DEBUG(0,("copy_dgram_packet: malloc fail.\n"));
+ return NULL;
+ }
+
+ /* Structure copy of entire thing. */
+
+ *pkt_copy = *packet;
+
+ /* Ensure this copy is not locked. */
+ pkt_copy->locked = False;
+
+ /* There are no additional pointers in a dgram packet,
+ we are finished. */
+ return pkt_copy;
+}
+
+/*******************************************************************
+ 'Copy constructor' for a generic packet
+ ******************************************************************/
+struct packet_struct *copy_packet(struct packet_struct *packet)
+{
+ if(packet->packet_type == NMB_PACKET)
+ return copy_nmb_packet(packet);
+ else if (packet->packet_type == DGRAM_PACKET)
+ return copy_dgram_packet(packet);
+ return NULL;
+}
+
+/*******************************************************************
+ free up any resources associated with an nmb packet
+ ******************************************************************/
+static void free_nmb_packet(struct nmb_packet *nmb)
+{
+ SAFE_FREE(nmb->answers);
+ SAFE_FREE(nmb->nsrecs);
+ SAFE_FREE(nmb->additional);
+}
+
+/*******************************************************************
+ free up any resources associated with a dgram packet
+ ******************************************************************/
+static void free_dgram_packet(struct dgram_packet *nmb)
+{
+ /* We have nothing to do for a dgram packet. */
+}
+
+/*******************************************************************
+ free up any resources associated with a packet
+ ******************************************************************/
+void free_packet(struct packet_struct *packet)
+{
+ if (packet->locked)
+ return;
+ if (packet->packet_type == NMB_PACKET)
+ free_nmb_packet(&packet->packet.nmb);
+ else if (packet->packet_type == DGRAM_PACKET)
+ free_dgram_packet(&packet->packet.dgram);
+ ZERO_STRUCTPN(packet);
+ SAFE_FREE(packet);
+}
+
+/*******************************************************************
+parse a packet buffer into a packet structure
+ ******************************************************************/
+struct packet_struct *parse_packet(char *buf,int length,
+ enum packet_type packet_type)
+{
+ struct packet_struct *p;
+ BOOL ok=False;
+
+ p = (struct packet_struct *)malloc(sizeof(*p));
+ if (!p) return(NULL);
+
+ p->next = NULL;
+ p->prev = NULL;
+ p->locked = False;
+ p->timestamp = time(NULL);
+ p->packet_type = packet_type;
+
+ switch (packet_type) {
+ case NMB_PACKET:
+ ok = parse_nmb(buf,length,&p->packet.nmb);
+ break;
+
+ case DGRAM_PACKET:
+ ok = parse_dgram(buf,length,&p->packet.dgram);
+ break;
+ }
+
+ if (!ok) {
+ free_packet(p);
+ return NULL;
+ }
+
+ return p;
+}
+
+/*******************************************************************
+ read a packet from a socket and parse it, returning a packet ready
+ to be used or put on the queue. This assumes a UDP socket
+ ******************************************************************/
+struct packet_struct *read_packet(int fd,enum packet_type packet_type)
+{
+ struct packet_struct *packet;
+ char buf[MAX_DGRAM_SIZE];
+ int length;
+ struct in_addr addr;
+ int port;
+
+ length = read_udp_socket(fd, buf, sizeof(buf), &addr, &port);
+ if (length < MIN_DGRAM_SIZE) return(NULL);
+
+ packet = parse_packet(buf, length, packet_type);
+ if (!packet) return NULL;
+
+ packet->fd = fd;
+ packet->ip = addr;
+ packet->port = port;
+
+ DEBUG(5,("Received a packet of len %d from (%s) port %d\n",
+ length, inet_ntoa(packet->ip), packet->port));
+
+ return packet;
+}
+
+
+/*******************************************************************
+ send a udp packet on a already open socket
+ ******************************************************************/
+static BOOL send_udp(int fd,char *buf,int len,struct in_addr ip,int port)
+{
+ BOOL ret = False;
+ int i;
+ struct sockaddr_in sock_out;
+
+ /* set the address and port */
+ memset((char *)&sock_out,'\0',sizeof(sock_out));
+ putip((char *)&sock_out.sin_addr,(char *)&ip);
+ sock_out.sin_port = htons( port );
+ sock_out.sin_family = AF_INET;
+
+ DEBUG( 5, ( "Sending a packet of len %d to (%s) on port %d\n",
+ len, inet_ntoa(ip), port ) );
+
+ /*
+ * Patch to fix asynch error notifications from Linux kernel.
+ */
+
+ for (i = 0; i < 5; i++) {
+ ret = (sendto(fd,buf,len,0,(struct sockaddr *)&sock_out, sizeof(sock_out)) >= 0);
+ if (ret || errno != ECONNREFUSED)
+ break;
+ }
+
+ if (!ret)
+ DEBUG(0,("Packet send failed to %s(%d) ERRNO=%s\n",
+ inet_ntoa(ip),port,strerror(errno)));
+
+ return(ret);
+}
+
+/*******************************************************************
+ build a dgram packet ready for sending
+
+ XXXX This currently doesn't handle packets too big for one
+ datagram. It should split them and use the packet_offset, more and
+ first flags to handle the fragmentation. Yuck.
+
+ [...but it isn't clear that we would ever need to send a
+ a fragmented NBT Datagram. The IP layer does its own
+ fragmentation to ensure that messages can fit into the path
+ MTU. It *is* important to be able to receive and rebuild
+ fragmented NBT datagrams, just in case someone out there
+ really has implemented this 'feature'. crh -)------ ]
+
+ ******************************************************************/
+static int build_dgram(char *buf,struct packet_struct *p)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ uchar *ubuf = (uchar *)buf;
+ int offset=0;
+
+ /* put in the header */
+ ubuf[0] = dgram->header.msg_type;
+ ubuf[1] = (((int)dgram->header.flags.node_type)<<2);
+ if (dgram->header.flags.more) ubuf[1] |= 1;
+ if (dgram->header.flags.first) ubuf[1] |= 2;
+ RSSVAL(ubuf,2,dgram->header.dgm_id);
+ putip(ubuf+4,(char *)&dgram->header.source_ip);
+ RSSVAL(ubuf,8,dgram->header.source_port);
+ RSSVAL(ubuf,12,dgram->header.packet_offset);
+
+ offset = 14;
+
+ if (dgram->header.msg_type == 0x10 ||
+ dgram->header.msg_type == 0x11 ||
+ dgram->header.msg_type == 0x12) {
+ offset += put_nmb_name((char *)ubuf,offset,&dgram->source_name);
+ offset += put_nmb_name((char *)ubuf,offset,&dgram->dest_name);
+ }
+
+ memcpy(ubuf+offset,dgram->data,dgram->datasize);
+ offset += dgram->datasize;
+
+ /* automatically set the dgm_length
+ * NOTE: RFC1002 says the dgm_length does *not*
+ * include the fourteen-byte header. crh
+ */
+ dgram->header.dgm_length = (offset - 14);
+ RSSVAL(ubuf,10,dgram->header.dgm_length);
+
+ return(offset);
+}
+
+/*******************************************************************
+ Build a nmb name
+*******************************************************************/
+
+void make_nmb_name( struct nmb_name *n, const char *name, int type)
+{
+ memset( (char *)n, '\0', sizeof(struct nmb_name) );
+ push_ascii(n->name, name, 16, STR_TERMINATE|STR_UPPER);
+ n->name_type = (unsigned int)type & 0xFF;
+ StrnCpy( n->scope, lp_netbios_scope(), 63 );
+ strupper( n->scope );
+}
+
+/*******************************************************************
+ Compare two nmb names
+ ******************************************************************/
+
+BOOL nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2)
+{
+ return ((n1->name_type == n2->name_type) &&
+ strequal(n1->name ,n2->name ) &&
+ strequal(n1->scope,n2->scope));
+}
+
+/*******************************************************************
+ build a nmb packet ready for sending
+
+ XXXX this currently relies on not being passed something that expands
+ to a packet too big for the buffer. Eventually this should be
+ changed to set the trunc bit so the receiver can request the rest
+ via tcp (when that becomes supported)
+ ******************************************************************/
+static int build_nmb(char *buf,struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ uchar *ubuf = (uchar *)buf;
+ int offset=0;
+
+ /* put in the header */
+ RSSVAL(ubuf,offset,nmb->header.name_trn_id);
+ ubuf[offset+2] = (nmb->header.opcode & 0xF) << 3;
+ if (nmb->header.response) ubuf[offset+2] |= (1<<7);
+ if (nmb->header.nm_flags.authoritative &&
+ nmb->header.response) ubuf[offset+2] |= 0x4;
+ if (nmb->header.nm_flags.trunc) ubuf[offset+2] |= 0x2;
+ if (nmb->header.nm_flags.recursion_desired) ubuf[offset+2] |= 0x1;
+ if (nmb->header.nm_flags.recursion_available &&
+ nmb->header.response) ubuf[offset+3] |= 0x80;
+ if (nmb->header.nm_flags.bcast) ubuf[offset+3] |= 0x10;
+ ubuf[offset+3] |= (nmb->header.rcode & 0xF);
+
+ RSSVAL(ubuf,offset+4,nmb->header.qdcount);
+ RSSVAL(ubuf,offset+6,nmb->header.ancount);
+ RSSVAL(ubuf,offset+8,nmb->header.nscount);
+ RSSVAL(ubuf,offset+10,nmb->header.arcount);
+
+ offset += 12;
+ if (nmb->header.qdcount) {
+ /* XXXX this doesn't handle a qdcount of > 1 */
+ offset += put_nmb_name((char *)ubuf,offset,&nmb->question.question_name);
+ RSSVAL(ubuf,offset,nmb->question.question_type);
+ RSSVAL(ubuf,offset+2,nmb->question.question_class);
+ offset += 4;
+ }
+
+ if (nmb->header.ancount)
+ offset += put_res_rec((char *)ubuf,offset,nmb->answers,
+ nmb->header.ancount);
+
+ if (nmb->header.nscount)
+ offset += put_res_rec((char *)ubuf,offset,nmb->nsrecs,
+ nmb->header.nscount);
+
+ /*
+ * The spec says we must put compressed name pointers
+ * in the following outgoing packets :
+ * NAME_REGISTRATION_REQUEST, NAME_REFRESH_REQUEST,
+ * NAME_RELEASE_REQUEST.
+ */
+
+ if((nmb->header.response == False) &&
+ ((nmb->header.opcode == NMB_NAME_REG_OPCODE) ||
+ (nmb->header.opcode == NMB_NAME_RELEASE_OPCODE) ||
+ (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_8) ||
+ (nmb->header.opcode == NMB_NAME_REFRESH_OPCODE_9) ||
+ (nmb->header.opcode == NMB_NAME_MULTIHOMED_REG_OPCODE)) &&
+ (nmb->header.arcount == 1)) {
+
+ offset += put_compressed_name_ptr(ubuf,offset,nmb->additional,12);
+
+ } else if (nmb->header.arcount) {
+ offset += put_res_rec((char *)ubuf,offset,nmb->additional,
+ nmb->header.arcount);
+ }
+ return(offset);
+}
+
+
+/*******************************************************************
+linearise a packet
+ ******************************************************************/
+int build_packet(char *buf, struct packet_struct *p)
+{
+ int len = 0;
+
+ switch (p->packet_type) {
+ case NMB_PACKET:
+ len = build_nmb(buf,p);
+ break;
+
+ case DGRAM_PACKET:
+ len = build_dgram(buf,p);
+ break;
+ }
+
+ return len;
+}
+
+/*******************************************************************
+ send a packet_struct
+ ******************************************************************/
+BOOL send_packet(struct packet_struct *p)
+{
+ char buf[1024];
+ int len=0;
+
+ memset(buf,'\0',sizeof(buf));
+
+ len = build_packet(buf, p);
+
+ if (!len) return(False);
+
+ return(send_udp(p->fd,buf,len,p->ip,p->port));
+}
+
+/****************************************************************************
+ receive a packet with timeout on a open UDP filedescriptor
+ The timeout is in milliseconds
+ ***************************************************************************/
+struct packet_struct *receive_packet(int fd,enum packet_type type,int t)
+{
+ fd_set fds;
+ struct timeval timeout;
+ int ret;
+
+ FD_ZERO(&fds);
+ FD_SET(fd,&fds);
+ timeout.tv_sec = t/1000;
+ timeout.tv_usec = 1000*(t%1000);
+
+ if ((ret = sys_select_intr(fd+1,&fds,NULL,NULL,&timeout)) == -1) {
+ /* errno should be EBADF or EINVAL. */
+ DEBUG(0,("select returned -1, errno = %s (%d)\n", strerror(errno), errno));
+ return NULL;
+ }
+
+ if (ret == 0) /* timeout */
+ return NULL;
+
+ if (FD_ISSET(fd,&fds))
+ return(read_packet(fd,type));
+
+ return(NULL);
+}
+
+
+/****************************************************************************
+ receive a UDP/137 packet either via UDP or from the unexpected packet
+ queue. The packet must be a reply packet and have the specified trn_id
+ The timeout is in milliseconds
+ ***************************************************************************/
+struct packet_struct *receive_nmb_packet(int fd, int t, int trn_id)
+{
+ struct packet_struct *p;
+
+ p = receive_packet(fd, NMB_PACKET, t);
+
+ if (p && p->packet.nmb.header.response &&
+ p->packet.nmb.header.name_trn_id == trn_id) {
+ return p;
+ }
+ if (p) free_packet(p);
+
+ /* try the unexpected packet queue */
+ return receive_unexpected(NMB_PACKET, trn_id, NULL);
+}
+
+/****************************************************************************
+ receive a UDP/138 packet either via UDP or from the unexpected packet
+ queue. The packet must be a reply packet and have the specified mailslot name
+ The timeout is in milliseconds
+ ***************************************************************************/
+struct packet_struct *receive_dgram_packet(int fd, int t, const char *mailslot_name)
+{
+ struct packet_struct *p;
+
+ p = receive_packet(fd, DGRAM_PACKET, t);
+
+ if (p && match_mailslot_name(p, mailslot_name)) {
+ return p;
+ }
+ if (p) free_packet(p);
+
+ /* try the unexpected packet queue */
+ return receive_unexpected(DGRAM_PACKET, 0, mailslot_name);
+}
+
+
+/****************************************************************************
+ see if a datagram has the right mailslot name
+***************************************************************************/
+BOOL match_mailslot_name(struct packet_struct *p, const char *mailslot_name)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ char *buf;
+
+ buf = &dgram->data[0];
+ buf -= 4;
+
+ buf = smb_buf(buf);
+
+ if (memcmp(buf, mailslot_name, strlen(mailslot_name)+1) == 0) {
+ return True;
+ }
+
+ return False;
+}
+
+
+/****************************************************************************
+return the number of bits that match between two 4 character buffers
+ ***************************************************************************/
+int matching_quad_bits(uchar *p1, uchar *p2)
+{
+ int i, j, ret = 0;
+ for (i=0; i<4; i++) {
+ if (p1[i] != p2[i]) break;
+ ret += 8;
+ }
+
+ if (i==4) return ret;
+
+ for (j=0; j<8; j++) {
+ if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j)))) break;
+ ret++;
+ }
+
+ return ret;
+}
+
+
+static uchar sort_ip[4];
+
+/****************************************************************************
+compare two query reply records
+ ***************************************************************************/
+static int name_query_comp(uchar *p1, uchar *p2)
+{
+ return matching_quad_bits(p2+2, sort_ip) - matching_quad_bits(p1+2, sort_ip);
+}
+
+/****************************************************************************
+sort a set of 6 byte name query response records so that the IPs that
+have the most leading bits in common with the specified address come first
+ ***************************************************************************/
+void sort_query_replies(char *data, int n, struct in_addr ip)
+{
+ if (n <= 1) return;
+
+ putip(sort_ip, (char *)&ip);
+
+ qsort(data, n, 6, QSORT_CAST name_query_comp);
+}
+
+
+#define TRUNCATE_NETBIOS_NAME 1
+
+/*******************************************************************
+ convert, possibly using a stupid microsoft-ism which has destroyed
+ the transport independence of netbios (for CIFS vendors that usually
+ use the Win95-type methods, not for NT to NT communication, which uses
+ DCE/RPC and therefore full-length unicode strings...) a dns name into
+ a netbios name.
+
+ the netbios name (NOT necessarily null-terminated) is truncated to 15
+ characters.
+
+ ******************************************************************/
+char *dns_to_netbios_name(char *dns_name)
+{
+ static char netbios_name[16];
+ int i;
+ StrnCpy(netbios_name, dns_name, 15);
+ netbios_name[15] = 0;
+
+#ifdef TRUNCATE_NETBIOS_NAME
+ /* ok. this is because of a stupid microsoft-ism. if the called host
+ name contains a '.', microsoft clients expect you to truncate the
+ netbios name up to and including the '.' this even applies, by
+ mistake, to workgroup (domain) names, which is _really_ daft.
+ */
+ for (i = 15; i >= 0; i--)
+ {
+ if (netbios_name[i] == '.')
+ {
+ netbios_name[i] = 0;
+ break;
+ }
+ }
+#endif /* TRUNCATE_NETBIOS_NAME */
+
+ return netbios_name;
+}
+
+
+/****************************************************************************
+interpret the weird netbios "name". Return the name type
+****************************************************************************/
+static int name_interpret(char *in,char *out)
+{
+ int ret;
+ int len = (*in++) / 2;
+
+ *out=0;
+
+ if (len > 30 || len<1) return(0);
+
+ while (len--)
+ {
+ if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') {
+ *out = 0;
+ return(0);
+ }
+ *out = ((in[0]-'A')<<4) + (in[1]-'A');
+ in += 2;
+ out++;
+ }
+ *out = 0;
+ ret = out[-1];
+
+#ifdef NETBIOS_SCOPE
+ /* Handle any scope names */
+ while(*in)
+ {
+ *out++ = '.'; /* Scope names are separated by periods */
+ len = *(uchar *)in++;
+ StrnCpy(out, in, len);
+ out += len;
+ *out=0;
+ in += len;
+ }
+#endif
+ return(ret);
+}
+
+
+/****************************************************************************
+return the number of bytes that would be occupied by the result of
+name_mangle()
+****************************************************************************/
+uint_t nbt_mangled_name_len(void)
+{
+ const char *scope = lp_netbios_scope();
+ uint_t ret = 34;
+ if (scope && *scope) {
+ ret += strlen(scope) + 1;
+ }
+ return ret;
+}
+
+/****************************************************************************
+mangle a name into netbios format
+
+ Note: <Out> must be nbt_mangled_name_len() in length
+****************************************************************************/
+int name_mangle(char *In, char *Out, char name_type)
+{
+ int i;
+ int c;
+ int len;
+ char buf[20];
+ char *p = Out;
+ const char *scope = lp_netbios_scope();
+
+ /* Safely copy the input string, In, into buf[]. */
+ memset( buf, 0, 20 );
+ if (strcmp(In,"*") == 0) {
+ buf[0] = '*';
+ } else {
+ slprintf( buf, sizeof(buf) - 1, "%-15.15s%c", In, name_type);
+ }
+
+ /* Place the length of the first field into the output buffer. */
+ p[0] = 32;
+ p++;
+
+ /* Now convert the name to the rfc1001/1002 format. */
+ for ( i = 0; i < 16; i++ ) {
+ c = toupper( buf[i] );
+ p[i*2] = ( (c >> 4) & 0xF ) + 'A';
+ p[(i*2)+1] = (c & 0xF) + 'A';
+ }
+ p += 32;
+ p[0] = '\0';
+
+ if (!scope || !*scope) {
+ return name_len(Out);
+ }
+
+ /* Add the scope string. */
+ for (i = 0, len = 0; scope[i]; i++, len++) {
+ switch(scope[i]) {
+ case '.':
+ p[0] = len;
+ p += (len + 1);
+ len = -1;
+ break;
+ default:
+ p[len+1] = scope[i];
+ break;
+ }
+ }
+
+ p[0] = len;
+ if (len > 0) {
+ p[len+1] = 0;
+ }
+
+ return name_len(Out);
+}
+
+/****************************************************************************
+find a pointer to a netbios name
+****************************************************************************/
+static char *name_ptr(char *buf,int ofs)
+{
+ uchar c = *(uchar *)(buf+ofs);
+
+ if ((c & 0xC0) == 0xC0)
+ {
+ uint16 l = RSVAL(buf, ofs) & 0x3FFF;
+ DEBUG(5,("name ptr to pos %d from %d is %s\n",l,ofs,buf+l));
+ return(buf + l);
+ }
+ else
+ return(buf+ofs);
+}
+
+/****************************************************************************
+extract a netbios name from a buf
+****************************************************************************/
+int name_extract(char *buf,int ofs,char *name)
+{
+ char *p = name_ptr(buf,ofs);
+ int d = PTR_DIFF(p,buf+ofs);
+ pstrcpy(name,"");
+ if (d < -50 || d > 50) return(0);
+ return(name_interpret(p,name));
+}
+
+/****************************************************************************
+return the total storage length of a mangled name
+****************************************************************************/
+int name_len(char *s1)
+{
+ /* NOTE: this argument _must_ be unsigned */
+ uchar *s = (uchar *)s1;
+ int len;
+
+ /* If the two high bits of the byte are set, return 2. */
+ if (0xC0 == (*s & 0xC0))
+ return(2);
+
+ /* Add up the length bytes. */
+ for (len = 1; (*s); s += (*s) + 1) {
+ len += *s + 1;
+ SMB_ASSERT(len < 80);
+ }
+
+ return(len);
+} /* name_len */
diff --git a/source4/libcli/ntlmssp.c b/source4/libcli/ntlmssp.c
new file mode 100644
index 0000000000..c4ad260a1a
--- /dev/null
+++ b/source4/libcli/ntlmssp.c
@@ -0,0 +1,625 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ handle NLTMSSP, server side
+
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Andrew Bartlett 2001-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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/**
+ * Print out the NTLMSSP flags for debugging
+ * @param neg_flags The flags from the packet
+ */
+
+void debug_ntlmssp_flags(uint32 neg_flags)
+{
+ DEBUG(3,("Got NTLMSSP neg_flags=0x%08x\n", neg_flags));
+
+ if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_UNICODE\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_OEM)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_OEM\n"));
+ if (neg_flags & NTLMSSP_REQUEST_TARGET)
+ DEBUGADD(4, (" NTLMSSP_REQUEST_TARGET\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_SIGN)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SIGN\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_SEAL)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SEAL\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_LM_KEY)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_LM_KEY\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_NETWARE)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NETWARE\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_NTLM)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_ALWAYS_SIGN\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_NTLM2)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM2\n"));
+ if (neg_flags & NTLMSSP_CHAL_TARGET_INFO)
+ DEBUGADD(4, (" NTLMSSP_CHAL_TARGET_INFO\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_128)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_128\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_KEY_EXCH\n"));
+}
+
+/**
+ * Default challenge generation code.
+ *
+ */
+
+static const uint8 *get_challenge(struct ntlmssp_state *ntlmssp_state)
+{
+ static uchar chal[8];
+ generate_random_buffer(chal, sizeof(chal), False);
+
+ return chal;
+}
+
+/**
+ * Determine correct target name flags for reply, given server role
+ * and negoitated falgs
+ *
+ * @param ntlmssp_state NTLMSSP State
+ * @param neg_flags The flags from the packet
+ * @param chal_flags The flags to be set in the reply packet
+ * @return The 'target name' string.
+ */
+
+static const char *ntlmssp_target_name(struct ntlmssp_state *ntlmssp_state,
+ uint32 neg_flags, uint32 *chal_flags)
+{
+ if (neg_flags & NTLMSSP_REQUEST_TARGET) {
+ *chal_flags |= NTLMSSP_CHAL_TARGET_INFO;
+ *chal_flags |= NTLMSSP_REQUEST_TARGET;
+ if (ntlmssp_state->server_role == ROLE_STANDALONE) {
+ *chal_flags |= NTLMSSP_TARGET_TYPE_SERVER;
+ return ntlmssp_state->get_global_myname();
+ } else {
+ *chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN;
+ return ntlmssp_state->get_domain();
+ };
+ } else {
+ return "";
+ }
+}
+
+/**
+ * Next state function for the Negotiate packet
+ *
+ * @param ntlmssp_state NTLMSSP State
+ * @param request The request, as a DATA_BLOB
+ * @param request The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors or MORE_PROCESSING_REQUIRED if a reply is sent.
+ */
+
+static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
+ const DATA_BLOB request, DATA_BLOB *reply)
+{
+ DATA_BLOB struct_blob;
+ fstring dnsname, dnsdomname;
+ uint32 ntlmssp_command, neg_flags, chal_flags;
+ char *cliname=NULL, *domname=NULL;
+ const uint8 *cryptkey;
+ const char *target_name;
+
+ /* parse the NTLMSSP packet */
+#if 0
+ file_save("ntlmssp_negotiate.dat", request.data, request.length);
+#endif
+
+ if (!msrpc_parse(&request, "CddAA",
+ "NTLMSSP",
+ &ntlmssp_command,
+ &neg_flags,
+ &cliname,
+ &domname)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ SAFE_FREE(cliname);
+ SAFE_FREE(domname);
+
+ debug_ntlmssp_flags(neg_flags);
+
+ cryptkey = ntlmssp_state->get_challenge(ntlmssp_state);
+
+ data_blob_free(&ntlmssp_state->chal);
+ ntlmssp_state->chal = data_blob(cryptkey, 8);
+
+ /* Give them the challenge. For now, ignore neg_flags and just
+ return the flags we want. Obviously this is not correct */
+
+ chal_flags =
+ NTLMSSP_NEGOTIATE_128 |
+ NTLMSSP_NEGOTIATE_NTLM;
+
+ if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) {
+ chal_flags |= NTLMSSP_NEGOTIATE_UNICODE;
+ ntlmssp_state->unicode = True;
+ } else {
+ chal_flags |= NTLMSSP_NEGOTIATE_OEM;
+ }
+
+ target_name = ntlmssp_target_name(ntlmssp_state,
+ neg_flags, &chal_flags);
+
+ /* This should be a 'netbios domain -> DNS domain' mapping */
+ dnsdomname[0] = '\0';
+ get_mydomname(dnsdomname);
+ strlower(dnsdomname);
+
+ dnsname[0] = '\0';
+ get_myfullname(dnsname);
+ strlower(dnsname);
+
+ if (chal_flags & NTLMSSP_CHAL_TARGET_INFO)
+ {
+ const char *target_name_dns = "";
+ if (chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN) {
+ target_name_dns = dnsdomname;
+ } else if (chal_flags |= NTLMSSP_TARGET_TYPE_SERVER) {
+ target_name_dns = dnsname;
+ }
+
+ /* the numbers here are the string type flags */
+ msrpc_gen(&struct_blob, "aaaaa",
+ ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN, target_name,
+ ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER, ntlmssp_state->get_global_myname(),
+ ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN_DNS, target_name_dns,
+ ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER_DNS, dnsdomname,
+ ntlmssp_state->unicode, 0, "");
+ } else {
+ struct_blob = data_blob(NULL, 0);
+ }
+
+ {
+ const char *gen_string;
+ if (ntlmssp_state->unicode) {
+ gen_string = "CdUdbddB";
+ } else {
+ gen_string = "CdAdbddB";
+ }
+
+ msrpc_gen(reply, gen_string,
+ "NTLMSSP",
+ NTLMSSP_CHALLENGE,
+ target_name,
+ chal_flags,
+ cryptkey, 8,
+ 0, 0,
+ struct_blob.data, struct_blob.length);
+ }
+
+ data_blob_free(&struct_blob);
+
+ ntlmssp_state->expected_state = NTLMSSP_AUTH;
+
+ return NT_STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+/**
+ * Next state function for the Authenticate packet
+ *
+ * @param ntlmssp_state NTLMSSP State
+ * @param request The request, as a DATA_BLOB
+ * @param request The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors or NT_STATUS_OK.
+ */
+
+static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
+ const DATA_BLOB request, DATA_BLOB *reply)
+{
+ DATA_BLOB sess_key;
+ uint32 ntlmssp_command, neg_flags;
+ NTSTATUS nt_status;
+
+ const char *parse_string;
+
+ /* parse the NTLMSSP packet */
+#if 0
+ file_save("ntlmssp_auth.dat", request.data, request.length);
+#endif
+
+ if (ntlmssp_state->unicode) {
+ parse_string = "CdBBUUUBd";
+ } else {
+ parse_string = "CdBBAAABd";
+ }
+
+ data_blob_free(&ntlmssp_state->lm_resp);
+ data_blob_free(&ntlmssp_state->nt_resp);
+
+ SAFE_FREE(ntlmssp_state->user);
+ SAFE_FREE(ntlmssp_state->domain);
+ SAFE_FREE(ntlmssp_state->workstation);
+
+ /* now the NTLMSSP encoded auth hashes */
+ if (!msrpc_parse(&request, parse_string,
+ "NTLMSSP",
+ &ntlmssp_command,
+ &ntlmssp_state->lm_resp,
+ &ntlmssp_state->nt_resp,
+ &ntlmssp_state->domain,
+ &ntlmssp_state->user,
+ &ntlmssp_state->workstation,
+ &sess_key,
+ &neg_flags)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ data_blob_free(&sess_key);
+
+ DEBUG(3,("Got user=[%s] domain=[%s] workstation=[%s] len1=%d len2=%d\n",
+ ntlmssp_state->user, ntlmssp_state->domain, ntlmssp_state->workstation, ntlmssp_state->lm_resp.length, ntlmssp_state->nt_resp.length));
+
+#if 0
+ file_save("nthash1.dat", &ntlmssp_state->nt_resp.data, &ntlmssp_state->nt_resp.length);
+ file_save("lmhash1.dat", &ntlmssp_state->lm_resp.data, &ntlmssp_state->lm_resp.length);
+#endif
+
+ nt_status = ntlmssp_state->check_password(ntlmssp_state);
+
+ *reply = data_blob(NULL, 0);
+
+ return nt_status;
+}
+
+/**
+ * Create an NTLMSSP state machine
+ *
+ * @param ntlmssp_state NTLMSSP State, allocated by this funciton
+ */
+
+NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state)
+{
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("NTLMSSP context");
+
+ *ntlmssp_state = talloc_zero(mem_ctx, sizeof(**ntlmssp_state));
+ if (!*ntlmssp_state) {
+ DEBUG(0,("ntlmssp_server_start: talloc failed!\n"));
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*ntlmssp_state)->mem_ctx = mem_ctx;
+ (*ntlmssp_state)->get_challenge = get_challenge;
+
+ (*ntlmssp_state)->get_global_myname = lp_netbios_name;
+ (*ntlmssp_state)->get_domain = lp_workgroup;
+ (*ntlmssp_state)->server_role = ROLE_DOMAIN_MEMBER; /* a good default */
+
+ (*ntlmssp_state)->expected_state = NTLMSSP_NEGOTIATE;
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * End an NTLMSSP state machine
+ *
+ * @param ntlmssp_state NTLMSSP State, free()ed by this funciton
+ */
+
+NTSTATUS ntlmssp_server_end(NTLMSSP_STATE **ntlmssp_state)
+{
+ TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx;
+
+ data_blob_free(&(*ntlmssp_state)->chal);
+ data_blob_free(&(*ntlmssp_state)->lm_resp);
+ data_blob_free(&(*ntlmssp_state)->nt_resp);
+
+ SAFE_FREE((*ntlmssp_state)->user);
+ SAFE_FREE((*ntlmssp_state)->domain);
+ SAFE_FREE((*ntlmssp_state)->workstation);
+
+ talloc_destroy(mem_ctx);
+ *ntlmssp_state = NULL;
+ return NT_STATUS_OK;
+}
+
+/**
+ * Next state function for the NTLMSSP state machine
+ *
+ * @param ntlmssp_state NTLMSSP State
+ * @param request The request, as a DATA_BLOB
+ * @param request The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors, NT_STATUS_MORE_PROCESSING_REQUIRED or NT_STATUS_OK.
+ */
+
+NTSTATUS ntlmssp_server_update(NTLMSSP_STATE *ntlmssp_state,
+ const DATA_BLOB request, DATA_BLOB *reply)
+{
+ uint32 ntlmssp_command;
+ *reply = data_blob(NULL, 0);
+
+ if (!msrpc_parse(&request, "Cd",
+ "NTLMSSP",
+ &ntlmssp_command)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (ntlmssp_command != ntlmssp_state->expected_state) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (ntlmssp_command == NTLMSSP_NEGOTIATE) {
+ return ntlmssp_server_negotiate(ntlmssp_state, request, reply);
+ } else if (ntlmssp_command == NTLMSSP_AUTH) {
+ return ntlmssp_server_auth(ntlmssp_state, request, reply);
+ } else {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+}
+
+/*********************************************************************
+ Client side NTLMSSP
+*********************************************************************/
+
+/**
+ * Next state function for the Initial packet
+ *
+ * @param ntlmssp_state NTLMSSP State
+ * @param request The request, as a DATA_BLOB. reply.data must be NULL
+ * @param request The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors or NT_STATUS_OK.
+ */
+
+static NTSTATUS ntlmssp_client_initial(struct ntlmssp_client_state *ntlmssp_state,
+ DATA_BLOB reply, DATA_BLOB *next_request)
+{
+ if (ntlmssp_state->unicode) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
+ }
+
+ /* generate the ntlmssp negotiate packet */
+ msrpc_gen(next_request, "CddAA",
+ "NTLMSSP",
+ NTLMSSP_NEGOTIATE,
+ ntlmssp_state->neg_flags,
+ ntlmssp_state->get_domain(),
+ ntlmssp_state->get_global_myname());
+
+ return NT_STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+/**
+ * Next state function for the Challenge Packet. Generate an auth packet.
+ *
+ * @param ntlmssp_state NTLMSSP State
+ * @param request The request, as a DATA_BLOB. reply.data must be NULL
+ * @param request The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors or NT_STATUS_OK.
+ */
+
+static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_state,
+ const DATA_BLOB reply, DATA_BLOB *next_request)
+{
+ uint32 chal_flags, ntlmssp_command, unkn1, unkn2;
+ DATA_BLOB server_domain_blob;
+ DATA_BLOB challenge_blob;
+ DATA_BLOB struct_blob;
+ char *server_domain;
+ const char *chal_parse_string;
+ const char *auth_gen_string;
+ DATA_BLOB lm_response = data_blob(NULL, 0);
+ DATA_BLOB nt_response = data_blob(NULL, 0);
+ DATA_BLOB session_key = data_blob(NULL, 0);
+ uint8 datagram_sess_key[16];
+
+ ZERO_STRUCT(datagram_sess_key);
+
+ if (!msrpc_parse(&reply, "CdBd",
+ "NTLMSSP",
+ &ntlmssp_command,
+ &server_domain_blob,
+ &chal_flags)) {
+ DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ data_blob_free(&server_domain_blob);
+
+ if (chal_flags & NTLMSSP_NEGOTIATE_UNICODE) {
+ chal_parse_string = "CdUdbddB";
+ auth_gen_string = "CdBBUUUBd";
+ ntlmssp_state->unicode = True;
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_OEM;
+ } else if (chal_flags & NTLMSSP_NEGOTIATE_OEM) {
+ chal_parse_string = "CdAdbddB";
+ auth_gen_string = "CdBBAAABd";
+ ntlmssp_state->unicode = False;
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_UNICODE;
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM;
+ } else {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!msrpc_parse(&reply, chal_parse_string,
+ "NTLMSSP",
+ &ntlmssp_command,
+ &server_domain,
+ &chal_flags,
+ &challenge_blob, 8,
+ &unkn1, &unkn2,
+ &struct_blob)) {
+ DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ SAFE_FREE(server_domain);
+ data_blob_free(&struct_blob);
+
+ if (challenge_blob.length != 8) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (ntlmssp_state->use_ntlmv2) {
+
+ /* TODO: if the remote server is standalone, then we should replace 'domain'
+ with the server name as supplied above */
+
+ if (!SMBNTLMv2encrypt(ntlmssp_state->user,
+ ntlmssp_state->domain,
+ ntlmssp_state->password, challenge_blob,
+ &lm_response, &nt_response, &session_key)) {
+ data_blob_free(&challenge_blob);
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ uchar nt_hash[16];
+ E_md4hash(ntlmssp_state->password, nt_hash);
+
+ /* non encrypted password supplied. Ignore ntpass. */
+ if (lp_client_lanman_auth()) {
+ lm_response = data_blob(NULL, 24);
+ SMBencrypt(ntlmssp_state->password,challenge_blob.data,
+ lm_response.data);
+ }
+
+ nt_response = data_blob(NULL, 24);
+ SMBNTencrypt(ntlmssp_state->password,challenge_blob.data,
+ nt_response.data);
+ session_key = data_blob(NULL, 16);
+ SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
+ }
+
+ data_blob_free(&challenge_blob);
+
+ /* this generates the actual auth packet */
+ if (!msrpc_gen(next_request, auth_gen_string,
+ "NTLMSSP",
+ NTLMSSP_AUTH,
+ lm_response.data, lm_response.length,
+ nt_response.data, nt_response.length,
+ ntlmssp_state->domain,
+ ntlmssp_state->user,
+ ntlmssp_state->get_global_myname(),
+ datagram_sess_key, 0,
+ ntlmssp_state->neg_flags)) {
+
+ data_blob_free(&lm_response);
+ data_blob_free(&nt_response);
+ data_blob_free(&session_key);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ data_blob_free(&lm_response);
+ data_blob_free(&nt_response);
+
+ ntlmssp_state->session_key = session_key;
+
+ return NT_STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS ntlmssp_client_start(NTLMSSP_CLIENT_STATE **ntlmssp_state)
+{
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("NTLMSSP Client context");
+
+ *ntlmssp_state = talloc_zero(mem_ctx, sizeof(**ntlmssp_state));
+ if (!*ntlmssp_state) {
+ DEBUG(0,("ntlmssp_server_start: talloc failed!\n"));
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*ntlmssp_state)->mem_ctx = mem_ctx;
+
+ (*ntlmssp_state)->get_global_myname = lp_netbios_name;
+ (*ntlmssp_state)->get_domain = lp_workgroup;
+
+ (*ntlmssp_state)->unicode = True;
+
+ (*ntlmssp_state)->neg_flags =
+ NTLMSSP_NEGOTIATE_128 |
+ NTLMSSP_NEGOTIATE_NTLM |
+ NTLMSSP_REQUEST_TARGET;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS ntlmssp_client_end(NTLMSSP_CLIENT_STATE **ntlmssp_state)
+{
+ TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx;
+
+ data_blob_free(&(*ntlmssp_state)->session_key);
+ talloc_destroy(mem_ctx);
+ *ntlmssp_state = NULL;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS ntlmssp_client_update(NTLMSSP_CLIENT_STATE *ntlmssp_state,
+ DATA_BLOB reply, DATA_BLOB *next_request)
+{
+ uint32 ntlmssp_command;
+ *next_request = data_blob(NULL, 0);
+
+ if (!reply.length) {
+ return ntlmssp_client_initial(ntlmssp_state, reply, next_request);
+ }
+
+ if (!msrpc_parse(&reply, "Cd",
+ "NTLMSSP",
+ &ntlmssp_command)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (ntlmssp_command == NTLMSSP_CHALLENGE) {
+ return ntlmssp_client_challenge(ntlmssp_state, reply, next_request);
+ }
+ return NT_STATUS_INVALID_PARAMETER;
+}
+
+NTSTATUS ntlmssp_set_username(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *user)
+{
+ ntlmssp_state->user = talloc_strdup(ntlmssp_state->mem_ctx, user);
+ if (!ntlmssp_state->user) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS ntlmssp_set_password(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *password)
+{
+ ntlmssp_state->password = talloc_strdup(ntlmssp_state->mem_ctx, password);
+ if (!ntlmssp_state->password) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS ntlmssp_set_domain(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *domain)
+{
+ ntlmssp_state->domain = talloc_strdup(ntlmssp_state->mem_ctx, domain);
+ if (!ntlmssp_state->domain) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}
diff --git a/source4/libcli/ntlmssp_parse.c b/source4/libcli/ntlmssp_parse.c
new file mode 100644
index 0000000000..ac779a3906
--- /dev/null
+++ b/source4/libcli/ntlmssp_parse.c
@@ -0,0 +1,303 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple kerberos5/SPNEGO routines
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Jim McDonough 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ this is a tiny msrpc packet generator. I am only using this to
+ avoid tying this code to a particular varient 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 BOOL unicode, 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
+ */
+BOOL msrpc_gen(DATA_BLOB *blob,
+ const char *format, ...)
+{
+ int i, n;
+ va_list ap;
+ char *s;
+ uint8 *b;
+ int head_size=0, data_size=0;
+ int head_ofs, data_ofs;
+ BOOL unicode;
+
+ /* 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;
+ data_size += str_charnum(s) * 2;
+ break;
+ case 'A':
+ s = va_arg(ap, char *);
+ head_size += 8;
+ data_size += str_ascii_charnum(s);
+ break;
+ case 'a':
+ unicode = va_arg(ap, BOOL);
+ n = va_arg(ap, int);
+ s = va_arg(ap, char *);
+ if (unicode) {
+ data_size += (str_charnum(s) * 2) + 4;
+ } else {
+ data_size += (str_ascii_charnum(s)) + 4;
+ }
+ break;
+ case 'B':
+ b = va_arg(ap, uint8 *);
+ head_size += 8;
+ data_size += va_arg(ap, int);
+ break;
+ case 'b':
+ b = va_arg(ap, uint8 *);
+ head_size += va_arg(ap, int);
+ break;
+ case 'd':
+ n = va_arg(ap, int);
+ head_size += 4;
+ break;
+ case 'C':
+ s = va_arg(ap, char *);
+ head_size += str_charnum(s) + 1;
+ break;
+ }
+ }
+ va_end(ap);
+
+ /* allocate the space, then scan the format again to fill in the values */
+ *blob = data_blob(NULL, head_size + data_size);
+
+ head_ofs = 0;
+ data_ofs = head_size;
+
+ va_start(ap, format);
+ for (i=0; format[i]; i++) {
+ switch (format[i]) {
+ case 'U':
+ s = va_arg(ap, char *);
+ n = str_charnum(s);
+ SSVAL(blob->data, head_ofs, n*2); head_ofs += 2;
+ SSVAL(blob->data, head_ofs, n*2); head_ofs += 2;
+ SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
+ push_string(NULL, blob->data+data_ofs, s, n*2, STR_UNICODE|STR_NOALIGN);
+ data_ofs += n*2;
+ break;
+ case 'A':
+ s = va_arg(ap, char *);
+ n = str_ascii_charnum(s);
+ 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;
+ push_string(NULL, blob->data+data_ofs, s, n, STR_ASCII|STR_NOALIGN);
+ data_ofs += n;
+ break;
+ case 'a':
+ unicode = va_arg(ap, BOOL);
+ n = va_arg(ap, int);
+ SSVAL(blob->data, data_ofs, n); data_ofs += 2;
+ s = va_arg(ap, char *);
+ if (unicode) {
+ n = str_charnum(s);
+ SSVAL(blob->data, data_ofs, n*2); data_ofs += 2;
+ if (0 < n) {
+ push_string(NULL, blob->data+data_ofs, s, n*2,
+ STR_UNICODE|STR_NOALIGN);
+ }
+ data_ofs += n*2;
+ } else {
+ n = str_ascii_charnum(s);
+ SSVAL(blob->data, data_ofs, n); data_ofs += 2;
+ if (0 < n) {
+ push_string(NULL, blob->data+data_ofs, s, n,
+ STR_ASCII|STR_NOALIGN);
+ }
+ data_ofs += n;
+ }
+ break;
+
+ case 'B':
+ b = va_arg(ap, uint8 *);
+ n = va_arg(ap, int);
+ 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;
+ memcpy(blob->data+data_ofs, b, n);
+ data_ofs += n;
+ break;
+ case 'd':
+ n = va_arg(ap, int);
+ SIVAL(blob->data, head_ofs, n); head_ofs += 4;
+ break;
+ case 'b':
+ b = va_arg(ap, uint8 *);
+ n = va_arg(ap, int);
+ memcpy(blob->data + head_ofs, b, n);
+ head_ofs += n;
+ break;
+ case 'C':
+ s = va_arg(ap, char *);
+ head_ofs += push_string(NULL, blob->data+head_ofs, s, -1,
+ STR_ASCII|STR_TERMINATE);
+ break;
+ }
+ }
+ va_end(ap);
+
+ return True;
+}
+
+
+/* a helpful macro to avoid running over the end of our blob */
+#define NEED_DATA(amount) \
+if ((head_ofs + amount) > blob->length) { \
+ 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(const DATA_BLOB *blob,
+ const char *format, ...)
+{
+ int i;
+ va_list ap;
+ char **ps, *s;
+ DATA_BLOB *b;
+ size_t head_ofs = 0;
+ uint16 len1, len2;
+ uint32 ptr;
+ uint32 *v;
+ pstring p;
+
+ 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;
+
+ /* make sure its in the right format - be strict */
+ if (len1 != len2 || ptr + len1 > blob->length) {
+ return False;
+ }
+ if (len1 & 1) {
+ /* if odd length and unicode */
+ return False;
+ }
+
+ ps = va_arg(ap, char **);
+ if (0 < len1) {
+ pull_string(NULL, p, blob->data + ptr, sizeof(p),
+ len1,
+ STR_UNICODE|STR_NOALIGN);
+ (*ps) = smb_xstrdup(p);
+ } else {
+ (*ps) = smb_xstrdup("");
+ }
+ 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;
+
+ /* make sure its in the right format - be strict */
+ if (len1 != len2 || ptr + len1 > blob->length) {
+ return False;
+ }
+
+ ps = va_arg(ap, char **);
+ if (0 < len1) {
+ pull_string(NULL, p, blob->data + ptr, sizeof(p),
+ len1,
+ STR_ASCII|STR_NOALIGN);
+ (*ps) = smb_xstrdup(p);
+ } else {
+ (*ps) = smb_xstrdup("");
+ }
+ 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;
+ /* make sure its in the right format - be strict */
+ if (len1 != len2 || ptr + len1 > blob->length) {
+ return False;
+ }
+ b = (DATA_BLOB *)va_arg(ap, void *);
+ *b = data_blob(blob->data + ptr, len1);
+ break;
+ case 'b':
+ b = (DATA_BLOB *)va_arg(ap, void *);
+ len1 = va_arg(ap, unsigned);
+ /* make sure its in the right format - be strict */
+ NEED_DATA(len1);
+ *b = data_blob(blob->data + head_ofs, len1);
+ head_ofs += len1;
+ break;
+ case 'd':
+ v = va_arg(ap, uint32 *);
+ NEED_DATA(4);
+ *v = IVAL(blob->data, head_ofs); head_ofs += 4;
+ break;
+ case 'C':
+ s = va_arg(ap, char *);
+ head_ofs += pull_string(NULL, p, blob->data+head_ofs, sizeof(p),
+ blob->length - head_ofs,
+ STR_ASCII|STR_TERMINATE);
+ if (strcmp(s, p) != 0) {
+ return False;
+ }
+ break;
+ }
+ }
+ va_end(ap);
+
+ return True;
+}
+
diff --git a/source4/libcli/raw/README b/source4/libcli/raw/README
new file mode 100644
index 0000000000..cb3e507e3a
--- /dev/null
+++ b/source4/libcli/raw/README
@@ -0,0 +1,5 @@
+Design notes for client library restructure:
+
+1 - no references to cli_state should exist in libcli/raw.
+2 - all interfaces to functions in this directory should use cli_session or cli_tree as
+ the primary context structure \ No newline at end of file
diff --git a/source4/libcli/raw/clikrb5.c b/source4/libcli/raw/clikrb5.c
new file mode 100644
index 0000000000..5edc56daa9
--- /dev/null
+++ b/source4/libcli/raw/clikrb5.c
@@ -0,0 +1,399 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple kerberos5 routines for active directory
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Luke Howard 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_KRB5
+
+#ifdef HAVE_KRB5_KEYBLOCK_KEYVALUE
+#define KRB5_KEY_TYPE(k) ((k)->keytype)
+#define KRB5_KEY_LENGTH(k) ((k)->keyvalue.length)
+#define KRB5_KEY_DATA(k) ((k)->keyvalue.data)
+#else
+#define KRB5_KEY_TYPE(k) ((k)->enctype)
+#define KRB5_KEY_LENGTH(k) ((k)->length)
+#define KRB5_KEY_DATA(k) ((k)->contents)
+#endif /* HAVE_KRB5_KEYBLOCK_KEYVALUE */
+
+#ifndef HAVE_KRB5_SET_REAL_TIME
+/*
+ * This function is not in the Heimdal mainline.
+ */
+ krb5_error_code krb5_set_real_time(krb5_context context, int32_t seconds, int32_t microseconds)
+{
+ krb5_error_code ret;
+ int32_t sec, usec;
+
+ ret = krb5_us_timeofday(context, &sec, &usec);
+ if (ret)
+ return ret;
+
+ context->kdc_sec_offset = seconds - sec;
+ context->kdc_usec_offset = microseconds - usec;
+
+ return 0;
+}
+#endif
+
+#if defined(HAVE_KRB5_SET_DEFAULT_IN_TKT_ETYPES) && !defined(HAVE_KRB5_SET_DEFAULT_TGS_KTYPES)
+ krb5_error_code krb5_set_default_tgs_ktypes(krb5_context ctx, const krb5_enctype *enc)
+{
+ return krb5_set_default_in_tkt_etypes(ctx, enc);
+}
+#endif
+
+#if defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS)
+/* HEIMDAL */
+ void setup_kaddr( krb5_address *pkaddr, struct sockaddr *paddr)
+{
+ pkaddr->addr_type = KRB5_ADDRESS_INET;
+ pkaddr->address.length = sizeof(((struct sockaddr_in *)paddr)->sin_addr);
+ pkaddr->address.data = (char *)&(((struct sockaddr_in *)paddr)->sin_addr);
+}
+#elif defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS)
+/* MIT */
+ void setup_kaddr( krb5_address *pkaddr, struct sockaddr *paddr)
+{
+ pkaddr->addrtype = ADDRTYPE_INET;
+ pkaddr->length = sizeof(((struct sockaddr_in *)paddr)->sin_addr);
+ pkaddr->contents = (char *)&(((struct sockaddr_in *)paddr)->sin_addr);
+}
+#else
+ __ERROR__XX__UNKNOWN_ADDRTYPE
+#endif
+
+#if defined(HAVE_KRB5_PRINCIPAL2SALT) && defined(HAVE_KRB5_USE_ENCTYPE) && defined(HAVE_KRB5_STRING_TO_KEY)
+ int create_kerberos_key_from_string(krb5_context context,
+ krb5_principal host_princ,
+ krb5_data *password,
+ krb5_keyblock *key,
+ krb5_enctype enctype)
+{
+ int ret;
+ krb5_data salt;
+ krb5_encrypt_block eblock;
+
+ ret = krb5_principal2salt(context, host_princ, &salt);
+ if (ret) {
+ DEBUG(1,("krb5_principal2salt failed (%s)\n", error_message(ret)));
+ return ret;
+ }
+ krb5_use_enctype(context, &eblock, enctype);
+ return krb5_string_to_key(context, &eblock, key, password, &salt);
+}
+#elif defined(HAVE_KRB5_GET_PW_SALT) && defined(HAVE_KRB5_STRING_TO_KEY_SALT)
+ int create_kerberos_key_from_string(krb5_context context,
+ krb5_principal host_princ,
+ krb5_data *password,
+ krb5_keyblock *key,
+ krb5_enctype enctype)
+{
+ int ret;
+ krb5_salt salt;
+
+ ret = krb5_get_pw_salt(context, host_princ, &salt);
+ if (ret) {
+ DEBUG(1,("krb5_get_pw_salt failed (%s)\n", error_message(ret)));
+ return ret;
+ }
+ return krb5_string_to_key_salt(context, enctype, password->data,
+ salt, key);
+}
+#else
+ __ERROR_XX_UNKNOWN_CREATE_KEY_FUNCTIONS
+#endif
+
+#if defined(HAVE_KRB5_GET_PERMITTED_ENCTYPES)
+krb5_error_code get_kerberos_allowed_etypes(krb5_context context,
+ krb5_enctype **enctypes)
+{
+ return krb5_get_permitted_enctypes(context, enctypes);
+}
+#elif defined(HAVE_KRB5_GET_DEFAULT_IN_TKT_ETYPES)
+krb5_error_code get_kerberos_allowed_etypes(krb5_context context,
+ krb5_enctype **enctypes)
+{
+ return krb5_get_default_in_tkt_etypes(context, enctypes);
+}
+#else
+#error UNKNOWN_GET_ENCTYPES_FUNCTIONS
+#endif
+
+ void free_kerberos_etypes(krb5_context context,
+ krb5_enctype *enctypes)
+{
+#if defined(HAVE_KRB5_FREE_KTYPES)
+ krb5_free_ktypes(context, enctypes);
+ return;
+#else
+ SAFE_FREE(enctypes);
+ return;
+#endif
+}
+
+#if defined(HAVE_KRB5_AUTH_CON_SETKEY) && !defined(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY)
+ krb5_error_code krb5_auth_con_setuseruserkey(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_keyblock *keyblock)
+{
+ return krb5_auth_con_setkey(context, auth_context, keyblock);
+}
+#endif
+
+ void get_auth_data_from_tkt(DATA_BLOB *auth_data, krb5_ticket *tkt)
+{
+#if defined(HAVE_KRB5_TKT_ENC_PART2)
+ if (tkt->enc_part2)
+ *auth_data = data_blob(tkt->enc_part2->authorization_data[0]->contents,
+ tkt->enc_part2->authorization_data[0]->length);
+#else
+ if (tkt->ticket.authorization_data && tkt->ticket.authorization_data->len)
+ *auth_data = data_blob(tkt->ticket.authorization_data->val->ad_data.data,
+ tkt->ticket.authorization_data->val->ad_data.length);
+#endif
+}
+
+ krb5_const_principal get_principal_from_tkt(krb5_ticket *tkt)
+{
+#if defined(HAVE_KRB5_TKT_ENC_PART2)
+ return tkt->enc_part2->client;
+#else
+ return tkt->client;
+#endif
+}
+
+#if !defined(HAVE_KRB5_LOCATE_KDC)
+ krb5_error_code krb5_locate_kdc(krb5_context ctx, const krb5_data *realm, struct sockaddr **addr_pp, int *naddrs, int get_masters)
+{
+ krb5_krbhst_handle hnd;
+ krb5_krbhst_info *hinfo;
+ krb5_error_code rc;
+ int num_kdcs, i;
+ struct sockaddr *sa;
+
+ *addr_pp = NULL;
+ *naddrs = 0;
+
+ rc = krb5_krbhst_init(ctx, realm->data, KRB5_KRBHST_KDC, &hnd);
+ if (rc) {
+ DEBUG(0, ("krb5_locate_kdc: krb5_krbhst_init failed (%s)\n", error_message(rc)));
+ return rc;
+ }
+
+ for ( num_kdcs = 0; (rc = krb5_krbhst_next(ctx, hnd, &hinfo) == 0); num_kdcs++)
+ ;
+
+ krb5_krbhst_reset(ctx, hnd);
+
+ if (!num_kdcs) {
+ DEBUG(0, ("krb5_locate_kdc: zero kdcs found !\n"));
+ krb5_krbhst_free(ctx, hnd);
+ return -1;
+ }
+
+ sa = malloc( sizeof(struct sockaddr) * num_kdcs );
+ if (!sa) {
+ DEBUG(0, ("krb5_locate_kdc: malloc failed\n"));
+ krb5_krbhst_free(ctx, hnd);
+ naddrs = 0;
+ return -1;
+ }
+
+ memset(*addr_pp, '\0', sizeof(struct sockaddr) * num_kdcs );
+
+ for (i = 0; i < num_kdcs && (rc = krb5_krbhst_next(ctx, hnd, &hinfo) == 0); i++) {
+ if (hinfo->ai->ai_family == AF_INET)
+ memcpy(&sa[i], hinfo->ai->ai_addr, sizeof(struct sockaddr));
+ }
+
+ krb5_krbhst_free(ctx, hnd);
+
+ *naddrs = num_kdcs;
+ *addr_pp = sa;
+ return 0;
+}
+#endif
+
+/*
+ we can't use krb5_mk_req because w2k wants the service to be in a particular format
+*/
+static krb5_error_code krb5_mk_req2(krb5_context context,
+ krb5_auth_context *auth_context,
+ const krb5_flags ap_req_options,
+ const char *principal,
+ krb5_ccache ccache,
+ krb5_data *outbuf)
+{
+ krb5_error_code retval;
+ krb5_principal server;
+ krb5_creds * credsp;
+ krb5_creds creds;
+ krb5_data in_data;
+
+ retval = krb5_parse_name(context, principal, &server);
+ if (retval) {
+ DEBUG(1,("Failed to parse principal %s\n", principal));
+ return retval;
+ }
+
+ /* obtain ticket & session key */
+ memset((char *)&creds, 0, sizeof(creds));
+ if ((retval = krb5_copy_principal(context, server, &creds.server))) {
+ DEBUG(1,("krb5_copy_principal failed (%s)\n",
+ error_message(retval)));
+ goto cleanup_princ;
+ }
+
+ if ((retval = krb5_cc_get_principal(context, ccache, &creds.client))) {
+ DEBUG(1,("krb5_cc_get_principal failed (%s)\n",
+ error_message(retval)));
+ goto cleanup_creds;
+ }
+
+ if ((retval = krb5_get_credentials(context, 0,
+ ccache, &creds, &credsp))) {
+ DEBUG(1,("krb5_get_credentials failed for %s (%s)\n",
+ principal, error_message(retval)));
+ goto cleanup_creds;
+ }
+
+ /* cope with the ticket being in the future due to clock skew */
+ if ((unsigned)credsp->times.starttime > time(NULL)) {
+ time_t t = time(NULL);
+ int time_offset = (unsigned)credsp->times.starttime - t;
+ DEBUG(4,("Advancing clock by %d seconds to cope with clock skew\n", time_offset));
+ krb5_set_real_time(context, t + time_offset + 1, 0);
+ }
+
+ in_data.length = 0;
+ retval = krb5_mk_req_extended(context, auth_context, ap_req_options,
+ &in_data, credsp, outbuf);
+ if (retval) {
+ DEBUG(1,("krb5_mk_req_extended failed (%s)\n",
+ error_message(retval)));
+ }
+
+ krb5_free_creds(context, credsp);
+
+cleanup_creds:
+ krb5_free_cred_contents(context, &creds);
+
+cleanup_princ:
+ krb5_free_principal(context, server);
+
+ return retval;
+}
+
+/*
+ get a kerberos5 ticket for the given service
+*/
+DATA_BLOB krb5_get_ticket(const char *principal, time_t time_offset)
+{
+ krb5_error_code retval;
+ krb5_data packet;
+ krb5_ccache ccdef;
+ krb5_context context;
+ krb5_auth_context auth_context = NULL;
+ DATA_BLOB ret;
+ krb5_enctype enc_types[] = {
+#ifdef ENCTYPE_ARCFOUR_HMAC
+ ENCTYPE_ARCFOUR_HMAC,
+#endif
+ ENCTYPE_DES_CBC_MD5,
+ ENCTYPE_DES_CBC_CRC,
+ ENCTYPE_NULL};
+
+ retval = krb5_init_context(&context);
+ if (retval) {
+ DEBUG(1,("krb5_init_context failed (%s)\n",
+ error_message(retval)));
+ goto failed;
+ }
+
+ if (time_offset != 0) {
+ krb5_set_real_time(context, time(NULL) + time_offset, 0);
+ }
+
+ if ((retval = krb5_cc_default(context, &ccdef))) {
+ DEBUG(1,("krb5_cc_default failed (%s)\n",
+ error_message(retval)));
+ goto failed;
+ }
+
+ if ((retval = krb5_set_default_tgs_ktypes(context, enc_types))) {
+ DEBUG(1,("krb5_set_default_tgs_ktypes failed (%s)\n",
+ error_message(retval)));
+ goto failed;
+ }
+
+ if ((retval = krb5_mk_req2(context,
+ &auth_context,
+ 0,
+ principal,
+ ccdef, &packet))) {
+ goto failed;
+ }
+
+ ret = data_blob(packet.data, packet.length);
+/* Hmm, heimdal dooesn't have this - what's the correct call? */
+/* krb5_free_data_contents(context, &packet); */
+ krb5_free_context(context);
+ return ret;
+
+failed:
+ if ( context )
+ krb5_free_context(context);
+
+ return data_blob(NULL, 0);
+}
+
+ BOOL krb5_get_smb_session_key(krb5_context context, krb5_auth_context auth_context, uint8 session_key[16])
+ {
+#ifdef ENCTYPE_ARCFOUR_HMAC
+ krb5_keyblock *skey;
+#endif
+ BOOL ret = False;
+
+ memset(session_key, 0, 16);
+
+#ifdef ENCTYPE_ARCFOUR_HMAC
+ if (krb5_auth_con_getremotesubkey(context, auth_context, &skey) == 0 && skey != NULL) {
+ if (KRB5_KEY_TYPE(skey) ==
+ ENCTYPE_ARCFOUR_HMAC
+ && KRB5_KEY_LENGTH(skey) == 16) {
+ memcpy(session_key, KRB5_KEY_DATA(skey), KRB5_KEY_LENGTH(skey));
+ ret = True;
+ }
+ krb5_free_keyblock(context, skey);
+ }
+#endif /* ENCTYPE_ARCFOUR_HMAC */
+
+ return ret;
+ }
+#else /* HAVE_KRB5 */
+ /* this saves a few linking headaches */
+DATA_BLOB krb5_get_ticket(const char *principal, time_t time_offset)
+ {
+ DEBUG(0,("NO KERBEROS SUPPORT\n"));
+ return data_blob(NULL, 0);
+ }
+
+#endif
diff --git a/source4/libcli/raw/clioplock.c b/source4/libcli/raw/clioplock.c
new file mode 100644
index 0000000000..8f69716bda
--- /dev/null
+++ b/source4/libcli/raw/clioplock.c
@@ -0,0 +1,57 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB client oplock functions
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+send an ack for an oplock break request
+****************************************************************************/
+BOOL cli_oplock_ack(struct cli_tree *tree, uint16 fnum, uint16 ack_level)
+{
+ BOOL ret;
+ struct cli_request *req;
+
+ req = cli_request_setup(tree, SMBlockingX, 8, 0);
+
+ SSVAL(req->out.vwv,VWV(0),0xFF);
+ SSVAL(req->out.vwv,VWV(1),0);
+ SSVAL(req->out.vwv,VWV(2),fnum);
+ SSVAL(req->out.vwv,VWV(3),ack_level);
+ SIVAL(req->out.vwv,VWV(4),0);
+ SSVAL(req->out.vwv,VWV(6),0);
+ SSVAL(req->out.vwv,VWV(7),0);
+
+ ret = cli_request_send(req);
+ cli_request_destroy(req);
+
+ return ret;
+}
+
+
+/****************************************************************************
+set the oplock handler for a connection
+****************************************************************************/
+void cli_oplock_handler(struct cli_transport *transport,
+ BOOL (*handler)(struct cli_transport *, uint16, uint16, uint8, void *),
+ void *private)
+{
+ transport->oplock.handler = handler;
+ transport->oplock.private = private;
+}
diff --git a/source4/libcli/raw/clirewrite.c b/source4/libcli/raw/clirewrite.c
new file mode 100644
index 0000000000..2d2e2e3feb
--- /dev/null
+++ b/source4/libcli/raw/clirewrite.c
@@ -0,0 +1,22 @@
+#include "includes.h"
+
+/*
+
+ this is a set of temporary stub functions used during the libsmb rewrite.
+ This file will need to go away before the rewrite is complete.
+*/
+
+void become_root(void)
+{}
+
+void unbecome_root(void)
+{}
+
+BOOL become_user_permanently(uid_t uid, gid_t gid)
+{ return True; }
+
+void set_effective_uid(uid_t uid)
+{}
+
+uid_t sec_initial_uid(void)
+{ return 0; }
diff --git a/source4/libcli/raw/clisession.c b/source4/libcli/raw/clisession.c
new file mode 100644
index 0000000000..406491e432
--- /dev/null
+++ b/source4/libcli/raw/clisession.c
@@ -0,0 +1,444 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB client session context management functions
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) James Myers 2003 <myersjj@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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#define SETUP_REQUEST_SESSION(cmd, wct, buflen) do { \
+ req = cli_request_setup_session(session, cmd, wct, buflen); \
+ if (!req) return NULL; \
+} while (0)
+
+/****************************************************************************
+ Initialize the session context
+****************************************************************************/
+struct cli_session *cli_session_init(struct cli_transport *transport)
+{
+ struct cli_session *session;
+ TALLOC_CTX *mem_ctx = talloc_init("cli_session");
+ if (mem_ctx == NULL) {
+ return NULL;
+ }
+
+ session = talloc_zero(mem_ctx, sizeof(*session));
+ if (!session) {
+ talloc_destroy(mem_ctx);
+ return NULL;
+ }
+
+ session->mem_ctx = mem_ctx;
+ session->transport = transport;
+ session->pid = (uint16)getpid();
+ session->vuid = UID_FIELD_INVALID;
+ session->transport->reference_count++;
+
+ return session;
+}
+
+/****************************************************************************
+reduce reference_count and destroy is <= 0
+****************************************************************************/
+void cli_session_close(struct cli_session *session)
+{
+ session->reference_count--;
+ if (session->reference_count <= 0) {
+ cli_transport_close(session->transport);
+ talloc_destroy(session->mem_ctx);
+ }
+}
+
+/****************************************************************************
+ Perform a session setup (async send)
+****************************************************************************/
+struct cli_request *smb_raw_session_setup_send(struct cli_session *session, union smb_sesssetup *parms)
+{
+ struct cli_request *req;
+
+ switch (parms->generic.level) {
+ case RAW_SESSSETUP_GENERIC:
+ /* handled elsewhere */
+ return NULL;
+
+ case RAW_SESSSETUP_OLD:
+ SETUP_REQUEST_SESSION(SMBsesssetupX, 10, 0);
+ SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
+ SSVAL(req->out.vwv, VWV(1), 0);
+ SSVAL(req->out.vwv,VWV(2),parms->old.in.bufsize);
+ SSVAL(req->out.vwv,VWV(3),parms->old.in.mpx_max);
+ SSVAL(req->out.vwv,VWV(4),parms->old.in.vc_num);
+ SIVAL(req->out.vwv,VWV(5),parms->old.in.sesskey);
+ SSVAL(req->out.vwv,VWV(7),parms->old.in.password.length);
+ cli_req_append_blob(req, &parms->old.in.password);
+ cli_req_append_string(req, parms->old.in.user, STR_TERMINATE);
+ cli_req_append_string(req, parms->old.in.domain, STR_TERMINATE|STR_UPPER);
+ cli_req_append_string(req, parms->old.in.os, STR_TERMINATE);
+ cli_req_append_string(req, parms->old.in.lanman, STR_TERMINATE);
+ break;
+
+ case RAW_SESSSETUP_NT1:
+ SETUP_REQUEST_SESSION(SMBsesssetupX, 13, 0);
+ SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
+ SSVAL(req->out.vwv, VWV(1), 0);
+ SSVAL(req->out.vwv, VWV(2), parms->nt1.in.bufsize);
+ SSVAL(req->out.vwv, VWV(3), parms->nt1.in.mpx_max);
+ SSVAL(req->out.vwv, VWV(4), parms->nt1.in.vc_num);
+ SIVAL(req->out.vwv, VWV(5), parms->nt1.in.sesskey);
+ SSVAL(req->out.vwv, VWV(7), parms->nt1.in.password1.length);
+ SSVAL(req->out.vwv, VWV(8), parms->nt1.in.password2.length);
+ SIVAL(req->out.vwv, VWV(9), 0); /* reserved */
+ SIVAL(req->out.vwv, VWV(11), parms->nt1.in.capabilities);
+ cli_req_append_blob(req, &parms->nt1.in.password1);
+ cli_req_append_blob(req, &parms->nt1.in.password2);
+ cli_req_append_string(req, parms->nt1.in.user, STR_TERMINATE);
+ cli_req_append_string(req, parms->nt1.in.domain, STR_TERMINATE|STR_UPPER);
+ cli_req_append_string(req, parms->nt1.in.os, STR_TERMINATE);
+ cli_req_append_string(req, parms->nt1.in.lanman, STR_TERMINATE);
+ break;
+
+ case RAW_SESSSETUP_SPNEGO:
+ SETUP_REQUEST_SESSION(SMBsesssetupX, 12, 0);
+ SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
+ SSVAL(req->out.vwv, VWV(1), 0);
+ SSVAL(req->out.vwv, VWV(2), parms->spnego.in.bufsize);
+ SSVAL(req->out.vwv, VWV(3), parms->spnego.in.mpx_max);
+ SSVAL(req->out.vwv, VWV(4), parms->spnego.in.vc_num);
+ SIVAL(req->out.vwv, VWV(5), parms->spnego.in.sesskey);
+ SSVAL(req->out.vwv, VWV(7), parms->spnego.in.secblob.length);
+ SIVAL(req->out.vwv, VWV(10), parms->spnego.in.capabilities);
+ cli_req_append_blob(req, &parms->spnego.in.secblob);
+ cli_req_append_string(req, parms->spnego.in.os, STR_TERMINATE);
+ cli_req_append_string(req, parms->spnego.in.lanman, STR_TERMINATE);
+ break;
+ }
+
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+
+/****************************************************************************
+ Perform a session setup (async recv)
+****************************************************************************/
+NTSTATUS smb_raw_session_setup_recv(struct cli_request *req,
+ TALLOC_CTX *mem_ctx,
+ union smb_sesssetup *parms)
+{
+ uint16 len;
+ char *p;
+
+ if (!cli_request_receive(req)) {
+ return cli_request_destroy(req);
+ }
+
+ if (!NT_STATUS_IS_OK(req->status) &&
+ !NT_STATUS_EQUAL(req->status,NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ return cli_request_destroy(req);
+ }
+
+ switch (parms->generic.level) {
+ case RAW_SESSSETUP_GENERIC:
+ /* handled elsewhere */
+ return NT_STATUS_INVALID_LEVEL;
+
+ case RAW_SESSSETUP_OLD:
+ CLI_CHECK_WCT(req, 3);
+ ZERO_STRUCT(parms->old.out);
+ parms->old.out.vuid = SVAL(req->in.hdr, HDR_UID);
+ parms->old.out.action = SVAL(req->in.vwv, VWV(2));
+ p = req->in.data;
+ if (p) {
+ p += cli_req_pull_string(req, mem_ctx, &parms->old.out.os, p, -1, STR_TERMINATE);
+ p += cli_req_pull_string(req, mem_ctx, &parms->old.out.lanman, p, -1, STR_TERMINATE);
+ p += cli_req_pull_string(req, mem_ctx, &parms->old.out.domain, p, -1, STR_TERMINATE);
+ }
+ break;
+
+ case RAW_SESSSETUP_NT1:
+ CLI_CHECK_WCT(req, 3);
+ ZERO_STRUCT(parms->nt1.out);
+ parms->nt1.out.vuid = SVAL(req->in.hdr, HDR_UID);
+ parms->nt1.out.action = SVAL(req->in.vwv, VWV(2));
+ p = req->in.data;
+ if (p) {
+ p += cli_req_pull_string(req, mem_ctx, &parms->nt1.out.os, p, -1, STR_TERMINATE);
+ p += cli_req_pull_string(req, mem_ctx, &parms->nt1.out.lanman, p, -1, STR_TERMINATE);
+ if (p < (req->in.data + req->in.data_size)) {
+ p += cli_req_pull_string(req, mem_ctx, &parms->nt1.out.domain, p, -1, STR_TERMINATE);
+ }
+ }
+ break;
+
+ case RAW_SESSSETUP_SPNEGO:
+ CLI_CHECK_WCT(req, 4);
+ ZERO_STRUCT(parms->spnego.out);
+ parms->spnego.out.vuid = SVAL(req->in.hdr, HDR_UID);
+ parms->spnego.out.action = SVAL(req->in.vwv, VWV(2));
+ len = SVAL(req->in.vwv, VWV(3));
+ p = req->in.data;
+ if (!p) {
+ break;
+ }
+
+ parms->spnego.out.secblob = cli_req_pull_blob(req, mem_ctx, p, len);
+ p += parms->spnego.out.secblob.length;
+ p += cli_req_pull_string(req, mem_ctx, &parms->spnego.out.os, p, -1, STR_TERMINATE);
+ p += cli_req_pull_string(req, mem_ctx, &parms->spnego.out.lanman, p, -1, STR_TERMINATE);
+ p += cli_req_pull_string(req, mem_ctx, &parms->spnego.out.domain, p, -1, STR_TERMINATE);
+ break;
+ }
+
+failed:
+ return cli_request_destroy(req);
+}
+
+/*
+ form an encrypted lanman password from a plaintext password
+ and the server supplied challenge
+*/
+static DATA_BLOB lanman_blob(const char *pass, DATA_BLOB challenge)
+{
+ DATA_BLOB blob = data_blob(NULL, 24);
+ SMBencrypt(pass, challenge.data, blob.data);
+ return blob;
+}
+
+/*
+ form an encrypted NT password from a plaintext password
+ and the server supplied challenge
+*/
+static DATA_BLOB nt_blob(const char *pass, DATA_BLOB challenge)
+{
+ DATA_BLOB blob = data_blob(NULL, 24);
+ SMBNTencrypt(pass, challenge.data, blob.data);
+ return blob;
+}
+
+/*
+ setup signing for a NT1 style session setup
+*/
+static void setup_nt1_signing(struct cli_transport *transport, const char *password)
+{
+ uchar nt_hash[16];
+ uchar session_key[16];
+ DATA_BLOB nt_response;
+
+ E_md4hash(password, nt_hash);
+ SMBsesskeygen_ntv1(nt_hash, NULL, session_key);
+ nt_response = nt_blob(password, transport->negotiate.secblob);
+
+ cli_transport_simple_set_signing(transport, session_key, nt_response);
+}
+
+/****************************************************************************
+ Perform a session setup (sync interface) using generic interface and the old
+ style sesssetup call
+****************************************************************************/
+static NTSTATUS smb_raw_session_setup_generic_old(struct cli_session *session,
+ TALLOC_CTX *mem_ctx,
+ union smb_sesssetup *parms)
+{
+ NTSTATUS status;
+ union smb_sesssetup s2;
+
+ /* use the old interface */
+ s2.generic.level = RAW_SESSSETUP_OLD;
+ s2.old.in.bufsize = ~0;
+ s2.old.in.mpx_max = 50;
+ s2.old.in.vc_num = 1;
+ s2.old.in.sesskey = parms->generic.in.sesskey;
+ s2.old.in.domain = parms->generic.in.domain;
+ s2.old.in.user = parms->generic.in.user;
+ s2.old.in.os = "Unix";
+ s2.old.in.lanman = "Samba";
+
+ if (session->transport->negotiate.sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) {
+ s2.old.in.password = lanman_blob(parms->generic.in.password,
+ session->transport->negotiate.secblob);
+ } else {
+ s2.old.in.password = data_blob(parms->generic.in.password,
+ strlen(parms->generic.in.password));
+ }
+
+ status = smb_raw_session_setup(session, mem_ctx, &s2);
+
+ data_blob_free(&s2.old.in.password);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ parms->generic.out.vuid = s2.old.out.vuid;
+ parms->generic.out.os = s2.old.out.os;
+ parms->generic.out.lanman = s2.old.out.lanman;
+ parms->generic.out.domain = s2.old.out.domain;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Perform a session setup (sync interface) using generic interface and the NT1
+ style sesssetup call
+****************************************************************************/
+static NTSTATUS smb_raw_session_setup_generic_nt1(struct cli_session *session,
+ TALLOC_CTX *mem_ctx,
+ union smb_sesssetup *parms)
+{
+ NTSTATUS status;
+ union smb_sesssetup s2;
+
+ s2.generic.level = RAW_SESSSETUP_NT1;
+ s2.nt1.in.bufsize = ~0;
+ s2.nt1.in.mpx_max = 50;
+ s2.nt1.in.vc_num = 1;
+ s2.nt1.in.sesskey = parms->generic.in.sesskey;
+ s2.nt1.in.capabilities = parms->generic.in.capabilities;
+ s2.nt1.in.domain = parms->generic.in.domain;
+ s2.nt1.in.user = parms->generic.in.user;
+ s2.nt1.in.os = "Unix";
+ s2.nt1.in.lanman = "Samba";
+
+ if (session->transport->negotiate.sec_mode &
+ NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) {
+ s2.nt1.in.password1 = lanman_blob(parms->generic.in.password,
+ session->transport->negotiate.secblob);
+ s2.nt1.in.password2 = nt_blob(parms->generic.in.password,
+ session->transport->negotiate.secblob);
+ setup_nt1_signing(session->transport, parms->generic.in.password);
+ } else {
+ s2.nt1.in.password1 = data_blob(parms->generic.in.password,
+ strlen(parms->generic.in.password));
+ s2.nt1.in.password2 = data_blob(NULL, 0);
+ }
+
+ status = smb_raw_session_setup(session, mem_ctx, &s2);
+
+ data_blob_free(&s2.nt1.in.password1);
+ data_blob_free(&s2.nt1.in.password2);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ parms->generic.out.vuid = s2.nt1.out.vuid;
+ parms->generic.out.os = s2.nt1.out.os;
+ parms->generic.out.lanman = s2.nt1.out.lanman;
+ parms->generic.out.domain = s2.nt1.out.domain;
+
+ return NT_STATUS_OK;
+}
+
+
+/****************************************************************************
+ Perform a session setup (sync interface) using generic interface
+****************************************************************************/
+static NTSTATUS smb_raw_session_setup_generic(struct cli_session *session,
+ TALLOC_CTX *mem_ctx,
+ union smb_sesssetup *parms)
+{
+ if (session->transport->negotiate.protocol < PROTOCOL_LANMAN1) {
+ /* no session setup at all in earliest protocols */
+ ZERO_STRUCT(parms->generic.out);
+ return NT_STATUS_OK;
+ }
+
+ /* see if we need to use the original session setup interface */
+ if (session->transport->negotiate.protocol < PROTOCOL_NT1) {
+ return smb_raw_session_setup_generic_old(session, mem_ctx, parms);
+ }
+
+ /* see if we should use the NT1 interface */
+ if (!(session->transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) ||
+ !session->transport->options.use_spnego) {
+ return smb_raw_session_setup_generic_nt1(session, mem_ctx, parms);
+ }
+
+ /* default to using SPNEGO/NTLMSSP */
+ DEBUG(0,("Need to add client SPNEGO code back in\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+
+/****************************************************************************
+ Perform a session setup (sync interface)
+this interface allows for RAW_SESSSETUP_GENERIC to auto-select session
+setup varient based on negotiated protocol options
+****************************************************************************/
+NTSTATUS smb_raw_session_setup(struct cli_session *session, TALLOC_CTX *mem_ctx,
+ union smb_sesssetup *parms)
+{
+ struct cli_request *req;
+
+ if (parms->generic.level == RAW_SESSSETUP_GENERIC) {
+ return smb_raw_session_setup_generic(session, mem_ctx, parms);
+ }
+
+ req = smb_raw_session_setup_send(session, parms);
+ return smb_raw_session_setup_recv(req, mem_ctx, parms);
+}
+
+
+/****************************************************************************
+ Send a uloggoff (async send)
+*****************************************************************************/
+struct cli_request *smb_raw_ulogoff_send(struct cli_session *session)
+{
+ struct cli_request *req;
+
+ SETUP_REQUEST_SESSION(SMBulogoffX, 2, 0);
+
+ SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
+ SSVAL(req->out.vwv, VWV(1), 0);
+
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+/****************************************************************************
+ Send a uloggoff (sync interface)
+*****************************************************************************/
+NTSTATUS smb_raw_ulogoff(struct cli_session *session)
+{
+ struct cli_request *req = smb_raw_ulogoff_send(session);
+ return cli_request_simple_recv(req);
+}
+
+
+/****************************************************************************
+ Send a SMBexit
+****************************************************************************/
+NTSTATUS smb_raw_exit(struct cli_session *session)
+{
+ struct cli_request *req;
+
+ req = cli_request_setup_session(session, SMBexit, 0, 0);
+
+ if (cli_request_send(req)) {
+ cli_request_receive(req);
+ }
+ return cli_request_destroy(req);
+}
diff --git a/source4/libcli/raw/clisocket.c b/source4/libcli/raw/clisocket.c
new file mode 100644
index 0000000000..f0e05085c4
--- /dev/null
+++ b/source4/libcli/raw/clisocket.c
@@ -0,0 +1,148 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB client socket context management functions
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) James Myers 2003 <myersjj@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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+
+/*
+ create a cli_socket context
+*/
+struct cli_socket *cli_sock_init(void)
+{
+ struct cli_socket *sock;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("cli_socket");
+ if (!mem_ctx) return NULL;
+
+ sock = talloc_zero(mem_ctx, sizeof(*sock));
+ if (!sock) {
+ talloc_destroy(mem_ctx);
+ return NULL;
+ }
+
+ sock->mem_ctx = mem_ctx;
+ sock->fd = -1;
+ sock->port = 445;
+ /* 20 second default timeout */
+ sock->timeout = 20000;
+
+ return sock;
+}
+
+/*
+ connect a cli_socket context to an IP/port pair
+ if port is 0 then choose 445 then 139
+*/
+BOOL cli_sock_connect(struct cli_socket *sock, struct in_addr *ip, int port)
+{
+ if (getenv("LIBSMB_PROG")) {
+ sock->fd = sock_exec(getenv("LIBSMB_PROG"));
+ return sock->fd != -1;
+ }
+
+ if (port == 0) {
+ return cli_sock_connect(sock, ip, 445) ||
+ cli_sock_connect(sock, ip, 139);
+ }
+
+ sock->dest_ip = *ip;
+ sock->port = port;
+ sock->fd = open_socket_out(SOCK_STREAM,
+ &sock->dest_ip,
+ sock->port,
+ LONG_CONNECT_TIMEOUT);
+ return (sock->fd != -1);
+}
+
+
+/****************************************************************************
+ reduce socket reference count - if it becomes zero then close
+****************************************************************************/
+void cli_sock_close(struct cli_socket *sock)
+{
+ sock->reference_count--;
+ if (sock->reference_count <= 0 && sock->fd != -1) {
+ close(sock->fd);
+ sock->fd = -1;
+ }
+}
+
+/****************************************************************************
+ Set socket options on a open connection.
+****************************************************************************/
+void cli_sock_set_options(struct cli_socket *sock, const char *options)
+{
+ set_socket_options(sock->fd, options);
+}
+
+/****************************************************************************
+ Write to socket. Return amount written.
+****************************************************************************/
+ssize_t cli_sock_write(struct cli_socket *sock, const char *data, size_t len)
+{
+ return write_data(sock->fd, data, len);
+}
+
+
+/****************************************************************************
+ Read from socket. return amount read
+****************************************************************************/
+ssize_t cli_sock_read(struct cli_socket *sock, char *data, size_t len)
+{
+ return read_data(sock->fd, data, len);
+}
+
+/****************************************************************************
+resolve a hostname and connect
+****************************************************************************/
+BOOL cli_sock_connect_byname(struct cli_socket *sock, const char *host, int port)
+{
+ int name_type = 0x20;
+ struct in_addr ip;
+ TALLOC_CTX *mem_ctx;
+ char *name, *p;
+
+ if (getenv("LIBSMB_PROG")) {
+ sock->fd = sock_exec(getenv("LIBSMB_PROG"));
+ return sock->fd != -1;
+ }
+
+ mem_ctx = talloc_init("cli_sock_connect_byname");
+ if (!mem_ctx) return False;
+
+ name = talloc_strdup(mem_ctx, host);
+
+ /* allow hostnames of the form NAME#xx and do a netbios lookup */
+ if ((p = strchr(name, '#'))) {
+ name_type = strtol(p+1, NULL, 16);
+ *p = 0;
+ }
+
+ if (!resolve_name(mem_ctx, name, &ip, name_type)) {
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+
+ talloc_destroy(mem_ctx);
+
+ return cli_sock_connect(sock, &ip, port);
+}
diff --git a/source4/libcli/raw/clispnego.c b/source4/libcli/raw/clispnego.c
new file mode 100644
index 0000000000..53f7eb6e7d
--- /dev/null
+++ b/source4/libcli/raw/clispnego.c
@@ -0,0 +1,533 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple kerberos5/SPNEGO routines
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Jim McDonough 2002
+ Copyright (C) Luke Howard 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ generate a negTokenInit packet given a GUID, a list of supported
+ OIDs (the mechanisms) and a principal name string
+*/
+DATA_BLOB spnego_gen_negTokenInit(uint8 guid[16],
+ const char *OIDs[],
+ const char *principal)
+{
+ int i;
+ ASN1_DATA data;
+ DATA_BLOB ret;
+
+ memset(&data, 0, sizeof(data));
+
+ asn1_write(&data, guid, 16);
+ asn1_push_tag(&data,ASN1_APPLICATION(0));
+ asn1_write_OID(&data,OID_SPNEGO);
+ asn1_push_tag(&data,ASN1_CONTEXT(0));
+ asn1_push_tag(&data,ASN1_SEQUENCE(0));
+
+ asn1_push_tag(&data,ASN1_CONTEXT(0));
+ asn1_push_tag(&data,ASN1_SEQUENCE(0));
+ for (i=0; OIDs[i]; i++) {
+ asn1_write_OID(&data,OIDs[i]);
+ }
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data, ASN1_CONTEXT(3));
+ asn1_push_tag(&data, ASN1_SEQUENCE(0));
+ asn1_push_tag(&data, ASN1_CONTEXT(0));
+ asn1_write_GeneralString(&data,principal);
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ asn1_pop_tag(&data);
+
+ if (data.has_error) {
+ DEBUG(1,("Failed to build negTokenInit at offset %d\n", (int)data.ofs));
+ asn1_free(&data);
+ }
+
+ ret = data_blob(data.data, data.length);
+ asn1_free(&data);
+
+ return ret;
+}
+
+/*
+ Generate a negTokenInit as used by the client side ... It has a mechType
+ (OID), and a mechToken (a security blob) ...
+
+ Really, we need to break out the NTLMSSP stuff as well, because it could be
+ raw in the packets!
+*/
+DATA_BLOB gen_negTokenInit(const char *OID, DATA_BLOB blob)
+{
+ ASN1_DATA data;
+ DATA_BLOB ret;
+
+ memset(&data, 0, sizeof(data));
+
+ asn1_push_tag(&data, ASN1_APPLICATION(0));
+ asn1_write_OID(&data,OID_SPNEGO);
+ asn1_push_tag(&data, ASN1_CONTEXT(0));
+ asn1_push_tag(&data, ASN1_SEQUENCE(0));
+
+ asn1_push_tag(&data, ASN1_CONTEXT(0));
+ asn1_push_tag(&data, ASN1_SEQUENCE(0));
+ asn1_write_OID(&data, OID);
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data, ASN1_CONTEXT(2));
+ asn1_write_OctetString(&data,blob.data,blob.length);
+ asn1_pop_tag(&data);
+
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ asn1_pop_tag(&data);
+
+ if (data.has_error) {
+ DEBUG(1,("Failed to build negTokenInit at offset %d\n", (int)data.ofs));
+ asn1_free(&data);
+ }
+
+ ret = data_blob(data.data, data.length);
+ asn1_free(&data);
+
+ return ret;
+}
+
+/*
+ parse a negTokenInit packet giving a GUID, a list of supported
+ OIDs (the mechanisms) and a principal name string
+*/
+BOOL spnego_parse_negTokenInit(DATA_BLOB blob,
+ char *OIDs[ASN1_MAX_OIDS],
+ char **principal)
+{
+ int i;
+ BOOL ret;
+ ASN1_DATA data;
+
+ asn1_load(&data, blob);
+
+ asn1_start_tag(&data,ASN1_APPLICATION(0));
+ asn1_check_OID(&data,OID_SPNEGO);
+ asn1_start_tag(&data,ASN1_CONTEXT(0));
+ asn1_start_tag(&data,ASN1_SEQUENCE(0));
+
+ asn1_start_tag(&data,ASN1_CONTEXT(0));
+ asn1_start_tag(&data,ASN1_SEQUENCE(0));
+ for (i=0; asn1_tag_remaining(&data) > 0 && i < ASN1_MAX_OIDS; i++) {
+ char *oid = NULL;
+ asn1_read_OID(&data,&oid);
+ OIDs[i] = oid;
+ }
+ OIDs[i] = NULL;
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ asn1_start_tag(&data, ASN1_CONTEXT(3));
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_start_tag(&data, ASN1_CONTEXT(0));
+ asn1_read_GeneralString(&data,principal);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ asn1_end_tag(&data);
+
+ ret = !data.has_error;
+ asn1_free(&data);
+ return ret;
+}
+
+
+/*
+ generate a negTokenTarg packet given a list of OIDs and a security blob
+*/
+DATA_BLOB gen_negTokenTarg(const char *OIDs[], DATA_BLOB blob)
+{
+ int i;
+ ASN1_DATA data;
+ DATA_BLOB ret;
+
+ memset(&data, 0, sizeof(data));
+
+ asn1_push_tag(&data, ASN1_APPLICATION(0));
+ asn1_write_OID(&data,OID_SPNEGO);
+ asn1_push_tag(&data, ASN1_CONTEXT(0));
+ asn1_push_tag(&data, ASN1_SEQUENCE(0));
+
+ asn1_push_tag(&data, ASN1_CONTEXT(0));
+ asn1_push_tag(&data, ASN1_SEQUENCE(0));
+ for (i=0; OIDs[i]; i++) {
+ asn1_write_OID(&data,OIDs[i]);
+ }
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data, ASN1_CONTEXT(2));
+ asn1_write_OctetString(&data,blob.data,blob.length);
+ asn1_pop_tag(&data);
+
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ asn1_pop_tag(&data);
+
+ if (data.has_error) {
+ DEBUG(1,("Failed to build negTokenTarg at offset %d\n", (int)data.ofs));
+ asn1_free(&data);
+ }
+
+ ret = data_blob(data.data, data.length);
+ asn1_free(&data);
+
+ return ret;
+}
+
+
+/*
+ parse a negTokenTarg packet giving a list of OIDs and a security blob
+*/
+BOOL parse_negTokenTarg(DATA_BLOB blob, char *OIDs[ASN1_MAX_OIDS], DATA_BLOB *secblob)
+{
+ int i;
+ ASN1_DATA data;
+
+ asn1_load(&data, blob);
+ asn1_start_tag(&data, ASN1_APPLICATION(0));
+ asn1_check_OID(&data,OID_SPNEGO);
+ asn1_start_tag(&data, ASN1_CONTEXT(0));
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+
+ asn1_start_tag(&data, ASN1_CONTEXT(0));
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ for (i=0; asn1_tag_remaining(&data) > 0 && i < ASN1_MAX_OIDS; i++) {
+ char *oid = NULL;
+ asn1_read_OID(&data,&oid);
+ OIDs[i] = oid;
+ }
+ OIDs[i] = NULL;
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ asn1_start_tag(&data, ASN1_CONTEXT(2));
+ asn1_read_OctetString(&data,secblob);
+ asn1_end_tag(&data);
+
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ asn1_end_tag(&data);
+
+ if (data.has_error) {
+ DEBUG(1,("Failed to parse negTokenTarg at offset %d\n", (int)data.ofs));
+ asn1_free(&data);
+ return False;
+ }
+
+ asn1_free(&data);
+ return True;
+}
+
+/*
+ generate a krb5 GSS-API wrapper packet given a ticket
+*/
+DATA_BLOB spnego_gen_krb5_wrap(DATA_BLOB ticket, const uint8 tok_id[2])
+{
+ ASN1_DATA data;
+ DATA_BLOB ret;
+
+ memset(&data, 0, sizeof(data));
+
+ asn1_push_tag(&data, ASN1_APPLICATION(0));
+ asn1_write_OID(&data, OID_KERBEROS5);
+
+ asn1_write(&data, tok_id, 2);
+ asn1_write(&data, ticket.data, ticket.length);
+ asn1_pop_tag(&data);
+
+ if (data.has_error) {
+ DEBUG(1,("Failed to build krb5 wrapper at offset %d\n", (int)data.ofs));
+ asn1_free(&data);
+ }
+
+ ret = data_blob(data.data, data.length);
+ asn1_free(&data);
+
+ return ret;
+}
+
+/*
+ parse a krb5 GSS-API wrapper packet giving a ticket
+*/
+BOOL spnego_parse_krb5_wrap(DATA_BLOB blob, DATA_BLOB *ticket, uint8 tok_id[2])
+{
+ BOOL ret;
+ ASN1_DATA data;
+ int data_remaining;
+
+ asn1_load(&data, blob);
+ asn1_start_tag(&data, ASN1_APPLICATION(0));
+ asn1_check_OID(&data, OID_KERBEROS5);
+
+ data_remaining = asn1_tag_remaining(&data);
+
+ if (data_remaining < 3) {
+ data.has_error = True;
+ } else {
+ asn1_read(&data, tok_id, 2);
+ data_remaining -= 2;
+ *ticket = data_blob(NULL, data_remaining);
+ asn1_read(&data, ticket->data, ticket->length);
+ }
+
+ asn1_end_tag(&data);
+
+ ret = !data.has_error;
+
+ asn1_free(&data);
+
+ return ret;
+}
+
+
+/*
+ generate a SPNEGO negTokenTarg packet, ready for a EXTENDED_SECURITY
+ kerberos session setup
+*/
+DATA_BLOB spnego_gen_negTokenTarg(const char *principal, int time_offset)
+{
+ DATA_BLOB tkt, tkt_wrapped, targ;
+ const char *krb_mechs[] = {OID_KERBEROS5_OLD, OID_NTLMSSP, NULL};
+
+ /* get a kerberos ticket for the service */
+ tkt = krb5_get_ticket(principal, time_offset);
+
+ /* wrap that up in a nice GSS-API wrapping */
+ tkt_wrapped = spnego_gen_krb5_wrap(tkt, TOK_ID_KRB_AP_REQ);
+
+ /* and wrap that in a shiny SPNEGO wrapper */
+ targ = gen_negTokenTarg(krb_mechs, tkt_wrapped);
+
+ data_blob_free(&tkt_wrapped);
+ data_blob_free(&tkt);
+
+ return targ;
+}
+
+
+/*
+ parse a spnego NTLMSSP challenge packet giving two security blobs
+*/
+BOOL spnego_parse_challenge(const DATA_BLOB blob,
+ DATA_BLOB *chal1, DATA_BLOB *chal2)
+{
+ BOOL ret;
+ ASN1_DATA data;
+
+ ZERO_STRUCTP(chal1);
+ ZERO_STRUCTP(chal2);
+
+ asn1_load(&data, blob);
+ asn1_start_tag(&data,ASN1_CONTEXT(1));
+ asn1_start_tag(&data,ASN1_SEQUENCE(0));
+
+ asn1_start_tag(&data,ASN1_CONTEXT(0));
+ asn1_check_enumerated(&data,1);
+ asn1_end_tag(&data);
+
+ asn1_start_tag(&data,ASN1_CONTEXT(1));
+ asn1_check_OID(&data, OID_NTLMSSP);
+ asn1_end_tag(&data);
+
+ asn1_start_tag(&data,ASN1_CONTEXT(2));
+ asn1_read_OctetString(&data, chal1);
+ asn1_end_tag(&data);
+
+ /* the second challenge is optional (XP doesn't send it) */
+ if (asn1_tag_remaining(&data)) {
+ asn1_start_tag(&data,ASN1_CONTEXT(3));
+ asn1_read_OctetString(&data, chal2);
+ asn1_end_tag(&data);
+ }
+
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ ret = !data.has_error;
+ asn1_free(&data);
+ return ret;
+}
+
+
+/*
+ generate a SPNEGO auth packet. This will contain the encrypted passwords
+*/
+DATA_BLOB spnego_gen_auth(DATA_BLOB blob)
+{
+ ASN1_DATA data;
+ DATA_BLOB ret;
+
+ memset(&data, 0, sizeof(data));
+
+ asn1_push_tag(&data, ASN1_CONTEXT(1));
+ asn1_push_tag(&data, ASN1_SEQUENCE(0));
+ asn1_push_tag(&data, ASN1_CONTEXT(2));
+ asn1_write_OctetString(&data,blob.data,blob.length);
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ ret = data_blob(data.data, data.length);
+
+ asn1_free(&data);
+
+ return ret;
+}
+
+/*
+ parse a SPNEGO auth packet. This contains the encrypted passwords
+*/
+BOOL spnego_parse_auth(DATA_BLOB blob, DATA_BLOB *auth)
+{
+ ASN1_DATA data;
+
+ asn1_load(&data, blob);
+ asn1_start_tag(&data, ASN1_CONTEXT(1));
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_start_tag(&data, ASN1_CONTEXT(2));
+ asn1_read_OctetString(&data,auth);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ if (data.has_error) {
+ DEBUG(3,("spnego_parse_auth failed at %d\n", (int)data.ofs));
+ asn1_free(&data);
+ return False;
+ }
+
+ asn1_free(&data);
+ return True;
+}
+
+/*
+ generate a minimal SPNEGO response packet. Doesn't contain much.
+*/
+DATA_BLOB spnego_gen_auth_response(DATA_BLOB *reply, NTSTATUS nt_status,
+ const char *mechOID)
+{
+ ASN1_DATA data;
+ DATA_BLOB ret;
+ uint8 negResult;
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ negResult = SPNEGO_NEG_RESULT_ACCEPT;
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ negResult = SPNEGO_NEG_RESULT_INCOMPLETE;
+ } else {
+ negResult = SPNEGO_NEG_RESULT_REJECT;
+ }
+
+ ZERO_STRUCT(data);
+
+ asn1_push_tag(&data, ASN1_CONTEXT(1));
+ asn1_push_tag(&data, ASN1_SEQUENCE(0));
+ asn1_push_tag(&data, ASN1_CONTEXT(0));
+ asn1_write_enumerated(&data, negResult);
+ asn1_pop_tag(&data);
+
+ if (reply->data != NULL) {
+ asn1_push_tag(&data,ASN1_CONTEXT(1));
+ asn1_write_OID(&data, mechOID);
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data,ASN1_CONTEXT(2));
+ asn1_write_OctetString(&data, reply->data, reply->length);
+ asn1_pop_tag(&data);
+ }
+
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ ret = data_blob(data.data, data.length);
+ asn1_free(&data);
+ return ret;
+}
+
+/*
+ parse a SPNEGO NTLMSSP auth packet. This contains the encrypted passwords
+*/
+BOOL spnego_parse_auth_response(DATA_BLOB blob, NTSTATUS nt_status,
+ DATA_BLOB *auth)
+{
+ ASN1_DATA data;
+ uint8 negResult;
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ negResult = SPNEGO_NEG_RESULT_ACCEPT;
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ negResult = SPNEGO_NEG_RESULT_INCOMPLETE;
+ } else {
+ negResult = SPNEGO_NEG_RESULT_REJECT;
+ }
+
+ asn1_load(&data, blob);
+ asn1_start_tag(&data, ASN1_CONTEXT(1));
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_start_tag(&data, ASN1_CONTEXT(0));
+ asn1_check_enumerated(&data, negResult);
+ asn1_end_tag(&data);
+
+ if (negResult == SPNEGO_NEG_RESULT_INCOMPLETE) {
+ asn1_start_tag(&data,ASN1_CONTEXT(1));
+ asn1_check_OID(&data, OID_NTLMSSP);
+ asn1_end_tag(&data);
+
+ asn1_start_tag(&data,ASN1_CONTEXT(2));
+ asn1_read_OctetString(&data, auth);
+ asn1_end_tag(&data);
+ }
+
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+
+ if (data.has_error) {
+ DEBUG(3,("spnego_parse_auth_response failed at %d\n", (int)data.ofs));
+ asn1_free(&data);
+ data_blob_free(auth);
+ return False;
+ }
+
+ asn1_free(&data);
+ return True;
+}
+
diff --git a/source4/libcli/raw/clitransport.c b/source4/libcli/raw/clitransport.c
new file mode 100644
index 0000000000..80bb1e301f
--- /dev/null
+++ b/source4/libcli/raw/clitransport.c
@@ -0,0 +1,218 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB client transport context management functions
+ Copyright (C) Andrew Tridgell 1994-2003
+ Copyright (C) James Myers 2003 <myersjj@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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ create a transport structure based on an established socket
+*/
+struct cli_transport *cli_transport_init(struct cli_socket *sock)
+{
+ TALLOC_CTX *mem_ctx;
+ struct cli_transport *transport;
+
+ mem_ctx = talloc_init("cli_transport");
+ if (!mem_ctx) return NULL;
+
+ transport = talloc_zero(mem_ctx, sizeof(*transport));
+ if (!transport) return NULL;
+
+ transport->mem_ctx = mem_ctx;
+ transport->socket = sock;
+ transport->negotiate.protocol = PROTOCOL_NT1;
+ transport->negotiate.max_xmit = ~0;
+ cli_null_set_signing(transport);
+ transport->socket->reference_count++;
+
+ return transport;
+}
+
+/*
+ decrease reference count on a transport, and destroy if it becomes
+ zero
+*/
+void cli_transport_close(struct cli_transport *transport)
+{
+ transport->reference_count--;
+ if (transport->reference_count <= 0) {
+ cli_sock_close(transport->socket);
+ talloc_destroy(transport->mem_ctx);
+ }
+}
+
+
+
+/****************************************************************************
+send a session request (if appropriate)
+****************************************************************************/
+BOOL cli_transport_connect(struct cli_transport *transport,
+ struct nmb_name *calling,
+ struct nmb_name *called)
+{
+ char *p;
+ int len = NBT_HDR_SIZE;
+ struct cli_request *req;
+
+ /* 445 doesn't have session request */
+ if (transport->socket->port == 445) {
+ return True;
+ }
+
+ /* allocate output buffer */
+ req = cli_request_setup_nonsmb(transport, NBT_HDR_SIZE + 2*nbt_mangled_name_len());
+
+ /* put in the destination name */
+ p = req->out.buffer + NBT_HDR_SIZE;
+ name_mangle(called->name, p, called->name_type);
+ len += name_len(p);
+
+ /* and my name */
+ p = req->out.buffer+len;
+ name_mangle(calling->name, p, calling->name_type);
+ len += name_len(p);
+
+ _smb_setlen(req->out.buffer,len-4);
+ SCVAL(req->out.buffer,0,0x81);
+
+ if (!cli_request_send(req) ||
+ !cli_request_receive(req)) {
+ cli_request_destroy(req);
+ return False;
+ }
+
+ if (CVAL(req->in.buffer,0) != 0x82) {
+ transport->error.etype = ETYPE_NBT;
+ transport->error.e.nbt_error = CVAL(req->in.buffer,4);
+ cli_request_destroy(req);
+ return False;
+ }
+
+ cli_request_destroy(req);
+ return True;
+}
+
+
+/****************************************************************************
+get next mid in sequence
+****************************************************************************/
+uint16 cli_transport_next_mid(struct cli_transport *transport)
+{
+ uint16 mid;
+ struct cli_request *req;
+
+ mid = transport->next_mid;
+
+again:
+ /* now check to see if this mid is being used by one of the
+ pending requests. This is quite efficient because the list is
+ usually very short */
+
+ /* the zero mid is reserved for requests that don't have a mid */
+ if (mid == 0) mid = 1;
+
+ for (req=transport->pending_requests; req; req=req->next) {
+ if (req->mid == mid) {
+ mid++;
+ goto again;
+ }
+ }
+
+ transport->next_mid = mid+1;
+ return mid;
+}
+
+/*
+ setup the idle handler for a transport
+*/
+void cli_transport_idle_handler(struct cli_transport *transport,
+ void (*idle_func)(struct cli_transport *, void *),
+ uint_t period,
+ void *private)
+{
+ transport->idle.func = idle_func;
+ transport->idle.private = private;
+ transport->idle.period = period;
+}
+
+
+/*
+ determine if a packet is pending for receive on a transport
+*/
+BOOL cli_transport_pending(struct cli_transport *transport)
+{
+ return socket_pending(transport->socket->fd);
+}
+
+
+
+/*
+ wait for data on a transport, periodically calling a wait function
+ if one has been defined
+ return True if a packet is received
+*/
+BOOL cli_transport_select(struct cli_transport *transport)
+{
+ fd_set fds;
+ int selrtn;
+ int fd;
+ struct timeval timeout;
+
+ fd = transport->socket->fd;
+
+ if (fd == -1) {
+ return False;
+ }
+
+ do {
+ uint_t period = 1000;
+
+ FD_ZERO(&fds);
+ FD_SET(fd,&fds);
+
+ if (transport->idle.func) {
+ period = transport->idle.period;
+ }
+
+ timeout.tv_sec = period / 1000;
+ timeout.tv_usec = 1000*(period%1000);
+
+ selrtn = sys_select_intr(fd+1,&fds,NULL,NULL,&timeout);
+
+ if (selrtn == 1) {
+ /* the fd is readable */
+ return True;
+ }
+
+ if (selrtn == -1) {
+ /* sys_select_intr() already handles EINTR, so this
+ is an error. The socket is probably dead */
+ return False;
+ }
+
+ /* only other possibility is that we timed out - call the idle function
+ if there is one */
+ if (transport->idle.func) {
+ transport->idle.func(transport, transport->idle.private);
+ }
+ } while (selrtn == 0);
+
+ return True;
+}
diff --git a/source4/libcli/raw/clitree.c b/source4/libcli/raw/clitree.c
new file mode 100644
index 0000000000..2a41273913
--- /dev/null
+++ b/source4/libcli/raw/clitree.c
@@ -0,0 +1,290 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB client tree context management functions
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) James Myers 2003 <myersjj@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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#define SETUP_REQUEST_TREE(cmd, wct, buflen) do { \
+ req = cli_request_setup(tree, cmd, wct, buflen); \
+ if (!req) return NULL; \
+} while (0)
+
+
+/****************************************************************************
+ Initialize the tree context
+****************************************************************************/
+struct cli_tree *cli_tree_init(struct cli_session *session)
+{
+ struct cli_tree *tree;
+ TALLOC_CTX *mem_ctx = talloc_init("cli_tree");
+ if (mem_ctx == NULL) {
+ return NULL;
+ }
+
+ tree = talloc_zero(mem_ctx, sizeof(*tree));
+ if (!tree) {
+ talloc_destroy(mem_ctx);
+ return NULL;
+ }
+
+ tree->mem_ctx = mem_ctx;
+ tree->session = session;
+ tree->session->reference_count++;
+
+ return tree;
+}
+
+/****************************************************************************
+reduce reference count on a tree and destroy if <= 0
+****************************************************************************/
+void cli_tree_close(struct cli_tree *tree)
+{
+ if (!tree) return;
+ tree->reference_count--;
+ if (tree->reference_count <= 0) {
+ cli_session_close(tree->session);
+ talloc_destroy(tree->mem_ctx);
+ }
+}
+
+
+/****************************************************************************
+ Send a tconX (async send)
+****************************************************************************/
+struct cli_request *smb_tree_connect_send(struct cli_tree *tree, union smb_tcon *parms)
+{
+ struct cli_request *req;
+
+ switch (parms->tcon.level) {
+ case RAW_TCON_TCON:
+ SETUP_REQUEST_TREE(SMBtcon, 0, 0);
+ cli_req_append_ascii4(req, parms->tcon.in.service, STR_ASCII);
+ cli_req_append_ascii4(req, parms->tcon.in.password,STR_ASCII);
+ cli_req_append_ascii4(req, parms->tcon.in.dev, STR_ASCII);
+ break;
+
+ case RAW_TCON_TCONX:
+ SETUP_REQUEST_TREE(SMBtconX, 4, 0);
+ SSVAL(req->out.vwv, VWV(0), 0xFF);
+ SSVAL(req->out.vwv, VWV(1), 0);
+ SSVAL(req->out.vwv, VWV(2), parms->tconx.in.flags);
+ SSVAL(req->out.vwv, VWV(3), parms->tconx.in.password.length);
+ cli_req_append_blob(req, &parms->tconx.in.password);
+ cli_req_append_string(req, parms->tconx.in.path, STR_TERMINATE | STR_UPPER);
+ cli_req_append_string(req, parms->tconx.in.device, STR_TERMINATE | STR_ASCII);
+ break;
+ }
+
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+/****************************************************************************
+ Send a tconX (async recv)
+****************************************************************************/
+NTSTATUS smb_tree_connect_recv(struct cli_request *req, TALLOC_CTX *mem_ctx, union smb_tcon *parms)
+{
+ char *p;
+
+ if (!cli_request_receive(req) ||
+ cli_request_is_error(req)) {
+ goto failed;
+ }
+
+ switch (parms->tcon.level) {
+ case RAW_TCON_TCON:
+ CLI_CHECK_WCT(req, 2);
+ parms->tcon.out.max_xmit = SVAL(req->in.vwv, VWV(0));
+ parms->tcon.out.cnum = SVAL(req->in.vwv, VWV(1));
+ break;
+
+ case RAW_TCON_TCONX:
+ ZERO_STRUCT(parms->tconx.out);
+ CLI_CHECK_MIN_WCT(req, 0); /* this depends on the protocol level */
+ parms->tconx.out.cnum = SVAL(req->in.hdr, HDR_TID);
+ if (req->in.wct >= 4) {
+ parms->tconx.out.options = SVAL(req->in.vwv, VWV(3));
+ }
+
+ /* output is actual service name */
+ p = req->in.data;
+ if (!p) break;
+
+ p += cli_req_pull_string(req, mem_ctx, &parms->tconx.out.dev_type,
+ p, -1, STR_ASCII | STR_TERMINATE);
+ p += cli_req_pull_string(req, mem_ctx, &parms->tconx.out.fs_type,
+ p, -1, STR_TERMINATE);
+ break;
+ }
+
+failed:
+ return cli_request_destroy(req);
+}
+
+/****************************************************************************
+ Send a tconX (sync interface)
+****************************************************************************/
+NTSTATUS smb_tree_connect(struct cli_tree *tree, TALLOC_CTX *mem_ctx, union smb_tcon *parms)
+{
+ struct cli_request *req = smb_tree_connect_send(tree, parms);
+ return smb_tree_connect_recv(req, mem_ctx, parms);
+}
+
+
+/****************************************************************************
+ Send a tree disconnect.
+****************************************************************************/
+NTSTATUS smb_tree_disconnect(struct cli_tree *tree)
+{
+ struct cli_request *req;
+
+ if (!tree) return NT_STATUS_OK;
+ req = cli_request_setup(tree, SMBtdis, 0, 0);
+
+ if (cli_request_send(req)) {
+ cli_request_receive(req);
+ }
+ return cli_request_destroy(req);
+}
+
+
+/*
+ a convenient function to establish a cli_tree from scratch, using reasonable default
+ parameters
+*/
+NTSTATUS cli_tree_full_connection(struct cli_tree **ret_tree,
+ const char *my_name,
+ const char *dest_host, int port,
+ const char *service, const char *service_type,
+ const char *user, const char *domain,
+ const char *password)
+{
+ struct cli_socket *sock;
+ struct cli_transport *transport;
+ struct cli_session *session;
+ struct cli_tree *tree;
+ NTSTATUS status;
+ struct nmb_name calling;
+ struct nmb_name called;
+ union smb_sesssetup setup;
+ union smb_tcon tcon;
+ TALLOC_CTX *mem_ctx;
+
+ *ret_tree = NULL;
+
+ sock = cli_sock_init();
+ if (!sock) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* open a TCP socket to the server */
+ if (!cli_sock_connect_byname(sock, dest_host, port)) {
+ DEBUG(2,("Failed to establish socket connection - %s\n", strerror(errno)));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ transport = cli_transport_init(sock);
+ if (!transport) {
+ cli_sock_close(sock);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* send a NBT session request, if applicable */
+ make_nmb_name(&calling, my_name, 0x0);
+ make_nmb_name(&called, dest_host, 0x20);
+
+ if (!cli_transport_connect(transport, &calling, &called)) {
+ cli_transport_close(transport);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+
+ /* negotiate protocol options with the server */
+ status = smb_raw_negotiate(transport);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_transport_close(transport);
+ return status;
+ }
+
+ session = cli_session_init(transport);
+ if (!session) {
+ cli_transport_close(transport);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* prepare a session setup to establish a security context */
+ setup.generic.level = RAW_SESSSETUP_GENERIC;
+ setup.generic.in.sesskey = transport->negotiate.sesskey;
+ setup.generic.in.capabilities = CAP_UNICODE | CAP_STATUS32 |
+ CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
+ CAP_W2K_SMBS | CAP_LARGE_READX | CAP_LARGE_WRITEX;
+ setup.generic.in.password = password;
+ setup.generic.in.user = user;
+ setup.generic.in.domain = domain;
+
+ mem_ctx = talloc_init("tcon");
+ if (!mem_ctx) {
+ cli_tree_close(tree);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = smb_raw_session_setup(session, mem_ctx, &setup);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_session_close(session);
+ talloc_destroy(mem_ctx);
+ return status;
+ }
+
+ session->vuid = setup.generic.out.vuid;
+
+ tree = cli_tree_init(session);
+ if (!tree) {
+ cli_session_close(session);
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* connect to a share using a tree connect */
+ tcon.generic.level = RAW_TCON_TCONX;
+ tcon.tconx.in.flags = 0;
+ tcon.tconx.in.password = data_blob(NULL, 0);
+ tcon.tconx.in.path = service;
+ tcon.tconx.in.device = service_type;
+
+ status = smb_tree_connect(tree, mem_ctx, &tcon);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_tree_close(tree);
+ talloc_destroy(mem_ctx);
+ return status;
+ }
+
+ tree->tid = tcon.tconx.out.cnum;
+ tree->device = talloc_strdup(tree->mem_ctx, tcon.tconx.out.dev_type);
+ tree->fs_type = talloc_strdup(tree->mem_ctx, tcon.tconx.out.fs_type);
+
+ talloc_destroy(mem_ctx);
+
+ *ret_tree = tree;
+ return NT_STATUS_OK;
+}
diff --git a/source4/libcli/raw/raweas.c b/source4/libcli/raw/raweas.c
new file mode 100644
index 0000000000..ce0368c304
--- /dev/null
+++ b/source4/libcli/raw/raweas.c
@@ -0,0 +1,147 @@
+/*
+ Unix SMB/CIFS implementation.
+ parsing of EA (extended attribute) lists
+ Copyright (C) Andrew Tridgell 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ work out how many bytes on the wire a ea list will consume.
+ This assumes the names are strict ascii, which should be a
+ reasonable assumption
+*/
+uint_t ea_list_size(uint_t num_eas, struct ea_struct *eas)
+{
+ uint_t total = 4;
+ int i;
+ for (i=0;i<num_eas;i++) {
+ total += 4 + strlen(eas[i].name.s)+1 + eas[i].value.length;
+ }
+ return total;
+}
+
+/*
+ put a ea_list into a pre-allocated buffer - buffer must be at least
+ of size ea_list_size()
+*/
+void ea_put_list(char *data, uint_t num_eas, struct ea_struct *eas)
+{
+ int i;
+ uint32 ea_size;
+
+ ea_size = ea_list_size(num_eas, eas);
+
+ SIVAL(data, 0, ea_size);
+ data += 4;
+
+ for (i=0;i<num_eas;i++) {
+ uint_t nlen = strlen(eas[i].name.s);
+ SCVAL(data, 0, eas[i].flags);
+ SCVAL(data, 1, nlen);
+ SSVAL(data, 2, eas[i].value.length);
+ memcpy(data+4, eas[i].name.s, nlen+1);
+ memcpy(data+4+nlen+1, eas[i].value.data, eas[i].value.length);
+ data += 4+nlen+1+eas[i].value.length;
+ }
+}
+
+
+/*
+ pull a ea_struct from a buffer. Return the number of bytes consumed
+*/
+uint_t ea_pull_struct(const DATA_BLOB *blob,
+ TALLOC_CTX *mem_ctx,
+ struct ea_struct *ea)
+{
+ uint8 nlen;
+ uint16 vlen;
+
+ if (blob->length < 6) {
+ return 0;
+ }
+
+ ea->flags = CVAL(blob->data, 0);
+ nlen = CVAL(blob->data, 1);
+ vlen = SVAL(blob->data, 2);
+
+ if (nlen+1+vlen > blob->length-4) {
+ return 0;
+ }
+
+ ea->name.s = talloc_strndup(mem_ctx, blob->data+4, nlen);
+ ea->name.private_length = nlen;
+ ea->value = data_blob_talloc(mem_ctx, NULL, vlen+1);
+ if (!ea->value.data) return 0;
+ if (vlen) {
+ memcpy(ea->value.data, blob->data+4+nlen+1, vlen);
+ }
+ ea->value.data[vlen] = 0;
+ ea->value.length--;
+
+ return 4 + nlen+1 + vlen;
+}
+
+
+/*
+ pull a ea_list from a buffer
+*/
+NTSTATUS ea_pull_list(const DATA_BLOB *blob,
+ TALLOC_CTX *mem_ctx,
+ uint_t *num_eas, struct ea_struct **eas)
+{
+ int n;
+ uint32 ea_size, ofs;
+
+ if (blob->length < 4) {
+ return NT_STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ ea_size = IVAL(blob->data, 0);
+ if (ea_size > blob->length) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ofs = 4;
+ n = 0;
+ *num_eas = 0;
+ *eas = NULL;
+
+ while (ofs < ea_size) {
+ uint_t len;
+ DATA_BLOB blob2;
+
+ blob2.data = blob->data + ofs;
+ blob2.length = ea_size - ofs;
+
+ *eas = talloc_realloc(mem_ctx, *eas, sizeof(**eas) * (n+1));
+ if (! *eas) return NT_STATUS_NO_MEMORY;
+
+ len = ea_pull_struct(&blob2, mem_ctx, &(*eas)[n]);
+ if (len == 0) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ofs += len;
+ n++;
+ }
+
+ *num_eas = n;
+
+ return NT_STATUS_OK;
+}
+
diff --git a/source4/libcli/raw/rawfile.c b/source4/libcli/raw/rawfile.c
new file mode 100644
index 0000000000..279dfcf0c1
--- /dev/null
+++ b/source4/libcli/raw/rawfile.c
@@ -0,0 +1,687 @@
+/*
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#define SETUP_REQUEST(cmd, wct, buflen) do { \
+ req = cli_request_setup(tree, cmd, wct, buflen); \
+ if (!req) return NULL; \
+} while (0)
+
+
+/****************************************************************************
+ Rename a file - async interface
+****************************************************************************/
+struct cli_request *smb_raw_rename_send(struct cli_tree *tree,
+ struct smb_rename *parms)
+{
+ struct cli_request *req;
+
+ SETUP_REQUEST(SMBmv, 1, 0);
+
+ SSVAL(req->out.vwv, VWV(0), parms->in.attrib);
+
+ cli_req_append_ascii4(req, parms->in.pattern1, STR_TERMINATE);
+ cli_req_append_ascii4(req, parms->in.pattern2, STR_TERMINATE);
+
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+/****************************************************************************
+ Rename a file - sync interface
+****************************************************************************/
+NTSTATUS smb_raw_rename(struct cli_tree *tree,
+ struct smb_rename *parms)
+{
+ struct cli_request *req = smb_raw_rename_send(tree, parms);
+ return cli_request_simple_recv(req);
+}
+
+
+/****************************************************************************
+ Delete a file - async interface
+****************************************************************************/
+struct cli_request *smb_raw_unlink_send(struct cli_tree *tree,
+ struct smb_unlink *parms)
+{
+ struct cli_request *req;
+
+ SETUP_REQUEST(SMBunlink, 1, 0);
+
+ SSVAL(req->out.vwv, VWV(0), parms->in.attrib);
+ cli_req_append_ascii4(req, parms->in.pattern, STR_TERMINATE);
+
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+ return req;
+}
+
+/*
+ delete a file - sync interface
+*/
+NTSTATUS smb_raw_unlink(struct cli_tree *tree,
+ struct smb_unlink *parms)
+{
+ struct cli_request *req = smb_raw_unlink_send(tree, parms);
+ return cli_request_simple_recv(req);
+}
+
+
+/****************************************************************************
+ create a directory using TRANSACT2_MKDIR - async interface
+****************************************************************************/
+static struct cli_request *smb_raw_t2mkdir_send(struct cli_tree *tree,
+ union smb_mkdir *parms)
+{
+ struct smb_trans2 t2;
+ uint16 setup = TRANSACT2_MKDIR;
+ TALLOC_CTX *mem_ctx;
+ struct cli_request *req;
+ uint16 data_total;
+
+ mem_ctx = talloc_init("t2mkdir");
+
+ data_total = ea_list_size(parms->t2mkdir.in.num_eas, parms->t2mkdir.in.eas);
+
+ t2.in.max_param = 0;
+ t2.in.max_data = 0;
+ t2.in.max_setup = 0;
+ t2.in.flags = 0;
+ t2.in.timeout = 0;
+ t2.in.setup_count = 1;
+ t2.in.setup = &setup;
+ t2.in.params = data_blob_talloc(mem_ctx, NULL, 4);
+ t2.in.data = data_blob_talloc(mem_ctx, NULL, data_total);
+
+ SIVAL(t2.in.params.data, VWV(0), 0); /* reserved */
+
+ cli_blob_append_string(tree->session, mem_ctx,
+ &t2.in.params, parms->t2mkdir.in.path, 0);
+
+ ea_put_list(t2.in.data.data, parms->t2mkdir.in.num_eas, parms->t2mkdir.in.eas);
+
+ req = smb_raw_trans2_send(tree, &t2);
+
+ talloc_destroy(mem_ctx);
+
+ return req;
+}
+
+/****************************************************************************
+ Create a directory - async interface
+****************************************************************************/
+struct cli_request *smb_raw_mkdir_send(struct cli_tree *tree,
+ union smb_mkdir *parms)
+{
+ struct cli_request *req;
+
+ if (parms->generic.level == RAW_MKDIR_T2MKDIR) {
+ return smb_raw_t2mkdir_send(tree, parms);
+ }
+
+ if (parms->generic.level != RAW_MKDIR_MKDIR) {
+ return NULL;
+ }
+
+ SETUP_REQUEST(SMBmkdir, 0, 0);
+
+ cli_req_append_ascii4(req, parms->mkdir.in.path, STR_TERMINATE);
+
+ if (!cli_request_send(req)) {
+ return NULL;
+ }
+
+ return req;
+}
+
+/****************************************************************************
+ Create a directory - sync interface
+****************************************************************************/
+NTSTATUS smb_raw_mkdir(struct cli_tree *tree,
+ union smb_mkdir *parms)
+{
+ struct cli_request *req = smb_raw_mkdir_send(tree, parms);
+ return cli_request_simple_recv(req);
+}
+
+/****************************************************************************
+ Remove a directory - async interface
+****************************************************************************/
+struct cli_request *smb_raw_rmdir_send(struct cli_tree *tree,
+ struct smb_rmdir *parms)
+{
+ struct cli_request *req;
+
+ SETUP_REQUEST(SMBrmdir, 0, 0);
+
+ cli_req_append_ascii4(req, parms->in.path, STR_TERMINATE);
+
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+/****************************************************************************
+ Remove a directory - sync interface
+****************************************************************************/
+NTSTATUS smb_raw_rmdir(struct cli_tree *tree,
+ struct smb_rmdir *parms)
+{
+ struct cli_request *req = smb_raw_rmdir_send(tree, parms);
+ return cli_request_simple_recv(req);
+}
+
+
+/****************************************************************************
+ Open a file using TRANSACT2_OPEN - async send
+****************************************************************************/
+static struct cli_request *smb_raw_t2open_send(struct cli_tree *tree,
+ union smb_open *parms)
+{
+ struct smb_trans2 t2;
+ uint16 setup = TRANSACT2_OPEN;
+ TALLOC_CTX *mem_ctx = talloc_init("smb_raw_t2open");
+ struct cli_request *req;
+ uint16 list_size;
+
+ list_size = ea_list_size(parms->t2open.in.num_eas, parms->t2open.in.eas);
+
+ t2.in.max_param = 30;
+ t2.in.max_data = 0;
+ t2.in.max_setup = 0;
+ t2.in.flags = 0;
+ t2.in.timeout = 0;
+ t2.in.setup_count = 1;
+ t2.in.setup = &setup;
+ t2.in.params = data_blob_talloc(mem_ctx, NULL, 28);
+ t2.in.data = data_blob_talloc(mem_ctx, NULL, list_size);
+
+ SSVAL(t2.in.params.data, VWV(0), parms->t2open.in.flags);
+ SSVAL(t2.in.params.data, VWV(1), parms->t2open.in.open_mode);
+ SSVAL(t2.in.params.data, VWV(2), 0); /* reserved */
+ SSVAL(t2.in.params.data, VWV(3), parms->t2open.in.file_attrs);
+ put_dos_date(t2.in.params.data, VWV(4), parms->t2open.in.write_time);
+ SSVAL(t2.in.params.data, VWV(6), parms->t2open.in.open_func);
+ SIVAL(t2.in.params.data, VWV(7), parms->t2open.in.size);
+ SIVAL(t2.in.params.data, VWV(9), parms->t2open.in.timeout);
+ SIVAL(t2.in.params.data, VWV(11), 0);
+ SSVAL(t2.in.params.data, VWV(13), 0);
+
+ cli_blob_append_string(tree->session, mem_ctx,
+ &t2.in.params, parms->t2open.in.fname,
+ STR_TERMINATE);
+
+ ea_put_list(t2.in.data.data, parms->t2open.in.num_eas, parms->t2open.in.eas);
+
+ req = smb_raw_trans2_send(tree, &t2);
+
+ talloc_destroy(mem_ctx);
+
+ return req;
+}
+
+
+/****************************************************************************
+ Open a file using TRANSACT2_OPEN - async recv
+****************************************************************************/
+static NTSTATUS smb_raw_t2open_recv(struct cli_request *req, TALLOC_CTX *mem_ctx, union smb_open *parms)
+{
+ struct smb_trans2 t2;
+ NTSTATUS status;
+
+ status = smb_raw_trans2_recv(req, mem_ctx, &t2);
+ if (!NT_STATUS_IS_OK(status)) return status;
+
+ if (t2.out.params.length < 30) {
+ return NT_STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ parms->t2open.out.fnum = SVAL(t2.out.params.data, VWV(0));
+ parms->t2open.out.attrib = SVAL(t2.out.params.data, VWV(1));
+ parms->t2open.out.write_time = make_unix_date3(t2.out.params.data + VWV(2));
+ parms->t2open.out.size = IVAL(t2.out.params.data, VWV(4));
+ parms->t2open.out.access = SVAL(t2.out.params.data, VWV(6));
+ parms->t2open.out.ftype = SVAL(t2.out.params.data, VWV(7));
+ parms->t2open.out.devstate = SVAL(t2.out.params.data, VWV(8));
+ parms->t2open.out.action = SVAL(t2.out.params.data, VWV(9));
+ parms->t2open.out.unknown = SVAL(t2.out.params.data, VWV(10));
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Open a file - async send
+****************************************************************************/
+struct cli_request *smb_raw_open_send(struct cli_tree *tree, union smb_open *parms)
+{
+ int len;
+ struct cli_request *req = NULL;
+
+ switch (parms->open.level) {
+ case RAW_OPEN_T2OPEN:
+ return smb_raw_t2open_send(tree, parms);
+
+ case RAW_OPEN_OPEN:
+ SETUP_REQUEST(SMBopen, 2, 0);
+ SSVAL(req->out.vwv, VWV(0), parms->open.in.flags);
+ SSVAL(req->out.vwv, VWV(1), parms->open.in.search_attrs);
+ cli_req_append_ascii4(req, parms->open.in.fname, STR_TERMINATE);
+ break;
+
+ case RAW_OPEN_OPENX:
+ SETUP_REQUEST(SMBopenX, 15, 0);
+ SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
+ SSVAL(req->out.vwv, VWV(1), 0);
+ SSVAL(req->out.vwv, VWV(2), parms->openx.in.flags);
+ SSVAL(req->out.vwv, VWV(3), parms->openx.in.open_mode);
+ SSVAL(req->out.vwv, VWV(4), parms->openx.in.search_attrs);
+ SSVAL(req->out.vwv, VWV(5), parms->openx.in.file_attrs);
+ put_dos_date3(req->out.vwv, VWV(6), parms->openx.in.write_time);
+ SSVAL(req->out.vwv, VWV(8), parms->openx.in.open_func);
+ SIVAL(req->out.vwv, VWV(9), parms->openx.in.size);
+ SIVAL(req->out.vwv, VWV(11),parms->openx.in.timeout);
+ SIVAL(req->out.vwv, VWV(13),0); /* reserved */
+ cli_req_append_string(req, parms->openx.in.fname, STR_TERMINATE);
+ break;
+
+ case RAW_OPEN_MKNEW:
+ SETUP_REQUEST(SMBmknew, 3, 0);
+ SSVAL(req->out.vwv, VWV(0), parms->mknew.in.attrib);
+ put_dos_date3(req->out.vwv, VWV(1), parms->mknew.in.write_time);
+ cli_req_append_ascii4(req, parms->mknew.in.fname, STR_TERMINATE);
+ break;
+
+ case RAW_OPEN_CTEMP:
+ SETUP_REQUEST(SMBctemp, 3, 0);
+ SSVAL(req->out.vwv, VWV(0), parms->ctemp.in.attrib);
+ put_dos_date3(req->out.vwv, VWV(1), parms->ctemp.in.write_time);
+ cli_req_append_ascii4(req, parms->ctemp.in.directory, STR_TERMINATE);
+ break;
+
+ case RAW_OPEN_SPLOPEN:
+ SETUP_REQUEST(SMBsplopen, 2, 0);
+ SSVAL(req->out.vwv, VWV(0), parms->splopen.in.setup_length);
+ SSVAL(req->out.vwv, VWV(1), parms->splopen.in.mode);
+ break;
+
+ case RAW_OPEN_NTCREATEX:
+ SETUP_REQUEST(SMBntcreateX, 24, 0);
+ SSVAL(req->out.vwv, VWV(0),SMB_CHAIN_NONE);
+ SSVAL(req->out.vwv, VWV(1),0);
+ SCVAL(req->out.vwv, VWV(2),0); /* padding */
+ SIVAL(req->out.vwv, 7, parms->ntcreatex.in.flags);
+ SIVAL(req->out.vwv, 11, parms->ntcreatex.in.root_fid);
+ SIVAL(req->out.vwv, 15, parms->ntcreatex.in.access_mask);
+ SBVAL(req->out.vwv, 19, parms->ntcreatex.in.alloc_size);
+ SIVAL(req->out.vwv, 27, parms->ntcreatex.in.file_attr);
+ SIVAL(req->out.vwv, 31, parms->ntcreatex.in.share_access);
+ SIVAL(req->out.vwv, 35, parms->ntcreatex.in.open_disposition);
+ SIVAL(req->out.vwv, 39, parms->ntcreatex.in.create_options);
+ SIVAL(req->out.vwv, 43, parms->ntcreatex.in.impersonation);
+ SCVAL(req->out.vwv, 47, parms->ntcreatex.in.security_flags);
+
+ cli_req_append_string_len(req, parms->ntcreatex.in.fname, STR_TERMINATE, &len);
+ SSVAL(req->out.vwv, 5, len);
+ break;
+ }
+
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+/****************************************************************************
+ Open a file - async recv
+****************************************************************************/
+NTSTATUS smb_raw_open_recv(struct cli_request *req, TALLOC_CTX *mem_ctx, union smb_open *parms)
+{
+ if (!cli_request_receive(req) ||
+ cli_request_is_error(req)) {
+ goto failed;
+ }
+
+ switch (parms->open.level) {
+ case RAW_OPEN_T2OPEN:
+ return smb_raw_t2open_recv(req, mem_ctx, parms);
+
+ case RAW_OPEN_OPEN:
+ CLI_CHECK_WCT(req, 7);
+ parms->open.out.fnum = SVAL(req->in.vwv, VWV(0));
+ parms->open.out.attrib = SVAL(req->in.vwv, VWV(1));
+ parms->open.out.write_time = make_unix_date3(req->in.vwv + VWV(2));
+ parms->open.out.size = IVAL(req->in.vwv, VWV(4));
+ parms->open.out.rmode = SVAL(req->in.vwv, VWV(6));
+ break;
+
+ case RAW_OPEN_OPENX:
+ CLI_CHECK_MIN_WCT(req, 15);
+ parms->openx.out.fnum = SVAL(req->in.vwv, VWV(2));
+ parms->openx.out.attrib = SVAL(req->in.vwv, VWV(3));
+ parms->openx.out.write_time = make_unix_date3(req->in.vwv + VWV(4));
+ parms->openx.out.size = IVAL(req->in.vwv, VWV(6));
+ parms->openx.out.access = SVAL(req->in.vwv, VWV(8));
+ parms->openx.out.ftype = SVAL(req->in.vwv, VWV(9));
+ parms->openx.out.devstate = SVAL(req->in.vwv, VWV(10));
+ parms->openx.out.action = SVAL(req->in.vwv, VWV(11));
+ parms->openx.out.unique_fid = IVAL(req->in.vwv, VWV(12));
+ if (req->in.wct >= 19) {
+ parms->openx.out.access_mask = IVAL(req->in.vwv, VWV(15));
+ parms->openx.out.unknown = IVAL(req->in.vwv, VWV(17));
+ } else {
+ parms->openx.out.access_mask = 0;
+ parms->openx.out.unknown = 0;
+ }
+ break;
+
+ case RAW_OPEN_MKNEW:
+ CLI_CHECK_WCT(req, 1);
+ parms->mknew.out.fnum = SVAL(req->in.vwv, VWV(0));
+ break;
+
+ case RAW_OPEN_CTEMP:
+ CLI_CHECK_WCT(req, 1);
+ parms->ctemp.out.fnum = SVAL(req->in.vwv, VWV(0));
+ cli_req_pull_string(req, mem_ctx, &parms->ctemp.out.name, req->in.data, -1, STR_TERMINATE | STR_ASCII);
+ break;
+
+ case RAW_OPEN_SPLOPEN:
+ CLI_CHECK_WCT(req, 1);
+ parms->splopen.out.fnum = SVAL(req->in.vwv, VWV(0));
+ break;
+
+ case RAW_OPEN_NTCREATEX:
+ CLI_CHECK_MIN_WCT(req, 34);
+ parms->ntcreatex.out.oplock_level = CVAL(req->in.vwv, 4);
+ parms->ntcreatex.out.fnum = SVAL(req->in.vwv, 5);
+ parms->ntcreatex.out.create_action = IVAL(req->in.vwv, 7);
+ parms->ntcreatex.out.create_time = cli_pull_nttime(req->in.vwv, 11);
+ parms->ntcreatex.out.access_time = cli_pull_nttime(req->in.vwv, 19);
+ parms->ntcreatex.out.write_time = cli_pull_nttime(req->in.vwv, 27);
+ parms->ntcreatex.out.change_time = cli_pull_nttime(req->in.vwv, 35);
+ parms->ntcreatex.out.attrib = IVAL(req->in.vwv, 43);
+ parms->ntcreatex.out.alloc_size = BVAL(req->in.vwv, 47);
+ parms->ntcreatex.out.size = BVAL(req->in.vwv, 55);
+ parms->ntcreatex.out.file_type = SVAL(req->in.vwv, 63);
+ parms->ntcreatex.out.ipc_state = SVAL(req->in.vwv, 65);
+ parms->ntcreatex.out.is_directory = CVAL(req->in.vwv, 67);
+ break;
+ }
+
+failed:
+ return cli_request_destroy(req);
+}
+
+
+/****************************************************************************
+ Open a file - sync interface
+****************************************************************************/
+NTSTATUS smb_raw_open(struct cli_tree *tree, TALLOC_CTX *mem_ctx, union smb_open *parms)
+{
+ struct cli_request *req = smb_raw_open_send(tree, parms);
+ return smb_raw_open_recv(req, mem_ctx, parms);
+}
+
+
+/****************************************************************************
+ Close a file - async send
+****************************************************************************/
+struct cli_request *smb_raw_close_send(struct cli_tree *tree, union smb_close *parms)
+{
+ struct cli_request *req;
+
+ switch (parms->generic.level) {
+ case RAW_CLOSE_GENERIC:
+ return NULL;
+
+ case RAW_CLOSE_CLOSE:
+ SETUP_REQUEST(SMBclose, 3, 0);
+ SSVAL(req->out.vwv, VWV(0), parms->close.in.fnum);
+ put_dos_date3(req->out.vwv, VWV(1), parms->close.in.write_time);
+ break;
+
+ case RAW_CLOSE_SPLCLOSE:
+ SETUP_REQUEST(SMBsplclose, 3, 0);
+ SSVAL(req->out.vwv, VWV(0), parms->splclose.in.fnum);
+ SIVAL(req->out.vwv, VWV(1), 0); /* reserved */
+ break;
+ }
+
+ if (!req) return NULL;
+
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+
+/****************************************************************************
+ Close a file - sync interface
+****************************************************************************/
+NTSTATUS smb_raw_close(struct cli_tree *tree, union smb_close *parms)
+{
+ struct cli_request *req = smb_raw_close_send(tree, parms);
+ return cli_request_simple_recv(req);
+}
+
+
+/****************************************************************************
+ Locking calls - async interface
+****************************************************************************/
+struct cli_request *smb_raw_lock_send(struct cli_tree *tree, union smb_lock *parms)
+{
+ struct cli_request *req;
+
+ switch (parms->generic.level) {
+ case RAW_LOCK_GENERIC:
+ return NULL;
+
+ case RAW_LOCK_LOCK:
+ SETUP_REQUEST(SMBlock, 5, 0);
+ SSVAL(req->out.vwv, VWV(0), parms->lock.in.fnum);
+ SIVAL(req->out.vwv, VWV(1), parms->lock.in.count);
+ SIVAL(req->out.vwv, VWV(3), parms->lock.in.offset);
+ break;
+
+ case RAW_LOCK_UNLOCK:
+ SETUP_REQUEST(SMBunlock, 5, 0);
+ SSVAL(req->out.vwv, VWV(0), parms->unlock.in.fnum);
+ SIVAL(req->out.vwv, VWV(1), parms->unlock.in.count);
+ SIVAL(req->out.vwv, VWV(3), parms->unlock.in.offset);
+ break;
+
+ case RAW_LOCK_LOCKX: {
+ struct smb_lock_entry *lockp;
+ uint_t lck_size = (parms->lockx.in.mode & LOCKING_ANDX_LARGE_FILES)? 20 : 10;
+ uint_t lock_count = parms->lockx.in.ulock_cnt + parms->lockx.in.lock_cnt;
+ int i;
+
+ SETUP_REQUEST(SMBlockingX, 8, lck_size * lock_count);
+ SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
+ SSVAL(req->out.vwv, VWV(1), 0);
+ SSVAL(req->out.vwv, VWV(2), parms->lockx.in.fnum);
+ SSVAL(req->out.vwv, VWV(3), parms->lockx.in.mode);
+ SIVAL(req->out.vwv, VWV(4), parms->lockx.in.timeout);
+ SSVAL(req->out.vwv, VWV(6), parms->lockx.in.ulock_cnt);
+ SSVAL(req->out.vwv, VWV(7), parms->lockx.in.lock_cnt);
+
+ /* copy in all the locks */
+ lockp = &parms->lockx.in.locks[0];
+ for (i = 0; i < lock_count; i++) {
+ char *p = req->out.data + lck_size * i;
+ SSVAL(p, 0, lockp[i].pid);
+ if (parms->lockx.in.mode & LOCKING_ANDX_LARGE_FILES) {
+ SSVAL(p, 2, 0); /* reserved */
+ SIVAL(p, 4, lockp[i].offset>>32);
+ SIVAL(p, 8, lockp[i].offset);
+ SIVAL(p, 12, lockp[i].count>>32);
+ SIVAL(p, 16, lockp[i].count);
+ } else {
+ SIVAL(p, 2, lockp[i].offset);
+ SIVAL(p, 6, lockp[i].count);
+ }
+ }
+ }
+ }
+
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+/****************************************************************************
+ Locking calls - sync interface
+****************************************************************************/
+NTSTATUS smb_raw_lock(struct cli_tree *tree, union smb_lock *parms)
+{
+ struct cli_request *req = smb_raw_lock_send(tree, parms);
+ return cli_request_simple_recv(req);
+}
+
+
+/****************************************************************************
+ Check for existence of a dir - async send
+****************************************************************************/
+struct cli_request *smb_raw_chkpath_send(struct cli_tree *tree, struct smb_chkpath *parms)
+{
+ struct cli_request *req;
+
+ SETUP_REQUEST(SMBchkpth, 0, 0);
+
+ cli_req_append_ascii4(req, parms->in.path, STR_TERMINATE);
+
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+/****************************************************************************
+ Check for existence of a dir - sync interface
+****************************************************************************/
+NTSTATUS smb_raw_chkpath(struct cli_tree *tree, struct smb_chkpath *parms)
+{
+ struct cli_request *req = smb_raw_chkpath_send(tree, parms);
+ return cli_request_simple_recv(req);
+}
+
+
+
+
+/****************************************************************************
+ flush a file - async send
+ a flush to fnum 0xFFFF will flush all files
+****************************************************************************/
+struct cli_request *smb_raw_flush_send(struct cli_tree *tree, struct smb_flush *parms)
+{
+ struct cli_request *req;
+
+ SETUP_REQUEST(SMBflush, 1, 0);
+ SSVAL(req->out.vwv, VWV(0), parms->in.fnum);
+
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+
+/****************************************************************************
+ flush a file - sync interface
+****************************************************************************/
+NTSTATUS smb_raw_flush(struct cli_tree *tree, struct smb_flush *parms)
+{
+ struct cli_request *req = smb_raw_flush_send(tree, parms);
+ return cli_request_simple_recv(req);
+}
+
+
+/****************************************************************************
+ seek a file - async send
+****************************************************************************/
+struct cli_request *smb_raw_seek_send(struct cli_tree *tree,
+ struct smb_seek *parms)
+{
+ struct cli_request *req;
+
+ SETUP_REQUEST(SMBlseek, 4, 0);
+
+ SSVAL(req->out.vwv, VWV(0), parms->in.fnum);
+ SSVAL(req->out.vwv, VWV(1), parms->in.mode);
+ SIVALS(req->out.vwv, VWV(2), parms->in.offset);
+
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+ return req;
+}
+
+/****************************************************************************
+ seek a file - async receive
+****************************************************************************/
+NTSTATUS smb_raw_seek_recv(struct cli_request *req,
+ struct smb_seek *parms)
+{
+ if (!cli_request_receive(req) ||
+ cli_request_is_error(req)) {
+ return cli_request_destroy(req);
+ }
+
+ CLI_CHECK_WCT(req, 2);
+ parms->out.offset = IVAL(req->in.vwv, VWV(0));
+
+failed:
+ return cli_request_destroy(req);
+}
+
+/*
+ seek a file - sync interface
+*/
+NTSTATUS smb_raw_seek(struct cli_tree *tree,
+ struct smb_seek *parms)
+{
+ struct cli_request *req = smb_raw_seek_send(tree, parms);
+ return smb_raw_seek_recv(req, parms);
+}
diff --git a/source4/libcli/raw/rawfileinfo.c b/source4/libcli/raw/rawfileinfo.c
new file mode 100644
index 0000000000..f685cef9c3
--- /dev/null
+++ b/source4/libcli/raw/rawfileinfo.c
@@ -0,0 +1,527 @@
+/*
+ Unix SMB/CIFS implementation.
+ client trans2 operations
+ Copyright (C) James Myers 2003
+ Copyright (C) Andrew Tridgell 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* local macros to make the code more readable */
+#define FINFO_CHECK_MIN_SIZE(size) if (blob->length < (size)) { \
+ DEBUG(1,("Unexpected FILEINFO reply size %d for level %u - expected min of %d\n", \
+ blob->length, parms->generic.level, (size))); \
+ return NT_STATUS_INFO_LENGTH_MISMATCH; \
+}
+#define FINFO_CHECK_SIZE(size) if (blob->length != (size)) { \
+ DEBUG(1,("Unexpected FILEINFO reply size %d for level %u - expected %d\n", \
+ blob->length, parms->generic.level, (size))); \
+ return NT_STATUS_INFO_LENGTH_MISMATCH; \
+}
+
+/****************************************************************************
+ Handle qfileinfo/qpathinfo trans2 backend.
+****************************************************************************/
+static NTSTATUS smb_raw_info_backend(struct cli_session *session,
+ TALLOC_CTX *mem_ctx,
+ union smb_fileinfo *parms,
+ DATA_BLOB *blob)
+{
+ uint_t len, ofs;
+
+ switch (parms->generic.level) {
+ case RAW_FILEINFO_GENERIC:
+ case RAW_FILEINFO_GETATTR:
+ case RAW_FILEINFO_GETATTRE:
+ /* not handled here */
+ return NT_STATUS_INVALID_LEVEL;
+
+ case RAW_FILEINFO_STANDARD:
+ FINFO_CHECK_SIZE(22);
+ parms->standard.out.create_time = make_unix_date2(blob->data + 0);
+ parms->standard.out.access_time = make_unix_date2(blob->data + 4);
+ parms->standard.out.write_time = make_unix_date2(blob->data + 8);
+ parms->standard.out.size = IVAL(blob->data, 12);
+ parms->standard.out.alloc_size = IVAL(blob->data, 16);
+ parms->standard.out.attrib = SVAL(blob->data, 20);
+ return NT_STATUS_OK;
+
+ case RAW_FILEINFO_EA_SIZE:
+ FINFO_CHECK_SIZE(26);
+ parms->ea_size.out.create_time = make_unix_date2(blob->data + 0);
+ parms->ea_size.out.access_time = make_unix_date2(blob->data + 4);
+ parms->ea_size.out.write_time = make_unix_date2(blob->data + 8);
+ parms->ea_size.out.size = IVAL(blob->data, 12);
+ parms->ea_size.out.alloc_size = IVAL(blob->data, 16);
+ parms->ea_size.out.attrib = SVAL(blob->data, 20);
+ parms->ea_size.out.ea_size = IVAL(blob->data, 22);
+ return NT_STATUS_OK;
+
+ case RAW_FILEINFO_ALL_EAS:
+ FINFO_CHECK_MIN_SIZE(4);
+ return ea_pull_list(blob, mem_ctx,
+ &parms->all_eas.out.num_eas,
+ &parms->all_eas.out.eas);
+
+ case RAW_FILEINFO_IS_NAME_VALID:
+ /* no data! */
+ FINFO_CHECK_SIZE(0);
+ return NT_STATUS_OK;
+
+ case RAW_FILEINFO_BASIC_INFO:
+ case RAW_FILEINFO_BASIC_INFORMATION:
+ /* some servers return 40 bytes and some 36. w2k3 return 40, so thats
+ what we should do, but we need to accept 36 */
+ if (blob->length != 36) {
+ FINFO_CHECK_SIZE(40);
+ }
+ parms->basic_info.out.create_time = cli_pull_nttime(blob->data, 0);
+ parms->basic_info.out.access_time = cli_pull_nttime(blob->data, 8);
+ parms->basic_info.out.write_time = cli_pull_nttime(blob->data, 16);
+ parms->basic_info.out.change_time = cli_pull_nttime(blob->data, 24);
+ parms->basic_info.out.attrib = IVAL(blob->data, 32);
+ return NT_STATUS_OK;
+
+ case RAW_FILEINFO_STANDARD_INFO:
+ case RAW_FILEINFO_STANDARD_INFORMATION:
+ FINFO_CHECK_SIZE(24);
+ parms->standard_info.out.alloc_size = BVAL(blob->data, 0);
+ parms->standard_info.out.size = BVAL(blob->data, 8);
+ parms->standard_info.out.nlink = IVAL(blob->data, 16);
+ parms->standard_info.out.delete_pending = CVAL(blob->data, 20);
+ parms->standard_info.out.directory = CVAL(blob->data, 21);
+ return NT_STATUS_OK;
+
+ case RAW_FILEINFO_EA_INFO:
+ case RAW_FILEINFO_EA_INFORMATION:
+ FINFO_CHECK_SIZE(4);
+ parms->ea_info.out.ea_size = IVAL(blob->data, 0);
+ return NT_STATUS_OK;
+
+ case RAW_FILEINFO_NAME_INFO:
+ case RAW_FILEINFO_NAME_INFORMATION:
+ FINFO_CHECK_MIN_SIZE(4);
+ cli_blob_pull_string(session, mem_ctx, blob,
+ &parms->name_info.out.fname, 0, 4, STR_UNICODE);
+ return NT_STATUS_OK;
+
+ case RAW_FILEINFO_ALL_INFO:
+ case RAW_FILEINFO_ALL_INFORMATION:
+ FINFO_CHECK_MIN_SIZE(72);
+ parms->all_info.out.create_time = cli_pull_nttime(blob->data, 0);
+ parms->all_info.out.access_time = cli_pull_nttime(blob->data, 8);
+ parms->all_info.out.write_time = cli_pull_nttime(blob->data, 16);
+ parms->all_info.out.change_time = cli_pull_nttime(blob->data, 24);
+ parms->all_info.out.attrib = IVAL(blob->data, 32);
+ parms->all_info.out.alloc_size = BVAL(blob->data, 40);
+ parms->all_info.out.size = BVAL(blob->data, 48);
+ parms->all_info.out.nlink = IVAL(blob->data, 56);
+ parms->all_info.out.delete_pending = CVAL(blob->data, 60);
+ parms->all_info.out.directory = CVAL(blob->data, 61);
+ parms->all_info.out.ea_size = IVAL(blob->data, 64);
+ cli_blob_pull_string(session, mem_ctx, blob,
+ &parms->all_info.out.fname, 68, 72, STR_UNICODE);
+ return NT_STATUS_OK;
+
+ case RAW_FILEINFO_ALT_NAME_INFO:
+ case RAW_FILEINFO_ALT_NAME_INFORMATION:
+ FINFO_CHECK_MIN_SIZE(4);
+ cli_blob_pull_string(session, mem_ctx, blob,
+ &parms->alt_name_info.out.fname, 0, 4, STR_UNICODE);
+ return NT_STATUS_OK;
+
+ case RAW_FILEINFO_STREAM_INFO:
+ case RAW_FILEINFO_STREAM_INFORMATION:
+ FINFO_CHECK_MIN_SIZE(0);
+ ofs = 0;
+ parms->stream_info.out.num_streams = 0;
+ parms->stream_info.out.streams = NULL;
+
+ while (blob->length - ofs >= 24) {
+ uint_t n = parms->stream_info.out.num_streams;
+ parms->stream_info.out.streams =
+ talloc_realloc(mem_ctx,parms->stream_info.out.streams,
+ (n+1) * sizeof(parms->stream_info.out.streams[0]));
+ if (!parms->stream_info.out.streams) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ parms->stream_info.out.streams[n].size = BVAL(blob->data, ofs + 8);
+ parms->stream_info.out.streams[n].alloc_size = BVAL(blob->data, ofs + 16);
+ cli_blob_pull_string(session, mem_ctx, blob,
+ &parms->stream_info.out.streams[n].stream_name,
+ ofs+4, ofs+24, STR_UNICODE);
+ parms->stream_info.out.num_streams++;
+ len = IVAL(blob->data, ofs);
+ if (len > blob->length - ofs) return NT_STATUS_INFO_LENGTH_MISMATCH;
+ if (len == 0) break;
+ ofs += len;
+ }
+ return NT_STATUS_OK;
+
+ case RAW_FILEINFO_INTERNAL_INFORMATION:
+ FINFO_CHECK_SIZE(8);
+ parms->internal_information.out.device = IVAL(blob->data, 0);
+ parms->internal_information.out.inode = IVAL(blob->data, 4);
+ return NT_STATUS_OK;
+
+ case RAW_FILEINFO_ACCESS_INFORMATION:
+ FINFO_CHECK_SIZE(4);
+ parms->access_information.out.access_flags = IVAL(blob->data, 0);
+ return NT_STATUS_OK;
+
+ case RAW_FILEINFO_POSITION_INFORMATION:
+ FINFO_CHECK_SIZE(8);
+ parms->position_information.out.position = BVAL(blob->data, 0);
+ return NT_STATUS_OK;
+
+ case RAW_FILEINFO_MODE_INFORMATION:
+ FINFO_CHECK_SIZE(4);
+ parms->mode_information.out.mode = IVAL(blob->data, 0);
+ return NT_STATUS_OK;
+
+ case RAW_FILEINFO_ALIGNMENT_INFORMATION:
+ FINFO_CHECK_SIZE(4);
+ parms->alignment_information.out.alignment_requirement
+ = IVAL(blob->data, 0);
+ return NT_STATUS_OK;
+
+ case RAW_FILEINFO_COMPRESSION_INFO:
+ case RAW_FILEINFO_COMPRESSION_INFORMATION:
+ FINFO_CHECK_SIZE(16);
+ parms->compression_info.out.compressed_size = BVAL(blob->data, 0);
+ parms->compression_info.out.format = SVAL(blob->data, 8);
+ parms->compression_info.out.unit_shift = CVAL(blob->data, 10);
+ parms->compression_info.out.chunk_shift = CVAL(blob->data, 11);
+ parms->compression_info.out.cluster_shift = CVAL(blob->data, 12);
+ /* 3 bytes of padding */
+ return NT_STATUS_OK;
+
+ case RAW_FILEINFO_UNIX_BASIC:
+ FINFO_CHECK_SIZE(100);
+ parms->unix_basic_info.out.end_of_file = BVAL(blob->data, 0);
+ parms->unix_basic_info.out.num_bytes = BVAL(blob->data, 8);
+ parms->unix_basic_info.out.status_change_time = cli_pull_nttime(blob->data, 16);
+ parms->unix_basic_info.out.access_time = cli_pull_nttime(blob->data, 24);
+ parms->unix_basic_info.out.change_time = cli_pull_nttime(blob->data, 32);
+ parms->unix_basic_info.out.uid = BVAL(blob->data, 40);
+ parms->unix_basic_info.out.gid = BVAL(blob->data, 48);
+ parms->unix_basic_info.out.file_type = IVAL(blob->data, 52);
+ parms->unix_basic_info.out.dev_major = BVAL(blob->data, 60);
+ parms->unix_basic_info.out.dev_minor = BVAL(blob->data, 68);
+ parms->unix_basic_info.out.unique_id = BVAL(blob->data, 76);
+ parms->unix_basic_info.out.permissions = BVAL(blob->data, 84);
+ parms->unix_basic_info.out.nlink = BVAL(blob->data, 92);
+ return NT_STATUS_OK;
+
+ case RAW_FILEINFO_UNIX_LINK:
+ FINFO_CHECK_MIN_SIZE(0);
+ cli_blob_pull_string(session, mem_ctx, blob,
+ &parms->unix_link_info.out.link_dest, 0, 4, STR_UNICODE);
+ return NT_STATUS_OK;
+
+ case RAW_FILEINFO_NETWORK_OPEN_INFORMATION:
+ FINFO_CHECK_SIZE(56);
+ parms->network_open_information.out.create_time = cli_pull_nttime(blob->data, 0);
+ parms->network_open_information.out.access_time = cli_pull_nttime(blob->data, 8);
+ parms->network_open_information.out.write_time = cli_pull_nttime(blob->data, 16);
+ parms->network_open_information.out.change_time = cli_pull_nttime(blob->data, 24);
+ parms->network_open_information.out.alloc_size = BVAL(blob->data, 32);
+ parms->network_open_information.out.size = BVAL(blob->data, 40);
+ parms->network_open_information.out.attrib = IVAL(blob->data, 48);
+ return NT_STATUS_OK;
+
+ case RAW_FILEINFO_ATTRIBUTE_TAG_INFORMATION:
+ FINFO_CHECK_SIZE(8);
+ parms->attribute_tag_information.out.attrib = IVAL(blob->data, 0);
+ parms->attribute_tag_information.out.reparse_tag = IVAL(blob->data, 4);
+ return NT_STATUS_OK;
+ }
+
+ return NT_STATUS_INVALID_LEVEL;
+}
+
+/****************************************************************************
+ Very raw query file info - returns param/data blobs - (async send)
+****************************************************************************/
+static struct cli_request *smb_raw_fileinfo_blob_send(struct cli_tree *tree,
+ uint16 fnum, uint16 info_level)
+{
+ struct smb_trans2 tp;
+ uint16 setup = TRANSACT2_QFILEINFO;
+ struct cli_request *req;
+ TALLOC_CTX *mem_ctx = talloc_init("raw_fileinfo");
+
+ tp.in.max_setup = 0;
+ tp.in.flags = 0;
+ tp.in.timeout = 0;
+ tp.in.setup_count = 1;
+ tp.in.data = data_blob(NULL, 0);
+ tp.in.max_param = 2;
+ tp.in.max_data = 0xFFFF;
+ tp.in.setup = &setup;
+
+ tp.in.params = data_blob_talloc(mem_ctx, NULL, 4);
+ if (!tp.in.params.data) {
+ talloc_destroy(mem_ctx);
+ return NULL;
+ }
+
+ SIVAL(tp.in.params.data, 0, fnum);
+ SSVAL(tp.in.params.data, 2, info_level);
+
+ req = smb_raw_trans2_send(tree, &tp);
+
+ talloc_destroy(mem_ctx);
+
+ return req;
+}
+
+
+/****************************************************************************
+ Very raw query file info - returns param/data blobs - (async recv)
+****************************************************************************/
+static NTSTATUS smb_raw_fileinfo_blob_recv(struct cli_request *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob)
+{
+ struct smb_trans2 tp;
+ NTSTATUS status = smb_raw_trans2_recv(req, mem_ctx, &tp);
+ if (NT_STATUS_IS_OK(status)) {
+ *blob = tp.out.data;
+ }
+ return status;
+}
+
+/****************************************************************************
+ Very raw query path info - returns param/data blobs (async send)
+****************************************************************************/
+static struct cli_request *smb_raw_pathinfo_blob_send(struct cli_tree *tree,
+ const char *fname,
+ uint16 info_level)
+{
+ struct smb_trans2 tp;
+ uint16 setup = TRANSACT2_QPATHINFO;
+ struct cli_request *req;
+ TALLOC_CTX *mem_ctx = talloc_init("raw_pathinfo");
+
+ tp.in.max_setup = 0;
+ tp.in.flags = 0;
+ tp.in.timeout = 0;
+ tp.in.setup_count = 1;
+ tp.in.data = data_blob(NULL, 0);
+ tp.in.max_param = 2;
+ tp.in.max_data = 0xFFFF;
+ tp.in.setup = &setup;
+
+ tp.in.params = data_blob_talloc(mem_ctx, NULL, 6);
+ if (!tp.in.params.data) {
+ talloc_destroy(mem_ctx);
+ return NULL;
+ }
+
+ SSVAL(tp.in.params.data, 0, info_level);
+ SIVAL(tp.in.params.data, 2, 0);
+ cli_blob_append_string(tree->session, mem_ctx, &tp.in.params,
+ fname, STR_TERMINATE);
+
+ req = smb_raw_trans2_send(tree, &tp);
+
+ talloc_destroy(mem_ctx);
+
+ return req;
+}
+
+/****************************************************************************
+ send a SMBgetatr (async send)
+****************************************************************************/
+static struct cli_request *smb_raw_getattr_send(struct cli_tree *tree,
+ union smb_fileinfo *parms)
+{
+ struct cli_request *req;
+
+ req = cli_request_setup(tree, SMBgetatr, 0, 0);
+ if (!req) return NULL;
+
+ cli_req_append_ascii4(req, parms->getattr.in.fname, STR_TERMINATE);
+
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+/****************************************************************************
+ send a SMBgetatr (async recv)
+****************************************************************************/
+static NTSTATUS smb_raw_getattr_recv(struct cli_request *req,
+ union smb_fileinfo *parms)
+{
+ if (!cli_request_receive(req) ||
+ cli_request_is_error(req)) {
+ return cli_request_destroy(req);
+ }
+
+ CLI_CHECK_WCT(req, 10);
+ parms->getattr.out.attrib = SVAL(req->in.vwv, VWV(0));
+ parms->getattr.out.write_time = make_unix_date3(req->in.vwv + VWV(1));
+ parms->getattr.out.size = IVAL(req->in.vwv, VWV(3));
+
+failed:
+ return cli_request_destroy(req);
+}
+
+
+/****************************************************************************
+ Handle SMBgetattrE (async send)
+****************************************************************************/
+static struct cli_request *smb_raw_getattrE_send(struct cli_tree *tree,
+ union smb_fileinfo *parms)
+{
+ struct cli_request *req;
+
+ req = cli_request_setup(tree, SMBgetattrE, 1, 0);
+ if (!req) return NULL;
+
+ SSVAL(req->out.vwv, VWV(0), parms->getattre.in.fnum);
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+/****************************************************************************
+ Handle SMBgetattrE (async send)
+****************************************************************************/
+static NTSTATUS smb_raw_getattrE_recv(struct cli_request *req,
+ union smb_fileinfo *parms)
+{
+ if (!cli_request_receive(req) ||
+ cli_request_is_error(req)) {
+ return cli_request_destroy(req);
+ }
+
+ CLI_CHECK_WCT(req, 11);
+ parms->getattre.out.create_time = make_unix_date2(req->in.vwv + VWV(0));
+ parms->getattre.out.access_time = make_unix_date2(req->in.vwv + VWV(2));
+ parms->getattre.out.write_time = make_unix_date2(req->in.vwv + VWV(4));
+ parms->getattre.out.size = IVAL(req->in.vwv, VWV(6));
+ parms->getattre.out.alloc_size = IVAL(req->in.vwv, VWV(8));
+ parms->getattre.out.attrib = SVAL(req->in.vwv, VWV(10));
+
+failed:
+ return cli_request_destroy(req);
+}
+
+
+/****************************************************************************
+ Query file info (async send)
+****************************************************************************/
+struct cli_request *smb_raw_fileinfo_send(struct cli_tree *tree,
+ union smb_fileinfo *parms)
+{
+ /* pass off the non-trans2 level to specialised functions */
+ if (parms->generic.level == RAW_FILEINFO_GETATTRE) {
+ return smb_raw_getattrE_send(tree, parms);
+ }
+ if (parms->generic.level >= RAW_FILEINFO_GENERIC) {
+ return NULL;
+ }
+
+ return smb_raw_fileinfo_blob_send(tree,
+ parms->generic.in.fnum,
+ parms->generic.level);
+}
+
+/****************************************************************************
+ Query file info (async recv)
+****************************************************************************/
+NTSTATUS smb_raw_fileinfo_recv(struct cli_request *req,
+ TALLOC_CTX *mem_ctx,
+ union smb_fileinfo *parms)
+{
+ DATA_BLOB blob;
+ NTSTATUS status;
+ struct cli_session *session = req?req->session:NULL;
+
+ if (parms->generic.level == RAW_FILEINFO_GETATTRE) {
+ return smb_raw_getattrE_recv(req, parms);
+ }
+ if (parms->generic.level == RAW_FILEINFO_GETATTR) {
+ return smb_raw_getattr_recv(req, parms);
+ }
+
+ status = smb_raw_fileinfo_blob_recv(req, mem_ctx, &blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return smb_raw_info_backend(session, mem_ctx, parms, &blob);
+}
+
+/****************************************************************************
+ Query file info (sync interface)
+****************************************************************************/
+NTSTATUS smb_raw_fileinfo(struct cli_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ union smb_fileinfo *parms)
+{
+ struct cli_request *req = smb_raw_fileinfo_send(tree, parms);
+ return smb_raw_fileinfo_recv(req, mem_ctx, parms);
+}
+
+/****************************************************************************
+ Query path info (async send)
+****************************************************************************/
+struct cli_request *smb_raw_pathinfo_send(struct cli_tree *tree,
+ union smb_fileinfo *parms)
+{
+ if (parms->generic.level == RAW_FILEINFO_GETATTR) {
+ return smb_raw_getattr_send(tree, parms);
+ }
+ if (parms->generic.level >= RAW_FILEINFO_GENERIC) {
+ return NULL;
+ }
+
+ return smb_raw_pathinfo_blob_send(tree, parms->generic.in.fname,
+ parms->generic.level);
+}
+
+/****************************************************************************
+ Query path info (async recv)
+****************************************************************************/
+NTSTATUS smb_raw_pathinfo_recv(struct cli_request *req,
+ TALLOC_CTX *mem_ctx,
+ union smb_fileinfo *parms)
+{
+ /* recv is idential to fileinfo */
+ return smb_raw_fileinfo_recv(req, mem_ctx, parms);
+}
+
+/****************************************************************************
+ Query path info (sync interface)
+****************************************************************************/
+NTSTATUS smb_raw_pathinfo(struct cli_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ union smb_fileinfo *parms)
+{
+ struct cli_request *req = smb_raw_pathinfo_send(tree, parms);
+ return smb_raw_pathinfo_recv(req, mem_ctx, parms);
+}
diff --git a/source4/libcli/raw/rawfsinfo.c b/source4/libcli/raw/rawfsinfo.c
new file mode 100644
index 0000000000..362063bfc5
--- /dev/null
+++ b/source4/libcli/raw/rawfsinfo.c
@@ -0,0 +1,282 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ RAW_QFS_* operations
+
+ Copyright (C) Andrew Tridgell 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Query FS Info - SMBdskattr call (async send)
+****************************************************************************/
+static struct cli_request *smb_raw_dskattr_send(struct cli_tree *tree,
+ union smb_fsinfo *fsinfo)
+{
+ struct cli_request *req;
+
+ req = cli_request_setup(tree, SMBdskattr, 0, 0);
+
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+/****************************************************************************
+ Query FS Info - SMBdskattr call (async recv)
+****************************************************************************/
+static NTSTATUS smb_raw_dskattr_recv(struct cli_request *req,
+ union smb_fsinfo *fsinfo)
+{
+ if (!cli_request_receive(req) ||
+ cli_request_is_error(req)) {
+ goto failed;
+ }
+
+ CLI_CHECK_WCT(req, 5);
+ fsinfo->dskattr.out.units_total = SVAL(req->in.vwv, VWV(0));
+ fsinfo->dskattr.out.blocks_per_unit = SVAL(req->in.vwv, VWV(1));
+ fsinfo->dskattr.out.block_size = SVAL(req->in.vwv, VWV(2));
+ fsinfo->dskattr.out.units_free = SVAL(req->in.vwv, VWV(3));
+
+failed:
+ return cli_request_destroy(req);
+}
+
+
+/****************************************************************************
+ RAW_QFS_ trans2 interface via blobs (async send)
+****************************************************************************/
+static struct cli_request *smb_raw_qfsinfo_send(struct cli_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ uint16 info_level)
+{
+ struct smb_trans2 tp;
+ uint16 setup = TRANSACT2_QFSINFO;
+
+ tp.in.max_setup = 0;
+ tp.in.flags = 0;
+ tp.in.timeout = 0;
+ tp.in.setup_count = 1;
+ tp.in.max_param = 0;
+ tp.in.max_data = 0x1000; /* plenty for all possible QFS levels */
+ tp.in.setup = &setup;
+ tp.in.data = data_blob(NULL, 0);
+ tp.in.timeout = 0;
+
+ tp.in.params = data_blob_talloc(mem_ctx, NULL, 2);
+ if (!tp.in.params.data) {
+ return NULL;
+ }
+ SSVAL(tp.in.params.data, 0, info_level);
+
+ return smb_raw_trans2_send(tree, &tp);
+}
+
+/****************************************************************************
+ RAW_QFS_ trans2 interface via blobs (async recv)
+****************************************************************************/
+static NTSTATUS smb_raw_qfsinfo_blob_recv(struct cli_request *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob)
+{
+ struct smb_trans2 tp;
+ NTSTATUS status;
+
+ status = smb_raw_trans2_recv(req, mem_ctx, &tp);
+
+ if (NT_STATUS_IS_OK(status)) {
+ (*blob) = tp.out.data;
+ }
+
+ return status;
+}
+
+
+/* local macros to make the code more readable */
+#define QFS_CHECK_MIN_SIZE(size) if (blob.length < (size)) { \
+ DEBUG(1,("Unexpected QFS reply size %d for level %u - expected min of %d\n", \
+ blob.length, fsinfo->generic.level, (size))); \
+ status = NT_STATUS_INFO_LENGTH_MISMATCH; \
+ goto failed; \
+}
+#define QFS_CHECK_SIZE(size) if (blob.length != (size)) { \
+ DEBUG(1,("Unexpected QFS reply size %d for level %u - expected %d\n", \
+ blob.length, fsinfo->generic.level, (size))); \
+ status = NT_STATUS_INFO_LENGTH_MISMATCH; \
+ goto failed; \
+}
+
+
+/****************************************************************************
+ Query FSInfo raw interface (async send)
+****************************************************************************/
+struct cli_request *smb_raw_fsinfo_send(struct cli_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ union smb_fsinfo *fsinfo)
+{
+ uint16 info_level;
+
+ /* handle the only non-trans2 call separately */
+ if (fsinfo->generic.level == RAW_QFS_DSKATTR) {
+ return smb_raw_dskattr_send(tree, fsinfo);
+ }
+ if (fsinfo->generic.level >= RAW_QFS_GENERIC) {
+ return NULL;
+ }
+
+ /* the headers map the trans2 levels direct to info levels */
+ info_level = (uint16)fsinfo->generic.level;
+
+ return smb_raw_qfsinfo_send(tree, mem_ctx, info_level);
+}
+
+
+/****************************************************************************
+ Query FSInfo raw interface (async recv)
+****************************************************************************/
+NTSTATUS smb_raw_fsinfo_recv(struct cli_request *req,
+ TALLOC_CTX *mem_ctx,
+ union smb_fsinfo *fsinfo)
+{
+ DATA_BLOB blob;
+ NTSTATUS status;
+ int i;
+ struct cli_session *session = req?req->session:NULL;
+
+ if (fsinfo->generic.level == RAW_QFS_DSKATTR) {
+ return smb_raw_dskattr_recv(req, fsinfo);
+ }
+
+ status = smb_raw_qfsinfo_blob_recv(req, mem_ctx, &blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* parse the results */
+ switch (fsinfo->generic.level) {
+ case RAW_QFS_GENERIC:
+ case RAW_QFS_DSKATTR:
+ /* handled above */
+ break;
+
+ case RAW_QFS_ALLOCATION:
+ QFS_CHECK_SIZE(18);
+ fsinfo->allocation.out.fs_id = IVAL(blob.data, 0);
+ fsinfo->allocation.out.sectors_per_unit = IVAL(blob.data, 4);
+ fsinfo->allocation.out.total_alloc_units = IVAL(blob.data, 8);
+ fsinfo->allocation.out.avail_alloc_units = IVAL(blob.data, 12);
+ fsinfo->allocation.out.bytes_per_sector = SVAL(blob.data, 16);
+ break;
+
+ case RAW_QFS_VOLUME:
+ QFS_CHECK_MIN_SIZE(5);
+ fsinfo->volume.out.serial_number = IVAL(blob.data, 0);
+ cli_blob_pull_string(session, mem_ctx, &blob,
+ &fsinfo->volume.out.volume_name,
+ 4, 5, STR_LEN8BIT | STR_NOALIGN);
+ break;
+
+ case RAW_QFS_VOLUME_INFO:
+ case RAW_QFS_VOLUME_INFORMATION:
+ QFS_CHECK_MIN_SIZE(18);
+ fsinfo->volume_info.out.create_time = cli_pull_nttime(blob.data, 0);
+ fsinfo->volume_info.out.serial_number = IVAL(blob.data, 8);
+ cli_blob_pull_string(session, mem_ctx, &blob,
+ &fsinfo->volume_info.out.volume_name,
+ 12, 18, STR_UNICODE);
+ break;
+
+ case RAW_QFS_SIZE_INFO:
+ case RAW_QFS_SIZE_INFORMATION:
+ QFS_CHECK_SIZE(24);
+ fsinfo->size_info.out.total_alloc_units = BVAL(blob.data, 0);
+ fsinfo->size_info.out.avail_alloc_units = BVAL(blob.data, 8);
+ fsinfo->size_info.out.sectors_per_unit = IVAL(blob.data, 16);
+ fsinfo->size_info.out.bytes_per_sector = IVAL(blob.data, 20);
+ break;
+
+ case RAW_QFS_DEVICE_INFO:
+ case RAW_QFS_DEVICE_INFORMATION:
+ QFS_CHECK_SIZE(8);
+ fsinfo->device_info.out.device_type = IVAL(blob.data, 0);
+ fsinfo->device_info.out.characteristics = IVAL(blob.data, 4);
+ break;
+
+ case RAW_QFS_ATTRIBUTE_INFO:
+ case RAW_QFS_ATTRIBUTE_INFORMATION:
+ QFS_CHECK_MIN_SIZE(12);
+ fsinfo->attribute_info.out.fs_attr = IVAL(blob.data, 0);
+ fsinfo->attribute_info.out.max_file_component_length = IVAL(blob.data, 4);
+ cli_blob_pull_string(session, mem_ctx, &blob,
+ &fsinfo->attribute_info.out.fs_type,
+ 8, 12, STR_UNICODE);
+ break;
+
+ case RAW_QFS_UNIX_INFO:
+ QFS_CHECK_SIZE(12);
+ fsinfo->unix_info.out.major_version = SVAL(blob.data, 0);
+ fsinfo->unix_info.out.minor_version = SVAL(blob.data, 2);
+ fsinfo->unix_info.out.capability = SVAL(blob.data, 4);
+ break;
+
+ case RAW_QFS_QUOTA_INFORMATION:
+ QFS_CHECK_SIZE(48);
+ fsinfo->quota_information.out.unknown[0] = BVAL(blob.data, 0);
+ fsinfo->quota_information.out.unknown[1] = BVAL(blob.data, 8);
+ fsinfo->quota_information.out.unknown[2] = BVAL(blob.data, 16);
+ fsinfo->quota_information.out.quota_soft = BVAL(blob.data, 24);
+ fsinfo->quota_information.out.quota_hard = BVAL(blob.data, 32);
+ fsinfo->quota_information.out.quota_flags = BVAL(blob.data, 40);
+ break;
+
+ case RAW_QFS_FULL_SIZE_INFORMATION:
+ QFS_CHECK_SIZE(32);
+ fsinfo->full_size_information.out.total_alloc_units = BVAL(blob.data, 0);
+ fsinfo->full_size_information.out.call_avail_alloc_units = BVAL(blob.data, 8);
+ fsinfo->full_size_information.out.actual_avail_alloc_units = BVAL(blob.data, 16);
+ fsinfo->full_size_information.out.sectors_per_unit = IVAL(blob.data, 24);
+ fsinfo->full_size_information.out.bytes_per_sector = IVAL(blob.data, 28);
+ break;
+
+ case RAW_QFS_OBJECTID_INFORMATION:
+ QFS_CHECK_SIZE(64);
+ memcpy(fsinfo->objectid_information.out.guid.info, blob.data, GUID_SIZE);
+ for (i=0;i<6;i++) {
+ fsinfo->objectid_information.out.unknown[i] = BVAL(blob.data, 16 + i*8);
+ }
+ break;
+ }
+
+failed:
+ return status;
+}
+
+/****************************************************************************
+ Query FSInfo raw interface (sync interface)
+****************************************************************************/
+NTSTATUS smb_raw_fsinfo(struct cli_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ union smb_fsinfo *fsinfo)
+{
+ struct cli_request *req = smb_raw_fsinfo_send(tree, mem_ctx, fsinfo);
+ return smb_raw_fsinfo_recv(req, mem_ctx, fsinfo);
+}
diff --git a/source4/libcli/raw/rawioctl.c b/source4/libcli/raw/rawioctl.c
new file mode 100644
index 0000000000..506bddd497
--- /dev/null
+++ b/source4/libcli/raw/rawioctl.c
@@ -0,0 +1,118 @@
+/*
+ Unix SMB/CIFS implementation.
+ client file operations
+ Copyright (C) Andrew Tridgell 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#define SETUP_REQUEST(cmd, wct, buflen) do { \
+ req = cli_request_setup(tree, cmd, wct, buflen); \
+ if (!req) return NULL; \
+} while (0)
+
+/*
+ send a raw ioctl - async send
+*/
+struct cli_request *smb_raw_ioctl_send(struct cli_tree *tree, struct smb_ioctl *parms)
+{
+ struct cli_request *req;
+
+ SETUP_REQUEST(SMBioctl, 3, 0);
+
+ SSVAL(req->out.vwv, VWV(0), parms->in.fnum);
+ SIVAL(req->out.vwv, VWV(1), parms->in.request);
+
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+/*
+ send a raw ioctl - async recv
+*/
+NTSTATUS smb_raw_ioctl_recv(struct cli_request *req, TALLOC_CTX *mem_ctx, struct smb_ioctl *parms)
+{
+ if (!cli_request_receive(req) ||
+ cli_request_is_error(req)) {
+ return cli_request_destroy(req);
+ }
+
+ parms->out.blob = cli_req_pull_blob(req, mem_ctx, req->in.data, -1);
+ return cli_request_destroy(req);
+}
+
+/*
+ send a raw ioctl - sync interface
+*/
+NTSTATUS smb_raw_ioctl(struct cli_tree *tree, TALLOC_CTX *mem_ctx, struct smb_ioctl *parms)
+{
+ struct cli_request *req = smb_raw_ioctl_send(tree, parms);
+ return smb_raw_ioctl_recv(req, mem_ctx, parms);
+}
+
+
+
+
+/****************************************************************************
+NT ioctl (async send)
+****************************************************************************/
+struct cli_request *smb_raw_ntioctl_send(struct cli_tree *tree,
+ struct smb_ntioctl *parms)
+{
+ struct smb_nttrans nt;
+ uint16 setup[4];
+
+ nt.in.max_setup = 0;
+ nt.in.max_param = 0;
+ nt.in.max_data = 0;
+ nt.in.setup_count = 4;
+ nt.in.setup = setup;
+ SIVAL(setup, 0, parms->in.function);
+ SSVAL(setup, 4, parms->in.fnum);
+ SCVAL(setup, 6, parms->in.fsctl);
+ SCVAL(setup, 7, parms->in.filter);
+ nt.in.function = NT_TRANSACT_IOCTL;
+ nt.in.params = data_blob(NULL, 0);
+ nt.in.data = data_blob(NULL, 0);
+
+ return smb_raw_nttrans_send(tree, &nt);
+}
+
+/****************************************************************************
+NT ioctl (async recv)
+****************************************************************************/
+NTSTATUS smb_raw_ntioctl_recv(struct cli_request *req,
+ struct smb_ntioctl *parms)
+{
+ struct smb_nttrans nt;
+
+ return smb_raw_nttrans_recv(req, req->mem_ctx, &nt);
+}
+
+/****************************************************************************
+NT ioctl (sync interface)
+****************************************************************************/
+NTSTATUS smb_raw_ntioctl(struct cli_tree *tree,
+ struct smb_ntioctl *parms)
+{
+ struct cli_request *req = smb_raw_ntioctl_send(tree, parms);
+ return smb_raw_ntioctl_recv(req, parms);
+}
diff --git a/source4/libcli/raw/rawnegotiate.c b/source4/libcli/raw/rawnegotiate.c
new file mode 100644
index 0000000000..78b2e00706
--- /dev/null
+++ b/source4/libcli/raw/rawnegotiate.c
@@ -0,0 +1,157 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB client negotiate context management functions
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) James Myers 2003 <myersjj@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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static const struct {
+ int prot;
+ const char *name;
+} 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_LANMAN1,"Windows for Workgroups 3.1a"},
+ {PROTOCOL_LANMAN2,"LM1.2X002"},
+ {PROTOCOL_LANMAN2,"DOS LANMAN2.1"},
+ {PROTOCOL_LANMAN2,"Samba"},
+ {PROTOCOL_NT1,"NT LANMAN 1.0"},
+ {PROTOCOL_NT1,"NT LM 0.12"},
+};
+
+/****************************************************************************
+ Send a negprot command.
+****************************************************************************/
+struct cli_request *smb_negprot_send(struct cli_transport *transport, int maxprotocol)
+{
+ struct cli_request *req;
+ int i;
+
+ req = cli_request_setup_transport(transport, SMBnegprot, 0, 0);
+ if (!req) {
+ return NULL;
+ }
+
+ /* setup the protocol strings */
+ for (i=0; i < ARRAY_SIZE(prots) && prots[i].prot <= maxprotocol; i++) {
+ cli_req_append_bytes(req, "\2", 1);
+ cli_req_append_string(req, prots[i].name, STR_TERMINATE | STR_ASCII);
+ }
+
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+/****************************************************************************
+ Send a negprot command.
+****************************************************************************/
+NTSTATUS smb_raw_negotiate(struct cli_transport *transport)
+{
+ struct cli_request *req;
+ int protocol;
+
+ req = smb_negprot_send(transport, PROTOCOL_NT1);
+ if (!req) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!cli_request_receive(req) ||
+ cli_request_is_error(req)) {
+ return cli_request_destroy(req);
+ }
+
+ CLI_CHECK_MIN_WCT(req, 1);
+
+ protocol = SVALS(req->in.vwv, VWV(0));
+
+ if (protocol >= ARRAY_SIZE(prots) || protocol < 0) {
+ req->status = NT_STATUS_UNSUCCESSFUL;
+ return cli_request_destroy(req);
+ }
+
+ transport->negotiate.protocol = prots[protocol].prot;
+
+ if (transport->negotiate.protocol >= PROTOCOL_NT1) {
+ NTTIME ntt;
+
+ /* NT protocol */
+ CLI_CHECK_WCT(req, 17);
+ transport->negotiate.sec_mode = CVAL(req->in.vwv,VWV(1));
+ transport->negotiate.max_mux = SVAL(req->in.vwv,VWV(1)+1);
+ transport->negotiate.max_xmit = IVAL(req->in.vwv,VWV(3)+1);
+ transport->negotiate.sesskey = IVAL(req->in.vwv,VWV(7)+1);
+ transport->negotiate.server_zone = SVALS(req->in.vwv,VWV(15)+1) * 60;
+
+ /* this time arrives in real GMT */
+ ntt = cli_pull_nttime(req->in.vwv, VWV(11)+1);
+ transport->negotiate.server_time = nt_time_to_unix(&ntt);
+ transport->negotiate.capabilities = IVAL(req->in.vwv,VWV(9)+1);
+
+ transport->negotiate.secblob = cli_req_pull_blob(req, transport->mem_ctx, req->in.data, req->in.data_size);
+ if (transport->negotiate.capabilities & CAP_RAW_MODE) {
+ transport->negotiate.readbraw_supported = True;
+ transport->negotiate.writebraw_supported = True;
+ }
+
+ /* work out if they sent us a workgroup */
+ if ((transport->negotiate.capabilities & CAP_EXTENDED_SECURITY) &&
+ req->in.data_size > 16) {
+ cli_req_pull_string(req, transport->mem_ctx, &transport->negotiate.server_domain,
+ req->in.data+16,
+ req->in.data_size-16, STR_UNICODE|STR_NOALIGN);
+ }
+ } else if (transport->negotiate.protocol >= PROTOCOL_LANMAN1) {
+ CLI_CHECK_WCT(req, 13);
+ transport->negotiate.sec_mode = SVAL(req->in.vwv,VWV(1));
+ transport->negotiate.max_xmit = SVAL(req->in.vwv,VWV(2));
+ transport->negotiate.sesskey = IVAL(req->in.vwv,VWV(6));
+ transport->negotiate.server_zone = SVALS(req->in.vwv,VWV(10)) * 60;
+
+ /* this time is converted to GMT by make_unix_date */
+ transport->negotiate.server_time = make_unix_date(req->in.vwv+VWV(8));
+ if ((SVAL(req->in.vwv,VWV(5)) & 0x1)) {
+ transport->negotiate.readbraw_supported = 1;
+ }
+ if ((SVAL(req->in.vwv,VWV(5)) & 0x2)) {
+ transport->negotiate.writebraw_supported = 1;
+ }
+ transport->negotiate.secblob = cli_req_pull_blob(req, transport->mem_ctx,
+ req->in.data, req->in.data_size);
+ } else {
+ /* the old core protocol */
+ transport->negotiate.sec_mode = 0;
+ transport->negotiate.server_time = time(NULL);
+ transport->negotiate.max_xmit = ~0;
+ transport->negotiate.server_zone = TimeDiff(time(NULL));
+ }
+
+ /* a way to force ascii SMB */
+ if (getenv("CLI_FORCE_ASCII")) {
+ transport->negotiate.capabilities &= ~CAP_UNICODE;
+ }
+
+failed:
+ return cli_request_destroy(req);
+}
diff --git a/source4/libcli/raw/rawnotify.c b/source4/libcli/raw/rawnotify.c
new file mode 100644
index 0000000000..7d635da0dc
--- /dev/null
+++ b/source4/libcli/raw/rawnotify.c
@@ -0,0 +1,116 @@
+/*
+ Unix SMB/CIFS implementation.
+ client change notify operations
+ Copyright (C) Andrew Tridgell 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+change notify (async send)
+****************************************************************************/
+struct cli_request *smb_raw_changenotify_send(struct cli_tree *tree, struct smb_notify *parms)
+{
+ struct smb_nttrans nt;
+ uint16 setup[4];
+
+ nt.in.max_setup = 0;
+ nt.in.max_param = parms->in.buffer_size;
+ nt.in.max_data = 0;
+ nt.in.setup_count = 4;
+ nt.in.setup = setup;
+ SIVAL(setup, 0, parms->in.completion_filter);
+ SSVAL(setup, 4, parms->in.fnum);
+ SSVAL(setup, 6, parms->in.recursive);
+ nt.in.function = NT_TRANSACT_NOTIFY_CHANGE;
+ nt.in.params = data_blob(NULL, 0);
+ nt.in.data = data_blob(NULL, 0);
+
+ return smb_raw_nttrans_send(tree, &nt);
+}
+
+/****************************************************************************
+change notify (async recv)
+****************************************************************************/
+NTSTATUS smb_raw_changenotify_recv(struct cli_request *req,
+ TALLOC_CTX *mem_ctx, struct smb_notify *parms)
+{
+ struct smb_nttrans nt;
+ NTSTATUS status;
+ uint32 ofs, i;
+ struct cli_session *session = req?req->session:NULL;
+
+ status = smb_raw_nttrans_recv(req, mem_ctx, &nt);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ parms->out.changes = NULL;
+ parms->out.num_changes = 0;
+
+ /* count them */
+ for (ofs=0; nt.out.params.length - ofs > 12; ) {
+ uint32 next = IVAL(nt.out.params.data, ofs);
+ parms->out.num_changes++;
+ if (next == 0 ||
+ ofs + next >= nt.out.params.length) break;
+ ofs += next;
+ }
+
+ /* allocate array */
+ parms->out.changes = talloc(mem_ctx, sizeof(parms->out.changes[0]) *
+ parms->out.num_changes);
+ if (!parms->out.changes) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=ofs=0; i<parms->out.num_changes; i++) {
+ parms->out.changes[i].action = IVAL(nt.out.params.data, ofs+4);
+ cli_blob_pull_string(session, mem_ctx, &nt.out.params,
+ &parms->out.changes[i].name,
+ ofs+8, ofs+12, STR_UNICODE);
+ ofs += IVAL(nt.out.params.data, ofs);
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/****************************************************************************
+ Send a NT Cancel request - used to hurry along a pending request. Usually
+ used to cancel a pending change notify request
+ note that this request does not expect a response!
+****************************************************************************/
+NTSTATUS smb_raw_ntcancel(struct cli_request *oldreq)
+{
+ struct cli_request *req;
+
+ req = cli_request_setup_transport(oldreq->transport, SMBntcancel, 0, 0);
+
+ SSVAL(req->out.hdr, HDR_MID, SVAL(oldreq->out.hdr, HDR_MID));
+ SSVAL(req->out.hdr, HDR_PID, SVAL(oldreq->out.hdr, HDR_PID));
+ SSVAL(req->out.hdr, HDR_TID, SVAL(oldreq->out.hdr, HDR_TID));
+ SSVAL(req->out.hdr, HDR_UID, SVAL(oldreq->out.hdr, HDR_UID));
+
+ /* this request does not expect a reply, so tell the signing
+ subsystem not to allocate an id for a reply */
+ req->one_way_request = 1;
+
+ cli_request_send(req);
+
+ return cli_request_destroy(req);
+}
diff --git a/source4/libcli/raw/rawreadwrite.c b/source4/libcli/raw/rawreadwrite.c
new file mode 100644
index 0000000000..84c7e3c00f
--- /dev/null
+++ b/source4/libcli/raw/rawreadwrite.c
@@ -0,0 +1,321 @@
+/*
+ Unix SMB/CIFS implementation.
+ client file read/write routines
+ Copyright (C) Andrew Tridgell 1994-1998
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#define SETUP_REQUEST(cmd, wct, buflen) do { \
+ req = cli_request_setup(tree, cmd, wct, buflen); \
+ if (!req) return NULL; \
+} while (0)
+
+
+/****************************************************************************
+ low level read operation (async send)
+****************************************************************************/
+struct cli_request *smb_raw_read_send(struct cli_tree *tree, union smb_read *parms)
+{
+ BOOL bigoffset = False;
+ struct cli_request *req;
+
+ switch (parms->generic.level) {
+ case RAW_READ_GENERIC:
+ return NULL;
+
+ case RAW_READ_READBRAW:
+ if (parms->readbraw.in.offset >= 0x80000000) {
+ bigoffset = True;
+ }
+ SETUP_REQUEST(SMBreadbraw, bigoffset? 10:8, 0);
+ SSVAL(req->out.vwv, VWV(0), parms->readbraw.in.fnum);
+ SIVAL(req->out.vwv, VWV(1), parms->readbraw.in.offset);
+ SSVAL(req->out.vwv, VWV(3), parms->readbraw.in.maxcnt);
+ SSVAL(req->out.vwv, VWV(4), parms->readbraw.in.mincnt);
+ SIVAL(req->out.vwv, VWV(5), parms->readbraw.in.timeout);
+ SSVAL(req->out.vwv, VWV(7), 0); /* reserved */
+ if (bigoffset) {
+ SIVAL(req->out.vwv, VWV(8),parms->readbraw.in.offset>>32);
+ }
+ break;
+
+ case RAW_READ_LOCKREAD:
+ SETUP_REQUEST(SMBlockread, 5, 0);
+ SSVAL(req->out.vwv, VWV(0), parms->lockread.in.fnum);
+ SSVAL(req->out.vwv, VWV(1), parms->lockread.in.count);
+ SIVAL(req->out.vwv, VWV(2), parms->lockread.in.offset);
+ SSVAL(req->out.vwv, VWV(4), parms->lockread.in.remaining);
+ break;
+
+ case RAW_READ_READ:
+ SETUP_REQUEST(SMBread, 5, 0);
+ SSVAL(req->out.vwv, VWV(0), parms->read.in.fnum);
+ SSVAL(req->out.vwv, VWV(1), parms->read.in.count);
+ SIVAL(req->out.vwv, VWV(2), parms->read.in.offset);
+ SSVAL(req->out.vwv, VWV(4), parms->read.in.remaining);
+ break;
+
+ case RAW_READ_READX:
+ if (parms->readx.in.offset >= 0x80000000) {
+ bigoffset = True;
+ }
+ SETUP_REQUEST(SMBreadX, bigoffset ? 12 : 10, 0);
+ SSVAL(req->out.vwv, VWV(0), 0xFF);
+ SSVAL(req->out.vwv, VWV(1), 0);
+ SSVAL(req->out.vwv, VWV(2), parms->readx.in.fnum);
+ SIVAL(req->out.vwv, VWV(3), parms->readx.in.offset);
+ SSVAL(req->out.vwv, VWV(5), parms->readx.in.maxcnt);
+ SSVAL(req->out.vwv, VWV(6), parms->readx.in.mincnt);
+ SIVAL(req->out.vwv, VWV(7), 0); /* reserved */
+ SSVAL(req->out.vwv, VWV(9), parms->readx.in.remaining);
+ if (bigoffset) {
+ SIVAL(req->out.vwv, VWV(10),parms->readx.in.offset>>32);
+ }
+ break;
+ }
+
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+
+ /* the transport layer needs to know that a readbraw is pending
+ and handle receives a little differently */
+ if (parms->generic.level == RAW_READ_READBRAW) {
+ tree->session->transport->readbraw_pending = 1;
+ }
+
+ return req;
+}
+
+/****************************************************************************
+ low level read operation (async recv)
+****************************************************************************/
+NTSTATUS smb_raw_read_recv(struct cli_request *req, union smb_read *parms)
+{
+ if (!cli_request_receive(req) ||
+ cli_request_is_error(req)) {
+ goto failed;
+ }
+
+ switch (parms->generic.level) {
+ case RAW_READ_GENERIC:
+ /* handled in _send() */
+ break;
+
+ case RAW_READ_READBRAW:
+ parms->readbraw.out.nread = req->in.size - NBT_HDR_SIZE;
+ if (parms->readbraw.out.nread >
+ MAX(parms->readx.in.mincnt, parms->readx.in.maxcnt)) {
+ req->status = NT_STATUS_BUFFER_TOO_SMALL;
+ goto failed;
+ }
+ memcpy(parms->readbraw.out.data, req->in.buffer + NBT_HDR_SIZE, parms->readbraw.out.nread);
+ break;
+
+ case RAW_READ_LOCKREAD:
+ CLI_CHECK_WCT(req, 5);
+ parms->lockread.out.nread = SVAL(req->in.vwv, VWV(0));
+ if (parms->lockread.out.nread > parms->lockread.in.count ||
+ !cli_raw_pull_data(req, req->in.data+3,
+ parms->lockread.out.nread, parms->lockread.out.data)) {
+ req->status = NT_STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case RAW_READ_READ:
+ /* there are 4 reserved words in the reply */
+ CLI_CHECK_WCT(req, 5);
+ parms->read.out.nread = SVAL(req->in.vwv, VWV(0));
+ if (parms->read.out.nread > parms->read.in.count ||
+ !cli_raw_pull_data(req, req->in.data+3,
+ parms->read.out.nread, parms->read.out.data)) {
+ req->status = NT_STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+
+ case RAW_READ_READX:
+ /* there are 5 reserved words in the reply */
+ CLI_CHECK_WCT(req, 12);
+ parms->readx.out.remaining = SVAL(req->in.vwv, VWV(2));
+ parms->readx.out.compaction_mode = SVAL(req->in.vwv, VWV(3));
+ parms->readx.out.nread = SVAL(req->in.vwv, VWV(5));
+ if (parms->readx.out.nread > MAX(parms->readx.in.mincnt, parms->readx.in.maxcnt) ||
+ !cli_raw_pull_data(req, req->in.hdr + SVAL(req->in.vwv, VWV(6)),
+ parms->readx.out.nread,
+ parms->readx.out.data)) {
+ req->status = NT_STATUS_BUFFER_TOO_SMALL;
+ }
+ break;
+ }
+
+failed:
+ return cli_request_destroy(req);
+}
+
+/****************************************************************************
+ low level read operation (sync interface)
+****************************************************************************/
+NTSTATUS smb_raw_read(struct cli_tree *tree, union smb_read *parms)
+{
+ struct cli_request *req = smb_raw_read_send(tree, parms);
+ return smb_raw_read_recv(req, parms);
+}
+
+
+/****************************************************************************
+ raw write interface (async send)
+****************************************************************************/
+struct cli_request *smb_raw_write_send(struct cli_tree *tree, union smb_write *parms)
+{
+ BOOL bigoffset = False;
+ struct cli_request *req;
+
+ switch (parms->generic.level) {
+ case RAW_WRITE_GENERIC:
+ return NULL;
+
+ case RAW_WRITE_WRITEUNLOCK:
+ SETUP_REQUEST(SMBwriteunlock, 5, 3 + parms->writeunlock.in.count);
+ SSVAL(req->out.vwv, VWV(0), parms->writeunlock.in.fnum);
+ SSVAL(req->out.vwv, VWV(1), parms->writeunlock.in.count);
+ SIVAL(req->out.vwv, VWV(2), parms->writeunlock.in.offset);
+ SSVAL(req->out.vwv, VWV(4), parms->writeunlock.in.remaining);
+ SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
+ SSVAL(req->out.data, 1, parms->writeunlock.in.count);
+ if (parms->writeunlock.in.count > 0) {
+ memcpy(req->out.data+3, parms->writeunlock.in.data,
+ parms->writeunlock.in.count);
+ }
+ break;
+
+ case RAW_WRITE_WRITE:
+ SETUP_REQUEST(SMBwrite, 5, 3 + parms->write.in.count);
+ SSVAL(req->out.vwv, VWV(0), parms->write.in.fnum);
+ SSVAL(req->out.vwv, VWV(1), parms->write.in.count);
+ SIVAL(req->out.vwv, VWV(2), parms->write.in.offset);
+ SSVAL(req->out.vwv, VWV(4), parms->write.in.remaining);
+ SCVAL(req->out.data, 0, SMB_DATA_BLOCK);
+ SSVAL(req->out.data, 1, parms->write.in.count);
+ if (parms->write.in.count > 0) {
+ memcpy(req->out.data+3, parms->write.in.data, parms->write.in.count);
+ }
+ break;
+
+ case RAW_WRITE_WRITECLOSE:
+ SETUP_REQUEST(SMBwriteclose, 6, 1 + parms->writeclose.in.count);
+ SSVAL(req->out.vwv, VWV(0), parms->writeclose.in.fnum);
+ SSVAL(req->out.vwv, VWV(1), parms->writeclose.in.count);
+ SIVAL(req->out.vwv, VWV(2), parms->writeclose.in.offset);
+ put_dos_date3(req->out.vwv, VWV(4), parms->writeclose.in.mtime);
+ SCVAL(req->out.data, 0, 0);
+ if (parms->writeclose.in.count > 0) {
+ memcpy(req->out.data+1, parms->writeclose.in.data,
+ parms->writeclose.in.count);
+ }
+ break;
+
+ case RAW_WRITE_WRITEX:
+ if (parms->writex.in.offset >= 0x80000000) {
+ bigoffset = True;
+ }
+ SETUP_REQUEST(SMBwriteX, bigoffset ? 14 : 12, parms->writex.in.count);
+ SSVAL(req->out.vwv, VWV(0), 0xFF);
+ SSVAL(req->out.vwv, VWV(1), 0);
+ SSVAL(req->out.vwv, VWV(2), parms->writex.in.fnum);
+ SIVAL(req->out.vwv, VWV(3), parms->writex.in.offset);
+ SIVAL(req->out.vwv, VWV(5), 0); /* reserved */
+ SSVAL(req->out.vwv, VWV(7), parms->writex.in.wmode);
+ SSVAL(req->out.vwv, VWV(8), parms->writex.in.remaining);
+ SSVAL(req->out.vwv, VWV(9), 0); /* reserved */
+ SSVAL(req->out.vwv, VWV(10), parms->writex.in.count);
+ SSVAL(req->out.vwv, VWV(11), PTR_DIFF(req->out.data, req->out.hdr));
+ if (bigoffset) {
+ SIVAL(req->out.vwv,VWV(12),parms->writex.in.offset>>32);
+ }
+ if (parms->writex.in.count > 0) {
+ memcpy(req->out.data, parms->writex.in.data, parms->writex.in.count);
+ }
+ break;
+
+ case RAW_WRITE_SPLWRITE:
+ SETUP_REQUEST(SMBsplwr, 1, parms->splwrite.in.count);
+ SSVAL(req->out.vwv, VWV(0), parms->splwrite.in.fnum);
+ if (parms->splwrite.in.count > 0) {
+ memcpy(req->out.data, parms->splwrite.in.data, parms->splwrite.in.count);
+ }
+ break;
+ }
+
+ if (!cli_request_send(req)) {
+cli_request_destroy(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+
+/****************************************************************************
+ raw write interface (async recv)
+****************************************************************************/
+NTSTATUS smb_raw_write_recv(struct cli_request *req, union smb_write *parms)
+{
+ if (!cli_request_receive(req) ||
+ cli_request_is_error(req)) {
+ goto failed;
+ }
+
+ switch (parms->generic.level) {
+ case RAW_WRITE_GENERIC:
+ break;
+ case RAW_WRITE_WRITEUNLOCK:
+ CLI_CHECK_WCT(req, 1);
+ parms->writeunlock.out.nwritten = SVAL(req->in.vwv, VWV(0));
+ break;
+ case RAW_WRITE_WRITE:
+ CLI_CHECK_WCT(req, 1);
+ parms->write.out.nwritten = SVAL(req->in.vwv, VWV(0));
+ break;
+ case RAW_WRITE_WRITECLOSE:
+ CLI_CHECK_WCT(req, 1);
+ parms->writeclose.out.nwritten = SVAL(req->in.vwv, VWV(0));
+ break;
+ case RAW_WRITE_WRITEX:
+ CLI_CHECK_WCT(req, 6);
+ parms->writex.out.nwritten = SVAL(req->in.vwv, VWV(2));
+ parms->writex.out.nwritten += (CVAL(req->in.vwv, VWV(4)) << 16);
+ parms->writex.out.remaining = SVAL(req->in.vwv, VWV(3));
+ break;
+ case RAW_WRITE_SPLWRITE:
+ break;
+ }
+
+failed:
+ return cli_request_destroy(req);
+}
+
+/****************************************************************************
+ raw write interface (sync interface)
+****************************************************************************/
+NTSTATUS smb_raw_write(struct cli_tree *tree, union smb_write *parms)
+{
+ struct cli_request *req = smb_raw_write_send(tree, parms);
+ return smb_raw_write_recv(req, parms);
+}
diff --git a/source4/libcli/raw/rawrequest.c b/source4/libcli/raw/rawrequest.c
new file mode 100644
index 0000000000..9c2b2c7367
--- /dev/null
+++ b/source4/libcli/raw/rawrequest.c
@@ -0,0 +1,1019 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) James Myers 2003 <myersjj@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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+ this file implements functions for manipulating the 'struct cli_request' structure in libsmb
+*/
+
+#include "includes.h"
+
+/* we over allocate the data buffer to prevent too many realloc calls */
+#define REQ_OVER_ALLOCATION 256
+
+/* assume that a character will not consume more than 3 bytes per char */
+#define MAX_BYTES_PER_CHAR 3
+
+/* destroy a request structure and return final status */
+NTSTATUS cli_request_destroy(struct cli_request *req)
+{
+ NTSTATUS status;
+
+ /* this is the error code we give the application for when a
+ _send() call fails completely */
+ if (!req) return NT_STATUS_UNSUCCESSFUL;
+
+ /* remove it from the list of pending requests (a null op if
+ its not in the list) */
+ DLIST_REMOVE(req->transport->pending_requests, req);
+
+ /* ahh, its so nice to destroy a complex structure in such a
+ simple way! */
+ status = req->status;
+ talloc_destroy(req->mem_ctx);
+ return status;
+}
+
+
+/*
+ low-level function to setup a request buffer for a non-SMB packet
+ at the transport level
+*/
+struct cli_request *cli_request_setup_nonsmb(struct cli_transport *transport, uint_t size)
+{
+ struct cli_request *req;
+ TALLOC_CTX *mem_ctx;
+
+ /* each request gets its own talloc context. The request
+ structure itself is also allocated inside this context,
+ so we need to allocate it before we construct the request
+ */
+ mem_ctx = talloc_init("cli_request");
+ if (!mem_ctx) {
+ return NULL;
+ }
+
+ req = talloc(mem_ctx, sizeof(struct cli_request));
+ if (!req) {
+ return NULL;
+ }
+ ZERO_STRUCTP(req);
+
+ /* setup the request context */
+ req->mem_ctx = mem_ctx;
+ req->transport = transport;
+ req->session = NULL;
+ req->tree = NULL;
+ req->out.size = size;
+
+ /* over allocate by a small amount */
+ req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
+
+ req->out.buffer = talloc(req->mem_ctx, req->out.allocated);
+ if (!req->out.buffer) {
+ return NULL;
+ }
+
+ SIVAL(req->out.buffer, 0, 0);
+
+ return req;
+}
+
+
+/*
+ setup a SMB packet at transport level
+*/
+struct cli_request *cli_request_setup_transport(struct cli_transport *transport,
+ uint8 command, unsigned wct, unsigned buflen)
+{
+ struct cli_request *req;
+
+ req = cli_request_setup_nonsmb(transport, NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen);
+
+ if (!req) return NULL;
+
+ req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
+ req->out.vwv = req->out.hdr + HDR_VWV;
+ req->out.wct = wct;
+ req->out.data = req->out.vwv + VWV(wct) + 2;
+ req->out.data_size = buflen;
+ req->out.ptr = req->out.data;
+
+ SCVAL(req->out.hdr, HDR_WCT, wct);
+ SSVAL(req->out.vwv, VWV(wct), buflen);
+
+ memcpy(req->out.hdr, "\377SMB", 4);
+ SCVAL(req->out.hdr,HDR_COM,command);
+
+ SCVAL(req->out.hdr,HDR_FLG, FLAG_CASELESS_PATHNAMES);
+ SSVAL(req->out.hdr,HDR_FLG2, 0);
+
+ /* assign a mid */
+ req->mid = cli_transport_next_mid(transport);
+
+ /* copy the pid, uid and mid to the request */
+ SSVAL(req->out.hdr, HDR_PID, 0);
+ SSVAL(req->out.hdr, HDR_UID, 0);
+ SSVAL(req->out.hdr, HDR_MID, req->mid);
+ SSVAL(req->out.hdr, HDR_TID,0);
+ SSVAL(req->out.hdr, HDR_PIDHIGH,0);
+ SIVAL(req->out.hdr, HDR_RCLS, 0);
+ memset(req->out.hdr+HDR_SS_FIELD, 0, 10);
+
+ return req;
+}
+
+/*
+ setup a reply in req->out with the given word count and initial data
+ buffer size. the caller will then fill in the command words and
+ data before calling cli_request_send() to send the reply on its
+ way. This interface is used before a session is setup.
+*/
+struct cli_request *cli_request_setup_session(struct cli_session *session,
+ uint8 command, unsigned wct, unsigned buflen)
+{
+ struct cli_request *req;
+ uint16 flags2;
+ uint32 capabilities;
+
+ req = cli_request_setup_transport(session->transport, command, wct, buflen);
+
+ if (!req) return NULL;
+
+ req->session = session;
+
+ flags2 = FLAGS2_LONG_PATH_COMPONENTS;
+ capabilities = session->transport->negotiate.capabilities;
+
+ if (capabilities & CAP_UNICODE) {
+ flags2 |= FLAGS2_UNICODE_STRINGS;
+ }
+ if (capabilities & CAP_STATUS32) {
+ flags2 |= FLAGS2_32_BIT_ERROR_CODES;
+ }
+ if (capabilities & CAP_EXTENDED_SECURITY) {
+ flags2 |= FLAGS2_EXTENDED_SECURITY;
+ }
+ if (session->transport->negotiate.sign_info.doing_signing) {
+ flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
+ }
+
+ SSVAL(req->out.hdr, HDR_FLG2, flags2);
+ SSVAL(req->out.hdr, HDR_PID, session->pid);
+ SSVAL(req->out.hdr, HDR_UID, session->vuid);
+
+ return req;
+}
+
+/*
+ setup a request for tree based commands
+*/
+struct cli_request *cli_request_setup(struct cli_tree *tree,
+ uint8 command,
+ unsigned wct, unsigned buflen)
+{
+ struct cli_request *req;
+
+ req = cli_request_setup_session(tree->session, command, wct, buflen);
+ if (req) {
+ req->tree = tree;
+ SSVAL(req->out.hdr,HDR_TID,tree->tid);
+ }
+ return req;
+}
+
+/*
+ grow the allocation of the data buffer portion of a reply
+ packet. Note that as this can reallocate the packet buffer this
+ invalidates any local pointers into the packet.
+
+ To cope with this req->out.ptr is supplied. This will be updated to
+ point at the same offset into the packet as before this call
+*/
+static void cli_req_grow_allocation(struct cli_request *req, unsigned new_size)
+{
+ int delta;
+ char *buf2;
+
+ delta = new_size - req->out.data_size;
+ if (delta + req->out.size <= req->out.allocated) {
+ /* it fits in the preallocation */
+ return;
+ }
+
+ /* we need to realloc */
+ req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
+ buf2 = talloc_realloc(req->mem_ctx, req->out.buffer, req->out.allocated);
+ if (buf2 == NULL) {
+ smb_panic("out of memory in req_grow_allocation");
+ }
+
+ if (buf2 == req->out.buffer) {
+ /* the malloc library gave us the same pointer */
+ return;
+ }
+
+ /* update the pointers into the packet */
+ req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
+ req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
+ req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
+ req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
+
+ req->out.buffer = buf2;
+}
+
+
+/*
+ grow the data buffer portion of a reply packet. Note that as this
+ can reallocate the packet buffer this invalidates any local pointers
+ into the packet.
+
+ To cope with this req->out.ptr is supplied. This will be updated to
+ point at the same offset into the packet as before this call
+*/
+static void cli_req_grow_data(struct cli_request *req, unsigned new_size)
+{
+ int delta;
+
+ cli_req_grow_allocation(req, new_size);
+
+ delta = new_size - req->out.data_size;
+
+ req->out.size += delta;
+ req->out.data_size += delta;
+
+ /* set the BCC to the new data size */
+ SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
+}
+
+/*
+ send a message
+*/
+BOOL cli_request_send(struct cli_request *req)
+{
+ if (IVAL(req->out.buffer, 0) == 0) {
+ _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
+ }
+
+ cli_request_calculate_sign_mac(req);
+
+ if (req->out.size != cli_sock_write(req->transport->socket, req->out.buffer, req->out.size)) {
+ req->transport->error.etype = ETYPE_SOCKET;
+ req->transport->error.e.socket_error = SOCKET_WRITE_ERROR;
+ DEBUG(0,("Error writing %d bytes to server - %s\n",
+ (int)req->out.size, strerror(errno)));
+ return False;
+ }
+
+ /* add it to the list of pending requests */
+ DLIST_ADD(req->transport->pending_requests, req);
+
+ return True;
+}
+
+
+/*
+ receive a response to a packet
+*/
+BOOL cli_request_receive(struct cli_request *req)
+{
+ /* req can be NULL when a send has failed. This eliminates lots of NULL
+ checks in each module */
+ if (!req) return False;
+
+ /* keep receiving packets until this one is replied to */
+ while (!req->in.buffer) {
+ if (!cli_transport_select(req->transport)) {
+ return False;
+ }
+
+ cli_request_receive_next(req->transport);
+ }
+
+ return True;
+}
+
+
+/*
+ handle oplock break requests from the server - return True if the request was
+ an oplock break
+*/
+static BOOL handle_oplock_break(struct cli_transport *transport, uint_t len, const char *hdr, const char *vwv)
+{
+ /* we must be very fussy about what we consider an oplock break to avoid
+ matching readbraw replies */
+ if (len != MIN_SMB_SIZE + VWV(8) ||
+ (CVAL(hdr, HDR_FLG) & FLAG_REPLY) ||
+ CVAL(hdr,HDR_COM) != SMBlockingX ||
+ SVAL(hdr, HDR_MID) != 0xFFFF ||
+ SVAL(vwv,VWV(6)) != 0 ||
+ SVAL(vwv,VWV(7)) != 0) {
+ return False;
+ }
+
+ if (transport->oplock.handler) {
+ uint16 tid = SVAL(hdr, HDR_TID);
+ uint16 fnum = SVAL(vwv,VWV(2));
+ uint8 level = CVAL(vwv,VWV(3));
+ transport->oplock.handler(transport, tid, fnum, level, transport->oplock.private);
+ }
+
+ return True;
+}
+
+
+/*
+ receive an async message from the server
+ this function assumes that the caller already knows that the socket is readable
+ and that there is a packet waiting
+
+ The packet is not actually returned by this function, instead any
+ registered async message handlers are called
+
+ return True if a packet was successfully received and processed
+ return False if the socket appears to be dead
+*/
+BOOL cli_request_receive_next(struct cli_transport *transport)
+{
+ BOOL ret;
+ int len;
+ char header[NBT_HDR_SIZE];
+ char *buffer, *hdr, *vwv;
+ TALLOC_CTX *mem_ctx;
+ struct cli_request *req;
+ uint16 wct, mid = 0;
+
+ len = cli_sock_read(transport->socket, header, 4);
+ if (len != 4) {
+ return False;
+ }
+
+ len = smb_len(header);
+
+ mem_ctx = talloc_init("cli_request_receive_next");
+
+ /* allocate the incoming buffer at the right size */
+ buffer = talloc(mem_ctx, len+NBT_HDR_SIZE);
+ if (!buffer) {
+ talloc_destroy(mem_ctx);
+ return False;
+ }
+
+ /* fill in the already received header */
+ memcpy(buffer, header, NBT_HDR_SIZE);
+
+ ret = cli_sock_read(transport->socket, buffer + NBT_HDR_SIZE, len);
+ /* If the server is not responding, note that now */
+ if (ret != len) {
+ return False;
+ }
+
+ hdr = buffer+NBT_HDR_SIZE;
+ vwv = hdr + HDR_VWV;
+
+ /* see if it could be an oplock break request */
+ if (handle_oplock_break(transport, len, hdr, vwv)) {
+ goto done;
+ }
+
+ /* at this point we need to check for a readbraw reply, as these can be any length */
+ if (transport->readbraw_pending) {
+ transport->readbraw_pending = 0;
+
+ /* it must match the first entry in the pending queue as the client is not allowed
+ to have outstanding readbraw requests */
+ req = transport->pending_requests;
+ if (!req) goto done;
+
+ req->in.buffer = buffer;
+ talloc_steal(mem_ctx, req->mem_ctx, buffer);
+ req->in.size = len + NBT_HDR_SIZE;
+ req->in.allocated = req->in.size;
+ goto async;
+ }
+
+ if (len >= MIN_SMB_SIZE) {
+ /* extract the mid for matching to pending requests */
+ mid = SVAL(hdr, HDR_MID);
+ wct = CVAL(hdr, HDR_WCT);
+ }
+
+ /* match the incoming request against the list of pending requests */
+ for (req=transport->pending_requests; req; req=req->next) {
+ if (req->mid == mid) break;
+ }
+
+ if (!req) {
+ DEBUG(3,("Discarding unmatched reply with mid %d\n", mid));
+ goto done;
+ }
+
+ /* fill in the 'in' portion of the matching request */
+ req->in.buffer = buffer;
+ talloc_steal(mem_ctx, req->mem_ctx, buffer);
+ req->in.size = len + NBT_HDR_SIZE;
+ req->in.allocated = req->in.size;
+
+ /* handle non-SMB replies */
+ if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE) {
+ goto done;
+ }
+
+ if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct)) {
+ DEBUG(2,("bad reply size for mid %d\n", mid));
+ req->status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ req->in.hdr = hdr;
+ req->in.vwv = vwv;
+ req->in.wct = wct;
+ if (req->in.size >= NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct)) {
+ req->in.data = req->in.vwv + VWV(wct) + 2;
+ req->in.data_size = SVAL(req->in.vwv, VWV(wct));
+ if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct) + req->in.data_size) {
+ DEBUG(3,("bad data size for mid %d\n", mid));
+ /* blergh - w2k3 gives a bogus data size values in some
+ openX replies */
+ req->in.data_size = req->in.size - (NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct));
+ }
+ }
+ req->in.ptr = req->in.data;
+ req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
+
+ if (!(req->flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
+ transport->error.etype = ETYPE_DOS;
+ transport->error.e.dos.eclass = CVAL(req->in.hdr,HDR_RCLS);
+ transport->error.e.dos.ecode = SVAL(req->in.hdr,HDR_ERR);
+ req->status = dos_to_ntstatus(transport->error.e.dos.eclass,
+ transport->error.e.dos.ecode);
+ } else {
+ transport->error.etype = ETYPE_NT;
+ transport->error.e.nt_status = NT_STATUS(IVAL(req->in.hdr, HDR_RCLS));
+ req->status = transport->error.e.nt_status;
+ }
+
+ if (!cli_request_check_sign_mac(req)) {
+ transport->error.etype = ETYPE_SOCKET;
+ transport->error.e.socket_error = SOCKET_READ_BAD_SIG;
+ return False;
+ };
+
+async:
+ /* if this request has an async handler then call that to
+ notify that the reply has been received. This might destroy
+ the request so it must happen last */
+ if (req->async.fn) {
+ req->async.fn(req);
+ }
+
+done:
+ talloc_destroy(mem_ctx);
+ return True;
+}
+
+
+/*
+ wait for a reply to be received for a packet that just returns an error
+ code and nothing more
+*/
+NTSTATUS cli_request_simple_recv(struct cli_request *req)
+{
+ cli_request_receive(req);
+ return cli_request_destroy(req);
+}
+
+
+/* Return true if the last packet was in error */
+BOOL cli_request_is_error(struct cli_request *req)
+{
+ return NT_STATUS_IS_ERR(req->status);
+}
+
+/*
+ append a string into the data portion of the request packet
+
+ return the number of bytes added to the packet
+*/
+size_t cli_req_append_string(struct cli_request *req, const char *str, unsigned flags)
+{
+ size_t len;
+
+ /* determine string type to use */
+ if (!(flags & (STR_ASCII|STR_UNICODE))) {
+ flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
+ }
+
+ len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;
+
+ cli_req_grow_allocation(req, len + req->out.data_size);
+
+ len = push_string(NULL, req->out.data + req->out.data_size, str, len, flags);
+
+ cli_req_grow_data(req, len + req->out.data_size);
+
+ return len;
+}
+
+/*
+ this is like cli_req_append_string but it also return the
+ non-terminated string byte length, which can be less than the number
+ of bytes consumed in the packet for 2 reasons:
+
+ 1) the string in the packet may be null terminated
+ 2) the string in the packet may need a 1 byte UCS2 alignment
+
+ this is used in places where the non-terminated string byte length is
+ placed in the packet as a separate field
+*/
+size_t cli_req_append_string_len(struct cli_request *req, const char *str, unsigned flags, int *len)
+{
+ int diff = 0;
+ size_t ret;
+
+ /* determine string type to use */
+ if (!(flags & (STR_ASCII|STR_UNICODE))) {
+ flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
+ }
+
+ /* see if an alignment byte will be used */
+ if ((flags & STR_UNICODE) && !(flags & STR_NOALIGN)) {
+ diff = ucs2_align(NULL, req->out.data + req->out.data_size, flags);
+ }
+
+ /* do the hard work */
+ ret = cli_req_append_string(req, str, flags);
+
+ /* see if we need to subtract the termination */
+ if (flags & STR_TERMINATE) {
+ diff += (flags & STR_UNICODE) ? 2 : 1;
+ }
+
+ if (ret >= diff) {
+ (*len) = ret - diff;
+ } else {
+ (*len) = ret;
+ }
+
+ return ret;
+}
+
+
+/*
+ push a string into the data portion of the request packet, growing it if necessary
+ this gets quite tricky - please be very careful to cover all cases when modifying this
+
+ if dest is NULL, then put the string at the end of the data portion of the packet
+
+ if dest_len is -1 then no limit applies
+*/
+size_t cli_req_append_ascii4(struct cli_request *req, const char *str, unsigned flags)
+{
+ size_t size;
+ cli_req_append_bytes(req, (const uint8 *)"\4", 1);
+ size = cli_req_append_string(req, str, flags);
+ return size + 1;
+}
+
+
+/*
+ push a blob into the data portion of the request packet, growing it if necessary
+ this gets quite tricky - please be very careful to cover all cases when modifying this
+
+ if dest is NULL, then put the blob at the end of the data portion of the packet
+*/
+size_t cli_req_append_blob(struct cli_request *req, const DATA_BLOB *blob)
+{
+ cli_req_grow_allocation(req, req->out.data_size + blob->length);
+ memcpy(req->out.data + req->out.data_size, blob->data, blob->length);
+ cli_req_grow_data(req, req->out.data_size + blob->length);
+ return blob->length;
+}
+
+/*
+ append raw bytes into the data portion of the request packet
+ return the number of bytes added
+*/
+size_t cli_req_append_bytes(struct cli_request *req, const uint8 *bytes, size_t byte_len)
+{
+ cli_req_grow_allocation(req, byte_len + req->out.data_size);
+ memcpy(req->out.data + req->out.data_size, bytes, byte_len);
+ cli_req_grow_data(req, byte_len + req->out.data_size);
+ return byte_len;
+}
+
+/*
+ append variable block (type 5 buffer) into the data portion of the request packet
+ return the number of bytes added
+*/
+size_t cli_req_append_var_block(struct cli_request *req, const uint8 *bytes, uint16 byte_len)
+{
+ cli_req_grow_allocation(req, byte_len + 3 + req->out.data_size);
+ SCVAL(req->out.data + req->out.data_size, 0, 5);
+ SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
+ if (byte_len > 0) {
+ memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
+ }
+ cli_req_grow_data(req, byte_len + 3 + req->out.data_size);
+ return byte_len + 3;
+}
+
+
+/*
+ pull a UCS2 string from a request packet, returning a talloced unix string
+
+ the string length is limited by the 3 things:
+ - the data size in the request (end of packet)
+ - the passed 'byte_len' if it is not -1
+ - the end of string (null termination)
+
+ Note that 'byte_len' is the number of bytes in the packet
+
+ on failure zero is returned and *dest is set to NULL, otherwise the number
+ of bytes consumed in the packet is returned
+*/
+static size_t cli_req_pull_ucs2(struct cli_request *req, TALLOC_CTX *mem_ctx,
+ char **dest, const char *src, int byte_len, unsigned flags)
+{
+ int src_len, src_len2, alignment=0;
+ ssize_t ret;
+
+ if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
+ src++;
+ alignment=1;
+ if (byte_len != -1) {
+ byte_len--;
+ }
+ }
+
+ src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
+ if (src_len < 0) {
+ *dest = NULL;
+ return 0;
+ }
+ if (byte_len != -1 && src_len > byte_len) {
+ src_len = byte_len;
+ }
+
+ src_len2 = strnlen_w((const smb_ucs2_t *)src, src_len/2) * 2;
+ if (src_len2 < src_len - 2) {
+ /* include the termination if we didn't reach the end of the packet */
+ src_len2 += 2;
+ }
+
+ /* ucs2 strings must be at least 2 bytes long */
+ if (src_len2 < 2) {
+ *dest = NULL;
+ return 0;
+ }
+
+ ret = convert_string_talloc(mem_ctx, CH_UCS2, CH_UNIX, src, src_len2, (const void **)dest);
+ if (ret == -1) {
+ *dest = NULL;
+ return 0;
+ }
+
+ return src_len2 + alignment;
+}
+
+/*
+ pull a ascii string from a request packet, returning a talloced string
+
+ the string length is limited by the 3 things:
+ - the data size in the request (end of packet)
+ - the passed 'byte_len' if it is not -1
+ - the end of string (null termination)
+
+ Note that 'byte_len' is the number of bytes in the packet
+
+ on failure zero is returned and *dest is set to NULL, otherwise the number
+ of bytes consumed in the packet is returned
+*/
+size_t cli_req_pull_ascii(struct cli_request *req, TALLOC_CTX *mem_ctx,
+ char **dest, const char *src, int byte_len, unsigned flags)
+{
+ int src_len, src_len2;
+ ssize_t ret;
+
+ src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
+ if (src_len < 0) {
+ *dest = NULL;
+ return 0;
+ }
+ if (byte_len != -1 && src_len > byte_len) {
+ src_len = byte_len;
+ }
+ src_len2 = strnlen(src, src_len);
+ if (src_len2 < src_len - 1) {
+ /* include the termination if we didn't reach the end of the packet */
+ src_len2++;
+ }
+
+ ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (const void **)dest);
+
+ if (ret == -1) {
+ *dest = NULL;
+ return 0;
+ }
+
+ return ret;
+}
+
+/*
+ pull a string from a request packet, returning a talloced string
+
+ the string length is limited by the 3 things:
+ - the data size in the request (end of packet)
+ - the passed 'byte_len' if it is not -1
+ - the end of string (null termination)
+
+ Note that 'byte_len' is the number of bytes in the packet
+
+ on failure zero is returned and *dest is set to NULL, otherwise the number
+ of bytes consumed in the packet is returned
+*/
+size_t cli_req_pull_string(struct cli_request *req, TALLOC_CTX *mem_ctx,
+ char **dest, const char *src, int byte_len, unsigned flags)
+{
+ if (!(flags & STR_ASCII) &&
+ ((flags & STR_UNICODE || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
+ return cli_req_pull_ucs2(req, mem_ctx, dest, src, byte_len, flags);
+ }
+
+ return cli_req_pull_ascii(req, mem_ctx, dest, src, byte_len, flags);
+}
+
+
+/*
+ pull a DATA_BLOB from a reply packet, returning a talloced blob
+ make sure we don't go past end of packet
+
+ if byte_len is -1 then limit the blob only by packet size
+*/
+DATA_BLOB cli_req_pull_blob(struct cli_request *req, TALLOC_CTX *mem_ctx, const char *src, int byte_len)
+{
+ int src_len;
+
+ src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
+
+ if (src_len < 0) {
+ return data_blob(NULL, 0);
+ }
+
+ if (byte_len != -1 && src_len > byte_len) {
+ src_len = byte_len;
+ }
+
+ return data_blob_talloc(mem_ctx, src, src_len);
+}
+
+/* check that a lump of data in a request is within the bounds of the data section of
+ the packet */
+static BOOL cli_req_data_oob(struct cli_request *req, const char *ptr, uint32 count)
+{
+ /* be careful with wraparound! */
+ if (ptr < req->in.data ||
+ ptr >= req->in.data + req->in.data_size ||
+ count > req->in.data_size ||
+ ptr + count > req->in.data + req->in.data_size) {
+ return True;
+ }
+ return False;
+}
+
+/*
+ pull a lump of data from a request packet
+
+ return False if any part is outside the data portion of the packet
+*/
+BOOL cli_raw_pull_data(struct cli_request *req, const char *src, int len, char *dest)
+{
+ if (len == 0) return True;
+
+ if (cli_req_data_oob(req, src, len)) {
+ return False;
+ }
+
+ memcpy(dest, src, len);
+ return True;
+}
+
+
+/*
+ put a NTTIME into a packet
+*/
+
+void cli_push_nttime(void *base, uint16 offset, NTTIME *t)
+{
+ SIVAL(base, offset, t->low);
+ SIVAL(base, offset+4, t->high);
+}
+
+/*
+ pull a NTTIME from a packet
+*/
+NTTIME cli_pull_nttime(void *base, uint16 offset)
+{
+ NTTIME ret;
+ ret.low = IVAL(base, offset);
+ ret.high = IVAL(base, offset+4);
+ return ret;
+}
+
+/*
+ pull a UCS2 string from a blob, returning a talloced unix string
+
+ the string length is limited by the 3 things:
+ - the data size in the blob
+ - the passed 'byte_len' if it is not -1
+ - the end of string (null termination)
+
+ Note that 'byte_len' is the number of bytes in the packet
+
+ on failure zero is returned and *dest is set to NULL, otherwise the number
+ of bytes consumed in the blob is returned
+*/
+static size_t cli_blob_pull_ucs2(TALLOC_CTX* mem_ctx,
+ DATA_BLOB *blob, const char **dest,
+ const char *src, int byte_len, unsigned flags)
+{
+ int src_len, src_len2, alignment=0;
+ ssize_t ret;
+
+ if (src < (const char *)blob->data ||
+ src >= (const char *)(blob->data + blob->length)) {
+ *dest = NULL;
+ return 0;
+ }
+
+ src_len = blob->length - PTR_DIFF(src, blob->data);
+
+ if (byte_len != -1 && src_len > byte_len) {
+ src_len = byte_len;
+ }
+
+ if (!(flags & STR_NOALIGN) && ucs2_align(blob->data, src, flags)) {
+ src++;
+ alignment=1;
+ src_len--;
+ }
+
+ if (src_len < 2) {
+ *dest = NULL;
+ return 0;
+ }
+
+ src_len2 = strnlen_w((const smb_ucs2_t *)src, src_len/2) * 2;
+
+ if (src_len2 < src_len - 2) {
+ /* include the termination if we didn't reach the end of the packet */
+ src_len2 += 2;
+ }
+
+ ret = convert_string_talloc(mem_ctx, CH_UCS2, CH_UNIX, src, src_len2, (const void **)dest);
+ if (ret == -1) {
+ *dest = NULL;
+ return 0;
+ }
+
+ return src_len2 + alignment;
+}
+
+/*
+ pull a ascii string from a blob, returning a talloced string
+
+ the string length is limited by the 3 things:
+ - the data size in the blob
+ - the passed 'byte_len' if it is not -1
+ - the end of string (null termination)
+
+ Note that 'byte_len' is the number of bytes in the blob
+
+ on failure zero is returned and *dest is set to NULL, otherwise the number
+ of bytes consumed in the blob is returned
+*/
+static size_t cli_blob_pull_ascii(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob, const char **dest,
+ const char *src, int byte_len, unsigned flags)
+{
+ int src_len, src_len2;
+ ssize_t ret;
+
+ src_len = blob->length - PTR_DIFF(src, blob->data);
+ if (src_len < 0) {
+ *dest = NULL;
+ return 0;
+ }
+ if (byte_len != -1 && src_len > byte_len) {
+ src_len = byte_len;
+ }
+ src_len2 = strnlen(src, src_len);
+
+ if (src_len2 < src_len - 1) {
+ /* include the termination if we didn't reach the end of the packet */
+ src_len2++;
+ }
+
+ ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (const void **)dest);
+
+ if (ret == -1) {
+ *dest = NULL;
+ return 0;
+ }
+
+ return ret;
+}
+
+/*
+ pull a string from a blob, returning a talloced WIRE_STRING
+
+ the string length is limited by the 3 things:
+ - the data size in the blob
+ - length field on the wire
+ - the end of string (null termination)
+
+ if STR_LEN8BIT is set in the flags then assume the length field is
+ 8 bits, instead of 32
+
+ on failure zero is returned and dest->s is set to NULL, otherwise the number
+ of bytes consumed in the blob is returned
+*/
+size_t cli_blob_pull_string(struct cli_session *session,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob,
+ WIRE_STRING *dest,
+ uint16 len_offset, uint16 str_offset,
+ unsigned flags)
+{
+ dest->s = NULL;
+
+ if (len_offset > blob->length-4) {
+ return 0;
+ }
+ if (flags & STR_LEN8BIT) {
+ dest->private_length = CVAL(blob->data, len_offset);
+ } else {
+ dest->private_length = IVAL(blob->data, len_offset);
+ }
+ dest->s = NULL;
+ if (!(flags & STR_ASCII) &&
+ ((flags & STR_UNICODE) ||
+ (session->transport->negotiate.capabilities & CAP_UNICODE))) {
+ if ((str_offset&1) && !(flags & STR_NOALIGN)) {
+ str_offset++;
+ }
+ return cli_blob_pull_ucs2(mem_ctx, blob, &dest->s,
+ blob->data+str_offset, dest->private_length, flags);
+ }
+
+ return cli_blob_pull_ascii(mem_ctx, blob, &dest->s,
+ blob->data+str_offset, dest->private_length, flags);
+}
+
+/*
+ append a string into a blob
+*/
+size_t cli_blob_append_string(struct cli_session *session,
+ TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
+ const char *str, unsigned flags)
+{
+ size_t max_len;
+ int len;
+
+ if (!str) return 0;
+
+ /* determine string type to use */
+ if (!(flags & (STR_ASCII|STR_UNICODE))) {
+ flags |= (session->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
+ }
+
+ max_len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;
+
+ blob->data = talloc_realloc(mem_ctx, blob->data, blob->length + max_len);
+ if (!blob->data) {
+ return 0;
+ }
+
+ len = push_string(NULL, blob->data + blob->length, str, max_len, flags);
+
+ blob->length += len;
+
+ return len;
+}
diff --git a/source4/libcli/raw/rawsearch.c b/source4/libcli/raw/rawsearch.c
new file mode 100644
index 0000000000..bdc39bb68c
--- /dev/null
+++ b/source4/libcli/raw/rawsearch.c
@@ -0,0 +1,569 @@
+/*
+ Unix SMB/CIFS implementation.
+ client directory search routines
+ Copyright (C) James Myers 2003 <myersjj@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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Old style search backend - process output.
+****************************************************************************/
+static void smb_raw_search_backend(struct cli_request *req,
+ TALLOC_CTX *mem_ctx,
+ uint16 count,
+ void *private,
+ BOOL (*callback)(void *private, union smb_search_data *file))
+
+{
+ union smb_search_data search_data;
+ int i;
+ char *p;
+
+ if (req->in.data_size < 3 + count*43) {
+ req->status = NT_STATUS_INVALID_PARAMETER;
+ return;
+ }
+
+ p = req->in.data + 3;
+
+ for (i=0; i < count; i++) {
+ search_data.search.search_id = cli_req_pull_blob(req, mem_ctx, p, 21);
+ search_data.search.attrib = CVAL(p, 21);
+ search_data.search.write_time = make_unix_date(p + 22);
+ search_data.search.size = IVAL(p, 26);
+ cli_req_pull_ascii(req, mem_ctx, &search_data.search.name, p+30, 13, STR_ASCII);
+ if (!callback(private, &search_data)) {
+ break;
+ }
+ p += 43;
+ }
+}
+
+/****************************************************************************
+ Old style search first.
+****************************************************************************/
+static NTSTATUS smb_raw_search_first_old(struct cli_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ union smb_search_first *io, void *private,
+ BOOL (*callback)(void *private, union smb_search_data *file))
+
+{
+ struct cli_request *req;
+
+ req = cli_request_setup(tree, SMBsearch, 2, 0);
+ if (!req) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ SSVAL(req->out.vwv, VWV(0), io->search_first.in.max_count);
+ SSVAL(req->out.vwv, VWV(1), io->search_first.in.search_attrib);
+ cli_req_append_ascii4(req, io->search_first.in.pattern, STR_TERMINATE);
+ cli_req_append_var_block(req, NULL, 0);
+
+ if (!cli_request_send(req) ||
+ !cli_request_receive(req)) {
+ return cli_request_destroy(req);
+ }
+
+ if (NT_STATUS_IS_OK(req->status)) {
+ io->search_first.out.count = SVAL(req->in.vwv, VWV(0));
+ smb_raw_search_backend(req, mem_ctx, io->search_first.out.count, private, callback);
+ }
+
+ return cli_request_destroy(req);
+}
+
+/****************************************************************************
+ Old style search next.
+****************************************************************************/
+static NTSTATUS smb_raw_search_next_old(struct cli_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ union smb_search_next *io, void *private,
+ BOOL (*callback)(void *private, union smb_search_data *file))
+
+{
+ struct cli_request *req;
+
+ req = cli_request_setup(tree, SMBsearch, 2, 0);
+ if (!req) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ SSVAL(req->out.vwv, VWV(0), io->search_next.in.max_count);
+ SSVAL(req->out.vwv, VWV(1), io->search_next.in.search_attrib);
+ cli_req_append_ascii4(req, "", STR_TERMINATE);
+ cli_req_append_var_block(req, io->search_next.in.search_id.data, 21);
+
+ if (!cli_request_send(req) ||
+ !cli_request_receive(req)) {
+ return cli_request_destroy(req);
+ }
+
+ if (NT_STATUS_IS_OK(req->status)) {
+ io->search_next.out.count = SVAL(req->in.vwv, VWV(0));
+ smb_raw_search_backend(req, mem_ctx, io->search_next.out.count, private, callback);
+ }
+
+ return cli_request_destroy(req);
+}
+
+/****************************************************************************
+ Very raw search first - returns param/data blobs.
+****************************************************************************/
+static NTSTATUS smb_raw_search_first_blob(struct cli_tree *tree,
+ TALLOC_CTX *mem_ctx, /* used to allocate output blobs */
+ union smb_search_first *io,
+ uint16 info_level,
+ DATA_BLOB *out_param_blob,
+ DATA_BLOB *out_data_blob)
+{
+ struct smb_trans2 tp;
+ uint16 setup = TRANSACT2_FINDFIRST;
+ NTSTATUS status;
+
+ tp.in.max_setup = 0;
+ tp.in.flags = 0;
+ tp.in.timeout = 0;
+ tp.in.setup_count = 1;
+ tp.in.data = data_blob(NULL, 0);
+ tp.in.max_param = 1024;
+ tp.in.max_data = 8192;
+ tp.in.setup = &setup;
+
+ tp.in.params = data_blob_talloc(mem_ctx, NULL, 12);
+ if (!tp.in.params.data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ SSVAL(tp.in.params.data, 0, io->t2ffirst.in.search_attrib);
+ SSVAL(tp.in.params.data, 2, io->t2ffirst.in.max_count);
+ SSVAL(tp.in.params.data, 4, io->t2ffirst.in.flags);
+ SSVAL(tp.in.params.data, 6, info_level);
+ SIVAL(tp.in.params.data, 8, io->t2ffirst.in.storage_type);
+
+ cli_blob_append_string(tree->session, mem_ctx, &tp.in.params,
+ io->t2ffirst.in.pattern, STR_TERMINATE);
+
+ status = smb_raw_trans2(tree, mem_ctx, &tp);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ out_param_blob->length = tp.out.params.length;
+ out_param_blob->data = tp.out.params.data;
+ out_data_blob->length = tp.out.data.length;
+ out_data_blob->data = tp.out.data.data;
+
+ return NT_STATUS_OK;
+}
+
+
+/****************************************************************************
+ Very raw search first - returns param/data blobs.
+ Used in CIFS-on-CIFS NTVFS.
+****************************************************************************/
+static NTSTATUS smb_raw_search_next_blob(struct cli_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ union smb_search_next *io,
+ uint16 info_level,
+ DATA_BLOB *out_param_blob,
+ DATA_BLOB *out_data_blob)
+{
+ struct smb_trans2 tp;
+ uint16 setup = TRANSACT2_FINDNEXT;
+ NTSTATUS status;
+
+ tp.in.max_setup = 0;
+ tp.in.flags = 0;
+ tp.in.timeout = 0;
+ tp.in.setup_count = 1;
+ tp.in.data = data_blob(NULL, 0);
+ tp.in.max_param = 1024;
+ tp.in.max_data = 8192;
+ tp.in.setup = &setup;
+
+ tp.in.params = data_blob_talloc(mem_ctx, NULL, 12);
+ if (!tp.in.params.data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ SSVAL(tp.in.params.data, 0, io->t2fnext.in.handle);
+ SSVAL(tp.in.params.data, 2, io->t2fnext.in.max_count);
+ SSVAL(tp.in.params.data, 4, info_level);
+ SIVAL(tp.in.params.data, 6, io->t2fnext.in.resume_key);
+ SSVAL(tp.in.params.data, 10, io->t2fnext.in.flags);
+
+ cli_blob_append_string(tree->session, mem_ctx, &tp.in.params,
+ io->t2fnext.in.last_name,
+ STR_TERMINATE);
+
+ status = smb_raw_trans2(tree, mem_ctx, &tp);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ out_param_blob->length = tp.out.params.length;
+ out_param_blob->data = tp.out.params.data;
+ out_data_blob->length = tp.out.data.length;
+ out_data_blob->data = tp.out.data.data;
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ parse a trans2 search response.
+ Return the number of bytes consumed
+ return 0 for success with end of list
+ return -1 for a parse error
+*/
+static int parse_trans2_search(struct cli_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ enum search_level level,
+ uint16 flags,
+ DATA_BLOB *blob,
+ union smb_search_data *data)
+{
+ uint_t len, ofs;
+
+ switch (level) {
+ case RAW_SEARCH_GENERIC:
+ case RAW_SEARCH_SEARCH:
+ /* handled elsewhere */
+ return -1;
+
+ case RAW_SEARCH_STANDARD:
+ if (flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
+ if (blob->length < 4) return -1;
+ data->standard.resume_key = IVAL(blob->data, 0);
+ blob->data += 4;
+ blob->length -= 4;
+ }
+ if (blob->length < 24) return -1;
+ data->standard.create_time = make_unix_date2(blob->data + 0);
+ data->standard.access_time = make_unix_date2(blob->data + 4);
+ data->standard.write_time = make_unix_date2(blob->data + 8);
+ data->standard.size = IVAL(blob->data, 12);
+ data->standard.alloc_size = IVAL(blob->data, 16);
+ data->standard.attrib = SVAL(blob->data, 20);
+ len = cli_blob_pull_string(tree->session, mem_ctx, blob,
+ &data->standard.name,
+ 22, 23, STR_LEN8BIT);
+ return (len + 23 + 3) & ~3;
+
+ case RAW_SEARCH_EA_SIZE:
+ if (flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
+ if (blob->length < 4) return -1;
+ data->ea_size.resume_key = IVAL(blob->data, 0);
+ blob->data += 4;
+ blob->length -= 4;
+ }
+ if (blob->length < 28) return -1;
+ data->ea_size.create_time = make_unix_date2(blob->data + 0);
+ data->ea_size.access_time = make_unix_date2(blob->data + 4);
+ data->ea_size.write_time = make_unix_date2(blob->data + 8);
+ data->ea_size.size = IVAL(blob->data, 12);
+ data->ea_size.alloc_size = IVAL(blob->data, 16);
+ data->ea_size.attrib = SVAL(blob->data, 20);
+ data->ea_size.ea_size = IVAL(blob->data, 22);
+ len = cli_blob_pull_string(tree->session, mem_ctx, blob,
+ &data->ea_size.name,
+ 26, 27, STR_LEN8BIT | STR_NOALIGN);
+ return len + 27;
+
+ case RAW_SEARCH_DIRECTORY_INFO:
+ if (blob->length < 65) return -1;
+ ofs = IVAL(blob->data, 0);
+ data->directory_info.file_index = IVAL(blob->data, 4);
+ data->directory_info.create_time = cli_pull_nttime(blob->data, 8);
+ data->directory_info.access_time = cli_pull_nttime(blob->data, 16);
+ data->directory_info.write_time = cli_pull_nttime(blob->data, 24);
+ data->directory_info.change_time = cli_pull_nttime(blob->data, 32);
+ data->directory_info.size = BVAL(blob->data, 40);
+ data->directory_info.alloc_size = BVAL(blob->data, 48);
+ data->directory_info.attrib = IVAL(blob->data, 56);
+ len = cli_blob_pull_string(tree->session, mem_ctx, blob,
+ &data->directory_info.name,
+ 60, 64, 0);
+ if (ofs != 0 && ofs < 64+len) {
+ return -1;
+ }
+ return ofs;
+
+ case RAW_SEARCH_FULL_DIRECTORY_INFO:
+ if (blob->length < 69) return -1;
+ ofs = IVAL(blob->data, 0);
+ data->full_directory_info.file_index = IVAL(blob->data, 4);
+ data->full_directory_info.create_time = cli_pull_nttime(blob->data, 8);
+ data->full_directory_info.access_time = cli_pull_nttime(blob->data, 16);
+ data->full_directory_info.write_time = cli_pull_nttime(blob->data, 24);
+ data->full_directory_info.change_time = cli_pull_nttime(blob->data, 32);
+ data->full_directory_info.size = BVAL(blob->data, 40);
+ data->full_directory_info.alloc_size = BVAL(blob->data, 48);
+ data->full_directory_info.attrib = IVAL(blob->data, 56);
+ data->full_directory_info.ea_size = IVAL(blob->data, 64);
+ len = cli_blob_pull_string(tree->session, mem_ctx, blob,
+ &data->full_directory_info.name,
+ 60, 68, 0);
+ if (ofs != 0 && ofs < 68+len) {
+ return -1;
+ }
+ return ofs;
+
+ case RAW_SEARCH_NAME_INFO:
+ if (blob->length < 13) return -1;
+ ofs = IVAL(blob->data, 0);
+ data->name_info.file_index = IVAL(blob->data, 4);
+ len = cli_blob_pull_string(tree->session, mem_ctx, blob,
+ &data->name_info.name,
+ 8, 12, 0);
+ if (ofs != 0 && ofs < 12+len) {
+ return -1;
+ }
+ return ofs;
+
+
+ case RAW_SEARCH_BOTH_DIRECTORY_INFO:
+ if (blob->length < 95) return -1;
+ ofs = IVAL(blob->data, 0);
+ data->both_directory_info.file_index = IVAL(blob->data, 4);
+ data->both_directory_info.create_time = cli_pull_nttime(blob->data, 8);
+ data->both_directory_info.access_time = cli_pull_nttime(blob->data, 16);
+ data->both_directory_info.write_time = cli_pull_nttime(blob->data, 24);
+ data->both_directory_info.change_time = cli_pull_nttime(blob->data, 32);
+ data->both_directory_info.size = BVAL(blob->data, 40);
+ data->both_directory_info.alloc_size = BVAL(blob->data, 48);
+ data->both_directory_info.attrib = IVAL(blob->data, 56);
+ data->both_directory_info.ea_size = IVAL(blob->data, 64);
+ cli_blob_pull_string(tree->session, mem_ctx, blob,
+ &data->both_directory_info.short_name,
+ 68, 70, STR_LEN8BIT | STR_UNICODE);
+ len = cli_blob_pull_string(tree->session, mem_ctx, blob,
+ &data->both_directory_info.name,
+ 60, 94, 0);
+ if (ofs != 0 && ofs < 94+len) {
+ return -1;
+ }
+ return ofs;
+
+
+ case RAW_SEARCH_261:
+ if (blob->length < 81) return -1;
+ ofs = IVAL(blob->data, 0);
+ data->level_261.file_index = IVAL(blob->data, 4);
+ data->level_261.create_time = cli_pull_nttime(blob->data, 8);
+ data->level_261.access_time = cli_pull_nttime(blob->data, 16);
+ data->level_261.write_time = cli_pull_nttime(blob->data, 24);
+ data->level_261.change_time = cli_pull_nttime(blob->data, 32);
+ data->level_261.size = BVAL(blob->data, 40);
+ data->level_261.alloc_size = BVAL(blob->data, 48);
+ data->level_261.attrib = IVAL(blob->data, 56);
+ data->level_261.ea_size = IVAL(blob->data, 64);
+ data->level_261.unknown[0] = IVAL(blob->data, 68);
+ data->level_261.unknown[1] = IVAL(blob->data, 72);
+ data->level_261.unknown[2] = IVAL(blob->data, 76);
+ len = cli_blob_pull_string(tree->session, mem_ctx, blob,
+ &data->level_261.name,
+ 60, 80, 0);
+ if (ofs != 0 && ofs < 80+len) {
+ return -1;
+ }
+ return ofs;
+
+ case RAW_SEARCH_262:
+ if (blob->length < 105) return -1;
+ ofs = IVAL(blob->data, 0);
+ data->level_262.file_index = IVAL(blob->data, 4);
+ data->level_262.create_time = cli_pull_nttime(blob->data, 8);
+ data->level_262.access_time = cli_pull_nttime(blob->data, 16);
+ data->level_262.write_time = cli_pull_nttime(blob->data, 24);
+ data->level_262.change_time = cli_pull_nttime(blob->data, 32);
+ data->level_262.size = BVAL(blob->data, 40);
+ data->level_262.alloc_size = BVAL(blob->data, 48);
+ data->level_262.attrib = SVAL(blob->data, 56);
+ data->level_262.ea_size = IVAL(blob->data, 64);
+ cli_blob_pull_string(tree->session, mem_ctx, blob,
+ &data->level_262.short_name,
+ 68, 70, STR_LEN8BIT | STR_UNICODE);
+ data->level_262.unknown[0] = IVAL(blob->data, 94);
+ data->level_262.unknown[1] = IVAL(blob->data, 98);
+ len = cli_blob_pull_string(tree->session, mem_ctx, blob,
+ &data->level_262.name,
+ 60, 104, 0);
+ if (ofs != 0 && ofs < 104+len) {
+ return -1;
+ }
+ return ofs;
+ }
+
+ /* invalid level */
+ return -1;
+}
+
+/****************************************************************************
+ Trans2 search backend - process output.
+****************************************************************************/
+static NTSTATUS smb_raw_t2search_backend(struct cli_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ enum search_level level,
+ uint16 flags,
+ int16 count,
+ DATA_BLOB *blob,
+ void *private,
+ BOOL (*callback)(void *private, union smb_search_data *file))
+
+{
+ int i;
+ DATA_BLOB blob2;
+
+ blob2.data = blob->data;
+ blob2.length = blob->length;
+
+ for (i=0; i < count; i++) {
+ union smb_search_data search_data;
+ uint_t len;
+
+ len = parse_trans2_search(tree, mem_ctx, level, flags, &blob2, &search_data);
+ if (len == -1) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* the callback function can tell us that no more will
+ fit - in that case we stop, but it isn't an error */
+ if (!callback(private, &search_data)) {
+ break;
+ }
+
+ if (len == 0) break;
+
+ blob2.data += len;
+ blob2.length -= len;
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/* Implements trans2findfirst2 and old search
+ */
+NTSTATUS smb_raw_search_first(struct cli_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ union smb_search_first *io, void *private,
+ BOOL (*callback)(void *private, union smb_search_data *file))
+{
+ uint16 info_level = 0;
+ DATA_BLOB p_blob, d_blob;
+ NTSTATUS status;
+
+ if (io->generic.level == RAW_SEARCH_SEARCH) {
+ return smb_raw_search_first_old(tree, mem_ctx, io, private, callback);
+ }
+ if (io->generic.level >= RAW_SEARCH_GENERIC) {
+ return NT_STATUS_INVALID_LEVEL;
+ }
+ info_level = (uint16)io->generic.level;
+
+ status = smb_raw_search_first_blob(tree, mem_ctx,
+ io, info_level, &p_blob, &d_blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (p_blob.length != 10) {
+ DEBUG(1,("smb_raw_search_first: parms wrong size %d != expected_param_size\n",
+ p_blob.length));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* process output data */
+ io->t2ffirst.out.handle = SVAL(p_blob.data, 0);
+ io->t2ffirst.out.count = SVAL(p_blob.data, 2);
+ io->t2ffirst.out.end_of_search = SVAL(p_blob.data, 4);
+
+ status = smb_raw_t2search_backend(tree, mem_ctx,
+ io->generic.level,
+ io->t2ffirst.in.flags, io->t2ffirst.out.count,
+ &d_blob, private, callback);
+
+ return status;
+}
+
+/* Implements trans2findnext2 and old smbsearch
+ */
+NTSTATUS smb_raw_search_next(struct cli_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ union smb_search_next *io, void *private,
+ BOOL (*callback)(void *private, union smb_search_data *file))
+{
+ uint16 info_level = 0;
+ DATA_BLOB p_blob, d_blob;
+ NTSTATUS status;
+
+ if (io->generic.level == RAW_SEARCH_SEARCH) {
+ return smb_raw_search_next_old(tree, mem_ctx, io, private, callback);
+ }
+ if (io->generic.level >= RAW_SEARCH_GENERIC) {
+ return NT_STATUS_INVALID_LEVEL;
+ }
+ info_level = (uint16)io->generic.level;
+
+ status = smb_raw_search_next_blob(tree, mem_ctx,
+ io, info_level, &p_blob, &d_blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (p_blob.length != 8) {
+ DEBUG(1,("smb_raw_search_next: parms wrong size %d != expected_param_size\n",
+ p_blob.length));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* process output data */
+ io->t2fnext.out.count = SVAL(p_blob.data, 0);
+ io->t2fnext.out.end_of_search = SVAL(p_blob.data, 2);
+
+ status = smb_raw_t2search_backend(tree, mem_ctx,
+ io->generic.level,
+ io->t2fnext.in.flags, io->t2fnext.out.count,
+ &d_blob, private, callback);
+
+ return status;
+}
+
+/*
+ Implements trans2findclose2
+ */
+NTSTATUS smb_raw_search_close(struct cli_tree *tree,
+ union smb_search_close *io)
+{
+ struct cli_request *req;
+
+ req = cli_request_setup(tree, SMBfindclose, 1, 0);
+ if (!req) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ SSVAL(req->out.vwv, VWV(0), io->findclose.in.handle);
+
+ if (cli_request_send(req)) {
+ cli_request_receive(req);
+ }
+
+ return cli_request_destroy(req);
+}
diff --git a/source4/libcli/raw/rawsetfileinfo.c b/source4/libcli/raw/rawsetfileinfo.c
new file mode 100644
index 0000000000..4044686c64
--- /dev/null
+++ b/source4/libcli/raw/rawsetfileinfo.c
@@ -0,0 +1,335 @@
+/*
+ Unix SMB/CIFS implementation.
+ RAW_SFILEINFO_* calls
+ Copyright (C) James Myers 2003
+ Copyright (C) Andrew Tridgell 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Handle qfileinfo/qpathinfo trans2 backend.
+****************************************************************************/
+static BOOL smb_raw_setinfo_backend(struct cli_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ union smb_setfileinfo *parms,
+ DATA_BLOB *blob)
+{
+ uint_t len;
+
+#define NEED_BLOB(n) do { \
+ *blob = data_blob_talloc(mem_ctx, NULL, n); \
+ if (blob->data == NULL) return False; \
+ } while (0)
+
+ switch (parms->generic.level) {
+ case RAW_SFILEINFO_GENERIC:
+ case RAW_SFILEINFO_SETATTR:
+ case RAW_SFILEINFO_SETATTRE:
+ /* not handled here */
+ return False;
+
+ case RAW_SFILEINFO_STANDARD:
+ NEED_BLOB(12);
+ put_dos_date2(blob->data, 0, parms->standard.in.create_time);
+ put_dos_date2(blob->data, 4, parms->standard.in.access_time);
+ put_dos_date2(blob->data, 8, parms->standard.in.write_time);
+ return True;
+
+ case RAW_SFILEINFO_EA_SET:
+ NEED_BLOB(ea_list_size(1, &parms->ea_set.in.ea));
+ ea_put_list(blob->data, 1, &parms->ea_set.in.ea);
+ return True;
+
+ case RAW_SFILEINFO_BASIC_INFO:
+ case RAW_SFILEINFO_BASIC_INFORMATION:
+ NEED_BLOB(40);
+ cli_push_nttime(blob->data, 0, &parms->basic_info.in.create_time);
+ cli_push_nttime(blob->data, 8, &parms->basic_info.in.access_time);
+ cli_push_nttime(blob->data, 16, &parms->basic_info.in.write_time);
+ cli_push_nttime(blob->data, 24, &parms->basic_info.in.change_time);
+ SIVAL(blob->data, 32, parms->basic_info.in.attrib);
+ SIVAL(blob->data, 36, 0); /* padding */
+ return True;
+
+ case RAW_SFILEINFO_UNIX_BASIC:
+ NEED_BLOB(92);
+ SBVAL(blob->data, 0, parms->unix_basic.in.end_of_file);
+ SBVAL(blob->data, 8, parms->unix_basic.in.num_bytes);
+ cli_push_nttime(blob->data, 16, &parms->unix_basic.in.status_change_time);
+ cli_push_nttime(blob->data, 24, &parms->unix_basic.in.access_time);
+ cli_push_nttime(blob->data, 32, &parms->unix_basic.in.change_time);
+ SBVAL(blob->data, 40, parms->unix_basic.in.uid);
+ SBVAL(blob->data, 48, parms->unix_basic.in.gid);
+ SIVAL(blob->data, 56, parms->unix_basic.in.file_type);
+ SBVAL(blob->data, 60, parms->unix_basic.in.dev_major);
+ SBVAL(blob->data, 68, parms->unix_basic.in.dev_minor);
+ SBVAL(blob->data, 76, parms->unix_basic.in.unique_id);
+ SBVAL(blob->data, 84, parms->unix_basic.in.nlink);
+ return True;
+
+ case RAW_SFILEINFO_DISPOSITION_INFO:
+ case RAW_SFILEINFO_DISPOSITION_INFORMATION:
+ NEED_BLOB(4);
+ SIVAL(blob->data, 0, parms->disposition_info.in.delete_on_close);
+ return True;
+
+ case RAW_SFILEINFO_ALLOCATION_INFO:
+ case RAW_SFILEINFO_ALLOCATION_INFORMATION:
+ NEED_BLOB(8);
+ SBVAL(blob->data, 0, parms->allocation_info.in.alloc_size);
+ return True;
+
+ case RAW_SFILEINFO_END_OF_FILE_INFO:
+ case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
+ NEED_BLOB(8);
+ SBVAL(blob->data, 0, parms->end_of_file_info.in.size);
+ return True;
+
+ case RAW_SFILEINFO_RENAME_INFORMATION:
+ NEED_BLOB(12);
+ SIVAL(blob->data, 0, parms->rename_information.in.overwrite);
+ SIVAL(blob->data, 4, parms->rename_information.in.root_fid);
+ len = cli_blob_append_string(tree->session, mem_ctx, blob,
+ parms->rename_information.in.new_name,
+ STR_UNICODE|STR_TERMINATE);
+ SIVAL(blob->data, 8, len - 2);
+ return True;
+
+ case RAW_SFILEINFO_POSITION_INFORMATION:
+ NEED_BLOB(8);
+ SBVAL(blob->data, 0, parms->position_information.in.position);
+ return True;
+
+ case RAW_SFILEINFO_MODE_INFORMATION:
+ NEED_BLOB(4);
+ SIVAL(blob->data, 0, parms->mode_information.in.mode);
+ return True;
+ }
+
+ return False;
+}
+
+/****************************************************************************
+ Very raw set file info - takes data blob (async send)
+****************************************************************************/
+static struct cli_request *smb_raw_setfileinfo_blob_send(struct cli_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ uint16 fnum,
+ uint16 info_level,
+ DATA_BLOB *blob)
+{
+ struct smb_trans2 tp;
+ uint16 setup = TRANSACT2_SETFILEINFO;
+
+ tp.in.max_setup = 0;
+ tp.in.flags = 0;
+ tp.in.timeout = 0;
+ tp.in.setup_count = 1;
+ tp.in.max_param = 2;
+ tp.in.max_data = 0;
+ tp.in.setup = &setup;
+
+ tp.in.params = data_blob_talloc(mem_ctx, NULL, 6);
+ if (!tp.in.params.data) {
+ return NULL;
+ }
+ SSVAL(tp.in.params.data, 0, fnum);
+ SSVAL(tp.in.params.data, 2, info_level);
+ SSVAL(tp.in.params.data, 4, 0); /* reserved */
+
+ tp.in.data = *blob;
+
+ return smb_raw_trans2_send(tree, &tp);
+}
+
+/****************************************************************************
+ Very raw set path info - takes data blob
+****************************************************************************/
+static struct cli_request *smb_raw_setpathinfo_blob_send(struct cli_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ const char *fname,
+ uint16 info_level,
+ DATA_BLOB *blob)
+{
+ struct smb_trans2 tp;
+ uint16 setup = TRANSACT2_SETPATHINFO;
+
+ tp.in.max_setup = 0;
+ tp.in.flags = 0;
+ tp.in.timeout = 0;
+ tp.in.setup_count = 1;
+ tp.in.max_param = 2;
+ tp.in.max_data = 0;
+ tp.in.setup = &setup;
+
+ tp.in.params = data_blob_talloc(mem_ctx, NULL, 4);
+ if (!tp.in.params.data) {
+ return NULL;
+ }
+ SSVAL(tp.in.params.data, 0, info_level);
+ SSVAL(tp.in.params.data, 2, 0);
+ cli_blob_append_string(tree->session, mem_ctx,
+ &tp.in.params,
+ fname, STR_TERMINATE);
+
+ tp.in.data = *blob;
+
+ return smb_raw_trans2_send(tree, &tp);
+}
+
+/****************************************************************************
+ Handle setattr (async send)
+****************************************************************************/
+static struct cli_request *smb_raw_setattr_send(struct cli_tree *tree,
+ union smb_setfileinfo *parms)
+{
+ struct cli_request *req;
+
+ req = cli_request_setup(tree, SMBsetatr, 8, 0);
+ if (!req) return NULL;
+
+ SSVAL(req->out.vwv, VWV(0), parms->setattr.in.attrib);
+ put_dos_date3(req->out.vwv, VWV(1), parms->setattr.in.write_time);
+ memset(req->out.vwv + VWV(3), 0, 10); /* reserved */
+ cli_req_append_ascii4(req, parms->setattr.file.fname, STR_TERMINATE);
+ cli_req_append_ascii4(req, "", STR_TERMINATE);
+
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+/****************************************************************************
+ Handle setattrE. (async send)
+****************************************************************************/
+static struct cli_request *smb_raw_setattrE_send(struct cli_tree *tree,
+ union smb_setfileinfo *parms)
+{
+ struct cli_request *req;
+
+ req = cli_request_setup(tree, SMBsetattrE, 7, 0);
+ if (!req) return NULL;
+
+ SSVAL(req->out.vwv, VWV(0), parms->setattre.file.fnum);
+ put_dos_date2(req->out.vwv, VWV(1), parms->setattre.in.create_time);
+ put_dos_date2(req->out.vwv, VWV(3), parms->setattre.in.access_time);
+ put_dos_date2(req->out.vwv, VWV(5), parms->setattre.in.write_time);
+
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+/****************************************************************************
+ Set file info (async send)
+****************************************************************************/
+struct cli_request *smb_raw_setfileinfo_send(struct cli_tree *tree,
+ union smb_setfileinfo *parms)
+{
+ DATA_BLOB blob;
+ TALLOC_CTX *mem_ctx;
+ struct cli_request *req;
+
+ if (parms->generic.level == RAW_SFILEINFO_SETATTRE) {
+ return smb_raw_setattrE_send(tree, parms);
+ }
+ if (parms->generic.level >= RAW_SFILEINFO_GENERIC) {
+ return NULL;
+ }
+
+ mem_ctx = talloc_init("setpathinfo");
+ if (!mem_ctx) return NULL;
+
+ if (!smb_raw_setinfo_backend(tree, mem_ctx, parms, &blob)) {
+ talloc_destroy(mem_ctx);
+ return NULL;
+ }
+
+ /* send request and process the output */
+ req = smb_raw_setfileinfo_blob_send(tree,
+ mem_ctx,
+ parms->generic.file.fnum,
+ parms->generic.level,
+ &blob);
+
+ talloc_destroy(mem_ctx);
+ return req;
+}
+
+/****************************************************************************
+ Set file info (async send)
+****************************************************************************/
+NTSTATUS smb_raw_setfileinfo(struct cli_tree *tree,
+ union smb_setfileinfo *parms)
+{
+ struct cli_request *req = smb_raw_setfileinfo_send(tree, parms);
+ return cli_request_simple_recv(req);
+}
+
+
+/****************************************************************************
+ Set path info (async send)
+****************************************************************************/
+struct cli_request *smb_raw_setpathinfo_send(struct cli_tree *tree,
+ union smb_setfileinfo *parms)
+{
+ DATA_BLOB blob;
+ TALLOC_CTX *mem_ctx;
+ struct cli_request *req;
+
+ if (parms->generic.level == RAW_SFILEINFO_SETATTR) {
+ return smb_raw_setattr_send(tree, parms);
+ }
+ if (parms->generic.level >= RAW_SFILEINFO_GENERIC) {
+ return NULL;
+ }
+
+ mem_ctx = talloc_init("setpathinfo");
+ if (!mem_ctx) return NULL;
+
+ if (!smb_raw_setinfo_backend(tree, mem_ctx, parms, &blob)) {
+ talloc_destroy(mem_ctx);
+ return NULL;
+ }
+
+ /* send request and process the output */
+ req = smb_raw_setpathinfo_blob_send(tree,
+ mem_ctx,
+ parms->generic.file.fname,
+ parms->generic.level,
+ &blob);
+
+ talloc_destroy(mem_ctx);
+ return req;
+}
+
+/****************************************************************************
+ Set path info (sync interface)
+****************************************************************************/
+NTSTATUS smb_raw_setpathinfo(struct cli_tree *tree,
+ union smb_setfileinfo *parms)
+{
+ struct cli_request *req = smb_raw_setpathinfo_send(tree, parms);
+ return cli_request_simple_recv(req);
+}
diff --git a/source4/libcli/raw/rawtrans.c b/source4/libcli/raw/rawtrans.c
new file mode 100644
index 0000000000..508f920268
--- /dev/null
+++ b/source4/libcli/raw/rawtrans.c
@@ -0,0 +1,489 @@
+/*
+ Unix SMB/CIFS implementation.
+ raw trans/trans2/nttrans operations
+
+ Copyright (C) James Myers 2003 <myersjj@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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+
+/*
+ check out of bounds for incoming data
+*/
+static BOOL raw_trans_oob(struct cli_request *req,
+ uint_t offset, uint_t count)
+{
+ char *ptr;
+
+ if (count == 0) {
+ return False;
+ }
+
+ ptr = req->in.hdr + offset;
+
+ /* be careful with wraparound! */
+ if (ptr < req->in.data ||
+ ptr >= req->in.data + req->in.data_size ||
+ count > req->in.data_size ||
+ ptr + count > req->in.data + req->in.data_size) {
+ return True;
+ }
+ return False;
+}
+
+/****************************************************************************
+ receive a SMB trans or trans2 response allocating the necessary memory
+ ****************************************************************************/
+NTSTATUS smb_raw_trans2_recv(struct cli_request *req,
+ TALLOC_CTX *mem_ctx,
+ struct smb_trans2 *parms)
+{
+ int total_data=0;
+ int total_param=0;
+ char *tdata;
+ char *tparam;
+
+ parms->out.data.length = 0;
+ parms->out.data.data = NULL;
+ parms->out.params.length = 0;
+ parms->out.params.data = NULL;
+
+ if (!cli_request_receive(req)) {
+ req->status = NT_STATUS_UNSUCCESSFUL;
+ return cli_request_destroy(req);
+ }
+
+ /*
+ * An NT RPC pipe call can return ERRDOS, ERRmoredata
+ * to a trans call. This is not an error and should not
+ * be treated as such.
+ */
+ if (NT_STATUS_IS_ERR(req->status)) {
+ return cli_request_destroy(req);
+ }
+
+ CLI_CHECK_MIN_WCT(req, 10);
+
+ /* parse out the lengths */
+ total_data = SVAL(req->in.vwv, VWV(1));
+ total_param = SVAL(req->in.vwv, VWV(0));
+
+ /* allocate it */
+ if (total_data != 0) {
+ tdata = talloc_realloc(mem_ctx, parms->out.data.data,total_data);
+ if (!tdata) {
+ DEBUG(0,("smb_raw_receive_trans: failed to enlarge data buffer to %d bytes\n", total_data));
+ req->status = NT_STATUS_NO_MEMORY;
+ return cli_request_destroy(req);
+ }
+ parms->out.data.data = tdata;
+ }
+
+ if (total_param != 0) {
+ tparam = talloc_realloc(mem_ctx, parms->out.params.data,total_param);
+ if (!tparam) {
+ DEBUG(0,("smb_raw_receive_trans: failed to enlarge param buffer to %d bytes\n", total_param));
+ req->status = NT_STATUS_NO_MEMORY;
+ return cli_request_destroy(req);
+ }
+ parms->out.params.data = tparam;
+ }
+
+ parms->out.setup_count = SVAL(req->in.vwv, VWV(9));
+ CLI_CHECK_WCT(req, 10 + parms->out.setup_count);
+
+ if (parms->out.setup_count > 0) {
+ int i;
+ parms->out.setup = talloc(mem_ctx, 2 * parms->out.setup_count);
+ if (!parms->out.setup) {
+ req->status = NT_STATUS_NO_MEMORY;
+ return cli_request_destroy(req);
+ }
+ for (i=0;i<parms->out.setup_count;i++) {
+ parms->out.setup[i] = SVAL(req->in.vwv, VWV(10+i));
+ }
+ }
+
+ while (1) {
+ uint16 param_count, param_ofs, param_disp;
+ uint16 data_count, data_ofs, data_disp;
+ uint16 total_data2, total_param2;
+
+ /* parse out the total lengths again - they can shrink! */
+ total_data2 = SVAL(req->in.vwv, VWV(1));
+ total_param2 = SVAL(req->in.vwv, VWV(0));
+
+ if (total_data2 > total_data ||
+ total_param2 > total_param) {
+ /* they must *only* shrink */
+ DEBUG(1,("smb_raw_receive_trans: data/params expanded!\n"));
+ req->status = NT_STATUS_BUFFER_TOO_SMALL;
+ return cli_request_destroy(req);
+ }
+
+ total_data = total_data2;
+ total_param = total_param2;
+
+ /* parse params for this lump */
+ param_count = SVAL(req->in.vwv, VWV(3));
+ param_ofs = SVAL(req->in.vwv, VWV(4));
+ param_disp = SVAL(req->in.vwv, VWV(5));
+
+ data_count = SVAL(req->in.vwv, VWV(6));
+ data_ofs = SVAL(req->in.vwv, VWV(7));
+ data_disp = SVAL(req->in.vwv, VWV(8));
+
+ if (data_count + data_disp > total_data ||
+ param_count + param_disp > total_param) {
+ DEBUG(1,("smb_raw_receive_trans: Buffer overflow\n"));
+ req->status = NT_STATUS_BUFFER_TOO_SMALL;
+ return cli_request_destroy(req);
+ }
+
+ /* check the server isn't being nasty */
+ if (raw_trans_oob(req, param_ofs, param_count) ||
+ raw_trans_oob(req, data_ofs, data_count)) {
+ DEBUG(1,("smb_raw_receive_trans: out of bounds parameters!\n"));
+ req->status = NT_STATUS_BUFFER_TOO_SMALL;
+ return cli_request_destroy(req);
+ }
+
+ if (data_count) {
+ memcpy(parms->out.data.data + data_disp,
+ req->in.hdr + data_ofs,
+ data_count);
+ }
+
+ if (param_count) {
+ memcpy(parms->out.params.data + param_disp,
+ req->in.hdr + param_ofs,
+ param_count);
+ }
+
+ parms->out.data.length += data_count;
+ parms->out.params.length += param_count;
+
+ if (total_data <= parms->out.data.length && total_param <= parms->out.params.length)
+ break;
+
+ /* to receive more requests we need to mark this request as not received */
+ req->in.buffer = NULL;
+
+ if (!cli_request_receive(req)) {
+ req->status = NT_STATUS_UNSUCCESSFUL;
+ return cli_request_destroy(req);
+ }
+ }
+
+failed:
+ return cli_request_destroy(req);
+}
+
+
+/****************************************************************************
+ trans2 raw async interface - only BLOBs used in this interface.
+note that this doesn't yet support multi-part requests
+****************************************************************************/
+struct cli_request *smb_raw_trans2_send(struct cli_tree *tree,
+ struct smb_trans2 *parms)
+{
+ uint8 command = SMBtrans2;
+ int wct = 14 + parms->in.setup_count;
+ struct cli_request *req;
+ char *outdata,*outparam;
+ int data_sent, param_sent;
+ int i;
+ const int padding = 3;
+
+ req = cli_request_setup(tree, command, wct, padding);
+ if (!req) {
+ return NULL;
+ }
+
+ /* fill in SMB parameters */
+ data_sent = parms->in.data.length;
+ param_sent = parms->in.params.length;
+ outparam = req->out.data + padding;
+ outdata = outparam + param_sent;
+
+ /* make sure we don't leak data via the padding */
+ memset(req->out.data, 0, padding);
+
+ /* primary request */
+ SSVAL(req->out.vwv,VWV(0),parms->in.params.length);
+ SSVAL(req->out.vwv,VWV(1),parms->in.data.length);
+ SSVAL(req->out.vwv,VWV(2),parms->in.max_param);
+ SSVAL(req->out.vwv,VWV(3),parms->in.max_data);
+ SSVAL(req->out.vwv,VWV(4),parms->in.max_setup);
+ SSVAL(req->out.vwv,VWV(5),parms->in.flags);
+ SIVAL(req->out.vwv,VWV(6),parms->in.timeout);
+ SSVAL(req->out.vwv,VWV(8),0); /* reserved */
+ SSVAL(req->out.vwv,VWV(9),parms->in.params.length);
+ SSVAL(req->out.vwv,VWV(10),PTR_DIFF(outparam,req->out.hdr));
+ SSVAL(req->out.vwv,VWV(11),parms->in.data.length);
+ SSVAL(req->out.vwv,VWV(12),PTR_DIFF(outdata,req->out.hdr));
+ SSVAL(req->out.vwv,VWV(13),parms->in.setup_count);
+ for (i=0;i<parms->in.setup_count;i++) {
+ SSVAL(req->out.vwv,VWV(14)+i*2,parms->in.setup[i]);
+ }
+ if (parms->in.params.data) {
+ cli_req_append_blob(req, &parms->in.params);
+ }
+ if (parms->in.data.data) {
+ cli_req_append_blob(req, &parms->in.data);
+ }
+
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+/*
+ trans2 synchronous blob interface
+*/
+NTSTATUS smb_raw_trans2(struct cli_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ struct smb_trans2 *parms)
+{
+ struct cli_request *req;
+ req = smb_raw_trans2_send(tree, parms);
+ if (!req) return NT_STATUS_UNSUCCESSFUL;
+ return smb_raw_trans2_recv(req, mem_ctx, parms);
+}
+
+
+/****************************************************************************
+ receive a SMB nttrans response allocating the necessary memory
+ ****************************************************************************/
+NTSTATUS smb_raw_nttrans_recv(struct cli_request *req,
+ TALLOC_CTX *mem_ctx,
+ struct smb_nttrans *parms)
+{
+ uint32 total_data, recvd_data=0;
+ uint32 total_param, recvd_param=0;
+
+ if (!cli_request_receive(req) ||
+ cli_request_is_error(req)) {
+ return cli_request_destroy(req);
+ }
+
+ /* sanity check */
+ if (CVAL(req->in.hdr, HDR_COM) != SMBnttrans) {
+ DEBUG(0,("smb_raw_receive_nttrans: Expected %s response, got command 0x%02x\n",
+ "SMBnttrans",
+ CVAL(req->in.hdr,HDR_COM)));
+ req->status = NT_STATUS_UNSUCCESSFUL;
+ return cli_request_destroy(req);
+ }
+
+ CLI_CHECK_MIN_WCT(req, 18);
+
+ /* parse out the lengths */
+ total_param = IVAL(req->in.vwv, 3);
+ total_data = IVAL(req->in.vwv, 7);
+
+ parms->out.data = data_blob_talloc(mem_ctx, NULL, total_data);
+ parms->out.params = data_blob_talloc(mem_ctx, NULL, total_param);
+
+ if (parms->out.data.length != total_data ||
+ parms->out.params.length != total_param) {
+ req->status = NT_STATUS_NO_MEMORY;
+ return cli_request_destroy(req);
+ }
+
+ parms->out.setup_count = CVAL(req->in.vwv, 35);
+ CLI_CHECK_WCT(req, 18 + parms->out.setup_count);
+
+ if (parms->out.setup_count > 0) {
+ int i;
+ parms->out.setup = talloc(mem_ctx, 2 * parms->out.setup_count);
+ if (!parms->out.setup) {
+ req->status = NT_STATUS_NO_MEMORY;
+ return cli_request_destroy(req);
+ }
+ for (i=0;i<parms->out.setup_count;i++) {
+ parms->out.setup[i] = SVAL(req->in.vwv, VWV(18+i));
+ }
+ }
+
+ while (recvd_data < total_data ||
+ recvd_param < total_param) {
+ uint32 param_count, param_ofs, param_disp;
+ uint32 data_count, data_ofs, data_disp;
+ uint32 total_data2, total_param2;
+
+ /* parse out the total lengths again - they can shrink! */
+ total_param2 = IVAL(req->in.vwv, 3);
+ total_data2 = IVAL(req->in.vwv, 7);
+
+ if (total_data2 > total_data ||
+ total_param2 > total_param) {
+ /* they must *only* shrink */
+ DEBUG(1,("smb_raw_receive_nttrans: data/params expanded!\n"));
+ req->status = NT_STATUS_BUFFER_TOO_SMALL;
+ return cli_request_destroy(req);
+ }
+
+ total_data = total_data2;
+ total_param = total_param2;
+ parms->out.data.length = total_data;
+ parms->out.params.length = total_param;
+
+ /* parse params for this lump */
+ param_count = IVAL(req->in.vwv, 11);
+ param_ofs = IVAL(req->in.vwv, 15);
+ param_disp = IVAL(req->in.vwv, 19);
+
+ data_count = IVAL(req->in.vwv, 23);
+ data_ofs = IVAL(req->in.vwv, 27);
+ data_disp = IVAL(req->in.vwv, 31);
+
+ if (data_count + data_disp > total_data ||
+ param_count + param_disp > total_param) {
+ DEBUG(1,("smb_raw_receive_nttrans: Buffer overflow\n"));
+ req->status = NT_STATUS_BUFFER_TOO_SMALL;
+ return cli_request_destroy(req);
+ }
+
+ /* check the server isn't being nasty */
+ if (raw_trans_oob(req, param_ofs, param_count) ||
+ raw_trans_oob(req, data_ofs, data_count)) {
+ DEBUG(1,("smb_raw_receive_nttrans: out of bounds parameters!\n"));
+ req->status = NT_STATUS_BUFFER_TOO_SMALL;
+ return cli_request_destroy(req);
+ }
+
+ if (data_count) {
+ memcpy(parms->out.data.data + data_disp,
+ req->in.hdr + data_ofs,
+ data_count);
+ }
+
+ if (param_count) {
+ memcpy(parms->out.params.data + param_disp,
+ req->in.hdr + param_ofs,
+ param_count);
+ }
+
+ recvd_param += param_count;
+ recvd_data += data_count;
+
+ if (recvd_data >= total_data &&
+ recvd_param >= total_param) {
+ break;
+ }
+
+ if (!cli_request_receive(req) ||
+ cli_request_is_error(req)) {
+ return cli_request_destroy(req);
+ }
+
+ /* sanity check */
+ if (CVAL(req->in.hdr, HDR_COM) != SMBnttrans) {
+ DEBUG(0,("smb_raw_receive_nttrans: Expected nttranss, got command 0x%02x\n",
+ CVAL(req->in.hdr, HDR_COM)));
+ req->status = NT_STATUS_UNSUCCESSFUL;
+ return cli_request_destroy(req);
+ }
+ }
+
+failed:
+ return cli_request_destroy(req);
+}
+
+
+/****************************************************************************
+ nttrans raw - only BLOBs used in this interface.
+ at the moment we only handle a single primary request
+****************************************************************************/
+struct cli_request *smb_raw_nttrans_send(struct cli_tree *tree,
+ struct smb_nttrans *parms)
+{
+ struct cli_request *req;
+ char *outdata, *outparam;
+ int i;
+ int align = 0;
+
+ /* only align if there are parameters or data */
+ if (parms->in.params.length || parms->in.data.length) {
+ align = 3;
+ }
+
+ req = cli_request_setup(tree, SMBnttrans,
+ 19 + parms->in.setup_count,
+ align +
+ parms->in.params.length +
+ parms->in.data.length);
+ if (!req) {
+ return NULL;
+ }
+
+ /* fill in SMB parameters */
+ outparam = req->out.data + align;
+ outdata = outparam + parms->in.params.length;
+
+ SCVAL(req->out.vwv, 0, parms->in.max_setup);
+ SSVAL(req->out.vwv, 1, 0); /* reserved */
+ SIVAL(req->out.vwv, 3, parms->in.params.length);
+ SIVAL(req->out.vwv, 7, parms->in.data.length);
+ SIVAL(req->out.vwv, 11, parms->in.max_param);
+ SIVAL(req->out.vwv, 15, parms->in.max_data);
+ SIVAL(req->out.vwv, 19, parms->in.params.length);
+ SIVAL(req->out.vwv, 23, PTR_DIFF(outparam,req->out.hdr));
+ SIVAL(req->out.vwv, 27, parms->in.data.length);
+ SIVAL(req->out.vwv, 31, PTR_DIFF(outdata,req->out.hdr));
+ SCVAL(req->out.vwv, 35, parms->in.setup_count);
+ SSVAL(req->out.vwv, 36, parms->in.function);
+ for (i=0;i<parms->in.setup_count;i++) {
+ SSVAL(req->out.vwv,VWV(19+i),parms->in.setup[i]);
+ }
+ if (parms->in.params.length) {
+ memcpy(outparam, parms->in.params.data, parms->in.params.length);
+ }
+ if (parms->in.data.length) {
+ memcpy(outparam, parms->in.data.data, parms->in.data.length);
+ }
+
+ if (!cli_request_send(req)) {
+ cli_request_destroy(req);
+ return NULL;
+ }
+
+ return req;
+}
+
+
+/****************************************************************************
+ receive a SMB nttrans response allocating the necessary memory
+ ****************************************************************************/
+NTSTATUS smb_raw_nttrans(struct cli_tree *tree,
+ TALLOC_CTX *mem_ctx,
+ struct smb_nttrans *parms)
+{
+ struct cli_request *req;
+
+ req = smb_raw_nttrans_send(tree, parms);
+ if (!req) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return smb_raw_nttrans_recv(req, mem_ctx, parms);
+}
diff --git a/source4/libcli/raw/smb_signing.c b/source4/libcli/raw/smb_signing.c
new file mode 100644
index 0000000000..2ab61aa001
--- /dev/null
+++ b/source4/libcli/raw/smb_signing.c
@@ -0,0 +1,341 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB Signing Code
+ Copyright (C) Jeremy Allison 2002.
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
+ Copyright (C) James J Myers <myersjj@samba.org> 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+struct smb_basic_signing_context {
+ DATA_BLOB mac_key;
+ uint32 next_seq_num;
+};
+
+/***********************************************************
+ SMB signing - Common code before we set a new signing implementation
+************************************************************/
+static BOOL set_smb_signing_common(struct cli_transport *transport)
+{
+ if (!(transport->negotiate.sec_mode &
+ (NEGOTIATE_SECURITY_SIGNATURES_REQUIRED|NEGOTIATE_SECURITY_SIGNATURES_ENABLED))) {
+ return False;
+ }
+
+ if (transport->negotiate.sign_info.doing_signing) {
+ return False;
+ }
+
+ if (transport->negotiate.sign_info.free_signing_context)
+ transport->negotiate.sign_info.free_signing_context(transport);
+
+ /* These calls are INCOMPATIBLE with SMB signing */
+ transport->negotiate.readbraw_supported = False;
+ transport->negotiate.writebraw_supported = False;
+
+ return True;
+}
+
+/***********************************************************
+ SMB signing - Common code for 'real' implementations
+************************************************************/
+static BOOL set_smb_signing_real_common(struct cli_transport *transport)
+{
+ if (transport->negotiate.sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) {
+ DEBUG(5, ("Mandatory SMB signing enabled!\n"));
+ transport->negotiate.sign_info.doing_signing = True;
+ }
+
+ DEBUG(5, ("SMB signing enabled!\n"));
+
+ return True;
+}
+
+static void mark_packet_signed(struct cli_request *req)
+{
+ uint16 flags2;
+ flags2 = SVAL(req->out.hdr, HDR_FLG2);
+ flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
+ SSVAL(req->out.hdr, HDR_FLG2, flags2);
+}
+
+static BOOL signing_good(struct cli_request *req, BOOL good)
+{
+ if (good && !req->transport->negotiate.sign_info.doing_signing) {
+ req->transport->negotiate.sign_info.doing_signing = True;
+ }
+
+ if (!good) {
+ if (req->transport->negotiate.sign_info.doing_signing) {
+ DEBUG(1, ("SMB signature check failed!\n"));
+ return False;
+ } else {
+ DEBUG(3, ("Server did not sign reply correctly\n"));
+ cli_transport_free_signing_context(req->transport);
+ return False;
+ }
+ }
+ return True;
+}
+
+/***********************************************************
+ SMB signing - Simple implementation - calculate a MAC to send.
+************************************************************/
+static void cli_request_simple_sign_outgoing_message(struct cli_request *req)
+{
+ unsigned char calc_md5_mac[16];
+ struct MD5Context md5_ctx;
+ struct smb_basic_signing_context *data = req->transport->negotiate.sign_info.signing_context;
+
+#if 0
+ /* enable this when packet signing is preventing you working out why valgrind
+ says that data is uninitialised */
+ file_save("pkt.dat", req->out.buffer, req->out.size);
+#endif
+
+ req->seq_num = data->next_seq_num;
+
+ /* some requests (eg. NTcancel) are one way, and the sequence number
+ should be increased by 1 not 2 */
+ if (req->one_way_request) {
+ data->next_seq_num += 1;
+ } else {
+ data->next_seq_num += 2;
+ }
+
+ /*
+ * Firstly put the sequence number into the first 4 bytes.
+ * and zero out the next 4 bytes.
+ */
+ SIVAL(req->out.hdr, HDR_SS_FIELD, req->seq_num);
+ SIVAL(req->out.hdr, HDR_SS_FIELD + 4, 0);
+
+ /* mark the packet as signed - BEFORE we sign it...*/
+ mark_packet_signed(req);
+
+ /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
+ MD5Init(&md5_ctx);
+ MD5Update(&md5_ctx, data->mac_key.data,
+ data->mac_key.length);
+ MD5Update(&md5_ctx,
+ req->out.buffer + NBT_HDR_SIZE,
+ req->out.size - NBT_HDR_SIZE);
+ MD5Final(calc_md5_mac, &md5_ctx);
+
+ memcpy(&req->out.hdr[HDR_SS_FIELD], calc_md5_mac, 8);
+
+/* req->out.hdr[HDR_SS_FIELD+2]=0;
+ Uncomment this to test if the remote server actually verifies signitures...*/
+}
+
+
+/***********************************************************
+ SMB signing - Simple implementation - check a MAC sent by server.
+************************************************************/
+static BOOL cli_request_simple_check_incoming_message(struct cli_request *req)
+{
+ BOOL good;
+ unsigned char calc_md5_mac[16];
+ unsigned char server_sent_mac[8];
+ unsigned char sequence_buf[8];
+ struct MD5Context md5_ctx;
+ struct smb_basic_signing_context *data = req->transport->negotiate.sign_info.signing_context;
+ const size_t offset_end_of_sig = (HDR_SS_FIELD + 8);
+ int i;
+ const int sign_range = 0;
+
+ /* its quite bogus to be guessing sequence numbers, but very useful
+ when debugging signing implementations */
+ for (i = 1-sign_range; i <= 1+sign_range; i++) {
+ /*
+ * Firstly put the sequence number into the first 4 bytes.
+ * and zero out the next 4 bytes.
+ */
+ SIVAL(sequence_buf, 0, req->seq_num+i);
+ SIVAL(sequence_buf, 4, 0);
+
+ /* get a copy of the server-sent mac */
+ memcpy(server_sent_mac, &req->in.hdr[HDR_SS_FIELD], sizeof(server_sent_mac));
+
+ /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
+ MD5Init(&md5_ctx);
+ MD5Update(&md5_ctx, data->mac_key.data,
+ data->mac_key.length);
+ MD5Update(&md5_ctx, req->in.hdr, HDR_SS_FIELD);
+ MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf));
+
+ MD5Update(&md5_ctx, req->in.hdr + offset_end_of_sig,
+ req->in.size - NBT_HDR_SIZE - (offset_end_of_sig));
+ MD5Final(calc_md5_mac, &md5_ctx);
+
+ good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
+ if (good) break;
+ }
+
+ if (good && i != 1) {
+ DEBUG(0,("SIGNING OFFSET %d\n", i));
+ }
+
+ if (!good) {
+ DEBUG(5, ("cli_request_simple_check_incoming_message: BAD SIG: wanted SMB signature of\n"));
+ dump_data(5, calc_md5_mac, 8);
+
+ DEBUG(5, ("cli_request_simple_check_incoming_message: BAD SIG: got SMB signature of\n"));
+ dump_data(5, server_sent_mac, 8);
+ }
+ return signing_good(req, good);
+}
+
+
+/***********************************************************
+ SMB signing - Simple implementation - free signing context
+************************************************************/
+static void cli_transport_simple_free_signing_context(struct cli_transport *transport)
+{
+ struct smb_basic_signing_context *data = transport->negotiate.sign_info.signing_context;
+
+ data_blob_free(&data->mac_key);
+ SAFE_FREE(transport->negotiate.sign_info.signing_context);
+
+ return;
+}
+
+
+/***********************************************************
+ SMB signing - Simple implementation - setup the MAC key.
+************************************************************/
+BOOL cli_transport_simple_set_signing(struct cli_transport *transport,
+ const uchar user_transport_key[16], const DATA_BLOB response)
+{
+ struct smb_basic_signing_context *data;
+
+ if (!set_smb_signing_common(transport)) {
+ return False;
+ }
+
+ if (!set_smb_signing_real_common(transport)) {
+ return False;
+ }
+
+ data = smb_xmalloc(sizeof(*data));
+ transport->negotiate.sign_info.signing_context = data;
+
+ data->mac_key = data_blob(NULL, MIN(response.length + 16, 40));
+
+ memcpy(&data->mac_key.data[0], user_transport_key, 16);
+ memcpy(&data->mac_key.data[16],response.data, MIN(response.length, 40 - 16));
+
+ /* Initialise the sequence number */
+ data->next_seq_num = 0;
+
+ transport->negotiate.sign_info.sign_outgoing_message = cli_request_simple_sign_outgoing_message;
+ transport->negotiate.sign_info.check_incoming_message = cli_request_simple_check_incoming_message;
+ transport->negotiate.sign_info.free_signing_context = cli_transport_simple_free_signing_context;
+
+ return True;
+}
+
+
+/***********************************************************
+ SMB signing - NULL implementation - calculate a MAC to send.
+************************************************************/
+static void cli_request_null_sign_outgoing_message(struct cli_request *req)
+{
+ /* we can't zero out the sig, as we might be trying to send a
+ transport request - which is NBT-level, not SMB level and doesn't
+ have the field */
+}
+
+
+/***********************************************************
+ SMB signing - NULL implementation - check a MAC sent by server.
+************************************************************/
+static BOOL cli_request_null_check_incoming_message(struct cli_request *req)
+{
+ return True;
+}
+
+
+/***********************************************************
+ SMB signing - NULL implementation - free signing context
+************************************************************/
+static void cli_null_free_signing_context(struct cli_transport *transport)
+{
+}
+
+/**
+ SMB signing - NULL implementation - setup the MAC key.
+
+ @note Used as an initialisation only - it will not correctly
+ shut down a real signing mechanism
+*/
+BOOL cli_null_set_signing(struct cli_transport *transport)
+{
+ transport->negotiate.sign_info.signing_context = NULL;
+
+ transport->negotiate.sign_info.sign_outgoing_message = cli_request_null_sign_outgoing_message;
+ transport->negotiate.sign_info.check_incoming_message = cli_request_null_check_incoming_message;
+ transport->negotiate.sign_info.free_signing_context = cli_null_free_signing_context;
+
+ return True;
+}
+
+
+/**
+ * Free the signing context
+ */
+void cli_transport_free_signing_context(struct cli_transport *transport)
+{
+ if (transport->negotiate.sign_info.free_signing_context) {
+ transport->negotiate.sign_info.free_signing_context(transport);
+ }
+
+ cli_null_set_signing(transport);
+}
+
+
+/**
+ * Sign a packet with the current mechanism
+ */
+void cli_request_calculate_sign_mac(struct cli_request *req)
+{
+ req->transport->negotiate.sign_info.sign_outgoing_message(req);
+}
+
+
+/**
+ * Check a packet with the current mechanism
+ * @return False if we had an established signing connection
+ * which had a back checksum, True otherwise
+ */
+BOOL cli_request_check_sign_mac(struct cli_request *req)
+{
+ BOOL good;
+
+ if (req->in.size < (HDR_SS_FIELD + 8)) {
+ good = False;
+ } else {
+ good = req->transport->negotiate.sign_info.check_incoming_message(req);
+ }
+
+ if (!good && req->transport->negotiate.sign_info.doing_signing) {
+ return False;
+ }
+
+ return True;
+}
diff --git a/source4/libcli/unexpected.c b/source4/libcli/unexpected.c
new file mode 100644
index 0000000000..c80dfa0465
--- /dev/null
+++ b/source4/libcli/unexpected.c
@@ -0,0 +1,172 @@
+/*
+ Unix SMB/CIFS implementation.
+ handle unexpected packets
+ Copyright (C) Andrew Tridgell 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+
+static TDB_CONTEXT *tdbd = NULL;
+
+/* the key type used in the unexpeceted packet database */
+struct unexpected_key {
+ enum packet_type packet_type;
+ time_t timestamp;
+ int count;
+};
+
+
+
+/****************************************************************************
+ all unexpected packets are passed in here, to be stored in a unexpected
+ packet database. This allows nmblookup and other tools to receive packets
+ erroneoously sent to the wrong port by broken MS systems
+ **************************************************************************/
+void unexpected_packet(struct packet_struct *p)
+{
+ static int count;
+ TDB_DATA kbuf, dbuf;
+ struct unexpected_key key;
+ char buf[1024];
+ int len=0;
+ TALLOC_CTX *mem_ctx;
+
+ if (!tdbd) {
+ mem_ctx = talloc_init("receive_unexpected");
+ if (!mem_ctx) return;
+ tdbd = tdb_open_log(lock_path(mem_ctx, "unexpected.tdb"), 0,
+ TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
+ O_RDWR | O_CREAT, 0644);
+ talloc_destroy(mem_ctx);
+ if (!tdbd) {
+ DEBUG(0,("Failed to open unexpected.tdb\n"));
+ return;
+ }
+ }
+
+ memset(buf,'\0',sizeof(buf));
+
+ len = build_packet(buf, p);
+
+ key.packet_type = p->packet_type;
+ key.timestamp = p->timestamp;
+ key.count = count++;
+
+ kbuf.dptr = (char *)&key;
+ kbuf.dsize = sizeof(key);
+ dbuf.dptr = buf;
+ dbuf.dsize = len;
+
+ tdb_store(tdbd, kbuf, dbuf, TDB_REPLACE);
+}
+
+
+static time_t lastt;
+
+/****************************************************************************
+delete the record if it is too old
+ **************************************************************************/
+static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+ struct unexpected_key key;
+
+ memcpy(&key, kbuf.dptr, sizeof(key));
+
+ if (lastt - key.timestamp > NMBD_UNEXPECTED_TIMEOUT) {
+ tdb_delete(ttdb, kbuf);
+ }
+
+ return 0;
+}
+
+
+/****************************************************************************
+delete all old unexpected packets
+ **************************************************************************/
+void clear_unexpected(time_t t)
+{
+ if (!tdbd) return;
+
+ if ((lastt != 0) && (t < lastt + NMBD_UNEXPECTED_TIMEOUT))
+ return;
+
+ lastt = t;
+
+ tdb_traverse(tdbd, traverse_fn, NULL);
+}
+
+
+static struct packet_struct *matched_packet;
+static int match_id;
+static enum packet_type match_type;
+static const char *match_name;
+
+/****************************************************************************
+tdb traversal fn to find a matching 137 packet
+ **************************************************************************/
+static int traverse_match(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+ struct unexpected_key key;
+ struct packet_struct *p;
+
+ memcpy(&key, kbuf.dptr, sizeof(key));
+
+ if (key.packet_type != match_type) return 0;
+
+ p = parse_packet(dbuf.dptr, dbuf.dsize, match_type);
+
+ if ((match_type == NMB_PACKET &&
+ p->packet.nmb.header.name_trn_id == match_id) ||
+ (match_type == DGRAM_PACKET &&
+ match_mailslot_name(p, match_name))) {
+ matched_packet = p;
+ return -1;
+ }
+
+ free_packet(p);
+
+ return 0;
+}
+
+
+/****************************************************************************
+check for a particular packet in the unexpected packet queue
+ **************************************************************************/
+struct packet_struct *receive_unexpected(enum packet_type packet_type, int id,
+ const char *mailslot_name)
+{
+ TDB_CONTEXT *tdb2;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("receive_unexpected");
+ if (!mem_ctx) return NULL;
+ tdb2 = tdb_open_log(lock_path(mem_ctx, "unexpected.tdb"), 0, 0, O_RDONLY, 0);
+ talloc_destroy(mem_ctx);
+ if (!tdb2) return NULL;
+
+ matched_packet = NULL;
+ match_id = id;
+ match_type = packet_type;
+ match_name = mailslot_name;
+
+ tdb_traverse(tdb2, traverse_match, NULL);
+
+ tdb_close(tdb2);
+
+ return matched_packet;
+}
diff --git a/source4/libcli/util/asn1.c b/source4/libcli/util/asn1.c
new file mode 100644
index 0000000000..09d4fbb6c9
--- /dev/null
+++ b/source4/libcli/util/asn1.c
@@ -0,0 +1,428 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple SPNEGO routines
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* free an asn1 structure */
+void asn1_free(ASN1_DATA *data)
+{
+ SAFE_FREE(data->data);
+}
+
+/* write to the ASN1 buffer, advancing the buffer pointer */
+BOOL asn1_write(ASN1_DATA *data, const void *p, int len)
+{
+ if (data->has_error) return False;
+ if (data->length < data->ofs+len) {
+ uint8 *newp;
+ newp = Realloc(data->data, data->ofs+len);
+ if (!newp) {
+ SAFE_FREE(data->data);
+ data->has_error = True;
+ return False;
+ }
+ data->data = newp;
+ data->length = data->ofs+len;
+ }
+ memcpy(data->data + data->ofs, p, len);
+ data->ofs += len;
+ return True;
+}
+
+/* useful fn for writing a uint8 */
+BOOL asn1_write_uint8(ASN1_DATA *data, uint8 v)
+{
+ return asn1_write(data, &v, 1);
+}
+
+/* push a tag onto the asn1 data buffer. Used for nested structures */
+BOOL asn1_push_tag(ASN1_DATA *data, uint8 tag)
+{
+ struct nesting *nesting;
+
+ asn1_write_uint8(data, tag);
+ nesting = (struct nesting *)malloc(sizeof(struct nesting));
+ if (!nesting) {
+ data->has_error = True;
+ return False;
+ }
+
+ nesting->start = data->ofs;
+ nesting->next = data->nesting;
+ data->nesting = nesting;
+ return asn1_write_uint8(data, 0xff);
+}
+
+/* pop a tag */
+BOOL asn1_pop_tag(ASN1_DATA *data)
+{
+ struct nesting *nesting;
+ size_t len;
+
+ nesting = data->nesting;
+
+ if (!nesting) {
+ data->has_error = True;
+ return False;
+ }
+ len = data->ofs - (nesting->start+1);
+ /* yes, this is ugly. We don't know in advance how many bytes the length
+ of a tag will take, so we assumed 1 byte. If we were wrong then we
+ need to correct our mistake */
+ if (len > 255) {
+ data->data[nesting->start] = 0x82;
+ if (!asn1_write_uint8(data, 0)) return False;
+ if (!asn1_write_uint8(data, 0)) return False;
+ memmove(data->data+nesting->start+3, data->data+nesting->start+1, len);
+ data->data[nesting->start+1] = len>>8;
+ data->data[nesting->start+2] = len&0xff;
+ } else if (len > 127) {
+ data->data[nesting->start] = 0x81;
+ if (!asn1_write_uint8(data, 0)) return False;
+ memmove(data->data+nesting->start+2, data->data+nesting->start+1, len);
+ data->data[nesting->start+1] = len;
+ } else {
+ data->data[nesting->start] = len;
+ }
+
+ data->nesting = nesting->next;
+ free(nesting);
+ return True;
+}
+
+
+/* write an integer */
+BOOL asn1_write_Integer(ASN1_DATA *data, int i)
+{
+ if (!asn1_push_tag(data, ASN1_INTEGER)) return False;
+ do {
+ asn1_write_uint8(data, i);
+ i = i >> 8;
+ } while (i);
+ return asn1_pop_tag(data);
+}
+
+/* write an object ID to a ASN1 buffer */
+BOOL asn1_write_OID(ASN1_DATA *data, const char *OID)
+{
+ unsigned v, v2;
+ const char *p = (const char *)OID;
+ char *newp;
+
+ if (!asn1_push_tag(data, ASN1_OID))
+ return False;
+ v = strtol(p, &newp, 10);
+ p = newp;
+ v2 = strtol(p, &newp, 10);
+ p = newp;
+ if (!asn1_write_uint8(data, 40*v + v2))
+ return False;
+
+ while (*p) {
+ v = strtol(p, &newp, 10);
+ p = newp;
+ if (v >= (1<<28)) asn1_write_uint8(data, 0x80 | ((v>>28)&0xff));
+ if (v >= (1<<21)) asn1_write_uint8(data, 0x80 | ((v>>21)&0xff));
+ if (v >= (1<<14)) asn1_write_uint8(data, 0x80 | ((v>>14)&0xff));
+ if (v >= (1<<7)) asn1_write_uint8(data, 0x80 | ((v>>7)&0xff));
+ if (!asn1_write_uint8(data, v&0x7f))
+ return False;
+ }
+ return asn1_pop_tag(data);
+}
+
+/* write an octet string */
+BOOL asn1_write_OctetString(ASN1_DATA *data, const void *p, size_t length)
+{
+ asn1_push_tag(data, ASN1_OCTET_STRING);
+ asn1_write(data, p, length);
+ asn1_pop_tag(data);
+ return !data->has_error;
+}
+
+/* write a general string */
+BOOL asn1_write_GeneralString(ASN1_DATA *data, const char *s)
+{
+ asn1_push_tag(data, ASN1_GENERAL_STRING);
+ asn1_write(data, s, strlen(s));
+ asn1_pop_tag(data);
+ return !data->has_error;
+}
+
+/* write a BOOLEAN */
+BOOL asn1_write_BOOLEAN(ASN1_DATA *data, BOOL v)
+{
+ asn1_write_uint8(data, ASN1_BOOLEAN);
+ asn1_write_uint8(data, v);
+ return !data->has_error;
+}
+
+/* write a BOOLEAN - hmm, I suspect this one is the correct one, and the
+ above boolean is bogus. Need to check */
+BOOL asn1_write_BOOLEAN2(ASN1_DATA *data, BOOL v)
+{
+ asn1_push_tag(data, ASN1_BOOLEAN);
+ asn1_write_uint8(data, v);
+ asn1_pop_tag(data);
+ return !data->has_error;
+}
+
+/* check a BOOLEAN */
+BOOL asn1_check_BOOLEAN(ASN1_DATA *data, BOOL v)
+{
+ uint8 b = 0;
+
+ asn1_read_uint8(data, &b);
+ if (b != ASN1_BOOLEAN) {
+ data->has_error = True;
+ return False;
+ }
+ asn1_read_uint8(data, &b);
+ if (b != v) {
+ data->has_error = True;
+ return False;
+ }
+ return !data->has_error;
+}
+
+
+/* load a ASN1_DATA structure with a lump of data, ready to be parsed */
+BOOL asn1_load(ASN1_DATA *data, DATA_BLOB blob)
+{
+ ZERO_STRUCTP(data);
+ data->data = memdup(blob.data, blob.length);
+ if (!data->data) {
+ data->has_error = True;
+ return False;
+ }
+ data->length = blob.length;
+ return True;
+}
+
+/* read from a ASN1 buffer, advancing the buffer pointer */
+BOOL asn1_read(ASN1_DATA *data, void *p, int len)
+{
+ if (data->ofs + len > data->length) {
+ data->has_error = True;
+ return False;
+ }
+ memcpy(p, data->data + data->ofs, len);
+ data->ofs += len;
+ return True;
+}
+
+/* read a uint8 from a ASN1 buffer */
+BOOL asn1_read_uint8(ASN1_DATA *data, uint8 *v)
+{
+ return asn1_read(data, v, 1);
+}
+
+/* start reading a nested asn1 structure */
+BOOL asn1_start_tag(ASN1_DATA *data, uint8 tag)
+{
+ uint8 b;
+ struct nesting *nesting;
+
+ if (!asn1_read_uint8(data, &b))
+ return False;
+
+ if (b != tag) {
+ data->has_error = True;
+ return False;
+ }
+ nesting = (struct nesting *)malloc(sizeof(struct nesting));
+ if (!nesting) {
+ data->has_error = True;
+ return False;
+ }
+
+ if (!asn1_read_uint8(data, &b)) {
+ return False;
+ }
+
+ if (b & 0x80) {
+ int n = b & 0x7f;
+ if (!asn1_read_uint8(data, &b))
+ return False;
+ nesting->taglen = b;
+ while (n > 1) {
+ if (!asn1_read_uint8(data, &b))
+ return False;
+ nesting->taglen = (nesting->taglen << 8) | b;
+ n--;
+ }
+ } else {
+ nesting->taglen = b;
+ }
+ nesting->start = data->ofs;
+ nesting->next = data->nesting;
+ data->nesting = nesting;
+ return !data->has_error;
+}
+
+
+/* stop reading a tag */
+BOOL asn1_end_tag(ASN1_DATA *data)
+{
+ struct nesting *nesting;
+
+ /* make sure we read it all */
+ if (asn1_tag_remaining(data) != 0) {
+ data->has_error = True;
+ return False;
+ }
+
+ nesting = data->nesting;
+
+ if (!nesting) {
+ data->has_error = True;
+ return False;
+ }
+
+ data->nesting = nesting->next;
+ free(nesting);
+ return True;
+}
+
+/* work out how many bytes are left in this nested tag */
+int asn1_tag_remaining(ASN1_DATA *data)
+{
+ if (!data->nesting) {
+ data->has_error = True;
+ return -1;
+ }
+ return data->nesting->taglen - (data->ofs - data->nesting->start);
+}
+
+/* read an object ID from a ASN1 buffer */
+BOOL asn1_read_OID(ASN1_DATA *data, char **OID)
+{
+ uint8 b;
+ pstring oid;
+ fstring el;
+
+ if (!asn1_start_tag(data, ASN1_OID)) return False;
+ asn1_read_uint8(data, &b);
+
+ oid[0] = 0;
+ snprintf(el, sizeof(el), "%u", b/40);
+ pstrcat(oid, el);
+ snprintf(el, sizeof(el), " %u", b%40);
+ pstrcat(oid, el);
+
+ while (asn1_tag_remaining(data) > 0) {
+ unsigned v = 0;
+ do {
+ asn1_read_uint8(data, &b);
+ v = (v<<7) | (b&0x7f);
+ } while (!data->has_error && b & 0x80);
+ snprintf(el, sizeof(el), " %u", v);
+ pstrcat(oid, el);
+ }
+
+ asn1_end_tag(data);
+
+ *OID = strdup(oid);
+
+ return !data->has_error;
+}
+
+/* check that the next object ID is correct */
+BOOL asn1_check_OID(ASN1_DATA *data, const char *OID)
+{
+ char *id;
+
+ if (!asn1_read_OID(data, &id)) return False;
+
+ if (strcmp(id, OID) != 0) {
+ data->has_error = True;
+ return False;
+ }
+ free(id);
+ return True;
+}
+
+/* read a GeneralString from a ASN1 buffer */
+BOOL asn1_read_GeneralString(ASN1_DATA *data, char **s)
+{
+ int len;
+ if (!asn1_start_tag(data, ASN1_GENERAL_STRING)) return False;
+ len = asn1_tag_remaining(data);
+ *s = malloc(len+1);
+ if (! *s) {
+ data->has_error = True;
+ return False;
+ }
+ asn1_read(data, *s, len);
+ (*s)[len] = 0;
+ asn1_end_tag(data);
+ return !data->has_error;
+}
+
+/* read a octet string blob */
+BOOL asn1_read_OctetString(ASN1_DATA *data, DATA_BLOB *blob)
+{
+ int len;
+ ZERO_STRUCTP(blob);
+ if (!asn1_start_tag(data, ASN1_OCTET_STRING)) return False;
+ len = asn1_tag_remaining(data);
+ *blob = data_blob(NULL, len);
+ asn1_read(data, blob->data, len);
+ asn1_end_tag(data);
+ return !data->has_error;
+}
+
+/* read an interger */
+BOOL asn1_read_Integer(ASN1_DATA *data, int *i)
+{
+ uint8 b;
+ *i = 0;
+
+ if (!asn1_start_tag(data, ASN1_INTEGER)) return False;
+ while (asn1_tag_remaining(data)>0) {
+ asn1_read_uint8(data, &b);
+ *i = (*i << 8) + b;
+ }
+ return asn1_end_tag(data);
+
+}
+
+/* check a enumarted value is correct */
+BOOL asn1_check_enumerated(ASN1_DATA *data, int v)
+{
+ uint8 b;
+ if (!asn1_start_tag(data, ASN1_ENUMERATED)) return False;
+ asn1_read_uint8(data, &b);
+ asn1_end_tag(data);
+
+ if (v != b)
+ data->has_error = False;
+
+ return !data->has_error;
+}
+
+/* write an enumarted value to the stream */
+BOOL asn1_write_enumerated(ASN1_DATA *data, uint8 v)
+{
+ if (!asn1_push_tag(data, ASN1_ENUMERATED)) return False;
+ asn1_write_uint8(data, v);
+ asn1_pop_tag(data);
+ return !data->has_error;
+}
diff --git a/source4/libcli/util/clierror.c b/source4/libcli/util/clierror.c
new file mode 100644
index 0000000000..4fa1daa3be
--- /dev/null
+++ b/source4/libcli/util/clierror.c
@@ -0,0 +1,99 @@
+/*
+ Unix SMB/CIFS implementation.
+ client error handling routines
+ Copyright (C) Andrew Tridgell 1994-1998
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+
+/***************************************************************************
+ Return an error message from the last response
+****************************************************************************/
+const char *cli_errstr(struct cli_state *cli)
+{
+ switch (cli->transport->error.etype) {
+ case ETYPE_DOS:
+ return dos_errstr(cli->transport->error.e.dos.eclass,
+ cli->transport->error.e.dos.ecode);
+ case ETYPE_NT:
+ return nt_errstr(cli->transport->error.e.nt_status);
+
+ case ETYPE_SOCKET:
+ return "socket_error";
+
+ case ETYPE_NBT:
+ return "nbt_error";
+
+ case ETYPE_NONE:
+ return "no_error";
+ }
+ return NULL;
+}
+
+
+/* Return the 32-bit NT status code from the last packet */
+NTSTATUS cli_nt_error(struct cli_state *cli)
+{
+ switch (cli->transport->error.etype) {
+ case ETYPE_NT:
+ return cli->transport->error.e.nt_status;
+
+ case ETYPE_DOS:
+ return dos_to_ntstatus(cli->transport->error.e.dos.eclass,
+ cli->transport->error.e.dos.ecode);
+ case ETYPE_SOCKET:
+ return NT_STATUS_UNSUCCESSFUL;
+
+ case ETYPE_NBT:
+ return NT_STATUS_UNSUCCESSFUL;
+
+ case ETYPE_NONE:
+ return NT_STATUS_OK;
+ }
+
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+
+/* Return the DOS error from the last packet - an error class and an error
+ code. */
+void cli_dos_error(struct cli_state *cli, uint8 *eclass, uint32 *ecode)
+{
+ if (cli->transport->error.etype == ETYPE_DOS) {
+ ntstatus_to_dos(cli->transport->error.e.nt_status,
+ eclass, ecode);
+ return;
+ }
+
+ if (eclass) *eclass = cli->transport->error.e.dos.eclass;
+ if (ecode) *ecode = cli->transport->error.e.dos.ecode;
+}
+
+
+/* Return true if the last packet was an error */
+BOOL cli_is_error(struct cli_state *cli)
+{
+ return NT_STATUS_IS_ERR(cli_nt_error(cli));
+}
+
+/* Return true if the last error was a DOS error */
+BOOL cli_is_dos_error(struct cli_state *cli)
+{
+ return cli->transport->error.etype == ETYPE_DOS;
+}
diff --git a/source4/libcli/util/cliutil.c b/source4/libcli/util/cliutil.c
new file mode 100644
index 0000000000..47f94992a4
--- /dev/null
+++ b/source4/libcli/util/cliutil.c
@@ -0,0 +1,110 @@
+/*
+ Unix SMB/CIFS implementation.
+ client utility routines
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) James Myers 2003 <myersjj@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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+/*******************************************************************
+ Functions nicked from lib/util.c needed by client.
+*******************************************************************/
+
+/* a default finfo structure to ensure all fields are sensible */
+file_info def_finfo = {-1,0,0,0,0,0,0,"",""};
+
+/*******************************************************************
+ A wrapper that handles case sensitivity and the special handling
+ of the ".." name.
+*******************************************************************/
+
+BOOL mask_match(struct cli_state *cli, const char *string, char *pattern, BOOL is_case_sensitive)
+{
+ fstring p2, s2;
+
+ if (strcmp(string,"..") == 0)
+ string = ".";
+ if (strcmp(pattern,".") == 0)
+ return False;
+
+ if (is_case_sensitive)
+ return ms_fnmatch(pattern, string,
+ cli->transport->negotiate.protocol) == 0;
+
+ fstrcpy(p2, pattern);
+ fstrcpy(s2, string);
+ strlower(p2);
+ strlower(s2);
+ return ms_fnmatch(p2, s2, cli->transport->negotiate.protocol) == 0;
+}
+
+/****************************************************************************
+ Put up a yes/no prompt.
+****************************************************************************/
+
+BOOL yesno(char *p)
+{
+ pstring ans;
+ printf("%s",p);
+
+ if (!fgets(ans,sizeof(ans)-1,stdin))
+ return(False);
+
+ if (*ans == 'y' || *ans == 'Y')
+ return(True);
+
+ return(False);
+}
+
+/*******************************************************************
+ A readdir wrapper which just returns the file name.
+ ********************************************************************/
+
+const char *readdirname(DIR *p)
+{
+ SMB_STRUCT_DIRENT *ptr;
+ char *dname;
+
+ if (!p)
+ return(NULL);
+
+ ptr = (SMB_STRUCT_DIRENT *)sys_readdir(p);
+ if (!ptr)
+ return(NULL);
+
+ dname = ptr->d_name;
+
+#ifdef NEXT2
+ if (telldir(p) < 0)
+ return(NULL);
+#endif
+
+#ifdef HAVE_BROKEN_READDIR
+ /* using /usr/ucb/cc is BAD */
+ dname = dname - 2;
+#endif
+
+ {
+ static pstring buf;
+ int len = NAMLEN(ptr);
+ memcpy(buf, dname, len);
+ buf[len] = 0;
+ dname = buf;
+ }
+
+ return(dname);
+}
diff --git a/source4/libcli/util/credentials.c b/source4/libcli/util/credentials.c
new file mode 100644
index 0000000000..0d521bae8a
--- /dev/null
+++ b/source4/libcli/util/credentials.c
@@ -0,0 +1,215 @@
+/*
+ Unix SMB/CIFS implementation.
+ code to manipulate domain credentials
+ Copyright (C) Andrew Tridgell 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+represent a credential as a string
+****************************************************************************/
+char *credstr(const uchar *cred)
+{
+ static fstring buf;
+ slprintf(buf, sizeof(buf) - 1, "%02X%02X%02X%02X%02X%02X%02X%02X",
+ cred[0], cred[1], cred[2], cred[3],
+ cred[4], cred[5], cred[6], cred[7]);
+ return buf;
+}
+
+
+/****************************************************************************
+ setup the session key.
+Input: 8 byte challenge block
+ 8 byte server challenge block
+ 16 byte md4 encrypted password
+Output:
+ 8 byte session key
+****************************************************************************/
+void cred_session_key(const DOM_CHAL *clnt_chal, const DOM_CHAL *srv_chal, const uchar *pass,
+ uchar session_key[8])
+{
+ uint32 sum[2];
+ unsigned char sum2[8];
+
+ sum[0] = IVAL(clnt_chal->data, 0) + IVAL(srv_chal->data, 0);
+ sum[1] = IVAL(clnt_chal->data, 4) + IVAL(srv_chal->data, 4);
+
+ SIVAL(sum2,0,sum[0]);
+ SIVAL(sum2,4,sum[1]);
+
+ cred_hash1(session_key, sum2, pass);
+
+ /* debug output */
+ DEBUG(4,("cred_session_key\n"));
+
+ DEBUG(5,(" clnt_chal: %s\n", credstr(clnt_chal->data)));
+ DEBUG(5,(" srv_chal : %s\n", credstr(srv_chal->data)));
+ DEBUG(5,(" clnt+srv : %s\n", credstr(sum2)));
+ DEBUG(5,(" sess_key : %s\n", credstr(session_key)));
+}
+
+
+/****************************************************************************
+create a credential
+
+Input:
+ 8 byte sesssion key
+ 8 byte stored credential
+ 4 byte timestamp
+
+Output:
+ 8 byte credential
+****************************************************************************/
+void cred_create(uchar session_key[8], DOM_CHAL *stor_cred, UTIME timestamp,
+ DOM_CHAL *cred)
+{
+ DOM_CHAL time_cred;
+
+ SIVAL(time_cred.data, 0, IVAL(stor_cred->data, 0) + timestamp.time);
+ SIVAL(time_cred.data, 4, IVAL(stor_cred->data, 4));
+
+ cred_hash2(cred->data, time_cred.data, session_key);
+
+ /* debug output*/
+ DEBUG(4,("cred_create\n"));
+
+ DEBUG(5,(" sess_key : %s\n", credstr(session_key)));
+ DEBUG(5,(" stor_cred: %s\n", credstr(stor_cred->data)));
+ DEBUG(5,(" timestamp: %x\n" , timestamp.time));
+ DEBUG(5,(" timecred : %s\n", credstr(time_cred.data)));
+ DEBUG(5,(" calc_cred: %s\n", credstr(cred->data)));
+}
+
+
+/****************************************************************************
+ check a supplied credential
+
+Input:
+ 8 byte received credential
+ 8 byte sesssion key
+ 8 byte stored credential
+ 4 byte timestamp
+
+Output:
+ returns 1 if computed credential matches received credential
+ returns 0 otherwise
+****************************************************************************/
+int cred_assert(DOM_CHAL *cred, uchar session_key[8], DOM_CHAL *stored_cred,
+ UTIME timestamp)
+{
+ DOM_CHAL cred2;
+
+ cred_create(session_key, stored_cred, timestamp, &cred2);
+
+ /* debug output*/
+ DEBUG(4,("cred_assert\n"));
+
+ DEBUG(5,(" challenge : %s\n", credstr(cred->data)));
+ DEBUG(5,(" calculated: %s\n", credstr(cred2.data)));
+
+ if (memcmp(cred->data, cred2.data, 8) == 0)
+ {
+ DEBUG(5, ("credentials check ok\n"));
+ return True;
+ }
+ else
+ {
+ DEBUG(5, ("credentials check wrong\n"));
+ return False;
+ }
+}
+
+
+/****************************************************************************
+ checks credentials; generates next step in the credential chain
+****************************************************************************/
+BOOL clnt_deal_with_creds(uchar sess_key[8],
+ DOM_CRED *sto_clnt_cred, DOM_CRED *rcv_srv_cred)
+{
+ UTIME new_clnt_time;
+ uint32 new_cred;
+
+ DEBUG(5,("clnt_deal_with_creds: %d\n", __LINE__));
+
+ /* increment client time by one second */
+ new_clnt_time.time = sto_clnt_cred->timestamp.time + 1;
+
+ /* check that the received server credentials are valid */
+ if (!cred_assert(&rcv_srv_cred->challenge, sess_key,
+ &sto_clnt_cred->challenge, new_clnt_time))
+ {
+ return False;
+ }
+
+ /* first 4 bytes of the new seed is old client 4 bytes + clnt time + 1 */
+ new_cred = IVAL(sto_clnt_cred->challenge.data, 0);
+ new_cred += new_clnt_time.time;
+
+ /* store new seed in client credentials */
+ SIVAL(sto_clnt_cred->challenge.data, 0, new_cred);
+
+ DEBUG(5,(" new clnt cred: %s\n", credstr(sto_clnt_cred->challenge.data)));
+ return True;
+}
+
+
+/****************************************************************************
+ checks credentials; generates next step in the credential chain
+****************************************************************************/
+BOOL deal_with_creds(uchar sess_key[8],
+ DOM_CRED *sto_clnt_cred,
+ DOM_CRED *rcv_clnt_cred, DOM_CRED *rtn_srv_cred)
+{
+ UTIME new_clnt_time;
+ uint32 new_cred;
+
+ DEBUG(5,("deal_with_creds: %d\n", __LINE__));
+
+ /* check that the received client credentials are valid */
+ if (!cred_assert(&rcv_clnt_cred->challenge, sess_key,
+ &sto_clnt_cred->challenge, rcv_clnt_cred->timestamp))
+ {
+ return False;
+ }
+
+ /* increment client time by one second */
+ new_clnt_time.time = rcv_clnt_cred->timestamp.time + 1;
+
+ /* first 4 bytes of the new seed is old client 4 bytes + clnt time + 1 */
+ new_cred = IVAL(sto_clnt_cred->challenge.data, 0);
+ new_cred += new_clnt_time.time;
+
+ DEBUG(5,("deal_with_creds: new_cred[0]=%x\n", new_cred));
+
+ /* doesn't matter that server time is 0 */
+ rtn_srv_cred->timestamp.time = 0;
+
+ DEBUG(5,("deal_with_creds: new_clnt_time=%x\n", new_clnt_time.time));
+
+ /* create return credentials for inclusion in the reply */
+ cred_create(sess_key, &sto_clnt_cred->challenge, new_clnt_time,
+ &rtn_srv_cred->challenge);
+
+ DEBUG(5,("deal_with_creds: clnt_cred=%s\n", credstr(sto_clnt_cred->challenge.data)));
+
+ /* store new seed in client credentials */
+ SIVAL(sto_clnt_cred->challenge.data, 0, new_cred);
+
+ return True;
+}
diff --git a/source4/libcli/util/doserr.c b/source4/libcli/util/doserr.c
new file mode 100644
index 0000000000..28bad6109d
--- /dev/null
+++ b/source4/libcli/util/doserr.c
@@ -0,0 +1,91 @@
+/*
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* DOS error codes. please read doserr.h */
+
+#include "includes.h"
+
+typedef const struct
+{
+ const char *dos_errstr;
+ WERROR werror;
+} werror_code_struct;
+
+werror_code_struct dos_errs[] =
+{
+ { "WERR_OK", WERR_OK },
+ { "WERR_BADFILE", WERR_BADFILE },
+ { "WERR_ACCESS_DENIED", WERR_ACCESS_DENIED },
+ { "WERR_BADFID", WERR_BADFID },
+ { "WERR_BADFUNC", WERR_BADFUNC },
+ { "WERR_INSUFFICIENT_BUFFER", WERR_INSUFFICIENT_BUFFER },
+ { "WERR_NO_SUCH_SHARE", WERR_NO_SUCH_SHARE },
+ { "WERR_ALREADY_EXISTS", WERR_ALREADY_EXISTS },
+ { "WERR_INVALID_PARAM", WERR_INVALID_PARAM },
+ { "WERR_NOT_SUPPORTED", WERR_NOT_SUPPORTED },
+ { "WERR_BAD_PASSWORD", WERR_BAD_PASSWORD },
+ { "WERR_NOMEM", WERR_NOMEM },
+ { "WERR_INVALID_NAME", WERR_INVALID_NAME },
+ { "WERR_UNKNOWN_LEVEL", WERR_UNKNOWN_LEVEL },
+ { "WERR_OBJECT_PATH_INVALID", WERR_OBJECT_PATH_INVALID },
+ { "WERR_NO_MORE_ITEMS", WERR_NO_MORE_ITEMS },
+ { "WERR_MORE_DATA", WERR_MORE_DATA },
+ { "WERR_UNKNOWN_PRINTER_DRIVER", WERR_UNKNOWN_PRINTER_DRIVER },
+ { "WERR_INVALID_PRINTER_NAME", WERR_INVALID_PRINTER_NAME },
+ { "WERR_PRINTER_ALREADY_EXISTS", WERR_PRINTER_ALREADY_EXISTS },
+ { "WERR_INVALID_DATATYPE", WERR_INVALID_DATATYPE },
+ { "WERR_INVALID_ENVIRONMENT", WERR_INVALID_ENVIRONMENT },
+ { "WERR_INVALID_FORM_NAME", WERR_INVALID_FORM_NAME },
+ { "WERR_INVALID_FORM_SIZE", WERR_INVALID_FORM_SIZE },
+ { "WERR_BUF_TOO_SMALL", WERR_BUF_TOO_SMALL },
+ { "WERR_JOB_NOT_FOUND", WERR_JOB_NOT_FOUND },
+ { "WERR_DEST_NOT_FOUND", WERR_DEST_NOT_FOUND },
+ { "WERR_NOT_LOCAL_DOMAIN", WERR_NOT_LOCAL_DOMAIN },
+ { "WERR_PRINTER_DRIVER_IN_USE", WERR_PRINTER_DRIVER_IN_USE },
+ { "WERR_STATUS_MORE_ENTRIES ", WERR_STATUS_MORE_ENTRIES },
+ { "WERR_DFS_NO_SUCH_VOL", WERR_DFS_NO_SUCH_VOL },
+ { "WERR_DFS_NO_SUCH_SHARE", WERR_DFS_NO_SUCH_SHARE },
+ { "WERR_DFS_NO_SUCH_SERVER", WERR_DFS_NO_SUCH_SERVER },
+ { "WERR_DFS_INTERNAL_ERROR", WERR_DFS_INTERNAL_ERROR },
+ { "WERR_DFS_CANT_CREATE_JUNCT", WERR_DFS_CANT_CREATE_JUNCT },
+ { "WERR_INVALID_SECURITY_DESCRIPTOR", WERR_INVALID_SECURITY_DESCRIPTOR },
+ { "WERR_INVALID_OWNER", WERR_INVALID_OWNER },
+ { NULL, W_ERROR(0) }
+};
+
+/*****************************************************************************
+ returns a windows error message. not amazingly helpful, but better than a number.
+ *****************************************************************************/
+const char *win_errstr(WERROR werror)
+{
+ static pstring msg;
+ int idx = 0;
+
+ slprintf(msg, sizeof(msg), "DOS code 0x%08x", W_ERROR_V(werror));
+
+ while (dos_errs[idx].dos_errstr != NULL) {
+ if (W_ERROR_V(dos_errs[idx].werror) ==
+ W_ERROR_V(werror))
+ return dos_errs[idx].dos_errstr;
+ idx++;
+ }
+
+ return msg;
+}
diff --git a/source4/libcli/util/errormap.c b/source4/libcli/util/errormap.c
new file mode 100644
index 0000000000..a257c2d0ea
--- /dev/null
+++ b/source4/libcli/util/errormap.c
@@ -0,0 +1,1546 @@
+/*
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#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 dos_class;
+ uint32 dos_code;
+ NTSTATUS ntstatus;
+} ntstatus_to_dos_map[] = {
+ {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, 87, 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, 161, NT_STATUS_OBJECT_PATH_INVALID},
+ {ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND},
+ {ERRDOS, 161, 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, 282, 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},
+ {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, 267, 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, 124, 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)},
+};
+
+
+/* dos -> nt status error map */
+static const struct {
+ uint8 dos_class;
+ uint32 dos_code;
+ NTSTATUS ntstatus;
+} dos_to_ntstatus_map[] = {
+ {ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED},
+ {ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE},
+ {ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND},
+ {ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES},
+ {ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED},
+ {ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE},
+ {ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES},
+ {ERRDOS, ERRbadaccess, NT_STATUS_INVALID_LOCK_SEQUENCE},
+ {ERRDOS, ERRbaddata, NT_STATUS_DATA_ERROR},
+ {ERRDOS, 14, NT_STATUS_SECTION_NOT_EXTENDED},
+ {ERRDOS, ERRremcd, NT_STATUS_DIRECTORY_NOT_EMPTY},
+ {ERRDOS, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE},
+ {ERRDOS, ERRnofiles, NT_STATUS(0x80000006)},
+ {ERRDOS, 19, NT_STATUS_MEDIA_WRITE_PROTECTED},
+ {ERRDOS, 21, NT_STATUS_NO_MEDIA_IN_DEVICE},
+ {ERRDOS, 22, NT_STATUS_INVALID_DEVICE_STATE},
+ {ERRDOS, 23, NT_STATUS_DATA_ERROR},
+ {ERRDOS, 24, NT_STATUS_DATA_ERROR},
+ {ERRDOS, 26, NT_STATUS_DISK_CORRUPT_ERROR},
+ {ERRDOS, 27, NT_STATUS_NONEXISTENT_SECTOR},
+ {ERRDOS, 28, NT_STATUS(0x8000000e)},
+ {ERRDOS, 31, NT_STATUS_UNSUCCESSFUL},
+ {ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION},
+ {ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT},
+ {ERRDOS, 34, NT_STATUS_WRONG_VOLUME},
+ {ERRDOS, 38, NT_STATUS_END_OF_FILE},
+ {ERRDOS, ERRunsup, NT_STATUS_CTL_FILE_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_GUIDS_REQUESTED},
+ {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, ERRfilexists, NT_STATUS_OBJECT_NAME_COLLISION},
+ {ERRDOS, 86, NT_STATUS_WRONG_PASSWORD},
+ {ERRDOS, 87, NT_STATUS_INVALID_INFO_CLASS},
+ {ERRDOS, 88, NT_STATUS_NET_WRITE_FAULT},
+ {ERRDOS, 109, NT_STATUS_PIPE_BROKEN},
+ {ERRDOS, 111, STATUS_MORE_ENTRIES},
+ {ERRDOS, 112, NT_STATUS_DISK_FULL},
+ {ERRDOS, 121, NT_STATUS_IO_TIMEOUT},
+ {ERRDOS, 122, NT_STATUS_BUFFER_TOO_SMALL},
+ {ERRDOS, ERRinvalidname, NT_STATUS_OBJECT_NAME_INVALID},
+ {ERRDOS, 124, NT_STATUS_INVALID_LEVEL},
+ {ERRDOS, 126, NT_STATUS_DLL_NOT_FOUND},
+ {ERRDOS, 127, NT_STATUS_PROCEDURE_NOT_FOUND},
+ {ERRDOS, 145, NT_STATUS_DIRECTORY_NOT_EMPTY},
+ {ERRDOS, 154, NT_STATUS_INVALID_VOLUME_LABEL},
+ {ERRDOS, 156, NT_STATUS_SUSPEND_COUNT_EXCEEDED},
+ {ERRDOS, 158, NT_STATUS_NOT_LOCKED},
+ {ERRDOS, 161, NT_STATUS_OBJECT_PATH_INVALID},
+ {ERRDOS, 170, NT_STATUS(0x80000011)},
+ {ERRDOS, 182, NT_STATUS_ORDINAL_NOT_FOUND},
+ {ERRDOS, 183, NT_STATUS_OBJECT_NAME_COLLISION},
+ {ERRDOS, 193, NT_STATUS_BAD_INITIAL_PC},
+ {ERRDOS, 203, NT_STATUS(0xc0000100)},
+ {ERRDOS, 206, NT_STATUS_NAME_TOO_LONG},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_INFO_CLASS},
+ {ERRDOS, ERRpipebusy, NT_STATUS_INSTANCE_NOT_AVAILABLE},
+ {ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_CLOSING},
+ {ERRDOS, ERRnotconnected, NT_STATUS_PIPE_DISCONNECTED},
+ {ERRDOS, ERRmoredata, NT_STATUS_MORE_PROCESSING_REQUIRED},
+ {ERRDOS, 240, NT_STATUS_VIRTUAL_CIRCUIT_CLOSED},
+ {ERRDOS, 254, NT_STATUS(0x80000013)},
+ {ERRDOS, 255, NT_STATUS_EA_TOO_LARGE},
+ {ERRDOS, 259, NT_STATUS_GUIDS_EXHAUSTED},
+ {ERRDOS, 267, NT_STATUS_NOT_A_DIRECTORY},
+ {ERRDOS, 275, NT_STATUS_EA_TOO_LARGE},
+ {ERRDOS, 276, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRDOS, 277, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRDOS, 278, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRDOS, 282, NT_STATUS_EAS_NOT_SUPPORTED},
+ {ERRDOS, 288, NT_STATUS_MUTANT_NOT_OWNED},
+ {ERRDOS, 298, NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED},
+ {ERRDOS, 299, NT_STATUS(0x8000000d)},
+ {ERRDOS, 300, NT_STATUS_OPLOCK_NOT_GRANTED},
+ {ERRDOS, 301, NT_STATUS_INVALID_OPLOCK_PROTOCOL},
+ {ERRDOS, 487, NT_STATUS_CONFLICTING_ADDRESSES},
+ {ERRDOS, 534, NT_STATUS_INTEGER_OVERFLOW},
+ {ERRDOS, 535, NT_STATUS_PIPE_CONNECTED},
+ {ERRDOS, 536, NT_STATUS_PIPE_LISTENING},
+ {ERRDOS, 995, NT_STATUS_CANCELLED},
+ {ERRDOS, 997, NT_STATUS(0x00000103)},
+ {ERRDOS, 998, NT_STATUS_ACCESS_VIOLATION},
+ {ERRDOS, 999, NT_STATUS_IN_PAGE_ERROR},
+ {ERRDOS, 1001, NT_STATUS_BAD_INITIAL_STACK},
+ {ERRDOS, 1005, NT_STATUS_UNRECOGNIZED_VOLUME},
+ {ERRDOS, 1006, NT_STATUS_FILE_INVALID},
+ {ERRDOS, 1007, NT_STATUS_FULLSCREEN_MODE},
+ {ERRDOS, 1008, NT_STATUS_NO_TOKEN},
+ {ERRDOS, 1009, NT_STATUS_REGISTRY_CORRUPT},
+ {ERRDOS, 1016, NT_STATUS_REGISTRY_IO_FAILED},
+ {ERRDOS, 1017, NT_STATUS_NOT_REGISTRY_FILE},
+ {ERRDOS, 1018, NT_STATUS_KEY_DELETED},
+ {ERRDOS, 1019, NT_STATUS_NO_LOG_SPACE},
+ {ERRDOS, 1020, NT_STATUS_KEY_HAS_CHILDREN},
+ {ERRDOS, 1021, NT_STATUS_CHILD_MUST_BE_VOLATILE},
+ {ERRDOS, 1022, NT_STATUS(0x0000010c)},
+ {ERRSRV, ERRbadpw, NT_STATUS_WRONG_PASSWORD},
+ {ERRSRV, ERRbadtype, NT_STATUS_BAD_DEVICE_TYPE},
+ {ERRSRV, ERRaccess, NT_STATUS_NETWORK_ACCESS_DENIED},
+ {ERRSRV, ERRinvnid, NT_STATUS_NETWORK_NAME_DELETED},
+ {ERRSRV, ERRinvnetname, NT_STATUS_BAD_NETWORK_NAME},
+ {ERRSRV, ERRinvdevice, NT_STATUS_BAD_DEVICE_TYPE},
+ {ERRSRV, ERRqfull, NT_STATUS_PRINT_QUEUE_FULL},
+ {ERRSRV, ERRqtoobig, NT_STATUS_NO_SPOOL_SPACE},
+ {ERRSRV, ERRinvpfid, NT_STATUS_PRINT_CANCELLED},
+ {ERRSRV, ERRsmbcmd, NT_STATUS_NOT_IMPLEMENTED},
+ {ERRSRV, ERRbadpermits, NT_STATUS_NETWORK_ACCESS_DENIED},
+ {ERRSRV, ERRpaused, NT_STATUS_SHARING_PAUSED},
+ {ERRSRV, ERRmsgoff, NT_STATUS_REQUEST_NOT_ACCEPTED},
+ {ERRSRV, ERRnoroom, NT_STATUS_DISK_FULL},
+ {ERRSRV, ERRnoresource, NT_STATUS_REQUEST_NOT_ACCEPTED},
+ {ERRSRV, ERRtoomanyuids, NT_STATUS_TOO_MANY_SESSIONS},
+ {ERRSRV, 123, NT_STATUS_OBJECT_NAME_INVALID},
+ {ERRSRV, 206, NT_STATUS_OBJECT_NAME_INVALID},
+ {ERRHRD, 1, NT_STATUS_NOT_IMPLEMENTED},
+ {ERRHRD, 2, NT_STATUS_NO_SUCH_DEVICE},
+ {ERRHRD, 3, NT_STATUS_OBJECT_PATH_NOT_FOUND},
+ {ERRHRD, 4, NT_STATUS_TOO_MANY_OPENED_FILES},
+ {ERRHRD, 5, NT_STATUS_INVALID_LOCK_SEQUENCE},
+ {ERRHRD, 6, NT_STATUS_INVALID_HANDLE},
+ {ERRHRD, 8, NT_STATUS_INSUFFICIENT_RESOURCES},
+ {ERRHRD, 12, NT_STATUS_INVALID_LOCK_SEQUENCE},
+ {ERRHRD, 13, NT_STATUS_DATA_ERROR},
+ {ERRHRD, 14, NT_STATUS_SECTION_NOT_EXTENDED},
+ {ERRHRD, 16, NT_STATUS_DIRECTORY_NOT_EMPTY},
+ {ERRHRD, 17, NT_STATUS_NOT_SAME_DEVICE},
+ {ERRHRD, 18, NT_STATUS(0x80000006)},
+ {ERRHRD, ERRnowrite, NT_STATUS_MEDIA_WRITE_PROTECTED},
+ {ERRHRD, ERRnotready, NT_STATUS_NO_MEDIA_IN_DEVICE},
+ {ERRHRD, ERRbadcmd, NT_STATUS_INVALID_DEVICE_STATE},
+ {ERRHRD, ERRdata, NT_STATUS_DATA_ERROR},
+ {ERRHRD, ERRbadreq, NT_STATUS_DATA_ERROR},
+ {ERRHRD, ERRbadmedia, NT_STATUS_DISK_CORRUPT_ERROR},
+ {ERRHRD, ERRbadsector, NT_STATUS_NONEXISTENT_SECTOR},
+ {ERRHRD, ERRnopaper, NT_STATUS(0x8000000e)},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNSUCCESSFUL},
+ {ERRHRD, ERRbadshare, NT_STATUS_SHARING_VIOLATION},
+ {ERRHRD, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT},
+ {ERRHRD, ERRwrongdisk, NT_STATUS_WRONG_VOLUME},
+ {ERRHRD, 38, NT_STATUS_END_OF_FILE},
+ {ERRHRD, ERRdiskfull, NT_STATUS_DISK_FULL},
+ {ERRHRD, 50, NT_STATUS_CTL_FILE_NOT_SUPPORTED},
+ {ERRHRD, 51, NT_STATUS_REMOTE_NOT_LISTENING},
+ {ERRHRD, 52, NT_STATUS_DUPLICATE_NAME},
+ {ERRHRD, 53, NT_STATUS_BAD_NETWORK_PATH},
+ {ERRHRD, 54, NT_STATUS_NETWORK_BUSY},
+ {ERRHRD, 55, NT_STATUS_DEVICE_DOES_NOT_EXIST},
+ {ERRHRD, 56, NT_STATUS_TOO_MANY_COMMANDS},
+ {ERRHRD, 57, NT_STATUS_ADAPTER_HARDWARE_ERROR},
+ {ERRHRD, 58, NT_STATUS_INVALID_NETWORK_RESPONSE},
+ {ERRHRD, 59, NT_STATUS_UNEXPECTED_NETWORK_ERROR},
+ {ERRHRD, 60, NT_STATUS_BAD_REMOTE_ADAPTER},
+ {ERRHRD, 61, NT_STATUS_PRINT_QUEUE_FULL},
+ {ERRHRD, 62, NT_STATUS_NO_SPOOL_SPACE},
+ {ERRHRD, 63, NT_STATUS_PRINT_CANCELLED},
+ {ERRHRD, 64, NT_STATUS_NETWORK_NAME_DELETED},
+ {ERRHRD, 65, NT_STATUS_NETWORK_ACCESS_DENIED},
+ {ERRHRD, 66, NT_STATUS_BAD_DEVICE_TYPE},
+ {ERRHRD, 67, NT_STATUS_BAD_NETWORK_NAME},
+ {ERRHRD, 68, NT_STATUS_TOO_MANY_GUIDS_REQUESTED},
+ {ERRHRD, 69, NT_STATUS_TOO_MANY_SESSIONS},
+ {ERRHRD, 70, NT_STATUS_SHARING_PAUSED},
+ {ERRHRD, 71, NT_STATUS_REQUEST_NOT_ACCEPTED},
+ {ERRHRD, 72, NT_STATUS_REDIRECTOR_PAUSED},
+ {ERRHRD, 80, NT_STATUS_OBJECT_NAME_COLLISION},
+ {ERRHRD, 86, NT_STATUS_WRONG_PASSWORD},
+ {ERRHRD, 87, NT_STATUS_INVALID_INFO_CLASS},
+ {ERRHRD, 88, NT_STATUS_NET_WRITE_FAULT},
+ {ERRHRD, 109, NT_STATUS_PIPE_BROKEN},
+ {ERRHRD, 111, STATUS_MORE_ENTRIES},
+ {ERRHRD, 112, NT_STATUS_DISK_FULL},
+ {ERRHRD, 121, NT_STATUS_IO_TIMEOUT},
+ {ERRHRD, 122, NT_STATUS_BUFFER_TOO_SMALL},
+ {ERRHRD, 123, NT_STATUS_OBJECT_NAME_INVALID},
+ {ERRHRD, 124, NT_STATUS_INVALID_LEVEL},
+ {ERRHRD, 126, NT_STATUS_DLL_NOT_FOUND},
+ {ERRHRD, 127, NT_STATUS_PROCEDURE_NOT_FOUND},
+ {ERRHRD, 145, NT_STATUS_DIRECTORY_NOT_EMPTY},
+ {ERRHRD, 154, NT_STATUS_INVALID_VOLUME_LABEL},
+ {ERRHRD, 156, NT_STATUS_SUSPEND_COUNT_EXCEEDED},
+ {ERRHRD, 158, NT_STATUS_NOT_LOCKED},
+ {ERRHRD, 161, NT_STATUS_OBJECT_PATH_INVALID},
+ {ERRHRD, 170, NT_STATUS(0x80000011)},
+ {ERRHRD, 182, NT_STATUS_ORDINAL_NOT_FOUND},
+ {ERRHRD, 183, NT_STATUS_OBJECT_NAME_COLLISION},
+ {ERRHRD, 193, NT_STATUS_BAD_INITIAL_PC},
+ {ERRHRD, 203, NT_STATUS(0xc0000100)},
+ {ERRHRD, 206, NT_STATUS_NAME_TOO_LONG},
+ {ERRHRD, 230, NT_STATUS_INVALID_INFO_CLASS},
+ {ERRHRD, 231, NT_STATUS_INSTANCE_NOT_AVAILABLE},
+ {ERRHRD, 232, NT_STATUS_PIPE_CLOSING},
+ {ERRHRD, 233, NT_STATUS_PIPE_DISCONNECTED},
+ {ERRHRD, 234, STATUS_MORE_ENTRIES},
+ {ERRHRD, 240, NT_STATUS_VIRTUAL_CIRCUIT_CLOSED},
+ {ERRHRD, 254, NT_STATUS(0x80000013)},
+ {ERRHRD, 255, NT_STATUS_EA_TOO_LARGE},
+ {ERRHRD, 259, NT_STATUS_GUIDS_EXHAUSTED},
+ {ERRHRD, 267, NT_STATUS_NOT_A_DIRECTORY},
+ {ERRHRD, 275, NT_STATUS_EA_TOO_LARGE},
+ {ERRHRD, 276, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRHRD, 277, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRHRD, 278, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRHRD, 282, NT_STATUS_EAS_NOT_SUPPORTED},
+ {ERRHRD, 288, NT_STATUS_MUTANT_NOT_OWNED},
+ {ERRHRD, 298, NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED},
+ {ERRHRD, 299, NT_STATUS(0x8000000d)},
+ {ERRHRD, 300, NT_STATUS_OPLOCK_NOT_GRANTED},
+ {ERRHRD, 301, NT_STATUS_INVALID_OPLOCK_PROTOCOL},
+ {ERRHRD, 487, NT_STATUS_CONFLICTING_ADDRESSES},
+ {ERRHRD, 534, NT_STATUS_INTEGER_OVERFLOW},
+ {ERRHRD, 535, NT_STATUS_PIPE_CONNECTED},
+ {ERRHRD, 536, NT_STATUS_PIPE_LISTENING},
+ {ERRHRD, 995, NT_STATUS_CANCELLED},
+ {ERRHRD, 997, NT_STATUS(0x00000103)},
+ {ERRHRD, 998, NT_STATUS_ACCESS_VIOLATION},
+ {ERRHRD, 999, NT_STATUS_IN_PAGE_ERROR},
+ {ERRHRD, 1001, NT_STATUS_BAD_INITIAL_STACK},
+ {ERRHRD, 1005, NT_STATUS_UNRECOGNIZED_VOLUME},
+ {ERRHRD, 1006, NT_STATUS_FILE_INVALID},
+ {ERRHRD, 1007, NT_STATUS_FULLSCREEN_MODE},
+ {ERRHRD, 1008, NT_STATUS_NO_TOKEN},
+ {ERRHRD, 1009, NT_STATUS_REGISTRY_CORRUPT},
+ {ERRHRD, 1016, NT_STATUS_REGISTRY_IO_FAILED},
+ {ERRHRD, 1017, NT_STATUS_NOT_REGISTRY_FILE},
+ {ERRHRD, 1018, NT_STATUS_KEY_DELETED},
+ {ERRHRD, 1019, NT_STATUS_NO_LOG_SPACE},
+ {ERRHRD, 1020, NT_STATUS_KEY_HAS_CHILDREN},
+ {ERRHRD, 1021, NT_STATUS_CHILD_MUST_BE_VOLATILE},
+ {ERRHRD, 1022, NT_STATUS(0x0000010c)},
+};
+
+/* 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}};
+
+
+/*****************************************************************************
+convert a dos eclas/ecode to a NT status32 code
+ *****************************************************************************/
+NTSTATUS dos_to_ntstatus(uint8 eclass, uint32 ecode)
+{
+ int i;
+ if (eclass == 0 && ecode == 0) return NT_STATUS_OK;
+ for (i=0; NT_STATUS_V(dos_to_ntstatus_map[i].ntstatus); i++) {
+ if (eclass == dos_to_ntstatus_map[i].dos_class &&
+ ecode == dos_to_ntstatus_map[i].dos_code) {
+ return dos_to_ntstatus_map[i].ntstatus;
+ }
+ }
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+
+/*****************************************************************************
+convert a NT status code to a dos class/code
+ *****************************************************************************/
+void ntstatus_to_dos(NTSTATUS ntstatus, uint8 *eclass, uint32 *ecode)
+{
+ int i;
+ if (NT_STATUS_IS_OK(ntstatus)) {
+ *eclass = 0;
+ *ecode = 0;
+ 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; 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);
+}
+
+/* Mapping between Unix, DOS and NT error numbers */
+
+const struct unix_error_map unix_dos_nt_errmap[] = {
+ { EPERM, ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED },
+ { EACCES, ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED },
+ { ENOENT, ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { ENOTDIR, ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND },
+ { EIO, ERRHRD, ERRgeneral, NT_STATUS_IO_DEVICE_ERROR },
+ { EBADF, ERRSRV, ERRsrverror, NT_STATUS_INVALID_HANDLE },
+ { EINVAL, ERRSRV, ERRsrverror, NT_STATUS_INVALID_HANDLE },
+ { EEXIST, ERRDOS, ERRfilexists, NT_STATUS_OBJECT_NAME_COLLISION},
+ { ENFILE, ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES },
+ { EMFILE, ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES },
+ { ENOSPC, ERRHRD, ERRdiskfull, NT_STATUS_DISK_FULL },
+ { EISDIR, ERRDOS, ERRbadpath, NT_STATUS_FILE_IS_A_DIRECTORY },
+#ifdef EDQUOT
+ { EDQUOT, ERRHRD, ERRdiskfull, NT_STATUS_DISK_FULL },
+#endif
+#ifdef ENOTEMPTY
+ { ENOTEMPTY, ERRDOS, ERRnoaccess, NT_STATUS_DIRECTORY_NOT_EMPTY },
+#endif
+#ifdef EXDEV
+ { EXDEV, ERRDOS, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE },
+#endif
+#ifdef EROFS
+ { EROFS, ERRHRD, ERRnowrite, NT_STATUS_ACCESS_DENIED },
+#endif
+#ifdef ENAMETOOLONG
+ { ENAMETOOLONG, ERRDOS, 206, NT_STATUS_OBJECT_NAME_INVALID },
+#endif
+#ifdef EFBIG
+ { EFBIG, ERRHRD, ERRdiskfull, NT_STATUS_DISK_FULL },
+#endif
+#ifdef EFBIG
+ { EBUSY, ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION },
+#endif
+ { 0, 0, 0, NT_STATUS_OK }
+};
+
+/*********************************************************************
+ Map an NT error code from a Unix error code.
+*********************************************************************/
+
+NTSTATUS map_nt_error_from_unix(int unix_error)
+{
+ int i = 0;
+
+ if (unix_error == 0)
+ return NT_STATUS_OK;
+
+ /* Look through list */
+ while(unix_dos_nt_errmap[i].unix_error != 0) {
+ if (unix_dos_nt_errmap[i].unix_error == unix_error)
+ return unix_dos_nt_errmap[i].nt_error;
+ i++;
+ }
+
+ /* Default return */
+ return NT_STATUS_ACCESS_DENIED;
+}
diff --git a/source4/libcli/util/nterr.c b/source4/libcli/util/nterr.c
new file mode 100644
index 0000000000..6c4b7c8417
--- /dev/null
+++ b/source4/libcli/util/nterr.c
@@ -0,0 +1,715 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ * Copyright (C) Luke Kenneth Casson Leighton 1997-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 2 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* NT error codes. please read nterr.h */
+
+#include "includes.h"
+
+typedef struct
+{
+ const char *nt_errstr;
+ NTSTATUS nt_errcode;
+} nt_err_code_struct;
+
+static const nt_err_code_struct nt_errs[] =
+{
+ { "NT_STATUS_OK", NT_STATUS_OK },
+ { "NT_STATUS_UNSUCCESSFUL", NT_STATUS_UNSUCCESSFUL },
+ { "NT_STATUS_NOT_IMPLEMENTED", NT_STATUS_NOT_IMPLEMENTED },
+ { "NT_STATUS_INVALID_INFO_CLASS", NT_STATUS_INVALID_INFO_CLASS },
+ { "NT_STATUS_INFO_LENGTH_MISMATCH", NT_STATUS_INFO_LENGTH_MISMATCH },
+ { "NT_STATUS_ACCESS_VIOLATION", NT_STATUS_ACCESS_VIOLATION },
+ { "STATUS_BUFFER_OVERFLOW", STATUS_BUFFER_OVERFLOW },
+ { "NT_STATUS_IN_PAGE_ERROR", NT_STATUS_IN_PAGE_ERROR },
+ { "NT_STATUS_PAGEFILE_QUOTA", NT_STATUS_PAGEFILE_QUOTA },
+ { "NT_STATUS_INVALID_HANDLE", NT_STATUS_INVALID_HANDLE },
+ { "NT_STATUS_BAD_INITIAL_STACK", NT_STATUS_BAD_INITIAL_STACK },
+ { "NT_STATUS_BAD_INITIAL_PC", NT_STATUS_BAD_INITIAL_PC },
+ { "NT_STATUS_INVALID_CID", NT_STATUS_INVALID_CID },
+ { "NT_STATUS_TIMER_NOT_CANCELED", NT_STATUS_TIMER_NOT_CANCELED },
+ { "NT_STATUS_INVALID_PARAMETER", NT_STATUS_INVALID_PARAMETER },
+ { "NT_STATUS_NO_SUCH_DEVICE", NT_STATUS_NO_SUCH_DEVICE },
+ { "NT_STATUS_NO_SUCH_FILE", NT_STATUS_NO_SUCH_FILE },
+ { "NT_STATUS_INVALID_DEVICE_REQUEST", NT_STATUS_INVALID_DEVICE_REQUEST },
+ { "NT_STATUS_END_OF_FILE", NT_STATUS_END_OF_FILE },
+ { "NT_STATUS_WRONG_VOLUME", NT_STATUS_WRONG_VOLUME },
+ { "NT_STATUS_NO_MEDIA_IN_DEVICE", NT_STATUS_NO_MEDIA_IN_DEVICE },
+ { "NT_STATUS_UNRECOGNIZED_MEDIA", NT_STATUS_UNRECOGNIZED_MEDIA },
+ { "NT_STATUS_NONEXISTENT_SECTOR", NT_STATUS_NONEXISTENT_SECTOR },
+ { "NT_STATUS_MORE_PROCESSING_REQUIRED", NT_STATUS_MORE_PROCESSING_REQUIRED },
+ { "NT_STATUS_NO_MEMORY", NT_STATUS_NO_MEMORY },
+ { "NT_STATUS_CONFLICTING_ADDRESSES", NT_STATUS_CONFLICTING_ADDRESSES },
+ { "NT_STATUS_NOT_MAPPED_VIEW", NT_STATUS_NOT_MAPPED_VIEW },
+ { "NT_STATUS_UNABLE_TO_FREE_VM", NT_STATUS_UNABLE_TO_FREE_VM },
+ { "NT_STATUS_UNABLE_TO_DELETE_SECTION", NT_STATUS_UNABLE_TO_DELETE_SECTION },
+ { "NT_STATUS_INVALID_SYSTEM_SERVICE", NT_STATUS_INVALID_SYSTEM_SERVICE },
+ { "NT_STATUS_ILLEGAL_INSTRUCTION", NT_STATUS_ILLEGAL_INSTRUCTION },
+ { "NT_STATUS_INVALID_LOCK_SEQUENCE", NT_STATUS_INVALID_LOCK_SEQUENCE },
+ { "NT_STATUS_INVALID_VIEW_SIZE", NT_STATUS_INVALID_VIEW_SIZE },
+ { "NT_STATUS_INVALID_FILE_FOR_SECTION", NT_STATUS_INVALID_FILE_FOR_SECTION },
+ { "NT_STATUS_ALREADY_COMMITTED", NT_STATUS_ALREADY_COMMITTED },
+ { "NT_STATUS_ACCESS_DENIED", NT_STATUS_ACCESS_DENIED },
+ { "NT_STATUS_BUFFER_TOO_SMALL", NT_STATUS_BUFFER_TOO_SMALL },
+ { "NT_STATUS_OBJECT_TYPE_MISMATCH", NT_STATUS_OBJECT_TYPE_MISMATCH },
+ { "NT_STATUS_NONCONTINUABLE_EXCEPTION", NT_STATUS_NONCONTINUABLE_EXCEPTION },
+ { "NT_STATUS_INVALID_DISPOSITION", NT_STATUS_INVALID_DISPOSITION },
+ { "NT_STATUS_UNWIND", NT_STATUS_UNWIND },
+ { "NT_STATUS_BAD_STACK", NT_STATUS_BAD_STACK },
+ { "NT_STATUS_INVALID_UNWIND_TARGET", NT_STATUS_INVALID_UNWIND_TARGET },
+ { "NT_STATUS_NOT_LOCKED", NT_STATUS_NOT_LOCKED },
+ { "NT_STATUS_PARITY_ERROR", NT_STATUS_PARITY_ERROR },
+ { "NT_STATUS_UNABLE_TO_DECOMMIT_VM", NT_STATUS_UNABLE_TO_DECOMMIT_VM },
+ { "NT_STATUS_NOT_COMMITTED", NT_STATUS_NOT_COMMITTED },
+ { "NT_STATUS_INVALID_PORT_ATTRIBUTES", NT_STATUS_INVALID_PORT_ATTRIBUTES },
+ { "NT_STATUS_PORT_MESSAGE_TOO_LONG", NT_STATUS_PORT_MESSAGE_TOO_LONG },
+ { "NT_STATUS_INVALID_PARAMETER_MIX", NT_STATUS_INVALID_PARAMETER_MIX },
+ { "NT_STATUS_INVALID_QUOTA_LOWER", NT_STATUS_INVALID_QUOTA_LOWER },
+ { "NT_STATUS_DISK_CORRUPT_ERROR", NT_STATUS_DISK_CORRUPT_ERROR },
+ { "NT_STATUS_OBJECT_NAME_INVALID", NT_STATUS_OBJECT_NAME_INVALID },
+ { "NT_STATUS_OBJECT_NAME_NOT_FOUND", NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { "NT_STATUS_OBJECT_NAME_COLLISION", NT_STATUS_OBJECT_NAME_COLLISION },
+ { "NT_STATUS_HANDLE_NOT_WAITABLE", NT_STATUS_HANDLE_NOT_WAITABLE },
+ { "NT_STATUS_PORT_DISCONNECTED", NT_STATUS_PORT_DISCONNECTED },
+ { "NT_STATUS_DEVICE_ALREADY_ATTACHED", NT_STATUS_DEVICE_ALREADY_ATTACHED },
+ { "NT_STATUS_OBJECT_PATH_INVALID", NT_STATUS_OBJECT_PATH_INVALID },
+ { "NT_STATUS_OBJECT_PATH_NOT_FOUND", NT_STATUS_OBJECT_PATH_NOT_FOUND },
+ { "NT_STATUS_OBJECT_PATH_SYNTAX_BAD", NT_STATUS_OBJECT_PATH_SYNTAX_BAD },
+ { "NT_STATUS_DATA_OVERRUN", NT_STATUS_DATA_OVERRUN },
+ { "NT_STATUS_DATA_LATE_ERROR", NT_STATUS_DATA_LATE_ERROR },
+ { "NT_STATUS_DATA_ERROR", NT_STATUS_DATA_ERROR },
+ { "NT_STATUS_CRC_ERROR", NT_STATUS_CRC_ERROR },
+ { "NT_STATUS_SECTION_TOO_BIG", NT_STATUS_SECTION_TOO_BIG },
+ { "NT_STATUS_PORT_CONNECTION_REFUSED", NT_STATUS_PORT_CONNECTION_REFUSED },
+ { "NT_STATUS_INVALID_PORT_HANDLE", NT_STATUS_INVALID_PORT_HANDLE },
+ { "NT_STATUS_SHARING_VIOLATION", NT_STATUS_SHARING_VIOLATION },
+ { "NT_STATUS_QUOTA_EXCEEDED", NT_STATUS_QUOTA_EXCEEDED },
+ { "NT_STATUS_INVALID_PAGE_PROTECTION", NT_STATUS_INVALID_PAGE_PROTECTION },
+ { "NT_STATUS_MUTANT_NOT_OWNED", NT_STATUS_MUTANT_NOT_OWNED },
+ { "NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED", NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED },
+ { "NT_STATUS_PORT_ALREADY_SET", NT_STATUS_PORT_ALREADY_SET },
+ { "NT_STATUS_SECTION_NOT_IMAGE", NT_STATUS_SECTION_NOT_IMAGE },
+ { "NT_STATUS_SUSPEND_COUNT_EXCEEDED", NT_STATUS_SUSPEND_COUNT_EXCEEDED },
+ { "NT_STATUS_THREAD_IS_TERMINATING", NT_STATUS_THREAD_IS_TERMINATING },
+ { "NT_STATUS_BAD_WORKING_SET_LIMIT", NT_STATUS_BAD_WORKING_SET_LIMIT },
+ { "NT_STATUS_INCOMPATIBLE_FILE_MAP", NT_STATUS_INCOMPATIBLE_FILE_MAP },
+ { "NT_STATUS_SECTION_PROTECTION", NT_STATUS_SECTION_PROTECTION },
+ { "NT_STATUS_EAS_NOT_SUPPORTED", NT_STATUS_EAS_NOT_SUPPORTED },
+ { "NT_STATUS_EA_TOO_LARGE", NT_STATUS_EA_TOO_LARGE },
+ { "NT_STATUS_NONEXISTENT_EA_ENTRY", NT_STATUS_NONEXISTENT_EA_ENTRY },
+ { "NT_STATUS_NO_EAS_ON_FILE", NT_STATUS_NO_EAS_ON_FILE },
+ { "NT_STATUS_EA_CORRUPT_ERROR", NT_STATUS_EA_CORRUPT_ERROR },
+ { "NT_STATUS_FILE_LOCK_CONFLICT", NT_STATUS_FILE_LOCK_CONFLICT },
+ { "NT_STATUS_LOCK_NOT_GRANTED", NT_STATUS_LOCK_NOT_GRANTED },
+ { "NT_STATUS_DELETE_PENDING", NT_STATUS_DELETE_PENDING },
+ { "NT_STATUS_CTL_FILE_NOT_SUPPORTED", NT_STATUS_CTL_FILE_NOT_SUPPORTED },
+ { "NT_STATUS_UNKNOWN_REVISION", NT_STATUS_UNKNOWN_REVISION },
+ { "NT_STATUS_REVISION_MISMATCH", NT_STATUS_REVISION_MISMATCH },
+ { "NT_STATUS_INVALID_OWNER", NT_STATUS_INVALID_OWNER },
+ { "NT_STATUS_INVALID_PRIMARY_GROUP", NT_STATUS_INVALID_PRIMARY_GROUP },
+ { "NT_STATUS_NO_IMPERSONATION_TOKEN", NT_STATUS_NO_IMPERSONATION_TOKEN },
+ { "NT_STATUS_CANT_DISABLE_MANDATORY", NT_STATUS_CANT_DISABLE_MANDATORY },
+ { "NT_STATUS_NO_LOGON_SERVERS", NT_STATUS_NO_LOGON_SERVERS },
+ { "NT_STATUS_NO_SUCH_LOGON_SESSION", NT_STATUS_NO_SUCH_LOGON_SESSION },
+ { "NT_STATUS_NO_SUCH_PRIVILEGE", NT_STATUS_NO_SUCH_PRIVILEGE },
+ { "NT_STATUS_PRIVILEGE_NOT_HELD", NT_STATUS_PRIVILEGE_NOT_HELD },
+ { "NT_STATUS_INVALID_ACCOUNT_NAME", NT_STATUS_INVALID_ACCOUNT_NAME },
+ { "NT_STATUS_USER_EXISTS", NT_STATUS_USER_EXISTS },
+ { "NT_STATUS_NO_SUCH_USER", NT_STATUS_NO_SUCH_USER },
+ { "NT_STATUS_GROUP_EXISTS", NT_STATUS_GROUP_EXISTS },
+ { "NT_STATUS_NO_SUCH_GROUP", NT_STATUS_NO_SUCH_GROUP },
+ { "NT_STATUS_MEMBER_IN_GROUP", NT_STATUS_MEMBER_IN_GROUP },
+ { "NT_STATUS_MEMBER_NOT_IN_GROUP", NT_STATUS_MEMBER_NOT_IN_GROUP },
+ { "NT_STATUS_LAST_ADMIN", NT_STATUS_LAST_ADMIN },
+ { "NT_STATUS_WRONG_PASSWORD", NT_STATUS_WRONG_PASSWORD },
+ { "NT_STATUS_ILL_FORMED_PASSWORD", NT_STATUS_ILL_FORMED_PASSWORD },
+ { "NT_STATUS_PASSWORD_RESTRICTION", NT_STATUS_PASSWORD_RESTRICTION },
+ { "NT_STATUS_LOGON_FAILURE", NT_STATUS_LOGON_FAILURE },
+ { "NT_STATUS_ACCOUNT_RESTRICTION", NT_STATUS_ACCOUNT_RESTRICTION },
+ { "NT_STATUS_INVALID_LOGON_HOURS", NT_STATUS_INVALID_LOGON_HOURS },
+ { "NT_STATUS_INVALID_WORKSTATION", NT_STATUS_INVALID_WORKSTATION },
+ { "NT_STATUS_PASSWORD_EXPIRED", NT_STATUS_PASSWORD_EXPIRED },
+ { "NT_STATUS_ACCOUNT_DISABLED", NT_STATUS_ACCOUNT_DISABLED },
+ { "NT_STATUS_NONE_MAPPED", NT_STATUS_NONE_MAPPED },
+ { "NT_STATUS_TOO_MANY_LUIDS_REQUESTED", NT_STATUS_TOO_MANY_LUIDS_REQUESTED },
+ { "NT_STATUS_LUIDS_EXHAUSTED", NT_STATUS_LUIDS_EXHAUSTED },
+ { "NT_STATUS_INVALID_SUB_AUTHORITY", NT_STATUS_INVALID_SUB_AUTHORITY },
+ { "NT_STATUS_INVALID_ACL", NT_STATUS_INVALID_ACL },
+ { "NT_STATUS_INVALID_SID", NT_STATUS_INVALID_SID },
+ { "NT_STATUS_INVALID_SECURITY_DESCR", NT_STATUS_INVALID_SECURITY_DESCR },
+ { "NT_STATUS_PROCEDURE_NOT_FOUND", NT_STATUS_PROCEDURE_NOT_FOUND },
+ { "NT_STATUS_INVALID_IMAGE_FORMAT", NT_STATUS_INVALID_IMAGE_FORMAT },
+ { "NT_STATUS_NO_TOKEN", NT_STATUS_NO_TOKEN },
+ { "NT_STATUS_BAD_INHERITANCE_ACL", NT_STATUS_BAD_INHERITANCE_ACL },
+ { "NT_STATUS_RANGE_NOT_LOCKED", NT_STATUS_RANGE_NOT_LOCKED },
+ { "NT_STATUS_DISK_FULL", NT_STATUS_DISK_FULL },
+ { "NT_STATUS_SERVER_DISABLED", NT_STATUS_SERVER_DISABLED },
+ { "NT_STATUS_SERVER_NOT_DISABLED", NT_STATUS_SERVER_NOT_DISABLED },
+ { "NT_STATUS_TOO_MANY_GUIDS_REQUESTED", NT_STATUS_TOO_MANY_GUIDS_REQUESTED },
+ { "NT_STATUS_GUIDS_EXHAUSTED", NT_STATUS_GUIDS_EXHAUSTED },
+ { "NT_STATUS_INVALID_ID_AUTHORITY", NT_STATUS_INVALID_ID_AUTHORITY },
+ { "NT_STATUS_AGENTS_EXHAUSTED", NT_STATUS_AGENTS_EXHAUSTED },
+ { "NT_STATUS_INVALID_VOLUME_LABEL", NT_STATUS_INVALID_VOLUME_LABEL },
+ { "NT_STATUS_SECTION_NOT_EXTENDED", NT_STATUS_SECTION_NOT_EXTENDED },
+ { "NT_STATUS_NOT_MAPPED_DATA", NT_STATUS_NOT_MAPPED_DATA },
+ { "NT_STATUS_RESOURCE_DATA_NOT_FOUND", NT_STATUS_RESOURCE_DATA_NOT_FOUND },
+ { "NT_STATUS_RESOURCE_TYPE_NOT_FOUND", NT_STATUS_RESOURCE_TYPE_NOT_FOUND },
+ { "NT_STATUS_RESOURCE_NAME_NOT_FOUND", NT_STATUS_RESOURCE_NAME_NOT_FOUND },
+ { "NT_STATUS_ARRAY_BOUNDS_EXCEEDED", NT_STATUS_ARRAY_BOUNDS_EXCEEDED },
+ { "NT_STATUS_FLOAT_DENORMAL_OPERAND", NT_STATUS_FLOAT_DENORMAL_OPERAND },
+ { "NT_STATUS_FLOAT_DIVIDE_BY_ZERO", NT_STATUS_FLOAT_DIVIDE_BY_ZERO },
+ { "NT_STATUS_FLOAT_INEXACT_RESULT", NT_STATUS_FLOAT_INEXACT_RESULT },
+ { "NT_STATUS_FLOAT_INVALID_OPERATION", NT_STATUS_FLOAT_INVALID_OPERATION },
+ { "NT_STATUS_FLOAT_OVERFLOW", NT_STATUS_FLOAT_OVERFLOW },
+ { "NT_STATUS_FLOAT_STACK_CHECK", NT_STATUS_FLOAT_STACK_CHECK },
+ { "NT_STATUS_FLOAT_UNDERFLOW", NT_STATUS_FLOAT_UNDERFLOW },
+ { "NT_STATUS_INTEGER_DIVIDE_BY_ZERO", NT_STATUS_INTEGER_DIVIDE_BY_ZERO },
+ { "NT_STATUS_INTEGER_OVERFLOW", NT_STATUS_INTEGER_OVERFLOW },
+ { "NT_STATUS_PRIVILEGED_INSTRUCTION", NT_STATUS_PRIVILEGED_INSTRUCTION },
+ { "NT_STATUS_TOO_MANY_PAGING_FILES", NT_STATUS_TOO_MANY_PAGING_FILES },
+ { "NT_STATUS_FILE_INVALID", NT_STATUS_FILE_INVALID },
+ { "NT_STATUS_ALLOTTED_SPACE_EXCEEDED", NT_STATUS_ALLOTTED_SPACE_EXCEEDED },
+ { "NT_STATUS_INSUFFICIENT_RESOURCES", NT_STATUS_INSUFFICIENT_RESOURCES },
+ { "NT_STATUS_DFS_EXIT_PATH_FOUND", NT_STATUS_DFS_EXIT_PATH_FOUND },
+ { "NT_STATUS_DEVICE_DATA_ERROR", NT_STATUS_DEVICE_DATA_ERROR },
+ { "NT_STATUS_DEVICE_NOT_CONNECTED", NT_STATUS_DEVICE_NOT_CONNECTED },
+ { "NT_STATUS_DEVICE_POWER_FAILURE", NT_STATUS_DEVICE_POWER_FAILURE },
+ { "NT_STATUS_FREE_VM_NOT_AT_BASE", NT_STATUS_FREE_VM_NOT_AT_BASE },
+ { "NT_STATUS_MEMORY_NOT_ALLOCATED", NT_STATUS_MEMORY_NOT_ALLOCATED },
+ { "NT_STATUS_WORKING_SET_QUOTA", NT_STATUS_WORKING_SET_QUOTA },
+ { "NT_STATUS_MEDIA_WRITE_PROTECTED", NT_STATUS_MEDIA_WRITE_PROTECTED },
+ { "NT_STATUS_DEVICE_NOT_READY", NT_STATUS_DEVICE_NOT_READY },
+ { "NT_STATUS_INVALID_GROUP_ATTRIBUTES", NT_STATUS_INVALID_GROUP_ATTRIBUTES },
+ { "NT_STATUS_BAD_IMPERSONATION_LEVEL", NT_STATUS_BAD_IMPERSONATION_LEVEL },
+ { "NT_STATUS_CANT_OPEN_ANONYMOUS", NT_STATUS_CANT_OPEN_ANONYMOUS },
+ { "NT_STATUS_BAD_VALIDATION_CLASS", NT_STATUS_BAD_VALIDATION_CLASS },
+ { "NT_STATUS_BAD_TOKEN_TYPE", NT_STATUS_BAD_TOKEN_TYPE },
+ { "NT_STATUS_BAD_MASTER_BOOT_RECORD", NT_STATUS_BAD_MASTER_BOOT_RECORD },
+ { "NT_STATUS_INSTRUCTION_MISALIGNMENT", NT_STATUS_INSTRUCTION_MISALIGNMENT },
+ { "NT_STATUS_INSTANCE_NOT_AVAILABLE", NT_STATUS_INSTANCE_NOT_AVAILABLE },
+ { "NT_STATUS_PIPE_NOT_AVAILABLE", NT_STATUS_PIPE_NOT_AVAILABLE },
+ { "NT_STATUS_INVALID_PIPE_STATE", NT_STATUS_INVALID_PIPE_STATE },
+ { "NT_STATUS_PIPE_BUSY", NT_STATUS_PIPE_BUSY },
+ { "NT_STATUS_ILLEGAL_FUNCTION", NT_STATUS_ILLEGAL_FUNCTION },
+ { "NT_STATUS_PIPE_DISCONNECTED", NT_STATUS_PIPE_DISCONNECTED },
+ { "NT_STATUS_PIPE_CLOSING", NT_STATUS_PIPE_CLOSING },
+ { "NT_STATUS_PIPE_CONNECTED", NT_STATUS_PIPE_CONNECTED },
+ { "NT_STATUS_PIPE_LISTENING", NT_STATUS_PIPE_LISTENING },
+ { "NT_STATUS_INVALID_READ_MODE", NT_STATUS_INVALID_READ_MODE },
+ { "NT_STATUS_IO_TIMEOUT", NT_STATUS_IO_TIMEOUT },
+ { "NT_STATUS_FILE_FORCED_CLOSED", NT_STATUS_FILE_FORCED_CLOSED },
+ { "NT_STATUS_PROFILING_NOT_STARTED", NT_STATUS_PROFILING_NOT_STARTED },
+ { "NT_STATUS_PROFILING_NOT_STOPPED", NT_STATUS_PROFILING_NOT_STOPPED },
+ { "NT_STATUS_COULD_NOT_INTERPRET", NT_STATUS_COULD_NOT_INTERPRET },
+ { "NT_STATUS_FILE_IS_A_DIRECTORY", NT_STATUS_FILE_IS_A_DIRECTORY },
+ { "NT_STATUS_NOT_SUPPORTED", NT_STATUS_NOT_SUPPORTED },
+ { "NT_STATUS_REMOTE_NOT_LISTENING", NT_STATUS_REMOTE_NOT_LISTENING },
+ { "NT_STATUS_DUPLICATE_NAME", NT_STATUS_DUPLICATE_NAME },
+ { "NT_STATUS_BAD_NETWORK_PATH", NT_STATUS_BAD_NETWORK_PATH },
+ { "NT_STATUS_NETWORK_BUSY", NT_STATUS_NETWORK_BUSY },
+ { "NT_STATUS_DEVICE_DOES_NOT_EXIST", NT_STATUS_DEVICE_DOES_NOT_EXIST },
+ { "NT_STATUS_TOO_MANY_COMMANDS", NT_STATUS_TOO_MANY_COMMANDS },
+ { "NT_STATUS_ADAPTER_HARDWARE_ERROR", NT_STATUS_ADAPTER_HARDWARE_ERROR },
+ { "NT_STATUS_INVALID_NETWORK_RESPONSE", NT_STATUS_INVALID_NETWORK_RESPONSE },
+ { "NT_STATUS_UNEXPECTED_NETWORK_ERROR", NT_STATUS_UNEXPECTED_NETWORK_ERROR },
+ { "NT_STATUS_BAD_REMOTE_ADAPTER", NT_STATUS_BAD_REMOTE_ADAPTER },
+ { "NT_STATUS_PRINT_QUEUE_FULL", NT_STATUS_PRINT_QUEUE_FULL },
+ { "NT_STATUS_NO_SPOOL_SPACE", NT_STATUS_NO_SPOOL_SPACE },
+ { "NT_STATUS_PRINT_CANCELLED", NT_STATUS_PRINT_CANCELLED },
+ { "NT_STATUS_NETWORK_NAME_DELETED", NT_STATUS_NETWORK_NAME_DELETED },
+ { "NT_STATUS_NETWORK_ACCESS_DENIED", NT_STATUS_NETWORK_ACCESS_DENIED },
+ { "NT_STATUS_BAD_DEVICE_TYPE", NT_STATUS_BAD_DEVICE_TYPE },
+ { "NT_STATUS_BAD_NETWORK_NAME", NT_STATUS_BAD_NETWORK_NAME },
+ { "NT_STATUS_TOO_MANY_NAMES", NT_STATUS_TOO_MANY_NAMES },
+ { "NT_STATUS_TOO_MANY_SESSIONS", NT_STATUS_TOO_MANY_SESSIONS },
+ { "NT_STATUS_SHARING_PAUSED", NT_STATUS_SHARING_PAUSED },
+ { "NT_STATUS_REQUEST_NOT_ACCEPTED", NT_STATUS_REQUEST_NOT_ACCEPTED },
+ { "NT_STATUS_REDIRECTOR_PAUSED", NT_STATUS_REDIRECTOR_PAUSED },
+ { "NT_STATUS_NET_WRITE_FAULT", NT_STATUS_NET_WRITE_FAULT },
+ { "NT_STATUS_PROFILING_AT_LIMIT", NT_STATUS_PROFILING_AT_LIMIT },
+ { "NT_STATUS_NOT_SAME_DEVICE", NT_STATUS_NOT_SAME_DEVICE },
+ { "NT_STATUS_FILE_RENAMED", NT_STATUS_FILE_RENAMED },
+ { "NT_STATUS_VIRTUAL_CIRCUIT_CLOSED", NT_STATUS_VIRTUAL_CIRCUIT_CLOSED },
+ { "NT_STATUS_NO_SECURITY_ON_OBJECT", NT_STATUS_NO_SECURITY_ON_OBJECT },
+ { "NT_STATUS_CANT_WAIT", NT_STATUS_CANT_WAIT },
+ { "NT_STATUS_PIPE_EMPTY", NT_STATUS_PIPE_EMPTY },
+ { "NT_STATUS_CANT_ACCESS_DOMAIN_INFO", NT_STATUS_CANT_ACCESS_DOMAIN_INFO },
+ { "NT_STATUS_CANT_TERMINATE_SELF", NT_STATUS_CANT_TERMINATE_SELF },
+ { "NT_STATUS_INVALID_SERVER_STATE", NT_STATUS_INVALID_SERVER_STATE },
+ { "NT_STATUS_INVALID_DOMAIN_STATE", NT_STATUS_INVALID_DOMAIN_STATE },
+ { "NT_STATUS_INVALID_DOMAIN_ROLE", NT_STATUS_INVALID_DOMAIN_ROLE },
+ { "NT_STATUS_NO_SUCH_DOMAIN", NT_STATUS_NO_SUCH_DOMAIN },
+ { "NT_STATUS_DOMAIN_EXISTS", NT_STATUS_DOMAIN_EXISTS },
+ { "NT_STATUS_DOMAIN_LIMIT_EXCEEDED", NT_STATUS_DOMAIN_LIMIT_EXCEEDED },
+ { "NT_STATUS_OPLOCK_NOT_GRANTED", NT_STATUS_OPLOCK_NOT_GRANTED },
+ { "NT_STATUS_INVALID_OPLOCK_PROTOCOL", NT_STATUS_INVALID_OPLOCK_PROTOCOL },
+ { "NT_STATUS_INTERNAL_DB_CORRUPTION", NT_STATUS_INTERNAL_DB_CORRUPTION },
+ { "NT_STATUS_INTERNAL_ERROR", NT_STATUS_INTERNAL_ERROR },
+ { "NT_STATUS_GENERIC_NOT_MAPPED", NT_STATUS_GENERIC_NOT_MAPPED },
+ { "NT_STATUS_BAD_DESCRIPTOR_FORMAT", NT_STATUS_BAD_DESCRIPTOR_FORMAT },
+ { "NT_STATUS_INVALID_USER_BUFFER", NT_STATUS_INVALID_USER_BUFFER },
+ { "NT_STATUS_UNEXPECTED_IO_ERROR", NT_STATUS_UNEXPECTED_IO_ERROR },
+ { "NT_STATUS_UNEXPECTED_MM_CREATE_ERR", NT_STATUS_UNEXPECTED_MM_CREATE_ERR },
+ { "NT_STATUS_UNEXPECTED_MM_MAP_ERROR", NT_STATUS_UNEXPECTED_MM_MAP_ERROR },
+ { "NT_STATUS_UNEXPECTED_MM_EXTEND_ERR", NT_STATUS_UNEXPECTED_MM_EXTEND_ERR },
+ { "NT_STATUS_NOT_LOGON_PROCESS", NT_STATUS_NOT_LOGON_PROCESS },
+ { "NT_STATUS_LOGON_SESSION_EXISTS", NT_STATUS_LOGON_SESSION_EXISTS },
+ { "NT_STATUS_INVALID_PARAMETER_1", NT_STATUS_INVALID_PARAMETER_1 },
+ { "NT_STATUS_INVALID_PARAMETER_2", NT_STATUS_INVALID_PARAMETER_2 },
+ { "NT_STATUS_INVALID_PARAMETER_3", NT_STATUS_INVALID_PARAMETER_3 },
+ { "NT_STATUS_INVALID_PARAMETER_4", NT_STATUS_INVALID_PARAMETER_4 },
+ { "NT_STATUS_INVALID_PARAMETER_5", NT_STATUS_INVALID_PARAMETER_5 },
+ { "NT_STATUS_INVALID_PARAMETER_6", NT_STATUS_INVALID_PARAMETER_6 },
+ { "NT_STATUS_INVALID_PARAMETER_7", NT_STATUS_INVALID_PARAMETER_7 },
+ { "NT_STATUS_INVALID_PARAMETER_8", NT_STATUS_INVALID_PARAMETER_8 },
+ { "NT_STATUS_INVALID_PARAMETER_9", NT_STATUS_INVALID_PARAMETER_9 },
+ { "NT_STATUS_INVALID_PARAMETER_10", NT_STATUS_INVALID_PARAMETER_10 },
+ { "NT_STATUS_INVALID_PARAMETER_11", NT_STATUS_INVALID_PARAMETER_11 },
+ { "NT_STATUS_INVALID_PARAMETER_12", NT_STATUS_INVALID_PARAMETER_12 },
+ { "NT_STATUS_REDIRECTOR_NOT_STARTED", NT_STATUS_REDIRECTOR_NOT_STARTED },
+ { "NT_STATUS_REDIRECTOR_STARTED", NT_STATUS_REDIRECTOR_STARTED },
+ { "NT_STATUS_STACK_OVERFLOW", NT_STATUS_STACK_OVERFLOW },
+ { "NT_STATUS_NO_SUCH_PACKAGE", NT_STATUS_NO_SUCH_PACKAGE },
+ { "NT_STATUS_BAD_FUNCTION_TABLE", NT_STATUS_BAD_FUNCTION_TABLE },
+ { "NT_STATUS_DIRECTORY_NOT_EMPTY", NT_STATUS_DIRECTORY_NOT_EMPTY },
+ { "NT_STATUS_FILE_CORRUPT_ERROR", NT_STATUS_FILE_CORRUPT_ERROR },
+ { "NT_STATUS_NOT_A_DIRECTORY", NT_STATUS_NOT_A_DIRECTORY },
+ { "NT_STATUS_BAD_LOGON_SESSION_STATE", NT_STATUS_BAD_LOGON_SESSION_STATE },
+ { "NT_STATUS_LOGON_SESSION_COLLISION", NT_STATUS_LOGON_SESSION_COLLISION },
+ { "NT_STATUS_NAME_TOO_LONG", NT_STATUS_NAME_TOO_LONG },
+ { "NT_STATUS_FILES_OPEN", NT_STATUS_FILES_OPEN },
+ { "NT_STATUS_CONNECTION_IN_USE", NT_STATUS_CONNECTION_IN_USE },
+ { "NT_STATUS_MESSAGE_NOT_FOUND", NT_STATUS_MESSAGE_NOT_FOUND },
+ { "NT_STATUS_PROCESS_IS_TERMINATING", NT_STATUS_PROCESS_IS_TERMINATING },
+ { "NT_STATUS_INVALID_LOGON_TYPE", NT_STATUS_INVALID_LOGON_TYPE },
+ { "NT_STATUS_NO_GUID_TRANSLATION", NT_STATUS_NO_GUID_TRANSLATION },
+ { "NT_STATUS_CANNOT_IMPERSONATE", NT_STATUS_CANNOT_IMPERSONATE },
+ { "NT_STATUS_IMAGE_ALREADY_LOADED", NT_STATUS_IMAGE_ALREADY_LOADED },
+ { "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_NO_LDT", NT_STATUS_NO_LDT },
+ { "NT_STATUS_INVALID_LDT_SIZE", NT_STATUS_INVALID_LDT_SIZE },
+ { "NT_STATUS_INVALID_LDT_OFFSET", NT_STATUS_INVALID_LDT_OFFSET },
+ { "NT_STATUS_INVALID_LDT_DESCRIPTOR", NT_STATUS_INVALID_LDT_DESCRIPTOR },
+ { "NT_STATUS_INVALID_IMAGE_NE_FORMAT", NT_STATUS_INVALID_IMAGE_NE_FORMAT },
+ { "NT_STATUS_RXACT_INVALID_STATE", NT_STATUS_RXACT_INVALID_STATE },
+ { "NT_STATUS_RXACT_COMMIT_FAILURE", NT_STATUS_RXACT_COMMIT_FAILURE },
+ { "NT_STATUS_MAPPED_FILE_SIZE_ZERO", NT_STATUS_MAPPED_FILE_SIZE_ZERO },
+ { "NT_STATUS_TOO_MANY_OPENED_FILES", NT_STATUS_TOO_MANY_OPENED_FILES },
+ { "NT_STATUS_CANCELLED", NT_STATUS_CANCELLED },
+ { "NT_STATUS_CANNOT_DELETE", NT_STATUS_CANNOT_DELETE },
+ { "NT_STATUS_INVALID_COMPUTER_NAME", NT_STATUS_INVALID_COMPUTER_NAME },
+ { "NT_STATUS_FILE_DELETED", NT_STATUS_FILE_DELETED },
+ { "NT_STATUS_SPECIAL_ACCOUNT", NT_STATUS_SPECIAL_ACCOUNT },
+ { "NT_STATUS_SPECIAL_GROUP", NT_STATUS_SPECIAL_GROUP },
+ { "NT_STATUS_SPECIAL_USER", NT_STATUS_SPECIAL_USER },
+ { "NT_STATUS_MEMBERS_PRIMARY_GROUP", NT_STATUS_MEMBERS_PRIMARY_GROUP },
+ { "NT_STATUS_FILE_CLOSED", NT_STATUS_FILE_CLOSED },
+ { "NT_STATUS_TOO_MANY_THREADS", NT_STATUS_TOO_MANY_THREADS },
+ { "NT_STATUS_THREAD_NOT_IN_PROCESS", NT_STATUS_THREAD_NOT_IN_PROCESS },
+ { "NT_STATUS_TOKEN_ALREADY_IN_USE", NT_STATUS_TOKEN_ALREADY_IN_USE },
+ { "NT_STATUS_PAGEFILE_QUOTA_EXCEEDED", NT_STATUS_PAGEFILE_QUOTA_EXCEEDED },
+ { "NT_STATUS_COMMITMENT_LIMIT", NT_STATUS_COMMITMENT_LIMIT },
+ { "NT_STATUS_INVALID_IMAGE_LE_FORMAT", NT_STATUS_INVALID_IMAGE_LE_FORMAT },
+ { "NT_STATUS_INVALID_IMAGE_NOT_MZ", NT_STATUS_INVALID_IMAGE_NOT_MZ },
+ { "NT_STATUS_INVALID_IMAGE_PROTECT", NT_STATUS_INVALID_IMAGE_PROTECT },
+ { "NT_STATUS_INVALID_IMAGE_WIN_16", NT_STATUS_INVALID_IMAGE_WIN_16 },
+ { "NT_STATUS_LOGON_SERVER_CONFLICT", NT_STATUS_LOGON_SERVER_CONFLICT },
+ { "NT_STATUS_TIME_DIFFERENCE_AT_DC", NT_STATUS_TIME_DIFFERENCE_AT_DC },
+ { "NT_STATUS_SYNCHRONIZATION_REQUIRED", NT_STATUS_SYNCHRONIZATION_REQUIRED },
+ { "NT_STATUS_DLL_NOT_FOUND", NT_STATUS_DLL_NOT_FOUND },
+ { "NT_STATUS_OPEN_FAILED", NT_STATUS_OPEN_FAILED },
+ { "NT_STATUS_IO_PRIVILEGE_FAILED", NT_STATUS_IO_PRIVILEGE_FAILED },
+ { "NT_STATUS_ORDINAL_NOT_FOUND", NT_STATUS_ORDINAL_NOT_FOUND },
+ { "NT_STATUS_ENTRYPOINT_NOT_FOUND", NT_STATUS_ENTRYPOINT_NOT_FOUND },
+ { "NT_STATUS_CONTROL_C_EXIT", NT_STATUS_CONTROL_C_EXIT },
+ { "NT_STATUS_LOCAL_DISCONNECT", NT_STATUS_LOCAL_DISCONNECT },
+ { "NT_STATUS_REMOTE_DISCONNECT", NT_STATUS_REMOTE_DISCONNECT },
+ { "NT_STATUS_REMOTE_RESOURCES", NT_STATUS_REMOTE_RESOURCES },
+ { "NT_STATUS_LINK_FAILED", NT_STATUS_LINK_FAILED },
+ { "NT_STATUS_LINK_TIMEOUT", NT_STATUS_LINK_TIMEOUT },
+ { "NT_STATUS_INVALID_CONNECTION", NT_STATUS_INVALID_CONNECTION },
+ { "NT_STATUS_INVALID_ADDRESS", NT_STATUS_INVALID_ADDRESS },
+ { "NT_STATUS_DLL_INIT_FAILED", NT_STATUS_DLL_INIT_FAILED },
+ { "NT_STATUS_MISSING_SYSTEMFILE", NT_STATUS_MISSING_SYSTEMFILE },
+ { "NT_STATUS_UNHANDLED_EXCEPTION", NT_STATUS_UNHANDLED_EXCEPTION },
+ { "NT_STATUS_APP_INIT_FAILURE", NT_STATUS_APP_INIT_FAILURE },
+ { "NT_STATUS_PAGEFILE_CREATE_FAILED", NT_STATUS_PAGEFILE_CREATE_FAILED },
+ { "NT_STATUS_NO_PAGEFILE", NT_STATUS_NO_PAGEFILE },
+ { "NT_STATUS_INVALID_LEVEL", NT_STATUS_INVALID_LEVEL },
+ { "NT_STATUS_WRONG_PASSWORD_CORE", NT_STATUS_WRONG_PASSWORD_CORE },
+ { "NT_STATUS_ILLEGAL_FLOAT_CONTEXT", NT_STATUS_ILLEGAL_FLOAT_CONTEXT },
+ { "NT_STATUS_PIPE_BROKEN", NT_STATUS_PIPE_BROKEN },
+ { "NT_STATUS_REGISTRY_CORRUPT", NT_STATUS_REGISTRY_CORRUPT },
+ { "NT_STATUS_REGISTRY_IO_FAILED", NT_STATUS_REGISTRY_IO_FAILED },
+ { "NT_STATUS_NO_EVENT_PAIR", NT_STATUS_NO_EVENT_PAIR },
+ { "NT_STATUS_UNRECOGNIZED_VOLUME", NT_STATUS_UNRECOGNIZED_VOLUME },
+ { "NT_STATUS_SERIAL_NO_DEVICE_INITED", NT_STATUS_SERIAL_NO_DEVICE_INITED },
+ { "NT_STATUS_NO_SUCH_ALIAS", NT_STATUS_NO_SUCH_ALIAS },
+ { "NT_STATUS_MEMBER_NOT_IN_ALIAS", NT_STATUS_MEMBER_NOT_IN_ALIAS },
+ { "NT_STATUS_MEMBER_IN_ALIAS", NT_STATUS_MEMBER_IN_ALIAS },
+ { "NT_STATUS_ALIAS_EXISTS", NT_STATUS_ALIAS_EXISTS },
+ { "NT_STATUS_LOGON_NOT_GRANTED", NT_STATUS_LOGON_NOT_GRANTED },
+ { "NT_STATUS_TOO_MANY_SECRETS", NT_STATUS_TOO_MANY_SECRETS },
+ { "NT_STATUS_SECRET_TOO_LONG", NT_STATUS_SECRET_TOO_LONG },
+ { "NT_STATUS_INTERNAL_DB_ERROR", NT_STATUS_INTERNAL_DB_ERROR },
+ { "NT_STATUS_FULLSCREEN_MODE", NT_STATUS_FULLSCREEN_MODE },
+ { "NT_STATUS_TOO_MANY_CONTEXT_IDS", NT_STATUS_TOO_MANY_CONTEXT_IDS },
+ { "NT_STATUS_LOGON_TYPE_NOT_GRANTED", NT_STATUS_LOGON_TYPE_NOT_GRANTED },
+ { "NT_STATUS_NOT_REGISTRY_FILE", NT_STATUS_NOT_REGISTRY_FILE },
+ { "NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED", NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED },
+ { "NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR", NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR },
+ { "NT_STATUS_FT_MISSING_MEMBER", NT_STATUS_FT_MISSING_MEMBER },
+ { "NT_STATUS_ILL_FORMED_SERVICE_ENTRY", NT_STATUS_ILL_FORMED_SERVICE_ENTRY },
+ { "NT_STATUS_ILLEGAL_CHARACTER", NT_STATUS_ILLEGAL_CHARACTER },
+ { "NT_STATUS_UNMAPPABLE_CHARACTER", NT_STATUS_UNMAPPABLE_CHARACTER },
+ { "NT_STATUS_UNDEFINED_CHARACTER", NT_STATUS_UNDEFINED_CHARACTER },
+ { "NT_STATUS_FLOPPY_VOLUME", NT_STATUS_FLOPPY_VOLUME },
+ { "NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND", NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND },
+ { "NT_STATUS_FLOPPY_WRONG_CYLINDER", NT_STATUS_FLOPPY_WRONG_CYLINDER },
+ { "NT_STATUS_FLOPPY_UNKNOWN_ERROR", NT_STATUS_FLOPPY_UNKNOWN_ERROR },
+ { "NT_STATUS_FLOPPY_BAD_REGISTERS", NT_STATUS_FLOPPY_BAD_REGISTERS },
+ { "NT_STATUS_DISK_RECALIBRATE_FAILED", NT_STATUS_DISK_RECALIBRATE_FAILED },
+ { "NT_STATUS_DISK_OPERATION_FAILED", NT_STATUS_DISK_OPERATION_FAILED },
+ { "NT_STATUS_DISK_RESET_FAILED", NT_STATUS_DISK_RESET_FAILED },
+ { "NT_STATUS_SHARED_IRQ_BUSY", NT_STATUS_SHARED_IRQ_BUSY },
+ { "NT_STATUS_FT_ORPHANING", NT_STATUS_FT_ORPHANING },
+ { "NT_STATUS_PARTITION_FAILURE", NT_STATUS_PARTITION_FAILURE },
+ { "NT_STATUS_INVALID_BLOCK_LENGTH", NT_STATUS_INVALID_BLOCK_LENGTH },
+ { "NT_STATUS_DEVICE_NOT_PARTITIONED", NT_STATUS_DEVICE_NOT_PARTITIONED },
+ { "NT_STATUS_UNABLE_TO_LOCK_MEDIA", NT_STATUS_UNABLE_TO_LOCK_MEDIA },
+ { "NT_STATUS_UNABLE_TO_UNLOAD_MEDIA", NT_STATUS_UNABLE_TO_UNLOAD_MEDIA },
+ { "NT_STATUS_EOM_OVERFLOW", NT_STATUS_EOM_OVERFLOW },
+ { "NT_STATUS_NO_MEDIA", NT_STATUS_NO_MEDIA },
+ { "NT_STATUS_NO_SUCH_MEMBER", NT_STATUS_NO_SUCH_MEMBER },
+ { "NT_STATUS_INVALID_MEMBER", NT_STATUS_INVALID_MEMBER },
+ { "NT_STATUS_KEY_DELETED", NT_STATUS_KEY_DELETED },
+ { "NT_STATUS_NO_LOG_SPACE", NT_STATUS_NO_LOG_SPACE },
+ { "NT_STATUS_TOO_MANY_SIDS", NT_STATUS_TOO_MANY_SIDS },
+ { "NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED", NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED },
+ { "NT_STATUS_KEY_HAS_CHILDREN", NT_STATUS_KEY_HAS_CHILDREN },
+ { "NT_STATUS_CHILD_MUST_BE_VOLATILE", NT_STATUS_CHILD_MUST_BE_VOLATILE },
+ { "NT_STATUS_DEVICE_CONFIGURATION_ERROR", NT_STATUS_DEVICE_CONFIGURATION_ERROR },
+ { "NT_STATUS_DRIVER_INTERNAL_ERROR", NT_STATUS_DRIVER_INTERNAL_ERROR },
+ { "NT_STATUS_INVALID_DEVICE_STATE", NT_STATUS_INVALID_DEVICE_STATE },
+ { "NT_STATUS_IO_DEVICE_ERROR", NT_STATUS_IO_DEVICE_ERROR },
+ { "NT_STATUS_DEVICE_PROTOCOL_ERROR", NT_STATUS_DEVICE_PROTOCOL_ERROR },
+ { "NT_STATUS_BACKUP_CONTROLLER", NT_STATUS_BACKUP_CONTROLLER },
+ { "NT_STATUS_LOG_FILE_FULL", NT_STATUS_LOG_FILE_FULL },
+ { "NT_STATUS_TOO_LATE", NT_STATUS_TOO_LATE },
+ { "NT_STATUS_NO_TRUST_LSA_SECRET", NT_STATUS_NO_TRUST_LSA_SECRET },
+ { "NT_STATUS_NO_TRUST_SAM_ACCOUNT", NT_STATUS_NO_TRUST_SAM_ACCOUNT },
+ { "NT_STATUS_TRUSTED_DOMAIN_FAILURE", NT_STATUS_TRUSTED_DOMAIN_FAILURE },
+ { "NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE", NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE },
+ { "NT_STATUS_EVENTLOG_FILE_CORRUPT", NT_STATUS_EVENTLOG_FILE_CORRUPT },
+ { "NT_STATUS_EVENTLOG_CANT_START", NT_STATUS_EVENTLOG_CANT_START },
+ { "NT_STATUS_TRUST_FAILURE", NT_STATUS_TRUST_FAILURE },
+ { "NT_STATUS_MUTANT_LIMIT_EXCEEDED", NT_STATUS_MUTANT_LIMIT_EXCEEDED },
+ { "NT_STATUS_NETLOGON_NOT_STARTED", NT_STATUS_NETLOGON_NOT_STARTED },
+ { "NT_STATUS_ACCOUNT_EXPIRED", NT_STATUS_ACCOUNT_EXPIRED },
+ { "NT_STATUS_POSSIBLE_DEADLOCK", NT_STATUS_POSSIBLE_DEADLOCK },
+ { "NT_STATUS_NETWORK_CREDENTIAL_CONFLICT", NT_STATUS_NETWORK_CREDENTIAL_CONFLICT },
+ { "NT_STATUS_REMOTE_SESSION_LIMIT", NT_STATUS_REMOTE_SESSION_LIMIT },
+ { "NT_STATUS_EVENTLOG_FILE_CHANGED", NT_STATUS_EVENTLOG_FILE_CHANGED },
+ { "NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT", NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT },
+ { "NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT", NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT },
+ { "NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT", NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT },
+ { "NT_STATUS_DOMAIN_TRUST_INCONSISTENT", NT_STATUS_DOMAIN_TRUST_INCONSISTENT },
+ { "NT_STATUS_FS_DRIVER_REQUIRED", NT_STATUS_FS_DRIVER_REQUIRED },
+ { "NT_STATUS_NO_USER_SESSION_KEY", NT_STATUS_NO_USER_SESSION_KEY },
+ { "NT_STATUS_USER_SESSION_DELETED", NT_STATUS_USER_SESSION_DELETED },
+ { "NT_STATUS_RESOURCE_LANG_NOT_FOUND", NT_STATUS_RESOURCE_LANG_NOT_FOUND },
+ { "NT_STATUS_INSUFF_SERVER_RESOURCES", NT_STATUS_INSUFF_SERVER_RESOURCES },
+ { "NT_STATUS_INVALID_BUFFER_SIZE", NT_STATUS_INVALID_BUFFER_SIZE },
+ { "NT_STATUS_INVALID_ADDRESS_COMPONENT", NT_STATUS_INVALID_ADDRESS_COMPONENT },
+ { "NT_STATUS_INVALID_ADDRESS_WILDCARD", NT_STATUS_INVALID_ADDRESS_WILDCARD },
+ { "NT_STATUS_TOO_MANY_ADDRESSES", NT_STATUS_TOO_MANY_ADDRESSES },
+ { "NT_STATUS_ADDRESS_ALREADY_EXISTS", NT_STATUS_ADDRESS_ALREADY_EXISTS },
+ { "NT_STATUS_ADDRESS_CLOSED", NT_STATUS_ADDRESS_CLOSED },
+ { "NT_STATUS_CONNECTION_DISCONNECTED", NT_STATUS_CONNECTION_DISCONNECTED },
+ { "NT_STATUS_CONNECTION_RESET", NT_STATUS_CONNECTION_RESET },
+ { "NT_STATUS_TOO_MANY_NODES", NT_STATUS_TOO_MANY_NODES },
+ { "NT_STATUS_TRANSACTION_ABORTED", NT_STATUS_TRANSACTION_ABORTED },
+ { "NT_STATUS_TRANSACTION_TIMED_OUT", NT_STATUS_TRANSACTION_TIMED_OUT },
+ { "NT_STATUS_TRANSACTION_NO_RELEASE", NT_STATUS_TRANSACTION_NO_RELEASE },
+ { "NT_STATUS_TRANSACTION_NO_MATCH", NT_STATUS_TRANSACTION_NO_MATCH },
+ { "NT_STATUS_TRANSACTION_RESPONDED", NT_STATUS_TRANSACTION_RESPONDED },
+ { "NT_STATUS_TRANSACTION_INVALID_ID", NT_STATUS_TRANSACTION_INVALID_ID },
+ { "NT_STATUS_TRANSACTION_INVALID_TYPE", NT_STATUS_TRANSACTION_INVALID_TYPE },
+ { "NT_STATUS_NOT_SERVER_SESSION", NT_STATUS_NOT_SERVER_SESSION },
+ { "NT_STATUS_NOT_CLIENT_SESSION", NT_STATUS_NOT_CLIENT_SESSION },
+ { "NT_STATUS_CANNOT_LOAD_REGISTRY_FILE", NT_STATUS_CANNOT_LOAD_REGISTRY_FILE },
+ { "NT_STATUS_DEBUG_ATTACH_FAILED", NT_STATUS_DEBUG_ATTACH_FAILED },
+ { "NT_STATUS_SYSTEM_PROCESS_TERMINATED", NT_STATUS_SYSTEM_PROCESS_TERMINATED },
+ { "NT_STATUS_DATA_NOT_ACCEPTED", NT_STATUS_DATA_NOT_ACCEPTED },
+ { "NT_STATUS_NO_BROWSER_SERVERS_FOUND", NT_STATUS_NO_BROWSER_SERVERS_FOUND },
+ { "NT_STATUS_VDM_HARD_ERROR", NT_STATUS_VDM_HARD_ERROR },
+ { "NT_STATUS_DRIVER_CANCEL_TIMEOUT", NT_STATUS_DRIVER_CANCEL_TIMEOUT },
+ { "NT_STATUS_REPLY_MESSAGE_MISMATCH", NT_STATUS_REPLY_MESSAGE_MISMATCH },
+ { "NT_STATUS_MAPPED_ALIGNMENT", NT_STATUS_MAPPED_ALIGNMENT },
+ { "NT_STATUS_IMAGE_CHECKSUM_MISMATCH", NT_STATUS_IMAGE_CHECKSUM_MISMATCH },
+ { "NT_STATUS_LOST_WRITEBEHIND_DATA", NT_STATUS_LOST_WRITEBEHIND_DATA },
+ { "NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID", NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID },
+ { "NT_STATUS_PASSWORD_MUST_CHANGE", NT_STATUS_PASSWORD_MUST_CHANGE },
+ { "NT_STATUS_NOT_FOUND", NT_STATUS_NOT_FOUND },
+ { "NT_STATUS_NOT_TINY_STREAM", NT_STATUS_NOT_TINY_STREAM },
+ { "NT_STATUS_RECOVERY_FAILURE", NT_STATUS_RECOVERY_FAILURE },
+ { "NT_STATUS_STACK_OVERFLOW_READ", NT_STATUS_STACK_OVERFLOW_READ },
+ { "NT_STATUS_FAIL_CHECK", NT_STATUS_FAIL_CHECK },
+ { "NT_STATUS_DUPLICATE_OBJECTID", NT_STATUS_DUPLICATE_OBJECTID },
+ { "NT_STATUS_OBJECTID_EXISTS", NT_STATUS_OBJECTID_EXISTS },
+ { "NT_STATUS_CONVERT_TO_LARGE", NT_STATUS_CONVERT_TO_LARGE },
+ { "NT_STATUS_RETRY", NT_STATUS_RETRY },
+ { "NT_STATUS_FOUND_OUT_OF_SCOPE", NT_STATUS_FOUND_OUT_OF_SCOPE },
+ { "NT_STATUS_ALLOCATE_BUCKET", NT_STATUS_ALLOCATE_BUCKET },
+ { "NT_STATUS_PROPSET_NOT_FOUND", NT_STATUS_PROPSET_NOT_FOUND },
+ { "NT_STATUS_MARSHALL_OVERFLOW", NT_STATUS_MARSHALL_OVERFLOW },
+ { "NT_STATUS_INVALID_VARIANT", NT_STATUS_INVALID_VARIANT },
+ { "NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND", NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND },
+ { "NT_STATUS_ACCOUNT_LOCKED_OUT", NT_STATUS_ACCOUNT_LOCKED_OUT },
+ { "NT_STATUS_HANDLE_NOT_CLOSABLE", NT_STATUS_HANDLE_NOT_CLOSABLE },
+ { "NT_STATUS_CONNECTION_REFUSED", NT_STATUS_CONNECTION_REFUSED },
+ { "NT_STATUS_GRACEFUL_DISCONNECT", NT_STATUS_GRACEFUL_DISCONNECT },
+ { "NT_STATUS_ADDRESS_ALREADY_ASSOCIATED", NT_STATUS_ADDRESS_ALREADY_ASSOCIATED },
+ { "NT_STATUS_ADDRESS_NOT_ASSOCIATED", NT_STATUS_ADDRESS_NOT_ASSOCIATED },
+ { "NT_STATUS_CONNECTION_INVALID", NT_STATUS_CONNECTION_INVALID },
+ { "NT_STATUS_CONNECTION_ACTIVE", NT_STATUS_CONNECTION_ACTIVE },
+ { "NT_STATUS_NETWORK_UNREACHABLE", NT_STATUS_NETWORK_UNREACHABLE },
+ { "NT_STATUS_HOST_UNREACHABLE", NT_STATUS_HOST_UNREACHABLE },
+ { "NT_STATUS_PROTOCOL_UNREACHABLE", NT_STATUS_PROTOCOL_UNREACHABLE },
+ { "NT_STATUS_PORT_UNREACHABLE", NT_STATUS_PORT_UNREACHABLE },
+ { "NT_STATUS_REQUEST_ABORTED", NT_STATUS_REQUEST_ABORTED },
+ { "NT_STATUS_CONNECTION_ABORTED", NT_STATUS_CONNECTION_ABORTED },
+ { "NT_STATUS_BAD_COMPRESSION_BUFFER", NT_STATUS_BAD_COMPRESSION_BUFFER },
+ { "NT_STATUS_USER_MAPPED_FILE", NT_STATUS_USER_MAPPED_FILE },
+ { "NT_STATUS_AUDIT_FAILED", NT_STATUS_AUDIT_FAILED },
+ { "NT_STATUS_TIMER_RESOLUTION_NOT_SET", NT_STATUS_TIMER_RESOLUTION_NOT_SET },
+ { "NT_STATUS_CONNECTION_COUNT_LIMIT", NT_STATUS_CONNECTION_COUNT_LIMIT },
+ { "NT_STATUS_LOGIN_TIME_RESTRICTION", NT_STATUS_LOGIN_TIME_RESTRICTION },
+ { "NT_STATUS_LOGIN_WKSTA_RESTRICTION", NT_STATUS_LOGIN_WKSTA_RESTRICTION },
+ { "NT_STATUS_IMAGE_MP_UP_MISMATCH", NT_STATUS_IMAGE_MP_UP_MISMATCH },
+ { "NT_STATUS_INSUFFICIENT_LOGON_INFO", NT_STATUS_INSUFFICIENT_LOGON_INFO },
+ { "NT_STATUS_BAD_DLL_ENTRYPOINT", NT_STATUS_BAD_DLL_ENTRYPOINT },
+ { "NT_STATUS_BAD_SERVICE_ENTRYPOINT", NT_STATUS_BAD_SERVICE_ENTRYPOINT },
+ { "NT_STATUS_LPC_REPLY_LOST", NT_STATUS_LPC_REPLY_LOST },
+ { "NT_STATUS_IP_ADDRESS_CONFLICT1", NT_STATUS_IP_ADDRESS_CONFLICT1 },
+ { "NT_STATUS_IP_ADDRESS_CONFLICT2", NT_STATUS_IP_ADDRESS_CONFLICT2 },
+ { "NT_STATUS_REGISTRY_QUOTA_LIMIT", NT_STATUS_REGISTRY_QUOTA_LIMIT },
+ { "NT_STATUS_PATH_NOT_COVERED", NT_STATUS_PATH_NOT_COVERED },
+ { "NT_STATUS_NO_CALLBACK_ACTIVE", NT_STATUS_NO_CALLBACK_ACTIVE },
+ { "NT_STATUS_LICENSE_QUOTA_EXCEEDED", NT_STATUS_LICENSE_QUOTA_EXCEEDED },
+ { "NT_STATUS_PWD_TOO_SHORT", NT_STATUS_PWD_TOO_SHORT },
+ { "NT_STATUS_PWD_TOO_RECENT", NT_STATUS_PWD_TOO_RECENT },
+ { "NT_STATUS_PWD_HISTORY_CONFLICT", NT_STATUS_PWD_HISTORY_CONFLICT },
+ { "NT_STATUS_PLUGPLAY_NO_DEVICE", NT_STATUS_PLUGPLAY_NO_DEVICE },
+ { "NT_STATUS_UNSUPPORTED_COMPRESSION", NT_STATUS_UNSUPPORTED_COMPRESSION },
+ { "NT_STATUS_INVALID_HW_PROFILE", NT_STATUS_INVALID_HW_PROFILE },
+ { "NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH", NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH },
+ { "NT_STATUS_DRIVER_ORDINAL_NOT_FOUND", NT_STATUS_DRIVER_ORDINAL_NOT_FOUND },
+ { "NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND", NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND },
+ { "NT_STATUS_RESOURCE_NOT_OWNED", NT_STATUS_RESOURCE_NOT_OWNED },
+ { "NT_STATUS_TOO_MANY_LINKS", NT_STATUS_TOO_MANY_LINKS },
+ { "NT_STATUS_QUOTA_LIST_INCONSISTENT", NT_STATUS_QUOTA_LIST_INCONSISTENT },
+ { "NT_STATUS_FILE_IS_OFFLINE", NT_STATUS_FILE_IS_OFFLINE },
+ { "NT_STATUS_NO_MORE_ENTRIES", NT_STATUS_NO_MORE_ENTRIES },
+ { "STATUS_MORE_ENTRIES", STATUS_MORE_ENTRIES },
+ { "STATUS_SOME_UNMAPPED", STATUS_SOME_UNMAPPED },
+ { NULL, NT_STATUS(0) }
+};
+
+static const nt_err_code_struct nt_err_desc[] =
+{
+ { "Success", NT_STATUS_OK },
+ { "Undetermined error", NT_STATUS_UNSUCCESSFUL },
+ { "Access denied", NT_STATUS_ACCESS_DENIED },
+ { "Account locked out", NT_STATUS_ACCOUNT_LOCKED_OUT },
+ { "Must change password", NT_STATUS_PASSWORD_MUST_CHANGE },
+ { "Password is too short", NT_STATUS_PWD_TOO_SHORT },
+ { "Password is too recent", NT_STATUS_PWD_TOO_RECENT },
+ { "Password history conflict", NT_STATUS_PWD_HISTORY_CONFLICT },
+ { "No logon servers", NT_STATUS_NO_LOGON_SERVERS },
+ { "Improperly formed account name", NT_STATUS_INVALID_ACCOUNT_NAME },
+ { "User exists", NT_STATUS_USER_EXISTS },
+ { "No such user", NT_STATUS_NO_SUCH_USER },
+ { "Group exists", NT_STATUS_GROUP_EXISTS },
+ { "No such group", NT_STATUS_NO_SUCH_GROUP },
+ { "Member not in group", NT_STATUS_MEMBER_NOT_IN_GROUP },
+ { "Wrong Password", NT_STATUS_WRONG_PASSWORD },
+ { "Ill formed password", NT_STATUS_ILL_FORMED_PASSWORD },
+ { "Password restriction", NT_STATUS_PASSWORD_RESTRICTION },
+ { "Logon failure", NT_STATUS_LOGON_FAILURE },
+ { "Account restriction", NT_STATUS_ACCOUNT_RESTRICTION },
+ { "Invalid logon hours", NT_STATUS_INVALID_LOGON_HOURS },
+ { "Invalid workstation", NT_STATUS_INVALID_WORKSTATION },
+ { "Password expired", NT_STATUS_PASSWORD_EXPIRED },
+ { "Account disabled", NT_STATUS_ACCOUNT_DISABLED },
+ { "Unexpected information received", NT_STATUS_INVALID_PARAMETER },
+ { "Memory allocation error", NT_STATUS_NO_MEMORY },
+ { "No domain controllers located", NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND },
+ { "Account locked out", NT_STATUS_ACCOUNT_LOCKED_OUT },
+ { "Named pipe not available", NT_STATUS_PIPE_NOT_AVAILABLE },
+ { "Not implemented", NT_STATUS_NOT_IMPLEMENTED },
+ { "Invalid information class", NT_STATUS_INVALID_INFO_CLASS },
+ { "Information length mismatch", NT_STATUS_INFO_LENGTH_MISMATCH },
+ { "Access violation", NT_STATUS_ACCESS_VIOLATION },
+ { "Invalid handle", NT_STATUS_INVALID_HANDLE },
+ { "Invalid parameter", NT_STATUS_INVALID_PARAMETER },
+ { "No memory", NT_STATUS_NO_MEMORY },
+ { "Buffer too small", NT_STATUS_BUFFER_TOO_SMALL },
+ { "Revision mismatch", NT_STATUS_REVISION_MISMATCH },
+ { "No logon servers", NT_STATUS_NO_LOGON_SERVERS },
+ { "No such logon session", NT_STATUS_NO_SUCH_LOGON_SESSION },
+ { "No such privilege", NT_STATUS_NO_SUCH_PRIVILEGE },
+ { "Procedure not found", NT_STATUS_PROCEDURE_NOT_FOUND },
+ { "Server disabled", NT_STATUS_SERVER_DISABLED },
+ { "Invalid pipe state", NT_STATUS_INVALID_PIPE_STATE },
+ { "Named pipe busy", NT_STATUS_PIPE_BUSY },
+ { "Illegal function", NT_STATUS_ILLEGAL_FUNCTION },
+ { "Named pipe dicconnected", NT_STATUS_PIPE_DISCONNECTED },
+ { "Named pipe closing", NT_STATUS_PIPE_CLOSING },
+ { "Remote host not listening", NT_STATUS_REMOTE_NOT_LISTENING },
+ { "Duplicate name on network", NT_STATUS_DUPLICATE_NAME },
+ { "Print queue is full", NT_STATUS_PRINT_QUEUE_FULL },
+ { "No print spool space available", NT_STATUS_NO_SPOOL_SPACE },
+ { "Too many names", NT_STATUS_TOO_MANY_NAMES },
+ { "Too many sessions", NT_STATUS_TOO_MANY_SESSIONS },
+ { "Invalid server state", NT_STATUS_INVALID_SERVER_STATE },
+ { "Invalid domain state", NT_STATUS_INVALID_DOMAIN_STATE },
+ { "Invalid domain role", NT_STATUS_INVALID_DOMAIN_ROLE },
+ { "No such domain", NT_STATUS_NO_SUCH_DOMAIN },
+ { "Domain exists", NT_STATUS_DOMAIN_EXISTS },
+ { "Domain limit exceeded", NT_STATUS_DOMAIN_LIMIT_EXCEEDED },
+ { "Bad logon session state", NT_STATUS_BAD_LOGON_SESSION_STATE },
+ { "Logon session collision", NT_STATUS_LOGON_SESSION_COLLISION },
+ { "Invalid logon type", NT_STATUS_INVALID_LOGON_TYPE },
+ { "Cancelled", NT_STATUS_CANCELLED },
+ { "Invalid computer name", NT_STATUS_INVALID_COMPUTER_NAME },
+ { "Logon server conflict", NT_STATUS_LOGON_SERVER_CONFLICT },
+ { "Time difference at domain controller", NT_STATUS_TIME_DIFFERENCE_AT_DC },
+ { "Pipe broken", NT_STATUS_PIPE_BROKEN },
+ { "Registry corrupt", NT_STATUS_REGISTRY_CORRUPT },
+ { "Too many secrets", NT_STATUS_TOO_MANY_SECRETS },
+ { "Too many SIDs", NT_STATUS_TOO_MANY_SIDS },
+ { "Lanmanager cross encryption required", NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED },
+ { "Log file full", NT_STATUS_LOG_FILE_FULL },
+ { "No trusted LSA secret", NT_STATUS_NO_TRUST_LSA_SECRET },
+ { "No trusted SAM account", NT_STATUS_NO_TRUST_SAM_ACCOUNT },
+ { "Trusted domain failure", NT_STATUS_TRUSTED_DOMAIN_FAILURE },
+ { "Trust relationship failure", NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE },
+ { "Trust failure", NT_STATUS_TRUST_FAILURE },
+ { "Netlogon service not started", NT_STATUS_NETLOGON_NOT_STARTED },
+ { "Account expired", NT_STATUS_ACCOUNT_EXPIRED },
+ { "Network credential conflict", NT_STATUS_NETWORK_CREDENTIAL_CONFLICT },
+ { "Remote session limit", NT_STATUS_REMOTE_SESSION_LIMIT },
+ { "No logon interdomain trust account", NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT },
+ { "No logon workstation trust account", NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT },
+ { "No logon server trust account", NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT },
+ { "Domain trust inconsistent", NT_STATUS_DOMAIN_TRUST_INCONSISTENT },
+ { "No user session key available", NT_STATUS_NO_USER_SESSION_KEY },
+ { "User session deleted", NT_STATUS_USER_SESSION_DELETED },
+ { "Insufficient server resources", NT_STATUS_INSUFF_SERVER_RESOURCES },
+ { "Insufficient logon information", NT_STATUS_INSUFFICIENT_LOGON_INFO },
+
+ { "License quota exceeded", NT_STATUS_LICENSE_QUOTA_EXCEEDED },
+
+ { NULL, NT_STATUS(0) }
+};
+
+
+/*****************************************************************************
+ returns an NT error message. not amazingly helpful, but better than a number.
+ *****************************************************************************/
+const char *nt_errstr(NTSTATUS nt_code)
+{
+ static pstring msg;
+ int idx = 0;
+
+ slprintf(msg, sizeof(msg), "NT code 0x%08x", NT_STATUS_V(nt_code));
+
+ 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++;
+ }
+
+ return msg;
+}
+
+/************************************************************************
+ Print friendler version fo 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);
+}
+
+/*****************************************************************************
+ returns an NT_STATUS constant as a string for inclusion in autogen C code
+ *****************************************************************************/
+const char *get_nt_error_c_code(NTSTATUS nt_code)
+{
+ static pstring out;
+ int 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++;
+ }
+
+ slprintf(out, sizeof(out), "NT_STATUS(0x%08x)", NT_STATUS_V(nt_code));
+
+ return out;
+}
+
+/*****************************************************************************
+ returns the NT_STATUS constant matching the string supplied (as an NTSTATUS)
+ *****************************************************************************/
+NTSTATUS nt_status_string_to_code(char *nt_status_str)
+{
+ int idx = 0;
+
+ while (nt_errs[idx].nt_errstr != NULL) {
+ if (strcmp(nt_errs[idx].nt_errstr, nt_status_str) == 0) {
+ return nt_errs[idx].nt_errcode;
+ }
+ idx++;
+ }
+ return NT_STATUS_UNSUCCESSFUL;
+}
diff --git a/source4/libcli/util/ntlmssp_sign.c b/source4/libcli/util/ntlmssp_sign.c
new file mode 100644
index 0000000000..bd6d64d842
--- /dev/null
+++ b/source4/libcli/util/ntlmssp_sign.c
@@ -0,0 +1,226 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Version 3.0
+ * NTLMSSP Signing routines
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-2001
+ * Copyright (C) Andrew Bartlett 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 2 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, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "includes.h"
+
+#define CLI_SIGN "session key to client-to-server signing key magic constant"
+#define CLI_SEAL "session key to client-to-server sealing key magic constant"
+#define SRV_SIGN "session key to server-to-client signing key magic constant"
+#define SRV_SEAL "session key to server-to-client sealing key magic constant"
+
+static void NTLMSSPcalc_ap( unsigned char *hash, unsigned char *data, int len)
+{
+ unsigned char index_i = hash[256];
+ unsigned char index_j = hash[257];
+ int ind;
+
+ for (ind = 0; ind < len; ind++)
+ {
+ unsigned char tc;
+ unsigned char t;
+
+ index_i++;
+ index_j += hash[index_i];
+
+ tc = hash[index_i];
+ hash[index_i] = hash[index_j];
+ hash[index_j] = tc;
+
+ t = hash[index_i] + hash[index_j];
+ data[ind] = data[ind] ^ hash[t];
+ }
+
+ hash[256] = index_i;
+ hash[257] = index_j;
+}
+
+static void calc_hash(unsigned char *hash, const char *k2, int k2l)
+{
+ unsigned char j = 0;
+ int ind;
+
+ for (ind = 0; ind < 256; ind++)
+ {
+ hash[ind] = (unsigned char)ind;
+ }
+
+ for (ind = 0; ind < 256; ind++)
+ {
+ unsigned char tc;
+
+ j += (hash[ind] + k2[ind%k2l]);
+
+ tc = hash[ind];
+ hash[ind] = hash[j];
+ hash[j] = tc;
+ }
+
+ hash[256] = 0;
+ hash[257] = 0;
+}
+
+static void calc_ntlmv2_hash(unsigned char hash[16], char digest[16],
+ const char encrypted_response[16],
+ const char *constant)
+{
+ struct MD5Context ctx3;
+
+ MD5Init(&ctx3);
+ MD5Update(&ctx3, encrypted_response, 5);
+ MD5Update(&ctx3, constant, strlen(constant));
+ MD5Final(digest, &ctx3);
+
+ calc_hash(hash, digest, 16);
+}
+
+enum ntlmssp_direction {
+ NTLMSSP_SEND,
+ NTLMSSP_RECEIVE
+};
+
+static NTSTATUS ntlmssp_make_packet_signiture(NTLMSSP_CLIENT_STATE *ntlmssp_state,
+ const uchar *data, size_t length,
+ enum ntlmssp_direction direction,
+ DATA_BLOB *sig)
+{
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ HMACMD5Context ctx;
+ char seq_num[4];
+ uchar digest[16];
+ SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);
+
+ hmac_md5_init_limK_to_64(ntlmssp_state->cli_sign_const, 16, &ctx);
+ hmac_md5_update(seq_num, 4, &ctx);
+ hmac_md5_update(data, length, &ctx);
+ hmac_md5_final(digest, &ctx);
+
+ if (!msrpc_gen(sig, "Bd", digest, sizeof(digest), ntlmssp_state->ntlmssp_seq_num)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ switch (direction) {
+ case NTLMSSP_SEND:
+ NTLMSSPcalc_ap(ntlmssp_state->cli_sign_hash, sig->data, sig->length);
+ break;
+ case NTLMSSP_RECEIVE:
+ NTLMSSPcalc_ap(ntlmssp_state->srv_sign_hash, sig->data, sig->length);
+ break;
+ }
+ } else {
+ uint32 crc;
+ crc = crc32_buffer(data, length);
+ if (!msrpc_gen(sig, "ddd", 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data, sig->length);
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS ntlmssp_client_sign_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
+ const uchar *data, size_t length,
+ DATA_BLOB *sig)
+{
+ ntlmssp_state->ntlmssp_seq_num++;
+ return ntlmssp_make_packet_signiture(ntlmssp_state, data, length, NTLMSSP_SEND, sig);
+}
+
+/**
+ * Check the signature of an incoming packet
+ * @note caller *must* check that the signature is the size it expects
+ *
+ */
+
+NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
+ const uchar *data, size_t length,
+ const DATA_BLOB *sig)
+{
+ DATA_BLOB local_sig;
+ NTSTATUS nt_status;
+
+ if (sig->length < 8) {
+ DEBUG(0, ("NTLMSSP packet check failed due to short signiture (%u bytes)!\n",
+ sig->length));
+ }
+
+ nt_status = ntlmssp_make_packet_signiture(ntlmssp_state, data,
+ length, NTLMSSP_RECEIVE, &local_sig);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(0, ("NTLMSSP packet check failed with %s\n", nt_errstr(nt_status)));
+ return nt_status;
+ }
+
+ if (memcmp(sig->data, local_sig.data, MIN(sig->length, local_sig.length)) == 0) {
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(5, ("BAD SIG: wanted signature of\n"));
+ dump_data(5, local_sig.data, local_sig.length);
+
+ DEBUG(5, ("BAD SIG: got signature of\n"));
+ dump_data(5, sig->data, sig->length);
+
+ DEBUG(0, ("NTLMSSP packet check failed due to invalid signiture!\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+}
+
+/**
+ Initialise the state for NTLMSSP signing.
+*/
+NTSTATUS ntlmssp_client_sign_init(NTLMSSP_CLIENT_STATE *ntlmssp_state)
+{
+ unsigned char p24[24];
+ unsigned char lm_hash[16];
+
+ if (!ntlmssp_state->lm_resp.data) {
+ /* can't sign or check signitures yet */
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ E_deshash(ntlmssp_state->password, lm_hash);
+
+ NTLMSSPOWFencrypt(lm_hash, ntlmssp_state->lm_resp.data, p24);
+
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2)
+ {
+ calc_ntlmv2_hash(ntlmssp_state->cli_sign_hash, ntlmssp_state->cli_sign_const, p24, CLI_SIGN);
+ calc_ntlmv2_hash(ntlmssp_state->cli_seal_hash, ntlmssp_state->cli_seal_const, p24, CLI_SEAL);
+ calc_ntlmv2_hash(ntlmssp_state->srv_sign_hash, ntlmssp_state->srv_sign_const, p24, SRV_SIGN);
+ calc_ntlmv2_hash(ntlmssp_state->srv_seal_hash, ntlmssp_state->srv_seal_const, p24, SRV_SEAL);
+ }
+ else
+ {
+ char k2[8];
+ memcpy(k2, p24, 5);
+ k2[5] = 0xe5;
+ k2[6] = 0x38;
+ k2[7] = 0xb0;
+
+ calc_hash(ntlmssp_state->ntlmssp_hash, k2, 8);
+ }
+
+ ntlmssp_state->ntlmssp_seq_num = 0;
+
+ ZERO_STRUCT(lm_hash);
+ return NT_STATUS_OK;
+}
diff --git a/source4/libcli/util/pwd_cache.c b/source4/libcli/util/pwd_cache.c
new file mode 100644
index 0000000000..0d84f04ee3
--- /dev/null
+++ b/source4/libcli/util/pwd_cache.c
@@ -0,0 +1,72 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password cacheing. obfuscation is planned
+ Copyright (C) Luke Kenneth Casson Leighton 1996-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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Initialises a password structure.
+****************************************************************************/
+
+static void pwd_init(struct pwd_info *pwd)
+{
+ memset((char *)pwd->password , '\0', sizeof(pwd->password ));
+ memset((char *)pwd->smb_lm_pwd, '\0', sizeof(pwd->smb_lm_pwd));
+ memset((char *)pwd->smb_nt_pwd, '\0', sizeof(pwd->smb_nt_pwd));
+ memset((char *)pwd->smb_lm_owf, '\0', sizeof(pwd->smb_lm_owf));
+ memset((char *)pwd->smb_nt_owf, '\0', sizeof(pwd->smb_nt_owf));
+
+ pwd->null_pwd = True; /* safest option... */
+ pwd->cleartext = False;
+ pwd->crypted = False;
+}
+
+/****************************************************************************
+ Makes lm and nt hashed passwords.
+****************************************************************************/
+
+static void pwd_make_lm_nt_16(struct pwd_info *pwd, const char *clr)
+{
+ pstring dos_passwd;
+
+ pwd_init(pwd);
+
+ push_ascii_pstring(dos_passwd, clr);
+
+ nt_lm_owf_gen(dos_passwd, pwd->smb_nt_pwd, pwd->smb_lm_pwd);
+ pwd->null_pwd = False;
+ pwd->cleartext = False;
+ pwd->crypted = False;
+}
+
+/****************************************************************************
+ Stores a cleartext password.
+****************************************************************************/
+
+void pwd_set_cleartext(struct pwd_info *pwd, const char *clr)
+{
+ pwd_init(pwd);
+ push_ascii_fstring(pwd->password, clr);
+ pwd->cleartext = True;
+ pwd->null_pwd = False;
+ pwd->crypted = False;
+ pwd_make_lm_nt_16(pwd, clr);
+}
+
+
diff --git a/source4/libcli/util/smbdes.c b/source4/libcli/util/smbdes.c
new file mode 100644
index 0000000000..cde77f94a3
--- /dev/null
+++ b/source4/libcli/util/smbdes.c
@@ -0,0 +1,415 @@
+/*
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/* NOTES:
+
+ This code makes no attempt to be fast! In fact, it is a very
+ slow implementation
+
+ This code is NOT a complete DES implementation. It implements only
+ the minimum necessary for SMB authentication, as used by all SMB
+ products (including every copy of Microsoft Windows95 ever sold)
+
+ In particular, it can only do a unchained forward DES pass. This
+ means it is not possible to use this code for encryption/decryption
+ of data, instead it is only useful as a "hash" algorithm.
+
+ There is no entry point into this code that allows normal DES operation.
+
+ I believe this means that this code does not come under ITAR
+ regulations but this is NOT a legal opinion. If you are concerned
+ about the applicability of ITAR regulations to this code then you
+ should confirm it for yourself (and maybe let me know if you come
+ up with a different answer to the one above)
+*/
+
+
+#define uchar unsigned char
+
+static const uchar perm1[56] = {57, 49, 41, 33, 25, 17, 9,
+ 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27,
+ 19, 11, 3, 60, 52, 44, 36,
+ 63, 55, 47, 39, 31, 23, 15,
+ 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29,
+ 21, 13, 5, 28, 20, 12, 4};
+
+static const uchar perm2[48] = {14, 17, 11, 24, 1, 5,
+ 3, 28, 15, 6, 21, 10,
+ 23, 19, 12, 4, 26, 8,
+ 16, 7, 27, 20, 13, 2,
+ 41, 52, 31, 37, 47, 55,
+ 30, 40, 51, 45, 33, 48,
+ 44, 49, 39, 56, 34, 53,
+ 46, 42, 50, 36, 29, 32};
+
+static const uchar perm3[64] = {58, 50, 42, 34, 26, 18, 10, 2,
+ 60, 52, 44, 36, 28, 20, 12, 4,
+ 62, 54, 46, 38, 30, 22, 14, 6,
+ 64, 56, 48, 40, 32, 24, 16, 8,
+ 57, 49, 41, 33, 25, 17, 9, 1,
+ 59, 51, 43, 35, 27, 19, 11, 3,
+ 61, 53, 45, 37, 29, 21, 13, 5,
+ 63, 55, 47, 39, 31, 23, 15, 7};
+
+static const uchar perm4[48] = { 32, 1, 2, 3, 4, 5,
+ 4, 5, 6, 7, 8, 9,
+ 8, 9, 10, 11, 12, 13,
+ 12, 13, 14, 15, 16, 17,
+ 16, 17, 18, 19, 20, 21,
+ 20, 21, 22, 23, 24, 25,
+ 24, 25, 26, 27, 28, 29,
+ 28, 29, 30, 31, 32, 1};
+
+static const uchar perm5[32] = { 16, 7, 20, 21,
+ 29, 12, 28, 17,
+ 1, 15, 23, 26,
+ 5, 18, 31, 10,
+ 2, 8, 24, 14,
+ 32, 27, 3, 9,
+ 19, 13, 30, 6,
+ 22, 11, 4, 25};
+
+
+static const uchar perm6[64] ={ 40, 8, 48, 16, 56, 24, 64, 32,
+ 39, 7, 47, 15, 55, 23, 63, 31,
+ 38, 6, 46, 14, 54, 22, 62, 30,
+ 37, 5, 45, 13, 53, 21, 61, 29,
+ 36, 4, 44, 12, 52, 20, 60, 28,
+ 35, 3, 43, 11, 51, 19, 59, 27,
+ 34, 2, 42, 10, 50, 18, 58, 26,
+ 33, 1, 41, 9, 49, 17, 57, 25};
+
+
+static const uchar sc[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
+
+static const uchar sbox[8][4][16] = {
+ {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
+ {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
+ {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
+ {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}},
+
+ {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
+ {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
+ {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
+ {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}},
+
+ {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
+ {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
+ {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
+ {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}},
+
+ {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
+ {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
+ {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
+ {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}},
+
+ {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
+ {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
+ {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
+ {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}},
+
+ {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
+ {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
+ {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
+ {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}},
+
+ {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
+ {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
+ {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
+ {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}},
+
+ {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
+ {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
+ {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
+ {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}}};
+
+static void permute(char *out, const char *in, const uchar *p, int n)
+{
+ int i;
+ for (i=0;i<n;i++)
+ out[i] = in[p[i]-1];
+}
+
+static void lshift(char *d, int count, int n)
+{
+ char out[64];
+ int i;
+ for (i=0;i<n;i++)
+ out[i] = d[(i+count)%n];
+ for (i=0;i<n;i++)
+ d[i] = out[i];
+}
+
+static void concat(char *out, char *in1, char *in2, int l1, int l2)
+{
+ while (l1--)
+ *out++ = *in1++;
+ while (l2--)
+ *out++ = *in2++;
+}
+
+static void xor(char *out, char *in1, char *in2, int n)
+{
+ int i;
+ for (i=0;i<n;i++)
+ out[i] = in1[i] ^ in2[i];
+}
+
+static void dohash(char *out, char *in, char *key, int forw)
+{
+ int i, j, k;
+ char pk1[56];
+ char c[28];
+ char d[28];
+ char cd[56];
+ char ki[16][48];
+ char pd1[64];
+ char l[32], r[32];
+ char rl[64];
+
+ permute(pk1, key, perm1, 56);
+
+ for (i=0;i<28;i++)
+ c[i] = pk1[i];
+ for (i=0;i<28;i++)
+ d[i] = pk1[i+28];
+
+ for (i=0;i<16;i++) {
+ lshift(c, sc[i], 28);
+ lshift(d, sc[i], 28);
+
+ concat(cd, c, d, 28, 28);
+ permute(ki[i], cd, perm2, 48);
+ }
+
+ permute(pd1, in, perm3, 64);
+
+ for (j=0;j<32;j++) {
+ l[j] = pd1[j];
+ r[j] = pd1[j+32];
+ }
+
+ for (i=0;i<16;i++) {
+ char er[48];
+ char erk[48];
+ char b[8][6];
+ char cb[32];
+ char pcb[32];
+ char r2[32];
+
+ permute(er, r, perm4, 48);
+
+ xor(erk, er, ki[forw ? i : 15 - i], 48);
+
+ for (j=0;j<8;j++)
+ for (k=0;k<6;k++)
+ b[j][k] = erk[j*6 + k];
+
+ for (j=0;j<8;j++) {
+ int m, n;
+ m = (b[j][0]<<1) | b[j][5];
+
+ n = (b[j][1]<<3) | (b[j][2]<<2) | (b[j][3]<<1) | b[j][4];
+
+ for (k=0;k<4;k++)
+ b[j][k] = (sbox[j][m][n] & (1<<(3-k)))?1:0;
+ }
+
+ for (j=0;j<8;j++)
+ for (k=0;k<4;k++)
+ cb[j*4+k] = b[j][k];
+ permute(pcb, cb, perm5, 32);
+
+ xor(r2, l, pcb, 32);
+
+ for (j=0;j<32;j++)
+ l[j] = r[j];
+
+ for (j=0;j<32;j++)
+ r[j] = r2[j];
+ }
+
+ concat(rl, r, l, 32, 32);
+
+ permute(out, rl, perm6, 64);
+}
+
+static void str_to_key(const unsigned char *str,unsigned char *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);
+ }
+}
+
+
+static void smbhash(unsigned char *out, const unsigned char *in, const unsigned char *key, int forw)
+{
+ int i;
+ char outb[64];
+ char inb[64];
+ char keyb[64];
+ unsigned char key2[8];
+
+ str_to_key(key, key2);
+
+ for (i=0;i<64;i++) {
+ inb[i] = (in[i/8] & (1<<(7-(i%8)))) ? 1 : 0;
+ keyb[i] = (key2[i/8] & (1<<(7-(i%8)))) ? 1 : 0;
+ outb[i] = 0;
+ }
+
+ dohash(outb, inb, keyb, forw);
+
+ for (i=0;i<8;i++) {
+ out[i] = 0;
+ }
+
+ for (i=0;i<64;i++) {
+ if (outb[i])
+ out[i/8] |= (1<<(7-(i%8)));
+ }
+}
+
+void E_P16(const unsigned char *p14,unsigned char *p16)
+{
+ unsigned char sp8[8] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
+ smbhash(p16, sp8, p14, 1);
+ smbhash(p16+8, sp8, p14+7, 1);
+}
+
+void E_P24(const unsigned char *p21, const unsigned char *c8, unsigned char *p24)
+{
+ smbhash(p24, c8, p21, 1);
+ smbhash(p24+8, c8, p21+7, 1);
+ smbhash(p24+16, c8, p21+14, 1);
+}
+
+void D_P16(const unsigned char *p14, const unsigned char *in, unsigned char *out)
+{
+ smbhash(out, in, p14, 0);
+ smbhash(out+8, in+8, p14+7, 0);
+}
+
+void E_old_pw_hash( unsigned char *p14, const unsigned char *in, unsigned char *out)
+{
+ smbhash(out, in, p14, 1);
+ smbhash(out+8, in+8, p14+7, 1);
+}
+
+void cred_hash1(unsigned char *out, const unsigned char *in, const unsigned char *key)
+{
+ unsigned char buf[8];
+
+ smbhash(buf, in, key, 1);
+ smbhash(out, buf, key+9, 1);
+}
+
+void cred_hash2(unsigned char *out, const unsigned char *in, const unsigned char *key)
+{
+ unsigned char buf[8];
+ static unsigned char key2[8];
+
+ smbhash(buf, in, key, 1);
+ key2[0] = key[7];
+ smbhash(out, buf, key2, 1);
+}
+
+void cred_hash3(unsigned char *out, unsigned char *in, const unsigned char *key, int forw)
+{
+ static unsigned char key2[8];
+
+ smbhash(out, in, key, forw);
+ key2[0] = key[7];
+ smbhash(out + 8, in + 8, key2, forw);
+}
+
+void SamOEMhash( unsigned char *data, const unsigned char *key, int val)
+{
+ unsigned char s_box[256];
+ unsigned char index_i = 0;
+ unsigned char index_j = 0;
+ unsigned char j = 0;
+ int ind;
+
+ for (ind = 0; ind < 256; ind++)
+ {
+ s_box[ind] = (unsigned char)ind;
+ }
+
+ for( ind = 0; ind < 256; ind++)
+ {
+ unsigned char tc;
+
+ j += (s_box[ind] + key[ind%16]);
+
+ tc = s_box[ind];
+ s_box[ind] = s_box[j];
+ s_box[j] = tc;
+ }
+ for( ind = 0; ind < val; ind++)
+ {
+ unsigned char tc;
+ unsigned char t;
+
+ index_i++;
+ index_j += s_box[index_i];
+
+ tc = s_box[index_i];
+ s_box[index_i] = s_box[index_j];
+ s_box[index_j] = tc;
+
+ t = s_box[index_i] + s_box[index_j];
+ data[ind] = data[ind] ^ s_box[t];
+ }
+}
+
+/* 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. */
+
+void sam_pwd_hash(unsigned int rid, const uchar *in, uchar *out, int forw)
+{
+ uchar s[14];
+
+ s[0] = s[4] = s[8] = s[12] = (uchar)(rid & 0xFF);
+ s[1] = s[5] = s[9] = s[13] = (uchar)((rid >> 8) & 0xFF);
+ s[2] = s[6] = s[10] = (uchar)((rid >> 16) & 0xFF);
+ s[3] = s[7] = s[11] = (uchar)((rid >> 24) & 0xFF);
+
+ smbhash(out, in, s, forw);
+ smbhash(out+8, in+8, s+7, forw);
+}
diff --git a/source4/libcli/util/smbencrypt.c b/source4/libcli/util/smbencrypt.c
new file mode 100644
index 0000000000..00c2b58146
--- /dev/null
+++ b/source4/libcli/util/smbencrypt.c
@@ -0,0 +1,418 @@
+/*
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "byteorder.h"
+
+/*
+ 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 */
+void SMBencrypt(const char *passwd, const uchar *c8, uchar p24[24])
+{
+ uchar p21[21];
+
+ memset(p21,'\0',21);
+ E_deshash(passwd, p21);
+
+ SMBOWFencrypt(p21, c8, p24);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("SMBencrypt: lm#, challenge, response\n"));
+ dump_data(100, (char *)p21, 16);
+ dump_data(100, (const char *)c8, 8);
+ dump_data(100, (char *)p24, 24);
+#endif
+}
+
+/**
+ * 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
+ */
+
+void E_md4hash(const char *passwd, uchar p16[16])
+{
+ int len;
+ smb_ucs2_t wpwd[129];
+
+ /* Password must be converted to NT unicode - null terminated. */
+ push_ucs2(NULL, wpwd, (const char *)passwd, 256, STR_UNICODE|STR_NOALIGN|STR_TERMINATE);
+ /* Calculate length in bytes */
+ len = strlen_w(wpwd) * sizeof(int16);
+
+ mdfour(p16, (unsigned char *)wpwd, len);
+ ZERO_STRUCT(wpwd);
+}
+
+/**
+ * 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
+ */
+
+void E_deshash(const char *passwd, uchar p16[16])
+{
+ fstring dospwd;
+ ZERO_STRUCT(dospwd);
+ ZERO_STRUCTP(p16);
+
+ /* Password must be converted to DOS charset - null terminated, uppercase. */
+ push_ascii(dospwd, (const char *)passwd, sizeof(dospwd), STR_UPPER|STR_TERMINATE);
+
+ /* Only the fisrt 14 chars are considered, password need not be null terminated. */
+ E_P16(dospwd, p16);
+
+ ZERO_STRUCT(dospwd);
+}
+
+/**
+ * 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, uchar nt_p16[16], uchar 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, pwd, strlen(pwd));
+ dump_data(100, (char *)nt_p16, 16);
+#endif
+
+ E_deshash(pwd, (uchar *)p16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("nt_lm_owf_gen: pwd, lm#\n"));
+ dump_data(120, pwd, strlen(pwd));
+ dump_data(100, (char *)p16, 16);
+#endif
+}
+
+/* Does both the NTLMv2 owfs of a user's password */
+BOOL ntv2_owf_gen(const uchar owf[16],
+ const char *user_in, const char *domain_in, uchar kr_buf[16])
+{
+ smb_ucs2_t *user;
+ smb_ucs2_t *domain;
+
+ size_t user_byte_len;
+ size_t domain_byte_len;
+
+ HMACMD5Context ctx;
+
+ user_byte_len = push_ucs2_allocate(&user, user_in);
+ if (user_byte_len == (size_t)-1) {
+ DEBUG(0, ("push_uss2_allocate() for user returned -1 (probably malloc() failure)\n"));
+ return False;
+ }
+
+ domain_byte_len = push_ucs2_allocate(&domain, domain_in);
+ if (domain_byte_len == (size_t)-1) {
+ DEBUG(0, ("push_uss2_allocate() for domain returned -1 (probably malloc() failure)\n"));
+ return False;
+ }
+
+ strupper_w(user);
+ strupper_w(domain);
+
+ 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;
+
+ hmac_md5_init_limK_to_64(owf, 16, &ctx);
+ hmac_md5_update((const unsigned char *)user, user_byte_len, &ctx);
+ hmac_md5_update((const unsigned char *)domain, domain_byte_len, &ctx);
+ hmac_md5_final(kr_buf, &ctx);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("ntv2_owf_gen: user, domain, owfkey, kr\n"));
+ dump_data(100, (const char *)user, user_byte_len);
+ dump_data(100, (const char *)domain, domain_byte_len);
+ dump_data(100, owf, 16);
+ dump_data(100, kr_buf, 16);
+#endif
+
+ SAFE_FREE(user);
+ SAFE_FREE(domain);
+ return True;
+}
+
+/* Does the des encryption from the NT or LM MD4 hash. */
+void SMBOWFencrypt(const uchar passwd[16], const uchar *c8, uchar p24[24])
+{
+ uchar p21[21];
+
+ ZERO_STRUCT(p21);
+
+ memcpy(p21, passwd, 16);
+ E_P24(p21, c8, p24);
+}
+
+/* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
+void NTLMSSPOWFencrypt(const uchar passwd[8], const uchar *ntlmchalresp, uchar p24[24])
+{
+ uchar p21[21];
+
+ memset(p21,'\0',21);
+ memcpy(p21, passwd, 8);
+ memset(p21 + 8, 0xbd, 8);
+
+ E_P24(p21, ntlmchalresp, p24);
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("NTLMSSPOWFencrypt: p21, c8, p24\n"));
+ dump_data(100, (char *)p21, 21);
+ dump_data(100, (const char *)ntlmchalresp, 8);
+ dump_data(100, (char *)p24, 24);
+#endif
+}
+
+
+/* Does the NT MD4 hash then des encryption. */
+
+void SMBNTencrypt(const char *passwd, uchar *c8, uchar *p24)
+{
+ uchar p21[21];
+
+ memset(p21,'\0',21);
+
+ E_md4hash(passwd, p21);
+ SMBOWFencrypt(p21, c8, p24);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("SMBNTencrypt: nt#, challenge, response\n"));
+ dump_data(100, (char *)p21, 16);
+ dump_data(100, (char *)c8, 8);
+ dump_data(100, (char *)p24, 24);
+#endif
+}
+
+BOOL make_oem_passwd_hash(char data[516], const char *passwd, uchar old_pw_hash[16], BOOL unicode)
+{
+ int new_pw_len = strlen(passwd) * (unicode ? 2 : 1);
+
+ if (new_pw_len > 512)
+ {
+ DEBUG(0,("make_oem_passwd_hash: new password is too long.\n"));
+ return False;
+ }
+
+ /*
+ * Now setup the data area.
+ * We need to generate a random fill
+ * for this area to make it harder to
+ * decrypt. JRA.
+ */
+ generate_random_buffer((unsigned char *)data, 516, False);
+ push_string(NULL, &data[512 - new_pw_len], passwd, new_pw_len,
+ STR_NOALIGN | (unicode?STR_UNICODE:STR_ASCII));
+ SIVAL(data, 512, new_pw_len);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("make_oem_passwd_hash\n"));
+ dump_data(100, data, 516);
+#endif
+ SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, 516);
+
+ return True;
+}
+
+/* Does the md5 encryption from the NT hash for NTLMv2. */
+void SMBOWFencrypt_ntv2(const uchar kr[16],
+ const DATA_BLOB srv_chal,
+ const DATA_BLOB cli_chal,
+ uchar resp_buf[16])
+{
+ HMACMD5Context ctx;
+
+ hmac_md5_init_limK_to_64(kr, 16, &ctx);
+ hmac_md5_update(srv_chal.data, srv_chal.length, &ctx);
+ hmac_md5_update(cli_chal.data, cli_chal.length, &ctx);
+ hmac_md5_final(resp_buf, &ctx);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBOWFencrypt_ntv2: srv_chal, cli_chal, resp_buf\n"));
+ dump_data(100, srv_chal.data, srv_chal.length);
+ dump_data(100, cli_chal.data, cli_chal.length);
+ dump_data(100, resp_buf, 16);
+#endif
+}
+
+void SMBsesskeygen_ntv2(const uchar kr[16],
+ const uchar * nt_resp, uint8 sess_key[16])
+{
+ HMACMD5Context ctx;
+
+ hmac_md5_init_limK_to_64(kr, 16, &ctx);
+ hmac_md5_update(nt_resp, 16, &ctx);
+ hmac_md5_final((unsigned char *)sess_key, &ctx);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBsesskeygen_ntv2:\n"));
+ dump_data(100, sess_key, 16);
+#endif
+}
+
+void SMBsesskeygen_ntv1(const uchar kr[16],
+ const uchar * nt_resp, uint8 sess_key[16])
+{
+ mdfour((unsigned char *)sess_key, kr, 16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBsesskeygen_ntv1:\n"));
+ dump_data(100, sess_key, 16);
+#endif
+}
+
+DATA_BLOB NTLMv2_generate_response(uchar ntlm_v2_hash[16],
+ DATA_BLOB server_chal, size_t client_chal_length)
+{
+ uchar ntlmv2_response[16];
+ DATA_BLOB ntlmv2_client_data;
+ DATA_BLOB final_response;
+
+ /* NTLMv2 */
+
+ /* We also get to specify some random data */
+ ntlmv2_client_data = data_blob(NULL, client_chal_length);
+ generate_random_buffer(ntlmv2_client_data.data, ntlmv2_client_data.length, False);
+
+ /* Given that data, and the challenge from the server, generate a response */
+ SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, ntlmv2_client_data, ntlmv2_response);
+
+ /* put it into nt_response, for the code below to put into the packet */
+ final_response = data_blob(NULL, ntlmv2_client_data.length + sizeof(ntlmv2_response));
+ memcpy(final_response.data, ntlmv2_response, sizeof(ntlmv2_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(ntlmv2_response), ntlmv2_client_data.data, ntlmv2_client_data.length);
+ data_blob_free(&ntlmv2_client_data);
+
+ return final_response;
+}
+
+BOOL SMBNTLMv2encrypt(const char *user, const char *domain, const char *password,
+ const DATA_BLOB server_chal,
+ DATA_BLOB *lm_response, DATA_BLOB *nt_response,
+ DATA_BLOB *session_key)
+{
+ uchar nt_hash[16];
+ uchar ntlm_v2_hash[16];
+ E_md4hash(password, nt_hash);
+
+ /* 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;
+ }
+
+ *nt_response = NTLMv2_generate_response(ntlm_v2_hash, server_chal, 64 /* pick a number, > 8 */);
+
+ /* LMv2 */
+
+ *lm_response = NTLMv2_generate_response(ntlm_v2_hash, server_chal, 8);
+
+ *session_key = data_blob(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 */
+ SMBsesskeygen_ntv2(ntlm_v2_hash, nt_response->data, session_key->data);
+
+ return True;
+}
+
+/***********************************************************
+ encode a password buffer. The caller gets to figure out
+ what to put in it.
+************************************************************/
+BOOL encode_pw_buffer(char buffer[516], char *new_pw, int new_pw_length)
+{
+ generate_random_buffer((unsigned char *)buffer, 516, True);
+
+ memcpy(&buffer[512 - new_pw_length], new_pw, new_pw_length);
+
+ /*
+ * The length of the new password is in the last 4 bytes of
+ * the data buffer.
+ */
+ SIVAL(buffer, 512, new_pw_length);
+
+ 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(char in_buffer[516], char *new_pwrd,
+ int new_pwrd_size, uint32 *new_pw_len)
+{
+ int byte_len=0;
+
+ /*
+ Warning !!! : This function is called from some rpc call.
+ The password IN the buffer is a UNICODE string.
+ The password IN new_pwrd is an ASCII string
+ If you reuse that code somewhere else check first.
+ */
+
+ /* 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 128 characters */
+ if ( (byte_len < 0) || (byte_len > new_pwrd_size - 1)) {
+ DEBUG(0, ("decode_pw_buffer: incorrect password length (%d).\n", byte_len));
+ DEBUG(0, ("decode_pw_buffer: check that 'encrypt passwords = yes'\n"));
+ return False;
+ }
+
+ /* decode into the return buffer. Buffer must be a pstring */
+ *new_pw_len = pull_string(NULL, new_pwrd, &in_buffer[512 - byte_len], new_pwrd_size, byte_len, STR_UNICODE);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("decode_pw_buffer: new_pwrd: "));
+ dump_data(100, (char *)new_pwrd, *new_pw_len);
+ DEBUG(100,("multibyte len:%d\n", *new_pw_len));
+ DEBUG(100,("original char len:%d\n", byte_len/2));
+#endif
+
+ return True;
+}
diff --git a/source4/libcli/util/smberr.c b/source4/libcli/util/smberr.c
new file mode 100644
index 0000000000..d6eabcfbce
--- /dev/null
+++ b/source4/libcli/util/smberr.c
@@ -0,0 +1,181 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) Andrew Tridgell 1998-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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ error code stuff - put together by Merik Karman
+ merik@blackadder.dsh.oz.au
+*/
+
+struct err_code_struct {
+ const char *name;
+ int code;
+ const char *message;
+};
+
+/* Dos Error Messages */
+static const struct err_code_struct dos_msgs[] = {
+ {"ERRbadfunc",ERRbadfunc,"Invalid function."},
+ {"ERRbadfile",ERRbadfile,"File not found."},
+ {"ERRbadpath",ERRbadpath,"Directory invalid."},
+ {"ERRnofids",ERRnofids,"No file descriptors available"},
+ {"ERRnoaccess",ERRnoaccess,"Access denied."},
+ {"ERRbadfid",ERRbadfid,"Invalid file handle."},
+ {"ERRbadmcb",ERRbadmcb,"Memory control blocks destroyed."},
+ {"ERRnomem",ERRnomem,"Insufficient server memory to perform the requested function."},
+ {"ERRbadmem",ERRbadmem,"Invalid memory block address."},
+ {"ERRbadenv",ERRbadenv,"Invalid environment."},
+ {"ERRbadformat",11,"Invalid format."},
+ {"ERRbadaccess",ERRbadaccess,"Invalid open mode."},
+ {"ERRbaddata",ERRbaddata,"Invalid data."},
+ {"ERRres",ERRres,"reserved."},
+ {"ERRbaddrive",ERRbaddrive,"Invalid drive specified."},
+ {"ERRremcd",ERRremcd,"A Delete Directory request attempted to remove the server's current directory."},
+ {"ERRdiffdevice",ERRdiffdevice,"Not same device."},
+ {"ERRnofiles",ERRnofiles,"A File Search command can find no more files matching the specified criteria."},
+ {"ERRbadshare",ERRbadshare,"The sharing mode specified for an Open conflicts with existing FIDs on the file."},
+ {"ERRlock",ERRlock,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."},
+ {"ERRunsup", ERRunsup, "The operation is unsupported"},
+ {"ERRnosuchshare", ERRnosuchshare, "You specified an invalid share name"},
+ {"ERRfilexists",ERRfilexists,"The file named in a Create Directory, Make New File or Link request already exists."},
+ {"ERRinvalidname",ERRinvalidname, "Invalid name"},
+ {"ERRbadpipe",ERRbadpipe,"Pipe invalid."},
+ {"ERRpipebusy",ERRpipebusy,"All instances of the requested pipe are busy."},
+ {"ERRpipeclosing",ERRpipeclosing,"Pipe close in progress."},
+ {"ERRnotconnected",ERRnotconnected,"No process on other end of pipe."},
+ {"ERRmoredata",ERRmoredata,"There is more data to be returned."},
+ {"ERRinvgroup",ERRinvgroup,"Invalid workgroup (try the -W option)"},
+ {"ERRlogonfailure",ERRlogonfailure,"Logon failure"},
+ {"ERRdiskfull",ERRdiskfull,"Disk full"},
+ {"ERRgeneral",ERRgeneral, "General failure"},
+ {"ERRunknownlevel",ERRunknownlevel, "Unknown info level"},
+ {NULL,-1,NULL}};
+
+/* Server Error Messages */
+static const struct err_code_struct server_msgs[] = {
+ {"ERRerror",1,"Non-specific error code."},
+ {"ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."},
+ {"ERRbadtype",3,"reserved."},
+ {"ERRaccess",4,"The requester does not have the necessary access rights within the specified context for the requested function. The context is defined by the TID or the UID."},
+ {"ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."},
+ {"ERRinvnetname",6,"Invalid network name in tree connect."},
+ {"ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or non-printer request made to printer connection."},
+ {"ERRqfull",49,"Print queue full (files) -- returned by open print file."},
+ {"ERRqtoobig",50,"Print queue full -- no space."},
+ {"ERRqeof",51,"EOF on print queue dump."},
+ {"ERRinvpfid",52,"Invalid print file FID."},
+ {"ERRsmbcmd",64,"The server did not recognize the command received."},
+ {"ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."},
+ {"ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid combination of values."},
+ {"ERRreserved",68,"reserved."},
+ {"ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute."},
+ {"ERRreserved",70,"reserved."},
+ {"ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."},
+ {"ERRpaused",81,"Server is paused."},
+ {"ERRmsgoff",82,"Not receiving messages."},
+ {"ERRnoroom",83,"No room to buffer message."},
+ {"ERRrmuns",87,"Too many remote user names."},
+ {"ERRtimeout",88,"Operation timed out."},
+ {"ERRnoresource",89,"No resources currently available for request."},
+ {"ERRtoomanyuids",90,"Too many UIDs active on this session."},
+ {"ERRbaduid",91,"The UID is not known as a valid ID on this session."},
+ {"ERRusempx",250,"Temp unable to support Raw, use MPX mode."},
+ {"ERRusestd",251,"Temp unable to support Raw, use standard read/write."},
+ {"ERRcontmpx",252,"Continue in MPX mode."},
+ {"ERRreserved",253,"reserved."},
+ {"ERRreserved",254,"reserved."},
+ {"ERRnosupport",0xFFFF,"Function not supported."},
+ {NULL,-1,NULL}};
+
+/* Hard Error Messages */
+static const struct err_code_struct hard_msgs[] = {
+ {"ERRnowrite",19,"Attempt to write on write-protected diskette."},
+ {"ERRbadunit",20,"Unknown unit."},
+ {"ERRnotready",21,"Drive not ready."},
+ {"ERRbadcmd",22,"Unknown command."},
+ {"ERRdata",23,"Data error (CRC)."},
+ {"ERRbadreq",24,"Bad request structure length."},
+ {"ERRseek",25 ,"Seek error."},
+ {"ERRbadmedia",26,"Unknown media type."},
+ {"ERRbadsector",27,"Sector not found."},
+ {"ERRnopaper",28,"Printer out of paper."},
+ {"ERRwrite",29,"Write fault."},
+ {"ERRread",30,"Read fault."},
+ {"ERRgeneral",31,"General failure."},
+ {"ERRbadshare",32,"An open conflicts with an existing open."},
+ {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."},
+ {"ERRwrongdisk",34,"The wrong disk was found in a drive."},
+ {"ERRFCBUnavail",35,"No FCBs are available to process request."},
+ {"ERRsharebufexc",36,"A sharing buffer has been exceeded."},
+ {NULL,-1,NULL}};
+
+
+static const struct {
+ uint8 class;
+ const char *class_name;
+ const struct err_code_struct *err_msgs;
+} err_classes[] = {
+ {0,"SUCCESS",NULL},
+ {0x01,"ERRDOS",dos_msgs},
+ {0x02,"ERRSRV",server_msgs},
+ {0x03,"ERRHRD",hard_msgs},
+ {0x04,"ERRXOS",NULL},
+ {0xE1,"ERRRMX1",NULL},
+ {0xE2,"ERRRMX2",NULL},
+ {0xE3,"ERRRMX3",NULL},
+ {0xFF,"ERRCMD",NULL},
+ {-1,NULL,NULL}};
+
+
+/* return a dos error string given a error class and error code */
+const char *dos_errstr(uint8 class, uint16 code)
+{
+ static char *msg;
+ int i, j;
+ const struct err_code_struct *err_msgs;
+
+ if (msg) {
+ free(msg);
+ msg = NULL;
+ }
+
+ for (i=0;err_classes[i].class_name;i++) {
+ if (class == err_classes[i].class) break;
+ }
+ if (!err_classes[i].class_name) {
+ asprintf(&msg, "Unknown DOS error %d:%d\n", class, code);
+ return msg;
+ }
+
+ err_msgs = err_classes[i].err_msgs;
+
+ for (j=0;err_msgs && err_msgs[j].name;j++) {
+ if (err_msgs[j].code == code) {
+ asprintf(&msg, "%s:%s (%s)\n",
+ err_classes[i].class_name,
+ err_msgs[j].name,
+ err_msgs[j].message);
+ return msg;
+ }
+ }
+
+ asprintf(&msg, "Unknown DOS error %s:%d\n", err_classes[i].class_name, code);
+ return msg;
+}