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