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