mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-03 23:47:16 +00:00 
			
		
		
		
	Code was was written where the pam error message put out was the result from a previous call to the pam modules instead of the current call to the pam module. Signed-off-by: Donald Sharp <sharpd@nvidia.com>
		
			
				
	
	
		
			221 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			221 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
						|
/* User authentication for vtysh.
 | 
						|
 * Copyright (C) 2000 Kunihiro Ishiguro
 | 
						|
 */
 | 
						|
 | 
						|
#include <zebra.h>
 | 
						|
#include <lib/version.h>
 | 
						|
 | 
						|
#include <pwd.h>
 | 
						|
 | 
						|
#ifdef USE_PAM
 | 
						|
#include <security/pam_appl.h>
 | 
						|
#ifdef HAVE_PAM_MISC_H
 | 
						|
#include <security/pam_misc.h>
 | 
						|
#endif
 | 
						|
#ifdef HAVE_OPENPAM_H
 | 
						|
#include <security/openpam.h>
 | 
						|
#endif
 | 
						|
#endif /* USE_PAM */
 | 
						|
 | 
						|
#include "memory.h"
 | 
						|
#include "linklist.h"
 | 
						|
#include "command.h"
 | 
						|
#include "vtysh/vtysh_user.h"
 | 
						|
 | 
						|
/*
 | 
						|
 * Compiler is warning about prototypes not being declared.
 | 
						|
 * The DEFUNSH and DEFUN macro's are messing with the
 | 
						|
 * compiler I believe.  This is just to make it happy.
 | 
						|
 */
 | 
						|
#ifdef USE_PAM
 | 
						|
static int vtysh_pam(const char *);
 | 
						|
#endif
 | 
						|
int vtysh_auth(void);
 | 
						|
void vtysh_user_init(void);
 | 
						|
 | 
						|
extern struct list *config_top;
 | 
						|
extern void config_add_line(struct list *config, const char *line);
 | 
						|
 | 
						|
#ifdef USE_PAM
 | 
						|
static struct pam_conv conv = {PAM_CONV_FUNC, NULL};
 | 
						|
 | 
						|
static int vtysh_pam(const char *user)
 | 
						|
{
 | 
						|
	int ret, second_ret;
 | 
						|
	pam_handle_t *pamh = NULL;
 | 
						|
 | 
						|
	/* Start PAM. */
 | 
						|
	ret = pam_start(FRR_PAM_NAME, user, &conv, &pamh);
 | 
						|
 | 
						|
	/* Is user really user? */
 | 
						|
	if (ret == PAM_SUCCESS)
 | 
						|
		ret = pam_authenticate(pamh, 0);
 | 
						|
 | 
						|
	if (ret != PAM_SUCCESS)
 | 
						|
		fprintf(stderr, "vtysh_pam: Failure to initialize pam: %s(%d)",
 | 
						|
			pam_strerror(pamh, ret), ret);
 | 
						|
 | 
						|
	second_ret = pam_acct_mgmt(pamh, 0);
 | 
						|
	if (second_ret != PAM_SUCCESS)
 | 
						|
		fprintf(stderr, "%s: Failed in account validation: %s(%d)",
 | 
						|
			__func__, pam_strerror(pamh, second_ret), second_ret);
 | 
						|
 | 
						|
	/* close Linux-PAM */
 | 
						|
	second_ret = pam_end(pamh, ret);
 | 
						|
	if (second_ret != PAM_SUCCESS) {
 | 
						|
		pamh = NULL;
 | 
						|
		fprintf(stderr,
 | 
						|
			"vtysh_pam: failed to release authenticator: %s(%d)\n",
 | 
						|
			pam_strerror(pamh, second_ret), second_ret);
 | 
						|
		exit(1);
 | 
						|
	}
 | 
						|
 | 
						|
	return ret == PAM_SUCCESS ? 0 : 1;
 | 
						|
}
 | 
						|
#endif /* USE_PAM */
 | 
						|
 | 
						|
struct vtysh_user {
 | 
						|
	char *name;
 | 
						|
	uint8_t nopassword;
 | 
						|
};
 | 
						|
 | 
						|
struct list *userlist;
 | 
						|
 | 
						|
static struct vtysh_user *user_new(void)
 | 
						|
{
 | 
						|
	return XCALLOC(MTYPE_TMP, sizeof(struct vtysh_user));
 | 
						|
}
 | 
						|
 | 
						|
