OpenSSH with Wilkinson patch on Mac OS X 10.2
lxs at MIT.EDU
Wed Oct 2 13:51:00 EDT 2002
>By bootstrap server do you mean the sshd child process that runs as
>the client and handles terminal emulation on the server side? If so,
By bootstrap server, Sam is referring to the bootstrap namespace
server and bootstrap subset port for the new login session. I'm not
a Mach expert, but I'll try to explain briefly how the bootstrap
ports and login sessions work.
Mach IPC servers (such as the CCacheServer which stores Kerberos
tickets) register themselves and are looked up by a service name.
This name is registered with a bootstrap namespace server which
listens on the bootstrap subset port.
Bootstrap ports are arranged in a hierarchy. At boot time a root
bootstrap port and root bootstrap server is created. After that,
whenever a new one is created, it becomes a child of the current one.
Requests for service names are forwarded up the hierarchy but not
down, so even though your process may belong to a subset port, it can
still look up servers in the root namespace.
In addition, there are also a hierarchy of Authorization sessions
controlled by the Security APIs in Mac OS X. Each session has its
own bootstrap namespace, and the root session is tied to the root
bootstrap namespace. Like the root bootstrap namespace, the root
Authorization session also serves all processes.
For security reasons, whenever your sshd logs in a new user, it
should create a new Authorization session and new bootstrap
namespace. The reason for this is because the user shouldn't be able
to create processes in the root Authorization session or root
bootstrap namespace. If the user can create such processes, there
are a variety of interesting attacks the user can potentially launch
against system servers to hijack them.
Fortunately, Apple already had to solve this problem for their own
sshd. There is a pam module to create a new Authorization session
for ssh sessions. Check out /etc/pam.d/ssh. (Thanks to Shantonu Sen
for pointing this out to me).
Unfortunately, Apple put the code to create the Authorization session
in pam_authenticate, so it won't happen in cases where the user
doesn't have to type a password. Which is of course mostly how
Kerberized ssh works. Sucko.
So you need to create your own Authorization session whenever your
sshd logs the user in without a password. To create one, you need to
call into a private API in the Security framework (add "-framework
Security" to your link line). Although it's a private function, you
can find the prototype in the Security sources in Darwin. Check out
the "Security" CVS module and look at
"SecurityServer/Authorization/AuthSession.h". You want to call
SessionCreate() with flags saying you are a remote login, and you
have a tty.
Note that since SessionCreate() is private, it's subject to change
without notice. Personally I wouldn't worry too much about software
updates, but major OS releases might break your code if the ABI of
the function changes.
Note that because SessionCreate() creates a new mach bootstrap subset
port and the Kerberos credentials are stored in a mach-IPC based
server, you must call SessionCreate() *before* storing credentials
for the first time.
>I think I've now got everything working. I discovered that I could
>get the server-side MIT libraries to create an API-style ticket cache
>in the client's context if I made the appropriate calls from this
>child process, after the "real user" id and group had already been
>irrevocably set to the client's id and group (using setuid() and
>setgid() instead of seteuid() and setegid()). (I'm calling
>ssh_gssapi_storecreds() from do_child() in session.c.) Ordinarily the
>calls to create the ticket cache are made much earlier -- as best I
>can tell even before the chrooted "privilege separation daemon" gets
For security reasons, the CCacheServer checks the effective uid of
all requests and refuses those from a uid other than the current
"server uid". This uid is determined from looking at the euid, uid
and the owner of the controlling terminal when tickets are first
stored. If all of these are root, it will launch as root. Otherwise
it favors (in order) non-root values in the euid, uid and owner of
the controlling terminal.
For historical reasons, the CCacheServer service name registered with
the bootstrap server contains the uid of the server (see above) and
the controlling terminal. So when you first store tickets, make sure
that the controlling terminal is set to the same controlling terminal
as the user's processes will be using. Otherwise the user's
processes won't be able to find the server because they will be
looking for the wrong name.
The reason we have the uid and controlling terminal in the service
name is because in Mac OS X 10.1 remote logins always landed in the
root namespace and root Authorization session. If a user logged in
twice or two users logged into the same machine, their CCacheServers
needed to register under unique names. We chose the controlling
terminal as the unique identifier. Technically this isn't necessary
now that logins call SessionCreate, but since there's always a chance
that someone will fail to call it (especially likely given that it's
a private API), we need to continue to support it.
Hope this helps,
Alexandra Ellwood <lxs at mit.edu>
MIT Information Systems http://mit.edu/lxs/www/
More information about the krbdev