A problem in handling multibyte character (and more)

kawasa_r at itg.hitachi.co.jp kawasa_r at itg.hitachi.co.jp
Thu Jan 15 15:35:06 GMT 2004


We've fixed three problems in samba3.0.0 so far. So I post patches for them. Maybe some of these problems are already fixed in the latest version, though.

[Problem-1]
The smbd is crushed when the file "test.txt" under the directory "test" is copied as "******(multi byte characters)test.txt" in the same directory.

[Cause]
In this case, the file name is exchanged from UTF-8(default setting of unix charset) to UCS-2, 
then it is exchanged from capital letter to small letter. 
If the invalid multi-byte character is included in the file name, exchange from UTF-8 to UCS-2 is failed. But smbd does not detect this error, so it try to exchange UTF-8 character(not UCS-2) from capital letter to small letter then segmentation violation is occurred.
(Invalid multi-byte character is created in the process of samba-300/source/smbd/open.c:line 76 to 77.)

[Countermeasure]
Check the result of iconv() which exchanges character code.

-------------


Index: samba-300/source/lib/charcnv.c
===================================================================
RCS file: /cvs/samba-300/source/lib/charcnv.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- samba-300/source/lib/charcnv.c	1 Oct 2003 04:26:41 -0000	1.1
+++ samba-300/source/lib/charcnv.c	19 Nov 2003 04:22:24 -0000	1.2
@@ -373,7 +373,7 @@
  **/
 
 size_t convert_string_allocate(TALLOC_CTX *ctx, charset_t from, charset_t to,
-			       void const *src, size_t srclen, void **dest)
+			       void const *src, size_t srclen, void **dest, int *as_is)
 {
 	size_t i_len, o_len, destlen = MAX(srclen, 512);
 	size_t retval;
@@ -382,6 +382,7 @@
 	smb_iconv_t descriptor;
 
 	*dest = NULL;
+	*as_is = 0;
 
 	if (src == NULL || srclen == (size_t)-1)
 		return (size_t)-1;
@@ -466,6 +467,7 @@
 
   use_as_is:
 
+	*as_is = 1;
 	/* conversion not supported, use as is */
 	{
 		if (srclen && (destlen != srclen)) {
@@ -502,9 +504,10 @@
 		      		void const *src, size_t srclen, void **dest)
 {
 	size_t dest_len;
+	int as_is = 0;
 
 	*dest = NULL;
-	dest_len=convert_string_allocate(ctx, from, to, src, srclen, dest);
+	dest_len=convert_string_allocate(ctx, from, to, src, srclen, dest, &as_is);
 	if (dest_len == (size_t)-1)
 		return (size_t)-1;
 	if (*dest == NULL)
@@ -516,11 +519,19 @@
 {
 	size_t size;
 	smb_ucs2_t *buffer;
+	int as_is = 0;
 	
-	size = push_ucs2_allocate(&buffer, src);
+	size = push_ucs2_allocate(&buffer, src, &as_is);
 	if (size == -1) {
 		smb_panic("failed to create UCS2 buffer");
 	}
+	if (as_is) {
+		if (dest != src) {
+			size = convert_string(CH_UNIX, CH_UNIX, buffer, size, dest, destlen);
+		}
+		free(buffer);
+		return size;
+	}
 	if (!strupper_w(buffer) && (dest == src)) {
 		free(buffer);
 		return srclen;
@@ -582,12 +593,20 @@
 {
 	size_t size;
 	smb_ucs2_t *buffer;
-	
+	int as_is = 0;
+
 	size = convert_string_allocate(NULL, CH_UNIX, CH_UCS2, src, srclen,
-				       (void **) &buffer);
+				       (void **) &buffer, &as_is);
 	if (size == -1) {
 		smb_panic("failed to create UCS2 buffer");
 	}
+	if (as_is) {
+		if (dest != src) {
+			size = convert_string(CH_UNIX, CH_UNIX, buffer, size, dest, destlen);
+		}
+		free(buffer);
+		return size;
+	}
 	if (!strlower_w(buffer) && (dest == src)) {
 		free(buffer);
 		return srclen;
@@ -606,8 +625,9 @@
 	size_t size;
 	smb_ucs2_t *buffer;
 	char *out_buffer;
+	int as_is = 0;
 	
-	size = push_ucs2_allocate(&buffer, s);
+	size = push_ucs2_allocate(&buffer, s, &as_is);
 	if (size == -1) {
 		return NULL;
 	}
@@ -826,12 +846,12 @@
  *         or -1 in case of error.
  **/
 
-size_t push_ucs2_allocate(smb_ucs2_t **dest, const char *src)
+size_t push_ucs2_allocate(smb_ucs2_t **dest, const char *src, int *as_is)
 {
 	size_t src_len = strlen(src)+1;
 
 	*dest = NULL;
-	return convert_string_allocate(NULL, CH_UNIX, CH_UCS2, src, src_len, (void **)dest);	
+	return convert_string_allocate(NULL, CH_UNIX, CH_UCS2, src, src_len, (void **)dest, as_is);
 }
 
 /**
@@ -897,9 +917,10 @@
 size_t push_utf8_allocate(char **dest, const char *src)
 {
 	size_t src_len = strlen(src)+1;
+	int as_is = 0;
 
 	*dest = NULL;
-	return convert_string_allocate(NULL, CH_UNIX, CH_UTF8, src, src_len, (void **)dest);	
+	return convert_string_allocate(NULL, CH_UNIX, CH_UTF8, src, src_len, (void **)dest, &as_is);
 }
 
 /**
@@ -984,9 +1005,10 @@
 
 size_t pull_ucs2_allocate(char **dest, const smb_ucs2_t *src)
 {
+	int as_is = 0;
 	size_t src_len = (strlen_w(src)+1) * sizeof(smb_ucs2_t);
 	*dest = NULL;
-	return convert_string_allocate(NULL, CH_UCS2, CH_UNIX, src, src_len, (void **)dest);	
+	return convert_string_allocate(NULL, CH_UCS2, CH_UNIX, src, src_len, (void **)dest, &as_is);
 }
 
 /**
@@ -1014,9 +1036,10 @@
 
 size_t pull_utf8_allocate(void **dest, const char *src)
 {
+	int as_is = 0;
 	size_t src_len = strlen(src)+1;
 	*dest = NULL;
-	return convert_string_allocate(NULL, CH_UTF8, CH_UNIX, src, src_len, dest);	
+	return convert_string_allocate(NULL, CH_UTF8, CH_UNIX, src, src_len, dest, &as_is);
 }
  
 /**



Index: samba-300/source/libsmb/climessage.c
===================================================================
RCS file: /cvs/samba-300/source/libsmb/climessage.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- samba-300/source/libsmb/climessage.c	1 Oct 2003 04:26:42 -0000	1.1
+++ samba-300/source/libsmb/climessage.c	19 Nov 2003 04:24:56 -0000	1.2
@@ -75,6 +75,7 @@
 	char *msgdos;
 	int lendos;
 	char *p;
+	int as_is = 0;
 
 	memset(cli->outbuf,'\0',smb_size);
 	set_message(cli->outbuf,1,0,True);
@@ -87,7 +88,7 @@
 	p = smb_buf(cli->outbuf);
 	*p++ = 1;
 
-	if ((lendos = convert_string_allocate(NULL,CH_UNIX, CH_DOS, msg,len, (void **) &msgdos)) < 0 || !msgdos) {
+	if ((lendos = convert_string_allocate(NULL,CH_UNIX, CH_DOS, msg,len, (void **) &msgdos, &as_is)) < 0 || !msgdos) {
 		DEBUG(3,("Conversion failed, sending message in UNIX charset\n"));
 		SSVAL(p, 0, len); p += 2;
 		memcpy(p, msg, len);


Index: samba-300/source/smbd/mangle_hash.c
===================================================================
RCS file: /cvs/samba-300/source/smbd/mangle_hash.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- samba-300/source/smbd/mangle_hash.c	1 Oct 2003 04:26:43 -0000	1.1
+++ samba-300/source/smbd/mangle_hash.c	19 Nov 2003 04:25:21 -0000	1.2
@@ -314,6 +314,7 @@
 	smb_ucs2_t *ucs2name;
 	NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
 	size_t size;
+	int as_is = 0;
 
 	if (!fname || !*fname)
 		return False;
@@ -325,7 +326,7 @@
 	if (strlen(f) > 12)
 		return False;
 	
-	size = push_ucs2_allocate(&ucs2name, f);
+	size = push_ucs2_allocate(&ucs2name, f, &as_is);
 	if (size == (size_t)-1) {
 		DEBUG(0,("is_8_3: internal error push_ucs2_allocate() failed!\n"));
 		goto done;
@@ -729,10 +730,11 @@
 static void name_map(char *OutName, BOOL need83, BOOL cache83)
 {
 	smb_ucs2_t *OutName_ucs2;
+	int as_is = 0;
 	DEBUG(5,("name_map( %s, need83 = %s, cache83 = %s)\n", OutName,
 		 need83 ? "True" : "False", cache83 ? "True" : "False"));
 	
-	if (push_ucs2_allocate(&OutName_ucs2, OutName) == (size_t)-1) {
+	if (push_ucs2_allocate(&OutName_ucs2, OutName, &as_is) == (size_t)-1) {
 		DEBUG(0, ("push_ucs2_allocate failed!\n"));
 		return;
 	}


Index: samba-300/source/smbd/message.c
===================================================================
RCS file: /cvs/samba-300/source/smbd/message.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- samba-300/source/smbd/message.c	1 Oct 2003 04:26:43 -0000	1.1
+++ samba-300/source/smbd/message.c	19 Nov 2003 04:25:25 -0000	1.2
@@ -43,6 +43,7 @@
   int fd;
   char *msg;
   int len;
+  int as_is = 0;
 
   if (! (*lp_msg_command()))
     {
@@ -64,7 +65,7 @@
    * Incoming message is in DOS codepage format. Convert to UNIX.
    */
   
-  if ((len = convert_string_allocate(NULL,CH_DOS, CH_UNIX, msgbuf, msgpos, (void **) &msg)) < 0 || !msg) {
+  if ((len = convert_string_allocate(NULL,CH_DOS, CH_UNIX, msgbuf, msgpos, (void **) &msg, &as_is)) < 0 || !msg) {
     DEBUG(3,("Conversion failed, delivering message in DOS codepage format\n"));
     for (i = 0; i < msgpos;) {
       if (msgbuf[i] == '\r' && i < (msgpos-1) && msgbuf[i+1] == '\n') {


Index: samba-300/source/libsmb/smbencrypt.c
===================================================================
RCS file: /cvs/samba-300/source/libsmb/smbencrypt.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- samba-300/source/libsmb/smbencrypt.c	1 Oct 2003 04:26:42 -0000	1.1
+++ samba-300/source/libsmb/smbencrypt.c	19 Nov 2003 04:25:07 -0000	1.2
@@ -127,14 +127,16 @@
 	size_t domain_byte_len;
 
 	HMACMD5Context ctx;
+	int as_is = 0;
 
-	user_byte_len = push_ucs2_allocate(&user, user_in);
+	user_byte_len = push_ucs2_allocate(&user, user_in, &as_is);
 	if (user_byte_len == (size_t)-1) {
 		DEBUG(0, ("push_uss2_allocate() for user returned -1 (probably malloc() failure)\n"));
 		return False;
 	}
 
-	domain_byte_len = push_ucs2_allocate(&domain, domain_in);
+	as_is = 0;
+	domain_byte_len = push_ucs2_allocate(&domain, domain_in, &as_is);
 	if (domain_byte_len == (size_t)-1) {
 		DEBUG(0, ("push_uss2_allocate() for domain returned -1 (probably malloc() failure)\n"));
 		return False;


Index: samba-300/source/lib/util_str.c
===================================================================
RCS file: /cvs/samba-300/source/lib/util_str.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- samba-300/source/lib/util_str.c	1 Oct 2003 04:26:42 -0000	1.1
+++ samba-300/source/lib/util_str.c	19 Nov 2003 04:24:31 -0000	1.2
@@ -184,6 +184,7 @@
 	size_t size;
 	smb_ucs2_t *buffer_s, *buffer_t;
 	int ret;
+	int as_is = 0;
 
 	for (ps = s, pt = t; ; ps++, pt++) {
 		char us, ut;
@@ -208,14 +209,15 @@
 			return +1;
 	}
 
-	size = push_ucs2_allocate(&buffer_s, s);
+	size = push_ucs2_allocate(&buffer_s, s, &as_is);
 	if (size == (size_t)-1) {
 		return strcmp(s, t); 
 		/* Not quite the right answer, but finding the right one
 		   under this failure case is expensive, and it's pretty close */
 	}
 	
-	size = push_ucs2_allocate(&buffer_t, t);
+	as_is = 0;
+	size = push_ucs2_allocate(&buffer_t, t, &as_is);
 	if (size == (size_t)-1) {
 		SAFE_FREE(buffer_s);
 		return strcmp(s, t); 



[Problem-2]
When network error is occurred in case of receiving data from client, the smbd process does not finish until disconnecting time is over keepalive time.

[Cause]
In case of receiving data from client, the read() system call does not check error occurrence. 

[Countermeasure]
Before read() is issued, add select() system call for checking timeout of network error.

-------------

Index: samba-300/source/lib/util_sock.c
===================================================================
RCS file: /cvs/samba-300/source/lib/util_sock.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- samba-300/source/lib/util_sock.c	1 Oct 2003 04:26:42 -0000	1.1
+++ samba-300/source/lib/util_sock.c	30 Oct 2003 14:27:10 -0000	1.2
@@ -327,9 +327,28 @@
 	ssize_t ret;
 	size_t total=0;  
  
+	fd_set fds ;
+	ssize_t selrtn ;
+	struct timeval tv ;
+
 	smb_read_error = 0;
 
+	tv.tv_sec = 180 ;
+	tv.tv_usec = 0 ;
+
 	while (total < N) {
+
+		FD_ZERO(&fds);
+		FD_SET(fd, &fds) ;
+
+		selrtn = sys_select_intr(fd + 1,&fds,NULL,NULL,&tv);
+		if (selrtn == -1 || selrtn == 0) {
+			DEBUG(0,("read_socket_data: timeout read. (read_data=%d) select error = %s.\n", 
+				(int)(N - total), strerror(errno) ));
+			smb_read_error = READ_ERROR;
+			return -1 ;
+		}
+		
 		ret = sys_read(fd,buffer + total,N - total);
 
 		if (ret == 0) {




[Problem-3]
The secrets.tbd file could not be changed by accessed NetBIOS name even if "%L" is set to "private dir" parameter in smb.conf. 

[Cause]
When smbd is accessed fro client, it issues tdb_reopen_all() function.
But in this time, smbd does not receive NetBIOS name, so NetBIOS name is not set even if "%L" is set to "private dir" parameter.

[Countermeasure]
Re-open secrets.tdb when smbd received "session request" message from client.

-------------


Index: samba-300/source/smbd/reply.c
===================================================================
RCS file: /cvs/samba-300/source/smbd/reply.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- samba-300/source/smbd/reply.c	1 Oct 2003 04:26:43 -0000	1.1
+++ samba-300/source/smbd/reply.c	1 Oct 2003 07:33:31 -0000	1.2
@@ -116,6 +116,9 @@
 		reload_services(True);
 		reopen_logs();
 
+		if (!secrets_reopen())
+			DEBUG(0,("secrets_reopen failed.\n"));
+
 		claim_connection(NULL,"",0,True,FLAG_MSG_GENERAL|FLAG_MSG_SMBD);
 
 		already_got_session = True;
Index: samba-300/source/passdb/secrets.c
===================================================================
RCS file: /cvs/samba-300/source/passdb/secrets.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- samba-300/source/passdb/secrets.c	1 Oct 2003 04:26:42 -0000	1.1
+++ samba-300/source/passdb/secrets.c	1 Oct 2003 07:33:18 -0000	1.2
@@ -49,6 +49,17 @@
 	return True;
 }
 
+/* reopen the secrets database */
+BOOL secrets_reopen(void)
+{
+	if(tdb) {
+		tdb_close(tdb);
+		tdb = NULL;
+	}
+
+	return secrets_init();
+}
+
 /* read a entry from the secrets database - the caller must free the result
    if size is non-null then the size of the entry is put in there
  */






More information about the samba-technical mailing list