Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 15 Dec 1996 18:51:23 -0500 (EST)
From:      Bill Paul <wpaul@skynet.ctr.columbia.edu>
To:        terry@lambert.org (Terry Lambert)
Cc:        current@freebsd.org
Subject:   Re: Plan for integrating Secure RPC -- comments wanted
Message-ID:  <199612152351.SAA05656@skynet.ctr.columbia.edu>
In-Reply-To: <199612152152.OAA24022@phaeton.artisoft.com> from "Terry Lambert" at Dec 15, 96 02:52:15 pm

next in thread | previous in thread | raw e-mail | index | archive | help
Of all the gin joints in all the towns in all the world, Terry Lambert 
had to walk into mine and say:

> > Okay, I've decided on a final plan for integrating Secure RPC into
> > the main source tree. There were a couple of problems that had to be
> > dealt with which didn't have easy solutions, so I'm going to outline
> > them here to give people a chance to tell me they suck, call me a looney,
> > or present alternate solutions.
> 
> [ ... much deleted ... ]
> 
> Bill, you great big stud, you!
> 
> 8-).

You mean I'm not a looney? I'm shocked, shocked I tell you.
 
> > loopback transport for this; BSD has no loopback transport, so I opted
> > to use AF_UNIX sockets instead. (Once this change goes in, I also plan
> > to modify rpc.yppasswdd to use this transport instead of the hack it
> > has now.)
> 
> The "correct" name is AF_LOCAL, not AF_UNIX, I believe (I was surprised
> when I went looking... I thought it was AF_POSIX, not AF_LOCAL).

It says AF_UNIX in the headers. Those interested in changing the
name just so they can avoid using the word 'UNIX' without the blessing
of X/Open can bite me.
  
> > Splitting out the DES code
> > ---------------------------

[chop]

>. The trick is to isolate the DES support in such a way
> > that it can be provided seperately with a minimum of hassle to both
> > us and the end users. In terms of the source code, everything ultimately
> > boils down to a single function called _des_crypt(). The Secure RPC
> > source distribution from Sun includes everything needed to implement
> > Secure RPC _except_ this function. We need to maintain this separation.
> 
> This is not so obvious.  Specifically, there is an exportable DES in the
> 4.4 sources which is used for the password facility there (they don't
> use MD5, they use an exportable DES hasher).  The code is a simplified
> hasher which is unidirectional.  I didn't bother to look to see if the
> values it used were no longer table driven, but I suspect that it
> might be the case.

No, that's an exportable DES crypt(3), which is not the same as
exportable DES. The MIT DES library can't be exported. (Although, I
discovered that my 4.4BSD-Lite CD from ORA at UNIX Expo a while back
includes the Kerberos IV source and the MIT DES library source. I
wonder if ORA has shipped any of those CDs overseas.) Luckily,
Eric Young has written his own libdes in Australia that does what
the MIT library does, and more. This is the library I use for testing:
it happens to have a _des_crypt() interface specifically for Secure RPC,
and it's included in the secure dist.

> Depnending on usage as hash *only*, you might be able to use this.
> Certainly, the password stuff should use it by default to get rid of
> the MD5 incompatability issues.

Sorry, Secure RPC needs crypt/decrypt capabilities. Hashing won't
cut it. (Secure RPC works mainly by having one side send a timestamp 
encrypted with DES using a conversation key. The conversation key is 
encrypted with your secret key and sent with the rest of the AUTH
info. The other side decrypts the conversation key with your public key, 
then decrypts the timestamp. If any of this fails to work, you aren't
authenticated.)

[chop]
 
