bsd_auth_sys/lib.rs
1#![allow(non_upper_case_globals)]
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4
5//include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
6
7/// Request item values for auth_getitem()
8///
9/// Item documentation from `auth_subr(3)`
10#[derive(Copy, Clone, Debug, Eq, PartialEq)]
11#[repr(u32)]
12pub enum AuthItem {
13 /// All items
14 All = 0,
15 /// The latest challenge, if any, set for the session
16 Challenge = 1,
17 /// The class of the user, as defined by the `/etc/login.conf` file.
18 /// This value is not directly used by BSD Authentication, rather, it is passed to the login
19 /// scripts for their possible use.
20 Class = 2,
21 /// The name of the user being authenticated.
22 /// The name should include the instance, if any, that is being requested.
23 Name = 3,
24 /// The service requesting the authentication.
25 /// Initially it is set to the default service which provides the traditional interactive service.
26 Service = 4,
27 /// The style of authentication being performed, as defined by the `/etc/login.conf` file.
28 /// The style determines which login script should actually be used.
29 Style = 5,
30 /// If set to any value, then the session is tagged as interactive. If not set, the session is
31 /// not interactive. When the value is requested it is always either NULL or "True".
32 /// The auth subroutines may choose to provide additional information to standard output or
33 /// standard error when the session is interactive.
34 /// There is no functional change in the operation of the subroutines.
35 Interactive = 6,
36}
37
38
39/// Raw FFI interface to authentication session struct
40///
41/// No access to internal members
42#[repr(C)]
43#[derive(Debug, Copy, Clone)]
44pub struct auth_session_t {
45 _unused: [u8; 0],
46}
47
48extern "C" {
49 /// Opens a BSD Authentication session
50 ///
51 /// Returns a raw pointer to an auth_session_t
52 /// Returns a null pointer if unable to allocate memory for the session
53 pub fn auth_open() -> *mut auth_session_t;
54
55 /// Get a challenge string for the BSD Authentication session
56 ///
57 /// From `auth_subr(3)`:
58 ///
59 /// ```no_build
60 /// The `auth_challenge()` function queries the login script defined by the current `style` for a
61 /// challenge for the user specified by `name`. It internally uses the `auth_call()` function.
62 /// The generated challenge is returned. NULL is returned on error or if no challenge was
63 /// generated. The challenge can also be extracted by the `auth_getchallenge()` function, which
64 /// simply returns the last challenge generated for this session.
65 /// ```
66 pub fn auth_challenge(_as: *mut auth_session_t) -> *mut libc::c_char;
67
68 /// Terminates the BSD Authentication session
69 ///
70 /// From `auth_subr(3)`:
71 ///
72 /// ```no_build
73 /// Also sets any environment variables requested by the login script (assuming the user was
74 /// not rejected) or removes files created b the login script if the authentication was not
75 /// successful. It returns the final state of the authentication request. A return value of 0
76 /// implies the user was not authenticated. A non-zero return value is made up of 1 or more of
77 /// the following values ORed together:
78 ///
79 /// AUTH_OKAY The user was authenticated.
80 ///
81 /// AUTH_ROOTOKAY The user was authenticated with a root instance.
82 ///
83 /// AUTH_SECURE The user was authenticated via a mechanism which is not subject to
84 /// eavesdropping attacks (such as provided by token cards).
85 /// ```
86 pub fn auth_close(_as: *mut auth_session_t) -> libc::c_int;
87
88 /// Get the full state of the session
89 ///
90 /// From `auth_subr(3)`:
91 ///
92 /// ```no_build
93 /// In addtion to the values for `auth_close()`, it also may contain the bits:
94 ///
95 /// AUTH_SILENT Do not report an error, the user was not authenticated for access and was
96 /// not expected to be. This is returned by login scripts that allow changing
97 /// of the user's password, for instance. This value is stripped off for normal
98 /// returns.
99 ///
100 /// AUTH_CHALLENGE The user was not authenticated for access and a challenge was issued. The
101 /// challenge should be displayed to the user, a response received, and the
102 /// result verified. This value is stripped off for normal returns.
103 ///
104 /// AUTH_EXPIRED The user's account has expired.
105 ///
106 /// AUTH_PWEXPIRED The user's password has expired and needs to be changed.
107 /// ```
108 pub fn auth_getstate(_as: *mut auth_session_t) -> libc::c_int;
109
110 /// Clean the BSD Authentication session
111 ///
112 /// From `auth_subr(3)`:
113 ///
114 /// ```no_build
115 /// This function removes any files created by a login script in this session and clears all
116 /// state associated with this session, with the exception of the option settings. It is not
117 /// necessary to call `auth_clean()` if `auth_close()` is called.
118 /// ```
119 pub fn auth_clean(_as: *mut auth_session_t);
120
121 /// Add/delete environment variables from the BSD Authentication session
122 ///
123 /// From `auth_subr(3)`:
124 ///
125 /// ```no_build
126 /// Adds/deletes any environment variables requested by the login script to the current
127 /// environemnt.
128 /// ```
129 pub fn auth_setenv(_as: *mut auth_session_t);
130
131 /// Clear requests set by the login script
132 ///
133 /// From `auth_subr(3)`:
134 ///
135 /// ```no_build
136 /// Clears any requests set by a login script for environment variables to be set.
137 /// ```
138 pub fn auth_clrenv(_as: *mut auth_session_t);
139
140 /// Get the value of the `item`
141 ///
142 /// From `auth_subr(3)`:
143 ///
144 /// ```no_build
145 /// The `item` may be one of:
146 ///
147 /// AUTH_CHALLENGE The latest challenge, if any, set for the session
148 ///
149 /// AUTH_CLASS The class of the user, as defined by the `/etc/login.conf` file. This
150 /// value is not directly used by BSD Authentication, rather, it is passed
151 /// to the login scripts for their possible use.
152 ///
153 /// AUTH_NAME The name of the user being authenticated. The name should include the
154 /// instance, if any, that is being requested.
155 ///
156 /// AUTH_SERVICE The service requesting the authentication. Initially it is set to the
157 /// default service which provides the traditional interactive service.
158 ///
159 /// AUTH_STYLE The style of authentication being performed, as defined by the
160 /// `/etc/login.conf` file. The style determines which login script should
161 /// actually be used.
162 ///
163 /// AUTH_INTERACTIVE If set to any value, then the session is tagged as interactive. If not
164 /// set, the session is not interactive. When the value is requested it is
165 /// always either NULL or "True". The auth subroutines may choose to provide
166 /// additional information to standard output or standard error when the
167 /// session is interactive. There is no functional change in the operation
168 /// of the subroutines.
169 /// ```
170 pub fn auth_getitem(
171 _as: *mut auth_session_t,
172 _item: libc::c_uint,
173 ) -> *mut libc::c_char;
174
175 /// Assigns value to the specified item
176 ///
177 /// From `auth_subr(3)`:
178 ///
179 /// ```no_build
180 /// Assigns `value` to the specified `item`. The items are described above with the
181 /// `auth_getitem()` function. In addition, if `value` is NULL, the `item` is cleared. If
182 /// `value` is NULL` and `item` is AUTH_ALL then all items are cleared.
183 /// ```
184 pub fn auth_setitem(
185 _as: *mut auth_session_t,
186 _item: libc::c_uint,
187 _value: *mut libc::c_char,
188 ) -> libc::c_int;
189
190 /// Set an option specified by name with the given value
191 ///
192 /// From `auth_subr(3)`:
193 ///
194 /// ```no_build
195 /// Requests that the option `name` be set with the value of `value` when a script is executed
196 /// by `auth_call()`. The actual arguments to the script will be placed at the beginning of the
197 /// argument vector. For each option two arguments will be issued: -v name=value.
198 /// ```
199 pub fn auth_setoption(
200 _as: *mut auth_session_t,
201 _name: *mut libc::c_char,
202 _value: *mut libc::c_char,
203 ) -> libc::c_int;
204
205 /// Set the password for the auth session
206 pub fn auth_setpwd(
207 _as: *mut auth_session_t,
208 _pwd: *mut libc::passwd
209 ) -> libc::c_int;
210
211 /// Manually set the authenticatio state for the session
212 pub fn auth_setstate(_as: *mut auth_session_t, _state: libc::c_int);
213
214 /// Clears all previously set options
215 pub fn auth_clroptions(_as: *mut auth_session_t);
216
217 /// Clears the previously set option `name`
218 pub fn auth_clroption(_as: *mut auth_session_t, _name: *mut libc::c_char);
219
220 /// Pass data to the BSD Authentication session to be used by a login script
221 ///
222 /// From `auth_subr(3)`:
223 ///
224 /// ```no_build
225 /// Makes a copy of `len` bytes of data pointed to by `ptr` for use by `auth_call()`. The data
226 /// will be passed on the back channel to the next login script called.
227 /// ```
228 pub fn auth_setdata(
229 _as: *mut auth_session_t,
230 _ptr: *mut libc::c_void,
231 _len: u64,
232 ) -> libc::c_int;
233
234 /// A single function interface to `auth_userokay`, but returns the opened BSD Authentication
235 /// session
236 ///
237 /// From `authenticate(3)`:
238 ///
239 /// ```no_build
240 /// The `auth_usercheck()` function operates the same as the `auth_userokay()` function except
241 /// that it does not close the BSD Authentication session created. Rather than returning the
242 /// status of the session, it returns a pointer to the newly created BSD Authentication
243 /// session.
244 /// ```
245 pub fn auth_usercheck(
246 _name: *mut libc::c_char,
247 _style: *mut libc::c_char,
248 _type: *mut libc::c_char,
249 _password: *mut libc::c_char,
250 ) -> *mut auth_session_t;
251
252 /// Provides a single function interface to a BSD Authentication session
253 ///
254 /// From `authenticate(3)`:
255 ///
256 /// ```no_build
257 /// Provided with a user's name in `name`, and an optional `style`, `type`, and `password`, the
258 /// `auth_userokay()` function returns a simple yes/no response. A return value of 0 implies
259 /// failure; a non-zero return value implies success. If `style` is not NULL, it specifies the
260 /// desired style of authentication to be used. If it is NULL then the default style for the
261 /// user is used. In this case, `name` may include the desired style by appending it to the
262 /// user's name with a single colon (':') as a separator. If `type` is not NULL then it is used
263 /// as the authentication type (such as "auth-myservice"). If `password` is NULL then
264 /// `auth_userokay()` operates in an interactive mode with the user on standard input, output,
265 /// and error. If `password` is specified, `auth_userokay()` operates in a non-interactive mode
266 /// and only tests the specified passwords. This non-interactive method does not work with
267 /// challenge-response authentication styles. For security reasons, when a `password` is
268 /// specified, `auth_userokay()` will zero out its value before it returns.
269 /// ```
270 pub fn auth_userokay(
271 _name: *mut libc::c_char,
272 _style: *mut libc::c_char,
273 _type: *mut libc::c_char,
274 _password: *mut libc::c_char,
275 ) -> libc::c_int;
276
277 /// Create a BSD Authentication session, and get a challenge for a challenge-response
278 /// authentication flow
279 ///
280 /// From `authenticate(3)`:
281 ///
282 /// ```no_build
283 /// Takes the same `name`, `style`, and `type` argments as does `auth_userokay()`. However,
284 /// rather than authenticating the user, it returns a possible challenge in the pointer pointed
285 /// to by `challengep`. The return value of the function is a pointer to a newly created BSD
286 /// Authentication session. This challenge, if not NULL, should be displayed to the user.
287 /// ```
288 pub fn auth_userchallenge(
289 _name: *mut libc::c_char,
290 _style: *mut libc::c_char,
291 _type: *mut libc::c_char,
292 _challengep: *mut *mut libc::c_char,
293 ) -> *mut auth_session_t;
294
295 /// Complete the challenge-response authentication initiated by `auth_userchallenge`
296 ///
297 /// Closes the BSD Authentication session
298 ///
299 /// From `authenticate(3)`:
300 ///
301 /// ```no_build
302 /// The user should provide a password which is the `response`. In addition to the password,
303 /// the pointer returned `auth_userchallenge()` shoud be passed in as `as` and the value of
304 /// `more` should be non-zero if the program wishes to allow more attempts. If `more` is zero
305 /// then the session will be closed. The `auth_userresponse()` function closes the BSD
306 /// Authentication session and has the same return value as `auth_userokay()`. For security
307 /// reasons, when a `response` is specified, `auth_userresponse()` will zero out its value
308 /// before it returns.
309 /// ```
310 pub fn auth_userresponse(
311 _as: *mut auth_session_t,
312 _response: *mut libc::c_char,
313 _more: libc::c_int,
314 ) -> libc::c_int;
315}
316
317#[cfg(test)]
318mod tests {
319 use super::*;
320
321 #[test]
322 fn test_auth_open() {
323 let session = unsafe { auth_open() };
324 assert_ne!(session, std::ptr::null_mut());
325 unsafe { auth_clean(session) };
326 }
327
328 #[test]
329 fn test_auth_setoption() {
330 let session = unsafe { auth_open() };
331 assert_ne!(session, std::ptr::null_mut());
332 let option = std::ffi::CString::new("some").unwrap();
333 let value = std::ffi::CString::new("option").unwrap();
334 let ret = unsafe { auth_setoption(session, option.into_raw(), value.into_raw()) };
335 assert_ne!(ret, -1);
336 unsafe { auth_clean(session) };
337 }
338
339 #[test]
340 fn test_auth_clroption() {
341 let session = unsafe { auth_open() };
342 assert_ne!(session, std::ptr::null_mut());
343 let option = std::ffi::CString::new("some").unwrap();
344 let value = std::ffi::CString::new("option").unwrap();
345 let ret = unsafe { auth_setoption(session, option.clone().into_raw(), value.into_raw()) };
346 assert_ne!(ret, -1);
347 unsafe { auth_clroption(session, option.into_raw()) };
348 unsafe { auth_clean(session) };
349 }
350
351 #[test]
352 fn test_auth_clroptions() {
353 let session = unsafe { auth_open() };
354 assert_ne!(session, std::ptr::null_mut());
355 let option = std::ffi::CString::new("some").unwrap();
356 let value = std::ffi::CString::new("option").unwrap();
357 let ret = unsafe { auth_setoption(session, option.into_raw(), value.into_raw()) };
358 assert_ne!(ret, -1);
359 unsafe { auth_clroptions(session) };
360 unsafe { auth_clean(session) };
361 }
362
363 #[test]
364 fn test_auth_setdata() {
365 let session = unsafe { auth_open() };
366 assert_ne!(session, std::ptr::null_mut());
367 let mut data = [0x65, 0x69, 0x66, 0x42];
368 let data_ptr = data.as_mut_ptr() as *mut _;
369 let ret = unsafe { auth_setdata(session, data_ptr, data.len() as u64) };
370 assert_ne!(ret, -1);
371 unsafe { auth_clean(session) };
372 }
373
374 #[test]
375 fn test_auth_setitem() {
376 let session = unsafe { auth_open() };
377 assert_ne!(session, std::ptr::null_mut());
378
379 let name = std::ffi::CString::new("nobody").unwrap();
380 let name_ptr = name.clone().into_raw();
381 let ret = unsafe { auth_setitem(session, AuthItem::Name as u32, name_ptr) };
382 assert_eq!(ret, 0);
383
384 let c_item = unsafe { auth_getitem(session, AuthItem::Name as u32) };
385 assert_ne!(c_item, std::ptr::null_mut());
386 let item = unsafe { std::ffi::CString::from_raw(c_item) };
387 assert_eq!(item, name);
388
389 // convert back to raw pointer to avoid double-free
390 let _ptr = item.into_raw();
391
392 let val = std::ffi::CString::new("value").unwrap();
393 let val_ptr = val.clone().into_raw();
394 let ret = unsafe { auth_setitem(session, AuthItem::Challenge as u32, val_ptr) };
395 assert_eq!(ret, 0);
396
397 let c_item = unsafe { auth_getitem(session, AuthItem::Challenge as u32) };
398 assert_ne!(c_item, std::ptr::null_mut());
399 let item = unsafe { std::ffi::CString::from_raw(c_item) };
400 assert_eq!(item, val);
401
402 let _ptr = item.into_raw();
403
404 let ret = unsafe { auth_setitem(session, AuthItem::Class as u32, val.clone().into_raw()) };
405 assert_eq!(ret, 0);
406
407 let c_item = unsafe { auth_getitem(session, AuthItem::Class as u32) };
408 assert_ne!(c_item, std::ptr::null_mut());
409 let item = unsafe { std::ffi::CString::from_raw(c_item) };
410 assert_eq!(item, val);
411
412 let _ptr = item.into_raw();
413
414 let ret = unsafe { auth_setitem(session, AuthItem::Service as u32, val.clone().into_raw()) };
415 assert_eq!(ret, 0);
416
417 let c_item = unsafe { auth_getitem(session, AuthItem::Service as u32) };
418 assert_ne!(c_item, std::ptr::null_mut());
419 let item = unsafe { std::ffi::CString::from_raw(c_item) };
420 assert_eq!(item, val);
421
422 let _ptr = item.into_raw();
423
424 /* **DO NOT** allow setting Service with null ptr
425 *
426 * Sets session->service to defservice, which may point to invalid memory
427 * In high-level bsd_auth lib, reject this pair as invalid
428 *
429 * let ret = unsafe { auth_setitem(session, AuthItem::Service as u32, std::ptr::null_mut()) };
430 * assert_eq!(ret, 0);
431 **/
432
433 let ret = unsafe { auth_setitem(session, AuthItem::Style as u32, val.clone().into_raw()) };
434 assert_eq!(ret, 0);
435
436 let c_item = unsafe { auth_getitem(session, AuthItem::Style as u32) };
437 assert_ne!(c_item, std::ptr::null_mut());
438 let item = unsafe { std::ffi::CString::from_raw(c_item) };
439 assert_eq!(item, val);
440
441 let _ptr = item.into_raw();
442
443 // Set Interactive item to any non-null to enable the flag
444 let ret = unsafe { auth_setitem(session, AuthItem::Interactive as u32, val.clone().into_raw()) };
445 assert_eq!(ret, 0);
446
447 // Set Interactive with a null pointer to disable the flag
448 let ret = unsafe { auth_setitem(session, AuthItem::Interactive as u32, std::ptr::null_mut()) };
449 assert_eq!(ret, 0);
450
451 let c_item = unsafe { auth_getitem(session, AuthItem::Interactive as u32) };
452 assert_eq!(c_item, std::ptr::null_mut());
453
454 let ret = unsafe { auth_setitem(session, AuthItem::All as u32, name.clone().into_raw()) };
455 assert_eq!(ret, -1);
456
457 let ret = unsafe { auth_setitem(session, AuthItem::All as u32, std::ptr::null_mut()) };
458 assert_eq!(ret, 0);
459
460 unsafe { auth_clean(session) };
461 }
462
463 #[test]
464 fn test_auth_setpwd() {
465 let session = unsafe { auth_open() };
466 assert_ne!(session, std::ptr::null_mut());
467
468 let ret = unsafe { auth_setpwd(session, std::ptr::null_mut()) };
469 assert_eq!(ret, -1);
470
471 let name = std::ffi::CString::new("nobody").unwrap();
472 let ret = unsafe { auth_setitem(session, AuthItem::Name as u32, name.into_raw()) };
473 assert_eq!(ret, 0);
474
475 let ret = unsafe { auth_setpwd(session, std::ptr::null_mut()) };
476 assert_eq!(ret, 0);
477
478 unsafe { auth_clean(session) };
479 }
480}