* Verify that the desired target user is in the build users group (as
specified in the setuid config file).
This commit is contained in:
		
							parent
							
								
									f07ac41656
								
							
						
					
					
						commit
						62ab131412
					
				
					 1 changed files with 43 additions and 10 deletions
				
			
		|  | @ -17,7 +17,10 @@ | ||||||
| using namespace nix; | using namespace nix; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static void secureChown(uid_t uidTarget, gid_t gidTarget, | /* Recursively change the ownership of `path' from `uidFrom' to
 | ||||||
|  |    `uidTo' and `gidTo'.  Barf if we encounter a file not owned by | ||||||
|  |    `uidFrom'. */ | ||||||
|  | static void secureChown(uid_t uidFrom, uid_t uidTo, gid_t gidTo, | ||||||
|     const Path & path) |     const Path & path) | ||||||
| { | { | ||||||
|     /* Recursively chown `path' to the specified uid and gid, but only
 |     /* Recursively chown `path' to the specified uid and gid, but only
 | ||||||
|  | @ -35,24 +38,53 @@ static uid_t nameToUid(const string & userName) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| static void runBuilder(const string & targetUser, | /* Run `program' under user account `targetUser'.  `targetUser' should
 | ||||||
|  |    be a member of `buildUsersGroup'.  The ownership of the current | ||||||
|  |    directory is changed from the Nix user (uidNix) to the target | ||||||
|  |    user. */ | ||||||
|  | static void runBuilder(uid_t uidNix, | ||||||
|  |     const string & buildUsersGroup, const string & targetUser, | ||||||
|     string program, int argc, char * * argv) |     string program, int argc, char * * argv) | ||||||
| { | { | ||||||
|     uid_t uidTargetUser = nameToUid(targetUser); |     uid_t uidTargetUser = nameToUid(targetUser); | ||||||
|     gid_t gidBuilders = 1234; | 
 | ||||||
|  |     /* Sanity check. */ | ||||||
|  |     if (uidTargetUser == 0) | ||||||
|  |         throw Error("won't setuid to root"); | ||||||
|  | 
 | ||||||
|  |     /* Get the gid and members of buildUsersGroup. */ | ||||||
|  |     struct group * gr = getgrnam(buildUsersGroup.c_str()); | ||||||
|  |     if (!gr) | ||||||
|  |         throw Error(format("group `%1%' does not exist") % buildUsersGroup); | ||||||
|  |     gid_t gidBuildUsers = gr->gr_gid; | ||||||
|  | 
 | ||||||
|  |     /* Verify that the target user is a member of that group. */ | ||||||
|  |     Strings users; | ||||||
|  |     bool found = false; | ||||||
|  |     for (char * * p = gr->gr_mem; *p; ++p) | ||||||
|  |         if (string(*p) == targetUser) { | ||||||
|  |             found = true; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     if (!found) | ||||||
|  |         throw Error(format("user `%1%' is not a member of `%2%'") | ||||||
|  |             % targetUser % buildUsersGroup); | ||||||
|      |      | ||||||
|     /* 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(uidTargetUser, gidBuilders, "."); |     secureChown(uidNix, uidTargetUser, gidBuildUsers, "."); | ||||||
| 
 | 
 | ||||||
|                  |  | ||||||
|     /* Set the real, effective and saved gid.  Must be done before
 |     /* Set the real, effective and saved gid.  Must be done before
 | ||||||
|        setuid(), otherwise it won't set the real and saved gids. */ |        setuid(), otherwise it won't set the real and saved gids. */ | ||||||
|     if (setgroups(0, 0) == -1) |     if (setgroups(0, 0) == -1) | ||||||
|         throw SysError("cannot clear the set of supplementary groups"); |         throw SysError("cannot clear the set of supplementary groups"); | ||||||
|     //setgid(gidBuilders);
 | 
 | ||||||
|  |     if (setgid(gidBuildUsers) == -1 || | ||||||
|  |         getgid() != gidBuildUsers || | ||||||
|  |         getegid() != gidBuildUsers) | ||||||
|  |         throw SysError("setgid failed"); | ||||||
| 
 | 
 | ||||||
|     /* Set the real, effective and saved uid. */ |     /* Set the real, effective and saved uid. */ | ||||||
|     if (setuid(uidTargetUser) == -1 || |     if (setuid(uidTargetUser) == -1 || | ||||||
|  | @ -116,14 +148,14 @@ static void run(int argc, char * * argv) | ||||||
|         throw Error(format("parse error in `%1%'") % configFile); |         throw Error(format("parse error in `%1%'") % configFile); | ||||||
| 
 | 
 | ||||||
|     Strings::iterator i = tokens.begin(); |     Strings::iterator i = tokens.begin(); | ||||||
|     string allowedUser = *i++; |     string nixUser = *i++; | ||||||
|     string buildUsersGroup = *i++; |     string buildUsersGroup = *i++; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     /* Check that the caller (real uid) is the one allowed to call
 |     /* Check that the caller (real uid) is the one allowed to call
 | ||||||
|        this program. */ |        this program. */ | ||||||
|     uid_t uidAllowedUser = nameToUid(allowedUser); |     uid_t uidNix = nameToUid(nixUser); | ||||||
|     if (uidAllowedUser != getuid()) |     if (uidNix != getuid()) | ||||||
|         throw Error("you are not allowed to call this program, go away"); |         throw Error("you are not allowed to call this program, go away"); | ||||||
|      |      | ||||||
|      |      | ||||||
|  | @ -137,7 +169,8 @@ static void run(int argc, char * * argv) | ||||||
|         /* Syntax: nix-setuid-helper run-builder <username> <program>
 |         /* Syntax: nix-setuid-helper run-builder <username> <program>
 | ||||||
|              <args...> */ |              <args...> */ | ||||||
|         if (argc < 4) throw Error("missing user name / program name"); |         if (argc < 4) throw Error("missing user name / program name"); | ||||||
|         runBuilder(argv[2], argv[3], argc - 4, argv + 4); |         runBuilder(uidNix, buildUsersGroup, | ||||||
|  |             argv[2], argv[3], argc - 4, argv + 4); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     else if (command == "fix-ownership") { |     else if (command == "fix-ownership") { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue