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