Imported Upstream version 3.3.3
[debian/amanda] / common-src / amservice.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-2000 University of Maryland at College Park
4  * Copyright (c) 2007-2012 Zmanda, Inc.  All Rights Reserved.
5  * All Rights Reserved.
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and its
8  * documentation for any purpose is hereby granted without fee, provided that
9  * the above copyright notice appear in all copies and that both that
10  * copyright notice and this permission notice appear in supporting
11  * documentation, and that the name of U.M. not be used in advertising or
12  * publicity pertaining to distribution of the software without specific,
13  * written prior permission.  U.M. makes no representations about the
14  * suitability of this software for any purpose.  It is provided "as is"
15  * without express or implied warranty.
16  *
17  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23  *
24  * Authors: the Amanda Development Team.  Its members are listed in a
25  * file named AUTHORS, in the root directory of this distribution.
26  */
27 /*
28  * $Id: amservice.c 11167 2008-05-06 11:53:54Z martineau $
29  *
30  * Take the REQ packet in stdin and output the REP packet in stdout
31  */
32 #include "amanda.h"
33 #include "util.h"
34 #include "conffile.h"
35 #include "packet.h"
36 #include "protocol.h"
37 #include "amfeatures.h"
38 #include "event.h"
39 #include "getopt.h"
40
41 static struct option long_options[] = {
42     {"version"         , 0, NULL,  1},
43     {NULL, 0, NULL, 0}
44 };
45
46 static int copy_stream = 0;
47 static time_t conf_ctimeout;
48 static am_feature_t *our_features = NULL;
49 static char *our_feature_string = NULL;
50 static int remote_errors = 0;
51 static event_handle_t *event_in;
52 static security_stream_t *fd;
53
54 /* local functions */
55
56 void usage(void);
57 void client_protocol(char *hostname, char *auth, char *service,
58                      FILE *input_file);
59 void client_first_stream(security_handle_t *sech, int port_num);
60 int main(int argc, char **argv);
61 static void read_in(void *cookie);
62 void aaa(void);
63 static void read_server(void *cookie, void *buf, ssize_t size);
64
65 void
66 usage(void)
67 {
68     error(_("Usage: amservice [--version] [-o configoption]* [-f input_file [-s]] host auth service"));
69     /*NOTREACHED*/
70 }
71
72 int
73 main(
74     int         argc,
75     char **     argv)
76 {
77     config_overrides_t *cfg_ovr;
78     char *hostname;
79     char *auth;
80     char *service;
81     int opt;
82     extern int optind;
83     extern char *optarg;
84     FILE *input_file;
85     int use_connect = 0;
86     int got_input_file = 0;
87
88     /*
89      * Configure program for internationalization:
90      *   1) Only set the message locale for now.
91      *   2) Set textdomain for all amanda related programs to "amanda"
92      *      We don't want to be forced to support dozens of message catalogs.
93      */  
94     setlocale(LC_MESSAGES, "C");
95     textdomain("amanda"); 
96
97     safe_fd(-1, 0);
98     safe_cd();
99
100     set_pname("amservice");
101     /* drop root privileges */
102     if (!set_root_privs(0)) {
103         error(_("amservice must be run setuid root"));
104     }
105
106     /* Don't die when child closes pipe */
107     signal(SIGPIPE, SIG_IGN);
108
109     dbopen(DBG_SUBDIR_SERVER);
110
111     add_amanda_log_handler(amanda_log_stderr);
112
113     our_features = am_init_feature_set();
114     our_feature_string = am_feature_to_string(our_features);
115
116     /* process arguments */
117
118     cfg_ovr = new_config_overrides(argc/2);
119     input_file = stdin;
120     while((opt = getopt_long(argc, argv, "o:f:s", long_options, NULL)) != EOF) {
121         switch(opt) {
122         case 1:         printf("amservice-%s\n", VERSION);
123                         return(0);
124                         break;
125         case 'o':       add_config_override_opt(cfg_ovr, optarg);
126                         break;
127         case 'f':       got_input_file = 1;
128                         if (*optarg == '/') {
129                             input_file = fopen(optarg, "r");
130                         } else {
131                             char *name = vstralloc(get_original_cwd(), "/",
132                                                    optarg, NULL);
133                             input_file = fopen(name, "r");
134                             amfree(name);
135                         }
136                         if (!input_file)
137                             g_critical("Cannot open output file '%s': %s",
138                                 optarg, strerror(errno));
139                         break;
140         case 's':       use_connect = 1;
141                         break;
142         }
143     }
144
145     if (use_connect && !got_input_file) {
146         g_critical("The -s option require -f");
147     }
148
149     argc -= optind, argv += optind;
150     if(argc < 3) usage();
151
152     /* set a default config */
153     set_config_overrides(cfg_ovr);
154     config_init(CONFIG_INIT_CLIENT, NULL);
155     dbrename(get_config_name(), DBG_SUBDIR_SERVER);
156
157     if (config_errors(NULL) >= CFGERR_WARNINGS) {
158         config_print_errors();
159         if (config_errors(NULL) >= CFGERR_ERRORS) {
160             g_critical(_("errors processing config file"));
161         }
162     }
163
164     conf_ctimeout = (time_t)getconf_int(CNF_CTIMEOUT);
165
166     hostname = argv[0];
167     auth = argv[1];
168     service = argv[2];
169
170     /* start client side checks */
171
172     copy_stream = use_connect && got_input_file;
173     client_protocol(hostname, auth, service, input_file);
174
175     amfree(our_feature_string);
176     am_release_feature_set(our_features);
177     our_features = NULL;
178
179     dbclose();
180     return(remote_errors != 0);
181 }
182
183 /* --------------------------------------------------- */
184
185 static void handle_result(void *, pkt_t *, security_handle_t *);
186 void start_host(char *hostname, char *auth, char *req);
187
188 void
189 start_host(
190     char        *hostname,
191     char        *auth,
192     char        *req)
193 {
194     const security_driver_t *secdrv;
195     secdrv = security_getdriver(auth);
196     if (secdrv == NULL) {
197         fprintf(stderr, _("Could not find security driver \"%s\".\n"), auth);
198     } else {
199         protocol_sendreq(hostname, secdrv, generic_client_get_security_conf,
200                          req, conf_ctimeout, handle_result, NULL);
201     }
202
203 }
204
205 void
206 client_protocol(
207     char        *hostname,
208     char        *auth,
209     char        *service,
210     FILE        *input_file)
211 {
212     char *req, *req1;
213
214     req = g_strdup_printf("SERVICE %s\nOPTIONS features=%s\n",
215                           service, our_feature_string);
216     req1 = malloc(1024);
217     while(fgets(req1, 1024, input_file) != NULL) {
218         vstrextend(&req, req1, NULL);
219     }
220     protocol_init();
221
222     start_host(hostname, auth, req);
223
224     protocol_run();
225
226     fflush(stdout);
227
228     amfree(our_feature_string);
229
230     return;
231 }
232
233 static void
234 handle_result(
235     void              *datap G_GNUC_UNUSED,
236     pkt_t             *pkt,
237     security_handle_t *sech)
238 {
239     char *line;
240     char *s;
241     int ch;
242     int port_num = 0;
243     int has_error = 0;
244
245     if (pkt == NULL) {
246         g_fprintf(stdout,
247                   _("Request failed: %s\n"), security_geterror(sech));
248         remote_errors++;
249         return;
250     }
251
252     s = pkt->body;
253     ch = *s++;
254     while(ch) {
255         line = s - 1;
256         skip_quoted_line(s, ch);
257         if (s[-2] == '\n') {
258             s[-2] = '\0';
259         }
260
261         if (copy_stream) {
262             g_debug("REP: %s\n", line);
263         } else {
264             fprintf(stdout, "%s\n", line);
265         }
266         if (strncmp(line, "CONNECT ", 8) == 0) {
267             char *port = strchr(line, ' ');
268             if (port) {
269                 port = strchr(port+1, ' ');
270                 if (port) {
271                     port_num = atoi(port+1);
272                 }
273             }
274         } else if (strncmp(line, "ERROR ", 6) == 0) {
275             if (copy_stream) {
276                 fprintf(stdout, "%s\n", line);
277             }
278             has_error++;
279         }
280     }
281
282     if (has_error)
283         return;
284
285     if (copy_stream) {
286         client_first_stream(sech, port_num);
287     } else {
288         fprintf(stdout, "\n");
289     }
290
291 }
292
293 void
294 client_first_stream(
295     security_handle_t *sech,
296     int port_num)
297 {
298
299     if (port_num == 0) {
300         g_critical("The service did not ask to open stream, do not use '-s' with that service");
301     }
302
303     fd = security_stream_client(sech, port_num);
304     if (!fd) {
305         g_critical("Could not connect to stream: %s\n", security_stream_geterror(fd));
306     }
307     if (security_stream_auth(fd) < 0) {
308         g_critical("could not authenticate stream: %s\n", security_stream_geterror(fd));
309     }
310
311     printf("Connected\n");
312     /* read from stdin */
313     event_in = event_register((event_id_t)0, EV_READFD, read_in, NULL);
314
315     /* read from connected stream */
316     security_stream_read(fd, read_server, NULL);
317 }
318
319
320 static void
321 read_in(
322     void *cookie G_GNUC_UNUSED)
323 {
324     size_t nread;
325     char   buf[1025];
326
327     nread = read(0, buf, 1024);
328     if (nread <= 0) {
329         event_release(event_in);
330         security_stream_close(fd);
331         return;
332     }
333
334     buf[nread] = '\0';
335     security_stream_write(fd, buf, nread);
336 }
337
338 static void
339 read_server(
340     void *      cookie G_GNUC_UNUSED,
341     void *      buf,
342     ssize_t     size)
343 {
344     switch (size) {
345     case -1:
346     case  0: security_stream_close(fd);
347              event_release(event_in);
348              break;
349     default:
350         full_write(1, buf, size);
351         if (errno > 0) {
352             g_debug("failed to write to stdout: %s", strerror(errno));
353         }
354         break;
355     }
356 }