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