WizardsToolkit  1.0.7
passphrase.c
Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %    PPPP    AAA   SSSSS  SSSSS  PPPP   H   H  RRRR    AAA   SSSSS  EEEEE     %
00007 %    P   P  A   A  SS     SS     P   P  H   H  R   R  A   A  SS     E         %
00008 %    PPPP   AAAAA   SSS    SSS   PPPP   HHHHH  RRRR   AAAAA   SSS   EEE       %
00009 %    P      A   A     SS     SS  P      H   H  R R    A   A     SS  E         %
00010 %    P      A   A  SSSSS  SSSSS  P      H   H  R  R   A   A  SSSSS  EEEEE     %
00011 %                                                                             %
00012 %                                                                             %
00013 %                     Wizard's Toolkit Passphrase Methods                     %
00014 %                                                                             %
00015 %                             Software Design                                 %
00016 %                               John Cristy                                   %
00017 %                               March 2003                                    %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.wizards-toolkit.org/script/license.php                        %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %
00037 */
00038 
00039 #include "wizard/studio.h"
00040 #include "wizard/exception.h"
00041 #include "wizard/exception-private.h"
00042 #include "wizard/memory_.h"
00043 #include "wizard/passphrase.h"
00044 #include "wizard/utility-private.h"
00045 #if defined(WIZARDSTOOLKIT_HAVE_TERMIOS_H)
00046 #include <termios.h>
00047 #endif
00048 
00049 /*
00050   Define declarations.
00051 */
00052 #ifdef TCSASOFT
00053 # define _T_FLUSH  (TCSAFLUSH | TCSASOFT)
00054 #else
00055 # define _T_FLUSH  (TCSAFLUSH)
00056 #endif
00057 
00058 #if !defined(_POSIX_VDISABLE) && defined(VDISABLE)
00059 # define _POSIX_VDISABLE  VDISABLE
00060 #endif
00061 
00062 #define _PATH_TTY "/dev/tty"
00063 
00064 /*
00065   Typedef declarations.
00066 */
00067 typedef enum
00068 {
00069   EchoOffMode    = 0x00,  /* Turn off echo (default). */
00070   EchoOnMode     = 0x01,  /* Leave echo on. */
00071   RequireTTYMode = 0x02,  /* Fail if there is no tty. */
00072   ForceLowerMode = 0x04,  /* Force input to lower case. */
00073   ForceUpperMode = 0x08,  /* Force input to upper case. */
00074   SevenBitMode   = 0x10,  /* Strip the high bit from input. */
00075   StdinMode      = 0x20   /* Read from stdin, not /dev/tty */
00076 } PassphraseMode;
00077 
00078 /*
00079   Global declarations.
00080 */
00081 static volatile sig_atomic_t
00082   signal_number = 0;
00083 
00084 /*
00085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00086 %                                                                             %
00087 %                                                                             %
00088 %                                                                             %
00089 %   G e t P h r a s e                                                         %
00090 %                                                                             %
00091 %                                                                             %
00092 %                                                                             %
00093 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00094 %
00095 %  GetPhrase() gets a phrase from the terminal.
00096 %
00097 %  The format of the GetPhrase method is:
00098 %
00099 %      WizardBooleanType GetPhrase(const char *prompt,PassphraseMode flags,
00100 %        StringInfo *phrase)
00101 %
00102 %  A description of each parameter follows:
00103 %
00104 %    o prompt: Prompt the user for the passphrase.
00105 %
00106 %    o flags: modify the behavior of this method by setting one or more of
00107 %      these flags:
00108 %
00109 %        EchoOffMode     Turn off echo (default).
00110 %        EchoOnMode      Leave echo on.
00111 %        RequireTTYMode  Fail if there is no tty.
00112 %        ForceLowerMode  Force input to lower case.
00113 %        ForceUpperMode  Force input to upper case.
00114 %        SevenBitMode    Strip the high bit from input.
00115 %        StdinMode       Read from stdin, not /dev/tty.
00116 %
00117 %    o phrase: The passphrase is returned in this buffer.
00118 %
00119 */
00120 
00121 static void SignalHandler(int signal)
00122 {
00123   signal_number=(sig_atomic_t) signal;
00124 }
00125 
00126 static WizardBooleanType GetPhrase(const char *prompt,PassphraseMode flags,
00127   StringInfo *phrase)
00128 {
00129   ssize_t
00130     count;
00131 
00132 #if defined(WIZARDSTOOLKIT_HAVE_TERMIOS_H)
00133   char
00134     c;
00135 
00136   int
00137     input,
00138     output;
00139 
00140   register unsigned char
00141     *p;
00142 
00143   struct sigaction
00144     action,
00145     sigalrm,
00146     sighup,
00147     sigint,
00148     sigpipe,
00149     sigquit,
00150     sigterm,
00151     sigtstp,
00152     sigttin,
00153     sigttou;
00154 
00155   struct termios
00156     attributes,
00157     save_attributes;
00158 
00159   /*
00160     Read and write to _PATH_TTY if available, otherwise from stdin.
00161   */
00162   signal_number=0;
00163   input=STDIN_FILENO;
00164   output=STDERR_FILENO;
00165   if ((flags & StdinMode) == 0)
00166     {
00167       input=open_utf8(_PATH_TTY,O_RDWR,0);
00168       output=input;
00169     }
00170   if (((flags & StdinMode) != 0) || (input == -1) || (output == -1))
00171     {
00172       if ((flags & RequireTTYMode) != 0)
00173         {
00174           errno=ENOTTY;
00175           return(WizardFalse);
00176         }
00177     }
00178   /*
00179     Set our signal handler.
00180   */
00181   (void) sigemptyset(&action.sa_mask);
00182   action.sa_flags=0;  /* don't restart system calls */
00183   action.sa_handler=SignalHandler;
00184   (void) sigaction(SIGALRM,&action,&sigalrm);
00185   (void) sigaction(SIGHUP,&action,&sighup);
00186   (void) sigaction(SIGINT,&action,&sigint);
00187   (void) sigaction(SIGPIPE,&action,&sigpipe);
00188   (void) sigaction(SIGQUIT,&action,&sigquit);
00189   (void) sigaction(SIGTERM,&action,&sigterm);
00190   (void) sigaction(SIGTSTP,&action,&sigtstp);
00191   (void) sigaction(SIGTTIN,&action,&sigttin);
00192   (void) sigaction(SIGTTOU,&action,&sigttou);
00193   if ((input == STDIN_FILENO) || (tcgetattr(input,&save_attributes) != 0))
00194     {
00195       (void) ResetWizardMemory(&attributes,0,sizeof(attributes));
00196       attributes.c_lflag|=ECHO;
00197       (void) CopyWizardMemory(&save_attributes,&attributes,sizeof(attributes));
00198     }
00199   else
00200     {
00201       /*
00202         Turn off echo.
00203       */
00204       (void) CopyWizardMemory(&attributes,&save_attributes,sizeof(attributes));
00205       if ((flags & EchoOnMode) == 0)
00206         attributes.c_lflag&=(~(ECHO | ECHONL));
00207 #if defined(VSTATUS)
00208       if (attributes.c_cc[VSTATUS] != _POSIX_VDISABLE)
00209         attributes.c_cc[VSTATUS]=_POSIX_VDISABLE;
00210 #endif
00211       (void) tcsetattr(input,_T_FLUSH,&attributes);
00212     }
00213   if ((flags & StdinMode) == 0)
00214     count=write(output,prompt,strlen(prompt));
00215   SetStringInfoLength(phrase,MaxTextExtent);
00216   p=GetStringInfoDatum(phrase);
00217   while (((count=read(input,&c,1)) == 1) && (c != '\n') && (c != '\r'))
00218   {
00219     if ((size_t) (p-GetStringInfoDatum(phrase)) <
00220         (GetStringInfoLength(phrase)-1))
00221       {
00222         if ((flags & SevenBitMode) != 0)
00223           c&=0x7f;
00224         if (isalpha((int) c) != 0)
00225           {
00226             if ((flags & ForceLowerMode) != 0)
00227               c=(char) tolower((int) c);
00228             if ((flags & ForceUpperMode) != 0)
00229               c=(char) toupper((int) c);
00230           }
00231         *p++=(unsigned char) c;
00232       }
00233   }
00234   *p=(unsigned char) '\0';
00235   SetStringInfoLength(phrase,(size_t) (p-GetStringInfoDatum(phrase)));
00236   if ((attributes.c_lflag & ECHO) == 0)
00237     count=write(output,"\n",1);
00238   /*
00239     Restore old terminal settings and signals.
00240   */
00241   if (memcmp(&attributes,&save_attributes,sizeof(attributes)) != 0)
00242     (void) tcsetattr(input,_T_FLUSH,&save_attributes);
00243   (void) sigaction(SIGALRM,&sigalrm,(struct sigaction *) NULL);
00244   (void) sigaction(SIGHUP,&sighup,(struct sigaction *) NULL);
00245   (void) sigaction(SIGINT,&sigint,(struct sigaction *) NULL);
00246   (void) sigaction(SIGQUIT,&sigquit,(struct sigaction *) NULL);
00247   (void) sigaction(SIGPIPE,&sigpipe,(struct sigaction *) NULL);
00248   (void) sigaction(SIGTERM,&sigterm,(struct sigaction *) NULL);
00249   (void) sigaction(SIGTSTP,&sigtstp,(struct sigaction *) NULL);
00250   (void) sigaction(SIGTTIN,&sigttin,(struct sigaction *) NULL);
00251   if (input != STDIN_FILENO)
00252     input=close(input)-1;
00253   if (signal_number != 0)
00254     {
00255       /*
00256         We were interrupted by a signal.
00257       */
00258       (void) kill((pid_t) getpid(),(int) signal_number);
00259       if ((signal_number == (sig_atomic_t) SIGTSTP) ||
00260           (signal_number == (sig_atomic_t) SIGTTIN) ||
00261           (signal_number == (sig_atomic_t) SIGTTOU))
00262         return(GetPhrase(prompt,flags,phrase));
00263     }
00264 #else
00265   (void) fputs(prompt,stdout);
00266   SetStringInfoLength(phrase,MaxTextExtent);
00267   count=read(fileno(stdin),GetStringInfoDatum(phrase),MaxTextExtent);
00268   SetStringInfoLength(phrase,count);
00269 #endif
00270   return(count != -1 ? WizardTrue : WizardFalse);
00271 }
00272 
00273 /*
00274 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00275 %                                                                             %
00276 %                                                                             %
00277 %                                                                             %
00278 %   G e t P a s s p h r a s e                                                 %
00279 %                                                                             %
00280 %                                                                             %
00281 %                                                                             %
00282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00283 %
00284 %  GetPassphrase() gets a passphrase from the terminal and returns it.
00285 %
00286 %  The format of the GetPassphrase method is:
00287 %
00288 %      StringInfo GetPassphrase(ExceptionInfo *exception)
00289 %
00290 %  A description of each parameter follows:
00291 %
00292 %    o prompt: Prompt the user for the passphrase.
00293 %
00294 */
00295 WizardExport StringInfo *GetPassphrase(ExceptionInfo *exception)
00296 {
00297   char
00298     prompt[MaxTextExtent];
00299 
00300   WizardBooleanType
00301     status;
00302 
00303   StringInfo
00304     *phrase,
00305     *rephrase;
00306 
00307   phrase=AcquireStringInfo(MaxTextExtent);
00308   rephrase=AcquireStringInfo(MaxTextExtent);
00309   (void) FormatLocaleString(prompt,MaxTextExtent,
00310     "Enter the passphrase (maximum of %d characters)\n",MaxTextExtent);
00311   status=write(STDERR_FILENO,prompt,strlen(prompt)) < 0 ? WizardFalse :
00312     WizardTrue;
00313   for ( ; ; )
00314   {
00315     status=GetPhrase("Enter passphrase: ",EchoOffMode,phrase);
00316     if (status == WizardFalse)
00317       {
00318         (void) ThrowWizardException(exception,GetWizardModule(),
00319           AuthenticateError,"unable to get pass phrase `%s'",strerror(errno));
00320         return((StringInfo *) NULL);
00321       }
00322     status=GetPhrase("Enter same passphrase again: ",EchoOffMode,rephrase);
00323     if (status == WizardFalse)
00324       {
00325         (void) ThrowWizardException(exception,GetWizardModule(),
00326           AuthenticateError,"unable to get pass phrase `%s'",strerror(errno));
00327         return((StringInfo *) NULL);
00328       }
00329     if (CompareStringInfo(phrase,rephrase) == 0)
00330       break;
00331     (void) PrintWizardString(stderr,"Passphrases are different.  Try again.\n");
00332   }
00333   rephrase=DestroyStringInfo(rephrase);
00334   SetStringInfoLength(phrase,GetStringInfoLength(phrase));
00335   return(phrase);
00336 }