Imported Upstream version 3.3.0
[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
39 static int copy_stream = 0;
40 static time_t conf_ctimeout;
41 static am_feature_t *our_features = NULL;
42 static char *our_feature_string = NULL;
43 static int remote_errors = 0;
44 static event_handle_t *event_in;
45 static security_stream_t *fd;
46
47 /* local functions */
48
49 void usage(void);
50 void client_protocol(char *hostname, char *auth, char *service,
51                      FILE *input_file);
52 void client_first_stream(security_handle_t *sech, int port_num);
53 int main(int argc, char **argv);
54 static void read_in(void *cookie);
55 void aaa(void);
56 static void read_server(void *cookie, void *buf, ssize_t size);
57
58 void
59 usage(void)
60 {
61     error(_("Usage: amservice [-o configoption]* [-f input_file [-s]] host auth service"));
62     /*NOTREACHED*/
63 }
64
65 int
66 main(
67     int         argc,
68     char **     argv)
69 {
70     config_overrides_t *cfg_ovr;
71     char *hostname;
72     char *auth;
73     char *service;
74     int opt;
75     extern int optind;
76     extern char *optarg;
77     FILE *input_file;
78     int use_connect = 0;
79     int got_input_file = 0;
80
81     /*
82      * Configure program for internationalization:
83      *   1) Only set the message locale for now.
84      *   2) Set textdomain for all amanda related programs to "amanda"
85      *      We don't want to be forced to support dozens of message catalogs.
86      */  
87     setlocale(LC_MESSAGES, "C");
88     textdomain("amanda"); 
89
90     safe_fd(-1, 0);
91     safe_cd();
92
93     set_pname("amservice");
94     /* drop root privileges */
95     if (!set_root_privs(0)) {
96         error(_("amservice must be run setuid root"));
97     }
98
99     /* Don't die when child closes pipe */
100     signal(SIGPIPE, SIG_IGN);
101
102     dbopen(DBG_SUBDIR_SERVER);
103
104     add_amanda_log_handler(amanda_log_stderr);
105
106     our_features = am_init_feature_set();
107     our_feature_string = am_feature_to_string(our_features);
108
109     /* process arguments */
110
111     cfg_ovr = new_config_overrides(argc/2);
112     input_file = stdin;
113     while((opt = getopt(argc, argv, "o:f:s")) != EOF) {
114         switch(opt) {
115         case 'o':       add_config_override_opt(cfg_ovr, optarg);
116                         break;
117         case 'f':       got_input_file = 1;
118                         if (*optarg == '/') {
119                             input_file = fopen(optarg, "r");
120                         } else {
121                             char *name = vstralloc(get_original_cwd(), "/",
122                                                    optarg, NULL);
123                             input_file = fopen(name, "r");
124                             amfree(name);
125                         }
126                         if (!input_file)
127                             g_critical("Cannot open output file '%s': %s",
128                                 optarg, strerror(errno));
129                         break;
130         case 's':       use_connect = 1;
131                         break;
132         }
133     }
134
135     if (use_connect && !got_input_file) {
136         g_critical("The -s option require -f");
137     }
138
139     argc -= optind, argv += optind;
140     if(argc < 3) usage();
141
142     /* set a default config */
143     set_config_overrides(cfg_ovr);
144     config_init(CONFIG_INIT_CLIENT, NULL);
145     dbrename(get_config_name(), DBG_SUBDIR_SERVER);
146
147     if (config_errors(NULL) >= CFGERR_WARNINGS) {
148         config_print_errors();
149         if (config_errors(NULL) >= CFGERR_ERRORS) {
150             g_critical(_("errors processing config file"));
151         }
152     }
153
154     conf_ctimeout = (time_t)getconf_int(CNF_CTIMEOUT);
155
156     hostname = argv[0];
157     auth = argv[1];
158     service = argv[2];
159
160     /* start client side checks */
161
162     copy_stream = use_connect && got_input_file;
163     client_protocol(hostname, auth, service, input_file);
164
165     amfree(our_feature_string);
166     am_release_feature_set(our_features);
167     our_features = NULL;
168
169     dbclose();
170     return(remote_errors != 0);
171 }
172
173 /* --------------------------------------------------- */
174
175 static void handle_result(void *, pkt_t *, security_handle_t *);
176 void start_host(char *hostname, char *auth, char *req);
177
178 void
179 start_host(
180     char        *hostname,
181     char        *auth,
182     char        *req)
183 {
184     const security_driver_t *secdrv;
185     secdrv = security_getdriver(auth);
186     if (secdrv == NULL) {
187         fprintf(stderr, _("Could not find security driver \"%s\".\n"), auth);
188     } else {
189         protocol_sendreq(hostname, secdrv, generic_client_get_security_conf,
190                          req, conf_ctimeout, handle_result, NULL);
191     }
192
193 }
194
195 void
196 client_protocol(
197     char        *hostname,
198     char        *auth,
199     char        *service,
200     FILE        *input_file)
201 {
202     char *req, *req1;
203
204     req = g_strdup_printf("SERVICE %s\nOPTIONS features=%s\n",
205                           service, our_feature_string);
206     req1 = malloc(1024);
207     while(fgets(req1, 1024, input_file) != NULL) {
208         vstrextend(&req, req1, NULL);
209     }
210     protocol_init();
211
212     start_host(hostname, auth, req);
213
214     protocol_run();
215
216     fflush(stdout);
217
218     amfree(our_feature_string);
219
220     return;
221 }
222
223 static void
224 handle_result(
225     void              *datap G_GNUC_UNUSED,
226     pkt_t             *pkt,
227     security_handle_t *sech)
228 {
229     char *line;
230     char *s;
231     int ch;
232     int port_num = 0;
233     int has_error = 0;
234
235     if (pkt == NULL) {
236         g_fprintf(stdout,
237                   _("Request failed: %s\n"), security_geterror(sech));
238         remote_errors++;
239         return;
240     }
241
242     s = pkt->body;
243     ch = *s++;
244     while(ch) {
245         line = s - 1;
246         skip_quoted_line(s, ch);
247         if (s[-2] == '\n') {
248             s[-2] = '\0';
249         }
250
251         if (copy_stream) {
252             g_debug("REP: %s\n", line);
253         } else {
254             fprintf(stdout, "%s\n", line);
255         }
256         if (strncmp(line, "CONNECT ", 8) == 0) {
257             char *port = strchr(line, ' ');
258             if (port) {
259                 port = strchr(port+1, ' ');
260                 if (port) {
261                     port_num = atoi(port+1);
262                 }
263             }
264         } else if (strncmp(line, "ERROR ", 6) == 0) {
265             if (copy_stream) {
266                 fprintf(stdout, "%s\n", line);
267             }
268             has_error++;
269         }
270     }
271
272     if (has_error)
273         return;
274
275     if (copy_stream) {
276         client_first_stream(sech, port_num);
277     } else {
278         fprintf(stdout, "\n");
279     }
280
281 }
282
283 void
284 client_first_stream(
285     security_handle_t *sech,
286     int port_num)
287 {
288
289     if (port_num == 0) {
290         g_critical("The service did not ask to open stream, do not use '-s' with that service");
291     }
292
293     fd = security_stream_client(sech, port_num);
294     if (!fd) {
295         g_critical("Could not connect to stream: %s\n", security_stream_geterror(fd));
296     }
297     if (security_stream_auth(fd) < 0) {
298         g_critical("could not authenticate stream: %s\n", security_stream_geterror(fd));
299     }
300
301     printf("Connected\n");
302     /* read from stdin */
303     event_in = event_register((event_id_t)0, EV_READFD, read_in, NULL);
304
305     /* read from connected stream */
306     security_stream_read(fd, read_server, NULL);
307 }
308
309
310 static void
311 read_in(
312     void *cookie G_GNUC_UNUSED)
313 {
314     size_t nread;
315     char   buf[1024];
316
317     event_release(event_in);
318     nread = read(0, buf, 1024);
319     if (nread == 0) {
320         security_stream_close(fd);
321         return;
322     }
323
324     buf[nread] = '\0';
325     security_stream_write(fd, buf, nread);
326     event_in = event_register((event_id_t)0, EV_READFD, read_in, NULL);
327 }
328
329 static void
330 read_server(
331     void *      cookie G_GNUC_UNUSED,
332     void *      buf,
333     ssize_t     size)
334 {
335     switch (size) {
336     case -1:
337     case  0: security_stream_close(fd);
338              event_release(event_in);
339              break;
340     default:
341         full_write(1, buf, size);
342         if (errno > 0) {
343             g_debug("failed to write to stdout: %s", strerror(errno));
344         }
345         security_stream_read(fd, read_server, NULL);
346         break;
347     }
348 }