Annotation of src/usr.bin/ssh/ssh-keysign.c, Revision 1.20
1.1 markus 1: /*
2: * Copyright (c) 2002 Markus Friedl. 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: #include "includes.h"
1.20 ! stevesk 25: RCSID("$OpenBSD: ssh-keysign.c,v 1.19 2005/09/13 23:40:07 djm Exp $");
! 26:
! 27: #include <paths.h>
1.1 markus 28:
29: #include <openssl/evp.h>
1.6 markus 30: #include <openssl/rand.h>
31: #include <openssl/rsa.h>
1.1 markus 32:
33: #include "log.h"
34: #include "key.h"
1.7 markus 35: #include "ssh.h"
1.1 markus 36: #include "ssh2.h"
37: #include "misc.h"
38: #include "xmalloc.h"
39: #include "buffer.h"
40: #include "bufaux.h"
41: #include "authfile.h"
42: #include "msg.h"
1.2 markus 43: #include "canohost.h"
1.1 markus 44: #include "pathnames.h"
1.7 markus 45: #include "readconf.h"
1.17 dtucker 46: #include "uidswap.h"
1.7 markus 47:
1.12 djm 48: /* XXX readconf.c needs these */
49: uid_t original_real_uid;
1.1 markus 50:
51: static int
1.2 markus 52: valid_request(struct passwd *pw, char *host, Key **ret, u_char *data,
53: u_int datalen)
1.1 markus 54: {
55: Buffer b;
1.11 markus 56: Key *key = NULL;
1.2 markus 57: u_char *pkblob;
58: u_int blen, len;
59: char *pkalg, *p;
1.1 markus 60: int pktype, fail;
61:
62: fail = 0;
63:
64: buffer_init(&b);
65: buffer_append(&b, data, datalen);
1.4 deraadt 66:
1.3 markus 67: /* session id, currently limited to SHA1 (20 bytes) */
68: p = buffer_get_string(&b, &len);
69: if (len != 20)
70: fail++;
71: xfree(p);
72:
1.1 markus 73: if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST)
74: fail++;
75:
76: /* server user */
77: buffer_skip_string(&b);
78:
79: /* service */
80: p = buffer_get_string(&b, NULL);
81: if (strcmp("ssh-connection", p) != 0)
82: fail++;
83: xfree(p);
84:
85: /* method */
86: p = buffer_get_string(&b, NULL);
87: if (strcmp("hostbased", p) != 0)
88: fail++;
89: xfree(p);
90:
91: /* pubkey */
92: pkalg = buffer_get_string(&b, NULL);
93: pkblob = buffer_get_string(&b, &blen);
94:
95: pktype = key_type_from_name(pkalg);
96: if (pktype == KEY_UNSPEC)
97: fail++;
98: else if ((key = key_from_blob(pkblob, blen)) == NULL)
99: fail++;
100: else if (key->type != pktype)
101: fail++;
102: xfree(pkalg);
103: xfree(pkblob);
104:
1.2 markus 105: /* client host name, handle trailing dot */
106: p = buffer_get_string(&b, &len);
107: debug2("valid_request: check expect chost %s got %s", host, p);
108: if (strlen(host) != len - 1)
109: fail++;
110: else if (p[len - 1] != '.')
1.4 deraadt 111: fail++;
1.2 markus 112: else if (strncasecmp(host, p, len - 1) != 0)
1.4 deraadt 113: fail++;
1.2 markus 114: xfree(p);
1.1 markus 115:
116: /* local user */
117: p = buffer_get_string(&b, NULL);
1.2 markus 118:
1.1 markus 119: if (strcmp(pw->pw_name, p) != 0)
120: fail++;
121: xfree(p);
122:
123: /* end of message */
124: if (buffer_len(&b) != 0)
125: fail++;
1.15 markus 126: buffer_free(&b);
1.1 markus 127:
128: debug3("valid_request: fail %d", fail);
129:
130: if (fail && key != NULL)
131: key_free(key);
132: else
133: *ret = key;
134:
135: return (fail ? -1 : 0);
136: }
137:
138: int
139: main(int argc, char **argv)
140: {
141: Buffer b;
1.7 markus 142: Options options;
1.1 markus 143: Key *keys[2], *key;
144: struct passwd *pw;
1.2 markus 145: int key_fd[2], i, found, version = 2, fd;
1.1 markus 146: u_char *signature, *data;
1.2 markus 147: char *host;
1.1 markus 148: u_int slen, dlen;
1.6 markus 149: u_int32_t rnd[256];
1.19 djm 150:
151: /* Ensure that stdin and stdout are connected */
152: if ((fd = open(_PATH_DEVNULL, O_RDWR)) < 2)
153: exit(1);
154: /* Leave /dev/null fd iff it is attached to stderr */
155: if (fd > 2)
156: close(fd);
1.1 markus 157:
158: key_fd[0] = open(_PATH_HOST_RSA_KEY_FILE, O_RDONLY);
159: key_fd[1] = open(_PATH_HOST_DSA_KEY_FILE, O_RDONLY);
160:
1.18 dtucker 161: original_real_uid = getuid(); /* XXX readconf.c needs this */
162: if ((pw = getpwuid(original_real_uid)) == NULL)
1.17 dtucker 163: fatal("getpwuid failed");
164: pw = pwcopy(pw);
165:
166: permanently_set_uid(pw);
1.1 markus 167:
168: #ifdef DEBUG_SSH_KEYSIGN
169: log_init("ssh-keysign", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 0);
1.4 deraadt 170: #endif
1.7 markus 171:
172: /* verify that ssh-keysign is enabled by the admin */
173: initialize_options(&options);
1.16 djm 174: (void)read_config_file(_PATH_HOST_CONFIG_FILE, "", &options, 0);
1.7 markus 175: fill_default_options(&options);
1.8 markus 176: if (options.enable_ssh_keysign != 1)
177: fatal("ssh-keysign not enabled in %s",
1.7 markus 178: _PATH_HOST_CONFIG_FILE);
1.1 markus 179:
180: if (key_fd[0] == -1 && key_fd[1] == -1)
181: fatal("could not open any host key");
182:
183: SSLeay_add_all_algorithms();
1.6 markus 184: for (i = 0; i < 256; i++)
185: rnd[i] = arc4random();
186: RAND_seed(rnd, sizeof(rnd));
1.1 markus 187:
188: found = 0;
189: for (i = 0; i < 2; i++) {
190: keys[i] = NULL;
191: if (key_fd[i] == -1)
192: continue;
193: keys[i] = key_load_private_pem(key_fd[i], KEY_UNSPEC,
194: NULL, NULL);
195: close(key_fd[i]);
196: if (keys[i] != NULL)
197: found = 1;
198: }
199: if (!found)
200: fatal("no hostkey found");
201:
202: buffer_init(&b);
1.9 djm 203: if (ssh_msg_recv(STDIN_FILENO, &b) < 0)
204: fatal("ssh_msg_recv failed");
1.1 markus 205: if (buffer_get_char(&b) != version)
206: fatal("bad version");
1.2 markus 207: fd = buffer_get_int(&b);
208: if ((fd == STDIN_FILENO) || (fd == STDOUT_FILENO))
209: fatal("bad fd");
210: if ((host = get_local_name(fd)) == NULL)
211: fatal("cannot get sockname for fd");
1.4 deraadt 212:
1.1 markus 213: data = buffer_get_string(&b, &dlen);
1.2 markus 214: if (valid_request(pw, host, &key, data, dlen) < 0)
1.1 markus 215: fatal("not a valid request");
1.2 markus 216: xfree(host);
1.1 markus 217:
218: found = 0;
219: for (i = 0; i < 2; i++) {
220: if (keys[i] != NULL &&
221: key_equal(key, keys[i])) {
222: found = 1;
223: break;
224: }
225: }
226: if (!found)
227: fatal("no matching hostkey found");
228:
229: if (key_sign(keys[i], &signature, &slen, data, dlen) != 0)
230: fatal("key_sign failed");
1.5 markus 231: xfree(data);
1.4 deraadt 232:
1.1 markus 233: /* send reply */
234: buffer_clear(&b);
235: buffer_put_string(&b, signature, slen);
1.14 djm 236: if (ssh_msg_send(STDOUT_FILENO, version, &b) == -1)
237: fatal("ssh_msg_send failed");
1.1 markus 238:
239: return (0);
240: }