No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / lib / kafs / afssys.c
blob29b628fe63fc5ef7039edd81d94f359d3973cf3c
1 /*
2 * Copyright (c) 1995 - 2000, 2002, 2004, 2005 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "kafs_locl.h"
36 __RCSID("$Heimdal: afssys.c 17050 2006-04-11 08:12:29Z lha $"
37 "$NetBSD$");
39 struct procdata {
40 unsigned long param4;
41 unsigned long param3;
42 unsigned long param2;
43 unsigned long param1;
44 unsigned long syscall;
46 #define VIOC_SYSCALL_PROC _IOW('C', 1, void *)
48 struct devdata {
49 unsigned long syscall;
50 unsigned long param1;
51 unsigned long param2;
52 unsigned long param3;
53 unsigned long param4;
54 unsigned long param5;
55 unsigned long param6;
56 unsigned long retval;
58 #define VIOC_SYSCALL_DEV _IOWR('C', 2, struct devdata)
59 #define VIOC_SYSCALL_DEV_OPENAFS _IOWR('C', 1, struct devdata)
62 int _kafs_debug; /* this should be done in a better way */
64 #define UNKNOWN_ENTRY_POINT (-1)
65 #define NO_ENTRY_POINT 0
66 #define SINGLE_ENTRY_POINT 1
67 #define MULTIPLE_ENTRY_POINT 2
68 #define SINGLE_ENTRY_POINT2 3
69 #define SINGLE_ENTRY_POINT3 4
70 #define LINUX_PROC_POINT 5
71 #define AIX_ENTRY_POINTS 6
72 #define MACOS_DEV_POINT 7
74 static int afs_entry_point = UNKNOWN_ENTRY_POINT;
75 static int afs_syscalls[2];
76 static char *afs_ioctlpath;
77 static unsigned long afs_ioctlnum;
79 /* Magic to get AIX syscalls to work */
80 #ifdef _AIX
82 static int (*Pioctl)(char*, int, struct ViceIoctl*, int);
83 static int (*Setpag)(void);
85 #include "dlfcn.h"
91 static int
92 try_aix(void)
94 #ifdef STATIC_AFS_SYSCALLS
95 Pioctl = aix_pioctl;
96 Setpag = aix_setpag;
97 #else
98 void *ptr;
99 char path[MaxPathLen], *p;
101 * If we are root or running setuid don't trust AFSLIBPATH!
103 if (getuid() != 0 && !issuid() && (p = getenv("AFSLIBPATH")) != NULL)
104 strlcpy(path, p, sizeof(path));
105 else
106 snprintf(path, sizeof(path), "%s/afslib.so", LIBDIR);
108 ptr = dlopen(path, RTLD_NOW);
109 if(ptr == NULL) {
110 if(_kafs_debug) {
111 if(errno == ENOEXEC && (p = dlerror()) != NULL)
112 fprintf(stderr, "dlopen(%s): %s\n", path, p);
113 else if (errno != ENOENT)
114 fprintf(stderr, "dlopen(%s): %s\n", path, strerror(errno));
116 return 1;
118 Setpag = (int (*)(void))dlsym(ptr, "aix_setpag");
119 Pioctl = (int (*)(char*, int,
120 struct ViceIoctl*, int))dlsym(ptr, "aix_pioctl");
121 #endif
122 afs_entry_point = AIX_ENTRY_POINTS;
123 return 0;
125 #endif /* _AIX */
128 * This probably only works under Solaris and could get confused if
129 * there's a /etc/name_to_sysnum file.
132 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
134 #define _PATH_ETC_NAME_TO_SYSNUM "/etc/name_to_sysnum"
136 static int
137 map_syscall_name_to_number (const char *str, int *res)
139 FILE *f;
140 char buf[256];
141 size_t str_len = strlen (str);
143 f = fopen (_PATH_ETC_NAME_TO_SYSNUM, "r");
144 if (f == NULL)
145 return -1;
146 while (fgets (buf, sizeof(buf), f) != NULL) {
147 if (buf[0] == '#')
148 continue;
150 if (strncmp (str, buf, str_len) == 0) {
151 char *begptr = buf + str_len;
152 char *endptr;
153 long val = strtol (begptr, &endptr, 0);
155 if (val != 0 && endptr != begptr) {
156 fclose (f);
157 *res = val;
158 return 0;
162 fclose (f);
163 return -1;
165 #endif
167 static int
168 try_ioctlpath(const char *path, unsigned long ioctlnum, int entrypoint)
170 int fd, ret, saved_errno;
172 fd = open(path, O_RDWR);
173 if (fd < 0)
174 return 1;
175 switch (entrypoint) {
176 case LINUX_PROC_POINT: {
177 struct procdata data = { 0, 0, 0, 0, AFSCALL_PIOCTL };
178 data.param2 = (unsigned long)VIOCGETTOK;
179 ret = ioctl(fd, ioctlnum, &data);
180 break;
182 case MACOS_DEV_POINT: {
183 struct devdata data = { AFSCALL_PIOCTL, 0, 0, 0, 0, 0, 0, 0 };
184 data.param2 = (unsigned long)VIOCGETTOK;
185 ret = ioctl(fd, ioctlnum, &data);
186 break;
188 default:
189 abort();
191 saved_errno = errno;
192 close(fd);
194 * Be quite liberal in what error are ok, the first is the one
195 * that should trigger given that params is NULL.
197 if (ret &&
198 (saved_errno != EFAULT &&
199 saved_errno != EDOM &&
200 saved_errno != ENOTCONN))
201 return 1;
202 afs_ioctlnum = ioctlnum;
203 afs_ioctlpath = strdup(path);
204 if (afs_ioctlpath == NULL)
205 return 1;
206 afs_entry_point = entrypoint;
207 return 0;
210 static int
211 do_ioctl(void *data)
213 int fd, ret, saved_errno;
214 fd = open(afs_ioctlpath, O_RDWR);
215 if (fd < 0) {
216 errno = EINVAL;
217 return -1;
219 ret = ioctl(fd, afs_ioctlnum, data);
220 saved_errno = errno;
221 close(fd);
222 errno = saved_errno;
223 return ret;
227 k_pioctl(char *a_path,
228 int o_opcode,
229 struct ViceIoctl *a_paramsP,
230 int a_followSymlinks)
232 #ifndef NO_AFS
233 switch(afs_entry_point){
234 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
235 case SINGLE_ENTRY_POINT:
236 case SINGLE_ENTRY_POINT2:
237 case SINGLE_ENTRY_POINT3:
238 return syscall(afs_syscalls[0], AFSCALL_PIOCTL,
239 a_path, o_opcode, a_paramsP, a_followSymlinks);
240 #endif
241 #if defined(AFS_PIOCTL)
242 case MULTIPLE_ENTRY_POINT:
243 return syscall(afs_syscalls[0],
244 a_path, o_opcode, a_paramsP, a_followSymlinks);
245 #endif
246 case LINUX_PROC_POINT: {
247 struct procdata data = { 0, 0, 0, 0, AFSCALL_PIOCTL };
248 data.param1 = (unsigned long)a_path;
249 data.param2 = (unsigned long)o_opcode;
250 data.param3 = (unsigned long)a_paramsP;
251 data.param4 = (unsigned long)a_followSymlinks;
252 return do_ioctl(&data);
254 case MACOS_DEV_POINT: {
255 struct devdata data = { AFSCALL_PIOCTL, 0, 0, 0, 0, 0, 0, 0 };
256 int ret;
258 data.param1 = (unsigned long)a_path;
259 data.param2 = (unsigned long)o_opcode;
260 data.param3 = (unsigned long)a_paramsP;
261 data.param4 = (unsigned long)a_followSymlinks;
263 ret = do_ioctl(&data);
264 if (ret)
265 return ret;
267 return data.retval;
269 #ifdef _AIX
270 case AIX_ENTRY_POINTS:
271 return Pioctl(a_path, o_opcode, a_paramsP, a_followSymlinks);
272 #endif
274 errno = ENOSYS;
275 #ifdef SIGSYS
276 kill(getpid(), SIGSYS); /* You lose! */
277 #endif
278 #endif /* NO_AFS */
279 return -1;
283 k_afs_cell_of_file(const char *path, char *cell, int len)
285 struct ViceIoctl parms;
286 parms.in = NULL;
287 parms.in_size = 0;
288 parms.out = cell;
289 parms.out_size = len;
290 return k_pioctl(rk_UNCONST(path), VIOC_FILE_CELL_NAME, &parms, 1);
294 k_unlog(void)
296 struct ViceIoctl parms;
297 memset(&parms, 0, sizeof(parms));
298 return k_pioctl(0, VIOCUNLOG, &parms, 0);
302 k_setpag(void)
304 #ifndef NO_AFS
305 switch(afs_entry_point){
306 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
307 case SINGLE_ENTRY_POINT:
308 case SINGLE_ENTRY_POINT2:
309 case SINGLE_ENTRY_POINT3:
310 return syscall(afs_syscalls[0], AFSCALL_SETPAG);
311 #endif
312 #if defined(AFS_PIOCTL)
313 case MULTIPLE_ENTRY_POINT:
314 return syscall(afs_syscalls[1]);
315 #endif
316 case LINUX_PROC_POINT: {
317 struct procdata data = { 0, 0, 0, 0, AFSCALL_SETPAG };
318 return do_ioctl(&data);
320 case MACOS_DEV_POINT: {
321 struct devdata data = { AFSCALL_SETPAG, 0, 0, 0, 0, 0, 0, 0 };
322 int ret = do_ioctl(&data);
323 if (ret)
324 return ret;
325 return data.retval;
327 #ifdef _AIX
328 case AIX_ENTRY_POINTS:
329 return Setpag();
330 #endif
333 errno = ENOSYS;
334 #ifdef SIGSYS
335 kill(getpid(), SIGSYS); /* You lose! */
336 #endif
337 #endif /* NO_AFS */
338 return -1;
341 static jmp_buf catch_SIGSYS;
343 #ifdef SIGSYS
345 static RETSIGTYPE
346 SIGSYS_handler(int sig)
348 errno = 0;
349 signal(SIGSYS, SIGSYS_handler); /* Need to reinstall handler on SYSV */
350 longjmp(catch_SIGSYS, 1);
353 #endif
356 * Try to see if `syscall' is a pioctl. Return 0 iff succesful.
359 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
360 static int
361 try_one (int syscall_num)
363 struct ViceIoctl parms;
364 memset(&parms, 0, sizeof(parms));
366 if (setjmp(catch_SIGSYS) == 0) {
367 syscall(syscall_num, AFSCALL_PIOCTL,
368 0, VIOCSETTOK, &parms, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
369 if (errno == EINVAL) {
370 afs_entry_point = SINGLE_ENTRY_POINT;
371 afs_syscalls[0] = syscall_num;
372 return 0;
375 return 1;
377 #endif
380 * Try to see if `syscall_pioctl' is a pioctl syscall. Return 0 iff
381 * succesful.
385 #ifdef AFS_PIOCTL
386 static int
387 try_two (int syscall_pioctl, int syscall_setpag)
389 struct ViceIoctl parms;
390 memset(&parms, 0, sizeof(parms));
392 if (setjmp(catch_SIGSYS) == 0) {
393 syscall(syscall_pioctl,
394 0, VIOCSETTOK, &parms, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
395 if (errno == EINVAL) {
396 afs_entry_point = MULTIPLE_ENTRY_POINT;
397 afs_syscalls[0] = syscall_pioctl;
398 afs_syscalls[1] = syscall_setpag;
399 return 0;
402 return 1;
404 #endif
407 k_hasafs(void)
409 #if !defined(NO_AFS) && defined(SIGSYS)
410 RETSIGTYPE (*saved_func)(int);
411 #endif
412 int saved_errno, ret;
413 char *env = NULL;
415 if (!issuid())
416 env = getenv ("AFS_SYSCALL");
419 * Already checked presence of AFS syscalls?
421 if (afs_entry_point != UNKNOWN_ENTRY_POINT)
422 return afs_entry_point != NO_ENTRY_POINT;
425 * Probe kernel for AFS specific syscalls,
426 * they (currently) come in two flavors.
427 * If the syscall is absent we recive a SIGSYS.
429 afs_entry_point = NO_ENTRY_POINT;
431 saved_errno = errno;
432 #ifndef NO_AFS
433 #ifdef SIGSYS
434 saved_func = signal(SIGSYS, SIGSYS_handler);
435 #endif
436 if (env && strstr(env, "..") == NULL) {
438 if (strncmp("/proc/", env, 6) == 0) {
439 if (try_ioctlpath(env, VIOC_SYSCALL_PROC, LINUX_PROC_POINT) == 0)
440 goto done;
442 if (strncmp("/dev/", env, 5) == 0) {
443 if (try_ioctlpath(env, VIOC_SYSCALL_DEV, MACOS_DEV_POINT) == 0)
444 goto done;
445 if (try_ioctlpath(env,VIOC_SYSCALL_DEV_OPENAFS,MACOS_DEV_POINT) ==0)
446 goto done;
450 ret = try_ioctlpath("/proc/fs/openafs/afs_ioctl",
451 VIOC_SYSCALL_PROC, LINUX_PROC_POINT);
452 if (ret == 0)
453 goto done;
454 ret = try_ioctlpath("/proc/fs/nnpfs/afs_ioctl",
455 VIOC_SYSCALL_PROC, LINUX_PROC_POINT);
456 if (ret == 0)
457 goto done;
459 ret = try_ioctlpath("/dev/openafs_ioctl",
460 VIOC_SYSCALL_DEV_OPENAFS, MACOS_DEV_POINT);
461 if (ret == 0)
462 goto done;
463 ret = try_ioctlpath("/dev/nnpfs_ioctl", VIOC_SYSCALL_DEV, MACOS_DEV_POINT);
464 if (ret == 0)
465 goto done;
467 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
469 int tmp;
471 if (env != NULL) {
472 if (sscanf (env, "%d", &tmp) == 1) {
473 if (try_one (tmp) == 0)
474 goto done;
475 } else {
476 char *end = NULL;
477 char *p;
478 char *s = strdup (env);
480 if (s != NULL) {
481 for (p = strtok_r (s, ",", &end);
482 p != NULL;
483 p = strtok_r (NULL, ",", &end)) {
484 if (map_syscall_name_to_number (p, &tmp) == 0)
485 if (try_one (tmp) == 0) {
486 free (s);
487 goto done;
490 free (s);
495 #endif /* AFS_SYSCALL || AFS_SYSCALL2 || AFS_SYSCALL3 */
497 #ifdef AFS_SYSCALL
498 if (try_one (AFS_SYSCALL) == 0)
499 goto done;
500 #endif /* AFS_SYSCALL */
502 #ifdef AFS_PIOCTL
504 int tmp[2];
506 if (env != NULL && sscanf (env, "%d%d", &tmp[0], &tmp[1]) == 2)
507 if (try_two (tmp[0], tmp[1]) == 2)
508 goto done;
510 #endif /* AFS_PIOCTL */
512 #ifdef AFS_PIOCTL
513 if (try_two (AFS_PIOCTL, AFS_SETPAG) == 0)
514 goto done;
515 #endif /* AFS_PIOCTL */
517 #ifdef AFS_SYSCALL2
518 if (try_one (AFS_SYSCALL2) == 0)
519 goto done;
520 #endif /* AFS_SYSCALL2 */
522 #ifdef AFS_SYSCALL3
523 if (try_one (AFS_SYSCALL3) == 0)
524 goto done;
525 #endif /* AFS_SYSCALL3 */
527 #ifdef _AIX
528 #if 0
529 if (env != NULL) {
530 char *pos = NULL;
531 char *pioctl_name;
532 char *setpag_name;
534 pioctl_name = strtok_r (env, ", \t", &pos);
535 if (pioctl_name != NULL) {
536 setpag_name = strtok_r (NULL, ", \t", &pos);
537 if (setpag_name != NULL)
538 if (try_aix (pioctl_name, setpag_name) == 0)
539 goto done;
542 #endif
544 if(try_aix() == 0)
545 goto done;
546 #endif
549 done:
550 #ifdef SIGSYS
551 signal(SIGSYS, saved_func);
552 #endif
553 #endif /* NO_AFS */
554 errno = saved_errno;
555 return afs_entry_point != NO_ENTRY_POINT;
559 k_hasafs_recheck(void)
561 afs_entry_point = UNKNOWN_ENTRY_POINT;
562 return k_hasafs();