2009-07-22 7 views
2

Actuellement, j'ai une application graphique qui a deux niveaux d'accès, opérateur et administrateur. Le login et l'authentification sont tous homebrewed et je voudrais changer l'application pour utiliser PAM à la place. Je ne suis pas sûr de ce que la bonne façon de faire est.Différents niveaux d'accès avec PAM

Corrigez-moi si je me trompe, mais il semble que PAM se résume à un "oui" ou "non" vérifier - oui vous pouvez accéder à ce service, ou non vous ne pouvez pas. Il n'y a aucune disposition pour avoir différents niveaux d'accès en fonction de l'utilisateur qui se connecte. Je dois pouvoir dire qui est un opérateur et qui est un administrateur, et je veux être capable de le faire strictement via PAM si possible.

Donc, ma pensée est que je l'avais mis en place deux services avec deux configurations différentes,/etc/pam.d/pamdemo pour les opérateurs et /etc/pam.d/pamdemo-admin pour les administrateurs. Mon application essayera alors de s'authentifier contre pamdemo-admin d'abord, et si cela échoue alors pamdemo. Si les deux échouent, l'accès est refusé. Suis-je sur la bonne voie ou suis-je complètement hors des rails?

Voici un exemple de code C que j'ai écrit comme preuve de concept. Lorsque je fais le login, je ne veux pas demander à l'utilisateur deux fois ses identifiants. Je l'ai donc il se souvient du nom d'utilisateur à travers les deux pam_start() appels, mais je ne peux pas accéder pam_get_item(PAM_AUTHTOK) du niveau de l'application pour faire la même mise en cache pour le mot de passe. Et c'est en essayant de le faire que j'ai réalisé qu'il pourrait y avoir une façon totalement différente de le faire. Je voudrais que cette application fonctionne quelle que soit la méthode d'authentification, que ce soit le nom d'utilisateur/mot de passe ou les tickets ou empreintes digitales Kerberos, peu importe.

pam_handle_t *try_login(const char *service, int *retval) 
{ 
    static char * username = NULL; 
    struct pam_conv pam_conversation = { conv, NULL }; 
    pam_handle_t * pamh; 

    *retval = pam_start(service, username, &pam_conversation, &pamh); 

    if (*retval == PAM_SUCCESS) *retval = pam_authenticate(pamh, 0); 
    if (*retval == PAM_SUCCESS) *retval = pam_acct_mgmt (pamh, 0); 
    if (*retval == PAM_SUCCESS) *retval = pam_open_session(pamh, 0); 

    if (username == NULL) { 
     if (pam_get_item(pamh, PAM_USER, (const void **) &username) == PAM_SUCCESS) { 
      username = strdup(username); 
     } 
    } 

    if (*retval != PAM_SUCCESS) { 
     fprintf(stderr, "%s: %s\n", service, pam_strerror(pamh, *retval)); 
     pam_end(pamh, *retval); 
     pamh = NULL; 
    } 

    return pamh; 
} 

int main(void) 
{ 
    pam_handle_t *pamh = NULL; 
    int retval; 
    const char *service, *username; 

    if (!pamh) pamh = try_login("pamdemo-admin", &retval); 
    if (!pamh) pamh = try_login("pamdemo",  &retval); 

    if (!pamh) { 
     fprintf(stderr, "Access denied.\n"); 
     return 1; 
    } 

    pam_get_item(pamh, PAM_SERVICE, (const void **) &service); 
    pam_get_item(pamh, PAM_USER, (const void **) &username); 

    printf("Logged into %s as %s.\n", service, username); 

    pam_close_session(pamh, 0); 
    pam_end   (pamh, retval); 

    return 0; 
} 

Comme écrit ce programme de démonstration répète le « mot de passe: » invite. Je ne veux pas qu'il demande deux fois!

Répondre

2

je crois une bonne façon de faire cela pourrait être:

  • Mettre en place le service « pamdemo » pour effectuer des fonctions compte, authentification et de session.
  • Configurer le service "pamdemo-admin" en seulement pour les fonctions de compte (et éventuellement de session). Pas d'authentification. Lorsque vous vous connectez, commencez par les faire passer "pamdemo" (pour s'assurer qu'ils sont bien ceux qu'ils prétendent être) - si cela échoue, expulsez-les. Puis, une fois authentifié, donnez-les à "pamdemo-admin". Cela vérifie juste si elles sont autorisées à être admin - si elles le sont, cette vérification réussit, si ce n'est pas le cas, ce n'est pas le cas. Parce que cette vérification ne fait pas de modules auth, ils ne sont plus invités à entrer un mot de passe.
1

par la suggestion de café, voici ma solution:

#define PAM_CALL(call)        \ 
    do {            \ 
     if ((retval = (call)) != PAM_SUCCESS) {  \ 
      goto pam_error;       \ 
     }           \ 
    } while (0) 

int check_admin_login(const char *user) 
{ 
    pam_handle_t * pamh = NULL; 
    struct pam_conv pam_conversation = { conv, NULL }; 
    int    retval; 

    PAM_CALL(pam_start ("pamdemo-admin", user, &pam_conversation, &pamh)); 
    PAM_CALL(pam_acct_mgmt(pamh, 0)); 
    PAM_CALL(pam_end  (pamh, retval)); 

    return 1; 

pam_error: 
    pam_end(pamh, retval); 
    return 0; 
} 

int main(void) 
{ 
    pam_handle_t * pamh = NULL; 
    struct pam_conv pam_conversation = { conv, NULL }; 
    int    retval; 

    const char * user; 
    int    is_admin; 

    PAM_CALL(pam_start  ("pamdemo", NULL, &pam_conversation, &pamh)); 
    PAM_CALL(pam_authenticate (pamh, 0)); 
    PAM_CALL(pam_acct_mgmt (pamh, 0)); 
    PAM_CALL(pam_open_session (pamh, 0)); 
    PAM_CALL(pam_get_item  (pamh, PAM_USER, (const void **) &user)); 

    is_admin = check_admin_login(user); 
    printf("Logged in as %s (%s).\n", user, is_admin ? "administrator" : "operator"); 

    PAM_CALL(pam_close_session(pamh, 0)); 
    pam_end (pamh, retval); 

    return 0; 

pam_error: 
    fprintf(stderr, "%s\n", pam_strerror(pamh, retval)); 
    pam_end(pamh, retval); 

    return 1; 
} 
0

vous pouvez simplement utiliser la commande « groupes » ou « id » et obtenir les groupes de l'utilisateur, puis grep les groupes et si vous cliquez d'abord sur admin, puis sur admin, sinon c'est un utilisateur démo.

Les groupes/commandes id (testé sur Linux) va obtenir les groupes pour les utilisateurs non locaux ainsi (par exemple PAM/LDAP)

Ainsi, au lieu de vérifier contre un service, vérifiez le groupe dans lequel la l'utilisateur appartient.

Questions connexes