Thread: Execute program as another user

  1. #1
    Registered User
    Join Date
    Jun 2017
    Posts
    18

    Execute program as another user

    Hello,
    I have written a C program in GTK+ with GUI support
    1. The administrator (root) can add specific programs to my program. At the time of installation of my program, it creates a user account without home directory.
    2. This user will become the owner of any programs added to the software.
    3. This means no one else can launch those programs externally other than via the software
    4. The software I wrote and installed can be executed by everyone else.
    5. There is a launchpad where all added programs are displayed with icons

    My question is when any user launches my software and clicks on these icons (added programs), I want these to be executed as the user created specific to execute these programs without asking for a password.

    I have used a similar software in a national facility, where I execute a program and it writes, creates files and folders, executes other operations that I cannot on a shell.

    Thanks
    Nethaji

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Perhaps you should look into setuid.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Jun 2017
    Posts
    18
    Hi Laserlight,
    Thank you for the hint. I will try and update my reply.

  4. #4
    Registered User
    Join Date
    Jun 2017
    Posts
    18
    Hi,
    I tried without much success using setuid.
    1. GTK+ applications does require a helper program to run setuid processes
    2. I created a helper program, but setuid doesn't work as I still have not understood how to use it correctly.

    In simple, what I did was
    1. Wrote a simple helper program that will launch the actual GTK+ application
    2. I set the ownership and group of the helper program and the application to be the same
    3. The helper program has a permission of 755
    4. I can execute the application via the helper program when its mode is 755 and not 750
    5. The setuid bit doesn't seem to apply even with seteuid
    None of my applications need to be root at any given time, so security wise there are no issues.

    I have created a user and group which takes the ownership and group control for the GTK+ application. Only this user can write to the directory or launch any other applications added to it.

    When I launch the application via the helper program using execv, I get the real and effective UID to be a 7 digit number and not the ones set for the owner and group for that user.

    Any help would be much appreciated.

    Code:
    void main()
    {
     /*Get the real and effective UIDs:*/
     realUID = getuid();
     effectiveUID = geteuid();
    
     printf("%d %d\n", realUID, effectiveUID);
    
     /*Call a function to execute GTK+ software from here:*/
     pid_t PID = fork();
     switch(PID)
     {
      case -1:
      {
       perror("Fork failed\n");
       break;
      }
      case 0:
      {
       cPID = getpid(); cPPID = getppid();
       printf("Child process\n");
       printf("PPID= %d PPPID= %d\n", cPID, cPPID);
       printf("Before: %d %d\n", getuid, geteuid);
       seteuid(effectiveUID);
       execv("/app/launcher", NULL);
       seteuid(realUID);
       printf("After: %d %d\n", getuid, geteuid);
       break;
      }
      default:
      {
       pPID = getpid(); pPPID = getppid();
       printf("Parent process\n");
       printf("PPID= %d PPPID= %d\n", pPID, pPPID);
       break;
      }
     }
     while((PID = waitpid(-1, &status, 0)) != -1)
     {/*Wait till all child processes finishes and then exit:*/
     }
     return;
    }

  5. #5
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    948
    That doesn't even compile for me.

    Also, you should turn up the warnings on your compiler:

    Code:
    176823.c:1:6: warning: return type of ‘main’ is not ‘int’ [-Wmain] void main()
          ^~~~
    Code:
    176823.c:23:21: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int (*)()’ [-Wformat=]
        printf("Before: %d %d\n", getuid, geteuid);
                         ^
    176823.c:23:24: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘int (*)()’ [-Wformat=]
        printf("Before: %d %d\n", getuid, geteuid);
                            ^
    Code:
    176823.c:27:20: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int (*)()’ [-Wformat=]
        printf("After: %d %d\n", getuid, geteuid);
                        ^
    176823.c:27:23: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘int (*)()’ [-Wformat=]
        printf("After: %d %d\n", getuid, geteuid);
                           ^
    (I left out the errors about unknown types and undeclared symbols because they presumably are defined/declared in the full code you didn't post.)

  6. #6
    Registered User
    Join Date
    Jun 2017
    Posts
    18
    Hi christop,
    Apologies. I have a few global variables and did not put the header files in the source. The following lines of codes go above the code I pasted in my earlier message.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <grp.h>
    #include <unistd.h>
    #include <pwd.h>
    #include <time.h>
    #include <sys/wait.h>
    
    /*Global variables:*/
    /*UID global variables:*/
    static uid_t effectiveUID, realUID;
    /*Process and parent process ids:*/
    int pPID = -1, pPPID = -1, cPID = -1, cPPID = -1;
    int status;
    /*Global variables ends*/

  7. #7
    Registered User
    Join Date
    Dec 2017
    Posts
    1,628
    Are you still ignoring the warnings? They are rather important! Fix them! The following line (and others) give a warning, and it's obviously not what you mean to do:
    Code:
    printf("Before: %d %d\n", getuid, geteuid);
    This would seem to do nothing at all: seteuid(effectiveUID). You are setting the euid to what it already is.

    If you are using execv then you must pass a non-null argument as the second paremeter since an array of char pointers is expected where the last pointer is NULL, so something like:
    Code:
        char *args[2] = {"launcher", NULL};
        execv("/app/launcher", args);
    Or you can use execl:
    Code:
        execl("/app/launcher", "launcher", (char*)NULL);
    It might not be possible to do what you want in this way, although I'm not sure exactly what you want. But maybe something like this might work: linux - Allowing another user to execute program? - Super User

    Or perhaps this, which might have been what laserlight was referring to:
    UNIX / Linux: Explains setuid File Permission - nixCraft
    Last edited by john.c; 12-12-2018 at 02:24 PM.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  8. #8
    Registered User
    Join Date
    Jun 2017
    Posts
    18
    Hi John,
    Thanks for the info and the link. I have already looked into what laserlight said and couldn't make it work.

    Nethaji

  9. #9
    Registered User
    Join Date
    Jun 2017
    Posts
    18
    Hi all,

    Thanks to laserlight.

    The code I pasted in my earlier messages work. I have given complete test code below.

    I have two users - user1 and user2 and the condition for the program to work

    When user1 launches an executable with mode 4755 set and the owner and group are user2 for that executable

    Now there is another executable which has mode 750, but the owner and group are user2 only.

    With the given code below user1 launches the compiled output of the code given below, which launches the software /app/launcher without any issues.

    I have given the debugging printf statements in the code below.

    So after compiling this code, one have to change the mode (4755), ownership and group to the owner of the launcher program. A standard user cannot set this unless sudo is invoked.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <grp.h>
    #include <unistd.h>
    #include <pwd.h>
    #include <time.h>
    #include <sys/wait.h>
    
    /*Global variables:*/
    int status;
    
    struct passwd *getuser2UID; /*A structure defined in pwd.h that will return a list of value for the given user. See 'man getpwnam' for more details:*/
    /*Global variables ends*/
    
    /*Restore the effective UIDs to its original value:*/
    void dosetuid(pid_t realUID, pid_t effectiveUID)
    {
     int status;
    
     #ifdef _POSIX_SAVED_IDS
      status = seteuid(effectiveUID);
     #else
      status = setreuid(realUID, effectiveUID);
     #endif
    
     if(status < 0)
      {
       fprintf (stderr, "Couldn't set uid.\n");
       exit(status);
      }
    }
    
    /*Set the effective UID to the real UID:*/
    void undosetuid(pid_t realUID, pid_t effectiveUID)
    {
     int status;
    
     #ifdef _POSIX_SAVED_IDS
      status = seteuid(realUID);
     #else
      status = setreuid(effectiveUID, realUID);
     #endif
    
     if(status < 0)
      {
       fprintf(stderr, "Couldn't set uid.\n");
       exit(status);
      }
    }
    
    void main()
    {
     /*UID global variables:*/
     static uid_t effectiveUID, realUID;
     /*Process and parent process ids:*/
     int pPID = -1, pPPID = -1, cPID = -1, cPPID = -1;
    
     /*Get the real and effective UIDs:*/
     realUID = getuid();
     effectiveUID = geteuid();
    
     printf("%d %d\n", realUID, effectiveUID);
     if((user2UID = getpwnam("user2")) != NULL)
      {/*Do nothing:*/
       printf("user2UID: %d\n", user2UID->pw_uid);
      }
    
     /*Call a function to execute GTK+ software from here:*/
     pid_t PID = fork();
     switch(PID)
     {
      case -1:
      {
       perror("Fork failed\n");
       break;
      }
      case 0:
      {
       cPID = getpid(); cPPID = getppid();
       printf("Child process\n");
       printf("PPID= %d PPPID= %d\n", cPID, cPPID);
       dosetuid(realUID, user2UID->pw_uid);
       printf("Before: %d %d\n", getuid(), geteuid());
       execv("/app/launcher", NULL);
       printf("After: %d %d\n", getuid(), geteuid());
       undosetuid(realUID, user2UID->pw_uid);
       break;
      }
      default:
      {
       pPID = getpid(); pPPID = getppid();
       printf("Parent process\n");
       printf("PPID= %d PPPID= %d\n", pPID, pPPID);
       break;
      }
     }
    
     while((PID = waitpid(-1, &status, 0)) != -1)
     {/*Wait till all child processes finishes and then exit:*/
     }
     return;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 4
    Last Post: 10-04-2017, 06:52 AM
  2. Execute shell command from other user
    By LuckyStr in forum C++ Programming
    Replies: 12
    Last Post: 08-24-2009, 03:48 PM
  3. Replies: 0
    Last Post: 04-08-2009, 04:23 PM
  4. Execute prog as other user
    By groorj in forum C Programming
    Replies: 2
    Last Post: 05-04-2005, 12:28 PM
  5. execute until user presses a key?
    By Unregistered in forum C Programming
    Replies: 4
    Last Post: 07-31-2002, 11:31 PM

Tags for this Thread