> > The very suckiest is the solution that Sun uses in Solaris, namely
> > the name service switch. The name service switch uses shared objects
> > to contain the various kinds of lookup routines: files, DNS, NIS and
> > NIS+. You can even create your own. The top-level lookup routines
> > (gethostbyname(), getpwent(), etc...) call a stub which reads the
> > /etc/nsswitch.conf file and dlopen()s the proper lookup modules
> > depending on what it finds there. Using this trick, one can supply
> > an NIS+ lookup module with no DES support in the core OS and a replacement
> > module with real DES support in the encryption kit. The problem with
> > this solution is that in the end, you really don't have any static
> > executables anymore: all programs that use the name service switch
> > must be linked with libdl.so. (The exception to this rule in Solaris
> > is /sbin/sh, which is truly static.)
> 
> I've been considering this type of approach for several months now
> for address family support.  Specifically, I've been looking for a
> way to implement extensions to the address family support space
> such that correctly written generic programs are transport independent,
> while current programs could continue to use header-defines (and
> inline stub functions, if neceaary) to get to historical interfaces.
> 
> Specifically, inet_aton, inet_addr, inet_network, inet_ntoa, inet_makeaddr,
> inet_lnaof, inet_netof.
> 
> I've been looking for this ever since Garrett murdered ISO.
> 
> It seems to me that this is an acceptable, if not ideal, method of
> solving the problem.
> 
> In any case, it should be possible to make the interfaces more abstract
> so that you don't implement non-reusable code (or I don't implement
> non-reuasble code -- whatever) and define a method of specifying a
> generic object file and dlopen'able list of shared objects for any
> given interface.  Maybe "name.i" or "name.in" in /usr/lib for an
> interface named "name"?

Solaris calls them /usr/lib/nss_foo.so, where foo is compat, nis, nisplus,
dns or files. I think the name service switch may work for what you have
in mind, except that the lookup function behavior is meant to be controlled
on a system-wide basis using /etc/nsswitch.conf. Controlling it on a
per-application basis may be harder.

I still haven't decided what to do when I finish NIS+ to allow the
admin to select which service to use. We use the '+' hack for NIS
now; without a hack similar to the name service switch, I'll need
to resort to something like choosing another magic character (maybe
the asterix '*') which can be substituted for '+' to specify that
we want NIS+ support instead of NIS v2.

This will get messier if, by some strange quirk of fate, we also get
NDS support.
 
> [ ... #2 ... ]
>  
> > The third solution, which is the one I've settled on, is to create
> > a 'DES daemon,' i.e. a server program that does the encryption.
> > Since Secure RPC needs keyserv(8) to be running anyway, I decided
> > to (ab)use it as the encryption server. (This is another case where
> > the "unix" transport comes in handy: only local processes can use
> > the service.) Basically I turned the _des_crypt() function into a
> > remote procedure call: the data block to be crypted/decrypted, the
> > key, and other arguments are sent to keyserv, which does the work,
> > then sends back the results. This way, the only program that needs
> > to call _des_crypt() as a local function is keyserv.
> 
> I guess my problem with this is "how are the guys in England going
> the get one without a major reengineering effort of their own?".

I don't understand. The over the wire RPC transactions are the same.
It's just local processes that call the local keyserv to encrypt/decrypt
data form them. Once you drop the DES library into place, FreeBSD's
Secure RPC will be compatible with all the other implementations.
The 'guys in England' can just load the non-US secure dist to get
Eric Young's libdes.so, and they're all set.

> > fixed keyserv so that it tries to dlopen() libdes.so in order to
> > obtain DES support rather than linking it to libdes.so at compile
> > time. At startup, keyserv, tries to dlopen() /usr/lib/libdes.so.3.x
> > and looks for the '__des_crypt()' symbol. If it finds it, it uses
> > that for its encryption and keyserv then operates in DES mode. If
> > it fails, it falls back to RC4 encryption (with a 40 bit key, just
> > like nutscrape). Since libdes.so is not supplied with the base OS,
> > keyserv will always operate in RC4 mode until you install the secure
> > dist. (The user can specify an alternate path for the shared lib
> > with a command line switch as well.)
> 
> This is clever.  It's probably the way the libc crypt() should be
> implemented by default.

Again, there's an issue with our implementation of dlopen(): the
actual dlopen() function lives in crt0.o, while static binaries are
linked with scrt0.o, which _doesn't_ have them. So if you link static,
I don't think this will work. That's why I made it a feature of keyserv
rather than a feature of libdesrpc, since programs linked static with
libdesrpc.a wouldn't work.

> Is there a reason you have not considered just taking the step of
> linking these programs shared (option 4?)?  This would resolve all
> of the problems simply and effectively.

Yes: I _like_ the fact that /bin and /sbin are linked static (/bin
mostly). The commands there keep working in the face of a corrupted
or deleted libc.so. I'm not in a hurry to change this.
 
> I believe the reasons for not running with a shared world are now
> largely irrelevant: the shared library dirty page library clobber
> bug seems to have died more than a year ago, and there is no real
> good reason for it.

That depends on your opinion. Again, I like having some purely static
binaries around to help deal in a shared lib crisis. Also, consider
fsck, which needs to be run on /usr (if /usr is not on the rootfs)
before /usr is mounted. We would have to move libc.so to the rootfs
in order for fsck to work if it was linked dynamic.

> The ld.so is mapped, and is therefore an open file reference, so
> overwriting it only affects programs started after the overwrite;
> clearly, there is a need to sync boot files over system instances
> so that you can back up in case of a screwup.  On the other hand,
> anyone using mount-time loaded LKM's (either intentionally or
> unwittingly) faces exactly the same problems of the component being
> invalid (for whatever reason, including a kernel mismatch, as in
> a proc structure change).
> 
> The need to use a .so for the DES in any case requires the dlopen()
> implementation.
> 
> 
> Arguably, the current implementation of seperate crt0's is not
> correct... once could easily claim from the SVR4 EABI start address
> base offset that the program loader (the kernel) should be mapping
> the ld.so into the process address space -- it is *not* the job of
> ctr0 to do this for you, it is the job of the kernel itself, in
> the abi-specific "exec".  This doesn't help a.out, which has too
> little room at the front to do this, but it certainly is meaningful
> for ELF.

