Add.
[gnutls.git] / src / psk.c
blob7de5ea5e2172a8155714ed4a6ea2765048839a4e
1 /*
2 * Copyright (C) 2005, 2007, 2008, 2009 Free Software Foundation
4 * This file is part of GNUTLS.
6 * GNUTLS is free software: you can redistribute it and/or modify
7 * it 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,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU 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 <http://www.gnu.org/licenses/>.
20 #include <config.h>
22 /* Gnulib portability files. */
23 #include <version-etc.h>
24 #include <progname.h>
26 #ifndef ENABLE_PSK
28 #include <stdio.h>
30 int
31 main (int argc, char **argv)
33 printf ("\nPSK not supported. This program is a dummy.\n\n");
34 return 1;
37 #else
39 #include <stdio.h>
40 #include <string.h>
41 #include <stdlib.h>
42 #include <gnutls/gnutls.h>
43 #include <gnutls/extra.h>
44 #include <psk-gaa.h>
46 #include "../lib/random.h" /* for random */
48 #include <sys/types.h>
49 #include <sys/stat.h>
51 #ifndef _WIN32
52 # include <pwd.h>
53 # include <unistd.h>
54 #else
55 # include <windows.h>
56 #endif
58 /* Gnulib portability files. */
59 #include <minmax.h>
60 #include "getpass.h"
62 static int write_key (const char *username, const char *key, int key_size,
63 char *passwd_file);
65 #define KPASSWD "/etc/passwd.psk"
66 #define MAX_KEY_SIZE 64
67 int
68 main (int argc, char **argv)
70 gaainfo info;
71 int ret;
72 struct passwd *pwd;
73 unsigned char key[MAX_KEY_SIZE];
74 char hex_key[MAX_KEY_SIZE * 2 + 1];
75 gnutls_datum_t dkey;
76 size_t hex_key_size = sizeof (hex_key);
78 set_program_name (argv[0]);
80 if ((ret = gnutls_global_init ()) < 0)
82 fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
83 exit (1);
86 umask (066);
88 if (gaa (argc, argv, &info) != -1)
90 fprintf (stderr, "Error in the arguments.\n");
91 return -1;
94 if (info.passwd == NULL)
95 info.passwd = (char*) KPASSWD;
97 if (info.username == NULL)
99 #ifndef _WIN32
100 pwd = getpwuid (getuid ());
102 if (pwd == NULL)
104 fprintf (stderr, "No such user\n");
105 return -1;
108 info.username = pwd->pw_name;
109 #else
110 fprintf (stderr, "Please specify a user\n");
111 return -1;
112 #endif
115 if (info.key_size > MAX_KEY_SIZE)
117 fprintf (stderr, "Key size is too long\n");
118 exit (1);
121 if (info.netconf_hint)
123 char *passwd;
125 if (info.key_size != 0 && info.key_size != 20)
127 fprintf (stderr, "For netconf, key size must always be 20.\n");
128 exit (1);
131 passwd = getpass ("Enter password: ");
132 if (passwd == NULL)
134 fprintf (stderr, "Please specify a password\n");
135 exit (1);
138 ret = gnutls_psk_netconf_derive_key (passwd,
139 info.username,
140 info.netconf_hint, &dkey);
141 if (ret < 0)
143 fprintf (stderr, "Deriving the key failed\n");
144 exit (1);
147 else
149 if (info.key_size < 1)
150 info.key_size = 16;
152 printf ("Generating a random key for user '%s'\n", info.username);
154 ret = _gnutls_rnd (GNUTLS_RND_RANDOM, (char *) key, info.key_size);
155 if (ret < 0)
157 fprintf (stderr, "Not enough randomness\n");
158 exit (1);
161 dkey.data = key;
162 dkey.size = info.key_size;
165 ret = gnutls_hex_encode (&dkey, hex_key, &hex_key_size);
166 if (info.netconf_hint)
167 gnutls_free (dkey.data);
168 if (ret < 0)
170 fprintf (stderr, "HEX encoding error\n");
171 exit (1);
174 ret = write_key (info.username, hex_key, hex_key_size, info.passwd);
175 if (ret == 0)
176 printf ("Key stored to %s\n", info.passwd);
178 return ret;
181 static int
182 filecopy (char *src, char *dst)
184 FILE *fd, *fd2;
185 char line[5 * 1024];
186 char *p;
188 fd = fopen (dst, "w");
189 if (fd == NULL)
191 fprintf (stderr, "Cannot open '%s' for write\n", dst);
192 return -1;
195 fd2 = fopen (src, "r");
196 if (fd2 == NULL)
198 /* empty file */
199 fclose (fd);
200 return 0;
203 line[sizeof (line) - 1] = 0;
206 p = fgets (line, sizeof (line) - 1, fd2);
207 if (p == NULL)
208 break;
210 fputs (line, fd);
212 while (1);
214 fclose (fd);
215 fclose (fd2);
217 return 0;
220 static int
221 write_key (const char *username, const char *key, int key_size,
222 char *passwd_file)
224 FILE *fd;
225 char line[5 * 1024];
226 char *p, *pp;
227 char tmpname[1024];
230 /* delete previous entry */
231 struct stat st;
232 FILE *fd2;
233 int put;
235 if (strlen (passwd_file) > sizeof (tmpname) + 5)
237 fprintf (stderr, "file '%s' is tooooo long\n", passwd_file);
238 return -1;
240 strcpy (tmpname, passwd_file);
241 strcat (tmpname, ".tmp");
243 if (stat (tmpname, &st) != -1)
245 fprintf (stderr, "file '%s' is locked\n", tmpname);
246 return -1;
249 if (filecopy (passwd_file, tmpname) != 0)
251 fprintf (stderr, "Cannot copy '%s' to '%s'\n", passwd_file, tmpname);
252 return -1;
255 fd = fopen (passwd_file, "w");
256 if (fd == NULL)
258 fprintf (stderr, "Cannot open '%s' for write\n", passwd_file);
259 remove (tmpname);
260 return -1;
263 fd2 = fopen (tmpname, "r");
264 if (fd2 == NULL)
266 fprintf (stderr, "Cannot open '%s' for read\n", tmpname);
267 remove (tmpname);
268 return -1;
271 put = 0;
274 p = fgets (line, sizeof (line) - 1, fd2);
275 if (p == NULL)
276 break;
278 pp = strchr (line, ':');
279 if (pp == NULL)
280 continue;
282 if (strncmp (p, username,
283 MAX (strlen (username), (unsigned int) (pp - p))) == 0)
285 put = 1;
286 fprintf (fd, "%s:%s\n", username, key);
288 else
290 fputs (line, fd);
293 while (1);
295 if (put == 0)
297 fprintf (fd, "%s:%s\n", username, key);
300 fclose (fd);
301 fclose (fd2);
303 remove (tmpname);
306 return 0;
309 #endif /* ENABLE_PSK */
311 void psktool_version (void);
313 void
314 psktool_version (void)
316 const char *p = PACKAGE_NAME;
317 if (strcmp (gnutls_check_version (NULL), PACKAGE_VERSION) != 0)
318 p = PACKAGE_STRING;
319 version_etc (stdout, "psktool", p, gnutls_check_version (NULL),
320 "Nikos Mavrogiannopoulos", (char *) NULL);