[PATCH] add option to read SASL password from command output

[PATCH] add option to read SASL password from command output

From: Karel Balej
Cc: pmnw, balejk
This is useful for instance for storing the password on the disk in
encrypted form and decrypting it on the fly whenever catgirl is run
without exposing it on the process command line.
---
 catgirl.1 | 12 +++++++++++-
 chat.c    | 19 +++++++++++++++++--
 2 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/catgirl.1 b/catgirl.1
index 815eade48590..363cad8df821 100644
--- a/catgirl.1
+++ b/catgirl.1
@@ -214,7 +214,17 @@ with
 using SASL PLAIN.
 Leave
 .Ar pass
-blank to prompt for the password.
+blank to use
+.Cm sasl-pass-cmd
+if set or prompt for the password.
+.
+.It Fl A Ar cmd | Cm sasl-pass-cmd No = Ar cmd
+Use the first line of the output of
+.Ar cmd
+as password for SASL PLAIN. Only used when
+.Ar pass
+is not set in
+.Cm sasl-plain .
 .
 .It Fl c Ar path | Cm cert No = Ar path
 Load the TLS client certificate from
diff --git a/chat.c b/chat.c
index 672824027c6d..738b30bb0ead 100644
--- a/chat.c
+++ b/chat.c
@@ -239,6 +239,7 @@ int main(int argc, char *argv[]) {
 	char *pass = NULL;
 	const char *user = NULL;
 	const char *real = NULL;
+	char *plainPassCmd = NULL;
 
 	struct option options[] = {
 		{ .val = '!', .name = "insecure", no_argument },
@@ -270,6 +271,7 @@ int main(int argc, char *argv[]) {
 		{ .val = 'u', .name = "user", required_argument },
 		{ .val = 'v', .name = "debug", no_argument },
 		{ .val = 'w', .name = "pass", required_argument },
+		{ .val = 'A', .name = "sasl-pass-cmd", required_argument },
 		{0},
 	};
 	char opts[3 * ARRAY_LEN(options)];
@@ -317,6 +319,7 @@ int main(int argc, char *argv[]) {
 			break; case 'u': user = optarg;
 			break; case 'v': self.debug = true;
 			break; case 'w': pass = optarg;
+			break; case 'A': plainPassCmd = optarg;
 			break; default:  return EX_USAGE;
 		}
 	}
@@ -349,8 +352,20 @@ int main(int argc, char *argv[]) {
 	if (self.plainPass && !self.plainPass[0]) {
 		char *buf = malloc(512);
 		if (!buf) err(EX_OSERR, "malloc");
-		self.plainPass = readpassphrase("Account password: ", buf, 512, 0);
-		if (!self.plainPass) errx(EX_IOERR, "unable to read passphrase");
+		if (plainPassCmd) {
+			FILE *fp = popen(plainPassCmd, "r");
+			if (!fp)
+				errx(EX_OSERR, "unable to execute SASL passphrase command");
+			if (!fgets(buf, 512, fp))
+				errx(EX_SOFTWARE, "invalid SASL passphrase command output");
+			pclose(fp);
+			// Strip trailing newline, if present.
+			buf[strcspn(buf, "\n")] = 0;
+			self.plainPass = buf;
+		} else {
+			self.plainPass = readpassphrase("Account password: ", buf, 512, 0);
+			if (!self.plainPass) errx(EX_IOERR, "unable to read passphrase");
+		}
 	}
 
 	// Modes defined in RFC 1459:
-- 
2.44.0

Re: [PATCH] add option to read SASL password from command output

From: Karel Balej
To: june
Hello,

Karel Balej, 2024-04-12T21:41:23+02:00:
> This is useful for instance for storing the password on the disk in
> encrypted form and decrypting it on the fly whenever catgirl is run
> without exposing it on the process command line.

it's been some time and I noticed that you have added a few commits and
made a new catgirl release in the meantime, so I was wondering whether
this has made it to you. If so, I would be happy to hear what you think
when you have a minute.

Thank you, kind regards,
K. B.

Re: [PATCH] add option to read SASL password from command output

From: june
> On May 31, 2024, at 13:06, Karel Balej <balejk@matfyz.cz> wrote:
> 
> Hello,
> 
> Karel Balej, 2024-04-12T21:41:23+02:00:
>> This is useful for instance for storing the password on the disk in
>> encrypted form and decrypting it on the fly whenever catgirl is run
>> without exposing it on the process command line.
> 
> it's been some time and I noticed that you have added a few commits and
> made a new catgirl release in the meantime, so I was wondering whether
> this has made it to you. If so, I would be happy to hear what you think
> when you have a minute.

hi! sorry, this got buried in my inbox. I think it makes sense for
catgirl to have something like this, but I'm not sure about the
design (especially since ideally it could also be used for the
server password). I'll have to think about it a little more, but
thank you for this initial version!

Re: [PATCH] add option to read SASL password from command output

From: Karel Balej
To: june
june, 2024-05-31T14:16:31-04:00:
> > On May 31, 2024, at 13:06, Karel Balej <balejk@matfyz.cz> wrote:
> > 
> > Hello,
> > 
> > Karel Balej, 2024-04-12T21:41:23+02:00:
> >> This is useful for instance for storing the password on the disk in
> >> encrypted form and decrypting it on the fly whenever catgirl is run
> >> without exposing it on the process command line.
> > 
> > it's been some time and I noticed that you have added a few commits and
> > made a new catgirl release in the meantime, so I was wondering whether
> > this has made it to you. If so, I would be happy to hear what you think
> > when you have a minute.
>
> hi! sorry, this got buried in my inbox. I think it makes sense for
> catgirl to have something like this, but I'm not sure about the
> design (especially since ideally it could also be used for the
> server password). I'll have to think about it a little more, but
> thank you for this initial version!

Great, thanks!

The design is definitely up for a discussion. The order of the password
acquisition mechanisms (pass > cmd > prompt) seemed to make sense to me,
though. I don't recall my train of thoughts precisely but I think I also
considered making the command part of the sasl-plain option, such as
after a second colon (user:pass:pass-cmd) with some implications for
when the second colon is missing -- using user:pass and user::pass-cmd
would make semantic sense too I believe and I would probably go this
route today. Nevertheless making it completely separate was the safest
and simplest option as it doesn't put any constrains on what the
password may consist of without needing to implement escaping.

Regarding PASS: I have never actually needed to use that myself and I
think SASL PLAIN is generally more common nowadays so I only did that.
It would definitely be great though to have this for it too -- in direct
analogy, pass-cmd and -W would be a possibility, or alternatively
pass:pass-cmd with the aforementioned caveats.

If there is anything more I can do to help with this, please let me
know.

All the best,
K. B.