static struct vtysh_user *user_lookup(const char *name)
 | 
						|
{
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct vtysh_user *user;
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(userlist, node, nnode, user)) {
 | 
						|
		if (strcmp(user->name, name) == 0)
 | 
						|
			return user;
 | 
						|
	}
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
void user_config_write(void)
 | 
						|
{
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct vtysh_user *user;
 | 
						|
	char line[128];
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(userlist, node, nnode, user)) {
 | 
						|
		if (user->nopassword) {
 | 
						|
			snprintf(line, sizeof(line), "username %s nopassword",
 | 
						|
				 user->name);
 | 
						|
			config_add_line(config_top, line);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static struct vtysh_user *user_get(const char *name)
 | 
						|
{
 | 
						|
	struct vtysh_user *user;
 | 
						|
	user = user_lookup(name);
 | 
						|
	if (user)
 | 
						|
		return user;
 | 
						|
 | 
						|
	user = user_new();
 | 
						|
	user->name = strdup(name);
 | 
						|
	listnode_add(userlist, user);
 | 
						|
 | 
						|
	return user;
 | 
						|
}
 | 
						|
 | 
						|
DEFUN (vtysh_banner_motd_file,
 | 
						|
       vtysh_banner_motd_file_cmd,
 | 
						|
       "banner motd file FILE",
 | 
						|
       "Set banner\n"
 | 
						|
       "Banner for motd\n"
 | 
						|
       "Banner from a file\n"
 | 
						|
       "Filename\n")
 | 
						|
{
 | 
						|
	int idx_file = 3;
 | 
						|
	return cmd_banner_motd_file(argv[idx_file]->arg);
 | 
						|
}
 | 
						|
 | 
						|
DEFUN (vtysh_banner_motd_line,
 | 
						|
       vtysh_banner_motd_line_cmd,
 | 
						|
       "banner motd line LINE...",
 | 
						|
       "Set banner\n"
 | 
						|
       "Banner for motd\n"
 | 
						|
       "Banner from an input\n"
 | 
						|
       "Text\n")
 | 
						|
{
 | 
						|
	int idx = 0;
 | 
						|
	char *motd;
 | 
						|
 | 
						|
	argv_find(argv, argc, "LINE", &idx);
 | 
						|
	motd = argv_concat(argv, argc, idx);
 | 
						|
 | 
						|
	cmd_banner_motd_line(motd);
 | 
						|
	XFREE(MTYPE_TMP, motd);
 | 
						|
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
DEFUN (username_nopassword,
 | 
						|
       username_nopassword_cmd,
 | 
						|
       "username WORD nopassword",
 | 
						|
       "\n"
 | 
						|
       "\n"
 | 
						|
       "\n")
 | 
						|
{
 | 
						|
	int idx_word = 1;
 | 
						|
	struct vtysh_user *user;
 | 
						|
	user = user_get(argv[idx_word]->arg);
 | 
						|
	user->nopassword = 1;
 | 
						|
	return CMD_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
int vtysh_auth(void)
 | 
						|
{
 | 
						|
	struct vtysh_user *user;
 | 
						|
	struct passwd *passwd;
 | 
						|
 | 
						|
	if ((passwd = getpwuid(geteuid())) == NULL) {
 | 
						|
		fprintf(stderr, "could not lookup user ID %d\n",
 | 
						|
			(int)geteuid());
 | 
						|
		exit(1);
 | 
						|
	}
 | 
						|
 | 
						|
	user = user_lookup(passwd->pw_name);
 | 
						|
	if (user && user->nopassword)
 | 
						|
		/* Pass through */;
 | 
						|
	else {
 | 
						|
#ifdef USE_PAM
 | 
						|
		if (vtysh_pam(passwd->pw_name))
 | 
						|
			exit(0);
 | 
						|
#endif /* USE_PAM */
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
char *vtysh_get_home(void)
 | 
						|
{
 | 
						|
	struct passwd *passwd;
 | 
						|
	char *homedir;
 | 
						|
 | 
						|
	if ((homedir = getenv("HOME")) != NULL)
 | 
						|
		return homedir;
 | 
						|
 | 
						|
	/* Fallback if HOME is undefined */
 | 
						|
	passwd = getpwuid(getuid());
 | 
						|
 | 
						|
	return passwd ? passwd->pw_dir : NULL;
 | 
						|
}
 | 
						|
 | 
						|
void vtysh_user_init(void)
 | 
						|
{
 | 
						|
	userlist = list_new();
 | 
						|
	install_element(CONFIG_NODE, &username_nopassword_cmd);
 | 
						|
	install_element(CONFIG_NODE, &vtysh_banner_motd_file_cmd);
 | 
						|
	install_element(CONFIG_NODE, &vtysh_banner_motd_line_cmd);
 | 
						|
}
 |