Oggi volevo presentarvi la libcrypt,la libreria GNU che Linux utlizza per la gestione degli account e dei login.
Quello che ho implementato è un mini-passwd,cioè una versione mooolto esemplificata del celeberrimo comando utilizzato per aggiungere in /etc/passwd le informazioni riguardante gli utenti e in /etc/shadow le loro password.Qui mi occupo solo delle password.
È da notare che l’algoritmo utilizzato dalla libreria per la criptazione della password ,può essere
scelto attraverso il prefisso inserito nei primi caratteri del vettore “salt” nel primo codice,da passare alla funzione crypt.
Nel nostro caso il suffisso “$1$” informa la funzione di criptazione che l’algoritmo da utilizzare
è quello basato su MD5,ma potrebbe essere anche utilizzato il vecchio DES.
Tuttavia la modifica apportata all’algoritmo MD5 lo rende ancora più robusto della sua implementazione originale,conferendogli un’affidabilità maggiore del DES stesso.
Il primo codice è relativo al programma per l’inserimento della password nel file shadow delle password,che verrà creato nella directory corrente.
Il secondo invece gestisce un semplice esempio di login relativo ad un account.
Ricordo infine che per compilare è necessario forzare il compilatore a consultare la libreria crypt con
gcc -lcrypt -o eseguibile codice.c
per entrambi i programmi.
#include <stdio .h>
#include <time .h>
#include <unistd .h>
#include <crypt .h>
#include <stdlib .h>
#include <string .h>
void insert(char*,char*);
int main(int argc,char* argv[])
{
if(argc != 2){
printf("Usage: %s username\n",argv[0]);
return 0;
}
if(strlen(argv[1])>34){
fprintf(stderr,"L'username contiene troppi caratteri,ridurne la dimensione\n");
return 1;
}
unsigned long seed[2];
char salt[] = "$1$........";
const char *const seedchars =
"./0123456789ABCDEFGHIJKLMNOPQRST"
"UVWXYZabcdefghijklmnopqrstuvwxyz";
char *password;
int i;
/* Genera dei seeds (non troppo) casuali. */
seed[0] = time(NULL);
seed[1] = getpid() ^ (seed[0] >> 14 & 0x30000); //usiamo il pid del processo per rendere il seme abbastanza casuale
/*A partire dai due numeri pseudocasuali in seed[0] e seed[1] è possibile costruire un vettore di 10 caratteri ascii salt,da dare in pasto alla funzione crypt,grazie ad esso l'algoritmo basato su md5 può partorire la password */
for (i = 0; i < 8; i++)
salt[3+i] = seedchars[(seed[i/5] >> (i%5)*6) & 0x3f];
/* getpass riceve la password dell'utente e crypt effettua il calcolo dell'hash */
password = crypt(getpass("Password:"), salt);
insert(argv[1],password); //Inserisce la entry con nomeutente e pass sul file shadow
return 0;
}
void insert(char* user,char* pwd){
FILE *fd;
char buffer[35];
char *old;
char *passwd=malloc(strlen(pwd));
/*il puntatore pwd punta ad un'area di memoria dove la funzione getpass precedentemente invocata ha allocato la password immessa dall'utente.Se get pass deve essere invocato per l'immissione di una nuova password è necessario spostare il contenuto di quella precedente in un'altra area di memoria.*/
strcpy(passwd,pwd);
if(!(fd = fopen("shadow","r+"))){ //routine standard di apertura del file in lettura
fprintf(stderr,"Errore nell'apertura del file\n");
exit(0);
}
while(!feof(fd) && strcmp(buffer,user)) //scansione del file shadow
fscanf(fd,"%s",buffer);
if(feof(fd)){ //se il puntatore al file è arrivato alla terminazione senza trovare l'utente...
fclose(fd);
char *entry=malloc(strlen(user)+2+strlen(passwd));
strcpy(entry,user);
strcat(entry," ");
strcat(entry,passwd);
strcat(entry,"\n");
fd = fopen("shadow","a"); //routine standard di apertura del file in lettura
/* scrivi la nuova entry su shadow nella directory corrente con lo username,uno spazio e l'hash */
if(fprintf(fd,"%s",entry) < strlen(entry))
fprintf(stderr,"Errore di scrittura sul file\n");
fclose(fd); //chiudi lo stream
exit(0);
}
fscanf(fd,"%s",buffer); //se l'utente invece è stato trovato,la stringa successiva è la sua password
printf("Procedura di sostituzione password per l'utente %s\n",user);
old=crypt(getpass("Password Vecchia:"), buffer);
if(strcmp (buffer,old) == 0){
fseek(fd,-34,SEEK_CUR);
char *entry=malloc(strlen(passwd)+1);
strcpy(entry,passwd);
strcat(entry,"\n");
if(fprintf(fd,"%s",entry) < strlen(entry)){
fprintf(fd,"Errore di scrittura sul file\n");
fclose(fd);
}
}
else{
fprintf(stderr,"Spiacente,password Errata\n");
fclose(fd);
}
}
#include <stdio.h>
#include <unistd .h>
#include <crypt .h>
#include <stdlib .h>
void check(int);
void usr_in();
void pwd_r(char*,char*);
int main(int argc,char* argv[])
/* Il primo e unico argomento è il nome utente*/
{
if(argc != 2){
printf("Usage: %s username\n",argv[0]);
return 0;
}
char pass[35]; //utilizziamo un buffer di 35 bytes per la password criptata
/*la funzione pwd_r legge il file delle password e carica sul buffer l'hash della password per quell'utente*/
pwd_r(argv[1],pass);
char *result;
int ok;
/* Leggi la password dell'utente e calcolane l'hash,immettendo anche la pass attesa*/
result = crypt(getpass("Password:"), pass); //getpass è una funzione di unistd che prompta la password
/* Testa il risultato confrontando il buffer con l'hash della frase immessa dall'utente. */
ok = strcmp (result, pass) == 0;
check(ok); //ok è 1 se l'hash della password immessa è uguale a quella reale presente nel file
}
void check(int p_chk){ //se le due hash corridpondono il processo di login procede con l'accesso dell'utente
p_chk ? usr_in() : printf("Authentication Failure\nSpiacente.\n");
}
void pwd_r(char* user, char *buffer){
FILE *fd;
if(!(fd = fopen("shadow","r"))){ //routine standard di apertura del file in lettura
fprintf(stderr,"Errore nell'apertura del file\n");
exit(0);
}
/*stringa per stringa si effettua la ricerca dell'utente scelto fino alla terminazione del file*/
while(!feof(fd) && strcmp(buffer,user))
fscanf(fd,"%s",buffer);
if(feof(fd)){
printf("L'utente non esiste\n");
exit(0);
}
fscanf(fd,"%s",buffer); //se l'utente è stato trovato la stringa successiva è la sua password
fclose(fd);
}
void usr_in(){
printf("Accesso effettuato\n");
}



















