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