818444dd3e52e636ef70f1998b2999478a8e5438
[silc.git] / apps / irssi / src / silc / core / clientutil.c
1 /*
2
3   client.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2002 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12   
13   This program 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.
17
18 */
19 /* $Id$ */
20
21 #include "module.h"
22
23 #include "net-nonblock.h"
24 #include "net-sendbuffer.h"
25 #include "signals.h"
26 #include "servers.h"
27 #include "commands.h"
28 #include "levels.h"
29 #include "modules.h"
30 #include "rawlog.h"
31 #include "misc.h"
32 #include "settings.h"
33
34 #include "channels-setup.h"
35
36 #include "silc-servers.h"
37 #include "silc-channels.h"
38 #include "silc-queries.h"
39 #include "silc-nicklist.h"
40 #include "window-item-def.h"
41
42 #include "fe-common/core/printtext.h"
43 #include "fe-common/core/keyboard.h"
44
45 #include "core.h"
46
47 /* Lists supported ciphers */
48
49 void silc_client_list_ciphers()
50 {
51   char *ciphers = silc_cipher_get_supported();
52   fprintf(stdout, "%s\n", ciphers);
53   silc_free(ciphers);
54 }
55
56 /* Lists supported hash functions */
57
58 void silc_client_list_hash_funcs()
59 {
60   char *hash = silc_hash_get_supported();
61   fprintf(stdout, "%s\n", hash);
62   silc_free(hash);
63 }
64
65 /* Lists supported hash functions */
66
67 void silc_client_list_hmacs()
68 {
69   char *hash = silc_hmac_get_supported();
70   fprintf(stdout, "%s\n", hash);
71   silc_free(hash);
72 }
73
74 /* Lists supported PKCS algorithms */
75
76 void silc_client_list_pkcs()
77 {
78   char *pkcs = silc_pkcs_get_supported();
79   fprintf(stdout, "%s\n", pkcs);
80   silc_free(pkcs);
81 }
82
83 /* This checks stats for various SILC files and directories. First it 
84    checks if ~/.silc directory exist and is owned by the correct user. If 
85    it doesn't exist, it will create the directory. After that it checks if
86    user's Public and Private key files exists and that they aren't expired.
87    If they doesn't exist or they are expired, they will be (re)created
88    after return. */
89
90 int silc_client_check_silc_dir()
91 {
92   char filename[256], file_public_key[256], file_private_key[256];
93   char servfilename[256], clientfilename[256], friendsfilename[256];
94   struct stat st;
95   struct passwd *pw;
96   time_t curtime, modtime;
97
98   SILC_LOG_DEBUG(("Checking ~./silc directory"));
99
100   memset(filename, 0, sizeof(filename));
101   memset(file_public_key, 0, sizeof(file_public_key));
102   memset(file_private_key, 0, sizeof(file_private_key));
103
104   pw = getpwuid(getuid());
105   if (!pw) {
106     fprintf(stderr, "silc: %s\n", strerror(errno));
107     return FALSE;
108   }
109
110   /* We'll take home path from /etc/passwd file to be sure. */
111   snprintf(filename, sizeof(filename) - 1, "%s/", get_irssi_dir());
112   snprintf(servfilename, sizeof(servfilename) - 1, "%s/serverkeys", 
113            get_irssi_dir());
114   snprintf(clientfilename, sizeof(clientfilename) - 1, "%s/clientkeys", 
115            get_irssi_dir());
116   snprintf(friendsfilename, sizeof(friendsfilename) - 1, "%s/friends", 
117            get_irssi_dir());
118
119   /*
120    * Check ~/.silc directory
121    */
122   if ((stat(filename, &st)) == -1) {
123     /* If dir doesn't exist */
124     if (errno == ENOENT) {
125       if (pw->pw_uid == geteuid()) {
126         if ((mkdir(filename, 0755)) == -1) {
127           fprintf(stderr, "Couldn't create `%s' directory\n", filename);
128           return FALSE;
129         }
130       } else {
131         fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
132                 filename);
133         return FALSE;
134       }
135     } else {
136       fprintf(stderr, "%s\n", strerror(errno));
137       return FALSE;
138     }
139   } else {
140     
141     /* Check the owner of the dir */
142     if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { 
143       fprintf(stderr, "You don't seem to own `%s' directory\n",
144               filename);
145       return FALSE;
146     }
147     
148 #if 0
149     /* Check the permissions of the dir */
150     if ((st.st_mode & 0777) != 0755) {
151       if ((chmod(filename, 0755)) == -1) {
152         fprintf(stderr, "Permissions for `%s' directory must be 0755\n", 
153                 filename);
154         return FALSE;
155       }
156     }
157 #endif
158   }
159
160   /*
161    * Check ~./silc/serverkeys directory
162    */
163   if ((stat(servfilename, &st)) == -1) {
164     /* If dir doesn't exist */
165     if (errno == ENOENT) {
166       if (pw->pw_uid == geteuid()) {
167         if ((mkdir(servfilename, 0755)) == -1) {
168           fprintf(stderr, "Couldn't create `%s' directory\n", servfilename);
169           return FALSE;
170         }
171       } else {
172         fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
173                 servfilename);
174         return FALSE;
175       }
176     } else {
177       fprintf(stderr, "%s\n", strerror(errno));
178       return FALSE;
179     }
180   }
181   
182   /*
183    * Check ~./silc/clientkeys directory
184    */
185   if ((stat(clientfilename, &st)) == -1) {
186     /* If dir doesn't exist */
187     if (errno == ENOENT) {
188       if (pw->pw_uid == geteuid()) {
189         if ((mkdir(clientfilename, 0755)) == -1) {
190           fprintf(stderr, "Couldn't create `%s' directory\n", clientfilename);
191           return FALSE;
192         }
193       } else {
194         fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
195                 clientfilename);
196         return FALSE;
197       }
198     } else {
199       fprintf(stderr, "%s\n", strerror(errno));
200       return FALSE;
201     }
202   }
203   
204   /*
205    * Check ~./silc/friends directory
206    */
207   if ((stat(friendsfilename, &st)) == -1) {
208     /* If dir doesn't exist */
209     if (errno == ENOENT) {
210       if (pw->pw_uid == geteuid()) {
211         if ((mkdir(friendsfilename, 0755)) == -1) {
212           fprintf(stderr, "Couldn't create `%s' directory\n", friendsfilename);
213           return FALSE;
214         }
215       } else {
216         fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
217                 friendsfilename);
218         return FALSE;
219       }
220     } else {
221       fprintf(stderr, "%s\n", strerror(errno));
222       return FALSE;
223     }
224   }
225   
226   /*
227    * Check Public and Private keys
228    */
229   snprintf(file_public_key, sizeof(file_public_key) - 1, "%s%s", 
230            filename, SILC_CLIENT_PUBLIC_KEY_NAME);
231   snprintf(file_private_key, sizeof(file_private_key) - 1, "%s%s", 
232            filename, SILC_CLIENT_PRIVATE_KEY_NAME);
233   
234   if ((stat(file_public_key, &st)) == -1) {
235     /* If file doesn't exist */
236     if (errno == ENOENT) {
237       fprintf(stdout, "Running SILC for the first time\n");
238       silc_create_key_pair(SILC_CLIENT_DEF_PKCS,
239                            SILC_CLIENT_DEF_PKCS_LEN,
240                            file_public_key, file_private_key, NULL,
241                            NULL, NULL, NULL, NULL, FALSE);
242       printf("Press <Enter> to continue...\n");
243       getchar();
244     } else {
245       fprintf(stderr, "%s\n", strerror(errno));
246       return FALSE;
247     }
248   }
249   
250   /* Check the owner of the public key */
251   if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { 
252     fprintf(stderr, "You don't seem to own your public key!?\n");
253     return FALSE;
254   }
255   
256   if ((stat(file_private_key, &st)) == -1) {
257     /* If file doesn't exist */
258     if (errno == ENOENT) {
259       fprintf(stdout, "Your private key doesn't exist\n");
260       silc_create_key_pair(SILC_CLIENT_DEF_PKCS,
261                            SILC_CLIENT_DEF_PKCS_LEN,
262                            file_public_key, file_private_key, NULL,
263                            NULL, NULL, NULL, NULL, FALSE);
264       printf("Press <Enter> to continue...\n");
265       getchar();
266     } else {
267       fprintf(stderr, "%s\n", strerror(errno));
268       return FALSE;
269     }
270   }
271     
272   /* Check the owner of the private key */
273   if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { 
274     fprintf(stderr, "You don't seem to own your private key!?\n");
275     return FALSE;
276   }
277     
278   /* Check the permissions for the private key */
279   if ((st.st_mode & 0777) != 0600) {
280     fprintf(stderr, "Wrong permissions in your private key file `%s'!\n"
281             "Trying to change them ... ", file_private_key);
282     if ((chmod(file_private_key, 0600)) == -1) {
283       fprintf(stderr,
284               "Failed to change permissions for private key file!\n" 
285               "Permissions for your private key file must be 0600.\n");
286       return FALSE;
287     }
288     fprintf(stderr, "Done.\n\n");
289   }
290
291   /* See if the key has expired. */
292   modtime = st.st_mtime;        /* last modified */
293   curtime = time(0) - modtime;
294     
295   /* 86400 is seconds in a day. */
296   if (curtime >= (86400 * SILC_CLIENT_KEY_EXPIRES)) {
297     char *answer;
298
299     fprintf(stdout, 
300             "----------------------------------------------------\n"
301             "Your private key has expired and needs to be\n" 
302             "recreated.  Would you like to create a new key pair\n"
303             "now?  If you answer Yes, the new key will expire in\n"
304             "%d days from today.  If you answer No, the old key\n"
305             "will expire again in %d days from today.\n"
306             "----------------------------------------------------\n",
307             SILC_CLIENT_KEY_EXPIRES, SILC_CLIENT_KEY_EXPIRES);
308
309     answer = silc_get_input("Would you like to create a new key pair "
310                             "([y]/n)?: ", FALSE);
311     if (!answer || answer[0] == 'Y' || answer[0] == 'y') {
312       silc_create_key_pair(SILC_CLIENT_DEF_PKCS,
313                            SILC_CLIENT_DEF_PKCS_LEN,
314                            file_public_key, file_private_key, NULL,
315                            NULL, NULL, NULL, NULL, FALSE);
316       printf("Press <Enter> to continue...\n");
317       getchar();
318     } else {
319 #ifdef HAVE_UTIME
320       struct utimbuf utim;
321       utim.actime = time(NULL);
322       utim.modtime = time(NULL);
323       utime(file_private_key, &utim);
324 #endif
325     }
326     silc_free(answer);
327   }
328   
329   return TRUE;
330 }
331
332 /* Loads public and private key from files. */
333
334 int silc_client_load_keys(SilcClient client)
335 {
336   char pub[256], prv[256];
337   struct passwd *pw;
338   bool ret;
339
340   SILC_LOG_DEBUG(("Loading public and private keys"));
341
342   pw = getpwuid(getuid());
343   if (!pw)
344     return FALSE;
345
346   memset(prv, 0, sizeof(prv));
347   snprintf(prv, sizeof(prv) - 1, "%s/%s",
348            get_irssi_dir(), SILC_CLIENT_PRIVATE_KEY_NAME);
349
350   memset(pub, 0, sizeof(pub));
351   snprintf(pub, sizeof(pub) - 1, "%s/%s",
352            get_irssi_dir(), SILC_CLIENT_PUBLIC_KEY_NAME);
353   
354   /* Try loading first with "" passphrase, for those that didn't set
355      passphrase for private key, and only if that fails let it prompt
356      for passphrase. */
357   ret = silc_load_key_pair(pub, prv, "", &client->pkcs, &client->public_key,
358                            &client->private_key);
359   if (!ret)
360     ret = silc_load_key_pair(pub, prv, NULL, &client->pkcs,
361                              &client->public_key, &client->private_key);
362   return ret;
363 }