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) {
 |