File gv-3.6.3-security.patch of Package gv

--- src/Makefile.am
+++ src/Makefile.am	2008-03-27 14:10:24.644359171 +0100
@@ -123,6 +123,7 @@ gv_SOURCES = Aaa.c \
              save.h \
              scale.c \
              scale.h \
+             secscanf.c \
              gv_signal.c \
              gv_signal.h \
              version.c \
--- src/Makefile.in
+++ src/Makefile.in	2008-03-27 14:18:31.898867989 +0100
@@ -79,13 +79,13 @@ am__gv_SOURCES_DIST = Aaa.c Aaa_bison.c 
 	options_gs.c options_gs.h options_gv.c options_gv.h \
 	options_setup.c options_setup.h paths.h process.c process.h \
 	popup.c popup.h ps.c ps.h resource.c resource.h save.c save.h \
-	scale.c scale.h gv_signal.c gv_signal.h version.c version.h \
-	versionp.h widgets_misc.c widgets_misc.h zoom.c zoom.h stdc.h \
-	Aaa_intern.h Aaa.h AaaP.h d_memdebug.h d_aaa_xtmem.h \
-	d_fs_xtmem.h d_gv_mem.h d_gv_xtmem.h d_proc_xtmem.h d_ps_mem.h \
-	d_ps_xtmem.h gv_message.h types.h Scrollbar.c Scrollbar.h \
-	ScrollbarP.h setenv.c setenv.h getenv.c d_mem.c d_mem.h \
-	d_xtmem.c d_xtmem.h
+	scale.c scale.h secscanf.c gv_signal.c gv_signal.h version.c \
+	version.h versionp.h widgets_misc.c widgets_misc.h zoom.c \
+	zoom.h stdc.h Aaa_intern.h Aaa.h AaaP.h d_memdebug.h \
+	d_aaa_xtmem.h d_fs_xtmem.h d_gv_mem.h d_gv_xtmem.h \
+	d_proc_xtmem.h d_ps_mem.h d_ps_xtmem.h gv_message.h types.h \
+	Scrollbar.c Scrollbar.h ScrollbarP.h setenv.c setenv.h \
+	getenv.c d_mem.c d_mem.h d_xtmem.c d_xtmem.h
 @USE_SCROLLBAR_CODE_TRUE@am__objects_1 = Scrollbar.$(OBJEXT)
 @USE_SETENV_CODE_TRUE@am__objects_2 = setenv.$(OBJEXT) \
 @USE_SETENV_CODE_TRUE@	getenv.$(OBJEXT)
@@ -103,9 +103,9 @@ am_gv_OBJECTS = Aaa.$(OBJEXT) Aaa_bison.
 	options_fs.$(OBJEXT) options_gs.$(OBJEXT) options_gv.$(OBJEXT) \
 	options_setup.$(OBJEXT) process.$(OBJEXT) popup.$(OBJEXT) \
 	ps.$(OBJEXT) resource.$(OBJEXT) save.$(OBJEXT) scale.$(OBJEXT) \
-	gv_signal.$(OBJEXT) version.$(OBJEXT) widgets_misc.$(OBJEXT) \
-	zoom.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
-	$(am__objects_3)
+	secscanf.$(OBJEXT) gv_signal.$(OBJEXT) version.$(OBJEXT) \
+	widgets_misc.$(OBJEXT) zoom.$(OBJEXT) $(am__objects_1) \
+	$(am__objects_2) $(am__objects_3)
 gv_OBJECTS = $(am_gv_OBJECTS)
 gv_LDADD = $(LDADD)
 gv_DEPENDENCIES = $(top_srcdir)/lib/libgnu.a
@@ -261,8 +261,8 @@ sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 sysconfdir = @sysconfdir@
 target_alias = @target_alias@
-dist_pkglib_DATA = gv_system.ad gv_user.ad gv_class.ad gv_spartan.dat gv_user_res.dat gv_copyright.dat gv_widgetless.dat
-appdefaultsdir = /etc/X11/app-defaults
+dist_pkglib_DATA = gv_system.ad gv_user.ad gv_class.ad gv_spartan.dat gv_user_res.dat gv_copyright.dat
+appdefaultsdir = $(pkglibdir)
 appdefaults_DATA = GV
 EXTRA_DIST = ad2c gv_font_res.dat gv_layout_res.dat gv_misc_res.dat Aaa_bison.yacc \
            gv_current.xbm gv_doc.xbm gv_empty.xbm gv_even.xbm gv_icon.xbm gv_odd.xbm \
@@ -303,9 +303,9 @@ gv_SOURCES = Aaa.c Aaa_bison.c Aaa_bison
 	options_gs.c options_gs.h options_gv.c options_gv.h \
 	options_setup.c options_setup.h paths.h process.c process.h \
 	popup.c popup.h ps.c ps.h resource.c resource.h save.c save.h \
