common/iobuf.c: Combine iobuf_open, iobuf_create and iobuf_openrw.
[gnupg.git] / common / userids.c
1 /* userids.c - Utility functions for user ids.
2  * Copyright (C) 2001, 2003, 2004, 2006,
3  *               2009 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * This file is free software; you can redistribute it and/or modify
8  * it under the terms of either
9  *
10  *   - the GNU Lesser General Public License as published by the Free
11  *     Software Foundation; either version 3 of the License, or (at
12  *     your option) any later version.
13  *
14  * or
15  *
16  *   - the GNU General Public License as published by the Free
17  *     Software Foundation; either version 2 of the License, or (at
18  *     your option) any later version.
19  *
20  * or both in parallel, as here.
21  *
22  * This file is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, see <http://www.gnu.org/licenses/>.
29  */
30
31 #include <config.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "util.h"
37 #include "userids.h"
38
39
40 /* Parse the user-id NAME and build a search description for it.
41  * Returns 0 on success or an error code.  DESC may be NULL to merely
42  * check the validity of a user-id.
43  *
44  * Some used rules:
45  * - If the username starts with 8,9,16 or 17 hex-digits (the first one
46  *   must be in the range 0..9), this is considered a keyid; depending
47  *   on the length a short or complete one.
48  * - If the username starts with 32,33,40 or 41 hex-digits (the first one
49  *   must be in the range 0..9), this is considered a fingerprint.
50  * - If the username starts with a left angle, we assume it is a complete
51  *   email address and look only at this part.
52  * - If the username starts with a colon we assume it is a unified
53  *   key specfification.
54  * - If the username starts with a '.', we assume it is the ending
55  *   part of an email address
56  * - If the username starts with an '@', we assume it is a part of an
57  *   email address
58  * - If the userid start with an '=' an exact compare is done.
59  * - If the userid starts with a '*' a case insensitive substring search is
60  *   done (This is the default).
61  * - If the userid starts with a '+' we will compare individual words
62  *   and a match requires that all the words are in the userid.
63  *   Words are delimited by white space or "()<>[]{}.@-+_,;/&!"
64  *   (note that you can't search for these characters). Compare
65  *   is not case sensitive.
66  * - If the userid starts with a '&' a 40 hex digits keygrip is expected.
67  */
68
69 gpg_error_t
70 classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
71 {
72   const char *s;
73   int hexprefix = 0;
74   int hexlength;
75   int mode = 0;
76   KEYDB_SEARCH_DESC dummy_desc;
77
78   if (!desc)
79     desc = &dummy_desc;
80
81   /* Clear the structure so that the mode field is set to zero unless
82      we set it to the correct value right at the end of this
83      function. */
84   memset (desc, 0, sizeof *desc);
85
86   /* Skip leading spaces.  */
87   for(s = name; *s && spacep (s); s++ )
88     ;
89
90   switch (*s)
91     {
92     case 0:  /* Empty string is an error.  */
93       return gpg_error (GPG_ERR_INV_USER_ID);
94
95     case '.': /* An email address, compare from end.  Note that this
96                  has not yet been implemented in the search code.  */
97       mode = KEYDB_SEARCH_MODE_MAILEND;
98       s++;
99       desc->u.name = s;
100       break;
101
102     case '<': /* An email address.  */
103       mode = KEYDB_SEARCH_MODE_MAIL;
104       /* FIXME: The keyring code in g10 assumes that the mail name is
105          prefixed with an '<'.  However the keybox code used for sm/
106          assumes it has been removed.  For now we use this simple hack
107          to overcome the problem.  */
108       if (!openpgp_hack)
109         s++;
110       desc->u.name = s;
111       break;
112
113     case '@':  /* Part of an email address.  */
114       mode = KEYDB_SEARCH_MODE_MAILSUB;
115       s++;
116       desc->u.name = s;
117       break;
118
119     case '=':  /* Exact compare.  */
120       mode = KEYDB_SEARCH_MODE_EXACT;
121       s++;
122       desc->u.name = s;
123       break;
124
125     case '*':  /* Case insensitive substring search.  */
126       mode = KEYDB_SEARCH_MODE_SUBSTR;
127       s++;
128       desc->u.name = s;
129       break;
130
131     case '+':  /* Compare individual words.  Note that this has not
132                   yet been implemented in the search code.  */
133       mode = KEYDB_SEARCH_MODE_WORDS;
134       s++;
135       desc->u.name = s;
136       break;
137
138     case '/': /* Subject's DN.  */
139       s++;
140       if (!*s || spacep (s)) /* No DN or prefixed with a space.  */
141         return gpg_error (GPG_ERR_INV_USER_ID);
142       desc->u.name = s;
143       mode = KEYDB_SEARCH_MODE_SUBJECT;
144       break;
145
146     case '#': /* S/N with optional issuer id or just issuer id.  */
147       {
148         const char *si;
149
150         s++;
151         if ( *s == '/')
152           { /* "#/" indicates an issuer's DN.  */
153             s++;
154             if (!*s || spacep (s)) /* No DN or prefixed with a space.  */
155               return gpg_error (GPG_ERR_INV_USER_ID);
156             desc->u.name = s;
157             mode = KEYDB_SEARCH_MODE_ISSUER;
158           }
159         else
160           { /* Serialnumber + optional issuer ID.  */
161             for (si=s; *si && *si != '/'; si++)
162               {
163                  /* Check for an invalid digit in the serial number. */
164                 if (!strchr("01234567890abcdefABCDEF", *si))
165                   return gpg_error (GPG_ERR_INV_USER_ID);
166               }
167             desc->sn = (const unsigned char*)s;
168             desc->snlen = -1;
169             if (!*si)
170               mode = KEYDB_SEARCH_MODE_SN;
171             else
172               {
173                 s = si+1;
174                 if (!*s || spacep (s))  /* No DN or prefixed with a space.  */
175                   return gpg_error (GPG_ERR_INV_USER_ID);
176                 desc->u.name = s;
177                 mode = KEYDB_SEARCH_MODE_ISSUER_SN;
178               }
179           }
180       }
181       break;
182
183     case ':': /* Unified fingerprint. */
184       {
185         const char *se, *si;
186         int i;
187
188         se = strchr (++s,':');
189         if (!se)
190           return gpg_error (GPG_ERR_INV_USER_ID);
191         for (i=0,si=s; si < se; si++, i++ )
192           {
193             if (!strchr("01234567890abcdefABCDEF", *si))
194               return gpg_error (GPG_ERR_INV_USER_ID); /* Invalid digit.  */
195           }
196         if (i != 32 && i != 40)
197           return gpg_error (GPG_ERR_INV_USER_ID); /* Invalid length of fpr.  */
198         for (i=0,si=s; si < se; i++, si +=2)
199           desc->u.fpr[i] = hextobyte(si);
200         for (; i < 20; i++)
201           desc->u.fpr[i]= 0;
202         s = se + 1;
203         mode = KEYDB_SEARCH_MODE_FPR;
204       }
205       break;
206
207     case '&': /* Keygrip*/
208       {
209         if (hex2bin (s+1, desc->u.grip, 20) < 0)
210           return gpg_error (GPG_ERR_INV_USER_ID); /* Invalid. */
211         mode = KEYDB_SEARCH_MODE_KEYGRIP;
212       }
213       break;
214
215     default:
216       if (s[0] == '0' && s[1] == 'x')
217         {
218           hexprefix = 1;
219           s += 2;
220         }
221
222       hexlength = strspn(s, "0123456789abcdefABCDEF");
223       if (hexlength >= 8 && s[hexlength] =='!')
224         {
225           desc->exact = 1;
226           hexlength++; /* Just for the following check.  */
227         }
228
229       /* Check if a hexadecimal number is terminated by EOS or blank.  */
230       if (hexlength && s[hexlength] && !spacep (s+hexlength))
231         {
232           if (hexprefix) /* A "0x" prefix without a correct
233                             termination is an error.  */
234             return gpg_error (GPG_ERR_INV_USER_ID);
235           /* The first characters looked like a hex number, but the
236              entire string is not.  */
237           hexlength = 0;
238         }
239
240       if (desc->exact)
241         hexlength--; /* Remove the bang.  */
242
243       if (hexlength == 8
244           || (!hexprefix && hexlength == 9 && *s == '0'))
245         {
246           /* Short keyid.  */
247           if (hexlength == 9)
248             s++;
249           desc->u.kid[1] = strtoul( s, NULL, 16 );
250           mode = KEYDB_SEARCH_MODE_SHORT_KID;
251         }
252       else if (hexlength == 16
253                || (!hexprefix && hexlength == 17 && *s == '0'))
254         {
255           /* Long keyid.  */
256           char buf[9];
257           if (hexlength == 17)
258             s++;
259           mem2str (buf, s, 9);
260           desc->u.kid[0] = strtoul (buf, NULL, 16);
261           desc->u.kid[1] = strtoul (s+8, NULL, 16);
262           mode = KEYDB_SEARCH_MODE_LONG_KID;
263         }
264       else if (hexlength == 32
265                || (!hexprefix && hexlength == 33 && *s == '0'))
266         {
267           /* MD5 fingerprint.  */
268           int i;
269           if (hexlength == 33)
270             s++;
271           memset (desc->u.fpr+16, 0, 4);
272           for (i=0; i < 16; i++, s+=2)
273             {
274               int c = hextobyte(s);
275               if (c == -1)
276                 return gpg_error (GPG_ERR_INV_USER_ID);
277               desc->u.fpr[i] = c;
278             }
279           mode = KEYDB_SEARCH_MODE_FPR16;
280         }
281       else if (hexlength == 40
282                || (!hexprefix && hexlength == 41 && *s == '0'))
283         {
284           /* SHA1/RMD160 fingerprint.  */
285           int i;
286           if (hexlength == 41)
287             s++;
288           for (i=0; i < 20; i++, s+=2)
289             {
290               int c = hextobyte(s);
291               if (c == -1)
292                 return gpg_error (GPG_ERR_INV_USER_ID);
293               desc->u.fpr[i] = c;
294             }
295           mode = KEYDB_SEARCH_MODE_FPR20;
296         }
297       else if (!hexprefix)
298         {
299           /* The fingerprint in an X.509 listing is often delimited by
300              colons, so we try to single this case out. */
301           mode = 0;
302           hexlength = strspn (s, ":0123456789abcdefABCDEF");
303           if (hexlength == 59 && (!s[hexlength] || spacep (s+hexlength)))
304             {
305               int i;
306
307               for (i=0; i < 20; i++, s += 3)
308                 {
309                   int c = hextobyte(s);
310                   if (c == -1 || (i < 19 && s[2] != ':'))
311                     break;
312                   desc->u.fpr[i] = c;
313                 }
314               if (i == 20)
315                 mode = KEYDB_SEARCH_MODE_FPR20;
316             }
317           if (!mode)
318             {
319               /* Still not found.  Now check for a space separated
320                  OpenPGP v4 fingerprint like:
321                    8061 5870 F5BA D690 3336  86D0 F2AD 85AC 1E42 B367
322                  or
323                    8061 5870 F5BA D690 3336 86D0 F2AD 85AC 1E42 B367
324                */
325               hexlength = strspn (s, " 0123456789abcdefABCDEF");
326               if (s[hexlength] && s[hexlength] != ' ')
327                 hexlength = 0; /* Followed by non-space.  */
328               while (hexlength && s[hexlength-1] == ' ')
329                 hexlength--;   /* Trim trailing spaces.  */
330               if ((hexlength == 49 || hexlength == 50)
331                   && (!s[hexlength] || s[hexlength] == ' '))
332                 {
333                   int i, c;
334
335                   for (i=0; i < 20; i++)
336                     {
337                       if (i && !(i % 2))
338                         {
339                           if (*s != ' ')
340                             break;
341                           s++;
342                           /* Skip the double space in the middle but
343                              don't require it to help copying
344                              fingerprints from sources which fold
345                              multiple space to one.  */
346                           if (i == 10 && *s == ' ')
347                             s++;
348                         }
349
350                       c = hextobyte(s);
351                       if (c == -1)
352                         break;
353                       desc->u.fpr[i] = c;
354                       s += 2;
355                     }
356                   if (i == 20)
357                     mode = KEYDB_SEARCH_MODE_FPR20;
358                 }
359             }
360           if (!mode) /* Default to substring search.  */
361             {
362               desc->exact = 0;
363               desc->u.name = s;
364               mode = KEYDB_SEARCH_MODE_SUBSTR;
365             }
366         }
367       else
368         {
369           /* Hex number with a prefix but with a wrong length.  */
370           return gpg_error (GPG_ERR_INV_USER_ID);
371         }
372     }
373
374   desc->mode = mode;
375   return 0;
376 }