77664d0b261f4c56e60cf4d9d1745042cfdab599
[dragonfly.git] / sys / emulation / linux / linux_uid16.c
1 /*-
2  * Copyright (c) 2001  The FreeBSD Project
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD: src/sys/compat/linux/linux_uid16.c,v 1.4.2.1 2001/10/21 03:57:35 marcel Exp $
27  * $DragonFly: src/sys/emulation/linux/linux_uid16.c,v 1.12 2006/12/23 00:27:02 swildner Exp $
28  */
29
30 #include "opt_compat.h"
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kern_syscall.h>
35 #include <sys/nlookup.h>
36 #include <sys/proc.h>
37 #include <sys/priv.h>
38 #include <sys/sysproto.h>
39 #include <sys/thread.h>
40
41 #include <sys/mplock2.h>
42
43 #include <arch_linux/linux.h>
44 #include <arch_linux/linux_proto.h>
45 #include "linux_util.h"
46
47 DUMMY(setfsuid16);
48 DUMMY(setfsgid16);
49 DUMMY(getresuid16);
50 DUMMY(getresgid16);
51
52 #define CAST_NOCHG(x)   ((x == 0xFFFF) ? -1 : x)
53
54 /*
55  * MPALMOSTSAFE
56  */
57 int
58 sys_linux_chown16(struct linux_chown16_args *args)
59 {
60         struct nlookupdata nd;
61         char *path;
62         int error;
63
64         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
65         if (error)
66                 return (error);
67 #ifdef DEBUG
68         if (ldebug(chown16))
69                 kprintf(ARGS(chown16, "%s, %d, %d"), path, args->uid,
70                     args->gid);
71 #endif
72         get_mplock();
73         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
74         if (error == 0) {
75                 error = kern_chown(&nd, CAST_NOCHG(args->uid),
76                                     CAST_NOCHG(args->gid));
77         }
78         nlookup_done(&nd);
79         rel_mplock();
80         linux_free_path(&path);
81         return(error);
82 }
83
84 /*
85  * MPALMOSTSAFE
86  */
87 int
88 sys_linux_lchown16(struct linux_lchown16_args *args)
89 {
90         struct nlookupdata nd;
91         char *path;
92         int error;
93
94         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
95         if (error)
96                 return (error);
97 #ifdef DEBUG
98         if (ldebug(lchown16))
99                 kprintf(ARGS(lchown16, "%s, %d, %d"), path, args->uid,
100                     args->gid);
101 #endif
102         get_mplock();
103         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
104         if (error == 0) {
105                 error = kern_chown(&nd, CAST_NOCHG(args->uid),
106                                     CAST_NOCHG(args->gid));
107         }
108         nlookup_done(&nd);
109         rel_mplock();
110         linux_free_path(&path);
111         return(error);
112 }
113
114 /*
115  * MPALMOSTSAFE
116  */
117 int
118 sys_linux_setgroups16(struct linux_setgroups16_args *args)
119 {
120         struct thread *td = curthread;
121         struct proc *p = td->td_proc;
122         struct ucred *newcred, *oldcred;
123         l_gid16_t linux_gidset[NGROUPS];
124         gid_t *bsd_gidset;
125         int ngrp, error;
126
127 #ifdef DEBUG
128         if (ldebug(setgroups16))
129                 kprintf(ARGS(setgroups16, "%d, *"), args->gidsetsize);
130 #endif
131
132         ngrp = args->gidsetsize;
133         oldcred = td->td_ucred;
134
135         /*
136          * cr_groups[0] holds egid. Setting the whole set from
137          * the supplied set will cause egid to be changed too.
138          * Keep cr_groups[0] unchanged to prevent that.
139          */
140
141         if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0)) != 0)
142                 return (error);
143
144         if ((u_int)ngrp >= NGROUPS)
145                 return (EINVAL);
146
147         get_mplock();
148         newcred = crdup(oldcred);
149         if (ngrp > 0) {
150                 error = copyin((caddr_t)args->gidset, linux_gidset,
151                                ngrp * sizeof(l_gid16_t));
152                 if (error) {
153                         crfree(newcred);
154                         goto done;
155                 }
156
157                 newcred->cr_ngroups = ngrp + 1;
158
159                 bsd_gidset = newcred->cr_groups;
160                 ngrp--;
161                 while (ngrp >= 0) {
162                         bsd_gidset[ngrp + 1] = linux_gidset[ngrp];
163                         ngrp--;
164                 }
165         } else {
166                 newcred->cr_ngroups = 1;
167         }
168
169         setsugid();
170         oldcred = p->p_ucred;   /* deal with threads race */
171         p->p_ucred = newcred;
172         crfree(oldcred);
173         error = 0;
174 done:
175         rel_mplock();
176         return (error);
177 }
178
179 /*
180  * MPSAFE
181  */
182 int
183 sys_linux_getgroups16(struct linux_getgroups16_args *args)
184 {
185         struct proc *p = curproc;
186         struct ucred *cred;
187         l_gid16_t linux_gidset[NGROUPS];
188         gid_t *bsd_gidset;
189         int bsd_gidsetsz, ngrp, error;
190
191 #ifdef DEBUG
192         if (ldebug(getgroups16))
193                 kprintf(ARGS(getgroups16, "%d, *"), args->gidsetsize);
194 #endif
195
196         cred = p->p_ucred;
197         bsd_gidset = cred->cr_groups;
198         bsd_gidsetsz = cred->cr_ngroups - 1;
199
200         /*
201          * cr_groups[0] holds egid. Returning the whole set
202          * here will cause a duplicate. Exclude cr_groups[0]
203          * to prevent that.
204          */
205
206         if ((ngrp = args->gidsetsize) == 0) {
207                 args->sysmsg_result = bsd_gidsetsz;
208                 return (0);
209         }
210
211         if ((u_int)ngrp < (u_int)bsd_gidsetsz)
212                 return (EINVAL);
213
214         ngrp = 0;
215         while (ngrp < bsd_gidsetsz) {
216                 linux_gidset[ngrp] = bsd_gidset[ngrp + 1];
217                 ngrp++;
218         }
219
220         error = copyout(linux_gidset, (caddr_t)args->gidset,
221                         ngrp * sizeof(l_gid16_t));
222         if (error)
223                 return (error);
224
225         args->sysmsg_result = ngrp;
226         return (0);
227 }
228
229 /*
230  * The FreeBSD native getgid(2) and getuid(2) also modify p->p_retval[1]
231  * when COMPAT_43 or COMPAT_SUNOS is defined. This globbers registers that
232  * are assumed to be preserved. The following lightweight syscalls fixes
233  * this. See also linux_getpid(2), linux_getgid(2) and linux_getuid(2) in
234  * linux_misc.c
235  *
236  * linux_getgid16() - MP SAFE
237  * linux_getuid16() - MP SAFE
238  */
239
240 /*
241  * MPSAFE
242  */
243 int
244 sys_linux_getgid16(struct linux_getgid16_args *args)
245 {
246         struct proc *p = curproc;
247
248         args->sysmsg_result = p->p_ucred->cr_rgid;
249         return (0);
250 }
251
252 /*
253  * MPSAFE
254  */
255 int
256 sys_linux_getuid16(struct linux_getuid16_args *args)
257 {
258         struct proc *p = curproc;
259
260         args->sysmsg_result = p->p_ucred->cr_ruid;
261         return (0);
262 }
263
264 /*
265  * MPSAFE
266  */
267 int
268 sys_linux_getegid16(struct linux_getegid16_args *args)
269 {
270         struct getegid_args bsd;
271         int error;
272
273         bsd.sysmsg_result = 0;
274
275         error = sys_getegid(&bsd);
276         args->sysmsg_result = bsd.sysmsg_result;
277         return(error);
278 }
279
280 /*
281  * MPSAFE
282  */
283 int
284 sys_linux_geteuid16(struct linux_geteuid16_args *args)
285 {
286         struct geteuid_args bsd;
287         int error;
288
289         bsd.sysmsg_result = 0;
290
291         error = sys_geteuid(&bsd);
292         args->sysmsg_result = bsd.sysmsg_result;
293         return(error);
294 }
295
296 /*
297  * MPSAFE
298  */
299 int
300 sys_linux_setgid16(struct linux_setgid16_args *args)
301 {
302         struct setgid_args bsd;
303         int error;
304
305         bsd.gid = args->gid;
306         bsd.sysmsg_result = 0;
307
308         error = sys_setgid(&bsd);
309         args->sysmsg_result = bsd.sysmsg_result;
310         return(error);
311 }
312
313 /*
314  * MPSAFE
315  */
316 int
317 sys_linux_setuid16(struct linux_setuid16_args *args)
318 {
319         struct setuid_args bsd;
320         int error;
321
322         bsd.uid = args->uid;
323         bsd.sysmsg_result = 0;
324
325         error = sys_setuid(&bsd);
326         args->sysmsg_result = bsd.sysmsg_result;
327         return(error);
328 }
329
330 /*
331  * MPSAFE
332  */
333 int
334 sys_linux_setregid16(struct linux_setregid16_args *args)
335 {
336         struct setregid_args bsd;
337         int error;
338
339         bsd.rgid = CAST_NOCHG(args->rgid);
340         bsd.egid = CAST_NOCHG(args->egid);
341         bsd.sysmsg_result = 0;
342
343         error = sys_setregid(&bsd);
344         args->sysmsg_result = bsd.sysmsg_result;
345         return(error);
346 }
347
348 /*
349  * MPSAFE
350  */
351 int
352 sys_linux_setreuid16(struct linux_setreuid16_args *args)
353 {
354         struct setreuid_args bsd;
355         int error;
356
357         bsd.ruid = CAST_NOCHG(args->ruid);
358         bsd.euid = CAST_NOCHG(args->euid);
359         bsd.sysmsg_result = 0;
360
361         error = sys_setreuid(&bsd);
362         args->sysmsg_result = bsd.sysmsg_result;
363         return(error);
364 }
365
366 /*
367  * MPSAFE
368  */
369 int
370 sys_linux_setresgid16(struct linux_setresgid16_args *args)
371 {
372         struct setresgid_args bsd;
373         int error;
374
375         bsd.rgid = CAST_NOCHG(args->rgid);
376         bsd.egid = CAST_NOCHG(args->egid);
377         bsd.sgid = CAST_NOCHG(args->sgid);
378         bsd.sysmsg_result = 0;
379
380         error = sys_setresgid(&bsd);
381         args->sysmsg_result = bsd.sysmsg_result;
382         return(error);
383 }
384
385 /*
386  * MPSAFE
387  */
388 int
389 sys_linux_setresuid16(struct linux_setresuid16_args *args)
390 {
391         struct setresuid_args bsd;
392         int error;
393
394         bsd.ruid = CAST_NOCHG(args->ruid);
395         bsd.euid = CAST_NOCHG(args->euid);
396         bsd.suid = CAST_NOCHG(args->suid);
397         bsd.sysmsg_result = 0;
398
399         error = sys_setresuid(&bsd);
400         args->sysmsg_result = bsd.sysmsg_result;
401         return(error);
402 }
403