Skip to content

Commit

Permalink
Ignore root and improve logging. Fix #3.
Browse files Browse the repository at this point in the history
  • Loading branch information
kuon committed Aug 27, 2020
1 parent 9c2b51d commit 15577df
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 50 deletions.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,13 @@ like this:

`-rwsr-xr-x 1 root root /usr/bin/radius_shell`

#### Su and Sudo

`su` should work as expected with `root` password, `sudo` will ask for the
mapped user password. For example, if you log in as `fred:pass` and this user is
mapped to `admin:secret` you will be logged as `admin` but `sudo` will expect
the password of the `admin` user: `secret`. The best way to provide sudo access
to mapped user is to use the `NOPASSWD:` option.

### Auth client

Expand All @@ -160,6 +167,17 @@ takes the path of the config file as command line argument.
The configuration is documented in the [sample configuration
file](config.toml.sample).

## Building

If you want to build the binaries yourself, you need to be running Linux and
install rust and windows cross compiler.

Then follow those steps:

- Clone this repository, including submodules
- Run `make applypatch`
- Run `make release`


## License

Expand Down
1 change: 1 addition & 0 deletions nss_module/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ libnss = "0.3.0"
paste = "1.0.0"
log = "0.4.11"
nss_db = {path = "../nss_db"}
nix = "0.18.0"

[lib]
name = "nss_radius_virtual"
Expand Down
86 changes: 63 additions & 23 deletions nss_module/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,41 +21,77 @@ libnss_passwd_hooks!(radius_virtual, VirtualPasswd);

