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