Annotation of src/usr.bin/ssh/ssh-keysign.c, Revision 1.24
1.24 ! stevesk 1: /* $OpenBSD: ssh-keysign.c,v 1.23 2006/04/02 08:34:52 dtucker Exp $ */
1.1 markus 2: /*
3: * Copyright (c) 2002 Markus Friedl. All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: *
14: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24: */
25: #include "includes.h"
1.20 stevesk 26:
1.24 ! stevesk 27: #include <sys/types.h>
1.1 markus 28:
29: #include <openssl/evp.h>
1.6 markus 30: #include <openssl/rand.h>
31: #include <openssl/rsa.h>
1.24 ! stevesk 32:
! 33: #include <paths.h>
! 34: #include <pwd.h>
1.1 markus 35:
36: #include "log.h"
37: #include "key.h"
1.7 markus 38: #include "ssh.h"
1.1 markus 39: #include "ssh2.h"
40: #include "misc.h"
41: #include "xmalloc.h"
42: #include "buffer.h"
43: #include "bufaux.h"
44: #include "authfile.h"
45: #include "msg.h"
1.2 markus 46: #include "canohost.h"
1.1 markus 47: #include "pathnames.h"
1.7 markus 48: #include "readconf.h"
1.17 dtucker 49: #include "uidswap.h"
1.7 markus 50:
1.12 djm 51: /* XXX readconf.c needs these */
52: uid_t original_real_uid;
1.1 markus 53:
54: static int
1.2 markus 55: valid_request(struct passwd *pw, char *host, Key **ret, u_char *data,
56: u_int datalen)
1.1 markus 57: {
58: Buffer b;
1.11 markus 59: Key *key = NULL;
1.2 markus 60: u_char *pkblob;
61: u_int blen, len;
62: char *pkalg, *p;
1.1 markus 63: int pktype, fail;
64:
65: fail = 0;
66:
67: buffer_init(&b);
68: buffer_append(&b, data, datalen);
1.4 deraadt 69:
1.23 dtucker 70: /* session id, currently limited to SHA1 (20 bytes) or SHA256 (32) */
1.3 markus 71: p = buffer_get_string(&b, &len);
1.23 dtucker 72: if (len != 20 && len != 32)
1.3 markus 73: fail++;
74: xfree(p);
75:
1.1 markus 76: if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST)
77: fail++;
78:
79: /* server user */
80: buffer_skip_string(&b);
81:
82: /* service */
83: p = buffer_get_string(&b, NULL);
84: if (strcmp("ssh-connection", p) != 0)
85: fail++;
86: xfree(p);
87:
88: /* method */
89: p = buffer_get_string(&b, NULL);
90: if (strcmp("hostbased", p) != 0)
91: fail++;
92: xfree(p);
93:
94: /* pubkey */
95: pkalg = buffer_get_string(&b, NULL);
96: pkblob = buffer_get_string(&b, &blen);
97:
98: pktype = key_type_from_name(pkalg);
99: if (pktype == KEY_UNSPEC)
100: fail++;
101: else if ((key = key_from_blob(pkblob, blen)) == NULL)
102: fail++;
103: else if (key->type != pktype)
104: fail++;
105: xfree(pkalg);
106: xfree(pkblob);
107:
1.2 markus 108: /* client host name, handle trailing dot */
109: p = buffer_get_string(&b, &len);
110: debug2("valid_request: check expect chost %s got %s", host, p);
111: if (strlen(host) != len - 1)
112: fail++;
113: else if (p[len - 1] != '.')
1.4 deraadt 114: fail++;
1.2 markus 115: else if (strncasecmp(host, p, len - 1) != 0)
1.4 deraadt 116: fail++;
1.2 markus 117: xfree(p);
1.1 markus 118:
119: /* local user */
120: p = buffer_get_string(&b, NULL);
1.2 markus 121:
1.1 markus 122: if (strcmp(pw->pw_name, p) != 0)
123: fail++;
124: xfree(p);
125:
126: /* end of message */
127: if (buffer_len(&b) != 0)
128: fail++;
1.15 markus 129: buffer_free(&b);
1.1 markus 130:
131: debug3("valid_request: fail %d", fail);
132:
133: if (fail && key != NULL)
134: key_free(key);
135: else
136: *ret = key;
137:
138: return (fail ? -1 : 0);
139: }
140:
141: int
142: main(int argc, char **argv)
143: {
144: Buffer b;
1.7 markus 145: Options options;
1.1 markus 146: Key *keys[2], *key;
147: struct passwd *pw;
1.2 markus 148: int key_fd[2], i, found, version = 2, fd;
1.1 markus 149: u_char *signature, *data;
1.2 markus 150: char *host;
1.1 markus 151: u_int slen, dlen;
1.6 markus 152: u_int32_t rnd[256];
1.19 djm 153:
154: /* Ensure that stdin and stdout are connected */
155: if ((fd = open(_PATH_DEVNULL, O_RDWR)) < 2)
156: exit(1);
157: /* Leave /dev/null fd iff it is attached to stderr */
158: if (fd > 2)
159: close(fd);
1.1 markus 160:
161: key_fd[0] = open(_PATH_HOST_RSA_KEY_FILE, O_RDONLY);
162: key_fd[1] = open(_PATH_HOST_DSA_KEY_FILE, O_RDONLY);
163:
1.18 dtucker 164: original_real_uid = getuid(); /* XXX readconf.c needs this */
165: if ((pw = getpwuid(original_real_uid)) == NULL)
1.17 dtucker 166: fatal("getpwuid failed");
167: pw = pwcopy(pw);
168:
169: permanently_set_uid(pw);
1.1 markus 170:
171: #ifdef DEBUG_SSH_KEYSIGN
172: log_init("ssh-keysign", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 0);
1.4 deraadt 173: #endif
1.7 markus 174:
175: /* verify that ssh-keysign is enabled by the admin */
176: initialize_options(&options);
1.16 djm 177: (void)read_config_file(_PATH_HOST_CONFIG_FILE, "", &options, 0);
1.7 markus 178: fill_default_options(&options);
1.8 markus 179: if (options.enable_ssh_keysign != 1)
180: fatal("ssh-keysign not enabled in %s",
1.7 markus 181: _PATH_HOST_CONFIG_FILE);
1.1 markus 182:
183: if (key_fd[0] == -1 && key_fd[1] == -1)
184: fatal("could not open any host key");
185:
186: SSLeay_add_all_algorithms();
1.6 markus 187: for (i = 0; i < 256; i++)
188: rnd[i] = arc4random();
189: RAND_seed(rnd, sizeof(rnd));
1.1 markus 190:
191: found = 0;
192: for (i = 0; i < 2; i++) {
193: keys[i] = NULL;
194: if (key_fd[i] == -1)
195: continue;
196: keys[i] = key_load_private_pem(key_fd[i], KEY_UNSPEC,
197: NULL, NULL);
198: close(key_fd[i]);
199: if (keys[i] != NULL)
200: found = 1;
201: }
202: if (!found)
203: fatal("no hostkey found");
204:
205: buffer_init(&b);
1.9 djm 206: if (ssh_msg_recv(STDIN_FILENO, &b) < 0)
207: fatal("ssh_msg_recv failed");
1.1 markus 208: if (buffer_get_char(&b) != version)
209: fatal("bad version");
1.2 markus 210: fd = buffer_get_int(&b);
211: if ((fd == STDIN_FILENO) || (fd == STDOUT_FILENO))
212: fatal("bad fd");
213: if ((host = get_local_name(fd)) == NULL)
214: fatal("cannot get sockname for fd");
1.4 deraadt 215:
1.1 markus 216: data = buffer_get_string(&b, &dlen);
1.2 markus 217: if (valid_request(pw, host, &key, data, dlen) < 0)
1.1 markus 218: fatal("not a valid request");
1.2 markus 219: xfree(host);
1.1 markus 220:
221: found = 0;
222: for (i = 0; i < 2; i++) {
223: if (keys[i] != NULL &&
224: key_equal(key, keys[i])) {
225: found = 1;
226: break;
227: }
228: }
229: if (!found)
230: fatal("no matching hostkey found");
231:
232: if (key_sign(keys[i], &signature, &slen, data, dlen) != 0)
233: fatal("key_sign failed");
1.5 markus 234: xfree(data);
1.4 deraadt 235:
1.1 markus 236: /* send reply */
237: buffer_clear(&b);
238: buffer_put_string(&b, signature, slen);
1.14 djm 239: if (ssh_msg_send(STDOUT_FILENO, version, &b) == -1)
240: fatal("ssh_msg_send failed");
1.1 markus 241:
242: return (0);
243: }