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 |
49 | extern "C" unsigned int alarm(unsigned int); |
50 | #endif |
51 | |
52 | #ifdef _XPG4_2 |
53 | extern "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 | |
68 | Requester *Requester::rq = 0L; |
69 | |
70 | Requester::Requester(int s) : socket(s) { |
71 | assert(rq==0L); |
72 | rq = this; |
73 | lastStatus = -1; |
74 | } |
75 | |
76 | Requester::~Requester() { |
77 | } |
78 | |
79 | // |
80 | // Receive file name and file descriptors from envoy |
81 | // |
82 | int 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 | |
142 | bool 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 | |
174 | int 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 | |
186 | int 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 | |
200 | bool 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 | |
211 | int 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 | |
222 | int 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 | |
232 | bool 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 | |
263 | bool 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 | |
278 | bool 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 | |
290 | bool 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 | |
304 | bool 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 | |
312 | int 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 | |
320 | bool 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 | |
331 | bool Requester::(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 | |
355 | int 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 | |
366 | void recv_timeout(int) { |
367 | kDebug(5002) << "timeout()" ; |
368 | } |
369 | |