* Check that the caller is allowed to call the setuid helper. The
allowed uid is specified in a configuration file in /etc/nix-setuid.conf.
This commit is contained in:
		
							parent
							
								
									173d328351
								
							
						
					
					
						commit
						f07ac41656
					
				
					 1 changed files with 50 additions and 13 deletions
				
			
		|  | @ -1,6 +1,7 @@ | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
|  | #include <fcntl.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| 
 | 
 | ||||||
| #include <pwd.h> | #include <pwd.h> | ||||||
|  | @ -25,20 +26,26 @@ static void secureChown(uid_t uidTarget, gid_t gidTarget, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static void runBuilder(string userName, | static uid_t nameToUid(const string & userName) | ||||||
|     string program, int argc, char * * argv) |  | ||||||
| { | { | ||||||
|     struct passwd * pw = getpwnam(userName.c_str()); |     struct passwd * pw = getpwnam(userName.c_str()); | ||||||
|     if (!pw) |     if (!pw) | ||||||
|         throw Error(format("the user `%1%' does not exist") % userName); |         throw Error(format("user `%1%' does not exist") % userName); | ||||||
|  |     return pw->pw_uid; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | static void runBuilder(const string & targetUser, | ||||||
|  |     string program, int argc, char * * argv) | ||||||
|  | { | ||||||
|  |     uid_t uidTargetUser = nameToUid(targetUser); | ||||||
|     gid_t gidBuilders = 1234; |     gid_t gidBuilders = 1234; | ||||||
|      |      | ||||||
|     /* Chown the current directory, *if* it is owned by the Nix
 |     /* Chown the current directory, *if* it is owned by the Nix
 | ||||||
|        account.  The idea is that the current directory is the |        account.  The idea is that the current directory is the | ||||||
|        temporary build directory in /tmp or somewhere else, and we |        temporary build directory in /tmp or somewhere else, and we | ||||||
|        don't want to create that directory here. */ |        don't want to create that directory here. */ | ||||||
|     secureChown(pw->pw_uid, gidBuilders, "."); |     secureChown(uidTargetUser, gidBuilders, "."); | ||||||
| 
 | 
 | ||||||
|                  |                  | ||||||
|     /* Set the real, effective and saved gid.  Must be done before
 |     /* Set the real, effective and saved gid.  Must be done before
 | ||||||
|  | @ -48,9 +55,9 @@ static void runBuilder(string userName, | ||||||
|     //setgid(gidBuilders);
 |     //setgid(gidBuilders);
 | ||||||
| 
 | 
 | ||||||
|     /* Set the real, effective and saved uid. */ |     /* Set the real, effective and saved uid. */ | ||||||
|     if (setuid(pw->pw_uid) == -1 || |     if (setuid(uidTargetUser) == -1 || | ||||||
|         getuid() != pw->pw_uid || |         getuid() != uidTargetUser || | ||||||
|         geteuid() != pw->pw_uid) |         geteuid() != uidTargetUser) | ||||||
|         throw SysError("setuid failed"); |         throw SysError("setuid failed"); | ||||||
| 
 | 
 | ||||||
|     /* Execute the program. */ |     /* Execute the program. */ | ||||||
|  | @ -65,6 +72,11 @@ static void runBuilder(string userName, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | #ifndef NIX_SETUID_CONFIG_FILE | ||||||
|  | #define NIX_SETUID_CONFIG_FILE "/etc/nix-setuid.conf" | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| static void run(int argc, char * * argv)  | static void run(int argc, char * * argv)  | ||||||
| { | { | ||||||
|     char * * oldEnviron = environ; |     char * * oldEnviron = environ; | ||||||
|  | @ -83,13 +95,38 @@ static void run(int argc, char * * argv) | ||||||
|        processes run (i.e., the supposed caller).  It should match our |        processes run (i.e., the supposed caller).  It should match our | ||||||
|        real uid.  The second is the Unix group to which the Nix |        real uid.  The second is the Unix group to which the Nix | ||||||
|        builders belong (and nothing else!). */ |        builders belong (and nothing else!). */ | ||||||
|     /* !!! */ |     string configFile = NIX_SETUID_CONFIG_FILE; | ||||||
|      |     AutoCloseFD fdConfig = open(configFile.c_str(), O_RDONLY); | ||||||
|      |     if (fdConfig == -1) | ||||||
|     /* Make sure that we are called by the Nix account, not by someone
 |         throw SysError(format("opening `%1%'") % configFile); | ||||||
|        else. */ |  | ||||||
|     // ...
 |  | ||||||
| 
 | 
 | ||||||
|  |     /* Config file should be owned by root. */ | ||||||
|  |     struct stat st; | ||||||
|  |     if (fstat(fdConfig, &st) == -1) throw SysError("statting file"); | ||||||
|  |     if (st.st_uid != 0) | ||||||
|  |         throw Error(format("`%1%' not owned by root") % configFile); | ||||||
|  |     if (st.st_mode & (S_IWGRP | S_IWOTH)) | ||||||
|  |         throw Error(format("`%1%' should not be group or world-writable") % configFile); | ||||||
|  | 
 | ||||||
|  |     Strings tokens = tokenizeString(readFile(fdConfig)); | ||||||
|  | 
 | ||||||
|  |     fdConfig.close(); | ||||||
|  | 
 | ||||||
|  |     if (tokens.size() != 2) | ||||||
|  |         throw Error(format("parse error in `%1%'") % configFile); | ||||||
|  | 
 | ||||||
|  |     Strings::iterator i = tokens.begin(); | ||||||
|  |     string allowedUser = *i++; | ||||||
|  |     string buildUsersGroup = *i++; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     /* Check that the caller (real uid) is the one allowed to call
 | ||||||
|  |        this program. */ | ||||||
|  |     uid_t uidAllowedUser = nameToUid(allowedUser); | ||||||
|  |     if (uidAllowedUser != getuid()) | ||||||
|  |         throw Error("you are not allowed to call this program, go away"); | ||||||
|  |      | ||||||
|  |      | ||||||
|     /* Perform the desired command. */ |     /* Perform the desired command. */ | ||||||
|     if (argc < 2) |     if (argc < 2) | ||||||
|         throw Error("invalid arguments"); |         throw Error("invalid arguments"); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue