├── COPYING
├── Makefile
├── README.md
├── TODO.md
├── config.def.h
├── sha256.c
├── sha256.h
├── sup.1
├── sup.c
└── test.c
/COPYING:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | CC?=gcc
2 | LDD?=ld
3 | DESTDIR?=
4 | PREFIX?=/usr/local
5 | VERSION=1.1
6 | USER=root
7 | GROUP=root
8 |
9 | CFLAGS?=-Os -O2
10 |
11 | all: shared
12 |
13 | shared: CFLAGS+=-fPIC -fPIE -Wall
14 | shared: LDFLAGS=-fPIC -fPIE -pie
15 | shared: config.h sup.o sha256.o
16 | ${CC} ${LDFLAGS} sup.o sha256.o -o sup
17 |
18 | musl: musl=/usr/local/musl
19 | musl: CC=${musl}/bin/musl-gcc
20 | musl: CFLAGS+=-I${musl}/include
21 | musl: LDFLAGS+=-static ${musl}/lib/libc.a
22 | musl: config.h sup.o sha256.o
23 | ${CC} ${LDFLAGS} sup.o sha256.o -o sup
24 |
25 | test: CC=colorgcc
26 | test: CFLAGS+=--std=gnu99
27 | test: LDFLAGS=-lcrypto -lm
28 | test: config.h test.o sha256.o
29 | ${CC} ${LDFLAGS} test.o sha256.o -o test
30 |
31 | debug: CFLAGS+=-ggdb
32 | debug: sup.o
33 | ${CC} ${LDFLAGS} sup.o sha256.o -o sup
34 |
35 | config.h:
36 | cp config.def.h config.h
37 |
38 | .c.o:
39 | $(CC) $(CFLAGS) -c $< -o $@ -DVERSION=\"${VERSION}\"
40 |
41 | clean:
42 | rm -f *.o sup test
43 |
44 | mrproper: clean
45 | rm -f config.h
46 |
47 | install:
48 | mkdir -p ${DESTDIR}${PREFIX}/bin
49 | cp -f sup ${DESTDIR}${PREFIX}/bin
50 | -chown ${USER}:${GROUP} ${DESTDIR}/${PREFIX}/bin/sup
51 | -chmod 4111 ${DESTDIR}${PREFIX}/bin/sup
52 | mkdir -p ${DESTDIR}${PREFIX}/share/man/man1
53 | sed s,VERSION,${VERSION}, sup.1 \
54 | > ${DESTDIR}${PREFIX}/share/man/man1/sup.1
55 |
56 | website: README.md
57 | docco -l linear -o website README.md sup.c sha256.c
58 | ln -sf README.html website/index.html
59 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # sup
2 |
3 | ## a "small is beautiful" tool for unix privilege escalation
4 |
5 | `sup` is a very small and secure c application. it is designed to run as
6 | root (with suid bit on) to facilitate the privilege escalation of users
7 | to execute certain programs as superuser.
8 |
9 | all settings in sup are hard-coded at compile time. sup is very
10 | portable and self-contained, designed for production use as a static
11 | binary. sup is a sort of hard-coded `sudo`: it is an ideal companion
12 | for artisans building small containers and embedded systems.
13 |
14 | sup's new homepage is [sup.dyne.org](https://sup.dyne.org)
15 |
16 | sup code can be [read and reviewed on-line](https://sup.dyne.org/sup.html)
17 |
18 | stable releases can be downloaded from [files.dyne.org/sup](https://files.dyne.org/sup)
19 |
20 | releases are signed with the [maintainer's keys](https://keybase.io/jaromil)
21 |
22 | the develpment version of sup can be found at [git.devuan.org/jaromil/sup](https://git.devuan.org/jaromil/sup)
23 |
24 | of course there is also a [github mirror](https://github.com/dyne/sup)
25 |
26 | [](http://www.dyne.org)
27 |
28 | [origin]: https://git.devuan.org/jaromil/sup
29 | [m1]: https://github.com/dyne/sup
30 |
31 | ## why are you whispering?
32 |
33 | as you may have realised already, sup is so minimal that all its
34 | documentation is written lowercase. it was originally written in 2009 by
35 | pancake of nopcode.org and maintained until 2011 as part of the suckless
36 | tools. in 2016 sup is being adopted by jaromil of dyne.org, extending
37 | its features to support static build with [musl-libc]() and hardcoded
38 | sha256 hashing of binary files.
39 |
40 | [musl-libc]: http://www.musl-libc.org/
41 |
42 | ## configure
43 |
44 | sup's configuration resides in `config.h` and should be set before
45 | building. here below an intuitive example:
46 |
47 | ```c
48 | // sup's configuration file
49 | // need sup to be re-compiled for any change to be effective
50 |
51 | /// un/comment flags below to remove functionalities
52 | #define HASH 1
53 | #define DAEMON 1
54 | // #define DEBUG 1
55 |
56 | #ifndef FLAGSONLY
57 |
58 | #define USER 1000
59 | #define GROUP -1
60 |
61 | #define SETUID 0
62 | #define SETGID 0
63 |
64 | #define CHROOT ""
65 | #define CHRDIR ""
66 |
67 | static struct rule_t rules[] = {
68 | // allow user to run these programs when found at a specific path location
69 | { USER, GROUP, "whoami", "/usr/bin/whoami", "" },
70 | { USER, GROUP, "ifconfig", "/sbin/ifconfig", "" },
71 | { USER, GROUP, "ls", "/bin/ls", "" },
72 | { USER, GROUP, "wifi", "/root/wifi.sh", "" },
73 | // allow to run id when found with matching hash anywhere in PATH
74 | { USER, GROUP, "id", "*", "db533b77fc9e262209a46e0f.." },
75 | // allow to run any program found in PATH
76 | { USER, GROUP, "*", "*"},
77 | { 0 }, // end of configuration
78 | };
79 | #endif
80 | ```
81 |
82 | fields are organized as follows:
83 |
84 | | USER | GROUP | binary name | binary path | hash (optional) |
85 |
86 | - `USER` is the numeric id (UID) of the user authorized to execute the
87 | binary as superuser
88 | - `GROUP` is the numeric group (GID) of the user authorized to execute
89 | the binary as superuser (use -1 for none)
90 | - `binary name` is the command to run with `setuid/setgid`, e.g., `ls`
91 | - `binary path` is the path to the program, e.g., `/bin/ls`
92 | - `hash` can be computed before build using `sha256sum` (from GNU coreutils)
93 |
94 | `binary name` and `binary path` accept the wildcard character `*` to
95 | mean any executable, and anywhere in PATH, respectively.
96 |
97 | running `sup -l` will display the compiled-in configuration.
98 |
99 | ## build
100 |
101 | sup requires a c compiler and the gnu make tool to be built.
102 |
103 | a simple `make` command will build a sup binary good enough for
104 | evaluation purposes, with dynamic links to the `libm` and `libc`
105 | libraries installed system-wide.
106 |
107 | for production use, sup should be built as a static binary: this is
108 | easily done by first installing `musl-libc` in its default location
109 | (`/usr/local/musl`) and then using the `make musl` command inside sup.
110 |
111 | ## technical details
112 |
113 | sup consists of 3 files:
114 |
115 | - `sup.c` is the main source
116 | - `config.h` is the configuration, hardcoded at compile time
117 | - `sha256.c` is optional and provides the hashing functionality if
118 | `# define HASH 1` is set.
119 |
120 | sup is written in ansi c with posix1.b compliance for gnu/linux and
121 | bsd systems. it uses `setuid/gid` for privilege escalation and
122 | `execv()` to launch processes as superuser. daemon mode uses `fork()`
123 | to send processes in the background with `NOTTY` and `stdin/out/err`
124 | file descriptors set to `/dev/null`.
125 |
126 | ## frequently asked questions
127 |
128 | ### is there a package for sup?
129 |
130 | it does not make sense to have a sup package. sup is configured at
131 | build-time and its built binaries are specific to the task they have
132 | been built and set suid for. sup is a tool for people distributing
133 | containers, online services, embedded devices, and such.
134 |
135 | ### why not use doas (openbsd)?
136 |
137 | sup is different from `doas`, because `doas` is
138 | [configured at runtime][doas].
139 |
140 | [doas]: http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man5/doas.conf.5
141 |
142 | ### why not use sudo?
143 |
144 | same reason as above, `sudo` is configured at runtime.
145 |
146 | also `sudo` is very complex and therefore less secure, for instance [it has been found to be vulnerable to an heap-overflow attack](https://blog.qualys.com/vulnerabilities-research/2021/01/26/cve-2021-3156-heap-based-buffer-overflow-in-sudo-baron-samedit) for a bug that went unnoticed for 10 years.
147 |
148 | ### why not use su?
149 |
150 | sup is made so that people (or scripts) don't have to type passwords
151 | every time they need to execute something they are entitled to execute
152 | as superusers. with `su` one has to type the root password every time.
153 | also scripts won't work without interaction.
154 |
155 | ### is sup still a suckless tool?
156 |
157 | this new code hasn't been grinded by the merry folks at suckless yet,
158 | but pancake has acknowledged this development and, having left
159 | maintainance, is happy to hand it over to jaromil.
160 |
161 | ## licensing
162 |
163 | sup is copyleft software licensed as gnu lesser public license
164 | (lgplv3). when compiled with hashing capability, its license turns into
165 | gnu gplv2+ because of the sha256 component.
166 |
167 | ```
168 | sup is copyleft (c) 2009-2011 by pancake of nopcode.org
169 | . (c) 2016 by jaromil of dyne.org
170 | the fips-180-2 sha-256 implementation optionally included in sup is
171 | copyleft (c) 2001-2003 by christophe cevine
172 | ```
173 |
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
1 | # TODO / wishlist
2 |
3 | ## Improve runtime documentation and manpage
4 |
5 | Print out more information on -help and complete manpage with all
6 | possible options and flags compiled at runtime.
7 |
8 | ## Eliminate all dynamic memory allocation
9 |
10 | When parsing binaries for checksum do not allocate their size
11 | dynamically in memory, but load fixed size chunks and use
12 | sha256_update on each one.
13 |
14 | ## Send signals to process names (kill etc.)
15 |
16 | Allow to send signals (default SIGTERM for kill) to PIDs of
17 | processes whose name matches the authorized list.
18 | This should be a compile-time flag.
19 |
20 | ## Daemon mode flag
21 |
22 | Isolate daemon forking code into #ifdefs to make it optional at
23 | compile time.
24 |
25 | ## Setuidgid flag
26 |
27 | Isolate target_uid/gid options into #ifdefs to make then optional
28 | at compile time.
29 |
--------------------------------------------------------------------------------
/config.def.h:
--------------------------------------------------------------------------------
1 | // sup's configuration file
2 | // need sup to be re-compiled for any change to be effective
3 |
4 | /// un/comment flags below to remove functionalities
5 | #define HASH 1
6 | #define DAEMON 1
7 | // #define DEBUG 1
8 |
9 | #ifndef FLAGSONLY
10 |
11 | #define USER 1000
12 | #define GROUP -1
13 |
14 | #define SETUID 0
15 | #define SETGID 0
16 |
17 | #define CHROOT ""
18 | #define CHRDIR ""
19 |
20 | static struct rule_t rules[] = {
21 | // allow user to run these programs when found in path location
22 | { USER, GROUP, "whoami", "/usr/bin/whoami", "" },
23 | { USER, GROUP, "ifconfig", "/sbin/ifconfig", "" },
24 | { USER, GROUP, "ls", "/bin/ls", "" },
25 | { USER, GROUP, "wifi", "/root/wifi.sh", "" },
26 |
27 | // allow to run this program when found in PATH */
28 | { USER, GROUP, "id", "*", "db533b77fc9e262209a46e0fe5bec646c1d2ed4e33285dc61da09dbc4caf6fa6" },
29 | /* { USER, GROUP, "*", "*"}, // allow to run any program found in PATH */
30 | { 0 },
31 | };
32 |
33 | #endif
34 |
--------------------------------------------------------------------------------
/sha256.c:
--------------------------------------------------------------------------------
1 | /*
2 | * FIPS-180-2 compliant SHA-256 implementation
3 | *
4 | * Copyright (C) 2001-2003 Christophe Devine
5 | *
6 | * This program is free software; you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation; either version 2 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program; if not, write to the Free Software
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 | */
20 |
21 | #define FLAGSONLY 1
22 | #include "config.h"
23 | // this is not compiled in if HASH is not set
24 | // meaning the license above doesn't applies.
25 | #ifdef HASH
26 |
27 | #include
28 |
29 | #include "sha256.h"
30 |
31 | #define GET_UINT32(n,b,i) \
32 | { \
33 | (n) = ( (uint32) (b)[(i) ] << 24 ) \
34 | | ( (uint32) (b)[(i) + 1] << 16 ) \
35 | | ( (uint32) (b)[(i) + 2] << 8 ) \
36 | | ( (uint32) (b)[(i) + 3] ); \
37 | }
38 |
39 | #define PUT_UINT32(n,b,i) \
40 | { \
41 | (b)[(i) ] = (uint8) ( (n) >> 24 ); \
42 | (b)[(i) + 1] = (uint8) ( (n) >> 16 ); \
43 | (b)[(i) + 2] = (uint8) ( (n) >> 8 ); \
44 | (b)[(i) + 3] = (uint8) ( (n) ); \
45 | }
46 |
47 | void sha256_starts( sha256_context *ctx )
48 | {
49 | ctx->total[0] = 0;
50 | ctx->total[1] = 0;
51 |
52 | ctx->state[0] = 0x6A09E667;
53 | ctx->state[1] = 0xBB67AE85;
54 | ctx->state[2] = 0x3C6EF372;
55 | ctx->state[3] = 0xA54FF53A;
56 | ctx->state[4] = 0x510E527F;
57 | ctx->state[5] = 0x9B05688C;
58 | ctx->state[6] = 0x1F83D9AB;
59 | ctx->state[7] = 0x5BE0CD19;
60 | }
61 |
62 | void sha256_process( sha256_context *ctx, uint8 data[64] )
63 | {
64 | uint32 temp1, temp2, W[64];
65 | uint32 A, B, C, D, E, F, G, H;
66 |
67 | GET_UINT32( W[0], data, 0 );
68 | GET_UINT32( W[1], data, 4 );
69 | GET_UINT32( W[2], data, 8 );
70 | GET_UINT32( W[3], data, 12 );
71 | GET_UINT32( W[4], data, 16 );
72 | GET_UINT32( W[5], data, 20 );
73 | GET_UINT32( W[6], data, 24 );
74 | GET_UINT32( W[7], data, 28 );
75 | GET_UINT32( W[8], data, 32 );
76 | GET_UINT32( W[9], data, 36 );
77 | GET_UINT32( W[10], data, 40 );
78 | GET_UINT32( W[11], data, 44 );
79 | GET_UINT32( W[12], data, 48 );
80 | GET_UINT32( W[13], data, 52 );
81 | GET_UINT32( W[14], data, 56 );
82 | GET_UINT32( W[15], data, 60 );
83 |
84 | #define SHR(x,n) ((x & 0xFFFFFFFF) >> n)
85 | #define ROTR(x,n) (SHR(x,n) | (x << (32 - n)))
86 |
87 | #define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3))
88 | #define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10))
89 |
90 | #define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22))
91 | #define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25))
92 |
93 | #define F0(x,y,z) ((x & y) | (z & (x | y)))
94 | #define F1(x,y,z) (z ^ (x & (y ^ z)))
95 |
96 | #define R(t) \
97 | ( \
98 | W[t] = S1(W[t - 2]) + W[t - 7] + \
99 | S0(W[t - 15]) + W[t - 16] \
100 | )
101 |
102 | #define P(a,b,c,d,e,f,g,h,x,K) \
103 | { \
104 | temp1 = h + S3(e) + F1(e,f,g) + K + x; \
105 | temp2 = S2(a) + F0(a,b,c); \
106 | d += temp1; h = temp1 + temp2; \
107 | }
108 |
109 | A = ctx->state[0];
110 | B = ctx->state[1];
111 | C = ctx->state[2];
112 | D = ctx->state[3];
113 | E = ctx->state[4];
114 | F = ctx->state[5];
115 | G = ctx->state[6];
116 | H = ctx->state[7];
117 |
118 | P( A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98 );
119 | P( H, A, B, C, D, E, F, G, W[ 1], 0x71374491 );
120 | P( G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF );
121 | P( F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5 );
122 | P( E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B );
123 | P( D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1 );
124 | P( C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4 );
125 | P( B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5 );
126 | P( A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98 );
127 | P( H, A, B, C, D, E, F, G, W[ 9], 0x12835B01 );
128 | P( G, H, A, B, C, D, E, F, W[10], 0x243185BE );
129 | P( F, G, H, A, B, C, D, E, W[11], 0x550C7DC3 );
130 | P( E, F, G, H, A, B, C, D, W[12], 0x72BE5D74 );
131 | P( D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE );
132 | P( C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7 );
133 | P( B, C, D, E, F, G, H, A, W[15], 0xC19BF174 );
134 | P( A, B, C, D, E, F, G, H, R(16), 0xE49B69C1 );
135 | P( H, A, B, C, D, E, F, G, R(17), 0xEFBE4786 );
136 | P( G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6 );
137 | P( F, G, H, A, B, C, D, E, R(19), 0x240CA1CC );
138 | P( E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F );
139 | P( D, E, F, G, H, A, B, C, R(21), 0x4A7484AA );
140 | P( C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC );
141 | P( B, C, D, E, F, G, H, A, R(23), 0x76F988DA );
142 | P( A, B, C, D, E, F, G, H, R(24), 0x983E5152 );
143 | P( H, A, B, C, D, E, F, G, R(25), 0xA831C66D );
144 | P( G, H, A, B, C, D, E, F, R(26), 0xB00327C8 );
145 | P( F, G, H, A, B, C, D, E, R(27), 0xBF597FC7 );
146 | P( E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3 );
147 | P( D, E, F, G, H, A, B, C, R(29), 0xD5A79147 );
148 | P( C, D, E, F, G, H, A, B, R(30), 0x06CA6351 );
149 | P( B, C, D, E, F, G, H, A, R(31), 0x14292967 );
150 | P( A, B, C, D, E, F, G, H, R(32), 0x27B70A85 );
151 | P( H, A, B, C, D, E, F, G, R(33), 0x2E1B2138 );
152 | P( G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC );
153 | P( F, G, H, A, B, C, D, E, R(35), 0x53380D13 );
154 | P( E, F, G, H, A, B, C, D, R(36), 0x650A7354 );
155 | P( D, E, F, G, H, A, B, C, R(37), 0x766A0ABB );
156 | P( C, D, E, F, G, H, A, B, R(38), 0x81C2C92E );
157 | P( B, C, D, E, F, G, H, A, R(39), 0x92722C85 );
158 | P( A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1 );
159 | P( H, A, B, C, D, E, F, G, R(41), 0xA81A664B );
160 | P( G, H, A, B, C, D, E, F, R(42), 0xC24B8B70 );
161 | P( F, G, H, A, B, C, D, E, R(43), 0xC76C51A3 );
162 | P( E, F, G, H, A, B, C, D, R(44), 0xD192E819 );
163 | P( D, E, F, G, H, A, B, C, R(45), 0xD6990624 );
164 | P( C, D, E, F, G, H, A, B, R(46), 0xF40E3585 );
165 | P( B, C, D, E, F, G, H, A, R(47), 0x106AA070 );
166 | P( A, B, C, D, E, F, G, H, R(48), 0x19A4C116 );
167 | P( H, A, B, C, D, E, F, G, R(49), 0x1E376C08 );
168 | P( G, H, A, B, C, D, E, F, R(50), 0x2748774C );
169 | P( F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5 );
170 | P( E, F, G, H, A, B, C, D, R(52), 0x391C0CB3 );
171 | P( D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A );
172 | P( C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F );
173 | P( B, C, D, E, F, G, H, A, R(55), 0x682E6FF3 );
174 | P( A, B, C, D, E, F, G, H, R(56), 0x748F82EE );
175 | P( H, A, B, C, D, E, F, G, R(57), 0x78A5636F );
176 | P( G, H, A, B, C, D, E, F, R(58), 0x84C87814 );
177 | P( F, G, H, A, B, C, D, E, R(59), 0x8CC70208 );
178 | P( E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA );
179 | P( D, E, F, G, H, A, B, C, R(61), 0xA4506CEB );
180 | P( C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7 );
181 | P( B, C, D, E, F, G, H, A, R(63), 0xC67178F2 );
182 |
183 | ctx->state[0] += A;
184 | ctx->state[1] += B;
185 | ctx->state[2] += C;
186 | ctx->state[3] += D;
187 | ctx->state[4] += E;
188 | ctx->state[5] += F;
189 | ctx->state[6] += G;
190 | ctx->state[7] += H;
191 | }
192 |
193 | void sha256_update( sha256_context *ctx, uint8 *input, uint32 length )
194 | {
195 | uint32 left, fill;
196 |
197 | if( ! length ) return;
198 |
199 | left = ctx->total[0] & 0x3F;
200 | fill = 64 - left;
201 |
202 | ctx->total[0] += length;
203 | ctx->total[0] &= 0xFFFFFFFF;
204 |
205 | if( ctx->total[0] < length )
206 | ctx->total[1]++;
207 |
208 | if( left && length >= fill )
209 | {
210 | memcpy( (void *) (ctx->buffer + left),
211 | (void *) input, fill );
212 | sha256_process( ctx, ctx->buffer );
213 | length -= fill;
214 | input += fill;
215 | left = 0;
216 | }
217 |
218 | while( length >= 64 )
219 | {
220 | sha256_process( ctx, input );
221 | length -= 64;
222 | input += 64;
223 | }
224 |
225 | if( length )
226 | {
227 | memcpy( (void *) (ctx->buffer + left),
228 | (void *) input, length );
229 | }
230 | }
231 |
232 | static uint8 sha256_padding[64] =
233 | {
234 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
235 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
236 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
237 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
238 | };
239 |
240 | void sha256_finish( sha256_context *ctx, uint8 digest[32] )
241 | {
242 | uint32 last, padn;
243 | uint32 high, low;
244 | uint8 msglen[8];
245 |
246 | high = ( ctx->total[0] >> 29 )
247 | | ( ctx->total[1] << 3 );
248 | low = ( ctx->total[0] << 3 );
249 |
250 | PUT_UINT32( high, msglen, 0 );
251 | PUT_UINT32( low, msglen, 4 );
252 |
253 | last = ctx->total[0] & 0x3F;
254 | padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
255 |
256 | sha256_update( ctx, sha256_padding, padn );
257 | sha256_update( ctx, msglen, 8 );
258 |
259 | PUT_UINT32( ctx->state[0], digest, 0 );
260 | PUT_UINT32( ctx->state[1], digest, 4 );
261 | PUT_UINT32( ctx->state[2], digest, 8 );
262 | PUT_UINT32( ctx->state[3], digest, 12 );
263 | PUT_UINT32( ctx->state[4], digest, 16 );
264 | PUT_UINT32( ctx->state[5], digest, 20 );
265 | PUT_UINT32( ctx->state[6], digest, 24 );
266 | PUT_UINT32( ctx->state[7], digest, 28 );
267 | }
268 |
269 | #endif
270 |
271 | #ifdef TEST
272 |
273 | #include
274 | #include
275 |
276 | /*
277 | * those are the standard FIPS-180-2 test vectors
278 | */
279 |
280 | static char *msg[] =
281 | {
282 | "abc",
283 | "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
284 | NULL
285 | };
286 |
287 | static char *val[] =
288 | {
289 | "ba7816bf8f01cfea414140de5dae2223" \
290 | "b00361a396177a9cb410ff61f20015ad",
291 | "248d6a61d20638b8e5c026930c3e6039" \
292 | "a33ce45964ff2167f6ecedd419db06c1",
293 | "cdc76e5c9914fb9281a1c7e284d73e67" \
294 | "f1809a48a497200e046d39ccc7112cd0"
295 | };
296 |
297 | int main( int argc, char *argv[] )
298 | {
299 | FILE *f;
300 | int i, j;
301 | char output[65];
302 | sha256_context ctx;
303 | unsigned char buf[1000];
304 | unsigned char sha256sum[32];
305 |
306 | if( argc < 2 )
307 | {
308 | printf( "\n SHA-256 Validation Tests:\n\n" );
309 |
310 | for( i = 0; i < 3; i++ )
311 | {
312 | printf( " Test %d ", i + 1 );
313 |
314 | sha256_starts( &ctx );
315 |
316 | if( i < 2 )
317 | {
318 | sha256_update( &ctx, (uint8 *) msg[i],
319 | strlen( msg[i] ) );
320 | }
321 | else
322 | {
323 | memset( buf, 'a', 1000 );
324 |
325 | for( j = 0; j < 1000; j++ )
326 | {
327 | sha256_update( &ctx, (uint8 *) buf, 1000 );
328 | }
329 | }
330 |
331 | sha256_finish( &ctx, sha256sum );
332 |
333 | for( j = 0; j < 32; j++ )
334 | {
335 | sprintf( output + j * 2, "%02x", sha256sum[j] );
336 | }
337 |
338 | if( memcmp( output, val[i], 64 ) )
339 | {
340 | printf( "failed!\n" );
341 | return( 1 );
342 | }
343 |
344 | printf( "passed.\n" );
345 | }
346 |
347 | printf( "\n" );
348 | }
349 | else
350 | {
351 | if( ! ( f = fopen( argv[1], "rb" ) ) )
352 | {
353 | perror( "fopen" );
354 | return( 1 );
355 | }
356 |
357 | sha256_starts( &ctx );
358 |
359 | while( ( i = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
360 | {
361 | sha256_update( &ctx, buf, i );
362 | }
363 |
364 | sha256_finish( &ctx, sha256sum );
365 |
366 | for( j = 0; j < 32; j++ )
367 | {
368 | printf( "%02x", sha256sum[j] );
369 | }
370 |
371 | printf( " %s\n", argv[1] );
372 | }
373 |
374 | return( 0 );
375 | }
376 |
377 | #endif
378 |
--------------------------------------------------------------------------------
/sha256.h:
--------------------------------------------------------------------------------
1 | #ifndef _SHA256_H
2 | #define _SHA256_H
3 |
4 | #ifndef uint8
5 | #define uint8 unsigned char
6 | #endif
7 |
8 | #ifndef uint32
9 | #define uint32 unsigned long int
10 | #endif
11 |
12 | typedef struct
13 | {
14 | uint32 total[2];
15 | uint32 state[8];
16 | uint8 buffer[64];
17 | }
18 | sha256_context;
19 |
20 | void sha256_starts( sha256_context *ctx );
21 | void sha256_update( sha256_context *ctx, uint8 *input, uint32 length );
22 | void sha256_finish( sha256_context *ctx, uint8 digest[32] );
23 |
24 | #endif /* sha256.h */
25 |
--------------------------------------------------------------------------------
/sup.1:
--------------------------------------------------------------------------------
1 | .TH SUP 1 sup\-1.2
2 | .SH NAME
3 | sup - a "small is beautiful" tool for UNIX privilege escalation
4 | .SH SYNOPSIS
5 | .B sup
6 | [ \fB-h -v\fR ]
7 | [ \fB-l\fR ]
8 | [ \fB-u \fIuser\fR \fB-g \fIgroup\fR ]
9 | [ \fB-b \fB-p \fIpidfile\fR ]
10 | \fBcommand\fR [ \fBargs...\fR ]
11 | .SH DESCRIPTION
12 | sup is a very small and secure C application. it is designed to run as root (with suid bit on) to facilitate the privilege escalation of users to execute certain programs as superuser.
13 | .P
14 | all settings in sup are hard-coded at compile time. sup is very portable and self-contained, designed for production use as a static binary. sup is a sort of hard-coded sudo: it is an ideal companion for artisans building small containers and embedded systems.
15 | .SH OPTIONS
16 | .TP
17 | .B \-h
18 | print help message
19 | .TP
20 | .B \-l
21 | list hardcoded configuration
22 | .TP
23 | .B \-v
24 | print version information
25 | .TP
26 | .B \-b
27 | run in daemon mode: fork process to background
28 | .TP
29 | .B \-p pidfile
30 | when in daemon mode, save first pid to file. beware this may not be the exact final pid of the forked process: some programs are more complex and go further forking new pids.
31 | .TP
32 | .B \-u username
33 | username for the target uid in setuid, in case not root. looked up by getpwnam(3) in /etc/passwd.
34 | .TP
35 | .B \-g groupname
36 | groupname for the target gid in setuid, in case not root. looked up by getpwnam(3) in /etc/passwd.
37 |
38 |
39 | .SH AUTHOR
40 | sup is copyleft software licensed as GNU Lesser Public License
41 | (LGPLv3). when compiled with the HASH flag on its license turns
42 | into GNU GPLv2 because of the sha256 component.
43 | .P
44 | sup is copyleft (c) 2009-2011 by pancake of nopcode.org
45 | .BR
46 | (c) 2016 by jaromil of dyne.org
47 | .P
48 | the FIPS-180-2 sha-256 implementation optionally included in sup is
49 | copyleft (c) 2001-2003 by Christophe Devine
50 |
--------------------------------------------------------------------------------
/sup.c:
--------------------------------------------------------------------------------
1 | // sup 1.2
2 |
3 | // (c) 2016 Dyne.org Foundation, Amsterdam
4 |
5 | // Written by:
6 | // - 2009-2011 pancake
7 | // - 2016 Denis Roio
8 |
9 | // License (LGPLv3)
10 | // -------
11 |
12 | // This source code is free software; you can redistribute it and/or
13 | // modify it under the terms of the GNU Lesser General Public License
14 | // as published by the Free Software Foundation; either version 3 of
15 | // the License, or (at your option) any later version.
16 |
17 | // This source code 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. Please refer
20 | // to the GNU Lesser General Public License for more details.
21 |
22 | // You should have received a copy of the GNU Lesser General Public
23 | // License along with this source code; if not, write to: Free
24 | // Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 |
26 |
27 | // Headers
28 | // -------
29 |
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include
41 |
42 | struct rule_t {
43 | int uid;
44 | int gid;
45 | const char *cmd;
46 | const char *path;
47 | const char *hash;
48 | };
49 |
50 | #include "config.h"
51 |
52 | #ifdef HASH
53 | #include "sha256.h"
54 | #endif
55 |
56 | // Help
57 | // ----
58 |
59 | static const char *HEADER = "sup " VERSION " - small and beautiful superuser tool\n";
60 |
61 | static const char *COPYLEFT =
62 | "copyright (C) 2016 dyne.org foundation, license GNU GPL v3+\n"
63 | "this is free software: you are free to change and redistribute it\n"
64 | "for the latest sourcecode go to \n";
65 |
66 | static const char *LICENSE =
67 | "this source code is distributed in the hope that it will be useful,\n"
68 | "but without any warranty; without even the implied warranty of\n"
69 | "merchantability or fitness for a particular purpose.\n"
70 | "when in need please refer to .\n";
71 |
72 |
73 | static const char *HELP =
74 | "Syntax: sup [options] command [arguments...]\n"
75 | "\n"
76 | "Options:\n"
77 | " -l list compiled-in authorizations and flags\n"
78 | " -u set uid to this user name\n"
79 | " -g set gid to this group name\n"
80 | " -d fork command as background process (daemon)\n"
81 | " -p saves pid of background process to file (daemon)\n"
82 | "\n"
83 | "Please report bugs to \n";
84 |
85 | // maximum length of a command string
86 | #define MAXCMD 512
87 | // maximum length of a command full path string
88 | #define MAXFILEPATH 4096
89 |
90 | // Always return 1 on error, conforming to standard shell checks.
91 | // Reason of error is described by stderr text before colon,
92 | // extended reason can be provided or falls back to errno.
93 | static int error(const char *code, const char *reason) {
94 | fprintf (stderr, "%s: %s\n",
95 | code? code : "",
96 | reason? reason : strerror (errno));
97 | exit(1);
98 | }
99 |
100 | // Check if binary is found in $PATH
101 | // --------------------------------
102 |
103 | static char *getpath(const char *str) {
104 | struct stat st;
105 | static char file[MAXFILEPATH];
106 | char *p, *path = getenv ("PATH");
107 | if (path)
108 | for (p = path; *p; p++) {
109 | if (*p==':' && (p>path&&*(p-1)!='\\')) {
110 | *p = 0;
111 | snprintf (file, sizeof (file)-1, "%s/%s", path, str);
112 | if (!lstat (file, &st))
113 | return file;
114 | *p = ':';
115 | path = p+1;
116 | }
117 | }
118 | return NULL;
119 | }
120 |
121 | // Compute SHA256 hash of binary
122 | // -----------------------------
123 |
124 | #ifdef HASH
125 |
126 | #define CHUNK 1048576 // 1MiB
127 | static uint32 getsha(const char *path, unsigned char *dest) {
128 | static sha256_context sha;
129 |
130 | unsigned char buf[CHUNK]; // 1 MiB
131 | uint32 len, tot;
132 | FILE *fd;
133 |
134 | fd = fopen(path,"r");
135 | if(!fd) error("fopen", "cannot read binary file");
136 |
137 | sha256_starts(&sha);
138 | clearerr(fd);
139 | len=0;
140 | tot=0;
141 |
142 | do {
143 | // read chunk of data in binary file
144 | len = fread(buf, 1, CHUNK, fd);
145 | // stop if NULL read
146 | if(!len) break;
147 | tot+=len;
148 | // stop if EOF reached
149 | if(len0);
155 |
156 | // check file descriptor for errors
157 | if(ferror(fd)) {
158 | fclose(fd);
159 | error("fread", "error reading binary file");
160 | }
161 | fclose(fd);
162 |
163 | // compute last chunk
164 | if(len>0) sha256_update(&sha, buf, len);
165 |
166 | // finish and save result in *dest
167 | sha256_finish(&sha, dest);
168 |
169 | return(tot);
170 | }
171 |
172 | #endif
173 |
174 | // Main()
175 | // ------
176 |
177 | int main(int argc, char **argv) {
178 |
179 | static char fullcmd[MAXCMD];
180 | static char *cmd;
181 |
182 | struct passwd *pw;
183 | struct stat st;
184 |
185 | static int i, uid, gid;
186 | static int target_uid=0;
187 | static int target_gid=0;
188 |
189 | #ifdef HASH
190 | unsigned char digest[32];
191 | char output[65];
192 | #endif
193 |
194 | #ifdef DAEMON
195 | int fork_daemon = 0;
196 | char pidfile[MAXFILEPATH] = "";
197 | #endif
198 |
199 | // parse commandline options
200 | int opt;
201 | while((opt = getopt(argc, argv, "+hvdlu:g:p:")) != -1) {
202 |
203 | switch(opt) {
204 |
205 | #ifdef DAEMON
206 | case 'p':
207 | snprintf(pidfile,MAXFILEPATH,"%s",optarg);
208 | break;
209 | #endif
210 |
211 | case 'u':
212 | {
213 | struct passwd *puid;
214 | errno=0;
215 | puid=getpwnam(optarg);
216 | if(!puid && errno) error("uid_getpwnam",NULL);
217 | if(puid) target_uid=puid->pw_uid;
218 | }
219 | break;
220 |
221 | case 'g':
222 | {
223 | struct passwd *pgid;
224 | errno=0;
225 | pgid=getpwnam(optarg);
226 | if(!pgid && errno) error("gid_getpwnam",NULL);
227 | if(pgid) target_gid=pgid->pw_gid;
228 | }
229 | break;
230 |
231 | case 'h':
232 | fprintf(stdout, "%s\n%s\n%s", HEADER, COPYLEFT, HELP);
233 | exit (0);
234 |
235 | case 'v':
236 | fprintf(stdout, "%s\n%s\n%s", HEADER, COPYLEFT, LICENSE);
237 |
238 | exit (0);
239 |
240 | #ifdef DAEMON
241 | case 'd':
242 | fork_daemon=1;
243 | break;
244 | #endif
245 |
246 | case 'l':
247 | fprintf(stdout,"%s\n%s\nList of compiled in authorizations:\n\n", HEADER, COPYLEFT);
248 | fprintf(stdout,"User\tUID\tGID\t%s\t\t%s\n",
249 | "Command","Forced PATH");
250 | for (i = 0; rules[i].cmd != NULL; i++) {
251 | // Using 'getpwuid' in statically linked applications
252 | // requires at runtime the shared libraries from the glibc
253 | // version used for linking. But not in case of musl-libc.
254 | pw = getpwuid( rules[i].uid );
255 | fprintf (stdout, "%s\t%d\t%d\t%s\t%s\n",
256 | pw?pw->pw_name:"", rules[i].uid, rules[i].gid,
257 | rules[i].cmd, rules[i].path);
258 | #ifdef HASH
259 | fprintf(stdout, "sha256: %s\n\n",rules[i].hash);
260 | #endif
261 | }
262 | fprintf(stdout,"\nFlags: %s %s %s %s\n",
263 | #ifdef HASH
264 | HASH?"HASH":"",
265 | #else
266 | "",
267 | #endif
268 | #ifdef DAEMON
269 | DAEMON?"DAEMON":"",
270 | #else
271 | "",
272 | #endif
273 | strlen(CHROOT)?"CHROOT":"",
274 | strlen(CHRDIR)?"CHRDIR":"");
275 | exit (0);
276 |
277 | } // switch(opt)
278 |
279 | } // getopt
280 |
281 | // get the called UID and GID
282 | uid = getuid ();
283 | gid = getgid ();
284 |
285 | // copy the execv argument locally
286 | snprintf(fullcmd,MAXCMD,"%s",argv[optind]);
287 | // save a pointer to basename string in cmd
288 | cmd = basename(fullcmd);
289 |
290 | // get the username string from /etc/passwd
291 | pw = getpwuid( uid );
292 | #ifdef DEBUG
293 | // one could maintain a log of calls here
294 | fprintf(stderr,"sup %s called by %s(%d) gid(%d)\n",
295 | cmd, pw?pw->pw_name:"", uid, gid);
296 | #endif
297 |
298 |
299 | // Check that all rules match
300 | // --------------------------
301 |
302 | // loop over each rule
303 | for (i = 0; rules[i].cmd != NULL; i++) {
304 |
305 | // command is * or locked path matches
306 | if (*rules[i].cmd == '*' || !strcmp (cmd, rules[i].cmd)) {
307 | // if path is locked
308 | if (*rules[i].path != '*') {
309 | // and if path is specified
310 | if((fullcmd[0]=='.')||(fullcmd[0]=='/')) {
311 | // then check that path matches
312 | if( strcmp(rules[i].path,fullcmd) )
313 | return error("path","path not matching");
314 | // or if path is not specified
315 | } else {
316 | // get the default path with our getpath()
317 | snprintf(fullcmd,MAXCMD,"%s",getpath(cmd));
318 | // check if the default environment path matches
319 | if( strcmp(rules[i].path,fullcmd) )
320 | return error("path","path not matching");
321 | }
322 | // or if path is not locked
323 | } else
324 | // and if path is not specified, getpath()
325 | if((fullcmd[0]!='.')&&(fullcmd[0]!='/'))
326 | snprintf(fullcmd,MAXCMD,"%s",getpath(cmd));
327 |
328 | #ifdef DEBUG
329 | fprintf(stderr,"path check passed\n");
330 | fprintf(stderr,"fullcmd: %s\n",fullcmd);
331 | fprintf(stderr,"cmd: %s\n",cmd);
332 | #endif
333 |
334 | // Command binary check
335 | // --------------------
336 |
337 | // command does not exist as binary on the filesystem
338 | if (lstat (fullcmd, &st) == -1)
339 | return error("lstat", "cannot stat program");
340 |
341 | if (st.st_mode & 0022)
342 | // command has wrong permissions (writable to others)
343 | return error("perm", "cannot run binaries others can write.");
344 |
345 | // user UID is not root
346 | if (uid != SETUID
347 | // and is not unlocked
348 | && rules[i].uid != -1
349 | // and is not the locked UID
350 | && rules[i].uid != uid)
351 | return error("uid", "user does not match");
352 |
353 | // user GID is not root
354 | if (gid != SETGID
355 | // and is not unlocked
356 | && rules[i].gid != -1
357 | // and is not the locked GID
358 | && rules[i].gid != gid)
359 | return error("gid", "group id does not match");
360 |
361 |
362 | #ifdef HASH
363 | // Binary hash checksum
364 | // --------------------
365 | if( strlen(rules[i].hash) ) {
366 | int c;
367 | uint32 sizeread;
368 |
369 | sizeread = getsha(fullcmd, digest);
370 | if(sizeread != st.st_size)
371 | error("getsha", "binary file size differs from size read");
372 |
373 | for(c = 0; c<32; c++)
374 | sprintf(output + (c * 2),"%02x",digest[c]);
375 | output[64] = '\0';
376 |
377 | if(strncmp(rules[i].hash, output, 64)!=0) {
378 | fprintf(stderr,"%s\n%s\n", rules[i].hash, output);
379 | return error("hash", "hash does not match");
380 | }
381 | }
382 | #endif
383 |
384 | // Green light to privilege escalation
385 | // -----------------------------------
386 | if (setuid (target_uid) <0)
387 | return error("setuid",NULL);
388 | if (setgid (target_gid) <0)
389 | return error("setgid",NULL);
390 | if (seteuid (target_uid) <0)
391 | return error("seteuid",NULL);
392 | if (setegid (target_gid) <0)
393 | return error("setegid",NULL);
394 |
395 | #ifdef CHROOT
396 | if (*CHROOT && (target_uid==0))
397 | if (chdir (CHROOT) == -1 || chroot (".") == -1)
398 | return error("chroot", NULL);
399 | if (*CHRDIR)
400 | if (chdir (CHRDIR) == -1)
401 | return error("chdir", NULL);
402 | #endif
403 |
404 | // Fork as daemon if desired
405 | // -------------------------
406 |
407 | #ifdef DAEMON
408 | if(fork_daemon) {
409 |
410 | pid_t pid;
411 | pid = fork();
412 | if(pid<0) return error("fork", NULL);
413 |
414 | // child
415 | else if(pid==0) {
416 |
417 | int fd = open("/dev/tty", O_RDWR);
418 | ioctl(fd, TIOCNOTTY, 0);
419 | close(fd);
420 | chdir("/");
421 | // secure default
422 | umask(022);
423 | // process group
424 | setpgid(0,0);
425 | // stdin
426 | fd=open("/dev/null", O_RDWR);
427 | // stdout
428 | dup(fd);
429 | // stderr
430 | dup(fd);
431 |
432 | // Execute in foreground
433 | // ---------------------
434 | } else {
435 |
436 | // if pidfile is not an empty string (-p is used)
437 | if( strncmp(pidfile,"",MAXFILEPATH) ) {
438 | // save the pid of the forked child. beware this
439 | // does not work with some daemons that follow up
440 | // with more forks.
441 | FILE *fpid = fopen(pidfile,"w");
442 | if(!fpid) error("pidfile", NULL);
443 | fprintf(fpid,"%u\n",pid);
444 | fclose(fpid);
445 | }
446 |
447 | // leave us kids alone
448 | _exit(0);
449 | }
450 | }
451 | #endif
452 |
453 | // turn current process into the execution of command
454 | execv (fullcmd, &argv[optind]);
455 | // execv returns only on errors
456 | error("execv", NULL);
457 |
458 | }
459 | }
460 |
461 | // be polite
462 | fprintf(stderr,"Sorry.\n");
463 | exit(1);
464 | }
465 |
--------------------------------------------------------------------------------
/test.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include "sha256.h"
9 | #include "base64.h"
10 |
11 | #include
12 | #include
13 | #include
14 |
15 | // openssl
16 | #include
17 | #include
18 |
19 | void die(int code, char *msg) {
20 | if(msg) fprintf(stderr,"ERR: %s\n", msg);
21 | exit(code);
22 | }
23 |
24 | int main(int argc, char **argv) {
25 | char path[512];
26 | struct stat fs;
27 | FILE *fd;
28 | uint8 *buf;
29 | size_t len, dlen;
30 | uint8 digest[32];
31 | char *digest64;
32 | sha256_context sha;
33 |
34 | int c;
35 |
36 | SHA256_CTX sha256;
37 | SHA256_Init(&sha256);
38 | unsigned char hash[SHA256_DIGEST_LENGTH];
39 | char myoutput[65];
40 | char output[65];
41 |
42 | snprintf(path,512,"%s",argv[1]);
43 | if( stat(path,&fs) <0) die(1, "stat");
44 | fprintf(stderr,"%s %ld\n",path, fs.st_size);
45 |
46 | if(!fs.st_size) die(1, "stat size");
47 |
48 | fd = fopen(path,"r");
49 | if(!fd) die(1, "fopen");
50 |
51 | buf = malloc(fs.st_size);
52 | if(!buf) die(1, "malloc");
53 |
54 | len = fread(buf,1,fs.st_size,fd);
55 | if(len != fs.st_size) die(1, "fread");
56 |
57 | sha256_starts(&sha);
58 | sha256_update(&sha, buf, (uint32)len);
59 | sha256_finish(&sha, digest);
60 |
61 | for(c = 0; c<32; c++)
62 | sprintf(myoutput + (c * 2),"%02x",digest[c]);
63 | fprintf(stderr,"%s\n", myoutput);
64 |
65 |
66 | SHA256_Update(&sha256, buf, len);
67 | SHA256_Final(hash, &sha256);
68 | for(c = 0; c < SHA256_DIGEST_LENGTH; c++)
69 | sprintf(output + (c * 2), "%02x", (unsigned char)hash[c]);
70 | output[64] = '\0';
71 | fprintf(stderr,"%s\n",output);
72 |
73 |
74 |
75 |
76 | output[64] = '\0';
77 | free(buf);
78 | exit(0);
79 | }
80 |
--------------------------------------------------------------------------------