]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_server.c
Fix segfault after the reload of an incorrect configuration
[bacula/bacula] / bacula / src / dird / ua_server.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2015 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is 
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *
21  *   Bacula Director -- User Agent Server
22  *
23  *     Kern Sibbald, September MM
24  *
25  */
26
27 #include "bacula.h"
28 #include "dird.h"
29
30 /* Imported variables */
31
32
33 /* Forward referenced functions */
34 extern "C" void *connect_thread(void *arg);
35 static void *handle_UA_client_request(void *arg);
36
37
38 /* Global variables */
39 static int started = FALSE;
40 static workq_t ua_workq;
41
42 struct s_addr_port {
43    char *addr;
44    char *port;
45 };
46
47 /* Called here by Director daemon to start UA (user agent)
48  * command thread. This routine creates the thread and then
49  * returns.
50  */
51 void start_UA_server(dlist *addrs)
52 {
53    pthread_t thid;
54    int status;
55    static dlist *myaddrs = addrs;
56
57    if ((status=pthread_create(&thid, NULL, connect_thread, (void *)myaddrs)) != 0) {
58       berrno be;
59       Emsg1(M_ABORT, 0, _("Cannot create UA thread: %s\n"), be.bstrerror(status));
60    }
61    started = TRUE;
62    return;
63 }
64
65 extern "C"
66 void *connect_thread(void *arg)
67 {
68    pthread_detach(pthread_self());
69    set_jcr_in_tsd(INVALID_JCR);
70
71    /* Permit MaxConsoleConnect console connections */
72    bnet_thread_server((dlist*)arg, director->MaxConsoleConnect, &ua_workq, handle_UA_client_request);
73    return NULL;
74 }
75
76 /*
77  * Create a Job Control Record for a control "job",
78  *   filling in all the appropriate fields.
79  */
80 JCR *new_control_jcr(const char *base_name, int job_type)
81 {
82    JCR *jcr;
83    jcr = new_jcr(sizeof(JCR), dird_free_jcr);
84    /*
85     * The job and defaults are not really used, but
86     *  we set them up to ensure that everything is correctly
87     *  initialized.
88     */
89    LockRes();
90    jcr->job = (JOB *)GetNextRes(R_JOB, NULL);
91    set_jcr_defaults(jcr, jcr->job);
92    /* We use a resource, so we should count in the reload */
93    jcr->setJobType(job_type);
94    UnlockRes();
95
96    jcr->sd_auth_key = bstrdup("dummy"); /* dummy Storage daemon key */
97    create_unique_job_name(jcr, base_name);
98    jcr->sched_time = jcr->start_time;
99    jcr->setJobLevel(L_NONE);
100    jcr->setJobStatus(JS_Running);
101    jcr->JobId = 0;
102    return jcr;
103 }
104
105 /*
106  * Handle Director User Agent commands
107  *
108  */
109 static void *handle_UA_client_request(void *arg)
110 {
111    int stat;
112    UAContext *ua;
113    JCR *jcr;
114    BSOCK *user = (BSOCK *)arg;
115
116    pthread_detach(pthread_self());
117
118    jcr = new_control_jcr("-Console-", JT_CONSOLE);
119
120    ua = new_ua_context(jcr);
121    ua->UA_sock = user;
122    set_jcr_in_tsd(INVALID_JCR);
123
124    user->recv();             /* Get first message */
125    if (!authenticate_user_agent(ua)) {
126       goto getout;
127    }
128
129    while (!ua->quit) {
130       if (ua->api) user->signal(BNET_MAIN_PROMPT);
131       stat = user->recv();
132       if (stat >= 0) {
133          pm_strcpy(ua->cmd, ua->UA_sock->msg);
134          parse_ua_args(ua);
135          if (ua->argc > 0 && ua->argk[0][0] == '.') {
136             do_a_dot_command(ua);
137          } else {
138             do_a_command(ua);
139          }
140          dequeue_messages(ua->jcr);
141          if (!ua->quit) {
142             if (console_msg_pending && acl_access_ok(ua, Command_ACL, "messages", 8)) {
143                if (ua->auto_display_messages) {
144                   pm_strcpy(ua->cmd, "messages");
145                   qmessagescmd(ua, ua->cmd);
146                   ua->user_notified_msg_pending = false;
147                } else if (!ua->gui && !ua->user_notified_msg_pending && console_msg_pending) {
148                   if (ua->api) {
149                      user->signal(BNET_MSGS_PENDING);
150                   } else {
151                      bsendmsg(ua, _("You have messages.\n"));
152                   }
153                   ua->user_notified_msg_pending = true;
154                }
155             }
156             if (!ua->api) user->signal(BNET_EOD);     /* send end of command */
157          }
158       } else if (user->is_stop()) {
159          ua->quit = true;
160       } else { /* signal */
161          user->signal(BNET_POLL);
162       }
163
164       /* At the end of each command, revert to the main shared SQL link */
165       ua->db = ua->shared_db;
166    }
167
168 getout:
169    close_db(ua);
170    free_ua_context(ua);
171    free_jcr(jcr);
172
173    return NULL;
174 }
175
176 /*
177  * Create a UAContext for a Job that is running so that
178  *   it can the User Agent routines and
179  *   to ensure that the Job gets the proper output.
180  *   This is a sort of mini-kludge, and should be
181  *   unified at some point.
182  */
183 UAContext *new_ua_context(JCR *jcr)
184 {
185    UAContext *ua;
186
187    ua = (UAContext *)malloc(sizeof(UAContext));
188    memset(ua, 0, sizeof(UAContext));
189    ua->jcr = jcr;
190    ua->shared_db = ua->db = jcr->db;
191    ua->cmd = get_pool_memory(PM_FNAME);
192    ua->args = get_pool_memory(PM_FNAME);
193    ua->errmsg = get_pool_memory(PM_FNAME);
194    ua->verbose = true;
195    ua->automount = true;
196    return ua;
197 }
198
199 void free_ua_context(UAContext *ua)
200 {
201    if (ua->cmd) {
202       free_pool_memory(ua->cmd);
203    }
204    if (ua->args) {
205       free_pool_memory(ua->args);
206    }
207    if (ua->errmsg) {
208       free_pool_memory(ua->errmsg);
209    }
210    if (ua->prompt) {
211       free(ua->prompt);
212    }
213    if (ua->unique) {
214       free(ua->unique);
215    }
216    free_bsock(ua->UA_sock);
217    free(ua);
218 }
219
220
221 /*
222  * Called from main Bacula thread
223  */
224 void term_ua_server()
225 {
226    if (!started) {
227       return;
228    }
229 }