xref: /illumos-gate/usr/src/cmd/ndmpd/ndmp/ndmpd_comm.c (revision 2e0fe3efe5f9d579d4e44b3532d8e342c68b40ca)
1 /*
2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3  */
4 
5 /*
6  * BSD 3 Clause License
7  *
8  * Copyright (c) 2007, The Storage Networking Industry Association.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 	- Redistributions of source code must retain the above copyright
14  *	  notice, this list of conditions and the following disclaimer.
15  *
16  * 	- Redistributions in binary form must reproduce the above copyright
17  *	  notice, this list of conditions and the following disclaimer in
18  *	  the documentation and/or other materials provided with the
19  *	  distribution.
20  *
21  *	- Neither the name of The Storage Networking Industry Association (SNIA)
22  *	  nor the names of its contributors may be used to endorse or promote
23  *	  products derived from this software without specific prior written
24  *	  permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 /* Copyright (c) 2007, The Storage Networking Industry Association. */
39 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
40 
41 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <sys/time.h>
44 #include <sys/uio.h>
45 #include <unistd.h>
46 #include <string.h>
47 #include <stdlib.h>
48 #include <errno.h>
49 #include <netdb.h>
50 #include <netinet/in.h>
51 #include <arpa/inet.h>
52 #include "ndmpd.h"
53 #include "ndmpd_common.h"
54 
55 #define	NDMP_PROC_ERR	-1
56 #define	NDMP_PROC_MSG	1
57 #define	NDMP_PROC_REP	0
58 #define	NDMP_PROC_REP_ERR	2
59 
60 /*
61  * The ndmp connection version can be set through command line. If command line
62  * is not specified it will be set from the ndmp SMF version property.
63  */
64 int ndmp_ver = 0;
65 
66 /*
67  * The NDMP listening port number
68  */
69 int ndmp_port = 0;
70 
71 /*
72  * Restore path mechanism definition
73  * 0 means partial path restore and
74  * 1 means full path restore.
75  * Refer to NDMP_FULL_RESTORE_PATH for partial path and full path definition.
76  */
77 int ndmp_full_restore_path = 1;
78 
79 /*
80  * Do we support Direct Access Restore?
81  */
82 int ndmp_dar_support = 0;
83 
84 /*
85  * ndmp_connection_t handler function
86  */
87 static ndmpd_file_handler_func_t connection_file_handler;
88 
89 extern ndmp_handler_t ndmp_msghdl_tab[];
90 
91 static int ndmp_readit(void *connection_handle,
92     caddr_t buf,
93     int len);
94 static int ndmp_writeit(void *connection_handle,
95     caddr_t buf,
96     int len);
97 static int ndmp_recv_msg(ndmp_connection_t *connection);
98 static int ndmp_process_messages(ndmp_connection_t *connection,
99     boolean_t reply_expected);
100 static ndmp_msg_handler_t *ndmp_get_handler(ndmp_connection_t *connection,
101     ndmp_message message);
102 static boolean_t ndmp_check_auth_required(ndmp_message message);
103 static ndmp_handler_t *ndmp_get_interface(ndmp_message message);
104 void *ndmpd_worker(void *ptarg);
105 
106 #ifdef	lint
107 bool_t
108 xdr_ndmp_header(XDR *xdrs, ndmp_header *objp)
109 {
110 	xdrs = xdrs;
111 	objp = objp;
112 	return (0);
113 }
114 #endif	/* lint */
115 
116 /*
117  * ndmp_create_connection
118  *
119  * Allocate and initialize a connection structure.
120  *
121  * Parameters:
122  *   handler_tbl (input) - message handlers.
123  *
124  * Returns:
125  *   NULL - error
126  *   connection pointer
127  *
128  * Notes:
129  *   The returned connection should be destroyed using
130  *   ndmp_destroy_connection().
131  */
132 ndmp_connection_t *
133 ndmp_create_connection(void)
134 {
135 	ndmp_connection_t *connection;
136 
137 	connection = ndmp_malloc(sizeof (ndmp_connection_t));
138 	if (connection == NULL)
139 		return (NULL);
140 
141 	connection->conn_sock = -1;
142 	connection->conn_my_sequence = 0;
143 	connection->conn_authorized = FALSE;
144 	connection->conn_eof = FALSE;
145 	connection->conn_msginfo.mi_body = 0;
146 	connection->conn_version = ndmp_ver;
147 	connection->conn_client_data = 0;
148 	(void) mutex_init(&connection->conn_lock, 0, NULL);
149 	connection->conn_xdrs.x_ops = 0;
150 
151 	xdrrec_create(&connection->conn_xdrs, 0, 0, (caddr_t)connection,
152 	    ndmp_readit, ndmp_writeit);
153 
154 	if (connection->conn_xdrs.x_ops == 0) {
155 		NDMP_LOG(LOG_DEBUG, "xdrrec_create failed");
156 		(void) mutex_destroy(&connection->conn_lock);
157 		(void) close(connection->conn_sock);
158 		free(connection);
159 		return (0);
160 	}
161 	return ((ndmp_connection_t *)connection);
162 }
163 
164 /*
165  * ndmp_destroy_connection
166  *
167  * Shutdown a connection and release allocated resources.
168  *
169  * Parameters:
170  *   connection_handle (Input) - connection handle.
171  *
172  * Returns:
173  *   void
174  */
175 void
176 ndmp_destroy_connection(ndmp_connection_t *connection_handle)
177 {
178 	ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
179 
180 	if (connection->conn_sock >= 0) {
181 		(void) mutex_destroy(&connection->conn_lock);
182 		(void) close(connection->conn_sock);
183 		connection->conn_sock = -1;
184 	}
185 	xdr_destroy(&connection->conn_xdrs);
186 	free(connection);
187 }
188 
189 
190 /*
191  * ndmp_close
192  *
193  * Close a connection.
194  *
195  * Parameters:
196  *   connection_handle (Input) - connection handle.
197  *
198  * Returns:
199  *   void
200  */
201 void
202 ndmp_close(ndmp_connection_t *connection_handle)
203 {
204 	ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
205 
206 	ndmpd_audit_disconnect(connection);
207 	if (connection->conn_sock >= 0) {
208 		(void) mutex_destroy(&connection->conn_lock);
209 		(void) close(connection->conn_sock);
210 		connection->conn_sock = -1;
211 	}
212 	connection->conn_eof = TRUE;
213 
214 	/*
215 	 * We should close all the tapes that are used by this connection.
216 	 * In some cases the ndmp client opens a tape, but does not close the
217 	 * tape and closes the connection.
218 	 */
219 	ndmp_open_list_release(connection_handle);
220 }
221 
222 /*
223  * ndmp_start_worker
224  *
225  * Initializes and starts a ndmp_worker thread
226  */
227 int
228 ndmp_start_worker(ndmpd_worker_arg_t *argp)
229 {
230 	pthread_attr_t tattr;
231 	int rc;
232 
233 	(void) pthread_attr_init(&tattr);
234 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
235 	rc = pthread_create(NULL, &tattr, ndmpd_worker, (void *)argp);
236 	(void) pthread_attr_destroy(&tattr);
237 	return (rc);
238 }
239 
240 /*
241  * ndmp_run
242  *
243  * Creates a socket for listening and accepting connections
244  * from NDMP clients.
245  * Accepts connections and passes each connection to the connection
246  * handler.
247  *
248  * Parameters:
249  *   port (input)   -  NDMP server port.
250  *		     If 0, the port number will be retrieved from
251  *		     the network service database. If not found there,
252  *		     the default NDMP port number (from ndmp.x)
253  *		     will be used.
254  *   handler (input) - connection handler function.
255  *
256  * Returns:
257  *   This function normally never returns unless there's error.
258  *   -1 : error
259  *
260  * Notes:
261  *   This function does not return unless encountering an error
262  *   related to the listen socket.
263  */
264 int
265 ndmp_run(ulong_t port, ndmp_con_handler_func_t con_handler_func)
266 {
267 	int ns;
268 	int on, tmp;
269 	int server_socket;
270 	unsigned int ipaddr;
271 	struct sockaddr_in sin;
272 	int flag = 1;
273 	ndmpd_worker_arg_t *argp;
274 
275 	sin.sin_family = AF_INET;
276 	sin.sin_addr.s_addr = INADDR_ANY;
277 	sin.sin_port = htons(port);
278 
279 	if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
280 		NDMP_LOG(LOG_DEBUG, "Socket error: %m");
281 		return (-1);
282 	}
283 
284 	on = 1;
285 	(void) setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR,
286 	    (char *)&on, sizeof (on));
287 
288 
289 	if (bind(server_socket, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
290 		NDMP_LOG(LOG_DEBUG, "bind error: %m");
291 		(void) close(server_socket);
292 		return (-1);
293 	}
294 	if (listen(server_socket, 5) < 0) {
295 		NDMP_LOG(LOG_DEBUG, "listen error: %m");
296 		(void) close(server_socket);
297 		return (-1);
298 	}
299 
300 	for (; ; ) {
301 		if ((ns = tcp_accept(server_socket, &ipaddr)) < 0) {
302 			NDMP_LOG(LOG_DEBUG, "tcp_accept error: %m");
303 			continue;
304 		}
305 
306 		NDMP_LOG(LOG_DEBUG, "connection fd: %d", ns);
307 
308 		/*
309 		 * 'css' and 'crs' in the following env variables stand for:
310 		 * 'connection send size' and 'connection receive size'.
311 		 */
312 		tmp = atoi((const char *)ndmpd_get_prop_default(NDMP_SOCKET_CSS,
313 		    "65"));
314 		if (tmp <= 0)
315 			tmp = 65;
316 		NDMP_LOG(LOG_DEBUG, "css: %d_KB", tmp);
317 		ndmp_set_socket_snd_buf(ns, tmp * KILOBYTE);
318 
319 		tmp = atoi((const char *)ndmpd_get_prop_default(NDMP_SOCKET_CRS,
320 		    "80"));
321 		if (tmp <= 0)
322 			tmp = 80;
323 		NDMP_LOG(LOG_DEBUG, "crs: %d_KB", tmp);
324 		ndmp_set_socket_rcv_buf(ns, tmp * KILOBYTE);
325 
326 		ndmp_set_socket_nodelay(ns);
327 		(void) setsockopt(ns, SOL_SOCKET, SO_KEEPALIVE, &flag,
328 		    sizeof (flag));
329 
330 		if ((argp = ndmp_malloc(sizeof (ndmpd_worker_arg_t))) != NULL) {
331 			argp->nw_sock = ns;
332 			argp->nw_ipaddr = ipaddr;
333 			argp->nw_con_handler_func = con_handler_func;
334 			(void) ndmp_start_worker(argp);
335 		}
336 	}
337 }
338 
339 /*
340  * ndmpd_worker thread
341  *
342  * Parameters:
343  *   argp (input) - structure containing socket and handler function
344  *
345  * Returns:
346  *   0 - successful connection.
347  *  -1 - error.
348  */
349 void *
350 ndmpd_worker(void *ptarg)
351 {
352 	int sock;
353 	ndmp_connection_t *connection;
354 	ndmpd_worker_arg_t *argp = (ndmpd_worker_arg_t *)ptarg;
355 
356 	if (!argp)
357 		return ((void *)-1);
358 
359 	NS_INC(trun);
360 	sock = argp->nw_sock;
361 
362 	if ((connection = ndmp_create_connection()) == NULL) {
363 		(void) close(sock);
364 		free(argp);
365 		exit(1);
366 	}
367 
368 	/* initialize auditing session */
369 	if (adt_start_session(&connection->conn_ah, NULL, 0) != 0) {
370 		free(argp);
371 		return ((void *)-1);
372 	}
373 
374 	((ndmp_connection_t *)connection)->conn_sock = sock;
375 	(*argp->nw_con_handler_func)(connection);
376 	(void) adt_end_session(connection->conn_ah);
377 	ndmp_destroy_connection(connection);
378 	NS_DEC(trun);
379 
380 	free(argp);
381 	return (NULL);
382 }
383 
384 /*
385  * ndmp_process_requests
386  *
387  * Reads the next request message into the stream buffer.
388  * Processes messages until the stream buffer is empty.
389  *
390  * Parameters:
391  *   connection_handle (input) - connection handle.
392  *
393  * Returns:
394  *   0 - 1 or more messages successfully processed.
395  *  -1 - error; connection no longer established.
396  */
397 int
398 ndmp_process_requests(ndmp_connection_t *connection_handle)
399 {
400 	int rv;
401 	ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
402 
403 	(void) mutex_lock(&connection->conn_lock);
404 	rv = 0;
405 	if (ndmp_process_messages(connection, FALSE) < 0)
406 		rv = -1;
407 
408 	(void) mutex_unlock(&connection->conn_lock);
409 	return (rv);
410 }
411 
412 
413 /*
414  * ndmp_send_request
415  *
416  * Send an NDMP request message.
417  *
418  * Parameters:
419  *   connection_handle (input) - connection pointer.
420  *   message (input) - message number.
421  *   err (input)  - error code to place in header.
422  *   request_data (input) - message body.
423  *   reply (output) - reply message. If 0, reply will be
424  *				discarded.
425  *
426  * Returns:
427  *   0	- successful send.
428  *  -1	- error.
429  *   otherwise - error from reply header.
430  *
431  * Notes:
432  *   - The reply body is only returned if the error code is NDMP_NO_ERR.
433  */
434 int
435 ndmp_send_request(ndmp_connection_t *connection_handle, ndmp_message message,
436     ndmp_error err, void *request_data, void **reply)
437 {
438 	ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
439 	ndmp_header header;
440 	ndmp_msg_handler_t *handler;
441 	int r;
442 	struct timeval time;
443 
444 	/* Lookup info necessary for processing this request. */
445 	if (!(handler = ndmp_get_handler(connection, message))) {
446 		NDMP_LOG(LOG_DEBUG, "Sending message 0x%x: not supported",
447 		    message);
448 		return (-1);
449 	}
450 	(void) gettimeofday(&time, 0);
451 
452 	header.sequence = ++(connection->conn_my_sequence);
453 	header.time_stamp = time.tv_sec;
454 	header.message_type = NDMP_MESSAGE_REQUEST;
455 	header.message = message;
456 	header.reply_sequence = 0;
457 	header.error = err;
458 
459 	connection->conn_xdrs.x_op = XDR_ENCODE;
460 	if (!xdr_ndmp_header(&connection->conn_xdrs, &header)) {
461 		NDMP_LOG(LOG_DEBUG,
462 		    "Sending message 0x%x: encoding request header", message);
463 		(void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
464 		return (-1);
465 	}
466 	if (err == NDMP_NO_ERR && handler->mh_xdr_request && request_data) {
467 		if (!(*handler->mh_xdr_request)(&connection->conn_xdrs,
468 		    request_data)) {
469 			NDMP_LOG(LOG_DEBUG,
470 			    "Sending message 0x%x: encoding request body",
471 			    message);
472 			(void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
473 			return (-1);
474 		}
475 	}
476 	(void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
477 
478 	if (handler->mh_xdr_reply == 0) {
479 		NDMP_LOG(LOG_DEBUG, "handler->mh_xdr_reply == 0");
480 		return (0);
481 	}
482 
483 	/*
484 	 * Process messages until the reply to this request has been
485 	 * processed.
486 	 */
487 	for (; ; ) {
488 		r = ndmp_process_messages(connection, TRUE);
489 
490 		/* connection error? */
491 		if (r < 0)
492 			return (-1);
493 
494 		/* no reply received? */
495 		if (r == 0)
496 			continue;
497 
498 		/* reply received? */
499 		if (r == 1) {
500 			if (message !=
501 			    connection->conn_msginfo.mi_hdr.message) {
502 				NDMP_LOG(LOG_DEBUG,
503 				    "Received unexpected reply 0x%x",
504 				    connection->conn_msginfo.mi_hdr.message);
505 				ndmp_free_message(connection_handle);
506 				return (-1);
507 			}
508 			if (reply != NULL)
509 				*reply = connection->conn_msginfo.mi_body;
510 			else
511 				ndmp_free_message(connection_handle);
512 
513 			return (connection->conn_msginfo.mi_hdr.error);
514 		}
515 		/* error handling reply */
516 
517 		return (-1);
518 	}
519 }
520 
521 
522 /*
523  * ndmp_send_request_lock
524  *
525  * A wrapper for ndmp_send_request with locks.
526  *
527  * Parameters:
528  *   connection_handle (input) - connection pointer.
529  *   message (input) - message number.
530  *   err (input) - error code to place in header.
531  *   request_data (input) - message body.
532  *   reply (output) - reply message. If 0, reply will be
533  *				discarded.
534  *
535  * Returns:
536  *   0	- successful send.
537  *  -1	- error.
538  *   otherwise - error from reply header.
539  *
540  * Notes:
541  *   - The reply body is only returned if the error code is NDMP_NO_ERR.
542  */
543 int
544 ndmp_send_request_lock(ndmp_connection_t *connection_handle,
545     ndmp_message message, ndmp_error err, void *request_data, void **reply)
546 {
547 	int rv;
548 	ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
549 
550 	(void) mutex_lock(&connection->conn_lock);
551 
552 	rv = ndmp_send_request(connection_handle, message, err, request_data,
553 	    reply);
554 	(void) mutex_unlock(&connection->conn_lock);
555 	return (rv);
556 }
557 
558 
559 /*
560  * ndmp_send_response
561  *
562  * Send an NDMP reply message.
563  *
564  * Parameters:
565  *   connection_handle  (input)  - connection pointer.
566  *   err	       (input)  - error code to place in header.
567  *   reply	     (input)  - reply message body.
568  *
569  * Returns:
570  *   0 - successful send.
571  *  -1 - error.
572  *
573  * Notes:
574  *   - The body is only sent if the error code is NDMP_NO_ERR.
575  */
576 int
577 ndmp_send_response(ndmp_connection_t *connection_handle, ndmp_error err,
578     void *reply)
579 {
580 	ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
581 	ndmp_header header;
582 	struct timeval time;
583 
584 	(void) gettimeofday(&time, 0);
585 
586 	header.sequence = ++(connection->conn_my_sequence);
587 	header.time_stamp = time.tv_sec;
588 	header.message_type = NDMP_MESSAGE_REPLY;
589 	header.message = connection->conn_msginfo.mi_hdr.message;
590 	header.reply_sequence = connection->conn_msginfo.mi_hdr.sequence;
591 	header.error = err;
592 
593 	connection->conn_xdrs.x_op = XDR_ENCODE;
594 	if (!xdr_ndmp_header(&connection->conn_xdrs, &header)) {
595 		NDMP_LOG(LOG_DEBUG, "Sending message 0x%x: "
596 		    "encoding reply header",
597 		    header.message);
598 		(void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
599 		return (-1);
600 	}
601 	if (err == NDMP_NO_ERR &&
602 	    connection->conn_msginfo.mi_handler->mh_xdr_reply &&
603 	    reply) {
604 		if (!(*connection->conn_msginfo.mi_handler->mh_xdr_reply)(
605 		    &connection->conn_xdrs, reply)) {
606 			NDMP_LOG(LOG_DEBUG,
607 			    "Sending message 0x%x: encoding reply body",
608 			    header.message);
609 			(void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
610 			return (-1);
611 	}
612 	}
613 	(void) xdrrec_endofrecord(&connection->conn_xdrs, 1);
614 	return (0);
615 }
616 
617 /*
618  * ndmp_free_message
619  *
620  * Free the memory of NDMP message body.
621  *
622  * Parameters:
623  *   connection_handle  (input)  - connection pointer.
624  *
625  * Returns:
626  *   void
627  *
628  */
629 void
630 ndmp_free_message(ndmp_connection_t *connection_handle)
631 {
632 	ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
633 
634 	if (connection->conn_msginfo.mi_handler == NULL ||
635 	    connection->conn_msginfo.mi_body == NULL)
636 		return;
637 
638 	connection->conn_xdrs.x_op = XDR_FREE;
639 	if (connection->conn_msginfo.mi_hdr.message_type ==
640 	    NDMP_MESSAGE_REQUEST) {
641 		if (connection->conn_msginfo.mi_handler->mh_xdr_request)
642 			(*connection->conn_msginfo.mi_handler->mh_xdr_request)(
643 			    &connection->conn_xdrs,
644 			    connection->conn_msginfo.mi_body);
645 	} else {
646 		if (connection->conn_msginfo.mi_handler->mh_xdr_reply)
647 			(*connection->conn_msginfo.mi_handler->mh_xdr_reply)(
648 			    &connection->conn_xdrs,
649 			    connection->conn_msginfo.mi_body);
650 	}
651 
652 	(void) free(connection->conn_msginfo.mi_body);
653 	connection->conn_msginfo.mi_body = 0;
654 }
655 
656 /*
657  * ndmp_get_fd
658  *
659  * Returns the connection file descriptor.
660  *
661  * Parameters:
662  *   connection_handle (input) - connection handle
663  *
664  * Returns:
665  *   >=0 - file descriptor.
666  *   -1  - connection not open.
667  */
668 int
669 ndmp_get_fd(ndmp_connection_t *connection_handle)
670 {
671 	return (((ndmp_connection_t *)connection_handle)->conn_sock);
672 }
673 
674 
675 /*
676  * ndmp_set_client_data
677  *
678  * This function provides a means for the library client to provide
679  * a pointer to some user data structure that is retrievable by
680  * each message handler via ndmp_get_client_data.
681  *
682  * Parameters:
683  *   connection_handle  (input) - connection handle.
684  *   client_data	(input) - user data pointer.
685  *
686  * Returns:
687  *   void
688  */
689 void
690 ndmp_set_client_data(ndmp_connection_t *connection_handle, void *client_data)
691 {
692 	((ndmp_connection_t *)connection_handle)->conn_client_data =
693 	    client_data;
694 }
695 
696 
697 /*
698  * ndmp_get_client_data
699  *
700  * This function provides a means for the library client to provide
701  * a pointer to some user data structure that is retrievable by
702  * each message handler via ndmp_get_client_data.
703  *
704  * Parameters:
705  *   connection_handle (input) - connection handle.
706  *
707  * Returns:
708  *   client data pointer.
709  */
710 void *
711 ndmp_get_client_data(ndmp_connection_t *connection_handle)
712 {
713 	return (((ndmp_connection_t *)connection_handle)->conn_client_data);
714 }
715 
716 
717 /*
718  * ndmp_set_version
719  *
720  * Sets the NDMP protocol version to be used on the connection.
721  *
722  * Parameters:
723  *   connection_handle  (input) - connection handle.
724  *   version	   (input) - protocol version.
725  *
726  * Returns:
727  *   void
728  */
729 void
730 ndmp_set_version(ndmp_connection_t *connection_handle, ushort_t version)
731 {
732 	((ndmp_connection_t *)connection_handle)->conn_version = version;
733 }
734 
735 
736 /*
737  * ndmp_get_version
738  *
739  * Gets the NDMP protocol version in use on the connection.
740  *
741  * Parameters:
742  *   connection_handle  (input) - connection handle.
743  *   version	   (input) - protocol version.
744  *
745  * Returns:
746  *   void
747  */
748 ushort_t
749 ndmp_get_version(ndmp_connection_t *connection_handle)
750 {
751 	return (((ndmp_connection_t *)connection_handle)->conn_version);
752 }
753 
754 
755 /*
756  * ndmp_set_authorized
757  *
758  * Mark the connection as either having been authorized or not.
759  *
760  * Parameters:
761  *   connection_handle  (input) - connection handle.
762  *   authorized	(input) - TRUE or FALSE.
763  *
764  * Returns:
765  *   void
766  */
767 void
768 ndmp_set_authorized(ndmp_connection_t *connection_handle, boolean_t authorized)
769 {
770 	((ndmp_connection_t *)connection_handle)->conn_authorized = authorized;
771 }
772 
773 
774 /*
775  * ndmpd_main
776  *
777  * NDMP main function called from main().
778  *
779  * Parameters:
780  *   void
781  *
782  * Returns:
783  *   void
784  */
785 void
786 ndmpd_main(void)
787 {
788 	char *propval;
789 
790 	ndmp_load_params();
791 	if (ndmp_log_open_file() != 0) {
792 		NDMP_LOG(LOG_ERR,
793 		    "Could not open log file properly.");
794 	}
795 
796 	/*
797 	 * Find ndmp port number to be used. If ndmpd is run as command line
798 	 * and port number is supplied, use that port number. If port number is
799 	 * is not supplied, find out if ndmp port property is set. If ndmp
800 	 * port property is set, use that port number otherwise use the defaule
801 	 * port number.
802 	 */
803 	if (ndmp_port == 0) {
804 		if ((propval = ndmpd_get_prop(NDMP_TCP_PORT)) == NULL ||
805 		    *propval == 0)
806 			ndmp_port = NDMPPORT;
807 		else
808 			ndmp_port = strtol(propval, 0, 0);
809 	}
810 
811 	if (ndmp_run(ndmp_port, connection_handler) == -1)
812 		perror("ndmp_run ERROR");
813 
814 	ndmp_log_close_file();
815 }
816 
817 /*
818  * connection_handler
819  *
820  * NDMP connection handler.
821  * Waits for, reads, and processes NDMP requests on a connection.
822  *
823  * Parameters:
824  *   connection (input) - connection handle.
825  *
826  * Return:
827  *   void
828  */
829 void
830 connection_handler(ndmp_connection_t *connection)
831 {
832 	static int conn_id = 1;
833 	ndmpd_session_t session;
834 	ndmp_notify_connected_request req;
835 	int connection_fd;
836 
837 	(void) memset(&session, 0, sizeof (session));
838 	session.ns_connection = connection;
839 	session.ns_eof = FALSE;
840 	/*
841 	 * The 'protocol_version' must be 1 at first, since the client talks
842 	 * to the server in version 1 then they can move to a higher
843 	 * protocol version.
844 	 */
845 	session.ns_protocol_version = ndmp_ver;
846 
847 	session.ns_scsi.sd_is_open = -1;
848 	session.ns_scsi.sd_devid = -1;
849 
850 	session.ns_scsi.sd_sid = 0;
851 	session.ns_scsi.sd_lun = 0;
852 	session.ns_scsi.sd_valid_target_set = 0;
853 	(void) memset(session.ns_scsi.sd_adapter_name, 0,
854 	    sizeof (session.ns_scsi.sd_adapter_name));
855 
856 	session.ns_tape.td_fd = -1;
857 	session.ns_tape.td_sid = 0;
858 	session.ns_tape.td_lun = 0;
859 	(void) memset(session.ns_tape.td_adapter_name, 0,
860 	    sizeof (session.ns_tape.td_adapter_name));
861 	session.ns_tape.td_pos = 0;
862 	session.ns_tape.td_record_count = 0;
863 	session.ns_file_handler_list = 0;
864 
865 	(void) ndmpd_data_init(&session);
866 	ndmpd_file_history_init(&session);
867 	if (ndmpd_mover_init(&session) < 0)
868 		return;
869 
870 	if (ndmp_lbr_init(&session) < 0)
871 		return;
872 
873 	/*
874 	 * Setup defaults here. The init functions can not set defaults
875 	 * since the init functions are called by the stop request handlers
876 	 * and client set variables need to persist across data operations.
877 	 */
878 	session.ns_mover.md_record_size = MAX_RECORD_SIZE;
879 
880 	ndmp_set_client_data(connection, (void *)&session);
881 
882 	req.reason = NDMP_CONNECTED;
883 	req.protocol_version = ndmp_ver;
884 	req.text_reason = "";
885 
886 	if (ndmp_send_request_lock(connection, NDMP_NOTIFY_CONNECTION_STATUS,
887 	    NDMP_NO_ERR, (void *)&req, 0) < 0) {
888 		NDMP_LOG(LOG_DEBUG, "Connection terminated");
889 		return;
890 	}
891 	connection_fd = ndmp_get_fd(connection);
892 
893 	NDMP_LOG(LOG_DEBUG, "connection_fd: %d", connection_fd);
894 
895 	/*
896 	 * Add the handler function for the connection to the DMA.
897 	 */
898 	if (ndmpd_add_file_handler(&session, (void *)&session, connection_fd,
899 	    NDMPD_SELECT_MODE_READ, HC_CLIENT, connection_file_handler) != 0) {
900 		NDMP_LOG(LOG_DEBUG, "Could not register session handler.");
901 		return;
902 	}
903 
904 	/*
905 	 * Register the connection in the list of active connections.
906 	 */
907 	if (ndmp_connect_list_add(connection, &conn_id) != 0) {
908 		NDMP_LOG(LOG_ERR,
909 		    "Could not register the session to the server.");
910 		(void) ndmpd_remove_file_handler(&session, connection_fd);
911 		return;
912 	}
913 
914 	session.hardlink_q = hardlink_q_init();
915 
916 	while (session.ns_eof == FALSE)
917 		(void) ndmpd_select(&session, TRUE, HC_ALL);
918 
919 	hardlink_q_cleanup(session.hardlink_q);
920 
921 	NDMP_LOG(LOG_DEBUG, "Connection terminated");
922 
923 	(void) ndmpd_remove_file_handler(&session, connection_fd);
924 
925 	if (session.ns_scsi.sd_is_open != -1) {
926 		NDMP_LOG(LOG_DEBUG, "scsi.is_open: %d",
927 		    session.ns_scsi.sd_is_open);
928 		(void) ndmp_open_list_del(session.ns_scsi.sd_adapter_name,
929 		    session.ns_scsi.sd_sid, session.ns_scsi.sd_lun);
930 	}
931 	if (session.ns_tape.td_fd != -1) {
932 		NDMP_LOG(LOG_DEBUG, "tape.fd: %d", session.ns_tape.td_fd);
933 		(void) close(session.ns_tape.td_fd);
934 		(void) ndmp_open_list_del(session.ns_tape.td_adapter_name,
935 		    session.ns_tape.td_sid, session.ns_tape.td_lun);
936 	}
937 	ndmpd_mover_shut_down(&session);
938 	ndmp_lbr_cleanup(&session);
939 	ndmpd_data_cleanup(&session);
940 	ndmpd_file_history_cleanup(&session, FALSE);
941 	ndmpd_mover_cleanup(&session);
942 
943 	(void) ndmp_connect_list_del(connection);
944 }
945 
946 
947 /*
948  * connection_file_handler
949  *
950  * ndmp_connection_t file handler function.
951  * Called by ndmpd_select when data is available to be read on the
952  * NDMP connection.
953  *
954  * Parameters:
955  *   cookie (input) - session pointer.
956  *   fd      (input) - connection file descriptor.
957  *   mode    (input) - select mode.
958  *
959  * Returns:
960  *   void.
961  */
962 /*ARGSUSED*/
963 static void
964 connection_file_handler(void *cookie, int fd, ulong_t mode)
965 {
966 	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
967 
968 	if (ndmp_process_requests(session->ns_connection) < 0)
969 		session->ns_eof = TRUE;
970 }
971 
972 
973 /* ************* private functions *************************************** */
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 
1656 /*
1657  * get_backup_path_v3
1658  *
1659  * Get the backup path from the NDMP environment variables.
1660  *
1661  * Parameters:
1662  *   params (input) - pointer to the parameters structure.
1663  *
1664  * Returns:
1665  *   The backup path: if anything is specified
1666  *   NULL: Otherwise
1667  */
1668 char *
1669 get_backup_path_v3(ndmpd_module_params_t *params)
1670 {
1671 	char *bkpath;
1672 
1673 	bkpath = MOD_GETENV(params, "PREFIX");
1674 	if (!bkpath)
1675 		bkpath = MOD_GETENV(params, "FILESYSTEM");
1676 
1677 
1678 	if (!bkpath) {
1679 		MOD_LOGV3(params, NDMP_LOG_ERROR,
1680 		    "Backup path not defined.\n");
1681 	} else {
1682 		NDMP_LOG(LOG_DEBUG, "bkpath: \"%s\"", bkpath);
1683 	}
1684 
1685 	return (bkpath);
1686 }
1687 
1688 /*
1689  * get_backup_path
1690  *
1691  * Find the backup path from the environment variables (v2)
1692  */
1693 char *
1694 get_backup_path_v2(ndmpd_module_params_t *params)
1695 {
1696 	char *bkpath;
1697 
1698 	bkpath = MOD_GETENV(params, "PREFIX");
1699 	if (bkpath == NULL)
1700 		bkpath = MOD_GETENV(params, "FILESYSTEM");
1701 
1702 	if (bkpath == NULL) {
1703 		MOD_LOG(params, "Error: restore path not specified.\n");
1704 		return (NULL);
1705 	}
1706 
1707 	if (*bkpath != '/') {
1708 		MOD_LOG(params, "Error: relative backup path not allowed.\n");
1709 		return (NULL);
1710 	}
1711 
1712 	return (bkpath);
1713 }
1714