[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Homeverzeichnis in /etc/passwd als relativer Pfad


Hallo Markus,

On Thu, Oct 25, 2012 at 11:09:42PM -0200, Markus Demleitner wrote:
> > Eine Option waere, den Zugriff auf die Datei /etc/passwd zu maskieren,
> > d.h. ein fopen("/etc/passwd") transparent fuer den jeweiligen Prozess
> > tatsaechlich umzuleiten auf $DIR/conf/etc/passwd, also eine Art
> > Mapping-Datei / Alias-Datei, die von zB glibc oder aber im Kernel
> > Anwendung findet. 
> Uh.  Du bist sicher, dass du nicht lieber einen winzigen Patch in die
> ssh-Quellen reinfummeln willst?  

Nein, will ich nicht. Ich will das Verhalten ja nur fuer einen bestimmten
Benutzer veraendern.

> Ich gebe zu, an ssh rumfummeln ist
> immer etwas aufregend, aber eigentlich sieht der Kram recht harmlos
> aus (ssh.c, einfach nach _PATH_SSH_USER_CONFFILE suchen; in 5.5p1 ist
> das in der Gegend von Zeile 650).  Aber ein Check auf ein Configfile
> macht dann eigentlich nicht viel was anderes als der Wrapper oben,
> der auch noch gleich den Vorteil hat, dass man ihn statt ssh dann
> lieber ssh-spezial nennen kann, so dass die Leute sehen, dass da
> Magie passiert.

Ich habe mir heute mal ne Stunde Zeit genommen und in den Sourcen von
openssh-portable rumgesucht. Ich habe in glob.c Code gefunden, der 
eigentlich  das tun sollte, was ich erwarten wuerde: ~ resolven nach
getenv("HOME").

---------------------------------------------------------------------------
static const Char *
globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t
*pglob)
{
...
#if 0
                if (issetugid() != 0 || (h = getenv("HOME")) == NULL) {
#endif
                if ((getuid() != geteuid()) || (h = getenv("HOME")) == NULL) {
                        if ((pwd = getpwuid(getuid())) == NULL)
                                return pattern;
                        else
                                h = pwd->pw_dir;
...
}
---------------------------------------------------------------------------

 
In getpwuid(3) steht entsprechend auch, dass man das so tun *sollte*

       The  pw_dir field contains the name of the iniâ??
       tial working directory of the user.  Login proâ??
       grams use the value of this field to initialize
       the HOME environment  variable  for  the  login
       shell.   An application that wants to determine
       its user's home directory  should  inspect  the
       value  of  HOME  (rather  than  the value getpâ??
       wuid(getuid())->pw_dir) since this  allows  the
       user to modify their notion of "the home direcâ??
       tory" during a login session.  To determine the
       (initial) home directory of another user, it is
       necessary to  use  getpwnam("username")->pw_dir
       or similar.

Es scheint, dass ssh(1) die diversen(!) Konstanten in der Form
"~/.ssh/..." nicht ueber HOME evaluiert sondern ueber offensichtlich 
ueber getpwuid(getuid())->pw_dir).

Obiger Code ist aus /openbsd-compat/glob.c, die Funktionen haengen so
zusammen: glob() --> glob0() --> globtilde()

Also habe ich den Code nach "glob(" gegreppt:

/work/usr/ports/security/openssh-portable/work/openssh-5.8p2]# find .  -type f -name "*.c"  -exec grep -l "glob(" {} +
./openbsd-compat/glob.c
./sftp.c
./sftp-glob.c

Der globbing-Code wird scheinbar nur fuer sftp verwendet, scheinbar 
nicht fuer ssh(1). 

Zugriff auf "pw_dir" (das ist der Name des Feldes aus /etc/passwd, in
dem das Homeverzeichnis steht) wird an sehr vielen Stellen verwendet:

find . -type f -name "*.c"  -exec grep -l "pw_dir" {} +
./monitor.c
./auth.c
./ssh-rand-helper.c
./ssh-add.c
./ssh-keygen.c
./auth-rhosts.c
./misc.c
./openbsd-compat/glob.c
./session.c
./monitor_wrap.c
./ssh.c

