--- ctm/ctm_pass3.c.ORI 2025-08-10 16:21:45.923332000 +0000 +++ ctm/ctm_pass3.c 2025-08-14 07:29:01.065066000 +0000 @@ -203,6 +203,8 @@ case CTM_F_Targetname: //GETNAMECOPY( targetname, sep, j, Verbose ); GETFIELDCOPY( targetname, sep ); + if( FnameDecode( targetname ) ) + return BADREAD; break; default: WRONG } --- ctm/ctm_input.c.ORI 2025-08-10 16:21:45.852199000 +0000 +++ ctm/ctm_input.c 2025-08-14 07:30:26.721303000 +0000 @@ -14,6 +14,38 @@ #include "ctm.h" +u_char FnameDecode( u_char* in ) +{ + u_char* o = in; + + // Return OK if this no encoded name + // + if( *in++ != '/' ) + return 0; + + + // Copy name, unescaping chars + // + while( 1 ) { + + if( (*o = *in++) == '\0' ) // copy char and return OK + return 0; + + if( *o++ != '%' ) // no magic, next char + continue; + + o--; // "delete" magic + + if( (*o = *in++) == '\0' ) { // no char after magic + Fatal( "Badly encoded filename." ); + return 1; // return BAD + } + + *o++ -= 0x20; // decode + } +} + + /*---------------------------------------------------------------------------*/ void Fatal_(int ln, char *fn, char *kind) @@ -152,6 +184,9 @@ struct stat st; if ((p = Ffield(fd,ctx,term)) == NULL) return(NULL); + + if( FnameDecode( p ) ) + return NULL; strcpy(CatPtr, p); --- ctm/ctm.h.ORI 2025-08-10 16:21:45.922547000 +0000 +++ ctm/ctm.h 2025-08-14 07:00:34.944434000 +0000 @@ -153,6 +153,7 @@ u_char * Ffield(FILE *fd, MD5_CTX *ctx,u_char term); u_char * Fname(FILE *fd, MD5_CTX *ctx,u_char term,int qual, int verbose); +u_char FnameDecode( u_char* n ); intmax_t Fbytecnt(FILE *fd, MD5_CTX *ctx, u_char term); --- ctm/ctm_pass1.c.ORI 2025-08-10 16:21:45.922914000 +0000 +++ ctm/ctm_pass1.c 2025-08-14 07:28:32.124418000 +0000 @@ -112,6 +112,8 @@ switch (j & CTM_F_MASK) { case CTM_F_Name: /* XXX check for garbage and .. */ GETFIELDCOPY(name,sep); + if( FnameDecode( name ) ) + return BADREAD; j = strlen(name); if(name[j-1] == '/' && !slashwarn) { fprintf(stderr,"Warning: contains trailing slash\n"); @@ -229,6 +231,8 @@ break; case CTM_F_Targetname: GETFIELDCOPY( targetname, sep ); + if( FnameDecode( targetname ) ) + return BADREAD; break; default: fprintf(stderr,"List = 0x%x\n",j); --- ctm/ctm_passb.c.ORI 2025-08-10 16:21:45.923530000 +0000 +++ ctm/ctm_passb.c 2025-08-14 07:29:29.050430000 +0000 @@ -92,7 +92,11 @@ break; case CTM_F_Count: GETBYTECNT(cnt,sep); break; case CTM_F_Bytes: GETDATA(trash,cnt); break; - case CTM_F_Targetname: GETFIELDCOPY( targetname, sep ); break; + case CTM_F_Targetname: + GETFIELDCOPY( targetname, sep ); + if( FnameDecode( targetname ) ) + return BADREAD; + break; default: WRONG } }