liminix

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

add-authkeyfile-option.patch (9765B)


      1 From 43f6d11e986666b0871b4e5b03171a4e7e8cb0e9 Mon Sep 17 00:00:00 2001
      2 From: Daniel Barlow <dan@telent.net>
      3 Date: Wed, 11 Mar 2026 18:13:32 +0000
      4 Subject: [PATCH] add -U otion to set path to authorized_keys file
      5 
      6 allow %u, %d, %n "format specifiers" in the name so that the user's
      7 username/homedir/uid can be embedded into the path
      8 ---
      9  Makefile.in          |   2 +-
     10  manpages/dropbear.8  |   2 +
     11  src/pathexpand.c     | 149 +++++++++++++++++++++++++++++++++++++++++++
     12  src/runopts.h        |   1 +
     13  src/svr-authpubkey.c |   5 ++
     14  src/svr-runopts.c    |  25 +++++---
     15  6 files changed, 175 insertions(+), 9 deletions(-)
     16  create mode 100644 src/pathexpand.c
     17 
     18 diff --git a/Makefile.in b/Makefile.in
     19 index a26f0112..e5bb99a3 100644
     20 --- a/Makefile.in
     21 +++ b/Makefile.in
     22 @@ -51,7 +51,7 @@ COMMONOBJS = $(patsubst %,$(OBJ_DIR)/%,$(_COMMONOBJS))
     23  _SVROBJS=svr-kex.o svr-auth.o sshpty.o \
     24  		svr-authpasswd.o svr-authpubkey.o svr-authpubkeyoptions.o svr-session.o svr-service.o \
     25  		svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o\
     26 -		svr-forward.o svr-tcpfwd.o svr-streamfwd.o svr-authpam.o
     27 +		svr-forward.o svr-tcpfwd.o svr-streamfwd.o svr-authpam.o  pathexpand.o
     28  SVROBJS = $(patsubst %,$(OBJ_DIR)/%,$(_SVROBJS))
     29  
     30  _CLIOBJS=cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
     31 diff --git a/manpages/dropbear.8 b/manpages/dropbear.8
     32 index fdfd2710..34bb3f38 100644
     33 --- a/manpages/dropbear.8
     34 +++ b/manpages/dropbear.8
     35 @@ -35,6 +35,8 @@ below.
     36  Generate hostkeys automatically. See
     37  .Dq Host Key Files
     38  below.
     39 +.Fl U Ar Iauthorized_keys
     40 +Absolute pathname to file containing authorized user keys. May contain the sequences %d, %n, %u which are expanded to the user's home directory, username and numeric uid respectively. Default '%d/.ssh/authorized_keys'.
     41  .It Fl F
     42  Don't fork into background.
     43  .It Fl E
     44 diff --git a/src/pathexpand.c b/src/pathexpand.c
     45 new file mode 100644
     46 index 00000000..07e69553
     47 --- /dev/null
     48 +++ b/src/pathexpand.c
     49 @@ -0,0 +1,149 @@
     50 +#include <limits.h>
     51 +#include <string.h>
     52 +#include <stdio.h>
     53 +
     54 +#ifdef TEST_PATHEXPAND
     55 +#include <stdlib.h>
     56 +
     57 +/* to run tests:
     58 +  gcc -Wall -o pathexpand -D TEST_PATHEXPAND=1 src/pathexpand.c && ./pathexpand
     59 +*/
     60 +
     61 +char * pathexpand(char *relfilename);
     62 +
     63 +
     64 +#define m_malloc(c) malloc(c)
     65 +#define m_strdup(c) strdup(c)
     66 +#define TRACE(c) dropbear_trace1 c
     67 +#include <stdarg.h>
     68 +
     69 +inline static void dropbear_trace1(const char* format, ...) {
     70 +        va_list param;
     71 +
     72 +        va_start(param, format);
     73 +        /* vfprintf(stderr, format, param); */
     74 +	/* fprintf(stderr, "\n"); */
     75 +}
     76 +
     77 +
     78 +struct session {
     79 +    struct AuthState {
     80 +	char * pw_dir;
     81 +	char * pw_name;
     82 +	uid_t pw_uid;
     83 +    } authstate;
     84 +};
     85 +
     86 +struct session ses = {
     87 +    .authstate = {
     88 +	.pw_dir = "/home/dan",
     89 +	.pw_name = "dan",
     90 +	.pw_uid = 12345,
     91 +    }
     92 +};
     93 +
     94 +int exit_status = 0;
     95 +
     96 +int expect_expansion(char * input, char * expected) {
     97 +    char *actual = pathexpand(input);
     98 +    if(strcmp(actual, expected) != 0) {
     99 +	printf("expected %s for %s, got %s\n", expected, input, actual);
    100 +	exit_status++;
    101 +    }
    102 +    free(actual);
    103 +    return exit_status;
    104 +}
    105 +
    106 +int main(int argc, char *argv[]) {
    107 +    for(int i = 1; i < argc; i++) {
    108 +	char *actual =  pathexpand(argv[i]);
    109 +	printf("%s => %s\n", argv[i], pathexpand(argv[i]));
    110 +	free(actual);
    111 +    }
    112 +
    113 +    /* a string without % is unaltered */
    114 +    expect_expansion("hello", "hello");
    115 +
    116 +    /* discards single trailing % */
    117 +    expect_expansion("hello%", "hello");
    118 +
    119 +    /* %% is transformed to % */
    120 +    expect_expansion("hello%%", "hello%");
    121 +    expect_expansion("hello%%goodbye", "hello%goodbye");
    122 +
    123 +    /* %u is transformed to uid */
    124 +    expect_expansion("/run/user/%u/authorized_keys", "/run/user/12345/authorized_keys");
    125 +    /* % sequences work when at start of string */
    126 +    expect_expansion("%u/authorized_keys", "12345/authorized_keys");
    127 +
    128 +    /* %d expands to home directory */
    129 +    expect_expansion("%d/.ssh", "/home/dan/.ssh");
    130 +
    131 +    /* %n expands to username */
    132 +    expect_expansion("/tmp/%n/.ssh", "/tmp/dan/.ssh");
    133 +
    134 +    /* unrecognised specifiers are discarded */
    135 +    expect_expansion("/hi/%q/.ssh", "/hi//.ssh");
    136 +
    137 +
    138 +    expect_expansion("%d/.ssh/authorized_keys", "/home/dan/.ssh/authorized_keys");
    139 +    exit(exit_status);
    140 +}
    141 +
    142 +#else
    143 +#include "session.h"
    144 +#include "debug.h"
    145 +#endif
    146 +#define NUMLEN(c) strlen(#c)
    147 +
    148 +char * pathexpand(char *relfilename)
    149 +{
    150 +    char * filename;
    151 +    int len;
    152 +
    153 +    len = strlen(relfilename);
    154 +    for(char *p = relfilename; p; p = strchr(p, '%')) {
    155 +	switch(*(p+1)) {
    156 +	case 'd': len += strlen(ses.authstate.pw_dir); break;
    157 +	case 'n': len += strlen(ses.authstate.pw_name); break;
    158 +	case 'u': len += NUMLEN(INT_MAX); break;
    159 +	}
    160 +	if(*(p+1) == '\0') break;
    161 +	p=p+2;
    162 +    }
    163 +    filename = m_malloc(len+1);
    164 +    filename[0] = '\0';
    165 +
    166 +    char *start = relfilename;
    167 +    char *out = filename;
    168 +    char *p = relfilename;
    169 +    do {
    170 +	p = strchr(start, '%');
    171 +
    172 +	if(!p) {
    173 +	    strcat(out, start);
    174 +	    break;
    175 +	}
    176 +	strncat(out, start, p - start);
    177 +
    178 +	switch(*(p+1)) {
    179 +	case '\0':
    180 +	    p++; break;
    181 +	case 'd':
    182 +	    strcat(out, ses.authstate.pw_dir); break;
    183 +	case 'n':
    184 +	    strcat(out, ses.authstate.pw_name); break;
    185 +	case 'u':
    186 +	    snprintf(out + strlen(out),
    187 +		     NUMLEN(INT_MAX),
    188 +		     "%d",
    189 +		     ses.authstate.pw_uid);
    190 +	    break;
    191 +	case '%':
    192 +	    strcat(out, "%"); break;
    193 +	}
    194 +	start = p+2;
    195 +    }
    196 +    while (*p);
    197 +    return filename;		/* caller must free */
    198 +}
    199 diff --git a/src/runopts.h b/src/runopts.h
    200 index 166ad4a7..b6772faf 100644
    201 --- a/src/runopts.h
    202 +++ b/src/runopts.h
    203 @@ -125,6 +125,7 @@ typedef struct svr_runopts {
    204  	char * pidfile;
    205  
    206  	char * authorized_keys_dir;
    207 +	char * authorized_keys_file;
    208  
    209  	char * forced_command;
    210  	char* interface;
    211 diff --git a/src/svr-authpubkey.c b/src/svr-authpubkey.c
    212 index 938b52da..8e25c238 100644
    213 --- a/src/svr-authpubkey.c
    214 +++ b/src/svr-authpubkey.c
    215 @@ -76,6 +76,7 @@
    216  #define MAX_AUTHKEYS_LINE 3000
    217  
    218  static char * authorized_keys_filepath(void);
    219 +extern char * pathexpand(char *input);
    220  static int checkpubkey(const char* keyalgo, unsigned int keyalgolen,
    221  		const unsigned char* keyblob, unsigned int keybloblen,
    222  		struct PubKeyOptions **ret_options);
    223 @@ -465,6 +466,10 @@ static char *authorized_keys_filepath() {
    224  	char *pathname = NULL, *dir = NULL;
    225  	const char *filename = "authorized_keys";
    226  
    227 +	if(svr_opts.authorized_keys_file) {
    228 +		return pathexpand(svr_opts.authorized_keys_file);
    229 +	};
    230 +
    231  	dir = expand_homedir_path_home(svr_opts.authorized_keys_dir,
    232  				       ses.authstate.pw_dir);
    233  
    234 diff --git a/src/svr-runopts.c b/src/svr-runopts.c
    235 index 2baec6bd..c0c73ee6 100644
    236 --- a/src/svr-runopts.c
    237 +++ b/src/svr-runopts.c
    238 @@ -1,19 +1,19 @@
    239  /*
    240   * Dropbear - a SSH2 server
    241 - * 
    242 + *
    243   * Copyright (c) 2002,2003 Matt Johnston
    244   * All rights reserved.
    245 - * 
    246 + *
    247   * Permission is hereby granted, free of charge, to any person obtaining a copy
    248   * of this software and associated documentation files (the "Software"), to deal
    249   * in the Software without restriction, including without limitation the rights
    250   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    251   * copies of the Software, and to permit persons to whom the Software is
    252   * furnished to do so, subject to the following conditions:
    253 - * 
    254 + *
    255   * The above copyright notice and this permission notice shall be included in
    256   * all copies or substantial portions of the Software.
    257 - * 
    258 + *
    259   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    260   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    261   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    262 @@ -65,7 +65,7 @@ static void printhelp(const char * progname) {
    263  					"-D		Directory containing authorized_keys file\n"
    264  #endif
    265  #if DROPBEAR_DELAY_HOSTKEY
    266 -					"-R		Create hostkeys as required\n" 
    267 +					"-R		Create hostkeys as required\n"
    268  #endif
    269  					"-F		Don't fork into background\n"
    270  					"-e		Pass on server process environment to child process\n"
    271 @@ -157,6 +157,7 @@ void svr_getopts(int argc, char ** argv) {
    272  	char* reexec_fd_arg = NULL;
    273  	char* keyfile = NULL;
    274  	char *algo_print_arg = NULL;
    275 +	char* authkeysfile = NULL;
    276  	char c;
    277  #if DROPBEAR_PLUGIN
    278          char* pubkey_plugin = NULL;
    279 @@ -184,6 +185,7 @@ void svr_getopts(int argc, char ** argv) {
    280  	svr_opts.delay_hostkey = 0;
    281  	svr_opts.pidfile = expand_homedir_path(DROPBEAR_PIDFILE);
    282  	svr_opts.authorized_keys_dir = "~/.ssh";
    283 +	svr_opts.authorized_keys_file = NULL;
    284  #if DROPBEAR_SVR_LOCALANYFWD
    285  	svr_opts.nolocaltcp = 0;
    286  #endif
    287 @@ -199,7 +201,7 @@ void svr_getopts(int argc, char ** argv) {
    288  
    289  #ifndef DISABLE_ZLIB
    290  	opts.compression = 1;
    291 -#endif 
    292 +#endif
    293  
    294  	/* not yet
    295  	opts.ipv4 = 1;
    296 @@ -362,6 +364,9 @@ void svr_getopts(int argc, char ** argv) {
    297  				case 'u':
    298  					/* backwards compatibility with old urandom option */
    299  					break;
    300 +				case 'U':
    301 +					next = &authkeysfile;
    302 +					break;
    303  #if DROPBEAR_PLUGIN
    304                                  case 'A':
    305                                          next = &pubkey_plugin;
    306 @@ -412,6 +417,10 @@ void svr_getopts(int argc, char ** argv) {
    307  				addhostkey(keyfile);
    308  				keyfile = NULL;
    309  			}
    310 +			if (authkeysfile) {
    311 +				svr_opts.authorized_keys_file = m_strdup(authkeysfile);
    312 +				authkeysfile = NULL;
    313 +			}
    314  		}
    315  	}
    316  
    317 @@ -709,7 +718,7 @@ void load_all_hostkeys() {
    318  	- Otherwise no ecdsa keys will be advertised */
    319  
    320  	/* check if any keys were loaded at startup */
    321 -	loaded_any_ecdsa = 
    322 +	loaded_any_ecdsa =
    323  		0
    324  #if DROPBEAR_ECC_256
    325  		|| svr_opts.hostkey->ecckey256
    326 @@ -756,7 +765,7 @@ void load_all_hostkeys() {
    327  #endif
    328  #if DROPBEAR_SK_ECDSA
    329  	disablekey(DROPBEAR_SIGNATURE_SK_ECDSA_NISTP256);
    330 -#endif 
    331 +#endif
    332  #if DROPBEAR_SK_ED25519
    333  	disablekey(DROPBEAR_SIGNATURE_SK_ED25519);
    334  #endif
    335 -- 
    336 2.54.0
    337