net.c revision 330897
1193240Ssam/*-
2193240Ssam * SPDX-License-Identifier: BSD-3-Clause
3193240Ssam *
4193240Ssam * Copyright (c) 1989, 1993
5193240Ssam *	The Regents of the University of California.  All rights reserved.
6193240Ssam *
7193240Ssam * This code is derived from software contributed to Berkeley by
8193240Ssam * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
9193240Ssam *
10193240Ssam * Redistribution and use in source and binary forms, with or without
11193240Ssam * modification, are permitted provided that the following conditions
12193240Ssam * are met:
13193240Ssam * 1. Redistributions of source code must retain the above copyright
14193240Ssam *    notice, this list of conditions and the following disclaimer.
15193240Ssam * 2. Redistributions in binary form must reproduce the above copyright
16193240Ssam *    notice, this list of conditions and the following disclaimer in the
17193240Ssam *    documentation and/or other materials provided with the distribution.
18193240Ssam * 4. Neither the name of the University nor the names of its contributors
19193240Ssam *    may be used to endorse or promote products derived from this software
20193240Ssam *    without specific prior written permission.
21193240Ssam *
22193240Ssam * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23193240Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24193240Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25193240Ssam * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26193240Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27193240Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28193240Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29193240Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30193240Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31193240Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32193240Ssam * SUCH DAMAGE.
33193240Ssam */
34193240Ssam
35193240Ssam#if 0
36193240Ssam#ifndef lint
37193240Ssamstatic char sccsid[] = "@(#)net.c	8.4 (Berkeley) 4/28/95";
38193240Ssam#endif
39193240Ssam#endif
40193240Ssam
41193240Ssam#include <sys/cdefs.h>
42193240Ssam__FBSDID("$FreeBSD: stable/11/usr.bin/finger/net.c 330897 2018-03-14 03:19:51Z eadler $");
43193240Ssam
44193240Ssam#include <sys/param.h>
45257176Sglebius#include <sys/socket.h>
46287197Sglebius#include <sys/uio.h>
47193240Ssam#include <wctype.h>
48193240Ssam#include <db.h>
49193240Ssam#include <err.h>
50193240Ssam#include <netdb.h>
51193240Ssam#include <pwd.h>
52193240Ssam#include <stdio.h>
53193240Ssam#include <stdlib.h>
54193240Ssam#include <string.h>
55193240Ssam#include <unistd.h>
56193240Ssam#include <utmpx.h>
57257176Sglebius#include <wchar.h>
58193240Ssam#include "finger.h"
59193240Ssam
60193240Ssamstatic void cleanup(int sig);
61257176Sglebiusstatic int do_protocol(const char *name, const struct addrinfo *ai);
62193240Ssamstatic void trying(const struct addrinfo *ai);
63193240Ssam
64193240Ssamvoid
65193240Ssamnetfinger(char *name)
66193240Ssam{
67193240Ssam	int error, multi;
68193240Ssam	char *host;
69193240Ssam	struct addrinfo *ai, *ai0;
70193240Ssam	static struct addrinfo hint;
71193240Ssam
72193240Ssam	host = strrchr(name, '@');
73193240Ssam	if (host == NULL)
74193240Ssam		return;
75193240Ssam	*host++ = '\0';
76193240Ssam	signal(SIGALRM, cleanup);
77193240Ssam	alarm(TIME_LIMIT);
78193240Ssam
79193240Ssam	hint.ai_flags = AI_CANONNAME;
80193240Ssam	hint.ai_family = family;
81193240Ssam	hint.ai_socktype = SOCK_STREAM;
82193240Ssam
83193240Ssam	error = getaddrinfo(host, "finger", &hint, &ai0);
84193240Ssam	if (error) {
85193240Ssam		warnx("%s: %s", host, gai_strerror(error));
86193240Ssam		return;
87193240Ssam	}
88193240Ssam
89193240Ssam	multi = (ai0->ai_next) != 0;
90193240Ssam
91193240Ssam	/* ai_canonname may not be filled in if the user specified an IP. */
92193240Ssam	if (ai0->ai_canonname == 0)
93193240Ssam		printf("[%s]\n", host);
94193240Ssam	else
95193240Ssam		printf("[%s]\n", ai0->ai_canonname);
96193240Ssam
97193240Ssam	for (ai = ai0; ai != NULL; ai = ai->ai_next) {
98193240Ssam		if (multi)
99193240Ssam			trying(ai);
100193240Ssam
101193240Ssam		error = do_protocol(name, ai);
102193240Ssam		if (!error)
103193240Ssam			break;
104193240Ssam	}
105193240Ssam	alarm(0);
106193240Ssam	freeaddrinfo(ai0);
107193240Ssam}
108193240Ssam
109193240Ssamstatic int
110193240Ssamdo_protocol(const char *name, const struct addrinfo *ai)
111193240Ssam{
112193240Ssam	int cnt, line_len, s;
113193240Ssam	FILE *fp;
114193240Ssam	wint_t c, lastc;
115193240Ssam	struct iovec iov[3];
116193240Ssam	struct msghdr msg;
117193240Ssam	static char slash_w[] = "/W ";
118193240Ssam	static char neteol[] = "\r\n";
119193240Ssam
120193240Ssam	s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
121193240Ssam	if (s < 0) {
122193240Ssam		warn("socket(%d, %d, %d)", ai->ai_family, ai->ai_socktype,
123193240Ssam		     ai->ai_protocol);
124193240Ssam		return -1;
125193240Ssam	}
126193240Ssam
127193240Ssam	msg.msg_name = (void *)ai->ai_addr;
128193240Ssam	msg.msg_namelen = ai->ai_addrlen;
129193240Ssam	msg.msg_iov = iov;
130193240Ssam	msg.msg_iovlen = 0;
131193240Ssam	msg.msg_control = 0;
132193240Ssam	msg.msg_controllen = 0;
133193240Ssam	msg.msg_flags = 0;
134193240Ssam
135193240Ssam	/* -l flag for remote fingerd  */
136254263Sscottl	if (lflag) {
137254263Sscottl		iov[msg.msg_iovlen].iov_base = slash_w;
138193240Ssam		iov[msg.msg_iovlen++].iov_len = 3;
139193240Ssam	}
140193240Ssam	/* send the name followed by <CR><LF> */
141193240Ssam	iov[msg.msg_iovlen].iov_base = strdup(name);
142193240Ssam	iov[msg.msg_iovlen++].iov_len = strlen(name);
143193240Ssam	iov[msg.msg_iovlen].iov_base = neteol;
144193240Ssam	iov[msg.msg_iovlen++].iov_len = 2;
145193240Ssam
146193240Ssam	if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
147193240Ssam		warn("connect");
148193240Ssam		close(s);
149193240Ssam		return -1;
150193240Ssam	}
151193240Ssam
152193240Ssam	if (sendmsg(s, &msg, 0) < 0) {
153193240Ssam		warn("sendmsg");
154193240Ssam		close(s);
155193240Ssam		return -1;
156193240Ssam	}
157193240Ssam
158193240Ssam	/*
159193240Ssam	 * Read from the remote system; once we're connected, we assume some
160193240Ssam	 * data.  If none arrives, we hang until the user interrupts.
161193240Ssam	 *
162193240Ssam	 * If we see a <CR> or a <CR> with the high bit set, treat it as
163193240Ssam	 * a newline; if followed by a newline character, only output one
164193240Ssam	 * newline.
165193240Ssam	 *
166193240Ssam	 * Otherwise, all high bits are stripped; if it isn't printable and
167193240Ssam	 * it isn't a space, we can simply set the 7th bit.  Every ASCII
168193240Ssam	 * character with bit 7 set is printable.
169193240Ssam	 */
170193240Ssam	lastc = 0;
171193240Ssam	if ((fp = fdopen(s, "r")) != NULL) {
172193240Ssam		cnt = 0;
173193240Ssam		line_len = 0;
174193240Ssam		while ((c = getwc(fp)) != EOF) {
175193240Ssam			if (++cnt > OUTPUT_MAX) {
176193240Ssam				printf("\n\n Output truncated at %d bytes...\n",
177193240Ssam					cnt - 1);
178193240Ssam				break;
179193240Ssam			}
180193240Ssam			if (c == 0x0d) {
181193240Ssam				if (lastc == '\r')	/* ^M^M - skip dupes */
182275870Sadrian					continue;
183193240Ssam				c = '\n';
184275870Sadrian				lastc = '\r';
185198366Srpaulo			} else {
186193240Ssam				if (!iswprint(c) && !iswspace(c)) {
187193240Ssam					c &= 0x7f;
188193240Ssam					c |= 0x40;
189193240Ssam				}
190193240Ssam				if (lastc != '\r' || c != '\n')
191193240Ssam					lastc = c;
192193240Ssam				else {
193193240Ssam					lastc = '\n';
194193240Ssam					continue;
195193240Ssam				}
196193240Ssam			}
197193240Ssam			putwchar(c);
198193240Ssam			if (c != '\n' && ++line_len > _POSIX2_LINE_MAX) {
199193240Ssam				putchar('\\');
200193240Ssam				putchar('\n');
201193240Ssam				lastc = '\r';
202193240Ssam			}
203193240Ssam			if (lastc == '\n' || lastc == '\r')
204193240Ssam				line_len = 0;
205193240Ssam		}
206193240Ssam		if (ferror(fp)) {
207193240Ssam			/*
208193240Ssam			 * Assume that whatever it was set errno...
209193240Ssam			 */
210193240Ssam			warn("reading from network");
211193240Ssam		}
212193240Ssam		if (lastc != L'\n')
213193240Ssam			putchar('\n');
214193240Ssam
215193240Ssam		fclose(fp);
216193240Ssam	}
217193240Ssam	return 0;
218193240Ssam}
219193240Ssam
220193240Ssamstatic void
221193240Ssamtrying(const struct addrinfo *ai)
222193240Ssam{
223193240Ssam	char buf[NI_MAXHOST];
224193240Ssam
225193240Ssam	if (getnameinfo(ai->ai_addr, ai->ai_addrlen, buf, sizeof buf,
226193240Ssam			(char *)0, 0, NI_NUMERICHOST) != 0)
227193240Ssam		return;		/* XXX can't happen */
228193240Ssam
229193240Ssam	printf("Trying %s...\n", buf);
230193240Ssam}
231193240Ssam
232193240Ssamstatic void
233193240Ssamcleanup(int sig __unused)
234193240Ssam{
235193240Ssam#define	ERRSTR	"Timed out.\n"
236193240Ssam	write(STDERR_FILENO, ERRSTR, sizeof ERRSTR);
237193240Ssam	exit(1);
238193240Ssam}
239193240Ssam
240193240Ssam