From Harald Welte:
[obnox/wireshark/wip.git] / wsutil / privileges.c
1 /* privileges.c
2  * Routines for handling privileges, e.g. set-UID and set-GID on UNIX.
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 2006 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #if defined(HAVE_SETRESUID) || defined(HAVE_SETREGUID)
30 #define _GNU_SOURCE /* Otherwise [sg]etres[gu]id won't be defined on Linux */
31 #endif
32
33 #include <glib.h>
34
35 #include "privileges.h"
36
37 #ifdef _WIN32
38 #include <windows.h>
39 #include <wchar.h>
40 #include <tchar.h>
41
42 /*
43  * Called when the program starts, to save whatever credential information
44  * we'll need later, and to do whatever other specialized platform-dependent
45  * initialization we want.
46  */
47 void
48 init_process_policies(void)
49 {
50         HMODULE kernel32Handle;
51         typedef BOOL (WINAPI *SetProcessDEPPolicyHandler)(DWORD);
52         SetProcessDEPPolicyHandler PSetProcessDEPPolicy;
53
54 #ifndef PROCESS_DEP_ENABLE
55 #define PROCESS_DEP_ENABLE 1
56 #endif
57
58         /*
59          * If we have SetProcessDEPPolicy(), turn "data execution
60          * prevention" on - i.e., if the MMU lets you set execute
61          * permission on a per-page basis, turn execute permission
62          * off on most data pages.  PSetProcessDEPPolicy() fails on
63          * 64-bit Windows (it's *always* on there), but if it fails,
64          * we don't care (we did our best), so we don't check for
65          * errors.
66          *
67          * XXX - if the GetModuleHandle() call fails, should we report
68          * an error?  That "shouldn't happen" - it's the equivalent
69          * of libc.{so,sl,a} or libSystem.dylib being missing on UN*X.
70          */
71         kernel32Handle = GetModuleHandle(_T("kernel32.dll"));
72         if (kernel32Handle != NULL) {
73                 PSetProcessDEPPolicy = (SetProcessDEPPolicyHandler) GetProcAddress(kernel32Handle, "SetProcessDEPPolicy");
74                 if (PSetProcessDEPPolicy) {
75                         PSetProcessDEPPolicy(PROCESS_DEP_ENABLE);
76                 }
77         }
78
79         npf_sys_is_running();
80 }
81
82 /*
83  * For now, we say the program wasn't started with special privileges.
84  * There are ways of running programs with credentials other than those
85  * for the session in which it's run, but I don't know whether that'd be
86  * done with Wireshark/TShark or not.
87  */
88 gboolean
89 started_with_special_privs(void)
90 {
91         return FALSE;
92 }
93
94 /*
95  * For now, we say the program isn't running with special privileges.
96  * There are ways of running programs with credentials other than those
97  * for the session in which it's run, but I don't know whether that'd be
98  * done with Wireshark/TShark or not.
99  */
100 gboolean
101 running_with_special_privs(void)
102 {
103         return FALSE;
104 }
105
106 /*
107  * For now, we don't do anything when asked to relinquish special privileges.
108  */
109 void
110 relinquish_special_privs_perm(void)
111 {
112 }
113
114 /*
115  * Get the current username.  String must be g_free()d after use.
116  */
117 gchar *
118 get_cur_username(void) {
119         gchar *username;
120         username = g_strdup("UNKNOWN");
121         return username;
122 }
123
124 /*
125  * Get the current group.  String must be g_free()d after use.
126  */
127 gchar *
128 get_cur_groupname(void) {
129         gchar *groupname;
130         groupname = g_strdup("UNKNOWN");
131         return groupname;
132 }
133
134 /*
135  * If npf.sys is running, return TRUE.
136  */
137 gboolean
138 npf_sys_is_running() {
139         SC_HANDLE h_scm, h_serv;
140         SERVICE_STATUS ss;
141
142         h_scm = OpenSCManager(NULL, NULL, 0);
143         if (!h_scm)
144                 return FALSE;
145
146         h_serv = OpenService(h_scm, _T("npf"), SC_MANAGER_CONNECT|SERVICE_QUERY_STATUS);
147         if (!h_serv)
148                 return FALSE;
149
150         if (QueryServiceStatus(h_serv, &ss)) {
151                 if (ss.dwCurrentState & SERVICE_RUNNING)
152                         return TRUE;
153         }
154         return FALSE;
155 }
156
157
158 #else /* _WIN32 */
159
160 #ifdef HAVE_SYS_TYPES_H
161 # include <sys/types.h>
162 #endif
163
164 #ifdef HAVE_UNISTD_H
165 #include <unistd.h>
166 #endif
167
168 #ifdef HAVE_PWD_H
169 #include <pwd.h>
170 #endif
171
172 #ifdef HAVE_GRP_H
173 #include <grp.h>
174 #endif
175
176 #include <glib.h>
177 #include <string.h>
178 #include <errno.h>
179
180 static uid_t ruid, euid;
181 static gid_t rgid, egid;
182 static gboolean init_process_policies_called = FALSE;
183
184 /*
185  * Called when the program starts, to save whatever credential information
186  * we'll need later, and to do whatever other specialized platform-dependent
187  * initialization we want.
188  *
189  * The credential information we'll need later on UNIX is the real and
190  * effective UID and GID.
191  *
192  * XXX - do any UN*Xes have opt-in "no execute on data pages by default"
193  * permission?  This would be the place to request it.
194  */
195 void
196 init_process_policies(void)
197 {
198         ruid = getuid();
199         euid = geteuid();
200         rgid = getgid();
201         egid = getegid();
202
203         init_process_policies_called = TRUE;
204 }
205
206 /*
207  * "Started with special privileges" means "started out set-UID or set-GID",
208  * or run as the root user or group.
209  */
210 gboolean
211 started_with_special_privs(void)
212 {
213         g_assert(init_process_policies_called);
214 #ifdef HAVE_ISSETUGID
215         return issetugid();
216 #else
217         return (ruid != euid || rgid != egid || ruid == 0 || rgid == 0);
218 #endif
219 }
220
221 /*
222  * Return TRUE if the real, effective, or saved (if we can check it) user
223  * ID or group are 0.
224  */
225 gboolean
226 running_with_special_privs(void)
227 {
228 #ifdef HAVE_SETRESUID
229         uid_t ru, eu, su;
230 #endif
231 #ifdef HAVE_SETRESGID
232         gid_t rg, eg, sg;
233 #endif
234
235 #ifdef HAVE_SETRESUID
236         getresuid(&ru, &eu, &su);
237         if (ru == 0 || eu == 0 || su == 0)
238                 return TRUE;
239 #else
240         if (getuid() == 0 || geteuid() == 0)
241                 return TRUE;
242 #endif
243 #ifdef HAVE_SETRESGID
244         getresgid(&rg, &eg, &sg);
245         if (rg == 0 || eg == 0 || sg == 0)
246                 return TRUE;
247 #else
248         if (getgid() == 0 || getegid() == 0)
249                 return TRUE;
250 #endif
251         return FALSE;
252 }
253
254 /*
255  * Permanently relinquish  set-UID and set-GID privileges.
256  * Ignore errors for now - if we have the privileges, we should
257  * be able to relinquish them.
258  */
259
260 void
261 relinquish_special_privs_perm(void)
262 {
263         /*
264          * If we were started with special privileges, set the
265          * real and effective group and user IDs to the original
266          * values of the real and effective group and user IDs.
267          * If we're not, don't bother - doing so seems to mung
268          * our group set, at least in OS X 10.5.
269          *
270          * (Set the effective UID last - that takes away our
271          * rights to set anything else.)
272          */
273         if (started_with_special_privs()) {
274 #ifdef HAVE_SETRESGID
275                 setresgid(rgid, rgid, rgid);
276 #else
277                 setgid(rgid);
278                 setegid(rgid);
279 #endif
280
281 #ifdef HAVE_SETRESUID
282                 setresuid(ruid, ruid, ruid);
283 #else
284                 setuid(ruid);
285                 seteuid(ruid);
286 #endif
287         }
288 }
289
290 /*
291  * Get the current username.  String must be g_free()d after use.
292  */
293 gchar *
294 get_cur_username(void) {
295         gchar *username;
296         struct passwd *pw = getpwuid(getuid());
297
298         if (pw) {
299                 username = g_strdup(pw->pw_name);
300         } else {
301                 username = g_strdup("UNKNOWN");
302         }
303         endpwent();
304         return username;
305 }
306
307 /*
308  * Get the current group.  String must be g_free()d after use.
309  */
310 gchar *
311 get_cur_groupname(void) {
312         gchar *groupname;
313         struct group *gr = getgrgid(getgid());
314
315         if (gr) {
316                 groupname = g_strdup(gr->gr_name);
317         } else {
318                 groupname = g_strdup("UNKNOWN");
319         }
320         endgrent();
321         return groupname;
322 }
323
324 #endif /* _WIN32 */
325
326 /*
327  * Editor modelines
328  *
329  * Local Variables:
330  * c-basic-offset: 8
331  * tab-width: 8
332  * indent-tabs-mode: t
333  * End:
334  *
335  * ex: set shiftwidth=8 tabstop=8 noexpandtab:
336  * :indentSize=8:tabSize=8:noTabs=false:
337  */