OpenSSH with Wilkinson patch on Mac OS X 10.2

Alexandra Ellwood 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,
>you're right.

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 Information Systems                     

More information about the krbdev mailing list