Vsftpd / pam_userdb.so - crie automaticamente diretórios pessoais de usuários virtuais

2

Configuração:

  • Amazon Linux EC2
  • vsftpd
  • Autenticação do PAM com o pam_userdb.so
  • Nomes de usuário / senhas gravados no banco de dados do usuário Berkeley a partir de uma fonte externa (lsyncd).

Existem muitos milhares de usuários virtuais, até hoje eu pré-criei manualmente os diretórios home para eles em / home / vsftpd

drwx------    2 vsftpd users     4096 Apr 11 15:28 user0123
drwx------    2 vsftpd users     4096 Apr 11 15:28 user0124
...

#%PAM-1.0
auth required pam_userdb.so db=/usr/local/vsftpd_auth/vsftpd_userdb crypt=none
account required pam_userdb.so db=/usr/local/vsftpd_auth/vsftpd_userdb

Eu quero evitar a pré-criação manual dos diretórios para que novas entradas no Berkeley DB funcionem automaticamente sem alterar cada nó.

A pesquisa produz perguntas semelhantes para autenticação LDAP e MySQL usando:

  • pam_mkhomedir.so
  • /etc/nsswitch.conf

Mas parece que não consigo juntar tudo isso para resolver este problema para o Berkeley DB.

    
por DanielB6 09.05.2018 / 15:01

1 resposta

0

Acabei de implementar um módulo PAM para usuários virtuais do vsftpd, baseado em pam_mkhomedir.so. Tenho certeza que pode ser melhorado, mas abaixo está uma versão de trabalho.

Uso:

pam_mkhomedir_vsftpd_virt.so [debug] vsftpd_user=<vsftpd_user> basedir=<basedir> 
  • vsftpd_user - geralmente vsftpd
  • basedir - normalmente / home / vsftpd /

/etc/pam.d/vsftpd:

#%PAM-1.0
auth requisite pam_userdb.so db=/path/to/userdb crypt=none
account requisite pam_userdb.so db=/path/to/userdb
account required pam_mkhomedir_vsftpd_virt.so debug vsftpd_user=vsftpd basedir=/home/vsftpd/
  • Eu alterei a autenticação e a conta de pam_userdb.so para 'requisite' para evitar a criação do diretório home se a autenticação do userdb não passar.
  • Eu implementei o módulo para atuar no nível da conta, porque as sessões não são usadas no meu contexto vsftpd.

Compilação:

gcc -fPIC -c pam_mkhomedir_vsftpd_virt.c
gcc -shared -o pam_mkhomedir_vsftpd_virt.so pam_mkhomedir_vsftpd_virt.o -lpam
  • Instale pam_mkhomedir_vsftpd_virt.so com os outros módulos PAM.

Código:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <unistd.h>
#include <syslog.h>

/* For now we will use the service function for account management
 */
#define PAM_SM_ACCOUNT
#include <security/pam_modules.h>

#define MAX_HOMEDIR_SIZE 100

typedef struct {
    bool debug;
    const char *vsftpd_user;
    const char *basedir;
    const char *user;
    char homedir[MAX_HOMEDIR_SIZE+1];
} options_t;

