started support for unicode on the wire in smbd. Using a very similar
authorAndrew Tridgell <tridge@samba.org>
Sat, 10 Mar 2001 11:38:27 +0000 (11:38 +0000)
committerAndrew Tridgell <tridge@samba.org>
Sat, 10 Mar 2001 11:38:27 +0000 (11:38 +0000)
method to what was used in the client I now have session setup and
tconx working.

Currently this is enabled with SMBD_USE_UNICODE environment
variable. Once the code is complete this will become a smb.conf
option.
(This used to be commit 7684c1e67294266d018c6f0cab58f1a9d797174f)

source3/Makefile.in
source3/lib/util.c
source3/smbd/negprot.c
source3/smbd/reply.c
source3/smbd/srvstr.c [new file with mode: 0644]

index 7760b29522f1058a22767b5c993c85e41bc580c7..a6e8dd32d9d358f5eb1b232a8c7527809a51e79c 100644 (file)
@@ -195,7 +195,7 @@ SMBD_OBJ1 = smbd/server.o smbd/files.o smbd/chgpasswd.o smbd/connection.o \
            smbd/vfs.o smbd/vfs-wrap.o smbd/statcache.o \
             smbd/posix_acls.o lib/msrpc-client.o lib/msrpc_use.o \
            smbd/process.o smbd/service.o smbd/error.o \
-           printing/printfsp.o lib/util_seaccess.o
+           printing/printfsp.o lib/util_seaccess.o smbd/srvstr.o
 
 PRINTING_OBJ = printing/pcap.o printing/print_svid.o printing/print_cups.o printing/load.o
 
index 70513c068eec2dc18db02e194a9d8cda1f913e40..8ad2cfd713f8cda8b5cd3bcf62c79e569aa15f92 100644 (file)
@@ -353,6 +353,15 @@ void set_message_bcc(char *buf,int num_bytes)
        smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4);
 }
 
+/*******************************************************************
+  setup only the byte count for a smb message, using the end of the
+  message as a marker
+********************************************************************/
+void set_message_end(void *outbuf,void *end_ptr)
+{
+       set_message_bcc(outbuf,PTR_DIFF(end_ptr,smb_buf(outbuf)));
+}
+
 /*******************************************************************
 reduce a file name, removing .. elements.
 ********************************************************************/
index 74d8eb39833e19b6786dc851db9732fac9d4fb93..c2026f46f9f67bdff0e41728c3d2ddb89bb9acac 100644 (file)
@@ -201,6 +201,12 @@ static int reply_nt1(char *outbuf)
          capabilities |= CAP_RAW_MODE;
   }
 
+
+  /* until the unicode conversion is complete have it disabled by default */
+  if (getenv("SMBD_USE_UNICODE")) {
+         capabilities |= CAP_UNICODE;
+  }
+
 #ifdef WITH_MSDFS
   if(lp_host_msdfs())
        capabilities |= CAP_DFS;
index 4e87782a4835d81d8d8ea44f085e0b8f1f854cdb..4f98c264b89c8853116f57d7c47d1e20550d4d4c 100644 (file)
@@ -273,12 +273,11 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
        pstring user;
        pstring password;
        pstring devicename;
-       BOOL doencrypt = SMBENCRYPT();
        int ecode = -1;
        uint16 vuid = SVAL(inbuf,smb_uid);
        int passlen = SVAL(inbuf,smb_vwv3);
-       char *path;
-       char *p;
+       pstring path;
+       char *p, *q;
        START_PROFILE(SMBtconX);
        
        *service = *user = *password = *devicename = 0;
@@ -294,7 +293,8 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
  
        memcpy(password,smb_buf(inbuf),passlen);
        password[passlen]=0;    
-       path = smb_buf(inbuf) + passlen;
+       p = smb_buf(inbuf) + passlen;
+       p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE|STR_CONVERT);
 
        if (passlen != 24) {
                if (strequal(password," "))
@@ -302,27 +302,20 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
                passlen = strlen(password);
        }
        
