Второй вызов getpwuid перезаписывает старое значение

Вот небольшая C-программа, которая печатает (ну, предположительно, для печати) реальные и эффективные идентификаторы процесса, когда в файле установлен флаг setuid. В этой программе, когда я звоню getpwuid во второй раз (L.No 38), это имеет тенденцию перезаписывать значение переменной realUserName это было получено в L.No 24. Я не могу объяснить это поведение. Это ожидаемое поведение и почему? Я пытаюсь это в коробке Linux (RHEL 2.6.18-371.1.2.el5).

  1 /* Filename: test.c
  2  * Notes:
  3  * 1] ./test owned by user cadmn (userID: 3585)
  4  * 2] ./test run by user pmn (4471)
  5  * 3] ./test has the setuid bit switched-on.
  6  */
  7 #include <stdio.h>
  8 #include <pwd.h>
  9 #include <sys/types.h>
 10 #include <unistd.h>
 11 int main()
 12 {
 13
 14     uid_t realId, effectiveId;
 15     struct passwd *realUser, *effUser;
 16
 17     realId = getuid(); // realId = 4471
 18     effectiveId = geteuid(); //effectiveId = 3585
 19
 20     printf("Real ID is %i and Effective ID is %i\n", (int)realId, (int)effectiveId);
 21     //prints 4472 and 3585, respectively
 22
 23     realUser = getpwuid(realId);
 24     char *realUserName = realUser->pw_name; //realUserName = pmn
 25
 26     printf("Real ID (name) at this point is %s\n", realUserName);
 27     // prints pmn.
 28
 29     /*
 30      *********************************************************
 31      *                                                       *
 32      *    everything works as expected up to this point      *
 33      *                                                       *
 34      *********************************************************
 35      */
 36
 37     // The value obtained from this call is not used anywhere in this program
 38     effUser = getpwuid(effectiveId);
 39     printf("\nCalled getpwuid with the effectiveId\n\n");
 40
 41     printf("Real ID is %i and Effective ID is %i\n", (int)realId, (int)effectiveId);
 42     //prints 4472 and 3585, respectively
 43
 44     printf("Real ID (name) at this point is %s.\n", realUserName);
 45     // Expect to still see 'pmn' printed; though see 'cadmn' as the output!
 46     // Why does this happen?
 47
 48     return 0;
 49 }
 50

Выход:

pmn@rhel /tmp/temp > id pmn
uid=4471(pmn) gid=1000(nusers) groups=1000(nusers)
pmn@rhel /tmp/temp >

pmn@rhel /tmp/temp > id cadmn
uid=3585(cadmn) gid=401(cusers) groups=401(cusers)
pmn@rhel /tmp/temp >

pmn@rhel /tmp/temp > ls -l ./test
-r-sr-xr-x 1 cadmn cusers 9377 Dec 24 19:48 ./test
pmn@rhel /tmp/temp >

pmn@rhel /tmp/temp > ./test
Real ID is 4471 and Effective ID is 3585
Real ID (name) at this point is pmn

Called getpwuid with the effectiveId

Real ID is 4471 and Effective ID is 3585
Real ID (name) at this point is cadmn.
pmn@rhel /tmp/temp >

1 ответ

Решение

Поведение, которое вы наблюдаете, является ожидаемым.

Структура, на которую ссылается возвращаемое значение getpwuid() определяется статически внутренним по отношению к последнему, поэтому ожидается, что он будет заполнен (и с этим перезаписан) для каждого вызова getpwuid(),

Эта линия

char * realUserName = realUser->pw_name; 

просто хранит ссылку на значение, хранящееся в этой статически внутренней структуре. Это значение также перезаписывается, если статически внутренняя структура перезаписывается при следующем вызове getpwuid(),

Чтобы обойти это, есть две возможности:

  • Используйте реентерабельную версию getpwuid() который getpwuid_r(), Чтобы иметь возможность использовать его, добавьте

    #define _POSIX_SOURCE
    

    до самого 1- го #include утверждение в источниках вашей программы.

  • Создайте копию нужных вам членов, pw_name в этом случае. Это может быть достигнуто, например, путем:

    char * realUserName = strdup(realUser->pw_name);
    

    Будь таким realUserName теперь указывает на динамически распределенную память, которая должна быть free() под редакцией самой программы, если не нужно больше. Для этого позвоните

    free(realUserName); 
    
Другие вопросы по тегам