wks: Allow reading of --install-key arguments from stdin.
[gnupg.git] / common / percent.c
1 /* percent.c - Percent escaping
2  * Copyright (C) 2008, 2009 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * This file is free software; you can redistribute it and/or modify
7  * it under the terms of either
8  *
9  *   - the GNU Lesser General Public License as published by the Free
10  *     Software Foundation; either version 3 of the License, or (at
11  *     your option) any later version.
12  *
13  * or
14  *
15  *   - the GNU General Public License as published by the Free
16  *     Software Foundation; either version 2 of the License, or (at
17  *     your option) any later version.
18  *
19  * or both in parallel, as here.
20  *
21  * This file is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, see <https://www.gnu.org/licenses/>.
28  */
29
30 #include <config.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <ctype.h>
34 #include <assert.h>
35
36 #include "util.h"
37
38
39 /* Create a newly alloced string from STRING with all spaces and
40    control characters converted to plus signs or %xx sequences.  The
41    function returns the new string or NULL in case of a malloc
42    failure.
43
44    Note that we also escape the quote character to work around a bug
45    in the mingw32 runtime which does not correctly handle command line
46    quoting.  We correctly double the quote mark when calling a program
47    (i.e. gpg-protect-tool), but the pre-main code does not notice the
48    double quote as an escaped quote.  We do this also on POSIX systems
49    for consistency.  */
50 char *
51 percent_plus_escape (const char *string)
52 {
53   char *buffer, *p;
54   const char *s;
55   size_t length;
56
57   for (length=1, s=string; *s; s++)
58     {
59       if (*s == '+' || *s == '\"' || *s == '%'
60           || *(const unsigned char *)s < 0x20)
61         length += 3;
62       else
63         length++;
64     }
65
66   buffer = p = xtrymalloc (length);
67   if (!buffer)
68     return NULL;
69
70   for (s=string; *s; s++)
71     {
72       if (*s == '+' || *s == '\"' || *s == '%'
73           || *(const unsigned char *)s < 0x20)
74         {
75           snprintf (p, 4, "%%%02X", *(unsigned char *)s);
76           p += 3;
77         }
78       else if (*s == ' ')
79         *p++ = '+';
80       else
81         *p++ = *s;
82     }
83   *p = 0;
84
85   return buffer;
86
87 }
88
89
90 /* Create a newly alloced string from (DATA,DATALEN) with embedded
91  * Nuls quoted as %00.  The standard percent unescaping can be
92  * used to reverse this encoding.   */
93 char *
94 percent_data_escape (const void *data, size_t datalen)
95 {
96   char *buffer, *p;
97   const char *s;
98   size_t n, length;
99
100   for (length=1, s=data, n=datalen; n; s++, n--)
101     {
102       if (!*s || *s == '%')
103         length += 3;
104       else
105         length++;
106     }
107
108   buffer = p = xtrymalloc (length);
109   if (!buffer)
110     return NULL;
111
112   for (s=data, n=datalen; n; s++, n--)
113     {
114       if (!*s)
115         {
116           memcpy (p, "%00", 3);
117           p += 3;
118         }
119       else if (*s == '%')
120         {
121           memcpy (p, "%25", 3);
122           p += 3;
123         }
124       else
125         *p++ = *s;
126     }
127   *p = 0;
128
129   return buffer;
130
131 }
132
133
134 /* Do the percent and plus/space unescaping from STRING to BUFFER and
135    return the length of the valid buffer.  Plus unescaping is only
136    done if WITHPLUS is true.  An escaped Nul character will be
137    replaced by NULREPL.  */
138 static size_t
139 do_unescape (unsigned char *buffer, const unsigned char *string,
140              int withplus, int nulrepl)
141 {
142   unsigned char *p = buffer;
143
144   while (*string)
145     {
146       if (*string == '%' && string[1] && string[2])
147         {
148           string++;
149           *p = xtoi_2 (string);
150           if (!*p)
151             *p = nulrepl;
152           string++;
153         }
154       else if (*string == '+' && withplus)
155         *p = ' ';
156       else
157         *p = *string;
158       p++;
159       string++;
160     }
161
162   return (p - buffer);
163 }
164
165
166 /* Count space required after unescaping STRING.  Note that this will
167    never be larger than strlen (STRING).  */
168 static size_t
169 count_unescape (const unsigned char *string)
170 {
171   size_t n = 0;
172
173   while (*string)
174     {
175       if (*string == '%' && string[1] && string[2])
176         {
177           string++;
178           string++;
179         }
180       string++;
181       n++;
182     }
183
184   return n;
185 }
186
187
188 /* Helper.  */
189 static char *
190 do_plus_or_plain_unescape (const char *string, int withplus, int nulrepl)
191 {
192   size_t nbytes, n;
193   char *newstring;
194
195   nbytes = count_unescape (string);
196   newstring = xtrymalloc (nbytes+1);
197   if (newstring)
198     {
199       n = do_unescape (newstring, string, withplus, nulrepl);
200       assert (n == nbytes);
201       newstring[n] = 0;
202     }
203   return newstring;
204 }
205
206
207 /* Create a new allocated string from STRING with all "%xx" sequences
208    decoded and all plus signs replaced by a space.  Embedded Nul
209    characters are replaced by the value of NULREPL.  The function
210    returns the new string or NULL in case of a malloc failure.  */
211 char *
212 percent_plus_unescape (const char *string, int nulrepl)
213 {
214   return do_plus_or_plain_unescape (string, 1, nulrepl);
215 }
216
217
218 /* Create a new allocated string from STRING with all "%xx" sequences
219    decoded.  Embedded Nul characters are replaced by the value of
220    NULREPL.  The function returns the new string or NULL in case of a
221    malloc failure.  */
222 char *
223 percent_unescape (const char *string, int nulrepl)
224 {
225   return do_plus_or_plain_unescape (string, 0, nulrepl);
226 }
227
228
229 static size_t
230 do_unescape_inplace (char *string, int withplus, int nulrepl)
231 {
232   unsigned char *p, *p0;
233
234   p = p0 = string;
235   while (*string)
236     {
237       if (*string == '%' && string[1] && string[2])
238         {
239           string++;
240           *p = xtoi_2 (string);
241           if (!*p)
242             *p = nulrepl;
243           string++;
244         }
245       else if (*string == '+' && withplus)
246         *p = ' ';
247       else
248         *p = *string;
249       p++;
250       string++;
251     }
252
253   return (p - p0);
254 }
255
256
257 /* Perform percent and plus unescaping in STRING and return the new
258    valid length of the string.  Embedded Nul characters are replaced
259    by the value of NULREPL.  A terminating Nul character is not
260    inserted; the caller might want to call this function this way:
261
262       foo[percent_plus_unescape_inplace (foo, 0)] = 0;
263  */
264 size_t
265 percent_plus_unescape_inplace (char *string, int nulrepl)
266 {
267   return do_unescape_inplace (string, 1, nulrepl);
268 }
269
270
271 /* Perform percent unescaping in STRING and return the new valid
272    length of the string.  Embedded Nul characters are replaced by the
273    value of NULREPL.  A terminating Nul character is not inserted; the
274    caller might want to call this function this way:
275
276       foo[percent_unescape_inplace (foo, 0)] = 0;
277  */
278 size_t
279 percent_unescape_inplace (char *string, int nulrepl)
280 {
281   return do_unescape_inplace (string, 0, nulrepl);
282 }