You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

str_util.c 71KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619
  1. /*-
  2. * Copyright 2016 Vsevolod Stakhov
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "config.h"
  17. #include "util.h"
  18. #include "cryptobox.h"
  19. #include "url.h"
  20. #include "str_util.h"
  21. #include "logger.h"
  22. #include "contrib/t1ha/t1ha.h"
  23. #include <unicode/uversion.h>
  24. #include <unicode/ucnv.h>
  25. #if U_ICU_VERSION_MAJOR_NUM >= 44
  26. #include <unicode/unorm2.h>
  27. #endif
  28. #include <math.h>
  29. #include "contrib/fastutf8/fastutf8.h"
  30. const guchar lc_map[256] = {
  31. 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
  32. 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
  33. 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
  34. 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
  35. 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
  36. 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
  37. 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
  38. 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
  39. 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
  40. 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
  41. 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
  42. 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
  43. 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
  44. 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
  45. 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
  46. 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
  47. 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
  48. 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
  49. 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
  50. 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
  51. 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
  52. 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
  53. 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
  54. 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
  55. 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
  56. 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
  57. 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
  58. 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
  59. 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
  60. 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
  61. 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
  62. 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
  63. };
  64. guint
  65. rspamd_str_lc (gchar *str, guint size)
  66. {
  67. guint leftover = size % 4;
  68. guint fp, i;
  69. const uint8_t* s = (const uint8_t*) str;
  70. gchar *dest = str;
  71. guchar c1, c2, c3, c4;
  72. fp = size - leftover;
  73. for (i = 0; i != fp; i += 4) {
  74. c1 = s[i], c2 = s[i + 1], c3 = s[i + 2], c4 = s[i + 3];
  75. dest[0] = lc_map[c1];
  76. dest[1] = lc_map[c2];
  77. dest[2] = lc_map[c3];
  78. dest[3] = lc_map[c4];
  79. dest += 4;
  80. }
  81. switch (leftover) {
  82. case 3:
  83. *dest++ = lc_map[(guchar)str[i++]];
  84. /* FALLTHRU */
  85. case 2:
  86. *dest++ = lc_map[(guchar)str[i++]];
  87. /* FALLTHRU */
  88. case 1:
  89. *dest = lc_map[(guchar)str[i]];
  90. }
  91. return size;
  92. }
  93. gint
  94. rspamd_lc_cmp (const gchar *s, const gchar *d, gsize l)
  95. {
  96. guint fp, i;
  97. guchar c1, c2, c3, c4;
  98. union {
  99. guchar c[4];
  100. guint32 n;
  101. } cmp1, cmp2;
  102. gsize leftover = l % 4;
  103. gint ret = 0;
  104. fp = l - leftover;
  105. for (i = 0; i != fp; i += 4) {
  106. c1 = s[i], c2 = s[i + 1], c3 = s[i + 2], c4 = s[i + 3];
  107. cmp1.c[0] = lc_map[c1];
  108. cmp1.c[1] = lc_map[c2];
  109. cmp1.c[2] = lc_map[c3];
  110. cmp1.c[3] = lc_map[c4];
  111. c1 = d[i], c2 = d[i + 1], c3 = d[i + 2], c4 = d[i + 3];
  112. cmp2.c[0] = lc_map[c1];
  113. cmp2.c[1] = lc_map[c2];
  114. cmp2.c[2] = lc_map[c3];
  115. cmp2.c[3] = lc_map[c4];
  116. if (cmp1.n != cmp2.n) {
  117. return cmp1.n - cmp2.n;
  118. }
  119. }
  120. while (leftover > 0) {
  121. if (g_ascii_tolower (s[i]) != g_ascii_tolower (d[i])) {
  122. return s[i] - d[i];
  123. }
  124. leftover--;
  125. i++;
  126. }
  127. return ret;
  128. }
  129. /*
  130. * The purpose of this function is fast and in place conversion of a unicode
  131. * string to lower case, so some locale peculiarities are simply ignored
  132. * If the target string is longer than initial one, then we just trim it
  133. */
  134. guint
  135. rspamd_str_lc_utf8 (gchar *str, guint size)
  136. {
  137. guchar *d = (guchar *)str, tst[6];
  138. gint32 i = 0, prev = 0;
  139. UChar32 uc;
  140. while (i < size) {
  141. prev = i;
  142. U8_NEXT ((guint8*)str, i, size, uc);
  143. uc = u_tolower (uc);
  144. gint32 olen = 0;
  145. U8_APPEND_UNSAFE (tst, olen, uc);
  146. if (olen <= (i - prev)) {
  147. memcpy (d, tst, olen);
  148. d += olen;
  149. }
  150. else {
  151. /* Lowercasing has increased the length, so we need to ignore it */
  152. d += i - prev;
  153. }
  154. }
  155. return d - (guchar *)str;
  156. }
  157. gboolean
  158. rspamd_strcase_equal (gconstpointer v, gconstpointer v2)
  159. {
  160. if (g_ascii_strcasecmp ((const gchar *)v, (const gchar *)v2) == 0) {
  161. return TRUE;
  162. }
  163. return FALSE;
  164. }
  165. guint64
  166. rspamd_icase_hash (const gchar *in, gsize len, guint64 seed)
  167. {
  168. guint leftover = len % sizeof (guint64);
  169. guint fp, i;
  170. const uint8_t* s = (const uint8_t*) in;
  171. union {
  172. struct {
  173. guchar c1, c2, c3, c4, c5, c6, c7, c8;
  174. } c;
  175. guint64 pp;
  176. } u;
  177. guint64 h = seed;
  178. fp = len - leftover;
  179. for (i = 0; i != fp; i += 8) {
  180. u.c.c1 = s[i], u.c.c2 = s[i + 1], u.c.c3 = s[i + 2], u.c.c4 = s[i + 3];
  181. u.c.c5 = s[i + 4], u.c.c6 = s[i + 5], u.c.c7 = s[i + 6], u.c.c8 = s[i + 7];
  182. u.c.c1 = lc_map[u.c.c1];
  183. u.c.c2 = lc_map[u.c.c2];
  184. u.c.c3 = lc_map[u.c.c3];
  185. u.c.c4 = lc_map[u.c.c4];
  186. u.c.c5 = lc_map[u.c.c5];
  187. u.c.c6 = lc_map[u.c.c6];
  188. u.c.c7 = lc_map[u.c.c7];
  189. u.c.c8 = lc_map[u.c.c8];
  190. h = t1ha (&u.pp, sizeof (u), h);
  191. }
  192. u.pp = 0;
  193. switch (leftover) {
  194. case 7:
  195. u.c.c7 = lc_map[(guchar)s[i++]]; /* FALLTHRU */
  196. case 6:
  197. u.c.c6 = lc_map[(guchar)s[i++]]; /* FALLTHRU */
  198. case 5:
  199. u.c.c5 = lc_map[(guchar)s[i++]]; /* FALLTHRU */
  200. case 4:
  201. u.c.c4 = lc_map[(guchar)s[i++]]; /* FALLTHRU */
  202. case 3:
  203. u.c.c3 = lc_map[(guchar)s[i++]]; /* FALLTHRU */
  204. case 2:
  205. u.c.c2 = lc_map[(guchar)s[i++]]; /* FALLTHRU */
  206. case 1:
  207. u.c.c1 = lc_map[(guchar)s[i]];
  208. break;
  209. }
  210. h = t1ha (&u.pp, sizeof (u), h);
  211. return h;
  212. }
  213. guint
  214. rspamd_strcase_hash (gconstpointer key)
  215. {
  216. const gchar *p = key;
  217. gsize len;
  218. len = strlen (p);
  219. return (guint)rspamd_icase_hash (p, len, rspamd_hash_seed ());
  220. }
  221. guint
  222. rspamd_str_hash (gconstpointer key)
  223. {
  224. gsize len;
  225. len = strlen ((const gchar *)key);
  226. return (guint)rspamd_cryptobox_fast_hash (key, len, rspamd_hash_seed ());
  227. }
  228. gboolean
  229. rspamd_str_equal (gconstpointer v, gconstpointer v2)
  230. {
  231. return strcmp ((const gchar *)v, (const gchar *)v2) == 0;
  232. }
  233. gboolean
  234. rspamd_ftok_icase_equal (gconstpointer v, gconstpointer v2)
  235. {
  236. const rspamd_ftok_t *f1 = v, *f2 = v2;
  237. if (f1->len == f2->len &&
  238. rspamd_lc_cmp (f1->begin, f2->begin, f1->len) == 0) {
  239. return TRUE;
  240. }
  241. return FALSE;
  242. }
  243. guint
  244. rspamd_ftok_icase_hash (gconstpointer key)
  245. {
  246. const rspamd_ftok_t *f = key;
  247. return (guint)rspamd_icase_hash (f->begin, f->len, rspamd_hash_seed ());
  248. }
  249. gboolean
  250. rspamd_ftok_equal (gconstpointer v, gconstpointer v2)
  251. {
  252. const rspamd_ftok_t *f1 = v, *f2 = v2;
  253. if (f1->len == f2->len &&
  254. memcmp (f1->begin, f2->begin, f1->len) == 0) {
  255. return TRUE;
  256. }
  257. return FALSE;
  258. }
  259. guint
  260. rspamd_ftok_hash (gconstpointer key)
  261. {
  262. const rspamd_ftok_t *f = key;
  263. return (guint)rspamd_cryptobox_fast_hash (f->begin, f->len, rspamd_hash_seed ());
  264. }
  265. gboolean
  266. rspamd_gstring_icase_equal (gconstpointer v, gconstpointer v2)
  267. {
  268. const GString *f1 = v, *f2 = v2;
  269. if (f1->len == f2->len &&
  270. rspamd_lc_cmp (f1->str, f2->str, f1->len) == 0) {
  271. return TRUE;
  272. }
  273. return FALSE;
  274. }
  275. guint
  276. rspamd_gstring_icase_hash (gconstpointer key)
  277. {
  278. const GString *f = key;
  279. return (guint)rspamd_icase_hash (f->str, f->len, rspamd_hash_seed ());
  280. }
  281. /* https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord */
  282. #define MEM_ALIGN (sizeof(gsize)-1)
  283. #if defined(__LP64__) || defined(_LP64)
  284. #define WORD_TYPE guint64
  285. #define ZEROMASK 0x7F7F7F7F7F7F7F7FLLU
  286. #else
  287. #define WORD_TYPE guint32
  288. #define ZEROMASK 0x7F7F7F7FU
  289. #endif
  290. #define HASZERO(x) ~(((((x) & ZEROMASK) + ZEROMASK) | (x)) | ZEROMASK)
  291. gsize
  292. rspamd_strlcpy_fast (gchar *dst, const gchar *src, gsize siz)
  293. {
  294. gchar *d = dst;
  295. const gchar *s = src;
  296. gsize n = siz;
  297. WORD_TYPE *wd;
  298. const WORD_TYPE *ws;
  299. /* Copy as many bytes as will fit */
  300. if (n-- != 0) {
  301. if (((uintptr_t) s & MEM_ALIGN) == ((uintptr_t) d & MEM_ALIGN)) {
  302. /* Init copy byte by byte */
  303. for (; ((uintptr_t) s & MEM_ALIGN) && n && (*d = *s); n--, s++, d++);
  304. if (n && *s) {
  305. wd = (void *) d;
  306. ws = (const void *) s;
  307. /*
  308. * Copy by 32 or 64 bits (causes valgrind warnings)
  309. */
  310. for (; n >= sizeof (WORD_TYPE) && !HASZERO(*ws);
  311. n -= sizeof (WORD_TYPE), ws++, wd++) {
  312. *wd = *ws;
  313. }
  314. d = (void *) wd;
  315. s = (const void *) ws;
  316. }
  317. }
  318. /* Copy the rest */
  319. for (; n && (*d = *s); n--, s++, d++);
  320. *d = 0;
  321. }
  322. else {
  323. return 0;
  324. }
  325. return (d - dst);
  326. }
  327. gsize
  328. rspamd_null_safe_copy (const gchar *src, gsize srclen,
  329. gchar *dest, gsize destlen)
  330. {
  331. gsize copied = 0, si = 0, di = 0;
  332. if (destlen == 0) {
  333. return 0;
  334. }
  335. while (si < srclen && di + 1 < destlen) {
  336. if (src[si] != '\0') {
  337. dest[di++] = src[si++];
  338. copied ++;
  339. }
  340. else {
  341. si ++;
  342. }
  343. }
  344. dest[di] = '\0';
  345. return copied;
  346. }
  347. size_t
  348. rspamd_strlcpy_safe (gchar *dst, const gchar *src, gsize siz)
  349. {
  350. gchar *d = dst;
  351. gsize nleft = siz;
  352. if (nleft != 0) {
  353. while (--nleft != 0) {
  354. if ((*d++ = *src++) == '\0') {
  355. d --;
  356. break;
  357. }
  358. }
  359. }
  360. if (nleft == 0) {
  361. if (siz != 0) {
  362. *d = '\0';
  363. }
  364. }
  365. return (d - dst);
  366. }
  367. /*
  368. * Try to convert string of length to long
  369. */
  370. gboolean
  371. rspamd_strtol (const gchar *s, gsize len, glong *value)
  372. {
  373. const gchar *p = s, *end = s + len;
  374. gchar c;
  375. glong v = 0;
  376. const glong cutoff = G_MAXLONG / 10, cutlim = G_MAXLONG % 10;
  377. gboolean neg;
  378. /* Case negative values */
  379. if (*p == '-') {
  380. neg = TRUE;
  381. p++;
  382. }
  383. else {
  384. neg = FALSE;
  385. }
  386. /* Some preparations for range errors */
  387. while (p < end) {
  388. c = *p;
  389. if (c >= '0' && c <= '9') {
  390. c -= '0';
  391. if (v > cutoff || (v == cutoff && c > cutlim)) {
  392. /* Range error */
  393. *value = neg ? G_MINLONG : G_MAXLONG;
  394. return FALSE;
  395. }
  396. else {
  397. v *= 10;
  398. v += c;
  399. }
  400. }
  401. else {
  402. return FALSE;
  403. }
  404. p++;
  405. }
  406. *value = neg ? -(v) : v;
  407. return TRUE;
  408. }
  409. /*
  410. * Try to convert string of length to long
  411. */
  412. gboolean
  413. rspamd_strtoul (const gchar *s, gsize len, gulong *value)
  414. {
  415. const gchar *p = s, *end = s + len;
  416. gchar c;
  417. gulong v = 0;
  418. const gulong cutoff = G_MAXULONG / 10, cutlim = G_MAXULONG % 10;
  419. /* Some preparations for range errors */
  420. while (p < end) {
  421. c = *p;
  422. if (c >= '0' && c <= '9') {
  423. c -= '0';
  424. if (v > cutoff || (v == cutoff && (guint8)c > cutlim)) {
  425. /* Range error */
  426. *value = G_MAXULONG;
  427. return FALSE;
  428. }
  429. else {
  430. v *= 10;
  431. v += c;
  432. }
  433. }
  434. else {
  435. *value = v;
  436. return FALSE;
  437. }
  438. p++;
  439. }
  440. *value = v;
  441. return TRUE;
  442. }
  443. /**
  444. * Utility function to provide mem_pool copy for rspamd_hash_table_copy function
  445. * @param data string to copy
  446. * @param ud memory pool to use
  447. * @return
  448. */
  449. gpointer
  450. rspamd_str_pool_copy (gconstpointer data, gpointer ud)
  451. {
  452. rspamd_mempool_t *pool = ud;
  453. return data ? rspamd_mempool_strdup (pool, data) : NULL;
  454. }
  455. /*
  456. * We use here z-base32 encoding described here:
  457. * http://philzimmermann.com/docs/human-oriented-base-32-encoding.txt
  458. */
  459. gint
  460. rspamd_encode_base32_buf (const guchar *in, gsize inlen, gchar *out, gsize outlen,
  461. enum rspamd_base32_type type)
  462. {
  463. static const char b32_default[] = "ybndrfg8ejkmcpqxot1uwisza345h769",
  464. b32_bleach[] = "qpzry9x8gf2tvdw0s3jn54khce6mua7l",
  465. b32_rfc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
  466. *b32;
  467. gchar *o, *end;
  468. gsize i;
  469. gint remain = -1, x;
  470. bool inverse_order = true;
  471. end = out + outlen;
  472. o = out;
  473. switch (type) {
  474. case RSPAMD_BASE32_DEFAULT:
  475. b32 = b32_default;
  476. break;
  477. case RSPAMD_BASE32_BLEACH:
  478. b32 = b32_bleach;
  479. inverse_order = false;
  480. break;
  481. case RSPAMD_BASE32_RFC:
  482. b32 = b32_rfc;
  483. inverse_order = false;
  484. break;
  485. default:
  486. g_assert_not_reached ();
  487. abort ();
  488. }
  489. if (inverse_order) {
  490. /* Zbase32 as used in Rspamd */
  491. for (i = 0; i < inlen && o < end - 1; i++) {
  492. switch (i % 5) {
  493. case 0:
  494. /* 8 bits of input and 3 to remain */
  495. x = in[i];
  496. remain = in[i] >> 5;
  497. *o++ = b32[x & 0x1F];
  498. break;
  499. case 1:
  500. /* 11 bits of input, 1 to remain */
  501. x = remain | in[i] << 3;
  502. *o++ = b32[x & 0x1F];
  503. *o++ = b32[x >> 5 & 0x1F];
  504. remain = x >> 10;
  505. break;
  506. case 2:
  507. /* 9 bits of input, 4 to remain */
  508. x = remain | in[i] << 1;
  509. *o++ = b32[x & 0x1F];
  510. remain = x >> 5;
  511. break;
  512. case 3:
  513. /* 12 bits of input, 2 to remain */
  514. x = remain | in[i] << 4;
  515. *o++ = b32[x & 0x1F];
  516. *o++ = b32[x >> 5 & 0x1F];
  517. remain = x >> 10 & 0x3;
  518. break;
  519. case 4:
  520. /* 10 bits of output, nothing to remain */
  521. x = remain | in[i] << 2;
  522. *o++ = b32[x & 0x1F];
  523. *o++ = b32[x >> 5 & 0x1F];
  524. remain = -1;
  525. break;
  526. default:
  527. /* Not to be happen */
  528. break;
  529. }
  530. }
  531. }
  532. else {
  533. /* Traditional base32 with no bits inversion */
  534. for (i = 0; i < inlen && o < end - 1; i++) {
  535. switch (i % 5) {
  536. case 0:
  537. /* 8 bits of input and 3 to remain */
  538. x = in[i] >> 3;
  539. remain = (in[i] & 7) << 2;
  540. *o++ = b32[x & 0x1F];
  541. break;
  542. case 1:
  543. /* 11 bits of input, 1 to remain */
  544. x = (remain << 6) | in[i];
  545. *o++ = b32[(x >> 6) & 0x1F];
  546. *o++ = b32[(x >> 1) & 0x1F];
  547. remain = (x & 0x1) << 4;
  548. break;
  549. case 2:
  550. /* 9 bits of input, 4 to remain */
  551. x = (remain << 4) | in[i];
  552. *o++ = b32[(x >> 4) & 0x1F];
  553. remain = (x & 15) << 1;
  554. break;
  555. case 3:
  556. /* 12 bits of input, 2 to remain */
  557. x = (remain << 7) | in[i];
  558. *o++ = b32[(x >> 7) & 0x1F];
  559. *o++ = b32[(x >> 2) & 0x1F];
  560. remain = (x & 3) << 3;
  561. break;
  562. case 4:
  563. /* 10 bits of output, nothing to remain */
  564. x = (remain << 5) | in[i];
  565. *o++ = b32[(x >> 5) & 0x1F];
  566. *o++ = b32[x & 0x1F];
  567. remain = -1;
  568. break;
  569. default:
  570. /* Not to be happen */
  571. break;
  572. }
  573. }
  574. }
  575. if (remain >= 0 && o < end) {
  576. *o++ = b32[remain & 0x1F];
  577. }
  578. if (o <= end) {
  579. return (o - out);
  580. }
  581. return -1;
  582. }
  583. gchar *
  584. rspamd_encode_base32 (const guchar *in, gsize inlen, enum rspamd_base32_type type)
  585. {
  586. gsize allocated_len = inlen * 8 / 5 + 2;
  587. gchar *out;
  588. gint outlen;
  589. out = g_malloc (allocated_len);
  590. outlen = rspamd_encode_base32_buf (in, inlen, out,
  591. allocated_len - 1, type);
  592. if (outlen >= 0) {
  593. out[outlen] = 0;
  594. return out;
  595. }
  596. g_free (out);
  597. return NULL;
  598. }
  599. enum rspamd_base32_type
  600. rspamd_base32_decode_type_from_str (const gchar *str)
  601. {
  602. enum rspamd_base32_type ret = RSPAMD_BASE32_INVALID;
  603. if (str == NULL) {
  604. return RSPAMD_BASE32_DEFAULT;
  605. }
  606. if (strcmp (str, "default") == 0 || strcmp (str, "zbase") == 0) {
  607. ret = RSPAMD_BASE32_ZBASE;
  608. }
  609. else if (strcmp (str, "bleach") == 0) {
  610. ret = RSPAMD_BASE32_BLEACH;
  611. }
  612. else if (strcmp (str, "rfc") == 0) {
  613. ret = RSPAMD_BASE32_RFC;
  614. }
  615. return ret;
  616. }
  617. static const guchar b32_dec_zbase[] = {
  618. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  619. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  620. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  621. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  622. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  623. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  624. 0xff, 0x12, 0xff, 0x19, 0x1a, 0x1b, 0x1e, 0x1d,
  625. 0x07, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  626. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  627. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  628. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  629. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  630. 0xff, 0x18, 0x01, 0x0c, 0x03, 0x08, 0x05, 0x06,
  631. 0x1c, 0x15, 0x09, 0x0a, 0xff, 0x0b, 0x02, 0x10,
  632. 0x0d, 0x0e, 0x04, 0x16, 0x11, 0x13, 0xff, 0x14,
  633. 0x0f, 0x00, 0x17, 0xff, 0xff, 0xff, 0xff, 0xff,
  634. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  635. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  636. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  637. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  638. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  639. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  640. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  641. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  642. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  643. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  644. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  645. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  646. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  647. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  648. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  649. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
  650. };
  651. static const guchar b32_dec_bleach[] = {
  652. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  653. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  654. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  655. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  656. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  657. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  658. 0x0f, 0xff, 0x0a, 0x11, 0x15, 0x14, 0x1a, 0x1e,
  659. 0x07, 0x05, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  660. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  661. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  662. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  663. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  664. 0xff, 0x1d, 0xff, 0x18, 0x0d, 0x19, 0x09, 0x08,
  665. 0x17, 0xff, 0x12, 0x16, 0x1f, 0x1b, 0x13, 0xff,
  666. 0x01, 0x00, 0x03, 0x10, 0x0b, 0x1c, 0x0c, 0x0e,
  667. 0x06, 0x04, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff,
  668. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  669. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  670. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  671. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  672. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  673. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  674. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  675. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  676. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  677. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  678. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  679. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  680. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  681. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  682. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  683. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
  684. };
  685. static const guchar b32_dec_rfc[] = {
  686. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  687. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  688. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  689. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  690. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  691. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  692. 0xff, 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
  693. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  694. 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
  695. 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
  696. 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
  697. 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
  698. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  699. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  700. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  701. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  702. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  703. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  704. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  705. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  706. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  707. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  708. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  709. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  710. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  711. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  712. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  713. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  714. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  715. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  716. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  717. 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  718. };
  719. gint
  720. rspamd_decode_base32_buf (const gchar *in, gsize inlen, guchar *out, gsize outlen,
  721. enum rspamd_base32_type type)
  722. {
  723. guchar *o, *end, decoded;
  724. guchar c;
  725. guint acc = 0U;
  726. guint processed_bits = 0;
  727. gsize i;
  728. const guchar *b32_dec;
  729. bool inverse_bits = true;
  730. end = out + outlen;
  731. o = out;
  732. switch (type) {
  733. case RSPAMD_BASE32_DEFAULT:
  734. b32_dec = b32_dec_zbase;
  735. break;
  736. case RSPAMD_BASE32_BLEACH:
  737. b32_dec = b32_dec_bleach;
  738. inverse_bits = false;
  739. break;
  740. case RSPAMD_BASE32_RFC:
  741. b32_dec = b32_dec_rfc;
  742. inverse_bits = false;
  743. break;
  744. default:
  745. g_assert_not_reached ();
  746. abort ();
  747. }
  748. if (inverse_bits) {
  749. for (i = 0; i < inlen; i++) {
  750. c = (guchar) in[i];
  751. if (processed_bits >= 8) {
  752. /* Emit from left to right */
  753. processed_bits -= 8;
  754. *o++ = acc & 0xFF;
  755. acc >>= 8;
  756. }
  757. decoded = b32_dec[c];
  758. if (decoded == 0xff || o >= end) {
  759. return -1;
  760. }
  761. acc = (decoded << processed_bits) | acc;
  762. processed_bits += 5;
  763. }
  764. if (processed_bits > 0 && o < end) {
  765. *o++ = (acc & 0xFF);
  766. }
  767. else if (o > end) {
  768. return -1;
  769. }
  770. }
  771. else {
  772. for (i = 0; i < inlen; i++) {
  773. c = (guchar) in[i];
  774. decoded = b32_dec[c];
  775. if (decoded == 0xff) {
  776. return -1;
  777. }
  778. acc = (acc << 5) | decoded;
  779. processed_bits += 5;
  780. if (processed_bits >= 8) {
  781. /* Emit from right to left */
  782. processed_bits -= 8;
  783. /* Output buffer overflow */
  784. if (o >= end) {
  785. return -1;
  786. }
  787. *o++ = (acc >> processed_bits) & 0xFF;
  788. /* Preserve lowers at the higher parts of the input */
  789. acc = (acc & ((1u << processed_bits) - 1));
  790. }
  791. }
  792. if (processed_bits > 0 && o < end) {
  793. *o++ = (acc & 0xFF);
  794. }
  795. else if (o > end) {
  796. return -1;
  797. }
  798. }
  799. return (o - out);
  800. }
  801. guchar *
  802. rspamd_decode_base32 (const gchar *in, gsize inlen, gsize *outlen,
  803. enum rspamd_base32_type type)
  804. {
  805. guchar *res;
  806. gsize allocated_len = inlen * 5 / 8 + 2;
  807. gssize olen;
  808. res = g_malloc (allocated_len);
  809. olen = rspamd_decode_base32_buf (in, inlen, res, allocated_len - 1,
  810. type);
  811. if (olen >= 0) {
  812. res[olen] = '\0';
  813. }
  814. else {
  815. g_free (res);
  816. if (outlen) {
  817. *outlen = 0;
  818. }
  819. return NULL;
  820. }
  821. if (outlen) {
  822. *outlen = olen;
  823. }
  824. return res;
  825. }
  826. gchar *
  827. rspamd_encode_base64_common (const guchar *in, gsize inlen, gint str_len,
  828. gsize *outlen, gboolean fold, enum rspamd_newlines_type how)
  829. {
  830. #define ADD_SPLIT do { \
  831. if (how == RSPAMD_TASK_NEWLINES_CR || how == RSPAMD_TASK_NEWLINES_CRLF) *o++ = '\r'; \
  832. if (how == RSPAMD_TASK_NEWLINES_LF || how == RSPAMD_TASK_NEWLINES_CRLF) *o++ = '\n'; \
  833. if (fold) *o++ = '\t'; \
  834. } while (0)
  835. #define CHECK_SPLIT \
  836. do { if (str_len > 0 && cols >= str_len) { \
  837. ADD_SPLIT; \
  838. cols = 0; \
  839. } } \
  840. while (0)
  841. gsize allocated_len = (inlen / 3) * 4 + 5;
  842. gchar *out, *o;
  843. guint64 n;
  844. guint32 rem, t, carry;
  845. gint cols, shift;
  846. static const char b64_enc[] =
  847. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  848. "abcdefghijklmnopqrstuvwxyz"
  849. "0123456789+/";
  850. if (str_len > 0) {
  851. g_assert (str_len > 8);
  852. if (fold) {
  853. switch (how) {
  854. case RSPAMD_TASK_NEWLINES_CR:
  855. case RSPAMD_TASK_NEWLINES_LF:
  856. allocated_len += (allocated_len / str_len + 1) * 2 + 1;
  857. break;
  858. default:
  859. allocated_len += (allocated_len / str_len + 1) * 3 + 1;
  860. break;
  861. }
  862. }
  863. else {
  864. switch (how) {
  865. case RSPAMD_TASK_NEWLINES_CR:
  866. case RSPAMD_TASK_NEWLINES_LF:
  867. allocated_len += (allocated_len / str_len + 1) * 1 + 1;
  868. break;
  869. default:
  870. allocated_len += (allocated_len / str_len + 1) * 2 + 1;
  871. break;
  872. }
  873. }
  874. }
  875. out = g_malloc (allocated_len);
  876. o = out;
  877. cols = 0;
  878. while (inlen > 6) {
  879. memcpy (&n, in, sizeof (n));
  880. n = GUINT64_TO_BE (n);
  881. if (str_len <= 0 || cols <= str_len - 8) {
  882. *o++ = b64_enc[(n >> 58) & 0x3F];
  883. *o++ = b64_enc[(n >> 52) & 0x3F];
  884. *o++ = b64_enc[(n >> 46) & 0x3F];
  885. *o++ = b64_enc[(n >> 40) & 0x3F];
  886. *o++ = b64_enc[(n >> 34) & 0x3F];
  887. *o++ = b64_enc[(n >> 28) & 0x3F];
  888. *o++ = b64_enc[(n >> 22) & 0x3F];
  889. *o++ = b64_enc[(n >> 16) & 0x3F];
  890. cols += 8;
  891. }
  892. else {
  893. cols = str_len - cols;
  894. shift = 58;
  895. while (cols) {
  896. *o++ = b64_enc[(n >> shift) & 0x3F];
  897. shift -= 6;
  898. cols --;
  899. }
  900. ADD_SPLIT;
  901. /* Remaining bytes */
  902. while (shift >= 16) {
  903. *o++ = b64_enc[(n >> shift) & 0x3F];
  904. shift -= 6;
  905. cols ++;
  906. }
  907. }
  908. in += 6;
  909. inlen -= 6;
  910. }
  911. CHECK_SPLIT;
  912. rem = 0;
  913. carry = 0;
  914. for (;;) {
  915. /* Padding + remaining data (0 - 2 bytes) */
  916. switch (rem) {
  917. case 0:
  918. if (inlen-- == 0) {
  919. goto end;
  920. }
  921. t = *in++;
  922. *o++ = b64_enc[t >> 2];
  923. carry = (t << 4) & 0x30;
  924. rem = 1;
  925. cols ++;
  926. case 1:
  927. if (inlen-- == 0) {
  928. goto end;
  929. }
  930. CHECK_SPLIT;
  931. t = *in++;
  932. *o++ = b64_enc[carry | (t >> 4)];
  933. carry = (t << 2) & 0x3C;
  934. rem = 2;
  935. cols ++;
  936. default:
  937. if (inlen-- == 0) {
  938. goto end;
  939. }
  940. CHECK_SPLIT;
  941. t = *in ++;
  942. *o++ = b64_enc[carry | (t >> 6)];
  943. cols ++;
  944. CHECK_SPLIT;
  945. *o++ = b64_enc[t & 0x3F];
  946. cols ++;
  947. CHECK_SPLIT;
  948. rem = 0;
  949. }
  950. }
  951. end:
  952. if (rem == 1) {
  953. *o++ = b64_enc[carry];
  954. cols ++;
  955. CHECK_SPLIT;
  956. *o++ = '=';
  957. cols ++;
  958. CHECK_SPLIT;
  959. *o++ = '=';
  960. cols ++;
  961. CHECK_SPLIT;
  962. }
  963. else if (rem == 2) {
  964. *o++ = b64_enc[carry];
  965. cols ++;
  966. CHECK_SPLIT;
  967. *o++ = '=';
  968. cols ++;
  969. }
  970. CHECK_SPLIT;
  971. *o = '\0';
  972. if (outlen != NULL) {
  973. *outlen = o - out;
  974. }
  975. return out;
  976. }
  977. gchar *
  978. rspamd_encode_base64 (const guchar *in, gsize inlen, gint str_len,
  979. gsize *outlen)
  980. {
  981. return rspamd_encode_base64_common (in, inlen, str_len, outlen, FALSE,
  982. RSPAMD_TASK_NEWLINES_CRLF);
  983. }
  984. gchar *
  985. rspamd_encode_base64_fold (const guchar *in, gsize inlen, gint str_len,
  986. gsize *outlen, enum rspamd_newlines_type how)
  987. {
  988. return rspamd_encode_base64_common (in, inlen, str_len, outlen, TRUE, how);
  989. }
  990. #define QP_RANGE(x) (((x) >= 33 && (x) <= 60) || ((x) >= 62 && (x) <= 126) \
  991. || (x) == '\r' || (x) == '\n' || (x) == ' ' || (x) == '\t')
  992. #define QP_SPAN_NORMAL(span, str_len) ((str_len) > 0 && \
  993. ((span) + 1) >= (str_len))
  994. #define QP_SPAN_SPECIAL(span, str_len) ((str_len) > 0 && \
  995. ((span) + 4) >= (str_len))
  996. gchar *
  997. rspamd_encode_qp_fold (const guchar *in, gsize inlen, gint str_len,
  998. gsize *outlen, enum rspamd_newlines_type how)
  999. {
  1000. gsize olen = 0, span = 0, i = 0, seen_spaces = 0;
  1001. gchar *out;
  1002. gint ch, last_sp;
  1003. const guchar *end = in + inlen, *p = in;
  1004. static const gchar hexdigests[16] = "0123456789ABCDEF";
  1005. while (p < end) {
  1006. ch = *p;
  1007. if (QP_RANGE(ch)) {
  1008. olen ++;
  1009. span ++;
  1010. if (ch == '\r' || ch == '\n') {
  1011. if (seen_spaces > 0) {
  1012. /* We must encode spaces at the end of line */
  1013. olen += 3;
  1014. seen_spaces = 0;
  1015. /* Special stuff for space character at the end */
  1016. if (QP_SPAN_SPECIAL(span, str_len)) {
  1017. if (how == RSPAMD_TASK_NEWLINES_CRLF) {
  1018. /* =\r\n */
  1019. olen += 3;
  1020. }
  1021. else {
  1022. olen += 2;
  1023. }
  1024. }
  1025. /* Continue with the same `ch` but without spaces logic */
  1026. continue;
  1027. }
  1028. span = 0;
  1029. }
  1030. else if (ch == ' ' || ch == '\t') {
  1031. seen_spaces ++;
  1032. last_sp = ch;
  1033. }
  1034. else {
  1035. seen_spaces = 0;
  1036. }
  1037. }
  1038. else {
  1039. if (QP_SPAN_SPECIAL(span, str_len)) {
  1040. if (how == RSPAMD_TASK_NEWLINES_CRLF) {
  1041. /* =\r\n */
  1042. olen += 3;
  1043. }
  1044. else {
  1045. olen += 2;
  1046. }
  1047. span = 0;
  1048. }
  1049. olen += 3;
  1050. span += 3;
  1051. }
  1052. if (QP_SPAN_NORMAL(span, str_len)) {
  1053. if (how == RSPAMD_TASK_NEWLINES_CRLF) {
  1054. /* =\r\n */
  1055. olen += 3;
  1056. }
  1057. else {
  1058. olen += 2;
  1059. }
  1060. span = 0;
  1061. }
  1062. p ++;
  1063. }
  1064. if (seen_spaces > 0) {
  1065. /* Reserve length for the last space encoded */
  1066. olen += 3;
  1067. }
  1068. out = g_malloc (olen + 1);
  1069. p = in;
  1070. i = 0;
  1071. span = 0;
  1072. seen_spaces = 0;
  1073. while (p < end) {
  1074. ch = *p;
  1075. if (QP_RANGE (ch)) {
  1076. if (ch == '\r' || ch == '\n') {
  1077. if (seen_spaces > 0) {
  1078. if (QP_SPAN_SPECIAL(span, str_len)) {
  1079. /* Add soft newline */
  1080. i --;
  1081. if (p + 1 < end || span + 3 >= str_len) {
  1082. switch (how) {
  1083. default:
  1084. case RSPAMD_TASK_NEWLINES_CRLF:
  1085. out[i++] = '=';
  1086. out[i++] = '\r';
  1087. out[i++] = '\n';
  1088. break;
  1089. case RSPAMD_TASK_NEWLINES_LF:
  1090. out[i++] = '=';
  1091. out[i++] = '\n';
  1092. break;
  1093. case RSPAMD_TASK_NEWLINES_CR:
  1094. out[i++] = '=';
  1095. out[i++] = '\r';
  1096. break;
  1097. }
  1098. }
  1099. /* Now write encoded `last_sp` but after newline */
  1100. out[i++] = '=';
  1101. out[i++] = hexdigests[((last_sp >> 4) & 0xF)];
  1102. out[i++] = hexdigests[(last_sp & 0xF)];
  1103. span = 0;
  1104. }
  1105. else {
  1106. /* Encode last space */
  1107. --i;
  1108. out[i++] = '=';
  1109. out[i++] = hexdigests[((last_sp >> 4) & 0xF)];
  1110. out[i++] = hexdigests[(last_sp & 0xF)];
  1111. seen_spaces = 0;
  1112. }
  1113. continue;
  1114. }
  1115. span = 0;
  1116. }
  1117. else if (ch == ' ' || ch == '\t') {
  1118. seen_spaces ++;
  1119. last_sp = ch;
  1120. span ++;
  1121. }
  1122. else {
  1123. seen_spaces = 0;
  1124. span ++;
  1125. }
  1126. out[i++] = ch;
  1127. }
  1128. else {
  1129. if (QP_SPAN_SPECIAL(span, str_len)) {
  1130. /* Add new line and then continue */
  1131. if (p + 1 < end || span + 3 >= str_len) {
  1132. switch (how) {
  1133. default:
  1134. case RSPAMD_TASK_NEWLINES_CRLF:
  1135. out[i++] = '=';
  1136. out[i++] = '\r';
  1137. out[i++] = '\n';
  1138. break;
  1139. case RSPAMD_TASK_NEWLINES_LF:
  1140. out[i++] = '=';
  1141. out[i++] = '\n';
  1142. break;
  1143. case RSPAMD_TASK_NEWLINES_CR:
  1144. out[i++] = '=';
  1145. out[i++] = '\r';
  1146. break;
  1147. }
  1148. span = 0;
  1149. }
  1150. }
  1151. out[i++] = '=';
  1152. out[i++] = hexdigests[((ch >> 4) & 0xF)];
  1153. out[i++] = hexdigests[(ch & 0xF)];
  1154. span += 3;
  1155. seen_spaces = 0;
  1156. }
  1157. if (QP_SPAN_NORMAL(span, str_len)) {
  1158. /* Add new line and then continue */
  1159. if (p + 1 < end || span > str_len || seen_spaces) {
  1160. switch (how) {
  1161. default:
  1162. case RSPAMD_TASK_NEWLINES_CRLF:
  1163. out[i++] = '=';
  1164. out[i++] = '\r';
  1165. out[i++] = '\n';
  1166. break;
  1167. case RSPAMD_TASK_NEWLINES_LF:
  1168. out[i++] = '=';
  1169. out[i++] = '\n';
  1170. break;
  1171. case RSPAMD_TASK_NEWLINES_CR:
  1172. out[i++] = '=';
  1173. out[i++] = '\r';
  1174. break;
  1175. }
  1176. span = 0;
  1177. seen_spaces = 0;
  1178. }
  1179. }
  1180. g_assert (i <= olen);
  1181. p ++;
  1182. }
  1183. /* Deal with the last space character */
  1184. if (seen_spaces > 0) {
  1185. i --;
  1186. out[i++] = '=';
  1187. out[i++] = hexdigests[((last_sp >> 4) & 0xF)];
  1188. out[i++] = hexdigests[(last_sp & 0xF)];
  1189. }
  1190. out[i] = '\0';
  1191. if (outlen) {
  1192. *outlen = i;
  1193. }
  1194. return out;
  1195. }
  1196. #define MIN3(a, b, c) ((a) < (b) ? ((a) < (c) ? (a) : (c)) : ((b) < (c) ? (b) : (c)))
  1197. gint
  1198. rspamd_strings_levenshtein_distance (const gchar *s1, gsize s1len,
  1199. const gchar *s2, gsize s2len,
  1200. guint replace_cost)
  1201. {
  1202. gchar c1, c2, last_c2, last_c1;
  1203. static GArray *current_row = NULL, *prev_row = NULL, *transp_row = NULL;
  1204. gint eq;
  1205. static const guint max_cmp = 8192;
  1206. gint ret;
  1207. g_assert (s1 != NULL);
  1208. g_assert (s2 != NULL);
  1209. if (s1len == 0) {
  1210. s1len = strlen (s1);
  1211. }
  1212. if (s2len == 0) {
  1213. s2len = strlen (s2);
  1214. }
  1215. if (MAX(s1len, s2len) > max_cmp) {
  1216. /* Cannot compare too many characters */
  1217. return max_cmp;
  1218. }
  1219. if (s1len > s2len) {
  1220. /* Exchange s1 and s2 */
  1221. const gchar *tmp;
  1222. gsize tmplen;
  1223. tmp = s2;
  1224. s2 = s1;
  1225. s1 = tmp;
  1226. tmplen = s2len;
  1227. s2len = s1len;
  1228. s1len = tmplen;
  1229. }
  1230. /* Adjust static space */
  1231. if (current_row == NULL) {
  1232. current_row = g_array_sized_new (FALSE, FALSE, sizeof (gint), s1len + 1);
  1233. prev_row = g_array_sized_new (FALSE, FALSE, sizeof (gint), s1len + 1);
  1234. transp_row = g_array_sized_new (FALSE, FALSE, sizeof (gint), s1len + 1);
  1235. g_array_set_size (current_row, s1len + 1);
  1236. g_array_set_size (prev_row, s1len + 1);
  1237. g_array_set_size (transp_row, s1len + 1);
  1238. }
  1239. else if (current_row->len < s1len + 1) {
  1240. g_array_set_size (current_row, s1len + 1);
  1241. g_array_set_size (prev_row, s1len + 1);
  1242. g_array_set_size (transp_row, s1len + 1);
  1243. }
  1244. memset (current_row->data, 0, (s1len + 1) * sizeof (gint));
  1245. memset (transp_row->data, 0, (s1len + 1) * sizeof (gint));
  1246. for (gint i = 0; i <= s1len; i++) {
  1247. g_array_index (prev_row, gint, i) = i;
  1248. }
  1249. last_c2 = '\0';
  1250. for (gint i = 1; i <= s2len; i++) {
  1251. c2 = s2[i - 1];
  1252. g_array_index (current_row, gint, 0) = i;
  1253. last_c1 = '\0';
  1254. for (gint j = 1; j <= s1len; j++) {
  1255. c1 = s1[j - 1];
  1256. eq = c1 == c2 ? 0 : replace_cost;
  1257. ret = MIN3 (g_array_index (current_row, gint, j - 1) + 1, /* Insert */
  1258. g_array_index (prev_row, gint, j) + 1, /* Remove */
  1259. g_array_index (prev_row, gint, j - 1) + eq /* Replace */);
  1260. /* Take reordering into account */
  1261. if (c1 == last_c2 && c2 == last_c1 && j >= 2) {
  1262. ret = MIN (ret, g_array_index (transp_row, gint, j - 2) + eq);
  1263. }
  1264. g_array_index (current_row, gint, j) = ret;
  1265. last_c1 = c1;
  1266. }
  1267. last_c2 = c2;
  1268. /* Exchange pointers */
  1269. GArray *tmp;
  1270. tmp = transp_row;
  1271. transp_row = prev_row;
  1272. prev_row = current_row;
  1273. current_row = tmp;
  1274. }
  1275. ret = g_array_index (prev_row, gint, s1len);
  1276. return ret;
  1277. }
  1278. GString *
  1279. rspamd_header_value_fold (const gchar *name,
  1280. const gchar *value,
  1281. guint fold_max,
  1282. enum rspamd_newlines_type how,
  1283. const gchar *fold_on_chars)
  1284. {
  1285. GString *res;
  1286. const guint default_fold_max = 76;
  1287. guint cur_len;
  1288. const gchar *p, *c;
  1289. guint nspaces = 0;
  1290. const gchar *last;
  1291. gboolean first_token = TRUE;
  1292. enum {
  1293. fold_before = 0,
  1294. fold_after
  1295. } fold_type = fold_before;
  1296. enum {
  1297. read_token = 0,
  1298. read_quoted,
  1299. after_quote,
  1300. fold_token,
  1301. } state = read_token, next_state = read_token;
  1302. g_assert (name != NULL);
  1303. g_assert (value != NULL);
  1304. /* Filter insane values */
  1305. if (fold_max < 20) {
  1306. fold_max = default_fold_max;
  1307. }
  1308. res = g_string_sized_new (strlen (value));
  1309. c = value;
  1310. p = c;
  1311. /* name:<WSP> */
  1312. cur_len = strlen (name) + 2;
  1313. while (*p) {
  1314. switch (state) {
  1315. case read_token:
  1316. if (fold_on_chars) {
  1317. if (strchr (fold_on_chars, *p) != NULL) {
  1318. fold_type = fold_after;
  1319. state = fold_token;
  1320. next_state = read_token;
  1321. }
  1322. p ++;
  1323. }
  1324. else {
  1325. if (*p == ',' || *p == ';') {
  1326. /* We have something similar to the token's end, so check len */
  1327. if (cur_len > fold_max * 0.8 && cur_len < fold_max) {
  1328. /* We want fold */
  1329. fold_type = fold_after;
  1330. state = fold_token;
  1331. next_state = read_token;
  1332. } else if (cur_len > fold_max && !first_token) {
  1333. fold_type = fold_before;
  1334. state = fold_token;
  1335. next_state = read_token;
  1336. } else {
  1337. g_string_append_len (res, c, p - c + 1);
  1338. c = p + 1;
  1339. first_token = FALSE;
  1340. }
  1341. p++;
  1342. } else if (*p == '"') {
  1343. /* Fold before quoted tokens */
  1344. g_string_append_len (res, c, p - c);
  1345. c = p;
  1346. state = read_quoted;
  1347. } else if (*p == '\r' || *p == '\n') {
  1348. if (cur_len > fold_max && !first_token) {
  1349. fold_type = fold_before;
  1350. state = fold_token;
  1351. next_state = read_token;
  1352. } else {
  1353. /* Reset line length */
  1354. cur_len = 0;
  1355. while (g_ascii_isspace (*p)) {
  1356. p++;
  1357. }
  1358. g_string_append_len (res, c, p - c);
  1359. c = p;
  1360. first_token = TRUE;
  1361. }
  1362. } else if (g_ascii_isspace (*p)) {
  1363. if (cur_len > fold_max * 0.8 && cur_len < fold_max) {
  1364. /* We want fold */
  1365. fold_type = fold_after;
  1366. state = fold_token;
  1367. next_state = read_token;
  1368. } else if (cur_len > fold_max && !first_token) {
  1369. fold_type = fold_before;
  1370. state = fold_token;
  1371. next_state = read_token;
  1372. } else {
  1373. g_string_append_len (res, c, p - c);
  1374. c = p;
  1375. first_token = FALSE;
  1376. p++;
  1377. cur_len++;
  1378. }
  1379. } else {
  1380. p++;
  1381. cur_len++;
  1382. }
  1383. }
  1384. break;
  1385. case fold_token:
  1386. /* Here, we have token start at 'c' and token end at 'p' */
  1387. if (fold_type == fold_after) {
  1388. nspaces = 0;
  1389. if (p > c) {
  1390. g_string_append_len (res, c, p - c);
  1391. /*
  1392. * Check any spaces that are appended to the result
  1393. * before folding
  1394. */
  1395. last = &res->str[res->len - 1];
  1396. while (g_ascii_isspace (*last)) {
  1397. last --;
  1398. nspaces ++;
  1399. res->len --;
  1400. }
  1401. }
  1402. switch (how) {
  1403. case RSPAMD_TASK_NEWLINES_LF:
  1404. g_string_append_len (res, "\n\t", 2);
  1405. break;
  1406. case RSPAMD_TASK_NEWLINES_CR:
  1407. g_string_append_len (res, "\r\t", 2);
  1408. break;
  1409. case RSPAMD_TASK_NEWLINES_CRLF:
  1410. default:
  1411. g_string_append_len (res, "\r\n\t", 3);
  1412. break;
  1413. }
  1414. /* Skip space if needed */
  1415. if (g_ascii_isspace (*p)) {
  1416. p ++;
  1417. }
  1418. /* Move leftover spaces */
  1419. while (nspaces) {
  1420. g_string_append_c (res, ' ');
  1421. nspaces --;
  1422. }
  1423. cur_len = 0;
  1424. }
  1425. else {
  1426. const gchar *last;
  1427. /* Skip space if needed */
  1428. if (g_ascii_isspace (*c) && p > c) {
  1429. c ++;
  1430. }
  1431. /* Avoid double folding */
  1432. last = &res->str[res->len - 1];
  1433. last --;
  1434. if (*last != '\r' && *last != '\n') {
  1435. last ++;
  1436. while (g_ascii_isspace (*last)) {
  1437. last --;
  1438. nspaces ++;
  1439. res->len --;
  1440. }
  1441. switch (how) {
  1442. case RSPAMD_TASK_NEWLINES_LF:
  1443. g_string_append_len (res, "\n\t", 2);
  1444. break;
  1445. case RSPAMD_TASK_NEWLINES_CR:
  1446. g_string_append_len (res, "\r\t", 2);
  1447. break;
  1448. case RSPAMD_TASK_NEWLINES_CRLF:
  1449. default:
  1450. g_string_append_len (res, "\r\n\t", 3);
  1451. break;
  1452. }
  1453. }
  1454. /* Move leftover spaces */
  1455. cur_len = nspaces;
  1456. while (nspaces) {
  1457. g_string_append_c (res, ' ');
  1458. nspaces --;
  1459. }
  1460. if (p > c) {
  1461. g_string_append_len (res, c, p - c);
  1462. cur_len += p - c;
  1463. }
  1464. else {
  1465. cur_len = 0;
  1466. }
  1467. }
  1468. first_token = TRUE;
  1469. c = p;
  1470. state = next_state;
  1471. break;
  1472. case read_quoted:
  1473. if (p != c && *p == '"') {
  1474. state = after_quote;
  1475. }
  1476. p ++;
  1477. cur_len ++;
  1478. break;
  1479. case after_quote:
  1480. state = read_token;
  1481. /* Skip one more character after the quote */
  1482. p ++;
  1483. cur_len ++;
  1484. g_string_append_len (res, c, p - c);
  1485. c = p;
  1486. first_token = TRUE;
  1487. break;
  1488. }
  1489. }
  1490. /* Last token */
  1491. switch (state) {
  1492. case read_token:
  1493. if (!fold_on_chars && cur_len > fold_max && !first_token) {
  1494. if (g_ascii_isspace (*c)) {
  1495. c ++;
  1496. }
  1497. switch (how) {
  1498. case RSPAMD_TASK_NEWLINES_LF:
  1499. g_string_append_len (res, "\n\t", 2);
  1500. break;
  1501. case RSPAMD_TASK_NEWLINES_CR:
  1502. g_string_append_len (res, "\r\t", 2);
  1503. break;
  1504. case RSPAMD_TASK_NEWLINES_CRLF:
  1505. default:
  1506. g_string_append_len (res, "\r\n\t", 3);
  1507. break;
  1508. }
  1509. g_string_append_len (res, c, p - c);
  1510. }
  1511. else {
  1512. g_string_append_len (res, c, p - c);
  1513. }
  1514. break;
  1515. case read_quoted:
  1516. case after_quote:
  1517. g_string_append_len (res, c, p - c);
  1518. break;
  1519. case fold_token:
  1520. /* Here, we have token start at 'c' and token end at 'p' */
  1521. if (g_ascii_isspace (res->str[res->len - 1])) {
  1522. g_string_append_len (res, c, p - c);
  1523. }
  1524. else {
  1525. if (*c != '\r' && *c != '\n') {
  1526. /* We need to add folding as well */
  1527. switch (how) {
  1528. case RSPAMD_TASK_NEWLINES_LF:
  1529. g_string_append_len (res, "\n\t", 2);
  1530. break;
  1531. case RSPAMD_TASK_NEWLINES_CR:
  1532. g_string_append_len (res, "\r\t", 2);
  1533. break;
  1534. case RSPAMD_TASK_NEWLINES_CRLF:
  1535. default:
  1536. g_string_append_len (res, "\r\n\t", 3);
  1537. break;
  1538. }
  1539. g_string_append_len (res, c, p - c);
  1540. }
  1541. else {
  1542. g_string_append_len (res, c, p - c);
  1543. }
  1544. }
  1545. break;
  1546. default:
  1547. g_assert (p == c);
  1548. break;
  1549. }
  1550. return res;
  1551. }
  1552. static inline bool rspamd_substring_cmp_func (guchar a, guchar b) { return a == b; }
  1553. static inline bool rspamd_substring_casecmp_func (guchar a, guchar b) { return lc_map[a] == lc_map[b]; }
  1554. typedef bool (*rspamd_cmpchar_func_t) (guchar a, guchar b);
  1555. static inline void
  1556. rspamd_substring_preprocess_kmp (const gchar *pat, gsize len, goffset *fsm,
  1557. rspamd_cmpchar_func_t f)
  1558. {
  1559. goffset i, j;
  1560. i = 0;
  1561. j = -1;
  1562. fsm[0] = -1;
  1563. while (i < len) {
  1564. while (j > -1 && !f(pat[i], pat[j])) {
  1565. j = fsm[j];
  1566. }
  1567. i++;
  1568. j++;
  1569. if (i < len && j < len && f(pat[i], pat[j])) {
  1570. fsm[i] = fsm[j];
  1571. }
  1572. else {
  1573. fsm[i] = j;
  1574. }
  1575. }
  1576. }
  1577. static inline goffset
  1578. rspamd_substring_search_preprocessed (const gchar *in, gsize inlen,
  1579. const gchar *srch,
  1580. gsize srchlen,
  1581. const goffset *fsm,
  1582. rspamd_cmpchar_func_t f)
  1583. {
  1584. goffset i, j, k, ell;
  1585. for (ell = 1; f(srch[ell - 1], srch[ell]); ell++) {}
  1586. if (ell == srchlen) {
  1587. ell = 0;
  1588. }
  1589. /* Searching */
  1590. i = ell;
  1591. j = k = 0;
  1592. while (j <= inlen - srchlen) {
  1593. while (i < srchlen && f(srch[i], in[i + j])) {
  1594. ++i;
  1595. }
  1596. if (i >= srchlen) {
  1597. while (k < ell && f(srch[k], in[j + k])) {
  1598. ++k;
  1599. }
  1600. if (k >= ell) {
  1601. return j;
  1602. }
  1603. }
  1604. j += (i - fsm[i]);
  1605. if (i == ell) {
  1606. k = MAX(0, k - 1);
  1607. }
  1608. else {
  1609. if (fsm[i] <= ell) {
  1610. k = MAX(0, fsm[i]);
  1611. i = ell;
  1612. } else {
  1613. k = ell;
  1614. i = fsm[i];
  1615. }
  1616. }
  1617. }
  1618. return -1;
  1619. }
  1620. static inline goffset
  1621. rspamd_substring_search_common (const gchar *in, gsize inlen,
  1622. const gchar *srch, gsize srchlen, rspamd_cmpchar_func_t f)
  1623. {
  1624. static goffset st_fsm[128];
  1625. goffset *fsm, ret;
  1626. if (G_LIKELY (srchlen < G_N_ELEMENTS (st_fsm))) {
  1627. fsm = st_fsm;
  1628. }
  1629. else {
  1630. fsm = g_malloc ((srchlen + 1) * sizeof (*fsm));
  1631. }
  1632. rspamd_substring_preprocess_kmp (srch, srchlen, fsm, f);
  1633. ret = rspamd_substring_search_preprocessed (in, inlen, srch, srchlen, fsm, f);
  1634. if (G_UNLIKELY (srchlen >= G_N_ELEMENTS (st_fsm))) {
  1635. g_free (fsm);
  1636. }
  1637. return ret;
  1638. }
  1639. goffset
  1640. rspamd_substring_search (const gchar *in, gsize inlen,
  1641. const gchar *srch, gsize srchlen)
  1642. {
  1643. if (inlen > srchlen) {
  1644. if (G_UNLIKELY (srchlen == 1)) {
  1645. const gchar *p;
  1646. p = memchr (in, srch[0], inlen);
  1647. if (p) {
  1648. return p - in;
  1649. }
  1650. return (-1);
  1651. }
  1652. return rspamd_substring_search_common (in, inlen, srch, srchlen,
  1653. rspamd_substring_cmp_func);
  1654. }
  1655. else if (inlen == srchlen) {
  1656. return rspamd_lc_cmp (srch, in, srchlen) == 0;
  1657. }
  1658. else {
  1659. return (-1);
  1660. }
  1661. return (-1);
  1662. }
  1663. goffset
  1664. rspamd_substring_search_caseless (const gchar *in, gsize inlen,
  1665. const gchar *srch, gsize srchlen)
  1666. {
  1667. if (inlen > srchlen) {
  1668. if (G_UNLIKELY (srchlen == 1)) {
  1669. goffset i;
  1670. gchar s = lc_map[(guchar)srch[0]];
  1671. for (i = 0; i < inlen; i++) {
  1672. if (lc_map[(guchar)in[i]] == s) {
  1673. return i;
  1674. }
  1675. }
  1676. return (-1);
  1677. }
  1678. return rspamd_substring_search_common (in, inlen, srch, srchlen,
  1679. rspamd_substring_casecmp_func);
  1680. }
  1681. else if (inlen == srchlen) {
  1682. return rspamd_lc_cmp (srch, in, srchlen) == 0 ? 0 : (-1);
  1683. }
  1684. return (-1);
  1685. }
  1686. goffset
  1687. rspamd_string_find_eoh (GString *input, goffset *body_start)
  1688. {
  1689. const gchar *p, *c = NULL, *end;
  1690. enum {
  1691. skip_char = 0,
  1692. got_cr,
  1693. got_lf,
  1694. got_linebreak,
  1695. got_linebreak_cr,
  1696. got_linebreak_lf,
  1697. obs_fws
  1698. } state = skip_char;
  1699. g_assert (input != NULL);
  1700. p = input->str;
  1701. end = p + input->len;
  1702. while (p < end) {
  1703. switch (state) {
  1704. case skip_char:
  1705. if (*p == '\r') {
  1706. p++;
  1707. state = got_cr;
  1708. }
  1709. else if (*p == '\n') {
  1710. p++;
  1711. state = got_lf;
  1712. }
  1713. else {
  1714. p++;
  1715. }
  1716. break;
  1717. case got_cr:
  1718. if (*p == '\r') {
  1719. /*
  1720. * Double \r\r, so need to check the current char
  1721. * if it is '\n', then we have \r\r\n sequence, that is NOT
  1722. * double end of line
  1723. */
  1724. if (p < end && p[1] == '\n') {
  1725. p++;
  1726. state = got_lf;
  1727. }
  1728. else {
  1729. /* We have \r\r[^\n] */
  1730. if (body_start) {
  1731. *body_start = p - input->str + 1;
  1732. }
  1733. return p - input->str;
  1734. }
  1735. }
  1736. else if (*p == '\n') {
  1737. p++;
  1738. state = got_lf;
  1739. }
  1740. else if (g_ascii_isspace (*p)) {
  1741. /* We have \r<space>*, allow to stay in this state */
  1742. c = p;
  1743. p ++;
  1744. state = obs_fws;
  1745. }
  1746. else {
  1747. p++;
  1748. state = skip_char;
  1749. }
  1750. break;
  1751. case got_lf:
  1752. if (*p == '\n') {
  1753. /* We have \n\n, which is obviously end of headers */
  1754. if (body_start) {
  1755. *body_start = p - input->str + 1;
  1756. }
  1757. return p - input->str;
  1758. }
  1759. else if (*p == '\r') {
  1760. state = got_linebreak;
  1761. }
  1762. else if (g_ascii_isspace (*p)) {
  1763. /* We have \n<space>*, allow to stay in this state */
  1764. c = p;
  1765. p ++;
  1766. state = obs_fws;
  1767. }
  1768. else {
  1769. p++;
  1770. state = skip_char;
  1771. }
  1772. break;
  1773. case got_linebreak:
  1774. if (*p == '\r') {
  1775. c = p;
  1776. p++;
  1777. state = got_linebreak_cr;
  1778. }
  1779. else if (*p == '\n') {
  1780. c = p;
  1781. p++;
  1782. state = got_linebreak_lf;
  1783. }
  1784. else if (g_ascii_isspace (*p)) {
  1785. /* We have <linebreak><space>*, allow to stay in this state */
  1786. c = p;
  1787. p ++;
  1788. state = obs_fws;
  1789. }
  1790. else {
  1791. p++;
  1792. state = skip_char;
  1793. }
  1794. break;
  1795. case got_linebreak_cr:
  1796. if (*p == '\r') {
  1797. /* Got double \r\r after \n, so does not treat it as EOH */
  1798. state = got_linebreak_cr;
  1799. p++;
  1800. }
  1801. else if (*p == '\n') {
  1802. state = got_linebreak_lf;
  1803. p++;
  1804. }
  1805. else if (g_ascii_isspace (*p)) {
  1806. /* We have \r\n<space>*, allow to keep in this state */
  1807. c = p;
  1808. state = obs_fws;
  1809. p ++;
  1810. }
  1811. else {
  1812. p++;
  1813. state = skip_char;
  1814. }
  1815. break;
  1816. case got_linebreak_lf:
  1817. g_assert (c != NULL);
  1818. if (body_start) {
  1819. /* \r\n\r\n */
  1820. *body_start = p - input->str;
  1821. }
  1822. return c - input->str;
  1823. case obs_fws:
  1824. if (*p == ' ' || *p == '\t') {
  1825. p ++;
  1826. }
  1827. else if (*p == '\r') {
  1828. /* Perform lookahead due to #2349 */
  1829. if (end - p > 2) {
  1830. if (p[1] == '\n' && g_ascii_isspace (p[2])) {
  1831. /* Real obs_fws state, switch */
  1832. c = p;
  1833. p ++;
  1834. state = got_cr;
  1835. }
  1836. else if (g_ascii_isspace (p[1])) {
  1837. p ++;
  1838. state = obs_fws;
  1839. }
  1840. else {
  1841. /*
  1842. * <nline> <wsp>+ \r <nwsp>.
  1843. * It is an empty header likely, so we can go further...
  1844. * https://tools.ietf.org/html/rfc2822#section-4.2
  1845. */
  1846. c = p;
  1847. p ++;
  1848. state = got_cr;
  1849. }
  1850. }
  1851. else {
  1852. /* shortage */
  1853. if (body_start) {
  1854. *body_start = p - input->str + 1;
  1855. }
  1856. return p - input->str;
  1857. }
  1858. }
  1859. else if (*p == '\n') {
  1860. /* Perform lookahead due to #2349 */
  1861. if (end - p > 1) {
  1862. /* Continue folding with an empty line */
  1863. if (p[1] == ' ' || p[1] == '\t') {
  1864. c = p;
  1865. p ++;
  1866. state = obs_fws;
  1867. }
  1868. else if (p[1] == '\r') {
  1869. /* WTF state: we have seen spaces, \n and then it follows \r */
  1870. c = p;
  1871. p ++;
  1872. state = got_lf;
  1873. }
  1874. else if (p[1] == '\n') {
  1875. /*
  1876. * Switching to got_lf state here will let us to finish
  1877. * the cycle.
  1878. */
  1879. c = p;
  1880. p ++;
  1881. state = got_lf;
  1882. }
  1883. else {
  1884. /*
  1885. * <nline> <wsp>+ \n <nwsp>.
  1886. * It is an empty header likely, so we can go further...
  1887. * https://tools.ietf.org/html/rfc2822#section-4.2
  1888. */
  1889. c = p;
  1890. p ++;
  1891. state = got_lf;
  1892. }
  1893. }
  1894. else {
  1895. /* shortage */
  1896. if (body_start) {
  1897. *body_start = p - input->str + 1;
  1898. }
  1899. return p - input->str;
  1900. }
  1901. }
  1902. else {
  1903. p++;
  1904. state = skip_char;
  1905. }
  1906. break;
  1907. }
  1908. }
  1909. if (state == got_linebreak_lf) {
  1910. if (body_start) {
  1911. /* \r\n\r\n */
  1912. *body_start = p - input->str;
  1913. }
  1914. return c - input->str;
  1915. }
  1916. return -1;
  1917. }
  1918. gint
  1919. rspamd_encode_hex_buf (const guchar *in, gsize inlen, gchar *out,
  1920. gsize outlen)
  1921. {
  1922. gchar *o, *end;
  1923. const guchar *p;
  1924. static const gchar hexdigests[16] = "0123456789abcdef";
  1925. end = out + outlen;
  1926. o = out;
  1927. p = in;
  1928. while (inlen > 0 && o < end - 1) {
  1929. *o++ = hexdigests[((*p >> 4) & 0xF)];
  1930. *o++ = hexdigests[((*p++) & 0xF)];
  1931. inlen --;
  1932. }
  1933. if (o <= end) {
  1934. return (o - out);
  1935. }
  1936. return -1;
  1937. }
  1938. gchar *
  1939. rspamd_encode_hex (const guchar *in, gsize inlen)
  1940. {
  1941. gchar *out;
  1942. gsize outlen = inlen * 2 + 1;
  1943. gint olen;
  1944. if (in == NULL) {
  1945. return NULL;
  1946. }
  1947. out = g_malloc (outlen);
  1948. olen = rspamd_encode_hex_buf (in, inlen, out, outlen - 1);
  1949. if (olen >= 0) {
  1950. out[olen] = '\0';
  1951. }
  1952. else {
  1953. g_free (out);
  1954. return NULL;
  1955. }
  1956. return out;
  1957. }
  1958. gssize
  1959. rspamd_decode_hex_buf (const gchar *in, gsize inlen,
  1960. guchar *out, gsize outlen)
  1961. {
  1962. guchar *o, *end, ret = 0;
  1963. const gchar *p;
  1964. gchar c;
  1965. end = out + outlen;
  1966. o = out;
  1967. p = in;
  1968. /* We ignore trailing chars if we have not even input */
  1969. inlen = inlen - inlen % 2;
  1970. while (inlen > 1 && o < end) {
  1971. c = *p++;
  1972. if (c >= '0' && c <= '9') ret = c - '0';
  1973. else if (c >= 'A' && c <= 'F') ret = c - 'A' + 10;
  1974. else if (c >= 'a' && c <= 'f') ret = c - 'a' + 10;
  1975. c = *p++;
  1976. ret *= 16;
  1977. if (c >= '0' && c <= '9') ret += c - '0';
  1978. else if (c >= 'A' && c <= 'F') ret += c - 'A' + 10;
  1979. else if (c >= 'a' && c <= 'f') ret += c - 'a' + 10;
  1980. *o++ = ret;
  1981. inlen -= 2;
  1982. }
  1983. if (o <= end) {
  1984. return (o - out);
  1985. }
  1986. return -1;
  1987. }
  1988. guchar*
  1989. rspamd_decode_hex (const gchar *in, gsize inlen)
  1990. {
  1991. guchar *out;
  1992. gsize outlen = (inlen / 2 + inlen % 2) + 1;
  1993. gint olen;
  1994. if (in == NULL) {
  1995. return NULL;
  1996. }
  1997. out = g_malloc (outlen);
  1998. olen = rspamd_decode_hex_buf (in, inlen, out, outlen - 1);
  1999. if (olen >= 0) {
  2000. out[olen] = '\0';
  2001. return out;
  2002. }
  2003. g_free (out);
  2004. return NULL;
  2005. }
  2006. gssize
  2007. rspamd_decode_qp_buf (const gchar *in, gsize inlen,
  2008. gchar *out, gsize outlen)
  2009. {
  2010. gchar *o, *end, *pos, c;
  2011. const gchar *p;
  2012. guchar ret;
  2013. gssize remain, processed;
  2014. p = in;
  2015. o = out;
  2016. end = out + outlen;
  2017. remain = inlen;
  2018. while (remain > 0 && o < end) {
  2019. if (*p == '=') {
  2020. remain --;
  2021. if (remain == 0) {
  2022. /* Last '=' character, bugon */
  2023. if (end - o > 0) {
  2024. *o++ = *p;
  2025. }
  2026. else {
  2027. /* Buffer overflow */
  2028. return (-1);
  2029. }
  2030. break;
  2031. }
  2032. p ++;
  2033. decode:
  2034. /* Decode character after '=' */
  2035. c = *p++;
  2036. remain --;
  2037. ret = 0;
  2038. if (c >= '0' && c <= '9') { ret = c - '0'; }
  2039. else if (c >= 'A' && c <= 'F') { ret = c - 'A' + 10; }
  2040. else if (c >= 'a' && c <= 'f') { ret = c - 'a' + 10; }
  2041. else if (c == '\r' || c == '\n') {
  2042. /* Soft line break */
  2043. while (remain > 0 && (*p == '\r' || *p == '\n')) {
  2044. remain --;
  2045. p ++;
  2046. }
  2047. continue;
  2048. }
  2049. else {
  2050. /* Hack, hack, hack, treat =<garbadge> as =<garbadge> */
  2051. if (remain > 0) {
  2052. *o++ = *(p - 1);
  2053. }
  2054. continue;
  2055. }
  2056. if (remain > 0) {
  2057. c = *p++;
  2058. ret *= 16;
  2059. if (c >= '0' && c <= '9') { ret += c - '0'; }
  2060. else if (c >= 'A' && c <= 'F') { ret += c - 'A' + 10; }
  2061. else if (c >= 'a' && c <= 'f') { ret += c - 'a' + 10; }
  2062. if (end - o > 0) {
  2063. *o++ = (gchar)ret;
  2064. }
  2065. else {
  2066. return (-1);
  2067. }
  2068. remain --;
  2069. }
  2070. }
  2071. else {
  2072. if (end - o >= remain) {
  2073. if ((pos = memccpy (o, p, '=', remain)) == NULL) {
  2074. /* All copied */
  2075. o += remain;
  2076. break;
  2077. }
  2078. else {
  2079. processed = pos - o;
  2080. remain -= processed;
  2081. p += processed;
  2082. if (remain > 0) {
  2083. o = pos - 1;
  2084. /*
  2085. * Skip comparison and jump inside decode branch,
  2086. * as we know that we have found match
  2087. */
  2088. goto decode;
  2089. }
  2090. else {
  2091. /* Last '=' character, bugon */
  2092. o = pos;
  2093. if (end - o > 0) {
  2094. *o = '=';
  2095. }
  2096. else {
  2097. /* Buffer overflow */
  2098. return (-1);
  2099. }
  2100. break;
  2101. }
  2102. }
  2103. }
  2104. else {
  2105. /* Buffer overflow */
  2106. return (-1);
  2107. }
  2108. }
  2109. }
  2110. return (o - out);
  2111. }
  2112. gssize
  2113. rspamd_decode_uue_buf (const gchar *in, gsize inlen,
  2114. gchar *out, gsize outlen)
  2115. {
  2116. gchar *o, *out_end;
  2117. const gchar *p;
  2118. gssize remain;
  2119. gboolean base64 = FALSE;
  2120. goffset pos;
  2121. const gchar *nline = "\r\n";
  2122. p = in;
  2123. o = out;
  2124. out_end = out + outlen;
  2125. remain = inlen;
  2126. /* Skip newlines */
  2127. #define SKIP_NEWLINE do { while (remain > 0 && (*p == '\n' || *p == '\r')) {p ++; remain --; } } while (0)
  2128. SKIP_NEWLINE;
  2129. /* First of all, we need to read the first line (and probably skip it) */
  2130. if (remain < sizeof ("begin-base64 ")) {
  2131. /* Obviously truncated */
  2132. return -1;
  2133. }
  2134. if (memcmp (p, "begin ", sizeof ("begin ") - 1) == 0) {
  2135. p += sizeof ("begin ") - 1;
  2136. remain -= sizeof ("begin ") - 1;
  2137. pos = rspamd_memcspn (p, nline, remain);
  2138. }
  2139. else if (memcmp (p, "begin-base64 ", sizeof ("begin-base64 ") - 1) == 0) {
  2140. base64 = TRUE;
  2141. p += sizeof ("begin-base64 ") - 1;
  2142. remain -= sizeof ("begin-base64 ") - 1;
  2143. pos = rspamd_memcspn (p, nline, remain);
  2144. }
  2145. else {
  2146. /* Crap */
  2147. return (-1);
  2148. }
  2149. if (pos == -1 || remain == 0) {
  2150. /* Crap */
  2151. return (-1);
  2152. }
  2153. #define DEC(c) (((c) - ' ') & 077) /* single character decode */
  2154. #define IS_DEC(c) ( (((c) - ' ') >= 0) && (((c) - ' ') <= 077 + 1) )
  2155. #define CHAR_OUT(c) do { if (o < out_end) { *o++ = c; } else { return (-1); } } while(0)
  2156. remain -= pos;
  2157. p = p + pos;
  2158. SKIP_NEWLINE;
  2159. if (base64) {
  2160. if (!rspamd_cryptobox_base64_decode (p,
  2161. remain,
  2162. out, &outlen)) {
  2163. return (-1);
  2164. }
  2165. return outlen;
  2166. }
  2167. while (remain > 0 && o < out_end) {
  2168. /* Main cycle */
  2169. const gchar *eol;
  2170. gint i, ch;
  2171. pos = rspamd_memcspn (p, nline, remain);
  2172. if (pos == 0) {
  2173. /* Skip empty lines */
  2174. SKIP_NEWLINE;
  2175. if (remain == 0) {
  2176. break;
  2177. }
  2178. }
  2179. eol = p + pos;
  2180. remain -= eol - p;
  2181. if ((i = DEC(*p)) <= 0) {
  2182. /* Last pos */
  2183. break;
  2184. }
  2185. /* i can be less than eol - p, it means uue padding which we ignore */
  2186. for (++p; i > 0 && p < eol; p += 4, i -= 3) {
  2187. if (i >= 3 && p + 3 < eol) {
  2188. /* Process 4 bytes of input */
  2189. if (!IS_DEC(*p)) {
  2190. return (-1);
  2191. }
  2192. if (!IS_DEC(*(p + 1))) {
  2193. return (-1);
  2194. }
  2195. if (!IS_DEC(*(p + 2))) {
  2196. return (-1);
  2197. }
  2198. if (!IS_DEC(*(p + 3))) {
  2199. return (-1);
  2200. }
  2201. ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
  2202. CHAR_OUT(ch);
  2203. ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
  2204. CHAR_OUT(ch);
  2205. ch = DEC(p[2]) << 6 | DEC(p[3]);
  2206. CHAR_OUT(ch);
  2207. }
  2208. else {
  2209. if (i >= 1 && p + 1 < eol) {
  2210. if (!IS_DEC(*p)) {
  2211. return (-1);
  2212. }
  2213. if (!IS_DEC(*(p + 1))) {
  2214. return (-1);
  2215. }
  2216. ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
  2217. CHAR_OUT(ch);
  2218. }
  2219. if (i >= 2 && p + 2 < eol) {
  2220. if (!IS_DEC(*(p + 1))) {
  2221. return (-1);
  2222. }
  2223. if (!IS_DEC(*(p + 2))) {
  2224. return (-1);
  2225. }
  2226. ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
  2227. CHAR_OUT(ch);
  2228. }
  2229. }
  2230. }
  2231. /* Skip newline */
  2232. p = eol;
  2233. SKIP_NEWLINE;
  2234. }
  2235. return (o - out);
  2236. }
  2237. #define BITOP(a,b,op) \
  2238. ((a)[(gsize)(b)/(8*sizeof *(a))] op (gsize)1<<((gsize)(b)%(8*sizeof *(a))))
  2239. gsize
  2240. rspamd_memcspn (const gchar *s, const gchar *e, gsize len)
  2241. {
  2242. gsize byteset[32 / sizeof(gsize)];
  2243. const gchar *p = s, *end = s + len;
  2244. if (!e[1]) {
  2245. for (; p < end && *p != *e; p++);
  2246. return p - s;
  2247. }
  2248. memset (byteset, 0, sizeof byteset);
  2249. for (; *e && BITOP (byteset, *(guchar *)e, |=); e++);
  2250. for (; p < end && !BITOP (byteset, *(guchar *)p, &); p++);
  2251. return p - s;
  2252. }
  2253. gsize
  2254. rspamd_memspn (const gchar *s, const gchar *e, gsize len)
  2255. {
  2256. gsize byteset[32 / sizeof(gsize)];
  2257. const gchar *p = s, *end = s + len;
  2258. if (!e[1]) {
  2259. for (; p < end && *p == *e; p++);
  2260. return p - s;
  2261. }
  2262. memset (byteset, 0, sizeof byteset);
  2263. for (; *e && BITOP (byteset, *(guchar *)e, |=); e++);
  2264. for (; p < end && BITOP (byteset, *(guchar *)p, &); p++);
  2265. return p - s;
  2266. }
  2267. gssize
  2268. rspamd_decode_qp2047_buf (const gchar *in, gsize inlen,
  2269. gchar *out, gsize outlen)
  2270. {
  2271. gchar *o, *end, c;
  2272. const gchar *p;
  2273. guchar ret;
  2274. gsize remain, processed;
  2275. p = in;
  2276. o = out;
  2277. end = out + outlen;
  2278. remain = inlen;
  2279. while (remain > 0 && o < end) {
  2280. if (*p == '=') {
  2281. p ++;
  2282. remain --;
  2283. if (remain == 0) {
  2284. if (end - o > 0) {
  2285. *o++ = *p;
  2286. break;
  2287. }
  2288. }
  2289. decode:
  2290. /* Decode character after '=' */
  2291. c = *p++;
  2292. remain --;
  2293. ret = 0;
  2294. if (c >= '0' && c <= '9') { ret = c - '0'; }
  2295. else if (c >= 'A' && c <= 'F') { ret = c - 'A' + 10; }
  2296. else if (c >= 'a' && c <= 'f') { ret = c - 'a' + 10; }
  2297. else if (c == '\r' || c == '\n') {
  2298. /* Soft line break */
  2299. while (remain > 0 && (*p == '\r' || *p == '\n')) {
  2300. remain --;
  2301. p ++;
  2302. }
  2303. continue;
  2304. }
  2305. if (remain > 0) {
  2306. c = *p++;
  2307. ret *= 16;
  2308. if (c >= '0' && c <= '9') { ret += c - '0'; }
  2309. else if (c >= 'A' && c <= 'F') { ret += c - 'A' + 10; }
  2310. else if (c >= 'a' && c <= 'f') { ret += c - 'a' + 10; }
  2311. if (end - o > 0) {
  2312. *o++ = (gchar)ret;
  2313. }
  2314. else {
  2315. return (-1);
  2316. }
  2317. remain --;
  2318. }
  2319. }
  2320. else {
  2321. if (end - o >= remain) {
  2322. processed = rspamd_memcspn (p, "=_", remain);
  2323. memcpy (o, p, processed);
  2324. o += processed;
  2325. if (processed == remain) {
  2326. break;
  2327. }
  2328. else {
  2329. remain -= processed;
  2330. p += processed;
  2331. if (G_LIKELY (*p == '=')) {
  2332. p ++;
  2333. /* Skip comparison, as we know that we have found match */
  2334. remain --;
  2335. goto decode;
  2336. }
  2337. else {
  2338. *o++ = ' ';
  2339. p ++;
  2340. remain --;
  2341. }
  2342. }
  2343. }
  2344. else {
  2345. /* Buffer overflow */
  2346. return (-1);
  2347. }
  2348. }
  2349. }
  2350. return (o - out);
  2351. }
  2352. gssize
  2353. rspamd_encode_qp2047_buf (const gchar *in, gsize inlen,
  2354. gchar *out, gsize outlen)
  2355. {
  2356. gchar *o = out, *end = out + outlen, c;
  2357. static const gchar hexdigests[16] = "0123456789ABCDEF";
  2358. while (inlen > 0 && o < end) {
  2359. c = *in;
  2360. if (g_ascii_isalnum (c)) {
  2361. *o++ = c;
  2362. }
  2363. else if (c == ' ') {
  2364. *o++ = '_';
  2365. }
  2366. else if (end - o >= 3){
  2367. *o++ = '=';
  2368. *o++ = hexdigests[((c >> 4) & 0xF)];
  2369. *o++ = hexdigests[(c & 0xF)];
  2370. }
  2371. else {
  2372. return (-1);
  2373. }
  2374. in ++;
  2375. inlen --;
  2376. }
  2377. if (inlen != 0) {
  2378. return (-1);
  2379. }
  2380. return (o - out);
  2381. }
  2382. /*
  2383. * GString ucl emitting functions
  2384. */
  2385. static int
  2386. rspamd_gstring_append_character (unsigned char c, size_t len, void *ud)
  2387. {
  2388. GString *buf = ud;
  2389. gsize old_len;
  2390. if (len == 1) {
  2391. g_string_append_c (buf, c);
  2392. }
  2393. else {
  2394. if (buf->allocated_len - buf->len <= len) {
  2395. old_len = buf->len;
  2396. g_string_set_size (buf, buf->len + len + 1);
  2397. buf->len = old_len;
  2398. }
  2399. memset (&buf->str[buf->len], c, len);
  2400. buf->len += len;
  2401. }
  2402. return 0;
  2403. }
  2404. static int
  2405. rspamd_gstring_append_len (const unsigned char *str, size_t len, void *ud)
  2406. {
  2407. GString *buf = ud;
  2408. g_string_append_len (buf, str, len);
  2409. return 0;
  2410. }
  2411. static int
  2412. rspamd_gstring_append_int (int64_t val, void *ud)
  2413. {
  2414. GString *buf = ud;
  2415. rspamd_printf_gstring (buf, "%L", (intmax_t) val);
  2416. return 0;
  2417. }
  2418. static int
  2419. rspamd_gstring_append_double (double val, void *ud)
  2420. {
  2421. GString *buf = ud;
  2422. const double delta = 0.0000001;
  2423. if (isfinite (val)) {
  2424. if (val == (double) (int) val) {
  2425. rspamd_printf_gstring (buf, "%.1f", val);
  2426. } else if (fabs (val - (double) (int) val) < delta) {
  2427. /* Write at maximum precision */
  2428. rspamd_printf_gstring (buf, "%.*g", DBL_DIG, val);
  2429. } else {
  2430. rspamd_printf_gstring (buf, "%f", val);
  2431. }
  2432. }
  2433. else {
  2434. rspamd_printf_gstring (buf, "null");
  2435. }
  2436. return 0;
  2437. }
  2438. void
  2439. rspamd_ucl_emit_gstring_comments (const ucl_object_t *obj,
  2440. enum ucl_emitter emit_type,
  2441. GString *target,
  2442. const ucl_object_t *comments)
  2443. {
  2444. struct ucl_emitter_functions func = {
  2445. .ucl_emitter_append_character = rspamd_gstring_append_character,
  2446. .ucl_emitter_append_len = rspamd_gstring_append_len,
  2447. .ucl_emitter_append_int = rspamd_gstring_append_int,
  2448. .ucl_emitter_append_double = rspamd_gstring_append_double
  2449. };
  2450. func.ud = target;
  2451. ucl_object_emit_full (obj, emit_type, &func, comments);
  2452. }
  2453. /*
  2454. * FString ucl emitting functions
  2455. */
  2456. static int
  2457. rspamd_fstring_emit_append_character (unsigned char c, size_t len, void *ud)
  2458. {
  2459. rspamd_fstring_t **buf = ud;
  2460. *buf = rspamd_fstring_append_chars (*buf, c, len);
  2461. return 0;
  2462. }
  2463. static int
  2464. rspamd_fstring_emit_append_len (const unsigned char *str, size_t len, void *ud)
  2465. {
  2466. rspamd_fstring_t **buf = ud;
  2467. *buf = rspamd_fstring_append (*buf, str, len);
  2468. return 0;
  2469. }
  2470. static int
  2471. rspamd_fstring_emit_append_int (int64_t val, void *ud)
  2472. {
  2473. rspamd_fstring_t **buf = ud;
  2474. rspamd_printf_fstring (buf, "%L", (intmax_t) val);
  2475. return 0;
  2476. }
  2477. static int
  2478. rspamd_fstring_emit_append_double (double val, void *ud)
  2479. {
  2480. rspamd_fstring_t **buf = ud;
  2481. #define MAX_PRECISION 6
  2482. if (isfinite (val)) {
  2483. if (val == (double) ((gint) val)) {
  2484. rspamd_printf_fstring (buf, "%.1f", val);
  2485. } else {
  2486. rspamd_printf_fstring (buf, "%." G_STRINGIFY (MAX_PRECISION) "f",
  2487. val);
  2488. }
  2489. }
  2490. else {
  2491. rspamd_printf_fstring (buf, "null");
  2492. }
  2493. return 0;
  2494. }
  2495. void
  2496. rspamd_ucl_emit_fstring_comments (const ucl_object_t *obj,
  2497. enum ucl_emitter emit_type,
  2498. rspamd_fstring_t **buf,
  2499. const ucl_object_t *comments)
  2500. {
  2501. struct ucl_emitter_functions func = {
  2502. .ucl_emitter_append_character = rspamd_fstring_emit_append_character,
  2503. .ucl_emitter_append_len = rspamd_fstring_emit_append_len,
  2504. .ucl_emitter_append_int = rspamd_fstring_emit_append_int,
  2505. .ucl_emitter_append_double = rspamd_fstring_emit_append_double
  2506. };
  2507. func.ud = buf;
  2508. ucl_object_emit_full (obj, emit_type, &func, comments);
  2509. }
  2510. #ifndef HAVE_MEMRCHR
  2511. void *
  2512. rspamd_memrchr (const void *m, gint c, gsize len)
  2513. {
  2514. const guint8 *p = m;
  2515. for (gsize i = len; i > 0; i --) {
  2516. if (p[i - 1] == c) {
  2517. return (void *)(p + i - 1);
  2518. }
  2519. }
  2520. return NULL;
  2521. }
  2522. #endif
  2523. struct UConverter *
  2524. rspamd_get_utf8_converter (void)
  2525. {
  2526. static UConverter *utf8_conv = NULL;
  2527. UErrorCode uc_err = U_ZERO_ERROR;
  2528. if (utf8_conv == NULL) {
  2529. utf8_conv = ucnv_open ("UTF-8", &uc_err);
  2530. if (!U_SUCCESS (uc_err)) {
  2531. msg_err ("FATAL error: cannot open converter for utf8: %s",
  2532. u_errorName (uc_err));
  2533. g_assert_not_reached ();
  2534. }
  2535. ucnv_setFromUCallBack (utf8_conv,
  2536. UCNV_FROM_U_CALLBACK_SUBSTITUTE,
  2537. NULL,
  2538. NULL,
  2539. NULL,
  2540. &uc_err);
  2541. ucnv_setToUCallBack (utf8_conv,
  2542. UCNV_TO_U_CALLBACK_SUBSTITUTE,
  2543. NULL,
  2544. NULL,
  2545. NULL,
  2546. &uc_err);
  2547. }
  2548. return utf8_conv;
  2549. }
  2550. const struct UNormalizer2 *
  2551. rspamd_get_unicode_normalizer (void)
  2552. {
  2553. #if U_ICU_VERSION_MAJOR_NUM >= 44
  2554. UErrorCode uc_err = U_ZERO_ERROR;
  2555. static const UNormalizer2 *norm = NULL;
  2556. if (norm == NULL) {
  2557. norm = unorm2_getInstance (NULL, "nfkc", UNORM2_COMPOSE, &uc_err);
  2558. g_assert (U_SUCCESS (uc_err));
  2559. }
  2560. return norm;
  2561. #else
  2562. /* Old libicu */
  2563. return NULL;
  2564. #endif
  2565. }
  2566. enum rspamd_normalise_result
  2567. rspamd_normalise_unicode_inplace (rspamd_mempool_t *pool, gchar *start,
  2568. guint *len)
  2569. {
  2570. #if U_ICU_VERSION_MAJOR_NUM >= 44
  2571. UErrorCode uc_err = U_ZERO_ERROR;
  2572. UConverter *utf8_conv = rspamd_get_utf8_converter ();
  2573. const UNormalizer2 *norm = rspamd_get_unicode_normalizer ();
  2574. gint32 nsym, end;
  2575. UChar *src = NULL, *dest = NULL;
  2576. enum rspamd_normalise_result ret = 0;
  2577. gboolean has_invisible = FALSE;
  2578. /* We first need to convert data to UChars :( */
  2579. src = g_malloc ((*len + 1) * sizeof (*src));
  2580. nsym = ucnv_toUChars (utf8_conv, src, *len + 1,
  2581. start, *len, &uc_err);
  2582. if (!U_SUCCESS (uc_err)) {
  2583. msg_warn_pool_check ("cannot normalise URL, cannot convert to unicode: %s",
  2584. u_errorName (uc_err));
  2585. ret |= RSPAMD_UNICODE_NORM_ERROR;
  2586. goto out;
  2587. }
  2588. /* We can now check if we need to decompose */
  2589. end = unorm2_spanQuickCheckYes (norm, src, nsym, &uc_err);
  2590. if (!U_SUCCESS (uc_err)) {
  2591. msg_warn_pool_check ("cannot normalise URL, cannot check normalisation: %s",
  2592. u_errorName (uc_err));
  2593. ret |= RSPAMD_UNICODE_NORM_ERROR;
  2594. goto out;
  2595. }
  2596. for (gint32 i = 0; i < nsym; i ++) {
  2597. if (IS_ZERO_WIDTH_SPACE (src[i])) {
  2598. has_invisible = TRUE;
  2599. break;
  2600. }
  2601. }
  2602. uc_err = U_ZERO_ERROR;
  2603. if (end != nsym) {
  2604. /* No normalisation needed, but we may still have invisible spaces */
  2605. /* We copy sub(src, 0, end) to dest and normalise the rest */
  2606. ret |= RSPAMD_UNICODE_NORM_UNNORMAL;
  2607. dest = g_malloc (nsym * sizeof (*dest));
  2608. memcpy (dest, src, end * sizeof (*dest));
  2609. nsym = unorm2_normalizeSecondAndAppend (norm, dest, end, nsym,
  2610. src + end, nsym - end, &uc_err);
  2611. if (!U_SUCCESS (uc_err)) {
  2612. if (uc_err != U_BUFFER_OVERFLOW_ERROR) {
  2613. msg_warn_pool_check ("cannot normalise URL: %s",
  2614. u_errorName (uc_err));
  2615. ret |= RSPAMD_UNICODE_NORM_ERROR;
  2616. }
  2617. goto out;
  2618. }
  2619. }
  2620. else if (!has_invisible) {
  2621. goto out;
  2622. }
  2623. else {
  2624. dest = src;
  2625. src = NULL;
  2626. }
  2627. if (has_invisible) {
  2628. /* Also filter zero width spaces */
  2629. gint32 new_len = 0;
  2630. UChar *t = dest, *h = dest;
  2631. ret |= RSPAMD_UNICODE_NORM_ZERO_SPACES;
  2632. for (gint32 i = 0; i < nsym; i ++) {
  2633. if (!IS_ZERO_WIDTH_SPACE (*h)) {
  2634. *t++ = *h++;
  2635. new_len ++;
  2636. }
  2637. else {
  2638. h ++;
  2639. }
  2640. }
  2641. nsym = new_len;
  2642. }
  2643. /* We now convert it back to utf */
  2644. nsym = ucnv_fromUChars (utf8_conv, start, *len, dest, nsym, &uc_err);
  2645. if (!U_SUCCESS (uc_err)) {
  2646. msg_warn_pool_check ("cannot normalise URL, cannot convert to UTF8: %s"
  2647. " input length: %d chars, unicode length: %d utf16 symbols",
  2648. u_errorName (uc_err), (gint)*len, (gint)nsym);
  2649. if (uc_err == U_BUFFER_OVERFLOW_ERROR) {
  2650. ret |= RSPAMD_UNICODE_NORM_OVERFLOW;
  2651. }
  2652. else {
  2653. ret |= RSPAMD_UNICODE_NORM_ERROR;
  2654. }
  2655. goto out;
  2656. }
  2657. *len = nsym;
  2658. out:
  2659. if (src) {
  2660. g_free (src);
  2661. }
  2662. if (dest) {
  2663. g_free (dest);
  2664. }
  2665. return ret;
  2666. #else
  2667. /* Kill that with fire please */
  2668. return FALSE;
  2669. #endif
  2670. }
  2671. gchar *
  2672. rspamd_str_regexp_escape (const gchar *pattern, gsize slen,
  2673. gsize *dst_len, enum rspamd_regexp_escape_flags flags)
  2674. {
  2675. const gchar *p, *end = pattern + slen;
  2676. gchar *res, *d, t, *tmp_utf = NULL, *dend;
  2677. gsize len;
  2678. static const gchar hexdigests[16] = "0123456789abcdef";
  2679. len = 0;
  2680. p = pattern;
  2681. /* [-[\]{}()*+?.,\\^$|#\s] need to be escaped */
  2682. while (p < end) {
  2683. t = *p ++;
  2684. switch (t) {
  2685. case '[':
  2686. case ']':
  2687. case '-':
  2688. case '\\':
  2689. case '{':
  2690. case '}':
  2691. case '(':
  2692. case ')':
  2693. case '*':
  2694. case '+':
  2695. case '?':
  2696. case '.':
  2697. case ',':
  2698. case '^':
  2699. case '$':
  2700. case '|':
  2701. case '#':
  2702. if (!(flags & RSPAMD_REGEXP_ESCAPE_RE)) {
  2703. len++;
  2704. }
  2705. break;
  2706. default:
  2707. if (g_ascii_isspace (t)) {
  2708. len ++;
  2709. }
  2710. else {
  2711. if (!g_ascii_isprint (t) || (t & 0x80)) {
  2712. if (flags & RSPAMD_REGEXP_ESCAPE_UTF) {
  2713. /* \x{code}, where code can be up to 5 digits */
  2714. len += 4;
  2715. }
  2716. else {
  2717. /* \\xHH -> 4 symbols */
  2718. len += 3;
  2719. }
  2720. }
  2721. }
  2722. break;
  2723. }
  2724. }
  2725. if (flags & RSPAMD_REGEXP_ESCAPE_UTF) {
  2726. if (rspamd_fast_utf8_validate (pattern, slen) != 0) {
  2727. tmp_utf = rspamd_str_make_utf_valid (pattern, slen, NULL, NULL);
  2728. }
  2729. }
  2730. if (len == 0) {
  2731. /* No need to escape anything */
  2732. if (dst_len) {
  2733. *dst_len = slen;
  2734. }
  2735. if (tmp_utf) {
  2736. return tmp_utf;
  2737. }
  2738. else {
  2739. return g_strdup (pattern);
  2740. }
  2741. }
  2742. /* Escape logic */
  2743. if (tmp_utf) {
  2744. pattern = tmp_utf;
  2745. }
  2746. len = slen + len;
  2747. res = g_malloc (len + 1);
  2748. p = pattern;
  2749. d = res;
  2750. dend = d + len;
  2751. while (p < end) {
  2752. g_assert (d < dend);
  2753. t = *p ++;
  2754. switch (t) {
  2755. case '[':
  2756. case ']':
  2757. case '-':
  2758. case '\\':
  2759. case '{':
  2760. case '}':
  2761. case '(':
  2762. case ')':
  2763. case '.':
  2764. case ',':
  2765. case '^':
  2766. case '$':
  2767. case '|':
  2768. case '#':
  2769. if (!(flags & RSPAMD_REGEXP_ESCAPE_RE)) {
  2770. *d++ = '\\';
  2771. }
  2772. break;
  2773. case '*':
  2774. case '?':
  2775. case '+':
  2776. if (flags & RSPAMD_REGEXP_ESCAPE_GLOB) {
  2777. /* Treat * as .* and ? as .? */
  2778. *d++ = '.';
  2779. }
  2780. else {
  2781. if (!(flags & RSPAMD_REGEXP_ESCAPE_RE)) {
  2782. *d++ = '\\';
  2783. }
  2784. }
  2785. break;
  2786. default:
  2787. if (g_ascii_isspace (t)) {
  2788. if (!(flags & RSPAMD_REGEXP_ESCAPE_RE)) {
  2789. *d++ = '\\';
  2790. }
  2791. }
  2792. else if (t & 0x80 || !g_ascii_isprint (t)) {
  2793. if (!(flags & RSPAMD_REGEXP_ESCAPE_UTF)) {
  2794. *d++ = '\\';
  2795. *d++ = 'x';
  2796. *d++ = hexdigests[((t >> 4) & 0xF)];
  2797. *d++ = hexdigests[((t) & 0xF)];
  2798. continue; /* To avoid *d++ = t; */
  2799. }
  2800. else {
  2801. if (flags & (RSPAMD_REGEXP_ESCAPE_RE|RSPAMD_REGEXP_ESCAPE_GLOB)) {
  2802. UChar32 uc;
  2803. gint32 off = p - pattern - 1;
  2804. U8_NEXT (pattern, off, slen, uc);
  2805. if (uc > 0) {
  2806. d += rspamd_snprintf (d, dend - d,
  2807. "\\x{%xd}", uc);
  2808. p = pattern + off;
  2809. }
  2810. continue; /* To avoid *d++ = t; */
  2811. }
  2812. }
  2813. }
  2814. break;
  2815. }
  2816. *d++ = t;
  2817. }
  2818. *d = '\0';
  2819. if (dst_len) {
  2820. *dst_len = d - res;
  2821. }
  2822. if (tmp_utf) {
  2823. g_free (tmp_utf);
  2824. }
  2825. return res;
  2826. }
  2827. gchar *
  2828. rspamd_str_make_utf_valid (const guchar *src, gsize slen,
  2829. gsize *dstlen,
  2830. rspamd_mempool_t *pool)
  2831. {
  2832. UChar32 uc;
  2833. goffset err_offset;
  2834. const guchar *p;
  2835. gchar *dst, *d;
  2836. gsize remain = slen, dlen = 0;
  2837. if (src == NULL) {
  2838. return NULL;
  2839. }
  2840. if (slen == 0) {
  2841. if (dstlen) {
  2842. *dstlen = 0;
  2843. }
  2844. return pool ? rspamd_mempool_strdup (pool, "") : g_strdup ("");
  2845. }
  2846. p = src;
  2847. dlen = slen + 1; /* As we add '\0' */
  2848. /* Check space required */
  2849. while (remain > 0 && (err_offset = rspamd_fast_utf8_validate (p, remain)) > 0) {
  2850. gint i = 0;
  2851. err_offset --; /* As it returns it 1 indexed */
  2852. p += err_offset;
  2853. remain -= err_offset;
  2854. dlen += err_offset;
  2855. /* Each invalid character of input requires 3 bytes of output (+2 bytes) */
  2856. while (i < remain) {
  2857. U8_NEXT (p, i, remain, uc);
  2858. if (uc < 0) {
  2859. dlen += 2;
  2860. }
  2861. else {
  2862. break;
  2863. }
  2864. }
  2865. p += i;
  2866. remain -= i;
  2867. }
  2868. if (pool) {
  2869. dst = rspamd_mempool_alloc (pool, dlen + 1);
  2870. }
  2871. else {
  2872. dst = g_malloc (dlen + 1);
  2873. }
  2874. p = src;
  2875. d = dst;
  2876. remain = slen;
  2877. while (remain > 0 && (err_offset = rspamd_fast_utf8_validate (p, remain)) > 0) {
  2878. /* Copy valid */
  2879. err_offset --; /* As it returns it 1 indexed */
  2880. memcpy (d, p, err_offset);
  2881. d += err_offset;
  2882. /* Append 0xFFFD for each bad character */
  2883. gint i = 0;
  2884. p += err_offset;
  2885. remain -= err_offset;
  2886. while (i < remain) {
  2887. gint old_i = i;
  2888. U8_NEXT (p, i, remain, uc);
  2889. if (uc < 0) {
  2890. *d++ = '\357';
  2891. *d++ = '\277';
  2892. *d++ = '\275';
  2893. }
  2894. else {
  2895. /* Adjust p and remaining stuff and go to the outer cycle */
  2896. i = old_i;
  2897. break;
  2898. }
  2899. }
  2900. /*
  2901. * Now p is the first valid utf8 character and remain is the rest of the string
  2902. * so we can continue our loop
  2903. */
  2904. p += i;
  2905. remain -= i;
  2906. }
  2907. if (err_offset == 0 && remain > 0) {
  2908. /* Last piece */
  2909. memcpy (d, p, remain);
  2910. d += remain;
  2911. }
  2912. /* Last '\0' */
  2913. g_assert (dlen > d - dst);
  2914. *d = '\0';
  2915. if (dstlen) {
  2916. *dstlen = d - dst;
  2917. }
  2918. return dst;
  2919. }
  2920. gsize
  2921. rspamd_gstring_strip (GString *s, const gchar *strip_chars)
  2922. {
  2923. const gchar *p, *sc;
  2924. gsize strip_len = 0, total = 0;
  2925. p = s->str + s->len - 1;
  2926. while (p >= s->str) {
  2927. gboolean seen = FALSE;
  2928. sc = strip_chars;
  2929. while (*sc != '\0') {
  2930. if (*p == *sc) {
  2931. strip_len ++;
  2932. seen = TRUE;
  2933. break;
  2934. }
  2935. sc ++;
  2936. }
  2937. if (!seen) {
  2938. break;
  2939. }
  2940. p --;
  2941. }
  2942. if (strip_len > 0) {
  2943. s->len -= strip_len;
  2944. s->str[s->len] = '\0';
  2945. total += strip_len;
  2946. }
  2947. if (s->len > 0) {
  2948. strip_len = rspamd_memspn (s->str, strip_chars, s->len);
  2949. if (strip_len > 0) {
  2950. memmove (s->str, s->str + strip_len, s->len - strip_len);
  2951. s->len -= strip_len;
  2952. total += strip_len;
  2953. }
  2954. }
  2955. return total;
  2956. }
  2957. const gchar* rspamd_string_len_strip (const gchar *in,
  2958. gsize *len,
  2959. const gchar *strip_chars)
  2960. {
  2961. const gchar *p, *sc;
  2962. gsize strip_len = 0, old_len = *len;
  2963. p = in + old_len - 1;
  2964. /* Trail */
  2965. while (p >= in) {
  2966. gboolean seen = FALSE;
  2967. sc = strip_chars;
  2968. while (*sc != '\0') {
  2969. if (*p == *sc) {
  2970. strip_len ++;
  2971. seen = TRUE;
  2972. break;
  2973. }
  2974. sc ++;
  2975. }
  2976. if (!seen) {
  2977. break;
  2978. }
  2979. p --;
  2980. }
  2981. if (strip_len > 0) {
  2982. *len -= strip_len;
  2983. }
  2984. /* Head */
  2985. old_len = *len;
  2986. if (old_len > 0) {
  2987. strip_len = rspamd_memspn (in, strip_chars, old_len);
  2988. if (strip_len > 0) {
  2989. *len -= strip_len;
  2990. return in + strip_len;
  2991. }
  2992. }
  2993. return in;
  2994. }
  2995. gchar **
  2996. rspamd_string_len_split (const gchar *in, gsize len, const gchar *spill,
  2997. gint max_elts, rspamd_mempool_t *pool)
  2998. {
  2999. const gchar *p = in, *end = in + len;
  3000. gsize detected_elts = 0;
  3001. gchar **res;
  3002. /* Detect number of elements */
  3003. while (p < end) {
  3004. gsize cur_fragment = rspamd_memcspn (p, spill, end - p);
  3005. if (cur_fragment > 0) {
  3006. detected_elts ++;
  3007. p += cur_fragment;
  3008. if (max_elts > 0 && detected_elts >= max_elts) {
  3009. break;
  3010. }
  3011. }
  3012. /* Something like a,,b produces {'a', 'b'} not {'a', '', 'b'} */
  3013. p += rspamd_memspn (p, spill, end - p);
  3014. }
  3015. res = pool ?
  3016. rspamd_mempool_alloc (pool, sizeof (gchar *) * (detected_elts + 1)) :
  3017. g_malloc (sizeof (gchar *) * (detected_elts + 1));
  3018. /* Last one */
  3019. res[detected_elts] = NULL;
  3020. detected_elts = 0;
  3021. p = in;
  3022. while (p < end) {
  3023. gsize cur_fragment = rspamd_memcspn (p, spill, end - p);
  3024. if (cur_fragment > 0) {
  3025. gchar *elt;
  3026. elt = pool ?
  3027. rspamd_mempool_alloc (pool, cur_fragment + 1) :
  3028. g_malloc (cur_fragment + 1);
  3029. memcpy (elt, p, cur_fragment);
  3030. elt[cur_fragment] = '\0';
  3031. res[detected_elts ++] = elt;
  3032. p += cur_fragment;
  3033. if (max_elts > 0 && detected_elts >= max_elts) {
  3034. break;
  3035. }
  3036. }
  3037. p += rspamd_memspn (p, spill, end - p);
  3038. }
  3039. return res;
  3040. }
  3041. #if defined(__x86_64__)
  3042. #include <x86intrin.h>
  3043. #endif
  3044. static inline gboolean
  3045. rspamd_str_has_8bit_u64 (const guchar *beg, gsize len)
  3046. {
  3047. guint8 orb = 0;
  3048. if (len >= 16) {
  3049. const guchar *nextd = beg+8;
  3050. guint64 n1 = 0, n2 = 0;
  3051. do {
  3052. n1 |= *(const guint64 *)beg;
  3053. n2 |= *(const guint64 *)nextd;
  3054. beg += 16;
  3055. nextd += 16;
  3056. len -= 16;
  3057. } while (len >= 16);
  3058. /*
  3059. * Idea from Benny Halevy <bhalevy@scylladb.com>
  3060. * - 7-th bit set ==> orb = !(non-zero) - 1 = 0 - 1 = 0xFF
  3061. * - 7-th bit clear ==> orb = !0 - 1 = 1 - 1 = 0x00
  3062. */
  3063. orb = !((n1 | n2) & 0x8080808080808080ULL) - 1;
  3064. }
  3065. while (len--) {
  3066. orb |= *beg++;
  3067. }
  3068. return orb >= 0x80;
  3069. }
  3070. gboolean
  3071. rspamd_str_has_8bit (const guchar *beg, gsize len)
  3072. {
  3073. #if defined(__x86_64__)
  3074. if (len >= 32) {
  3075. const uint8_t *nextd = beg + 16;
  3076. __m128i n1 = _mm_set1_epi8 (0), n2;
  3077. n2 = n1;
  3078. while (len >= 32) {
  3079. __m128i xmm1 = _mm_loadu_si128 ((const __m128i *)beg);
  3080. __m128i xmm2 = _mm_loadu_si128 ((const __m128i *)nextd);
  3081. n1 = _mm_or_si128 (n1, xmm1);
  3082. n2 = _mm_or_si128 (n2, xmm2);
  3083. beg += 32;
  3084. nextd += 32;
  3085. len -= 32;
  3086. }
  3087. n1 = _mm_or_si128 (n1, n2);
  3088. /* We assume 2 complement here */
  3089. if (_mm_movemask_epi8 (n1)) {
  3090. return TRUE;
  3091. }
  3092. }
  3093. #endif
  3094. return rspamd_str_has_8bit_u64 (beg, len);
  3095. }