Related
The following C program can check the password of a user on Linux.
But it does not work on macOS because some functions are Linux specific.
Could anybody show me how to revise the program so that it works on macOS?
#include <unistd.h>
#include <pwd.h>
#include <shadow.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
char *username = argv[1];
struct passwd *pwd = getpwnam(username);
if (pwd == NULL) {
fputs("couldn't get password record", stderr);
return 1;
}
struct spwd *spwd = getspnam(username);
if (spwd == NULL) {
if(errno == EACCES) {
fputs("no permission to read shadow password file", stderr);
return 1;
}
fputs("No such username", stderr);
return 1;
}
char *password = getpass("Password: ");
printf("spwd->sp_pwdp: %s\n", spwd->sp_pwdp);
char *encrypted = crypt(password, spwd->sp_pwdp);
for (char *p = password; *p != '\0'; ++p)
*p = '\0';
if (encrypted == NULL) {
perror("crypt");
return 1;
}
if (strcmp(encrypted, spwd->sp_pwdp) != 0) {
fputs("Incorrect password\n", stderr);
return 1;
}
printf("Successfully authenticated: UID=%d\n", pwd->pw_uid);
return 0;
}
$ sudo ./checkpass "$USER"
Password:
spwd->sp_pwdp: $y$j9T$F5Jx5fExrKuPp53xLKQ..1$X3DX6M94c7o.9agCG9G317fhZg9SqC.5i5rd.RhAtQ7
Successfully authenticated: UID=504
Both Linux and macOS use PAM for authentication; Linux uses Linux-PAM, and MacOS and BSDs OpenPAM.
To authenticate via PAM:
/*
This is a variant of the Linux-PAM example at
http://www.linux-pam.org/Linux-PAM-html/adg-example.html
modified to use the 'login' PAM service.
That program was contributed by Shane Watts
[modifications by AGM and kukuk]
Save as ex_login.c, compile using (for Linux-PAM):
gcc -Wall -Wextra -O2 ex_login.c -lpam -lpam_misc -o ex_login
or (for OpenPAM):
gcc -DOPENPAM -Wall -Wextra -O2 ex_login.c -lpam -o ex_login
and run
./ex_login username
to authenticate the specified user.
*/
#include <stdlib.h>
#include <security/pam_appl.h>
#ifdef OPENPAM
#include <security/openpam.h>
#define USE_CONV_FUNC openpam_ttyconv
#else
#include <security/pam_misc.h>
#define USE_CONV_FUNC misc_conv
#endif
#include <stdio.h>
static struct pam_conv conv = {
USE_CONV_FUNC,
NULL
};
int main(int argc, char *argv[])
{
const char *arg0 = (argc > 0 && argv && argv[0] && argv[0][0] != '\0') ? argv[0] : "(this)";
pam_handle_t *pamh = NULL;
int retval;
const char *user;
if (argc != 2) {
fprintf(stderr, "\nUsage: %s USERNAME\n\n", arg0);
exit(EXIT_FAILURE);
}
user = argv[1];
retval = pam_start("login", user, &conv, &pamh);
if (retval == PAM_SUCCESS)
retval = pam_authenticate(pamh, 0); /* is user really user? */
if (retval == PAM_SUCCESS)
retval = pam_acct_mgmt(pamh, 0); /* permitted access? */
/* This is where we have been authorized or not. */
if (retval == PAM_SUCCESS) {
fprintf(stdout, "Authenticated\n");
} else {
fprintf(stdout, "Not Authenticated\n");
}
if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */
pamh = NULL;
fprintf(stderr, "%s: failed to release authenticator\n", arg0);
exit(EXIT_FAILURE);
}
return ( retval == PAM_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE );
}
I have an application running on an unprivileged user, but at some point this program needs to run another one as a root, would be nice if I can reuse a configured PAM module, like, su, sudo, login or anyone.
So I am trying to write some code to authenticate the root and run this program using PAM, like sudo does, but I cant ask for password, it needs to be automatic. This unprivileged program in a specific time will have the access to root password.
Tried this example here https://www.netbsd.org/docs/guide/en/chap-pam.html but on pam_authenticate, it always return PAM_AUTH_ERR, I have tried all configured modules on my ubuntu 18.04.
#include <security/pam_appl.h>
#include <security/pam_misc.h>
#include <stdio.h>
#include <sys/wait.h>
#include <err.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <grp.h>
#include <assert.h>
#include <string>
#include <vector>
int converse(int n, const struct pam_message **msg, struct pam_response **resp, void *data)
{
struct pam_response *aresp;
char buf[PAM_MAX_RESP_SIZE];
int i;
data = data;
if (n <= 0 || n > PAM_MAX_NUM_MSG)
return (PAM_CONV_ERR);
if ((aresp = (struct pam_response *) calloc(n, sizeof *aresp)) == NULL)
return (PAM_BUF_ERR);
for (i = 0; i < n; ++i) {
aresp[i].resp_retcode = 0;
aresp[i].resp = NULL;
switch (msg[i]->msg_style) {
case PAM_PROMPT_ECHO_OFF:
//aresp[i].resp = strdup(getpass(msg[i]->msg));
aresp[i].resp = strdup("mypass");
aresp[i].resp_retcode = 0;
if (aresp[i].resp == NULL)
goto fail;
break;
case PAM_PROMPT_ECHO_ON:
fputs(msg[i]->msg, stderr);
if (fgets(buf, sizeof buf, stdin) == NULL)
goto fail;
aresp[i].resp = strdup(buf);
if (aresp[i].resp == NULL)
goto fail;
break;
case PAM_ERROR_MSG:
fputs(msg[i]->msg, stderr);
if (strlen(msg[i]->msg) > 0 &&
msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
fputc('\n', stderr);
break;
case PAM_TEXT_INFO:
fputs(msg[i]->msg, stdout);
if (strlen(msg[i]->msg) > 0 &&
msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
fputc('\n', stdout);
break;
default:
goto fail;
}
}
*resp = aresp;
return (PAM_SUCCESS);
fail:
for (i = 0; i < n; ++i) {
if (aresp[i].resp != NULL) {
memset(aresp[i].resp, 0, strlen(aresp[i].resp));
free(aresp[i].resp);
}
}
memset(aresp, 0, n * sizeof *aresp);
*resp = NULL;
return (PAM_CONV_ERR);
}
static struct pam_conv conv = {
converse,
//misc_conv,
NULL
};
extern char **environ;
static pam_handle_t *pamh;
static struct pam_conv pamc;
static void
usage(void)
{
fprintf(stderr, "Usage: su [login [args]]\n");
exit(1);
}
int
main(int argc, char *argv[])
{
char hostname[64];
const char *user, *tty;
char **args, **pam_envlist, **pam_env;
struct passwd *pwd;
int o, pam_err, status;
pid_t pid;
while ((o = getopt(argc, argv, "h")) != -1)
switch (o) {
case 'h':
default:
usage();
}
argc -= optind;
argv += optind;
if (argc > 0) {
user = *argv;
--argc;
++argv;
} else {
user = "root";
}
int pam_status = PAM_SUCCESS;
/* initialize PAM */
//pamc.conv = &openpam_ttyconv;
if ((pam_status = pam_start("passwd", user, &conv, &pamh)) != PAM_SUCCESS)
{
assert(false);
}
/* set some items */
gethostname(hostname, sizeof(hostname));
if ((pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS)
{
assert(false);
}
user = getlogin();
if ((pam_err = pam_set_item(pamh, PAM_RUSER, user)) != PAM_SUCCESS)
{
assert(false);
}
tty = ttyname(STDERR_FILENO);
if ((pam_err = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS)
{
assert(false);
}
/* authenticate the applicant */
pam_err = pam_authenticate(pamh, PAM_SILENT);
if (pam_err != PAM_SUCCESS)
{
printf("Pam Error (%d)\n", pam_err);
warn("pam_authenticate");
assert(false);
}
printf("AUTHENTICATED ;-)");
assert(false);
if ((pam_err = pam_acct_mgmt(pamh, 0)) == PAM_NEW_AUTHTOK_REQD)
pam_err = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
if (pam_err != PAM_SUCCESS)
{
assert(false);
}
/* establish the requested credentials */
if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
{
assert(false);
}
/* authentication succeeded; open a session */
if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS)
{
assert(false);
}
/* get mapped user name; PAM may have changed it */
pam_err = pam_get_item(pamh, PAM_USER, (const void **)&user);
if (pam_err != PAM_SUCCESS || (pwd = getpwnam(user)) == NULL)
{
assert(false);
}
/* export PAM environment */
if ((pam_envlist = pam_getenvlist(pamh)) != NULL) {
for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) {
putenv(*pam_env);
free(*pam_env);
}
free(pam_envlist);
}
std::vector<std::string> arguments;
arguments.resize(argc + 2);
char * args_ptr [arguments.size()];
arguments[0] = pwd->pw_shell;
args_ptr[argc +1] = NULL;
args_ptr[0] = (char *)arguments[0].c_str();
for (int i = 0; i < argc; i++)
{
arguments[i + 1] = argv[i];
args_ptr[i+1] = (char *)arguments[i+1].c_str();
}
/* set uid and groups */
if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
warn("initgroups()");
_exit(1);
}
if (setgid(pwd->pw_gid) == -1) {
warn("setgid()");
_exit(1);
}
if (setuid(pwd->pw_uid) == -1) {
warn("setuid()");
_exit(1);
}
execve(args_ptr[0], args_ptr, environ);
warn("execve()");
_exit(1);
pamerr:
fprintf(stderr, "Sorry\n");
err:
pam_end(pamh, pam_err);
exit(1);
}
I expect to fork in a elevated child and run my new program, without asking for password.
I know it might be a duplicate question but I couldn't find a solution for my problem yet.
What I want to do
I'm trying to write in C a sort of simulation of a growing society where there are 2 types of persons, A and B (2 people in my example).
A accepts "engagement proposals" from B
The communication between A, B and gestore is handled with message queues
gestore decides attributes of every "person" and then creates them with execve, passing each attribute as argument
There is a main message queue where each A process sends a message with its info and the key of his private message queue
B reads from the main message queue and then communicates with A using the given key found in the message
I'm under Linux Mint 18.3 32 bit.
The problem
It always gives the error stack smashing detected in file
My files
header.h
#ifndef _HEAD_H
#define _HEAD_H
#include <unistd.h>
#include <sys/msg.h>
#define OFFSET 1000000
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
struct person{
char type;
int name;
unsigned long genome;
};
struct msg_text {
pid_t pid;
char type;
int name;
unsigned long genome;
int key_of_love;
pid_t partner;
};
struct mymsg {
long mtype;
struct msg_text mtxt;
};
int initSemAvailable(int, int);
int initSemInUse(int, int);
int reserveSem(int, int);
int releaseSem(int, int);
#endif
header.c
#include <sys/sem.h>
#include <sys/types.h>
#include "header.h"
int initSemAvailable(int semId, int semNum)
{
union semun arg;
arg.val = 1;
return semctl(semId, semNum, SETVAL, arg);
}
int initSemInUse(int semId, int semNum)
{
union semun arg;
arg.val = 0;
return semctl(semId, semNum, SETVAL, arg);
}
int reserveSem(int semId, int semNum) {
struct sembuf sops;
sops.sem_num = semNum;
sops.sem_op = -1;
sops.sem_flg = 0;
return semop(semId, &sops, 1);
}
int releaseSem(int semId, int semNum) {
struct sembuf sops;
sops.sem_num = semNum;
sops.sem_op = 1;
sops.sem_flg = 0;
return semop(semId, &sops, 1);
}
gestore.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "header.h"
#ifndef MAX_PEOPLE
#define MAX_PEOPLE 5
#endif
#ifndef GENES
#define GENES 1000000
#endif
#ifndef BIRTH_DEATH
#define BIRTH_DEATH 5
#endif
#define SIZE_N 15
//handle signals
struct sigaction sa;
sigset_t my_mask;
void handle_signal(int);
//remove every IPC object
void remove_all();
//terminate every child
void terminate_children();
//free memory
void free_all();
//print every field of message
void print_msg(struct mymsg);
unsigned int init_people;
int * child_status;
pid_t * initial_children;
char * child_name;
char * child_genome;
char * child_sem;
char * child_sem2;
char * child_msgq_a;
//message queue
struct msqid_ds msq;
int msgq_a;
//semaphores
int sem_init_people;
int sem_init_people2;
int main(void)
{
init_people = 0;//will contain initial number of people
int i = 0;
pid_t child;//fork value
unsigned long random_ulong = 0;
child_name = (char *)calloc(SIZE_N, sizeof(char));
child_genome = (char *)calloc(SIZE_N, sizeof(char));
child_sem = (char*)calloc(SIZE_N, sizeof(char));
child_sem2 = (char*)calloc(SIZE_N, sizeof(char));
child_msgq_a = (char*)calloc(SIZE_N, sizeof(char));
char * args[8] = {};
char * envs[] = {NULL};
if( child_name == NULL || child_genome == NULL
|| child_sem == NULL || child_sem2 == NULL
|| child_msgq_a == NULL){
perror("there's a null variable");
exit(EXIT_FAILURE);
}
//handle signals
sa.sa_handler = &handle_signal;
sa.sa_flags = 0;
sigemptyset(&my_mask);
sigaction(SIGALRM, &sa, NULL);
sigaction(SIGUSR1, &sa, NULL);
printf("\nSTARTING SIMULATION\n\n");
init_people = 2;
initial_children = (pid_t *)calloc(init_people,
sizeof(pid_t));
//create 2 semaphores
sem_init_people = semget(IPC_PRIVATE, 1,
0666|IPC_CREAT|IPC_EXCL);
if( sem_init_people == -1 ){
if(errno == EEXIST){
if( semctl(sem_init_people, 0,
IPC_RMID, NULL) == -1 ){
perror("rm sem_init_people");
exit(EXIT_FAILURE);
}
}else{
perror("semget init_people");
exit(EXIT_FAILURE);
}
}
sem_init_people2 = semget(IPC_PRIVATE, 1,
0666|IPC_CREAT|IPC_EXCL);
if( sem_init_people2 == -1 ){
if(errno == EEXIST){
if( semctl(sem_init_people2, 0,
IPC_RMID, NULL) == -1 ){
perror("remove sem_init_people2");
exit(EXIT_FAILURE);
}
}else{
perror("semget sem_init_people2");
exit(EXIT_FAILURE);
}
}
//create message queue
msgq_a = msgget(IPC_PRIVATE, 0666|IPC_CREAT|IPC_EXCL);
if(msgq_a == -1){
if( errno == EEXIST ){//if exists
// delete message queue
if( msgctl(msgq_a, IPC_RMID, &msq) == -1 )
perror("rmid");
}else
perror("msgget queue A");
exit(EXIT_FAILURE);
}
//initialize sem_init_people to 0 (reserved)
if( initSemInUse(sem_init_people, 0) == -1 ){
perror("initSemInUse for sem_init_people");
exit(EXIT_FAILURE);
}
//initialize sem_init_people2 to 0 (reserved)
if( initSemInUse(sem_init_people2, 0) == -1 ){
perror("initSemInUse for sem_init_people");
exit(EXIT_FAILURE);
}
//RWX permissions for people processes
if( chmod("./A", 0777) != 0 ){
perror("chmod person A");
exit(EXIT_FAILURE);
}
if( chmod("./B", 0777) != 0 ){
perror("chmod person B");
exit(EXIT_FAILURE);
}
printf("Generating %u people\n\n", init_people);
//generate initial population
for(i = 0; i < init_people; i++){
//TYPE
if( i%2 == 0 )
args[0] = "./A";
else
args[0] = "./B";
//NAME
if( sprintf(child_name, "%d", i+65) < 0 ){
perror("printf NAME execve");
exit(EXIT_FAILURE);
}
args[1] = child_name;
//GENOME
if( sprintf(child_genome, "%lu",
(long)i+100000) < 0 ){
perror("sprintf GENOME execve");
exit(EXIT_FAILURE);
}
args[2] = child_genome;
//semaphore 1
if( sprintf(child_sem, "%d",
sem_init_people) < 0 ){
perror("sprintf sem_init_prople execve");
exit(EXIT_FAILURE);
}
args[3] = child_sem;
//semaphore 2
if( sprintf(child_sem2, "%d",
sem_init_people2) < 0 ){
perror("sprintf sem_init_prople2 execve");
exit(EXIT_FAILURE);
}
args[4] = child_sem2;
//msg queue
if( sprintf(child_msgq_a, "%d", msgq_a) < 0 ){
perror("sprintf child_msgq_a execve");
exit(EXIT_FAILURE);
}
args[5] = child_msgq_a;
//final argument
args[6] = NULL;
switch(child = fork()){
case -1:{ //error
perror("fork init_people");
exit(EXIT_FAILURE);
}
case 0:{//child
if( execve(args[0], args, envs) == -1 ){
perror("execve");
}
//execve didnt't work
exit(EXIT_FAILURE);
}
default:{//parent
printf("[type:%c][name:%c][pid:%d][gen:%s][sem1:%s]\
[sem2:%s][msgq:%s]\n",
args[0][2],
atoi(args[1]),
(int)child,
args[2],
args[3],
args[4],
args[5] );
//add every child in the array
initial_children[i] = child;
}
}//-switch
}//-for
//wait for every child to be ready to start
for(i = 0; i < init_people; i++){
if( reserveSem(sem_init_people, 0) != 0 ){
perror("reserveSem sem_init_people");
exit(EXIT_FAILURE);
}
}
//allow every child to start
for(i = 0; i < init_people; i++){
if( releaseSem(sem_init_people2, 0) != 0 ){
perror("releaseSem sem_init_people2");
exit(EXIT_FAILURE);
}
}
//wait for termination of every child
if( waitpid(-1, child_status, (int)WNOHANG) == -1 ){
perror("waitpid");
}
printf("Father is now waiting...\n");
for(i = 0; i < 3; i++){
sleep(3);
}
terminate_children();
remove_all();
free_all();
return EXIT_SUCCESS;
}
void handle_signal(int signum)
{
switch(signum){
case SIGUSR1:{
pid_t pidA = 0, pidB = 0;
unsigned long genomeA = 0, genomeB = 0;
struct mymsg msg1, msg2;
int msg_flag = 0;
//ignore sigusr1
if( sigaddset(&my_mask, SIGUSR1) == -1 ){
perror("sigaddset");
exit(EXIT_FAILURE);
}
//read for every message
while(msg_flag == 0){
if( msgrcv(msgq_a, &msg1, sizeof(msg1),
OFFSET+getpid(), IPC_NOWAIT) == -1 ){
if( errno == ENOMSG ){
msg_flag = -1;
printf("gestore is empty\n");
}else{ //random error happened
perror("msgrcv parent A and B");
exit(EXIT_FAILURE);
}
}else{
print_msg(msg1);
msg_flag = 0;
}
}
//do not ignore SIGUSR1
if( sigdelset(&my_mask, SIGUSR1) == -1 ){
perror("sigdelset");
exit(EXIT_FAILURE);
}
break;
}
default:{}
}
}
void terminate_children()
{
int i = 0;
for(i = 0; i < init_people; i++){
if( kill(initial_children[i], 0) == 0 ){
if( kill(initial_children[i], SIGTERM) == -1){
perror("kill sigterm to child");
}
}
}
}
void remove_all()
{
//...
}
void free_all()
{
//...
}
void print_msg(struct mymsg msg)
{
printf("gestore rcv [mtype:%lu][pid:%d][type:%c]\
[name:%c][gen:%lu][key<3:%d][pid<3:%d]\n",
msg.mtype,
(int)msg.mtxt.pid,
msg.mtxt.type,
msg.mtxt.name,
msg.mtxt.genome,
msg.mtxt.key_of_love,
(int)msg.mtxt.partner );
}
personA.c
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "header.h"
#define NMEMB 50
void accept_lover(int msgq, int love_msg_queue,
struct mymsg love_letter, struct person myself);
void reject_lover(int, struct mymsg love_letter);
struct sigaction sa;
void handle_signal(int);
void print_rcvd_msg(struct mymsg);
void print_sent_msg(struct mymsg);
struct msqid_ds msq;
int love_msg_queue;
int main(int argc, char** argv)
{
if(argc < 6){
perror("A argc");
exit(EXIT_FAILURE);
}
struct person myself;//info of A process
myself.type = 'A';
myself.name = (int)atoi(argv[1]);
myself.genome = (unsigned long)atol(argv[2]);
int sem_init_people, sem_init_people2;
sem_init_people = (int)atoi(argv[3]);
sem_init_people2 = (int)atoi(argv[4]);
int msgq = atoi(argv[5]);
struct mymsg msg_out, love_letter;
struct msqid_ds msq;
int engaged = -1;
int count_refused = 0;
sa.sa_handler = &handle_signal;
sigaction(SIGTERM, &sa, NULL);
//tell parent you're ready
if( releaseSem(sem_init_people, 0) != 0 ){
perror("releaseSem sem_init_people");
exit(EXIT_FAILURE);
}
//wait for parent permission
if( reserveSem(sem_init_people2, 0) != 0 ){
perror("reserveSem sem_init_people2");
exit(EXIT_FAILURE);
}
//create personal message queue of love
love_msg_queue = msgget(IPC_PRIVATE,
0666|IPC_CREAT|IPC_EXCL);
if( love_msg_queue == -1 ){
if( errno == EEXIST ){//if exists
// delete message queue
if( msgctl(love_msg_queue,
IPC_RMID, &msq) == -1 ){
perror("rmid queue of love");
exit(EXIT_FAILURE);
}
}else{
perror("msgget queue of love");
exit(EXIT_FAILURE);
}
}
//create message with correct info of process A
msg_out.mtype = myself.genome;
msg_out.mtxt.pid = getpid();
msg_out.mtxt.type = myself.type;
msg_out.mtxt.genome = myself.genome;
msg_out.mtxt.name = myself.name;
msg_out.mtxt.key_of_love = love_msg_queue;
msg_out.mtxt.partner = -1;
//when A accepts B engaged = 0
while(engaged != 0){
//send info in message queue
if( msgsnd(msgq, &msg_out, sizeof(msg_out), 0)
== -1 ){
if(errno == EINTR)
perror("A caught a signal and failed \
a blocked msgsnd");
else
perror("A msgsnd");
exit(EXIT_FAILURE);
}
print_sent_msg(msg_out);
//wait for love letter from B
if( msgrcv(love_msg_queue, &love_letter,
sizeof(love_letter), 0, 0) == -1 ){
perror("A msgrcv love letter from B");
exit(EXIT_FAILURE);
}
print_rcvd_msg(love_letter);
//accept B if..
if( count_refused >= 2 ){
engaged = 0;//B is good, EXIT loop
accept_lover(msgq, love_msg_queue,
love_letter, myself);
printf("[A:%d]accepted[B:%d]\n",(int)getpid(),
(int)love_letter.mtxt.pid);
}else{
reject_lover(love_msg_queue,love_letter);
printf("[A:%d] refused %d times\n",
(int)getpid(),count_refused+1);
count_refused++;
}
}
pause();
return EXIT_SUCCESS;
}
void handle_signal(int signum)
{
switch(signum){
case SIGTERM:{
printf("A SIGTERM from parent\n");
// delete message queue if exists
if( (msgctl(love_msg_queue, IPC_RMID,
&msq) == -1) && (errno != EIDRM) ){
perror("A rmid 2");
}
break;
}
default:{}
}
}
void accept_lover(int msgq, int love_msg_queue,
struct mymsg love_letter, struct person myself)
{
struct mymsg
msg_to_B, msg_to_gestore1, msg_to_gestore2;
//tell B you accept his request (key_of_love = 0)
msg_to_B.mtype = love_letter.mtype; //pid of B
msg_to_B.mtxt.pid = getpid();
msg_to_B.mtxt.type = 'A';
msg_to_B.mtxt.name = myself.name;
msg_to_B.mtxt.genome = myself.genome;
msg_to_B.mtxt.key_of_love = 0; //0 means accepted
msg_to_B.mtxt.partner = -1;
//send msg to B in queue of love
if( msgsnd(love_msg_queue, &msg_to_B,
sizeof(msg_to_B), 0) == -1 ){
perror("A msgsnd to B accept lover");
exit(EXIT_FAILURE);
}
print_sent_msg(msg_to_B);
//tell gestore that A accepted a request from B
//send message with info of A
//send message with info of B
//A
msg_to_gestore1.mtype = OFFSET + getppid();
msg_to_gestore1.mtxt.pid = getpid();
msg_to_gestore1.mtxt.type = 'A';
msg_to_gestore1.mtxt.name = myself.name;
msg_to_gestore1.mtxt.genome = myself.genome;
msg_to_gestore1.mtxt.key_of_love = 0;
msg_to_gestore1.mtxt.partner = love_letter.mtype;
//B
msg_to_gestore2.mtype = OFFSET + getppid();
msg_to_gestore2.mtxt.pid = love_letter.mtype;
msg_to_gestore2.mtxt.type = 'B';
msg_to_gestore2.mtxt.name = love_letter.mtxt.name;
msg_to_gestore2.mtxt.genome = love_letter.mtxt.genome;
msg_to_gestore2.mtxt.key_of_love = 0;
msg_to_gestore2.mtxt.partner = getpid();
//send msg B
if( msgsnd(msgq, &msg_to_gestore2,
sizeof(msg_to_gestore2), 0) == -1 ){
perror("A msg_to_gestore2");
exit(EXIT_FAILURE);
}
//send msg A
if( msgsnd(msgq, &msg_to_gestore1,
sizeof(msg_to_gestore1), 0) == -1 ){
perror("A msg_to_gestore1");
exit(EXIT_FAILURE);
}
print_sent_msg(msg_to_gestore2);
print_sent_msg(msg_to_gestore1);
/*messages for gestore have mtype=OFFSET+father_pid
so that others can't read messages with mtype greater
than OFFSET and father can directly receive messages
knowing both OFFSET and his pid. */
}
void reject_lover(int love_msg_queue,
struct mymsg love_letter)
{
love_letter.mtxt.key_of_love = -1;
if( (msgsnd(love_msg_queue, &love_letter,
sizeof(love_letter), 0) == -1) ){
perror("A error refusing B in msgsnd");
exit(EXIT_FAILURE);
}
print_sent_msg(love_letter);
}
void print_rcvd_msg(struct mymsg msg)
{
printf("A received [mtype:%lu][pid:%d][type:%c]\
[name:%c][gen:%lu][key<3:%d][pid<3:%d]\n",
msg.mtype,
(int)msg.mtxt.pid,
msg.mtxt.type,
msg.mtxt.name,
msg.mtxt.genome,
msg.mtxt.key_of_love,
(int)msg.mtxt.partner );
}
void print_sent_msg(struct mymsg msg)
{
printf("A sent [mtype:%lu][pid:%d][type:%c][name:%c]\
[gen:%lu][key<3:%d][pid<3:%d]\n",
msg.mtype,
(int)msg.mtxt.pid,
msg.mtxt.type,
msg.mtxt.name,
msg.mtxt.genome,
msg.mtxt.key_of_love,
(int)msg.mtxt.partner );
}
personB.c
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include "header.h"
//send message to A process and wait for response
int flirt(struct mymsg msg, struct person myself);
void print_rcvd_msg(struct mymsg);
void print_sent_msg(struct mymsg);
int main(int argc, char** argv)
{
if(argc < 6){
perror("B argc");
exit(EXIT_FAILURE);
}
struct person myself;
myself.type = 'B';
myself.name = (int)atoi(argv[1]);
myself.genome = (unsigned long)atol(argv[2]);
int sem_init_people, sem_init_people2;
sem_init_people = (int)atoi(argv[3]);
sem_init_people2 = (int)atoi(argv[4]);
int love_response = 1;
int msgq = atoi(argv[5]);
struct mymsg msg_out, msg_in;
struct msqid_ds msq;
//tell parent you're ready
if( releaseSem(sem_init_people, 0) != 0 ){
perror("release sem_init_people child proc");
exit(EXIT_FAILURE);
}
//wait for parent permission to start living
if( reserveSem(sem_init_people2, 0) != 0 ){
perror("reserve sem_init_people2 child proc");
exit(EXIT_FAILURE);
}
//when love_response is 0 A accepted B requests
while(love_response != 0){
//read message from queue
if( msgrcv(msgq, &msg_in, sizeof(msg_in),
-OFFSET, 0) < 1 ){
perror("msgrcv");
exit(EXIT_FAILURE);
}
print_rcvd_msg(msg_in);
//send message to A process and wait for a response
love_response = flirt(msg_in, myself);
printf("2----------------------------\n");
}
//TODO: get ready to terminate
return 0;
}
int flirt(struct mymsg msg, struct person myself)
{
int queue_of_love = msg.mtxt.key_of_love;
pid_t pid_A = msg.mtxt.pid;
struct mymsg love_letter, msg_in;
//create love letter
love_letter.mtype = getpid();
love_letter.mtxt.pid = getpid();
love_letter.mtxt.type = 'B';
love_letter.mtxt.name = myself.name;
love_letter.mtxt.genome = myself.genome;
love_letter.mtxt.key_of_love = -1;
love_letter.mtxt.partner = -1;
//send love letter to A to introduce yourself
if( msgsnd(queue_of_love, &love_letter,
sizeof(love_letter), 0) == -1 ){
perror("B - msg send love");
exit(EXIT_FAILURE);
}
printf("[B:%d] sent<3to [A:%d][mtype:%d][pid:%d]\
[type:%c][gen:%lu][name:%c][love:%d]\n",
(int)getpid(), (int)pid_A,
(int)love_letter.mtype,
(int)love_letter.mtxt.pid,
(int)love_letter.mtxt.type,
(unsigned long)love_letter.mtxt.genome,
love_letter.mtxt.name,
love_letter.mtxt.key_of_love );
//wait for response from A
if( msgrcv(queue_of_love, &msg_in, sizeof(msg_in),
getpid(), 0) == -1 ){
perror("B can't wait for A's response");
exit(EXIT_FAILURE);
}
print_rcvd_msg(msg_in);
//if key of love 0 then accepted love request
printf("1 ----------------------------\n");
return msg_in.mtxt.key_of_love;
}
void print_rcvd_msg(struct mymsg msg)
{
printf("B received [mtype:%lu][pid:%d][type:%c]\
[name:%c][gen:%lu][key<3:%d][pid<3:%d]\n",
msg.mtype,
(int)msg.mtxt.pid,
msg.mtxt.type,
msg.mtxt.name,
msg.mtxt.genome,
msg.mtxt.key_of_love,
(int)msg.mtxt.partner );
}
void print_sent_msg(struct mymsg msg)
{
printf("B sent [mtype:%lu][pid:%d][type:%c]\
[name:%c][gen:%lu][key<3:%d][pid<3:%d]\n",
msg.mtype,
(int)msg.mtxt.pid,
msg.mtxt.type,
msg.mtxt.name,
msg.mtxt.genome,
msg.mtxt.key_of_love,
(int)msg.mtxt.partner );
}
To compile and execute the project
gcc -c header.c
gcc -c personA.c header.c
gcc -c personB.c header.c
gcc -Wall -Wextra -Wconversion -pedantic -std=gnu11 -o A personA.o header.o
gcc -Wall -Wextra -Wconversion -pedantic -std=gnu11 -o B personB.o header.o
gcc -c gestore.c header.c
gcc -Wall -Wextra -Wconversion -std=gnu11 -pedantic -o gestore gestore.o header.o
./gestore
Note the lines of code in personB.c.
printf("1----------------------------\n");
printf("2----------------------------\n");
The second line doesn't get printed because of the error.
Thank you in advance for the help.
Ouput
output error, stack smashing detected
Valgrind valgrind --leak-check=full -v ./gestore gives this output:
==8647== HEAP SUMMARY:
==8647== in use at exit: 0 bytes in 0 blocks
==8647== total heap usage: 7 allocs, 7 frees, 4,179 bytes allocated
==8647==
==8647== All heap blocks were freed -- no leaks are possible
==8647==
==8647== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==8647== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
EDIT
Should I link and compile like this?
gcc -c -Wall -Wextra -Wconversion -std=gnu11 -ggdb header.c
gcc -c -Wall -Wextra -Wconversion -std=gnu11 -ggdb personA.c header.c
gcc -c -Wall -Wextra -Wconversion -std=gnu11 -ggdb personB.c header.c
gcc -Wall -pedantic -ggdb -o A personA.o header.o
gcc -Wall -pedantic -ggdb -o B personB.o header.o
gcc -c -Wall -Wextra -Wconversion -std=gnu11 -ggdb gestore.c header.c
gcc -Wall -pedantic -ggdb -o gestore gestore.o header.o
I 'heavily' edited this answer and removed statements that no longer applied, due to OPs modifying the posted code.
Note: when modifying the posted code, in general, DO NOT modify the original posted code, rather post the modified code as an EDIT. For the current question, suggest just posting interleaved code, perhaps via
#if 0
<old code>
#else
<new code>
#endif
===================
in the 'main()function that repeatedly callssystem()` Suggest the compile steps enable the warnings. At a minimum use these compile options:
-Wall -Wextra -Wconversion -pedantic -std=gnu11
Note: the above parameters need to be in the compile statements, not the link statements.
and to make debugging much easier, suggest the compile and link options include:
-ggdb
Also, that main() function will perform ALL the steps every time. Suggest writing a makefile (and executing it with make) so only those files that have changed will be re-compiled/ re-linked
================
Note: there is the setup for a message queue that the code omits, so the default values will be used. Those default values may not be correct for the OPs application.
Here is a cut/paste of a typical setup of a message queue:
Note: the code is from an application that contains LOTS of message queues taskSelector selects which message queue
/* initialize the queue attributes */
attr[taskSelector].mq_flags = 0;
attr[taskSelector].mq_maxmsg = 10;
attr[taskSelector].mq_msgsize =
sizeof(struct structITC)
+ dWEB_PAYLOAD_OVERHEAD
+ dMAX_DATA_BLOCK_SIZE;
attr[taskSelector].mq_curmsgs = 0;
================
the posted code fails to define:
struct msqid_ds -- oops it is defined in one of the header files
=================
when a check of argc indicates that the user did not enter all the needed command line parameters, then the code should output a USAGE message and exit. Something similar to:
fprintf( stderr, "USAGE: %s ..description of all needed parameters..\n", argv[0] );
exit( EXIT_FAILURE );
I implemented basic PAM module and test application from this github link.
In the src folder it has a simple PAM module and test code for it.
PAM module code mypam.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <security/pam_appl.h>
#include <security/pam_modules.h>
/* expected hook */
PAM_EXTERN int pam_sm_setcred( pam_handle_t *pamh, int flags, int argc, const char **argv ) {
return PAM_SUCCESS;
}
PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) {
printf("Acct mgmt\n");
return PAM_SUCCESS;
}
/* expected hook, this is where custom stuff happens */
PAM_EXTERN int pam_sm_authenticate( pam_handle_t *pamh, int flags,int argc, const char **argv ) {
int retval;
const char* pUsername;
retval = pam_get_user(pamh, &pUsername, "Username: ");
printf("Welcome %s\n", pUsername);
if (retval != PAM_SUCCESS) {
return retval;
}
if (strcmp(pUsername, "backdoor") != 0) {
return PAM_AUTH_ERR;
}
return PAM_SUCCESS;
}
Test code test.c:
#include <security/pam_appl.h>
#include <security/pam_misc.h>
#include <stdio.h>
const struct pam_conv conv = {
misc_conv,
NULL
};
int main(int argc, char *argv[]) {
pam_handle_t* pamh = NULL;
int retval;
const char* user = "nobody";
if(argc != 2) {
printf("Usage: app [username]\n");
exit(1);
}
user = argv[1];
retval = pam_start("check_user", user, &conv, &pamh);
// Are the credentials correct?
if (retval == PAM_SUCCESS) {
printf("Credentials accepted.\n");
retval = pam_authenticate(pamh, 0);
}
// Can the accound be used at this time?
if (retval == PAM_SUCCESS) {
printf("Account is valid.\n");
retval = pam_acct_mgmt(pamh, 0);
}
// Did everything work?
if (retval == PAM_SUCCESS) {
printf("Authenticated\n");
} else {
printf("Not Authenticated\n");
}
// close PAM (end session)
if (pam_end(pamh, retval) != PAM_SUCCESS) {
pamh = NULL;
printf("check_user: failed to release authenticator\n");
exit(1);
}
return retval == PAM_SUCCESS ? 0 : 1;
}
I built the module according to the github link instructions:
gcc -fPIC -fno-stack-protector -c src/mypam.c
sudo ld -x --shared -o /lib/security/mypam.so mypam.o
sudo ld -x --shared -o /lib/x86_64-linux-gnu/security/mypam.so mypam.o
gcc -o pam_test src/test.c -lpam -lpam_misc
I put below two command into /etc/pam.d/common-auth at the top.
auth sufficient mypam.so
account sufficient mypam.s
According to the site:
To run the test program, just do: pam_test backdoor and you should get
some messages saying that you're authenticated!
But I got following error:
abnormal#abnormal:~/Desktop$ pam_test backdoor
No command 'pam_test' found, did you mean:
Command 'pim_test' from package 'styx' (universe)
pam_test: command not found
abnormal#abnormal:~/Desktop$
what sholud I do now? I am using ubuntu 14,04 LTS. Please help.
There's nothing wrong with the code, but the invocation. You shoud use this:
abnormal#abnormal:~/Desktop$ ./pam_test backdoor
Unlike Windows, the current directory usually is not part of the search PATH on Linux.
I want to get the following details for all the NICs attached to my computer:
1) Interface name (eg. eth0)
2) Interface Number (like in Windows) if such a thing exists in Linux
3) NIC bandwidth capacity and mode (eg. 1Gb/s full duplex)
You can use getifaddrs()/freeifaddrs() to obtain a linked list of all interfaces, then ioctl(fd, SIOCGIFINDEX, struct ifreq *) to obtain the interface index for each. Since the interfaces are consecutive and always listed (regardless of whether or they are up (active) or not), I choose to enumerate them with a loop using ioctl(fd, SIOCGIFNAME, struct ifreq *) instead. In all cases fd is an AF_INET socket.
To obtain the duplex and speed of the interface, you need to use the ioctl(fd, SIOCETHTOOL, struct ifreq *) with the ifr_data pointing to a struct ethtool_cmd having cmd = ETHTOOL_GSET.
The ioctls should return -1 if they fail, and a nonnegative value (zero, I believe) if success.
Here is an example program:
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/ip.h>
#include <net/if.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
struct interface {
int index;
int flags; /* IFF_UP etc. */
long speed; /* Mbps; -1 is unknown */
int duplex; /* DUPLEX_FULL, DUPLEX_HALF, or unknown */
char name[IF_NAMESIZE + 1];
};
static int get_interface_common(const int fd, struct ifreq *const ifr, struct interface *const info)
{
struct ethtool_cmd cmd;
int result;
/* Interface flags. */
if (ioctl(fd, SIOCGIFFLAGS, ifr) == -1)
info->flags = 0;
else
info->flags = ifr->ifr_flags;
ifr->ifr_data = (void *)&cmd;
cmd.cmd = ETHTOOL_GSET; /* "Get settings" */
if (ioctl(fd, SIOCETHTOOL, ifr) == -1) {
/* Unknown */
info->speed = -1L;
info->duplex = DUPLEX_UNKNOWN;
} else {
info->speed = ethtool_cmd_speed(&cmd);
info->duplex = cmd.duplex;
}
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
if (result == -1)
return errno;
return 0;
}
int get_interface_by_index(const int index, struct interface *const info)
{
int socketfd, result;
struct ifreq ifr;
if (index < 1 || !info)
return errno = EINVAL;
socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (socketfd == -1)
return errno;
ifr.ifr_ifindex = index;
if (ioctl(socketfd, SIOCGIFNAME, &ifr) == -1) {
do {
result = close(socketfd);
} while (result == -1 && errno == EINTR);
return errno = ENOENT;
}
info->index = index;
strncpy(info->name, ifr.ifr_name, IF_NAMESIZE);
info->name[IF_NAMESIZE] = '\0';
return get_interface_common(socketfd, &ifr, info);
}
int get_interface_by_name(const char *const name, struct interface *const info)
{
int socketfd, result;
struct ifreq ifr;
if (!name || !*name || !info)
return errno = EINVAL;
socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (socketfd == -1)
return errno;
strncpy(ifr.ifr_name, name, IF_NAMESIZE);
if (ioctl(socketfd, SIOCGIFINDEX, &ifr) == -1) {
do {
result = close(socketfd);
} while (result == -1 && errno == EINTR);
return errno = ENOENT;
}
info->index = ifr.ifr_ifindex;
strncpy(info->name, name, IF_NAMESIZE);
info->name[IF_NAMESIZE] = '\0';
return get_interface_common(socketfd, &ifr, info);
}
int main(int argc, char *argv[])
{
struct interface iface;
int arg;
int status = 0;
if (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s { -h | --help }\n", argv[0]);
fprintf(stderr, " %s\n", argv[0]);
fprintf(stderr, " %s INTERFACE ...\n", argv[0]);
fprintf(stderr, "\n");
return 1;
}
if (argc > 1) {
for (arg = 1; arg < argc; arg++) {
if (get_interface_by_name(argv[arg], &iface) != 0) {
fprintf(stderr, "%s: No such interface.\n", argv[arg]);
status = 1;
continue;
}
printf("%s: Interface %d", iface.name, iface.index);
if (iface.flags & IFF_UP)
printf(", up");
if (iface.duplex == DUPLEX_FULL)
printf(", full duplex");
else
if (iface.duplex == DUPLEX_HALF)
printf(", half duplex");
if (iface.speed > 0)
printf(", %ld Mbps", iface.speed);
printf("\n");
}
} else {
for (arg = 1; ; arg++) {
if (get_interface_by_index(arg, &iface) != 0)
break;
printf("%s: Interface %d", iface.name, iface.index);
if (iface.flags & IFF_UP)
printf(", up");
if (iface.duplex == DUPLEX_FULL)
printf(", full duplex");
else
if (iface.duplex == DUPLEX_HALF)
printf(", half duplex");
if (iface.speed > 0)
printf(", %ld Mbps", iface.speed);
printf("\n");
}
}
return status;
}
If you save the above as iflist.c, you can compile it using
gcc -W -Wall -O3 iflist.c -o iflist
To see the usage, run iflist -h. To list all interfaces, run it without parameters:
./iflist
The above will use the enumeration method I described. To list only specific interfaces, run it naming the interfaces:
./iflist eth0 lo
Duplex and speed is only listed for ethernet interfaces, of course.
Edited to add:
If the above program does not supply the bandwidth and mode for an interface, here is a simplified version which reports the exact reason (errors). This one takes the interface names as commandline parameters; it does not enumerate interfaces.
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/ip.h>
#include <net/if.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
int ethernet_interface(const char *const name,
int *const index, int *const speed, int *const duplex)
{
struct ifreq ifr;
struct ethtool_cmd cmd;
int fd, result;
if (!name || !*name) {
fprintf(stderr, "Error: NULL interface name.\n");
fflush(stderr);
return errno = EINVAL;
}
if (index) *index = -1;
if (speed) *speed = -1;
if (duplex) *duplex = -1;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1) {
const int err = errno;
fprintf(stderr, "%s: Cannot create AF_INET socket: %s.\n", name, strerror(err));
fflush(stderr);
return errno = err;
}
strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
ifr.ifr_data = (void *)&cmd;
cmd.cmd = ETHTOOL_GSET;
if (ioctl(fd, SIOCETHTOOL, &ifr) < 0) {
const int err = errno;
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
fprintf(stderr, "%s: SIOCETHTOOL ioctl: %s.\n", name, strerror(err));
return errno = err;
}
if (speed)
*speed = ethtool_cmd_speed(&cmd);
if (duplex)
switch (cmd.duplex) {
case DUPLEX_HALF: *duplex = 0; break;
case DUPLEX_FULL: *duplex = 1; break;
default:
fprintf(stderr, "%s: Unknown mode (0x%x).\n", name, cmd.duplex);
fflush(stderr);
*duplex = -1;
}
if (index && ioctl(fd, SIOCGIFINDEX, &ifr) >= 0)
*index = ifr.ifr_ifindex;
do {
result = close(fd);
} while (result == -1 && errno == EINTR);
if (result == -1) {
const int err = errno;
fprintf(stderr, "%s: Error closing socket: %s.\n", name, strerror(err));
return errno = err;
}
return 0;
}
int main(int argc, char *argv[])
{
int arg, speed, index, duplex;
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s INTERFACE ...\n", argv[0]);
fprintf(stderr, "\n");
return 0;
}
for (arg = 1; arg < argc; arg++) {
if (ethernet_interface(argv[arg], &index, &speed, &duplex))
return 1;
if (index == -1)
printf("%s: (no interface index)", argv[arg]);
else
printf("%s: interface %d", argv[arg], index);
if (speed == -1)
printf(", unknown bandwidth");
else
printf(", %d Mbps bandwidth", speed);
if (duplex == 0)
printf(", half duplex.\n");
else if (duplex == 1)
printf(", full duplex.\n");
else
printf(", unknown mode.\n");
}
return 0;
}
Questions?
(1) getifaddrs()
(2) if_indextoname(), if_nameindex(), if_nametoindex()
(3) I'm not sure about this one but you might be able to get at it through ioctl() and one of the SIOCGIF* parameters or from /proc.
the following link well explain the getifaddrs function with a working example
getifaddrs()
ethtool eth1
this command will list all the details about eth1 including speed, duplex, port...
you can use popen() to get the output and map it.
POPEN(3) Linux Programmer's Manual
POPEN(3)
NAME
popen, pclose - pipe stream to or from a process
SYNOPSIS
#include
FILE *popen(const char *command, const char *type);