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 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 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 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 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 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}