00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
#include <kdebug.h>
00020
00021
#include <config.h>
00022
00023
#include "kpgpbase.h"
00024
#include "kpgp.h"
00025
#include "kpgpblock.h"
00026
00027
#include <stdlib.h>
00028
#include <unistd.h>
00029
#include <sys/poll.h>
00030
#include <sys/types.h>
00031
#include <sys/wait.h>
00032
#include <errno.h>
00033
00034
#include <qapplication.h>
00035
00036
00037
namespace Kpgp {
00038
00039 Base::Base()
00040 : input(), output(), error(), errMsg(), status(OK)
00041 {
00042 }
00043
00044
00045 Base::~Base()
00046 {
00047 }
00048
00049
00050
void
00051 Base::clear()
00052 {
00053 input =
QCString();
00054 output = QCString();
00055 error = QCString();
00056 errMsg = QString::null;
00057 status = OK;
00058 }
00059
00060
00061
int
00062 Base::run(
const char *cmd,
const char *passphrase,
bool onlyReadFromPGP )
00063 {
00064
00065
00066
00067
00068
char str[1025] =
"\0";
00069
int pin[2], pout[2], perr[2], ppass[2];
00070
int len, len2;
00071 FILE *pass;
00072 pid_t child_pid;
00073
int childExitStatus;
00074
struct pollfd pollin, pollout, pollerr;
00075
int pollstatus;
00076
00077
if(passphrase)
00078 {
00079 pipe(ppass);
00080
00081 pass = fdopen(ppass[1],
"w");
00082 fwrite(passphrase,
sizeof(
char), strlen(passphrase), pass);
00083 fwrite(
"\n",
sizeof(
char), 1, pass);
00084 fclose(pass);
00085 close(ppass[1]);
00086
00087
00088
QCString tmp;
00089 tmp.sprintf(
"%d",ppass[0]);
00090 ::setenv(
"PGPPASSFD",tmp.data(),1);
00091
00092
00093
00094
00095 }
00096 else
00097 ::unsetenv(
"PGPPASSFD");
00098
00099
00100 kdDebug(5100) <<
"pgp cmd = " << cmd << endl;
00101
00102
00103
00104 error =
"";
00105 output =
"";
00106
00107 pipe(pin);
00108 pipe(pout);
00109 pipe(perr);
00110
00111 QApplication::flushX();
00112
if(!(child_pid = fork()))
00113 {
00114
00115 close(pin[1]);
00116 dup2(pin[0], 0);
00117 close(pin[0]);
00118
00119 close(pout[0]);
00120 dup2(pout[1], 1);
00121 close(pout[1]);
00122
00123 close(perr[0]);
00124 dup2(perr[1], 2);
00125 close(perr[1]);
00126
00127 execl(
"/bin/sh",
"sh",
"-c", cmd, (
void *)0);
00128 _exit(127);
00129 }
00130
00131
00132 close(pin[0]);
00133 close(pout[1]);
00134 close(perr[1]);
00135
00136
00137 pollout.fd = pout[0];
00138 pollout.events = POLLIN;
00139 pollerr.fd = perr[0];
00140 pollerr.events = POLLIN;
00141
00142
00143 pollin.fd = pin[1];
00144 pollin.events = POLLOUT;
00145
00146
if (!onlyReadFromPGP) {
00147
if (!input.isEmpty()) {
00148
00149
for (
unsigned int i=0; i<input.length(); i+=len2) {
00150 len2 = 0;
00151
00152
00153
00154 pollstatus = poll(&pollin, 1, 5);
00155
if (pollstatus == 1) {
00156
00157
if (pollin.revents & POLLERR) {
00158 kdDebug(5100) <<
"PGP seems to have hung up" << endl;
00159
break;
00160 }
00161
else if (pollin.revents & POLLOUT) {
00162
00163
if ((len2 = input.find(
'\n', i)) == -1)
00164 len2 = input.length()-i;
00165
else
00166 len2 = len2-i+1;
00167
00168
00169 len2 = write(pin[1], input.mid(i,len2).data(), len2);
00170
00171 }
00172 }
00173
else if (!pollstatus) {
00174
00175
00176 }
00177
else if (pollstatus == -1) {
00178 kdDebug(5100) <<
"Error while polling pin[1]: "
00179 << pollin.revents << endl;
00180 }
00181
00182
if (pout[0] >= 0) {
00183
do {
00184
00185
00186 pollstatus = poll(&pollout, 1, 0);
00187
if (pollstatus == 1) {
00188
00189
if (pollout.revents & POLLIN) {
00190
00191
if ((len = read(pout[0],str,1024))>0) {
00192
00193 str[len] =
'\0';
00194 output += str;
00195 }
00196
else
00197
break;
00198 }
00199 }
00200
else if (pollstatus == -1) {
00201 kdDebug(5100) <<
"Error while polling pout[0]: "
00202 << pollout.revents << endl;
00203 }
00204 }
while ((pollstatus == 1) && (pollout.revents & POLLIN));
00205 }
00206
00207
if (perr[0] >= 0) {
00208
do {
00209
00210
00211 pollstatus = poll(&pollerr, 1, 0);
00212
if (pollstatus == 1) {
00213
00214
if (pollerr.revents & POLLIN) {
00215
00216
if ((len = read(perr[0],str,1024))>0) {
00217
00218 str[len] =
'\0';
00219 error += str;
00220 }
00221
else
00222
break;
00223 }
00224 }
00225
else if (pollstatus == -1) {
00226 kdDebug(5100) <<
"Error while polling perr[0]: "
00227 << pollerr.revents << endl;
00228 }
00229 }
while ((pollstatus == 1) && (pollerr.revents & POLLIN));
00230 }
00231
00232
00233
if ((pollstatus == 1) &&
00234 ((pollout.revents & POLLHUP) || (pollerr.revents & POLLHUP))) {
00235 kdDebug(5100) <<
"PGP hung up" << endl;
00236
break;
00237 }
00238 }
00239 }
00240
else
00241 write(pin[1],
"\n", 1);
00242
00243 }
00244 close(pin[1]);
00245
00246 pid_t waitpidRetVal;
00247
00248
do {
00249
00250 childExitStatus = 0;
00251 waitpidRetVal = waitpid(child_pid, &childExitStatus, WNOHANG);
00252
00253
if (pout[0] >= 0) {
00254
do {
00255
00256
00257 pollstatus = poll(&pollout, 1, 0);
00258
if (pollstatus == 1) {
00259
00260
if (pollout.revents & POLLIN) {
00261
00262
if ((len = read(pout[0],str,1024))>0) {
00263
00264 str[len] =
'\0';
00265 output += str;
00266 }
else {
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285 pollout.revents |= POLLHUP;
00286
break;
00287 }
00288 }
00289 }
00290
else if (pollstatus == -1) {
00291 kdDebug(5100) <<
"Error while polling pout[0]: "
00292 << pollout.revents << endl;
00293 }
00294 }
while ((pollstatus == 1) && (pollout.revents & POLLIN));
00295 }
00296
00297
if (perr[0] >= 0) {
00298
do {
00299
00300
00301 pollstatus = poll(&pollerr, 1, 0);
00302
if (pollstatus == 1) {
00303
00304
if (pollerr.revents & POLLIN) {
00305
00306
if ((len = read(perr[0],str,1024))>0) {
00307
00308 str[len] =
'\0';
00309 error += str;
00310 }
else {
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329 pollerr.revents |= POLLHUP;
00330
break;
00331 }
00332 }
00333 }
00334
else if (pollstatus == -1) {
00335 kdDebug(5100) <<
"Error while polling perr[0]: "
00336 << pollerr.revents << endl;
00337 }
00338 }
while ((pollstatus == 1) && (pollerr.revents & POLLIN));
00339 }
00340 }
while (waitpidRetVal == 0);
00341
00342 close(pout[0]);
00343 close(perr[0]);
00344
00345 unsetenv(
"PGPPASSFD");
00346
if(passphrase)
00347 close(ppass[0]);
00348
00349
00350
if (WIFEXITED(childExitStatus) != 0) {
00351
00352 childExitStatus = WEXITSTATUS(childExitStatus);
00353 kdDebug(5100) <<
"PGP exited with exit status " << childExitStatus
00354 << endl;
00355 }
00356
else {
00357 childExitStatus = -1;
00358 kdDebug(5100) <<
"PGP exited abnormally!" << endl;
00359 }
00360
00361
00362
00363
00364
00365
00366
00367
00368 kdDebug(5100) << error << endl;
00369
00370
return childExitStatus;
00371 }
00372
00373
00374
int
00375 Base::runGpg(
const char *cmd,
const char *passphrase,
bool onlyReadFromGnuPG )
00376 {
00377
00378
00379
00380
00381
char str[1025] =
"\0";
00382
int pin[2], pout[2], perr[2], ppass[2];
00383
int len, len2;
00384 FILE *pass;
00385 pid_t child_pid;
00386
int childExitStatus;
00387
char gpgcmd[1024] =
"\0";
00388
struct pollfd poller[3];
00389
int num_pollers = 0;
00390
const int STD_OUT = 0;
00391
const int STD_ERR = 1;
00392
const int STD_IN = 2;
00393
int pollstatus;
00394
00395
if(passphrase)
00396 {
00397 pipe(ppass);
00398
00399 pass = fdopen(ppass[1],
"w");
00400 fwrite(passphrase,
sizeof(
char), strlen(passphrase), pass);
00401 fwrite(
"\n",
sizeof(
char), 1, pass);
00402 fclose(pass);
00403 close(ppass[1]);
00404
00405
00406
00407 }
00408
00409
00410
00411
00412
00413
00414 error =
"";
00415 output =
"";
00416
00417 pipe(pin);
00418 pipe(pout);
00419 pipe(perr);
00420
00421
if( passphrase ) {
00422
if( mVersion >=
"1.0.7" ) {
00423
00424
if( 0 == getenv(
"GPG_AGENT_INFO") ) {
00425
00426 snprintf( gpgcmd, 1023,
00427
"LANGUAGE=C gpg --no-use-agent --passphrase-fd %d %s",
00428 ppass[0], cmd );
00429 }
00430
else {
00431
00432 snprintf( gpgcmd, 1023,
00433
"LANGUAGE=C gpg --use-agent %s",
00434 cmd );
00435 }
00436 }
00437
else {
00438
00439 snprintf( gpgcmd, 1023,
00440
"LANGUAGE=C gpg --passphrase-fd %d %s",
00441 ppass[0], cmd );
00442 }
00443 }
00444
else {
00445 snprintf(gpgcmd, 1023,
"LANGUAGE=C gpg %s",cmd);
00446 }
00447
00448 QApplication::flushX();
00449
if(!(child_pid = fork()))
00450 {
00451
00452 close(pin[1]);
00453 dup2(pin[0], 0);
00454 close(pin[0]);
00455
00456 close(pout[0]);
00457 dup2(pout[1], 1);
00458 close(pout[1]);
00459
00460 close(perr[0]);
00461 dup2(perr[1], 2);
00462 close(perr[1]);
00463
00464
00465
00466
if( passphrase ) {
00467
if( mVersion >=
"1.0.7" ) {
00468
00469
if( 0 == getenv(
"GPG_AGENT_INFO") ) {
00470
00471 snprintf( gpgcmd, 1023,
00472
"LANGUAGE=C gpg --no-use-agent --passphrase-fd %d %s",
00473 ppass[0], cmd );
00474 }
00475
else {
00476
00477 snprintf( gpgcmd, 1023,
00478
"LANGUAGE=C gpg --use-agent %s",
00479 cmd );
00480 }
00481 }
00482
else {
00483
00484 snprintf( gpgcmd, 1023,
00485
"LANGUAGE=C gpg --passphrase-fd %d %s",
00486 ppass[0], cmd );
00487 }
00488 }
00489
else {
00490 snprintf(gpgcmd, 1023,
"LANGUAGE=C gpg %s",cmd);
00491 }
00492
00493 kdDebug(5100) <<
"pgp cmd = " << gpgcmd << endl;
00494
00495 execl(
"/bin/sh",
"sh",
"-c", gpgcmd, (
void *)0);
00496 _exit(127);
00497 }
00498
00499
00500
00501 close(pin[0]);
00502 close(pout[1]);
00503 close(perr[1]);
00504
00505
00506 poller[STD_OUT].fd = pout[0];
00507 poller[STD_OUT].events = POLLIN;
00508 poller[STD_ERR].fd = perr[0];
00509 poller[STD_ERR].events = POLLIN;
00510 num_pollers = 2;
00511
00512
if (!onlyReadFromGnuPG) {
00513
00514 poller[STD_IN].fd = pin[1];
00515 poller[STD_IN].events = POLLOUT;
00516 num_pollers = 3;
00517 }
else {
00518 close (pin[1]);
00519 pin[1] = -1;
00520 }
00521
00522 pid_t waitpidRetVal;
00523
unsigned int input_pos = 0;
00524
00525
do {
00526
00527 childExitStatus = 0;
00528 waitpidRetVal = waitpid(child_pid, &childExitStatus, WNOHANG);
00529
00530
do {
00531
00532 pollstatus = poll(poller, num_pollers, 10);
00533
if( 0 < pollstatus ) {
00534
00535
if (poller[STD_OUT].revents & POLLIN) {
00536
00537
if ((len = read(pout[0],str,1024))>0) {
00538
00539 str[len] =
'\0';
00540 output += str;
00541 }
00542
else {
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560 poller[STD_OUT].revents |= POLLHUP;
00561 poller[STD_OUT].events = 0;
00562 }
00563 }
else if (poller[STD_OUT].revents & POLLHUP) {
00564
00565 poller[STD_OUT].events = 0;
00566 }
00567
00568
00569
if (poller[STD_ERR].revents & POLLIN) {
00570
00571
if ((len = read(poller[STD_ERR].fd,str,1024))>0) {
00572
00573 str[len] =
'\0';
00574 error += str;
00575 }
00576
else {
00577
00578 poller[STD_ERR].revents |= POLLHUP;
00579 poller[STD_ERR].events = 0;
00580 }
00581 }
else if (poller[STD_ERR].revents & POLLHUP) {
00582
00583 poller[STD_ERR].events = 0;
00584 }
00585
00586
if (num_pollers > 2) {
00587
if (poller[STD_IN].revents & ( POLLERR | POLLHUP ) ) {
00588 kdDebug(5100) <<
"GnuPG seems to have hung up" << endl;
00589 close (pin[1]);
00590 pin[1] = -1;
00591 --num_pollers;
00592 }
00593
else if (poller[STD_IN].revents & POLLOUT) {
00594
if (!input.isEmpty()) {
00595
00596
if ((len2 = input.find(
'\n', input_pos)) == -1)
00597 len2 = input.length()-input_pos;
00598
else
00599 len2 = len2-input_pos+1;
00600
00601
00602 len2 = write(pin[1], input.mid(input_pos,len2).data(), len2);
00603
00604 input_pos += len2;
00605
00606
00607
if (input_pos >= input.length()) {
00608
00609 close (pin[1]);
00610 pin[1] = -1;
00611 --num_pollers;
00612 }
00613 }
00614
else {
00615 write(pin[1],
"\n", 1);
00616
00617 close (pin[1]);
00618 pin[1] = -1;
00619 --num_pollers;
00620 }
00621 }
00622 }
00623 }
00624 }
while ( (pollstatus > 0) && ( (num_pollers > 2)
00625 || (poller[STD_OUT].events != 0)
00626 || (poller[STD_ERR].events != 0) ) );
00627
00628
if (pollstatus == -1) {
00629 kdDebug(5100) <<
"GnuPG poll failed, errno: " << errno << endl;
00630 }
00631
00632 }
while(waitpidRetVal == 0);
00633
00634
if( 0 <= pin[1] )
00635 close (pin[1]);
00636 close(pout[0]);
00637 close(perr[0]);
00638
00639
if(passphrase)
00640 close(ppass[0]);
00641
00642
00643
if (WIFEXITED(childExitStatus) != 0) {
00644
00645 childExitStatus = WEXITSTATUS(childExitStatus);
00646 kdDebug(5100) <<
"GnuPG exited with exit status " << childExitStatus
00647 << endl;
00648 }
00649
else {
00650 childExitStatus = -1;
00651 kdDebug(5100) <<
"GnuPG exited abnormally!" << endl;
00652 }
00653
00654
00655
00656
00657
00658
00659 kdDebug(5100) <<
"gpg stderr:\n" << error << endl;
00660
00661
return childExitStatus;
00662 }
00663
00664
00665
QCString
00666 Base::addUserId()
00667 {
00668
QCString cmd;
00669
QCString pgpUser = Module::getKpgp()->user();
00670
00671
if(!pgpUser.isEmpty())
00672 {
00673 cmd +=
" -u 0x";
00674 cmd += pgpUser;
00675
return cmd;
00676 }
00677
return QCString();
00678 }
00679
00680
00681 }