Skip to content

Commit d07bd9e

Browse files
committed
Add: Nasl builtin functions for Kerberos support
This includes: - krb5_error_code_to_string - krb5_find_kdc - krb5_gss_init - krb5_gss_prepare_context - krb5_gss_session_key - krb5_gss_update_context - krb5_gss_update_context_needs_more - krb5_gss_update_context_out - krb5_is_failure - krb5_is_success
1 parent d8802a0 commit d07bd9e

File tree

3 files changed

+292
-0
lines changed

3 files changed

+292
-0
lines changed

rust/src/nasl/builtin/error.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
use thiserror::Error;
66

7+
#[cfg(feature = "nasl-c-lib")]
8+
use crate::nasl::builtin::krb5::Krb5Error;
79
use crate::nasl::prelude::*;
810
use crate::nasl::utils::error::FnErrorKind;
911

@@ -56,6 +58,9 @@ pub enum BuiltinError {
5658
RawIp(RawIpError),
5759
#[error("{0}")]
5860
Preference(String),
61+
#[cfg(feature = "nasl-c-lib")]
62+
#[error("{0}")]
63+
Krb5(Krb5Error),
5964
}
6065

6166
macro_rules! builtin_error_variant (
@@ -104,3 +109,6 @@ builtin_error_variant!(SnmpError, Snmp);
104109

105110
#[cfg(feature = "nasl-builtin-raw-ip")]
106111
builtin_error_variant!(RawIpError, RawIp);
112+
113+
#[cfg(feature = "nasl-c-lib")]
114+
builtin_error_variant!(Krb5Error, Krb5);

rust/src/nasl/builtin/krb5/mod.rs

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
// SPDX-FileCopyrightText: 2026 Greenbone AG
2+
//
3+
// SPDX-License-Identifier: GPL-2.0-or-later WITH x11vnc-openssl-exception
4+
5+
#![allow(non_upper_case_globals)]
6+
#![allow(non_camel_case_types)]
7+
#![allow(non_snake_case)]
8+
9+
use std::ffi::CStr;
10+
use std::os;
11+
use thiserror::Error;
12+
13+
use nasl_c_lib::krb5::{
14+
OKrb5Credential, OKrb5ErrorCode, OKrb5ErrorCode_O_KRB5_CONF_NOT_CREATED,
15+
OKrb5ErrorCode_O_KRB5_CONF_NOT_FOUND, OKrb5ErrorCode_O_KRB5_EXPECTED_NOT_NULL,
16+
OKrb5ErrorCode_O_KRB5_EXPECTED_NULL, OKrb5ErrorCode_O_KRB5_NOMEM,
17+
OKrb5ErrorCode_O_KRB5_REALM_NOT_FOUND, OKrb5ErrorCode_O_KRB5_SUCCESS,
18+
OKrb5ErrorCode_O_KRB5_TMP_CONF_NOT_CREATED, OKrb5ErrorCode_O_KRB5_TMP_CONF_NOT_MOVED,
19+
OKrb5ErrorCode_O_KRB5_UNABLE_TO_WRITE, OKrb5Slice, OKrb5Target, OKrb5User, o_krb5_add_realm,
20+
o_krb5_find_kdc, okrb5_gss_init_context,
21+
};
22+
use nasl_function_proc_macro::nasl_function;
23+
24+
use crate::{function_set, nasl::FnError};
25+
26+
macro_rules! get_var_or_env {
27+
($var:expr, $env:expr) => {
28+
$var.map(|x| x.to_string())
29+
.or(std::env::var($env).ok())
30+
.ok_or(Krb5Error::Var(
31+
stringify!($var).to_string(),
32+
$env.to_string(),
33+
))
34+
};
35+
}
36+
37+
fn error_code_to_string(code: OKrb5ErrorCode) -> String {
38+
match code {
39+
OKrb5ErrorCode_O_KRB5_SUCCESS => "success".to_string(),
40+
OKrb5ErrorCode_O_KRB5_CONF_NOT_FOUND => "krb5.conf not found".to_string(),
41+
OKrb5ErrorCode_O_KRB5_CONF_NOT_CREATED => "krb5.conf not created".to_string(),
42+
OKrb5ErrorCode_O_KRB5_TMP_CONF_NOT_CREATED => "tmp krb5.conf not created".to_string(),
43+
OKrb5ErrorCode_O_KRB5_TMP_CONF_NOT_MOVED => "tmp krb5.conf not moved".to_string(),
44+
OKrb5ErrorCode_O_KRB5_REALM_NOT_FOUND => "realm not found".to_string(),
45+
OKrb5ErrorCode_O_KRB5_EXPECTED_NULL => "expected null".to_string(),
46+
OKrb5ErrorCode_O_KRB5_EXPECTED_NOT_NULL => "expected not null".to_string(),
47+
OKrb5ErrorCode_O_KRB5_UNABLE_TO_WRITE => "unable to write".to_string(),
48+
OKrb5ErrorCode_O_KRB5_NOMEM => "no memory".to_string(),
49+
_ => "unknown error code".to_string(),
50+
}
51+
}
52+
53+
fn string_from_okrb5_slice(slice: OKrb5Slice) -> String {
54+
unsafe {
55+
let bytes = std::slice::from_raw_parts(slice.data as *const u8, slice.len);
56+
String::from_utf8_lossy(bytes).into_owned()
57+
}
58+
}
59+
60+
#[derive(Debug, Error)]
61+
pub enum Krb5Error {
62+
#[error("Expected {0} or env variable {1}")]
63+
Var(String, String),
64+
#[error(
65+
"[config_path: '{config_path}', realm: '{realm}', user: '{user}'] => {message} ({code})"
66+
)]
67+
Credential {
68+
config_path: String,
69+
realm: String,
70+
user: String,
71+
message: String,
72+
code: OKrb5ErrorCode,
73+
},
74+
}
75+
76+
#[derive(Default)]
77+
pub struct Krb5 {
78+
last_okrb5_result: OKrb5ErrorCode,
79+
}
80+
81+
impl Krb5 {
82+
#[nasl_function]
83+
fn krb5_is_failure(&self, code: Option<u32>) -> bool {
84+
let code = code.unwrap_or(self.last_okrb5_result);
85+
code != OKrb5ErrorCode_O_KRB5_SUCCESS
86+
}
87+
88+
#[nasl_function]
89+
fn krb5_is_success(&self, code: Option<u32>) -> bool {
90+
let code = code.unwrap_or(self.last_okrb5_result);
91+
code == OKrb5ErrorCode_O_KRB5_SUCCESS
92+
}
93+
94+
#[nasl_function]
95+
fn krb5_error_code_to_string(&self) -> String {
96+
error_code_to_string(self.last_okrb5_result)
97+
}
98+
99+
fn make_credential(
100+
config_path: &str,
101+
realm: &str,
102+
kdc: &str,
103+
user: &str,
104+
password: &str,
105+
host: &str,
106+
) -> OKrb5Credential {
107+
OKrb5Credential {
108+
config_path: OKrb5Slice {
109+
data: config_path.as_ptr() as *mut os::raw::c_void,
110+
len: config_path.len(),
111+
},
112+
realm: OKrb5Slice {
113+
data: realm.as_ptr() as *mut os::raw::c_void,
114+
len: realm.len(),
115+
},
116+
kdc: OKrb5Slice {
117+
data: kdc.as_ptr() as *mut os::raw::c_void,
118+
len: kdc.len(),
119+
},
120+
user: OKrb5User {
121+
user: OKrb5Slice {
122+
data: user.as_ptr() as *mut os::raw::c_void,
123+
len: user.len(),
124+
},
125+
password: OKrb5Slice {
126+
data: password.as_ptr() as *mut os::raw::c_void,
127+
len: password.len(),
128+
},
129+
},
130+
target: OKrb5Target {
131+
host_name: OKrb5Slice {
132+
data: host.as_ptr() as *mut os::raw::c_void,
133+
len: host.len(),
134+
},
135+
service: OKrb5Slice {
136+
data: std::ptr::null_mut(),
137+
len: 0,
138+
},
139+
domain: OKrb5Slice {
140+
data: std::ptr::null_mut(),
141+
len: 0,
142+
},
143+
},
144+
}
145+
}
146+
147+
fn build_krb5_credential(
148+
&mut self,
149+
config_path: Option<&str>,
150+
realm: Option<&str>,
151+
kdc: Option<&str>,
152+
user: Option<&str>,
153+
password: Option<&str>,
154+
host: Option<&str>,
155+
) -> Result<OKrb5Credential, Krb5Error> {
156+
let config_path = config_path
157+
.map(|x| x.to_string())
158+
.or(std::env::var("KRB5_CONFIG").ok())
159+
.unwrap_or("/etc/krb5.conf".to_string());
160+
161+
let realm = get_var_or_env!(realm, "KRB5_REALM")?;
162+
let kdc = get_var_or_env!(kdc, "KRB5_KDC")?;
163+
let user = get_var_or_env!(user, "KRB5_USER")?;
164+
let password = get_var_or_env!(password, "KRB5_PASSWORD")?;
165+
let host = get_var_or_env!(host, "KRB5_TARGET_HOST")?;
166+
167+
let credential = Self::make_credential(&config_path, &realm, &kdc, &user, &password, &host);
168+
169+
let mut kdc_ptr: *mut i8 = std::ptr::null_mut();
170+
let code = unsafe { o_krb5_find_kdc(&credential, &mut kdc_ptr) };
171+
172+
match code {
173+
OKrb5ErrorCode_O_KRB5_SUCCESS => {
174+
if !kdc_ptr.is_null() {
175+
unsafe {
176+
libc::free(kdc_ptr as *mut libc::c_void);
177+
}
178+
}
179+
}
180+
code if code != OKrb5ErrorCode_O_KRB5_REALM_NOT_FOUND
181+
&& code != OKrb5ErrorCode_O_KRB5_CONF_NOT_FOUND =>
182+
{
183+
return Err(Krb5Error::Credential {
184+
config_path,
185+
realm,
186+
user,
187+
message: error_code_to_string(code),
188+
code,
189+
});
190+
}
191+
_ => {
192+
let code =
193+
unsafe { o_krb5_add_realm(&credential, credential.kdc.data as *const i8) };
194+
if code != OKrb5ErrorCode_O_KRB5_SUCCESS {
195+
return Err(Krb5Error::Credential {
196+
config_path,
197+
realm,
198+
user,
199+
message: error_code_to_string(code),
200+
code,
201+
});
202+
}
203+
}
204+
}
205+
206+
Ok(credential)
207+
}
208+
209+
#[nasl_function(named(config_path, realm, kdc, user, password, host))]
210+
fn krb5_find_kdc(
211+
&mut self,
212+
config_path: Option<&str>,
213+
realm: Option<&str>,
214+
kdc: Option<&str>,
215+
user: Option<&str>,
216+
password: Option<&str>,
217+
host: Option<&str>,
218+
) -> Result<String, FnError> {
219+
let credential =
220+
self.build_krb5_credential(config_path, realm, kdc, user, password, host)?;
221+
let mut kdc_ptr: *mut i8 = std::ptr::null_mut();
222+
223+
self.last_okrb5_result = unsafe { o_krb5_find_kdc(&credential, &mut kdc_ptr) };
224+
225+
if self.last_okrb5_result != OKrb5ErrorCode_O_KRB5_SUCCESS {
226+
return Err(Krb5Error::Credential {
227+
config_path: string_from_okrb5_slice(credential.config_path),
228+
realm: string_from_okrb5_slice(credential.realm),
229+
user: string_from_okrb5_slice(credential.user.user),
230+
message: error_code_to_string(self.last_okrb5_result),
231+
code: self.last_okrb5_result,
232+
}
233+
.into());
234+
}
235+
236+
if kdc_ptr.is_null() {
237+
return Ok(String::new());
238+
}
239+
240+
let result = unsafe {
241+
let c_str = CStr::from_ptr(kdc_ptr);
242+
let rust_string = c_str.to_string_lossy().into_owned();
243+
libc::free(kdc_ptr as *mut libc::c_void);
244+
rust_string
245+
};
246+
247+
Ok(result)
248+
}
249+
250+
#[nasl_function]
251+
fn krb5_gss_init(&mut self) {
252+
let chached_gss_context = unsafe { okrb5_gss_init_context() };
253+
if chached_gss_context.is_null() {
254+
self.last_okrb5_result = OKrb5ErrorCode_O_KRB5_EXPECTED_NOT_NULL;
255+
} else {
256+
self.last_okrb5_result = OKrb5ErrorCode_O_KRB5_SUCCESS;
257+
}
258+
}
259+
260+
fn krb5_gss_prepare_context() {}
261+
262+
fn krb5_gss_update_context() {}
263+
264+
fn krb5_gss_update_context_out() {}
265+
266+
fn krb5_gss_update_context_needs_more() {}
267+
268+
fn krb5_gss_session_key() {}
269+
}
270+
271+
function_set! {
272+
Krb5,
273+
(
274+
(Krb5::krb5_is_failure, "krb5_is_failure"),
275+
(Krb5::krb5_is_success, "krb5_is_success"),
276+
(Krb5::krb5_error_code_to_string, "krb5_error_code_to_string"),
277+
(Krb5::krb5_find_kdc, "krb5_find_kdc"),
278+
(Krb5::krb5_gss_init, "krb5_gss_init"),
279+
)
280+
}

rust/src/nasl/builtin/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ mod host;
1414
mod http;
1515
mod isotime;
1616
mod knowledge_base;
17+
#[cfg(feature = "nasl-c-lib")]
18+
mod krb5;
1719
pub mod misc;
1820
pub mod network;
1921
mod preferences;
@@ -65,6 +67,8 @@ pub fn nasl_std_functions() -> Executor {
6567
.add_set(snmp::Snmp)
6668
.add_set(cert::NaslCerts::default());
6769

70+
#[cfg(feature = "nasl-c-lib")]
71+
executor.add_set(krb5::Krb5::default());
6872
#[cfg(feature = "nasl-builtin-raw-ip")]
6973
executor.add_set(raw_ip::RawIp);
7074
#[cfg(feature = "nasl-builtin-raw-ip")]

0 commit comments

Comments
 (0)