~sircmpwn/himitsu-ssh

3ee8153a7a3c4f4f4c589a8a3fe2fedb0524eefa — Armin Preiml 3 months ago 84afdbe
agent: add supprt for remember consent

Defaults can be overwritten via config file at
$XDG_CONFIG_HOME/himitsu-ssh/config.ini
2 files changed, 139 insertions(+), 1 deletions(-)

A cmd/hissh-agent/config.ha
M cmd/hissh-agent/main.ha
A cmd/hissh-agent/config.ha => cmd/hissh-agent/config.ha +89 -0
@@ 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 = [];
};

M cmd/hissh-agent/main.ha => cmd/hissh-agent/main.ha +50 -1
@@ 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 =>