session required pam_mkhomedir.so skel=/etc/ftp/ umask=0022
Como você pode ver, pam_mkhomedir.so
atua no nível sessão . Isso significa que ele age após o usuário ter sido autenticado (pelo auth
facility). Para fazer isso, ele define a seguinte função específica do PAM:
PAM_EXTERN
int pam_sm_open_session(pam_handle_t * pamh, int flags,
int argc, const char **argv);
Como eu disse, essa função é chamada quando o usuário foi autenticado. Portanto, quando ele recupera o manipulador de usuário do PAM ...
/* Determine the user name so we can get the home directory */
retval = pam_get_item(pamh, PAM_USER, (const void **)&user);
... obtém acesso ao nome de um autenticado , usuário existente. Com esta informação, o módulo será capaz de recuperar o que precisa (o caminho para um diretório pessoal) através de um simples getpwnam(3)
chamada da biblioteca:
/* Get the password entry */
pwd = getpwnam(user);
Isso retornará a seguinte estrutura, preenchida com informações sobre o usuário:
struct passwd {
char *pw_name; /* username */
char *pw_passwd; /* user password */
uid_t pw_uid; /* user ID */
gid_t pw_gid; /* group ID */
char *pw_gecos; /* user information */
char *pw_dir; /* home directory */
char *pw_shell; /* shell program */
};
Agora, se você quer saber de onde esta informação está vindo, dê uma olhada em /etc/nsswitch.conf
. O serviço de nomes (NSS) está aqui para fornecer informações sobre nomes em geral (que podem ser usernames, aliases, grupos, hosts, ... veja nsswitch.conf(5)
para mais detalhes). Se o guia que você seguiu estiver completo o suficiente, você deve configurar o PAM e NSS: o primeiro gerencia a autenticação e o gerenciamento de conta / sessão, enquanto o outro está aqui apenas para fornecer informações de nome. Em outras palavras, o primeiro pode realizar operações de leitura / gravação, enquanto o segundo é somente leitura.
Quando pam_mkhomedir.so
tiver recuperado o caminho para o diretório pessoal do usuário, tudo o que ele precisa fazer é verificar se ele existe ou não e criá-lo se não existir:
/* Stat the home directory, if something exists then we
* assume it is correct and return a success. */
if(stat(pwd->pw_dir, &st) == 0) return PAM_SUCCESS;
return create_homedir(..., pwd, ...);
A função create_homedir
é definida pelo próprio módulo, e é um pouco longo demais para eu colá-lo aqui. Basta vê-lo como uma grande chamada mkdir(2)
, que lida com casos específicos e garante que tudo corra bem. Se você estiver interessado em mais detalhes, dê uma olhada no código fonte de pam_mkhomedir.so
. Eu usei esta versão dele para minha resposta ( foi escrito por Jason Gunthorpe , cujo nome também está em meu pam_mkhomedir.so
manpage ).
Agora, no que me diz respeito, acho que o guia que você seguiu está um pouco incompleto ou, pelo menos,
+----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| username | varchar(30) | NO | UNI | NULL | |
| pass | varchar(50) | NO | | NULL | |
+----------+-------------+------+-----+---------+----------------+
Esta tabela provavelmente é detalhada o suficiente para que o VSFTPd funcione. Como ele é configurado com uma raiz inicial, ele pode determinar facilmente o diretório inicial de um usuário: $ftp_root/username
. Na verdade, isso é definido com o parâmetro local_root
:
local_root=/home/vsftpd/$USER
No entanto, pam_mkhomedir.so
não é VSFTPd. Ele não usa esse mecanismo, mas depende do NSS (por meio de getpwnam(3)
). O problema é: sua tabela do MySQL não fornece informações suficientes para que o NSS preencha o struct passwd
que vimos anteriormente. Para que o NSS use o MySQL como fonte, você precisará instalar o nss-mysql , que requer uma tabela MySQL maior . Isto irá requerer ajustes na sua configuração VSFTPd, mas você não deve ter nenhum problema em coabitar o VSFTPd e o nss-mysql.
Este diretório dá um exemplo para uma configuração mínima do nss-mysql. A tabela MySQL para usuários é definida da seguinte forma:
+-----------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| username | varchar(255) | NO | | NULL | |
| username_canonical | varchar(255) | NO | UNI | NULL | |
| email | varchar(255) | NO | | NULL | |
| email_canonical | varchar(255) | NO | UNI | NULL | |
| enabled | tinyint(1) | NO | | NULL | |
| salt | varchar(255) | NO | | NULL | |
| password | varchar(255) | NO | | NULL | |
| last_login | datetime | YES | | NULL | |
| locked | tinyint(1) | NO | | NULL | |
| expired | tinyint(1) | NO | | NULL | |
| expires_at | datetime | YES | | NULL | |
| confirmation_token | varchar(255) | YES | | NULL | |
| password_requested_at | datetime | YES | | NULL | |
| roles | longtext | NO | | NULL | |
| credentials_expired | tinyint(1) | NO | | NULL | |
| credentials_expire_at | datetime | YES | | NULL | |
+-----------------------+--------------+------+-----+---------+----------------+
Agora, você pode não precisar de todos esses campos, mas tenha em mente que struct passwd
estrutura que vimos anteriormente e tenha certeza de que nss-mysql tem dados suficientes para preenchê-lo :) Além disso, os arquivos de configuração nss-mysql são flexível o suficiente para você usar valores padrão para qualquer coisa.