/[winpt]/trunk/Src/wptPassphraseCB.cpp
ViewVC logotype

Diff of /trunk/Src/wptPassphraseCB.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 22 by twoaday, Wed Aug 10 11:33:35 2005 UTC revision 25 by twoaday, Wed Oct 12 10:04:26 2005 UTC
# Line 1  Line 1 
1  /* wptPassphraseCB.cpp - GPGME Passphrase Callback  /* wptPassphraseCB.cpp - GPGME Passphrase Callback
2   *      Copyright (C) 2001, 2002, 2003 Timo Schulz   *      Copyright (C) 2001, 2002, 2003, 2005 Timo Schulz
3     *      Copyright (C) 2005 g10 Code GmbH
4   *   *
5   * This file is part of WinPT.   * This file is part of WinPT.
6   *   *
# Line 32  Line 33 
33  #include "wptUTF8.h"  #include "wptUTF8.h"
34  #include "wptErrors.h"  #include "wptErrors.h"
35  #include "wptTypes.h"  #include "wptTypes.h"
36    #include "wptKeyList.h"
37  #include "wptAgent.h"  #include "wptAgent.h"
38  #include "wptRegistry.h"  #include "wptRegistry.h"
39    
40    const char* get_symkey_algo (int algo);
41    
42  #define item_ctrl_id( cmd ) \  #define item_ctrl_id( cmd ) \
43      ((cmd) == GPG_CMD_DECRYPT? IDC_DECRYPT_PWD : IDC_DECRYPT_SIGN_PWD)      ((cmd) == GPG_CMD_DECRYPT? IDC_DECRYPT_PWD : IDC_DECRYPT_SIGN_PWD)
# Line 43  Line 46 
46      ((cmd) == GPG_CMD_DECRYPT? IDC_DECRYPT_HIDE : IDC_DECRYPT_SIGN_HIDE)      ((cmd) == GPG_CMD_DECRYPT? IDC_DECRYPT_HIDE : IDC_DECRYPT_SIGN_HIDE)
47    
48    
49  BOOL CALLBACK  /* Dialog procedure for the passphrase callback. */
50    static BOOL CALLBACK
51  passphrase_callback_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)  passphrase_callback_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
52  {      {    
53      static passphrase_cb_s * c;      static passphrase_cb_s * c;
54        gpgme_decrypt_result_t res;
55        gpgme_sign_result_t res_sig;
56      gpgme_key_t key;      gpgme_key_t key;
57      const char * s, * id;      void *ctx = NULL, *item;
58      char info[768] = {0};      const char *id;
59      void * ctx = NULL, * item;      char *info;
60      unsigned int pkalgo;      int n;
61    
62      switch( msg )  {      switch (msg) {
63      case WM_INITDIALOG:      case WM_INITDIALOG:
64          c = (passphrase_cb_s *)lparam;          c = (passphrase_cb_s *)lparam;
65          if (!c)          if (!c)
# Line 64  passphrase_callback_proc (HWND dlg, UINT Line 70  passphrase_callback_proc (HWND dlg, UINT
70                  _("Encrypted with the following public key(s)") );                  _("Encrypted with the following public key(s)") );
71              CheckDlgButton( dlg, IDC_DECRYPT_HIDE, BST_CHECKED );              CheckDlgButton( dlg, IDC_DECRYPT_HIDE, BST_CHECKED );
72          }          }
73          else if( c->gpg_cmd == GPG_CMD_SIGN )          else if (c->gpg_cmd == GPG_CMD_SIGN)
74              CheckDlgButton( dlg, IDC_DECRYPT_SIGN_HIDE, BST_CHECKED );              CheckDlgButton (dlg, IDC_DECRYPT_SIGN_HIDE, BST_CHECKED);
75          if( c->enc_to && c->gpg_cmd == GPG_CMD_DECRYPT ) {          res = gpgme_op_decrypt_result (c->gpg);
76              gpgme_recipients_enum_open( c->enc_to, &ctx );          if (res != NULL && c->gpg_cmd == GPG_CMD_DECRYPT) {
77              while ( (s = gpgme_recipients_enum_read( c->enc_to, &ctx )) ) {              gpgme_recipient_t r;
78                  pkalgo = *s; s++;  
79                  get_pubkey( s, &key );              /* XXX: not all ENCRYPT_TO entries are listed here. */
80                  if( key ) {              for (r = res->recipients; r; r = r->next) {
81                      char * uid = NULL;                  get_pubkey (r->keyid, &key);
82                      id = gpgme_key_get_string_attr( key, GPGME_ATTR_USERID, NULL, 0 );                  if (key) {
83                      if( !id )                      char *uid;
84                        id = key->uids->name;
85                        if (!id)
86                          id = _("Invalid User ID");                          id = _("Invalid User ID");
87                      uid = utf8_to_wincp (id, strlen (id));                                      uid = utf8_to_wincp (id, strlen (id));
88                      _snprintf( info, sizeof info - 1, "%s (%s, 0x%s)", uid,                      info = new char [32+strlen (uid)+1 + 4 + strlen (r->keyid)+1
89                                  gpgme_key_expand_attr( GPGME_ATTR_ALGO, pkalgo ), s+8 );                                       + strlen (key->uids->email)+1];
90                      free( uid );                      if (!info)
91                            BUG (NULL);
92                        sprintf (info, "%s <%s> (%s, 0x%s)", uid, key->uids->email,
93                                 get_key_pubalgo (r->pubkey_algo), r->keyid+8);
94                        free (uid);
95                        
96                  }                  }
97                  else                  else {
98                      _snprintf( info, sizeof info - 1, _("Unknown (key ID 0x%s)"),                      info = new char [32 + strlen (r->keyid)+1 + 4];
99                                 s? s + 8 : "DEADBEEF" );                      if (!info)
100                  listbox_add_string( GetDlgItem( dlg, IDC_DECRYPT_LIST ), info );                          BUG (NULL);
101                        sprintf (info, _("Unknown key ID (%s, 0x%s)"),
102                                 get_key_pubalgo (r->pubkey_algo), r->keyid+8);
103                    }
104                    listbox_add_string (GetDlgItem (dlg, IDC_DECRYPT_LIST), info);
105                    free_if_alloc (info);
106              }              }
             gpgme_recipients_enum_close( c->enc_to, &ctx );  
107          }          }
108          SetDlgItemText( dlg, c->gpg_cmd == GPG_CMD_DECRYPT?          else if (c->gpg_cmd == GPG_CMD_DECRYPT)
109                EnableWindow (GetDlgItem (dlg, IDC_DECRYPT_LIST), FALSE);
110            SetDlgItemText (dlg, c->gpg_cmd == GPG_CMD_DECRYPT?
111                          IDC_DECRYPT_PWDINFO : IDC_DECRYPT_SIGN_PWDINFO,                          IDC_DECRYPT_PWDINFO : IDC_DECRYPT_SIGN_PWDINFO,
112                          _("Please enter your passphrase") );                          _("Please enter your passphrase"));
113          if( c->gpg_cmd == GPG_CMD_DECRYPT ) {          if (c->gpg_cmd == GPG_CMD_DECRYPT) {
114              SetFocus( GetDlgItem( dlg, IDC_DECRYPT_PWD ) );              SetFocus (GetDlgItem (dlg, IDC_DECRYPT_PWD));
115              SetDlgItemText( dlg, IDC_DECRYPT_MSG, c->info );              if (res && !res->recipients) {
116                    const char *s = _("Symmetric encryption.\n"
117                                      "%s encrypted data.");
118                    const char *alg = get_symkey_algo (c->sym.sym_algo);
119                    info = new char[strlen (s) + strlen (alg) + 2];
120                    if (!info)
121                        BUG (NULL);
122                    sprintf (info, s, alg);
123                    SetDlgItemText (dlg, IDC_DECRYPT_MSG, info);
124                    free_if_alloc (info);
125                }
126                else
127                    SetDlgItemText (dlg, IDC_DECRYPT_MSG, c->info);
128          }          }
129          else {          else {
130              SetFocus( GetDlgItem( dlg, IDC_DECRYPT_SIGN_PWD ) );              SetFocus( GetDlgItem (dlg, IDC_DECRYPT_SIGN_PWD));
131              SetDlgItemText( dlg, IDC_DECRYPT_SIGN_MSG, c->info );              SetDlgItemText (dlg, IDC_DECRYPT_SIGN_MSG, c->info);
132          }          }
133          center_window( dlg );          center_window (dlg, NULL);
134          SetForegroundWindow( dlg );          SetForegroundWindow (dlg);
135          set_active_window( dlg );          set_active_window (dlg);
136          return FALSE;          return FALSE;
137    
138          case WM_SYSCOMMAND:          case WM_SYSCOMMAND:
# Line 110  passphrase_callback_proc (HWND dlg, UINT Line 141  passphrase_callback_proc (HWND dlg, UINT
141                  c->cancel = 1;                  c->cancel = 1;
142                  EndDialog( dlg, TRUE );                  EndDialog( dlg, TRUE );
143              }              }
144              return FALSE;              break;
145    
146          case WM_COMMAND:          case WM_COMMAND:
147              switch( HIWORD( wparam ) ) {              switch( HIWORD( wparam ) ) {
# Line 120  passphrase_callback_proc (HWND dlg, UINT Line 151  passphrase_callback_proc (HWND dlg, UINT
151                      HWND hwnd;                      HWND hwnd;
152                      int hide = IsDlgButtonChecked (dlg, item_ctrl_id2 (c->gpg_cmd));                      int hide = IsDlgButtonChecked (dlg, item_ctrl_id2 (c->gpg_cmd));
153                      hwnd = GetDlgItem (dlg, item_ctrl_id (c->gpg_cmd));                      hwnd = GetDlgItem (dlg, item_ctrl_id (c->gpg_cmd));
154                      SendMessage( hwnd, EM_SETPASSWORDCHAR, hide? '*' : 0, 0 );                      SendMessage (hwnd, EM_SETPASSWORDCHAR, hide? '*' : 0, 0);
155                      SetFocus (hwnd);                      SetFocus (hwnd);
156                  }                  }
157              }              }
# Line 130  passphrase_callback_proc (HWND dlg, UINT Line 161  passphrase_callback_proc (HWND dlg, UINT
161                  /* fixme: the item is even cached when the passphrase is not                  /* fixme: the item is even cached when the passphrase is not
162                            correct, which means that the user needs to delete all                            correct, which means that the user needs to delete all
163                            cached entries to continue. */                            cached entries to continue. */
164                  GetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), c->pwd, sizeof (c->pwd) -1);                  if (c->pwd) {
165                  if (reg_prefs.cache_time > 0 && !c->is_card && !strstr (c->keyid, "missing")) {                      delete []c->pwd;
166                        c->pwd = NULL;
167                    }
168                    n = item_get_text_length (dlg, item_ctrl_id (c->gpg_cmd));
169                    if (!n) {
170                        c->pwd = new char[2];
171                        strcpy (c->pwd, "");
172                    }
173                    else {
174                        c->pwd = new char[n+2];
175                        if (!c->pwd)
176                            BUG (NULL);
177                        GetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), c->pwd, n+1);
178                    }
179                    res = gpgme_op_decrypt_result (c->gpg);
180                    if (!res)
181                        res_sig = gpgme_op_sign_result (c->gpg);
182                    if (reg_prefs.cache_time > 0 && !c->is_card &&
183                        ((res && res->recipients) || (res_sig && res_sig->signatures))) {
184                      if (agent_get_cache (c->keyid, &item))                      if (agent_get_cache (c->keyid, &item))
185                          agent_unlock_cache_entry (&item);                          agent_unlock_cache_entry (&item);
186                      else                      else
# Line 150  passphrase_callback_proc (HWND dlg, UINT Line 199  passphrase_callback_proc (HWND dlg, UINT
199      }      }
200            
201      return FALSE;      return FALSE;
202  } /* passphrase_callback_proc */  }
203    
204    
205  static const char *  /* Extract the main keyid from @pass_info.
206  parse_gpg_keyid (const char * desc)     Return value: long main keyid or NULL for an error. */
207    static const char*
208    parse_gpg_keyid (const char *pass_info)
209  {  {
210      static char keyid[16+1];      static char keyid[16+1];
     char * p;  
211            
212      p = strrchr (desc, '\n');      if (strlen (pass_info) < 16)
     if( !p )  
213          return NULL;          return NULL;
214      /* the format of the desc buffer looks like this:      /* the format of the desc buffer looks like this:
215         request_keyid[16] main_keyid[16] keytype[1] keylength[4]         request_keyid[16] main_keyid[16] keytype[1] keylength[4]
216         we use the main keyid to use only one cache entry. */         we use the main keyid to use only one cache entry. */
217      strncpy (keyid, desc+(p-desc+1+17), 16);      strncpy (keyid, pass_info+17, 16);
218        keyid[16] = 0;
219      return keyid;      return keyid;
220  } /* parse_gpg_keyid */  }
221    
222    
223    /* Parse the information in @uid_hint and @pass_info to generate
224       a input message for the user in @desc. */
225  static void  static void
226  parse_gpg_description( char * desc, int size )  parse_gpg_description (const char *uid_hint, const char *pass_info,
227                           char *desc, int size)
228  {  {
229      char * buffer = NULL, ch, uid[128] = {0}, * uid2 = NULL;      gpgme_pubkey_algo_t algo;
230      char usedkey[16+1] = {0}, mainkey[16+1] = {0};      char usedkey[16+1], mainkey[16+1];
231      const char * buf;      char *uid, *p;
232      int i, algo, try_again = 0;      int n=0;
233    
234      if( stristr( desc, "[User ID hint missing]" )      while (p = strsep ((char**)&pass_info, " ")) {
235          || stristr( desc, "[passphrase info missing]" ) ) {          switch (n++) {
236          _snprintf( desc, size-1,          case 0: strncpy (mainkey, p, 16); mainkey[16] = 0; break;
237                     _("You need a passphrase to unlock the secret key for\n"          case 1: strncpy (usedkey, p, 16); usedkey[16] = 0; break;
238                       "user: [UserID hint missing]\n"          case 2: algo = (gpgme_pubkey_algo_t)atol (p); break;
                      "      [passphrase info missing]\n") );  
         return;  
     }  
   
     buffer = new char[size+1];  
     if( !buffer )  
         BUG( NULL );  
     strcpy( buffer, desc );  
     buf = buffer;  
     if( strstr( buf, "TRY_AGAIN" ) ) {  
         buf += strlen( "TRY_AGAIN\n" );  
         try_again = 1;  
     }  
     else if( strstr( buf, "ENTER_PASSPHRASE" ) )  
         buf += strlen( "ENTER_PASSPHRASE\n" );  
     else  
         BUG( NULL );  
     buf += 17;  
     for( i = 0; i < sizeof uid-1; i++ ) {  
         ch = *buf++;  
         if( ch == '\n' ) {  
             uid[i] = '\0';  
             break;  
239          }          }
         uid[i] = ch;  
240      }      }
241      memcpy( usedkey, buf, 16 );      uid_hint += 16; /* skip keyid */
242      usedkey[16] = '\0';      uid_hint += 1;  /* space */
     buf += 17;  
     memcpy( mainkey, buf, 16 );  
     mainkey[16] = '\0';  
     buf += 17;  
     if( !buf )  
         BUG( NULL );  
     algo = atol( buf );  
     free_if_alloc( buffer );  
243    
244      uid2 = utf8_to_wincp (uid, strlen (uid));      uid = utf8_to_wincp (uid_hint, strlen (uid_hint));
245    
246      if( strcmp( usedkey, mainkey ) )      if (strcmp (usedkey, mainkey))
247          _snprintf( desc, size-1,          _snprintf (desc, size-1,
248                     _("You need a passphrase to unlock the secret key for\n"                     _("You need a passphrase to unlock the secret key for\n"
249                       "user: \"%s\"\n"                       "user: \"%s\"\n"
250                       "%s key, ID %s (main key ID %s)\n"),                       "%s key, ID %s (main key ID %s)\n"),
251                     uid2, gpgme_key_expand_attr( GPGME_ATTR_ALGO, algo ),                     uid, get_key_pubalgo (algo), usedkey+8, mainkey+8);
252                     usedkey+8, mainkey+8 );      else if (!strcmp (usedkey, mainkey))
253      else if( !strcmp( usedkey, mainkey ) )          _snprintf (desc, size-1,
         _snprintf( desc, size-1,  
254                     _("You need a passphrase to unlock the secret key for\n"                     _("You need a passphrase to unlock the secret key for\n"
255                       "user: \"%s\"\n"                       "user: \"%s\"\n"
256                       "%s key, ID %s\n"),                       "%s key, ID %s\n"),
257                       uid2, gpgme_key_expand_attr( GPGME_ATTR_ALGO, algo ),                       uid, get_key_pubalgo (algo), usedkey+8);
258                       usedkey+8 );      free (uid);
259      free( uid2 );  }
 } /* parse_gpg_describtion */  
