Browse Source

Use iconv to handle encoding. Adds detection of system's locale

Julien 'Lta' BALLET 11 years ago
parent
commit
52842e9f78
6 changed files with 89 additions and 25 deletions
  1. 1 0
      .gitignore
  2. 5 5
      Makefile
  3. 34 4
      include/bdsm/smb_utils.h
  4. 1 1
      src/smb_message.c
  5. 4 4
      src/smb_ntlm.c
  6. 44 11
      src/smb_utils.c

+ 1 - 0
.gitignore

@@ -8,3 +8,4 @@ discover
 lookup
 inverse
 
+doc/html/*

+ 5 - 5
Makefile

@@ -19,7 +19,7 @@
 
 
 CFLAGS      	= -Iinclude -I contrib -DBDSM_DEBUG=1 -D_BSD_SOURCE -std=c99 -fPIC
-LDFLAGS     	= #-levent
+LDFLAGS     	=
 CC          	= clang
 AR						= ar
 RANLIB				= ranlib
@@ -55,6 +55,9 @@ LIB_OBJS			= $(LIB_SRC:.c=.o)
 
 all: $(LIB) $(LIB_STATIC) $(UTILS)
 
+doc:
+	doxygen
+
 clean:
 	rm -f $(UTILS) $(LIB) $(LIB_STATIC) *.o
 	rm -rf $(LIB_OBJS)
@@ -67,9 +70,6 @@ $(LIB): $(LIB_OBJS)
 $(LIB_STATIC): $(LIB_OBJS)
 	$(AR) -rcs $@ $(LIB_OBJS)
 
-
-test:
-
 dsm: $(LIB) $(DSM_SRC)
 	$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(DSM_SRC) $(LIB_STATIC)
 discover: $(LIB) $(DISCOVER_SRC)
@@ -83,4 +83,4 @@ lookup:  $(LIB) $(LOOKUP_SRC)
 	$(CC) -c $(CFLAGS) -o $@ $<
 
 
-.PHONY: all clean re
+.PHONY: all clean re doc

+ 34 - 4
include/bdsm/smb_utils.h

@@ -16,14 +16,44 @@
 // published by Sam Hocevar. See the COPYING file for more details.
 //----------------------------------------------------------------------------
 
+/**
+ * @file smb_utils.h
+ * @brief SMB helper functions
+ */
+
 #ifndef __BDSM_SMB_UTILS_H_
 #define __BDSM_SMB_UTILS_H_
 
 #include <stdint.h>
 
-// Only ASCII is supported yet as src_enc. dst will be set to newly allocated
-// memory You'll have to call free() on it after use
-size_t      smb_to_utf16(const char *src_enc, const char *src,
-                         size_t src_len, char **dst);
+/**
+ * @internal
+ * @brief Converts a string from current locale encoding to UCS2-LE
+ * @details It allocates the output string on the heap, you have to free it !
+ *
+ * @param[in] src The input string. It is considere to be in the current locale
+ * @param[in] src_len The length in byte of the input string (strlen will do
+ *  the job for utf-8 or single byte encoding)
+ * @param[out] dst Will be set to the newly allocated encoded string, you have
+ *  to free() it after usage unless the function returns 0, in that case, it'll
+ *  be set to NULL
+ * @return The size of the encoded string in bytes
+ */
+size_t      smb_to_utf16(const char *src, size_t src_len, char **dst);
+
+/**
+ * @internal
+ * @brief Converts from UCS2-LE to local encoding (fetched using setlocale())
+ * @details It returns a newly allocated string that you need to free
+ * after usage
+ *
+ * @param[in] src The UCS2-LE string to be converved to local encoding
+ * @param[in] src_len The size in bytes of src
+ * @param[out] dst will be set to the newly allocated and converted string.
+ *   You have to free() it unless the function returns 0, in that case, it'll
+ *   be set to NULL
+ * @return The size of the decoded string in bytes
+ */
+size_t      smb_from_utf16(const char *src, size_t src_len, char **dst);
 
 #endif

+ 1 - 1
src/smb_message.c

