1 /* setresuid -- set real user ID, effective user ID, and saved-set user ID
2    Copyright (C) 2002-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <errno.h>
20 #include <unistd.h>
21 #include <hurd.h>
22 #include <hurd/id.h>
23 
24 /* Set the real user ID, effective user ID, and saved-set user ID,
25    of the calling process to RUID, EUID, and SUID, respectively.  */
26 int
__setresuid(uid_t ruid,uid_t euid,uid_t suid)27 __setresuid (uid_t ruid, uid_t euid, uid_t suid)
28 {
29   auth_t newauth;
30   error_t err;
31 
32 retry:
33   HURD_CRITICAL_BEGIN;
34   __mutex_lock (&_hurd_id.lock);
35   err = _hurd_check_ids ();
36 
37   if (!err)
38     {
39       /* Make a new auth handle which has EUID as the first element in the
40 	 list of effective uids.  */
41 
42       uid_t *newgen, *newaux;
43       uid_t auxs[2] = { ruid, suid };
44       size_t ngen, naux;
45 
46       newgen = _hurd_id.gen.uids;
47       ngen = _hurd_id.gen.nuids;
48       if (euid != -1)
49 	{
50 	  if (_hurd_id.gen.nuids == 0)
51 	    {
52 	      /* No effective uids now.  The new set will be just UID.  */
53 	      newgen = &euid;
54 	      ngen = 1;
55 	    }
56 	  else
57 	    {
58 	      _hurd_id.gen.uids[0] = euid;
59 	      _hurd_id.valid = 0;
60 	    }
61 	}
62 
63       newaux = _hurd_id.aux.uids;
64       naux = _hurd_id.aux.nuids;
65       if (ruid != -1)
66 	{
67 	  if (_hurd_id.aux.nuids == 0)
68 	    {
69 	      newaux = &ruid;
70 	      naux = 1;
71 	    }
72 	  else
73 	    {
74 	      _hurd_id.aux.uids[0] = ruid;
75 	      _hurd_id.valid = 0;
76 	    }
77 	}
78 
79       if (suid != -1)
80 	{
81 	  if (ruid == -1)
82 	    {
83 	      if (_hurd_id.aux.nuids >= 1)
84 		auxs[0] = _hurd_id.aux.uids[0];
85 	      else if (_hurd_id.gen.nuids >= 1)
86 		auxs[0] = _hurd_id.gen.uids[0];
87 	      else
88 		/* Not even an effective UID.
89                    Fall back to the only UID we have. */
90 		auxs[0] = suid;
91 	    }
92 	  if (_hurd_id.aux.nuids <= 1)
93 	    {
94 	      /* No saved uids now.  The new set will be just UID.  */
95 	      newaux = auxs;
96 	      naux = 2;
97 	    }
98 	  else
99 	    {
100 	      _hurd_id.aux.uids[1] = suid;
101 	      _hurd_id.valid = 0;
102 	    }
103 	}
104 
105       err = __USEPORT (AUTH, __auth_makeauth
106 		       (port, NULL, MACH_MSG_TYPE_COPY_SEND, 0,
107 			newgen, ngen, newaux, naux,
108 			_hurd_id.gen.gids, _hurd_id.gen.ngids,
109 			_hurd_id.aux.gids, _hurd_id.aux.ngids,
110 			&newauth));
111     }
112 
113   __mutex_unlock (&_hurd_id.lock);
114   HURD_CRITICAL_END;
115   if (err == EINTR)
116     /* Got a signal while inside an RPC of the critical section, retry again */
117     goto retry;
118 
119   if (err)
120     return __hurd_fail (err);
121 
122   /* Install the new handle and reauthenticate everything.  */
123   err = __setauth (newauth);
124   __mach_port_deallocate (__mach_task_self (), newauth);
125   return err;
126 }
127 libc_hidden_def (__setresuid)
128 weak_alias (__setresuid, setresuid)
129