[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