203 lines
3.9 KiB
C
203 lines
3.9 KiB
C
#define _GNU_SOURCE
|
|
#include <crypt.h>
|
|
#include <fcntl.h>
|
|
#include <grp.h>
|
|
#include <pwd.h>
|
|
#include <shadow.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <termios.h>
|
|
#include <unistd.h>
|
|
|
|
#define MAX_IDS 100
|
|
long long ids[MAX_IDS] = { 0 };
|
|
size_t ids_len = 0;
|
|
|
|
read_ids()
|
|
{
|
|
FILE *f = fopen("/etc/sus", "r");
|
|
if (!f) return 0;
|
|
while (!feof(f))
|
|
fscanf(f, "%lld", &ids[ids_len++]);
|
|
if (ids_len == 0) return 0;
|
|
return 1;
|
|
}
|
|
|
|
check_password(pass_buf)
|
|
char *pass_buf;
|
|
{
|
|
struct spwd* shadow_entry;
|
|
struct passwd* pa;
|
|
char *p, *correct, *supplied, *salt;
|
|
pa = getpwuid(getuid());
|
|
|
|
shadow_entry = getspnam(pa->pw_name);
|
|
if (shadow_entry == NULL)
|
|
return 2;
|
|
|
|
supplied = crypt(pass_buf, shadow_entry->sp_pwdp);
|
|
if (supplied == NULL)
|
|
return 6;
|
|
return !!strcmp(supplied, shadow_entry->sp_pwdp);
|
|
}
|
|
|
|
int getting_pass = 0;
|
|
ask_password()
|
|
{
|
|
getting_pass = 1;
|
|
int i = 3;
|
|
while (i--) {
|
|
char *pass_buf = getpass("Password: ");
|
|
if (!pass_buf || *pass_buf == '\0') {
|
|
i++;
|
|
continue;
|
|
}
|
|
int res = check_password(pass_buf);
|
|
memset(pass_buf, 0, strlen(pass_buf)-1);
|
|
if (res == 0) {
|
|
getting_pass = 0;
|
|
return 1;
|
|
} else
|
|
fputs("Wrong password!\n", stderr);
|
|
sleep(1);
|
|
}
|
|
getting_pass = 0;
|
|
return 0;
|
|
}
|
|
|
|
int_handler()
|
|
{
|
|
if (getting_pass)
|
|
return;
|
|
fputs("Cancelled.\n", stderr);
|
|
exit(0);
|
|
}
|
|
|
|
is_valid()
|
|
{
|
|
int i, j, groups = getgroups(0, NULL);
|
|
gid_t list[groups];
|
|
int ngroups = getgroups(groups, list);
|
|
|
|
if (ngroups < 0)
|
|
return -1;
|
|
|
|
for (i = 0; i < groups; i++) {
|
|
struct group* grp;
|
|
grp = getgrgid(list[i]);
|
|
if (grp == NULL)
|
|
return 0;
|
|
|
|
for (j = 0; j < ids_len; j++)
|
|
if (grp->gr_gid == ids[j])
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
main(argc, argv, envp, cstart, uid)
|
|
char **argv; char **envp;
|
|
uid_t uid;
|
|
{
|
|
cstart = 1;
|
|
uid = 0;
|
|
struct sigaction savealrm, saveint, savehup, savequit, saveterm;
|
|
struct sigaction savetstp, savettin, savettou, savepipe;
|
|
|
|
struct sigaction sa;
|
|
sigemptyset(&sa.sa_mask);
|
|
sa.sa_flags = 0;
|
|
sa.sa_handler = int_handler;
|
|
|
|
sigaction(SIGALRM, &sa, &savealrm);
|
|
sigaction(SIGHUP, &sa, &savehup);
|
|
sigaction(SIGINT, &sa, &saveint);
|
|
sigaction(SIGPIPE, &sa, &savepipe);
|
|
sigaction(SIGQUIT, &sa, &savequit);
|
|
sigaction(SIGTERM, &sa, &saveterm);
|
|
sigaction(SIGTSTP, &sa, &savetstp);
|
|
sigaction(SIGTTIN, &sa, &savettin);
|
|
sigaction(SIGTTOU, &sa, &savettou);
|
|
|
|
if (argc < 2) {
|
|
fprintf(stderr, "Usage: %s [- user] -- command\n", argv[0]);
|
|
return 0;
|
|
}
|
|
|
|
if (strcmp(*(argv + cstart), "-") == 0) {
|
|
if (argc < 4) {
|
|
fprintf(stderr, "No command or user specified.\n");
|
|
return -1;
|
|
}
|
|
|
|
struct passwd *p = getpwnam(argv[2]);
|
|
if (!p) {
|
|
fprintf(stderr, "Invalid user specified.\n");
|
|
return -1;
|
|
}
|
|
|
|
uid = p->pw_uid;
|
|
char **envp2 = envp;
|
|
while (*envp2 != NULL) {
|
|
if (strncmp(*envp2, "USER=", 5) == 0) {
|
|
char *new_user_string = malloc(strlen(p->pw_name) + 6);
|
|
sprintf(new_user_string, "USER=%s", p->pw_name);
|
|
strcpy(*envp2, new_user_string);
|
|
free(new_user_string);
|
|
break;
|
|
}
|
|
envp2++;
|
|
}
|
|
cstart += 2;
|
|
}
|
|
|
|
if (strcmp(*(argv + cstart), "--") == 0) {
|
|
struct passwd *p = getpwuid(uid);
|
|
if (!p) {
|
|
fprintf(stderr, "UID not found, this should not happen.\n");
|
|
return -1;
|
|
}
|
|
|
|
chdir(p->pw_dir);
|
|
cstart++;
|
|
if (argc - cstart < 1) {
|
|
fprintf(stderr, "Command not found.\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (!read_ids()) {
|
|
fputs("Failed to read ids file /etc/sus.\n", stderr);
|
|
return -1;
|
|
}
|
|
|
|
if (!is_valid()) {
|
|
fputs("Not in the susers file, this incident won't be reported.\n", stderr);
|
|
return -1;
|
|
}
|
|
|
|
if (ask_password() != 1) {
|
|
fputs("Too many attempts.\n", stderr);
|
|
return -1;
|
|
}
|
|
|
|
sigaction(SIGALRM, &sa, NULL);
|
|
sigaction(SIGHUP, &sa, NULL);
|
|
sigaction(SIGINT, &sa, NULL);
|
|
sigaction(SIGPIPE, &sa, NULL);
|
|
sigaction(SIGQUIT, &sa, NULL);
|
|
sigaction(SIGTERM, &sa, NULL);
|
|
sigaction(SIGTSTP, &sa, NULL);
|
|
sigaction(SIGTTIN, &sa, NULL);
|
|
sigaction(SIGTTOU, &sa, NULL);
|
|
|
|
argv += cstart;
|
|
setuid(uid);
|
|
execvpe(argv[0], argv, envp);
|
|
|
|
return 0;
|
|
}
|
|
|