]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/wx-console/console_thread.cpp
Fix my errors in specifying the configuration defaults:
[bacula/bacula] / bacula / src / wx-console / console_thread.cpp
1 /*
2  *
3  *    Interaction thread between director and the GUI
4  *
5  *    Nicolas Boichat, April 2004
6  *
7  *    Version $Id$
8  */
9 /*
10    Copyright (C) 2004-2005 Kern Sibbald
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License
14    version 2 as amended with additional clauses defined in the
15    file LICENSE in the main source directory.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
20    the file LICENSE for additional details.
21
22  */
23
24 // http://66.102.9.104/search?q=cache:Djc1mPF3hRoJ:cvs.sourceforge.net/viewcvs.py/audacity/audacity-src/src/AudioIO.cpp%3Frev%3D1.102+macos+x+wxthread&hl=fr
25
26 /* _("...") macro returns a wxChar*, so if we need a char*, we need to convert it with:
27  * wxString(_("...")).mb_str(*wxConvCurrent) */
28
29 #include "console_thread.h" // class's header file
30
31 #include <wx/wxprec.h>
32
33 #include <wx/thread.h>
34 #include <wx/file.h>
35
36 #include "console_conf.h"
37
38 #include "csprint.h"
39
40 #ifdef HAVE_WIN32
41 #include <windows.h>
42 char OK_msg[]   = "2000 OK\n";
43 char TERM_msg[] = "2999 Terminate\n";
44 #endif
45
46 /* Imported functions */
47 int authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons);
48
49 bool console_thread::inited = false;
50 bool console_thread::configloaded = false;
51 wxString console_thread::working_dir = wxT(".");
52
53 int numdir = 0;
54
55 /*
56  * Call-back for reading a passphrase for an encrypted PEM file
57  * This function uses getpass(), which uses a static buffer and is NOT thread-safe.
58  */
59 static int tls_pem_callback(char *buf, int size, const void *userdata)
60 {
61 #ifdef HAVE_TLS
62    const char *prompt = (const char *) userdata;
63    char *passwd;
64
65    passwd = getpass(prompt);
66    bstrncpy(buf, passwd, size);
67    return (strlen(buf));
68 #else
69    buf[0] = 0;
70    return 0;
71 #endif
72 }
73
74
75 /*
76  * Make a quick check to see that we have all the
77  * resources needed.
78  */
79 static int check_resources()
80 {
81    int xOK = true;
82    DIRRES *director;
83
84    LockRes();
85
86    numdir = 0;
87    foreach_res(director, R_DIRECTOR) {
88       numdir++;
89       /* tls_require implies tls_enable */
90       if (director->tls_require) {
91          if (have_tls) {
92             director->tls_enable = true;
93          } else {
94             Jmsg(NULL, M_FATAL, 0, wxString(_("TLS required but not configured in Bacula.\n")).mb_str(*wxConvCurrent));
95             xOK = false;
96             continue;
97          }
98       }
99
100       if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && director->tls_enable) {
101          Jmsg(NULL, M_FATAL, 0, wxString(_("Neither \"TLS CA Certificate\" or \"TLS CA Certificate Dir\" are defined for Director \"%s\" in config file.\nAt least one CA certificate store is required.\n")).mb_str(*wxConvCurrent),
102                              director->hdr.name);
103          xOK = false;
104       }
105    }
106    
107    if (numdir == 0) {
108       Jmsg(NULL, M_FATAL, 0, wxString(_("No Director resource defined in config file.\nWithout that I don't how to speak to the Director :-(\n")).mb_str(*wxConvCurrent));
109       xOK = false;
110    }
111
112    CONRES *cons;
113    /* Loop over Consoles */
114    foreach_res(cons, R_CONSOLE) {
115       /* tls_require implies tls_enable */
116       if (cons->tls_require) {
117          if (have_tls) {
118             cons->tls_enable = true;
119          } else {
120             Jmsg(NULL, M_FATAL, 0, wxString(_("TLS required but not configured in Bacula.\n")).mb_str(*wxConvCurrent));
121             xOK = false;
122             continue;
123          }
124       }
125
126       if ((!cons->tls_ca_certfile && !cons->tls_ca_certdir) && cons->tls_enable) {
127          Jmsg(NULL, M_FATAL, 0, wxString(_("Neither \"TLS CA Certificate\" or \"TLS CA Certificate Dir\" are defined for Console \"%s\" in config file.\n")).mb_str(*wxConvCurrent),
128                              cons->hdr.name);
129          xOK = false;
130       }
131    }
132    UnlockRes();
133    return xOK;
134 }
135
136
137 void console_thread::SetWorkingDirectory(wxString w_dir) {
138    if ((w_dir.Last() == '/') || (w_dir.Last() == '\\')) {
139       console_thread::working_dir = w_dir.Mid(0, w_dir.Length()-1);
140    }
141    else {
142       console_thread::working_dir = w_dir;
143    }
144 }
145
146 void console_thread::InitLib() {
147    if (WSA_Init() != 0) {
148       csprint(_("Error while initializing windows sockets...\n"));
149       inited = false;
150       return;
151    }
152    
153    init_stack_dump();
154    my_name_is(0, NULL, "wx-console");
155    working_directory = (const char*) console_thread::working_dir.GetData();
156    
157    inited = true;
158 }
159
160 void console_thread::FreeLib() {
161    if (inited) {
162       if (WSACleanup() != 0) {
163          csprint(_("Error while cleaning up windows sockets...\n"));
164       }
165    }
166 }
167
168 wxString errmsg;
169
170 /*
171  * Format a scanner error message
172  */
173 static void scan_err(const char *file, int line, LEX *lc, const char *msg, ...)
174 {
175    va_list arg_ptr;
176    char buf[MAXSTRING];
177    char more[MAXSTRING];
178    wxString err;
179    
180    va_start(arg_ptr, msg);
181    bvsnprintf(buf, sizeof(buf), msg, arg_ptr);
182    va_end(arg_ptr);
183
184    if (lc->line_no > lc->begin_line_no) {
185       bsnprintf(more, sizeof(more),
186                 wxString(_("Problem probably begins at line %d.\n")).mb_str(*wxConvCurrent), lc->begin_line_no);
187    } else {
188       more[0] = 0;
189    }
190
191    err.Format(_("Config error: %s\n            : line %d, col %d of file %s\n%s\n%s"),
192       buf, lc->line_no, lc->col_no, lc->fname, lc->line, more);
193      
194    errmsg << err; 
195 }
196
197 wxString console_thread::LoadConfig(wxString configfile) {
198    if (!inited) {
199       InitLib();
200       if (!inited)
201          return _("Error while initializing library.");
202    }
203    
204    free_config_resources();
205    
206    MSGS* msgs = (MSGS *)malloc(sizeof(MSGS));
207    memset(msgs, 0, sizeof(MSGS));
208    for (int i=1; i<=M_MAX; i++) {
209 #ifndef WIN32
210       add_msg_dest(msgs, MD_STDOUT, i, NULL, NULL);
211 #endif
212 //    add_msg_dest(msgs, MD_SYSLOG, i, NULL, NULL);
213       add_msg_dest(msgs, MD_CONSOLE, i, NULL, NULL);
214    }
215    
216    init_msg(NULL, msgs);
217    init_console_msg(console_thread::working_dir.mb_str(*wxConvCurrent));
218
219    errmsg = wxT("");
220    if (!parse_config(configfile.mb_str(*wxConvCurrent), &scan_err)) {
221       configloaded = false;
222       term_msg();
223       return errmsg;
224    }
225    
226    if (init_tls() != 0) {
227       Jmsg(NULL, M_ERROR_TERM, 0, wxString(_("TLS library initialization failed.\n")).mb_str(*wxConvCurrent));
228    }
229
230    if (!check_resources()) {
231       Jmsg(NULL, M_ERROR_TERM, 0, wxString(_("Please correct configuration file.\n")).mb_str(*wxConvCurrent));
232    }
233
234    term_msg();
235    wxRemoveFile(console_thread::working_dir + wxT("/wx-console.conmsg"));
236    init_msg(NULL, NULL);
237    
238    configloaded = true;
239    
240    return wxT("");
241 }
242
243 // class constructor
244 console_thread::console_thread() {
245    UA_sock = NULL;
246    choosingdirector = false;
247 }
248
249 // class destructor
250 console_thread::~console_thread() {
251    if (UA_sock) {
252       bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
253       bnet_close(UA_sock);
254       UA_sock = NULL;
255    }
256 }
257
258 /*
259  * Thread entry point
260  */
261 void* console_thread::Entry() {
262    /* It seems we must redefine the locale on each thread. */
263    wxLocale m_locale;
264    m_locale.Init();
265    m_locale.AddCatalog(wxT("bacula"));
266 #ifndef ENABLE_NLS
267 #undef LOCALEDIR
268 #define LOCALEDIR "."
269 #endif
270    wxLocale::AddCatalogLookupPathPrefix(wxT(LOCALEDIR));
271
272    DIRRES* dir;
273    if (!inited) {
274       csprint(_("Error : Library not initialized\n"));
275       csprint(NULL, CS_END);
276       csprint(NULL, CS_DISCONNECTED);
277       csprint(NULL, CS_TERMINATED);
278       #ifdef HAVE_WIN32
279          Exit();
280       #endif
281       return NULL;
282    }
283    
284    if (!configloaded) {
285       csprint(_("Error : No configuration file loaded\n"));
286       csprint(NULL, CS_END);
287       csprint(NULL, CS_DISCONNECTED);
288       csprint(NULL, CS_TERMINATED);
289       #ifdef HAVE_WIN32
290          Exit();
291       #endif
292       return NULL;
293    }
294    
295    csprint(_("Connecting...\n"));
296   
297    int count = 0;
298    DIRRES* res[16]; /* Maximum 16 directors */
299    
300    LockRes();
301    foreach_res(dir, R_DIRECTOR) {
302       res[count] = dir;
303       count++;
304       if (count == 16) {
305          break;
306       }
307    }
308    UnlockRes();
309    
310    if (count == 0) {
311       csprint(_("Error : No director defined in config file.\n"));
312       csprint(NULL, CS_END);
313       csprint(NULL, CS_DISCONNECTED);
314       csprint(NULL, CS_TERMINATED);
315       #ifdef HAVE_WIN32
316          Exit();
317       #endif
318       return NULL;
319    } else if (count == 1) {
320       directorchoosen = 1;
321    } else {
322       while (true) {
323          csprint(_("Multiple directors found in your config file.\n"));
324          for (int i = 0; i < count; i++) {
325             if (i < 9) {
326                csprint(wxString(wxT("    ")) << (i+1) << wxT(": ") << wxString(res[i]->hdr.name,*wxConvCurrent) << wxT("\n"));
327             }
328             else {
329                csprint(wxString(wxT("   ")) <<  (i+1) << wxT(": ") << wxString(res[i]->hdr.name,*wxConvCurrent) << wxT("\n"));
330             }
331          }
332          csprint(wxString::Format(_("Please choose a director (1-%d): "), count), CS_DATA);
333          csprint(NULL, CS_PROMPT);
334          choosingdirector = true;
335          directorchoosen = -1;
336          while(directorchoosen == -1) {
337             bmicrosleep(0, 2000);
338             Yield();
339          }      
340          choosingdirector = false;
341          if (directorchoosen != 0) {
342             break;
343          }
344       }
345    }
346    dir = res[directorchoosen-1];
347
348    memset(&jcr, 0, sizeof(jcr));
349    
350    jcr.dequeuing = 1; /* TODO: catch messages */
351
352    LockRes();
353    /* If cons==NULL, default console will be used */
354    CONRES *cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL);
355    UnlockRes();
356
357    char buf[1024];
358    /* Initialize Console TLS context */
359    if (cons && (cons->tls_enable || cons->tls_require)) {
360       /* Generate passphrase prompt */
361       bsnprintf(buf, sizeof(buf), wxString(_("Passphrase for Console \"%s\" TLS private key: ")).mb_str(*wxConvCurrent), cons->hdr.name);
362
363       /* Initialize TLS context:
364        * Args: CA certfile, CA certdir, Certfile, Keyfile,
365        * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
366       cons->tls_ctx = new_tls_context(cons->tls_ca_certfile,
367          cons->tls_ca_certdir, cons->tls_certfile,
368          cons->tls_keyfile, tls_pem_callback, &buf, NULL, true);
369
370       if (!cons->tls_ctx) {
371          bsnprintf(buf, sizeof(buf), wxString(_("Failed to initialize TLS context for Console \"%s\".\n")).mb_str(*wxConvCurrent),
372             dir->hdr.name);
373          csprint(buf);
374          return NULL;
375       }
376
377    }
378
379    /* Initialize Director TLS context */
380    if (dir->tls_enable || dir->tls_require) {
381       /* Generate passphrase prompt */
382       bsnprintf(buf, sizeof(buf), wxString(_("Passphrase for Director \"%s\" TLS private key: ")).mb_str(*wxConvCurrent), dir->hdr.name);
383
384       /* Initialize TLS context:
385        * Args: CA certfile, CA certdir, Certfile, Keyfile,
386        * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
387       dir->tls_ctx = new_tls_context(dir->tls_ca_certfile,
388          dir->tls_ca_certdir, dir->tls_certfile,
389          dir->tls_keyfile, tls_pem_callback, &buf, NULL, true);
390
391       if (!dir->tls_ctx) {
392          bsnprintf(buf, sizeof(buf), wxString(_("Failed to initialize TLS context for Director \"%s\".\n")).mb_str(*wxConvCurrent),
393             dir->hdr.name);
394          csprint(buf);
395          return NULL;
396       }
397    }
398
399
400    UA_sock = bnet_connect(&jcr, 3, 3, wxString(_("Director daemon")).mb_str(*wxConvCurrent),
401       dir->address, NULL, dir->DIRport, 0);
402       
403    if (UA_sock == NULL) {
404       csprint(_("Failed to connect to the director\n"));
405       csprint(NULL, CS_END);
406       csprint(NULL, CS_DISCONNECTED);
407       csprint(NULL, CS_TERMINATED);
408       #ifdef HAVE_WIN32
409          Exit();
410       #endif
411       return NULL;
412    }
413
414    csprint(_("Connected\n"));
415
416    jcr.dir_bsock = UA_sock;
417    if (!authenticate_director(&jcr, dir, cons)) {
418       csprint("ERR=");
419       csprint(UA_sock->msg);
420       csprint(NULL, CS_END);
421       csprint(NULL, CS_DISCONNECTED);
422       csprint(NULL, CS_TERMINATED);
423       #ifdef HAVE_WIN32
424          Exit();
425       #endif
426       return NULL;
427    }
428    
429    csprint(NULL, CS_CONNECTED);
430    
431    Write(".messages\n");
432
433    int stat;
434
435    /* main loop */
436    while(!TestDestroy()) {   /* Tests if thread has been ended */
437       if ((stat = bnet_recv(UA_sock)) >= 0) {
438          csprint(UA_sock->msg);
439       }
440       else if (stat == BNET_SIGNAL) {
441          if (UA_sock->msglen == BNET_PROMPT) {
442             csprint(NULL, CS_PROMPT);
443          }
444          else if (UA_sock->msglen == BNET_EOD) {
445             csprint(NULL, CS_END);
446          }
447          else if (UA_sock->msglen == BNET_HEARTBEAT) {
448             bnet_sig(UA_sock, BNET_HB_RESPONSE);
449             csprint(_("<< Heartbeat signal received, answered. >>\n"), CS_DEBUG);
450          }
451          else {
452             csprint(_("<< Unexpected signal received : "), CS_DEBUG);
453             csprint(bnet_sig_to_ascii(UA_sock), CS_DEBUG);
454             csprint(">>\n", CS_DEBUG);
455          }
456       }
457       else { /* BNET_HARDEOF || BNET_ERROR */
458          csprint(NULL, CS_END);
459          break;
460       }
461            
462       if (is_bnet_stop(UA_sock)) {
463          csprint(NULL, CS_END);
464          break;            /* error or term */
465       }
466    }
467    
468    csprint(NULL, CS_DISCONNECTED);
469
470    csprint(_("Connection terminated\n"));
471    
472    UA_sock = NULL;
473
474    csprint(NULL, CS_TERMINATED);
475
476    #ifdef HAVE_WIN32
477       Exit();
478    #endif
479    
480    return NULL;
481 }
482
483 void console_thread::Write(const char* str) 
484 {
485    if (UA_sock) {
486        UA_sock->msglen = strlen(str);
487        pm_strcpy(&UA_sock->msg, str);
488        bnet_send(UA_sock);
489    } else if (choosingdirector) {
490 //      wxString number = str;
491 //      number.RemoveLast(); /* Removes \n */
492       long val;
493       
494 //      if (number.ToLong(&val)) {
495       val = atol(str);
496       if (val) {
497          directorchoosen = (int)val;
498       } else {
499          directorchoosen = 0;
500       }
501    }
502 }
503
504 void console_thread::Delete() {
505    Write("quit\n");
506    if (UA_sock) {
507       bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
508       bnet_close(UA_sock);
509       UA_sock = NULL;
510       /*csprint(NULL, CS_END);
511       csprint(NULL, CS_DISCONNECTED);
512       csprint(NULL, CS_TERMINATED);*/
513    }
514 }