xref: /illumos-gate/usr/src/lib/libwrap/misc.c (revision fe4627ef755b7c263f91a0e6f07cdca5d7083501)
1 /*
2  * Copyright 2001 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 #pragma ident	"%Z%%M%	%I%	%E% SMI"
6 
7  /*
8   * Misc routines that are used by tcpd and by tcpdchk.
9   *
10   * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
11   */
12 
13 #ifndef lint
14 static char sccsic[] = "@(#) misc.c 1.2 96/02/11 17:01:29";
15 #endif
16 
17 #include <sys/types.h>
18 #include <sys/param.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <ctype.h>
24 #include <netdb.h>
25 
26 #include "tcpd.h"
27 
28 extern char *fgets();
29 
30 #ifndef	INADDR_NONE
31 #define	INADDR_NONE	(-1)		/* XXX should be 0xffffffff */
32 #endif
33 
34 /* xgets - fgets() with backslash-newline stripping */
35 
36 char   *xgets(ptr, len, fp)
37 char   *ptr;
38 int     len;
39 FILE   *fp;
40 {
41     int     got;
42     char   *start = ptr;
43 
44     while (fgets(ptr, len, fp)) {
45 	got = strlen(ptr);
46 	if (got >= 1 && ptr[got - 1] == '\n') {
47 	    tcpd_context.line++;
48 	    if (got >= 2 && ptr[got - 2] == '\\') {
49 		got -= 2;
50 	    } else {
51 		return (start);
52 	    }
53 	}
54 	ptr += got;
55 	len -= got;
56 	ptr[0] = 0;
57     }
58     return (ptr > start ? start : 0);
59 }
60 
61 /* split_at - break string at delimiter or return NULL */
62 
63 char   *split_at(string, delimiter)
64 char   *string;
65 int     delimiter;
66 {
67     char   *cp;
68 
69     if ((cp = strchr(string, delimiter)) != 0)
70 	*cp++ = 0;
71     return (cp);
72 }
73 
74 /* dot_quad_addr - convert dotted quad to internal form */
75 
76 unsigned long dot_quad_addr(str)
77 char   *str;
78 {
79     int     in_run = 0;
80     int     runs = 0;
81     char   *cp = str;
82 
83     /* Count the number of runs of non-dot characters. */
84 
85     while (*cp) {
86 	if (*cp == '.') {
87 	    in_run = 0;
88 	} else if (in_run == 0) {
89 	    in_run = 1;
90 	    runs++;
91 	}
92 	cp++;
93     }
94     return (runs == 4 ? inet_addr(str) : INADDR_NONE);
95 }
96 
97 /* numeric_addr - convert textual IP address to binary form */
98 
99 int numeric_addr(str, addr, af, len)
100 char *str;
101 union gen_addr *addr;
102 int *af;
103 int *len;
104 {
105     union gen_addr t;
106 
107     if (addr == NULL)
108 	addr = &t;
109 #ifdef HAVE_IPV6
110     if (strchr(str,':')) {
111 	if (af) *af = AF_INET6;
112 	if (len) *len = sizeof(struct in6_addr);
113 	if (inet_pton(AF_INET6, str, (void*) addr) == 1)
114 	    return 0;
115 	return -1;
116     }
117 #endif
118     if (af) *af = AF_INET;
119     if (len) *len = sizeof(struct in_addr);
120     addr->ga_in.s_addr = dot_quad_addr(str);
121     return addr->ga_in.s_addr == INADDR_NONE ? -1 : 0;
122 }
123 
124 /* For none RFC 2553 compliant systems */
125 #ifdef USE_GETHOSTBYNAME2
126 #define getipnodebyname(h,af,flags,err)	gethostbyname2(h,af)
127 #define freehostent(x)			x = 0
128 #endif
129 
130 /* tcpd_gethostbyname - an IP family neutral gethostbyname */
131 
132 struct hostent *tcpd_gethostbyname(host, af)
133 char *host;
134 int af;
135 {
136 #ifdef HAVE_IPV6
137     struct hostent *hp;
138     static struct hostent *hs;		/* freehostent() on next call */
139     int err;
140 
141     if (af == AF_INET6) {		/* must be AF_INET6 */
142 	if (hs)
143 	    freehostent(hs);
144 	return (hs = getipnodebyname(host, AF_INET6, 0, &err));
145     }
146     hp = gethostbyname(host);
147     if (hp != NULL || af == AF_INET) { 	/* found or must be AF_INET */
148 	return hp;
149     } else {				/* Try INET6 */
150 	if (hs)
151 	    freehostent(hs);
152 	return (hs = getipnodebyname(host, AF_INET6, 0, &err));
153     }
154 #else
155     return gethostbyname(host);
156 #endif
157 }
158 
159 #ifdef HAVE_IPV6
160 /*
161  * When using IPv6 addresses, we'll be seeing lots of ":"s;
162  * we require the addresses to be specified as [address].
163  * An IPv6 address can be specified in 3 ways:
164  *
165  * x:x:x:x:x:x:x:x		(fully specified)
166  * x::x:x:x:x			(zeroes squashed)
167  * ::FFFF:1.2.3.4		(IPv4 mapped)
168  *
169  * These need to be skipped to get at the ":" delimeters.
170  *
171  * We also allow a '/prefix' specifier.
172  */
173 char *skip_ipv6_addrs(str)
174 char *str;
175 {
176     char *obr, *cbr, *colon;
177     char *p = str;
178     char *q;
179 
180     while (1) {
181 	if ((colon = strchr(p, ':')) == NULL)
182 	    return p;
183 	if ((obr = strchr(p, '[')) == NULL || obr > colon)
184 	    return p;
185 	if ((cbr = strchr(obr, ']')) == NULL)
186 	    return p;
187 
188 	for (q = obr + 1; q < cbr; q++) {
189 	    /*
190 	     * Quick and dirty parse, cheaper than inet_pton
191 	     * Could count colons and dots (must be 0 or 3 dots, no
192 	     * colons after dots seens, only one double :, etc, etc)
193 	     */
194 	    if (*q != ':' && *q != '.' && *q != '/' && !isxdigit(*q & 0xff))
195 		return p;
196 	}
197 	p = cbr + 1;
198     }
199 }
200 #endif /* HAVE_IPV6 */
201