/crypto/heimdal/lib/kafs/afssys.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 570 lines · 443 code · 64 blank · 63 comment · 123 complexity · 9857744879098c0c467e3cd6e0096623 MD5 · raw file

  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.
  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. #include "kafs_locl.h"
  34. struct procdata {
  35. unsigned long param4;
  36. unsigned long param3;
  37. unsigned long param2;
  38. unsigned long param1;
  39. unsigned long syscall;
  40. };
  41. #define VIOC_SYSCALL_PROC _IOW('C', 1, void *)
  42. struct devdata {
  43. unsigned long syscall;
  44. unsigned long param1;
  45. unsigned long param2;
  46. unsigned long param3;
  47. unsigned long param4;
  48. unsigned long param5;
  49. unsigned long param6;
  50. unsigned long retval;
  51. };
  52. #ifdef _IOWR
  53. #define VIOC_SYSCALL_DEV _IOWR('C', 2, struct devdata)
  54. #define VIOC_SYSCALL_DEV_OPENAFS _IOWR('C', 1, struct devdata)
  55. #endif
  56. int _kafs_debug; /* this should be done in a better way */
  57. #define UNKNOWN_ENTRY_POINT (-1)
  58. #define NO_ENTRY_POINT 0
  59. #define SINGLE_ENTRY_POINT 1
  60. #define MULTIPLE_ENTRY_POINT 2
  61. #define SINGLE_ENTRY_POINT2 3
  62. #define SINGLE_ENTRY_POINT3 4
  63. #define LINUX_PROC_POINT 5
  64. #define AIX_ENTRY_POINTS 6
  65. #define MACOS_DEV_POINT 7
  66. static int afs_entry_point = UNKNOWN_ENTRY_POINT;
  67. static int afs_syscalls[2];
  68. static char *afs_ioctlpath;
  69. static unsigned long afs_ioctlnum;
  70. /* Magic to get AIX syscalls to work */
  71. #ifdef _AIX
  72. static int (*Pioctl)(char*, int, struct ViceIoctl*, int);
  73. static int (*Setpag)(void);
  74. #include "dlfcn.h"
  75. /*
  76. *
  77. */
  78. static int
  79. try_aix(void)
  80. {
  81. #ifdef STATIC_AFS_SYSCALLS
  82. Pioctl = aix_pioctl;
  83. Setpag = aix_setpag;
  84. #else
  85. void *ptr;
  86. char path[MaxPathLen], *p;
  87. /*
  88. * If we are root or running setuid don't trust AFSLIBPATH!
  89. */
  90. if (getuid() != 0 && !issuid() && (p = getenv("AFSLIBPATH")) != NULL)
  91. strlcpy(path, p, sizeof(path));
  92. else
  93. snprintf(path, sizeof(path), "%s/afslib.so", LIBDIR);
  94. ptr = dlopen(path, RTLD_NOW);
  95. if(ptr == NULL) {
  96. if(_kafs_debug) {
  97. if(errno == ENOEXEC && (p = dlerror()) != NULL)
  98. fprintf(stderr, "dlopen(%s): %s\n", path, p);
  99. else if (errno != ENOENT)
  100. fprintf(stderr, "dlopen(%s): %s\n", path, strerror(errno));
  101. }
  102. return 1;
  103. }
  104. Setpag = (int (*)(void))dlsym(ptr, "aix_setpag");
  105. Pioctl = (int (*)(char*, int,
  106. struct ViceIoctl*, int))dlsym(ptr, "aix_pioctl");
  107. #endif
  108. afs_entry_point = AIX_ENTRY_POINTS;
  109. return 0;
  110. }
  111. #endif /* _AIX */
  112. /*
  113. * This probably only works under Solaris and could get confused if
  114. * there's a /etc/name_to_sysnum file.
  115. */
  116. #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
  117. #define _PATH_ETC_NAME_TO_SYSNUM "/etc/name_to_sysnum"
  118. static int
  119. map_syscall_name_to_number (const char *str, int *res)
  120. {
  121. FILE *f;
  122. char buf[256];
  123. size_t str_len = strlen (str);
  124. f = fopen (_PATH_ETC_NAME_TO_SYSNUM, "r");
  125. if (f == NULL)
  126. return -1;
  127. while (fgets (buf, sizeof(buf), f) != NULL) {
  128. if (buf[0] == '#')
  129. continue;
  130. if (strncmp (str, buf, str_len) == 0) {
  131. char *begptr = buf + str_len;
  132. char *endptr;
  133. long val = strtol (begptr, &endptr, 0);
  134. if (val != 0 && endptr != begptr) {
  135. fclose (f);
  136. *res = val;
  137. return 0;
  138. }
  139. }
  140. }
  141. fclose (f);
  142. return -1;
  143. }
  144. #endif
  145. static int
  146. try_ioctlpath(const char *path, unsigned long ioctlnum, int entrypoint)
  147. {
  148. int fd, ret, saved_errno;
  149. fd = open(path, O_RDWR);
  150. if (fd < 0)
  151. return 1;
  152. switch (entrypoint) {
  153. case LINUX_PROC_POINT: {
  154. struct procdata data = { 0, 0, 0, 0, AFSCALL_PIOCTL };
  155. data.param2 = (unsigned long)VIOCGETTOK;
  156. ret = ioctl(fd, ioctlnum, &data);
  157. break;
  158. }
  159. case MACOS_DEV_POINT: {
  160. struct devdata data = { AFSCALL_PIOCTL, 0, 0, 0, 0, 0, 0, 0 };
  161. data.param2 = (unsigned long)VIOCGETTOK;
  162. ret = ioctl(fd, ioctlnum, &data);
  163. break;
  164. }
  165. default:
  166. abort();
  167. }
  168. saved_errno = errno;
  169. close(fd);
  170. /*
  171. * Be quite liberal in what error are ok, the first is the one
  172. * that should trigger given that params is NULL.
  173. */
  174. if (ret &&
  175. (saved_errno != EFAULT &&
  176. saved_errno != EDOM &&
  177. saved_errno != ENOTCONN))
  178. return 1;
  179. afs_ioctlnum = ioctlnum;
  180. afs_ioctlpath = strdup(path);
  181. if (afs_ioctlpath == NULL)
  182. return 1;
  183. afs_entry_point = entrypoint;
  184. return 0;
  185. }
  186. static int
  187. do_ioctl(void *data)
  188. {
  189. int fd, ret, saved_errno;
  190. fd = open(afs_ioctlpath, O_RDWR);
  191. if (fd < 0) {
  192. errno = EINVAL;
  193. return -1;
  194. }
  195. ret = ioctl(fd, afs_ioctlnum, data);
  196. saved_errno = errno;
  197. close(fd);
  198. errno = saved_errno;
  199. return ret;
  200. }
  201. int
  202. k_pioctl(char *a_path,
  203. int o_opcode,
  204. struct ViceIoctl *a_paramsP,
  205. int a_followSymlinks)
  206. {
  207. #ifndef NO_AFS
  208. switch(afs_entry_point){
  209. #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
  210. case SINGLE_ENTRY_POINT:
  211. case SINGLE_ENTRY_POINT2:
  212. case SINGLE_ENTRY_POINT3:
  213. return syscall(afs_syscalls[0], AFSCALL_PIOCTL,
  214. a_path, o_opcode, a_paramsP, a_followSymlinks);
  215. #endif
  216. #if defined(AFS_PIOCTL)
  217. case MULTIPLE_ENTRY_POINT:
  218. return syscall(afs_syscalls[0],
  219. a_path, o_opcode, a_paramsP, a_followSymlinks);
  220. #endif
  221. case LINUX_PROC_POINT: {
  222. struct procdata data = { 0, 0, 0, 0, AFSCALL_PIOCTL };
  223. data.param1 = (unsigned long)a_path;
  224. data.param2 = (unsigned long)o_opcode;
  225. data.param3 = (unsigned long)a_paramsP;
  226. data.param4 = (unsigned long)a_followSymlinks;
  227. return do_ioctl(&data);
  228. }
  229. case MACOS_DEV_POINT: {
  230. struct devdata data = { AFSCALL_PIOCTL, 0, 0, 0, 0, 0, 0, 0 };
  231. int ret;
  232. data.param1 = (unsigned long)a_path;
  233. data.param2 = (unsigned long)o_opcode;
  234. data.param3 = (unsigned long)a_paramsP;
  235. data.param4 = (unsigned long)a_followSymlinks;
  236. ret = do_ioctl(&data);
  237. if (ret)
  238. return ret;
  239. return data.retval;
  240. }
  241. #ifdef _AIX
  242. case AIX_ENTRY_POINTS:
  243. return Pioctl(a_path, o_opcode, a_paramsP, a_followSymlinks);
  244. #endif
  245. }
  246. errno = ENOSYS;
  247. #ifdef SIGSYS
  248. kill(getpid(), SIGSYS); /* You lose! */
  249. #endif
  250. #endif /* NO_AFS */
  251. return -1;
  252. }
  253. int
  254. k_afs_cell_of_file(const char *path, char *cell, int len)
  255. {
  256. struct ViceIoctl parms;
  257. parms.in = NULL;
  258. parms.in_size = 0;
  259. parms.out = cell;
  260. parms.out_size = len;
  261. return k_pioctl(rk_UNCONST(path), VIOC_FILE_CELL_NAME, &parms, 1);
  262. }
  263. int
  264. k_unlog(void)
  265. {
  266. struct ViceIoctl parms;
  267. memset(&parms, 0, sizeof(parms));
  268. return k_pioctl(0, VIOCUNLOG, &parms, 0);
  269. }
  270. int
  271. k_setpag(void)
  272. {
  273. #ifndef NO_AFS
  274. switch(afs_entry_point){
  275. #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
  276. case SINGLE_ENTRY_POINT:
  277. case SINGLE_ENTRY_POINT2:
  278. case SINGLE_ENTRY_POINT3:
  279. return syscall(afs_syscalls[0], AFSCALL_SETPAG);
  280. #endif
  281. #if defined(AFS_PIOCTL)
  282. case MULTIPLE_ENTRY_POINT:
  283. return syscall(afs_syscalls[1]);
  284. #endif
  285. case LINUX_PROC_POINT: {
  286. struct procdata data = { 0, 0, 0, 0, AFSCALL_SETPAG };
  287. return do_ioctl(&data);
  288. }
  289. case MACOS_DEV_POINT: {
  290. struct devdata data = { AFSCALL_SETPAG, 0, 0, 0, 0, 0, 0, 0 };
  291. int ret = do_ioctl(&data);
  292. if (ret)
  293. return ret;
  294. return data.retval;
  295. }
  296. #ifdef _AIX
  297. case AIX_ENTRY_POINTS:
  298. return Setpag();
  299. #endif
  300. }
  301. errno = ENOSYS;
  302. #ifdef SIGSYS
  303. kill(getpid(), SIGSYS); /* You lose! */
  304. #endif
  305. #endif /* NO_AFS */
  306. return -1;
  307. }
  308. static jmp_buf catch_SIGSYS;
  309. #ifdef SIGSYS
  310. static RETSIGTYPE
  311. SIGSYS_handler(int sig)
  312. {
  313. errno = 0;
  314. signal(SIGSYS, SIGSYS_handler); /* Need to reinstall handler on SYSV */
  315. longjmp(catch_SIGSYS, 1);
  316. }
  317. #endif
  318. /*
  319. * Try to see if `syscall' is a pioctl. Return 0 iff succesful.
  320. */
  321. #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
  322. static int
  323. try_one (int syscall_num)
  324. {
  325. struct ViceIoctl parms;
  326. memset(&parms, 0, sizeof(parms));
  327. if (setjmp(catch_SIGSYS) == 0) {
  328. syscall(syscall_num, AFSCALL_PIOCTL,
  329. 0, VIOCSETTOK, &parms, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  330. if (errno == EINVAL) {
  331. afs_entry_point = SINGLE_ENTRY_POINT;
  332. afs_syscalls[0] = syscall_num;
  333. return 0;
  334. }
  335. }
  336. return 1;
  337. }
  338. #endif
  339. /*
  340. * Try to see if `syscall_pioctl' is a pioctl syscall. Return 0 iff
  341. * succesful.
  342. *
  343. */
  344. #ifdef AFS_PIOCTL
  345. static int
  346. try_two (int syscall_pioctl, int syscall_setpag)
  347. {
  348. struct ViceIoctl parms;
  349. memset(&parms, 0, sizeof(parms));
  350. if (setjmp(catch_SIGSYS) == 0) {
  351. syscall(syscall_pioctl,
  352. 0, VIOCSETTOK, &parms, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  353. if (errno == EINVAL) {
  354. afs_entry_point = MULTIPLE_ENTRY_POINT;
  355. afs_syscalls[0] = syscall_pioctl;
  356. afs_syscalls[1] = syscall_setpag;
  357. return 0;
  358. }
  359. }
  360. return 1;
  361. }
  362. #endif
  363. int
  364. k_hasafs(void)
  365. {
  366. #if !defined(NO_AFS) && defined(SIGSYS)
  367. RETSIGTYPE (*saved_func)(int);
  368. #endif
  369. int saved_errno, ret;
  370. char *env = NULL;
  371. if (!issuid())
  372. env = getenv ("AFS_SYSCALL");
  373. /*
  374. * Already checked presence of AFS syscalls?
  375. */
  376. if (afs_entry_point != UNKNOWN_ENTRY_POINT)
  377. return afs_entry_point != NO_ENTRY_POINT;
  378. /*
  379. * Probe kernel for AFS specific syscalls,
  380. * they (currently) come in two flavors.
  381. * If the syscall is absent we recive a SIGSYS.
  382. */
  383. afs_entry_point = NO_ENTRY_POINT;
  384. saved_errno = errno;
  385. #ifndef NO_AFS
  386. #ifdef SIGSYS
  387. saved_func = signal(SIGSYS, SIGSYS_handler);
  388. #endif
  389. if (env && strstr(env, "..") == NULL) {
  390. if (strncmp("/proc/", env, 6) == 0) {
  391. if (try_ioctlpath(env, VIOC_SYSCALL_PROC, LINUX_PROC_POINT) == 0)
  392. goto done;
  393. }
  394. if (strncmp("/dev/", env, 5) == 0) {
  395. #ifdef VIOC_SYSCALL_DEV
  396. if (try_ioctlpath(env, VIOC_SYSCALL_DEV, MACOS_DEV_POINT) == 0)
  397. goto done;
  398. #endif
  399. #ifdef VIOC_SYSCALL_DEV_OPENAFS
  400. if (try_ioctlpath(env,VIOC_SYSCALL_DEV_OPENAFS,MACOS_DEV_POINT) ==0)
  401. goto done;
  402. #endif
  403. }
  404. }
  405. ret = try_ioctlpath("/proc/fs/openafs/afs_ioctl",
  406. VIOC_SYSCALL_PROC, LINUX_PROC_POINT);
  407. if (ret == 0)
  408. goto done;
  409. ret = try_ioctlpath("/proc/fs/nnpfs/afs_ioctl",
  410. VIOC_SYSCALL_PROC, LINUX_PROC_POINT);
  411. if (ret == 0)
  412. goto done;
  413. #ifdef VIOC_SYSCALL_DEV_OPENAFS
  414. ret = try_ioctlpath("/dev/openafs_ioctl",
  415. VIOC_SYSCALL_DEV_OPENAFS, MACOS_DEV_POINT);
  416. if (ret == 0)
  417. goto done;
  418. #endif
  419. #ifdef VIOC_SYSCALL_DEV
  420. ret = try_ioctlpath("/dev/nnpfs_ioctl", VIOC_SYSCALL_DEV, MACOS_DEV_POINT);
  421. if (ret == 0)
  422. goto done;
  423. #endif
  424. #if defined(AFS_SYSCALL) || defined(AFS_SYSCALL2) || defined(AFS_SYSCALL3)
  425. {
  426. int tmp;
  427. if (env != NULL) {
  428. if (sscanf (env, "%d", &tmp) == 1) {
  429. if (try_one (tmp) == 0)
  430. goto done;
  431. } else {
  432. char *end = NULL;
  433. char *p;
  434. char *s = strdup (env);
  435. if (s != NULL) {
  436. for (p = strtok_r (s, ",", &end);
  437. p != NULL;
  438. p = strtok_r (NULL, ",", &end)) {
  439. if (map_syscall_name_to_number (p, &tmp) == 0)
  440. if (try_one (tmp) == 0) {
  441. free (s);
  442. goto done;
  443. }
  444. }
  445. free (s);
  446. }
  447. }
  448. }
  449. }
  450. #endif /* AFS_SYSCALL || AFS_SYSCALL2 || AFS_SYSCALL3 */
  451. #ifdef AFS_SYSCALL
  452. if (try_one (AFS_SYSCALL) == 0)
  453. goto done;
  454. #endif /* AFS_SYSCALL */
  455. #ifdef AFS_PIOCTL
  456. {
  457. int tmp[2];
  458. if (env != NULL && sscanf (env, "%d%d", &tmp[0], &tmp[1]) == 2)
  459. if (try_two (tmp[0], tmp[1]) == 2)
  460. goto done;
  461. }
  462. #endif /* AFS_PIOCTL */
  463. #ifdef AFS_PIOCTL
  464. if (try_two (AFS_PIOCTL, AFS_SETPAG) == 0)
  465. goto done;
  466. #endif /* AFS_PIOCTL */
  467. #ifdef AFS_SYSCALL2
  468. if (try_one (AFS_SYSCALL2) == 0)
  469. goto done;
  470. #endif /* AFS_SYSCALL2 */
  471. #ifdef AFS_SYSCALL3
  472. if (try_one (AFS_SYSCALL3) == 0)
  473. goto done;
  474. #endif /* AFS_SYSCALL3 */
  475. #ifdef _AIX
  476. #if 0
  477. if (env != NULL) {
  478. char *pos = NULL;
  479. char *pioctl_name;
  480. char *setpag_name;
  481. pioctl_name = strtok_r (env, ", \t", &pos);
  482. if (pioctl_name != NULL) {
  483. setpag_name = strtok_r (NULL, ", \t", &pos);
  484. if (setpag_name != NULL)
  485. if (try_aix (pioctl_name, setpag_name) == 0)
  486. goto done;
  487. }
  488. }
  489. #endif
  490. if(try_aix() == 0)
  491. goto done;
  492. #endif
  493. done:
  494. #ifdef SIGSYS
  495. signal(SIGSYS, saved_func);
  496. #endif
  497. #endif /* NO_AFS */
  498. errno = saved_errno;
  499. return afs_entry_point != NO_ENTRY_POINT;
  500. }
  501. int
  502. k_hasafs_recheck(void)
  503. {
  504. afs_entry_point = UNKNOWN_ENTRY_POINT;
  505. return k_hasafs();
  506. }