Search code examples
cuidfile-ownership

getpwuid and getgrgid causes segfault when user does not exist for given UID


I am running a C program in linux, which prints filename plus its user and group ownership. I am using getpwuid and getgrgid.

When file is owned by non-existent user (ie, there is no entry in /etc/passwd for given UID on my machine), my program segfaults with "terminated by signal 11".

How can I make my program behave same as ls, so that it prints numerical UID when user does not exist, instead of segfaulting?

Relevant code snippet is below:

lstat(filename,&fileStat)

struct group *grp;
struct passwd *pwd;

pwd = getpwuid(fileStat.st_uid);
printf(" %s", pwd->pw_name);

grp = getgrgid(fileStat.st_gid);
printf(" %s", grp->gr_name);

Solution

  • getpwuid and getgrgid return a NULL pointer if the user is not found in /etc/passwd database or there was an error. You have to check that is not NULL before accessing it value to avoid segfaults.

    You have to also check the return value of lstat to be sure that it was successful before using fileStat otherwise it cause another segfault. lstat returns -1 on fail and sets errno otherwise 0. lstat(3)

    int ret =  lstat(filename,&fileStat)
    
    if(ret == -1){
      fprintf(stderr, "lstat: (%s): %s\n", filename, strerror(errno));
      return 1;
    }
    
    struct group *grp;
    struct passwd *pwd;
    
    pwd = getpwuid(fileStat.st_uid);
    
    if(pwd != NULL){
       printf(" %s", pwd->pw_name);
    }else{
      printf(" %ld", (long)fileStat.st_uid);
    }
    
    grp = getgrgid(fileStat.st_gid);
    if(grp != NULL){
     printf(" %s", grp->gr_name);}
    else{
      printf(" %ld", (long)fileStat.st_gid);
    }
    

    getpwuid(3) Sometimes it might return a NULL pointer on an error and will set errno. Which you have to set errno to zero before you check for the specific error