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