Kapitel 6 System- und Benutzerdateien
Gerade als Programmierer von Programmen sollten Sie sich auch mit den zentralen Benutzerdateien auskennen. Gewöhnlich finden Sie diese Dateien im Verzeichnis /etc unter dem Namen /etc/passwd, /etc/shadow oder /etc/group. Meldet sich z. B. ein neuer Anwender beim System an, wird die Datei /etc/passwd benötigt. Aber auch Kommandos wie »who«,» ls –l« oder »finger« benötigen Daten aus der Datei /etc/passwd. Neben der Möglichkeit, Informationen zu Benutzer- bzw. Gruppendateien zu beschaffen, gibt es auch noch die entsprechenden Netzwerkdateien /etc/service, /etc/networks, /etc/protocols und /etc/hosts. Wie Sie an die entsprechenden Informationen programmiertechnisch herankommen, erfahren Sie in diesem Kapitel.
6.1 Die Datei /etc/passwd
Alle Benutzer werden gewöhnlich zentral über die Datei /etc/passwd verwaltet. Laut POSIX.1 wird diese Datei als Benutzerdatenbank bezeichnet. Neben dem Namen des Benutzers enthält diese Datei einige Kenndaten. Hierbei finden Sie allerdings nicht nur die Kenndaten der normalen Benutzer, sondern auch die vom Superuser root und Standard- und Systembenutzer. Mit cat können Sie sich die Datei ansehen:
you@host > cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
...
tot:x:1000:1000:J.Wolf,,,:/home/tot:/bin/bash
john:x:1001:1001:John Wolf,Augsburg,,:/home/john:/bin/bash
Jede Zeile dieser Datei beinhaltet einen Benutzer. Die einzelnen Doppelpunkte dienen als Trennzeichen zwischen den einzelnen Feldern. Somit hat eine solche Zeile folgende Syntax:
Benutzername:Passwort:UID:GID:Info:Heimatverzeichnis:Shell
|
Benutzername – Unter diesem Namen kann sich der Benutzer am System anmelden. Daher sollte dieser Name eindeutig sein. Da die Datei von oben nach unten abgearbeitet wird, wird bei einem doppelten Eintrag immer der erste Eintrag verwendet, der gefunden wird. |
|
Passwort – Bei älteren Systemen befand sich beim zweiten Feld früher das verschlüsselte Passwort. In der Regel sollte man allerdings heutzutage ein »x« dort stehen sehen. Dies bedeutet, dass das Passwort in /etc/shadow steht (verschlüsselt). Der Grund ist ganz einfach, da viele Programme auf die Datei /etc/passwd zurückgreifen müssen, weil hier auch die Shell und der Pfadname zum Heimatverzeichnis vermerkt sind, heißt das Leserecht für alle. Zwar sind die Passwörter immer noch verschlüsselt, aber jetzt bestand hier die Möglichkeit, ein Passwort zu entschlüsseln. Auch wenn dies im Augenblick nicht sehr einfach zu knacken ist, die Angriffsfläche ist nun mal da – daher auch die Auslagerung nach /etc/shadow. Diese Datei ist nicht mehr für jedermann lesbar. Befindet sich in diesem Feld ein »*« (für nobody), dann erfolgt die Anmeldung ohne Passwortanfrage. |
|
UID – Die Benutzernummer des Benutzers. Der Wert dieser Nummer sollte in Praxis größer als 100 (auf vielen Systemen mittlerweile auch größer als 1000) sein, weil die Zahlen darunter für den Systembenutzer vorgesehen sind. Aus technischen Gründen sollte die UID allerdings nicht größer als 64000 sein. Die UID 0 ist natürlich weiterhin dem Superuser root vorbehalten. |
|
GID – Die Gruppennummer des Benutzers. Auch hierbei sollte die Zahl nicht größer als 64000 sein. |
|
Info – Hier werden ggf. weitere Informationen zum Benutzer hinterlegt, wie z. B. der vollständige Name, die Adresse usw. - das Feld kann also mit einem beliebigen Text gefüllt werden. Gewöhnlich gibt man hier den vollständigen Namen des Benutzers an. Mehrere Angaben werden durch ein Komma getrennt. |
|
Heimatverzeichnis – Hier steht das Heimatverzeichnis des Benutzers bzw. das Startverzeichnis nach dem Login. Die Angabe erfolgt immer über eine absolute Pfadangabe und sollte natürlich im Dateisystem liegen, das zum Zeitpunkt der Anmeldung auch eingebunden ist. Natürlich sollte der Benutzer des Heimatverzeichnisses auch der Besitzer dessen sein. Die Angabe des Heimatverzeichnisses wird in der Variablen HOME abgelegt und steuert somit auch das Verhalten des Kommandos cd, wenn dies ohne Parameter aufgerufen wird. Natürlich wird hierdurch auch das Tilde-Zeichen ~ beeinflusst. |
|
Shell – Auch wenn hier gewöhnlich eine Shell steht, die nach der Anmeldung des Benutzers gestartet werden kann, können Sie hierbei auch jedes beliebige andere Startprogramm verwenden (vom Sinn abgesehen). Alle erlaubten Programme, die gestartet werden können, müssen in der Datei /etc/shells eingetragen sein. Wird dieses Feld leer gelassen, wird standardmäßig die Bourne-Shell (/bin/sh) verwendet – was unter Linux wieder nur ein symbolischer Link zur Bash ist. |
Somit können Sie die folgende Zeile wie folgt interpretieren:
john:x:1001:1001:John Wolf,Augsburg,,:/home/john:/bin/bash
Der Benutzername lautet »john«, das Passwort steht verschlüsselt in /etc/shadow, die UID und die GID lauten 1001, als zusätzliche Angaben wurde hier der Namen »John Wolf« und »Augsburg« angegeben. Das Heimatverzeichnis lautet /home/john und das Startprogramm (die Shell) ist die Bash (Bourne-Again-Shell).
6.1.1 Die Datei /etc/passwd auswerten
Die einzelnen Felder der Datei /etc/passwd sind in der Struktur struct passwd enthalten, die in der Headerdatei <pwd. h.> definiert ist.
Tabelle 6.1
Die Struktur struct passwd der Headerdatei <pwd. h.>
Strukturvariable
|
Bedeutung
|
char *pw_name
|
Benutzername
|
char *pw_passwd
|
Verschlüsseltes Passwort (nicht POSIX.1)
|
uid_t pw_uid
|
Benutzernummer UID
|
gid_t pw_gid
|
Gruppennummer GID
|
char *pw_gecos
|
Kommentarfeld (nicht POSIX.1)
|
char *pw_dir
|
Startverzeichnis nach dem Login
|
char *pw_shell
|
Loginshell
|
6.1.2 getpwuid und getpwnam – einzelne Abfrage von /etc/passwd
Mit den beiden Funktionen getpwname() und getpwuid() können Sie einen Eintrag der Passwortdatei /etc/passwd erfragen. Beide Funktionen sind POSIX.1-konform. Dies ist die Syntax:
#include <pwd. h.>
#include <sys/types.h>
struct passwd *getpwnam(const char * name);
struct passwd *getpwuid(uid_t uid);
Die Funktion getpwnam() gibt bei Erfolg einen Zeiger auf eine Struktur passwd zurück, die den Inhalt einer Zeile in /etc/passwd mit dem Benutzernamen name enthält (erstes Feld in /etc/passwd).
Die Funktion getpwuid() hingegeben gibt einen Zeiger auf eine Struktur zurück, die eine Zeile in /etc/passwd enthält, die der User-ID uid entspricht.
Beide Funktionen geben bei einem Fehler NULL zurück, wenn kein passender Eintrag in /etc/passwd gefunden wurde oder ein anderer Fehler aufgetreten ist. Konnte nicht ausreichend Speicher für eine passwd-Struktur alloziiert werden, wird errno auf ENOMEM gesetzt.
Hier die Funktion getpwnam() bei der Ausführung. Wollen Sie getpwuid() verwenden, brauchen Sie nur den entsprechenden Codeabschnitt auszukommentieren und die Kommentare um getpwuid() zu entfernen.
/* pasname.c */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <pwd. h.>
#include <string.h>
int main(int argc, char *argv[]) {
struct passwd *pas_ptr;
if( argc != 2 ) {
fprintf(stderr, "Usage: %s Name\n", argv[0]);
exit (EXIT_FAILURE);
}
/* Alternativ mit getpwuid() : */
/* pas_ptr=getpwuid( strtoul(argv[1], NULL, 10) ); */
pas_ptr=getpwnam(argv[1]);
if(pas_ptr == NULL) {
printf("Konnte nichts über %s ermitteln\n", argv[1]);
exit (EXIT_FAILURE);
}
printf("Folgende Angaben wurden ermittelt: \n");
printf("Benutzername : %s\n", pas_ptr->pw_name);
printf("Benutzernummer : %d\n", pas_ptr->pw_uid);
printf("Gruppennummer : %d\n", pas_ptr->pw_gid);
printf("Kommentar : %s\n", pas_ptr->pw_gecos);
printf("Loginverzeichnis : %s\n", pas_ptr->pw_dir);
printf("Loginshell : %s\n", pas_ptr->pw_shell);
return EXIT_SUCCESS;
}
Das Programm bei der Ausführung:
you@host > gcc -Wall -o pasname pasname.c
you@host > ./pasname john
Folgende Angaben wurden zu john ermitteln:
Benutzername : john
Benutzernummer : 1001
Gruppennummer : 1001
Kommentar : John Wolf,Augsburg,,
Loginverzeichnis : /home/john
Loginshell : /bin/bash
you@host > ./pasname tot
Folgende Angaben wurden zu tot ermittelt:
Benutzername : tot
Benutzernummer : 1000
Gruppennummer : 1000
Kommentar : J.Wolf,,,
Loginverzeichnis : /home/tot
Loginshell : /bin/bash
Hinweis Bei BSD-UNIX wird bei den Funktionen getpwnam() und getpwuid() das verschlüsselte Passwort automatisch aus /etc/shadow gelesen und in die Strukturvariable pw_passwd geschrieben, wenn das Programm vom Superuser (UID=0) gestartet wurde.
|
6.1.3 getpwent, setpwent und endpwent – komplette Abfrage
von /etc/passwd
Wollen Sie alle Daten in /etc/passwd erfragen, stehen Ihnen die drei Funktionen getpwent(), setpwent() und endpwent() zur Verfügung.
#include <pwd. h.>
#include <sys/types.h>
struct passwd *getpwent(void);
void setpwent(void);
void endpwent(void);
Die Funktion getpwent() liefert einen Zeiger auf die Struktur passwd zurück, die den Inhalt einer Zeile in /etc/passwd beinhaltet. Beim ersten Aufruf von getpwent() wird immer der erste Eintrag zurückgegeben. Jeder weitere Aufruf liefert dann den nächsten Eintrag (Zeile) in /etc/passwd zurück. Beachten Sie bitte außerdem, dass nach jedem erneuten Aufruf von getpwent() der alte Inhalt in der Struktur passwd mit dem neuen überschrieben wird. Tritt ein Fehler auf oder sind alle Einträge gelesen worden, gibt getpwent() NULL zurück. Konnte kein Speicher für die Struktur passwd alloziiert werden, wird errno auf ENOMEM gesetzt.
Die Funktion setpwent() öffnet die Datei /etc/passwd, wenn diese nicht bereits geöffnet wurde, und setzt den Dateizeiger auf den Anfang der Passwortdatei. setpwent() muss nicht unbedingt vor einem getpwent()-Aufruf verwendet werden.
Wenn Sie mit getpwent() fertig sind, können Sie mit endpwent() die Datei /etc/passwd wieder ordentlich schließen. Dies garantiert Ihnen bei einem erneuten Aufruf von getpwent(), dass /etc/passwd wieder neu geöffnet wird und sich der Dateizeiger am Anfang dieser Passwortdatei befindet.
Hierzu sind die Funktion getpwent() und endpwent() im Einsatz. Im Beispiel wird die Funktion getpwnam() nachgebildet.
/* pasname2.c */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <pwd. h.>
#include <string.h>
struct passwd *getpasswd(const char *loginname) {
struct passwd *pas_ptr;
while( pas_ptr=getpwent() ) {
if( strcmp(pas_ptr->pw_name, loginname) == 0) {
endpwent();
return pas_ptr;
}
}
endpwent();
return NULL;
}
int main(int argc, char *argv[]) {
struct passwd *pas_ptr;
if( argc != 2 ) {
fprintf(stderr, "Usage: %s Name\n", argv[0]);
exit (EXIT_FAILURE);
}
pas_ptr=getpasswd(argv[1]);
if(pas_ptr == NULL) {
printf("Konnte nichts über %s ermitteln\n", argv[1]);
exit (EXIT_FAILURE);
}
printf("Folgendes wurde zu %s ermittelt: \n", argv[1]);
printf("Benutzername : %s\n", pas_ptr->pw_name);
printf("Benutzernummer : %d\n", pas_ptr->pw_uid);
printf("Gruppennummer : %d\n", pas_ptr->pw_gid);
printf("Kommentar : %s\n", pas_ptr->pw_gecos);
printf("Loginverzeichnis : %s\n", pas_ptr->pw_dir);
printf("Loginshell : %s\n", pas_ptr->pw_shell);
return EXIT_SUCCESS;
}
Die Ausführung des Programms entspricht exakt der von »pasname.c«, das im Beispiel zuvor demonstriert wurde.
|