Thread: Another method to kick a user from a linux system?

  1. #1
    Registered User
    Join Date
    Apr 2019
    Posts
    62

    Another method to kick a user from a linux system?

    Hi,

    In a program I have, I need the ability to kick certain users from the server (running linux).

    Currently, I am using a system call to pkill,
    Code:
    system("sudo pkill -KILL -u baduser > /dev/null 2>&1");
    , but would like to get away from making system calls as they seem like lazy programming.

    Is there an existing function, that can work in a similar way to pkill? I can't seem to find any with my searches. I'm looking into using kill(), but I need the programs pid. I think I need to kill the first pid listed to the user as that should be their shell process.

    Any ideas?

    Ty.

  2. #2
    Registered User
    Join Date
    Apr 2019
    Posts
    62

    Possible solution?

    It looks like I can run through the pid entries in the /proc folder. I need to kill the first process with the name `bash` associated with the user, which means reading the first line of `/proc/PID/status`.

    Not really sure if this is going to be quicker than opening a new shell with a system command, though.

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,312
    > as they seem like lazy programming.
    Where do you draw the line?

    Do assembler programmers think C programmers are lazy, because they take the easier road?

    > I need to kill the first process with the name `bash` associated with the user
    You do know that PIDs cycle, so the first numeric pid you find isn't necessarily the parent of all pid.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Registered User
    Join Date
    Apr 2019
    Posts
    62
    Quote Originally Posted by Salem View Post
    > as they seem like lazy programming.
    Where do you draw the line?

    Do assembler programmers think C programmers are lazy, because they take the easier road?
    When I first started learning the C language, I realized that I could write programs really quickly by just using `system()` calls or the occasional `popen()`.

    For instance, I need to read in one file and update another, can all be done with system calls, instead of learning how to open and read/write to a file. I could basically make a bash script into a C program by just converting all statements to `system` calls. I feel `system()` is very similar to the `goto` statement. Use it only when nothing else is possible.

    Quote Originally Posted by Salem View Post
    > I need to kill the first process with the name `bash` associated with the user
    You do know that PIDs cycle, so the first numeric pid you find isn't necessarily the parent of all pid.
    I do realize it might not be the first pid listed to the user. But going through the PIDS under the /proc folder, that are owned by the users, it should be the oldest file with the lowest PID (as a handful of processes can start during the same minute). I can read the `status` file in that directory.

    But it still isn't working. I guess you are telling me that in this instance a `system` call is what should be used?

  5. #5
    Registered User
    Join Date
    May 2009
    Posts
    3,925
    No a C system function call should not be used!

    Why do you think a C program should be used?

    Tim S.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  6. #6
    Registered User
    Join Date
    Apr 2019
    Posts
    62
    Quote Originally Posted by stahta01 View Post
    Why do you think a C program should be used?
    Because the program is already written in C. The program doesn't just kick users, it does many wonderful thing. But it needs to be able to kick users.

    Quote Originally Posted by stahta01 View Post
    No a C system function call should not be used!
    Do you have the other half of that statement? What should be used?

  7. #7
    Registered User
    Join Date
    May 2009
    Posts
    3,925
    The exec family functions are slightly safer.

    exec(3) - Linux manual page

    Note: I am not an Linux programming; so, I can not confirm you can do what you want using them.

    Tim S.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  8. #8
    Registered User
    Join Date
    May 2009
    Posts
    3,925
    From system(3) - Linux manual page

    Do not use system() from a privileged program (a set-user-ID or set-
    group-ID program, or a program with capabilities) because strange
    values for some environment variables might be used to subvert system
    integrity.
    Tim S.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,312
    You could always run an strace on "pkill -KILL -u baduser", then figure out if you have the time to replicate the necessary functionality in your code.

    Or you could grab the source code for pkill, study it to find out what it does.

    > The program doesn't just kick users, it does many wonderful thing.
    Is this for your own use, or do you intend to publish it in any way.

    Because if your 'licence' is anything more restrictive than GPL, then system/exec give you a nice clean line of separation.
    Grabbing bits of source code from pkill would be a no-no.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  10. #10
    Registered User
    Join Date
    Apr 2019
    Posts
    62
    Quote Originally Posted by Salem View Post
    Is this for your own use, or do you intend to publish it in any way.

    Because if your 'licence' is anything more restrictive than GPL, then system/exec give you a nice clean line of separation.
    Grabbing bits of source code from pkill would be a no-no.
    I don't sell software, I program for me and my friends.

    Anyway, I have found a solution,.. sort of. This works, as far as finding the proper PID to kill. And the program doesn't fail. And I get the word `Killed` displayed (even though there's no code for it), but it doesn't kill the process. And it doesn't finish the program code. I feel I wasted too much time on this and just need to go back to what I had. Here's the code though:
    Code:
    // Declare includes.
    #include <dirent.h>
    #include <errno.h>
    #include <libgen.h>
    #include <pwd.h>
    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <time.h>
    
    // Declare defines.
    #define FILENAME_SIZE       100
    #define PROGRAM_NAME_SIZE    50
    #define PROCESS_NAME_SIZE    50
    #define DIRECTORY             "/proc/"
    #define MARKER                "@pts/"
    
    // Declare global variables.
    char program_name[PROGRAM_NAME_SIZE + 1] = {0};
    
    // Declare function prototypes.
    uid_t get_uid (char *user);
    void kick_user (char *user);
    void kill_process (char *filename);
    void process_proc (uid_t user_id);
    
    int main (int argc, char *argv[])
    {
    // Get program name for error reporting.
        strcpy(program_name, basename(argv[0]));
    
    // Check number of arguments.
        if(argc != 2)
        {
            fprintf(stderr, "Usage: %s USERNAME\n", program_name);
            exit(EXIT_FAILURE);
        }
    
    // Run process.
        kick_user(argv[1]);
    
    // Exit cleanly.
        exit(EXIT_SUCCESS);
    }
    
    void kick_user (char *user)
    {
    // Declare variables.
        uid_t user_id = {0};
    
    // Get UID from username.
        user_id = get_uid(user);
    
    // Process folders in the '/proc' directory
        process_proc(user_id);
    }
    
    uid_t get_uid (char *user)
    {
    // Declare variables.
        struct passwd *pwd = NULL;
    
    // Set errno in case of error.
        errno = 0;
    
    // Get record for user.
        if((pwd = getpwnam(user)) == NULL)
            if(errno != 0)
            {
                fprintf(stderr, "%s: kill_user error: getpwnam failed (%s) (%s)\n", program_name, strerror(errno), user);
                exit(EXIT_FAILURE);
            }
    
    // Return UID.
        return(pwd->pw_uid);
    }
    
    void process_proc (uid_t user_id)
    {
    // Declare variables.
        DIR *dp = NULL;
        struct stat buf = {0};
        struct dirent *entry = NULL;
        char filename[FILENAME_SIZE + 1] = {0};
    
    // Open directory for reading.
        if((dp = opendir(DIRECTORY)) == NULL)
        {
            fprintf(stderr, "%s: kill_user error: opendir failed (%s) (%s)\n", program_name, strerror(errno), DIRECTORY);
            exit(EXIT_FAILURE);
        }
    
    // Loop through all entries.
        while((entry = readdir(dp)) != NULL)
        {
            if(entry->d_type == DT_DIR)
            {
    // Build filename.
                sprintf(filename, "%s%s", DIRECTORY, entry->d_name);
    
    // Get file info.
                if(stat(filename, &buf) == -1)
                    continue;
    
    // If UIDs match, check the process.
                if(buf.st_uid == user_id)
                    kill_process(filename);
            }
        }
    }
    
    void kill_process (char *filename)
    {
    // Declare variables.
        FILE *fp = NULL;
        pid_t pid = {0};
        char new_filename[FILENAME_SIZE + 1] = {0};
        char process_name[PROCESS_NAME_SIZE + 1] = {0};
    
    // Build new filename.
        sprintf(new_filename, "%s/cmdline", filename);
    
    // Open cmdline for process name.
        if((fp = fopen(new_filename, "r")) == NULL)
        {
            fprintf(stderr, "%s: kill_process error: fopen failed (%s) (%s)\n", program_name, strerror(errno), filename);
            exit(EXIT_FAILURE);
        }
    
    // Get process name.
        if(fgets(process_name, PROCESS_NAME_SIZE, fp) == NULL)
        {
            fprintf(stderr, "%s: kill_process error: fgets failed\n", program_name);
            exit(EXIT_FAILURE);
        }
    
    // Close process name file.
        fclose(fp);
    
    // Check process name.
        if(strstr(process_name, MARKER) == NULL)
    // Return when they don't match.
            return;
    
    // Get PID fron filename.
        pid = (pid_t) atoi(filename);
    
    printf("PID: %s\n", basename(filename));
    
    // Kick user from system.
    //    if(kill(pid, SIGTERM) == -1)
        if(kill(pid, SIGKILL) == -1)
        {
            fprintf(stderr, "%s: kill_process error: kill failed (%s) (%s)\n", program_name, strerror(errno), basename(filename));
            exit(EXIT_FAILURE);
        }
    
    puts("Doesn't get the here.\n");
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Best method for console timing system?
    By thegr8n8 in forum C++ Programming
    Replies: 2
    Last Post: 08-09-2010, 02:22 AM
  2. How to get the user ID and group ID from UNIX system
    By dragonfly1801 in forum Linux Programming
    Replies: 6
    Last Post: 11-16-2006, 04:45 AM
  3. system call with user input
    By enlinux in forum C Programming
    Replies: 7
    Last Post: 03-02-2003, 10:23 PM
  4. Replies: 3
    Last Post: 12-15-2001, 01:46 PM

Tags for this Thread