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 }