+
+Key *
+key_load_private_type(int type, const char *filename, const char *passphrase,
+ char **commentp, int *perm_ok)
+{
+ int fd;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+ if (!key_perm_ok(fd, filename)) {
+ if (perm_ok != NULL)
+ *perm_ok = 0;
+ error("bad permissions: ignore key: %s", filename);
+ close(fd);
+ return NULL;
+ }
+ if (perm_ok != NULL)
+ *perm_ok = 1;
+ switch (type) {
+ case KEY_RSA1:
+ return key_load_private_rsa1(fd, filename, passphrase,
+ commentp);
+ /* closes fd */
+ case KEY_DSA:
+ case KEY_RSA:
+ case KEY_UNSPEC:
+ return key_load_private_pem(fd, type, passphrase, commentp);
+ /* closes fd */
+ default:
+ close(fd);
+ break;
+ }
+ return NULL;
+}
+
+Key *
+key_load_private(const char *filename, const char *passphrase,
+ char **commentp)
+{
+ Key *pub, *prv;
+ int fd;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+ if (!key_perm_ok(fd, filename)) {
+ error("bad permissions: ignore key: %s", filename);
+ close(fd);
+ return NULL;
+ }
+ pub = key_load_public_rsa1(fd, filename, commentp);
+ lseek(fd, (off_t) 0, SEEK_SET); /* rewind */
+ if (pub == NULL) {
+ /* closes fd */
+ prv = key_load_private_pem(fd, KEY_UNSPEC, passphrase, NULL);
+ /* use the filename as a comment for PEM */
+ if (commentp && prv)
+ *commentp = xstrdup(filename);
+ } else {
+ /* it's a SSH v1 key if the public key part is readable */
+ key_free(pub);
+ /* closes fd */
+ prv = key_load_private_rsa1(fd, filename, passphrase, NULL);
+ }
+ return prv;
+}
+
+static int
+key_try_load_public(Key *k, const char *filename, char **commentp)
+{
+ FILE *f;
+ char line[SSH_MAX_PUBKEY_BYTES];
+ char *cp;
+ u_long linenum = 0;
+
+ f = fopen(filename, "r");
+ if (f != NULL) {
+ while (read_keyfile_line(f, filename, line, sizeof(line),
+ &linenum) != -1) {
+ cp = line;
+ switch (*cp) {
+ case '#':
+ case '\n':
+ case '\0':
+ continue;
+ }
+ /* Skip leading whitespace. */
+ for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
+ ;
+ if (*cp) {
+ if (key_read(k, &cp) == 1) {
+ if (commentp)
+ *commentp=xstrdup(filename);
+ fclose(f);
+ return 1;
+ }
+ }
+ }
+ fclose(f);
+ }
+ return 0;
+}
+
+/* load public key from ssh v1 private or any pubkey file */
+Key *
+key_load_public(const char *filename, char **commentp)
+{
+ Key *pub;
+ char file[MAXPATHLEN];
+
+ /* try rsa1 private key */
+ pub = key_load_public_type(KEY_RSA1, filename, commentp);
+ if (pub != NULL)
+ return pub;
+
+ /* try rsa1 public key */
+ pub = key_new(KEY_RSA1);
+ if (key_try_load_public(pub, filename, commentp) == 1)
+ return pub;
+ key_free(pub);
+
+ /* try ssh2 public key */
+ pub = key_new(KEY_UNSPEC);
+ if (key_try_load_public(pub, filename, commentp) == 1)
+ return pub;
+ if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
+ (strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
+ (key_try_load_public(pub, file, commentp) == 1))
+ return pub;
+ key_free(pub);
+ return NULL;
+}