1 /* -- updatedd: libtzo.c --
2  *
3  * Copyright (C) 2004, 2005 Philipp Benner
4  *
5  * This file is part of UpdateDD - http://updatedd.philipp-benner.de.
6  *
7  * UpdateDD is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * any later version.
11  *
12  * UpdateDD is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with UpdateDD; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <ctype.h>
28 #include <unistd.h>
29 #include <getopt.h>
30 
31 #include <dprintf.h>
32 #include <get_connection.h>
33 #include <updatedd-exception.h>
34 #include <ret_codes.h>
35 #include <version.h>
36 
37 #include "libtzo.h"
38 
39 static void
print_usage(char * pname,FILE * fp)40 print_usage(char *pname, FILE *fp)
41 {
42 	(void)fprintf(fp,
43 		      "\nUsage: %s [...] %s -- [OPTION]... [USERNAME:PASSWORD] HOSTNAME\n\n",
44 		      pname, COLORED("tzo"));
45 	(void)fprintf(fp,
46 		      "For security reasons use the environment variable LOGIN instead of\n"
47 		      "passing the login information directly.\n\n"
48 
49 		      "Options:\n"
50 		      "   -4    --ipv4 <address>        ip address version 4\n"
51 		      "         --help                  print help and exit\n"
52 		      "         --version               display version information and exit\n\n"
53 
54 		      "WARNING: This plugin has never been tested due to the fact that\n"
55 		      "tzo.com is not free! If you are a registered tzo user please help\n"
56 		      "to complete this plugin.\n\n"
57 
58 		      "Report bugs to <"EMAIL">.\n\n");
59 
60 	return;
61 }
62 
63 static void
print_version(FILE * fp)64 print_version(FILE *fp)
65 {
66 
67 	(void)fprintf(fp,
68 		      "\n" PNAME " plugin for tzo.com version " VERSION ",\n"
69 		      "Copyright (C) 2005 Philipp Benner.\n"
70 		      HOMEPAGE "\n\n"
71 
72 		      "This is free software, and you are welcome to redistribute it\n"
73 		      "under certain conditions; see the source for copying conditions.\n"
74 		      "There is NO warranty; not even for MERCHANTABILITY or FITNESS\n"
75 		      "FOR A PARTICULAR PURPOSE.\n\n");
76 
77 	return;
78 
79 }
80 
81 static void
ret_msg(int mode,const char * fmt,...)82 ret_msg(int mode, const char *fmt, ...)
83 {
84 
85 	va_list az;
86 
87 	va_start(az, fmt);
88 	(void)vs_warn(ret_msg_buf, BUFSIZE, mode, fmt, az);
89 	va_end(az);
90 
91 	return;
92 
93 }
94 
95 int
dyndns(int argc,char * argv[])96 dyndns(int argc, char *argv[])
97 {
98 
99 	struct arguments args;
100 	const char *ptr;
101 	int s, ret;
102 
103 	(void)memset(&args, 0, sizeof(struct arguments));
104 
105 	if(get_flags(&args, argc, argv) != RET_OK) {
106 		return RET_WRONG_USAGE;
107 	}
108 
109 	s = get_connection(DYNDNSHOST, PORT, &ptr);
110 	if(s == -1) {
111 		ret_msg(HERR, "%s: %s", ptr, DYNDNSHOST);
112 		ret = RET_WARNING;
113 	} else {
114 		ret = update_dyndns(s, &args);
115                 if(ret == RET_OK) {
116                         ret = check_server_msg(s, args.hostname);
117                 }
118 		(void)close(s);
119 	}
120 
121 	return ret;
122 
123 }
124 
125 static int
get_flags(struct arguments * args,int argc,char * argv[])126 get_flags(struct arguments *args, int argc, char *argv[])
127 {
128 
129 	int c;
130 
131 	for(;;) {
132 
133 		int option_index = 0;
134 		static struct option long_options[] = {
135 			{ "ipv4",		1, 0, '4' },
136 			{ "help",		0, 0, 'h' },
137 			{ "version",		0, 0, 'v' },
138 			{ NULL,			0, 0, 0   }
139 		};
140 
141 		c = getopt_long(argc, argv, "4:",
142 				long_options, &option_index);
143 
144 		if(c == -1) break;
145 
146 		switch(c) {
147 		case '4':
148 			args->ipv4 = optarg;
149 			break;
150 		case 'h':
151 			print_usage(argv[ARGV_PNAME], stdout);
152 			exit(EXIT_SUCCESS);
153 		case 'v':
154 			print_version(stdout);
155 			exit(EXIT_SUCCESS);
156 		}
157 	}
158 
159 	switch(argc-optind) {
160         default:
161 		ret_msg(NONE, "wrong usage");
162 		return RET_WRONG_USAGE;
163 
164         case 2:
165 		args->login = getenv("LOGIN");
166 		if(args->login == NULL) {
167 			ret_msg(NONE,
168 				"environment variable LOGIN is empty");
169 			return RET_WRONG_USAGE;
170 		}
171 		break;
172         case 3:
173 		args->login = argv[ARGV_LOGIN];
174 	}
175 	args->hostname = argv[ARGV_HOSTNAME];
176 
177 	return RET_OK;
178 
179 }
180 
181 #define BUFFREE(name) BUFSIZE - strlen(name)
182 
183 static int
update_dyndns(int s,struct arguments * args)184 update_dyndns(int s, struct arguments *args)
185 {
186 
187 	char *user, *pass;
188 	char msg[BUFSIZE], server_msg[BUFSIZE];
189         int len = strlen(args->login), ret;
190         char login[len];
191 
192         strcpy(login, args->login);
193 	user = strtok(login, ":");
194 	pass = strtok(NULL, "");
195 
196         (void)snprintf(msg, BUFSIZE, "R %s,%s,%s",
197                        args->hostname,
198                        user, pass);
199 
200         if(args->ipv4) {
201                 (void)strncat(msg, ",", BUFFREE(msg));
202                 (void)strncat(msg, args->ipv4, BUFFREE(msg));
203         }
204 
205         (void)memset(server_msg, 0, BUFSIZE);
206         if(read(s, server_msg, BUFSIZE-1) == -1) {
207                 ret_msg(PERR, "%s: read() failed",
208                         args->hostname);
209                 ret = RET_ERROR;
210         } else {
211                 print_debug("Server Message: %s", server_msg);
212                 if(strstr(server_msg, "TZO/Linksys Update Server")) {
213                         print_debug("Message: %s\n", msg);
214                         (void)dprintf(s, "%s\r\n", msg);
215                         ret = RET_OK;
216                 } else {
217                         ret_msg(NONE, "%s: invalid server",
218                                 args->hostname);
219                         ret = RET_ERROR;
220                 }
221         }
222 
223 	return ret;
224 
225 }
226 
227 static int
check_server_msg(int s,const char * hostname)228 check_server_msg(int s, const char *hostname)
229 {
230 
231 	char server_msg[BUFSIZE];
232         int ret;
233 
234         (void)memset(server_msg, 0, BUFSIZE);
235         if((ret = read(s, server_msg, BUFSIZE-1)) != -1) {
236                 print_debug("Server Message: %s", server_msg);
237 
238                 ret_msg(NONE, "%s: %s",
239                         hostname, server_msg+3);
240                 if(strncmp(server_msg, "40", 2) == 0) {
241                         ret = RET_OK;
242                 } else {
243                         ret = RET_ERROR;
244                 }
245         } else {
246                 ret_msg(PERR, "%s: read() failed",
247                         hostname);
248                 ret = RET_ERROR;
249         }
250 
251         return ret;
252 
253 }
254