Zagorax
Zagorax

Reputation: 11890

Passing command line arguments through a C setuid wrapper to another script

I have the following c setuid wrapper:

#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>

main( int argc, char ** argv ) {
    struct passwd *pwd;
    char user[] = "cvmfs-test";

    pwd = getpwnam(user);

    setuid(pwd->pw_uid);
    system(argv[1]);
}

I can call my perl script with ./cwrapper perlscript.pl.

I would like to do ./cwrapper perlscript.pl --option1 --option2 --option3 and elaborate all arguments inside the perl script with GetOptions. How should I change my wrapper?

Upvotes: 1

Views: 1490

Answers (4)

mpu
mpu

Reputation: 433

There is also a nice solution which does not need any allocation, is able to deal with arbitrary long commands and does not imply running useless processes because it does not use system. Moreover with the following solution you get the exit code of the spawned process for free.

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <pwd.h>

#define SETUIDUSER "foobar"

int main(int argc, char **argv) {
  struct passwd *pwd;
  char user[] = SETUIDUSER;

  pwd = getpwnam(user);
  // success test needed here 
  setuid(pwd->pw_uid);
  // success test needed here 

  if (argc < 2)
    return 1;

  execvp(argv[1], &argv[1]);
  return 42;
}

Upvotes: 3

Stephane Rouberol
Stephane Rouberol

Reputation: 4384

Here is a version dealing with a variable number of arguments. Please note that your syscalls should be tested to ensure everything is going OK.

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <pwd.h>

#define CMDMAXLGTH 4096
#define SETUIDUSER "testuser"

int main( int argc, char ** argv ) {
  struct passwd *pwd;
  char user[] = SETUIDUSER;
  char buf[CMDMAXLGTH];
  char *p = buf;
  int i = 1;

  pwd = getpwnam(user);
  // success test needed here 
  setuid(pwd->pw_uid);
  // success test needed here 

  memset (buf, 0, sizeof(buf));
  while (argv[i]) {
    p += sprintf(p, " %s", argv[i++]);
  }
  system(buf);
  return 0;
}

Upvotes: 2

Federico
Federico

Reputation: 3892

Ignore the argv[0] because is the name of the c program and use all the other. You can calculate (strlen) the required memory to assemble a new string, malloc() the memory for the new string and then build your new string by concatenating all the argv (strcat). Or for a fixed length approach, follow @dan1111 answer.

Upvotes: 0

dan1111
dan1111

Reputation: 6566

You should use sprintf to build a character string with your options, then pass this string to system:

 char command [100];
 sprintf (command, "./cwrapper %s --%s --%s --%s", program_name,option1,option2,
     option3);
 system(command);

Update: this approach assumes a fixed number of arguments, and looking back at your question, I see that may not be the case.

Upvotes: 0

Related Questions