OpenSSH with Wilkinson patch on Mac OS X 10.2

Steven Michaud smichaud at pobox.com
Mon Nov 11 11:16:25 EST 2002


Thanks again for for your description of the bootstrap port and
authorization session hierarchies.  It gave me a very clear idea of
how things _should_ work in transactions with the OS X/Darwin
SecurityServer.  And one day, no doubt, they will work that way
consistently.  But they don't quite yet :-)

A) Problems -- Summary

First off, no program that links to the MIT/Apple Kerberos framework
can use SessionCreate() (at least on OS X 10.2) -- it will always fail
with the cryptic error return 0x80010001, which translates to
CSSM_ERRCODE_INTERNAL_ERROR.

Second, the error reporting for the client side of IPC transactions in
Apple's Security framework is badly broken -- the only possible error
returns are CSSM_ERRCODE_SERVICE_NOT_AVAILABLE,
CSSM_ERRCODE_MEMORY_ERROR and CSSM_ERRCODE_INTERNAL_ERROR.

Third, I appreciate the careful attention Apple paid in their Security
framework code to the issue of thread safety ... but they forgot about
fork() and exec().  There's a lot of IPC-related code that breaks
in a child process launched by either of these.

Finally, Apple has decided that, at least for the time being, not to
allow clients to reinitialize an authorization session once it's been
established.  Any IPC call to SecurityServer will establish an
authorization session.  So if you're going to call SessionCreate(), it
has to be the very first thing you do.  If, for example, you call
SessionGetInfo() first, your call to SessionCreate() will fail.  Apple
has made its OS components (such as its implementation of OpenSSH)
live with this restriction.  But I consider it a design flaw, and hope
it goes away soon.

I've found solutions or workarounds for all of these problems, and
will append patches to Darwin/OS X's Security framework and to Simon
Wilkinson's OpenSSH patch that contain them.  Please look at them, try
them out, and let me know what you think.  With luck something like
them will eventually find its way into production code :-)

By the way, my task would have been _much_ easier had I been able to
look at the source code for KfM.  So forgive me for putting in a
strong plug for open-sourcing the current versions of KfM.  KfM used
to be open-source.  MIT's Unix and Windows packages still are.  Even
Apple is, in fits and starts, open-sourcing important chunks of
Darwin/OS X.  So far as I can tell, MIT has no objections in
principle.  So please, please, please open source KfM as soon as
possible!

(I haven't yet reported my Security framework bugs to Apple, but I
will soon.)

(Yes, Apple should really take care of all of this, and we really
shouldn't have to add a call to SessionCreate() to the OpenSSH code.
But I'm not sure the vector should be PAM.  And in any case OpenSSH
already contains lots of platform-specific code -- just look at
sshpty.c.)

B) MIT/Apple Kerberos Framework Incompatible with SessionCreate()

Once I'd repaired the error reporting of the Darwin/OS X's Security
framework and had inserted extra syslog calls into its implementations
of SessionCreate() and SessionGetInfo(), I could see that the Kerberos
framework makes, somewhere in its initialization code, multiple calls
to SessionGetInfo().  These calls take place even before the first
line of main().  I've been linking to the Kerberos framework
indirectly (via libgssapi_krb5.dylib and so forth), but I suspect the
same thing would happen if I used "-framework Kerberos".

The (repaired) error return from SessionCreate() is 0xFFFF13AA (or
-60502), which translates to errSessionAuthorizationDenied.  But if
you look at the code for Session::setupAttributes() in SecurityServer/
session.cpp, you'll see that this error occurs because a session for
the same client already exists.

C) Security Framework Error Reporting Broken

Error::cssmError() in cdsa/cdsa-utilities/mach++.cpp can only return
either CSSM_ERRCODE_SERVICE_NOT_AVAILABLE or
CSSM_ERRCODE_INTERNAL_ERROR.  But if you replace "return
CSSM_ERRCODE_INTERNAL_ERROR;" with "return error;" (as I do in my
patch), IPC-related errors start getting reported correctly on the
client side.

D) Don't Forget fork() and exec()!

Both these bugs are subtle, but one is really wierd.

First the more obvious one:

A child process launched by fork() gets a new process id.  But if its
parent has already opened a connection to the SecurityServer, the Mach
ports inherited by the child (the "server" and "reply" ports used to
communicate with the SecurityServer) will be invalid.  I've added code
to ClientSession::activate() in SecurityServer/ssclient.cpp to
reinitialize the mGlobal object whenever the pid changes, and thereby
create new Mach ports.

Now the wierd one:

Strangely, the previous change only gets you a new server port.  The
reply port was stored by the parent process in thread-local storage
(in the replyPort field of the Thread object, a reference to which is
returned by calling mGlobal.thread()).  But when the new thread (in
the new process) gets its new slot for thread-local storage, the
contents, which should be NULL, is a pointer to the parent's
replyPort!  I'm not really sure how this happens.  But clearly a child
process can't assume that newly allocated thread-local storage has
been initialized to NULL.  I've added code to ThreadStoreSlot::
ThreadStoreSlot() in cdsa/cdsa-utilities/threading.cpp to deal with
this.

E) Let Clients Call SessionCreate() At Any Time

There used to be code to do this (in Server::resetConnection() in
SecurityServer/server.cpp and in other places), but Apple commented it
out because it was too dangerous.  I agree that it _was_ dangerous --
objects could get deleted even if they were still in use.  But I think
I've found a way to accomplish the same goal safely.

Just above Server::resetConnection() in server.cpp is
Server::endConnection().  The client could call this (via IPC) to make
SecurityServer delete its information on the client's current
connection.  It was the client's responsiblity to do this safely --
not to tear down a connection in one thread while it was still being
used in another.  Otherwise the server would crash.

I've added code to Server::endConnection() (and to some other places)
to make it refuse to delete a connection object unless it's safe to do
so, and to also delete the associated session object if _that's_ safe
(i.e. if no other connection is "using" the session).  If the objects
the client wants deleted don't get deleted, the client's subsequent
actions will generate the errors you'd have seen if the client hadn't
tried to delete those objects in the first place.

On the client side I've added code to ClientSession::setupSession() in
SecurityServer/sstransit.cpp to call Server::endSession() (via
ucsp_client_teardown()) just before it tries to create a new session.

F) Comments on the Security Framework Patch

The patch is to Security-54.tar.gz as downloaded from
http://www.opensource.apple.com/projects/darwin/6.0/projects.html.  I
haven't yet been brave enough to try out a CVS download of the
Security framework.  But as of yesterday, none of the problems I've
patched had been dealt with -- so my patch should also apply to recent
CVS downloads (possibly with offsets), and should still work
correctly.

Yes, this is supposed to be for Darwin only.  But you can't compile it
on Darwin (Project Builder is required, which is only available on OS
X).  And I've been able to use my patched copy of SecurityServer and
of the Security framework on OS X 10.2.1 without any difficulty.  (You
do get lots of prebinding errors for the first few boots, but they
eventually go away.)

One slightly annoying requirement to build the patch is that you need
to copy the PrivateHeader hierarchy from Darwin's CoreFoundation
framework to OS X's.  This contains two files -- CFRuntime.h and
CFPriv.h.  Don't forget to also create a soft link to "PrivateHeaders"
in the CoreFoundation.framework directory.

Note that a couple of header files are missing from Security-54.tar.gz
-- feeTypes.h (for "Fast Elliptic Encryption") and comcryption.h (for
"Apple Secure Compression").  I suspect this was deliberate, and has
something to do with Apple's patent claims.  But you can get around
this by not defining CRYPTKIT_CSP_ENABLE or ASC_CSP_ENABLE in your
project.pbxproj file.  This is what I've done in my patch.  I didn't
get any complaints about missing symbols when I copied my Security
framework into place and rebooted.  This must mean that nothing in OS
X is currently using either of these two technologies.

G) Comments on the Patch to Simon Wilkinson's OpenSSH Patch

First patch with Simon Wilkinson's patch, then patch with mine, then
run autoreconf.

But don't configure and make until you've done the following:

Fix /usr/include/openssl/opensslv.h to get its version information to
match the version that actually comes with OS X 10.2 (I'll append a
patch).

If you link to OS X's zlib, you need to fix /usr/include/zconf.h
(patch appended).

If you include PAM support, you need to create the
/usr/include/security directory, and in it place a soft link to
pam_appl.h.


    [ Part 2, ""  Text/PLAIN (Name: "Security-54-patch")  392 lines. ]
    [ Unable to print this part. ]


    [ Part 3, ""  Text/PLAIN (Name: "openssh-3.4p1-gss-OSX-patch")  718 ]
    [ lines. ]
    [ Unable to print this part. ]


    [ Part 4, ""  Text/PLAIN (Name: "opensslv.h-patch")  16 lines. ]
    [ Unable to print this part. ]


    [ Part 5, ""  Text/PLAIN (Name: "zconf.h-patch")  14 lines. ]
    [ Unable to print this part. ]

