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