1 /* 2 * Copyright (c) 1995, 1996, 1997, 1998, 1999 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. 12 * 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. 16 * 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. 20 * 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. 32 */ 33 34 #include "kafs_locl.h" 35 36 RCSID("$Id: afssys.c,v 1.65 1999/12/02 16:58:40 joda Exp $"); 37 38 int _kafs_debug; /* this should be done in a better way */ 39 40 #define NO_ENTRY_POINT 0 41 #define SINGLE_ENTRY_POINT 1 42 #define MULTIPLE_ENTRY_POINT 2 43 #define SINGLE_ENTRY_POINT2 3 44 #define SINGLE_ENTRY_POINT3 4 45 #define AIX_ENTRY_POINTS 5 46 #define UNKNOWN_ENTRY_POINT 6 47 static int afs_entry_point = UNKNOWN_ENTRY_POINT; 48 static int afs_syscalls[2]; 49 50 /* Magic to get AIX syscalls to work */ 51 #ifdef _AIX 52 53 static int (*Pioctl)(char*, int, struct ViceIoctl*, int); 54 static int (*Setpag)(void); 55 56 #include "dlfcn.h" 57 58 /* 59 * 60 */ 61 62 static int 63 try_aix(void) 64 { 65 #ifdef STATIC_AFS_SYSCALLS 66 Pioctl = aix_pioctl; 67 Setpag = aix_setpag; 68 #else 69 void *ptr; 70 char path[MaxPathLen], *p; 71 /* 72 * If we are root or running setuid don't trust AFSLIBPATH! 73 */ 74 if (getuid() != 0 && !issuid() && (p = getenv("AFSLIBPATH")) != NULL) 75 strlcpy(path, p, sizeof(path)); 76 else 77 snprintf(path, sizeof(path), "%s/afslib.so", LIBDIR); 78 79 ptr = dlopen(path, RTLD_NOW); 80 if(ptr == NULL) { 81 if(_kafs_debug) { 82 if(errno == ENOEXEC && (p = dlerror()) != NULL) 83 fprintf(stderr, "dlopen(%s): %s\n", path, p); 84 else if (errno != ENOENT) 85 fprintf(stderr, "dlopen(%s): %s\n", path, strerror(errno)); 86 } 87 return 1; 88 } 89 Setpag = (int (*)(void))dlsym(ptr, "aix_setpag"); 90 Pioctl = (int (*)(char*, int, 91 struct ViceIoctl*, int))dlsym(ptr, "aix_pioctl"); 92 #endif 93 afs_entry_point = AIX_ENTRY_POINTS; 94 return 0; 95 } 96 #endif /* _AIX */ 97 98 /* 99 * This probably only works under Solaris and could get confused if 100 * there's a /etc/name_to_sysnum file. 101 */ 102 103 #define _PATH_ETC_NAME_TO_SYSNUM "/etc/name_to_sysnum" 104 105 static int 106 map_syscall_name_to_number (const char *str, int *res) 107 { 108 FILE *f; 109 char buf[256]; 110 size_t str_len = strlen (str); 111 112 f = fopen (_PATH_ETC_NAME_TO_SYSNUM, "r"); 113 if (f == NULL) 114 return -1; 115 while (fgets (buf, sizeof(buf), f) != NULL) { 116 if (strncmp (str, buf, str_len) == 0) { 117 char *begptr = buf + str_len; 118 char *endptr; 119 long val = strtol (begptr, &endptr, 0); 120 121 if (val != 0 && endptr != begptr) { 122 fclose (f); 123 *res = val; 124 return 0; 125 } 126 } 127 } 128 fclose (f); 129 return -1; 130 } 131 132 int 133 k_pioctl(char *a_path, 134 int o_opcode, 135 struct ViceIoctl *a_paramsP, 136 int a_followSymlinks) 137 { 138 #ifndef NO_AFS 139 switch(afs_entry_point){ 140 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3) 141 case SINGLE_ENTRY_POINT: 142 case SINGLE_ENTRY_POINT2: 143 case SINGLE_ENTRY_POINT3: 144 return syscall(afs_syscalls[0], AFSCALL_PIOCTL, 145 a_path, o_opcode, a_paramsP, a_followSymlinks); 146 #endif 147 #if defined(AFS_PIOCTL) 148 case MULTIPLE_ENTRY_POINT: 149 return syscall(afs_syscalls[0], 150 a_path, o_opcode, a_paramsP, a_followSymlinks); 151 #endif 152 #ifdef _AIX 153 case AIX_ENTRY_POINTS: 154 return Pioctl(a_path, o_opcode, a_paramsP, a_followSymlinks); 155 #endif 156 } 157 158 errno = ENOSYS; 159 #ifdef SIGSYS 160 kill(getpid(), SIGSYS); /* You loose! */ 161 #endif 162 #endif /* NO_AFS */ 163 return -1; 164 } 165 166 int 167 k_afs_cell_of_file(const char *path, char *cell, int len) 168 { 169 struct ViceIoctl parms; 170 parms.in = NULL; 171 parms.in_size = 0; 172 parms.out = cell; 173 parms.out_size = len; 174 return k_pioctl((char*)path, VIOC_FILE_CELL_NAME, &parms, 1); 175 } 176 177 int 178 k_unlog(void) 179 { 180 struct ViceIoctl parms; 181 memset(&parms, 0, sizeof(parms)); 182 return k_pioctl(0, VIOCUNLOG, &parms, 0); 183 } 184 185 int 186 k_setpag(void) 187 { 188 #ifndef NO_AFS 189 switch(afs_entry_point){ 190 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3) 191 case SINGLE_ENTRY_POINT: 192 case SINGLE_ENTRY_POINT2: 193 case SINGLE_ENTRY_POINT3: 194 return syscall(afs_syscalls[0], AFSCALL_SETPAG); 195 #endif 196 #if defined(AFS_PIOCTL) 197 case MULTIPLE_ENTRY_POINT: 198 return syscall(afs_syscalls[1]); 199 #endif 200 #ifdef _AIX 201 case AIX_ENTRY_POINTS: 202 return Setpag(); 203 #endif 204 } 205 206 errno = ENOSYS; 207 #ifdef SIGSYS 208 kill(getpid(), SIGSYS); /* You loose! */ 209 #endif 210 #endif /* NO_AFS */ 211 return -1; 212 } 213 214 static jmp_buf catch_SIGSYS; 215 216 #ifdef SIGSYS 217 218 static RETSIGTYPE 219 SIGSYS_handler(int sig) 220 { 221 errno = 0; 222 signal(SIGSYS, SIGSYS_handler); /* Need to reinstall handler on SYSV */ 223 longjmp(catch_SIGSYS, 1); 224 } 225 226 #endif 227 228 /* 229 * Try to see if `syscall' is a pioctl. Return 0 iff succesful. 230 */ 231 232 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3) 233 static int 234 try_one (int syscall_num) 235 { 236 struct ViceIoctl parms; 237 memset(&parms, 0, sizeof(parms)); 238 239 if (setjmp(catch_SIGSYS) == 0) { 240 syscall(syscall_num, AFSCALL_PIOCTL, 241 0, VIOCSETTOK, &parms, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); 242 if (errno == EINVAL) { 243 afs_entry_point = SINGLE_ENTRY_POINT; 244 afs_syscalls[0] = syscall_num; 245 return 0; 246 } 247 } 248 return 1; 249 } 250 #endif 251 252 /* 253 * Try to see if `syscall_pioctl' is a pioctl syscall. Return 0 iff 254 * succesful. 255 * 256 */ 257 258 #ifdef AFS_PIOCTL 259 static int 260 try_two (int syscall_pioctl, int syscall_setpag) 261 { 262 struct ViceIoctl parms; 263 memset(&parms, 0, sizeof(parms)); 264 265 if (setjmp(catch_SIGSYS) == 0) { 266 syscall(syscall_pioctl, 267 0, VIOCSETTOK, &parms, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); 268 if (errno == EINVAL) { 269 afs_entry_point = MULTIPLE_ENTRY_POINT; 270 afs_syscalls[0] = syscall_pioctl; 271 afs_syscalls[1] = syscall_setpag; 272 return 0; 273 } 274 } 275 return 1; 276 } 277 #endif 278 279 int 280 k_hasafs(void) 281 { 282 #if !defined(NO_AFS) && defined(SIGSYS) 283 RETSIGTYPE (*saved_func)(); 284 #endif 285 int saved_errno; 286 char *env = getenv ("AFS_SYSCALL"); 287 288 /* 289 * Already checked presence of AFS syscalls? 290 */ 291 if (afs_entry_point != UNKNOWN_ENTRY_POINT) 292 return afs_entry_point != NO_ENTRY_POINT; 293 294 /* 295 * Probe kernel for AFS specific syscalls, 296 * they (currently) come in two flavors. 297 * If the syscall is absent we recive a SIGSYS. 298 */ 299 afs_entry_point = NO_ENTRY_POINT; 300 301 saved_errno = errno; 302 #ifndef NO_AFS 303 #ifdef SIGSYS 304 saved_func = signal(SIGSYS, SIGSYS_handler); 305 #endif 306 307 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3) 308 { 309 int tmp; 310 311 if (env != NULL) { 312 if (sscanf (env, "%d", &tmp) == 1) { 313 if (try_one (tmp) == 0) 314 goto done; 315 } else { 316 char *end = NULL; 317 char *p; 318 char *s = strdup (env); 319 320 if (s != NULL) { 321 for (p = strtok_r (s, ",", &end); 322 p != NULL; 323 p = strtok_r (NULL, ",", &end)) { 324 if (map_syscall_name_to_number (p, &tmp) == 0) 325 if (try_one (tmp) == 0) { 326 free (s); 327 goto done; 328 } 329 } 330 free (s); 331 } 332 } 333 } 334 } 335 #endif /* AFS_SYSCALL || AFS_SYSCALL2 || AFS_SYSCALL3 */ 336 337 #ifdef AFS_SYSCALL 338 if (try_one (AFS_SYSCALL) == 0) 339 goto done; 340 #endif /* AFS_SYSCALL */ 341 342 #ifdef AFS_PIOCTL 343 { 344 int tmp[2]; 345 346 if (env != NULL && sscanf (env, "%d%d", &tmp[0], &tmp[1]) == 2) 347 if (try_two (tmp[0], tmp[1]) == 2) 348 goto done; 349 } 350 #endif /* AFS_PIOCTL */ 351 352 #ifdef AFS_PIOCTL 353 if (try_two (AFS_PIOCTL, AFS_SETPAG) == 0) 354 goto done; 355 #endif /* AFS_PIOCTL */ 356 357 #ifdef AFS_SYSCALL2 358 if (try_one (AFS_SYSCALL2) == 0) 359 goto done; 360 #endif /* AFS_SYSCALL2 */ 361 362 #ifdef AFS_SYSCALL3 363 if (try_one (AFS_SYSCALL3) == 0) 364 goto done; 365 #endif /* AFS_SYSCALL3 */ 366 367 #ifdef _AIX 368 #if 0 369 if (env != NULL) { 370 char *pos = NULL; 371 char *pioctl_name; 372 char *setpag_name; 373 374 pioctl_name = strtok_r (env, ", \t", &pos); 375 if (pioctl_name != NULL) { 376 setpag_name = strtok_r (NULL, ", \t", &pos); 377 if (setpag_name != NULL) 378 if (try_aix (pioctl_name, setpag_name) == 0) 379 goto done; 380 } 381 } 382 #endif 383 384 if(try_aix() == 0) 385 goto done; 386 #endif 387 388 done: 389 #ifdef SIGSYS 390 signal(SIGSYS, saved_func); 391 #endif 392 #endif /* NO_AFS */ 393 errno = saved_errno; 394 return afs_entry_point != NO_ENTRY_POINT; 395 } 396