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