@@ -114,7 +114,7 @@ size_t          smb_message_put_utf16(smb_message_t *msg, const char *src_enc,
   size_t        utf_str_len;
   int           res;
 
-  utf_str_len = smb_to_utf16(src_enc, str, str_len, &utf_str);
+  utf_str_len = smb_to_utf16(str, str_len, &utf_str);
   res = smb_message_append(msg, utf_str, utf_str_len);
   free(utf_str);
 

+ 4 - 4
src/smb_ntlm.c

@@ -51,7 +51,7 @@ void        smb_ntlm_hash(const char *password, smb_ntlmh_t *hash)
 
   assert(password != NULL && hash != NULL);
 
-  sz = smb_to_utf16("ASCII", password, strlen(password), &ucs2le_pass);
+  sz = smb_to_utf16(password, strlen(password), &ucs2le_pass);
   memset((void *)hash, 0, SMB_NTLM_HASH_SIZE);
 
   MD4_Init(&ctx);
@@ -71,8 +71,8 @@ void        smb_ntlm2_hash(const char *user, const char *password,
 
   smb_ntlm_hash(password, &hash_v1);
 
-  ucs_user_len  = smb_to_utf16("", user, strlen(user), &ucs_user);
-  ucs_dest_len  = smb_to_utf16("", dest, strlen(dest), &ucs_dest);
+  ucs_user_len  = smb_to_utf16(user, strlen(user), &ucs_user);
+  ucs_dest_len  = smb_to_utf16(dest, strlen(dest), &ucs_dest);
   data_len      = ucs_user_len + ucs_dest_len;
   data          = alloca(data_len);
 
@@ -122,7 +122,7 @@ size_t      smb_ntlm_blob(smb_ntlm_blob_t *blob, uint64_t ts,
   blob->timestamp = ts;
   blob->challenge = user_challenge;
 
-  ucs_domain_len = smb_to_utf16("", domain, strlen(domain), &ucs_domain);
+  ucs_domain_len = smb_to_utf16(domain, strlen(domain), &ucs_domain);
   *((uint16_t *)blob->domain)     = 0x0002;   // type == Netbios domain
   *((uint16_t *)blob->domain + 1) = ucs_domain_len;
 

+ 44 - 11
src/smb_utils.c

@@ -16,28 +16,61 @@
 // published by Sam Hocevar. See the COPYING file for more details.
 //----------------------------------------------------------------------------
 
+#include <assert.h>
+#include <iconv.h>
+#include <langinfo.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 
 #include "bdsm/smb_utils.h"
 
-size_t      smb_to_utf16(const char *src_enc, const char *src,
-                         size_t src_len, char **dst)
+static const char *current_encoding()
+{
+  return (nl_langinfo(CODESET));
+}
+
+static size_t smb_iconv(const char *src, size_t src_len, char **dst,
+                        size_t dst_len, const char *src_enc,
+                        const char *dst_enc)
 {
-  size_t    res = src_len * 2;
+  iconv_t   ic;
   char      *out;
+  size_t    outleft;
 
-  out = malloc(res);
-  assert(out != NULL);
-  *dst = (char *)out;
+  assert(src != NULL && dst != NULL && src_enc != NULL && dst_enc != NULL);
+
+  if (!src_len)
+  {
+    *dst = NULL;
+    return (0);
+  }
 
-  for (size_t i = 0; i < src_len; i++)
+  if ((ic = iconv_open(dst_enc, src_enc)) < 0)
   {
-    out[2 * i]      = src[i];
-    out[2 * i + 1]  = 0;
+    fprintf(stderr, "Unable to open iconv to convert from %s to %s\n",
+            src_enc, dst_enc);
+    return (0);
   }
 
-  return (res);
+  outleft = dst_len; // The utf-16 str is at most 2x bigger than the utf-8 one. (i think ?)
+  out     = *dst = malloc(outleft);
 
+  assert(out != NULL);
+  iconv(ic, (char **)&src, &src_len, &out, &outleft);
+  assert(src_len == 0);
+
+  return (dst_len - outleft);
+}
+
+size_t      smb_to_utf16(const char *src, size_t src_len, char **dst)
+{
+  return(smb_iconv(src, src_len, dst, src_len * 2,
+         current_encoding(), "UCS-2LE"));
+}
+
+size_t      smb_from_utf16(const char *src, size_t src_len, char **dst)
+{
+  return(smb_iconv(src, src_len, dst, src_len,
+         "UCS-2LE", current_encoding()));
 }