5.1 Esempio modulo

Il seguente codice implementa un semplice modulo di autenticazione che effettua due controlli :

 
punto elenco

si assicura che l’utente sia elencato nel file delle password

punto elenco

richiede una password all’utente e verifica che la sua lunghezza sia almeno di otto caratteri, concedendo in caso positivo l’accesso

Come richiesto dalle convenzioni della libreria PAM, il modulo definisce le due funzioni pam_sm_authenticate(), che esegue i due compiti elencati sopra, e pam_sm_setcred(), che non esegue nessuna azione. L’esempio illustra l’uso del meccanismo di conversazione, utilizzato per richiedere all’utente la password da verificare. 

 

#include <string.h>
#include <stdio.h>
#include <pwd.h>
#define PAM_SM_AUTH

#include <security/pam_appl.h>
#include <security/pam_misc.h>

PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags,
                            int argc, const char **argv)
{

                   int ritorno;
                  const char *utente;
                  const struct pam_conv *conv;
                  struct passwd *pw; struct pam_message messaggio[1];
                  const struct pam_message *mes[1];
                  struct pam_response *risposta;

                  ritorno=pam_get_user(pamh,&utente,"Inserire nome utente: ");
                  pw=getpwnam(utente);
                  if (!pw)
                         return(PAM_USER_UNKNOWN);
                  ritorno=pam_get_item(pamh,PAM_CONV,(const void **) &conv);
                  mes[0]=messaggio;
                  messaggio[0].msg_style=PAM_PROMPT_ECHO_OFF;
                  messaggio[0].msg="Inserire la password\n";
                  conv->conv(1,(const struct pam_message **) mes,&risposta,NULL);
                  if(strlen(risposta->resp)<8)  return PAM_AUTH_ERR;
                       else  return PAM_SUCCESS;

 }

 

  PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)

                            return PAM_SUCCESS; 

}

5.2 Esempio applicazione

Il seguente codice implementa un'applicazione che utilizza PAM e mostra l’estrema versatilità permessa da questa libreria. Essa richiede di autenticare un utente, il cui user-name può essere inserito dalla linea di comando, delegando la scelta del meccanismo di autenticazione all’amministratore di sistema ( che configura il file nella directory /etc/pam.d ). L’applicazione resta all’oscuro di come l’utente viene autenticato, ma , a seconda del valore di ritorno della funzione pam_authenticate(), può decidere di concedere l’accesso all’utente o meno.

 

#include <security/pam_appl.h>
#include <security/pam_misc.h>
#include <stdio.h>

 static struct pam_conv conv = {
                                          misc_conv,
                                          NULL
 };

int main(int argc, char *argv[])
{

   pam_handle_t *pamh=NULL;
   int ritorno;
   const char *utente=NULL;
   if(argc == 2)
          utente = argv[1];
   if(argc > 2) {
         printf("Numero argomenti errati. Uso: ver_utente [nome utente]\n");
         exit(1);
 
  }    

  ritorno= pam_start("ver_utente",utente, &conv, &pamh);

  if (ritorno == PAM_SUCCESS)                                     /* Richiesta alla libreriadi autenticazione*/
               ritorno = pam_authenticate(pamh, 0);  
       /* dell'utente tramite il modulo definito in */
  else printf("%s \n ",pam_strerror(pamh, ritorno));    
/* /etc/pam.d/ver_utente */
   if(ritorno==PAM_USER_UNKNOWN)
                 printf("Utente inesistente \n ");

    if (ritorno == PAM_SUCCESS)
                 printf("L'utente è stato autenticato \n");
    else
                 printf("L'utente non è stato autenticato \n");

 
     if (pam_end(pamh,ritorno) != PAM_SUCCESS) {
                  pamh = NULL;
                  printf("%s \n ",pam_strerror(pamh, ritorno));
                  exit(1);
     }

}

5.3 Esempio Login

Quest'ultima sezione dell'appendice illustra una semplice applicazione login che utilizza le API PAM. Ciò non vuol dire che la porzione di codice seguente sia un programma login pienamente funzionante poiché alcune delle funzionalità necessarie non sono state incluse in maniera da enfatizzare l'utilizzo delle API PAM.

 