What I don't understand is that in FreeBSD 2.1.x, we don't have an
scrt0.o (there's just crt0.o), yet we still have static binaries.
In any case, my reason for making this dependent on keyserv alone
(which will always be linked shared) was so that I could avoid getting
embroiled in this whole issue. :)

[session credential discussion chopped -- I don't want to get embroiled
 in this issue either :) ]
 
> > Utilities that call keyserv usually supply their UID as one of the
> > arguments in the RPC call. They also supply their UID in their
> > AUTH_UNIX credentials (keyserv requires clients to use AUTH_UNIX
> > creds). The problem is that there's no way for keyserv to be sure
> > that the client isn't lying, and it _needs_ to be sure, otherwise
> > a user can fool it into revealing other users' secret keys.
> 
> Using the method above, and exchange can be initiated by storing a
> keyserv credential as part of the user credential for all created
> processes, and changing it per request based on a callback event.
> 
> Specifically:
> 
> o	process calls "get keyserv credential"
> o	kernel saves current keyserv credential
> o	kernel sends event to keyserv saying credential has been
> 	retrieved
> o	keyserv events kernel telling it the new credential to
> 	store as the current keyserv credential
> o	kernel returns current keyserv credential to caller
> o	process uses current credential to authenticate to keyserv,
> 	after which credential is invalid for future instances because
> 	it is no longer current
> o	credentials created tis way should "time out".
> 
> Since the process can only retrieve "self" credentials, and the
> keyserv keeps these on a per process basis, spoofing of identity
> will fail because the credential/process pair is unique.  Any
> attempt to spoof will not match the one-behind.
> 
> Sort of like kerberos tickets.  8-).

I tried to fake this sort of thing up with message queues, though I
didn't try to have keyserv authenticate itself to the user. The
sequence was:

- Client calls msgget() to create a message queue with 0600 perms.
  The kernel creates the message queue with the client's UID and GID
  in the ipc_perms struct as credentials.
- Client generates a random number and puts it in the message queue,
  along with some other data.
- The client sends the message queue ID number to the server as part
  of its AUTH_UNIX verifier along with the random number it generated
  earlier.
- The server looks in the message queue and reads the random number,
  comparing it to the one sent with the AUTH_UNIX verifier. It then
  does the following tests:

   o Are the creator and owner UIDs of the queue the same?
   o Do they match the AUTH_UNIX UID?
   o Were the perms on the queue really 0600?
   o Does the random number from the message match the one
     sent with the AUTH_UNIX verifier?

  If the answer to all these questions is yes, then the server considers
  the authentication successful. It also removes the message queue, so
  the client needs to make a new one for each call.

Again, the problem with this is that we can't count on SysV message
queue support being in the kernel for us to use. You can't count on
my little LKM either, but it's easier to load the LKM than to recompile
the kernel. (Unless someone makes a SysV IPC LKM.)

-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
=============================================================================
 "It is not I who am crazy; it is I who am mad!" - Ren Hoek, "Space Madness"
=============================================================================



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199612152351.SAA05656>