Skip to content

Commit 0600769

Browse files
authored
feat: safe sscanf (#108)
1 parent 790a1f0 commit 0600769

12 files changed

+836
-47
lines changed

Makefile.am

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@ psqlodbca_la_SOURCES = \
2121
statement.c tuple.c dlg_specific.c \
2222
multibyte.c odbcapi.c descriptor.c \
2323
odbcapi30.c pgapi30.c mylog.c \
24+
secure_sscanf.c \
2425
\
2526
bind.h catfunc.h columninfo.h connection.h convert.h \
2627
descriptor.h dlg_specific.h environ.h unicode_support.h \
2728
lobj.h misc.h multibyte.h pgapifunc.h pgtypes.h \
2829
psqlodbc.h qresult.h resource.h statement.h tuple.h \
29-
version.h pgenlist.h mylog.h xalibname.h
30+
version.h pgenlist.h mylog.h xalibname.h \
31+
secure_sscanf.h
3032

3133
psqlodbcw_la_SOURCES = $(psqlodbca_la_SOURCES) \
3234
odbcapi30w.c odbcapiw.c win_unicode.c

convert.c

+65-23
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
#include "catfunc.h"
4848
#include "pgapifunc.h"
4949

50+
#include "secure_sscanf.h"
51+
5052
CSTR NAN_STRING = "NaN";
5153
CSTR INFINITY_STRING = "Infinity";
5254
CSTR MINFINITY_STRING = "-Infinity";
@@ -255,14 +257,16 @@ static SQLLEN pg_bin2whex(const char *src, SQLWCHAR *dst, SQLLEN length);
255257
#else
256258
static ODBCINT64 ATOI64(const char *val)
257259
{
260+
int status;
258261
ODBCINT64 ll;
259-
sscanf(val, "%lld", &ll);
262+
secure_sscanf(val, &status, "%lld", ARG_LLONG(&ll));
260263
return ll;
261264
}
262265
static unsigned ODBCINT64 ATOI64U(const char *val)
263266
{
267+
int status;
264268
unsigned ODBCINT64 ll;
265-
sscanf(val, "%llu", &ll);
269+
secure_sscanf(val, &status, "%llu", ARG_ULLONG(&ll));
266270
return ll;
267271
}
268272
#endif /* HAVE_STRTOLL */
@@ -283,6 +287,7 @@ timestamp2stime(const char *str, SIMPLE_TIME *st, BOOL *bZone, int *zone)
283287
char rest[64], bc[16],
284288
*ptr;
285289
int scnt,
290+
status,
286291
i;
287292
int y, m, d, hh, mm, ss;
288293
#ifdef TIMEZONE_GLOBAL
@@ -296,7 +301,10 @@ timestamp2stime(const char *str, SIMPLE_TIME *st, BOOL *bZone, int *zone)
296301
st->infinity = 0;
297302
rest[0] = '\0';
298303
bc[0] = '\0';
299-
if ((scnt = sscanf(str, "%4d-%2d-%2d %2d:%2d:%2d%31s %15s", &y, &m, &d, &hh, &mm, &ss, rest, bc)) < 6)
304+
if ((scnt = secure_sscanf(str, &status, "%4d-%2d-%2d %2d:%2d:%2d%31s %15s",
305+
ARG_INT(&y), ARG_INT(&m), ARG_INT(&d),
306+
ARG_INT(&hh), ARG_INT(&mm), ARG_INT(&ss),
307+
ARG_STR(&rest, sizeof(rest)), ARG_STR(&bc, sizeof(bc)))) < 6)
300308
{
301309
if (scnt == 3) /* date */
302310
{
@@ -308,7 +316,9 @@ timestamp2stime(const char *str, SIMPLE_TIME *st, BOOL *bZone, int *zone)
308316
st->ss = 0;
309317
return TRUE;
310318
}
311-
if ((scnt = sscanf(str, "%2d:%2d:%2d%31s %15s", &hh, &mm, &ss, rest, bc)) < 3)
319+
if ((scnt = secure_sscanf(str, &status, "%2d:%2d:%2d%31s %15s",
320+
ARG_INT(&hh), ARG_INT(&mm), ARG_INT(&ss),
321+
ARG_STR(&rest, sizeof(rest)), ARG_STR(&bc, sizeof(bc)))) < 3)
312322
return FALSE;
313323
else
314324
{
@@ -573,9 +583,11 @@ interval2istruct(SQLSMALLINT ctype, int precision, const char *str, SQL_INTERVAL
573583
int scnt, years, mons, days, hours, minutes, seconds;
574584
BOOL sign;
575585
SQLINTERVAL itype = interval2itype(ctype);
586+
int status = 0;
576587

577588
pg_memset(st, 0, sizeof(SQL_INTERVAL_STRUCT));
578-
if ((scnt = sscanf(str, "%d-%d", &years, &mons)) >=2)
589+
if ((scnt = secure_sscanf(str, &status, "%d-%d",
590+
ARG_INT(&years), ARG_INT(&mons))) >=2)
579591
{
580592
if (SQL_IS_YEAR_TO_MONTH == itype)
581593
{
@@ -588,7 +600,11 @@ interval2istruct(SQLSMALLINT ctype, int precision, const char *str, SQL_INTERVAL
588600
}
589601
return FALSE;
590602
}
591-
else if (scnt = sscanf(str, "%d %02d:%02d:%02d.%09s", &days, &hours, &minutes, &seconds, lit2), 5 == scnt || 4 == scnt)
603+
else if (scnt = secure_sscanf(str, &status, "%d %02d:%02d:%02d.%09s",
604+
ARG_INT(&days), ARG_INT(&hours),
605+
ARG_INT(&minutes), ARG_INT(&seconds),
606+
ARG_STR(&lit2, sizeof(lit2))
607+
), 5 == scnt || 4 == scnt)
592608
{
593609
sign = days < 0 ? SQL_TRUE : SQL_FALSE;
594610
st->interval_type = itype;
@@ -601,7 +617,9 @@ interval2istruct(SQLSMALLINT ctype, int precision, const char *str, SQL_INTERVAL
601617
st->intval.day_second.fraction = getPrecisionPart(precision, lit2);
602618
return TRUE;
603619
}
604-
else if ((scnt = sscanf(str, "%d %10s %d %10s", &years, lit1, &mons, lit2)) >=4)
620+
else if ((scnt = secure_sscanf(str, &status, "%d %10s %d %10s",
621+
ARG_INT(&years), ARG_STR(&lit1, sizeof(lit1)),
622+
ARG_INT(&mons), ARG_STR(&lit2, sizeof(lit2)))) >=4)
605623
{
606624
if (strnicmp(lit1, "year", 4) == 0 &&
607625
strnicmp(lit2, "mon", 2) == 0 &&
@@ -617,7 +635,9 @@ interval2istruct(SQLSMALLINT ctype, int precision, const char *str, SQL_INTERVAL
617635
}
618636
return FALSE;
619637
}
620-
if ((scnt = sscanf(str, "%d %10s %d", &years, lit1, &days)) == 2)
638+
if ((scnt = secure_sscanf(str, &status, "%d %10s %d",
639+
ARG_INT(&years), ARG_STR(&lit1, sizeof(lit1)),
640+
ARG_INT(&days))) == 2)
621641
{
622642
sign = years < 0 ? SQL_TRUE : SQL_FALSE;
623643
if (SQL_IS_YEAR == itype &&
@@ -654,7 +674,10 @@ interval2istruct(SQLSMALLINT ctype, int precision, const char *str, SQL_INTERVAL
654674
/* these formats should've been handled above already */
655675
return FALSE;
656676
}
657-
scnt = sscanf(str, "%d %10s %02d:%02d:%02d.%09s", &days, lit1, &hours, &minutes, &seconds, lit2);
677+
scnt = secure_sscanf(str, &status, "%d %10s %02d:%02d:%02d.%09s",
678+
ARG_INT(&days), ARG_STR(&lit1, sizeof(lit1)),
679+
ARG_INT(&hours), ARG_INT(&minutes), ARG_INT(&seconds),
680+
ARG_STR(&lit2, sizeof(lit2)));
658681
if (scnt == 5 || scnt == 6)
659682
{
660683
if (strnicmp(lit1, "day", 3) != 0)
@@ -671,7 +694,9 @@ interval2istruct(SQLSMALLINT ctype, int precision, const char *str, SQL_INTERVAL
671694
st->intval.day_second.fraction = getPrecisionPart(precision, lit2);
672695
return TRUE;
673696
}
674-
scnt = sscanf(str, "%02d:%02d:%02d.%09s", &hours, &minutes, &seconds, lit2);
697+
scnt = secure_sscanf(str, &status, "%02d:%02d:%02d.%09s",
698+
ARG_INT(&hours), ARG_INT(&minutes), ARG_INT(&seconds),
699+
ARG_STR(&lit2, sizeof(lit2)));
675700
if (scnt == 3 || scnt == 4)
676701
{
677702
sign = hours < 0 ? SQL_TRUE : SQL_FALSE;
@@ -860,12 +885,15 @@ static int char2guid(const char *str, SQLGUID *g)
860885
* "unsigned int", so use a temporary variable for it.
861886
*/
862887
unsigned int Data1;
863-
if (sscanf(str,
888+
int status = 0;
889+
if (secure_sscanf(str, &status,
864890
"%08X-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX",
865-
&Data1,
866-
&g->Data2, &g->Data3,
867-
&g->Data4[0], &g->Data4[1], &g->Data4[2], &g->Data4[3],
868-
&g->Data4[4], &g->Data4[5], &g->Data4[6], &g->Data4[7]) < 11)
891+
ARG_UINT(&Data1),
892+
ARG_USHORT(&g->Data2), ARG_USHORT(&g->Data3),
893+
ARG_UCHAR(&g->Data4[0]), ARG_UCHAR(&g->Data4[1]),
894+
ARG_UCHAR(&g->Data4[2]), ARG_UCHAR(&g->Data4[3]),
895+
ARG_UCHAR(&g->Data4[4]), ARG_UCHAR(&g->Data4[5]),
896+
ARG_UCHAR(&g->Data4[6]), ARG_UCHAR(&g->Data4[7])) < 11)
869897
return COPY_GENERAL_ERROR;
870898
g->Data1 = Data1;
871899
return COPY_OK;
@@ -1416,7 +1444,11 @@ MYLOG(0, "null_cvt_date_string=%d\n", conn->connInfo.cvt_null_date_string);
14161444
* PG_TYPE_CHAR,VARCHAR $$$
14171445
*/
14181446
case PG_TYPE_DATE:
1419-
sscanf(value, "%4d-%2d-%2d", &std_time.y, &std_time.m, &std_time.d);
1447+
{
1448+
int status = 0;
1449+
secure_sscanf(value, &status, "%4d-%2d-%2d",
1450+
ARG_INT(&std_time.y), ARG_INT(&std_time.m), ARG_INT(&std_time.d));
1451+
}
14201452
break;
14211453

14221454
case PG_TYPE_TIME:
@@ -1530,7 +1562,8 @@ MYLOG(DETAIL_LOG_LEVEL, "2stime fr=%d\n", std_time.fr);
15301562
MYLOG(0, "index=(");
15311563
for (i = 0;; i++)
15321564
{
1533-
if (sscanf(vp, "%hi", &shortv) != 1)
1565+
int status = 0;
1566+
if (secure_sscanf(vp, &status, "%hi", ARG_SHORT(&shortv)) != 1)
15341567
break;
15351568
MYPRINTF(0, " %hi", shortv);
15361569
nval++;
@@ -5555,7 +5588,8 @@ convert_escape(QueryParse *qp, QueryBuild *qb)
55555588
while (isspace((UCHAR) qp->statement[++qp->opos]));
55565589
}
55575590

5558-
sscanf(F_OldPtr(qp), "%32s", key);
5591+
int status = 0;
5592+
secure_sscanf(F_OldPtr(qp), &status, "%32s", ARG_STR(&key, sizeof(key)));
55595593
while ((ucv = F_OldChar(qp)) != '\0' && (IS_NOT_SPACE(ucv)))
55605594
F_OldNext(qp);
55615595
while ((ucv = F_OldChar(qp)) != '\0' && isspace(ucv))
@@ -5970,6 +6004,7 @@ parse_datetime(const char *buf, SIMPLE_TIME *st)
59706004
mm,
59716005
ss;
59726006
int nf;
6007+
int status = 0;
59736008
BOOL bZone; int zone;
59746009

59756010
y = m = d = hh = mm = ss = 0;
@@ -5993,9 +6028,13 @@ parse_datetime(const char *buf, SIMPLE_TIME *st)
59936028
if (timestamp2stime(buf, st, &bZone, &zone))
59946029
return TRUE;
59956030
if (buf[4] == '-') /* year first */
5996-
nf = sscanf(buf, "%4d-%2d-%2d %2d:%2d:%2d", &y, &m, &d, &hh, &mm, &ss);
6031+
nf = secure_sscanf(buf, &status, "%4d-%2d-%2d %2d:%2d:%2d",
6032+
ARG_INT(&y), ARG_INT(&m), ARG_INT(&d),
6033+
ARG_INT(&hh), ARG_INT(&mm), ARG_INT(&ss));
59976034
else
5998-
nf = sscanf(buf, "%2d-%2d-%4d %2d:%2d:%2d", &m, &d, &y, &hh, &mm, &ss);
6035+
nf = secure_sscanf(buf, &status, "%2d-%2d-%4d %2d:%2d:%2d",
6036+
ARG_INT(&m), ARG_INT(&d), ARG_INT(&y),
6037+
ARG_INT(&hh), ARG_INT(&mm), ARG_INT(&ss));
59996038

60006039
if (nf == 5 || nf == 6)
60016040
{
@@ -6010,9 +6049,11 @@ parse_datetime(const char *buf, SIMPLE_TIME *st)
60106049
}
60116050

60126051
if (buf[4] == '-') /* year first */
6013-
nf = sscanf(buf, "%4d-%2d-%2d", &y, &m, &d);
6052+
nf = secure_sscanf(buf, &status, "%4d-%2d-%2d",
6053+
ARG_INT(&y), ARG_INT(&m), ARG_INT(&d));
60146054
else
6015-
nf = sscanf(buf, "%2d-%2d-%4d", &m, &d, &y);
6055+
nf = secure_sscanf(buf, &status, "%2d-%2d-%4d",
6056+
ARG_INT(&m), ARG_INT(&d), ARG_INT(&y));
60166057

60176058
if (nf == 3)
60186059
{
@@ -6023,7 +6064,8 @@ parse_datetime(const char *buf, SIMPLE_TIME *st)
60236064
return TRUE;
60246065
}
60256066

6026-
nf = sscanf(buf, "%2d:%2d:%2d", &hh, &mm, &ss);
6067+
nf = secure_sscanf(buf, &status, "%2d:%2d:%2d",
6068+
ARG_INT(&hh), ARG_INT(&mm), ARG_INT(&ss));
60276069
if (nf == 2 || nf == 3)
60286070
{
60296071
st->hh = hh;

dlg_specific.c

+15-7
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323

2424
#include "pgapifunc.h"
2525

26+
#include "secure_sscanf.h"
27+
2628
#define NULL_IF_NULL(a) ((a) ? ((const char *)(a)) : "(null)")
2729
CSTR ENTRY_TEST = " @@@ ";
2830

@@ -103,6 +105,7 @@ BOOL setExtraOptions(ConnInfo *ci, const char *optstr, const char *format)
103105
{
104106
UInt4 flag = 0, cnt;
105107
char dummy[2];
108+
int status = 0;
106109

107110
if (!format)
108111
{
@@ -127,7 +130,8 @@ BOOL setExtraOptions(ConnInfo *ci, const char *optstr, const char *format)
127130
format = dec_format;
128131
}
129132

130-
if (cnt = sscanf(optstr, format, &flag, dummy), cnt < 1) // format error
133+
if (cnt = secure_sscanf(optstr, &status, format,
134+
ARG_UINT(&flag), ARG_STR(&dummy, sizeof(dummy))), cnt < 1) // format error
131135
return FALSE;
132136
else if (cnt > 1) // format error
133137
return FALSE;
@@ -551,19 +555,20 @@ unfoldCXAttribute(ConnInfo *ci, const char *value)
551555
{
552556
int count;
553557
UInt4 flag;
558+
int status = 0;
554559

555560
if (strlen(value) < 2)
556561
{
557562
count = 3;
558-
sscanf(value, "%x", &flag);
563+
secure_sscanf(value, &status, "%x", ARG_UINT(&flag));
559564
}
560565
else
561566
{
562567
char cnt[8];
563568
memcpy(cnt, value, 2);
564569
cnt[2] = '\0';
565-
sscanf(cnt, "%x", &count);
566-
sscanf(value + 2, "%x", &flag);
570+
secure_sscanf(cnt, &status, "%x", ARG_UINT(&count));
571+
secure_sscanf(value + 2, &status, "%x", ARG_UINT(&flag));
567572
}
568573
ci->allow_keyset = (char)((flag & BIT_UPDATABLECURSORS) != 0);
569574
ci->lf_conversion = (char)((flag & BIT_LFCONVERSION) != 0);
@@ -756,15 +761,17 @@ copyConnAttributes(ConnInfo *ci, const char *attribute, const char *value)
756761
else if (stricmp(attribute, INI_EXTRAOPTIONS) == 0)
757762
{
758763
UInt4 val1 = 0, val2 = 0;
764+
int status = 0;
759765

760766
if ('+' == value[0])
761767
{
762-
sscanf(value + 1, "%x-%x", &val1, &val2);
768+
secure_sscanf(value + 1, &status, "%x-%x",
769+
ARG_UINT(&val1), ARG_UINT(&val2));
763770
add_removeExtraOptions(ci, val1, val2);
764771
}
765772
else if ('-' == value[0])
766773
{
767-
sscanf(value + 1, "%x", &val2);
774+
secure_sscanf(value + 1, &status, "%x", ARG_UINT(&val2));
768775
add_removeExtraOptions(ci, 0, val2);
769776
}
770777
else
@@ -1112,8 +1119,9 @@ MYLOG(0, "drivername=%s\n", drivername);
11121119
temp, sizeof(temp), ODBC_INI) > 0)
11131120
{
11141121
UInt4 val = 0;
1122+
int status = 0;
11151123

1116-
sscanf(temp, "%x", &val);
1124+
secure_sscanf(temp, &status, "%x", ARG_UINT(&val));
11171125
replaceExtraOptions(ci, val, TRUE);
11181126
MYLOG(0, "force_abbrev=%d bde=%d cvt_null_date=%d\n", ci->force_abbrev_connstr, ci->bde_environment, ci->cvt_null_date_string);
11191127
}

execute.c

+6-3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
#include "lobj.h"
3434
#include "pgapifunc.h"
3535

36+
#include "secure_sscanf.h"
37+
3638
/**
3739
* @brief Perform a Prepare on the SQL statement
3840
*
@@ -643,11 +645,12 @@ MYLOG(0, "count_of_deffered=%d has_notice=%d\n", count_of_deferred, stmt->has_no
643645
NULL != env &&
644646
EN_is_odbc3(env))
645647
{
646-
int count;
648+
int count;
649+
int status = 0;
647650

648-
if (sscanf(cmd , "UPDATE %d", &count) == 1)
651+
if (secure_sscanf(cmd, &status, "UPDATE %d", ARG_INT(&count)) == 1)
649652
;
650-
else if (sscanf(cmd , "DELETE %d", &count) == 1)
653+
else if (secure_sscanf(cmd, &status, "DELETE %d", ARG_INT(&count)) == 1)
651654
;
652655
else
653656
count = -1;

info.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
#include "multibyte.h"
4242
#include "catfunc.h"
4343

44+
#include "secure_sscanf.h"
45+
4446
/* Trigger related stuff for SQLForeign Keys */
4547
#define TRIGGER_SHIFT 3
4648
#define TRIGGER_MASK 0x03
@@ -5367,7 +5369,8 @@ MYLOG(0, "atttypid=%s\n", atttypid ? atttypid : "(null)");
53675369
params = NULL;
53685370
else
53695371
{
5370-
sscanf(params, "%u", &pgtype);
5372+
int status = 0;
5373+
secure_sscanf(params, &status, "%u", ARG_UINT(&pgtype));
53715374
while (isdigit((unsigned char) *params))
53725375
params++;
53735376
}

0 commit comments

Comments
 (0)