Update files for OpenSSH-5.9p1 import.
[dragonfly.git] / crypto / openssh / ssh-vulnkey.c
1 /*
2  * Copyright (c) 2008 Canonical Ltd.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "includes.h"
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29
30 #include <string.h>
31 #include <stdio.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34
35 #include <openssl/evp.h>
36
37 #include "xmalloc.h"
38 #include "ssh.h"
39 #include "log.h"
40 #include "key.h"
41 #include "authfile.h"
42 #include "pathnames.h"
43 #include "misc.h"
44
45 extern char *__progname;
46
47 /* Default files to check */
48 static char *default_host_files[] = {
49         _PATH_HOST_RSA_KEY_FILE,
50         _PATH_HOST_DSA_KEY_FILE,
51         _PATH_HOST_KEY_FILE,
52         NULL
53 };
54 static char *default_files[] = {
55         _PATH_SSH_CLIENT_ID_RSA,
56         _PATH_SSH_CLIENT_ID_DSA,
57         _PATH_SSH_CLIENT_IDENTITY,
58         _PATH_SSH_USER_PERMITTED_KEYS,
59         _PATH_SSH_USER_PERMITTED_KEYS2,
60         NULL
61 };
62
63 static int quiet = 0;
64
65 static void
66 usage(void)
67 {
68         fprintf(stderr, "usage: %s [-aq] [file ...]\n", __progname);
69         fprintf(stderr, "Options:\n");
70         fprintf(stderr, "  -a          Check keys of all users.\n");
71         fprintf(stderr, "  -q          Quiet mode.\n");
72         exit(1);
73 }
74
75 void
76 describe_key(const char *msg, Key *key, const char *comment)
77 {
78         char *fp;
79
80         fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
81         if (!quiet)
82                 printf("%s: %u %s %s\n", msg, key_size(key), fp, comment);
83         xfree(fp);
84 }
85
86 int
87 do_key(Key *key, const char *comment)
88 {
89         char *blacklist_file;
90         struct stat st;
91         int ret = 1;
92
93         blacklist_file = blacklist_filename(key);
94         if (stat(blacklist_file, &st) < 0)
95                 describe_key("Unknown (no blacklist information)",
96                     key, comment);
97         else if (blacklisted_key(key)) {
98                 describe_key("COMPROMISED", key, comment);
99                 ret = 0;
100         } else
101                 describe_key("Not blacklisted", key, comment);
102         xfree(blacklist_file);
103
104         return ret;
105 }
106
107 int
108 do_filename(const char *filename, int quiet_open)
109 {
110         FILE *f;
111         char line[SSH_MAX_PUBKEY_BYTES];
112         char *cp;
113         u_long linenum = 0;
114         Key *key;
115         char *comment = NULL;
116         int found = 0, ret = 1;
117
118         /* Copy much of key_load_public's logic here so that we can read
119          * several keys from a single file (e.g. authorized_keys).
120          */
121
122         if (strcmp(filename, "-") != 0) {
123                 f = fopen(filename, "r");
124                 if (!f) {
125                         char pubfile[MAXPATHLEN];
126                         if (strlcpy(pubfile, filename, sizeof pubfile) <
127                             sizeof(pubfile) &&
128                             strlcat(pubfile, ".pub", sizeof pubfile) <
129                             sizeof(pubfile))
130                                 f = fopen(pubfile, "r");
131                 }
132                 if (!f) {
133                         if (!quiet_open)
134                                 perror(filename);
135                         return -1;
136                 }
137         } else
138                 f = stdin;
139         while (read_keyfile_line(f, filename, line, sizeof(line),
140                     &linenum) != -1) {
141                 int i;
142                 char *space;
143                 int type;
144
145                 /* Chop trailing newline. */
146                 i = strlen(line) - 1;
147                 if (line[i] == '\n')
148                         line[i] = '\0';
149
150                 /* Skip leading whitespace, empty and comment lines. */
151                 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
152                         ;
153                 if (!*cp || *cp == '\n' || *cp == '#')
154                         continue;
155
156                 /* Cope with ssh-keyscan output and options in
157                  * authorized_keys files.
158                  */
159                 space = strchr(cp, ' ');
160                 if (!space)
161                         continue;
162                 *space = '\0';
163                 type = key_type_from_name(cp);
164                 *space = ' ';
165                 /* Leading number (RSA1) or valid type (RSA/DSA) indicates
166                  * that we have no host name or options to skip.
167                  */
168                 if (atoi(cp) == 0 && type == KEY_UNSPEC) {
169                         int quoted = 0;
170
171                         for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
172                                 if (*cp == '\\' && cp[1] == '"')
173                                         cp++;   /* Skip both */
174                                 else if (*cp == '"')
175                                         quoted = !quoted;
176                         }
177                         /* Skip remaining whitespace. */
178                         for (; *cp == ' ' || *cp == '\t'; cp++)
179                                 ;
180                         if (!*cp)
181                                 continue;
182                 }
183
184                 /* Read and process the key itself. */
185                 key = key_new(KEY_RSA1);
186                 if (key_read(key, &cp) == 1) {
187                         while (*cp == ' ' || *cp == '\t')
188                                 cp++;
189                         if (!do_key(key, *cp ? cp : filename))
190                                 ret = 0;
191                         found = 1;
192                 } else {
193                         key_free(key);
194                         key = key_new(KEY_UNSPEC);
195                         if (key_read(key, &cp) == 1) {
196                                 while (*cp == ' ' || *cp == '\t')
197                                         cp++;
198                                 if (!do_key(key, *cp ? cp : filename))
199                                         ret = 0;
200                                 found = 1;
201                         }
202                 }
203                 key_free(key);
204         }
205         if (f != stdin)
206                 fclose(f);
207
208         if (!found && filename) {
209                 key = key_load_public(filename, &comment);
210                 if (key) {
211                         if (!do_key(key, comment))
212                                 ret = 0;
213                         found = 1;
214                 }
215                 if (comment)
216                         xfree(comment);
217         }
218
219         return ret;
220 }
221
222 int
223 do_host(void)
224 {
225         int i;
226         struct stat st;
227         int ret = 1;
228
229         for (i = 0; default_host_files[i]; i++) {
230                 if (stat(default_host_files[i], &st) < 0)
231                         continue;
232                 if (!do_filename(default_host_files[i], 1))
233                         ret = 0;
234         }
235
236         return ret;
237 }
238
239 int
240 do_user(const char *dir)
241 {
242         int i;
243         char buf[MAXPATHLEN];
244         struct stat st;
245         int ret = 1;
246
247         for (i = 0; default_files[i]; i++) {
248                 snprintf(buf, sizeof(buf), "%s/%s", dir, default_files[i]);
249                 if (stat(buf, &st) < 0)
250                         continue;
251                 if (!do_filename(buf, 0))
252                         ret = 0;
253         }
254
255         return ret;
256 }
257
258 int
259 main(int argc, char **argv)
260 {
261         int opt, all_users = 0;
262         int ret = 1;
263         extern int optind;
264
265         /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
266         sanitise_stdfd();
267
268         __progname = ssh_get_progname(argv[0]);
269
270         SSLeay_add_all_algorithms();
271         log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
272
273         /* We don't need the RNG ourselves, but symbol references here allow
274          * ld to link us properly.
275          */
276         seed_rng();
277
278         while ((opt = getopt(argc, argv, "ahq")) != -1) {
279                 switch (opt) {
280                 case 'a':
281                         all_users = 1;
282                         break;
283                 case 'q':
284                         quiet = 1;
285                         break;
286                 case 'h':
287                 default:
288                         usage();
289                 }
290         }
291
292         if (all_users) {
293                 struct passwd *pw;
294
295                 if (!do_host())
296                         ret = 0;
297
298                 while ((pw = getpwent()) != NULL) {
299                         if (pw->pw_dir) {
300                                 if (!do_user(pw->pw_dir))
301                                         ret = 0;
302                         }
303                 }
304         } else if (optind == argc) {
305                 struct passwd *pw;
306
307                 if (!do_host())
308                         ret = 0;
309
310                 if ((pw = getpwuid(getuid())) == NULL)
311                         fprintf(stderr, "No user found with uid %u\n",
312                             (u_int)getuid());
313                 else {
314                         if (!do_user(pw->pw_dir))
315                                 ret = 0;
316                 }
317         } else {
318                 while (optind < argc)
319                         if (!do_filename(argv[optind++], 0))
320                                 ret = 0;
321         }
322
323         return ret;
324 }