If a callback fails try the other.
[gnutls.git] / src / psk.c
blobdab0c14340dc9b52cde41ff069af0ea9a20e0e63
1 /*
2 * Copyright (C) 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
4 * This file is part of GnuTLS.
6 * GnuTLS is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuTLS is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see
18 * <http://www.gnu.org/licenses/>.
21 #include <config.h>
23 /* Gnulib portability files. */
24 #include <version-etc.h>
25 #include <progname.h>
27 #ifndef ENABLE_PSK
29 #include <stdio.h>
31 int
32 main (int argc, char **argv)
34 printf ("\nPSK not supported. This program is a dummy.\n\n");
35 return 1;
38 #else
40 #include <stdio.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <gnutls/gnutls.h>
44 #include <gnutls/extra.h>
45 #include <psk-gaa.h>
47 #include "../lib/random.h" /* for random */
49 #include <sys/types.h>
50 #include <sys/stat.h>
52 #ifndef _WIN32
53 #include <pwd.h>
54 #include <unistd.h>
55 #else
56 #include <windows.h>
57 #endif
59 /* Gnulib portability files. */
60 #include <minmax.h>
61 #include "getpass.h"
63 static int write_key (const char *username, const char *key, int key_size,
64 char *passwd_file);
66 #define KPASSWD "/etc/passwd.psk"
67 #define MAX_KEY_SIZE 64
68 int
69 main (int argc, char **argv)
71 gaainfo info;
72 int ret;
73 #ifndef _WIN32
74 struct passwd *pwd;
75 #endif
76 unsigned char key[MAX_KEY_SIZE];
77 char hex_key[MAX_KEY_SIZE * 2 + 1];
78 gnutls_datum_t dkey;
79 size_t hex_key_size = sizeof (hex_key);
81 set_program_name (argv[0]);
83 if ((ret = gnutls_global_init ()) < 0)
85 fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
86 exit (1);
89 umask (066);
91 if (gaa (argc, argv, &info) != -1)
93 fprintf (stderr, "Error in the arguments.\n");
94 return -1;
97 if (info.passwd == NULL)
98 info.passwd = (char *) KPASSWD;
100 if (info.username == NULL)
102 #ifndef _WIN32
103 pwd = getpwuid (getuid ());
105 if (pwd == NULL)
107 fprintf (stderr, "No such user\n");
108 return -1;
111 info.username = pwd->pw_name;
112 #else
113 fprintf (stderr, "Please specify a user\n");
114 return -1;
115 #endif
118 if (info.key_size > MAX_KEY_SIZE)
120 fprintf (stderr, "Key size is too long\n");
121 exit (1);
124 if (info.key_size < 1)
125 info.key_size = 16;
127 printf ("Generating a random key for user '%s'\n", info.username);
129 ret = gnutls_rnd (GNUTLS_RND_RANDOM, (char *) key, info.key_size);
130 if (ret < 0)
132 fprintf (stderr, "Not enough randomness\n");
133 exit (1);
136 dkey.data = key;
137 dkey.size = info.key_size;
139 ret = gnutls_hex_encode (&dkey, hex_key, &hex_key_size);
140 if (ret < 0)
142 fprintf (stderr, "HEX encoding error\n");
143 exit (1);
146 ret = write_key (info.username, hex_key, hex_key_size, info.passwd);
147 if (ret == 0)
148 printf ("Key stored to %s\n", info.passwd);
150 return ret;
153 static int
154 filecopy (char *src, char *dst)
156 FILE *fd, *fd2;
157 char line[5 * 1024];
158 char *p;
160 fd = fopen (dst, "w");
161 if (fd == NULL)
163 fprintf (stderr, "Cannot open '%s' for write\n", dst);
164 return -1;
167 fd2 = fopen (src, "r");
168 if (fd2 == NULL)
170 /* empty file */
171 fclose (fd);
172 return 0;
175 line[sizeof (line) - 1] = 0;
178 p = fgets (line, sizeof (line) - 1, fd2);
179 if (p == NULL)
180 break;
182 fputs (line, fd);
184 while (1);
186 fclose (fd);
187 fclose (fd2);
189 return 0;
192 static int
193 write_key (const char *username, const char *key, int key_size,
194 char *passwd_file)
196 FILE *fd;
197 char line[5 * 1024];
198 char *p, *pp;
199 char tmpname[1024];
202 /* delete previous entry */
203 struct stat st;
204 FILE *fd2;
205 int put;
207 if (strlen (passwd_file) > sizeof (tmpname) + 5)
209 fprintf (stderr, "file '%s' is tooooo long\n", passwd_file);
210 return -1;
212 strcpy (tmpname, passwd_file);
213 strcat (tmpname, ".tmp");
215 if (stat (tmpname, &st) != -1)
217 fprintf (stderr, "file '%s' is locked\n", tmpname);
218 return -1;
221 if (filecopy (passwd_file, tmpname) != 0)
223 fprintf (stderr, "Cannot copy '%s' to '%s'\n", passwd_file, tmpname);
224 return -1;
227 fd = fopen (passwd_file, "w");
228 if (fd == NULL)
230 fprintf (stderr, "Cannot open '%s' for write\n", passwd_file);
231 remove (tmpname);
232 return -1;
235 fd2 = fopen (tmpname, "r");
236 if (fd2 == NULL)
238 fprintf (stderr, "Cannot open '%s' for read\n", tmpname);
239 remove (tmpname);
240 return -1;
243 put = 0;
246 p = fgets (line, sizeof (line) - 1, fd2);
247 if (p == NULL)
248 break;
250 pp = strchr (line, ':');
251 if (pp == NULL)
252 continue;
254 if (strncmp (p, username,
255 MAX (strlen (username), (unsigned int) (pp - p))) == 0)
257 put = 1;
258 fprintf (fd, "%s:%s\n", username, key);
260 else
262 fputs (line, fd);
265 while (1);
267 if (put == 0)
269 fprintf (fd, "%s:%s\n", username, key);
272 fclose (fd);
273 fclose (fd2);
275 remove (tmpname);
278 return 0;
281 #endif /* ENABLE_PSK */
283 void psktool_version (void);
285 void
286 psktool_version (void)
288 const char *p = PACKAGE_NAME;
289 if (strcmp (gnutls_check_version (NULL), PACKAGE_VERSION) != 0)
290 p = PACKAGE_STRING;
291 version_etc (stdout, "psktool", p, gnutls_check_version (NULL),
292 "Nikos Mavrogiannopoulos", (char *) NULL);