Source Code (Use browser search to find items of interest.)
Class Index
kppp'Opener (./kdenetwork/kppp/opener.h:21)
class Opener {
public:
Opener(int);
~Opener();
enum { OpenDevice = 1,
OpenLock, RemoveLock,
OpenResolv,
OpenSysLog,
SetSecret, RemoveSecret,
SetHostname,
ExecPPPDaemon, KillPPPDaemon,
Stop };
enum Auth { PAP = 1, CHAP };
enum { MaxPathLen = 30, MaxStrLen = 40, MaxArgs = 100 };
private:
enum { Original=0x100, New=0x200, Old=0x400 } Version;
void mainLoop();
int sendFD(int ttyfd, struct ResponseHeader *response);
int sendResponse(struct ResponseHeader *response);
const char *deviceByIndex(int idx);
bool createAuthFile(Auth method, char *username, char *password);
bool removeAuthFile(Auth method);
const char* authFile(Auth method, int version = Original);
bool execpppd(const char *arguments);
bool killpppd();
void parseargs(char* buf, char** args);
int socket;
int ttyfd;
char lockfile[MaxPathLen+1];
};
kppp'Opener::Opener() (./kdenetwork/kppp/opener.cpp:109)
Opener::Opener(int s) : socket(s), ttyfd(-1) {
lockfile[0] = '\0';
signal(SIGUSR1, SIG_IGN);
signal(SIGTERM, SIG_IGN);
signal(SIGINT, SIG_IGN);
signal(SIGCHLD, sighandler);
mainLoop();
}
kppp'Opener::mainLoop() (./kdenetwork/kppp/opener.cpp:118)
void Opener::mainLoop() {
int len;
int fd = -1;
int flags, mode;
const char *device;
union AllRequests request;
struct ResponseHeader response;
struct msghdr msg;
struct iovec iov;
iov.iov_base = IOV_BASE_CAST &request;
iov.iov_len = sizeof(request);
msg.msg_name = 0L;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = 0L;
msg.msg_controllen = 0;
// loop forever
while(1) {
len = recvmsg(socket, &msg, 0);
if(len < 0) {
switch(errno) {
case EINTR:
Debug("Opener: interrupted system call, continuing");
break;
default:
perror("Opener: error reading from socket");
_exit(1);
}
} else {
switch(request.header.type) {
case OpenDevice:
Debug("Opener: received OpenDevice");
MY_ASSERT(len == sizeof(struct OpenModemRequest));
close(ttyfd);
device = deviceByIndex(request.modem.deviceNum);
response.status = 0;
if ((ttyfd = open(device, O_RDWR|O_NDELAY|O_NOCTTY)) == -1) {
Debug("error opening modem device !");
fd = open(DEVNULL, O_RDONLY);
response.status = -errno;
sendFD(fd, &response);
close(fd);
} else
sendFD(ttyfd, &response);
break;
case OpenLock:
Debug("Opener: received OpenLock\n");
MY_ASSERT(len == sizeof(struct OpenLockRequest));
flags = request.lock.flags;
MY_ASSERT(flags == O_RDONLY || flags == O_WRONLY|O_TRUNC|O_CREAT);
if(flags == O_WRONLY|O_TRUNC|O_CREAT)
mode = 0644;
else
mode = 0;
device = deviceByIndex(request.lock.deviceNum);
MY_ASSERT(strlen(LOCK_DIR)+strlen(device) < MaxPathLen);
strncpy(lockfile, LOCK_DIR"/LCK..", MaxPathLen);
strncat(lockfile, device + strlen("/dev/"),
MaxPathLen - strlen(lockfile));
lockfile[MaxPathLen] = '\0';
response.status = 0;
// TODO:
// struct stat st;
// if(stat(lockfile.data(), &st) == -1) {
// if(errno == EBADF)
// return -1;
// } else {
// // make sure that this is a regular file
// if(!S_ISREG(st.st_mode))
// return -1;
// }
if ((fd = open(lockfile, flags, mode)) == -1) {
Debug("error opening lockfile!");
lockfile[0] = '\0';
fd = open(DEVNULL, O_RDONLY);
response.status = -errno;
} else
fchown(fd, 0, 0);
sendFD(fd, &response);
close(fd);
break;
case RemoveLock:
Debug("Opener: received RemoveLock");
MY_ASSERT(len == sizeof(struct RemoveLockRequest));
close(ttyfd);
ttyfd = -1;
response.status = unlink(lockfile);
lockfile[0] = '\0';
sendResponse(&response);
break;
case OpenResolv:
Debug("Opener: received OpenResolv");
MY_ASSERT(len == sizeof(struct OpenResolvRequest));
flags = request.resolv.flags;
response.status = 0;
if ((fd = open(_PATH_RESCONF, flags)) == -1) {
Debug("error opening resolv.conf!");
fd = open(DEVNULL, O_RDONLY);
response.status = -errno;
}
sendFD(fd, &response);
close(fd);
break;
case OpenSysLog:
Debug("Opener: received OpenSysLog");
MY_ASSERT(len == sizeof(struct OpenLogRequest));
response.status = 0;
if ((fd = open("/var/log/messages", O_RDONLY)) == -1) {
if ((fd = open("/var/log/syslog.ppp", O_RDONLY)) == -1) {
Debug("error opening syslog file !");
fd = open(DEVNULL, O_RDONLY);
response.status = -errno;
}
}
sendFD(fd, &response);
close(fd);
break;
case SetSecret:
Debug("Opener: received SetSecret");
MY_ASSERT(len == sizeof(struct SetSecretRequest));
response.status = !createAuthFile(request.secret.method,
request.secret.username,
request.secret.password);
sendResponse(&response);
break;
case RemoveSecret:
Debug("Opener: received RemoveSecret");
MY_ASSERT(len == sizeof(struct RemoveSecretRequest));
response.status = !removeAuthFile(request.remove.method);
sendResponse(&response);
break;
case SetHostname:
Debug("Opener: received SetHostname");
MY_ASSERT(len == sizeof(struct SetHostnameRequest));
response.status = 0;
if(sethostname(request.host.name, strlen(request.host.name)))
response.status = -errno;
sendResponse(&response);
break;
case ExecPPPDaemon:
Debug("Opener: received ExecPPPDaemon");
MY_ASSERT(len == sizeof(struct ExecDaemonRequest));
response.status = execpppd(request.daemon.arguments);
sendResponse(&response);
break;
case KillPPPDaemon:
Debug("Opener: received KillPPPDaemon");
MY_ASSERT(len == sizeof(struct KillDaemonRequest));
response.status = killpppd();
sendResponse(&response);
break;
case Stop:
Debug("Opener: received STOP command");
_exit(0);
break;
default:
Debug("Opener: unknown command type. Exiting ...");
_exit(1);
}
} // else
}
}
//
// Send an open fd over a UNIX socket pair
//
kppp'Opener::sendFD() (./kdenetwork/kppp/opener.cpp:303)
int Opener::sendFD(int fd, struct ResponseHeader *response) {
struct { struct cmsghdr cmsg; int fd; } control;
struct msghdr msg;
struct iovec iov;
msg.msg_name = 0L;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
// Send data
iov.iov_base = IOV_BASE_CAST response;
iov.iov_len = sizeof(struct ResponseHeader);
// Send a (duplicate of) the file descriptor
control.cmsg.cmsg_len = sizeof(struct cmsghdr) + sizeof(int);
control.cmsg.cmsg_level = SOL_SOCKET;
control.cmsg.cmsg_type = MY_SCM_RIGHTS;
msg.msg_control = (char *) &control;
msg.msg_controllen = control.cmsg.cmsg_len;
#ifdef CMSG_DATA
*((int *)CMSG_DATA(&control.cmsg)) = fd;
#else
*((int *) &control.cmsg.cmsg_data) = fd;
#endif
if (sendmsg(socket, &msg, 0) < 0) {
perror("unable to send file descriptors");
return -1;
}
return 0;
}
kppp'Opener::sendResponse() (./kdenetwork/kppp/opener.cpp:340)
int Opener::sendResponse(struct ResponseHeader *response) {
struct msghdr msg;
struct iovec iov;
msg.msg_name = 0L;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = 0L;
msg.msg_controllen = 0;
// Send data
iov.iov_base = IOV_BASE_CAST response;
iov.iov_len = sizeof(struct ResponseHeader);
if (sendmsg(socket, &msg, 0) < 0) {
perror("unable to send response");
return -1;
}
return 0;
}
kppp'Opener::deviceByIndex() (./kdenetwork/kppp/opener.cpp:364)
const char* Opener::deviceByIndex(int idx) {
const char *device = 0L;
for(int i = 0; devices[i]; i++)
if(i == idx)
device = devices[i];
MY_ASSERT(device);
return device;
}
kppp'Opener::createAuthFile() (./kdenetwork/kppp/opener.cpp:375)
bool Opener::createAuthFile(Auth method, char *username, char *password) {
const char *authfile, *oldName, *newName;
char line[100];
char regexp[2*MaxStrLen+30];
regex_t preg;
if(!(authfile = authFile(method)))
return false;
if(!(newName = authFile(method, New)))
return false;
// look for username, "username" or 'username'
// if you modify this RE you have to adapt regexp's size above
sprintf(regexp, "^[ \t]*%s[ \t]\\|^[ \t]*[\"\']%s[\"\']",
username,username);
MY_ASSERT(regcomp(&preg, regexp, 0) == 0);
// copy to new file pap- or chap-secrets
int old_umask = umask(0077);
FILE *fout = fopen(newName, "w");
if(fout) {
// copy old file
FILE *fin = fopen(authfile, "r");
if(fin) {
while(fgets(line, sizeof(line), fin)) {
if(regexec(&preg, line, 0, 0L, 0) == 0)
continue;
fputs(line, fout);
}
fclose(fin);
}
// append user/pass pair
fprintf(fout, "\"%s\"\t*\t\"%s\"\n", username, password);
fclose(fout);
}
// restore umask
umask(old_umask);
// free memory allocated by regcomp
regfree(&preg);
if(!(oldName = authFile(method, Old)))
return false;
// delete old file if any
unlink(oldName);
rename(authfile, oldName);
rename(newName, authfile);
return true;
}
kppp'Opener::removeAuthFile() (./kdenetwork/kppp/opener.cpp:432)
bool Opener::removeAuthFile(Auth method) {
const char *authfile, *oldName;
if(!(authfile = authFile(method)))
return false;
if(!(oldName = authFile(method, Old)))
return false;
if(access(oldName, F_OK) == 0) {
unlink(authfile);
return (rename(oldName, authfile) == 0);
} else
return false;
}
kppp'Opener::authFile() (./kdenetwork/kppp/opener.cpp:448)
const char* Opener::authFile(Auth method, int version) {
switch(method|version) {
case PAP|Original:
return PAP_AUTH_FILE;
break;
case PAP|New:
return PAP_AUTH_FILE".new";
break;
case PAP|Old:
return PAP_AUTH_FILE".old";
break;
case CHAP|Original:
return CHAP_AUTH_FILE;
break;
case CHAP|New:
return CHAP_AUTH_FILE".new";
break;
case CHAP|Old:
return CHAP_AUTH_FILE".old";
break;
default:
return 0L;
}
}
kppp'Opener::execpppd() (./kdenetwork/kppp/opener.cpp:474)
bool Opener::execpppd(const char *arguments) {
char buf[MAX_CMDLEN];
char *args[MaxArgs];
pid_t pgrpid;
if(ttyfd<0)
return false;
pppdExitStatus = -1;
switch(pppdPid = fork())
{
case -1:
fprintf(stderr,"In parent: fork() failed\n");
return false;
break;
case 0:
// let's parse the arguments the user supplied into UNIX suitable form
// that is a list of pointers each pointing to exactly one word
strcpy(buf, arguments);
parseargs(buf, args);
// become a session leader and let /dev/ttySx
// be the controlling terminal.
pgrpid = setsid();
if(ioctl(ttyfd, TIOCSCTTY, 0)<0)
fprintf(stderr, "ioctl() failed.\n");
if(tcsetpgrp(ttyfd, pgrpid)<0)
fprintf(stderr, "tcsetpgrp() failed.\n");
dup2(ttyfd, 0);
dup2(ttyfd, 1);
switch (checkForInterface()) {
case 1:
fprintf(stderr, "Cannot determine if kernel supports ppp.\n");
break;
case -1:
fprintf(stderr, "Kernel does not support ppp, oops.\n");
break;
case 0:
fprintf(stderr, "Kernel supports ppp alright.\n");
break;
}
execve(pppdPath(), args, 0L);
_exit(0);
break;
default:
Debug2("In parent: pppd pid %d\n",pppdPid);
close(ttyfd);
ttyfd = -1;
return true;
break;
}
}
kppp'Opener::killpppd() (./kdenetwork/kppp/opener.cpp:533)
bool Opener::killpppd() {
if(pppdPid > 0) {
Debug2("In killpppd(): Sending SIGTERM to %d\n", pppdPid);
if(kill(pppdPid, SIGTERM) < 0) {
Debug2("Error terminating %d. Sending SIGKILL\n", pppdPid);
if(kill(pppdPid, SIGKILL) < 0) {
Debug2("Error killing %d\n", pppdPid);
return false;
}
}
}
return true;
}
kppp'Opener::parseargs() (./kdenetwork/kppp/opener.cpp:548)
void Opener::parseargs(char* buf, char** args) {
int nargs = 0;
int quotes;
while(nargs < MaxArgs-1 && *buf != '\0') {
quotes = 0;
// Strip whitespace. Use nulls, so that the previous argument is
// terminated automatically.
while ((*buf == ' ' ) || (*buf == '\t' ) || (*buf == '\n' ) )
*buf++ = '\0';
// detect begin of quoted argument
if (*buf == '"' || *buf == '\'') {
quotes = *buf;
*buf++ = '\0';
}
// save the argument
if(*buf != '\0') {
*args++ = buf;
nargs++;
}
if (!quotes)
while ((*buf != '\0') && (*buf != '\n') &&
(*buf != '\t') && (*buf != ' '))
buf++;
else {
while ((*buf != '\0') && (*buf != quotes))
buf++;
*buf++ = '\0';
}
}
*args = 0L;
}