11use anyhow:: { Context , Result } ;
22use bootc_utils:: CommandRunExt ;
33use bootc_utils:: PathQuotedDisplay ;
4+ use openssh_keys:: PublicKey ;
45use rustix:: fs:: Uid ;
56use rustix:: process:: geteuid;
67use rustix:: process:: getuid;
@@ -10,6 +11,8 @@ use std::collections::BTreeMap;
1011use std:: collections:: BTreeSet ;
1112use std:: fmt:: Display ;
1213use std:: fmt:: Formatter ;
14+ use std:: fs:: File ;
15+ use std:: io:: BufReader ;
1316use std:: os:: unix:: process:: CommandExt ;
1417use std:: process:: Command ;
1518use uzers:: os:: unix:: UserExt ;
@@ -84,12 +87,12 @@ impl Drop for UidChange {
8487#[ derive( Clone , Debug ) ]
8588pub ( crate ) struct UserKeys {
8689 pub ( crate ) user : String ,
87- pub ( crate ) authorized_keys : String ,
90+ pub ( crate ) authorized_keys : Vec < PublicKey > ,
8891}
8992
9093impl UserKeys {
9194 pub ( crate ) fn num_keys ( & self ) -> usize {
92- self . authorized_keys . lines ( ) . count ( )
95+ self . authorized_keys . len ( )
9396 }
9497}
9598
@@ -135,9 +138,9 @@ impl<'a> SshdConfig<'a> {
135138 }
136139}
137140
138- fn get_keys_from_files ( user : & uzers:: User , keyfiles : & Vec < & str > ) -> Result < String > {
141+ fn get_keys_from_files ( user : & uzers:: User , keyfiles : & Vec < & str > ) -> Result < Vec < PublicKey > > {
139142 let home_dir = user. home_dir ( ) ;
140- let mut user_authorized_keys = String :: new ( ) ;
143+ let mut user_authorized_keys: Vec < PublicKey > = Vec :: new ( ) ;
141144
142145 for keyfile in keyfiles {
143146 let user_authorized_keys_path = home_dir. join ( keyfile) ;
@@ -159,16 +162,16 @@ fn get_keys_from_files(user: &uzers::User, keyfiles: &Vec<&str>) -> Result<Strin
159162 // shouldn't through symlinks
160163 let _uid_change = UidChange :: new ( user_uid) ?;
161164
162- let key = std :: fs :: read_to_string ( & user_authorized_keys_path)
165+ let file = File :: open ( user_authorized_keys_path)
163166 . context ( "Failed to read user's authorized keys" ) ?;
164- user_authorized_keys . push_str ( key . as_str ( ) ) ;
165- user_authorized_keys. push ( '\n' ) ;
167+ let mut keys = PublicKey :: read_keys ( BufReader :: new ( file ) ) ? ;
168+ user_authorized_keys. append ( & mut keys ) ;
166169 }
167170
168171 Ok ( user_authorized_keys)
169172}
170173
171- fn get_keys_from_command ( command : & str , command_user : & str ) -> Result < String > {
174+ fn get_keys_from_command ( command : & str , command_user : & str ) -> Result < Vec < PublicKey > > {
172175 let user_config = uzers:: get_user_by_name ( command_user) . context ( format ! (
173176 "authorized_keys_command_user {} not found" ,
174177 command_user
@@ -177,9 +180,10 @@ fn get_keys_from_command(command: &str, command_user: &str) -> Result<String> {
177180 let mut cmd = Command :: new ( command) ;
178181 cmd. uid ( user_config. uid ( ) ) ;
179182 let output = cmd
180- . run_get_string ( )
183+ . run_get_output ( )
181184 . context ( format ! ( "running authorized_keys_command {}" , command) ) ?;
182- Ok ( output)
185+ let keys = PublicKey :: read_keys ( output) ?;
186+ Ok ( keys)
183187}
184188
185189pub ( crate ) fn get_all_users_keys ( ) -> Result < Vec < UserKeys > > {
@@ -200,26 +204,26 @@ pub(crate) fn get_all_users_keys() -> Result<Vec<UserKeys>> {
200204 let user_info = uzers:: get_user_by_name ( user_name. as_str ( ) )
201205 . context ( format ! ( "user {} not found" , user_name) ) ?;
202206
203- let mut user_authorized_keys = String :: new ( ) ;
207+ let mut user_authorized_keys: Vec < PublicKey > = Vec :: new ( ) ;
204208 if !sshd_config. authorized_keys_files . is_empty ( ) {
205- let keys = get_keys_from_files ( & user_info, & sshd_config. authorized_keys_files ) ?;
206- user_authorized_keys. push_str ( keys. as_str ( ) ) ;
209+ let mut keys = get_keys_from_files ( & user_info, & sshd_config. authorized_keys_files ) ?;
210+ user_authorized_keys. append ( & mut keys) ;
207211 }
208212
209213 if sshd_config. authorized_keys_command != "none" {
210- let keys = get_keys_from_command (
214+ let mut keys = get_keys_from_command (
211215 & sshd_config. authorized_keys_command ,
212216 & sshd_config. authorized_keys_command_user ,
213217 ) ?;
214- user_authorized_keys. push_str ( keys. as_str ( ) ) ;
218+ user_authorized_keys. append ( & mut keys) ;
215219 } ;
216220
217221 let user_name = user_info
218222 . name ( )
219223 . to_str ( )
220224 . context ( "user name is not valid utf-8" ) ?;
221225
222- if user_authorized_keys. trim ( ) . is_empty ( ) {
226+ if user_authorized_keys. is_empty ( ) {
223227 tracing:: debug!(
224228 "Skipping user {} because it has no SSH authorized_keys" ,
225229 user_name
@@ -232,7 +236,6 @@ pub(crate) fn get_all_users_keys() -> Result<Vec<UserKeys>> {
232236 authorized_keys : user_authorized_keys,
233237 } ;
234238
235- tracing:: trace!( "Found user keys: {:?}" , user_keys) ;
236239 tracing:: debug!(
237240 "Found user {} with {} SSH authorized_keys" ,
238241 user_keys. user,
0 commit comments