-------------- next part --------------
diff -c -r src.old/Security.pbproj/project.pbxproj src/Security.pbproj/project.pbxproj
*** src.old/Security.pbproj/project.pbxproj	Sat Nov  9 14:58:24 2002
--- src/Security.pbproj/project.pbxproj	Sat Nov  9 14:58:16 2002
***************
*** 126,132 ****
  				HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/BSafe.framework/Headers\" \"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks/BSafe.framework/Headers\" \"$(SRCROOT)/AppleCSP\" \"$(SRCROOT)/AppleCSP/open_ssl\"";
  				LIBRARY_STYLE = STATIC;
  				OPTIMIZATION_CFLAGS = "-O3 -DNDEBUG";
! 				OTHER_CFLAGS = "-DCRYPTKIT_CSP_ENABLE -DASC_CSP_ENABLE -DVDADER_RULES -DALLOW_ZERO_PASSWORD -DCRYPTKIT_DER_ENABLE";
  				OTHER_LDFLAGS = "";
  				OTHER_LIBTOOL_FLAGS = "";
  				OTHER_REZFLAGS = "";
--- 126,132 ----
  				HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/BSafe.framework/Headers\" \"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks/BSafe.framework/Headers\" \"$(SRCROOT)/AppleCSP\" \"$(SRCROOT)/AppleCSP/open_ssl\"";
  				LIBRARY_STYLE = STATIC;
  				OPTIMIZATION_CFLAGS = "-O3 -DNDEBUG";
! 				OTHER_CFLAGS = "-DVDADER_RULES -DALLOW_ZERO_PASSWORD -DCRYPTKIT_DER_ENABLE";
  				OTHER_LDFLAGS = "";
  				OTHER_LIBTOOL_FLAGS = "";
  				OTHER_REZFLAGS = "";
***************
*** 9339,9349 ****
  				INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks";
  				LIBRARY_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)\"";
  				OPTIMIZATION_CFLAGS = "-Os -DNDEBUG";
! 				OTHER_CFLAGS = "-DLIMITED_SIGNING -DBUILTIN_PLUGINS -DVDADER_RULES -DCRYPTKIT_CSP_ENABLE -DASC_CSP_ENABLE";
! 				OTHER_LDFLAGS = "-lComCryption -lCryptKit -twolevel_namespace";
  				PREBINDING = YES;
  				PRODUCT_NAME = Security;
! 				SECTORDER_FLAGS = "-sectorder __TEXT __text \"$(APPLE_INTERNAL_DIR)/OrderFiles/Security.order\" -seg_addr_table \"$(APPLE_INTERNAL_DEVELOPER_DIR)/seg_addr_table\"";
  				VERSIONING_SYSTEM = "apple-generic";
  				VERSION_INFO_PREFIX = Sec;
  				WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
--- 9339,9349 ----
  				INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks";
  				LIBRARY_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)\"";
  				OPTIMIZATION_CFLAGS = "-Os -DNDEBUG";
! 				OTHER_CFLAGS = "-DLIMITED_SIGNING -DBUILTIN_PLUGINS -DVDADER_RULES";
! 				OTHER_LDFLAGS = "-twolevel_namespace";
  				PREBINDING = YES;
  				PRODUCT_NAME = Security;
! 				SECTORDER_FLAGS = "";
  				VERSIONING_SYSTEM = "apple-generic";
  				VERSION_INFO_PREFIX = Sec;
  				WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
diff -c -r src.old/SecurityServer/Authorization/Authorization.cpp src/SecurityServer/Authorization/Authorization.cpp
*** src.old/SecurityServer/Authorization/Authorization.cpp	Sat Nov  9 14:58:25 2002
--- src/SecurityServer/Authorization/Authorization.cpp	Sat Nov  9 14:58:17 2002
***************
*** 151,156 ****
--- 151,157 ----
  	END_API(CSSM)
  }
  
+ #include <syslog.h>
  
  //
  // Get session information
***************
*** 161,173 ****
  {
      BEGIN_API
      SecuritySessionId sid = session;
      server().getSessionInfo(sid, *attributes);
      if (sessionId)
          *sessionId = sid;
!     END_API(CSSM)
  }
  
- 
  //
  // Create a new session
  //
--- 162,191 ----
  {
      BEGIN_API
      SecuritySessionId sid = session;
+     syslog(7,"SessionGetInfo(), entering");
      server().getSessionInfo(sid, *attributes);
+     syslog(7,"SessionGetInfo(), session id is 0x%.8X, "
+         "attributes are 0x%.8X",sid,*attributes);
      if (sessionId)
          *sessionId = sid;
!     //END_API(CSSM)
!     }
!     catch (const CssmCommonError &err) {
!         syslog(7,"SessionGetInfo(), CssmCommonError error is 0x%.8X",
!             err.cssmError(CSSM_CSSM_BASE_ERROR));
!         return err.cssmError(CSSM_CSSM_BASE_ERROR);
!     }
!     catch (const std::bad_alloc &) {
!         syslog(7,"SessionGetInfo(), memory error");
!         return CssmError::merge(CSSM_ERRCODE_MEMORY_ERROR, CSSM_CSSM_BASE_ERROR);
!     }
!     catch (...) {
!         syslog(7,"SessionGetInfo(), unknown error");
!         return CssmError::merge(CSSM_ERRCODE_INTERNAL_ERROR, CSSM_CSSM_BASE_ERROR);
!     }
!     return CSSM_OK;
  }
  
  //
  // Create a new session
  //
***************
*** 175,180 ****
--- 193,200 ----
      SessionAttributeBits attributes)
  {
      BEGIN_API
+     syslog(7,"SessionCreate(), called with flags = 0x%.8X, attrs = 0x%.8X",
+         flags,attributes);
      
      // unless the (expert) caller has already done so, create a sub-bootstrap and set it
      // note that this is inherently thread-unfriendly; we can't do anything about that
***************
*** 182,193 ****
      Bootstrap bootstrap;
      if (!(flags & sessionKeepCurrentBootstrap)) {
  		TaskPort self;
  		bootstrap = bootstrap.subset(TaskPort());
  		self.bootstrap(bootstrap);
      }
      
      // now call the SecurityServer and tell it to initialize the (new) session
      server().setupSession(flags, attributes);
! 	
!     END_API(CSSM)
  }
--- 202,231 ----
      Bootstrap bootstrap;
      if (!(flags & sessionKeepCurrentBootstrap)) {
  		TaskPort self;
+ 		syslog(7,"SessionCreate(), before bootstrap.subset(TaskPort())");
  		bootstrap = bootstrap.subset(TaskPort());
  		self.bootstrap(bootstrap);
+ 		syslog(7,"SessionCreate(), after self.bootstrap(bootstrap)");
      }
      
      // now call the SecurityServer and tell it to initialize the (new) session
      server().setupSession(flags, attributes);
!     syslog(7,"SessionCreate(), succeeded");
! 
!     //END_API(CSSM)
!     }
!     catch (const CssmCommonError &err) {
!         syslog(7,"SessionCreate(), CssmCommonError error is 0x%.8X",
!             err.cssmError(CSSM_CSSM_BASE_ERROR));
!         return err.cssmError(CSSM_CSSM_BASE_ERROR);
!     }
!     catch (const std::bad_alloc &) {
!         syslog(7,"SessionCreate(), memory error");
!         return CssmError::merge(CSSM_ERRCODE_MEMORY_ERROR, CSSM_CSSM_BASE_ERROR);
!     }
!     catch (...) {
!         syslog(7,"SessionCreate(), unknown error");
!         return CssmError::merge(CSSM_ERRCODE_INTERNAL_ERROR, CSSM_CSSM_BASE_ERROR);
!     }
!     return CSSM_OK;
  }
diff -c -r src.old/SecurityServer/connection.h src/SecurityServer/connection.h
*** src.old/SecurityServer/connection.h	Sat Nov  9 14:58:25 2002
--- src/SecurityServer/connection.h	Sat Nov  9 14:58:18 2002
***************
*** 48,53 ****
--- 48,54 ----
  	virtual ~Connection();
  	void terminate();		// normal termination
  	bool abort(bool keepReplyPort = false); // abnormal termination
+ 	bool safeToDelete() { return (state == idle); }
  	
      Port clientPort() const	{ return mClientPort; }
  
