No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / lib / kdfs / k5dfspag.c
blobbf41cbf0eca867f256ae59b61b14581007a95d46
1 /*
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.
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.
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.
21 * krb5_dfs_pag()
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
28 __RCSID("$Heimdal: k5dfspag.c 11081 2002-08-12 15:11:58Z joda $"
29 "$NetBSD$");
31 #include <krb5.h>
33 #ifdef DCE
35 #include <stdio.h>
36 #include <sys/stat.h>
37 #include <sys/wait.h>
38 #include <fcntl.h>
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.
49 #define POSIX_SETJMP
50 #define POSIX_SIGNALS
51 #define HAVE_WAITPID
53 #include <signal.h>
54 #include <setjmp.h>
55 #ifndef POSIX_SETJMP
56 #undef sigjmp_buf
57 #undef sigsetjmp
58 #undef siglongjmp
59 #define sigjmp_buf jmp_buf
60 #define sigsetjmp(j,s) setjmp(j)
61 #define siglongjmp longjmp
62 #endif
64 #ifdef POSIX_SIGNALS
65 typedef struct sigaction handler;
66 #define handler_init(H,F) (sigemptyset(&(H).sa_mask), \
67 (H).sa_flags=0, \
68 (H).sa_handler=(F))
69 #define handler_swap(S,NEW,OLD) sigaction(S, &NEW, &OLD)
70 #define handler_set(S,OLD) sigaction(S, &OLD, NULL)
71 #else
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)))
76 #endif
78 #define krb5_sigtype void
79 #define WAIT_USES_INT
80 typedef krb5_sigtype sigtype;
83 /*
84 * Need some syscall numbers based on different systems.
85 * These are based on:
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!
91 * DEE 5/27/97
96 #define AFSCALL_SETPAG 2
97 #define AFSCALL_GETPAG 11
99 #if defined(sun)
100 #define AFS_SYSCALL 72
102 #elif defined(hpux)
103 /* assume HPUX 10 + or is it 50 */
104 #define AFS_SYSCALL 326
106 #elif defined(_AIX)
107 #ifndef DPAGAIX
108 #define DPAGAIX LIBEXECDIR "/dpagaix"
109 #endif
110 int *load();
111 static int (*dpagaix)(int, int, int, int, int, int) = 0;
113 #elif defined(sgi) || defined(_sgi)
114 #define AFS_SYSCALL 206+1000
116 #else
117 #define AFS_SYSCALL (Unknown_DFS_AFS_SYSCALL)
118 #endif
121 #ifdef WAIT_USES_INT
122 int wait_status;
123 #else /* WAIT_USES_INT */
124 union wait wait_status;
125 #endif /* WAIT_USES_INT */
127 #ifndef K5DCECON
128 #define K5DCECON LIBEXECDIR "/k5dcecon"
129 #endif
132 * mysig()
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)
153 int opt1;
154 int opt2;
156 handler sa1, osa1;
157 handler sa2, osa2;
158 int pag = -2;
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) {
167 #if defined(_AIX)
168 if (!dpagaix)
169 dpagaix = load(DPAGAIX, 0, 0);
170 if (dpagaix)
171 pag = (*dpagaix)(opt1, opt2, 0, 0, 0, 0);
172 #else
173 pag = syscall(AFS_SYSCALL, opt1, opt2, 0, 0, 0, 0);
174 #endif
176 handler_set (SIGSYS, osa1);
177 handler_set (SIGSEGV, osa2);
178 return(pag);
181 /* syscall failed! return 0 */
182 handler_set (SIGSYS, osa1);
183 handler_set (SIGSEGV, osa2);
184 return(-2);
188 * krb5_dfs_newpag()
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)
201 int new_pag;
203 return(krb5_dfs_pag_syscall(AFSCALL_SETPAG, new_pag));
207 * krb5_dfs_getpag()
209 * get the current PAG. Used mostly as a test.
212 int krb5_dfs_getpag()
214 return(krb5_dfs_pag_syscall(AFSCALL_GETPAG, 0));
218 * krb5_dfs_pag()
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
237 * user.
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.
245 * DEE - 7/97
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;
252 const char *luser;
256 struct stat stx;
257 int fd[2];
258 int i,j;
259 int pid;
260 int new_pag;
261 int pag;
262 char newccname[MAXPATHLEN] = "";
263 char *princ;
264 int err;
265 struct sigaction newsig, oldsig;
267 #ifdef WAIT_USES_INT
268 int wait_status;
269 #else /* WAIT_USES_INT */
270 union wait wait_status;
271 #endif /* WAIT_USES_INT */
273 if (krb5_unparse_name(context, principal, &princ))
274 return(0);
276 /* test if DFS is running or installed */
277 if (krb5_dfs_getpag() == -2)
278 return(0); /* DFS not running, dont try */
280 if (pipe(fd) == -1)
281 return(0);
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);
288 pid = fork();
289 if (pid <0)
290 return(0);
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" ,
301 "-l", luser,
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); */
314 /* #else */
317 wait_status = 0;
318 #ifdef HAVE_WAITPID
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 */
323 /* #endif */
325 sigaction(SIGCHLD, &oldsig, 0);
326 if (WIFEXITED(wait_status)){
327 if (WEXITSTATUS(wait_status) == 0) {
328 i = 1;
329 j = 0;
330 while (i != 0) {
331 i = read(fd[0], &newccname[j], sizeof(newccname)-1-j);
332 if ( i > 0)
333 j += i;
334 if (j >= sizeof(newccname)-1)
335 i = 0;
337 close(fd[0]);
338 if (j > 0) {
339 newccname[j] = '\0';
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) {
344 return(pag);
350 return(0); /* something not right */
353 #else /* DCE */
356 * krb5_dfs_pag - dummy version for the lib for systems
357 * which don't have DFS, or the needed setpag kernel code.
360 krb5_boolean
361 krb5_dfs_pag(context, principal, luser)
362 krb5_context context;
363 krb5_principal principal;
364 const char *luser;
366 return(0);
369 #endif /* DCE */