]>
git.saurik.com Git - apt.git/blob - apt-pkg/contrib/gpgv.cc 
   1  // -*- mode: cpp; mode: fold -*-    2  // Include Files                                                        /*{{{*/    5  #include<apt-pkg/configuration.h>    6  #include<apt-pkg/error.h>    7  #include<apt-pkg/strutl.h>    8  #include<apt-pkg/fileutl.h>    9  #include<apt-pkg/gpgv.h>   27  static char  *  GenerateTemporaryFileTemplate ( const char  * basename
)        /*{{{*/   30     std :: string tmpdir 
=  GetTempDir ();   31     strprintf ( out
,   " %s / %s .XXXXXX" ,  tmpdir
. c_str (),  basename
);   32     return  strdup ( out
. c_str ());   35  // ExecGPGV - returns the command needed for verify                     /*{{{*/   36  // ---------------------------------------------------------------------   37  /* Generating the commandline for calling gpg is somehow complicated as   38     we need to add multiple keyrings and user supplied options.   39     Also, as gpg has no options to enforce a certain reduced style of   40     clear-signed files (=the complete content of the file is signed and   41     the content isn't encoded) we do a divide and conquer approach here   42     and split up the clear-signed file in message and signature for gpg.   43     And as a cherry on the cake, we use our apt-key wrapper to do part   44     of the lifting in regards to merging keyrings. Fun for the whole family.   46  void  ExecGPGV ( std :: string 
const  & File
,  std :: string 
const  & FileGPG
,   47               int const  & statusfd
,  int  fd
[ 2 ],  std :: string 
const  & key
)   50     std :: string 
const  aptkey 
=  _config
-> FindFile ( "Dir::Bin::apt-key" ,  "/usr/bin/apt-key" );   52     bool const  Debug 
=  _config
-> FindB ( "Debug::Acquire::gpgv" ,  false );   54     std :: vector
< const char  *>  Args
;   57     Args
. push_back ( aptkey
. c_str ());   58     Args
. push_back ( "--quiet" );   59     Args
. push_back ( "--readonly" );   60     if  ( key
. empty () ==  false )   64           Args
. push_back ( "--keyring" );   65           Args
. push_back ( key
. c_str ());   69           Args
. push_back ( "--keyid" );   70           Args
. push_back ( key
. c_str ());   73     Args
. push_back ( "verify" );   78        Args
. push_back ( "--status-fd" );   79        snprintf ( statusfdstr
,  sizeof ( statusfdstr
),  " %i " ,  statusfd
);   80        Args
. push_back ( statusfdstr
);   83     Configuration :: Item 
const  * Opts
;   84     Opts 
=  _config
-> Tree ( "Acquire::gpgv::Options" );   88        for  (;  Opts 
!=  0 ;  Opts 
=  Opts
-> Next
)   90           if  ( Opts
-> Value
. empty () ==  true )   92           Args
. push_back ( Opts
-> Value
. c_str ());   96     enum   {  DETACHED
,  CLEARSIGNED 
}  releaseSignature 
= ( FileGPG 
!=  File
) ?  DETACHED 
:  CLEARSIGNED
;   97     std :: vector
< std :: string
>  dataHeader
;  101     if  ( releaseSignature 
==  DETACHED
)  103        Args
. push_back ( FileGPG
. c_str ());  104        Args
. push_back ( File
. c_str ());  106     else  // clear-signed file  108        sig 
=  GenerateTemporaryFileTemplate ( "apt.sig" );  109        data 
=  GenerateTemporaryFileTemplate ( "apt.data" );  110        if  ( sig 
==  NULL 
||  data 
==  NULL
)  112           ioprintf ( std :: cerr
,  "Couldn't create tempfile names for splitting up  %s " ,  File
. c_str ());  116        int const  sigFd 
=  mkstemp ( sig
);  117        int const  dataFd 
=  mkstemp ( data
);  118        if  ( sigFd 
== - 1  ||  dataFd 
== - 1 )  124           ioprintf ( std :: cerr
,  "Couldn't create tempfiles for splitting up  %s " ,  File
. c_str ());  129        signature
. OpenDescriptor ( sigFd
,  FileFd :: WriteOnly
,  true );  131        message
. OpenDescriptor ( dataFd
,  FileFd :: WriteOnly
,  true );  133        if  ( signature
. Failed () ==  true  ||  message
. Failed () ==  true  ||  134              SplitClearSignedFile ( File
, & message
, & dataHeader
, & signature
) ==  false )  140           ioprintf ( std :: cerr
,  "Splitting up  %s  into data and signature failed" ,  File
. c_str ());  144        Args
. push_back ( data
);  147     Args
. push_back ( NULL
);  151        std :: clog 
<<  "Preparing to exec: " ;  152        for  ( std :: vector
< const char  *>:: const_iterator a 
=  Args
. begin (); * a 
!=  NULL
; ++ a
)  153           std :: clog 
<<  " "  << * a
;  154        std :: clog 
<<  std :: endl
;  159        int const  nullfd 
=  open ( "/dev/null" ,  O_WRONLY
);  161        // Redirect output to /dev/null; we read from the status fd  162        if  ( statusfd 
!=  STDOUT_FILENO
)  163           dup2 ( nullfd
,  STDOUT_FILENO
);  164        if  ( statusfd 
!=  STDERR_FILENO
)  165           dup2 ( nullfd
,  STDERR_FILENO
);  166        // Redirect the pipe to the status fd (3)  167        dup2 ( fd
[ 1 ],  statusfd
);  169        putenv (( char  *) "LANG=" );  170        putenv (( char  *) "LC_ALL=" );  171        putenv (( char  *) "LC_MESSAGES=" );  174     if  ( releaseSignature 
==  DETACHED
)  176        execvp ( Args
[ 0 ], ( char  **) & Args
[ 0 ]);  177        ioprintf ( std :: cerr
,  "Couldn't execute  %s  to check  %s " ,  Args
[ 0 ],  File
. c_str ());  182  //#define UNLINK_EXIT(X) exit(X)  183  #define UNLINK_EXIT(X) unlink(sig);unlink(data);exit(X)  185        // for clear-signed files we have created tempfiles we have to clean up  186        // and we do an additional check, so fork yet another time …  187        pid_t pid 
=  ExecFork ();  189           ioprintf ( std :: cerr
,  "Fork failed for  %s  to check  %s " ,  Args
[ 0 ],  File
. c_str ());  190           UNLINK_EXIT ( EINTERNAL
);  195              dup2 ( fd
[ 1 ],  statusfd
);  196           execvp ( Args
[ 0 ], ( char  **) & Args
[ 0 ]);  197           ioprintf ( std :: cerr
,  "Couldn't execute  %s  to check  %s " ,  Args
[ 0 ],  File
. c_str ());  198           UNLINK_EXIT ( EINTERNAL
);  201        // Wait and collect the error code - taken from WaitPid as we need the exact Status  203        while  ( waitpid ( pid
,& Status
, 0 ) !=  pid
)  207           ioprintf ( std :: cerr
,  _ ( "Waited for  %s  but it wasn't there" ),  "apt-key" );  208           UNLINK_EXIT ( EINTERNAL
);  211        // we don't need the files any longer  217        // check if it exit'ed normally …  218        if  ( WIFEXITED ( Status
) ==  false )  220           ioprintf ( std :: cerr
,  _ ( "Sub-process  %s  exited unexpectedly" ),  "apt-key" );  224        // … and with a good exit code  225        if  ( WEXITSTATUS ( Status
) !=  0 )  227           ioprintf ( std :: cerr
,  _ ( "Sub-process  %s  returned an error code ( %u )" ),  "apt-key" ,  WEXITSTATUS ( Status
));  228           exit ( WEXITSTATUS ( Status
));  234     exit ( EINTERNAL
);  // unreachable safe-guard  237  // SplitClearSignedFile - split message into data/signature             /*{{{*/  238  bool  SplitClearSignedFile ( std :: string 
const  & InFile
,  FileFd 
*  const  ContentFile
,  239        std :: vector
< std :: string
> *  const  ContentHeader
,  FileFd 
*  const  SignatureFile
)  241     FILE  * in 
=  fopen ( InFile
. c_str (),  "r" );  243        return  _error
-> Errno ( "fopen" ,  "can not open  %s " ,  InFile
. c_str ());  245     bool  found_message_start 
=  false ;  246     bool  found_message_end 
=  false ;  247     bool  skip_until_empty_line 
=  false ;  248     bool  found_signature 
=  false ;  249     bool  first_line 
=  true ;  253     while  ( getline (& buf
, & buf_size
,  in
) != - 1 )  256        if  ( found_message_start 
==  false )  258           if  ( strcmp ( buf
,  "-----BEGIN PGP SIGNED MESSAGE-----" ) ==  0 )  260              found_message_start 
=  true ;  261              skip_until_empty_line 
=  true ;  264        else if  ( skip_until_empty_line 
==  true )  266           if  ( strlen ( buf
) ==  0 )  267              skip_until_empty_line 
=  false ;  268           // save "Hash" Armor Headers, others aren't allowed  269           else if  ( ContentHeader 
!=  NULL 
&&  strncmp ( buf
,  "Hash: " ,  strlen ( "Hash: " )) ==  0 )  270              ContentHeader
-> push_back ( buf
);  272        else if  ( found_signature 
==  false )  274           if  ( strcmp ( buf
,  "-----BEGIN PGP SIGNATURE-----" ) ==  0 )  276              found_signature 
=  true ;  277              found_message_end 
=  true ;  278              if  ( SignatureFile 
!=  NULL
)  280                 SignatureFile
-> Write ( buf
,  strlen ( buf
));  281                 SignatureFile
-> Write ( " \n " ,  1 );  284           else if  ( found_message_end 
==  false )  // we are in the message block  286              // we don't have any fields which need dash-escaped,  287              // but implementations are free to encode all lines …  288              char const  *  dashfree 
=  buf
;  289              if  ( strncmp ( dashfree
,  "- " ,  2 ) ==  0 )  291              if ( first_line 
==  true )  // first line does not need a newline  293              else if  ( ContentFile 
!=  NULL
)  294                 ContentFile
-> Write ( " \n " ,  1 );  297              if  ( ContentFile 
!=  NULL
)  298                 ContentFile
-> Write ( dashfree
,  strlen ( dashfree
));  301        else if  ( found_signature 
==  true )  303           if  ( SignatureFile 
!=  NULL
)  305              SignatureFile
-> Write ( buf
,  strlen ( buf
));  306              SignatureFile
-> Write ( " \n " ,  1 );  308           if  ( strcmp ( buf
,  "-----END PGP SIGNATURE-----" ) ==  0 )  309              found_signature 
=  false ;  // look for other signatures  311        // all the rest is whitespace, unsigned garbage or additional message blocks we ignore  317     if  ( found_signature 
==  true )  318        return  _error
-> Error ( "Signature in file  %s  wasn't closed" ,  InFile
. c_str ());  320     // if we haven't found any of them, this an unsigned file,  321     // so don't generate an error, but splitting was unsuccessful none-the-less  322     if  ( first_line 
==  true  &&  found_message_start 
==  false  &&  found_message_end 
==  false )  324     // otherwise one missing indicates a syntax error  325     else if  ( first_line 
==  true  ||  found_message_start 
==  false  ||  found_message_end 
==  false )  326       return  _error
-> Error ( "Splitting of file  %s  failed as it doesn't contain all expected parts  %i %i %i " ,  InFile
. c_str (),  first_line
,  found_message_start
,  found_message_end
);  331  bool  OpenMaybeClearSignedFile ( std :: string 
const  & ClearSignedFileName
,  FileFd 
& MessageFile
)  /*{{{*/  333     char  *  const  message 
=  GenerateTemporaryFileTemplate ( "fileutl.message" );  334     int const  messageFd 
=  mkstemp ( message
);  338        return  _error
-> Errno ( "mkstemp" ,  "Couldn't create temporary file to work with  %s " ,  ClearSignedFileName
. c_str ());  340     // we have the fd, thats enough for us  344     MessageFile
. OpenDescriptor ( messageFd
,  FileFd :: ReadWrite
,  true );  345     if  ( MessageFile
. Failed () ==  true )  346        return  _error
-> Error ( "Couldn't open temporary file to work with  %s " ,  ClearSignedFileName
. c_str ());  348     _error
-> PushToStack ();  349     bool const  splitDone 
=  SplitClearSignedFile ( ClearSignedFileName
, & MessageFile
,  NULL
,  NULL
);  350     bool const  errorDone 
=  _error
-> PendingError ();  351     _error
-> MergeWithStack ();  352     if  ( splitDone 
==  false )  356        if  ( errorDone 
==  true )  359        // we deal with an unsigned file  360        MessageFile
. Open ( ClearSignedFileName
,  FileFd :: ReadOnly
);  364        if  ( MessageFile
. Seek ( 0 ) ==  false )  365           return  _error
-> Errno ( "lseek" ,  "Unable to seek back in message for file  %s " ,  ClearSignedFileName
. c_str ());  368     return  MessageFile
. Failed () ==  false ;