I want to change any Linux user password using C++, any solution would be great.
I need to do it manually, that mean by opening files (Can't use system()):
- /etc/passwd
- /etc/shadow
- /etc/group
Also seems I need to lock these files. Have c code sample for opening .txt file and reading content, but can't read large content, that is problem too.
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/file.h>
#include <stdlib.h>
#include <string>
const char* path = "/tmp/log.txt";
void read_file()
{
int fd;
char buf[1000];
int i;
fd = open(path, O_RDONLY);
flock(fd, LOCK_SH);
for(i=0; i < 255 ; i++) {
read(fd, &buf[i], 1);
usleep(10 * 10); // 10 ms
}
flock(fd, LOCK_UN);
close(fd);
printf("reader: %#x: %s\n", getpid(), buf);
usleep(10 * 10); // 10 ms
}
void reader()
{
read_file();
exit(0);
}
int main()
{
setlinebuf(stdout);
reader();
return 0;
}
In ideal solution it must work like that:
- Program ask to enter username.
- Program ask to enter new password.
- Open necessary file, change password and save file, but not corrupt it.
Can someone explain with which file I need to work to change password and how to open it properly to not hurt the system? How to edit exactly that line where is password?
At the moment i'm working on Ubuntu 16.04.
EDIT
I saw in comments that normal user cant access these files. And one comment was to give permissions to every user change any user password.
So what about if one user have permissions to edit these files and change password to any user. So is it way to safe open and edit system file shadow
, save and close it. I need to lock it somehow or how I can access it?
There is shadow
file structure, as all can see there is special hash or crypt for password, so if change it properly and save file, password must change.
My code to get user data using username:
#include <stdio.h>
#include <pwd.h>
#include <iostream>
using namespace std;
int main()
{
struct passwd *p_entry1, *p_entry2;
char* username;
cout<<"Insert username: ";
cin>>username;
/* Find user data by entered username */
p_entry1 = getpwnam(username);
printf("username = %s = %s"
" userid = %d group id = %d"
" real name = %s directory = %s"
" primary shell = %s",
p_entry1->pw_name, p_entry1->pw_passwd,
p_entry1->pw_uid, p_entry1->pw_gid,
p_entry1->pw_gecos, p_entry1->pw_dir,
p_entry1->pw_shell);
}
You cannot access these files directly, of course, because they're privileged files that are owned by root. After all, there wouldn't be much security if any process can randomly scribble over these files, and change anyone's password.
As such, there is no way to avoid privilege escalation in order to update a system password. This is a basic, fundamental security principle.
So, no matter how you go about it, at some point, something, somewhere, has to system()
-execute a privileged binary. There is a reason why /usr/bin/passwd
is a setuid-root binary.
So, if you can't use system()
, you cannot do it. This is fundamental.
The most that can could possibly be done here is to have a separate daemon process running, as root, and have your application connect and communicate with it, passing the appropriate credentials to it, and have the daemon process take care of changing the password. This would avoid having to use system()
directly, by the application.
As far as the task of actually changing the password, once you have sufficient root privileges to do it, this is not typically done by scribbling over the files yourself. The Linux PAM library provides an API for verifying and updating system passwords. Consult the Linux PAM library documentation for more information.
To change a user's password you may use the putpwent and putspent functions from <pwd.h>
and <shadow.h>
respectively. This way you don't need to explicitly read, parse, and write the passwd and shadow files.
Regarding permissions:
If you're not willing to run your program as root, an alternative is to give setuid permission to your executable file, just like the passwd
executable itself.
chown root.root <executable>
chmod u+s <executable>
A setuid
program is executed under the privileges/permissions of its owner (in this case root
), so you're granted the binary owner's privileges/permissions.
If your binary is owned by root
and it has the suid
permission, it will be able to change /etc/passwd
and any other files that only root
has access to. This is quite handy, but at the same time it can be quite dangerous. For instance, if your program has a bug or unforeseen circumstance, it may be exploited by a malicious user to gain root privilege/access in your system.
Writing secure programs seem to be simple, but it has various gotchas. Good luck!
All is possible in this way -> to make c++ code which change password I done this:
- Password must be encrypted, so I used code to make it in
$6$:SHA-512
hash.
- Must open
/etc/shadow
file, read it, find user by username and change password. There you can read about shadow
file structure.
To open file used fstream, to find and change line I used std::getline
and std::vector
.
To run .cpp file, need to be root in terminal, run g++ fileName.cpp -o excqFileName -lcrypt
and ./excqFileName
commands. Thats it's for me.
That all folks, I did my task and it's possible. Will not share code, but I explained enough to understand how it works.