1/*
2 * kPPP: A pppd front end for the KDE project
3 *
4 * $Id$
5 *
6 * Copyright (C) 1997 Bernd Johannes Wuebben
7 * wuebben@math.cornell.edu
8 *
9 * This file was contributed by Mario Weilguni <mweilguni@sime.com>
10 * Thanks Mario !
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free
24 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 */
26
27#include <qdir.h>
28#include "runtests.h"
29#include <ctype.h>
30#include <unistd.h>
31#include <kmessagebox.h>
32#include <sys/stat.h>
33#include <stdlib.h>
34#include <sys/types.h>
35#include <pwd.h>
36#include <netinet/in.h>
37
38#ifdef HAVE_RESOLV_H
39#include <arpa/nameser.h>
40#include <resolv.h>
41#endif
42
43#ifndef _PATH_RESCONF
44#define _PATH_RESCONF "/etc/resolv.conf"
45#endif
46
47#include <klocale.h>
48#include "pppdata.h"
49
50// initial effective uid (main.cpp)
51extern uid_t euid;
52
53// secure pppd location (opener.cpp)
54extern const char* pppdPath();
55
56// shamelessly stolen from pppd-2.3.5
57/********************************************************************
58 *
59 * Internal routine to decode the version.modification.patch level
60 */
61
62static void decode_version (const char *_buf, int *version,
63 int *modification, int *patch)
64 {
65 char *buffer = qstrdup(_buf);
66 char *buf = buffer;
67 *version = (int) strtoul (buf, &buf, 10);
68 *modification = 0;
69 *patch = 0;
70
71 if (*buf == '.')
72 {
73 ++buf;
74 *modification = (int) strtoul (buf, &buf, 10);
75 if (*buf == '.')
76 {
77 ++buf;
78 *patch = (int) strtoul (buf, &buf, 10);
79 }
80 }
81
82 if (*buf != '\0')
83 {
84 *version =
85 *modification =
86 *patch = 0;
87 }
88
89 delete [] buffer;
90 }
91
92
93void pppdVersion(int *version, int *modification, int *patch) {
94 char buffer[30];
95 const char *pppd;
96 char *query;
97
98 *version = *modification = *patch = 0;
99
100 // locate pppd
101 if(!(pppd = pppdPath()))
102 return;
103
104 // call pppd with --version option
105 if(!(query = new char[strlen(pppd)+25]))
106 return;
107 strcpy(query, pppd);
108 // had to add a dummy device to prevent a "no device specified
109 // and stdin is not a tty" error from newer pppd versions.
110 strcat(query, " --version /dev/tty 2>&1");
111 fflush(0L);
112 FILE *output = popen(query, "r");
113 delete [] query;
114 if(!output)
115 return;
116
117 // read output
118 int size = fread(buffer, sizeof(char), 29, output);
119
120 if(ferror(output)) {
121 pclose(output);
122 return;
123 }
124 pclose(output);
125 buffer[size] = '\0';
126
127 // find position of version number x.y.z
128 char *p = buffer;
129 while(*p && !isdigit(*p))
130 p++;
131 if (*p == 0)
132 return;
133 char *p2 = p;
134 while(*p2 == '.' || isdigit(*p2))
135 p2++;
136 *p2 = '\0';
137
138 decode_version(p, version, modification, patch);
139}
140
141
142int uidFromName(const char *uname) {
143 struct passwd *pw;
144
145 setpwent();
146 while((pw = getpwent()) != NULL) {
147 if(strcmp(uname, pw->pw_name) == 0) {
148 int uid = pw->pw_uid;
149 endpwent();
150 return uid;
151 }
152 }
153
154 endpwent();
155 return -1;
156}
157
158
159const char *homedirFromUid(uid_t uid) {
160 struct passwd *pw;
161 char *d = 0;
162
163 setpwent();
164 while((pw = getpwent()) != NULL) {
165 if(pw->pw_uid == uid) {
166 d = strdup(pw->pw_dir);
167 endpwent();
168 return d;
169 }
170 }
171
172 endpwent();
173 return d;
174}
175
176
177const char* getHomeDir() {
178 static const char *hd = 0;
179 static bool ranTest = false;
180 if(!ranTest) {
181 hd = homedirFromUid(getuid());
182 ranTest = true;
183 }
184
185 return hd;
186}
187
188
189int runTests() {
190 int warning = 0;
191
192 // Test pre-1: check if the user is allowed to dial-out
193 if(access("/etc/kppp.allow", R_OK) == 0 && getuid() != 0) {
194 bool access = false;
195 FILE *f;
196 if((f = fopen("/etc/kppp.allow", "r")) != NULL) {
197 char buf[2048]; // safe
198 while(f != NULL && !feof(f)) {
199 if(fgets(buf, sizeof(buf), f) != NULL) {
200 QString s(buf);
201
202 s = s.trimmed();
203 if(s[0] == '#' || s.length() == 0)
204 continue;
205
206 if((uid_t)uidFromName(QFile::encodeName(s)) == getuid()) {
207 access = true;
208 fclose(f);
209 f = NULL;
210 }
211 }
212 }
213 if(f)
214 fclose(f);
215 }
216
217 if(!access) {
218 KMessageBox::error(0,
219 i18n("You are not allowed to dial out with "
220 "kppp.\nContact your system administrator."));
221 return TEST_CRITICAL;
222 }
223 }
224
225 // Test 1: search the pppd binary
226 const char *f = pppdPath();
227
228 if(!f) {
229 KMessageBox::error(0,
230 i18n("Cannot find the PPP daemon.\n"
231 "Make sure that pppd is installed."));
232 warning++;
233 }
234
235 // Test 2: check access to the pppd binary
236 if(f) {
237#if 0
238 if(access(f, X_OK) != 0 /* && geteuid() != 0 */) {
239 KMessageBox::error(0,
240 i18n("You do not have the permission "
241 "to start pppd.\n"
242 "Contact your system administrator "
243 "and ask to get access to pppd."));
244 return TEST_CRITICAL;
245 }
246#endif
247
248 if(euid != 0) {
249 struct stat st;
250 stat(f, &st);
251 if(st.st_uid != 0 || (st.st_mode & S_ISUID) == 0) {
252 KMessageBox::error(0,
253 i18n("You do not have sufficient permission to run:\n"
254 "%1\n"
255 "Please make sure that kppp is owned by root "
256 "and has the SUID bit set.", f));
257 warning++;
258 }
259 }
260 }
261
262 // Test 5: check for existence of /etc/resolv.conf
263 if (access(_PATH_RESCONF, R_OK) != 0) {
264 QString file = _PATH_RESCONF" ";
265 QString msgstr = i18n("%1 is missing or can not be read.\n"
266 "Ask your system administrator to create "
267 "this file (can be empty) with appropriate "
268 "read and write permissions.", file);
269 KMessageBox::error(0, msgstr);
270 warning ++;
271 }
272
273 if(warning == 0)
274 return TEST_OK;
275 else
276 return TEST_WARNING;
277}
278
279