1 /*
2 * Copyright (c) 1997, 1998, 1999, 2001, 2002, 2004, 2008, 2009, 2010, 2011,
3 * 2012, 2013, 2014, 2020
4 * Inferno Nettverk A/S, Norway. 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. The above copyright notice, this list of conditions and the following
10 * disclaimer must appear in all copies of the software, derivative works
11 * or modified versions, and any portions thereof, aswell as in all
12 * supporting documentation.
13 * 2. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by
16 * Inferno Nettverk A/S, Norway.
17 * 3. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Inferno Nettverk A/S requests users of this software to return to
32 *
33 * Software Distribution Coordinator or sdc@inet.no
34 * Inferno Nettverk A/S
35 * Oslo Research Park
36 * Gaustadall�en 21
37 * NO-0349 Oslo
38 * Norway
39 *
40 * any improvements or extensions that they make and grant Inferno Nettverk A/S
41 * the rights to redistribute these changes.
42 *
43 */
44
45 #include "common.h"
46
47 static const char rcsid[] =
48 "$Id: Rcompat.c,v 1.89.4.2.6.2 2020/11/11 16:11:51 karls Exp $";
49
50 #if !HAVE_DECL_GETS
51 char *gets(char *buf);
52 #endif /* !HAVE_DECL_GETS */
53
54 int
Rselect(nfds,readfds,writefds,exceptfds,timeout)55 Rselect(nfds, readfds, writefds, exceptfds, timeout)
56 int nfds;
57 fd_set *readfds;
58 fd_set *writefds;
59 fd_set *exceptfds;
60 struct timeval *timeout;
61 {
62 return select(nfds, readfds, writefds, exceptfds, timeout);
63 }
64
65 ssize_t
Rwrite(d,buf,nbytes)66 Rwrite(d, buf, nbytes)
67 int d;
68 const void *buf;
69 size_t nbytes;
70 {
71 const char *function = "Rwrite()";
72
73 clientinit();
74
75 slog(LOG_DEBUG, "%s: fd %d, bytes %lu", function, d, (unsigned long)nbytes);
76
77 return Rsend(d, buf, nbytes, 0);
78 }
79
80 ssize_t
Rwritev(d,iov,iovcnt)81 Rwritev(d, iov, iovcnt)
82 int d;
83 const struct iovec *iov;
84 int iovcnt;
85 {
86 struct msghdr msg;
87 const char *function = "Rwritev()";
88
89 clientinit();
90
91 slog(LOG_DEBUG, "%s: fd %d, iovcnt %d", function, d, iovcnt);
92
93 bzero(&msg, sizeof(msg));
94 msg.msg_iov = iov;
95 msg.msg_iovlen = iovcnt;
96
97 return Rsendmsg(d, &msg, 0);
98 }
99
100 ssize_t
Rsend(s,msg,len,flags)101 Rsend(s, msg, len, flags)
102 int s;
103 const void *msg;
104 size_t len;
105 int flags;
106 {
107 const char *function = "Rsend()";
108 struct msghdr msghdr;
109 /* any way to get rid of warning about losing const except make a copy? */
110 struct iovec iov = { msg, len };
111
112 clientinit();
113
114 slog(LOG_DEBUG, "%s: fd %d, bytes %lu, flags %d",
115 function, s, (unsigned long)len, flags);
116
117 bzero(&msghdr, sizeof(msghdr));
118 msghdr.msg_iov = &iov;
119 msghdr.msg_iovlen = 1;
120
121 return Rsendmsg(s, &msghdr, flags);
122 }
123
124 ssize_t
Rsendmsg(s,msg,flags)125 Rsendmsg(s, msg, flags)
126 int s;
127 const struct msghdr *msg;
128 int flags;
129 {
130 const int errno_s = errno;
131 size_t sent, ioc;
132 ssize_t rc;
133 struct sockaddr_storage name;
134 socklen_t namelen;
135 const char *function = "Rsendmsg()";
136
137 clientinit();
138
139 slog(LOG_DEBUG, "%s: fd %d, msg %p, flags %d",
140 function, s, msg, flags);
141
142 if (msg == NULL)
143 return write(s, NULL, 0);
144
145 namelen = sizeof(name);
146 if (getsockname(s, TOSA(&name), &namelen) == -1) {
147 errno = errno_s;
148 return writev(s, msg->msg_iov, (int)msg->msg_iovlen);
149 }
150
151 switch (TOSA(&name)->sa_family) {
152 case AF_INET:
153 break;
154
155 case AF_INET6:
156 break;
157
158 default:
159 return sendmsg(s, msg, flags);
160 }
161
162 for (sent = ioc = rc = 0; ioc < (size_t)msg->msg_iovlen; ++ioc) {
163 if ((rc = Rsendto(s,
164 msg->msg_iov[ioc].iov_base,
165 msg->msg_iov[ioc].iov_len,
166 flags,
167 TOSA(msg->msg_name),
168 msg->msg_namelen)) == -1)
169 break;
170
171 sent += rc;
172
173 if (rc != (ssize_t)msg->msg_iov[ioc].iov_len)
174 break;
175 }
176
177 if (sent <= 0)
178 return rc;
179
180 return sent;
181 }
182
183 ssize_t
Rread(d,buf,nbytes)184 Rread(d, buf, nbytes)
185 int d;
186 void *buf;
187 size_t nbytes;
188 {
189 const char *function = "Rread()";
190
191 clientinit();
192
193 slog(LOG_DEBUG, "%s: fd %d, bytes %lu",
194 function, d, (unsigned long)nbytes);
195
196 return Rrecv(d, buf, nbytes, 0);
197 }
198
199 ssize_t
Rreadv(d,_iov,iovcnt)200 Rreadv(d, _iov, iovcnt)
201 int d;
202 const struct iovec *_iov;
203 int iovcnt;
204 {
205 const char *function = "Rreadv()";
206 struct iovec iov[1] = { { _iov->iov_base, _iov->iov_len } };
207 struct msghdr msg;
208
209 clientinit();
210
211 slog(LOG_DEBUG, "%s: fd %d, iovcnt %d", function, d, iovcnt);
212
213 bzero(&msg, sizeof(msg));
214 /* LINTED operands have incompatible pointer types */
215 msg.msg_iov = iov;
216 msg.msg_iovlen = iovcnt;
217
218 return Rrecvmsg(d, &msg, 0);
219 }
220
221 ssize_t
Rrecv(s,msg,len,flags)222 Rrecv(s, msg, len, flags)
223 int s;
224 void *msg;
225 size_t len;
226 int flags;
227 {
228 struct msghdr msghdr;
229 struct iovec iov;
230 const char *function = "Rrecv()";
231
232 clientinit();
233
234 slog(LOG_DEBUG, "%s: fd %d, len %lu, flags %d",
235 function, s, (unsigned long)len, flags);
236
237 /* LINTED cast discards 'const' from pointer target type */
238 bzero(&iov, sizeof(iov));
239 iov.iov_base = (void *)msg;
240 iov.iov_len = len;
241
242 bzero(&msghdr, sizeof(msghdr));
243 msghdr.msg_iov = &iov;
244 msghdr.msg_iovlen = 1;
245
246 return Rrecvmsg(s, &msghdr, flags);
247 }
248
249 ssize_t
Rrecvmsg(s,msg,flags)250 Rrecvmsg(s, msg, flags)
251 int s;
252 struct msghdr *msg;
253 int flags;
254 {
255 const int errno_s = errno;
256 size_t received, ioc;
257 ssize_t rc;
258 struct sockaddr_storage name;
259 socklen_t namelen;
260 const char *function = "Rrecvmsg()";
261
262 clientinit();
263
264 slog(LOG_DEBUG, "%s: fd %d, msg %p, flags %d",
265 function, s, msg, flags);
266
267 if (msg == NULL) {
268 rc = recvmsg(s, msg, flags);
269 slog(LOG_DEBUG, "%s: rc = %ld", function, (long)rc);
270
271 return rc;
272 }
273
274 namelen = sizeof(name);
275 if (getsockname(s, TOSA(&name), &namelen) == -1) {
276 errno = errno_s;
277
278 /* readv(2). recvmsg(2) is only for sockets. */
279 rc = readv(s, msg->msg_iov, (int)msg->msg_iovlen);
280 slog(LOG_DEBUG, "%s: rc = %ld", function, (long)rc);
281
282 return rc;
283 }
284
285 switch (TOSA(&name)->sa_family) {
286 case AF_INET:
287 break;
288
289 #ifdef AF_INET6
290 case AF_INET6:
291 break;
292 #endif /* AF_INET6 */
293
294 default:
295 return recvmsg(s, msg, flags);
296 }
297
298 /* no cmsg on proxied sockets. */
299 CMSG_TOTLEN(*msg) = 0;
300 CMSG_CONTROLDATA(*msg) = NULL;
301
302 for (received = ioc = rc = 0; ioc < (size_t)msg->msg_iovlen; ++ioc) {
303 if ((rc = Rrecvfrom(s,
304 msg->msg_iov[ioc].iov_base,
305 msg->msg_iov[ioc].iov_len,
306 flags,
307 TOSA(msg->msg_name),
308 &msg->msg_namelen)) == -1)
309 break;
310
311 received += rc;
312
313 if (rc != (ssize_t)msg->msg_iov[ioc].iov_len)
314 break;
315 }
316
317 slog(LOG_DEBUG, "%s: bytes received on fd %d: %ld (%s)",
318 function, s, (long)rc, strerror(errno));
319
320 if (received <= 0)
321 return rc;
322
323 return received;
324 }
325
326 #if HAVE_GSSAPI && HAVE_LINUX_GLIBC_WORKAROUND
327 /*
328 * This code was contributed by
329 * Markus Moeller (markus_moeller at compuserve.com).
330 */
331
332 int
Rfputc(c,stream)333 Rfputc(c, stream)
334 int c;
335 FILE *stream;
336 {
337 const char *function = "Rfputc()";
338 const int d = fileno(stream);
339
340 clientinit();
341
342 slog(LOG_DEBUG, "%s: fd %d", function, d);
343
344 if (!gssapi_isencrypted(d))
345 return fputc(c, stream);
346
347 socks_setbufferfd(d, _IOFBF, -1);
348
349 return Rsend(d, &c, sizeof(char), 0);
350 }
351
352 int
Rfputs(buf,stream)353 Rfputs(buf, stream)
354 const char *buf;
355 FILE *stream;
356 {
357 const char *function = "Rfputs()";
358 const int d = fileno(stream);
359
360 clientinit();
361
362 slog(LOG_DEBUG, "%s: fd %d", function, d);
363
364 if (!gssapi_isencrypted(d))
365 return fputs(buf,stream);
366
367 socks_setbufferfd(d, _IOFBF, -1);
368
369 return Rsend(d, buf, strlen(buf), 0);
370 }
371
372 size_t
Rfwrite(ptr,size,nmb,stream)373 Rfwrite(ptr, size, nmb, stream)
374 const void *ptr;
375 size_t size; size_t nmb;
376 FILE *stream;
377 {
378 const char *function = "Rfwrite()";
379 const unsigned char *buf=ptr;
380 const int d = fileno(stream);
381 size_t i;
382
383 slog(LOG_DEBUG, "%s: fd %d", function, d);
384
385 if (!gssapi_isencrypted(d))
386 return fwrite(ptr, size, nmb, stream);
387
388 socks_setbufferfd(d, _IOFBF, -1);
389
390 for (i = 0; i < nmb; ++i)
391 if (Rwrite(d,buf+i*size,size) <= 0)
392 return i;
393
394 return nmb;
395 }
396
397 int
Rfprintf(FILE * stream,const char * format,...)398 Rfprintf(FILE *stream, const char *format, ...)
399 {
400 const int d = fileno(stream);
401 const char *function = "Rfprintf()";
402 va_list ap;
403 int rc;
404
405 slog(LOG_DEBUG, "%s: fd %d", function, d);
406
407 va_start(ap, format);
408
409 socks_setbufferfd(d, _IOFBF, -1);
410
411 rc = Rvfprintf(stream, format, ap);
412
413 va_end(ap);
414
415 return rc;
416 }
417
418 int
Rvfprintf(stream,format,ap)419 Rvfprintf(stream, format, ap)
420 FILE *stream;
421 const char *format;
422 va_list ap;
423 {
424 const char *function = "Rvfprintf()";
425 const int d = fileno(stream);
426 ssize_t len;
427 char buf[8 * BUFSIZ];
428
429 slog(LOG_DEBUG, "%s: fd %d", function, d);
430
431 if (!gssapi_isencrypted(d))
432 return vfprintf(stream, format, ap);
433
434 len = vsnprintf(buf, sizeof(buf), format, ap);
435 if (len > (ssize_t)sizeof(buf))
436 len = (ssize_t)sizeof(buf);
437
438 socks_setbufferfd(d, _IOFBF, -1);
439
440 return Rwrite(d, buf, len);
441 }
442
443 int
Rfflush(s)444 Rfflush(s)
445 FILE *s;
446 {
447 const char *function = "Rfflush()";
448 int d;
449
450 if (s == NULL) {
451 (void)socks_flushbuffer(-1, -1, NULL);
452 return fflush(s);
453 }
454
455 d = fileno(s);
456
457 slog(LOG_DEBUG, "%s: fd %d", function, d);
458
459 if (!gssapi_isencrypted(d))
460 return fflush(s);
461
462 (void)socks_flushbuffer(d, -1, NULL);
463 return 0;
464 }
465
466 int
Rfclose(s)467 Rfclose(s)
468 FILE *s;
469 {
470 const char *function = "Rfclose()";
471 const int d = fileno(s);
472
473 clientinit();
474
475 slog(LOG_DEBUG, "%s: fd %d", function, d);
476
477 if (gssapi_isencrypted(d))
478 (void)socks_flushbuffer(d, -1, NULL);
479
480 return fclose(s);
481 }
482
Rfgetc(stream)483 int Rfgetc(stream)
484 FILE *stream;
485 {
486 const char *function = "Rfgetc()";
487 unsigned char c;
488 const int d = fileno(stream);
489
490 clientinit();
491
492 slog(LOG_DEBUG, "%s: fd %d", function, d);
493
494 if (!gssapi_isencrypted(d))
495 return fgetc(stream);
496
497 if (Rread(d, &c, 1) != 1)
498 return EOF;
499
500 return (int)c;
501 }
502
503 char *
Rgets(buf)504 Rgets(buf)
505 char *buf;
506 {
507 const char *function = "Rgets()";
508 const int d = fileno(stdin);
509 size_t i;
510
511 clientinit();
512
513 slog(LOG_DEBUG, "%s: fd %d", function, d);
514
515 if (!gssapi_isencrypted(d))
516 return gets(buf);
517
518 i = 0;
519 while (Rread(d, buf + i, 1) == 1 && buf[i] != '\n')
520 ++i;
521 buf[i] = NUL;
522
523 return buf;
524 }
525
526 char *
Rfgets(buf,size,stream)527 Rfgets(buf, size, stream)
528 char *buf;
529 int size;
530 FILE *stream;
531 {
532 const char *function = "Rfgets()";
533 const int d = fileno(stream);
534 int i;
535
536 clientinit();
537
538 slog(LOG_DEBUG, "%s: fd %d", function, d);
539
540 if (!gssapi_isencrypted(d))
541 return fgets(buf, size, stream);
542
543 i = 0;
544 while (Rread(d, buf + i, 1) == 1 && i < size - 1 && buf[i] != '\n')
545 ++i;
546
547 if (size >= 1)
548 buf[i != 0 ? i + 1 : i] = NUL;
549
550 return buf;
551 }
552
553 size_t
Rfread(void * ptr,size_t size,size_t nmb,FILE * stream)554 Rfread(void *ptr, size_t size, size_t nmb, FILE *stream)
555 {
556 const char *function = "Rfread()";
557 unsigned char *buf=(unsigned char *)ptr;
558 size_t i;
559 const int d = fileno(stream);
560
561 slog(LOG_DEBUG, "%s: fd %d", function, d);
562
563 if (!gssapi_isencrypted(d))
564 return fread(ptr, size, nmb, stream);
565
566 for (i = 0; i < nmb; ++i)
567 if (Rread(d, buf + (i * size), size) <= 0)
568 return i;
569
570 return nmb;
571 }
572 #endif /* HAVE_GSSAPI && HAVE_LINUX_GLIBC_WORKAROUND */
573