0079d8cf6a5035602e7c66238fec153fd4514f80
[openafs.git] / src / util / hostparse.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * ALL RIGHTS RESERVED
12  */
13
14 #include <afsconfig.h>
15 #include <afs/param.h>
16
17 #include <roken.h>
18
19 #ifdef AFS_NT40_ENV
20 #include <direct.h>
21 #else
22 #include <ctype.h>
23 #endif
24
25 #include "afsutil.h"
26
27 /* also parse a.b.c.d addresses */
28 struct hostent *
29 hostutil_GetHostByName(char *ahost)
30 {
31     int tc;
32     static struct hostent thostent;
33     static char *addrp[2];
34     static char addr[4];
35     char *ptr = ahost;
36     afs_uint32 tval, numeric = 0;
37     int dots = 0;
38
39     tc = *ahost;                /* look at the first char */
40     if (tc >= '0' && tc <= '9') {
41         numeric = 1;
42         while ((tc = *ptr++)) {
43             if (tc == '.') {
44                 if (dots >= 3) {
45                     numeric = 0;
46                     break;
47                 }
48                 dots++;
49             } else if (tc > '9' || tc < '0') {
50                 numeric = 0;
51                 break;
52             }
53         }
54     }
55     if (numeric) {
56         tc = *ahost;            /* look at the first char */
57         /* decimal address, return fake hostent with only hostaddr field good */
58         tval = 0;
59         dots = 0;
60         memset(addr, 0, sizeof(addr));
61         while ((tc = *ahost++)) {
62             if (tc == '.') {
63                 if (dots >= 3)
64                     return NULL;        /* too many dots */
65                 addr[dots++] = tval;
66                 tval = 0;
67             } else if (tc > '9' || tc < '0')
68                 return NULL;
69             else {
70                 tval *= 10;
71                 tval += tc - '0';
72             }
73         }
74         addr[dots] = tval;
75 #ifdef h_addr
76         /* 4.3 system */
77         addrp[0] = addr;
78         addrp[1] = NULL;
79         thostent.h_addr_list = &addrp[0];
80 #else /* h_addr */
81         /* 4.2 and older systems */
82         thostent.h_addr = addr;
83 #endif /* h_addr */
84         return &thostent;
85     } else {
86 #ifdef AFS_NT40_ENV
87         if (afs_winsockInit() < 0)
88             return NULL;
89 #endif
90         return gethostbyname(ahost);
91     }
92 }
93
94 /* Translate an internet address into a nice printable string. The
95  * variable addr is in network byte order.
96  */
97 char *
98 hostutil_GetNameByINet(afs_uint32 addr)
99 {
100     struct hostent *th;
101     static char tbuffer[256];
102
103 #ifdef AFS_NT40_ENV
104     if (afs_winsockInit() < 0)
105         return NULL;
106 #endif
107     th = gethostbyaddr((void *)&addr, sizeof(addr), AF_INET);
108     if (th) {
109         strcpy(tbuffer, th->h_name);
110     } else {
111         addr = ntohl(addr);
112         sprintf(tbuffer, "%d.%d.%d.%d", (int)((addr >> 24) & 0xff),
113                 (int)((addr >> 16) & 0xff), (int)((addr >> 8) & 0xff),
114                 (int)(addr & 0xff));
115     }
116
117     return tbuffer;
118 }
119
120 /* the parameter is a pointer to a buffer containing a string of
121 ** bytes of the form
122 ** w.x.y.z      # machineName
123 ** returns the network interface in network byte order
124 */
125 afs_uint32
126 extractAddr(char *line, int maxSize)
127 {
128     char byte1[32], byte2[32], byte3[32], byte4[32];
129     int i = 0;
130     char *endPtr;
131     afs_uint32 val1, val2, val3, val4;
132     afs_uint32 val = 0;
133
134     /* skip empty spaces */
135     while (isspace(*line) && maxSize) {
136         line++;
137         maxSize--;
138     }
139
140     /* skip empty lines */
141     if (!maxSize || !*line)
142         return AFS_IPINVALIDIGNORE;
143
144     while ((*line != '.') && maxSize) { /* extract first byte */
145         if (!isdigit(*line))
146             return AFS_IPINVALID;
147         if (i > 31)
148             return AFS_IPINVALID;       /* no space */
149         byte1[i++] = *line++;
150         maxSize--;
151     }
152     if (!maxSize)
153         return AFS_IPINVALID;
154     byte1[i] = 0;
155
156     i = 0, line++;
157     while ((*line != '.') && maxSize) { /* extract second byte */
158         if (!isdigit(*line))
159             return AFS_IPINVALID;
160         if (i > 31)
161             return AFS_IPINVALID;       /* no space */
162         byte2[i++] = *line++;
163         maxSize--;
164     }
165     if (!maxSize)
166         return AFS_IPINVALID;
167     byte2[i] = 0;
168
169     i = 0, line++;
170     while ((*line != '.') && maxSize) {
171         if (!isdigit(*line))
172             return AFS_IPINVALID;
173         if (i > 31)
174             return AFS_IPINVALID;       /* no space */
175         byte3[i++] = *line++;
176         maxSize--;
177     }
178     if (!maxSize)
179         return AFS_IPINVALID;
180     byte3[i] = 0;
181
182     i = 0, line++;
183     while (*line && !isspace(*line) && maxSize) {
184         if (!isdigit(*line))
185             return AFS_IPINVALID;
186         if (i > 31)
187             return AFS_IPINVALID;       /* no space */
188         byte4[i++] = *line++;
189         maxSize--;
190     }
191     if (!maxSize)
192         return AFS_IPINVALID;
193     byte4[i] = 0;
194
195     errno = 0;
196     val1 = strtol(byte1, &endPtr, 10);
197     if ((val1 == 0) && (errno != 0 || byte1 == endPtr))
198         return AFS_IPINVALID;
199
200     errno = 0;
201     val2 = strtol(byte2, &endPtr, 10);
202     if ((val2 == 0) && (errno != 0 || byte2 == endPtr)) /* no conversion */
203         return AFS_IPINVALID;
204
205     errno = 0;
206     val3 = strtol(byte3, &endPtr, 10);
207     if ((val3 == 0) && (errno != 0 || byte3 == endPtr)) /* no conversion */
208         return AFS_IPINVALID;
209
210     errno = 0;
211     val4 = strtol(byte4, &endPtr, 10);
212     if ((val4 == 0) && (errno != 0 || byte4 == endPtr)) /* no conversion */
213         return AFS_IPINVALID;
214
215     val = (val1 << 24) | (val2 << 16) | (val3 << 8) | val4;
216     val = htonl(val);
217     return val;
218 }
219
220 /* same as inet_ntoa, but to a non-static buffer, must be freed by called */
221 char *
222 afs_inet_ntoa_r(afs_uint32 addr, char *buf)
223 {
224     int temp;
225
226     temp = ntohl(addr);
227     sprintf(buf, "%d.%d.%d.%d", (temp >> 24) & 0xff, (temp >> 16) & 0xff,
228             (temp >> 8) & 0xff, (temp) & 0xff);
229     return buf;
230 }
231
232 /*
233  * gettmpdir() -- Returns pointer to global temporary directory string.
234  *     Always succeeds.  Never attempt to deallocate directory string.
235  */
236
237 char *
238 gettmpdir(void)
239 {
240     char *tmpdirp = NULL;
241
242 #ifdef AFS_NT40_ENV
243     static char *saveTmpDir = NULL;
244
245     if (saveTmpDir == NULL) {
246         /* initialize global temporary directory string */
247         char *dirp = (char *)malloc(MAX_PATH+1);
248         int freeDirp = 1;
249
250         if (dirp != NULL) {
251             DWORD pathLen = GetTempPath(MAX_PATH+1, dirp);
252
253             if (pathLen == 0 || pathLen > MAX_PATH) {
254                 /* can't get tmp path; get cur work dir */
255                 pathLen = GetCurrentDirectory(MAX_PATH, dirp);
256                 if (pathLen == 0 || pathLen > MAX_PATH) {
257                     free(dirp);
258                     dirp = NULL;
259                 }
260             }
261
262             if (dirp != NULL) {
263                 /* Have a valid dir path; check that actually exists. */
264                 DWORD fileAttr = GetFileAttributes(dirp);
265
266                 if ((fileAttr == 0xFFFFFFFF)
267                     || ((fileAttr & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
268                     free(dirp);
269                     dirp = NULL;
270                 }
271             }
272         }
273
274         if (dirp != NULL) {
275             FilepathNormalize(dirp);
276         } else {
277             /* most likely TMP or TEMP env vars specify a non-existent dir */
278             dirp = "/";
279             freeDirp = 0;
280         }
281
282         /* atomically initialize shared buffer pointer IF still null */
283         if (InterlockedCompareExchangePointer(&saveTmpDir, dirp, NULL) != NULL) {
284             /* shared buffer pointer already initialized by another thread */
285             if (freeDirp)
286                 free(dirp);
287         }
288     }
289     /* if (!saveTmpDir) */
290     tmpdirp = saveTmpDir;
291 #else
292     tmpdirp = "/tmp";
293 #endif /* AFS_NT40_ENV */
294
295     return tmpdirp;
296 }