source: heimdal/trunk/lib/kdfs/k5dfspag.c@ 3

Last change on this file since 3 was 1, checked in by Paul Smedley, 10 years ago

Initial commit of Heimdal 1.5.3

File size: 8.4 KB
Line 
1/*
2 * lib/krb5/os/k5dfspag.c
3 *
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.
7 *
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
12 * will continue.
13 *
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.
18 *
19 *
20 *
21 * krb5_dfs_pag()
22 */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28RCSID("$Id$");
29
30#include <krb5.h>
31
32#ifdef DCE
33
34#include <stdio.h>
35#include <sys/stat.h>
36#include <sys/wait.h>
37#include <fcntl.h>
38#include <sys/param.h>
39
40/* Only run this DFS PAG code on systems with POSIX
41 * All that we are interested in dor:, AIX 4.x,
42 * Solaris 2.5.x, HPUX 10.x Even SunOS 4.1.4, AIX 3.2.5
43 * and SGI 5.3 are OK. This simplifies
44 * the build/configure which I don't want to change now.
45 * All of them also have waitpid as well.
46 */
47
48#define POSIX_SETJMP
49#define POSIX_SIGNALS
50#define HAVE_WAITPID
51
52#include <signal.h>
53#include <setjmp.h>
54#ifndef POSIX_SETJMP
55#undef sigjmp_buf
56#undef sigsetjmp
57#undef siglongjmp
58#define sigjmp_buf jmp_buf
59#define sigsetjmp(j,s) setjmp(j)
60#define siglongjmp longjmp
61#endif
62
63#ifdef POSIX_SIGNALS
64typedef struct sigaction handler;
65#define handler_init(H,F) (sigemptyset(&(H).sa_mask), \
66 (H).sa_flags=0, \
67 (H).sa_handler=(F))
68#define handler_swap(S,NEW,OLD) sigaction(S, &NEW, &OLD)
69#define handler_set(S,OLD) sigaction(S, &OLD, NULL)
70#else
71typedef sigtype (*handler)();
72#define handler_init(H,F) ((H) = (F))
73#define handler_swap(S,NEW,OLD) ((OLD) = signal ((S), (NEW)))
74#define handler_set(S,OLD) (signal ((S), (OLD)))
75#endif
76
77#define krb5_sigtype void
78#define WAIT_USES_INT
79typedef krb5_sigtype sigtype;
80
81
82/*
83 * Need some syscall numbers based on different systems.
84 * These are based on:
85 * HPUX 10.10 /opt/dce/include/dcedfs/syscall.h
86 * Solaris 2.5 /opt/dcelocal/share/include/dcedfs/syscall.h
87 * AIX 4.2 - needs some funny games with load and kafs_syscall
88 * to get the kernel extentions. There should be a better way!
89 *
90 * DEE 5/27/97
91 *
92 */
93
94
95#define AFSCALL_SETPAG 2
96#define AFSCALL_GETPAG 11
97
98#if defined(sun)
99#define AFS_SYSCALL 72
100
101#elif defined(hpux)
102/* assume HPUX 10 + or is it 50 */
103#define AFS_SYSCALL 326
104
105#elif defined(_AIX)
106#ifndef DPAGAIX
107#define DPAGAIX LIBEXECDIR "/dpagaix"
108#endif
109int *load();
110static int (*dpagaix)(int, int, int, int, int, int) = 0;
111
112#elif defined(sgi) || defined(_sgi)
113#define AFS_SYSCALL 206+1000
114
115#else
116#define AFS_SYSCALL (Unknown_DFS_AFS_SYSCALL)
117#endif
118
119
120#ifdef WAIT_USES_INT
121 int wait_status;
122#else /* WAIT_USES_INT */
123 union wait wait_status;
124#endif /* WAIT_USES_INT */
125
126#ifndef K5DCECON
127#define K5DCECON LIBEXECDIR "/k5dcecon"
128#endif
129
130/*
131 * mysig()
132 *
133 * signal handler if DFS not running
134 *
135 */
136
137static sigjmp_buf setpag_buf;
138
139static sigtype mysig()
140{
141 siglongjmp(setpag_buf, 1);
142}
143
144/*
145 * krb5_dfs_pag_syscall()
146 *
147 * wrapper for the syscall with signal handlers
148 *
149 */
150
151static int krb5_dfs_pag_syscall(opt1,opt2)
152 int opt1;
153 int opt2;
154{
155 handler sa1, osa1;
156 handler sa2, osa2;
157 int pag = -2;
158
159 handler_init (sa1, mysig);
160 handler_init (sa2, mysig);
161 handler_swap (SIGSYS, sa1, osa1);
162 handler_swap (SIGSEGV, sa2, osa2);
163
164 if (sigsetjmp(setpag_buf, 1) == 0) {
165
166#if defined(_AIX)
167 if (!dpagaix)
168 dpagaix = load(DPAGAIX, 0, 0);
169 if (dpagaix)
170 pag = (*dpagaix)(opt1, opt2, 0, 0, 0, 0);
171#else
172 pag = syscall(AFS_SYSCALL, opt1, opt2, 0, 0, 0, 0);
173#endif
174
175 handler_set (SIGSYS, osa1);
176 handler_set (SIGSEGV, osa2);
177 return(pag);
178 }
179
180 /* syscall failed! return 0 */
181 handler_set (SIGSYS, osa1);
182 handler_set (SIGSEGV, osa2);
183 return(-2);
184}
185
186/*
187 * krb5_dfs_newpag()
188 *
189 * issue a DCE/DFS setpag system call to set the newpag
190 * for this process. This takes advantage of a currently
191 * undocumented feature of the Transarc port of DFS.
192 * Even in DCE 1.2.2 for which the source is available,
193 * (but no vendors have released), this feature is not
194 * there, but it should be, or could be added.
195 * If new_pag is zero, then the syscall will get a new pag
196 * and return its value.
197 */
198
199int krb5_dfs_newpag(new_pag)
200 int new_pag;
201{
202 return(krb5_dfs_pag_syscall(AFSCALL_SETPAG, new_pag));
203}
204
205/*
206 * krb5_dfs_getpag()
207 *
208 * get the current PAG. Used mostly as a test.
209 */
210
211int krb5_dfs_getpag()
212{
213 return(krb5_dfs_pag_syscall(AFSCALL_GETPAG, 0));
214}
215
216/*
217 * krb5_dfs_pag()
218 *
219 * Given a principal and local username,
220 * fork and exec the k5dcecon module to create
221 * refresh or join a new DCE/DFS
222 * Process Authentication Group (PAG)
223 *
224 * This routine should be called after krb5_kuserok has
225 * determined that this combination of local user and
226 * principal are acceptable for the local host.
227 *
228 * It should also be called after a forwarded ticket has
229 * been received, and the KRB5CCNAME environment variable
230 * has been set to point at it. k5dcecon will convert this
231 * to a new DCE context and a new pag and replace KRB5CCNAME
232 * in the environment.
233 *
234 * If there is no forwarded ticket, k5dcecon will attempt
235 * to join an existing PAG for the same principal and local
236 * user.
237 *
238 * And it should be called before access to the home directory
239 * as this may be in DFS, not accessable by root, and require
240 * the PAG to have been setup.
241 *
242 * The krb5_afs_pag can be called after this routine to
243 * use the the cache obtained by k5dcecon to get an AFS token.
244 * DEE - 7/97
245 */
246
247int krb5_dfs_pag(context, flag, principal, luser)
248 krb5_context context;
249 int flag; /* 1 if a forwarded TGT is to be used */
250 krb5_principal principal;
251 const char *luser;
252
253{
254
255 struct stat stx;
256 int fd[2];
257 int i,j;
258 int pid;
259 int new_pag;
260 int pag;
261 char newccname[MAXPATHLEN] = "";
262 char *princ;
263 int err;
264 struct sigaction newsig, oldsig;
265
266#ifdef WAIT_USES_INT
267 int wait_status;
268#else /* WAIT_USES_INT */
269 union wait wait_status;
270#endif /* WAIT_USES_INT */
271
272 if (krb5_unparse_name(context, principal, &princ))
273 return(0);
274
275 /* test if DFS is running or installed */
276 if (krb5_dfs_getpag() == -2)
277 return(0); /* DFS not running, dont try */
278
279 if (pipe(fd) == -1)
280 return(0);
281
282 /* Make sure that telnetd.c's SIGCHLD action don't happen right now... */
283 memset((char *)&newsig, 0, sizeof(newsig));
284 newsig.sa_handler = SIG_DFL;
285 sigaction(SIGCHLD, &newsig, &oldsig);
286
287 pid = fork();
288 if (pid <0)
289 return(0);
290
291 if (pid == 0) { /* child process */
292
293 close(1); /* close stdout */
294 dup(fd[1]); /* point stdout at pipe here */
295 close(fd[0]); /* don't use end of pipe here */
296 close(fd[1]); /* pipe now as stdout */
297
298 execl(K5DCECON, "k5dcecon",
299 (flag) ? "-f" : "-s" ,
300 "-l", luser,
301 "-p", princ, (char *)0);
302
303 exit(127); /* incase execl fails */
304 }
305
306 /* parent, wait for child to finish */
307
308 close(fd[1]); /* dont need this end of pipe */
309
310/* #if defined(sgi) || defined(_sgi) */
311 /* wait_status.w_status = 0; */
312 /* waitpid((pid_t) pid, &wait_status.w_status, 0); */
313/* #else */
314
315
316 wait_status = 0;
317#ifdef HAVE_WAITPID
318 err = waitpid((pid_t) pid, &wait_status, 0);
319#else /* HAVE_WAITPID */
320 err = wait4(pid, &wait_status, 0, (struct rusage *) NULL);
321#endif /* HAVE_WAITPID */
322/* #endif */
323
324 sigaction(SIGCHLD, &oldsig, 0);
325 if (WIFEXITED(wait_status)){
326 if (WEXITSTATUS(wait_status) == 0) {
327 i = 1;
328 j = 0;
329 while (i != 0) {
330 i = read(fd[0], &newccname[j], sizeof(newccname)-1-j);
331 if ( i > 0)
332 j += i;
333 if (j >= sizeof(newccname)-1)
334 i = 0;
335 }
336 close(fd[0]);
337 if (j > 0) {
338 newccname[j] = '\0';
339 esetenv("KRB5CCNAME",newccname,1);
340 sscanf(&newccname[j-8],"%8x",&new_pag);
341 if (new_pag && strncmp("FILE:/opt/dcelocal/var/security/creds/dcecred_", newccname, 46) == 0) {
342 if((pag = krb5_dfs_newpag(new_pag)) != -2) {
343 return(pag);
344 }
345 }
346 }
347 }
348 }
349 return(0); /* something not right */
350}
351
352#else /* DCE */
353
354/*
355 * krb5_dfs_pag - dummy version for the lib for systems
356 * which don't have DFS, or the needed setpag kernel code.
357 */
358
359krb5_boolean
360krb5_dfs_pag(context, principal, luser)
361 krb5_context context;
362 krb5_principal principal;
363 const char *luser;
364{
365 return(0);
366}
367
368#endif /* DCE */
Note: See TracBrowser for help on using the repository browser.