260    
261    
262  static int inline  static int inline
263  is_hexstring( const char * p )  is_hexstring (const char * p)
264  {  {
265      size_t i;      size_t i;
266      for( i=0; i < strlen( p ); i++ ) {  
267          if( !isxdigit( p[i] ) )      for (i=0; i < strlen (p); i++) {
268            if (!isxdigit (p[i]))
269              return -1;              return -1;
270      }      }
271      return 0;      return 0;
272  }  }
273    
274    
275  const char *  /* Passphrase callback with the ability to support caching. */
276  passphrase_cb( void * opaque, const char * desc, void * r_hd )  gpgme_error_t
277  {    passphrase_cb (void *hook, const char *uid_hint,
278      passphrase_cb_s * c = (passphrase_cb_s *)opaque;                 const char *passphrase_info,
279      void * item;                 int prev_was_bad, int fd)
280      const char * pass, * keyid;  {
281      int rc = 0;      passphrase_cb_s *c = (passphrase_cb_s*)hook;
282        HANDLE hd = (HANDLE)fd;
283      if( !c )      void *item;
284          return NULL;      const char *keyid, *pass;
285        DWORD n;
286        int rc;
287    
288        /* XXX: pubkey_enc cancel does not quit gpg.exe */
289        /* XXX: handle prev_was_bad case. */
290        if (!c)
291            return gpg_error (GPG_ERR_INV_ARG);
292    
293        if (passphrase_info) {
294            if (strlen (passphrase_info) < 16) {/* assume symetric encryption. */
295                int n=2;
296                c->sym.sym_algo = atoi (passphrase_info);
297                if (c->sym.sym_algo > 9)
298                    n++;
299                /* XXX: be more strict. */
300                c->sym.s2k_mode = atoi (passphrase_info+n);
301                c->sym.s2k_hash = atoi (passphrase_info+n+2);
302            }
303    
304      if( desc ) {          keyid = parse_gpg_keyid (passphrase_info);
305          keyid = parse_gpg_keyid (desc);          pass = agent_get_cache (keyid+8, &item);
306          pass = agent_get_cache( keyid, &item );          if (pass) {
307          if( pass ) {              agent_unlock_cache_entry (&item);
             agent_unlock_cache_entry( &item );  
308              c->pwd_init = 0;              c->pwd_init = 0;
309              return pass;              if (!WriteFile (hd, pass, strlen (pass), &n, NULL))
310                    log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
311                if (!WriteFile (hd, "\n", 1, &n, NULL))
312                    log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
313                return 0;
314          }          }
315      }      }
316    
317      if( c->pwd_init ) {      if (c->pwd_init) {
318          c->keyid = keyid;          if (keyid && strlen (keyid) == 16)
319                strcpy (c->keyid, keyid+8);
320    
321          /* if the desc has a length of 32 and only hex digits, we assume a          /* if the desc has a length of 32 and only hex digits, we assume a
322             smart card has been used. */             smart card has been used. */
323          /*log_box( "", 0, "%s %d %d", desc,strlen( desc), is_hexstring( desc ) );*/          if (uid_hint && strlen (uid_hint) == 32 && !is_hexstring (uid_hint)) {
         if( desc && strlen( desc ) == 32 && !is_hexstring( desc ) ) {  
324              char buf[16];              char buf[16];
325              memset( buf, 0, sizeof buf );              memset (buf, 0, sizeof buf);
326              strncpy( buf, desc+20, 8 );              strncpy (buf, uid_hint+20, 8);
327              _snprintf( c->info, sizeof c->info-1,              _snprintf (c->info, sizeof c->info-1,
328                      _("Please enter the PIN to unlock your secret card key\n"                         _("Please enter the PIN to unlock your secret card key\n"
329                        "Card: %s"), buf );                           "Card: %s"), buf);
330              c->is_card = 1;              c->is_card = 1;
331          }          }
332          else if(desc) {          else if (uid_hint)
333              strcpy (c->info, desc);              parse_gpg_description (uid_hint, passphrase_info,
334              parse_gpg_description (c->info, sizeof c->info - 1);                                     c->info, sizeof c->info - 1);
335          }          if (c->gpg_cmd == GPG_CMD_DECRYPT) {
336          if( c->gpg_cmd == GPG_CMD_DECRYPT ) {              rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT,
337              rc = DialogBoxParam( glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT,                                   (HWND)c->hwnd, passphrase_callback_proc,
338                                  (HWND)c->hwnd, passphrase_callback_proc,                                   (LPARAM)c);
339                                  (LPARAM)c );          }
340          }          else if (c->gpg_cmd == GPG_CMD_SIGN) {
341          else if( c->gpg_cmd == GPG_CMD_SIGN ) {              rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT_SIGN,
342              rc = DialogBoxParam( glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT_SIGN,                                   (HWND)c->hwnd, passphrase_callback_proc,
343                                  (HWND)c->hwnd, passphrase_callback_proc,                                   (LPARAM)c);
344                                  (LPARAM)c );          }
345            if (rc == -1) {
346                WriteFile (hd, "\n", 1, &n, NULL);
347                return gpg_error (GPG_ERR_EOF);
348          }          }
         if( rc == -1 )  
             return NULL;  
349          c->pwd_init = 0;          c->pwd_init = 0;
350      }      }
351        if (c->cancel) {
352            WriteFile (hd, "\n", 1, &n, NULL);
353            return gpg_error (GPG_ERR_EOF);
354        }
355    
356      if( c->cancel )      WriteFile (hd, c->pwd, strlen (c->pwd), &n, NULL);
357          return NULL;      WriteFile (hd, "\n", 1, &n, NULL);
358        return 0;
359      return c->pwd;  }
 } /* passphrase_cb */  
