summaryrefslogtreecommitdiff
path: root/libs/fetch-root.c
blob: e036f2046fba56feb8d7f5cfc561af65499ea104 (plain)
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
   Copyright (C) 1995,96,99,2000,02 Free Software Foundation, Inc.
   Written by Michael I. Bushnell.

   This file is part of the GNU Hurd.

   The GNU Hurd is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2, or (at
   your option) any later version.

   The GNU Hurd is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */


#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <hurd.h>
#include <hurd/fsys.h>
#include <hurd/fshelp.h>
#include <hurd/auth.h>
#include <hurd/io.h>

typedef error_t (*mycallback2_t)(int, mach_port_t *, mach_msg_type_name_t *);

error_t
helper_fetch_root (file_t dotdot,
                   mycallback2_t callback2,
                   uid_t uid, gid_t gid,
                   char *argz, size_t argz_len,
                   mach_port_t *control_port)
{
	error_t err;
	mach_port_t control;
	int i;
	mach_port_t ports[INIT_PORT_MAX];
	int ints[INIT_INT_MAX];
	mach_port_t fds[STDERR_FILENO + 1];
	auth_t ourauth, newauth;

	mach_port_t reauth (mach_port_t port) /* Consumes PORT.  */
	{
		mach_port_t rend, ret;
		error_t err;

		if (port == MACH_PORT_NULL)
			return port;

		if (ourauth == MACH_PORT_NULL)
			/* We have no auth server, so we aren't doing reauthentications.
			   Just pass on our own ports directly.  */
			return port;

		rend = mach_reply_port ();

		/* MAKE_SEND is safe here because we destroy REND ourselves. */
		err = io_reauthenticate (port, rend,
				MACH_MSG_TYPE_MAKE_SEND);
		mach_port_deallocate (mach_task_self (), port);
		if (! err)
			err = auth_user_authenticate (newauth, rend,
					MACH_MSG_TYPE_MAKE_SEND, &ret);
		if (err)
			ret = MACH_PORT_NULL;

		mach_port_destroy (mach_task_self (), rend);

		return ret;
	}

	error_t fetch_underlying (int flags, mach_port_t *underlying,
			mach_msg_type_name_t *underlying_type,
			task_t task, void *cookie)
	{
		return
			(*callback2) (flags, underlying, underlying_type);
	}

	ourauth = getauth ();
	if (ourauth == MACH_PORT_NULL)
		newauth = ourauth;
	else
	{
		uid_t uidarray[2] = { uid, uid };
		gid_t gidarray[2] = { gid, gid };
		err = auth_makeauth (ourauth, 0, MACH_MSG_TYPE_COPY_SEND, 0,
				uidarray, 1, uidarray, 2,
				gidarray, 1, gidarray, 2, &newauth);
		if (err)
			return err;
	}

	bzero (ports, INIT_PORT_MAX * sizeof (mach_port_t));
	bzero (fds, (STDERR_FILENO + 1) * sizeof (mach_port_t));
	bzero (ints, INIT_INT_MAX * sizeof (int));

	ports[INIT_PORT_CWDIR] = dotdot;
	ports[INIT_PORT_CRDIR] = reauth (getcrdir ());
	ports[INIT_PORT_AUTH] = newauth;

	fds[STDERR_FILENO] = reauth (getdport (STDERR_FILENO));

	err = fshelp_start_translator_long (fetch_underlying, NULL,
			argz, argz, argz_len,
			fds, MACH_MSG_TYPE_COPY_SEND,
			STDERR_FILENO + 1,
			ports, MACH_MSG_TYPE_COPY_SEND,
			INIT_PORT_MAX,
			ints, INIT_INT_MAX,
			uid,
			0, &control);
	for (i = 0; i <= STDERR_FILENO; i++)
		mach_port_deallocate (mach_task_self (), fds[i]);

	for (i = 0; i < INIT_PORT_MAX; i++)
		if (i != INIT_PORT_CWDIR)
			mach_port_deallocate (mach_task_self (), ports[i]);

	*control_port = control;

	return err;
}