• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/procd/jail/console.c

  1 /*
  2  * Copyright (C) 2020 Daniel Golle <daniel@makrotopia.org>
  3  *
  4  * This program is free software; you can redistribute it and/or modify
  5  * it under the terms of the GNU Lesser General Public License version 2.1
  6  * as published by the Free Software Foundation
  7  *
  8  * This program is distributed in the hope that it will be useful,
  9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 11  * GNU General Public License for more details.
 12  */
 13 
 14 #ifndef _GNU_SOURCE
 15 #define _GNU_SOURCE
 16 #endif
 17 
 18 #include <stdlib.h>
 19 #include <fcntl.h>
 20 #include <libubox/ustream.h>
 21 #include <libubus.h>
 22 #include <signal.h>
 23 #include <stdio.h>
 24 #include <stdlib.h>
 25 #include <unistd.h>
 26 #include <fcntl.h>
 27 #include <errno.h>
 28 #include <sys/types.h>
 29 #include <termios.h>
 30 
 31 static inline int setup_tios(int fd, struct termios *oldtios)
 32 {
 33         struct termios newtios;
 34 
 35         if (!isatty(fd)) {
 36                 return -1;
 37         }
 38 
 39         /* Get current termios */
 40         if (tcgetattr(fd, oldtios))
 41                 return -1;
 42 
 43         newtios = *oldtios;
 44 
 45         /* We use the same settings that ssh does. */
 46         newtios.c_iflag |= IGNPAR;
 47         newtios.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
 48         newtios.c_lflag &= ~(TOSTOP | ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
 49         newtios.c_oflag &= ~ONLCR;
 50         newtios.c_oflag |= OPOST;
 51         newtios.c_cc[VMIN] = 1;
 52         newtios.c_cc[VTIME] = 0;
 53 
 54         /* Set new attributes */
 55         if (tcsetattr(fd, TCSAFLUSH, &newtios))
 56                 return -1;
 57 
 58         return 0;
 59 }
 60 
 61 
 62 
 63 #define OPT_ARGS        "i:c:"
 64 
 65 static struct ustream_fd cufd;
 66 static struct ustream_fd lufd;
 67 
 68 static void usage()
 69 {
 70         fprintf(stderr, "ujail-console -c <container> [-i <instance>]\n");
 71         exit(1);
 72 }
 73 
 74 static void client_cb(struct ustream *s, int bytes)
 75 {
 76         char *buf;
 77         int len, rv;
 78 
 79         do {
 80                 buf = ustream_get_read_buf(s, &len);
 81                 if (!buf)
 82                         break;
 83 
 84                 rv = ustream_write(&lufd.stream, buf, len, false);
 85 
 86                 if (rv > 0)
 87                         ustream_consume(s, rv);
 88 
 89                 if (rv <= len)
 90                         break;
 91         } while(1);
 92 }
 93 
 94 static void local_cb(struct ustream *s, int bytes)
 95 {
 96         char *buf;
 97         int len, rv;
 98 
 99         do {
100                 buf = ustream_get_read_buf(s, &len);
101                 if (!buf)
102                         break;
103 
104                 if ((len > 0) && (buf[0] == 2))
105                                 uloop_end();
106 
107                 rv = ustream_write(&cufd.stream, buf, len, false);
108 
109                 if (rv > 0)
110                         ustream_consume(s, rv);
111 
112                 if (rv <= len)
113                         break;
114         } while(1);
115 }
116 
117 int main(int argc, char **argv)
118 {
119         struct ubus_context *ctx;
120         uint32_t id;
121         static struct blob_buf req;
122         char *container_name = NULL, *instance_name = NULL;
123         int client_fd, server_fd, tty_fd;
124         struct termios oldtermios;
125         int ch;
126 
127         while ((ch = getopt(argc, argv, OPT_ARGS)) != -1) {
128                 switch (ch) {
129                 case 'i':
130                         instance_name = optarg;
131                         break;
132                 case 'c':
133                         container_name = optarg;
134                         break;
135                 default:
136                         usage();
137                 }
138         }
139 
140         if (!container_name)
141                 usage();
142 
143         ctx = ubus_connect(NULL);
144         if (!ctx) {
145                 fprintf(stderr, "can't connect to ubus!\n");
146                 return -1;
147         }
148 
149         /* open pseudo-terminal pair */
150         client_fd = posix_openpt(O_RDWR | O_NOCTTY);
151         if (client_fd < 0) {
152                 fprintf(stderr, "can't create virtual console!\n");
153                 ubus_free(ctx);
154                 return -1;
155         }
156         setup_tios(client_fd, &oldtermios);
157         grantpt(client_fd);
158         unlockpt(client_fd);
159         server_fd = open(ptsname(client_fd), O_RDWR | O_NOCTTY);
160         if (server_fd < 0) {
161                 fprintf(stderr, "can't open virtual console!\n");
162                 close(client_fd);
163                 ubus_free(ctx);
164                 return -1;
165         }
166 
167         setup_tios(server_fd, &oldtermios);
168         tty_fd = open("/dev/tty", O_RDWR);
169         setup_tios(tty_fd, &oldtermios);
170 
171         /* register server-side with procd */
172         blob_buf_init(&req, 0);
173         blobmsg_add_string(&req, "name", container_name);
174         if (instance_name)
175                 blobmsg_add_string(&req, "instance", instance_name);
176 
177         if (ubus_lookup_id(ctx, "container", &id) ||
178             ubus_invoke_fd(ctx, id, "console_attach", req.head, NULL, NULL, 3000, server_fd)) {
179                 fprintf(stderr, "ubus request failed\n");
180                 close(server_fd);
181                 close(client_fd);
182                 blob_buf_free(&req);
183                 ubus_free(ctx);
184                 return -2;
185         }
186 
187         close(server_fd);
188         blob_buf_free(&req);
189         ubus_free(ctx);
190 
191         uloop_init();
192 
193         /* forward between stdio and client_fd until detach is requested */
194         lufd.stream.notify_read = local_cb;
195         ustream_fd_init(&lufd, tty_fd);
196 
197         cufd.stream.notify_read = client_cb;
198 /* ToDo: handle remote close and other events */
199 //      cufd.stream.notify_state = client_state_cb;
200         ustream_fd_init(&cufd, client_fd);
201 
202         fprintf(stderr, "attaching to jail console. press [CTRL]+[B] to exit.\n");
203         close(0);
204         close(1);
205         close(2);
206         uloop_run();
207 
208         tcsetattr(tty_fd, TCSAFLUSH, &oldtermios);
209         ustream_free(&lufd.stream);
210         ustream_free(&cufd.stream);
211         close(client_fd);
212 
213         return 0;
214 }
215 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt