1 | /********************************************************************\ |
---|
2 | * BitlBee -- An IRC to other IM-networks gateway * |
---|
3 | * * |
---|
4 | * Copyright 2002-2004 Wilmer van der Gaast and others * |
---|
5 | \********************************************************************/ |
---|
6 | |
---|
7 | /* Main file (Windows specific part) */ |
---|
8 | |
---|
9 | /* |
---|
10 | This program is free software; you can redistribute it and/or modify |
---|
11 | it under the terms of the GNU General Public License as published by |
---|
12 | the Free Software Foundation; either version 2 of the License, or |
---|
13 | (at your option) any later version. |
---|
14 | |
---|
15 | This program is distributed in the hope that it will be useful, |
---|
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
18 | GNU General Public License for more details. |
---|
19 | |
---|
20 | You should have received a copy of the GNU General Public License with |
---|
21 | the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; |
---|
22 | if not, write to the Free Software Foundation, Inc., 59 Temple Place, |
---|
23 | Suite 330, Boston, MA 02111-1307 USA |
---|
24 | */ |
---|
25 | |
---|
26 | #define BITLBEE_CORE |
---|
27 | #include "bitlbee.h" |
---|
28 | #include "commands.h" |
---|
29 | #include "crypting.h" |
---|
30 | #include "protocols/nogaim.h" |
---|
31 | #include "help.h" |
---|
32 | #include <signal.h> |
---|
33 | #include <windows.h> |
---|
34 | |
---|
35 | global_t global; /* Against global namespace pollution */ |
---|
36 | |
---|
37 | static void WINAPI service_ctrl (DWORD dwControl) |
---|
38 | { |
---|
39 | switch (dwControl) |
---|
40 | { |
---|
41 | case SERVICE_CONTROL_STOP: |
---|
42 | /* FIXME */ |
---|
43 | break; |
---|
44 | |
---|
45 | case SERVICE_CONTROL_INTERROGATE: |
---|
46 | break; |
---|
47 | |
---|
48 | default: |
---|
49 | break; |
---|
50 | |
---|
51 | } |
---|
52 | } |
---|
53 | |
---|
54 | static void bitlbee_init(int argc, char **argv) |
---|
55 | { |
---|
56 | int i = -1; |
---|
57 | memset( &global, 0, sizeof( global_t ) ); |
---|
58 | |
---|
59 | global.loop = g_main_new( FALSE ); |
---|
60 | |
---|
61 | global.conf = conf_load( argc, argv ); |
---|
62 | if( global.conf == NULL ) |
---|
63 | return; |
---|
64 | |
---|
65 | if( global.conf->runmode == RUNMODE_INETD ) |
---|
66 | { |
---|
67 | i = bitlbee_inetd_init(); |
---|
68 | log_message( LOGLVL_INFO, "Bitlbee %s starting in inetd mode.", BITLBEE_VERSION ); |
---|
69 | |
---|
70 | } |
---|
71 | else if( global.conf->runmode == RUNMODE_DAEMON ) |
---|
72 | { |
---|
73 | i = bitlbee_daemon_init(); |
---|
74 | log_message( LOGLVL_INFO, "Bitlbee %s starting in daemon mode.", BITLBEE_VERSION ); |
---|
75 | } |
---|
76 | else |
---|
77 | { |
---|
78 | log_message( LOGLVL_INFO, "No bitlbee mode specified..."); |
---|
79 | } |
---|
80 | |
---|
81 | if( i != 0 ) |
---|
82 | return; |
---|
83 | |
---|
84 | if( access( global.conf->configdir, F_OK ) != 0 ) |
---|
85 | log_message( LOGLVL_WARNING, "The configuration directory %s does not exist. Configuration won't be saved.", global.conf->configdir ); |
---|
86 | else if( access( global.conf->configdir, 06 ) != 0 ) |
---|
87 | log_message( LOGLVL_WARNING, "Permission problem: Can't read/write from/to %s.", global.conf->configdir ); |
---|
88 | if( help_init( &(global.help) ) == NULL ) |
---|
89 | log_message( LOGLVL_WARNING, "Error opening helpfile %s.", global.helpfile ); |
---|
90 | } |
---|
91 | |
---|
92 | void service_main (DWORD argc, LPTSTR *argv) |
---|
93 | { |
---|
94 | SERVICE_STATUS_HANDLE handle; |
---|
95 | SERVICE_STATUS status; |
---|
96 | |
---|
97 | handle = RegisterServiceCtrlHandler("bitlbee", service_ctrl); |
---|
98 | |
---|
99 | if (!handle) |
---|
100 | return; |
---|
101 | |
---|
102 | status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; |
---|
103 | status.dwServiceSpecificExitCode = 0; |
---|
104 | |
---|
105 | bitlbee_init(argc, argv); |
---|
106 | |
---|
107 | SetServiceStatus(handle, &status); |
---|
108 | |
---|
109 | g_main_run( global.loop ); |
---|
110 | } |
---|
111 | |
---|
112 | SERVICE_TABLE_ENTRY dispatch_table[] = |
---|
113 | { |
---|
114 | { TEXT("bitlbee"), (LPSERVICE_MAIN_FUNCTION)service_main }, |
---|
115 | { NULL, NULL } |
---|
116 | }; |
---|
117 | |
---|
118 | static int debug = 0; |
---|
119 | |
---|
120 | static void usage() |
---|
121 | { |
---|
122 | printf("Options:\n"); |
---|
123 | printf("-h Show this help message\n"); |
---|
124 | printf("-d Debug mode (simple console program)\n"); |
---|
125 | } |
---|
126 | |
---|
127 | int main( int argc, char **argv) |
---|
128 | { |
---|
129 | int i; |
---|
130 | WSADATA WSAData; |
---|
131 | |
---|
132 | nogaim_init( ); |
---|
133 | |
---|
134 | for (i = 1; i < argc; i++) { |
---|
135 | if (!strcmp(argv[i], "-d")) debug = 1; |
---|
136 | if (!strcmp(argv[i], "-h")) { |
---|
137 | usage(); |
---|
138 | return 0; |
---|
139 | } |
---|
140 | } |
---|
141 | |
---|
142 | WSAStartup(MAKEWORD(1,1), &WSAData); |
---|
143 | |
---|
144 | if (!debug) { |
---|
145 | if (!StartServiceCtrlDispatcher(dispatch_table)) |
---|
146 | log_message( LOGLVL_ERROR, "StartServiceCtrlDispatcher failed."); |
---|
147 | } else { |
---|
148 | bitlbee_init(argc, argv); |
---|
149 | g_main_run( global.loop ); |
---|
150 | } |
---|
151 | |
---|
152 | return 0; |
---|
153 | } |
---|
154 | |
---|
155 | double gettime() |
---|
156 | { |
---|
157 | return (GetTickCount() / 1000); |
---|
158 | } |
---|
159 | |
---|
160 | void conf_get_string(HKEY section, const char *name, const char *def, char **dest) |
---|
161 | { |
---|
162 | char buf[4096]; |
---|
163 | long x; |
---|
164 | if (RegQueryValue(section, name, buf, &x) == ERROR_SUCCESS) { |
---|
165 | *dest = g_strdup(buf); |
---|
166 | } else if (!def) { |
---|
167 | *dest = NULL; |
---|
168 | } else { |
---|
169 | *dest = g_strdup(def); |
---|
170 | } |
---|
171 | } |
---|
172 | |
---|
173 | |
---|
174 | void conf_get_int(HKEY section, const char *name, int def, int *dest) |
---|
175 | { |
---|
176 | char buf[20]; |
---|
177 | long x; |
---|
178 | DWORD y; |
---|
179 | if (RegQueryValue(section, name, buf, &x) == ERROR_SUCCESS) { |
---|
180 | memcpy(&y, buf, sizeof(DWORD)); |
---|
181 | *dest = y; |
---|
182 | } else { |
---|
183 | *dest = def; |
---|
184 | } |
---|
185 | } |
---|
186 | |
---|
187 | conf_t *conf_load( int argc, char *argv[] ) |
---|
188 | { |
---|
189 | conf_t *conf; |
---|
190 | HKEY key, key_main, key_proxy; |
---|
191 | char *tmp; |
---|
192 | |
---|
193 | RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Bitlbee", &key); |
---|
194 | RegOpenKey(key, "main", &key_main); |
---|
195 | RegOpenKey(key, "proxy", &key_proxy); |
---|
196 | |
---|
197 | memset( &global, 0, sizeof( global_t ) ); |
---|
198 | global.loop = g_main_new(FALSE); |
---|
199 | |
---|
200 | conf = g_new0( conf_t,1 ); |
---|
201 | global.conf = conf; |
---|
202 | conf_get_string(key_main, "interface", "0.0.0.0", &global.conf->iface); |
---|
203 | conf_get_int(key_main, "port", 6667, &global.conf->port); |
---|
204 | conf_get_int(key_main, "verbose", 0, &global.conf->verbose); |
---|
205 | conf_get_string(key_main, "auth_pass", "", &global.conf->auth_pass); |
---|
206 | conf_get_string(key_main, "oper_pass", "", &global.conf->oper_pass); |
---|
207 | conf_get_int(key_main, "ping_interval_timeout", 60, &global.conf->ping_interval); |
---|
208 | conf_get_string(key_main, "hostname", "localhost", &global.conf->hostname); |
---|
209 | conf_get_string(key_main, "configdir", NULL, &global.conf->configdir); |
---|
210 | conf_get_string(key_main, "motdfile", NULL, &global.conf->motdfile); |
---|
211 | conf_get_string(key_main, "helpfile", NULL, &global.helpfile); |
---|
212 | global.conf->runmode = RUNMODE_DAEMON; |
---|
213 | conf_get_int(key_main, "AuthMode", AUTHMODE_OPEN, &global.conf->authmode); |
---|
214 | conf_get_string(key_proxy, "host", "", &tmp); strcpy(proxyhost, tmp); |
---|
215 | conf_get_string(key_proxy, "user", "", &tmp); strcpy(proxyuser, tmp); |
---|
216 | conf_get_string(key_proxy, "password", "", &tmp); strcpy(proxypass, tmp); |
---|
217 | conf_get_int(key_proxy, "type", PROXY_NONE, &proxytype); |
---|
218 | conf_get_int(key_proxy, "port", 3128, &proxyport); |
---|
219 | |
---|
220 | RegCloseKey(key); |
---|
221 | RegCloseKey(key_main); |
---|
222 | RegCloseKey(key_proxy); |
---|
223 | |
---|
224 | return conf; |
---|
225 | } |
---|
226 | |
---|
227 | void conf_loaddefaults( irc_t *irc ) |
---|
228 | { |
---|
229 | HKEY key_defaults; |
---|
230 | int i; |
---|
231 | char name[4096], data[4096]; |
---|
232 | DWORD namelen = sizeof(name), datalen = sizeof(data); |
---|
233 | DWORD type; |
---|
234 | if (RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Bitlbee\\defaults", &key_defaults) != ERROR_SUCCESS) { |
---|
235 | return; |
---|
236 | } |
---|
237 | |
---|
238 | for (i = 0; RegEnumValue(key_defaults, i, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS; i++) { |
---|
239 | set_t *s = set_find( irc, name ); |
---|
240 | |
---|
241 | if( s ) |
---|
242 | { |
---|
243 | if( s->def ) g_free( s->def ); |
---|
244 | s->def = g_strdup( data ); |
---|
245 | } |
---|
246 | |
---|
247 | namelen = sizeof(name); |
---|
248 | datalen = sizeof(data); |
---|
249 | } |
---|
250 | |
---|
251 | RegCloseKey(key_defaults); |
---|
252 | } |
---|
253 | |
---|
254 | #ifndef INADDR_NONE |
---|
255 | #define INADDR_NONE 0xffffffff |
---|
256 | #endif |
---|
257 | |
---|
258 | int |
---|
259 | inet_aton(const char *cp, struct in_addr *addr) |
---|
260 | { |
---|
261 | addr->s_addr = inet_addr(cp); |
---|
262 | return (addr->s_addr == INADDR_NONE) ? 0 : 1; |
---|
263 | } |
---|
264 | |
---|
265 | void log_error(char *msg) |
---|
266 | { |
---|
267 | log_message(LOGLVL_ERROR, "%s", msg); |
---|
268 | } |
---|
269 | |
---|
270 | void log_message(int level, char *message, ...) |
---|
271 | { |
---|
272 | HANDLE hEventSource; |
---|
273 | LPTSTR lpszStrings[2]; |
---|
274 | WORD elevel; |
---|
275 | va_list ap; |
---|
276 | |
---|
277 | va_start(ap, message); |
---|
278 | |
---|
279 | if (debug) { |
---|
280 | vprintf(message, ap); |
---|
281 | putchar('\n'); |
---|
282 | va_end(ap); |
---|
283 | return; |
---|
284 | } |
---|
285 | |
---|
286 | hEventSource = RegisterEventSource(NULL, TEXT("bitlbee")); |
---|
287 | |
---|
288 | lpszStrings[0] = TEXT("bitlbee"); |
---|
289 | lpszStrings[1] = g_strdup_vprintf(message, ap); |
---|
290 | va_end(ap); |
---|
291 | |
---|
292 | switch (level) { |
---|
293 | case LOGLVL_ERROR: elevel = EVENTLOG_ERROR_TYPE; break; |
---|
294 | case LOGLVL_WARNING: elevel = EVENTLOG_WARNING_TYPE; break; |
---|
295 | case LOGLVL_INFO: elevel = EVENTLOG_INFORMATION_TYPE; break; |
---|
296 | #ifdef DEBUG |
---|
297 | case LOGLVL_DEBUG: elevel = EVENTLOG_AUDIT_SUCCESS; break; |
---|
298 | #endif |
---|
299 | } |
---|
300 | |
---|
301 | if (hEventSource != NULL) { |
---|
302 | ReportEvent(hEventSource, |
---|
303 | elevel, |
---|
304 | 0, |
---|
305 | 0, |
---|
306 | NULL, |
---|
307 | 2, |
---|
308 | 0, |
---|
309 | lpszStrings, |
---|
310 | NULL); |
---|
311 | |
---|
312 | DeregisterEventSource(hEventSource); |
---|
313 | } |
---|
314 | |
---|
315 | g_free(lpszStrings[1]); |
---|
316 | } |
---|
317 | |
---|
318 | void log_link(int level, int output) { /* FIXME */ } |
---|
319 | |
---|
320 | #ifndef NS_INADDRSZ |
---|
321 | #define NS_INADDRSZ 4 |
---|
322 | #endif |
---|
323 | #ifndef NS_IN6ADDRSZ |
---|
324 | #define NS_IN6ADDRSZ 16 |
---|
325 | #endif |
---|
326 | #ifndef NS_INT16SZ |
---|
327 | #define NS_INT16SZ 2 |
---|
328 | #endif |
---|
329 | |
---|
330 | static const char *inet_ntop4(const guchar *src, char *dst, size_t size); |
---|
331 | static const char *inet_ntop6(const guchar *src, char *dst, size_t size); |
---|
332 | |
---|
333 | /* char * |
---|
334 | * inet_ntop(af, src, dst, size) |
---|
335 | * convert a network format address to presentation format. |
---|
336 | * return: |
---|
337 | * pointer to presentation format address (`dst'), or NULL (see errno). |
---|
338 | * author: |
---|
339 | * Paul Vixie, 1996. |
---|
340 | */ |
---|
341 | const char * |
---|
342 | inet_ntop(af, src, dst, size) |
---|
343 | int af; |
---|
344 | const void *src; |
---|
345 | char *dst; |
---|
346 | size_t size; |
---|
347 | { |
---|
348 | switch (af) { |
---|
349 | case AF_INET: |
---|
350 | return (inet_ntop4(src, dst, size)); |
---|
351 | case AF_INET6: |
---|
352 | return (inet_ntop6(src, dst, size)); |
---|
353 | default: |
---|
354 | errno = WSAEAFNOSUPPORT; |
---|
355 | return (NULL); |
---|
356 | } |
---|
357 | /* NOTREACHED */ |
---|
358 | } |
---|
359 | |
---|
360 | /* const char * |
---|
361 | * inet_ntop4(src, dst, size) |
---|
362 | * format an IPv4 address |
---|
363 | * return: |
---|
364 | * `dst' (as a const) |
---|
365 | * notes: |
---|
366 | * (1) uses no statics |
---|
367 | * (2) takes a u_char* not an in_addr as input |
---|
368 | * author: |
---|
369 | * Paul Vixie, 1996. |
---|
370 | */ |
---|
371 | static const char * |
---|
372 | inet_ntop4(src, dst, size) |
---|
373 | const u_char *src; |
---|
374 | char *dst; |
---|
375 | size_t size; |
---|
376 | { |
---|
377 | static const char fmt[] = "%u.%u.%u.%u"; |
---|
378 | char tmp[sizeof "255.255.255.255"]; |
---|
379 | int nprinted; |
---|
380 | |
---|
381 | nprinted = g_snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); |
---|
382 | if (nprinted < 0) |
---|
383 | return (NULL); /* we assume "errno" was set by "g_snprintf()" */ |
---|
384 | if ((size_t)nprinted > size) { |
---|
385 | errno = ENOSPC; |
---|
386 | return (NULL); |
---|
387 | } |
---|
388 | strcpy(dst, tmp); |
---|
389 | return (dst); |
---|
390 | } |
---|
391 | |
---|
392 | /* const char * |
---|
393 | * inet_ntop6(src, dst, size) |
---|
394 | * convert IPv6 binary address into presentation (printable) format |
---|
395 | * author: |
---|
396 | * Paul Vixie, 1996. |
---|
397 | */ |
---|
398 | static const char * |
---|
399 | inet_ntop6(src, dst, size) |
---|
400 | const u_char *src; |
---|
401 | char *dst; |
---|
402 | size_t size; |
---|
403 | { |
---|
404 | /* |
---|
405 | * Note that int32_t and int16_t need only be "at least" large enough |
---|
406 | * to contain a value of the specified size. On some systems, like |
---|
407 | * Crays, there is no such thing as an integer variable with 16 bits. |
---|
408 | * Keep this in mind if you think this function should have been coded |
---|
409 | * to use pointer overlays. All the world's not a VAX. |
---|
410 | */ |
---|
411 | char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; |
---|
412 | struct { int base, len; } best, cur; |
---|
413 | guint words[NS_IN6ADDRSZ / NS_INT16SZ]; |
---|
414 | int i; |
---|
415 | |
---|
416 | /* |
---|
417 | * Preprocess: |
---|
418 | * Copy the input (bytewise) array into a wordwise array. |
---|
419 | * Find the longest run of 0x00's in src[] for :: shorthanding. |
---|
420 | */ |
---|
421 | memset(words, '\0', sizeof words); |
---|
422 | for (i = 0; i < NS_IN6ADDRSZ; i++) |
---|
423 | words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); |
---|
424 | best.base = -1; |
---|
425 | cur.base = -1; |
---|
426 | for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { |
---|
427 | if (words[i] == 0) { |
---|
428 | if (cur.base == -1) |
---|
429 | cur.base = i, cur.len = 1; |
---|
430 | else |
---|
431 | cur.len++; |
---|
432 | } else { |
---|
433 | if (cur.base != -1) { |
---|
434 | if (best.base == -1 || cur.len > best.len) |
---|
435 | best = cur; |
---|
436 | cur.base = -1; |
---|
437 | } |
---|
438 | } |
---|
439 | } |
---|
440 | if (cur.base != -1) { |
---|
441 | if (best.base == -1 || cur.len > best.len) |
---|
442 | best = cur; |
---|
443 | } |
---|
444 | if (best.base != -1 && best.len < 2) |
---|
445 | best.base = -1; |
---|
446 | |
---|
447 | /* |
---|
448 | * Format the result. |
---|
449 | */ |
---|
450 | tp = tmp; |
---|
451 | for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { |
---|
452 | /* Are we inside the best run of 0x00's? */ |
---|
453 | if (best.base != -1 && i >= best.base && |
---|
454 | i < (best.base + best.len)) { |
---|
455 | if (i == best.base) |
---|
456 | *tp++ = ':'; |
---|
457 | continue; |
---|
458 | } |
---|
459 | /* Are we following an initial run of 0x00s or any real hex? */ |
---|
460 | if (i != 0) |
---|
461 | *tp++ = ':'; |
---|
462 | /* Is this address an encapsulated IPv4? */ |
---|
463 | if (i == 6 && best.base == 0 && |
---|
464 | (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { |
---|
465 | if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) |
---|
466 | return (NULL); |
---|
467 | tp += strlen(tp); |
---|
468 | break; |
---|
469 | } |
---|
470 | tp += g_snprintf(tp, sizeof tmp - (tp - tmp), "%x", words[i]); |
---|
471 | } |
---|
472 | /* Was it a trailing run of 0x00's? */ |
---|
473 | if (best.base != -1 && (best.base + best.len) == |
---|
474 | (NS_IN6ADDRSZ / NS_INT16SZ)) |
---|
475 | *tp++ = ':'; |
---|
476 | *tp++ = '\0'; |
---|
477 | |
---|
478 | /* |
---|
479 | * Check for overflow, copy, and we're done. |
---|
480 | */ |
---|
481 | if ((size_t)(tp - tmp) > size) { |
---|
482 | errno = ENOSPC; |
---|
483 | return (NULL); |
---|
484 | } |
---|
485 | strcpy(dst, tmp); |
---|
486 | return (dst); |
---|
487 | } |
---|
488 | |
---|
489 | #ifdef AF_INET |
---|
490 | static int inet_pton4(const char *src, u_char *dst); |
---|
491 | #endif |
---|
492 | #ifdef AF_INET6 |
---|
493 | static int inet_pton6(const char *src, u_char *dst); |
---|
494 | #endif |
---|
495 | |
---|
496 | /* int |
---|
497 | * inet_pton(af, src, dst) |
---|
498 | * convert from presentation format (which usually means ASCII printable) |
---|
499 | * to network format (which is usually some kind of binary format). |
---|
500 | * return: |
---|
501 | * 1 if the address was valid for the specified address family |
---|
502 | * 0 if the address wasn't valid (`dst' is untouched in this case) |
---|
503 | * -1 if some other error occurred (`dst' is untouched in this case, too) |
---|
504 | * author: |
---|
505 | * Paul Vixie, 1996. |
---|
506 | */ |
---|
507 | int |
---|
508 | inet_pton(af, src, dst) |
---|
509 | int af; |
---|
510 | const char *src; |
---|
511 | void *dst; |
---|
512 | { |
---|
513 | switch (af) { |
---|
514 | #ifdef AF_INET |
---|
515 | case AF_INET: |
---|
516 | return (inet_pton4(src, dst)); |
---|
517 | #endif |
---|
518 | #ifdef AF_INET6 |
---|
519 | case AF_INET6: |
---|
520 | return (inet_pton6(src, dst)); |
---|
521 | #endif |
---|
522 | default: |
---|
523 | errno = WSAEAFNOSUPPORT; |
---|
524 | return (-1); |
---|
525 | } |
---|
526 | /* NOTREACHED */ |
---|
527 | } |
---|
528 | |
---|
529 | #ifdef AF_INET |
---|
530 | /* int |
---|
531 | * inet_pton4(src, dst) |
---|
532 | * like inet_aton() but without all the hexadecimal and shorthand. |
---|
533 | * return: |
---|
534 | * 1 if `src' is a valid dotted quad, else 0. |
---|
535 | * notice: |
---|
536 | * does not touch `dst' unless it's returning 1. |
---|
537 | * author: |
---|
538 | * Paul Vixie, 1996. |
---|
539 | */ |
---|
540 | static int |
---|
541 | inet_pton4(src, dst) |
---|
542 | const char *src; |
---|
543 | u_char *dst; |
---|
544 | { |
---|
545 | static const char digits[] = "0123456789"; |
---|
546 | int saw_digit, octets, ch; |
---|
547 | u_char tmp[NS_INADDRSZ], *tp; |
---|
548 | |
---|
549 | saw_digit = 0; |
---|
550 | octets = 0; |
---|
551 | *(tp = tmp) = 0; |
---|
552 | while ((ch = *src++) != '\0') { |
---|
553 | const char *pch; |
---|
554 | |
---|
555 | if ((pch = strchr(digits, ch)) != NULL) { |
---|
556 | u_int new = *tp * 10 + (pch - digits); |
---|
557 | |
---|
558 | if (new > 255) |
---|
559 | return (0); |
---|
560 | *tp = new; |
---|
561 | if (! saw_digit) { |
---|
562 | if (++octets > 4) |
---|
563 | return (0); |
---|
564 | saw_digit = 1; |
---|
565 | } |
---|
566 | } else if (ch == '.' && saw_digit) { |
---|
567 | if (octets == 4) |
---|
568 | return (0); |
---|
569 | *++tp = 0; |
---|
570 | saw_digit = 0; |
---|
571 | } else |
---|
572 | return (0); |
---|
573 | } |
---|
574 | if (octets < 4) |
---|
575 | return (0); |
---|
576 | memcpy(dst, tmp, NS_INADDRSZ); |
---|
577 | return (1); |
---|
578 | } |
---|
579 | #endif |
---|
580 | |
---|
581 | #ifdef AF_INET6 |
---|
582 | /* int |
---|
583 | * inet_pton6(src, dst) |
---|
584 | * convert presentation level address to network order binary form. |
---|
585 | * return: |
---|
586 | * 1 if `src' is a valid [RFC1884 2.2] address, else 0. |
---|
587 | * notice: |
---|
588 | * (1) does not touch `dst' unless it's returning 1. |
---|
589 | * (2) :: in a full address is silently ignored. |
---|
590 | * credit: |
---|
591 | * inspired by Mark Andrews. |
---|
592 | * author: |
---|
593 | * Paul Vixie, 1996. |
---|
594 | */ |
---|
595 | static int |
---|
596 | inet_pton6(src, dst) |
---|
597 | const char *src; |
---|
598 | u_char *dst; |
---|
599 | { |
---|
600 | static const char xdigits_l[] = "0123456789abcdef", |
---|
601 | xdigits_u[] = "0123456789ABCDEF"; |
---|
602 | u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; |
---|
603 | const char *xdigits, *curtok; |
---|
604 | int ch, saw_xdigit; |
---|
605 | u_int val; |
---|
606 | |
---|
607 | memset((tp = tmp), '\0', NS_IN6ADDRSZ); |
---|
608 | endp = tp + NS_IN6ADDRSZ; |
---|
609 | colonp = NULL; |
---|
610 | /* Leading :: requires some special handling. */ |
---|
611 | if (*src == ':') |
---|
612 | if (*++src != ':') |
---|
613 | return (0); |
---|
614 | curtok = src; |
---|
615 | saw_xdigit = 0; |
---|
616 | val = 0; |
---|
617 | while ((ch = *src++) != '\0') { |
---|
618 | const char *pch; |
---|
619 | |
---|
620 | if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) |
---|
621 | pch = strchr((xdigits = xdigits_u), ch); |
---|
622 | if (pch != NULL) { |
---|
623 | val <<= 4; |
---|
624 | val |= (pch - xdigits); |
---|
625 | if (val > 0xffff) |
---|
626 | return (0); |
---|
627 | saw_xdigit = 1; |
---|
628 | continue; |
---|
629 | } |
---|
630 | if (ch == ':') { |
---|
631 | curtok = src; |
---|
632 | if (!saw_xdigit) { |
---|
633 | if (colonp) |
---|
634 | return (0); |
---|
635 | colonp = tp; |
---|
636 | continue; |
---|
637 | } else if (*src == '\0') { |
---|
638 | return (0); |
---|
639 | } |
---|
640 | if (tp + NS_INT16SZ > endp) |
---|
641 | return (0); |
---|
642 | *tp++ = (u_char) (val >> 8) & 0xff; |
---|
643 | *tp++ = (u_char) val & 0xff; |
---|
644 | saw_xdigit = 0; |
---|
645 | val = 0; |
---|
646 | continue; |
---|
647 | } |
---|
648 | if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && |
---|
649 | inet_pton4(curtok, tp) > 0) { |
---|
650 | tp += NS_INADDRSZ; |
---|
651 | saw_xdigit = 0; |
---|
652 | break; /* '\0' was seen by inet_pton4(). */ |
---|
653 | } |
---|
654 | return (0); |
---|
655 | } |
---|
656 | if (saw_xdigit) { |
---|
657 | if (tp + NS_INT16SZ > endp) |
---|
658 | return (0); |
---|
659 | *tp++ = (u_char) (val >> 8) & 0xff; |
---|
660 | *tp++ = (u_char) val & 0xff; |
---|
661 | } |
---|
662 | if (colonp != NULL) { |
---|
663 | /* |
---|
664 | * Since some memmove()'s erroneously fail to handle |
---|
665 | * overlapping regions, we'll do the shift by hand. |
---|
666 | */ |
---|
667 | const int n = tp - colonp; |
---|
668 | int i; |
---|
669 | |
---|
670 | if (tp == endp) |
---|
671 | return (0); |
---|
672 | for (i = 1; i <= n; i++) { |
---|
673 | endp[- i] = colonp[n - i]; |
---|
674 | colonp[n - i] = 0; |
---|
675 | } |
---|
676 | tp = endp; |
---|
677 | } |
---|
678 | if (tp != endp) |
---|
679 | return (0); |
---|
680 | memcpy(dst, tmp, NS_IN6ADDRSZ); |
---|
681 | return (1); |
---|
682 | } |
---|
683 | #endif |
---|