⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 auth-pam.c

📁 OpenSSH 是 SSH (Secure SHell) 协议的免费开源实现。它用安全、加密的网络连接工具代替了 telnet、ftp、 rlogin、rsh 和 rcp 工具。OpenSSH 支持
💻 C
📖 第 1 页 / 共 2 页
字号:
	debug("PAM: initializing for \"%s\"", user);	sshpam_err =	    pam_start(SSHD_PAM_SERVICE, user, &store_conv, &sshpam_handle);	sshpam_authctxt = authctxt;	if (sshpam_err != PAM_SUCCESS) {		pam_end(sshpam_handle, sshpam_err);		sshpam_handle = NULL;		return (-1);	}	pam_rhost = get_remote_name_or_ip(utmp_len, options.use_dns);	debug("PAM: setting PAM_RHOST to \"%s\"", pam_rhost);	sshpam_err = pam_set_item(sshpam_handle, PAM_RHOST, pam_rhost);	if (sshpam_err != PAM_SUCCESS) {		pam_end(sshpam_handle, sshpam_err);		sshpam_handle = NULL;		return (-1);	}#ifdef PAM_TTY_KLUDGE	/*	 * Some silly PAM modules (e.g. pam_time) require a TTY to operate.	 * sshd doesn't set the tty until too late in the auth process and	 * may not even set one (for tty-less connections)	 */	debug("PAM: setting PAM_TTY to \"ssh\"");	sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, "ssh");	if (sshpam_err != PAM_SUCCESS) {		pam_end(sshpam_handle, sshpam_err);		sshpam_handle = NULL;		return (-1);	}#endif	return (0);}static void *sshpam_init_ctx(Authctxt *authctxt){	struct pam_ctxt *ctxt;	int socks[2];	debug3("PAM: %s entering", __func__);	/* Refuse to start if we don't have PAM enabled */	if (!options.use_pam)		return NULL;	/* Initialize PAM */	if (sshpam_init(authctxt) == -1) {		error("PAM: initialization failed");		return (NULL);	}	ctxt = xmalloc(sizeof *ctxt);	memset(ctxt, 0, sizeof(*ctxt));	/* Start the authentication thread */	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {		error("PAM: failed create sockets: %s", strerror(errno));		xfree(ctxt);		return (NULL);	}	ctxt->pam_psock = socks[0];	ctxt->pam_csock = socks[1];	if (pthread_create(&ctxt->pam_thread, NULL, sshpam_thread, ctxt) == -1) {		error("PAM: failed to start authentication thread: %s",		    strerror(errno));		close(socks[0]);		close(socks[1]);		xfree(ctxt);		return (NULL);	}	cleanup_ctxt = ctxt;	return (ctxt);}static intsshpam_query(void *ctx, char **name, char **info,    u_int *num, char ***prompts, u_int **echo_on){	Buffer buffer;	struct pam_ctxt *ctxt = ctx;	size_t plen;	u_char type;	char *msg;	size_t len, mlen;	debug3("PAM: %s entering", __func__);	buffer_init(&buffer);	*name = xstrdup("");	*info = xstrdup("");	*prompts = xmalloc(sizeof(char *));	**prompts = NULL;	plen = 0;	*echo_on = xmalloc(sizeof(u_int));	while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) {		type = buffer_get_char(&buffer);		msg = buffer_get_string(&buffer, NULL);		mlen = strlen(msg);		switch (type) {		case PAM_PROMPT_ECHO_ON:		case PAM_PROMPT_ECHO_OFF:			*num = 1;			len = plen + mlen + 1;			**prompts = xrealloc(**prompts, len);			strlcpy(**prompts + plen, msg, len - plen);			plen += mlen;			**echo_on = (type == PAM_PROMPT_ECHO_ON);			xfree(msg);			return (0);		case PAM_ERROR_MSG:		case PAM_TEXT_INFO:			/* accumulate messages */			len = plen + mlen + 2;			**prompts = xrealloc(**prompts, len);			strlcpy(**prompts + plen, msg, len - plen);			plen += mlen;			strlcat(**prompts + plen, "\n", len - plen);			plen++;			xfree(msg);			break;		case PAM_SUCCESS:		case PAM_AUTH_ERR:			if (**prompts != NULL) {				/* drain any accumulated messages */				debug("PAM: %s", **prompts);				buffer_append(&loginmsg, **prompts,				    strlen(**prompts));				xfree(**prompts);				**prompts = NULL;			}			if (type == PAM_SUCCESS) {				if (!sshpam_authctxt->valid ||				    (sshpam_authctxt->pw->pw_uid == 0 &&				    options.permit_root_login != PERMIT_YES))					fatal("Internal error: PAM auth "					    "succeeded when it should have "					    "failed");				import_environments(&buffer);				*num = 0;				**echo_on = 0;				ctxt->pam_done = 1;				xfree(msg);				return (0);			}			error("PAM: %s for %s%.100s from %.100s", msg,			    sshpam_authctxt->valid ? "" : "illegal user ",			    sshpam_authctxt->user,			    get_remote_name_or_ip(utmp_len, options.use_dns));			/* FALLTHROUGH */		default:			*num = 0;			**echo_on = 0;			xfree(msg);			ctxt->pam_done = -1;			return (-1);		}	}	return (-1);}/* XXX - see also comment in auth-chall.c:verify_response */static intsshpam_respond(void *ctx, u_int num, char **resp){	Buffer buffer;	struct pam_ctxt *ctxt = ctx;	debug2("PAM: %s entering, %d responses", __func__, num);	switch (ctxt->pam_done) {	case 1:		sshpam_authenticated = 1;		return (0);	case 0:		break;	default:		return (-1);	}	if (num != 1) {		error("PAM: expected one response, got %u", num);		return (-1);	}	buffer_init(&buffer);	if (sshpam_authctxt->valid &&	    (sshpam_authctxt->pw->pw_uid != 0 ||	     options.permit_root_login == PERMIT_YES))		buffer_put_cstring(&buffer, *resp);	else		buffer_put_cstring(&buffer, badpw);	if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) {		buffer_free(&buffer);		return (-1);	}	buffer_free(&buffer);	return (1);}static voidsshpam_free_ctx(void *ctxtp){	struct pam_ctxt *ctxt = ctxtp;	debug3("PAM: %s entering", __func__);	sshpam_thread_cleanup();	xfree(ctxt);	/*	 * We don't call sshpam_cleanup() here because we may need the PAM	 * handle at a later stage, e.g. when setting up a session.  It's	 * still on the cleanup list, so pam_end() *will* be called before	 * the server process terminates.	 */}KbdintDevice sshpam_device = {	"pam",	sshpam_init_ctx,	sshpam_query,	sshpam_respond,	sshpam_free_ctx};KbdintDevice mm_sshpam_device = {	"pam",	mm_sshpam_init_ctx,	mm_sshpam_query,	mm_sshpam_respond,	mm_sshpam_free_ctx};/* * This replaces auth-pam.c */voidstart_pam(Authctxt *authctxt){	if (!options.use_pam)		fatal("PAM: initialisation requested when UsePAM=no");	if (sshpam_init(authctxt) == -1)		fatal("PAM: initialisation failed");}voidfinish_pam(void){	sshpam_cleanup();}u_intdo_pam_account(void){	debug("%s: called", __func__);	if (sshpam_account_status != -1)		return (sshpam_account_status);	sshpam_err = pam_acct_mgmt(sshpam_handle, 0);	debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err,	    pam_strerror(sshpam_handle, sshpam_err));		if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) {		sshpam_account_status = 0;		return (sshpam_account_status);	}	if (sshpam_err == PAM_NEW_AUTHTOK_REQD)		sshpam_password_change_required(1);	sshpam_account_status = 1;	return (sshpam_account_status);}voiddo_pam_set_tty(const char *tty){	if (tty != NULL) {		debug("PAM: setting PAM_TTY to \"%s\"", tty);		sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, tty);		if (sshpam_err != PAM_SUCCESS)			fatal("PAM: failed to set PAM_TTY: %s",			    pam_strerror(sshpam_handle, sshpam_err));	}}voiddo_pam_setcred(int init){	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,	    (const void *)&store_conv);	if (sshpam_err != PAM_SUCCESS)		fatal("PAM: failed to set PAM_CONV: %s",		    pam_strerror(sshpam_handle, sshpam_err));	if (init) {		debug("PAM: establishing credentials");		sshpam_err = pam_setcred(sshpam_handle, PAM_ESTABLISH_CRED);	} else {		debug("PAM: reinitializing credentials");		sshpam_err = pam_setcred(sshpam_handle, PAM_REINITIALIZE_CRED);	}	if (sshpam_err == PAM_SUCCESS) {		sshpam_cred_established = 1;		return;	}	if (sshpam_authenticated)		fatal("PAM: pam_setcred(): %s",		    pam_strerror(sshpam_handle, sshpam_err));	else		debug("PAM: pam_setcred(): %s",		    pam_strerror(sshpam_handle, sshpam_err));}static intsshpam_tty_conv(int n, struct pam_message **msg,    struct pam_response **resp, void *data){	char input[PAM_MAX_MSG_SIZE];	struct pam_response *reply;	int i;	debug3("PAM: %s called with %d messages", __func__, n);	*resp = NULL;	if (n <= 0 || n > PAM_MAX_NUM_MSG || !isatty(STDIN_FILENO))		return (PAM_CONV_ERR);	if ((reply = malloc(n * sizeof(*reply))) == NULL)		return (PAM_CONV_ERR);	memset(reply, 0, n * sizeof(*reply));	for (i = 0; i < n; ++i) {		switch (PAM_MSG_MEMBER(msg, i, msg_style)) {		case PAM_PROMPT_ECHO_OFF:			reply[i].resp =			    read_passphrase(PAM_MSG_MEMBER(msg, i, msg),			    RP_ALLOW_STDIN);			reply[i].resp_retcode = PAM_SUCCESS;			break;		case PAM_PROMPT_ECHO_ON:			fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg));			fgets(input, sizeof input, stdin);			if ((reply[i].resp = strdup(input)) == NULL)				goto fail;			reply[i].resp_retcode = PAM_SUCCESS;			break;		case PAM_ERROR_MSG:		case PAM_TEXT_INFO:			fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg));			reply[i].resp_retcode = PAM_SUCCESS;			break;		default:			goto fail;		}	}	*resp = reply;	return (PAM_SUCCESS); fail:	for(i = 0; i < n; i++) {		if (reply[i].resp != NULL)			xfree(reply[i].resp);	}	xfree(reply);	return (PAM_CONV_ERR);}static struct pam_conv tty_conv = { sshpam_tty_conv, NULL };/* * XXX this should be done in the authentication phase, but ssh1 doesn't * support that */voiddo_pam_chauthtok(void){	if (use_privsep)		fatal("Password expired (unable to change with privsep)");	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,	    (const void *)&tty_conv);	if (sshpam_err != PAM_SUCCESS)		fatal("PAM: failed to set PAM_CONV: %s",		    pam_strerror(sshpam_handle, sshpam_err));	debug("PAM: changing password");	sshpam_err = pam_chauthtok(sshpam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);	if (sshpam_err != PAM_SUCCESS)		fatal("PAM: pam_chauthtok(): %s",		    pam_strerror(sshpam_handle, sshpam_err));}voiddo_pam_session(void){	debug3("PAM: opening session");	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,	    (const void *)&store_conv);	if (sshpam_err != PAM_SUCCESS)		fatal("PAM: failed to set PAM_CONV: %s",		    pam_strerror(sshpam_handle, sshpam_err));	sshpam_err = pam_open_session(sshpam_handle, 0);	if (sshpam_err == PAM_SUCCESS)		sshpam_session_open = 1;	else {		sshpam_session_open = 0;		disable_forwarding();		error("PAM: pam_open_session(): %s",		    pam_strerror(sshpam_handle, sshpam_err));	}}intis_pam_session_open(void){	return sshpam_session_open;}/* * Set a PAM environment string. We need to do this so that the session * modules can handle things like Kerberos/GSI credentials that appear * during the ssh authentication process. */intdo_pam_putenv(char *name, char *value){	int ret = 1;#ifdef HAVE_PAM_PUTENV	char *compound;	size_t len;	len = strlen(name) + strlen(value) + 2;	compound = xmalloc(len);	snprintf(compound, len, "%s=%s", name, value);	ret = pam_putenv(sshpam_handle, compound);	xfree(compound);#endif	return (ret);}char **fetch_pam_child_environment(void){	return sshpam_env;}char **fetch_pam_environment(void){	return (pam_getenvlist(sshpam_handle));}voidfree_pam_environment(char **env){	char **envp;	if (env == NULL)		return;	for (envp = env; *envp; envp++)		xfree(*envp);	xfree(env);}/* * "Blind" conversation function for password authentication.  Assumes that * echo-off prompts are for the password and stores messages for later * display. */static intsshpam_passwd_conv(int n, struct pam_message **msg,    struct pam_response **resp, void *data){	struct pam_response *reply;	int i;	size_t len;	debug3("PAM: %s called with %d messages", __func__, n);	*resp = NULL;	if (n <= 0 || n > PAM_MAX_NUM_MSG)		return (PAM_CONV_ERR);	if ((reply = malloc(n * sizeof(*reply))) == NULL)		return (PAM_CONV_ERR);	memset(reply, 0, n * sizeof(*reply));	for (i = 0; i < n; ++i) {		switch (PAM_MSG_MEMBER(msg, i, msg_style)) {		case PAM_PROMPT_ECHO_OFF:			if (sshpam_password == NULL)				goto fail;			if ((reply[i].resp = strdup(sshpam_password)) == NULL)				goto fail;			reply[i].resp_retcode = PAM_SUCCESS;			break;		case PAM_ERROR_MSG:		case PAM_TEXT_INFO:			len = strlen(PAM_MSG_MEMBER(msg, i, msg));			if (len > 0) {				buffer_append(&loginmsg,				    PAM_MSG_MEMBER(msg, i, msg), len);				buffer_append(&loginmsg, "\n", 1);			}			if ((reply[i].resp = strdup("")) == NULL)				goto fail;			reply[i].resp_retcode = PAM_SUCCESS;			break;		default:			goto fail;		}	}	*resp = reply;	return (PAM_SUCCESS); fail: 	for(i = 0; i < n; i++) {		if (reply[i].resp != NULL)			xfree(reply[i].resp);	}	xfree(reply);	return (PAM_CONV_ERR);}static struct pam_conv passwd_conv = { sshpam_passwd_conv, NULL };/* * Attempt password authentication via PAM */intsshpam_auth_passwd(Authctxt *authctxt, const char *password){	int flags = (options.permit_empty_passwd == 0 ?	    PAM_DISALLOW_NULL_AUTHTOK : 0);	if (!options.use_pam || sshpam_handle == NULL)		fatal("PAM: %s called when PAM disabled or failed to "		    "initialise.", __func__);	sshpam_password = password;	sshpam_authctxt = authctxt;	/*	 * If the user logging in is invalid, or is root but is not permitted	 * by PermitRootLogin, use an invalid password to prevent leaking	 * information via timing (eg if the PAM config has a delay on fail).	 */	if (!authctxt->valid || (authctxt->pw->pw_uid == 0 &&	     options.permit_root_login != PERMIT_YES))		sshpam_password = badpw;	sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,	    (const void *)&passwd_conv);	if (sshpam_err != PAM_SUCCESS)		fatal("PAM: %s: failed to set PAM_CONV: %s", __func__,		    pam_strerror(sshpam_handle, sshpam_err));	sshpam_err = pam_authenticate(sshpam_handle, flags);	sshpam_password = NULL;	if (sshpam_err == PAM_SUCCESS && authctxt->valid) {		debug("PAM: password authentication accepted for %.100s",		    authctxt->user);               return 1;	} else {		debug("PAM: password authentication failed for %.100s: %s",		    authctxt->valid ? authctxt->user : "an illegal user",		    pam_strerror(sshpam_handle, sshpam_err));		return 0;	}}#endif /* USE_PAM */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -