kernel: Remove 'options COMPAT_SUNOS'.
[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  */
28
29 #include "opt_compat.h"
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kern_syscall.h>
34 #include <sys/nlookup.h>
35 #include <sys/proc.h>
36 #include <sys/priv.h>
37 #include <sys/sysproto.h>
38 #include <sys/thread.h>
39
40 #include <sys/mplock2.h>
41
42 #include <arch_linux/linux.h>
43 #include <arch_linux/linux_proto.h>
44 #include "linux_util.h"
45
46 DUMMY(setfsuid16);
47 DUMMY(setfsgid16);
48 DUMMY(getresuid16);
49 DUMMY(getresgid16);
50
51 #define CAST_NOCHG(x)   ((x == 0xFFFF) ? -1 : x)
52
53 /*
54  * MPALMOSTSAFE
55  */
56 int
57 sys_linux_chown16(struct linux_chown16_args *args)
58 {
59         struct nlookupdata nd;
60         char *path;
61         int error;
62
63         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
64         if (error)
65                 return (error);
66 #ifdef DEBUG
67         if (ldebug(chown16))
68                 kprintf(ARGS(chown16, "%s, %d, %d"), path, args->uid,
69                     args->gid);
70 #endif
71         get_mplock();
72         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
73         if (error == 0) {
74                 error = kern_chown(&nd, CAST_NOCHG(args->uid),
75                                     CAST_NOCHG(args->gid));
76         }
77         nlookup_done(&nd);
78         rel_mplock();
79         linux_free_path(&path);
80         return(error);
81 }
82
83 /*
84  * MPALMOSTSAFE
85  */
86 int
87 sys_linux_lchown16(struct linux_lchown16_args *args)
88 {
89         struct nlookupdata nd;
90         char *path;
91         int error;
92
93         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
94         if (error)
95                 return (error);
96 #ifdef DEBUG
97         if (ldebug(lchown16))
98                 kprintf(ARGS(lchown16, "%s, %d, %d"), path, args->uid,
99                     args->gid);
100 #endif
101         get_mplock();
102         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
103         if (error == 0) {
104                 error = kern_chown(&nd, CAST_NOCHG(args->uid),
105                                     CAST_NOCHG(args->gid));
106         }
107         nlookup_done(&nd);
108         rel_mplock();
109         linux_free_path(&path);
110         return(error);
111 }
112
113 /*
114  * MPALMOSTSAFE
115  */
116 int
117 sys_linux_setgroups16(struct linux_setgroups16_args *args)
118 {
119         struct thread *td = curthread;
120         struct proc *p = td->td_proc;
121         struct ucred *newcred, *oldcred;
122         l_gid16_t linux_gidset[NGROUPS];
123         gid_t *bsd_gidset;
124         int ngrp, error;
125
126 #ifdef DEBUG
127         if (ldebug(setgroups16))
128                 kprintf(ARGS(setgroups16, "%d, *"), args->gidsetsize);
129 #endif
130
131         ngrp = args->gidsetsize;
132         oldcred = td->td_ucred;
133
134         /*
135          * cr_groups[0] holds egid. Setting the whole set from
136          * the supplied set will cause egid to be changed too.
137          * Keep cr_groups[0] unchanged to prevent that.
138          */
139
140         if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS, 0)) != 0)
141                 return (error);
142
143         if ((u_int)ngrp >= NGROUPS)
144                 return (EINVAL);
145
146         get_mplock();
147         newcred = crdup(oldcred);
148         if (ngrp > 0) {
149                 error = copyin((caddr_t)args->gidset, linux_gidset,
150                                ngrp * sizeof(l_gid16_t));
151                 if (error) {
152                         crfree(newcred);
153                         goto done;
154                 }
155
156                 newcred->cr_ngroups = ngrp + 1;
157
158                 bsd_gidset = newcred->cr_groups;
159                 ngrp--;
160                 while (ngrp >= 0) {
161                         bsd_gidset[ngrp + 1] = linux_gidset[ngrp];
162                         ngrp--;
163                 }
164         } else {
165                 newcred->cr_ngroups = 1;
166         }
167
168         setsugid();
169         oldcred = p->p_ucred;   /* deal with threads race */
170         p->p_ucred = newcred;
171         crfree(oldcred);
172         error = 0;
173 done:
174         rel_mplock();
175         return (error);
176 }
177
178 /*
179  * MPSAFE
180  */
181 int
182 sys_linux_getgroups16(struct linux_getgroups16_args *args)
183 {
184         struct proc *p = curproc;
185         struct ucred *cred;
186         l_gid16_t linux_gidset[NGROUPS];
187         gid_t *bsd_gidset;
188         int bsd_gidsetsz, ngrp, error;
189
190 #ifdef DEBUG
191         if (ldebug(getgroups16))
192                 kprintf(ARGS(getgroups16, "%d, *"), args->gidsetsize);
193 #endif
194
195         cred = p->p_ucred;
196         bsd_gidset = cred->cr_groups;
197         bsd_gidsetsz = cred->cr_ngroups - 1;
198
199         /*
200          * cr_groups[0] holds egid. Returning the whole set
201          * here will cause a duplicate. Exclude cr_groups[0]
202          * to prevent that.
203          */
204
205         if ((ngrp = args->gidsetsize) == 0) {
206                 args->sysmsg_result = bsd_gidsetsz;
207                 return (0);
208         }
209
210         if ((u_int)ngrp < (u_int)bsd_gidsetsz)
211                 return (EINVAL);
212
213         ngrp = 0;
214         while (ngrp < bsd_gidsetsz) {
215                 linux_gidset[ngrp] = bsd_gidset[ngrp + 1];
216                 ngrp++;
217         }
218
219         error = copyout(linux_gidset, (caddr_t)args->gidset,
220                         ngrp * sizeof(l_gid16_t));
221         if (error)
222                 return (error);
223
224         args->sysmsg_result = ngrp;
225         return (0);
226 }
227
228 /*
229  * The FreeBSD native getgid(2) and getuid(2) also modify p->p_retval[1]
230  * when COMPAT_43 is defined. This globbers registers that
231  * are assumed to be preserved. The following lightweight syscalls fixes
232  * this. See also linux_getpid(2), linux_getgid(2) and linux_getuid(2) in
233  * linux_misc.c
234  *
235  * linux_getgid16() - MP SAFE
236  * linux_getuid16() - MP SAFE
237  */
238
239 /*
240  * MPSAFE
241  */
242 int
243 sys_linux_getgid16(struct linux_getgid16_args *args)
244 {
245         struct proc *p = curproc;
246
247         args->sysmsg_result = p->p_ucred->cr_rgid;
248         return (0);
249 }
250
251 /*
252  * MPSAFE
253  */
254 int
255 sys_linux_getuid16(struct linux_getuid16_args *args)
256 {
257         struct proc *p = curproc;
258
259         args->sysmsg_result = p->p_ucred->cr_ruid;
260         return (0);
261 }
262
263 /*
264  * MPSAFE
265  */
266 int
267 sys_linux_getegid16(struct linux_getegid16_args *args)
268 {
269         struct getegid_args bsd;
270         int error;
271
272         bsd.sysmsg_result = 0;
273
274         error = sys_getegid(&bsd);
275         args->sysmsg_result = bsd.sysmsg_result;
276         return(error);
277 }
278
279 /*
280  * MPSAFE
281  */
282 int
283 sys_linux_geteuid16(struct linux_geteuid16_args *args)
284 {
285         struct geteuid_args bsd;
286         int error;
287
288         bsd.sysmsg_result = 0;
289
290         error = sys_geteuid(&bsd);
291         args->sysmsg_result = bsd.sysmsg_result;
292         return(error);
293 }
294
295 /*
296  * MPSAFE
297  */
298 int
299 sys_linux_setgid16(struct linux_setgid16_args *args)
300 {
301         struct setgid_args bsd;
302         int error;
303
304         bsd.gid = args->gid;
305         bsd.sysmsg_result = 0;
306
307         error = sys_setgid(&bsd);
308         args->sysmsg_result = bsd.sysmsg_result;
309         return(error);
310 }
311
312 /*
313  * MPSAFE
314  */
315 int
316 sys_linux_setuid16(struct linux_setuid16_args *args)
317 {
318         struct setuid_args bsd;
319         int error;
320
321         bsd.uid = args->uid;
322         bsd.sysmsg_result = 0;
323
324         error = sys_setuid(&bsd);
325         args->sysmsg_result = bsd.sysmsg_result;
326         return(error);
327 }
328
329 /*
330  * MPSAFE
331  */
332 int
333 sys_linux_setregid16(struct linux_setregid16_args *args)
334 {
335         struct setregid_args bsd;
336         int error;
337
338         bsd.rgid = CAST_NOCHG(args->rgid);
339         bsd.egid = CAST_NOCHG(args->egid);
340         bsd.sysmsg_result = 0;
341
342         error = sys_setregid(&bsd);
343         args->sysmsg_result = bsd.sysmsg_result;
344         return(error);
345 }
346
347 /*
348  * MPSAFE
349  */
350 int
351 sys_linux_setreuid16(struct linux_setreuid16_args *args)
352 {
353         struct setreuid_args bsd;
354         int error;
355
356         bsd.ruid = CAST_NOCHG(args->ruid);
357         bsd.euid = CAST_NOCHG(args->euid);
358         bsd.sysmsg_result = 0;
359
360         error = sys_setreuid(&bsd);
361         args->sysmsg_result = bsd.sysmsg_result;
362         return(error);
363 }
364
365 /*
366  * MPSAFE
367  */
368 int
369 sys_linux_setresgid16(struct linux_setresgid16_args *args)
370 {
371         struct setresgid_args bsd;
372         int error;
373
374         bsd.rgid = CAST_NOCHG(args->rgid);
375         bsd.egid = CAST_NOCHG(args->egid);
376         bsd.sgid = CAST_NOCHG(args->sgid);
377         bsd.sysmsg_result = 0;
378
379         error = sys_setresgid(&bsd);
380         args->sysmsg_result = bsd.sysmsg_result;
381         return(error);
382 }
383
384 /*
385  * MPSAFE
386  */
387 int
388 sys_linux_setresuid16(struct linux_setresuid16_args *args)
389 {
390         struct setresuid_args bsd;
391         int error;
392
393         bsd.ruid = CAST_NOCHG(args->ruid);
394         bsd.euid = CAST_NOCHG(args->euid);
395         bsd.suid = CAST_NOCHG(args->suid);
396         bsd.sysmsg_result = 0;
397
398         error = sys_setresuid(&bsd);
399         args->sysmsg_result = bsd.sysmsg_result;
400         return(error);
401 }
402