diff -c -r src.old/SecurityServer/main.cpp src/SecurityServer/main.cpp
*** src.old/SecurityServer/main.cpp	Sat Nov  9 14:58:26 2002
--- src/SecurityServer/main.cpp	Sat Nov  9 14:58:18 2002
***************
*** 124,130 ****
  		Syslog::open(argv[0], LOG_AUTHPRIV, LOG_PERROR);
  		Syslog::notice("SecurityServer started in debug mode");
  	} else {
! 		Syslog::open(argv[0], LOG_AUTHPRIV, LOG_CONS);
  	}
      
      // if we're not running as root in production mode, fail
--- 124,131 ----
  		Syslog::open(argv[0], LOG_AUTHPRIV, LOG_PERROR);
  		Syslog::notice("SecurityServer started in debug mode");
  	} else {
! 		//Syslog::open(argv[0], LOG_AUTHPRIV, LOG_CONS);
! 		Syslog::open(argv[0], LOG_AUTH, LOG_CONS);	// For debugging only
  	}
      
      // if we're not running as root in production mode, fail
diff -c -r src.old/SecurityServer/process.h src/SecurityServer/process.h
*** src.old/SecurityServer/process.h	Sat Nov  9 14:58:26 2002
--- src/SecurityServer/process.h	Sat Nov  9 14:58:18 2002
***************
*** 63,68 ****
--- 63,69 ----
  	void beginConnection(Connection &);
  	bool endConnection(Connection &);
  	bool kill();
+ 	bool safeToDelete() { return (mBusyCount == 0); }
      
      void addDatabase(Database *database);
      void removeDatabase(Database *database);
diff -c -r src.old/SecurityServer/server.cpp src/SecurityServer/server.cpp
*** src.old/SecurityServer/server.cpp	Sat Nov  9 14:58:26 2002
--- src/SecurityServer/server.cpp	Sat Nov  9 14:58:18 2002
***************
*** 177,191 ****
--- 177,209 ----
  //
  // Synchronously end a Connection.
  // This is due to a request from the client, so no thread races are possible.
+ // (Still, only end the connection (and delete its object) if it's safe to do
+ // so.  And if it's safe to delete its associated process (and the process's
+ // associated session), do that, too.  This makes it possible for the client
+ // to later make another connection and call SessionCreate() without getting
+ // an error because the previous session still exists.)
  //
  void Server::endConnection(Port replyPort)
  {
  	StLock<Mutex> _(lock);
+ 	syslog(7,"Server::endConnection(), entering");
  	Connection *connection = connections[replyPort];
  	assert(connection);
+ 	if (!connection->safeToDelete())
+ 		return;
  	connections.erase(replyPort);
+ 	syslog(7,"Server::endConnection(), before connection->terminate()");
  	connection->terminate();
+ 	Process *process = &connection->process;
+ 	syslog(7,"Server::endConnection(), before delete connection");
  	delete connection;
+ 	assert(process);
+ 	if (!process->safeToDelete())
+ 		return;
+ 	processes.erase(replyPort);
+ 	syslog(7,"Server::endConnection(), before delete process");
+ 	delete process;
+ 	syslog(7,"Server::endConnection(), done");
  }
  
  
diff -c -r src.old/SecurityServer/ssclient.cpp src/SecurityServer/ssclient.cpp
*** src.old/SecurityServer/ssclient.cpp	Sat Nov  9 14:58:26 2002
--- src/SecurityServer/ssclient.cpp	Sat Nov  9 14:58:19 2002
***************
*** 37,49 ****
  //
  ModuleNexus<ClientSession::Global> ClientSession::mGlobal;
  bool ClientSession::mSetupSession;
  
  
  //
  // Construct a client session
  //
  ClientSession::ClientSession(CssmAllocator &std, CssmAllocator &rtn)
! : internalAllocator(std), returnAllocator(rtn)
  { }
  
  
--- 37,50 ----
  //
  ModuleNexus<ClientSession::Global> ClientSession::mGlobal;
  bool ClientSession::mSetupSession;
+ bool ClientSession::mTeardownBeforeSessionSetup;
  
  
  //
  // Construct a client session
  //
  ClientSession::ClientSession(CssmAllocator &std, CssmAllocator &rtn)
! : internalAllocator(std), returnAllocator(rtn), mProcessId(NULL)
  { }
  
  
***************
*** 60,71 ****
  //
  void ClientSession::activate()
  {
! 	Global &global = mGlobal();
      Thread &thread = global.thread();
      if (!thread) {
  		// first time for this thread - use abbreviated registration
  		IPCN(ucsp_client_setup(UCSP_ARGS, mach_task_self(), ""));
          thread.registered = true;
          global.serverPort.requestNotify(thread.replyPort, MACH_NOTIFY_DEAD_NAME, true);
          debug("SSclnt", "Thread registered with SecurityServer");
  	}
--- 61,88 ----
  //
  void ClientSession::activate()
  {
!     pid_t currentProcessId = getpid();
!     // If the process id has changed (for example because we are a child
!     // process spawned by fork() or exec()) and we inherited a connection from
!     // our parent, the server and reply ports in mGlobal will be invalid and
!     // the connection we inherited will no longer work.  So clean out mGlobal
!     // to make its constructor (mGlobal(), whose code is in ClientSession::
!     // Global::Global() below) reinitialize it and give us a new connection
!     // and new ports.  But don't do this if mGlobal.reset() has already been
!     // called in ClientSession::setupSession().
!     if (!mSetupSession && mProcessId && (mProcessId!=currentProcessId)) {
!         syslog(7,"SSclnt, pid was 0x%.8X, is now 0x%.8X, so calling mGlobal.reset()",
!             mProcessId, currentProcessId);
!         mGlobal.reset();
!     }
!     mProcessId = currentProcessId;
!     Global &global = mGlobal();
      Thread &thread = global.thread();
      if (!thread) {
  		// first time for this thread - use abbreviated registration
  		IPCN(ucsp_client_setup(UCSP_ARGS, mach_task_self(), ""));
          thread.registered = true;
+ 		mTeardownBeforeSessionSetup = true;
          global.serverPort.requestNotify(thread.replyPort, MACH_NOTIFY_DEAD_NAME, true);
          debug("SSclnt", "Thread registered with SecurityServer");
  	}
***************
*** 85,90 ****
--- 102,108 ----
  	Bootstrap myBootstrap;
      serverPort = myBootstrap.lookup("SecurityServer");
  	debug("SSclnt", "contacting SecurityServer at port %d", serverPort.port());
+ 	syslog(7,"SSclnt, contacting SecurityServer at port %d", serverPort.port());
      
      // send identification/setup message
      string extForm;
***************
*** 98,117 ****
      }
      // cannot use UCSP_ARGS here because it uses mGlobal() -> deadlock
      Thread &thread = this->thread();
! 	
  	if (mSetupSession) {
  		debug("SSclnt", "sending session setup request");
  		mSetupSession = false;
  		IPCN(ucsp_client_setupNew(serverPort, thread.replyPort, &rcode,
  			mach_task_self(), extForm.c_str(), &serverPort.port()));
  		debug("SSclnt", "new session server port is %d", serverPort.port());
  	} else {	
  		IPCN(ucsp_client_setup(serverPort, thread.replyPort, &rcode,
  			mach_task_self(), extForm.c_str()));
  	}
      thread.registered = true;	// as a side-effect of setup call above
  	serverPort.requestNotify(thread.replyPort, MACH_NOTIFY_DEAD_NAME, true);
  	debug("SSclnt", "contact with SecurityServer established");
  }
  
  
--- 116,138 ----
      }
      // cannot use UCSP_ARGS here because it uses mGlobal() -> deadlock
      Thread &thread = this->thread();
! 
  	if (mSetupSession) {
  		debug("SSclnt", "sending session setup request");
  		mSetupSession = false;
  		IPCN(ucsp_client_setupNew(serverPort, thread.replyPort, &rcode,
  			mach_task_self(), extForm.c_str(), &serverPort.port()));
  		debug("SSclnt", "new session server port is %d", serverPort.port());
+ 		syslog(7,"SSclnt, new session server port is %d", serverPort.port());
  	} else {	
  		IPCN(ucsp_client_setup(serverPort, thread.replyPort, &rcode,
  			mach_task_self(), extForm.c_str()));
  	}
      thread.registered = true;	// as a side-effect of setup call above
+ 	mTeardownBeforeSessionSetup = true;
  	serverPort.requestNotify(thread.replyPort, MACH_NOTIFY_DEAD_NAME, true);
  	debug("SSclnt", "contact with SecurityServer established");
+ 	syslog(7,"SSclnt, contact with SecurityServer established");
  }
  
  
diff -c -r src.old/SecurityServer/ssclient.h src/SecurityServer/ssclient.h
*** src.old/SecurityServer/ssclient.h	Sat Nov  9 14:58:26 2002
--- src/SecurityServer/ssclient.h	Sat Nov  9 14:58:19 2002
***************
*** 302,307 ****
--- 302,309 ----
  
  	static ModuleNexus<Global> mGlobal;
  	static bool mSetupSession;
