xref: /illumos-gate/usr/src/cmd/ndmpd/ndmp/ndmpd_comm.c (revision 71269a2275bf5a143dad6461eee2710a344e7261)
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(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 /*
976  * ndmp_readit
977  *
978  * Low level read routine called by the xdrrec library.
979  *
980  * Parameters:
981  *   connection (input) - connection pointer.
982  *   buf	(input) - location to store received data.
983  *   len	(input) - max number of bytes to read.
984  *
985  * Returns:
986  *   >0 - number of bytes received.
987  *   -1 - error.
988  */
989 static int
990 ndmp_readit(void *connection_handle, caddr_t buf, int len)
991 {
992 	ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
993 
994 	len = read(connection->conn_sock, buf, len);
995 	if (len <= 0) {
996 		/* ndmp_connection_t has been closed. */
997 		connection->conn_eof = TRUE;
998 		return (-1);
999 	}
1000 	return (len);
1001 }
1002 
1003 /*
1004  * ndmp_writeit
1005  *
1006  * Low level write routine called by the xdrrec library.
1007  *
1008  * Parameters:
1009  *   connection (input) - connection pointer.
1010  *   buf	(input) - location to store received data.
1011  *   len	(input) - max number of bytes to read.
1012  *
1013  * Returns:
1014  *   >0 - number of bytes sent.
1015  *   -1 - error.
1016  */
1017 static int
1018 ndmp_writeit(void *connection_handle, caddr_t buf, int len)
1019 {
1020 	ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
1021 	register int n;
1022 	register int cnt;
1023 
1024 	for (cnt = len; cnt > 0; cnt -= n, buf += n) {
1025 		if ((n = write(connection->conn_sock, buf, cnt)) < 0) {
1026 			connection->conn_eof = TRUE;
1027 			return (-1);
1028 		}
1029 	}
1030 
1031 	return (len);
1032 }
1033 
1034 
1035 /*
1036  * ndmp_recv_msg
1037  *
1038  * Read the next message.
1039  *
1040  * Parameters:
1041  *   connection (input)  - connection pointer.
1042  *   msg	(output) - received message.
1043  *
1044  * Returns:
1045  *   0 - Message successfully received.
1046  *   error number - Message related error.
1047  *  -1 - Error decoding the message header.
1048  */
1049 static int
1050 ndmp_recv_msg(ndmp_connection_t *connection)
1051 {
1052 	bool_t(*xdr_func) (XDR *, ...) = NULL;
1053 
1054 	/* Decode the header. */
1055 	connection->conn_xdrs.x_op = XDR_DECODE;
1056 	(void) xdrrec_skiprecord(&connection->conn_xdrs);
1057 	if (!xdr_ndmp_header(&connection->conn_xdrs,
1058 	    &connection->conn_msginfo.mi_hdr))
1059 		return (-1);
1060 
1061 	/* Lookup info necessary for processing this message. */
1062 	if ((connection->conn_msginfo.mi_handler = ndmp_get_handler(connection,
1063 	    connection->conn_msginfo.mi_hdr.message)) == 0) {
1064 		NDMP_LOG(LOG_DEBUG, "Message 0x%x not supported",
1065 		    connection->conn_msginfo.mi_hdr.message);
1066 		return (NDMP_NOT_SUPPORTED_ERR);
1067 	}
1068 	connection->conn_msginfo.mi_body = 0;
1069 
1070 	if (connection->conn_msginfo.mi_hdr.error != NDMP_NO_ERR)
1071 		return (0);
1072 
1073 	/* Determine body type */
1074 	if (connection->conn_msginfo.mi_hdr.message_type ==
1075 	    NDMP_MESSAGE_REQUEST) {
1076 		if (ndmp_check_auth_required(
1077 		    connection->conn_msginfo.mi_hdr.message) &&
1078 		    !connection->conn_authorized) {
1079 			NDMP_LOG(LOG_DEBUG,
1080 			    "Processing request 0x%x:connection not authorized",
1081 			    connection->conn_msginfo.mi_hdr.message);
1082 			return (NDMP_NOT_AUTHORIZED_ERR);
1083 		}
1084 		if (connection->conn_msginfo.mi_handler->mh_sizeof_request >
1085 		    0) {
1086 			xdr_func =
1087 			    connection->conn_msginfo.mi_handler->mh_xdr_request;
1088 			if (xdr_func == NULL) {
1089 				NDMP_LOG(LOG_DEBUG,
1090 				    "Processing request 0x%x: no xdr function "
1091 				    "in handler table",
1092 				    connection->conn_msginfo.mi_hdr.message);
1093 				return (NDMP_NOT_SUPPORTED_ERR);
1094 			}
1095 			connection->conn_msginfo.mi_body = ndmp_malloc(
1096 			    connection->conn_msginfo.mi_handler->
1097 			    mh_sizeof_request);
1098 			if (connection->conn_msginfo.mi_body == NULL)
1099 				return (NDMP_NO_MEM_ERR);
1100 
1101 			(void) memset(connection->conn_msginfo.mi_body, 0,
1102 			    connection->conn_msginfo.mi_handler->
1103 			    mh_sizeof_request);
1104 		}
1105 	} else {
1106 		if (connection->conn_msginfo.mi_handler->mh_sizeof_reply > 0) {
1107 			xdr_func =
1108 			    connection->conn_msginfo.mi_handler->mh_xdr_reply;
1109 			if (xdr_func == NULL) {
1110 				NDMP_LOG(LOG_DEBUG,
1111 				    "Processing reply 0x%x: no xdr function "
1112 				    "in handler table",
1113 				    connection->conn_msginfo.mi_hdr.message);
1114 				return (NDMP_NOT_SUPPORTED_ERR);
1115 			}
1116 			connection->conn_msginfo.mi_body = ndmp_malloc(
1117 			    connection->conn_msginfo.mi_handler->
1118 			    mh_sizeof_reply);
1119 			if (connection->conn_msginfo.mi_body == NULL)
1120 				return (NDMP_NO_MEM_ERR);
1121 
1122 			(void) memset(connection->conn_msginfo.mi_body, 0,
1123 			    connection->conn_msginfo.mi_handler->
1124 			    mh_sizeof_reply);
1125 		}
1126 	}
1127 
1128 	/* Decode message arguments if needed */
1129 	if (xdr_func) {
1130 		if (!(*xdr_func)(&connection->conn_xdrs,
1131 		    connection->conn_msginfo.mi_body)) {
1132 			NDMP_LOG(LOG_DEBUG,
1133 			    "Processing message 0x%x: error decoding arguments",
1134 			    connection->conn_msginfo.mi_hdr.message);
1135 			free(connection->conn_msginfo.mi_body);
1136 			connection->conn_msginfo.mi_body = 0;
1137 			return (NDMP_XDR_DECODE_ERR);
1138 		}
1139 	}
1140 	return (0);
1141 }
1142 
1143 /*
1144  * ndmp_process_messages
1145  *
1146  * Reads the next message into the stream buffer.
1147  * Processes messages until the stream buffer is empty.
1148  *
1149  * This function processes all data in the stream buffer before returning.
1150  * This allows functions like poll() to be used to determine when new
1151  * messages have arrived. If only some of the messages in the stream buffer
1152  * were processed and then poll was called, poll() could block waiting for
1153  * a message that had already been received and read into the stream buffer.
1154  *
1155  * This function processes both request and reply messages.
1156  * Request messages are dispatched using the appropriate function from the
1157  * message handling table.
1158  * Only one reply messages may be pending receipt at a time.
1159  * A reply message, if received, is placed in connection->conn_msginfo
1160  * before returning to the caller.
1161  * Errors are reported if a reply is received but not expected or if
1162  * more than one reply message is received
1163  *
1164  * Parameters:
1165  *   connection     (input)  - connection pointer.
1166  *   reply_expected (output) - TRUE  - a reply message is expected.
1167  *			     FALSE - no reply message is expected and
1168  *			     an error will be reported if a reply
1169  *			     is received.
1170  *
1171  * Returns:
1172  *   NDMP_PROC_REP_ERR - 1 or more messages successfully processed,
1173  *   	error processing reply message.
1174  *   NDMP_PROC_REP_ERR - 1 or more messages successfully processed,
1175  *	reply seen.
1176  *   NDMP_PROC_REP_ERR - 1 or more messages successfully processed,
1177  * 	no reply seen.
1178  *   NDMP_PROC_REP_ERR - error; connection no longer established.
1179  *
1180  * Notes:
1181  *   If the peer is generating a large number of requests, a caller
1182  *   looking for a reply will be blocked while the requests are handled.
1183  *   This is because this function does not return until the stream
1184  *   buffer is empty.
1185  *   Code needs to be added to allow a return if the stream buffer
1186  *   is not empty but there is data available on the socket. This will
1187  *   prevent poll() from blocking and prevent a caller looking for a reply
1188  *   from getting blocked by a bunch of requests.
1189  */
1190 static int
1191 ndmp_process_messages(ndmp_connection_t *connection, boolean_t reply_expected)
1192 {
1193 	msg_info_t reply_msginfo;
1194 	boolean_t reply_read = FALSE;
1195 	boolean_t reply_error = FALSE;
1196 	int err;
1197 
1198 	NDMP_LOG(LOG_DEBUG, "reply_expected: %s",
1199 	    reply_expected == TRUE ? "TRUE" : "FALSE");
1200 
1201 	(void) memset((void *)&reply_msginfo, 0, sizeof (msg_info_t));
1202 
1203 	do {
1204 		(void) memset((void *)&connection->conn_msginfo, 0,
1205 		    sizeof (msg_info_t));
1206 
1207 		if ((err = ndmp_recv_msg(connection)) != NDMP_NO_ERR) {
1208 			if (connection->conn_eof) {
1209 				NDMP_LOG(LOG_DEBUG, "detected eof");
1210 				return (NDMP_PROC_ERR);
1211 			}
1212 			if (err < 1) {
1213 				NDMP_LOG(LOG_DEBUG, "error decoding header");
1214 
1215 				/*
1216 				 * Error occurred decoding the header.
1217 				 * Don't send a reply since we don't know
1218 				 * the message or if the message was even
1219 				 * a request message.  To be safe, assume
1220 				 * that the message was a reply if a reply
1221 				 * was expected. Need to do this to prevent
1222 				 * hanging ndmp_send_request() waiting for a
1223 				 * reply.  Don't set reply_read so that the
1224 				 * reply will be processed if it is received
1225 				 * later.
1226 				 */
1227 				if (reply_read == FALSE)
1228 					reply_error = TRUE;
1229 
1230 				continue;
1231 			}
1232 			if (connection->conn_msginfo.mi_hdr.message_type
1233 			    != NDMP_MESSAGE_REQUEST) {
1234 				NDMP_LOG(LOG_DEBUG, "received reply: 0x%x",
1235 				    connection->conn_msginfo.mi_hdr.message);
1236 
1237 				if (reply_expected == FALSE ||
1238 				    reply_read == TRUE)
1239 					NDMP_LOG(LOG_DEBUG,
1240 					    "Unexpected reply message: 0x%x",
1241 					    connection->conn_msginfo.mi_hdr.
1242 					    message);
1243 
1244 				ndmp_free_message((ndmp_connection_t *)
1245 				    connection);
1246 
1247 				if (reply_read == FALSE) {
1248 					reply_read = TRUE;
1249 					reply_error = TRUE;
1250 				}
1251 				continue;
1252 			}
1253 			NDMP_LOG(LOG_DEBUG, "received request: 0x%x",
1254 			    connection->conn_msginfo.mi_hdr.message);
1255 
1256 			(void) ndmp_send_response((ndmp_connection_t *)
1257 			    connection, err, NULL);
1258 			ndmp_free_message((ndmp_connection_t *)connection);
1259 			continue;
1260 		}
1261 		if (connection->conn_msginfo.mi_hdr.message_type
1262 		    != NDMP_MESSAGE_REQUEST) {
1263 			NDMP_LOG(LOG_DEBUG, "received reply: 0x%x",
1264 			    connection->conn_msginfo.mi_hdr.message);
1265 
1266 			if (reply_expected == FALSE || reply_read == TRUE) {
1267 				NDMP_LOG(LOG_DEBUG,
1268 				    "Unexpected reply message: 0x%x",
1269 				    connection->conn_msginfo.mi_hdr.message);
1270 				ndmp_free_message((ndmp_connection_t *)
1271 				    connection);
1272 				continue;
1273 			}
1274 			reply_read = TRUE;
1275 			reply_msginfo = connection->conn_msginfo;
1276 			continue;
1277 		}
1278 		NDMP_LOG(LOG_DEBUG, "received request: 0x%x",
1279 		    connection->conn_msginfo.mi_hdr.message);
1280 
1281 		/*
1282 		 * The following is needed to catch an improperly constructed
1283 		 * handler table or to deal with an NDMP client that is not
1284 		 * conforming to the negotiated protocol version.
1285 		 */
1286 		if (connection->conn_msginfo.mi_handler->mh_func == NULL) {
1287 			NDMP_LOG(LOG_DEBUG, "No handler for message 0x%x",
1288 			    connection->conn_msginfo.mi_hdr.message);
1289 
1290 			(void) ndmp_send_response((ndmp_connection_t *)
1291 			    connection, NDMP_NOT_SUPPORTED_ERR, NULL);
1292 			ndmp_free_message((ndmp_connection_t *)connection);
1293 			continue;
1294 		}
1295 		/*
1296 		 * Call the handler function.
1297 		 * The handler will send any necessary reply.
1298 		 */
1299 		(*connection->conn_msginfo.mi_handler->mh_func) (connection,
1300 		    connection->conn_msginfo.mi_body);
1301 
1302 		ndmp_free_message((ndmp_connection_t *)connection);
1303 
1304 	} while (xdrrec_eof(&connection->conn_xdrs) == FALSE &&
1305 	    connection->conn_eof == FALSE);
1306 
1307 	NDMP_LOG(LOG_DEBUG, "no more messages in stream buffer");
1308 
1309 	if (connection->conn_eof == TRUE) {
1310 		if (reply_msginfo.mi_body)
1311 			free(reply_msginfo.mi_body);
1312 		return (NDMP_PROC_ERR);
1313 	}
1314 	if (reply_error) {
1315 		if (reply_msginfo.mi_body)
1316 			free(reply_msginfo.mi_body);
1317 		return (NDMP_PROC_REP_ERR);
1318 	}
1319 	if (reply_read) {
1320 		connection->conn_msginfo = reply_msginfo;
1321 		return (NDMP_PROC_MSG);
1322 	}
1323 	return (NDMP_PROC_REP);
1324 }
1325 
1326 
1327 /*
1328  * ndmp_get_interface
1329  *
1330  * Return the NDMP interface (e.g. config, scsi, tape) for the
1331  * specific message.
1332  *
1333  * Parameters:
1334  *   message (input) - message number.
1335  *
1336  * Returns:
1337  *   NULL - message not found.
1338  *   pointer to handler info.
1339  */
1340 static ndmp_handler_t *
1341 ndmp_get_interface(ndmp_message message)
1342 {
1343 	ndmp_handler_t *ni = &ndmp_msghdl_tab[(message >> 8) % INT_MAXCMD];
1344 
1345 	if ((message & 0xff) >= ni->hd_cnt)
1346 		return (NULL);
1347 
1348 	/* Sanity check */
1349 	if (ni->hd_msgs[message & 0xff].hm_message != message)
1350 		return (NULL);
1351 
1352 	return (ni);
1353 }
1354 
1355 /*
1356  * ndmp_get_handler
1357  *
1358  * Return the handler info for the specified NDMP message.
1359  *
1360  * Parameters:
1361  *   connection (input) - connection pointer.
1362  *   message (input) - message number.
1363  *
1364  * Returns:
1365  *   NULL - message not found.
1366  *   pointer to handler info.
1367  */
1368 static ndmp_msg_handler_t *
1369 ndmp_get_handler(ndmp_connection_t *connection, ndmp_message message)
1370 {
1371 	ndmp_msg_handler_t *handler = NULL;
1372 
1373 	ndmp_handler_t *ni = ndmp_get_interface(message);
1374 	int ver = connection->conn_version;
1375 
1376 	if (ni)
1377 		handler = &ni->hd_msgs[message & 0xff].hm_msg_v[ver - 2];
1378 
1379 	return (handler);
1380 }
1381 
1382 /*
1383  * ndmp_check_auth_required
1384  *
1385  * Check if the connection needs to be authenticated before
1386  * this message is being processed.
1387  *
1388  * Parameters:
1389  *   message (input) - message number.
1390  *
1391  * Returns:
1392  *   TRUE - required
1393  *   FALSE - not required
1394  */
1395 static boolean_t
1396 ndmp_check_auth_required(ndmp_message message)
1397 {
1398 	boolean_t auth_req = FALSE;
1399 	ndmp_handler_t *ni = ndmp_get_interface(message);
1400 
1401 	if (ni)
1402 		auth_req = ni->hd_msgs[message & 0xff].hm_auth_required;
1403 
1404 	return (auth_req);
1405 }
1406 
1407 /*
1408  * tcp_accept
1409  *
1410  * A wrapper around accept for retrying and getting the IP address
1411  *
1412  * Parameters:
1413  *   listen_sock (input) - the socket for listening
1414  *   inaddr_p (output) - the IP address of peer connection
1415  *
1416  * Returns:
1417  *   socket for the accepted connection
1418  *   -1: error
1419  */
1420 int
1421 tcp_accept(int listen_sock, unsigned int *inaddr_p)
1422 {
1423 	struct sockaddr_in	sin;
1424 	int			sock, i;
1425 	int			try;
1426 
1427 	for (try = 0; try < 3; try++) {
1428 		i = sizeof (sin);
1429 		sock = accept(listen_sock, (struct sockaddr *)&sin, &i);
1430 		if (sock < 0) {
1431 			continue;
1432 		}
1433 		*inaddr_p = sin.sin_addr.s_addr;
1434 		return (sock);
1435 	}
1436 	return (-1);
1437 }
1438 
1439 
1440 /*
1441  * tcp_get_peer
1442  *
1443  * Get the peer IP address for a connection
1444  *
1445  * Parameters:
1446  *   sock (input) - the active socket
1447  *   inaddr_p (output) - the IP address of peer connection
1448  *   port_p (output) - the port number of peer connection
1449  *
1450  * Returns:
1451  *   socket for the accepted connection
1452  *   -1: error
1453  */
1454 int
1455 tcp_get_peer(int sock, unsigned int *inaddr_p, int *port_p)
1456 {
1457 	struct sockaddr_in sin;
1458 	int i, rc;
1459 
1460 	i = sizeof (sin);
1461 	rc = getpeername(sock, (struct sockaddr *)&sin, &i);
1462 	if (rc != 0)
1463 		return (-1);
1464 
1465 	if (inaddr_p)
1466 		*inaddr_p = sin.sin_addr.s_addr;
1467 
1468 	if (port_p)
1469 		*port_p = ntohs(sin.sin_port);
1470 
1471 	return (sock);
1472 
1473 }
1474 
1475 /*
1476  * gethostaddr
1477  *
1478  * Get the IP address string of the current host
1479  *
1480  * Parameters:
1481  *   void
1482  *
1483  * Returns:
1484  *   IP address
1485  *   NULL: error
1486  */
1487 char *
1488 gethostaddr(void)
1489 {
1490 	static char s[MAXHOSTNAMELEN];
1491 	struct hostent *h;
1492 	struct in_addr in;
1493 	char *p;
1494 
1495 	if (gethostname(s, sizeof (s)) == -1)
1496 		return (NULL);
1497 
1498 	if ((h = gethostbyname(s)) == NULL)
1499 		return (NULL);
1500 
1501 	p = h->h_addr_list[0];
1502 	(void) memcpy(&in.s_addr, p, sizeof (in.s_addr));
1503 	return (inet_ntoa(in));
1504 }
1505 
1506 /*
1507  * ndmpd_audit_backup
1508  *
1509  * Generate AUE_ndmp_backup audit record
1510  */
1511 /*ARGSUSED*/
1512 void
1513 ndmpd_audit_backup(ndmp_connection_t *conn,
1514     char *path, int dest, char *local_path, int result)
1515 {
1516 	adt_event_data_t *event;
1517 
1518 	if ((event = adt_alloc_event(conn->conn_ah, ADT_ndmp_backup)) == NULL) {
1519 		NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1520 		return;
1521 	}
1522 	event->adt_ndmp_backup.source = path;
1523 
1524 	if (dest == NDMP_ADDR_LOCAL) {
1525 		event->adt_ndmp_backup.local_dest = local_path;
1526 	} else {
1527 		event->adt_ndmp_backup.remote_dest = conn->conn_sock;
1528 	}
1529 
1530 	if (result == 0) {
1531 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
1532 			NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1533 	} else {
1534 		if (adt_put_event(event, ADT_FAILURE, result) != 0)
1535 			NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1536 	}
1537 
1538 	adt_free_event(event);
1539 }
1540 
1541 
1542 /*
1543  * ndmpd_audit_restore
1544  *
1545  * Generate AUE_ndmp_restore audit record
1546  */
1547 /*ARGSUSED*/
1548 void
1549 ndmpd_audit_restore(ndmp_connection_t *conn,
1550     char *path, int dest, char *local_path, int result)
1551 {
1552 	adt_event_data_t *event;
1553 
1554 	if ((event = adt_alloc_event(conn->conn_ah,
1555 	    ADT_ndmp_restore)) == NULL) {
1556 		NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1557 		return;
1558 	}
1559 	event->adt_ndmp_restore.destination = path;
1560 
1561 	if (dest == NDMP_ADDR_LOCAL) {
1562 		event->adt_ndmp_restore.local_source = local_path;
1563 	} else {
1564 		event->adt_ndmp_restore.remote_source = conn->conn_sock;
1565 	}
1566 
1567 	if (result == 0) {
1568 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
1569 			NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1570 	} else {
1571 		if (adt_put_event(event, ADT_FAILURE, result) != 0)
1572 			NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1573 	}
1574 
1575 	adt_free_event(event);
1576 }
1577 
1578 
1579 /*
1580  * ndmpd_audit_connect
1581  *
1582  * Generate AUE_ndmp_connect audit record
1583  */
1584 /*ARGSUSED*/
1585 void
1586 ndmpd_audit_connect(ndmp_connection_t *conn, int result)
1587 {
1588 	adt_event_data_t *event;
1589 	adt_termid_t *termid;
1590 
1591 	if (adt_load_termid(conn->conn_sock, &termid) != 0) {
1592 		NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1593 		return;
1594 	}
1595 
1596 	if (adt_set_user(conn->conn_ah, ADT_NO_ATTRIB, ADT_NO_ATTRIB,
1597 	    ADT_NO_ATTRIB, ADT_NO_ATTRIB, termid, ADT_NEW) != 0) {
1598 		NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1599 		free(termid);
1600 		return;
1601 	}
1602 	free(termid);
1603 
1604 	if ((event = adt_alloc_event(conn->conn_ah,
1605 	    ADT_ndmp_connect)) == NULL) {
1606 		NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1607 		return;
1608 	}
1609 
1610 	if (result == 0) {
1611 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
1612 			NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1613 	} else {
1614 		if (adt_put_event(event, ADT_FAILURE, result) != 0)
1615 			NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1616 	}
1617 
1618 	adt_free_event(event);
1619 }
1620 
1621 
1622 /*
1623  * ndmpd_audit_disconnect
1624  *
1625  * Generate AUE_ndmp_disconnect audit record
1626  */
1627 /*ARGSUSED*/
1628 void
1629 ndmpd_audit_disconnect(ndmp_connection_t *conn)
1630 {
1631 	adt_event_data_t *event;
1632 
1633 	if ((event = adt_alloc_event(conn->conn_ah,
1634 	    ADT_ndmp_disconnect)) == NULL) {
1635 		NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1636 		return;
1637 	}
1638 	if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
1639 		NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1640 
1641 	adt_free_event(event);
1642 }
1643 
1644 void *
1645 ndmp_malloc(size_t size)
1646 {
1647 	void *data;
1648 
1649 	if ((data = calloc(1, size)) == NULL) {
1650 		NDMP_LOG(LOG_ERR, "Out of memory.");
1651 	}
1652 
1653 	return (data);
1654 }
1655