2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
9 * Copyright (c) 2007, The Storage Networking Industry Association.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * - Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
17 * - Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
22 * - Neither the name of The Storage Networking Industry Association (SNIA)
23 * nor the names of its contributors may be used to endorse or promote
24 * products derived from this software without specific prior written
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
39 /* Copyright (c) 2007, The Storage Networking Industry Association. */
40 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
42 #include <sys/types.h>
43 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
53 #include <libinetutil.h>
55 #include "ndmpd_common.h"
57 #define NDMP_PROC_ERR -1
58 #define NDMP_PROC_MSG 1
59 #define NDMP_PROC_REP 0
60 #define NDMP_PROC_REP_ERR 2
63 * The ndmp connection version can be set through command line. If command line
64 * is not specified it will be set from the ndmp SMF version property.
69 * The NDMP listening port number
74 * Restore path mechanism definition
75 * 0 means partial path restore and
76 * 1 means full path restore.
77 * Refer to NDMP_FULL_RESTORE_PATH for partial path and full path definition.
79 int ndmp_full_restore_path
= 1;
82 * Do we support Direct Access Restore?
84 int ndmp_dar_support
= 0;
87 * ndmp_connection_t handler function
89 static ndmpd_file_handler_func_t connection_file_handler
;
91 extern ndmp_handler_t ndmp_msghdl_tab
[];
93 static int ndmp_readit(void *connection_handle
,
96 static int ndmp_writeit(void *connection_handle
,
99 static int ndmp_recv_msg(ndmp_connection_t
*connection
);
100 static int ndmp_process_messages(ndmp_connection_t
*connection
,
101 boolean_t reply_expected
);
102 static ndmp_msg_handler_t
*ndmp_get_handler(ndmp_connection_t
*connection
,
103 ndmp_message message
);
104 static boolean_t
ndmp_check_auth_required(ndmp_message message
);
105 static ndmp_handler_t
*ndmp_get_interface(ndmp_message message
);
106 void *ndmpd_worker(void *ptarg
);
110 xdr_ndmp_header(XDR
*xdrs
, ndmp_header
*objp
)
119 * ndmp_create_connection
121 * Allocate and initialize a connection structure.
124 * handler_tbl (input) - message handlers.
131 * The returned connection should be destroyed using
132 * ndmp_destroy_connection().
135 ndmp_create_connection(void)
137 ndmp_connection_t
*connection
;
139 connection
= ndmp_malloc(sizeof (ndmp_connection_t
));
140 if (connection
== NULL
)
143 connection
->conn_sock
= -1;
144 connection
->conn_my_sequence
= 0;
145 connection
->conn_authorized
= FALSE
;
146 connection
->conn_eof
= FALSE
;
147 connection
->conn_msginfo
.mi_body
= 0;
148 connection
->conn_version
= ndmp_ver
;
149 connection
->conn_client_data
= 0;
150 (void) mutex_init(&connection
->conn_lock
, 0, NULL
);
151 connection
->conn_xdrs
.x_ops
= 0;
153 xdrrec_create(&connection
->conn_xdrs
, 0, 0, (caddr_t
)connection
,
154 ndmp_readit
, ndmp_writeit
);
156 if (connection
->conn_xdrs
.x_ops
== 0) {
157 NDMP_LOG(LOG_DEBUG
, "xdrrec_create failed");
158 (void) mutex_destroy(&connection
->conn_lock
);
159 (void) close(connection
->conn_sock
);
163 return ((ndmp_connection_t
*)connection
);
167 * ndmp_destroy_connection
169 * Shutdown a connection and release allocated resources.
172 * connection_handle (Input) - connection handle.
178 ndmp_destroy_connection(ndmp_connection_t
*connection_handle
)
180 ndmp_connection_t
*connection
= (ndmp_connection_t
*)connection_handle
;
182 if (connection
->conn_sock
>= 0) {
183 (void) mutex_destroy(&connection
->conn_lock
);
184 (void) close(connection
->conn_sock
);
185 connection
->conn_sock
= -1;
187 xdr_destroy(&connection
->conn_xdrs
);
195 * Close a connection.
198 * connection_handle (Input) - connection handle.
204 ndmp_close(ndmp_connection_t
*connection_handle
)
206 ndmp_connection_t
*connection
= (ndmp_connection_t
*)connection_handle
;
208 ndmpd_audit_disconnect(connection
);
209 if (connection
->conn_sock
>= 0) {
210 (void) mutex_destroy(&connection
->conn_lock
);
211 (void) close(connection
->conn_sock
);
212 connection
->conn_sock
= -1;
214 connection
->conn_eof
= TRUE
;
217 * We should close all the tapes that are used by this connection.
218 * In some cases the ndmp client opens a tape, but does not close the
219 * tape and closes the connection.
221 ndmp_open_list_release(connection_handle
);
227 * Initializes and starts a ndmp_worker thread
230 ndmp_start_worker(ndmpd_worker_arg_t
*argp
)
232 pthread_attr_t tattr
;
235 (void) pthread_attr_init(&tattr
);
236 (void) pthread_attr_setdetachstate(&tattr
, PTHREAD_CREATE_DETACHED
);
237 rc
= pthread_create(NULL
, &tattr
, ndmpd_worker
, (void *)argp
);
238 (void) pthread_attr_destroy(&tattr
);
245 * Creates a socket for listening and accepting connections
247 * Accepts connections and passes each connection to the connection
251 * port (input) - NDMP server port.
252 * If 0, the port number will be retrieved from
253 * the network service database. If not found there,
254 * the default NDMP port number (from ndmp.x)
256 * handler (input) - connection handler function.
259 * This function normally never returns unless there's error.
263 * This function does not return unless encountering an error
264 * related to the listen socket.
267 ndmp_run(ulong_t port
, ndmp_con_handler_func_t con_handler_func
)
273 struct sockaddr_in sin
;
274 ndmpd_worker_arg_t
*argp
;
276 sin
.sin_family
= AF_INET
;
277 sin
.sin_addr
.s_addr
= INADDR_ANY
;
278 sin
.sin_port
= htons(port
);
280 if ((server_socket
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
281 NDMP_LOG(LOG_DEBUG
, "Socket error: %m");
286 (void) setsockopt(server_socket
, SOL_SOCKET
, SO_REUSEADDR
,
287 (char *)&on
, sizeof (on
));
290 if (bind(server_socket
, (struct sockaddr
*)&sin
, sizeof (sin
)) < 0) {
291 NDMP_LOG(LOG_DEBUG
, "bind error: %m");
292 (void) close(server_socket
);
295 if (listen(server_socket
, 5) < 0) {
296 NDMP_LOG(LOG_DEBUG
, "listen error: %m");
297 (void) close(server_socket
);
302 if ((ns
= tcp_accept(server_socket
, &ipaddr
)) < 0) {
303 NDMP_LOG(LOG_DEBUG
, "tcp_accept error: %m");
306 NDMP_LOG(LOG_DEBUG
, "connection fd: %d", ns
);
307 set_socket_options(ns
);
309 if ((argp
= ndmp_malloc(sizeof (ndmpd_worker_arg_t
))) != NULL
) {
311 argp
->nw_ipaddr
= ipaddr
;
312 argp
->nw_con_handler_func
= con_handler_func
;
313 (void) ndmp_start_worker(argp
);
319 * ndmpd_worker thread
322 * argp (input) - structure containing socket and handler function
325 * 0 - successful connection.
329 ndmpd_worker(void *ptarg
)
332 ndmp_connection_t
*connection
;
333 ndmpd_worker_arg_t
*argp
= (ndmpd_worker_arg_t
*)ptarg
;
339 sock
= argp
->nw_sock
;
341 if ((connection
= ndmp_create_connection()) == NULL
) {
347 /* initialize auditing session */
348 if (adt_start_session(&connection
->conn_ah
, NULL
, 0) != 0) {
353 ((ndmp_connection_t
*)connection
)->conn_sock
= sock
;
354 (*argp
->nw_con_handler_func
)(connection
);
355 (void) adt_end_session(connection
->conn_ah
);
356 ndmp_destroy_connection(connection
);
364 * ndmp_process_requests
366 * Reads the next request message into the stream buffer.
367 * Processes messages until the stream buffer is empty.
370 * connection_handle (input) - connection handle.
373 * 0 - 1 or more messages successfully processed.
374 * -1 - error; connection no longer established.
377 ndmp_process_requests(ndmp_connection_t
*connection_handle
)
380 ndmp_connection_t
*connection
= (ndmp_connection_t
*)connection_handle
;
382 (void) mutex_lock(&connection
->conn_lock
);
384 if (ndmp_process_messages(connection
, FALSE
) < 0)
387 (void) mutex_unlock(&connection
->conn_lock
);
395 * Send an NDMP request message.
398 * connection_handle (input) - connection pointer.
399 * message (input) - message number.
400 * err (input) - error code to place in header.
401 * request_data (input) - message body.
402 * reply (output) - reply message. If 0, reply will be
406 * 0 - successful send.
408 * otherwise - error from reply header.
411 * - The reply body is only returned if the error code is NDMP_NO_ERR.
414 ndmp_send_request(ndmp_connection_t
*connection_handle
, ndmp_message message
,
415 ndmp_error err
, void *request_data
, void **reply
)
417 ndmp_connection_t
*connection
= (ndmp_connection_t
*)connection_handle
;
419 ndmp_msg_handler_t
*handler
;
423 /* Lookup info necessary for processing this request. */
424 if (!(handler
= ndmp_get_handler(connection
, message
))) {
425 NDMP_LOG(LOG_DEBUG
, "Sending message 0x%x: not supported",
429 (void) gettimeofday(&time
, 0);
431 header
.sequence
= ++(connection
->conn_my_sequence
);
432 header
.time_stamp
= time
.tv_sec
;
433 header
.message_type
= NDMP_MESSAGE_REQUEST
;
434 header
.message
= message
;
435 header
.reply_sequence
= 0;
438 connection
->conn_xdrs
.x_op
= XDR_ENCODE
;
439 if (!xdr_ndmp_header(&connection
->conn_xdrs
, &header
)) {
441 "Sending message 0x%x: encoding request header", message
);
442 (void) xdrrec_endofrecord(&connection
->conn_xdrs
, 1);
445 if (err
== NDMP_NO_ERR
&& handler
->mh_xdr_request
&& request_data
) {
446 if (!(*handler
->mh_xdr_request
)(&connection
->conn_xdrs
,
449 "Sending message 0x%x: encoding request body",
451 (void) xdrrec_endofrecord(&connection
->conn_xdrs
, 1);
455 (void) xdrrec_endofrecord(&connection
->conn_xdrs
, 1);
457 if (handler
->mh_xdr_reply
== 0) {
458 NDMP_LOG(LOG_DEBUG
, "handler->mh_xdr_reply == 0");
463 * Process messages until the reply to this request has been
467 r
= ndmp_process_messages(connection
, TRUE
);
469 /* connection error? */
473 /* no reply received? */
477 /* reply received? */
480 connection
->conn_msginfo
.mi_hdr
.message
) {
482 "Received unexpected reply 0x%x",
483 connection
->conn_msginfo
.mi_hdr
.message
);
484 ndmp_free_message(connection_handle
);
488 *reply
= connection
->conn_msginfo
.mi_body
;
490 ndmp_free_message(connection_handle
);
492 return (connection
->conn_msginfo
.mi_hdr
.error
);
494 /* error handling reply */
502 * ndmp_send_request_lock
504 * A wrapper for ndmp_send_request with locks.
507 * connection_handle (input) - connection pointer.
508 * message (input) - message number.
509 * err (input) - error code to place in header.
510 * request_data (input) - message body.
511 * reply (output) - reply message. If 0, reply will be
515 * 0 - successful send.
517 * otherwise - error from reply header.
520 * - The reply body is only returned if the error code is NDMP_NO_ERR.
523 ndmp_send_request_lock(ndmp_connection_t
*connection_handle
,
524 ndmp_message message
, ndmp_error err
, void *request_data
, void **reply
)
527 ndmp_connection_t
*connection
= (ndmp_connection_t
*)connection_handle
;
529 (void) mutex_lock(&connection
->conn_lock
);
531 rv
= ndmp_send_request(connection_handle
, message
, err
, request_data
,
533 (void) mutex_unlock(&connection
->conn_lock
);
541 * Send an NDMP reply message.
544 * connection_handle (input) - connection pointer.
545 * err (input) - error code to place in header.
546 * reply (input) - reply message body.
549 * 0 - successful send.
553 * - The body is only sent if the error code is NDMP_NO_ERR.
556 ndmp_send_response(ndmp_connection_t
*connection_handle
, ndmp_error err
,
559 ndmp_connection_t
*connection
= (ndmp_connection_t
*)connection_handle
;
563 (void) gettimeofday(&time
, 0);
565 header
.sequence
= ++(connection
->conn_my_sequence
);
566 header
.time_stamp
= time
.tv_sec
;
567 header
.message_type
= NDMP_MESSAGE_REPLY
;
568 header
.message
= connection
->conn_msginfo
.mi_hdr
.message
;
569 header
.reply_sequence
= connection
->conn_msginfo
.mi_hdr
.sequence
;
572 connection
->conn_xdrs
.x_op
= XDR_ENCODE
;
573 if (!xdr_ndmp_header(&connection
->conn_xdrs
, &header
)) {
574 NDMP_LOG(LOG_DEBUG
, "Sending message 0x%x: "
575 "encoding reply header",
577 (void) xdrrec_endofrecord(&connection
->conn_xdrs
, 1);
580 if (err
== NDMP_NO_ERR
&&
581 connection
->conn_msginfo
.mi_handler
->mh_xdr_reply
&&
583 if (!(*connection
->conn_msginfo
.mi_handler
->mh_xdr_reply
)(
584 &connection
->conn_xdrs
, reply
)) {
586 "Sending message 0x%x: encoding reply body",
588 (void) xdrrec_endofrecord(&connection
->conn_xdrs
, 1);
592 (void) xdrrec_endofrecord(&connection
->conn_xdrs
, 1);
599 * Free the memory of NDMP message body.
602 * connection_handle (input) - connection pointer.
609 ndmp_free_message(ndmp_connection_t
*connection_handle
)
611 ndmp_connection_t
*connection
= (ndmp_connection_t
*)connection_handle
;
613 if (connection
->conn_msginfo
.mi_handler
== NULL
||
614 connection
->conn_msginfo
.mi_body
== NULL
)
617 connection
->conn_xdrs
.x_op
= XDR_FREE
;
618 if (connection
->conn_msginfo
.mi_hdr
.message_type
==
619 NDMP_MESSAGE_REQUEST
) {
620 if (connection
->conn_msginfo
.mi_handler
->mh_xdr_request
)
621 (*connection
->conn_msginfo
.mi_handler
->mh_xdr_request
)(
622 &connection
->conn_xdrs
,
623 connection
->conn_msginfo
.mi_body
);
625 if (connection
->conn_msginfo
.mi_handler
->mh_xdr_reply
)
626 (*connection
->conn_msginfo
.mi_handler
->mh_xdr_reply
)(
627 &connection
->conn_xdrs
,
628 connection
->conn_msginfo
.mi_body
);
631 (void) free(connection
->conn_msginfo
.mi_body
);
632 connection
->conn_msginfo
.mi_body
= 0;
638 * Returns the connection file descriptor.
641 * connection_handle (input) - connection handle
644 * >=0 - file descriptor.
645 * -1 - connection not open.
648 ndmp_get_fd(ndmp_connection_t
*connection_handle
)
650 return (((ndmp_connection_t
*)connection_handle
)->conn_sock
);
655 * ndmp_set_client_data
657 * This function provides a means for the library client to provide
658 * a pointer to some user data structure that is retrievable by
659 * each message handler via ndmp_get_client_data.
662 * connection_handle (input) - connection handle.
663 * client_data (input) - user data pointer.
669 ndmp_set_client_data(ndmp_connection_t
*connection_handle
, void *client_data
)
671 ((ndmp_connection_t
*)connection_handle
)->conn_client_data
=
677 * ndmp_get_client_data
679 * This function provides a means for the library client to provide
680 * a pointer to some user data structure that is retrievable by
681 * each message handler via ndmp_get_client_data.
684 * connection_handle (input) - connection handle.
687 * client data pointer.
690 ndmp_get_client_data(ndmp_connection_t
*connection_handle
)
692 return (((ndmp_connection_t
*)connection_handle
)->conn_client_data
);
699 * Sets the NDMP protocol version to be used on the connection.
702 * connection_handle (input) - connection handle.
703 * version (input) - protocol version.
709 ndmp_set_version(ndmp_connection_t
*connection_handle
, ushort_t version
)
711 ((ndmp_connection_t
*)connection_handle
)->conn_version
= version
;
718 * Gets the NDMP protocol version in use on the connection.
721 * connection_handle (input) - connection handle.
722 * version (input) - protocol version.
728 ndmp_get_version(ndmp_connection_t
*connection_handle
)
730 return (((ndmp_connection_t
*)connection_handle
)->conn_version
);
735 * ndmp_set_authorized
737 * Mark the connection as either having been authorized or not.
740 * connection_handle (input) - connection handle.
741 * authorized (input) - TRUE or FALSE.
747 ndmp_set_authorized(ndmp_connection_t
*connection_handle
, boolean_t authorized
)
749 ((ndmp_connection_t
*)connection_handle
)->conn_authorized
= authorized
;
756 * NDMP main function called from main().
772 * Find ndmp port number to be used. If ndmpd is run as command line
773 * and port number is supplied, use that port number. If port number is
774 * is not supplied, find out if ndmp port property is set. If ndmp
775 * port property is set, use that port number otherwise use the defaule
778 if (ndmp_port
== 0) {
779 if ((propval
= ndmpd_get_prop(NDMP_TCP_PORT
)) == NULL
||
781 ndmp_port
= NDMPPORT
;
783 ndmp_port
= strtol(propval
, 0, 0);
786 if (ndmp_run(ndmp_port
, connection_handler
) == -1)
787 perror("ndmp_run ERROR");
793 * NDMP connection handler.
794 * Waits for, reads, and processes NDMP requests on a connection.
797 * connection (input) - connection handle.
803 connection_handler(ndmp_connection_t
*connection
)
805 static int conn_id
= 1;
806 ndmpd_session_t session
;
807 ndmp_notify_connected_request req
;
810 (void) memset(&session
, 0, sizeof (session
));
811 session
.ns_connection
= connection
;
812 session
.ns_eof
= FALSE
;
814 * The 'protocol_version' must be 1 at first, since the client talks
815 * to the server in version 1 then they can move to a higher
818 session
.ns_protocol_version
= ndmp_ver
;
820 session
.ns_scsi
.sd_is_open
= -1;
821 session
.ns_scsi
.sd_devid
= -1;
823 session
.ns_scsi
.sd_sid
= 0;
824 session
.ns_scsi
.sd_lun
= 0;
825 session
.ns_scsi
.sd_valid_target_set
= 0;
826 (void) memset(session
.ns_scsi
.sd_adapter_name
, 0,
827 sizeof (session
.ns_scsi
.sd_adapter_name
));
829 session
.ns_tape
.td_fd
= -1;
830 session
.ns_tape
.td_sid
= 0;
831 session
.ns_tape
.td_lun
= 0;
832 (void) memset(session
.ns_tape
.td_adapter_name
, 0,
833 sizeof (session
.ns_tape
.td_adapter_name
));
834 session
.ns_tape
.td_pos
= 0;
835 session
.ns_tape
.td_record_count
= 0;
836 session
.ns_file_handler_list
= 0;
838 (void) ndmpd_data_init(&session
);
839 ndmpd_file_history_init(&session
);
840 if (ndmpd_mover_init(&session
) < 0)
843 if (ndmp_lbr_init(&session
) < 0)
847 * Setup defaults here. The init functions can not set defaults
848 * since the init functions are called by the stop request handlers
849 * and client set variables need to persist across data operations.
851 session
.ns_mover
.md_record_size
= MAX_RECORD_SIZE
;
853 ndmp_set_client_data(connection
, (void *)&session
);
855 req
.reason
= NDMP_CONNECTED
;
856 req
.protocol_version
= ndmp_ver
;
857 req
.text_reason
= "";
859 if (ndmp_send_request_lock(connection
, NDMP_NOTIFY_CONNECTION_STATUS
,
860 NDMP_NO_ERR
, (void *)&req
, 0) < 0) {
861 NDMP_LOG(LOG_DEBUG
, "Connection terminated");
864 connection_fd
= ndmp_get_fd(connection
);
866 NDMP_LOG(LOG_DEBUG
, "connection_fd: %d", connection_fd
);
869 * Add the handler function for the connection to the DMA.
871 if (ndmpd_add_file_handler(&session
, (void *)&session
, connection_fd
,
872 NDMPD_SELECT_MODE_READ
, HC_CLIENT
, connection_file_handler
) != 0) {
873 NDMP_LOG(LOG_DEBUG
, "Could not register session handler.");
878 * Register the connection in the list of active connections.
880 if (ndmp_connect_list_add(connection
, &conn_id
) != 0) {
882 "Could not register the session to the server.");
883 (void) ndmpd_remove_file_handler(&session
, connection_fd
);
887 session
.hardlink_q
= hardlink_q_init();
889 while (session
.ns_eof
== FALSE
)
890 (void) ndmpd_select(&session
, TRUE
, HC_ALL
);
892 hardlink_q_cleanup(session
.hardlink_q
);
894 NDMP_LOG(LOG_DEBUG
, "Connection terminated");
896 (void) ndmpd_remove_file_handler(&session
, connection_fd
);
898 if (session
.ns_scsi
.sd_is_open
!= -1) {
899 NDMP_LOG(LOG_DEBUG
, "scsi.is_open: %d",
900 session
.ns_scsi
.sd_is_open
);
901 (void) ndmp_open_list_del(session
.ns_scsi
.sd_adapter_name
,
902 session
.ns_scsi
.sd_sid
, session
.ns_scsi
.sd_lun
);
904 if (session
.ns_tape
.td_fd
!= -1) {
905 NDMP_LOG(LOG_DEBUG
, "tape.fd: %d", session
.ns_tape
.td_fd
);
906 (void) close(session
.ns_tape
.td_fd
);
907 (void) ndmp_open_list_del(session
.ns_tape
.td_adapter_name
,
908 session
.ns_tape
.td_sid
, session
.ns_tape
.td_lun
);
910 ndmpd_mover_shut_down(&session
);
911 ndmp_lbr_cleanup(&session
);
912 ndmpd_data_cleanup(&session
);
913 ndmpd_file_history_cleanup(&session
, FALSE
);
914 ndmpd_mover_cleanup(&session
);
916 (void) ndmp_connect_list_del(connection
);
921 * connection_file_handler
923 * ndmp_connection_t file handler function.
924 * Called by ndmpd_select when data is available to be read on the
928 * cookie (input) - session pointer.
929 * fd (input) - connection file descriptor.
930 * mode (input) - select mode.
937 connection_file_handler(void *cookie
, int fd
, ulong_t mode
)
939 ndmpd_session_t
*session
= (ndmpd_session_t
*)cookie
;
941 if (ndmp_process_requests(session
->ns_connection
) < 0)
942 session
->ns_eof
= TRUE
;
946 /* ************* private functions *************************************** */
951 * Low level read routine called by the xdrrec library.
954 * connection (input) - connection pointer.
955 * buf (input) - location to store received data.
956 * len (input) - max number of bytes to read.
959 * >0 - number of bytes received.
963 ndmp_readit(void *connection_handle
, caddr_t buf
, int len
)
965 ndmp_connection_t
*connection
= (ndmp_connection_t
*)connection_handle
;
967 len
= read(connection
->conn_sock
, buf
, len
);
969 /* ndmp_connection_t has been closed. */
970 connection
->conn_eof
= TRUE
;
979 * Low level write routine called by the xdrrec library.
982 * connection (input) - connection pointer.
983 * buf (input) - location to store received data.
984 * len (input) - max number of bytes to read.
987 * >0 - number of bytes sent.
991 ndmp_writeit(void *connection_handle
, caddr_t buf
, int len
)
993 ndmp_connection_t
*connection
= (ndmp_connection_t
*)connection_handle
;
997 for (cnt
= len
; cnt
> 0; cnt
-= n
, buf
+= n
) {
998 if ((n
= write(connection
->conn_sock
, buf
, cnt
)) < 0) {
999 connection
->conn_eof
= TRUE
;
1011 * Read the next message.
1014 * connection (input) - connection pointer.
1015 * msg (output) - received message.
1018 * 0 - Message successfully received.
1019 * error number - Message related error.
1020 * -1 - Error decoding the message header.
1023 ndmp_recv_msg(ndmp_connection_t
*connection
)
1025 bool_t(*xdr_func
) (XDR
*, ...) = NULL
;
1027 /* Decode the header. */
1028 connection
->conn_xdrs
.x_op
= XDR_DECODE
;
1029 (void) xdrrec_skiprecord(&connection
->conn_xdrs
);
1030 if (!xdr_ndmp_header(&connection
->conn_xdrs
,
1031 &connection
->conn_msginfo
.mi_hdr
))
1034 /* Lookup info necessary for processing this message. */
1035 if ((connection
->conn_msginfo
.mi_handler
= ndmp_get_handler(connection
,
1036 connection
->conn_msginfo
.mi_hdr
.message
)) == 0) {
1037 NDMP_LOG(LOG_DEBUG
, "Message 0x%x not supported",
1038 connection
->conn_msginfo
.mi_hdr
.message
);
1039 return (NDMP_NOT_SUPPORTED_ERR
);
1041 connection
->conn_msginfo
.mi_body
= 0;
1043 if (connection
->conn_msginfo
.mi_hdr
.error
!= NDMP_NO_ERR
)
1046 /* Determine body type */
1047 if (connection
->conn_msginfo
.mi_hdr
.message_type
==
1048 NDMP_MESSAGE_REQUEST
) {
1049 if (ndmp_check_auth_required(
1050 connection
->conn_msginfo
.mi_hdr
.message
) &&
1051 !connection
->conn_authorized
) {
1053 "Processing request 0x%x:connection not authorized",
1054 connection
->conn_msginfo
.mi_hdr
.message
);
1055 return (NDMP_NOT_AUTHORIZED_ERR
);
1057 if (connection
->conn_msginfo
.mi_handler
->mh_sizeof_request
>
1060 connection
->conn_msginfo
.mi_handler
->mh_xdr_request
;
1061 if (xdr_func
== NULL
) {
1063 "Processing request 0x%x: no xdr function "
1065 connection
->conn_msginfo
.mi_hdr
.message
);
1066 return (NDMP_NOT_SUPPORTED_ERR
);
1068 connection
->conn_msginfo
.mi_body
= ndmp_malloc(
1069 connection
->conn_msginfo
.mi_handler
->
1071 if (connection
->conn_msginfo
.mi_body
== NULL
)
1072 return (NDMP_NO_MEM_ERR
);
1074 (void) memset(connection
->conn_msginfo
.mi_body
, 0,
1075 connection
->conn_msginfo
.mi_handler
->
1079 if (connection
->conn_msginfo
.mi_handler
->mh_sizeof_reply
> 0) {
1081 connection
->conn_msginfo
.mi_handler
->mh_xdr_reply
;
1082 if (xdr_func
== NULL
) {
1084 "Processing reply 0x%x: no xdr function "
1086 connection
->conn_msginfo
.mi_hdr
.message
);
1087 return (NDMP_NOT_SUPPORTED_ERR
);
1089 connection
->conn_msginfo
.mi_body
= ndmp_malloc(
1090 connection
->conn_msginfo
.mi_handler
->
1092 if (connection
->conn_msginfo
.mi_body
== NULL
)
1093 return (NDMP_NO_MEM_ERR
);
1095 (void) memset(connection
->conn_msginfo
.mi_body
, 0,
1096 connection
->conn_msginfo
.mi_handler
->
1101 /* Decode message arguments if needed */
1103 if (!(*xdr_func
)(&connection
->conn_xdrs
,
1104 connection
->conn_msginfo
.mi_body
)) {
1106 "Processing message 0x%x: error decoding arguments",
1107 connection
->conn_msginfo
.mi_hdr
.message
);
1108 free(connection
->conn_msginfo
.mi_body
);
1109 connection
->conn_msginfo
.mi_body
= 0;
1110 return (NDMP_XDR_DECODE_ERR
);
1117 * ndmp_process_messages
1119 * Reads the next message into the stream buffer.
1120 * Processes messages until the stream buffer is empty.
1122 * This function processes all data in the stream buffer before returning.
1123 * This allows functions like poll() to be used to determine when new
1124 * messages have arrived. If only some of the messages in the stream buffer
1125 * were processed and then poll was called, poll() could block waiting for
1126 * a message that had already been received and read into the stream buffer.
1128 * This function processes both request and reply messages.
1129 * Request messages are dispatched using the appropriate function from the
1130 * message handling table.
1131 * Only one reply messages may be pending receipt at a time.
1132 * A reply message, if received, is placed in connection->conn_msginfo
1133 * before returning to the caller.
1134 * Errors are reported if a reply is received but not expected or if
1135 * more than one reply message is received
1138 * connection (input) - connection pointer.
1139 * reply_expected (output) - TRUE - a reply message is expected.
1140 * FALSE - no reply message is expected and
1141 * an error will be reported if a reply
1145 * NDMP_PROC_REP_ERR - 1 or more messages successfully processed,
1146 * error processing reply message.
1147 * NDMP_PROC_REP_ERR - 1 or more messages successfully processed,
1149 * NDMP_PROC_REP_ERR - 1 or more messages successfully processed,
1151 * NDMP_PROC_REP_ERR - error; connection no longer established.
1154 * If the peer is generating a large number of requests, a caller
1155 * looking for a reply will be blocked while the requests are handled.
1156 * This is because this function does not return until the stream
1158 * Code needs to be added to allow a return if the stream buffer
1159 * is not empty but there is data available on the socket. This will
1160 * prevent poll() from blocking and prevent a caller looking for a reply
1161 * from getting blocked by a bunch of requests.
1164 ndmp_process_messages(ndmp_connection_t
*connection
, boolean_t reply_expected
)
1166 msg_info_t reply_msginfo
;
1167 boolean_t reply_read
= FALSE
;
1168 boolean_t reply_error
= FALSE
;
1171 NDMP_LOG(LOG_DEBUG
, "reply_expected: %s",
1172 reply_expected
== TRUE
? "TRUE" : "FALSE");
1174 (void) memset((void *)&reply_msginfo
, 0, sizeof (msg_info_t
));
1177 (void) memset((void *)&connection
->conn_msginfo
, 0,
1178 sizeof (msg_info_t
));
1180 if ((err
= ndmp_recv_msg(connection
)) != NDMP_NO_ERR
) {
1181 if (connection
->conn_eof
) {
1182 NDMP_LOG(LOG_DEBUG
, "detected eof");
1183 return (NDMP_PROC_ERR
);
1186 NDMP_LOG(LOG_DEBUG
, "error decoding header");
1189 * Error occurred decoding the header.
1190 * Don't send a reply since we don't know
1191 * the message or if the message was even
1192 * a request message. To be safe, assume
1193 * that the message was a reply if a reply
1194 * was expected. Need to do this to prevent
1195 * hanging ndmp_send_request() waiting for a
1196 * reply. Don't set reply_read so that the
1197 * reply will be processed if it is received
1200 if (reply_read
== FALSE
)
1205 if (connection
->conn_msginfo
.mi_hdr
.message_type
1206 != NDMP_MESSAGE_REQUEST
) {
1207 NDMP_LOG(LOG_DEBUG
, "received reply: 0x%x",
1208 connection
->conn_msginfo
.mi_hdr
.message
);
1210 if (reply_expected
== FALSE
||
1213 "Unexpected reply message: 0x%x",
1214 connection
->conn_msginfo
.mi_hdr
.
1217 ndmp_free_message((ndmp_connection_t
*)
1220 if (reply_read
== FALSE
) {
1226 NDMP_LOG(LOG_DEBUG
, "received request: 0x%x",
1227 connection
->conn_msginfo
.mi_hdr
.message
);
1229 (void) ndmp_send_response((ndmp_connection_t
*)
1230 connection
, err
, NULL
);
1231 ndmp_free_message((ndmp_connection_t
*)connection
);
1234 if (connection
->conn_msginfo
.mi_hdr
.message_type
1235 != NDMP_MESSAGE_REQUEST
) {
1236 NDMP_LOG(LOG_DEBUG
, "received reply: 0x%x",
1237 connection
->conn_msginfo
.mi_hdr
.message
);
1239 if (reply_expected
== FALSE
|| reply_read
== TRUE
) {
1241 "Unexpected reply message: 0x%x",
1242 connection
->conn_msginfo
.mi_hdr
.message
);
1243 ndmp_free_message((ndmp_connection_t
*)
1248 reply_msginfo
= connection
->conn_msginfo
;
1251 NDMP_LOG(LOG_DEBUG
, "received request: 0x%x",
1252 connection
->conn_msginfo
.mi_hdr
.message
);
1255 * The following is needed to catch an improperly constructed
1256 * handler table or to deal with an NDMP client that is not
1257 * conforming to the negotiated protocol version.
1259 if (connection
->conn_msginfo
.mi_handler
->mh_func
== NULL
) {
1260 NDMP_LOG(LOG_DEBUG
, "No handler for message 0x%x",
1261 connection
->conn_msginfo
.mi_hdr
.message
);
1263 (void) ndmp_send_response((ndmp_connection_t
*)
1264 connection
, NDMP_NOT_SUPPORTED_ERR
, NULL
);
1265 ndmp_free_message((ndmp_connection_t
*)connection
);
1269 * Call the handler function.
1270 * The handler will send any necessary reply.
1272 (*connection
->conn_msginfo
.mi_handler
->mh_func
) (connection
,
1273 connection
->conn_msginfo
.mi_body
);
1275 ndmp_free_message((ndmp_connection_t
*)connection
);
1277 } while (xdrrec_eof(&connection
->conn_xdrs
) == FALSE
&&
1278 connection
->conn_eof
== FALSE
);
1280 NDMP_LOG(LOG_DEBUG
, "no more messages in stream buffer");
1282 if (connection
->conn_eof
== TRUE
) {
1283 if (reply_msginfo
.mi_body
)
1284 free(reply_msginfo
.mi_body
);
1285 return (NDMP_PROC_ERR
);
1288 if (reply_msginfo
.mi_body
)
1289 free(reply_msginfo
.mi_body
);
1290 return (NDMP_PROC_REP_ERR
);
1293 connection
->conn_msginfo
= reply_msginfo
;
1294 return (NDMP_PROC_MSG
);
1296 return (NDMP_PROC_REP
);
1301 * ndmp_get_interface
1303 * Return the NDMP interface (e.g. config, scsi, tape) for the
1307 * message (input) - message number.
1310 * NULL - message not found.
1311 * pointer to handler info.
1313 static ndmp_handler_t
*
1314 ndmp_get_interface(ndmp_message message
)
1316 ndmp_handler_t
*ni
= &ndmp_msghdl_tab
[(message
>> 8) % INT_MAXCMD
];
1318 if ((message
& 0xff) >= ni
->hd_cnt
)
1322 if (ni
->hd_msgs
[message
& 0xff].hm_message
!= message
)
1331 * Return the handler info for the specified NDMP message.
1334 * connection (input) - connection pointer.
1335 * message (input) - message number.
1338 * NULL - message not found.
1339 * pointer to handler info.
1341 static ndmp_msg_handler_t
*
1342 ndmp_get_handler(ndmp_connection_t
*connection
, ndmp_message message
)
1344 ndmp_msg_handler_t
*handler
= NULL
;
1346 ndmp_handler_t
*ni
= ndmp_get_interface(message
);
1347 int ver
= connection
->conn_version
;
1350 handler
= &ni
->hd_msgs
[message
& 0xff].hm_msg_v
[ver
- 2];
1356 * ndmp_check_auth_required
1358 * Check if the connection needs to be authenticated before
1359 * this message is being processed.
1362 * message (input) - message number.
1366 * FALSE - not required
1369 ndmp_check_auth_required(ndmp_message message
)
1371 boolean_t auth_req
= FALSE
;
1372 ndmp_handler_t
*ni
= ndmp_get_interface(message
);
1375 auth_req
= ni
->hd_msgs
[message
& 0xff].hm_auth_required
;
1383 * A wrapper around accept for retrying and getting the IP address
1386 * listen_sock (input) - the socket for listening
1387 * inaddr_p (output) - the IP address of peer connection
1390 * socket for the accepted connection
1394 tcp_accept(int listen_sock
, unsigned int *inaddr_p
)
1396 struct sockaddr_in sin
;
1400 for (try = 0; try < 3; try++) {
1402 sock
= accept(listen_sock
, (struct sockaddr
*)&sin
, &i
);
1406 *inaddr_p
= sin
.sin_addr
.s_addr
;
1416 * Get the peer IP address for a connection
1419 * sock (input) - the active socket
1420 * inaddr_p (output) - the IP address of peer connection
1421 * port_p (output) - the port number of peer connection
1424 * socket for the accepted connection
1428 tcp_get_peer(int sock
, unsigned int *inaddr_p
, int *port_p
)
1430 struct sockaddr_in sin
;
1434 rc
= getpeername(sock
, (struct sockaddr
*)&sin
, &i
);
1439 *inaddr_p
= sin
.sin_addr
.s_addr
;
1442 *port_p
= ntohs(sin
.sin_port
);
1451 * Get the IP address string of the current host
1463 static char s
[MAXHOSTNAMELEN
];
1468 if (gethostname(s
, sizeof (s
)) == -1)
1471 if ((h
= gethostbyname(s
)) == NULL
)
1474 p
= h
->h_addr_list
[0];
1475 (void) memcpy(&in
.s_addr
, p
, sizeof (in
.s_addr
));
1476 return (inet_ntoa(in
));
1481 * get_default_nic_addr
1483 * Get the IP address of the default NIC
1486 get_default_nic_addr(void)
1488 struct ifaddrlist
*al
= NULL
;
1489 char errmsg
[ERRBUFSIZE
];
1490 struct in_addr addr
;
1493 nifs
= ifaddrlist(&al
, AF_INET
, LIFC_EXTERNAL_SOURCE
, errmsg
);
1497 /* pick the first interface's address */
1498 addr
= al
[0].addr
.addr
;
1501 return (inet_ntoa(IN_ADDR(addr
.s_addr
)));
1506 * ndmpd_audit_backup
1508 * Generate AUE_ndmp_backup audit record
1512 ndmpd_audit_backup(ndmp_connection_t
*conn
,
1513 char *path
, int dest
, char *local_path
, int result
)
1515 adt_event_data_t
*event
;
1517 if ((event
= adt_alloc_event(conn
->conn_ah
, ADT_ndmp_backup
)) == NULL
) {
1518 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1521 event
->adt_ndmp_backup
.source
= path
;
1523 if (dest
== NDMP_ADDR_LOCAL
) {
1524 event
->adt_ndmp_backup
.local_dest
= local_path
;
1526 event
->adt_ndmp_backup
.remote_dest
= conn
->conn_sock
;
1530 if (adt_put_event(event
, ADT_SUCCESS
, ADT_SUCCESS
) != 0)
1531 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1533 if (adt_put_event(event
, ADT_FAILURE
, result
) != 0)
1534 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1537 adt_free_event(event
);
1542 * ndmpd_audit_restore
1544 * Generate AUE_ndmp_restore audit record
1548 ndmpd_audit_restore(ndmp_connection_t
*conn
,
1549 char *path
, int dest
, char *local_path
, int result
)
1551 adt_event_data_t
*event
;
1553 if ((event
= adt_alloc_event(conn
->conn_ah
,
1554 ADT_ndmp_restore
)) == NULL
) {
1555 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1558 event
->adt_ndmp_restore
.destination
= path
;
1560 if (dest
== NDMP_ADDR_LOCAL
) {
1561 event
->adt_ndmp_restore
.local_source
= local_path
;
1563 event
->adt_ndmp_restore
.remote_source
= conn
->conn_sock
;
1567 if (adt_put_event(event
, ADT_SUCCESS
, ADT_SUCCESS
) != 0)
1568 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1570 if (adt_put_event(event
, ADT_FAILURE
, result
) != 0)
1571 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1574 adt_free_event(event
);
1579 * ndmpd_audit_connect
1581 * Generate AUE_ndmp_connect audit record
1585 ndmpd_audit_connect(ndmp_connection_t
*conn
, int result
)
1587 adt_event_data_t
*event
;
1588 adt_termid_t
*termid
;
1590 if (adt_load_termid(conn
->conn_sock
, &termid
) != 0) {
1591 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1595 if (adt_set_user(conn
->conn_ah
, ADT_NO_ATTRIB
, ADT_NO_ATTRIB
,
1596 ADT_NO_ATTRIB
, ADT_NO_ATTRIB
, termid
, ADT_NEW
) != 0) {
1597 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1603 if ((event
= adt_alloc_event(conn
->conn_ah
,
1604 ADT_ndmp_connect
)) == NULL
) {
1605 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1610 if (adt_put_event(event
, ADT_SUCCESS
, ADT_SUCCESS
) != 0)
1611 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1613 if (adt_put_event(event
, ADT_FAILURE
, result
) != 0)
1614 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1617 adt_free_event(event
);
1622 * ndmpd_audit_disconnect
1624 * Generate AUE_ndmp_disconnect audit record
1628 ndmpd_audit_disconnect(ndmp_connection_t
*conn
)
1630 adt_event_data_t
*event
;
1632 if ((event
= adt_alloc_event(conn
->conn_ah
,
1633 ADT_ndmp_disconnect
)) == NULL
) {
1634 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1637 if (adt_put_event(event
, ADT_SUCCESS
, ADT_SUCCESS
) != 0)
1638 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1640 adt_free_event(event
);
1644 ndmp_malloc(size_t size
)
1648 if ((data
= calloc(1, size
)) == NULL
) {
1649 NDMP_LOG(LOG_ERR
, "Out of memory.");
1656 * get_backup_path_v3
1658 * Get the backup path from the NDMP environment variables.
1661 * params (input) - pointer to the parameters structure.
1664 * The backup path: if anything is specified
1668 get_backup_path_v3(ndmpd_module_params_t
*params
)
1672 bkpath
= MOD_GETENV(params
, "PREFIX");
1674 bkpath
= MOD_GETENV(params
, "FILESYSTEM");
1678 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
1679 "Backup path not defined.\n");
1681 NDMP_LOG(LOG_DEBUG
, "bkpath: \"%s\"", bkpath
);
1690 * Find the backup path from the environment variables (v2)
1693 get_backup_path_v2(ndmpd_module_params_t
*params
)
1697 bkpath
= MOD_GETENV(params
, "PREFIX");
1699 bkpath
= MOD_GETENV(params
, "FILESYSTEM");
1701 if (bkpath
== NULL
) {
1702 MOD_LOG(params
, "Error: restore path not specified.\n");
1706 if (*bkpath
!= '/') {
1707 MOD_LOG(params
, "Error: relative backup path not allowed.\n");