+ 	static bool mTeardownBeforeSessionSetup;
+ 	pid_t mProcessId;
  };
  
  
diff -c -r src.old/SecurityServer/sstransit.cpp src/SecurityServer/sstransit.cpp
*** src.old/SecurityServer/sstransit.cpp	Sat Nov  9 14:58:27 2002
--- src/SecurityServer/sstransit.cpp	Sat Nov  9 14:58:19 2002
***************
*** 586,591 ****
--- 586,599 ----
  
  void ClientSession::setupSession(SessionCreationFlags flags, SessionAttributeBits attrs)
  {
+ 	// If a connection already exists, so does a session (it may be the root
+ 	// session).  In this case we need to tear down the existing connection
+ 	// (and session) before we can create a new one.
+ 	if (mTeardownBeforeSessionSetup) {
+ 		syslog(7,"ClientSession::setupSession(), before ucsp_client_teardown()");
+ 		IPC(ucsp_client_teardown(UCSP_ARGS));
+ 		syslog(7,"ClientSession::setupSession(), after ucsp_client_teardown()");
+ 	}
  	mSetupSession = true;		// global flag to Global constructor
  	mGlobal.reset();			// kill existing cache, all threads
  	IPC(ucsp_client_setupSession(UCSP_ARGS, flags, attrs));
diff -c -r src.old/cdsa/cdsa-utilities/mach++.cpp src/cdsa/cdsa-utilities/mach++.cpp
*** src.old/cdsa/cdsa-utilities/mach++.cpp	Sat Nov  9 14:58:21 2002
--- src/cdsa/cdsa-utilities/mach++.cpp	Sat Nov  9 14:58:14 2002
***************
*** 45,52 ****
  	case MIG_SERVER_DIED:
  		return CSSM_ERRCODE_SERVICE_NOT_AVAILABLE;
  	default: 
! 		return CSSM_ERRCODE_INTERNAL_ERROR;
! 	}
  }
  
  OSStatus
--- 45,52 ----
  	case MIG_SERVER_DIED:
  		return CSSM_ERRCODE_SERVICE_NOT_AVAILABLE;
  	default: 
! 		return error;	// Don't return CSSM_ERRCODE_INTERNAL_ERROR here --
! 	}					// that breaks all IPC error reporting!
  }
  
  OSStatus
diff -c -r src.old/cdsa/cdsa-utilities/threading.cpp src/cdsa/cdsa-utilities/threading.cpp
*** src.old/cdsa/cdsa-utilities/threading.cpp	Sat Nov  9 14:58:21 2002
--- src/cdsa/cdsa-utilities/threading.cpp	Sat Nov  9 14:58:14 2002
***************
*** 40,45 ****
--- 40,52 ----
  {
      if (int err = pthread_key_create(&mKey, destructor))
          UnixError::throwMe(err);
+     // If we are a child process spawned by fork() or exec(), the thread-local
+     // storage pointed to by the key we just created may already contain a
+     // non-NULL value -- one set by a thread in our parent process before it
+     // called fork() or exec()!  So we need to initialize our thread-local
+     // storage.
+     if (int err = pthread_setspecific(mKey, NULL))
+         UnixError::throwMe(err);
  }
  
  ThreadStoreSlot::~ThreadStoreSlot()
-------------- next part --------------
diff -c -r -N src.old/AuthSession.h src/AuthSession.h
*** src.old/AuthSession.h	Wed Dec 31 18:00:00 1969
--- src/AuthSession.h	Sat Nov  9 20:52:58 2002
***************
*** 0 ****
--- 1,171 ----
+ /*
+  * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
+  * 
+  * The contents of this file constitute Original Code as defined in and are
+  * subject to the Apple Public Source License Version 1.2 (the 'License').
+  * You may not use this file except in compliance with the License. Please obtain
+  * a copy of the License at http://www.apple.com/publicsource and read it before
+  * using this file.
+  * 
+  * This Original Code and all software distributed under the License are
+  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
+  * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
+  * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+  * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
+  * specific language governing rights and limitations under the License.
+  */
+ 
+ 
+ /*
+  *  AuthSession.h
+  *  AuthSession - APIs for managing login, authorization, and security Sessions.
+  */
+ #if !defined(__AuthSession__)
+ #define __AuthSession__ 1
+ 
+ #include <Security/Authorization.h>
+ 
+ #if defined(__cplusplus)
+ extern "C" {
+ #endif
+ 
+ 
+ /*!
+ 	@header AuthSession
+ 
+ 	The Session API provides specialized applications access to Session management and inquiry
+     functions. This is a specialized API that should not be of interest to most people.
+     
+     If you do not know what "Session" means in the context of MacOS Authorization and security,
+     please check with your documentation and come back when you have figured it out - we won't
+     explain it here.
+     
+     This API is tentative, preliminary, incomplete, internal, and subject to change.
+     You have been warned.
+ */
+ 
+ 
+ /*!
+ 	@typedef SecuritySessionId
+ 	These are externally visible identifiers for authorization sessions.
+         Different sessions have different identifiers; beyond that, you can't
+         tell anything from these values.
+     SessionIds can be compared for equality as you'd expect, but you should be careful
+         to use attribute bits wherever appropriate. For example, don't rely on there being
+         "the" graphical login session - some day, we may have more than one...
+ */
+ typedef UInt32 SecuritySessionId;
+ 
+ 
+ /*!
+     @enum SecuritySessionId
+     Here are some special values for SecuritySessionId. You may specify those
+         on input to SessionAPI functions. They will never be returned from such
+         functions.
+ */
+ enum {
+     noSecuritySession                      = 0,     /* definitely not a valid SecuritySessionId */
+     callerSecuritySession                  = -1     /* the Session I (the caller) am in */
+ };
+ 
+ 
+ /*!
+     @enum SessionAttributeBits
+     Each Session has a set of attribute bits. You can get those from the
+         SessionGetInfo API function.
+  */
+ typedef UInt32 SessionAttributeBits;
+  
+ enum {
+     sessionIsRoot                          = 0x0001, /* is the root session (startup/system programs) */
+     sessionHasGraphicAccess                = 0x0010, /* graphic subsystem (CoreGraphics et al) available */
+     sessionHasTTY                          = 0x0020, /* /dev/tty is available */
+     sessionIsRemote                        = 0x1000, /* session was established over the network */
+ 
+     sessionWasInitialized                  = 0x8000  /* session has been set up by its leader */
+ };
+ 
+ 
+ /*!
+     @enum SessionCreationFlags
+     These flags control how a new session is created by SessionCreate.
+         They have no permanent meaning beyond that.
+  */
+ typedef UInt32 SessionCreationFlags;
+  
+ enum {
+     sessionKeepCurrentBootstrap             = 0x8000 /* caller has allocated sub-bootstrap (expert use only) */
+ };
+  
+  
+ /*!
+ 	@enum SessionStatus
+ 	Error codes returned by AuthSession API.
+     Note that the AuthSession APIs can also return Authorization API error codes.
+ */
+ enum {
+     errSessionSuccess                       = 0,      /* all is well */
+     errSessionInvalidId                     = -60500, /* invalid session id specified */
+     errSessionInvalidAttributes             = -60501, /* invalid set of requested attribute bits */
+     errSessionAuthorizationDenied           = -60502, /* you are not allowed to do this */
+ 
+     errSessionInternal                      = errAuthorizationInternal,	/* internal error */
+ 	errSessionInvalidFlags                  = errAuthorizationInvalidFlags /* invalid flags/options */
+ };
+ 
+ 
+ /*!
+     @function SessionGetInfo
+     Obtain information about a session.
+ 
+     @param session (input) The Session you are asking about. Can be one of the
+         special constants defined above.
+ 	
+ 	@param sessionId (output/optional) The actual SecuritySessionId for the session you asked about.
+         Will never be one of those constants.
+         
+     @param attributes (output/optional) Receives the attribute bits for the session.
+ 
+     @result An OSStatus indicating success (noErr) or an error cause.
+     
+     errSessionInvalidId -60500 Invalid session id specified
+ 
+ */
+ OSStatus SessionGetInfo(SecuritySessionId session,
+     SecuritySessionId *sessionId,
+     SessionAttributeBits *attributes);
+     
+ 
+ /*!
+     @function SessionCreate
+     This (very specialized) function creates and/or initializes a security session.
+         It always sets up the session that the calling process belongs to - you cannot
+         create a session for someone else.
+     By default, a new bootstrap subset port is created for the calling process. The process
+         acquires this new port as its bootstrap port, which all its children will inherit.
+         If you happen to have created the subset port on your own, you can pass the
+         sessionKeepCurrentBootstrap flag, and SessionCreate will use it. Note however that
+         you cannot supersede a prior SessionCreate call that way; only a single SessionCreate
+         call is allowed for each Session (however made).
+     
+     @param flags Flags controlling how the session is created.
+     
+     @param attributes The set of attribute bits to set for the new session.
+         Not all bits can be set this way.
+     
+     @result An OSStatus indicating success (noErr) or an error cause.
+     
+     errSessionInvalidAttributes -60501 Attempt to set invalid attribute bits	
+     errSessionAuthorizationDenied -60502 Attempt to re-initialize a session
+     errSessionInvalidFlags -60011 Attempt to specify unsupported flag bits
+     
+ */
+ OSStatus SessionCreate(SessionCreationFlags flags,
+     SessionAttributeBits attributes);
+     
+ 
+ #if defined(__cplusplus)
+ }
+ #endif
+ 
+ #endif /* ! __AuthSession__ */
diff -c -r -N src.old/acconfig.h src/acconfig.h
*** src.old/acconfig.h	Sat Nov  9 20:53:01 2002
--- src/acconfig.h	Sat Nov  9 20:52:57 2002
***************
*** 301,306 ****
--- 301,321 ----
  /* Use IPv4 for connection by default, IPv6 can still if explicity asked */
  #undef IPV4_DEFAULT
  
