summaryrefslogtreecommitdiff
path: root/libdiskfs/file-exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdiskfs/file-exec.c')
-rw-r--r--libdiskfs/file-exec.c334
1 files changed, 12 insertions, 322 deletions
diff --git a/libdiskfs/file-exec.c b/libdiskfs/file-exec.c
index 81a3102f..4521585f 100644
--- a/libdiskfs/file-exec.c
+++ b/libdiskfs/file-exec.c
@@ -26,155 +26,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <hurd/exec.h>
#include <hurd/paths.h>
#include <string.h>
-
-static int
-scan_ids (uid_t *set, int setlen, uid_t test)
-{
- int i;
- for (i = 0; i < setlen; i++)
- if (set[i] == test)
- return 1;
- return 0;
-}
-
-/* If SETID is true, adds ID to the sets OLDGENIDS & OLDAUXIDS, and returns
- the new set in GENIDS and AUXIDS, which are malloced; if SETID is false,
- just makes GENIDS and AUXIDS (malloced) copies of OLDGENIDS & OLDAUXIDS;
- SECURE is also updated to reflect whether a secure exec is called for.
- ENOMEM is returned if a malloc fails, otherwise 0. The return parameters
- are only touched if this call succeeds. */
-static error_t
-setid (int setid, uid_t id, int *secure,
- uid_t *oldgenids, size_t noldgenids,
- uid_t *oldauxids, size_t noldauxids,
- uid_t **genids, size_t *ngenids,
- uid_t **auxids, size_t *nauxids)
-{
- /* These hold the new auxids array until we're sure we're going to return. */
- uid_t *_genids, *_auxids;
- size_t _ngenids, _nauxids;
-
-/* Return malloced storage for N uids. If the malloc fails, return ENOMEM
- from the function enclosing the call. */
-#define MALLOC_IDS(n) \
- ({ void *_p = malloc ((n) * sizeof (uid_t)); if (! _p) return ENOMEM; _p; })
-
-/* Copy N uids/gids from SRC to DST. */
-#define COPY_IDS(src, dst, n) \
- bcopy (src, dst, (n) * sizeof (uid_t))
-
- if (setid)
- {
- /* We are dumping the current first id; put it into the auxids array.
- This is complex. The different cases below are intended to make
- sure that we don't lose any ids (unlike posix) and to make sure that
- aux ids zero and one (if already set) behave like the posix ones. */
- if (noldauxids == 0)
- {
- if (noldgenids == 0)
- {
- _nauxids = 0;
- _auxids = 0;
- }
- else
- {
- _auxids = MALLOC_IDS (_nauxids = 1);
- _auxids[0] = oldgenids[0];
- }
- }
- else if (noldauxids == 1)
- {
- _nauxids = noldgenids > 0 ? 2 : 1;
- _auxids = MALLOC_IDS (_nauxids);
- _auxids[0] = oldauxids[0];
- if (noldgenids > 0)
- _auxids[1] = oldgenids[0];
- }
- else if (noldauxids == 2)
- {
- if (noldgenids == 0 || oldgenids[0] == oldauxids[1])
- {
- _auxids = MALLOC_IDS (_nauxids = 2);
- _auxids[0] = oldauxids[0];
- _auxids[1] = oldauxids[1];
- }
- else
- {
- /* Shift by one */
- _auxids = MALLOC_IDS (_nauxids = 3);
- _auxids[0] = oldauxids[0];
- _auxids[1] = oldgenids[0];
- _auxids[2] = oldauxids[1];
- }
- }
- else
- {
- /* Just like above, but in the shift case note
- that the new _auxids[2] shouldn't be allowed
- to needlessly duplicate something further on. */
- if (noldgenids == 0
- || oldgenids[0] == oldauxids[1]
- || scan_ids (&oldauxids[2], noldauxids - 2, oldauxids[1]))
- {
- _auxids = MALLOC_IDS (_nauxids = noldauxids);
- COPY_IDS (oldauxids, _auxids, _nauxids);
- if (noldgenids > 0)
- _auxids[1] = oldgenids[0];
- }
- else
- {
- _auxids = MALLOC_IDS (_nauxids = noldauxids + 1);
- _auxids[0] = oldauxids[0];
- _auxids[1] = oldgenids[0];
- COPY_IDS (&oldauxids[1], &_auxids[2], noldauxids - 1);
- }
- }
-
- /* Whew. Now set the new id. */
- _ngenids = noldgenids ?: 1;
- _genids = malloc (_ngenids * sizeof (uid_t));
-
- if (! _genids)
- {
- free (_auxids);
- return ENOMEM;
- }
-
- _genids[0] = id;
- if (noldgenids > 1)
- COPY_IDS (&oldgenids[1], &_genids[1], _ngenids - 1);
-
- if (secure && !*secure
- && !scan_ids (oldgenids, noldgenids, id)
- && !scan_ids (oldauxids, noldauxids, id))
- *secure = 1;
- }
- else
- /* Not SETID; just copy the old values. */
- {
- _ngenids = noldgenids;
- _nauxids = noldauxids;
- _genids = MALLOC_IDS (_ngenids);
- _auxids = malloc (_nauxids * sizeof (uid_t));
-
- if (! _auxids)
- {
- free (_genids);
- return ENOMEM;
- }
-
- COPY_IDS (oldgenids, _genids, _ngenids);
- COPY_IDS (oldauxids, _auxids, _nauxids);
- }
-
- /* Finally we can zot the return params. */
- *genids = _genids;
- *ngenids = _ngenids;
- *auxids = _auxids;
- *nauxids = _nauxids;
-
- return 0;
-}
+#include <idvec.h>
kern_return_t
diskfs_S_file_exec (struct protid *cred,
@@ -198,7 +50,7 @@ diskfs_S_file_exec (struct protid *cred,
struct node *np;
error_t err;
struct protid *newpi;
- int suid, sgid, secure;
+ int suid, sgid;
if (!cred)
return EOPNOTSUPP;
@@ -232,186 +84,24 @@ diskfs_S_file_exec (struct protid *cred,
return EACCES;
}
- suid = np->dn_stat.st_mode & S_ISUID; /* XXX not if we can't do it... */
- sgid = np->dn_stat.st_mode & S_ISGID; /* XXX not of we can't do it... */
- secure = 0;
-
+ suid = np->dn_stat.st_mode & S_ISUID;
+ sgid = np->dn_stat.st_mode & S_ISGID;
if (suid || sgid)
{
- /* These variables describe the auth port that the
- user gave us. */
- uid_t aubuf[10], gubuf[10], agbuf[20], ggbuf[20];
- uid_t *oldauxuids = aubuf, *oldgenuids = gubuf;
- gid_t *oldauxgids = agbuf, *oldgengids = ggbuf;
- int noldauxuids = 10, noldgenuids = 10;
- int noldauxgids = 20, noldgengids = 20;
-
- /* These describe the auth port we are trying to create. */
- uid_t *auxuids = 0, *genuids = 0;
- gid_t *auxgids = 0, *gengids = 0;
- int nauxuids = 0, ngenuids = 0;
- int nauxgids = 0, ngengids = 0;
- auth_t newauth;
-
- int i;
-
- void
- reauth (mach_port_t *port, int isproc)
- {
- mach_port_t newport, ref;
- if (*port == MACH_PORT_NULL)
- return;
- ref = mach_reply_port ();
- err = (isproc ? proc_reauthenticate : io_reauthenticate)
- (*port, ref, MACH_MSG_TYPE_MAKE_SEND);
- if (!err)
- err = auth_user_authenticate (newauth, *port, ref,
- MACH_MSG_TYPE_MAKE_SEND, &newport);
- if (err)
- {
- /* Could not reauthenticate. Roland thinks we should not
- give away the old port. I disagree; it can't actually hurt
- because the old id's are still available, so it's no
- security problem. */
-
- /* Nothing Happens. */
- }
- else
- {
- if (isproc)
- mach_port_deallocate (mach_task_self (), newport);
- else
- {
- mach_port_deallocate (mach_task_self (), *port);
- *port = newport;
- }
- }
- mach_port_destroy (mach_task_self (), ref);
- }
-
-
- /* STEP 0: Fetch the user's current id's. */
-
- /* First fetch the current ID's the user has. */
- err = auth_getids (portarray[INIT_PORT_AUTH],
- &oldgenuids, &noldgenuids,
- &oldauxuids, &noldauxuids,
- &oldgengids, &noldgengids,
- &oldauxgids, &noldauxgids);
- if (err)
- goto abandon_suid;
-
-
- /* STEP 1: Find out if the user's permission will be
- increasing, or just rearranged. */
-
- /* If the user's auth port is fraudulent, then these values
- will be wrong. No matter; we will repeat these checks
- using secure id sets later if the port turns out to be
- bogus. */
-
- err = setid (suid, np->dn_stat.st_uid, &secure,
- oldgenuids, noldgenuids, oldauxuids, noldauxuids,
- &genuids, &ngenuids, &auxuids, &nauxuids);
- if (! err)
- err = setid (sgid, np->dn_stat.st_gid, &secure,
- oldgengids, noldgengids, oldauxgids, noldauxgids,
- &gengids, &ngengids, &auxgids, &nauxgids);
- if (scan_ids (oldgenuids, noldgenuids, 0)
- || scan_ids (oldauxuids, noldauxuids, 0))
- secure = 0; /* If we're root, we don't have to be. */
-
- /* Deallocate the buffers if MiG allocated them. */
- if (oldgenuids != gubuf)
- vm_deallocate (mach_task_self (), (vm_address_t) oldgenuids,
- noldgenuids * sizeof (uid_t));
- if (oldauxuids != aubuf)
- vm_deallocate (mach_task_self (), (vm_address_t) oldauxuids,
- noldauxuids * sizeof (uid_t));
- if (oldgengids != ggbuf)
- vm_deallocate (mach_task_self (), (vm_address_t) oldgengids,
- noldgengids * (sizeof (gid_t)));
- if (oldauxgids != agbuf)
- vm_deallocate (mach_task_self (), (vm_address_t) oldauxgids,
- noldauxgids * (sizeof (gid_t)));
-
- if (err)
- goto free_abandon_suid;
-
-
- /* STEP 3: Attempt to create this new auth handle. */
- err = auth_makeauth (diskfs_auth_server_port, &portarray[INIT_PORT_AUTH],
- MACH_MSG_TYPE_COPY_SEND, 1,
- genuids, ngenuids,
- auxuids, nauxuids,
- gengids, ngengids,
- auxgids, nauxgids,
- &newauth);
- if (err == EINVAL)
- /* The user's auth port was bogus. As we can't trust what the user
- has told us about ids, we use the authentication on the file being
- execed (which we know is good), as the effective ids, and assume
- no aux ids. */
+ int secure = 0;
+ error_t get_file_ids (struct idvec *uids, struct idvec *gids)
{
- /* Free our first attempts. [Reinit to 0, so we can free them] */
- free (genuids); genuids = 0;
- free (auxuids); auxuids = 0;
- free (gengids); gengids = 0;
- free (auxgids); auxgids = 0;
-
- err = setid (suid, np->dn_stat.st_uid, &secure,
- cred->uids, cred->nuids, 0, 0,
- &genuids, &ngenuids, &auxuids, &nauxuids);
+ error_t err = idvec_merge_ids (uids, cred->uids, cred->nuids);
if (! err)
- err = setid (sgid, np->dn_stat.st_gid, &secure,
- cred->gids, cred->ngids, 0, 0,
- &gengids, &ngengids, &auxgids, &nauxgids);
- if (diskfs_isuid (0, cred))
- secure = 0; /* If we're root, we don't have to be. */
-
- if (err)
- goto abandon_suid; /* setid() failed. */
-
- /* Trrrry again... */
- err = auth_makeauth (diskfs_auth_server_port, 0,
- MACH_MSG_TYPE_COPY_SEND, 1,
- genuids, ngenuids, auxuids, nauxuids,
- gengids, ngengids, auxgids, nauxgids,
- &newauth);
+ err = idvec_merge_ids (gids, cred->gids, cred->ngids);
+ return err;
}
-
- if (err)
- goto free_abandon_suid;
-
- /* STEP 4: Re-authenticate all the ports we are handing to the user
- with this new port, and install the new auth port in portarray. */
- for (i = 0; i < fdslen; ++i)
- reauth (&fds[i], 0);
- if (secure)
- /* Not worth doing; the exec server will just do it again. */
- portarray[INIT_PORT_CRDIR] = MACH_PORT_NULL;
- else
- reauth (&portarray[INIT_PORT_CRDIR], 0);
- reauth (&portarray[INIT_PORT_PROC], 1);
- reauth (&portarray[INIT_PORT_CWDIR], 0);
- mach_port_deallocate (mach_task_self (), portarray[INIT_PORT_AUTH]);
- portarray[INIT_PORT_AUTH] = newauth;
-
- if (ngenuids > 0)
- proc_setowner (portarray[INIT_PORT_PROC], genuids[0]);
-
- /* STEP 5: If we must be secure, then set the appropriate flags
- to tell the exec server so. */
+ fshelp_exec_reauth (suid, np->dn_stat.st_uid, sgid, np->dn_stat.st_gid,
+ diskfs_auth_server_port, get_file_ids,
+ portarray, portarraylen, fds, fdslen, &secure);
if (secure)
flags |= EXEC_SECURE | EXEC_NEWTASK;
-
- free_abandon_suid:
- free (genuids);
- free (auxuids);
- free (gengids);
- free (auxgids);
}
- abandon_suid:
/* If the user can't read the file, then we should use a new task,
which would be inaccessible to the user. Actually, this doesn't