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