summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Weiss <holger@zedat.fu-berlin.de>2014-06-18 21:47:10 +0200
committerHolger Weiss <holger@zedat.fu-berlin.de>2014-06-18 21:47:10 +0200
commit91d04ad62d5272dd0e0e76af80e86ef912a3f643 (patch)
treeef7574789b32480496fb692ae7f6a1f42f05b50a
parentae24aaeefba290d910a8d8f945716ecc84ca02ca (diff)
downloadmonitoring-plugins-91d04ad62d5272dd0e0e76af80e86ef912a3f643.tar.gz
Add Gnulib module "idpriv-droptemp"
-rw-r--r--gl/Makefile.am10
-rw-r--r--gl/idpriv-droptemp.c204
-rw-r--r--gl/idpriv.h116
-rw-r--r--gl/m4/gnulib-cache.m43
-rw-r--r--gl/m4/gnulib-comp.m49
-rw-r--r--gl/m4/idpriv.m414
6 files changed, 352 insertions, 4 deletions
diff --git a/gl/Makefile.am b/gl/Makefile.am
index 4339b2c6..54abb4c7 100644
--- a/gl/Makefile.am
+++ b/gl/Makefile.am
@@ -21,7 +21,7 @@
21# the same distribution terms as the rest of that program. 21# the same distribution terms as the rest of that program.
22# 22#
23# Generated by gnulib-tool. 23# Generated by gnulib-tool.
24# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files base64 crypto/sha1 dirname environ floorf fsusage getaddrinfo gethostname getloadavg getopt-gnu gettext mountlist regex setenv strcase strsep timegm unsetenv vasprintf vsnprintf 24# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files base64 crypto/sha1 dirname environ floorf fsusage getaddrinfo gethostname getloadavg getopt-gnu gettext idpriv-droptemp mountlist regex setenv strcase strsep timegm unsetenv vasprintf vsnprintf
25 25
26AUTOMAKE_OPTIONS = 1.9.6 gnits subdir-objects 26AUTOMAKE_OPTIONS = 1.9.6 gnits subdir-objects
27 27
@@ -402,6 +402,14 @@ EXTRA_DIST += $(top_srcdir)/build-aux/config.rpath
402 402
403## end gnulib module havelib 403## end gnulib module havelib
404 404
405## begin gnulib module idpriv-droptemp
406
407libgnu_a_SOURCES += idpriv-droptemp.c
408
409EXTRA_DIST += idpriv.h
410
411## end gnulib module idpriv-droptemp
412
405## begin gnulib module inet_ntop 413## begin gnulib module inet_ntop
406 414
407 415
diff --git a/gl/idpriv-droptemp.c b/gl/idpriv-droptemp.c
new file mode 100644
index 00000000..13d1064e
--- /dev/null
+++ b/gl/idpriv-droptemp.c
@@ -0,0 +1,204 @@
1/* Dropping uid/gid privileges of the current process temporarily.
2 Copyright (C) 2009-2013 Free Software Foundation, Inc.
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
16
17#include <config.h>
18
19#include "idpriv.h"
20
21#include <errno.h>
22#include <stdlib.h>
23#include <sys/types.h>
24#include <unistd.h>
25
26/* The privileged uid and gid that the process had earlier. */
27#if HAVE_GETUID
28static int saved_uid = -1;
29#endif
30#if HAVE_GETGID
31static int saved_gid = -1;
32#endif
33
34int
35idpriv_temp_drop (void)
36{
37#if HAVE_GETEUID && HAVE_GETEGID && (HAVE_SETRESUID || HAVE_SETREUID) && (HAVE_SETRESGID || HAVE_SETREGID)
38 int uid = getuid ();
39 int gid = getgid ();
40
41 /* Find out about the privileged uid and gid at the first call. */
42 if (saved_uid == -1)
43 saved_uid = geteuid ();
44 if (saved_gid == -1)
45 saved_gid = getegid ();
46
47 /* Drop the gid privilege first, because in some cases the gid privilege
48 cannot be dropped after the uid privilege has been dropped. */
49
50 /* This is for executables that have the setgid bit set. */
51# if HAVE_SETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */
52 if (setresgid (-1, gid, saved_gid) < 0)
53 return -1;
54# else /* Mac OS X, NetBSD, AIX, IRIX, Solaris >= 2.5, OSF/1, Cygwin */
55 if (setregid (-1, gid) < 0)
56 return -1;
57# endif
58
59 /* This is for executables that have the setuid bit set. */
60# if HAVE_SETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */
61 /* See <http://www.usenix.org/events/sec02/full_papers/chen/chen.pdf>
62 figure 14. */
63 if (setresuid (-1, uid, saved_uid) < 0)
64 return -1;
65# else /* Mac OS X, NetBSD, AIX, IRIX, Solaris >= 2.5, OSF/1, Cygwin */
66 if (setreuid (-1, uid) < 0)
67 return -1;
68# endif
69
70 /* Verify that the privileges have really been dropped.
71 This verification is here for security reasons. Doesn't matter if it
72 takes a couple of system calls.
73 When the verification fails, it indicates that we need to use different
74 API in the code above. Therefore 'abort ()', not 'return -1'. */
75# if HAVE_GETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */
76 {
77 uid_t real;
78 uid_t effective;
79 uid_t saved;
80 if (getresuid (&real, &effective, &saved) < 0
81 || real != uid
82 || effective != uid
83 || saved != saved_uid)
84 abort ();
85 }
86# else
87# if HAVE_GETEUID
88 if (geteuid () != uid)
89 abort ();
90# endif
91 if (getuid () != uid)
92 abort ();
93# endif
94# if HAVE_GETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */
95 {
96 uid_t real;
97 uid_t effective;
98 uid_t saved;
99 if (getresgid (&real, &effective, &saved) < 0
100 || real != gid
101 || effective != gid
102 || saved != saved_gid)
103 abort ();
104 }
105# else
106# if HAVE_GETEGID
107 if (getegid () != gid)
108 abort ();
109# endif
110 if (getgid () != gid)
111 abort ();
112# endif
113
114 return 0;
115#else
116 errno = ENOSYS;
117 return -1;
118#endif
119}
120
121int
122idpriv_temp_restore (void)
123{
124#if HAVE_GETEUID && HAVE_GETEGID && (HAVE_SETRESUID || HAVE_SETREUID) && (HAVE_SETRESGID || HAVE_SETREGID)
125 int uid = getuid ();
126 int gid = getgid ();
127
128 if (saved_uid == -1 || saved_gid == -1)
129 /* Caller error: idpriv_temp_drop was never invoked. */
130 abort ();
131
132 /* Acquire the gid privilege last, because in some cases the gid privilege
133 cannot be acquired before the uid privilege has been acquired. */
134
135 /* This is for executables that have the setuid bit set. */
136# if HAVE_SETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */
137 /* See <http://www.usenix.org/events/sec02/full_papers/chen/chen.pdf>
138 figure 14. */
139 if (setresuid (-1, saved_uid, -1) < 0)
140 return -1;
141# else /* Mac OS X, NetBSD, AIX, IRIX, Solaris >= 2.5, OSF/1, Cygwin */
142 if (setreuid (-1, saved_uid) < 0)
143 return -1;
144# endif
145
146 /* This is for executables that have the setgid bit set. */
147# if HAVE_SETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */
148 if (setresgid (-1, saved_gid, -1) < 0)
149 return -1;
150# else /* Mac OS X, NetBSD, AIX, IRIX, Solaris >= 2.5, OSF/1, Cygwin */
151 if (setregid (-1, saved_gid) < 0)
152 return -1;
153# endif
154
155 /* Verify that the privileges have really been acquired.
156 This verification is here for security reasons. Doesn't matter if it
157 takes a couple of system calls.
158 When the verification fails, it indicates that we need to use different
159 API in the code above. Therefore 'abort ()', not 'return -1'. */
160# if HAVE_GETRESUID /* glibc, FreeBSD, OpenBSD, HP-UX */
161 {
162 uid_t real;
163 uid_t effective;
164 uid_t saved;
165 if (getresuid (&real, &effective, &saved) < 0
166 || real != uid
167 || effective != saved_uid
168 || saved != saved_uid)
169 abort ();
170 }
171# else
172# if HAVE_GETEUID
173 if (geteuid () != saved_uid)
174 abort ();
175# endif
176 if (getuid () != uid)
177 abort ();
178# endif
179# if HAVE_GETRESGID /* glibc, FreeBSD, OpenBSD, HP-UX */
180 {
181 uid_t real;
182 uid_t effective;
183 uid_t saved;
184 if (getresgid (&real, &effective, &saved) < 0
185 || real != gid
186 || effective != saved_gid
187 || saved != saved_gid)
188 abort ();
189 }
190# else
191# if HAVE_GETEGID
192 if (getegid () != saved_gid)
193 abort ();
194# endif
195 if (getgid () != gid)
196 abort ();
197# endif
198
199 return 0;
200#else
201 errno = ENOSYS;
202 return -1;
203#endif
204}
diff --git a/gl/idpriv.h b/gl/idpriv.h
new file mode 100644
index 00000000..f454a2cc
--- /dev/null
+++ b/gl/idpriv.h
@@ -0,0 +1,116 @@
1/* Dropping uid/gid privileges of the current process.
2 Copyright (C) 2009-2013 Free Software Foundation, Inc.
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
16
17#ifndef _IDPRIV_H
18#define _IDPRIV_H
19
20#ifdef __cplusplus
21extern "C" {
22#endif
23
24/* This module allows programs which are installed with setuid or setgid bit
25 (and which therefore initially run with an effective user id or group id
26 different from the one of the current user) to drop their uid or gid
27 privilege, either permanently or temporarily.
28
29 It is absolutely necessary to minimize the amount of code that is running
30 with escalated privileges (e.g. with effective uid = root). The reason is
31 that any bug or exploit in a part of a program that is running with
32 escalated privileges is a security vulnerability that - upon discovery -
33 puts the users in danger and requires immediate fixing. Then consider that
34 there's a bug every 10 or 20 lines of code on average...
35
36 For programs that temporarily drop privileges but have the ability to
37 restore them later, there are additionally the dangers that
38 - Any bug in the non-privileged part of the program may be used to
39 create invalid data structures that will trigger security
40 vulnerabilities in the privileged part of the program.
41 - Code execution exploits in the non-privileged part of the program may
42 be used to invoke the function that restores high privileges and then
43 execute additional arbitrary code.
44
45 1) The usual, and reasonably safe, way to minimize the amount of code
46 running with privileges is to create a separate executable, with setuid
47 or setgid bit, that contains only code for the tasks that require
48 privileges (and,of course, strict checking of the arguments, so that the
49 program cannot be abused). The main program is installed without setuid
50 or setgid bit.
51
52 2) A less safe way is to do some privileged tasks at the beginning of the
53 program's run, and drop privileges permanently as soon as possible.
54
55 Note: There may still be security issues if the privileged task puts
56 sensitive data into the process memory or opens communication channels
57 to restricted facilities.
58
59 3) The most unsafe way is to drop privileges temporarily for most of the
60 main program but to re-enable them for the duration of privileged tasks.
61
62 As explained above, this approach has uncontrollable dangers for
63 security.
64
65 This approach is normally not usable in multithreaded programs, because
66 you cannot know what kind of system calls the other threads could be
67 doing during the time the privileges are enabled.
68
69 With approach 1, you don't need gnulib modules.
70 With approach 2, you need the gnulib module 'idpriv-drop'.
71 With approach 3, you need the gnulib module 'idpriv-droptemp'. But really,
72 you should better stay away from this approach.
73 */
74
75/* For more in-depth discussion of these topics, see the papers/articles
76 * Hao Chen, David Wagner, Drew Dean: Setuid Demystified
77 <http://www.usenix.org/events/sec02/full_papers/chen/chen.pdf>
78 * Dan Tsafrir, Dilma da Silva, David Wagner: The Murky Issue of Changing
79 Process Identity: Revising "Setuid Demystified"
80 <http://www.eecs.berkeley.edu/~daw/papers/setuid-login08b.pdf>
81 <http://code.google.com/p/change-process-identity/>
82 * Dhruv Mohindra: Observe correct revocation order while relinquishing
83 privileges
84 <https://www.securecoding.cert.org/confluence/display/seccode/POS36-C.+Observe+correct+revocation+order+while+relinquishing+privileges>
85 */
86
87
88/* For approach 2. */
89
90/* Drop the uid and gid privileges of the current process.
91 Return 0 if successful, or -1 with errno set upon failure. The recommended
92 handling of failure is to terminate the process. */
93extern int idpriv_drop (void);
94
95
96/* For approach 3. */
97
98/* Drop the uid and gid privileges of the current process in a way that allows
99 them to be restored later.
100 Return 0 if successful, or -1 with errno set upon failure. The recommended
101 handling of failure is to terminate the process. */
102extern int idpriv_temp_drop (void);
103
104/* Restore the uid and gid privileges of the current process.
105 Return 0 if successful, or -1 with errno set upon failure. The recommended
106 handling of failure is to not perform the actions that require the escalated
107 privileges. */
108extern int idpriv_temp_restore (void);
109
110
111#ifdef __cplusplus
112}
113#endif
114
115
116#endif /* _IDPRIV_H */
diff --git a/gl/m4/gnulib-cache.m4 b/gl/m4/gnulib-cache.m4
index e61a5362..d6fca2a3 100644
--- a/gl/m4/gnulib-cache.m4
+++ b/gl/m4/gnulib-cache.m4
@@ -27,7 +27,7 @@
27 27
28 28
29# Specification in the form of a command-line invocation: 29# Specification in the form of a command-line invocation:
30# gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files base64 crypto/sha1 dirname environ floorf fsusage getaddrinfo gethostname getloadavg getopt-gnu gettext mountlist regex setenv strcase strsep timegm unsetenv vasprintf vsnprintf 30# gnulib-tool --import --dir=. --lib=libgnu --source-base=gl --m4-base=gl/m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files base64 crypto/sha1 dirname environ floorf fsusage getaddrinfo gethostname getloadavg getopt-gnu gettext idpriv-droptemp mountlist regex setenv strcase strsep timegm unsetenv vasprintf vsnprintf
31 31
32# Specification in the form of a few gnulib-tool.m4 macro invocations: 32# Specification in the form of a few gnulib-tool.m4 macro invocations:
33gl_LOCAL_DIR([]) 33gl_LOCAL_DIR([])
@@ -43,6 +43,7 @@ gl_MODULES([
43 getloadavg 43 getloadavg
44 getopt-gnu 44 getopt-gnu
45 gettext 45 gettext
46 idpriv-droptemp
46 mountlist 47 mountlist
47 regex 48 regex
48 setenv 49 setenv
diff --git a/gl/m4/gnulib-comp.m4 b/gl/m4/gnulib-comp.m4
index b3cb4c12..67a81566 100644
--- a/gl/m4/gnulib-comp.m4
+++ b/gl/m4/gnulib-comp.m4
@@ -28,7 +28,7 @@
28# other built files. 28# other built files.
29 29
30 30
31# This macro should be invoked from ./configure.in, in the section 31# This macro should be invoked from ./configure.ac, in the section
32# "Checks for programs", right after AC_PROG_CC, and certainly before 32# "Checks for programs", right after AC_PROG_CC, and certainly before
33# any checks for libraries, header files, types and library functions. 33# any checks for libraries, header files, types and library functions.
34AC_DEFUN([gl_EARLY], 34AC_DEFUN([gl_EARLY],
@@ -70,6 +70,7 @@ AC_DEFUN([gl_EARLY],
70 # Code from module gettext-h: 70 # Code from module gettext-h:
71 # Code from module havelib: 71 # Code from module havelib:
72 # Code from module hostent: 72 # Code from module hostent:
73 # Code from module idpriv-droptemp:
73 # Code from module include_next: 74 # Code from module include_next:
74 # Code from module inet_ntop: 75 # Code from module inet_ntop:
75 # Code from module intprops: 76 # Code from module intprops:
@@ -153,7 +154,7 @@ AC_DEFUN([gl_EARLY],
153 # Code from module xstrndup: 154 # Code from module xstrndup:
154]) 155])
155 156
156# This macro should be invoked from ./configure.in, in the section 157# This macro should be invoked from ./configure.ac, in the section
157# "Check for header files, types and library functions". 158# "Check for header files, types and library functions".
158AC_DEFUN([gl_INIT], 159AC_DEFUN([gl_INIT],
159[ 160[
@@ -258,6 +259,7 @@ AC_DEFUN([gl_INIT],
258 AC_SUBST([LIBINTL]) 259 AC_SUBST([LIBINTL])
259 AC_SUBST([LTLIBINTL]) 260 AC_SUBST([LTLIBINTL])
260 gl_HOSTENT 261 gl_HOSTENT
262 gl_IDPRIV
261 gl_FUNC_INET_NTOP 263 gl_FUNC_INET_NTOP
262 if test $HAVE_INET_NTOP = 0 || test $REPLACE_INET_NTOP = 1; then 264 if test $HAVE_INET_NTOP = 0 || test $REPLACE_INET_NTOP = 1; then
263 AC_LIBOBJ([inet_ntop]) 265 AC_LIBOBJ([inet_ntop])
@@ -658,6 +660,8 @@ AC_DEFUN([gl_FILE_LIST], [
658 lib/glthread/lock.c 660 lib/glthread/lock.c
659 lib/glthread/lock.h 661 lib/glthread/lock.h
660 lib/glthread/threadlib.c 662 lib/glthread/threadlib.c
663 lib/idpriv-droptemp.c
664 lib/idpriv.h
661 lib/inet_ntop.c 665 lib/inet_ntop.c
662 lib/intprops.h 666 lib/intprops.h
663 lib/itold.c 667 lib/itold.c
@@ -790,6 +794,7 @@ AC_DEFUN([gl_FILE_LIST], [
790 m4/gnulib-common.m4 794 m4/gnulib-common.m4
791 m4/hostent.m4 795 m4/hostent.m4
792 m4/iconv.m4 796 m4/iconv.m4
797 m4/idpriv.m4
793 m4/include_next.m4 798 m4/include_next.m4
794 m4/inet_ntop.m4 799 m4/inet_ntop.m4
795 m4/intdiv0.m4 800 m4/intdiv0.m4
diff --git a/gl/m4/idpriv.m4 b/gl/m4/idpriv.m4
new file mode 100644
index 00000000..167f5238
--- /dev/null
+++ b/gl/m4/idpriv.m4
@@ -0,0 +1,14 @@
1# idpriv.m4 serial 1
2dnl Copyright (C) 2009-2013 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved.
6
7AC_DEFUN([gl_IDPRIV],
8[
9 dnl Persuade glibc <unistd.h> to declare {get,set}res{uid,gid}.
10 AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
11
12 AC_CHECK_FUNCS_ONCE([getuid geteuid getresuid getgid getegid getresgid])
13 AC_CHECK_FUNCS_ONCE([setresuid setreuid seteuid setresgid setregid setegid])
14])