-	scale.c scale.h gv_signal.c gv_signal.h version.c version.h \
-	versionp.h widgets_misc.c widgets_misc.h zoom.c zoom.h \
-	message.h stdc.h Aaa_intern.h Aaa.h AaaP.h d_memdebug.h \
+	scale.c scale.h secscanf.c gv_signal.c gv_signal.h version.c \
+	version.h versionp.h widgets_misc.c widgets_misc.h zoom.c \
+	zoom.h message.h stdc.h Aaa_intern.h Aaa.h AaaP.h d_memdebug.h \
 	d_aaa_xtmem.h d_fs_xtmem.h d_gv_mem.h d_gv_xtmem.h \
 	d_proc_xtmem.h d_ps_mem.h d_ps_xtmem.h gv_message.h types.h \
 	$(am__append_1) $(am__append_2) $(am__append_3)
@@ -436,6 +436,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resource.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/save.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scale.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/secscanf.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/setenv.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/widgets_misc.Po@am__quote@
@@ -746,7 +747,7 @@ $(srcdir)/gv_make_res.dat :
 	@echo "GV.useBackingPixmap:	$(USE_BACKING_PIXMAP)"		>> $(srcdir)/gv_make_res.dat
 	@echo "GV*dirs:		Home\n\\"				>> $(srcdir)/gv_make_res.dat
 	@echo "			Tmp\n\\"				>> $(srcdir)/gv_make_res.dat
-	@echo "			/usr/share/doc\n\\"			>> $(srcdir)/gv_make_res.dat
+	@echo "			/usr/doc\n\\"				>> $(srcdir)/gv_make_res.dat
 	@echo "			/usr/local/doc"				>> $(srcdir)/gv_make_res.dat
 	@echo "GV*filter:		no .*"				>> $(srcdir)/gv_make_res.dat
 	@echo "GV*filters:		None\n\\"			>> $(srcdir)/gv_make_res.dat
--- src/ps.c
+++ src/ps.c	2008-03-27 14:20:04.186703895 +0100
@@ -93,6 +93,10 @@ extern Media *gv_medias;
 #define memset(a,b,c) bzero(a,c)
 #endif
 
+extern int sec_sscanf(const char *, const char *, ...);
+
+
+
 /* We use this helper function for providing proper */
 /* case and colon :-) insensitive DSC matching */
 static int dsc_strncmp(s1, s2, n)
@@ -464,7 +468,7 @@ unc_ok:
       doc = (struct document *) PS_malloc(sizeof(struct document));
       CHECK_MALLOCED(doc);
       memset(doc, 0, sizeof(struct document));
-      sscanf(line, "%*s %256s", text);
+      sec_sscanf(line, "%*s %256s", text);
       /*###jp###*/
       /*doc->epsf = iscomment(text, "EPSF-");*/
       doc->epsf = iscomment(text, "EPSF");
