Home | History | Annotate | Download | only in ndmp
      1 /*
      2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      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
     24  *	  products derived from this software without specific prior written
     25  *	  permission.
     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 "ndmpd.h"
     54 #include "ndmpd_common.h"
     55 
     56 #define	NDMP_PROC_ERR	-1
     57 #define	NDMP_PROC_MSG	1
     58 #define	NDMP_PROC_REP	0
     59 #define	NDMP_PROC_REP_ERR	2
     60 
     61 /*
     62  * The ndmp connection version can be set through command line. If command line
     63  * is not specified it will be set from the ndmp SMF version property.
     64  */
     65 int ndmp_ver = 0;
     66 
     67 /*
     68  * The NDMP listening port number
     69  */
     70 int ndmp_port = 0;
     71 
     72 /*
     73  * Restore path mechanism definition
     74  * 0 means partial path restore and
     75  * 1 means full path restore.
     76  * Refer to NDMP_FULL_RESTORE_PATH for partial path and full path definition.
     77  */
     78 int ndmp_full_restore_path = 1;
     79 
     80 /*
     81  * Do we support Direct Access Restore?
     82  */
     83 int ndmp_dar_support = 0;
     84 
     85 /*
     86  * ndmp_connection_t handler function
     87  */
     88 static ndmpd_file_handler_func_t connection_file_handler;
     89 
     90 extern ndmp_handler_t ndmp_msghdl_tab[];
     91 
     92 static int ndmp_readit(void *connection_handle,
     93     caddr_t buf,
     94     int len);
     95 static int ndmp_writeit(void *connection_handle,
     96     caddr_t buf,
     97     int len);
     98 static int ndmp_recv_msg(ndmp_connection_t *connection);
     99 static int ndmp_process_messages(ndmp_connection_t *connection,
    100     boolean_t reply_expected);
    101 static ndmp_msg_handler_t *ndmp_get_handler(ndmp_connection_t *connection,
    102     ndmp_message message);
    103 static boolean_t ndmp_check_auth_required(ndmp_message message);
    104 static ndmp_handler_t *ndmp_get_interface(ndmp_message message);
    105 void *ndmpd_worker(void *ptarg);
    106 
    107 #ifdef	lint
    108 bool_t
    109 xdr_ndmp_header(XDR *xdrs, ndmp_header *objp)
    110 {
    111 	xdrs = xdrs;
    112 	objp = objp;
    113 	return (0);
    114 }
    115 #endif	/* lint */
    116 
    117 /*
    118  * ndmp_create_connection
    119  *
    120  * Allocate and initialize a connection structure.
    121  *
    122  * Parameters:
    123  *   handler_tbl (input) - message handlers.
    124  *
    125  * Returns:
    126  *   NULL - error
    127  *   connection pointer
    128  *
    129  * Notes:
    130  *   The returned connection should be destroyed using
    131  *   ndmp_destroy_connection().
    132  */
    133 ndmp_connection_t *
    134 ndmp_create_connection(void)
    135 {
    136 	ndmp_connection_t *connection;
    137 
    138 	connection = ndmp_malloc(sizeof (ndmp_connection_t));
    139 	if (connection == NULL)
    140 		return (NULL);
    141 
    142 	connection->conn_sock = -1;
    143 	connection->conn_my_sequence = 0;
    144 	connection->conn_authorized = FALSE;
    145 	connection->conn_eof = FALSE;
    146 	connection->conn_msginfo.mi_body = 0;
    147 	connection->conn_version = ndmp_ver;
    148 	connection->conn_client_data = 0;
    149 	(void) mutex_init(&connection->conn_lock, 0, NULL);
    150 	connection->conn_xdrs.x_ops = 0;
    151 
    152 	xdrrec_create(&connection->conn_xdrs, 0, 0, (caddr_t)connection,
    153 	    ndmp_readit, ndmp_writeit);
    154 
    155 	if (connection->conn_xdrs.x_ops == 0) {
    156 		NDMP_LOG(LOG_DEBUG, "xdrrec_create failed");
    157 		(void) mutex_destroy(&connection->conn_lock);
    158 		(void) close(connection->conn_sock);
    159 		free(connection);
    160 		return (0);
    161 	}
    162 	return ((ndmp_connection_t *)connection);
    163 }
    164 
    165 /*
    166  * ndmp_destroy_connection
    167  *
    168  * Shutdown a connection and release allocated resources.
    169  *
    170  * Parameters:
    171  *   connection_handle (Input) - connection handle.
    172  *
    173  * Returns:
    174  *   void
    175  */
    176 void
    177 ndmp_destroy_connection(ndmp_connection_t *connection_handle)
    178 {
    179 	ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
    180 
    181 	if (connection->conn_sock >= 0) {
    182 		(void) mutex_destroy(&connection->conn_lock);
    183 		(void) close(connection->conn_sock);
    184 		connection->conn_sock = -1;
    185 	}
    186 	xdr_destroy(&connection->conn_xdrs);
    187 	free(connection);
    188 }
    189 
    190 
    191 /*
    192  * ndmp_close
    193  *
    194  * Close a connection.
    195  *
    196  * Parameters:
    197  *   connection_handle (Input) - connection handle.
    198  *
    199  * Returns:
    200  *   void
    201  */
    202 void
    203 ndmp_close(ndmp_connection_t *connection_handle)
    204 {
    205 	ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
    206 
    207 	ndmpd_audit_disconnect(connection);
    208 	if (connection->conn_sock >= 0) {
    209 		(void) mutex_destroy(&connection->conn_lock);
    210 		(void) close(connection->conn_sock);
    211 		connection->conn_sock = -1;
    212 	}
    213 	connection->conn_eof = TRUE;
    214 
    215 	/*
    216 	 * We should close all the tapes that are used by this connection.
    217 	 * In some cases the ndmp client opens a tape, but does not close the
    218 	 * tape and closes the connection.
    219 	 */
    220 	ndmp_open_list_release(connection_handle);
    221 }
    222 
    223 /*
    224  * ndmp_start_worker
    225  *
    226  * Initializes and starts a ndmp_worker thread
    227  */
    228 int
    229 ndmp_start_worker(ndmpd_worker_arg_t *argp)
    230 {
    231 	pthread_attr_t tattr;
    232 	int rc;
    233 
    234 	(void) pthread_attr_init(&tattr);
    235 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
    236 	rc = pthread_create(NULL, &tattr, ndmpd_worker, (void *)argp);
    237 	(void) pthread_attr_destroy(&tattr);
    238 	return (rc);
    239 }
    240 
    241 /*
    242  * ndmp_run
    243  *
    244  * Creates a socket for listening and accepting connections
    245  * from NDMP clients.
    246  * Accepts connections and passes each connection to the connection
    247  * handler.
    248  *
    249  * Parameters:
    250  *   port (input)   -  NDMP server port.
    251  *		     If 0, the port number will be retrieved from
    252  *		     the network service database. If not found there,
    253  *		     the default NDMP port number (from ndmp.x)
    254  *		     will be used.
    255  *   handler (input) - connection handler function.
    256  *
    257  * Returns:
    258  *   This function normally never returns unless there's error.
    259  *   -1 : error
    260  *
    261  * Notes:
    262  *   This function does not return unless encountering an error
    263  *   related to the listen socket.
    264  */
    265 int
    266 ndmp_run(ulong_t port, ndmp_con_handler_func_t con_handler_func)
    267 {
    268 	int ns;
    269 	int on, tmp;
    270 	int server_socket;
    271 	unsigned int ipaddr;
    272 	struct sockaddr_in sin;
    273 	int flag = 1;
    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 
    307 		NDMP_LOG(LOG_DEBUG, "connection fd: %d", ns);
    308 
    309 		/*
    310 		 * 'css' and 'crs' in the following env variables stand for:
    311 		 * 'connection send size' and 'connection receive size'.
    312 		 */
    313 		tmp = atoi((const char *)ndmpd_get_prop_default(NDMP_SOCKET_CSS,
    314 		    "65"));
    315 		if (tmp <= 0)
    316 			tmp = 65;
    317 		NDMP_LOG(LOG_DEBUG, "css: %d_KB", tmp);
    318 		ndmp_set_socket_snd_buf(ns, tmp * KILOBYTE);
    319 
    320 		tmp = atoi((const char *)ndmpd_get_prop_default(NDMP_SOCKET_CRS,
    321 		    "80"));
    322 		if (tmp <= 0)
    323 			tmp = 80;
    324 		NDMP_LOG(LOG_DEBUG, "crs: %d_KB", tmp);
    325 		ndmp_set_socket_rcv_buf(ns, tmp * KILOBYTE);
    326 
    327 		ndmp_set_socket_nodelay(ns);
    328 		(void) setsockopt(ns, SOL_SOCKET, SO_KEEPALIVE, &flag,
    329 		    sizeof (flag));
    330 
    331 		if ((argp = ndmp_malloc(sizeof (ndmpd_worker_arg_t))) != NULL) {
    332 			argp->nw_sock = ns;
    333 			argp->nw_ipaddr = ipaddr;
    334 			argp->nw_con_handler_func = con_handler_func;
    335 			(void) ndmp_start_worker(argp);
    336 		}
    337 	}
    338 }
    339 
    340 /*
    341  * ndmpd_worker thread
    342  *
    343  * Parameters:
    344  *   argp (input) - structure containing socket and handler function
    345  *
    346  * Returns:
    347  *   0 - successful connection.
    348  *  -1 - error.
    349  */
    350 void *
    351 ndmpd_worker(void *ptarg)
    352 {
    353 	int sock;
    354 	ndmp_connection_t *connection;
    355 	ndmpd_worker_arg_t *argp = (ndmpd_worker_arg_t *)ptarg;
    356 
    357 	if (!argp)
    358 		return ((void *)-1);
    359 
    360 	NS_INC(trun);
    361 	sock = argp->nw_sock;
    362 
    363 	if ((connection = ndmp_create_connection()) == NULL) {
    364 		(void) close(sock);
    365 		free(argp);
    366 		exit(1);
    367 	}
    368 
    369 	/* initialize auditing session */
    370 	if (adt_start_session(&connection->conn_ah, NULL, 0) != 0) {
    371 		free(argp);
    372 		return ((void *)-1);
    373 	}
    374 
    375 	((ndmp_connection_t *)connection)->conn_sock = sock;
    376 	(*argp->nw_con_handler_func)(connection);
    377 	(void) adt_end_session(connection->conn_ah);
    378 	ndmp_destroy_connection(connection);
    379 	NS_DEC(trun);
    380 
    381 	free(argp);
    382 	return (NULL);
    383 }
    384 
    385 /*
    386  * ndmp_process_requests
    387  *
    388  * Reads the next request message into the stream buffer.
    389  * Processes messages until the stream buffer is empty.
    390  *
    391  * Parameters:
    392  *   connection_handle (input) - connection handle.
    393  *
    394  * Returns:
    395  *   0 - 1 or more messages successfully processed.
    396  *  -1 - error; connection no longer established.
    397  */
    398 int
    399 ndmp_process_requests(ndmp_connection_t *connection_handle)
    400 {
    401 	int rv;
    402 	ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
    403 
    404 	(void) mutex_lock(&connection->conn_lock);
    405 	rv = 0;
    406 	if (ndmp_process_messages(connection, FALSE) < 0)
    407 		rv = -1;
    408 
    409 	(void) mutex_unlock(&connection->conn_lock);
    410 	return (rv);
    411 }
    412 
    413 
    414 /*
    415  * ndmp_send_request
    416  *
    417  * Send an NDMP request message.
    418  *
    419  * Parameters:
    420  *   connection_handle (input) - connection pointer.
    421  *   message (input) - message number.
    422  *   err (input)  - error code to place in header.
    423  *   request_data (input) - message body.
    424  *   reply (output) - reply message. If 0, reply will be
    425  *				discarded.
    426  *
    427  * Returns:
    428  *   0	- successful send.
    429  *  -1	- error.
    430  *   otherwise - error from reply header.
    431  *
    432  * Notes:
    433  *   - The reply body is only returned if the error code is NDMP_NO_ERR.
    434  */
    435 int
    436 ndmp_send_request(ndmp_connection_t *connection_handle, ndmp_message message,
    437     ndmp_error err, void *request_data, void **reply)
    438 {
    439 	ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
    440 	ndmp_header header;
    441 	ndmp_msg_handler_t *handler;
    442 	int r;
    443 	struct timeval time;
    444 
    445 	/* Lookup info necessary for processing this request. */
    446 	if (!(handler = ndmp_get_handler(connection, message))) {
    447 		NDMP_LOG(LOG_DEBUG, "Sending message 0x%x: not supported",
    448 		    message);
    449 		return (-1);
    450 	}
    451 	(void) gettimeofday(&time, 0);
    452 
    453 	header.sequence = ++(connection->conn_my_sequence);
    454 	header.time_stamp = time.tv_sec;
    455 	header.message_type = NDMP_MESSAGE_REQUEST;
    456 	header.message = message;
    457 	header.reply_sequence = 0;
    458 	header.error = err;
    459 
    460 	connection->conn_xdrs.x_op = XDR_ENCODE;
    461 	if (!xdr_ndmp_header(&connection->conn_xdrs, &header)) {
    462 		NDMP_LOG(LOG_DEBUG,
    463 		    "Sending message 0x%x: encoding request header", message);
    464 		(void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
    465 		return (-1);
    466 	}
    467 	if (err == NDMP_NO_ERR && handler->mh_xdr_request && request_data) {
    468 		if (!(*handler->mh_xdr_request)(&connection->conn_xdrs,
    469 		    request_data)) {
    470 			NDMP_LOG(LOG_DEBUG,
    471 			    "Sending message 0x%x: encoding request body",
    472 			    message);
    473 			(void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
    474 			return (-1);
    475 		}
    476 	}
    477 	(void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
    478 
    479 	if (handler->mh_xdr_reply == 0) {
    480 		NDMP_LOG(LOG_DEBUG, "handler->mh_xdr_reply == 0");
    481 		return (0);
    482 	}
    483 
    484 	/*
    485 	 * Process messages until the reply to this request has been
    486 	 * processed.
    487 	 */
    488 	for (; ; ) {
    489 		r = ndmp_process_messages(connection, TRUE);
    490 
    491 		/* connection error? */
    492 		if (r < 0)
    493 			return (-1);
    494 
    495 		/* no reply received? */
    496 		if (r == 0)
    497 			continue;
    498 
    499 		/* reply received? */
    500 		if (r == 1) {
    501 			if (message !=
    502 			    connection->conn_msginfo.mi_hdr.message) {
    503 				NDMP_LOG(LOG_DEBUG,
    504 				    "Received unexpected reply 0x%x",
    505 				    connection->conn_msginfo.mi_hdr.message);
    506 				ndmp_free_message(connection_handle);
    507 				return (-1);
    508 			}
    509 			if (reply != NULL)
    510 				*reply = connection->conn_msginfo.mi_body;
    511 			else
    512 				ndmp_free_message(connection_handle);
    513 
    514 			return (connection->conn_msginfo.mi_hdr.error);
    515 		}
    516 		/* error handling reply */
    517 
    518 		return (-1);
    519 	}
    520 }
    521 
    522 
    523 /*
    524  * ndmp_send_request_lock
    525  *
    526  * A wrapper for ndmp_send_request with locks.
    527  *
    528  * Parameters:
    529  *   connection_handle (input) - connection pointer.
    530  *   message (input) - message number.
    531  *   err (input) - error code to place in header.
    532  *   request_data (input) - message body.
    533  *   reply (output) - reply message. If 0, reply will be
    534  *				discarded.
    535  *
    536  * Returns:
    537  *   0	- successful send.
    538  *  -1	- error.
    539  *   otherwise - error from reply header.
    540  *
    541  * Notes:
    542  *   - The reply body is only returned if the error code is NDMP_NO_ERR.
    543  */
    544 int
    545 ndmp_send_request_lock(ndmp_connection_t *connection_handle,
    546     ndmp_message message, ndmp_error err, void *request_data, void **reply)
    547 {
    548 	int rv;
    549 	ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
    550 
    551 	(void) mutex_lock(&connection->conn_lock);
    552 
    553 	rv = ndmp_send_request(connection_handle, message, err, request_data,
    554 	    reply);
    555 	(void) mutex_unlock(&connection->conn_lock);
    556 	return (rv);
    557 }
    558 
    559 
    560 /*
    561  * ndmp_send_response
    562  *
    563  * Send an NDMP reply message.
    564  *
    565  * Parameters:
    566  *   connection_handle  (input)  - connection pointer.
    567  *   err	       (input)  - error code to place in header.
    568  *   reply	     (input)  - reply message body.
    569  *
    570  * Returns:
    571  *   0 - successful send.
    572  *  -1 - error.
    573  *
    574  * Notes:
    575  *   - The body is only sent if the error code is NDMP_NO_ERR.
    576  */
    577 int
    578 ndmp_send_response(ndmp_connection_t *connection_handle, ndmp_error err,
    579     void *reply)
    580 {
    581 	ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
    582 	ndmp_header header;
    583 	struct timeval time;
    584 
    585 	(void) gettimeofday(&time, 0);
    586 
    587 	header.sequence = ++(connection->conn_my_sequence);
    588 	header.time_stamp = time.tv_sec;
    589 	header.message_type = NDMP_MESSAGE_REPLY;
    590 	header.message = connection->conn_msginfo.mi_hdr.message;
    591 	header.reply_sequence = connection->conn_msginfo.mi_hdr.sequence;
    592 	header.error = err;
    593 
    594 	connection->conn_xdrs.x_op = XDR_ENCODE;
    595 	if (!xdr_ndmp_header(&connection->conn_xdrs, &header)) {
    596 		NDMP_LOG(LOG_DEBUG, "Sending message 0x%x: "
    597 		    "encoding reply header",
    598 		    header.message);
    599 		(void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
    600 		return (-1);
    601 	}
    602 	if (err == NDMP_NO_ERR &&
    603 	    connection->conn_msginfo.mi_handler->mh_xdr_reply &&
    604 	    reply) {
    605 		if (!(*connection->conn_msginfo.mi_handler->mh_xdr_reply)(
    606 		    &connection->conn_xdrs, reply)) {
    607 			NDMP_LOG(LOG_DEBUG,
    608 			    "Sending message 0x%x: encoding reply body",
    609 			    header.message);
    610 			(void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
    611 			return (-1);
    612 	}
    613 	}
    614 	(void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
    615 	return (0);
    616 }
    617 
    618 /*
    619  * ndmp_free_message
    620  *
    621  * Free the memory of NDMP message body.
    622  *
    623  * Parameters:
    624  *   connection_handle  (input)  - connection pointer.
    625  *
    626  * Returns:
    627  *   void
    628  *
    629  */
    630 void
    631 ndmp_free_message(ndmp_connection_t *connection_handle)
    632 {
    633 	ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
    634 
    635 	if (connection->conn_msginfo.mi_handler == NULL ||
    636 	    connection->conn_msginfo.mi_body == NULL)
    637 		return;
    638 
    639 	connection->conn_xdrs.x_op = XDR_FREE;
    640 	if (connection->conn_msginfo.mi_hdr.message_type ==
    641 	    NDMP_MESSAGE_REQUEST) {
    642 		if (connection->conn_msginfo.mi_handler->mh_xdr_request)
    643 			(*connection->conn_msginfo.mi_handler->mh_xdr_request)(
    644 			    &connection->conn_xdrs,
    645 			    connection->conn_msginfo.mi_body);
    646 	} else {
    647 		if (connection->conn_msginfo.mi_handler->mh_xdr_reply)
    648 			(*connection->conn_msginfo.mi_handler->mh_xdr_reply)(
    649 			    &connection->conn_xdrs,
    650 			    connection->conn_msginfo.mi_body);
    651 	}
    652 
    653 	(void) free(connection->conn_msginfo.mi_body);
    654 	connection->conn_msginfo.mi_body = 0;
    655 }
    656 
    657 /*
    658  * ndmp_get_fd
    659  *
    660  * Returns the connection file descriptor.
    661  *
    662  * Parameters:
    663  *   connection_handle (input) - connection handle
    664  *
    665  * Returns:
    666  *   >=0 - file descriptor.
    667  *   -1  - connection not open.
    668  */
    669 int
    670 ndmp_get_fd(ndmp_connection_t *connection_handle)
    671 {
    672 	return (((ndmp_connection_t *)connection_handle)->conn_sock);
    673 }
    674 
    675 
    676 /*
    677  * ndmp_set_client_data
    678  *
    679  * This function provides a means for the library client to provide
    680  * a pointer to some user data structure that is retrievable by
    681  * each message handler via ndmp_get_client_data.
    682  *
    683  * Parameters:
    684  *   connection_handle  (input) - connection handle.
    685  *   client_data	(input) - user data pointer.
    686  *
    687  * Returns:
    688  *   void
    689  */
    690 void
    691 ndmp_set_client_data(ndmp_connection_t *connection_handle, void *client_data)
    692 {
    693 	((ndmp_connection_t *)connection_handle)->conn_client_data =
    694 	    client_data;
    695 }
    696 
    697 
    698 /*
    699  * ndmp_get_client_data
    700  *
    701  * This function provides a means for the library client to provide
    702  * a pointer to some user data structure that is retrievable by
    703  * each message handler via ndmp_get_client_data.
    704  *
    705  * Parameters:
    706  *   connection_handle (input) - connection handle.
    707  *
    708  * Returns:
    709  *   client data pointer.
    710  */
    711 void *
    712 ndmp_get_client_data(ndmp_connection_t *connection_handle)
    713 {
    714 	return (((ndmp_connection_t *)connection_handle)->conn_client_data);
    715 }
    716 
    717 
    718 /*
    719  * ndmp_set_version
    720  *
    721  * Sets the NDMP protocol version to be used on the connection.
    722  *
    723  * Parameters:
    724  *   connection_handle  (input) - connection handle.
    725  *   version	   (input) - protocol version.
    726  *
    727  * Returns:
    728  *   void
    729  */
    730 void
    731 ndmp_set_version(ndmp_connection_t *connection_handle, ushort_t version)
    732 {
    733 	((ndmp_connection_t *)connection_handle)->conn_version = version;
    734 }
    735 
    736 
    737 /*
    738  * ndmp_get_version
    739  *
    740  * Gets the NDMP protocol version in use on the connection.
    741  *
    742  * Parameters:
    743  *   connection_handle  (input) - connection handle.
    744  *   version	   (input) - protocol version.
    745  *
    746  * Returns:
    747  *   void
    748  */
    749 ushort_t
    750 ndmp_get_version(ndmp_connection_t *connection_handle)
    751 {
    752 	return (((ndmp_connection_t *)connection_handle)->conn_version);
    753 }
    754 
    755 
    756 /*
    757  * ndmp_set_authorized
    758  *
    759  * Mark the connection as either having been authorized or not.
    760  *
    761  * Parameters:
    762  *   connection_handle  (input) - connection handle.
    763  *   authorized	(input) - TRUE or FALSE.
    764  *
    765  * Returns:
    766  *   void
    767  */
    768 void
    769 ndmp_set_authorized(ndmp_connection_t *connection_handle, boolean_t authorized)
    770 {
    771 	((ndmp_connection_t *)connection_handle)->conn_authorized = authorized;
    772 }
    773 
    774 
    775 /*
    776  * ndmpd_main
    777  *
    778  * NDMP main function called from main().
    779  *
    780  * Parameters:
    781  *   void
    782  *
    783  * Returns:
    784  *   void
    785  */
    786 void
    787 ndmpd_main(void)
    788 {
    789 	char *propval;
    790 
    791 	ndmp_load_params();
    792 	if (ndmp_log_open_file() != 0) {
    793 		NDMP_LOG(LOG_ERR,
    794 		    "Could not open log file properly.");
    795 	}
    796 
    797 	/*
    798 	 * Find ndmp port number to be used. If ndmpd is run as command line
    799 	 * and port number is supplied, use that port number. If port number is
    800 	 * is not supplied, find out if ndmp port property is set. If ndmp
    801 	 * port property is set, use that port number otherwise use the defaule
    802 	 * port number.
    803 	 */
    804 	if (ndmp_port == 0) {
    805 		if ((propval = ndmpd_get_prop(NDMP_TCP_PORT)) == NULL ||
    806 		    *propval == 0)
    807 			ndmp_port = NDMPPORT;
    808 		else
    809 			ndmp_port = strtol(propval, 0, 0);
    810 	}
    811 
    812 	if (ndmp_run(ndmp_port, connection_handler) == -1)
    813 		perror("ndmp_run ERROR");
    814 
    815 	ndmp_log_close_file();
    816 }
    817 
    818 /*
    819  * connection_handler
    820  *
    821  * NDMP connection handler.
    822  * Waits for, reads, and processes NDMP requests on a connection.
    823  *
    824  * Parameters:
    825  *   connection (input) - connection handle.
    826  *
    827  * Return:
    828  *   void
    829  */
    830 void
    831 connection_handler(ndmp_connection_t *connection)
    832 {
    833 	static int conn_id = 1;
    834 	ndmpd_session_t session;
    835 	ndmp_notify_connected_request req;
    836 	int connection_fd;
    837 
    838 	(void) memset(&session, 0, sizeof (session));
    839 	session.ns_connection = connection;
    840 	session.ns_eof = FALSE;
    841 	/*
    842 	 * The 'protocol_version' must be 1 at first, since the client talks
    843 	 * to the server in version 1 then they can move to a higher
    844 	 * protocol version.
    845 	 */
    846 	session.ns_protocol_version = ndmp_ver;
    847 
    848 	session.ns_scsi.sd_is_open = -1;
    849 	session.ns_scsi.sd_devid = -1;
    850 
    851 	session.ns_scsi.sd_sid = 0;
    852 	session.ns_scsi.sd_lun = 0;
    853 	session.ns_scsi.sd_valid_target_set = 0;
    854 	(void) memset(session.ns_scsi.sd_adapter_name, 0,
    855 	    sizeof (session.ns_scsi.sd_adapter_name));
    856 
    857 	session.ns_tape.td_fd = -1;
    858 	session.ns_tape.td_sid = 0;
    859 	session.ns_tape.td_lun = 0;
    860 	(void) memset(session.ns_tape.td_adapter_name, 0,
    861 	    sizeof (session.ns_tape.td_adapter_name));
    862 	session.ns_tape.td_pos = 0;
    863 	session.ns_tape.td_record_count = 0;
    864 	session.ns_file_handler_list = 0;
    865 
    866 	(void) ndmpd_data_init(&session);
    867 	ndmpd_file_history_init(&session);
    868 	if (ndmpd_mover_init(&session) < 0)
    869 		return;
    870 
    871 	if (ndmp_lbr_init(&session) < 0)
    872 		return;
    873 
    874 	/*
    875 	 * Setup defaults here. The init functions can not set defaults
    876 	 * since the init functions are called by the stop request handlers
    877 	 * and client set variables need to persist across data operations.
    878 	 */
    879 	session.ns_mover.md_record_size = MAX_RECORD_SIZE;
    880 
    881 	ndmp_set_client_data(connection, (void *)&session);
    882 
    883 	req.reason = NDMP_CONNECTED;
    884 	req.protocol_version = ndmp_ver;
    885 	req.text_reason = "";
    886 
    887 	if (ndmp_send_request_lock(connection, NDMP_NOTIFY_CONNECTION_STATUS,
    888 	    NDMP_NO_ERR, (void *)&req, 0) < 0) {
    889 		NDMP_LOG(LOG_DEBUG, "Connection terminated");
    890 		return;
    891 	}
    892 	connection_fd = ndmp_get_fd(connection);
    893 
    894 	NDMP_LOG(LOG_DEBUG, "connection_fd: %d", connection_fd);
    895 
    896 	/*
    897 	 * Add the handler function for the connection to the DMA.
    898 	 */
    899 	if (ndmpd_add_file_handler(&session, (void *)&session, connection_fd,
    900 	    NDMPD_SELECT_MODE_READ, HC_CLIENT, connection_file_handler) != 0) {
    901 		NDMP_LOG(LOG_DEBUG, "Could not register session handler.");
    902 		return;
    903 	}
    904 
    905 	/*
    906 	 * Register the connection in the list of active connections.
    907 	 */
    908 	if (ndmp_connect_list_add(connection, &conn_id) != 0) {
    909 		NDMP_LOG(LOG_ERR,
    910 		    "Could not register the session to the server.");
    911 		(void) ndmpd_remove_file_handler(&session, connection_fd);
    912 		return;
    913 	}
    914 
    915 	session.hardlink_q = hardlink_q_init();
    916 
    917 	while (session.ns_eof == FALSE)
    918 		(void) ndmpd_select(&session, TRUE, HC_ALL);
    919 
    920 	hardlink_q_cleanup(session.hardlink_q);
    921 
    922 	NDMP_LOG(LOG_DEBUG, "Connection terminated");
    923 
    924 	(void) ndmpd_remove_file_handler(&session, connection_fd);
    925 
    926 	if (session.ns_scsi.sd_is_open != -1) {
    927 		NDMP_LOG(LOG_DEBUG, "scsi.is_open: %d",
    928 		    session.ns_scsi.sd_is_open);
    929 		(void) ndmp_open_list_del(session.ns_scsi.sd_adapter_name,
    930 		    session.ns_scsi.sd_sid, session.ns_scsi.sd_lun);
    931 	}
    932 	if (session.ns_tape.td_fd != -1) {
    933 		NDMP_LOG(LOG_DEBUG, "tape.fd: %d", session.ns_tape.td_fd);
    934 		(void) close(session.ns_tape.td_fd);
    935 		(void) ndmp_open_list_del(session.ns_tape.td_adapter_name,
    936 		    session.ns_tape.td_sid, session.ns_tape.td_lun);
    937 	}
    938 	ndmpd_mover_shut_down(&session);
    939 	ndmp_lbr_cleanup(&session);
    940 	ndmpd_data_cleanup(&session);
    941 	ndmpd_file_history_cleanup(&session, FALSE);
    942 	ndmpd_mover_cleanup(&session);
    943 
    944 	(void) ndmp_connect_list_del(connection);
    945 }
    946 
    947 
    948 /*
    949  * connection_file_handler
    950  *
    951  * ndmp_connection_t file handler function.
    952  * Called by ndmpd_select when data is available to be read on the
    953  * NDMP connection.
    954  *
    955  * Parameters:
    956  *   cookie (input) - session pointer.
    957  *   fd      (input) - connection file descriptor.
    958  *   mode    (input) - select mode.
    959  *
    960  * Returns:
    961  *   void.
    962  */
    963 /*ARGSUSED*/
    964 static void
    965 connection_file_handler(void *cookie, int fd, ulong_t mode)
    966 {
    967 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
    968 
    969 	if (ndmp_process_requests(session->ns_connection) < 0)
    970 		session->ns_eof = TRUE;
    971 }
    972 
    973 
    974 /* ************* private functions *************************************** */
    975 
    976 /*
    977  * ndmp_readit
    978  *
    979  * Low level read routine called by the xdrrec library.
    980  *
    981  * Parameters:
    982  *   connection (input) - connection pointer.
    983  *   buf	(input) - location to store received data.
    984  *   len	(input) - max number of bytes to read.
    985  *
    986  * Returns:
    987  *   >0 - number of bytes received.
    988  *   -1 - error.
    989  */
    990 static int
    991 ndmp_readit(void *connection_handle, caddr_t buf, int len)
    992 {
    993 	ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
    994 
    995 	len = read(connection->conn_sock, buf, len);
    996 	if (len <= 0) {
    997 		/* ndmp_connection_t has been closed. */
    998 		connection->conn_eof = TRUE;
    999 		return (-1);
   1000 	}
   1001 	return (len);
   1002 }
   1003 
   1004 /*
   1005  * ndmp_writeit
   1006  *
   1007  * Low level write routine called by the xdrrec library.
   1008  *
   1009  * Parameters:
   1010  *   connection (input) - connection pointer.
   1011  *   buf	(input) - location to store received data.
   1012  *   len	(input) - max number of bytes to read.
   1013  *
   1014  * Returns:
   1015  *   >0 - number of bytes sent.
   1016  *   -1 - error.
   1017  */
   1018 static int
   1019 ndmp_writeit(void *connection_handle, caddr_t buf, int len)
   1020 {
   1021 	ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
   1022 	register int n;
   1023 	register int cnt;
   1024 
   1025 	for (cnt = len; cnt > 0; cnt -= n, buf += n) {
   1026 		if ((n = write(connection->conn_sock, buf, cnt)) < 0) {
   1027 			connection->conn_eof = TRUE;
   1028 			return (-1);
   1029 		}
   1030 	}
   1031 
   1032 	return (len);
   1033 }
   1034 
   1035 
   1036 /*
   1037  * ndmp_recv_msg
   1038  *
   1039  * Read the next message.
   1040  *
   1041  * Parameters:
   1042  *   connection (input)  - connection pointer.
   1043  *   msg	(output) - received message.
   1044  *
   1045  * Returns:
   1046  *   0 - Message successfully received.
   1047  *   error number - Message related error.
   1048  *  -1 - Error decoding the message header.
   1049  */
   1050 static int
   1051 ndmp_recv_msg(ndmp_connection_t *connection)
   1052 {
   1053 	bool_t(*xdr_func) (XDR *, ...) = NULL;
   1054 
   1055 	/* Decode the header. */
   1056 	connection->conn_xdrs.x_op = XDR_DECODE;
   1057 	(void) xdrrec_skiprecord(&connection->conn_xdrs);
   1058 	if (!xdr_ndmp_header(&connection->conn_xdrs,
   1059 	    &connection->conn_msginfo.mi_hdr))
   1060 		return (-1);
   1061 
   1062 	/* Lookup info necessary for processing this message. */
   1063 	if ((connection->conn_msginfo.mi_handler = ndmp_get_handler(connection,
   1064 	    connection->conn_msginfo.mi_hdr.message)) == 0) {
   1065 		NDMP_LOG(LOG_DEBUG, "Message 0x%x not supported",
   1066 		    connection->conn_msginfo.mi_hdr.message);
   1067 		return (NDMP_NOT_SUPPORTED_ERR);
   1068 	}
   1069 	connection->conn_msginfo.mi_body = 0;
   1070 
   1071 	if (connection->conn_msginfo.mi_hdr.error != NDMP_NO_ERR)
   1072 		return (0);
   1073 
   1074 	/* Determine body type */
   1075 	if (connection->conn_msginfo.mi_hdr.message_type ==
   1076 	    NDMP_MESSAGE_REQUEST) {
   1077 		if (ndmp_check_auth_required(
   1078 		    connection->conn_msginfo.mi_hdr.message) &&
   1079 		    !connection->conn_authorized) {
   1080 			NDMP_LOG(LOG_DEBUG,
   1081 			    "Processing request 0x%x:connection not authorized",
   1082 			    connection->conn_msginfo.mi_hdr.message);
   1083 			return (NDMP_NOT_AUTHORIZED_ERR);
   1084 		}
   1085 		if (connection->conn_msginfo.mi_handler->mh_sizeof_request >
   1086 		    0) {
   1087 			xdr_func =
   1088 			    connection->conn_msginfo.mi_handler->mh_xdr_request;
   1089 			if (xdr_func == NULL) {
   1090 				NDMP_LOG(LOG_DEBUG,
   1091 				    "Processing request 0x%x: no xdr function "
   1092 				    "in handler table",
   1093 				    connection->conn_msginfo.mi_hdr.message);
   1094 				return (NDMP_NOT_SUPPORTED_ERR);
   1095 			}
   1096 			connection->conn_msginfo.mi_body = ndmp_malloc(
   1097 			    connection->conn_msginfo.mi_handler->
   1098 			    mh_sizeof_request);
   1099 			if (connection->conn_msginfo.mi_body == NULL)
   1100 				return (NDMP_NO_MEM_ERR);
   1101 
   1102 			(void) memset(connection->conn_msginfo.mi_body, 0,
   1103 			    connection->conn_msginfo.mi_handler->
   1104 			    mh_sizeof_request);
   1105 		}
   1106 	} else {
   1107 		if (connection->conn_msginfo.mi_handler->mh_sizeof_reply > 0) {
   1108 			xdr_func =
   1109 			    connection->conn_msginfo.mi_handler->mh_xdr_reply;
   1110 			if (xdr_func == NULL) {
   1111 				NDMP_LOG(LOG_DEBUG,
   1112 				    "Processing reply 0x%x: no xdr function "
   1113 				    "in handler table",
   1114 				    connection->conn_msginfo.mi_hdr.message);
   1115 				return (NDMP_NOT_SUPPORTED_ERR);
   1116 			}
   1117 			connection->conn_msginfo.mi_body = ndmp_malloc(
   1118 			    connection->conn_msginfo.mi_handler->
   1119 			    mh_sizeof_reply);
   1120 			if (connection->conn_msginfo.mi_body == NULL)
   1121 				return (NDMP_NO_MEM_ERR);
   1122 
   1123 			(void) memset(connection->conn_msginfo.mi_body, 0,
   1124 			    connection->conn_msginfo.mi_handler->
   1125 			    mh_sizeof_reply);
   1126 		}
   1127 	}
   1128 
   1129 	/* Decode message arguments if needed */
   1130 	if (xdr_func) {
   1131 		if (!(*xdr_func)(&connection->conn_xdrs,
   1132 		    connection->conn_msginfo.mi_body)) {
   1133 			NDMP_LOG(LOG_DEBUG,
   1134 			    "Processing message 0x%x: error decoding arguments",
   1135 			    connection->conn_msginfo.mi_hdr.message);
   1136 			free(connection->conn_msginfo.mi_body);
   1137 			connection->conn_msginfo.mi_body = 0;
   1138 			return (NDMP_XDR_DECODE_ERR);
   1139 		}
   1140 	}
   1141 	return (0);
   1142 }
   1143 
   1144 /*
   1145  * ndmp_process_messages
   1146  *
   1147  * Reads the next message into the stream buffer.
   1148  * Processes messages until the stream buffer is empty.
   1149  *
   1150  * This function processes all data in the stream buffer before returning.
   1151  * This allows functions like poll() to be used to determine when new
   1152  * messages have arrived. If only some of the messages in the stream buffer
   1153  * were processed and then poll was called, poll() could block waiting for
   1154  * a message that had already been received and read into the stream buffer.
   1155  *
   1156  * This function processes both request and reply messages.
   1157  * Request messages are dispatched using the appropriate function from the
   1158  * message handling table.
   1159  * Only one reply messages may be pending receipt at a time.
   1160  * A reply message, if received, is placed in connection->conn_msginfo
   1161  * before returning to the caller.
   1162  * Errors are reported if a reply is received but not expected or if
   1163  * more than one reply message is received
   1164  *
   1165  * Parameters:
   1166  *   connection     (input)  - connection pointer.
   1167  *   reply_expected (output) - TRUE  - a reply message is expected.
   1168  *			     FALSE - no reply message is expected and
   1169  *			     an error will be reported if a reply
   1170  *			     is received.
   1171  *
   1172  * Returns:
   1173  *   NDMP_PROC_REP_ERR - 1 or more messages successfully processed,
   1174  *   	error processing reply message.
   1175  *   NDMP_PROC_REP_ERR - 1 or more messages successfully processed,
   1176  *	reply seen.
   1177  *   NDMP_PROC_REP_ERR - 1 or more messages successfully processed,
   1178  * 	no reply seen.
   1179  *   NDMP_PROC_REP_ERR - error; connection no longer established.
   1180  *
   1181  * Notes:
   1182  *   If the peer is generating a large number of requests, a caller
   1183  *   looking for a reply will be blocked while the requests are handled.
   1184  *   This is because this function does not return until the stream
   1185  *   buffer is empty.
   1186  *   Code needs to be added to allow a return if the stream buffer
   1187  *   is not empty but there is data available on the socket. This will
   1188  *   prevent poll() from blocking and prevent a caller looking for a reply
   1189  *   from getting blocked by a bunch of requests.
   1190  */
   1191 static int
   1192 ndmp_process_messages(ndmp_connection_t *connection, boolean_t reply_expected)
   1193 {
   1194 	msg_info_t reply_msginfo;
   1195 	boolean_t reply_read = FALSE;
   1196 	boolean_t reply_error = FALSE;
   1197 	int err;
   1198 
   1199 	NDMP_LOG(LOG_DEBUG, "reply_expected: %s",
   1200 	    reply_expected == TRUE ? "TRUE" : "FALSE");
   1201 
   1202 	(void) memset((void *)&reply_msginfo, 0, sizeof (msg_info_t));
   1203 
   1204 	do {
   1205 		(void) memset((void *)&connection->conn_msginfo, 0,
   1206 		    sizeof (msg_info_t));
   1207 
   1208 		if ((err = ndmp_recv_msg(connection)) != NDMP_NO_ERR) {
   1209 			if (connection->conn_eof) {
   1210 				NDMP_LOG(LOG_DEBUG, "detected eof");
   1211 				return (NDMP_PROC_ERR);
   1212 			}
   1213 			if (err < 1) {
   1214 				NDMP_LOG(LOG_DEBUG, "error decoding header");
   1215 
   1216 				/*
   1217 				 * Error occurred decoding the header.
   1218 				 * Don't send a reply since we don't know
   1219 				 * the message or if the message was even
   1220 				 * a request message.  To be safe, assume
   1221 				 * that the message was a reply if a reply
   1222 				 * was expected. Need to do this to prevent
   1223 				 * hanging ndmp_send_request() waiting for a
   1224 				 * reply.  Don't set reply_read so that the
   1225 				 * reply will be processed if it is received
   1226 				 * later.
   1227 				 */
   1228 				if (reply_read == FALSE)
   1229 					reply_error = TRUE;
   1230 
   1231 				continue;
   1232 			}
   1233 			if (connection->conn_msginfo.mi_hdr.message_type
   1234 			    != NDMP_MESSAGE_REQUEST) {
   1235 				NDMP_LOG(LOG_DEBUG, "received reply: 0x%x",
   1236 				    connection->conn_msginfo.mi_hdr.message);
   1237 
   1238 				if (reply_expected == FALSE ||
   1239 				    reply_read == TRUE)
   1240 					NDMP_LOG(LOG_DEBUG,
   1241 					    "Unexpected reply message: 0x%x",
   1242 					    connection->conn_msginfo.mi_hdr.
   1243 					    message);
   1244 
   1245 				ndmp_free_message((ndmp_connection_t *)
   1246 				    connection);
   1247 
   1248 				if (reply_read == FALSE) {
   1249 					reply_read = TRUE;
   1250 					reply_error = TRUE;
   1251 				}
   1252 				continue;
   1253 			}
   1254 			NDMP_LOG(LOG_DEBUG, "received request: 0x%x",
   1255 			    connection->conn_msginfo.mi_hdr.message);
   1256 
   1257 			(void) ndmp_send_response((ndmp_connection_t *)
   1258 			    connection, err, NULL);
   1259 			ndmp_free_message((ndmp_connection_t *)connection);
   1260 			continue;
   1261 		}
   1262 		if (connection->conn_msginfo.mi_hdr.message_type
   1263 		    != NDMP_MESSAGE_REQUEST) {
   1264 			NDMP_LOG(LOG_DEBUG, "received reply: 0x%x",
   1265 			    connection->conn_msginfo.mi_hdr.message);
   1266 
   1267 			if (reply_expected == FALSE || reply_read == TRUE) {
   1268 				NDMP_LOG(LOG_DEBUG,
   1269 				    "Unexpected reply message: 0x%x",
   1270 				    connection->conn_msginfo.mi_hdr.message);
   1271 				ndmp_free_message((ndmp_connection_t *)
   1272 				    connection);
   1273 				continue;
   1274 			}
   1275 			reply_read = TRUE;
   1276 			reply_msginfo = connection->conn_msginfo;
   1277 			continue;
   1278 		}
   1279 		NDMP_LOG(LOG_DEBUG, "received request: 0x%x",
   1280 		    connection->conn_msginfo.mi_hdr.message);
   1281 
   1282 		/*
   1283 		 * The following is needed to catch an improperly constructed
   1284 		 * handler table or to deal with an NDMP client that is not
   1285 		 * conforming to the negotiated protocol version.
   1286 		 */
   1287 		if (connection->conn_msginfo.mi_handler->mh_func == NULL) {
   1288 			NDMP_LOG(LOG_DEBUG, "No handler for message 0x%x",
   1289 			    connection->conn_msginfo.mi_hdr.message);
   1290 
   1291 			(void) ndmp_send_response((ndmp_connection_t *)
   1292 			    connection, NDMP_NOT_SUPPORTED_ERR, NULL);
   1293 			ndmp_free_message((ndmp_connection_t *)connection);
   1294 			continue;
   1295 		}
   1296 		/*
   1297 		 * Call the handler function.
   1298 		 * The handler will send any necessary reply.
   1299 		 */
   1300 		(*connection->conn_msginfo.mi_handler->mh_func) (connection,
   1301 		    connection->conn_msginfo.mi_body);
   1302 
   1303 		ndmp_free_message((ndmp_connection_t *)connection);
   1304 
   1305 	} while (xdrrec_eof(&connection->conn_xdrs) == FALSE &&
   1306 	    connection->conn_eof == FALSE);
   1307 
   1308 	NDMP_LOG(LOG_DEBUG, "no more messages in stream buffer");
   1309 
   1310 	if (connection->conn_eof == TRUE) {
   1311 		if (reply_msginfo.mi_body)
   1312 			free(reply_msginfo.mi_body);
   1313 		return (NDMP_PROC_ERR);
   1314 	}
   1315 	if (reply_error) {
   1316 		if (reply_msginfo.mi_body)
   1317 			free(reply_msginfo.mi_body);
   1318 		return (NDMP_PROC_REP_ERR);
   1319 	}
   1320 	if (reply_read) {
   1321 		connection->conn_msginfo = reply_msginfo;
   1322 		return (NDMP_PROC_MSG);
   1323 	}
   1324 	return (NDMP_PROC_REP);
   1325 }
   1326 
   1327 
   1328 /*
   1329  * ndmp_get_interface
   1330  *
   1331  * Return the NDMP interface (e.g. config, scsi, tape) for the
   1332  * specific message.
   1333  *
   1334  * Parameters:
   1335  *   message (input) - message number.
   1336  *
   1337  * Returns:
   1338  *   NULL - message not found.
   1339  *   pointer to handler info.
   1340  */
   1341 static ndmp_handler_t *
   1342 ndmp_get_interface(ndmp_message message)
   1343 {
   1344 	ndmp_handler_t *ni = &ndmp_msghdl_tab[(message >> 8) % INT_MAXCMD];
   1345 
   1346 	if ((message & 0xff) >= ni->hd_cnt)
   1347 		return (NULL);
   1348 
   1349 	/* Sanity check */
   1350 	if (ni->hd_msgs[message & 0xff].hm_message != message)
   1351 		return (NULL);
   1352 
   1353 	return (ni);
   1354 }
   1355 
   1356 /*
   1357  * ndmp_get_handler
   1358  *
   1359  * Return the handler info for the specified NDMP message.
   1360  *
   1361  * Parameters:
   1362  *   connection (input) - connection pointer.
   1363  *   message (input) - message number.
   1364  *
   1365  * Returns:
   1366  *   NULL - message not found.
   1367  *   pointer to handler info.
   1368  */
   1369 static ndmp_msg_handler_t *
   1370 ndmp_get_handler(ndmp_connection_t *connection, ndmp_message message)
   1371 {
   1372 	ndmp_msg_handler_t *handler = NULL;
   1373 
   1374 	ndmp_handler_t *ni = ndmp_get_interface(message);
   1375 	int ver = connection->conn_version;
   1376 
   1377 	if (ni)
   1378 		handler = &ni->hd_msgs[message & 0xff].hm_msg_v[ver - 2];
   1379 
   1380 	return (handler);
   1381 }
   1382 
   1383 /*
   1384  * ndmp_check_auth_required
   1385  *
   1386  * Check if the connection needs to be authenticated before
   1387  * this message is being processed.
   1388  *
   1389  * Parameters:
   1390  *   message (input) - message number.
   1391  *
   1392  * Returns:
   1393  *   TRUE - required
   1394  *   FALSE - not required
   1395  */
   1396 static boolean_t
   1397 ndmp_check_auth_required(ndmp_message message)
   1398 {
   1399 	boolean_t auth_req = FALSE;
   1400 	ndmp_handler_t *ni = ndmp_get_interface(message);
   1401 
   1402 	if (ni)
   1403 		auth_req = ni->hd_msgs[message & 0xff].hm_auth_required;
   1404 
   1405 	return (auth_req);
   1406 }
   1407 
   1408 /*
   1409  * tcp_accept
   1410  *
   1411  * A wrapper around accept for retrying and getting the IP address
   1412  *
   1413  * Parameters:
   1414  *   listen_sock (input) - the socket for listening
   1415  *   inaddr_p (output) - the IP address of peer connection
   1416  *
   1417  * Returns:
   1418  *   socket for the accepted connection
   1419  *   -1: error
   1420  */
   1421 int
   1422 tcp_accept(int listen_sock, unsigned int *inaddr_p)
   1423 {
   1424 	struct sockaddr_in	sin;
   1425 	int			sock, i;
   1426 	int			try;
   1427 
   1428 	for (try = 0; try < 3; try++) {
   1429 		i = sizeof (sin);
   1430 		sock = accept(listen_sock, (struct sockaddr *)&sin, &i);
   1431 		if (sock < 0) {
   1432 			continue;
   1433 		}
   1434 		*inaddr_p = sin.sin_addr.s_addr;
   1435 		return (sock);
   1436 	}
   1437 	return (-1);
   1438 }
   1439 
   1440 
   1441 /*
   1442  * tcp_get_peer
   1443  *
   1444  * Get the peer IP address for a connection
   1445  *
   1446  * Parameters:
   1447  *   sock (input) - the active socket
   1448  *   inaddr_p (output) - the IP address of peer connection
   1449  *   port_p (output) - the port number of peer connection
   1450  *
   1451  * Returns:
   1452  *   socket for the accepted connection
   1453  *   -1: error
   1454  */
   1455 int
   1456 tcp_get_peer(int sock, unsigned int *inaddr_p, int *port_p)
   1457 {
   1458 	struct sockaddr_in sin;
   1459 	int i, rc;
   1460 
   1461 	i = sizeof (sin);
   1462 	rc = getpeername(sock, (struct sockaddr *)&sin, &i);
   1463 	if (rc != 0)
   1464 		return (-1);
   1465 
   1466 	if (inaddr_p)
   1467 		*inaddr_p = sin.sin_addr.s_addr;
   1468 
   1469 	if (port_p)
   1470 		*port_p = ntohs(sin.sin_port);
   1471 
   1472 	return (sock);
   1473 
   1474 }
   1475 
   1476 /*
   1477  * gethostaddr
   1478  *
   1479  * Get the IP address string of the current host
   1480  *
   1481  * Parameters:
   1482  *   void
   1483  *
   1484  * Returns:
   1485  *   IP address
   1486  *   NULL: error
   1487  */
   1488 char *
   1489 gethostaddr(void)
   1490 {
   1491 	static char s[MAXHOSTNAMELEN];
   1492 	struct hostent *h;
   1493 	struct in_addr in;
   1494 	char *p;
   1495 
   1496 	if (gethostname(s, sizeof (s)) == -1)
   1497 		return (NULL);
   1498 
   1499 	if ((h = gethostbyname(s)) == NULL)
   1500 		return (NULL);
   1501 
   1502 	p = h->h_addr_list[0];
   1503 	(void) memcpy(&in.s_addr, p, sizeof (in.s_addr));
   1504 	return (inet_ntoa(in));
   1505 }
   1506 
   1507 /*
   1508  * ndmpd_audit_backup
   1509  *
   1510  * Generate AUE_ndmp_backup audit record
   1511  */
   1512 /*ARGSUSED*/
   1513 void
   1514 ndmpd_audit_backup(ndmp_connection_t *conn,
   1515     char *path, int dest, char *local_path, int result)
   1516 {
   1517 	adt_event_data_t *event;
   1518 
   1519 	if ((event = adt_alloc_event(conn->conn_ah, ADT_ndmp_backup)) == NULL) {
   1520 		NDMP_LOG(LOG_ERR, "Audit failure: %m.");
   1521 		return;
   1522 	}
   1523 	event->adt_ndmp_backup.source = path;
   1524 
   1525 	if (dest == NDMP_ADDR_LOCAL) {
   1526 		event->adt_ndmp_backup.local_dest = local_path;
   1527 	} else {
   1528 		event->adt_ndmp_backup.remote_dest = conn->conn_sock;
   1529 	}
   1530 
   1531 	if (result == 0) {
   1532 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
   1533 			NDMP_LOG(LOG_ERR, "Audit failure: %m.");
   1534 	} else {
   1535 		if (adt_put_event(event, ADT_FAILURE, result) != 0)
   1536 			NDMP_LOG(LOG_ERR, "Audit failure: %m.");
   1537 	}
   1538 
   1539 	adt_free_event(event);
   1540 }
   1541 
   1542 
   1543 /*
   1544  * ndmpd_audit_restore
   1545  *
   1546  * Generate AUE_ndmp_restore audit record
   1547  */
   1548 /*ARGSUSED*/
   1549 void
   1550 ndmpd_audit_restore(ndmp_connection_t *conn,
   1551     char *path, int dest, char *local_path, int result)
   1552 {
   1553 	adt_event_data_t *event;
   1554 
   1555 	if ((event = adt_alloc_event(conn->conn_ah,
   1556 	    ADT_ndmp_restore)) == NULL) {
   1557 		NDMP_LOG(LOG_ERR, "Audit failure: %m.");
   1558 		return;
   1559 	}
   1560 	event->adt_ndmp_restore.destination = path;
   1561 
   1562 	if (dest == NDMP_ADDR_LOCAL) {
   1563 		event->adt_ndmp_restore.local_source = local_path;
   1564 	} else {
   1565 		event->adt_ndmp_restore.remote_source = conn->conn_sock;
   1566 	}
   1567 
   1568 	if (result == 0) {
   1569 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
   1570 			NDMP_LOG(LOG_ERR, "Audit failure: %m.");
   1571 	} else {
   1572 		if (adt_put_event(event, ADT_FAILURE, result) != 0)
   1573 			NDMP_LOG(LOG_ERR, "Audit failure: %m.");
   1574 	}
   1575 
   1576 	adt_free_event(event);
   1577 }
   1578 
   1579 
   1580 /*
   1581  * ndmpd_audit_connect
   1582  *
   1583  * Generate AUE_ndmp_connect audit record
   1584  */
   1585 /*ARGSUSED*/
   1586 void
   1587 ndmpd_audit_connect(ndmp_connection_t *conn, int result)
   1588 {
   1589 	adt_event_data_t *event;
   1590 	adt_termid_t *termid;
   1591 
   1592 	if (adt_load_termid(conn->conn_sock, &termid) != 0) {
   1593 		NDMP_LOG(LOG_ERR, "Audit failure: %m.");
   1594 		return;
   1595 	}
   1596 
   1597 	if (adt_set_user(conn->conn_ah, ADT_NO_ATTRIB, ADT_NO_ATTRIB,
   1598 	    ADT_NO_ATTRIB, ADT_NO_ATTRIB, termid, ADT_NEW) != 0) {
   1599 		NDMP_LOG(LOG_ERR, "Audit failure: %m.");
   1600 		free(termid);
   1601 		return;
   1602 	}
   1603 	free(termid);
   1604 
   1605 	if ((event = adt_alloc_event(conn->conn_ah,
   1606 	    ADT_ndmp_connect)) == NULL) {
   1607 		NDMP_LOG(LOG_ERR, "Audit failure: %m.");
   1608 		return;
   1609 	}
   1610 
   1611 	if (result == 0) {
   1612 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
   1613 			NDMP_LOG(LOG_ERR, "Audit failure: %m.");
   1614 	} else {
   1615 		if (adt_put_event(event, ADT_FAILURE, result) != 0)
   1616 			NDMP_LOG(LOG_ERR, "Audit failure: %m.");
   1617 	}
   1618 
   1619 	adt_free_event(event);
   1620 }
   1621 
   1622 
   1623 /*
   1624  * ndmpd_audit_disconnect
   1625  *
   1626  * Generate AUE_ndmp_disconnect audit record
   1627  */
   1628 /*ARGSUSED*/
   1629 void
   1630 ndmpd_audit_disconnect(ndmp_connection_t *conn)
   1631 {
   1632 	adt_event_data_t *event;
   1633 
   1634 	if ((event = adt_alloc_event(conn->conn_ah,
   1635 	    ADT_ndmp_disconnect)) == NULL) {
   1636 		NDMP_LOG(LOG_ERR, "Audit failure: %m.");
   1637 		return;
   1638 	}
   1639 	if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
   1640 		NDMP_LOG(LOG_ERR, "Audit failure: %m.");
   1641 
   1642 	adt_free_event(event);
   1643 }
   1644 
   1645 void *
   1646 ndmp_malloc(size_t size)
   1647 {
   1648 	void *data;
   1649 
   1650 	if ((data = calloc(1, size)) == NULL) {
   1651 		NDMP_LOG(LOG_ERR, "Out of memory.");
   1652 	}
   1653 
   1654 	return (data);
   1655 }
   1656