#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
RCSID("$Id$");
#include <krb5.h>
#ifdef DCE
#include <stdio.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/param.h>
#define POSIX_SETJMP
#define POSIX_SIGNALS
#define HAVE_WAITPID
#include <signal.h>
#include <setjmp.h>
#ifndef POSIX_SETJMP
#undef sigjmp_buf
#undef sigsetjmp
#undef siglongjmp
#define sigjmp_buf jmp_buf
#define sigsetjmp(j,s) setjmp(j)
#define siglongjmp longjmp
#endif
#ifdef POSIX_SIGNALS
typedef struct sigaction handler;
#define handler_init(H,F) (sigemptyset(&(H).sa_mask), \
(H).sa_flags=0, \
(H).sa_handler=(F))
#define handler_swap(S,NEW,OLD) sigaction(S, &NEW, &OLD)
#define handler_set(S,OLD) sigaction(S, &OLD, NULL)
#else
typedef sigtype (*handler)();
#define handler_init(H,F) ((H) = (F))
#define handler_swap(S,NEW,OLD) ((OLD) = signal ((S), (NEW)))
#define handler_set(S,OLD) (signal ((S), (OLD)))
#endif
#define krb5_sigtype void
#define WAIT_USES_INT
typedef krb5_sigtype sigtype;
#define AFSCALL_SETPAG 2
#define AFSCALL_GETPAG 11
#if defined(sun)
#define AFS_SYSCALL 72
#elif defined(hpux)
#define AFS_SYSCALL 326
#elif defined(_AIX)
#ifndef DPAGAIX
#define DPAGAIX LIBEXECDIR "/dpagaix"
#endif
int *load();
static int (*dpagaix)(int, int, int, int, int, int) = 0;
#elif defined(sgi) || defined(_sgi)
#define AFS_SYSCALL 206+1000
#else
#define AFS_SYSCALL (Unknown_DFS_AFS_SYSCALL)
#endif
#ifdef WAIT_USES_INT
int wait_status;
#else
union wait wait_status;
#endif
#ifndef K5DCECON
#define K5DCECON LIBEXECDIR "/k5dcecon"
#endif
static sigjmp_buf setpag_buf;
static sigtype mysig()
{
siglongjmp(setpag_buf, 1);
}
static int krb5_dfs_pag_syscall(opt1,opt2)
int opt1;
int opt2;
{
handler sa1, osa1;
handler sa2, osa2;
int pag = -2;
handler_init (sa1, mysig);
handler_init (sa2, mysig);
handler_swap (SIGSYS, sa1, osa1);
handler_swap (SIGSEGV, sa2, osa2);
if (sigsetjmp(setpag_buf, 1) == 0) {
#if defined(_AIX)
if (!dpagaix)
dpagaix = load(DPAGAIX, 0, 0);
if (dpagaix)
pag = (*dpagaix)(opt1, opt2, 0, 0, 0, 0);
#else
pag = syscall(AFS_SYSCALL, opt1, opt2, 0, 0, 0, 0);
#endif
handler_set (SIGSYS, osa1);
handler_set (SIGSEGV, osa2);
return(pag);
}
handler_set (SIGSYS, osa1);
handler_set (SIGSEGV, osa2);
return(-2);
}
int krb5_dfs_newpag(new_pag)
int new_pag;
{
return(krb5_dfs_pag_syscall(AFSCALL_SETPAG, new_pag));
}
int krb5_dfs_getpag()
{
return(krb5_dfs_pag_syscall(AFSCALL_GETPAG, 0));
}
int krb5_dfs_pag(context, flag, principal, luser)
krb5_context context;
int flag;
krb5_principal principal;
const char *luser;
{
struct stat stx;
int fd[2];
int i,j;
int pid;
int new_pag;
int pag;
char newccname[MAXPATHLEN] = "";
char *princ;
int err;
struct sigaction newsig, oldsig;
#ifdef WAIT_USES_INT
int wait_status;
#else
union wait wait_status;
#endif
if (krb5_unparse_name(context, principal, &princ))
return(0);
if (krb5_dfs_getpag() == -2)
return(0);
if (pipe(fd) == -1)
return(0);
memset((char *)&newsig, 0, sizeof(newsig));
newsig.sa_handler = SIG_DFL;
sigaction(SIGCHLD, &newsig, &oldsig);
pid = fork();
if (pid <0)
return(0);
if (pid == 0) {
close(1);
dup(fd[1]);
close(fd[0]);
close(fd[1]);
execl(K5DCECON, "k5dcecon",
(flag) ? "-f" : "-s" ,
"-l", luser,
"-p", princ, (char *)0);
exit(127);
}
close(fd[1]);
wait_status = 0;
#ifdef HAVE_WAITPID
err = waitpid((pid_t) pid, &wait_status, 0);
#else
err = wait4(pid, &wait_status, 0, (struct rusage *) NULL);
#endif
sigaction(SIGCHLD, &oldsig, 0);
if (WIFEXITED(wait_status)){
if (WEXITSTATUS(wait_status) == 0) {
i = 1;
j = 0;
while (i != 0) {
i = read(fd[0], &newccname[j], sizeof(newccname)-1-j);
if ( i > 0)
j += i;
if (j >= sizeof(newccname)-1)
i = 0;
}
close(fd[0]);
if (j > 0) {
newccname[j] = '\0';
esetenv("KRB5CCNAME",newccname,1);
sscanf(&newccname[j-8],"%8x",&new_pag);
if (new_pag && strncmp("FILE:/opt/dcelocal/var/security/creds/dcecred_", newccname, 46) == 0) {
if((pag = krb5_dfs_newpag(new_pag)) != -2) {
return(pag);
}
}
}
}
}
return(0);
}
#else
krb5_boolean
krb5_dfs_pag(context, principal, luser)
krb5_context context;
krb5_principal principal;
const char *luser;
{
return(0);
}
#endif