I have a problem with the compiling of my program, when I test something like "./philo -p 3 -e 4" I get the error
philo: tpp.c:62: __pthread_tpp_change_priority: Assertion `new_prio == -1 || (new_prio >= __sched_fifo_min_prio && new_prio <= __sched_fifo_max_prio)' failed.
Aborted
But I don't understand where it does come from, as it's working sometimes, for exemple if I test "./philo -p 2 -e 4" it doesn't crash.
The two .h
#ifndef _PHILO_H_
# define _PHILO_H_
#include <pthread.h>
typedef struct s_philosop
{
pthread_t philosophers;
pthread_mutex_t *chopsticks1;
pthread_mutex_t *chopsticks2;
int nbr_occ;
} t_philosop;
int parse_arg(char **argv, int *philo, int *occ);
int create_threads_mutex(int nbr_philo, int occurences);
void *start_routine(void *arg);
void philosoph_eating_chopsticks(t_philosop *philosop);
#endif /* !_PHILO_H_ */
#ifndef __LIBRICEFEREE_EXTERN__
# define __LIBRICEFEREE_EXTERN__
#include <pthread.h>
int RCFStartup(int ac, char **av);
void RCFCleanup();
int lphilo_eat();
int lphilo_sleep();
int lphilo_think();
int lphilo_take_chopstick(const pthread_mutex_t *mutex_id);
int lphilo_release_chopstick(const pthread_mutex_t *mutex_id);
#endif /* __LIBRICEFEREE_EXTERN__ */
And this is my .c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include "philo.h"
#include "extern.h"
void philosoph_comportement(t_philosop *philosop)
{
int i = 0;
if ((pthread_mutex_lock(philosop->chopsticks1)) == 0)
{
printf("%s\n", "Taking left stick");
lphilo_take_chopstick(philosop->chopsticks1);
i++;
}
if ((pthread_mutex_lock(philosop->chopsticks2)) == 0)
{
printf("%s\n", "Taking right stick");
lphilo_take_chopstick(philosop->chopsticks2);
i++;
}
if (i == 2)
{
printf("%s\n", "Eat");
lphilo_eat();
sleep(1);
printf("%s\n", "Sleep");
pthread_mutex_unlock(philosop->chopsticks1);
pthread_mutex_unlock(philosop->chopsticks2);
lphilo_release_chopstick(philosop->chopsticks1);
lphilo_release_chopstick(philosop->chopsticks2);
lphilo_sleep();
}
}
void *start_routine(void *arg)
{
t_philosop *philosop;
int i;
i = 0;
philosop = (t_philosop *)arg;
while (i != philosop->nbr_occ)
{
philosoph_comportement(philosop);
i++;
}
return (0);
}
int create_threads_mutex(int nbr_philo, int occurences)
{
int i;
t_philosop *philosop;
pthread_mutex_t *chopsticks;
i = -1;
if ((chopsticks = malloc(sizeof(pthread_mutex_t) * nbr_philo)) == NULL)
return (2);
if ((philosop = malloc(sizeof(t_philosop) * nbr_philo)) == NULL)
return (2);
while (++i != nbr_philo)
{
philosop[i].nbr_occ = occurences;
philosop[i].chopsticks1 = &chopsticks[i];
if (i - 1 < 0)
philosop[i].chopsticks2 = &chopsticks[nbr_philo];
else
philosop[i].chopsticks2 = &chopsticks[i - 1];
}
i = -1;
while (++i != nbr_philo)
pthread_create(&philosop[i].philosophers, NULL, start_routine, &philosop[i]);
i = -1;
while (++i != nbr_philo)
{
printf("Philo number : %d\n", i);
pthread_join(philosop[i].philosophers, NULL);
}
return (0);
}
int parse_arg(char **argv, int *philo, int *occ)
{
if (strcmp(argv[1], "-p") == 0 && strcmp(argv[3], "-e") == 0 &&
argv[2] != NULL && argv[4] != NULL)
{
*philo = atoi(argv[2]);
*occ = atoi(argv[4]);
}
else if (strcmp(argv[1], "-e") == 0 && strcmp(argv[3], "-p") == 0 &&
argv[2] != NULL && argv[4] != NULL)
{
*philo = atoi(argv[4]);
*occ = atoi(argv[2]);
}
else
return (2);
return (0);
}
int main(int argc, char **argv)
{
int philo;
int occurences;
philo = 0;
occurences = 0;
if (argc != 5)
return (2);
if ((parse_arg(argv, &philo, &occurences)) == 2)
return (2);
RCFStartup(argc, argv);
if ((create_threads_mutex(philo, occurences)) == 2)
return (2);
RCFCleanup();
return (0);
}
You don't initialize any of your mutexes with pthread_mutex_init.
And assuming lphilo_release_chopstick does nothing but unlock a mutex, this code is wrong as it will try to unlock each mutex twice:
pthread_mutex_unlock(philosop->chopsticks1);
pthread_mutex_unlock(philosop->chopsticks2);
lphilo_release_chopstick(philosop->chopsticks1);
lphilo_release_chopstick(philosop->chopsticks2);
Related
I was writing a simple shared memory test program like below.
And I used a line like below.
e_intf[i % 8].flag = i;
I thought it should be like below.
e_intf[i % 8]->flag = i;
But if I use "->" operator, I have errors.
This is a full source code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#define SHM_KEY 0x9998
typedef struct _ethernet_interface {
char name[8];
int32_t flag;
} Ethernet_Interface_t;
int32_t memory_update(void)
{
int32_t i = 0;
int32_t shmid;
Ethernet_Interface_t *e_intf;
int32_t ret;
shmid = shmget(SHM_KEY, 8 * sizeof(Ethernet_Interface_t), 0644|IPC_CREAT);
if (shmid == -1)
{
perror("Shared Memory");
return -1;
}
e_intf = shmat(shmid, NULL, 0);
if (e_intf == (void *)-1)
{
perror("Shared Memory Attach");
return -1;
}
while (1)
{
e_intf[i % 8].flag = i;
if (i < 8)
{
sprintf(e_intf[i % 8].name, "%s%d", "eth", (i % 8));
}
printf("memory_update : e_intf[%d].name = %s, e_intf[%d] = %d\n", i % 8, e_intf[i % 8].name, (i % 8), i);
sleep(2);
i++;
}
ret = shmdt(e_intf);
if (ret == -1)
{
perror("shmdt");
return -1;
}
return 0;
}
int32_t memory_read(void)
{
int32_t i;
int32_t shmid;
Ethernet_Interface_t *e_intf;
int32_t ret;
shmid = shmget(SHM_KEY, 8 * sizeof(Ethernet_Interface_t), 0644|IPC_CREAT);
if (shmid == -1)
{
perror("Shared Memory");
return -1;
}
e_intf = shmat(shmid, NULL, 0);
if (e_intf == (void *)-1)
{
perror("Shared Memory Attach");
return -1;
}
i = 0;
while (1)
{
printf("[%d]memory_read : index = %d\n", i, (i % 8));
printf("[%d]memory_read : e_intf[%d].name = %s\n", i, (i % 8), e_intf[i % 8].name);
printf("[%d]memory_read : e_intf[%d].flag = %d\n", i, (i % 8), e_intf[i % 8].flag);
if (e_intf[i % 8].flag == 42)
{
printf("[%d]memory_read : Exiting\n", i);
break;
}
sleep(1);
i++;
}
ret = shmdt(e_intf);
if (ret == -1)
{
perror("shmdt");
return -1;
}
ret = shmctl(shmid, IPC_RMID, 0);
if (ret == -1)
{
perror("shmctl");
return -1;
}
return 0;
}
int32_t main(int32_t argc, char *argv[])
{
pid_t pid;
pid = fork();
if (pid == 0)
{
/* child process */
memory_update();
}
else
{
/* parent process */
memory_read();
}
exit(0);
}
But when I made another simple test program for pointer operation.
I can use "->" operator as I expected.
Here is the source code for the test program for pointer operation.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
typedef struct _ethernet_interface {
char name[8];
int32_t flag;
} Ethernet_Interface_t;
int32_t main(int32_t argc, char *argv[])
{
Ethernet_Interface_t intf;
Ethernet_Interface_t *p_intf;
p_intf = malloc(sizeof(Ethernet_Interface_t));
intf.flag = 1111;
p_intf->flag = 2222;
printf("intf.flag = %d\n", intf.flag);
printf("p_intf->flag = %d\n", p_intf->flag);
return 0;
}
Can someone point out why I am confused with these 2 cases?
The answer is very simple - index dereferences the pointer:
pointer[n] === *(pointer + n)
so in your case:
e_intf[i % 8] === *(e_intf + i % 8)
and
e_intf[i % 8].flag == (*(e_intf + i % 8)).flag
if you want to use the -> operator you need pointer, not referenced object.
(&e_intf[i % 8]) -> flag
or
(e_intf + i % 8) -> flag
This question already has answers here:
C 2D array Memory allocation
(2 answers)
Closed 1 year ago.
I am writing a basic shell program in C for an assignment. I am currently having troubles allocating the memory that will be used to store the command line arguments that will be passed into the program to be parsed.
I am getting a segmentation fault if the input size is greater than or equal to 4 (i.e. "this is a test" will produce a segmentation fault upon program terminations whereas "this is a" will not).
I imagine my issue lies within how I was allocating the memory but the program is capturing each token that I enter and printing them to the screen.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main()
{
char cap[] = "";
char* cmd;
const int MAX_ARGS = 16;
const int MAX_ARG_SIZE = 256;
char** arglst = (char**)malloc(MAX_ARGS * sizeof(char*));
for(int i = 0; i < MAX_ARGS; i++)
{
arglst[i] = (char*)malloc(MAX_ARG_SIZE * sizeof(char));
}
pid_t cpid;
//implement ls, cd, mkdir, chdir, rm, rmdir
while(1)
{
printf("Enter a command: ");
scanf("%[^\n]s", cap);
int index = 0;
cmd = strtok(cap, " ");
while( cmd != NULL )
{
strcpy(arglst[index], cmd);
cmd = strtok(NULL, " ");
index++;
}
for(int i = 0; i < index; i++)
{
printf("%s\n", arglst[i]);
}
printf("%d\n", index);
/*
if(strcmp(cap, "quit") == 0) exit(EXIT_SUCCESS);
if( (cpid = fork()) == -1) perror("fork()");
else if(cpid == 0)
{
if( execvp(cmd, arglst) == -1 )
{
errorp("cmd error");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
else
{
cpid = wait(NULL);
strcpy(cmd, "/bin/");
}
*/
for(int i = 0; i < index; i++)
{
free(arglst[i]);
}
free(arglst);
return 0;
}
}
There are a number of bugs.
This won't compile (e.g. errorp instead of perror).
cap is too small to contain a line. Better to use (e.g.) char cap[1000];
Doing a preallocate of each arglst[i] once before the main loop is problematic. One of the cells has to get a NULL value so it works with execvp. However, doing so would cause a memory leak. The solution is to use strdup inside the strtok loop so that cells are only allocated when needed.
Also, because arglst[i] is set only once during initialization, doing a loop with free near the bottom causes UB [accessing the buffer after being freed]. This is fixed with the use of strdup below.
The commented out code references variables (e.g. cmd and cap) that should not be relied upon. At that point, cmd will be NULL, causing a segfault.
The return 0; is placed incorrectly. Only one iteration (and thus only one command) will be executed.
The final free of arglst (e.g. free(arglst)) is done inside the outer loop, so referencing it on the second iteration is UB.
There are a few more issues [annotated below]
Here's a refactored version. It fixes the bugs and is heavily annotated.
I've used the preprocessor to show old/original code vs new/fixed code:
#if 0
// old code
#else
// new code
#endif
Likewise, using #if 1 for purely new code.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#if 1
#include <sys/wait.h>
#endif
int
main(void)
{
// NOTE/BUG: this must be large enough to contain a command line
#if 0
char cap[] = "";
#else
char cap[1000];
#endif
char *cmd;
const int MAX_ARGS = 16;
char **arglst = malloc(MAX_ARGS * sizeof(*arglst));
// NOTE/BUG: because we need to add a NULL terminator, don't preallocate the
// elements -- we'll leak memory
#if 0
const int MAX_ARG_SIZE = 256;
for (int i = 0; i < MAX_ARGS; i++) {
arglst[i] = (char *) malloc(MAX_ARG_SIZE * sizeof(char));
}
#endif
pid_t cpid;
// implement ls, cd, mkdir, chdir, rm, rmdir
while (1) {
printf("Enter a command: ");
// NOTE/BUG: this didn't work too well
#if 0
scanf("%[^\n]s", cap);
#else
fgets(cap,sizeof(cap),stdin);
cap[strcspn(cap,"\n")] = 0;
#endif
int index = 0;
cmd = strtok(cap, " ");
while (cmd != NULL) {
// NOTE/BUG: we should strdup dynamically rather than preallocate -- otherwise,
// we leak memory when we set the necessary NULL pointer below
#if 0
strcpy(arglst[index], cmd);
#else
arglst[index] = strdup(cmd);
#endif
cmd = strtok(NULL, " ");
index++;
}
// NOTE/FIX: we have to add a NULL terminator before passing to execvp
#if 1
arglst[index] = NULL;
#endif
for (int i = 0; i < index; i++) {
printf("%s\n", arglst[i]);
}
printf("%d\n", index);
// NOTE/BUG: we can't [shouldn't] rely on cap here
#if 0
if (strcmp(cap, "quit") == 0)
exit(EXIT_SUCCESS);
#else
if (strcmp(arglst[0], "quit") == 0)
exit(EXIT_SUCCESS);
#endif
if ((cpid = fork()) == -1)
perror("fork()");
else if (cpid == 0) {
// NOTE/BUG: cmd will be NULL here
#if 0
if (execvp(cmd, arglst) == -1) {
errorp("cmd error");
exit(EXIT_FAILURE);
}
#else
if (execvp(arglst[0], arglst) == -1) {
perror("cmd error");
exit(EXIT_FAILURE);
}
#endif
// NOTE/BUG: this will never be executed
#if 0
exit(EXIT_SUCCESS);
#endif
}
else {
cpid = wait(NULL);
// NOTE/BUG -- cmd is NULL and this serves no purpose
#if 0
strcpy(cmd, "/bin/");
#endif
}
// NOTE/BUG: in the _old_ code that did a single preallocate of these cells
// _before_ the loop, freeing them here is wrong -- they would never be
// reallocated because -- the fix using strdup alleviates the issue
for (int i = 0; i < index; i++) {
free(arglst[i]);
}
// NOTE/BUG: freeing this is wrong because we do the allocation only _once_
// above the outer loop
#if 0
free(arglst);
#endif
// NOTE/BUG -- this should be placed at the end to allow multiple commands --
// here it stops after the first command is input
#if 0
return 0;
#endif
}
// NOTE/FIX: correct placement for the above
#if 1
free(arglst);
return 0;
#endif
}
Here's that version cleaned up so that only the fixed code remains:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
int
main(void)
{
char cap[1000];
char *cmd;
const int MAX_ARGS = 16;
char **arglst = malloc(MAX_ARGS * sizeof(*arglst));
pid_t cpid;
// implement ls, cd, mkdir, chdir, rm, rmdir
while (1) {
printf("Enter a command: ");
fgets(cap,sizeof(cap),stdin);
cap[strcspn(cap,"\n")] = 0;
int index = 0;
cmd = strtok(cap, " ");
while (cmd != NULL) {
arglst[index] = strdup(cmd);
cmd = strtok(NULL, " ");
index++;
}
arglst[index] = NULL;
for (int i = 0; i < index; i++) {
printf("%s\n", arglst[i]);
}
printf("%d\n", index);
if (strcmp(arglst[0], "quit") == 0)
exit(EXIT_SUCCESS);
if ((cpid = fork()) == -1)
perror("fork()");
else if (cpid == 0) {
if (execvp(arglst[0], arglst) == -1) {
perror("cmd error");
exit(EXIT_FAILURE);
}
}
else {
cpid = wait(NULL);
}
for (int i = 0; i < index; i++) {
free(arglst[i]);
}
}
free(arglst);
return 0;
}
Note that the above does not check for the number of actual arguments exceeding MAX_ARGS.
While we could add that check, a better way is to use realloc on arglst to dynamically increase it, so an arbitrary limit on the number of arguments isn't needed
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
int
main(void)
{
char cap[1000];
char *cmd;
char **arglst = NULL;
int argmax = 0;
pid_t cpid;
// implement ls, cd, mkdir, chdir, rm, rmdir
while (1) {
printf("Enter a command: ");
fgets(cap,sizeof(cap),stdin);
cap[strcspn(cap,"\n")] = 0;
int index = 0;
cmd = strtok(cap, " ");
while (cmd != NULL) {
if (index >= argmax) {
argmax += 10;
arglst = realloc(arglst,sizeof(*arglst) * (argmax + 1));
}
arglst[index] = strdup(cmd);
cmd = strtok(NULL, " ");
index++;
}
arglst[index] = NULL;
for (int i = 0; i < index; i++) {
printf("%s\n", arglst[i]);
}
printf("%d\n", index);
if (strcmp(arglst[0], "quit") == 0)
exit(EXIT_SUCCESS);
if ((cpid = fork()) == -1)
perror("fork()");
else if (cpid == 0) {
if (execvp(arglst[0], arglst) == -1) {
perror("cmd error");
exit(EXIT_FAILURE);
}
}
else {
cpid = wait(NULL);
}
for (int i = 0; i < index; i++) {
free(arglst[i]);
}
}
free(arglst);
return 0;
}
The original code used malloc and/or strdup on the individual elements of arglst (e.g. arglst[i]).
This makes the code general enough to be used in more complex scenarios. But, as the code is written, the malloc/strdup for the individual elements really isn't necessary.
This is because the cells are fully used [up] at the bottom of the main loop, so we don't need to save them.
We can reuse the cap buffer space on each loop iteration because we do not need any tokens to live on iteration to iteration.
We can simply store the return value from strtok and simplify the code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
int
main(void)
{
char cap[1000];
char *cmd;
char **arglst = NULL;
int argmax = 0;
pid_t cpid;
// implement ls, cd, mkdir, chdir, rm, rmdir
while (1) {
printf("Enter a command: ");
fgets(cap,sizeof(cap),stdin);
cap[strcspn(cap,"\n")] = 0;
int index = 0;
cmd = strtok(cap, " ");
while (cmd != NULL) {
if (index >= argmax) {
argmax += 10;
arglst = realloc(arglst,sizeof(*arglst) * (argmax + 1));
}
arglst[index] = cmd;
cmd = strtok(NULL, " ");
index++;
}
arglst[index] = NULL;
for (int i = 0; i < index; i++) {
printf("%s\n", arglst[i]);
}
printf("%d\n", index);
if (strcmp(arglst[0], "quit") == 0)
exit(EXIT_SUCCESS);
if ((cpid = fork()) == -1)
perror("fork()");
else if (cpid == 0) {
if (execvp(arglst[0], arglst) == -1) {
perror("cmd error");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
else {
cpid = wait(NULL);
}
}
free(arglst);
return 0;
}
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 use sigsetjmp/siglongjmp to change the progame stack. This is the demo:
#include <stdio.h>
#include <stddef.h>
#include <setjmp.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#define POOLSIZE 4096
int active = 0;
int total = 0;
struct thread
{
int tid;
sigjmp_buf env;
char buf[4096];
int state;
ssize_t size;
};
struct thread *thread_pool = 0L;
char* anchor_beg = 0L;
char* anchor_end = 0L;
void(*new_thread)(int) = 0L;
void sig_call(int sig)
{
char anchor;
anchor_end = &anchor;
if(sigsetjmp(thread_pool[active].env, 0) == 0)
{
thread_pool[active].size = anchor_beg - anchor_end;
memcpy(thread_pool[active].buf, anchor_end, thread_pool[active].size);
siglongjmp(thread_pool[0].env, 1);
}
else
{
memcpy(anchor_beg - thread_pool[active].size, thread_pool[active].buf, thread_pool[active].size);
}
}
void thread_new(void(*pfn)(int))
{
alarm(0);
new_thread = pfn;
thread_pool[0].state = 2;
// printf("create new thread:%d\n", total + 1);
raise(SIGUSR1);
}
void test(int thread)
{
int i = 0;
for(;i != 1000000; i++)
{
}
}
void thread_main(int thread)
{
int i = 0;
for(i = 0; i < 4000; i++)
thread_new(test);
}
void call(void(*pfn)(int))
{
active = ++ total;
thread_pool[active].tid = active;
thread_pool[active].state = 1;
ualarm(500, 0);
pfn(active);
thread_pool[active].state = 0;
}
void dispatcher()
{
thread_pool = (struct thread*)malloc(sizeof(struct thread) * POOLSIZE);
char anchor;
anchor_beg = &anchor;
thread_pool[0].tid = 0;
thread_pool[0].state = 1;
if(sigsetjmp(thread_pool[0].env, 0) == 0)
{
signal(SIGUSR1, sig_call);
signal(SIGALRM, sig_call);
call(thread_main);
}
else if(thread_pool[0].state == -1)
{
return;
}
else if(thread_pool[0].state == 2)
{
thread_pool[0].state = 1;
call(new_thread);
}
while(1)
{
int i, alive = 0;
for(i = 1; i <= total; i++)
{
if(thread_pool[i].state == 1)
{
alive ++;
ualarm(500, 0);
active = thread_pool[i].tid;
siglongjmp(thread_pool[i].env, 1);
}
}
if(alive == 0)
return;
}
}
int main()
{
dispatcher();
}
Is there any problem here? And when i want to call some third party interface, and maybe it is a block I/O there, can i do something to change another context to execute? and How?
Unfortunately, what you're trying to do doesn't work, because (per the setjmp manual):
The longjmp() routines may not be called after the routine which called
the setjmp() routines returns.
This is because the setjmp/longjmp family of functions (including the sig variants) do not preserve the entire contents of the process stack.
I am trying to make a simple shell program with the C language which have the options of redirecting stdin and stdout and making a pipe but it's giving me a segmentation fault error. Maybe the problem is in the getline but I'm not sure. Here is the code:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#define R 0
#define W 1
#define LINE_LEN 25
struct Job {
char* command;
char** argv;
int stdin;
int stdout;
} typedef Job;
int tokens_number = 0;
int sign_place = 0;
int contain_left = 0;
int contain_right = 0;
int contain_line = 0;
char** parse_cmdline (char * cmdline ){
char** arg = calloc(15, sizeof(char*));
char temp_cmd[LINE_LEN*10];
strcpy(temp_cmd, cmdline);
char * tmp;
tmp = strtok(temp_cmd, " ");
while(tmp != NULL) {
arg[tokens_number] = (char*) malloc(LINE_LEN * sizeof(char*));
strcpy(arg[tokens_number],tmp);
tmp = strtok(NULL, " ");
tokens_number++;
}
//LAST ELEMENT IS NULL
arg[tokens_number+1] = NULL;
return arg;
}
void check_for_special_signs(char** argv){
int i;
for(i=0; i<tokens_number; i++){
if(strcmp(argv[i], "<") == 0){
contain_left = 1;
sign_place = i;
return;
}else if(strcmp(argv[i], ">") == 0){
contain_right = 1;
sign_place = i;
return;
}else if(strcmp(argv[i], "|") == 0){
contain_line = 1;
sign_place = i;
return;
}
}
}
void fork_child(Job* my_job) {
pid_t pid = fork();
if (pid == 0) {
execv(my_job -> command, my_job -> argv);
perror(my_job -> command);
} else if (pid > 0) {
int status;
wait(&status);
} else
perror("fork");
}
char** create_argv(char** argv){
int i;
int j = 0;
char** argvs = calloc(sign_place,sizeof(char*));
if(sign_place!=0){
for(i=0; i < sign_place ; i++){
argvs[i] = (char*) malloc(sizeof(char*));
strcpy(argvs[i],argv[i]);
}
return argvs;
}else{
return argv;
}
}
void close_job(Job* my_job) {
if (my_job -> stdin != STDIN_FILENO)
close(my_job -> stdin);
if (my_job -> stdout != STDOUT_FILENO)
close(my_job -> stdout);
free(my_job);
}
int main() {
size_t s = 512;
char* buffer = malloc(s * sizeof(char));
char** sep_cmd = malloc(s * sizeof(char));
while (getline(&buffer, &s, stdin) != EOF) {
Job* my_job;
int my_pipe[2];
int in = 0;
int out = 1;
sep_cmd = parse_cmdline(buffer);
my_job->command = sep_cmd[0];
my_job->argv = sep_cmd;
my_job->stdin = in;
my_job->stdout = out;
check_for_special_signs(my_job->argv);
pid_t pid = fork();
if (pid == 0) {
if(contain_left == 1){
in = open(my_job->argv[sign_place + 1], O_RDONLY);
if(in < 0){
perror("open()");
}
my_job->argv = create_argv(my_job->argv);
my_job->stdin = in;
}else if(contain_right == 1){
out = open(my_job->argv[sign_place + 1], O_WRONLY | O_CREAT,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (out < 0)
perror("open()");
my_job->argv = create_argv(my_job->argv);
my_job->stdout = out;
}else if(contain_line == 1){
pipe(my_pipe);
if (my_job -> stdin == my_pipe[R])
close(my_pipe[W]);
else
close(my_pipe[R]);
}
execv(my_job -> command, my_job -> argv);
perror(my_job -> command);
} else if (pid > 0) {
int status;
wait(&status);
} else{
perror("fork");
}
close_job(my_job);
free(buffer);
buffer = (char*) malloc(s * sizeof(char));
}
free(buffer);
return 0;
}
That way I can't see if there are more mistakes in the code. Please if you see more mistakes list them too.
Thank you.
You forgot to allocate memory for my_job in main function