diff -ur cfitsio3430/cfileio.c cfitsio3440/cfileio.c --- cfitsio3430/cfileio.c 2018-03-01 17:28:51.000000000 +0100 +++ cfitsio3440/cfileio.c 2018-04-11 16:33:41.000000000 +0200 @@ -1490,7 +1490,7 @@ char oldbinspec[FLEN_FILENAME], oldcolspec[FLEN_FILENAME]; char cwd[FLEN_FILENAME]; char tmpStr[FLEN_FILENAME]; - char tmpinfile[FLEN_FILENAME]; + char tmpinfile[FLEN_FILENAME]; *isopen = 0; @@ -1508,7 +1508,8 @@ if(fits_strcasecmp(urltype,"FILE://") == 0) { - fits_path2url(infile,tmpinfile,status); + if (fits_path2url(infile,FLEN_FILENAME,tmpinfile,status)) + return (*status); if(tmpinfile[0] != '/') { @@ -1546,7 +1547,8 @@ if(fits_strcasecmp(oldurltype,"FILE://") == 0) { - fits_path2url(oldinfile,tmpStr,status); + if(fits_path2url(oldinfile,FLEN_FILENAME,tmpStr,status)) + return(*status); if(tmpStr[0] != '/') { @@ -1856,7 +1858,7 @@ fitsfile *newptr; int ii, hdunum, slen, colnum = -1, testnum, deletecol = 0, savecol = 0; int numcols = 0, *colindex = 0, tstatus = 0; - char *cptr, *cptr2, *cptr3, *clause = NULL, keyname[FLEN_KEYWORD]; + char *tstbuff=0, *cptr, *cptr2, *cptr3, *clause = NULL, keyname[FLEN_KEYWORD]; char colname[FLEN_VALUE], oldname[FLEN_VALUE], colformat[FLEN_VALUE]; char *file_expr = NULL, testname[FLEN_VALUE], card[FLEN_CARD]; @@ -1962,11 +1964,15 @@ if (clause[0] == '!' || clause[0] == '-') { + char *clause1 = clause+1; /* ===================================== */ /* Case I. delete this column or keyword */ /* ===================================== */ - if (ffgcno(*fptr, CASEINSEN, &clause[1], &colnum, status) <= 0) + /* Check that clause does not have leading '#' and + that column name exists */ + if (clause1[0] && clause1[0] != '#' && + ffgcno(*fptr, CASEINSEN, clause1, &colnum, status) <= 0) { /* a column with this name exists, so try to delete it */ if (ffdcol(*fptr, colnum, status) > 0) @@ -1984,18 +1990,41 @@ } else { + int delall = 0, clen = 0; ffcmsg(); /* clear previous error message from ffgcno */ /* try deleting a keyword with this name */ *status = 0; - if (ffdkey(*fptr, &clause[1], status) > 0) - { - ffpmsg("column or keyword to be deleted does not exist:"); - ffpmsg(clause); - if( colindex ) free( colindex ); - if( file_expr ) free( file_expr ); - if( clause ) free(clause); - return(*status); - } + /* skip past leading '#' if any */ + if (clause1[0] == '#') clause1++; + clen = strlen(clause1); + + /* Repeat deletion of keyword if requested with trailing '+' */ + if (clen > 1 && clause1[clen-1] == '+') { + delall = 1; + clause1[clen-1] = 0; + } + /* Single or repeated deletions until done */ + do { + if (ffdkey(*fptr, clause1, status) > 0) + { + if (delall && *status == KEY_NO_EXIST && + (strchr(clause1,'*') || strchr(clause1,'?')) ) { + /* Found last wildcard item. Stop deleting */ + ffcmsg(); + *status = 0; + delall = 0; /* Force end of this loop */ + } else { + /* This was not a wildcard deletion, or it resulted in + another kind of error */ + ffpmsg("column or keyword to be deleted does not exist:"); + ffpmsg(clause1); + if( colindex ) free( colindex ); + if( file_expr ) free( file_expr ); + if( clause ) free(clause); + return(*status); + } + } + } while(delall); /* end do{} */ } } else @@ -2011,17 +2040,32 @@ calculation expression (case 2B) */ /* ===================================================== */ cptr2 = clause; - slen = fits_get_token(&cptr2, "( =", colname, NULL); + slen = fits_get_token2(&cptr2, "( =", &tstbuff, NULL, status); - if (slen == 0) + if (slen == 0 || *status) { - ffpmsg("error: column or keyword name is blank:"); + ffpmsg("error: column or keyword name is blank (ffedit_columns):"); ffpmsg(clause); if( colindex ) free( colindex ); if( file_expr ) free( file_expr ); if (clause) free(clause); + if (*status==0) + *status=URL_PARSE_ERROR; + return(*status); + } + if (strlen(tstbuff) > FLEN_VALUE-1) + { + ffpmsg("error: column or keyword name is too long (ffedit_columns):"); + ffpmsg(clause); + if( colindex ) free( colindex ); + if( file_expr ) free( file_expr ); + if (clause) free(clause); + free(tstbuff); return(*status= URL_PARSE_ERROR); } + strcpy(colname, tstbuff); + free(tstbuff); + tstbuff=0; /* If this is a keyword of the form #KEYWORD# @@ -2091,9 +2135,22 @@ */ if (*cptr2 == '(') { - fits_get_token(&cptr2, ")", oldname, NULL); - strcat(colname, oldname); + fits_get_token2(&cptr2, ")", &tstbuff, NULL, status); + if (*status || (strlen(tstbuff) + strlen(colname) + 1) > + FLEN_VALUE-1) + { + ffpmsg("error: column name is too long (ffedit_columns):"); + if( file_expr ) free( file_expr ); + if (clause) free(clause); + free(tstbuff); + if (*status==0) + *status=URL_PARSE_ERROR; + return (*status); + } + strcat(colname, tstbuff); strcat(colname, ")"); + free(tstbuff); + tstbuff=0; cptr2++; } @@ -2177,7 +2234,20 @@ while (*cptr2 == ' ') cptr2++; /* skip white space */ - fits_get_token(&cptr2, " ", oldname, NULL); + fits_get_token2(&cptr2, " ", &tstbuff, NULL, status); + if (*status || strlen(tstbuff) > FLEN_VALUE-1) + { + ffpmsg("error: column name syntax is too long (ffedit_columns):"); + if( file_expr ) free( file_expr ); + if (clause) free(clause); + free(tstbuff); + if (*status==0) + *status=URL_PARSE_ERROR; + return (*status); + } + strcpy(oldname, tstbuff); + free(tstbuff); + tstbuff=0; /* get column number of the existing column */ if (ffgcno(*fptr, CASEINSEN, oldname, &colnum, status) <= 0) @@ -2232,12 +2302,40 @@ colformat[0] = '\0'; cptr3 = colname; - fits_get_token(&cptr3, "(", oldname, NULL); + fits_get_token2(&cptr3, "(", &tstbuff, NULL, status); + if (*status || strlen(tstbuff) > FLEN_VALUE-1) + { + ffpmsg("column expression is too long (ffedit_columns)"); + if( colindex ) free( colindex ); + if( file_expr ) free( file_expr ); + if (clause) free(clause); + free(tstbuff); + if (*status==0) + *status=URL_PARSE_ERROR; + return(*status); + } + strcpy(oldname, tstbuff); + free(tstbuff); + tstbuff=0; if (cptr3[0] == '(' ) { cptr3++; /* skip the '(' */ - fits_get_token(&cptr3, ")", colformat, NULL); + fits_get_token2(&cptr3, ")", &tstbuff, NULL, status); + if (*status || strlen(tstbuff) > FLEN_VALUE-1) + { + ffpmsg("column expression is too long (ffedit_columns)"); + if( colindex ) free( colindex ); + if( file_expr ) free( file_expr ); + if (clause) free(clause); + free(tstbuff); + if (*status==0) + *status=URL_PARSE_ERROR; + return(*status); + } + strcpy(colformat, tstbuff); + free(tstbuff); + tstbuff=0; } /* calculate values for the column or keyword */ @@ -3282,13 +3380,24 @@ */ { int slen, isanumber; - char token[FLEN_VALUE]; + char token[FLEN_VALUE], *tstbuff=0; if (*status > 0) return(*status); - slen = fits_get_token(ptr, " ,:", token, &isanumber); /* get 1st token */ - + slen = fits_get_token2(ptr, " ,:", &tstbuff, &isanumber, status); /* get 1st token */ + if (*status || strlen(tstbuff) > FLEN_VALUE-1) + { + ffpmsg("Error: image section string too long (fits_get_section_range)"); + free(tstbuff); + if (*status==0) + *status = URL_PARSE_ERROR; + return(*status); + } + strcpy(token, tstbuff); + free(tstbuff); + tstbuff=0; + /* support [:2,:2] type syntax, where the leading * is implied */ if (slen==0) strcpy(token,"*"); @@ -3311,8 +3420,18 @@ *secmin = atol(token); (*ptr)++; /* skip the colon between the min and max values */ - slen = fits_get_token(ptr, " ,:", token, &isanumber); /* get token */ - + slen = fits_get_token2(ptr, " ,:", &tstbuff, &isanumber, status); /* get token */ + if (*status || strlen(tstbuff) > FLEN_VALUE-1) + { + ffpmsg("Error: image section string too long (fits_get_section_range)"); + free(tstbuff); + if (*status==0) + *status = URL_PARSE_ERROR; + return(*status); + } + strcpy(token, tstbuff); + free(tstbuff); + tstbuff=0; if (slen == 0 || !isanumber) return(*status = URL_PARSE_ERROR); @@ -3323,7 +3442,18 @@ if (**ptr == ':') { (*ptr)++; /* skip the colon between the max and incre values */ - slen = fits_get_token(ptr, " ,", token, &isanumber); /* get token */ + slen = fits_get_token2(ptr, " ,", &tstbuff, &isanumber, status); /* get token */ + if (*status || strlen(tstbuff) > FLEN_VALUE-1) + { + ffpmsg("Error: image section string too long (fits_get_section_range)"); + free(tstbuff); + if (*status==0) + *status = URL_PARSE_ERROR; + return(*status); + } + strcpy(token, tstbuff); + free(tstbuff); + tstbuff=0; if (slen == 0 || !isanumber) return(*status = URL_PARSE_ERROR); @@ -5063,9 +5193,14 @@ /* to the output file, and is not the urltype of the input file */ ptr2 = 0; /* so reset pointer to zero */ } - + if (ptr2) /* copy the explicit urltype string */ { + if (ptr2-ptr1+3 >= MAX_PREFIX_LEN) + { + ffpmsg("Name of urltype is too long."); + return(*status = URL_PARSE_ERROR); + } if (urltype) strncat(urltype, ptr1, ptr2 - ptr1 + 3); ptr1 = ptr2 + 3; diff -ur cfitsio3430/drvrfile.c cfitsio3440/drvrfile.c --- cfitsio3430/drvrfile.c 2018-03-01 17:28:51.000000000 +0100 +++ cfitsio3440/drvrfile.c 2018-04-11 16:33:41.000000000 +0200 @@ -358,7 +358,7 @@ /* Get the current working directory */ fits_get_cwd(cwd, &status); slen = strlen(cwd); - if (cwd[slen-1] != '/') strcat(cwd,"/"); /* make sure the CWD ends with slash */ + if ((slen < FLEN_FILENAME) && cwd[slen-1] != '/') strcat(cwd,"/"); /* make sure the CWD ends with slash */ /* check that CWD string matches the rootstring */ @@ -370,6 +370,7 @@ /* get the user name from CWD (it follows the root string) */ strncpy(username, cwd+rootlen, 50); /* limit length of user name */ + username[50]=0; cpos=strchr(username, '/'); if (!cpos) { ffpmsg("invalid CWD: not equal to root data directory + username"); @@ -765,7 +766,7 @@ /* Open file. Try various suffix combinations */ if (file_openfile(filename, 0, &diskfile)) { - if (strlen(filename) > FLEN_FILENAME - 1) + if (strlen(filename) > FLEN_FILENAME - 5) return(0); strcpy(tmpfilename,filename); @@ -773,7 +774,7 @@ if (file_openfile(filename, 0, &diskfile)) { #if HAVE_BZIP2 - strcpy(tmpfilename,filename); + strcpy(filename,tmpfilename); strcat(filename,".bz2"); if (file_openfile(filename, 0, &diskfile)) { diff -ur cfitsio3430/drvrgsiftp.c cfitsio3440/drvrgsiftp.c --- cfitsio3430/drvrgsiftp.c 2018-03-01 17:28:51.000000000 +0100 +++ cfitsio3440/drvrgsiftp.c 2018-04-11 16:33:41.000000000 +0200 @@ -2,7 +2,7 @@ /* This file, drvrgsiftp.c contains driver routines for gsiftp files. */ /* Andrea Barisani */ /* Taffoni Giuliano */ -#ifdef HAVE_NET_SERVICES +#ifdef HAVE_NET_SERVICES #ifdef HAVE_GSIFTP #include @@ -21,6 +21,7 @@ static int gsiftpopen = 0; static int global_offset = 0; +static int free_gsiftp_tmp=0; static int gsiftp_get(char *filename, FILE **gsiftpfile, int num_streams); static globus_mutex_t lock; @@ -45,7 +46,9 @@ ffpmsg("Cannot create temporary directory!"); return (FILE_NOT_OPENED); } - gsiftp_tmpfile = malloc(strlen(gsiftp_tmpdir) + strlen("/gsiftp_buffer.tmp")); + gsiftp_tmpfile = malloc(strlen(gsiftp_tmpdir) + strlen("/gsiftp_buffer.tmp")+1); + gsiftp_tmpfile[0]=0; + free_gsiftp_tmp=1; strcat(gsiftp_tmpfile, gsiftp_tmpdir); strcat(gsiftp_tmpfile, "/gsiftp_buffer.tmp"); } @@ -56,8 +59,8 @@ int gsiftp_shutdown(void) { free(gsiftpurl); - free(gsiftp_tmpfile); - free(gsiftp_tmpdir); + if (free_gsiftp_tmp) + free(gsiftp_tmpfile); return file_shutdown(); } @@ -356,6 +359,11 @@ done = GLOBUS_FALSE; strcpy(gsiurl,"gsiftp://"); + if (strlen(gsiurl)+strlen(filename) > MAXLEN-1) + { + ffpmsg("file name too long (gsiftp_get)"); + return (FILE_NOT_OPENED); + } strcat(gsiurl,filename); *gsiftpfile = fopen(gsiftp_tmpfile,"w+"); @@ -448,6 +456,11 @@ done = GLOBUS_FALSE; strcpy(gsiurl,"gsiftp://"); + if (strlen(gsiurl)+strlen(filename) > MAXLEN-1) + { + ffpmsg("file name too long (gsiftp_put)"); + return (FILE_NOT_OPENED); + } strcat(gsiurl,filename); *gsiftpfile = fopen(gsiftp_tmpfile,"r"); diff -ur cfitsio3430/drvrnet.c cfitsio3440/drvrnet.c --- cfitsio3430/drvrnet.c 2018-03-01 17:28:51.000000000 +0100 +++ cfitsio3440/drvrnet.c 2018-04-11 16:33:41.000000000 +0200 @@ -920,6 +920,12 @@ /* return the new URL string, and set contentencoding to "ftp" as a flag to the http_checkfile routine */ + if (strlen(scratchstr2) > FLEN_FILENAME-1) + { + ffpmsg("Error: redirected url string too long (http_open_network)"); + fclose(*httpfile); + return URL_PARSE_ERROR; + } strcpy(url, scratchstr2); strcpy(contentencoding,"ftp://"); fclose (*httpfile); @@ -935,6 +941,12 @@ /* return the new URL string, and set contentencoding to "https" as a flag to the http_checkfile routine */ + if (strlen(scratchstr2) > FLEN_FILENAME-1) + { + ffpmsg("Error: redirected url string too long (http_open_network)"); + fclose(*httpfile); + return URL_PARSE_ERROR; + } strcpy(url, scratchstr2); strcpy(contentencoding,"https://"); fclose(*httpfile); @@ -973,6 +985,12 @@ /* Found the : */ scratchstr++; /* skip the : */ scratchstr++; /* skip the extra space */ + if (strlen(scratchstr) > SHORTLEN-1) + { + ffpmsg("Error: content-encoding string too long (http_open_network)"); + fclose(*httpfile); + return URL_PARSE_ERROR; + } strcpy(contentencoding,scratchstr); } } @@ -2556,6 +2574,11 @@ if ((thost = strchr(urlcopy, '@')) != NULL) urlcopy = thost+1; + if (strlen(urlcopy) > SHORTLEN-1) + { + free(urlcopyorig); + return 1; + } strcpy(host,urlcopy); thost = host; while (*urlcopy != '/' && *urlcopy != ':' && *urlcopy) { @@ -2572,6 +2595,11 @@ } } else { /* do this for ftp */ + if (strlen(urlcopy) > SHORTLEN-1) + { + free(urlcopyorig); + return 1; + } strcpy(host,urlcopy); thost = host; while (*urlcopy != '/' && *urlcopy) { @@ -2585,6 +2613,11 @@ /* Now the rest is a fn */ if (*urlcopy) { + if (strlen(urlcopy) > MAXLEN-1) + { + free(urlcopyorig); + return 1; + } strcpy(fn,urlcopy); } free(urlcopyorig); @@ -2645,7 +2678,11 @@ if (!strstr(infile,".gz") && (!strstr(infile,".Z"))) { /* The infile string does not contain the name of a compressed file. */ /* Fisrt, look for a .gz compressed version of the file. */ - + + if (strlen(infile) + 3 > MAXLEN-1) + { + return URL_PARSE_ERROR; + } strcpy(newinfile,infile); strcat(newinfile,".gz"); @@ -2700,7 +2737,11 @@ if (!foundfile) { /* did not find .gz compressed version of the file, so look for .Z file. */ - + + if (strlen(infile+2) > MAXLEN-1) + { + return URL_PARSE_ERROR; + } strcpy(newinfile,infile); strcat(newinfile,".Z"); if (!http_open_network(newinfile,&httpfile,contentencoding, @@ -2878,6 +2919,10 @@ /* The infile string does not contain the name of a compressed file. */ /* Fisrt, look for a .gz compressed version of the file. */ + if (strlen(infile)+3 > MAXLEN-1) + { + return URL_PARSE_ERROR; + } strcpy(newinfile,infile); strcat(newinfile,".gz"); @@ -2888,6 +2933,10 @@ } if (!foundfile) { + if (strlen(infile)+2 > MAXLEN-1) + { + return URL_PARSE_ERROR; + } strcpy(newinfile,infile); strcat(newinfile,".Z"); @@ -3312,6 +3361,11 @@ /* Parse the URL apart again */ + if (strlen(url)+7 > MAXLEN-1) + { + ffpmsg("Error: url too long"); + return(FILE_NOT_OPENED); + } strcpy(turl,"root://"); strcat(turl,url); if (NET_ParseUrl(turl,proto,host,&port,fn)) { @@ -3329,6 +3383,11 @@ /* get the username */ if (NULL != getenv("ROOTUSERNAME")) { + if (strlen(getenv("ROOTUSERNAME")) > MAXLEN-1) + { + ffpmsg("root user name too long (root_openfile)"); + return (FILE_NOT_OPENED); + } strcpy(recbuf,getenv("ROOTUSERNAME")); } else { printf("Username: "); @@ -3357,6 +3416,11 @@ /* now the password */ if (NULL != getenv("ROOTPASSWORD")) { + if (strlen(getenv("ROOTPASSWORD")) > MAXLEN-1) + { + ffpmsg("root password too long (root_openfile)"); + return (FILE_NOT_OPENED); + } strcpy(recbuf,getenv("ROOTPASSWORD")); } else { printf("Password: "); @@ -3387,6 +3451,11 @@ } /* now the file open request */ + if (strlen(fn)+strlen(rwmode)+1 > MAXLEN-1) + { + ffpmsg("root file name too long (root_openfile)"); + return (FILE_NOT_OPENED); + } strcpy(recbuf,fn); strcat(recbuf," "); strcat(recbuf,rwmode); diff -ur cfitsio3430/editcol.c cfitsio3440/editcol.c --- cfitsio3430/editcol.c 2018-03-01 17:28:51.000000000 +0100 +++ cfitsio3440/editcol.c 2018-04-11 16:33:41.000000000 +0200 @@ -1097,6 +1097,11 @@ delbyte = 0; for (ii = 0; ii < ncols; ii++) { + if (strlen(tform[ii]) > FLEN_VALUE-1) + { + ffpmsg("Column format string too long (fficls)"); + return (*status=BAD_TFORM); + } strcpy(tfm, tform[ii]); ffupch(tfm); /* make sure format is in upper case */ diff -ur cfitsio3430/eval_f.c cfitsio3440/eval_f.c --- cfitsio3430/eval_f.c 2018-03-01 17:28:51.000000000 +0100 +++ cfitsio3440/eval_f.c 2018-04-11 16:33:41.000000000 +0200 @@ -593,7 +593,7 @@ if( parInfo==NULL || *parInfo=='\0' ) { /* Figure out best default column type */ if( gParse.hdutype==BINARY_TBL ) { - snprintf(tform,16,"%ld",nelem); + snprintf(tform,15,"%ld",nelem); switch( Info.datatype ) { case TLOGICAL: strcat(tform,"L"); break; case TLONG: strcat(tform,"J"); break; diff -ur cfitsio3430/fitscore.c cfitsio3440/fitscore.c --- cfitsio3430/fitscore.c 2018-03-01 17:28:51.000000000 +0100 +++ cfitsio3440/fitscore.c 2018-04-11 16:33:41.000000000 +0200 @@ -976,21 +977,21 @@ (int) (ii+1), (int) card[ii] ); if (card[ii] == 0) - strcat(msg, " (NULL char.)"); + strncat(msg, " (NULL char.)",FLEN_ERRMSG-strlen(msg)-1); else if (card[ii] == 9) - strcat(msg, " (TAB char.)"); + strncat(msg, " (TAB char.)",FLEN_ERRMSG-strlen(msg)-1); else if (card[ii] == 10) - strcat(msg, " (Line Feed char.)"); + strncat(msg, " (Line Feed char.)",FLEN_ERRMSG-strlen(msg)-1); else if (card[ii] == 11) - strcat(msg, " (Vertical Tab)"); + strncat(msg, " (Vertical Tab)",FLEN_ERRMSG-strlen(msg)-1); else if (card[ii] == 12) - strcat(msg, " (Form Feed char.)"); + strncat(msg, " (Form Feed char.)",FLEN_ERRMSG-strlen(msg)-1); else if (card[ii] == 13) - strcat(msg, " (Carriage Return)"); + strncat(msg, " (Carriage Return)",FLEN_ERRMSG-strlen(msg)-1); else if (card[ii] == 27) - strcat(msg, " (Escape char.)"); + strncat(msg, " (Escape char.)",FLEN_ERRMSG-strlen(msg)-1); else if (card[ii] == 127) - strcat(msg, " (Delete char.)"); + strncat(msg, " (Delete char.)",FLEN_ERRMSG-strlen(msg)-1); ffpmsg(msg); @@ -1118,6 +1119,13 @@ /* for now at least, treat all cases as an implicit ESO HIERARCH keyword. */ /* This could change if FITS is ever expanded to directly support longer keywords. */ + if (namelen + 11 > FLEN_CARD-1) + { + ffpmsg( + "The following keyword is too long to fit on a card:"); + ffpmsg(keyname); + return(*status = BAD_KEYCHAR); + } strcat(card, "HIERARCH "); strcat(card, tmpname); namelen += 9; @@ -1293,7 +1301,6 @@ /* Construct a keyword name string by appending the index number to the root. e.g., if root = "TTYPE" and value = 12 then keyname = "TTYPE12". - Note: this allows keyword names longer than 8 characters. */ { char suffix[16]; @@ -1312,7 +1319,9 @@ rootlen--; /* remove trailing spaces in root name */ keyname[rootlen] = '\0'; } - + if (strlen(suffix) + strlen(keyname) > 8) + return (*status=206); + strcat(keyname, suffix); /* append suffix to the root */ return(*status); } @@ -1582,7 +1591,7 @@ { char keyname[FLEN_KEYWORD], value[140], comment[140]; char *tok, *suffix, *loc, tvalue[140]; - int len, vlen, more, tstatus; + int len, vlen, more, tstatus, lentok1=0, remainlen=0; double dval; if (*status > 0) @@ -1619,36 +1628,41 @@ tok++; len = strspn(tok, " "); /* no. of spaces before keyword */ tok += len; - if (len < 8) /* not a blank name? */ - { - len = strcspn(tok, " ="); /* length of name */ - if (len >= FLEN_KEYWORD) - return(*status = BAD_KEYCHAR); + + len = strcspn(tok, " =+"); /* length of name */ + if (len >= FLEN_KEYWORD) + return(*status = BAD_KEYCHAR); - strncat(card, tok, len); + lentok1 = len; + strncat(card, tok, len); - /* - The HIERARCH convention supports non-standard characters - in the keyword name, so don't always convert to upper case or - abort if there are illegal characters in the name or if the - name is greater than 8 characters long. - */ + /* + The HIERARCH convention supports non-standard characters + in the keyword name, so don't always convert to upper case or + abort if there are illegal characters in the name or if the + name is greater than 8 characters long. + */ - if (len < 9) /* this is possibly a normal FITS keyword name */ + if (len < 9) /* this is possibly a normal FITS keyword name */ + { + ffupch(card); + tstatus = 0; + if (fftkey(card, &tstatus) > 0) { - ffupch(card); - tstatus = 0; - if (fftkey(card, &tstatus) > 0) - { - /* name contained non-standard characters, so reset */ - card[0] = '\0'; - strncat(card, tok, len); - } + /* name contained non-standard characters, so reset */ + card[0] = '\0'; + strncat(card, tok, len); } - - tok += len; } + tok += len; + + /* Check optional "+" indicator to delete multiple keywords */ + if (tok[0] == '+' && len < FLEN_KEYWORD) { + strcat(card, "+"); + return (*status); + } + /* second token, if present, is the new name for the keyword */ len = strspn(tok, " "); /* no. of spaces before next token */ @@ -1659,13 +1673,24 @@ *hdtype = -2; len = strcspn(tok, " "); /* length of new name */ - if (len > 40) /* name has to fit on columns 41-80 of card */ - return(*status = BAD_KEYCHAR); + /* this name has to fit on columns 41-80 of card, + and first name must now fit in 1-40 */ + if (lentok1 > 40) + { + card[0] = '\0'; + return (*status = BAD_KEYCHAR); + } + if (len > 40) + { + card[0] = '\0'; + return(*status = BAD_KEYCHAR); + } /* copy the new name to card + 40; This is awkward, */ /* but is consistent with the way the Fortran FITSIO works */ strcat(card," "); - strncpy(&card[40], tok, len+1); /* copy len+1 to get terminator */ + strncpy(&card[40], tok, len); + card[80] = '\0'; /* necessary to add terminator in case len = 40 */ /* The HIERARCH convention supports non-standard characters @@ -1728,7 +1753,7 @@ { *hdtype = 1; /* simply append COMMENT and HISTORY keywords */ strcpy(card, keyname); - strncat(card, tok, 73); + strncat(card, tok, 72); return(*status); } @@ -1739,12 +1764,16 @@ if (*tok == '\'') /* is value enclosed in quotes? */ { more = TRUE; + remainlen = 139; while (more) { tok++; /* temporarily move past the quote char */ len = strcspn(tok, "'"); /* length of quoted string */ tok--; - strncat(value, tok, len + 2); + if (len+2 > remainlen) + return (*status=BAD_KEYCHAR); + strncat(value, tok, len + 2); + remainlen -= (len+2); tok += len + 1; if (tok[0] != '\'') /* check there is a closing quote */ @@ -1762,7 +1791,8 @@ else /* not a quoted string value */ { len = strcspn(tok, " /"); /* length of value string */ - + if (len > 139) + return (*status=BAD_KEYCHAR); strncat(value, tok, len); if (!( (tok[0] == 'T' || tok[0] == 'F') && (tok[1] == ' ' || tok[1] == '/' || tok[1] == '\0') )) @@ -1796,6 +1826,8 @@ if (*suffix != '\0' && *suffix != ' ' && *suffix != '/') { /* value is not a number; must enclose it in quotes */ + if (len > 137) + return (*status=BAD_KEYCHAR); strcpy(value, "'"); strncat(value, tok, len); strcat(value, "'"); @@ -2607,6 +2639,11 @@ while (tform[ii] != 0 && tform[ii] == ' ') /* find first non-blank char */ ii++; + if (strlen(&tform[ii]) > FLEN_VALUE-1) + { + ffpmsg("Error: ASCII table TFORM code is too long (ffasfm)"); + return(*status = BAD_TFORM); + } strcpy(temp, &tform[ii]); /* copy format string */ ffupch(temp); /* make sure it is in upper case */ form = temp; /* point to start of format string */ @@ -2764,6 +2801,11 @@ return(*status = BAD_TFORM); } + if (nchar-ii > FLEN_VALUE-1) + { + ffpmsg("Error: binary table TFORM code is too long (ffbnfm)."); + return (*status = BAD_TFORM); + } strcpy(temp, &tform[ii]); /* copy format string */ ffupch(temp); /* make sure it is in upper case */ form = temp; /* point to start of format string */ @@ -2779,7 +2821,13 @@ if (ii == 0) repeat = 1; /* no explicit repeat count */ else - sscanf(form,"%ld", &repeat); /* read repeat count */ + { + if (sscanf(form,"%ld", &repeat) != 1) /* read repeat count */ + { + ffpmsg("Error: Bad repeat format in TFORM (ffbnfm)."); + return(*status = BAD_TFORM); + } + } /*-----------------------------------------------*/ /* determine datatype code */ @@ -2948,7 +2996,12 @@ ffpmsg("Error: binary table TFORM code is blank (ffbnfmll)."); return(*status = BAD_TFORM); } - + + if (strlen(&tform[ii]) > FLEN_VALUE-1) + { + ffpmsg("Error: binary table TFORM code is too long (ffbnfmll)."); + return(*status = BAD_TFORM); + } strcpy(temp, &tform[ii]); /* copy format string */ ffupch(temp); /* make sure it is in upper case */ form = temp; /* point to start of format string */ @@ -6559,7 +6612,7 @@ 'len' is the maximum length of the vector in the table (e.g., '1PE(400)') */ { - int ii; + int ii, lenform=0; long tflds; LONGLONG length, addr, maxlen, naxis2, jj; char comment[FLEN_COMMENT], keyname[FLEN_KEYWORD]; @@ -6598,13 +6651,20 @@ /* construct the new keyword value */ strcpy(newform, "'"); tmp = strchr(tform, '('); /* truncate old length, if present */ - if (tmp) *tmp = 0; - strcat(newform, tform); + if (tmp) *tmp = 0; + lenform = strlen(tform); /* print as double, because the string-to-64-bit */ /* conversion is platform dependent (%lld, %ld, %I64d) */ snprintf(lenval,40, "(%.0f)", (double) maxlen); + + if (lenform+strlen(lenval)+2 > FLEN_VALUE-1) + { + ffpmsg("Error assembling TFORMn string (ffuptf)."); + return(*status = BAD_TFORM); + } + strcat(newform, tform); strcat(newform,lenval); while(strlen(newform) < 9) @@ -9234,7 +9294,7 @@ if (errno == ERANGE) { strcpy(msg,"Range Error in ffc2jj converting string to longlong int: "); - strncat(msg,cval,25); + strncat(msg,cval,23); ffpmsg(msg); *status = NUM_OVERFLOW; @@ -9349,6 +9409,12 @@ if (strchr(cval, 'D') || decimalpt == ',') { /* strtod expects a comma, not a period, as the decimal point */ + if (strlen(cval) > 72) + { + strcpy(msg,"Error: Invalid string to float in ffc2rr"); + ffpmsg(msg); + return (*status=BAD_C2F); + } strcpy(tval, cval); /* The C language does not support a 'D'; replace with 'E' */ @@ -9419,6 +9485,12 @@ if (strchr(cval, 'D') || decimalpt == ',') { /* need to modify a temporary copy of the string before parsing it */ + if (strlen(cval) > 72) + { + strcpy(msg,"Error: Invalid string to double in ffc2dd"); + ffpmsg(msg); + return (*status=BAD_C2D); + } strcpy(tval, cval); /* The C language does not support a 'D'; replace with 'E' */ if ((loc = strchr(tval, 'D'))) *loc = 'E'; diff -ur cfitsio3430/fpackutil.c cfitsio3440/fpackutil.c --- cfitsio3430/fpackutil.c 2018-03-01 17:28:51.000000000 +0100 +++ cfitsio3440/fpackutil.c 2018-04-11 23:05:04.000000000 +0200 @@ -63,16 +63,23 @@ int status = 0, hdunum; char msg[SZ_STR]; - fits_file_name(infptr, tempfilename, &status); - fits_get_hdu_num(infptr, &hdunum); - - fits_close_file (infptr, &status); - - snprintf(msg, SZ_STR,"Error processing file: %s\n", tempfilename); - fp_msg (msg); - snprintf(msg, SZ_STR," in HDU number %d\n", hdunum); - fp_msg (msg); - + if (infptr) + { + fits_file_name(infptr, tempfilename, &status); + fits_get_hdu_num(infptr, &hdunum); + + fits_close_file (infptr, &status); + + snprintf(msg, SZ_STR,"Error processing file: %s\n", tempfilename); + fp_msg (msg); + snprintf(msg, SZ_STR," in HDU number %d\n", hdunum); + fp_msg (msg); + } + else + { + snprintf(msg, SZ_STR,"Error: Unable to process input file\n"); + fp_msg(msg); + } fits_report_error (stderr, stat); if (outfptr) { @@ -129,6 +136,13 @@ for (ii = 0; ii < maxtry; ii++) { if (fp_access(tmpnam)) break; /* good, the file does not exist */ + if (strlen(tmpnam) > SZ_STR-2) + { + fp_msg ("\nCould not create temporary file name:\n"); + fp_msg (tmpnam); + fp_msg ("\n"); + exit (-1); + } strcat(tmpnam, "x"); /* append an x to the name, and try again */ } @@ -203,7 +217,8 @@ } for (iarg=fpvar.firstfile; iarg < argc; iarg++) { - strncpy (infits, argv[iarg], SZ_STR); + strncpy (infits, argv[iarg], SZ_STR-1); + infits[SZ_STR-1]=0; if (strchr (infits, '[') || strchr (infits, ']')) { fp_msg ("Error: section/extension notation not supported: "); @@ -472,6 +487,11 @@ /* if gzipping the output, make sure .gz file doesn't exist */ if (fpptr->do_gzip_file) { + if (strlen(outfits)+3 > SZ_STR-1) + { + fp_msg ("Error: output file name too long:\n "); fp_msg (outfits); + fp_msg ("\n "); fp_noop (); exit (-1); + } strcat(outfits, ".gz"); if (fp_access (outfits) == 0) { fp_msg ("Error: output file already exists:\n "); fp_msg (outfits); @@ -486,6 +506,11 @@ /* check that input file exists */ if (infits[0] != '-') { /* if not reading from stdin stream */ if (fp_access (infits) != 0) { /* if not, then check if */ + if (strlen(infits)+3 > SZ_STR-1) + { + fp_msg ("Error: input file name too long:\n "); fp_msg (infits); + fp_msg ("\n "); fp_noop (); exit (-1); + } strcat(infits, ".gz"); /* a gzipped version exsits */ if (fp_access (infits) != 0) { namelen = strlen(infits); @@ -553,7 +578,8 @@ { char infits[SZ_STR], outfits[SZ_STR]; char temp[SZ_STR], answer[30]; - int iarg, islossless, namelen, iraf_infile = 0, status = 0, ifail; + char valchar[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.#()+,-_@[]/^{}"; + int ichar=0, outlen=0, iarg, islossless, namelen, iraf_infile = 0, status = 0, ifail; if (fpvar.initialized != FP_INIT_MAGIC) { fp_msg ("Error: internal initialization error\n"); exit (-1); @@ -598,6 +624,7 @@ islossless = 1; strncpy (infits, argv[iarg], SZ_STR - 1); + infits[SZ_STR-1]=0; if (unpack) { /* ********** This section applies to funpack ************ */ @@ -678,6 +705,7 @@ } strncpy(temp, outfits, SZ_STR-1); + temp[SZ_STR-1]=0; if (infits[0] != '-') { /* if not reading from stdin stream */ if (!strcmp(infits, outfits) ) { /* are input and output names the same? */ @@ -828,6 +856,20 @@ if (fpvar.do_gzip_file) { /* gzip the output file */ strcpy(temp, "gzip -1 "); + outlen = strlen(outfits); + if (outlen + 8 > SZ_STR-1) + { + fp_msg("\nError: Output file name is too long.\n"); + exit(-1); + } + for (ichar=0; ichar < outlen; ++ichar) + { + if (!strchr(valchar, outfits[ichar])) + { + fp_msg("\n Error: Invalid characters in output file name.\n"); + exit(-1); + } + } strcat(temp,outfits); system(temp); strcat(outfits, ".gz"); /* only possibible with funpack */ @@ -1197,11 +1239,12 @@ snprintf(dimen,100," (%ld", naxes[0]); len =strlen(dimen); for (ii = 1; ii < naxis; ii++) { - if (len < 100) + if (len < 99) snprintf(dimen+len,100-len,",%ld", naxes[ii]); len =strlen(dimen); } - strcat(dimen, ")"); + if (strlen(dimen)<99) + strcat(dimen, ")"); printf("%-12s",dimen); fits_get_hduaddr(inputfptr, &headstart, &datastart, &dataend, &stat); diff -ur cfitsio3430/getcols.c cfitsio3440/getcols.c --- cfitsio3430/getcols.c 2018-03-01 17:28:51.000000000 +0100 +++ cfitsio3440/getcols.c 2018-04-11 16:33:41.000000000 +0200 @@ -296,8 +296,9 @@ /* write the formated string for each value */ if (nulval) { - strcpy(tmpnull, nulval); - nulwidth = strlen(nulval); + strncpy(tmpnull, nulval,79); + tmpnull[79]='\0'; /* In case len(nulval) >= 79 */ + nulwidth = strlen(tmpnull); } else { strcpy(tmpnull, " "); nulwidth = 1; @@ -430,8 +431,9 @@ } if (nulval) { - strcpy(tmpnull, nulval); - nulwidth = strlen(nulval); + strncpy(tmpnull, nulval,79); + tmpnull[79]='\0'; + nulwidth = strlen(tmpnull); } else { strcpy(tmpnull, " "); nulwidth = 1; diff -ur cfitsio3430/getkey.c cfitsio3440/getkey.c --- cfitsio3430/getkey.c 2018-03-01 17:28:51.000000000 +0100 +++ cfitsio3440/getkey.c 2018-04-11 16:33:42.000000000 +0200 @@ -1451,6 +1451,10 @@ equalssign = strchr(card, '='); if (equalssign == 0) continue; /* keyword has no value */ + if (equalssign - card - lenroot > 7) + { + return (*status=BAD_KEYCHAR); + } strncat(keyindex, &card[lenroot], equalssign - card - lenroot); /* copy suffix */ tstatus = 0; if (ffc2ii(keyindex, &ival, &tstatus) <= 0) /* test suffix */ @@ -1528,6 +1532,10 @@ equalssign = strchr(card, '='); if (equalssign == 0) continue; /* keyword has no value */ + if (equalssign - card - lenroot > 7) + { + return (*status=BAD_KEYCHAR); + } strncat(keyindex, &card[lenroot], equalssign - card - lenroot); /* copy suffix */ tstatus = 0; @@ -1605,6 +1613,10 @@ equalssign = strchr(card, '='); if (equalssign == 0) continue; /* keyword has no value */ + if (equalssign - card - lenroot > 7) + { + return (*status=BAD_KEYCHAR); + } strncat(keyindex, &card[lenroot], equalssign - card - lenroot); /* copy suffix */ tstatus = 0; @@ -1682,6 +1694,10 @@ equalssign = strchr(card, '='); if (equalssign == 0) continue; /* keyword has no value */ + if (equalssign - card - lenroot > 7) + { + return (*status=BAD_KEYCHAR); + } strncat(keyindex, &card[lenroot], equalssign - card - lenroot); /* copy suffix */ tstatus = 0; @@ -1759,6 +1775,10 @@ equalssign = strchr(card, '='); if (equalssign == 0) continue; /* keyword has no value */ + if (equalssign - card - lenroot > 7) + { + return (*status=BAD_KEYCHAR); + } strncat(keyindex, &card[lenroot], equalssign - card - lenroot); /* copy suffix */ tstatus = 0; @@ -1835,6 +1855,10 @@ equalssign = strchr(card, '='); if (equalssign == 0) continue; /* keyword has no value */ + if (equalssign - card - lenroot > 7) + { + return (*status=BAD_KEYCHAR); + } strncat(keyindex, &card[lenroot], equalssign - card - lenroot); /* copy suffix */ tstatus = 0; if (ffc2ii(keyindex, &ival, &tstatus) <= 0) /* test suffix */ diff -ur cfitsio3430/group.c cfitsio3440/group.c --- cfitsio3430/group.c 2018-03-01 17:28:51.000000000 +0100 +++ cfitsio3440/group.c 2018-04-11 16:33:41.000000000 +0200 @@ -1543,6 +1543,13 @@ else { strcpy(memberLocation,cwd); + if (strlen(memberLocation)+strlen(memberFileName)+1 > + FLEN_FILENAME-1) + { + ffpmsg("member path and filename is too long (ffgtam)"); + *status = URL_PARSE_ERROR; + continue; + } strcat(memberLocation,"/"); strcat(memberLocation,memberFileName); } @@ -1565,6 +1572,14 @@ else { strcpy(groupLocation,cwd); + if (strlen(groupLocation)+strlen(groupFileName)+1 > + FLEN_FILENAME-1) + { + ffpmsg("group path and filename is too long (ffgtam)"); + *status = URL_PARSE_ERROR; + continue; + } + strcat(groupLocation,"/"); strcat(groupLocation,groupFileName); } @@ -1782,11 +1797,18 @@ /* make grplc absolute if necessary */ if(!fits_is_url_absolute(grplc)) { - fits_path2url(grplc,groupLocation,status); + fits_path2url(grplc,FLEN_FILENAME,groupLocation,status); if(groupLocation[0] != '/') { strcpy(tmp, cwd); + if (strlen(tmp)+strlen(groupLocation)+1 > + FLEN_FILENAME-1) + { + ffpmsg("path and group location is too long (ffgtam)"); + *status = URL_PARSE_ERROR; + continue; + } strcat(tmp,"/"); strcat(tmp,groupLocation); fits_clean_url(tmp,grplc,status); @@ -1795,11 +1817,18 @@ /* make groupFileName absolute if necessary */ if(!fits_is_url_absolute(groupFileName)) { - fits_path2url(groupFileName,groupLocation,status); + fits_path2url(groupFileName,FLEN_FILENAME,groupLocation,status); if(groupLocation[0] != '/') { strcpy(tmp, cwd); + if (strlen(tmp)+strlen(groupLocation)+1 > + FLEN_FILENAME-1) + { + ffpmsg("path and group location is too long (ffgtam)"); + *status = URL_PARSE_ERROR; + continue; + } strcat(tmp,"/"); strcat(tmp,groupLocation); /* @@ -2145,7 +2174,14 @@ &locationCol,&uriCol,&grptype,status); if(*status != 0) continue; + + /* verify the column formats */ + + *status = ffvcfm(gfptr,xtensionCol,extnameCol,extverCol,positionCol, + locationCol,uriCol,status); + if(*status != 0) continue; + /* extract the member information from grouping table */ @@ -2415,6 +2451,13 @@ { fits_get_cwd(cwd,status); strcat(cwd,"/"); + if (strlen(cwd)+strlen(grpLocation1)+1 > + FLEN_FILENAME-1) + { + ffpmsg("cwd and group location1 is too long (ffgmop)"); + *status = URL_PARSE_ERROR; + continue; + } strcat(cwd,grpLocation1); strcpy(grpLocation1,cwd); } @@ -2477,6 +2520,13 @@ *grpLocation2 != '/') { fits_get_cwd(cwd,status); + if (strlen(cwd)+strlen(grpLocation2)+1 > + FLEN_FILENAME-1) + { + ffpmsg("cwd and group location2 is too long (ffgmop)"); + *status = URL_PARSE_ERROR; + continue; + } strcat(cwd,"/"); strcat(cwd,grpLocation2); strcpy(grpLocation2,cwd); @@ -3112,6 +3162,13 @@ !fits_is_url_absolute(grpLocation1)) { strcpy(grpLocation3,cwd); + if (strlen(grpLocation3)+strlen(grpLocation1)+1 > + FLEN_FILENAME-1) + { + ffpmsg("group locations are too long (ffgmrm)"); + *status = URL_PARSE_ERROR; + continue; + } strcat(grpLocation3,"/"); strcat(grpLocation3,grpLocation1); fits_clean_url(grpLocation3,grpLocation1,status); @@ -3121,6 +3178,13 @@ !fits_is_url_absolute(grpLocation2)) { strcpy(grpLocation3,cwd); + if (strlen(grpLocation3)+strlen(grpLocation2)+1 > + FLEN_FILENAME-1) + { + ffpmsg("group locations are too long (ffgmrm)"); + *status = URL_PARSE_ERROR; + continue; + } strcat(grpLocation3,"/"); strcat(grpLocation3,grpLocation2); fits_clean_url(grpLocation3,grpLocation2,status); @@ -3225,6 +3289,13 @@ *editLocation = '\0'; } + if (strlen(grpLocation3)+strlen(grplc)+1 > + FLEN_FILENAME-1) + { + ffpmsg("group locations are too long (ffgmrm)"); + *status = URL_PARSE_ERROR; + continue; + } strcat(grpLocation3,"/"); strcat(grpLocation3,grplc); *status = fits_clean_url(grpLocation3,grplc, @@ -3466,6 +3537,87 @@ } /*****************************************************************************/ +int ffvcfm(fitsfile *gfptr, int xtensionCol, int extnameCol, int extverCol, + int positionCol, int locationCol, int uriCol, int *status) +{ +/* + Perform validation on column formats to ensure this matches the grouping + format the get functions expect. Particularly want to check widths of + string columns. +*/ + + int typecode=0; + long repeat=0, width=0; + + if (*status != 0) return (*status); + + do { + if (xtensionCol) + { + fits_get_coltype(gfptr, xtensionCol, &typecode, &repeat, &width, status); + if (*status || typecode != TSTRING || repeat != width || repeat > 8) + { + if (*status==0) *status=NOT_GROUP_TABLE; + ffpmsg("Wrong format for Grouping xtension col. (ffvcfm)"); + continue; + } + } + if (extnameCol) + { + fits_get_coltype(gfptr, extnameCol, &typecode, &repeat, &width, status); + if (*status || typecode != TSTRING || repeat != width || repeat > 32) + { + if (*status==0) *status=NOT_GROUP_TABLE; + ffpmsg("Wrong format for Grouping name col. (ffvcfm)"); + continue; + } + } + if (extverCol) + { + fits_get_coltype(gfptr, extverCol, &typecode, &repeat, &width, status); + if (*status || typecode != TINT32BIT || repeat > 1) + { + if (*status==0) *status=NOT_GROUP_TABLE; + ffpmsg("Wrong format for Grouping version col. (ffvcfm)"); + continue; + } + } + if (positionCol) + { + fits_get_coltype(gfptr, positionCol, &typecode, &repeat, &width, status); + if (*status || typecode != TINT32BIT || repeat > 1) + { + if (*status==0) *status=NOT_GROUP_TABLE; + ffpmsg("Wrong format for Grouping position col. (ffvcfm)"); + continue; + } + } + if (locationCol) + { + fits_get_coltype(gfptr, locationCol, &typecode, &repeat, &width, status); + if (*status || typecode != TSTRING || repeat != width || repeat > 256) + { + if (*status==0) *status=NOT_GROUP_TABLE; + ffpmsg("Wrong format for Grouping location col. (ffvcfm)"); + continue; + } + } + if (uriCol) + { + fits_get_coltype(gfptr, uriCol, &typecode, &repeat, &width, status); + if (*status || typecode != TSTRING || repeat != width || repeat > 3) + { + if (*status==0) *status=NOT_GROUP_TABLE; + ffpmsg("Wrong format for Grouping URI col. (ffvcfm)"); + continue; + } + } + } while (0); + return (*status); +} + + +/*****************************************************************************/ int ffgtdc(int grouptype, /* code specifying the type of grouping table information: GT_ID_ALL_URI 0 ==> defualt (all columns) @@ -3977,11 +4129,17 @@ else if(!fits_is_url_absolute(location)) { - fits_path2url(location,tmpLocation,status); + fits_path2url(location,FLEN_FILENAME,tmpLocation,status); if(*tmpLocation != '/') { fits_get_cwd(cwd,status); + if (strlen(cwd)+strlen(tmpLocation)+1 > + FLEN_FILENAME-1) + { + ffpmsg("cwd and location are too long (ffgmf)"); + return (*status = URL_PARSE_ERROR); + } strcat(cwd,"/"); strcat(cwd,tmpLocation); fits_clean_url(cwd,tmpLocation,status); @@ -4084,6 +4242,13 @@ *mbrLocation1 != '/') { fits_get_cwd(cwd,status); + if (strlen(cwd)+strlen(mbrLocation1)+1 > + FLEN_FILENAME-1) + { + ffpmsg("cwd and member locations are too long (ffgmf)"); + *status = URL_PARSE_ERROR; + continue; + } strcat(cwd,"/"); strcat(cwd,mbrLocation1); fits_clean_url(cwd,mbrLocation1,status); @@ -4094,6 +4259,13 @@ *mbrLocation2 != '/') { fits_get_cwd(cwd,status); + if (strlen(cwd)+strlen(mbrLocation2)+1 > + FLEN_FILENAME-1) + { + ffpmsg("cwd and member locations are too long (ffgmf)"); + *status = URL_PARSE_ERROR; + continue; + } strcat(cwd,"/"); strcat(cwd,mbrLocation2); fits_clean_url(cwd,mbrLocation2,status); @@ -4119,6 +4291,13 @@ if(!fits_is_url_absolute(grpLocation1) && *grpLocation1 != '/') { fits_get_cwd(cwd,status); + if (strlen(cwd)+strlen(grpLocation1)+1 > + FLEN_FILENAME-1) + { + ffpmsg("cwd and group locations are too long (ffgmf)"); + *status = URL_PARSE_ERROR; + continue; + } strcat(cwd,"/"); strcat(cwd,grpLocation1); fits_clean_url(cwd,grpLocation1,status); @@ -4154,6 +4333,13 @@ if(!fits_is_url_absolute(grpLocation2) && *grpLocation2 != '/') { fits_get_cwd(cwd,status); + if (strlen(cwd)+strlen(grpLocation2)+1 > + FLEN_FILENAME-1) + { + ffpmsg("cwd and group locations are too long (ffgmf)"); + *status = URL_PARSE_ERROR; + continue; + } strcat(cwd,"/"); strcat(cwd,grpLocation2); fits_clean_url(cwd,grpLocation2,status); @@ -4823,6 +5009,8 @@ Host dependent directory path to/from URL functions --------------------------------------------------------------------------*/ int fits_path2url(char *inpath, /* input file path string */ + int maxlength, /* I max number of chars that can be written + to output, including terminating NULL */ char *outpath, /* output file path string */ int *status) /* @@ -5187,7 +5375,7 @@ encode all "unsafe" and "reserved" URL characters */ - *status = fits_encode_url(buff,outpath,status); + *status = fits_encode_url(buff,maxlength,outpath,status); return(*status); } @@ -5473,7 +5661,12 @@ Good old getcwd() seems to work with all other platforms */ - getcwd(buff,FLEN_FILENAME); + if (!getcwd(buff,FLEN_FILENAME)) + { + cwd[0]=0; + ffpmsg("Path and file name too long (fits_get_cwd)"); + return (*status=URL_PARSE_ERROR); + } #endif @@ -5481,7 +5674,7 @@ convert the cwd string to a URL standard path string */ - fits_path2url(buff,cwd,status); + fits_path2url(buff,FLEN_FILENAME,cwd,status); return(*status); } @@ -5788,7 +5981,7 @@ i = 0; } - *status = fits_path2url(tmpPtr,realURL+i,status); + *status = fits_path2url(tmpPtr,FLEN_FILENAME-i,realURL+i,status); } } @@ -5810,7 +6003,7 @@ i = 0; } - *status = fits_path2url(tmpPtr,startURL+i,status); + *status = fits_path2url(tmpPtr,FLEN_FILENAME-i,startURL+i,status); } } @@ -5923,6 +6116,14 @@ * onto output string until stack is empty */ while(0 < mystack->stack_size) { tmp = shift_grp_stack(mystack); + if (strlen(outURL) + strlen(tmp) + 1 > FLEN_FILENAME-1) + { + outURL[0]=0; + ffpmsg("outURL is too long (fits_clean_url)"); + *status = URL_PARSE_ERROR; + delete_grp_stack(&mystack); + return *status; + } strcat(outURL, tmp); strcat(outURL, "/"); } @@ -6118,10 +6319,25 @@ */ for(j = refcount; j < refsize; ++j) - if(refURL[j] == '/') strcat(relURL,"../"); + if(refURL[j] == '/') + { + if (strlen(relURL)+3 > FLEN_FILENAME-1) + { + *status = URL_PARSE_ERROR; + ffpmsg("relURL too long (fits_url2relurl)"); + return (*status); + } + strcat(relURL,"../"); + } /* copy all remaining characters of absURL to the output relURL */ + if (strlen(relURL) + strlen(absURL+abscount) > FLEN_FILENAME-1) + { + *status = URL_PARSE_ERROR; + ffpmsg("relURL too long (fits_url2relurl)"); + return (*status); + } strcat(relURL,absURL+abscount); /* we are done building the relative URL */ @@ -6168,6 +6384,13 @@ make a copy of the reference URL string refURL for parsing purposes */ + if (strlen(refURL) > FLEN_FILENAME-1) + { + absURL[0]=0; + ffpmsg("ref URL is too long (fits_relurl2url)"); + *status = URL_PARSE_ERROR; + continue; + } strcpy(tmpStr,refURL); /* @@ -6199,6 +6422,13 @@ if(tmpStr1 != NULL) tmpStr1[1] = 0; else tmpStr[0] = 0; + if (strlen(tmpStr)+strlen(relURL) > FLEN_FILENAME-1) + { + absURL[0]=0; + ffpmsg("rel + ref URL is too long (fits_relurl2url)"); + *status = URL_PARSE_ERROR; + continue; + } strcat(tmpStr,relURL); } else @@ -6220,7 +6450,17 @@ strcpy(absURL,"/"); - for(i = 0; relURL[i] == '/'; ++i) strcat(absURL,"/"); + for(i = 0; relURL[i] == '/'; ++i) + { + if (strlen(absURL) + 1 > FLEN_FILENAME-1) + { + absURL[0]=0; + ffpmsg("abs URL is too long (fits_relurl2url)"); + *status = URL_PARSE_ERROR; + return (*status); + } + strcat(absURL,"/"); + } /* loop over the refURL string until the slash pattern stored @@ -6265,6 +6505,13 @@ the absURL */ + if (strlen(tmpStr)+strlen(relURL) > FLEN_FILENAME-1) + { + absURL[0]=0; + ffpmsg("rel + ref URL is too long (fits_relurl2url)"); + *status = URL_PARSE_ERROR; + continue; + } strcat(tmpStr,relURL); } @@ -6280,7 +6527,9 @@ return(*status); } /*--------------------------------------------------------------------------*/ -int fits_encode_url(char *inpath, /* I URL to be encoded */ +int fits_encode_url(char *inpath, /* I URL to be encoded */ + int maxlength, /* I max number of chars that may be copied + to outpath, including terminating NULL. */ char *outpath, /* O output encoded URL */ int *status) /* @@ -6288,12 +6537,12 @@ convention, where XX stand for the two hexidecimal digits of the encode character's ASCII code. - Note that the output path is at least as large as, if not larger than - the input path, so that OUTPATH should be passed to this function - with room for growth. If not a runtime error could result. It is - assumed that OUTPATH has been allocated with enough room to hold - the resulting encoded URL. - + Note that the outpath length, as specified by the maxlength argument, + should be at least as large as inpath and preferably larger (to hold + any characters that need encoding). If more than maxlength chars are + required for outpath, including the terminating NULL, outpath will + be set to size 0 and an error status will be returned. + This function was adopted from code in the libwww.a library available via the W3 consortium */ @@ -6303,6 +6552,7 @@ char *p; char *q; char *hex = "0123456789ABCDEF"; + int iout=0; unsigned const char isAcceptable[96] = {/* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xA 0xB 0xC 0xD 0xE 0xF */ @@ -6325,7 +6575,7 @@ /* loop over all characters in inpath until '\0' is encountered */ - for(q = outpath, p = inpath; *p; p++) + for(q = outpath, p = inpath; *p && (iout < maxlength-1) ; p++) { a = (unsigned char)*p; @@ -6333,19 +6583,41 @@ if(!( a>=32 && a<128 && (isAcceptable[a-32]))) { - /* add a '%' character to the outpath */ - *q++ = HEX_ESCAPE; - /* add the most significant ASCII code hex value */ - *q++ = hex[a >> 4]; - /* add the least significant ASCII code hex value */ - *q++ = hex[a & 15]; + if (iout+2 < maxlength-1) + { + /* add a '%' character to the outpath */ + *q++ = HEX_ESCAPE; + /* add the most significant ASCII code hex value */ + *q++ = hex[a >> 4]; + /* add the least significant ASCII code hex value */ + *q++ = hex[a & 15]; + iout += 3; + } + else + { + ffpmsg("URL input is too long to encode (fits_encode_url)"); + *status = URL_PARSE_ERROR; + outpath[0] = 0; + return (*status); + } } /* else just copy the character as is */ - else *q++ = *p; + else + { + *q++ = *p; + iout++; + } } /* null terminate the outpath string */ + if (*p && (iout == maxlength-1)) + { + ffpmsg("URL input is too long to encode (fits_encode_url)"); + *status = URL_PARSE_ERROR; + outpath[0] = 0; + return (*status); + } *q++ = 0; return(*status); diff -ur cfitsio3430/group.h cfitsio3440/group.h --- cfitsio3430/group.h 2018-03-01 17:28:51.000000000 +0100 +++ cfitsio3440/group.h 2018-04-11 16:33:41.000000000 +0200 @@ -23,6 +23,9 @@ int *positionCol, int *locationCol, int *uriCol, int *grptype, int *status); +int ffvcfm(fitsfile *gfptr, int xtensionCol, int extnameCol, int extverCol, + int positionCol, int locationCol, int uriCol, int *status); + int ffgmul(fitsfile *mfptr, int rmopt, int *status); int ffgmf(fitsfile *gfptr, char *xtension, char *extname, int extver, @@ -41,7 +44,7 @@ void prepare_keyvalue(char *keyvalue); -int fits_path2url(char *inpath, char *outpath, int *status); +int fits_path2url(char *inpath, int maxlength, char *outpath, int *status); int fits_url2path(char *inpath, char *outpath, int *status); @@ -57,7 +60,7 @@ int fits_url2relurl(char *refURL, char *absURL, char *relURL, int *status); -int fits_encode_url(char *inpath, char *outpath, int *status); +int fits_encode_url(char *inpath, int maxlength, char *outpath, int *status); int fits_unencode_url(char *inpath, char *outpath, int *status); diff -ur cfitsio3430/histo.c cfitsio3440/histo.c --- cfitsio3430/histo.c 2018-03-01 17:28:51.000000000 +0100 +++ cfitsio3440/histo.c 2018-04-11 16:33:41.000000000 +0200 @@ -58,7 +58,7 @@ most other reasonable combinations are supported. */ int ii, slen, defaulttype; - char *ptr, tmpname[30], *file_expr = NULL; + char *ptr, tmpname[FLEN_VALUE], *file_expr = NULL; double dummy; if (*status > 0) @@ -369,52 +369,78 @@ the column name, histogram min and max values, and bin size. */ { - int slen, isanumber; - char token[FLEN_VALUE]; + int slen, isanumber=0; + char *token=0; if (*status > 0) return(*status); - slen = fits_get_token(ptr, " ,=:;", token, &isanumber); /* get 1st token */ + slen = fits_get_token2(ptr, " ,=:;", &token, &isanumber, status); /* get 1st token */ - if (slen == 0 && (**ptr == '\0' || **ptr == ',' || **ptr == ';') ) + if ((*status) || (slen == 0 && (**ptr == '\0' || **ptr == ',' || **ptr == ';')) ) return(*status); /* a null range string */ - + if (!isanumber && **ptr != ':') { /* this looks like the column name */ - - if (token[0] == '#' && isdigit((int) token[1]) ) + + /* Check for case where col name string is empty but '=' + is still there (indicating a following specification string). + Musn't enter this block as token would not have been allocated. */ + if (slen != 0 || (**ptr != '=')) { - /* omit the leading '#' in the column number */ - strcpy(colname, token+1); - } - else - strcpy(colname, token); - - while (**ptr == ' ') /* skip over blanks */ - (*ptr)++; + if (strlen(token) > FLEN_VALUE-1) + { + ffpmsg("column name too long (ffbinr)"); + free(token); + return(*status=PARSE_SYNTAX_ERR); + } + if (token[0] == '#' && isdigit((int) token[1]) ) + { + /* omit the leading '#' in the column number */ + strcpy(colname, token+1); + } + else + strcpy(colname, token); + free(token); + token=0; + while (**ptr == ' ') /* skip over blanks */ + (*ptr)++; - if (**ptr != '=') - return(*status); /* reached the end */ + if (**ptr != '=') + return(*status); /* reached the end */ + } (*ptr)++; /* skip over the = sign */ while (**ptr == ' ') /* skip over blanks */ (*ptr)++; - slen = fits_get_token(ptr, " ,:;", token, &isanumber); /* get token */ + /* get specification info */ + slen = fits_get_token2(ptr, " ,:;", &token, &isanumber, status); + if (*status) + return(*status); } if (**ptr != ':') { - /* this is the first token, and since it is not followed by */ - /* a ':' this must be the binsize token */ + /* This is the first token, and since it is not followed by + a ':' this must be the binsize token. Or it could be empty + in which case none of the following operations will do anything */ if (!isanumber) + { + if (strlen(token) > FLEN_VALUE-1) + { + ffpmsg("binname too long (ffbinr)"); + free(token); + return(*status=PARSE_SYNTAX_ERR); + } strcpy(binname, token); + } else *binsizein = strtod(token, NULL); - + + free(token); return(*status); /* reached the end */ } else @@ -423,37 +449,73 @@ if (slen) { if (!isanumber) + { + if (strlen(token) > FLEN_VALUE-1) + { + ffpmsg("minname too long (ffbinr)"); + free(token); + return(*status=PARSE_SYNTAX_ERR); + } strcpy(minname, token); + } else *minin = strtod(token, NULL); + free(token); + token=0; } } (*ptr)++; /* skip the colon between the min and max values */ - slen = fits_get_token(ptr, " ,:;", token, &isanumber); /* get token */ + slen = fits_get_token2(ptr, " ,:;", &token, &isanumber, status); /* get token */ + if (*status) + return(*status); /* the token contains the max value */ if (slen) { if (!isanumber) + { + if (strlen(token) > FLEN_VALUE-1) + { + ffpmsg("maxname too long (ffbinr)"); + free(token); + return(*status=PARSE_SYNTAX_ERR); + } strcpy(maxname, token); + } else *maxin = strtod(token, NULL); + free(token); + token=0; } if (**ptr != ':') + { + free(token); return(*status); /* reached the end; no binsize token */ + } (*ptr)++; /* skip the colon between the max and binsize values */ - slen = fits_get_token(ptr, " ,:;", token, &isanumber); /* get token */ + slen = fits_get_token2(ptr, " ,:;", &token, &isanumber, status); /* get token */ + if (*status) + return(*status); /* the token contains the binsize value */ if (slen) { if (!isanumber) + { + if (strlen(token) > FLEN_VALUE-1) + { + ffpmsg("binname too long (ffbinr)"); + free(token); + return(*status=PARSE_SYNTAX_ERR); + } strcpy(binname, token); + } else *binsizein = strtod(token, NULL); + free(token); } return(*status); @@ -935,7 +997,7 @@ > 0) { strcpy(errmsg, "column for histogram axis doesn't exist: "); - strcat(errmsg, colname[ii]); + strncat(errmsg, colname[ii], FLEN_ERRMSG-strlen(errmsg)-1); ffpmsg(errmsg); return(*status); } @@ -947,7 +1009,7 @@ if (repeat > 1) { strcpy(errmsg, "Can't bin a vector column: "); - strcat(errmsg, colname[ii]); + strncat(errmsg, colname[ii],FLEN_ERRMSG-strlen(errmsg)-1); ffpmsg(errmsg); return(*status = BAD_DATATYPE); } @@ -959,7 +1021,7 @@ if (datatype < 0 || datatype == TSTRING) { strcpy(errmsg, "Inappropriate datatype; can't bin this column: "); - strcat(errmsg, colname[ii]); + strncat(errmsg, colname[ii],FLEN_ERRMSG-strlen(errmsg)-1); ffpmsg(errmsg); return(*status = BAD_DATATYPE); } @@ -970,14 +1032,14 @@ if (minin[ii] == DOUBLENULLVALUE) { ffkeyn("TLMIN", histData.hcolnum[ii], keyname, status); - if (ffgky(*fptr, TFLOAT, keyname, amin+ii, NULL, status) > 0) + if (ffgky(*fptr, TFLOAT, keyname, amin+ii, NULL, status) > 0) { /* use actual data minimum value for the histogram minimum */ *status = 0; if (fits_get_col_minmax(*fptr, histData.hcolnum[ii], amin+ii, &datamax, status) > 0) { strcpy(errmsg, "Error calculating datamin and datamax for column: "); - strcat(errmsg, colname[ii]); + strncat(errmsg, colname[ii],FLEN_ERRMSG-strlen(errmsg)-1); ffpmsg(errmsg); return(*status); } @@ -1004,7 +1066,7 @@ if (fits_get_col_minmax(*fptr, histData.hcolnum[ii], &datamin, &amax[ii], status) > 0) { strcpy(errmsg, "Error calculating datamin and datamax for column: "); - strcat(errmsg, colname[ii]); + strncat(errmsg, colname[ii],FLEN_ERRMSG-strlen(errmsg)-1); ffpmsg(errmsg); return(*status); } @@ -1543,7 +1646,7 @@ > 0) { strcpy(errmsg, "column for histogram axis doesn't exist: "); - strcat(errmsg, colname[ii]); + strncat(errmsg, colname[ii],FLEN_ERRMSG-strlen(errmsg)-1); ffpmsg(errmsg); return(*status); } @@ -1558,7 +1661,7 @@ if (repeat > 1) { strcpy(errmsg, "Can't bin a vector column: "); - strcat(errmsg, colname[ii]); + strncat(errmsg, colname[ii],FLEN_ERRMSG-strlen(errmsg)-1); ffpmsg(errmsg); return(*status = BAD_DATATYPE); } @@ -1570,7 +1673,7 @@ if (datatype < 0 || datatype == TSTRING) { strcpy(errmsg, "Inappropriate datatype; can't bin this column: "); - strcat(errmsg, colname[ii]); + strncat(errmsg, colname[ii],FLEN_ERRMSG-strlen(errmsg)-1); ffpmsg(errmsg); return(*status = BAD_DATATYPE); } @@ -1593,19 +1696,19 @@ if (minin[ii] != DOUBLENULLVALUE) { - amin[ii] = (float) minin[ii]; + amin[ii] = (float) minin[ii]; } else { ffkeyn("TLMIN", colnum[ii], keyname, status); - if (ffgky(fptr, TFLOAT, keyname, amin+ii, NULL, status) > 0) + if (ffgky(fptr, TFLOAT, keyname, amin+ii, NULL, status) > 0) { /* use actual data minimum value for the histogram minimum */ *status = 0; if (fits_get_col_minmax(fptr, colnum[ii], amin+ii, &datamax, status) > 0) { strcpy(errmsg, "Error calculating datamin and datamax for column: "); - strcat(errmsg, colname[ii]); + strncat(errmsg, colname[ii],FLEN_ERRMSG-strlen(errmsg)-1); ffpmsg(errmsg); return(*status); } @@ -1645,7 +1748,7 @@ if (fits_get_col_minmax(fptr, colnum[ii], &datamin, &amax[ii], status) > 0) { strcpy(errmsg, "Error calculating datamin and datamax for column: "); - strcat(errmsg, colname[ii]); + strncat(errmsg, colname[ii],FLEN_ERRMSG-strlen(errmsg)-1); ffpmsg(errmsg); return(*status); } diff -ur cfitsio3430/imcompress.c cfitsio3440/imcompress.c --- cfitsio3430/imcompress.c 2018-03-01 17:28:51.000000000 +0100 +++ cfitsio3440/imcompress.c 2018-04-11 16:33:41.000000000 +0200 @@ -162,8 +162,8 @@ static int fits_unshuffle_2bytes(char *heap, LONGLONG length, int *status); static int fits_int_to_longlong_inplace(int *intarray, long length, int *status); -static int fits_short_to_int_inplace(short *intarray, long length, int *status); -static int fits_ushort_to_int_inplace(unsigned short *intarray, long length, int *status); +static int fits_short_to_int_inplace(short *intarray, long length, int shift, int *status); +static int fits_ushort_to_int_inplace(unsigned short *intarray, long length, int shift, int *status); static int fits_sbyte_to_int_inplace(signed char *intarray, long length, int *status); static int fits_ubyte_to_int_inplace(unsigned char *intarray, long length, int *status); @@ -2252,7 +2252,7 @@ } else { /* just do the data type conversion to int */ /* have to convert sbuff to an I*4 array, in place */ /* sbuff must have been allocated large enough to do this */ - fits_short_to_int_inplace(sbuff, tilelen, status); + fits_short_to_int_inplace(sbuff, tilelen, 0, status); } } else { /* have to convert to int if using PLIO */ @@ -2273,10 +2273,10 @@ else idata[ii] = (int) sbuff[ii] + 32768; } - } else { /* just do the data type conversion to int */ + } else { /* have to convert sbuff to an I*4 array, in place */ /* sbuff must have been allocated large enough to do this */ - fits_short_to_int_inplace(sbuff, tilelen, status); + fits_short_to_int_inplace(sbuff, tilelen, 32768, status); } } else { /* This is not an unsigned 16-bit integer array, so process normally */ @@ -2292,7 +2292,7 @@ } else { /* just do the data type conversion to int */ /* have to convert sbuff to an I*4 array, in place */ /* sbuff must have been allocated large enough to do this */ - fits_short_to_int_inplace(sbuff, tilelen, status); + fits_short_to_int_inplace(sbuff, tilelen, 0, status); } } } @@ -2373,9 +2373,15 @@ idata[ii] = ((int) usbuff[ii]) - 32768; } } else { /* just do the data type conversion to int */ - /* have to convert usbuff to an I*4 array, in place */ - /* usbuff must have been allocated large enough to do this */ - fits_ushort_to_int_inplace(usbuff, tilelen, status); + /* for HCOMPRESS we need to simply subtract 32768 */ + /* for PLIO, have to convert usbuff to an I*4 array, in place */ + /* usbuff must have been allocated large enough to do this */ + + if ((outfptr->Fptr)->compress_type == HCOMPRESS_1) { + fits_ushort_to_int_inplace(usbuff, tilelen, -32768, status); + } else { + fits_ushort_to_int_inplace(usbuff, tilelen, 0, status); + } } } @@ -8397,7 +8403,7 @@ cratio[ii] = uncompressed_size / compressed_size; snprintf(tempstring,FLEN_VALUE," r=%6.2f",cratio[ii]); - strcat(results[ii],tempstring); + strncat(results[ii],tempstring, 29-strlen(results[ii])); /* now we just have to compress the array of descriptors (both input and output) */ /* and write them to the output table. */ @@ -8524,7 +8530,7 @@ cratio[ii] = (float) datasize / (float) dlen; /* compression ratio of the column */ snprintf(tempstring,FLEN_VALUE," r=%6.2f",cratio[ii]); - strcat(results[ii],tempstring); + strncat(results[ii],tempstring,29-strlen(results[ii])); } /* end of not a virtual column */ } /* end of loop over columns */ @@ -9508,7 +9514,7 @@ return(*status); } /*--------------------------------------------------------------------------*/ -static int fits_short_to_int_inplace(short *shortarray, long length, int *status) +static int fits_short_to_int_inplace(short *shortarray, long length, int shift, int *status) /* convert the input array of 16-bit integers into an array of 32-bit integers, in place. This will overwrite the input array with the new longer array starting @@ -9549,7 +9555,7 @@ /* do datatype conversion into temp array */ for (ii = 0; ii < ntodo; ii++) { - intarray[ii] = shortarray[ii + firstelem]; + intarray[ii] = (int)(shortarray[ii + firstelem]) + shift; } /* copy temp array back to alias */ @@ -9572,7 +9578,7 @@ } /*--------------------------------------------------------------------------*/ static int fits_ushort_to_int_inplace(unsigned short *ushortarray, long length, - int *status) + int shift, int *status) /* convert the input array of 16-bit unsigned integers into an array of 32-bit integers, in place. This will overwrite the input array with the new longer array starting @@ -9613,7 +9619,7 @@ /* do datatype conversion into temp array */ for (ii = 0; ii < ntodo; ii++) { - intarray[ii] = ushortarray[ii + firstelem]; + intarray[ii] = (int)(ushortarray[ii + firstelem]) + shift; } /* copy temp array back to alias */ diff -ur cfitsio3430/iraffits.c cfitsio3440/iraffits.c --- cfitsio3430/iraffits.c 2018-03-01 17:28:51.000000000 +0100 +++ cfitsio3440/iraffits.c 2018-04-11 16:33:41.000000000 +0200 @@ -1329,6 +1329,8 @@ /* Translate value from ASCII to binary */ if (value != NULL) { minint = -MAXINT - 1; + if (strlen(value) > 29) + return(0); strcpy (val, value); dval = atof (val); if (dval+0.001 > MAXINT) @@ -1372,10 +1374,13 @@ lval = strlen (value); if (lval < lstr) strcpy (str, value); - else if (lstr > 1) + else if (lstr > 1) { strncpy (str, value, lstr-1); - else + str[lstr-1]=0; + } + else { str[0] = value[0]; + } return (1); } else @@ -1422,6 +1427,7 @@ /* Find length of variable name */ strncpy (keyword,keyword0, sizeof(keyword)-1); + keyword[80]=0; brack1 = strsrch (keyword,lbracket); if (brack1 == NULL) brack1 = strsrch (keyword,comma); --- cfitsio3430/modkey.c 2018-03-01 17:28:51.000000000 +0100 +++ cfitsio3440/modkey.c 2018-04-11 16:33:42.000000000 +0200 @@ -754,6 +754,11 @@ contin = 0; while (remain > 0) { + if (nchar > FLEN_VALUE-1) + { + ffpmsg("longstr keyword value is too long (ffmkls)"); + return (*status=BAD_KEYCHAR); + } strncpy(tstring, &value[next], nchar); /* copy string to temp buff */ tstring[nchar] = '\0'; ffs2c(tstring, valstring, status); /* put quotes around the string */ @@ -984,9 +989,19 @@ strcpy(valstring, "(" ); ffr2f(value[0], decim, tmpstring, status); /* convert to string */ + if (strlen(tmpstring)+3 > FLEN_VALUE-1) + { + ffpmsg("complex key value too long (ffmkfc)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ", "); ffr2f(value[1], decim, tmpstring, status); /* convert to string */ + if (strlen(valstring) + strlen(tmpstring)+1 > FLEN_VALUE-1) + { + ffpmsg("complex key value too long (ffmkfc)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ")"); @@ -1019,9 +1034,19 @@ strcpy(valstring, "(" ); ffr2e(value[0], decim, tmpstring, status); /* convert to string */ + if (strlen(tmpstring)+3 > FLEN_VALUE-1) + { + ffpmsg("complex key value too long (ffmkyc)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ", "); ffr2e(value[1], decim, tmpstring, status); /* convert to string */ + if (strlen(valstring) + strlen(tmpstring)+1 > FLEN_VALUE-1) + { + ffpmsg("complex key value too long (ffmkyc)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ")"); @@ -1054,9 +1079,19 @@ strcpy(valstring, "(" ); ffd2f(value[0], decim, tmpstring, status); /* convert to string */ + if (strlen(tmpstring)+3 > FLEN_VALUE-1) + { + ffpmsg("complex key value too long (ffmkfm)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ", "); ffd2f(value[1], decim, tmpstring, status); /* convert to string */ + if (strlen(valstring) + strlen(tmpstring)+1 > FLEN_VALUE-1) + { + ffpmsg("complex key value too long (ffmkfm)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ")"); @@ -1089,9 +1124,19 @@ strcpy(valstring, "(" ); ffd2e(value[0], decim, tmpstring, status); /* convert to string */ + if (strlen(tmpstring)+3 > FLEN_VALUE-1) + { + ffpmsg("complex key value too long (ffmkym)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ", "); ffd2e(value[1], decim, tmpstring, status); /* convert to string */ + if (strlen(valstring) + strlen(tmpstring)+1 > FLEN_VALUE-1) + { + ffpmsg("complex key value too long (ffmkym)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ")"); @@ -1208,6 +1253,11 @@ contin = 0; while (remain > 0) { + if (nchar > FLEN_VALUE-1) + { + ffpmsg("longstr keyword value is too long (ffikls)"); + return (*status=BAD_KEYCHAR); + } strncpy(tstring, &value[next], nchar); /* copy string to temp buff */ tstring[nchar] = '\0'; ffs2c(tstring, valstring, status); /* put quotes around the string */ @@ -1379,9 +1429,19 @@ strcpy(valstring, "(" ); ffr2f(value[0], decim, tmpstring, status); /* convert to string */ + if (strlen(tmpstring)+3 > FLEN_VALUE-1) + { + ffpmsg("complex key value too long (ffikfc)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ", "); ffr2f(value[1], decim, tmpstring, status); /* convert to string */ + if (strlen(valstring) + strlen(tmpstring)+1 > FLEN_VALUE-1) + { + ffpmsg("complex key value too long (ffikfc)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ")"); @@ -1406,9 +1466,19 @@ strcpy(valstring, "(" ); ffr2e(value[0], decim, tmpstring, status); /* convert to string */ + if (strlen(tmpstring)+3 > FLEN_VALUE-1) + { + ffpmsg("complex key value too long (ffikyc)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ", "); ffr2e(value[1], decim, tmpstring, status); /* convert to string */ + if (strlen(valstring) + strlen(tmpstring)+1 > FLEN_VALUE-1) + { + ffpmsg("complex key value too long (ffikyc)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ")"); @@ -1434,9 +1504,19 @@ strcpy(valstring, "(" ); ffd2f(value[0], decim, tmpstring, status); /* convert to string */ + if (strlen(tmpstring)+3 > FLEN_VALUE-1) + { + ffpmsg("complex key value too long (ffikfm)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ", "); ffd2f(value[1], decim, tmpstring, status); /* convert to string */ + if (strlen(valstring) + strlen(tmpstring)+1 > FLEN_VALUE-1) + { + ffpmsg("complex key value too long (ffikfm)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ")"); @@ -1461,9 +1541,19 @@ strcpy(valstring, "(" ); ffd2e(value[0], decim, tmpstring, status); /* convert to string */ + if (strlen(tmpstring)+3 > FLEN_VALUE-1) + { + ffpmsg("complex key value too long (ffikym)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ", "); ffd2e(value[1], decim, tmpstring, status); /* convert to string */ + if (strlen(valstring) + strlen(tmpstring)+1 > FLEN_VALUE-1) + { + ffpmsg("complex key value too long (ffikym)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ")"); @@ -1531,6 +1621,11 @@ keylength = strcspn(buff2, "="); if (keylength == 80) keylength = 8; + /* test for the common commentary keywords which by definition have 8-char names */ + if ( !fits_strncasecmp( "COMMENT ", buff2, 8) || !fits_strncasecmp( "HISTORY ", buff2, 8) || + !fits_strncasecmp( " ", buff2, 8) || !fits_strncasecmp( "CONTINUE", buff2, 8) ) + keylength = 8; + for (ii=0; ii < keylength; ii++) /* make sure keyword name is uppercase */ buff2[ii] = toupper(buff2[ii]); diff -ur cfitsio3430/putcol.c cfitsio3440/putcol.c --- cfitsio3430/putcol.c 2018-03-01 17:28:51.000000000 +0100 +++ cfitsio3440/putcol.c 2018-04-11 16:33:42.000000000 +0200 @@ -855,7 +855,8 @@ */ { col->fptr = fptr; - strcpy(col->colname, colname); + strncpy(col->colname, colname,69); + col->colname[69]=0; col->colnum = 0; /* set column number undefined since name is given */ col->datatype = datatype; col->iotype = iotype; @@ -894,7 +895,8 @@ set iterator column parameter */ { - strcpy(col->colname, colname); + strncpy(col->colname, colname,69); + col->colname[69]=0; col->colnum = 0; /* set column number undefined since name is given */ return(0); } diff -ur cfitsio3430/putkey.c cfitsio3440/putkey.c --- cfitsio3430/putkey.c 2018-03-01 17:28:51.000000000 +0100 +++ cfitsio3440/putkey.c 2018-04-11 16:33:42.000000000 +0200 @@ -724,9 +724,19 @@ strcpy(valstring, "(" ); ffr2e(value[0], decim, tmpstring, status); /* convert to string */ + if (strlen(valstring)+strlen(tmpstring)+2 > FLEN_VALUE-1) + { + ffpmsg("Error converting complex to string (ffpkyc)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ", "); ffr2e(value[1], decim, tmpstring, status); /* convert to string */ + if (strlen(valstring)+strlen(tmpstring)+1 > FLEN_VALUE-1) + { + ffpmsg("Error converting complex to string (ffpkyc)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ")"); @@ -755,9 +765,19 @@ strcpy(valstring, "(" ); ffd2e(value[0], decim, tmpstring, status); /* convert to string */ + if (strlen(valstring)+strlen(tmpstring)+2 > FLEN_VALUE-1) + { + ffpmsg("Error converting complex to string (ffpkym)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ", "); ffd2e(value[1], decim, tmpstring, status); /* convert to string */ + if (strlen(valstring)+strlen(tmpstring)+1 > FLEN_VALUE-1) + { + ffpmsg("Error converting complex to string (ffpkym)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ")"); @@ -786,9 +806,19 @@ strcpy(valstring, "(" ); ffr2f(value[0], decim, tmpstring, status); /* convert to string */ + if (strlen(valstring)+strlen(tmpstring)+2 > FLEN_VALUE-1) + { + ffpmsg("Error converting complex to string (ffpkfc)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ", "); ffr2f(value[1], decim, tmpstring, status); /* convert to string */ + if (strlen(valstring)+strlen(tmpstring)+1 > FLEN_VALUE-1) + { + ffpmsg("Error converting complex to string (ffpkfc)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ")"); @@ -817,9 +847,19 @@ strcpy(valstring, "(" ); ffd2f(value[0], decim, tmpstring, status); /* convert to string */ + if (strlen(valstring)+strlen(tmpstring)+2 > FLEN_VALUE-1) + { + ffpmsg("Error converting complex to string (ffpkfm)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ", "); ffd2f(value[1], decim, tmpstring, status); /* convert to string */ + if (strlen(valstring)+strlen(tmpstring)+1 > FLEN_VALUE-1) + { + ffpmsg("Error converting complex to string (ffpkfm)"); + return(*status=BAD_F2C); + } strcat(valstring, tmpstring); strcat(valstring, ")"); @@ -858,6 +898,11 @@ ffd2f(fraction, 16, fstring, status); /* convert to 16 decimal string */ cptr = strchr(fstring, '.'); /* find the decimal point */ + if (strlen(valstring)+strlen(cptr) > FLEN_VALUE-1) + { + ffpmsg("converted numerical string too long"); + return(*status=BAD_F2C); + } strcat(valstring, cptr); /* append the fraction to the integer */ ffmkky(keyname, valstring, comm, card, status); /* construct the keyword*/ @@ -1990,6 +2035,12 @@ } snprintf(value, 80,"%ld", naxes[ii]); + /* This will either be followed by a ',' or ')'. */ + if (strlen(tdimstr)+strlen(value)+1 > FLEN_VALUE-1) + { + ffpmsg("TDIM string too long (ffptdm)"); + return(*status = BAD_TDIM); + } strcat(tdimstr, value); /* append the axis size */ totalpix *= naxes[ii]; @@ -2087,7 +2138,12 @@ /* sprintf is platform dependent ( %lld, %ld, %I64d ) */ snprintf(value, 80, "%.0f", (double) naxes[ii]); - + + if (strlen(tdimstr)+strlen(value)+1 > FLEN_VALUE-1) + { + ffpmsg("TDIM string too long (ffptdmll)"); + return(*status = BAD_TDIM); + } strcat(tdimstr, value); /* append the axis size */ totalpix *= naxes[ii]; @@ -2464,6 +2520,12 @@ ffkeyn("TBCOL", ii + 1, name, status); ffpkyj(fptr, name, tbcol[ii], comm, status); + if (strlen(tform[ii]) > 29) + { + ffpmsg("Error: ASCII table TFORM code is too long (ffphtb)"); + *status = BAD_TFORM; + break; + } strcpy(tfmt, tform[ii]); /* required TFORMn keyword */ ffupch(tfmt); ffkeyn("TFORM", ii + 1, name, status); @@ -2582,6 +2644,12 @@ ffpkys(fptr, name, ttype[ii], comm, status); } + if (strlen(tform[ii]) > 29) + { + ffpmsg("Error: BIN table TFORM code is too long (ffphbn)"); + *status = BAD_TFORM; + break; + } strcpy(tfmt, tform[ii]); /* required TFORMn keyword */ ffupch(tfmt); @@ -2915,7 +2983,7 @@ return(*status = BAD_DECIM); } - if (sprintf(cval, "%.*f", decim, fval) < 0) + if (snprintf(cval, FLEN_VALUE,"%.*f", decim, fval) < 0) { ffpmsg("Error in ffr2f converting float to string"); *status = BAD_F2C; @@ -2951,7 +3019,7 @@ if (decim < 0) { /* use G format if decim is negative */ - if ( sprintf(cval, "%.*G", -decim, fval) < 0) + if ( snprintf(cval, FLEN_VALUE,"%.*G", -decim, fval) < 0) { ffpmsg("Error in ffr2e converting float to string"); *status = BAD_F2C; @@ -2962,7 +3030,7 @@ if ( !strchr(cval, '.') && strchr(cval,'E') ) { /* reformat value with a decimal point and single zero */ - if ( sprintf(cval, "%.1E", fval) < 0) + if ( snprintf(cval, FLEN_VALUE,"%.1E", fval) < 0) { ffpmsg("Error in ffr2e converting float to string"); *status = BAD_F2C; @@ -2974,7 +3042,7 @@ } else { - if ( sprintf(cval, "%.*E", decim, fval) < 0) + if ( snprintf(cval, FLEN_VALUE,"%.*E", decim, fval) < 0) { ffpmsg("Error in ffr2e converting float to string"); *status = BAD_F2C; @@ -2992,7 +3060,7 @@ ffpmsg("Error in ffr2e: float value is a NaN or INDEF"); *status = BAD_F2C; } - else if ( !strchr(cval, '.') && !strchr(cval,'E') ) + else if ( !strchr(cval, '.') && !strchr(cval,'E') && strlen(cval) < FLEN_VALUE-1 ) { /* add decimal point if necessary to distinquish from integer */ strcat(cval, "."); @@ -3023,7 +3091,7 @@ return(*status = BAD_DECIM); } - if (sprintf(cval, "%.*f", decim, dval) < 0) + if (snprintf(cval, FLEN_VALUE,"%.*f", decim, dval) < 0) { ffpmsg("Error in ffd2f converting double to string"); *status = BAD_F2C; @@ -3059,7 +3127,7 @@ if (decim < 0) { /* use G format if decim is negative */ - if ( sprintf(cval, "%.*G", -decim, dval) < 0) + if ( snprintf(cval, FLEN_VALUE,"%.*G", -decim, dval) < 0) { ffpmsg("Error in ffd2e converting float to string"); *status = BAD_F2C; @@ -3070,7 +3138,7 @@ if ( !strchr(cval, '.') && strchr(cval,'E') ) { /* reformat value with a decimal point and single zero */ - if ( sprintf(cval, "%.1E", dval) < 0) + if ( snprintf(cval, FLEN_VALUE,"%.1E", dval) < 0) { ffpmsg("Error in ffd2e converting float to string"); *status = BAD_F2C; @@ -3082,7 +3150,7 @@ } else { - if ( sprintf(cval, "%.*E", decim, dval) < 0) + if ( snprintf(cval, FLEN_VALUE,"%.*E", decim, dval) < 0) { ffpmsg("Error in ffd2e converting float to string"); *status = BAD_F2C; @@ -3100,7 +3168,7 @@ ffpmsg("Error in ffd2e: double value is a NaN or INDEF"); *status = BAD_F2C; } - else if ( !strchr(cval, '.') && !strchr(cval,'E') ) + else if ( !strchr(cval, '.') && !strchr(cval,'E') && strlen(cval) < FLEN_VALUE-1) { /* add decimal point if necessary to distinquish from integer */ strcat(cval, "."); diff -ur cfitsio3430/windumpexts.c cfitsio3440/windumpexts.c --- cfitsio3430/windumpexts.c 2018-03-01 17:28:51.000000000 +0100 +++ cfitsio3440/windumpexts.c 2018-04-11 16:33:42.000000000 +0200 @@ -232,7 +232,8 @@ symbol[8] = 0; } else { s = stringTable + pSymbolTable->N.Name.Long; - strcpy(symbol, s); + strncpy(symbol, s, 1023); + symbol[1023]=0; } s = symbol; f = strchr(s, '@'); @@ -485,7 +486,8 @@ } pos = 0; for (i = 0; i < arg; i++) { - strcpy(&cmdline[pos], argv[i]); + strncpy(&cmdline[pos], argv[i], 9999-pos); + cmdline[9999]=0; pos += strlen(&cmdline[pos]) + 1; fargv[i] = argv[i]; }