1 |
#undef _GNU_SOURCE |
2 |
#define _GNU_SOURCE |
3 |
|
4 |
#include <limits.h> |
5 |
#include <sys/types.h> |
6 |
#include <sys/stat.h> |
7 |
#include <sys/wait.h> |
8 |
#include <dlfcn.h> |
9 |
#include <errno.h> |
10 |
#include <unistd.h> |
11 |
#include <sys/socket.h> |
12 |
#include <sys/socket.h> |
13 |
#include <stdio.h> |
14 |
#include <string.h> |
15 |
#include <arpa/inet.h> |
16 |
|
17 |
#include <unordered_map> |
18 |
#include <mutex> |
19 |
|
20 |
#define PATHBUFSIZE 4097 |
21 |
#define NAMEMAX 255 |
22 |
#define DEFAULT_SHORTENER "/root/enametoolong/shortener-prod" |
23 |
|
24 |
static std::mutex shorten_mutex; |
25 |
|
26 |
static int shortener_fd = -1; |
27 |
static pid_t shortener_pid; |
28 |
|
29 |
static void |
30 |
die (const char *msg) |
31 |
{ |
32 |
perror ("socketpair"); |
33 |
exit (EXIT_FAILURE); |
34 |
} |
35 |
|
36 |
static bool |
37 |
xread (int fd, void *buf, size_t count) |
38 |
{ |
39 |
while (count > 0) |
40 |
{ |
41 |
ssize_t bytesRead = read (fd, buf, count); |
42 |
|
43 |
if (bytesRead < 0) |
44 |
{ |
45 |
if (errno == EINTR) |
46 |
continue; |
47 |
|
48 |
return false; |
49 |
} |
50 |
else if (bytesRead == 0) |
51 |
return false; |
52 |
|
53 |
buf = (char *)buf + bytesRead; |
54 |
count -= bytesRead; |
55 |
} |
56 |
|
57 |
return true; |
58 |
} |
59 |
|
60 |
static bool |
61 |
xwrite(int fd, const void *buf, size_t count) |
62 |
{ |
63 |
while (count > 0) |
64 |
{ |
65 |
ssize_t bytesWritten = send (fd, buf, count, MSG_NOSIGNAL); |
66 |
|
67 |
if (bytesWritten < 0) |
68 |
{ |
69 |
if (errno == EINTR) |
70 |
continue; |
71 |
|
72 |
return false; |
73 |
} |
74 |
|
75 |
buf = (char *)buf + bytesWritten; |
76 |
count -= bytesWritten; |
77 |
} |
78 |
|
79 |
return true; |
80 |
} |
81 |
|
82 |
static void |
83 |
shortener_open (void) |
84 |
{ |
85 |
int sp[2]; |
86 |
|
87 |
if (socketpair (AF_UNIX, SOCK_STREAM, 0, sp) < 0) |
88 |
die ("socketpair"); |
89 |
|
90 |
shortener_pid = vfork (); |
91 |
|
92 |
if (shortener_pid < 0) |
93 |
die ("vfork"); |
94 |
|
95 |
if (shortener_pid == 0) |
96 |
{ |
97 |
dup2 (sp[1], 0); |
98 |
dup2 (sp[1], 1); |
99 |
close (sp[0]); |
100 |
|
101 |
static const char *const argv[2] = { "-", 0 }; |
102 |
const char *shortener_path = secure_getenv ("ENAMETOOLONG_SHORTENER"); |
103 |
execve (shortener_path ? shortener_path : DEFAULT_SHORTENER, const_cast<char *const *>(argv), 0); |
104 |
_exit (126); |
105 |
} |
106 |
|
107 |
close (sp[1]); |
108 |
|
109 |
shortener_fd = sp[0]; |
110 |
} |
111 |
|
112 |
static void |
113 |
shortener_close (void) |
114 |
{ |
115 |
if (shortener_fd < 0) |
116 |
return; |
117 |
|
118 |
close (shortener_fd); |
119 |
shortener_fd = -1; |
120 |
|
121 |
if (shortener_pid > 0) |
122 |
{ |
123 |
int wstatus; |
124 |
waitpid (shortener_pid, &wstatus, 0); |
125 |
shortener_pid = -1; |
126 |
} |
127 |
|
128 |
sleep (1); // rate limit retries |
129 |
} |
130 |
|
131 |
static std::unordered_map<std::string, std::string> cache; |
132 |
|
133 |
__attribute__ ((__cold__, __noinline__)) |
134 |
static const char * |
135 |
shorten (const char *path) |
136 |
{ |
137 |
std::lock_guard<std::mutex> guard (shorten_mutex); |
138 |
|
139 |
std::string &shorter = cache[path]; |
140 |
|
141 |
if (shorter.size ()) |
142 |
return shorter.c_str (); |
143 |
|
144 |
for (;;) |
145 |
{ |
146 |
if (shortener_fd < 0) |
147 |
shortener_open (); |
148 |
|
149 |
uint32_t slen = strlen (path); |
150 |
uint32_t nlen = htonl (slen); |
151 |
xwrite (shortener_fd, &nlen, sizeof nlen); |
152 |
xwrite (shortener_fd, path, slen); |
153 |
|
154 |
if (xread (shortener_fd, &nlen, sizeof nlen)) |
155 |
{ |
156 |
nlen = ntohl (nlen); |
157 |
|
158 |
if (nlen < PATHBUFSIZE) |
159 |
{ |
160 |
shorter.resize (nlen); |
161 |
|
162 |
if (xread (shortener_fd, shorter.data (), nlen)) |
163 |
return shorter.c_str (); |
164 |
} |
165 |
} |
166 |
|
167 |
shortener_close (); |
168 |
} |
169 |
} |
170 |
|
171 |
static bool |
172 |
toolong (const char *path) |
173 |
{ |
174 |
size_t clen = 0; |
175 |
|
176 |
for (;;) |
177 |
{ |
178 |
if (*path == '/') |
179 |
clen = 0; |
180 |
else if (!*path) |
181 |
return false; |
182 |
else if (++clen > NAMEMAX) |
183 |
return true; |
184 |
|
185 |
++path; |
186 |
} |
187 |
} |
188 |
|
189 |
#include "wrap.C" |