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}