├── 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 | [![software by Dyne.org](https://www.dyne.org/wp-content/uploads/2015/12/software_by_dyne.png)](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 | --------------------------------------------------------------------------------