Идентифицировать программу, которая подключается к сокету домена Unix

#linux #unix-socket

#linux #unix-сокет

Вопрос:

У меня есть программа, которая прослушивает доменный сокет Unix.

Когда клиент подключается к сокету, я хотел бы выяснить, какая программа подключилась, а затем решить, разрешаю ли я подключение или нет (на основе настроек пользователя / группы).

Возможно ли это в Linux, и если да, то каким образом?

Ответ №1:

Да, это возможно в Linux, но это будет не очень переносимо. Это достигается с использованием так называемых «вспомогательных данных» с помощью sendmsg / recvmsg .

  • Используйте SO_PASSCRED с setsockopt
  • Использование SCM_CREDENTIALS и struct ucred структура

Эта структура определена в Linux:

 struct ucred {
    pid_t pid;    /* process ID of the sending process */
    uid_t uid;    /* user ID of the sending process */
    gid_t gid;    /* group ID of the sending process */
};
  

Обратите внимание, что вы должны заполнить их в своем msghdr.control , и ядро проверит, верны ли они.

Основным препятствием для переносимости является то, что эта структура отличается в других Unix-версиях — например, во FreeBSD это:

 struct cmsgcred {
    pid_t   cmcred_pid;          /* PID of sending process */
    uid_t   cmcred_uid;          /* real UID of sending process */
    uid_t   cmcred_euid;         /* effective UID of sending process */
    gid_t   cmcred_gid;          /* real GID of sending process */
    short   cmcred_ngroups;      /* number or groups */
    gid_t   cmcred_groups[CMGROUP_MAX];     /* groups */
};
  

Комментарии:

1. Большое вам спасибо. Именно то, что я искал. Переносимость не является проблемой. Код в любом случае будет выполняться только на Android как собственный код.

2. Привет, я новичок в сокете. Мне интересно, как я могу узнать PID процесса отправки. Спасибо.

Ответ №2:

Я довольно долго искал это, поэтому я покажу вам этот пример о том, как использовать SO_PEERCRED на сокете sock , чтобы получить pid / uid / gid узла сокета:

 int len;
struct ucred ucred;

len = sizeof(struct ucred);

if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, amp;ucred, amp;len) == -1) {
    //getsockopt failed
}

printf("Credentials from SO_PEERCRED: pid=%ld, euid=%ld, egid=%ldn",
    (long) ucred.pid, (long) ucred.uid, (long) ucred.gid);
  

Комментарии:

1. Я также довольно много искал, и мне очень повезло, что я нашел этот ответ! Большинство других источников настаивают на том, что вам нужно использовать sendmsg и recvmsg , когда это просто неверно. Я добавлю, что sock параметром в приведенном примере будет файловый дескриптор клиентского процесса, который вы хотите идентифицировать, и я обнаружил, что мне нужно обработать хотя бы один read() из данных клиента, иначе я получу неопределенные значения в ucred структуре.

2. начиная с версии 2.8.0 (2009), требуется _GNU_SOURCE определение glibc. Специальный источник: github.com/apple/cups/issues/2860

Ответ №3:

Возможно, getpeername или getsockname могли бы помочь. и я думаю, что разрешение вашего сокета unix полезно (не уверен в этом). И вы могли бы прочитать ссылку внутри, /proc/self/fd/12 если ваш accept установленный сокет равен 12.

Редактировать

намного лучше использовать вспомогательные данные для учетных данных и sendmsg , как предлагает cnicutar ниже.