Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

modem.cpp

Go to the documentation of this file.
00001 /*
00002  *              kPPP: A pppd Front End for the KDE project
00003  *
00004  * $Id: modem.cpp,v 1.13 2004/10/14 01:44:27 zecke Exp $
00005  *
00006  *              Copyright (C) 1997 Bernd Johannes Wuebben
00007  *                      wuebben@math.cornell.edu
00008  *
00009  * This file was added by Harri Porten <porten@tu-harburg.de>
00010  *
00011  *
00012  * This program is free software; you can redistribute it and/or
00013  * modify it under the terms of the GNU Library General Public
00014  * License as published by the Free Software Foundation; either
00015  * version 2 of the License, or (at your option) any later version.
00016  *
00017  * This program is distributed in the hope that it will be useful,
00018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00020  * Library General Public License for more details.
00021  *
00022  * You should have received a copy of the GNU Library General Public
00023  * License along with this program; if not, write to the Free
00024  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00025  */
00026 
00027 /* OPIE */
00028 #include <opie2/odebug.h>
00029 using namespace Opie::Core;
00030 
00031 /* STD */
00032 #include <errno.h>
00033 #include <stdlib.h>
00034 #include <unistd.h>
00035 #include <fcntl.h>
00036 #include <signal.h>
00037 #include <sys/ioctl.h>
00038 #include <sys/types.h>
00039 #include <sys/stat.h>
00040 #include <setjmp.h>
00041 #include <regex.h>
00042 #include <qregexp.h>
00043 #include <assert.h>
00044 #include <string.h>
00045 
00046 #ifdef HAVE_RESOLV_H
00047 #  include <arpa/nameser.h>
00048 #  include <resolv.h>
00049 #endif
00050 
00051 #ifndef _PATH_RESCONF
00052 #define _PATH_RESCONF "/etc/resolv.conf"
00053 #endif
00054 
00055 #define strlcpy strcpy
00056 #include "auth.h"
00057 #include "modem.h"
00058 #include "pppdata.h"
00059 
00060 
00061 #define MY_ASSERT(x)  if (!(x)) { \
00062         ofatal << "ASSERT: \"" << #x << "\" in " << __FILE__ << " (" << __LINE__ << ")\n" << oendl;  \
00063         exit(1); }
00064 
00065 
00066 static sigjmp_buf jmp_buffer;
00067 
00068 //Modem *Modem::modem = 0;
00069 
00070 
00071 const char* pppdPath() {
00072   // wasting a few bytes
00073   static char buffer[sizeof(PPPDSEARCHPATH)+sizeof(PPPDNAME)];
00074   static char *pppdPath = 0L;
00075   char *p;
00076 
00077   if(pppdPath == 0L) {
00078     const char *c = PPPDSEARCHPATH;
00079     while(*c != '\0') {
00080       while(*c == ':')
00081         c++;
00082       p = buffer;
00083       while(*c != '\0' && *c != ':')
00084         *p++ = *c++;
00085       *p = '\0';
00086       strcat(p, "/");
00087       strcat(p, PPPDNAME);
00088       if(access(buffer, F_OK) == 0)
00089         return (pppdPath = buffer);
00090     }
00091   }
00092 
00093   return pppdPath;
00094 }
00095 
00096 
00097 Modem::Modem( PPPData* pd )
00098 {
00099     _pppdata = pd;
00100     modemfd = -1;
00101     _pppdExitStatus = -1;
00102     pppdPid = -1;
00103     sn = m_modemDebug =  0L;
00104     data_mode = false;
00105     modem_is_locked = false;
00106     lockfile[0] = '\0';
00107     device = "/dev/modem";
00108 }
00109 
00110 
00111 Modem::~Modem()
00112 {
00113 }
00114 
00115 
00116 speed_t Modem::modemspeed() {
00117   // convert the string modem speed int the gpppdata object to a t_speed type
00118   // to set the modem.  The constants here should all be ifdef'd because
00119   // other systems may not have them
00120     int i = _pppdata->speed().toInt()/100;
00121 
00122   switch(i) {
00123   case 24:
00124     return B2400;
00125     break;
00126   case 96:
00127     return B9600;
00128     break;
00129   case 192:
00130     return B19200;
00131     break;
00132   case 384:
00133     return B38400;
00134     break;
00135 #ifdef B57600
00136   case 576:
00137     return B57600;
00138     break;
00139 #endif
00140 
00141 #ifdef B115200
00142   case 1152:
00143     return B115200;
00144     break;
00145 #endif
00146 
00147 #ifdef B230400
00148   case 2304:
00149     return B230400;
00150     break;
00151 #endif
00152 
00153 #ifdef B460800
00154   case 4608:
00155     return B460800;
00156     break;
00157 #endif
00158 
00159   default:
00160     return B38400;
00161     break;
00162   }
00163 }
00164 
00165 bool Modem::opentty() {
00166   //  int flags;
00167 
00168 //begin  if((modemfd = Requester::rq->openModem(gpppdata.modemDevice()))<0) {
00169     close(modemfd);
00170     device = _pppdata->modemDevice();
00171     if ((modemfd = open(device, O_RDWR|O_NDELAY|O_NOCTTY)) == -1) {
00172         odebug << "error opening modem device !" << oendl;
00173         errmsg = QObject::tr("Unable to open modem.");
00174         return false;
00175     }
00176 //bend  if((modemfd = Requester::rq->openModem(gpppdata.modemDevice()))<0) {
00177 //}
00178 
00179 #if 0
00180   if(_pppdata->UseCDLine()) {
00181     if(ioctl(modemfd, TIOCMGET, &flags) == -1) {
00182       errmsg = QObject::tr("Unable to detect state of CD line.");
00183       ::close(modemfd);
00184       modemfd = -1;
00185       return false;
00186     }
00187     if ((flags&TIOCM_CD) == 0) {
00188       errmsg = QObject::tr("The modem is not ready.");
00189       ::close(modemfd);
00190       modemfd = -1;
00191       return false;
00192     }
00193   }
00194 #endif
00195 
00196   tcdrain (modemfd);
00197   tcflush (modemfd, TCIOFLUSH);
00198 
00199   if(tcgetattr(modemfd, &tty) < 0){
00200     // this helps in some cases
00201     tcsendbreak(modemfd, 0);
00202     sleep(1);
00203     if(tcgetattr(modemfd, &tty) < 0){
00204       errmsg = QObject::tr("The modem is busy.");
00205       ::close(modemfd);
00206       modemfd = -1;
00207       return false;
00208     }
00209   }
00210 
00211   memset(&initial_tty,'\0',sizeof(initial_tty));
00212 
00213   initial_tty = tty;
00214 
00215   tty.c_cc[VMIN] = 0; // nonblocking
00216   tty.c_cc[VTIME] = 0;
00217   tty.c_oflag = 0;
00218   tty.c_lflag = 0;
00219 
00220   tty.c_cflag &= ~(CSIZE | CSTOPB | PARENB);
00221   tty.c_cflag |= CS8 | CREAD;
00222   tty.c_cflag |= CLOCAL;                   // ignore modem status lines
00223   tty.c_iflag = IGNBRK | IGNPAR /* | ISTRIP */ ;
00224   tty.c_lflag &= ~ICANON;                  // non-canonical mode
00225   tty.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHOKE);
00226 
00227 
00228   if(_pppdata->flowcontrol() != PPPData::FlowNone) {
00229       if(_pppdata->flowcontrol() == PPPData::FlowHardware) {
00230       tty.c_cflag |= CRTSCTS;
00231     }
00232     else {
00233       tty.c_iflag |= IXON | IXOFF;
00234       tty.c_cc[VSTOP]  = 0x13; /* DC3 = XOFF = ^S */
00235       tty.c_cc[VSTART] = 0x11; /* DC1 = XON  = ^Q */
00236     }
00237   }
00238   else {
00239     tty.c_cflag &= ~CRTSCTS;
00240     tty.c_iflag &= ~(IXON | IXOFF);
00241   }
00242 
00243   cfsetospeed(&tty, modemspeed());
00244   cfsetispeed(&tty, modemspeed());
00245 
00246   tcdrain(modemfd);
00247 
00248   if(tcsetattr(modemfd, TCSANOW, &tty) < 0){
00249     errmsg = QObject::tr("The modem is busy.");
00250     ::close(modemfd);
00251     modemfd=-1;
00252     return false;
00253   }
00254 
00255   errmsg = QObject::tr("Modem Ready.");
00256   return true;
00257 }
00258 
00259 
00260 bool Modem::closetty() {
00261   if(modemfd >=0 ) {
00262     stop();
00263     /* discard data not read or transmitted */
00264     tcflush(modemfd, TCIOFLUSH);
00265 
00266     if(tcsetattr(modemfd, TCSANOW, &initial_tty) < 0){
00267       errmsg = QObject::tr("Can't restore tty settings: tcsetattr()\n");
00268       ::close(modemfd);
00269       modemfd = -1;
00270       return false;
00271     }
00272     ::close(modemfd);
00273     modemfd = -1;
00274   }
00275 
00276   return true;
00277 }
00278 
00279 
00280 void Modem::readtty(int) {
00281   char buffer[200];
00282   unsigned char c;
00283   int len;
00284 
00285   // read data in chunks of up to 200 bytes
00286   if((len = ::read(modemfd, buffer, 200)) > 0) {
00287     // split buffer into single characters for further processing
00288     for(int i = 0; i < len; i++) {
00289       c = buffer[i] & 0x7F;
00290       emit charWaiting(c);
00291     }
00292   }
00293 }
00294 
00295 
00296 void Modem::notify(const QObject *receiver, const char *member) {
00297   connect(this, SIGNAL(charWaiting(unsigned char)), receiver, member);
00298   startNotifier();
00299 }
00300 
00301 
00302 void Modem::stop() {
00303   disconnect(SIGNAL(charWaiting(unsigned char)));
00304   stopNotifier();
00305 }
00306 
00307 
00308 void Modem::startNotifier() {
00309   if(modemfd >= 0) {
00310     if(sn == 0) {
00311       sn = new QSocketNotifier(modemfd, QSocketNotifier::Read, this);
00312       connect(sn, SIGNAL(activated(int)), SLOT(readtty(int)));
00313       odebug << "QSocketNotifier started!" << oendl;
00314     } else {
00315         odebug << "QSocketNotifier re-enabled!" << oendl;
00316         sn->setEnabled(true);
00317     }
00318   }
00319 }
00320 
00321 
00322 void Modem::stopNotifier() {
00323   if(sn != 0) {
00324     sn->setEnabled(false);
00325     disconnect(sn);
00326     delete sn;
00327     sn = 0;
00328     odebug << "QSocketNotifier stopped!" << oendl;
00329   }
00330 }
00331 
00332 
00333 void Modem::flush() {
00334   char c;
00335   while(read(modemfd, &c, 1) == 1);
00336 }
00337 
00338 
00339 bool Modem::writeChar(unsigned char c) {
00340   int s;
00341   do {
00342     s = write(modemfd, &c, 1);
00343     if (s < 0) {
00344       oerr << "write() in Modem::writeChar failed" << oendl;
00345       return false;
00346     }
00347   } while(s == 0);
00348 
00349   return true;
00350 }
00351 
00352 
00353 bool Modem::writeLine(const char *buf) {
00354   int len = strlen(buf);
00355   char *b = new char[len+2];
00356   memcpy(b, buf, len);
00357   // different modems seem to need different line terminations
00358   switch( _pppdata->enter() ) {
00359   case PPPData::EndLF:
00360     b[len++]='\n';
00361     break;
00362   case PPPData::EndCR:
00363     b[len++]='\r';
00364     break;
00365   case PPPData::EndCRLF:
00366     b[len++]='\r';
00367     b[len++]='\n';
00368     break;
00369   }
00370 
00371   int l = len;
00372   while(l) {
00373     int wr = write(modemfd, &b[len-l], l);
00374     if(wr < 0) {
00375       // TODO do something meaningful with the error code (or ignore it
00376       oerr << "write() in Modem::writeLine failed" << oendl;
00377       delete[] b;
00378       return false;
00379     }
00380     l -= wr;
00381   }
00382   delete[] b;
00383   return true;
00384 }
00385 
00386 
00387 bool Modem::hangup() {
00388   // this should really get the modem to hang up and go into command mode
00389   // If anyone sees a fault in the following please let me know, since
00390   // this is probably the most imporant snippet of code in the whole of
00391   // kppp. If people complain about kppp being stuck, this piece of code
00392   // is most likely the reason.
00393   struct termios temptty;
00394 
00395   if(modemfd >= 0) {
00396 
00397     // is this Escape & HangupStr stuff really necessary ? (Harri)
00398 
00399     if (data_mode) escape_to_command_mode();
00400 
00401     // Then hangup command
00402     writeLine(_pppdata->modemHangupStr().local8Bit());
00403 
00404     usleep(_pppdata->modemInitDelay() * 10000); // 0.01 - 3.0 sec
00405 
00406 #ifndef DEBUG_WO_DIALING
00407     if (sigsetjmp(jmp_buffer, 1) == 0) {
00408       // set alarm in case tcsendbreak() hangs
00409       signal(SIGALRM, alarm_handler);
00410       alarm(2);
00411 
00412       tcsendbreak(modemfd, 0);
00413 
00414       alarm(0);
00415       signal(SIGALRM, SIG_IGN);
00416     } else {
00417       // we reach this point if the alarm handler got called
00418       closetty();
00419       close(modemfd);
00420       modemfd = -1;
00421       errmsg = QObject::tr("The modem does not respond.");
00422       return false;
00423     }
00424 
00425 #ifndef __svr4__ // drops DTR but doesn't set it afterwards again. not good for init.
00426     tcgetattr(modemfd, &temptty);
00427     cfsetospeed(&temptty, B0);
00428     cfsetispeed(&temptty, B0);
00429     tcsetattr(modemfd, TCSAFLUSH, &temptty);
00430 #else
00431     int modemstat;
00432     ioctl(modemfd, TIOCMGET, &modemstat);
00433     modemstat &= ~TIOCM_DTR;
00434     ioctl(modemfd, TIOCMSET, &modemstat);
00435     ioctl(modemfd, TIOCMGET, &modemstat);
00436     modemstat |= TIOCM_DTR;
00437     ioctl(modemfd, TIOCMSET, &modemstat);
00438 #endif
00439 
00440     usleep(_pppdata->modemInitDelay() * 10000); // 0.01 - 3.0 secs
00441 
00442     cfsetospeed(&temptty, modemspeed());
00443     cfsetispeed(&temptty, modemspeed());
00444     tcsetattr(modemfd, TCSAFLUSH, &temptty);
00445 #endif
00446     return true;
00447   } else
00448     return false;
00449 }
00450 
00451 
00452 void Modem::escape_to_command_mode() {
00453   // Send Properly bracketed escape code to put the modem back into command state.
00454   // A modem will accept AT commands only when it is in command state.
00455   // When a modem sends the host the CONNECT string, that signals
00456   // that the modem is now in the connect state (no long accepts AT commands.)
00457   // Need to send properly timed escape sequence to put modem in command state.
00458   // Escape codes and guard times are controlled by S2 and S12 values.
00459   //
00460   tcflush(modemfd, TCIOFLUSH);
00461 
00462   // +3 because quiet time must be greater than guard time.
00463   usleep((_pppdata->modemEscapeGuardTime()+3)*20000);
00464   QCString tmp = _pppdata->modemEscapeStr().local8Bit();
00465   write(modemfd, tmp.data(), tmp.length());
00466   tcflush(modemfd, TCIOFLUSH);
00467   usleep((_pppdata->modemEscapeGuardTime()+3)*20000);
00468 
00469   data_mode = false;
00470 }
00471 
00472 
00473 const QString Modem::modemMessage() {
00474   return errmsg;
00475 }
00476 
00477 
00478 QString Modem::parseModemSpeed(const QString &s) {
00479   // this is a small (and bad) parser for modem speeds
00480   int rx = -1;
00481   int tx = -1;
00482   int i;
00483   QString result;
00484 
00485   odebug << "Modem reported result string: " << s.latin1() << "" << oendl;
00486 
00487   const int RXMAX = 7;
00488   const int TXMAX = 2;
00489   QRegExp rrx[RXMAX] = {
00490     QRegExp("[0-9]+[:/ ]RX", false),
00491     QRegExp("[0-9]+RX", false),
00492     QRegExp("[/: -][0-9]+[/: ]", false),
00493     QRegExp("[/: -][0-9]+$", false),
00494     QRegExp("CARRIER [^0-9]*[0-9]+", false),
00495     QRegExp("CONNECT [^0-9]*[0-9]+", false),
00496     QRegExp("[0-9]+") // panic mode
00497   };
00498 
00499   QRegExp trx[TXMAX] = {
00500     QRegExp("[0-9]+[:/ ]TX", false),
00501     QRegExp("[0-9]+TX", false)
00502   };
00503 
00504   for(i = 0; i < RXMAX; i++) {
00505     int len, idx, result;
00506     if((idx = rrx[i].match(s,0,&len)) > -1) {
00507 //    if((idx = rrx[i].search(s)) > -1) {
00508         //     len = rrx[i].matchedLength();
00509 
00510       //
00511       // rrx[i] has been matched, idx contains the start of the match
00512       // and len contains how long the match is. Extract the match.
00513       //
00514       QString sub = s.mid(idx, len);
00515 
00516       //
00517       // Now extract the digits only from the match, which will
00518       // then be converted to an int.
00519       //
00520       if ((idx = rrx[RXMAX-1].match( sub,0,&len )) > -1) {
00521 //      if ((idx = rrx[RXMAX-1].search( sub )) > -1) {
00522 //        len = rrx[RXMAX-1].matchedLength();
00523         sub = sub.mid(idx, len);
00524         result = sub.toInt();
00525         if(result > 0) {
00526           rx = result;
00527           break;
00528         }
00529       }
00530     }
00531   }
00532 
00533   for(i = 0; i < TXMAX; i++) {
00534     int len, idx, result;
00535     if((idx = trx[i].match(s,0,&len)) > -1) {
00536 //    if((idx = trx[i].search(s)) > -1) {
00537 //      len = trx[i].matchedLength();
00538 
00539       //
00540       // trx[i] has been matched, idx contains the start of the match
00541       // and len contains how long the match is. Extract the match.
00542       //
00543       QString sub = s.mid(idx, len);
00544 
00545       //
00546       // Now extract the digits only from the match, which will then
00547       // be converted to an int.
00548       //
00549       if((idx = rrx[RXMAX-1].match(sub,0,&len)) > -1) {
00550 //      if((idx = rrx[RXMAX-1].search(sub)) > -1) {
00551 //        len = rrx[RXMAX-1].matchedLength();
00552         sub = sub.mid(idx, len);
00553         result = sub.toInt();
00554         if(result > 0) {
00555           tx = result;
00556           break;
00557         }
00558       }
00559     }
00560   }
00561 
00562   if(rx == -1 && tx == -1)
00563     result = QObject::tr("Unknown speed");
00564   else if(tx == -1)
00565     result.setNum(rx);
00566   else if(rx == -1) // should not happen
00567     result.setNum(tx);
00568   else
00569     result.sprintf("%d/%d", rx, tx);
00570 
00571   odebug << "The parsed result is: " << result.latin1() << "" << oendl;
00572 
00573   return result;
00574 }
00575 
00576 
00577 // Lock modem device. Returns 0 on success 1 if the modem is locked and -1 if
00578 // a lock file can't be created ( permission problem )
00579 int Modem::lockdevice() {
00580   int fd;
00581   char newlock[80]=""; // safe
00582 
00583   if(!_pppdata->modemLockFile()) {
00584     odebug << "The user doesn't want a lockfile." << oendl;
00585     return 0;
00586   }
00587 
00588   if (modem_is_locked)
00589     return 1;
00590 
00591   QString lockfile = LOCK_DIR"/LCK..";
00592   lockfile += _pppdata->modemDevice().mid(5); // append everything after /dev/
00593 
00594   if(access(QFile::encodeName(lockfile), F_OK) == 0) {
00595 //    if ((fd = Requester::rq->
00596 if ((fd = openLockfile(QFile::encodeName(lockfile), O_RDONLY)) >= 0) {
00597       // Mario: it's not necessary to read more than lets say 32 bytes. If
00598       // file has more than 32 bytes, skip the rest
00599       char oldlock[33]; // safe
00600       int sz = read(fd, &oldlock, 32);
00601       close (fd);
00602       if (sz <= 0)
00603         return 1;
00604       oldlock[sz] = '\0';
00605 
00606       odebug << "Device is locked by: " << oldlock << "" << oendl;
00607 
00608       int oldpid;
00609       int match = sscanf(oldlock, "%d", &oldpid);
00610 
00611       // found a pid in lockfile ?
00612       if (match < 1 || oldpid <= 0)
00613         return 1;
00614 
00615       // check if process exists
00616       if (kill((pid_t)oldpid, 0) == 0 || errno != ESRCH)
00617         return 1;
00618 
00619       odebug << "lockfile is stale" << oendl;
00620     }
00621   }
00622 
00623   fd = openLockfile(_pppdata->modemDevice(),O_WRONLY|O_TRUNC|O_CREAT);
00624   if(fd >= 0) {
00625     sprintf(newlock,"%010d\n", getpid());
00626     odebug << "Locking Device: " << newlock << "" << oendl;
00627 
00628     write(fd, newlock, strlen(newlock));
00629     close(fd);
00630     modem_is_locked=true;
00631 
00632     return 0;
00633   }
00634 
00635   return -1;
00636 
00637 }
00638 
00639 
00640 // UnLock modem device
00641 void Modem::unlockdevice() {
00642   if (modem_is_locked) {
00643     odebug << "UnLocking Modem Device" << oendl;
00644     close(modemfd);
00645     modemfd = -1;
00646     unlink(lockfile);
00647     lockfile[0] = '\0';
00648     modem_is_locked=false;
00649   }
00650 }
00651 
00652 int Modem::openLockfile( QString lockfile, int flags)
00653 {
00654     int fd;
00655     int mode;
00656     flags = O_RDONLY;
00657     if(flags == O_WRONLY|O_TRUNC|O_CREAT)
00658         mode = 0644;
00659     else
00660         mode = 0;
00661 
00662     lockfile = LOCK_DIR;
00663     lockfile += "/LCK..";
00664     lockfile += device.right( device.length() - device.findRev("/") -1 );
00665     odebug << "lockfile >" << lockfile.latin1() << "<" << oendl;
00666     // TODO:
00667     //   struct stat st;
00668     //   if(stat(lockfile.data(), &st) == -1) {
00669     //     if(errno == EBADF)
00670     //       return -1;
00671     //   } else {
00672     //     // make sure that this is a regular file
00673     //     if(!S_ISREG(st.st_mode))
00674     //       return -1;
00675     //   }
00676     if ((fd = open(lockfile, flags, mode)) == -1) {
00677         odebug << "error opening lockfile!" << oendl;
00678         lockfile = QString::null;
00679         fd = open(DEVNULL, O_RDONLY);
00680     } else
00681         fchown(fd, 0, 0);
00682     return fd;
00683 }
00684 
00685 
00686 
00687 void alarm_handler(int) {
00688   //  fprintf(stderr, "alarm_handler(): Received SIGALRM\n");
00689 
00690   // jump
00691   siglongjmp(jmp_buffer, 1);
00692 }
00693 
00694 
00695 const char* Modem::authFile(Auth method, int version) {
00696   switch(method|version) {
00697   case PAP|Original:
00698     return PAP_AUTH_FILE;
00699     break;
00700   case PAP|New:
00701     return PAP_AUTH_FILE".new";
00702     break;
00703   case PAP|Old:
00704     return PAP_AUTH_FILE".old";
00705     break;
00706   case CHAP|Original:
00707     return CHAP_AUTH_FILE;
00708     break;
00709   case CHAP|New:
00710     return CHAP_AUTH_FILE".new";
00711     break;
00712   case CHAP|Old:
00713     return CHAP_AUTH_FILE".old";
00714     break;
00715   default:
00716     return 0L;
00717   }
00718 }
00719 
00720 
00721 bool Modem::createAuthFile(Auth method, const char *username, const char *password) {
00722   const char *authfile, *oldName, *newName;
00723   char line[100];
00724   char regexp[2*MaxStrLen+30];
00725   regex_t preg;
00726 
00727   if(!(authfile = authFile(method)))
00728     return false;
00729 
00730   if(!(newName = authFile(method, New)))
00731     return false;
00732 
00733   // look for username, "username" or 'username'
00734   // if you modify this RE you have to adapt regexp's size above
00735   snprintf(regexp, sizeof(regexp), "^[ \t]*%s[ \t]\\|^[ \t]*[\"\']%s[\"\']",
00736           username,username);
00737   MY_ASSERT(regcomp(&preg, regexp, 0) == 0);
00738 
00739   // copy to new file pap- or chap-secrets
00740   int old_umask = umask(0077);
00741   FILE *fout = fopen(newName, "w");
00742   if(fout) {
00743     // copy old file
00744     FILE *fin = fopen(authfile, "r");
00745     if(fin) {
00746       while(fgets(line, sizeof(line), fin)) {
00747         if(regexec(&preg, line, 0, 0L, 0) == 0)
00748            continue;
00749         fputs(line, fout);
00750       }
00751       fclose(fin);
00752     }
00753 
00754     // append user/pass pair
00755     fprintf(fout, "\"%s\"\t*\t\"%s\"\n", username, password);
00756     fclose(fout);
00757   }
00758 
00759   // restore umask
00760   umask(old_umask);
00761 
00762   // free memory allocated by regcomp
00763   regfree(&preg);
00764 
00765   if(!(oldName = authFile(method, Old)))
00766     return false;
00767 
00768   // delete old file if any
00769   unlink(oldName);
00770 
00771   rename(authfile, oldName);
00772   rename(newName, authfile);
00773 
00774   return true;
00775 }
00776 
00777 
00778 bool Modem::removeAuthFile(Auth method) {
00779   const char *authfile, *oldName;
00780 
00781   if(!(authfile = authFile(method)))
00782     return false;
00783   if(!(oldName = authFile(method, Old)))
00784     return false;
00785 
00786   if(access(oldName, F_OK) == 0) {
00787     unlink(authfile);
00788     return (rename(oldName, authfile) == 0);
00789   } else
00790     return false;
00791 }
00792 
00793 
00794 bool Modem::setSecret(int method, const char* name, const char* password)
00795 {
00796 
00797     Auth auth;
00798     if(method == AUTH_PAPCHAP)
00799         return setSecret(AUTH_PAP, name, password) &&
00800             setSecret(AUTH_CHAP, name, password);
00801 
00802     switch(method) {
00803     case AUTH_PAP:
00804         auth = Modem::PAP;
00805         break;
00806     case AUTH_CHAP:
00807         auth = Modem::CHAP;
00808         break;
00809     default:
00810         return false;
00811     }
00812 
00813     return createAuthFile(auth, name, password);
00814 
00815 }
00816 
00817 bool Modem::removeSecret(int method)
00818 {
00819    Auth auth;
00820 
00821     switch(method) {
00822     case AUTH_PAP:
00823         auth = Modem::PAP;
00824         break;
00825     case AUTH_CHAP:
00826         auth = Modem::CHAP;
00827         break;
00828     default:
00829         return false;
00830     }
00831     return removeAuthFile( auth );
00832 }
00833 
00834 int checkForInterface()
00835 {
00836 // I don't know if Linux needs more initialization to get the ioctl to
00837 // work, pppd seems to hint it does.  But BSD doesn't, and the following
00838 // code should compile.
00839 #if (defined(HAVE_NET_IF_PPP_H) || defined(HAVE_LINUX_IF_PPP_H)) && !defined(__svr4__)
00840     int s, ok;
00841     struct ifreq ifr;
00842     //    extern char *no_ppp_msg;
00843 
00844     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
00845         return 1;               /* can't tell */
00846 
00847     strlcpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
00848     ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
00849     close(s);
00850 
00851     if (ok == -1) {
00852 // This is ifdef'd FreeBSD, because FreeBSD is the only BSD that supports
00853 // KLDs, the old LKM interface couldn't handle loading devices
00854 // dynamically, and thus can't load ppp support on the fly
00855 #ifdef __FreeBSD__
00856         // If we failed to load ppp support and don't have it already.
00857         if (kldload("if_ppp") == -1) {
00858             return -1;
00859         }
00860         return 0;
00861 #else
00862         return -1;
00863 #endif
00864     }
00865     return 0;
00866 #else
00867 // We attempt to use the SunOS/SysVr4 method and stat /dev/ppp
00868    struct stat buf;
00869 
00870    memset(&buf, 0, sizeof(buf));
00871    return stat("/dev/ppp", &buf);
00872 #endif
00873 }
00874 
00875 bool Modem::execpppd(const char *arguments) {
00876   char buf[MAX_CMDLEN];
00877   char *args[MaxArgs];
00878   pid_t pgrpid;
00879 
00880   if(modemfd<0)
00881     return false;
00882 
00883   _pppdExitStatus = -1;
00884 
00885   (void)::pipe( m_pppdLOG );
00886 
00887   switch(pppdPid = fork())
00888     {
00889     case -1:
00890       fprintf(stderr,"In parent: fork() failed\n");
00891       ::close(  m_pppdLOG[0] );
00892       ::close(  m_pppdLOG[1] );
00893       return false;
00894       break;
00895 
00896     case 0:
00897       // let's parse the arguments the user supplied into UNIX suitable form
00898       // that is a list of pointers each pointing to exactly one word
00899       strlcpy(buf, arguments);
00900       parseargs(buf, args);
00901       // become a session leader and let /dev/ttySx
00902       // be the controlling terminal.
00903       pgrpid = setsid();
00904 #ifdef TIOCSCTTY
00905       if(ioctl(modemfd, TIOCSCTTY, 0)<0)
00906         fprintf(stderr, "ioctl() failed.\n");
00907 #elif defined (TIOCSPGRP)
00908        if(ioctl(modemfd, TIOCSPGRP, &pgrpid)<0)
00909        fprintf(stderr, "ioctl() failed.\n");
00910 #endif
00911       if(tcsetpgrp(modemfd, pgrpid)<0)
00912         fprintf(stderr, "tcsetpgrp() failed.\n");
00913 
00914       ::close( m_pppdLOG[0] );
00915       ::setenv( "LANG", "C", 1 ); // overwrite
00916       dup2(m_pppdLOG[1], 11 ); // for logfd 11
00917       dup2(modemfd, 0);
00918       dup2(modemfd, 1);
00919 
00920 
00921       switch (checkForInterface()) {
00922         case 1:
00923           fprintf(stderr, "Cannot determine if kernel supports ppp.\n");
00924           break;
00925         case -1:
00926           fprintf(stderr, "Kernel does not support ppp, oops.\n");
00927           break;
00928         case 0:
00929           fprintf(stderr, "Kernel supports ppp alright.\n");
00930           break;
00931       }
00932 
00933       execve(pppdPath(), args, 0L);
00934       _exit(0);
00935       break;
00936 
00937     default:
00938       odebug << "In parent: pppd pid " << pppdPid << "\n" << oendl;
00939       close(modemfd);
00940 
00941       ::close( m_pppdLOG[1] );
00942       // set it to nonblocking io
00943       int flag = ::fcntl( m_pppdLOG[0], F_GETFL );
00944 
00945       if ( !(flag & O_NONBLOCK) ) {
00946           odebug << "Setting nonblocking io" << oendl;
00947           flag |= O_NONBLOCK;
00948           ::fcntl(m_pppdLOG[0], F_SETFL, flag );
00949       }
00950 
00951       delete m_modemDebug;
00952       m_modemDebug = new QSocketNotifier(m_pppdLOG[0], QSocketNotifier::Read, this );
00953       connect(m_modemDebug, SIGNAL(activated(int) ),
00954               this, SLOT(slotModemDebug(int) ) );
00955 
00956       modemfd = -1;
00957       m_pppdDev = QString::fromLatin1("ppp0");
00958       return true;
00959       break;
00960     }
00961 }
00962 
00963 
00964 bool Modem::killpppd() {
00965     odebug << "In killpppd and pid is " << pppdPid << "" << oendl;
00966   if(pppdPid > 0) {
00967     delete m_modemDebug;
00968     m_modemDebug = 0;
00969     odebug << "In killpppd(): Sending SIGTERM to " << pppdPid << "\n" << oendl;
00970     if(kill(pppdPid, SIGTERM) < 0) {
00971       odebug << "Error terminating " << pppdPid << ". Sending SIGKILL\n" << oendl;
00972       if(kill(pppdPid, SIGKILL) < 0) {
00973         odebug << "Error killing " << pppdPid << "\n" << oendl;
00974         return false;
00975       }
00976     }
00977   }
00978   return true;
00979 }
00980 
00981 
00982 void Modem::parseargs(char* buf, char** args) {
00983   int nargs = 0;
00984   int quotes;
00985 
00986   while(nargs < MaxArgs-1 && *buf != '\0') {
00987 
00988     quotes = 0;
00989 
00990     // Strip whitespace. Use nulls, so that the previous argument is
00991     // terminated automatically.
00992 
00993     while ((*buf == ' ' ) || (*buf == '\t' ) || (*buf == '\n' ) )
00994       *buf++ = '\0';
00995 
00996     // detect begin of quoted argument
00997     if (*buf == '"' || *buf == '\'') {
00998       quotes = *buf;
00999       *buf++ = '\0';
01000     }
01001 
01002     // save the argument
01003     if(*buf != '\0') {
01004       *args++ = buf;
01005       nargs++;
01006     }
01007 
01008     if (!quotes)
01009       while ((*buf != '\0') && (*buf != '\n') &&
01010          (*buf != '\t') && (*buf != ' '))
01011     buf++;
01012     else {
01013       while ((*buf != '\0') && (*buf != quotes))
01014     buf++;
01015       *buf++ = '\0';
01016     }
01017   }
01018 
01019   *args = 0L;
01020 }
01021 
01022 bool Modem::execPPPDaemon(const QString & arguments)
01023 {
01024   if(execpppd(arguments)) {
01025     _pppdata->setpppdRunning(true);
01026     return true;
01027   } else
01028     return false;
01029 }
01030 
01031 void Modem::killPPPDaemon()
01032 {
01033   _pppdata->setpppdRunning(false);
01034   killpppd();
01035 }
01036 
01037 int Modem::pppdExitStatus()
01038 {
01039     return _pppdExitStatus;
01040 }
01041 
01042 int Modem::openResolv(int flags)
01043 {
01044     int fd;
01045     if ((fd = open(_PATH_RESCONF, flags)) == -1) {
01046         odebug << "error opening resolv.conf!" << oendl;
01047         fd = open(DEVNULL, O_RDONLY);
01048     }
01049     return fd;
01050 }
01051 
01052 bool Modem::setHostname(const QString & name)
01053 {
01054     return sethostname(name, name.length()) == 0;
01055 }
01056 
01057 QString Modem::pppDevice()const {
01058     return m_pppdDev;
01059 }
01060 void Modem::setPPPDevice( const QString& dev ) {
01061     m_pppdDev = dev;
01062 }
01063 pid_t Modem::pppPID()const {
01064     return pppdPid;
01065 }
01066 void Modem::setPPPDPid( pid_t pid ) {
01067     odebug << "Modem setting pid" << oendl;
01068     _pppdExitStatus = -1;
01069     pppdPid = pid;
01070     modemfd = -1;
01071 }
01072 void Modem::slotModemDebug(int fd) {
01073     char buf[2049];
01074     int len;
01075 
01076     // read in pppd data look for Using interface
01077     // then read the interface
01078     // we limit to 10 device now 0-9
01079     if((len = ::read(fd, buf, 2048)) > 0) {
01080         buf[len+1] = '\0';
01081         char *found;
01082         if ( (found = ::strstr(buf, "Using interface ") ) ) {
01083             found += 16;
01084             m_pppdDev = QString::fromLatin1(found, 5 );
01085             m_pppdDev = m_pppdDev.simplifyWhiteSpace();
01086         }
01087     }
01088 }

Generated on Sat Nov 5 16:17:50 2005 for OPIE by  doxygen 1.4.2