// Dichiarazione dei prototipi di funzione

static int login_conv(int num_msg, struct pam_message **msg, struct pam_response **response, void *appdata_ptr);
struct pam_conv pam_conv = { login_conv, NULL }; 
pam_handle_t *pamh;              
 /* handle di autenticazione*/

// Funzione main

 void main(int argc, char *argv[], char **renvp) {

 /* * Msnca il codice per collezionare i parametri PAM */
 /* * Invocare pam_start per dare inizio alle operazioni di autenticazione PAM  */

if ((pam_start("login", user_name, &pam_conv, &pamh)) != PAM_SUCCESS)
        login_exit(1);
pam_set_item(pamh, PAM_TTY, ttyn);
pam_set_item(pamh, PAM_RHOST, remote_host);
 while (!authenticated && retry < MAX_RETRIES) {
        status = pam_authenticate(pamh, 0);
        authenticated = (status == PAM_SUCCESS);
}

 if (status != PAM_SUCCESS) {
        fprintf(stderr, "error: %s\n", pam_strerror(pamh, status));
        login_exit(1);
}

/* ora controlliamo se l'utente autenticato ha il permesso di effettuare la login. */

 if ((status = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) {
        if (status == PAM_AUTHTOK_EXPIRED) {
                status = pam_chauthtok(pamh, 0);
                if (status != PAM_SUCCESS)
                     login_exit(1);
         }    
    }

/* invoca call pam_open_session per aprire la sessione autenticata
  * pam_close_session deve essere invocata dal processo chr
  * cancella l'entrata utmp  (i.e., init) */

if (status = pam_open_session(pamh, 0) != PAM_SUCCESS)
        login_exit(status);

/* stabilisce le credenziali del processo */

setgid(pwd->pw_gid);

 /* * Inizializza la lista supplementare di accesso per i gruppi
     * Ciò dovrebbe essere fatto prima di invocare pam_setcred perchè
     * il modulo PAM potrebbe aggiungere gruppi durante
     * la chiamata a pam_setcred
     */

initgroups(user_name, pwd->pw_gid);
status = pam_setcred(pamh, PAM_ESTABLISH_CRED);
if (status != PAM_SUCCESS)
        login_exit(status);

/* imposta il real (e l'effective) UID */

setuid(pwd->pw_uid);
pam_end(pamh, PAM_SUCCESS);

/* Una volta terminato l'utilizzo di PAM
  * è possibile implementare le funzionalità
  * di login che devono svolgere altri compiti
  */

}

/* login_exit - Effettua una chiamata a exit() e termina.
  * Questa funzione viene inserita affinchè PAM possa liberare la memoria
  * prima che il processo restituisca il controllo.
  */

  static void login_exit(int exit_code) {

            if (pamh) pam_end(pamh, PAM_ABORT);
                    exit(exit_code);

}

/* Corpo della funzione login_conv():
  * Questa è la funzione di conv (conversazione) chiamata da
  * un modulo di autenticazione PAM per stampare i messaggi di errore
  * o per ottenere le informazioni dall'utente.
  */

int login_conv(int num_msg, struct pam_message **msg,
                         struct pam_response **response, void *appdata_ptr) {
                while (num_msg--) {
                    switch (m->msg_style) {
                    case PAM_PROMPT_ECHO_OFF:
                                r->resp = strdup(getpass(m->msg));
                                 break;


                    case PAM_PROMPT_ECHO_ON:
                                (void) fputs(m->msg, stdout);
                                 r->resp = malloc(PAM_MAX_RESP_SIZE);
                                 fgets(r->resp, PAM_MAX_RESP_SIZE, stdin);
                               
/* aggiungere codice qui per rimuovere il carattere \n dalla stringa ritornata da fputs */
                                break;


                    case PAM_ERROR_MSG:
                                (void) fputs(m->msg, stderr);
                                break;


                    case PAM_TEXT_INFO:
                                (void) fputs(m->msg, stdout);
                                break;
                       

                    default:
                            log_error();
                            break;
                    }
                }
         return (PAM_SUCCESS);
}