How to authenticate username/password using PAM w/o root privileges
The application needed to be able to read /etc/shadow
.
See my post for one way to do this.
EDIT:
Add post from above link in case the link ever breaks
I wrote authentication module in C++ which alows to check
username/password through PAM in Linux (I’m using Fedora Linux). I
would like to share with you, what I made :-) . So, let’s go :-)Prerequisities:
Install package pam-devel
(This step is necessary when you use shadow password) Create new Linux user and group. Set this group as default for this user. Then
follow with these steps:
Go to /etc
Log in as root (su)
Change group to the new one for file shadow (chgrp new_group shadow)
Set ‘read’ privilage for this group (chmod 0440 shadow)Write this code: (authModule.c) view plaincopy to clipboardprint?
#include <stdio.h>
#include <security/pam_appl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
struct pam_response *reply;
// //function used to get user input
int function_conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
{
*resp = reply;
return PAM_SUCCESS;
}
int authenticate_system(const char *username, const char *password)
{
const struct pam_conv local_conversation = { function_conversation, NULL };
pam_handle_t *local_auth_handle = NULL; // this gets set by pam_start
int retval;
retval = pam_start("su", username, &local_conversation, &local_auth_handle);
if (retval != PAM_SUCCESS)
{
printf("pam_start returned: %d\n ", retval);
return 0;
}
reply = (struct pam_response *)malloc(sizeof(struct pam_response));
reply[0].resp = strdup(password);
reply[0].resp_retcode = 0;
retval = pam_authenticate(local_auth_handle, 0);
if (retval != PAM_SUCCESS)
{
if (retval == PAM_AUTH_ERR)
{
printf("Authentication failure.\n");
}
else
{
printf("pam_authenticate returned %d\n", retval);
}
return 0;
}
printf("Authenticated.\n");
retval = pam_end(local_auth_handle, retval);
if (retval != PAM_SUCCESS)
{
printf("pam_end returned\n");
return 0;
}
return 1;
}
int main(int argc, char** argv)
{
char* login;
char* password;
printf("Authentication module\n");
if (argc != 3)
{
printf("Invalid count of arguments %d.\n", argc);
printf("./authModule <username> <password>");
return 1;
}
login = argv[1];
password = argv[2];
if (authenticate_system(login, password) == 1)
{
printf("Authenticate with %s - %s through system\n", login, password);
return 0;
}
printf("Authentication failed!\n");
return 1;
}
Compile code:
gcc -o authModule authModule.c -lpam
Run code (as the new user!):
./authModule user password
That’s all!! :-) Hope it helps!
Configuring MongoDB to authenticate user's password via Linux PAM
Unfortunately, MongoDB authentication using PAM Linux seems to be configurable only in MongoDB Enterprise Edition.
This is because PAM Authentication requires PLAIN Authentication Mechanism, available only in MongoDB Enterprise Edition as mentionned in the documentation:
PLAIN (LDAP SASL) External authentication using LDAP. You can also use PLAIN for authenticating in-database users. PLAIN transmits passwords in plain text. This mechanism is available only in MongoDB Enterprise.
BTW, in MongoDB Enterprise Edition, you can enable PAM Authentication using the following (tested on Debian Stretch):
Install saslauthd
apt-get install sasl2-bin
vi /etc/default/saslauthd
START=yes
/etc/init.d/saslauthd restart
At this step you may test your sasl configuration with ("myuser" is your unix user):
testsaslauthd -u <myuser> -p <SecretPassword>
This should output a success message:
0: OK "Success."
Create a MongoDB user "myuser"
Replace "myuser" with the user with whom you want to authenticate.
mongo admin
db.getSiblingDB("$external").createUser(
{
user : "myuser",
roles: [ { role: "read", db: "mydb" } ]
}
)
Configure MongoDB to enable PLAIN Authentication Mechanism
vi /etc/mongod.conf
security:
authorization: enabled
setParameter:
authenticationMechanisms: PLAIN,MONGODB-X509,SCRAM-SHA-1,SCRAM-SHA-256
You should add the (Linux) mongodb user to the sasl group (this makes sure that MongoDB has the permission to access saslauthd)
adduser mongodb sasl
Restart mongod
systemctl restart mongod.service
Connect to MongoDB
Now, on MongoDB Enterprise, you should be able to authenticate using your linux username/pwd:
mongo --authenticationMechanism=PLAIN --authenticationDatabase='$external' -u myuser mydb
MongoDB shell version v4.0.7
connecting to: mongodb://127.0.0.1:27017/mydb?authMechanism=PLAIN&authSource=%24external&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("********-****-****-****-************") }
MongoDB server version: 4.0.7
MongoDB Enterprise >
On MongoDB Community Edition, it sadly fails with an "Unsupported mechanism" error:
MongoDB shell version v4.0.7
connecting to: mongodb://127.0.0.1:27017/mydb?authMechanism=PLAIN&authSource=%24external&gssapiServiceName=mongodb
2019-03-25T18:26:51.307+0100 E QUERY [js] Error: Unsupported mechanism 'PLAIN' on authentication database '$external' :
connect@src/mongo/shell/mongo.js:343:13
@(connect):3:6
exception: connect failed
How to set up diferent password rules for regular users and for root on PAM
Note that root is not asked for an old password so the checks that compare the old and new password are not performed.
So, basically, the phrase
The following rule does not apply to the root password
means you can't make difok=7 work for root and not that you must create a separate rule for root.
PAM Authentication for a Legacy Application
This is what I ended up doing. See the comment marked with three asterisks.
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <security/pam_appl.h>
#include <unistd.h>
// To build this:
// g++ test.cpp -lpam -o test
// if pam header files missing try:
// sudo apt install libpam0g-dev
struct pam_response *reply;
//function used to get user input
int function_conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
{
*resp = reply;
return PAM_SUCCESS;
}
int main(int argc, char** argv)
{
if(argc != 2) {
fprintf(stderr, "Usage: check_user <username>\n");
exit(1);
}
const char *username;
username = argv[1];
const struct pam_conv local_conversation = { function_conversation, NULL };
pam_handle_t *local_auth_handle = NULL; // this gets set by pam_start
int retval;
// local_auth_handle gets set based on the service
retval = pam_start("common-auth", username, &local_conversation, &local_auth_handle);
if (retval != PAM_SUCCESS)
{
std::cout << "pam_start returned " << retval << std::endl;
exit(retval);
}
reply = (struct pam_response *)malloc(sizeof(struct pam_response));
// *** Get the password by any method, or maybe it was passed into this function.
reply[0].resp = getpass("Password: ");
reply[0].resp_retcode = 0;
retval = pam_authenticate(local_auth_handle, 0);
if (retval != PAM_SUCCESS)
{
if (retval == PAM_AUTH_ERR)
{
std::cout << "Authentication failure." << std::endl;
}
else
{
std::cout << "pam_authenticate returned " << retval << std::endl;
}
exit(retval);
}
std::cout << "Authenticated." << std::endl;
retval = pam_end(local_auth_handle, retval);
if (retval != PAM_SUCCESS)
{
std::cout << "pam_end returned " << retval << std::endl;
exit(retval);
}
return retval;
}
Related Topics
Can a Program Read Its Own Elf Section
Sdl Configuration in Eclipse Ide
Find a Line in a File and Add Something to The End of The Line in Bash
Gnu Octave, Round a Number to Units Precision
Swift on Linux: Make Very First Step Work
How Does Copy-On-Write in Fork() Handle Multiple Fork
Replace Column If Equal to a Specific Value
Linux Postfix/Dovecot 554 Relay Access Denied
User-Space Memory Editing Programs
Dynamic Listening Ports Inside Docker Container
Batch Crop and Resize Images to Create Thumbnails
X86 Assembly, Little Endianness Not Being Followed(Or Is It) (Linux)
Linux/Unix Socket Self-Connection
How to Edit a Symlink with a Text Editor
Is Anyone Using Netlink for Ipc