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