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