You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

155 lines
5.0 KiB

  1. mod openssl_server;
  2. use crate::openssl_server::start as server_start;
  3. use acme_common::crypto::X509Certificate;
  4. use acme_common::error::Error;
  5. use clap::{App, Arg, ArgMatches};
  6. use log::{debug, error, info};
  7. use std::fs::File;
  8. use std::io::{self, Read};
  9. const APP_NAME: &str = env!("CARGO_PKG_NAME");
  10. const APP_VERSION: &str = env!("CARGO_PKG_VERSION");
  11. const DEFAULT_PID_FILE: &str = "/var/run/admed.pid";
  12. const DEFAULT_LISTEN_ADDR: &str = "127.0.0.1:5001";
  13. const ALPN_ACME_PROTO_NAME: &[u8] = b"\x0aacme-tls/1";
  14. fn read_line(path: Option<&str>) -> Result<String, Error> {
  15. let mut input = String::new();
  16. match path {
  17. Some(p) => File::open(p)?.read_to_string(&mut input)?,
  18. None => io::stdin().read_line(&mut input)?,
  19. };
  20. let line = input.trim().to_string();
  21. Ok(line)
  22. }
  23. fn get_acme_value(cnf: &ArgMatches, opt: &str, opt_file: &str) -> Result<String, Error> {
  24. match cnf.value_of(opt) {
  25. Some(v) => Ok(v.to_string()),
  26. None => {
  27. debug!(
  28. "Reading {} from {}",
  29. opt,
  30. cnf.value_of(opt_file).unwrap_or("stdin")
  31. );
  32. read_line(cnf.value_of(opt_file))
  33. }
  34. }
  35. }
  36. fn init(cnf: &ArgMatches) -> Result<(), Error> {
  37. acme_common::init_server(
  38. cnf.is_present("foregroung"),
  39. cnf.value_of("pid-file").unwrap_or(DEFAULT_PID_FILE),
  40. );
  41. let domain = get_acme_value(cnf, "domain", "domain-file")?;
  42. let ext = get_acme_value(cnf, "acme-ext", "acme-ext-file")?;
  43. let listen_addr = cnf.value_of("listen").unwrap_or(DEFAULT_LISTEN_ADDR);
  44. let (pk, cert) = X509Certificate::from_acme_ext(&domain, &ext)?;
  45. info!("Starting {} on {} for {}", APP_NAME, listen_addr, domain);
  46. server_start(listen_addr, &cert, &pk)?;
  47. Ok(())
  48. }
  49. fn main() {
  50. let matches = App::new(APP_NAME)
  51. .version(APP_VERSION)
  52. .arg(
  53. Arg::with_name("listen")
  54. .long("listen")
  55. .short("l")
  56. .help("Specifies the host and port to listen on")
  57. .takes_value(true)
  58. .value_name("host:port|unix:path"),
  59. )
  60. .arg(
  61. Arg::with_name("domain")
  62. .long("domain")
  63. .short("d")
  64. .help("The domain that is being validated")
  65. .takes_value(true)
  66. .value_name("STRING")
  67. .conflicts_with("domain-file")
  68. )
  69. .arg(
  70. Arg::with_name("domain-file")
  71. .long("domain-file")
  72. .help("File from which is read the domain that is being validated")
  73. .takes_value(true)
  74. .value_name("FILE")
  75. .conflicts_with("domain")
  76. )
  77. .arg(
  78. Arg::with_name("acme-ext")
  79. .long("acme-ext")
  80. .short("e")
  81. .help("The acmeIdentifier extension to set in the self-signed certificate")
  82. .takes_value(true)
  83. .value_name("STRING")
  84. .conflicts_with("acme-ext-file")
  85. )
  86. .arg(
  87. Arg::with_name("acme-ext-file")
  88. .long("acme-ext-file")
  89. .help("File from which is read the acmeIdentifier extension to set in the self-signed certificate")
  90. .takes_value(true)
  91. .value_name("FILE")
  92. .conflicts_with("acme-ext-file")
  93. )
  94. .arg(
  95. Arg::with_name("log-level")
  96. .long("log-level")
  97. .help("Specify the log level")
  98. .takes_value(true)
  99. .value_name("LEVEL")
  100. .possible_values(&["error", "warn", "info", "debug", "trace"]),
  101. )
  102. .arg(
  103. Arg::with_name("to-syslog")
  104. .long("log-syslog")
  105. .help("Sends log messages via syslog")
  106. .conflicts_with("to-stderr"),
  107. )
  108. .arg(
  109. Arg::with_name("to-stderr")
  110. .long("log-stderr")
  111. .help("Prints log messages to the standard error output")
  112. .conflicts_with("log-syslog"),
  113. )
  114. .arg(
  115. Arg::with_name("foregroung")
  116. .long("foregroung")
  117. .short("f")
  118. .help("Runs in the foregroung"),
  119. )
  120. .arg(
  121. Arg::with_name("pid-file")
  122. .long("pid-file")
  123. .help("Specifies the location of the PID file")
  124. .takes_value(true)
  125. .value_name("FILE")
  126. .conflicts_with("foregroung"),
  127. )
  128. .get_matches();
  129. match acme_common::logs::set_log_system(
  130. matches.value_of("log-level"),
  131. matches.is_present("log-syslog"),
  132. matches.is_present("to-stderr"),
  133. ) {
  134. Ok(_) => {}
  135. Err(e) => {
  136. eprintln!("Error: {}", e);
  137. std::process::exit(2);
  138. }
  139. };
  140. match init(&matches) {
  141. Ok(_) => {}
  142. Err(e) => {
  143. error!("{}", e);
  144. std::process::exit(1);
  145. }
  146. };
  147. }