LCOV - code coverage report
Current view: top level - source3/lib - charcnv.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 139 180 77.2 %
Date: 2024-02-28 12:06:22 Functions: 10 11 90.9 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Character set conversion Extensions
       4             :    Copyright (C) Igor Vergeichik <iverg@mail.ru> 2001
       5             :    Copyright (C) Andrew Tridgell 2001
       6             :    Copyright (C) Simo Sorce 2001
       7             :    Copyright (C) Martin Pool 2003
       8             : 
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : 
      22             : */
      23             : #include "includes.h"
      24             : 
      25             : /**
      26             :  * Destroy global objects allocated by init_iconv()
      27             :  **/
      28       18628 : void gfree_charcnv(void)
      29             : {
      30       18628 :         free_iconv_handle();
      31       18628 : }
      32             : 
      33             : /**
      34             :  * Copy a string from a char* unix src to a dos codepage string destination.
      35             :  *
      36             :  * @return the number of bytes occupied by the string in the destination.
      37             :  *
      38             :  * @param flags can include
      39             :  * <dl>
      40             :  * <dt>STR_TERMINATE</dt> <dd>means include the null termination</dd>
      41             :  * <dt>STR_UPPER</dt> <dd>means uppercase in the destination</dd>
      42             :  * </dl>
      43             :  *
      44             :  * @param dest_len the maximum length in bytes allowed in the
      45             :  * destination.
      46             :  **/
      47       92481 : size_t push_ascii(void *dest, const char *src, size_t dest_len, int flags)
      48             : {
      49       92481 :         size_t src_len = 0;
      50       92481 :         char *tmpbuf = NULL;
      51       92481 :         size_t size = 0;
      52         771 :         bool ret;
      53             : 
      54             :         /* No longer allow a length of -1. */
      55       92481 :         if (dest_len == (size_t)-1) {
      56           0 :                 smb_panic("push_ascii - dest_len == -1");
      57             :         }
      58             : 
      59       92481 :         if (flags & STR_UPPER) {
      60         238 :                 tmpbuf = SMB_STRDUP(src);
      61         238 :                 if (!tmpbuf) {
      62           0 :                         smb_panic("malloc fail");
      63             :                 }
      64         238 :                 if (!strupper_m(tmpbuf)) {
      65           0 :                         if ((flags & (STR_TERMINATE|STR_TERMINATE_ASCII)) &&
      66           0 :                                         dest &&
      67           0 :                                         dest_len > 0) {
      68           0 :                                 *(char *)dest = 0;
      69             :                         }
      70           0 :                         SAFE_FREE(tmpbuf);
      71           0 :                         return 0;
      72             :                 }
      73         238 :                 src = tmpbuf;
      74             :         }
      75             : 
      76       92481 :         src_len = strlen(src);
      77       92481 :         if (flags & (STR_TERMINATE | STR_TERMINATE_ASCII)) {
      78       46453 :                 src_len++;
      79             :         }
      80             : 
      81       92481 :         ret = convert_string(CH_UNIX, CH_DOS, src, src_len, dest, dest_len, &size);
      82       92481 :         SAFE_FREE(tmpbuf);
      83       92481 :         if (ret == false) {
      84          20 :                 if ((flags & (STR_TERMINATE | STR_TERMINATE_ASCII)) &&
      85             :                                 dest_len > 0) {
      86           2 :                         ((char *)dest)[0] = '\0';
      87             :                 }
      88          20 :                 return 0;
      89             :         }
      90       92461 :         return size;
      91             : }
      92             : 
      93             : /********************************************************************
      94             :  Push and malloc an ascii string. src and dest null terminated.
      95             : ********************************************************************/
      96             : 
      97             : /**
      98             :  * Copy a string from a dos codepage source to a unix char* destination.
      99             :  *
     100             :  * The resulting string in "dest" is always null terminated.
     101             :  *
     102             :  * @param flags can have:
     103             :  * <dl>
     104             :  * <dt>STR_TERMINATE</dt>
     105             :  * <dd>STR_TERMINATE means the string in @p src
     106             :  * is null terminated, and src_len is ignored.</dd>
     107             :  * </dl>
     108             :  *
     109             :  * @param src_len is the length of the source area in bytes.
     110             :  * @returns the number of bytes occupied by the string in @p src.
     111             :  **/
     112       48016 : size_t pull_ascii(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
     113             : {
     114           0 :         bool ret;
     115       48016 :         size_t size = 0;
     116             : 
     117       48016 :         if (dest_len == (size_t)-1) {
     118             :                 /* No longer allow dest_len of -1. */
     119           0 :                 smb_panic("pull_ascii - invalid dest_len of -1");
     120             :         }
     121             : 
     122       48016 :         if (flags & STR_TERMINATE) {
     123       48016 :                 if (src_len == (size_t)-1) {
     124       19372 :                         src_len = strlen((const char *)src) + 1;
     125             :                 } else {
     126       28644 :                         size_t len = strnlen((const char *)src, src_len);
     127       28644 :                         if (len < src_len)
     128       19550 :                                 len++;
     129       28644 :                         src_len = len;
     130             :                 }
     131             :         }
     132             : 
     133       48016 :         ret = convert_string(CH_DOS, CH_UNIX, src, src_len, dest, dest_len, &size);
     134       48016 :         if (ret == false) {
     135           0 :                 size = 0;
     136           0 :                 dest_len = 0;
     137             :         }
     138             : 
     139       48016 :         if (dest_len && size) {
     140             :                 /* Did we already process the terminating zero ? */
     141       48016 :                 if (dest[MIN(size-1, dest_len-1)] != 0) {
     142        9094 :                         dest[MIN(size, dest_len-1)] = 0;
     143             :                 }
     144             :         } else  {
     145           0 :                 dest[0] = 0;
     146             :         }
     147             : 
     148       48016 :         return src_len;
     149             : }
     150             : 
     151             : /**
     152             :  * Copy a string from a dos codepage source to a unix char* destination.
     153             :  * Talloc version.
     154             :  *
     155             :  * The resulting string in "dest" is always null terminated.
     156             :  *
     157             :  * @param flags can have:
     158             :  * <dl>
     159             :  * <dt>STR_TERMINATE</dt>
     160             :  * <dd>STR_TERMINATE means the string in @p src
     161             :  * is null terminated, and src_len is ignored.</dd>
     162             :  * </dl>
     163             :  *
     164             :  * @param src_len is the length of the source area in bytes.
     165             :  * @returns the number of bytes occupied by the string in @p src.
     166             :  **/
     167             : 
     168       16947 : static size_t pull_ascii_base_talloc(TALLOC_CTX *ctx,
     169             :                                      char **ppdest,
     170             :                                      const void *src,
     171             :                                      size_t src_len,
     172             :                                      int flags)
     173             : {
     174       16947 :         char *dest = NULL;
     175         144 :         size_t dest_len;
     176             : 
     177       16947 :         *ppdest = NULL;
     178             : 
     179       16947 :         if (!src_len) {
     180           0 :                 return 0;
     181             :         }
     182             : 
     183       16947 :         if (src_len == (size_t)-1) {
     184           0 :                 smb_panic("src_len == -1 in pull_ascii_base_talloc");
     185             :         }
     186             : 
     187       16947 :         if (flags & STR_TERMINATE) {
     188        7333 :                 size_t len = strnlen((const char *)src, src_len);
     189        7333 :                 if (len < src_len)
     190        7331 :                         len++;
     191        7333 :                 src_len = len;
     192             :                 /* Ensure we don't use an insane length from the client. */
     193        7333 :                 if (src_len >= 1024*1024) {
     194           0 :                         char *msg = talloc_asprintf(ctx,
     195             :                                         "Bad src length (%u) in "
     196             :                                         "pull_ascii_base_talloc",
     197             :                                         (unsigned int)src_len);
     198           0 :                         smb_panic(msg);
     199             :                 }
     200             :         }
     201             : 
     202             :         /* src_len != -1 here. */
     203             : 
     204       16947 :         if (!convert_string_talloc(ctx, CH_DOS, CH_UNIX, src, src_len, &dest,
     205             :                                      &dest_len)) {
     206           0 :                 dest_len = 0;
     207             :         }
     208             : 
     209       16947 :         if (dest_len && dest) {
     210             :                 /* Did we already process the terminating zero ? */
     211       16947 :                 if (dest[dest_len-1] != 0) {
     212           4 :                         size_t size = talloc_get_size(dest);
     213             :                         /* Have we got space to append the '\0' ? */
     214           4 :                         if (size <= dest_len) {
     215             :                                 /* No, realloc. */
     216           0 :                                 dest = talloc_realloc(ctx, dest, char,
     217             :                                                 dest_len+1);
     218           0 :                                 if (!dest) {
     219             :                                         /* talloc fail. */
     220           0 :                                         dest_len = (size_t)-1;
     221           0 :                                         return 0;
     222             :                                 }
     223             :                         }
     224             :                         /* Yay - space ! */
     225           4 :                         dest[dest_len] = '\0';
     226           4 :                         dest_len++;
     227             :                 }
     228           0 :         } else if (dest) {
     229           0 :                 dest[0] = 0;
     230             :         }
     231             : 
     232       16947 :         *ppdest = dest;
     233       16947 :         return src_len;
     234             : }
     235             : 
     236             : /**
     237             :  * Copy a string from a char* src to a unicode destination.
     238             :  *
     239             :  * @returns the number of bytes occupied by the string in the destination.
     240             :  *
     241             :  * @param flags can have:
     242             :  *
     243             :  * <dl>
     244             :  * <dt>STR_TERMINATE <dd>means include the null termination.
     245             :  * <dt>STR_UPPER     <dd>means uppercase in the destination.
     246             :  * <dt>STR_NOALIGN   <dd>means don't do alignment.
     247             :  * </dl>
     248             :  *
     249             :  * @param dest_len is the maximum length allowed in the
     250             :  * destination.
     251             :  **/
     252             : 
     253     1056829 : static size_t push_ucs2(const void *base_ptr, void *dest, const char *src, size_t dest_len, int flags)
     254             : {
     255     1056829 :         size_t len=0;
     256        1042 :         size_t src_len;
     257     1056829 :         size_t size = 0;
     258        1042 :         bool ret;
     259             : 
     260     1056829 :         if (dest_len == (size_t)-1) {
     261             :                 /* No longer allow dest_len of -1. */
     262           0 :                 smb_panic("push_ucs2 - invalid dest_len of -1");
     263             :         }
     264             : 
     265     1056829 :         if (flags & STR_TERMINATE)
     266      193943 :                 src_len = (size_t)-1;
     267             :         else
     268      862349 :                 src_len = strlen(src);
     269             : 
     270     1056829 :         if (ucs2_align(base_ptr, dest, flags)) {
     271        4380 :                 *(char *)dest = 0;
     272        4380 :                 dest = (void *)((char *)dest + 1);
     273        4380 :                 if (dest_len)
     274        4380 :                         dest_len--;
     275        4245 :                 len++;
     276             :         }
     277             : 
     278             :         /* ucs2 is always a multiple of 2 bytes */
     279     1056829 :         dest_len &= ~1;
     280             : 
     281     1056829 :         ret = convert_string(CH_UNIX, CH_UTF16LE, src, src_len, dest, dest_len, &size);
     282     1056829 :         if (ret == false) {
     283          80 :                 if ((flags & STR_TERMINATE) &&
     284          40 :                                 dest &&
     285             :                                 dest_len) {
     286          40 :                         *(char *)dest = 0;
     287             :                 }
     288          80 :                 return len;
     289             :         }
     290             : 
     291     1056749 :         len += size;
     292             : 
     293     1056749 :         if (flags & STR_UPPER) {
     294       43774 :                 smb_ucs2_t *dest_ucs2 = (smb_ucs2_t *)dest;
     295             :                 size_t i;
     296             : 
     297             :                 /* We check for i < (size / 2) below as the dest string isn't null
     298             :                    terminated if STR_TERMINATE isn't set. */
     299             : 
     300      435480 :                 for (i = 0; i < (size / 2) && i < (dest_len / 2) && dest_ucs2[i]; i++) {
     301      391681 :                         smb_ucs2_t v = toupper_w(dest_ucs2[i]);
     302      391681 :                         if (v != dest_ucs2[i]) {
     303           0 :                                 dest_ucs2[i] = v;
     304             :                         }
     305             :                 }
     306             :         }
     307             : 
     308     1055707 :         return len;
     309             : }
     310             : 
     311             : /**
     312             :  Copy a string from a ucs2 source to a unix char* destination.
     313             :  Talloc version with a base pointer.
     314             :  Uses malloc if TALLOC_CTX is NULL (this is a bad interface and
     315             :  needs fixing. JRA).
     316             :  Flags can have:
     317             :   STR_TERMINATE means the string in src is null terminated.
     318             :   STR_NOALIGN   means don't try to align.
     319             :  if STR_TERMINATE is set then src_len is ignored if it is -1.
     320             :  src_len is the length of the source area in bytes
     321             :  Return the number of bytes occupied by the string in src.
     322             :  The resulting string in "dest" is always null terminated.
     323             : **/
     324             : 
     325      363040 : static size_t pull_ucs2_base_talloc(TALLOC_CTX *ctx,
     326             :                                     const void *base_ptr,
     327             :                                     char **ppdest,
     328             :                                     const void *src,
     329             :                                     size_t src_len,
     330             :                                     int flags)
     331             : {
     332       10719 :         char *dest;
     333       10719 :         size_t dest_len;
     334      363040 :         size_t ucs2_align_len = 0;
     335             : 
     336      363040 :         *ppdest = NULL;
     337             : 
     338             : #ifdef DEVELOPER
     339             :         /* Ensure we never use the braindead "malloc" variant. */
     340      363040 :         if (ctx == NULL) {
     341           0 :                 smb_panic("NULL talloc CTX in pull_ucs2_base_talloc\n");
     342             :         }
     343             : #endif
     344             : 
     345      363040 :         if (!src_len) {
     346       40355 :                 return 0;
     347             :         }
     348             : 
     349      322685 :         if (src_len == (size_t)-1) {
     350             :                 /* no longer used anywhere, but worth checking */
     351           0 :                 smb_panic("sec_len == -1 in pull_ucs2_base_talloc");
     352             :         }
     353             : 
     354      322685 :         if (ucs2_align(base_ptr, src, flags)) {
     355       83571 :                 src = (const void *)((const char *)src + 1);
     356       83571 :                 src_len--;
     357       83571 :                 ucs2_align_len = 1;
     358             :         }
     359             : 
     360      322685 :         if (flags & STR_TERMINATE) {
     361             :                 /* src_len -1 is the default for null terminated strings. */
     362      219718 :                 size_t len = strnlen_w((const smb_ucs2_t *)src,
     363             :                                        src_len/2);
     364      219718 :                 if (len < src_len/2)
     365      218778 :                         len++;
     366      219718 :                 src_len = len*2;
     367             : 
     368             :                 /* Ensure we don't use an insane length from the client. */
     369      219718 :                 if (src_len >= 1024*1024) {
     370           0 :                         smb_panic("Bad src length in pull_ucs2_base_talloc\n");
     371             :                 }
     372             :         }
     373             : 
     374             :         /* ucs2 is always a multiple of 2 bytes */
     375      322685 :         src_len &= ~1;
     376             : 
     377      322685 :         if (!convert_string_talloc(ctx, CH_UTF16LE, CH_UNIX, src, src_len,
     378             :                                    (void *)&dest, &dest_len)) {
     379           5 :                 dest_len = 0;
     380             :         }
     381             : 
     382      322685 :         if (dest_len) {
     383             :                 /* Did we already process the terminating zero ? */
     384      322680 :                 if (dest[dest_len-1] != 0) {
     385      103902 :                         size_t size = talloc_get_size(dest);
     386             :                         /* Have we got space to append the '\0' ? */
     387      103902 :                         if (size <= dest_len) {
     388             :                                 /* No, realloc. */
     389           0 :                                 dest = talloc_realloc(ctx, dest, char,
     390             :                                                 dest_len+1);
     391           0 :                                 if (!dest) {
     392             :                                         /* talloc fail. */
     393           0 :                                         dest_len = (size_t)-1;
     394           0 :                                         return 0;
     395             :                                 }
     396             :                         }
     397             :                         /* Yay - space ! */
     398      103902 :                         dest[dest_len] = '\0';
     399      103902 :                         dest_len++;
     400             :                 }
     401           5 :         } else if (dest) {
     402           0 :                 dest[0] = 0;
     403             :         }
     404             : 
     405      322685 :         *ppdest = dest;
     406      322685 :         return src_len + ucs2_align_len;
     407             : }
     408             : 
     409             : /**
     410             :  Copy a string from a char* src to a unicode or ascii
     411             :  dos codepage destination choosing unicode or ascii based on the 
     412             :  flags supplied
     413             :  Return the number of bytes occupied by the string in the destination.
     414             :  flags can have:
     415             :   STR_TERMINATE means include the null termination.
     416             :   STR_UPPER     means uppercase in the destination.
     417             :   STR_ASCII     use ascii even with unicode packet.
     418             :   STR_NOALIGN   means don't do alignment.
     419             :  dest_len is the maximum length allowed in the destination. If dest_len
     420             :  is -1 then no maximum is used.
     421             : **/
     422             : 
     423         862 : size_t push_string_check_fn(void *dest, const char *src,
     424             :                          size_t dest_len, int flags)
     425             : {
     426         862 :         if (!(flags & STR_ASCII) && (flags & STR_UNICODE)) {
     427           0 :                 return push_ucs2(NULL, dest, src, dest_len, flags);
     428             :         }
     429         862 :         return push_ascii(dest, src, dest_len, flags);
     430             : }
     431             : 
     432             : 
     433             : /**
     434             :  Copy a string from a char* src to a unicode or ascii
     435             :  dos codepage destination choosing unicode or ascii based on the 
     436             :  flags in the SMB buffer starting at base_ptr.
     437             :  Return the number of bytes occupied by the string in the destination.
     438             :  flags can have:
     439             :   STR_TERMINATE means include the null termination.
     440             :   STR_UPPER     means uppercase in the destination.
     441             :   STR_ASCII     use ascii even with unicode packet.
     442             :   STR_NOALIGN   means don't do alignment.
     443             :  dest_len is the maximum length allowed in the destination. If dest_len
     444             :  is -1 then no maximum is used.
     445             : **/
     446             : 
     447     1066131 : size_t push_string_base(const char *base, uint16_t flags2,
     448             :                         void *dest, const char *src,
     449             :                         size_t dest_len, int flags)
     450             : {
     451             : 
     452     1066131 :         if (!(flags & STR_ASCII) && \
     453     1056827 :             ((flags & STR_UNICODE || \
     454             :               (flags2 & FLAGS2_UNICODE_STRINGS)))) {
     455     1056821 :                 return push_ucs2(base, dest, src, dest_len, flags);
     456             :         }
     457        9310 :         return push_ascii(dest, src, dest_len, flags);
     458             : }
     459             : 
     460             : /**
     461             :  Copy a string from a unicode or ascii source (depending on
     462             :  the packet flags) to a char* destination.
     463             :  Variant that uses talloc.
     464             :  Flags can have:
     465             :   STR_TERMINATE means the string in src is null terminated.
     466             :   STR_UNICODE   means to force as unicode.
     467             :   STR_ASCII     use ascii even with unicode packet.
     468             :   STR_NOALIGN   means don't do alignment.
     469             :  if STR_TERMINATE is set then src_len is ignored is it is -1
     470             :  src_len is the length of the source area in bytes.
     471             :  Return the number of bytes occupied by the string in src.
     472             :  The resulting string in "dest" is always null terminated.
     473             : **/
     474             : 
     475      379987 : size_t pull_string_talloc(TALLOC_CTX *ctx,
     476             :                           const void *base_ptr,
     477             :                           uint16_t smb_flags2,
     478             :                           char **ppdest,
     479             :                           const void *src,
     480             :                           size_t src_len,
     481             :                           int flags)
     482             : {
     483      379987 :         if ((base_ptr == NULL) && ((flags & (STR_ASCII|STR_UNICODE)) == 0)) {
     484           0 :                 smb_panic("No base ptr to get flg2 and neither ASCII nor "
     485             :                           "UNICODE defined");
     486             :         }
     487             : 
     488      379987 :         if (!(flags & STR_ASCII) && \
     489      363096 :             ((flags & STR_UNICODE || \
     490             :               (smb_flags2 & FLAGS2_UNICODE_STRINGS)))) {
     491      363040 :                 return pull_ucs2_base_talloc(ctx,
     492             :                                         base_ptr,
     493             :                                         ppdest,
     494             :                                         src,
     495             :                                         src_len,
     496             :                                         flags);
     497             :         }
     498       16947 :         return pull_ascii_base_talloc(ctx,
     499             :                                         ppdest,
     500             :                                         src,
     501             :                                         src_len,
     502             :                                         flags);
     503             : }
     504             : 
     505             : /*******************************************************************
     506             :  Write a string in (little-endian) unicode format. src is in
     507             :  the current DOS codepage. len is the length in bytes of the
     508             :  string pointed to by dst.
     509             : 
     510             :  if null_terminate is True then null terminate the packet (adds 2 bytes)
     511             : 
     512             :  the return value is the length in bytes consumed by the string, including the
     513             :  null termination if applied
     514             : ********************************************************************/
     515             : 
     516           8 : size_t dos_PutUniCode(char *dst,const char *src, size_t len, bool null_terminate)
     517             : {
     518           8 :         int flags = null_terminate ? STR_UNICODE|STR_NOALIGN|STR_TERMINATE
     519           8 :                                    : STR_UNICODE|STR_NOALIGN;
     520           8 :         return push_ucs2(NULL, dst, src, len, flags);
     521             : }
     522             : 
     523             : 
     524             : /* Converts a string from internal samba format to unicode. Always terminates.
     525             :  * Actually just a wrapper round push_ucs2_talloc().
     526             :  */
     527             : 
     528           0 : int rpcstr_push_talloc(TALLOC_CTX *ctx, smb_ucs2_t **dest, const char *src)
     529             : {
     530           0 :         size_t size;
     531           0 :         if (push_ucs2_talloc(ctx, dest, src, &size))
     532           0 :                 return size;
     533             :         else
     534           0 :                 return -1;
     535             : }

Generated by: LCOV version 1.14