summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2003-02-15 00:10:09 +0000
committerAndrew Bartlett <abartlet@samba.org>2003-02-15 00:10:09 +0000
commit3b2693f1ae3b1e06d3015843d2933177fcb97a87 (patch)
treeceaa38b6667ecffc5500c349ab0e6d8315e10a8d /source3
parenta2781ba60d219c61f983d6feba40b0efcbcb96cf (diff)
downloadsamba-3b2693f1ae3b1e06d3015843d2933177fcb97a87.tar.gz
samba-3b2693f1ae3b1e06d3015843d2933177fcb97a87.tar.bz2
samba-3b2693f1ae3b1e06d3015843d2933177fcb97a87.zip
Move our NTLMSSP code into easily seperated peices, not relying on the whole
of libsmb. Andrew Bartlett (This used to be commit b5ec7efa80478187124c1cfa8c7fcc4036506a37)
Diffstat (limited to 'source3')
-rw-r--r--source3/Makefile.in12
-rw-r--r--source3/libsmb/clispnego.c322
-rw-r--r--source3/libsmb/ntlmssp.c43
-rw-r--r--source3/libsmb/ntlmssp_parse.c303
4 files changed, 353 insertions, 327 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in
index f744e39194..b4559e2b4e 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -186,18 +186,22 @@ LIBADS_SERVER_OBJ = libads/util.o libads/kerberos_verify.o
SECRETS_OBJ = passdb/secrets.o
+LIBNTLMSSP_OBJ = libsmb/ntlmssp.o libsmb/ntlmssp_parse.o
+
+LIBSAMBA_OBJ = libsmb/nterr.o
+
LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \
libsmb/clikrb5.o libsmb/clispnego.o libsmb/asn1.o \
libsmb/clirap.o libsmb/clierror.o libsmb/climessage.o \
libsmb/clireadwrite.o libsmb/clilist.o libsmb/cliprint.o \
libsmb/clitrans.o libsmb/clisecdesc.o libsmb/clidgram.o \
libsmb/namequery.o libsmb/nmblib.o libsmb/clistr.o \
- libsmb/nterr.o libsmb/smbdes.o libsmb/smbencrypt.o \
+ libsmb/smbdes.o libsmb/smbencrypt.o \
libsmb/smberr.o libsmb/credentials.o libsmb/pwd_cache.o \
libsmb/clioplock.o libsmb/errormap.o libsmb/clirap2.o \
libsmb/passchange.o libsmb/unexpected.o libsmb/doserr.o \
- libsmb/namecache.o libsmb/trustdom_cache.o libsmb/ntlmssp.o \
- $(RPC_PARSE_OBJ1)
+ libsmb/namecache.o libsmb/trustdom_cache.o \
+ $(RPC_PARSE_OBJ1) $(LIBNTLMSSP_OBJ) $(LIBSAMBA_OBJ)
LIBMSRPC_OBJ = rpc_client/cli_lsarpc.o rpc_client/cli_samr.o \
rpc_client/cli_netlogon.o rpc_client/cli_srvsvc.o \
@@ -594,7 +598,7 @@ POPT_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
TDBBACKUP_OBJ = tdb/tdbbackup.o $(TDBBASE_OBJ)
-NTLM_AUTH_OBJ = utils/ntlm_auth.o $(LIBSMB_OBJ) $(POPT_LIB_OBJ)
+NTLM_AUTH_OBJ = utils/ntlm_auth.o $(LIBNTLMSSP_OBJ) $(LIBSAMBA_OBJ) $(POPT_LIB_OBJ)
######################################################################
# now the rules...
diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c
index 54069fc637..91748c4c7a 100644
--- a/source3/libsmb/clispnego.c
+++ b/source3/libsmb/clispnego.c
@@ -478,325 +478,3 @@ DATA_BLOB spnego_gen_auth_response(DATA_BLOB *ntlmssp_reply, NTSTATUS nt_status)
asn1_free(&data);
return ret;
}
-
-/*
- this is a tiny msrpc packet generator. I am only using this to
- avoid tying this code to a particular varient of our rpc code. This
- generator is not general enough for all our rpc needs, its just
- enough for the spnego/ntlmssp code
-
- format specifiers are:
-
- U = unicode string (input is unix string)
- a = address (input is BOOL unicode, char *unix_string)
- (1 byte type, 1 byte length, unicode/ASCII string, all inline)
- A = ASCII string (input is unix string)
- B = data blob (pointer + length)
- b = data blob in header (pointer + length)
- D
- d = word (4 bytes)
- C = constant ascii string
- */
-BOOL msrpc_gen(DATA_BLOB *blob,
- const char *format, ...)
-{
- int i, n;
- va_list ap;
- char *s;
- uint8 *b;
- int head_size=0, data_size=0;
- int head_ofs, data_ofs;
- BOOL unicode;
-
- /* first scan the format to work out the header and body size */
- va_start(ap, format);
- for (i=0; format[i]; i++) {
- switch (format[i]) {
- case 'U':
- s = va_arg(ap, char *);
- head_size += 8;
- data_size += str_charnum(s) * 2;
- break;
- case 'A':
- s = va_arg(ap, char *);
- head_size += 8;
- data_size += str_ascii_charnum(s);
- break;
- case 'a':
- unicode = va_arg(ap, BOOL);
- n = va_arg(ap, int);
- s = va_arg(ap, char *);
- if (unicode) {
- data_size += (str_charnum(s) * 2) + 4;
- } else {
- data_size += (str_ascii_charnum(s)) + 4;
- }
- break;
- case 'B':
- b = va_arg(ap, uint8 *);
- head_size += 8;
- data_size += va_arg(ap, int);
- break;
- case 'b':
- b = va_arg(ap, uint8 *);
- head_size += va_arg(ap, int);
- break;
- case 'd':
- n = va_arg(ap, int);
- head_size += 4;
- break;
- case 'C':
- s = va_arg(ap, char *);
- head_size += str_charnum(s) + 1;
- break;
- }
- }
- va_end(ap);
-
- /* allocate the space, then scan the format again to fill in the values */
- *blob = data_blob(NULL, head_size + data_size);
-
- head_ofs = 0;
- data_ofs = head_size;
-
- va_start(ap, format);
- for (i=0; format[i]; i++) {
- switch (format[i]) {
- case 'U':
- s = va_arg(ap, char *);
- n = str_charnum(s);
- SSVAL(blob->data, head_ofs, n*2); head_ofs += 2;
- SSVAL(blob->data, head_ofs, n*2); head_ofs += 2;
- SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
- push_string(NULL, blob->data+data_ofs, s, n*2, STR_UNICODE|STR_NOALIGN);
- data_ofs += n*2;
- break;
- case 'A':
- s = va_arg(ap, char *);
- n = str_ascii_charnum(s);
- SSVAL(blob->data, head_ofs, n); head_ofs += 2;
- SSVAL(blob->data, head_ofs, n); head_ofs += 2;
- SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
- push_string(NULL, blob->data+data_ofs, s, n, STR_ASCII|STR_NOALIGN);
- data_ofs += n;
- break;
- case 'a':
- unicode = va_arg(ap, BOOL);
- n = va_arg(ap, int);
- SSVAL(blob->data, data_ofs, n); data_ofs += 2;
- s = va_arg(ap, char *);
- if (unicode) {
- n = str_charnum(s);
- SSVAL(blob->data, data_ofs, n*2); data_ofs += 2;
- if (0 < n) {
- push_string(NULL, blob->data+data_ofs, s, n*2,
- STR_UNICODE|STR_NOALIGN);
- }
- data_ofs += n*2;
- } else {
- n = str_ascii_charnum(s);
- SSVAL(blob->data, data_ofs, n); data_ofs += 2;
- if (0 < n) {
- push_string(NULL, blob->data+data_ofs, s, n,
- STR_ASCII|STR_NOALIGN);
- }
- data_ofs += n;
- }
- break;
-
- case 'B':
- b = va_arg(ap, uint8 *);
- n = va_arg(ap, int);
- SSVAL(blob->data, head_ofs, n); head_ofs += 2;
- SSVAL(blob->data, head_ofs, n); head_ofs += 2;
- SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
- memcpy(blob->data+data_ofs, b, n);
- data_ofs += n;
- break;
- case 'd':
- n = va_arg(ap, int);
- SIVAL(blob->data, head_ofs, n); head_ofs += 4;
- break;
- case 'b':
- b = va_arg(ap, uint8 *);
- n = va_arg(ap, int);
- memcpy(blob->data + head_ofs, b, n);
- head_ofs += n;
- break;
- case 'C':
- s = va_arg(ap, char *);
- head_ofs += push_string(NULL, blob->data+head_ofs, s, -1,
- STR_ASCII|STR_TERMINATE);
- break;
- }
- }
- va_end(ap);
-
- return True;
-}
-
-
-/* a helpful macro to avoid running over the end of our blob */
-#define NEED_DATA(amount) \
-if (head_ofs + amount > blob->length) { \
- return False; \
-}
-
-/*
- this is a tiny msrpc packet parser. This the the partner of msrpc_gen
-
- format specifiers are:
-
- U = unicode string (output is unix string)
- A = ascii string
- B = data blob
- b = data blob in header
- d = word (4 bytes)
- C = constant ascii string
- */
-
-BOOL msrpc_parse(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':
- NEED_DATA(8);
- len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
- len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
- ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
-
- /* make sure its in the right format - be strict */
- if (len1 != len2 || ptr + len1 > blob->length) {
- return False;
- }
- if (len1 & 1) {
- /* if odd length and unicode */
- return False;
- }
-
- ps = va_arg(ap, char **);
- if (0 < len1) {
- pull_string(NULL, p, blob->data + ptr, sizeof(p),
- len1,
- STR_UNICODE|STR_NOALIGN);
- (*ps) = strdup(p);
- } else {
- (*ps) = NULL;
- }
- break;
- case 'A':
- NEED_DATA(8);
- len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
- len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
- ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
-
- /* make sure its in the right format - be strict */
- if (len1 != len2 || ptr + len1 > blob->length) {
- return False;
- }
-
- ps = va_arg(ap, char **);
- if (0 < len1) {
- pull_string(NULL, p, blob->data + ptr, sizeof(p),
- len1,
- STR_ASCII|STR_NOALIGN);
- (*ps) = strdup(p);
- } else {
- (*ps) = NULL;
- }
- break;
- case 'B':
- NEED_DATA(8);
- len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
- len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
- ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
- /* make sure its in the right format - be strict */
- if (len1 != len2 || ptr + len1 > blob->length) {
- return False;
- }
- b = (DATA_BLOB *)va_arg(ap, void *);
- *b = data_blob(blob->data + ptr, len1);
- break;
- case 'b':
- b = (DATA_BLOB *)va_arg(ap, void *);
- len1 = va_arg(ap, unsigned);
- /* make sure its in the right format - be strict */
- NEED_DATA(len1);
- *b = data_blob(blob->data + head_ofs, len1);
- head_ofs += len1;
- break;
- case 'd':
- v = va_arg(ap, uint32 *);
- NEED_DATA(4);
- *v = IVAL(blob->data, head_ofs); head_ofs += 4;
- break;
- case 'C':
- s = va_arg(ap, char *);
- head_ofs += pull_string(NULL, p, blob->data+head_ofs, sizeof(p),
- blob->length - head_ofs,
- STR_ASCII|STR_TERMINATE);
- if (strcmp(s, p) != 0) {
- return False;
- }
- break;
- }
- }
- va_end(ap);
-
- return True;
-}
-
-/**
- * Print out the NTLMSSP flags for debugging
- */
-
-void debug_ntlmssp_flags(uint32 neg_flags)
-{
- DEBUG(3,("Got NTLMSSP neg_flags=0x%08x\n", neg_flags));
-
- if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_UNICODE\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_OEM)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_OEM\n"));
- if (neg_flags & NTLMSSP_REQUEST_TARGET)
- DEBUGADD(4, (" NTLMSSP_REQUEST_TARGET\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_SIGN)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SIGN\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_SEAL)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SEAL\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_LM_KEY)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_LM_KEY\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_NETWARE)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NETWARE\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_NTLM)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_ALWAYS_SIGN\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_NTLM2)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM2\n"));
- if (neg_flags & NTLMSSP_CHAL_TARGET_INFO)
- DEBUGADD(4, (" NTLMSSP_CHAL_TARGET_INFO\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_128)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_128\n"));
- if (neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)
- DEBUGADD(4, (" NTLMSSP_NEGOTIATE_KEY_EXCH\n"));
-}
-
diff --git a/source3/libsmb/ntlmssp.c b/source3/libsmb/ntlmssp.c
index 48df7fc564..92a18d25c0 100644
--- a/source3/libsmb/ntlmssp.c
+++ b/source3/libsmb/ntlmssp.c
@@ -24,11 +24,52 @@
#include "includes.h"
/**
+ * Print out the NTLMSSP flags for debugging
+ */
+
+void debug_ntlmssp_flags(uint32 neg_flags)
+{
+ DEBUG(3,("Got NTLMSSP neg_flags=0x%08x\n", neg_flags));
+
+ if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_UNICODE\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_OEM)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_OEM\n"));
+ if (neg_flags & NTLMSSP_REQUEST_TARGET)
+ DEBUGADD(4, (" NTLMSSP_REQUEST_TARGET\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_SIGN)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SIGN\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_SEAL)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_SEAL\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_LM_KEY)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_LM_KEY\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_NETWARE)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NETWARE\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_NTLM)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_ALWAYS_SIGN\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_NTLM2)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_NTLM2\n"));
+ if (neg_flags & NTLMSSP_CHAL_TARGET_INFO)
+ DEBUGADD(4, (" NTLMSSP_CHAL_TARGET_INFO\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_128)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_128\n"));
+ if (neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)
+ DEBUGADD(4, (" NTLMSSP_NEGOTIATE_KEY_EXCH\n"));
+}
+
+/**
* Default challenge generation code.
*
*/
-
static const uint8 *get_challenge(struct ntlmssp_state *ntlmssp_state)
{
static uchar chal[8];
diff --git a/source3/libsmb/ntlmssp_parse.c b/source3/libsmb/ntlmssp_parse.c
new file mode 100644
index 0000000000..5f3132694e
--- /dev/null
+++ b/source3/libsmb/ntlmssp_parse.c
@@ -0,0 +1,303 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple kerberos5/SPNEGO routines
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Jim McDonough 2002
+ Copyright (C) Andrew Bartlett 2002-2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ this is a tiny msrpc packet generator. I am only using this to
+ avoid tying this code to a particular varient of our rpc code. This
+ generator is not general enough for all our rpc needs, its just
+ enough for the spnego/ntlmssp code
+
+ format specifiers are:
+
+ U = unicode string (input is unix string)
+ a = address (input is BOOL unicode, char *unix_string)
+ (1 byte type, 1 byte length, unicode/ASCII string, all inline)
+ A = ASCII string (input is unix string)
+ B = data blob (pointer + length)
+ b = data blob in header (pointer + length)
+ D
+ d = word (4 bytes)
+ C = constant ascii string
+ */
+BOOL msrpc_gen(DATA_BLOB *blob,
+ const char *format, ...)
+{
+ int i, n;
+ va_list ap;
+ char *s;
+ uint8 *b;
+ int head_size=0, data_size=0;
+ int head_ofs, data_ofs;
+ BOOL unicode;
+
+ /* first scan the format to work out the header and body size */
+ va_start(ap, format);
+ for (i=0; format[i]; i++) {
+ switch (format[i]) {
+ case 'U':
+ s = va_arg(ap, char *);
+ head_size += 8;
+ data_size += str_charnum(s) * 2;
+ break;
+ case 'A':
+ s = va_arg(ap, char *);
+ head_size += 8;
+ data_size += str_ascii_charnum(s);
+ break;
+ case 'a':
+ unicode = va_arg(ap, BOOL);
+ n = va_arg(ap, int);
+ s = va_arg(ap, char *);
+ if (unicode) {
+ data_size += (str_charnum(s) * 2) + 4;
+ } else {
+ data_size += (str_ascii_charnum(s)) + 4;
+ }
+ break;
+ case 'B':
+ b = va_arg(ap, uint8 *);
+ head_size += 8;
+ data_size += va_arg(ap, int);
+ break;
+ case 'b':
+ b = va_arg(ap, uint8 *);
+ head_size += va_arg(ap, int);
+ break;
+ case 'd':
+ n = va_arg(ap, int);
+ head_size += 4;
+ break;
+ case 'C':
+ s = va_arg(ap, char *);
+ head_size += str_charnum(s) + 1;
+ break;
+ }
+ }
+ va_end(ap);
+
+ /* allocate the space, then scan the format again to fill in the values */
+ *blob = data_blob(NULL, head_size + data_size);
+
+ head_ofs = 0;
+ data_ofs = head_size;
+
+ va_start(ap, format);
+ for (i=0; format[i]; i++) {
+ switch (format[i]) {
+ case 'U':
+ s = va_arg(ap, char *);
+ n = str_charnum(s);
+ SSVAL(blob->data, head_ofs, n*2); head_ofs += 2;
+ SSVAL(blob->data, head_ofs, n*2); head_ofs += 2;
+ SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
+ push_string(NULL, blob->data+data_ofs, s, n*2, STR_UNICODE|STR_NOALIGN);
+ data_ofs += n*2;
+ break;
+ case 'A':
+ s = va_arg(ap, char *);
+ n = str_ascii_charnum(s);
+ SSVAL(blob->data, head_ofs, n); head_ofs += 2;
+ SSVAL(blob->data, head_ofs, n); head_ofs += 2;
+ SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
+ push_string(NULL, blob->data+data_ofs, s, n, STR_ASCII|STR_NOALIGN);
+ data_ofs += n;
+ break;
+ case 'a':
+ unicode = va_arg(ap, BOOL);
+ n = va_arg(ap, int);
+ SSVAL(blob->data, data_ofs, n); data_ofs += 2;
+ s = va_arg(ap, char *);
+ if (unicode) {
+ n = str_charnum(s);
+ SSVAL(blob->data, data_ofs, n*2); data_ofs += 2;
+ if (0 < n) {
+ push_string(NULL, blob->data+data_ofs, s, n*2,
+ STR_UNICODE|STR_NOALIGN);
+ }
+ data_ofs += n*2;
+ } else {
+ n = str_ascii_charnum(s);
+ SSVAL(blob->data, data_ofs, n); data_ofs += 2;
+ if (0 < n) {
+ push_string(NULL, blob->data+data_ofs, s, n,
+ STR_ASCII|STR_NOALIGN);
+ }
+ data_ofs += n;
+ }
+ break;
+
+ case 'B':
+ b = va_arg(ap, uint8 *);
+ n = va_arg(ap, int);
+ SSVAL(blob->data, head_ofs, n); head_ofs += 2;
+ SSVAL(blob->data, head_ofs, n); head_ofs += 2;
+ SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
+ memcpy(blob->data+data_ofs, b, n);
+ data_ofs += n;
+ break;
+ case 'd':
+ n = va_arg(ap, int);
+ SIVAL(blob->data, head_ofs, n); head_ofs += 4;
+ break;
+ case 'b':
+ b = va_arg(ap, uint8 *);
+ n = va_arg(ap, int);
+ memcpy(blob->data + head_ofs, b, n);
+ head_ofs += n;
+ break;
+ case 'C':
+ s = va_arg(ap, char *);
+ head_ofs += push_string(NULL, blob->data+head_ofs, s, -1,
+ STR_ASCII|STR_TERMINATE);
+ break;
+ }
+ }
+ va_end(ap);
+
+ return True;
+}
+
+
+/* a helpful macro to avoid running over the end of our blob */
+#define NEED_DATA(amount) \
+if (head_ofs + amount > blob->length) { \
+ return False; \
+}
+
+/*
+ this is a tiny msrpc packet parser. This the the partner of msrpc_gen
+
+ format specifiers are:
+
+ U = unicode string (output is unix string)
+ A = ascii string
+ B = data blob
+ b = data blob in header
+ d = word (4 bytes)
+ C = constant ascii string
+ */
+
+BOOL msrpc_parse(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':
+ NEED_DATA(8);
+ len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
+
+ /* make sure its in the right format - be strict */
+ if (len1 != len2 || ptr + len1 > blob->length) {
+ return False;
+ }
+ if (len1 & 1) {
+ /* if odd length and unicode */
+ return False;
+ }
+
+ ps = va_arg(ap, char **);
+ if (0 < len1) {
+ pull_string(NULL, p, blob->data + ptr, sizeof(p),
+ len1,
+ STR_UNICODE|STR_NOALIGN);
+ (*ps) = strdup(p);
+ } else {
+ (*ps) = NULL;
+ }
+ break;
+ case 'A':
+ NEED_DATA(8);
+ len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
+
+ /* make sure its in the right format - be strict */
+ if (len1 != len2 || ptr + len1 > blob->length) {
+ return False;
+ }
+
+ ps = va_arg(ap, char **);
+ if (0 < len1) {
+ pull_string(NULL, p, blob->data + ptr, sizeof(p),
+ len1,
+ STR_ASCII|STR_NOALIGN);
+ (*ps) = strdup(p);
+ } else {
+ (*ps) = NULL;
+ }
+ break;
+ case 'B':
+ NEED_DATA(8);
+ len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
+ /* make sure its in the right format - be strict */
+ if (len1 != len2 || ptr + len1 > blob->length) {
+ return False;
+ }
+ b = (DATA_BLOB *)va_arg(ap, void *);
+ *b = data_blob(blob->data + ptr, len1);
+ break;
+ case 'b':
+ b = (DATA_BLOB *)va_arg(ap, void *);
+ len1 = va_arg(ap, unsigned);
+ /* make sure its in the right format - be strict */
+ NEED_DATA(len1);
+ *b = data_blob(blob->data + head_ofs, len1);
+ head_ofs += len1;
+ break;
+ case 'd':
+ v = va_arg(ap, uint32 *);
+ NEED_DATA(4);
+ *v = IVAL(blob->data, head_ofs); head_ofs += 4;
+ break;
+ case 'C':
+ s = va_arg(ap, char *);
+ head_ofs += pull_string(NULL, p, blob->data+head_ofs, sizeof(p),
+ blob->length - head_ofs,
+ STR_ASCII|STR_TERMINATE);
+ if (strcmp(s, p) != 0) {
+ return False;
+ }
+ break;
+ }
+ }
+ va_end(ap);
+
+ return True;
+}
+