Squelch a warning from the MSVC++ static analyzer (it's worried that
[metze/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 (*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                 if (PSetProcessDEPPolicy = (SetProcessDEPPolicyHandler) GetProcAddress(kernel32Handle, "SetProcessDEPPolicy")) {
74                         PSetProcessDEPPolicy(PROCESS_DEP_ENABLE);
75                 }
76         }
77
78         npf_sys_is_running();
79 }
80
81 /*
82  * For now, we say the program wasn't started with special privileges.
83  * There are ways of running programs with credentials other than those
84  * for the session in which it's run, but I don't know whether that'd be
85  * done with Wireshark/TShark or not.
86  */
87 gboolean
88 started_with_special_privs(void)
89 {
90         return FALSE;
91 }
92
93 /*
94  * For now, we say the program isn't running with special privileges.
95  * There are ways of running programs with credentials other than those
96  * for the session in which it's run, but I don't know whether that'd be
97  * done with Wireshark/TShark or not.
98  */
99 gboolean
100 running_with_special_privs(void)
101 {
102         return FALSE;
103 }
104
105 /*
106  * For now, we don't do anything when asked to relinquish special privileges.
107  */
108 void
109 relinquish_special_privs_perm(void)
110 {
111 }
112
113 /*
114  * Get the current username.  String must be g_free()d after use.
115  */
116 gchar *
117 get_cur_username(void) {
118         gchar *username;
119         username = g_strdup("UNKNOWN");
120         return username;
121 }
122
123 /*
124  * Get the current group.  String must be g_free()d after use.
125  */
126 gchar *
127 get_cur_groupname(void) {
128         gchar *groupname;
129         groupname = g_strdup("UNKNOWN");
130         return groupname;
131 }
132
133 /*
134  * If npf.sys is running, return TRUE.
135  */
136 gboolean
137 npf_sys_is_running() {
138         SC_HANDLE h_scm, h_serv;
139         SERVICE_STATUS ss;
140
141         h_scm = OpenSCManager(NULL, NULL, 0);
142         if (!h_scm)
143                 return FALSE;
144
145         h_serv = OpenService(h_scm, _T("npf"), SC_MANAGER_CONNECT|SERVICE_QUERY_STATUS);
146         if (!h_serv)
147                 return FALSE;
148
149         if (QueryServiceStatus(h_serv, &ss)) {
150                 if (ss.dwCurrentState & SERVICE_RUNNING)
151                         return TRUE;
152         }
153         return FALSE;
154 }
155
156
157 #else /* _WIN32 */
158
159 #ifdef HAVE_SYS_TYPES_H
160 # include <sys/types.h>
161 #endif
162
163 #ifdef HAVE_UNISTD_H
164 #include <unistd.h>
165 #endif
166
167 #ifdef HAVE_PWD_H
168 #include <pwd.h>
169 #endif
170
171 #ifdef HAVE_GRP_H
172 #include <grp.h>
173 #endif
174
175 #include <glib.h>
176 #include <string.h>
177 #include <errno.h>
178
179 static uid_t ruid, euid;
180 static gid_t rgid, egid;
181 static gboolean init_process_policies_called = FALSE;
182
183 /*
184  * Called when the program starts, to save whatever credential information
185  * we'll need later, and to do whatever other specialized platform-dependent
186  * initialization we want.
187  *
188  * The credential information we'll need later on UNIX is the real and
189  * effective UID and GID.
190  *
191  * XXX - do any UN*Xes have opt-in "no execute on data pages by default"
192  * permission?  This would be the place to request it.
193  */
194 void
195 init_process_policies(void)
196 {
197         ruid = getuid();
198         euid = geteuid();
199         rgid = getgid();
200         egid = getegid();
201
202         init_process_policies_called = TRUE;
203 }
204
205 /*
206  * "Started with special privileges" means "started out set-UID or set-GID",
207  * or run as the root user or group.
208  */
209 gboolean
210 started_with_special_privs(void)
211 {
212         g_assert(init_process_policies_called);
213 #ifdef HAVE_ISSETUGID
214         return issetugid();
215 #else
216         return (ruid != euid || rgid != egid || ruid == 0 || rgid == 0);
217 #endif
218 }
219
220 /*
221  * Return TRUE if the real, effective, or saved (if we can check it) user
222  * ID or group are 0.
223  */
224 gboolean
225 running_with_special_privs(void)
226 {
227 #ifdef HAVE_SETRESUID
228         uid_t ru, eu, su;
229 #endif
230 #ifdef HAVE_SETRESGID
231         gid_t rg, eg, sg;
232 #endif
233
234 #ifdef HAVE_SETRESUID
235         getresuid(&ru, &eu, &su);
236         if (ru == 0 || eu == 0 || su == 0)
237                 return TRUE;
238 #else
239         if (getuid() == 0 || geteuid() == 0)
240                 return TRUE;
241 #endif
242 #ifdef HAVE_SETRESGID
243         getresgid(&rg, &eg, &sg);
244         if (rg == 0 || eg == 0 || sg == 0)
245                 return TRUE;
246 #else
247         if (getgid() == 0 || getegid() == 0)
248                 return TRUE;
249 #endif
250         return FALSE;
251 }
252
253 /*
254  * Permanently relinquish  set-UID and set-GID privileges.
255  * Ignore errors for now - if we have the privileges, we should
256  * be able to relinquish them.
257  */
258
259 void
260 relinquish_special_privs_perm(void)
261 {
262         /*
263          * If we were started with special privileges, set the
264          * real and effective group and user IDs to the original
265          * values of the real and effective group and user IDs.
266          * If we're not, don't bother - doing so seems to mung
267          * our group set, at least in OS X 10.5.
268          *
269          * (Set the effective UID last - that takes away our
270          * rights to set anything else.)
271          */
272         if (started_with_special_privs()) {
273 #ifdef HAVE_SETRESGID
274                 setresgid(rgid, rgid, rgid);
275 #else
276                 setgid(rgid);
277                 setegid(rgid);
278 #endif
279
280 #ifdef HAVE_SETRESUID
281                 setresuid(ruid, ruid, ruid);
282 #else
283                 setuid(ruid);
284                 seteuid(ruid);
285 #endif
286         }
287 }
288
289 /*
290  * Get the current username.  String must be g_free()d after use.
291  */
292 gchar *
293 get_cur_username(void) {
294         gchar *username;
295         struct passwd *pw = getpwuid(getuid());
296
297         if (pw) {
298                 username = g_strdup(pw->pw_name);
299         } else {
300                 username = g_strdup("UNKNOWN");
301         }
302         endpwent();
303         return username;
304 }
305
306 /*
307  * Get the current group.  String must be g_free()d after use.
308  */
309 gchar *
310 get_cur_groupname(void) {
311         gchar *groupname;
312         struct group *gr = getgrgid(getgid());
313
314         if (gr) {
315                 groupname = g_strdup(gr->gr_name);
316         } else {
317                 groupname = g_strdup("UNKNOWN");
318         }
319         endgrent();
320         return groupname;
321 }
322
323 #endif /* _WIN32 */
324
325 /*
326  * Editor modelines
327  *
328  * Local Variables:
329  * c-basic-offset: 8
330  * tab-width: 8
331  * indent-tabs-mode: tabs
332  * End:
333  *
334  * ex: set shiftwidth=8 tabstop=8 noexpandtab
335  * :indentSize=8:tabSize=8:noTabs=false:
336  */