1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2001-2010 Free Software Foundation Europe e.V.
5 Copyright (C) 2016-2017 Bareos GmbH & Co. KG
6
7 This program is Free Software; you can redistribute it and/or
8 modify it under the terms of version three of the GNU Affero General Public
9 License as published by the Free Software Foundation and included
10 in the file LICENSE.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Affero General Public License for more details.
16
17 You should have received a copy of the GNU Affero General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301, USA.
21 */
22 /*
23 * Kern Sibbald, October MMI
24 */
25 /**
26 * @file
27 * User Agent Input and scanning code
28 */
29
30 #include "include/bareos.h"
31 #include "dird.h"
32 #include "dird/ua_input.h"
33 #include "dird/ua_cmds.h"
34 #include "dird/ua_select.h"
35 #include "lib/bnet.h"
36 #include "lib/edit.h"
37
38 namespace directordaemon {
39
40 /* Imported variables */
41
42 /* Exported functions */
43
44 /**
45 * If subprompt is set, we send a BNET_SUB_PROMPT signal otherwise
46 * send a BNET_TEXT_INPUT signal.
47 */
GetCmd(UaContext * ua,const char * prompt,bool subprompt)48 bool GetCmd(UaContext* ua, const char* prompt, bool subprompt)
49 {
50 int status;
51 BareosSocket* sock = ua->UA_sock;
52
53 ua->cmd[0] = 0;
54 if (!sock || ua->batch) { /* No UA or batch mode */
55 return false;
56 }
57 if (!subprompt && ua->api) { sock->signal(BNET_TEXT_INPUT); }
58 ua->SendMsg("%s", prompt);
59 if (!ua->api || subprompt) { sock->signal(BNET_SUB_PROMPT); }
60 for (;;) {
61 status = sock->recv();
62 if (status == BNET_SIGNAL) { continue; /* ignore signals */ }
63 if (IsBnetStop(sock)) { return false; /* error or Terminate */ }
64 PmStrcpy(ua->cmd, sock->msg);
65 StripTrailingJunk(ua->cmd);
66 if (bstrcmp(ua->cmd, ".messages")) { DotMessagesCmd(ua, ua->cmd); }
67 /* Lone dot => break */
68 if (ua->cmd[0] == '.' && ua->cmd[1] == 0) { return false; }
69 break;
70 }
71 return true;
72 }
73
74 /**
75 * Get a positive integer
76 * Returns: false if failure
77 * true if success => value in ua->pint32_val
78 */
GetPint(UaContext * ua,const char * prompt)79 bool GetPint(UaContext* ua, const char* prompt)
80 {
81 double dval;
82 ua->pint32_val = 0;
83 ua->int64_val = 0;
84 for (;;) {
85 ua->cmd[0] = 0;
86 if (!GetCmd(ua, prompt)) { return false; }
87 /* Kludge for slots blank line => 0 */
88 if (ua->cmd[0] == 0 &&
89 bstrncmp(prompt, _("Enter slot"), strlen(_("Enter slot")))) {
90 return true;
91 }
92 if (!Is_a_number(ua->cmd)) {
93 ua->WarningMsg(_("Expected a positive integer, got: %s\n"), ua->cmd);
94 continue;
95 }
96 errno = 0;
97 dval = strtod(ua->cmd, NULL);
98 if (errno != 0 || dval < 0) {
99 ua->WarningMsg(_("Expected a positive integer, got: %s\n"), ua->cmd);
100 continue;
101 }
102 ua->pint32_val = (uint32_t)dval;
103 ua->int64_val = (int64_t)dval;
104 return true;
105 }
106 }
107
108 /**
109 * Test a yes or no response
110 * Returns: false if failure
111 * true if success => ret == true for yes
112 * ret == false for no
113 */
IsYesno(char * val,bool * ret)114 bool IsYesno(char* val, bool* ret)
115 {
116 *ret = 0;
117 if (Bstrcasecmp(val, _("yes")) || Bstrcasecmp(val, NT_("yes"))) {
118 *ret = true;
119 } else if (Bstrcasecmp(val, _("no")) || Bstrcasecmp(val, NT_("no"))) {
120 *ret = false;
121 } else {
122 return false;
123 }
124
125 return true;
126 }
127
128 /**
129 * Gets a yes or no response
130 * Returns: false if failure
131 * true if success => ua->pint32_val == 1 for yes
132 * ua->pint32_val == 0 for no
133 */
GetYesno(UaContext * ua,const char * prompt)134 bool GetYesno(UaContext* ua, const char* prompt)
135 {
136 int len;
137 bool ret;
138
139 ua->pint32_val = 0;
140 for (;;) {
141 if (ua->api) { ua->UA_sock->signal(BNET_YESNO); }
142
143 if (!GetCmd(ua, prompt)) { return false; }
144
145 len = strlen(ua->cmd);
146 if (len < 1 || len > 3) { continue; }
147
148 if (IsYesno(ua->cmd, &ret)) {
149 ua->pint32_val = ret;
150 return true;
151 }
152
153 ua->WarningMsg(_("Invalid response. You must answer yes or no.\n"));
154 }
155 }
156
157 /**
158 * Checks for "yes" cmd parameter.
159 * If not given, display prompt and gets user input "yes" or "no".
160 *
161 * Returns: true if cmd parameter "yes" is given
162 * or user enters "yes"
163 * false otherwise
164 */
GetConfirmation(UaContext * ua,const char * prompt)165 bool GetConfirmation(UaContext* ua, const char* prompt)
166 {
167 if (FindArg(ua, NT_("yes")) >= 0) { return true; }
168
169 if (ua->api || ua->batch) { return false; }
170
171 if (GetYesno(ua, prompt)) { return (ua->pint32_val == 1); }
172
173 return false;
174 }
175
176 /**
177 * Gets an Enabled value => 0, 1, 2, yes, no, archived
178 * Returns: 0, 1, 2 if OK
179 * -1 on error
180 */
GetEnabled(UaContext * ua,const char * val)181 int GetEnabled(UaContext* ua, const char* val)
182 {
183 int Enabled = -1;
184
185 if (Bstrcasecmp(val, "yes") || Bstrcasecmp(val, "true")) {
186 Enabled = VOL_ENABLED;
187 } else if (Bstrcasecmp(val, "no") || Bstrcasecmp(val, "false")) {
188 Enabled = VOL_NOT_ENABLED;
189 } else if (Bstrcasecmp(val, "archived")) {
190 Enabled = VOL_ARCHIVED;
191 } else {
192 Enabled = atoi(val);
193 }
194
195 if (Enabled < 0 || Enabled > 2) {
196 ua->ErrorMsg(
197 _("Invalid Enabled value, it must be yes, no, archived, 0, 1, or 2\n"));
198 return -1;
199 }
200
201 return Enabled;
202 }
203
ParseUaArgs(UaContext * ua)204 void ParseUaArgs(UaContext* ua)
205 {
206 ParseArgs(ua->cmd, ua->args, &ua->argc, ua->argk, ua->argv, MAX_CMD_ARGS);
207 }
208
209 /**
210 * Check if the comment has legal characters
211 * If ua is non-NULL send the message
212 */
IsCommentLegal(UaContext * ua,const char * name)213 bool IsCommentLegal(UaContext* ua, const char* name)
214 {
215 int len;
216 const char* p;
217 const char* forbid = "'<>&\\\"";
218
219 /* Restrict the characters permitted in the comment */
220 for (p = name; *p; p++) {
221 if (!strchr(forbid, (int)(*p))) { continue; }
222 if (ua) { ua->ErrorMsg(_("Illegal character \"%c\" in a comment.\n"), *p); }
223 return 0;
224 }
225 len = strlen(name);
226 if (len >= MAX_NAME_LENGTH) {
227 if (ua) { ua->ErrorMsg(_("Comment too long.\n")); }
228 return 0;
229 }
230 if (len == 0) {
231 if (ua) {
232 ua->ErrorMsg(_("Comment must be at least one character long.\n"));
233 }
234 return 0;
235 }
236 return 1;
237 }
238 } /* namespace directordaemon */
239