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