*BSD News Article 67977


Return to BSD News archive

Path: euryale.cc.adfa.oz.au!newshost.anu.edu.au!harbinger.cc.monash.edu.au!news.mira.net.au!vic.news.telstra.net!act.news.telstra.net!imci3!imci2!news.internetMCI.com!newsfeed.internetmci.com!news.msfc.nasa.gov!sol.ctr.columbia.edu!startide.ctr.columbia.edu!wpaul
From: wpaul@ctr.columbia.edu (Bill Paul)
Newsgroups: comp.unix.bsd.freebsd.misc
Subject: Re: NIS client setup
Date: 8 May 1996 14:35:59 GMT
Organization: Columbia University Center for Telecommunications Research
Lines: 177
Message-ID: <4mqbgg$29n@sol.ctr.columbia.edu>
References: <3189E69E.727C@arrakis.comm.pub.ro> <4ml84l$3nf@plains.nodak.edu> <4mnh4i$s7p@picard.cistron.nl>
NNTP-Posting-Host: startide.ctr.columbia.edu
X-Newsreader: TIN [version 1.2 PL2]

Daring to challenge the will of the almighty Leviam00se,
Miquel van Smoorenburg (miquels@cistron.nl) had the courage to say:

: In article <4ml84l$3nf@plains.nodak.edu>,
: Mark Tinguely <tinguely@plains.nodak.edu> wrote:
: >we should x-or the password record coming from NIS server (and x-or on
: >client), because NIS defeats a shadowed password. Looking at the network
: >text showed one of our students another NIS bug that I need to document
: >and send to the NIS maintainers.

The 'bug' you're thinking of (I got your mail) is not a bug, but a
misfeature.

Let me address something else first: you don't have to put any magic
information in the NIS '+' entries that go in /etc/master.passwd in
order for users to be able to change their passwords. Ideally, you
should do nothing at all except add a line to /etc/master.passwd that
says:

+:::::::::

That's it. Nothing else. (Well, and add +::: to /etc/group.) IF you
read the passwd(5) man page, it says that in FreeBSD, _ALL_ fields
can be remapped. So if you do this:

+:*:0:0::::::

Then what you'll be doing is remapping all NIS users' passwords to '*'
and all UIDs and GIDs to 0. This is not what you want. The man page
warns quite strenuously not to do this.

As for the misfeature, you're wondering why FreeBSD NIS clients always
seem to request the first record from the master.passwd map whenever
they make a request. (Note that in your mail, you claimed that this
could be triggered by calling getuid(). This is wrong: getuid() is a 
system call. System calls never use NIS. I think you meant getpwuid(3).)

Okay, to understand what's going on here, consider that we're trying
to shoehorn the BSD password database system into NIS. There are actually
two databases: master.passwd, which contains real encrypted passwords
and has extra fields in it compared to the standard UNIX /etc/passwd format,
and passwd, which has * in the passwords fields and is in standard format
for compatibility with other systems.

A FreeBSD NIS client wants the server to have both master.passwd maps
and passwd maps so that it can use a shadow password scheme similar to
the one it uses for the local databases. The way the system works, if a
non-root user on the NIS client calls one of the getpwent(3) functions,
the library code just looks for the passwd.byname maps (the 'safe'
database, with no real password data). If invoked by the superuser, they
try to find the master.passwd maps first and use those instead if they're
available. All of the user authentication programs in BSD run with
root privilege, so they will be able to read the correct password data,
while normal users will only get to see the passwd maps, which have
no password info in them.

To enforce the restriction, the FreeBSD ypserv will refuse to serve the
master.passwd maps to a client unless it receives an RPC from a reserved
port. Since only the superuser can bind to a reserved port, ypserv can
tell that a request is coming from the superuser on a client and honor
it. If a non-privileged user tries to do, for example,
'ypcat master.passwd.byname,' all they'll get is a 'YP server error.'

But supposing you're using a FreeBSD client with a non-FreeBSD NIS server
which doesn't have any master.passwd maps on it (or supposing you configure
a FreeBSD NIS server not to have any master.passwd maps). In order to
maintain compatibility, the client must fall back on using the standard
passwd maps. This means it must make due with the old format, and the
shadowing system is defeated: any user can grab the password file, complete
with encrypted passwords.

