Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2013-2014 Baptiste Daroussin <bapt@FreeBSD.org>
3 : : * Copyright (c) 2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
4 : : * All rights reserved.
5 : : *
6 : : * Redistribution and use in source and binary forms, with or without
7 : : * modification, are permitted provided that the following conditions
8 : : * are met:
9 : : * 1. Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer
11 : : * in this position and unchanged.
12 : : * 2. Redistributions in binary form must reproduce the above copyright
13 : : * notice, this list of conditions and the following disclaimer in the
14 : : * documentation and/or other materials provided with the distribution.
15 : : *
16 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
17 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 : : * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
20 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 : : */
27 : :
28 : : #ifdef HAVE_CONFIG_H
29 : : #include "pkg_config.h"
30 : : #endif
31 : : #ifdef HAVE_CAPSICUM
32 : : #include <sys/capsicum.h>
33 : : #endif
34 : : #include <sys/types.h>
35 : : #include <sys/param.h>
36 : : #include <sys/stat.h>
37 : :
38 : : #include <ctype.h>
39 : : #include <stdlib.h>
40 : : #include <inttypes.h>
41 : : #include <stdio.h>
42 : : #include <string.h>
43 : : #include <unistd.h>
44 : : #include <fcntl.h>
45 : :
46 : : #include <bsd_compat.h>
47 : :
48 : : #include "pkg.h"
49 : : #include "private/event.h"
50 : : #include "private/utils.h"
51 : :
52 : : int
53 : 5 : pkg_sshserve(int fd)
54 : : {
55 : : struct stat st;
56 : 5 : char *line = NULL;
57 : : char *file, *age;
58 : 5 : size_t linecap = 0, r;
59 : : ssize_t linelen;
60 : 5 : time_t mtime = 0;
61 : : const char *errstr;
62 : : int ffd;
63 : : char buf[32768];
64 : : char fpath[MAXPATHLEN];
65 : : char rpath[MAXPATHLEN];
66 : 5 : const char *restricted = NULL;
67 : :
68 : 5 : restricted = pkg_object_string(pkg_config_get("SSH_RESTRICT_DIR"));
69 : :
70 : 5 : printf("ok: pkg "PKGVERSION"\n");
71 : 7 : for (;;) {
72 [ - + ]: 17 : if ((linelen = getline(&line, &linecap, stdin)) < 0)
73 : 0 : break;
74 : :
75 [ + - ]: 17 : if (linelen == 0)
76 : 0 : continue;
77 : :
78 : : /* trim cr */
79 [ - + ]: 17 : if (line[linelen - 1] == '\n')
80 : 17 : line[linelen - 1] = '\0';
81 : :
82 [ + + ]: 17 : if (STREQ(line, "quit")) {
83 : 5 : free(line);
84 : 5 : return (EPKG_OK);
85 : : }
86 : :
87 [ + + ]: 12 : if (strncmp(line, "get ", 4) != 0) {
88 : 1 : printf("ko: unknown command '%s'\n", line);
89 : 1 : continue;
90 : : }
91 : :
92 : 11 : file = line + 4;
93 : :
94 [ + + ]: 11 : if (*file == '\0') {
95 : 1 : printf("ko: bad command get, expecting 'get file age'\n");
96 : 1 : continue;
97 : : }
98 [ + + ]: 10 : if (*file == '/')
99 : 7 : file++;
100 : :
101 : 10 : pkg_debug(1, "SSH server> file requested: %s", file);
102 : :
103 : 10 : age = file;
104 [ + + ]: 129 : while (!isspace(*age)) {
105 [ + + ]: 120 : if (*age == '\0') {
106 : 1 : age = NULL;
107 : 1 : break;
108 : : }
109 : 119 : age++;
110 : : }
111 : :
112 [ + + ]: 10 : if (age == NULL) {
113 : 1 : printf("ko: bad command get, expecting 'get file age'\n");
114 : 1 : continue;
115 : : }
116 : :
117 : 9 : *age = '\0';
118 : 9 : age++;
119 : :
120 [ + - ]: 9 : while (isspace(*age)) {
121 [ # # ]: 0 : if (*age == '\0') {
122 : 0 : age = NULL;
123 : 0 : break;
124 : : }
125 : 0 : age++;
126 : : }
127 : :
128 [ + - ]: 9 : if (age == NULL) {
129 : 0 : printf("ko: bad command get, expecting 'get file age'\n");
130 : 0 : continue;
131 : : }
132 : :
133 : 9 : mtime = strtonum(age, 0, LONG_MAX, &errstr);
134 [ + + ]: 9 : if (errstr) {
135 : 1 : printf("ko: bad number %s: %s\n", age, errstr);
136 : 1 : continue;
137 : : }
138 : :
139 : : #ifdef HAVE_CAPSICUM
140 : : if (!cap_sandboxed() && restricted != NULL) {
141 : : #else
142 [ + + ]: 8 : if (restricted != NULL) {
143 : : #endif
144 [ + + ]: 7 : if (chdir(restricted)) {
145 : 1 : printf("ko: chdir failed (%s)\n", restricted);
146 : 1 : continue;
147 : : }
148 : :
149 [ + + + + ]: 10 : if (realpath(file, fpath) == NULL ||
150 [ - + ]: 4 : realpath(restricted, rpath) == NULL ||
151 : 4 : strncmp(rpath, get_dirname(fpath), strlen(rpath)) != 0) {
152 : 3 : printf("ko: file not found\n");
153 : 3 : continue;
154 : : }
155 : 3 : }
156 : :
157 [ + - ]: 4 : if (fstatat(fd, file, &st, 0) == -1) {
158 : 0 : pkg_debug(1, "SSH server> fstatat failed");
159 : 0 : printf("ko: file not found\n");
160 : 0 : continue;
161 : : }
162 : :
163 [ + + ]: 4 : if (!S_ISREG(st.st_mode)) {
164 : 1 : printf("ko: not a file\n");
165 : 1 : continue;
166 : : }
167 : :
168 [ + + ]: 3 : if (st.st_mtime <= mtime) {
169 : 1 : printf("ok: 0\n");
170 : 1 : continue;
171 : : }
172 : :
173 [ + - ]: 2 : if ((ffd = openat(fd, file, O_RDONLY)) == -1) {
174 : 0 : printf("ko: file not found\n");
175 : 0 : continue;
176 : : }
177 : :
178 : 2 : printf("ok: %" PRIdMAX "\n", (intmax_t)st.st_size);
179 : 2 : pkg_debug(1, "SSH server> sending ok: %" PRIdMAX "", (intmax_t)st.st_size);
180 : :
181 [ + + ]: 4 : while ((r = read(ffd, buf, sizeof(buf))) > 0) {
182 : 2 : pkg_debug(1, "SSH server> sending data");
183 : 2 : fwrite(buf, 1, r, stdout);
184 : : }
185 : :
186 : 2 : pkg_debug(1, "SSH server> finished");
187 : :
188 : 2 : close(ffd);
189 : : }
190 : :
191 : 0 : free(line);
192 : :
193 : 0 : return (EPKG_OK);
194 : 5 : }
|