[GLUE] Rsync SAMBA_3_2_0 SVN r25598 in order to create the v3-2-test branch.
[samba.git] / source / smbd / srvstr.c
index c3eef464408e4f5097bf0dafd48079013a433d30..68e61033ae1a30b482073a53ca62fb534a52afef 100644 (file)
@@ -1,12 +1,12 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 3.0
+   Unix SMB/CIFS implementation.
    server specific string routines
    Copyright (C) Andrew Tridgell 2001
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   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,
    GNU 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.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#define NO_SYSLOG
-
 #include "includes.h"
+extern int max_send;
 
-#define UNICODE_FLAG(buf) (SVAL(buf, smb_flg2) & FLAGS2_UNICODE_STRINGS)
+/* Make sure we can't write a string past the end of the buffer */
 
-/****************************************************************************
-copy a string from a char* src to a unicode or ascii
-dos code page destination choosing unicode or ascii based on the 
-FLAGS2_UNICODE_STRINGS bit in inbuf
-return the number of bytes occupied by the string in the destination
-flags can have:
-  STR_TERMINATE means include the null termination
-  STR_CONVERT   means convert from unix to dos codepage
-  STR_UPPER     means uppercase in the destination
-  STR_ASCII     use ascii even with unicode servers
-dest_len is the maximum length allowed in the destination. If dest_len
-is -1 then no maxiumum is used
-****************************************************************************/
-int srvstr_push(void *outbuf, void *dest, const char *src, int dest_len, int flags)
+size_t srvstr_push_fn(const char *function, unsigned int line, 
+                     const char *base_ptr, uint16 smb_flags2, void *dest,
+                     const char *src, int dest_len, int flags)
 {
-       int len=0;
-
-       /* treat a pstring as "unlimited" length */
+       size_t buf_used = PTR_DIFF(dest, base_ptr);
        if (dest_len == -1) {
-               dest_len = sizeof(pstring);
-       }
-
-       if (!(flags & STR_ASCII) && srvstr_align(outbuf, PTR_DIFF(dest, outbuf))) {
-               *(char *)dest = 0;
-               dest++;
-               dest_len--;
-               len++;
-       }
-
-       if ((flags & STR_ASCII) || !UNICODE_FLAG(outbuf)) {
-               /* the client doesn't want unicode */
-               safe_strcpy(dest, src, dest_len);
-               len = strlen(dest);
-               if (flags & STR_TERMINATE) len++;
-               if (flags & STR_CONVERT) unix_to_dos(dest,True);
-               if (flags & STR_UPPER) strupper(dest);
-               return len;
-       }
-
-       /* the server likes unicode. give it the works */
-       if (flags & STR_CONVERT) {
-               dos_PutUniCode(dest, src, dest_len, flags & STR_TERMINATE);
-       } else {
-               ascii_to_unistr(dest, src, dest_len);
-       }
-       if (flags & STR_UPPER) {
-               strupper_w(dest);
+               if (((ptrdiff_t)dest < (ptrdiff_t)base_ptr) || (buf_used > (size_t)max_send)) {
+#if 0
+                       DEBUG(0, ("Pushing string of 'unlimited' length into non-SMB buffer!\n"));
+#endif
+                       return push_string_fn(function, line, base_ptr,
+                                             smb_flags2, dest, src, -1,
+                                             flags);
+               }
+               return push_string_fn(function, line, base_ptr, smb_flags2,
+                                     dest, src, max_send - buf_used, flags);
        }
-       len += strlen(src)*2;
-       if (flags & STR_TERMINATE) len += 2;
-       return len;
+       
+       /* 'normal' push into size-specified buffer */
+       return push_string_fn(function, line, base_ptr, smb_flags2, dest, src,
+                             dest_len, flags);
 }
 
+/*******************************************************************
+ Add a string to the end of a smb_buf, adjusting bcc and smb_len.
+ Return the bytes added
+********************************************************************/
 
