Added SELInux hacks and did some cleanups.
[gnupg.git] / g10 / misc.c
1 /* misc.c -  miscellaneous functions
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
3  *               2004 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <errno.h>
28 #if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
29 #include <asm/sysinfo.h>
30 #include <asm/unistd.h>
31 #endif
32 #ifdef HAVE_SETRLIMIT
33 #include <time.h>
34 #include <sys/time.h>
35 #include <sys/resource.h>
36 #endif
37 #ifdef ENABLE_SELINUX_HACKS
38 #include <sys/stat.h>
39 #endif
40 #include "util.h"
41 #include "main.h"
42 #include "photoid.h"
43 #include "options.h"
44 #include "i18n.h"
45 #include "cardglue.h"
46
47
48 #ifdef ENABLE_SELINUX_HACKS
49 /* A object and a global variable to keep track of files marked as
50    secured. */
51 struct secured_file_item 
52 {
53   struct secured_file_item *next;
54   ino_t ino;
55   dev_t dev;
56 };
57 static struct secured_file_item *secured_files;
58 #endif /*ENABLE_SELINUX_HACKS*/
59
60
61
62 #if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
63 static int
64 setsysinfo(unsigned long op, void *buffer, unsigned long size,
65                      int *start, void *arg, unsigned long flag)
66 {
67     return syscall(__NR_osf_setsysinfo, op, buffer, size, start, arg, flag);
68 }
69
70 void
71 trap_unaligned(void)
72 {
73     unsigned int buf[2];
74
75     buf[0] = SSIN_UACPROC;
76     buf[1] = UAC_SIGBUS | UAC_NOPRINT;
77     setsysinfo(SSI_NVPAIRS, buf, 1, 0, 0, 0);
78 }
79 #else
80 void
81 trap_unaligned(void)
82 {  /* dummy */
83 }
84 #endif
85
86
87 int
88 disable_core_dumps()
89 {
90 #ifdef HAVE_DOSISH_SYSTEM
91     return 0;
92 #else
93 #ifdef HAVE_SETRLIMIT
94     struct rlimit limit;
95
96     limit.rlim_cur = 0;
97     limit.rlim_max = 0;
98     if( !setrlimit( RLIMIT_CORE, &limit ) )
99         return 0;
100     if( errno != EINVAL && errno != ENOSYS )
101         log_fatal(_("can't disable core dumps: %s\n"), strerror(errno) );
102 #endif
103     return 1;
104 #endif
105 }
106
107
108 /* For the sake of SELinux we want to restrict access through gpg to
109    certain files we keep under our own control.  This function
110    registers such a file and is_secured_file may then be used to
111    check whether a file has ben registered as secured. */
112 void
113 register_secured_file (const char *fname)
114 {
115 #ifdef ENABLE_SELINUX_HACKS
116   struct stat buf;
117   struct secured_file_item *sf;
118
119   /* Note that we stop immediatley if something goes wrong here. */
120   if (stat (fname, &buf))
121     log_fatal (_("fstat of `%s' failed in %s: %s\n"), fname, 
122                "register_secured_file", strerror (errno));
123 /*   log_debug ("registering `%s' i=%lu.%lu\n", fname, */
124 /*              (unsigned long)buf.st_dev, (unsigned long)buf.st_ino); */
125   for (sf=secured_files; sf; sf = sf->next)
126     {
127       if (sf->ino == buf.st_ino && sf->dev == buf.st_dev)
128         return; /* Already registered.  */
129     }
130
131   sf = xmalloc (sizeof *sf);
132   sf->ino = buf.st_ino;
133   sf->dev = buf.st_dev;
134   sf->next = secured_files;
135   secured_files = sf;
136 #endif /*ENABLE_SELINUX_HACKS*/
137 }
138
139 /* Remove a file registerd as secure. */
140 void
141 unregister_secured_file (const char *fname)
142 {
143 #ifdef ENABLE_SELINUX_HACKS
144   struct stat buf;
145   struct secured_file_item *sf, *sfprev;
146
147   if (stat (fname, &buf))
148     {
149       log_error (_("fstat of `%s' failed in %s: %s\n"), fname,
150                  "unregister_secured_file", strerror (errno));
151       return;
152     }
153 /*   log_debug ("unregistering `%s' i=%lu.%lu\n", fname,  */
154 /*              (unsigned long)buf.st_dev, (unsigned long)buf.st_ino); */
155   for (sfprev=NULL,sf=secured_files; sf; sfprev=sf, sf = sf->next)
156     {
157       if (sf->ino == buf.st_ino && sf->dev == buf.st_dev)
158         {
159           if (sfprev)
160             sfprev->next = sf->next;
161           else
162             secured_files = sf->next;
163           xfree (sf);
164           return;
165         }
166     }
167 #endif /*ENABLE_SELINUX_HACKS*/
168 }
169
170 /* Return true if FD is corresponds to a secured file.  Using -1 for
171    FS is allowed and will return false. */ 
172 int 
173 is_secured_file (int fd)
174 {
175 #ifdef ENABLE_SELINUX_HACKS
176   struct stat buf;
177   struct secured_file_item *sf;
178
179   if (fd == -1)
180     return 0; /* No file descriptor so it can't be secured either.  */
181
182   /* Note that we print out a error here and claim that a file is
183      secure if something went wrong. */
184   if (fstat (fd, &buf))
185     {
186       log_error (_("fstat(%d) failed in %s: %s\n"), fd, 
187                  "is_secured_file", strerror (errno));
188       return 1;
189     }
190 /*   log_debug ("is_secured_file (%d) i=%lu.%lu\n", fd, */
191 /*              (unsigned long)buf.st_dev, (unsigned long)buf.st_ino); */
192   for (sf=secured_files; sf; sf = sf->next)
193     {
194       if (sf->ino == buf.st_ino && sf->dev == buf.st_dev)
195         return 1; /* Yes.  */
196     }
197 #endif /*ENABLE_SELINUX_HACKS*/
198   return 0; /* No. */
199 }
200
201
202
203 u16
204 checksum_u16( unsigned n )
205 {
206     u16 a;
207
208     a  = (n >> 8) & 0xff;
209     a += n & 0xff;
210     return a;
211 }
212
213
214 u16
215 checksum( byte *p, unsigned n )
216 {
217     u16 a;
218
219     for(a=0; n; n-- )
220         a += *p++;
221     return a;
222 }
223
224 u16
225 checksum_mpi( MPI a )
226 {
227     u16 csum;
228     byte *buffer;
229     unsigned nbytes;
230     unsigned nbits;
231
232     buffer = mpi_get_buffer( a, &nbytes, NULL );
233     nbits = mpi_get_nbits(a);
234     csum = checksum_u16( nbits );
235     csum += checksum( buffer, nbytes );
236     m_free( buffer );
237     return csum;
238 }
239
240 u32
241 buffer_to_u32( const byte *buffer )
242 {
243     unsigned long a;
244     a =  *buffer << 24;
245     a |= buffer[1] << 16;
246     a |= buffer[2] << 8;
247     a |= buffer[3];
248     return a;
249 }
250
251
252 static void
253 no_exp_algo(void)
254 {
255     static int did_note = 0;
256
257     if( !did_note ) {
258         did_note = 1;
259         log_info(_("Experimental algorithms should not be used!\n"));
260     }
261 }
262
263 void
264 print_pubkey_algo_note( int algo )
265 {
266     if( algo >= 100 && algo <= 110 )
267         no_exp_algo();
268 }
269
270 void
271 print_cipher_algo_note( int algo )
272 {
273     if( algo >= 100 && algo <= 110 )
274         no_exp_algo();
275     else if(    algo == CIPHER_ALGO_3DES
276              || algo == CIPHER_ALGO_CAST5
277              || algo == CIPHER_ALGO_BLOWFISH
278              || algo == CIPHER_ALGO_TWOFISH
279              || algo == CIPHER_ALGO_AES
280              || algo == CIPHER_ALGO_AES192
281              || algo == CIPHER_ALGO_AES256
282            )
283         ;
284     else {
285         static int did_note = 0;
286
287         if( !did_note ) {
288             did_note = 1;
289             log_info(_("this cipher algorithm is deprecated; "
290                        "please use a more standard one!\n"));
291         }
292     }
293 }
294
295 void
296 print_digest_algo_note( int algo )
297 {
298     if( algo >= 100 && algo <= 110 )
299         no_exp_algo();
300 }
301
302
303 /* Return a string which is used as a kind of process ID */
304 const byte *
305 get_session_marker( size_t *rlen )
306 {
307     static byte marker[SIZEOF_UNSIGNED_LONG*2];
308     static int initialized;
309
310     if ( !initialized ) {
311         volatile ulong aa, bb; /* we really want the uninitialized value */
312         ulong a, b;
313
314         initialized = 1;
315         /* also this marker is guessable it is not easy to use this 
316          * for a faked control packet because an attacker does not
317          * have enough control about the time the verification does 
318          * take place.  Of course, we can add just more random but 
319          * than we need the random generator even for verification
320          * tasks - which does not make sense. */
321         a = aa ^ (ulong)getpid();
322         b = bb ^ (ulong)time(NULL);
323         memcpy( marker, &a, SIZEOF_UNSIGNED_LONG );
324         memcpy( marker+SIZEOF_UNSIGNED_LONG, &b, SIZEOF_UNSIGNED_LONG );
325     }
326     *rlen = sizeof(marker);
327     return marker;
328 }
329
330 /****************
331  * Wrapper around the libgcrypt function with addional checks on
332  * openPGP contraints for the algo ID.
333  */
334 int
335 openpgp_cipher_test_algo( int algo )
336 {
337     if( algo < 0 || algo > 110 )
338         return G10ERR_CIPHER_ALGO;
339     return check_cipher_algo(algo);
340 }
341
342 int
343 openpgp_pk_test_algo( int algo, unsigned int usage_flags )
344 {
345     if( algo < 0 || algo > 110 )
346         return G10ERR_PUBKEY_ALGO;
347     return check_pubkey_algo2( algo, usage_flags );
348 }
349
350 int 
351 openpgp_pk_algo_usage ( int algo )
352 {
353     int use = 0; 
354     
355     /* they are hardwired in gpg 1.0 */
356     switch ( algo ) {    
357       case PUBKEY_ALGO_RSA:
358           use = PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH;
359           break;
360       case PUBKEY_ALGO_RSA_E:
361           use = PUBKEY_USAGE_ENC;
362           break;
363       case PUBKEY_ALGO_RSA_S:
364           use = PUBKEY_USAGE_SIG;
365           break;
366       case PUBKEY_ALGO_ELGAMAL_E:
367           use = PUBKEY_USAGE_ENC;
368           break;
369       case PUBKEY_ALGO_DSA:  
370           use = PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;
371           break;
372       default:
373           break;
374     }
375     return use;
376 }
377
378 int
379 openpgp_md_test_algo( int algo )
380 {
381     if( algo < 0 || algo > 110 )
382         return G10ERR_DIGEST_ALGO;
383     return check_digest_algo(algo);
384 }
385
386 #ifdef USE_IDEA
387 /* Special warning for the IDEA cipher */
388 void
389 idea_cipher_warn(int show)
390 {
391   static int warned=0;
392
393   if(!warned || show)
394     {
395       log_info(_("the IDEA cipher plugin is not present\n"));
396       log_info(_("please see http://www.gnupg.org/why-not-idea.html "
397                  "for more information\n"));
398       warned=1;
399     }
400 }
401 #endif
402
403 static unsigned long get_signature_count(PKT_secret_key *sk)
404 {
405 #ifdef ENABLE_CARD_SUPPORT
406   if(sk && sk->is_protected && sk->protect.s2k.mode==1002)
407     {
408       struct agent_card_info_s info;
409       if(agent_scd_getattr("SIG-COUNTER",&info)==0)
410         return info.sig_counter;
411     }  
412 #endif
413
414   /* How to do this without a card? */
415
416   return 0;
417 }
418
419 /* Expand %-strings.  Returns a string which must be m_freed.  Returns
420    NULL if the string cannot be expanded (too large). */
421 char *
422 pct_expando(const char *string,struct expando_args *args)
423 {
424   const char *ch=string;
425   int idx=0,maxlen=0,done=0;
426   u32 pk_keyid[2]={0,0},sk_keyid[2]={0,0};
427   char *ret=NULL;
428
429   if(args->pk)
430     keyid_from_pk(args->pk,pk_keyid);
431
432   if(args->sk)
433     keyid_from_sk(args->sk,sk_keyid);
434
435   /* This is used so that %k works in photoid command strings in
436      --list-secret-keys (which of course has a sk, but no pk). */
437   if(!args->pk && args->sk)
438     keyid_from_sk(args->sk,pk_keyid);
439
440   while(*ch!='\0')
441     {
442       char *str=NULL;
443
444       if(!done)
445         {
446           /* 8192 is way bigger than we'll need here */
447           if(maxlen>=8192)
448             goto fail;
449
450           maxlen+=1024;
451           ret=m_realloc(ret,maxlen);
452         }
453
454       done=0;
455
456       if(*ch=='%')
457         {
458           switch(*(ch+1))
459             {
460             case 's': /* short key id */
461               if(idx+8<maxlen)
462                 {
463                   sprintf(&ret[idx],"%08lX",(ulong)sk_keyid[1]);
464                   idx+=8;
465                   done=1;
466                 }
467               break;
468
469             case 'S': /* long key id */
470               if(idx+16<maxlen)
471                 {
472                   sprintf(&ret[idx],"%08lX%08lX",
473                           (ulong)sk_keyid[0],(ulong)sk_keyid[1]);
474                   idx+=16;
475                   done=1;
476                 }
477               break;
478
479             case 'k': /* short key id */
480               if(idx+8<maxlen)
481                 {
482                   sprintf(&ret[idx],"%08lX",(ulong)pk_keyid[1]);
483                   idx+=8;
484                   done=1;
485                 }
486               break;
487
488             case 'K': /* long key id */
489               if(idx+16<maxlen)
490                 {
491                   sprintf(&ret[idx],"%08lX%08lX",
492                           (ulong)pk_keyid[0],(ulong)pk_keyid[1]);
493                   idx+=16;
494                   done=1;
495                 }
496               break;
497
498             case 'c': /* signature count from card, if any. */
499               if(idx+10<maxlen)
500                 {
501                   sprintf(&ret[idx],"%lu",get_signature_count(args->sk));
502                   idx+=strlen(&ret[idx]);
503                   done=1;
504                 }             
505               break;
506
507             case 'p': /* primary pk fingerprint of a sk */
508             case 'f': /* pk fingerprint */
509             case 'g': /* sk fingerprint */
510               {
511                 byte array[MAX_FINGERPRINT_LEN];
512                 size_t len;
513                 int i;
514
515                 if((*(ch+1))=='p' && args->sk)
516                   {
517                     if(args->sk->is_primary)
518                       fingerprint_from_sk(args->sk,array,&len);
519                     else if(args->sk->main_keyid[0] || args->sk->main_keyid[1])
520                       {
521                         PKT_public_key *pk=
522                           m_alloc_clear(sizeof(PKT_public_key));
523
524                         if(get_pubkey_fast(pk,args->sk->main_keyid)==0)
525                           fingerprint_from_pk(pk,array,&len);
526                         else
527                           memset(array,0,(len=MAX_FINGERPRINT_LEN));
528                         free_public_key(pk);
529                       }
530                     else
531                       memset(array,0,(len=MAX_FINGERPRINT_LEN));
532                   }
533                 else if((*(ch+1))=='f' && args->pk)
534                   fingerprint_from_pk(args->pk,array,&len);
535                 else if((*(ch+1))=='g' && args->sk)
536                   fingerprint_from_sk(args->sk,array,&len);
537                 else
538                   memset(array,0,(len=MAX_FINGERPRINT_LEN));
539
540                 if(idx+(len*2)<maxlen)
541                   {
542                     for(i=0;i<len;i++)
543                       {
544                         sprintf(&ret[idx],"%02X",array[i]);
545                         idx+=2;
546                       }
547                     done=1;
548                   }
549               }
550               break;
551
552             case 't': /* e.g. "jpg" */
553               str=image_type_to_string(args->imagetype,0);
554               /* fall through */
555
556             case 'T': /* e.g. "image/jpeg" */
557               if(str==NULL)
558                 str=image_type_to_string(args->imagetype,2);
559
560               if(idx+strlen(str)<maxlen)
561                 {
562                   strcpy(&ret[idx],str);
563                   idx+=strlen(str);
564                   done=1;
565                 }
566               break;
567
568             case '%':
569               if(idx+1<maxlen)
570                 {
571                   ret[idx++]='%';
572                   ret[idx]='\0';
573                   done=1;
574                 }
575               break;
576
577               /* Any unknown %-keys (like %i, %o, %I, and %O) are
578                  passed through for later expansion.  Note this also
579                  handles the case where the last character in the
580                  string is a '%' - the terminating \0 will end up here
581                  and properly terminate the string. */
582             default:
583               if(idx+2<maxlen)
584                 {
585                   ret[idx++]='%';
586                   ret[idx++]=*(ch+1);
587                   ret[idx]='\0';
588                   done=1;
589                 }
590               break;
591               }
592
593           if(done)
594             ch++;
595         }
596       else
597         {
598           if(idx+1<maxlen)
599             {
600               ret[idx++]=*ch;
601               ret[idx]='\0';
602               done=1;
603             }
604         }
605
606       if(done)
607         ch++;
608     }
609
610   return ret;
611
612  fail:
613   m_free(ret);
614   return NULL;
615 }
616
617 void
618 deprecated_warning(const char *configname,unsigned int configlineno,
619                    const char *option,const char *repl1,const char *repl2)
620 {
621   if(configname)
622     {
623       if(strncmp("--",option,2)==0)
624         option+=2;
625
626       if(strncmp("--",repl1,2)==0)
627         repl1+=2;
628
629       log_info(_("%s:%d: deprecated option \"%s\"\n"),
630                configname,configlineno,option);
631     }
632   else
633     log_info(_("WARNING: \"%s\" is a deprecated option\n"),option);
634
635   log_info(_("please use \"%s%s\" instead\n"),repl1,repl2);
636 }
637
638 const char *
639 compress_algo_to_string(int algo)
640 {
641   const char *s=NULL;
642
643   switch(algo)
644     {
645     case COMPRESS_ALGO_NONE:
646       s=_("Uncompressed");
647       break;
648
649     case COMPRESS_ALGO_ZIP:
650       s="ZIP";
651       break;
652
653     case COMPRESS_ALGO_ZLIB:
654       s="ZLIB";
655       break;
656
657 #ifdef HAVE_BZIP2
658     case COMPRESS_ALGO_BZIP2:
659       s="BZIP2";
660       break;
661 #endif
662     }
663
664   return s;
665 }
666
667 int
668 string_to_compress_algo(const char *string)
669 {
670   /* NOTE TO TRANSLATOR: See doc/TRANSLATE about this string. */
671   if(match_multistr(_("uncompressed|none"),string))
672     return 0;
673   else if(ascii_strcasecmp(string,"uncompressed")==0)
674     return 0;
675   else if(ascii_strcasecmp(string,"none")==0)
676     return 0;
677   else if(ascii_strcasecmp(string,"zip")==0)
678     return 1;
679   else if(ascii_strcasecmp(string,"zlib")==0)
680     return 2;
681 #ifdef HAVE_BZIP2
682   else if(ascii_strcasecmp(string,"bzip2")==0)
683     return 3;
684 #endif
685   else if(ascii_strcasecmp(string,"z0")==0)
686     return 0;
687   else if(ascii_strcasecmp(string,"z1")==0)
688     return 1;
689   else if(ascii_strcasecmp(string,"z2")==0)
690     return 2;
691 #ifdef HAVE_BZIP2
692   else if(ascii_strcasecmp(string,"z3")==0)
693     return 3;
694 #endif
695   else
696     return -1;
697 }
698
699 int
700 check_compress_algo(int algo)
701 {
702 #ifdef HAVE_BZIP2
703   if(algo>=0 && algo<=3)
704     return 0;
705 #else
706   if(algo>=0 && algo<=2)
707     return 0;
708 #endif
709
710   return G10ERR_COMPR_ALGO;
711 }
712
713 int
714 default_cipher_algo(void)
715 {
716   if(opt.def_cipher_algo)
717     return opt.def_cipher_algo;
718   else if(opt.personal_cipher_prefs)
719     return opt.personal_cipher_prefs[0].value;
720   else
721     return opt.s2k_cipher_algo;
722 }
723
724 /* There is no default_digest_algo function, but see
725    sign.c:hash_for() */
726
727 int
728 default_compress_algo(void)
729 {
730   if(opt.compress_algo!=-1)
731     return opt.compress_algo;
732   else if(opt.personal_compress_prefs)
733     return opt.personal_compress_prefs[0].value;
734   else
735     return DEFAULT_COMPRESS_ALGO;
736 }
737
738 const char *
739 compliance_option_string(void)
740 {
741   switch(opt.compliance)
742     {
743     case CO_RFC2440:
744       return "--openpgp";
745     case CO_PGP2:
746       return "--pgp2";
747     case CO_PGP6:
748       return "--pgp6";
749     case CO_PGP7:
750       return "--pgp7";
751     case CO_PGP8:
752       return "--pgp8";
753     default:
754       return "???";
755     }
756 }
757
758 static const char *
759 compliance_string(void)
760 {
761   switch(opt.compliance)
762     {
763     case CO_RFC2440:
764       return "OpenPGP";
765     case CO_PGP2:
766       return "PGP 2.x";
767     case CO_PGP6:
768       return "PGP 6.x";
769     case CO_PGP7:
770       return "PGP 7.x";
771     case CO_PGP8:
772       return "PGP 8.x";
773     default:
774       return "???";
775     }
776 }
777
778 void
779 compliance_failure(void)
780 {
781   log_info(_("this message may not be usable by %s\n"),compliance_string());
782   opt.compliance=CO_GNUPG;
783 }
784
785 /* Break a string into successive option pieces.  Accepts single word
786    options and key=value argument options. */
787 char *
788 optsep(char **stringp)
789 {
790   char *tok,*end;
791
792   tok=*stringp;
793   if(tok)
794     {
795       end=strpbrk(tok," ,=");
796       if(end)
797         {
798           int sawequals=0;
799           char *ptr=end;
800
801           /* what we need to do now is scan along starting with *end,
802              If the next character we see (ignoring spaces) is an =
803              sign, then there is an argument. */
804
805           while(*ptr)
806             {
807               if(*ptr=='=')
808                 sawequals=1;
809               else if(*ptr!=' ')
810                 break;
811               ptr++;
812             }
813
814           /* There is an argument, so grab that too.  At this point,
815              ptr points to the first character of the argument. */
816           if(sawequals)
817             {
818               /* Is it a quoted argument? */
819               if(*ptr=='"')
820                 {
821                   ptr++;
822                   end=strchr(ptr,'"');
823                   if(end)
824                     end++;
825                 }
826               else
827                 end=strpbrk(ptr," ,");
828             }
829
830           if(end && *end)
831             {
832               *end='\0';
833               *stringp=end+1;
834             }
835           else
836             *stringp=NULL;
837         }
838       else
839         *stringp=NULL;
840     }
841
842   return tok;
843 }
844
845 /* Breaks an option value into key and value.  Returns NULL if there
846    is no value.  Note that "string" is modified to remove the =value
847    part. */
848 char *
849 argsplit(char *string)
850 {
851   char *equals,*arg=NULL;
852
853   equals=strchr(string,'=');
854   if(equals)
855     {
856       char *quote,*space;
857
858       *equals='\0';
859       arg=equals+1;
860
861       /* Quoted arg? */
862       quote=strchr(arg,'"');
863       if(quote)
864         {
865           arg=quote+1;
866
867           quote=strchr(arg,'"');
868           if(quote)
869             *quote='\0';
870         }
871       else
872         {
873           size_t spaces;
874
875           /* Trim leading spaces off of the arg */
876           spaces=strspn(arg," ");
877           arg+=spaces;
878         }
879
880       /* Trim tailing spaces off of the tag */
881       space=strchr(string,' ');
882       if(space)
883         *space='\0';
884     }
885
886   return arg;
887 }
888
889 /* Return the length of the initial token, leaving off any
890    argument. */
891 static size_t
892 optlen(const char *s)
893 {
894   char *end=strpbrk(s," =");
895
896   if(end)
897     return end-s;
898   else
899     return strlen(s);
900 }
901
902 int
903 parse_options(char *str,unsigned int *options,
904               struct parse_options *opts,int noisy)
905 {
906   char *tok;
907
908   while((tok=optsep(&str)))
909     {
910       int i,rev=0;
911       char *otok=tok;
912
913       if(tok[0]=='\0')
914         continue;
915
916       if(ascii_strncasecmp("no-",tok,3)==0)
917         {
918           rev=1;
919           tok+=3;
920         }
921
922       for(i=0;opts[i].name;i++)
923         {
924           size_t toklen=optlen(tok);
925
926           if(ascii_strncasecmp(opts[i].name,tok,toklen)==0)
927             {
928               /* We have a match, but it might be incomplete */
929               if(toklen!=strlen(opts[i].name))
930                 {
931                   int j;
932
933                   for(j=i+1;opts[j].name;j++)
934                     {
935                       if(ascii_strncasecmp(opts[j].name,tok,toklen)==0)
936                         {
937                           if(noisy)
938                             log_info(_("ambiguous option `%s'\n"),otok);
939                           return 0;
940                         }
941                     }
942                 }
943
944               if(rev)
945                 {
946                   *options&=~opts[i].bit;
947                   if(opts[i].value)
948                     *opts[i].value=NULL;
949                 }
950               else
951                 {
952                   *options|=opts[i].bit;
953                   if(opts[i].value)
954                     *opts[i].value=argsplit(tok);
955                 }
956               break;
957             }
958         }
959
960       if(!opts[i].name)
961         {
962           if(noisy)
963             log_info(_("unknown option `%s'\n"),otok);
964           return 0;
965         }
966     }
967
968   return 1;
969 }