use getopts::Options;
use pwhash::*;
use pwtool::*;
use std::env;
const VERSION: &str = env!("CARGO_PKG_VERSION");
fn print_usage(program: &str, opts: Options) {
let brief = format!("Usage: {} [options]", program);
print!("{}", opts.usage(&brief));
}
fn set_config_options(
matches: &getopts::Matches,
c: &mut Config,
args: Vec<String>,
opts: Options,
) {
if matches.opt_present("version") {
println!("pwtool {VERSION}");
std::process::exit(0);
}
if matches.opt_present("words") {
c.word_list = Some("/usr/share/dict/words".to_string());
}
if matches.opt_present("createdatabase") {
c.create_database = true;
}
if matches.opt_present("wordsfile") {
let words = matches.opt_str("wordsfile").unwrap();
c.word_list = Some(words);
}
let mut found = false;
for opt in [
"onlynumeric",
"onlyalpha",
"onlyuppercase",
"onlylowercase",
"onlyextended",
] {
if matches.opt_present(opt) {
if found {
eprintln!("cannot have multiple --only* options");
std::process::exit(1);
}
found = true;
}
}
if matches.opt_present("onlynumeric") {
c.pw_type = Some(PwClass::Num as u32);
}
if matches.opt_present("onlyalpha") {
c.pw_type = Some(PwClass::Alpha as u32);
}
if matches.opt_present("onlyuppercase") {
c.pw_type = Some(PwClass::Upper as u32);
}
if matches.opt_present("onlylowercase") {
c.pw_type = Some(PwClass::Lower as u32);
}
if matches.opt_present("onlyextended") {
c.pw_type = Some(PwClass::Ext as u32);
}
if matches.opt_present("onlyextended") {
c.pw_type = Some(PwClass::Ext as u32);
}
if matches.opt_present("help") {
print_usage(&args[0], opts);
std::process::exit(0);
}
if matches.opt_present("username") {
c.username = matches.opt_str("username");
}
if matches.opt_present("database") {
c.database = matches.opt_str("database");
}
if matches.opt_present("servername") {
c.servername = matches.opt_str("servername");
}
c.len = if matches.opt_present("length") {
let n = matches.opt_str("length").unwrap();
match n.parse::<u32>() {
Ok(l) => l,
Err(_) => {
eprintln!("cannot convert {} to number", n);
std::process::exit(1);
}
}
} else if c.word_list.is_some() {
3
} else {
10
};
c.number = if matches.opt_present("number") {
let n = matches.opt_str("number").unwrap();
match n.parse::<u32>() {
Ok(l) => l,
Err(_) => {
eprintln!("cannot convert {} to number", n);
std::process::exit(1);
}
}
} else {
20
};
if matches.opt_present("numeric") {
c.pw_type = Some(match c.pw_type {
Some(s) => s | PwClass::Num as u32,
None => {
PwClass::Alpha as u32
| PwClass::Lower as u32
| PwClass::Upper as u32
| PwClass::Num as u32
}
});
}
if matches.opt_present("alpha") {
c.pw_type = Some(match c.pw_type {
Some(s) => s | PwClass::Alpha as u32,
None => {
PwClass::Alpha as u32
| PwClass::Lower as u32
| PwClass::Upper as u32
| PwClass::Num as u32
}
});
}
if matches.opt_present("extended") {
c.pw_type = Some(match c.pw_type {
Some(s) => s | PwClass::Ext as u32,
None => {
PwClass::Alpha as u32
| PwClass::Lower as u32
| PwClass::Upper as u32
| PwClass::Num as u32
| PwClass::Ext as u32
}
});
}
if matches.opt_present("uppercase") {
c.pw_type = Some(match c.pw_type {
Some(s) => s | PwClass::Upper as u32,
None => {
PwClass::Alpha as u32
| PwClass::Lower as u32
| PwClass::Upper as u32
| PwClass::Num as u32
}
});
}
if matches.opt_present("lowercase") {
c.pw_type = Some(match c.pw_type {
Some(s) => s | PwClass::Lower as u32,
None => {
PwClass::Alpha as u32
| PwClass::Lower as u32
| PwClass::Upper as u32
| PwClass::Num as u32
}
});
}
if matches.opt_present("help") {
print_usage(&args[0], opts);
std::process::exit(0);
}
c.len = if matches.opt_present("length") {
let n = matches.opt_str("length").unwrap();
match n.parse::<u32>() {
Ok(l) => l,
Err(_) => {
eprintln!("cannot convert {} to number", n);
std::process::exit(1);
}
}
} else if c.word_list.is_some() {
3
} else {
10
};
c.spaces = !matches.opt_present("nospaces");
c.number = if matches.opt_present("number") {
let n = matches.opt_str("number").unwrap();
match n.parse::<u32>() {
Ok(l) => l,
Err(_) => {
eprintln!("cannot convert {} to number", n);
std::process::exit(1);
}
}
} else {
20
};
for digest in ["bcrypt", "md5", "des", "sha1", "sha256", "sha512"] {
if matches.opt_present(digest) {
c.digest = Some(digest.to_string());
}
}
}
#[allow(deprecated)]
fn main() {
let mut c = Config::new();
let args: Vec<String> = env::args().collect();
let mut opts = Options::new();
opts.optflag("h", "help", "display help");
opts.optflag("", "alpha", "use alpha characters (default)");
opts.optflag("", "numeric", "use numeric characters (default)");
opts.optflag("", "extended", "use extended characters");
opts.optflag("", "lowercase", "use lowercase characters (default)");
opts.optflag("", "uppercase", "use uppercase characters (default)");
opts.optflag("", "onlyuppercase", "use uppercase characters");
opts.optflag("", "onlylowercase", "use lowercase characters");
opts.optflag("", "onlynumeric", "use numeric characters");
opts.optflag("", "onlyextended", "use extended characters");
opts.optflag("", "onlyalpha", "use alpha characters");
opts.optflag("", "md5", "use MD5");
opts.optflag("", "bcrypt", "use bcrypt");
opts.optflag("", "des", "use traditional unix crypt");
opts.optflag("", "sha1", "use SHA1");
opts.optflag("", "sha256", "use SHA256");
opts.optflag("", "sha512", "use SHA512");
opts.optflag("", "mysqlfmt", "alias for --format \"%{mysqlfmt}\\n\"");
opts.optflag(
"",
"mysqluserfmt",
"alias for --format \"%{mysqluserfmt}\\n\"",
);
opts.optflag("", "pgfmt", "alias for --format \"%{pgfmt}\\n\"");
opts.optflag("", "userfmt", "alias for --format \"%{userfmt}\\n\"");
opts.optflag("", "usermodfmt", "alias for --format \"%{usermodfmt}\\n\"");
opts.optflag("", "htauthfmt", "alias for --format \"%{htauthfm}\\n\"");
opts.optflag("", "nginxfmt", "alias for --format \"%{nginxfmt}\\n\"");
opts.optflag("", "apachefmt", "alias for --format \"%{apachefmt}\\n\"");
opts.optopt("", "username", "for %{username} formatter", "STRING");
opts.optopt("", "database", "for %{database} formatter", "STRING");
opts.optopt("", "servername", "for %{servername} formatter", "STRING");
opts.optflag(
"",
"createdatabase",
"when using --pgfmt or --mysql*fmt, prefix with a create database statement",
);
opts.optflag("v", "version", "display version");
opts.optopt("n", "number", "number of passwords", "NUMBER");
opts.optopt(
"l",
"length",
"length of passwords (default is three with a wordlist)",
"NUMBER",
);
opts.optflag("w", "words", "use default wordlist");
opts.optflag("", "nospaces", "don't join words with spaces");
opts.optopt("", "wordsfile", "use wordsfile", "FILE");
opts.optopt(
"",
"format",
"output using a string: %{VAL} where VAL is md5, bcrypt, des, sha1, sha256, sha512, mysql, postgres, database, password or username.\nmysqlfmt, pgfmt, userfmt, htauthfmt\n",
"FORMAT",
);
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => {
eprintln!("{}", f);
std::process::exit(1);
}
};
set_config_options(&matches, &mut c, args, opts);
for _ in 0..c.number {
let pw = prng_string(&mut c);
let mut donefmtopt = false;
if matches.opt_present("pgfmt") {
let mut format_string =
format!("%{{pgfmt}} {} -- # %{{password}}\n", create_pg_database(&c)).to_string();
format_string = process_format_string(&mut format_string, &c, &pw);
print!("{}", format_string);
donefmtopt = true;
}
if matches.opt_present("mysqlfmt") {
let mut format_string = format!(
"{}%{{mysqlfmt}} -- # %{{password}}\n",
create_mysql_database(&c)
)
.to_string();
format_string = process_format_string(&mut format_string, &c, &pw);
print!("{}", format_string);
donefmtopt = true;
}
if matches.opt_present("mysqluserfmt") {
let mut format_string = format!(
"{}%{{mysqluserfmt}} -- # %{{password}}\n",
create_mysql_database(&c)
)
.to_string();
format_string = process_format_string(&mut format_string, &c, &pw);
print!("{}", format_string);
donefmtopt = true;
}
if matches.opt_present("htauthfmt") {
let mut format_string = "# %{password}\n%{htauthfmt}\n".to_string();
format_string = process_format_string(&mut format_string, &c, &pw);
print!("{}", format_string);
donefmtopt = true;
}
if matches.opt_present("nginxfmt") {
let mut format_string = create_nginx_vhost();
format_string = process_format_string(&mut format_string, &c, &pw);
print!("{}", format_string);
donefmtopt = true;
}
if matches.opt_present("apachefmt") {
let mut format_string = create_apache_vhost();
format_string = process_format_string(&mut format_string, &c, &pw);
print!("{}", format_string);
donefmtopt = true;
}
if matches.opt_present("userfmt") {
let mut format_string = "%{userfmt} # %{password}\n".to_string();
format_string = process_format_string(&mut format_string, &c, &pw);
print!("{}", format_string);
donefmtopt = true;
}
if matches.opt_present("usermodfmt") {
let mut format_string = "%{usermodfmt} # %{password}\n".to_string();
format_string = process_format_string(&mut format_string, &c, &pw);
print!("{}", format_string);
donefmtopt = true;
}
if matches.opt_present("format") {
let mut format_string = matches.opt_str("format").unwrap().to_string();
if format_string.trim() == "useradd" {
format_string = "%{userfmt} # %{password}\n".to_string();
}
if format_string.trim() == "usermod" {
format_string = "%{usermodfmt} # %{password}\n".to_string();
}
if format_string.trim() == "mysql" {
format_string = "%{mysqlfmt} -- %{password}\n".to_string();
}
if format_string.trim() == "pg" {
format_string = "%{pgfmt} -- %{password}\n".to_string();
}
if format_string.trim() == "htauth" {
format_string = "# %{password}\n%{htauthfmt}\n".to_string();
}
format_string = process_format_string(&mut format_string, &c, &pw);
print!("{}", format_string);
continue;
}
if donefmtopt {
continue;
}
if matches.opt_present("md5") {
println!("{} {}", pw, md5_crypt::hash(&pw).unwrap());
continue;
}
if matches.opt_present("sha1") {
println!("{} {}", pw, sha1_crypt::hash(&pw).unwrap());
continue;
}
if matches.opt_present("sha256") {
println!("{} {}", pw, sha256_crypt::hash(&pw).unwrap());
continue;
}
if matches.opt_present("sha512") {
println!("{} {}", pw, sha512_crypt::hash(&pw).unwrap());
continue;
}
if matches.opt_present("bcrypt") {
println!("{} {}", pw, bcrypt::hash(&pw).unwrap());
continue;
}
if matches.opt_present("des") {
println!("{} {}", pw, unix_crypt::hash(&pw).unwrap());
continue;
}
for j in 1..8 {
let pw = prng_string(&mut c);
print!("{}{}", pw, if j != 8 { " " } else { "" },);
if c.word_list.is_some() {
break;
}
}
println!();
}
}