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