kanidm_unix/
kanidm-unix.rs

1#![deny(warnings)]
2#![warn(unused_extern_crates)]
3#![deny(clippy::todo)]
4#![deny(clippy::unimplemented)]
5#![deny(clippy::unwrap_used)]
6#![deny(clippy::expect_used)]
7#![deny(clippy::panic)]
8#![deny(clippy::unreachable)]
9#![deny(clippy::await_holding_lock)]
10#![deny(clippy::needless_pass_by_value)]
11#![deny(clippy::trivially_copy_pass_by_ref)]
12
13#[macro_use]
14extern crate tracing;
15
16use std::process::ExitCode;
17
18use clap::Parser;
19use kanidm_unix_common::client::DaemonClient;
20use kanidm_unix_common::constants::DEFAULT_CONFIG_PATH;
21use kanidm_unix_common::unix_config::PamNssConfig;
22use kanidm_unix_common::unix_proto::{
23    ClientRequest, ClientResponse, PamAuthRequest, PamAuthResponse, PamServiceInfo,
24};
25use std::path::PathBuf;
26
27include!("../opt/tool.rs");
28
29macro_rules! setup_client {
30    () => {{
31        let Ok(cfg) = PamNssConfig::new().read_options_from_optional_config(DEFAULT_CONFIG_PATH)
32        else {
33            error!("Failed to parse {}", DEFAULT_CONFIG_PATH);
34            return ExitCode::FAILURE;
35        };
36
37        debug!("Connecting to resolver ...");
38
39        debug!(
40            "Using kanidm_unixd socket path: {:?}",
41            cfg.sock_path.as_str()
42        );
43
44        // see if the kanidm_unixd socket exists and quit if not
45        if !PathBuf::from(&cfg.sock_path).exists() {
46            error!(
47                "Failed to find unix socket at {}, quitting!",
48                cfg.sock_path.as_str()
49            );
50            return ExitCode::FAILURE;
51        }
52
53        match DaemonClient::new(cfg.sock_path.as_str(), cfg.unix_sock_timeout).await {
54            Ok(dc) => dc,
55            Err(err) => {
56                error!(
57                    "Failed to connect to resolver at {}-> {:?}",
58                    cfg.sock_path.as_str(),
59                    err
60                );
61                return ExitCode::FAILURE;
62            }
63        }
64    }};
65}
66
67#[tokio::main(flavor = "current_thread")]
68async fn main() -> ExitCode {
69    let opt = KanidmUnixParser::parse();
70
71    let debug = match opt.commands {
72        KanidmUnixOpt::AuthTest {
73            debug,
74            account_id: _,
75        } => debug,
76        KanidmUnixOpt::CacheClear { debug, really: _ } => debug,
77        KanidmUnixOpt::CacheInvalidate { debug } => debug,
78        KanidmUnixOpt::Status { debug } => debug,
79        KanidmUnixOpt::Version { debug } => debug,
80    };
81
82    if debug {
83        ::std::env::set_var("RUST_LOG", "kanidm=debug,kanidm_client=debug");
84    }
85    sketching::tracing_subscriber::fmt::init();
86
87    match opt.commands {
88        KanidmUnixOpt::AuthTest {
89            debug: _,
90            account_id,
91        } => {
92            debug!("Starting PAM auth tester tool ...");
93
94            let mut daemon_client = setup_client!();
95
96            info!("Sending request for user {}", &account_id);
97
98            let mut req = ClientRequest::PamAuthenticateInit {
99                account_id: account_id.clone(),
100                info: PamServiceInfo {
101                    service: "kanidm-unix".to_string(),
102                    tty: None,
103                    rhost: None,
104                },
105            };
106            loop {
107                match daemon_client.call(&req, None).await {
108                    Ok(r) => match r {
109                        ClientResponse::PamAuthenticateStepResponse(PamAuthResponse::Success) => {
110                            println!("auth success!");
111                            break;
112                        }
113                        ClientResponse::PamAuthenticateStepResponse(PamAuthResponse::Denied) => {
114                            println!("auth failed!");
115                            break;
116                        }
117                        ClientResponse::PamAuthenticateStepResponse(PamAuthResponse::Unknown) => {
118                            debug!("User may need to be in allow_local_account_override");
119                            println!("auth user unknown");
120                            break;
121                        }
122                        ClientResponse::PamAuthenticateStepResponse(PamAuthResponse::Password) => {
123                            // Prompt for and get the password
124                            let cred = match dialoguer::Password::new()
125                                .with_prompt("Enter Unix password")
126                                .interact()
127                            {
128                                Ok(p) => p,
129                                Err(e) => {
130                                    error!("Problem getting input: {}", e);
131                                    return ExitCode::FAILURE;
132                                }
133                            };
134
135                            // Setup the req for the next loop.
136                            req = ClientRequest::PamAuthenticateStep(PamAuthRequest::Password {
137                                cred,
138                            });
139                            continue;
140                        }
141                        ClientResponse::Error(err) => {
142                            error!("Error from kanidm-unixd: {}", err);
143                            break;
144                        }
145                        ClientResponse::PamAuthenticateStepResponse(_)
146                        | ClientResponse::SshKeys(_)
147                        | ClientResponse::NssAccounts(_)
148                        | ClientResponse::NssAccount(_)
149                        | ClientResponse::NssGroup(_)
150                        | ClientResponse::NssGroups(_)
151                        | ClientResponse::ProviderStatus(_)
152                        | ClientResponse::Ok
153                        | ClientResponse::PamStatus(_) => {
154                            // unexpected response.
155                            error!("Error: unexpected response -> {:?}", r);
156                            break;
157                        }
158                    },
159                    Err(e) => {
160                        error!("Error -> {:?}", e);
161                        break;
162                    }
163                }
164            }
165
166            let sereq = ClientRequest::PamAccountAllowed(account_id);
167
168            match daemon_client.call(&sereq, None).await {
169                Ok(r) => match r {
170                    ClientResponse::PamStatus(Some(true)) => {
171                        println!("account success!");
172                    }
173                    ClientResponse::PamStatus(Some(false)) => {
174                        println!("account failed!");
175                    }
176                    ClientResponse::PamStatus(None) => {
177                        println!("account user unknown");
178                    }
179                    _ => {
180                        // unexpected response.
181                        error!("Error: unexpected response -> {:?}", r);
182                    }
183                },
184                Err(e) => {
185                    error!("Error -> {:?}", e);
186                }
187            };
188            ExitCode::SUCCESS
189        }
190        KanidmUnixOpt::CacheClear { debug: _, really } => {
191            debug!("Starting cache clear tool ...");
192
193            let mut daemon_client = setup_client!();
194
195            if !really {
196                error!("Are you sure you want to proceed? If so use --really");
197                return ExitCode::SUCCESS;
198            }
199
200            let req = ClientRequest::ClearCache;
201
202            match daemon_client.call(&req, None).await {
203                Ok(r) => match r {
204                    ClientResponse::Ok => info!("success"),
205                    _ => {
206                        error!("Error: unexpected response -> {:?}", r);
207                    }
208                },
209                Err(e) => {
210                    error!("Error -> {:?}", e);
211                }
212            };
213            println!("success");
214            ExitCode::SUCCESS
215        }
216        KanidmUnixOpt::CacheInvalidate { debug: _ } => {
217            debug!("Starting cache invalidate tool ...");
218
219            let mut daemon_client = setup_client!();
220
221            let req = ClientRequest::InvalidateCache;
222
223            match daemon_client.call(&req, None).await {
224                Ok(r) => match r {
225                    ClientResponse::Ok => info!("success"),
226                    _ => {
227                        error!("Error: unexpected response -> {:?}", r);
228                    }
229                },
230                Err(e) => {
231                    error!("Error -> {:?}", e);
232                }
233            };
234            println!("success");
235            ExitCode::SUCCESS
236        }
237        KanidmUnixOpt::Status { debug: _ } => {
238            trace!("Starting cache status tool ...");
239
240            let mut daemon_client = setup_client!();
241            let req = ClientRequest::Status;
242
243            match daemon_client.call(&req, None).await {
244                Ok(r) => match r {
245                    ClientResponse::ProviderStatus(results) => {
246                        for provider in results {
247                            println!(
248                                "{}: {}",
249                                provider.name,
250                                if provider.online { "online" } else { "offline" }
251                            );
252                        }
253                    }
254                    _ => {
255                        error!("Error: unexpected response -> {:?}", r);
256                    }
257                },
258                Err(e) => {
259                    error!("Error -> {:?}", e);
260                }
261            }
262            ExitCode::SUCCESS
263        }
264        KanidmUnixOpt::Version { debug: _ } => {
265            println!("kanidm-unix {}", env!("KANIDM_PKG_VERSION"));
266            ExitCode::SUCCESS
267        }
268    }
269}