Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 15 Dec 1996 14:52:15 -0700 (MST)
From:      Terry Lambert <terry@lambert.org>
To:        wpaul@skynet.ctr.columbia.edu (Bill Paul)
Cc:        current@freebsd.org
Subject:   Re: Plan for integrating Secure RPC -- comments wanted
Message-ID:  <199612152152.OAA24022@phaeton.artisoft.com>
In-Reply-To: <199612152022.PAA05216@skynet.ctr.columbia.edu> from "Bill Paul" at Dec 15, 96 03:22:39 pm

next in thread | previous in thread | raw e-mail | index | archive | help
> 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-).


> 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).


> Splitting out the DES code
> ---------------------------
> 
> We obviously can't provide the DES support with the core OS since
> that would violate U.S. crypto export laws. (The Linux distributors
> don't seem to care and are happily exporting it anyway, but I think
> it's safe to say we don't want to follow their example. :) Consequently,
> the DES code has to be shipped seperately as part of the DES or secure
> distributions. 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.

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.


> Right now, there are several programs in /bin and /sbin which use
> NIS code as a side effect of calling libc functions that have NIS
> support in them. All the executables in these directories are linked
> static, hence each has a copy of the NIS support in them. This includes
> things like /bin/csh, /sbin/dump, /sbin/mountd, /sbin/mount_*, and
> many more. Right now, we deal with this problem by providing replacement
> executables in the DES distribution (/sbin/init and /bin/ed). But
> in this case there will be a _lot_ more programs affected, and replacing
> all of them just doesn't seem like a good solution to me.
> 
> The question then is how to seperate out the DES code without actually
> changing any executables. There are actually three ways, all of which
> suck. It's a matter of choosing the least suckiest.

[ ... ]

> 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"?

[ ... #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?".


> 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.


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.

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.

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.


[ ... ]

> The last sticky issue has to do with the way keyserv(8) works.
> Keyserv's purpose is to store users' unencrypted secret keys. It
> keeps them in memory, and they're all lost when keyserv exits.
> 
> (The exception is root's secret key, which can be stored in
> /etc/.rootkey. This is needed in case a system crashes and reboots
> while the system operator is away and can't reload root's secret
> key with keylogin(1). In some cases, system daemons (like rpc.ypupdated
> and rpc.nisd) need root's secret key to work correctly and will
> break if it's not available.)

I have been thinking along similar lines to allow for support of
the password/kernel_object mapping for some types of advanced
applications.

Specifically, it seems to me that the user's credentials should be
associated with the session, and not with the process, in the
kernel space.

Add to this that the credentials attached to a credential pointer
should be extensible.

What this basically means is that for a process which you grant root
credentials, you have granted all of the associated credentials at
the same time.

Some applications include:

o	SMBFS per user credentials, as required by the Microsoft
	server security model

o	NDS (NetWare Directory Services) per user credentials
	so that an authenticated shell user is an authenticated
	NetWare user

o	Directory-level and file-level password protection.  This
	is required for most B-level security in any case -- I
	refer interested parties to the relevent Books, and to
	Helen Custer's _Inside Windows NT_.

In point of fact, if these credentials are associated with the
session, then each user credential will be a member of the same
session, by definition.

This kind of implies (but does not require: there is always the
possibility of preauthentication vs. denial of service) a session
manager that can make requests of the user based on kernel events,
like credential requests for non-existant, non-cached credentials
("please enter your NetWare login:", "please enter your NetWare
password", "save this password as part of your account information?",
etc.).

This leads to a Windows95 or WindowsNT style password cache interface.

For your example of a root credential, you would ensure a saved key
as part of the cached root credentials that were loaded from the
cache into the kernel credentials when a root session is instantiated.


> 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-).


The more I think about it, the more I want a session manager so I
can open /dev/session in xdm, and when I get events, put put nice
credential requestors that the user has to reply to.  8-).


					Regards,
					Terry Lambert
					terry@lambert.org
---
Any opinions in this posting are my own and not those of my present
or previous employers.



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