]> andersk Git - test.git/blob - shellinabox/service.c
ca05fafec23385baa4a596fa1f79a5d8586a4102
[test.git] / shellinabox / service.c
1 // service.c -- Service descriptions
2 // Copyright (C) 2008-2009 Markus Gutschke <markus@shellinabox.com>
3 //
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.
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 // 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.
16 //
17 // In addition to these license terms, the author grants the following
18 // additional rights:
19 //
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.
28 //
29 // You may at your option choose to remove this additional permission from
30 // the work, or from any part of it.
31 //
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:
35 //
36 // This product includes software developed by the OpenSSL Project
37 // for use in the OpenSSL Toolkit. (http://www.openssl.org/)
38 //
39 // This product includes cryptographic software written by Eric Young
40 // (eay@cryptsoft.com)
41 //
42 //
43 // The most up-to-date version of this program is always available from
44 // http://shellinabox.com
45
46 #include "config.h"
47
48 #include <stdlib.h>
49 #include <string.h>
50 #include <sys/types.h>
51 #include <unistd.h>
52
53 #include "logging/logging.h"
54 #include "shellinabox/launcher.h"
55 #include "shellinabox/privileges.h"
56 #include "shellinabox/service.h"
57
58
59 struct Service **services;
60 int            numServices;
61
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.
66   char *desc;
67   check(desc                                = strdup(arg));
68   while (*arg == '/') {
69     arg++;
70   }
71   char *ptr;
72   if ((ptr = strchr(arg, ':')) == NULL) {
73   error:
74     fatal("Syntax error in service description \"%s\".", desc);
75   }
76   service->id                               = -1;
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';
83   }
84   arg                                       = ptr + 1;
85
86 #ifdef HAVE_BIN_LOGIN
87   // The next part of the argument is either the word 'LOGIN' or the
88   // application definition.
89   if (!strcmp(arg, "LOGIN")) {
90     if (geteuid()) {
91       fatal("Must be \"root\" to invoke \"/bin/login\". Maybe, change "
92             "--service definitions?");
93     }
94     service->useLogin                       = 1;
95     service->useHomeDir                     = 0;
96     service->authUser                       = 0;
97     service->useDefaultShell                = 0;
98     service->uid                            = 0;
99     service->gid                            = 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}"));
105   } else
106 #endif
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;
112     service->uid                            = -1;
113     service->gid                            = -1;
114     service->user                           = NULL;
115     service->group                          = NULL;
116     check(service->cwd                      = strdup("/"));
117     char *host;
118     check(host                              = strdup("localhost"));
119     if ((ptr                                = strchr(arg, ':')) != NULL) {
120       check(ptr                             = strdup(ptr + 1));
121       char *end;
122       if ((end                              = strchr(ptr, ':')) != NULL) {
123         *end                                = '\000';
124       }
125       if (*ptr) {
126         free(host);
127         host                                = ptr;
128       } else {
129         free(ptr);
130       }
131     }
132
133     // Don't allow manipulation of the SSH command line through "creative" use
134     // of the host name.
135     for (char *h = host; *h; h++) {
136       char ch                               = *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);
142       }
143     }
144
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);
156     free(host);
157   } else {
158     service->useLogin                       = 0;
159
160     // The user definition is either the word 'AUTH' or a valid user and
161     // group id.
162     if ((ptr                                = strchr(arg, ':')) == NULL) {
163       goto error;
164     }
165     *ptr                                    = '\000';
166     if (supportsPAM() && !strcmp(arg, "AUTH")) {
167       service->authUser                     = 1;
168       service->uid                          = -1;
169       service->gid                          = -1;
170       service->user                         = NULL;
171       service->group                        = NULL;
172     } else {
173       service->authUser                     = 0;
174
175       // Numeric or symbolic user id
176       service->uid                          = parseUser(arg, &service->user);
177       *ptr                                  = ':';
178       arg                                   = ptr + 1;
179
180       // Numeric or symbolic group id
181       if ((ptr                              = strchr(arg, ':')) == NULL) {
182         goto error;
183       }
184       *ptr                                  = '\000';
185       service->gid                          = parseGroup(arg, &service->group);
186     }
187     *ptr                                    = ':';
188     arg                                     = ptr + 1;
189
190     // The next part of the argument is the starting working directory
191     if ((ptr                                = strchr(arg, ':')) == NULL) {
192       goto error;
193     }
194     *ptr                                    = '\000';
195     if (!strcmp(arg, "HOME")) {
196       service->useHomeDir                   = 1;
197       service->cwd                          = NULL;
198     } else {
199       if (*arg != '/') {
200         fatal("Working directories must have absolute paths");
201       }
202       service->useHomeDir                   = 0;
203       check(service->cwd                    = strdup(arg));
204     }
205     *ptr                                    = ':';
206     arg                                     = ptr + 1;
207
208     // The final argument is the command line
209     if (!*arg) {
210       goto error;
211     }
212     if (!strcmp(arg, "SHELL")) {
213       service->useDefaultShell              = 1;
214       service->cmdline                      = NULL;
215     } else {
216       service->useDefaultShell              = 0;
217       check(service->cmdline                = strdup(arg));
218     }
219   }
220   free(desc);
221 }
222
223 struct Service *newService(const char *arg) {
224   struct Service *service;
225   check(service = malloc(sizeof(struct Service)));
226   initService(service, arg);
227   return service;
228 }
229
230 void destroyService(struct Service *service) {
231   if (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);
237   }
238 }
239
240 void deleteService(struct Service *service) {
241   destroyService(service);
242   free(service);
243 }
244
245 void destroyServiceHashEntry(void *arg, char *key, char *value) {
246 }
247
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;
253   return 1;
254 }
255
256 void enumerateServices(HashMap *serviceTable) {
257   check(!services);
258   check(!numServices);
259   iterateOverHashMap(serviceTable, enumerateServicesHelper, NULL);
260 }
This page took 0.351007 seconds and 3 git commands to generate.