Zum Beispiel hier in ssh.c:

main(...)
{
... 
       /* Get user data. */
        pw = getpwuid(original_real_uid);
        if (!pw) {
                logit("You don't exist, go away!");
                exit(255);
        }
        /* Take a copy of the returned structure. */
        pw = pwcopy(pw);
...
        /*
         * Read per-user configuration file.  Ignore the system wide
         * config
         * file if the user specifies a config file on the command line.
         */
        if (config != NULL) {
                if (!read_config_file(config, host, &options, 0))
                        fatal("Can't open user config file %.100s: "
                            "%.100s", config, strerror(errno));
        } else {
                r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir,
                    _PATH_SSH_USER_CONFFILE);
                if (r > 0 && (size_t)r < sizeof(buf))
                        (void)read_config_file(buf, host, &options, 1);
...

}

Oder kurz:
* pw = getpwuid(...)
* pw->pw_dir 

Hier wird also in ssh.c gezielt nur die Information benutzt, die aus
getpwuid() kommt (also das Homeverzeichnis anhand von /etc/passwd)

Ich kann sowas fuer sshd(8) nachvollziehen, weil da macht es Sinn *NICHT*
$HOME zu verwenden oder wenn der Benutzer root-Rechte hat.

Aber wenn ein normaler Benutzer ssh(1) verwendet, dann sollte ihm
gestattet sein, ueber Anderung von HOME=/some/where/ auf andere Dateien
zu verweisen, die er ohnehin lokal verwenden oder ueberschreiben koennte.

Ich verstehe also den Sicherheitsgewinn nicht, wieso nicht HOME
verwendet wird.

Fazit: SSH ist ein ziemliches Biest!


[mapping fuer fopen()]
> LD_PRELOAD; zumindest auf glibc-Systemen muesstest du in ld.so(8) was
> finden.  Das Zeug ist fuer alles moegliche gut (ich erinnere mich

Nachdem ich etwas vom Code gelesen und oberflaechlich verstanden habe,
wuerde ich nur fuer den Aufgruf von ssh(1) die Funktion getpwuid()
ueberladen, sodass getpwuid() mir etwas liefert, was ich ueber eine
Umgebungsvariable steuern kann, zB HOME_OVERRIDE=/opt/foo/bla/conf/
wuerde (falls gesetzt) den Wert ersetzen, den getpwuid() sonst aus
/etc/passwd ziehen wuerde, sodass ssh(1) dann nicht HOME sondern effektiv
HOME_OVERRIDE bekommt.

Das ist sicher die Hardcore-Variante, waere aber gegenueber dem restlichen
System und Standardverhalten minimalinvasiv anwendbar, da es nur on-demand
per LD_PRELOAD verwendet wird.

Vermutlich koennte man sich den erforderlichen Code per copy-paste aus
den openssh-Quellen zusammenbauen. Ich hab schlichtweg aber keine Ahnung
wie man C entwickelt sodass es das oben beschriebene (HOME_OVERRIDE
nehmen falls gesetzt) tut.

Haette den Vorteil, dass man das fuer alles verwenden koennte, was aehnlich
garstig ist wie openssh.

Aktuell lebe ich mit dem Hack, dass ich in /etc/passwd als
Homeverzeichnis "./conf" eingetragen habe, was dann abhaengig vom
aktuellen Pfad verwendet wird.

Gruss
Raphael

-- 
Raphael Eiselstein <rabe@xxxxxxxxx>               http://rabe.uugrn.org/
xmpp:freibyter@xxxxxx  | https://www.xing.com/profile/Raphael_Eiselstein   
GnuPG:                E7B2 1D66 3AF2 EDC7 9828  6D7A 9CDA 3E7B 10CA 9F2D
.........|.........|.........|.........|.........|.........|.........|..



-- 
UUGRN e.V. http://www.uugrn.org/
http://mailman.uugrn.org/mailman/listinfo/uugrn
Wiki: https://wiki.uugrn.org/UUGRN:Mailingliste
Archiv: http://lists.uugrn.org/