1190203Srpaulo/*	$NetBSD: monitor_wrap.c,v 1.34 2023/12/20 17:15:20 christos Exp $	*/
2190203Srpaulo/* $OpenBSD: monitor_wrap.c,v 1.129 2023/12/18 14:45:49 djm Exp $ */
3190203Srpaulo
4190203Srpaulo/*
5190203Srpaulo * Copyright 2002 Niels Provos <provos@citi.umich.edu>
6190203Srpaulo * Copyright 2002 Markus Friedl <markus@openbsd.org>
7190203Srpaulo * All rights reserved.
8190203Srpaulo *
9190203Srpaulo * Redistribution and use in source and binary forms, with or without
10190203Srpaulo * modification, are permitted provided that the following conditions
11190203Srpaulo * are met:
12190203Srpaulo * 1. Redistributions of source code must retain the above copyright
13190203Srpaulo *    notice, this list of conditions and the following disclaimer.
14190203Srpaulo * 2. Redistributions in binary form must reproduce the above copyright
15235530Sdelphij *    notice, this list of conditions and the following disclaimer in the
16190203Srpaulo *    documentation and/or other materials provided with the distribution.
17190203Srpaulo *
18190203Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19235530Sdelphij * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20190203Srpaulo * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21190203Srpaulo * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22190203Srpaulo * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23190203Srpaulo * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24214478Srpaulo * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25190203Srpaulo * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26190203Srpaulo * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27190203Srpaulo * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28190203Srpaulo */
29190203Srpaulo
30190203Srpaulo#include "includes.h"
31190203Srpaulo__RCSID("$NetBSD: monitor_wrap.c,v 1.34 2023/12/20 17:15:20 christos Exp $");
32190203Srpaulo#include <sys/types.h>
33190203Srpaulo#include <sys/uio.h>
34190203Srpaulo#include <sys/queue.h>
35190203Srpaulo
36190203Srpaulo#include <errno.h>
37190203Srpaulo#include <pwd.h>
38190203Srpaulo#include <signal.h>
39190203Srpaulo#include <stdio.h>
40190203Srpaulo#include <string.h>
41190203Srpaulo#include <stdarg.h>
42190203Srpaulo#include <unistd.h>
43190203Srpaulo
44190203Srpaulo#ifdef WITH_OPENSSL
45190203Srpaulo#include <openssl/bn.h>
46190203Srpaulo#include <openssl/dh.h>
47190203Srpaulo#endif
48190203Srpaulo
49190203Srpaulo#include "xmalloc.h"
50190203Srpaulo#include "ssh.h"
51190203Srpaulo#ifdef WITH_OPENSSL
52190203Srpaulo#include "dh.h"
53190203Srpaulo#endif
54190203Srpaulo#include "sshbuf.h"
55190203Srpaulo#include "sshkey.h"
56190203Srpaulo#include "cipher.h"
57190203Srpaulo#include "kex.h"
58190203Srpaulo#include "hostfile.h"
59190203Srpaulo#include "auth.h"
60190203Srpaulo#include "auth-options.h"
61190203Srpaulo#include "packet.h"
62190203Srpaulo#include "mac.h"
63190203Srpaulo#include "log.h"
64190203Srpaulo#include "monitor.h"
65190203Srpaulo#ifdef GSSAPI
66190203Srpaulo#include "ssh-gss.h"
67190203Srpaulo#endif
68190203Srpaulo#include "monitor_wrap.h"
69190203Srpaulo#include "atomicio.h"
70190203Srpaulo#include "monitor_fdpass.h"
71190203Srpaulo#ifdef USE_PAM
72190203Srpaulo#include "misc.h"
73190203Srpaulo#include "servconf.h"
74190203Srpaulo#include <security/pam_appl.h>
75190203Srpaulo#endif
76190203Srpaulo#include "misc.h"
77190203Srpaulo
78190203Srpaulo#include "channels.h"
79190203Srpaulo#include "session.h"
80190203Srpaulo#include "servconf.h"
81190203Srpaulo
82190203Srpaulo#include "ssherr.h"
83190203Srpaulo
84190203Srpaulo/* Imports */
85190203Srpauloextern struct monitor *pmonitor;
86190203Srpauloextern struct sshbuf *loginmsg;
87190203Srpauloextern ServerOptions options;
88190203Srpaulo
89190203Srpaulovoid
90190203Srpaulomm_log_handler(LogLevel level, int forced, const char *msg, void *ctx)
91190203Srpaulo{
92190203Srpaulo	struct sshbuf *log_msg;
93190203Srpaulo	struct monitor *mon = (struct monitor *)ctx;
94190203Srpaulo	int r;
95190203Srpaulo	size_t len;
96190203Srpaulo
97190203Srpaulo	if (mon->m_log_sendfd == -1)
98190203Srpaulo		fatal_f("no log channel");
99190203Srpaulo
100190203Srpaulo	if ((log_msg = sshbuf_new()) == NULL)
101190203Srpaulo		fatal_f("sshbuf_new failed");
102190203Srpaulo
103190203Srpaulo	if ((r = sshbuf_put_u32(log_msg, 0)) != 0 || /* length; filled below */
104190203Srpaulo	    (r = sshbuf_put_u32(log_msg, level)) != 0 ||
105190203Srpaulo	    (r = sshbuf_put_u32(log_msg, forced)) != 0 ||
106190203Srpaulo	    (r = sshbuf_put_cstring(log_msg, msg)) != 0)
107190203Srpaulo		fatal_fr(r, "assemble");
108190203Srpaulo	if ((len = sshbuf_len(log_msg)) < 4 || len > 0xffffffff)
109190203Srpaulo		fatal_f("bad length %zu", len);
110190203Srpaulo	POKE_U32(sshbuf_mutable_ptr(log_msg), len - 4);
111190203Srpaulo	if (atomicio(vwrite, mon->m_log_sendfd,
112190203Srpaulo	    sshbuf_mutable_ptr(log_msg), len) != len)
113190203Srpaulo		fatal_f("write: %s", strerror(errno));
114190203Srpaulo	sshbuf_free(log_msg);
115190203Srpaulo}
116190203Srpaulo
117190203Srpauloint
118190203Srpaulomm_is_monitor(void)
119190203Srpaulo{
120190203Srpaulo	/*
121190203Srpaulo	 * m_pid is only set in the privileged part, and
122190203Srpaulo	 * points to the unprivileged child.
123190203Srpaulo	 */
124190203Srpaulo	return (pmonitor && pmonitor->m_pid > 0);
125190203Srpaulo}
126190203Srpaulo
127190203Srpaulovoid
128190203Srpaulomm_request_send(int sock, enum monitor_reqtype type, struct sshbuf *m)
129190203Srpaulo{
130190203Srpaulo	size_t mlen = sshbuf_len(m);
131190203Srpaulo	u_char buf[5];
132190203Srpaulo
133190203Srpaulo	debug3_f("entering, type %d", type);
134190203Srpaulo
135190203Srpaulo	if (mlen >= 0xffffffff)
136190203Srpaulo		fatal_f("bad length %zu", mlen);
137190203Srpaulo	POKE_U32(buf, mlen + 1);
138190203Srpaulo	buf[4] = (u_char) type;		/* 1st byte of payload is mesg-type */
139190203Srpaulo	if (atomicio(vwrite, sock, buf, sizeof(buf)) != sizeof(buf))
140190203Srpaulo		fatal_f("write: %s", strerror(errno));
141190203Srpaulo	if (atomicio(vwrite, sock, sshbuf_mutable_ptr(m), mlen) != mlen)
142190203Srpaulo		fatal_f("write: %s", strerror(errno));
143190203Srpaulo}
144190203Srpaulo
145190203Srpaulovoid
146190203Srpaulomm_request_receive(int sock, struct sshbuf *m)
147190203Srpaulo{
148190203Srpaulo	u_char buf[4], *p = NULL;
149190203Srpaulo	u_int msg_len;
150190203Srpaulo	int r;
151190203Srpaulo
152190203Srpaulo	debug3_f("entering");
153190203Srpaulo
154190203Srpaulo	if (atomicio(read, sock, buf, sizeof(buf)) != sizeof(buf)) {
155190203Srpaulo		if (errno == EPIPE)
156190203Srpaulo			cleanup_exit(254);
157190203Srpaulo		fatal_f("read: %s", strerror(errno));
158190203Srpaulo	}
159190203Srpaulo	msg_len = PEEK_U32(buf);
160190203Srpaulo	if (msg_len > 256 * 1024)
161190203Srpaulo		fatal_f("read: bad msg_len %d", msg_len);
162190203Srpaulo	sshbuf_reset(m);
163190203Srpaulo	if ((r = sshbuf_reserve(m, msg_len, &p)) != 0)
164190203Srpaulo		fatal_fr(r, "reserve");
165190203Srpaulo	if (atomicio(read, sock, p, msg_len) != msg_len)
166190203Srpaulo		fatal_f("read: %s", strerror(errno));
167190203Srpaulo}
168190203Srpaulo
169190203Srpaulovoid
170190203Srpaulomm_request_receive_expect(int sock, enum monitor_reqtype type, struct sshbuf *m)
171190203Srpaulo{
172190203Srpaulo	u_char rtype;
173190203Srpaulo	int r;
174190203Srpaulo
175190203Srpaulo	debug3_f("entering, type %d", type);
176190203Srpaulo
177190203Srpaulo	mm_request_receive(sock, m);
178190203Srpaulo	if ((r = sshbuf_get_u8(m, &rtype)) != 0)
179190203Srpaulo		fatal_fr(r, "parse");
180190203Srpaulo	if (rtype != type)
181190203Srpaulo		fatal_f("read: rtype %d != type %d", rtype, type);
182190203Srpaulo}
183190203Srpaulo
184190203Srpaulo#ifdef WITH_OPENSSL
185190203SrpauloDH *
186190203Srpaulomm_choose_dh(int min, int nbits, int max)
187190203Srpaulo{
188190203Srpaulo	BIGNUM *p, *g;
189190203Srpaulo	int r;
190190203Srpaulo	u_char success = 0;
191190203Srpaulo	struct sshbuf *m;
192190203Srpaulo
193190203Srpaulo	if ((m = sshbuf_new()) == NULL)
194190203Srpaulo		fatal_f("sshbuf_new failed");
195190203Srpaulo	if ((r = sshbuf_put_u32(m, min)) != 0 ||
196190203Srpaulo	    (r = sshbuf_put_u32(m, nbits)) != 0 ||
197190203Srpaulo	    (r = sshbuf_put_u32(m, max)) != 0)
198190203Srpaulo		fatal_fr(r, "assemble");
199190203Srpaulo
200190203Srpaulo	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_MODULI, m);
201190203Srpaulo
202190203Srpaulo	debug3_f("waiting for MONITOR_ANS_MODULI");
203190203Srpaulo	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_MODULI, m);
204190203Srpaulo
205190203Srpaulo	if ((r = sshbuf_get_u8(m, &success)) != 0)
206190203Srpaulo		fatal_fr(r, "parse success");
207190203Srpaulo	if (success == 0)
208190203Srpaulo		fatal_f("MONITOR_ANS_MODULI failed");
209190203Srpaulo
210190203Srpaulo	if ((r = sshbuf_get_bignum2(m, &p)) != 0 ||
211190203Srpaulo	    (r = sshbuf_get_bignum2(m, &g)) != 0)
212190203Srpaulo		fatal_fr(r, "parse group");
213190203Srpaulo
214190203Srpaulo	debug3_f("remaining %zu", sshbuf_len(m));
215190203Srpaulo	sshbuf_free(m);
216190203Srpaulo
217190203Srpaulo	return (dh_new_group(g, p));
218190203Srpaulo}
219190203Srpaulo#endif
220190203Srpaulo
221190203Srpauloint
222190203Srpaulomm_sshkey_sign(struct ssh *ssh, struct sshkey *key, u_char **sigp, size_t *lenp,
223190203Srpaulo    const u_char *data, size_t datalen, const char *hostkey_alg,
224190203Srpaulo    const char *sk_provider, const char *sk_pin, u_int compat)
225190203Srpaulo{
226190203Srpaulo	struct kex *kex = *pmonitor->m_pkex;
227190203Srpaulo	struct sshbuf *m;
228190203Srpaulo	u_int ndx = kex->host_key_index(key, 0, ssh);
229190203Srpaulo	int r;
230190203Srpaulo
231190203Srpaulo	debug3_f("entering");
232190203Srpaulo	if ((m = sshbuf_new()) == NULL)
233190203Srpaulo		fatal_f("sshbuf_new failed");
234190203Srpaulo	if ((r = sshbuf_put_u32(m, ndx)) != 0 ||
235190203Srpaulo	    (r = sshbuf_put_string(m, data, datalen)) != 0 ||
236190203Srpaulo	    (r = sshbuf_put_cstring(m, hostkey_alg)) != 0 ||
237190203Srpaulo	    (r = sshbuf_put_u32(m, compat)) != 0)
238190203Srpaulo		fatal_fr(r, "assemble");
239190203Srpaulo
240190203Srpaulo	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_SIGN, m);
241190203Srpaulo
242190203Srpaulo	debug3_f("waiting for MONITOR_ANS_SIGN");
243190203Srpaulo	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_SIGN, m);
244190203Srpaulo	if ((r = sshbuf_get_string(m, sigp, lenp)) != 0)
245190203Srpaulo		fatal_fr(r, "parse");
246190203Srpaulo	sshbuf_free(m);
247190203Srpaulo
248190203Srpaulo	return (0);
249190203Srpaulo}
250190203Srpaulo
251190203Srpaulo#define GETPW(b, id) \
252190203Srpaulo	do { \
253190203Srpaulo		if ((r = sshbuf_get_string_direct(b, &p, &len)) != 0) \
254190203Srpaulo			fatal_fr(r, "parse pw %s", #id); \
255190203Srpaulo		if (len != sizeof(pw->id)) \
256190203Srpaulo			fatal_fr(r, "bad length for %s", #id); \
257190203Srpaulo		memcpy(&pw->id, p, len); \
258190203Srpaulo	} while (0)
259190203Srpaulo
260190203Srpaulostruct passwd *
261190203Srpaulomm_getpwnamallow(struct ssh *ssh, const char *username)
262190203Srpaulo{
263190203Srpaulo	struct sshbuf *m;
264190203Srpaulo	struct passwd *pw;
265190203Srpaulo	size_t len;
266190203Srpaulo	u_int i;
267190203Srpaulo	ServerOptions *newopts;
268190203Srpaulo	int r;
269190203Srpaulo	u_char ok;
270190203Srpaulo	const u_char *p;
271190203Srpaulo
272190203Srpaulo	debug3_f("entering");
273190203Srpaulo
274190203Srpaulo	if ((m = sshbuf_new()) == NULL)
275190203Srpaulo		fatal_f("sshbuf_new failed");
276190203Srpaulo	if ((r = sshbuf_put_cstring(m, username)) != 0)
277190203Srpaulo		fatal_fr(r, "assemble");
278190203Srpaulo
279190203Srpaulo	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PWNAM, m);
280190203Srpaulo
281190203Srpaulo	debug3_f("waiting for MONITOR_ANS_PWNAM");
282190203Srpaulo	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PWNAM, m);
283190203Srpaulo
284190203Srpaulo	if ((r = sshbuf_get_u8(m, &ok)) != 0)
285190203Srpaulo		fatal_fr(r, "parse success");
286190203Srpaulo	if (ok == 0) {
287190203Srpaulo		pw = NULL;
288190203Srpaulo		goto out;
289190203Srpaulo	}
290190203Srpaulo
291190203Srpaulo	pw = xcalloc(sizeof(*pw), 1);
292190203Srpaulo	GETPW(m, pw_uid);
293190203Srpaulo	GETPW(m, pw_gid);
294190203Srpaulo	GETPW(m, pw_change);
295190203Srpaulo	GETPW(m, pw_expire);
296190203Srpaulo	if ((r = sshbuf_get_cstring(m, &pw->pw_name, NULL)) != 0 ||
297190203Srpaulo	    (r = sshbuf_get_cstring(m, &pw->pw_passwd, NULL)) != 0 ||
298190203Srpaulo	    (r = sshbuf_get_cstring(m, &pw->pw_gecos, NULL)) != 0 ||
299190203Srpaulo	    (r = sshbuf_get_cstring(m, &pw->pw_class, NULL)) != 0 ||
300190203Srpaulo	    (r = sshbuf_get_cstring(m, &pw->pw_dir, NULL)) != 0 ||
301190203Srpaulo	    (r = sshbuf_get_cstring(m, &pw->pw_shell, NULL)) != 0)
302190203Srpaulo		fatal_fr(r, "parse pw");
303190203Srpaulo
304190203Srpauloout:
305190203Srpaulo	/* copy options block as a Match directive may have changed some */
306190203Srpaulo	if ((r = sshbuf_get_string_direct(m, &p, &len)) != 0)
307190203Srpaulo		fatal_fr(r, "parse opts");
308190203Srpaulo	if (len != sizeof(*newopts))
309190203Srpaulo		fatal_f("option block size mismatch");
310190203Srpaulo	newopts = xcalloc(sizeof(*newopts), 1);
311190203Srpaulo	memcpy(newopts, p, sizeof(*newopts));
312190203Srpaulo
313190203Srpaulo#define M_CP_STROPT(x) do { \
314190203Srpaulo		if (newopts->x != NULL && \
315190203Srpaulo		    (r = sshbuf_get_cstring(m, &newopts->x, NULL)) != 0) \
316190203Srpaulo			fatal_fr(r, "parse %s", #x); \
317190203Srpaulo	} while (0)
318190203Srpaulo#define M_CP_STRARRAYOPT(x, nx) do { \
319190203Srpaulo		newopts->x = newopts->nx == 0 ? \
320190203Srpaulo		    NULL : xcalloc(newopts->nx, sizeof(*newopts->x)); \
321190203Srpaulo		for (i = 0; i < newopts->nx; i++) { \
322190203Srpaulo			if ((r = sshbuf_get_cstring(m, \
323190203Srpaulo			    &newopts->x[i], NULL)) != 0) \
324190203Srpaulo				fatal_fr(r, "parse %s", #x); \
325190203Srpaulo		} \
326190203Srpaulo	} while (0)
327190203Srpaulo	/* See comment in servconf.h */
328190203Srpaulo	COPY_MATCH_STRING_OPTS();
329190203Srpaulo#undef M_CP_STROPT
330190203Srpaulo#undef M_CP_STRARRAYOPT
331190203Srpaulo
332190203Srpaulo	copy_set_server_options(&options, newopts, 1);
333190203Srpaulo	log_change_level(options.log_level);
334190203Srpaulo	log_verbose_reset();
335190203Srpaulo	for (i = 0; i < options.num_log_verbose; i++)
336190203Srpaulo		log_verbose_add(options.log_verbose[i]);
337190203Srpaulo	process_permitopen(ssh, &options);
338190203Srpaulo	process_channel_timeouts(ssh, &options);
339190203Srpaulo	kex_set_server_sig_algs(ssh, options.pubkey_accepted_algos);
340190203Srpaulo	free(newopts);
341190203Srpaulo	sshbuf_free(m);
342190203Srpaulo
343190203Srpaulo	return (pw);
344190203Srpaulo}
345190203Srpaulo
346190203Srpaulochar *
347190203Srpaulomm_auth2_read_banner(void)
348190203Srpaulo{
349190203Srpaulo	struct sshbuf *m;
350190203Srpaulo	char *banner;
351190203Srpaulo	int r;
352190203Srpaulo
353190203Srpaulo	debug3_f("entering");
354190203Srpaulo
355190203Srpaulo	if ((m = sshbuf_new()) == NULL)
356190203Srpaulo		fatal_f("sshbuf_new failed");
357190203Srpaulo	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTH2_READ_BANNER, m);
358190203Srpaulo	sshbuf_reset(m);
359190203Srpaulo
360190203Srpaulo	mm_request_receive_expect(pmonitor->m_recvfd,
361190203Srpaulo	    MONITOR_ANS_AUTH2_READ_BANNER, m);
362190203Srpaulo	if ((r = sshbuf_get_cstring(m, &banner, NULL)) != 0)
363190203Srpaulo		fatal_fr(r, "parse");
364190203Srpaulo	sshbuf_free(m);
365190203Srpaulo
366190203Srpaulo	/* treat empty banner as missing banner */
367190203Srpaulo	if (strlen(banner) == 0) {
368190203Srpaulo		free(banner);
369190203Srpaulo		banner = NULL;
370190203Srpaulo	}
371190203Srpaulo	return (banner);
372190203Srpaulo}
373190203Srpaulo
374190203Srpaulo/* Inform the privileged process about service and style */
375190203Srpaulo
376190203Srpaulovoid
377190203Srpaulomm_inform_authserv(char *service, char *style)
378190203Srpaulo{
379190203Srpaulo	struct sshbuf *m;
380190203Srpaulo	int r;
381190203Srpaulo
382190203Srpaulo	debug3_f("entering");
383190203Srpaulo
384190203Srpaulo	if ((m = sshbuf_new()) == NULL)
385190203Srpaulo		fatal_f("sshbuf_new failed");
386190203Srpaulo	if ((r = sshbuf_put_cstring(m, service)) != 0 ||
387190203Srpaulo	    (r = sshbuf_put_cstring(m, style ? style : "")) != 0)
388241235Sdelphij		fatal_fr(r, "assemble");
389190203Srpaulo
390241235Sdelphij	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHSERV, m);
391190203Srpaulo
392190203Srpaulo	sshbuf_free(m);
393190203Srpaulo}
394190203Srpaulo
395190203Srpaulo/* Do the password authentication */
396190203Srpauloint
397190203Srpaulomm_auth_password(struct ssh *ssh, const char *password)
398190203Srpaulo{
399190203Srpaulo	struct sshbuf *m;
400190203Srpaulo	int r;
401190203Srpaulo	u_int authenticated = 0;
402190203Srpaulo
403190203Srpaulo	debug3_f("entering");
404190203Srpaulo
405190203Srpaulo	if ((m = sshbuf_new()) == NULL)
406190203Srpaulo		fatal_f("sshbuf_new failed");
407190203Srpaulo	if ((r = sshbuf_put_cstring(m, password)) != 0)
408190203Srpaulo		fatal_fr(r, "assemble");
409190203Srpaulo	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHPASSWORD, m);
410190203Srpaulo
411190203Srpaulo	debug3_f("waiting for MONITOR_ANS_AUTHPASSWORD");
412190203Srpaulo	mm_request_receive_expect(pmonitor->m_recvfd,
413190203Srpaulo	    MONITOR_ANS_AUTHPASSWORD, m);
414190203Srpaulo
415190203Srpaulo	if ((r = sshbuf_get_u32(m, &authenticated)) != 0)
416190203Srpaulo		fatal_fr(r, "parse");
417190203Srpaulo
418190203Srpaulo	sshbuf_free(m);
419190203Srpaulo
420190203Srpaulo	debug3_f("user %sauthenticated", authenticated ? "" : "not ");
421190203Srpaulo	return (authenticated);
422190203Srpaulo}
423190203Srpaulo
424190203Srpauloint
425190203Srpaulomm_user_key_allowed(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
426190203Srpaulo    int pubkey_auth_attempt, struct sshauthopt **authoptp)
427190203Srpaulo{
428190203Srpaulo	return (mm_key_allowed(MM_USERKEY, NULL, NULL, key,
429190203Srpaulo	    pubkey_auth_attempt, authoptp));
430190203Srpaulo}
431190203Srpaulo
432190203Srpauloint
433190203Srpaulomm_hostbased_key_allowed(struct ssh *ssh, struct passwd *pw,
434190203Srpaulo    const char *user, const char *host, struct sshkey *key)
435190203Srpaulo{
436190203Srpaulo	return (mm_key_allowed(MM_HOSTKEY, user, host, key, 0, NULL));
437190203Srpaulo}
438190203Srpaulo
439190203Srpauloint
440190203Srpaulomm_key_allowed(enum mm_keytype type, const char *user, const char *host,
441190203Srpaulo    struct sshkey *key, int pubkey_auth_attempt, struct sshauthopt **authoptp)
442190203Srpaulo{
443190203Srpaulo	struct sshbuf *m;
444190203Srpaulo	int r;
445190203Srpaulo	u_int allowed = 0;
446190203Srpaulo	struct sshauthopt *opts = NULL;
447190203Srpaulo
448190203Srpaulo	debug3_f("entering");
449190203Srpaulo
450190203Srpaulo	if (authoptp != NULL)
451190203Srpaulo		*authoptp = NULL;
452190203Srpaulo
453190203Srpaulo	if ((m = sshbuf_new()) == NULL)
454190203Srpaulo		fatal_f("sshbuf_new failed");
455190203Srpaulo	if ((r = sshbuf_put_u32(m, type)) != 0 ||
456190203Srpaulo	    (r = sshbuf_put_cstring(m, user ? user : "")) != 0 ||
457190203Srpaulo	    (r = sshbuf_put_cstring(m, host ? host : "")) != 0 ||
458190203Srpaulo	    (r = sshkey_puts(key, m)) != 0 ||
459190203Srpaulo	    (r = sshbuf_put_u32(m, pubkey_auth_attempt)) != 0)
460190203Srpaulo		fatal_fr(r, "assemble");
461190203Srpaulo
462190203Srpaulo	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KEYALLOWED, m);
463190203Srpaulo
464190203Srpaulo	debug3_f("waiting for MONITOR_ANS_KEYALLOWED");
465190203Srpaulo	mm_request_receive_expect(pmonitor->m_recvfd,
466190203Srpaulo	    MONITOR_ANS_KEYALLOWED, m);
467190203Srpaulo
468190203Srpaulo	if ((r = sshbuf_get_u32(m, &allowed)) != 0)
469190203Srpaulo		fatal_fr(r, "parse");
470190203Srpaulo	if (allowed && type == MM_USERKEY &&
471190203Srpaulo	    (r = sshauthopt_deserialise(m, &opts)) != 0)
472190203Srpaulo		fatal_fr(r, "sshauthopt_deserialise");
473190203Srpaulo	sshbuf_free(m);
474190203Srpaulo
475190203Srpaulo	if (authoptp != NULL) {
476190203Srpaulo		*authoptp = opts;
477190203Srpaulo		opts = NULL;
478190203Srpaulo	}
479190203Srpaulo	sshauthopt_free(opts);
480190203Srpaulo
481190203Srpaulo	return allowed;
482190203Srpaulo}
483190203Srpaulo
484190203Srpaulo/*
485190203Srpaulo * This key verify needs to send the key type along, because the
486190203Srpaulo * privileged parent makes the decision if the key is allowed
487190203Srpaulo * for authentication.
488190203Srpaulo */
489190203Srpaulo
490190203Srpauloint
491190203Srpaulomm_sshkey_verify(const struct sshkey *key, const u_char *sig, size_t siglen,
492190203Srpaulo    const u_char *data, size_t datalen, const char *sigalg, u_int compat,
493190203Srpaulo    struct sshkey_sig_details **sig_detailsp)
494190203Srpaulo{
495190203Srpaulo	struct sshbuf *m;
496190203Srpaulo	u_int encoded_ret = 0;
497190203Srpaulo	int r;
498190203Srpaulo	u_char sig_details_present, flags;
499190203Srpaulo	u_int counter;
500190203Srpaulo
501190203Srpaulo	debug3_f("entering");
502190203Srpaulo
503190203Srpaulo	if (sig_detailsp != NULL)
504190203Srpaulo		*sig_detailsp = NULL;
505190203Srpaulo	if ((m = sshbuf_new()) == NULL)
506190203Srpaulo		fatal_f("sshbuf_new failed");
507190203Srpaulo	if ((r = sshkey_puts(key, m)) != 0 ||
508190203Srpaulo	    (r = sshbuf_put_string(m, sig, siglen)) != 0 ||
509190203Srpaulo	    (r = sshbuf_put_string(m, data, datalen)) != 0 ||
510190203Srpaulo	    (r = sshbuf_put_cstring(m, sigalg == NULL ? "" : sigalg)) != 0)
511190203Srpaulo		fatal_fr(r, "assemble");
512190203Srpaulo
513190203Srpaulo	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KEYVERIFY, m);
514190203Srpaulo
515190203Srpaulo	debug3_f("waiting for MONITOR_ANS_KEYVERIFY");
516190203Srpaulo	mm_request_receive_expect(pmonitor->m_recvfd,
517190203Srpaulo	    MONITOR_ANS_KEYVERIFY, m);
518190203Srpaulo
519190203Srpaulo	if ((r = sshbuf_get_u32(m, &encoded_ret)) != 0 ||
520190203Srpaulo	    (r = sshbuf_get_u8(m, &sig_details_present)) != 0)
521190203Srpaulo		fatal_fr(r, "parse");
522190203Srpaulo	if (sig_details_present && encoded_ret == 0) {
523190203Srpaulo		if ((r = sshbuf_get_u32(m, &counter)) != 0 ||
524190203Srpaulo		    (r = sshbuf_get_u8(m, &flags)) != 0)
525190203Srpaulo			fatal_fr(r, "parse sig_details");
526190203Srpaulo		if (sig_detailsp != NULL) {
527190203Srpaulo			*sig_detailsp = xcalloc(1, sizeof(**sig_detailsp));
528190203Srpaulo			(*sig_detailsp)->sk_counter = counter;
529190203Srpaulo			(*sig_detailsp)->sk_flags = flags;
530190203Srpaulo		}
531190203Srpaulo	}
532190203Srpaulo
533190203Srpaulo	sshbuf_free(m);
534190203Srpaulo
535190203Srpaulo	if (encoded_ret != 0)
536190203Srpaulo		return SSH_ERR_SIGNATURE_INVALID;
537190203Srpaulo	return 0;
538190203Srpaulo}
539190203Srpaulo
540190203Srpaulovoid
541190203Srpaulomm_send_keystate(struct ssh *ssh, struct monitor *monitor)
542190203Srpaulo{
543190203Srpaulo	struct sshbuf *m;
544190203Srpaulo	int r;
545190203Srpaulo
546235530Sdelphij	if ((m = sshbuf_new()) == NULL)
547235530Sdelphij		fatal_f("sshbuf_new failed");
548235530Sdelphij	if ((r = ssh_packet_get_state(ssh, m)) != 0)
549235530Sdelphij		fatal_fr(r, "ssh_packet_get_state");
550235530Sdelphij	mm_request_send(monitor->m_recvfd, MONITOR_REQ_KEYEXPORT, m);
551235530Sdelphij	debug3_f("Finished sending state");
552235530Sdelphij	sshbuf_free(m);
553235530Sdelphij}
554235530Sdelphij
555235530Sdelphijint
556235530Sdelphijmm_pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen)
557235530Sdelphij{
558235530Sdelphij	struct sshbuf *m;
559235530Sdelphij	char *p, *msg;
560235530Sdelphij	u_int success = 0;
561235530Sdelphij	int tmp1 = -1, tmp2 = -1, r;
562235530Sdelphij
563190203Srpaulo	/* Kludge: ensure there are fds free to receive the pty/tty */
564190203Srpaulo	if ((tmp1 = dup(pmonitor->m_recvfd)) == -1 ||
565190203Srpaulo	    (tmp2 = dup(pmonitor->m_recvfd)) == -1) {
566190203Srpaulo		error_f("cannot allocate fds for pty");
567190203Srpaulo		if (tmp1 >= 0)
568190203Srpaulo			close(tmp1);
569190203Srpaulo		return 0;
570190203Srpaulo	}
571190203Srpaulo	close(tmp1);
572190203Srpaulo	close(tmp2);
573190203Srpaulo
574190203Srpaulo	if ((m = sshbuf_new()) == NULL)
575190203Srpaulo		fatal_f("sshbuf_new failed");
576190203Srpaulo	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PTY, m);
577235530Sdelphij
578190203Srpaulo	debug3_f("waiting for MONITOR_ANS_PTY");
579190203Srpaulo	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PTY, m);
580235530Sdelphij
581190203Srpaulo	if ((r = sshbuf_get_u32(m, &success)) != 0)
582190203Srpaulo		fatal_fr(r, "parse success");
583235530Sdelphij	if (success == 0) {
584190203Srpaulo		debug3_f("pty alloc failed");
585235530Sdelphij		sshbuf_free(m);
586235530Sdelphij		return (0);
587235530Sdelphij	}
588190203Srpaulo	if ((r = sshbuf_get_cstring(m, &p, NULL)) != 0 ||
589190203Srpaulo	    (r = sshbuf_get_cstring(m, &msg, NULL)) != 0)
590190203Srpaulo		fatal_fr(r, "parse");
591190203Srpaulo	sshbuf_free(m);
592190203Srpaulo
593190203Srpaulo	strlcpy(namebuf, p, namebuflen); /* Possible truncation */
594190203Srpaulo	free(p);
595190203Srpaulo
596235530Sdelphij	if ((r = sshbuf_put(loginmsg, msg, strlen(msg))) != 0)
597235530Sdelphij		fatal_fr(r, "put loginmsg");
598235530Sdelphij	free(msg);
599190203Srpaulo
600190203Srpaulo	if ((*ptyfd = mm_receive_fd(pmonitor->m_recvfd)) == -1 ||
601190203Srpaulo	    (*ttyfd = mm_receive_fd(pmonitor->m_recvfd)) == -1)
602190203Srpaulo		fatal_f("receive fds failed");
603235530Sdelphij
604235530Sdelphij	/* Success */
605235530Sdelphij	return (1);
606190203Srpaulo}
607190203Srpaulo
608190203Srpaulovoid
609190203Srpaulomm_session_pty_cleanup2(Session *s)
610190203Srpaulo{
611190203Srpaulo	struct sshbuf *m;
612235530Sdelphij	int r;
613235530Sdelphij
614235530Sdelphij	if (s->ttyfd == -1)
615190203Srpaulo		return;
616190203Srpaulo	if ((m = sshbuf_new()) == NULL)
617235530Sdelphij		fatal_f("sshbuf_new failed");
618235530Sdelphij	if ((r = sshbuf_put_cstring(m, s->tty)) != 0)
619235530Sdelphij		fatal_fr(r, "assmble");
620235530Sdelphij	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PTYCLEANUP, m);
621235530Sdelphij	sshbuf_free(m);
622235530Sdelphij
623235530Sdelphij	/* closed dup'ed master */
624190203Srpaulo	if (s->ptymaster != -1 && close(s->ptymaster) == -1)
625235530Sdelphij		error("close(s->ptymaster/%d): %s",
626190203Srpaulo		    s->ptymaster, strerror(errno));
627190203Srpaulo
628235530Sdelphij	/* unlink pty from session */
629235530Sdelphij	s->ttyfd = -1;
630235530Sdelphij}
631235530Sdelphij
632235530Sdelphij#ifdef USE_PAM
633235530Sdelphijvoid
634235530Sdelphijmm_start_pam(struct ssh *ssh)
635190203Srpaulo{
636235530Sdelphij	struct sshbuf *m;
637190203Srpaulo
638190203Srpaulo	debug3("%s entering", __func__);
639190203Srpaulo	if (!options.use_pam)
640190203Srpaulo		fatal("UsePAM=no, but ended up in %s anyway", __func__);
641190203Srpaulo
642190203Srpaulo	if ((m = sshbuf_new()) == NULL)
643190203Srpaulo		fatal("%s: sshbuf_new failed", __func__);
644190203Srpaulo	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_START, m);
645190203Srpaulo
646190203Srpaulo	sshbuf_free(m);
647190203Srpaulo}
648235530Sdelphij
649190203Srpaulou_int
650190203Srpaulomm_do_pam_account(void)
651235530Sdelphij{
652190203Srpaulo	struct sshbuf *m;
653190203Srpaulo	int r;
654190203Srpaulo	u_int ret;
655235530Sdelphij	size_t len;
656235530Sdelphij	char *msg;
657235530Sdelphij
658190203Srpaulo	debug3("%s entering", __func__);
659190203Srpaulo	if (!options.use_pam)
660190203Srpaulo		fatal("UsePAM=no, but ended up in %s anyway", __func__);
661190203Srpaulo
662190203Srpaulo	if ((m = sshbuf_new()) == NULL)
663190203Srpaulo		fatal("%s: sshbuf_new failed", __func__);
664190203Srpaulo	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_ACCOUNT, m);
665190203Srpaulo
666235530Sdelphij	mm_request_receive_expect(pmonitor->m_recvfd,
667235530Sdelphij	    MONITOR_ANS_PAM_ACCOUNT, m);
668235530Sdelphij	if ((r = sshbuf_get_u32(m, &ret)) != 0 ||
669190203Srpaulo	    (r = sshbuf_get_cstring(m, &msg, &len)) != 0)
670190203Srpaulo		fatal("%s: buffer error: %s", __func__, ssh_err(r));
671190203Srpaulo	sshbuf_put_cstring(loginmsg, msg);
672190203Srpaulo	free(msg);
673190203Srpaulo
674190203Srpaulo	sshbuf_free(m);
675190203Srpaulo
676190203Srpaulo	debug3("%s returning %d", __func__, ret);
677190203Srpaulo
678190203Srpaulo	return (ret);
679190203Srpaulo}
680190203Srpaulo
681235530Sdelphijvoid *
682235530Sdelphijmm_sshpam_init_ctx(Authctxt *authctxt)
683235530Sdelphij{
684190203Srpaulo	struct sshbuf *m;
685190203Srpaulo	u_int success;
686190203Srpaulo	int r;
687190203Srpaulo
688190203Srpaulo	debug3("%s", __func__);
689190203Srpaulo	if ((m = sshbuf_new()) == NULL)
690190203Srpaulo		fatal("%s: sshbuf_new failed", __func__);
691235530Sdelphij	sshbuf_put_cstring(m, authctxt->user);
692235530Sdelphij	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_INIT_CTX, m);
693235530Sdelphij	debug3("%s: waiting for MONITOR_ANS_PAM_INIT_CTX", __func__);
694190203Srpaulo	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_INIT_CTX, m);
695190203Srpaulo	if ((r = sshbuf_get_u32(m, &success)) != 0)
696190203Srpaulo		fatal("%s: buffer error: %s", __func__, ssh_err(r));
697190203Srpaulo	if (success == 0) {
698190203Srpaulo		debug3("%s: pam_init_ctx failed", __func__);
699190203Srpaulo		sshbuf_free(m);
700190203Srpaulo		return (NULL);
701190203Srpaulo	}
702190203Srpaulo	sshbuf_free(m);
703190203Srpaulo	return (authctxt);
704190203Srpaulo}
705190203Srpaulo
706190203Srpauloint
707190203Srpaulomm_sshpam_query(void *ctx, char **name, char **info,
708190203Srpaulo    u_int *num, char ***prompts, u_int **echo_on)
709190203Srpaulo{
710190203Srpaulo	struct sshbuf *m;
711190203Srpaulo	u_int i, ret;
712190203Srpaulo	int r;
713190203Srpaulo
714190203Srpaulo	debug3("%s", __func__);
715190203Srpaulo	if ((m = sshbuf_new()) == NULL)
716190203Srpaulo		fatal("%s: sshbuf_new failed", __func__);
717190203Srpaulo	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_QUERY, m);
718190203Srpaulo	debug3("%s: waiting for MONITOR_ANS_PAM_QUERY", __func__);
719190203Srpaulo	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_QUERY, m);
720190203Srpaulo	if ((r = sshbuf_get_u32(m, &ret)) != 0)
721190203Srpaulo		fatal("%s: buffer error: %s", __func__, ssh_err(r));
722190203Srpaulo	debug3("%s: pam_query returned %d", __func__, ret);
723190203Srpaulo	if ((r = sshbuf_get_cstring(m, name, NULL)) != 0 ||
724190203Srpaulo	    (r = sshbuf_get_cstring(m, info, NULL)) != 0 ||
725190203Srpaulo	    (r = sshbuf_get_u32(m, num)) != 0)
726190203Srpaulo		fatal("%s: buffer error: %s", __func__, ssh_err(r));
727190203Srpaulo	if (*num > PAM_MAX_NUM_MSG)
728190203Srpaulo		fatal("%s: received %u PAM messages, expected <= %u",
729190203Srpaulo		    __func__, *num, PAM_MAX_NUM_MSG);
730190203Srpaulo	*prompts = xcalloc((*num + 1), sizeof(char *));
731190203Srpaulo	*echo_on = xcalloc((*num + 1), sizeof(u_int));
732190203Srpaulo	for (i = 0; i < *num; ++i) {
733190203Srpaulo		if ((r = sshbuf_get_cstring(m, &(*prompts)[i], NULL)) != 0 ||
734235530Sdelphij		    (r = sshbuf_get_u32(m, (echo_on)[i])) != 0)
735235530Sdelphij			fatal("%s: buffer error: %s", __func__, ssh_err(r));
736190203Srpaulo	}
737235530Sdelphij	sshbuf_free(m);
738235530Sdelphij	return (ret);
739235530Sdelphij}
740190203Srpaulo
741190203Srpauloint
742190203Srpaulomm_sshpam_respond(void *ctx, u_int num, char **resp)
743190203Srpaulo{
744190203Srpaulo	struct sshbuf *m;
745190203Srpaulo	int r;
746190203Srpaulo	u_int i;
747190203Srpaulo	u_int ret;
748235530Sdelphij
749235530Sdelphij	debug3("%s", __func__);
750235530Sdelphij	if ((m = sshbuf_new()) == NULL)
751190203Srpaulo		fatal("%s: sshbuf_new failed", __func__);
752190203Srpaulo	sshbuf_put_u32(m, num);
753190203Srpaulo	for (i = 0; i < num; ++i)
754190203Srpaulo		sshbuf_put_cstring(m, resp[i]);
755190203Srpaulo	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_RESPOND, m);
756190203Srpaulo	debug3("%s: waiting for MONITOR_ANS_PAM_RESPOND", __func__);
757190203Srpaulo	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_RESPOND, m);
758190203Srpaulo	if ((r = sshbuf_get_u32(m, &ret)) != 0)
759190203Srpaulo		fatal("%s: buffer error: %s", __func__, ssh_err(r));
760235530Sdelphij	debug3("%s: pam_respond returned %d", __func__, ret);
761235530Sdelphij	sshbuf_free(m);
762235530Sdelphij	return (ret);
763190203Srpaulo}
764190203Srpaulo
765190203Srpaulovoid
766190203Srpaulomm_sshpam_free_ctx(void *ctxtp)
767190203Srpaulo{
768190203Srpaulo	struct sshbuf *m;
769190203Srpaulo
770190203Srpaulo	debug3("%s", __func__);
771190203Srpaulo	if ((m = sshbuf_new()) == NULL)
772190203Srpaulo		fatal("%s: sshbuf_new failed", __func__);
773190203Srpaulo	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_FREE_CTX, m);
774190203Srpaulo	debug3("%s: waiting for MONITOR_ANS_PAM_FREE_CTX", __func__);
775190203Srpaulo	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_FREE_CTX, m);
776190203Srpaulo	sshbuf_free(m);
777235530Sdelphij}
778235530Sdelphij#endif /* USE_PAM */
779235530Sdelphij
780190203Srpaulo/* Request process termination */
781190203Srpaulo
782190203Srpaulovoid
783190203Srpaulomm_terminate(void)
784190203Srpaulo{
785190203Srpaulo	struct sshbuf *m;
786190203Srpaulo
787235530Sdelphij	if ((m = sshbuf_new()) == NULL)
788235530Sdelphij		fatal_f("sshbuf_new failed");
789235530Sdelphij	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_TERM, m);
790190203Srpaulo	sshbuf_free(m);
791190203Srpaulo}
792190203Srpaulo
793190203Srpaulo#if defined(BSD_AUTH) || defined(SKEY)
794190203Srpaulostatic void
795190203Srpaulomm_chall_setup(char **name, char **infotxt, u_int *numprompts,
796190203Srpaulo    char ***prompts, u_int **echo_on)
797190203Srpaulo{
798190203Srpaulo	*name = xstrdup("");
799190203Srpaulo	*infotxt = xstrdup("");
800190203Srpaulo	*numprompts = 1;
801190203Srpaulo	*prompts = xcalloc(*numprompts, sizeof(char *));
802190203Srpaulo	*echo_on = xcalloc(*numprompts, sizeof(u_int));
803190203Srpaulo	(*echo_on)[0] = 0;
804190203Srpaulo}
805190203Srpaulo
806235530Sdelphij#ifdef BSD_AUTH
807235530Sdelphijint
808235530Sdelphijmm_bsdauth_query(void *ctx, char **name, char **infotxt,
809190203Srpaulo   u_int *numprompts, char ***prompts, u_int **echo_on)
810235530Sdelphij{
811235530Sdelphij	struct sshbuf *m;
812235530Sdelphij	u_int success;
813235530Sdelphij	char *challenge;
814235530Sdelphij	int r;
815235530Sdelphij
816190203Srpaulo	debug3_f("entering");
817190203Srpaulo
818190203Srpaulo	if ((m = sshbuf_new()) == NULL)
819190203Srpaulo		fatal_f("sshbuf_new failed");
820190203Srpaulo	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_BSDAUTHQUERY, m);
821190203Srpaulo
822190203Srpaulo	mm_request_receive_expect(pmonitor->m_recvfd,
823190203Srpaulo	    MONITOR_ANS_BSDAUTHQUERY, m);
824190203Srpaulo	if ((r = sshbuf_get_u32(m, &success)) != 0)
825190203Srpaulo		fatal_fr(r, "parse success");
826190203Srpaulo	if (success == 0) {
827190203Srpaulo		debug3_f("no challenge");
828190203Srpaulo		sshbuf_free(m);
829235530Sdelphij		return (-1);
830235530Sdelphij	}
831235530Sdelphij
832190203Srpaulo	/* Get the challenge, and format the response */
833190203Srpaulo	if ((r = sshbuf_get_cstring(m, &challenge, NULL)) != 0)
834190203Srpaulo		fatal_fr(r, "parse challenge");
835190203Srpaulo	sshbuf_free(m);
836190203Srpaulo
837190203Srpaulo	mm_chall_setup(name, infotxt, numprompts, prompts, echo_on);
838190203Srpaulo	(*prompts)[0] = challenge;
839190203Srpaulo
840190203Srpaulo	debug3_f("received challenge: %s", challenge);
841190203Srpaulo
842190203Srpaulo	return (0);
843190203Srpaulo}
844190203Srpaulo
845190203Srpauloint
846235530Sdelphijmm_bsdauth_respond(void *ctx, u_int numresponses, char **responses)
847235530Sdelphij{
848235530Sdelphij	struct sshbuf *m;
849190203Srpaulo	int r, authok;
850190203Srpaulo
851190203Srpaulo	debug3_f("entering");
852190203Srpaulo	if (numresponses != 1)
853190203Srpaulo		return (-1);
854190203Srpaulo
855190203Srpaulo	if ((m = sshbuf_new()) == NULL)
856190203Srpaulo		fatal_f("sshbuf_new failed");
857190203Srpaulo	if ((r = sshbuf_put_cstring(m, responses[0])) != 0)
858190203Srpaulo		fatal_fr(r, "assemble");
859190203Srpaulo	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_BSDAUTHRESPOND, m);
860190203Srpaulo
861190203Srpaulo	mm_request_receive_expect(pmonitor->m_recvfd,
862190203Srpaulo	    MONITOR_ANS_BSDAUTHRESPOND, m);
863190203Srpaulo
864190203Srpaulo	if ((r = sshbuf_get_u32(m, &authok)) != 0)
865190203Srpaulo		fatal_fr(r, "parse");
866190203Srpaulo	sshbuf_free(m);
867190203Srpaulo
868235530Sdelphij	return ((authok == 0) ? -1 : 0);
869235530Sdelphij}
870235530Sdelphij#endif
871190203Srpaulo
872190203Srpaulo#ifdef SKEY
873190203Srpauloint
874190203Srpaulomm_skey_query(void *ctx, char **name, char **infotxt,
875190203Srpaulo   u_int *numprompts, char ***prompts, u_int **echo_on)
876190203Srpaulo{
877190203Srpaulo	struct sshbuf m;
878190203Srpaulo	u_int success;
879190203Srpaulo	char *challenge;
880190203Srpaulo
881190203Srpaulo	debug3("%s: entering", __func__);
882190203Srpaulo
883190203Srpaulo	sshbuf_new(&m);
884190203Srpaulo	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_SKEYQUERY, &m);
885190203Srpaulo
886190203Srpaulo	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_SKEYQUERY,
887190203Srpaulo	    &m);
888190203Srpaulo	success = sshbuf_get_int(&m);
889190203Srpaulo	if (success == 0) {
890190203Srpaulo		debug3("%s: no challenge", __func__);
891190203Srpaulo		sshbuf_free(&m);
892190203Srpaulo		return (-1);
893190203Srpaulo	}
894190203Srpaulo
895190203Srpaulo	/* Get the challenge, and format the response */
896190203Srpaulo	challenge  = sshbuf_get_string(&m, NULL);
897190203Srpaulo	sshbuf_free(&m);
898190203Srpaulo
899190203Srpaulo	debug3("%s: received challenge: %s", __func__, challenge);
900190203Srpaulo
901190203Srpaulo	mm_chall_setup(name, infotxt, numprompts, prompts, echo_on);
902190203Srpaulo
903190203Srpaulo	xasprintf(*prompts, "%s%s", challenge, SKEY_PROMPT);
904190203Srpaulo	free(challenge);
905190203Srpaulo
906235530Sdelphij	return (0);
907235530Sdelphij}
908235530Sdelphij
909235530Sdelphijint
910235530Sdelphijmm_skey_respond(void *ctx, u_int numresponses, char **responses)
911235530Sdelphij{
912235530Sdelphij	struct sshbuf m;
913235530Sdelphij	int authok;
914235530Sdelphij
915235530Sdelphij	debug3("%s: entering", __func__);
916235530Sdelphij	if (numresponses != 1)
917235530Sdelphij		return (-1);
918235530Sdelphij
919235530Sdelphij	sshbuf_new(&m);
920235530Sdelphij	sshbuf_put_cstring(&m, responses[0]);
921235530Sdelphij	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_SKEYRESPOND, &m);
922235530Sdelphij
923235530Sdelphij	mm_request_receive_expect(pmonitor->m_recvfd,
924235530Sdelphij	    MONITOR_ANS_SKEYRESPOND, &m);
925235530Sdelphij
926235530Sdelphij	authok = sshbuf_get_int(&m);
927235530Sdelphij	sshbuf_free(&m);
928235530Sdelphij
929235530Sdelphij	return ((authok == 0) ? -1 : 0);
930235530Sdelphij}
931235530Sdelphij#endif /* SKEY */
932235530Sdelphij#endif /* BSDAUTH || SKEY */
933235530Sdelphij
934235530Sdelphij#ifdef GSSAPI
935235530SdelphijOM_uint32
936235530Sdelphijmm_ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID goid)
937235530Sdelphij{
938235530Sdelphij	struct sshbuf *m;
939235530Sdelphij	OM_uint32 major;
940235530Sdelphij	int r;
941235530Sdelphij
942235530Sdelphij	/* Client doesn't get to see the context */
943235530Sdelphij	*ctx = NULL;
944235530Sdelphij
945235530Sdelphij	if ((m = sshbuf_new()) == NULL)
946235530Sdelphij		fatal_f("sshbuf_new failed");
947235530Sdelphij	if ((r = sshbuf_put_string(m, goid->elements, goid->length)) != 0)
948235530Sdelphij		fatal_fr(r, "assemble");
949235530Sdelphij
950235530Sdelphij	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSETUP, m);
951235530Sdelphij	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSETUP, m);
952235530Sdelphij
953235530Sdelphij	if ((r = sshbuf_get_u32(m, &major)) != 0)
954235530Sdelphij		fatal_fr(r, "parse");
955235530Sdelphij
956235530Sdelphij	sshbuf_free(m);
957235530Sdelphij	return (major);
958235530Sdelphij}
959235530Sdelphij
960235530SdelphijOM_uint32
961235530Sdelphijmm_ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *in,
962235530Sdelphij    gss_buffer_desc *out, OM_uint32 *flagsp)
963235530Sdelphij{
964235530Sdelphij	struct sshbuf *m;
965235530Sdelphij	OM_uint32 major;
966235530Sdelphij	u_int flags;
967235530Sdelphij	int r;
968235530Sdelphij
969235530Sdelphij	if ((m = sshbuf_new()) == NULL)
970235530Sdelphij		fatal_f("sshbuf_new failed");
971235530Sdelphij	if ((r = sshbuf_put_string(m, in->value, in->length)) != 0)
972235530Sdelphij		fatal_fr(r, "assemble");
973235530Sdelphij
974235530Sdelphij	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSTEP, m);
975235530Sdelphij	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSTEP, m);
976235530Sdelphij
977235530Sdelphij	if ((r = sshbuf_get_u32(m, &major)) != 0 ||
978235530Sdelphij	    (r = ssh_gssapi_get_buffer_desc(m, out)) != 0)
979235530Sdelphij		fatal_fr(r, "parse");
980235530Sdelphij	if (flagsp != NULL) {
981235530Sdelphij		if ((r = sshbuf_get_u32(m, &flags)) != 0)
982235530Sdelphij			fatal_fr(r, "parse flags");
983235530Sdelphij		*flagsp = flags;
984235530Sdelphij	}
985235530Sdelphij
986235530Sdelphij	sshbuf_free(m);
987235530Sdelphij
988235530Sdelphij	return (major);
989235530Sdelphij}
990235530Sdelphij
991235530SdelphijOM_uint32
992235530Sdelphijmm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
993235530Sdelphij{
994235530Sdelphij	struct sshbuf *m;
995235530Sdelphij	OM_uint32 major;
996235530Sdelphij	int r;
997235530Sdelphij
998235530Sdelphij	if ((m = sshbuf_new()) == NULL)
999235530Sdelphij		fatal_f("sshbuf_new failed");
1000235530Sdelphij	if ((r = sshbuf_put_string(m, gssbuf->value, gssbuf->length)) != 0 ||
1001235530Sdelphij	    (r = sshbuf_put_string(m, gssmic->value, gssmic->length)) != 0)
1002235530Sdelphij		fatal_fr(r, "assemble");
1003235530Sdelphij
1004235530Sdelphij	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSCHECKMIC, m);
1005235530Sdelphij	mm_request_receive_expect(pmonitor->m_recvfd,
1006235530Sdelphij	    MONITOR_ANS_GSSCHECKMIC, m);
1007235530Sdelphij
1008235530Sdelphij	if ((r = sshbuf_get_u32(m, &major)) != 0)
1009235530Sdelphij		fatal_fr(r, "parse");
1010235530Sdelphij	sshbuf_free(m);
1011235530Sdelphij	return(major);
1012235530Sdelphij}
1013235530Sdelphij
1014235530Sdelphijint
1015235530Sdelphijmm_ssh_gssapi_userok(char *user)
1016235530Sdelphij{
1017235530Sdelphij	struct sshbuf *m;
1018235530Sdelphij	int r;
1019235530Sdelphij	u_int authenticated = 0;
1020235530Sdelphij
1021235530Sdelphij	if ((m = sshbuf_new()) == NULL)
1022235530Sdelphij		fatal_f("sshbuf_new failed");
1023235530Sdelphij
1024235530Sdelphij	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, m);
1025235530Sdelphij	mm_request_receive_expect(pmonitor->m_recvfd,
1026235530Sdelphij	    MONITOR_ANS_GSSUSEROK, m);
1027235530Sdelphij
1028235530Sdelphij	if ((r = sshbuf_get_u32(m, &authenticated)) != 0)
1029235530Sdelphij		fatal_fr(r, "parse");
1030235530Sdelphij
1031235530Sdelphij	sshbuf_free(m);
1032235530Sdelphij	debug3_f("user %sauthenticated", authenticated ? "" : "not ");
1033235530Sdelphij	return (authenticated);
1034235530Sdelphij}
1035235530Sdelphij#endif /* GSSAPI */
1036235530Sdelphij
1037235530Sdelphij#ifdef KRB5
1038235530Sdelphijint
1039235530Sdelphijmm_auth_krb5(void *ctx, void *argp, char **userp, void *resp)
1040235530Sdelphij{
1041235530Sdelphij	krb5_data *tkt, *reply;
1042235530Sdelphij	struct sshbuf *m;
1043235530Sdelphij	u_int success;
1044235530Sdelphij	int r;
1045235530Sdelphij
1046235530Sdelphij	debug3("%s entering", __func__);
1047235530Sdelphij	tkt = (krb5_data *) argp;
1048235530Sdelphij	reply = (krb5_data *) resp;
1049235530Sdelphij
1050235530Sdelphij	if ((m = sshbuf_new()) == NULL)
1051235530Sdelphij		fatal("%s: sshbuf_new failed", __func__);
1052235530Sdelphij	sshbuf_put_string(m, tkt->data, tkt->length);
1053235530Sdelphij
1054235530Sdelphij	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KRB5, m);
1055235530Sdelphij	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_KRB5, m);
1056235530Sdelphij
1057235530Sdelphij	if ((r = sshbuf_get_u32(m, &success)) != 0)
1058235530Sdelphij		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1059235530Sdelphij	if (success) {
1060235530Sdelphij		size_t len;
1061235530Sdelphij		u_char *data;
1062235530Sdelphij
1063235530Sdelphij		if ((r = sshbuf_get_cstring(m, userp, NULL)) != 0 ||
1064235530Sdelphij		    (r = sshbuf_get_string(m, &data, &len)) != 0)
1065235530Sdelphij			fatal("%s: buffer error: %s", __func__, ssh_err(r));
1066235530Sdelphij		reply->data = data;
1067235530Sdelphij		reply->length = len;
1068235530Sdelphij	} else {
1069190203Srpaulo		memset(reply, 0, sizeof(*reply));
1070235530Sdelphij		*userp = NULL;
1071190203Srpaulo	}
1072190203Srpaulo
1073190203Srpaulo	sshbuf_free(m);
1074190203Srpaulo	return (success);
1075190203Srpaulo}
1076235530Sdelphij#endif
1077235530Sdelphij