@@ 0,0 1,89 @@
+use errors;
+use format::ini;
+use himitsu::remember;
+use path;
+use fs;
+use os;
+use io;
+use dirs;
+use log;
+
+type conferr = !(fs::error | io::error | ini::error);
+
+type config = struct {
+ rpersist: []remember::option,
+ rdisclose: []remember::option,
+};
+
+fn newdefaultconfig() config = {
+ return config {
+ rpersist = alloc([
+ remember::session,
+ 5i64 * 60: remember::timeout,
+ remember::refuse
+ ]),
+ rdisclose = alloc([
+ remember::skip,
+ remember::session,
+ 5i64 * 60: remember::timeout,
+ ]),
+ };
+};
+
+fn load_config() (config | conferr) = {
+ let buf = path::init()!;
+ path::set(&buf, dirs::config("himitsu-ssh"), "config.ini")!;
+ let path = path::string(&buf);
+ match (load_config_at(path)) {
+ case let c: config =>
+ log::println("Config loaded:", path);
+ return c;
+ case =>
+ log::println("Using default config");
+ return newdefaultconfig();
+ };
+};
+
+fn load_config_at(path: str) (config | conferr) = {
+ const file = os::open(path)?;
+ defer io::close(file)!;
+
+ const sc = ini::scan(file);
+ defer ini::finish(&sc);
+
+ let conf = config { ... };
+ let ok = false;
+ defer if (!ok) conf_finish(&conf);
+
+ for (let e => ini::next(&sc)?) {
+ switch (e.0) {
+ case "remember" =>
+ match (conf_remember(&conf, &e)) {
+ case void => void;
+ case let e: errors::invalid =>
+ return e: io::error;
+ };
+ case => void;
+ };
+ };
+
+ ok = true;
+ return conf;
+};
+
+fn conf_remember(conf: *config, e: *ini::entry) (void | errors::invalid) = {
+ switch (e.1) {
+ case "persist" =>
+ conf.rpersist = remember::parse_options(e.2)?;
+ case "disclose" =>
+ conf.rdisclose = remember::parse_options(e.2)?;
+ case => void;
+ };
+};
+
+fn conf_finish(conf: *config) void = {
+ free(conf.rpersist);
+ free(conf.rdisclose);
+ conf.rpersist = [];
+ conf.rdisclose = [];
+};
@@ 10,6 10,7 @@ use format::ssh;
use fs;
use himitsu::client;
use himitsu::query;
+use himitsu::remember;
use io;
use log;
use net::ssh::agent;
@@ 24,6 25,7 @@ use unix::signal;
let running: bool = true;
type server = struct {
+ config: config,
sock: (void | net::socket),
};
@@ 54,8 56,16 @@ export fn main() void = {
// make write/read from borken sockets cause an error
signal::ignore(signal::sig::PIPE);
+ let config = match (load_config()) {
+ case let c: config =>
+ yield c;
+ case conferr =>
+ yield newdefaultconfig();
+ };
+
let server = server {
sock = void,
+ config = config,
};
defer server_finish(&server);
@@ 74,6 84,36 @@ export fn main() void = {
log::println("Terminated.");
};
+fn has_remember(options: []remember::option) bool = {
+ for (let o .. options) {
+ if (o is remember::skip || o is remember::refuse) {
+ continue;
+ };
+ return true;
+ };
+ return false;
+};
+
+fn himitsu_request_persist(s: *server, himitsu: net::socket) (void | io::error) = {
+ if (!has_remember(s.config.rpersist)) {
+ return;
+ };
+
+ let q = query::parse_str("proto=ssh")!;
+ defer query::finish(&q);
+
+ let r = client::persist(himitsu, &q, 0, client::options {
+ remember = s.config.rpersist,
+ });
+
+ match (r) {
+ case let e: client::error =>
+ log::println("error on persist:", client::strerror(e));
+ case let r: remember::option =>
+ void;
+ };
+};
+
fn handle_signal(sig: signal::sig, info: *signal::siginfo, ucontext: *opaque) void = {
running = false;
};
@@ 255,9 295,17 @@ fn handle_sign_request(
};
defer ssh::key_free(key);
+ himitsu_request_persist(s, himitsu)!;
let req = memio::dynamic();
defer io::close(&req)!;
- fmt::fprint(&req, "query -d proto=ssh pkey=")?;
+
+ fmt::fprint(&req, "query -d")!;
+ if (has_remember(s.config.rpersist)) {
+ let roptions = remember::optionsstr(s.config.rdisclose);
+ defer free(roptions);
+ fmt::fprint(&req, " -r", roptions)!;
+ };
+ fmt::fprint(&req, " proto=ssh pkey=")!;
let b64en = base64::newencoder(&base64::std_encoding, &req);
ssh::key_encoderawpub(key, &b64en)!;
io::close(&b64en)!;
@@ 390,6 438,7 @@ fn himitsu_connect(s: *server) (net::socket | net::error) = {
};
fn server_finish(s: *server) void = {
+ conf_finish(&s.config);
match (s.sock) {
case void => void;
case let s: net::socket =>