1 /* 2 * Copyright (c) 1995 - 200 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.67 2000/07/08 12:06:03 assar 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 (buf[0] == '#') 117 continue; 118 119 if (strncmp (str, buf, str_len) == 0) { 120 char *begptr = buf + str_len; 121 char *endptr; 122 long val = strtol (begptr, &endptr, 0); 123 124 if (val != 0 && endptr != begptr) { 125 fclose (f); 126 *res = val; 127 return 0; 128 } 129 } 130 } 131 fclose (f); 132 return -1; 133 } 134 135 int 136 k_pioctl(char *a_path, 137 int o_opcode, 138 struct ViceIoctl *a_paramsP, 139 int a_followSymlinks) 140 { 141 #ifndef NO_AFS 142 switch(afs_entry_point){ 143 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3) 144 case SINGLE_ENTRY_POINT: 145 case SINGLE_ENTRY_POINT2: 146 case SINGLE_ENTRY_POINT3: 147 return syscall(afs_syscalls[0], AFSCALL_PIOCTL, 148 a_path, o_opcode, a_paramsP, a_followSymlinks); 149 #endif 150 #if defined(AFS_PIOCTL) 151 case MULTIPLE_ENTRY_POINT: 152 return syscall(afs_syscalls[0], 153 a_path, o_opcode, a_paramsP, a_followSymlinks); 154 #endif 155 #ifdef _AIX 156 case AIX_ENTRY_POINTS: 157 return Pioctl(a_path, o_opcode, a_paramsP, a_followSymlinks); 158 #endif 159 } 160 161 errno = ENOSYS; 162 #ifdef SIGSYS 163 kill(getpid(), SIGSYS); /* You loose! */ 164 #endif 165 #endif /* NO_AFS */ 166 return -1; 167 } 168 169 int 170 k_afs_cell_of_file(const char *path, char *cell, int len) 171 { 172 struct ViceIoctl parms; 173 parms.in = NULL; 174 parms.in_size = 0; 175 parms.out = cell; 176 parms.out_size = len; 177 return k_pioctl((char*)path, VIOC_FILE_CELL_NAME, &parms, 1); 178 } 179 180 int 181 k_unlog(void) 182 { 183 struct ViceIoctl parms; 184 memset(&parms, 0, sizeof(parms)); 185 return k_pioctl(0, VIOCUNLOG, &parms, 0); 186 } 187 188 int 189 k_setpag(void) 190 { 191 #ifndef NO_AFS 192 switch(afs_entry_point){ 193 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3) 194 case SINGLE_ENTRY_POINT: 195 case SINGLE_ENTRY_POINT2: 196 case SINGLE_ENTRY_POINT3: 197 return syscall(afs_syscalls[0], AFSCALL_SETPAG); 198 #endif 199 #if defined(AFS_PIOCTL) 200 case MULTIPLE_ENTRY_POINT: 201 return syscall(afs_syscalls[1]); 202 #endif 203 #ifdef _AIX 204 case AIX_ENTRY_POINTS: 205 return Setpag(); 206 #endif 207 } 208 209 errno = ENOSYS; 210 #ifdef SIGSYS 211 kill(getpid(), SIGSYS); /* You loose! */ 212 #endif 213 #endif /* NO_AFS */ 214 return -1; 215 } 216 217 static jmp_buf catch_SIGSYS; 218 219 #ifdef SIGSYS 220 221 static RETSIGTYPE 222 SIGSYS_handler(int sig) 223 { 224 errno = 0; 225 signal(SIGSYS, SIGSYS_handler); /* Need to reinstall handler on SYSV */ 226 longjmp(catch_SIGSYS, 1); 227 } 228 229 #endif 230 231 /* 232 * Try to see if `syscall' is a pioctl. Return 0 iff succesful. 233 */ 234 235 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3) 236 static int 237 try_one (int syscall_num) 238 { 239 struct ViceIoctl parms; 240 memset(&parms, 0, sizeof(parms)); 241 242 if (setjmp(catch_SIGSYS) == 0) { 243 syscall(syscall_num, AFSCALL_PIOCTL, 244 0, VIOCSETTOK, &parms, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); 245 if (errno == EINVAL) { 246 afs_entry_point = SINGLE_ENTRY_POINT; 247 afs_syscalls[0] = syscall_num; 248 return 0; 249 } 250 } 251 return 1; 252 } 253 #endif 254 255 /* 256 * Try to see if `syscall_pioctl' is a pioctl syscall. Return 0 iff 257 * succesful. 258 * 259 */ 260 261 #ifdef AFS_PIOCTL 262 static int 263 try_two (int syscall_pioctl, int syscall_setpag) 264 { 265 struct ViceIoctl parms; 266 memset(&parms, 0, sizeof(parms)); 267 268 if (setjmp(catch_SIGSYS) == 0) { 269 syscall(syscall_pioctl, 270 0, VIOCSETTOK, &parms, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); 271 if (errno == EINVAL) { 272 afs_entry_point = MULTIPLE_ENTRY_POINT; 273 afs_syscalls[0] = syscall_pioctl; 274 afs_syscalls[1] = syscall_setpag; 275 return 0; 276 } 277 } 278 return 1; 279 } 280 #endif 281 282 int 283 k_hasafs(void) 284 { 285 #if !defined(NO_AFS) && defined(SIGSYS) 286 RETSIGTYPE (*saved_func)(int); 287 #endif 288 int saved_errno; 289 char *env = getenv ("AFS_SYSCALL"); 290 291 /* 292 * Already checked presence of AFS syscalls? 293 */ 294 if (afs_entry_point != UNKNOWN_ENTRY_POINT) 295 return afs_entry_point != NO_ENTRY_POINT; 296 297 /* 298 * Probe kernel for AFS specific syscalls, 299 * they (currently) come in two flavors. 300 * If the syscall is absent we recive a SIGSYS. 301 */ 302 afs_entry_point = NO_ENTRY_POINT; 303 304 saved_errno = errno; 305 #ifndef NO_AFS 306 #ifdef SIGSYS 307 saved_func = signal(SIGSYS, SIGSYS_handler); 308 #endif 309 310 #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3) 311 { 312 int tmp; 313 314 if (env != NULL) { 315 if (sscanf (env, "%d", &tmp) == 1) { 316 if (try_one (tmp) == 0) 317 goto done; 318 } else { 319 char *end = NULL; 320 char *p; 321 char *s = strdup (env); 322 323 if (s != NULL) { 324 for (p = strtok_r (s, ",", &end); 325 p != NULL; 326 p = strtok_r (NULL, ",", &end)) { 327 if (map_syscall_name_to_number (p, &tmp) == 0) 328 if (try_one (tmp) == 0) { 329 free (s); 330 goto done; 331 } 332 } 333 free (s); 334 } 335 } 336 } 337 } 338 #endif /* AFS_SYSCALL || AFS_SYSCALL2 || AFS_SYSCALL3 */ 339 340 #ifdef AFS_SYSCALL 341 if (try_one (AFS_SYSCALL) == 0) 342 goto done; 343 #endif /* AFS_SYSCALL */ 344 345 #ifdef AFS_PIOCTL 346 { 347 int tmp[2]; 348 349 if (env != NULL && sscanf (env, "%d%d", &tmp[0], &tmp[1]) == 2) 350 if (try_two (tmp[0], tmp[1]) == 2) 351 goto done; 352 } 353 #endif /* AFS_PIOCTL */ 354 355 #ifdef AFS_PIOCTL 356 if (try_two (AFS_PIOCTL, AFS_SETPAG) == 0) 357 goto done; 358 #endif /* AFS_PIOCTL */ 359 360 #ifdef AFS_SYSCALL2 361 if (try_one (AFS_SYSCALL2) == 0) 362 goto done; 363 #endif /* AFS_SYSCALL2 */ 364 365 #ifdef AFS_SYSCALL3 366 if (try_one (AFS_SYSCALL3) == 0) 367 goto done; 368 #endif /* AFS_SYSCALL3 */ 369 370 #ifdef _AIX 371 #if 0 372 if (env != NULL) { 373 char *pos = NULL; 374 char *pioctl_name; 375 char *setpag_name; 376 377 pioctl_name = strtok_r (env, ", \t", &pos); 378 if (pioctl_name != NULL) { 379 setpag_name = strtok_r (NULL, ", \t", &pos); 380 if (setpag_name != NULL) 381 if (try_aix (pioctl_name, setpag_name) == 0) 382 goto done; 383 } 384 } 385 #endif 386 387 if(try_aix() == 0) 388 goto done; 389 #endif 390 391 done: 392 #ifdef SIGSYS 393 signal(SIGSYS, saved_func); 394 #endif 395 #endif /* NO_AFS */ 396 errno = saved_errno; 397 return afs_entry_point != NO_ENTRY_POINT; 398 } 399