1/* ============================================================================
2 * Copyright (C) 1998-2001 Angus Mackay. All rights reserved;
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
10 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
11 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
13 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
14 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
15 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
16 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
17 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
18 * POSSIBILITY OF SUCH DAMAGE.
19 * ============================================================================
20 */
21
22/*
23 * ez-ipupdate
24 *
25 * a very simple dynDNS client for the ez-ip dynamic dns service
26 * (http://www.ez-ip.net).
27 *
28 * why this program when something like:
29 *   curl -u user:pass http://www.ez-ip.net/members/update/?key=val&...
30 * would do the trick? because there are nicer clients for other OSes and
31 * I don't like to see UNIX get the short end of the stick.
32 *
33 * tested under Linux and Solaris.
34 *
35 */
36//2007.03.14 Yau add
37#ifdef ASUS_DDNS
38#include "asus_ddns.h"
39#include <bcmnvram.h>
40#endif  // ASUS_DDNS
41
42#ifdef HAVE_CONFIG_H
43#  include <config.h>
44#endif
45
46#ifndef EMBED
47// you man very well need to edit this, don't worry though, email is only sent
48// if bad things happend and it has to exit when in daemon mode.
49#define SEND_EMAIL_CMD "mail"
50#endif
51
52#define EZIP_DEFAULT_SERVER "www.EZ-IP.Net"
53#define EZIP_DEFAULT_PORT "80"
54#define EZIP_REQUEST "/members/update/"
55
56#define PGPOW_DEFAULT_SERVER "www.penguinpowered.com"
57#define PGPOW_DEFAULT_PORT "2345"
58#define PGPOW_REQUEST "update"
59#define PGPOW_VERSION "1.0"
60
61#define DHS_DEFAULT_SERVER "members.dhs.org"
62#define DHS_DEFAULT_PORT "80"
63#define DHS_REQUEST "/nic/hosts"
64#define DHS_SUCKY_TIMEOUT 5 //60
65
66#define DYNDNS_DEFAULT_SERVER "members.dyndns.org"
67#define DYNDNS_DEFAULT_PORT "80"
68#define DYNDNS_REQUEST "/nic/update"
69#define DYNDNS_STAT_REQUEST "/nic/update"
70#define DYNDNS_MAX_INTERVAL (25*24*3600)
71
72#define QDNS_DEFAULT_SERVER "members.3322.org"
73#define QDNS_DEFAULT_PORT "80"
74#define QDNS_REQUEST "/dyndns/update"
75#define QDNS_STAT_REQUEST "/dyndns/update"
76
77#define ODS_DEFAULT_SERVER "update.ods.org"
78#define ODS_DEFAULT_PORT "7070"
79#define ODS_REQUEST "update"
80
81#define TZO_DEFAULT_SERVER "cgi.tzo.com"
82#define TZO_DEFAULT_PORT "80"
83#define TZO_REQUEST "/webclient/signedon.html"
84
85#define GNUDIP_DEFAULT_SERVER ""
86#define GNUDIP_DEFAULT_PORT "3495"
87#define GNUDIP_REQUEST "0"
88
89#define EASYDNS_DEFAULT_SERVER "members.easydns.com"
90#define EASYDNS_DEFAULT_PORT "80"
91#define EASYDNS_REQUEST "/dyn/ez-ipupdate.php"
92
93#define EASYDNS_PARTNER_DEFAULT_SERVER "api.easydns.com"
94#define EASYDNS_PARTNER_DEFAULT_PORT "80"
95#define EASYDNS_PARTNER_REQUEST "/dyn/ez-ipupdate.php"
96
97#define JUSTL_DEFAULT_SERVER "www.justlinux.com"
98#define JUSTL_DEFAULT_PORT "80"
99#define JUSTL_REQUEST "/bin/controlpanel/dyndns/jlc.pl"
100#define JUSTL_VERSION "2.0"
101
102#define DYNS_DEFAULT_SERVER "www.dyns.cx"
103#define DYNS_DEFAULT_PORT "80"
104#define DYNS_REQUEST "/postscript.php"
105
106#define HN_DEFAULT_SERVER "dup.hn.org"
107#define HN_DEFAULT_PORT "80"
108#define HN_REQUEST "/vanity/update"
109
110#define ZONEEDIT_DEFAULT_SERVER "www.zoneedit.com"
111#define ZONEEDIT_DEFAULT_PORT "80"
112#define ZONEEDIT_REQUEST "/auth/dynamic.html"
113
114#define HEIPV6TB_DEFAULT_SERVER "ipv6tb.he.net"
115#define HEIPV6TB_DEFAULT_PORT "80"
116#define HEIPV6TB_REQUEST "/index.cgi"
117
118#define DEFAULT_TIMEOUT 5 //120
119#define DEFAULT_UPDATE_PERIOD 120
120#define DEFAULT_RESOLV_PERIOD 30
121
122#ifdef DEBUG
123#  define BUFFER_SIZE (16*1024)
124#else
125#  define BUFFER_SIZE (4*1024-1)
126#endif
127
128#ifdef HAVE_GETOPT_H
129#  include <getopt.h>
130#endif
131#include <stdio.h>
132#include <stdlib.h>
133#include <string.h>
134#include <ctype.h>
135#include <unistd.h>
136#include <time.h>
137#if HAVE_FCNTL_H
138#  include <fcntl.h>
139#endif
140#include <netinet/in.h>
141#if HAVE_ARPA_INET_H
142#  include <arpa/inet.h>
143#endif
144#if HAVE_ERRNO_H
145#  include <errno.h>
146#endif
147#include <netdb.h>
148#include <sys/socket.h>
149#if HAVE_SYS_TYPES_H
150#  include <sys/types.h>
151#endif
152#if HAVE_SIGNAL_H
153#  include <signal.h>
154#endif
155#if HAVE_SYS_TIME_H
156#  include <sys/time.h>
157#endif
158#if HAVE_SYS_WAIT_H
159#  include <sys/wait.h>
160#endif
161#if HAVE_SYSLOG_H
162#  include <syslog.h>
163#endif
164#if HAVE_STDARG_H
165#  include <stdarg.h>
166#endif
167#include <error.h>
168#if HAVE_PWD_H && HAVE_GRP_H
169#  include <pwd.h>
170#  include <grp.h>
171#endif
172#if defined(HAVE_FORK) && !defined(HAVE_VFORK)
173#  define vfork fork
174#endif
175#if USE_MD5
176#  include <md5.h>
177#  define MD5_DIGEST_BYTES (16)
178#endif
179
180
181#if __linux__ || __SVR4 || __OpenBSD__ || __FreeBSD__ || __NetBSD__
182#  define IF_LOOKUP 1
183#  include <sys/ioctl.h>
184#  include <net/if.h>
185#  ifdef HAVE_SYS_SOCKIO_H
186#    include <sys/sockio.h>
187#  endif
188#endif
189
190#include <dprintf.h>
191#include <conf_file.h>
192#include <cache_file.h>
193#include <pid_file.h>
194
195#if !defined(__GNUC__) && !defined(HAVE_SNPRINTF)
196#error "get gcc, fix this code, or find yourself a snprintf!"
197#else
198#  if HAVE_SNPRINTF
199#    define  snprintf(x, y, z...) snprintf(x, y, ## z)
200#  else
201#    define  snprintf(x, y, z...) sprintf(x, ## z)
202#  endif
203#endif
204#if HAVE_VSNPRINTF
205#  define  vsnprintf(x, y, z...) vsnprintf(x, y, ## z)
206#else
207#  define  vsnprintf(x, y, z...) vsprintf(x, ## z)
208#endif
209
210#ifndef HAVE_HERROR
211#  define herror(x) show_message("%s: error\n", x)
212#endif
213
214#define ARRAY_LEN(x) (sizeof(x)/sizeof(x[0]))
215#define N_STR(x) (x == NULL ? "(null)" : x)
216
217#ifndef OS
218#  define OS "unknown"
219#endif
220
221// the min period for checking the interface
222#define MIN_UPDATE_PERIOD 10
223// the min/max time to wait if we fail to update
224#define MIN_WAIT_PERIOD 300
225#define MAX_WAIT_PERIOD (2*3600)
226// the min time that max-period can be set to
227#define MIN_MAXINTERVAL (24*3600)
228// the max time we will wait if the server tells us to
229#define MAX_WAITRESPONSE_WAIT (24*3600)
230#define MAX_MESSAGE_LEN 256
231#define ARGLENGTH 32
232#define BLOCK_FILE "/var/run/ez-ipupdate.block"
233#define PID_FILE "/var/run/ez-ipupdate.pid"
234
235/**************************************************/
236
237struct service_t
238{
239  char *title;
240  char *names[3];
241  void (*init)(void);
242  int (*update_entry)(void);
243  int (*check_info)(void);
244  char **fields_used;
245  char *default_server;
246  char *default_port;
247  char *default_request;
248};
249
250enum {
251  UPDATERES_OK = 0,
252  UPDATERES_ERROR,
253  UPDATERES_SHUTDOWN,
254};
255
256/**************************************************/
257
258char *program_name = NULL;
259char *cache_file = NULL;
260char *config_file = NULL;
261char *server = NULL;
262char *port = NULL;
263char user[256];
264char auth[512];
265char user_name[128];
266char password[128];
267char *address = NULL;
268char *request = NULL;
269char *request_over_ride = NULL;
270int wildcard = 0;
271char *mx = NULL;
272char *url = NULL;
273char *host = NULL;
274char *cloak_title = NULL;
275char *interface = NULL;
276int ntrys = 1;
277int update_period = DEFAULT_UPDATE_PERIOD;
278int resolv_period = DEFAULT_RESOLV_PERIOD;
279struct timeval timeout;
280int max_interval = 0;
281int service_set = 0;
282char *post_update_cmd = NULL;
283char *post_update_cmd_arg = NULL;
284int connection_type = 1;
285time_t last_update = 0;
286#ifdef SEND_EMAIL_CMD
287char *notify_email = NULL;
288#endif
289char *pid_file = NULL;
290char *partner = NULL;
291char update_entry_buf[BUFFER_SIZE+1];
292char update_entry_putbuf[BUFFER_SIZE+1];
293
294//2007.03.14 Yau add
295#ifdef ASUS_DDNS
296volatile int client_sockfd;
297#else   // !ASUS_DDNS
298static volatile int client_sockfd;
299#endif  // ASUS_DDNS
300static volatile int last_sig = 0;
301
302/* service objects for various services */
303
304// this one is for when people don't configure a default service at build time
305int NULL_check_info(void);
306static char *NULL_fields_used[] = { NULL };
307
308int EZIP_update_entry(void);
309int EZIP_check_info(void);
310static char *EZIP_fields_used[] = { "server", "user", "address", "wildcard", "mx", "url", "host", NULL };
311
312#ifdef CONFIG_PGP
313int PGPOW_update_entry(void);
314int PGPOW_check_info(void);
315static char *PGPOW_fields_used[] = { "server", "host", NULL };
316#endif
317
318int DHS_update_entry(void);
319int DHS_check_info(void);
320static char *DHS_fields_used[] = { "server", "user", "address", "wildcard", "mx", "url", "host", NULL };
321
322void DYNDNS_init(void);
323int DYNDNS_update_entry(void);
324int DYNDNS_check_info(void);
325static char *DYNDNS_fields_used[] = { "server", "user", "address", "wildcard", "mx", "host", NULL };
326static char *DYNDNS_STAT_fields_used[] = { "server", "user", "address", "wildcard", "mx", "host", NULL };
327
328#ifdef CONFIG_ODS
329int ODS_update_entry(void);
330int ODS_check_info(void);
331static char *ODS_fields_used[] = { "server", "host", "address", NULL };
332#endif
333
334int TZO_update_entry(void);
335int TZO_check_info(void);
336static char *TZO_fields_used[] = { "server", "user", "address", "host", "connection-type", NULL };
337
338int EASYDNS_update_entry(void);
339int EASYDNS_check_info(void);
340static char *EASYDNS_fields_used[] = { "server", "user", "address", "wildcard", "mx", "host", NULL };
341
342int EASYDNS_PARTNER_update_entry(void);
343int EASYDNS_PARTNER_check_info(void);
344static char *EASYDNS_PARTNER_fields_used[] = { "server", "partner", "user", "address", "wildcard", "host", NULL };
345
346#ifdef USE_MD5
347int GNUDIP_update_entry(void);
348int GNUDIP_check_info(void);
349static char *GNUDIP_fields_used[] = { "server", "user", "host", "address", NULL };
350#endif
351
352#ifdef CONFIG_PGP
353int JUSTL_update_entry(void);
354int JUSTL_check_info(void);
355static char *JUSTL_fields_used[] = { "server", "user", "host", NULL };
356#endif
357
358int DYNS_update_entry(void);
359int DYNS_check_info(void);
360static char *DYNS_fields_used[] = { "server", "user", "host", NULL };
361
362#ifdef CONFIG_HN
363int HN_update_entry(void);
364int HN_check_info(void);
365static char *HN_fields_used[] = { "server", "user", "address", NULL };
366#endif
367
368int ZONEEDIT_update_entry(void);
369int ZONEEDIT_check_info(void);
370static char *ZONEEDIT_fields_used[] = { "server", "user", "address", "mx", "host", NULL };
371
372#ifdef CONFIG_HEIP
373int HEIPV6TB_update_entry(void);
374int HEIPV6TB_check_info(void);
375static char *HEIPV6TB_fields_used[] = { "server", "user", NULL };
376#endif
377
378struct service_t services[] = {
379  { "NULL",
380    { "null", "NULL", 0, },
381    NULL,
382    NULL,
383    NULL_check_info,
384    NULL_fields_used,
385    "",
386    "",
387    ""
388  },
389  { "ez-ip",
390    { "ezip", "ez-ip", 0, },
391    NULL,
392    EZIP_update_entry,
393    EZIP_check_info,
394    EZIP_fields_used,
395    EZIP_DEFAULT_SERVER,
396    EZIP_DEFAULT_PORT,
397    EZIP_REQUEST
398  },
399#ifdef CONFIG_PGP
400  { "justlinux v1.0 (penguinpowered)",
401    { "pgpow", "penguinpowered", 0, },
402    NULL,
403    PGPOW_update_entry,
404    PGPOW_check_info,
405    PGPOW_fields_used,
406    PGPOW_DEFAULT_SERVER,
407    PGPOW_DEFAULT_PORT,
408    PGPOW_REQUEST
409  },
410#endif
411#ifdef CONFIG_DHS
412  { "dhs",
413    { "dhs", 0, 0, },
414    NULL,
415    DHS_update_entry,
416    DHS_check_info,
417    DHS_fields_used,
418    DHS_DEFAULT_SERVER,
419    DHS_DEFAULT_PORT,
420    DHS_REQUEST
421  },
422#endif
423  { "dyndns",
424    { "dyndns", 0, 0, },
425    DYNDNS_init,
426    DYNDNS_update_entry,
427    DYNDNS_check_info,
428    DYNDNS_fields_used,
429    DYNDNS_DEFAULT_SERVER,
430    DYNDNS_DEFAULT_PORT,
431    DYNDNS_REQUEST
432  },
433  { "dyndns-static",
434    { "dyndns-static", "dyndns-stat", "statdns", },
435    DYNDNS_init,
436    DYNDNS_update_entry,
437    DYNDNS_check_info,
438    DYNDNS_STAT_fields_used,
439    DYNDNS_DEFAULT_SERVER,
440    DYNDNS_DEFAULT_PORT,
441    DYNDNS_STAT_REQUEST
442  },
443  { "dyndns-custom",
444    { "dyndns-custom", "mydyndns", 0 },
445    DYNDNS_init,
446    DYNDNS_update_entry,
447    DYNDNS_check_info,
448    DYNDNS_STAT_fields_used,
449    DYNDNS_DEFAULT_SERVER,
450    DYNDNS_DEFAULT_PORT,
451    DYNDNS_REQUEST
452  },
453  { "qdns",
454    {  "qdns dynamic" },
455    DYNDNS_init,
456    DYNDNS_update_entry,
457    DYNDNS_check_info,
458    DYNDNS_fields_used,
459    QDNS_DEFAULT_SERVER,
460    QDNS_DEFAULT_PORT,
461    QDNS_REQUEST
462  },
463  { "qdns-static",
464    {"qdns-static"},
465    DYNDNS_init,
466    DYNDNS_update_entry,
467    DYNDNS_check_info,
468    DYNDNS_STAT_fields_used,
469    QDNS_DEFAULT_SERVER,
470    QDNS_DEFAULT_PORT,
471    QDNS_STAT_REQUEST
472  },
473#ifdef CONFIG_ODS
474  { "ods",
475    { "ods", 0, 0, },
476    NULL,
477    ODS_update_entry,
478    ODS_check_info,
479    ODS_fields_used,
480    ODS_DEFAULT_SERVER,
481    ODS_DEFAULT_PORT,
482    ODS_REQUEST
483  },
484#endif
485  { "tzo",
486    { "tzo", 0, 0, },
487    NULL,
488    TZO_update_entry,
489    TZO_check_info,
490    TZO_fields_used,
491    TZO_DEFAULT_SERVER,
492    TZO_DEFAULT_PORT,
493    TZO_REQUEST
494  },
495  { "easydns",
496    { "easydns", 0, 0, },
497    NULL,
498    EASYDNS_update_entry,
499    EASYDNS_check_info,
500    EASYDNS_fields_used,
501    EASYDNS_DEFAULT_SERVER,
502    EASYDNS_DEFAULT_PORT,
503    EASYDNS_REQUEST
504  },
505  { "easydns-partner",
506    { "easydns-partner", 0, 0, },
507    NULL,
508    EASYDNS_PARTNER_update_entry,
509    EASYDNS_PARTNER_check_info,
510    EASYDNS_PARTNER_fields_used,
511    EASYDNS_PARTNER_DEFAULT_SERVER,
512    EASYDNS_PARTNER_DEFAULT_PORT,
513    EASYDNS_PARTNER_REQUEST
514  },
515#ifdef USE_MD5
516  { "gnudip",
517    { "gnudip", 0, 0, },
518    NULL,
519    GNUDIP_update_entry,
520    GNUDIP_check_info,
521    GNUDIP_fields_used,
522    GNUDIP_DEFAULT_SERVER,
523    GNUDIP_DEFAULT_PORT,
524    GNUDIP_REQUEST
525  },
526#endif
527
528#ifdef CONFIG_PGP
529  { "justlinux v2.0 (penguinpowered)",
530    { "justlinux", 0, 0, },
531    NULL,
532    JUSTL_update_entry,
533    JUSTL_check_info,
534    JUSTL_fields_used,
535    JUSTL_DEFAULT_SERVER,
536    JUSTL_DEFAULT_PORT,
537    JUSTL_REQUEST
538  },
539#endif
540  { "dyns",
541    { "dyns", 0, 0, },
542    NULL,
543    DYNS_update_entry,
544    DYNS_check_info,
545    DYNS_fields_used,
546    DYNS_DEFAULT_SERVER,
547    DYNS_DEFAULT_PORT,
548    DYNS_REQUEST
549  },
550#ifdef CONFIG_HN
551  { "hammer node",
552    { "hn", 0, 0, },
553    NULL,
554    HN_update_entry,
555    HN_check_info,
556    HN_fields_used,
557    HN_DEFAULT_SERVER,
558    HN_DEFAULT_PORT,
559    HN_REQUEST
560  },
561#endif
562  { "zoneedit",
563    { "zoneedit", 0, 0, },
564    NULL,
565    ZONEEDIT_update_entry,
566    ZONEEDIT_check_info,
567    ZONEEDIT_fields_used,
568    ZONEEDIT_DEFAULT_SERVER,
569    ZONEEDIT_DEFAULT_PORT,
570    ZONEEDIT_REQUEST
571  },
572#ifdef CONFIG_HEIP
573  { "heipv6tb",
574    { "heipv6tb", 0, 0, },
575    NULL,
576    HEIPV6TB_update_entry,
577    HEIPV6TB_check_info,
578    HEIPV6TB_fields_used,
579    HEIPV6TB_DEFAULT_SERVER,
580    HEIPV6TB_DEFAULT_PORT,
581    HEIPV6TB_REQUEST
582  },
583#endif
584};
585
586static struct service_t *service = NULL;
587
588int options;
589
590#define OPT_DEBUG       0x0001
591#define OPT_DAEMON      0x0004
592#define OPT_QUIET       0x0008
593#define OPT_FOREGROUND  0x0010
594#define OPT_OFFLINE     0x0020
595#define OPT_ONCE		0x0040
596
597enum {
598  CMD__start = 1,
599  CMD_service_type,
600  CMD_server,
601  CMD_request,
602  CMD_user,
603  CMD_address,
604  CMD_wildcard,
605  CMD_mx,
606  CMD_max_interval,
607  CMD_url,
608  CMD_host,
609  CMD_cloak_title,
610  CMD_interface,
611  CMD_retrys,
612  CMD_resolv_period,
613  CMD_period,
614  CMD_daemon,
615  CMD_debug,
616  CMD_execute,
617  CMD_foreground,
618  CMD_quiet,
619  CMD_timeout,
620  CMD_run_as_user,
621  CMD_run_as_euser,
622  CMD_connection_type,
623  CMD_cache_file,
624#ifdef SEND_EMAIL_CMD
625  CMD_notify_email,
626#endif
627  CMD_pid_file,
628  CMD_offline,
629  CMD_partner,
630  CMD_once,
631//2007.03.14 Yau add
632#ifdef ASUS_DDNS
633  CMD_asus,
634#endif  // ASUS_DDNS
635  CMD__end
636};
637
638int conf_handler(struct conf_cmd *cmd, char *arg);
639static struct conf_cmd conf_commands[] = {
640  { CMD_address,         "address",         CONF_NEED_ARG, 1, conf_handler, "%s=<ip address>" },
641  { CMD_cache_file,      "cache-file",      CONF_NEED_ARG, 1, conf_handler, "%s=<cache file>" },
642  { CMD_cloak_title,     "cloak-title",     CONF_NEED_ARG, 1, conf_handler, "%s=<title>" },
643  { CMD_daemon,          "daemon",          CONF_NO_ARG,   1, conf_handler, "%s=<command>" },
644  { CMD_execute,         "execute",         CONF_NEED_ARG, 1, conf_handler, "%s=<shell command>" },
645  { CMD_debug,           "debug",           CONF_NO_ARG,   1, conf_handler, "%s" },
646  { CMD_foreground,      "foreground",      CONF_NO_ARG,   1, conf_handler, "%s" },
647  { CMD_pid_file,        "pid-file",        CONF_NEED_ARG, 1, conf_handler, "%s=<file>" },
648  { CMD_host,            "host",            CONF_NEED_ARG, 1, conf_handler, "%s=<host>" },
649  { CMD_interface,       "interface",       CONF_NEED_ARG, 1, conf_handler, "%s=<interface>" },
650  { CMD_mx,              "mx",              CONF_NEED_ARG, 1, conf_handler, "%s=<mail exchanger>" },
651  { CMD_max_interval,    "max-interval",    CONF_NEED_ARG, 1, conf_handler, "%s=<number of seconds between updates>" },
652#ifdef SEND_EMAIL_CMD
653  { CMD_notify_email,    "notify-email",    CONF_NEED_ARG, 1, conf_handler, "%s=<address to email if bad things happen>" },
654#endif
655  { CMD_offline,         "offline",         CONF_NO_ARG,   1, conf_handler, "%s" },
656  { CMD_retrys,          "retrys",          CONF_NEED_ARG, 1, conf_handler, "%s=<number of trys>" },
657  { CMD_server,          "server",          CONF_NEED_ARG, 1, conf_handler, "%s=<server name>" },
658  { CMD_service_type,    "service-type",    CONF_NEED_ARG, 1, conf_handler, "%s=<service type>" },
659  { CMD_timeout,         "timeout",         CONF_NEED_ARG, 1, conf_handler, "%s=<sec.millisec>" },
660  { CMD_resolv_period,   "resolv-period",   CONF_NEED_ARG, 1, conf_handler, "%s=<time between failed resolve attempts>" },
661  { CMD_period,          "period",          CONF_NEED_ARG, 1, conf_handler, "%s=<time between update attempts>" },
662  { CMD_url,             "url",             CONF_NEED_ARG, 1, conf_handler, "%s=<url>" },
663  { CMD_user,            "user",            CONF_NEED_ARG, 1, conf_handler, "%s=<user name>[:password]" },
664  { CMD_run_as_user,     "run-as-user",     CONF_NEED_ARG, 1, conf_handler, "%s=<user>" },
665  { CMD_run_as_euser,    "run-as-euser",    CONF_NEED_ARG, 1, conf_handler, "%s=<user> (this is not secure)" },
666  { CMD_wildcard,        "wildcard",        CONF_NO_ARG,   1, conf_handler, "%s" },
667  { CMD_quiet,           "quiet",           CONF_NO_ARG,   1, conf_handler, "%s" },
668  { CMD_connection_type, "connection-type", CONF_NEED_ARG, 1, conf_handler, "%s=<connection type>" },
669  { CMD_request,         "request",         CONF_NEED_ARG, 1, conf_handler, "%s=<request uri>" },
670  { CMD_partner,         "partner",         CONF_NEED_ARG, 1, conf_handler, "%s=<easydns partner>" },
671  { 0, 0, 0, 0, 0 }
672};
673
674/**************************************************/
675
676void print_usage( void );
677void print_version( void );
678void parse_args( int argc, char **argv );
679int do_connect(int *sock, char *host, char *port);
680void base64Encode(char *intext, char *output);
681int main( int argc, char **argv );
682void warn_fields(char **okay_fields);
683static int is_in_list(char *needle, char **haystack);
684
685/**************************************************/
686
687void print_usage( void )
688{
689  int i;
690  int width;
691
692  fprintf(stdout, "usage: ");
693  fprintf(stdout, "%s [options] \n\n", program_name);
694  fprintf(stdout, " Options are:\n");
695  fprintf(stdout, "  -a, --address <ip address>\tstring to send as your ip address\n");
696  fprintf(stdout, "  -b, --cache-file <file>\tfile to use for caching the ipaddress\n");
697  fprintf(stdout, "  -c, --config-file <file>\tconfiguration file, almost all arguments can be\n");
698  fprintf(stdout, "\t\t\t\tgiven with: <name>[=<value>]\n\t\t\t\tto see a list of possible config commands\n");
699  fprintf(stdout, "\t\t\t\ttry \"echo help | %s -c -\"\n", program_name);
700  fprintf(stdout, "  -d, --daemon\t\t\trun as a daemon periodicly updating if \n\t\t\t\tnecessary\n");
701#ifdef DEBUG
702  fprintf(stdout, "  -D, --debug\t\t\tturn on debuggin\n");
703#endif
704  fprintf(stdout, "  -e, --execute <command>\tshell command to execute after a successful\n\t\t\t\tupdate\n");
705  fprintf(stdout, "  -f, --foreground\t\twhen running as a daemon run in the foreground\n");
706  fprintf(stdout, "  -F, --pidfile <file>\t\tuse <file> as a pid file\n");
707  fprintf(stdout, "  -g, --request-uri <uri>\tURI to send updates to\n");
708  fprintf(stdout, "  -h, --host <host>\t\tstring to send as host parameter\n");
709  fprintf(stdout, "  -i, --interface <iface>\twhich interface to use\n");
710  fprintf(stdout, "  -L, --cloak_title <host>\tsome stupid thing for DHS only\n");
711  fprintf(stdout, "  -m, --mx <mail exchange>\tstring to send as your mail exchange\n");
712  fprintf(stdout, "  -M, --max-interval <# of sec>\tmax time in between updates\n");
713#ifdef SEND_EMAIL_CMD
714  fprintf(stdout, "  -N, --notify-email <email>\taddress to send mail to if bad things happen\n");
715#endif
716  fprintf(stdout, "  -o, --offline\t\t\tset to off line mode\n");
717  fprintf(stdout, "  -p, --resolv-period <sec>\tperiod to check IP if it can't be resolved\n");
718  fprintf(stdout, "  -P, --period <# of sec>\tperiod to check IP in daemon \n\t\t\t\tmode (default: 1800 seconds)\n");
719  fprintf(stdout, "  -q, --quiet \t\t\tbe quiet\n");
720  fprintf(stdout, "  -r, --retrys <num>\t\tnumber of trys (default: 1)\n");
721  fprintf(stdout, "  -R, --run-as-user <user>\tchange to <user> for running, be ware\n\t\t\t\tthat this can cause problems with handeling\n\t\t\t\tSIGHUP properly if that user can't read the\n\t\t\t\tconfig file. also it can't write it's pid file \n\t\t\t\tto a root directory\n");
722  fprintf(stdout, "  -Q, --run-as-euser <user>\tchange to effective <user> for running, \n\t\t\t\tthis is NOT secure but it does solve the \n\t\t\t\tproblems with run-as-user and config files and \n\t\t\t\tpid files.\n");
723  fprintf(stdout, "  -s, --server <server[:port]>\tthe server to connect to\n");
724  fprintf(stdout, "  -S, --service-type <server>\tthe type of service that you are using\n");
725  width = fprintf(stdout, "\t\t\t\ttry one of: ") + 4*7;
726  for(i=0; i<ARRAY_LEN(services); i++)
727  {
728    if(width > 60) { width = fprintf(stdout, "\n\t\t\t\t") -1 + 4*7; }
729    width += fprintf(stdout, "%s ", services[i].names[0]);
730  }
731  fprintf(stdout, "\n");
732  fprintf(stdout, "  -t, --timeout <sec.millisec>\tthe amount of time to wait on I/O\n");
733  fprintf(stdout, "  -T, --connection-type <num>\tnumber sent to TZO as your connection \n\t\t\t\ttype (default: 1)\n");
734  fprintf(stdout, "  -U, --url <url>\t\tstring to send as the url parameter\n");
735  fprintf(stdout, "  -u, --user <user[:passwd]>\tuser ID and password, if either is left blank \n\t\t\t\tthey will be prompted for\n");
736  fprintf(stdout, "  -w, --wildcard\t\tset your domain to have a wildcard alias\n");
737  fprintf(stdout, "  -z, --partner <partner>\tspecify easyDNS partner (for easydns-partner \n\t\t\t\tservices)\n");
738  fprintf(stdout, "  -1, --once\tin daemon mode, update once then exit\n");
739  fprintf(stdout, "      --help\t\t\tdisplay this help and exit\n");
740  fprintf(stdout, "      --version\t\t\toutput version information and exit\n");
741  fprintf(stdout, "      --credits\t\t\tprint the credits and exit\n");
742#ifndef EMBED
743  fprintf(stdout, "      --signalhelp\t\tprint help about signals\n");
744#endif
745  fprintf(stdout, "\n");
746}
747
748void print_version( void )
749{
750  fprintf(stdout, "%s: - %s - $Id: ez-ipupdate.c,v 1.1.1.1 2008/10/15 03:28:47 james26_jang Exp $\n", program_name, VERSION);
751}
752
753void print_credits( void )
754{
755  fprintf( stdout, "AUTHORS / CONTRIBUTORS\n"
756      "  Angus Mackay <amackay@gusnet.cx>\n"
757      "  Jeremy Bopp <jbopp@mail.utexas.edu>\n"
758      "  Mark Jeftovic <markjr@easydns.com>\n"
759      "  Stefaan Ponnet <webmaster@dyns.cx>\n"
760      "  Colin Viebrock <colin@easydns.com>\n"
761      "  Tim Brown <timb@machine.org.uk>\n"
762      "\n" );
763}
764
765#ifndef EMBED
766void print_signalhelp( void )
767{
768  fprintf(stdout, "\nsignals are only really used when in daemon mode.\n\n");
769  fprintf(stdout, "signals: \n");
770  fprintf(stdout, "  HUP\t\tcauses it to re-read its config file\n");
771  fprintf(stdout, "  TERM\t\twake up and possibly perform an update\n");
772  fprintf(stdout, "  QUIT\t\tshutdown\n");
773  fprintf(stdout, "\n");
774}
775#endif
776
777#if HAVE_SIGNAL_H
778RETSIGTYPE sigint_handler(int sig)
779{
780  char message[] = "interupted.\n";
781  close(client_sockfd);
782  write(2, message, sizeof(message)-1);
783
784#if HAVE_GETPID
785  if(pid_file)
786  {
787    pid_file_delete(pid_file);
788  }
789#endif
790
791  exit(1);
792}
793RETSIGTYPE generic_sig_handler(int sig)
794{
795  last_sig = sig;
796}
797#endif
798
799int get_duration(char *str)
800{
801  char *multchar;
802  int mult;
803  char save;
804  int duration;
805
806  for(multchar=str; *multchar != '\0'; multchar++);
807  if(multchar != str) { multchar--; }
808  if(*multchar == '\0' || isdigit(*multchar)) { mult = 1; multchar++; }
809  else if(*multchar == 'M') { mult = 60; }
810  else if(*multchar == 'H') { mult = 60*60; }
811  else if(*multchar == 'd') { mult = 60*60*24; }
812  else if(*multchar == 'w') { mult = 60*60*24*7; }
813  else if(*multchar == 'f') { mult = 60*60*24*7*2; }
814  else if(*multchar == 'm') { mult = 60*60*24*30; }
815  else if(*multchar == 'y') { mult = 60*60*24*365; }
816  else
817  {
818    show_message("invalid multiplier: %c\n", *multchar);
819#ifndef EMBED
820    fprintf(stderr, "valid multipliers:\n");
821    fprintf(stderr, "  %c -> %s (%d)\n", 'M', "Minute",    60);
822    fprintf(stderr, "  %c -> %s (%d)\n", 'H', "Hour",      60*60);
823    fprintf(stderr, "  %c -> %s (%d)\n", 'd', "day",       60*60*24);
824    fprintf(stderr, "  %c -> %s (%d)\n", 'w', "week",      60*60*24*7);
825    fprintf(stderr, "  %c -> %s (%d)\n", 'f', "fortnight", 60*60*24*7*2);
826    fprintf(stderr, "  %c -> %s (%d)\n", 'm', "month",     60*60*24*30);
827    fprintf(stderr, "  %c -> %s (%d)\n", 'y', "year",      60*60*24*365);
828#else
829	fprintf(stderr, "valid multipliers: MHdwfmy\n");
830#endif
831    exit(1);
832  }
833  save = *multchar;
834  *multchar = '\0';
835  duration = strtol(str, NULL, 0) * mult;
836  *multchar = save;
837
838  return(duration);
839}
840
841const char* format_time(int seconds)
842{
843  static char buf[16];
844
845  snprintf(buf, sizeof(buf), "%d:%02d:%02d", seconds/(3600),
846          (seconds%(3600))/(60), (seconds%60));
847  return(buf);
848}
849
850/*
851 * like "chomp" in perl, take off trailing newline chars
852 */
853char *chomp(char *buf)
854{
855  char *p;
856
857  for(p=buf; *p != '\0'; p++);
858  if(p != buf) { p--; }
859  while(p>=buf && (*p == '\n' || *p == '\r'))
860  {
861    *p-- = '\0';
862  }
863
864  return(buf);
865}
866
867void get_input(char *prompt, char *buf, int buflen)
868{
869  printf("%s: ", prompt);
870  fflush(stdout);
871  *buf = '\0';
872  fgets(buf, buflen-1, stdin);
873  chomp(buf);
874}
875
876/*
877 * show_message
878 *
879 * if we are running in daemon mode then log to syslog, if not just output to
880 * stderr.
881 *
882 */
883#ifdef REMOVE
884void show_message(char *fmt, ...)
885{
886  va_list args;
887  va_start(args, fmt);
888
889  if((options & OPT_DAEMON) && !(options & OPT_FOREGROUND))
890  {
891    char buf[MAX_MESSAGE_LEN];
892
893#if defined(HAVE_VSPRINTF) || defined(HAVE_VSNPRINTF)
894    vsnprintf(buf, sizeof(buf), fmt, args);
895#else
896    sprintf(buf, "message incomplete because your OS sucks: %s\n", fmt);
897#endif
898
899    syslog(LOG_NOTICE, buf);
900  }
901  else
902  {
903#ifdef HAVE_VFPRINTF
904    vfprintf(stderr, fmt, args);
905#else
906    fprintf(stderr, "message incomplete because your OS sucks: %s\n", fmt);
907#endif
908  }
909
910  va_end(args);
911}
912#else
913/*
914 * show_message
915 *
916 */
917void show_message(char *fmt, ...)
918{
919  va_list args;
920  char buf[512];
921
922  va_start(args, fmt);
923  vsnprintf(buf, sizeof(buf), fmt, args);
924  openlog("ddns update", 0, 0);
925  syslog(0, buf);
926  closelog();
927  va_end(args);
928}
929#endif
930
931/*
932 * returns true if the string passed in is an internet address in dotted quad
933 * notation.
934 */
935int is_dotted_quad(char *addr)
936{
937  int q[4];
938  char *p;
939  int i;
940
941  if(sscanf(addr, "%d.%d.%d.%d", &(q[0]), &(q[1]), &(q[2]), &(q[3])) != 4)
942  {
943    return(0);
944  }
945
946  if(q[0] > 255 || q[0] < 0 ||
947      q[1] > 255 || q[1] < 0 ||
948      q[2] > 255 || q[2] < 0 ||
949      q[3] > 255 || q[3] < 0)
950  {
951    return(0);
952  }
953
954  /* we know there are 3 dots */
955  p = addr;
956  if(p != NULL) { p = strchr(p, '.'); p++; }
957  if(p != NULL) { p = strchr(p, '.'); p++; }
958  if(p != NULL) { p = strchr(p, '.'); }
959  for(i=0; *p != '\0' && i<4; i++, p++);
960  if(*p != '\0')
961  {
962    return(0);
963  }
964
965  return(1);
966}
967
968void parse_service(char *str)
969{
970  int i;
971  int width;
972
973  for(i=0; i<ARRAY_LEN(services); i++)
974  {
975    int j;
976    for(j=0; j<ARRAY_LEN(services[i].names) && services[i].names[j] != NULL; j++)
977    {
978      if(strcmp(services[i].names[j], str) == 0)
979      {
980        service = &(services[i]);
981        return;
982      }
983    }
984  }
985  show_message("unknown service type: %s\n", str);
986  fprintf(stderr, "try one of: \n");
987  width = fprintf(stderr, "  ");
988  for(i=0; i<ARRAY_LEN(services); i++)
989  {
990    if(width > 60) { width = fprintf(stderr, "\n  ") -1; }
991    width += fprintf(stderr, "%s ", services[i].names[0]);
992  }
993  fprintf(stderr, "\n");
994  exit(1);
995}
996
997int option_handler(int id, char *optarg)
998{
999#if HAVE_PWD_H && HAVE_GRP_H
1000  struct passwd *pw;
1001#endif
1002  char *tmp;
1003  int i;
1004
1005  switch(id)
1006  {
1007    case CMD_address:
1008      if(address) { free(address); }
1009      address = strdup(optarg);
1010      dprintf((stderr, "address: %s\n", address));
1011      break;
1012
1013//2007.03.14 Yau add
1014#ifdef ASUS_DDNS
1015        case CMD_asus:
1016                i = atoi (optarg);
1017                if (i >= 0 && i <= 2)   {
1018                        g_asus_ddns_mode = i;
1019                        dprintf((stderr, "register domain mode %d\n", g_asus_ddns_mode));
1020                }
1021                break;
1022#endif  // ASUS_DDNS
1023
1024    case CMD_daemon:
1025      options |= OPT_DAEMON;
1026      dprintf((stderr, "daemon mode\n"));
1027#if HAVE_GETPID
1028      if(!pid_file) pid_file = strdup(PID_FILE);
1029#endif
1030      break;
1031
1032    case CMD_debug:
1033#ifdef DEBUG
1034      options |= OPT_DEBUG;
1035      dprintf((stderr, "debugging on\n"));
1036#else
1037      show_message("debugging was not enabled at compile time\n");
1038#endif
1039      break;
1040
1041    case CMD_execute:
1042#if defined(HAVE_WAITPID) || defined(HAVE_WAIT)
1043      if(post_update_cmd) { free(post_update_cmd); }
1044      post_update_cmd = malloc(strlen(optarg) + 1 + ARGLENGTH + 1);
1045      post_update_cmd_arg = post_update_cmd + strlen(optarg) + 1;
1046      sprintf(post_update_cmd, "%s ", optarg);
1047      dprintf((stderr, "post_update_cmd: %s\n", post_update_cmd));
1048#else
1049      show_message("command execution not enabled at compile time\n");
1050      exit(1);
1051#endif
1052      break;
1053
1054    case CMD_foreground:
1055      options |= OPT_FOREGROUND;
1056      dprintf((stderr, "fork()ing off\n"));
1057      break;
1058
1059    case CMD_pid_file:
1060#if HAVE_GETPID
1061      if(pid_file) { free(pid_file); }
1062      pid_file = strdup(optarg);
1063      dprintf((stderr, "pid file: %s\n", pid_file));
1064#else
1065      show_message("pid file support not enabled at compile time\n");
1066#endif
1067      break;
1068
1069    case CMD_host:
1070      if(host) { free(host); }
1071      host = strdup(optarg);
1072      dprintf((stderr, "host: %s\n", host));
1073      break;
1074
1075    case CMD_interface:
1076#ifdef IF_LOOKUP
1077      if(interface) { free(interface); }
1078      interface = strdup(optarg);
1079      dprintf((stderr, "interface: %s\n", interface));
1080#else
1081      show_message("interface lookup not enabled at compile time\n");
1082      exit(1);
1083#endif
1084      break;
1085
1086    case CMD_mx:
1087      if(mx) { free(mx); }
1088      mx = strdup(optarg);
1089      dprintf((stderr, "mx: %s\n", mx));
1090      break;
1091
1092    case CMD_max_interval:
1093      max_interval = get_duration(optarg);
1094      if(max_interval < MIN_MAXINTERVAL)
1095      {
1096        show_message("WARNING: max-interval of %d is too short, using %d\n",
1097            max_interval, MIN_MAXINTERVAL);
1098        max_interval = MIN_MAXINTERVAL;
1099      }
1100      dprintf((stderr, "max_interval: %d\n", max_interval));
1101      break;
1102
1103#ifdef SEND_EMAIL_CMD
1104    case CMD_notify_email:
1105      if(notify_email) { free(notify_email); }
1106      notify_email = strdup(optarg);
1107      dprintf((stderr, "notify_email: %s\n", notify_email));
1108      break;
1109#endif
1110
1111    case CMD_offline:
1112      options |= OPT_OFFLINE;
1113      dprintf((stderr, "offline mode\n"));
1114      break;
1115
1116    case CMD_period:
1117      update_period = get_duration(optarg);
1118      if(update_period < MIN_UPDATE_PERIOD)
1119      {
1120        show_message("WARNING: period of %d is too short, using %d\n",
1121            update_period, MIN_UPDATE_PERIOD);
1122        update_period = MIN_UPDATE_PERIOD;
1123      }
1124      dprintf((stderr, "update_period: %d\n", update_period));
1125      break;
1126
1127    case CMD_resolv_period:
1128      resolv_period = get_duration(optarg);
1129      if(resolv_period < 1)
1130      {
1131        show_message("WARNING: period of %d is too short, using %d\n",
1132            resolv_period, 1);
1133        resolv_period = 1;
1134      }
1135      dprintf((stderr, "resolv_period: %d\n", resolv_period));
1136      break;
1137
1138    case CMD_quiet:
1139      options |= OPT_QUIET;
1140      dprintf((stderr, "quiet mode\n"));
1141      break;
1142
1143    case CMD_retrys:
1144      ntrys = atoi(optarg);
1145      dprintf((stderr, "ntrys: %d\n", ntrys));
1146      break;
1147
1148    case CMD_server:
1149      if(server) { free(server); }
1150      server = strdup(optarg);
1151      tmp = strchr(server, ':');
1152      if(tmp)
1153      {
1154        *tmp++ = '\0';
1155        if(port) { free(port); }
1156        port = strdup(tmp);
1157      }
1158      dprintf((stderr, "server: %s\n", server));
1159      dprintf((stderr, "port: %s\n", port));
1160      break;
1161
1162    case CMD_request:
1163      if(request_over_ride) { free(request_over_ride); }
1164      request_over_ride = strdup(optarg);
1165      dprintf((stderr, "request_over_ride: %s\n", request_over_ride));
1166      break;
1167
1168    case CMD_partner:
1169      if(partner) { free(partner); }
1170      partner = strdup(optarg);
1171      dprintf((stderr, "easyDNS partner: %s\n", partner));
1172      break;
1173
1174    case CMD_service_type:
1175      parse_service(optarg);
1176      service_set = 1;
1177      dprintf((stderr, "service_type: %s\n", service->title));
1178      dprintf((stderr, "service->name: %s\n", service->names[0]));
1179      break;
1180
1181    case CMD_user:
1182      strncpy(user, optarg, sizeof(user));
1183      user[sizeof(user)-1] = '\0';
1184      dprintf((stderr, "user: %s\n", user));
1185      tmp = strchr(optarg, ':');
1186      if(tmp)
1187      {
1188        tmp++;
1189        while(*tmp) { *tmp++ = '*'; }
1190      }
1191      break;
1192
1193    case CMD_run_as_user:
1194#if HAVE_PWD_H && HAVE_GRP_H
1195      if((pw=getpwnam(optarg)) == NULL)
1196      {
1197        i = atoi(optarg);
1198      }
1199      else
1200      {
1201        if(setgid(pw->pw_gid) != 0)
1202        {
1203          show_message("error changing group id\n");
1204        }
1205        dprintf((stderr, "GID now %d\n", pw->pw_gid));
1206        i = pw->pw_uid;
1207      }
1208      if(setuid(i) != 0)
1209      {
1210        show_message("error changing user id\n");
1211      }
1212      dprintf((stderr, "UID now %d\n", i));
1213#else
1214      show_message("option \"daemon-user\" not supported on this system\n");
1215#endif
1216      break;
1217
1218    case CMD_run_as_euser:
1219#if HAVE_PWD_H && HAVE_GRP_H && HAVE_SETEUID && HAVE_SETEGID
1220      if((pw=getpwnam(optarg)) == NULL)
1221      {
1222        i = atoi(optarg);
1223      }
1224      else
1225      {
1226        if(setegid(pw->pw_gid) != 0)
1227        {
1228          show_message("error changing group id\n");
1229        }
1230        dprintf((stderr, "GID now %d\n", pw->pw_gid));
1231        i = pw->pw_uid;
1232      }
1233      if(seteuid(i) != 0)
1234      {
1235        show_message("error changing user id\n");
1236      }
1237      dprintf((stderr, "UID now %d\n", i));
1238#else
1239      show_message("option \"daemon-euser\" not supported on this system\n");
1240#endif
1241      break;
1242
1243    case CMD_url:
1244      if(url) { free(url); }
1245      url = strdup(optarg);
1246      dprintf((stderr, "url: %s\n", url));
1247      break;
1248
1249    case CMD_wildcard:
1250      wildcard = 1;
1251      dprintf((stderr, "wildcard: %d\n", wildcard));
1252      break;
1253
1254    case CMD_cloak_title:
1255      if(cloak_title) { free(cloak_title); }
1256      cloak_title = strdup(optarg);
1257      dprintf((stderr, "cloak_title: %s\n", cloak_title));
1258      break;
1259
1260    case CMD_timeout:
1261      timeout.tv_sec = atoi(optarg);
1262      timeout.tv_usec = (atof(optarg) - timeout.tv_sec) * 1000000L;
1263      dprintf((stderr, "timeout: %ld.%06ld\n", timeout.tv_sec, timeout.tv_usec));
1264      break;
1265
1266    case CMD_connection_type:
1267      connection_type = atoi(optarg);
1268      dprintf((stderr, "connection_type: %d\n", connection_type));
1269      break;
1270
1271    case CMD_cache_file:
1272      if(cache_file) { free(cache_file); }
1273      cache_file = strdup(optarg);
1274      dprintf((stderr, "cache_file: %s\n", cache_file));
1275      break;
1276
1277    case CMD_once:
1278      options |= OPT_ONCE;
1279      dprintf((stderr, "update once only\n"));
1280      break;
1281
1282    default:
1283      dprintf((stderr, "case not handled: %d\n", id));
1284      break;
1285  }
1286
1287  return 0;
1288}
1289
1290int conf_handler(struct conf_cmd *cmd, char *arg)
1291{
1292  return(option_handler(cmd->id, arg));
1293}
1294
1295
1296#ifdef HAVE_GETOPT_LONG
1297#  define xgetopt( x1, x2, x3, x4, x5 ) getopt_long( x1, x2, x3, x4, x5 )
1298#else
1299#  define xgetopt( x1, x2, x3, x4, x5 ) getopt( x1, x2, x3 )
1300#endif
1301
1302void parse_args( int argc, char **argv )
1303{
1304#ifdef HAVE_GETOPT_LONG
1305  struct option long_options[] = {
1306//2007.03.14 Yau add
1307#ifdef ASUS_DDNS
1308      {"asus",                required_argument,      0, 'A'},
1309#endif  // ASUS_DDNS
1310      {"address",         required_argument,      0, 'a'},
1311      {"cache-file",      required_argument,      0, 'b'},
1312      {"config_file",     required_argument,      0, 'c'},
1313      {"config-file",     required_argument,      0, 'c'},
1314      {"daemon",          no_argument,            0, 'd'},
1315      {"debug",           no_argument,            0, 'D'},
1316      {"execute",         required_argument,      0, 'e'},
1317      {"foreground",      no_argument,            0, 'f'},
1318      {"pid-file",        required_argument,      0, 'F'},
1319      {"host",            required_argument,      0, 'h'},
1320      {"interface",       required_argument,      0, 'i'},
1321      {"cloak_title",     required_argument,      0, 'L'},
1322      {"mx",              required_argument,      0, 'm'},
1323      {"max-interval",    required_argument,      0, 'M'},
1324#ifdef SEND_EMAIL_CMD
1325      {"notify-email",    required_argument,      0, 'N'},
1326#endif
1327      {"resolv-period",   required_argument,      0, 'p'},
1328      {"period",          required_argument,      0, 'P'},
1329      {"quiet",           no_argument,            0, 'q'},
1330      {"retrys",          required_argument,      0, 'r'},
1331      {"run-as-user",     required_argument,      0, 'R'},
1332      {"run-as-euser",    required_argument,      0, 'Q'},
1333      {"server",          required_argument,      0, 's'},
1334      {"service-type",    required_argument,      0, 'S'},
1335      {"timeout",         required_argument,      0, 't'},
1336      {"connection-type", required_argument,      0, 'T'},
1337      {"url",             required_argument,      0, 'U'},
1338      {"user",            required_argument,      0, 'u'},
1339      {"wildcard",        no_argument,            0, 'w'},
1340      {"help",            no_argument,            0, 'H'},
1341      {"version",         no_argument,            0, 'V'},
1342      {"credits",         no_argument,            0, 'C'},
1343#ifndef EMBED
1344      {"signalhelp",      no_argument,            0, 'Z'},
1345#endif
1346      {"once",            no_argument,            0, '1'},
1347      {0,0,0,0}
1348  };
1349#else
1350#  define long_options NULL
1351#endif
1352  int opt;
1353
1354//2007.03.14 Yau add
1355#ifdef ASUS_DDNS
1356  while((opt=xgetopt(argc, argv, "A:a:b:c:dDe:fF:h:i:L:m:M:N:o:p:P:qr:R:s:S:t:T:U:u:wHVCZ", long_options, NULL)) != -1)
1357#else   // !ASUS_DDNS
1358  while((opt=xgetopt(argc, argv, "a:b:c:dDe:fF:h:i:L:m:M:N:o:p:P:qr:R:s:S:t:T:U:u:wHVCZ", long_options, NULL)) != -1)
1359#endif  // ASUS_DDNS
1360  {
1361    switch (opt)
1362    {
1363      case 'a':
1364        option_handler(CMD_address, optarg);
1365        break;
1366
1367//2007.03.14 Yau add
1368#ifdef ASUS_DDNS
1369      case 'A':
1370        option_handler(CMD_asus, optarg);
1371        break;
1372#endif  // ASUS_DDNS
1373
1374      case 'b':
1375        option_handler(CMD_cache_file, optarg);
1376        break;
1377
1378      case 'c':
1379        if(config_file) { free(config_file); }
1380        config_file = strdup(optarg);
1381        dprintf((stderr, "config_file: %s\n", config_file));
1382        if(config_file)
1383        {
1384          if(parse_conf_file(config_file, conf_commands) != 0)
1385          {
1386            show_message("error parsing config file \"%s\"\n", config_file);
1387            exit(1);
1388          }
1389        }
1390        break;
1391
1392      case 'd':
1393        option_handler(CMD_daemon, optarg);
1394        break;
1395
1396      case 'D':
1397        option_handler(CMD_debug, optarg);
1398        break;
1399
1400      case 'e':
1401        option_handler(CMD_execute, optarg);
1402        break;
1403
1404      case 'f':
1405        option_handler(CMD_foreground, optarg);
1406        break;
1407
1408      case 'F':
1409        option_handler(CMD_pid_file, optarg);
1410        break;
1411
1412      case 'g':
1413        option_handler(CMD_request, optarg);
1414        break;
1415
1416      case 'h':
1417        option_handler(CMD_host, optarg);
1418        break;
1419
1420      case 'i':
1421        option_handler(CMD_interface, optarg);
1422        break;
1423
1424      case 'L':
1425        option_handler(CMD_cloak_title, optarg);
1426        break;
1427
1428      case 'm':
1429        option_handler(CMD_mx, optarg);
1430        break;
1431
1432      case 'M':
1433        option_handler(CMD_max_interval, optarg);
1434        break;
1435
1436#ifdef SEND_EMAIL_CMD
1437      case 'N':
1438        option_handler(CMD_notify_email, optarg);
1439        break;
1440#endif
1441
1442      case 'o':
1443        option_handler(CMD_offline, optarg);
1444        break;
1445
1446      case 'p':
1447        option_handler(CMD_resolv_period, optarg);
1448        break;
1449
1450      case 'P':
1451        option_handler(CMD_period, optarg);
1452        break;
1453
1454      case 'q':
1455        option_handler(CMD_quiet, optarg);
1456        break;
1457
1458      case 'Q':
1459        option_handler(CMD_run_as_euser, optarg);
1460        break;
1461
1462      case 'r':
1463        option_handler(CMD_retrys, optarg);
1464        break;
1465
1466      case 'R':
1467        option_handler(CMD_run_as_user, optarg);
1468        break;
1469
1470      case 's':
1471        option_handler(CMD_server, optarg);
1472        break;
1473
1474      case 'S':
1475        option_handler(CMD_service_type, optarg);
1476        break;
1477
1478      case 't':
1479        option_handler(CMD_timeout, optarg);
1480        break;
1481
1482      case 'T':
1483        option_handler(CMD_connection_type, optarg);
1484        break;
1485
1486      case 'u':
1487        option_handler(CMD_user, optarg);
1488        break;
1489
1490      case 'U':
1491        option_handler(CMD_url, optarg);
1492        break;
1493
1494      case 'w':
1495        option_handler(CMD_wildcard, optarg);
1496        break;
1497
1498      case 'H':
1499        print_usage();
1500        exit(0);
1501        break;
1502
1503      case 'V':
1504        print_version();
1505        exit(0);
1506        break;
1507
1508      case 'C':
1509        print_credits();
1510        exit(0);
1511        break;
1512
1513#ifndef EMBED
1514      case 'Z':
1515        print_signalhelp();
1516        exit(0);
1517        break;
1518#endif
1519
1520      case 'z':
1521        option_handler(CMD_partner, optarg);
1522        break;
1523
1524      case '1':
1525        option_handler(CMD_once, optarg);
1526        break;
1527
1528      default:
1529#ifdef HAVE_GETOPT_LONG
1530        fprintf(stderr, "Try `%s --help' for more information\n", argv[0]);
1531#else
1532        fprintf(stderr, "Try `%s -H' for more information\n", argv[0]);
1533        fprintf(stderr, "warning: this program was compilied without getopt_long\n");
1534        fprintf(stderr, "         as such all long options will not work!\n");
1535#endif
1536        exit(1);
1537        break;
1538    }
1539  }
1540}
1541
1542/*
1543 * do_connect
1544 *
1545 * connect a socket and return the file descriptor
1546 *
1547 */
1548int do_connect(int *sock, char *host, char *port)
1549{
1550  struct sockaddr_in address;
1551  int len;
1552  int result;
1553  struct hostent *hostinfo;
1554  struct servent *servinfo;
1555
1556  // set up the socket
1557  if((*sock=socket(AF_INET, SOCK_STREAM, 0)) == -1)
1558  {
1559    if(!(options & OPT_QUIET))
1560    {
1561      perror("socket");
1562    }
1563    return(-1);
1564  }
1565  address.sin_family = AF_INET;
1566
1567  // get the host address
1568  hostinfo = gethostbyname(host);
1569  if(!hostinfo)
1570  {
1571    if(!(options & OPT_QUIET))
1572    {
1573      herror("gethostbyname");
1574    }
1575    close(*sock);
1576    return(-1);
1577  }
1578  address.sin_addr = *(struct in_addr *)*hostinfo -> h_addr_list;
1579
1580  // get the host port
1581  servinfo = getservbyname(port, "tcp");
1582  if(servinfo)
1583  {
1584    address.sin_port = servinfo -> s_port;
1585  }
1586  else
1587  {
1588    address.sin_port = htons(atoi(port));
1589  }
1590
1591  // connect the socket
1592  len = sizeof(address);
1593  if((result=connect(*sock, (struct sockaddr *)&address, len)) == -1)
1594  {
1595    if(!(options & OPT_QUIET))
1596    {
1597      perror("connect");
1598    }
1599    close(*sock);
1600    return(-1);
1601  }
1602  // print out some info
1603  if(!(options & OPT_QUIET))
1604  {
1605    show_message(
1606        "connected to %s (%s) on port %d.\n",
1607        host,
1608        inet_ntoa(address.sin_addr),
1609        ntohs(address.sin_port));
1610  }
1611
1612  return 0;
1613}
1614
1615static char table64[]=
1616  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1617void base64Encode(char *intext, char *output)
1618{
1619  unsigned char ibuf[3];
1620  unsigned char obuf[4];
1621  int i;
1622  int inputparts;
1623
1624  while(*intext) {
1625    for (i = inputparts = 0; i < 3; i++) {
1626      if(*intext) {
1627        inputparts++;
1628        ibuf[i] = *intext;
1629        intext++;
1630      }
1631      else
1632        ibuf[i] = 0;
1633    }
1634
1635    obuf [0] = (ibuf [0] & 0xFC) >> 2;
1636    obuf [1] = ((ibuf [0] & 0x03) << 4) | ((ibuf [1] & 0xF0) >> 4);
1637    obuf [2] = ((ibuf [1] & 0x0F) << 2) | ((ibuf [2] & 0xC0) >> 6);
1638    obuf [3] = ibuf [2] & 0x3F;
1639
1640    switch(inputparts) {
1641      case 1: /* only one byte read */
1642        sprintf(output, "%c%c==",
1643            table64[obuf[0]],
1644            table64[obuf[1]]);
1645        break;
1646      case 2: /* two bytes read */
1647        sprintf(output, "%c%c%c=",
1648            table64[obuf[0]],
1649            table64[obuf[1]],
1650            table64[obuf[2]]);
1651        break;
1652      default:
1653        sprintf(output, "%c%c%c%c",
1654            table64[obuf[0]],
1655            table64[obuf[1]],
1656            table64[obuf[2]],
1657            table64[obuf[3]] );
1658        break;
1659    }
1660    output += 4;
1661  }
1662  *output=0;
1663}
1664
1665#if IF_LOOKUP
1666#  if !defined(HAVE_INET_ATON)
1667#    if defined(HAVE_INET_ADDR)
1668int inet_aton(const char *cp, struct in_addr *inp)
1669{
1670  (*inp).s_addr = inet_addr(cp);
1671}
1672#  else
1673#    error "sorry, can't compile with IF_LOOKUP and no inet_aton"
1674#  endif
1675#endif
1676#endif
1677
1678void output(void *buf)
1679{
1680  fd_set writefds;
1681  int max_fd;
1682  struct timeval tv;
1683  int ret;
1684
1685  dprintf((stderr, "I say: %s\n", (char *)buf));
1686
1687  // set up our fdset and timeout
1688  FD_ZERO(&writefds);
1689  FD_SET(client_sockfd, &writefds);
1690  max_fd = client_sockfd;
1691  memcpy(&tv, &timeout, sizeof(struct timeval));
1692
1693  ret = select(max_fd + 1, NULL, &writefds, NULL, &tv);
1694  dprintf((stderr, "ret: %d\n", ret));
1695
1696  if(ret == -1)
1697  {
1698    dprintf((stderr, "select: %s\n", error_string));
1699  }
1700  else if(ret == 0)
1701  {
1702    show_message("timeout\n");
1703  }
1704  else
1705  {
1706    /* if we woke up on client_sockfd do the data passing */
1707    if(FD_ISSET(client_sockfd, &writefds))
1708    {
1709      if(send(client_sockfd, buf, strlen(buf), 0) == -1)
1710      {
1711        show_message("error send()ing request: %s\n", error_string);
1712      }
1713    }
1714    else
1715    {
1716      dprintf((stderr, "error: case not handled."));
1717    }
1718  }
1719}
1720
1721int read_input(char *buf, int len)
1722{
1723  fd_set readfds;
1724  int max_fd;
1725  struct timeval tv;
1726  int ret;
1727  int bread = -1;
1728
1729  // set up our fdset and timeout
1730  FD_ZERO(&readfds);
1731  FD_SET(client_sockfd, &readfds);
1732  max_fd = client_sockfd;
1733  memcpy(&tv, &timeout, sizeof(struct timeval));
1734
1735  ret = select(max_fd + 1, &readfds, NULL, NULL, &tv);
1736  dprintf((stderr, "ret: %d\n", ret));
1737
1738  if(ret == -1)
1739  {
1740    dprintf((stderr, "select: %s\n", error_string));
1741  }
1742  else if(ret == 0)
1743  {
1744    show_message("timeout\n");
1745  }
1746  else
1747  {
1748    /* if we woke up on client_sockfd do the data passing */
1749    if(FD_ISSET(client_sockfd, &readfds))
1750    {
1751      bread = recv(client_sockfd, buf, len-1, 0);
1752      dprintf((stderr, "bread: %d\n", bread));
1753      buf[bread] = '\0';
1754      dprintf((stderr, "got: %s\n", buf));
1755      if(bread == -1)
1756      {
1757        show_message("error recv()ing reply: %s\n", error_string);
1758      }
1759    }
1760    else
1761    {
1762      dprintf((stderr, "error: case not handled."));
1763    }
1764  }
1765
1766  return(bread);
1767}
1768
1769int get_if_addr(int sock, char *name, struct sockaddr_in *sin)
1770{
1771#ifdef IF_LOOKUP
1772  struct ifreq ifr;
1773
1774  memset(&ifr, 0, sizeof(ifr));
1775  strcpy(ifr.ifr_name, name);
1776  ifr.ifr_addr.sa_family = AF_INET;
1777  if(ioctl(sock, SIOCGIFADDR, &ifr) < 0)
1778  {
1779    perror("ioctl(SIOCGIFADDR)");
1780    memset(sin, 0, sizeof(struct sockaddr_in));
1781    dprintf((stderr, "%s: %s\n", name, "unknown interface"));
1782    return -1;
1783  }
1784
1785  if(ifr.ifr_addr.sa_family == AF_INET)
1786  {
1787    memcpy(sin, &(ifr.ifr_addr), sizeof(struct sockaddr_in));
1788    dprintf((stderr, "%s: %s\n", name, inet_ntoa(sin->sin_addr)));
1789    return 0;
1790  }
1791  else
1792  {
1793    memset(sin, 0, sizeof(struct sockaddr_in));
1794    dprintf((stderr, "%s: %s\n", name, "could not resolve interface"));
1795    return -1;
1796  }
1797  return -1;
1798#else
1799  return -1;
1800#endif
1801}
1802
1803#ifdef CONFIG_PGP
1804static int PGPOW_read_response(char *buf)
1805{
1806  int bytes;
1807
1808  bytes = read_input(buf, BUFFER_SIZE);
1809  if(bytes < 1)
1810  {
1811    close(client_sockfd);
1812    return(-1);
1813  }
1814  buf[bytes] = '\0';
1815
1816  dprintf((stderr, "server says: %s\n", buf));
1817
1818  if(strncmp("OK", buf, 2) != 0)
1819  {
1820    return(1);
1821  }
1822  else
1823  {
1824    return(0);
1825  }
1826}
1827#endif
1828
1829static int ODS_read_response(char *buf, int len)
1830{
1831  int bytes = 0;
1832  int bread = 0;
1833  char* p = buf;
1834  int max_iter = 32;
1835
1836  for(; bytes < len && max_iter > 0; max_iter--)
1837  {
1838    bread = read_input(p, len-bytes);
1839    bytes += bread;
1840    if(bytes < 1)
1841    {
1842      close(client_sockfd);
1843      return(-1);
1844    }
1845    if(strstr(buf, "\r\n") > 0)
1846    {
1847      break;
1848    }
1849
1850    dprintf((stderr, "server says: %s\n", p));
1851    p += bread;
1852  }
1853  dprintf((stderr, "server said: %s\n", buf));
1854
1855  return(atoi(buf));
1856}
1857
1858int NULL_check_info(void)
1859{
1860  char buf[64];
1861
1862  if(options & OPT_DAEMON)
1863  {
1864    show_message("no compile time default service was set therefor you must "
1865        "specify a service type.\n");
1866
1867    return(-1);
1868  }
1869  get_input("service", buf, sizeof(buf));
1870  option_handler(CMD_service_type, buf);
1871
1872  return(0);
1873}
1874
1875int EZIP_check_info(void)
1876{
1877  warn_fields(service->fields_used);
1878
1879  return 0;
1880}
1881
1882int EZIP_update_entry(void)
1883{
1884  char *buf = update_entry_buf;
1885  char *bp;
1886  int bytes;
1887  int btot;
1888  int ret;
1889
1890  buf[BUFFER_SIZE] = '\0';
1891
1892  if(do_connect((int*)&client_sockfd, server, port) != 0)
1893  {
1894    if(!(options & OPT_QUIET))
1895    {
1896      show_message("error connecting to %s:%s\n", server, port);
1897    }
1898    return(UPDATERES_ERROR);
1899  }
1900
1901  snprintf(buf, BUFFER_SIZE, "GET %s?mode=update&", request);
1902  output(buf);
1903  if(address)
1904  {
1905    snprintf(buf, BUFFER_SIZE, "%s=%s&", "ipaddress", address);
1906    output(buf);
1907  }
1908  snprintf(buf, BUFFER_SIZE, "%s=%s&", "wildcard", wildcard ? "yes" : "no");
1909  output(buf);
1910  snprintf(buf, BUFFER_SIZE, "%s=%s&", "mx", mx);
1911  output(buf);
1912  snprintf(buf, BUFFER_SIZE, "%s=%s&", "url", url);
1913  output(buf);
1914  snprintf(buf, BUFFER_SIZE, "%s=%s&", "host", host);
1915  output(buf);
1916  snprintf(buf, BUFFER_SIZE, " HTTP/1.0\015\012");
1917  output(buf);
1918  snprintf(buf, BUFFER_SIZE, "Authorization: Basic %s\015\012", auth);
1919  output(buf);
1920  snprintf(buf, BUFFER_SIZE, "User-Agent: %s-%s %s [%s] (%s)\015\012",
1921      "ez-update", VERSION, OS, (options & OPT_DAEMON) ? "daemon" : "", "by Angus Mackay");
1922  output(buf);
1923  snprintf(buf, BUFFER_SIZE, "Host: %s\015\012", server);
1924  output(buf);
1925  snprintf(buf, BUFFER_SIZE, "\015\012");
1926  output(buf);
1927
1928  bp = buf;
1929  bytes = 0;
1930  btot = 0;
1931  while((bytes=read_input(bp, BUFFER_SIZE-btot)) > 0)
1932  {
1933    bp += bytes;
1934    btot += bytes;
1935    dprintf((stderr, "btot: %d\n", btot));
1936  }
1937  close(client_sockfd);
1938  buf[btot] = '\0';
1939
1940  dprintf((stderr, "server output: %s\n", buf));
1941
1942  if(sscanf(buf, " HTTP/1.%*c %3d", &ret) != 1)
1943  {
1944    ret = -1;
1945  }
1946
1947  switch(ret)
1948  {
1949    case -1:
1950      if(!(options & OPT_QUIET))
1951      {
1952        show_message("strange server response, are you connecting to the right server?\n");
1953      }
1954      return(UPDATERES_ERROR);
1955      break;
1956
1957    case 200:
1958      if(!(options & OPT_QUIET))
1959      {
1960        show_message("request successful\n");
1961      }
1962      break;
1963
1964    case 401:
1965      if(!(options & OPT_QUIET))
1966      {
1967        show_message("authentication failure\n");
1968      }
1969      return(UPDATERES_SHUTDOWN);
1970      break;
1971
1972    default:
1973      if(!(options & OPT_QUIET))
1974      {
1975        // reuse the auth buffer
1976        *auth = '\0';
1977        sscanf(buf, " HTTP/1.%*c %*3d %255[^\r\n]", auth);
1978        show_message("unknown return code: %d\n", ret);
1979        show_message("server response: %s\n", auth);
1980      }
1981      return(UPDATERES_ERROR);
1982      break;
1983  }
1984
1985  return(UPDATERES_OK);
1986}
1987
1988void DYNDNS_init(void)
1989{
1990
1991  if(options & OPT_DAEMON)
1992  {
1993    if(!(max_interval > 0))
1994    {
1995      max_interval = DYNDNS_MAX_INTERVAL;
1996    }
1997  }
1998}
1999
2000int DYNDNS_check_info(void)
2001{
2002  char buf[BUFSIZ+1];
2003
2004  if((host == NULL) || (*host == '\0'))
2005  {
2006    if(options & OPT_DAEMON)
2007    {
2008      return(-1);
2009    }
2010    if(host) { free(host); }
2011    get_input("host", buf, sizeof(buf));
2012    host = strdup(buf);
2013  }
2014
2015  if(address != NULL && !is_dotted_quad(address))
2016  {
2017    show_message("the IP address \"%s\" is invalid\n", address);
2018    return(-1);
2019  }
2020
2021  if(interface == NULL && address == NULL)
2022  {
2023    if(options & OPT_DAEMON)
2024    {
2025      show_message("you must provide either an interface or an address\n");
2026      return(-1);
2027    }
2028    if(interface) { free(interface); }
2029    get_input("interface", buf, sizeof(buf));
2030    option_handler(CMD_interface, buf);
2031  }
2032
2033  warn_fields(service->fields_used);
2034
2035  return 0;
2036}
2037
2038int DYNDNS_update_entry(void)
2039{
2040  char *buf = update_entry_buf;
2041  char *bp = buf;
2042  int bytes;
2043  int btot;
2044  int ret;
2045  int retval = UPDATERES_OK;
2046
2047  buf[BUFFER_SIZE] = '\0';
2048
2049  if(do_connect((int*)&client_sockfd, server, port) != 0)
2050  {
2051    if(!(options & OPT_QUIET))
2052    {
2053      show_message("error connecting to %s:%s\n", server, port);
2054    }
2055    return(UPDATERES_ERROR);
2056  }
2057
2058  snprintf(buf, BUFFER_SIZE, "GET %s?", request);
2059  output(buf);
2060
2061  if(is_in_list("dyndns-static", service->names))
2062  {
2063    snprintf(buf, BUFFER_SIZE, "%s=%s&", "system", "statdns");
2064    output(buf);
2065  }
2066  else if(is_in_list("dyndns-custom", service->names))
2067  {
2068    snprintf(buf, BUFFER_SIZE, "%s=%s&", "system", "custom");
2069    output(buf);
2070  }
2071
2072  snprintf(buf, BUFFER_SIZE, "%s=%s&", "hostname", host);
2073  output(buf);
2074  if(address != NULL)
2075  {
2076    snprintf(buf, BUFFER_SIZE, "%s=%s&", "myip", address);
2077    output(buf);
2078  }
2079  snprintf(buf, BUFFER_SIZE, "%s=%s&", "wildcard", wildcard ? "ON" : "OFF");
2080  output(buf);
2081  if(mx != NULL && *mx != '\0')
2082  {
2083    snprintf(buf, BUFFER_SIZE, "%s=%s&", "mx", mx);
2084    output(buf);
2085  }
2086  //snprintf(buf, BUFFER_SIZE, "%s=%s&", "backmx", "NO");
2087  //output(buf);
2088  if(options & OPT_OFFLINE)
2089  {
2090    snprintf(buf, BUFFER_SIZE, "%s=%s&", "offline", "yes");
2091    output(buf);
2092  }
2093  snprintf(buf, BUFFER_SIZE, " HTTP/1.0\015\012");
2094  output(buf);
2095  snprintf(buf, BUFFER_SIZE, "Authorization: Basic %s\015\012", auth);
2096  output(buf);
2097  snprintf(buf, BUFFER_SIZE, "User-Agent: %s-%s %s [%s] (%s)\015\012",
2098      "ez-update", VERSION, OS, (options & OPT_DAEMON) ? "daemon" : "", "by Angus Mackay");
2099  output(buf);
2100  snprintf(buf, BUFFER_SIZE, "Host: %s\015\012", server);
2101  output(buf);
2102  snprintf(buf, BUFFER_SIZE, "\015\012");
2103  output(buf);
2104
2105  bp = buf;
2106  bytes = 0;
2107  btot = 0;
2108  while((bytes=read_input(bp, BUFFER_SIZE-btot)) > 0)
2109  {
2110    bp += bytes;
2111    btot += bytes;
2112    dprintf((stderr, "btot: %d\n", btot));
2113  }
2114  close(client_sockfd);
2115  buf[btot] = '\0';
2116
2117  dprintf((stderr, "server output: %s\n", buf));
2118
2119  if(sscanf(buf, " HTTP/1.%*c %3d", &ret) != 1)
2120  {
2121    ret = -1;
2122  }
2123
2124  switch(ret)
2125  {
2126    case -1:
2127      if(!(options & OPT_QUIET))
2128      {
2129        show_message("strange server response, are you connecting to the right server?\n");
2130      }
2131      retval = UPDATERES_ERROR;
2132      break;
2133
2134    case 200:
2135      if(strstr(buf, "\ngood ") != NULL)
2136      {
2137        if(!(options & OPT_QUIET))
2138        {
2139          show_message("request successful\n");
2140        }
2141      }
2142      else
2143      {
2144        if(strstr(buf, "\nnohost") != NULL)
2145        {
2146          show_message("invalid hostname: %s\n", host);
2147          retval = UPDATERES_SHUTDOWN;
2148        }
2149        else if(strstr(buf, "\nnotfqdn") != NULL)
2150        {
2151          show_message("malformed hostname: %s\n", host);
2152          retval = UPDATERES_SHUTDOWN;
2153        }
2154        else if(strstr(buf, "\n!yours") != NULL)
2155        {
2156          show_message("host \"%s\" is not under your control\n", host);
2157          retval = UPDATERES_SHUTDOWN;
2158        }
2159        else if(strstr(buf, "\nabuse") != NULL)
2160        {
2161          show_message("host \"%s\" has been blocked for abuse\n", host);
2162          retval = UPDATERES_SHUTDOWN;
2163        }
2164        else if(strstr(buf, "\nnochg") != NULL)
2165        {
2166          show_message("%s says that your IP address has not changed since the last update\n", server);
2167          // lets say that this counts as a successful update
2168          // but we'll roll back the last update time to max_interval/2
2169          if(max_interval > 0)
2170          {
2171            last_update = time(NULL) - max_interval/2;
2172          }
2173          retval = UPDATERES_OK;
2174        }
2175        else if(strstr(buf, "\nbadauth") != NULL)
2176        {
2177          show_message("authentication failure\n");
2178          retval = UPDATERES_SHUTDOWN;
2179        }
2180        else if(strstr(buf, "\nbadsys") != NULL)
2181        {
2182          show_message("invalid system parameter\n");
2183          retval = UPDATERES_SHUTDOWN;
2184        }
2185        else if(strstr(buf, "\nbadagent") != NULL)
2186        {
2187          show_message("this useragent has been blocked\n");
2188          retval = UPDATERES_SHUTDOWN;
2189        }
2190        else if(strstr(buf, "\nnumhost") != NULL)
2191        {
2192          show_message("Too many or too few hosts found\n");
2193          retval = UPDATERES_SHUTDOWN;
2194        }
2195        else if(strstr(buf, "\ndnserr") != NULL)
2196        {
2197          char *p = strstr(buf, "\ndnserr");
2198          show_message("dyndns internal error, please report this number to "
2199              "their support people: %s\n", N_STR(p));
2200          retval = UPDATERES_ERROR;
2201        }
2202        else if(strstr(buf, "\n911") != NULL)
2203        {
2204          show_message("Ahhhh! call 911!\n");
2205          retval = UPDATERES_SHUTDOWN;
2206        }
2207        else if(strstr(buf, "\n999") != NULL)
2208        {
2209          show_message("Ahhhh! call 999!\n");
2210          retval = UPDATERES_SHUTDOWN;
2211        }
2212        else if(strstr(buf, "\n!donator") != NULL)
2213        {
2214          show_message("a feature requested is only available to donators, please donate.\n", host);
2215          retval = UPDATERES_OK;
2216        }
2217        // this one should be last as it is a stupid string to signify waits
2218        // with as it is so short
2219        else if(strstr(buf, "\nw") != NULL)
2220        {
2221          int howlong = 0;
2222          char *p = strstr(buf, "\nw");
2223          char reason[256];
2224          char mult;
2225
2226          // get time and reason
2227          if(strlen(p) >= 2)
2228          {
2229            sscanf(p, "%d%c %255[^\r\n]", &howlong, &mult, reason);
2230            if(mult == 'h')
2231            {
2232              howlong *= 3600;
2233            }
2234            else if(mult == 'm')
2235            {
2236              howlong *= 60;
2237            }
2238            if(howlong > MAX_WAITRESPONSE_WAIT)
2239            {
2240              howlong = MAX_WAITRESPONSE_WAIT;
2241            };
2242          }
2243          else
2244          {
2245            sprintf(reason, "problem parsing reason for wait response");
2246          }
2247
2248          show_message("Wait response received, waiting for %s before next update.\n",
2249              format_time(howlong));
2250          show_message("Wait response reason: %d\n", N_STR(reason));
2251          sleep(howlong);
2252          retval = UPDATERES_ERROR;
2253        }
2254        else
2255        {
2256          show_message("error processing request\n");
2257          if(!(options & OPT_QUIET))
2258          {
2259            show_message("server output: %s\n", buf);
2260          }
2261          retval = UPDATERES_ERROR;
2262        }
2263      }
2264      break;
2265
2266    case 401:
2267      if(!(options & OPT_QUIET))
2268      {
2269        show_message("authentication failure\n");
2270      }
2271      retval = UPDATERES_SHUTDOWN;
2272      break;
2273
2274    default:
2275      if(!(options & OPT_QUIET))
2276      {
2277        // reuse the auth buffer
2278        *auth = '\0';
2279        sscanf(buf, " HTTP/1.%*c %*3d %255[^\r\n]", auth);
2280        show_message("unknown return code: %d\n", ret);
2281        show_message("server response: %s\n", auth);
2282      }
2283      retval = UPDATERES_ERROR;
2284      break;
2285  }
2286
2287  return(retval);
2288}
2289
2290#ifdef CONFIG_PGP
2291int PGPOW_check_info(void)
2292{
2293  char buf[BUFSIZ+1];
2294
2295  if((host == NULL) || (*host == '\0'))
2296  {
2297    if(options & OPT_DAEMON)
2298    {
2299      return(-1);
2300    }
2301    if(host) { free(host); }
2302    get_input("host", buf, sizeof(buf));
2303    host = strdup(buf);
2304  }
2305
2306  if(interface == NULL && address == NULL)
2307  {
2308    if(options & OPT_DAEMON)
2309    {
2310      show_message("you must provide either an interface or an address\n");
2311      return(-1);
2312    }
2313    if(interface) { free(interface); }
2314    get_input("interface", buf, sizeof(buf));
2315    option_handler(CMD_interface, buf);
2316  }
2317
2318  warn_fields(service->fields_used);
2319
2320  return 0;
2321}
2322
2323int PGPOW_update_entry(void)
2324{
2325  char *buf = update_entry_buf;
2326
2327  buf[BUFFER_SIZE] = '\0';
2328
2329  if(do_connect((int*)&client_sockfd, server, port) != 0)
2330  {
2331    if(!(options & OPT_QUIET))
2332    {
2333      show_message("error connecting to %s:%s\n", server, port);
2334    }
2335    return(UPDATERES_ERROR);
2336  }
2337
2338  /* read server message */
2339  if(PGPOW_read_response(buf) != 0)
2340  {
2341    show_message("strange server response, are you connecting to the right server?\n");
2342    close(client_sockfd);
2343    return(UPDATERES_ERROR);
2344  }
2345
2346  /* send version command */
2347  snprintf(buf, BUFFER_SIZE, "VER %s [%s-%s %s (%s)]\015\012", PGPOW_VERSION,
2348      "ez-update", VERSION, OS, "by Angus Mackay");
2349  output(buf);
2350
2351  if(PGPOW_read_response(buf) != 0)
2352  {
2353    if(strncmp("ERR", buf, 3) == 0)
2354    {
2355      show_message("error talking to server: %s\n", &(buf[3]));
2356    }
2357    else
2358    {
2359      show_message("error talking to server:\n\t%s\n", buf);
2360    }
2361    close(client_sockfd);
2362    return(UPDATERES_ERROR);
2363  }
2364
2365  /* send user command */
2366  snprintf(buf, BUFFER_SIZE, "USER %s\015\012", user_name);
2367  output(buf);
2368
2369  if(PGPOW_read_response(buf) != 0)
2370  {
2371    if(strncmp("ERR", buf, 3) == 0)
2372    {
2373      show_message("error talking to server: %s\n", &(buf[3]));
2374    }
2375    else
2376    {
2377      show_message("error talking to server:\n\t%s\n", buf);
2378    }
2379    close(client_sockfd);
2380    return(UPDATERES_ERROR);
2381  }
2382
2383  /* send pass command */
2384  snprintf(buf, BUFFER_SIZE, "PASS %s\015\012", password);
2385  output(buf);
2386
2387  if(PGPOW_read_response(buf) != 0)
2388  {
2389    if(strncmp("ERR", buf, 3) == 0)
2390    {
2391      show_message("error talking to server: %s\n", &(buf[3]));
2392    }
2393    else
2394    {
2395      show_message("error talking to server:\n\t%s\n", buf);
2396    }
2397    close(client_sockfd);
2398    return(UPDATERES_ERROR);
2399  }
2400
2401  /* send host command */
2402  snprintf(buf, BUFFER_SIZE, "HOST %s\015\012", host);
2403  output(buf);
2404
2405  if(PGPOW_read_response(buf) != 0)
2406  {
2407    if(strncmp("ERR", buf, 3) == 0)
2408    {
2409      show_message("error talking to server: %s\n", &(buf[3]));
2410    }
2411    else
2412    {
2413      show_message("error talking to server:\n\t%s\n", buf);
2414    }
2415    close(client_sockfd);
2416    return(UPDATERES_ERROR);
2417  }
2418
2419  /* send oper command */
2420  snprintf(buf, BUFFER_SIZE, "OPER %s\015\012", request);
2421  output(buf);
2422
2423  if(PGPOW_read_response(buf) != 0)
2424  {
2425    if(strncmp("ERR", buf, 3) == 0)
2426    {
2427      show_message("error talking to server: %s\n", &(buf[3]));
2428    }
2429    else
2430    {
2431      show_message("error talking to server:\n\t%s\n", buf);
2432    }
2433    close(client_sockfd);
2434    return(UPDATERES_ERROR);
2435  }
2436
2437  if(strcmp("update", request) == 0)
2438  {
2439    /* send ip command */
2440    snprintf(buf, BUFFER_SIZE, "IP %s\015\012", address);
2441    output(buf);
2442
2443    if(PGPOW_read_response(buf) != 0)
2444    {
2445      if(strncmp("ERR", buf, 3) == 0)
2446      {
2447        show_message("error talking to server: %s\n", &(buf[3]));
2448      }
2449      else
2450      {
2451        show_message("error talking to server:\n\t%s\n", buf);
2452      }
2453      close(client_sockfd);
2454      return(UPDATERES_ERROR);
2455    }
2456  }
2457
2458  /* send done command */
2459  snprintf(buf, BUFFER_SIZE, "DONE\015\012");
2460  output(buf);
2461
2462  if(PGPOW_read_response(buf) != 0)
2463  {
2464    if(strncmp("ERR", buf, 3) == 0)
2465    {
2466      show_message("error talking to server: %s\n", &(buf[3]));
2467    }
2468    else
2469    {
2470      show_message("error talking to server:\n\t%s\n", buf);
2471    }
2472    close(client_sockfd);
2473    return(UPDATERES_ERROR);
2474  }
2475
2476  if(!(options & OPT_QUIET))
2477  {
2478    show_message("request successful\n");
2479  }
2480
2481  close(client_sockfd);
2482  return(UPDATERES_OK);
2483}
2484#endif
2485
2486#ifdef CONFIG_DHS
2487int DHS_check_info(void)
2488{
2489  char buf[BUFSIZ+1];
2490
2491  if((host == NULL) || (*host == '\0'))
2492  {
2493    if(options & OPT_DAEMON)
2494    {
2495      return(-1);
2496    }
2497    if(host) { free(host); }
2498    get_input("host", buf, sizeof(buf));
2499    host = strdup(buf);
2500  }
2501
2502  if(interface == NULL && address == NULL)
2503  {
2504    if(options & OPT_DAEMON)
2505    {
2506      show_message("you must provide either an interface or an address\n");
2507      return(-1);
2508    }
2509    if(interface) { free(interface); }
2510    get_input("interface", buf, sizeof(buf));
2511    option_handler(CMD_interface, buf);
2512  }
2513
2514  warn_fields(service->fields_used);
2515
2516  return 0;
2517}
2518
2519/*
2520 * grrrrr, it seems that dhs.org requires us to use POST
2521 * also DHS doesn't update both the mx record and the address at the same
2522 * time, this service really stinks. go with justlinix.com (penguinpowered)
2523 * instead, the only advantage is short host names.
2524 */
2525int DHS_update_entry(void)
2526{
2527  char *buf = update_entry_buf;
2528  char *putbuf = update_entry_putbuf;
2529  char *bp = buf;
2530  int bytes;
2531  int btot;
2532  int ret;
2533  char *domain = NULL;
2534  char *hostname = NULL;
2535  char *p;
2536  int limit;
2537  int retval = UPDATERES_OK;
2538
2539  buf[BUFFER_SIZE] = '\0';
2540  putbuf[BUFFER_SIZE] = '\0';
2541
2542  /* parse apart the domain and hostname */
2543  hostname = strdup(host);
2544  if((p=strchr(hostname, '.')) == NULL)
2545  {
2546    if(!(options & OPT_QUIET))
2547    {
2548      show_message("error parsing hostname from host %s\n", host);
2549    }
2550    return(UPDATERES_ERROR);
2551  }
2552  *p = '\0';
2553  p++;
2554  if(*p == '\0')
2555  {
2556    if(!(options & OPT_QUIET))
2557    {
2558      show_message("error parsing domain from host %s\n", host);
2559    }
2560    return(UPDATERES_ERROR);
2561  }
2562  domain = strdup(p);
2563
2564  dprintf((stderr, "hostname: %s, domain: %s\n", hostname, domain));
2565
2566  if(do_connect((int*)&client_sockfd, server, port) != 0)
2567  {
2568    if(!(options & OPT_QUIET))
2569    {
2570      show_message("error connecting to %s:%s\n", server, port);
2571    }
2572    return(UPDATERES_ERROR);
2573  }
2574
2575  snprintf(buf, BUFFER_SIZE, "POST %s HTTP/1.0\015\012", request);
2576  output(buf);
2577  snprintf(buf, BUFFER_SIZE, "Authorization: Basic %s\015\012", auth);
2578  output(buf);
2579  snprintf(buf, BUFFER_SIZE, "User-Agent: %s-%s %s [%s] (%s)\015\012",
2580      "ez-update", VERSION, OS, (options & OPT_DAEMON) ? "daemon" : "", "by Angus Mackay");
2581  output(buf);
2582  snprintf(buf, BUFFER_SIZE, "Host: %s\015\012", server);
2583  output(buf);
2584
2585  p = putbuf;
2586  *p = '\0';
2587  limit = BUFFER_SIZE - 1 - strlen(buf);
2588  snprintf(p, limit, "hostscmd=edit&hostscmdstage=2&type=4&");
2589  p += strlen(p);
2590  limit = BUFFER_SIZE - 1 - strlen(buf);
2591  snprintf(p, limit, "%s=%s&", "updatetype", "Online");
2592  p += strlen(p);
2593  limit = BUFFER_SIZE - 1 - strlen(buf);
2594  snprintf(p, limit, "%s=%s&", "ip", address);
2595  p += strlen(p);
2596  limit = BUFFER_SIZE - 1 - strlen(buf);
2597  snprintf(p, limit, "%s=%s&", "mx", mx);
2598  p += strlen(p);
2599  limit = BUFFER_SIZE - 1 - strlen(buf);
2600  snprintf(p, limit, "%s=%s&", "offline_url", url);
2601  p += strlen(p);
2602  limit = BUFFER_SIZE - 1 - strlen(buf);
2603  if(cloak_title)
2604  {
2605    snprintf(p, limit, "%s=%s&", "cloak", "Y");
2606    p += strlen(p);
2607    limit = BUFFER_SIZE - 1 - strlen(buf);
2608    snprintf(p, limit, "%s=%s&", "cloak_title", cloak_title);
2609    p += strlen(p);
2610    limit = BUFFER_SIZE - 1 - strlen(buf);
2611  }
2612  else
2613  {
2614    snprintf(p, limit, "%s=%s&", "cloak_title", "");
2615    p += strlen(p);
2616    limit = BUFFER_SIZE - 1 - strlen(buf);
2617  }
2618  snprintf(p, limit, "%s=%s&", "submit", "Update");
2619  p += strlen(p);
2620  limit = BUFFER_SIZE - 1 - strlen(buf);
2621  snprintf(p, limit, "%s=%s&", "domain", domain);
2622  p += strlen(p);
2623  limit = BUFFER_SIZE - 1 - strlen(buf);
2624  snprintf(p, limit, "%s=%s", "hostname", hostname);
2625  p += strlen(p);
2626  limit = BUFFER_SIZE - 1 - strlen(buf);
2627
2628  snprintf(buf, BUFFER_SIZE, "Content-length: %d\015\012", strlen(putbuf));
2629  output(buf);
2630  snprintf(buf, BUFFER_SIZE, "\015\012");
2631  output(buf);
2632
2633  output(putbuf);
2634  snprintf(buf, BUFFER_SIZE, "\015\012");
2635  output(buf);
2636
2637  bp = buf;
2638  bytes = 0;
2639  btot = 0;
2640  while((bytes=read_input(bp, BUFFER_SIZE-btot)) > 0)
2641  {
2642    bp += bytes;
2643    btot += bytes;
2644    dprintf((stderr, "btot: %d\n", btot));
2645  }
2646  close(client_sockfd);
2647  buf[btot] = '\0';
2648
2649  dprintf((stderr, "server output: %s\n", buf));
2650
2651  if(sscanf(buf, " HTTP/1.%*c %3d", &ret) != 1)
2652  {
2653    ret = -1;
2654  }
2655
2656  switch(ret)
2657  {
2658    case -1:
2659      if(!(options & OPT_QUIET))
2660      {
2661        show_message("strange server response, are you connecting to the right server?\n");
2662      }
2663      retval = UPDATERES_ERROR;
2664      break;
2665
2666    case 200:
2667      if(!(options & OPT_QUIET))
2668      {
2669        show_message("request successful\n");
2670      }
2671      break;
2672
2673    case 401:
2674      if(!(options & OPT_QUIET))
2675      {
2676        show_message("authentication failure\n");
2677      }
2678      retval = UPDATERES_SHUTDOWN;
2679      break;
2680
2681    default:
2682      if(!(options & OPT_QUIET))
2683      {
2684        // reuse the auth buffer
2685        *auth = '\0';
2686        sscanf(buf, " HTTP/1.%*c %*3d %255[^\r\n]", auth);
2687        show_message("unknown return code: %d\n", ret);
2688        show_message("server response: %s\n", auth);
2689      }
2690      retval = UPDATERES_ERROR;
2691      break;
2692  }
2693
2694  // this stupid service requires us to do seperate request if we want to
2695  // update the mail exchanger (mx). grrrrrr
2696  if(*mx != '\0')
2697  {
2698    // okay, dhs's service is incredibly stupid and will not work with two
2699    // requests right after each other. I could care less that this is ugly,
2700    // I personally will NEVER use dhs, it is laughable.
2701    sleep(DHS_SUCKY_TIMEOUT < timeout.tv_sec ? DHS_SUCKY_TIMEOUT : timeout.tv_sec);
2702
2703    if(do_connect((int*)&client_sockfd, server, port) != 0)
2704    {
2705      if(!(options & OPT_QUIET))
2706      {
2707        show_message("error connecting to %s:%s\n", server, port);
2708      }
2709      return(UPDATERES_ERROR);
2710    }
2711
2712    snprintf(buf, BUFFER_SIZE, "POST %s HTTP/1.0\015\012", request);
2713    output(buf);
2714    snprintf(buf, BUFFER_SIZE, "Authorization: Basic %s\015\012", auth);
2715    output(buf);
2716    snprintf(buf, BUFFER_SIZE, "User-Agent: %s-%s %s [%s] (%s)\015\012",
2717        "ez-update", VERSION, OS, (options & OPT_DAEMON) ? "daemon" : "", "by Angus Mackay");
2718    output(buf);
2719    snprintf(buf, BUFFER_SIZE, "Host: %s\015\012", server);
2720    output(buf);
2721
2722    p = putbuf;
2723    *p = '\0';
2724    limit = BUFFER_SIZE - 1 - strlen(buf);
2725    snprintf(p, limit, "hostscmd=edit&hostscmdstage=2&type=4&");
2726    p += strlen(p);
2727    limit = BUFFER_SIZE - 1 - strlen(buf);
2728    snprintf(p, limit, "%s=%s&", "updatetype", "Update+Mail+Exchanger");
2729    p += strlen(p);
2730    limit = BUFFER_SIZE - 1 - strlen(buf);
2731    snprintf(p, limit, "%s=%s&", "ip", address);
2732    p += strlen(p);
2733    limit = BUFFER_SIZE - 1 - strlen(buf);
2734    snprintf(p, limit, "%s=%s&", "mx", mx);
2735    p += strlen(p);
2736    limit = BUFFER_SIZE - 1 - strlen(buf);
2737    snprintf(p, limit, "%s=%s&", "offline_url", url);
2738    p += strlen(p);
2739    limit = BUFFER_SIZE - 1 - strlen(buf);
2740    if(cloak_title)
2741    {
2742      snprintf(p, limit, "%s=%s&", "cloak", "Y");
2743      p += strlen(p);
2744      limit = BUFFER_SIZE - 1 - strlen(buf);
2745      snprintf(p, limit, "%s=%s&", "cloak_title", cloak_title);
2746      p += strlen(p);
2747      limit = BUFFER_SIZE - 1 - strlen(buf);
2748    }
2749    else
2750    {
2751      snprintf(p, limit, "%s=%s&", "cloak_title", "");
2752      p += strlen(p);
2753      limit = BUFFER_SIZE - 1 - strlen(buf);
2754    }
2755    snprintf(p, limit, "%s=%s&", "submit", "Update");
2756    p += strlen(p);
2757    limit = BUFFER_SIZE - 1 - strlen(buf);
2758    snprintf(p, limit, "%s=%s&", "domain", domain);
2759    p += strlen(p);
2760    limit = BUFFER_SIZE - 1 - strlen(buf);
2761    snprintf(p, limit, "%s=%s", "hostname", hostname);
2762    p += strlen(p);
2763    limit = BUFFER_SIZE - 1 - strlen(buf);
2764
2765    snprintf(buf, BUFFER_SIZE, "Content-length: %d\015\012", strlen(putbuf));
2766    output(buf);
2767    snprintf(buf, BUFFER_SIZE, "\015\012");
2768    output(buf);
2769
2770    output(putbuf);
2771    snprintf(buf, BUFFER_SIZE, "\015\012");
2772    output(buf);
2773
2774    bp = buf;
2775    bytes = 0;
2776    btot = 0;
2777    while((bytes=read_input(bp, BUFFER_SIZE-btot)) > 0)
2778    {
2779      bp += bytes;
2780      btot += bytes;
2781      dprintf((stderr, "btot: %d\n", btot));
2782    }
2783    close(client_sockfd);
2784    buf[btot] = '\0';
2785
2786    dprintf((stderr, "server output: %s\n", buf));
2787
2788    if(sscanf(buf, " HTTP/1.%*c %3d", &ret) != 1)
2789    {
2790      ret = -1;
2791    }
2792
2793    switch(ret)
2794    {
2795      case -1:
2796        if(!(options & OPT_QUIET))
2797        {
2798          show_message("strange server response, are you connecting to the right server?\n");
2799        }
2800        retval = UPDATERES_ERROR;
2801        break;
2802
2803      case 200:
2804        if(!(options & OPT_QUIET))
2805        {
2806          show_message("request successful\n");
2807        }
2808        break;
2809
2810      case 401:
2811        if(!(options & OPT_QUIET))
2812        {
2813          show_message("authentication failure\n");
2814        }
2815        retval = UPDATERES_SHUTDOWN;
2816        break;
2817
2818      default:
2819        if(!(options & OPT_QUIET))
2820        {
2821          // reuse the auth buffer
2822          *auth = '\0';
2823          sscanf(buf, " HTTP/1.%*c %*3d %255[^\r\n]", auth);
2824          show_message("unknown return code: %d\n", ret);
2825          show_message("server response: %s\n", auth);
2826        }
2827        retval = UPDATERES_ERROR;
2828        break;
2829    }
2830  }
2831
2832  return(retval);
2833}
2834#endif
2835
2836#ifdef CONFIG_ODS
2837int ODS_check_info(void)
2838{
2839  char buf[BUFSIZ+1];
2840
2841  if((host == NULL) || (*host == '\0'))
2842  {
2843    if(options & OPT_DAEMON)
2844    {
2845      return(-1);
2846    }
2847    if(host) { free(host); }
2848    get_input("host", buf, sizeof(buf));
2849    host = strdup(buf);
2850  }
2851
2852  if(interface == NULL && address == NULL)
2853  {
2854    if(options & OPT_DAEMON)
2855    {
2856      show_message("you must provide either an interface or an address\n");
2857      return(-1);
2858    }
2859    if(address) { free(address); }
2860    address = strdup("");
2861  }
2862
2863  warn_fields(service->fields_used);
2864
2865  return 0;
2866}
2867
2868int ODS_update_entry(void)
2869{
2870  char *buf = update_entry_buf;
2871  int response;
2872
2873  buf[BUFFER_SIZE] = '\0';
2874
2875  if(do_connect((int*)&client_sockfd, server, port) != 0)
2876  {
2877    if(!(options & OPT_QUIET))
2878    {
2879      show_message("error connecting to %s:%s\n", server, port);
2880    }
2881    return(UPDATERES_ERROR);
2882  }
2883
2884  /* read server message */
2885  if(ODS_read_response(buf, BUFFER_SIZE) != 100)
2886  {
2887    show_message("strange server response, are you connecting to the right server?\n");
2888    close(client_sockfd);
2889    return(UPDATERES_ERROR);
2890  }
2891
2892  /* send login command */
2893  snprintf(buf, BUFFER_SIZE, "LOGIN %s %s\012", user_name, password);
2894  output(buf);
2895
2896  response = ODS_read_response(buf, BUFFER_SIZE);
2897  if(!(response == 225 || response == 226))
2898  {
2899    if(strlen(buf) > 4)
2900    {
2901      show_message("error talking to server: %s\n", &(buf[4]));
2902    }
2903    else
2904    {
2905      show_message("error talking to server\n");
2906    }
2907    close(client_sockfd);
2908    return(UPDATERES_ERROR);
2909  }
2910
2911  /* send delete command */
2912  snprintf(buf, BUFFER_SIZE, "DELRR %s A\012", host);
2913  output(buf);
2914
2915  if(ODS_read_response(buf, BUFFER_SIZE) != 901)
2916  {
2917    if(strlen(buf) > 4)
2918    {
2919      show_message("error talking to server: %s\n", &(buf[4]));
2920    }
2921    else
2922    {
2923      show_message("error talking to server\n");
2924    }
2925    close(client_sockfd);
2926    return(UPDATERES_ERROR);
2927  }
2928
2929  /* send address command */
2930  snprintf(buf, BUFFER_SIZE, "ADDRR %s A %s\012", host,
2931                *address == '\0' ? "CONNIP" :  address);
2932  output(buf);
2933
2934  response = ODS_read_response(buf, BUFFER_SIZE);
2935  if(!(response == 795 || response == 796))
2936  {
2937    if(strlen(buf) > 4)
2938    {
2939      show_message("error talking to server: %s\n", &(buf[4]));
2940    }
2941    else
2942    {
2943      show_message("error talking to server\n");
2944    }
2945    close(client_sockfd);
2946    return(UPDATERES_ERROR);
2947  }
2948
2949  if(!(options & OPT_QUIET))
2950  {
2951    show_message("request successful\n");
2952  }
2953
2954  close(client_sockfd);
2955  return(UPDATERES_OK);
2956}
2957#endif
2958
2959int TZO_check_info(void)
2960{
2961  char buf[BUFSIZ+1];
2962
2963  if((host == NULL) || (*host == '\0'))
2964  {
2965    if(options & OPT_DAEMON)
2966    {
2967      return(-1);
2968    }
2969    if(host) { free(host); }
2970    get_input("host", buf, sizeof(buf));
2971    host = strdup(buf);
2972  }
2973
2974  if(interface == NULL && address == NULL)
2975  {
2976    if(options & OPT_DAEMON)
2977    {
2978      show_message("you must provide either an interface or an address\n");
2979      return(-1);
2980    }
2981    if(interface) { free(interface); }
2982    get_input("interface", buf, sizeof(buf));
2983    option_handler(CMD_interface, buf);
2984  }
2985
2986  warn_fields(service->fields_used);
2987
2988  return 0;
2989}
2990
2991int TZO_update_entry(void)
2992{
2993  char *buf = update_entry_buf;
2994  char *bp = buf;
2995  int bytes;
2996  int btot;
2997  int ret;
2998
2999  buf[BUFFER_SIZE] = '\0';
3000
3001  if(do_connect((int*)&client_sockfd, server, port) != 0)
3002  {
3003    if(!(options & OPT_QUIET))
3004    {
3005      show_message("error connecting to %s:%s\n", server, port);
3006    }
3007    return(UPDATERES_ERROR);
3008  }
3009
3010  snprintf(buf, BUFFER_SIZE, "GET %s?", request);
3011  output(buf);
3012  snprintf(buf, BUFFER_SIZE, "%s=%s&", "TZOName", host);
3013  output(buf);
3014  snprintf(buf, BUFFER_SIZE, "%s=%s&", "Email", user_name);
3015  output(buf);
3016  snprintf(buf, BUFFER_SIZE, "%s=%s&", "TZOKey", password);
3017  output(buf);
3018  snprintf(buf, BUFFER_SIZE, "%s=%s&", "IPAddress", address);
3019  output(buf);
3020  snprintf(buf, BUFFER_SIZE, " HTTP/1.0\015\012");
3021  output(buf);
3022  snprintf(buf, BUFFER_SIZE, "User-Agent: %s-%s %s [%s] (%s)\015\012",
3023      "ez-update", VERSION, OS, (options & OPT_DAEMON) ? "daemon" : "", "by Angus Mackay");
3024  output(buf);
3025  snprintf(buf, BUFFER_SIZE, "Host: %s\015\012", server);
3026  output(buf);
3027  snprintf(buf, BUFFER_SIZE, "\015\012");
3028  output(buf);
3029
3030  bp = buf;
3031  bytes = 0;
3032  btot = 0;
3033  while((bytes=read_input(bp, BUFFER_SIZE-btot)) > 0)
3034  {
3035    bp += bytes;
3036    btot += bytes;
3037    dprintf((stderr, "btot: %d\n", btot));
3038  }
3039  close(client_sockfd);
3040  buf[btot] = '\0';
3041
3042  dprintf((stderr, "server output: %s\n", buf));
3043
3044  if(sscanf(buf, " HTTP/1.%*c %3d", &ret) != 1)
3045  {
3046    ret = -1;
3047  }
3048
3049  switch(ret)
3050  {
3051    case -1:
3052      if(!(options & OPT_QUIET))
3053      {
3054        show_message("strange server response, are you connecting to the right server?\n");
3055      }
3056      return(UPDATERES_ERROR);
3057      break;
3058
3059    case 200:
3060      if(!(options & OPT_QUIET))
3061      {
3062        show_message("request successful\n");
3063      }
3064      break;
3065
3066    case 302:
3067      // There is no neat way to determine the exact error other than to
3068      // parse the Location part of the mime header to find where we're
3069      // being redirected.
3070      if(!(options & OPT_QUIET))
3071      {
3072        // reuse the auth buffer
3073        *auth = '\0';
3074        bp = strstr(buf, "Location: ");
3075        if((bp < strstr(buf, "\r\n\r\n")) && (sscanf(bp, "Location: http://%*[^/]%255[^\r\n]", auth) == 1))
3076        {
3077          bp = strrchr(auth, '/') + 1;
3078        }
3079        else
3080        {
3081          bp = "";
3082        }
3083        dprintf((stderr, "location: %s\n", bp));
3084
3085        if(!(strncmp(bp, "domainmismatch.htm", strlen(bp)) && strncmp(bp, "invname.htm", strlen(bp))))
3086        {
3087          show_message("invalid host name\n");
3088        }
3089        else if(!strncmp(bp, "invkey.htm", strlen(bp)))
3090        {
3091          show_message("invalid password(tzo key)\n");
3092        }
3093        else if(!(strncmp(bp, "emailmismatch.htm", strlen(bp)) && strncmp(bp, "invemail.htm", strlen(bp))))
3094        {
3095          show_message("invalid user name(email address)\n");
3096        }
3097        else
3098        {
3099          show_message("unknown error\n");
3100        }
3101      }
3102      return(UPDATERES_ERROR);
3103      break;
3104
3105    default:
3106      if(!(options & OPT_QUIET))
3107      {
3108        // reuse the auth buffer
3109        *auth = '\0';
3110        sscanf(buf, " HTTP/1.%*c %*3d %255[^\r\n]", auth);
3111        show_message("unknown return code: %d\n", ret);
3112        show_message("server response: %s\n", auth);
3113      }
3114      return(UPDATERES_ERROR);
3115      break;
3116  }
3117
3118  return(UPDATERES_OK);
3119}
3120
3121int EASYDNS_check_info(void)
3122{
3123  char buf[BUFSIZ+1];
3124
3125  if((host == NULL) || (*host == '\0'))
3126  {
3127    if(options & OPT_DAEMON)
3128    {
3129      return(-1);
3130    }
3131    if(host) { free(host); }
3132    get_input("host", buf, sizeof(buf));
3133    host = strdup(buf);
3134  }
3135
3136  if(interface == NULL && address == NULL)
3137  {
3138    if(options & OPT_DAEMON)
3139    {
3140      show_message("you must provide either an interface or an address\n");
3141      return(-1);
3142    }
3143    if(interface) { free(interface); }
3144    get_input("interface", buf, sizeof(buf));
3145    option_handler(CMD_interface, buf);
3146  }
3147
3148  warn_fields(service->fields_used);
3149
3150  return 0;
3151}
3152
3153int EASYDNS_update_entry(void)
3154{
3155  char *buf = update_entry_buf;
3156  char *bp = buf;
3157  int bytes;
3158  int btot;
3159  int ret;
3160
3161  buf[BUFFER_SIZE] = '\0';
3162
3163  if(do_connect((int*)&client_sockfd, server, port) != 0)
3164  {
3165    if(!(options & OPT_QUIET))
3166    {
3167      show_message("error connecting to %s:%s\n", server, port);
3168    }
3169    return(UPDATERES_ERROR);
3170  }
3171
3172  snprintf(buf, BUFFER_SIZE, "GET %s?action=edit&", request);
3173  output(buf);
3174  if(address != NULL && *address != '\0')
3175  {
3176    snprintf(buf, BUFFER_SIZE, "%s=%s&", "myip", address);
3177    output(buf);
3178  }
3179  snprintf(buf, BUFFER_SIZE, "%s=%s&", "wildcard", wildcard ? "ON" : "OFF");
3180  output(buf);
3181  snprintf(buf, BUFFER_SIZE, "%s=%s&", "mx", mx);
3182  output(buf);
3183  snprintf(buf, BUFFER_SIZE, "%s=%s&", "backmx", *mx == '\0' ? "NO" : "YES");
3184  output(buf);
3185  snprintf(buf, BUFFER_SIZE, "%s=%s&", "host_id", host);
3186  output(buf);
3187  snprintf(buf, BUFFER_SIZE, " HTTP/1.0\015\012");
3188  output(buf);
3189  snprintf(buf, BUFFER_SIZE, "Authorization: Basic %s\015\012", auth);
3190  output(buf);
3191  snprintf(buf, BUFFER_SIZE, "User-Agent: %s-%s %s [%s] (%s)\015\012",
3192      "ez-update", VERSION, OS, (options & OPT_DAEMON) ? "daemon" : "", "by Angus Mackay");
3193  output(buf);
3194  snprintf(buf, BUFFER_SIZE, "Host: %s\015\012", server);
3195  output(buf);
3196  snprintf(buf, BUFFER_SIZE, "\015\012");
3197  output(buf);
3198
3199  bp = buf;
3200  bytes = 0;
3201  btot = 0;
3202  while((bytes=read_input(bp, BUFFER_SIZE-btot)) > 0)
3203  {
3204    bp += bytes;
3205    btot += bytes;
3206    dprintf((stderr, "btot: %d\n", btot));
3207  }
3208  close(client_sockfd);
3209  buf[btot] = '\0';
3210
3211  dprintf((stderr, "server output: %s\n", buf));
3212
3213  if(sscanf(buf, " HTTP/1.%*c %3d", &ret) != 1)
3214  {
3215    ret = -1;
3216  }
3217
3218  switch(ret)
3219  {
3220    case -1:
3221      if(!(options & OPT_QUIET))
3222      {
3223        show_message("strange server response, are you connecting to the right server?\n");
3224      }
3225      return(UPDATERES_ERROR);
3226      break;
3227
3228    case 200:
3229      if(strstr(buf, "NOERROR\n") != NULL)
3230      {
3231        if(!(options & OPT_QUIET))
3232        {
3233          show_message("request successful\n");
3234        }
3235      }
3236      else
3237      {
3238        show_message("error processing request\n");
3239        if(!(options & OPT_QUIET))
3240        {
3241          show_message("server output: %s\n", buf);
3242        }
3243        return(UPDATERES_ERROR);
3244      }
3245      break;
3246
3247    case 401:
3248      if(!(options & OPT_QUIET))
3249      {
3250        show_message("authentication failure\n");
3251      }
3252      return(UPDATERES_SHUTDOWN);
3253      break;
3254
3255    default:
3256      if(!(options & OPT_QUIET))
3257      {
3258        // reuse the auth buffer
3259        *auth = '\0';
3260        sscanf(buf, " HTTP/1.%*c %*3d %255[^\r\n]", auth);
3261        show_message("unknown return code: %d\n", ret);
3262        show_message("server response: %s\n", auth);
3263      }
3264      return(UPDATERES_ERROR);
3265      break;
3266  }
3267
3268  return(UPDATERES_OK);
3269}
3270
3271int EASYDNS_PARTNER_check_info(void)
3272{
3273  char buf[BUFSIZ+1];
3274
3275  if((host == NULL) || (*host == '\0'))
3276  {
3277    if(options & OPT_DAEMON)
3278    {
3279      return(-1);
3280    }
3281    if(host) { free(host); }
3282    get_input("host", buf, sizeof(buf));
3283    host = strdup(buf);
3284  }
3285
3286  if((partner == NULL) || (*partner == '\0'))
3287  {
3288    if(options & OPT_DAEMON)
3289    {
3290      return(-1);
3291    }
3292    if(partner) { free(partner); }
3293    get_input("easyDNS partner", buf, sizeof(buf));
3294    partner = strdup(buf);
3295  }
3296
3297  if(interface == NULL && address == NULL)
3298  {
3299    if(options & OPT_DAEMON)
3300    {
3301      show_message("you must provide either an interface or an address\n");
3302      return(-1);
3303    }
3304    if(interface) { free(interface); }
3305    get_input("interface", buf, sizeof(buf));
3306    option_handler(CMD_interface, buf);
3307  }
3308
3309  warn_fields(service->fields_used);
3310
3311  return 0;
3312}
3313
3314int EASYDNS_PARTNER_update_entry(void)
3315{
3316  char *buf = update_entry_buf;
3317  char *bp = buf;
3318  int bytes;
3319  int btot;
3320  int ret;
3321
3322  buf[BUFFER_SIZE] = '\0';
3323
3324  if(do_connect((int*)&client_sockfd, server, port) != 0)
3325  {
3326    if(!(options & OPT_QUIET))
3327    {
3328      show_message("error connecting to %s:%s\n", server, port);
3329    }
3330    return(UPDATERES_ERROR);
3331  }
3332
3333  snprintf(buf, BUFFER_SIZE, "GET %s?action=edit&", request);
3334  output(buf);
3335  if(address != NULL && *address != '\0')
3336  {
3337    snprintf(buf, BUFFER_SIZE, "%s=%s&", "myip", address);
3338    output(buf);
3339  }
3340  snprintf(buf, BUFFER_SIZE, "%s=%s&", "partner", partner);
3341  output(buf);
3342  snprintf(buf, BUFFER_SIZE, "%s=%s&", "wildcard", wildcard ? "ON" : "OFF");
3343  output(buf);
3344  snprintf(buf, BUFFER_SIZE, "%s=%s", "hostname", host);
3345  output(buf);
3346  snprintf(buf, BUFFER_SIZE, " HTTP/1.0\015\012");
3347  output(buf);
3348  snprintf(buf, BUFFER_SIZE, "Authorization: Basic %s\015\012", auth);
3349  output(buf);
3350  snprintf(buf, BUFFER_SIZE, "User-Agent: %s-%s %s [%s] (%s)\015\012",
3351      "ez-update", VERSION, OS, (options & OPT_DAEMON) ? "daemon" : "", "by Angus Mackay");
3352  output(buf);
3353  snprintf(buf, BUFFER_SIZE, "Host: %s\015\012", server);
3354  output(buf);
3355  snprintf(buf, BUFFER_SIZE, "\015\012");
3356  output(buf);
3357
3358  bp = buf;
3359  bytes = 0;
3360  btot = 0;
3361  while((bytes=read_input(bp, BUFFER_SIZE-btot)) > 0)
3362  {
3363    bp += bytes;
3364    btot += bytes;
3365    dprintf((stderr, "btot: %d\n", btot));
3366  }
3367  close(client_sockfd);
3368  buf[btot] = '\0';
3369
3370  dprintf((stderr, "server output: %s\n", buf));
3371
3372  if(sscanf(buf, " HTTP/1.%*c %3d", &ret) != 1)
3373  {
3374    ret = -1;
3375  }
3376
3377  switch(ret)
3378  {
3379    case -1:
3380      if(!(options & OPT_QUIET))
3381      {
3382        show_message("strange server response, are you connecting to the right server?\n");
3383      }
3384      return(UPDATERES_ERROR);
3385      break;
3386
3387    case 200:
3388      if(strstr(buf, "OK\n") != NULL)
3389      {
3390        if(!(options & OPT_QUIET))
3391        {
3392          show_message("request successful\n");
3393        }
3394      }
3395      else
3396      {
3397        show_message("error processing request\n");
3398        if(!(options & OPT_QUIET))
3399        {
3400          show_message("server output: %s\n", buf);
3401        }
3402        return(UPDATERES_ERROR);
3403      }
3404      break;
3405
3406    case 401:
3407      if(!(options & OPT_QUIET))
3408      {
3409        show_message("authentication failure\n");
3410      }
3411      return(UPDATERES_SHUTDOWN);
3412      break;
3413
3414    case 403:
3415      if(!(options & OPT_QUIET))
3416      {
3417        show_message("updating too frequently\n");
3418      }
3419      show_message("sleeping for %s\n", format_time(MAX_WAITRESPONSE_WAIT));
3420      sleep(MAX_WAITRESPONSE_WAIT);
3421      return(UPDATERES_ERROR);
3422      break;
3423
3424    case 404:
3425      if(!(options & OPT_QUIET))
3426      {
3427        show_message("no dynamic service for this host/domain\n");
3428      }
3429      return(UPDATERES_SHUTDOWN);
3430      break;
3431
3432    case 405:
3433      if(!(options & OPT_QUIET))
3434      {
3435        show_message("partner not supported\n");
3436      }
3437      return(UPDATERES_SHUTDOWN);
3438      break;
3439
3440    default:
3441      if(!(options & OPT_QUIET))
3442      {
3443        // reuse the auth buffer
3444        *auth = '\0';
3445        sscanf(buf, " HTTP/1.%*c %*3d %255[^\r\n]", auth);
3446        show_message("unknown return code: %d\n", ret);
3447        show_message("server response: %s\n", auth);
3448      }
3449      return(UPDATERES_ERROR);
3450      break;
3451  }
3452
3453  return(UPDATERES_OK);
3454}
3455
3456
3457#ifdef USE_MD5
3458int GNUDIP_check_info(void)
3459{
3460  char buf[BUFSIZ+1];
3461
3462  if((server == NULL) || (*server == '\0'))
3463  {
3464    if(options & OPT_DAEMON)
3465    {
3466      return(-1);
3467    }
3468    if(server) { free(server); }
3469    get_input("server", buf, sizeof(buf));
3470    server = strdup(buf);
3471  }
3472
3473  if((host == NULL) || (*host == '\0'))
3474  {
3475    if(options & OPT_DAEMON)
3476    {
3477      return(-1);
3478    }
3479    if(host) { free(host); }
3480    get_input("host", buf, sizeof(buf));
3481    host = strdup(buf);
3482  }
3483
3484  if((address) && (strcmp(address, "0.0.0.0") != 0))
3485  {
3486    if(!(options & OPT_QUIET))
3487    {
3488      show_message("warning: for GNUDIP the \"address\" parpameter is only used if set to \"0.0.0.0\" thus making an offline request.\n");
3489    }
3490  }
3491
3492  warn_fields(service->fields_used);
3493
3494  return 0;
3495}
3496
3497int GNUDIP_update_entry(void)
3498{
3499  char *buf = update_entry_buf;
3500  unsigned char digestbuf[MD5_DIGEST_BYTES];
3501  char *p;
3502  int bytes;
3503  int ret;
3504  int i;
3505  char *domainname;
3506  char gnudip_request[2];
3507
3508  // send an offline request if address 0.0.0.0 is used
3509  // otherwise, we ignore the address and send an update request
3510  gnudip_request[0] = strcmp(address, "0.0.0.0") == 0 ? '1' : '0';
3511  gnudip_request[1] = '\0';
3512
3513  // find domainname
3514  for(p=host; *p != '\0' && *p != '.'; p++);
3515  if(*p != '\0') { p++; }
3516  if(*p == '\0')
3517  {
3518    return(UPDATERES_ERROR);
3519  }
3520  domainname = p;
3521
3522  if(do_connect((int*)&client_sockfd, server, port) != 0)
3523  {
3524    if(!(options & OPT_QUIET))
3525    {
3526      show_message("error connecting to %s:%s\n", server, port);
3527    }
3528    return(UPDATERES_ERROR);
3529  }
3530
3531  if((bytes=read_input(buf, BUFFER_SIZE)) <= 0)
3532  {
3533    close(client_sockfd);
3534    return(UPDATERES_ERROR);
3535  }
3536  buf[bytes] = '\0';
3537  dprintf((stderr, "bytes: %d\n", bytes));
3538  dprintf((stderr, "server output: %s\n", buf));
3539
3540  // buf holds the shared secret
3541  chomp(buf);
3542
3543  // use the auth buffer
3544  md5_buffer(password, strlen(password), digestbuf);
3545  for(i=0, p=auth; i<MD5_DIGEST_BYTES; i++, p+=2)
3546  {
3547    sprintf(p, "%02x", digestbuf[i]);
3548  }
3549  strncat(auth, ".", 255-strlen(auth));
3550  strncat(auth, buf, 255-strlen(auth));
3551  dprintf((stderr, "auth: %s\n", auth));
3552  md5_buffer(auth, strlen(auth), digestbuf);
3553  for(i=0, p=buf; i<MD5_DIGEST_BYTES; i++, p+=2)
3554  {
3555    sprintf(p, "%02x", digestbuf[i]);
3556  }
3557  strcpy(auth, buf);
3558
3559  dprintf((stderr, "auth: %s\n", auth));
3560
3561  snprintf(buf, BUFFER_SIZE, "%s:%s:%s:%s\n", user_name, auth, domainname,
3562      gnudip_request);
3563  output(buf);
3564
3565  bytes = 0;
3566  if((bytes=read_input(buf, BUFFER_SIZE)) <= 0)
3567  {
3568    close(client_sockfd);
3569    return(UPDATERES_ERROR);
3570  }
3571  buf[bytes] = '\0';
3572
3573  dprintf((stderr, "bytes: %d\n", bytes));
3574  dprintf((stderr, "server output: %s\n", buf));
3575
3576  close(client_sockfd);
3577
3578  if(sscanf(buf, "%d", &ret) != 1)
3579  {
3580    ret = -1;
3581  }
3582
3583  switch(ret)
3584  {
3585    case -1:
3586      if(!(options & OPT_QUIET))
3587      {
3588        show_message("strange server response, are you connecting to the right server?\n");
3589      }
3590      return(UPDATERES_ERROR);
3591      break;
3592
3593    case 0:
3594      if(!(options & OPT_QUIET))
3595      {
3596        show_message("update request successful\n");
3597      }
3598      break;
3599
3600    case 1:
3601      if(!(options & OPT_QUIET))
3602      {
3603        show_message("invalid login attempt\n");
3604      }
3605      return(UPDATERES_ERROR);
3606      break;
3607
3608    case 2:
3609      if(!(options & OPT_QUIET))
3610      {
3611        show_message("offline request successful\n");
3612      }
3613      break;
3614
3615    default:
3616      if(!(options & OPT_QUIET))
3617      {
3618        show_message("unknown return code: %d\n", ret);
3619      }
3620      return(UPDATERES_ERROR);
3621      break;
3622  }
3623
3624  return(UPDATERES_OK);
3625}
3626#endif
3627
3628#ifdef CONFIG_PGP
3629int JUSTL_check_info(void)
3630{
3631  char buf[BUFSIZ+1];
3632
3633  if(host == NULL)
3634  {
3635    if(options & OPT_DAEMON)
3636    {
3637      return(-1);
3638    }
3639    get_input("host", buf, sizeof(buf));
3640    host = strdup(buf);
3641  }
3642
3643  if(interface == NULL && address == NULL)
3644  {
3645    if(options & OPT_DAEMON)
3646    {
3647      show_message("you must provide either an interface or an address\n");
3648      return(-1);
3649    }
3650    if(interface) { free(interface); }
3651    get_input("interface", buf, sizeof(buf));
3652    option_handler(CMD_interface, buf);
3653  }
3654
3655  warn_fields(service->fields_used);
3656
3657  return 0;
3658}
3659
3660int JUSTL_update_entry(void)
3661{
3662  char *buf = update_entry_buf;
3663  char *bp = buf;
3664  int bytes;
3665  int btot;
3666  int ret;
3667
3668  buf[BUFFER_SIZE] = '\0';
3669
3670  if(do_connect((int*)&client_sockfd, server, port) != 0)
3671  {
3672    if(!(options & OPT_QUIET))
3673    {
3674      show_message("error connecting to %s:%s\n", server, port);
3675    }
3676    return(UPDATERES_ERROR);
3677  }
3678
3679  snprintf(buf, BUFFER_SIZE, "GET %s?direct=1&", request);
3680  output(buf);
3681  snprintf(buf, BUFFER_SIZE, "%s=%s&", "username", user_name);
3682  output(buf);
3683  snprintf(buf, BUFFER_SIZE, "%s=%s&", "password", password);
3684  output(buf);
3685  snprintf(buf, BUFFER_SIZE, "%s=%s&", "host", host);
3686  output(buf);
3687  snprintf(buf, BUFFER_SIZE, "%s=%s&", "ip", address);
3688  output(buf);
3689  snprintf(buf, BUFFER_SIZE, " HTTP/1.0\015\012");
3690  output(buf);
3691  snprintf(buf, BUFFER_SIZE, "Authorization: Basic %s\015\012", auth);
3692  output(buf);
3693  snprintf(buf, BUFFER_SIZE, "User-Agent: %s-%s %s [%s] (%s)\015\012",
3694      "ez-update", VERSION, OS, (options & OPT_DAEMON) ? "daemon" : "", "by Angus Mackay");
3695  output(buf);
3696  snprintf(buf, BUFFER_SIZE, "Host: %s\015\012", server);
3697  output(buf);
3698  snprintf(buf, BUFFER_SIZE, "\015\012");
3699  output(buf);
3700
3701  bp = buf;
3702  bytes = 0;
3703  btot = 0;
3704  while((bytes=read_input(bp, BUFFER_SIZE-btot)) > 0)
3705  {
3706    bp += bytes;
3707    btot += bytes;
3708    dprintf((stderr, "btot: %d\n", btot));
3709  }
3710  close(client_sockfd);
3711  buf[btot] = '\0';
3712
3713  dprintf((stderr, "server output: %s\n", buf));
3714
3715  if(sscanf(buf, " HTTP/1.%*c %3d", &ret) != 1)
3716  {
3717    ret = -1;
3718  }
3719
3720  switch(ret)
3721  {
3722    case -1:
3723      if(!(options & OPT_QUIET))
3724      {
3725        show_message("strange server response, are you connecting to the right server?\n");
3726      }
3727      return(UPDATERES_ERROR);
3728      break;
3729
3730    case 200:
3731      if(strstr(buf, " set ") != NULL)
3732      {
3733        if(!(options & OPT_QUIET))
3734        {
3735          show_message("request successful\n");
3736        }
3737      }
3738      else
3739      {
3740        show_message("error processing request\n");
3741        if(!(options & OPT_QUIET))
3742        {
3743          show_message("server output: %s\n", buf);
3744        }
3745        return(UPDATERES_ERROR);
3746      }
3747      break;
3748
3749    case 401:
3750      if(!(options & OPT_QUIET))
3751      {
3752        show_message("authentication failure\n");
3753      }
3754      return(UPDATERES_SHUTDOWN);
3755      break;
3756
3757    default:
3758      if(!(options & OPT_QUIET))
3759      {
3760        // reuse the auth buffer
3761        *auth = '\0';
3762        sscanf(buf, " HTTP/1.%*c %*3d %255[^\r\n]", auth);
3763        show_message("unknown return code: %d\n", ret);
3764        show_message("server response: %s\n", auth);
3765      }
3766      return(UPDATERES_ERROR);
3767      break;
3768  }
3769
3770  return(UPDATERES_OK);
3771}
3772#endif
3773
3774int DYNS_check_info(void)
3775{
3776  char buf[BUFSIZ+1];
3777
3778  if(host == NULL)
3779  {
3780    if(options & OPT_DAEMON)
3781    {
3782      return(-1);
3783    }
3784    get_input("host", buf, sizeof(buf));
3785    host = strdup(buf);
3786  }
3787
3788  if(interface == NULL && address == NULL)
3789  {
3790    if(options & OPT_DAEMON)
3791    {
3792      show_message("you must provide either an interface or an address\n");
3793      return(-1);
3794    }
3795    if(interface) { free(interface); }
3796    get_input("interface", buf, sizeof(buf));
3797    option_handler(CMD_interface, buf);
3798  }
3799
3800  warn_fields(service->fields_used);
3801
3802  return 0;
3803}
3804
3805int DYNS_update_entry(void)
3806{
3807  char *buf = update_entry_buf;
3808  char *bp = buf;
3809  int bytes;
3810  int btot;
3811  int ret;
3812
3813  buf[BUFFER_SIZE] = '\0';
3814
3815  if(do_connect((int*)&client_sockfd, server, port) != 0)
3816  {
3817    if(!(options & OPT_QUIET))
3818    {
3819      show_message("error connecting to %s:%s\n", server, port);
3820    }
3821    return(UPDATERES_ERROR);
3822  }
3823
3824  snprintf(buf, BUFFER_SIZE, "GET %s?", request);
3825  output(buf);
3826  snprintf(buf, BUFFER_SIZE, "%s=%s&", "username", user_name);
3827  output(buf);
3828  snprintf(buf, BUFFER_SIZE, "%s=%s&", "password", password);
3829  output(buf);
3830  snprintf(buf, BUFFER_SIZE, "%s=%s&", "host", host);
3831  output(buf);
3832  snprintf(buf, BUFFER_SIZE, "%s=%s", "ip", address);
3833  output(buf);
3834  snprintf(buf, BUFFER_SIZE, " HTTP/1.0\015\012");
3835  output(buf);
3836  snprintf(buf, BUFFER_SIZE, "Authorization: Basic %s\015\012", auth);
3837  output(buf);
3838  snprintf(buf, BUFFER_SIZE, "User-Agent: %s-%s %s [%s] (%s)\015\012",
3839      "ez-update", VERSION, OS, (options & OPT_DAEMON) ? "daemon" : "", "by Angus Mackay");
3840  output(buf);
3841  snprintf(buf, BUFFER_SIZE, "Host: %s\015\012", server);
3842  output(buf);
3843  snprintf(buf, BUFFER_SIZE, "\015\012");
3844  output(buf);
3845
3846  bp = buf;
3847  bytes = 0;
3848  btot = 0;
3849  while((bytes=read_input(bp, BUFFER_SIZE-btot)) > 0)
3850  {
3851    bp += bytes;
3852    btot += bytes;
3853    dprintf((stderr, "btot: %d\n", btot));
3854  }
3855  close(client_sockfd);
3856  buf[btot] = '\0';
3857
3858  dprintf((stderr, "server output: %s\n", buf));
3859
3860  if(sscanf(buf, " HTTP/1.%*c %3d", &ret) != 1)
3861  {
3862    ret = -1;
3863  }
3864
3865  switch(ret)
3866  {
3867    case -1:
3868      if(!(options & OPT_QUIET))
3869      {
3870        show_message("strange server response, are you connecting to the right server?\n");
3871      }
3872      return(UPDATERES_ERROR);
3873      break;
3874
3875    case 200:
3876      if(strstr(buf, "200 Host") != NULL ||
3877          strstr(buf, "200 host") != NULL)
3878      {
3879        if(!(options & OPT_QUIET))
3880        {
3881          show_message("request successful\n");
3882        }
3883      }
3884      else if(strstr(buf, "400 Bad Request") != NULL)
3885      {
3886        if(!(options & OPT_QUIET))
3887        {
3888          show_message("bad request\n");
3889        }
3890      }
3891      else if(strstr(buf, "401 User") != NULL)
3892      {
3893        if(!(options & OPT_QUIET))
3894        {
3895          show_message("authentication failure (username/password)\n");
3896        }
3897      }
3898      else if(strstr(buf, "405 Hostname") != NULL)
3899      {
3900        if(!(options & OPT_QUIET))
3901        {
3902          show_message("authentication failure (hostname not found)\n");
3903        }
3904      }
3905
3906      else
3907      {
3908        show_message("error processing request\n");
3909        if(!(options & OPT_QUIET))
3910        {
3911          show_message("server output: %s\n", buf);
3912        }
3913        return(UPDATERES_ERROR);
3914      }
3915
3916      break;
3917
3918    case 405:
3919      if(!(options & OPT_QUIET))
3920      {
3921        show_message("authentication failure\n");
3922      }
3923      return(UPDATERES_ERROR);
3924      break;
3925
3926    default:
3927      if(!(options & OPT_QUIET))
3928      {
3929        // reuse the auth buffer
3930        *auth = '\0';
3931        sscanf(buf, " HTTP/1.%*c %*3d %255[^\r\n]", auth);
3932        show_message("unknown return code: %d\n", ret);
3933        show_message("server response: %s\n", auth);
3934      }
3935      return(UPDATERES_ERROR);
3936      break;
3937  }
3938
3939  return(UPDATERES_OK);
3940}
3941
3942#ifdef CONFIG_HN
3943int HN_check_info(void)
3944{
3945  warn_fields(service->fields_used);
3946
3947  return 0;
3948}
3949
3950int HN_update_entry(void)
3951{
3952  char *buf = update_entry_buf;
3953  char *bp = buf;
3954  int bytes;
3955  int btot;
3956  int ret;
3957
3958  buf[BUFFER_SIZE] = '\0';
3959
3960  if(do_connect((int*)&client_sockfd, server, port) != 0)
3961  {
3962    if(!(options & OPT_QUIET))
3963    {
3964      show_message("error connecting to %s:%s\n", server, port);
3965    }
3966    return(UPDATERES_ERROR);
3967  }
3968
3969  snprintf(buf, BUFFER_SIZE, "GET %s?ver=%d&", request, 1);
3970  output(buf);
3971  if(address)
3972  {
3973    snprintf(buf, BUFFER_SIZE, "%s=%s&", "IP", address);
3974    output(buf);
3975  }
3976  snprintf(buf, BUFFER_SIZE, " HTTP/1.0\015\012");
3977  output(buf);
3978  snprintf(buf, BUFFER_SIZE, "Authorization: Basic %s\015\012", auth);
3979  output(buf);
3980  snprintf(buf, BUFFER_SIZE, "User-Agent: %s-%s %s [%s] (%s)\015\012",
3981      "ez-update", VERSION, OS, (options & OPT_DAEMON) ? "daemon" : "", "by Angus Mackay");
3982  output(buf);
3983  snprintf(buf, BUFFER_SIZE, "Host: %s\015\012", server);
3984  output(buf);
3985  snprintf(buf, BUFFER_SIZE, "\015\012");
3986  output(buf);
3987
3988  bp = buf;
3989  bytes = 0;
3990  btot = 0;
3991  while((bytes=read_input(bp, BUFFER_SIZE-btot)) > 0)
3992  {
3993    bp += bytes;
3994    btot += bytes;
3995    dprintf((stderr, "btot: %d\n", btot));
3996  }
3997  close(client_sockfd);
3998  buf[btot] = '\0';
3999
4000  dprintf((stderr, "server output: %s\n", buf));
4001
4002  if(sscanf(buf, " HTTP/1.%*c %3d", &ret) != 1)
4003  {
4004    ret = -1;
4005  }
4006
4007  switch(ret)
4008  {
4009    char *p;
4010
4011    case -1:
4012      if(!(options & OPT_QUIET))
4013      {
4014        show_message("strange server response, are you connecting to the right server?\n");
4015      }
4016      return(UPDATERES_ERROR);
4017      break;
4018
4019    case 200:
4020      ret = -1;
4021      if((p=strstr(buf, "DDNS_Response_")) != NULL)
4022      {
4023         sscanf(p, "DDNS_Response_%*code=%3d", &ret);
4024      }
4025
4026      /*
4027       * 101 - Successfully Updated
4028       * 201 - Failure because previous update occured
4029       *       less than 300 seconds ago
4030       * 202 - Failure because of server error
4031       * 203 - Failure because account is frozen (by admin)
4032       * 204 - Failure because account is locked (by user)
4033       */
4034      switch(ret)
4035      {
4036        case -1:
4037          if(!(options & OPT_QUIET))
4038          {
4039            show_message("strange server response, are you connecting to the right server?\n");
4040          }
4041          return(UPDATERES_ERROR);
4042          break;
4043
4044        case 101:
4045          if(!(options & OPT_QUIET))
4046          {
4047            show_message("request successful\n");
4048          }
4049          break;
4050
4051        case 201:
4052          show_message("Last update was less than %d seconds ago.\n", 300);
4053          return(UPDATERES_ERROR);
4054          break;
4055
4056        case 202:
4057          show_message("Server error.\n");
4058          return(UPDATERES_ERROR);
4059          break;
4060
4061        case 203:
4062          show_message("Failure because account is frozen (by admin).\n");
4063          return(UPDATERES_SHUTDOWN);
4064          break;
4065
4066        case 204:
4067          show_message("Failure because account is locked (by user).\n");
4068          return(UPDATERES_SHUTDOWN);
4069          break;
4070
4071        default:
4072          if(!(options & OPT_QUIET))
4073          {
4074            show_message("unknown return code: %d\n", ret);
4075            show_message("server response: %s\n", buf);
4076          }
4077          return(UPDATERES_ERROR);
4078          break;
4079      }
4080      break;
4081
4082    case 401:
4083      if(!(options & OPT_QUIET))
4084      {
4085        show_message("authentication failure\n");
4086      }
4087      return(UPDATERES_SHUTDOWN);
4088      break;
4089
4090    default:
4091      if(!(options & OPT_QUIET))
4092      {
4093        // reuse the auth buffer
4094        *auth = '\0';
4095        sscanf(buf, " HTTP/1.%*c %*3d %255[^\r\n]", auth);
4096        show_message("unknown return code: %d\n", ret);
4097        show_message("server response: %s\n", auth);
4098      }
4099      return(UPDATERES_ERROR);
4100      break;
4101  }
4102
4103  return(UPDATERES_OK);
4104}
4105#endif
4106
4107int ZONEEDIT_check_info(void)
4108{
4109  char buf[BUFSIZ+1];
4110
4111  if((host == NULL) || (*host == '\0'))
4112  {
4113    if(options & OPT_DAEMON)
4114    {
4115      return(-1);
4116    }
4117    if(host) { free(host); }
4118    get_input("host", buf, sizeof(buf));
4119    host = strdup(buf);
4120  }
4121
4122  warn_fields(service->fields_used);
4123
4124  return 0;
4125}
4126
4127int ZONEEDIT_update_entry(void)
4128{
4129  char *buf = update_entry_buf;
4130  char *bp = buf;
4131  int bytes;
4132  int btot;
4133  int ret;
4134
4135  buf[BUFFER_SIZE] = '\0';
4136
4137  if(do_connect((int*)&client_sockfd, server, port) != 0)
4138  {
4139    if(!(options & OPT_QUIET))
4140    {
4141      show_message("error connecting to %s:%s\n", server, port);
4142    }
4143    return(UPDATERES_ERROR);
4144  }
4145
4146  snprintf(buf, BUFFER_SIZE, "GET %s?", request);
4147  output(buf);
4148  snprintf(buf, BUFFER_SIZE, "%s=%s&", "host", host);
4149  output(buf);
4150  if (address && *address) {
4151      snprintf(buf, BUFFER_SIZE, "%s=%s&", "dnsto", address);
4152      output(buf);
4153  }
4154  if (address && *mx && *mx != '0') {
4155      snprintf(buf, BUFFER_SIZE, "%s=%s&", "type", "a,mx");
4156      output(buf);
4157  }
4158  snprintf(buf, BUFFER_SIZE, " HTTP/1.0\015\012");
4159  output(buf);
4160  snprintf(buf, BUFFER_SIZE, "User-Agent: %s-%s %s (%s)\015\012",
4161      "zoneedit", VERSION, OS, "by Angus Mackay");
4162  output(buf);
4163  snprintf(buf, BUFFER_SIZE, "Host: %s\015\012", server);
4164  output(buf);
4165  snprintf(buf, BUFFER_SIZE, "Authorization: Basic %s\015\012", auth);
4166  output(buf);
4167  snprintf(buf, BUFFER_SIZE, "\015\012");
4168  output(buf);
4169
4170  bp = buf;
4171  bytes = 0;
4172  btot = 0;
4173  while((bytes=read_input(bp, BUFFER_SIZE-btot)) > 0)
4174  {
4175    bp += bytes;
4176    btot += bytes;
4177    dprintf((stderr, "btot: %d\n", btot));
4178  }
4179  close(client_sockfd);
4180  buf[btot] = '\0';
4181
4182  dprintf((stderr, "server output: %s\n", buf));
4183
4184  if(sscanf(buf, " HTTP/1.%*c %3d", &ret) != 1)
4185  {
4186    ret = -1;
4187  }
4188
4189  switch(ret)
4190  {
4191    case -1:
4192      if(!(options & OPT_QUIET))
4193      {
4194        show_message("strange server response, are you connecting to the right server?\n");
4195      }
4196      return(UPDATERES_ERROR);
4197      break;
4198
4199    case 200:
4200      if(strstr(buf, "<SUCCESS") != NULL)
4201      {
4202        if(!(options & OPT_QUIET))
4203        {
4204          show_message("request successful\n");
4205        }
4206      }
4207      else
4208      {
4209        show_message("error processing request\n");
4210        if(!(options & OPT_QUIET))
4211        {
4212          show_message("server output: %s\n", buf);
4213        }
4214        return(UPDATERES_ERROR);
4215      }
4216      break;
4217
4218    case 401:
4219      if(!(options & OPT_QUIET))
4220      {
4221        show_message("authentication failure\n");
4222      }
4223      return(UPDATERES_SHUTDOWN);
4224      break;
4225
4226    default:
4227      if(!(options & OPT_QUIET))
4228      {
4229        // reuse the auth buffer
4230        *auth = '\0';
4231        sscanf(buf, " HTTP/1.%*c %*3d %255[^\r\n]", auth);
4232        show_message("unknown return code: %d\n", ret);
4233        show_message("server response: %s\n", auth);
4234      }
4235      return(UPDATERES_ERROR);
4236      break;
4237  }
4238
4239  return(UPDATERES_OK);
4240}
4241
4242#ifdef CONFIG_HEIP
4243int HEIPV6TB_check_info(void)
4244{
4245  char buf[BUFSIZ+1];
4246
4247  if(interface == NULL)
4248  {
4249    if(options & OPT_DAEMON)
4250    {
4251      show_message("you must provide either an interface or an address\n");
4252      return(-1);
4253    }
4254    if(interface) { free(interface); }
4255    get_input("interface", buf, sizeof(buf));
4256    option_handler(CMD_interface, buf);
4257  }
4258  warn_fields(service->fields_used);
4259
4260  return 0;
4261}
4262
4263int HEIPV6TB_update_entry(void)
4264{
4265  char *buf = update_entry_buf;
4266  char *bp = buf;
4267  int bytes;
4268  int btot;
4269  int ret;
4270
4271  buf[BUFFER_SIZE] = '\0';
4272
4273  if(do_connect((int*)&client_sockfd, server, port) != 0)
4274  {
4275    if(!(options & OPT_QUIET))
4276    {
4277      show_message("error connecting to %s:%s\n", server, port);
4278    }
4279    return(UPDATERES_ERROR);
4280  }
4281
4282  snprintf(buf, BUFFER_SIZE, "GET %s?menu=%s&", request, "edit_tunnel_address");
4283  output(buf);
4284  snprintf(buf, BUFFER_SIZE, "aname=%s&", user_name);
4285  output(buf);
4286  snprintf(buf, BUFFER_SIZE, "auth=%s&", password);
4287  output(buf);
4288  snprintf(buf, BUFFER_SIZE, "ipv4b=%s", address);
4289  output(buf);
4290  snprintf(buf, BUFFER_SIZE, " HTTP/1.0\015\012");
4291  output(buf);
4292  snprintf(buf, BUFFER_SIZE, "User-Agent: %s-%s %s [%s] (%s)\015\012",
4293      "ez-update", VERSION, OS, (options & OPT_DAEMON) ? "daemon" : "", "by Angus Mackay");
4294  output(buf);
4295  snprintf(buf, BUFFER_SIZE, "Host: %s\015\012", server);
4296  output(buf);
4297  snprintf(buf, BUFFER_SIZE, "\015\012");
4298  output(buf);
4299
4300  bp = buf;
4301  bytes = 0;
4302  btot = 0;
4303  while((bytes=read_input(bp, BUFFER_SIZE-btot)) > 0)
4304  {
4305    bp += bytes;
4306    btot += bytes;
4307    dprintf((stderr, "btot: %d\n", btot));
4308  }
4309  close(client_sockfd);
4310  buf[btot] = '\0';
4311
4312  dprintf((stderr, "server output: %s\n", buf));
4313  if(sscanf(buf, " HTTP/1.%*c %3d", &ret) != 1)
4314  {
4315    ret = -1;
4316  }
4317
4318  switch(ret)
4319  {
4320    char *p;
4321
4322    case -1:
4323      if(!(options & OPT_QUIET))
4324      {
4325        show_message("strange server response, are you connecting to the right server?\n");
4326      }
4327      return(UPDATERES_ERROR);
4328      break;
4329    case 200:
4330      if(!(options & OPT_QUIET))
4331      {
4332        show_message("request successful\n");
4333      }
4334      break;
4335    default:
4336      if(!(options & OPT_QUIET))
4337      {
4338        // reuse the auth buffer
4339        *auth = '\0';
4340        sscanf(buf, " HTTP/1.%*c %*3d %255[^\r\n]", auth);
4341        show_message("unknown return code: %d\n", ret);
4342        show_message("server response: %s\n", auth);
4343      }
4344      return(UPDATERES_ERROR);
4345      break;
4346  }
4347
4348  return(UPDATERES_OK);
4349}
4350#endif
4351
4352static int is_in_list(char *needle, char **haystack)
4353{
4354  char **p;
4355  int found = 0;
4356
4357  for(p=haystack; *p != NULL; p++)
4358  {
4359    if(strcmp(needle, *p) == 0)
4360    {
4361      found = 1;
4362      break;
4363    }
4364  }
4365
4366  return(found);
4367}
4368
4369void warn_fields(char **okay_fields)
4370{
4371  if(wildcard != 0 && !is_in_list("wildcard", okay_fields))
4372  {
4373    show_message("warning: this service does not support the %s option\n",
4374        "wildcard");
4375  }
4376  if(!(mx == NULL || *mx == '\0') && !is_in_list("mx", okay_fields))
4377  {
4378    show_message("warning: this service does not support the %s option\n",
4379        "mx");
4380  }
4381  if(!(url == NULL || *url == '\0') && !is_in_list("url", okay_fields))
4382  {
4383    show_message("warning: this service does not support the %s option\n",
4384        "url");
4385  }
4386  if(!(cloak_title == NULL || *cloak_title == '\0') && !is_in_list("cloak_title", okay_fields))
4387  {
4388    show_message("warning: this service does not support the %s option\n",
4389        "cloak_title");
4390  }
4391  if(connection_type != 1 && !is_in_list("connection-type", okay_fields))
4392  {
4393    show_message("warning: this service does not support the %s option\n",
4394        "connection-type");
4395  }
4396}
4397
4398int exec_cmd(char *cmd)
4399{
4400#if (defined(HAVE_WAITPID) || defined(HAVE_WAIT)) && (defined(HAVE_VFORK) || defined(HAVE_FORK))
4401  int kid;
4402  int exit_code;
4403
4404  switch((kid=vfork()))
4405  {
4406    case -1:
4407      if(!(options & OPT_QUIET))
4408      {
4409        perror("fork");
4410      }
4411      return(-1);
4412      break;
4413    case 0:
4414      /* child */
4415      execl("/bin/sh", "sh", "-c", cmd, (char *)0);
4416      if(!(options & OPT_QUIET))
4417      {
4418        perror("exec");
4419      }
4420      exit(1);
4421      break;
4422    default:
4423      /* parent */
4424      dprintf((stderr, "forked kid: %d\n", kid));
4425      break;
4426  }
4427
4428#  ifdef HAVE_WAITPID
4429  if(waitpid(kid, &exit_code, 0) != kid)
4430  {
4431    return(1);
4432  }
4433#  else
4434  if(wait(&exit_code) != kid)
4435  {
4436    return(1);
4437  }
4438#  endif
4439  exit_code = WEXITSTATUS(exit_code);
4440
4441  return(exit_code);
4442#else
4443  return(-1);
4444#endif
4445}
4446
4447void handle_sig(int sig)
4448{
4449
4450  switch(sig)
4451  {
4452    case SIGHUP:
4453      if(config_file)
4454      {
4455        show_message("SIGHUP recieved, re-reading config file\n");
4456        if(parse_conf_file(config_file, conf_commands) != 0)
4457        {
4458          show_message("error parsing config file \"%s\"\n", config_file);
4459        }
4460      }
4461      break;
4462    case SIGTERM:
4463      /*
4464       * this is used to wake up the client so that it will perform an update
4465       */
4466      break;
4467    case SIGQUIT:
4468      show_message("received SIGQUIT, shutting down\n");
4469
4470#if HAVE_SYSLOG_H
4471      closelog();
4472#endif
4473
4474#if HAVE_GETPID
4475      if(pid_file)
4476      {
4477        pid_file_delete(pid_file);
4478      }
4479#endif
4480
4481      exit(0);
4482    default:
4483      dprintf((stderr, "case not handled: %d\n", sig));
4484      break;
4485  }
4486}
4487
4488int main(int argc, char **argv)
4489{
4490  int ifresolve_warned = 0;
4491  int i;
4492  int retval = 1;
4493#ifdef IF_LOOKUP
4494  int sock = -1;
4495#endif
4496
4497#if defined(DEBUG) && defined(__linux__) && !defined(EMBED)
4498  //mcheck(NULL);
4499#endif
4500
4501  dprintf((stderr, "staring...\n"));
4502
4503  program_name = argv[0];
4504  options = 0;
4505  *user = '\0';
4506  timeout.tv_sec = DEFAULT_TIMEOUT;
4507  timeout.tv_usec = 0;
4508  parse_service(DEF_SERVICE);
4509
4510
4511#if HAVE_SIGNAL_H
4512  // catch user interupts
4513  signal(SIGINT,  sigint_handler);
4514  signal(SIGHUP,  generic_sig_handler);
4515  signal(SIGTERM, generic_sig_handler);
4516  signal(SIGQUIT, generic_sig_handler);
4517#endif
4518
4519  parse_args(argc, argv);
4520
4521  if(!(options & OPT_QUIET) && !(options & OPT_DAEMON))
4522  {
4523    fprintf(stderr, "ez-ipupdate Version %s\nCopyright (C) 1998-2001 Angus Mackay.\n", VERSION);
4524  }
4525
4526#if HAVE_SYSLOG_H
4527  if(options & OPT_DAEMON)
4528    openlog(program_name, LOG_PID, LOG_USER );
4529#endif
4530
4531
4532  dprintf((stderr, "options: 0x%04X\n", options));
4533  dprintf((stderr, "interface: %s\n", interface));
4534  dprintf((stderr, "ntrys: %d\n", ntrys));
4535  dprintf((stderr, "server: %s:%s\n", server, port));
4536
4537  dprintf((stderr, "address: %s\n", address));
4538  dprintf((stderr, "wildcard: %d\n", wildcard));
4539  dprintf((stderr, "mx: %s\n", mx));
4540  dprintf((stderr, "auth: %s\n", auth));
4541
4542  while(is_in_list("null", service->names))
4543  {
4544    if(service->check_info() != 0)
4545    {
4546      show_message("invalid data to perform requested action.\n");
4547      exit(1);
4548    }
4549  }
4550
4551  if(server == NULL)
4552  {
4553    server = strdup(service->default_server);
4554  }
4555  if(port == NULL)
4556  {
4557    port = strdup(service->default_port);
4558  }
4559
4560  *user_name = '\0';
4561  *password = '\0';
4562
4563//2007.03.14 Yau add
4564#ifdef ASUS_DDNS
4565        if (g_asus_ddns_mode == 0)      {
4566#endif  // ASUS_DDNS
4567
4568  if(*user != '\0')
4569  {
4570    sscanf(user, "%127[^:]:%127[^\n]", user_name, password);
4571    dprintf((stderr, "user_name: %s\n", user_name));
4572    dprintf((stderr, "password: %s\n", password));
4573  }
4574  if(*user_name == '\0')
4575  {
4576    get_input("user name", user_name, sizeof(user_name));
4577  }
4578  if(*password == '\0')
4579  {
4580    strncpy(password, getpass("password: "), sizeof(password));
4581  }
4582  sprintf(user, "%s:%s", user_name, password);
4583
4584  base64Encode(user, auth);
4585
4586//2007.03.14 Yau add
4587#ifdef ASUS_DDNS
4588        }
4589#endif  // ASUS_DDNS
4590
4591  request = strdup(request_over_ride == NULL ? service->default_request : request_over_ride);
4592  dprintf((stderr, "request: %s\n", request));
4593
4594  if(service->init != NULL)
4595  {
4596    service->init();
4597  }
4598
4599  if(service->check_info() != 0)
4600  {
4601    show_message("invalid data to perform requested action.\n");
4602    exit(1);
4603  }
4604
4605  if(mx == NULL) { mx = strdup(""); }
4606  if(url == NULL) { url = strdup(""); }
4607
4608#ifdef IF_LOOKUP
4609  if(options & OPT_DAEMON)
4610  {
4611    sock = socket(AF_INET, SOCK_STREAM, 0);
4612  }
4613#endif
4614
4615//2007.03.14 Yau add
4616#ifdef ASUS_DDNS
4617        if (g_asus_ddns_mode != 0)      {
4618                nvram_unset ("ddns_return_code");
4619                nvram_unset ("ddns_suggest_name");
4620                nvram_unset ("ddns_old_name");
4621                if (asus_private() == -1)
4622                        goto exit_main;
4623        }
4624        if (g_asus_ddns_mode == 1)      {
4625                asus_reg_domain ();
4626                goto exit_main;
4627        } else if (g_asus_ddns_mode == 2)       {
4628                // override update_entry() method
4629                service->update_entry = asus_update_entry;
4630        }
4631#endif  // ASUS_DDNS
4632
4633  if(options & OPT_DAEMON)
4634  {
4635    int local_update_period = update_period;
4636#if IF_LOOKUP
4637    struct sockaddr_in sin;
4638    struct sockaddr_in sin2;
4639
4640    if(interface == NULL)
4641    {
4642      show_message("invalid data to perform requested action.\n");
4643      show_message("you must provide an interface for daemon mode");
4644      exit(1);
4645    }
4646
4647    /* background our selves */
4648    if(!(options & OPT_FOREGROUND))
4649    {
4650#  if HAVE_SYSLOG_H
4651      close(0);
4652      close(1);
4653      close(2);
4654#  endif
4655#  if HAVE_FORK
4656      if(fork() > 0) { exit(0); } /* parent */
4657#  endif
4658    }
4659
4660#if HAVE_GETPID
4661    if(pid_file && pid_file_create(pid_file) != 0)
4662    {
4663      show_message("exiting...\n");
4664      exit(1);
4665    }
4666#endif
4667
4668    show_message("ez-ipupdate Version %s, Copyright (C) 1998-2001 Angus Mackay.\n",
4669        VERSION);
4670    show_message("%s started for interface %s host %s using server %s and service %s\n",
4671        program_name, N_STR(interface), N_STR(host), server, service->title);
4672
4673    memset(&sin, 0, sizeof(sin));
4674
4675    if(cache_file)
4676    {
4677      time_t ipdate;
4678      char *ipstr;
4679
4680      if(read_cache_file(cache_file, &ipdate, &ipstr) == 0)
4681      {
4682        dprintf((stderr, "cache date: %ld\n", ipdate));
4683        dprintf((stderr, "cache IP: %s\n", ipstr ?: ""));
4684
4685        if(ipstr && strchr(ipstr, '.'))
4686        {
4687          struct tm *ts;
4688          char timebuf[64];
4689
4690          inet_aton(ipstr, &sin.sin_addr);
4691          last_update = ipdate;
4692
4693          ts = localtime(&ipdate);
4694          strftime(timebuf, sizeof(timebuf), "%Y/%m/%d %H:%M", ts);
4695          show_message("got last update %s on %s from cache file\n", ipstr, timebuf);
4696        }
4697        if(ipstr) { free(ipstr); ipstr = NULL; }
4698      }
4699      else
4700      {
4701        show_message("error reading cache file \"%s\": %s\n", cache_file,
4702            errno == 0 ? "malformed entry" : strerror(errno));
4703      }
4704    }
4705
4706    for(;;)
4707    {
4708      if(options & OPT_ONCE)
4709      {
4710        int f;
4711
4712        f = open(BLOCK_FILE, O_RDONLY);
4713        if(f >= 0)
4714        {
4715          close(f);
4716          show_message("update critically failed on a previous attempt\n");
4717          show_message("delete %s if the problem has been corrected\n",
4718              BLOCK_FILE);
4719          break;
4720		}
4721	  }
4722
4723#if HAVE_SIGNAL_H
4724      /* check for signals */
4725      if(last_sig != 0)
4726      {
4727        handle_sig(last_sig);
4728        last_sig = 0;
4729      }
4730#endif
4731printf("Get IF addr\n");
4732      if(get_if_addr(sock, interface, &sin2) == 0)
4733      {
4734        ifresolve_warned = 0;
4735        if(memcmp(&sin.sin_addr, &sin2.sin_addr, sizeof(struct in_addr)) != 0 ||
4736            (max_interval > 0 && time(NULL) - last_update > max_interval))
4737        {
4738          int updateres;
4739
4740          // save this new ipaddr
4741          memcpy(&sin, &sin2, sizeof(sin));
4742
4743          // update the address buffer
4744          if(address) { free(address); }
4745          address = strdup(inet_ntoa(sin.sin_addr));
4746
4747          if((updateres=service->update_entry()) == UPDATERES_OK)
4748          {
4749            last_update = time(NULL);
4750            local_update_period = update_period;
4751
4752            show_message("successful update for %s->%s (%s)\n",
4753                interface, inet_ntoa(sin.sin_addr), N_STR(host));
4754
4755            if(post_update_cmd)
4756            {
4757              int res;
4758
4759              if(post_update_cmd)
4760              {
4761                sprintf(post_update_cmd_arg, "%s", inet_ntoa(sin.sin_addr));
4762
4763                if((res=exec_cmd(post_update_cmd)) != 0)
4764                {
4765                  if(res == -1)
4766                  {
4767                    show_message("(%s) error running post update command: %s\n",
4768                        N_STR(host), error_string);
4769                  }
4770                  else
4771                  {
4772                    show_message(
4773                        "(%s) error running post update command, command exit code: %d\n",
4774                        N_STR(host), res);
4775                  }
4776                }
4777              }
4778            }
4779
4780            if(cache_file)
4781            {
4782              char ipbuf[64];
4783
4784              snprintf(ipbuf, sizeof(ipbuf), "%s", inet_ntoa(sin.sin_addr));
4785
4786              if(write_cache_file(cache_file, last_update, ipbuf) != 0)
4787              {
4788                show_message("unable to write cache file \"%s\": %s\n",
4789                    cache_file, error_string);
4790              }
4791            }
4792
4793			if(options & OPT_ONCE)
4794				break;
4795          }
4796          else
4797          {
4798            show_message("failure to update %s->%s (%s)\n",
4799                interface, inet_ntoa(sin.sin_addr), N_STR(host));
4800            memset(&sin, 0, sizeof(sin));
4801
4802            // double the time between attempts between each failure to update
4803            // this gets set back to the normal value the next time we get a
4804            // successful update
4805            if(local_update_period < MIN_WAIT_PERIOD)
4806            {
4807              local_update_period = MIN_WAIT_PERIOD;
4808            }
4809            else
4810            {
4811              local_update_period *= 2;
4812            }
4813            if(local_update_period > MAX_WAIT_PERIOD)
4814            {
4815              local_update_period = MAX_WAIT_PERIOD;
4816            }
4817            dprintf((stderr, "local_update_period: %d\n", local_update_period));
4818
4819            dprintf((stderr, "updateres: %d\n", updateres));
4820            if(updateres == UPDATERES_SHUTDOWN)
4821            {
4822              show_message("shutting down updater for %s due to fatal error\n",
4823                  N_STR(host));
4824#ifdef SEND_MEAIL_CMD
4825              if(notify_email && *notify_email != '\0')
4826              {
4827                char buf[1024];
4828
4829                dprintf((stderr, "sending email to %s\n", notify_email));
4830                snprintf(buf, sizeof(buf), "echo \"ez-ipupdate shutting down"
4831                    " updater for %s due to fatal error.\" | %s %s", host,
4832                    SEND_EMAIL_CMD,
4833                    notify_email);
4834                system(buf);
4835              }
4836#endif
4837              if(options & OPT_ONCE)
4838              {
4839                int f;
4840
4841                f = open(BLOCK_FILE, O_WRONLY|O_CREAT);
4842                if(f >= 0)
4843                  close(f);
4844              }
4845              break;
4846            }
4847          }
4848        }
4849		else if(options & OPT_ONCE)
4850			break;
4851        sleep(local_update_period);
4852      }
4853      else
4854      {
4855        if(!ifresolve_warned)
4856        {
4857          ifresolve_warned = 1;
4858          show_message("(%s) unable to resolve interface %s\n",
4859              N_STR(host), interface);
4860        }
4861        sleep(resolv_period);
4862      }
4863    }
4864
4865#if HAVE_GETPID
4866    if(pid_file)
4867    {
4868      pid_file_delete(pid_file);
4869    }
4870#endif
4871
4872#else
4873    show_message("sorry, this mode is only available on platforms that the ");
4874    show_message("IP address \ncan be determined. feel free to hack the code");
4875    show_message(" though.\n");
4876    exit(1);
4877#endif
4878  }
4879  else
4880  {
4881    int need_update = 1;
4882
4883    if(cache_file)
4884    {
4885      time_t ipdate;
4886      char *ipstr;
4887      char ipbuf[64];
4888
4889      if(read_cache_file(cache_file, &ipdate, &ipstr) != 0)
4890      {
4891        show_message( "error reading cache file \"%s\": %s\n", cache_file,
4892            errno == 0 ? "malformed entry" : strerror(errno));
4893      }
4894      dprintf((stderr, "cache date: %ld\n", ipdate));
4895      dprintf((stderr, "cache IP: %s\n", N_STR(ipstr)));
4896
4897      // check that the cache file contained something
4898      if(ipstr != NULL)
4899      {
4900
4901        if(address == NULL || *address == '\0')
4902        {
4903#ifdef IF_LOOKUP
4904          struct sockaddr_in sin;
4905          int sock;
4906
4907          sock = socket(AF_INET, SOCK_STREAM, 0);
4908          if(get_if_addr(sock, interface, &sin) != 0)
4909          {
4910            exit(1);
4911          }
4912          close(sock);
4913          snprintf(ipbuf, sizeof(ipbuf), "%s", inet_ntoa(sin.sin_addr));
4914#else
4915          show_message("interface lookup not enabled at compile time\n");
4916          exit(1);
4917#endif
4918        }
4919        else
4920        {
4921          snprintf(ipbuf, sizeof(ipbuf), "%s", address);
4922        }
4923
4924        // check for a change in the IP
4925        if(strcmp(ipstr, ipbuf) == 0)
4926        {
4927          dprintf((stderr, "cache IP doesn't need updating\n"));
4928          need_update = 0;
4929        }
4930
4931        // check the date
4932        if(max_interval > 0)
4933        {
4934          if(time(NULL) - ipdate > max_interval)
4935          {
4936            dprintf((stderr, "cache IP is passed max_interval of %d\n", max_interval));
4937            need_update = 1;
4938          }
4939        }
4940      }
4941      if(ipstr) { free(ipstr); ipstr = NULL; }
4942    }
4943
4944    if(need_update)
4945    {
4946      int res;
4947
4948      if(address == NULL && interface != NULL)
4949      {
4950        struct sockaddr_in sin;
4951        int sock;
4952
4953        sock = socket(AF_INET, SOCK_STREAM, 0);
4954        if(get_if_addr(sock, interface, &sin) == 0)
4955        {
4956          if(address) { free(address); }
4957          address = strdup(inet_ntoa(sin.sin_addr));
4958        }
4959        else
4960        {
4961          show_message("could not resolve ip address for %s.\n", interface);
4962          exit(1);
4963        }
4964        close(sock);
4965      }
4966
4967      for(i=0; i<ntrys; i++)
4968      {
4969        if(service->update_entry() == UPDATERES_OK)
4970        {
4971          retval = 0;
4972          break;
4973        }
4974        if(i+1 != ntrys) { sleep(10 + 10*i); }
4975      }
4976
4977      // write cache file
4978      if(retval == 0 && cache_file)
4979      {
4980        char ipbuf[64];
4981
4982        if(address == NULL || *address == '\0')
4983        {
4984#ifdef IF_LOOKUP
4985          struct sockaddr_in sin;
4986          int sock;
4987
4988          sock = socket(AF_INET, SOCK_STREAM, 0);
4989          if(get_if_addr(sock, interface, &sin) != 0)
4990          {
4991            exit(1);
4992          }
4993          close(sock);
4994          snprintf(ipbuf, sizeof(ipbuf), "%s", inet_ntoa(sin.sin_addr));
4995#else
4996          show_message("interface lookup not enabled at compile time\n");
4997          exit(1);
4998#endif
4999        }
5000        else
5001        {
5002          snprintf(ipbuf, sizeof(ipbuf), "%s", address);
5003        }
5004
5005        if(write_cache_file(cache_file, time(NULL), ipbuf) != 0)
5006        {
5007          show_message("unable to write cache file \"%s\": %s\n",
5008              cache_file, error_string);
5009          exit(1);
5010        }
5011      }
5012      if(retval == 0 && post_update_cmd)
5013      {
5014        if((res=exec_cmd(post_update_cmd)) != 0)
5015        {
5016          if(!(options & OPT_QUIET))
5017          {
5018            if(res == -1)
5019            {
5020              show_message("error running post update command: %s\n",
5021                  error_string);
5022            }
5023            else
5024            {
5025              show_message(
5026                  "error running post update command, command exit code: %d\n",
5027                  res);
5028            }
5029          }
5030        }
5031      }
5032    }
5033    else
5034    {
5035      show_message("no update needed at this time\n");
5036    }
5037  }
5038
5039//2007.03.14 Yau add
5040#ifdef ASUS_DDNS
5041exit_main:
5042#endif  // ASUS_DDNS
5043
5044#ifdef IF_LOOKUP
5045  if(sock > 0) { close(sock); }
5046#endif
5047
5048  if(address) { free(address); }
5049  if(cache_file) { free(cache_file); }
5050  if(config_file) { free(config_file); }
5051  if(host) { free(host); }
5052  if(interface) { free(interface); }
5053  if(mx) { free(mx); }
5054  if(port) { free(port); }
5055  if(request) { free(request); }
5056  if(request_over_ride) { free(request_over_ride); }
5057  if(server) { free(server); }
5058  if(url) { free(url); }
5059  if(partner) { free(partner); }
5060
5061  dprintf((stderr, "done\n"));
5062  return(retval);
5063}
5064
5065