-       p = strchr(path+2,'\\');
-       if (!p) {
+       q = strchr(path+2,'\\');
+       if (!q) {
                END_PROFILE(SMBtconX);
                return(ERROR(ERRDOS,ERRnosuchshare));
        }
-       fstrcpy(service,p+1);
-       p = strchr(service,'%');
-       if (p) {
-               *p++ = 0;
-               fstrcpy(user,p);
+       fstrcpy(service,q+1);
+       q = strchr(service,'%');
+       if (q) {
+               *q++ = 0;
+               fstrcpy(user,q);
        }
-       StrnCpy(devicename,path + strlen(path) + 1,6);
-       DEBUG(4,("Got device type %s\n",devicename));
+       p += srvstr_pull(inbuf, devicename, p, sizeof(devicename), 6, STR_CONVERT);
 
-       /*
-        * Ensure the user and password names are in UNIX codepage format.
-        */
-
-       dos_to_unix(user,True);
-       if (!doencrypt)
-               dos_to_unix(password,True);
+       DEBUG(4,("Got device type %s\n",devicename));
 
        /*
         * Pass the user through the NT -> unix user mapping
@@ -349,13 +342,13 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
        } else {
                char *fsname = lp_fstype(SNUM(conn));
 
-               set_message(outbuf,3,3,True);
+               set_message(outbuf,3,0,True);
 
                p = smb_buf(outbuf);
-               pstrcpy(p,devicename); p = skip_string(p,1); /* device name */
-               pstrcpy(p,fsname); p = skip_string(p,1); /* filesystem type e.g NTFS */
+               p += srvstr_push(inbuf, outbuf, p, devicename, -1, STR_CONVERT|STR_TERMINATE);
+               p += srvstr_push(inbuf, outbuf, p, fsname, -1, STR_CONVERT|STR_TERMINATE);
                
-               set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
+               set_message_end(outbuf,p);
                
                /* what does setting this bit do? It is set by NT4 and
                   may affect the ability to autorun mounted cdroms */
@@ -703,10 +696,12 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
   BOOL valid_lm_password = False;
   pstring user;
   pstring orig_user;
+  fstring domain;
+  fstring native_os;
+  fstring native_lanman;
   BOOL guest=False;
   static BOOL done_sesssetup = False;
   BOOL doencrypt = SMBENCRYPT();
-  char *domain = "";
   START_PROFILE(SMBsesssetupX);
 
   *smb_apasswd = 0;
@@ -835,17 +830,19 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
     }
     
     p += passlen1 + passlen2;
-    fstrcpy(user,p);
-    p = skip_string(p,1);
+    p += srvstr_pull(inbuf, user, p, sizeof(user), -1, STR_CONVERT|STR_TERMINATE);
     /*
      * Incoming user and domain are in DOS codepage format. Convert
      * to UNIX.
      */
-    dos_to_unix(user,True);
-    domain = p;
-    dos_to_unix(domain, True);
+    p += srvstr_pull(inbuf, domain, p, sizeof(domain), 
+                    -1, STR_CONVERT|STR_TERMINATE);
+    p += srvstr_pull(inbuf, native_os, p, sizeof(native_os), 
+                    -1, STR_CONVERT|STR_TERMINATE);
+    p += srvstr_pull(inbuf, native_lanman, p, sizeof(native_lanman),
+                    -1, STR_CONVERT|STR_TERMINATE);
     DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
-            domain,skip_string(p,1),skip_string(p,2)));
+            domain,native_os,native_lanman));
   }
 
   DEBUG(3,("sesssetupX:name=[%s]\n",user));
@@ -1027,12 +1024,12 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int
     set_message(outbuf,3,0,True);
   } else {
     char *p;
-    set_message(outbuf,3,3,True);
+    set_message(outbuf,3,0,True);
     p = smb_buf(outbuf);
-    pstrcpy(p,"Unix"); p = skip_string(p,1);
-    pstrcpy(p,"Samba "); pstrcat(p,VERSION); p = skip_string(p,1);
-    pstrcpy(p,global_myworkgroup); unix_to_dos(p, True); p = skip_string(p,1);
-    set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
+    p += srvstr_push(inbuf, outbuf, p, "Unix", -1, STR_TERMINATE|STR_CONVERT);
+    p += srvstr_push(inbuf, outbuf, p, "Samba", -1, STR_TERMINATE|STR_CONVERT);
+    p += srvstr_push(inbuf, outbuf, p, global_myworkgroup, -1, STR_TERMINATE|STR_CONVERT);
+    set_message_end(outbuf,p);
     /* perhaps grab OS version here?? */
   }
 
diff --git a/source3/smbd/srvstr.c b/source3/smbd/srvstr.c
new file mode 100644 (file)
index 0000000..e420b8f
--- /dev/null
@@ -0,0 +1,186 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 3.0
+   server specific 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.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+#define UNICODE_FLAG() (SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS)
+
+/****************************************************************************
+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 *inbuf, void *outbuf, void *dest, const char *src, int dest_len, int flags)
+{
+       int len=0;
+
+       /* treat a pstring as "unlimited" length */
+       if (dest_len == -1) {
+               dest_len = sizeof(pstring);
+       }
+
+       if (!(flags & STR_ASCII) && srvstr_align(inbuf, PTR_DIFF(dest, outbuf))) {
+               *(char *)dest = 0;
+               dest++;
+               dest_len--;
+               len++;
+       }
+
+       if ((flags & STR_ASCII) || !UNICODE_FLAG()) {
+               /* 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);
+       }
+       len += strlen(src)*2;
+       if (flags & STR_TERMINATE) len += 2;
+       return len;
+}
+
+
+/****************************************************************************
+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 *inbuf, void *outbuf, 
+                    const void *dest, const char *src, int dest_len, int flags)
+{
+       int len = strlen(src);
+       if (flags & STR_TERMINATE) len++;
+       if (!(flags & STR_ASCII) && UNICODE_FLAG()) len *= 2;
+
+       if (!(flags & STR_ASCII) && dest && srvstr_align(inbuf, PTR_DIFF(outbuf, dest))) {
+               len++;
+       }
+
+       return len;
+}
+
+/****************************************************************************
+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 (srvstr_align(inbuf, PTR_DIFF(src, inbuf))) {
+               src++;
+               if (src_len > 0) src_len--;
+       }
+
+       if (!(flags & STR_UNICODE) && !UNICODE_FLAG()) {
+               /* 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--;
+       }
+
+       if (!UNICODE_FLAG()) {
+               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()) return 0;
+       return offset & 1;
+}