Rename context handle lifetime to endtime
[heimdal.git] / lib / kafs / afssys.c
blobfe37c346b62b3906e31f36d1ba3c1470616bc295
1 /*
2 * Copyright (c) 1995 - 2000, 2002, 2004, 2005 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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 struct procdata {
37 unsigned long param4;
38 unsigned long param3;
39 unsigned long param2;
40 unsigned long param1;
41 unsigned long syscall;
43 #ifdef __GNU__
44 #define _IOT_procdata _IOT(_IOTS(long), 5, 0, 0, 0, 0)
45 #define VIOC_SYSCALL_PROC _IOW('C', 1, struct procdata)
46 #else
47 #define VIOC_SYSCALL_PROC _IOW('C', 1, void *)
48 #endif
50 struct devdata {
51 unsigned long syscall;
52 unsigned long param1;
53 unsigned long param2;
54 unsigned long param3;
55 unsigned long param4;
56 unsigned long param5;
57 unsigned long param6;
58 unsigned long retval;
60 #ifdef __GNU__
61 #define _IOT_devdata _IOT(_IOTS(long), 8, 0, 0, 0, 0)
62 #endif
63 #ifdef _IOWR
64 #define VIOC_SYSCALL_DEV _IOWR('C', 2, struct devdata)
65 #define VIOC_SYSCALL_DEV_OPENAFS _IOWR('C', 1, struct devdata)
66 #endif
68 #ifdef _IOW
69 #ifdef _ILP32
70 struct sundevdata {
71 uint32_t param6;
72 uint32_t param5;
73 uint32_t param4;
74 uint32_t param3;
75 uint32_t param2;
76 uint32_t param1;
77 uint32_t syscall;
79 #define VIOC_SUN_SYSCALL_DEV _IOW('C', 2, struct sundevdata)
80 #else
81 struct sundevdata {
82 uint64_t param6;
83 uint64_t param5;
84 uint64_t param4;
85 uint64_t param3;
86 uint64_t param2;
87 uint64_t param1;
88 uint64_t syscall;
90 #define VIOC_SUN_SYSCALL_DEV _IOW('C', 1, struct sundevdata)
91 #endif
92 #endif /* _IOW */
95 int _kafs_debug; /* this should be done in a better way */
97 #define UNKNOWN_ENTRY_POINT (-1)
98 #define NO_ENTRY_POINT 0
99 #define SINGLE_ENTRY_POINT 1
100 #define MULTIPLE_ENTRY_POINT 2
101 #define SINGLE_ENTRY_POINT2 3
102 #define SINGLE_ENTRY_POINT3 4
103 #define LINUX_PROC_POINT 5
104 #define AIX_ENTRY_POINTS 6
105 #define MACOS_DEV_POINT 7
106 #define SUN_PROC_POINT 8
108 static int afs_entry_point = UNKNOWN_ENTRY_POINT;
109 static int afs_syscalls[2];
110 static char *afs_ioctlpath;
111 static unsigned long afs_ioctlnum;
113 /* Magic to get AIX syscalls to work */
114 #ifdef _AIX
116 static int (*Pioctl)(char*, int, struct ViceIoctl*, int);
117 static int (*Setpag)(void);
119 #include "dlfcn.h"
125 static int
126 try_aix(void)
128 #ifdef STATIC_AFS_SYSCALLS
129 Pioctl = aix_pioctl;
130 Setpag = aix_setpag;
131 #else
132 void *ptr;
133 char path[MaxPathLen], *p;
135 * If we are root or running setuid don't trust AFSLIBPATH!
137 if (getuid() != 0 && !issuid() && (p = getenv("AFSLIBPATH")) != NULL)
138 strlcpy(path, p, sizeof(path));
139 else
140 snprintf(path, sizeof(path), "%s/afslib.so", LIBDIR);
142 ptr = dlopen(path, RTLD_NOW);
143 if(ptr == NULL) {
144 if(_kafs_debug) {
145 if(errno == ENOEXEC && (p = dlerror()) != NULL)
146 fprintf(stderr, "dlopen(%s): %s\n", path, p);
147 else if (errno != ENOENT)
148 fprintf(stderr, "dlopen(%s): %s\n", path, strerror(errno));
150 return 1;
152 Setpag = (int (*)(void))dlsym(ptr, "aix_setpag");
153 Pioctl = (int (*)(char*, int,
154 struct ViceIoctl*, int))dlsym(ptr, "aix_pioctl");
155 #endif
156 afs_entry_point = AIX_ENTRY_POINTS;
157 return 0;
159 #endif /* _AIX */
162 * This probably only works under Solaris and could get confused if
163 * there's a /etc/name_to_sysnum file.
166 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
168 #define _PATH_ETC_NAME_TO_SYSNUM "/etc/name_to_sysnum"
170 static int
171 map_syscall_name_to_number (const char *str, int *res)
173 FILE *f;
174 char buf[256];
175 size_t str_len = strlen (str);
177 f = fopen (_PATH_ETC_NAME_TO_SYSNUM, "r");
178 if (f == NULL)
179 return -1;
180 while (fgets (buf, sizeof(buf), f) != NULL) {
181 if (buf[0] == '#')
182 continue;
184 if (strncmp (str, buf, str_len) == 0) {
185 char *begptr = buf + str_len;
186 char *endptr;
187 long val = strtol (begptr, &endptr, 0);
189 if (val != 0 && endptr != begptr) {
190 fclose (f);
191 *res = val;
192 return 0;
196 fclose (f);
197 return -1;
199 #endif
201 static int
202 try_ioctlpath(const char *path, unsigned long ioctlnum, int entrypoint)
204 int fd, ret, saved_errno;
206 fd = open(path, O_RDWR);
207 if (fd < 0)
208 return 1;
209 switch (entrypoint) {
210 case LINUX_PROC_POINT: {
211 struct procdata data = { 0, 0, 0, 0, AFSCALL_PIOCTL };
212 data.param2 = (unsigned long)VIOCGETTOK;
213 ret = ioctl(fd, ioctlnum, &data);
214 break;
216 case MACOS_DEV_POINT: {
217 struct devdata data = { AFSCALL_PIOCTL, 0, 0, 0, 0, 0, 0, 0 };
218 data.param2 = (unsigned long)VIOCGETTOK;
219 ret = ioctl(fd, ioctlnum, &data);
220 break;
222 case SUN_PROC_POINT: {
223 struct sundevdata data = { 0, 0, 0, 0, 0, 0, AFSCALL_PIOCTL };
224 data.param2 = (unsigned long)VIOCGETTOK;
225 ret = ioctl(fd, ioctlnum, &data);
226 break;
228 default:
229 abort();
231 saved_errno = errno;
232 close(fd);
234 * Be quite liberal in what error are ok, the first is the one
235 * that should trigger given that params is NULL.
237 if (ret &&
238 (saved_errno != EFAULT &&
239 saved_errno != EDOM &&
240 saved_errno != ENOTCONN))
241 return 1;
242 afs_ioctlnum = ioctlnum;
243 afs_ioctlpath = strdup(path);
244 if (afs_ioctlpath == NULL)
245 return 1;
246 afs_entry_point = entrypoint;
247 return 0;
250 static int
251 do_ioctl(void *data)
253 int fd, ret, saved_errno;
254 fd = open(afs_ioctlpath, O_RDWR);
255 if (fd < 0) {
256 errno = EINVAL;
257 return -1;
259 ret = ioctl(fd, afs_ioctlnum, data);
260 saved_errno = errno;
261 close(fd);
262 errno = saved_errno;
263 return ret;
267 k_pioctl(char *a_path,
268 int o_opcode,
269 struct ViceIoctl *a_paramsP,
270 int a_followSymlinks)
272 #ifndef NO_AFS
273 switch(afs_entry_point){
274 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
275 case SINGLE_ENTRY_POINT:
276 case SINGLE_ENTRY_POINT2:
277 case SINGLE_ENTRY_POINT3:
278 return syscall(afs_syscalls[0], AFSCALL_PIOCTL,
279 a_path, o_opcode, a_paramsP, a_followSymlinks);
280 #endif
281 #if defined(AFS_PIOCTL)
282 case MULTIPLE_ENTRY_POINT:
283 return syscall(afs_syscalls[0],
284 a_path, o_opcode, a_paramsP, a_followSymlinks);
285 #endif
286 case LINUX_PROC_POINT: {
287 struct procdata data = { 0, 0, 0, 0, AFSCALL_PIOCTL };
288 data.param1 = (unsigned long)a_path;
289 data.param2 = (unsigned long)o_opcode;
290 data.param3 = (unsigned long)a_paramsP;
291 data.param4 = (unsigned long)a_followSymlinks;
292 return do_ioctl(&data);
294 case MACOS_DEV_POINT: {
295 struct devdata data = { AFSCALL_PIOCTL, 0, 0, 0, 0, 0, 0, 0 };
296 int ret;
298 data.param1 = (unsigned long)a_path;
299 data.param2 = (unsigned long)o_opcode;
300 data.param3 = (unsigned long)a_paramsP;
301 data.param4 = (unsigned long)a_followSymlinks;
303 ret = do_ioctl(&data);
304 if (ret)
305 return ret;
307 return data.retval;
309 case SUN_PROC_POINT: {
310 struct sundevdata data = { 0, 0, 0, 0, 0, 0, AFSCALL_PIOCTL };
311 data.param1 = (unsigned long)a_path;
312 data.param2 = (unsigned long)o_opcode;
313 data.param3 = (unsigned long)a_paramsP;
314 data.param4 = (unsigned long)a_followSymlinks;
315 return do_ioctl(&data);
317 #ifdef _AIX
318 case AIX_ENTRY_POINTS:
319 return Pioctl(a_path, o_opcode, a_paramsP, a_followSymlinks);
320 #endif
322 errno = ENOSYS;
323 #ifdef SIGSYS
324 kill(getpid(), SIGSYS); /* You lose! */
325 #endif
326 #endif /* NO_AFS */
327 return -1;
331 k_afs_cell_of_file(const char *path, char *cell, int len)
333 struct ViceIoctl parms;
334 parms.in = NULL;
335 parms.in_size = 0;
336 parms.out = cell;
337 parms.out_size = len;
338 return k_pioctl(rk_UNCONST(path), VIOC_FILE_CELL_NAME, &parms, 1);
342 k_unlog(void)
344 struct ViceIoctl parms;
345 memset(&parms, 0, sizeof(parms));
346 return k_pioctl(0, VIOCUNLOG, &parms, 0);
350 k_setpag(void)
352 #ifndef NO_AFS
353 switch(afs_entry_point){
354 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
355 case SINGLE_ENTRY_POINT:
356 case SINGLE_ENTRY_POINT2:
357 case SINGLE_ENTRY_POINT3:
358 return syscall(afs_syscalls[0], AFSCALL_SETPAG);
359 #endif
360 #if defined(AFS_PIOCTL)
361 case MULTIPLE_ENTRY_POINT:
362 return syscall(afs_syscalls[1]);
363 #endif
364 case LINUX_PROC_POINT: {
365 struct procdata data = { 0, 0, 0, 0, AFSCALL_SETPAG };
366 return do_ioctl(&data);
368 case MACOS_DEV_POINT: {
369 struct devdata data = { AFSCALL_SETPAG, 0, 0, 0, 0, 0, 0, 0 };
370 int ret = do_ioctl(&data);
371 if (ret)
372 return ret;
373 return data.retval;
375 case SUN_PROC_POINT: {
376 struct sundevdata data = { 0, 0, 0, 0, 0, 0, AFSCALL_SETPAG };
377 return do_ioctl(&data);
379 #ifdef _AIX
380 case AIX_ENTRY_POINTS:
381 return Setpag();
382 #endif
385 errno = ENOSYS;
386 #ifdef SIGSYS
387 kill(getpid(), SIGSYS); /* You lose! */
388 #endif
389 #endif /* NO_AFS */
390 return -1;
393 static jmp_buf catch_SIGSYS;
395 #ifdef SIGSYS
397 static RETSIGTYPE
398 SIGSYS_handler(int sig)
400 errno = 0;
401 signal(SIGSYS, SIGSYS_handler); /* Need to reinstall handler on SYSV */
402 longjmp(catch_SIGSYS, 1);
405 #endif
408 * Try to see if `syscall' is a pioctl. Return 0 iff succesful.
411 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
412 static int
413 try_one (int syscall_num)
415 struct ViceIoctl parms;
416 memset(&parms, 0, sizeof(parms));
418 if (setjmp(catch_SIGSYS) == 0) {
419 syscall(syscall_num, AFSCALL_PIOCTL,
420 0, VIOCSETTOK, &parms, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
421 if (errno == EINVAL) {
422 afs_entry_point = SINGLE_ENTRY_POINT;
423 afs_syscalls[0] = syscall_num;
424 return 0;
427 return 1;
429 #endif
432 * Try to see if `syscall_pioctl' is a pioctl syscall. Return 0 iff
433 * succesful.
437 #ifdef AFS_PIOCTL
438 static int
439 try_two (int syscall_pioctl, int syscall_setpag)
441 struct ViceIoctl parms;
442 memset(&parms, 0, sizeof(parms));
444 if (setjmp(catch_SIGSYS) == 0) {
445 syscall(syscall_pioctl,
446 0, VIOCSETTOK, &parms, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
447 if (errno == EINVAL) {
448 afs_entry_point = MULTIPLE_ENTRY_POINT;
449 afs_syscalls[0] = syscall_pioctl;
450 afs_syscalls[1] = syscall_setpag;
451 return 0;
454 return 1;
456 #endif
459 k_hasafs(void)
461 #if !defined(NO_AFS) && defined(SIGSYS)
462 RETSIGTYPE (*saved_func)(int);
463 #endif
464 int saved_errno, ret;
465 char *env = NULL;
467 if (!issuid())
468 env = getenv ("AFS_SYSCALL");
471 * Already checked presence of AFS syscalls?
473 if (afs_entry_point != UNKNOWN_ENTRY_POINT)
474 return afs_entry_point != NO_ENTRY_POINT;
477 * Probe kernel for AFS specific syscalls,
478 * they (currently) come in two flavors.
479 * If the syscall is absent we recive a SIGSYS.
481 afs_entry_point = NO_ENTRY_POINT;
483 saved_errno = errno;
484 #ifndef NO_AFS
485 #ifdef SIGSYS
486 saved_func = signal(SIGSYS, SIGSYS_handler);
487 #endif
488 if (env && strstr(env, "..") == NULL) {
490 if (strncmp("/proc/", env, 6) == 0) {
491 if (try_ioctlpath(env, VIOC_SYSCALL_PROC, LINUX_PROC_POINT) == 0)
492 goto done;
494 if (strncmp("/dev/", env, 5) == 0) {
495 #ifdef VIOC_SYSCALL_DEV
496 if (try_ioctlpath(env, VIOC_SYSCALL_DEV, MACOS_DEV_POINT) == 0)
497 goto done;
498 #endif
499 #ifdef VIOC_SYSCALL_DEV_OPENAFS
500 if (try_ioctlpath(env,VIOC_SYSCALL_DEV_OPENAFS,MACOS_DEV_POINT) ==0)
501 goto done;
502 #endif
506 ret = try_ioctlpath("/proc/fs/openafs/afs_ioctl",
507 VIOC_SYSCALL_PROC, LINUX_PROC_POINT);
508 if (ret == 0)
509 goto done;
510 ret = try_ioctlpath("/proc/fs/nnpfs/afs_ioctl",
511 VIOC_SYSCALL_PROC, LINUX_PROC_POINT);
512 if (ret == 0)
513 goto done;
515 #ifdef VIOC_SYSCALL_DEV_OPENAFS
516 ret = try_ioctlpath("/dev/openafs_ioctl",
517 VIOC_SYSCALL_DEV_OPENAFS, MACOS_DEV_POINT);
518 if (ret == 0)
519 goto done;
520 #endif
521 #ifdef VIOC_SYSCALL_DEV
522 ret = try_ioctlpath("/dev/nnpfs_ioctl", VIOC_SYSCALL_DEV, MACOS_DEV_POINT);
523 if (ret == 0)
524 goto done;
525 #endif
526 #ifdef VIOC_SUN_SYSCALL_DEV
527 ret = try_ioctlpath("/dev/afs", VIOC_SUN_SYSCALL_DEV, SUN_PROC_POINT);
528 if (ret == 0)
529 goto done;
530 #endif
533 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
535 int tmp;
537 if (env != NULL) {
538 if (sscanf (env, "%d", &tmp) == 1) {
539 if (try_one (tmp) == 0)
540 goto done;
541 } else {
542 char *end = NULL;
543 char *p;
544 char *s = strdup (env);
546 if (s != NULL) {
547 for (p = strtok_r (s, ",", &end);
548 p != NULL;
549 p = strtok_r (NULL, ",", &end)) {
550 if (map_syscall_name_to_number (p, &tmp) == 0)
551 if (try_one (tmp) == 0) {
552 free (s);
553 goto done;
556 free (s);
561 #endif /* AFS_SYSCALL || AFS_SYSCALL2 || AFS_SYSCALL3 */
563 #ifdef AFS_SYSCALL
564 if (try_one (AFS_SYSCALL) == 0)
565 goto done;
566 #endif /* AFS_SYSCALL */
568 #ifdef AFS_PIOCTL
570 int tmp[2];
572 if (env != NULL && sscanf (env, "%d%d", &tmp[0], &tmp[1]) == 2)
573 if (try_two (tmp[0], tmp[1]) == 2)
574 goto done;
576 #endif /* AFS_PIOCTL */
578 #ifdef AFS_PIOCTL
579 if (try_two (AFS_PIOCTL, AFS_SETPAG) == 0)
580 goto done;
581 #endif /* AFS_PIOCTL */
583 #ifdef AFS_SYSCALL2
584 if (try_one (AFS_SYSCALL2) == 0)
585 goto done;
586 #endif /* AFS_SYSCALL2 */
588 #ifdef AFS_SYSCALL3
589 if (try_one (AFS_SYSCALL3) == 0)
590 goto done;
591 #endif /* AFS_SYSCALL3 */
593 #ifdef _AIX
594 #if 0
595 if (env != NULL) {
596 char *pos = NULL;
597 char *pioctl_name;
598 char *setpag_name;
600 pioctl_name = strtok_r (env, ", \t", &pos);
601 if (pioctl_name != NULL) {
602 setpag_name = strtok_r (NULL, ", \t", &pos);
603 if (setpag_name != NULL)
604 if (try_aix (pioctl_name, setpag_name) == 0)
605 goto done;
608 #endif
610 if(try_aix() == 0)
611 goto done;
612 #endif
615 done:
616 #ifdef SIGSYS
617 signal(SIGSYS, saved_func);
618 #endif
619 #endif /* NO_AFS */
620 errno = saved_errno;
621 return afs_entry_point != NO_ENTRY_POINT;
625 k_hasafs_recheck(void)
627 afs_entry_point = UNKNOWN_ENTRY_POINT;
628 return k_hasafs();