+ /* Don't use krb5_init_ets() -- it's not present (MIT only) */
+ #undef DONT_KRB5_INIT_ETS
+ 
+ /* Our Kerberos 5 credentials cache uses the Ccache API (MIT only) */
+ #undef HAVE_API_CCACHE
+ 
+ /* OS X workaround */
+ #undef HAVE_SECURITYSERVER
+ 
+ /* OS X workaround */
+ #undef _POSIX_SAVED_IDS
+ 
+ /* OS X workaround */
+ #undef HAVE_ONLY_MKSTEMP
+ 
  /* getaddrinfo is broken (if present) */
  #undef BROKEN_GETADDRINFO
  
diff -c -r -N src.old/auth-krb5.c src/auth-krb5.c
*** src.old/auth-krb5.c	Sat Nov  9 20:53:02 2002
--- src/auth-krb5.c	Sat Nov  9 20:52:58 2002
***************
*** 42,50 ****
--- 42,55 ----
  #ifdef KRB5
  #include <krb5.h>
  #ifndef HEIMDAL
+ #include <com_err.h>
  #define krb5_get_err_text(context,code) error_message(code)
  #endif /* !HEIMDAL */
  
+ #if defined(HAVE_API_CCACHE)
+ #include "ssh-gss.h"
+ #endif
+ 
  extern ServerOptions	 options;
  
  static int
***************
*** 185,196 ****
  
  #ifdef HEIMDAL
  	problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, &ccache);
! #else
  {
  	char ccname[40];
  	int tmpfd;
! 	
! 	snprintf(ccname,sizeof(ccname),"FILE:/tmp/krb5cc_%d_XXXXXX",geteuid());
  	
  	if ((tmpfd = mkstemp(ccname+strlen("FILE:")))==-1) {
  		log("mkstemp(): %.100s", strerror(errno));
--- 190,201 ----
  
  #ifdef HEIMDAL
  	problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, &ccache);
! #elif !defined(HAVE_API_CCACHE)
  {
  	char ccname[40];
  	int tmpfd;
! 
! 	snprintf(ccname,sizeof(ccname)-1,"FILE:/tmp/krb5cc_%d_XXXXXX",geteuid());
  	
  	if ((tmpfd = mkstemp(ccname+strlen("FILE:")))==-1) {
  		log("mkstemp(): %.100s", strerror(errno));
***************
*** 207,212 ****
--- 212,218 ----
  	problem = krb5_cc_resolve(authctxt->krb5_ctx, ccname, &ccache);
  }
  #endif
+ #if !defined(HAVE_API_CCACHE)
  	if (problem)
  		goto fail;
  
***************
*** 214,219 ****
--- 220,226 ----
  	    authctxt->krb5_user);
  	if (problem)
  		goto fail;
+ #endif
  
  #ifdef HEIMDAL
  	problem = krb5_rd_cred2(authctxt->krb5_ctx, authctxt->krb5_auth_ctx,
***************
*** 225,239 ****
--- 232,262 ----
  	    tgt, &creds, NULL);
  	if (problem)
  		goto fail;
+ #if defined(HAVE_API_CCACHE)
+ 	memcpy(&gssapi_client_krb5_creds,*creds,sizeof(krb5_creds));
+ 	problem = krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user,
+ 	    (char **)(&gssapi_client_name.value));
+ 	if (problem)
+ 		goto fail;
+ 	gssapi_client_name.length = strlen(gssapi_client_name.value);
+ 	snprintf(gssapi_client_krb5_ccname,sizeof(gssapi_client_krb5_ccname)-1,
+ 		"Credentials from passed TGT");
+ 	//strncpy(gssapi_client_krb5_ccname,API_CCACHE_DFLT_NAME,
+ 	//	sizeof(gssapi_client_krb5_ccname)-1);
+ 	gssapi_client_type = GSS_KERBEROS;
+ #else
  	problem = krb5_cc_store_cred(authctxt->krb5_ctx, ccache, *creds);
  	if (problem)
  		goto fail;
  #endif
+ #endif
  
+ #if !defined(HAVE_API_CCACHE)
  	authctxt->krb5_fwd_ccache = ccache;
  	ccache = NULL;
  
  	authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
+ #endif
  
  	problem = krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user,
  	    &pname);
***************
*** 264,271 ****
--- 287,296 ----
  #ifndef HEIMDAL
  	krb5_creds creds;
  	krb5_principal server;
+ #if !defined(HAVE_API_CCACHE)
  	char ccname[40];
  	int tmpfd;
+ #endif
  #endif	
  	krb5_error_code problem;
  
***************
*** 284,290 ****
  		goto out;
  
  #ifdef HEIMDAL
! 	problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops,
  	    &authctxt->krb5_fwd_ccache);
  	if (problem)
  		goto out;
--- 309,315 ----
  		goto out;
  
  #ifdef HEIMDAL
! 	problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops,
  	    &authctxt->krb5_fwd_ccache);
  	if (problem)
  		goto out;
***************
*** 297,302 ****
--- 322,335 ----
  	restore_uid();
  	problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user,
  	    authctxt->krb5_fwd_ccache, password, 1, NULL);
+ 	if (!problem) {
+ 		authctxt->krb5_ticket_file = (char *) krb5_cc_get_name(authctxt->krb5_ctx,
+ 			authctxt->krb5_fwd_ccache);
+ 		/* krb5_verify_user() changes the ownership of authctxt->
+ 		   krb5_fwd_ccache, so we need to change it back */
+ 		problem = chown(authctxt->krb5_ticket_file,
+ 			authctxt->pw->pw_uid,authctxt->pw->pw_gid);
+ 	}
  	temporarily_use_uid(authctxt->pw);
  
  	if (problem)
***************
*** 327,333 ****
  		goto out;
  	} 
  
! 	snprintf(ccname,sizeof(ccname),"FILE:/tmp/krb5cc_%d_XXXXXX",geteuid());
  	
  	if ((tmpfd = mkstemp(ccname+strlen("FILE:")))==-1) {
  		log("mkstemp(): %.100s", strerror(errno));
--- 360,379 ----
  		goto out;
  	} 
  
! #if defined(HAVE_API_CCACHE)
! 	memcpy(&gssapi_client_krb5_creds,&creds,sizeof(krb5_creds));
! 	problem = krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user,
! 	    (char **)(&gssapi_client_name.value));
! 	if (problem)
! 		goto out;
! 	gssapi_client_name.length = strlen(gssapi_client_name.value);
! 	snprintf(gssapi_client_krb5_ccname,sizeof(gssapi_client_krb5_ccname)-1,
! 		"Credentials from password");
! 	//strncpy(gssapi_client_krb5_ccname,API_CCACHE_DFLT_NAME,
! 	//	sizeof(gssapi_client_krb5_ccname)-1);
! 	gssapi_client_type = GSS_KERBEROS;
! #else
! 	snprintf(ccname,sizeof(ccname)-1,"FILE:/tmp/krb5cc_%d_XXXXXX",geteuid());
  	
  	if ((tmpfd = mkstemp(ccname+strlen("FILE:")))==-1) {
  		log("mkstemp(): %.100s", strerror(errno));
***************
*** 356,364 ****
  				 &creds);
  	if (problem)
  		goto out;
- #endif		
  
  	authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
  
   out:
  	restore_uid();
