xref: /illumos-gate/usr/src/cmd/ndmpd/ndmp/ndmpd_comm.c (revision faac71c0)
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
xdr_ndmp_header(XDR * xdrs,ndmp_header * objp)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 *
ndmp_create_connection(void)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
ndmp_destroy_connection(ndmp_connection_t * connection_handle)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
ndmp_close(ndmp_connection_t * connection_handle)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
ndmp_start_worker(ndmpd_worker_arg_t * argp)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
ndmp_run(ulong_t port,ndmp_con_handler_func_t con_handler_func)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 *
ndmpd_worker(void * ptarg)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
ndmp_process_requests(ndmp_connection_t * connection_handle)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
ndmp_send_request(ndmp_connection_t * connection_handle,ndmp_message message,ndmp_error err,void * request_data,void ** reply)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
ndmp_send_request_lock(ndmp_connection_t * connection_handle,ndmp_message message,ndmp_error err,void * request_data,void ** reply)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
ndmp_send_response(ndmp_connection_t * connection_handle,ndmp_error err,void * reply)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
ndmp_free_message(ndmp_connection_t * connection_handle)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
ndmp_get_fd(ndmp_connection_t * connection_handle)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
ndmp_set_client_data(ndmp_connection_t * connection_handle,void * client_data)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 *
ndmp_get_client_data(ndmp_connection_t * connection_handle)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
ndmp_set_version(ndmp_connection_t * connection_handle,ushort_t version)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
ndmp_get_version(ndmp_connection_t * connection_handle)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
ndmp_set_authorized(ndmp_connection_t * connection_handle,boolean_t authorized)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
ndmpd_main(void)765 ndmpd_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  */
802 void
connection_handler(ndmp_connection_t * connection)803 connection_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*/
936 static void
connection_file_handler(void * cookie,int fd,ulong_t mode)937 connection_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  */
962 static int
ndmp_readit(void * connection_handle,caddr_t buf,int len)963 ndmp_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  */
990 static int
ndmp_writeit(void * connection_handle,caddr_t buf,int len)991 ndmp_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  */
1022 static int
ndmp_recv_msg(ndmp_connection_t * connection)1023 ndmp_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  */
1163 static int
ndmp_process_messages(ndmp_connection_t * connection,boolean_t reply_expected)1164 ndmp_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  */
1313 static ndmp_handler_t *
ndmp_get_interface(ndmp_message message)1314 ndmp_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  */
1341 static ndmp_msg_handler_t *
ndmp_get_handler(ndmp_connection_t * connection,ndmp_message message)1342 ndmp_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  */
1368 static boolean_t
ndmp_check_auth_required(ndmp_message message)1369 ndmp_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  */
1393 int
tcp_accept(int listen_sock,unsigned int * inaddr_p)1394 tcp_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  */
1427 int
tcp_get_peer(int sock,unsigned int * inaddr_p,int * port_p)1428 tcp_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  */
1460 char *
gethostaddr(void)1461 gethostaddr(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  */
1485 char *
get_default_nic_addr(void)1486 get_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*/
1511 void
ndmpd_audit_backup(ndmp_connection_t * conn,char * path,int dest,char * local_path,int result)1512 ndmpd_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*/
1547 void
ndmpd_audit_restore(ndmp_connection_t * conn,char * path,int dest,char * local_path,int result)1548 ndmpd_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*/
1584 void
ndmpd_audit_connect(ndmp_connection_t * conn,int result)1585 ndmpd_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*/
1627 void
ndmpd_audit_disconnect(ndmp_connection_t * conn)1628 ndmpd_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 
1643 void *
ndmp_malloc(size_t size)1644 ndmp_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  */
1667 char *
get_backup_path_v3(ndmpd_module_params_t * params)1668 get_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  */
1692 char *
get_backup_path_v2(ndmpd_module_params_t * params)1693 get_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