impl PasswdHooks for VirtualPasswd {
fn get_entry_by_name(name: String) -> Response<Passwd> {
if name == "root" {
return Response::NotFound;
}

let root = nix::unistd::Uid::from_raw(0);
if nix::unistd::geteuid() != root {
return Response::NotFound;
}

setup_log(SYSLOG_NAME);

let config = match Config::system() {
Ok(config) => config,
_ => return Response::Unavail,
Err(err) => {
error!("Cannot read system configuration: {}", err);
return Response::Unavail;
}
};

if config.debug() {
log::set_max_level(log::LevelFilter::Debug)
}

debug!("Looking up user {}", name);

let db = match Db::with_config(&config) {
Ok(db) => db,
_ => return Response::Unavail,
Err(err) => {
error!("Cannot read user database: {}", err);
return Response::Unavail;
}
};

let user = db.get_user(&name).ok();

match user {
None => Response::Success(Passwd {
name: config.mapping.default_user.username.clone(),
passwd: "x".to_string(),
uid: config.mapping.default_user.uid,
gid: config.mapping.default_user.gid,
gecos: "Radius default user".to_string(),
dir: config.mapping.default_user.home.clone(),
shell: config.mapping.default_user.shell.clone()
}),
Some(user) => Response::Success(Passwd {
name: user.mapping.username.clone(),
passwd: "x".to_string(),
uid: user.mapping.uid,
gid: user.mapping.gid,
gecos: format!(
"Mapped RADIUS account {}->{}",
None => {
debug!(
"Didn't find any user for {}, \
fallling back to default user {}",
name, config.mapping.default_user.username
);
Response::Success(Passwd {
name: config.mapping.default_user.username.clone(),
passwd: "x".to_string(),
uid: config.mapping.default_user.uid,
gid: config.mapping.default_user.gid,
gecos: "Radius default user".to_string(),
dir: config.mapping.default_user.home.clone(),
shell: config.mapping.default_user.shell.clone(),
})
}
Some(user) => {
debug!(
"Found user {}, mapped to {}",
name, user.mapping.username
)
.to_string(),
dir: user.mapping.home,
shell: config.mapping.default_user.shell.clone()
}),
);
Response::Success(Passwd {
name: user.mapping.username.clone(),
passwd: "x".to_string(),
uid: user.mapping.uid,
gid: user.mapping.gid,
gecos: format!(
"Mapped RADIUS account {}->{}",
name, user.mapping.username
)
.to_string(),
dir: user.mapping.home,
shell: config.mapping.default_user.shell.clone(),
})
}
}
}
fn get_all_entries() -> Response<Vec<Passwd>> {
Expand All @@ -71,6 +107,10 @@ libnss_shadow_hooks!(radius_virtual, VirtualShadow);

impl ShadowHooks for VirtualShadow {
fn get_entry_by_name(name: String) -> Response<Shadow> {
if name == "root" {
return Response::NotFound;
}

let config = match Config::system() {
Ok(config) => config,
_ => return Response::Unavail,
Expand Down
100 changes: 73 additions & 27 deletions pam_module/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,60 +13,90 @@ use radius::Client;
use radius::Credentials;
use radius::Error;


const SYSLOG_NAME: &str = "pam_radius_virtual";

struct PamTime;
struct PamRadius;

impl PamServiceModule for PamTime {
impl PamServiceModule for PamRadius {
fn authenticate(
pamh: Pam,
_flags: PamFlag,
_args: Vec<String>,
) -> PamError {
setup_log(SYSLOG_NAME);

let config = match Config::system() {
Ok(config) => config,
Err(err) => {
error!("Cannot read configuration file: {}", err);
return PamError::SERVICE_ERR;
}
};

if config.debug() {
log::set_max_level(log::LevelFilter::Debug)
}

let username = match pamh.get_user(None) {
Ok(Some(u)) => u,
Ok(None) => return PamError::USER_UNKNOWN,
Ok(None) => {
error!("Cannot get username");
return PamError::USER_UNKNOWN;
}
Err(e) => return e,
};

let username = match username.to_str() {
Ok(u) => u,
_ => return PamError::USER_UNKNOWN,
_ => {
error!("Cannot convert username to string");
return PamError::USER_UNKNOWN;
}
};

debug!("Got username {}", username);

if username == "root" {
return PamError::USER_UNKNOWN;
}

let pass = match pamh.get_authtok(None) {
Ok(Some(p)) => p,
Ok(None) => return PamError::AUTH_ERR,
Ok(None) => {
error!("Cannot get password");
return PamError::AUTH_ERR;
}
Err(e) => return e,
};

let pass = match pass.to_str() {
Ok(p) => p,
_ => return PamError::AUTH_ERR,
_ => {
error!("Cannot convert password to string");
return PamError::AUTH_ERR;
}
};

let config = Config::system();

let config = match config {
Ok(config) => config,
_ => return PamError::SERVICE_ERR,
};
debug!("Got password for {}", username);

let client = Client::with_config(&config.radius);

let client = match client {
Ok(client) => client,
_ => return PamError::SERVICE_ERR,
Err(err) => {
error!("Cannot create radius client: {}", err);
return PamError::SERVICE_ERR;
}
};

let db = Db::with_config(&config);

let mut db = match db {
Ok(db) => db,
_ => return PamError::SERVICE_ERR,
Err(err) => {
error!("Cannot read database: {}", err);
return PamError::SERVICE_ERR;
}
};

let cred = Credentials::with_username_password(username, pass);
Expand All @@ -76,7 +106,10 @@ impl PamServiceModule for PamTime {
let radius_user = match res {
Ok(user) => user,
Err(Error::AuthReject) => return PamError::AUTH_ERR,
_ => return PamError::SERVICE_ERR,
Err(err) => {
error!("Radius error: {}", err);
return PamError::SERVICE_ERR;
}
};

let res = config.map_user(&radius_user);
Expand All @@ -88,26 +121,30 @@ impl PamServiceModule for PamTime {

let res = db.store_user(&user);


let cookie = match res {
Ok(s) => s,
_ => return PamError::SERVICE_ERR,
Err(err) => {
error!("Cannot write to database: {}", err);
return PamError::SERVICE_ERR;
}
};

let res = pamh.putenv(&format!("RADIUS_USER={}", username));
if let Err(_) = res {
if let Err(_) = res {
return PamError::SERVICE_ERR;
}

let res = pamh.putenv(&format!("RADIUS_USER_COOKIE={}", cookie));
if let Err(_) = res {
if let Err(_) = res {
return PamError::SERVICE_ERR;
}


match res {
Ok(_) => return PamError::SUCCESS,
_ => return PamError::SERVICE_ERR,
Err(err) => {
error!("Cannot set environment variables: {}", err);
return PamError::SERVICE_ERR;
}
};
}

Expand All @@ -118,15 +155,20 @@ impl PamServiceModule for PamTime {

let config = match config {
Ok(config) => config,
_ => return PamError::SERVICE_ERR,
Err(err) => {
error!("Cannot read configuration file: {}", err);
return PamError::SERVICE_ERR;
}
};


let db = Db::with_config(&config);

let db = match db {
Ok(db) => db,
_ => return PamError::SERVICE_ERR,
Err(err) => {
error!("Cannot read database: {}", err);
return PamError::SERVICE_ERR;
}
};

let user = match pamh.get_user(None) {
Expand All @@ -140,13 +182,17 @@ impl PamServiceModule for PamTime {
_ => return PamError::USER_UNKNOWN,
};

if user == "root" {
return PamError::USER_UNKNOWN;
}

let user = db.get_user(user);

match user {
Ok(_user) => PamError::SUCCESS,
_ => PamError::AUTH_ERR
_ => PamError::AUTH_ERR,
}
}
}

pam_module!(PamTime);
pam_module!(PamRadius);

0 comments on commit 15577df

Please sign in to comment.