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 * ndmp_create_connection
112 * Allocate and initialize a connection structure.
115 * handler_tbl (input) - message handlers.
122 * The returned connection should be destroyed using
123 * ndmp_destroy_connection().
126 ndmp_create_connection(void)
128 ndmp_connection_t
*connection
;
130 connection
= ndmp_malloc(sizeof (ndmp_connection_t
));
131 if (connection
== NULL
)
134 connection
->conn_sock
= -1;
135 connection
->conn_my_sequence
= 0;
136 connection
->conn_authorized
= FALSE
;
137 connection
->conn_eof
= FALSE
;
138 connection
->conn_msginfo
.mi_body
= 0;
139 connection
->conn_version
= ndmp_ver
;
140 connection
->conn_client_data
= 0;
141 (void) mutex_init(&connection
->conn_lock
, 0, NULL
);
142 connection
->conn_xdrs
.x_ops
= 0;
144 xdrrec_create(&connection
->conn_xdrs
, 0, 0, (caddr_t
)connection
,
145 ndmp_readit
, ndmp_writeit
);
147 if (connection
->conn_xdrs
.x_ops
== 0) {
148 NDMP_LOG(LOG_DEBUG
, "xdrrec_create failed");
149 (void) mutex_destroy(&connection
->conn_lock
);
150 (void) close(connection
->conn_sock
);
154 return ((ndmp_connection_t
*)connection
);
158 * ndmp_destroy_connection
160 * Shutdown a connection and release allocated resources.
163 * connection_handle (Input) - connection handle.
169 ndmp_destroy_connection(ndmp_connection_t
*connection_handle
)
171 ndmp_connection_t
*connection
= (ndmp_connection_t
*)connection_handle
;
173 if (connection
->conn_sock
>= 0) {
174 (void) mutex_destroy(&connection
->conn_lock
);
175 (void) close(connection
->conn_sock
);
176 connection
->conn_sock
= -1;
178 xdr_destroy(&connection
->conn_xdrs
);
186 * Close a connection.
189 * connection_handle (Input) - connection handle.
195 ndmp_close(ndmp_connection_t
*connection_handle
)
197 ndmp_connection_t
*connection
= (ndmp_connection_t
*)connection_handle
;
199 ndmpd_audit_disconnect(connection
);
200 if (connection
->conn_sock
>= 0) {
201 (void) mutex_destroy(&connection
->conn_lock
);
202 (void) close(connection
->conn_sock
);
203 connection
->conn_sock
= -1;
205 connection
->conn_eof
= TRUE
;
208 * We should close all the tapes that are used by this connection.
209 * In some cases the ndmp client opens a tape, but does not close the
210 * tape and closes the connection.
212 ndmp_open_list_release(connection_handle
);
218 * Initializes and starts a ndmp_worker thread
221 ndmp_start_worker(ndmpd_worker_arg_t
*argp
)
223 pthread_attr_t tattr
;
226 (void) pthread_attr_init(&tattr
);
227 (void) pthread_attr_setdetachstate(&tattr
, PTHREAD_CREATE_DETACHED
);
228 rc
= pthread_create(NULL
, &tattr
, ndmpd_worker
, (void *)argp
);
229 (void) pthread_attr_destroy(&tattr
);
236 * Creates a socket for listening and accepting connections
238 * Accepts connections and passes each connection to the connection
242 * port (input) - NDMP server port.
243 * If 0, the port number will be retrieved from
244 * the network service database. If not found there,
245 * the default NDMP port number (from ndmp.x)
247 * handler (input) - connection handler function.
250 * This function normally never returns unless there's error.
254 * This function does not return unless encountering an error
255 * related to the listen socket.
258 ndmp_run(ulong_t port
, ndmp_con_handler_func_t con_handler_func
)
264 struct sockaddr_in sin
;
265 ndmpd_worker_arg_t
*argp
;
267 sin
.sin_family
= AF_INET
;
268 sin
.sin_addr
.s_addr
= INADDR_ANY
;
269 sin
.sin_port
= htons(port
);
271 if ((server_socket
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
272 NDMP_LOG(LOG_DEBUG
, "Socket error: %m");
277 (void) setsockopt(server_socket
, SOL_SOCKET
, SO_REUSEADDR
,
278 (char *)&on
, sizeof (on
));
281 if (bind(server_socket
, (struct sockaddr
*)&sin
, sizeof (sin
)) < 0) {
282 NDMP_LOG(LOG_DEBUG
, "bind error: %m");
283 (void) close(server_socket
);
286 if (listen(server_socket
, 5) < 0) {
287 NDMP_LOG(LOG_DEBUG
, "listen error: %m");
288 (void) close(server_socket
);
293 if ((ns
= tcp_accept(server_socket
, &ipaddr
)) < 0) {
294 NDMP_LOG(LOG_DEBUG
, "tcp_accept error: %m");
297 NDMP_LOG(LOG_DEBUG
, "connection fd: %d", ns
);
298 set_socket_options(ns
);
300 if ((argp
= ndmp_malloc(sizeof (ndmpd_worker_arg_t
))) != NULL
) {
302 argp
->nw_ipaddr
= ipaddr
;
303 argp
->nw_con_handler_func
= con_handler_func
;
304 (void) ndmp_start_worker(argp
);
310 * ndmpd_worker thread
313 * argp (input) - structure containing socket and handler function
316 * 0 - successful connection.
320 ndmpd_worker(void *ptarg
)
323 ndmp_connection_t
*connection
;
324 ndmpd_worker_arg_t
*argp
= (ndmpd_worker_arg_t
*)ptarg
;
330 sock
= argp
->nw_sock
;
332 if ((connection
= ndmp_create_connection()) == NULL
) {
338 /* initialize auditing session */
339 if (adt_start_session(&connection
->conn_ah
, NULL
, 0) != 0) {
344 ((ndmp_connection_t
*)connection
)->conn_sock
= sock
;
345 (*argp
->nw_con_handler_func
)(connection
);
346 (void) adt_end_session(connection
->conn_ah
);
347 ndmp_destroy_connection(connection
);
355 * ndmp_process_requests
357 * Reads the next request message into the stream buffer.
358 * Processes messages until the stream buffer is empty.
361 * connection_handle (input) - connection handle.
364 * 0 - 1 or more messages successfully processed.
365 * -1 - error; connection no longer established.
368 ndmp_process_requests(ndmp_connection_t
*connection_handle
)
371 ndmp_connection_t
*connection
= (ndmp_connection_t
*)connection_handle
;
373 (void) mutex_lock(&connection
->conn_lock
);
375 if (ndmp_process_messages(connection
, FALSE
) < 0)
378 (void) mutex_unlock(&connection
->conn_lock
);
386 * Send an NDMP request message.
389 * connection_handle (input) - connection pointer.
390 * message (input) - message number.
391 * err (input) - error code to place in header.
392 * request_data (input) - message body.
393 * reply (output) - reply message. If 0, reply will be
397 * 0 - successful send.
399 * otherwise - error from reply header.
402 * - The reply body is only returned if the error code is NDMP_NO_ERR.
405 ndmp_send_request(ndmp_connection_t
*connection_handle
, ndmp_message message
,
406 ndmp_error err
, void *request_data
, void **reply
)
408 ndmp_connection_t
*connection
= (ndmp_connection_t
*)connection_handle
;
410 ndmp_msg_handler_t
*handler
;
414 /* Lookup info necessary for processing this request. */
415 if (!(handler
= ndmp_get_handler(connection
, message
))) {
416 NDMP_LOG(LOG_DEBUG
, "Sending message 0x%x: not supported",
420 (void) gettimeofday(&time
, 0);
422 header
.sequence
= ++(connection
->conn_my_sequence
);
423 header
.time_stamp
= time
.tv_sec
;
424 header
.message_type
= NDMP_MESSAGE_REQUEST
;
425 header
.message
= message
;
426 header
.reply_sequence
= 0;
429 connection
->conn_xdrs
.x_op
= XDR_ENCODE
;
430 if (!xdr_ndmp_header(&connection
->conn_xdrs
, &header
)) {
432 "Sending message 0x%x: encoding request header", message
);
433 (void) xdrrec_endofrecord(&connection
->conn_xdrs
, 1);
436 if (err
== NDMP_NO_ERR
&& handler
->mh_xdr_request
&& request_data
) {
437 if (!(*handler
->mh_xdr_request
)(&connection
->conn_xdrs
,
440 "Sending message 0x%x: encoding request body",
442 (void) xdrrec_endofrecord(&connection
->conn_xdrs
, 1);
446 (void) xdrrec_endofrecord(&connection
->conn_xdrs
, 1);
448 if (handler
->mh_xdr_reply
== 0) {
449 NDMP_LOG(LOG_DEBUG
, "handler->mh_xdr_reply == 0");
454 * Process messages until the reply to this request has been
458 r
= ndmp_process_messages(connection
, TRUE
);
460 /* connection error? */
464 /* no reply received? */
468 /* reply received? */
471 connection
->conn_msginfo
.mi_hdr
.message
) {
473 "Received unexpected reply 0x%x",
474 connection
->conn_msginfo
.mi_hdr
.message
);
475 ndmp_free_message(connection_handle
);
479 *reply
= connection
->conn_msginfo
.mi_body
;
481 ndmp_free_message(connection_handle
);
483 return (connection
->conn_msginfo
.mi_hdr
.error
);
485 /* error handling reply */
493 * ndmp_send_request_lock
495 * A wrapper for ndmp_send_request with locks.
498 * connection_handle (input) - connection pointer.
499 * message (input) - message number.
500 * err (input) - error code to place in header.
501 * request_data (input) - message body.
502 * reply (output) - reply message. If 0, reply will be
506 * 0 - successful send.
508 * otherwise - error from reply header.
511 * - The reply body is only returned if the error code is NDMP_NO_ERR.
514 ndmp_send_request_lock(ndmp_connection_t
*connection_handle
,
515 ndmp_message message
, ndmp_error err
, void *request_data
, void **reply
)
518 ndmp_connection_t
*connection
= (ndmp_connection_t
*)connection_handle
;
520 (void) mutex_lock(&connection
->conn_lock
);
522 rv
= ndmp_send_request(connection_handle
, message
, err
, request_data
,
524 (void) mutex_unlock(&connection
->conn_lock
);
532 * Send an NDMP reply message.
535 * connection_handle (input) - connection pointer.
536 * err (input) - error code to place in header.
537 * reply (input) - reply message body.
540 * 0 - successful send.
544 * - The body is only sent if the error code is NDMP_NO_ERR.
547 ndmp_send_response(ndmp_connection_t
*connection_handle
, ndmp_error err
,
550 ndmp_connection_t
*connection
= (ndmp_connection_t
*)connection_handle
;
554 (void) gettimeofday(&time
, 0);
556 header
.sequence
= ++(connection
->conn_my_sequence
);
557 header
.time_stamp
= time
.tv_sec
;
558 header
.message_type
= NDMP_MESSAGE_REPLY
;
559 header
.message
= connection
->conn_msginfo
.mi_hdr
.message
;
560 header
.reply_sequence
= connection
->conn_msginfo
.mi_hdr
.sequence
;
563 connection
->conn_xdrs
.x_op
= XDR_ENCODE
;
564 if (!xdr_ndmp_header(&connection
->conn_xdrs
, &header
)) {
565 NDMP_LOG(LOG_DEBUG
, "Sending message 0x%x: "
566 "encoding reply header",
568 (void) xdrrec_endofrecord(&connection
->conn_xdrs
, 1);
571 if (err
== NDMP_NO_ERR
&&
572 connection
->conn_msginfo
.mi_handler
->mh_xdr_reply
&&
574 if (!(*connection
->conn_msginfo
.mi_handler
->mh_xdr_reply
)(
575 &connection
->conn_xdrs
, reply
)) {
577 "Sending message 0x%x: encoding reply body",
579 (void) xdrrec_endofrecord(&connection
->conn_xdrs
, 1);
583 (void) xdrrec_endofrecord(&connection
->conn_xdrs
, 1);
590 * Free the memory of NDMP message body.
593 * connection_handle (input) - connection pointer.
600 ndmp_free_message(ndmp_connection_t
*connection_handle
)
602 ndmp_connection_t
*connection
= (ndmp_connection_t
*)connection_handle
;
604 if (connection
->conn_msginfo
.mi_handler
== NULL
||
605 connection
->conn_msginfo
.mi_body
== NULL
)
608 connection
->conn_xdrs
.x_op
= XDR_FREE
;
609 if (connection
->conn_msginfo
.mi_hdr
.message_type
==
610 NDMP_MESSAGE_REQUEST
) {
611 if (connection
->conn_msginfo
.mi_handler
->mh_xdr_request
)
612 (*connection
->conn_msginfo
.mi_handler
->mh_xdr_request
)(
613 &connection
->conn_xdrs
,
614 connection
->conn_msginfo
.mi_body
);
616 if (connection
->conn_msginfo
.mi_handler
->mh_xdr_reply
)
617 (*connection
->conn_msginfo
.mi_handler
->mh_xdr_reply
)(
618 &connection
->conn_xdrs
,
619 connection
->conn_msginfo
.mi_body
);
622 (void) free(connection
->conn_msginfo
.mi_body
);
623 connection
->conn_msginfo
.mi_body
= 0;
629 * Returns the connection file descriptor.
632 * connection_handle (input) - connection handle
635 * >=0 - file descriptor.
636 * -1 - connection not open.
639 ndmp_get_fd(ndmp_connection_t
*connection_handle
)
641 return (((ndmp_connection_t
*)connection_handle
)->conn_sock
);
646 * ndmp_set_client_data
648 * This function provides a means for the library client to provide
649 * a pointer to some user data structure that is retrievable by
650 * each message handler via ndmp_get_client_data.
653 * connection_handle (input) - connection handle.
654 * client_data (input) - user data pointer.
660 ndmp_set_client_data(ndmp_connection_t
*connection_handle
, void *client_data
)
662 ((ndmp_connection_t
*)connection_handle
)->conn_client_data
=
668 * ndmp_get_client_data
670 * This function provides a means for the library client to provide
671 * a pointer to some user data structure that is retrievable by
672 * each message handler via ndmp_get_client_data.
675 * connection_handle (input) - connection handle.
678 * client data pointer.
681 ndmp_get_client_data(ndmp_connection_t
*connection_handle
)
683 return (((ndmp_connection_t
*)connection_handle
)->conn_client_data
);
690 * Sets the NDMP protocol version to be used on the connection.
693 * connection_handle (input) - connection handle.
694 * version (input) - protocol version.
700 ndmp_set_version(ndmp_connection_t
*connection_handle
, ushort_t version
)
702 ((ndmp_connection_t
*)connection_handle
)->conn_version
= version
;
709 * Gets the NDMP protocol version in use on the connection.
712 * connection_handle (input) - connection handle.
713 * version (input) - protocol version.
719 ndmp_get_version(ndmp_connection_t
*connection_handle
)
721 return (((ndmp_connection_t
*)connection_handle
)->conn_version
);
726 * ndmp_set_authorized
728 * Mark the connection as either having been authorized or not.
731 * connection_handle (input) - connection handle.
732 * authorized (input) - TRUE or FALSE.
738 ndmp_set_authorized(ndmp_connection_t
*connection_handle
, boolean_t authorized
)
740 ((ndmp_connection_t
*)connection_handle
)->conn_authorized
= authorized
;
747 * NDMP main function called from main().
763 * Find ndmp port number to be used. If ndmpd is run as command line
764 * and port number is supplied, use that port number. If port number is
765 * is not supplied, find out if ndmp port property is set. If ndmp
766 * port property is set, use that port number otherwise use the defaule
769 if (ndmp_port
== 0) {
770 if ((propval
= ndmpd_get_prop(NDMP_TCP_PORT
)) == NULL
||
772 ndmp_port
= NDMPPORT
;
774 ndmp_port
= strtol(propval
, 0, 0);
777 if (ndmp_run(ndmp_port
, connection_handler
) == -1)
778 perror("ndmp_run ERROR");
784 * NDMP connection handler.
785 * Waits for, reads, and processes NDMP requests on a connection.
788 * connection (input) - connection handle.
794 connection_handler(ndmp_connection_t
*connection
)
796 static int conn_id
= 1;
797 ndmpd_session_t session
;
798 ndmp_notify_connected_request req
;
801 (void) memset(&session
, 0, sizeof (session
));
802 session
.ns_connection
= connection
;
803 session
.ns_eof
= FALSE
;
805 * The 'protocol_version' must be 1 at first, since the client talks
806 * to the server in version 1 then they can move to a higher
809 session
.ns_protocol_version
= ndmp_ver
;
811 session
.ns_scsi
.sd_is_open
= -1;
812 session
.ns_scsi
.sd_devid
= -1;
814 session
.ns_scsi
.sd_sid
= 0;
815 session
.ns_scsi
.sd_lun
= 0;
816 session
.ns_scsi
.sd_valid_target_set
= 0;
817 (void) memset(session
.ns_scsi
.sd_adapter_name
, 0,
818 sizeof (session
.ns_scsi
.sd_adapter_name
));
820 session
.ns_tape
.td_fd
= -1;
821 session
.ns_tape
.td_sid
= 0;
822 session
.ns_tape
.td_lun
= 0;
823 (void) memset(session
.ns_tape
.td_adapter_name
, 0,
824 sizeof (session
.ns_tape
.td_adapter_name
));
825 session
.ns_tape
.td_pos
= 0;
826 session
.ns_tape
.td_record_count
= 0;
827 session
.ns_file_handler_list
= 0;
829 (void) ndmpd_data_init(&session
);
830 ndmpd_file_history_init(&session
);
831 if (ndmpd_mover_init(&session
) < 0)
834 if (ndmp_lbr_init(&session
) < 0)
838 * Setup defaults here. The init functions can not set defaults
839 * since the init functions are called by the stop request handlers
840 * and client set variables need to persist across data operations.
842 session
.ns_mover
.md_record_size
= MAX_RECORD_SIZE
;
844 ndmp_set_client_data(connection
, (void *)&session
);
846 req
.reason
= NDMP_CONNECTED
;
847 req
.protocol_version
= ndmp_ver
;
848 req
.text_reason
= "";
850 if (ndmp_send_request_lock(connection
, NDMP_NOTIFY_CONNECTION_STATUS
,
851 NDMP_NO_ERR
, (void *)&req
, 0) < 0) {
852 NDMP_LOG(LOG_DEBUG
, "Connection terminated");
855 connection_fd
= ndmp_get_fd(connection
);
857 NDMP_LOG(LOG_DEBUG
, "connection_fd: %d", connection_fd
);
860 * Add the handler function for the connection to the DMA.
862 if (ndmpd_add_file_handler(&session
, (void *)&session
, connection_fd
,
863 NDMPD_SELECT_MODE_READ
, HC_CLIENT
, connection_file_handler
) != 0) {
864 NDMP_LOG(LOG_DEBUG
, "Could not register session handler.");
869 * Register the connection in the list of active connections.
871 if (ndmp_connect_list_add(connection
, &conn_id
) != 0) {
873 "Could not register the session to the server.");
874 (void) ndmpd_remove_file_handler(&session
, connection_fd
);
878 session
.hardlink_q
= hardlink_q_init();
880 while (session
.ns_eof
== FALSE
)
881 (void) ndmpd_select(&session
, TRUE
, HC_ALL
);
883 hardlink_q_cleanup(session
.hardlink_q
);
885 NDMP_LOG(LOG_DEBUG
, "Connection terminated");
887 (void) ndmpd_remove_file_handler(&session
, connection_fd
);
889 if (session
.ns_scsi
.sd_is_open
!= -1) {
890 NDMP_LOG(LOG_DEBUG
, "scsi.is_open: %d",
891 session
.ns_scsi
.sd_is_open
);
892 (void) ndmp_open_list_del(session
.ns_scsi
.sd_adapter_name
,
893 session
.ns_scsi
.sd_sid
, session
.ns_scsi
.sd_lun
);
895 if (session
.ns_tape
.td_fd
!= -1) {
896 NDMP_LOG(LOG_DEBUG
, "tape.fd: %d", session
.ns_tape
.td_fd
);
897 (void) close(session
.ns_tape
.td_fd
);
898 (void) ndmp_open_list_del(session
.ns_tape
.td_adapter_name
,
899 session
.ns_tape
.td_sid
, session
.ns_tape
.td_lun
);
901 ndmpd_mover_shut_down(&session
);
902 ndmp_lbr_cleanup(&session
);
903 ndmpd_data_cleanup(&session
);
904 ndmpd_file_history_cleanup(&session
, FALSE
);
905 ndmpd_mover_cleanup(&session
);
907 (void) ndmp_connect_list_del(connection
);
912 * connection_file_handler
914 * ndmp_connection_t file handler function.
915 * Called by ndmpd_select when data is available to be read on the
919 * cookie (input) - session pointer.
920 * fd (input) - connection file descriptor.
921 * mode (input) - select mode.
928 connection_file_handler(void *cookie
, int fd
, ulong_t mode
)
930 ndmpd_session_t
*session
= (ndmpd_session_t
*)cookie
;
932 if (ndmp_process_requests(session
->ns_connection
) < 0)
933 session
->ns_eof
= TRUE
;
937 /* ************* private functions *************************************** */
942 * Low level read routine called by the xdrrec library.
945 * connection (input) - connection pointer.
946 * buf (input) - location to store received data.
947 * len (input) - max number of bytes to read.
950 * >0 - number of bytes received.
954 ndmp_readit(void *connection_handle
, caddr_t buf
, int len
)
956 ndmp_connection_t
*connection
= (ndmp_connection_t
*)connection_handle
;
958 len
= read(connection
->conn_sock
, buf
, len
);
960 /* ndmp_connection_t has been closed. */
961 connection
->conn_eof
= TRUE
;
970 * Low level write routine called by the xdrrec library.
973 * connection (input) - connection pointer.
974 * buf (input) - location to store received data.
975 * len (input) - max number of bytes to read.
978 * >0 - number of bytes sent.
982 ndmp_writeit(void *connection_handle
, caddr_t buf
, int len
)
984 ndmp_connection_t
*connection
= (ndmp_connection_t
*)connection_handle
;
988 for (cnt
= len
; cnt
> 0; cnt
-= n
, buf
+= n
) {
989 if ((n
= write(connection
->conn_sock
, buf
, cnt
)) < 0) {
990 connection
->conn_eof
= TRUE
;
1002 * Read the next message.
1005 * connection (input) - connection pointer.
1006 * msg (output) - received message.
1009 * 0 - Message successfully received.
1010 * error number - Message related error.
1011 * -1 - Error decoding the message header.
1014 ndmp_recv_msg(ndmp_connection_t
*connection
)
1016 bool_t(*xdr_func
) (XDR
*, ...) = NULL
;
1018 /* Decode the header. */
1019 connection
->conn_xdrs
.x_op
= XDR_DECODE
;
1020 (void) xdrrec_skiprecord(&connection
->conn_xdrs
);
1021 if (!xdr_ndmp_header(&connection
->conn_xdrs
,
1022 &connection
->conn_msginfo
.mi_hdr
))
1025 /* Lookup info necessary for processing this message. */
1026 if ((connection
->conn_msginfo
.mi_handler
= ndmp_get_handler(connection
,
1027 connection
->conn_msginfo
.mi_hdr
.message
)) == 0) {
1028 NDMP_LOG(LOG_DEBUG
, "Message 0x%x not supported",
1029 connection
->conn_msginfo
.mi_hdr
.message
);
1030 return (NDMP_NOT_SUPPORTED_ERR
);
1032 connection
->conn_msginfo
.mi_body
= 0;
1034 if (connection
->conn_msginfo
.mi_hdr
.error
!= NDMP_NO_ERR
)
1037 /* Determine body type */
1038 if (connection
->conn_msginfo
.mi_hdr
.message_type
==
1039 NDMP_MESSAGE_REQUEST
) {
1040 if (ndmp_check_auth_required(
1041 connection
->conn_msginfo
.mi_hdr
.message
) &&
1042 !connection
->conn_authorized
) {
1044 "Processing request 0x%x:connection not authorized",
1045 connection
->conn_msginfo
.mi_hdr
.message
);
1046 return (NDMP_NOT_AUTHORIZED_ERR
);
1048 if (connection
->conn_msginfo
.mi_handler
->mh_sizeof_request
>
1051 connection
->conn_msginfo
.mi_handler
->mh_xdr_request
;
1052 if (xdr_func
== NULL
) {
1054 "Processing request 0x%x: no xdr function "
1056 connection
->conn_msginfo
.mi_hdr
.message
);
1057 return (NDMP_NOT_SUPPORTED_ERR
);
1059 connection
->conn_msginfo
.mi_body
= ndmp_malloc(
1060 connection
->conn_msginfo
.mi_handler
->
1062 if (connection
->conn_msginfo
.mi_body
== NULL
)
1063 return (NDMP_NO_MEM_ERR
);
1065 (void) memset(connection
->conn_msginfo
.mi_body
, 0,
1066 connection
->conn_msginfo
.mi_handler
->
1070 if (connection
->conn_msginfo
.mi_handler
->mh_sizeof_reply
> 0) {
1072 connection
->conn_msginfo
.mi_handler
->mh_xdr_reply
;
1073 if (xdr_func
== NULL
) {
1075 "Processing reply 0x%x: no xdr function "
1077 connection
->conn_msginfo
.mi_hdr
.message
);
1078 return (NDMP_NOT_SUPPORTED_ERR
);
1080 connection
->conn_msginfo
.mi_body
= ndmp_malloc(
1081 connection
->conn_msginfo
.mi_handler
->
1083 if (connection
->conn_msginfo
.mi_body
== NULL
)
1084 return (NDMP_NO_MEM_ERR
);
1086 (void) memset(connection
->conn_msginfo
.mi_body
, 0,
1087 connection
->conn_msginfo
.mi_handler
->
1092 /* Decode message arguments if needed */
1094 if (!(*xdr_func
)(&connection
->conn_xdrs
,
1095 connection
->conn_msginfo
.mi_body
)) {
1097 "Processing message 0x%x: error decoding arguments",
1098 connection
->conn_msginfo
.mi_hdr
.message
);
1099 free(connection
->conn_msginfo
.mi_body
);
1100 connection
->conn_msginfo
.mi_body
= 0;
1101 return (NDMP_XDR_DECODE_ERR
);
1108 * ndmp_process_messages
1110 * Reads the next message into the stream buffer.
1111 * Processes messages until the stream buffer is empty.
1113 * This function processes all data in the stream buffer before returning.
1114 * This allows functions like poll() to be used to determine when new
1115 * messages have arrived. If only some of the messages in the stream buffer
1116 * were processed and then poll was called, poll() could block waiting for
1117 * a message that had already been received and read into the stream buffer.
1119 * This function processes both request and reply messages.
1120 * Request messages are dispatched using the appropriate function from the
1121 * message handling table.
1122 * Only one reply messages may be pending receipt at a time.
1123 * A reply message, if received, is placed in connection->conn_msginfo
1124 * before returning to the caller.
1125 * Errors are reported if a reply is received but not expected or if
1126 * more than one reply message is received
1129 * connection (input) - connection pointer.
1130 * reply_expected (output) - TRUE - a reply message is expected.
1131 * FALSE - no reply message is expected and
1132 * an error will be reported if a reply
1136 * NDMP_PROC_REP_ERR - 1 or more messages successfully processed,
1137 * error processing reply message.
1138 * NDMP_PROC_REP_ERR - 1 or more messages successfully processed,
1140 * NDMP_PROC_REP_ERR - 1 or more messages successfully processed,
1142 * NDMP_PROC_REP_ERR - error; connection no longer established.
1145 * If the peer is generating a large number of requests, a caller
1146 * looking for a reply will be blocked while the requests are handled.
1147 * This is because this function does not return until the stream
1149 * Code needs to be added to allow a return if the stream buffer
1150 * is not empty but there is data available on the socket. This will
1151 * prevent poll() from blocking and prevent a caller looking for a reply
1152 * from getting blocked by a bunch of requests.
1155 ndmp_process_messages(ndmp_connection_t
*connection
, boolean_t reply_expected
)
1157 msg_info_t reply_msginfo
;
1158 boolean_t reply_read
= FALSE
;
1159 boolean_t reply_error
= FALSE
;
1162 NDMP_LOG(LOG_DEBUG
, "reply_expected: %s",
1163 reply_expected
== TRUE
? "TRUE" : "FALSE");
1165 (void) memset(&reply_msginfo
, 0, sizeof (msg_info_t
));
1168 (void) memset(&connection
->conn_msginfo
, 0,
1169 sizeof (msg_info_t
));
1171 if ((err
= ndmp_recv_msg(connection
)) != NDMP_NO_ERR
) {
1172 if (connection
->conn_eof
) {
1173 NDMP_LOG(LOG_DEBUG
, "detected eof");
1174 return (NDMP_PROC_ERR
);
1177 NDMP_LOG(LOG_DEBUG
, "error decoding header");
1180 * Error occurred decoding the header.
1181 * Don't send a reply since we don't know
1182 * the message or if the message was even
1183 * a request message. To be safe, assume
1184 * that the message was a reply if a reply
1185 * was expected. Need to do this to prevent
1186 * hanging ndmp_send_request() waiting for a
1187 * reply. Don't set reply_read so that the
1188 * reply will be processed if it is received
1191 if (reply_read
== FALSE
)
1196 if (connection
->conn_msginfo
.mi_hdr
.message_type
1197 != NDMP_MESSAGE_REQUEST
) {
1198 NDMP_LOG(LOG_DEBUG
, "received reply: 0x%x",
1199 connection
->conn_msginfo
.mi_hdr
.message
);
1201 if (reply_expected
== FALSE
||
1204 "Unexpected reply message: 0x%x",
1205 connection
->conn_msginfo
.mi_hdr
.
1208 ndmp_free_message((ndmp_connection_t
*)
1211 if (reply_read
== FALSE
) {
1217 NDMP_LOG(LOG_DEBUG
, "received request: 0x%x",
1218 connection
->conn_msginfo
.mi_hdr
.message
);
1220 (void) ndmp_send_response((ndmp_connection_t
*)
1221 connection
, err
, NULL
);
1222 ndmp_free_message((ndmp_connection_t
*)connection
);
1225 if (connection
->conn_msginfo
.mi_hdr
.message_type
1226 != NDMP_MESSAGE_REQUEST
) {
1227 NDMP_LOG(LOG_DEBUG
, "received reply: 0x%x",
1228 connection
->conn_msginfo
.mi_hdr
.message
);
1230 if (reply_expected
== FALSE
|| reply_read
== TRUE
) {
1232 "Unexpected reply message: 0x%x",
1233 connection
->conn_msginfo
.mi_hdr
.message
);
1234 ndmp_free_message((ndmp_connection_t
*)
1239 reply_msginfo
= connection
->conn_msginfo
;
1242 NDMP_LOG(LOG_DEBUG
, "received request: 0x%x",
1243 connection
->conn_msginfo
.mi_hdr
.message
);
1246 * The following is needed to catch an improperly constructed
1247 * handler table or to deal with an NDMP client that is not
1248 * conforming to the negotiated protocol version.
1250 if (connection
->conn_msginfo
.mi_handler
->mh_func
== NULL
) {
1251 NDMP_LOG(LOG_DEBUG
, "No handler for message 0x%x",
1252 connection
->conn_msginfo
.mi_hdr
.message
);
1254 (void) ndmp_send_response((ndmp_connection_t
*)
1255 connection
, NDMP_NOT_SUPPORTED_ERR
, NULL
);
1256 ndmp_free_message((ndmp_connection_t
*)connection
);
1260 * Call the handler function.
1261 * The handler will send any necessary reply.
1263 (*connection
->conn_msginfo
.mi_handler
->mh_func
) (connection
,
1264 connection
->conn_msginfo
.mi_body
);
1266 ndmp_free_message((ndmp_connection_t
*)connection
);
1268 } while (xdrrec_eof(&connection
->conn_xdrs
) == FALSE
&&
1269 connection
->conn_eof
== FALSE
);
1271 NDMP_LOG(LOG_DEBUG
, "no more messages in stream buffer");
1273 if (connection
->conn_eof
== TRUE
) {
1274 free(reply_msginfo
.mi_body
);
1275 return (NDMP_PROC_ERR
);
1278 free(reply_msginfo
.mi_body
);
1279 return (NDMP_PROC_REP_ERR
);
1282 connection
->conn_msginfo
= reply_msginfo
;
1283 return (NDMP_PROC_MSG
);
1285 return (NDMP_PROC_REP
);
1290 * ndmp_get_interface
1292 * Return the NDMP interface (e.g. config, scsi, tape) for the
1296 * message (input) - message number.
1299 * NULL - message not found.
1300 * pointer to handler info.
1302 static ndmp_handler_t
*
1303 ndmp_get_interface(ndmp_message message
)
1305 ndmp_handler_t
*ni
= &ndmp_msghdl_tab
[(message
>> 8) % INT_MAXCMD
];
1307 if ((message
& 0xff) >= ni
->hd_cnt
)
1311 if (ni
->hd_msgs
[message
& 0xff].hm_message
!= message
)
1320 * Return the handler info for the specified NDMP message.
1323 * connection (input) - connection pointer.
1324 * message (input) - message number.
1327 * NULL - message not found.
1328 * pointer to handler info.
1330 static ndmp_msg_handler_t
*
1331 ndmp_get_handler(ndmp_connection_t
*connection
, ndmp_message message
)
1333 ndmp_msg_handler_t
*handler
= NULL
;
1335 ndmp_handler_t
*ni
= ndmp_get_interface(message
);
1336 int ver
= connection
->conn_version
;
1339 handler
= &ni
->hd_msgs
[message
& 0xff].hm_msg_v
[ver
- 2];
1345 * ndmp_check_auth_required
1347 * Check if the connection needs to be authenticated before
1348 * this message is being processed.
1351 * message (input) - message number.
1355 * FALSE - not required
1358 ndmp_check_auth_required(ndmp_message message
)
1360 boolean_t auth_req
= FALSE
;
1361 ndmp_handler_t
*ni
= ndmp_get_interface(message
);
1364 auth_req
= ni
->hd_msgs
[message
& 0xff].hm_auth_required
;
1372 * A wrapper around accept for retrying and getting the IP address
1375 * listen_sock (input) - the socket for listening
1376 * inaddr_p (output) - the IP address of peer connection
1379 * socket for the accepted connection
1383 tcp_accept(int listen_sock
, unsigned int *inaddr_p
)
1385 struct sockaddr_in sin
;
1390 for (try = 0; try < 3; try++) {
1392 sock
= accept(listen_sock
, (struct sockaddr
*)&sin
, &i
);
1396 *inaddr_p
= sin
.sin_addr
.s_addr
;
1406 * Get the peer IP address for a connection
1409 * sock (input) - the active socket
1410 * inaddr_p (output) - the IP address of peer connection
1411 * port_p (output) - the port number of peer connection
1414 * socket for the accepted connection
1418 tcp_get_peer(int sock
, unsigned int *inaddr_p
, int *port_p
)
1420 struct sockaddr_in sin
;
1425 rc
= getpeername(sock
, (struct sockaddr
*)&sin
, &i
);
1430 *inaddr_p
= sin
.sin_addr
.s_addr
;
1433 *port_p
= ntohs(sin
.sin_port
);
1442 * Get the IP address string of the current host
1454 static char s
[MAXHOSTNAMELEN
];
1459 if (gethostname(s
, sizeof (s
)) == -1)
1462 if ((h
= gethostbyname(s
)) == NULL
)
1465 p
= h
->h_addr_list
[0];
1466 (void) memcpy(&in
.s_addr
, p
, sizeof (in
.s_addr
));
1467 return (inet_ntoa(in
));
1472 * get_default_nic_addr
1474 * Get the IP address of the default NIC
1477 get_default_nic_addr(void)
1479 struct ifaddrlist
*al
= NULL
;
1480 char errmsg
[ERRBUFSIZE
];
1481 struct in_addr addr
;
1484 nifs
= ifaddrlist(&al
, AF_INET
, LIFC_EXTERNAL_SOURCE
, errmsg
);
1488 /* pick the first interface's address */
1489 addr
= al
[0].addr
.addr
;
1492 return (inet_ntoa(IN_ADDR(addr
.s_addr
)));
1497 * ndmpd_audit_backup
1499 * Generate AUE_ndmp_backup audit record
1503 ndmpd_audit_backup(ndmp_connection_t
*conn
,
1504 char *path
, int dest
, char *local_path
, int result
)
1506 adt_event_data_t
*event
;
1508 if ((event
= adt_alloc_event(conn
->conn_ah
, ADT_ndmp_backup
)) == NULL
) {
1509 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1512 event
->adt_ndmp_backup
.source
= path
;
1514 if (dest
== NDMP_ADDR_LOCAL
) {
1515 event
->adt_ndmp_backup
.local_dest
= local_path
;
1517 event
->adt_ndmp_backup
.remote_dest
= conn
->conn_sock
;
1521 if (adt_put_event(event
, ADT_SUCCESS
, ADT_SUCCESS
) != 0)
1522 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1524 if (adt_put_event(event
, ADT_FAILURE
, result
) != 0)
1525 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1528 adt_free_event(event
);
1533 * ndmpd_audit_restore
1535 * Generate AUE_ndmp_restore audit record
1539 ndmpd_audit_restore(ndmp_connection_t
*conn
,
1540 char *path
, int dest
, char *local_path
, int result
)
1542 adt_event_data_t
*event
;
1544 if ((event
= adt_alloc_event(conn
->conn_ah
,
1545 ADT_ndmp_restore
)) == NULL
) {
1546 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1549 event
->adt_ndmp_restore
.destination
= path
;
1551 if (dest
== NDMP_ADDR_LOCAL
) {
1552 event
->adt_ndmp_restore
.local_source
= local_path
;
1554 event
->adt_ndmp_restore
.remote_source
= conn
->conn_sock
;
1558 if (adt_put_event(event
, ADT_SUCCESS
, ADT_SUCCESS
) != 0)
1559 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1561 if (adt_put_event(event
, ADT_FAILURE
, result
) != 0)
1562 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1565 adt_free_event(event
);
1570 * ndmpd_audit_connect
1572 * Generate AUE_ndmp_connect audit record
1576 ndmpd_audit_connect(ndmp_connection_t
*conn
, int result
)
1578 adt_event_data_t
*event
;
1579 adt_termid_t
*termid
;
1581 if (adt_load_termid(conn
->conn_sock
, &termid
) != 0) {
1582 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1586 if (adt_set_user(conn
->conn_ah
, ADT_NO_ATTRIB
, ADT_NO_ATTRIB
,
1587 ADT_NO_ATTRIB
, ADT_NO_ATTRIB
, termid
, ADT_NEW
) != 0) {
1588 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1594 if ((event
= adt_alloc_event(conn
->conn_ah
,
1595 ADT_ndmp_connect
)) == NULL
) {
1596 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1601 if (adt_put_event(event
, ADT_SUCCESS
, ADT_SUCCESS
) != 0)
1602 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1604 if (adt_put_event(event
, ADT_FAILURE
, result
) != 0)
1605 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1608 adt_free_event(event
);
1613 * ndmpd_audit_disconnect
1615 * Generate AUE_ndmp_disconnect audit record
1619 ndmpd_audit_disconnect(ndmp_connection_t
*conn
)
1621 adt_event_data_t
*event
;
1623 if ((event
= adt_alloc_event(conn
->conn_ah
,
1624 ADT_ndmp_disconnect
)) == NULL
) {
1625 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1628 if (adt_put_event(event
, ADT_SUCCESS
, ADT_SUCCESS
) != 0)
1629 NDMP_LOG(LOG_ERR
, "Audit failure: %m.");
1631 adt_free_event(event
);
1635 ndmp_malloc(size_t size
)
1639 if ((data
= calloc(1, size
)) == NULL
) {
1640 NDMP_LOG(LOG_ERR
, "Out of memory.");
1647 * get_backup_path_v3
1649 * Get the backup path from the NDMP environment variables.
1652 * params (input) - pointer to the parameters structure.
1655 * The backup path: if anything is specified
1659 get_backup_path_v3(ndmpd_module_params_t
*params
)
1663 bkpath
= MOD_GETENV(params
, "PREFIX");
1665 bkpath
= MOD_GETENV(params
, "FILESYSTEM");
1669 MOD_LOGV3(params
, NDMP_LOG_ERROR
,
1670 "Backup path not defined.\n");
1672 NDMP_LOG(LOG_DEBUG
, "bkpath: \"%s\"", bkpath
);
1681 * Find the backup path from the environment variables (v2)
1684 get_backup_path_v2(ndmpd_module_params_t
*params
)
1688 bkpath
= MOD_GETENV(params
, "PREFIX");
1690 bkpath
= MOD_GETENV(params
, "FILESYSTEM");
1692 if (bkpath
== NULL
) {
1693 MOD_LOG(params
, "Error: restore path not specified.\n");
1697 if (*bkpath
!= '/') {
1698 MOD_LOG(params
, "Error: relative backup path not allowed.\n");