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