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