Add userutils
This commit is contained in:
		
							parent
							
								
									5d7b0a3889
								
							
						
					
					
						commit
						0d1afaa016
					
				
					 12 changed files with 21 additions and 376 deletions
				
			
		
							
								
								
									
										3
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
								
							|  | @ -25,3 +25,6 @@ | |||
| [submodule "programs/smith"] | ||||
| 	path = programs/smith | ||||
| 	url = https://github.com/IGI-111/Smith.git | ||||
| [submodule "programs/userutils"] | ||||
| 	path = programs/userutils | ||||
| 	url = https://github.com/redox-os/userutils.git | ||||
|  |  | |||
							
								
								
									
										26
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										26
									
								
								Makefile
									
										
									
									
									
								
							|  | @ -28,15 +28,11 @@ clean: | |||
| 	cargo clean --manifest-path drivers/ps2d/Cargo.toml | ||||
| 	cargo clean --manifest-path drivers/pcid/Cargo.toml | ||||
| 	cargo clean --manifest-path drivers/vesad/Cargo.toml | ||||
| 	cargo clean --manifest-path programs/getty/Cargo.toml | ||||
| 	cargo clean --manifest-path programs/id/Cargo.toml | ||||
| 	cargo clean --manifest-path programs/init/Cargo.toml | ||||
| 	cargo clean --manifest-path programs/sudo/Cargo.toml | ||||
| 	cargo clean --manifest-path programs/ion/Cargo.toml | ||||
| 	cargo clean --manifest-path programs/login/Cargo.toml | ||||
| 	cargo clean --manifest-path programs/sudo/Cargo.toml | ||||
| 	cargo clean --manifest-path programs/coreutils/Cargo.toml | ||||
| 	cargo clean --manifest-path programs/extrautils/Cargo.toml | ||||
| 	cargo clean --manifest-path programs/userutils/Cargo.toml | ||||
| 	cargo clean --manifest-path programs/smith/Cargo.toml | ||||
| 	cargo clean --manifest-path schemes/example/Cargo.toml | ||||
| 	cargo clean --manifest-path schemes/redoxfs/Cargo.toml | ||||
|  | @ -217,6 +213,12 @@ filesystem/bin/%: programs/extrautils/Cargo.toml programs/extrautils/src/bin/%.r | |||
| 	strip $@ | ||||
| 	rm $@.d | ||||
| 
 | ||||
| filesystem/bin/%: programs/userutils/Cargo.toml programs/userutils/src/bin/%.rs $(BUILD)/libstd.rlib | ||||
| 	mkdir -p filesystem/bin | ||||
| 	$(CARGO) rustc --manifest-path $< --bin $* $(CARGOFLAGS) -o $@ | ||||
| 	strip $@ | ||||
| 	rm $@.d | ||||
| 
 | ||||
