Fix a really interesting problem found by Volker's conversion of sessionsetup SPNEGO...
[abartlet/samba.git/.git] / source3 / libsmb / clistr.c
index e07b4d5a63d2845841705d046059efc2393b92ec..4e490913123e0d54facade4da7f7ab4b9cc3058f 100644 (file)
@@ -1,12 +1,12 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 3.0
+   Unix SMB/CIFS implementation.
    client 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"
 
-/****************************************************************************
-copy a string from a char* src to a unicode or ascii
-dos code page destination choosing unicode or ascii based on the 
-cli->capabilities flag
-return the number of bytes occupied by the string in the destination
-flags can have:
-  CLISTR_TERMINATE means include the null termination
-  CLISTR_CONVERT   means convert from unix to dos codepage
-  CLISTR_UPPER     means uppercase in the destination
-  CLISTR_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 clistr_push(struct cli_state *cli, void *dest, const char *src, int dest_len, int flags)
+size_t clistr_push_fn(const char *function,
+                       unsigned int line,
+                       struct cli_state *cli,
+                       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, cli->outbuf);
        if (dest_len == -1) {
-               dest_len = sizeof(pstring);
-       }
-
-       if (!(flags & CLISTR_ASCII) && clistr_align(cli, PTR_DIFF(dest, cli->outbuf))) {
-               *(char *)dest = 0;
-               dest++;
-               dest_len--;
-               len++;
-       }
-
-       if ((flags & CLISTR_ASCII) || !(cli->capabilities & CAP_UNICODE)) {
-               /* the server doesn't want unicode */
-               safe_strcpy(dest, src, dest_len);
-               len = strlen(dest);
-               if (flags & CLISTR_TERMINATE) len++;
-               if (flags & CLISTR_CONVERT) unix_to_dos(dest,True);
-               if (flags & CLISTR_UPPER) strupper(dest);
-               return len;
+               if (((ptrdiff_t)dest < (ptrdiff_t)cli->outbuf) || (buf_used > cli->bufsize)) {
+                       DEBUG(0, ("Pushing string of 'unlimited' length into non-SMB buffer!\n"));
+                       return push_string_base(function, line,
+                                               cli->outbuf,
+                                               (uint16_t)(cli_ucs2(cli) ? FLAGS2_UNICODE_STRINGS : 0),
+                                               dest, src, -1, flags);
+               }
+               return push_string_base(function, line, 
+                                       cli->outbuf,
+                                       (uint16_t)(cli_ucs2(cli) ? FLAGS2_UNICODE_STRINGS : 0),
+                                       dest, src, cli->bufsize - buf_used,
+                                       flags);
        }
 
-       /* the server likes unicode. give it the works */
-       if (flags & CLISTR_CONVERT) {
-               dos_PutUniCode(dest, src, dest_len, flags & CLISTR_TERMINATE);
-       } else {
-               ascii_to_unistr(dest, src, dest_len);
-       }
-       if (flags & CLISTR_UPPER) {
-               strupper_w(dest);
-       }
-       len += strlen(src)*2;
-       if (flags & CLISTR_TERMINATE) len += 2;
-       return len;
+       /* 'normal' push into size-specified buffer */
+       return push_string_base(function, line, 
+                               cli->outbuf,
+                               (uint16_t)(cli_ucs2(cli) ? FLAGS2_UNICODE_STRINGS : 0),
+                               dest, src, dest_len, flags);
 }
 
-
-/****************************************************************************
-return the length that a string would occupy when copied with clistr_push()
-  CLISTR_TERMINATE means include the null termination
-  CLISTR_CONVERT   means convert from unix to dos codepage
-  CLISTR_UPPER     means uppercase in the destination
-note that dest is only used for alignment purposes. No data is written.
-****************************************************************************/
-int clistr_push_size(struct cli_state *cli, const void *dest, const char *src, int dest_len, int flags)
+size_t clistr_pull_fn(const char *function,
+                       unsigned int line,
+                       const char *inbuf,
+                       char *dest,
+                       const void *src,
+                       int dest_len,
+                       int src_len,
+                       int flags)
 {
-       int len = strlen(src);
-       if (flags & CLISTR_TERMINATE) len++;
-       if (!(flags & CLISTR_ASCII) && (cli->capabilities & CAP_UNICODE)) len *= 2;
-
-       if (!(flags & CLISTR_ASCII) && dest && clistr_align(cli, PTR_DIFF(cli->outbuf, dest))) {
-               len++;
-       }
-
-       return len;
+       return pull_string_fn(function, line, inbuf,
+                             SVAL(inbuf, smb_flg2), dest, src, dest_len,
+                             src_len, flags);
 }
 
-/****************************************************************************
-copy a string from a unicode or ascii source (depending on
-cli->capabilities) to a char* destination
-flags can have:
-  CLISTR_CONVERT   means convert from dos to unix codepage
-  CLISTR_TERMINATE means the string in src is null terminated
-if CLISTR_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 clistr_pull(struct cli_state *cli, char *dest, const void *src, int dest_len, int src_len, int flags)
+size_t clistr_pull_talloc_fn(const char *function,
+                               unsigned int line,
+                               TALLOC_CTX *ctx,
+                               const char *inbuf,
+                               char **pp_dest,
+                               const void *src,
+                               int src_len,
+                               int flags)
 {
-       int len;
-
-       if (dest_len == -1) {
-               dest_len = sizeof(pstring);
-       }
-
-       if (clistr_align(cli, PTR_DIFF(cli->inbuf, src))) {
-               src++;
-               if (src_len > 0) src_len--;
-       }
-
-       if (!(cli->capabilities & CAP_UNICODE)) {
-               /* the server doesn't want unicode */
-               if (flags & CLISTR_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 & CLISTR_CONVERT) dos_to_unix(dest,True);
-               return len;
-       }
-
-       if (flags & CLISTR_TERMINATE) {
-               unistr_to_ascii(dest, src, dest_len);
-               len = strlen(dest)*2 + 2;
-       } else {
-               int i, c;
-               if (dest_len < src_len) src_len = dest_len;
-               for (i=0; i < src_len; i += 2) {
-                       c = SVAL(src, i);
-                       *dest++ = c;
-               }
-               *dest++ = 0;
-               len = src_len;
-       }
-       if (flags & CLISTR_CONVERT) dos_to_unix(dest,True);
-       return len;
+       return pull_string_talloc_fn(function,
+                                       line,
+                                       ctx,
+                                       inbuf,
+                                       SVAL(inbuf, smb_flg2),
+                                       pp_dest,
+                                       src,
+                                       src_len,
+                                       flags);
 }
 
-/****************************************************************************
-return the length that a string would occupy (not including the null)
-when copied with clistr_pull()
-if src_len is -1 then assume the source is null terminated
-****************************************************************************/
-int clistr_pull_size(struct cli_state *cli, const void *src, int src_len)
+size_t clistr_align_out(struct cli_state *cli, const void *p, int flags)
 {
-       if (clistr_align(cli, PTR_DIFF(cli->inbuf, src))) {
-               src++;
-               if (src_len > 0) src_len--;
-       }
-
-       if (!(cli->capabilities & CAP_UNICODE)) {
-               return strlen(src);
-       }       
-       return strlen_w(src);
+       return align_string(cli->outbuf, (const char *)p, flags);
 }
 
-/****************************************************************************
-return an alignment of either 0 or 1
-if unicode is not negotiated then return 0
-otherwise return 1 if offset is off
-****************************************************************************/
-int clistr_align(struct cli_state *cli, int offset)
+size_t clistr_align_in(struct cli_state *cli, const void *p, int flags)
 {
-       if (!(cli->capabilities & CAP_UNICODE)) return 0;
-       return offset & 1;
+       return align_string(cli->inbuf, (const char *)p, flags);
 }