So: in order for this scheme to work, the client code must test for the
presence of the master.passwd maps. The only way to do this is to ask the
NIS server to do some operation on one of the maps and see if it gets
an error. (Note that this test is only done if you're superuser: there's
no point in doing it for non-root users since ypserv won't let them access
the master.passwd maps anyway.) Originally, I did this test by trying
to do a yp_order() on one of the master.passwd maps. Unfortunately, I
later discovered that the Solaris rpc.nisd (the NIS+ server) in 'NIS v2
compat mode' doesn't support the YPPROC_ORDER procedure. This broke
FreeBSD clients when used with NIS+ servers. (The reason they don't support
it any more probably has to do with the fact tha YPPROC_ORDER is used
mostly when doing map transfers between NIS master and slave servers,
and NIS+ doesn't use the same scheme for that anymore.) So I decided to
change it from yp_order() to yp_first(), since yp_first() doesn't require
me to know any of the keys in the map.

Take a look at src/lib/libc/gen/getpwent.c and search for the function
called _havemaster(). This is the function that tests for the presence
of the master.passwd map.

Yes, this is a kludge. Yes it's ugly. Yes I wish I could do it better.
I could have made _havemaster() read a local configutation file that
tells whether or not to use the master.passwd maps, but I didn't want
to put Yet Another Configuration File (tm) in /etc. The code is supposed
to be smart enough to figure this out by itself.

As for encryption, don't think I haven't thought of that. The trouble
is that both the client and the server have to agree on a key (even
if you use a simple XOR scheme). Having the key hardcoded into ypserv
and libc seems silly. I do have a Cunning Plan (tm) to actually impliment
encryption (at least for the master.passwd maps) but I have to find
time to actually sit down and make it work. Also, this will result in
yet another system-specific shadow password scheme that won't work with
anyone else. And last, bear in mind that NIS transactions are supposed
to be fast; if you add encryption to the mix and don't do it right, you
can wreck performance. (The system call overhead is already murder once
you start using very large maps with very small records. Calling sendto()
and recvfrom() a few thousand times over can consume a lot of cycles,
you know.)

: You could check the port the request is originating from and xxx out
: the password field if it is > 1024 (ie insecure). The standard RPC libs
: always try to bind to a reserved port, so root processes will get the
: password but user processes won't. Ofcourse this will only work if the
: slave servers behave the same (and bind to a reserved port during ypxfr).

The problem with this trick is that a) it's easy to spoof, and b) it
won't work with some systems. If you have access to a Solaris machine,
do an rpcinfo -p on it and check the output. You'll notice that except
for the portmap service itself, everything is bound to a non-privileged
port. I attribute this to a bug in the Solaris RPC library. (Note that
Solaris uses TI-RPC, which is based on STREAMS rather than RPC 4.0, which
is based on sockets). I call it a bug because I've tried to write RPC
programs using the TCP and UDP transports and I can't get them to use
a reserved port even on purpose; the bindresvport() function doesn't
work. (I've pawed through the source code from TI-RPC 2.3 and I've
discovered why: bindresvport() is supposed to accept a socket and bind
it to a reserved port, but since TI-RPC uses STREAMS, it tries to convert
the socket to a TLI endpoint and it gets it wrong. On socket based systems
it works fine.)

Anyway, Solaris doesn't worry about reserved ports with RPC since it
has Secure RPC. This is in fact what NIS+ uses to prevent giving out
information to unauthorized clients. The point though is that using
a Solaris machine as an NIS client with a server that enforces the
'only honor requests from reserved ports' rule won't work: the Solaris
machine will neve be able to use a reserved port, so its requests will
always go unanswered. The fact that it works with FreeBSD is just a
happy coincidence, and I put up with it for now because it's marginally
better than nothing.

(There's one other OS that I've encountered which gets this wrong too:
Sony NEWS-OS 3.33. This is a BSD 4.3 variant and it does use standard
sockets-based RPC, yet for some reason it still doesn't use reserved
ports correctly.)

: I've helped developing something like this in the Linux NIS server
: (ypserv-0.18), it actually works quite nice.

I already added this feature to the Linux NIS server when ported it
to FreeBSD. :) Note however that this particular ypserv won't be in
FreeBSD 2.2: I've replaced it with one that I wrote myself. (Ditto
for rpc.yppasswdd, yppush, ypxfr and yp_mkdb.)

At one point I ported the GNU ypserv to IRIX for use in a lab here
on campus (50 Indys and one Challenge M server) and did a variation
on the privileged port trick. (Fortunately, the IRIX RPC library binds
root-owned processes to reserved ports correctly.) In this case, I
added an extra function to mangle the password field in the passwd
maps for all requests made by non-privileged users. So if, for example,
a user does 'ypcat passwd' on one of the machines, the password fields
in the data they get back are all overwritten with asterixes. (Asteri?)
If root does it, then the correct information is returned. I wanted to
impliment this scheme with my own network, unfortunately I have Solaris
clients (and Sony NEWS-OS clients).

-Bill

--
=============================================================================
-Bill Paul            (212) 854-6020 | System Manager, Master of Unix-Fu
Work:         wpaul@ctr.columbia.edu | Center for Telecommunications Research
Home:  wpaul@skynet.ctr.columbia.edu | Columbia University, New York City
=============================================================================
 "If you're ever in trouble, go to the CTR. Ask for Bill. He will help you."
=============================================================================