Changeset 1524


Ignore:
Timestamp:
Mar 5, 2007, 12:07:48 AM (15 years ago)
Author:
joshe
Message:

Better checking of metainfo.
Strip / out of filenames and path components.
Safely handle . and .. in file paths.

Location:
trunk/libtransmission
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/bencode.c

    r1444 r1524  
    215215}
    216216
    217 benc_val_t * tr_bencDictFind( benc_val_t * val, char * key )
     217benc_val_t * tr_bencDictFind( benc_val_t * val, const char * key )
    218218{
    219219    int i;
     
    232232
    233233    return NULL;
     234}
     235
     236benc_val_t * tr_bencDictFindFirst( benc_val_t * val, ... )
     237{
     238    const char * key;
     239    benc_val_t * ret;
     240    va_list      ap;
     241
     242    va_start( ap, val );
     243    while( ( key = va_arg( ap, const char * ) ) )
     244    {
     245        ret = tr_bencDictFind( val, key );
     246        if( NULL != ret )
     247        {
     248            break;
     249        }
     250    }
     251    va_end( ap );
     252
     253    return ret;
    234254}
    235255
  • trunk/libtransmission/bencode.h

    r920 r1524  
    5757void         tr_bencPrint( benc_val_t * val );
    5858void         tr_bencFree( benc_val_t * val );
    59 benc_val_t * tr_bencDictFind( benc_val_t * val, char * key );
     59benc_val_t * tr_bencDictFind( benc_val_t * val, const char * key );
     60benc_val_t * tr_bencDictFindFirst( benc_val_t * val, ... );
    6061char *       tr_bencSaveMalloc( benc_val_t * val, int * len );
    6162int          tr_bencSave( benc_val_t * val, char ** buf,
  • trunk/libtransmission/metainfo.c

    r1517 r1524  
    3030 * Local prototypes
    3131 **********************************************************************/
     32static int getfile( char * buf, int size,
     33                    const char * prefix, const benc_val_t * name );
    3234static int getannounce( tr_info_t * inf, benc_val_t * meta );
    3335static char * announceToScrape( const char * announce );
    34 #define strcatUTF8( dst, src) _strcatUTF8( (dst), sizeof( dst ) - 1, (src) )
    35 static void _strcatUTF8( char *, int, char * );
     36static void strcatUTF8( char *, int, const char *, int );
    3637
    3738/***********************************************************************
     
    103104
    104105    /* Get info hash */
    105     if( !( beInfo = tr_bencDictFind( &meta, "info" ) ) )
    106     {
    107         tr_err( "Could not find \"info\" dictionary" );
     106    beInfo = tr_bencDictFind( &meta, "info" );
     107    if( NULL == beInfo || TYPE_DICT != beInfo->type )
     108    {
     109        tr_err( "%s \"info\" dictionary", ( beInfo ? "Invalid" : "Missing" ) );
    108110        tr_bencFree( &meta );
    109111        free( buf );
     
    151153       
    152154    /* Comment info */
    153     if( ( val = tr_bencDictFind( &meta, "comment.utf-8" ) ) || ( val = tr_bencDictFind( &meta, "comment" ) ) )
    154     {
    155         strcatUTF8( inf->comment, val->val.s.s );
     155    val = tr_bencDictFindFirst( &meta, "comment.utf-8", "comment", NULL );
     156    if( NULL != val && TYPE_STR == val->type )
     157    {
     158        strcatUTF8( inf->comment, sizeof( inf->comment ), val->val.s.s, 0 );
    156159    }
    157160   
    158161    /* Creator info */
    159     if( ( val = tr_bencDictFind( &meta, "created by.utf-8" ) ) || ( val = tr_bencDictFind( &meta, "created by" ) ) )
    160     {
    161         strcatUTF8( inf->creator, val->val.s.s );
     162    tr_bencDictFindFirst( &meta, "created by.utf-8", "created by", NULL );
     163    if( NULL != val && TYPE_STR == val->type )
     164    {
     165        strcatUTF8( inf->creator, sizeof( inf->creator ), val->val.s.s, 0 );
    162166    }
    163167   
    164168    /* Date created */
    165     if( ( val = tr_bencDictFind( &meta, "creation date" ) ) )
     169    inf->dateCreated = 0;
     170    val = tr_bencDictFind( &meta, "creation date" );
     171    if( NULL != val && TYPE_INT == val->type )
    166172    {
    167173        inf->dateCreated = val->val.i;
    168174    }
    169     else
    170     {
    171         inf->dateCreated = 0;
    172     }
    173175   
    174176    /* Private torrent */
    175     if( ( NULL != ( val = tr_bencDictFind( beInfo, "private" ) ) &&
    176           TYPE_INT == val->type && val->val.i ) ||
    177         ( NULL != ( val = tr_bencDictFind( &meta, "private" ) ) &&
    178           TYPE_INT == val->type && val->val.i ) )
     177    if( tr_bencDictFind( beInfo, "private" ) ||
     178        tr_bencDictFind( &meta, "private" ) )
    179179    {
    180180        inf->flags |= TR_FLAG_PRIVATE;
     
    182182   
    183183    /* Piece length */
    184     if( !( val = tr_bencDictFind( beInfo, "piece length" ) ) )
    185     {
    186         tr_err( "No \"piece length\" entry" );
    187         tr_bencFree( &meta );
    188         return 1;
     184    val = tr_bencDictFind( beInfo, "piece length" );
     185    if( NULL == val || TYPE_INT != val->type )
     186    {
     187        tr_err( "%s \"piece length\" entry", ( val ? "Invalid" : "Missing" ) );
     188        goto fail;
    189189    }
    190190    inf->pieceSize = val->val.i;
     
    192192    /* Hashes */
    193193    val = tr_bencDictFind( beInfo, "pieces" );
     194    if( NULL == val || TYPE_STR != val->type )
     195    {
     196        tr_err( "%s \"pieces\" entry", ( val ? "Invalid" : "Missing" ) );
     197        goto fail;
     198    }
    194199    if( val->val.s.i % SHA_DIGEST_LENGTH )
    195200    {
    196201        tr_err( "Invalid \"piece\" string (size is %d)", val->val.s.i );
    197         tr_bencFree( &meta );
    198         return 1;
     202        goto fail;
    199203    }
    200204    inf->pieceCount = val->val.s.i / SHA_DIGEST_LENGTH;
     
    204208    /* TODO add more tests so we don't crash on weird files */
    205209
     210    /* get file or top directory name */
     211    val = tr_bencDictFindFirst( beInfo, "name.utf-8", "name", NULL );
     212    if( NULL == val || TYPE_STR != val->type )
     213    {
     214        tr_err( "%s \"name\" string", ( val ? "Invalid" : "Missing" ) );
     215        goto fail;
     216    }
     217    strcatUTF8( inf->name, sizeof( inf->name ), val->val.s.s, 1 );
    206218    inf->totalSize = 0;
     219
    207220    if( ( list = tr_bencDictFind( beInfo, "files" ) ) )
    208221    {
    209222        /* Multi-file mode */
    210         int j;
    211 
    212         val = tr_bencDictFind( beInfo, "name.utf-8" );
    213         if( NULL == val )
    214         {
    215             val = tr_bencDictFind( beInfo, "name" );
    216         }
    217         strcatUTF8( inf->name, val->val.s.s );
    218 
    219223        inf->multifile = 1;
    220224        inf->fileCount = list->val.l.count;
     
    223227        for( i = 0; i < list->val.l.count; i++ )
    224228        {
    225             val = tr_bencDictFind( &list->val.l.vals[i], "path.utf-8" );
    226             if( NULL == val )
    227             {
    228                 val = tr_bencDictFind( &list->val.l.vals[i], "path" );
    229             }
    230             strcatUTF8( inf->files[i].name, inf->name );
    231             for( j = 0; j < val->val.l.count; j++ )
    232             {
    233                 strcatUTF8( inf->files[i].name, "/" );
    234                 strcatUTF8( inf->files[i].name,
    235                             val->val.l.vals[j].val.s.s );
     229            val = tr_bencDictFindFirst( &list->val.l.vals[i],
     230                                        "path.utf-8", "path", NULL );
     231            if( getfile( inf->files[i].name, sizeof( inf->files[i].name ),
     232                         inf->name, val ) )
     233            {
     234                tr_err( "%s \"path\" entry", ( val ? "Invalid" : "Missing" ) );
     235                goto fail;
    236236            }
    237237            val = tr_bencDictFind( &list->val.l.vals[i], "length" );
     
    239239            inf->totalSize       += val->val.i;
    240240        }
    241 
    242241    }
    243242    else
     
    248247        inf->files     = calloc( sizeof( tr_file_t ), 1 );
    249248
    250         val = tr_bencDictFind( beInfo, "name.utf-8" );
    251         if( NULL == val )
    252         {
    253             val = tr_bencDictFind( beInfo, "name" );
    254         }
    255         strcatUTF8( inf->files[0].name, val->val.s.s );
    256         strcatUTF8( inf->name, val->val.s.s );
     249        strcatUTF8( inf->files[0].name, sizeof( inf->files[0].name),
     250                    val->val.s.s, 1 );
    257251       
    258252        val = tr_bencDictFind( beInfo, "length" );
     253        if( NULL == val || TYPE_INT != val->type )
     254        {
     255            tr_err( "%s \"length\" entry", ( val ? "Invalid" : "Missing" ) );
     256            goto fail;
     257        }
    259258        inf->files[0].length  = val->val.i;
    260259        inf->totalSize       += val->val.i;
     
    265264    {
    266265        tr_err( "Size of hashes and files don't match" );
    267         tr_metainfoFree( inf );
    268         tr_bencFree( &meta );
    269         return 1;
     266        goto fail;
    270267    }
    271268
     
    273270    if( getannounce( inf, &meta ) )
    274271    {
    275         tr_metainfoFree( inf );
    276         tr_bencFree( &meta );
    277         return 1;
     272        goto fail;
    278273    }
    279274
    280275    tr_bencFree( &meta );
    281276    return 0;
     277
     278  fail:
     279    tr_metainfoFree( inf );
     280    tr_bencFree( &meta );
     281    return 1;
    282282}
    283283
     
    300300    }
    301301    free( inf->trackerList );
     302}
     303
     304static int getfile( char * buf, int size,
     305                    const char * prefix, const benc_val_t * name )
     306{
     307    const benc_val_t * dir;
     308    const char      ** list;
     309    int                ii, jj;
     310
     311    if( TYPE_LIST != name->type )
     312    {
     313        return 1;
     314    }
     315
     316    list = calloc( name->val.l.count, sizeof( list[0] ) );
     317    if( NULL == list )
     318    {
     319        return 1;
     320    }
     321
     322    for( ii = jj = 0; name->val.l.count > ii; ii++ )
     323    {
     324        if( TYPE_STR != name->val.l.vals[ii].type )
     325        {
     326            continue;
     327        }
     328        dir = &name->val.l.vals[ii];
     329        if( 0 == strcmp( "..", dir->val.s.s ) )
     330        {
     331            if( 0 < jj )
     332            {
     333                jj--;
     334            }
     335        }
     336        else if( 0 != strcmp( ".", dir->val.s.s ) )
     337        {
     338            list[jj] = dir->val.s.s;
     339            jj++;
     340        }
     341    }
     342
     343    if( 0 == jj )
     344    {
     345        return 1;
     346    }
     347
     348    strcatUTF8( buf, size, prefix, 0 );
     349    for( ii = 0; jj > ii; ii++ )
     350    {
     351        strcatUTF8( buf, size, "/", 0 );
     352        strcatUTF8( buf, size, list[ii], 1 );
     353    }
     354    free( list );
     355
     356    return 0;
    302357}
    303358
     
    475530#define WANTBYTES( want, got ) \
    476531    if( (want) > (got) ) { return; } else { (got) -= (want); }
    477 static void _strcatUTF8( char * s, int len, char * append )
     532static void strcatUTF8( char * s, int len, const char * append, int deslash )
    478533{
    479     char * p;
     534    const char * p;
     535
     536    /* don't overwrite the nul at the end */
     537    len--;
    480538
    481539    /* Go to the end of the destination string */
     
    489547    for( p = append; p[0]; )
    490548    {
     549        /* skip over / if requested */
     550        if( deslash && '/' == p[0] )
     551        {
     552            p++;
     553            continue;
     554        }
     555
    491556        if( !( p[0] & 0x80 ) )
    492557        {
Note: See TracChangeset for help on using the changeset viewer.