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