--- 402,412 ----
  				 &creds);
  	if (problem)
  		goto out;
  
  	authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
+ #endif	/* #if defined(HAVE_API_CCACHE) */
+ 
+ #endif	/* #ifdef HEIMDAL */
  
   out:
  	restore_uid();
diff -c -r -N src.old/configure.ac src/configure.ac
*** src.old/configure.ac	Sat Nov  9 20:53:02 2002
--- src/configure.ac	Sat Nov  9 20:52:58 2002
***************
*** 93,99 ****
  	AC_DEFINE(IP_TOS_IS_BROKEN)
  	;;
  *-*-darwin*)
! 	AC_DEFINE(BROKEN_GETADDRINFO)
  	;;
  *-*-hpux10.26)
  	if test -z "$GCC"; then
--- 93,105 ----
  	AC_DEFINE(IP_TOS_IS_BROKEN)
  	;;
  *-*-darwin*)
! 	LDFLAGS="$LDFLAGS -framework Security -bind_at_load"
! 	AC_DEFINE(HAVE_SETLOGIN)
! 	AC_DEFINE(DONT_KRB5_INIT_ETS)	# MIT only
! 	AC_DEFINE(HAVE_API_CCACHE)		# MIT only
! 	AC_DEFINE(HAVE_SECURITYSERVER)
! 	AC_DEFINE(_POSIX_SAVED_IDS)
! 	AC_DEFINE(HAVE_ONLY_MKSTEMP)
  	;;
  *-*-hpux10.26)
  	if test -z "$GCC"; then
***************
*** 1751,1758 ****
                          else
                                  KRB5ROOT=${withval}
                          fi
! 			CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include"
!                         LDFLAGS="$LDFLAGS -L${KRB5ROOT}/lib"
                          AC_DEFINE(KRB5)
  			KRB5_MSG="yes"
                          AC_MSG_CHECKING(whether we are using Heimdal)
--- 1757,1764 ----
                          else
                                  KRB5ROOT=${withval}
                          fi
! 			CPPFLAGS="-I${KRB5ROOT}/include $CPPFLAGS"
!                         LDFLAGS="-L${KRB5ROOT}/lib $LDFLAGS"
                          AC_DEFINE(KRB5)
  			KRB5_MSG="yes"
                          AC_MSG_CHECKING(whether we are using Heimdal)
***************
*** 1760,1776 ****
                                         [ char *tmp = heimdal_version; ],
                                         [ AC_MSG_RESULT(yes)
                                           AC_DEFINE(HEIMDAL)
!                                          K5LIBS="-lkrb5 -ldes -lcom_err -lasn1 -lroken"
                                         ],
                                         [ AC_MSG_RESULT(no)
                                           K5LIBS="-lkrb5 -lk5crypto -lcom_err"
                                         ]
                          )
                          if test ! -z "$need_dash_r" ; then
!                                 LDFLAGS="$LDFLAGS -R${KRB5ROOT}/lib"
                          fi
                          if test ! -z "$blibpath" ; then
!                                 blibpath="$blibpath:${KRB5ROOT}/lib"
                          fi
                          AC_CHECK_LIB(resolv, dn_expand, , )
  
--- 1766,1782 ----
                                         [ char *tmp = heimdal_version; ],
                                         [ AC_MSG_RESULT(yes)
                                           AC_DEFINE(HEIMDAL)
!                                          K5LIBS="${KRB5ROOT}/lib/libkrb5.a ${KRB5ROOT}/lib/libcom_err.a -lasn1 -lroken"
                                         ],
                                         [ AC_MSG_RESULT(no)
                                           K5LIBS="-lkrb5 -lk5crypto -lcom_err"
                                         ]
                          )
                          if test ! -z "$need_dash_r" ; then
!                                 LDFLAGS="-R${KRB5ROOT}/lib $LDFLAGS"
                          fi
                          if test ! -z "$blibpath" ; then
!                                 blibpath="${KRB5ROOT}/lib:$blibpath"
                          fi
                          AC_CHECK_LIB(resolv, dn_expand, , )
  
