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