Add announcement message.
[gnutls.git] / src / psk.c
blob75ab745bfee06af9bb86f2173b2253f28380ba51
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 struct passwd *pwd;
74 unsigned char key[MAX_KEY_SIZE];
75 char hex_key[MAX_KEY_SIZE * 2 + 1];
76 gnutls_datum_t dkey;
77 size_t hex_key_size = sizeof (hex_key);
79 set_program_name (argv[0]);
81 if ((ret = gnutls_global_init ()) < 0)
83 fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
84 exit (1);
87 umask (066);
89 if (gaa (argc, argv, &info) != -1)
91 fprintf (stderr, "Error in the arguments.\n");
92 return -1;
95 if (info.passwd == NULL)
96 info.passwd = (char *) KPASSWD;
98 if (info.username == NULL)
100 #ifndef _WIN32
101 pwd = getpwuid (getuid ());
103 if (pwd == NULL)
105 fprintf (stderr, "No such user\n");
106 return -1;
109 info.username = pwd->pw_name;
110 #else
111 fprintf (stderr, "Please specify a user\n");
112 return -1;
113 #endif
116 if (info.key_size > MAX_KEY_SIZE)
118 fprintf (stderr, "Key size is too long\n");
119 exit (1);
122 if (info.netconf_hint)
124 char *passwd;
126 if (info.key_size != 0 && info.key_size != 20)
128 fprintf (stderr, "For netconf, key size must always be 20.\n");
129 exit (1);
132 passwd = getpass ("Enter password: ");
133 if (passwd == NULL)
135 fprintf (stderr, "Please specify a password\n");
136 exit (1);
139 ret = gnutls_psk_netconf_derive_key (passwd,
140 info.username,
141 info.netconf_hint, &dkey);
142 if (ret < 0)
144 fprintf (stderr, "Deriving the key failed\n");
145 exit (1);
148 else
150 if (info.key_size < 1)
151 info.key_size = 16;
153 printf ("Generating a random key for user '%s'\n", info.username);
155 ret = _gnutls_rnd (GNUTLS_RND_RANDOM, (char *) key, info.key_size);
156 if (ret < 0)
158 fprintf (stderr, "Not enough randomness\n");
159 exit (1);
162 dkey.data = key;
163 dkey.size = info.key_size;
166 ret = gnutls_hex_encode (&dkey, hex_key, &hex_key_size);
167 if (info.netconf_hint)
168 gnutls_free (dkey.data);
169 if (ret < 0)
171 fprintf (stderr, "HEX encoding error\n");
172 exit (1);
175 ret = write_key (info.username, hex_key, hex_key_size, info.passwd);
176 if (ret == 0)
177 printf ("Key stored to %s\n", info.passwd);
179 return ret;
182 static int
183 filecopy (char *src, char *dst)
185 FILE *fd, *fd2;
186 char line[5 * 1024];
187 char *p;
189 fd = fopen (dst, "w");
190 if (fd == NULL)
192 fprintf (stderr, "Cannot open '%s' for write\n", dst);
193 return -1;
196 fd2 = fopen (src, "r");
197 if (fd2 == NULL)
199 /* empty file */
200 fclose (fd);
201 return 0;
204 line[sizeof (line) - 1] = 0;
207 p = fgets (line, sizeof (line) - 1, fd2);
208 if (p == NULL)
209 break;
211 fputs (line, fd);
213 while (1);
215 fclose (fd);
216 fclose (fd2);
218 return 0;
221 static int
222 write_key (const char *username, const char *key, int key_size,
223 char *passwd_file)
225 FILE *fd;
226 char line[5 * 1024];
227 char *p, *pp;
228 char tmpname[1024];
231 /* delete previous entry */
232 struct stat st;
233 FILE *fd2;
234 int put;
236 if (strlen (passwd_file) > sizeof (tmpname) + 5)
238 fprintf (stderr, "file '%s' is tooooo long\n", passwd_file);
239 return -1;
241 strcpy (tmpname, passwd_file);
242 strcat (tmpname, ".tmp");
244 if (stat (tmpname, &st) != -1)
246 fprintf (stderr, "file '%s' is locked\n", tmpname);
247 return -1;
250 if (filecopy (passwd_file, tmpname) != 0)
252 fprintf (stderr, "Cannot copy '%s' to '%s'\n", passwd_file, tmpname);
253 return -1;
256 fd = fopen (passwd_file, "w");
257 if (fd == NULL)
259 fprintf (stderr, "Cannot open '%s' for write\n", passwd_file);
260 remove (tmpname);
261 return -1;
264 fd2 = fopen (tmpname, "r");
265 if (fd2 == NULL)
267 fprintf (stderr, "Cannot open '%s' for read\n", tmpname);
268 remove (tmpname);
269 return -1;
272 put = 0;
275 p = fgets (line, sizeof (line) - 1, fd2);
276 if (p == NULL)
277 break;
279 pp = strchr (line, ':');
280 if (pp == NULL)
281 continue;
283 if (strncmp (p, username,
284 MAX (strlen (username), (unsigned int) (pp - p))) == 0)
286 put = 1;
287 fprintf (fd, "%s:%s\n", username, key);
289 else
291 fputs (line, fd);
294 while (1);
296 if (put == 0)
298 fprintf (fd, "%s:%s\n", username, key);
301 fclose (fd);
302 fclose (fd2);
304 remove (tmpname);
307 return 0;
310 #endif /* ENABLE_PSK */
312 void psktool_version (void);
314 void
315 psktool_version (void)
317 const char *p = PACKAGE_NAME;
318 if (strcmp (gnutls_check_version (NULL), PACKAGE_VERSION) != 0)
319 p = PACKAGE_STRING;
320 version_etc (stdout, "psktool", p, gnutls_check_version (NULL),
321 "Nikos Mavrogiannopoulos", (char *) NULL);