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) |
51 | extern uid_t euid; |
52 | |
53 | // secure pppd location (opener.cpp) |
54 | extern 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 | |
62 | static 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 | |
93 | void 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 | |
142 | int 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 | |
159 | const 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 | |
177 | const 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 | |
189 | int 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 | |