This source file includes following definitions.
- xfs_crcopy
- sys_xfspioctl
- xfs_is_pag
- xfs_get_pag
- store_pag
- xfs_setpag_call
- xfs_unpag
- xfs_setgroups
- lookup_node
- getfh_compat
- trad_fhget
- fhget_call
- fhopen_call
- remote_pioctl
- xfs_debug
- xfs_pioctl_call
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 #include <xfs/xfs_locl.h>
35
36 RCSID("$arla: xfs_syscalls-common.c,v 1.72 2003/01/19 20:53:49 lha Exp $");
37
38
39
40
41
42 #include <xfs/xfs_syscalls.h>
43 #include <xfs/xfs_message.h>
44 #include <xfs/xfs_fs.h>
45 #include <xfs/xfs_dev.h>
46 #include <xfs/xfs_node.h>
47 #include <xfs/xfs_vfsops.h>
48 #include <xfs/xfs_deb.h>
49
50
51 #ifdef HAVE_SYS_IOCCOM_H
52 #include <sys/ioccom.h>
53 #elif defined(HAVE_SYS_IOCTL_H)
54 #include <sys/ioctl.h>
55 #endif
56
57
58
59
60 #if (defined(__OpenBSD__) || defined(__NetBSD__)) && !defined(_LKM)
61 #define NNPFS_NOT_LKM 1
62 #elif defined(__FreeBSD__) && !defined(KLD_MODULE)
63 #define NNPFS_NOT_LKM 1
64 #endif
65
66 #ifdef NNPFS_NOT_LKM
67 #include <xfs/xfs_pioctl.h>
68 #else
69 #include <kafs.h>
70 #endif
71
72 int (*old_setgroups_func)(syscall_d_thread_t *p, void *v, register_t *retval);
73
74 #if defined(__FreeBSD__) && __FreeBSD_version >= 500026
75
76
77
78 static struct ucred *
79 xfs_crcopy(struct ucred *cr)
80 {
81 struct ucred *ncr;
82
83 if (crshared(cr)) {
84 ncr = crdup(cr);
85 crfree(cr);
86 return ncr;
87 }
88 return cr;
89 }
90 #else
91 #define xfs_crcopy crcopy
92 #endif
93
94
95
96
97
98
99 #ifdef NNPFS_NOT_LKM
100 int
101 sys_xfspioctl(syscall_d_thread_t *proc, void *varg, register_t *return_value)
102 #else
103 int
104 xfspioctl(syscall_d_thread_t *proc, void *varg, register_t *return_value)
105 #endif
106 {
107 #ifdef NNPFS_NOT_LKM
108 struct sys_xfspioctl_args *arg = (struct sys_xfspioctl_args *) varg;
109 #else
110 struct sys_pioctl_args *arg = (struct sys_pioctl_args *) varg;
111 #endif
112 int error = EINVAL;
113
114 switch (SCARG(arg, operation)) {
115 case AFSCALL_PIOCTL:
116 error = xfs_pioctl_call(syscall_thread_to_thread(proc),
117 varg, return_value);
118 break;
119 case AFSCALL_SETPAG:
120 #ifdef HAVE_FREEBSD_THREAD
121 error = xfs_setpag_call(&xfs_thread_to_cred(proc));
122 #else
123 error = xfs_setpag_call(&xfs_proc_to_cred(syscall_thread_to_thread(proc)));
124 #endif
125 break;
126 default:
127 NNPFSDEB(XDEBSYS, ("Unimplemeted xfspioctl: %d\n",
128 SCARG(arg, operation)));
129 error = EINVAL;
130 break;
131 }
132
133 return error;
134 }
135
136
137
138
139
140
141
142 #define NNPFS_PAG1_LLIM 33536
143 #define NNPFS_PAG1_ULIM 34560
144 #define NNPFS_PAG2_LLIM 32512
145 #define NNPFS_PAG2_ULIM 48896
146
147 static gid_t pag_part_one = NNPFS_PAG1_LLIM;
148 static gid_t pag_part_two = NNPFS_PAG2_LLIM;
149
150
151
152
153
154 static int
155 xfs_is_pag(struct ucred *cred)
156 {
157
158
159 if (cred->cr_ngroups >= 3 &&
160 cred->cr_groups[1] >= NNPFS_PAG1_LLIM &&
161 cred->cr_groups[1] <= NNPFS_PAG1_ULIM &&
162 cred->cr_groups[2] >= NNPFS_PAG2_LLIM &&
163 cred->cr_groups[2] <= NNPFS_PAG2_ULIM)
164 return 1;
165 else
166 return 0;
167 }
168
169
170
171
172
173 xfs_pag_t
174 xfs_get_pag(struct ucred *cred)
175 {
176 if (xfs_is_pag(cred)) {
177
178 return (((cred->cr_groups[1] << 16) & 0xFFFF0000) |
179 ((cred->cr_groups[2] & 0x0000FFFF)));
180
181 } else
182 return cred->cr_uid;
183 }
184
185
186
187
188
189 static int
190 store_pag (struct ucred **ret_cred, gid_t part1, gid_t part2)
191 {
192 struct ucred *cred = *ret_cred;
193
194 if (!xfs_is_pag (cred)) {
195 int i;
196
197 if (cred->cr_ngroups + 2 >= NGROUPS)
198 return E2BIG;
199
200 cred = xfs_crcopy (cred);
201
202 for (i = cred->cr_ngroups - 1; i > 0; i--) {
203 cred->cr_groups[i + 2] = cred->cr_groups[i];
204 }
205 cred->cr_ngroups += 2;
206 } else {
207 cred = xfs_crcopy (cred);
208 }
209 cred->cr_groups[1] = part1;
210 cred->cr_groups[2] = part2;
211 *ret_cred = cred;
212
213 return 0;
214 }
215
216
217
218
219
220 int
221 xfs_setpag_call(struct ucred **ret_cred)
222 {
223 int ret;
224
225 ret = store_pag (ret_cred, pag_part_one, pag_part_two++);
226 if (ret)
227 return ret;
228
229 if (pag_part_two > NNPFS_PAG2_ULIM) {
230 pag_part_one++;
231 pag_part_two = NNPFS_PAG2_LLIM;
232 }
233 return 0;
234 }
235
236 #ifndef NNPFS_NOT_LKM
237
238
239
240
241 static int
242 xfs_unpag (struct ucred *cred)
243 {
244 while (xfs_is_pag (cred)) {
245 int i;
246
247 for (i = 0; i < cred->cr_ngroups - 2; ++i)
248 cred->cr_groups[i] = cred->cr_groups[i+2];
249 cred->cr_ngroups -= 2;
250 }
251 return 0;
252 }
253
254
255
256
257
258 int
259 xfs_setgroups (syscall_d_thread_t *p,
260 void *varg,
261 register_t *retval)
262 {
263 struct xfs_setgroups_args *uap = (struct xfs_setgroups_args *)varg;
264 #ifdef HAVE_FREEBSD_THREAD
265 struct ucred **cred = &xfs_thread_to_cred(p);
266 #else
267 struct ucred **cred = &xfs_proc_to_cred(syscall_thread_to_thread(p));
268 #endif
269
270 if (xfs_is_pag (*cred)) {
271 gid_t part1, part2;
272 int ret;
273
274 if (SCARG(uap,gidsetsize) + 2 > NGROUPS)
275 return EINVAL;
276
277 part1 = (*cred)->cr_groups[1];
278 part2 = (*cred)->cr_groups[2];
279 ret = (*old_setgroups_func) (p, uap, retval);
280 if (ret)
281 return ret;
282 return store_pag (cred, part1, part2);
283 } else {
284 int ret;
285
286 ret = (*old_setgroups_func) (p, uap, retval);
287
288 if (xfs_is_pag (*cred)) {
289 xfs_unpag (*cred);
290 return EINVAL;
291 }
292 return ret;
293 }
294 }
295 #endif
296
297
298
299
300
301 static int
302 lookup_node (const char *pathptr,
303 int follow_links_p,
304 struct vnode **res,
305 d_thread_t *proc)
306 {
307 int error;
308 char path[MAXPATHLEN];
309 #ifdef __osf__
310 struct nameidata *ndp = &u.u_nd;
311 #else
312 struct nameidata nd, *ndp = &nd;
313 #endif
314 struct vnode *vp;
315 size_t count;
316
317 NNPFSDEB(XDEBSYS, ("xfs_syscall: looking up: %lx\n",
318 (unsigned long)pathptr));
319
320 error = copyinstr((char *) pathptr, path, MAXPATHLEN, &count);
321
322 NNPFSDEB(XDEBSYS, ("xfs_syscall: looking up: %s, error: %d\n", path, error));
323
324 if (error)
325 return error;
326
327 NDINIT(ndp, LOOKUP,
328 follow_links_p ? FOLLOW : 0,
329 UIO_SYSSPACE, path, proc);
330
331 error = namei(ndp);
332
333 if (error != 0) {
334 NNPFSDEB(XDEBSYS, ("xfs_syscall: error during namei: %d\n", error));
335 return EINVAL;
336 }
337
338 vp = ndp->ni_vp;
339
340 *res = vp;
341 return 0;
342 }
343
344
345
346
347
348
349 static int
350 getfh_compat (d_thread_t *p,
351 struct ViceIoctl *vice_ioctl,
352 struct vnode *vp)
353 {
354
355 fhandle_t fh;
356 int error;
357
358 bzero((caddr_t)&fh, sizeof(fh));
359 fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
360 #if __osf__
361 VFS_VPTOFH(vp, &fh.fh_fid, error);
362 #else
363 error = VFS_VPTOFH(vp, &fh.fh_fid);
364 #endif
365 if (error)
366 return error;
367
368 if (vice_ioctl->out_size < sizeof(fh))
369 return EINVAL;
370
371 return copyout((caddr_t)&fh, vice_ioctl->out, sizeof (fh));
372 }
373
374
375
376
377
378 #ifndef __OpenBSD__
379 static int
380 trad_fhget (d_thread_t *p,
381 struct ViceIoctl *vice_ioctl,
382 struct vnode *vp)
383 {
384 int error;
385 struct mount *mnt;
386 struct vattr vattr;
387 size_t len;
388 struct xfs_fhandle_t xfs_handle;
389 struct xfs_fh_args fh_args;
390
391 #ifdef HAVE_FREEBSD_THREAD
392 xfs_vop_getattr(vp, &vattr, xfs_thread_to_cred(p), p, error);
393 #else
394 xfs_vop_getattr(vp, &vattr, xfs_proc_to_cred(p), p, error);
395 #endif
396 if (error)
397 return error;
398
399 mnt = vp->v_mount;
400
401 SCARG(&fh_args, fsid) = mnt->mnt_stat.f_fsid;
402 SCARG(&fh_args, fileid) = vattr.va_fileid;
403 SCARG(&fh_args, gen) = vattr.va_gen;
404
405 xfs_handle.len = sizeof(fh_args);
406 memcpy (xfs_handle.fhdata, &fh_args, sizeof(fh_args));
407 len = sizeof(xfs_handle);
408
409 if (vice_ioctl->out_size < len)
410 return EINVAL;
411
412 error = copyout (&xfs_handle, vice_ioctl->out, len);
413 if (error) {
414 NNPFSDEB(XDEBSYS, ("fhget_call: copyout failed: %d\n", error));
415 }
416 return error;
417 }
418 #endif
419
420
421
422
423
424
425 static int
426 fhget_call (d_thread_t *p,
427 struct ViceIoctl *vice_ioctl,
428 struct vnode *vp)
429 {
430 int error;
431
432 NNPFSDEB(XDEBSYS, ("fhget_call\n"));
433
434 if (vp == NULL)
435 return EBADF;
436
437 #if defined(__APPLE__) || defined(__osf__)
438 error = EINVAL;
439 goto out;
440 #endif
441
442 error = xfs_suser (p);
443 if (error)
444 goto out;
445
446 #if (defined(HAVE_GETFH) && defined(HAVE_FHOPEN)) || defined(__osf__)
447 error = getfh_compat (p, vice_ioctl, vp);
448 #else
449 error = trad_fhget (p, vice_ioctl, vp);
450 #endif
451 out:
452 vrele(vp);
453 return error;
454 }
455
456
457
458
459
460 static int
461 fhopen_call (d_thread_t *p,
462 struct ViceIoctl *vice_ioctl,
463 struct vnode *vp,
464 int flags,
465 register_t *retval)
466 {
467
468 NNPFSDEB(XDEBSYS, ("fhopen_call: flags = %d\n", flags));
469
470 if (vp != NULL) {
471 vrele (vp);
472 return EINVAL;
473 }
474
475 #if defined(__APPLE__) || defined(__osf__)
476 return EINVAL;
477 #endif
478
479 return xfs_fhopen (p,
480 (struct xfs_fhandle_t *)vice_ioctl->in,
481 flags,
482 retval);
483 }
484
485
486
487
488
489 static int
490 remote_pioctl (d_thread_t *p,
491 struct sys_pioctl_args *arg,
492 struct ViceIoctl *vice_ioctl,
493 struct vnode *vp)
494 {
495 int error = 0;
496 struct xfs_message_pioctl *msg = NULL;
497 struct xfs_message_wakeup_data *msg2;
498
499 msg = malloc(sizeof(struct xfs_message_symlink), M_TEMP, M_WAITOK);
500 if (msg == NULL) {
501 error = ENOMEM;
502 goto done;
503 }
504 memset(msg, 0, sizeof(*msg));
505
506 if (vp != NULL) {
507 struct xfs_node *xn;
508
509 if (vp->v_tag != VT_XFS) {
510 NNPFSDEB(XDEBSYS, ("xfs_syscall: file is not in afs\n"));
511 vrele(vp);
512 error = EINVAL;
513 goto done;
514 }
515
516 xn = VNODE_TO_XNODE(vp);
517
518 msg->handle = xn->handle;
519 vrele(vp);
520 }
521
522 if (vice_ioctl->in_size < 0) {
523 printf("xfs: remote pioctl: got a negative data size: opcode: %d",
524 SCARG(arg, a_opcode));
525 error = EINVAL;
526 goto done;
527 }
528
529 if (vice_ioctl->in_size > NNPFS_MSG_MAX_DATASIZE) {
530 printf("xfs_pioctl_call: got a humongous in packet: opcode: %d",
531 SCARG(arg, a_opcode));
532 error = EINVAL;
533 goto done;
534 }
535 if (vice_ioctl->in_size != 0) {
536 error = copyin(vice_ioctl->in, msg->msg, vice_ioctl->in_size);
537 if (error)
538 goto done;
539 }
540
541 msg->header.opcode = NNPFS_MSG_PIOCTL;
542 msg->header.size = sizeof(*msg);
543 msg->opcode = SCARG(arg, a_opcode);
544
545 msg->insize = vice_ioctl->in_size;
546 msg->outsize = vice_ioctl->out_size;
547 #ifdef HAVE_FREEBSD_THREAD
548 msg->cred.uid = xfs_thread_to_euid(p);
549 msg->cred.pag = xfs_get_pag(xfs_thread_to_cred(p));
550 #else
551 msg->cred.uid = xfs_proc_to_euid(p);
552 msg->cred.pag = xfs_get_pag(xfs_proc_to_cred(p));
553 #endif
554
555 error = xfs_message_rpc(0, &(msg->header), sizeof(*msg), p);
556 msg2 = (struct xfs_message_wakeup_data *) msg;
557
558 if (error == 0)
559 error = msg2->error;
560 if (error == ENODEV)
561 error = EINVAL;
562
563 if (error == 0 && msg2->header.opcode == NNPFS_MSG_WAKEUP_DATA) {
564 int len;
565
566 len = msg2->len;
567 if (len > vice_ioctl->out_size)
568 len = vice_ioctl->out_size;
569 if (len > NNPFS_MSG_MAX_DATASIZE)
570 len = NNPFS_MSG_MAX_DATASIZE;
571 if (len < 0)
572 len = 0;
573
574 error = copyout(msg2->msg, vice_ioctl->out, len);
575 }
576 done:
577 free(msg, M_TEMP);
578 return error;
579 }
580
581 static int
582 xfs_debug (d_thread_t *p,
583 struct ViceIoctl *vice_ioctl)
584 {
585 int32_t flags;
586 int error;
587
588 if (vice_ioctl->in_size != 0) {
589 if (vice_ioctl->in_size < sizeof(int32_t))
590 return EINVAL;
591
592 error = xfs_suser (p);
593 if (error)
594 return error;
595
596 error = copyin (vice_ioctl->in,
597 &flags,
598 sizeof(flags));
599 if (error)
600 return error;
601
602 xfsdeb = flags;
603 }
604
605 if (vice_ioctl->out_size != 0) {
606 if (vice_ioctl->out_size < sizeof(int32_t))
607 return EINVAL;
608
609 error = copyout (&xfsdeb,
610 vice_ioctl->out,
611 sizeof(int32_t));
612 if (error)
613 return error;
614 }
615
616 return 0;
617 }
618
619
620
621
622
623
624 int
625 xfs_pioctl_call(d_thread_t *proc,
626 struct sys_pioctl_args *arg,
627 register_t *return_value)
628 {
629 int error;
630 struct ViceIoctl vice_ioctl;
631 char *pathptr;
632 struct vnode *vp = NULL;
633
634 NNPFSDEB(XDEBSYS, ("xfs_syscall(%d, %lx, %d, %lx, %d)\n",
635 SCARG(arg, operation),
636 (unsigned long)SCARG(arg, a_pathP),
637 SCARG(arg, a_opcode),
638 (unsigned long)SCARG(arg, a_paramsP),
639 SCARG(arg, a_followSymlinks)));
640
641
642
643 error = copyin(SCARG(arg, a_paramsP),
644 &vice_ioctl,
645 sizeof(vice_ioctl));
646
647 if (error)
648 return error;
649
650 pathptr = SCARG(arg, a_pathP);
651
652 if (pathptr != NULL) {
653 error = lookup_node (pathptr, SCARG(arg, a_followSymlinks), &vp,
654 proc);
655 if(error)
656 return error;
657 }
658
659 switch (SCARG(arg, a_opcode)) {
660 case VIOC_FHGET :
661 return fhget_call (proc, &vice_ioctl, vp);
662 case VIOC_FHOPEN :
663 return fhopen_call (proc, &vice_ioctl, vp,
664 SCARG(arg, a_followSymlinks), return_value);
665 case VIOC_XFSDEBUG :
666 if (vp != NULL)
667 vrele (vp);
668 return xfs_debug (proc, &vice_ioctl);
669 default :
670 NNPFSDEB(XDEBSYS, ("a_opcode = %x\n", SCARG(arg, a_opcode)));
671 return remote_pioctl (proc, arg, &vice_ioctl, vp);
672 }
673 }