static int parse_input(pam_handle_t *pamh, int flags, int argc, const char **argv, options_t *options) {
    int rc;
    int basedir_len;
    int total_len;
    bool add_slash = false;
    int i;

    /* Retrieve the user name
     */
    rc = pam_get_item(pamh, PAM_USER, (void *)&options->user);

    if (rc != PAM_SUCCESS || options->user == NULL || *(options->user) == '
pam_mkhomedir_vsftpd_virt.so [debug] vsftpd_user=<vsftpd_user> basedir=<basedir> 
') { pam_syslog(pamh, LOG_ERR, "cannot retrieve the user name"); return PAM_USER_UNKNOWN; } /* Retrieve the module parms */ for (i = 0 ; i < argc; *argv++, i++) { if (strcmp(*argv, "debug") == 0) { options->debug = true; } else if (strncmp(*argv, "vsftpd_user=", 12) == 0) { options->vsftpd_user = *argv+12; } else if (strncmp(*argv, "basedir=", 8) == 0) { options->basedir = *argv+8; } else { pam_syslog(pamh, LOG_ERR, "unknown option '%s'", *argv); } } /* Validate input */ if (options->vsftpd_user == NULL || *(options->vsftpd_user) == '
#%PAM-1.0
auth requisite pam_userdb.so db=/path/to/userdb crypt=none
account requisite pam_userdb.so db=/path/to/userdb
account required pam_mkhomedir_vsftpd_virt.so debug vsftpd_user=vsftpd basedir=/home/vsftpd/
') { pam_syslog(pamh, LOG_ERR, "cannot retrieve the vsftpd user"); return PAM_NO_MODULE_DATA; } if (options->basedir == NULL || *(options->basedir) == '
gcc -fPIC -c pam_mkhomedir_vsftpd_virt.c
gcc -shared -o pam_mkhomedir_vsftpd_virt.so pam_mkhomedir_vsftpd_virt.o -lpam
') { pam_syslog(pamh, LOG_ERR, "cannot retrieve the base dir"); return PAM_NO_MODULE_DATA; } if (options->basedir[0] != '/') { pam_syslog(pamh, LOG_ERR, "base dir must start with '/'"); return PAM_NO_MODULE_DATA; } /* Check whether we need to add a slash to the path */ basedir_len = (int) strlen(options->basedir); if (options->basedir[basedir_len-1] != '/') add_slash = true; /* Verify we haven't exceeded the max dir length */ total_len = basedir_len + (int) strlen(options->user) + (add_slash?1:0); if (total_len > MAX_HOMEDIR_SIZE) { pam_syslog(pamh, LOG_ERR, "home directory max length of %d exceeded '%d'", MAX_HOMEDIR_SIZE, total_len); return PAM_BUF_ERR; } /* Create the homedir string */ snprintf(options->homedir, MAX_HOMEDIR_SIZE+1, "%s%s%s", options->basedir, add_slash?"/":"", options->user); /* Finished parsing input, log what we got... */ if (options->debug) { pam_syslog(pamh, LOG_DEBUG, "vsftpd user '%s'", options->vsftpd_user); pam_syslog(pamh, LOG_DEBUG, "base directory '%s'", options->basedir); pam_syslog(pamh, LOG_DEBUG, "user '%s'", options->user); pam_syslog(pamh, LOG_DEBUG, "home directory '%s'", options->homedir); } return PAM_SUCCESS; } static int create_homedir(pam_handle_t *pamh, options_t *options) { struct stat status; struct passwd *pwd; const char *vsftpd_user = options->vsftpd_user; char *homedir = options->homedir; /* Retrieve passwd data for the vsftpd user */ pwd = getpwnam(vsftpd_user); if (pwd == NULL) { pam_syslog(pamh, LOG_ERR, "unable to get user creds for '%s'", vsftpd_user); return PAM_CRED_INSUFFICIENT; } /* Check if home directory already exists */ if (stat(homedir, &status) == 0) { if (options->debug) pam_syslog(pamh, LOG_DEBUG, "home directory '%s' already exists", homedir); return PAM_SUCCESS; } /* Home directory doesn't exist, create it */ if (options->debug) pam_syslog(pamh, LOG_DEBUG, "creating home directory '%s'", homedir); if (mkdir(homedir, 0700) != 0) { pam_syslog(pamh, LOG_ERR, "unable to create home directory '%s'", homedir); return PAM_PERM_DENIED; } if (chmod(homedir, 0700) != 0 || chown(homedir, pwd->pw_uid, pwd->pw_gid) != 0) { pam_syslog(pamh, LOG_ERR, "unable to change perms on directory '%s'", homedir); return PAM_PERM_DENIED; } return PAM_SUCCESS; } /* PAM Account Management function */ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv) { options_t options; int rc; memset(&options, 0, sizeof(options_t)); rc = parse_input(pamh, flags, argc, argv, &options); if (rc != PAM_SUCCESS) { return rc; } rc = create_homedir(pamh, &options); if (rc != PAM_SUCCESS) { return rc; } return PAM_SUCCESS; }
    
por 16.05.2018 / 04:02