summaryrefslogtreecommitdiff
path: root/source3/libsmb
diff options
context:
space:
mode:
Diffstat (limited to 'source3/libsmb')
-rw-r--r--source3/libsmb/.cvsignore3
-rw-r--r--source3/libsmb/asn1.c408
-rw-r--r--source3/libsmb/cli_dfs.c253
-rw-r--r--source3/libsmb/cli_lsarpc.c1167
-rw-r--r--source3/libsmb/cli_netlogon.c673
-rw-r--r--source3/libsmb/cli_pipe_util.c82
-rw-r--r--source3/libsmb/cli_reg.c111
-rw-r--r--source3/libsmb/cli_samr.c1274
-rw-r--r--source3/libsmb/cli_spoolss.c1590
-rw-r--r--source3/libsmb/cli_srvsvc.c79
-rw-r--r--source3/libsmb/cli_wkssvc.c112
-rw-r--r--source3/libsmb/cliconnect.c1348
-rw-r--r--source3/libsmb/clidgram.c267
-rw-r--r--source3/libsmb/clientgen.c280
-rw-r--r--source3/libsmb/clierror.c281
-rw-r--r--source3/libsmb/clifile.c1051
-rw-r--r--source3/libsmb/clikrb5.c145
-rw-r--r--source3/libsmb/clilist.c464
-rw-r--r--source3/libsmb/climessage.c120
-rw-r--r--source3/libsmb/clioplock.c68
-rw-r--r--source3/libsmb/cliprint.c157
-rw-r--r--source3/libsmb/clirap.c738
-rw-r--r--source3/libsmb/clirap2.c1961
-rw-r--r--source3/libsmb/clireadwrite.c374
-rw-r--r--source3/libsmb/clisecdesc.c131
-rw-r--r--source3/libsmb/clispnego.c622
-rw-r--r--source3/libsmb/clistr.c43
-rw-r--r--source3/libsmb/clitrans.c468
-rw-r--r--source3/libsmb/credentials.c215
-rw-r--r--source3/libsmb/doserr.c89
-rw-r--r--source3/libsmb/errormap.c1483
-rw-r--r--source3/libsmb/libsmbclient.c2581
-rw-r--r--source3/libsmb/namequery.c1330
-rw-r--r--source3/libsmb/netlogon_unigrp.c157
-rw-r--r--source3/libsmb/nmblib.c1187
-rw-r--r--source3/libsmb/nterr.c596
-rw-r--r--source3/libsmb/passchange.c101
-rw-r--r--source3/libsmb/pwd_cache.c249
-rw-r--r--source3/libsmb/smbdes.c415
-rw-r--r--source3/libsmb/smbencrypt.c423
-rw-r--r--source3/libsmb/smberr.c255
-rw-r--r--source3/libsmb/trust_passwd.c115
-rw-r--r--source3/libsmb/unexpected.c164
43 files changed, 23062 insertions, 568 deletions
diff --git a/source3/libsmb/.cvsignore b/source3/libsmb/.cvsignore
new file mode 100644
index 0000000000..07da2225c7
--- /dev/null
+++ b/source3/libsmb/.cvsignore
@@ -0,0 +1,3 @@
+*.po
+*.po32
+
diff --git a/source3/libsmb/asn1.c b/source3/libsmb/asn1.c
new file mode 100644
index 0000000000..b4ad3ad0b8
--- /dev/null
+++ b/source3/libsmb/asn1.c
@@ -0,0 +1,408 @@
+/*
+ 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;
+}
+
+/* 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;
+
+ asn1_read_uint8(data, &b);
+ if (b != tag) {
+ data->has_error = True;
+ return False;
+ }
+ nesting = (struct nesting *)malloc(sizeof(struct nesting));
+ if (!nesting) {
+ data->has_error = True;
+ return False;
+ }
+
+ asn1_read_uint8(data, &b);
+ if (b & 0x80) {
+ int n = b & 0x7f;
+ if (n > 2) {
+ data->has_error = True;
+ return False;
+ }
+ asn1_read_uint8(data, &b);
+ nesting->taglen = b;
+ if (n == 2) {
+ asn1_read_uint8(data, &b);
+ nesting->taglen = (nesting->taglen << 8) | b;
+ }
+ } 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, 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;
+ 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) {
+ *i = (*i << 8) + asn1_read_uint8(data, &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);
+ return !data->has_error && (v == b);
+}
+
+/* check a enumarted value is correct */
+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/source3/libsmb/cli_dfs.c b/source3/libsmb/cli_dfs.c
new file mode 100644
index 0000000000..312275926c
--- /dev/null
+++ b/source3/libsmb/cli_dfs.c
@@ -0,0 +1,253 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+ Copyright (C) Tim Potter 2000-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"
+
+/* Opens a SMB connection to the netdfs pipe */
+
+struct cli_state *cli_dfs_initialise(struct cli_state *cli, char *system_name,
+ struct ntuser_creds *creds)
+{
+ return cli_pipe_initialise(cli, system_name, PIPE_NETDFS, creds);
+}
+
+/* Query DFS support */
+
+NTSTATUS cli_dfs_exist(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ BOOL *dfs_exists)
+{
+ prs_struct qbuf, rbuf;
+ DFS_Q_DFS_EXIST q;
+ DFS_R_DFS_EXIST r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_dfs_q_dfs_exist(&q);
+
+ if (!dfs_io_q_dfs_exist("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, DFS_EXIST, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!dfs_io_r_dfs_exist("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return result */
+
+ *dfs_exists = (r.status != 0);
+
+ result = NT_STATUS_OK;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+NTSTATUS cli_dfs_add(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ char *entrypath, char *servername, char *sharename,
+ char *comment, uint32 flags)
+{
+ prs_struct qbuf, rbuf;
+ DFS_Q_DFS_ADD q;
+ DFS_R_DFS_ADD r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_dfs_q_dfs_add(&q, entrypath, servername, sharename, comment,
+ flags);
+
+ if (!dfs_io_q_dfs_add("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, DFS_ADD, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!dfs_io_r_dfs_add("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return result */
+
+ result = werror_to_ntstatus(r.status);
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+NTSTATUS cli_dfs_remove(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ char *entrypath, char *servername, char *sharename)
+{
+ prs_struct qbuf, rbuf;
+ DFS_Q_DFS_REMOVE q;
+ DFS_R_DFS_REMOVE r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_dfs_q_dfs_remove(&q, entrypath, servername, sharename);
+
+ if (!dfs_io_q_dfs_remove("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, DFS_REMOVE, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!dfs_io_r_dfs_remove("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return result */
+
+ result = werror_to_ntstatus(r.status);
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+NTSTATUS cli_dfs_get_info(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ char *entrypath, char *servername, char *sharename,
+ uint32 info_level, DFS_INFO_CTR *ctr)
+
+{
+ prs_struct qbuf, rbuf;
+ DFS_Q_DFS_GET_INFO q;
+ DFS_R_DFS_GET_INFO r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_dfs_q_dfs_get_info(&q, entrypath, servername, sharename,
+ info_level);
+
+ if (!dfs_io_q_dfs_get_info("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, DFS_GET_INFO, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!dfs_io_r_dfs_get_info("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return result */
+
+ result = werror_to_ntstatus(r.status);
+ *ctr = r.ctr;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Enumerate dfs shares */
+
+NTSTATUS cli_dfs_enum(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ uint32 info_level, DFS_INFO_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ DFS_Q_DFS_ENUM q;
+ DFS_R_DFS_ENUM r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_dfs_q_dfs_enum(&q, info_level, ctr);
+
+ if (!dfs_io_q_dfs_enum("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, DFS_ENUM, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ r.ctr = ctr;
+
+ if (!dfs_io_r_dfs_enum("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return result */
+
+ result = werror_to_ntstatus(r.status);
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
diff --git a/source3/libsmb/cli_lsarpc.c b/source3/libsmb/cli_lsarpc.c
new file mode 100644
index 0000000000..3216854608
--- /dev/null
+++ b/source3/libsmb/cli_lsarpc.c
@@ -0,0 +1,1167 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+ Copyright (C) Tim Potter 2000-2001,
+ Copyright (C) Andrew Tridgell 1992-1997,2000,
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997,2000,
+ Copyright (C) Paul Ashton 1997,2000,
+ Copyright (C) Elrond 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"
+
+/** @defgroup lsa LSA - Local Security Architecture
+ * @ingroup rpc_client
+ *
+ * @{
+ **/
+
+/**
+ * @file cli_lsarpc.c
+ *
+ * RPC client routines for the LSA RPC pipe. LSA means "local
+ * security authority", which is half of a password database.
+ **/
+
+/** Opens a SMB connection and connects to the LSARPC pipe.
+ *
+ * @param cli Uninitialised client handle.
+ * @param system_name NETBIOS name of the machine to connect to.
+ * @param creds User credentials to connect as.
+ * @returns Initialised client handle.
+ */
+struct cli_state *cli_lsa_initialise(struct cli_state *cli, char *system_name,
+ struct ntuser_creds *creds)
+{
+ return cli_pipe_initialise(cli, system_name, PIPE_LSARPC, creds);
+}
+
+/** Open a LSA policy handle
+ *
+ * @param cli Handle on an initialised SMB connection */
+
+NTSTATUS cli_lsa_open_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ BOOL sec_qos, uint32 des_access, POLICY_HND *pol)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_OPEN_POL q;
+ LSA_R_OPEN_POL r;
+ LSA_SEC_QOS qos;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ if (sec_qos) {
+ init_lsa_sec_qos(&qos, 2, 1, 0);
+ init_q_open_pol(&q, '\\', 0, des_access, &qos);
+ } else {
+ init_q_open_pol(&q, '\\', 0, des_access, NULL);
+ }
+
+ /* Marshall data and send request */
+
+ if (!lsa_io_q_open_pol("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_OPENPOLICY, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_open_pol("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *pol = r.pol;
+#ifdef __INSURE__
+ pol->marker = malloc(1);
+#endif
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Open a LSA policy handle
+ *
+ * @param cli Handle on an initialised SMB connection
+ */
+
+NTSTATUS cli_lsa_open_policy2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ BOOL sec_qos, uint32 des_access, POLICY_HND *pol)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_OPEN_POL2 q;
+ LSA_R_OPEN_POL2 r;
+ LSA_SEC_QOS qos;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ if (sec_qos) {
+ init_lsa_sec_qos(&qos, 2, 1, 0);
+ init_q_open_pol2(&q, cli->srv_name_slash, 0, des_access,
+ &qos);
+ } else {
+ init_q_open_pol2(&q, cli->srv_name_slash, 0, des_access,
+ NULL);
+ }
+
+ /* Marshall data and send request */
+
+ if (!lsa_io_q_open_pol2("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_OPENPOLICY2, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_open_pol2("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *pol = r.pol;
+#ifdef __INSURE__
+ pol->marker = (char *)malloc(1);
+#endif
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Close a LSA policy handle */
+
+NTSTATUS cli_lsa_close(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_CLOSE q;
+ LSA_R_CLOSE r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_lsa_q_close(&q, pol);
+
+ if (!lsa_io_q_close("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_CLOSE, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_close("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+#ifdef __INSURE__
+ SAFE_FREE(pol->marker);
+#endif
+ *pol = r.pol;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Lookup a list of sids */
+
+NTSTATUS cli_lsa_lookup_sids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, int num_sids, DOM_SID *sids,
+ char ***domains, char ***names, uint32 **types, int *num_names)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_LOOKUP_SIDS q;
+ LSA_R_LOOKUP_SIDS r;
+ DOM_R_REF ref;
+ LSA_TRANS_NAME_ENUM t_names;
+ NTSTATUS result;
+ int i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_q_lookup_sids(mem_ctx, &q, pol, num_sids, sids, 1);
+
+ if (!lsa_io_q_lookup_sids("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_LOOKUPSIDS, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ ZERO_STRUCT(ref);
+ ZERO_STRUCT(t_names);
+
+ r.dom_ref = &ref;
+ r.names = &t_names;
+
+ if (!lsa_io_r_lookup_sids("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ result = r.status;
+
+ if (!NT_STATUS_IS_OK(result) &&
+ NT_STATUS_V(result) != NT_STATUS_V(NT_STATUS_FILES_OPEN)) {
+ /* An actual error occured */
+
+ goto done;
+ }
+
+
+ /* Return output parameters */
+
+ if (r.mapped_count == 0) {
+ result = NT_STATUS_NONE_MAPPED;
+ goto done;
+ }
+
+ (*num_names) = r.mapped_count;
+ result = NT_STATUS_OK;
+
+ if (!((*domains) = (char **)talloc(mem_ctx, sizeof(char *) * r.mapped_count))) {
+ DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!((*names) = (char **)talloc(mem_ctx, sizeof(char *) * r.mapped_count))) {
+ DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!((*types) = (uint32 *)talloc(mem_ctx, sizeof(uint32) * r.mapped_count))) {
+ DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ for (i = 0; i < r.mapped_count; i++) {
+ fstring name, dom_name;
+ uint32 dom_idx = t_names.name[i].domain_idx;
+
+ /* Translate optimised name through domain index array */
+
+ if (dom_idx != 0xffffffff) {
+
+ rpcstr_pull_unistr2_fstring(
+ dom_name, &ref.ref_dom[dom_idx].uni_dom_name);
+ rpcstr_pull_unistr2_fstring(
+ name, &t_names.uni_name[i]);
+
+ (*names)[i] = talloc_strdup(mem_ctx, name);
+ (*domains)[i] = talloc_strdup(mem_ctx, dom_name);
+ (*types)[i] = t_names.name[i].sid_name_use;
+
+ if (((*names)[i] == NULL) || ((*domains)[i] == NULL)) {
+ DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ } else {
+ (*names)[i] = NULL;
+ (*types)[i] = SID_NAME_UNKNOWN;
+ }
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Lookup a list of names */
+
+NTSTATUS cli_lsa_lookup_names(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, int num_names, const char **names,
+ DOM_SID **sids, uint32 **types, int *num_sids)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_LOOKUP_NAMES q;
+ LSA_R_LOOKUP_NAMES r;
+ DOM_R_REF ref;
+ NTSTATUS result;
+ int i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_q_lookup_names(mem_ctx, &q, pol, num_names, names);
+
+ if (!lsa_io_q_lookup_names("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_LOOKUPNAMES, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ ZERO_STRUCT(ref);
+ r.dom_ref = &ref;
+
+ if (!lsa_io_r_lookup_names("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ result = r.status;
+
+ if (!NT_STATUS_IS_OK(result)) {
+ /* An actual error occured */
+
+ goto done;
+ }
+
+
+ /* Return output parameters */
+
+ if (r.mapped_count == 0) {
+ result = NT_STATUS_NONE_MAPPED;
+ goto done;
+ }
+
+ (*num_sids) = r.mapped_count;
+ result = NT_STATUS_OK;
+
+ if (!((*sids = (DOM_SID *)talloc(mem_ctx, sizeof(DOM_SID) * r.mapped_count)))) {
+ DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!((*types = (uint32 *)talloc(mem_ctx, sizeof(uint32) * r.mapped_count)))) {
+ DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ for (i = 0; i < r.mapped_count; i++) {
+ DOM_RID2 *t_rids = r.dom_rid;
+ uint32 dom_idx = t_rids[i].rid_idx;
+ uint32 dom_rid = t_rids[i].rid;
+ DOM_SID *sid = &(*sids)[i];
+
+ /* Translate optimised sid through domain index array */
+
+ if (dom_idx != 0xffffffff) {
+
+ sid_copy(sid, &ref.ref_dom[dom_idx].ref_dom.sid);
+
+ if (dom_rid != 0xffffffff) {
+ sid_append_rid(sid, dom_rid);
+ }
+
+ (*types)[i] = t_rids[i].type;
+ } else {
+ ZERO_STRUCTP(sid);
+ (*types)[i] = SID_NAME_UNKNOWN;
+ }
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Query info policy
+ *
+ * @param domain_sid - returned remote server's domain sid */
+
+NTSTATUS cli_lsa_query_info_policy(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint16 info_class,
+ fstring domain_name, DOM_SID *domain_sid)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_QUERY_INFO q;
+ LSA_R_QUERY_INFO r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_q_query(&q, pol, info_class);
+
+ if (!lsa_io_q_query("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_QUERYINFOPOLICY, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_query("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ ZERO_STRUCTP(domain_sid);
+ domain_name[0] = '\0';
+
+ switch (info_class) {
+
+ case 3:
+ if (r.dom.id3.buffer_dom_name != 0) {
+ unistr2_to_ascii(domain_name,
+ &r.dom.id3.
+ uni_domain_name,
+ sizeof (fstring) - 1);
+ }
+
+ if (r.dom.id3.buffer_dom_sid != 0) {
+ *domain_sid = r.dom.id3.dom_sid.sid;
+ }
+
+ break;
+
+ case 5:
+
+ if (r.dom.id5.buffer_dom_name != 0) {
+ unistr2_to_ascii(domain_name, &r.dom.id5.
+ uni_domain_name,
+ sizeof (fstring) - 1);
+ }
+
+ if (r.dom.id5.buffer_dom_sid != 0) {
+ *domain_sid = r.dom.id5.dom_sid.sid;
+ }
+
+ break;
+
+ default:
+ DEBUG(3, ("unknown info class %d\n", info_class));
+ break;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Enumerate list of trusted domains */
+
+NTSTATUS cli_lsa_enum_trust_dom(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 *enum_ctx,
+ uint32 *num_domains, char ***domain_names,
+ DOM_SID **domain_sids)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_ENUM_TRUST_DOM q;
+ LSA_R_ENUM_TRUST_DOM r;
+ NTSTATUS result;
+ int i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_q_enum_trust_dom(&q, pol, *enum_ctx, 0xffffffff);
+
+ if (!lsa_io_q_enum_trust_dom("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_ENUMTRUSTDOM, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_enum_trust_dom("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ result = r.status;
+
+ if (!NT_STATUS_IS_OK(result) &&
+ NT_STATUS_V(result) != NT_STATUS_V(NT_STATUS_NO_MORE_ENTRIES)) {
+
+ /* An actual error ocured */
+
+ goto done;
+ }
+
+ result = NT_STATUS_OK;
+
+ /* Return output parameters */
+
+ if (r.num_domains) {
+
+ /* Allocate memory for trusted domain names and sids */
+
+ *domain_names = (char **)talloc(mem_ctx, sizeof(char *) *
+ r.num_domains);
+
+ if (!*domain_names) {
+ DEBUG(0, ("cli_lsa_enum_trust_dom(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ *domain_sids = (DOM_SID *)talloc(mem_ctx, sizeof(DOM_SID) *
+ r.num_domains);
+ if (!domain_sids) {
+ DEBUG(0, ("cli_lsa_enum_trust_dom(): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Copy across names and sids */
+
+ for (i = 0; i < r.num_domains; i++) {
+ fstring tmp;
+
+ unistr2_to_ascii(tmp, &r.uni_domain_name[i],
+ sizeof(tmp) - 1);
+ (*domain_names)[i] = talloc_strdup(mem_ctx, tmp);
+ sid_copy(&(*domain_sids)[i], &r.domain_sid[i].sid);
+ }
+ }
+
+ *num_domains = r.num_domains;
+ *enum_ctx = r.enum_context;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Enumerate privileges*/
+
+NTSTATUS cli_lsa_enum_privilege(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 *enum_context, uint32 pref_max_length,
+ uint32 *count, char ***privs_name, uint32 **privs_high, uint32 **privs_low)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_ENUM_PRIVS q;
+ LSA_R_ENUM_PRIVS r;
+ NTSTATUS result;
+ int i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_q_enum_privs(&q, pol, *enum_context, pref_max_length);
+
+ if (!lsa_io_q_enum_privs("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_ENUM_PRIVS, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_enum_privs("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ *enum_context = r.enum_context;
+ *count = r.count;
+
+ if (!((*privs_name = (char **)talloc(mem_ctx, sizeof(char *) * r.count)))) {
+ DEBUG(0, ("(cli_lsa_enum_privilege): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!((*privs_high = (uint32 *)talloc(mem_ctx, sizeof(uint32) * r.count)))) {
+ DEBUG(0, ("(cli_lsa_enum_privilege): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!((*privs_low = (uint32 *)talloc(mem_ctx, sizeof(uint32) * r.count)))) {
+ DEBUG(0, ("(cli_lsa_enum_privilege): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ for (i = 0; i < r.count; i++) {
+ fstring name;
+
+ rpcstr_pull_unistr2_fstring( name, &r.privs[i].name);
+
+ (*privs_name)[i] = talloc_strdup(mem_ctx, name);
+
+ (*privs_high)[i] = r.privs[i].luid_high;
+ (*privs_low)[i] = r.privs[i].luid_low;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Get privilege name */
+
+NTSTATUS cli_lsa_get_dispname(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, char *name, uint16 lang_id, uint16 lang_id_sys,
+ fstring description, uint16 *lang_id_desc)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_PRIV_GET_DISPNAME q;
+ LSA_R_PRIV_GET_DISPNAME r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_lsa_priv_get_dispname(&q, pol, name, lang_id, lang_id_sys);
+
+ if (!lsa_io_q_priv_get_dispname("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_PRIV_GET_DISPNAME, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_priv_get_dispname("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ rpcstr_pull_unistr2_fstring(description , &r.desc);
+ *lang_id_desc = r.lang_id;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Enumerate list of SIDs */
+
+NTSTATUS cli_lsa_enum_sids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 *enum_ctx, uint32 pref_max_length,
+ uint32 *num_sids, DOM_SID **sids)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_ENUM_ACCOUNTS q;
+ LSA_R_ENUM_ACCOUNTS r;
+ NTSTATUS result;
+ int i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_lsa_q_enum_accounts(&q, pol, *enum_ctx, pref_max_length);
+
+ if (!lsa_io_q_enum_accounts("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_ENUM_ACCOUNTS, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_enum_accounts("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ result = r.status;
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ if (r.sids.num_entries==0)
+ goto done;
+
+ /* Return output parameters */
+
+ *sids = (DOM_SID *)talloc(mem_ctx, sizeof(DOM_SID) * r.sids.num_entries);
+ if (!*sids) {
+ DEBUG(0, ("(cli_lsa_enum_sids): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Copy across names and sids */
+
+ for (i = 0; i < r.sids.num_entries; i++) {
+ sid_copy(&(*sids)[i], &r.sids.sid[i].sid);
+ }
+
+ *num_sids= r.sids.num_entries;
+ *enum_ctx = r.enum_context;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Open a LSA user handle
+ *
+ * @param cli Handle on an initialised SMB connection */
+
+NTSTATUS cli_lsa_open_account(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *dom_pol, DOM_SID *sid, uint32 des_access,
+ POLICY_HND *user_pol)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_OPENACCOUNT q;
+ LSA_R_OPENACCOUNT r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ init_lsa_q_open_account(&q, dom_pol, sid, des_access);
+
+ /* Marshall data and send request */
+
+ if (!lsa_io_q_open_account("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_OPENACCOUNT, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_open_account("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *user_pol = r.pol;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Enumerate user privileges
+ *
+ * @param cli Handle on an initialised SMB connection */
+
+NTSTATUS cli_lsa_enum_privsaccount(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 *count, LUID_ATTR **set)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_ENUMPRIVSACCOUNT q;
+ LSA_R_ENUMPRIVSACCOUNT r;
+ NTSTATUS result;
+ int i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ init_lsa_q_enum_privsaccount(&q, pol);
+
+ /* Marshall data and send request */
+
+ if (!lsa_io_q_enum_privsaccount("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_ENUMPRIVSACCOUNT, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_enum_privsaccount("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ if (r.count == 0)
+ goto done;
+
+ if (!((*set = (LUID_ATTR *)talloc(mem_ctx, sizeof(LUID_ATTR) * r.count)))) {
+ DEBUG(0, ("(cli_lsa_enum_privsaccount): out of memory\n"));
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ for (i=0; i<r.count; i++) {
+ (*set)[i].luid.low = r.set.set[i].luid.low;
+ (*set)[i].luid.high = r.set.set[i].luid.high;
+ (*set)[i].attr = r.set.set[i].attr;
+ }
+
+ *count=r.count;
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Get a privilege value given its name */
+
+NTSTATUS cli_lsa_lookupprivvalue(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, char *name, LUID *luid)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_LOOKUPPRIVVALUE q;
+ LSA_R_LOOKUPPRIVVALUE r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_lsa_q_lookupprivvalue(&q, pol, name);
+
+ if (!lsa_io_q_lookupprivvalue("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_LOOKUPPRIVVALUE, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_lookupprivvalue("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ (*luid).low=r.luid.low;
+ (*luid).high=r.luid.high;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Query LSA security object */
+
+NTSTATUS cli_lsa_query_secobj(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 sec_info,
+ SEC_DESC_BUF **psdb)
+{
+ prs_struct qbuf, rbuf;
+ LSA_Q_QUERY_SEC_OBJ q;
+ LSA_R_QUERY_SEC_OBJ r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_q_query_sec_obj(&q, pol, sec_info);
+
+ if (!lsa_io_q_query_sec_obj("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, LSA_QUERYSECOBJ, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!lsa_io_r_query_sec_obj("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (psdb)
+ *psdb = r.buf;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+#if 0
+
+/** An example of how to use the routines in this file. Fetch a DOMAIN
+ sid. Does complete cli setup / teardown anonymously. */
+
+BOOL fetch_domain_sid( char *domain, char *remote_machine, DOM_SID *psid)
+{
+ extern pstring global_myname;
+ struct cli_state cli;
+ NTSTATUS result;
+ POLICY_HND lsa_pol;
+ BOOL ret = False;
+
+ ZERO_STRUCT(cli);
+ if(cli_initialise(&cli) == False) {
+ DEBUG(0,("fetch_domain_sid: unable to initialize client connection.\n"));
+ return False;
+ }
+
+ if(!resolve_name( remote_machine, &cli.dest_ip, 0x20)) {
+ DEBUG(0,("fetch_domain_sid: Can't resolve address for %s\n", remote_machine));
+ goto done;
+ }
+
+ if (!cli_connect(&cli, remote_machine, &cli.dest_ip)) {
+ DEBUG(0,("fetch_domain_sid: unable to connect to SMB server on \
+machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
+ goto done;
+ }
+
+ if (!attempt_netbios_session_request(&cli, global_myname, remote_machine, &cli.dest_ip)) {
+ DEBUG(0,("fetch_domain_sid: machine %s rejected the NetBIOS session request.\n",
+ remote_machine));
+ goto done;
+ }
+
+ cli.protocol = PROTOCOL_NT1;
+
+ if (!cli_negprot(&cli)) {
+ DEBUG(0,("fetch_domain_sid: machine %s rejected the negotiate protocol. \
+Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
+ goto done;
+ }
+
+ if (cli.protocol != PROTOCOL_NT1) {
+ DEBUG(0,("fetch_domain_sid: machine %s didn't negotiate NT protocol.\n",
+ remote_machine));
+ goto done;
+ }
+
+ /*
+ * Do an anonymous session setup.
+ */
+
+ if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) {
+ DEBUG(0,("fetch_domain_sid: machine %s rejected the session setup. \
+Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
+ goto done;
+ }
+
+ if (!(cli.sec_mode & 1)) {
+ DEBUG(0,("fetch_domain_sid: machine %s isn't in user level security mode\n",
+ remote_machine));
+ goto done;
+ }
+
+ if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
+ DEBUG(0,("fetch_domain_sid: machine %s rejected the tconX on the IPC$ share. \
+Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
+ goto done;
+ }
+
+ /* Fetch domain sid */
+
+ if (!cli_nt_session_open(&cli, PIPE_LSARPC)) {
+ DEBUG(0, ("fetch_domain_sid: Error connecting to SAM pipe\n"));
+ goto done;
+ }
+
+ result = cli_lsa_open_policy(&cli, cli.mem_ctx, True, SEC_RIGHTS_QUERY_VALUE, &lsa_pol);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0, ("fetch_domain_sid: Error opening lsa policy handle. %s\n",
+ nt_errstr(result) ));
+ goto done;
+ }
+
+ result = cli_lsa_query_info_policy(&cli, cli.mem_ctx, &lsa_pol, 5, domain, psid);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0, ("fetch_domain_sid: Error querying lsa policy handle. %s\n",
+ nt_errstr(result) ));
+ goto done;
+ }
+
+ ret = True;
+
+ done:
+
+ cli_shutdown(&cli);
+ return ret;
+}
+
+#endif
+
+/** @} **/
diff --git a/source3/libsmb/cli_netlogon.c b/source3/libsmb/cli_netlogon.c
new file mode 100644
index 0000000000..125590b6d3
--- /dev/null
+++ b/source3/libsmb/cli_netlogon.c
@@ -0,0 +1,673 @@
+/*
+ Unix SMB/CIFS implementation.
+ NT Domain Authentication SMB / MSRPC client
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Tim Potter 2001
+ Copyright (C) Paul Ashton 1997.
+ Copyright (C) Jeremy Allison 1998.
+ Copyright (C) Andrew Bartlett 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"
+
+/* Opens a SMB connection to the netlogon pipe */
+
+struct cli_state *cli_netlogon_initialise(struct cli_state *cli,
+ char *system_name,
+ struct ntuser_creds *creds)
+{
+ return cli_pipe_initialise(cli, system_name, PIPE_NETLOGON, creds);
+}
+
+/* LSA Request Challenge. Sends our challenge to server, then gets
+ server response. These are used to generate the credentials. */
+
+NTSTATUS new_cli_net_req_chal(struct cli_state *cli, DOM_CHAL *clnt_chal,
+ DOM_CHAL *srv_chal)
+{
+ prs_struct qbuf, rbuf;
+ NET_Q_REQ_CHAL q;
+ NET_R_REQ_CHAL r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ extern pstring global_myname;
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api NET_REQCHAL */
+
+ DEBUG(4,("cli_net_req_chal: LSA Request Challenge from %s to %s: %s\n",
+ cli->desthost, global_myname, credstr(clnt_chal->data)));
+
+ /* store the parameters */
+ init_q_req_chal(&q, cli->srv_name_slash, global_myname, clnt_chal);
+
+ /* Marshall data and send request */
+
+ if (!net_io_q_req_chal("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, NET_REQCHAL, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarhall response */
+
+ if (!net_io_r_req_chal("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ result = r.status;
+
+ /* Return result */
+
+ if (NT_STATUS_IS_OK(result)) {
+ memcpy(srv_chal, r.srv_chal.data, sizeof(srv_chal->data));
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/****************************************************************************
+LSA Authenticate 2
+
+Send the client credential, receive back a server credential.
+Ensure that the server credential returned matches the session key
+encrypt of the server challenge originally received. JRA.
+****************************************************************************/
+
+NTSTATUS new_cli_net_auth2(struct cli_state *cli,
+ uint16 sec_chan,
+ uint32 neg_flags, DOM_CHAL *srv_chal)
+{
+ prs_struct qbuf, rbuf;
+ NET_Q_AUTH_2 q;
+ NET_R_AUTH_2 r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ extern pstring global_myname;
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api NET_AUTH2 */
+
+ DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s chal %s neg: %x\n",
+ cli->srv_name_slash, cli->mach_acct, sec_chan, global_myname,
+ credstr(cli->clnt_cred.challenge.data), neg_flags));
+
+ /* store the parameters */
+ init_q_auth_2(&q, cli->srv_name_slash, cli->mach_acct,
+ sec_chan, global_myname, &cli->clnt_cred.challenge,
+ neg_flags);
+
+ /* turn parameters into data stream */
+
+ if (!net_io_q_auth_2("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, NET_AUTH2, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!net_io_r_auth_2("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ result = r.status;
+
+ if (NT_STATUS_IS_OK(result)) {
+ UTIME zerotime;
+
+ /*
+ * Check the returned value using the initial
+ * server received challenge.
+ */
+
+ zerotime.time = 0;
+ if (cred_assert( &r.srv_chal, cli->sess_key, srv_chal,
+ zerotime) == 0) {
+
+ /*
+ * Server replied with bad credential. Fail.
+ */
+ DEBUG(0,("cli_net_auth2: server %s replied with bad credential (bad machine \
+password ?).\n", cli->desthost ));
+ result = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Initialize domain session credentials */
+
+NTSTATUS new_cli_nt_setup_creds(struct cli_state *cli,
+ uint16 sec_chan,
+ const unsigned char mach_pwd[16])
+{
+ DOM_CHAL clnt_chal;
+ DOM_CHAL srv_chal;
+ UTIME zerotime;
+ NTSTATUS result;
+
+ /******************* Request Challenge ********************/
+
+ generate_random_buffer(clnt_chal.data, 8, False);
+
+ /* send a client challenge; receive a server challenge */
+ result = new_cli_net_req_chal(cli, &clnt_chal, &srv_chal);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0,("cli_nt_setup_creds: request challenge failed\n"));
+ return result;
+ }
+
+ /**************** Long-term Session key **************/
+
+ /* calculate the session key */
+ cred_session_key(&clnt_chal, &srv_chal, mach_pwd,
+ cli->sess_key);
+ memset((char *)cli->sess_key+8, '\0', 8);
+
+ /******************* Authenticate 2 ********************/
+
+ /* calculate auth-2 credentials */
+ zerotime.time = 0;
+ cred_create(cli->sess_key, &clnt_chal, zerotime,
+ &cli->clnt_cred.challenge);
+
+ /*
+ * Send client auth-2 challenge.
+ * Receive an auth-2 challenge response and check it.
+ */
+
+ result = new_cli_net_auth2(cli, sec_chan, 0x000001ff,
+ &srv_chal);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0,("cli_nt_setup_creds: auth2 challenge failed %s\n",
+ nt_errstr(result)));
+ }
+
+ return result;
+}
+
+/* Logon Control 2 */
+
+NTSTATUS cli_netlogon_logon_ctrl2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ uint32 query_level)
+{
+ prs_struct qbuf, rbuf;
+ NET_Q_LOGON_CTRL2 q;
+ NET_R_LOGON_CTRL2 r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ init_net_q_logon_ctrl2(&q, cli->srv_name_slash, query_level);
+
+ /* Marshall data and send request */
+
+ if (!net_io_q_logon_ctrl2("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, NET_LOGON_CTRL2, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!net_io_r_logon_ctrl2("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ result = r.status;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/****************************************************************************
+Generate the next creds to use. Yuck - this is a cut&paste from another
+file. They should be combined at some stage. )-:
+****************************************************************************/
+
+static void gen_next_creds( struct cli_state *cli, DOM_CRED *new_clnt_cred)
+{
+ /*
+ * Create the new client credentials.
+ */
+
+ cli->clnt_cred.timestamp.time = time(NULL);
+
+ memcpy(new_clnt_cred, &cli->clnt_cred, sizeof(*new_clnt_cred));
+
+ /* Calculate the new credentials. */
+ cred_create(cli->sess_key, &(cli->clnt_cred.challenge),
+ new_clnt_cred->timestamp, &(new_clnt_cred->challenge));
+
+}
+
+/* Sam synchronisation */
+
+NTSTATUS cli_netlogon_sam_sync(struct cli_state *cli, TALLOC_CTX *mem_ctx, DOM_CRED *ret_creds,
+ uint32 database_id, uint32 *num_deltas,
+ SAM_DELTA_HDR **hdr_deltas,
+ SAM_DELTA_CTR **deltas)
+{
+ prs_struct qbuf, rbuf;
+ NET_Q_SAM_SYNC q;
+ NET_R_SAM_SYNC r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ DOM_CRED clnt_creds;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ gen_next_creds(cli, &clnt_creds);
+
+ init_net_q_sam_sync(&q, cli->srv_name_slash, cli->clnt_name_slash + 2,
+ &clnt_creds, ret_creds, database_id);
+
+ /* Marshall data and send request */
+
+ if (!net_io_q_sam_sync("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, NET_SAM_SYNC, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!net_io_r_sam_sync("", cli->sess_key, &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return results */
+
+ result = r.status;
+ *num_deltas = r.num_deltas2;
+ *hdr_deltas = r.hdr_deltas;
+ *deltas = r.deltas;
+
+ memcpy(ret_creds, &r.srv_creds, sizeof(*ret_creds));
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Sam synchronisation */
+
+NTSTATUS cli_netlogon_sam_deltas(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ uint32 database_id, UINT64_S seqnum,
+ uint32 *num_deltas,
+ SAM_DELTA_HDR **hdr_deltas,
+ SAM_DELTA_CTR **deltas)
+{
+ prs_struct qbuf, rbuf;
+ NET_Q_SAM_DELTAS q;
+ NET_R_SAM_DELTAS r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ DOM_CRED clnt_creds;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ gen_next_creds(cli, &clnt_creds);
+
+ init_net_q_sam_deltas(&q, cli->srv_name_slash,
+ cli->clnt_name_slash + 2, &clnt_creds,
+ database_id, seqnum);
+
+ /* Marshall data and send request */
+
+ if (!net_io_q_sam_deltas("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, NET_SAM_DELTAS, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!net_io_r_sam_deltas("", cli->sess_key, &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return results */
+
+ result = r.status;
+ *num_deltas = r.num_deltas2;
+ *hdr_deltas = r.hdr_deltas;
+ *deltas = r.deltas;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Logon domain user */
+
+NTSTATUS cli_netlogon_sam_logon(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ char *username, char *password,
+ int logon_type)
+{
+ prs_struct qbuf, rbuf;
+ NET_Q_SAM_LOGON q;
+ NET_R_SAM_LOGON r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ DOM_CRED clnt_creds, dummy_rtn_creds;
+ extern pstring global_myname;
+ NET_ID_INFO_CTR ctr;
+ NET_USER_INFO_3 user;
+ int validation_level = 3;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ gen_next_creds(cli, &clnt_creds);
+
+ q.validation_level = validation_level;
+
+ memset(&dummy_rtn_creds, '\0', sizeof(dummy_rtn_creds));
+ dummy_rtn_creds.timestamp.time = time(NULL);
+
+ ctr.switch_value = logon_type;
+
+ switch (logon_type) {
+ case INTERACTIVE_LOGON_TYPE: {
+ unsigned char lm_owf_user_pwd[16], nt_owf_user_pwd[16];
+
+ nt_lm_owf_gen(password, nt_owf_user_pwd, lm_owf_user_pwd);
+
+ init_id_info1(&ctr.auth.id1, lp_workgroup(),
+ 0, /* param_ctrl */
+ 0xdead, 0xbeef, /* LUID? */
+ username, cli->clnt_name_slash,
+ cli->sess_key, lm_owf_user_pwd,
+ nt_owf_user_pwd);
+
+ break;
+ }
+ case NET_LOGON_TYPE: {
+ uint8 chal[8];
+ unsigned char local_lm_response[24];
+ unsigned char local_nt_response[24];
+
+ generate_random_buffer(chal, 8, False);
+
+ SMBencrypt(password, chal, local_lm_response);
+ SMBNTencrypt(password, chal, local_nt_response);
+
+ init_id_info2(&ctr.auth.id2, lp_workgroup(),
+ 0, /* param_ctrl */
+ 0xdead, 0xbeef, /* LUID? */
+ username, cli->clnt_name_slash, chal,
+ local_lm_response, 24, local_nt_response, 24);
+ break;
+ }
+ default:
+ DEBUG(0, ("switch value %d not supported\n",
+ ctr.switch_value));
+ goto done;
+ }
+
+ init_sam_info(&q.sam_id, cli->srv_name_slash, global_myname,
+ &clnt_creds, &dummy_rtn_creds, logon_type,
+ &ctr);
+
+ /* Marshall data and send request */
+
+ if (!net_io_q_sam_logon("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, NET_SAMLOGON, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ r.user = &user;
+
+ if (!net_io_r_sam_logon("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return results */
+
+ result = r.status;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+
+/**
+ * Logon domain user with an 'network' SAM logon
+ *
+ * @param info3 Pointer to a NET_USER_INFO_3 already allocated by the caller.
+ **/
+
+NTSTATUS cli_netlogon_sam_network_logon(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ const char *username, const char *domain, const char *workstation,
+ const uint8 chal[8],
+ DATA_BLOB lm_response, DATA_BLOB nt_response,
+ NET_USER_INFO_3 *info3)
+
+{
+ prs_struct qbuf, rbuf;
+ NET_Q_SAM_LOGON q;
+ NET_R_SAM_LOGON r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ DOM_CRED clnt_creds, dummy_rtn_creds;
+ NET_ID_INFO_CTR ctr;
+ extern pstring global_myname;
+ int validation_level = 3;
+ char *workstation_name_slash;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation);
+
+ if (!workstation_name_slash) {
+ DEBUG(0, ("talloc_asprintf failed!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ gen_next_creds(cli, &clnt_creds);
+
+ q.validation_level = validation_level;
+
+ memset(&dummy_rtn_creds, '\0', sizeof(dummy_rtn_creds));
+ dummy_rtn_creds.timestamp.time = time(NULL);
+
+ ctr.switch_value = NET_LOGON_TYPE;
+
+ init_id_info2(&ctr.auth.id2, domain,
+ 0, /* param_ctrl */
+ 0xdead, 0xbeef, /* LUID? */
+ username, workstation_name_slash, (const uchar*)chal,
+ lm_response.data, lm_response.length, nt_response.data, nt_response.length);
+
+ init_sam_info(&q.sam_id, cli->srv_name_slash, global_myname,
+ &clnt_creds, &dummy_rtn_creds, NET_LOGON_TYPE,
+ &ctr);
+
+ /* Marshall data and send request */
+
+ if (!net_io_q_sam_logon("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, NET_SAMLOGON, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ r.user = info3;
+
+ if (!net_io_r_sam_logon("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return results */
+
+ result = r.status;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/***************************************************************************
+LSA Server Password Set.
+****************************************************************************/
+
+NTSTATUS cli_net_srv_pwset(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ char* machine_name, uint8 hashed_mach_pwd[16])
+{
+ prs_struct rbuf;
+ prs_struct qbuf;
+ DOM_CRED new_clnt_cred;
+ NET_Q_SRV_PWSET q_s;
+ uint16 sec_chan_type = 2;
+ NTSTATUS nt_status;
+ char *mach_acct;
+
+ gen_next_creds( cli, &new_clnt_cred);
+
+ prs_init(&qbuf , 1024, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* create and send a MSRPC command with api NET_SRV_PWSET */
+
+ mach_acct = talloc_asprintf(mem_ctx, "%s$", machine_name);
+
+ if (!mach_acct) {
+ DEBUG(0,("talloc_asprintf failed!\n"));
+ nt_status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ DEBUG(4,("cli_net_srv_pwset: srv:%s acct:%s sc: %d mc: %s clnt %s %x\n",
+ cli->srv_name_slash, mach_acct, sec_chan_type, machine_name,
+ credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time));
+
+ /* store the parameters */
+ init_q_srv_pwset(&q_s, cli->srv_name_slash, cli->sess_key,
+ mach_acct, sec_chan_type, machine_name,
+ &new_clnt_cred, (char *)hashed_mach_pwd);
+
+ /* turn parameters into data stream */
+ if(!net_io_q_srv_pwset("", &q_s, &qbuf, 0)) {
+ DEBUG(0,("cli_net_srv_pwset: Error : failed to marshall NET_Q_SRV_PWSET struct.\n"));
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* send the data on \PIPE\ */
+ if (rpc_api_pipe_req(cli, NET_SRVPWSET, &qbuf, &rbuf))
+ {
+ NET_R_SRV_PWSET r_s;
+
+ if (!net_io_r_srv_pwset("", &r_s, &rbuf, 0)) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ nt_status = r_s.status;
+
+ if (!NT_STATUS_IS_OK(r_s.status))
+ {
+ /* report error code */
+ DEBUG(0,("cli_net_srv_pwset: %s\n", nt_errstr(nt_status)));
+ goto done;
+ }
+
+ /* Update the credentials. */
+ if (!clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &(r_s.srv_cred)))
+ {
+ /*
+ * Server replied with bad credential. Fail.
+ */
+ DEBUG(0,("cli_net_srv_pwset: server %s replied with bad credential (bad machine \
+password ?).\n", cli->desthost ));
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return nt_status;
+}
+
diff --git a/source3/libsmb/cli_pipe_util.c b/source3/libsmb/cli_pipe_util.c
new file mode 100644
index 0000000000..de1c832e44
--- /dev/null
+++ b/source3/libsmb/cli_pipe_util.c
@@ -0,0 +1,82 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client utility functions
+ Copyright (C) Tim Potter 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"
+
+/** \defgroup rpc_client RPC Client routines
+ */
+
+/* Opens a SMB connection to a named pipe */
+
+struct cli_state *cli_pipe_initialise(struct cli_state *cli, char *system_name,
+ char *pipe_name,
+ struct ntuser_creds *creds)
+{
+ struct in_addr dest_ip;
+ struct nmb_name calling, called;
+ fstring dest_host;
+ extern pstring global_myname;
+ struct ntuser_creds anon;
+
+ /* Initialise cli_state information */
+
+ if (!cli_initialise(cli)) {
+ return NULL;
+ }
+
+ if (!creds) {
+ ZERO_STRUCT(anon);
+ anon.pwd.null_pwd = 1;
+ creds = &anon;
+ }
+
+ cli_init_creds(cli, creds);
+
+ /* Establish a SMB connection */
+
+ if (!resolve_srv_name(system_name, dest_host, &dest_ip)) {
+ return NULL;
+ }
+
+ make_nmb_name(&called, dns_to_netbios_name(dest_host), 0x20);
+ make_nmb_name(&calling, dns_to_netbios_name(global_myname), 0);
+
+ if (!cli_establish_connection(cli, dest_host, &dest_ip, &calling,
+ &called, "IPC$", "IPC", False, True)) {
+ return NULL;
+ }
+
+ /* Open a NT session thingy */
+
+ if (!cli_nt_session_open(cli, pipe_name)) {
+ cli_shutdown(cli);
+ return NULL;
+ }
+
+ return cli;
+}
+
+/* Shut down a SMB connection to the SAMR pipe */
+
+void cli_pipe_shutdown(struct cli_state *cli)
+{
+ if (cli->fd != -1) cli_ulogoff(cli);
+ cli_shutdown(cli);
+}
diff --git a/source3/libsmb/cli_reg.c b/source3/libsmb/cli_reg.c
new file mode 100644
index 0000000000..c09ccabb29
--- /dev/null
+++ b/source3/libsmb/cli_reg.c
@@ -0,0 +1,111 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC Pipe client
+
+ Copyright (C) Andrew Tridgell 1992-1998,
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
+ Copyright (C) Paul Ashton 1997-1998.
+ Copyright (C) Jeremy Allison 1999.
+ Copyright (C) Simo Sorce 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"
+
+/* Opens a SMB connection to the WINREG pipe */
+
+struct cli_state *cli_winreg_initialise(struct cli_state *cli,
+ char *system_name,
+ struct ntuser_creds *creds)
+{
+ return cli_pipe_initialise(cli, system_name, PIPE_WINREG, creds);
+}
+
+/* Shutdown a server */
+
+NTSTATUS cli_reg_shutdown(struct cli_state * cli, TALLOC_CTX *mem_ctx,
+ const char *msg, uint32 timeout, uint16 flags)
+{
+ prs_struct qbuf;
+ prs_struct rbuf;
+ REG_Q_SHUTDOWN q_s;
+ REG_R_SHUTDOWN r_s;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ if (msg == NULL) return NT_STATUS_INVALID_PARAMETER;
+
+ ZERO_STRUCT (q_s);
+ ZERO_STRUCT (r_s);
+
+ prs_init(&qbuf , MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_reg_q_shutdown(&q_s, msg, timeout, flags);
+
+ if (!reg_io_q_shutdown("", &q_s, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, REG_SHUTDOWN, &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if(reg_io_r_shutdown("", &r_s, &rbuf, 0))
+ result = r_s.status;
+
+done:
+ prs_mem_free(&rbuf);
+ prs_mem_free(&qbuf);
+
+ return result;
+}
+
+
+/* Abort a server shutdown */
+
+NTSTATUS cli_reg_abort_shutdown(struct cli_state * cli, TALLOC_CTX *mem_ctx)
+{
+ prs_struct rbuf;
+ prs_struct qbuf;
+ REG_Q_ABORT_SHUTDOWN q_s;
+ REG_R_ABORT_SHUTDOWN r_s;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT (q_s);
+ ZERO_STRUCT (r_s);
+
+ prs_init(&qbuf , MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_reg_q_abort_shutdown(&q_s);
+
+ if (!reg_io_q_abort_shutdown("", &q_s, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, REG_ABORT_SHUTDOWN, &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if (reg_io_r_abort_shutdown("", &r_s, &rbuf, 0))
+ result = r_s.status;
+
+done:
+ prs_mem_free(&rbuf);
+ prs_mem_free(&qbuf );
+
+ return result;
+}
diff --git a/source3/libsmb/cli_samr.c b/source3/libsmb/cli_samr.c
new file mode 100644
index 0000000000..85a7375f99
--- /dev/null
+++ b/source3/libsmb/cli_samr.c
@@ -0,0 +1,1274 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+ Copyright (C) Tim Potter 2000-2001,
+ Copyright (C) Andrew Tridgell 1992-1997,2000,
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997,2000,
+ Copyright (C) Paul Ashton 1997,2000,
+ Copyright (C) Elrond 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"
+
+/* Opens a SMB connection to the SAMR pipe */
+
+struct cli_state *cli_samr_initialise(struct cli_state *cli, char *system_name,
+ struct ntuser_creds *creds)
+{
+ return cli_pipe_initialise(cli, system_name, PIPE_SAMR, creds);
+}
+
+/* Connect to SAMR database */
+
+NTSTATUS cli_samr_connect(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ uint32 access_mask, POLICY_HND *connect_pol)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_CONNECT q;
+ SAMR_R_CONNECT r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_connect(&q, cli->desthost, access_mask);
+
+ if (!samr_io_q_connect("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_CONNECT, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_connect("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *connect_pol = r.connect_pol;
+#ifdef __INSURE__
+ connect_pol->marker = malloc(1);
+#endif
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Close SAMR handle */
+
+NTSTATUS cli_samr_close(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *connect_pol)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_CLOSE_HND q;
+ SAMR_R_CLOSE_HND r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_close_hnd(&q, connect_pol);
+
+ if (!samr_io_q_close_hnd("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_CLOSE_HND, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_close_hnd("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+#ifdef __INSURE__
+ SAFE_FREE(connect_pol->marker);
+#endif
+ *connect_pol = r.pol;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Open handle on a domain */
+
+NTSTATUS cli_samr_open_domain(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *connect_pol, uint32 access_mask,
+ const DOM_SID *domain_sid, POLICY_HND *domain_pol)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_OPEN_DOMAIN q;
+ SAMR_R_OPEN_DOMAIN r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_open_domain(&q, connect_pol, access_mask, domain_sid);
+
+ if (!samr_io_q_open_domain("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_OPEN_DOMAIN, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_open_domain("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *domain_pol = r.domain_pol;
+#ifdef __INSURE__
+ domain_pol->marker = malloc(1);
+#endif
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Open handle on a user */
+
+NTSTATUS cli_samr_open_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *domain_pol, uint32 access_mask,
+ uint32 user_rid, POLICY_HND *user_pol)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_OPEN_USER q;
+ SAMR_R_OPEN_USER r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_open_user(&q, domain_pol, access_mask, user_rid);
+
+ if (!samr_io_q_open_user("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_OPEN_USER, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_open_user("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *user_pol = r.user_pol;
+#ifdef __INSURE__
+ user_pol->marker = malloc(1);
+#endif
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Open handle on a group */
+
+NTSTATUS cli_samr_open_group(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *domain_pol, uint32 access_mask,
+ uint32 group_rid, POLICY_HND *group_pol)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_OPEN_GROUP q;
+ SAMR_R_OPEN_GROUP r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_open_group(&q, domain_pol, access_mask, group_rid);
+
+ if (!samr_io_q_open_group("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_OPEN_GROUP, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_open_group("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *group_pol = r.pol;
+#ifdef __INSURE__
+ group_pol->marker = malloc(1);
+#endif
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Query user info */
+
+NTSTATUS cli_samr_query_userinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *user_pol, uint16 switch_value,
+ SAM_USERINFO_CTR **ctr)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_QUERY_USERINFO q;
+ SAMR_R_QUERY_USERINFO r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_query_userinfo(&q, user_pol, switch_value);
+
+ if (!samr_io_q_query_userinfo("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_QUERY_USERINFO, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_query_userinfo("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ result = r.status;
+ *ctr = r.ctr;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Query group info */
+
+NTSTATUS cli_samr_query_groupinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *group_pol, uint32 info_level,
+ GROUP_INFO_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_QUERY_GROUPINFO q;
+ SAMR_R_QUERY_GROUPINFO r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_query_groupinfo(&q, group_pol, info_level);
+
+ if (!samr_io_q_query_groupinfo("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_QUERY_GROUPINFO, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ r.ctr = ctr;
+
+ if (!samr_io_r_query_groupinfo("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Query user groups */
+
+NTSTATUS cli_samr_query_usergroups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *user_pol, uint32 *num_groups,
+ DOM_GID **gid)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_QUERY_USERGROUPS q;
+ SAMR_R_QUERY_USERGROUPS r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_query_usergroups(&q, user_pol);
+
+ if (!samr_io_q_query_usergroups("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_QUERY_USERGROUPS, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_query_usergroups("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *num_groups = r.num_entries;
+ *gid = r.gid;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Query user aliases */
+
+NTSTATUS cli_samr_query_useraliases(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *user_pol, uint32 num_sids, DOM_SID2 *sid,
+ uint32 *num_aliases, uint32 **als_rids)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_QUERY_USERALIASES q;
+ SAMR_R_QUERY_USERALIASES r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint ptr=1;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_query_useraliases(&q, user_pol, num_sids, &ptr, sid);
+
+ if (!samr_io_q_query_useraliases("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_QUERY_USERALIASES, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_query_useraliases("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *num_aliases = r.num_entries;
+ *als_rids = r.rid;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Query user groups */
+
+NTSTATUS cli_samr_query_groupmem(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *group_pol, uint32 *num_mem,
+ uint32 **rid, uint32 **attr)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_QUERY_GROUPMEM q;
+ SAMR_R_QUERY_GROUPMEM r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_query_groupmem(&q, group_pol);
+
+ if (!samr_io_q_query_groupmem("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_QUERY_GROUPMEM, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_query_groupmem("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *num_mem = r.num_entries;
+ *rid = r.rid;
+ *attr = r.attr;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Enumerate domain groups */
+
+NTSTATUS cli_samr_enum_dom_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 *start_idx,
+ uint32 size, struct acct_info **dom_groups,
+ uint32 *num_dom_groups)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_ENUM_DOM_GROUPS q;
+ SAMR_R_ENUM_DOM_GROUPS r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 name_idx, i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_enum_dom_groups(&q, pol, *start_idx, size);
+
+ if (!samr_io_q_enum_dom_groups("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_ENUM_DOM_GROUPS, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_enum_dom_groups("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ if (!NT_STATUS_IS_OK(result) &&
+ NT_STATUS_V(result) != NT_STATUS_V(STATUS_MORE_ENTRIES)) {
+ goto done;
+ }
+
+ *num_dom_groups = r.num_entries2;
+
+ if (!((*dom_groups) = (struct acct_info *)
+ talloc(mem_ctx, sizeof(struct acct_info) * *num_dom_groups))) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ memset(*dom_groups, 0, sizeof(struct acct_info) * *num_dom_groups);
+
+ name_idx = 0;
+
+ for (i = 0; i < *num_dom_groups; i++) {
+
+ (*dom_groups)[i].rid = r.sam[i].rid;
+
+ if (r.sam[i].hdr_name.buffer) {
+ unistr2_to_ascii((*dom_groups)[i].acct_name,
+ &r.uni_grp_name[name_idx],
+ sizeof(fstring) - 1);
+ name_idx++;
+ }
+
+ *start_idx = r.next_idx;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Enumerate domain groups */
+
+NTSTATUS cli_samr_enum_als_groups(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 *start_idx,
+ uint32 size, struct acct_info **dom_groups,
+ uint32 *num_dom_groups)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_ENUM_DOM_ALIASES q;
+ SAMR_R_ENUM_DOM_ALIASES r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 name_idx, i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_enum_dom_aliases(&q, pol, *start_idx, size);
+
+ if (!samr_io_q_enum_dom_aliases("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_ENUM_DOM_ALIASES, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_enum_dom_aliases("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ if (!NT_STATUS_IS_OK(result) &&
+ NT_STATUS_V(result) != NT_STATUS_V(STATUS_MORE_ENTRIES)) {
+ goto done;
+ }
+
+ *num_dom_groups = r.num_entries2;
+
+ if (!((*dom_groups) = (struct acct_info *)
+ talloc(mem_ctx, sizeof(struct acct_info) * *num_dom_groups))) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ memset(*dom_groups, 0, sizeof(struct acct_info) * *num_dom_groups);
+
+ name_idx = 0;
+
+ for (i = 0; i < *num_dom_groups; i++) {
+
+ (*dom_groups)[i].rid = r.sam[i].rid;
+
+ if (r.sam[i].hdr_name.buffer) {
+ unistr2_to_ascii((*dom_groups)[i].acct_name,
+ &r.uni_grp_name[name_idx],
+ sizeof(fstring) - 1);
+ name_idx++;
+ }
+
+ *start_idx = r.next_idx;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Query alias members */
+
+NTSTATUS cli_samr_query_aliasmem(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *alias_pol, uint32 *num_mem,
+ DOM_SID **sids)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_QUERY_ALIASMEM q;
+ SAMR_R_QUERY_ALIASMEM r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_query_aliasmem(&q, alias_pol);
+
+ if (!samr_io_q_query_aliasmem("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_QUERY_ALIASMEM, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_query_aliasmem("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ *num_mem = r.num_sids;
+
+ if (!(*sids = talloc(mem_ctx, sizeof(DOM_SID) * *num_mem))) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ for (i = 0; i < *num_mem; i++) {
+ (*sids)[i] = r.sid[i].sid;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Open handle on an alias */
+
+NTSTATUS cli_samr_open_alias(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *domain_pol, uint32 access_mask,
+ uint32 alias_rid, POLICY_HND *alias_pol)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_OPEN_ALIAS q;
+ SAMR_R_OPEN_ALIAS r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_open_alias(&q, domain_pol, access_mask, alias_rid);
+
+ if (!samr_io_q_open_alias("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_OPEN_ALIAS, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_open_alias("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (NT_STATUS_IS_OK(result = r.status)) {
+ *alias_pol = r.pol;
+#ifdef __INSURE__
+ alias_pol->marker = malloc(1);
+#endif
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Query domain info */
+
+NTSTATUS cli_samr_query_dom_info(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *domain_pol, uint16 switch_value,
+ SAM_UNK_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_QUERY_DOMAIN_INFO q;
+ SAMR_R_QUERY_DOMAIN_INFO r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_query_dom_info(&q, domain_pol, switch_value);
+
+ if (!samr_io_q_query_dom_info("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_QUERY_DOMAIN_INFO, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ r.ctr = ctr;
+
+ if (!samr_io_r_query_dom_info("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Query display info */
+
+NTSTATUS cli_samr_query_dispinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *domain_pol, uint32 *start_idx,
+ uint16 switch_value, uint32 *num_entries,
+ uint32 max_entries, SAM_DISPINFO_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_QUERY_DISPINFO q;
+ SAMR_R_QUERY_DISPINFO r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_query_dispinfo(&q, domain_pol, switch_value,
+ *start_idx, max_entries);
+
+ if (!samr_io_q_query_dispinfo("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_QUERY_DISPINFO, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ r.ctr = ctr;
+
+ if (!samr_io_r_query_dispinfo("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ if (!NT_STATUS_IS_OK(result) &&
+ NT_STATUS_V(result) != NT_STATUS_V(STATUS_MORE_ENTRIES)) {
+ goto done;
+ }
+
+ *num_entries = r.num_entries;
+ *start_idx += r.num_entries; /* No next_idx in this structure! */
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Lookup rids. Note that NT4 seems to crash if more than ~1000 rids are
+ looked up in one packet. */
+
+NTSTATUS cli_samr_lookup_rids(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *domain_pol, uint32 flags,
+ uint32 num_rids, uint32 *rids,
+ uint32 *num_names, char ***names,
+ uint32 **name_types)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_LOOKUP_RIDS q;
+ SAMR_R_LOOKUP_RIDS r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 i;
+
+ if (num_rids > 1000) {
+ DEBUG(2, ("cli_samr_lookup_rids: warning: NT4 can crash if "
+ "more than ~1000 rids are looked up at once.\n"));
+ }
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_lookup_rids(mem_ctx, &q, domain_pol, flags,
+ num_rids, rids);
+
+ if (!samr_io_q_lookup_rids("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_LOOKUP_RIDS, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_lookup_rids("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ if (r.num_names1 == 0) {
+ *num_names = 0;
+ *names = NULL;
+ goto done;
+ }
+
+ *num_names = r.num_names1;
+ *names = talloc(mem_ctx, sizeof(char *) * r.num_names1);
+ *name_types = talloc(mem_ctx, sizeof(uint32) * r.num_names1);
+
+ for (i = 0; i < r.num_names1; i++) {
+ fstring tmp;
+
+ unistr2_to_ascii(tmp, &r.uni_name[i], sizeof(tmp) - 1);
+ (*names)[i] = talloc_strdup(mem_ctx, tmp);
+ (*name_types)[i] = r.type[i];
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Lookup names */
+
+NTSTATUS cli_samr_lookup_names(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *domain_pol, uint32 flags,
+ uint32 num_names, char **names,
+ uint32 *num_rids, uint32 **rids,
+ uint32 **rid_types)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_LOOKUP_NAMES q;
+ SAMR_R_LOOKUP_NAMES r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ uint32 i;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_lookup_names(mem_ctx, &q, domain_pol, flags,
+ num_names, names);
+
+ if (!samr_io_q_lookup_names("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_LOOKUP_NAMES, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_lookup_names("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ if (r.num_rids1 == 0) {
+ *num_rids = 0;
+ goto done;
+ }
+
+ *num_rids = r.num_rids1;
+ *rids = talloc(mem_ctx, sizeof(uint32) * r.num_rids1);
+ *rid_types = talloc(mem_ctx, sizeof(uint32) * r.num_rids1);
+
+ for (i = 0; i < r.num_rids1; i++) {
+ (*rids)[i] = r.rids[i];
+ (*rid_types)[i] = r.types[i];
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Create a domain user */
+
+NTSTATUS cli_samr_create_dom_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *domain_pol, const char *acct_name,
+ uint32 acb_info, uint32 unknown,
+ POLICY_HND *user_pol, uint32 *rid)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_CREATE_USER q;
+ SAMR_R_CREATE_USER r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_create_user(&q, domain_pol, acct_name, acb_info, unknown);
+
+ if (!samr_io_q_create_user("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_CREATE_USER, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_create_user("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ if (user_pol)
+ *user_pol = r.user_pol;
+
+ if (rid)
+ *rid = r.user_rid;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Set userinfo */
+
+NTSTATUS cli_samr_set_userinfo(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *user_pol, uint16 switch_value,
+ uchar sess_key[16], SAM_USERINFO_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_SET_USERINFO q;
+ SAMR_R_SET_USERINFO r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ q.ctr = ctr;
+
+ init_samr_q_set_userinfo(&q, user_pol, sess_key, switch_value,
+ ctr->info.id);
+
+ if (!samr_io_q_set_userinfo("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_SET_USERINFO, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_set_userinfo("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Set userinfo2 */
+
+NTSTATUS cli_samr_set_userinfo2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *user_pol, uint16 switch_value,
+ uchar sess_key[16], SAM_USERINFO_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_SET_USERINFO2 q;
+ SAMR_R_SET_USERINFO2 r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_set_userinfo2(&q, user_pol, sess_key, switch_value, ctr);
+
+ if (!samr_io_q_set_userinfo2("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_SET_USERINFO2, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_set_userinfo2("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ if (!NT_STATUS_IS_OK(result = r.status)) {
+ goto done;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Delete domain user */
+
+NTSTATUS cli_samr_delete_dom_user(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *user_pol)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_DELETE_DOM_USER q;
+ SAMR_R_DELETE_DOM_USER r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_delete_dom_user(&q, user_pol);
+
+ if (!samr_io_q_delete_dom_user("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_DELETE_DOM_USER, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_delete_dom_user("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Query user security object */
+
+NTSTATUS cli_samr_query_sec_obj(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *user_pol, uint16 switch_value,
+ TALLOC_CTX *ctx, SEC_DESC_BUF **sec_desc_buf)
+{
+ prs_struct qbuf, rbuf;
+ SAMR_Q_QUERY_SEC_OBJ q;
+ SAMR_R_QUERY_SEC_OBJ r;
+ NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Marshall data and send request */
+
+ init_samr_q_query_sec_obj(&q, user_pol, switch_value);
+
+ if (!samr_io_q_query_sec_obj("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SAMR_QUERY_SEC_OBJECT, &qbuf, &rbuf)) {
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ if (!samr_io_r_query_sec_obj("", &r, &rbuf, 0)) {
+ goto done;
+ }
+
+ /* Return output parameters */
+
+ result = r.status;
+ *sec_desc_buf=dup_sec_desc_buf(ctx, r.buf);
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
diff --git a/source3/libsmb/cli_spoolss.c b/source3/libsmb/cli_spoolss.c
new file mode 100644
index 0000000000..cf356ef815
--- /dev/null
+++ b/source3/libsmb/cli_spoolss.c
@@ -0,0 +1,1590 @@
+/*
+ Unix SMB/CIFS implementation.
+ RPC pipe client
+
+ Copyright (C) Gerald Carter 2001-2002,
+ Copyright (C) Tim Potter 2000-2002,
+ Copyright (C) Andrew Tridgell 1994-2000,
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
+ Copyright (C) Jean-Francois Micouleau 1999-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"
+
+/** @defgroup spoolss SPOOLSS - NT printing routines
+ * @ingroup rpc_client
+ *
+ * @{
+ **/
+
+/** Opens a SMB connection and connects to the SPOOLSS pipe.
+ *
+ * @param cli Uninitialised client handle.
+ * @param system_name NETBIOS name of the machine to connect to.
+ * @param creds User credentials to connect as.
+ * @returns Initialised client handle.
+ */
+struct cli_state *cli_spoolss_initialise(struct cli_state *cli,
+ char *system_name,
+ struct ntuser_creds *creds)
+{
+ return cli_pipe_initialise(cli, system_name, PIPE_SPOOLSS, creds);
+}
+
+/**********************************************************************
+ Initialize a new spoolss buff for use by a client rpc
+**********************************************************************/
+static void init_buffer(NEW_BUFFER *buffer, uint32 size, TALLOC_CTX *ctx)
+{
+ buffer->ptr = (size != 0);
+ buffer->size = size;
+ buffer->string_at_end = size;
+ prs_init(&buffer->prs, size, ctx, MARSHALL);
+ buffer->struct_start = prs_offset(&buffer->prs);
+}
+
+/*********************************************************************
+ Decode various spoolss rpc's and info levels
+ ********************************************************************/
+
+/**********************************************************************
+**********************************************************************/
+static void decode_printer_info_0(TALLOC_CTX *mem_ctx, NEW_BUFFER *buffer,
+ uint32 returned, PRINTER_INFO_0 **info)
+{
+ uint32 i;
+ PRINTER_INFO_0 *inf;
+
+ inf=(PRINTER_INFO_0 *)talloc(mem_ctx, returned*sizeof(PRINTER_INFO_0));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ smb_io_printer_info_0("", buffer, &inf[i], 0);
+ }
+
+ *info=inf;
+}
+
+/**********************************************************************
+**********************************************************************/
+static void decode_printer_info_1(TALLOC_CTX *mem_ctx, NEW_BUFFER *buffer,
+ uint32 returned, PRINTER_INFO_1 **info)
+{
+ uint32 i;
+ PRINTER_INFO_1 *inf;
+
+ inf=(PRINTER_INFO_1 *)talloc(mem_ctx, returned*sizeof(PRINTER_INFO_1));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ smb_io_printer_info_1("", buffer, &inf[i], 0);
+ }
+
+ *info=inf;
+}
+
+/**********************************************************************
+**********************************************************************/
+static void decode_printer_info_2(TALLOC_CTX *mem_ctx, NEW_BUFFER *buffer,
+ uint32 returned, PRINTER_INFO_2 **info)
+{
+ uint32 i;
+ PRINTER_INFO_2 *inf;
+
+ inf=(PRINTER_INFO_2 *)talloc(mem_ctx, returned*sizeof(PRINTER_INFO_2));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ /* a little initialization as we go */
+ inf[i].secdesc = NULL;
+ smb_io_printer_info_2("", buffer, &inf[i], 0);
+ }
+
+ *info=inf;
+}
+
+/**********************************************************************
+**********************************************************************/
+static void decode_printer_info_3(TALLOC_CTX *mem_ctx, NEW_BUFFER *buffer,
+ uint32 returned, PRINTER_INFO_3 **info)
+{
+ uint32 i;
+ PRINTER_INFO_3 *inf;
+
+ inf=(PRINTER_INFO_3 *)talloc(mem_ctx, returned*sizeof(PRINTER_INFO_3));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ inf[i].secdesc = NULL;
+ smb_io_printer_info_3("", buffer, &inf[i], 0);
+ }
+
+ *info=inf;
+}
+
+/**********************************************************************
+**********************************************************************/
+static void decode_port_info_1(TALLOC_CTX *mem_ctx, NEW_BUFFER *buffer,
+ uint32 returned, PORT_INFO_1 **info)
+{
+ uint32 i;
+ PORT_INFO_1 *inf;
+
+ inf=(PORT_INFO_1*)talloc(mem_ctx, returned*sizeof(PORT_INFO_1));
+
+ prs_set_offset(&buffer->prs, 0);
+
+ for (i=0; i<returned; i++) {
+ smb_io_port_info_1("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+/**********************************************************************
+**********************************************************************/
+static void decode_port_info_2(TALLOC_CTX *mem_ctx, NEW_BUFFER *buffer,
+ uint32 returned, PORT_INFO_2 **info)
+{
+ uint32 i;
+ PORT_INFO_2 *inf;
+
+ inf=(PORT_INFO_2*)talloc(mem_ctx, returned*sizeof(PORT_INFO_2));
+
+ prs_set_offset(&buffer->prs, 0);
+
+ for (i=0; i<returned; i++) {
+ smb_io_port_info_2("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+/**********************************************************************
+**********************************************************************/
+static void decode_printer_driver_1(TALLOC_CTX *mem_ctx, NEW_BUFFER *buffer,
+ uint32 returned, DRIVER_INFO_1 **info)
+{
+ uint32 i;
+ DRIVER_INFO_1 *inf;
+
+ inf=(DRIVER_INFO_1 *)talloc(mem_ctx, returned*sizeof(DRIVER_INFO_1));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ smb_io_printer_driver_info_1("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+/**********************************************************************
+**********************************************************************/
+static void decode_printer_driver_2(TALLOC_CTX *mem_ctx, NEW_BUFFER *buffer,
+ uint32 returned, DRIVER_INFO_2 **info)
+{
+ uint32 i;
+ DRIVER_INFO_2 *inf;
+
+ inf=(DRIVER_INFO_2 *)talloc(mem_ctx, returned*sizeof(DRIVER_INFO_2));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ smb_io_printer_driver_info_2("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+/**********************************************************************
+**********************************************************************/
+static void decode_printer_driver_3(TALLOC_CTX *mem_ctx, NEW_BUFFER *buffer,
+ uint32 returned, DRIVER_INFO_3 **info)
+{
+ uint32 i;
+ DRIVER_INFO_3 *inf;
+
+ inf=(DRIVER_INFO_3 *)talloc(mem_ctx, returned*sizeof(DRIVER_INFO_3));
+
+ buffer->prs.data_offset=0;
+
+ for (i=0; i<returned; i++) {
+ smb_io_printer_driver_info_3("", buffer, &(inf[i]), 0);
+ }
+
+ *info=inf;
+}
+
+/**********************************************************************
+**********************************************************************/
+static void decode_printerdriverdir_1 (TALLOC_CTX *mem_ctx, NEW_BUFFER *buffer,
+ uint32 returned, DRIVER_DIRECTORY_1 **info
+)
+{
+ DRIVER_DIRECTORY_1 *inf;
+
+ inf=(DRIVER_DIRECTORY_1 *)talloc(mem_ctx, sizeof(DRIVER_DIRECTORY_1));
+
+ prs_set_offset(&buffer->prs, 0);
+
+ smb_io_driverdir_1("", buffer, inf, 0);
+
+ *info=inf;
+}
+
+/** Return a handle to the specified printer or print server.
+ *
+ * @param cli Pointer to client state structure which is open
+ * on the SPOOLSS pipe.
+ *
+ * @param mem_ctx Pointer to an initialised talloc context.
+ *
+ * @param printername The name of the printer or print server to be
+ * opened in UNC format.
+ *
+ * @param datatype Specifies the default data type for the printer.
+ *
+ * @param access_required The access rights requested on the printer or
+ * print server.
+ *
+ * @param station The UNC name of the requesting workstation.
+ *
+ * @param username The name of the user requesting the open.
+ *
+ * @param pol Returned policy handle.
+ */
+
+/*********************************************************************************
+ Win32 API - OpenPrinter()
+ ********************************************************************************/
+
+WERROR cli_spoolss_open_printer_ex(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ char *printername, char *datatype, uint32 access_required,
+ char *station, char *username, POLICY_HND *pol)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_OPEN_PRINTER_EX q;
+ SPOOL_R_OPEN_PRINTER_EX r;
+ WERROR result = W_ERROR(ERRgeneral);
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ make_spoolss_q_open_printer_ex(&q, printername, datatype,
+ access_required, station, username);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_open_printer_ex("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SPOOLSS_OPENPRINTEREX, &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if (!spoolss_io_r_open_printer_ex("", &r, &rbuf, 0))
+ goto done;
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ if (W_ERROR_IS_OK(result))
+ *pol = r.handle;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Close a printer handle
+ *
+ * @param cli Pointer to client state structure which is open
+ * on the SPOOLSS pipe.
+ *
+ * @param mem_ctx Pointer to an initialised talloc context.
+ *
+ * @param pol Policy handle of printer or print server to close.
+ */
+/*********************************************************************************
+ Win32 API - ClosePrinter()
+ ********************************************************************************/
+
+WERROR cli_spoolss_close_printer(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_CLOSEPRINTER q;
+ SPOOL_R_CLOSEPRINTER r;
+ WERROR result = W_ERROR(ERRgeneral);
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ make_spoolss_q_closeprinter(&q, pol);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_closeprinter("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SPOOLSS_CLOSEPRINTER, &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if (!spoolss_io_r_closeprinter("", &r, &rbuf, 0))
+ goto done;
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ if (W_ERROR_IS_OK(result))
+ *pol = r.handle;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Enumerate printers on a print server.
+ *
+ * @param cli Pointer to client state structure which is open
+ * on the SPOOLSS pipe.
+ * @param mem_ctx Pointer to an initialised talloc context.
+ *
+ * @param offered Buffer size offered in the request.
+ * @param needed Number of bytes needed to complete the request.
+ * may be NULL.
+ *
+ * @param flags Selected from PRINTER_ENUM_* flags.
+ * @param level Request information level.
+ *
+ * @param num_printers Pointer to number of printers returned. May be
+ * NULL.
+ * @param ctr Return structure for printer information. May
+ * be NULL.
+ */
+/*********************************************************************************
+ Win32 API - EnumPrinters()
+ ********************************************************************************/
+
+WERROR cli_spoolss_enum_printers(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ uint32 offered, uint32 *needed,
+ uint32 flags, uint32 level,
+ uint32 *num_printers, PRINTER_INFO_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ENUMPRINTERS q;
+ SPOOL_R_ENUMPRINTERS r;
+ NEW_BUFFER buffer;
+ WERROR result = W_ERROR(ERRgeneral);
+ fstring server;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ fstrcpy (server, cli->desthost);
+ strupper (server);
+
+ /* Initialise input parameters */
+
+ init_buffer(&buffer, offered, mem_ctx);
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ make_spoolss_q_enumprinters(&q, flags, server, level, &buffer,
+ offered);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_enumprinters("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SPOOLSS_ENUMPRINTERS, &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if (spoolss_io_r_enumprinters("", &r, &rbuf, 0)) {
+ if (needed)
+ *needed = r.needed;
+ }
+
+ result = r.status;
+
+ /* Return output parameters */
+
+ if (!W_ERROR_IS_OK(r.status))
+ goto done;
+
+ if (num_printers)
+ *num_printers = r.returned;
+
+ if (!ctr)
+ goto done;
+
+ switch (level) {
+ case 0:
+ decode_printer_info_0(mem_ctx, r.buffer, r.returned,
+ &ctr->printers_0);
+ break;
+ case 1:
+ decode_printer_info_1(mem_ctx, r.buffer, r.returned,
+ &ctr->printers_1);
+ break;
+ case 2:
+ decode_printer_info_2(mem_ctx, r.buffer, r.returned,
+ &ctr->printers_2);
+ break;
+ case 3:
+ decode_printer_info_3(mem_ctx, r.buffer, r.returned,
+ &ctr->printers_3);
+ break;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/*********************************************************************************
+ Win32 API - EnumPorts()
+ ********************************************************************************/
+/** Enumerate printer ports on a print server.
+ *
+ * @param cli Pointer to client state structure which is open
+ * on the SPOOLSS pipe.
+ * @param mem_ctx Pointer to an initialised talloc context.
+ *
+ * @param offered Buffer size offered in the request.
+ * @param needed Number of bytes needed to complete the request.
+ * May be NULL.
+ *
+ * @param level Requested information level.
+ *
+ * @param num_ports Pointer to number of ports returned. May be NULL.
+ * @param ctr Pointer to structure holding port information.
+ * May be NULL.
+ */
+
+WERROR cli_spoolss_enum_ports(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ uint32 offered, uint32 *needed,
+ uint32 level, int *num_ports, PORT_INFO_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ENUMPORTS q;
+ SPOOL_R_ENUMPORTS r;
+ NEW_BUFFER buffer;
+ WERROR result = W_ERROR(ERRgeneral);
+ fstring server;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ slprintf (server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (server);
+
+ /* Initialise input parameters */
+
+ init_buffer(&buffer, offered, mem_ctx);
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ make_spoolss_q_enumports(&q, server, level, &buffer, offered);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_enumports("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SPOOLSS_ENUMPORTS, &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if (spoolss_io_r_enumports("", &r, &rbuf, 0)) {
+ if (needed)
+ *needed = r.needed;
+ }
+
+ result = r.status;
+
+ /* Return output parameters */
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ if (num_ports)
+ *num_ports = r.returned;
+
+ if (!ctr)
+ goto done;
+
+ switch (level) {
+ case 1:
+ decode_port_info_1(mem_ctx, r.buffer, r.returned,
+ &ctr->port.info_1);
+ break;
+ case 2:
+ decode_port_info_2(mem_ctx, r.buffer, r.returned,
+ &ctr->port.info_2);
+ break;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/*********************************************************************************
+ Win32 API - GetPrinter()
+ ********************************************************************************/
+
+WERROR cli_spoolss_getprinter(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ uint32 offered, uint32 *needed,
+ POLICY_HND *pol, uint32 level,
+ PRINTER_INFO_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_GETPRINTER q;
+ SPOOL_R_GETPRINTER r;
+ NEW_BUFFER buffer;
+ WERROR result = W_ERROR(ERRgeneral);
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise input parameters */
+
+ init_buffer(&buffer, offered, mem_ctx);
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ make_spoolss_q_getprinter(mem_ctx, &q, pol, level, &buffer, offered);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_getprinter("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SPOOLSS_GETPRINTER, &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if (!spoolss_io_r_getprinter("", &r, &rbuf, 0))
+ goto done;
+
+ if (needed)
+ *needed = r.needed;
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ if (NT_STATUS_IS_OK(result)) {
+ switch (level) {
+ case 0:
+ decode_printer_info_0(mem_ctx, r.buffer, 1, &ctr->printers_0);
+ break;
+ case 1:
+ decode_printer_info_1(mem_ctx, r.buffer, 1, &ctr->printers_1);
+ break;
+ case 2:
+ decode_printer_info_2(mem_ctx, r.buffer, 1, &ctr->printers_2);
+ break;
+ case 3:
+ decode_printer_info_3(mem_ctx, r.buffer, 1, &ctr->printers_3);
+ break;
+ }
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/*********************************************************************************
+ Win32 API - SetPrinter()
+ ********************************************************************************/
+/** Set printer info
+ *
+ * @param cli Pointer to client state structure which is open
+ * on the SPOOLSS pipe.
+ * @param mem_ctx Pointer to an initialised talloc context.
+ *
+ * @param pol Policy handle on printer to set info.
+ * @param level Information level to set.
+ * @param ctr Pointer to structure holding printer information.
+ * @param command Specifies the action performed. See
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/prntspol_13ua.asp
+ * for details.
+ *
+ */
+
+WERROR cli_spoolss_setprinter(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, uint32 level,
+ PRINTER_INFO_CTR *ctr, uint32 command)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_SETPRINTER q;
+ SPOOL_R_SETPRINTER r;
+ WERROR result = W_ERROR(ERRgeneral);
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise input parameters */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ make_spoolss_q_setprinter(mem_ctx, &q, pol, level, ctr, command);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_setprinter("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SPOOLSS_SETPRINTER, &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if (!spoolss_io_r_setprinter("", &r, &rbuf, 0))
+ goto done;
+
+ result = r.status;
+
+done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/*********************************************************************************
+ Win32 API - GetPrinterDriver()
+ ********************************************************************************/
+/** Get installed printer drivers for a given printer
+ *
+ * @param cli Pointer to client state structure which is open
+ * on the SPOOLSS pipe.
+ *
+ * @param mem_ctx Pointer to an initialised talloc context.
+ *
+ * @param offered Buffer size offered in the request.
+ * @param needed Number of bytes needed to complete the request.
+ * may be NULL.
+ *
+ * @param pol Pointer to an open policy handle for the printer
+ * opened with cli_spoolss_open_printer_ex().
+ * @param level Requested information level.
+ * @param env The print environment or archictecture. This is
+ * "Windows NT x86" for NT4.
+ * @param ctr Returned printer driver information.
+ */
+
+WERROR cli_spoolss_getprinterdriver(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 offered, uint32 *needed,
+ POLICY_HND *pol, uint32 level,
+ char *env, PRINTER_DRIVER_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_GETPRINTERDRIVER2 q;
+ SPOOL_R_GETPRINTERDRIVER2 r;
+ NEW_BUFFER buffer;
+ WERROR result = W_ERROR(ERRgeneral);
+ fstring server;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ fstrcpy (server, cli->desthost);
+ strupper (server);
+
+ /* Initialise input parameters */
+
+ init_buffer(&buffer, offered, mem_ctx);
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ make_spoolss_q_getprinterdriver2(&q, pol, env, level, 2, 2,
+ &buffer, offered);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_getprinterdriver2 ("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req (cli, SPOOLSS_GETPRINTERDRIVER2, &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if (spoolss_io_r_getprinterdriver2 ("", &r, &rbuf, 0)) {
+ if (needed)
+ *needed = r.needed;
+ }
+
+ result = r.status;
+
+ /* Return output parameters */
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+ if (!ctr)
+ goto done;
+
+ switch (level) {
+ case 1:
+ decode_printer_driver_1(mem_ctx, r.buffer, 1, &ctr->info1);
+ break;
+ case 2:
+ decode_printer_driver_2(mem_ctx, r.buffer, 1, &ctr->info2);
+ break;
+ case 3:
+ decode_printer_driver_3(mem_ctx, r.buffer, 1, &ctr->info3);
+ break;
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/*********************************************************************************
+ Win32 API - EnumPrinterDrivers()
+ ********************************************************************************/
+/**********************************************************************
+ * Get installed printer drivers for a given printer
+ */
+WERROR cli_spoolss_enumprinterdrivers (struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 offered, uint32 *needed,
+ uint32 level, char *env,
+ uint32 *num_drivers,
+ PRINTER_DRIVER_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ENUMPRINTERDRIVERS q;
+ SPOOL_R_ENUMPRINTERDRIVERS r;
+ NEW_BUFFER buffer;
+ WERROR result = W_ERROR(ERRgeneral);
+ fstring server;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ slprintf (server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (server);
+
+ /* Initialise input parameters */
+
+ init_buffer(&buffer, offered, mem_ctx);
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Write the request */
+
+ make_spoolss_q_enumprinterdrivers(&q, server, env, level, &buffer,
+ offered);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_enumprinterdrivers ("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req (cli, SPOOLSS_ENUMPRINTERDRIVERS, &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if (!spoolss_io_r_enumprinterdrivers ("", &r, &rbuf, 0))
+ goto done;
+
+ if (needed)
+ *needed = r.needed;
+
+ if (num_drivers)
+ *num_drivers = r.returned;
+
+ result = r.status;
+
+ /* Return output parameters */
+
+ if (W_ERROR_IS_OK(result) && (r.returned != 0)) {
+ *num_drivers = r.returned;
+
+ switch (level) {
+ case 1:
+ decode_printer_driver_1(mem_ctx, r.buffer, r.returned, &ctr->info1);
+ break;
+ case 2:
+ decode_printer_driver_2(mem_ctx, r.buffer, r.returned, &ctr->info2);
+ break;
+ case 3:
+ decode_printer_driver_3(mem_ctx, r.buffer, r.returned, &ctr->info3);
+ break;
+ }
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+
+/*********************************************************************************
+ Win32 API - GetPrinterDriverDirectory()
+ ********************************************************************************/
+/**********************************************************************
+ * Get installed printer drivers for a given printer
+ */
+WERROR cli_spoolss_getprinterdriverdir (struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 offered, uint32 *needed,
+ uint32 level, char *env,
+ DRIVER_DIRECTORY_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_GETPRINTERDRIVERDIR q;
+ SPOOL_R_GETPRINTERDRIVERDIR r;
+ NEW_BUFFER buffer;
+ WERROR result = W_ERROR(ERRgeneral);
+ fstring server;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ slprintf (server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (server);
+
+ /* Initialise input parameters */
+
+ init_buffer(&buffer, offered, mem_ctx);
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Write the request */
+
+ make_spoolss_q_getprinterdriverdir(&q, server, env, level, &buffer,
+ offered);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_getprinterdriverdir ("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req (cli, SPOOLSS_GETPRINTERDRIVERDIRECTORY,
+ &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if (spoolss_io_r_getprinterdriverdir ("", &r, &rbuf, 0)) {
+ if (needed)
+ *needed = r.needed;
+ }
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ if (W_ERROR_IS_OK(result)) {
+ switch (level) {
+ case 1:
+ decode_printerdriverdir_1(mem_ctx, r.buffer, 1,
+ &ctr->info1);
+ break;
+ }
+ }
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/*********************************************************************************
+ Win32 API - AddPrinterDriver()
+ ********************************************************************************/
+/**********************************************************************
+ * Install a printer driver
+ */
+WERROR cli_spoolss_addprinterdriver (struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, uint32 level,
+ PRINTER_DRIVER_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ADDPRINTERDRIVER q;
+ SPOOL_R_ADDPRINTERDRIVER r;
+ WERROR result = W_ERROR(ERRgeneral);
+ fstring server;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ slprintf (server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (server);
+
+ /* Initialise input parameters */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Write the request */
+
+ make_spoolss_q_addprinterdriver (mem_ctx, &q, server, level, ctr);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_addprinterdriver ("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req (cli, SPOOLSS_ADDPRINTERDRIVER, &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if (!spoolss_io_r_addprinterdriver ("", &r, &rbuf, 0))
+ goto done;
+
+ /* Return output parameters */
+
+ result = r.status;
+
+done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/*********************************************************************************
+ Win32 API - AddPrinter()
+ ********************************************************************************/
+/**********************************************************************
+ * Install a printer
+ */
+WERROR cli_spoolss_addprinterex (struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ uint32 level, PRINTER_INFO_CTR*ctr)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ADDPRINTEREX q;
+ SPOOL_R_ADDPRINTEREX r;
+ WERROR result = W_ERROR(ERRgeneral);
+ fstring server,
+ client,
+ user;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ slprintf (client, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (client);
+ slprintf (server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (server);
+ fstrcpy (user, cli->user_name);
+
+ /* Initialise input parameters */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Write the request */
+
+ make_spoolss_q_addprinterex (mem_ctx, &q, server, client, user,
+ level, ctr);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_addprinterex ("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req (cli, SPOOLSS_ADDPRINTEREX, &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if (!spoolss_io_r_addprinterex ("", &r, &rbuf, 0))
+ goto done;
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/*********************************************************************************
+ Win32 API - DeltePrinterDriver()
+ ********************************************************************************/
+/**********************************************************************
+ * Delete a Printer Driver from the server (does not remove
+ * the driver files
+ */
+WERROR cli_spoolss_deleteprinterdriver (struct cli_state *cli,
+ TALLOC_CTX *mem_ctx, char *arch,
+ char *driver)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_DELETEPRINTERDRIVER q;
+ SPOOL_R_DELETEPRINTERDRIVER r;
+ WERROR result = W_ERROR(ERRgeneral);
+ fstring server;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+
+ /* Initialise input parameters */
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ slprintf (server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+ strupper (server);
+
+ /* Write the request */
+
+ make_spoolss_q_deleteprinterdriver(mem_ctx, &q, server, arch, driver);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_deleteprinterdriver ("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req (cli,SPOOLSS_DELETEPRINTERDRIVER , &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if (!spoolss_io_r_deleteprinterdriver ("", &r, &rbuf, 0))
+ goto done;
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/*********************************************************************************
+ Win32 API - GetPrinterProcessorDirectory()
+ ********************************************************************************/
+
+WERROR cli_spoolss_getprintprocessordirectory(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 offered, uint32 *needed,
+ char *name, char *environment,
+ fstring procdir)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_GETPRINTPROCESSORDIRECTORY q;
+ SPOOL_R_GETPRINTPROCESSORDIRECTORY r;
+ int level = 1;
+ WERROR result = W_ERROR(ERRgeneral);
+ NEW_BUFFER buffer;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ init_buffer(&buffer, offered, mem_ctx);
+
+ make_spoolss_q_getprintprocessordirectory(
+ &q, name, environment, level, &buffer, offered);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_getprintprocessordirectory("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SPOOLSS_GETPRINTPROCESSORDIRECTORY,
+ &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if (!spoolss_io_r_getprintprocessordirectory("", &r, &rbuf, 0))
+ goto done;
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ if (needed)
+ *needed = r.needed;
+
+ if (W_ERROR_IS_OK(result))
+ fstrcpy(procdir, "Not implemented!");
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Add a form to a printer.
+ *
+ * @param cli Pointer to client state structure which is open
+ * on the SPOOLSS pipe.
+ * @param mem_ctx Pointer to an initialised talloc context.
+ *
+ * @param handle Policy handle opened with cli_spoolss_open_printer_ex
+ * or cli_spoolss_addprinterex.
+ * @param level Form info level to add - should always be 1.
+ * @param form A pointer to the form to be added.
+ *
+ */
+
+WERROR cli_spoolss_addform(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *handle, uint32 level, FORM *form)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ADDFORM q;
+ SPOOL_R_ADDFORM r;
+ WERROR result = W_ERROR(ERRgeneral);
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ make_spoolss_q_addform(&q, handle, level, form);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_addform("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SPOOLSS_ADDFORM, &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if (!spoolss_io_r_addform("", &r, &rbuf, 0))
+ goto done;
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Set a form on a printer.
+ *
+ * @param cli Pointer to client state structure which is open
+ * on the SPOOLSS pipe.
+ * @param mem_ctx Pointer to an initialised talloc context.
+ *
+ * @param handle Policy handle opened with cli_spoolss_open_printer_ex
+ * or cli_spoolss_addprinterex.
+ * @param level Form info level to set - should always be 1.
+ * @param form A pointer to the form to be set.
+ *
+ */
+
+WERROR cli_spoolss_setform(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *handle, uint32 level, char *form_name,
+ FORM *form)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_SETFORM q;
+ SPOOL_R_SETFORM r;
+ WERROR result = W_ERROR(ERRgeneral);
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ make_spoolss_q_setform(&q, handle, level, form_name, form);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_setform("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SPOOLSS_SETFORM, &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if (!spoolss_io_r_setform("", &r, &rbuf, 0))
+ goto done;
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ if (!W_ERROR_IS_OK(result))
+ goto done;
+
+
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Get a form on a printer.
+ *
+ * @param cli Pointer to client state structure which is open
+ * on the SPOOLSS pipe.
+ * @param mem_ctx Pointer to an initialised talloc context.
+ *
+ * @param handle Policy handle opened with cli_spoolss_open_printer_ex
+ * or cli_spoolss_addprinterex.
+ * @param formname Name of the form to get
+ * @param level Form info level to get - should always be 1.
+ *
+ */
+
+WERROR cli_spoolss_getform(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ uint32 offered, uint32 *needed,
+ POLICY_HND *handle, char *formname, uint32 level,
+ FORM_1 *form)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_GETFORM q;
+ SPOOL_R_GETFORM r;
+ WERROR result = W_ERROR(ERRgeneral);
+ NEW_BUFFER buffer;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ init_buffer(&buffer, offered, mem_ctx);
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ make_spoolss_q_getform(&q, handle, formname, level, &buffer, offered);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_getform("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SPOOLSS_GETFORM, &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if (!spoolss_io_r_getform("", &r, &rbuf, 0))
+ goto done;
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ if (needed)
+ *needed = r.needed;
+
+ if (W_ERROR_IS_OK(result))
+ smb_io_form_1("", r.buffer, form, 0);
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** Delete a form on a printer.
+ *
+ * @param cli Pointer to client state structure which is open
+ * on the SPOOLSS pipe.
+ * @param mem_ctx Pointer to an initialised talloc context.
+ *
+ * @param handle Policy handle opened with cli_spoolss_open_printer_ex
+ * or cli_spoolss_addprinterex.
+ * @param form The name of the form to delete.
+ *
+ */
+
+WERROR cli_spoolss_deleteform(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *handle, char *form_name)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_DELETEFORM q;
+ SPOOL_R_DELETEFORM r;
+ WERROR result = W_ERROR(ERRgeneral);
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ make_spoolss_q_deleteform(&q, handle, form_name);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_deleteform("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SPOOLSS_DELETEFORM, &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if (!spoolss_io_r_deleteform("", &r, &rbuf, 0))
+ goto done;
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+static void decode_forms_1(TALLOC_CTX *mem_ctx, NEW_BUFFER *buffer,
+ uint32 num_forms, FORM_1 **forms)
+{
+ int i;
+
+ *forms = (FORM_1 *)talloc(mem_ctx, num_forms * sizeof(FORM_1));
+ buffer->prs.data_offset = 0;
+
+ for (i = 0; i < num_forms; i++)
+ smb_io_form_1("", buffer, &((*forms)[i]), 0);
+}
+
+/** Enumerate forms
+ *
+ * @param cli Pointer to client state structure which is open
+ * on the SPOOLSS pipe.
+ * @param mem_ctx Pointer to an initialised talloc context.
+ *
+ * @param offered Buffer size offered in the request.
+ * @param needed Number of bytes needed to complete the request.
+ * may be NULL.
+ * or cli_spoolss_addprinterex.
+ * @param level Form info level to get - should always be 1.
+ * @param handle Open policy handle
+ *
+ */
+
+WERROR cli_spoolss_enumforms(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ uint32 offered, uint32 *needed,
+ POLICY_HND *handle, int level, uint32 *num_forms,
+ FORM_1 **forms)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ENUMFORMS q;
+ SPOOL_R_ENUMFORMS r;
+ WERROR result = W_ERROR(ERRgeneral);
+ NEW_BUFFER buffer;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ init_buffer(&buffer, offered, mem_ctx);
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ make_spoolss_q_enumforms(&q, handle, level, &buffer, offered);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_enumforms("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SPOOLSS_ENUMFORMS, &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if (!spoolss_io_r_enumforms("", &r, &rbuf, 0))
+ goto done;
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ if (needed)
+ *needed = r.needed;
+
+ if (num_forms)
+ *num_forms = r.numofforms;
+
+ decode_forms_1(mem_ctx, r.buffer, *num_forms, forms);
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/*********************************************************************************
+ Win32 API - SetPrinterData()
+ ********************************************************************************/
+
+WERROR cli_spoolss_setprinterdata (struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ POLICY_HND *pol, char* valname, char* value)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_SETPRINTERDATA q;
+ SPOOL_R_SETPRINTERDATA r;
+ WERROR result = W_ERROR(ERRgeneral);
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise input parameters */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+
+ /* write the request */
+ make_spoolss_q_setprinterdata(&q, mem_ctx, pol, valname, value);
+
+ /* Marshall data and send request */
+ if (!spoolss_io_q_setprinterdata ("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req (cli, SPOOLSS_SETPRINTERDATA, &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+ if (spoolss_io_r_setprinterdata ("", &r, &rbuf, 0))
+ goto done;
+
+ result = r.status;
+
+done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/* Enumerate jobs */
+
+WERROR cli_spoolss_enumjobs(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ uint32 offered, uint32 *needed,
+ POLICY_HND *hnd, uint32 firstjob, uint32 numofjobs,
+ uint32 level)
+{
+ prs_struct qbuf, rbuf;
+ SPOOL_Q_ENUMJOBS q;
+ SPOOL_R_ENUMJOBS r;
+ WERROR result = W_ERROR(ERRgeneral);
+ NEW_BUFFER buffer;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ init_buffer(&buffer, offered, mem_ctx);
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ make_spoolss_q_enumjobs(&q, hnd, firstjob, numofjobs, level, &buffer,
+ offered);
+
+ /* Marshall data and send request */
+
+ if (!spoolss_io_q_enumjobs("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SPOOLSS_ENUMJOBS, &qbuf, &rbuf))
+ goto done;
+
+ /* Unmarshall response */
+
+ if (!spoolss_io_r_enumjobs("", &r, &rbuf, 0))
+ goto done;
+
+ /* Return output parameters */
+
+ result = r.status;
+
+ if (needed)
+ *needed = r.needed;
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
+
+/** @} **/
diff --git a/source3/libsmb/cli_srvsvc.c b/source3/libsmb/cli_srvsvc.c
new file mode 100644
index 0000000000..9d33149540
--- /dev/null
+++ b/source3/libsmb/cli_srvsvc.c
@@ -0,0 +1,79 @@
+/*
+ Unix SMB/CIFS implementation.
+ NT Domain Authentication SMB / MSRPC client
+ Copyright (C) Andrew Tridgell 1994-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Tim Potter 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"
+
+/* Opens a SMB connection to the svrsvc pipe */
+
+struct cli_state *cli_svrsvc_initialise(struct cli_state *cli,
+ char *system_name,
+ struct ntuser_creds *creds)
+{
+ return cli_pipe_initialise(cli, system_name, PIPE_SRVSVC, creds);
+}
+
+NTSTATUS cli_srvsvc_net_srv_get_info(struct cli_state *cli,
+ TALLOC_CTX *mem_ctx,
+ uint32 switch_value, SRV_INFO_CTR *ctr)
+{
+ prs_struct qbuf, rbuf;
+ SRV_Q_NET_SRV_GET_INFO q;
+ SRV_R_NET_SRV_GET_INFO r;
+ NTSTATUS result;
+
+ ZERO_STRUCT(q);
+ ZERO_STRUCT(r);
+
+ /* Initialise parse structures */
+
+ prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ /* Initialise input parameters */
+
+ init_srv_q_net_srv_get_info(&q, cli->srv_name_slash, switch_value);
+
+ /* Marshall data and send request */
+
+ if (!srv_io_q_net_srv_get_info("", &q, &qbuf, 0) ||
+ !rpc_api_pipe_req(cli, SRV_NET_SRV_GET_INFO, &qbuf, &rbuf)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ /* Unmarshall response */
+
+ r.ctr = ctr;
+
+ if (!srv_io_r_net_srv_get_info("", &r, &rbuf, 0)) {
+ result = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ result = werror_to_ntstatus(r.status);
+
+ done:
+ prs_mem_free(&qbuf);
+ prs_mem_free(&rbuf);
+
+ return result;
+}
diff --git a/source3/libsmb/cli_wkssvc.c b/source3/libsmb/cli_wkssvc.c
new file mode 100644
index 0000000000..2a84e6b698
--- /dev/null
+++ b/source3/libsmb/cli_wkssvc.c
@@ -0,0 +1,112 @@
+/*
+ Unix SMB/CIFS implementation.
+ NT Domain Authentication SMB / MSRPC client
+ Copyright (C) Andrew Tridgell 1994-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Tim Potter 2001
+ Copytight (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"
+
+/**
+ * Opens a SMB connection to the wkssvc pipe
+ *
+ * @param cli client structure (not yet initialised)
+ * @param system_name called rpc server name
+ * @param creds user credentials
+ *
+ * @return client structure with opened pipe
+ **/
+
+struct cli_state *cli_wkssvc_initialise(struct cli_state *cli,
+ char *system_name,
+ struct ntuser_creds *creds)
+{
+ return cli_pipe_initialise(cli, system_name, PIPE_WKSSVC, creds);
+}
+
+
+/**
+ * WksQueryInfo rpc call (like query for server's capabilities)
+ *
+ * @param initialised client structure with \PIPE\wkssvc opened
+ * @param mem_ctx memory context assigned to this rpc binding
+ * @param wks100 WksQueryInfo structure
+ *
+ * @return NTSTATUS of rpc call
+ */
+
+NTSTATUS cli_wks_query_info(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ WKS_INFO_100 *wks100)
+{
+ prs_struct buf;
+ prs_struct rbuf;
+ WKS_Q_QUERY_INFO q_o;
+ WKS_R_QUERY_INFO r_o;
+ NTSTATUS nt_status;
+
+ if (cli == NULL || wks100 == NULL)
+ return NT_STATUS_UNSUCCESSFUL;
+
+ /* init rpc parse structures */
+ prs_init(&buf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+ prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+ DEBUG(4, ("WksQueryInfo\n"));
+
+ /* init query structure with rpc call arguments */
+ init_wks_q_query_info(&q_o, cli->desthost, 100);
+
+ /* marshall data */
+ if (!wks_io_q_query_info("", &q_o, &buf, 0)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* actual rpc call over \PIPE\wkssvc */
+ if (!rpc_api_pipe_req(cli, WKS_QUERY_INFO, &buf, &rbuf)) {
+ prs_mem_free(&buf);
+ prs_mem_free(&rbuf);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ prs_mem_free(&buf);
+
+ r_o.wks100 = wks100;
+
+ /* get call results from response buffer */
+ if (!wks_io_r_query_info("", &r_o, &rbuf, 0)) {
+ prs_mem_free(&rbuf);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* check returnet status code */
+ if (NT_STATUS_IS_ERR(r_o.status)) {
+ /* report the error */
+ DEBUG(0,("WKS_R_QUERY_INFO: %s\n", nt_errstr(r_o.status)));
+ prs_mem_free(&rbuf);
+ return r_o.status;
+ }
+
+ /* do clean up */
+ prs_mem_free(&rbuf);
+
+ return nt_status;
+}
+
diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c
new file mode 100644
index 0000000000..8ddd116679
--- /dev/null
+++ b/source3/libsmb/cliconnect.c
@@ -0,0 +1,1348 @@
+/*
+ Unix SMB/CIFS implementation.
+ client connect/disconnect 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.
+*/
+
+#define NO_SYSLOG
+
+#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_LANMAN2,"LM1.2X002"},
+ {PROTOCOL_LANMAN2,"Samba"},
+ {PROTOCOL_NT1,"NT LANMAN 1.0"},
+ {PROTOCOL_NT1,"NT LM 0.12"},
+ {-1,NULL}
+ };
+
+
+/****************************************************************************
+do an old lanman2 style session setup
+****************************************************************************/
+static BOOL cli_session_setup_lanman2(struct cli_state *cli, char *user,
+ char *pass, int passlen)
+{
+ fstring pword;
+ char *p;
+
+ if (passlen > sizeof(pword)-1) {
+ return False;
+ }
+
+ /* if in share level security then don't send a password now */
+ if (!(cli->sec_mode & 1)) {
+ passlen = 0;
+ }
+
+ if (passlen > 0 && (cli->sec_mode & 2) && passlen != 24) {
+ /* Encrypted mode needed, and non encrypted password supplied. */
+ passlen = 24;
+ clistr_push(cli, pword, pass, -1, STR_TERMINATE);
+ SMBencrypt((uchar *)pword,cli->secblob.data,(uchar *)pword);
+ } else if ((cli->sec_mode & 2) && passlen == 24) {
+ /* Encrypted mode needed, and encrypted password supplied. */
+ memcpy(pword, pass, passlen);
+ } else if (passlen > 0) {
+ /* Plaintext mode needed, assume plaintext supplied. */
+ passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
+ }
+
+ /* send a session setup command */
+ memset(cli->outbuf,'\0',smb_size);
+ set_message(cli->outbuf,10, 0, True);
+ SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
+ SSVAL(cli->outbuf,smb_vwv3,2);
+ SSVAL(cli->outbuf,smb_vwv4,1);
+ SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
+ SSVAL(cli->outbuf,smb_vwv7,passlen);
+
+ p = smb_buf(cli->outbuf);
+ memcpy(p,pword,passlen);
+ p += passlen;
+ p += clistr_push(cli, p, user, -1, STR_TERMINATE);
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ /* use the returned vuid from now on */
+ cli->vuid = SVAL(cli->inbuf,smb_uid);
+ fstrcpy(cli->user_name, user);
+
+ return True;
+}
+
+
+/****************************************************************************
+work out suitable capabilities to offer the server
+****************************************************************************/
+static uint32 cli_session_setup_capabilities(struct cli_state *cli)
+{
+ uint32 capabilities = CAP_NT_SMBS;
+
+ if (!cli->force_dos_errors) {
+ capabilities |= CAP_STATUS32;
+ }
+
+ if (cli->use_level_II_oplocks) {
+ capabilities |= CAP_LEVEL_II_OPLOCKS;
+ }
+
+ if (cli->capabilities & CAP_UNICODE) {
+ capabilities |= CAP_UNICODE;
+ }
+
+ return capabilities;
+}
+
+
+/****************************************************************************
+do a NT1 guest session setup
+****************************************************************************/
+static BOOL cli_session_setup_guest(struct cli_state *cli)
+{
+ char *p;
+ uint32 capabilities = cli_session_setup_capabilities(cli);
+
+ set_message(cli->outbuf,13,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
+ SSVAL(cli->outbuf,smb_vwv3,2);
+ SSVAL(cli->outbuf,smb_vwv4,cli->pid);
+ SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
+ SSVAL(cli->outbuf,smb_vwv7,0);
+ SSVAL(cli->outbuf,smb_vwv8,0);
+ SIVAL(cli->outbuf,smb_vwv11,capabilities);
+ p = smb_buf(cli->outbuf);
+ p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* username */
+ p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* workgroup */
+ p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
+ p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ cli->vuid = SVAL(cli->inbuf,smb_uid);
+
+ p = smb_buf(cli->inbuf);
+ p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
+
+ fstrcpy(cli->user_name, "");
+
+ return True;
+}
+
+
+/****************************************************************************
+do a NT1 plaintext session setup
+****************************************************************************/
+static BOOL cli_session_setup_plaintext(struct cli_state *cli, char *user,
+ char *pass, char *workgroup)
+{
+ uint32 capabilities = cli_session_setup_capabilities(cli);
+ fstring pword;
+ int passlen;
+ char *p;
+
+ passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE|STR_ASCII);
+
+ set_message(cli->outbuf,13,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
+ SSVAL(cli->outbuf,smb_vwv3,2);
+ SSVAL(cli->outbuf,smb_vwv4,cli->pid);
+ SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
+ SSVAL(cli->outbuf,smb_vwv7,passlen);
+ SSVAL(cli->outbuf,smb_vwv8,0);
+ SIVAL(cli->outbuf,smb_vwv11,capabilities);
+ p = smb_buf(cli->outbuf);
+ memcpy(p, pword, passlen);
+ p += passlen;
+ p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
+ p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
+ p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
+ p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ cli->vuid = SVAL(cli->inbuf,smb_uid);
+ p = smb_buf(cli->inbuf);
+ p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
+ fstrcpy(cli->user_name, user);
+
+ return True;
+}
+
+
+/****************************************************************************
+do a NT1 NTLM/LM encrypted session setup
+****************************************************************************/
+static BOOL cli_session_setup_nt1(struct cli_state *cli, char *user,
+ char *pass, int passlen,
+ char *ntpass, int ntpasslen,
+ char *workgroup)
+{
+ uint32 capabilities = cli_session_setup_capabilities(cli);
+ fstring pword, ntpword;
+ char *p;
+
+ if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) {
+ return False;
+ }
+
+ if (passlen != 24) {
+ /* non encrypted password supplied. Ignore ntpass. */
+ passlen = 24;
+ ntpasslen = 24;
+ clistr_push(cli, pword,
+ pass?pass:"", sizeof(pword), STR_TERMINATE|STR_ASCII);
+ clistr_push(cli, ntpword,
+ pass?pass:"", sizeof(ntpword), STR_TERMINATE|STR_ASCII);
+ SMBencrypt((uchar *)pword,cli->secblob.data,(uchar *)pword);
+ SMBNTencrypt((uchar *)ntpword,cli->secblob.data,(uchar *)ntpword);
+ } else {
+ memcpy(pword, pass, passlen);
+ memcpy(ntpword, ntpass, ntpasslen);
+ }
+
+ /* send a session setup command */
+ memset(cli->outbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,13,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
+ SSVAL(cli->outbuf,smb_vwv3,2);
+ SSVAL(cli->outbuf,smb_vwv4,cli->pid);
+ SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
+ SSVAL(cli->outbuf,smb_vwv7,passlen);
+ SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
+ SIVAL(cli->outbuf,smb_vwv11,capabilities);
+ p = smb_buf(cli->outbuf);
+ memcpy(p,pword,passlen); p += passlen;
+ memcpy(p,ntpword,ntpasslen); p += ntpasslen;
+ p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
+ p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
+ p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
+ p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ /* use the returned vuid from now on */
+ cli->vuid = SVAL(cli->inbuf,smb_uid);
+
+ p = smb_buf(cli->inbuf);
+ p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
+ p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
+
+ fstrcpy(cli->user_name, user);
+
+ return True;
+}
+
+
+/****************************************************************************
+send a extended security session setup blob, returning a reply blob
+****************************************************************************/
+static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
+{
+ uint32 capabilities = cli_session_setup_capabilities(cli);
+ char *p;
+ DATA_BLOB blob2;
+ uint32 len;
+
+ blob2 = data_blob(NULL, 0);
+
+ capabilities |= CAP_EXTENDED_SECURITY;
+
+ /* send a session setup command */
+ memset(cli->outbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,12,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
+ SSVAL(cli->outbuf,smb_vwv3,2);
+ SSVAL(cli->outbuf,smb_vwv4,1);
+ SIVAL(cli->outbuf,smb_vwv5,0);
+ SSVAL(cli->outbuf,smb_vwv7,blob.length);
+ SIVAL(cli->outbuf,smb_vwv10,capabilities);
+ p = smb_buf(cli->outbuf);
+ memcpy(p, blob.data, blob.length);
+ p += blob.length;
+ p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
+ p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return blob2;
+
+ show_msg(cli->inbuf);
+
+ if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
+ NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ return blob2;
+ }
+
+ /* use the returned vuid from now on */
+ cli->vuid = SVAL(cli->inbuf,smb_uid);
+
+ p = smb_buf(cli->inbuf);
+
+ blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
+
+ p += blob2.length;
+ p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
+
+ /* w2k with kerberos doesn't properly null terminate this field */
+ len = smb_buflen(cli->inbuf) - PTR_DIFF(p, smb_buf(cli->inbuf));
+ p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), len, 0);
+
+ return blob2;
+}
+
+
+#ifdef HAVE_KRB5
+/****************************************************************************
+do a spnego/kerberos encrypted session setup
+****************************************************************************/
+static BOOL cli_session_setup_kerberos(struct cli_state *cli, char *principal, char *workgroup)
+{
+ DATA_BLOB blob2, negTokenTarg;
+
+ DEBUG(2,("Doing kerberos session setup\n"));
+
+ /* generate the encapsulated kerberos5 ticket */
+ negTokenTarg = spnego_gen_negTokenTarg(cli, principal);
+
+ if (!negTokenTarg.data) return False;
+
+#if 0
+ file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
+#endif
+
+ blob2 = cli_session_setup_blob(cli, negTokenTarg);
+
+ /* we don't need this blob for kerberos */
+ data_blob_free(&blob2);
+
+ data_blob_free(&negTokenTarg);
+
+ return !cli_is_error(cli);
+}
+#endif
+
+/****************************************************************************
+do a spnego/NTLMSSP encrypted session setup
+****************************************************************************/
+static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, char *user,
+ char *pass, char *workgroup)
+{
+ const char *mechs[] = {OID_NTLMSSP, NULL};
+ DATA_BLOB msg1;
+ DATA_BLOB blob, chal1, chal2, auth;
+ uint8 challenge[8];
+ uint8 nthash[24], lmhash[24], sess_key[16];
+ uint32 neg_flags;
+
+ neg_flags = NTLMSSP_NEGOTIATE_UNICODE |
+ NTLMSSP_NEGOTIATE_LM_KEY |
+ NTLMSSP_NEGOTIATE_NTLM;
+
+ memset(sess_key, 0, 16);
+
+ /* generate the ntlmssp negotiate packet */
+ msrpc_gen(&blob, "CddB",
+ "NTLMSSP",
+ NTLMSSP_NEGOTIATE,
+ neg_flags,
+ sess_key, 16);
+
+ /* and wrap it in a SPNEGO wrapper */
+ msg1 = gen_negTokenTarg(mechs, blob);
+ data_blob_free(&blob);
+
+ /* now send that blob on its way */
+ blob = cli_session_setup_blob(cli, msg1);
+
+ data_blob_free(&msg1);
+
+ if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ return False;
+ }
+
+#if 0
+ file_save("chal.dat", blob.data, blob.length);
+#endif
+
+ /* the server gives us back two challenges */
+ if (!spnego_parse_challenge(blob, &chal1, &chal2)) {
+ DEBUG(3,("Failed to parse challenges\n"));
+ return False;
+ }
+
+ data_blob_free(&blob);
+
+ /* encrypt the password with the challenge */
+ memcpy(challenge, chal1.data + 24, 8);
+ SMBencrypt((unsigned char *)pass, challenge,lmhash);
+ SMBNTencrypt((unsigned char *)pass, challenge,nthash);
+
+#if 0
+ file_save("nthash.dat", nthash, 24);
+ file_save("lmhash.dat", lmhash, 24);
+ file_save("chal1.dat", chal1.data, chal1.length);
+#endif
+
+ data_blob_free(&chal1);
+ data_blob_free(&chal2);
+
+ /* this generates the actual auth packet */
+ msrpc_gen(&blob, "CdBBUUUBd",
+ "NTLMSSP",
+ NTLMSSP_AUTH,
+ lmhash, 24,
+ nthash, 24,
+ workgroup,
+ user,
+ cli->calling.name,
+ sess_key, 16,
+ neg_flags);
+
+ /* wrap it in SPNEGO */
+ auth = spnego_gen_auth(blob);
+
+ data_blob_free(&blob);
+
+ /* now send the auth packet and we should be done */
+ blob = cli_session_setup_blob(cli, auth);
+
+ data_blob_free(&auth);
+ data_blob_free(&blob);
+
+ return !cli_is_error(cli);
+}
+
+
+/****************************************************************************
+do a spnego encrypted session setup
+****************************************************************************/
+static BOOL cli_session_setup_spnego(struct cli_state *cli, char *user,
+ char *pass, char *workgroup)
+{
+ char *principal;
+ char *OIDs[ASN1_MAX_OIDS];
+ uint8 guid[16];
+ int i;
+ BOOL got_kerberos_mechanism = False;
+
+ DEBUG(2,("Doing spnego session setup (blob length=%d)\n", cli->secblob.length));
+
+ /* the server might not even do spnego */
+ if (cli->secblob.length == 16) {
+ DEBUG(3,("server didn't supply a full spnego negprot\n"));
+ goto ntlmssp;
+ }
+
+#if 0
+ file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
+#endif
+
+ /* the server sent us the first part of the SPNEGO exchange in the negprot
+ reply */
+ if (!spnego_parse_negTokenInit(cli->secblob, guid, OIDs, &principal)) {
+ return False;
+ }
+
+ /* make sure the server understands kerberos */
+ for (i=0;OIDs[i];i++) {
+ DEBUG(3,("got OID=%s\n", OIDs[i]));
+ if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
+ strcmp(OIDs[i], OID_KERBEROS5) == 0) {
+ got_kerberos_mechanism = True;
+ }
+ free(OIDs[i]);
+ }
+ DEBUG(3,("got principal=%s\n", principal));
+
+ fstrcpy(cli->user_name, user);
+
+#ifdef HAVE_KRB5
+ if (got_kerberos_mechanism && cli->use_kerberos) {
+ return cli_session_setup_kerberos(cli, principal, workgroup);
+ }
+#endif
+
+ free(principal);
+
+ntlmssp:
+
+ return cli_session_setup_ntlmssp(cli, user, pass, workgroup);
+}
+
+
+/****************************************************************************
+ Send a session setup. The username and workgroup is in UNIX character
+ format and must be converted to DOS codepage format before sending. If the
+ password is in plaintext, the same should be done.
+****************************************************************************/
+BOOL cli_session_setup(struct cli_state *cli,
+ char *user,
+ char *pass, int passlen,
+ char *ntpass, int ntpasslen,
+ char *workgroup)
+{
+ char *p;
+ fstring user2;
+
+ /* allow for workgroups as part of the username */
+ fstrcpy(user2, user);
+ if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
+ (p=strchr_m(user2,*lp_winbind_separator()))) {
+ *p = 0;
+ user = p+1;
+ workgroup = user2;
+ }
+
+ if (cli->protocol < PROTOCOL_LANMAN1)
+ return True;
+
+ /* now work out what sort of session setup we are going to
+ do. I have split this into separate functions to make the
+ flow a bit easier to understand (tridge) */
+
+ /* if its an older server then we have to use the older request format */
+ if (cli->protocol < PROTOCOL_NT1) {
+ return cli_session_setup_lanman2(cli, user, pass, passlen);
+ }
+
+ /* if no user is supplied then we have to do an anonymous connection.
+ passwords are ignored */
+ if (!user || !*user) {
+ return cli_session_setup_guest(cli);
+ }
+
+ /* if the server is share level then send a plaintext null
+ password at this point. The password is sent in the tree
+ connect */
+ if ((cli->sec_mode & 1) == 0) {
+ return cli_session_setup_plaintext(cli, user, "", workgroup);
+ }
+
+ /* if the server doesn't support encryption then we have to use plaintext. The
+ second password is ignored */
+ if ((cli->sec_mode & 2) == 0) {
+ return cli_session_setup_plaintext(cli, user, pass, workgroup);
+ }
+
+ /* if the server supports extended security then use SPNEGO */
+ if (cli->capabilities & CAP_EXTENDED_SECURITY) {
+ return cli_session_setup_spnego(cli, user, pass, workgroup);
+ }
+
+ /* otherwise do a NT1 style session setup */
+ return cli_session_setup_nt1(cli, user,
+ pass, passlen, ntpass, ntpasslen,
+ workgroup);
+}
+
+/****************************************************************************
+ Send a uloggoff.
+*****************************************************************************/
+
+BOOL cli_ulogoff(struct cli_state *cli)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ set_message(cli->outbuf,2,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBulogoffX);
+ cli_setup_packet(cli);
+ SSVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ return !cli_is_error(cli);
+}
+
+/****************************************************************************
+send a tconX
+****************************************************************************/
+BOOL cli_send_tconX(struct cli_state *cli,
+ const char *share, const char *dev, const char *pass, int passlen)
+{
+ fstring fullshare, pword, dos_pword;
+ char *p;
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ fstrcpy(cli->share, share);
+
+ /* in user level security don't send a password now */
+ if (cli->sec_mode & 1) {
+ passlen = 1;
+ pass = "";
+ }
+
+ if ((cli->sec_mode & 2) && *pass && passlen != 24) {
+ /*
+ * Non-encrypted passwords - convert to DOS codepage before encryption.
+ */
+ passlen = 24;
+ clistr_push(cli, dos_pword, pass, -1, STR_TERMINATE);
+ SMBencrypt((uchar *)dos_pword,cli->secblob.data,(uchar *)pword);
+ } else {
+ if((cli->sec_mode & 3) == 0) {
+ /*
+ * Non-encrypted passwords - convert to DOS codepage before using.
+ */
+ passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
+ } else {
+ memcpy(pword, pass, passlen);
+ }
+ }
+
+ if (cli->port == 445) {
+ slprintf(fullshare, sizeof(fullshare)-1,
+ "%s", share);
+ } else {
+ slprintf(fullshare, sizeof(fullshare)-1,
+ "\\\\%s\\%s", cli->desthost, share);
+ }
+
+ set_message(cli->outbuf,4, 0, True);
+ SCVAL(cli->outbuf,smb_com,SMBtconX);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv3,passlen);
+
+ p = smb_buf(cli->outbuf);
+ memcpy(p,pword,passlen);
+ p += passlen;
+ p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
+ fstrcpy(p, dev); p += strlen(dev)+1;
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
+
+ if (strcasecmp(share,"IPC$")==0) {
+ fstrcpy(cli->dev, "IPC");
+ }
+
+ if (cli->protocol >= PROTOCOL_NT1 &&
+ smb_buflen(cli->inbuf) == 3) {
+ /* almost certainly win95 - enable bug fixes */
+ cli->win95 = True;
+ }
+
+ cli->cnum = SVAL(cli->inbuf,smb_tid);
+ return True;
+}
+
+
+/****************************************************************************
+send a tree disconnect
+****************************************************************************/
+BOOL cli_tdis(struct cli_state *cli)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ set_message(cli->outbuf,0,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBtdis);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ return !cli_is_error(cli);
+}
+
+
+/****************************************************************************
+send a negprot command
+****************************************************************************/
+void cli_negprot_send(struct cli_state *cli)
+{
+ char *p;
+ int numprots;
+
+ memset(cli->outbuf,'\0',smb_size);
+
+ /* setup the protocol strings */
+ set_message(cli->outbuf,0,0,True);
+
+ p = smb_buf(cli->outbuf);
+ for (numprots=0;
+ prots[numprots].name && prots[numprots].prot<=cli->protocol;
+ numprots++) {
+ *p++ = 2;
+ p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
+ }
+
+ SCVAL(cli->outbuf,smb_com,SMBnegprot);
+ cli_setup_bcc(cli, p);
+ cli_setup_packet(cli);
+
+ SCVAL(smb_buf(cli->outbuf),0,2);
+
+ cli_send_smb(cli);
+}
+
+
+/****************************************************************************
+send a negprot command
+****************************************************************************/
+BOOL cli_negprot(struct cli_state *cli)
+{
+ char *p;
+ int numprots;
+ int plength;
+
+ memset(cli->outbuf,'\0',smb_size);
+
+ /* setup the protocol strings */
+ for (plength=0,numprots=0;
+ prots[numprots].name && prots[numprots].prot<=cli->protocol;
+ numprots++)
+ plength += strlen(prots[numprots].name)+2;
+
+ set_message(cli->outbuf,0,plength,True);
+
+ p = smb_buf(cli->outbuf);
+ for (numprots=0;
+ prots[numprots].name && prots[numprots].prot<=cli->protocol;
+ numprots++) {
+ *p++ = 2;
+ p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
+ }
+
+ SCVAL(cli->outbuf,smb_com,SMBnegprot);
+ cli_setup_packet(cli);
+
+ SCVAL(smb_buf(cli->outbuf),0,2);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ if (cli_is_error(cli) ||
+ ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
+ return(False);
+ }
+
+ cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
+
+ if (cli->protocol >= PROTOCOL_NT1) {
+ /* NT protocol */
+ cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
+ cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
+ cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
+ cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
+ cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
+ cli->serverzone *= 60;
+ /* this time arrives in real GMT */
+ cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
+ cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
+ cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
+ if (cli->capabilities & CAP_RAW_MODE) {
+ cli->readbraw_supported = True;
+ cli->writebraw_supported = True;
+ }
+ /* work out if they sent us a workgroup */
+ if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
+ smb_buflen(cli->inbuf) > 8) {
+ clistr_pull(cli, cli->server_domain,
+ smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
+ smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
+ }
+ } else if (cli->protocol >= PROTOCOL_LANMAN1) {
+ cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
+ cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
+ cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
+ cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
+ cli->serverzone *= 60;
+ /* this time is converted to GMT by make_unix_date */
+ cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
+ cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
+ cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
+ cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
+ } else {
+ /* the old core protocol */
+ cli->sec_mode = 0;
+ cli->serverzone = TimeDiff(time(NULL));
+ }
+
+ cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
+
+ /* a way to force ascii SMB */
+ if (getenv("CLI_FORCE_ASCII")) {
+ cli->capabilities &= ~CAP_UNICODE;
+ }
+
+ return True;
+}
+
+
+/****************************************************************************
+ send a session request. see rfc1002.txt 4.3 and 4.3.2
+****************************************************************************/
+BOOL cli_session_request(struct cli_state *cli,
+ struct nmb_name *calling, struct nmb_name *called)
+{
+ char *p;
+ int len = 4;
+ extern pstring user_socket_options;
+
+ /* 445 doesn't have session request */
+ if (cli->port == 445) return True;
+
+ /* send a session request (RFC 1002) */
+ memcpy(&(cli->calling), calling, sizeof(*calling));
+ memcpy(&(cli->called ), called , sizeof(*called ));
+
+ /* put in the destination name */
+ p = cli->outbuf+len;
+ name_mangle(cli->called .name, p, cli->called .name_type);
+ len += name_len(p);
+
+ /* and my name */
+ p = cli->outbuf+len;
+ name_mangle(cli->calling.name, p, cli->calling.name_type);
+ len += name_len(p);
+
+ /* setup the packet length */
+ _smb_setlen(cli->outbuf,len);
+ SCVAL(cli->outbuf,0,0x81);
+
+#ifdef WITH_SSL
+retry:
+#endif /* WITH_SSL */
+
+ cli_send_smb(cli);
+ DEBUG(5,("Sent session request\n"));
+
+ if (!cli_receive_smb(cli))
+ return False;
+
+ if (CVAL(cli->inbuf,0) == 0x84) {
+ /* C. Hoch 9/14/95 Start */
+ /* For information, here is the response structure.
+ * We do the byte-twiddling to for portability.
+ struct RetargetResponse{
+ unsigned char type;
+ unsigned char flags;
+ int16 length;
+ int32 ip_addr;
+ int16 port;
+ };
+ */
+ int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
+ /* SESSION RETARGET */
+ putip((char *)&cli->dest_ip,cli->inbuf+4);
+
+ cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
+ if (cli->fd == -1)
+ return False;
+
+ DEBUG(3,("Retargeted\n"));
+
+ set_socket_options(cli->fd,user_socket_options);
+
+ /* Try again */
+ {
+ static int depth;
+ BOOL ret;
+ if (depth > 4) {
+ DEBUG(0,("Retarget recursion - failing\n"));
+ return False;
+ }
+ depth++;
+ ret = cli_session_request(cli, calling, called);
+ depth--;
+ return ret;
+ }
+ } /* C. Hoch 9/14/95 End */
+
+#ifdef WITH_SSL
+ if (CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
+ if (!sslutil_fd_is_ssl(cli->fd)){
+ if (sslutil_connect(cli->fd) == 0)
+ goto retry;
+ }
+ }
+#endif /* WITH_SSL */
+
+ if (CVAL(cli->inbuf,0) != 0x82) {
+ /* This is the wrong place to put the error... JRA. */
+ cli->rap_error = CVAL(cli->inbuf,4);
+ return False;
+ }
+ return(True);
+}
+
+/****************************************************************************
+open the client sockets
+****************************************************************************/
+BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
+{
+ extern pstring user_socket_options;
+ int name_type = 0x20;
+ char *p;
+
+ /* reasonable default hostname */
+ if (!host) host = "*SMBSERVER";
+
+ fstrcpy(cli->desthost, host);
+
+ /* allow hostnames of the form NAME#xx and do a netbios lookup */
+ if ((p = strchr(cli->desthost, '#'))) {
+ name_type = strtol(p+1, NULL, 16);
+ *p = 0;
+ }
+
+ if (!ip || is_zero_ip(*ip)) {
+ if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
+ return False;
+ }
+ if (ip) *ip = cli->dest_ip;
+ } else {
+ cli->dest_ip = *ip;
+ }
+
+ if (getenv("LIBSMB_PROG")) {
+ cli->fd = sock_exec(getenv("LIBSMB_PROG"));
+ } else {
+ /* try 445 first, then 139 */
+ int port = cli->port?cli->port:445;
+ cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
+ port, cli->timeout);
+ if (cli->fd == -1 && cli->port == 0) {
+ port = 139;
+ cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
+ port, cli->timeout);
+ }
+ if (cli->fd != -1) cli->port = port;
+ }
+ if (cli->fd == -1) {
+ DEBUG(1,("Error connecting to %s (%s)\n",
+ inet_ntoa(*ip),strerror(errno)));
+ return False;
+ }
+
+ set_socket_options(cli->fd,user_socket_options);
+
+ return True;
+}
+
+/****************************************************************************
+establishes a connection right up to doing tconX, password in cache.
+****************************************************************************/
+BOOL cli_establish_connection(struct cli_state *cli,
+ char *dest_host, struct in_addr *dest_ip,
+ struct nmb_name *calling, struct nmb_name *called,
+ char *service, char *service_type,
+ BOOL do_shutdown, BOOL do_tcon)
+{
+ DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
+ nmb_namestr(calling), nmb_namestr(called), inet_ntoa(*dest_ip),
+ cli->user_name, cli->domain));
+
+ /* establish connection */
+
+ if ((!cli->initialised))
+ {
+ return False;
+ }
+
+ /* cli_establish_connection() can't handle spnego yet. Once we get rid of
+ pwd_cache and other horrors we can get rid of this */
+ cli->use_spnego = False;
+
+ if (cli->fd == -1)
+ {
+ if (!cli_connect(cli, dest_host, dest_ip))
+ {
+ DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
+ nmb_namestr(called), inet_ntoa(*dest_ip)));
+ return False;
+ }
+ }
+
+ if (!cli_session_request(cli, calling, called))
+ {
+ DEBUG(1,("failed session request\n"));
+ if (do_shutdown)
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (!cli_negprot(cli))
+ {
+ DEBUG(1,("failed negprot\n"));
+ if (do_shutdown)
+ cli_shutdown(cli);
+ return False;
+ }
+
+ if (cli->pwd.cleartext || cli->pwd.null_pwd)
+ {
+ fstring passwd;
+ int pass_len;
+
+ if (cli->pwd.null_pwd)
+ {
+ /* attempt null session */
+ passwd[0] = 0;
+ pass_len = 1;
+ }
+ else
+ {
+ /* attempt clear-text session */
+ pwd_get_cleartext(&(cli->pwd), passwd);
+ pass_len = strlen(passwd);
+ }
+
+ /* attempt clear-text session */
+ if (!cli_session_setup(cli, cli->user_name,
+ passwd, pass_len,
+ NULL, 0,
+ cli->domain))
+ {
+ DEBUG(1,("failed session setup\n"));
+ if (do_shutdown)
+ {
+ cli_shutdown(cli);
+ }
+ return False;
+ }
+ if (do_tcon)
+ {
+ if (!cli_send_tconX(cli, service, service_type,
+ (char*)passwd, strlen(passwd)))
+ {
+ DEBUG(1,("failed tcon_X\n"));
+ if (do_shutdown)
+ {
+ cli_shutdown(cli);
+ }
+ return False;
+ }
+ }
+ }
+ else
+ {
+ /* attempt encrypted session */
+ unsigned char nt_sess_pwd[24];
+ unsigned char lm_sess_pwd[24];
+
+ /* creates (storing a copy of) and then obtains a 24 byte password OWF */
+ pwd_make_lm_nt_owf(&(cli->pwd), cli->secblob.data);
+ pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd);
+
+ /* attempt encrypted session */
+ if (!cli_session_setup(cli, cli->user_name,
+ (char*)lm_sess_pwd, sizeof(lm_sess_pwd),
+ (char*)nt_sess_pwd, sizeof(nt_sess_pwd),
+ cli->domain))
+ {
+ DEBUG(1,("failed session setup\n"));
+ if (do_shutdown)
+ cli_shutdown(cli);
+ return False;
+ }
+
+ DEBUG(1,("session setup ok\n"));
+
+ if (*cli->server_domain || *cli->server_os || *cli->server_type)
+ {
+ DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
+ cli->server_domain,
+ cli->server_os,
+ cli->server_type));
+ }
+
+ if (do_tcon)
+ {
+ if (!cli_send_tconX(cli, service, service_type,
+ (char*)nt_sess_pwd, sizeof(nt_sess_pwd)))
+ {
+ DEBUG(1,("failed tcon_X\n"));
+ if (do_shutdown)
+ cli_shutdown(cli);
+ return False;
+ }
+ }
+ }
+
+ if (do_shutdown)
+ cli_shutdown(cli);
+
+ return True;
+}
+
+/* Initialise client credentials for authenticated pipe access */
+
+static void init_creds(struct ntuser_creds *creds, char* username,
+ char* domain, char* password, int pass_len)
+{
+ ZERO_STRUCTP(creds);
+
+ pwd_set_cleartext(&creds->pwd, password);
+
+ fstrcpy(creds->user_name, username);
+ fstrcpy(creds->domain, domain);
+
+ if (!*username) {
+ creds->pwd.null_pwd = True;
+ }
+}
+
+/****************************************************************************
+establishes a connection right up to doing tconX, password specified.
+****************************************************************************/
+NTSTATUS cli_full_connection(struct cli_state **output_cli,
+ const char *my_name, const char *dest_host,
+ struct in_addr *dest_ip, int port,
+ char *service, char *service_type,
+ char *user, char *domain,
+ char *password, int pass_len)
+{
+ struct ntuser_creds creds;
+ NTSTATUS nt_status;
+ struct nmb_name calling;
+ struct nmb_name called;
+ struct cli_state *cli;
+ struct in_addr ip;
+
+ if (!output_cli)
+ DEBUG(0, ("output_cli is NULL!?!"));
+
+ *output_cli = NULL;
+
+ make_nmb_name(&calling, my_name, 0x0);
+ make_nmb_name(&called , dest_host, 0x20);
+
+again:
+
+ if (!(cli = cli_initialise(NULL)))
+ return NT_STATUS_NO_MEMORY;
+
+ if (cli_set_port(cli, port) != port) {
+ cli_shutdown(cli);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ ip = *dest_ip;
+
+ DEBUG(3,("Connecting to host=%s share=%s\n", dest_host, service));
+
+ if (!cli_connect(cli, dest_host, &ip)) {
+ DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
+ nmb_namestr(&called), inet_ntoa(*dest_ip)));
+ cli_shutdown(cli);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!cli_session_request(cli, &calling, &called)) {
+ char *p;
+ DEBUG(1,("session request to %s failed (%s)\n",
+ called.name, cli_errstr(cli)));
+ cli_shutdown(cli);
+ if ((p=strchr(called.name, '.'))) {
+ *p = 0;
+ goto again;
+ }
+ if (strcmp(called.name, "*SMBSERVER")) {
+ make_nmb_name(&called , "*SMBSERVER", 0x20);
+ goto again;
+ }
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (!cli_negprot(cli)) {
+ DEBUG(1,("failed negprot\n"));
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ cli_shutdown(cli);
+ return nt_status;
+ }
+
+ if (!cli_session_setup(cli, user, password, pass_len, password, pass_len,
+ domain)) {
+ DEBUG(1,("failed session setup\n"));
+ nt_status = cli_nt_error(cli);
+ cli_shutdown(cli);
+ if (NT_STATUS_IS_OK(nt_status))
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ return nt_status;
+ }
+
+ if (service) {
+ if (!cli_send_tconX(cli, service, service_type,
+ (char*)password, pass_len)) {
+ DEBUG(1,("failed tcon_X\n"));
+ nt_status = cli_nt_error(cli);
+ cli_shutdown(cli);
+ if (NT_STATUS_IS_OK(nt_status))
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ return nt_status;
+ }
+ }
+
+ init_creds(&creds, user, domain, password, pass_len);
+ cli_init_creds(cli, &creds);
+
+ *output_cli = cli;
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
+****************************************************************************/
+
+BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
+ struct in_addr *pdest_ip)
+{
+ struct nmb_name calling, called;
+
+ make_nmb_name(&calling, srchost, 0x0);
+
+ /*
+ * If the called name is an IP address
+ * then use *SMBSERVER immediately.
+ */
+
+ if(is_ipaddress(desthost))
+ make_nmb_name(&called, "*SMBSERVER", 0x20);
+ else
+ make_nmb_name(&called, desthost, 0x20);
+
+ if (!cli_session_request(cli, &calling, &called)) {
+ struct nmb_name smbservername;
+
+ make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
+
+ /*
+ * If the name wasn't *SMBSERVER then
+ * try with *SMBSERVER if the first name fails.
+ */
+
+ if (nmb_name_equal(&called, &smbservername)) {
+
+ /*
+ * The name used was *SMBSERVER, don't bother with another name.
+ */
+
+ DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
+with error %s.\n", desthost, cli_errstr(cli) ));
+ cli_shutdown(cli);
+ return False;
+ }
+
+ cli_shutdown(cli);
+
+ if (!cli_initialise(cli) ||
+ !cli_connect(cli, desthost, pdest_ip) ||
+ !cli_session_request(cli, &calling, &smbservername)) {
+ DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
+name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));
+ cli_shutdown(cli);
+ return False;
+ }
+ }
+
+ return True;
+}
+
+
diff --git a/source3/libsmb/clidgram.c b/source3/libsmb/clidgram.c
new file mode 100644
index 0000000000..8f4bdf7be6
--- /dev/null
+++ b/source3/libsmb/clidgram.c
@@ -0,0 +1,267 @@
+/*
+ Unix SMB/CIFS implementation.
+ client dgram calls
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Richard Sharpe 2001
+ Copyright (C) John Terpstra 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"
+
+/*
+ * cli_send_mailslot, send a mailslot for client code ...
+ */
+
+int cli_send_mailslot(int dgram_sock, BOOL unique, char *mailslot,
+ char *buf, int len,
+ const char *srcname, int src_type,
+ const char *dstname, int dest_type,
+ struct in_addr dest_ip, struct in_addr src_ip,
+ int dest_port, int src_port)
+{
+ struct packet_struct p;
+ struct dgram_packet *dgram = &p.packet.dgram;
+ char *ptr, *p2;
+ char tmp[4];
+
+ memset((char *)&p, '\0', sizeof(p));
+
+ /*
+ * Next, build the DGRAM ...
+ */
+
+ /* DIRECT GROUP or UNIQUE datagram. */
+ dgram->header.msg_type = unique ? 0x10 : 0x11;
+ dgram->header.flags.node_type = M_NODE;
+ dgram->header.flags.first = True;
+ dgram->header.flags.more = False;
+ dgram->header.dgm_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + ((unsigned)sys_getpid()%(unsigned)100);
+ dgram->header.source_ip.s_addr = src_ip.s_addr;
+ dgram->header.source_port = ntohs(src_port);
+ dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
+ dgram->header.packet_offset = 0;
+
+ make_nmb_name(&dgram->source_name,srcname,src_type);
+ make_nmb_name(&dgram->dest_name,dstname,dest_type);
+
+ 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);
+
+ SCVAL(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,buf,len);
+ p2 += len;
+
+ dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
+
+ p.ip = dest_ip;
+ p.port = dest_port;
+ p.fd = dgram_sock;
+ p.timestamp = time(NULL);
+ p.packet_type = DGRAM_PACKET;
+
+ DEBUG(4,("send_mailslot: Sending to mailslot %s from %s IP %s ", mailslot,
+ nmb_namestr(&dgram->source_name), inet_ntoa(src_ip)));
+ DEBUG(4,("to %s IP %s\n", nmb_namestr(&dgram->dest_name), inet_ntoa(dest_ip)));
+
+ return send_packet(&p);
+
+}
+
+/*
+ * cli_get_response: Get a response ...
+ */
+int cli_get_response(int dgram_sock, BOOL unique, char *mailslot, char *buf, int bufsiz)
+{
+ struct packet_struct *packet;
+
+ packet = receive_dgram_packet(dgram_sock, 5, mailslot);
+
+ if (packet) { /* We got one, pull what we want out of the SMB data ... */
+
+ struct dgram_packet *dgram = &packet->packet.dgram;
+
+ /*
+ * We should probably parse the SMB, but for now, we will pull what
+ * from fixed, known locations ...
+ */
+
+ /* Copy the data to buffer, respecting sizes ... */
+
+ memcpy(buf, &dgram->data[92], MIN(bufsiz, (dgram->datasize - 92)));
+
+ }
+ else
+ return -1;
+
+ return 0;
+
+}
+
+/*
+ * cli_get_backup_list: Send a get backup list request ...
+ */
+
+static char cli_backup_list[1024];
+
+int cli_get_backup_list(const char *myname, const char *send_to_name)
+{
+ char outbuf[15];
+ char *p;
+ struct in_addr sendto_ip, my_ip;
+ int dgram_sock;
+ struct sockaddr_in sock_out;
+ socklen_t name_size;
+
+ if (!resolve_name(send_to_name, &sendto_ip, 0x1d)) {
+
+ DEBUG(0, ("Could not resolve name: %s<1D>\n", send_to_name));
+ return False;
+
+ }
+
+ my_ip.s_addr = inet_addr("0.0.0.0");
+
+ if (!resolve_name(myname, &my_ip, 0x00)) { /* FIXME: Call others here */
+
+ DEBUG(0, ("Could not resolve name: %s<00>\n", myname));
+
+ }
+
+ if ((dgram_sock = open_socket_out(SOCK_DGRAM, &sendto_ip, 138, LONG_CONNECT_TIMEOUT)) < 0) {
+
+ DEBUG(4, ("open_sock_out failed ..."));
+ return False;
+
+ }
+
+ /* Make it a broadcast socket ... */
+
+ set_socket_options(dgram_sock, "SO_BROADCAST");
+
+ /* Make it non-blocking??? */
+
+ if (fcntl(dgram_sock, F_SETFL, O_NONBLOCK) < 0) {
+
+ DEBUG(0, ("Unable to set non blocking on dgram sock\n"));
+
+ }
+
+ /* Now, bind a local addr to it ... Try port 138 first ... */
+
+ memset((char *)&sock_out, '\0', sizeof(sock_out));
+ sock_out.sin_addr.s_addr = INADDR_ANY;
+ sock_out.sin_port = htons(138);
+ sock_out.sin_family = AF_INET;
+
+ if (bind(dgram_sock, (struct sockaddr *)&sock_out, sizeof(sock_out)) < 0) {
+
+ /* Try again on any port ... */
+
+ sock_out.sin_port = INADDR_ANY;
+
+ if (bind(dgram_sock, (struct sockaddr *)&sock_out, sizeof(sock_out)) < 0) {
+
+ DEBUG(4, ("failed to bind socket to address ...\n"));
+ return False;
+
+ }
+
+ }
+
+ /* Now, figure out what socket name we were bound to. We want the port */
+
+ name_size = sizeof(sock_out);
+
+ getsockname(dgram_sock, (struct sockaddr *)&sock_out, &name_size);
+
+ DEBUG(5, ("Socket bound to IP:%s, port: %d\n", inet_ntoa(sock_out.sin_addr), ntohs(sock_out.sin_port)));
+
+ /* Now, build the request */
+
+ memset(cli_backup_list, '\0', sizeof(cli_backup_list));
+ memset(outbuf, '\0', sizeof(outbuf));
+
+ p = outbuf;
+
+ SCVAL(p, 0, ANN_GetBackupListReq);
+ p++;
+
+ SCVAL(p, 0, 1); /* Count pointer ... */
+ p++;
+
+ SIVAL(p, 0, 1); /* The sender's token ... */
+ p += 4;
+
+ cli_send_mailslot(dgram_sock, True, "\\MAILSLOT\\BROWSE", outbuf,
+ PTR_DIFF(p, outbuf), myname, 0, send_to_name,
+ 0x1d, sendto_ip, my_ip, 138, sock_out.sin_port);
+
+ /* We should check the error and return if we got one */
+
+ /* Now, get the response ... */
+
+ cli_get_response(dgram_sock, True, "\\MAILSLOT\\BROWSE", cli_backup_list, sizeof(cli_backup_list));
+
+ /* Should check the response here ... FIXME */
+
+ close(dgram_sock);
+
+ return True;
+
+}
+
+/*
+ * cli_get_backup_server: Get the backup list and retrieve a server from it
+ */
+
+int cli_get_backup_server(char *my_name, char *target, char *servername, int namesize)
+{
+
+ /* Get the backup list first. We could pull this from the cache later */
+
+ cli_get_backup_list(my_name, target); /* FIXME: Check the response */
+
+ if (!cli_backup_list[0]) { /* Empty list ... try again */
+
+ cli_get_backup_list(my_name, target);
+
+ }
+
+ strncpy(servername, cli_backup_list, MIN(16, namesize));
+
+ return True;
+
+}
+
+
+
diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c
new file mode 100644
index 0000000000..ba7a327344
--- /dev/null
+++ b/source3/libsmb/clientgen.c
@@ -0,0 +1,280 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB client generic functions
+ 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.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+/*
+ * Change the port number used to call on
+ */
+int cli_set_port(struct cli_state *cli, int port)
+{
+ cli->port = port;
+ return port;
+}
+
+/****************************************************************************
+recv an smb
+****************************************************************************/
+BOOL cli_receive_smb(struct cli_state *cli)
+{
+ BOOL ret;
+
+ /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
+ if (cli->fd == -1) return False;
+
+ again:
+ ret = client_receive_smb(cli->fd,cli->inbuf,cli->timeout);
+
+ if (ret) {
+ /* it might be an oplock break request */
+ if (!(CVAL(cli->inbuf, smb_flg) & FLAG_REPLY) &&
+ CVAL(cli->inbuf,smb_com) == SMBlockingX &&
+ SVAL(cli->inbuf,smb_vwv6) == 0 &&
+ SVAL(cli->inbuf,smb_vwv7) == 0) {
+ if (cli->oplock_handler) {
+ int fnum = SVAL(cli->inbuf,smb_vwv2);
+ unsigned char level = CVAL(cli->inbuf,smb_vwv3+1);
+ if (!cli->oplock_handler(cli, fnum, level)) return False;
+ }
+ /* try to prevent loops */
+ SCVAL(cli->inbuf,smb_com,0xFF);
+ goto again;
+ }
+ }
+
+ /* If the server is not responding, note that now */
+
+ if (!ret) {
+ close(cli->fd);
+ cli->fd = -1;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ send an smb to a fd.
+****************************************************************************/
+
+BOOL cli_send_smb(struct cli_state *cli)
+{
+ size_t len;
+ size_t nwritten=0;
+ ssize_t ret;
+
+ /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
+ if (cli->fd == -1) return False;
+
+ len = smb_len(cli->outbuf) + 4;
+
+ while (nwritten < len) {
+ ret = write_socket(cli->fd,cli->outbuf+nwritten,len - nwritten);
+ if (ret <= 0) {
+ close(cli->fd);
+ cli->fd = -1;
+ DEBUG(0,("Error writing %d bytes to client. %d\n",
+ (int)len,(int)ret));
+ return False;
+ }
+ nwritten += ret;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+setup basics in a outgoing packet
+****************************************************************************/
+void cli_setup_packet(struct cli_state *cli)
+{
+ cli->rap_error = 0;
+ SSVAL(cli->outbuf,smb_pid,cli->pid);
+ SSVAL(cli->outbuf,smb_uid,cli->vuid);
+ SSVAL(cli->outbuf,smb_mid,cli->mid);
+ if (cli->protocol > PROTOCOL_CORE) {
+ uint16 flags2;
+ SCVAL(cli->outbuf,smb_flg,0x8);
+ flags2 = FLAGS2_LONG_PATH_COMPONENTS;
+ if (cli->capabilities & CAP_UNICODE) {
+ flags2 |= FLAGS2_UNICODE_STRINGS;
+ }
+ if (cli->capabilities & CAP_STATUS32) {
+ flags2 |= FLAGS2_32_BIT_ERROR_CODES;
+ }
+ if (cli->use_spnego) {
+ flags2 |= FLAGS2_EXTENDED_SECURITY;
+ }
+ SSVAL(cli->outbuf,smb_flg2, flags2);
+ }
+}
+
+/****************************************************************************
+setup the bcc length of the packet from a pointer to the end of the data
+****************************************************************************/
+void cli_setup_bcc(struct cli_state *cli, void *p)
+{
+ set_message_bcc(cli->outbuf, PTR_DIFF(p, smb_buf(cli->outbuf)));
+}
+
+
+
+/****************************************************************************
+initialise credentials of a client structure
+****************************************************************************/
+void cli_init_creds(struct cli_state *cli, const struct ntuser_creds *usr)
+{
+ /* copy_nt_creds(&cli->usr, usr); */
+ safe_strcpy(cli->domain , usr->domain , sizeof(usr->domain )-1);
+ safe_strcpy(cli->user_name, usr->user_name, sizeof(usr->user_name)-1);
+ memcpy(&cli->pwd, &usr->pwd, sizeof(usr->pwd));
+ cli->ntlmssp_flags = usr->ntlmssp_flags;
+ cli->ntlmssp_cli_flgs = usr != NULL ? usr->ntlmssp_flags : 0;
+
+ DEBUG(10,("cli_init_creds: user %s domain %s flgs: %x\nntlmssp_cli_flgs:%x\n",
+ cli->user_name, cli->domain,
+ cli->ntlmssp_flags,cli->ntlmssp_cli_flgs));
+}
+
+
+/****************************************************************************
+initialise a client structure
+****************************************************************************/
+struct cli_state *cli_initialise(struct cli_state *cli)
+{
+ BOOL alloced_cli = False;
+
+ /* Check the effective uid - make sure we are not setuid */
+ if (is_setuid_root()) {
+ DEBUG(0,("libsmb based programs must *NOT* be setuid root.\n"));
+ return NULL;
+ }
+
+ if (!cli) {
+ cli = (struct cli_state *)malloc(sizeof(*cli));
+ if (!cli)
+ return NULL;
+ ZERO_STRUCTP(cli);
+ alloced_cli = True;
+ }
+
+ if (cli->initialised) {
+ cli_shutdown(cli);
+ }
+
+ ZERO_STRUCTP(cli);
+
+ cli->port = 0;
+ cli->fd = -1;
+ cli->cnum = -1;
+ cli->pid = (uint16)sys_getpid();
+ cli->mid = 1;
+ cli->vuid = UID_FIELD_INVALID;
+ cli->protocol = PROTOCOL_NT1;
+ cli->timeout = 20000; /* Timeout is in milliseconds. */
+ cli->bufsize = CLI_BUFFER_SIZE+4;
+ cli->max_xmit = cli->bufsize;
+ cli->outbuf = (char *)malloc(cli->bufsize);
+ cli->inbuf = (char *)malloc(cli->bufsize);
+ cli->oplock_handler = cli_oplock_ack;
+ cli->use_spnego = True;
+
+ /* Set the CLI_FORCE_DOSERR environment variable to test
+ client routines using DOS errors instead of STATUS32
+ ones. This intended only as a temporary hack. */
+ if (getenv("CLI_FORCE_DOSERR")) {
+ cli->force_dos_errors = True;
+ }
+
+ if (!cli->outbuf || !cli->inbuf)
+ goto error;
+
+ if ((cli->mem_ctx = talloc_init_named("cli based talloc")) == NULL)
+ goto error;
+
+ memset(cli->outbuf, 0, cli->bufsize);
+ memset(cli->inbuf, 0, cli->bufsize);
+
+ cli->nt_pipe_fnum = 0;
+
+ cli->initialised = 1;
+ cli->allocated = alloced_cli;
+
+ return cli;
+
+ /* Clean up after malloc() error */
+
+ error:
+
+ SAFE_FREE(cli->inbuf);
+ SAFE_FREE(cli->outbuf);
+
+ if (alloced_cli)
+ SAFE_FREE(cli);
+
+ return NULL;
+}
+
+/****************************************************************************
+shutdown a client structure
+****************************************************************************/
+void cli_shutdown(struct cli_state *cli)
+{
+ BOOL allocated;
+ SAFE_FREE(cli->outbuf);
+ SAFE_FREE(cli->inbuf);
+
+ data_blob_free(&cli->secblob);
+
+ if (cli->mem_ctx)
+ talloc_destroy(cli->mem_ctx);
+
+#ifdef WITH_SSL
+ if (cli->fd != -1)
+ sslutil_disconnect(cli->fd);
+#endif /* WITH_SSL */
+ if (cli->fd != -1)
+ close(cli->fd);
+ allocated = cli->allocated;
+ ZERO_STRUCTP(cli);
+ if (allocated) {
+ free(cli);
+ }
+}
+
+
+/****************************************************************************
+set socket options on a open connection
+****************************************************************************/
+void cli_sockopt(struct cli_state *cli, char *options)
+{
+ set_socket_options(cli->fd, options);
+}
+
+/****************************************************************************
+set the PID to use for smb messages. Return the old pid.
+****************************************************************************/
+uint16 cli_setpid(struct cli_state *cli, uint16 pid)
+{
+ uint16 ret = cli->pid;
+ cli->pid = pid;
+ return ret;
+}
diff --git a/source3/libsmb/clierror.c b/source3/libsmb/clierror.c
new file mode 100644
index 0000000000..591c04db22
--- /dev/null
+++ b/source3/libsmb/clierror.c
@@ -0,0 +1,281 @@
+/*
+ Unix SMB/CIFS implementation.
+ client error handling 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.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+/*****************************************************
+ RAP error codes - a small start but will be extended.
+
+ XXX: Perhaps these should move into a common function because they're
+ duplicated in clirap2.c
+
+*******************************************************/
+
+static const struct
+{
+ int err;
+ char *message;
+} rap_errmap[] =
+{
+ {5, "RAP5: User has insufficient privilege" },
+ {50, "RAP50: Not supported by server" },
+ {65, "RAP65: Access denied" },
+ {86, "RAP86: The specified password is invalid" },
+ {2220, "RAP2220: Group does not exist" },
+ {2221, "RAP2221: User does not exist" },
+ {2226, "RAP2226: Operation only permitted on a Primary Domain Controller" },
+ {2237, "RAP2237: User is not in group" },
+ {2242, "RAP2242: The password of this user has expired." },
+ {2243, "RAP2243: The password of this user cannot change." },
+ {2244, "RAP2244: This password cannot be used now (password history conflict)." },
+ {2245, "RAP2245: The password is shorter than required." },
+ {2246, "RAP2246: The password of this user is too recent to change."},
+
+ /* these really shouldn't be here ... */
+ {0x80, "Not listening on called name"},
+ {0x81, "Not listening for calling name"},
+ {0x82, "Called name not present"},
+ {0x83, "Called name present, but insufficient resources"},
+
+ {0, NULL}
+};
+
+/****************************************************************************
+ return a description of an SMB error
+****************************************************************************/
+static char *cli_smb_errstr(struct cli_state *cli)
+{
+ return smb_dos_errstr(cli->inbuf);
+}
+
+/***************************************************************************
+ Return an error message - either an NT error, SMB error or a RAP error.
+ Note some of the NT errors are actually warnings or "informational" errors
+ in which case they can be safely ignored.
+****************************************************************************/
+
+char *cli_errstr(struct cli_state *cli)
+{
+ static fstring cli_error_message;
+ uint32 flgs2 = SVAL(cli->inbuf,smb_flg2), errnum;
+ uint8 errclass;
+ int i;
+
+ if (!cli->initialised) {
+ fstrcpy(cli_error_message, "[Programmer's error] cli_errstr called on unitialized cli_stat struct!\n");
+ return cli_error_message;
+ }
+
+ /* Case #1: RAP error */
+ if (cli->rap_error) {
+ for (i = 0; rap_errmap[i].message != NULL; i++) {
+ if (rap_errmap[i].err == cli->rap_error) {
+ return rap_errmap[i].message;
+ }
+ }
+
+ slprintf(cli_error_message, sizeof(cli_error_message) - 1, "RAP code %d",
+ cli->rap_error);
+
+ return cli_error_message;
+ }
+
+ /* Case #2: 32-bit NT errors */
+ if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
+ NTSTATUS status = NT_STATUS(IVAL(cli->inbuf,smb_rcls));
+
+ return nt_errstr(status);
+ }
+
+ cli_dos_error(cli, &errclass, &errnum);
+
+ /* Case #3: SMB error */
+
+ return cli_smb_errstr(cli);
+}
+
+
+/* Return the 32-bit NT status code from the last packet */
+NTSTATUS cli_nt_error(struct cli_state *cli)
+{
+ int flgs2 = SVAL(cli->inbuf,smb_flg2);
+
+ if (!(flgs2 & FLAGS2_32_BIT_ERROR_CODES)) {
+ int class = CVAL(cli->inbuf,smb_rcls);
+ int code = SVAL(cli->inbuf,smb_err);
+ return dos_to_ntstatus(class, code);
+ }
+
+ return NT_STATUS(IVAL(cli->inbuf,smb_rcls));
+}
+
+
+/* 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)
+{
+ int flgs2;
+ char rcls;
+ int code;
+
+ if(!cli->initialised) return;
+
+ flgs2 = SVAL(cli->inbuf,smb_flg2);
+
+ if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
+ NTSTATUS ntstatus = NT_STATUS(IVAL(cli->inbuf, smb_rcls));
+ ntstatus_to_dos(ntstatus, eclass, ecode);
+ return;
+ }
+
+ rcls = CVAL(cli->inbuf,smb_rcls);
+ code = SVAL(cli->inbuf,smb_err);
+
+ if (eclass) *eclass = rcls;
+ if (ecode) *ecode = code;
+}
+
+/* Return a UNIX errno from a dos error class, error number tuple */
+
+int cli_errno_from_dos(uint8 eclass, uint32 num)
+{
+ if (eclass == ERRDOS) {
+ switch (num) {
+ case ERRbadfile: return ENOENT;
+ case ERRbadpath: return ENOTDIR;
+ case ERRnoaccess: return EACCES;
+ case ERRfilexists: return EEXIST;
+ case ERRrename: return EEXIST;
+ case ERRbadshare: return EBUSY;
+ case ERRlock: return EBUSY;
+ case ERRinvalidname: return ENOENT;
+ case ERRnosuchshare: return ENODEV;
+ }
+ }
+
+ if (eclass == ERRSRV) {
+ switch (num) {
+ case ERRbadpw: return EPERM;
+ case ERRaccess: return EACCES;
+ case ERRnoresource: return ENOMEM;
+ case ERRinvdevice: return ENODEV;
+ case ERRinvnetname: return ENODEV;
+ }
+ }
+
+ /* for other cases */
+ return EINVAL;
+}
+
+/* Return a UNIX errno from a NT status code */
+static struct {
+ NTSTATUS status;
+ int error;
+} nt_errno_map[] = {
+ {NT_STATUS_ACCESS_VIOLATION, EACCES},
+ {NT_STATUS_NO_SUCH_FILE, ENOENT},
+ {NT_STATUS_NO_SUCH_DEVICE, ENODEV},
+ {NT_STATUS_INVALID_HANDLE, EBADF},
+ {NT_STATUS_NO_MEMORY, ENOMEM},
+ {NT_STATUS_ACCESS_DENIED, EACCES},
+ {NT_STATUS_OBJECT_NAME_NOT_FOUND, ENOENT},
+ {NT_STATUS_SHARING_VIOLATION, EBUSY},
+ {NT_STATUS_OBJECT_PATH_INVALID, ENOTDIR},
+ {NT_STATUS_OBJECT_NAME_COLLISION, EEXIST},
+ {NT_STATUS_PATH_NOT_COVERED, ENOENT},
+ {NT_STATUS(0), 0}
+};
+
+int cli_errno_from_nt(NTSTATUS status)
+{
+ int i;
+ DEBUG(10,("cli_errno_from_nt: 32 bit codes: code=%08x\n", NT_STATUS_V(status)));
+
+ /* Status codes without this bit set are not errors */
+
+ if (!(NT_STATUS_V(status) & 0xc0000000))
+ return 0;
+
+ for (i=0;nt_errno_map[i].error;i++) {
+ if (NT_STATUS_V(nt_errno_map[i].status) ==
+ NT_STATUS_V(status)) return nt_errno_map[i].error;
+ }
+
+ /* for all other cases - a default code */
+ return EINVAL;
+}
+
+/* Return a UNIX errno appropriate for the error received in the last
+ packet. */
+
+int cli_errno(struct cli_state *cli)
+{
+ NTSTATUS status;
+
+ if (cli_is_dos_error(cli)) {
+ uint8 eclass;
+ uint32 ecode;
+
+ cli_dos_error(cli, &eclass, &ecode);
+ return cli_errno_from_dos(eclass, ecode);
+ }
+
+ status = cli_nt_error(cli);
+
+ return cli_errno_from_nt(status);
+}
+
+/* Return true if the last packet was in error */
+
+BOOL cli_is_error(struct cli_state *cli)
+{
+ uint32 flgs2 = SVAL(cli->inbuf,smb_flg2), rcls = 0;
+
+ if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
+ /* Return error is error bits are set */
+ rcls = IVAL(cli->inbuf, smb_rcls);
+ return (rcls & 0xF0000000) == 0xC0000000;
+ }
+
+ /* Return error if error class in non-zero */
+
+ rcls = CVAL(cli->inbuf, smb_rcls);
+ return rcls != 0;
+}
+
+/* Return true if the last error was an NT error */
+
+BOOL cli_is_nt_error(struct cli_state *cli)
+{
+ uint32 flgs2 = SVAL(cli->inbuf,smb_flg2);
+
+ return cli_is_error(cli) && (flgs2 & FLAGS2_32_BIT_ERROR_CODES);
+}
+
+/* Return true if the last error was a DOS error */
+
+BOOL cli_is_dos_error(struct cli_state *cli)
+{
+ uint32 flgs2 = SVAL(cli->inbuf,smb_flg2);
+
+ return cli_is_error(cli) && !(flgs2 & FLAGS2_32_BIT_ERROR_CODES);
+}
diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
new file mode 100644
index 0000000000..05843ac5de
--- /dev/null
+++ b/source3/libsmb/clifile.c
@@ -0,0 +1,1051 @@
+/*
+ Unix SMB/CIFS implementation.
+ client file operations
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Jeremy Allison 2001-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.
+*/
+
+#define NO_SYSLOG
+
+#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)
+{
+ int data_len = 0;
+ int param_len = 0;
+ uint16 setup = TRANSACT2_SETPATHINFO;
+ char param[sizeof(pstring)+6];
+ pstring data;
+ char *rparam=NULL, *rdata=NULL;
+ char *p;
+
+ memset(param, 0, sizeof(param));
+ SSVAL(param,0,hard_link ? SMB_SET_FILE_UNIX_HLINK : SMB_SET_FILE_UNIX_LINK);
+ p = &param[6];
+
+ p += clistr_push(cli, p, fname_src, -1, STR_TERMINATE);
+ param_len = PTR_DIFF(p, param);
+
+ p = data;
+ p += clistr_push(cli, p, fname_dst, -1, STR_TERMINATE);
+ data_len = PTR_DIFF(p, data);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ (char *)&data, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return False;
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return True;
+}
+
+/****************************************************************************
+ Map standard UNIX permissions onto wire representations.
+****************************************************************************/
+
+uint32 unix_perms_to_wire(mode_t perms)
+{
+ uint 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_ISVTX) ? 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)
+{
+ int data_len = 0;
+ int param_len = 0;
+ uint16 setup = TRANSACT2_SETPATHINFO;
+ char param[sizeof(pstring)+6];
+ char data[100];
+ char *rparam=NULL, *rdata=NULL;
+ char *p;
+
+ memset(param, 0, sizeof(param));
+ memset(data, 0, sizeof(data));
+ SSVAL(param,0,SMB_SET_FILE_UNIX_BASIC);
+ p = &param[6];
+
+ p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
+ param_len = PTR_DIFF(p, param);
+
+ SIVAL(data,40,uid);
+ SIVAL(data,48,gid);
+ SIVAL(data,84,mode);
+
+ data_len = 100;
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ (char *)&data, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return False;
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return True;
+}
+
+/****************************************************************************
+ 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)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,1, 0, True);
+
+ SCVAL(cli->outbuf,smb_com,SMBmv);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN | aDIR);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, fname_src, -1, STR_TERMINATE);
+ *p++ = 4;
+ p += clistr_push(cli, p, fname_dst, -1, STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli))
+ return False;
+
+ if (cli_is_error(cli))
+ return False;
+
+ return True;
+}
+
+/****************************************************************************
+ Delete a file.
+****************************************************************************/
+
+BOOL cli_unlink(struct cli_state *cli, const char *fname)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,1, 0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBunlink);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Create a directory.
+****************************************************************************/
+
+BOOL cli_mkdir(struct cli_state *cli, const char *dname)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,0, 0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBmkdir);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, dname, -1, STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Remove a directory.
+****************************************************************************/
+
+BOOL cli_rmdir(struct cli_state *cli, const char *dname)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,0, 0, True);
+
+ SCVAL(cli->outbuf,smb_com,SMBrmdir);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, dname, -1, STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Set or clear the delete on close flag.
+****************************************************************************/
+
+int cli_nt_delete_on_close(struct cli_state *cli, int fnum, BOOL flag)
+{
+ int data_len = 1;
+ int param_len = 6;
+ uint16 setup = TRANSACT2_SETFILEINFO;
+ pstring param;
+ unsigned char data;
+ char *rparam=NULL, *rdata=NULL;
+
+ memset(param, 0, param_len);
+ SSVAL(param,0,fnum);
+ SSVAL(param,2,SMB_SET_FILE_DISPOSITION_INFO);
+
+ data = flag ? 1 : 0;
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ (char *)&data, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return False;
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return True;
+}
+
+/****************************************************************************
+ Open a file - exposing the full horror of the NT API :-).
+ Used in smbtorture.
+****************************************************************************/
+
+int cli_nt_create_full(struct cli_state *cli, const char *fname, uint32 DesiredAccess,
+ uint32 FileAttributes, uint32 ShareAccess,
+ uint32 CreateDisposition, uint32 CreateOptions)
+{
+ char *p;
+ int len;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,24,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBntcreateX);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,0xFF);
+ if (cli->use_oplocks)
+ SIVAL(cli->outbuf,smb_ntcreate_Flags, REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
+ else
+ SIVAL(cli->outbuf,smb_ntcreate_Flags, 0);
+ SIVAL(cli->outbuf,smb_ntcreate_RootDirectoryFid, 0x0);
+ SIVAL(cli->outbuf,smb_ntcreate_DesiredAccess, DesiredAccess);
+ SIVAL(cli->outbuf,smb_ntcreate_FileAttributes, FileAttributes);
+ SIVAL(cli->outbuf,smb_ntcreate_ShareAccess, ShareAccess);
+ SIVAL(cli->outbuf,smb_ntcreate_CreateDisposition, CreateDisposition);
+ SIVAL(cli->outbuf,smb_ntcreate_CreateOptions, CreateOptions);
+ SIVAL(cli->outbuf,smb_ntcreate_ImpersonationLevel, 0x02);
+
+ p = smb_buf(cli->outbuf);
+ /* this alignment and termination is critical for netapp filers. Don't change */
+ p += clistr_align_out(cli, p, 0);
+ len = clistr_push(cli, p, fname, -1, 0);
+ p += len;
+ SSVAL(cli->outbuf,smb_ntcreate_NameLength, len);
+ /* sigh. this copes with broken netapp filer behaviour */
+ p += clistr_push(cli, p, "", -1, STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return -1;
+ }
+
+ if (cli_is_error(cli)) {
+ return -1;
+ }
+
+ return SVAL(cli->inbuf,smb_vwv2 + 1);
+}
+
+/****************************************************************************
+ Open a file.
+****************************************************************************/
+
+int cli_nt_create(struct cli_state *cli, const char *fname, uint32 DesiredAccess)
+{
+ return cli_nt_create_full(cli, fname, DesiredAccess, 0,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_EXISTS_OPEN, 0x0);
+}
+
+/****************************************************************************
+ Open a file
+ 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)
+{
+ char *p;
+ unsigned openfn=0;
+ unsigned accessmode=0;
+
+ if (flags & O_CREAT)
+ openfn |= (1<<4);
+ if (!(flags & O_EXCL)) {
+ if (flags & O_TRUNC)
+ openfn |= (1<<1);
+ else
+ openfn |= (1<<0);
+ }
+
+ accessmode = (share_mode<<4);
+
+ if ((flags & O_ACCMODE) == O_RDWR) {
+ accessmode |= 2;
+ } else if ((flags & O_ACCMODE) == O_WRONLY) {
+ accessmode |= 1;
+ }
+
+#if defined(O_SYNC)
+ if ((flags & O_SYNC) == O_SYNC) {
+ accessmode |= (1<<14);
+ }
+#endif /* O_SYNC */
+
+ if (share_mode == DENY_FCB) {
+ accessmode = 0xFF;
+ }
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,15,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBopenX);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
+ SSVAL(cli->outbuf,smb_vwv3,accessmode);
+ SSVAL(cli->outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
+ SSVAL(cli->outbuf,smb_vwv5,0);
+ SSVAL(cli->outbuf,smb_vwv8,openfn);
+
+ if (cli->use_oplocks) {
+ /* if using oplocks then ask for a batch oplock via
+ core and extended methods */
+ SCVAL(cli->outbuf,smb_flg, CVAL(cli->outbuf,smb_flg)|
+ FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK);
+ SSVAL(cli->outbuf,smb_vwv2,SVAL(cli->outbuf,smb_vwv2) | 6);
+ }
+
+ p = smb_buf(cli->outbuf);
+ p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return -1;
+ }
+
+ if (cli_is_error(cli)) {
+ return -1;
+ }
+
+ return SVAL(cli->inbuf,smb_vwv2);
+}
+
+/****************************************************************************
+ Close a file.
+****************************************************************************/
+
+BOOL cli_close(struct cli_state *cli, int fnum)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,3,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBclose);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,fnum);
+ SIVALS(cli->outbuf,smb_vwv1,-1);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ return !cli_is_error(cli);
+}
+
+
+/****************************************************************************
+ 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)
+{
+ char *p;
+ int saved_timeout = cli->timeout;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0', smb_size);
+
+ set_message(cli->outbuf,8,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBlockingX);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+ SCVAL(cli->outbuf,smb_vwv3,locktype);
+ SIVALS(cli->outbuf, smb_vwv4, timeout);
+ SSVAL(cli->outbuf,smb_vwv6,0);
+ SSVAL(cli->outbuf,smb_vwv7,1);
+
+ p = smb_buf(cli->outbuf);
+ SSVAL(p, 0, cli->pid);
+ SIVAL(p, 2, offset);
+ SIVAL(p, 6, len);
+
+ p += 10;
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+
+ if (timeout != 0) {
+ cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 2*1000);
+ }
+
+ if (!cli_receive_smb(cli)) {
+ cli->timeout = saved_timeout;
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ cli->timeout = saved_timeout;
+
+ return cli_nt_error(cli);
+}
+
+
+/****************************************************************************
+ Lock a file.
+****************************************************************************/
+
+BOOL cli_lock(struct cli_state *cli, int fnum,
+ uint32 offset, uint32 len, int timeout, enum brl_type lock_type)
+{
+ char *p;
+ int saved_timeout = cli->timeout;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0', smb_size);
+
+ set_message(cli->outbuf,8,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBlockingX);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+ SCVAL(cli->outbuf,smb_vwv3,(lock_type == READ_LOCK? 1 : 0));
+ SIVALS(cli->outbuf, smb_vwv4, timeout);
+ SSVAL(cli->outbuf,smb_vwv6,0);
+ SSVAL(cli->outbuf,smb_vwv7,1);
+
+ p = smb_buf(cli->outbuf);
+ SSVAL(p, 0, cli->pid);
+ SIVAL(p, 2, offset);
+ SIVAL(p, 6, len);
+
+ p += 10;
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+
+ if (timeout != 0) {
+ cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 2*1000);
+ }
+
+ if (!cli_receive_smb(cli)) {
+ cli->timeout = saved_timeout;
+ return False;
+ }
+
+ cli->timeout = saved_timeout;
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Unlock a file.
+****************************************************************************/
+
+BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,8,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBlockingX);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+ SCVAL(cli->outbuf,smb_vwv3,0);
+ SIVALS(cli->outbuf, smb_vwv4, 0);
+ SSVAL(cli->outbuf,smb_vwv6,1);
+ SSVAL(cli->outbuf,smb_vwv7,0);
+
+ p = smb_buf(cli->outbuf);
+ SSVAL(p, 0, cli->pid);
+ SIVAL(p, 2, offset);
+ SIVAL(p, 6, len);
+ p += 10;
+ cli_setup_bcc(cli, p);
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Lock a file with 64 bit offsets.
+****************************************************************************/
+
+BOOL cli_lock64(struct cli_state *cli, int fnum,
+ SMB_BIG_UINT offset, SMB_BIG_UINT len, int timeout, enum brl_type lock_type)
+{
+ char *p;
+ int saved_timeout = cli->timeout;
+ int ltype;
+
+ if (! (cli->capabilities & CAP_LARGE_FILES)) {
+ return cli_lock(cli, fnum, offset, len, timeout, lock_type);
+ }
+
+ ltype = (lock_type == READ_LOCK? 1 : 0);
+ ltype |= LOCKING_ANDX_LARGE_FILES;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0', smb_size);
+
+ set_message(cli->outbuf,8,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBlockingX);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+ SCVAL(cli->outbuf,smb_vwv3,ltype);
+ SIVALS(cli->outbuf, smb_vwv4, timeout);
+ SSVAL(cli->outbuf,smb_vwv6,0);
+ SSVAL(cli->outbuf,smb_vwv7,1);
+
+ p = smb_buf(cli->outbuf);
+ SIVAL(p, 0, cli->pid);
+ SOFF_T_R(p, 4, offset);
+ SOFF_T_R(p, 12, len);
+ p += 20;
+
+ cli_setup_bcc(cli, p);
+ cli_send_smb(cli);
+
+ if (timeout != 0) {
+ cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 5*1000);
+ }
+
+ if (!cli_receive_smb(cli)) {
+ cli->timeout = saved_timeout;
+ return False;
+ }
+
+ cli->timeout = saved_timeout;
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Unlock a file with 64 bit offsets.
+****************************************************************************/
+
+BOOL cli_unlock64(struct cli_state *cli, int fnum, SMB_BIG_UINT offset, SMB_BIG_UINT len)
+{
+ char *p;
+
+ if (! (cli->capabilities & CAP_LARGE_FILES)) {
+ return cli_unlock(cli, fnum, offset, len);
+ }
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,8,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBlockingX);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+ SCVAL(cli->outbuf,smb_vwv3,LOCKING_ANDX_LARGE_FILES);
+ SIVALS(cli->outbuf, smb_vwv4, 0);
+ SSVAL(cli->outbuf,smb_vwv6,1);
+ SSVAL(cli->outbuf,smb_vwv7,0);
+
+ p = smb_buf(cli->outbuf);
+ SIVAL(p, 0, cli->pid);
+ SOFF_T_R(p, 4, offset);
+ SOFF_T_R(p, 12, len);
+ p += 20;
+ cli_setup_bcc(cli, p);
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+
+/****************************************************************************
+ 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)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,1,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBgetattrE);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,fd);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ if (size) {
+ *size = IVAL(cli->inbuf, smb_vwv6);
+ }
+
+ if (attr) {
+ *attr = SVAL(cli->inbuf,smb_vwv10);
+ }
+
+ if (c_time) {
+ *c_time = make_unix_date3(cli->inbuf+smb_vwv0);
+ }
+
+ if (a_time) {
+ *a_time = make_unix_date3(cli->inbuf+smb_vwv2);
+ }
+
+ if (m_time) {
+ *m_time = make_unix_date3(cli->inbuf+smb_vwv4);
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Do a SMBgetatr call
+****************************************************************************/
+
+BOOL cli_getatr(struct cli_state *cli, const char *fname,
+ uint16 *attr, size_t *size, time_t *t)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,0,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBgetatr);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ if (size) {
+ *size = IVAL(cli->inbuf, smb_vwv3);
+ }
+
+ if (t) {
+ *t = make_unix_date3(cli->inbuf+smb_vwv1);
+ }
+
+ if (attr) {
+ *attr = SVAL(cli->inbuf,smb_vwv0);
+ }
+
+
+ return True;
+}
+
+/****************************************************************************
+ Do a SMBsetatr call.
+****************************************************************************/
+
+BOOL cli_setatr(struct cli_state *cli, const char *fname, uint16 attr, time_t t)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,8,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBsetatr);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0, attr);
+ put_dos_date3(cli->outbuf,smb_vwv1, t);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
+ *p++ = 4;
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) {
+ return False;
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ Check for existance of a dir.
+****************************************************************************/
+
+BOOL cli_chkpath(struct cli_state *cli, const char *path)
+{
+ pstring path2;
+ char *p;
+
+ safe_strcpy(path2,path,sizeof(pstring));
+ trim_string(path2,NULL,"\\");
+ if (!*path2) *path2 = '\\';
+
+ memset(cli->outbuf,'\0',smb_size);
+ set_message(cli->outbuf,0,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBchkpth);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, path2, -1, STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) return False;
+
+ return True;
+}
+
+/****************************************************************************
+ Query disk space.
+****************************************************************************/
+
+BOOL cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ set_message(cli->outbuf,0,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBdskattr);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ *bsize = SVAL(cli->inbuf,smb_vwv1)*SVAL(cli->inbuf,smb_vwv2);
+ *total = SVAL(cli->inbuf,smb_vwv0);
+ *avail = SVAL(cli->inbuf,smb_vwv3);
+
+ return True;
+}
+
+/****************************************************************************
+ Create and open a temporary file.
+****************************************************************************/
+
+int cli_ctemp(struct cli_state *cli, const char *path, char **tmp_path)
+{
+ int len;
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,3,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBctemp);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,0);
+ SIVALS(cli->outbuf,smb_vwv1,-1);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, path, -1, STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ return -1;
+ }
+
+ if (cli_is_error(cli)) {
+ return -1;
+ }
+
+ /* despite the spec, the result has a -1, followed by
+ length, followed by name */
+ p = smb_buf(cli->inbuf);
+ p += 4;
+ len = smb_buflen(cli->inbuf) - 4;
+ if (len <= 0) return -1;
+
+ if (tmp_path) {
+ pstring path2;
+ clistr_pull(cli, path2, p,
+ sizeof(path2), len, STR_ASCII);
+ *tmp_path = strdup(path2);
+ }
+
+ return SVAL(cli->inbuf,smb_vwv0);
+}
diff --git a/source3/libsmb/clikrb5.c b/source3/libsmb/clikrb5.c
new file mode 100644
index 0000000000..685c4a25e0
--- /dev/null
+++ b/source3/libsmb/clikrb5.c
@@ -0,0 +1,145 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple kerberos5 routines for active directory
+ 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"
+
+#ifdef HAVE_KRB5
+/*
+ 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;
+ }
+
+ 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(char *principal)
+{
+ 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[] = {ENCTYPE_DES_CBC_MD5, ENCTYPE_NULL};
+
+ retval = krb5_init_context(&context);
+ if (retval) {
+ DEBUG(1,("krb5_init_context failed (%s)\n",
+ error_message(retval)));
+ goto failed;
+ }
+
+ 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:
+ krb5_free_context(context);
+ return data_blob(NULL, 0);
+}
+
+
+#else /* HAVE_KRB5 */
+ /* this saves a few linking headaches */
+ DATA_BLOB krb5_get_ticket(char *principal)
+ {
+ DEBUG(0,("NO KERBEROS SUPPORT\n"));
+ return data_blob(NULL, 0);
+ }
+#endif
diff --git a/source3/libsmb/clilist.c b/source3/libsmb/clilist.c
new file mode 100644
index 0000000000..8b28e05a47
--- /dev/null
+++ b/source3/libsmb/clilist.c
@@ -0,0 +1,464 @@
+/*
+ Unix SMB/CIFS implementation.
+ client directory list 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.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+
+/****************************************************************************
+interpret a long filename structure - this is mostly guesses at the moment
+The length of the structure is returned
+The structure of a long filename depends on the info level. 260 is used
+by NT and 2 is used by OS/2
+****************************************************************************/
+static int interpret_long_filename(struct cli_state *cli,
+ int level,char *p,file_info *finfo)
+{
+ extern file_info def_finfo;
+ file_info finfo2;
+ int len;
+ char *base = p;
+
+ if (!finfo) finfo = &finfo2;
+
+ memcpy(finfo,&def_finfo,sizeof(*finfo));
+
+ switch (level)
+ {
+ case 1: /* OS/2 understands this */
+ /* these dates are converted to GMT by
+ make_unix_date */
+ finfo->ctime = make_unix_date2(p+4);
+ finfo->atime = make_unix_date2(p+8);
+ finfo->mtime = make_unix_date2(p+12);
+ finfo->size = IVAL(p,16);
+ finfo->mode = CVAL(p,24);
+ len = CVAL(p, 26);
+ p += 27;
+ p += clistr_align_in(cli, p, 0);
+ p += clistr_pull(cli, finfo->name, p,
+ sizeof(finfo->name),
+ len,
+ STR_TERMINATE);
+ return PTR_DIFF(p, base);
+
+ case 2: /* this is what OS/2 uses mostly */
+ /* these dates are converted to GMT by
+ make_unix_date */
+ finfo->ctime = make_unix_date2(p+4);
+ finfo->atime = make_unix_date2(p+8);
+ finfo->mtime = make_unix_date2(p+12);
+ finfo->size = IVAL(p,16);
+ finfo->mode = CVAL(p,24);
+ len = CVAL(p, 30);
+ p += 31;
+ /* check for unisys! */
+ p += clistr_pull(cli, finfo->name, p,
+ sizeof(finfo->name),
+ len,
+ STR_NOALIGN);
+ return PTR_DIFF(p, base) + 1;
+
+ case 260: /* NT uses this, but also accepts 2 */
+ {
+ int namelen, slen;
+ p += 4; /* next entry offset */
+ p += 4; /* fileindex */
+
+ /* these dates appear to arrive in a
+ weird way. It seems to be localtime
+ plus the serverzone given in the
+ initial connect. This is GMT when
+ DST is not in effect and one hour
+ from GMT otherwise. Can this really
+ be right??
+
+ I suppose this could be called
+ kludge-GMT. Is is the GMT you get
+ by using the current DST setting on
+ a different localtime. It will be
+ cheap to calculate, I suppose, as
+ no DST tables will be needed */
+
+ finfo->ctime = interpret_long_date(p); p += 8;
+ finfo->atime = interpret_long_date(p); p += 8;
+ finfo->mtime = interpret_long_date(p); p += 8; p += 8;
+ finfo->size = IVAL(p,0); p += 8;
+ p += 8; /* alloc size */
+ finfo->mode = CVAL(p,0); p += 4;
+ namelen = IVAL(p,0); p += 4;
+ p += 4; /* EA size */
+ slen = SVAL(p, 0);
+ p += 2;
+ {
+ /* stupid NT bugs. grr */
+ int flags = 0;
+ if (p[1] == 0 && namelen > 1) flags |= STR_UNICODE;
+ clistr_pull(cli, finfo->short_name, p,
+ sizeof(finfo->short_name),
+ slen, flags);
+ }
+ p += 24; /* short name? */
+ clistr_pull(cli, finfo->name, p,
+ sizeof(finfo->name),
+ namelen, 0);
+ return SVAL(base, 0);
+ }
+ }
+
+ DEBUG(1,("Unknown long filename format %d\n",level));
+ return(SVAL(p,0));
+}
+
+
+/****************************************************************************
+ do a directory listing, calling fn on each file found
+ ****************************************************************************/
+int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
+ void (*fn)(file_info *, const char *, void *), void *state)
+{
+ int max_matches = 512;
+ int info_level;
+ char *p, *p2;
+ pstring mask;
+ file_info finfo;
+ int i;
+ char *tdl, *dirlist = NULL;
+ int dirlist_len = 0;
+ int total_received = -1;
+ BOOL First = True;
+ int ff_searchcount=0;
+ int ff_eos=0;
+ int ff_lastname=0;
+ int ff_dir_handle=0;
+ int loop_count = 0;
+ char *rparam=NULL, *rdata=NULL;
+ int param_len, data_len;
+ uint16 setup;
+ pstring param;
+
+ /* NT uses 260, OS/2 uses 2. Both accept 1. */
+ info_level = (cli->capabilities&CAP_NT_SMBS)?260:1;
+
+ pstrcpy(mask,Mask);
+
+ while (ff_eos == 0) {
+ loop_count++;
+ if (loop_count > 200) {
+ DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
+ break;
+ }
+
+ if (First) {
+ setup = TRANSACT2_FINDFIRST;
+ SSVAL(param,0,attribute); /* attribute */
+ SSVAL(param,2,max_matches); /* max count */
+ SSVAL(param,4,4+2); /* resume required + close on end */
+ SSVAL(param,6,info_level);
+ SIVAL(param,8,0);
+ p = param+12;
+ p += clistr_push(cli, param+12, mask, -1,
+ STR_TERMINATE);
+ } else {
+ setup = TRANSACT2_FINDNEXT;
+ SSVAL(param,0,ff_dir_handle);
+ SSVAL(param,2,max_matches); /* max count */
+ SSVAL(param,4,info_level);
+ SIVAL(param,6,0); /* ff_resume_key */
+ SSVAL(param,10,8+4+2); /* continue + resume required + close on end */
+ p = param+12;
+ p += clistr_push(cli, param+12, mask, -1,
+ STR_TERMINATE);
+ }
+
+ param_len = PTR_DIFF(p, param);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* Name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 10, /* param, length, max */
+ NULL, 0,
+ cli->max_xmit /* data, length, max */
+ )) {
+ break;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len) &&
+ cli_is_dos_error(cli)) {
+ /* we need to work around a Win95 bug - sometimes
+ it gives ERRSRV/ERRerror temprarily */
+ uint8 eclass;
+ uint32 ecode;
+ cli_dos_error(cli, &eclass, &ecode);
+ if (eclass != ERRSRV || ecode != ERRerror) break;
+ msleep(100);
+ continue;
+ }
+
+ if (cli_is_error(cli) || !rdata || !rparam)
+ break;
+
+ if (total_received == -1) total_received = 0;
+
+ /* parse out some important return info */
+ p = rparam;
+ if (First) {
+ ff_dir_handle = SVAL(p,0);
+ ff_searchcount = SVAL(p,2);
+ ff_eos = SVAL(p,4);
+ ff_lastname = SVAL(p,8);
+ } else {
+ ff_searchcount = SVAL(p,0);
+ ff_eos = SVAL(p,2);
+ ff_lastname = SVAL(p,6);
+ }
+
+ if (ff_searchcount == 0)
+ break;
+
+ /* point to the data bytes */
+ p = rdata;
+
+ /* we might need the lastname for continuations */
+ if (ff_lastname > 0) {
+ switch(info_level)
+ {
+ case 260:
+ clistr_pull(cli, mask, p+ff_lastname,
+ sizeof(mask),
+ data_len-ff_lastname,
+ STR_TERMINATE);
+ break;
+ case 1:
+ clistr_pull(cli, mask, p+ff_lastname+1,
+ sizeof(mask),
+ -1,
+ STR_TERMINATE);
+ break;
+ }
+ } else {
+ pstrcpy(mask,"");
+ }
+
+ /* and add them to the dirlist pool */
+ tdl = Realloc(dirlist,dirlist_len + data_len);
+
+ if (!tdl) {
+ DEBUG(0,("cli_list_new: Failed to expand dirlist\n"));
+ break;
+ }
+ else dirlist = tdl;
+
+ /* put in a length for the last entry, to ensure we can chain entries
+ into the next packet */
+ for (p2=p,i=0;i<(ff_searchcount-1);i++)
+ p2 += interpret_long_filename(cli,info_level,p2,NULL);
+ SSVAL(p2,0,data_len - PTR_DIFF(p2,p));
+
+ /* grab the data for later use */
+ memcpy(dirlist+dirlist_len,p,data_len);
+ dirlist_len += data_len;
+
+ total_received += ff_searchcount;
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ DEBUG(3,("received %d entries (eos=%d)\n",
+ ff_searchcount,ff_eos));
+
+ if (ff_searchcount > 0) loop_count = 0;
+
+ First = False;
+ }
+
+ for (p=dirlist,i=0;i<total_received;i++) {
+ p += interpret_long_filename(cli,info_level,p,&finfo);
+ fn(&finfo, Mask, state);
+ }
+
+ /* free up the dirlist buffer */
+ SAFE_FREE(dirlist);
+ return(total_received);
+}
+
+
+
+/****************************************************************************
+interpret a short filename structure
+The length of the structure is returned
+****************************************************************************/
+static int interpret_short_filename(struct cli_state *cli, char *p,file_info *finfo)
+{
+ extern file_info def_finfo;
+
+ *finfo = def_finfo;
+
+ finfo->mode = CVAL(p,21);
+
+ /* this date is converted to GMT by make_unix_date */
+ finfo->ctime = make_unix_date(p+22);
+ finfo->mtime = finfo->atime = finfo->ctime;
+ finfo->size = IVAL(p,26);
+ clistr_pull(cli, finfo->name, p+30, sizeof(finfo->name), 12, STR_ASCII);
+ if (strcmp(finfo->name, "..") && strcmp(finfo->name, "."))
+ fstrcpy(finfo->short_name,finfo->name);
+
+ return(DIR_STRUCT_SIZE);
+}
+
+
+/****************************************************************************
+ do a directory listing, calling fn on each file found
+ this uses the old SMBsearch interface. It is needed for testing Samba,
+ but should otherwise not be used
+ ****************************************************************************/
+int cli_list_old(struct cli_state *cli,const char *Mask,uint16 attribute,
+ void (*fn)(file_info *, const char *, void *), void *state)
+{
+ char *p;
+ int received = 0;
+ BOOL first = True;
+ char status[21];
+ int num_asked = (cli->max_xmit - 100)/DIR_STRUCT_SIZE;
+ int num_received = 0;
+ int i;
+ char *tdl, *dirlist = NULL;
+ pstring mask;
+
+ ZERO_ARRAY(status);
+
+ pstrcpy(mask,Mask);
+
+ while (1) {
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,2,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBsearch);
+
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,num_asked);
+ SSVAL(cli->outbuf,smb_vwv1,attribute);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+
+ p += clistr_push(cli, p, first?mask:"", -1, STR_TERMINATE);
+ *p++ = 5;
+ if (first) {
+ SSVAL(p,0,0);
+ p += 2;
+ } else {
+ SSVAL(p,0,21);
+ p += 2;
+ memcpy(p,status,21);
+ p += 21;
+ }
+
+ cli_setup_bcc(cli, p);
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) break;
+
+ received = SVAL(cli->inbuf,smb_vwv0);
+ if (received <= 0) break;
+
+ first = False;
+
+ tdl = Realloc(dirlist,(num_received + received)*DIR_STRUCT_SIZE);
+
+ if (!tdl) {
+ DEBUG(0,("cli_list_old: failed to expand dirlist"));
+ SAFE_FREE(dirlist);
+ return 0;
+ }
+ else dirlist = tdl;
+
+ p = smb_buf(cli->inbuf) + 3;
+
+ memcpy(dirlist+num_received*DIR_STRUCT_SIZE,
+ p,received*DIR_STRUCT_SIZE);
+
+ memcpy(status,p + ((received-1)*DIR_STRUCT_SIZE),21);
+
+ num_received += received;
+
+ if (cli_is_error(cli)) break;
+ }
+
+ if (!first) {
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,2,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBfclose);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf, smb_vwv0, 0); /* find count? */
+ SSVAL(cli->outbuf, smb_vwv1, attribute);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ fstrcpy(p, "");
+ p += strlen(p) + 1;
+ *p++ = 5;
+ SSVAL(p, 0, 21);
+ p += 2;
+ memcpy(p,status,21);
+ p += 21;
+
+ cli_setup_bcc(cli, p);
+ cli_send_smb(cli);
+ if (!cli_receive_smb(cli)) {
+ DEBUG(0,("Error closing search: %s\n",cli_errstr(cli)));
+ }
+ }
+
+ for (p=dirlist,i=0;i<num_received;i++) {
+ file_info finfo;
+ p += interpret_short_filename(cli, p,&finfo);
+ fn(&finfo, Mask, state);
+ }
+
+ SAFE_FREE(dirlist);
+ return(num_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->protocol <= PROTOCOL_LANMAN1) {
+ return cli_list_old(cli, Mask, attribute, fn, state);
+ }
+ return cli_list_new(cli, Mask, attribute, fn, state);
+}
diff --git a/source3/libsmb/climessage.c b/source3/libsmb/climessage.c
new file mode 100644
index 0000000000..1587e6f4cd
--- /dev/null
+++ b/source3/libsmb/climessage.c
@@ -0,0 +1,120 @@
+/*
+ Unix SMB/CIFS implementation.
+ client message handling 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.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+
+/****************************************************************************
+start a message sequence
+****************************************************************************/
+BOOL cli_message_start(struct cli_state *cli, char *host, char *username,
+ int *grp)
+{
+ char *p;
+
+ /* send a SMBsendstrt command */
+ memset(cli->outbuf,'\0',smb_size);
+ set_message(cli->outbuf,0,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBsendstrt);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 4;
+ p += clistr_push(cli, p, username, -1, STR_TERMINATE);
+ *p++ = 4;
+ p += clistr_push(cli, p, host, -1, STR_TERMINATE);
+
+ cli_setup_bcc(cli, p);
+
+ cli_send_smb(cli);
+
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) return False;
+
+ *grp = SVAL(cli->inbuf,smb_vwv0);
+
+ return True;
+}
+
+
+/****************************************************************************
+send a message
+****************************************************************************/
+BOOL cli_message_text(struct cli_state *cli, char *msg, int len, int grp)
+{
+ char *p;
+
+ memset(cli->outbuf,'\0',smb_size);
+ set_message(cli->outbuf,1,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBsendtxt);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,grp);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 1;
+ SSVAL(p,0,len); p += 2;
+ memcpy(p,msg,len);
+ p += len;
+
+ cli_setup_bcc(cli, p);
+ cli_send_smb(cli);
+
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) return False;
+
+ return True;
+}
+
+/****************************************************************************
+end a message
+****************************************************************************/
+BOOL cli_message_end(struct cli_state *cli, int grp)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ set_message(cli->outbuf,1,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBsendend);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+
+ SSVAL(cli->outbuf,smb_vwv0,grp);
+
+ cli_setup_packet(cli);
+
+ cli_send_smb(cli);
+
+ if (!cli_receive_smb(cli)) {
+ return False;
+ }
+
+ if (cli_is_error(cli)) return False;
+
+ return True;
+}
+
diff --git a/source3/libsmb/clioplock.c b/source3/libsmb/clioplock.c
new file mode 100644
index 0000000000..0ffeb1926b
--- /dev/null
+++ b/source3/libsmb/clioplock.c
@@ -0,0 +1,68 @@
+/*
+ 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.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+/****************************************************************************
+send an ack for an oplock break request
+****************************************************************************/
+BOOL cli_oplock_ack(struct cli_state *cli, int fnum, unsigned char level)
+{
+ char *oldbuf = cli->outbuf;
+ pstring buf;
+ BOOL ret;
+
+ cli->outbuf = buf;
+
+ memset(buf,'\0',smb_size);
+ set_message(buf,8,0,True);
+
+ SCVAL(buf,smb_com,SMBlockingX);
+ SSVAL(buf,smb_tid, cli->cnum);
+ cli_setup_packet(cli);
+ SSVAL(buf,smb_vwv0,0xFF);
+ SSVAL(buf,smb_vwv1,0);
+ SSVAL(buf,smb_vwv2,fnum);
+ if (level == 1)
+ SSVAL(buf,smb_vwv3,0x102); /* levelII oplock break ack */
+ else
+ SSVAL(buf,smb_vwv3,2); /* exclusive oplock break ack */
+ SIVAL(buf,smb_vwv4,0); /* timoeut */
+ SSVAL(buf,smb_vwv6,0); /* unlockcount */
+ SSVAL(buf,smb_vwv7,0); /* lockcount */
+
+ ret = cli_send_smb(cli);
+
+ cli->outbuf = oldbuf;
+
+ return ret;
+}
+
+
+/****************************************************************************
+set the oplock handler for a connection
+****************************************************************************/
+void cli_oplock_handler(struct cli_state *cli,
+ BOOL (*handler)(struct cli_state *, int, unsigned char))
+{
+ cli->oplock_handler = handler;
+}
diff --git a/source3/libsmb/cliprint.c b/source3/libsmb/cliprint.c
new file mode 100644
index 0000000000..92fbf02e91
--- /dev/null
+++ b/source3/libsmb/cliprint.c
@@ -0,0 +1,157 @@
+/*
+ Unix SMB/CIFS implementation.
+ client print 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.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+/*****************************************************************************
+ Convert a character pointer in a cli_call_api() response to a form we can use.
+ This function contains code to prevent core dumps if the server returns
+ invalid data.
+*****************************************************************************/
+static char *fix_char_ptr(unsigned int datap, unsigned int converter,
+ char *rdata, int rdrcnt)
+{
+ if (datap == 0) { /* turn NULL pointers into zero length strings */
+ return "";
+ } else {
+ unsigned int offset = datap - converter;
+
+ if (offset >= rdrcnt) {
+ DEBUG(1,("bad char ptr: datap=%u, converter=%u rdrcnt=%d>",
+ datap, converter, rdrcnt));
+ return "<ERROR>";
+ } else {
+ return &rdata[offset];
+ }
+ }
+}
+
+
+/****************************************************************************
+call fn() on each entry in a print queue
+****************************************************************************/
+int cli_print_queue(struct cli_state *cli,
+ void (*fn)(struct print_job_info *))
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt, rprcnt;
+ pstring param;
+ int result_code=0;
+ int i = -1;
+
+ memset(param,'\0',sizeof(param));
+
+ p = param;
+ SSVAL(p,0,76); /* API function number 76 (DosPrintJobEnum) */
+ p += 2;
+ pstrcpy(p,"zWrLeh"); /* parameter description? */
+ p = skip_string(p,1);
+ pstrcpy(p,"WWzWWDDzz"); /* returned data format */
+ p = skip_string(p,1);
+ pstrcpy(p,cli->share); /* name of queue */
+ p = skip_string(p,1);
+ SSVAL(p,0,2); /* API function level 2, PRJINFO_2 data structure */
+ SSVAL(p,2,1000); /* size of bytes of returned data buffer */
+ p += 4;
+ pstrcpy(p,""); /* subformat */
+ p = skip_string(p,1);
+
+ DEBUG(4,("doing cli_print_queue for %s\n", cli->share));
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) { /* return data, length */
+ int converter;
+ result_code = SVAL(rparam,0);
+ converter = SVAL(rparam,2); /* conversion factor */
+
+ if (result_code == 0) {
+ struct print_job_info job;
+
+ p = rdata;
+
+ for (i = 0; i < SVAL(rparam,4); ++i) {
+ job.id = SVAL(p,0);
+ job.priority = SVAL(p,2);
+ fstrcpy(job.user,
+ fix_char_ptr(SVAL(p,4), converter,
+ rdata, rdrcnt));
+ job.t = make_unix_date3(p + 12);
+ job.size = IVAL(p,16);
+ fstrcpy(job.name,fix_char_ptr(SVAL(p,24),
+ converter,
+ rdata, rdrcnt));
+ fn(&job);
+ p += 28;
+ }
+ }
+ }
+
+ /* If any parameters or data were returned, free the storage. */
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return i;
+}
+
+/****************************************************************************
+ cancel a print job
+ ****************************************************************************/
+int cli_printjob_del(struct cli_state *cli, int job)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt, ret = -1;
+ pstring param;
+
+ memset(param,'\0',sizeof(param));
+
+ p = param;
+ SSVAL(p,0,81); /* DosPrintJobDel() */
+ p += 2;
+ pstrcpy(p,"W");
+ p = skip_string(p,1);
+ pstrcpy(p,"");
+ p = skip_string(p,1);
+ SSVAL(p,0,job);
+ p += 2;
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) { /* return data, length */
+ ret = SVAL(rparam,0);
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return ret;
+}
+
+
diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c
new file mode 100644
index 0000000000..a2b6c8bb8b
--- /dev/null
+++ b/source3/libsmb/clirap.c
@@ -0,0 +1,738 @@
+/*
+ Unix SMB/CIFS implementation.
+ client RAP calls
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 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.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+
+/****************************************************************************
+Call a remote api on an arbitrary pipe. takes param, data and setup buffers.
+****************************************************************************/
+BOOL cli_api_pipe(struct cli_state *cli, char *pipe_name,
+ uint16 *setup, uint32 setup_count, uint32 max_setup_count,
+ char *params, uint32 param_count, uint32 max_param_count,
+ char *data, uint32 data_count, uint32 max_data_count,
+ char **rparam, uint32 *rparam_count,
+ char **rdata, uint32 *rdata_count)
+{
+ cli_send_trans(cli, SMBtrans,
+ pipe_name,
+ 0,0, /* fid, flags */
+ setup, setup_count, max_setup_count,
+ params, param_count, max_param_count,
+ data, data_count, max_data_count);
+
+ return (cli_receive_trans(cli, SMBtrans,
+ rparam, (int *)rparam_count,
+ rdata, (int *)rdata_count));
+}
+
+/****************************************************************************
+call a remote api
+****************************************************************************/
+BOOL cli_api(struct cli_state *cli,
+ char *param, int prcnt, int mprcnt,
+ char *data, int drcnt, int mdrcnt,
+ char **rparam, int *rprcnt,
+ char **rdata, int *rdrcnt)
+{
+ cli_send_trans(cli,SMBtrans,
+ PIPE_LANMAN, /* Name */
+ 0,0, /* fid, flags */
+ NULL,0,0, /* Setup, length, max */
+ param, prcnt, mprcnt, /* Params, length, max */
+ data, drcnt, mdrcnt /* Data, length, max */
+ );
+
+ return (cli_receive_trans(cli,SMBtrans,
+ rparam, rprcnt,
+ rdata, rdrcnt));
+}
+
+
+/****************************************************************************
+perform a NetWkstaUserLogon
+****************************************************************************/
+BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ pstring param;
+
+ memset(param, 0, sizeof(param));
+
+ /* send a SMBtrans command with api NetWkstaUserLogon */
+ p = param;
+ SSVAL(p,0,132); /* api number */
+ p += 2;
+ pstrcpy(p,"OOWb54WrLh");
+ p = skip_string(p,1);
+ pstrcpy(p,"WB21BWDWWDDDDDDDzzzD");
+ p = skip_string(p,1);
+ SSVAL(p,0,1);
+ p += 2;
+ pstrcpy(p,user);
+ strupper(p);
+ p += 21;
+ p++;
+ p += 15;
+ p++;
+ pstrcpy(p, workstation);
+ strupper(p);
+ p += 16;
+ SSVAL(p, 0, CLI_BUFFER_SIZE);
+ p += 2;
+ SSVAL(p, 0, CLI_BUFFER_SIZE);
+ p += 2;
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),1024, /* param, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt /* return data, return size */
+ )) {
+ cli->rap_error = rparam? SVAL(rparam,0) : -1;
+ p = rdata;
+
+ if (cli->rap_error == 0) {
+ DEBUG(4,("NetWkstaUserLogon success\n"));
+ cli->privileges = SVAL(p, 24);
+ fstrcpy(cli->eff_name,p+2);
+ } else {
+ DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
+ }
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+ return (cli->rap_error == 0);
+}
+
+/****************************************************************************
+call a NetShareEnum - try and browse available connections on a host
+****************************************************************************/
+int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ pstring param;
+ int count = -1;
+
+ /* now send a SMBtrans command with api RNetShareEnum */
+ p = param;
+ SSVAL(p,0,0); /* api number */
+ p += 2;
+ pstrcpy(p,"WrLeh");
+ p = skip_string(p,1);
+ pstrcpy(p,"B13BWz");
+ p = skip_string(p,1);
+ SSVAL(p,0,1);
+ /*
+ * Win2k needs a *smaller* buffer than 0xFFFF here -
+ * it returns "out of server memory" with 0xFFFF !!! JRA.
+ */
+ SSVAL(p,2,0xFFE0);
+ p += 4;
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 0xFFE0, /* data, length, maxlen - Win2k needs a small buffer here too ! */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ int res = rparam? SVAL(rparam,0) : -1;
+
+ if (res == 0 || res == ERRmoredata) {
+ int converter=SVAL(rparam,2);
+ int i;
+
+ count=SVAL(rparam,4);
+ p = rdata;
+
+ for (i=0;i<count;i++,p+=20) {
+ char *sname = p;
+ int type = SVAL(p,14);
+ int comment_offset = IVAL(p,16) & 0xFFFF;
+ char *cmnt = comment_offset?(rdata+comment_offset-converter):"";
+ pstring s1, s2;
+
+ pull_ascii_pstring(s1, sname);
+ pull_ascii_pstring(s2, cmnt);
+
+ fn(s1, type, s2, state);
+ }
+ } else {
+ DEBUG(4,("NetShareEnum res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetShareEnum failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return count;
+}
+
+
+/****************************************************************************
+call a NetServerEnum for the specified workgroup and servertype mask. This
+function then calls the specified callback function for each name returned.
+
+The callback function takes 4 arguments: the machine name, the server type,
+the comment and a state pointer.
+****************************************************************************/
+BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
+ void (*fn)(const char *, uint32, const char *, void *),
+ void *state)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rdrcnt,rprcnt;
+ char *p;
+ pstring param;
+ int uLevel = 1;
+ int count = -1;
+
+ /* send a SMBtrans command with api NetServerEnum */
+ p = param;
+ SSVAL(p,0,0x68); /* api number */
+ p += 2;
+ pstrcpy(p,"WrLehDz");
+ p = skip_string(p,1);
+
+ pstrcpy(p,"B16BBDz");
+
+ p = skip_string(p,1);
+ SSVAL(p,0,uLevel);
+ SSVAL(p,2,CLI_BUFFER_SIZE);
+ p += 4;
+ SIVAL(p,0,stype);
+ p += 4;
+
+ p += push_pstring(p, workgroup);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 8, /* params, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt /* return data, return size */
+ )) {
+ int res = rparam? SVAL(rparam,0) : -1;
+
+ if (res == 0 || res == ERRmoredata) {
+ int i;
+ int converter=SVAL(rparam,2);
+
+ count=SVAL(rparam,4);
+ p = rdata;
+
+ for (i = 0;i < count;i++, p += 26) {
+ char *sname = p;
+ int comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
+ char *cmnt = comment_offset?(rdata+comment_offset):"";
+ pstring s1, s2;
+
+ if (comment_offset < 0 || comment_offset > rdrcnt) continue;
+
+ stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
+
+ pull_ascii_pstring(s1, sname);
+ pull_ascii_pstring(s2, cmnt);
+ fn(s1, stype, s2, state);
+ }
+ }
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return(count > 0);
+}
+
+
+
+/****************************************************************************
+Send a SamOEMChangePassword command
+****************************************************************************/
+BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
+ const char *old_password)
+{
+ char param[16+sizeof(fstring)];
+ char data[532];
+ char *p = param;
+ fstring upper_case_old_pw;
+ fstring upper_case_new_pw;
+ unsigned char old_pw_hash[16];
+ unsigned char new_pw_hash[16];
+ int data_len;
+ int param_len = 0;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rprcnt, rdrcnt;
+ pstring dos_new_password;
+
+ if (strlen(user) >= sizeof(fstring)-1) {
+ DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
+ return False;
+ }
+
+ SSVAL(p,0,214); /* SamOEMChangePassword command. */
+ p += 2;
+ pstrcpy(p, "zsT");
+ p = skip_string(p,1);
+ pstrcpy(p, "B516B16");
+ p = skip_string(p,1);
+ pstrcpy(p,user);
+ p = skip_string(p,1);
+ SSVAL(p,0,532);
+ p += 2;
+
+ param_len = PTR_DIFF(p,param);
+
+ /*
+ * Get the Lanman hash of the old password, we
+ * use this as the key to make_oem_passwd_hash().
+ */
+ memset(upper_case_old_pw, '\0', sizeof(upper_case_old_pw));
+ clistr_push(cli, upper_case_old_pw, old_password, -1,STR_TERMINATE|STR_UPPER|STR_ASCII);
+ E_P16((uchar *)upper_case_old_pw, old_pw_hash);
+
+ clistr_push(cli, dos_new_password, new_password, -1, STR_TERMINATE|STR_ASCII);
+
+ if (!make_oem_passwd_hash( data, dos_new_password, old_pw_hash, False))
+ return False;
+
+ /*
+ * Now place the old password hash in the data.
+ */
+ memset(upper_case_new_pw, '\0', sizeof(upper_case_new_pw));
+ clistr_push(cli, upper_case_new_pw, new_password, -1, STR_TERMINATE|STR_UPPER|STR_ASCII);
+
+ E_P16((uchar *)upper_case_new_pw, new_pw_hash);
+
+ E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
+
+ data_len = 532;
+
+ if (cli_send_trans(cli,SMBtrans,
+ PIPE_LANMAN, /* name */
+ 0,0, /* fid, flags */
+ NULL,0,0, /* setup, length, max */
+ param,param_len,2, /* param, length, max */
+ data,data_len,0 /* data, length, max */
+ ) == False) {
+ DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
+ user ));
+ return False;
+ }
+
+ if (cli_receive_trans(cli,SMBtrans,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ if (rparam)
+ cli->rap_error = SVAL(rparam,0);
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return (cli->rap_error == 0);
+}
+
+
+/****************************************************************************
+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)
+{
+ int data_len = 0;
+ int param_len = 0;
+ int rparam_len, rdata_len;
+ uint16 setup = TRANSACT2_QPATHINFO;
+ pstring param;
+ char *rparam=NULL, *rdata=NULL;
+ int count=8;
+ BOOL ret;
+ time_t (*date_fn)(void *);
+ char *p;
+
+ p = param;
+ memset(p, 0, 6);
+ SSVAL(p, 0, SMB_INFO_STANDARD);
+ p += 6;
+ p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
+
+ param_len = PTR_DIFF(p, param);
+
+ do {
+ ret = (cli_send_trans(cli, SMBtrans2,
+ NULL, /* Name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 10, /* param, length, max */
+ NULL, data_len, cli->max_xmit /* data, length, max */
+ ) &&
+ cli_receive_trans(cli, SMBtrans2,
+ &rparam, &rparam_len,
+ &rdata, &rdata_len));
+ if (!cli_is_dos_error(cli)) break;
+ if (!ret) {
+ /* we need to work around a Win95 bug - sometimes
+ it gives ERRSRV/ERRerror temprarily */
+ uint8 eclass;
+ uint32 ecode;
+ cli_dos_error(cli, &eclass, &ecode);
+ if (eclass != ERRSRV || ecode != ERRerror) break;
+ msleep(100);
+ }
+ } while (count-- && ret==False);
+
+ if (!ret || !rdata || rdata_len < 22) {
+ return False;
+ }
+
+ if (cli->win95) {
+ date_fn = make_unix_date;
+ } else {
+ date_fn = make_unix_date2;
+ }
+
+ if (c_time) {
+ *c_time = date_fn(rdata+0);
+ }
+ if (a_time) {
+ *a_time = date_fn(rdata+4);
+ }
+ if (m_time) {
+ *m_time = date_fn(rdata+8);
+ }
+ if (size) {
+ *size = IVAL(rdata, 12);
+ }
+ if (mode) {
+ *mode = SVAL(rdata,l1_attrFile);
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ 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)
+{
+ int data_len = 0;
+ int param_len = 0;
+ uint16 setup = TRANSACT2_QPATHINFO;
+ pstring param;
+ char *rparam=NULL, *rdata=NULL;
+ char *p;
+
+ p = param;
+ memset(p, 0, 6);
+ SSVAL(p, 0, SMB_QUERY_FILE_ALL_INFO);
+ p += 6;
+ p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
+
+ param_len = PTR_DIFF(p, param);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 10, /* param, length, max */
+ NULL, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return False;
+ }
+
+ if (!rdata || data_len < 22) {
+ return False;
+ }
+
+ if (c_time) {
+ *c_time = interpret_long_date(rdata+0) - cli->serverzone;
+ }
+ if (a_time) {
+ *a_time = interpret_long_date(rdata+8) - cli->serverzone;
+ }
+ if (m_time) {
+ *m_time = interpret_long_date(rdata+16) - cli->serverzone;
+ }
+ if (w_time) {
+ *w_time = interpret_long_date(rdata+24) - cli->serverzone;
+ }
+ if (mode) {
+ *mode = SVAL(rdata, 32);
+ }
+ if (size) {
+ *size = IVAL(rdata, 48);
+ }
+ if (ino) {
+ *ino = IVAL(rdata, 64);
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return True;
+}
+
+
+/****************************************************************************
+send a qfileinfo QUERY_FILE_NAME_INFO call
+****************************************************************************/
+BOOL cli_qfilename(struct cli_state *cli, int fnum,
+ pstring name)
+{
+ int data_len = 0;
+ int param_len = 0;
+ uint16 setup = TRANSACT2_QFILEINFO;
+ pstring param;
+ char *rparam=NULL, *rdata=NULL;
+
+ param_len = 4;
+ memset(param, 0, param_len);
+ SSVAL(param, 0, fnum);
+ SSVAL(param, 2, SMB_QUERY_FILE_NAME_INFO);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ NULL, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return False;
+ }
+
+ if (!rdata || data_len < 4) {
+ return False;
+ }
+
+ clistr_pull(cli, name, rdata+4, sizeof(pstring), IVAL(rdata, 0), STR_UNICODE);
+
+ 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)
+{
+ int data_len = 0;
+ int param_len = 0;
+ uint16 setup = TRANSACT2_QFILEINFO;
+ pstring param;
+ char *rparam=NULL, *rdata=NULL;
+
+ /* if its a win95 server then fail this - win95 totally screws it
+ up */
+ if (cli->win95) return False;
+
+ param_len = 4;
+
+ memset(param, 0, param_len);
+ SSVAL(param, 0, fnum);
+ SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ NULL, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return False;
+ }
+
+ if (!rdata || data_len < 68) {
+ return False;
+ }
+
+ if (c_time) {
+ *c_time = interpret_long_date(rdata+0) - cli->serverzone;
+ }
+ if (a_time) {
+ *a_time = interpret_long_date(rdata+8) - cli->serverzone;
+ }
+ if (m_time) {
+ *m_time = interpret_long_date(rdata+16) - cli->serverzone;
+ }
+ if (w_time) {
+ *w_time = interpret_long_date(rdata+24) - cli->serverzone;
+ }
+ if (mode) {
+ *mode = SVAL(rdata, 32);
+ }
+ if (size) {
+ *size = IVAL(rdata, 48);
+ }
+ if (ino) {
+ *ino = IVAL(rdata, 64);
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return True;
+}
+
+/****************************************************************************
+send a qfileinfo call
+****************************************************************************/
+BOOL cli_qfileinfo_test(struct cli_state *cli, int fnum, int level, char *outdata)
+{
+ int data_len = 0;
+ int param_len = 0;
+ uint16 setup = TRANSACT2_QFILEINFO;
+ pstring param;
+ char *rparam=NULL, *rdata=NULL;
+
+ /* if its a win95 server then fail this - win95 totally screws it
+ up */
+ if (cli->win95) return False;
+
+ param_len = 4;
+
+ memset(param, 0, param_len);
+ SSVAL(param, 0, fnum);
+ SSVAL(param, 2, level);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ NULL, data_len, cli->max_xmit /* data, length, max */
+ )) {
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return False;
+ }
+
+ memcpy(outdata, rdata, data_len);
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return True;
+}
+
+
+
+/****************************************************************************
+send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call
+****************************************************************************/
+NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
+{
+ int data_len = 0;
+ int param_len = 0;
+ uint16 setup = TRANSACT2_QPATHINFO;
+ pstring param;
+ char *rparam=NULL, *rdata=NULL;
+ int count=8;
+ char *p;
+ BOOL ret;
+ int len;
+
+ p = param;
+ memset(p, 0, 6);
+ SSVAL(p, 0, SMB_QUERY_FILE_ALT_NAME_INFO);
+ p += 6;
+ p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
+
+ param_len = PTR_DIFF(p, param);
+
+ do {
+ ret = (cli_send_trans(cli, SMBtrans2,
+ NULL, /* Name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 10, /* param, length, max */
+ NULL, data_len, cli->max_xmit /* data, length, max */
+ ) &&
+ cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len));
+ if (!ret && cli_is_dos_error(cli)) {
+ /* we need to work around a Win95 bug - sometimes
+ it gives ERRSRV/ERRerror temprarily */
+ uint8 eclass;
+ uint32 ecode;
+ cli_dos_error(cli, &eclass, &ecode);
+ if (eclass != ERRSRV || ecode != ERRerror) break;
+ msleep(100);
+ }
+ } while (count-- && ret==False);
+
+ if (!ret || !rdata || data_len < 4) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ len = IVAL(rdata, 0);
+
+ if (len > data_len - 4) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ clistr_pull(cli, alt_name, rdata+4, sizeof(fstring), len, 0);
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return NT_STATUS_OK;
+}
diff --git a/source3/libsmb/clirap2.c b/source3/libsmb/clirap2.c
new file mode 100644
index 0000000000..00cd4b15f3
--- /dev/null
+++ b/source3/libsmb/clirap2.c
@@ -0,0 +1,1961 @@
+/*
+ Samba Unix/Linux SMB client library
+ More client RAP (SMB Remote Procedure Calls) functions
+ Copyright (C) 2001 Steve French (sfrench@us.ibm.com)
+ Copyright (C) 2001 Jim McDonough (jmcd@us.ibm.com)
+
+
+ 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.
+*/
+
+/*****************************************************/
+/* */
+/* Additional RAP functionality */
+/* */
+/* RAP is the original SMB RPC, documented */
+/* by Microsoft and X/Open in the 1990s and */
+/* supported by most SMB/CIFS servers although */
+/* it is unlikely that any one implementation */
+/* supports all RAP command codes since some */
+/* are quite obsolete and a few are specific */
+/* to a particular network operating system */
+/* */
+/* Although it has largely been replaced */
+/* for complex remote admistration and management */
+/* (of servers) by the relatively newer */
+/* DCE/RPC based remote API (which better handles */
+/* large >64K data structures), there are many */
+/* important administrative and resource location */
+/* tasks and user tasks (e.g. password change) */
+/* that are performed via RAP. */
+/* */
+/* Although a few of the RAP calls are implemented */
+/* in the Samba client library already (clirap.c) */
+/* the new ones are in clirap2.c for easy patching */
+/* and integration and a corresponding header */
+/* file, rap.h, has been created. */
+/* */
+/* This is based on data from the CIFS spec */
+/* and the LAN Server and LAN Manager */
+/* Programming Reference books and published */
+/* RAP document and CIFS forum postings and */
+/* lots of trial and error */
+/* */
+/* Function names changed from API_ (as they are */
+/* in the CIFS specification) to RAP_ in order */
+/* to avoid confusion with other API calls */
+/* sent via DCE RPC */
+/* */
+/*****************************************************/
+
+/*****************************************************/
+/* */
+/* cifsrap.c already includes support for: */
+/* */
+/* WshareEnum ( API number 0, level 1) */
+/* NetServerEnum2 (API num 104, level 1) */
+/* WWkstaUserLogon (132) */
+/* SamOEMchgPasswordUser2_P (214) */
+/* */
+/* cifsprint.c already includes support for: */
+/* */
+/* WPrintJobEnum (API num 76, level 2) */
+/* WPrintJobDel (API num 81) */
+/* */
+/*****************************************************/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+#define WORDSIZE 2
+#define DWORDSIZE 4
+
+#define PUTBYTE(p,b) do {SCVAL(p,0,b); p++;} while(0)
+#define GETBYTE(p,b) do {b = CVAL(p,0); p++;} while(0)
+#define PUTWORD(p,w) do {SSVAL(p,0,w); p += WORDSIZE;} while(0)
+#define GETWORD(p,w) do {w = SVAL(p,0); p += WORDSIZE;} while(0)
+#define PUTDWORD(p,d) do {SIVAL(p,0,d); p += DWORDSIZE;} while(0)
+#define GETDWORD(p,d) do {d = IVAL(p,0); p += DWORDSIZE;} while(0)
+#define GETRES(p) p ? SVAL(p,0) : -1
+/* put string s at p with max len n and increment p past string */
+#define PUTSTRING(p,s,n) do {\
+ push_ascii(p,s?s:"",n?n:256,STR_TERMINATE);\
+ p = skip_string(p,1);\
+ } while(0)
+/* put string s and p, using fixed len l, and increment p by l */
+#define PUTSTRINGF(p,s,l) do {\
+ push_ascii(p,s?s:"",l,STR_TERMINATE);\
+ p += l;\
+ } while (0)
+/* put string pointer at p, supplying offset o from rdata r, store */
+/* dword offset at p, increment p by 4 and o by length of s. This */
+/* means on the first call, you must calc the offset yourself! */
+#define PUTSTRINGP(p,s,r,o) do {\
+ if (s) {\
+ push_ascii(r+o,s,strlen(s)+1,STR_TERMINATE);\
+ PUTDWORD(p,o);\
+ o += strlen(s) + 1;\
+ } else PUTDWORD(p,0);\
+ }while(0);
+/* get asciiz string s from p, increment p past string */
+#define GETSTRING(p,s) do {\
+ pull_ascii_pstring(s,p);\
+ p = skip_string(p,1);\
+ } while(0)
+/* get fixed length l string s from p, increment p by l */
+#define GETSTRINGF(p,s,l) do {\
+ pull_ascii_pstring(s,p);\
+ p += l;\
+ } while(0)
+/* get string s from offset (obtained at p) from rdata r - converter c */
+#define GETSTRINGP(p,s,r,c) do {\
+ uint32 off;\
+ GETDWORD(p,off);\
+ off &= 0x0000FFFF; /* mask the obsolete segment number from the offset */ \
+ pull_ascii_pstring(s, off?(r+off-c):"");\
+ } while(0)
+
+static char *make_header(char *param, uint16 apinum, char *reqfmt, char *datafmt)
+{
+ PUTWORD(param,apinum);
+ if (reqfmt)
+ PUTSTRING(param,reqfmt,0);
+ else
+ *param++ = (char) 0;
+
+ if (datafmt)
+ PUTSTRING(param,datafmt,0);
+ else
+ *param++ = (char) 0;
+
+ return param;
+}
+
+
+/****************************************************************************
+ call a NetGroupDelete - delete user group from remote server
+****************************************************************************/
+int cli_NetGroupDelete(struct cli_state *cli, const char *group_name )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt, res;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupDel_REQ) /* parm string */
+ +1 /* no ret string */
+ +RAP_GROUPNAME_LEN /* group to del */
+ +WORDSIZE]; /* reserved word */
+
+ /* now send a SMBtrans command with api GroupDel */
+ p = make_header(param, RAP_WGroupDel, RAP_NetGroupDel_REQ, NULL);
+ PUTSTRING(p, group_name, RAP_GROUPNAME_LEN);
+ PUTWORD(p,0); /* reserved word MBZ on input */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 200, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = GETRES(rparam);
+
+ if (res == 0) {
+ /* nothing to do */
+ }
+ else if ((res == 5) || (res == 65)) {
+ DEBUG(1, ("Access Denied\n"));
+ }
+ else if (res == 2220) {
+ DEBUG (1, ("Group does not exist\n"));
+ }
+ else {
+ DEBUG(4,("NetGroupDelete res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetGroupDelete failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+ call a NetGroupAdd - add user group to remote server
+****************************************************************************/
+int cli_NetGroupAdd(struct cli_state *cli, RAP_GROUP_INFO_1 * grinfo )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt,res;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupAdd_REQ) /* req string */
+ +sizeof(RAP_GROUP_INFO_L1) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* reserved word */
+
+ char data[1024];
+
+ /* offset into data of free format strings. Will be updated */
+ /* by PUTSTRINGP macro and end up with total data length. */
+ int soffset = RAP_GROUPNAME_LEN + 1 + DWORDSIZE;
+
+ /* now send a SMBtrans command with api WGroupAdd */
+
+ p = make_header(param, RAP_WGroupAdd,
+ RAP_NetGroupAdd_REQ, RAP_GROUP_INFO_L1);
+ PUTWORD(p, 1); /* info level */
+ PUTWORD(p, 0); /* reserved word 0 */
+
+ p = data;
+ PUTSTRINGF(p, grinfo->group_name, RAP_GROUPNAME_LEN);
+ PUTBYTE(p, 0); /* pad byte 0 */
+ PUTSTRINGP(p, grinfo->comment, data, soffset);
+
+ if (cli_api(cli,
+ param, sizeof(param), 1024, /* Param, length, maxlen */
+ data, soffset, sizeof(data), /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = GETRES(rparam);
+
+ if (res == 0) {
+ /* nothing to do */
+ } else if ((res == 5) || (res == 65)) {
+ DEBUG(1, ("Access Denied\n"));
+ }
+ else if (res == 2223) {
+ DEBUG (1, ("Group already exists\n"));
+ }
+ else {
+ DEBUG(4,("NetGroupAdd res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetGroupAdd failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+call a NetGroupEnum - try and list user groups on a different host
+****************************************************************************/
+int cli_RNetGroupEnum(struct cli_state *cli, void (*fn)(const char *, const char *, void *), void *state)
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupEnum_REQ) /* parm string */
+ +sizeof(RAP_GROUP_INFO_L1) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rprcnt, rdrcnt;
+ int res = -1;
+
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WGroupEnum,
+ RAP_NetGroupEnum_REQ, RAP_GROUP_INFO_L1);
+ PUTWORD(p,1); /* Info level 1 */ /* add level 0 */
+ PUTWORD(p,0xFFE0); /* Return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),8,
+ NULL, 0, 0xFFE0 /* data area size */,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ res = GETRES(rparam);
+ cli->rap_error = res;
+ if(cli->rap_error == 234)
+ DEBUG(1,("Not all group names were returned (such as those longer than 21 characters)\n"));
+ else if (cli->rap_error != 0) {
+ DEBUG(1,("NetGroupEnum gave error %d\n", cli->rap_error));
+ }
+ }
+
+ if (rdata) {
+ if (res == 0 || res == ERRmoredata) {
+ int i, converter, count;
+
+ p = rparam + WORDSIZE; /* skip result */
+ GETWORD(p, converter);
+ GETWORD(p, count);
+
+ for (i=0,p=rdata;i<count;i++) {
+ pstring comment;
+ char groupname[RAP_GROUPNAME_LEN];
+
+ GETSTRINGF(p, groupname, RAP_GROUPNAME_LEN);
+ p++; /* pad byte */
+ GETSTRINGP(p, comment, rdata, converter);
+
+ fn(groupname, comment, cli);
+ }
+ } else {
+ DEBUG(4,("NetGroupEnum res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetGroupEnum no data returned\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+int cli_NetGroupDelUser(struct cli_state * cli, const char *group_name, const char *user_name)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt,res;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupDelUser_REQ) /* parm string */
+ +1 /* no ret string */
+ +RAP_GROUPNAME_LEN /* group name */
+ +RAP_USERNAME_LEN]; /* user to del */
+
+ /* now send a SMBtrans command with api GroupMemberAdd */
+ p = make_header(param, RAP_WGroupDelUser, RAP_NetGroupDelUser_REQ, NULL);
+ PUTSTRING(p,group_name,RAP_GROUPNAME_LEN);
+ PUTSTRING(p,user_name,RAP_USERNAME_LEN);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 200, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = GETRES(rparam);
+
+ switch(res) {
+ case 0:
+ break;
+ case 5:
+ case 65:
+ DEBUG(1, ("Access Denied\n"));
+ break;
+ case 50:
+ DEBUG(1, ("Not supported by server\n"));
+ break;
+ case 2220:
+ DEBUG(1, ("Group does not exist\n"));
+ break;
+ case 2221:
+ DEBUG(1, ("User does not exist\n"));
+ break;
+ case 2237:
+ DEBUG(1, ("User is not in group\n"));
+ break;
+ default:
+ DEBUG(4,("NetGroupDelUser res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetGroupDelUser failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+int cli_NetGroupAddUser(struct cli_state * cli, const char *group_name, const char *user_name)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt,res;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupAddUser_REQ) /* parm string */
+ +1 /* no ret string */
+ +RAP_GROUPNAME_LEN /* group name */
+ +RAP_USERNAME_LEN]; /* user to add */
+
+ /* now send a SMBtrans command with api GroupMemberAdd */
+ p = make_header(param, RAP_WGroupAddUser, RAP_NetGroupAddUser_REQ, NULL);
+ PUTSTRING(p,group_name,RAP_GROUPNAME_LEN);
+ PUTSTRING(p,user_name,RAP_USERNAME_LEN);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 200, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = GETRES(rparam);
+
+ switch(res) {
+ case 0:
+ break;
+ case 5:
+ case 65:
+ DEBUG(1, ("Access Denied\n"));
+ break;
+ case 50:
+ DEBUG(1, ("Not supported by server\n"));
+ break;
+ case 2220:
+ DEBUG(1, ("Group does not exist\n"));
+ break;
+ case 2221:
+ DEBUG(1, ("User does not exist\n"));
+ break;
+ default:
+ DEBUG(4,("NetGroupAddUser res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetGroupAddUser failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+
+int cli_NetGroupGetUsers(struct cli_state * cli, const char *group_name, void (*fn)(const char *, void *), void *state )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ int res = -1;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupGetUsers_REQ)/* parm string */
+ +sizeof(RAP_GROUP_USERS_INFO_0) /* return string */
+ +RAP_GROUPNAME_LEN /* group name */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+
+ /* now send a SMBtrans command with api GroupGetUsers */
+ p = make_header(param, RAP_WGroupGetUsers,
+ RAP_NetGroupGetUsers_REQ, RAP_GROUP_USERS_INFO_0);
+ PUTSTRING(p,group_name,RAP_GROUPNAME_LEN-1);
+ PUTWORD(p,0); /* info level 0 */
+ PUTWORD(p,0xFFE0); /* return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),PTR_DIFF(p,param),
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ res = GETRES(rparam);
+ cli->rap_error = res;
+ if (res != 0) {
+ DEBUG(1,("NetGroupGetUsers gave error %d\n", res));
+ }
+ }
+ if (rdata) {
+ if (res == 0 || res == ERRmoredata) {
+ int i, converter, count;
+ fstring username;
+ p = rparam +WORDSIZE;
+ GETWORD(p, converter);
+ GETWORD(p, count);
+
+ for (i=0,p=rdata; i<count; i++) {
+ GETSTRINGF(p, username, RAP_USERNAME_LEN);
+ fn(username, state);
+ }
+ } else {
+ DEBUG(4,("NetGroupGetUsers res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetGroupGetUsers no data returned\n"));
+ }
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return res;
+}
+
+int cli_NetUserGetGroups(struct cli_state * cli, const char *user_name, void (*fn)(const char *, void *), void *state )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ int res = -1;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetUserGetGroups_REQ)/* parm string */
+ +sizeof(RAP_GROUP_USERS_INFO_0) /* return string */
+ +RAP_USERNAME_LEN /* user name */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+
+ /* now send a SMBtrans command with api GroupGetUsers */
+ p = make_header(param, RAP_WUserGetGroups,
+ RAP_NetUserGetGroups_REQ, RAP_GROUP_USERS_INFO_0);
+ PUTSTRING(p,user_name,RAP_USERNAME_LEN-1);
+ PUTWORD(p,0); /* info level 0 */
+ PUTWORD(p,0xFFE0); /* return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),PTR_DIFF(p,param),
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ res = GETRES(rparam);
+ cli->rap_error = res;
+ if (res != 0) {
+ DEBUG(1,("NetUserGetGroups gave error %d\n", res));
+ }
+ }
+ if (rdata) {
+ if (res == 0 || res == ERRmoredata) {
+ int i, converter, count;
+ fstring groupname;
+ p = rparam +WORDSIZE;
+ GETWORD(p, converter);
+ GETWORD(p, count);
+
+ for (i=0,p=rdata; i<count; i++) {
+ GETSTRINGF(p, groupname, RAP_USERNAME_LEN);
+ fn(groupname, state);
+ }
+ } else {
+ DEBUG(4,("NetUserGetGroups res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetUserGetGroups no data returned\n"));
+ }
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return res;
+}
+
+
+/****************************************************************************
+ call a NetUserDelete - delete user from remote server
+****************************************************************************/
+int cli_NetUserDelete(struct cli_state *cli, const char * user_name )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt, res;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetGroupDel_REQ) /* parm string */
+ +1 /* no ret string */
+ +RAP_USERNAME_LEN /* user to del */
+ +WORDSIZE]; /* reserved word */
+
+ /* now send a SMBtrans command with api UserDel */
+ p = make_header(param, RAP_WUserDel, RAP_NetGroupDel_REQ, NULL);
+ PUTSTRING(p, user_name, RAP_USERNAME_LEN);
+ PUTWORD(p,0); /* reserved word MBZ on input */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 200, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = GETRES(rparam);
+
+ if (res == 0) {
+ /* nothing to do */
+ }
+ else if ((res == 5) || (res == 65)) {
+ DEBUG(1, ("Access Denied\n"));
+ }
+ else if (res == 2221) {
+ DEBUG (1, ("User does not exist\n"));
+ }
+ else {
+ DEBUG(4,("NetUserDelete res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetUserDelete failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+ call a NetUserAdd - add user to remote server
+****************************************************************************/
+int cli_NetUserAdd(struct cli_state *cli, RAP_USER_INFO_1 * userinfo )
+{
+
+
+
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt,res;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetUserAdd2_REQ) /* req string */
+ +sizeof(RAP_USER_INFO_L1) /* data string */
+ +WORDSIZE /* info level */
+ +WORDSIZE /* buffer length */
+ +WORDSIZE]; /* reserved */
+
+ char data[1024];
+ /* offset into data of free format strings. Will be updated */
+ /* by PUTSTRINGP macro and end up with total data length. */
+ int soffset=RAP_USERNAME_LEN+1 /* user name + pad */
+ + RAP_UPASSWD_LEN /* password */
+ + DWORDSIZE /* password age */
+ + WORDSIZE /* privilege */
+ + DWORDSIZE /* home dir ptr */
+ + DWORDSIZE /* comment ptr */
+ + WORDSIZE /* flags */
+ + DWORDSIZE; /* login script ptr*/
+
+ /* now send a SMBtrans command with api NetUserAdd */
+ p = make_header(param, RAP_WUserAdd2,
+ RAP_NetUserAdd2_REQ, RAP_USER_INFO_L1);
+ PUTWORD(p, 1); /* info level */
+
+ PUTWORD(p, 0); /* pwencrypt */
+ if(userinfo->passwrd)
+ PUTWORD(p,MIN(strlen(userinfo->passwrd), RAP_UPASSWD_LEN));
+ else
+ PUTWORD(p, 0); /* password length */
+
+ p = data;
+ memset(data, '\0', soffset);
+
+ PUTSTRINGF(p, userinfo->user_name, RAP_USERNAME_LEN);
+ PUTBYTE(p, 0); /* pad byte 0 */
+ PUTSTRINGF(p, userinfo->passwrd, RAP_UPASSWD_LEN);
+ PUTDWORD(p, 0); /* pw age - n.a. on user add */
+ PUTWORD(p, userinfo->priv);
+ PUTSTRINGP(p, userinfo->home_dir, data, soffset);
+ PUTSTRINGP(p, userinfo->comment, data, soffset);
+ PUTWORD(p, userinfo->userflags);
+ PUTSTRINGP(p, userinfo->logon_script, data, soffset);
+
+ if (cli_api(cli,
+ param, sizeof(param), 1024, /* Param, length, maxlen */
+ data, soffset, sizeof(data), /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = GETRES(rparam);
+
+ if (res == 0) {
+ /* nothing to do */
+ }
+ else if ((res == 5) || (res == 65)) {
+ DEBUG(1, ("Access Denied\n"));
+ }
+ else if (res == 2224) {
+ DEBUG (1, ("User already exists\n"));
+ }
+ else {
+ DEBUG(4,("NetUserAdd res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetUserAdd failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+call a NetUserEnum - try and list users on a different host
+****************************************************************************/
+int cli_RNetUserEnum(struct cli_state *cli, void (*fn)(const char *, const char *, const char *, const char *, void *), void *state)
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetUserEnum_REQ) /* parm string */
+ +sizeof(RAP_USER_INFO_L1) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rprcnt, rdrcnt;
+ int res = -1;
+
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WUserEnum,
+ RAP_NetUserEnum_REQ, RAP_USER_INFO_L1);
+ PUTWORD(p,1); /* Info level 1 */
+ PUTWORD(p,0xFF00); /* Return buffer size */
+
+/* BB Fix handling of large numbers of users to be returned */
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),8,
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ res = GETRES(rparam);
+ cli->rap_error = res;
+ if (cli->rap_error != 0) {
+ DEBUG(1,("NetUserEnum gave error %d\n", cli->rap_error));
+ }
+ }
+ if (rdata) {
+ if (res == 0 || res == ERRmoredata) {
+ int i, converter, count;
+ char username[RAP_USERNAME_LEN];
+ char userpw[RAP_UPASSWD_LEN];
+ pstring comment, homedir, logonscript;
+ int pwage, priv, flags;
+
+ p = rparam + WORDSIZE; /* skip result */
+ GETWORD(p, converter);
+ GETWORD(p, count);
+
+ for (i=0,p=rdata;i<count;i++) {
+ GETSTRINGF(p, username, RAP_USERNAME_LEN);
+ p++; /* pad byte */
+ GETSTRINGF(p, userpw, RAP_UPASSWD_LEN);
+ GETDWORD(p, pwage); /* password age */
+ GETWORD(p, priv); /* 0=guest, 1=user, 2=admin */
+ GETSTRINGP(p, homedir, rdata, converter);
+ GETSTRINGP(p, comment, rdata, converter);
+ GETWORD(p, flags);
+ GETSTRINGP(p, logonscript, rdata, converter);
+
+ fn(username, comment, homedir, logonscript, cli);
+ }
+ } else {
+ DEBUG(4,("NetUserEnum res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetUserEnum no data returned\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+ call a NetFileClose2 - close open file on another session to server
+****************************************************************************/
+int cli_NetFileClose(struct cli_state *cli, uint32 file_id )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WFileClose2_REQ) /* req string */
+ +1 /* no ret string */
+ +DWORDSIZE]; /* file ID */
+ int res = -1;
+
+ /* now send a SMBtrans command with api RNetShareEnum */
+ p = make_header(param, RAP_WFileClose2, RAP_WFileClose2_REQ, NULL);
+ PUTDWORD(p, file_id);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 200, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = GETRES(rparam);
+
+ if (res == 0) {
+ /* nothing to do */
+ } else if (res == 2314){
+ DEBUG(1, ("NetFileClose2 - attempt to close non-existant file open instance\n"));
+ } else {
+ DEBUG(4,("NetFileClose2 res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetFileClose2 failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+call a NetFileGetInfo - get information about server file opened from other
+ workstation
+****************************************************************************/
+int cli_NetFileGetInfo(struct cli_state *cli, uint32 file_id, void (*fn)(const char *, const char *, uint16, uint16, uint32))
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt, res;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WFileGetInfo2_REQ) /* req string */
+ +sizeof(RAP_FILE_INFO_L3) /* return string */
+ +DWORDSIZE /* file ID */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+
+ /* now send a SMBtrans command with api RNetShareEnum */
+ p = make_header(param, RAP_WFileGetInfo2,
+ RAP_WFileGetInfo2_REQ, RAP_FILE_INFO_L3);
+ PUTDWORD(p, file_id);
+ PUTWORD(p, 3); /* info level */
+ PUTWORD(p, 0x1000); /* buffer size */
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 0x1000, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = GETRES(rparam);
+ if (res == 0 || res == ERRmoredata) {
+ int converter,id, perms, locks;
+ pstring fpath, fuser;
+
+ p = rparam + WORDSIZE; /* skip result */
+ GETWORD(p, converter);
+
+ p = rdata;
+ GETDWORD(p, id);
+ GETWORD(p, perms);
+ GETWORD(p, locks);
+ GETSTRINGP(p, fpath, rdata, converter);
+ GETSTRINGP(p, fuser, rdata, converter);
+
+ fn(fpath, fuser, perms, locks, id);
+ } else {
+ DEBUG(4,("NetFileGetInfo2 res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetFileGetInfo2 failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+* Call a NetFileEnum2 - list open files on an SMB server
+*
+* PURPOSE: Remotes a NetFileEnum API call to the current server or target
+* server listing the files open via the network (and their
+* corresponding open instance ids)
+*
+* Dependencies: none
+*
+* Parameters:
+* cli - pointer to cli_state structure
+* user - if present, return only files opened by this remote user
+* base_path - if present, return only files opened below this
+* base path
+* fn - display function to invoke for each entry in the result
+*
+*
+* Returns:
+* True - success
+* False - failure
+*
+****************************************************************************/
+int cli_NetFileEnum(struct cli_state *cli, char * user, char * base_path, void (*fn)(const char *, const char *, uint16, uint16, uint32))
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WFileEnum2_REQ) /* req string */
+ +sizeof(RAP_FILE_INFO_L3) /* return string */
+ +256 /* base path (opt) */
+ +RAP_USERNAME_LEN /* user name (opt) */
+ +WORDSIZE /* info level */
+ +WORDSIZE /* buffer size */
+ +DWORDSIZE /* resume key ? */
+ +DWORDSIZE]; /* resume key ? */
+ int count = -1;
+
+ /* now send a SMBtrans command with api RNetShareEnum */
+ p = make_header(param, RAP_WFileEnum2,
+ RAP_WFileEnum2_REQ, RAP_FILE_INFO_L3);
+
+ PUTSTRING(p, base_path, 256);
+ PUTSTRING(p, user, RAP_USERNAME_LEN);
+ PUTWORD(p, 3); /* info level */
+ PUTWORD(p, 0xFF00); /* buffer size */
+ PUTDWORD(p, 0); /* zero out the resume key */
+ PUTDWORD(p, 0); /* or is this one the resume key? */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 0xFF00, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ int res = GETRES(rparam);
+
+ if (res == 0 || res == ERRmoredata) {
+ int converter, i;
+
+ p = rparam + WORDSIZE; /* skip result */
+ GETWORD(p, converter);
+ GETWORD(p, count);
+
+ p = rdata;
+ for (i=0; i<count; i++) {
+ int id, perms, locks;
+ pstring fpath, fuser;
+
+ GETDWORD(p, id);
+ GETWORD(p, perms);
+ GETWORD(p, locks);
+ GETSTRINGP(p, fpath, rdata, converter);
+ GETSTRINGP(p, fuser, rdata, converter);
+
+ fn(fpath, fuser, perms, locks, id);
+ } /* BB fix ERRmoredata case to send resume request */
+ } else {
+ DEBUG(4,("NetFileEnum2 res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetFileEnum2 failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return count;
+}
+
+/****************************************************************************
+ call a NetShareAdd - share/export directory on remote server
+****************************************************************************/
+int cli_NetShareAdd(struct cli_state *cli, RAP_SHARE_INFO_2 * sinfo )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt,res;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WShareAdd_REQ) /* req string */
+ +sizeof(RAP_SHARE_INFO_L2) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* reserved word */
+ char data[1024];
+ /* offset to free format string section following fixed length data. */
+ /* will be updated by PUTSTRINGP macro and will end up with total len */
+ int soffset = RAP_SHARENAME_LEN + 1 /* share name + pad */
+ + WORDSIZE /* share type */
+ + DWORDSIZE /* comment pointer */
+ + WORDSIZE /* permissions */
+ + WORDSIZE /* max users */
+ + WORDSIZE /* active users */
+ + DWORDSIZE /* share path */
+ + RAP_SPASSWD_LEN + 1; /* share password + pad */
+
+ memset(param,'\0',sizeof(param));
+ /* now send a SMBtrans command with api RNetShareAdd */
+ p = make_header(param, RAP_WshareAdd,
+ RAP_WShareAdd_REQ, RAP_SHARE_INFO_L2);
+ PUTWORD(p, 2); /* info level */
+ PUTWORD(p, 0); /* reserved word 0 */
+
+ p = data;
+ PUTSTRINGF(p, sinfo->share_name, RAP_SHARENAME_LEN);
+ PUTBYTE(p, 0); /* pad byte 0 */
+
+ PUTWORD(p, sinfo->share_type);
+ PUTSTRINGP(p, sinfo->comment, data, soffset);
+ PUTWORD(p, sinfo->perms);
+ PUTWORD(p, sinfo->maximum_users);
+ PUTWORD(p, sinfo->active_users);
+ PUTSTRINGP(p, sinfo->path, data, soffset);
+ PUTSTRINGF(p, sinfo->password, RAP_SPASSWD_LEN);
+ SCVAL(p,-1,0x0A); /* required 0x0A at end of password */
+
+ if (cli_api(cli,
+ param, sizeof(param), 1024, /* Param, length, maxlen */
+ data, soffset, sizeof(data), /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = rparam? SVAL(rparam,0) : -1;
+
+ if (res == 0) {
+ /* nothing to do */
+ }
+ else {
+ DEBUG(4,("NetShareAdd res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetShareAdd failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+/****************************************************************************
+ call a NetShareDelete - unshare exported directory on remote server
+****************************************************************************/
+int cli_NetShareDelete(struct cli_state *cli, const char * share_name )
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt, res;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WShareDel_REQ) /* req string */
+ +1 /* no ret string */
+ +RAP_SHARENAME_LEN /* share to del */
+ +WORDSIZE]; /* reserved word */
+
+
+ /* now send a SMBtrans command with api RNetShareDelete */
+ p = make_header(param, RAP_WshareDel, RAP_WShareDel_REQ, NULL);
+ PUTSTRING(p,share_name,RAP_SHARENAME_LEN);
+ PUTWORD(p,0); /* reserved word MBZ on input */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 200, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = GETRES(rparam);
+
+ if (res == 0) {
+ /* nothing to do */
+ }
+ else {
+ DEBUG(4,("NetShareDelete res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetShareDelete failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+/*************************************************************************
+*
+* Function Name: cli_get_pdc_name
+*
+* PURPOSE: Remotes a NetServerEnum API call to the current server
+* requesting the name of a server matching the server
+* type of SV_TYPE_DOMAIN_CTRL (PDC).
+*
+* Dependencies: none
+*
+* Parameters:
+* cli - pointer to cli_state structure
+* workgroup - pointer to string containing name of domain
+* pdc_name - pointer to string that will contain PDC name
+* on successful return
+*
+* Returns:
+* True - success
+* False - failure
+*
+************************************************************************/
+BOOL cli_get_pdc_name(struct cli_state *cli, char *workgroup, char *pdc_name)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rdrcnt,rprcnt;
+ char *p;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetServerEnum2_REQ) /* req string */
+ +sizeof(RAP_SERVER_INFO_L1) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE /* buffer size */
+ +DWORDSIZE /* server type */
+ +RAP_MACHNAME_LEN]; /* workgroup */
+ int count = -1;
+
+ *pdc_name = '\0';
+
+ /* send a SMBtrans command with api NetServerEnum */
+ p = make_header(param, RAP_NetServerEnum2,
+ RAP_NetServerEnum2_REQ, RAP_SERVER_INFO_L1);
+ PUTWORD(p, 1); /* info level */
+ PUTWORD(p, CLI_BUFFER_SIZE);
+ PUTDWORD(p, SV_TYPE_DOMAIN_CTRL);
+ PUTSTRING(p, workgroup, RAP_MACHNAME_LEN);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 8, /* params, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt /* return data, return size */
+ )) {
+ cli->rap_error = GETRES(rparam);
+
+ /*
+ * We only really care to copy a name if the
+ * API succeeded and we got back a name.
+ */
+ if (cli->rap_error == 0) {
+ p = rparam + WORDSIZE + WORDSIZE; /* skip result and converter */
+ GETWORD(p, count);
+ p = rdata;
+
+ if (count > 0)
+ GETSTRING(p, pdc_name);
+ }
+ else {
+ DEBUG(4,("cli_get_pdc_name: machine %s failed the NetServerEnum call. "
+ "Error was : %s.\n", cli->desthost, cli_errstr(cli) ));
+ }
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return(count > 0);
+}
+
+
+/*************************************************************************
+*
+* Function Name: cli_get_server_domain
+*
+* PURPOSE: Remotes a NetWkstaGetInfo API call to the current server
+* requesting wksta_info_10 level information to determine
+* the domain the server belongs to. On success, this
+* routine sets the server_domain field in the cli_state structure
+* to the server's domain name.
+*
+* Dependencies: none
+*
+* Parameters:
+* cli - pointer to cli_state structure
+*
+* Returns:
+* True - success
+* False - failure
+*
+* Origins: samba 2.0.6 source/libsmb/clientgen.c cli_NetServerEnum()
+*
+************************************************************************/
+BOOL cli_get_server_domain(struct cli_state *cli)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rdrcnt,rprcnt;
+ char *p;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WWkstaGetInfo_REQ) /* req string */
+ +sizeof(RAP_WKSTA_INFO_L10) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ int res = -1;
+
+ /* send a SMBtrans command with api NetWkstaGetInfo */
+ p = make_header(param, RAP_WWkstaGetInfo,
+ RAP_WWkstaGetInfo_REQ, RAP_WKSTA_INFO_L10);
+ PUTWORD(p, 10); /* info level */
+ PUTWORD(p, CLI_BUFFER_SIZE);
+
+ if (cli_api(cli, param, PTR_DIFF(p,param), 8, /* params, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt)) { /* return data, return size */
+ res = GETRES(rparam);
+ p = rdata;
+
+ if (res == 0) {
+ int converter;
+
+ p = rparam + WORDSIZE;
+ GETWORD(p, converter);
+
+ p = rdata + DWORDSIZE + DWORDSIZE; /* skip computer & user names */
+ GETSTRINGP(p, cli->server_domain, rdata, converter);
+ }
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return(res == 0);
+}
+
+
+/*************************************************************************
+*
+* Function Name: cli_get_server_type
+*
+* PURPOSE: Remotes a NetServerGetInfo API call to the current server
+* requesting server_info_1 level information to retrieve
+* the server type.
+*
+* Dependencies: none
+*
+* Parameters:
+* cli - pointer to cli_state structure
+* pstype - pointer to uint32 to contain returned server type
+*
+* Returns:
+* True - success
+* False - failure
+*
+* Origins: samba 2.0.6 source/libsmb/clientgen.c cli_NetServerEnum()
+*
+************************************************************************/
+BOOL cli_get_server_type(struct cli_state *cli, uint32 *pstype)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rdrcnt,rprcnt;
+ char *p;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_WserverGetInfo_REQ) /* req string */
+ +sizeof(RAP_SERVER_INFO_L1) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ int res = -1;
+
+ /* send a SMBtrans command with api NetServerGetInfo */
+ p = make_header(param, RAP_WserverGetInfo,
+ RAP_WserverGetInfo_REQ, RAP_SERVER_INFO_L1);
+ PUTWORD(p, 1); /* info level */
+ PUTWORD(p, CLI_BUFFER_SIZE);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 8, /* params, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt /* return data, return size */
+ )) {
+
+ res = GETRES(rparam);
+
+ if (res == 0 || res == ERRmoredata) {
+ p = rdata;
+ *pstype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
+ }
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return(res == 0 || res == ERRmoredata);
+}
+
+
+/*************************************************************************
+*
+* Function Name: cli_ns_check_server_type
+*
+* PURPOSE: Remotes a NetServerEnum2 API call to the current server
+* requesting server_info_0 level information of machines
+* matching the given server type. If the returned server
+* list contains the machine name contained in cli->desthost
+* then we conclude the server type checks out. This routine
+* is useful to retrieve list of server's of a certain
+* type when all you have is a null session connection and
+* can't remote API calls such as NetWkstaGetInfo or
+* NetServerGetInfo.
+*
+* Dependencies: none
+*
+* Parameters:
+* cli - pointer to cli_state structure
+* workgroup - pointer to string containing domain
+* stype - server type
+*
+* Returns:
+* True - success
+* False - failure
+*
+************************************************************************/
+BOOL cli_ns_check_server_type(struct cli_state *cli, char *workgroup, uint32 stype)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rdrcnt,rprcnt;
+ char *p;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetServerEnum2_REQ) /* req string */
+ +sizeof(RAP_SERVER_INFO_L0) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE /* buffer size */
+ +DWORDSIZE /* server type */
+ +RAP_MACHNAME_LEN]; /* workgroup */
+ BOOL found_server = False;
+ int res = -1;
+
+ /* send a SMBtrans command with api NetServerEnum */
+ p = make_header(param, RAP_NetServerEnum2,
+ RAP_NetServerEnum2_REQ, RAP_SERVER_INFO_L0);
+ PUTWORD(p, 0); /* info level 0 */
+ PUTWORD(p, CLI_BUFFER_SIZE);
+ PUTDWORD(p, stype);
+ PUTSTRING(p, workgroup, RAP_MACHNAME_LEN);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 8, /* params, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt /* return data, return size */
+ )) {
+
+ res = GETRES(rparam);
+ cli->rap_error = res;
+
+ if (res == 0 || res == ERRmoredata) {
+ int i, converter, count;
+
+ p = rparam + WORDSIZE;
+ GETWORD(p, converter);
+ GETWORD(p, count);
+
+ p = rdata;
+ for (i = 0;i < count;i++, p += 16) {
+ char ret_server[RAP_MACHNAME_LEN];
+
+ GETSTRINGF(p, ret_server, RAP_MACHNAME_LEN);
+ if (strequal(ret_server, cli->desthost)) {
+ found_server = True;
+ break;
+ }
+ }
+ }
+ else {
+ DEBUG(4,("cli_ns_check_server_type: machine %s failed the NetServerEnum call. "
+ "Error was : %s.\n", cli->desthost, cli_errstr(cli) ));
+ }
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return found_server;
+ }
+
+
+/****************************************************************************
+ perform a NetWkstaUserLogoff
+****************************************************************************/
+BOOL cli_NetWkstaUserLogoff(struct cli_state *cli,char *user, char *workstation)
+{
+ char *rparam = NULL;
+ char *rdata = NULL;
+ char *p;
+ int rdrcnt,rprcnt;
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetWkstaUserLogoff_REQ) /* req string */
+ +sizeof(RAP_USER_LOGOFF_INFO_L1) /* return string */
+ +RAP_USERNAME_LEN+1 /* user name+pad */
+ +RAP_MACHNAME_LEN /* wksta name */
+ +WORDSIZE /* buffer size */
+ +WORDSIZE]; /* buffer size? */
+ fstring upperbuf;
+
+ memset(param, 0, sizeof(param));
+
+ /* send a SMBtrans command with api NetWkstaUserLogoff */
+ p = make_header(param, RAP_WWkstaUserLogoff,
+ RAP_NetWkstaUserLogoff_REQ, RAP_USER_LOGOFF_INFO_L1);
+ PUTDWORD(p, 0); /* Null pointer */
+ PUTDWORD(p, 0); /* Null pointer */
+ fstrcpy(upperbuf, user);
+ strupper(upperbuf);
+ PUTSTRINGF(p, upperbuf, RAP_USERNAME_LEN);
+ p++; /* strange format, but ok */
+ fstrcpy(upperbuf, workstation);
+ strupper(upperbuf);
+ PUTSTRINGF(p, upperbuf, RAP_MACHNAME_LEN);
+ PUTWORD(p, CLI_BUFFER_SIZE);
+ PUTWORD(p, CLI_BUFFER_SIZE);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),1024, /* param, length, max */
+ NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
+ &rparam, &rprcnt, /* return params, return size */
+ &rdata, &rdrcnt /* return data, return size */
+ )) {
+ cli->rap_error = GETRES(rparam);
+
+ if (cli->rap_error != 0) {
+ DEBUG(4,("NetwkstaUserLogoff gave error %d\n", cli->rap_error));
+ }
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+ return (cli->rap_error == 0);
+}
+
+int cli_NetPrintQEnum(struct cli_state *cli,
+ void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16),
+ void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,uint,uint,const char*))
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetPrintQEnum_REQ) /* req string */
+ +sizeof(RAP_PRINTQ_INFO_L2) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE /* buffer size */
+ +sizeof(RAP_SMB_PRINT_JOB_L1)]; /* more ret data */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rprcnt, rdrcnt;
+ int res = -1;
+
+
+ memset(param, '\0',sizeof(param));
+ p = make_header(param, RAP_WPrintQEnum,
+ RAP_NetPrintQEnum_REQ, RAP_PRINTQ_INFO_L2);
+ PUTWORD(p,2); /* Info level 2 */
+ PUTWORD(p,0xFFE0); /* Return buffer size */
+ PUTSTRING(p, RAP_SMB_PRINT_JOB_L1, 0);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),1024,
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ res = GETRES(rparam);
+ cli->rap_error = res;
+ if (res != 0) {
+ DEBUG(1,("NetPrintQEnum gave error %d\n", res));
+ }
+ }
+
+ if (rdata) {
+ if (res == 0 || res == ERRmoredata) {
+ int i, converter, count;
+
+ p = rparam + WORDSIZE;
+ GETWORD(p, converter);
+ GETWORD(p, count);
+
+ p = rdata;
+ for (i=0;i<count;i++) {
+ pstring qname, sep_file, print_proc, dest, parms, comment;
+ uint16 jobcount, priority, start_time, until_time, status;
+
+ GETSTRINGF(p, qname, RAP_SHARENAME_LEN);
+ p++; /* pad */
+ GETWORD(p, priority);
+ GETWORD(p, start_time);
+ GETWORD(p, until_time);
+ GETSTRINGP(p, sep_file, rdata, converter);
+ GETSTRINGP(p, print_proc, rdata, converter);
+ GETSTRINGP(p, dest, rdata, converter);
+ GETSTRINGP(p, parms, rdata, converter);
+ GETSTRINGP(p, parms, comment, converter);
+ GETWORD(p, status);
+ GETWORD(p, jobcount);
+
+ qfn(qname, priority, start_time, until_time, sep_file, print_proc,
+ dest, parms, comment, status, jobcount);
+
+ if (jobcount) {
+ int j;
+ for (j=0;j<jobcount;j++) {
+ uint16 jid, pos, fsstatus;
+ pstring ownername, notifyname, datatype, jparms, jstatus, jcomment;
+ uint submitted, jsize;
+
+ GETWORD(p, jid);
+ GETSTRINGF(p, ownername, RAP_USERNAME_LEN);
+ p++; /* pad byte */
+ GETSTRINGF(p, notifyname, RAP_MACHNAME_LEN);
+ GETSTRINGF(p, datatype, RAP_DATATYPE_LEN);
+ GETSTRINGP(p, jparms, rdata, converter);
+ GETWORD(p, pos);
+ GETWORD(p, fsstatus);
+ GETSTRINGP(p, jstatus, rdata, converter);
+ GETDWORD(p, submitted);
+ GETDWORD(p, jsize);
+ GETSTRINGP(p, jcomment, rdata, converter);
+
+ jfn(jid, ownername, notifyname, datatype, jparms, pos, fsstatus,
+ jstatus, submitted, jsize, jcomment);
+ }
+ }
+ }
+ } else {
+ DEBUG(4,("NetPrintQEnum res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetPrintQEnum no data returned\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+int cli_NetPrintQGetInfo(struct cli_state *cli, const char *printer,
+ void (*qfn)(const char*,uint16,uint16,uint16,const char*,const char*,const char*,const char*,const char*,uint16,uint16),
+ void (*jfn)(uint16,const char*,const char*,const char*,const char*,uint16,uint16,const char*,uint,uint,const char*))
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetPrintQGetInfo_REQ) /* req string */
+ +sizeof(RAP_PRINTQ_INFO_L2) /* return string */
+ +RAP_SHARENAME_LEN /* printer name */
+ +WORDSIZE /* info level */
+ +WORDSIZE /* buffer size */
+ +sizeof(RAP_SMB_PRINT_JOB_L1)]; /* more ret data */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rprcnt, rdrcnt;
+ int res = -1;
+
+
+ memset(param, '\0',sizeof(param));
+ p = make_header(param, RAP_WPrintQGetInfo,
+ RAP_NetPrintQGetInfo_REQ, RAP_PRINTQ_INFO_L2);
+ PUTSTRING(p, printer, RAP_SHARENAME_LEN-1);
+ PUTWORD(p, 2); /* Info level 2 */
+ PUTWORD(p,0xFFE0); /* Return buffer size */
+ PUTSTRING(p, RAP_SMB_PRINT_JOB_L1, 0);
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),1024,
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ res = GETRES(rparam);
+ cli->rap_error = res;
+ if (res != 0) {
+ DEBUG(1,("NetPrintQGetInfo gave error %d\n", res));
+ }
+ }
+
+ if (rdata) {
+ if (res == 0 || res == ERRmoredata) {
+ int rsize, converter;
+ pstring qname, sep_file, print_proc, dest, parms, comment;
+ uint16 jobcount, priority, start_time, until_time, status;
+
+ p = rparam + WORDSIZE;
+ GETWORD(p, converter);
+ GETWORD(p, rsize);
+
+ p = rdata;
+ GETSTRINGF(p, qname, RAP_SHARENAME_LEN);
+ p++; /* pad */
+ GETWORD(p, priority);
+ GETWORD(p, start_time);
+ GETWORD(p, until_time);
+ GETSTRINGP(p, sep_file, rdata, converter);
+ GETSTRINGP(p, print_proc, rdata, converter);
+ GETSTRINGP(p, dest, rdata, converter);
+ GETSTRINGP(p, parms, rdata, converter);
+ GETSTRINGP(p, comment, rdata, converter);
+ GETWORD(p, status);
+ GETWORD(p, jobcount);
+ qfn(qname, priority, start_time, until_time, sep_file, print_proc,
+ dest, parms, comment, status, jobcount);
+ if (jobcount) {
+ int j;
+ for (j=0;(j<jobcount)&&(PTR_DIFF(p,rdata)< rsize);j++) {
+ uint16 jid, pos, fsstatus;
+ pstring ownername, notifyname, datatype, jparms, jstatus, jcomment;
+ uint submitted, jsize;
+
+ GETWORD(p, jid);
+ GETSTRINGF(p, ownername, RAP_USERNAME_LEN);
+ p++; /* pad byte */
+ GETSTRINGF(p, notifyname, RAP_MACHNAME_LEN);
+ GETSTRINGF(p, datatype, RAP_DATATYPE_LEN);
+ GETSTRINGP(p, jparms, rdata, converter);
+ GETWORD(p, pos);
+ GETWORD(p, fsstatus);
+ GETSTRINGP(p, jstatus, rdata, converter);
+ GETDWORD(p, submitted);
+ GETDWORD(p, jsize);
+ GETSTRINGP(p, jcomment, rdata, converter);
+
+ jfn(jid, ownername, notifyname, datatype, jparms, pos, fsstatus,
+ jstatus, submitted, jsize, jcomment);
+ }
+ }
+ } else {
+ DEBUG(4,("NetPrintQGetInfo res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetPrintQGetInfo no data returned\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+call a NetServiceEnum - list running services on a different host
+****************************************************************************/
+int cli_RNetServiceEnum(struct cli_state *cli, void (*fn)(const char *, const char *, void *), void *state)
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetServiceEnum_REQ) /* parm string */
+ +sizeof(RAP_SERVICE_INFO_L2) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rprcnt, rdrcnt;
+ int res = -1;
+
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WServiceEnum,
+ RAP_NetServiceEnum_REQ, RAP_SERVICE_INFO_L2);
+ PUTWORD(p,2); /* Info level 2 */
+ PUTWORD(p,0xFFE0); /* Return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),8,
+ NULL, 0, 0xFFE0 /* data area size */,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ res = GETRES(rparam);
+ cli->rap_error = res;
+ if(cli->rap_error == 234)
+ DEBUG(1,("Not all service names were returned (such as those longer than 15 characters)\n"));
+ else if (cli->rap_error != 0) {
+ DEBUG(1,("NetServiceEnum gave error %d\n", cli->rap_error));
+ }
+ }
+
+ if (rdata) {
+ if (res == 0 || res == ERRmoredata) {
+ int i, converter, count;
+
+ p = rparam + WORDSIZE; /* skip result */
+ GETWORD(p, converter);
+ GETWORD(p, count);
+
+ for (i=0,p=rdata;i<count;i++) {
+ pstring comment;
+ char servicename[RAP_SRVCNAME_LEN];
+
+ GETSTRINGF(p, servicename, RAP_SRVCNAME_LEN);
+ p+=8; /* pass status words */
+ GETSTRINGF(p, comment, RAP_SRVCCMNT_LEN);
+
+ fn(servicename, comment, cli); /* BB add status too */
+ }
+ } else {
+ DEBUG(4,("NetServiceEnum res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetServiceEnum no data returned\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+
+/****************************************************************************
+call a NetSessionEnum - list workstations with sessions to an SMB server
+****************************************************************************/
+int cli_NetSessionEnum(struct cli_state *cli, void (*fn)(char *, char *, uint16, uint16, uint16, uint, uint, uint, char *))
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetSessionEnum_REQ) /* parm string */
+ +sizeof(RAP_SESSION_INFO_L2) /* return string */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rprcnt, rdrcnt;
+ int res = -1;
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WsessionEnum,
+ RAP_NetSessionEnum_REQ, RAP_SESSION_INFO_L2);
+ PUTWORD(p,2); /* Info level 2 */
+ PUTWORD(p,0xFF); /* Return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),8,
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ res = GETRES(rparam);
+ cli->rap_error = res;
+ if (res != 0) {
+ DEBUG(1,("NetSessionEnum gave error %d\n", res));
+ }
+ }
+
+ if (rdata) {
+ if (res == 0 || res == ERRmoredata) {
+ int i, converter, count;
+
+ p = rparam + WORDSIZE;
+ GETWORD(p, converter);
+ GETWORD(p, count);
+
+ for (i=0,p=rdata;i<count;i++) {
+ pstring wsname, username, clitype_name;
+ uint16 num_conns, num_opens, num_users;
+ uint sess_time, idle_time, user_flags;
+
+ GETSTRINGP(p, wsname, rdata, converter);
+ GETSTRINGP(p, username, rdata, converter);
+ GETWORD(p, num_conns);
+ GETWORD(p, num_opens);
+ GETWORD(p, num_users);
+ GETDWORD(p, sess_time);
+ GETDWORD(p, idle_time);
+ GETDWORD(p, user_flags);
+ GETSTRINGP(p, clitype_name, rdata, converter);
+
+ fn(wsname, username, num_conns, num_opens, num_users, sess_time,
+ idle_time, user_flags, clitype_name);
+ }
+
+ } else {
+ DEBUG(4,("NetSessionEnum res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetSesssionEnum no data returned\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+ Call a NetSessionGetInfo - get information about other session to an SMB server.
+****************************************************************************/
+
+int cli_NetSessionGetInfo(struct cli_state *cli, const char *workstation, void (*fn)(const char *, const char *, uint16, uint16, uint16, uint, uint, uint, const char *))
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetSessionGetInfo_REQ) /* req string */
+ +sizeof(RAP_SESSION_INFO_L2) /* return string */
+ +RAP_MACHNAME_LEN /* wksta name */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rprcnt, rdrcnt;
+ int res = -1;
+
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WsessionGetInfo,
+ RAP_NetSessionGetInfo_REQ, RAP_SESSION_INFO_L2);
+ PUTSTRING(p, workstation, RAP_MACHNAME_LEN-1);
+ PUTWORD(p,2); /* Info level 2 */
+ PUTWORD(p,0xFF); /* Return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),PTR_DIFF(p,param),
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ cli->rap_error = SVAL(rparam,0);
+ if (cli->rap_error != 0) {
+ DEBUG(1,("NetSessionGetInfo gave error %d\n", cli->rap_error));
+ }
+ }
+
+ if (rdata) {
+ res = GETRES(rparam);
+
+ if (res == 0 || res == ERRmoredata) {
+ int rsize, converter;
+ pstring wsname, username, clitype_name;
+ uint16 num_conns, num_opens, num_users;
+ uint sess_time, idle_time, user_flags;
+
+ p = rparam + WORDSIZE;
+ GETWORD(p, converter);
+ GETWORD(p, rsize);
+
+ p = rdata;
+ GETSTRINGP(p, wsname, rdata, converter);
+ GETSTRINGP(p, username, rdata, converter);
+ GETWORD(p, num_conns);
+ GETWORD(p, num_opens);
+ GETWORD(p, num_users);
+ GETDWORD(p, sess_time);
+ GETDWORD(p, idle_time);
+ GETDWORD(p, user_flags);
+ GETSTRINGP(p, clitype_name, rdata, converter);
+
+ fn(wsname, username, num_conns, num_opens, num_users, sess_time,
+ idle_time, user_flags, clitype_name);
+ } else {
+ DEBUG(4,("NetSessionGetInfo res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetSessionGetInfo no data returned\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+/****************************************************************************
+call a NetSessionDel - close a session to an SMB server
+****************************************************************************/
+int cli_NetSessionDel(struct cli_state *cli, const char *workstation)
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetSessionDel_REQ) /* req string */
+ +1 /* no return string */
+ +RAP_MACHNAME_LEN /* workstation name */
+ +WORDSIZE]; /* reserved (0) */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rprcnt, rdrcnt;
+ int res;
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WsessionDel, RAP_NetSessionDel_REQ, NULL);
+ PUTSTRING(p, workstation, RAP_MACHNAME_LEN-1);
+ PUTWORD(p,0); /* reserved word of 0 */
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
+ NULL, 0, 200, /* data, length, maxlen */
+ &rparam, &rprcnt, /* return params, length */
+ &rdata, &rdrcnt)) /* return data, length */
+ {
+ res = GETRES(rparam);
+ cli->rap_error = res;
+
+ if (res == 0) {
+ /* nothing to do */
+ }
+ else {
+ DEBUG(4,("NetFileClose2 res=%d\n", res));
+ }
+ } else {
+ res = -1;
+ DEBUG(4,("NetFileClose2 failed\n"));
+ }
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ return res;
+}
+
+
+int cli_NetConnectionEnum(struct cli_state *cli, const char *qualifier, void (*fn)(uint16 conid, uint16 contype, uint16 numopens, uint16 numusers, uint32 contime, const char *username, const char *netname))
+{
+ char param[WORDSIZE /* api number */
+ +sizeof(RAP_NetConnectionEnum_REQ) /* req string */
+ +sizeof(RAP_CONNECTION_INFO_L1) /* return string */
+ +RAP_MACHNAME_LEN /* wksta name */
+ +WORDSIZE /* info level */
+ +WORDSIZE]; /* buffer size */
+ char *p;
+ char *rparam = NULL;
+ char *rdata = NULL;
+ int rprcnt, rdrcnt;
+ int res = -1;
+
+ memset(param, '\0', sizeof(param));
+ p = make_header(param, RAP_WconnectionEnum,
+ RAP_NetConnectionEnum_REQ, RAP_CONNECTION_INFO_L1);
+ PUTSTRING(p, qualifier, RAP_MACHNAME_LEN-1);/* Workstation name */
+ PUTWORD(p,1); /* Info level 1 */
+ PUTWORD(p,0xFFE0); /* Return buffer size */
+
+ if (cli_api(cli,
+ param, PTR_DIFF(p,param),PTR_DIFF(p,param),
+ NULL, 0, CLI_BUFFER_SIZE,
+ &rparam, &rprcnt,
+ &rdata, &rdrcnt)) {
+ res = GETRES(rparam);
+ cli->rap_error = res;
+ if (res != 0) {
+ DEBUG(1,("NetConnectionEnum gave error %d\n", res));
+ }
+ }
+ if (rdata) {
+ if (res == 0 || res == ERRmoredata) {
+ int i, converter, count;
+
+ p = rparam + WORDSIZE;
+ GETWORD(p, converter);
+ GETWORD(p, count);
+
+ for (i=0,p=rdata;i<count;i++) {
+ pstring netname, username;
+ uint16 conn_id, conn_type, num_opens, num_users;
+ uint conn_time;
+
+ GETWORD(p,conn_id);
+ GETWORD(p,conn_type);
+ GETWORD(p,num_opens);
+ GETWORD(p,num_users);
+ GETDWORD(p,conn_time);
+ GETSTRINGP(p, username, rdata, converter);
+ GETSTRINGP(p, netname, rdata, converter);
+
+ fn(conn_id, conn_type, num_opens, num_users, conn_time,
+ username, netname);
+ }
+
+ } else {
+ DEBUG(4,("NetConnectionEnum res=%d\n", res));
+ }
+ } else {
+ DEBUG(4,("NetConnectionEnum no data returned\n"));
+ }
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return res;
+}
diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c
new file mode 100644
index 0000000000..0a9569fc69
--- /dev/null
+++ b/source3/libsmb/clireadwrite.c
@@ -0,0 +1,374 @@
+/*
+ Unix SMB/CIFS implementation.
+ client file read/write 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.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+/****************************************************************************
+Issue a single SMBread and don't wait for a reply.
+****************************************************************************/
+
+static BOOL cli_issue_read(struct cli_state *cli, int fnum, off_t offset,
+ size_t size, int i)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,10,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBreadX);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+ SIVAL(cli->outbuf,smb_vwv3,offset);
+ SSVAL(cli->outbuf,smb_vwv5,size);
+ SSVAL(cli->outbuf,smb_vwv6,size);
+ SSVAL(cli->outbuf,smb_mid,cli->mid + i);
+
+ return cli_send_smb(cli);
+}
+
+/****************************************************************************
+Issue a single SMBreadraw and don't wait for a reply.
+****************************************************************************/
+
+static BOOL cli_issue_readraw(struct cli_state *cli, int fnum, off_t offset,
+ size_t size, int i)
+{
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,10,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBreadbraw);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,fnum);
+ SIVAL(cli->outbuf,smb_vwv1,offset);
+ SSVAL(cli->outbuf,smb_vwv2,size);
+ SSVAL(cli->outbuf,smb_vwv3,size);
+ SSVAL(cli->outbuf,smb_mid,cli->mid + i);
+
+ return cli_send_smb(cli);
+}
+
+/****************************************************************************
+ 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)
+{
+ char *p;
+ int size2;
+ int readsize;
+ ssize_t total = 0;
+
+ if (size == 0)
+ return 0;
+
+ /*
+ * Set readsize to the maximum size we can handle in one readX,
+ * rounded down to a multiple of 1024.
+ */
+
+ readsize = (cli->max_xmit - (smb_size+32)) & ~1023;
+
+ while (total < size) {
+ readsize = MIN(readsize, size-total);
+
+ /* Issue a read and receive a reply */
+
+ if (!cli_issue_read(cli, fnum, offset, readsize, 0))
+ return -1;
+
+ if (!cli_receive_smb(cli))
+ return -1;
+
+ /* Check for error. Make sure to check for DOS and NT
+ errors. */
+
+ if (cli_is_error(cli)) {
+ NTSTATUS status = NT_STATUS_OK;
+ uint8 eclass = 0;
+ uint32 ecode = 0;
+
+ if (cli_is_nt_error(cli))
+ status = cli_nt_error(cli);
+ else
+ cli_dos_error(cli, &eclass, &ecode);
+
+ if ((eclass == ERRDOS && ecode == ERRmoredata) ||
+ NT_STATUS_V(status) == NT_STATUS_V(STATUS_MORE_ENTRIES))
+ return -1;
+ }
+
+ size2 = SVAL(cli->inbuf, smb_vwv5);
+
+ if (size2 > readsize) {
+ DEBUG(5,("server returned more than we wanted!\n"));
+ return -1;
+ } else if (size2 < 0) {
+ DEBUG(5,("read return < 0!\n"));
+ return -1;
+ }
+
+ /* Copy data into buffer */
+
+ p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6);
+ memcpy(buf + total, p, size2);
+
+ total += size2;
+ offset += size2;
+
+ /*
+ * If the server returned less than we asked for we're at EOF.
+ */
+
+ if (size2 < readsize)
+ break;
+ }
+
+ return total;
+}
+
+/****************************************************************************
+ Tester for the readraw call.
+****************************************************************************/
+
+ssize_t cli_readraw(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size)
+{
+ char *p;
+ int size2;
+ size_t readsize;
+ ssize_t total = 0;
+
+ if (size == 0)
+ return 0;
+
+ /*
+ * Set readsize to the maximum size we can handle in one readraw.
+ */
+
+ readsize = 0xFFFF;
+
+ while (total < size) {
+ readsize = MIN(readsize, size-total);
+
+ /* Issue a read and receive a reply */
+
+ if (!cli_issue_readraw(cli, fnum, offset, readsize, 0))
+ return -1;
+
+ if (!client_receive_smb(cli->fd, cli->inbuf, cli->timeout))
+ return -1;
+
+ size2 = smb_len(cli->inbuf);
+
+ if (size2 > readsize) {
+ DEBUG(5,("server returned more than we wanted!\n"));
+ return -1;
+ } else if (size2 < 0) {
+ DEBUG(5,("read return < 0!\n"));
+ return -1;
+ }
+
+ /* Copy data into buffer */
+
+ if (size2) {
+ p = cli->inbuf + 4;
+ memcpy(buf + total, p, size2);
+ }
+
+ total += size2;
+ offset += size2;
+
+ /*
+ * If the server returned less than we asked for we're at EOF.
+ */
+
+ if (size2 < readsize)
+ break;
+ }
+
+ return total;
+}
+
+/****************************************************************************
+issue a single SMBwrite and don't wait for a reply
+****************************************************************************/
+
+static BOOL cli_issue_write(struct cli_state *cli, int fnum, off_t offset, uint16 mode, char *buf,
+ size_t size, int i)
+{
+ char *p;
+
+ if (size > cli->bufsize) {
+ cli->outbuf = realloc(cli->outbuf, size + 1024);
+ cli->inbuf = realloc(cli->inbuf, size + 1024);
+ if (cli->outbuf == NULL || cli->inbuf == NULL)
+ return False;
+ cli->bufsize = size + 1024;
+ }
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ if (size > 0xFFFF)
+ set_message(cli->outbuf,14,0,True);
+ else
+ set_message(cli->outbuf,12,0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBwriteX);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SCVAL(cli->outbuf,smb_vwv0,0xFF);
+ SSVAL(cli->outbuf,smb_vwv2,fnum);
+
+ SIVAL(cli->outbuf,smb_vwv3,offset);
+ SIVAL(cli->outbuf,smb_vwv5,(mode & 0x0008) ? 0xFFFFFFFF : 0);
+ SSVAL(cli->outbuf,smb_vwv7,mode);
+
+ SSVAL(cli->outbuf,smb_vwv8,(mode & 0x0008) ? size : 0);
+ SSVAL(cli->outbuf,smb_vwv9,((size>>16)&1));
+ SSVAL(cli->outbuf,smb_vwv10,size);
+ SSVAL(cli->outbuf,smb_vwv11,
+ smb_buf(cli->outbuf) - smb_base(cli->outbuf));
+
+ p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11);
+ memcpy(p, buf, size);
+ cli_setup_bcc(cli, p+size);
+
+ SSVAL(cli->outbuf,smb_mid,cli->mid + i);
+
+ show_msg(cli->outbuf);
+ return cli_send_smb(cli);
+}
+
+/****************************************************************************
+ 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,
+ char *buf, off_t offset, size_t size)
+{
+ int bwritten = 0;
+ int issued = 0;
+ int received = 0;
+ int mpx = MAX(cli->max_mux-1, 1);
+ int block = (cli->max_xmit - (smb_size+32)) & ~1023;
+ int blocks = (size + (block-1)) / block;
+
+ while (received < blocks) {
+
+ while ((issued - received < mpx) && (issued < blocks)) {
+ int bsent = issued * block;
+ int size1 = MIN(block, size - bsent);
+
+ if (!cli_issue_write(cli, fnum, offset + bsent,
+ write_mode,
+ buf + bsent,
+ size1, issued))
+ return -1;
+ issued++;
+ }
+
+ if (!cli_receive_smb(cli))
+ return bwritten;
+
+ received++;
+
+ if (cli_is_error(cli))
+ break;
+
+ bwritten += SVAL(cli->inbuf, smb_vwv2);
+ bwritten += (((int)(SVAL(cli->inbuf, smb_vwv4)))>>16);
+ }
+
+ while (received < issued && cli_receive_smb(cli))
+ received++;
+
+ return bwritten;
+}
+
+/****************************************************************************
+ 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)
+{
+ char *p;
+ ssize_t total = 0;
+
+ do {
+ size_t size = MIN(size1, cli->max_xmit - 48);
+
+ memset(cli->outbuf,'\0',smb_size);
+ memset(cli->inbuf,'\0',smb_size);
+
+ set_message(cli->outbuf,5, 0,True);
+
+ SCVAL(cli->outbuf,smb_com,SMBwrite);
+ SSVAL(cli->outbuf,smb_tid,cli->cnum);
+ cli_setup_packet(cli);
+
+ SSVAL(cli->outbuf,smb_vwv0,fnum);
+ SSVAL(cli->outbuf,smb_vwv1,size);
+ SIVAL(cli->outbuf,smb_vwv2,offset);
+ SSVAL(cli->outbuf,smb_vwv4,0);
+
+ p = smb_buf(cli->outbuf);
+ *p++ = 1;
+ SSVAL(p, 0, size); p += 2;
+ memcpy(p, buf, size); p += size;
+
+ cli_setup_bcc(cli, p);
+
+ if (!cli_send_smb(cli))
+ return -1;
+
+ if (!cli_receive_smb(cli))
+ return -1;
+
+ if (cli_is_error(cli))
+ return -1;
+
+ size = SVAL(cli->inbuf,smb_vwv0);
+ if (size == 0)
+ break;
+
+ size1 -= size;
+ total += size;
+ offset += size;
+
+ } while (size1);
+
+ return total;
+}
diff --git a/source3/libsmb/clisecdesc.c b/source3/libsmb/clisecdesc.c
new file mode 100644
index 0000000000..5de67b1e05
--- /dev/null
+++ b/source3/libsmb/clisecdesc.c
@@ -0,0 +1,131 @@
+/*
+ Unix SMB/CIFS implementation.
+ client security descriptor functions
+ 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"
+
+/****************************************************************************
+ query the security descriptor for a open file
+ ****************************************************************************/
+SEC_DESC *cli_query_secdesc(struct cli_state *cli, int fnum,
+ TALLOC_CTX *mem_ctx)
+{
+ char param[8];
+ char *rparam=NULL, *rdata=NULL;
+ int rparam_count=0, rdata_count=0;
+ prs_struct pd;
+ SEC_DESC *psd = NULL;
+
+ SIVAL(param, 0, fnum);
+ SSVAL(param, 4, 0x7);
+
+ if (!cli_send_nt_trans(cli,
+ NT_TRANSACT_QUERY_SECURITY_DESC,
+ 0,
+ NULL, 0, 0,
+ param, 8, 4,
+ NULL, 0, 0x10000)) {
+ DEBUG(1,("Failed to send NT_TRANSACT_QUERY_SECURITY_DESC\n"));
+ goto cleanup;
+ }
+
+
+ if (!cli_receive_nt_trans(cli,
+ &rparam, &rparam_count,
+ &rdata, &rdata_count)) {
+ DEBUG(1,("Failed to recv NT_TRANSACT_QUERY_SECURITY_DESC\n"));
+ goto cleanup;
+ }
+
+ prs_init(&pd, rdata_count, mem_ctx, UNMARSHALL);
+ prs_append_data(&pd, rdata, rdata_count);
+ pd.data_offset = 0;
+
+ if (!sec_io_desc("sd data", &psd, &pd, 1)) {
+ DEBUG(1,("Failed to parse secdesc\n"));
+ goto cleanup;
+ }
+
+ cleanup:
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ 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)
+{
+ char param[8];
+ char *rparam=NULL, *rdata=NULL;
+ int rparam_count=0, rdata_count=0;
+ TALLOC_CTX *mem_ctx;
+ prs_struct pd;
+ BOOL ret = False;
+
+ if ((mem_ctx = talloc_init()) == NULL) {
+ DEBUG(0,("talloc_init failed.\n"));
+ goto cleanup;
+ }
+
+ 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;
+ }
+
+ SIVAL(param, 0, fnum);
+ SSVAL(param, 4, 0x7);
+
+ if (!cli_send_nt_trans(cli,
+ NT_TRANSACT_SET_SECURITY_DESC,
+ 0,
+ NULL, 0, 0,
+ param, 8, 0,
+ pd.data_p, pd.data_offset, 0)) {
+ DEBUG(1,("Failed to send NT_TRANSACT_SET_SECURITY_DESC\n"));
+ goto cleanup;
+ }
+
+
+ if (!cli_receive_nt_trans(cli,
+ &rparam, &rparam_count,
+ &rdata, &rdata_count)) {
+ DEBUG(1,("NT_TRANSACT_SET_SECURITY_DESC failed\n"));
+ goto cleanup;
+ }
+
+ ret = True;
+
+ cleanup:
+
+ SAFE_FREE(rparam);
+ SAFE_FREE(rdata);
+
+ talloc_destroy(mem_ctx);
+
+ prs_mem_free(&pd);
+ return ret;
+}
diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c
new file mode 100644
index 0000000000..a4fcfa5d9a
--- /dev/null
+++ b/source3/libsmb/clispnego.c
@@ -0,0 +1,622 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple kerberos5/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"
+
+/*
+ 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;
+}
+
+
+/*
+ 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,
+ uint8 guid[16],
+ char *OIDs[ASN1_MAX_OIDS],
+ char **principal)
+{
+ int i;
+ BOOL ret;
+ ASN1_DATA data;
+
+ asn1_load(&data, blob);
+
+ asn1_read(&data, guid, 16);
+ 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)
+{
+ 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_BOOLEAN(&data, 0);
+ 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)
+{
+ 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);
+ asn1_check_BOOLEAN(&data, 0);
+
+ data_remaining = asn1_tag_remaining(&data);
+
+ if (data_remaining < 1) {
+ data.has_error = True;
+ } else {
+
+ *ticket = data_blob(data.data, 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(struct cli_state *cli, char *principal)
+{
+ 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);
+
+ /* wrap that up in a nice GSS-API wrapping */
+ tkt_wrapped = spnego_gen_krb5_wrap(tkt);
+
+ /* 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(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 NTLMSSP challenge packet given two security blobs
+ The second challenge is optional
+*/
+BOOL spnego_gen_challenge(DATA_BLOB *blob,
+ DATA_BLOB *chal1, DATA_BLOB *chal2)
+{
+ ASN1_DATA data;
+
+ 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,1);
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data,ASN1_CONTEXT(1));
+ asn1_write_OID(&data, OID_NTLMSSP);
+ asn1_pop_tag(&data);
+
+ asn1_push_tag(&data,ASN1_CONTEXT(2));
+ asn1_write_OctetString(&data, chal1->data, chal1->length);
+ asn1_pop_tag(&data);
+
+ /* the second challenge is optional (XP doesn't send it) */
+ if (chal2) {
+ asn1_push_tag(&data,ASN1_CONTEXT(3));
+ asn1_write_OctetString(&data, chal2->data, chal2->length);
+ asn1_pop_tag(&data);
+ }
+
+ asn1_pop_tag(&data);
+ asn1_pop_tag(&data);
+
+ if (data.has_error) {
+ return False;
+ }
+
+ *blob = data_blob(data.data, data.length);
+ asn1_free(&data);
+ return True;
+}
+
+/*
+ generate a SPNEGO NTLMSSP 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 NTLMSSP 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;
+}
+
+
+/*
+ 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)
+ B = data blob (pointer + length)
+ b = data blob in header (pointer + length)
+ 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;
+
+ /* 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 '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 '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;
+}
+
+
+/*
+ this is a tiny msrpc packet parser. This the the partner of msrpc_gen
+
+ format specifiers are:
+
+ U = unicode string (input is unix string)
+ B = data blob
+ b = data blob in header
+ d = word (4 bytes)
+ C = constant ascii string
+ */
+BOOL msrpc_parse(DATA_BLOB *blob,
+ const char *format, ...)
+{
+ int i;
+ va_list ap;
+ char **ps, *s;
+ DATA_BLOB *b;
+ int 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':
+ 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 || (len1&1) || ptr + len1 > blob->length) {
+ return False;
+ }
+ ps = va_arg(ap, char **);
+ pull_string(NULL, p, blob->data + ptr, -1, len1,
+ STR_UNICODE|STR_NOALIGN);
+ (*ps) = strdup(p);
+ break;
+ case 'B':
+ 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);
+ *b = data_blob(blob->data + head_ofs, len1);
+ head_ofs += len1;
+ break;
+ case 'd':
+ v = va_arg(ap, uint32 *);
+ *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, -1,
+ blob->length - head_ofs,
+ STR_ASCII|STR_TERMINATE);
+ if (strcmp(s, p) != 0) {
+ return False;
+ }
+ break;
+ }
+ }
+ va_end(ap);
+
+ return True;
+}
diff --git a/source3/libsmb/clistr.c b/source3/libsmb/clistr.c
new file mode 100644
index 0000000000..3c9964368e
--- /dev/null
+++ b/source3/libsmb/clistr.c
@@ -0,0 +1,43 @@
+/*
+ Unix SMB/CIFS implementation.
+ client string 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"
+
+int clistr_push(struct cli_state *cli, void *dest, const char *src, int dest_len, int flags)
+{
+ return push_string(cli->outbuf, dest, src, dest_len, flags);
+}
+
+int clistr_pull(struct cli_state *cli, char *dest, const void *src, int dest_len, int src_len,
+ int flags)
+{
+ return pull_string(cli->inbuf, dest, src, dest_len, src_len, flags);
+}
+
+
+int clistr_align_out(struct cli_state *cli, const void *p, int flags)
+{
+ return align_string(cli->outbuf, p, flags);
+}
+
+int clistr_align_in(struct cli_state *cli, const void *p, int flags)
+{
+ return align_string(cli->inbuf, p, flags);
+}
diff --git a/source3/libsmb/clitrans.c b/source3/libsmb/clitrans.c
new file mode 100644
index 0000000000..3d862a1796
--- /dev/null
+++ b/source3/libsmb/clitrans.c
@@ -0,0 +1,468 @@
+/*
+ Unix SMB/CIFS implementation.
+ client transaction calls
+ Copyright (C) Andrew Tridgell 1994-1998
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 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.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+
+/****************************************************************************
+ send a SMB trans or trans2 request
+ ****************************************************************************/
+BOOL cli_send_trans(struct cli_state *cli, int trans,
+ const char *pipe_name,
+ int fid, int flags,
+ uint16 *setup, int lsetup, int msetup,
+ char *param, int lparam, int mparam,
+ char *data, int ldata, int mdata)
+{
+ int i;
+ int this_ldata,this_lparam;
+ int tot_data=0,tot_param=0;
+ char *outdata,*outparam;
+ char *p;
+ int pipe_name_len=0;
+
+ this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
+ this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
+
+ memset(cli->outbuf,'\0',smb_size);
+ set_message(cli->outbuf,14+lsetup,0,True);
+ SCVAL(cli->outbuf,smb_com,trans);
+ SSVAL(cli->outbuf,smb_tid, cli->cnum);
+ cli_setup_packet(cli);
+
+ if (pipe_name) {
+ pipe_name_len = clistr_push(cli, smb_buf(cli->outbuf), pipe_name, -1, STR_TERMINATE);
+ }
+
+ outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? pipe_name_len : 3);
+ outdata = outparam+this_lparam;
+
+ /* primary request */
+ SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
+ SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
+ SSVAL(cli->outbuf,smb_mprcnt,mparam); /* mprcnt */
+ SSVAL(cli->outbuf,smb_mdrcnt,mdata); /* mdrcnt */
+ SCVAL(cli->outbuf,smb_msrcnt,msetup); /* msrcnt */
+ SSVAL(cli->outbuf,smb_flags,flags); /* flags */
+ SIVAL(cli->outbuf,smb_timeout,0); /* timeout */
+ SSVAL(cli->outbuf,smb_pscnt,this_lparam); /* pscnt */
+ SSVAL(cli->outbuf,smb_psoff,smb_offset(outparam,cli->outbuf)); /* psoff */
+ SSVAL(cli->outbuf,smb_dscnt,this_ldata); /* dscnt */
+ SSVAL(cli->outbuf,smb_dsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
+ SCVAL(cli->outbuf,smb_suwcnt,lsetup); /* suwcnt */
+ for (i=0;i<lsetup;i++) /* setup[] */
+ SSVAL(cli->outbuf,smb_setup+i*2,setup[i]);
+ p = smb_buf(cli->outbuf);
+ if (trans != SMBtrans) {
+ *p++ = 0; /* put in a null smb_name */
+ *p++ = 'D'; *p++ = ' '; /* observed in OS/2 */
+ }
+ if (this_lparam) /* param[] */
+ memcpy(outparam,param,this_lparam);
+ if (this_ldata) /* data[] */
+ memcpy(outdata,data,this_ldata);
+ cli_setup_bcc(cli, outdata+this_ldata);
+
+ show_msg(cli->outbuf);
+ cli_send_smb(cli);
+
+ if (this_ldata < ldata || this_lparam < lparam) {
+ /* receive interim response */
+ if (!cli_receive_smb(cli) ||
+ cli_is_error(cli)) {
+ return(False);
+ }
+
+ tot_data = this_ldata;
+ tot_param = this_lparam;
+
+ while (tot_data < ldata || tot_param < lparam) {
+ this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
+ this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
+
+ set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
+ SCVAL(cli->outbuf,smb_com,(trans==SMBtrans ? SMBtranss : SMBtranss2));
+
+ outparam = smb_buf(cli->outbuf);
+ outdata = outparam+this_lparam;
+
+ /* secondary request */
+ SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
+ SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
+ SSVAL(cli->outbuf,smb_spscnt,this_lparam); /* pscnt */
+ SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
+ SSVAL(cli->outbuf,smb_spsdisp,tot_param); /* psdisp */
+ SSVAL(cli->outbuf,smb_sdscnt,this_ldata); /* dscnt */
+ SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
+ SSVAL(cli->outbuf,smb_sdsdisp,tot_data); /* dsdisp */
+ if (trans==SMBtrans2)
+ SSVALS(cli->outbuf,smb_sfid,fid); /* fid */
+ if (this_lparam) /* param[] */
+ memcpy(outparam,param+tot_param,this_lparam);
+ if (this_ldata) /* data[] */
+ memcpy(outdata,data+tot_data,this_ldata);
+ cli_setup_bcc(cli, outdata+this_ldata);
+
+ show_msg(cli->outbuf);
+ cli_send_smb(cli);
+
+ tot_data += this_ldata;
+ tot_param += this_lparam;
+ }
+ }
+
+ return(True);
+}
+
+
+/****************************************************************************
+ receive a SMB trans or trans2 response allocating the necessary memory
+ ****************************************************************************/
+BOOL cli_receive_trans(struct cli_state *cli,int trans,
+ char **param, int *param_len,
+ char **data, int *data_len)
+{
+ int total_data=0;
+ int total_param=0;
+ int this_data,this_param;
+ NTSTATUS status;
+ char *tdata;
+ char *tparam;
+
+ *data_len = *param_len = 0;
+
+ if (!cli_receive_smb(cli))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ /* sanity check */
+ if (CVAL(cli->inbuf,smb_com) != trans) {
+ DEBUG(0,("Expected %s response, got command 0x%02x\n",
+ trans==SMBtrans?"SMBtrans":"SMBtrans2",
+ CVAL(cli->inbuf,smb_com)));
+ return(False);
+ }
+
+ /*
+ * 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.
+ */
+ status = cli_nt_error(cli);
+
+ if (NT_STATUS_IS_ERR(status)) {
+ return False;
+ }
+
+ /* parse out the lengths */
+ total_data = SVAL(cli->inbuf,smb_tdrcnt);
+ total_param = SVAL(cli->inbuf,smb_tprcnt);
+
+ /* allocate it */
+ if (total_data!=0) {
+ tdata = Realloc(*data,total_data);
+ if (!tdata) {
+ DEBUG(0,("cli_receive_trans: failed to enlarge data buffer\n"));
+ return False;
+ }
+ else
+ *data = tdata;
+ }
+
+ if (total_param!=0) {
+ tparam = Realloc(*param,total_param);
+ if (!tparam) {
+ DEBUG(0,("cli_receive_trans: failed to enlarge param buffer\n"));
+ return False;
+ }
+ else
+ *param = tparam;
+ }
+
+ while (1) {
+ this_data = SVAL(cli->inbuf,smb_drcnt);
+ this_param = SVAL(cli->inbuf,smb_prcnt);
+
+ if (this_data + *data_len > total_data ||
+ this_param + *param_len > total_param) {
+ DEBUG(1,("Data overflow in cli_receive_trans\n"));
+ return False;
+ }
+
+ if (this_data)
+ memcpy(*data + SVAL(cli->inbuf,smb_drdisp),
+ smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_droff),
+ this_data);
+ if (this_param)
+ memcpy(*param + SVAL(cli->inbuf,smb_prdisp),
+ smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_proff),
+ this_param);
+ *data_len += this_data;
+ *param_len += this_param;
+
+ /* parse out the total lengths again - they can shrink! */
+ total_data = SVAL(cli->inbuf,smb_tdrcnt);
+ total_param = SVAL(cli->inbuf,smb_tprcnt);
+
+ if (total_data <= *data_len && total_param <= *param_len)
+ break;
+
+ if (!cli_receive_smb(cli))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ /* sanity check */
+ if (CVAL(cli->inbuf,smb_com) != trans) {
+ DEBUG(0,("Expected %s response, got command 0x%02x\n",
+ trans==SMBtrans?"SMBtrans":"SMBtrans2",
+ CVAL(cli->inbuf,smb_com)));
+ return(False);
+ }
+ if (NT_STATUS_IS_ERR(cli_nt_error(cli))) {
+ return(False);
+ }
+ }
+
+ return(True);
+}
+
+
+
+
+/****************************************************************************
+ send a SMB nttrans request
+ ****************************************************************************/
+BOOL cli_send_nt_trans(struct cli_state *cli,
+ int function,
+ int flags,
+ uint16 *setup, int lsetup, int msetup,
+ char *param, int lparam, int mparam,
+ char *data, int ldata, int mdata)
+{
+ int i;
+ int this_ldata,this_lparam;
+ int tot_data=0,tot_param=0;
+ char *outdata,*outparam;
+
+ this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
+ this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
+
+ memset(cli->outbuf,'\0',smb_size);
+ set_message(cli->outbuf,19+lsetup,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBnttrans);
+ SSVAL(cli->outbuf,smb_tid, cli->cnum);
+ cli_setup_packet(cli);
+
+ outparam = smb_buf(cli->outbuf)+3;
+ outdata = outparam+this_lparam;
+
+ /* primary request */
+ SCVAL(cli->outbuf,smb_nt_MaxSetupCount,msetup);
+ SCVAL(cli->outbuf,smb_nt_Flags,flags);
+ SIVAL(cli->outbuf,smb_nt_TotalParameterCount, lparam);
+ SIVAL(cli->outbuf,smb_nt_TotalDataCount, ldata);
+ SIVAL(cli->outbuf,smb_nt_MaxParameterCount, mparam);
+ SIVAL(cli->outbuf,smb_nt_MaxDataCount, mdata);
+ SIVAL(cli->outbuf,smb_nt_ParameterCount, this_lparam);
+ SIVAL(cli->outbuf,smb_nt_ParameterOffset, smb_offset(outparam,cli->outbuf));
+ SIVAL(cli->outbuf,smb_nt_DataCount, this_ldata);
+ SIVAL(cli->outbuf,smb_nt_DataOffset, smb_offset(outdata,cli->outbuf));
+ SIVAL(cli->outbuf,smb_nt_SetupCount, lsetup);
+ SIVAL(cli->outbuf,smb_nt_Function, function);
+ for (i=0;i<lsetup;i++) /* setup[] */
+ SSVAL(cli->outbuf,smb_nt_SetupStart+i*2,setup[i]);
+
+ if (this_lparam) /* param[] */
+ memcpy(outparam,param,this_lparam);
+ if (this_ldata) /* data[] */
+ memcpy(outdata,data,this_ldata);
+
+ cli_setup_bcc(cli, outdata+this_ldata);
+
+ show_msg(cli->outbuf);
+ cli_send_smb(cli);
+
+ if (this_ldata < ldata || this_lparam < lparam) {
+ /* receive interim response */
+ if (!cli_receive_smb(cli) ||
+ cli_is_error(cli)) {
+ return(False);
+ }
+
+ tot_data = this_ldata;
+ tot_param = this_lparam;
+
+ while (tot_data < ldata || tot_param < lparam) {
+ this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
+ this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
+
+ set_message(cli->outbuf,18,0,True);
+ SCVAL(cli->outbuf,smb_com,SMBnttranss);
+
+ /* XXX - these should probably be aligned */
+ outparam = smb_buf(cli->outbuf);
+ outdata = outparam+this_lparam;
+
+ /* secondary request */
+ SIVAL(cli->outbuf,smb_nts_TotalParameterCount,lparam);
+ SIVAL(cli->outbuf,smb_nts_TotalDataCount,ldata);
+ SIVAL(cli->outbuf,smb_nts_ParameterCount,this_lparam);
+ SIVAL(cli->outbuf,smb_nts_ParameterOffset,smb_offset(outparam,cli->outbuf));
+ SIVAL(cli->outbuf,smb_nts_ParameterDisplacement,tot_param);
+ SIVAL(cli->outbuf,smb_nts_DataCount,this_ldata);
+ SIVAL(cli->outbuf,smb_nts_DataOffset,smb_offset(outdata,cli->outbuf));
+ SIVAL(cli->outbuf,smb_nts_DataDisplacement,tot_data);
+ if (this_lparam) /* param[] */
+ memcpy(outparam,param+tot_param,this_lparam);
+ if (this_ldata) /* data[] */
+ memcpy(outdata,data+tot_data,this_ldata);
+ cli_setup_bcc(cli, outdata+this_ldata);
+
+ show_msg(cli->outbuf);
+ cli_send_smb(cli);
+
+ tot_data += this_ldata;
+ tot_param += this_lparam;
+ }
+ }
+
+ return(True);
+}
+
+
+
+/****************************************************************************
+ receive a SMB nttrans response allocating the necessary memory
+ ****************************************************************************/
+BOOL cli_receive_nt_trans(struct cli_state *cli,
+ char **param, int *param_len,
+ char **data, int *data_len)
+{
+ int total_data=0;
+ int total_param=0;
+ int this_data,this_param;
+ uint8 eclass;
+ uint32 ecode;
+ char *tdata;
+ char *tparam;
+
+ *data_len = *param_len = 0;
+
+ if (!cli_receive_smb(cli))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ /* sanity check */
+ if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
+ DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
+ CVAL(cli->inbuf,smb_com)));
+ return(False);
+ }
+
+ /*
+ * 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 (cli_is_dos_error(cli)) {
+ cli_dos_error(cli, &eclass, &ecode);
+ if (cli->nt_pipe_fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata))
+ return(False);
+ }
+
+ /* parse out the lengths */
+ total_data = SVAL(cli->inbuf,smb_ntr_TotalDataCount);
+ total_param = SVAL(cli->inbuf,smb_ntr_TotalParameterCount);
+
+ /* allocate it */
+ if (total_data) {
+ tdata = Realloc(*data,total_data);
+ if (!tdata) {
+ DEBUG(0,("cli_receive_nt_trans: failed to enlarge data buffer to %d\n",total_data));
+ return False;
+ } else {
+ *data = tdata;
+ }
+ }
+
+ if (total_param) {
+ tparam = Realloc(*param,total_param);
+ if (!tparam) {
+ DEBUG(0,("cli_receive_nt_trans: failed to enlarge param buffer to %d\n", total_param));
+ return False;
+ } else {
+ *param = tparam;
+ }
+ }
+
+ while (1) {
+ this_data = SVAL(cli->inbuf,smb_ntr_DataCount);
+ this_param = SVAL(cli->inbuf,smb_ntr_ParameterCount);
+
+ if (this_data + *data_len > total_data ||
+ this_param + *param_len > total_param) {
+ DEBUG(1,("Data overflow in cli_receive_trans\n"));
+ return False;
+ }
+
+ if (this_data)
+ memcpy(*data + SVAL(cli->inbuf,smb_ntr_DataDisplacement),
+ smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_ntr_DataOffset),
+ this_data);
+ if (this_param)
+ memcpy(*param + SVAL(cli->inbuf,smb_ntr_ParameterDisplacement),
+ smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_ntr_ParameterOffset),
+ this_param);
+ *data_len += this_data;
+ *param_len += this_param;
+
+ /* parse out the total lengths again - they can shrink! */
+ total_data = SVAL(cli->inbuf,smb_ntr_TotalDataCount);
+ total_param = SVAL(cli->inbuf,smb_ntr_TotalParameterCount);
+
+ if (total_data <= *data_len && total_param <= *param_len)
+ break;
+
+ if (!cli_receive_smb(cli))
+ return False;
+
+ show_msg(cli->inbuf);
+
+ /* sanity check */
+ if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
+ DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
+ CVAL(cli->inbuf,smb_com)));
+ return(False);
+ }
+ if (cli_is_dos_error(cli)) {
+ cli_dos_error(cli, &eclass, &ecode);
+ if(cli->nt_pipe_fnum == 0 ||
+ !(eclass == ERRDOS && ecode == ERRmoredata))
+ return(False);
+ }
+ }
+
+ return(True);
+}
diff --git a/source3/libsmb/credentials.c b/source3/libsmb/credentials.c
new file mode 100644
index 0000000000..0d521bae8a
--- /dev/null
+++ b/source3/libsmb/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/source3/libsmb/doserr.c b/source3/libsmb/doserr.c
new file mode 100644
index 0000000000..adc001bf29
--- /dev/null
+++ b/source3/libsmb/doserr.c
@@ -0,0 +1,89 @@
+/*
+ * 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
+{
+ 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 },
+ { NULL, W_ERROR(0) }
+};
+
+/*****************************************************************************
+ returns a DOS error message. not amazingly helpful, but better than a number.
+ *****************************************************************************/
+char *dos_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/source3/libsmb/errormap.c b/source3/libsmb/errormap.c
new file mode 100644
index 0000000000..c30db3ad95
--- /dev/null
+++ b/source3/libsmb/errormap.c
@@ -0,0 +1,1483 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * error mapping 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"
+
+/* 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 */
+const static 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 */
+const static 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 */
+const static 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(int eclass, int 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);
+}
diff --git a/source3/libsmb/libsmbclient.c b/source3/libsmb/libsmbclient.c
new file mode 100644
index 0000000000..237701b968
--- /dev/null
+++ b/source3/libsmb/libsmbclient.c
@@ -0,0 +1,2581 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB client library implementation
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000
+ Copyright (C) John Terpstra 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"
+#include "libsmbclient.h"
+
+/* Structure for servers ... Held here so we don't need an include ...
+ * May be better to put in an include file
+ */
+
+struct smbc_server {
+ struct smbc_server *next, *prev;
+ struct cli_state cli;
+ dev_t dev;
+ char *server_name;
+ char *share_name;
+ char *workgroup;
+ char *username;
+ BOOL no_pathinfo2;
+};
+
+/* Keep directory entries in a list */
+struct smbc_dir_list {
+ struct smbc_dir_list *next;
+ struct smbc_dirent *dirent;
+};
+
+struct smbc_file {
+ int cli_fd;
+ int smbc_fd;
+ char *fname;
+ off_t offset;
+ struct smbc_server *srv;
+ BOOL file;
+ struct smbc_dir_list *dir_list, *dir_end, *dir_next;
+ int dir_type, dir_error;
+};
+
+int smbc_fstatdir(int fd, struct stat *st); /* Forward decl */
+BOOL smbc_getatr(struct smbc_server *srv, char *path,
+ uint16 *mode, size_t *size,
+ time_t *c_time, time_t *a_time, time_t *m_time,
+ SMB_INO_T *ino);
+
+extern BOOL in_client;
+extern pstring global_myname;
+static int smbc_initialized = 0;
+static smbc_get_auth_data_fn smbc_auth_fn = NULL;
+/*static int smbc_debug;*/
+static int smbc_start_fd;
+static struct smbc_file **smbc_file_table;
+static struct smbc_server *smbc_srvs;
+static pstring my_netbios_name;
+static pstring smbc_user;
+
+/*
+ * Function to parse a path and turn it into components
+ *
+ * We accept smb://[[[domain;]user[:password@]]server[/share[/path[/file]]]]
+ *
+ * smb:// means show all the workgroups
+ * smb://name/ means, if name<1D> exists, list servers in workgroup,
+ * else, if name<20> exists, list all shares for server ...
+ */
+
+static const char *smbc_prefix = "smb:";
+
+static int
+smbc_parse_path(const char *fname, char *server, char *share, char *path,
+ char *user, char *password) /* FIXME, lengths of strings */
+{
+ static pstring s;
+ pstring userinfo;
+ char *p;
+ char *q, *r;
+ int len;
+
+ server[0] = share[0] = path[0] = user[0] = password[0] = (char)0;
+ pstrcpy(s, fname);
+
+ /* clean_fname(s); causing problems ... */
+
+ /* see if it has the right prefix */
+ len = strlen(smbc_prefix);
+ if (strncmp(s,smbc_prefix,len) ||
+ (s[len] != '/' && s[len] != 0)) return -1; /* What about no smb: ? */
+
+ p = s + len;
+
+ /* Watch the test below, we are testing to see if we should exit */
+
+ if (strncmp(p, "//", 2) && strncmp(p, "\\\\", 2)) {
+
+ return -1;
+
+ }
+
+ p += 2; /* Skip the // or \\ */
+
+ if (*p == (char)0)
+ return 0;
+
+ if (*p == '/') {
+
+ strncpy(server, (char *)lp_workgroup(), 16); /* FIXME: Danger here */
+ return 0;
+
+ }
+
+ /*
+ * ok, its for us. Now parse out the server, share etc.
+ *
+ * However, we want to parse out [[domain;]user[:password]@] if it
+ * exists ...
+ */
+
+ /* check that '@' occurs before '/', if '/' exists at all */
+ q = strchr_m(p, '@');
+ r = strchr_m(p, '/');
+ if (q && (!r || q < r)) {
+ pstring username, passwd, domain;
+ char *u = userinfo;
+
+ next_token(&p, userinfo, "@", sizeof(fstring));
+
+ username[0] = passwd[0] = domain[0] = 0;
+
+ if (strchr_m(u, ';')) {
+
+ next_token(&u, domain, ";", sizeof(fstring));
+
+ }
+
+ if (strchr_m(u, ':')) {
+
+ next_token(&u, username, ":", sizeof(fstring));
+
+ pstrcpy(passwd, u);
+
+ }
+ else {
+
+ pstrcpy(username, u);
+
+ }
+
+ if (username[0])
+ strncpy(user, username, sizeof(fstring)); /* FIXME, size and domain */
+
+ if (passwd[0])
+ strncpy(password, passwd, sizeof(fstring)); /* FIXME, size */
+
+ }
+
+ if (!next_token(&p, server, "/", sizeof(fstring))) {
+
+ return -1;
+
+ }
+
+ if (*p == (char)0) return 0; /* That's it ... */
+
+ if (!next_token(&p, share, "/", sizeof(fstring))) {
+
+ return -1;
+
+ }
+
+ pstrcpy(path, p);
+
+ all_string_sub(path, "/", "\\", 0);
+
+ return 0;
+}
+
+/*
+ * Convert an SMB error into a UNIX error ...
+ */
+
+int smbc_errno(struct cli_state *c)
+{
+ int ret;
+
+ if (cli_is_dos_error(c)) {
+ uint8 eclass;
+ uint32 ecode;
+
+ cli_dos_error(c, &eclass, &ecode);
+ ret = cli_errno_from_dos(eclass, ecode);
+
+ DEBUG(3,("smbc_error %d %d (0x%x) -> %d\n",
+ (int)eclass, (int)ecode, (int)ecode, ret));
+ } else {
+ NTSTATUS status;
+
+ status = cli_nt_error(c);
+ ret = cli_errno_from_nt(status);
+
+ DEBUG(3,("smbc errno %s -> %d\n",
+ nt_errstr(status), ret));
+ }
+
+ return ret;
+}
+
+/*
+ * Connect to a server, possibly on an existing connection
+ *
+ * Here, what we want to do is: If the server and username
+ * match an existing connection, reuse that, otherwise, establish a
+ * new connection.
+ *
+ * If we have to create a new connection, call the auth_fn to get the
+ * info we need, unless the username and password were passed in.
+ */
+
+struct smbc_server *smbc_server(char *server, char *share,
+ char *workgroup, char *username,
+ char *password)
+{
+ struct smbc_server *srv=NULL;
+ struct cli_state c;
+ struct nmb_name called, calling;
+ char *p, *server_n = server;
+ fstring group;
+ pstring ipenv;
+ struct in_addr ip;
+
+ zero_ip(&ip);
+ ZERO_STRUCT(c);
+
+ /* try to use an existing connection */
+ for (srv=smbc_srvs;srv;srv=srv->next) {
+ if (strcmp(server,srv->server_name)==0 &&
+ strcmp(share,srv->share_name)==0 &&
+ strcmp(workgroup,srv->workgroup)==0 &&
+ strcmp(username, srv->username) == 0)
+ return srv;
+ }
+
+ if (server[0] == 0) {
+ errno = EPERM;
+ return NULL;
+ }
+
+ /*
+ * Pick up the auth info here, once we know we need to connect
+ * But only if we do not have a username and password ...
+ */
+
+ if (!username[0] || !password[0])
+ smbc_auth_fn(server, share, workgroup, sizeof(fstring),
+ username, sizeof(fstring), password, sizeof(fstring));
+
+ /*
+ * However, smbc_auth_fn may have picked up info relating to an
+ * existing connection, so try for an existing connection again ...
+ */
+
+ for (srv=smbc_srvs;srv;srv=srv->next) {
+ if (strcmp(server,srv->server_name)==0 &&
+ strcmp(share,srv->share_name)==0 &&
+ strcmp(workgroup,srv->workgroup)==0 &&
+ strcmp(username, srv->username) == 0)
+ return srv;
+ }
+
+ make_nmb_name(&calling, my_netbios_name, 0x0);
+ make_nmb_name(&called , server, 0x20);
+
+ DEBUG(4,("smbc_server: server_n=[%s] server=[%s]\n", server_n, server));
+
+ if ((p=strchr_m(server_n,'#')) &&
+ (strcmp(p+1,"1D")==0 || strcmp(p+1,"01")==0)) {
+
+ fstrcpy(group, server_n);
+ p = strchr_m(group,'#');
+ *p = 0;
+
+ }
+
+ DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
+
+ again:
+ slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n);
+
+ zero_ip(&ip);
+
+ /* have to open a new connection */
+ if (!cli_initialise(&c) || !cli_connect(&c, server_n, &ip)) {
+ if (c.initialised) cli_shutdown(&c);
+ errno = ENOENT;
+ return NULL;
+ }
+
+ if (!cli_session_request(&c, &calling, &called)) {
+ cli_shutdown(&c);
+ if (strcmp(called.name, "*SMBSERVER")) {
+ make_nmb_name(&called , "*SMBSERVER", 0x20);
+ goto again;
+ }
+ errno = ENOENT;
+ return NULL;
+ }
+
+ DEBUG(4,(" session request ok\n"));
+
+ if (!cli_negprot(&c)) {
+ cli_shutdown(&c);
+ errno = ENOENT;
+ return NULL;
+ }
+
+ if (!cli_session_setup(&c, username,
+ password, strlen(password),
+ password, strlen(password),
+ workgroup) &&
+ /* try an anonymous login if it failed */
+ !cli_session_setup(&c, "", "", 1,"", 0, workgroup)) {
+ cli_shutdown(&c);
+ errno = EPERM;
+ return NULL;
+ }
+
+ DEBUG(4,(" session setup ok\n"));
+
+ if (!cli_send_tconX(&c, share, "?????",
+ password, strlen(password)+1)) {
+ errno = smbc_errno(&c);
+ cli_shutdown(&c);
+ return NULL;
+ }
+
+ DEBUG(4,(" tconx ok\n"));
+
+ srv = (struct smbc_server *)malloc(sizeof(*srv));
+ if (!srv) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ ZERO_STRUCTP(srv);
+
+ srv->cli = c;
+
+ srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
+
+ srv->server_name = strdup(server);
+ if (!srv->server_name) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ srv->share_name = strdup(share);
+ if (!srv->share_name) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ srv->workgroup = strdup(workgroup);
+ if (!srv->workgroup) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ srv->username = strdup(username);
+ if (!srv->username) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ DLIST_ADD(smbc_srvs, srv);
+
+ return srv;
+
+ failed:
+ cli_shutdown(&c);
+ if (!srv) return NULL;
+
+ SAFE_FREE(srv->server_name);
+ SAFE_FREE(srv->share_name);
+ SAFE_FREE(srv->workgroup);
+ SAFE_FREE(srv->username);
+ SAFE_FREE(srv);
+ return NULL;
+}
+
+/*
+ *Remove a server from the list smbc_srvs if it's unused -- Tom (tom@ninja.nl)
+ *
+ * We accept a *srv
+ */
+BOOL smbc_remove_unused_server(struct smbc_server * s)
+{
+ int p;
+
+ /* are we being fooled ? */
+ if (!s) return False;
+
+ /* close all open files/directories on this server */
+ for (p = 0; p < SMBC_MAX_FD; p++) {
+ if (smbc_file_table[p] &&
+ smbc_file_table[p]->srv == s) {
+ /* Still used .. DARN */
+ DEBUG(3, ("smbc_remove_usused_server: %x still used by %s (%d).\n", (int) s,
+ smbc_file_table[p]->fname, smbc_file_table[p]->smbc_fd));
+ return False;
+ }
+ }
+
+ cli_shutdown(&s->cli);
+
+ SAFE_FREE(s->username);
+ SAFE_FREE(s->workgroup);
+ SAFE_FREE(s->server_name);
+ SAFE_FREE(s->share_name);
+ DLIST_REMOVE(smbc_srvs, s);
+ DEBUG(3, ("smbc_remove_usused_server: %x removed.\n", (int) s));
+ SAFE_FREE(s);
+ return True;
+}
+
+/*
+ *Initialise the library etc
+ *
+ * We accept valid values for debug from 0 to 100,
+ * and insist that fn must be non-null.
+ */
+
+int smbc_init(smbc_get_auth_data_fn fn, int debug)
+{
+ pstring conf;
+ int p, pid;
+ char *user = NULL, *home = NULL, *pname="libsmbclient";
+
+ if (!fn || debug < 0 || debug > 100) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (smbc_initialized) { /* Don't go through this if we have already done it */
+
+ return 0;
+
+ }
+
+ smbc_initialized = 1;
+ smbc_auth_fn = fn;
+ /* smbc_debug = debug; */
+
+ DEBUGLEVEL = -1;
+
+ setup_logging(pname, False);
+
+ /* Here we would open the smb.conf file if needed ... */
+
+ home = getenv("HOME");
+
+ slprintf(conf, sizeof(conf), "%s/.smb/smb.conf", home);
+
+ load_interfaces(); /* Load the list of interfaces ... */
+
+ in_client = True; /* FIXME, make a param */
+
+ if (!lp_load(conf, True, False, False)) {
+
+ /*
+ * Hmmm, what the hell do we do here ... we could not parse the
+ * config file ... We must return an error ... and keep info around
+ * about why we failed
+ */
+
+ errno = ENOENT; /* FIXME: Figure out the correct error response */
+ return -1;
+
+ }
+
+ reopen_logs(); /* Get logging working ... */
+
+ /*
+ * FIXME: Is this the best way to get the user info?
+ */
+
+ user = getenv("USER");
+ /* walk around as "guest" if no username can be found */
+ if (!user) user = strdup("guest");
+ pstrcpy(smbc_user, user); /* Save for use elsewhere */
+
+ /*
+ * We try to get our netbios name from the config. If that fails we fall
+ * back on constructing our netbios name from our hostname etc
+ */
+ if (global_myname) {
+ pstrcpy(my_netbios_name, global_myname);
+ }
+ else {
+ /*
+ * Hmmm, I want to get hostname as well, but I am too lazy for the moment
+ */
+ pid = sys_getpid();
+ slprintf(my_netbios_name, 16, "smbc%s%d", user, pid);
+ }
+ DEBUG(0,("Using netbios name %s.\n", my_netbios_name));
+
+ name_register_wins(my_netbios_name, 0);
+
+ /*
+ * Now initialize the file descriptor array and figure out what the
+ * max open files is, so we can return FD's that are above the max
+ * open file, and separated by a guard band
+ */
+
+#if (defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE))
+ do {
+ struct rlimit rlp;
+
+ if (getrlimit(RLIMIT_NOFILE, &rlp)) {
+
+ DEBUG(0, ("smbc_init: getrlimit(1) for RLIMIT_NOFILE failed with error %s\n", strerror(errno)));
+
+ smbc_start_fd = 1000000;
+
+ }
+ else {
+
+ smbc_start_fd = rlp.rlim_max + 10000; /* Leave a guard space of 10,000 */
+
+ }
+ } while ( 0 );
+#else /* !defined(HAVE_GETRLIMIT) || !defined(RLIMIT_NOFILE) */
+
+ smbc_start_fd = 1000000;
+
+#endif
+
+ smbc_file_table = malloc(SMBC_MAX_FD * sizeof(struct smbc_file *));
+
+ for (p = 0; p < SMBC_MAX_FD; p++)
+ smbc_file_table[p] = NULL;
+
+ if (!smbc_file_table)
+ return ENOMEM;
+
+ return 0; /* Success */
+
+}
+
+/*
+ * Routine to open() a file ...
+ */
+
+int smbc_open(const char *fname, int flags, mode_t mode)
+{
+ fstring server, share, user, password, workgroup;
+ pstring path;
+ struct smbc_server *srv = NULL;
+ int fd;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL; /* Best I can think of ... */
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ smbc_parse_path(fname, server, share, path, user, password); /* FIXME, check errors */
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ pstrcpy(workgroup, lp_workgroup());
+
+ srv = smbc_server(server, share, workgroup, user, password);
+
+ if (!srv) {
+
+ if (errno == EPERM) errno = EACCES;
+ return -1; /* smbc_server sets errno */
+
+ }
+
+ /* Hmmm, the test for a directory is suspect here ... FIXME */
+
+ if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') {
+
+ fd = -1;
+
+ }
+ else {
+
+ int slot = 0;
+
+ /* Find a free slot first */
+
+ while (smbc_file_table[slot])
+ slot++;
+
+ if (slot > SMBC_MAX_FD) {
+
+ errno = ENOMEM; /* FIXME, is this best? */
+ return -1;
+
+ }
+
+ smbc_file_table[slot] = malloc(sizeof(struct smbc_file));
+
+ if (!smbc_file_table[slot]) {
+
+ errno = ENOMEM;
+ return -1;
+
+ }
+
+ if ((fd = cli_open(&srv->cli, path, flags, DENY_NONE)) < 0) {
+
+ /* Handle the error ... */
+
+ SAFE_FREE(smbc_file_table[slot]);
+ errno = smbc_errno(&srv->cli);
+ return -1;
+
+ }
+
+ /* Fill in file struct */
+
+ smbc_file_table[slot]->cli_fd = fd;
+ smbc_file_table[slot]->smbc_fd = slot + smbc_start_fd;
+ smbc_file_table[slot]->fname = strdup(fname);
+ smbc_file_table[slot]->srv = srv;
+ smbc_file_table[slot]->offset = 0;
+ smbc_file_table[slot]->file = True;
+
+ return smbc_file_table[slot]->smbc_fd;
+
+ }
+
+ /* Check if opendir needed ... */
+
+ if (fd == -1) {
+ int eno = 0;
+
+ eno = smbc_errno(&srv->cli);
+ fd = smbc_opendir(fname);
+ if (fd < 0) errno = eno;
+ return fd;
+
+ }
+
+ return 1; /* Success, with fd ... */
+
+}
+
+/*
+ * Routine to create a file
+ */
+
+static int creat_bits = O_WRONLY | O_CREAT | O_TRUNC; /* FIXME: Do we need this */
+
+int smbc_creat(const char *path, mode_t mode)
+{
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ return smbc_open(path, creat_bits, mode);
+}
+
+/*
+ * Routine to read() a file ...
+ */
+
+ssize_t smbc_read(int fd, void *buf, size_t count)
+{
+ struct smbc_file *fe;
+ int ret;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_read(%d, %d)\n", fd, (int)count));
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ /* Check that the buffer exists ... */
+
+ if (buf == NULL) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe || !fe->file) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ ret = cli_read(&fe->srv->cli, fe->cli_fd, buf, fe->offset, count);
+
+ if (ret < 0) {
+
+ errno = smbc_errno(&fe->srv->cli);
+ return -1;
+
+ }
+
+ fe->offset += ret;
+
+ DEBUG(4, (" --> %d\n", ret));
+
+ return ret; /* Success, ret bytes of data ... */
+
+}
+
+/*
+ * Routine to write() a file ...
+ */
+
+ssize_t smbc_write(int fd, void *buf, size_t count)
+{
+ int ret;
+ struct smbc_file *fe;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ /* Check that the buffer exists ... */
+
+ if (buf == NULL) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe || !fe->file) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ ret = cli_write(&fe->srv->cli, fe->cli_fd, 0, buf, fe->offset, count);
+
+ if (ret <= 0) {
+
+ errno = smbc_errno(&fe->srv->cli);
+ return -1;
+
+ }
+
+ fe->offset += ret;
+
+ return ret; /* Success, 0 bytes of data ... */
+}
+
+/*
+ * Routine to close() a file ...
+ */
+
+int smbc_close(int fd)
+{
+ struct smbc_file *fe;
+ struct smbc_server *srv;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ if (!fe->file) {
+
+ return smbc_closedir(fd);
+
+ }
+
+ if (!cli_close(&fe->srv->cli, fe->cli_fd)) {
+
+ DEBUG(3, ("cli_close failed on %s (%d). purging server.\n",
+ fe->fname, fe->smbc_fd));
+ /* Deallocate slot and remove the server
+ * from the server cache if unused */
+ errno = smbc_errno(&fe->srv->cli);
+ srv = fe->srv;
+ SAFE_FREE(fe->fname);
+ SAFE_FREE(fe);
+ smbc_file_table[fd - smbc_start_fd] = NULL;
+ smbc_remove_unused_server(srv);
+
+ return -1;
+
+ }
+
+ SAFE_FREE(fe->fname);
+ SAFE_FREE(fe);
+ smbc_file_table[fd - smbc_start_fd] = NULL;
+
+ return 0;
+}
+
+/*
+ * Routine to unlink() a file
+ */
+
+int smbc_unlink(const char *fname)
+{
+ fstring server, share, user, password, workgroup;
+ pstring path;
+ struct smbc_server *srv = NULL;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL; /* Best I can think of ... */
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ smbc_parse_path(fname, server, share, path, user, password); /* FIXME, check errors */
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ pstrcpy(workgroup, lp_workgroup());
+
+ srv = smbc_server(server, share, workgroup, user, password);
+
+ if (!srv) {
+
+ return -1; /* smbc_server sets errno */
+
+ }
+
+ /* if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
+
+ int job = smbc_stat_printjob(srv, path, NULL, NULL);
+ if (job == -1) {
+
+ return -1;
+
+ }
+ if ((err = cli_printjob_del(&srv->cli, job)) != 0) {
+
+
+ return -1;
+
+ }
+ } else */
+
+ if (!cli_unlink(&srv->cli, path)) {
+
+ errno = smbc_errno(&srv->cli);
+
+ if (errno == EACCES) { /* Check if the file is a directory */
+
+ int saverr = errno;
+ size_t size = 0;
+ uint16 mode = 0;
+ time_t m_time = 0, a_time = 0, c_time = 0;
+ SMB_INO_T ino = 0;
+
+ if (!smbc_getatr(srv, path, &mode, &size,
+ &c_time, &a_time, &m_time, &ino)) {
+
+ /* Hmmm, bad error ... What? */
+
+ errno = smbc_errno(&srv->cli);
+ return -1;
+
+ }
+ else {
+
+ if (IS_DOS_DIR(mode))
+ errno = EISDIR;
+ else
+ errno = saverr; /* Restore this */
+
+ }
+ }
+
+ return -1;
+
+ }
+
+ return 0; /* Success ... */
+
+}
+
+/*
+ * Routine to rename() a file
+ */
+
+int smbc_rename(const char *oname, const char *nname)
+{
+ fstring server1, share1, server2, share2, user1, user2, password1, password2, workgroup;
+ pstring path1, path2;
+ struct smbc_server *srv = NULL;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL; /* Best I can think of ... */
+ return -1;
+
+ }
+
+ if (!oname || !nname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname));
+
+ smbc_parse_path(oname, server1, share1, path1, user1, password1);
+
+ if (user1[0] == (char)0) pstrcpy(user1, smbc_user);
+
+ smbc_parse_path(nname, server2, share2, path2, user2, password2);
+
+ if (user2[0] == (char)0) pstrcpy(user2, smbc_user);
+
+ if (strcmp(server1, server2) || strcmp(share1, share2) ||
+ strcmp(user1, user2)) {
+
+ /* Can't rename across file systems, or users?? */
+
+ errno = EXDEV;
+ return -1;
+
+ }
+
+ pstrcpy(workgroup, lp_workgroup());
+
+ srv = smbc_server(server1, share1, workgroup, user1, password1);
+ if (!srv) {
+
+ return -1;
+
+ }
+
+ if (!cli_rename(&srv->cli, path1, path2)) {
+ int eno = smbc_errno(&srv->cli);
+
+ if (eno != EEXIST ||
+ !cli_unlink(&srv->cli, path2) ||
+ !cli_rename(&srv->cli, path1, path2)) {
+
+ errno = eno;
+ return -1;
+
+ }
+ }
+
+ return 0; /* Success */
+
+}
+
+/*
+ * A routine to lseek() a file
+ */
+
+off_t smbc_lseek(int fd, off_t offset, int whence)
+{
+ struct smbc_file *fe;
+ size_t size;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ if (!fe->file) {
+
+ errno = EINVAL;
+ return -1; /* Can't lseek a dir ... */
+
+ }
+
+ switch (whence) {
+ case SEEK_SET:
+ fe->offset = offset;
+ break;
+
+ case SEEK_CUR:
+ fe->offset += offset;
+ break;
+
+ case SEEK_END:
+ if (!cli_qfileinfo(&fe->srv->cli, fe->cli_fd, NULL, &size, NULL, NULL,
+ NULL, NULL, NULL) &&
+ !cli_getattrE(&fe->srv->cli, fe->cli_fd, NULL, &size, NULL, NULL,
+ NULL)) {
+
+ errno = EINVAL;
+ return -1;
+ }
+ fe->offset = size + offset;
+ break;
+
+ default:
+ errno = EINVAL;
+ break;
+
+ }
+
+ return fe->offset;
+
+}
+
+/*
+ * Generate an inode number from file name for those things that need it
+ */
+
+static
+ino_t smbc_inode(const char *name)
+{
+
+ if (!*name) return 2; /* FIXME, why 2 ??? */
+ return (ino_t)str_checksum(name);
+
+}
+
+/*
+ * Routine to put basic stat info into a stat structure ... Used by stat and
+ * fstat below.
+ */
+
+static
+int smbc_setup_stat(struct stat *st, char *fname, size_t size, int mode)
+{
+
+ st->st_mode = 0;
+
+ if (IS_DOS_DIR(mode)) {
+ st->st_mode = SMBC_DIR_MODE;
+ } else {
+ st->st_mode = SMBC_FILE_MODE;
+ }
+
+ if (IS_DOS_ARCHIVE(mode)) st->st_mode |= S_IXUSR;
+ if (IS_DOS_SYSTEM(mode)) st->st_mode |= S_IXGRP;
+ if (IS_DOS_HIDDEN(mode)) st->st_mode |= S_IXOTH;
+ if (!IS_DOS_READONLY(mode)) st->st_mode |= S_IWUSR;
+
+ st->st_size = size;
+ st->st_blksize = 512;
+ st->st_blocks = (size+511)/512;
+ st->st_uid = getuid();
+ st->st_gid = getgid();
+
+ if (IS_DOS_DIR(mode)) {
+ st->st_nlink = 2;
+ } else {
+ st->st_nlink = 1;
+ }
+
+ if (st->st_ino == 0) {
+ st->st_ino = smbc_inode(fname);
+ }
+
+ return True; /* FIXME: Is this needed ? */
+
+}
+
+/*
+ * Get info from an SMB server on a file. Use a qpathinfo call first
+ * and if that fails, use getatr, as Win95 sometimes refuses qpathinfo
+ */
+
+BOOL smbc_getatr(struct smbc_server *srv, char *path,
+ uint16 *mode, size_t *size,
+ time_t *c_time, time_t *a_time, time_t *m_time,
+ SMB_INO_T *ino)
+{
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4,("smbc_getatr: sending qpathinfo\n"));
+
+ if (!srv->no_pathinfo2 &&
+ cli_qpathinfo2(&srv->cli, path, c_time, a_time, m_time, NULL,
+ size, mode, ino)) return True;
+
+ /* if this is NT then don't bother with the getatr */
+ if (srv->cli.capabilities & CAP_NT_SMBS) return False;
+
+ if (cli_getatr(&srv->cli, path, mode, size, m_time)) {
+ a_time = c_time = m_time;
+ srv->no_pathinfo2 = True;
+ return True;
+ }
+ return False;
+}
+
+/*
+ * Routine to stat a file given a name
+ */
+
+int smbc_stat(const char *fname, struct stat *st)
+{
+ struct smbc_server *srv;
+ fstring server, share, user, password, workgroup;
+ pstring path;
+ time_t m_time = 0, a_time = 0, c_time = 0;
+ size_t size = 0;
+ uint16 mode = 0;
+ SMB_INO_T ino = 0;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL; /* Best I can think of ... */
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_stat(%s)\n", fname));
+
+ smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ pstrcpy(workgroup, lp_workgroup());
+
+ srv = smbc_server(server, share, workgroup, user, password);
+
+ if (!srv) {
+
+ return -1; /* errno set by smbc_server */
+
+ }
+
+ /* if (strncmp(srv->cli.dev, "IPC", 3) == 0) {
+
+ mode = aDIR | aRONLY;
+
+ }
+ else if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
+
+ if (strcmp(path, "\\") == 0) {
+
+ mode = aDIR | aRONLY;
+
+ }
+ else {
+
+ mode = aRONLY;
+ smbc_stat_printjob(srv, path, &size, &m_time);
+ c_time = a_time = m_time;
+
+ }
+ else { */
+
+ if (!smbc_getatr(srv, path, &mode, &size,
+ &c_time, &a_time, &m_time, &ino)) {
+
+ errno = smbc_errno(&srv->cli);
+ return -1;
+
+ }
+
+ /* } */
+
+ st->st_ino = ino;
+
+ smbc_setup_stat(st, path, size, mode);
+
+ st->st_atime = a_time;
+ st->st_ctime = c_time;
+ st->st_mtime = m_time;
+ st->st_dev = srv->dev;
+
+ return 0;
+
+}
+
+/*
+ * Routine to stat a file given an fd
+ */
+
+int smbc_fstat(int fd, struct stat *st)
+{
+ struct smbc_file *fe;
+ time_t c_time, a_time, m_time;
+ size_t size;
+ uint16 mode;
+ SMB_INO_T ino = 0;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ if (!fe->file) {
+
+ return smbc_fstatdir(fd, st);
+
+ }
+
+ if (!cli_qfileinfo(&fe->srv->cli, fe->cli_fd,
+ &mode, &size, &c_time, &a_time, &m_time, NULL, &ino) &&
+ !cli_getattrE(&fe->srv->cli, fe->cli_fd,
+ &mode, &size, &c_time, &a_time, &m_time)) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ st->st_ino = ino;
+
+ smbc_setup_stat(st, fe->fname, size, mode);
+
+ st->st_atime = a_time;
+ st->st_ctime = c_time;
+ st->st_mtime = m_time;
+ st->st_dev = fe->srv->dev;
+
+ return 0;
+
+}
+
+/*
+ * Routine to open a directory
+ *
+ * We want to allow:
+ *
+ * smb: which should list all the workgroups available
+ * smb:workgroup
+ * smb:workgroup//server
+ * smb://server
+ * smb://server/share
+ * smb://<IP-addr> which should list shares on server
+ * smb://<IP-addr>/share which should list files on share
+ */
+
+static void smbc_remove_dir(struct smbc_file *dir)
+{
+ struct smbc_dir_list *d,*f;
+
+ d = dir->dir_list;
+ while (d) {
+
+ f = d; d = d->next;
+
+ SAFE_FREE(f->dirent);
+ SAFE_FREE(f);
+
+ }
+
+ dir->dir_list = dir->dir_end = dir->dir_next = NULL;
+
+}
+
+static int add_dirent(struct smbc_file *dir, const char *name, const char *comment, uint32 type)
+{
+ struct smbc_dirent *dirent;
+ int size;
+
+ /*
+ * Allocate space for the dirent, which must be increased by the
+ * size of the name and the comment and 1 for the null on the comment.
+ * The null on the name is already accounted for.
+ */
+
+ size = sizeof(struct smbc_dirent) + (name?strlen(name):0) +
+ (comment?strlen(comment):0) + 1;
+
+ dirent = malloc(size);
+
+ if (!dirent) {
+
+ dir->dir_error = ENOMEM;
+ return -1;
+
+ }
+
+ if (dir->dir_list == NULL) {
+
+ dir->dir_list = malloc(sizeof(struct smbc_dir_list));
+ if (!dir->dir_list) {
+
+ SAFE_FREE(dirent);
+ dir->dir_error = ENOMEM;
+ return -1;
+
+ }
+
+ dir->dir_end = dir->dir_next = dir->dir_list;
+
+ }
+ else {
+
+ dir->dir_end->next = malloc(sizeof(struct smbc_dir_list));
+
+ if (!dir->dir_end) {
+
+ SAFE_FREE(dirent);
+ dir->dir_error = ENOMEM;
+ return -1;
+
+ }
+
+ dir->dir_end = dir->dir_end->next;
+
+ }
+
+ dir->dir_end->next = NULL;
+ dir->dir_end->dirent = dirent;
+
+ dirent->smbc_type = type;
+ dirent->namelen = (name?strlen(name):0);
+ dirent->commentlen = (comment?strlen(comment):0);
+ dirent->dirlen = size;
+
+ strncpy(dirent->name, (name?name:""), dirent->namelen + 1);
+
+ dirent->comment = (char *)(&dirent->name + dirent->namelen + 1);
+ strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1);
+
+ return 0;
+
+}
+
+static void
+list_fn(const char *name, uint32 type, const char *comment, void *state)
+{
+ struct smbc_file *dir = (struct smbc_file *)state;
+ int dirent_type;
+
+ /* We need to process the type a little ... */
+
+ if (dir->dir_type == SMBC_FILE_SHARE) {
+
+ switch (type) {
+ case 0: /* Directory tree */
+ dirent_type = SMBC_FILE_SHARE;
+ break;
+
+ case 1:
+ dirent_type = SMBC_PRINTER_SHARE;
+ break;
+
+ case 2:
+ dirent_type = SMBC_COMMS_SHARE;
+ break;
+
+ case 3:
+ dirent_type = SMBC_IPC_SHARE;
+ break;
+
+ default:
+ dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */
+ break;
+ }
+
+ }
+ else dirent_type = dir->dir_type;
+
+ if (add_dirent(dir, name, comment, dirent_type) < 0) {
+
+ /* An error occurred, what do we do? */
+ /* FIXME: Add some code here */
+
+ }
+
+}
+
+static void
+dir_list_fn(file_info *finfo, const char *mask, void *state)
+{
+
+ if (add_dirent((struct smbc_file *)state, finfo->name, "",
+ (finfo->mode&aDIR?SMBC_DIR:SMBC_FILE)) < 0) {
+
+ /* Handle an error ... */
+ /* FIXME: Add some code ... */
+
+ }
+
+}
+
+int smbc_opendir(const char *fname)
+{
+ fstring server, share, user, password, workgroup;
+ pstring path;
+ struct smbc_server *srv = NULL;
+ struct in_addr rem_ip;
+ int slot = 0;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (smbc_parse_path(fname, server, share, path, user, password)) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ pstrcpy(workgroup, lp_workgroup());
+
+ /* Get a file entry ... */
+
+ slot = 0;
+
+ while (smbc_file_table[slot])
+ slot++;
+
+ if (slot > SMBC_MAX_FD) {
+
+ errno = ENOMEM;
+ return -1; /* FIXME, ... move into a func */
+
+ }
+
+ smbc_file_table[slot] = malloc(sizeof(struct smbc_file));
+
+ if (!smbc_file_table[slot]) {
+
+ errno = ENOMEM;
+ return -1;
+
+ }
+
+ smbc_file_table[slot]->cli_fd = 0;
+ smbc_file_table[slot]->smbc_fd = slot + smbc_start_fd;
+ smbc_file_table[slot]->fname = strdup(fname);
+ smbc_file_table[slot]->srv = NULL;
+ smbc_file_table[slot]->offset = 0;
+ smbc_file_table[slot]->file = False;
+ smbc_file_table[slot]->dir_list =
+ smbc_file_table[slot]->dir_next =
+ smbc_file_table[slot]->dir_end = NULL;
+
+ if (server[0] == (char)0) {
+
+ if (share[0] != (char)0 || path[0] != (char)0) {
+
+ errno = EINVAL;
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ return -1;
+
+ }
+
+ /* We have server and share and path empty ... so list the workgroups */
+
+ if (!resolve_name(lp_workgroup(), &rem_ip, 0x1d)) {
+
+ errno = EINVAL; /* Something wrong with smb.conf? */
+ return -1;
+
+ }
+
+ smbc_file_table[slot]->dir_type = SMBC_WORKGROUP;
+
+ /* find the name of the server ... */
+
+ if (!name_status_find("*", 0, 0, rem_ip, server)) {
+
+ DEBUG(0, ("Could not get the name of local master browser for server %s\n", server));
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ /*
+ * Get a connection to IPC$ on the server if we do not already have one
+ */
+
+ srv = smbc_server(server, "IPC$", workgroup, user, password);
+
+ if (!srv) {
+
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ return -1;
+
+ }
+
+ smbc_file_table[slot]->srv = srv;
+
+ /* Now, list the stuff ... */
+
+ if (!cli_NetServerEnum(&srv->cli, workgroup, 0x80000000, list_fn,
+ (void *)smbc_file_table[slot])) {
+
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ errno = cli_errno(&srv->cli);
+ return -1;
+
+ }
+ }
+ else { /* Server not an empty string ... Check the rest and see what gives */
+
+ if (share[0] == (char)0) {
+
+ if (path[0] != (char)0) { /* Should not have empty share with path */
+
+ errno = EINVAL;
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ return -1;
+
+ }
+
+ /* Check to see if <server><1D> translates, or <server><20> translates */
+ /* However, we check to see if <server> is an IP address first */
+
+ if (!is_ipaddress(server) && /* Not an IP addr so check next */
+ resolve_name(server, &rem_ip, 0x1d)) { /* Found LMB */
+ pstring buserver;
+
+ smbc_file_table[slot]->dir_type = SMBC_SERVER;
+
+ /*
+ * Get the backup list ...
+ */
+
+
+ if (!name_status_find("*", 0, 0, rem_ip, buserver)) {
+
+ DEBUG(0, ("Could not get name of local master browser %s\n", server));
+ errno = EPERM; /* FIXME, is this correct */
+ return -1;
+
+ }
+
+ /*
+ * Get a connection to IPC$ on the server if we do not already have one
+ */
+
+ srv = smbc_server(buserver, "IPC$", workgroup, user, password);
+
+ if (!srv) {
+
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ return -1;
+
+ }
+
+ smbc_file_table[slot]->srv = srv;
+
+ /* Now, list the servers ... */
+
+ if (!cli_NetServerEnum(&srv->cli, server, 0x0000FFFE, list_fn,
+ (void *)smbc_file_table[slot])) {
+
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ errno = cli_errno(&srv->cli);
+ return -1;
+
+ }
+
+ }
+ else {
+
+ if (resolve_name(server, &rem_ip, 0x20)) {
+
+ /* Now, list the shares ... */
+
+ smbc_file_table[slot]->dir_type = SMBC_FILE_SHARE;
+
+ srv = smbc_server(server, "IPC$", workgroup, user, password);
+
+ if (!srv) {
+
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ return -1;
+
+ }
+
+ smbc_file_table[slot]->srv = srv;
+
+ /* Now, list the servers ... */
+
+ if (cli_RNetShareEnum(&srv->cli, list_fn,
+ (void *)smbc_file_table[slot]) < 0) {
+
+ errno = cli_errno(&srv->cli);
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ return -1;
+
+ }
+
+ }
+ else {
+
+ errno = ENODEV; /* Neither the workgroup nor server exists */
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ return -1;
+
+ }
+
+ }
+
+ }
+ else { /* The server and share are specified ... work from there ... */
+
+ /* Well, we connect to the server and list the directory */
+
+ smbc_file_table[slot]->dir_type = SMBC_FILE_SHARE;
+
+ srv = smbc_server(server, share, workgroup, user, password);
+
+ if (!srv) {
+
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ return -1;
+
+ }
+
+ smbc_file_table[slot]->srv = srv;
+
+ /* Now, list the files ... */
+
+ pstrcat(path, "\\*");
+
+ if (cli_list(&srv->cli, path, aDIR | aSYSTEM | aHIDDEN, dir_list_fn,
+ (void *)smbc_file_table[slot]) < 0) {
+
+ if (smbc_file_table[slot]) {
+ SAFE_FREE(smbc_file_table[slot]->fname);
+ SAFE_FREE(smbc_file_table[slot]);
+ }
+ errno = smbc_errno(&srv->cli);
+ return -1;
+
+ }
+ }
+
+ }
+
+ return smbc_file_table[slot]->smbc_fd;
+
+}
+
+/*
+ * Routine to close a directory
+ */
+
+int smbc_closedir(int fd)
+{
+ struct smbc_file *fe;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ smbc_remove_dir(fe); /* Clean it up */
+
+ if (fe) {
+
+ SAFE_FREE(fe->fname);
+ SAFE_FREE(fe); /* Free the space too */
+
+ }
+
+ smbc_file_table[fd - smbc_start_fd] = NULL;
+
+ return 0;
+
+}
+
+/*
+ * Routine to get a directory entry
+ */
+
+static char smbc_local_dirent[512]; /* Make big enough */
+
+struct smbc_dirent *smbc_readdir(unsigned int fd)
+{
+ struct smbc_file *fe;
+ struct smbc_dirent *dirp, *dirent;
+
+ /* Check that all is ok first ... */
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return NULL;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
+
+ errno = EBADF;
+ return NULL;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return NULL;
+
+ }
+
+ if (fe->file != False) { /* FIXME, should be dir, perhaps */
+
+ errno = ENOTDIR;
+ return NULL;
+
+ }
+
+ if (!fe->dir_next)
+ return NULL;
+ else {
+
+ dirent = fe->dir_next->dirent;
+
+ if (!dirent) {
+
+ errno = ENOENT;
+ return NULL;
+
+ }
+
+ /* Hmmm, do I even need to copy it? */
+
+ memcpy(smbc_local_dirent, dirent, dirent->dirlen); /* Copy the dirent */
+
+ dirp = (struct smbc_dirent *)smbc_local_dirent;
+
+ dirp->comment = (char *)(&dirp->name + dirent->namelen + 1);
+
+ fe->dir_next = fe->dir_next->next;
+
+ return (struct smbc_dirent *)smbc_local_dirent;
+ }
+
+}
+
+/*
+ * Routine to get directory entries
+ */
+
+int smbc_getdents(unsigned int fd, struct smbc_dirent *dirp, int count)
+{
+ struct smbc_file *fe;
+ struct smbc_dir_list *dir;
+ int rem = count, reqd;
+ char *ndir = (char *)dirp;
+
+ /* Check that all is ok first ... */
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ if (fe->file != False) { /* FIXME, should be dir, perhaps */
+
+ errno = ENOTDIR;
+ return -1;
+
+ }
+
+ /*
+ * Now, retrieve the number of entries that will fit in what was passed
+ * We have to figure out if the info is in the list, or we need to
+ * send a request to the server to get the info.
+ */
+
+ while ((dir = fe->dir_next)) {
+ struct smbc_dirent *dirent;
+
+ if (!dir->dirent) {
+
+ errno = ENOENT; /* Bad error */
+ return -1;
+
+ }
+
+ if (rem < (reqd = (sizeof(struct smbc_dirent) + dir->dirent->namelen +
+ dir->dirent->commentlen + 1))) {
+
+ if (rem < count) { /* We managed to copy something */
+
+ errno = 0;
+ return count - rem;
+
+ }
+ else { /* Nothing copied ... */
+
+ errno = EINVAL; /* Not enough space ... */
+ return -1;
+
+ }
+
+ }
+
+ dirent = dir->dirent;
+
+ memcpy(ndir, dirent, reqd); /* Copy the data in ... */
+
+ ((struct smbc_dirent *)ndir)->comment =
+ (char *)(&((struct smbc_dirent *)ndir)->name + dirent->namelen + 1);
+
+ ndir += reqd;
+
+ rem -= reqd;
+
+ fe->dir_next = dir = dir -> next;
+ }
+
+ if (rem == count)
+ return 0;
+ else
+ return count - rem;
+
+}
+
+/*
+ * Routine to create a directory ...
+ */
+
+int smbc_mkdir(const char *fname, mode_t mode)
+{
+ struct smbc_server *srv;
+ fstring server, share, user, password, workgroup;
+ pstring path;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_mkdir(%s)\n", fname));
+
+ smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ pstrcpy(workgroup, lp_workgroup());
+
+ srv = smbc_server(server, share, workgroup, user, password);
+
+ if (!srv) {
+
+ return -1; /* errno set by smbc_server */
+
+ }
+
+ /* if (strncmp(srv->cli.dev, "IPC", 3) == 0) {
+
+ mode = aDIR | aRONLY;
+
+ }
+ else if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
+
+ if (strcmp(path, "\\") == 0) {
+
+ mode = aDIR | aRONLY;
+
+ }
+ else {
+
+ mode = aRONLY;
+ smbc_stat_printjob(srv, path, &size, &m_time);
+ c_time = a_time = m_time;
+
+ }
+ else { */
+
+ if (!cli_mkdir(&srv->cli, path)) {
+
+ errno = smbc_errno(&srv->cli);
+ return -1;
+
+ }
+
+ return 0;
+
+}
+
+/*
+ * Our list function simply checks to see if a directory is not empty
+ */
+
+static int smbc_rmdir_dirempty = True;
+
+static void rmdir_list_fn(file_info *finfo, const char *mask, void *state)
+{
+
+ if (strncmp(finfo->name, ".", 1) != 0 && strncmp(finfo->name, "..", 2) != 0)
+ smbc_rmdir_dirempty = False;
+
+}
+
+/*
+ * Routine to remove a directory
+ */
+
+int smbc_rmdir(const char *fname)
+{
+ struct smbc_server *srv;
+ fstring server, share, user, password, workgroup;
+ pstring path;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_rmdir(%s)\n", fname));
+
+ smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ pstrcpy(workgroup, lp_workgroup());
+
+ srv = smbc_server(server, share, workgroup, user, password);
+
+ if (!srv) {
+
+ return -1; /* errno set by smbc_server */
+
+ }
+
+ /* if (strncmp(srv->cli.dev, "IPC", 3) == 0) {
+
+ mode = aDIR | aRONLY;
+
+ }
+ else if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
+
+ if (strcmp(path, "\\") == 0) {
+
+ mode = aDIR | aRONLY;
+
+ }
+ else {
+
+ mode = aRONLY;
+ smbc_stat_printjob(srv, path, &size, &m_time);
+ c_time = a_time = m_time;
+
+ }
+ else { */
+
+ if (!cli_rmdir(&srv->cli, path)) {
+
+ errno = smbc_errno(&srv->cli);
+
+ if (errno == EACCES) { /* Check if the dir empty or not */
+
+ pstring lpath; /* Local storage to avoid buffer overflows */
+
+ smbc_rmdir_dirempty = True; /* Make this so ... */
+
+ pstrcpy(lpath, path);
+ pstrcat(lpath, "\\*");
+
+ if (cli_list(&srv->cli, lpath, aDIR | aSYSTEM | aHIDDEN, rmdir_list_fn,
+ NULL) < 0) {
+
+ /* Fix errno to ignore latest error ... */
+
+ DEBUG(5, ("smbc_rmdir: cli_list returned an error: %d\n",
+ smbc_errno(&srv->cli)));
+ errno = EACCES;
+
+ }
+
+ if (smbc_rmdir_dirempty)
+ errno = EACCES;
+ else
+ errno = ENOTEMPTY;
+
+ }
+
+ return -1;
+
+ }
+
+ return 0;
+
+}
+
+/*
+ * Routine to return the current directory position
+ */
+
+off_t smbc_telldir(int fd)
+{
+ struct smbc_file *fe;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ if (fe->file != False) { /* FIXME, should be dir, perhaps */
+
+ errno = ENOTDIR;
+ return -1;
+
+ }
+
+ return (off_t) fe->dir_next;
+
+}
+
+/*
+ * A routine to run down the list and see if the entry is OK
+ */
+
+struct smbc_dir_list *smbc_check_dir_ent(struct smbc_dir_list *list,
+ struct smbc_dirent *dirent)
+{
+
+ /* Run down the list looking for what we want */
+
+ if (dirent) {
+
+ struct smbc_dir_list *tmp = list;
+
+ while (tmp) {
+
+ if (tmp->dirent == dirent)
+ return tmp;
+
+ tmp = tmp->next;
+
+ }
+
+ }
+
+ return NULL; /* Not found, or an error */
+
+}
+
+
+/*
+ * Routine to seek on a directory
+ */
+
+int smbc_lseekdir(int fd, off_t offset)
+{
+ struct smbc_file *fe;
+ struct smbc_dirent *dirent = (struct smbc_dirent *)offset;
+ struct smbc_dir_list *list_ent = NULL;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + SMBC_MAX_FD)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ if (fe->file != False) { /* FIXME, should be dir, perhaps */
+
+ errno = ENOTDIR;
+ return -1;
+
+ }
+
+ /* Now, check what we were passed and see if it is OK ... */
+
+ if (dirent == NULL) { /* Seek to the begining of the list */
+
+ fe->dir_next = fe->dir_list;
+ return 0;
+
+ }
+
+ /* Now, run down the list and make sure that the entry is OK */
+ /* This may need to be changed if we change the format of the list */
+
+ if ((list_ent = smbc_check_dir_ent(fe->dir_list, dirent)) == NULL) {
+
+ errno = EINVAL; /* Bad entry */
+ return -1;
+
+ }
+
+ fe->dir_next = list_ent;
+
+ return 0;
+
+}
+
+/*
+ * Routine to fstat a dir
+ */
+
+int smbc_fstatdir(int fd, struct stat *st)
+{
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ /* No code yet ... */
+
+ return 0;
+
+}
+
+/*
+ * Routine to print a file on a remote server ...
+ *
+ * We open the file, which we assume to be on a remote server, and then
+ * copy it to a print file on the share specified by printq.
+ */
+
+int smbc_print_file(const char *fname, const char *printq)
+{
+ int fid1, fid2, bytes, saverr, tot_bytes = 0;
+ char buf[4096];
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!fname && !printq) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ /* Try to open the file for reading ... */
+
+ if ((fid1 = smbc_open(fname, O_RDONLY, 0666)) < 0) {
+
+ DEBUG(3, ("Error, fname=%s, errno=%i\n", fname, errno));
+ return -1; /* smbc_open sets errno */
+
+ }
+
+ /* Now, try to open the printer file for writing */
+
+ if ((fid2 = smbc_open_print_job(printq)) < 0) {
+
+ saverr = errno; /* Save errno */
+ smbc_close(fid1);
+ errno = saverr;
+ return -1;
+
+ }
+
+ while ((bytes = smbc_read(fid1, buf, sizeof(buf))) > 0) {
+
+ tot_bytes += bytes;
+
+ if ((smbc_write(fid2, buf, bytes)) < 0) {
+
+ saverr = errno;
+ smbc_close(fid1);
+ smbc_close(fid2);
+ errno = saverr;
+
+ }
+
+ }
+
+ saverr = errno;
+
+ smbc_close(fid1); /* We have to close these anyway */
+ smbc_close(fid2);
+
+ if (bytes < 0) {
+
+ errno = saverr;
+ return -1;
+
+ }
+
+ return tot_bytes;
+
+}
+
+/*
+ * Open a print file to be written to by other calls
+ */
+
+int smbc_open_print_job(const char *fname)
+{
+ fstring server, share, user, password;
+ pstring path;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_open_print_job(%s)\n", fname));
+
+ smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
+
+ /* What if the path is empty, or the file exists? */
+
+ return smbc_open(fname, O_WRONLY, 666);
+
+}
+
+/*
+ * Routine to list print jobs on a printer share ...
+ */
+
+int smbc_list_print_jobs(const char *fname, void (*fn)(struct print_job_info *))
+{
+ struct smbc_server *srv;
+ fstring server, share, user, password, workgroup;
+ pstring path;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_list_print_jobs(%s)\n", fname));
+
+ smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ pstrcpy(workgroup, lp_workgroup());
+
+ srv = smbc_server(server, share, workgroup, user, password);
+
+ if (!srv) {
+
+ return -1; /* errno set by smbc_server */
+
+ }
+
+ if (cli_print_queue(&srv->cli, fn) < 0) {
+
+ errno = smbc_errno(&srv->cli);
+ return -1;
+
+ }
+
+ return 0;
+
+}
+
+/*
+ * Delete a print job from a remote printer share
+ */
+
+int smbc_unlink_print_job(const char *fname, int id)
+{
+ struct smbc_server *srv;
+ fstring server, share, user, password, workgroup;
+ pstring path;
+ int err;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_unlink_print_job(%s)\n", fname));
+
+ smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ pstrcpy(workgroup, lp_workgroup());
+
+ srv = smbc_server(server, share, workgroup, user, password);
+
+ if (!srv) {
+
+ return -1; /* errno set by smbc_server */
+
+ }
+
+ if ((err = cli_printjob_del(&srv->cli, id)) != 0) {
+
+ if (err < 0)
+ errno = smbc_errno(&srv->cli);
+ else if (err == ERRnosuchprintjob)
+ errno = EINVAL;
+ return -1;
+
+
+ }
+
+ return 0;
+
+}
+
diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
new file mode 100644
index 0000000000..7928d44652
--- /dev/null
+++ b/source3/libsmb/namequery.c
@@ -0,0 +1,1330 @@
+/*
+ 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(sys_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;
+
+ 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, 15, 0, 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;
+}
+
+/****************************************************************************
+ Do a NetBIOS name registation to try to claim a name ...
+***************************************************************************/
+BOOL name_register(int fd, const char *name, int name_type,
+ struct in_addr name_ip, int opcode,
+ BOOL bcast,
+ struct in_addr to_ip, int *count)
+{
+ int retries = 3;
+ struct timeval tval;
+ struct packet_struct p;
+ struct packet_struct *p2;
+ struct nmb_packet *nmb = &p.packet.nmb;
+ struct in_addr register_ip;
+
+ DEBUG(4, ("name_register: %s as %s on %s\n", name, inet_ntoa(name_ip), inet_ntoa(to_ip)));
+
+ register_ip.s_addr = name_ip.s_addr; /* Fix this ... */
+
+ memset((char *)&p, '\0', sizeof(p));
+
+ *count = 0;
+
+ nmb->header.name_trn_id = generate_trn_id();
+ nmb->header.opcode = opcode;
+ nmb->header.response = False;
+ nmb->header.nm_flags.bcast = False;
+ nmb->header.nm_flags.recursion_available = False;
+ nmb->header.nm_flags.recursion_desired = True; /* ? */
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = True;
+
+ nmb->header.qdcount = 1;
+ nmb->header.ancount = 0;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = 1;
+
+ make_nmb_name(&nmb->question.question_name, name, name_type);
+
+ nmb->question.question_type = 0x20;
+ nmb->question.question_class = 0x1;
+
+ /* Now, create the additional stuff for a registration request */
+
+ if ((nmb->additional = (struct res_rec *)malloc(sizeof(struct res_rec))) == NULL) {
+
+ DEBUG(0, ("name_register: malloc fail for additional record.\n"));
+ return False;
+
+ }
+
+ memset((char *)nmb->additional, '\0', sizeof(struct res_rec));
+
+ nmb->additional->rr_name = nmb->question.question_name;
+ nmb->additional->rr_type = RR_TYPE_NB;
+ nmb->additional->rr_class = RR_CLASS_IN;
+
+ /* See RFC 1002, sections 5.1.1.1, 5.1.1.2 and 5.1.1.3 */
+ if (nmb->header.nm_flags.bcast)
+ nmb->additional->ttl = PERMANENT_TTL;
+ else
+ nmb->additional->ttl = lp_max_ttl();
+
+ nmb->additional->rdlength = 6;
+
+ nmb->additional->rdata[0] = NB_MFLAG & 0xFF;
+
+ /* Set the address for the name we are registering. */
+ putip(&nmb->additional->rdata[2], &register_ip);
+
+ 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 False;
+
+ retries--;
+
+ if ((p2 = receive_nmb_packet(fd, 10, nmb->header.name_trn_id))) {
+ debug_nmb_packet(p2);
+ SAFE_FREE(p2); /* No memory leaks ... */
+ }
+
+ return True;
+}
+
+/****************************************************************************
+ 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.
+****************************************************************************/
+struct in_addr *name_query(int fd,const char *name,int name_type,
+ BOOL bcast,BOOL recurse,
+ struct in_addr to_ip, int *count)
+{
+ 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;
+
+ memset((char *)&p,'\0',sizeof(p));
+ (*count) = 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 */
+ dbgtext( "Negative name query response, rcode 0x%02x: ", nmb2->header.rcode );
+ switch( nmb2->header.rcode ) {
+ case 0x01:
+ dbgtext( "Request was invalidly formatted.\n" );
+ break;
+ case 0x02:
+ dbgtext( "Problem with NBNS, cannot process name.\n");
+ break;
+ case 0x03:
+ dbgtext( "The name requested does not exist.\n" );
+ break;
+ case 0x04:
+ dbgtext( "Unsupported request error.\n" );
+ break;
+ case 0x05:
+ dbgtext( "Query refused error.\n" );
+ break;
+ default:
+ dbgtext( "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;
+ 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;
+ }
+ }
+
+ /* Reach here if we've timed out waiting for replies.. */
+ if( !bcast && !found ) {
+ /* Timed out wating for WINS server to respond. Mark it dead. */
+ wins_srv_died( to_ip );
+ }
+
+ 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( XFILE *fp, pstring name, int *name_type, struct in_addr *ipaddr)
+{
+ pstring line;
+
+ while(!x_feof(fp) && !x_ferror(fp)) {
+ pstring ip,flags,extra;
+ char *ptr;
+ 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(ip);
+
+ /* Extra feature. If the name ends in '#XX', where XX is a hex number,
+ then only add that name type. */
+ if((ptr = strchr_m(name, '#')) != NULL)
+ {
+ char *endptr;
+
+ ptr++;
+ *name_type = (int)strtol(ptr, &endptr, 16);
+
+ if(!*ptr || (endptr == ptr))
+ {
+ DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name));
+ continue;
+ }
+
+ *(--ptr) = '\0'; /* Truncate at the '#' */
+ }
+
+ return True;
+ }
+
+ return False;
+}
+
+/********************************************************
+ Finish parsing the lmhosts file.
+*********************************************************/
+
+void endlmhosts(XFILE *fp)
+{
+ x_fclose(fp);
+}
+
+BOOL name_register_wins(const char *name, int name_type)
+{
+ int sock, i, return_count;
+ int num_interfaces = iface_count();
+ struct in_addr sendto_ip;
+
+ /*
+ * Check if we have any interfaces, prevents a segfault later
+ */
+
+ if (num_interfaces <= 0)
+ return False; /* Should return some indication of the problem */
+
+ /*
+ * Do a broadcast register ...
+ */
+
+ if (0 == wins_srv_count())
+ return False;
+
+ if( DEBUGLVL( 4 ) )
+ {
+ dbgtext( "name_register_wins: Registering my name %s ", name );
+ dbgtext( "with WINS server %s.\n", wins_srv_name() );
+ }
+
+ sock = open_socket_in( SOCK_DGRAM, 0, 3,
+ interpret_addr("0.0.0.0"), True );
+
+ if (sock == -1) return False;
+
+ set_socket_options(sock, "SO_BROADCAST"); /* ????! crh */
+
+ sendto_ip = wins_srv_ip();
+
+ if (num_interfaces > 1) {
+
+ for (i = 0; i < num_interfaces; i++) {
+
+ if (!name_register(sock, name, name_type, *iface_n_ip(i),
+ NMB_NAME_MULTIHOMED_REG_OPCODE,
+ True, sendto_ip, &return_count)) {
+
+ close(sock);
+ return False;
+
+ }
+
+ }
+
+ }
+ else {
+
+ if (!name_register(sock, name, name_type, *iface_n_ip(0),
+ NMB_NAME_REG_OPCODE,
+ True, sendto_ip, &return_count)) {
+
+ close(sock);
+ return False;
+
+ }
+
+ }
+
+ close(sock);
+
+ return True;
+
+}
+
+/********************************************************
+ 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();
+
+ *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;
+ /* 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);
+ if(*return_ip_list != NULL) {
+ close(sock);
+ return True;
+ }
+ }
+
+ close(sock);
+ return False;
+}
+
+/********************************************************
+ Resolve via "wins" method.
+*********************************************************/
+
+static BOOL resolve_wins(const char *name, int name_type,
+ struct in_addr **return_iplist, int *return_count)
+{
+ int sock;
+ struct in_addr wins_ip;
+ BOOL wins_ismyip;
+
+ *return_iplist = NULL;
+ *return_count = 0;
+
+ /*
+ * "wins" means do a unicast lookup to the WINS server.
+ * Ignore if there is no WINS server specified or if the
+ * WINS server is one of our interfaces (if we're being
+ * called from within nmbd - we can't do this call as we
+ * would then block).
+ */
+
+ DEBUG(3,("resolve_wins: Attempting wins lookup for name %s<0x%x>\n", name, name_type));
+
+ if (lp_wins_support()) {
+ /*
+ * We're providing WINS support. Call ourselves so
+ * long as we're not nmbd.
+ */
+ extern struct in_addr loopback_ip;
+ wins_ip = loopback_ip;
+ wins_ismyip = True;
+ } else if( wins_srv_count() < 1 ) {
+ DEBUG(3,("resolve_wins: WINS server resolution selected and no WINS servers listed.\n"));
+ return False;
+ } else {
+ wins_ip = wins_srv_ip();
+ wins_ismyip = ismyip(wins_ip);
+ }
+
+ DEBUG(3, ("resolve_wins: WINS server == <%s>\n", inet_ntoa(wins_ip)) );
+ if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) {
+ sock = open_socket_in( SOCK_DGRAM, 0, 3,
+ interpret_addr(lp_socket_address()),
+ True );
+ if (sock != -1) {
+ *return_iplist = name_query( sock, name,
+ name_type, False,
+ True, wins_ip,
+ return_count);
+ if(*return_iplist != NULL) {
+ close(sock);
+ return True;
+ }
+ close(sock);
+ }
+ }
+
+ return False;
+}
+
+/********************************************************
+ Resolve via "lmhosts" method.
+*********************************************************/
+
+static BOOL resolve_lmhosts(const char *name, int name_type,
+ struct in_addr **return_iplist, int *return_count)
+{
+ /*
+ * "lmhosts" means parse the local lmhosts file.
+ */
+
+ XFILE *fp;
+ pstring lmhost_name;
+ int name_type2;
+ struct in_addr return_ip;
+
+ *return_iplist = NULL;
+ *return_count = 0;
+
+ DEBUG(3,("resolve_lmhosts: Attempting lmhosts lookup for name %s<0x%x>\n", name, name_type));
+
+ fp = startlmhosts(dyn_LMHOSTSFILE);
+ if(fp) {
+ while (getlmhostsent(fp, lmhost_name, &name_type2, &return_ip)) {
+ if (strequal(name, lmhost_name) &&
+ ((name_type2 == -1) || (name_type == name_type2))
+ ) {
+ endlmhosts(fp);
+ *return_iplist = (struct in_addr *)malloc(sizeof(struct in_addr));
+ if(*return_iplist == NULL) {
+ DEBUG(3,("resolve_lmhosts: malloc fail !\n"));
+ return False;
+ }
+ **return_iplist = return_ip;
+ *return_count = 1;
+ return True;
+ }
+ }
+ endlmhosts(fp);
+ }
+ return False;
+}
+
+
+/********************************************************
+ 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(const char *name, int name_type,
+ struct in_addr **return_iplist, int *return_count)
+{
+ pstring name_resolve_list;
+ fstring tok;
+ 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 */
+ (*return_iplist)->s_addr = inet_addr(name);
+ } else {
+ (*return_iplist)->s_addr = allones ? 0xFFFFFFFF : 0;
+ *return_count = 1;
+ }
+ return True;
+ }
+
+ pstrcpy(name_resolve_list, 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 && resolve_hosts(name, return_iplist, return_count)) {
+ result = True;
+ goto done;
+ }
+ } else if(strequal( tok, "lmhosts")) {
+ if (resolve_lmhosts(name, name_type, return_iplist, return_count)) {
+ result = True;
+ goto done;
+ }
+ } else if(strequal( tok, "wins")) {
+ /* don't resolve 1D via WINS */
+ if (name_type != 0x1D &&
+ resolve_wins(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;
+ }
+
+ /* 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(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(name);
+ return True;
+ }
+
+ if (internal_resolve_name(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;
+}
+
+
+/********************************************************
+ resolve a name of format \\server_name or \\ipaddress
+ into a name. also, cut the \\ from the front for us.
+*********************************************************/
+
+BOOL resolve_srv_name(const char* srv_name, fstring dest_host,
+ struct in_addr *ip)
+{
+ BOOL ret;
+ const char *sv_name = srv_name;
+
+ DEBUG(10,("resolve_srv_name: %s\n", srv_name));
+
+ if (srv_name == NULL || strequal("\\\\.", srv_name))
+ {
+ extern pstring global_myname;
+ fstrcpy(dest_host, global_myname);
+ ip = interpret_addr2("127.0.0.1");
+ return True;
+ }
+
+ if (strnequal("\\\\", srv_name, 2))
+ {
+ sv_name = &srv_name[2];
+ }
+
+ fstrcpy(dest_host, sv_name);
+ /* treat the '*' name specially - it is a magic name for the PDC */
+ if (strcmp(dest_host,"*") == 0) {
+ extern pstring global_myname;
+ ret = resolve_name(lp_workgroup(), ip, 0x1B);
+ lookup_dc_name(global_myname, lp_workgroup(), ip, dest_host);
+ } else {
+ ret = resolve_name(dest_host, ip, 0x20);
+ }
+
+ if (is_ipaddress(dest_host))
+ {
+ fstrcpy(dest_host, "*SMBSERVER");
+ }
+
+ return ret;
+}
+
+
+/********************************************************
+ Find the IP address of the master browser or DMB for a workgroup.
+*********************************************************/
+
+BOOL find_master_ip(char *group, struct in_addr *master_ip)
+{
+ struct in_addr *ip_list = NULL;
+ int count = 0;
+
+ if (internal_resolve_name(group, 0x1D, &ip_list, &count)) {
+ *master_ip = ip_list[0];
+ SAFE_FREE(ip_list);
+ return True;
+ }
+ if(internal_resolve_name(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;
+
+ /*
+ * 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 Local Master Browsers
+ ********************************************************/
+
+BOOL get_lmb_list(struct in_addr **ip_list, int *count)
+{
+ return internal_resolve_name( MSBROWSE, 0x1, ip_list, count);
+}
+
+/********************************************************
+ Get the IP address list of the PDC/BDC's of a Domain.
+*********************************************************/
+
+BOOL get_dc_list(BOOL pdc_only, const char *group, struct in_addr **ip_list, int *count)
+{
+ int name_type = pdc_only ? 0x1B : 0x1C;
+
+ /*
+ * If it's our domain then
+ * use the 'password server' parameter.
+ */
+
+ if (strequal(group, lp_workgroup())) {
+ char *p;
+ char *pserver = lp_passwordserver();
+ fstring name;
+ int num_adresses = 0;
+ struct in_addr *return_iplist = NULL;
+
+ if (! *pserver)
+ return internal_resolve_name(group, name_type, ip_list, count);
+
+ p = pserver;
+ while (next_token(&p,name,LIST_SEP,sizeof(name))) {
+ if (strequal(name, "*"))
+ return internal_resolve_name(group, name_type, ip_list, count);
+ num_adresses++;
+ }
+ if (num_adresses == 0)
+ return internal_resolve_name(group, name_type, ip_list, count);
+
+ return_iplist = (struct in_addr *)malloc(num_adresses * sizeof(struct in_addr));
+ if(return_iplist == NULL) {
+ DEBUG(3,("get_dc_list: malloc fail !\n"));
+ return False;
+ }
+ p = pserver;
+ *count = 0;
+ while (next_token(&p,name,LIST_SEP,sizeof(name))) {
+ struct in_addr name_ip;
+ if (resolve_name( name, &name_ip, 0x20) == False)
+ continue;
+ return_iplist[(*count)++] = name_ip;
+ }
+ *ip_list = return_iplist;
+ return (*count != 0);
+ } else
+ return internal_resolve_name(group, name_type, ip_list, count);
+}
diff --git a/source3/libsmb/netlogon_unigrp.c b/source3/libsmb/netlogon_unigrp.c
new file mode 100644
index 0000000000..979ff52bd3
--- /dev/null
+++ b/source3/libsmb/netlogon_unigrp.c
@@ -0,0 +1,157 @@
+/*
+ Unix SMB/CIFS implementation.
+ Universal groups helpers
+ Copyright (C) Alexander Bokovoy 2002.
+ 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.
+
+ This work was sponsored by Optifacio Software Services, Inc.
+*/
+
+#include "includes.h"
+
+/*
+ Handle for netlogon_unigrp.tdb database. It is used internally
+ in cli_store_uni_groups_*() and cli_fetch_uni_groups()
+ and is initialized on first call to cli_store_uni_groups_*()
+*/
+static TDB_CONTEXT *netlogon_unigrp_tdb = NULL;
+
+/*
+ Store universal groups info into netlogon_unigrp.tdb for
+ later usage. We use 'domain_SID/user_rid' as key and
+ array of uint32 where array[0] is number of elements
+ and elements are array[1] ... array[array[0]]
+*/
+
+BOOL uni_group_cache_init(void)
+{
+ if (!netlogon_unigrp_tdb) {
+ netlogon_unigrp_tdb = tdb_open_log(lock_path("netlogon_unigrp.tdb"), 0,
+ TDB_DEFAULT, O_RDWR | O_CREAT, 0644);
+ }
+
+ return (netlogon_unigrp_tdb != NULL);
+}
+
+void uni_group_cache_store_netlogon(TALLOC_CTX *mem_ctx, NET_USER_INFO_3 *user)
+{
+ TDB_DATA key,data;
+ fstring keystr;
+ int i;
+
+ if (!uni_group_cache_init()) {
+ DEBUG(0,("uni_group_cache_store_netlogon: cannot open netlogon_unigrp.tdb for write!\n"));
+ return;
+ }
+
+ /* Prepare key as DOMAIN-SID/USER-RID string */
+ slprintf(keystr, sizeof(keystr), "%s/%d",
+ sid_string_static(&user->dom_sid.sid), user->user_rid);
+ key.dptr = keystr;
+ key.dsize = strlen(keystr) + 1;
+
+ /* Prepare data */
+ data.dsize = (user->num_groups2+1)*sizeof(uint32);
+ data.dptr = talloc(mem_ctx, data.dsize);
+ if(!data.dptr) {
+ DEBUG(0,("uni_group_cache_store_netlogon: cannot allocate memory!\n"));
+ talloc_destroy(mem_ctx);
+ return;
+ }
+
+ /* Store data in byteorder-independent format */
+ SIVAL(&((uint32*)data.dptr)[0],0,user->num_groups2);
+ for(i=1; i<=user->num_groups2; i++) {
+ SIVAL(&((uint32*)data.dptr)[i],0,user->gids[i-1].g_rid);
+ }
+ tdb_store(netlogon_unigrp_tdb, key, data, TDB_REPLACE);
+}
+
+/*
+ Fetch universal groups info from netlogon_unigrp.tdb for given
+ domain sid and user rid and allocate it using given mem_ctx.
+ Universal groups are returned as array of uint32 elements
+ and elements are array[0] ... array[num_elements-1]
+
+*/
+uint32* uni_group_cache_fetch(DOM_SID *domain, uint32 user_rid,
+ TALLOC_CTX *mem_ctx, uint32 *num_groups)
+{
+ TDB_DATA key,data;
+ fstring keystr;
+ uint32 *groups;
+ uint32 i;
+ uint32 group_count;
+
+ if (!domain) {
+ DEBUG(1,("uni_group_cache_fetch: expected non-null domain sid\n"));
+ return NULL;
+ }
+ if (!mem_ctx) {
+ DEBUG(1,("uni_group_cache_fetch: expected non-null memory context\n"));
+ return NULL;
+ }
+ if (!num_groups) {
+ DEBUG(1,("uni_group_cache_fetch: expected non-null num_groups\n"));
+ return NULL;
+ }
+ if (!netlogon_unigrp_tdb) {
+ netlogon_unigrp_tdb = tdb_open_log(lock_path("netlogon_unigrp.tdb"), 0,
+ TDB_DEFAULT, O_RDWR, 0644);
+ }
+ if (!netlogon_unigrp_tdb) {
+ DEBUG(5,("uni_group_cache_fetch: cannot open netlogon_unigrp.tdb for read - normal if not created yet\n"));
+ return NULL;
+ }
+
+ *num_groups = 0;
+
+ /* Fetch universal groups */
+ slprintf(keystr, sizeof(keystr), "%s/%d",
+ sid_string_static(domain), user_rid);
+ key.dptr = keystr;
+ key.dsize = strlen(keystr) + 1;
+ data = tdb_fetch(netlogon_unigrp_tdb, key);
+
+ /* There is no cached universal groups in netlogon_unigrp.tdb */
+ /* for this user. */
+ if (!data.dptr) return NULL;
+
+ /* Transfer data to receiver's memory context */
+ group_count = IVAL(&((uint32*)data.dptr)[0],0);
+ groups = talloc(mem_ctx, (group_count)*sizeof(uint32));
+ if (groups) {
+ for(i=0; i<group_count; i++) {
+ groups[i] = IVAL(&((uint32*)data.dptr)[i+1],0);
+ }
+
+ } else {
+ DEBUG(1,("uni_group_cache_fetch: cannot allocate uni groups in receiver's memory context\n"));
+ }
+ SAFE_FREE(data.dptr);
+ *num_groups = group_count;
+ return groups;
+}
+
+/* Shutdown netlogon_unigrp database */
+void uni_group_cache_shutdown(void)
+{
+ if(netlogon_unigrp_tdb) {
+ tdb_close(netlogon_unigrp_tdb);
+ }
+}
+
diff --git a/source3/libsmb/nmblib.c b/source3/libsmb/nmblib.c
index 6743227173..c78946fa09 100644
--- a/source3/libsmb/nmblib.c
+++ b/source3/libsmb/nmblib.c
@@ -1,8 +1,7 @@
/*
- Unix SMB/Netbios implementation.
- Version 1.9.
+ Unix SMB/CIFS implementation.
NBT netbios library routines
- Copyright (C) Andrew Tridgell 1994-1995
+ 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
@@ -21,24 +20,141 @@
*/
#include "includes.h"
-#include "nameserv.h"
-extern int DEBUGLEVEL;
+int num_good_sends = 0;
+int num_good_receives = 0;
+
+static const struct opcode_names {
+ 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 }
+};
-int num_good_sends=0;
-int num_good_receives=0;
-static uint16 name_trn_id = 0;
-BOOL CanRecurse = True;
-extern pstring scope;
+/****************************************************************************
+ * 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, 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 ) )
+ {
+ dbgtext( "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) );
+ dbgtext( " 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) );
+ dbgtext( " 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(unsigned char *ubuf,int *offset,int length,
+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;
@@ -54,34 +170,41 @@ static BOOL handle_name_ptrs(unsigned char *ubuf,int *offset,int length,
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 offset,int length,
- struct nmb_name *name)
+static int parse_nmb_name(char *inbuf,int ofs,int length, struct nmb_name *name)
{
int m,n=0;
- unsigned char *ubuf = (unsigned char *)inbuf;
+ uchar *ubuf = (uchar *)inbuf;
int ret = 0;
BOOL got_pointer=False;
+ int loop_count=0;
+ int offset = ofs;
- if (length - offset < 2) return(0);
+ if (length - offset < 2)
+ return(0);
/* handle initial name pointers */
- if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret)) return(0);
+ 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);
+ if (!m)
+ return(0);
+ if ((m & 0xC0) || offset+m+2 > length)
+ return(0);
- bzero((char *)name,sizeof(*name));
+ memset((char *)name,'\0',sizeof(*name));
/* the "compressed" part */
- if (!got_pointer) ret += m + 2;
+ if (!got_pointer)
+ ret += m + 2;
offset++;
- while (m) {
- unsigned char c1,c2;
+ while (m > 0) {
+ uchar c1,c2;
c1 = ubuf[offset++]-'A';
c2 = ubuf[offset++]-'A';
- if ((c1 & 0xF0) || (c2 & 0xF0)) return(0);
+ if ((c1 & 0xF0) || (c2 & 0xF0) || (n > sizeof(name->name)-1))
+ return(0);
name->name[n++] = (c1<<4) | c2;
m -= 2;
}
@@ -90,25 +213,43 @@ static int parse_nmb_name(char *inbuf,int offset,int length,
if (n==16) {
/* parse out the name type,
its always in the 16th byte of the name */
- name->name_type = name->name[15];
+ 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;
+ while (n && name->name[n]==' ')
+ name->name[n--] = 0;
}
/* now the domain parts (if any) */
n = 0;
- while ((m=ubuf[offset])) {
+ 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);
-
- if (!got_pointer) ret += m+1;
- if (n) name->scope[n++] = '.';
- if (m+2+offset>length || n+m+1>sizeof(name->scope)) return(0);
+ 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++];
+ while (m--)
+ name->scope[n++] = (char)ubuf[offset++];
+
+ /*
+ * Watch for malicious loops.
+ */
+ if (loop_count++ == 10)
+ return 0;
}
name->scope[n++] = 0;
@@ -130,12 +271,13 @@ static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
fstring buf1;
char *p;
- if (name->name[0] == '*') {
+ if (strcmp(name->name,"*") == 0) {
/* special case for wildcard name */
- bzero(buf1,20);
+ memset(buf1,'\0',20);
buf1[0] = '*';
+ buf1[15] = name->name_type;
} else {
- sprintf(buf1,"%-15.15s%c",name->name,name->name_type);
+ slprintf(buf1, sizeof(buf1) - 1,"%-15.15s%c",name->name,name->name_type);
}
buf[offset] = 0x20;
@@ -153,12 +295,12 @@ static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
if (name->scope[0]) {
/* XXXX this scope handling needs testing */
ret += strlen(name->scope) + 1;
- strcpy(&buf[offset+1],name->scope);
+ pstrcpy(&buf[offset+1],name->scope);
p = &buf[offset+1];
- while ((p = strchr(p,'.'))) {
- buf[offset] = PTR_DIFF(p,&buf[offset]);
- offset += buf[offset];
+ 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]);
@@ -170,39 +312,38 @@ static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
/*******************************************************************
useful for debugging messages
******************************************************************/
-char *namestr(struct nmb_name *n)
+char *nmb_namestr(struct nmb_name *n)
{
static int i=0;
static fstring ret[4];
char *p = ret[i];
if (!n->scope[0])
- sprintf(p,"%s(%x)",n->name,n->name_type);
+ slprintf(p,sizeof(fstring)-1, "%s<%02x>",n->name,n->name_type);
else
- sprintf(p,"%s(%x).%s",n->name,n->name_type,n->scope);
+ slprintf(p,sizeof(fstring)-1, "%s<%02x>.%s",n->name,n->name_type,n->scope);
i = (i+1)%4;
return(p);
}
/*******************************************************************
- allocate are parse some resource records
+ allocate and parse some resource records
******************************************************************/
static BOOL parse_alloc_res_rec(char *inbuf,int *offset,int length,
- struct res_rec **recs,
- int count)
+ struct res_rec **recs, int count)
{
int i;
*recs = (struct res_rec *)malloc(sizeof(**recs)*count);
if (!*recs) return(False);
- bzero(*recs,sizeof(**recs)*count);
+ 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) {
- free(*recs);
+ SAFE_FREE(*recs);
return(False);
}
(*recs)[i].rr_type = RSVAL(inbuf,(*offset));
@@ -212,7 +353,7 @@ static BOOL parse_alloc_res_rec(char *inbuf,int *offset,int length,
(*offset) += 10;
if ((*recs)[i].rdlength>sizeof((*recs)[i].rdata) ||
(*offset)+(*recs)[i].rdlength > length) {
- free(*recs);
+ SAFE_FREE(*recs);
return(False);
}
memcpy((*recs)[i].rdata,inbuf+(*offset),(*recs)[i].rdlength);
@@ -246,6 +387,27 @@ static int put_res_rec(char *buf,int offset,struct res_rec *recs,int count)
}
/*******************************************************************
+ 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
@@ -256,7 +418,7 @@ static BOOL parse_dgram(char *inbuf,int length,struct dgram_packet *dgram)
int offset;
int flags;
- bzero((char *)dgram,sizeof(*dgram));
+ memset((char *)dgram,'\0',sizeof(*dgram));
if (length < 14) return(False);
@@ -298,12 +460,15 @@ static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
{
int nm_flags,offset;
- bzero((char *)nmb,sizeof(*nmb));
+ 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);
@@ -311,7 +476,7 @@ static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
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.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);
@@ -351,13 +516,128 @@ static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
}
/*******************************************************************
+ '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
******************************************************************/
-void free_nmb_packet(struct nmb_packet *nmb)
+static void free_nmb_packet(struct nmb_packet *nmb)
{
- if (nmb->answers) free(nmb->answers);
- if (nmb->nsrecs) free(nmb->nsrecs);
- if (nmb->additional) free(nmb->additional);
+ 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. */
}
/*******************************************************************
@@ -365,58 +645,80 @@ void free_nmb_packet(struct nmb_packet *nmb)
******************************************************************/
void free_packet(struct packet_struct *packet)
{
+ if (packet->locked)
+ return;
if (packet->packet_type == NMB_PACKET)
free_nmb_packet(&packet->packet.nmb);
- free(packet);
+ else if (packet->packet_type == DGRAM_PACKET)
+ free_dgram_packet(&packet->packet.dgram);
+ ZERO_STRUCTPN(packet);
+ SAFE_FREE(packet);
}
/*******************************************************************
- 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
+parse a packet buffer into a packet structure
******************************************************************/
-struct packet_struct *read_packet(int fd,enum packet_type packet_type)
+struct packet_struct *parse_packet(char *buf,int length,
+ enum packet_type packet_type)
{
- extern struct in_addr lastip;
- extern int lastport;
- struct packet_struct *packet;
- char buf[MAX_DGRAM_SIZE];
- int length;
- BOOL ok=False;
-
- length = read_udp_socket(fd,buf,sizeof(buf));
- if (length < MIN_DGRAM_SIZE) return(NULL);
-
- packet = (struct packet_struct *)malloc(sizeof(*packet));
- if (!packet) return(NULL);
-
- packet->next = NULL;
- packet->prev = NULL;
- packet->ip = lastip;
- packet->port = lastport;
- packet->fd = fd;
- packet->timestamp = time(NULL);
- packet->packet_type = packet_type;
- switch (packet_type)
- {
- case NMB_PACKET:
- ok = parse_nmb(buf,length,&packet->packet.nmb);
- break;
+ extern struct in_addr lastip;
+ extern int lastport;
+ 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->ip = lastip;
+ p->port = lastport;
+ 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;
+ }
- case DGRAM_PACKET:
- ok = parse_dgram(buf,length,&packet->packet.dgram);
- break;
- }
- if (!ok) {
- free(packet);
- return(NULL);
- }
+ if (!ok) {
+ free_packet(p);
+ return NULL;
+ }
- num_good_receives++;
+ return p;
+}
- DEBUG(4,("%s received a packet of len %d from (%s) port %d\n",
- timestring(),length,inet_ntoa(packet->ip),packet->port));
+/*******************************************************************
+ 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;
+
+ length = read_udp_socket(fd,buf,sizeof(buf));
+ if (length < MIN_DGRAM_SIZE) return(NULL);
+
+ packet = parse_packet(buf, length, packet_type);
+ if (!packet) return NULL;
- return(packet);
+ packet->fd = fd;
+
+ num_good_receives++;
+
+ DEBUG(5,("Received a packet of len %d from (%s) port %d\n",
+ length, inet_ntoa(packet->ip), packet->port ) );
+
+ return(packet);
}
@@ -425,20 +727,28 @@ struct packet_struct *read_packet(int fd,enum packet_type packet_type)
******************************************************************/
static BOOL send_udp(int fd,char *buf,int len,struct in_addr ip,int port)
{
- BOOL ret;
+ BOOL ret = False;
+ int i;
struct sockaddr_in sock_out;
/* set the address and port */
- bzero((char *)&sock_out,sizeof(sock_out));
+ 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(4,("%s sending a packet of len %d to (%s) on port %d\n",
- timestring(),len,inet_ntoa(ip),port));
+ 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.
+ */
- ret = (sendto(fd,buf,len,0,(struct sockaddr *)&sock_out,
- sizeof(sock_out)) >= 0);
+ 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",
@@ -460,7 +770,7 @@ static BOOL send_udp(int fd,char *buf,int len,struct in_addr ip,int port)
static int build_dgram(char *buf,struct packet_struct *p)
{
struct dgram_packet *dgram = &p->packet.dgram;
- unsigned char *ubuf = (unsigned char *)buf;
+ uchar *ubuf = (uchar *)buf;
int offset=0;
/* put in the header */
@@ -494,15 +804,27 @@ static int build_dgram(char *buf,struct packet_struct *p)
/*******************************************************************
build a nmb name
- ******************************************************************/
-void make_nmb_name(struct nmb_name *n,char *name,int type,char *this_scope)
+ *******************************************************************/
+void make_nmb_name( struct nmb_name *n, const char *name, int type)
{
- strcpy(n->name,name);
- strupper(n->name);
- n->name_type = type;
- strcpy(n->scope,this_scope);
+ extern pstring global_scope;
+ 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, global_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
@@ -515,19 +837,22 @@ void make_nmb_name(struct nmb_name *n,char *name,int type,char *this_scope)
static int build_nmb(char *buf,struct packet_struct *p)
{
struct nmb_packet *nmb = &p->packet.nmb;
- unsigned char *ubuf = (unsigned char *)buf;
+ 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) ubuf[offset+2] |= 0x4;
+ 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) ubuf[offset+3] |= 0x80;
+ 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);
@@ -550,15 +875,52 @@ static int build_nmb(char *buf,struct packet_struct *p)
offset += put_res_rec((char *)ubuf,offset,nmb->nsrecs,
nmb->header.nscount);
- if (nmb->header.arcount)
+ /*
+ * 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)
@@ -566,18 +928,9 @@ BOOL send_packet(struct packet_struct *p)
char buf[1024];
int len=0;
- bzero(buf,sizeof(buf));
-
- switch (p->packet_type)
- {
- case NMB_PACKET:
- len = build_nmb(buf,p);
- break;
+ memset(buf,'\0',sizeof(buf));
- case DGRAM_PACKET:
- len = build_dgram(buf,p);
- break;
- }
+ len = build_packet(buf, p);
if (!len) return(False);
@@ -590,347 +943,327 @@ BOOL send_packet(struct packet_struct *p)
***************************************************************************/
struct packet_struct *receive_packet(int fd,enum packet_type type,int t)
{
- fd_set fds;
- struct timeval timeout;
+ 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;
+ }
- FD_ZERO(&fds);
- FD_SET(fd,&fds);
- timeout.tv_sec = t/1000;
- timeout.tv_usec = 1000*(t%1000);
+ if (ret == 0) /* timeout */
+ return NULL;
- sys_select(&fds,&timeout);
+ if (FD_ISSET(fd,&fds))
+ return(read_packet(fd,type));
+
+ 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);
+}
/****************************************************************************
-interpret a node status response
-****************************************************************************/
-static void interpret_node_status(char *p, char *master,char *rname)
+ 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, char *mailslot_name)
{
- int level = (master||rname)?4:0;
- int numnames = CVAL(p,0);
- DEBUG(level,("received %d names\n",numnames));
+ struct packet_struct *p;
- if (rname) *rname = 0;
- if (master) *master = 0;
+ p = receive_packet(fd, DGRAM_PACKET, t);
- p += 1;
- while (numnames--)
- {
- char qname[17];
- int type;
- fstring flags;
- *flags = 0;
- StrnCpy(qname,p,15);
- type = CVAL(p,15);
- p += 16;
-
- if (p[0] & 0x80) strcat(flags,"<GROUP> ");
- if ((p[0] & 0x60) == 0) strcat(flags,"B ");
- if ((p[0] & 0x60) == 1) strcat(flags,"P ");
- if ((p[0] & 0x60) == 2) strcat(flags,"M ");
- if ((p[0] & 0x60) == 3) strcat(flags,"_ ");
- if (p[0] & 0x10) strcat(flags,"<DEREGISTERING> ");
- if (p[0] & 0x08) strcat(flags,"<CONFLICT> ");
- if (p[0] & 0x04) strcat(flags,"<ACTIVE> ");
- if (p[0] & 0x02) strcat(flags,"<PERMANENT> ");
-
- if (master && !*master && type == 0x1d) {
- StrnCpy(master,qname,15);
- trim_string(master,NULL," ");
- }
+ if (p && match_mailslot_name(p, mailslot_name)) {
+ return p;
+ }
+ if (p) free_packet(p);
- if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) {
- StrnCpy(rname,qname,15);
- trim_string(rname,NULL," ");
- }
-
- DEBUG(level,("\t%s (type=0x%x)\t%s\n",qname,type,flags));
- p+=2;
- }
- DEBUG(level,("num_good_sends=%d num_good_receives=%d\n",
- IVAL(p,20),IVAL(p,24)));
+ /* try the unexpected packet queue */
+ return receive_unexpected(DGRAM_PACKET, 0, mailslot_name);
}
/****************************************************************************
- do a netbios name status query on a host
-
- the "master" parameter is a hack used for finding workgroups.
- **************************************************************************/
-BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
- struct in_addr to_ip,char *master,char *rname,
- void (*fn)())
-{
- BOOL found=False;
- int retries = 2;
- int retry_time = 5000;
- struct timeval tval;
- struct packet_struct p;
- struct packet_struct *p2;
- struct nmb_packet *nmb = &p.packet.nmb;
-
- bzero((char *)&p,sizeof(p));
-
- if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) +
- (getpid()%(unsigned)100);
- name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
-
- nmb->header.name_trn_id = name_trn_id;
- nmb->header.opcode = 0;
- nmb->header.response = False;
- nmb->header.nm_flags.bcast = False;
- nmb->header.nm_flags.recursion_available = CanRecurse;
- 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,scope);
-
- 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(False);
+ see if a datagram has the right mailslot name
+***************************************************************************/
+BOOL match_mailslot_name(struct packet_struct *p, char *mailslot_name)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ char *buf;
- retries--;
+ buf = &dgram->data[0];
+ buf -= 4;
- while (1)
- {
- struct timeval tval2;
- GetTimeOfDay(&tval2);
- if (TvalDiff(&tval,&tval2) > retry_time) {
- if (!retries) break;
- if (!found && !send_packet(&p))
- return False;
- GetTimeOfDay(&tval);
- retries--;
- }
+ buf = smb_buf(buf);
- if ((p2=receive_packet(fd,NMB_PACKET,90)))
- {
- struct nmb_packet *nmb2 = &p2->packet.nmb;
- if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
- !nmb2->header.response) {
- /* its not for us - maybe deal with it later */
- if (fn)
- fn(p2);
- else
- free_packet(p2);
- continue;
- }
-
- 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;
- }
-
- interpret_node_status(&nmb2->answers->rdata[0], master,rname);
- free_packet(p2);
- return(True);
+ if (memcmp(buf, mailslot_name, strlen(mailslot_name)+1) == 0) {
+ return True;
}
- }
-
- DEBUG(0,("No status response (this is not unusual)\n"));
+ return False;
+}
+
+
+/****************************************************************************
+return the number of bits that match between two 4 character buffers
+ ***************************************************************************/
+static int matching_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_bits(p2+2, sort_ip) - matching_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);
- return(False);
+ 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;
}
/****************************************************************************
- do a netbios name query to find someones IP
- ****************************************************************************/
-BOOL name_query(int fd,char *name,int name_type,
- BOOL bcast,BOOL recurse,
- struct in_addr to_ip, struct in_addr *ip,void (*fn)())
-{
- BOOL found=False;
- int 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;
-
- bzero((char *)&p,sizeof(p));
-
- if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) +
- (getpid()%(unsigned)100);
- name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
-
- nmb->header.name_trn_id = name_trn_id;
- nmb->header.opcode = 0;
- nmb->header.response = False;
- nmb->header.nm_flags.bcast = bcast;
- nmb->header.nm_flags.recursion_available = CanRecurse;
- 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,scope);
-
- 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(False);
+interpret the weird netbios "name". Return the name type
+****************************************************************************/
+static int name_interpret(char *in,char *out)
+{
+ int ret;
+ int len = (*in++) / 2;
- retries--;
+ *out=0;
- while (1)
+ if (len > 30 || len<1) return(0);
+
+ while (len--)
{
- struct timeval tval2;
- GetTimeOfDay(&tval2);
- if (TvalDiff(&tval,&tval2) > retry_time) {
- if (!retries) break;
- if (!found && !send_packet(&p))
- return False;
- GetTimeOfDay(&tval);
- retries--;
+ if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') {
+ *out = 0;
+ return(0);
}
-
- if ((p2=receive_packet(fd,NMB_PACKET,90)))
- {
- struct nmb_packet *nmb2 = &p2->packet.nmb;
- if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
- !nmb2->header.response) {
- /* its not for us - maybe deal with it later
- (put it on the queue?) */
- if (fn)
- fn(p2);
- else
- free_packet(p2);
- continue;
- }
-
- 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;
- }
-
- if (ip) {
- putip((char *)ip,&nmb2->answers->rdata[2]);
- DEBUG(fn?3:2,("Got a positive name query response from %s",
- inet_ntoa(p2->ip)));
- DEBUG(fn?3:2,(" (%s)\n",inet_ntoa(*ip)));
- }
- found=True; retries=0;
- free_packet(p2);
- if (fn) break;
- }
+ *out = ((in[0]-'A')<<4) + (in[1]-'A');
+ in += 2;
+ out++;
}
+ *out = 0;
+ ret = out[-1];
- return(found);
+#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);
}
-
/****************************************************************************
- construct and send a netbios DGRAM
-
- Note that this currently sends all answers to port 138. thats the
- wrong things to do! I should send to the requestors port. XXX
- **************************************************************************/
-BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,
- char *srcname,char *dstname,
- int src_type,int dest_type,
- struct in_addr dest_ip,
- struct in_addr src_ip)
-{
- struct packet_struct p;
- struct dgram_packet *dgram = &p.packet.dgram;
- char *ptr,*p2;
- char tmp[4];
-
- bzero((char *)&p,sizeof(p));
-
- dgram->header.msg_type = 0x11; /* DIRECT GROUP DATAGRAM */
- dgram->header.flags.node_type = M_NODE;
- dgram->header.flags.first = True;
- dgram->header.flags.more = False;
- dgram->header.dgm_id = name_trn_id++;
- dgram->header.source_ip = src_ip;
- dgram->header.source_port = DGRAM_PORT;
- dgram->header.dgm_length = 0; /* let build_dgram() handle this */
- dgram->header.packet_offset = 0;
-
- make_nmb_name(&dgram->source_name,srcname,src_type,scope);
- make_nmb_name(&dgram->dest_name,dstname,dest_type,scope);
+mangle a name into netbios format
- ptr = &dgram->data[0];
+ Note: <Out> must be (33 + strlen(scope) + 2) bytes long, at minimum.
+****************************************************************************/
+int name_mangle( char *In, char *Out, char name_type )
+ {
+ int i;
+ int c;
+ int len;
+ char buf[20];
+ char *p = Out;
+ extern pstring global_scope;
+
+ /* Safely copy the input string, In, into buf[]. */
+ (void)memset( buf, 0, 20 );
+ if (strcmp(In,"*") == 0)
+ buf[0] = '*';
+ else
+ (void)slprintf( buf, sizeof(buf) - 1, "%-15.15s%c", In, name_type );
- /* now 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);
+ /* Place the length of the first field into the output buffer. */
+ p[0] = 32;
+ p++;
- 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);
- strcpy(p2,mailslot);
- p2 = skip_string(p2,1);
+ /* Now convert the name to the rfc1001/1002 format. */
+ for( i = 0; i < 16; i++ )
+ {
+ c = toupper( buf[i] );
+ p[i*2] = ( (c >> 4) & 0x000F ) + 'A';
+ p[(i*2)+1] = (c & 0x000F) + 'A';
+ }
+ p += 32;
+ p[0] = '\0';
- memcpy(p2,buf,len);
- p2 += len;
+ /* Add the scope string. */
+ for( i = 0, len = 0; NULL != global_scope; i++, len++ )
+ {
+ switch( global_scope[i] )
+ {
+ case '\0':
+ p[0] = len;
+ if( len > 0 )
+ p[len+1] = 0;
+ return( name_len(Out) );
+ case '.':
+ p[0] = len;
+ p += (len + 1);
+ len = -1;
+ break;
+ default:
+ p[len+1] = global_scope[i];
+ break;
+ }
+ }
- dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length */
+ return( name_len(Out) );
+ } /* name_mangle */
- p.ip = dest_ip;
- p.port = DGRAM_PORT;
- p.fd = fd;
- p.timestamp = time(NULL);
- p.packet_type = DGRAM_PACKET;
- return(send_packet(&p));
-}
+/****************************************************************************
+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/source3/libsmb/nterr.c b/source3/libsmb/nterr.c
new file mode 100644
index 0000000000..b74dde9b14
--- /dev/null
+++ b/source3/libsmb/nterr.c
@@ -0,0 +1,596 @@
+/*
+ * 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 const struct
+{
+ char *nt_errstr;
+ NTSTATUS nt_errcode;
+} nt_err_code_struct;
+
+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 },
+ { NULL, NT_STATUS(0) }
+};
+
+/*****************************************************************************
+ returns an NT error message. not amazingly helpful, but better than a number.
+ *****************************************************************************/
+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;
+}
+
+/*****************************************************************************
+ returns an NT_STATUS constant as a string for inclusion in autogen C code
+ *****************************************************************************/
+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/source3/libsmb/passchange.c b/source3/libsmb/passchange.c
new file mode 100644
index 0000000000..b96bdc95a1
--- /dev/null
+++ b/source3/libsmb/passchange.c
@@ -0,0 +1,101 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB client password change routine
+ 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"
+
+
+extern pstring global_myname;
+
+/*************************************************************
+change a password on a remote machine using IPC calls
+*************************************************************/
+BOOL remote_password_change(const char *remote_machine, const char *user_name,
+ const char *old_passwd, const char *new_passwd,
+ char *err_str, size_t err_str_len)
+{
+ struct nmb_name calling, called;
+ struct cli_state cli;
+ struct in_addr ip;
+
+ *err_str = '\0';
+
+ if(!resolve_name( remote_machine, &ip, 0x20)) {
+ slprintf(err_str, err_str_len-1, "unable to find an IP address for machine %s.\n",
+ remote_machine );
+ return False;
+ }
+
+ ZERO_STRUCT(cli);
+
+ if (!cli_initialise(&cli) || !cli_connect(&cli, remote_machine, &ip)) {
+ slprintf(err_str, err_str_len-1, "unable to connect to SMB server on machine %s. Error was : %s.\n",
+ remote_machine, cli_errstr(&cli) );
+ return False;
+ }
+
+ make_nmb_name(&calling, global_myname , 0x0);
+ make_nmb_name(&called , remote_machine, 0x20);
+
+ if (!cli_session_request(&cli, &calling, &called)) {
+ slprintf(err_str, err_str_len-1, "machine %s rejected the session setup. Error was : %s.\n",
+ remote_machine, cli_errstr(&cli) );
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ cli.protocol = PROTOCOL_NT1;
+
+ if (!cli_negprot(&cli)) {
+ slprintf(err_str, err_str_len-1, "machine %s rejected the negotiate protocol. Error was : %s.\n",
+ remote_machine, cli_errstr(&cli) );
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ /*
+ * We should connect as the anonymous user here, in case
+ * the server has "must change password" checked...
+ * Thanks to <Nicholas.S.Jenkins@cdc.com> for this fix.
+ */
+
+ if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) {
+ slprintf(err_str, err_str_len-1, "machine %s rejected the session setup. Error was : %s.\n",
+ remote_machine, cli_errstr(&cli) );
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
+ slprintf(err_str, err_str_len-1, "machine %s rejected the tconX on the IPC$ share. Error was : %s.\n",
+ remote_machine, cli_errstr(&cli) );
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ if(!cli_oem_change_password(&cli, user_name, new_passwd, old_passwd)) {
+ slprintf(err_str, err_str_len-1, "machine %s rejected the password change: Error was : %s.\n",
+ remote_machine, cli_errstr(&cli) );
+ cli_shutdown(&cli);
+ return False;
+ }
+
+ cli_shutdown(&cli);
+ return True;
+}
diff --git a/source3/libsmb/pwd_cache.c b/source3/libsmb/pwd_cache.c
new file mode 100644
index 0000000000..7d1185d9a7
--- /dev/null
+++ b/source3/libsmb/pwd_cache.c
@@ -0,0 +1,249 @@
+/*
+ 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.
+****************************************************************************/
+
+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;
+}
+
+/****************************************************************************
+ Returns NULL password flag.
+****************************************************************************/
+
+BOOL pwd_is_nullpwd(const struct pwd_info *pwd)
+{
+ return pwd->null_pwd;
+}
+
+/****************************************************************************
+ Compares two passwords. hmm, not as trivial as expected. hmm.
+****************************************************************************/
+
+BOOL pwd_compare(const struct pwd_info *pwd1, const struct pwd_info *pwd2)
+{
+ if (pwd1->cleartext && pwd2->cleartext) {
+ if (strequal(pwd1->password, pwd2->password))
+ return True;
+ }
+ if (pwd1->null_pwd && pwd2->null_pwd)
+ return True;
+
+ if (!pwd1->null_pwd && !pwd2->null_pwd &&
+ !pwd1->cleartext && !pwd2->cleartext) {
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("pwd compare: nt#\n"));
+ dump_data(100, pwd1->smb_nt_pwd, 16);
+ dump_data(100, pwd2->smb_nt_pwd, 16);
+#endif
+ if (memcmp(pwd1->smb_nt_pwd, pwd2->smb_nt_pwd, 16) == 0)
+ return True;
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("pwd compare: lm#\n"));
+ dump_data(100, pwd1->smb_lm_pwd, 16);
+ dump_data(100, pwd2->smb_lm_pwd, 16);
+#endif
+ if (memcmp(pwd1->smb_lm_pwd, pwd2->smb_lm_pwd, 16) == 0)
+ return True;
+ }
+ return False;
+}
+
+/****************************************************************************
+ Reads a password.
+****************************************************************************/
+
+void pwd_read(struct pwd_info *pwd, char *passwd_report, BOOL do_encrypt)
+{
+ /* grab a password */
+ char *user_pass;
+
+ pwd_init(pwd);
+
+ user_pass = (char*)getpass(passwd_report);
+
+ /*
+ * Do not assume that an empty string is a NULL password.
+ * If you do this will break the session key generation for
+ * and account with an emtpy password. If you wish to use
+ * a NULL password, use the -N option to smbclient and rpcclient
+ * --jerry
+ */
+#if 0
+ if (user_pass == NULL || user_pass[0] == 0)
+ pwd_set_nullpwd(pwd);
+ else if (do_encrypt)
+#endif
+ if (do_encrypt)
+ pwd_make_lm_nt_16(pwd, user_pass);
+ else
+ pwd_set_cleartext(pwd, user_pass);
+}
+
+/****************************************************************************
+ Stores a cleartext password.
+****************************************************************************/
+
+void pwd_set_nullpwd(struct pwd_info *pwd)
+{
+ pwd_init(pwd);
+
+ pwd->cleartext = False;
+ pwd->null_pwd = True;
+ pwd->crypted = False;
+}
+
+/****************************************************************************
+ Stores a cleartext password.
+****************************************************************************/
+
+void pwd_set_cleartext(struct pwd_info *pwd, 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);
+}
+
+/****************************************************************************
+ Gets a cleartext password.
+****************************************************************************/
+
+void pwd_get_cleartext(struct pwd_info *pwd, char *clr)
+{
+ if (pwd->cleartext)
+ fstrcpy(clr, pwd->password);
+ else
+ clr[0] = 0;
+
+}
+
+/****************************************************************************
+ Stores lm and nt hashed passwords.
+****************************************************************************/
+
+void pwd_set_lm_nt_16(struct pwd_info *pwd, uchar lm_pwd[16], uchar nt_pwd[16])
+{
+ pwd_init(pwd);
+
+ if (lm_pwd)
+ memcpy(pwd->smb_lm_pwd, lm_pwd, 16);
+ else
+ memset((char *)pwd->smb_lm_pwd, '\0', 16);
+
+ if (nt_pwd)
+ memcpy(pwd->smb_nt_pwd, nt_pwd, 16);
+ else
+ memset((char *)pwd->smb_nt_pwd, '\0', 16);
+
+ pwd->null_pwd = False;
+ pwd->cleartext = False;
+ pwd->crypted = False;
+}
+
+/****************************************************************************
+ Gets lm and nt hashed passwords.
+****************************************************************************/
+
+void pwd_get_lm_nt_16(struct pwd_info *pwd, uchar lm_pwd[16], uchar nt_pwd[16])
+{
+ if (lm_pwd != NULL)
+ memcpy(lm_pwd, pwd->smb_lm_pwd, 16);
+ if (nt_pwd != NULL)
+ memcpy(nt_pwd, pwd->smb_nt_pwd, 16);
+}
+
+/****************************************************************************
+ Makes lm and nt hashed passwords.
+****************************************************************************/
+
+void pwd_make_lm_nt_16(struct pwd_info *pwd, 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;
+}
+
+/****************************************************************************
+ Makes lm and nt OWF crypts.
+****************************************************************************/
+
+void pwd_make_lm_nt_owf(struct pwd_info *pwd, uchar cryptkey[8])
+{
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("client cryptkey: "));
+ dump_data(100, (char *)cryptkey, 8);
+#endif
+
+ SMBOWFencrypt(pwd->smb_nt_pwd, cryptkey, pwd->smb_nt_owf);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("nt_owf_passwd: "));
+ dump_data(100, (char *)pwd->smb_nt_owf, sizeof(pwd->smb_nt_owf));
+ DEBUG(100,("nt_sess_pwd: "));
+ dump_data(100, (char *)pwd->smb_nt_pwd, sizeof(pwd->smb_nt_pwd));
+#endif
+
+ SMBOWFencrypt(pwd->smb_lm_pwd, cryptkey, pwd->smb_lm_owf);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("lm_owf_passwd: "));
+ dump_data(100, (char *)pwd->smb_lm_owf, sizeof(pwd->smb_lm_owf));
+ DEBUG(100,("lm_sess_pwd: "));
+ dump_data(100, (char *)pwd->smb_lm_pwd, sizeof(pwd->smb_lm_pwd));
+#endif
+
+ pwd->crypted = True;
+}
+
+/****************************************************************************
+ Gets lm and nt crypts.
+****************************************************************************/
+
+void pwd_get_lm_nt_owf(struct pwd_info *pwd, uchar lm_owf[24], uchar nt_owf[24])
+{
+ if (lm_owf != NULL)
+ memcpy(lm_owf, pwd->smb_lm_owf, 24);
+ if (nt_owf != NULL)
+ memcpy(nt_owf, pwd->smb_nt_owf, 24);
+}
diff --git a/source3/libsmb/smbdes.c b/source3/libsmb/smbdes.c
new file mode 100644
index 0000000000..cde77f94a3
--- /dev/null
+++ b/source3/libsmb/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/source3/libsmb/smbencrypt.c b/source3/libsmb/smbencrypt.c
index a0683b5d28..6fa8de418a 100644
--- a/source3/libsmb/smbencrypt.c
+++ b/source3/libsmb/smbencrypt.c
@@ -1,10 +1,10 @@
-#ifdef SMB_PASSWD
/*
- Unix SMB/Netbios implementation.
- Version 1.9.
+ Unix SMB/CIFS implementation.
SMB parameters and setup
- Copyright (C) Andrew Tridgell 1992-1995
+ 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.
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
@@ -22,181 +22,322 @@
*/
#include "includes.h"
-#include "loadparm.h"
-#include "des.h"
-#include "md4.h"
-
-extern int DEBUGLEVEL;
-
-#ifndef uchar
-#define uchar unsigned char
-#endif
-#ifndef int16
-#define int16 unsigned short
-#endif
-#ifndef uint16
-#define uint16 unsigned short
-#endif
-#ifndef uint32
-#define uint32 unsigned int
-#endif
-
#include "byteorder.h"
-void str_to_key(uchar *str,uchar *key)
+/*
+ This implements the X/Open SMB password encryption
+ It takes a password, a 8 byte "crypt key" and puts 24 bytes of
+ encrypted password into p24 */
+void SMBencrypt(const uchar *passwd, const uchar *c8, uchar *p24)
{
- void des_set_odd_parity(des_cblock *);
- 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);
- }
- des_set_odd_parity((des_cblock *)key);
-}
+ uchar p14[15], p21[21];
-void D1(uchar *k, uchar *d, uchar *out)
-{
- des_key_schedule ks;
- des_cblock deskey;
+ memset(p21,'\0',21);
+ memset(p14,'\0',14);
+ StrnCpy((char *)p14,(const char *)passwd,14);
- str_to_key(k,(uchar *)deskey);
- des_set_key(deskey,ks);
- des_ecb_encrypt(d, out, ks, DES_DECRYPT);
-}
+ strupper((char *)p14);
+ E_P16(p14, p21);
-void E1(uchar *k, uchar *d, uchar *out)
-{
- des_key_schedule ks;
- des_cblock deskey;
+ SMBOWFencrypt(p21, c8, p24);
- str_to_key(k,(uchar *)deskey);
- des_set_key(deskey,ks);
- des_ecb_encrypt(d, out, ks, DES_ENCRYPT);
+#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.
+ */
-void E_P16(uchar *p14,uchar *p16)
+void E_md4hash(const uchar *passwd, uchar *p16)
{
- uchar sp7[7];
- /* the following constant makes us compatible with other
- implementations. Note that publishing this constant does not reduce the
- security of the encryption mechanism */
- uchar sp8[] = {0xAA,0xD3,0xB4,0x35,0xB5,0x14,0x4,0xEE};
- uchar x[8];
-
- memset(sp7,'\0',7);
-
- D1(sp7, sp8, x);
- E1(p14, x, p16);
- E1(p14+7, x, p16+8);
+ int len;
+ smb_ucs2_t wpwd[129];
+
+ /* Password cannot be longer than 128 characters */
+ len = strlen((const char *)passwd);
+ if(len > 128)
+ len = 128;
+ /* 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);
}
-void E_P24(uchar *p21, uchar *c8, uchar *p24)
+/* 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])
{
- E1(p21, c8, p24);
- E1(p21+7, c8, p24+8);
- E1(p21+14, c8, p24+16);
-}
+ char passwd[514];
+ memset(passwd,'\0',514);
+ safe_strcpy( passwd, pwd, sizeof(passwd)-1);
-/*
- This implements the X/Open SMB password encryption
- It takes a password, a 8 byte "crypt key" and puts 24 bytes of
- encrypted password into p24 */
-void SMBencrypt(uchar *passwd, uchar *c8, uchar *p24)
-{
- uchar p14[15], p21[21];
+ /* Calculate the MD4 hash (NT compatible) of the password */
+ memset(nt_p16, '\0', 16);
+ E_md4hash((uchar *)passwd, nt_p16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("nt_lm_owf_gen: pwd, nt#\n"));
+ dump_data(120, passwd, strlen(passwd));
+ dump_data(100, (char *)nt_p16, 16);
+#endif
- memset(p21,'\0',21);
- memset(p14,'\0',14);
- StrnCpy((char *)p14,(char *)passwd,14);
+ /* Mangle the passwords into Lanman format */
+ passwd[14] = '\0';
+ strupper(passwd);
- strupper((char *)p14);
- E_P16(p14, p21);
- E_P24(p21, c8, p24);
+ /* Calculate the SMB (lanman) hash functions of the password */
+
+ memset(p16, '\0', 16);
+ E_P16((uchar *) passwd, (uchar *)p16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("nt_lm_owf_gen: pwd, lm#\n"));
+ dump_data(120, passwd, strlen(passwd));
+ dump_data(100, (char *)p16, 16);
+#endif
+ /* clear out local copy of user's password (just being paranoid). */
+ memset(passwd, '\0', sizeof(passwd));
}
-/* Routines for Windows NT MD4 Hash functions. */
-static int _my_wcslen(int16 *str)
+/* Does both the NTLMv2 owfs of a user's password */
+void ntv2_owf_gen(const uchar owf[16],
+ const char *user_n, const char *domain_n, uchar kr_buf[16])
{
- int len = 0;
- while(*str++ != 0)
- len++;
- return len;
+ pstring user_u;
+ pstring dom_u;
+ HMACMD5Context ctx;
+
+ int user_l = strlen(user_n);
+ int domain_l = strlen(domain_n);
+
+ push_ucs2(NULL, user_u, user_n, (user_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER);
+ push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER);
+
+ hmac_md5_init_limK_to_64(owf, 16, &ctx);
+ hmac_md5_update((const unsigned char *)user_u, user_l * 2, &ctx);
+ hmac_md5_update((const unsigned char *)dom_u, domain_l * 2, &ctx);
+ hmac_md5_final(kr_buf, &ctx);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("ntv2_owf_gen: user, domain, owfkey, kr\n"));
+ dump_data(100, user_u, user_l * 2);
+ dump_data(100, dom_u, domain_l * 2);
+ dump_data(100, owf, 16);
+ dump_data(100, kr_buf, 16);
+#endif
}
-/*
- * Convert a string into an NT UNICODE string.
- * Note that regardless of processor type
- * this must be in intel (little-endian)
- * format.
- */
-
-static int _my_mbstowcs(int16 *dst, uchar *src, int len)
+/* Does the des encryption from the NT or LM MD4 hash. */
+void SMBOWFencrypt(const uchar passwd[16], const uchar *c8, uchar p24[24])
{
- int i;
- int16 val;
+ uchar p21[21];
- for(i = 0; i < len; i++) {
- val = *src;
- SSVAL(dst,0,val);
- dst++;
- src++;
- if(val == 0)
- break;
- }
- return i;
+ memset(p21,'\0',21);
+
+ memcpy(p21, passwd, 16);
+ E_P24(p21, c8, p24);
}
-/*
- * Creates the MD4 Hash of the users password in NT UNICODE.
- */
-
-void E_md4hash(uchar *passwd, uchar *p16)
+/* 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])
{
- int i, len;
- int16 wpwd[129];
- MDstruct MD;
-
- /* Password cannot be longer than 128 characters */
- len = strlen(passwd);
- if(len > 128)
- len = 128;
- /* Password must be converted to NT unicode */
- _my_mbstowcs( wpwd, passwd, len);
- wpwd[len] = 0; /* Ensure string is null terminated */
- /* Calculate length in bytes */
- len = _my_wcslen(wpwd) * sizeof(int16);
+ uchar p21[21];
- MDbegin(&MD);
- for(i = 0; i + 64 <= len; i += 64)
- MDupdate(&MD,wpwd + (i/2), 512);
- MDupdate(&MD,wpwd + (i/2),(len-i)*8);
- SIVAL(p16,0,MD.buffer[0]);
- SIVAL(p16,4,MD.buffer[1]);
- SIVAL(p16,8,MD.buffer[2]);
- SIVAL(p16,12,MD.buffer[3]);
+ 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(uchar *passwd, uchar *c8, uchar *p24)
+void SMBNTencrypt(const uchar *passwd, uchar *c8, uchar *p24)
{
uchar p21[21];
memset(p21,'\0',21);
E_md4hash(passwd, p21);
- E_P24(p21, c8, p24);
+ 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,
+ char 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((unsigned char *)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
}
-#else
-void smbencrypt_dummy(void){}
+/***********************************************************
+ 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;
+
+}
+
+/* Calculate the NT owfs of a user's password */
+void nt_owf_genW(const UNISTR2 *pwd, uchar nt_p16[16])
+{
+ char buf[512];
+ int i;
+
+ for (i = 0; i < MIN(pwd->uni_str_len, sizeof(buf) / 2); i++)
+ {
+ SIVAL(buf, i * 2, pwd->buffer[i]);
+ }
+ /* Calculate the MD4 hash (NT compatible) of the password */
+ mdfour(nt_p16, (const unsigned char *)buf, pwd->uni_str_len * 2);
+
+ /* clear out local copy of user's password (just being paranoid). */
+ ZERO_STRUCT(buf);
+}
diff --git a/source3/libsmb/smberr.c b/source3/libsmb/smberr.c
new file mode 100644
index 0000000000..84b3f507e6
--- /dev/null
+++ b/source3/libsmb/smberr.c
@@ -0,0 +1,255 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+/* error code stuff - put together by Merik Karman
+ merik@blackadder.dsh.oz.au */
+
+
+/* There is a big list of error codes and their meanings at:
+
+ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/errlist_7oz7.asp
+
+ and if you don't like MSDN try:
+
+ http://www.siris.gr/computers/library/error.htm
+
+*/
+
+typedef const struct
+{
+ char *name;
+ int code;
+ char *message;
+} err_code_struct;
+
+/* Dos Error Messages */
+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"},
+ {NULL,-1,NULL}};
+
+/* Server Error Messages */
+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 */
+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}};
+
+
+const struct
+{
+ int code;
+ char *class;
+ 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 SMB error name from a class and code
+****************************************************************************/
+char *smb_dos_err_name(uint8 class, uint16 num)
+{
+ static pstring ret;
+ int i,j;
+
+ for (i=0;err_classes[i].class;i++)
+ if (err_classes[i].code == class) {
+ if (err_classes[i].err_msgs) {
+ err_code_struct *err = err_classes[i].err_msgs;
+ for (j=0;err[j].name;j++)
+ if (num == err[j].code) {
+ return err[j].name;
+ }
+ }
+ slprintf(ret, sizeof(ret) - 1, "%d",num);
+ return ret;
+ }
+
+ slprintf(ret, sizeof(ret) - 1, "Error: Unknown error class (%d,%d)",class,num);
+ return(ret);
+}
+
+/* Return a string for a DOS error */
+
+char *get_dos_error_msg(WERROR result)
+{
+ uint16 errnum;
+
+ errnum = W_ERROR_V(result);
+
+ return smb_dos_err_name(ERRDOS, errnum);
+}
+
+/****************************************************************************
+return a SMB error class name as a string.
+****************************************************************************/
+char *smb_dos_err_class(uint8 class)
+{
+ static pstring ret;
+ int i;
+
+ for (i=0;err_classes[i].class;i++) {
+ if (err_classes[i].code == class) {
+ return err_classes[i].class;
+ }
+ }
+
+ slprintf(ret, sizeof(ret) - 1, "Error: Unknown class (%d)",class);
+ return(ret);
+}
+
+/****************************************************************************
+return a SMB string from an SMB buffer
+****************************************************************************/
+char *smb_dos_errstr(char *inbuf)
+{
+ static pstring ret;
+ int class = CVAL(inbuf,smb_rcls);
+ int num = SVAL(inbuf,smb_err);
+ int i,j;
+
+ for (i=0;err_classes[i].class;i++)
+ if (err_classes[i].code == class) {
+ if (err_classes[i].err_msgs) {
+ err_code_struct *err = err_classes[i].err_msgs;
+ for (j=0;err[j].name;j++)
+ if (num == err[j].code) {
+ if (DEBUGLEVEL > 0)
+ slprintf(ret, sizeof(ret) - 1, "%s - %s (%s)",
+ err_classes[i].class,
+ err[j].name,err[j].message);
+ else
+ slprintf(ret, sizeof(ret) - 1, "%s - %s",
+ err_classes[i].class,err[j].name);
+ return ret;
+ }
+ }
+
+ slprintf(ret, sizeof(ret) - 1, "%s - %d",err_classes[i].class,num);
+ return ret;
+ }
+
+ slprintf(ret, sizeof(ret) - 1, "Error: Unknown error (%d,%d)",class,num);
+ return(ret);
+}
+
+/*****************************************************************************
+map a unix errno to a win32 error
+ *****************************************************************************/
+WERROR map_werror_from_unix(int error)
+{
+ NTSTATUS status = map_nt_error_from_unix(error);
+ return ntstatus_to_werror(status);
+}
diff --git a/source3/libsmb/trust_passwd.c b/source3/libsmb/trust_passwd.c
new file mode 100644
index 0000000000..51ffa1dd95
--- /dev/null
+++ b/source3/libsmb/trust_passwd.c
@@ -0,0 +1,115 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Routines to change trust account passwords.
+ * Copyright (C) Andrew Bartlett 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"
+
+extern pstring global_myname;
+
+/*********************************************************
+ Change the domain password on the PDC.
+
+ Just changes the password betwen the two values specified.
+
+ Caller must have the cli connected to the netlogon pipe
+ already.
+**********************************************************/
+static NTSTATUS just_change_the_password(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ unsigned char orig_trust_passwd_hash[16],
+ unsigned char new_trust_passwd_hash[16])
+{
+ NTSTATUS result;
+ result = new_cli_nt_setup_creds(cli, (lp_server_role() == ROLE_DOMAIN_MEMBER) ?
+ SEC_CHAN_WKSTA : SEC_CHAN_BDC, orig_trust_passwd_hash);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0,("just_change_the_password: unable to setup creds (%s)!\n",
+ nt_errstr(result)));
+ return result;
+ }
+
+ result = cli_net_srv_pwset(cli, mem_ctx, global_myname, new_trust_passwd_hash);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0,("just_change_the_password: unable to change password (%s)!\n",
+ nt_errstr(result)));
+ }
+ return result;
+}
+
+/*********************************************************
+ Change the domain password on the PDC.
+ Store the password ourselves, but use the supplied password
+ Caller must have already setup the connection to the NETLOGON pipe
+**********************************************************/
+
+NTSTATUS trust_pw_change_and_store_it(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+ unsigned char orig_trust_passwd_hash[16])
+{
+ unsigned char new_trust_passwd_hash[16];
+ char *new_trust_passwd;
+ char *str;
+ NTSTATUS nt_status;
+
+ /* Create a random machine account password */
+ str = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
+ new_trust_passwd = talloc_strdup(mem_ctx, str);
+
+ E_md4hash((uchar *)new_trust_passwd, new_trust_passwd_hash);
+
+ nt_status = just_change_the_password(cli, mem_ctx, orig_trust_passwd_hash,
+ new_trust_passwd_hash);
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(3,("%s : change_trust_account_password: Changed password.\n", timestring(False)));
+ /*
+ * Return the result of trying to write the new password
+ * back into the trust account file.
+ */
+ if (!secrets_store_machine_password(new_trust_passwd)) {
+ nt_status = NT_STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ return nt_status;
+}
+
+/*********************************************************
+ Change the domain password on the PDC.
+ Do most of the legwork ourselfs. Caller must have
+ already setup the connection to the NETLOGON pipe
+**********************************************************/
+
+NTSTATUS trust_pw_find_change_and_store_it(struct cli_state *cli, TALLOC_CTX *mem_ctx, char *domain)
+{
+ unsigned char old_trust_passwd_hash[16];
+ char *up_domain;
+
+ up_domain = talloc_strdup(mem_ctx, domain);
+
+ if (!secrets_fetch_trust_account_password(domain,
+ old_trust_passwd_hash,
+ NULL)) {
+ DEBUG(0, ("could not fetch domain secrets for domain %s!\n", domain));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return trust_pw_change_and_store_it(cli, mem_ctx, old_trust_passwd_hash);
+
+}
diff --git a/source3/libsmb/unexpected.c b/source3/libsmb/unexpected.c
new file mode 100644
index 0000000000..f74a05f75f
--- /dev/null
+++ b/source3/libsmb/unexpected.c
@@ -0,0 +1,164 @@
+/*
+ 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;
+
+ if (!tdbd) {
+ tdbd = tdb_open_log(lock_path("unexpected.tdb"), 1,
+ TDB_CLEAR_IF_FIRST|TDB_DEFAULT,
+ O_RDWR | O_CREAT, 0644);
+ 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 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,
+ char *mailslot_name)
+{
+ TDB_CONTEXT *tdb2;
+
+ tdb2 = tdb_open_log(lock_path("unexpected.tdb"), 0, 0, O_RDONLY, 0);
+ 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;
+}