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/capability.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 <inttypes.h>
40 : #define _WITH_GETLINE
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 :
51 : int
52 0 : pkg_sshserve(int fd)
53 : {
54 : struct stat st;
55 0 : char *line = NULL;
56 : char *file, *age;
57 0 : size_t linecap = 0, r;
58 : ssize_t linelen;
59 0 : time_t mtime = 0;
60 : const char *errstr;
61 : int ffd;
62 : char buf[BUFSIZ];
63 : char fpath[MAXPATHLEN];
64 : char rpath[MAXPATHLEN];
65 0 : const char *restricted = NULL;
66 :
67 0 : restricted = pkg_object_string(pkg_config_get("SSH_RESTRICT_DIR"));
68 :
69 0 : printf("ok: pkg "PKGVERSION"\n");
70 : for (;;) {
71 0 : if ((linelen = getline(&line, &linecap, stdin)) < 0)
72 0 : break;
73 :
74 0 : if (linelen == 0)
75 0 : continue;
76 :
77 : /* trim cr */
78 0 : if (line[linelen - 1] == '\n')
79 0 : line[linelen - 1] = '\0';
80 :
81 0 : if (strcmp(line, "quit") == 0)
82 0 : return (EPKG_OK);
83 :
84 0 : if (strncmp(line, "get ", 4) != 0) {
85 0 : printf("ko: unknown command '%s'\n", line);
86 0 : continue;
87 : }
88 :
89 0 : file = line + 4;
90 :
91 0 : if (*file == '/')
92 0 : file++;
93 0 : else if (*file == '\0') {
94 0 : printf("ko: bad command get, expecting 'get file age'\n");
95 0 : continue;
96 : }
97 :
98 0 : pkg_debug(1, "SSH server> file requested: %s", file);
99 :
100 0 : age = file;
101 0 : while (!isspace(*age)) {
102 0 : if (*age == '\0') {
103 0 : age = NULL;
104 0 : break;
105 : }
106 0 : age++;
107 : }
108 :
109 0 : if (age == NULL) {
110 0 : printf("ko: bad command get, expecting 'get file age'\n");
111 0 : continue;
112 : }
113 :
114 0 : *age = '\0';
115 0 : age++;
116 :
117 0 : while (isspace(*age)) {
118 0 : if (*age == '\0') {
119 0 : age = NULL;
120 0 : break;
121 : }
122 0 : age++;
123 : }
124 :
125 0 : if (age == NULL) {
126 0 : printf("ko: bad command get, expecting 'get file age'\n");
127 0 : continue;
128 : }
129 :
130 0 : mtime = strtonum(age, 0, LONG_MAX, &errstr);
131 0 : if (errstr) {
132 0 : printf("ko: bad number %s: %s\n", age, errstr);
133 0 : continue;
134 : }
135 :
136 : #ifdef HAVE_CAPSICUM
137 0 : if (!cap_sandboxed() && restricted != NULL) {
138 : #else
139 : if (restricted != NULL) {
140 : #endif
141 0 : chdir(restricted);
142 0 : if (realpath(file, fpath) == NULL ||
143 0 : realpath(restricted, rpath) == NULL ||
144 0 : strncmp(fpath, rpath, strlen(rpath)) != 0) {
145 0 : printf("ko: file not found\n");
146 0 : continue;
147 : }
148 : }
149 :
150 0 : if (fstatat(fd, file, &st, 0) == -1) {
151 0 : pkg_debug(1, "SSH server> fstatat failed");
152 0 : printf("ko: file not found\n");
153 0 : continue;
154 : }
155 :
156 0 : if (!S_ISREG(st.st_mode)) {
157 0 : printf("ko: not a file\n");
158 0 : continue;
159 : }
160 :
161 0 : if (st.st_mtime <= mtime) {
162 0 : printf("ok: 0\n");
163 0 : continue;
164 : }
165 :
166 0 : if ((ffd = openat(fd, file, O_RDONLY)) == -1) {
167 0 : printf("ko: file not found\n");
168 0 : continue;
169 : }
170 :
171 0 : printf("ok: %" PRIdMAX "\n", (intmax_t)st.st_size);
172 0 : pkg_debug(1, "SSH server> sending ok: %" PRIdMAX "", (intmax_t)st.st_size);
173 :
174 0 : while ((r = read(ffd, buf, sizeof(buf))) > 0) {
175 0 : pkg_debug(1, "SSH server> sending data");
176 0 : fwrite(buf, 1, r, stdout);
177 : }
178 :
179 0 : pkg_debug(1, "SSH server> finished");
180 :
181 0 : close(ffd);
182 0 : }
183 :
184 0 : free(line);
185 :
186 0 : return (EPKG_OK);
187 : }
|