r23858: Added srvstr_pull_buf_talloc() and srvstr_pull_talloc()
authorJeremy Allison <jra@samba.org>
Fri, 13 Jul 2007 01:22:09 +0000 (01:22 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:28:35 +0000 (12:28 -0500)
calls and converted reply_tcon and reply_tconX to use
them - to show the boilerplate usage (valgrind tested).
In conjunction with Volker's srvstr_get_path_talloc()
work this should allow us to start eliminating all
pstrings/fstrings out of the main path processing
code.
I'll watch the build farm tonight...
Jeremy.

source/include/safe_string.h
source/include/srvstr.h
source/lib/charcnv.c
source/smbd/reply.c

index 68be38df75a747b2f512955924a80e0951161a60..8c4d90c44a33e35bf08b5b93904907a1a93d95c5 100644 (file)
@@ -164,6 +164,7 @@ size_t __unsafe_string_function_usage_here_char__(void);
 #define safe_strcat(dest,src,maxlength)        safe_strcat_fn2(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE,dest,src,maxlength)
 #define push_string(base_ptr, dest, src, dest_len, flags) push_string_fn2(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, base_ptr, dest, src, dest_len, flags)
 #define pull_string(base_ptr, smb_flags2, dest, src, dest_len, src_len, flags) pull_string_fn2(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, base_ptr, smb_flags2, dest, src, dest_len, src_len, flags)
+#define pull_string_talloc(ctx, base_ptr, smb_flags2, dest, src, src_len, flags) pull_string_talloc_fn2(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, ctx, base_ptr, smb_flags2, dest, src, src_len, flags)
 #define clistr_push(cli, dest, src, dest_len, flags) clistr_push_fn2(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, cli, dest, src, dest_len, flags)
 #define clistr_pull(cli, dest, src, dest_len, src_len, flags) clistr_pull_fn2(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, cli, dest, src, dest_len, src_len, flags)
 #define srvstr_push(base_ptr, dest, src, dest_len, flags) srvstr_push_fn2(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, base_ptr, dest, src, dest_len, flags)
@@ -197,6 +198,9 @@ size_t __unsafe_string_function_usage_here_char__(void);
     ? __unsafe_string_function_usage_here_size_t__() \
     : pull_string_fn(fn_name, fn_line, base_ptr, smb_flags2, dest, src, dest_len, src_len, flags))
 
