#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <libinetutil.h>
#include "ndmpd.h"
#include "ndmpd_common.h"
#define NDMP_PROC_ERR -1
#define NDMP_PROC_MSG 1
#define NDMP_PROC_REP 0
#define NDMP_PROC_REP_ERR 2
int ndmp_ver = 0;
int ndmp_port = 0;
int ndmp_full_restore_path = 1;
int ndmp_dar_support = 0;
static ndmpd_file_handler_func_t connection_file_handler;
extern ndmp_handler_t ndmp_msghdl_tab[];
static int ndmp_readit(void *connection_handle,
caddr_t buf,
int len);
static int ndmp_writeit(void *connection_handle,
caddr_t buf,
int len);
static int ndmp_recv_msg(ndmp_connection_t *connection);
static int ndmp_process_messages(ndmp_connection_t *connection,
boolean_t reply_expected);
static ndmp_msg_handler_t *ndmp_get_handler(ndmp_connection_t *connection,
ndmp_message message);
static boolean_t ndmp_check_auth_required(ndmp_message message);
static ndmp_handler_t *ndmp_get_interface(ndmp_message message);
void *ndmpd_worker(void *ptarg);
#ifdef lint
bool_t
xdr_ndmp_header(XDR *xdrs, ndmp_header *objp)
{
xdrs = xdrs;
objp = objp;
return (0);
}
#endif
ndmp_connection_t *
ndmp_create_connection(void)
{
ndmp_connection_t *connection;
connection = ndmp_malloc(sizeof (ndmp_connection_t));
if (connection == NULL)
return (NULL);
connection->conn_sock = -1;
connection->conn_my_sequence = 0;
connection->conn_authorized = FALSE;
connection->conn_eof = FALSE;
connection->conn_msginfo.mi_body = 0;
connection->conn_version = ndmp_ver;
connection->conn_client_data = 0;
(void) mutex_init(&connection->conn_lock, 0, NULL);
connection->conn_xdrs.x_ops = 0;
xdrrec_create(&connection->conn_xdrs, 0, 0, (caddr_t)connection,
ndmp_readit, ndmp_writeit);
if (connection->conn_xdrs.x_ops == 0) {
NDMP_LOG(LOG_DEBUG, "xdrrec_create failed");
(void) mutex_destroy(&connection->conn_lock);
(void) close(connection->conn_sock);
free(connection);
return (0);
}
return ((ndmp_connection_t *)connection);
}
void
ndmp_destroy_connection(ndmp_connection_t *connection_handle)
{
ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
if (connection->conn_sock >= 0) {
(void) mutex_destroy(&connection->conn_lock);
(void) close(connection->conn_sock);
connection->conn_sock = -1;
}
xdr_destroy(&connection->conn_xdrs);
free(connection);
}
void
ndmp_close(ndmp_connection_t *connection_handle)
{
ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
ndmpd_audit_disconnect(connection);
if (connection->conn_sock >= 0) {
(void) mutex_destroy(&connection->conn_lock);
(void) close(connection->conn_sock);
connection->conn_sock = -1;
}
connection->conn_eof = TRUE;
ndmp_open_list_release(connection_handle);
}
int
ndmp_start_worker(ndmpd_worker_arg_t *argp)
{
pthread_attr_t tattr;
int rc;
(void) pthread_attr_init(&tattr);
(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
rc = pthread_create(NULL, &tattr, ndmpd_worker, (void *)argp);
(void) pthread_attr_destroy(&tattr);
return (rc);
}
int
ndmp_run(ulong_t port, ndmp_con_handler_func_t con_handler_func)
{
int ns;
int on;
int server_socket;
unsigned int ipaddr;
struct sockaddr_in sin;
ndmpd_worker_arg_t *argp;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(port);
if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
NDMP_LOG(LOG_DEBUG, "Socket error: %m");
return (-1);
}
on = 1;
(void) setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof (on));
if (bind(server_socket, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
NDMP_LOG(LOG_DEBUG, "bind error: %m");
(void) close(server_socket);
return (-1);
}
if (listen(server_socket, 5) < 0) {
NDMP_LOG(LOG_DEBUG, "listen error: %m");
(void) close(server_socket);
return (-1);
}
for (; ; ) {
if ((ns = tcp_accept(server_socket, &ipaddr)) < 0) {
NDMP_LOG(LOG_DEBUG, "tcp_accept error: %m");
continue;
}
NDMP_LOG(LOG_DEBUG, "connection fd: %d", ns);
set_socket_options(ns);
if ((argp = ndmp_malloc(sizeof (ndmpd_worker_arg_t))) != NULL) {
argp->nw_sock = ns;
argp->nw_ipaddr = ipaddr;
argp->nw_con_handler_func = con_handler_func;
(void) ndmp_start_worker(argp);
}
}
}
void *
ndmpd_worker(void *ptarg)
{
int sock;
ndmp_connection_t *connection;
ndmpd_worker_arg_t *argp = (ndmpd_worker_arg_t *)ptarg;
if (!argp)
return ((void *)-1);
NS_INC(trun);
sock = argp->nw_sock;
if ((connection = ndmp_create_connection()) == NULL) {
(void) close(sock);
free(argp);
exit(1);
}
if (adt_start_session(&connection->conn_ah, NULL, 0) != 0) {
free(argp);
return ((void *)-1);
}
((ndmp_connection_t *)connection)->conn_sock = sock;
(*argp->nw_con_handler_func)(connection);
(void) adt_end_session(connection->conn_ah);
ndmp_destroy_connection(connection);
NS_DEC(trun);
free(argp);
return (NULL);
}
int
ndmp_process_requests(ndmp_connection_t *connection_handle)
{
int rv;
ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
(void) mutex_lock(&connection->conn_lock);
rv = 0;
if (ndmp_process_messages(connection, FALSE) < 0)
rv = -1;
(void) mutex_unlock(&connection->conn_lock);
return (rv);
}
int
ndmp_send_request(ndmp_connection_t *connection_handle, ndmp_message message,
ndmp_error err, void *request_data, void **reply)
{
ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
ndmp_header header;
ndmp_msg_handler_t *handler;
int r;
struct timeval time;
if (!(handler = ndmp_get_handler(connection, message))) {
NDMP_LOG(LOG_DEBUG, "Sending message 0x%x: not supported",
message);
return (-1);
}
(void) gettimeofday(&time, 0);
header.sequence = ++(connection->conn_my_sequence);
header.time_stamp = time.tv_sec;
header.message_type = NDMP_MESSAGE_REQUEST;
header.message = message;
header.reply_sequence = 0;
header.error = err;
connection->conn_xdrs.x_op = XDR_ENCODE;
if (!xdr_ndmp_header(&connection->conn_xdrs, &header)) {
NDMP_LOG(LOG_DEBUG,
"Sending message 0x%x: encoding request header", message);
(void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
return (-1);
}
if (err == NDMP_NO_ERR && handler->mh_xdr_request && request_data) {
if (!(*handler->mh_xdr_request)(&connection->conn_xdrs,
request_data)) {
NDMP_LOG(LOG_DEBUG,
"Sending message 0x%x: encoding request body",
message);
(void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
return (-1);
}
}
(void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
if (handler->mh_xdr_reply == 0) {
NDMP_LOG(LOG_DEBUG, "handler->mh_xdr_reply == 0");
return (0);
}
for (; ; ) {
r = ndmp_process_messages(connection, TRUE);
if (r < 0)
return (-1);
if (r == 0)
continue;
if (r == 1) {
if (message !=
connection->conn_msginfo.mi_hdr.message) {
NDMP_LOG(LOG_DEBUG,
"Received unexpected reply 0x%x",
connection->conn_msginfo.mi_hdr.message);
ndmp_free_message(connection_handle);
return (-1);
}
if (reply != NULL)
*reply = connection->conn_msginfo.mi_body;
else
ndmp_free_message(connection_handle);
return (connection->conn_msginfo.mi_hdr.error);
}
return (-1);
}
}
int
ndmp_send_request_lock(ndmp_connection_t *connection_handle,
ndmp_message message, ndmp_error err, void *request_data, void **reply)
{
int rv;
ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
(void) mutex_lock(&connection->conn_lock);
rv = ndmp_send_request(connection_handle, message, err, request_data,
reply);
(void) mutex_unlock(&connection->conn_lock);
return (rv);
}
int
ndmp_send_response(ndmp_connection_t *connection_handle, ndmp_error err,
void *reply)
{
ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
ndmp_header header;
struct timeval time;
(void) gettimeofday(&time, 0);
header.sequence = ++(connection->conn_my_sequence);
header.time_stamp = time.tv_sec;
header.message_type = NDMP_MESSAGE_REPLY;
header.message = connection->conn_msginfo.mi_hdr.message;
header.reply_sequence = connection->conn_msginfo.mi_hdr.sequence;
header.error = err;
connection->conn_xdrs.x_op = XDR_ENCODE;
if (!xdr_ndmp_header(&connection->conn_xdrs, &header)) {
NDMP_LOG(LOG_DEBUG, "Sending message 0x%x: "
"encoding reply header",
header.message);
(void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
return (-1);
}
if (err == NDMP_NO_ERR &&
connection->conn_msginfo.mi_handler->mh_xdr_reply &&
reply) {
if (!(*connection->conn_msginfo.mi_handler->mh_xdr_reply)(
&connection->conn_xdrs, reply)) {
NDMP_LOG(LOG_DEBUG,
"Sending message 0x%x: encoding reply body",
header.message);
(void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
return (-1);
}
}
(void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
return (0);
}
void
ndmp_free_message(ndmp_connection_t *connection_handle)
{
ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
if (connection->conn_msginfo.mi_handler == NULL ||
connection->conn_msginfo.mi_body == NULL)
return;
connection->conn_xdrs.x_op = XDR_FREE;
if (connection->conn_msginfo.mi_hdr.message_type ==
NDMP_MESSAGE_REQUEST) {
if (connection->conn_msginfo.mi_handler->mh_xdr_request)
(*connection->conn_msginfo.mi_handler->mh_xdr_request)(
&connection->conn_xdrs,
connection->conn_msginfo.mi_body);
} else {
if (connection->conn_msginfo.mi_handler->mh_xdr_reply)
(*connection->conn_msginfo.mi_handler->mh_xdr_reply)(
&connection->conn_xdrs,
connection->conn_msginfo.mi_body);
}
(void) free(connection->conn_msginfo.mi_body);
connection->conn_msginfo.mi_body = 0;
}
int
ndmp_get_fd(ndmp_connection_t *connection_handle)
{
return (((ndmp_connection_t *)connection_handle)->conn_sock);
}
void
ndmp_set_client_data(ndmp_connection_t *connection_handle, void *client_data)
{
((ndmp_connection_t *)connection_handle)->conn_client_data =
client_data;
}
void *
ndmp_get_client_data(ndmp_connection_t *connection_handle)
{
return (((ndmp_connection_t *)connection_handle)->conn_client_data);
}
void
ndmp_set_version(ndmp_connection_t *connection_handle, ushort_t version)
{
((ndmp_connection_t *)connection_handle)->conn_version = version;
}
ushort_t
ndmp_get_version(ndmp_connection_t *connection_handle)
{
return (((ndmp_connection_t *)connection_handle)->conn_version);
}
void
ndmp_set_authorized(ndmp_connection_t *connection_handle, boolean_t authorized)
{
((ndmp_connection_t *)connection_handle)->conn_authorized = authorized;
}
void
ndmpd_main(void)
{
char *propval;
ndmp_load_params();
if (ndmp_port == 0) {
if ((propval = ndmpd_get_prop(NDMP_TCP_PORT)) == NULL ||
*propval == 0)
ndmp_port = NDMPPORT;
else
ndmp_port = strtol(propval, 0, 0);
}
if (ndmp_run(ndmp_port, connection_handler) == -1)
perror("ndmp_run ERROR");
}
void
connection_handler(ndmp_connection_t *connection)
{
static int conn_id = 1;
ndmpd_session_t session;
ndmp_notify_connected_request req;
int connection_fd;
(void) memset(&session, 0, sizeof (session));
session.ns_connection = connection;
session.ns_eof = FALSE;
session.ns_protocol_version = ndmp_ver;
session.ns_scsi.sd_is_open = -1;
session.ns_scsi.sd_devid = -1;
session.ns_scsi.sd_sid = 0;
session.ns_scsi.sd_lun = 0;
session.ns_scsi.sd_valid_target_set = 0;
(void) memset(session.ns_scsi.sd_adapter_name, 0,
sizeof (session.ns_scsi.sd_adapter_name));
session.ns_tape.td_fd = -1;
session.ns_tape.td_sid = 0;
session.ns_tape.td_lun = 0;
(void) memset(session.ns_tape.td_adapter_name, 0,
sizeof (session.ns_tape.td_adapter_name));
session.ns_tape.td_pos = 0;
session.ns_tape.td_record_count = 0;
session.ns_file_handler_list = 0;
(void) ndmpd_data_init(&session);
ndmpd_file_history_init(&session);
if (ndmpd_mover_init(&session) < 0)
return;
if (ndmp_lbr_init(&session) < 0)
return;
session.ns_mover.md_record_size = MAX_RECORD_SIZE;
ndmp_set_client_data(connection, (void *)&session);
req.reason = NDMP_CONNECTED;
req.protocol_version = ndmp_ver;
req.text_reason = "";
if (ndmp_send_request_lock(connection, NDMP_NOTIFY_CONNECTION_STATUS,
NDMP_NO_ERR, (void *)&req, 0) < 0) {
NDMP_LOG(LOG_DEBUG, "Connection terminated");
return;
}
connection_fd = ndmp_get_fd(connection);
NDMP_LOG(LOG_DEBUG, "connection_fd: %d", connection_fd);
if (ndmpd_add_file_handler(&session, (void *)&session, connection_fd,
NDMPD_SELECT_MODE_READ, HC_CLIENT, connection_file_handler) != 0) {
NDMP_LOG(LOG_DEBUG, "Could not register session handler.");
return;
}
if (ndmp_connect_list_add(connection, &conn_id) != 0) {
NDMP_LOG(LOG_ERR,
"Could not register the session to the server.");
(void) ndmpd_remove_file_handler(&session, connection_fd);
return;
}
session.hardlink_q = hardlink_q_init();
while (session.ns_eof == FALSE)
(void) ndmpd_select(&session, TRUE, HC_ALL);
hardlink_q_cleanup(session.hardlink_q);
NDMP_LOG(LOG_DEBUG, "Connection terminated");
(void) ndmpd_remove_file_handler(&session, connection_fd);
if (session.ns_scsi.sd_is_open != -1) {
NDMP_LOG(LOG_DEBUG, "scsi.is_open: %d",
session.ns_scsi.sd_is_open);
(void) ndmp_open_list_del(session.ns_scsi.sd_adapter_name,
session.ns_scsi.sd_sid, session.ns_scsi.sd_lun);
}
if (session.ns_tape.td_fd != -1) {
NDMP_LOG(LOG_DEBUG, "tape.fd: %d", session.ns_tape.td_fd);
(void) close(session.ns_tape.td_fd);
(void) ndmp_open_list_del(session.ns_tape.td_adapter_name,
session.ns_tape.td_sid, session.ns_tape.td_lun);
}
ndmpd_mover_shut_down(&session);
ndmp_lbr_cleanup(&session);
ndmpd_data_cleanup(&session);
ndmpd_file_history_cleanup(&session, FALSE);
ndmpd_mover_cleanup(&session);
(void) ndmp_connect_list_del(connection);
}
static void
connection_file_handler(void *cookie, int fd, ulong_t mode)
{
ndmpd_session_t *session = (ndmpd_session_t *)cookie;
if (ndmp_process_requests(session->ns_connection) < 0)
session->ns_eof = TRUE;
}
static int
ndmp_readit(void *connection_handle, caddr_t buf, int len)
{
ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
len = read(connection->conn_sock, buf, len);
if (len <= 0) {
connection->conn_eof = TRUE;
return (-1);
}
return (len);
}
static int
ndmp_writeit(void *connection_handle, caddr_t buf, int len)
{
ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
register int n;
register int cnt;
for (cnt = len; cnt > 0; cnt -= n, buf += n) {
if ((n = write(connection->conn_sock, buf, cnt)) < 0) {
connection->conn_eof = TRUE;
return (-1);
}
}
return (len);
}
static int
ndmp_recv_msg(ndmp_connection_t *connection)
{
bool_t(*xdr_func) (XDR *, ...) = NULL;
connection->conn_xdrs.x_op = XDR_DECODE;
(void) xdrrec_skiprecord(&connection->conn_xdrs);
if (!xdr_ndmp_header(&connection->conn_xdrs,
&connection->conn_msginfo.mi_hdr))
return (-1);
if ((connection->conn_msginfo.mi_handler = ndmp_get_handler(connection,
connection->conn_msginfo.mi_hdr.message)) == 0) {
NDMP_LOG(LOG_DEBUG, "Message 0x%x not supported",
connection->conn_msginfo.mi_hdr.message);
return (NDMP_NOT_SUPPORTED_ERR);
}
connection->conn_msginfo.mi_body = 0;
if (connection->conn_msginfo.mi_hdr.error != NDMP_NO_ERR)
return (0);
if (connection->conn_msginfo.mi_hdr.message_type ==
NDMP_MESSAGE_REQUEST) {
if (ndmp_check_auth_required(
connection->conn_msginfo.mi_hdr.message) &&
!connection->conn_authorized) {
NDMP_LOG(LOG_DEBUG,
"Processing request 0x%x:connection not authorized",
connection->conn_msginfo.mi_hdr.message);
return (NDMP_NOT_AUTHORIZED_ERR);
}
if (connection->conn_msginfo.mi_handler->mh_sizeof_request >
0) {
xdr_func =
connection->conn_msginfo.mi_handler->mh_xdr_request;
if (xdr_func == NULL) {
NDMP_LOG(LOG_DEBUG,
"Processing request 0x%x: no xdr function "
"in handler table",
connection->conn_msginfo.mi_hdr.message);
return (NDMP_NOT_SUPPORTED_ERR);
}
connection->conn_msginfo.mi_body = ndmp_malloc(
connection->conn_msginfo.mi_handler->
mh_sizeof_request);
if (connection->conn_msginfo.mi_body == NULL)
return (NDMP_NO_MEM_ERR);
(void) memset(connection->conn_msginfo.mi_body, 0,
connection->conn_msginfo.mi_handler->
mh_sizeof_request);
}
} else {
if (connection->conn_msginfo.mi_handler->mh_sizeof_reply > 0) {
xdr_func =
connection->conn_msginfo.mi_handler->mh_xdr_reply;
if (xdr_func == NULL) {
NDMP_LOG(LOG_DEBUG,
"Processing reply 0x%x: no xdr function "
"in handler table",
connection->conn_msginfo.mi_hdr.message);
return (NDMP_NOT_SUPPORTED_ERR);
}
connection->conn_msginfo.mi_body = ndmp_malloc(
connection->conn_msginfo.mi_handler->
mh_sizeof_reply);
if (connection->conn_msginfo.mi_body == NULL)
return (NDMP_NO_MEM_ERR);
(void) memset(connection->conn_msginfo.mi_body, 0,
connection->conn_msginfo.mi_handler->
mh_sizeof_reply);
}
}
if (xdr_func) {
if (!(*xdr_func)(&connection->conn_xdrs,
connection->conn_msginfo.mi_body)) {
NDMP_LOG(LOG_DEBUG,
"Processing message 0x%x: error decoding arguments",
connection->conn_msginfo.mi_hdr.message);
free(connection->conn_msginfo.mi_body);
connection->conn_msginfo.mi_body = 0;
return (NDMP_XDR_DECODE_ERR);
}
}
return (0);
}
static int
ndmp_process_messages(ndmp_connection_t *connection, boolean_t reply_expected)
{
msg_info_t reply_msginfo;
boolean_t reply_read = FALSE;
boolean_t reply_error = FALSE;
int err;
NDMP_LOG(LOG_DEBUG, "reply_expected: %s",
reply_expected == TRUE ? "TRUE" : "FALSE");
(void) memset((void *)&reply_msginfo, 0, sizeof (msg_info_t));
do {
(void) memset((void *)&connection->conn_msginfo, 0,
sizeof (msg_info_t));
if ((err = ndmp_recv_msg(connection)) != NDMP_NO_ERR) {
if (connection->conn_eof) {
NDMP_LOG(LOG_DEBUG, "detected eof");
return (NDMP_PROC_ERR);
}
if (err < 1) {
NDMP_LOG(LOG_DEBUG, "error decoding header");
if (reply_read == FALSE)
reply_error = TRUE;
continue;
}
if (connection->conn_msginfo.mi_hdr.message_type
!= NDMP_MESSAGE_REQUEST) {
NDMP_LOG(LOG_DEBUG, "received reply: 0x%x",
connection->conn_msginfo.mi_hdr.message);
if (reply_expected == FALSE ||
reply_read == TRUE)
NDMP_LOG(LOG_DEBUG,
"Unexpected reply message: 0x%x",
connection->conn_msginfo.mi_hdr.
message);
ndmp_free_message((ndmp_connection_t *)
connection);
if (reply_read == FALSE) {
reply_read = TRUE;
reply_error = TRUE;
}
continue;
}
NDMP_LOG(LOG_DEBUG, "received request: 0x%x",
connection->conn_msginfo.mi_hdr.message);
(void) ndmp_send_response((ndmp_connection_t *)
connection, err, NULL);
ndmp_free_message((ndmp_connection_t *)connection);
continue;
}
if (connection->conn_msginfo.mi_hdr.message_type
!= NDMP_MESSAGE_REQUEST) {
NDMP_LOG(LOG_DEBUG, "received reply: 0x%x",
connection->conn_msginfo.mi_hdr.message);
if (reply_expected == FALSE || reply_read == TRUE) {
NDMP_LOG(LOG_DEBUG,
"Unexpected reply message: 0x%x",
connection->conn_msginfo.mi_hdr.message);
ndmp_free_message((ndmp_connection_t *)
connection);
continue;
}
reply_read = TRUE;
reply_msginfo = connection->conn_msginfo;
continue;
}
NDMP_LOG(LOG_DEBUG, "received request: 0x%x",
connection->conn_msginfo.mi_hdr.message);
if (connection->conn_msginfo.mi_handler->mh_func == NULL) {
NDMP_LOG(LOG_DEBUG, "No handler for message 0x%x",
connection->conn_msginfo.mi_hdr.message);
(void) ndmp_send_response((ndmp_connection_t *)
connection, NDMP_NOT_SUPPORTED_ERR, NULL);
ndmp_free_message((ndmp_connection_t *)connection);
continue;
}
(*connection->conn_msginfo.mi_handler->mh_func) (connection,
connection->conn_msginfo.mi_body);
ndmp_free_message((ndmp_connection_t *)connection);
} while (xdrrec_eof(&connection->conn_xdrs) == FALSE &&
connection->conn_eof == FALSE);
NDMP_LOG(LOG_DEBUG, "no more messages in stream buffer");
if (connection->conn_eof == TRUE) {
if (reply_msginfo.mi_body)
free(reply_msginfo.mi_body);
return (NDMP_PROC_ERR);
}
if (reply_error) {
if (reply_msginfo.mi_body)
free(reply_msginfo.mi_body);
return (NDMP_PROC_REP_ERR);
}
if (reply_read) {
connection->conn_msginfo = reply_msginfo;
return (NDMP_PROC_MSG);
}
return (NDMP_PROC_REP);
}
static ndmp_handler_t *
ndmp_get_interface(ndmp_message message)
{
ndmp_handler_t *ni = &ndmp_msghdl_tab[(message >> 8) % INT_MAXCMD];
if ((message & 0xff) >= ni->hd_cnt)
return (NULL);
if (ni->hd_msgs[message & 0xff].hm_message != message)
return (NULL);
return (ni);
}
static ndmp_msg_handler_t *
ndmp_get_handler(ndmp_connection_t *connection, ndmp_message message)
{
ndmp_msg_handler_t *handler = NULL;
ndmp_handler_t *ni = ndmp_get_interface(message);
int ver = connection->conn_version;
if (ni)
handler = &ni->hd_msgs[message & 0xff].hm_msg_v[ver - 2];
return (handler);
}
static boolean_t
ndmp_check_auth_required(ndmp_message message)
{
boolean_t auth_req = FALSE;
ndmp_handler_t *ni = ndmp_get_interface(message);
if (ni)
auth_req = ni->hd_msgs[message & 0xff].hm_auth_required;
return (auth_req);
}
int
tcp_accept(int listen_sock, unsigned int *inaddr_p)
{
struct sockaddr_in sin;
int sock, i;
int try;
for (try = 0; try < 3; try++) {
i = sizeof (sin);
sock = accept(listen_sock, (struct sockaddr *)&sin, &i);
if (sock < 0) {
continue;
}
*inaddr_p = sin.sin_addr.s_addr;
return (sock);
}
return (-1);
}
int
tcp_get_peer(int sock, unsigned int *inaddr_p, int *port_p)
{
struct sockaddr_in sin;
int i, rc;
i = sizeof (sin);
rc = getpeername(sock, (struct sockaddr *)&sin, &i);
if (rc != 0)
return (-1);
if (inaddr_p)
*inaddr_p = sin.sin_addr.s_addr;
if (port_p)
*port_p = ntohs(sin.sin_port);
return (sock);
}
char *
gethostaddr(void)
{
static char s[MAXHOSTNAMELEN];
struct hostent *h;
struct in_addr in;
char *p;
if (gethostname(s, sizeof (s)) == -1)
return (NULL);
if ((h = gethostbyname(s)) == NULL)
return (NULL);
p = h->h_addr_list[0];
(void) memcpy(&in.s_addr, p, sizeof (in.s_addr));
return (inet_ntoa(in));
}
char *
get_default_nic_addr(void)
{
struct ifaddrlist *al = NULL;
char errmsg[ERRBUFSIZE];
struct in_addr addr;
int nifs;
nifs = ifaddrlist(&al, AF_INET, LIFC_EXTERNAL_SOURCE, errmsg);
if (nifs <= 0)
return (NULL);
addr = al[0].addr.addr;
free(al);
return (inet_ntoa(IN_ADDR(addr.s_addr)));
}
void
ndmpd_audit_backup(ndmp_connection_t *conn,
char *path, int dest, char *local_path, int result)
{
adt_event_data_t *event;
if ((event = adt_alloc_event(conn->conn_ah, ADT_ndmp_backup)) == NULL) {
NDMP_LOG(LOG_ERR, "Audit failure: %m.");
return;
}
event->adt_ndmp_backup.source = path;
if (dest == NDMP_ADDR_LOCAL) {
event->adt_ndmp_backup.local_dest = local_path;
} else {
event->adt_ndmp_backup.remote_dest = conn->conn_sock;
}
if (result == 0) {
if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
NDMP_LOG(LOG_ERR, "Audit failure: %m.");
} else {
if (adt_put_event(event, ADT_FAILURE, result) != 0)
NDMP_LOG(LOG_ERR, "Audit failure: %m.");
}
adt_free_event(event);
}
void
ndmpd_audit_restore(ndmp_connection_t *conn,
char *path, int dest, char *local_path, int result)
{
adt_event_data_t *event;
if ((event = adt_alloc_event(conn->conn_ah,
ADT_ndmp_restore)) == NULL) {
NDMP_LOG(LOG_ERR, "Audit failure: %m.");
return;
}
event->adt_ndmp_restore.destination = path;
if (dest == NDMP_ADDR_LOCAL) {
event->adt_ndmp_restore.local_source = local_path;
} else {
event->adt_ndmp_restore.remote_source = conn->conn_sock;
}
if (result == 0) {
if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
NDMP_LOG(LOG_ERR, "Audit failure: %m.");
} else {
if (adt_put_event(event, ADT_FAILURE, result) != 0)
NDMP_LOG(LOG_ERR, "Audit failure: %m.");
}
adt_free_event(event);
}
void
ndmpd_audit_connect(ndmp_connection_t *conn, int result)
{
adt_event_data_t *event;
adt_termid_t *termid;
if (adt_load_termid(conn->conn_sock, &termid) != 0) {
NDMP_LOG(LOG_ERR, "Audit failure: %m.");
return;
}
if (adt_set_user(conn->conn_ah, ADT_NO_ATTRIB, ADT_NO_ATTRIB,
ADT_NO_ATTRIB, ADT_NO_ATTRIB, termid, ADT_NEW) != 0) {
NDMP_LOG(LOG_ERR, "Audit failure: %m.");
free(termid);
return;
}
free(termid);
if ((event = adt_alloc_event(conn->conn_ah,
ADT_ndmp_connect)) == NULL) {
NDMP_LOG(LOG_ERR, "Audit failure: %m.");
return;
}
if (result == 0) {
if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
NDMP_LOG(LOG_ERR, "Audit failure: %m.");
} else {
if (adt_put_event(event, ADT_FAILURE, result) != 0)
NDMP_LOG(LOG_ERR, "Audit failure: %m.");
}
adt_free_event(event);
}
void
ndmpd_audit_disconnect(ndmp_connection_t *conn)
{
adt_event_data_t *event;
if ((event = adt_alloc_event(conn->conn_ah,
ADT_ndmp_disconnect)) == NULL) {
NDMP_LOG(LOG_ERR, "Audit failure: %m.");
return;
}
if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
NDMP_LOG(LOG_ERR, "Audit failure: %m.");
adt_free_event(event);
}
void *
ndmp_malloc(size_t size)
{
void *data;
if ((data = calloc(1, size)) == NULL) {
NDMP_LOG(LOG_ERR, "Out of memory.");
}
return (data);
}
char *
get_backup_path_v3(ndmpd_module_params_t *params)
{
char *bkpath;
bkpath = MOD_GETENV(params, "PREFIX");
if (!bkpath)
bkpath = MOD_GETENV(params, "FILESYSTEM");
if (!bkpath) {
MOD_LOGV3(params, NDMP_LOG_ERROR,
"Backup path not defined.\n");
} else {
NDMP_LOG(LOG_DEBUG, "bkpath: \"%s\"", bkpath);
}
return (bkpath);
}
char *
get_backup_path_v2(ndmpd_module_params_t *params)
{
char *bkpath;
bkpath = MOD_GETENV(params, "PREFIX");
if (bkpath == NULL)
bkpath = MOD_GETENV(params, "FILESYSTEM");
if (bkpath == NULL) {
MOD_LOG(params, "Error: restore path not specified.\n");
return (NULL);
}
if (*bkpath != '/') {
MOD_LOG(params, "Error: relative backup path not allowed.\n");
return (NULL);
}
return (bkpath);
}