Skip to content

Commit 4684440

Browse files
committed
SECURITY FIX: Actually restrict the access to the printer to localhost
Before, any machine in any network connected by any of the interfaces (as listed by "ifconfig") could access to an IPP-over-USB printer on the assigned port, allowing users on remote machines to print and to access the web configuration interface of a IPP-over-USB printer in contrary to conventional USB printers which are only accessible locally.
1 parent 9cae16b commit 4684440

File tree

3 files changed

+125
-15
lines changed

3 files changed

+125
-15
lines changed

Diff for: src/ippusbxd.c

+22-6
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,12 @@ static void start_daemon()
171171

172172
// Capture a socket
173173
uint16_t desired_port = g_options.desired_port;
174-
struct tcp_sock_t *tcp_socket;
175-
while ((tcp_socket = tcp_open(desired_port)) == NULL &&
176-
g_options.only_desired_port == 0) {
174+
struct tcp_sock_t *tcp_socket = NULL, *tcp6_socket = NULL;
175+
for (;;) {
176+
tcp_socket = tcp_open(desired_port);
177+
tcp6_socket = tcp6_open(desired_port);
178+
if (tcp_socket || tcp6_socket || g_options.only_desired_port)
179+
break;
177180
// Search for a free port
178181
desired_port ++;
179182
// We failed with 0 as port number or we reached the max
@@ -183,11 +186,16 @@ static void start_daemon()
183186
// ports
184187
// https://en.wikipedia.org/wiki/Ephemeral_port
185188
desired_port = 49152;
189+
NOTE("Access to desired port failed, trying alternative port %d", desired_port);
186190
}
187-
if (tcp_socket == NULL)
191+
if (tcp_socket == NULL && tcp6_socket == NULL)
188192
goto cleanup_tcp;
189193

190-
uint16_t real_port = tcp_port_number_get(tcp_socket);
194+
uint16_t real_port;
195+
if (tcp_socket)
196+
real_port = tcp_port_number_get(tcp_socket);
197+
else
198+
real_port = tcp_port_number_get(tcp6_socket);
191199
if (desired_port != 0 && g_options.only_desired_port == 1 &&
192200
desired_port != real_port) {
193201
ERR("Received port number did not match requested port number."
@@ -197,6 +205,9 @@ static void start_daemon()
197205
printf("%u|", real_port);
198206
fflush(stdout);
199207

208+
NOTE("Port: %d, IPv4 %savailable, IPv6 %savailable",
209+
real_port, tcp_socket ? "" : "not ", tcp6_socket ? "" : "not ");
210+
200211
// Lose connection to caller
201212
uint16_t pid;
202213
if (!g_options.nofork_mode && (pid = fork()) > 0) {
@@ -216,7 +227,10 @@ static void start_daemon()
216227
}
217228

218229
args->usb_sock = usb_sock;
219-
args->tcp = tcp_conn_accept(tcp_socket);
230+
231+
// For each request/response round we use the socket (IPv4 or
232+
// IPv6) which receives data first
233+
args->tcp = tcp_conn_select(tcp_socket, tcp6_socket);
220234
if (args->tcp == NULL) {
221235
ERR("Failed to open tcp connection");
222236
goto cleanup_thread;
@@ -243,6 +257,8 @@ static void start_daemon()
243257
cleanup_tcp:
244258
if (tcp_socket!= NULL)
245259
tcp_close(tcp_socket);
260+
if (tcp6_socket!= NULL)
261+
tcp_close(tcp6_socket);
246262
cleanup_usb:
247263
if (usb_sock != NULL)
248264
usb_close(usb_sock);

Diff for: src/tcp.c

+100-8
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
#include <stdlib.h>
1818
#include <string.h>
1919
#include <ctype.h>
20+
#include <sys/time.h>
21+
#include <sys/types.h>
22+
#include <unistd.h>
2023

2124
#include <fcntl.h>
2225
#include <unistd.h>
@@ -31,15 +34,66 @@ struct tcp_sock_t *tcp_open(uint16_t port)
3134
{
3235
struct tcp_sock_t *this = calloc(1, sizeof *this);
3336
if (this == NULL) {
34-
ERR("callocing this failed");
37+
ERR("IPv4: callocing this failed");
38+
goto error;
39+
}
40+
41+
// Open [S]ocket [D]escriptor
42+
this->sd = -1;
43+
this->sd = socket(AF_INET, SOCK_STREAM, 0);
44+
if (this->sd < 0) {
45+
ERR("IPv4 socket open failed");
46+
goto error;
47+
}
48+
49+
// Configure socket params
50+
struct sockaddr_in addr;
51+
memset(&addr, 0, sizeof addr);
52+
addr.sin_family = AF_INET;
53+
addr.sin_port = htons(port);
54+
addr.sin_addr.s_addr = htonl(0x7F000001);
55+
56+
// Bind to localhost
57+
if (bind(this->sd,
58+
(struct sockaddr *)&addr,
59+
sizeof addr) < 0) {
60+
if (g_options.only_desired_port == 1)
61+
ERR("IPv4 bind on port failed. "
62+
"Requested port may be taken or require root permissions.");
63+
goto error;
64+
}
65+
66+
// Let kernel over-accept max number of connections
67+
if (listen(this->sd, HTTP_MAX_PENDING_CONNS) < 0) {
68+
ERR("IPv4 listen failed on socket");
69+
goto error;
70+
}
71+
72+
return this;
73+
74+
error:
75+
if (this != NULL) {
76+
if (this->sd != -1) {
77+
close(this->sd);
78+
}
79+
free(this);
80+
}
81+
return NULL;
82+
}
83+
84+
struct tcp_sock_t *tcp6_open(uint16_t port)
85+
{
86+
struct tcp_sock_t *this = calloc(1, sizeof *this);
87+
if (this == NULL) {
88+
ERR("IPv6: callocing this failed");
3589
goto error;
3690
}
3791

3892
// Open [S]ocket [D]escriptor
3993
this->sd = -1;
4094
this->sd = socket(AF_INET6, SOCK_STREAM, 0);
4195
if (this->sd < 0) {
42-
ERR("sockect open failed");
96+
ERR("Ipv6 socket open failed");
4397
goto error;
4498
}
4599

@@ -48,21 +102,21 @@ struct tcp_sock_t *tcp_open(uint16_t port)
48102
memset(&addr, 0, sizeof addr);
49103
addr.sin6_family = AF_INET6;
50104
addr.sin6_port = htons(port);
51-
addr.sin6_addr = in6addr_any;
105+
addr.sin6_addr = in6addr_loopback;
52106

53107
// Bind to localhost
54108
if (bind(this->sd,
55109
(struct sockaddr *)&addr,
56110
sizeof addr) < 0) {
57111
if (g_options.only_desired_port == 1)
58-
ERR("Bind on port failed. "
112+
ERR("IPv6 bind on port failed. "
59113
"Requested port may be taken or require root permissions.");
60114
goto error;
61115
}
62116

63117
// Let kernel over-accept max number of connections
64118
if (listen(this->sd, HTTP_MAX_PENDING_CONNS) < 0) {
65-
ERR("listen failed on socket");
119+
ERR("IPv6 listen failed on socket");
66120
goto error;
67121
}
68122

@@ -179,20 +233,58 @@ void tcp_packet_send(struct tcp_conn_t *conn, struct http_packet_t *pkt)
179233
}
180234

181235

182-
struct tcp_conn_t *tcp_conn_accept(struct tcp_sock_t *sock)
236+
struct tcp_conn_t *tcp_conn_select(struct tcp_sock_t *sock,
237+
struct tcp_sock_t *sock6)
183238
{
184239
struct tcp_conn_t *conn = calloc(1, sizeof *conn);
185240
if (conn == NULL) {
186241
ERR("Calloc for connection struct failed");
187242
goto error;
188243
}
244+
fd_set rfds;
245+
struct timeval tv;
246+
int retval = 0;
247+
int nfds = 0;
248+
while (retval == 0) {
249+
FD_ZERO(&rfds);
250+
if (sock) {
251+
FD_SET(sock->sd, &rfds);
252+
nfds = sock->sd;
253+
}
254+
if (sock6) {
255+
FD_SET(sock6->sd, &rfds);
256+
if (sock6->sd > nfds)
257+
nfds = sock6->sd;
258+
}
259+
if (nfds == 0) {
260+
ERR("No valid TCP socket supplied.");
261+
goto error;
262+
}
263+
nfds += 1;
264+
/* Wait up to five seconds. */
265+
tv.tv_sec = 5;
266+
tv.tv_usec = 0;
267+
retval = select(nfds, &rfds, NULL, NULL, &tv);
268+
if (retval == -1) {
269+
ERR("Failed to open tcp connection");
270+
goto error;
271+
}
272+
}
189273

190-
conn->sd = accept(sock->sd, NULL, NULL);
274+
if (sock && FD_ISSET(sock->sd, &rfds)) {
275+
conn->sd = accept(sock->sd, NULL, NULL);
276+
NOTE ("Using IPv4");
277+
} else if (sock6 && FD_ISSET(sock6->sd, &rfds)) {
278+
conn->sd = accept(sock6->sd, NULL, NULL);
279+
NOTE ("Using IPv6");
280+
} else {
281+
ERR("select failed");
282+
goto error;
283+
}
191284
if (conn->sd < 0) {
192285
ERR("accept failed");
193286
goto error;
194287
}
195-
196288
return conn;
197289

198290
error:

Diff for: src/tcp.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,12 @@ struct tcp_conn_t {
4040
};
4141

4242
struct tcp_sock_t *tcp_open(uint16_t);
43+
struct tcp_sock_t *tcp6_open(uint16_t);
4344
void tcp_close(struct tcp_sock_t *);
4445
uint16_t tcp_port_number_get(struct tcp_sock_t *);
4546

46-
struct tcp_conn_t *tcp_conn_accept(struct tcp_sock_t *);
47+
struct tcp_conn_t *tcp_conn_select(struct tcp_sock_t *sock,
48+
struct tcp_sock_t *sock6);
4749
void tcp_conn_close(struct tcp_conn_t *);
4850

4951
struct http_packet_t *tcp_packet_get(struct tcp_conn_t *,

0 commit comments

Comments
 (0)