| filesystem/bin/%: schemes/%/Cargo.toml schemes/%/src/** $(BUILD)/libstd.rlib | ||||
| 	mkdir -p filesystem/bin | ||||
| 	$(CARGO) rustc --manifest-path $< --bin $* $(CARGOFLAGS) -o $@ | ||||
|  | @ -269,6 +271,12 @@ extrautils: \ | |||
| 	filesystem/bin/rem \
 | ||||
| 	#filesystem/bin/dmesg filesystem/bin/info filesystem/bin/man filesystem/bin/watch | ||||
| 
 | ||||
| userutils: \ | ||||
| 	filesystem/bin/getty \
 | ||||
| 	filesystem/bin/id \
 | ||||
| 	filesystem/bin/login \
 | ||||
| 	filesystem/bin/su \
 | ||||
| 	filesystem/bin/sudo | ||||
| 
 | ||||
| schemes: \ | ||||
| 	filesystem/bin/example | ||||
|  | @ -277,13 +285,10 @@ $(BUILD)/filesystem.bin: \ | |||
| 		drivers \
 | ||||
| 		coreutils \
 | ||||
| 		extrautils \
 | ||||
| 		userutils \
 | ||||
| 		schemes \
 | ||||
| 		filesystem/bin/getty \
 | ||||
| 		filesystem/bin/id \
 | ||||
| 		filesystem/bin/ion \
 | ||||
| 		filesystem/bin/login \
 | ||||
| 		filesystem/bin/smith \
 | ||||
| 		filesystem/bin/sudo | ||||
| 		filesystem/bin/smith | ||||
| 	rm -rf $@ $(BUILD)/filesystem/ | ||||
| 	echo exit | cargo run --manifest-path schemes/redoxfs/Cargo.toml --bin redoxfs-utility $@ 8 | ||||
| 	mkdir -p $(BUILD)/filesystem/ | ||||
|  | @ -294,6 +299,7 @@ $(BUILD)/filesystem.bin: \ | |||
| 	-chown -R 1000:1000 $(BUILD)/filesystem/home/user/ | ||||
| 	-chmod 700 $(BUILD)/filesystem/root/ | ||||
| 	-chmod 700 $(BUILD)/filesystem/home/user/ | ||||
| 	-chmod +s $(BUILD)/filesystem/bin/su | ||||
| 	-chmod +s $(BUILD)/filesystem/bin/sudo | ||||
| 	sync | ||||
| 	-fusermount -u $(BUILD)/filesystem/ | ||||
|  |  | |||
|  | @ -1 +1 @@ | |||
| Subproject commit dc2ebd63734f30f345732fcd2e51e3f485d0ed0d | ||||
| Subproject commit adbf93876da794bde338ed8d53e5e7c4f14549dc | ||||
|  | @ -1,6 +0,0 @@ | |||
| [package] | ||||
| name = "getty" | ||||
| version = "0.1.0" | ||||
| 
 | ||||
| [dependencies] | ||||
| syscall = { path = "../../syscall/" } | ||||
|  | @ -1,51 +0,0 @@ | |||
| #![feature(question_mark)] | ||||
| 
 | ||||
| extern crate syscall; | ||||
| 
 | ||||
| use std::io::Write; | ||||
| use std::process::Command; | ||||
| use std::{env, io, str, thread}; | ||||
| 
 | ||||
| pub fn main() { | ||||
|     let mut args = env::args().skip(1); | ||||
| 
 | ||||
|     let tty = args.next().expect("getty: no tty provided"); | ||||
| 
 | ||||
|     let _ = syscall::close(2); | ||||
|     let _ = syscall::close(1); | ||||
|     let _ = syscall::close(0); | ||||
| 
 | ||||
|     let _ = syscall::open(&tty, syscall::flag::O_RDWR); | ||||
|     let _ = syscall::open(&tty, syscall::flag::O_RDWR); | ||||
|     let _ = syscall::open(&tty, syscall::flag::O_RDWR); | ||||
| 
 | ||||
|     env::set_current_dir("file:").unwrap(); | ||||
| 
 | ||||
|     env::set_var("TTY", &tty); | ||||
|     { | ||||
|         let mut path = [0; 4096]; | ||||
|         if let Ok(count) = syscall::fpath(0, &mut path) { | ||||
|             let path_str = str::from_utf8(&path[..count]).unwrap_or(""); | ||||
|             let reference = path_str.split(':').nth(1).unwrap_or(""); | ||||
|             let mut parts = reference.split('/'); | ||||
|             env::set_var("COLUMNS", parts.next().unwrap_or("80")); | ||||
|             env::set_var("LINES", parts.next().unwrap_or("30")); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     thread::spawn(move || { | ||||
|         let stdout = io::stdout(); | ||||
|         let mut stdout = stdout.lock(); | ||||
|         loop { | ||||
|             stdout.write(b"\x1Bc").unwrap(); | ||||
|             let _ = stdout.flush(); | ||||
|             match Command::new("file:bin/login").spawn() { | ||||
|                 Ok(mut child) => match child.wait() { | ||||
|                     Ok(_status) => (), //println!("getty: waited for login: {:?}", status.code()),
 | ||||
|                     Err(err) => panic!("getty: failed to wait for login: {}", err) | ||||
|                 }, | ||||
|                 Err(err) => panic!("getty: failed to execute login: {}", err) | ||||
|             } | ||||
|         } | ||||
|     }); | ||||
| } | ||||
|  | @ -1,6 +0,0 @@ | |||
| [package] | ||||
| name = "id" | ||||
| version = "0.1.0" | ||||
| 
 | ||||
| [dependencies] | ||||
| syscall = { path = "../../syscall/" } | ||||
|  | @ -1,9 +0,0 @@ | |||
| extern crate syscall; | ||||
| 
 | ||||
| use std::env; | ||||
| 
 | ||||
| pub fn main() { | ||||
|     let uid = syscall::getuid().expect("id: failed to get UID"); | ||||
|     let gid = syscall::getgid().expect("id: failed to get GID"); | ||||
|     println!("uid={}({}) gid={}({})", uid, env::var("USER").unwrap_or(String::new()), gid, ""); | ||||
| } | ||||
|  | @ -1,15 +0,0 @@ | |||
| [package] | ||||
| name = "login" | ||||
| version = "0.1.0" | ||||
| 
 | ||||
| [dependencies] | ||||
| termion = "*" | ||||
| 
 | ||||
| [dependencies.octavo] | ||||
| git = "https://github.com/libOctavo/octavo" | ||||
| default-features = false | ||||
| features = ["digest"] | ||||
| 
 | ||||
| [replace] | ||||
| "libc:0.2.16" = { git = "https://github.com/redox-os/liblibc.git", branch = "new_kernel" } | ||||
| "rustc-serialize:0.3.19" = { git = "https://github.com/redox-os/rustc-serialize.git" } | ||||
|  | @ -1,149 +0,0 @@ | |||
| #![feature(question_mark)] | ||||
| 
 | ||||
| extern crate octavo; | ||||
| extern crate termion; | ||||
| 
 | ||||
| use octavo::octavo_digest::Digest; | ||||
| use octavo::octavo_digest::sha3::Sha512; | ||||
| use std::fs::File; | ||||
| use std::io::{self, Read, Write}; | ||||
| use std::os::unix::process::CommandExt; | ||||
| use std::process::Command; | ||||
| use std::str; | ||||
| use termion::input::TermRead; | ||||
| 
 | ||||
| pub struct Passwd<'a> { | ||||
|     user: &'a str, | ||||
|     hash: &'a str, | ||||
|     uid: u32, | ||||
|     gid: u32, | ||||
|     name: &'a str, | ||||
|     home: &'a str, | ||||
|     shell: &'a str | ||||
| } | ||||
| 
 | ||||
| impl<'a> Passwd<'a> { | ||||
|     pub fn parse(line: &'a str) -> Result<Passwd<'a>, ()> { | ||||
|         let mut parts = line.split(';'); | ||||
| 
 | ||||
|         let user = parts.next().ok_or(())?; | ||||
|         let hash = parts.next().ok_or(())?; | ||||
|         let uid = parts.next().ok_or(())?.parse::<u32>().or(Err(()))?; | ||||
|         let gid = parts.next().ok_or(())?.parse::<u32>().or(Err(()))?; | ||||
|         let name = parts.next().ok_or(())?; | ||||
|         let home = parts.next().ok_or(())?; | ||||
|         let shell = parts.next().ok_or(())?; | ||||
| 
 | ||||
|         Ok(Passwd { | ||||
|             user: user, | ||||
|             hash: hash, | ||||
|             uid: uid, | ||||
|             gid: gid, | ||||
|             name: name, | ||||
|             home: home, | ||||
|             shell: shell | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn main() { | ||||
|     let stdin = io::stdin(); | ||||
|     let mut stdin = stdin.lock(); | ||||
|     let stdout = io::stdout(); | ||||
|     let mut stdout = stdout.lock(); | ||||
| 
 | ||||
|     if let Ok(mut issue) = File::open("/etc/issue") { | ||||
|         io::copy(&mut issue, &mut stdout).unwrap(); | ||||
|         let _ = stdout.flush(); | ||||
|     } | ||||
| 
 | ||||
|     loop { | ||||
|         stdout.write_all(b"\x1B[1mredox login:\x1B[0m ").unwrap(); | ||||
|         let _ = stdout.flush(); | ||||
| 
 | ||||
|         let user = (&mut stdin as &mut Read).read_line().unwrap().unwrap_or(String::new()); | ||||
|         if ! user.is_empty() { | ||||
|             let mut passwd_string = String::new(); | ||||
|             File::open("file:etc/passwd").unwrap().read_to_string(&mut passwd_string).unwrap(); | ||||
| 
 | ||||
|             let mut passwd_option = None; | ||||
|             for line in passwd_string.lines() { | ||||
|                 if let Ok(passwd) = Passwd::parse(line) { | ||||
|                     if user == passwd.user && "" == passwd.hash { | ||||
|                         passwd_option = Some(passwd); | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if passwd_option.is_none() { | ||||
|                 stdout.write_all(b"\x1B[1mpassword:\x1B[0m ").unwrap(); | ||||
|                 let _ = stdout.flush(); | ||||
| 
 | ||||
|                 if let Some(password) = stdin.read_passwd(&mut stdout).unwrap() { | ||||
|                     stdout.write(b"\n").unwrap(); | ||||
|                     let _ = stdout.flush(); | ||||
| 
 | ||||
|                     let password_hash = { | ||||
|                         let mut output = vec![0; Sha512::output_bytes()]; | ||||
|                         let mut hash = Sha512::default(); | ||||
|                         hash.update(&password.as_bytes()); | ||||
|                         hash.result(&mut output); | ||||
|                         let mut encoded = String::new(); | ||||
|                         for b in output.iter() { | ||||
|                             encoded.push_str(&format!("{:X}", b)); | ||||
|                         } | ||||
|                         encoded | ||||
|                     }; | ||||
| 
 | ||||
|                     if let Ok(mut debug) = File::open("debug:") { | ||||
|                         let _  = write!(debug, "{};{}\n", user, password_hash); | ||||
|                     } | ||||
| 
 | ||||
|                     for line in passwd_string.lines() { | ||||
|                         if let Ok(passwd) = Passwd::parse(line) { | ||||
|                             if user == passwd.user && password_hash == passwd.hash { | ||||
|                                 passwd_option = Some(passwd); | ||||
|                                 break; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if let Some(passwd) = passwd_option  { | ||||
|                 if let Ok(mut motd) = File::open("/etc/motd") { | ||||
|                     io::copy(&mut motd, &mut stdout).unwrap(); | ||||
|                     let _ = stdout.flush(); | ||||
|                 } | ||||
| 
 | ||||
|                 let mut command = Command::new(passwd.shell); | ||||
| 
 | ||||
|                 command.uid(passwd.uid); | ||||
|                 command.gid(passwd.gid); | ||||
| 
 | ||||
|                 command.current_dir(passwd.home); | ||||
| 
 | ||||
|                 command.env("USER", &user); | ||||
|                 command.env("HOME", passwd.home); | ||||
|                 command.env("PATH", "file:bin"); | ||||
| 
 | ||||
|                 match command.spawn() { | ||||
|                     Ok(mut child) => match child.wait() { | ||||
|                         Ok(_status) => (), //println!("login: waited for {}: {:?}", sh, status.code()),
 | ||||
|                         Err(err) => panic!("login: failed to wait for '{}': {}", passwd.shell, err) | ||||
|                     }, | ||||
|                     Err(err) => panic!("login: failed to execute '{}': {}", passwd.shell, err) | ||||
|                 } | ||||
| 
 | ||||
|                 break; | ||||
|             } else { | ||||
|                 stdout.write(b"\nLogin failed\n").unwrap(); | ||||
|                 let _ = stdout.flush(); | ||||
|             } | ||||
|         } else { | ||||
|             stdout.write(b"\n").unwrap(); | ||||
|             let _ = stdout.flush(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -1,6 +0,0 @@ | |||
| [package] | ||||
| name = "sudo" | ||||
| version = "0.1.0" | ||||
| 
 | ||||
| [dependencies] | ||||
| syscall = { path = "../../syscall/" } | ||||
|  | @ -1,123 +0,0 @@ | |||
| #![feature(question_mark)] | ||||
| 
 | ||||
| extern crate syscall; | ||||
| 
 | ||||
| use std::env; | ||||
| use std::fs::File; | ||||
| use std::io::Read; | ||||
| use std::os::unix::process::CommandExt; | ||||
| use std::process::{self, Command}; | ||||
| 
 | ||||
| pub struct Passwd<'a> { | ||||
|     user: &'a str, | ||||
|     hash: &'a str, | ||||
|     uid: u32, | ||||
|     gid: u32, | ||||
|     name: &'a str, | ||||
|     home: &'a str, | ||||
|     shell: &'a str | ||||
| } | ||||
| 
 | ||||
| impl<'a> Passwd<'a> { | ||||
|     pub fn parse(line: &'a str) -> Result<Passwd<'a>, ()> { | ||||
|         let mut parts = line.split(';'); | ||||
| 
 | ||||
|         let user = parts.next().ok_or(())?; | ||||
|         let hash = parts.next().ok_or(())?; | ||||
|         let uid = parts.next().ok_or(())?.parse::<u32>().or(Err(()))?; | ||||
|         let gid = parts.next().ok_or(())?.parse::<u32>().or(Err(()))?; | ||||
|         let name = parts.next().ok_or(())?; | ||||
|         let home = parts.next().ok_or(())?; | ||||
|         let shell = parts.next().ok_or(())?; | ||||
| 
 | ||||
|         Ok(Passwd { | ||||
|             user: user, | ||||
|             hash: hash, | ||||
|             uid: uid, | ||||
|             gid: gid, | ||||
|             name: name, | ||||
|             home: home, | ||||
|             shell: shell | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct Group<'a> { | ||||
|     group: &'a str, | ||||
|     gid: u32, | ||||
|     users: &'a str, | ||||
| } | ||||
| 
 | ||||
| impl<'a> Group<'a> { | ||||
|     pub fn parse(line: &'a str) -> Result<Group<'a>, ()> { | ||||
|         let mut parts = line.split(';'); | ||||
| 
 | ||||
|         let group = parts.next().ok_or(())?; | ||||
|         let gid = parts.next().ok_or(())?.parse::<u32>().or(Err(()))?; | ||||
|         let users = parts.next().ok_or(())?; | ||||
| 
 | ||||
|         Ok(Group { | ||||
|             group: group, | ||||
|             gid: gid, | ||||
|             users: users | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn main() { | ||||
|     let mut args = env::args().skip(1); | ||||
|     let cmd = args.next().expect("sudo: no command provided"); | ||||
| 
 | ||||
|     let uid = syscall::getuid().unwrap() as u32; | ||||
| 
 | ||||
|     if uid != 0 { | ||||
|         let mut passwd_string = String::new(); | ||||
|         File::open("file:etc/passwd").unwrap().read_to_string(&mut passwd_string).unwrap(); | ||||
| 
 | ||||
|         let mut passwd_option = None; | ||||
|         for line in passwd_string.lines() { | ||||
|             if let Ok(passwd) = Passwd::parse(line) { | ||||
|                 if uid == passwd.uid { | ||||
|                     passwd_option = Some(passwd); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         let passwd = passwd_option.expect("sudo: user not found in passwd"); | ||||
| 
 | ||||
|         let mut group_string = String::new(); | ||||
|         File::open("file:etc/group").unwrap().read_to_string(&mut group_string).unwrap(); | ||||
| 
 | ||||
|         let mut group_option = None; | ||||
|         for line in group_string.lines() { | ||||
|             if let Ok(group) = Group::parse(line) { | ||||
|                 if group.group == "sudo" && group.users.split(',').any(|name| name == passwd.user) { | ||||
|                     group_option = Some(group); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if group_option.is_none() { | ||||
|             panic!("sudo: '{}' not in sudo group", passwd.user); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     let mut command = Command::new(&cmd); | ||||
|     for arg in args { | ||||
|         command.arg(&arg); | ||||
|     } | ||||
| 
 | ||||
|     command.uid(0); | ||||
|     command.gid(0); | ||||
|     command.env("USER", "root"); | ||||
| 
 | ||||
|     match command.spawn() { | ||||
|         Ok(mut child) => match child.wait() { | ||||
|             Ok(status) => process::exit(status.code().unwrap_or(0)), | ||||
|             Err(err) => panic!("sudo: failed to wait for {}: {}", cmd, err) | ||||
|         }, | ||||
|         Err(err) => panic!("sudo: failed to execute {}: {}", cmd, err) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										1
									
								
								programs/userutils
									
										
									
									
									
										Submodule
									
								
							
							
						
						
									
										1
									
								
								programs/userutils
									
										
									
									
									
										Submodule
									
								
							|  | @ -0,0 +1 @@ | |||
| Subproject commit eaf26765c12efe5519fb2af72557dc0ee8286bcd | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jeremy Soller
						Jeremy Soller