***************
*** 1787,1793 ****
  			
  			AC_CHECK_HEADER(gssapi.h, ,
  				[ unset ac_cv_header_gssapi_h
! 				  CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include/gssapi" 
  				  AC_CHECK_HEADERS(gssapi.h, ,
  					AC_MSG_WARN([Cannot find any suitable gss-api header - build may fail])
  				  ) 
--- 1793,1799 ----
  			
  			AC_CHECK_HEADER(gssapi.h, ,
  				[ unset ac_cv_header_gssapi_h
! 				  CPPFLAGS="-I${KRB5ROOT}/include/gssapi $CPPFLAGS"
  				  AC_CHECK_HEADERS(gssapi.h, ,
  					AC_MSG_WARN([Cannot find any suitable gss-api header - build may fail])
  				  ) 
***************
*** 1795,1801 ****
  			)
  
  			oldCPP="$CPPFLAGS"
! 			CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include/gssapi"
  			AC_CHECK_HEADER(gssapi_krb5.h, ,
  					[ CPPFLAGS="$oldCPP" ])
  
--- 1801,1807 ----
  			)
  
  			oldCPP="$CPPFLAGS"
! 			CPPFLAGS="-I${KRB5ROOT}/include/gssapi $CPPFLAGS"
  			AC_CHECK_HEADER(gssapi_krb5.h, ,
  					[ CPPFLAGS="$oldCPP" ])
  
diff -c -r -N src.old/defines.h src/defines.h
*** src.old/defines.h	Sat Nov  9 20:53:02 2002
--- src/defines.h	Sat Nov  9 20:52:58 2002
***************
*** 3,8 ****
--- 3,12 ----
  
  /* $Id: defines.h,v 1.92 2002/06/24 16:26:49 stevesk Exp $ */
  
+ #if defined(HEIMDAL)
+ # undef DONT_KRB5_INIT_ETS
+ # undef HAVE_API_CCACHE
+ #endif
  
  /* Constants */
  
***************
*** 434,439 ****
--- 438,447 ----
  # define PAM_MSG_MEMBER(msg, n, member) ((*(msg))[(n)].member)
  #else
  # define PAM_MSG_MEMBER(msg, n, member) ((msg)[(n)]->member)
+ #endif
+ 
+ #if defined(DONT_KRB5_INIT_ETS)
+ # define krb5_init_ets(table)
  #endif
  
  #if defined(BROKEN_GETADDRINFO) && defined(HAVE_GETADDRINFO)
diff -c -r -N src.old/gss-genr.c src/gss-genr.c
*** src.old/gss-genr.c	Sat Nov  9 20:53:02 2002
--- src/gss-genr.c	Sat Nov  9 20:52:58 2002
***************
*** 49,54 ****
--- 49,58 ----
  gss_buffer_desc gssapi_client_name = {0,NULL}; /* Name of our client */
  gss_cred_id_t   gssapi_client_creds = GSS_C_NO_CREDENTIAL; /* Their credentials */
  enum ssh_gss_id gssapi_client_type = GSS_LAST_ENTRY;
+ #if defined(HAVE_API_CCACHE)
+ char			gssapi_client_krb5_ccname[40] = {0};
+ krb5_creds		gssapi_client_krb5_creds = {0};
+ #endif
  
  /* The mechanism name used in the list below is defined in the internet
   * draft as the Base 64 encoding of the MD5 hash of the ASN.1 DER encoding 
diff -c -r -N src.old/gss-serv.c src/gss-serv.c
*** src.old/gss-serv.c	Sat Nov  9 20:53:02 2002
--- src/gss-serv.c	Sat Nov  9 20:52:59 2002
***************
*** 58,64 ****
  	void *data;
  } ssh_gssapi_cred_cache;
  
! static struct ssh_gssapi_cred_cache gssapi_cred_store = {NULL,NULL,NULL};
  
  #ifdef KRB5
  
--- 58,64 ----
  	void *data;
  } ssh_gssapi_cred_cache;
  
! static struct ssh_gssapi_cred_cache gssapi_cred_store = {0};
  
  #ifdef KRB5
  
***************
*** 66,71 ****
--- 66,72 ----
  #include <krb5.h>
  #else
  #include <gssapi_krb5.h>
+ #include <com_err.h>
  #define krb5_get_err_text(context,code) error_message(code)
  #endif
  
***************
*** 138,158 ****
  	krb5_principal princ;
  	char ccname[35];
  	static char name[40];
  	int tmpfd;
  	OM_uint32 maj_status,min_status;
  
  
  	if (gssapi_client_creds==NULL) {
  		debug("No credentials stored"); 
  		return;
  	}
  		
! 	if (ssh_gssapi_krb5_init() == 0)
! 		return;
! 
  	if (options.gss_use_session_ccache) {
!         	snprintf(ccname,sizeof(ccname),"/tmp/krb5cc_%d_XXXXXX",geteuid());
!        
          	if ((tmpfd = mkstemp(ccname))==-1) {
                  	log("mkstemp(): %.100s", strerror(errno));
                  	return;
--- 139,210 ----
  	krb5_principal princ;
  	char ccname[35];
  	static char name[40];
+ #if defined(HAVE_API_CCACHE)
+ 	cc_context_t cc_context = NULL;
+ 	cc_ccache_t cc_cache = NULL;
+ 	cc_ccache_iterator_t ccacheIterator = NULL;
+ 	cc_string_t cc_name = NULL;
+ 	cc_int32 cc_err;
+ #else
  	int tmpfd;
+ #endif
  	OM_uint32 maj_status,min_status;
  
+ 	if (ssh_gssapi_krb5_init() == 0)
+ 		return;
  
+ #if defined(HAVE_API_CCACHE)
+ 	cc_err = cc_initialize(&cc_context, ccapi_version_4, NULL, NULL);
+ 	if (cc_err != ccNoError) {
+ 		log("cc_initialize returned error = %d", cc_err);
+ 		return;
+ 	}
+ 	cc_err = cc_context_new_ccache_iterator(cc_context, &ccacheIterator);
+ 	if (cc_err != ccNoError) {
+ 		log("cc_ccache_new_ccache_iterator returned error = %d", cc_err);
+ 		return;
+ 	}
+ 	for (;;) {
+ 		cc_err = cc_ccache_iterator_next(ccacheIterator, &cc_cache);
+ 		if ((cc_err != ccNoError) && (cc_err != ccIteratorEnd)) {
+ 			log("cc_ccache_iterator_next returned error = %d", cc_err);
+ 			return;
+ 		} else if (cc_err == ccIteratorEnd) {
+ 			break;
+ 		}
+ 		cc_err = cc_ccache_get_name(cc_cache, &cc_name);
+ 		if (cc_err == ccNoError) {
+ 			log("destroying previous credentials cache in \"%s\"", cc_name->data);
+ 		}
+ 		cc_string_release(cc_name);
+ 		cc_err = cc_ccache_destroy(cc_cache);
+ 		if (cc_err != ccNoError) {
+ 			log("cc_ccache_destroy returned error = %d", cc_err);
+ 			return;
+ 		}
+ 	}
+ 	cc_ccache_iterator_release(ccacheIterator);
+ 	cc_context_release(cc_context);
+ #endif
+ 
+ #if defined(HAVE_API_CCACHE) && !defined(HEIMDAL)
+ 	if ((gssapi_client_creds==NULL)&&(gssapi_client_krb5_creds.client==NULL)) {
+ #else
  	if (gssapi_client_creds==NULL) {
+ #endif
  		debug("No credentials stored"); 
  		return;
  	}
  		
! #if defined(HAVE_API_CCACHE) && !defined(HEIMDAL)
! 	if (gssapi_client_krb5_ccname[0] == 0) {
!        		snprintf(ccname,sizeof(ccname)-1,"Forwarded credentials");
! 			//strncpy(ccname,API_CCACHE_DFLT_NAME,sizeof(ccname)-1);
! 		}
! 		else strncpy(ccname,gssapi_client_krb5_ccname,sizeof(ccname)-1);
! #else
  	if (options.gss_use_session_ccache) {
!         	snprintf(ccname,sizeof(ccname)-1,"/tmp/krb5cc_%d_XXXXXX",geteuid());
          	if ((tmpfd = mkstemp(ccname))==-1) {
                  	log("mkstemp(): %.100s", strerror(errno));
                  	return;
***************
*** 163,184 ****
  	               	return;
  	        }
          } else {
!         	snprintf(ccname,sizeof(ccname),"/tmp/krb5cc_%d",geteuid());
          	tmpfd = open(ccname, O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
          	if (tmpfd == -1) {
          		log("open(): %.100s", strerror(errno));
          		return;
          	}
          }
  
!        	close(tmpfd);
!         snprintf(name, sizeof(name), "FILE:%s",ccname);
   
!         if ((problem = krb5_cc_resolve(krb_context, name, &ccache))) {
!                 log("krb5_cc_default(): %.100s", 
!                 	krb5_get_err_text(krb_context,problem));
!                 return;
!         }
  
  	if ((problem = krb5_parse_name(krb_context, gssapi_client_name.value, 
  				       &princ))) {
--- 215,262 ----
  	               	return;
  	        }
          } else {
!         	snprintf(ccname,sizeof(ccname)-1,"/tmp/krb5cc_%d",geteuid());
          	tmpfd = open(ccname, O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
          	if (tmpfd == -1) {
          		log("open(): %.100s", strerror(errno));
          		return;
          	}
          }
+ #endif
  
! #if defined(HAVE_API_CCACHE)
! 	cc_err = cc_initialize(&cc_context, ccapi_version_4, NULL, NULL);
! 	if (cc_err != ccNoError) {
! 		log("cc_initialize returned error = %d", cc_err);
! 		return;
! 	}
! 	cc_err = cc_context_create_ccache(cc_context, ccname, cc_credentials_v5,
! 		gssapi_client_name.value, &cc_cache);
! 	if (cc_err != ccNoError) {
! 		log("cc_context_create_ccache returned error = %d", cc_err);
! 		return;
! 	}
! 	cc_err = cc_ccache_set_default(cc_cache);
! 	if (cc_err != ccNoError) {
! 		log("cc_ccache_set_default returned error = %d", cc_err);
! 		return;
! 	}
! 	cc_context_release(cc_context);
! 	cc_ccache_release(cc_cache);
! #endif
! 
! #if defined(HAVE_API_CCACHE) && !defined(HEIMDAL)
!     snprintf(name, sizeof(name)-1, "API:%s", ccname);
! #else
!     close(tmpfd);
!     snprintf(name, sizeof(name)-1, "FILE:%s",ccname);
! #endif
   
!     if ((problem = krb5_cc_resolve(krb_context, name, &ccache))) {
!         log("krb5_cc_resolve(): %.100s", 
!        	    krb5_get_err_text(krb_context,problem));
!         return;
!     }
  
  	if ((problem = krb5_parse_name(krb_context, gssapi_client_name.value, 
  				       &princ))) {
***************
*** 208,213 ****
--- 286,292 ----
  		return;
  	}
  	#else
+ 	#ifndef HAVE_API_CCACHE
  	if ((maj_status = gss_krb5_copy_ccache(&min_status, 
  					       gssapi_client_creds, 
  					       ccache))) {
***************
*** 216,231 ****
  		krb5_cc_destroy(krb_context,ccache);
  		return;
  	}
  	#endif
  	
  	krb5_cc_close(krb_context,ccache);
  
- 
  #ifdef USE_PAM
  	do_pam_putenv("KRB5CCNAME",name);
  #endif
  
  	gssapi_cred_store.filename=strdup(ccname);
  	gssapi_cred_store.envvar="KRB5CCNAME";
  	gssapi_cred_store.envval=strdup(name);
  
--- 295,334 ----
  		krb5_cc_destroy(krb_context,ccache);
  		return;
  	}
+ 	#else
+ 	if (gssapi_client_creds != NULL) {
+ 		if ((maj_status = gss_krb5_copy_ccache(
+ 			&min_status,
+ 			gssapi_client_creds,
+ 			ccache)))
+ 		{
+ 			log("gss_krb5_copy_ccache() failed");
+ 			ssh_gssapi_error(maj_status,min_status);
+ 			krb5_cc_destroy(krb_context,ccache);
+ 			return;
+ 		}
+ 	} else if (gssapi_client_krb5_creds.client != NULL) {
+ 		if ((problem = krb5_cc_store_cred(krb_context, ccache,
+ 			&gssapi_client_krb5_creds)))
+ 		{
+ 		log("krb5_cc_store_cred(): %.100s", 
+ 			krb5_get_err_text(krb_context,problem));
+ 		krb5_cc_destroy(krb_context,ccache);
+ 		return;
+ 		}
+ 	}
+ 	#endif
  	#endif
  	
  	krb5_cc_close(krb_context,ccache);
  
  #ifdef USE_PAM
  	do_pam_putenv("KRB5CCNAME",name);
  #endif
  
+ #if !defined(HAVE_API_CCACHE)
  	gssapi_cred_store.filename=strdup(ccname);
+ #endif
  	gssapi_cred_store.envvar="KRB5CCNAME";
  	gssapi_cred_store.envval=strdup(name);
  
diff -c -r -N src.old/openbsd-compat/bsd-misc.h src/openbsd-compat/bsd-misc.h
*** src.old/openbsd-compat/bsd-misc.h	Sat Nov  9 20:53:00 2002
--- src/openbsd-compat/bsd-misc.h	Sat Nov  9 20:52:57 2002
***************
*** 29,34 ****
--- 29,39 ----
  
  #include "config.h"
  
+ /* Resolve name conflict with libroken */
+ #ifdef HEIMDAL
+ #define get_progname get_progname_x
+ #endif
+ 
  char *get_progname(char *argv0);
  
  #ifndef HAVE_SETSID
diff -c -r -N src.old/openbsd-compat/mktemp.h src/openbsd-compat/mktemp.h
*** src.old/openbsd-compat/mktemp.h	Sat Nov  9 20:53:01 2002
--- src/openbsd-compat/mktemp.h	Sat Nov  9 20:52:57 2002
***************
*** 5,10 ****
--- 5,15 ----
  
  #include "config.h"
  #ifndef HAVE_MKDTEMP
+ /* Resolve name conflict in OS X, which has mkstemp() but
+    not the other two. */
+ #if defined(HAVE_ONLY_MKSTEMP)
+ # define mkstemp mkstemp_x
+ #endif
  int mkstemps(char *path, int slen);
  int mkstemp(char *path);
  char *mkdtemp(char *path);
diff -c -r -N src.old/servconf.c src/servconf.c
*** src.old/servconf.c	Sat Nov  9 20:53:03 2002
--- src/servconf.c	Sat Nov  9 20:52:59 2002
***************
*** 16,28 ****
  #include <krb.h>
  #endif
  #if defined(KRB5)
- #ifdef HEIMDAL
- #include <krb.h>
- #else
  /* Bodge - but then, so is using the kerberos IV KEYFILE to get a Kerberos V
   * keytab */
  #define KEYFILE "/etc/krb5.keytab"
- #endif
  #endif
  #ifdef AFS
  #include <kafs.h>
--- 16,24 ----
diff -c -r -N src.old/session.c src/session.c
*** src.old/session.c	Sat Nov  9 20:53:03 2002
--- src/session.c	Sat Nov  9 20:52:59 2002
***************
*** 62,67 ****
--- 62,74 ----
  #include "ssh-gss.h"
  #endif
  
+ #if defined(HAVE_SECURITYSERVER)
+ #include <mach/mach.h>
+ #include <servers/bootstrap.h>
+ #include <mach/mach_error.h>
+ #include "AuthSession.h"
+ #endif
+ 
  #ifdef HAVE_CYGWIN
  #include <windows.h>
  #include <sys/cygwin.h>
***************
*** 464,470 ****
  
  	session_proctitle(s);
  
! #if defined(GSSAPI)
  	temporarily_use_uid(s->pw);
  	ssh_gssapi_storecreds();
  	restore_uid();
--- 471,477 ----
  
  	session_proctitle(s);
  
! #if defined(GSSAPI) && !defined(HAVE_API_CCACHE)
  	temporarily_use_uid(s->pw);
  	ssh_gssapi_storecreds();
  	restore_uid();
***************
*** 588,594 ****
  	ptyfd = s->ptyfd;
  	ttyfd = s->ttyfd;
  
! #if defined(GSSAPI)
  	temporarily_use_uid(s->pw);
  	ssh_gssapi_storecreds();
  	restore_uid();
--- 595,601 ----
  	ptyfd = s->ptyfd;
  	ttyfd = s->ttyfd;
  
! #if defined(GSSAPI) && !defined(HAVE_API_CCACHE)
  	temporarily_use_uid(s->pw);
  	ssh_gssapi_storecreds();
  	restore_uid();
***************
*** 1182,1188 ****
  void
  do_setusercontext(struct passwd *pw)
  {
! 	char tty='\0';
  
  #ifdef HAVE_CYGWIN
  	if (is_winnt) {
--- 1189,1195 ----
  void
  do_setusercontext(struct passwd *pw)
  {
! 	/*char tty='\0';*/
  
  #ifdef HAVE_CYGWIN
  	if (is_winnt) {
***************
*** 1308,1313 ****
--- 1315,1349 ----
  	shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
  #ifdef HAVE_LOGIN_CAP
  	shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);
+ #endif
+ 
+ #if defined(HAVE_SECURITYSERVER)
+ 	{
+ 	OSStatus err;
+ 	SecuritySessionId sec_session_id = 0;
+ 	SessionAttributeBits sec_session_attr = 0;
+ 	static char AuthSession = 0;
+ 	if (AuthSession == 0 ) {
+ 		err = SessionCreate(0,sessionHasTTY|sessionIsRemote);
+ 		if (err != 0) {
+ 			log("SessionCreate() failed with error %.8X",(unsigned)err);
+ 		} else {
+ 			log("SessionCreate() succeeded");
+ 			AuthSession = 1;
+ 		}
+ 	}
+ 	err = SessionGetInfo(callerSecuritySession,&sec_session_id,
+ 		&sec_session_attr);
+ 	log("SessionGetInfo() returned %.8X",(unsigned)err);
+ 	log("sec_session_id is %.8X",(unsigned)sec_session_id);
+ 	log("sec_session_attr is %.8X",(unsigned)sec_session_attr);
+ 	}
+ #endif
+ 
+ #if defined(GSSAPI) && defined(HAVE_API_CCACHE)
+ 	if (gssapi_client_type == GSS_LAST_ENTRY)
+ 		gssapi_client_type = GSS_KERBEROS;
+ 	ssh_gssapi_storecreds();
  #endif
  
  	env = do_setup_env(s, shell);
diff -c -r -N src.old/ssh-gss.h src/ssh-gss.h
*** src.old/ssh-gss.h	Sat Nov  9 20:53:03 2002
--- src/ssh-gss.h	Sat Nov  9 20:52:59 2002
***************
*** 34,39 ****
--- 34,43 ----
  
  #ifdef KRB5
  #ifndef HEIMDAL
+ #if defined(HAVE_API_CCACHE)
+ #include <krb5.h>
+ #include <Kerberos/CredentialsCache.h>
+ #endif
  #include <gssapi_generic.h>
  
  /* MIT Kerberos doesn't seem to define GSS_NT_HOSTBASED_SERVICE */
***************
*** 87,92 ****
--- 91,101 ----
  extern gss_buffer_desc gssapi_client_name;
  extern gss_cred_id_t   gssapi_client_creds;
  extern enum ssh_gss_id gssapi_client_type;
+ #if defined(HAVE_API_CCACHE)
+ extern char            gssapi_client_krb5_ccname[40];
+ extern krb5_creds      gssapi_client_krb5_creds;
+ #define API_CCACHE_DFLT_NAME "Initial default ccache"
+ #endif
  
  char *ssh_gssapi_mechanisms(int server, char *host);
  gss_OID ssh_gssapi_id_kex(Gssctxt *ctx, char *name);
-------------- next part --------------
*** opensslv.h.org	Sun Nov 10 13:40:48 2002
--- opensslv.h	Sun Nov 10 13:40:48 2002
***************
*** 25,32 ****
   * (Prior to 0.9.5a beta1, a different scheme was used: MMNNFFRBB for
   *  major minor fix final patch/beta)
   */
! #define OPENSSL_VERSION_NUMBER	0x0090602fL
! #define OPENSSL_VERSION_TEXT	"OpenSSL 0.9.6b 9 Jul 2001"
  #define OPENSSL_VERSION_PTEXT	" part of " OPENSSL_VERSION_TEXT
  
  
--- 25,32 ----
   * (Prior to 0.9.5a beta1, a different scheme was used: MMNNFFRBB for
   *  major minor fix final patch/beta)
   */
! #define OPENSSL_VERSION_NUMBER	0x0090605fL
! #define OPENSSL_VERSION_TEXT	"OpenSSL 0.9.6e 30 Jul 2002"
  #define OPENSSL_VERSION_PTEXT	" part of " OPENSSL_VERSION_TEXT
  
  
-------------- next part --------------
*** zconf.h.org	Sun Nov 10 13:41:59 2002
--- zconf.h	Sun Nov 10 13:41:59 2002
***************
*** 210,218 ****
  #   define FAR
  #endif
  
! #if !defined(MACOS) && !defined(TARGET_OS_MAC)
  typedef unsigned char  Byte;  /* 8 bits */
! #endif
  typedef unsigned int   uInt;  /* 16 bits or more */
  typedef unsigned long  uLong; /* 32 bits or more */
  
--- 210,218 ----
  #   define FAR
  #endif
  
! //#if !defined(MACOS) && !defined(TARGET_OS_MAC)
  typedef unsigned char  Byte;  /* 8 bits */
! //#endif
  typedef unsigned int   uInt;  /* 16 bits or more */
  typedef unsigned long  uLong; /* 32 bits or more */
  


More information about the krbdev mailing list