]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/console.c
lxc: forbid open fds upon startup
[mirror_lxc.git] / src / lxc / console.c
CommitLineData
b0a33c1e 1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
7 * Daniel Lezcano <dlezcano at fr.ibm.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24#include <stdio.h>
e0dc0de7 25#include <stdlib.h>
b0a33c1e 26#include <unistd.h>
63376d7d 27#include <fcntl.h>
b0a33c1e 28#include <errno.h>
63376d7d 29#include <pty.h>
b0a33c1e 30#include <sys/types.h>
31#include <sys/un.h>
32
00b3c2e2
CLG
33#include <lxc/log.h>
34#include <lxc/conf.h>
35#include <lxc/start.h> /* for struct lxc_handler */
36
96fa1ff0 37#include "commands.h"
63376d7d 38#include "mainloop.h"
724e753c 39#include "af_unix.h"
36eb9bde
CLG
40
41lxc_log_define(lxc_console, lxc);
42
96fa1ff0
MN
43extern int lxc_console(const char *name, int ttynum, int *fd)
44{
d97b36f8 45 int ret, stopped = 0;
96fa1ff0
MN
46 struct lxc_command command = {
47 .request = { .type = LXC_COMMAND_TTY, .data = ttynum },
48 };
49
d97b36f8
DL
50 ret = lxc_command(name, &command, &stopped);
51 if (ret < 0 && stopped) {
52 ERROR("'%s' is stopped", name);
53 return -1;
54 }
55
96fa1ff0
MN
56 if (ret < 0) {
57 ERROR("failed to send command");
58 return -1;
59 }
60
61 if (!ret) {
62 ERROR("console denied by '%s'", name);
63 return -1;
64 }
65
3cc5de36
MN
66 if (command.answer.ret) {
67 ERROR("console access denied: %s",
68 strerror(-command.answer.ret));
69 return -1;
70 }
71
96fa1ff0
MN
72 *fd = command.answer.fd;
73 if (*fd <0) {
74 ERROR("unable to allocate fd for tty %d", ttynum);
75 return -1;
76 }
77
78 INFO("tty %d allocated", ttynum);
79 return 0;
80}
724e753c
MN
81
82/*----------------------------------------------------------------------------
83 * functions used by lxc-start mainloop
84 * to handle above command request.
85 *--------------------------------------------------------------------------*/
86extern void lxc_console_remove_fd(int fd, struct lxc_tty_info *tty_info)
87{
88 int i;
89
90 for (i = 0; i < tty_info->nbtty; i++) {
91
92 if (tty_info->pty_info[i].busy != fd)
93 continue;
94
95 tty_info->pty_info[i].busy = 0;
96 }
97
98 return;
99}
100
101extern int lxc_console_callback(int fd, struct lxc_request *request,
63376d7d 102 struct lxc_handler *handler)
724e753c
MN
103{
104 int ttynum = request->data;
fae349da 105 struct lxc_tty_info *tty_info = &handler->conf->tty_info;
724e753c
MN
106
107 if (ttynum > 0) {
108 if (ttynum > tty_info->nbtty)
109 goto out_close;
110
111 if (tty_info->pty_info[ttynum - 1].busy)
112 goto out_close;
113
114 goto out_send;
115 }
116
117 /* fixup index tty1 => [0] */
118 for (ttynum = 1;
119 ttynum <= tty_info->nbtty && tty_info->pty_info[ttynum - 1].busy;
120 ttynum++);
121
122 /* we didn't find any available slot for tty */
123 if (ttynum > tty_info->nbtty)
124 goto out_close;
125
126out_send:
127 if (lxc_af_unix_send_fd(fd, tty_info->pty_info[ttynum - 1].master,
128 &ttynum, sizeof(ttynum)) < 0) {
129 ERROR("failed to send tty to client");
130 goto out_close;
131 }
132
133 tty_info->pty_info[ttynum - 1].busy = fd;
134
135 return 0;
136
137out_close:
138 /* the close fd and related cleanup will be done by caller */
139 return 1;
140}
141
1560f6c9 142int lxc_create_console(struct lxc_conf *conf)
63376d7d 143{
e0dc0de7 144 struct termios tios;
1560f6c9
DL
145 struct lxc_console *console = &conf->console;
146
147 if (!conf->rootfs)
148 return 0;
e0dc0de7 149
63376d7d
DL
150 if (openpty(&console->master, &console->slave,
151 console->name, NULL, NULL)) {
152 SYSERROR("failed to allocate a pty");
153 return -1;
154 }
155
156 if (fcntl(console->master, F_SETFD, FD_CLOEXEC)) {
157 SYSERROR("failed to set console master to close-on-exec");
158 goto err;
159 }
160
161 if (fcntl(console->slave, F_SETFD, FD_CLOEXEC)) {
162 SYSERROR("failed to set console slave to close-on-exec");
163 goto err;
164 }
165
e0dc0de7
DL
166 if (!isatty(console->peer))
167 return 0;
168
169 console->tios = malloc(sizeof(tios));
170 if (!console->tios) {
171 SYSERROR("failed to allocate memory");
172 goto err;
173 }
174
175 /* Get termios */
176 if (tcgetattr(console->peer, console->tios)) {
177 SYSERROR("failed to get current terminal settings");
178 goto err_free;
179 }
180
181 tios = *console->tios;
182
183 /* Remove the echo characters and signal reception, the echo
184 * will be done below with master proxying */
185 tios.c_iflag &= ~IGNBRK;
186 tios.c_iflag &= BRKINT;
187 tios.c_lflag &= ~(ECHO|ICANON|ISIG);
188 tios.c_cc[VMIN] = 1;
189 tios.c_cc[VTIME] = 0;
190
191 /* Set new attributes */
192 if (tcsetattr(console->peer, TCSAFLUSH, &tios)) {
193 ERROR("failed to set new terminal settings");
194 goto err_free;
195 }
196
63376d7d 197 return 0;
e0dc0de7
DL
198
199err_free:
200 free(console->tios);
63376d7d
DL
201err:
202 close(console->master);
203 close(console->slave);
204 return -1;
205}
206
207void lxc_delete_console(const struct lxc_console *console)
208{
e0dc0de7
DL
209 if (console->tios &&
210 tcsetattr(console->peer, TCSAFLUSH, console->tios))
211 WARN("failed to set old terminal settings");
63376d7d
DL
212 close(console->master);
213 close(console->slave);
214}
215
216static int console_handler(int fd, void *data, struct lxc_epoll_descr *descr)
217{
218 struct lxc_console *console = (struct lxc_console *)data;
219 char buf[1024];
220 int r;
221
222 r = read(fd, buf, sizeof(buf));
223 if (r < 0) {
224 SYSERROR("failed to read");
225 return 1;
226 }
227
228 /* no output for the console, do nothing */
229 if (console->peer == -1)
230 return 0;
231
232 if (console->peer == fd)
233 write(console->master, buf, r);
234 else
235 write(console->peer, buf, r);
236
237 return 0;
238}
239
240int lxc_console_mainloop_add(struct lxc_epoll_descr *descr,
241 struct lxc_handler *handler)
242{
243 struct lxc_conf *conf = handler->conf;
244 struct lxc_console *console = &conf->console;
245
1560f6c9
DL
246 if (!conf->rootfs) {
247 INFO("no rootfs, no console.");
248 return 0;
249 }
250
63376d7d
DL
251 if (lxc_mainloop_add_handler(descr, console->master,
252 console_handler, console)) {
253 ERROR("failed to add to mainloop console handler for '%d'",
254 console->master);
255 return -1;
256 }
257
258 if (console->peer != -1 &&
259 lxc_mainloop_add_handler(descr, console->peer,
260 console_handler, console))
261 WARN("console input disabled");
262
263 return 0;
264}