1/*
2 * kPPP: A pppd Front End for the KDE project
3 *
4 * $Id$
5 *
6 * Copyright (C) 1997,98 Bernd Johannes Wuebben,
7 * Mario Weilguni,
8 * Harri Porten
9 *
10 *
11 * This file was contributed by Harri Porten <porten@tu-harburg.de>
12 *
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Library General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public
25 * License along with this program; if not, write to the Free
26 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 */
28
29#ifdef __osf__
30#define _XOPEN_SOURCE_EXTENDED 1
31#endif
32
33
34#include <unistd.h>
35#include <stdlib.h>
36#include <stdio.h>
37#include <signal.h>
38#include <sys/uio.h>
39#include <sys/types.h>
40#include <sys/socket.h>
41#include <sys/un.h>
42#include <fcntl.h>
43#include <assert.h>
44#include <errno.h>
45#include <string.h>
46
47#ifdef __osf__
48#undef accept
49extern "C" unsigned int alarm(unsigned int);
50#endif
51
52#ifdef _XPG4_2
53extern "C" {
54 ssize_t sendmsg(int, const struct msghdr *, int);
55 ssize_t recvmsg(int, struct msghdr *, int);
56}
57#endif
58
59#include <kdebug.h>
60#include <qfile.h>
61
62#include "auth.h"
63#include "pppdata.h"
64#include "opener.h"
65#include "requester.h"
66#include "devices.h"
67
68Requester *Requester::rq = 0L;
69
70Requester::Requester(int s) : socket(s) {
71 assert(rq==0L);
72 rq = this;
73 lastStatus = -1;
74}
75
76Requester::~Requester() {
77}
78
79//
80// Receive file name and file descriptors from envoy
81//
82int Requester::recvFD() {
83 struct { struct cmsghdr cmsg; int fd; } control;
84 struct msghdr msg;
85 struct ResponseHeader response;
86
87 struct iovec iov;
88 int flags = 0, fd, len;
89 size_t cmsglen;
90
91 msg.msg_name = 0L;
92 msg.msg_namelen = 0;
93 msg.msg_iov = &iov;
94 msg.msg_iovlen = 1;
95
96 iov.iov_base = IOV_BASE_CAST &response;
97 iov.iov_len = sizeof(struct ResponseHeader);
98#ifdef CMSG_LEN
99 cmsglen = CMSG_LEN(sizeof(int));
100#else
101 cmsglen = sizeof(struct cmsghdr) + sizeof(int);
102#endif
103 control.cmsg.cmsg_len = cmsglen;
104 control.cmsg.cmsg_level = SOL_SOCKET;
105 control.cmsg.cmsg_type = MY_SCM_RIGHTS;
106
107 msg.msg_control = (char *) &control;
108 msg.msg_controllen = control.cmsg.cmsg_len;
109
110 fd = -1;
111
112 // set alarm in case recvmsg() hangs
113 signal(SIGALRM, recv_timeout);
114 alarm(2);
115
116 len = recvmsg(socket, &msg, flags);
117
118 alarm(0);
119 signal(SIGALRM, SIG_DFL);
120
121 if(len <= 0) {
122 kError(5002) << "recvmsg failed " << strerror(errno) << endl;
123 return -1;
124 } else if (msg.msg_controllen < cmsglen) {
125 kError(5002) << "recvmsg: truncated message " << strerror(errno) << endl;
126 exit(1);
127 } else {
128#ifdef CMSG_DATA
129 fd = *((int *)CMSG_DATA(&control.cmsg));
130#else
131 fd = *((int *) control.cmsg.cmsg_data);
132#endif
133 kDebug(5002) << "response.status: " << response.status;
134 assert(response.status <= 0);
135 if(response.status < 0)
136 return response.status;
137 }
138
139 return fd;
140}
141
142bool Requester::recvResponse() {
143
144 struct msghdr msg;
145 struct iovec iov;
146 struct ResponseHeader response;
147 int flags = 0, len;
148
149 msg.msg_name = 0L;
150 msg.msg_namelen = 0;
151 msg.msg_iov = &iov;
152 msg.msg_iovlen = 1;
153 msg.msg_control = 0L;
154 msg.msg_controllen = 0;
155
156 iov.iov_base = IOV_BASE_CAST &response;
157 iov.iov_len = sizeof(struct ResponseHeader);
158 kDebug(5002) << "recvResponse(): waiting for message";
159 len = recvmsg(socket, &msg, flags);
160 kDebug(5002) << "recvResponse(): received message";
161 if (len <= 0) {
162 if (errno == EINTR)
163 kDebug(5002) << "Interrupted system call. Continuing.";
164 else
165 perror("recvmsg failed");
166 } else {
167 kDebug(5002) << "response.status: " << response.status;
168 }
169
170 lastStatus = response.status;
171 return (response.status == 0);
172}
173
174int Requester::openModem(const QString & dev) {
175
176 struct OpenModemRequest req;
177 req.header.type = Opener::OpenDevice;
178 if((req.deviceNum = indexDevice(dev)) < 0)
179 return -1;
180
181 sendRequest((struct RequestHeader *) &req, sizeof(req));
182 return recvFD();
183}
184
185
186int Requester::openLockfile(const QString &dev, int flags) {
187
188 struct OpenLockRequest req;
189
190 req.header.type = Opener::OpenLock;
191 if((req.deviceNum = indexDevice(dev)) < 0)
192 return -1;
193 req.flags = flags;
194
195 sendRequest((struct RequestHeader *) &req, sizeof(req));
196 return recvFD();
197}
198
199
200bool Requester::removeLockfile() {
201
202 struct RemoveLockRequest req;
203
204 req.header.type = Opener::RemoveLock;
205
206 sendRequest((struct RequestHeader *) &req, sizeof(req));
207 return recvResponse();
208}
209
210
211int Requester::openResolv(int flags) {
212
213 struct OpenResolvRequest req;
214
215 req.header.type = Opener::OpenResolv;
216 req.flags = flags;
217 sendRequest((struct RequestHeader *) &req, sizeof(req));
218 return recvFD();
219}
220
221
222int Requester::openSysLog() {
223
224 struct OpenLogRequest req;
225
226 req.header.type = Opener::OpenSysLog;
227 sendRequest((struct RequestHeader *) &req, sizeof(req));
228 return recvFD();
229}
230
231
232bool Requester::setSecret(int method, const QString &name, const QString &password) {
233#ifdef __GNUC__
234#warning check if QString != 0 means using isNull or isEmpty
235#endif
236 assert(!name.isNull());
237 assert(!password.isNull());
238
239 if(method == AUTH_PAPCHAP)
240 return setSecret(AUTH_PAP, name, password) &&
241 setSecret(AUTH_CHAP, name, password);
242
243 struct SetSecretRequest req;
244 req.header.type = Opener::SetSecret;
245 switch(method) {
246 case AUTH_PAP:
247 req.method = Opener::PAP;
248 break;
249 case AUTH_CHAP:
250 req.method = Opener::CHAP;
251 break;
252 default:
253 return false;
254 }
255 strncpy(req.username, QFile::encodeName(name), Opener::MaxStrLen);
256 req.username[Opener::MaxStrLen] = '\0';
257 strncpy(req.password, QFile::encodeName(password), Opener::MaxStrLen);
258 req.password[Opener::MaxStrLen] = '\0';
259 sendRequest((struct RequestHeader *) &req, sizeof(req));
260 return recvResponse();
261}
262
263bool Requester::removeSecret(int authMethod) {
264 struct RemoveSecretRequest req;
265 req.header.type = Opener::RemoveSecret;
266 if(authMethod == AUTH_PAP)
267 req.method = Opener::PAP;
268 else
269 if(authMethod == AUTH_CHAP)
270 req.method = Opener::CHAP;
271 else
272 return false;
273
274 sendRequest((struct RequestHeader *) &req, sizeof(req));
275 return recvResponse();
276}
277
278bool Requester::setHostname(const QString &name) {
279 if (name.isEmpty())
280 return false;
281 struct SetHostnameRequest req;
282 req.header.type = Opener::SetHostname;
283 strncpy(req.name, QFile::encodeName(name), Opener::MaxStrLen);
284 req.name[Opener::MaxStrLen] = '\0';
285 sendRequest((struct RequestHeader *) &req, sizeof(req));
286 return recvResponse();
287}
288
289
290bool Requester::execPPPDaemon(const QString &arguments) {
291 struct ExecDaemonRequest req;
292 req.header.type = Opener::ExecPPPDaemon;
293 strncpy(req.arguments, QFile::encodeName(arguments), MAX_CMDLEN);
294 req.arguments[MAX_CMDLEN] = '\0';
295 sendRequest((struct RequestHeader *) &req, sizeof(req));
296 if(recvResponse()==0) {
297 gpppdata.setpppdRunning(true);
298 return true;
299 } else
300 return false;
301}
302
303
304bool Requester::killPPPDaemon() {
305 struct KillDaemonRequest req;
306 gpppdata.setpppdRunning(false);
307 req.header.type = Opener::KillPPPDaemon;
308 sendRequest((struct RequestHeader *) &req, sizeof(req));
309 return recvResponse();
310}
311
312int Requester::pppdExitStatus()
313{
314 struct PPPDExitStatusRequest req;
315 req.header.type = Opener::PPPDExitStatus;
316 sendRequest((struct RequestHeader *) &req, sizeof(req));
317 return recvResponse();
318}
319
320bool Requester::stop() {
321
322 struct StopRequest req;
323 req.header.type = Opener::Stop;
324 sendRequest((struct RequestHeader *) &req, sizeof(req));
325
326 // return recvResponse();
327 return true;
328}
329
330
331bool Requester::sendRequest(struct RequestHeader *request, int len) {
332
333 request->len = len - sizeof(struct RequestHeader);
334
335 struct msghdr msg;
336 struct iovec iov;
337
338 iov.iov_base = IOV_BASE_CAST request;
339 iov.iov_len = len;
340
341 msg.msg_name = 0L;
342 msg.msg_namelen = 0;
343 msg.msg_iov = &iov;
344 msg.msg_iovlen = 1;
345 msg.msg_control = 0L;
346 msg.msg_controllen = 0;
347 kDebug(5002) << "sendRequest: trying to send msg type " << request->type;
348 sendmsg(socket, &msg, 0);
349 kDebug(5002) << "sendRequest: sent message";
350
351 return true;
352}
353
354
355int Requester::indexDevice(const QString &dev) {
356
357 int index = -1;
358
359 for(int i = 0; devices[i]; i++)
360 if (dev == devices[i])
361 index = i;
362 return index;
363}
364
365
366void recv_timeout(int) {
367 kDebug(5002) << "timeout()";
368}
369