From 9bb6b3acdf45a99a7a5c89e22b4f23ca7091845e Mon Sep 17 00:00:00 2001
From: Vladimir Stoiakin <VStoiakin@lavabit.com>
Date: Thu, 13 Mar 2025 12:47:16 +0300
Subject: [PATCH] unl0kr: add the CLI option to avoid suffixing a password with
 a newline character

Appending the newline character '\n' is the right thing to do when you print a password to a tty or a text file.
But different tools process it differently. For example, cryptsetup strips the newline character, but systemd-cryptsetup with a password agent does not.
This commit allows to control the newline character with an option.
---
 man/unl0kr.1.scd      | 10 ++++++----
 unl0kr/command_line.c |  7 ++++++-
 unl0kr/command_line.h |  2 ++
 unl0kr/main.c         |  2 +-
 unl0kr/unl0kr-agent.c |  2 +-
 5 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/man/unl0kr.1.scd b/man/unl0kr.1.scd
index 7aa9ed5..65c30ab 100644
--- a/man/unl0kr.1.scd
+++ b/man/unl0kr.1.scd
@@ -32,7 +32,7 @@ password is printed to STDOUT. All other output happens on STDERR.
 *-g, --geometry=NxM[@X,Y]*
 	Force a display size of N horizontal times M vertical pixels, offset 
 	horizontally by X pixels and vertically by Y pixels.
-*-d  --dpi=N*               
+*-d  --dpi=N*
 	Override the display's DPI value.
 *-r, --rotate=[0-3]*
 	Rotate the UI to the given orientation. The
@@ -42,11 +42,13 @@ password is printed to STDOUT. All other output happens on STDERR.
 	* 1 - clockwise orientation (90 degrees)
 	* 2 - upside down orientation (180 degrees)
 	* 3 - counterclockwise orientation (270 degrees)
-*-h, --help*                
+*-h, --help*
 	Print this message and exit.
-*-v, --verbose*             
+*-n*
+        Do not append a newline character to a password.
+*-v, --verbose*
 	Enable more detailed logging output on STDERR.
-*-V, --version*             
+*-V, --version*
 	Print the unl0kr version and exit.
 
 # EXAMPLES
diff --git a/unl0kr/command_line.c b/unl0kr/command_line.c
index 9d8f4c5..100a826 100644
--- a/unl0kr/command_line.c
+++ b/unl0kr/command_line.c
@@ -45,6 +45,7 @@ static void init_opts(ul_cli_opts *opts) {
     opts->y_offset = 0;
     opts->dpi = 0;
     opts->rotation = LV_DISPLAY_ROTATION_0;
+    opts->newline = true;
     opts->verbose = false;
 }
 
@@ -77,6 +78,7 @@ static void print_usage() {
         "                            * 2 - upside down orientation (180 degrees)\n"
         "                            * 3 - counterclockwise orientation (270 degrees)\n"
         "  -h, --help                Print this message and exit\n"
+        "  -n                        Do not append a newline character to a password\n"
         "  -v, --verbose             Enable more detailed logging output on STDERR\n"
         "  -V, --version             Print the unl0kr version and exit\n");
         /*-------------------------------- 78 CHARS --------------------------------*/
@@ -103,7 +105,7 @@ void ul_cli_parse_opts(int argc, char *argv[], ul_cli_opts *opts) {
 
     int opt, index = 0;
 
-    while ((opt = getopt_long(argc, argv, "C:g:d:r:hvV", long_opts, &index)) != -1) {
+    while ((opt = getopt_long(argc, argv, "C:g:d:r:hnvV", long_opts, &index)) != -1) {
         switch (opt) {
         case 'C':
             opts->config_files = realloc(opts->config_files, (opts->num_config_files + 1) * sizeof(char *));
@@ -153,6 +155,9 @@ void ul_cli_parse_opts(int argc, char *argv[], ul_cli_opts *opts) {
         case 'h':
             print_usage();
             exit(EXIT_SUCCESS);
+        case 'n':
+            opts->newline = false;
+            break;
         case 'v':
             opts->verbose = true;
             break;
diff --git a/unl0kr/command_line.h b/unl0kr/command_line.h
index b9cea7e..c6e075f 100644
--- a/unl0kr/command_line.h
+++ b/unl0kr/command_line.h
@@ -30,6 +30,8 @@ typedef struct {
     int dpi;
     /* Display rotation */
     lv_display_rotation_t rotation;
+    /* If true, append a newline character to a password */
+    bool newline;
     /* Verbose mode. If true, provide more detailed logging output on STDERR. */
     bool verbose;
 } ul_cli_opts;
diff --git a/unl0kr/main.c b/unl0kr/main.c
index 5e337e1..7e99814 100644
--- a/unl0kr/main.c
+++ b/unl0kr/main.c
@@ -337,7 +337,7 @@ static void textarea_ready_cb(lv_event_t *event) {
 
 static void print_password_and_exit(lv_obj_t *textarea) {
     /* Print the password to STDOUT */
-    printf("%s\n", lv_textarea_get_text(textarea));
+    printf(cli_opts.newline? "%s\n" : "%s", lv_textarea_get_text(textarea));
 
     /* Clear the screen so that when the password field was unobscured, it cannot
      * leak via stale display buffers after we've exited */
diff --git a/unl0kr/unl0kr-agent.c b/unl0kr/unl0kr-agent.c
index 6f0b01f..e62edb8 100644
--- a/unl0kr/unl0kr-agent.c
+++ b/unl0kr/unl0kr-agent.c
@@ -418,7 +418,7 @@ int exec_unl0kr(char** ret_password)
             exit(EXIT_FAILURE);
         }
 
-        execl(UNL0KR_BINARY, "unl0kr", (char*) 0);
+        execl(UNL0KR_BINARY, UNL0KR_BINARY, "-n", (char*) 0);
 
         perror("exec() is failed");
         exit(EXIT_FAILURE);
-- 
GitLab