1 /*
2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
4 */
5
6 /*
7 * BSD 3 Clause License
8 *
9 * Copyright (c) 2007, The Storage Networking Industry Association.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * - Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 *
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
20 * distribution.
21 *
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
26 *
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.
38 */
39 /* Copyright (c) 2007, The Storage Networking Industry Association. */
40 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
41
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <sys/time.h>
45 #include <sys/uio.h>
46 #include <unistd.h>
47 #include <string.h>
48 #include <stdlib.h>
49 #include <errno.h>
50 #include <netdb.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
53 #include <libinetutil.h>
54 #include "ndmpd.h"
55 #include "ndmpd_common.h"
56
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
61
62 /*
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.
65 */
67
68 /*
69 * The NDMP listening port number
70 */
71 int ndmp_port = 0;
72
73 /*
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.
78 */
79 int ndmp_full_restore_path = 1;
80
81 /*
82 * Do we support Direct Access Restore?
83 */
84 int ndmp_dar_support = 0;
85
86 /*
87 * ndmp_connection_t handler function
88 */
89 static ndmpd_file_handler_func_t connection_file_handler;
90
91 extern ndmp_handler_t ndmp_msghdl_tab[];
92
93 static int ndmp_readit(void *connection_handle,
94 caddr_t buf,
95 int len);
96 static int ndmp_writeit(void *connection_handle,
97 caddr_t buf,
98 int len);
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);
137 ndmp_connection_t *connection;
138
139 connection = ndmp_malloc(sizeof (ndmp_connection_t));
140 if (connection == NULL)
141 return (NULL);
142
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;
152
153 xdrrec_create(&connection->conn_xdrs, 0, 0, (caddr_t)connection,
154 ndmp_readit, ndmp_writeit);
155
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);
160 free(connection);
161 return (0);
162 }
163 return ((ndmp_connection_t *)connection);
164 }
165
166 /*
167 * ndmp_destroy_connection
168 *
169 * Shutdown a connection and release allocated resources.
170 *
171 * Parameters:
172 * connection_handle (Input) - connection handle.
173 *
174 * Returns:
175 * void
176 */
177 void
261 *
262 * Notes:
263 * This function does not return unless encountering an error
264 * related to the listen socket.
265 */
266 int
267 ndmp_run(ulong_t port, ndmp_con_handler_func_t con_handler_func)
268 {
269 int ns;
270 int on;
271 int server_socket;
272 unsigned int ipaddr;
273 struct sockaddr_in sin;
274 ndmpd_worker_arg_t *argp;
275
276 sin.sin_family = AF_INET;
277 sin.sin_addr.s_addr = INADDR_ANY;
278 sin.sin_port = htons(port);
279
280 if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
281 NDMP_LOG(LOG_DEBUG, "Socket error: %m");
282 return (-1);
283 }
284
285 on = 1;
286 (void) setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR,
287 (char *)&on, sizeof (on));
288
289
290 if (bind(server_socket, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
291 NDMP_LOG(LOG_DEBUG, "bind error: %m");
292 (void) close(server_socket);
293 return (-1);
294 }
295 if (listen(server_socket, 5) < 0) {
296 NDMP_LOG(LOG_DEBUG, "listen error: %m");
297 (void) close(server_socket);
298 return (-1);
299 }
300
301 for (; ; ) {
302 if ((ns = tcp_accept(server_socket, &ipaddr)) < 0) {
303 NDMP_LOG(LOG_DEBUG, "tcp_accept error: %m");
304 continue;
305 }
306 NDMP_LOG(LOG_DEBUG, "connection fd: %d", ns);
307 set_socket_options(ns);
308
309 if ((argp = ndmp_malloc(sizeof (ndmpd_worker_arg_t))) != NULL) {
310 argp->nw_sock = ns;
311 argp->nw_ipaddr = ipaddr;
312 argp->nw_con_handler_func = con_handler_func;
313 (void) ndmp_start_worker(argp);
314 }
315 }
316 }
317
318 /*
319 * ndmpd_worker thread
320 *
321 * Parameters:
322 * argp (input) - structure containing socket and handler function
323 *
324 * Returns:
325 * 0 - successful connection.
326 * -1 - error.
405 * Returns:
406 * 0 - successful send.
407 * -1 - error.
408 * otherwise - error from reply header.
409 *
410 * Notes:
411 * - The reply body is only returned if the error code is NDMP_NO_ERR.
412 */
413 int
414 ndmp_send_request(ndmp_connection_t *connection_handle, ndmp_message message,
415 ndmp_error err, void *request_data, void **reply)
416 {
417 ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
418 ndmp_header header;
419 ndmp_msg_handler_t *handler;
420 int r;
421 struct timeval time;
422
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",
426 message);
427 return (-1);
428 }
429 (void) gettimeofday(&time, 0);
430
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;
436 header.error = err;
437
438 connection->conn_xdrs.x_op = XDR_ENCODE;
439 if (!xdr_ndmp_header(&connection->conn_xdrs, &header)) {
440 NDMP_LOG(LOG_DEBUG,
441 "Sending message 0x%x: encoding request header", message);
442 (void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
443 return (-1);
444 }
445 if (err == NDMP_NO_ERR && handler->mh_xdr_request && request_data) {
446 if (!(*handler->mh_xdr_request)(&connection->conn_xdrs,
447 request_data)) {
448 NDMP_LOG(LOG_DEBUG,
449 "Sending message 0x%x: encoding request body",
450 message);
451 (void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
452 return (-1);
453 }
454 }
455 (void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
456
457 if (handler->mh_xdr_reply == 0) {
458 NDMP_LOG(LOG_DEBUG, "handler->mh_xdr_reply == 0");
459 return (0);
460 }
461
462 /*
463 * Process messages until the reply to this request has been
464 * processed.
465 */
466 for (; ; ) {
467 r = ndmp_process_messages(connection, TRUE);
468
469 /* connection error? */
470 if (r < 0)
471 return (-1);
472
473 /* no reply received? */
474 if (r == 0)
475 continue;
476
477 /* reply received? */
478 if (r == 1) {
479 if (message !=
480 connection->conn_msginfo.mi_hdr.message) {
481 NDMP_LOG(LOG_DEBUG,
482 "Received unexpected reply 0x%x",
483 connection->conn_msginfo.mi_hdr.message);
484 ndmp_free_message(connection_handle);
485 return (-1);
486 }
487 if (reply != NULL)
488 *reply = connection->conn_msginfo.mi_body;
489 else
490 ndmp_free_message(connection_handle);
491
492 return (connection->conn_msginfo.mi_hdr.error);
493 }
494 /* error handling reply */
495
496 return (-1);
497 }
498 }
499
500
501 /*
554 */
555 int
556 ndmp_send_response(ndmp_connection_t *connection_handle, ndmp_error err,
557 void *reply)
558 {
559 ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
560 ndmp_header header;
561 struct timeval time;
562
563 (void) gettimeofday(&time, 0);
564
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;
570 header.error = err;
571
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",
576 header.message);
577 (void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
578 return (-1);
579 }
580 if (err == NDMP_NO_ERR &&
581 connection->conn_msginfo.mi_handler->mh_xdr_reply &&
582 reply) {
583 if (!(*connection->conn_msginfo.mi_handler->mh_xdr_reply)(
584 &connection->conn_xdrs, reply)) {
585 NDMP_LOG(LOG_DEBUG,
586 "Sending message 0x%x: encoding reply body",
587 header.message);
588 (void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
589 return (-1);
590 }
591 }
592 (void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
593 return (0);
594 }
595
596 /*
597 * ndmp_free_message
598 *
599 * Free the memory of NDMP message body.
600 *
601 * Parameters:
602 * connection_handle (input) - connection pointer.
603 *
604 * Returns:
605 * void
841 return;
842
843 if (ndmp_lbr_init(&session) < 0)
844 return;
845
846 /*
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.
850 */
851 session.ns_mover.md_record_size = MAX_RECORD_SIZE;
852
853 ndmp_set_client_data(connection, (void *)&session);
854
855 req.reason = NDMP_CONNECTED;
856 req.protocol_version = ndmp_ver;
857 req.text_reason = "";
858
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");
862 return;
863 }
864 connection_fd = ndmp_get_fd(connection);
865
866 NDMP_LOG(LOG_DEBUG, "connection_fd: %d", connection_fd);
867
868 /*
869 * Add the handler function for the connection to the DMA.
870 */
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.");
874 return;
875 }
876
877 /*
878 * Register the connection in the list of active connections.
879 */
880 if (ndmp_connect_list_add(connection, &conn_id) != 0) {
881 NDMP_LOG(LOG_ERR,
882 "Could not register the session to the server.");
883 (void) ndmpd_remove_file_handler(&session, connection_fd);
884 return;
885 }
886
887 session.hardlink_q = hardlink_q_init();
888
889 while (session.ns_eof == FALSE)
890 (void) ndmpd_select(&session, TRUE, HC_ALL);
891
892 hardlink_q_cleanup(session.hardlink_q);
893
894 NDMP_LOG(LOG_DEBUG, "Connection terminated");
895
896 (void) ndmpd_remove_file_handler(&session, connection_fd);
897
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);
903 }
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);
909 }
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);
915
916 (void) ndmp_connect_list_del(connection);
917 }
918
919
920 /*
921 * connection_file_handler
922 *
923 * ndmp_connection_t file handler function.
924 * Called by ndmpd_select when data is available to be read on the
925 * NDMP connection.
1017 * Returns:
1018 * 0 - Message successfully received.
1019 * error number - Message related error.
1020 * -1 - Error decoding the message header.
1021 */
1022 static int
1023 ndmp_recv_msg(ndmp_connection_t *connection)
1024 {
1025 bool_t(*xdr_func) (XDR *, ...) = NULL;
1026
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))
1032 return (-1);
1033
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);
1040 }
1041 connection->conn_msginfo.mi_body = 0;
1042
1043 if (connection->conn_msginfo.mi_hdr.error != NDMP_NO_ERR)
1044 return (0);
1045
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) {
1052 NDMP_LOG(LOG_DEBUG,
1053 "Processing request 0x%x:connection not authorized",
1054 connection->conn_msginfo.mi_hdr.message);
1055 return (NDMP_NOT_AUTHORIZED_ERR);
1056 }
1057 if (connection->conn_msginfo.mi_handler->mh_sizeof_request >
1058 0) {
1059 xdr_func =
1060 connection->conn_msginfo.mi_handler->mh_xdr_request;
1061 if (xdr_func == NULL) {
1062 NDMP_LOG(LOG_DEBUG,
1063 "Processing request 0x%x: no xdr function "
1064 "in handler table",
1065 connection->conn_msginfo.mi_hdr.message);
1066 return (NDMP_NOT_SUPPORTED_ERR);
1067 }
1068 connection->conn_msginfo.mi_body = ndmp_malloc(
1069 connection->conn_msginfo.mi_handler->
1070 mh_sizeof_request);
1071 if (connection->conn_msginfo.mi_body == NULL)
1072 return (NDMP_NO_MEM_ERR);
1073
1074 (void) memset(connection->conn_msginfo.mi_body, 0,
1075 connection->conn_msginfo.mi_handler->
1076 mh_sizeof_request);
1077 }
1078 } else {
1079 if (connection->conn_msginfo.mi_handler->mh_sizeof_reply > 0) {
1080 xdr_func =
1081 connection->conn_msginfo.mi_handler->mh_xdr_reply;
1082 if (xdr_func == NULL) {
1083 NDMP_LOG(LOG_DEBUG,
1084 "Processing reply 0x%x: no xdr function "
1085 "in handler table",
1086 connection->conn_msginfo.mi_hdr.message);
1087 return (NDMP_NOT_SUPPORTED_ERR);
1088 }
1089 connection->conn_msginfo.mi_body = ndmp_malloc(
1090 connection->conn_msginfo.mi_handler->
1091 mh_sizeof_reply);
1092 if (connection->conn_msginfo.mi_body == NULL)
1093 return (NDMP_NO_MEM_ERR);
1094
1095 (void) memset(connection->conn_msginfo.mi_body, 0,
1096 connection->conn_msginfo.mi_handler->
1097 mh_sizeof_reply);
1098 }
1099 }
1100
1101 /* Decode message arguments if needed */
1102 if (xdr_func) {
1103 if (!(*xdr_func)(&connection->conn_xdrs,
1104 connection->conn_msginfo.mi_body)) {
1105 NDMP_LOG(LOG_DEBUG,
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);
1111 }
1112 }
1113 return (0);
1114 }
1115
1116 /*
1117 * ndmp_process_messages
1118 *
1119 * Reads the next message into the stream buffer.
1120 * Processes messages until the stream buffer is empty.
1121 *
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.
1151 * NDMP_PROC_REP_ERR - error; connection no longer established.
1152 *
1153 * Notes:
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
1157 * buffer is empty.
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.
1162 */
1163 static int
1164 ndmp_process_messages(ndmp_connection_t *connection, boolean_t reply_expected)
1165 {
1166 msg_info_t reply_msginfo;
1167 boolean_t reply_read = FALSE;
1168 boolean_t reply_error = FALSE;
1169 int err;
1170
1171 NDMP_LOG(LOG_DEBUG, "reply_expected: %s",
1172 reply_expected == TRUE ? "TRUE" : "FALSE");
1173
1174 (void) memset((void *)&reply_msginfo, 0, sizeof (msg_info_t));
1175
1176 do {
1177 (void) memset((void *)&connection->conn_msginfo, 0,
1178 sizeof (msg_info_t));
1179
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);
1184 }
1185 if (err < 1) {
1186 NDMP_LOG(LOG_DEBUG, "error decoding header");
1187
1188 /*
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
1198 * later.
1199 */
1200 if (reply_read == FALSE)
1201 reply_error = TRUE;
1202
1203 continue;
1204 }
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);
1209
1210 if (reply_expected == FALSE ||
1211 reply_read == TRUE)
1212 NDMP_LOG(LOG_DEBUG,
1213 "Unexpected reply message: 0x%x",
1214 connection->conn_msginfo.mi_hdr.
1215 message);
1216
1217 ndmp_free_message((ndmp_connection_t *)
1218 connection);
1219
1220 if (reply_read == FALSE) {
1221 reply_read = TRUE;
1222 reply_error = TRUE;
1223 }
1224 continue;
1225 }
1226 NDMP_LOG(LOG_DEBUG, "received request: 0x%x",
1227 connection->conn_msginfo.mi_hdr.message);
1228
1229 (void) ndmp_send_response((ndmp_connection_t *)
1230 connection, err, NULL);
1231 ndmp_free_message((ndmp_connection_t *)connection);
1232 continue;
1233 }
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);
1238
1239 if (reply_expected == FALSE || reply_read == TRUE) {
1240 NDMP_LOG(LOG_DEBUG,
1241 "Unexpected reply message: 0x%x",
1242 connection->conn_msginfo.mi_hdr.message);
1243 ndmp_free_message((ndmp_connection_t *)
1244 connection);
1245 continue;
1246 }
1247 reply_read = TRUE;
1248 reply_msginfo = connection->conn_msginfo;
1249 continue;
1250 }
1251 NDMP_LOG(LOG_DEBUG, "received request: 0x%x",
1252 connection->conn_msginfo.mi_hdr.message);
1253
1254 /*
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.
1258 */
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);
1262
1263 (void) ndmp_send_response((ndmp_connection_t *)
1264 connection, NDMP_NOT_SUPPORTED_ERR, NULL);
1265 ndmp_free_message((ndmp_connection_t *)connection);
1266 continue;
1267 }
1268 /*
1269 * Call the handler function.
1270 * The handler will send any necessary reply.
1271 */
1272 (*connection->conn_msginfo.mi_handler->mh_func) (connection,
1273 connection->conn_msginfo.mi_body);
1274
1275 ndmp_free_message((ndmp_connection_t *)connection);
1276
1277 } while (xdrrec_eof(&connection->conn_xdrs) == FALSE &&
1278 connection->conn_eof == FALSE);
1279
1280 NDMP_LOG(LOG_DEBUG, "no more messages in stream buffer");
1281
1282 if (connection->conn_eof == TRUE) {
1283 if (reply_msginfo.mi_body)
1284 free(reply_msginfo.mi_body);
1285 return (NDMP_PROC_ERR);
1286 }
1287 if (reply_error) {
1288 if (reply_msginfo.mi_body)
1289 free(reply_msginfo.mi_body);
1290 return (NDMP_PROC_REP_ERR);
1291 }
1292 if (reply_read) {
1293 connection->conn_msginfo = reply_msginfo;
1294 return (NDMP_PROC_MSG);
1295 }
1296 return (NDMP_PROC_REP);
1297 }
1298
1299
1300 /*
1301 * ndmp_get_interface
1498 addr = al[0].addr.addr;
1499 free(al);
1500
1501 return (inet_ntoa(IN_ADDR(addr.s_addr)));
1502 }
1503
1504
1505 /*
1506 * ndmpd_audit_backup
1507 *
1508 * Generate AUE_ndmp_backup audit record
1509 */
1510 /*ARGSUSED*/
1511 void
1512 ndmpd_audit_backup(ndmp_connection_t *conn,
1513 char *path, int dest, char *local_path, int result)
1514 {
1515 adt_event_data_t *event;
1516
1517 if ((event = adt_alloc_event(conn->conn_ah, ADT_ndmp_backup)) == NULL) {
1518 NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1519 return;
1520 }
1521 event->adt_ndmp_backup.source = path;
1522
1523 if (dest == NDMP_ADDR_LOCAL) {
1524 event->adt_ndmp_backup.local_dest = local_path;
1525 } else {
1526 event->adt_ndmp_backup.remote_dest = conn->conn_sock;
1527 }
1528
1529 if (result == 0) {
1530 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
1531 NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1532 } else {
1533 if (adt_put_event(event, ADT_FAILURE, result) != 0)
1534 NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1535 }
1536
1537 adt_free_event(event);
1538 }
1539
1540
1541 /*
1542 * ndmpd_audit_restore
1543 *
1544 * Generate AUE_ndmp_restore audit record
1545 */
1546 /*ARGSUSED*/
1547 void
1548 ndmpd_audit_restore(ndmp_connection_t *conn,
1549 char *path, int dest, char *local_path, int result)
1550 {
1551 adt_event_data_t *event;
1552
1553 if ((event = adt_alloc_event(conn->conn_ah,
1554 ADT_ndmp_restore)) == NULL) {
1555 NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1556 return;
1557 }
1558 event->adt_ndmp_restore.destination = path;
1559
1560 if (dest == NDMP_ADDR_LOCAL) {
1561 event->adt_ndmp_restore.local_source = local_path;
1562 } else {
1563 event->adt_ndmp_restore.remote_source = conn->conn_sock;
1564 }
1565
1566 if (result == 0) {
1567 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
1568 NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1569 } else {
1570 if (adt_put_event(event, ADT_FAILURE, result) != 0)
1571 NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1572 }
1573
1574 adt_free_event(event);
1575 }
1576
1577
1578 /*
1579 * ndmpd_audit_connect
1580 *
1581 * Generate AUE_ndmp_connect audit record
1582 */
1583 /*ARGSUSED*/
1584 void
1585 ndmpd_audit_connect(ndmp_connection_t *conn, int result)
1586 {
1587 adt_event_data_t *event;
1588 adt_termid_t *termid;
1589
1590 if (adt_load_termid(conn->conn_sock, &termid) != 0) {
1591 NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1592 return;
1593 }
1594
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.");
1598 free(termid);
1599 return;
1600 }
1601 free(termid);
1602
1603 if ((event = adt_alloc_event(conn->conn_ah,
1604 ADT_ndmp_connect)) == NULL) {
1605 NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1606 return;
1607 }
1608
1609 if (result == 0) {
1610 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
1611 NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1612 } else {
1613 if (adt_put_event(event, ADT_FAILURE, result) != 0)
1614 NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1615 }
1616
1617 adt_free_event(event);
1618 }
1619
1620
1621 /*
1622 * ndmpd_audit_disconnect
1623 *
1624 * Generate AUE_ndmp_disconnect audit record
1625 */
1626 /*ARGSUSED*/
1627 void
1628 ndmpd_audit_disconnect(ndmp_connection_t *conn)
1629 {
1630 adt_event_data_t *event;
1631
1632 if ((event = adt_alloc_event(conn->conn_ah,
1633 ADT_ndmp_disconnect)) == NULL) {
1634 NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1635 return;
1636 }
1637 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
1638 NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1639
1640 adt_free_event(event);
1641 }
1642
1643 void *
1644 ndmp_malloc(size_t size)
1645 {
1646 void *data;
1647
1648 if ((data = calloc(1, size)) == NULL) {
1649 NDMP_LOG(LOG_ERR, "Out of memory.");
1650 }
1651
1652 return (data);
1653 }
1654
1655 /*
1656 * get_backup_path_v3
1657 *
1658 * Get the backup path from the NDMP environment variables.
1659 *
1660 * Parameters:
1661 * params (input) - pointer to the parameters structure.
1662 *
1663 * Returns:
1664 * The backup path: if anything is specified
1665 * NULL: Otherwise
1666 */
1667 char *
1668 get_backup_path_v3(ndmpd_module_params_t *params)
1669 {
1670 char *bkpath;
1671
1672 bkpath = MOD_GETENV(params, "PREFIX");
1673 if (!bkpath)
1674 bkpath = MOD_GETENV(params, "FILESYSTEM");
1675
1676
1677 if (!bkpath) {
1678 MOD_LOGV3(params, NDMP_LOG_ERROR,
1679 "Backup path not defined.\n");
1680 } else {
1681 NDMP_LOG(LOG_DEBUG, "bkpath: \"%s\"", bkpath);
1682 }
1683
1684 return (bkpath);
1685 }
1686
1687 /*
1688 * get_backup_path
1689 *
1690 * Find the backup path from the environment variables (v2)
1691 */
1692 char *
1693 get_backup_path_v2(ndmpd_module_params_t *params)
1694 {
1695 char *bkpath;
1696
1697 bkpath = MOD_GETENV(params, "PREFIX");
1698 if (bkpath == NULL)
1699 bkpath = MOD_GETENV(params, "FILESYSTEM");
1700
1701 if (bkpath == NULL) {
|
1 /*
2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3 * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
4 */
5
6 /*
7 * BSD 3 Clause License
8 *
9 * Copyright (c) 2007, The Storage Networking Industry Association.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * - Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 *
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
20 * distribution.
21 *
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
26 *
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.
38 */
39 /* Copyright (c) 2007, The Storage Networking Industry Association. */
40 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
41
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <sys/time.h>
45 #include <sys/uio.h>
46 #include <syslog.h>
47 #include <unistd.h>
48 #include <string.h>
49 #include <stdlib.h>
50 #include <errno.h>
51 #include <netdb.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
54 #include <libinetutil.h>
55 #include "ndmpd.h"
56 #include "ndmpd_common.h"
57
58 #define NDMP_PROC_ERR -1
59 #define NDMP_PROC_MSG 1
60 #define NDMP_PROC_REP 0
61 #define NDMP_PROC_REP_ERR 2
62
63 /*
64 * The ndmp connection version can be set through command line. If command line
65 * is not specified it will be set from the ndmp SMF version property.
66 */
68
69 /*
70 * The NDMP listening port number
71 */
72 int ndmp_port = 0;
73
74 /*
75 * Restore path mechanism definition
76 * 0 means partial path restore and
77 * 1 means full path restore.
78 * Refer to NDMP_FULL_RESTORE_PATH for partial path and full path definition.
79 */
80 int ndmp_full_restore_path = 1;
81
82 /*
83 * Do we support Direct Access Restore?
84 */
85 int ndmp_dar_support = 0;
86
87 /*
88 * Is autosync enabled?
89 */
90 int ndmp_autosync_support = 0;
91
92 /*
93 * Is HPR snapshot enabled?
94 */
95 int ndmp_hpr_support = 0;
96
97 /*
98 * ndmp_connection_t handler function
99 */
100 static ndmpd_file_handler_func_t connection_file_handler;
101
102 extern ndmp_handler_t ndmp_msghdl_tab[];
103
104 static int ndmp_readit(void *connection_handle,
105 caddr_t buf,
106 int len);
107 static int ndmp_writeit(void *connection_handle,
108 caddr_t buf,
109 int len);
110 static int ndmp_recv_msg(ndmp_connection_t *connection);
111 static int ndmp_process_messages(ndmp_connection_t *connection,
112 boolean_t reply_expected);
113 static ndmp_msg_handler_t *ndmp_get_handler(ndmp_connection_t *connection,
114 ndmp_message message);
115 static boolean_t ndmp_check_auth_required(ndmp_message message);
116 static ndmp_handler_t *ndmp_get_interface(ndmp_message message);
117 void *ndmpd_worker(void *ptarg);
148 ndmp_connection_t *connection;
149
150 connection = ndmp_malloc(sizeof (ndmp_connection_t));
151 if (connection == NULL)
152 return (NULL);
153
154 connection->conn_sock = -1;
155 connection->conn_my_sequence = 0;
156 connection->conn_authorized = FALSE;
157 connection->conn_eof = FALSE;
158 connection->conn_msginfo.mi_body = 0;
159 connection->conn_version = ndmp_ver;
160 connection->conn_client_data = 0;
161 (void) mutex_init(&connection->conn_lock, 0, NULL);
162 connection->conn_xdrs.x_ops = 0;
163
164 xdrrec_create(&connection->conn_xdrs, 0, 0, (caddr_t)connection,
165 ndmp_readit, ndmp_writeit);
166
167 if (connection->conn_xdrs.x_ops == 0) {
168 syslog(LOG_ERR, "xdrrec_create failed");
169 (void) mutex_destroy(&connection->conn_lock);
170 (void) close(connection->conn_sock);
171 free(connection);
172 return (0);
173 }
174 return ((ndmp_connection_t *)connection);
175 }
176
177 /*
178 * ndmp_destroy_connection
179 *
180 * Shutdown a connection and release allocated resources.
181 *
182 * Parameters:
183 * connection_handle (Input) - connection handle.
184 *
185 * Returns:
186 * void
187 */
188 void
272 *
273 * Notes:
274 * This function does not return unless encountering an error
275 * related to the listen socket.
276 */
277 int
278 ndmp_run(ulong_t port, ndmp_con_handler_func_t con_handler_func)
279 {
280 int ns;
281 int on;
282 int server_socket;
283 unsigned int ipaddr;
284 struct sockaddr_in sin;
285 ndmpd_worker_arg_t *argp;
286
287 sin.sin_family = AF_INET;
288 sin.sin_addr.s_addr = INADDR_ANY;
289 sin.sin_port = htons(port);
290
291 if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
292 syslog(LOG_ERR, "Socket error: %m");
293 return (-1);
294 }
295
296 on = 1;
297 (void) setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR,
298 (char *)&on, sizeof (on));
299
300
301 if (bind(server_socket, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
302 syslog(LOG_ERR, "bind error: %m");
303 (void) close(server_socket);
304 return (-1);
305 }
306 if (listen(server_socket, 5) < 0) {
307 syslog(LOG_ERR, "listen error: %m");
308 (void) close(server_socket);
309 return (-1);
310 }
311
312 for (; ; ) {
313 if ((ns = tcp_accept(server_socket, &ipaddr)) < 0) {
314 syslog(LOG_ERR, "tcp_accept error: %m");
315 continue;
316 }
317 set_socket_options(ns);
318
319 if ((argp = ndmp_malloc(sizeof (ndmpd_worker_arg_t))) != NULL) {
320 argp->nw_sock = ns;
321 argp->nw_ipaddr = ipaddr;
322 argp->nw_con_handler_func = con_handler_func;
323 (void) ndmp_start_worker(argp);
324 }
325 }
326 }
327
328 /*
329 * ndmpd_worker thread
330 *
331 * Parameters:
332 * argp (input) - structure containing socket and handler function
333 *
334 * Returns:
335 * 0 - successful connection.
336 * -1 - error.
415 * Returns:
416 * 0 - successful send.
417 * -1 - error.
418 * otherwise - error from reply header.
419 *
420 * Notes:
421 * - The reply body is only returned if the error code is NDMP_NO_ERR.
422 */
423 int
424 ndmp_send_request(ndmp_connection_t *connection_handle, ndmp_message message,
425 ndmp_error err, void *request_data, void **reply)
426 {
427 ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
428 ndmp_header header;
429 ndmp_msg_handler_t *handler;
430 int r;
431 struct timeval time;
432
433 /* Lookup info necessary for processing this request. */
434 if (!(handler = ndmp_get_handler(connection, message))) {
435 syslog(LOG_ERR, "Sending message 0x%x: not supported",
436 message);
437 return (-1);
438 }
439 (void) gettimeofday(&time, 0);
440
441 header.sequence = ++(connection->conn_my_sequence);
442 header.time_stamp = time.tv_sec;
443 header.message_type = NDMP_MESSAGE_REQUEST;
444 header.message = message;
445 header.reply_sequence = 0;
446 header.error = err;
447
448 connection->conn_xdrs.x_op = XDR_ENCODE;
449 if (!xdr_ndmp_header(&connection->conn_xdrs, &header)) {
450 syslog(LOG_ERR,
451 "Sending message 0x%x: encoding request header", message);
452 (void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
453 return (-1);
454 }
455 if (err == NDMP_NO_ERR && handler->mh_xdr_request && request_data) {
456 if (!(*handler->mh_xdr_request)(&connection->conn_xdrs,
457 request_data)) {
458 syslog(LOG_ERR,
459 "Sending message 0x%x: encoding request body",
460 message);
461 (void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
462 return (-1);
463 }
464 }
465 (void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
466
467 if (handler->mh_xdr_reply == 0) {
468 return (0);
469 }
470
471 /*
472 * Process messages until the reply to this request has been
473 * processed.
474 */
475 for (; ; ) {
476 r = ndmp_process_messages(connection, TRUE);
477
478 /* connection error? */
479 if (r < 0)
480 return (-1);
481
482 /* no reply received? */
483 if (r == 0)
484 continue;
485
486 /* reply received? */
487 if (r == 1) {
488 if (message !=
489 connection->conn_msginfo.mi_hdr.message) {
490 syslog(LOG_ERR,
491 "Received unexpected reply 0x%x",
492 connection->conn_msginfo.mi_hdr.message);
493 ndmp_free_message(connection_handle);
494 return (-1);
495 }
496 if (reply != NULL)
497 *reply = connection->conn_msginfo.mi_body;
498 else
499 ndmp_free_message(connection_handle);
500
501 return (connection->conn_msginfo.mi_hdr.error);
502 }
503 /* error handling reply */
504
505 return (-1);
506 }
507 }
508
509
510 /*
563 */
564 int
565 ndmp_send_response(ndmp_connection_t *connection_handle, ndmp_error err,
566 void *reply)
567 {
568 ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
569 ndmp_header header;
570 struct timeval time;
571
572 (void) gettimeofday(&time, 0);
573
574 header.sequence = ++(connection->conn_my_sequence);
575 header.time_stamp = time.tv_sec;
576 header.message_type = NDMP_MESSAGE_REPLY;
577 header.message = connection->conn_msginfo.mi_hdr.message;
578 header.reply_sequence = connection->conn_msginfo.mi_hdr.sequence;
579 header.error = err;
580
581 connection->conn_xdrs.x_op = XDR_ENCODE;
582 if (!xdr_ndmp_header(&connection->conn_xdrs, &header)) {
583 syslog(LOG_ERR, "Sending message 0x%x: "
584 "encoding reply header",
585 header.message);
586 (void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
587 return (-1);
588 }
589 if (err == NDMP_NO_ERR &&
590 connection->conn_msginfo.mi_handler->mh_xdr_reply &&
591 reply) {
592 if (!(*connection->conn_msginfo.mi_handler->mh_xdr_reply)(
593 &connection->conn_xdrs, reply)) {
594 syslog(LOG_ERR,
595 "Sending message 0x%x: encoding reply body",
596 header.message);
597 (void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
598 return (-1);
599 }
600 }
601 (void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
602 return (0);
603 }
604
605 /*
606 * ndmp_free_message
607 *
608 * Free the memory of NDMP message body.
609 *
610 * Parameters:
611 * connection_handle (input) - connection pointer.
612 *
613 * Returns:
614 * void
850 return;
851
852 if (ndmp_lbr_init(&session) < 0)
853 return;
854
855 /*
856 * Setup defaults here. The init functions can not set defaults
857 * since the init functions are called by the stop request handlers
858 * and client set variables need to persist across data operations.
859 */
860 session.ns_mover.md_record_size = MAX_RECORD_SIZE;
861
862 ndmp_set_client_data(connection, (void *)&session);
863
864 req.reason = NDMP_CONNECTED;
865 req.protocol_version = ndmp_ver;
866 req.text_reason = "";
867
868 if (ndmp_send_request_lock(connection, NDMP_NOTIFY_CONNECTION_STATUS,
869 NDMP_NO_ERR, (void *)&req, 0) < 0) {
870 syslog(LOG_DEBUG, "Send CONNECTION STATUS failed");
871 return;
872 }
873 connection_fd = ndmp_get_fd(connection);
874
875 /*
876 * Add the handler function for the connection to the DMA.
877 */
878 if (ndmpd_add_file_handler(&session, (void *)&session, connection_fd,
879 NDMPD_SELECT_MODE_READ, HC_CLIENT, connection_file_handler) != 0) {
880 syslog(LOG_ERR, "Could not register session handler.");
881 return;
882 }
883
884 /*
885 * Register the connection in the list of active connections.
886 */
887 if (ndmp_connect_list_add(connection, &conn_id) != 0) {
888 syslog(LOG_ERR,
889 "Could not register the session to the server.");
890 (void) ndmpd_remove_file_handler(&session, connection_fd);
891 return;
892 }
893
894 session.hardlink_q = hardlink_q_init();
895
896 while (session.ns_eof == FALSE)
897 (void) ndmpd_select(&session, TRUE, HC_ALL);
898
899 hardlink_q_cleanup(session.hardlink_q);
900
901 (void) ndmpd_remove_file_handler(&session, connection_fd);
902
903 if (session.ns_scsi.sd_is_open != -1) {
904 syslog(LOG_ERR, "scsi.is_open: %d",
905 session.ns_scsi.sd_is_open);
906 (void) ndmp_open_list_del(session.ns_scsi.sd_adapter_name,
907 session.ns_scsi.sd_sid, session.ns_scsi.sd_lun);
908 }
909 if (session.ns_tape.td_fd != -1) {
910 syslog(LOG_ERR, "tape.fd: %d", session.ns_tape.td_fd);
911 (void) close(session.ns_tape.td_fd);
912 (void) ndmp_open_list_del(session.ns_tape.td_adapter_name,
913 session.ns_tape.td_sid, session.ns_tape.td_lun);
914 }
915 ndmpd_mover_shut_down(&session);
916 ndmp_lbr_cleanup(&session);
917 ndmpd_data_cleanup(&session);
918 ndmpd_file_history_cleanup(&session, FALSE);
919 ndmpd_mover_cleanup(&session);
920
921 (void) ndmp_connect_list_del(connection);
922 }
923
924
925 /*
926 * connection_file_handler
927 *
928 * ndmp_connection_t file handler function.
929 * Called by ndmpd_select when data is available to be read on the
930 * NDMP connection.
1022 * Returns:
1023 * 0 - Message successfully received.
1024 * error number - Message related error.
1025 * -1 - Error decoding the message header.
1026 */
1027 static int
1028 ndmp_recv_msg(ndmp_connection_t *connection)
1029 {
1030 bool_t(*xdr_func) (XDR *, ...) = NULL;
1031
1032 /* Decode the header. */
1033 connection->conn_xdrs.x_op = XDR_DECODE;
1034 (void) xdrrec_skiprecord(&connection->conn_xdrs);
1035 if (!xdr_ndmp_header(&connection->conn_xdrs,
1036 &connection->conn_msginfo.mi_hdr))
1037 return (-1);
1038
1039 /* Lookup info necessary for processing this message. */
1040 if ((connection->conn_msginfo.mi_handler = ndmp_get_handler(connection,
1041 connection->conn_msginfo.mi_hdr.message)) == 0) {
1042 syslog(LOG_DEBUG, "Message 0x%x not supported",
1043 connection->conn_msginfo.mi_hdr.message);
1044 return (NDMP_NOT_SUPPORTED_ERR);
1045 }
1046 connection->conn_msginfo.mi_body = 0;
1047
1048 if (connection->conn_msginfo.mi_hdr.error != NDMP_NO_ERR)
1049 return (0);
1050
1051 /* Determine body type */
1052 if (connection->conn_msginfo.mi_hdr.message_type ==
1053 NDMP_MESSAGE_REQUEST) {
1054 if (ndmp_check_auth_required(
1055 connection->conn_msginfo.mi_hdr.message) &&
1056 !connection->conn_authorized) {
1057 syslog(LOG_ERR,
1058 "Processing request 0x%x:connection not authorized",
1059 connection->conn_msginfo.mi_hdr.message);
1060 return (NDMP_NOT_AUTHORIZED_ERR);
1061 }
1062 if (connection->conn_msginfo.mi_handler->mh_sizeof_request >
1063 0) {
1064 xdr_func =
1065 connection->conn_msginfo.mi_handler->mh_xdr_request;
1066 if (xdr_func == NULL) {
1067 syslog(LOG_ERR,
1068 "Processing request 0x%x: no xdr function "
1069 "in handler table",
1070 connection->conn_msginfo.mi_hdr.message);
1071 return (NDMP_NOT_SUPPORTED_ERR);
1072 }
1073 connection->conn_msginfo.mi_body = ndmp_malloc(
1074 connection->conn_msginfo.mi_handler->
1075 mh_sizeof_request);
1076 if (connection->conn_msginfo.mi_body == NULL)
1077 return (NDMP_NO_MEM_ERR);
1078
1079 (void) memset(connection->conn_msginfo.mi_body, 0,
1080 connection->conn_msginfo.mi_handler->
1081 mh_sizeof_request);
1082 }
1083 } else {
1084 if (connection->conn_msginfo.mi_handler->mh_sizeof_reply > 0) {
1085 xdr_func =
1086 connection->conn_msginfo.mi_handler->mh_xdr_reply;
1087 if (xdr_func == NULL) {
1088 syslog(LOG_ERR,
1089 "Processing reply 0x%x: no xdr function "
1090 "in handler table",
1091 connection->conn_msginfo.mi_hdr.message);
1092 return (NDMP_NOT_SUPPORTED_ERR);
1093 }
1094 connection->conn_msginfo.mi_body = ndmp_malloc(
1095 connection->conn_msginfo.mi_handler->
1096 mh_sizeof_reply);
1097 if (connection->conn_msginfo.mi_body == NULL)
1098 return (NDMP_NO_MEM_ERR);
1099
1100 (void) memset(connection->conn_msginfo.mi_body, 0,
1101 connection->conn_msginfo.mi_handler->
1102 mh_sizeof_reply);
1103 }
1104 }
1105
1106 /* Decode message arguments if needed */
1107 if (xdr_func) {
1108 if (!(*xdr_func)(&connection->conn_xdrs,
1109 connection->conn_msginfo.mi_body)) {
1110 syslog(LOG_ERR,
1111 "Processing %s message 0x%x: "
1112 "error decoding arguments",
1113 connection->conn_msginfo.mi_hdr.message_type ==
1114 NDMP_MESSAGE_REQUEST ?
1115 "Request" : "Reply",
1116 connection->conn_msginfo.mi_hdr.message);
1117 free(connection->conn_msginfo.mi_body);
1118 connection->conn_msginfo.mi_body = 0;
1119 return (NDMP_XDR_DECODE_ERR);
1120 }
1121 }
1122 return (0);
1123 }
1124
1125 /*
1126 * ndmp_process_messages
1127 *
1128 * Reads the next message into the stream buffer.
1129 * Processes messages until the stream buffer is empty.
1130 *
1131 * This function processes all data in the stream buffer before returning.
1132 * This allows functions like poll() to be used to determine when new
1133 * messages have arrived. If only some of the messages in the stream buffer
1134 * were processed and then poll was called, poll() could block waiting for
1135 * a message that had already been received and read into the stream buffer.
1160 * NDMP_PROC_REP_ERR - error; connection no longer established.
1161 *
1162 * Notes:
1163 * If the peer is generating a large number of requests, a caller
1164 * looking for a reply will be blocked while the requests are handled.
1165 * This is because this function does not return until the stream
1166 * buffer is empty.
1167 * Code needs to be added to allow a return if the stream buffer
1168 * is not empty but there is data available on the socket. This will
1169 * prevent poll() from blocking and prevent a caller looking for a reply
1170 * from getting blocked by a bunch of requests.
1171 */
1172 static int
1173 ndmp_process_messages(ndmp_connection_t *connection, boolean_t reply_expected)
1174 {
1175 msg_info_t reply_msginfo;
1176 boolean_t reply_read = FALSE;
1177 boolean_t reply_error = FALSE;
1178 int err;
1179
1180 (void) memset((void *)&reply_msginfo, 0, sizeof (msg_info_t));
1181
1182 do {
1183 (void) memset((void *)&connection->conn_msginfo, 0,
1184 sizeof (msg_info_t));
1185
1186 if ((err = ndmp_recv_msg(connection)) != NDMP_NO_ERR) {
1187 if (connection->conn_eof) {
1188 return (NDMP_PROC_ERR);
1189 }
1190 if (err < 1) {
1191 syslog(LOG_ERR, "error decoding header");
1192
1193 /*
1194 * Error occurred decoding the header.
1195 * Don't send a reply since we don't know
1196 * the message or if the message was even
1197 * a request message. To be safe, assume
1198 * that the message was a reply if a reply
1199 * was expected. Need to do this to prevent
1200 * hanging ndmp_send_request() waiting for a
1201 * reply. Don't set reply_read so that the
1202 * reply will be processed if it is received
1203 * later.
1204 */
1205 if (reply_read == FALSE)
1206 reply_error = TRUE;
1207
1208 continue;
1209 }
1210 if (connection->conn_msginfo.mi_hdr.message_type
1211 != NDMP_MESSAGE_REQUEST) {
1212 syslog(LOG_DEBUG, "received reply: 0x%x",
1213 connection->conn_msginfo.mi_hdr.message);
1214
1215 if (reply_expected == FALSE ||
1216 reply_read == TRUE)
1217 syslog(LOG_DEBUG,
1218 "Unexpected reply message: 0x%x",
1219 connection->conn_msginfo.mi_hdr.
1220 message);
1221
1222 ndmp_free_message((ndmp_connection_t *)
1223 connection);
1224
1225 if (reply_read == FALSE) {
1226 reply_read = TRUE;
1227 reply_error = TRUE;
1228 }
1229 continue;
1230 }
1231
1232 (void) ndmp_send_response((ndmp_connection_t *)
1233 connection, err, NULL);
1234 ndmp_free_message((ndmp_connection_t *)connection);
1235 continue;
1236 }
1237 if (connection->conn_msginfo.mi_hdr.message_type
1238 != NDMP_MESSAGE_REQUEST) {
1239 syslog(LOG_DEBUG, "received reply: 0x%x",
1240 connection->conn_msginfo.mi_hdr.message);
1241
1242 if (reply_expected == FALSE || reply_read == TRUE) {
1243 syslog(LOG_DEBUG,
1244 "Unexpected reply message: 0x%x",
1245 connection->conn_msginfo.mi_hdr.message);
1246 ndmp_free_message((ndmp_connection_t *)
1247 connection);
1248 continue;
1249 }
1250 reply_read = TRUE;
1251 reply_msginfo = connection->conn_msginfo;
1252 continue;
1253 }
1254 /*
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.
1258 */
1259 if (connection->conn_msginfo.mi_handler->mh_func == NULL) {
1260 syslog(LOG_DEBUG, "No handler for message 0x%x",
1261 connection->conn_msginfo.mi_hdr.message);
1262
1263 (void) ndmp_send_response((ndmp_connection_t *)
1264 connection, NDMP_NOT_SUPPORTED_ERR, NULL);
1265 ndmp_free_message((ndmp_connection_t *)connection);
1266 continue;
1267 }
1268 /*
1269 * Call the handler function.
1270 * The handler will send any necessary reply.
1271 */
1272 (*connection->conn_msginfo.mi_handler->mh_func) (connection,
1273 connection->conn_msginfo.mi_body);
1274
1275 ndmp_free_message((ndmp_connection_t *)connection);
1276
1277 } while (xdrrec_eof(&connection->conn_xdrs) == FALSE &&
1278 connection->conn_eof == FALSE);
1279
1280 if (connection->conn_eof == TRUE) {
1281 if (reply_msginfo.mi_body)
1282 free(reply_msginfo.mi_body);
1283 return (NDMP_PROC_ERR);
1284 }
1285 if (reply_error) {
1286 if (reply_msginfo.mi_body)
1287 free(reply_msginfo.mi_body);
1288 return (NDMP_PROC_REP_ERR);
1289 }
1290 if (reply_read) {
1291 connection->conn_msginfo = reply_msginfo;
1292 return (NDMP_PROC_MSG);
1293 }
1294 return (NDMP_PROC_REP);
1295 }
1296
1297
1298 /*
1299 * ndmp_get_interface
1496 addr = al[0].addr.addr;
1497 free(al);
1498
1499 return (inet_ntoa(IN_ADDR(addr.s_addr)));
1500 }
1501
1502
1503 /*
1504 * ndmpd_audit_backup
1505 *
1506 * Generate AUE_ndmp_backup audit record
1507 */
1508 /*ARGSUSED*/
1509 void
1510 ndmpd_audit_backup(ndmp_connection_t *conn,
1511 char *path, int dest, char *local_path, int result)
1512 {
1513 adt_event_data_t *event;
1514
1515 if ((event = adt_alloc_event(conn->conn_ah, ADT_ndmp_backup)) == NULL) {
1516 syslog(LOG_ERR, "Audit failure: %m.");
1517 return;
1518 }
1519 event->adt_ndmp_backup.source = path;
1520
1521 if (dest == NDMP_ADDR_LOCAL) {
1522 event->adt_ndmp_backup.local_dest = local_path;
1523 } else {
1524 event->adt_ndmp_backup.remote_dest = conn->conn_sock;
1525 }
1526
1527 if (result == 0) {
1528 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
1529 syslog(LOG_ERR, "Audit failure: %m.");
1530 } else {
1531 if (adt_put_event(event, ADT_FAILURE, result) != 0)
1532 syslog(LOG_ERR, "Audit failure: %m.");
1533 }
1534
1535 adt_free_event(event);
1536 }
1537
1538
1539 /*
1540 * ndmpd_audit_restore
1541 *
1542 * Generate AUE_ndmp_restore audit record
1543 */
1544 /*ARGSUSED*/
1545 void
1546 ndmpd_audit_restore(ndmp_connection_t *conn,
1547 char *path, int dest, char *local_path, int result)
1548 {
1549 adt_event_data_t *event;
1550
1551 if ((event = adt_alloc_event(conn->conn_ah,
1552 ADT_ndmp_restore)) == NULL) {
1553 syslog(LOG_ERR, "Audit failure: %m.");
1554 return;
1555 }
1556 event->adt_ndmp_restore.destination = path;
1557
1558 if (dest == NDMP_ADDR_LOCAL) {
1559 event->adt_ndmp_restore.local_source = local_path;
1560 } else {
1561 event->adt_ndmp_restore.remote_source = conn->conn_sock;
1562 }
1563
1564 if (result == 0) {
1565 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
1566 syslog(LOG_ERR, "Audit failure: %m.");
1567 } else {
1568 if (adt_put_event(event, ADT_FAILURE, result) != 0)
1569 syslog(LOG_ERR, "Audit failure: %m.");
1570 }
1571
1572 adt_free_event(event);
1573 }
1574
1575
1576 /*
1577 * ndmpd_audit_connect
1578 *
1579 * Generate AUE_ndmp_connect audit record
1580 */
1581 /*ARGSUSED*/
1582 void
1583 ndmpd_audit_connect(ndmp_connection_t *conn, int result)
1584 {
1585 adt_event_data_t *event;
1586 adt_termid_t *termid;
1587
1588 if (adt_load_termid(conn->conn_sock, &termid) != 0) {
1589 syslog(LOG_ERR, "Audit failure: %m.");
1590 return;
1591 }
1592
1593 if (adt_set_user(conn->conn_ah, ADT_NO_ATTRIB, ADT_NO_ATTRIB,
1594 ADT_NO_ATTRIB, ADT_NO_ATTRIB, termid, ADT_NEW) != 0) {
1595 syslog(LOG_ERR, "Audit failure: %m.");
1596 free(termid);
1597 return;
1598 }
1599 free(termid);
1600
1601 if ((event = adt_alloc_event(conn->conn_ah,
1602 ADT_ndmp_connect)) == NULL) {
1603 syslog(LOG_ERR, "Audit failure: %m.");
1604 return;
1605 }
1606
1607 if (result == 0) {
1608 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
1609 syslog(LOG_ERR, "Audit failure: %m.");
1610 } else {
1611 if (adt_put_event(event, ADT_FAILURE, result) != 0)
1612 syslog(LOG_ERR, "Audit failure: %m.");
1613 }
1614
1615 adt_free_event(event);
1616 }
1617
1618
1619 /*
1620 * ndmpd_audit_disconnect
1621 *
1622 * Generate AUE_ndmp_disconnect audit record
1623 */
1624 /*ARGSUSED*/
1625 void
1626 ndmpd_audit_disconnect(ndmp_connection_t *conn)
1627 {
1628 adt_event_data_t *event;
1629
1630 if ((event = adt_alloc_event(conn->conn_ah,
1631 ADT_ndmp_disconnect)) == NULL) {
1632 syslog(LOG_ERR, "Audit failure: %m.");
1633 return;
1634 }
1635 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
1636 syslog(LOG_ERR, "Audit failure: %m.");
1637
1638 adt_free_event(event);
1639 }
1640
1641 void *
1642 ndmp_malloc(size_t size)
1643 {
1644 void *data;
1645
1646 if ((data = calloc(1, size)) == NULL) {
1647 syslog(LOG_ERR, "Out of memory.");
1648 }
1649
1650 return (data);
1651 }
1652
1653 /*
1654 * get_backup_path_v3
1655 *
1656 * Get the backup path from the NDMP environment variables.
1657 *
1658 * Parameters:
1659 * params (input) - pointer to the parameters structure.
1660 *
1661 * Returns:
1662 * The backup path: if anything is specified
1663 * NULL: Otherwise
1664 */
1665 char *
1666 get_backup_path_v3(ndmpd_module_params_t *params)
1667 {
1668 char *bkpath;
1669
1670 bkpath = MOD_GETENV(params, "PREFIX");
1671 if (!bkpath)
1672 bkpath = MOD_GETENV(params, "FILESYSTEM");
1673
1674
1675 if (!bkpath) {
1676 MOD_LOGV3(params, NDMP_LOG_ERROR,
1677 "Backup path not defined.\n");
1678 } else {
1679 syslog(LOG_DEBUG, "bkpath: \"%s\"", bkpath);
1680 }
1681
1682 return (bkpath);
1683 }
1684
1685 /*
1686 * get_backup_path
1687 *
1688 * Find the backup path from the environment variables (v2)
1689 */
1690 char *
1691 get_backup_path_v2(ndmpd_module_params_t *params)
1692 {
1693 char *bkpath;
1694
1695 bkpath = MOD_GETENV(params, "PREFIX");
1696 if (bkpath == NULL)
1697 bkpath = MOD_GETENV(params, "FILESYSTEM");
1698
1699 if (bkpath == NULL) {
|