2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Simon Josefsson
3 * Copyright (C) 2001,2003 Nikos Mavrogiannopoulos
4 * Copyright (C) 2004 Free Software Foundation
6 * This file is part of GNUTLS.
8 * GNUTLS is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * GNUTLS is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include <gnutls/gnutls.h>
28 #include <gnutls/extra.h>
29 #include <crypt-gaa.h>
30 #include "../lib/random.h" /* for random */
32 #include <sys/types.h>
42 /* Gnulib portability files. */
46 #include <version-etc.h>
48 /* This may need some rewrite. A lot of stuff which should be here
49 * are in the library, which is not good.
52 int crypt_int (const char *username
, const char *passwd
, int salt
,
53 char *tpasswd_conf
, char *tpasswd
, int uindex
);
54 static int read_conf_values (gnutls_datum_t
* g
, gnutls_datum_t
* n
,
56 static int _verify_passwd_int (const char *username
, const char *passwd
,
57 char *verifier
, char *salt
,
58 const gnutls_datum_t
* g
,
59 const gnutls_datum_t
* n
);
62 print_num (const char *msg
, const gnutls_datum_t
* num
)
66 printf ("%s:\t", msg
);
68 for (i
= 0; i
< num
->size
; i
++)
70 if (i
!= 0 && i
% 12 == 0)
72 else if (i
!= 0 && i
!= num
->size
)
74 printf ("%.2x", num
->data
[i
]);
81 generate_create_conf (char *tpasswd_conf
)
87 gnutls_datum_t str_g
, str_n
;
89 fd
= fopen (tpasswd_conf
, "w");
92 fprintf (stderr
, "Cannot open file '%s'\n", tpasswd_conf
);
96 for (index
= 1; index
<= 3; index
++)
101 n
= gnutls_srp_1024_group_prime
;
102 g
= gnutls_srp_1024_group_generator
;
106 n
= gnutls_srp_1536_group_prime
;
107 g
= gnutls_srp_1536_group_generator
;
111 n
= gnutls_srp_2048_group_prime
;
112 g
= gnutls_srp_2048_group_generator
;
115 printf ("\nGroup %d, of %d bits:\n", index
, n
.size
* 8);
116 print_num ("Generator", &g
);
117 print_num ("Prime", &n
);
119 if (gnutls_srp_base64_encode_alloc (&n
, &str_n
) < 0)
121 fprintf (stderr
, "Could not encode\n");
125 if (gnutls_srp_base64_encode_alloc (&g
, &str_g
) < 0)
127 fprintf (stderr
, "Could not encode\n");
131 sprintf (line
, "%d:%s:%s\n", index
, str_n
.data
, str_g
.data
);
133 gnutls_free (str_n
.data
);
134 gnutls_free (str_g
.data
);
136 fwrite (line
, 1, strlen (line
), fd
);
146 /* The format of a tpasswd file is:
147 * username:verifier:salt:index
149 * index is the index of the prime-generator pair in tpasswd.conf
152 _verify_passwd_int (const char *username
, const char *passwd
,
153 char *verifier
, char *salt
,
154 const gnutls_datum_t
* g
, const gnutls_datum_t
* n
)
157 gnutls_datum_t tmp
, raw_salt
, new_verifier
;
161 if (salt
== NULL
|| verifier
== NULL
)
164 /* copy salt, and null terminate after the ':' */
165 strcpy (_salt
, salt
);
166 pos
= strchr (_salt
, ':');
170 /* convert salt to binary. */
172 tmp
.size
= strlen (_salt
);
174 if (gnutls_srp_base64_decode_alloc (&tmp
, &raw_salt
) < 0)
176 fprintf (stderr
, "Could not decode salt.\n");
180 if (gnutls_srp_verifier
181 (username
, passwd
, &raw_salt
, g
, n
, &new_verifier
) < 0)
183 fprintf (stderr
, "Could not make the verifier\n");
187 free (raw_salt
.data
);
189 /* encode the verifier into _salt */
190 salt_size
= sizeof (_salt
);
191 memset (_salt
, 0, salt_size
);
192 if (gnutls_srp_base64_encode (&new_verifier
, _salt
, &salt_size
) < 0)
194 fprintf (stderr
, "Encoding error\n");
198 free (new_verifier
.data
);
200 if (strncmp (verifier
, _salt
, strlen (_salt
)) == 0)
202 fprintf (stderr
, "Password verified\n");
207 fprintf (stderr
, "Password does NOT match\n");
213 filecopy (char *src
, char *dst
)
219 fd
= fopen (dst
, "w");
222 fprintf (stderr
, "Cannot open '%s' for write\n", dst
);
226 fd2
= fopen (src
, "r");
234 line
[sizeof (line
) - 1] = 0;
237 p
= fgets (line
, sizeof (line
) - 1, fd2
);
251 /* accepts password file */
253 find_strchr (char *username
, char *file
)
260 fd
= fopen (file
, "r");
263 fprintf (stderr
, "Cannot open file '%s'\n", file
);
267 while (fgets (line
, sizeof (line
), fd
) != NULL
)
269 /* move to first ':' */
271 while ((line
[i
] != ':') && (line
[i
] != '\0') && (i
< sizeof (line
)))
275 if (strncmp (username
, line
, MAX (i
, strlen (username
))) == 0)
278 pos
= strrchr (line
, ':');
289 /* Parses the tpasswd files, in order to verify the given
290 * username/password pair.
293 verify_passwd (char *conffile
, char *tpasswd
, char *username
,
303 iindex
= find_strchr (username
, tpasswd
);
306 fprintf (stderr
, "Cannot find '%s' in %s\n", username
, tpasswd
);
310 fd
= fopen (conffile
, "r");
313 fprintf (stderr
, "Cannot find %s\n", conffile
);
319 p
= fgets (line
, sizeof (line
) - 1, fd
);
321 while (p
!= NULL
&& atoi (p
) != iindex
);
325 fprintf (stderr
, "Cannot find entry in %s\n", conffile
);
328 line
[sizeof (line
) - 1] = 0;
332 if ((iindex
= read_conf_values (&g
, &n
, line
)) < 0)
334 fprintf (stderr
, "Cannot parse conf file '%s'\n", conffile
);
338 fd
= fopen (tpasswd
, "r");
341 fprintf (stderr
, "Cannot open file '%s'\n", tpasswd
);
345 while (fgets (line
, sizeof (line
), fd
) != NULL
)
348 * This is the actual verifier.
351 while ((line
[i
] != ':') && (line
[i
] != '\0') && (i
< sizeof (line
)))
355 if (strncmp (username
, line
, MAX (i
, strlen (username
))) == 0)
357 char *verifier_pos
, *salt_pos
;
359 pos
= strchr (line
, ':');
363 fprintf (stderr
, "Cannot parse conf file '%s'\n", conffile
);
369 /* Move to the salt */
370 pos
= strchr (pos
, ':');
373 fprintf (stderr
, "Cannot parse conf file '%s'\n", conffile
);
379 return _verify_passwd_int (username
, passwd
,
380 verifier_pos
, salt_pos
, &g
, &n
);
389 #define KPASSWD "/etc/tpasswd"
390 #define KPASSWD_CONF "/etc/tpasswd.conf"
393 main (int argc
, char **argv
)
400 set_program_name (argv
[0]);
402 if ((ret
= gnutls_global_init ()) < 0)
404 fprintf (stderr
, "global_init: %s\n", gnutls_strerror (ret
));
410 if (gaa (argc
, argv
, &info
) != -1)
412 fprintf (stderr
, "Error in the arguments.\n");
416 if (info
.create_conf
!= NULL
)
418 return generate_create_conf (info
.create_conf
);
421 if (info
.passwd
== NULL
)
422 info
.passwd
= (char*) KPASSWD
;
423 if (info
.passwd_conf
== NULL
)
424 info
.passwd_conf
= (char*) KPASSWD_CONF
;
426 if (info
.username
== NULL
)
429 pwd
= getpwuid (getuid ());
433 fprintf (stderr
, "No such user\n");
437 info
.username
= pwd
->pw_name
;
439 fprintf (stderr
, "Please specify a user\n");
446 passwd
= getpass ("Enter password: ");
449 fprintf (stderr
, "Please specify a password\n");
454 if (info
.verify
!= 0)
456 return verify_passwd (info
.passwd_conf
, info
.passwd
,
457 info
.username
, passwd
);
461 return crypt_int (info
.username
, passwd
, salt_size
,
462 info
.passwd_conf
, info
.passwd
, info
.index
);
467 _srp_crypt (const char *username
, const char *passwd
, int salt_size
,
468 const gnutls_datum_t
* g
, const gnutls_datum_t
* n
)
471 static char result
[1024];
472 gnutls_datum_t dat_salt
, txt_salt
;
473 gnutls_datum_t verifier
, txt_verifier
;
475 if ((unsigned) salt_size
> sizeof (salt
))
480 if (_gnutls_rnd (GNUTLS_RND_NONCE
, salt
, salt_size
) < 0)
482 fprintf (stderr
, "Could not create nonce\n");
486 dat_salt
.data
= salt
;
487 dat_salt
.size
= salt_size
;
489 if (gnutls_srp_verifier (username
, passwd
, &dat_salt
, g
, n
, &verifier
) < 0)
491 fprintf (stderr
, "Error getting verifier\n");
495 /* base64 encode the verifier */
496 if (gnutls_srp_base64_encode_alloc (&verifier
, &txt_verifier
) < 0)
498 fprintf (stderr
, "Error encoding\n");
499 free (verifier
.data
);
503 free (verifier
.data
);
505 if (gnutls_srp_base64_encode_alloc (&dat_salt
, &txt_salt
) < 0)
507 fprintf (stderr
, "Error encoding\n");
511 sprintf (result
, "%s:%s", txt_verifier
.data
, txt_salt
.data
);
512 free (txt_salt
.data
);
513 free (txt_verifier
.data
);
521 crypt_int (const char *username
, const char *passwd
, int salt_size
,
522 char *tpasswd_conf
, char *tpasswd
, int uindex
)
532 fd
= fopen (tpasswd_conf
, "r");
535 fprintf (stderr
, "Cannot find %s\n", tpasswd_conf
);
540 { /* find the specified uindex in file */
541 p
= fgets (line
, sizeof (line
) - 1, fd
);
544 while (p
!= NULL
&& iindex
!= uindex
);
548 fprintf (stderr
, "Cannot find entry in %s\n", tpasswd_conf
);
551 line
[sizeof (line
) - 1] = 0;
554 if ((iindex
= read_conf_values (&g
, &n
, line
)) < 0)
556 fprintf (stderr
, "Cannot parse conf file '%s'\n", tpasswd_conf
);
560 cr
= _srp_crypt (username
, passwd
, salt_size
, &g
, &n
);
563 fprintf (stderr
, "Cannot _srp_crypt()...\n");
568 /* delete previous entry */
573 if (strlen (tpasswd
) > sizeof (tmpname
) + 5)
575 fprintf (stderr
, "file '%s' is tooooo long\n", tpasswd
);
578 strcpy (tmpname
, tpasswd
);
579 strcat (tmpname
, ".tmp");
581 if (stat (tmpname
, &st
) != -1)
583 fprintf (stderr
, "file '%s' is locked\n", tpasswd
);
587 if (filecopy (tpasswd
, tmpname
) != 0)
589 fprintf (stderr
, "Cannot copy '%s' to '%s'\n", tpasswd
, tmpname
);
593 fd
= fopen (tpasswd
, "w");
596 fprintf (stderr
, "Cannot open '%s' for write\n", tpasswd
);
601 fd2
= fopen (tmpname
, "r");
604 fprintf (stderr
, "Cannot open '%s' for read\n", tmpname
);
612 p
= fgets (line
, sizeof (line
) - 1, fd2
);
616 pp
= strchr (line
, ':');
620 if (strncmp (p
, username
,
621 MAX (strlen (username
), (unsigned int) (pp
- p
))) == 0)
624 fprintf (fd
, "%s:%s:%u\n", username
, cr
, iindex
);
635 fprintf (fd
, "%s:%s:%u\n", username
, cr
, iindex
);
651 /* this function parses tpasswd.conf file. Format is:
652 * int(index):base64(n):base64(g)
655 read_conf_values (gnutls_datum_t
* g
, gnutls_datum_t
* n
, char *str
)
664 p
= strrchr (str
, ':'); /* we have g */
673 /* read the generator */
675 if (p
[len
- 1] == '\n')
680 ret
= gnutls_srp_base64_decode_alloc (&dat
, g
);
684 fprintf (stderr
, "Decoding error\n");
688 /* now go for n - modulo */
689 p
= strrchr (str
, ':'); /* we have n */
699 dat
.size
= strlen (p
);
701 ret
= gnutls_srp_base64_decode_alloc (&dat
, n
);
705 fprintf (stderr
, "Decoding error\n");
713 extern void srptool_version(void);
716 srptool_version (void)
718 const char *p
= PACKAGE_NAME
;
719 if (strcmp (gnutls_check_version (NULL
), PACKAGE_VERSION
) != 0)
721 version_etc (stdout
, "srptool", p
, gnutls_check_version (NULL
),
722 "Nikos Mavrogiannopoulos", (char *) NULL
);