360    
361    
362    /* Initialize the given passphrase callback @cb with the
363       used gpgme context @ctx, the command @cmd and a title
364       @title for the dialog. */
365  void  void
366  set_gpg_passphrase_cb (gpgme_ctx_t c, passphrase_cb_s *ctx, int cmd,  set_gpg_passphrase_cb (passphrase_cb_s *cb, gpgme_ctx_t ctx,
367                         HWND hwnd, const char *title)                         int cmd, HWND hwnd, const char *title)
368  {  {
369      ctx->gpg_cmd = cmd;      memset (cb, 0, sizeof *cb);
370      ctx->is_card = 0;      cb->gpg_cmd = cmd;
371      ctx->cancel = 0;      cb->is_card = 0;
372      ctx->hwnd = hwnd;      cb->cancel = 0;
373      ctx->pwd_init = 1;      cb->hwnd = hwnd;
374      if (strlen (title) > 256)      cb->pwd_init = 1;
375          BUG (NULL); /* check bounds */      free_if_alloc (cb->title);
376      strcpy (ctx->title, title);      cb->title = m_strdup (title);
377      gpgme_set_passphrase_cb (c, passphrase_cb, ctx);      if (!cb->title)
378  } /* set_gpg_passphrase_cb */          BUG (NULL);
379        gpgme_set_passphrase_cb (ctx, passphrase_cb, cb);
380        cb->gpg = ctx;
381    }
382    
383    
384    /* Release a passphrase callback @ctx. */
385    void
386    release_gpg_passphrase_cb (passphrase_cb_s *ctx)
387    {
388        if (!ctx)
389            return;
390        sfree_if_alloc (ctx->pwd);
391        free_if_alloc (ctx->title);
392    }
393    
394    /* Simple check to measure passphrase (@pass) quality.
395       Return value: 0 on success. */
396  int  int
397  check_passwd_quality (const char *pass, int strict)  check_passwd_quality (const char *pass, int strict)
398  {  {

Legend:
Removed from v.22  
changed lines
  Added in v.25

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26