+#define pull_string_talloc_fn2(fn_name, fn_line, ctx, base_ptr, smb_flags2, dest, src, src_len, flags) \
+    pull_string_talloc_fn(fn_name, fn_line, ctx, base_ptr, smb_flags2, dest, src, src_len, flags)
+
 #define clistr_push_fn2(fn_name, fn_line, cli, dest, src, dest_len, flags) \
     (CHECK_STRING_SIZE(dest, dest_len) \
     ? __unsafe_string_function_usage_here_size_t__() \
@@ -218,6 +222,7 @@ size_t __unsafe_string_function_usage_here_char__(void);
 #define safe_strcat_fn2 safe_strcat_fn
 #define push_string_fn2 push_string_fn
 #define pull_string_fn2 pull_string_fn
+#define pull_string_talloc_fn2 pull_string_talloc_fn
 #define clistr_push_fn2 clistr_push_fn
 #define clistr_pull_fn2 clistr_pull_fn
 #define srvstr_push_fn2 srvstr_push_fn
index c1bb5226e5c5a7683249519aa1f5e5538365b80f..588a807f64b298d2215966c985c60ec6f5d99df2 100644 (file)
 #define srvstr_pull(base_ptr, smb_flags2, dest, src, dest_len, src_len, flags) \
     pull_string(base_ptr, smb_flags2, dest, src, dest_len, src_len, flags)
 
+/* talloc version of above. */
+#define srvstr_pull_talloc(ctx, base_ptr, smb_flags2, dest, src, src_len, flags) \
+    pull_string_talloc(ctx, base_ptr, smb_flags2, dest, src, src_len, flags)
+
 /* pull a string from the smb_buf part of a packet. In this case the
    string can either be null terminated or it can be terminated by the
    end of the smbbuf area 
@@ -28,3 +32,6 @@
 #define srvstr_pull_buf(inbuf, smb_flags2, dest, src, dest_len, flags) \
     pull_string(inbuf, smb_flags2, dest, src, dest_len, smb_bufrem(inbuf, src), flags)
 
+/* talloc version of above. */
+#define srvstr_pull_buf_talloc(ctx, inbuf, smb_flags2, dest, src, flags) \
+    pull_string_talloc(ctx, inbuf, smb_flags2, dest, src, smb_bufrem(inbuf, src), flags)
index b48880a8ea9239c81627cfef0a45c94accb4ce5d..b71e15f44d4e9fe121fd0737fc1e1b1902db9da4 100644 (file)
@@ -1,21 +1,21 @@
-/* 
+/*
    Unix SMB/CIFS implementation.
    Character set conversion Extensions
    Copyright (C) Igor Vergeichik <iverg@mail.ru> 2001
    Copyright (C) Andrew Tridgell 2001
    Copyright (C) Simo Sorce 2001
    Copyright (C) Martin Pool 2003
-   
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
@@ -33,7 +33,7 @@ char lp_failed_convert_char(void)
  * @file
  *
  * @brief Character-set conversion routines built on our iconv.
- * 
+ *
  * @note Samba's internal character set (at least in the 3.0 series)
  * is always the same as the one for the Unix filesystem.  It is
  * <b>not</b> necessarily UTF-8 and may be different on machines that
@@ -509,6 +509,7 @@ size_t convert_string(charset_t from, charset_t to,
  * Convert between character sets, allocating a new buffer for the result.
  *
  * @param ctx TALLOC_CTX to use to allocate with. If NULL use malloc.
+ * (this is a bad interface and needs fixing. JRA).
  * @param srclen length of source buffer.
  * @param dest always set at least to NULL
  * @note -1 is not accepted for srclen.
@@ -516,7 +517,7 @@ size_t convert_string(charset_t from, charset_t to,
  * @returns Size in bytes of the converted string; or -1 in case of error.
  *
  * Ensure the srclen contains the terminating zero.
- * 
+ *
  * I hate the goto's in this function. It's embarressing.....
  * There has to be a cleaner way to do this. JRA.
  **/
@@ -603,6 +604,11 @@ size_t convert_string_allocate(TALLOC_CTX *ctx, charset_t from, charset_t to,
                if (!conv_silent)
                        DEBUG(0,("Conversion error: %s(%s)\n",reason,inbuf));
                /* smb_panic(reason); */
+               if (ctx) {
+                       TALLOC_FREE(ob);
+               } else {
+                       SAFE_FREE(ob);
+               }
                return (size_t)-1;
        }
 
@@ -711,7 +717,7 @@ size_t convert_string_allocate(TALLOC_CTX *ctx, charset_t from, charset_t to,
  * Convert between character sets, allocating a new buffer using talloc for the result.
  *
  * @param srclen length of source buffer.
- * @param dest always set at least to NULL 
+ * @param dest always set at least to NULL
  * @note -1 is not accepted for srclen.
  *
  * @returns Size in bytes of the converted string; or -1 in case of error.
@@ -736,7 +742,7 @@ size_t unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
 {
        size_t size;
        smb_ucs2_t *buffer;
-       
+
        size = push_ucs2_allocate(&buffer, src);
        if (size == (size_t)-1) {
                smb_panic("failed to create UCS2 buffer");
@@ -745,7 +751,7 @@ size_t unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
                free(buffer);
                return srclen;
        }
-       
+
        size = convert_string(CH_UTF16LE, CH_UNIX, buffer, size, dest, destlen, True);
        free(buffer);
        return size;
@@ -788,7 +794,7 @@ char *strdup_upper(const char *s)
                }
 
                strupper_w(buffer);
-       
+
                size = convert_string(CH_UTF16LE, CH_UNIX, buffer, -1, out_buffer, sizeof(out_buffer), True);
                if (size == (size_t)-1) {
                        return NULL;
@@ -802,7 +808,7 @@ size_t unix_strlower(const char *src, size_t srclen, char *dest, size_t destlen)
 {
        size_t size;
        smb_ucs2_t *buffer = NULL;
-       
+
        size = convert_string_allocate(NULL, CH_UNIX, CH_UTF16LE, src, srclen,
                                       (void **)(void *)&buffer, True);
        if (size == (size_t)-1 || !buffer) {
@@ -826,21 +832,21 @@ char *strdup_lower(const char *s)
        size_t size;
        smb_ucs2_t *buffer = NULL;
        char *out_buffer;
-       
+
        size = push_ucs2_allocate(&buffer, s);
        if (size == -1 || !buffer) {
                return NULL;
        }
 
        strlower_w(buffer);
-       
+
        size = pull_ucs2_allocate(&out_buffer, buffer);
        SAFE_FREE(buffer);
 
        if (size == (size_t)-1) {
                return NULL;
        }
-       
+
        return out_buffer;
 }
 
@@ -987,6 +993,84 @@ size_t pull_ascii(char *dest, const void *src, size_t dest_len, size_t src_len,
        return src_len;
 }
 
+/**
+ * Copy a string from a dos codepage source to a unix char* destination.
+ Talloc version.
+ Uses malloc if TALLOC_CTX is NULL (this is a bad interface and
+ needs fixing. JRA).
+ *
+ * The resulting string in "dest" is always null terminated.
+ *
+ * @param flags can have:
+ * <dl>
+ * <dt>STR_TERMINATE</dt>
+ * <dd>STR_TERMINATE means the string in @p src
+ * is null terminated, and src_len is ignored.</dd>
+ * </dl>
+ *
+ * @param src_len is the length of the source area in bytes.
+ * @returns the number of bytes occupied by the string in @p src.
+ **/
+
+static size_t pull_ascii_base_talloc(TALLOC_CTX *ctx,
+                                       char **ppdest,
+                                       const void *src,
+                                       size_t src_len,
+                                       int flags)
+{
+       char *dest = NULL;
+       size_t dest_len = 0;
+
+#ifdef DEVELOPER
+       /* Ensure we never use the braindead "malloc" varient. */
+       if (ctx == NULL) {
+               smb_panic("NULL talloc CTX in pull_ascii_base_talloc\n");
+       }
+#endif
+
+       *ppdest = NULL;
+
+       if (flags & STR_TERMINATE) {
+               if (src_len == (size_t)-1) {
+                       src_len = strlen((const char *)src) + 1;
+               } else {
+                       size_t len = strnlen((const char *)src, src_len);
+                       if (len < src_len)
+                               len++;
+                       src_len = len;
+               }
+               /* Ensure we don't use an insane length from the client. */
+               if (src_len >= 1024*1024) {
+                       smb_panic("Bad src length in pull_ascii_base_talloc\n");
+               }
+       }
+
+       dest_len = convert_string_allocate(ctx,
+                               CH_DOS,
+                               CH_UNIX,
+                               src,
+                               src_len,
+                               &dest,
+                               True);
+
+       if (dest_len == (size_t)-1) {
+               return 0;
+       }
+
+       if (dest_len && dest) {
+               /* Did we already process the terminating zero ? */
+               if (dest[dest_len-1] != 0) {
+                       dest[dest_len-1] = 0;
+               }
+       } else if (dest) {
+               dest[0] = 0;
+       }
+
+       *ppdest = dest;
+       return src_len;
+}
+
+
 size_t pull_ascii_pstring(char *dest, const void *src)
 {
        return pull_ascii(dest, src, sizeof(pstring), -1, STR_TERMINATE);
@@ -1214,7 +1298,7 @@ size_t pull_ucs2(const void *base_ptr, char *dest, const void *src, size_t dest_
        /* ucs2 is always a multiple of 2 bytes */
        if (src_len != (size_t)-1)
                src_len &= ~1;
-       
+
        ret = convert_string(CH_UTF16LE, CH_UNIX, src, src_len, dest, dest_len, True);
        if (ret == (size_t)-1) {
                return 0;
@@ -1222,7 +1306,7 @@ size_t pull_ucs2(const void *base_ptr, char *dest, const void *src, size_t dest_
 
        if (src_len == (size_t)-1)
                src_len = ret*2;
-               
+
        if (dest_len && ret) {
                /* Did we already process the terminating zero ? */
                if (dest[MIN(ret-1, dest_len-1)] != 0) {
@@ -1235,6 +1319,92 @@ size_t pull_ucs2(const void *base_ptr, char *dest, const void *src, size_t dest_
        return src_len;
 }
 
+/**
+ Copy a string from a ucs2 source to a unix char* destination.
+ Talloc version with a base pointer.
+ Uses malloc if TALLOC_CTX is NULL (this is a bad interface and
+ needs fixing. JRA).
+ Flags can have:
+  STR_TERMINATE means the string in src is null terminated.
+  STR_NOALIGN   means don't try to align.
+ if STR_TERMINATE is set then src_len is ignored if it is -1.
+ src_len is the length of the source area in bytes
+ Return the number of bytes occupied by the string in src.
+ The resulting string in "dest" is always null terminated.
+**/
+
+static size_t pull_ucs2_base_talloc(TALLOC_CTX *ctx,
+                       const void *base_ptr,
+                       char **ppdest,
+                       const void *src,
+                       size_t src_len,
+                       int flags)
+{
+       char *dest;
+       size_t dest_len;
+
+       *ppdest = NULL;
+
+#ifdef DEVELOPER
+       /* Ensure we never use the braindead "malloc" varient. */
+       if (ctx == NULL) {
+               smb_panic("NULL talloc CTX in pull_ucs2_base_talloc\n");
+       }
+#endif
+
+       if (ucs2_align(base_ptr, src, flags)) {
+               src = (const void *)((const char *)src + 1);
+               if (src_len != (size_t)-1)
+                       src_len--;
+       }
+
+       if (flags & STR_TERMINATE) {
+               /* src_len -1 is the default for null terminated strings. */
+               if (src_len != (size_t)-1) {
+                       size_t len = strnlen_w((const smb_ucs2_t *)src,
+                                               src_len/2);
+                       if (len < src_len/2)
+                               len++;
+                       src_len = len*2;
+               }
+               /* Ensure we don't use an insane length from the client. */
+               if (src_len >= 1024*1024) {
+                       smb_panic("Bad src length in pull_ucs2_base_talloc\n");
+               }
+       }
+
+       /* ucs2 is always a multiple of 2 bytes */
+       if (src_len != (size_t)-1) {
+               src_len &= ~1;
+       }
+
+       dest_len = convert_string_talloc(ctx,
+                                       CH_UTF16LE,
+                                       CH_UNIX,
+                                       src,
+                                       src_len,
+                                       (void **)&dest,
+                                       True);
+       if (dest_len == (size_t)-1) {
+               return 0;
+       }
+
+       if (src_len == (size_t)-1)
+               src_len = dest_len*2;
+
+       if (dest_len) {
+               /* Did we already process the terminating zero ? */
+               if (dest[dest_len-1] != 0) {
+                       dest[dest_len-1] = 0;
+               }
+       } else if (dest) {
+               dest[0] = 0;
+       }
+
+       *ppdest = dest;
+       return src_len;
+}
+
 size_t pull_ucs2_pstring(char *dest, const void *src)
 {
        return pull_ucs2(NULL, dest, src, sizeof(pstring), -1, STR_TERMINATE);
@@ -1398,6 +1568,54 @@ size_t pull_string_fn(const char *function, unsigned int line,
        return pull_ascii(dest, src, dest_len, src_len, flags);
 }
 
+/**
+ Copy a string from a unicode or ascii source (depending on
+ the packet flags) to a char* destination.
+ Variant that uses talloc.
+ Flags can have:
+  STR_TERMINATE means the string in src is null terminated.
+  STR_UNICODE   means to force as unicode.
+  STR_ASCII     use ascii even with unicode packet.
+  STR_NOALIGN   means don't do alignment.
+ if STR_TERMINATE is set then src_len is ignored is it is -1
+ src_len is the length of the source area in bytes.
+ Return the number of bytes occupied by the string in src.
+ The resulting string in "dest" is always null terminated.
+**/
+
+size_t pull_string_talloc_fn(const char *function,
+                       unsigned int line,
+                       TALLOC_CTX *ctx,
+                       const void *base_ptr,
+                       uint16 smb_flags2,
+                       char **ppdest,
+                       const void *src,
+                       size_t src_len,
+                       int flags)
+{
+       if ((base_ptr == NULL) && ((flags & (STR_ASCII|STR_UNICODE)) == 0)) {
+               smb_panic("No base ptr to get flg2 and neither ASCII nor "
+                         "UNICODE defined");
+       }
+
+       if (!(flags & STR_ASCII) && \
+           ((flags & STR_UNICODE || \
+             (smb_flags2 & FLAGS2_UNICODE_STRINGS)))) {
+               return pull_ucs2_base_talloc(ctx,
+                                       base_ptr,
+                                       ppdest,
+                                       src,
+                                       src_len,
+                                       flags);
+       }
+       return pull_ascii_base_talloc(ctx,
+                                       ppdest,
+                                       src,
+                                       src_len,
+                                       flags);
+}
+
+
 size_t align_string(const void *base_ptr, const char *p, int flags)
 {
        if (!(flags & STR_ASCII) && \
index 9a2dc19fa10bec89163739bf246015acc6fbf883..8b6a164a6656a8a55bc89d48e813ff7c6bf6abac 100644 (file)
@@ -381,30 +381,40 @@ int reply_special(char *inbuf,char *outbuf)
 int reply_tcon(connection_struct *conn,
               char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
 {
+       TALLOC_CTX *ctx;
        const char *service;
-       pstring service_buf;
-       pstring password;
-       pstring dev;
+       char *service_buf = NULL;
+       char *password = NULL;
+       char *dev = NULL;
        int outsize = 0;
        uint16 vuid = SVAL(inbuf,smb_uid);
        int pwlen=0;
        NTSTATUS nt_status;
        char *p;
        DATA_BLOB password_blob;
-       
+
        START_PROFILE(SMBtcon);
 
-       *service_buf = *password = *dev = 0;
+       ctx = talloc_init("reply_tcon");
+       if (!ctx) {
+               END_PROFILE(SMBtcon);
+               return ERROR_NT(NT_STATUS_NO_MEMORY);
+       }
 
        p = smb_buf(inbuf)+1;
-       p += srvstr_pull_buf(inbuf, SVAL(inbuf, smb_flg2), service_buf, p,
-                            sizeof(service_buf), STR_TERMINATE) + 1;
-       pwlen = srvstr_pull_buf(inbuf, SVAL(inbuf, smb_flg2), password, p,
-                               sizeof(password), STR_TERMINATE) + 1;
+       p += srvstr_pull_buf_talloc(ctx, inbuf, SVAL(inbuf, smb_flg2),
+                       &service_buf, p, STR_TERMINATE) + 1;
+       pwlen = srvstr_pull_buf_talloc(ctx, inbuf, SVAL(inbuf, smb_flg2),
+                       &password, p, STR_TERMINATE) + 1;
        p += pwlen;
-       p += srvstr_pull_buf(inbuf, SVAL(inbuf, smb_flg2), dev, p, sizeof(dev),
-                            STR_TERMINATE) + 1;
+       p += srvstr_pull_buf_talloc(ctx, inbuf, SVAL(inbuf, smb_flg2),
+                       &dev, p, STR_TERMINATE) + 1;
 
+       if (service_buf == NULL || password == NULL || dev == NULL) {
+               TALLOC_FREE(ctx);
+               END_PROFILE(SMBtcon);
+               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+       }
        p = strrchr_m(service_buf,'\\');
        if (p) {
                service = p+1;
@@ -417,21 +427,23 @@ int reply_tcon(connection_struct *conn,
        conn = make_connection(service,password_blob,dev,vuid,&nt_status);
 
        data_blob_clear_free(&password_blob);
-  
+
        if (!conn) {
+               TALLOC_FREE(ctx);
                END_PROFILE(SMBtcon);
                return ERROR_NT(nt_status);
        }
-  
+
        outsize = set_message(inbuf,outbuf,2,0,True);
        SSVAL(outbuf,smb_vwv0,max_recv);
        SSVAL(outbuf,smb_vwv1,conn->cnum);
        SSVAL(outbuf,smb_tid,conn->cnum);
-  
+
        DEBUG(3,("tcon service=%s cnum=%d\n", 
                 service, conn->cnum));
-  
+
        END_PROFILE(SMBtcon);
+       TALLOC_FREE(ctx);
        return(outsize);
 }
 
@@ -442,23 +454,22 @@ int reply_tcon(connection_struct *conn,
 
 int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
 {
-       fstring service;
+       char *service = NULL;
        DATA_BLOB password;
 
+       TALLOC_CTX *ctx = NULL;
        /* what the cleint thinks the device is */
-       fstring client_devicetype;
+       char *client_devicetype = NULL;
        /* what the server tells the client the share represents */
        const char *server_devicetype;
        NTSTATUS nt_status;
        uint16 vuid = SVAL(inbuf,smb_uid);
        int passlen = SVAL(inbuf,smb_vwv3);
-       pstring path;
+       char *path = NULL;
        char *p, *q;
        uint16 tcon_flags = SVAL(inbuf,smb_vwv2);
-       
-       START_PROFILE(SMBtconX);        
 
-       *service = *client_devicetype = 0;
+       START_PROFILE(SMBtconX);
 
        /* we might have to close an old one */
        if ((SVAL(inbuf,smb_vwv2) & 0x1) && conn) {
@@ -468,7 +479,7 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
        if (passlen > MAX_PASS_LEN) {
                return ERROR_DOS(ERRDOS,ERRbuftoosmall);
        }
+
        if (global_encrypted_passwords_negotiated) {
                password = data_blob(smb_buf(inbuf),passlen);
                if (lp_security() == SEC_SHARE) {
@@ -487,34 +498,53 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                p = smb_buf(inbuf) + passlen + 1;
        }
 
-       p += srvstr_pull_buf(inbuf, SVAL(inbuf, smb_flg2), path, p,
-                            sizeof(path), STR_TERMINATE);
+       ctx = talloc_init("reply_tcon_and_X");
+       if (!ctx) {
+               END_PROFILE(SMBtconX);
+               return ERROR_NT(NT_STATUS_NO_MEMORY);
+       }
+       p += srvstr_pull_buf_talloc(ctx, inbuf, SVAL(inbuf, smb_flg2), &path, p,
+                            STR_TERMINATE);
+
+       if (path == NULL) {
+               TALLOC_FREE(ctx);
+               END_PROFILE(SMBtconX);
+               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+       }
 
        /*
         * the service name can be either: \\server\share
         * or share directly like on the DELL PowerVault 705
         */
-       if (*path=='\\') {      
+       if (*path=='\\') {
                q = strchr_m(path+2,'\\');
                if (!q) {
+                       TALLOC_FREE(ctx);
                        END_PROFILE(SMBtconX);
                        return(ERROR_DOS(ERRDOS,ERRnosuchshare));
                }
-               fstrcpy(service,q+1);
+               service = q+1;
+       } else {
+               service = path;
+       }
+
+       p += srvstr_pull_talloc(ctx, inbuf, SVAL(inbuf, smb_flg2), &client_devicetype, p,
+                        6, STR_ASCII);
+
+       if (client_devicetype == NULL) {
+               TALLOC_FREE(ctx);
+               END_PROFILE(SMBtconX);
+               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
        }
-       else
-               fstrcpy(service,path);
-               
-       p += srvstr_pull(inbuf, SVAL(inbuf, smb_flg2), client_devicetype, p,
-                        sizeof(client_devicetype), 6, STR_ASCII);
 
        DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
 
        conn = make_connection(service,password,client_devicetype,vuid,&nt_status);
-       
+
        data_blob_clear_free(&password);
 
        if (!conn) {
+               TALLOC_FREE(ctx);
                END_PROFILE(SMBtconX);
                return ERROR_NT(nt_status);
        }
@@ -523,19 +553,19 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                server_devicetype = "IPC";
        else if ( IS_PRINT(conn) )
                server_devicetype = "LPT1:";
-       else 
+       else
                server_devicetype = "A:";
 
        if (Protocol < PROTOCOL_NT1) {
                set_message(inbuf,outbuf,2,0,True);
                p = smb_buf(outbuf);
-               p += srvstr_push(outbuf, p, server_devicetype, -1, 
+               p += srvstr_push(outbuf, p, server_devicetype, -1,
                                 STR_TERMINATE|STR_ASCII);
                set_message_end(inbuf,outbuf,p);
        } else {
                /* NT sets the fstype of IPC$ to the null string */
                const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
-               
+
                if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
                        /* Return permissions. */
                        uint32 perm1 = 0;
@@ -559,29 +589,30 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                }
 
                p = smb_buf(outbuf);
-               p += srvstr_push(outbuf, p, server_devicetype, -1, 
+               p += srvstr_push(outbuf, p, server_devicetype, -1,
                                 STR_TERMINATE|STR_ASCII);
-               p += srvstr_push(outbuf, p, fstype, -1, 
+               p += srvstr_push(outbuf, p, fstype, -1,
                                 STR_TERMINATE);
-               
+
                set_message_end(inbuf,outbuf,p);
-               
+
                /* what does setting this bit do? It is set by NT4 and
                   may affect the ability to autorun mounted cdroms */
                SSVAL(outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
                                (lp_csc_policy(SNUM(conn)) << 2));
-               
+
                init_dfsroot(conn, inbuf, outbuf);
        }
 
-  
+
        DEBUG(3,("tconX service=%s \n",
                 service));
-  
+
        /* set the incoming and outgoing tid to the just created one */
        SSVAL(inbuf,smb_tid,conn->cnum);
        SSVAL(outbuf,smb_tid,conn->cnum);
 
+       TALLOC_FREE(ctx);
        END_PROFILE(SMBtconX);
        return chain_reply(inbuf,outbuf,length,bufsize);
 }