📄 monitor.c
字号:
/* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * Copyright 2002 Markus Friedl <markus@openbsd.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "includes.h"RCSID("$OpenBSD: monitor.c,v 1.16 2002/06/21 05:50:51 djm Exp $");#include <openssl/dh.h>#ifdef SKEY#include <skey.h>#endif#include "ssh.h"#include "auth.h"#include "kex.h"#include "dh.h"#include "zlib.h"#include "packet.h"#include "auth-options.h"#include "sshpty.h"#include "channels.h"#include "session.h"#include "sshlogin.h"#include "canohost.h"#include "log.h"#include "servconf.h"#include "monitor.h"#include "monitor_mm.h"#include "monitor_wrap.h"#include "monitor_fdpass.h"#include "xmalloc.h"#include "misc.h"#include "buffer.h"#include "bufaux.h"#include "compat.h"#include "ssh2.h"#include "mpaux.h"/* Imports */extern ServerOptions options;extern u_int utmp_len;extern Newkeys *current_keys[];extern z_stream incoming_stream;extern z_stream outgoing_stream;extern u_char session_id[];extern Buffer input, output;extern Buffer auth_debug;extern int auth_debug_init;/* State exported from the child */struct { z_stream incoming; z_stream outgoing; u_char *keyin; u_int keyinlen; u_char *keyout; u_int keyoutlen; u_char *ivin; u_int ivinlen; u_char *ivout; u_int ivoutlen; u_char *ssh1key; u_int ssh1keylen; int ssh1cipher; int ssh1protoflags; u_char *input; u_int ilen; u_char *output; u_int olen;} child_state;/* Functions on the montior that answer unprivileged requests */int mm_answer_moduli(int, Buffer *);int mm_answer_sign(int, Buffer *);int mm_answer_pwnamallow(int, Buffer *);int mm_answer_auth2_read_banner(int, Buffer *);int mm_answer_authserv(int, Buffer *);int mm_answer_authpassword(int, Buffer *);int mm_answer_bsdauthquery(int, Buffer *);int mm_answer_bsdauthrespond(int, Buffer *);int mm_answer_skeyquery(int, Buffer *);int mm_answer_skeyrespond(int, Buffer *);int mm_answer_keyallowed(int, Buffer *);int mm_answer_keyverify(int, Buffer *);int mm_answer_pty(int, Buffer *);int mm_answer_pty_cleanup(int, Buffer *);int mm_answer_term(int, Buffer *);int mm_answer_rsa_keyallowed(int, Buffer *);int mm_answer_rsa_challenge(int, Buffer *);int mm_answer_rsa_response(int, Buffer *);int mm_answer_sesskey(int, Buffer *);int mm_answer_sessid(int, Buffer *);#ifdef USE_PAMint mm_answer_pam_start(int, Buffer *);#endifstatic Authctxt *authctxt;static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth *//* local state for key verify */static u_char *key_blob = NULL;static u_int key_bloblen = 0;static int key_blobtype = MM_NOKEY;static u_char *hostbased_cuser = NULL;static u_char *hostbased_chost = NULL;static char *auth_method = "unknown";static int session_id2_len = 0;static u_char *session_id2 = NULL;struct mon_table { enum monitor_reqtype type; int flags; int (*f)(int, Buffer *);};#define MON_ISAUTH 0x0004 /* Required for Authentication */#define MON_AUTHDECIDE 0x0008 /* Decides Authentication */#define MON_ONCE 0x0010 /* Disable after calling */#define MON_AUTH (MON_ISAUTH|MON_AUTHDECIDE)#define MON_PERMIT 0x1000 /* Request is permitted */struct mon_table mon_dispatch_proto20[] = { {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli}, {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner}, {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},#ifdef USE_PAM {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},#endif#ifdef BSD_AUTH {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery}, {MONITOR_REQ_BSDAUTHRESPOND, MON_AUTH,mm_answer_bsdauthrespond},#endif#ifdef SKEY {MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery}, {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond},#endif {MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed}, {MONITOR_REQ_KEYVERIFY, MON_AUTH, mm_answer_keyverify}, {0, 0, NULL}};struct mon_table mon_dispatch_postauth20[] = { {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, {MONITOR_REQ_SIGN, 0, mm_answer_sign}, {MONITOR_REQ_PTY, 0, mm_answer_pty}, {MONITOR_REQ_PTYCLEANUP, 0, mm_answer_pty_cleanup}, {MONITOR_REQ_TERM, 0, mm_answer_term}, {0, 0, NULL}};struct mon_table mon_dispatch_proto15[] = { {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, {MONITOR_REQ_SESSKEY, MON_ONCE, mm_answer_sesskey}, {MONITOR_REQ_SESSID, MON_ONCE, mm_answer_sessid}, {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, {MONITOR_REQ_RSAKEYALLOWED, MON_ISAUTH, mm_answer_rsa_keyallowed}, {MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed}, {MONITOR_REQ_RSACHALLENGE, MON_ONCE, mm_answer_rsa_challenge}, {MONITOR_REQ_RSARESPONSE, MON_ONCE|MON_AUTHDECIDE, mm_answer_rsa_response},#ifdef USE_PAM {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},#endif#ifdef BSD_AUTH {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery}, {MONITOR_REQ_BSDAUTHRESPOND, MON_AUTH,mm_answer_bsdauthrespond},#endif#ifdef SKEY {MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery}, {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond},#endif#ifdef USE_PAM {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},#endif {0, 0, NULL}};struct mon_table mon_dispatch_postauth15[] = { {MONITOR_REQ_PTY, MON_ONCE, mm_answer_pty}, {MONITOR_REQ_PTYCLEANUP, MON_ONCE, mm_answer_pty_cleanup}, {MONITOR_REQ_TERM, 0, mm_answer_term}, {0, 0, NULL}};struct mon_table *mon_dispatch;/* Specifies if a certain message is allowed at the moment */static voidmonitor_permit(struct mon_table *ent, enum monitor_reqtype type, int permit){ while (ent->f != NULL) { if (ent->type == type) { ent->flags &= ~MON_PERMIT; ent->flags |= permit ? MON_PERMIT : 0; return; } ent++; }}static voidmonitor_permit_authentications(int permit){ struct mon_table *ent = mon_dispatch; while (ent->f != NULL) { if (ent->flags & MON_AUTH) { ent->flags &= ~MON_PERMIT; ent->flags |= permit ? MON_PERMIT : 0; } ent++; }}Authctxt *monitor_child_preauth(struct monitor *pmonitor){ struct mon_table *ent; int authenticated = 0; debug3("preauth child monitor started"); if (compat20) { mon_dispatch = mon_dispatch_proto20; /* Permit requests for moduli and signatures */ monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); } else { mon_dispatch = mon_dispatch_proto15; monitor_permit(mon_dispatch, MONITOR_REQ_SESSKEY, 1); } authctxt = authctxt_new(); /* The first few requests do not require asynchronous access */ while (!authenticated) { authenticated = monitor_read(pmonitor, mon_dispatch, &ent); if (authenticated) { if (!(ent->flags & MON_AUTHDECIDE)) fatal("%s: unexpected authentication from %d", __func__, ent->type); if (authctxt->pw->pw_uid == 0 && !auth_root_allowed(auth_method)) authenticated = 0;#ifdef USE_PAM if (!do_pam_account(authctxt->pw->pw_name, NULL)) authenticated = 0;#endif } if (ent->flags & MON_AUTHDECIDE) { auth_log(authctxt, authenticated, auth_method, compat20 ? " ssh2" : ""); if (!authenticated) authctxt->failures++; } } if (!authctxt->valid) fatal("%s: authenticated invalid user", __func__); debug("%s: %s has been authenticated by privileged process", __func__, authctxt->user); mm_get_keystate(pmonitor); return (authctxt);}voidmonitor_child_postauth(struct monitor *pmonitor){ if (compat20) { mon_dispatch = mon_dispatch_postauth20; /* Permit requests for moduli and signatures */ monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); } else { mon_dispatch = mon_dispatch_postauth15; monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); } if (!no_pty_flag) { monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1); } for (;;) monitor_read(pmonitor, mon_dispatch, NULL);}voidmonitor_sync(struct monitor *pmonitor){ if (options.compression) { /* The member allocation is not visible, so sync it */ mm_share_sync(&pmonitor->m_zlib, &pmonitor->m_zback); }}intmonitor_read(struct monitor *pmonitor, struct mon_table *ent, struct mon_table **pent){ Buffer m; int ret; u_char type; buffer_init(&m); mm_request_receive(pmonitor->m_sendfd, &m); type = buffer_get_char(&m); debug3("%s: checking request %d", __func__, type); while (ent->f != NULL) { if (ent->type == type) break; ent++; } if (ent->f != NULL) { if (!(ent->flags & MON_PERMIT)) fatal("%s: unpermitted request %d", __func__, type); ret = (*ent->f)(pmonitor->m_sendfd, &m); buffer_free(&m); /* The child may use this request only once, disable it */ if (ent->flags & MON_ONCE) { debug2("%s: %d used once, disabling now", __func__, type); ent->flags &= ~MON_PERMIT; } if (pent != NULL) *pent = ent; return ret; } fatal("%s: unsupported request: %d", __func__, type); /* NOTREACHED */ return (-1);}/* allowed key state */static intmonitor_allowed_key(u_char *blob, u_int bloblen){ /* make sure key is allowed */ if (key_blob == NULL || key_bloblen != bloblen || memcmp(key_blob, blob, key_bloblen)) return (0); return (1);}static voidmonitor_reset_key_state(void){ /* reset state */ if (key_blob != NULL) xfree(key_blob); if (hostbased_cuser != NULL) xfree(hostbased_cuser); if (hostbased_chost != NULL) xfree(hostbased_chost); key_blob = NULL; key_bloblen = 0; key_blobtype = MM_NOKEY; hostbased_cuser = NULL; hostbased_chost = NULL;}intmm_answer_moduli(int socket, Buffer *m){ DH *dh; int min, want, max; min = buffer_get_int(m); want = buffer_get_int(m); max = buffer_get_int(m); debug3("%s: got parameters: %d %d %d", __func__, min, want, max); /* We need to check here, too, in case the child got corrupted */ if (max < min || want < min || max < want) fatal("%s: bad parameters: %d %d %d", __func__, min, want, max); buffer_clear(m); dh = choose_dh(min, want, max); if (dh == NULL) { buffer_put_char(m, 0); return (0); } else { /* Send first bignum */ buffer_put_char(m, 1); buffer_put_bignum2(m, dh->p); buffer_put_bignum2(m, dh->g); DH_free(dh); } mm_request_send(socket, MONITOR_ANS_MODULI, m); return (0);}intmm_answer_sign(int socket, Buffer *m){ Key *key; u_char *p; u_char *signature; u_int siglen, datlen; int keyid; debug3("%s", __func__); keyid = buffer_get_int(m); p = buffer_get_string(m, &datlen); if (datlen != 20) fatal("%s: data length incorrect: %d", __func__, datlen); /* save session id, it will be passed on the first call */ if (session_id2_len == 0) { session_id2_len = datlen; session_id2 = xmalloc(session_id2_len); memcpy(session_id2, p, session_id2_len); } if ((key = get_hostkey_by_index(keyid)) == NULL) fatal("%s: no hostkey from index %d", __func__, keyid); if (key_sign(key, &signature, &siglen, p, datlen) < 0) fatal("%s: key_sign failed", __func__); debug3("%s: signature %p(%d)", __func__, signature, siglen); buffer_clear(m); buffer_put_string(m, signature, siglen); xfree(p); xfree(signature); mm_request_send(socket, MONITOR_ANS_SIGN, m); /* Turn on permissions for getpwnam */ monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1); return (0);}/* Retrieves the password entry and also checks if the user is permitted */intmm_answer_pwnamallow(int socket, Buffer *m){ char *login; struct passwd *pwent; int allowed = 0; debug3("%s", __func__); if (authctxt->attempt++ != 0) fatal("%s: multiple attempts for getpwnam", __func__); login = buffer_get_string(m, NULL); pwent = getpwnamallow(login); authctxt->user = xstrdup(login); setproctitle("%s [priv]", pwent ? login : "unknown"); xfree(login); buffer_clear(m);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -