2 * lib/krb5/os/k5dfspag.c
4 * New Kerberos module to issue the DFS PAG syscalls.
5 * It also contains the routine to fork and exec the
6 * k5dcecon routine to do most of the work.
8 * This file is designed to be as independent of DCE
9 * and DFS as possible. The only dependencies are on
10 * the syscall numbers. If DFS not running or not installed,
11 * the sig handlers will catch and the signal and
14 * krb5_dfs_newpag and krb5_dfs_getpag should not be real
15 * Kerberos routines, since they should be setpag and getpag
16 * in the DCE library, but without the DCE baggage.
17 * Thus they don't have context, and don't return a krb5 error.
28 __RCSID("$Heimdal: k5dfspag.c 11081 2002-08-12 15:11:58Z joda $"
39 #include <sys/param.h>
41 /* Only run this DFS PAG code on systems with POSIX
42 * All that we are interested in dor:, AIX 4.x,
43 * Solaris 2.5.x, HPUX 10.x Even SunOS 4.1.4, AIX 3.2.5
44 * and SGI 5.3 are OK. This simplifies
45 * the build/configure which I don't want to change now.
46 * All of them also have waitpid as well.
59 #define sigjmp_buf jmp_buf
60 #define sigsetjmp(j,s) setjmp(j)
61 #define siglongjmp longjmp
65 typedef struct sigaction handler
;
66 #define handler_init(H,F) (sigemptyset(&(H).sa_mask), \
69 #define handler_swap(S,NEW,OLD) sigaction(S, &NEW, &OLD)
70 #define handler_set(S,OLD) sigaction(S, &OLD, NULL)
72 typedef sigtype (*handler
)();
73 #define handler_init(H,F) ((H) = (F))
74 #define handler_swap(S,NEW,OLD) ((OLD) = signal ((S), (NEW)))
75 #define handler_set(S,OLD) (signal ((S), (OLD)))
78 #define krb5_sigtype void
80 typedef krb5_sigtype sigtype
;
84 * Need some syscall numbers based on different systems.
86 * HPUX 10.10 /opt/dce/include/dcedfs/syscall.h
87 * Solaris 2.5 /opt/dcelocal/share/include/dcedfs/syscall.h
88 * AIX 4.2 - needs some funny games with load and kafs_syscall
89 * to get the kernel extentions. There should be a better way!
96 #define AFSCALL_SETPAG 2
97 #define AFSCALL_GETPAG 11
100 #define AFS_SYSCALL 72
103 /* assume HPUX 10 + or is it 50 */
104 #define AFS_SYSCALL 326
108 #define DPAGAIX LIBEXECDIR "/dpagaix"
111 static int (*dpagaix
)(int, int, int, int, int, int) = 0;
113 #elif defined(sgi) || defined(_sgi)
114 #define AFS_SYSCALL 206+1000
117 #define AFS_SYSCALL (Unknown_DFS_AFS_SYSCALL)
123 #else /* WAIT_USES_INT */
124 union wait wait_status
;
125 #endif /* WAIT_USES_INT */
128 #define K5DCECON LIBEXECDIR "/k5dcecon"
134 * signal handler if DFS not running
138 static sigjmp_buf setpag_buf
;
140 static sigtype
mysig()
142 siglongjmp(setpag_buf
, 1);
146 * krb5_dfs_pag_syscall()
148 * wrapper for the syscall with signal handlers
152 static int krb5_dfs_pag_syscall(opt1
,opt2
)
160 handler_init (sa1
, mysig
);
161 handler_init (sa2
, mysig
);
162 handler_swap (SIGSYS
, sa1
, osa1
);
163 handler_swap (SIGSEGV
, sa2
, osa2
);
165 if (sigsetjmp(setpag_buf
, 1) == 0) {
169 dpagaix
= load(DPAGAIX
, 0, 0);
171 pag
= (*dpagaix
)(opt1
, opt2
, 0, 0, 0, 0);
173 pag
= syscall(AFS_SYSCALL
, opt1
, opt2
, 0, 0, 0, 0);
176 handler_set (SIGSYS
, osa1
);
177 handler_set (SIGSEGV
, osa2
);
181 /* syscall failed! return 0 */
182 handler_set (SIGSYS
, osa1
);
183 handler_set (SIGSEGV
, osa2
);
190 * issue a DCE/DFS setpag system call to set the newpag
191 * for this process. This takes advantage of a currently
192 * undocumented feature of the Transarc port of DFS.
193 * Even in DCE 1.2.2 for which the source is available,
194 * (but no vendors have released), this feature is not
195 * there, but it should be, or could be added.
196 * If new_pag is zero, then the syscall will get a new pag
197 * and return its value.
200 int krb5_dfs_newpag(new_pag
)
203 return(krb5_dfs_pag_syscall(AFSCALL_SETPAG
, new_pag
));
209 * get the current PAG. Used mostly as a test.
212 int krb5_dfs_getpag()
214 return(krb5_dfs_pag_syscall(AFSCALL_GETPAG
, 0));
220 * Given a principal and local username,
221 * fork and exec the k5dcecon module to create
222 * refresh or join a new DCE/DFS
223 * Process Authentication Group (PAG)
225 * This routine should be called after krb5_kuserok has
226 * determined that this combination of local user and
227 * principal are acceptable for the local host.
229 * It should also be called after a forwarded ticket has
230 * been received, and the KRB5CCNAME environment variable
231 * has been set to point at it. k5dcecon will convert this
232 * to a new DCE context and a new pag and replace KRB5CCNAME
233 * in the environment.
235 * If there is no forwarded ticket, k5dcecon will attempt
236 * to join an existing PAG for the same principal and local
239 * And it should be called before access to the home directory
240 * as this may be in DFS, not accessable by root, and require
241 * the PAG to have been setup.
243 * The krb5_afs_pag can be called after this routine to
244 * use the the cache obtained by k5dcecon to get an AFS token.
248 int krb5_dfs_pag(context
, flag
, principal
, luser
)
249 krb5_context context
;
250 int flag
; /* 1 if a forwarded TGT is to be used */
251 krb5_principal principal
;
262 char newccname
[MAXPATHLEN
] = "";
265 struct sigaction newsig
, oldsig
;
269 #else /* WAIT_USES_INT */
270 union wait wait_status
;
271 #endif /* WAIT_USES_INT */
273 if (krb5_unparse_name(context
, principal
, &princ
))
276 /* test if DFS is running or installed */
277 if (krb5_dfs_getpag() == -2)
278 return(0); /* DFS not running, dont try */
283 /* Make sure that telnetd.c's SIGCHLD action don't happen right now... */
284 memset((char *)&newsig
, 0, sizeof(newsig
));
285 newsig
.sa_handler
= SIG_DFL
;
286 sigaction(SIGCHLD
, &newsig
, &oldsig
);
292 if (pid
== 0) { /* child process */
294 close(1); /* close stdout */
295 dup(fd
[1]); /* point stdout at pipe here */
296 close(fd
[0]); /* don't use end of pipe here */
297 close(fd
[1]); /* pipe now as stdout */
299 execl(K5DCECON
, "k5dcecon",
300 (flag
) ? "-f" : "-s" ,
302 "-p", princ
, (char *)0);
304 exit(127); /* incase execl fails */
307 /* parent, wait for child to finish */
309 close(fd
[1]); /* dont need this end of pipe */
311 /* #if defined(sgi) || defined(_sgi) */
312 /* wait_status.w_status = 0; */
313 /* waitpid((pid_t) pid, &wait_status.w_status, 0); */
319 err
= waitpid((pid_t
) pid
, &wait_status
, 0);
320 #else /* HAVE_WAITPID */
321 err
= wait4(pid
, &wait_status
, 0, (struct rusage
*) NULL
);
322 #endif /* HAVE_WAITPID */
325 sigaction(SIGCHLD
, &oldsig
, 0);
326 if (WIFEXITED(wait_status
)){
327 if (WEXITSTATUS(wait_status
) == 0) {
331 i
= read(fd
[0], &newccname
[j
], sizeof(newccname
)-1-j
);
334 if (j
>= sizeof(newccname
)-1)
340 esetenv("KRB5CCNAME",newccname
,1);
341 sscanf(&newccname
[j
-8],"%8x",&new_pag
);
342 if (new_pag
&& strncmp("FILE:/opt/dcelocal/var/security/creds/dcecred_", newccname
, 46) == 0) {
343 if((pag
= krb5_dfs_newpag(new_pag
)) != -2) {
350 return(0); /* something not right */
356 * krb5_dfs_pag - dummy version for the lib for systems
357 * which don't have DFS, or the needed setpag kernel code.
361 krb5_dfs_pag(context
, principal
, luser
)
362 krb5_context context
;
363 krb5_principal principal
;