在sudo下运行时如何从C获取登录用户

问题描述

我正在编写一个将在sudo下运行的C应用程序。

我需要获取原始登录用户的UID。

我正在调用getuid,文档说明该状态将返回真实的UID。

我假设这将是登录用户的UID,但它返回的是0,这是根UID。

是否有一个api调用,可让我获取已登录用户的UID。

我知道SUDO_UID,但希望避免使用环境变量(或者我只是感到困难)。

解决方法

这是我的解决方案,不使用依赖于stat()/proc/<pid>中文件的环境变量,因此这使其仅适用于linux。 基本上,它会经过进程树,直到找到(sudo)pid=1为止,如果找到sudo,它将显示调用它的父进程以及该进程的uid。

hello_sudoer.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
struct process_info {
    pid_t pid;  
    // max file name is 255 + 2 for "()" in /proc/<pid>/stat
    char process_name[257]; 
    char status;
    pid_t ppid; // parent process id
    uid_t uid; // uid of this process
};

struct process_info get_process_info(pid_t pid){
    struct process_info pi;
    struct stat* s = malloc(sizeof(struct stat));
    memset(&pi,sizeof(struct process_info));
    if(pid > 0) {
        char proc_path[64];
        FILE* proc_stat;
        memset(&proc_path,sizeof(proc_path));
        sprintf(proc_path,"/proc/%d/stat",pid);
        proc_stat = fopen(proc_path,"r");
        if (proc_stat != NULL) {
            fscanf(proc_stat,"%d %s %c %d",&pi.pid,pi.process_name,&pi.status,&pi.ppid);

            // stat struct doesn't have the parent process id
            // as is only checking on the file properies of /proc/<pid> directory
            // so we can't get the info needed only with stat(2)
            // and stat file doesn't have uid so we can't only use that
            // we need both
            stat(proc_path,s); 
            pi.uid = s -> st_uid;
            free(s);
            fclose(proc_stat);
        } 

    } 
    return pi;
}

void print_process_info(struct process_info pi){
    printf("pid=%d file_name=%s status=%c uid=%d ppid=%d\n",pi.pid,pi.status,pi.uid,pi.ppid);
}

int main()
{
    pid_t pid = getpid();

    while (pid > 0) {
        struct process_info pi = get_process_info(pid);
        print_process_info(pi);

        if( strcmp("(sudo)",pi.process_name) == 0 ) {
            // found sudo 
            struct process_info sudo_parent_info = get_process_info(pi.ppid);
            printf("user that ran sudo is uid=%d,from process: \n",sudo_parent_info.uid);
            print_process_info(sudo_parent_info);
            break;
        }
        pid = pi.ppid;
    }
    return 0;
}

示例输出:

pid=41769 file_name=(hello_sudoer.o) status=R uid=0 ppid=41749
pid=41749 file_name=(sudo) status=S uid=0 ppid=20078
user that ran sudo is uid=1000,from process: 
pid=20078 file_name=(bash) status=S uid=1000 ppid=5985

,

在运行systemd(或更准确地说是systemd-logind)的系统上,您可以使用sd_pid_get_owner_uid获取启动当前会话的用户:

gradient: LinearGradient(

                                                begin: Alignment.topLeft,end: Alignment.bottomRight,colors: [
                                                  Color(0x0ffd6dcf4).withOpacity(0),Colors.white.withOpacity(1),],stops: [
                                                  0.3,1
                                                ])

您需要链接到#include <systemd/sd-login.h> … uid_t user_id; if (sd_pid_get_owner(0,&user_id) != 0) … /* handle error */ printf("UID: %ju\n",(uintmax_t) user_id);

此ID将指示已登录系统的用户。它不适用于没有登录会话的进程(例如,系统服务),但是在这种情况下,可以说该进程没有登录用户。如果用户有权启动新的会话或服务,他们也可以隐藏其原始登录会话。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...