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 */
66int ndmp_ver = 0;
67
68/*
69 * The NDMP listening port number
70 */
71int 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 */
79int ndmp_full_restore_path = 1;
80
81/*
82 * Do we support Direct Access Restore?
83 */
84int ndmp_dar_support = 0;
85
86/*
87 * ndmp_connection_t handler function
88 */
89static ndmpd_file_handler_func_t connection_file_handler;
90
91extern ndmp_handler_t ndmp_msghdl_tab[];
92
93static int ndmp_readit(void *connection_handle,
94    caddr_t buf,
95    int len);
96static int ndmp_writeit(void *connection_handle,
97    caddr_t buf,
98    int len);
99static int ndmp_recv_msg(ndmp_connection_t *connection);
100static int ndmp_process_messages(ndmp_connection_t *connection,
101    boolean_t reply_expected);
102static ndmp_msg_handler_t *ndmp_get_handler(ndmp_connection_t *connection,
103    ndmp_message message);
104static boolean_t ndmp_check_auth_required(ndmp_message message);
105static ndmp_handler_t *ndmp_get_interface(ndmp_message message);
106void *ndmpd_worker(void *ptarg);
107
108#ifdef	lint
109bool_t
110xdr_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 */
134ndmp_connection_t *
135ndmp_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 */
177void
178ndmp_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 */
203void
204ndmp_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 */
229int
230ndmp_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 */
266int
267ndmp_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 */
328void *
329ndmpd_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 */
376int
377ndmp_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 */
413int
414ndmp_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 */
522int
523ndmp_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 */
555int
556ndmp_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 */
608void
609ndmp_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 */
647int
648ndmp_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 */
668void
669ndmp_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 */
689void *
690ndmp_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 */
708void
709ndmp_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 */
727ushort_t
728ndmp_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 */
746void
747ndmp_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 */
764void
765ndmpd_main(void)
766{
767	char *propval;
768
769	ndmp_load_params();
770
771	/*
772	 * Find ndmp port number to be used. If ndmpd is run as command line
773	 * and port number is supplied, use that port number. If port number is
774	 * is not supplied, find out if ndmp port property is set. If ndmp
775	 * port property is set, use that port number otherwise use the defaule
776	 * port number.
777	 */
778	if (ndmp_port == 0) {
779		if ((propval = ndmpd_get_prop(NDMP_TCP_PORT)) == NULL ||
780		    *propval == 0)
781			ndmp_port = NDMPPORT;
782		else
783			ndmp_port = strtol(propval, 0, 0);
784	}
785
786	if (ndmp_run(ndmp_port, connection_handler) == -1)
787		perror("ndmp_run ERROR");
788}
789
790/*
791 * connection_handler
792 *
793 * NDMP connection handler.
794 * Waits for, reads, and processes NDMP requests on a connection.
795 *
796 * Parameters:
797 *   connection (input) - connection handle.
798 *
799 * Return:
800 *   void
801 */
802void
803connection_handler(ndmp_connection_t *connection)
804{
805	static int conn_id = 1;
806	ndmpd_session_t session;
807	ndmp_notify_connected_request req;
808	int connection_fd;
809
810	(void) memset(&session, 0, sizeof (session));
811	session.ns_connection = connection;
812	session.ns_eof = FALSE;
813	/*
814	 * The 'protocol_version' must be 1 at first, since the client talks
815	 * to the server in version 1 then they can move to a higher
816	 * protocol version.
817	 */
818	session.ns_protocol_version = ndmp_ver;
819
820	session.ns_scsi.sd_is_open = -1;
821	session.ns_scsi.sd_devid = -1;
822
823	session.ns_scsi.sd_sid = 0;
824	session.ns_scsi.sd_lun = 0;
825	session.ns_scsi.sd_valid_target_set = 0;
826	(void) memset(session.ns_scsi.sd_adapter_name, 0,
827	    sizeof (session.ns_scsi.sd_adapter_name));
828
829	session.ns_tape.td_fd = -1;
830	session.ns_tape.td_sid = 0;
831	session.ns_tape.td_lun = 0;
832	(void) memset(session.ns_tape.td_adapter_name, 0,
833	    sizeof (session.ns_tape.td_adapter_name));
834	session.ns_tape.td_pos = 0;
835	session.ns_tape.td_record_count = 0;
836	session.ns_file_handler_list = 0;
837
838	(void) ndmpd_data_init(&session);
839	ndmpd_file_history_init(&session);
840	if (ndmpd_mover_init(&session) < 0)
841		return;
842
843	if (ndmp_lbr_init(&session) < 0)
844		return;
845
846	/*
847	 * Setup defaults here. The init functions can not set defaults
848	 * since the init functions are called by the stop request handlers
849	 * and client set variables need to persist across data operations.
850	 */
851	session.ns_mover.md_record_size = MAX_RECORD_SIZE;
852
853	ndmp_set_client_data(connection, (void *)&session);
854
855	req.reason = NDMP_CONNECTED;
856	req.protocol_version = ndmp_ver;
857	req.text_reason = "";
858
859	if (ndmp_send_request_lock(connection, NDMP_NOTIFY_CONNECTION_STATUS,
860	    NDMP_NO_ERR, (void *)&req, 0) < 0) {
861		NDMP_LOG(LOG_DEBUG, "Connection terminated");
862		return;
863	}
864	connection_fd = ndmp_get_fd(connection);
865
866	NDMP_LOG(LOG_DEBUG, "connection_fd: %d", connection_fd);
867
868	/*
869	 * Add the handler function for the connection to the DMA.
870	 */
871	if (ndmpd_add_file_handler(&session, (void *)&session, connection_fd,
872	    NDMPD_SELECT_MODE_READ, HC_CLIENT, connection_file_handler) != 0) {
873		NDMP_LOG(LOG_DEBUG, "Could not register session handler.");
874		return;
875	}
876
877	/*
878	 * Register the connection in the list of active connections.
879	 */
880	if (ndmp_connect_list_add(connection, &conn_id) != 0) {
881		NDMP_LOG(LOG_ERR,
882		    "Could not register the session to the server.");
883		(void) ndmpd_remove_file_handler(&session, connection_fd);
884		return;
885	}
886
887	session.hardlink_q = hardlink_q_init();
888
889	while (session.ns_eof == FALSE)
890		(void) ndmpd_select(&session, TRUE, HC_ALL);
891
892	hardlink_q_cleanup(session.hardlink_q);
893
894	NDMP_LOG(LOG_DEBUG, "Connection terminated");
895
896	(void) ndmpd_remove_file_handler(&session, connection_fd);
897
898	if (session.ns_scsi.sd_is_open != -1) {
899		NDMP_LOG(LOG_DEBUG, "scsi.is_open: %d",
900		    session.ns_scsi.sd_is_open);
901		(void) ndmp_open_list_del(session.ns_scsi.sd_adapter_name,
902		    session.ns_scsi.sd_sid, session.ns_scsi.sd_lun);
903	}
904	if (session.ns_tape.td_fd != -1) {
905		NDMP_LOG(LOG_DEBUG, "tape.fd: %d", session.ns_tape.td_fd);
906		(void) close(session.ns_tape.td_fd);
907		(void) ndmp_open_list_del(session.ns_tape.td_adapter_name,
908		    session.ns_tape.td_sid, session.ns_tape.td_lun);
909	}
910	ndmpd_mover_shut_down(&session);
911	ndmp_lbr_cleanup(&session);
912	ndmpd_data_cleanup(&session);
913	ndmpd_file_history_cleanup(&session, FALSE);
914	ndmpd_mover_cleanup(&session);
915
916	(void) ndmp_connect_list_del(connection);
917}
918
919
920/*
921 * connection_file_handler
922 *
923 * ndmp_connection_t file handler function.
924 * Called by ndmpd_select when data is available to be read on the
925 * NDMP connection.
926 *
927 * Parameters:
928 *   cookie (input) - session pointer.
929 *   fd      (input) - connection file descriptor.
930 *   mode    (input) - select mode.
931 *
932 * Returns:
933 *   void.
934 */
935/*ARGSUSED*/
936static void
937connection_file_handler(void *cookie, int fd, ulong_t mode)
938{
939	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
940
941	if (ndmp_process_requests(session->ns_connection) < 0)
942		session->ns_eof = TRUE;
943}
944
945
946/* ************* private functions *************************************** */
947
948/*
949 * ndmp_readit
950 *
951 * Low level read routine called by the xdrrec library.
952 *
953 * Parameters:
954 *   connection (input) - connection pointer.
955 *   buf	(input) - location to store received data.
956 *   len	(input) - max number of bytes to read.
957 *
958 * Returns:
959 *   >0 - number of bytes received.
960 *   -1 - error.
961 */
962static int
963ndmp_readit(void *connection_handle, caddr_t buf, int len)
964{
965	ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
966
967	len = read(connection->conn_sock, buf, len);
968	if (len <= 0) {
969		/* ndmp_connection_t has been closed. */
970		connection->conn_eof = TRUE;
971		return (-1);
972	}
973	return (len);
974}
975
976/*
977 * ndmp_writeit
978 *
979 * Low level write routine called by the xdrrec library.
980 *
981 * Parameters:
982 *   connection (input) - connection pointer.
983 *   buf	(input) - location to store received data.
984 *   len	(input) - max number of bytes to read.
985 *
986 * Returns:
987 *   >0 - number of bytes sent.
988 *   -1 - error.
989 */
990static int
991ndmp_writeit(void *connection_handle, caddr_t buf, int len)
992{
993	ndmp_connection_t *connection = (ndmp_connection_t *)connection_handle;
994	register int n;
995	register int cnt;
996
997	for (cnt = len; cnt > 0; cnt -= n, buf += n) {
998		if ((n = write(connection->conn_sock, buf, cnt)) < 0) {
999			connection->conn_eof = TRUE;
1000			return (-1);
1001		}
1002	}
1003
1004	return (len);
1005}
1006
1007
1008/*
1009 * ndmp_recv_msg
1010 *
1011 * Read the next message.
1012 *
1013 * Parameters:
1014 *   connection (input)  - connection pointer.
1015 *   msg	(output) - received message.
1016 *
1017 * Returns:
1018 *   0 - Message successfully received.
1019 *   error number - Message related error.
1020 *  -1 - Error decoding the message header.
1021 */
1022static int
1023ndmp_recv_msg(ndmp_connection_t *connection)
1024{
1025	bool_t(*xdr_func) (XDR *, ...) = NULL;
1026
1027	/* Decode the header. */
1028	connection->conn_xdrs.x_op = XDR_DECODE;
1029	(void) xdrrec_skiprecord(&connection->conn_xdrs);
1030	if (!xdr_ndmp_header(&connection->conn_xdrs,
1031	    &connection->conn_msginfo.mi_hdr))
1032		return (-1);
1033
1034	/* Lookup info necessary for processing this message. */
1035	if ((connection->conn_msginfo.mi_handler = ndmp_get_handler(connection,
1036	    connection->conn_msginfo.mi_hdr.message)) == 0) {
1037		NDMP_LOG(LOG_DEBUG, "Message 0x%x not supported",
1038		    connection->conn_msginfo.mi_hdr.message);
1039		return (NDMP_NOT_SUPPORTED_ERR);
1040	}
1041	connection->conn_msginfo.mi_body = 0;
1042
1043	if (connection->conn_msginfo.mi_hdr.error != NDMP_NO_ERR)
1044		return (0);
1045
1046	/* Determine body type */
1047	if (connection->conn_msginfo.mi_hdr.message_type ==
1048	    NDMP_MESSAGE_REQUEST) {
1049		if (ndmp_check_auth_required(
1050		    connection->conn_msginfo.mi_hdr.message) &&
1051		    !connection->conn_authorized) {
1052			NDMP_LOG(LOG_DEBUG,
1053			    "Processing request 0x%x:connection not authorized",
1054			    connection->conn_msginfo.mi_hdr.message);
1055			return (NDMP_NOT_AUTHORIZED_ERR);
1056		}
1057		if (connection->conn_msginfo.mi_handler->mh_sizeof_request >
1058		    0) {
1059			xdr_func =
1060			    connection->conn_msginfo.mi_handler->mh_xdr_request;
1061			if (xdr_func == NULL) {
1062				NDMP_LOG(LOG_DEBUG,
1063				    "Processing request 0x%x: no xdr function "
1064				    "in handler table",
1065				    connection->conn_msginfo.mi_hdr.message);
1066				return (NDMP_NOT_SUPPORTED_ERR);
1067			}
1068			connection->conn_msginfo.mi_body = ndmp_malloc(
1069			    connection->conn_msginfo.mi_handler->
1070			    mh_sizeof_request);
1071			if (connection->conn_msginfo.mi_body == NULL)
1072				return (NDMP_NO_MEM_ERR);
1073
1074			(void) memset(connection->conn_msginfo.mi_body, 0,
1075			    connection->conn_msginfo.mi_handler->
1076			    mh_sizeof_request);
1077		}
1078	} else {
1079		if (connection->conn_msginfo.mi_handler->mh_sizeof_reply > 0) {
1080			xdr_func =
1081			    connection->conn_msginfo.mi_handler->mh_xdr_reply;
1082			if (xdr_func == NULL) {
1083				NDMP_LOG(LOG_DEBUG,
1084				    "Processing reply 0x%x: no xdr function "
1085				    "in handler table",
1086				    connection->conn_msginfo.mi_hdr.message);
1087				return (NDMP_NOT_SUPPORTED_ERR);
1088			}
1089			connection->conn_msginfo.mi_body = ndmp_malloc(
1090			    connection->conn_msginfo.mi_handler->
1091			    mh_sizeof_reply);
1092			if (connection->conn_msginfo.mi_body == NULL)
1093				return (NDMP_NO_MEM_ERR);
1094
1095			(void) memset(connection->conn_msginfo.mi_body, 0,
1096			    connection->conn_msginfo.mi_handler->
1097			    mh_sizeof_reply);
1098		}
1099	}
1100
1101	/* Decode message arguments if needed */
1102	if (xdr_func) {
1103		if (!(*xdr_func)(&connection->conn_xdrs,
1104		    connection->conn_msginfo.mi_body)) {
1105			NDMP_LOG(LOG_DEBUG,
1106			    "Processing message 0x%x: error decoding arguments",
1107			    connection->conn_msginfo.mi_hdr.message);
1108			free(connection->conn_msginfo.mi_body);
1109			connection->conn_msginfo.mi_body = 0;
1110			return (NDMP_XDR_DECODE_ERR);
1111		}
1112	}
1113	return (0);
1114}
1115
1116/*
1117 * ndmp_process_messages
1118 *
1119 * Reads the next message into the stream buffer.
1120 * Processes messages until the stream buffer is empty.
1121 *
1122 * This function processes all data in the stream buffer before returning.
1123 * This allows functions like poll() to be used to determine when new
1124 * messages have arrived. If only some of the messages in the stream buffer
1125 * were processed and then poll was called, poll() could block waiting for
1126 * a message that had already been received and read into the stream buffer.
1127 *
1128 * This function processes both request and reply messages.
1129 * Request messages are dispatched using the appropriate function from the
1130 * message handling table.
1131 * Only one reply messages may be pending receipt at a time.
1132 * A reply message, if received, is placed in connection->conn_msginfo
1133 * before returning to the caller.
1134 * Errors are reported if a reply is received but not expected or if
1135 * more than one reply message is received
1136 *
1137 * Parameters:
1138 *   connection     (input)  - connection pointer.
1139 *   reply_expected (output) - TRUE  - a reply message is expected.
1140 *			     FALSE - no reply message is expected and
1141 *			     an error will be reported if a reply
1142 *			     is received.
1143 *
1144 * Returns:
1145 *   NDMP_PROC_REP_ERR - 1 or more messages successfully processed,
1146 *   	error processing reply message.
1147 *   NDMP_PROC_REP_ERR - 1 or more messages successfully processed,
1148 *	reply seen.
1149 *   NDMP_PROC_REP_ERR - 1 or more messages successfully processed,
1150 * 	no reply seen.
1151 *   NDMP_PROC_REP_ERR - error; connection no longer established.
1152 *
1153 * Notes:
1154 *   If the peer is generating a large number of requests, a caller
1155 *   looking for a reply will be blocked while the requests are handled.
1156 *   This is because this function does not return until the stream
1157 *   buffer is empty.
1158 *   Code needs to be added to allow a return if the stream buffer
1159 *   is not empty but there is data available on the socket. This will
1160 *   prevent poll() from blocking and prevent a caller looking for a reply
1161 *   from getting blocked by a bunch of requests.
1162 */
1163static int
1164ndmp_process_messages(ndmp_connection_t *connection, boolean_t reply_expected)
1165{
1166	msg_info_t reply_msginfo;
1167	boolean_t reply_read = FALSE;
1168	boolean_t reply_error = FALSE;
1169	int err;
1170
1171	NDMP_LOG(LOG_DEBUG, "reply_expected: %s",
1172	    reply_expected == TRUE ? "TRUE" : "FALSE");
1173
1174	(void) memset((void *)&reply_msginfo, 0, sizeof (msg_info_t));
1175
1176	do {
1177		(void) memset((void *)&connection->conn_msginfo, 0,
1178		    sizeof (msg_info_t));
1179
1180		if ((err = ndmp_recv_msg(connection)) != NDMP_NO_ERR) {
1181			if (connection->conn_eof) {
1182				NDMP_LOG(LOG_DEBUG, "detected eof");
1183				return (NDMP_PROC_ERR);
1184			}
1185			if (err < 1) {
1186				NDMP_LOG(LOG_DEBUG, "error decoding header");
1187
1188				/*
1189				 * Error occurred decoding the header.
1190				 * Don't send a reply since we don't know
1191				 * the message or if the message was even
1192				 * a request message.  To be safe, assume
1193				 * that the message was a reply if a reply
1194				 * was expected. Need to do this to prevent
1195				 * hanging ndmp_send_request() waiting for a
1196				 * reply.  Don't set reply_read so that the
1197				 * reply will be processed if it is received
1198				 * later.
1199				 */
1200				if (reply_read == FALSE)
1201					reply_error = TRUE;
1202
1203				continue;
1204			}
1205			if (connection->conn_msginfo.mi_hdr.message_type
1206			    != NDMP_MESSAGE_REQUEST) {
1207				NDMP_LOG(LOG_DEBUG, "received reply: 0x%x",
1208				    connection->conn_msginfo.mi_hdr.message);
1209
1210				if (reply_expected == FALSE ||
1211				    reply_read == TRUE)
1212					NDMP_LOG(LOG_DEBUG,
1213					    "Unexpected reply message: 0x%x",
1214					    connection->conn_msginfo.mi_hdr.
1215					    message);
1216
1217				ndmp_free_message((ndmp_connection_t *)
1218				    connection);
1219
1220				if (reply_read == FALSE) {
1221					reply_read = TRUE;
1222					reply_error = TRUE;
1223				}
1224				continue;
1225			}
1226			NDMP_LOG(LOG_DEBUG, "received request: 0x%x",
1227			    connection->conn_msginfo.mi_hdr.message);
1228
1229			(void) ndmp_send_response((ndmp_connection_t *)
1230			    connection, err, NULL);
1231			ndmp_free_message((ndmp_connection_t *)connection);
1232			continue;
1233		}
1234		if (connection->conn_msginfo.mi_hdr.message_type
1235		    != NDMP_MESSAGE_REQUEST) {
1236			NDMP_LOG(LOG_DEBUG, "received reply: 0x%x",
1237			    connection->conn_msginfo.mi_hdr.message);
1238
1239			if (reply_expected == FALSE || reply_read == TRUE) {
1240				NDMP_LOG(LOG_DEBUG,
1241				    "Unexpected reply message: 0x%x",
1242				    connection->conn_msginfo.mi_hdr.message);
1243				ndmp_free_message((ndmp_connection_t *)
1244				    connection);
1245				continue;
1246			}
1247			reply_read = TRUE;
1248			reply_msginfo = connection->conn_msginfo;
1249			continue;
1250		}
1251		NDMP_LOG(LOG_DEBUG, "received request: 0x%x",
1252		    connection->conn_msginfo.mi_hdr.message);
1253
1254		/*
1255		 * The following is needed to catch an improperly constructed
1256		 * handler table or to deal with an NDMP client that is not
1257		 * conforming to the negotiated protocol version.
1258		 */
1259		if (connection->conn_msginfo.mi_handler->mh_func == NULL) {
1260			NDMP_LOG(LOG_DEBUG, "No handler for message 0x%x",
1261			    connection->conn_msginfo.mi_hdr.message);
1262
1263			(void) ndmp_send_response((ndmp_connection_t *)
1264			    connection, NDMP_NOT_SUPPORTED_ERR, NULL);
1265			ndmp_free_message((ndmp_connection_t *)connection);
1266			continue;
1267		}
1268		/*
1269		 * Call the handler function.
1270		 * The handler will send any necessary reply.
1271		 */
1272		(*connection->conn_msginfo.mi_handler->mh_func) (connection,
1273		    connection->conn_msginfo.mi_body);
1274
1275		ndmp_free_message((ndmp_connection_t *)connection);
1276
1277	} while (xdrrec_eof(&connection->conn_xdrs) == FALSE &&
1278	    connection->conn_eof == FALSE);
1279
1280	NDMP_LOG(LOG_DEBUG, "no more messages in stream buffer");
1281
1282	if (connection->conn_eof == TRUE) {
1283		if (reply_msginfo.mi_body)
1284			free(reply_msginfo.mi_body);
1285		return (NDMP_PROC_ERR);
1286	}
1287	if (reply_error) {
1288		if (reply_msginfo.mi_body)
1289			free(reply_msginfo.mi_body);
1290		return (NDMP_PROC_REP_ERR);
1291	}
1292	if (reply_read) {
1293		connection->conn_msginfo = reply_msginfo;
1294		return (NDMP_PROC_MSG);
1295	}
1296	return (NDMP_PROC_REP);
1297}
1298
1299
1300/*
1301 * ndmp_get_interface
1302 *
1303 * Return the NDMP interface (e.g. config, scsi, tape) for the
1304 * specific message.
1305 *
1306 * Parameters:
1307 *   message (input) - message number.
1308 *
1309 * Returns:
1310 *   NULL - message not found.
1311 *   pointer to handler info.
1312 */
1313static ndmp_handler_t *
1314ndmp_get_interface(ndmp_message message)
1315{
1316	ndmp_handler_t *ni = &ndmp_msghdl_tab[(message >> 8) % INT_MAXCMD];
1317
1318	if ((message & 0xff) >= ni->hd_cnt)
1319		return (NULL);
1320
1321	/* Sanity check */
1322	if (ni->hd_msgs[message & 0xff].hm_message != message)
1323		return (NULL);
1324
1325	return (ni);
1326}
1327
1328/*
1329 * ndmp_get_handler
1330 *
1331 * Return the handler info for the specified NDMP message.
1332 *
1333 * Parameters:
1334 *   connection (input) - connection pointer.
1335 *   message (input) - message number.
1336 *
1337 * Returns:
1338 *   NULL - message not found.
1339 *   pointer to handler info.
1340 */
1341static ndmp_msg_handler_t *
1342ndmp_get_handler(ndmp_connection_t *connection, ndmp_message message)
1343{
1344	ndmp_msg_handler_t *handler = NULL;
1345
1346	ndmp_handler_t *ni = ndmp_get_interface(message);
1347	int ver = connection->conn_version;
1348
1349	if (ni)
1350		handler = &ni->hd_msgs[message & 0xff].hm_msg_v[ver - 2];
1351
1352	return (handler);
1353}
1354
1355/*
1356 * ndmp_check_auth_required
1357 *
1358 * Check if the connection needs to be authenticated before
1359 * this message is being processed.
1360 *
1361 * Parameters:
1362 *   message (input) - message number.
1363 *
1364 * Returns:
1365 *   TRUE - required
1366 *   FALSE - not required
1367 */
1368static boolean_t
1369ndmp_check_auth_required(ndmp_message message)
1370{
1371	boolean_t auth_req = FALSE;
1372	ndmp_handler_t *ni = ndmp_get_interface(message);
1373
1374	if (ni)
1375		auth_req = ni->hd_msgs[message & 0xff].hm_auth_required;
1376
1377	return (auth_req);
1378}
1379
1380/*
1381 * tcp_accept
1382 *
1383 * A wrapper around accept for retrying and getting the IP address
1384 *
1385 * Parameters:
1386 *   listen_sock (input) - the socket for listening
1387 *   inaddr_p (output) - the IP address of peer connection
1388 *
1389 * Returns:
1390 *   socket for the accepted connection
1391 *   -1: error
1392 */
1393int
1394tcp_accept(int listen_sock, unsigned int *inaddr_p)
1395{
1396	struct sockaddr_in	sin;
1397	int			sock, i;
1398	int			try;
1399
1400	for (try = 0; try < 3; try++) {
1401		i = sizeof (sin);
1402		sock = accept(listen_sock, (struct sockaddr *)&sin, &i);
1403		if (sock < 0) {
1404			continue;
1405		}
1406		*inaddr_p = sin.sin_addr.s_addr;
1407		return (sock);
1408	}
1409	return (-1);
1410}
1411
1412
1413/*
1414 * tcp_get_peer
1415 *
1416 * Get the peer IP address for a connection
1417 *
1418 * Parameters:
1419 *   sock (input) - the active socket
1420 *   inaddr_p (output) - the IP address of peer connection
1421 *   port_p (output) - the port number of peer connection
1422 *
1423 * Returns:
1424 *   socket for the accepted connection
1425 *   -1: error
1426 */
1427int
1428tcp_get_peer(int sock, unsigned int *inaddr_p, int *port_p)
1429{
1430	struct sockaddr_in sin;
1431	int i, rc;
1432
1433	i = sizeof (sin);
1434	rc = getpeername(sock, (struct sockaddr *)&sin, &i);
1435	if (rc != 0)
1436		return (-1);
1437
1438	if (inaddr_p)
1439		*inaddr_p = sin.sin_addr.s_addr;
1440
1441	if (port_p)
1442		*port_p = ntohs(sin.sin_port);
1443
1444	return (sock);
1445
1446}
1447
1448/*
1449 * gethostaddr
1450 *
1451 * Get the IP address string of the current host
1452 *
1453 * Parameters:
1454 *   void
1455 *
1456 * Returns:
1457 *   IP address
1458 *   NULL: error
1459 */
1460char *
1461gethostaddr(void)
1462{
1463	static char s[MAXHOSTNAMELEN];
1464	struct hostent *h;
1465	struct in_addr in;
1466	char *p;
1467
1468	if (gethostname(s, sizeof (s)) == -1)
1469		return (NULL);
1470
1471	if ((h = gethostbyname(s)) == NULL)
1472		return (NULL);
1473
1474	p = h->h_addr_list[0];
1475	(void) memcpy(&in.s_addr, p, sizeof (in.s_addr));
1476	return (inet_ntoa(in));
1477}
1478
1479
1480/*
1481 * get_default_nic_addr
1482 *
1483 * Get the IP address of the default NIC
1484 */
1485char *
1486get_default_nic_addr(void)
1487{
1488	struct ifaddrlist *al = NULL;
1489	char errmsg[ERRBUFSIZE];
1490	struct in_addr addr;
1491	int nifs;
1492
1493	nifs = ifaddrlist(&al, AF_INET, LIFC_EXTERNAL_SOURCE, errmsg);
1494	if (nifs <= 0)
1495		return (NULL);
1496
1497	/* pick the first interface's address */
1498	addr = al[0].addr.addr;
1499	free(al);
1500
1501	return (inet_ntoa(IN_ADDR(addr.s_addr)));
1502}
1503
1504
1505/*
1506 * ndmpd_audit_backup
1507 *
1508 * Generate AUE_ndmp_backup audit record
1509 */
1510/*ARGSUSED*/
1511void
1512ndmpd_audit_backup(ndmp_connection_t *conn,
1513    char *path, int dest, char *local_path, int result)
1514{
1515	adt_event_data_t *event;
1516
1517	if ((event = adt_alloc_event(conn->conn_ah, ADT_ndmp_backup)) == NULL) {
1518		NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1519		return;
1520	}
1521	event->adt_ndmp_backup.source = path;
1522
1523	if (dest == NDMP_ADDR_LOCAL) {
1524		event->adt_ndmp_backup.local_dest = local_path;
1525	} else {
1526		event->adt_ndmp_backup.remote_dest = conn->conn_sock;
1527	}
1528
1529	if (result == 0) {
1530		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
1531			NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1532	} else {
1533		if (adt_put_event(event, ADT_FAILURE, result) != 0)
1534			NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1535	}
1536
1537	adt_free_event(event);
1538}
1539
1540
1541/*
1542 * ndmpd_audit_restore
1543 *
1544 * Generate AUE_ndmp_restore audit record
1545 */
1546/*ARGSUSED*/
1547void
1548ndmpd_audit_restore(ndmp_connection_t *conn,
1549    char *path, int dest, char *local_path, int result)
1550{
1551	adt_event_data_t *event;
1552
1553	if ((event = adt_alloc_event(conn->conn_ah,
1554	    ADT_ndmp_restore)) == NULL) {
1555		NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1556		return;
1557	}
1558	event->adt_ndmp_restore.destination = path;
1559
1560	if (dest == NDMP_ADDR_LOCAL) {
1561		event->adt_ndmp_restore.local_source = local_path;
1562	} else {
1563		event->adt_ndmp_restore.remote_source = conn->conn_sock;
1564	}
1565
1566	if (result == 0) {
1567		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
1568			NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1569	} else {
1570		if (adt_put_event(event, ADT_FAILURE, result) != 0)
1571			NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1572	}
1573
1574	adt_free_event(event);
1575}
1576
1577
1578/*
1579 * ndmpd_audit_connect
1580 *
1581 * Generate AUE_ndmp_connect audit record
1582 */
1583/*ARGSUSED*/
1584void
1585ndmpd_audit_connect(ndmp_connection_t *conn, int result)
1586{
1587	adt_event_data_t *event;
1588	adt_termid_t *termid;
1589
1590	if (adt_load_termid(conn->conn_sock, &termid) != 0) {
1591		NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1592		return;
1593	}
1594
1595	if (adt_set_user(conn->conn_ah, ADT_NO_ATTRIB, ADT_NO_ATTRIB,
1596	    ADT_NO_ATTRIB, ADT_NO_ATTRIB, termid, ADT_NEW) != 0) {
1597		NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1598		free(termid);
1599		return;
1600	}
1601	free(termid);
1602
1603	if ((event = adt_alloc_event(conn->conn_ah,
1604	    ADT_ndmp_connect)) == NULL) {
1605		NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1606		return;
1607	}
1608
1609	if (result == 0) {
1610		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
1611			NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1612	} else {
1613		if (adt_put_event(event, ADT_FAILURE, result) != 0)
1614			NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1615	}
1616
1617	adt_free_event(event);
1618}
1619
1620
1621/*
1622 * ndmpd_audit_disconnect
1623 *
1624 * Generate AUE_ndmp_disconnect audit record
1625 */
1626/*ARGSUSED*/
1627void
1628ndmpd_audit_disconnect(ndmp_connection_t *conn)
1629{
1630	adt_event_data_t *event;
1631
1632	if ((event = adt_alloc_event(conn->conn_ah,
1633	    ADT_ndmp_disconnect)) == NULL) {
1634		NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1635		return;
1636	}
1637	if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0)
1638		NDMP_LOG(LOG_ERR, "Audit failure: %m.");
1639
1640	adt_free_event(event);
1641}
1642
1643void *
1644ndmp_malloc(size_t size)
1645{
1646	void *data;
1647
1648	if ((data = calloc(1, size)) == NULL) {
1649		NDMP_LOG(LOG_ERR, "Out of memory.");
1650	}
1651
1652	return (data);
1653}
1654
1655/*
1656 * get_backup_path_v3
1657 *
1658 * Get the backup path from the NDMP environment variables.
1659 *
1660 * Parameters:
1661 *   params (input) - pointer to the parameters structure.
1662 *
1663 * Returns:
1664 *   The backup path: if anything is specified
1665 *   NULL: Otherwise
1666 */
1667char *
1668get_backup_path_v3(ndmpd_module_params_t *params)
1669{
1670	char *bkpath;
1671
1672	bkpath = MOD_GETENV(params, "PREFIX");
1673	if (!bkpath)
1674		bkpath = MOD_GETENV(params, "FILESYSTEM");
1675
1676
1677	if (!bkpath) {
1678		MOD_LOGV3(params, NDMP_LOG_ERROR,
1679		    "Backup path not defined.\n");
1680	} else {
1681		NDMP_LOG(LOG_DEBUG, "bkpath: \"%s\"", bkpath);
1682	}
1683
1684	return (bkpath);
1685}
1686
1687/*
1688 * get_backup_path
1689 *
1690 * Find the backup path from the environment variables (v2)
1691 */
1692char *
1693get_backup_path_v2(ndmpd_module_params_t *params)
1694{
1695	char *bkpath;
1696
1697	bkpath = MOD_GETENV(params, "PREFIX");
1698	if (bkpath == NULL)
1699		bkpath = MOD_GETENV(params, "FILESYSTEM");
1700
1701	if (bkpath == NULL) {
1702		MOD_LOG(params, "Error: restore path not specified.\n");
1703		return (NULL);
1704	}
1705
1706	if (*bkpath != '/') {
1707		MOD_LOG(params, "Error: relative backup path not allowed.\n");
1708		return (NULL);
1709	}
1710
1711	return (bkpath);
1712}
1713