1 // service.c -- Service descriptions
2 // Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License version 2 as
6 // published by the Free Software Foundation.
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.
13 // You should have received a copy of the GNU General Public License along
14 // with this program; if not, write to the Free Software Foundation, Inc.,
15 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 // In addition to these license terms, the author grants the following
20 // If you modify this program, or any covered work, by linking or
21 // combining it with the OpenSSL project's OpenSSL library (or a
22 // modified version of that library), containing parts covered by the
23 // terms of the OpenSSL or SSLeay licenses, the author
24 // grants you additional permission to convey the resulting work.
25 // Corresponding Source for a non-source form of such a combination
26 // shall include the source code for the parts of OpenSSL used as well
27 // as that of the covered work.
29 // You may at your option choose to remove this additional permission from
30 // the work, or from any part of it.
32 // It is possible to build this program in a way that it loads OpenSSL
33 // libraries at run-time. If doing so, the following notices are required
34 // by the OpenSSL and SSLeay licenses:
36 // This product includes software developed by the OpenSSL Project
37 // for use in the OpenSSL Toolkit. (http://www.openssl.org/)
39 // This product includes cryptographic software written by Eric Young
40 // (eay@cryptsoft.com)
43 // The most up-to-date version of this program is always available from
44 // http://shellinabox.com
50 #include <sys/types.h>
53 #include "logging/logging.h"
54 #include "shellinabox/launcher.h"
55 #include "shellinabox/privileges.h"
56 #include "shellinabox/service.h"
59 struct Service **services;
62 void initService(struct Service *service, const char *arg) {
63 // The first part of the argument is the path where the service should
64 // be mounted. Remove any trailing slashes and make sure there is exactly
65 // one leading slash before copying it into service->path.
67 check(desc = strdup(arg));
72 if ((ptr = strchr(arg, ':')) == NULL) {
74 fatal("Syntax error in service description \"%s\".", desc);
77 check(service->path = malloc(ptr - arg + 2));
78 ((char *)service->path)[0] = '/';
79 memcpy((char *)service->path + 1, arg, ptr - arg);
80 ((char *)service->path)[ptr - arg + 1] = '\000';
81 while (service->path[1] && strrchr(service->path, '\000')[-1] == '/') {
82 strrchr(service->path, '\000')[-1] = '\000';
87 // The next part of the argument is either the word 'LOGIN' or the
88 // application definition.
89 if (!strcmp(arg, "LOGIN")) {
91 fatal("Must be \"root\" to invoke \"/bin/login\". Maybe, change "
92 "--service definitions?");
94 service->useLogin = 1;
95 service->useHomeDir = 0;
96 service->authUser = 0;
97 service->useDefaultShell = 0;
100 check(service->user = strdup("root"));
101 check(service->group = strdup("root"));
102 check(service->cwd = strdup("/"));
103 check(service->cmdline = strdup(
104 "/bin/login -p -h ${peer}"));
107 if (!strcmp(arg, "SSH") || !strncmp(arg, "SSH:", 4)) {
108 service->useLogin = 0;
109 service->useHomeDir = 0;
110 service->authUser = 2;
111 service->useDefaultShell = 0;
114 service->user = NULL;
115 service->group = NULL;
116 check(service->cwd = strdup("/"));
118 check(host = strdup("localhost"));
119 if ((ptr = strchr(arg, ':')) != NULL) {
120 check(ptr = strdup(ptr + 1));
122 if ((end = strchr(ptr, ':')) != NULL) {
133 // Don't allow manipulation of the SSH command line through "creative" use
135 for (char *h = host; *h; h++) {
137 if (!((ch >= '0' && ch <= '9') ||
138 (ch >= 'A' && ch <= 'Z') ||
139 (ch >= 'a' && ch <= 'z') ||
140 ch == '-' || ch == '.')) {
141 fatal("Invalid hostname \"%s\" in service definition", host);
145 service->cmdline = stringPrintf(NULL,
146 "ssh -a -e none -i /dev/null -x -oChallengeResponseAuthentication=no "
147 "-oCheckHostIP=no -oClearAllForwardings=yes -oCompression=no "
148 "-oControlMaster=no -oGSSAPIAuthentication=no "
149 "-oHostbasedAuthentication=no -oIdentitiesOnly=yes "
150 "-oKbdInteractiveAuthentication=yes -oPasswordAuthentication=yes "
151 "-oPreferredAuthentications=keyboard-interactive,password "
152 "-oPubkeyAuthentication=no -oRhostsRSAAuthentication=no "
153 "-oRSAAuthentication=no -oStrictHostKeyChecking=no -oTunnel=no "
154 "-oUserKnownHostsFile=/dev/null -oVerifyHostKeyDNS=no "
155 "-oVisualHostKey=no -oLogLevel=QUIET %%s@%s", host);
158 service->useLogin = 0;
160 // The user definition is either the word 'AUTH' or a valid user and
162 if ((ptr = strchr(arg, ':')) == NULL) {
166 if (supportsPAM() && !strcmp(arg, "AUTH")) {
167 service->authUser = 1;
170 service->user = NULL;
171 service->group = NULL;
173 service->authUser = 0;
175 // Numeric or symbolic user id
176 service->uid = parseUser(arg, &service->user);
180 // Numeric or symbolic group id
181 if ((ptr = strchr(arg, ':')) == NULL) {
185 service->gid = parseGroup(arg, &service->group);
190 // The next part of the argument is the starting working directory
191 if ((ptr = strchr(arg, ':')) == NULL) {
195 if (!strcmp(arg, "HOME")) {
196 service->useHomeDir = 1;
200 fatal("Working directories must have absolute paths");
202 service->useHomeDir = 0;
203 check(service->cwd = strdup(arg));
208 // The final argument is the command line
212 if (!strcmp(arg, "SHELL")) {
213 service->useDefaultShell = 1;
214 service->cmdline = NULL;
216 service->useDefaultShell = 0;
217 check(service->cmdline = strdup(arg));
223 struct Service *newService(const char *arg) {
224 struct Service *service;
225 check(service = malloc(sizeof(struct Service)));
226 initService(service, arg);
230 void destroyService(struct Service *service) {
232 free((char *)service->path);
233 free((char *)service->user);
234 free((char *)service->group);
235 free((char *)service->cwd);
236 free((char *)service->cmdline);
240 void deleteService(struct Service *service) {
241 destroyService(service);
245 void destroyServiceHashEntry(void *arg, char *key, char *value) {
248 static int enumerateServicesHelper(void *arg, const char *key, char **value) {
249 check(services = realloc(services,
250 ++numServices * sizeof(struct Service *)));
251 services[numServices-1] = *(struct Service **)value;
252 services[numServices-1]->id = numServices-1;
256 void enumerateServices(HashMap *serviceTable) {
259 iterateOverHashMap(serviceTable, enumerateServicesHelper, NULL);