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