-/****************************************************************************
-return the length that a string would occupy when copied with srvstr_push()
-  STR_TERMINATE means include the null termination
-  STR_CONVERT   means convert from unix to dos codepage
-  STR_UPPER     means uppercase in the destination
-note that dest is only used for alignment purposes. No data is written.
-****************************************************************************/
-int srvstr_push_size(void *outbuf, 
-                    const void *dest, const char *src, int dest_len, int flags)
+ssize_t message_push_string(uint8 **outbuf, const char *str, int flags)
 {
-       int len = strlen(src);
-       if (flags & STR_TERMINATE) len++;
-       if (!(flags & STR_ASCII) && UNICODE_FLAG(outbuf)) len *= 2;
-
-       if (!(flags & STR_ASCII) && dest && srvstr_align(outbuf, PTR_DIFF(outbuf, dest))) {
-               len++;
+       size_t buf_size = smb_len(*outbuf) + 4;
+       size_t grow_size;
+       size_t result;
+       uint8 *tmp;
+
+       /*
+        * We need to over-allocate, now knowing what srvstr_push will
+        * actually use. This is very generous by incorporating potential
+        * padding, the terminating 0 and at most 4 chars per UTF-16 code
+        * point.
+        */
+       grow_size = (strlen(str) + 2) * 4;
+
+       if (!(tmp = TALLOC_REALLOC_ARRAY(NULL, *outbuf, uint8,
+                                        buf_size + grow_size))) {
+               DEBUG(0, ("talloc failed\n"));
+               return -1;
        }
 
-       return len;
-}
+       result = srvstr_push((char *)tmp, SVAL(tmp, smb_flg2),
+                            tmp + buf_size, str, grow_size, flags);
 
-/****************************************************************************
-copy a string from a unicode or ascii source (depending on flg2) 
-to a char* destination
-flags can have:
-  STR_CONVERT   means convert from dos to unix codepage
-  STR_TERMINATE means the string in src is null terminated
-  STR_UNICODE   means to force as unicode
-if STR_TERMINATE is set then src_len is ignored
-src_len is the length of the source area in bytes
-return the number of bytes occupied by the string in src
-****************************************************************************/
-int srvstr_pull(void *inbuf, char *dest, const void *src, int dest_len, int src_len, int flags)
-{
-       int len;
-
-       if (dest_len == -1) {
-               dest_len = sizeof(pstring);
+       if (result == (size_t)-1) {
+               DEBUG(0, ("srvstr_push failed\n"));
+               return -1;
        }
+       set_message_bcc((char *)tmp, smb_buflen(tmp) + result);
 
-       if (!(flags & STR_ASCII) && srvstr_align(inbuf, PTR_DIFF(src, inbuf))) {
-               src++;
-               if (src_len > 0) src_len--;
-       }
-
-       if ((flags & STR_ASCII) || (!(flags & STR_UNICODE) && !UNICODE_FLAG(inbuf))) {
-               /* the server doesn't want unicode */
-               if (flags & STR_TERMINATE) {
-                       safe_strcpy(dest, src, dest_len);
-                       len = strlen(src)+1;
-               } else {
-                       if (src_len > dest_len) src_len = dest_len;
-                       len = src_len;
-                       memcpy(dest, src, len);
-                       dest[len] = 0;
-               }
-               if (flags & STR_CONVERT) dos_to_unix(dest,True);
-               return len;
-       }
-
-       if (flags & STR_TERMINATE) {
-               unistr_to_ascii(dest, src, dest_len);
-               len = strlen(dest)*2 + 2;
-       } else {
-               int i, c;
-               if (dest_len*2 < src_len) src_len = 2*dest_len;
-               for (i=0; i < src_len; i += 2) {
-                       c = SVAL(src, i);
-                       *dest++ = c;
-               }
-               *dest++ = 0;
-               len = src_len;
-       }
-       if (flags & STR_CONVERT) dos_to_unix(dest,True);
-       return len;
-}
-
-/****************************************************************************
-return the length that a string would occupy (not including the null)
-when copied with srvstr_pull()
-if src_len is -1 then assume the source is null terminated
-****************************************************************************/
-int srvstr_pull_size(void *inbuf, const void *src, int src_len)
-{
-       if (srvstr_align(inbuf, PTR_DIFF(src, inbuf))) {
-               src++;
-               if (src_len > 0) src_len--;
-       }
+       *outbuf = tmp;
 
-       if (!UNICODE_FLAG(inbuf)) {
-               return strlen(src);
-       }       
-       return strlen_w(src);
-}
-
-/****************************************************************************
-return an alignment of either 0 or 1
-if unicode is not negotiated then return 0
-otherwise return 1 if offset is off
-****************************************************************************/
-int srvstr_align(void *inbuf, int offset)
-{
-       if (!UNICODE_FLAG(inbuf)) return 0;
-       return offset & 1;
+       return result;
 }