[OpenAFS-devel] Re: OpenSSH, OpenAFS, Heimdal Kerberos and MIT Kerberos
Douglas E. Engert
deengert@anl.gov
Fri, 30 Jan 2004 11:47:54 -0600
On Monday, I proposed a alternative method of obtaining and AFS PAG and
token when used with OpenSSH or any other deamon.
I now have a test working using openssh-snap-20040122.
This relies on an external program referred to as get-afs-token
which accepts at least two parameters:
-setpag - Use the AFS Kernel mods to set the AFS PAG
of the parent process.
-path <directory> - Get a AFS token for the cell containing this
directory.
The get-afs-token program would be provided by the OpenAFS or Kerberos
communities, and could be a link to aklog, afslog or gssklog. I have
tried this with my version of aklog, called ak5log, and with gssklog.
The aklog already accepted these parameters and afslog only need a minor
addition as did the gssklog.
Here is the sample code used with OpenSSH. Note that the get_afs_token
routine does not require any AFS or Kerberos header files.
--- ./,session.c Tue Jan 20 18:00:46 2004
+++ ./session.c Fri Jan 30 11:38:02 2004
@@ -66,6 +66,10 @@
#include "ssh-gss.h"
#endif
+#ifdef ANL_AFS_PAG
+int get_afs_token(char * pgm, char ** env, char *homedir, int setpag);
+#endif
+
/* func */
Session *session_new(void);
@@ -1419,6 +1423,14 @@
*/
environ = env;
+#ifdef ANL_AFS_PAG
+ /* Get PAG and AFS token using external program and KRB5CCNAME */
+ if (options.kerberos_get_afs_token) {
+ debug("Getting AFS token");
+ get_afs_token(NULL, env, pw->pw_dir, 1);
+ }
+#endif
+
#if defined(HEIMDAL) && defined(AFS)
/*
* At this point, we check to see if AFS is active and if we have
@@ -2216,3 +2228,119 @@
if (!use_privsep || mm_is_monitor())
session_destroy_all(session_pty_cleanup2);
}
+
+#ifdef ANL_AFS_PAG
+/* gafstoken.c
+
+ A generic routine to get an AFS token by calling
+ an external program.
+
+ This routine is generic in that it does not depend on
+ any specific implementation of AFS, or Kerberos.
+ This will allow a deamon to be configured, compiled
+ and linked without any AFS or Kerberos dependencies
+ and can thus avoid conflicts between these packages.
+ The resulting deamon executable can be run on a system with
+ or without AFS.
+
+ Examples of external programs that could be called
+ are aklog, afslog, gssklog, klog, ak5log or even a script
+ to call one of these.
+
+ The external program is expected to support
+ (or ignore) the -setpag and -path <homedir>
+
+ Parameters to gafstoken:
+
+ char * external_program - path to the executable
+ this would be set by configure, or defaulted
+ in some way. If NULL a built in location is used.
+
+ char **env - Environment to run under. This
+ should include any environment variables needed
+ by the external program such as KRB5CCNAME
+ or X509_USER_PROXY These would have been set
+ by GSSAPI or PAM. If NULL, the current environment
+ is used.
+
+ char * homedir - A file location, if in AFS the
+ external program will attempt to get a token
+ for the cell containing it. If NULL attempt
+ to get a token for the default cell of the client.
+
+ int setpag - Used to tell external program to get
+ an AFS PAG. The caller's process must be a process
+ that will be an ancestor of the user's process.
+
+ Returns:
+ -1 - some system error, see errno;
+ 0 - the external program if present was called and
+ MAY have worked.
+
+ The caller should not need to test the return code, and should
+ continue with or without the AFS token or PAG.
+
+ */
+
+#ifndef _PATH_AFS_EXTERNAL_PROGRAM
+#define _PATH_AFS_EXTERNAL_PROGRAM "/usr/libexec/get-afs-token"
+#endif
+
+int
+get_afs_token(char * external_program,
+ char ** env,
+ char * homedir,
+ int setpag)
+{
+ pid_t pid;
+ int status;
+ struct stat stx;
+ char * ppath = _PATH_AFS_EXTERNAL_PROGRAM;
+ char * args[5]; /* arg0, -setpag, -path, homedir, NULL */
+ int argi = 0;
+
+ if (external_program)
+ ppath = external_program;
+
+ /* test if external program exists */
+ if (stat(ppath, &stx))
+ return 0; /* does not exist, skip getting PAG and token */
+
+ args[argi++] = "getafstoken";
+ if (setpag)
+ args[argi++] = "-setpag";
+ if (homedir) {
+ args[argi++] = "-path";
+ args[argi++] = homedir;
+ }
+ args[argi] = NULL;
+
+ if ((pid = fork()) < 0) {
+ return -1; /* see errno */
+ }
+
+ if (pid == 0) {
+ /* Don't want any output confusing the deamon */
+ close(1);
+ open("/dev/null",O_WRONLY);
+ close(2);
+ open("/dev/null",O_WRONLY);
+
+ if (env)
+ execve(ppath, args, env);
+ else
+ execv(ppath, args);
+ exit(127); /* exec failed! Should never get here */
+ }
+
+ while (waitpid(pid, &status, 0) < 0) {
+ if (errno != EINTR)
+ break;
+ }
+
+ /* we could set a return code based on status,
+ * be we want to go on with or without a token */
+
+ return 0;
+}
+#endif
--- ./,Makefile.in Fri Nov 21 06:48:55 2003
+++ ./Makefile.in Thu Jan 29 11:22:40 2004
@@ -22,6 +22,7 @@
VPATH=@srcdir@
SSH_PROGRAM=@bindir@/ssh
ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass
+AFS_EXTERNAL_PROGRAM=$(libexecdir)/get-afs-token
SFTP_SERVER=$(libexecdir)/sftp-server
SSH_KEYSIGN=$(libexecdir)/ssh-keysign
RAND_HELPER=$(libexecdir)/ssh-rand-helper
@@ -32,6 +33,7 @@
PATHS= -DSSHDIR=\"$(sysconfdir)\" \
-D_PATH_SSH_PROGRAM=\"$(SSH_PROGRAM)\" \
-D_PATH_SSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\" \
+ -D_PATH_AFS_EXTERNAL_PROGRAM=\"$(AFS_EXTERNAL_PROGRAM)\" \
-D_PATH_SFTP_SERVER=\"$(SFTP_SERVER)\" \
-D_PATH_SSH_KEY_SIGN=\"$(SSH_KEYSIGN)\" \
-D_PATH_SSH_PIDDIR=\"$(piddir)\" \
"Douglas E. Engert" wrote:
>
> Rather then implementing kafs in MIT Kerberos, I would like to
> suggest an alternative which has advantages to all parties.
>
> The OpenSSH sshd needs to do two things:
> (1) sets a PAG in the kernel,
> (2) obtains an AFS token storing it in the kernel.
>
> It can use the Kerberos credentials either obtained via GSSAPI
> delegation, PAM or other kerberos login code in the sshd.
>
> The above two actions can be accomplished by a separate process,
> which can be forked and execd by the sshd and passed the environment
> which may have a KREB5CCNAME pointing at the Kerberos ticket cache
> Other parameters such as the home directory could also be passed.
>
> This would then allow simple code in OpenSSH that does not depend
> on OpenAFS, Hiemdal or MIT code to fork/exec the process that does
> all the work. This would be called by the process that would
> eventially become the user's shell process and is run as the user.
>
> OpenSSH could be built on systems that may or may not have AFS
> installed and run on a system with or without AFS. The decision
> is based on the existence of the executable and any options
> in sshd_config.
>
> In its simplest form, all that is needed is:
>
> system("/usr/ssh/libexec/aklog -setpag")
>
> This is a little over simplified as there should be a test if the
> executable exists, processing of some return codes, making sure the
> environment is set, setting some time limit. etc. But the point is
> there is no compile dependence on OpenAFS, MIT or Hiemdal by the
> OpenSSH sshd, and any failure of the process will not effect the sshd.
>
> We have been using something like this for years which issues a
> syscall to set a PAG for the current process, then fork/exec ak5log.
> Our current mode to OpenSSH in session.c is as simple as:
>
> krb5_afs_pag_env(NULL, env);
>
> It is currently built with the MIT Kerberos code for historic reasons,
> but could be seperate as it has no real dependency on the MIT code.
>
> I would hope that the members of the OpenSSH community who use OpenAFS,
> Hiemdal and/or MIT could agree on a simple command line interface that
> would encourage the builders of OpenSSH to always have this enabled.
>
> --
>
> Douglas E. Engert <DEEngert@anl.gov>
> Argonne National Laboratory
> 9700 South Cass Avenue
> Argonne, Illinois 60439
> (630) 252-5444
--
Douglas E. Engert <DEEngert@anl.gov>
Argonne National Laboratory
9700 South Cass Avenue
Argonne, Illinois 60439
(630) 252-5444