@@ -560,11 +564,11 @@ scan_ok:
 	} else if (doc->date == NULL && iscomment(line+2, "CreationDate:")) {
 	    doc->date = gettextline(line+length("%%CreationDate:"));
 	} else if (bb_set == NONE && iscomment(line+2, "BoundingBox:")) {
-	    sscanf(line+length("%%BoundingBox:"), "%256s", text);
+	    sec_sscanf(line+length("%%BoundingBox:"), "%256s", text);
 	    if (strcmp(text, "(atend)") == 0) {
 		bb_set = ATEND;
 	    } else {
-		if (sscanf(line+length("%%BoundingBox:"), "%d %d %d %d",
+		if (sec_sscanf(line+length("%%BoundingBox:"), "%d %d %d %d",
 			   &(doc->boundingbox[LLX]),
 			   &(doc->boundingbox[LLY]),
 			   &(doc->boundingbox[URX]),
@@ -572,7 +576,7 @@ scan_ok:
 		    bb_set = 1;
 		else {
 		    float fllx, flly, furx, fury;
-		    if (sscanf(line+length("%%BoundingBox:"), "%f %f %f %f",
+		    if (sec_sscanf(line+length("%%BoundingBox:"), "%f %f %f %f",
 			       &fllx, &flly, &furx, &fury) == 4) {
 			bb_set = 1;
 			doc->boundingbox[LLX] = fllx;
@@ -592,7 +596,7 @@ scan_ok:
 	    }
 	} else if (orientation_set == NONE &&
 		   iscomment(line+2, "Orientation:")) {
-	    sscanf(line+length("%%Orientation:"), "%256s", text);
+	    sec_sscanf(line+length("%%Orientation:"), "%256s", text);
 	    if (strcmp(text, "(atend)") == 0) {
 		orientation_set = ATEND;
 	    } else if (strcmp(text, "Portrait") == 0) {
@@ -603,7 +607,7 @@ scan_ok:
 		orientation_set = 1;
 	    }
 	} else if (page_order_set == NONE && iscomment(line+2, "PageOrder:")) {
-	    sscanf(line+length("%%PageOrder:"), "%256s", text);
+	    sec_sscanf(line+length("%%PageOrder:"), "%256s", text);
 	    if (strcmp(text, "(atend)") == 0) {
 		page_order_set = ATEND;
 	    } else if (strcmp(text, "Ascend") == 0) {
@@ -617,11 +621,11 @@ scan_ok:
 		page_order_set = 1;
 	    }
 	} else if (pages_set == NONE && iscomment(line+2, "Pages:")) {
-	    sscanf(line+length("%%Pages:"), "%256s", text);
+	    sec_sscanf(line+length("%%Pages:"), "%256s", text);
 	    if (strcmp(text, "(atend)") == 0) {
 		pages_set = ATEND;
 	    } else {
-		switch (sscanf(line+length("%%Pages:"), "%d %d",
+		switch (sec_sscanf(line+length("%%Pages:"), "%d %d",
 			       &maxpages, &i)) {
 		    case 2:
 			if (page_order_set == NONE) {
@@ -653,7 +657,7 @@ scan_ok:
 	    doc->media[0].name = ps_gettext(line+length("%%DocumentMedia:"),
 					    &next_char);
 	    if (doc->media[0].name != NULL) {
-		if (sscanf(next_char, "%f %f", &w, &h) == 2) {
+		if (sec_sscanf(next_char, "%f %f", &w, &h) == 2) {
 		    doc->media[0].width = w + 0.5;
 		    doc->media[0].height = h + 0.5;
 		}
@@ -674,7 +678,7 @@ scan_ok:
 		doc->media[doc->nummedia].name = ps_gettext(line+length("%%+"),
 							    &next_char);
 		if (doc->media[doc->nummedia].name != NULL) {
-		    if (sscanf(next_char, "%f %f", &w, &h) == 2) {
+		    if (sec_sscanf(next_char, "%f %f", &w, &h) == 2) {
 			doc->media[doc->nummedia].width = w + 0.5;
 			doc->media[doc->nummedia].height = h + 0.5;
 		    }
@@ -837,7 +841,7 @@ scan_ok:
 		/* Do nothing */
 	    } else if (doc->default_page_orientation == NONE &&
 		iscomment(line+2, "PageOrientation:")) {
-		sscanf(line+length("%%PageOrientation:"), "%256s", text);
+		sec_sscanf(line+length("%%PageOrientation:"), "%256s", text);
 		if (strcmp(text, "Portrait") == 0) {
 		    doc->default_page_orientation = PORTRAIT;
 		} else if (strcmp(text, "Landscape") == 0) {
@@ -856,7 +860,7 @@ scan_ok:
 		PS_free(cp);
 	    } else if (page_bb_set == NONE &&
 		       iscomment(line+2, "PageBoundingBox:")) {
-		if (sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
+		if (sec_sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
 			   &(doc->default_page_boundingbox[LLX]),
 			   &(doc->default_page_boundingbox[LLY]),
 			   &(doc->default_page_boundingbox[URX]),
@@ -864,7 +868,7 @@ scan_ok:
 		    page_bb_set = 1;
 		else {
 		    float fllx, flly, furx, fury;
-		    if (sscanf(line+length("%%PageBoundingBox:"), "%f %f %f %f",
+		    if (sec_sscanf(line+length("%%PageBoundingBox:"), "%f %f %f %f",
 			       &fllx, &flly, &furx, &fury) == 4) {
 			page_bb_set = 1;
 			doc->default_page_boundingbox[LLX] = fllx;
@@ -959,7 +963,7 @@ scan_ok:
 		/* Do nothing */
 	    } else if (doc->default_page_orientation == NONE &&
 		iscomment(line+2, "PageOrientation:")) {
-		sscanf(line+length("%%PageOrientation:"), "%256s", text);
+		sec_sscanf(line+length("%%PageOrientation:"), "%256s", text);
 		if (strcmp(text, "Portrait") == 0) {
 		    doc->default_page_orientation = PORTRAIT;
 		} else if (strcmp(text, "Landscape") == 0) {
@@ -982,7 +986,7 @@ scan_ok:
 		PS_free(cp);
 	    } else if (page_bb_set == NONE &&
 		       iscomment(line+2, "PageBoundingBox:")) {
-		if (sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
+		if (sec_sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
 			   &(doc->default_page_boundingbox[LLX]),
 			   &(doc->default_page_boundingbox[LLY]),
 			   &(doc->default_page_boundingbox[URX]),
@@ -990,7 +994,7 @@ scan_ok:
 		    page_bb_set = 1;
 		else {
 		    float fllx, flly, furx, fury;
-		    if (sscanf(line+length("%%PageBoundingBox:"), "%f %f %f %f",
+		    if (sec_sscanf(line+length("%%PageBoundingBox:"), "%f %f %f %f",
 			       &fllx, &flly, &furx, &fury) == 4) {
 			page_bb_set = 1;
 			doc->default_page_boundingbox[LLX] = fllx;
@@ -1058,7 +1062,7 @@ newpage:
             CHECK_MALLOCED(doc->pages);
 	}
 	label = ps_gettext(line+length("%%Page:"), &next_char);
-	if (sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
+	if (sec_sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
 	if (nextpage == 1) {
 	    ignore = thispage != 1;
 	}
@@ -1096,7 +1100,7 @@ continuepage:
 		/* Do nothing */
 	    } else if (doc->pages[doc->numpages].orientation == NONE &&
 		iscomment(line+2, "PageOrientation:")) {
-		sscanf(line+length("%%PageOrientation:"), "%256s", text);
+		sec_sscanf(line+length("%%PageOrientation:"), "%256s", text);
 		if (strcmp(text, "Portrait") == 0) {
 		    doc->pages[doc->numpages].orientation = PORTRAIT;
 		} else if (strcmp(text, "Landscape") == 0) {
@@ -1128,11 +1132,11 @@ continuepage:
 		PS_free(cp);
 	    } else if ((page_bb_set == NONE || page_bb_set == ATEND) &&
 		       iscomment(line+2, "PageBoundingBox:")) {
-		sscanf(line+length("%%PageBoundingBox:"), "%256s", text);
+		sec_sscanf(line+length("%%PageBoundingBox:"), "%256s", text);
 		if (strcmp(text, "(atend)") == 0) {
 		    page_bb_set = ATEND;
 		} else {
-		    if (sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
+		    if (sec_sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
 			    &(doc->pages[doc->numpages].boundingbox[LLX]),
 			    &(doc->pages[doc->numpages].boundingbox[LLY]),
 			    &(doc->pages[doc->numpages].boundingbox[URX]),
@@ -1142,7 +1146,7 @@ continuepage:
 		      }
 		    else {
 			float fllx, flly, furx, fury;
-			if (sscanf(line+length("%%PageBoundingBox:"),
+			if (sec_sscanf(line+length("%%PageBoundingBox:"),
 				   "%f %f %f %f",
 				   &fllx, &flly, &furx, &fury) == 4) {
 			    if (page_bb_set == NONE) page_bb_set = 1;
@@ -1193,7 +1197,7 @@ continuepage:
 	    /* Do nothing */
 	} else if (iscomment(line+2, "Page:")) {
 	    PS_free(ps_gettext(line+length("%%Page:"), &next_char));
-	    if (sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
+	    if (sec_sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
 	    if (!ignore && thispage == nextpage) {
 		if (doc->numpages > 0) {
 		    doc->pages[doc->numpages-1].end = position;
@@ -1220,13 +1224,13 @@ continuepage:
 	    doc->begintrailer = position;
 	    section_len = line_len;
 	} else if (bb_set == ATEND && iscomment(line+2, "BoundingBox:")) {
-	    if (sscanf(line+length("%%BoundingBox:"), "%d %d %d %d",
+	    if (sec_sscanf(line+length("%%BoundingBox:"), "%d %d %d %d",
 		       &(doc->boundingbox[LLX]),
 		       &(doc->boundingbox[LLY]),
 		       &(doc->boundingbox[URX]),
 		       &(doc->boundingbox[URY])) != 4) {
 		float fllx, flly, furx, fury;
-		if (sscanf(line+length("%%BoundingBox:"), "%f %f %f %f",
+		if (sec_sscanf(line+length("%%BoundingBox:"), "%f %f %f %f",
 			   &fllx, &flly, &furx, &fury) == 4) {
 		    doc->boundingbox[LLX] = fllx;
 		    doc->boundingbox[LLY] = flly;
@@ -1244,14 +1248,14 @@ continuepage:
 	    }
 	} else if (orientation_set == ATEND &&
 		   iscomment(line+2, "Orientation:")) {
-	    sscanf(line+length("%%Orientation:"), "%256s", text);
+	    sec_sscanf(line+length("%%Orientation:"), "%256s", text);
 	    if (strcmp(text, "Portrait") == 0) {
 		doc->orientation = PORTRAIT;
 	    } else if (strcmp(text, "Landscape") == 0) {
 		doc->orientation = LANDSCAPE;
 	    }
 	} else if (page_order_set == ATEND && iscomment(line+2, "PageOrder:")) {
-	    sscanf(line+length("%%PageOrder:"), "%256s", text);
+	    sec_sscanf(line+length("%%PageOrder:"), "%256s", text);
 	    if (strcmp(text, "Ascend") == 0) {
 		doc->pageorder = ASCEND;
 	    } else if (strcmp(text, "Descend") == 0) {
@@ -1260,7 +1264,7 @@ continuepage:
 		doc->pageorder = SPECIAL;
 	    }
 	} else if (pages_set == ATEND && iscomment(line+2, "Pages:")) {
-	    if (sscanf(line+length("%%Pages:"), "%*u %d", &i) == 1) {
+	    if (sec_sscanf(line+length("%%Pages:"), "%*u %d", &i) == 1) {
 		if (page_order_set == NONE) {
 		    if (i == -1) doc->pageorder = DESCEND;
 		    else if (i == 0) doc->pageorder = SPECIAL;
@@ -1286,7 +1290,7 @@ continuepage:
 	preread = 0;
 	if (DSCcomment(line) && iscomment(line+2, "Page:")) {
 	    PS_free(ps_gettext(line+length("%%Page:"), &next_char));
-	    if (sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
+	    if (sec_sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
 	    if (!ignore && thispage == nextpage) {
 		if (doc->numpages > 0) {
 		    doc->pages[doc->numpages-1].end = position;
@@ -1825,7 +1829,7 @@ static char * readline (fd, lineP, posit
       INFMESSAGE(encountered "BeginData:")
       if (FD_LINE_LEN > 100) FD_BUF[100] = '\0';
       text[0] = '\0';
-      if (sscanf(line+length("%%BeginData:"), "%d %*s %100s", &num, text) >= 1) {
+      if (sec_sscanf(line+length("%%BeginData:"), "%d %*s %100s", &num, text) >= 1) {
          if (strcmp(text, "Lines") == 0) {
             INFIMESSAGE(number of lines to skip:,num)
             while (num) {
@@ -1849,7 +1853,7 @@ static char * readline (fd, lineP, posit
    else if IS_BEGIN("Binary:") {
       int  num;
       INFMESSAGE(encountered "BeginBinary:")
-      if (sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
+      if (sec_sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
          int read_chunk_size = LINE_CHUNK_SIZE;
          INFIMESSAGE(number of chars to skip:,num)
          while (num>0) {
@@ -1924,7 +1928,7 @@ pscopyuntil(fd, to, begin, end, comment)
          INFMESSAGE(encountered "BeginData:")
          if (FD_LINE_LEN > 100) FD_BUF[100] = '\0';
          text[0] = '\0';
-         if (sscanf(line+length("%%BeginData:"), "%d %*s %100s", &num, text) >= 1) {
+         if (sec_sscanf(line+length("%%BeginData:"), "%d %*s %100s", &num, text) >= 1) {
             if (strcmp(text, "Lines") == 0) {
                INFIMESSAGE(number of lines:,num)
                while (num) {
@@ -1947,7 +1951,7 @@ pscopyuntil(fd, to, begin, end, comment)
       else if IS_BEGIN("Binary:") {
          int  num;
          INFMESSAGE(encountered "BeginBinary:")
-         if (sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
+         if (sec_sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
             int read_chunk_size = LINE_CHUNK_SIZE;
             INFIMESSAGE(number of chars:,num)
             while (num>0) {
@@ -2021,12 +2025,12 @@ pscopydoc(dest_file,src_filename,d,pagel
           PS_free(comment);
           continue;
        }
-       sscanf(comment+length("%%Pages:"), "%256s", text);
+       sec_sscanf(comment+length("%%Pages:"), "%256s", text);
        if (strcmp(text, "(atend)") == 0) {
           fputs(comment, dest_file);
           pages_atend = True;
        } else {
-          switch (sscanf(comment+length("%%Pages:"), "%*d %d", &i)) {
+          switch (sec_sscanf(comment+length("%%Pages:"), "%*d %d", &i)) {
              case 1:
                 fprintf(dest_file, "%%%%Pages: %d %d\n", pages, i);
                 break;
@@ -2061,7 +2065,7 @@ pscopydoc(dest_file,src_filename,d,pagel
          PS_free(comment);
          continue;
       }
-      switch (sscanf(comment+length("%%Pages:"), "%*d %d", &i)) {
+      switch (sec_sscanf(comment+length("%%Pages:"), "%*d %d", &i)) {
          case 1:
             fprintf(dest_file, "%%%%Pages: %d %d\n", pages, i);
             break;
--- src/secscanf.c
+++ src/secscanf.c	2002-09-20 13:54:53.000000000 +0200
@@ -0,0 +1,540 @@
+/*
+ * Secure sscanf - sscanf with an additional size argument for string
+ * arguments. All format specifiers should work as in the standard
+ * scanf - except for those writing to a string buffer provided by the
+ * caller. These specifiers take an additional argument of type size_t
+ * that specifies the size of the buffer.
+ *
+ * Copyright (C) 2002, Olaf Kirch <okir@suse.de>
+ */
+
+#define _GNU_SOURCE
+
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+
+enum {
+	CONV_ANY,
+	CONV_STR,
+	CONV_NUM,
+	CONV_INTEGER,
+	CONV_FLOAT,
+	CONV_POINTER,
+};
+
+enum {
+	SIZE_ANY,
+	SIZE_SHORT,
+	SIZE_LONG,
+	SIZE_QUAD,
+};
+
+union scan_value {
+	const char *		v_string;
+	long long		v_signed;
+	unsigned long long	v_integer;
+	long double		v_double;
+	void *			v_pointer;
+};
+
+
+static int	process_number(union scan_value *vp, const char **sp, char fmt);
+static int	process_char_class(const char **, const char **, int);
+
+static inline int
+set_conv_type(int *type, int new_type)
+{
+	switch (*type) {
+	case CONV_ANY:
+		break;
+	case CONV_NUM:
+		if (new_type == CONV_INTEGER
+		 || new_type == CONV_FLOAT
+		 || new_type == CONV_POINTER)
+		 	break;
+		/* fallthru */
+	default:
+		if (*type != new_type)
+			return 0;
+		break;
+	}
+
+	*type = new_type;
+	return 1;
+}
+
+int
+sec_sscanf(const char *s, const char *fmt, ...)
+{
+	const char	*begin = s;
+	int		num_fields = 0, fmt_empty = 1;
+	va_list		ap;
+
+	va_start(ap, fmt);
+	while (*fmt) {
+		union scan_value value;
+		const char	*pre_space_skip,
+				*value_begin;
+		int		assign = 1, allocate = 0,
+				conv_type = CONV_ANY,
+				conv_size = SIZE_ANY,
+				field_width = -1,
+				nul_terminated = 1;
+		char		c;
+
+		c = *fmt++;
+		if (isspace(c)) {
+			while (isspace(*s))
+				s++;
+			continue;
+		}
+
+		fmt_empty = 0;
+		if (c != '%') {
+			if (c != *s)
+				goto stop;
+			s++;
+			continue;
+		}
+
+		/* Each % directive implicitly skips white space
+		 * except for the %c case */
+		pre_space_skip = s;
+		while (isspace(*s))
+			s++;
+
+		while (1) {
+			int	type = CONV_ANY, size = SIZE_ANY;
+
+			switch (*fmt) {
+			case '*':
+				assign = 0;
+				break;
+			case 'a':
+				type = CONV_STR;
+				allocate = 1;
+				break;
+			case 'h':
+				type = CONV_INTEGER;
+				size = SIZE_SHORT;
+				break;
+			case 'l':
+				type = CONV_NUM;
+				size = SIZE_LONG;
+				break;
+			case 'L':
+			case 'q':
+				type = CONV_NUM;
+				size = SIZE_QUAD;
+				break;
+			case '0': case '1': case '2': case '3': case '4':
+			case '5': case '6': case '7': case '8': case '9':
+				field_width = strtol(fmt, (char **) &fmt, 10);
+				fmt--;
+				break;
+			default:
+				goto flags_done;
+			}
+
+			if (!set_conv_type(&conv_type, type))
+				goto stop;
+
+			if (size != SIZE_ANY) {
+				if (size == SIZE_LONG && conv_size == SIZE_LONG)
+					conv_size = SIZE_QUAD;
+				else
+					conv_size = size;
+			}
+
+			fmt++;
+		}
+
+	flags_done:
+		value_begin = s;
+
+		switch (*fmt++) {
+		case '%':
+			if (*s == '\0')
+				goto eof;
+			if (*s != '%')
+				goto stop;
+			continue;
+		case '[':
+			value.v_string = s;
+			if (!set_conv_type(&conv_type, CONV_STR)
+			 || !process_char_class(&fmt, &s, field_width))
+				goto stop;
+			break;
+		case 's':
+			value.v_string = s;
+			if (!set_conv_type(&conv_type, CONV_STR))
+				goto stop;
+			while (*s && !isspace(*s) && field_width-- != 0)
+				s++;
+			break;
+		case 'c':
+			if (!set_conv_type(&conv_type, CONV_STR))
+				goto stop;
+			value.v_string = s = value_begin = pre_space_skip;
+
+			if (field_width < 0)
+				s++;
+			else while (*s && field_width--)
+				s++;
+			nul_terminated = 0;
+			break;
+		case 'd':
+		case 'i':
+		case 'o':
+		case 'u':
+		case 'x':
+		case 'X':
+			if (!set_conv_type(&conv_type, CONV_INTEGER)
+			 || !process_number(&value, &s, fmt[-1]))
+				goto stop;
+			break;
+		case 'p':
+			if (!set_conv_type(&conv_type, CONV_POINTER)
+			 || !process_number(&value, &s, fmt[-1]))
+				goto stop;
+			break;
+		case 'f':
+		case 'g':
+		case 'e':
+		case 'E':
+			if (!set_conv_type(&conv_type, CONV_FLOAT)
+			 || !process_number(&value, &s, fmt[-1]))
+				goto stop;
+			break;
+		case 'n':
+			if (!set_conv_type(&conv_type, CONV_INTEGER))
+				goto stop;
+			value.v_signed = (s - begin);
+			break;
+		default:
+			goto stop;
+		}
+
+		/* We've consumed what we need to consume. Now copy */
+		if (!assign)
+			continue;
+
+		/* Make sure we've consumed at least *something* */
+		if (s == value_begin)
+			goto eof;
+
+		/* Deal with a conversion flag */
+		if (conv_type == CONV_STR && allocate) {
+			value.v_pointer = strndup(value.v_string, s - value.v_string);
+			conv_type = CONV_POINTER;
+			allocate = 0;
+		}
+
+		switch (conv_type) {
+		case CONV_STR:
+			{
+				const char *string = value.v_string;
+				char	*buf;
+				size_t	size;
+
+				if (string == NULL)
+					goto stop;
+				buf = va_arg(ap, char *);
+				size = va_arg(ap, size_t) - nul_terminated;
+				if (size > s - string)
+					size = s - string;
+				strncpy(buf, string, size);
+				if (nul_terminated)
+					buf[size] = '\0';
+			}
+			break;
+
+		case CONV_POINTER:
+			{
+				void	**ptr;
+
+				ptr = va_arg(ap, void **);
+				*ptr = value.v_pointer;
+			}
+			break;
+		case CONV_INTEGER:
+			{
+				void	*ptr;
+
+				ptr = va_arg(ap, void *);
+				switch (conv_size) {
+				case SIZE_SHORT:
+					*(short *) ptr = value.v_integer;
+					break;
+				case SIZE_ANY:
+					*(int *) ptr = value.v_integer;
+					break;
+				case SIZE_LONG:
+					*(long *) ptr = value.v_integer;
+					break;
+				case SIZE_QUAD:
+					*(long long *) ptr = value.v_integer;
+					break;
+				default:
+					goto stop;
+				}
+			}
+			break;
+		case CONV_FLOAT:
+			{
+				void	*ptr;
+
+				ptr = va_arg(ap, void *);
+				switch (conv_size) {
+				case SIZE_ANY:
+					*(float *) ptr = value.v_double;
+					break;
+				case SIZE_LONG:
+					*(double *) ptr = value.v_double;
+					break;
+				case SIZE_QUAD:
+					*(long double *) ptr = value.v_double;
+					break;
+				default:
+					goto stop;
+				}
+			}
+			break;
+		default:
+			goto stop;
+		}
+
+		num_fields++;
+	}
+
+stop:	return num_fields;
+
+eof:	if (num_fields)
+		return num_fields;
+	return EOF;
+}
+
+static int
+process_number(union scan_value *vp, const char **sp, char fmt)
+{
+	const char	*s = *sp;
+
+	switch (fmt) {
+	case 'd':
+		vp->v_signed = strtoll(s, (char **) sp, 10);
+		break;
+	case 'i':
+		vp->v_signed = strtoll(s, (char **) sp, 0);
+		break;
+	case 'o':
+		vp->v_integer = strtoull(s, (char **) sp, 8);
+		break;
+	case 'u':
+		vp->v_integer = strtoull(s, (char **) sp, 10);
+		break;
+	case 'x':
+	case 'X':
+		vp->v_integer = strtoull(s, (char **) sp, 16);
+		break;
+	case 'p':
+		vp->v_pointer = (void *) strtoull(s, (char **) sp, 0);
+		break;
+	case 'f':
+	case 'g':
+	case 'e':
+	case 'E':
+		vp->v_double = strtold(s, (char **) sp);
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+static int
+process_char_class(const char **fmt, const char **sp, int width)
+{
+	unsigned char	*s, c, prev_char = 0;
+	unsigned char	table[255];
+	int		val = 1;
+
+	s = (unsigned char *) *fmt;
+	if (*s == '^') {
+		memset(table, 1, sizeof(table));
+		val = 0;
+		s++;
+	} else {
+		memset(table, 0, sizeof(table));
+		val = 1;
+	}
+	/* First character in set is closing bracket means add it to the
+	 * set of characters */
+	if ((c = *s) == ']') {
+		table[c] = val;
+		prev_char = c;
+		s++;
+	}
+
+	/* Any other closing bracket finishes off the set */
+	while ((c = *s++) != ']') {
+		if (prev_char) {
+			if (c == '-' && *s != '\0' && *s != ']') {
+				c = *s++;
+			} else {
+				//table[prev_char] = val;
+				prev_char = '\0';
+			}
+		}
+
+		if (c == '\0')
+			return 0;
+
+		if (prev_char) {
+			while (prev_char < c)
+				table[prev_char++] = val;
+		}
+		table[c] = val;
+		prev_char = c;
+	}
+	*fmt = (char *) s;
+
+#if 0
+	{
+		int	n;
+
+		printf("char class=");
+		for (n = 0; n < 255; n++)
+			if (table[n])
+				printf(isprint(n)? "%c" : "\\%03o", n);
+		printf("\n");
+	}
+#endif
+
+	s = (unsigned char *) *sp;
+	while ((c = *s) != '\0' && table[c] && width--)
+		s++;
+
+	*sp = (char *) s;
+	return 1;
+}
+
+#ifdef TEST
+static int	verify(const char *fmt, const char *s);
+static int	verify_s(const char *fmt, const char *s);
+
+enum { S, I, L, F, D, P };
+
+int
+main(int argc, char **argv)
+{
+	verify("%d %d", "12 13");
+	verify("%d-%d", "12 13");
+	verify("%d-%d", "12-13");
+	verify("%u %u", "12 13");
+	verify("%o %o", "12 13");
+	verify("%x %x", "12 13");
+	verify("%X %X", "12 13");
+	verify("%hd %hd", "12 13");
+	verify("%ld %ld", "12 13");
+	verify("%lld %lld", "12 13");
+	verify("%Ld %Ld", "12 13");
+	verify("%qd %qd", "12 13");
+	verify("%f %f", "12 13");
+	verify("%lf %lf", "12 13");
+	verify("%Lf %Lf", "12 13");
+	verify("%qf %qf", "12 13");
+	verify("%*d-%d", "12-13");
+	verify("%*s %d", "12 13");
+	verify("%p", "0xdeadbeef");
+	verify("%*[a-e] %x", "deadbeef feeb");
+	verify("%*[a-f] %x", "deadbeef feeb");
+	verify("%*[^g-z] %x", "deadbeef feeb");
+	verify("%*[^ g-z] %x", "deadbeef feeb");
+	verify("%*[^ g-z-] %x", "dead-beef feeb");
+	verify("%*5s %d", "toast123 456");
+	verify("", "lalla");
+	verify("%u", "");
+
+	verify_s("%s", "aa bb");
+	verify_s("%s %s", "aa bb");
+	verify_s("%[a-z] %s", "aa bb");
+	verify_s("%c %s", "aa bb");
+	verify_s("%2c %s", " aa bb");
+	verify_s("%20c %s", " aa bb");
+
+	return 0;
+}
+
+static int
+verify(const char *fmt, const char *s)
+{
+	union scan_value vals[5], vals_ref[5], *v;
+	int	n, m;
+
+	memset(vals, 0xe5, sizeof(vals));
+	memset(vals_ref, 0xe5, sizeof(vals_ref));
+
+	v = vals;
+	n = sec_sscanf(s, fmt, v + 0, v + 1, v + 2, v + 3, v + 4);
+
+	v = vals_ref;
+	m = sscanf(s, fmt, v + 0, v + 1, v + 2, v + 3, v + 4);
+
+	if (m != n) {
+		printf("FAILED: fmt=\"%s\"\n"
+		       "        str=\"%s\"\n"
+		       "        sec_scanf returns %d, sscanf returns %d\n",
+		       fmt, s, n, m);
+		return 0;
+	}
+
+	if (memcmp(vals, vals_ref, sizeof(vals))) {
+		printf("FAILED: fmt=\"%s\"\n"
+		       "        str=\"%s\"\n"
+		       "        data differs!\n",
+		       fmt, s);
+		printf("0x%Lx != 0x%Lx\n", vals[0].v_integer, vals_ref[0].v_integer);
+		return 0;
+	}
+
+	return 1;
+}
+
+static int
+verify_s(const char *fmt, const char *s)
+{
+	char	buf[3][256], buf_ref[3][256];
+	int	n, m;
+
+	memset(buf, 0xe5, sizeof(buf));
+	memset(buf_ref, 0xe5, sizeof(buf_ref));
+
+	n = sec_sscanf(s, fmt, buf, sizeof(buf[0]), buf + 1, sizeof(buf[1]), buf + 2, sizeof(buf[2]));
+
+	m = sscanf(s, fmt, buf_ref, buf_ref + 1, buf_ref + 2);
+
+	if (m != n) {
+		printf("FAILED: fmt=\"%s\"\n"
+		       "        str=\"%s\"\n"
+		       "        sec_scanf returns %d, sscanf returns %d\n",
+		       fmt, s, n, m);
+		return 0;
+	}
+
+	if (memcmp(buf, buf_ref, sizeof(buf))) {
+		printf("FAILED: fmt=\"%s\"\n"
+		       "        str=\"%s\"\n"
+		       "        data differs!\n",
+		       fmt, s);
+		printf("%s != %s\n", buf[0], buf_ref[0]);
+		return 0;
+	}
+
+	return 1;
+}
+#endif
openSUSE Build Service is sponsored by