2 * Copyright (c) 2008 Canonical Ltd. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include <sys/types.h>
35 #include <openssl/evp.h>
42 #include "pathnames.h"
45 extern char *__progname
;
47 /* Default files to check */
48 static char *default_host_files
[] = {
49 _PATH_HOST_RSA_KEY_FILE
,
50 _PATH_HOST_DSA_KEY_FILE
,
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
,
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");
76 describe_key(const char *msg
, const Key
*key
, const char *comment
)
80 fp
= key_fingerprint(key
, SSH_FP_MD5
, SSH_FP_HEX
);
82 printf("%s: %u %s %s\n", msg
, key_size(key
), fp
, comment
);
87 do_key(const Key
*key
, const char *comment
)
93 blacklist_file
= blacklist_filename(key
);
94 if (stat(blacklist_file
, &st
) < 0)
95 describe_key("Unknown (no blacklist information)",
97 else if (blacklisted_key(key
)) {
98 describe_key("COMPROMISED", key
, comment
);
101 describe_key("Not blacklisted", key
, comment
);
102 xfree(blacklist_file
);
108 do_filename(const char *filename
, int quiet_open
)
111 char line
[SSH_MAX_PUBKEY_BYTES
];
115 char *comment
= NULL
;
116 int found
= 0, ret
= 1;
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).
122 if (strcmp(filename
, "-") != 0) {
123 f
= fopen(filename
, "r");
125 char pubfile
[MAXPATHLEN
];
126 if (strlcpy(pubfile
, filename
, sizeof pubfile
) <
128 strlcat(pubfile
, ".pub", sizeof pubfile
) <
130 f
= fopen(pubfile
, "r");
139 while (read_keyfile_line(f
, filename
, line
, sizeof(line
),
145 /* Chop trailing newline. */
146 i
= strlen(line
) - 1;
150 /* Skip leading whitespace, empty and comment lines. */
151 for (cp
= line
; *cp
== ' ' || *cp
== '\t'; cp
++)
153 if (!*cp
|| *cp
== '\n' || *cp
== '#')
156 /* Cope with ssh-keyscan output and options in
157 * authorized_keys files.
159 space
= strchr(cp
, ' ');
163 type
= key_type_from_name(cp
);
165 /* Leading number (RSA1) or valid type (RSA/DSA) indicates
166 * that we have no host name or options to skip.
168 if (atoi(cp
) == 0 && type
== KEY_UNSPEC
) {
171 for (; *cp
&& (quoted
|| (*cp
!= ' ' && *cp
!= '\t')); cp
++) {
172 if (*cp
== '\\' && cp
[1] == '"')
173 cp
++; /* Skip both */
177 /* Skip remaining whitespace. */
178 for (; *cp
== ' ' || *cp
== '\t'; cp
++)
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')
189 if (!do_key(key
, *cp
? cp
: filename
))
194 key
= key_new(KEY_UNSPEC
);
195 if (key_read(key
, &cp
) == 1) {
196 while (*cp
== ' ' || *cp
== '\t')
198 if (!do_key(key
, *cp
? cp
: filename
))
208 if (!found
&& filename
) {
209 key
= key_load_public(filename
, &comment
);
211 if (!do_key(key
, comment
))
229 for (i
= 0; default_host_files
[i
]; i
++) {
230 if (stat(default_host_files
[i
], &st
) < 0)
232 if (!do_filename(default_host_files
[i
], 1))
240 do_user(const char *dir
)
243 char buf
[MAXPATHLEN
];
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)
251 if (!do_filename(buf
, 0))
259 main(int argc
, char **argv
)
261 int opt
, all_users
= 0;
265 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
268 __progname
= ssh_get_progname(argv
[0]);
270 SSLeay_add_all_algorithms();
271 log_init(argv
[0], SYSLOG_LEVEL_INFO
, SYSLOG_FACILITY_USER
, 1);
273 /* We don't need the RNG ourselves, but symbol references here allow
274 * ld to link us properly.
279 while ((opt
= getopt(argc
, argv
, "ahq")) != -1) {
299 while ((pw
= getpwent()) != NULL
) {
301 if (!do_user(pw
->pw_dir
))
305 } else if (optind
== argc
) {
311 if ((pw
= getpwuid(getuid())) == NULL
)
312 fprintf(stderr
, "No user found with uid %u\n",
315 if (!do_user(pw
->pw_dir
))
319 while (optind
< argc
)
320 if (!do_filename(argv
[optind
++], 0))