Tizen 2.0 Release
[external/libgnutls26.git] / src / psk.c
1 /*
2  * Copyright (C) 2005, 2007, 2008, 2009, 2010  Free Software Foundation, Inc.
3  *
4  * This file is part of GnuTLS.
5  *
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.
10  *
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.
15  *
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/>.
19  */
20
21 #include <config.h>
22
23 /* Gnulib portability files. */
24 #include <version-etc.h>
25 #include <progname.h>
26
27 #ifndef ENABLE_PSK
28
29 #include <stdio.h>
30
31 int
32 main (int argc, char **argv)
33 {
34   printf ("\nPSK not supported. This program is a dummy.\n\n");
35   return 1;
36 };
37
38 #else
39
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>
46
47 #include "../lib/random.h"      /* for random */
48
49 #include <sys/types.h>
50 #include <sys/stat.h>
51
52 #ifndef _WIN32
53 #include <pwd.h>
54 #include <unistd.h>
55 #else
56 #include <windows.h>
57 #endif
58
59 /* Gnulib portability files. */
60 #include <minmax.h>
61 #include "getpass.h"
62
63 static int write_key (const char *username, const char *key, int key_size,
64                       char *passwd_file);
65
66 #define KPASSWD "/etc/passwd.psk"
67 #define MAX_KEY_SIZE 64
68 int
69 main (int argc, char **argv)
70 {
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);
80
81   set_program_name (argv[0]);
82
83   if ((ret = gnutls_global_init ()) < 0)
84     {
85       fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
86       exit (1);
87     }
88
89   umask (066);
90
91   if (gaa (argc, argv, &info) != -1)
92     {
93       fprintf (stderr, "Error in the arguments.\n");
94       return -1;
95     }
96
97   if (info.passwd == NULL)
98     info.passwd = (char *) KPASSWD;
99
100   if (info.username == NULL)
101     {
102 #ifndef _WIN32
103       pwd = getpwuid (getuid ());
104
105       if (pwd == NULL)
106         {
107           fprintf (stderr, "No such user\n");
108           return -1;
109         }
110
111       info.username = pwd->pw_name;
112 #else
113       fprintf (stderr, "Please specify a user\n");
114       return -1;
115 #endif
116     }
117
118   if (info.key_size > MAX_KEY_SIZE)
119     {
120       fprintf (stderr, "Key size is too long\n");
121       exit (1);
122     }
123
124   if (info.key_size < 1)
125     info.key_size = 16;
126
127   printf ("Generating a random key for user '%s'\n", info.username);
128
129   ret = gnutls_rnd (GNUTLS_RND_RANDOM, (char *) key, info.key_size);
130   if (ret < 0)
131     {
132       fprintf (stderr, "Not enough randomness\n");
133       exit (1);
134     }
135
136   dkey.data = key;
137   dkey.size = info.key_size;
138
139   ret = gnutls_hex_encode (&dkey, hex_key, &hex_key_size);
140   if (ret < 0)
141     {
142       fprintf (stderr, "HEX encoding error\n");
143       exit (1);
144     }
145
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);
149
150   return ret;
151 }
152
153 static int
154 filecopy (char *src, char *dst)
155 {
156   FILE *fd, *fd2;
157   char line[5 * 1024];
158   char *p;
159
160   fd = fopen (dst, "w");
161   if (fd == NULL)
162     {
163       fprintf (stderr, "Cannot open '%s' for write\n", dst);
164       return -1;
165     }
166
167   fd2 = fopen (src, "r");
168   if (fd2 == NULL)
169     {
170       /* empty file */
171       fclose (fd);
172       return 0;
173     }
174
175   line[sizeof (line) - 1] = 0;
176   do
177     {
178       p = fgets (line, sizeof (line) - 1, fd2);
179       if (p == NULL)
180         break;
181
182       fputs (line, fd);
183     }
184   while (1);
185
186   fclose (fd);
187   fclose (fd2);
188
189   return 0;
190 }
191
192 static int
193 write_key (const char *username, const char *key, int key_size,
194            char *passwd_file)
195 {
196   FILE *fd;
197   char line[5 * 1024];
198   char *p, *pp;
199   char tmpname[1024];
200
201
202   /* delete previous entry */
203   struct stat st;
204   FILE *fd2;
205   int put;
206
207   if (strlen (passwd_file) > sizeof (tmpname) + 5)
208     {
209       fprintf (stderr, "file '%s' is tooooo long\n", passwd_file);
210       return -1;
211     }
212   strcpy (tmpname, passwd_file);
213   strcat (tmpname, ".tmp");
214
215   if (stat (tmpname, &st) != -1)
216     {
217       fprintf (stderr, "file '%s' is locked\n", tmpname);
218       return -1;
219     }
220
221   if (filecopy (passwd_file, tmpname) != 0)
222     {
223       fprintf (stderr, "Cannot copy '%s' to '%s'\n", passwd_file, tmpname);
224       return -1;
225     }
226
227   fd = fopen (passwd_file, "w");
228   if (fd == NULL)
229     {
230       fprintf (stderr, "Cannot open '%s' for write\n", passwd_file);
231       remove (tmpname);
232       return -1;
233     }
234
235   fd2 = fopen (tmpname, "r");
236   if (fd2 == NULL)
237     {
238       fprintf (stderr, "Cannot open '%s' for read\n", tmpname);
239       remove (tmpname);
240       return -1;
241     }
242
243   put = 0;
244   do
245     {
246       p = fgets (line, sizeof (line) - 1, fd2);
247       if (p == NULL)
248         break;
249
250       pp = strchr (line, ':');
251       if (pp == NULL)
252         continue;
253
254       if (strncmp (p, username,
255                    MAX (strlen (username), (unsigned int) (pp - p))) == 0)
256         {
257           put = 1;
258           fprintf (fd, "%s:%s\n", username, key);
259         }
260       else
261         {
262           fputs (line, fd);
263         }
264     }
265   while (1);
266
267   if (put == 0)
268     {
269       fprintf (fd, "%s:%s\n", username, key);
270     }
271
272   fclose (fd);
273   fclose (fd2);
274
275   remove (tmpname);
276
277
278   return 0;
279 }
280
281 #endif /* ENABLE_PSK */
282
283 void psktool_version (void);
284
285 void
286 psktool_version (void)
287 {
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);
293 }