1 /*
   2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
   3  * Use is subject to license terms.
   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 /* Copyright 2014 Nexenta Systems, Inc. All rights reserved. */
  42 
  43 #include <sys/types.h>
  44 #include <errno.h>
  45 #include <pwd.h>
  46 #include <sys/socket.h>
  47 #include <netinet/in.h>
  48 #include <sys/queue.h>
  49 #include <arpa/inet.h>
  50 #include <md5.h>
  51 #include <shadow.h>
  52 #include <crypt.h>
  53 #include <alloca.h>
  54 #include "ndmpd_common.h"
  55 #include "ndmpd.h"
  56 #include <libndmp.h>
  57 #include <ndmpd_door.h>
  58 #include <security/pam_appl.h>
  59 
  60 
  61 static int ndmpd_connect_auth_text(char *uname, char *auth_id,
  62     char *auth_password);
  63 static int ndmpd_connect_auth_md5(char *uname, char *auth_id, char *auth_digest,
  64     unsigned char *auth_challenge);
  65 static struct conn_list *ndmp_connect_list_find(ndmp_connection_t *connection);
  66 static void create_md5_digest(unsigned char *digest, char *passwd,
  67     unsigned char *challenge);
  68 static struct conn_list *ndmp_connect_list_find_id(int id);
  69 
  70 /* routines for connection info */
  71 void ndmp_connect_list_get(ndmp_door_ctx_t *enc_ctx);
  72 static void connection_get(struct conn_list *clp, ndmp_door_ctx_t *enc_ctx);
  73 static void ndmp_connect_get_conn(struct conn_list *clp,
  74     ndmp_door_ctx_t *enc_ctx);
  75 static void ndmp_connect_get_v2(ndmp_connection_t *connection,
  76     ndmp_door_ctx_t *enc_ctx);
  77 static void ndmp_connect_get_scsi_v2(ndmpd_session_t *session,
  78     ndmp_door_ctx_t *enc_ctx);
  79 static void ndmp_connect_get_tape_v2(ndmpd_session_t *session,
  80     ndmp_door_ctx_t *enc_ctx);
  81 static void ndmp_connect_get_mover_v2(ndmpd_session_t *session,
  82     ndmp_door_ctx_t *enc_ctx);
  83 static void ndmp_connect_get_data_v2(ndmpd_session_t *session,
  84     ndmp_door_ctx_t *enc_ctx);
  85 static void ndmp_connect_get_v3(ndmp_connection_t *connection,
  86     ndmp_door_ctx_t *enc_ctx);
  87 static void ndmp_connect_get_mover_v3(ndmpd_session_t *session,
  88     ndmp_door_ctx_t *enc_ctx);
  89 static void ndmp_connect_get_data_v3(ndmpd_session_t *session,
  90     ndmp_door_ctx_t *enc_ctx);
  91 void ndmpd_get_devs(ndmp_door_ctx_t *enc_ctx);
  92 
  93 #ifndef LIST_FOREACH
  94 #define LIST_FOREACH(var, head, field)                                  \
  95         for ((var) = (head)->lh_first; (var); (var) = (var)->field.le_next)
  96 #endif /* LIST_FOREACH */
  97 
  98 /*
  99  * List of active connections.
 100  */
 101 struct conn_list {
 102         LIST_ENTRY(conn_list) cl_q;
 103         int cl_id;
 104         ndmp_connection_t *cl_conn;
 105 };
 106 LIST_HEAD(cl_head, conn_list);
 107 
 108 /*
 109  * Head of the active connections.
 110  */
 111 static struct cl_head cl_head;
 112 
 113 mutex_t cl_mutex = DEFAULTMUTEX;
 114 
 115 
 116 /*
 117  * Set this variable to non-zero to print verbose information.
 118  */
 119 int ndmp_connect_print_verbose = 0;
 120 
 121 
 122 /*
 123  * ************************************************************************
 124  * NDMP V2 HANDLERS
 125  * ************************************************************************
 126  */
 127 
 128 /*
 129  * ndmpd_connect_open_v2
 130  *
 131  * This handler sets the protocol version to be used on the connection.
 132  *
 133  * Parameters:
 134  *   connection (input) - connection handle.
 135  *   body       (input) - request message body.
 136  *
 137  * Returns:
 138  *   void
 139  */
 140 
 141 void
 142 ndmpd_connect_open_v2(ndmp_connection_t *connection, void *body)
 143 {
 144         ndmp_connect_open_request *request = (ndmp_connect_open_request *)body;
 145         ndmp_connect_open_reply reply;
 146         ndmpd_session_t *session;
 147 
 148         reply.error = NDMP_NO_ERR;
 149 
 150         if (!(session = (ndmpd_session_t *)ndmp_get_client_data(connection)))
 151                 return;
 152 
 153         if (session->ns_mover.md_state != NDMP_MOVER_STATE_IDLE ||
 154             session->ns_data.dd_state != NDMP_DATA_STATE_IDLE)
 155                 reply.error = NDMP_ILLEGAL_STATE_ERR;
 156         else if (request->protocol_version > ndmp_ver)
 157                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 158 
 159         ndmp_send_reply(connection, (void *) &reply,
 160             "sending connect_open reply");
 161 
 162         /*
 163          * Set the protocol version.
 164          * Must wait until after sending the reply since the reply
 165          * must be sent using the same protocol version that was used
 166          * to process the request.
 167          */
 168         if (reply.error == NDMP_NO_ERR) {
 169                 NDMP_LOG(LOG_DEBUG, "set ver to: %d",
 170                     request->protocol_version);
 171                 ndmp_set_version(connection, request->protocol_version);
 172                 session->ns_protocol_version = request->protocol_version;
 173         }
 174 }
 175 
 176 
 177 /*
 178  * ndmpd_connect_client_auth_v2
 179  *
 180  * This handler authorizes the NDMP connection.
 181  *
 182  * Parameters:
 183  *   connection (input) - connection handle.
 184  *   msginfo    (input) - request message.
 185  *
 186  * Returns:
 187  *   void
 188  */
 189 void
 190 ndmpd_connect_client_auth_v2(ndmp_connection_t *connection, void *body)
 191 {
 192         ndmp_connect_client_auth_request *request;
 193         ndmp_connect_client_auth_reply reply;
 194         ndmp_auth_text *auth;
 195         ndmpd_session_t *session;
 196         ndmp_auth_md5 *md5;
 197         unsigned char md5_digest[16];
 198         char *passwd, *dec_passwd;
 199         char *uname;
 200 
 201         request = (ndmp_connect_client_auth_request *)body;
 202         NDMP_LOG(LOG_DEBUG, "auth_type:%s",
 203             request->auth_data.auth_type == NDMP_AUTH_NONE ? "None" :
 204             (request->auth_data.auth_type == NDMP_AUTH_TEXT ? "Text" :
 205             (request->auth_data.auth_type == NDMP_AUTH_MD5 ? "MD5" :
 206             "Invalid")));
 207 
 208         reply.error = NDMP_NO_ERR;
 209 
 210         switch (request->auth_data.auth_type) {
 211         case NDMP_AUTH_NONE:
 212                 /*
 213                  * Allow no authorization for development.
 214                  * Comment the following for a non-secure production server.
 215                  */
 216                 NDMP_LOG(LOG_ERR, "Authorization denied.");
 217                 NDMP_LOG(LOG_ERR,
 218                     "Authorization type should be md5 or cleartext.");
 219                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 220                 ndmpd_audit_connect(connection, EINVAL);
 221                 break;
 222 
 223         case NDMP_AUTH_TEXT:
 224                 /* Check authorization.  */
 225                 if ((uname = ndmpd_get_prop(NDMP_CLEARTEXT_USERNAME)) == NULL ||
 226                     *uname == 0) {
 227                         NDMP_LOG(LOG_ERR, "Authorization denied.");
 228                         NDMP_LOG(LOG_ERR, "User name is not set at server.");
 229                         reply.error = NDMP_NOT_AUTHORIZED_ERR;
 230                         ndmp_set_authorized(connection, FALSE);
 231                         ndmp_send_reply(connection, (void *) &reply,
 232                             "sending ndmp_connect_client_auth reply");
 233                         ndmpd_audit_connect(connection,
 234                             ADT_FAIL_PAM + PAM_AUTH_ERR);
 235                         return;
 236                 }
 237                 auth = &request->auth_data.ndmp_auth_data_u.auth_text;
 238                 if (strcmp(uname, auth->user) != 0) {
 239                         NDMP_LOG(LOG_ERR,
 240                             "Authorization denied. Not a valid user.");
 241                         reply.error = NDMP_NOT_AUTHORIZED_ERR;
 242                         ndmpd_audit_connect(connection,
 243                             ADT_FAIL_PAM + PAM_AUTH_ERR);
 244                         break;
 245                 }
 246                 passwd = ndmpd_get_prop(NDMP_CLEARTEXT_PASSWORD);
 247                 if (!passwd || !*passwd) {
 248                         NDMP_LOG(LOG_ERR, "Authorization denied.");
 249                         NDMP_LOG(LOG_ERR,
 250                             "Cleartext password is not set at server.");
 251                         reply.error = NDMP_NOT_AUTHORIZED_ERR;
 252                         ndmp_set_authorized(connection, FALSE);
 253                         ndmp_send_reply(connection, (void *) &reply,
 254                             "sending ndmp_connect_client_auth reply");
 255                         ndmpd_audit_connect(connection,
 256                             ADT_FAIL_PAM + PAM_AUTH_ERR);
 257                         return;
 258                 } else {
 259                         dec_passwd = ndmp_base64_decode(passwd);
 260                 }
 261                 if (!dec_passwd || !*dec_passwd ||
 262                     strcmp(auth->password, dec_passwd) != 0) {
 263                         NDMP_LOG(LOG_ERR,
 264                             "Authorization denied. Invalid password.");
 265                         reply.error = NDMP_NOT_AUTHORIZED_ERR;
 266                 } else {
 267                         NDMP_LOG(LOG_DEBUG, "Authorization granted.");
 268                 }
 269                 ndmpd_audit_connect(connection, reply.error ?
 270                     ADT_FAIL_PAM + PAM_AUTH_ERR : 0);
 271 
 272                 free(dec_passwd);
 273                 break;
 274 
 275         case NDMP_AUTH_MD5:
 276                 /* Check authorization.  */
 277                 if ((uname = ndmpd_get_prop(NDMP_CRAM_MD5_USERNAME)) == NULL ||
 278                     *uname == 0) {
 279                         NDMP_LOG(LOG_ERR, "Authorization denied.");
 280                         NDMP_LOG(LOG_ERR,  "User name is not set at server.");
 281                         reply.error = NDMP_NOT_AUTHORIZED_ERR;
 282                         ndmp_set_authorized(connection, FALSE);
 283                         ndmp_send_reply(connection, (void *) &reply,
 284                             "sending ndmp_connect_client_auth reply");
 285                         ndmpd_audit_connect(connection,
 286                             ADT_FAIL_PAM + PAM_AUTH_ERR);
 287                         return;
 288                 }
 289                 md5 = &request->auth_data.ndmp_auth_data_u.auth_md5;
 290                 passwd = ndmpd_get_prop(NDMP_CRAM_MD5_PASSWORD);
 291                 if (!passwd || !*passwd) {
 292                         NDMP_LOG(LOG_ERR, "Authorization denied.");
 293                         NDMP_LOG(LOG_ERR, "MD5 password is not set at server.");
 294                         reply.error = NDMP_NOT_AUTHORIZED_ERR;
 295                         ndmp_set_authorized(connection, FALSE);
 296                         ndmp_send_reply(connection, (void *) &reply,
 297                             "sending ndmp_connect_client_auth reply");
 298                         ndmpd_audit_connect(connection,
 299                             ADT_FAIL_PAM + PAM_AUTH_ERR);
 300                         return;
 301                 } else {
 302                         dec_passwd = ndmp_base64_decode(passwd);
 303                 }
 304                 session = ndmp_get_client_data(connection);
 305                 create_md5_digest(md5_digest, dec_passwd,
 306                     session->ns_challenge);
 307 
 308                 if (strcmp(uname, md5->user) != 0) {
 309                         NDMP_LOG(LOG_ERR,
 310                             "Authorization denied. Not a valid user.");
 311                         reply.error = NDMP_NOT_AUTHORIZED_ERR;
 312                 } else if (memcmp(md5_digest, md5->auth_digest,
 313                     sizeof (md5_digest)) != 0) {
 314                         NDMP_LOG(LOG_ERR,
 315                             "Authorization denied. Invalid password.");
 316                         reply.error = NDMP_NOT_AUTHORIZED_ERR;
 317                 } else {
 318                         NDMP_LOG(LOG_DEBUG, "Authorization granted");
 319                 }
 320                 ndmpd_audit_connect(connection, reply.error ?
 321                     ADT_FAIL_PAM + PAM_AUTH_ERR : 0);
 322 
 323                 free(dec_passwd);
 324                 break;
 325 
 326         default:
 327                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 328         }
 329 
 330         if (reply.error == NDMP_NO_ERR)
 331                 ndmp_set_authorized(connection, TRUE);
 332         else
 333                 ndmp_set_authorized(connection, FALSE);
 334 
 335         ndmp_send_reply(connection, (void *) &reply,
 336             "sending ndmp_connect_client_auth reply");
 337 }
 338 
 339 
 340 /*
 341  * ndmpd_connect_server_auth_v2
 342  *
 343  * This handler authenticates the server to the client.
 344  *
 345  * Parameters:
 346  *   connection (input) - connection handle.
 347  *   msginfo    (input) - request message.
 348  *
 349  * Returns:
 350  *   void
 351  */
 352 void
 353 ndmpd_connect_server_auth_v2(ndmp_connection_t *connection, void *body)
 354 {
 355         ndmp_connect_server_auth_request *request;
 356         ndmp_connect_server_auth_reply reply;
 357 
 358         request = (ndmp_connect_server_auth_request *)body;
 359 
 360         NDMP_LOG(LOG_DEBUG, "auth_type:%s",
 361             request->client_attr.auth_type == NDMP_AUTH_NONE ? "None" :
 362             (request->client_attr.auth_type == NDMP_AUTH_TEXT ? "Text" :
 363             (request->client_attr.auth_type == NDMP_AUTH_MD5 ? "MD5" :
 364             "Invalid")));
 365 
 366         reply.error = NDMP_NO_ERR;
 367         reply.auth_result.auth_type = request->client_attr.auth_type;
 368         switch (request->client_attr.auth_type) {
 369         case NDMP_AUTH_NONE:
 370                 break;
 371 
 372         case NDMP_AUTH_TEXT:
 373                 reply.auth_result.ndmp_auth_data_u.auth_text.user = "ndmpd";
 374                 reply.auth_result.ndmp_auth_data_u.auth_text.password =
 375                     "ndmpsdk";
 376                 break;
 377 
 378         case NDMP_AUTH_MD5:
 379                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 380                 break;
 381 
 382         default:
 383                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 384         }
 385 
 386         ndmp_send_reply(connection, (void *) &reply,
 387             "sending ndmp_connect_auth reply");
 388 }
 389 
 390 
 391 /*
 392  * ndmpd_connect_close_v2
 393  *
 394  * This handler closes the connection.
 395  *
 396  * Parameters:
 397  *   connection (input) - connection handle.
 398  *   msginfo    (input) - request message.
 399  *
 400  * Returns:
 401  *   void
 402  */
 403 /*ARGSUSED*/
 404 void
 405 ndmpd_connect_close_v2(ndmp_connection_t *connection, void *body)
 406 {
 407         ndmpd_session_t *session;
 408 
 409         if ((session = (ndmpd_session_t *)ndmp_get_client_data(connection))) {
 410                 (void) ndmp_close(connection);
 411                 session->ns_eof = TRUE;
 412         }
 413 }
 414 
 415 /*
 416  * ************************************************************************
 417  * NDMP V3 HANDLERS
 418  * ************************************************************************
 419  */
 420 
 421 /*
 422  * ndmpd_connect_client_auth_v3
 423  *
 424  * This handler authorizes the NDMP connection.
 425  *
 426  * Parameters:
 427  *   connection (input) - connection handle.
 428  *   msginfo    (input) - request message.
 429  *
 430  * Returns:
 431  *   void
 432  */
 433 void
 434 ndmpd_connect_client_auth_v3(ndmp_connection_t *connection, void *body)
 435 {
 436         ndmp_connect_client_auth_request_v3 *request;
 437         ndmp_connect_client_auth_reply_v3 reply;
 438         ndmp_auth_text_v3 *auth;
 439         ndmpd_session_t *session;
 440         ndmp_auth_md5_v3 *md5;
 441         struct in_addr addr;
 442         char *uname;
 443         char *type;
 444 
 445         request = (ndmp_connect_client_auth_request_v3 *)body;
 446         NDMP_LOG(LOG_DEBUG, "auth_type %s",
 447             request->auth_data.auth_type == NDMP_AUTH_NONE ? "None" :
 448             request->auth_data.auth_type == NDMP_AUTH_TEXT ? "Text" :
 449             request->auth_data.auth_type == NDMP_AUTH_MD5 ? "MD5" : "Invalid");
 450 
 451         reply.error = NDMP_NO_ERR;
 452 
 453         switch (request->auth_data.auth_type) {
 454         case NDMP_AUTH_NONE:
 455                 type = "none";
 456                 reply.error = NDMP_NOT_SUPPORTED_ERR;
 457                 ndmpd_audit_connect(connection, ENOTSUP);
 458                 break;
 459 
 460         case NDMP_AUTH_TEXT:
 461                 /* Check authorization.  */
 462                 if ((uname = ndmpd_get_prop(NDMP_CLEARTEXT_USERNAME)) == NULL ||
 463                     *uname == 0) {
 464                         NDMP_LOG(LOG_ERR, "Authorization denied.");
 465                         NDMP_LOG(LOG_ERR, "User name is not set at server.");
 466                         reply.error = NDMP_NOT_AUTHORIZED_ERR;
 467                         ndmp_set_authorized(connection, FALSE);
 468                         ndmp_send_reply(connection, (void *) &reply,
 469                             "sending ndmp_connect_client_auth reply");
 470                         ndmpd_audit_connect(connection,
 471                             ADT_FAIL_PAM + PAM_AUTH_ERR);
 472                         return;
 473                 }
 474                 type = "text";
 475                 auth = &request->auth_data.ndmp_auth_data_v3_u.auth_text;
 476                 reply.error = ndmpd_connect_auth_text(uname, auth->auth_id,
 477                     auth->auth_password);
 478                 ndmpd_audit_connect(connection, reply.error ?
 479                     ADT_FAIL_PAM + PAM_AUTH_ERR : 0);
 480                 break;
 481 
 482         case NDMP_AUTH_MD5:
 483                 /* Check authorization.  */
 484                 if ((uname = ndmpd_get_prop(NDMP_CRAM_MD5_USERNAME)) == NULL ||
 485                     *uname == 0) {
 486                         NDMP_LOG(LOG_ERR, "Authorization denied.");
 487                         NDMP_LOG(LOG_ERR, "User name is not set at server.");
 488                         reply.error = NDMP_NOT_AUTHORIZED_ERR;
 489                         ndmp_set_authorized(connection, FALSE);
 490                         ndmp_send_reply(connection, (void *) &reply,
 491                             "sending ndmp_connect_client_auth reply");
 492                         ndmpd_audit_connect(connection,
 493                             ADT_FAIL_PAM + PAM_AUTH_ERR);
 494                         return;
 495                 }
 496                 type = "md5";
 497                 session = ndmp_get_client_data(connection);
 498                 md5 = &request->auth_data.ndmp_auth_data_v3_u.auth_md5;
 499                 reply.error = ndmpd_connect_auth_md5(uname, md5->auth_id,
 500                     md5->auth_digest, session->ns_challenge);
 501                 ndmpd_audit_connect(connection, reply.error ?
 502                     ADT_FAIL_PAM + PAM_AUTH_ERR : 0);
 503                 break;
 504 
 505         default:
 506                 type = "unknown";
 507                 reply.error = NDMP_ILLEGAL_ARGS_ERR;
 508                 ndmpd_audit_connect(connection, EINVAL);
 509         }
 510 
 511         if (reply.error == NDMP_NO_ERR) {
 512                 ndmp_set_authorized(connection, TRUE);
 513         } else {
 514                 ndmp_set_authorized(connection, FALSE);
 515                 if (tcp_get_peer(connection->conn_sock, &addr.s_addr,
 516                     NULL) != -1) {
 517                         NDMP_LOG(LOG_ERR,
 518                             "Authorization(%s) denied for %s.", type,
 519                             inet_ntoa(IN_ADDR(addr)));
 520                 }
 521         }
 522 
 523         ndmp_send_reply(connection, (void *) &reply,
 524             "sending ndmp_connect_auth reply");
 525 }
 526 
 527 
 528 /*
 529  * ndmpd_connect_close_v3
 530  *
 531  * Close the connection to the DMA.
 532  * Send the SHUTDOWN message before closing the socket connection to the DMA.
 533  *
 534  * Parameters:
 535  *   connection (input) - connection handle.
 536  *   msginfo    (input) - request message.
 537  *
 538  * Returns:
 539  *   void
 540  */
 541 /*ARGSUSED*/
 542 void
 543 ndmpd_connect_close_v3(ndmp_connection_t *connection, void *body)
 544 {
 545         ndmpd_session_t *session;
 546         ndmp_lbr_params_t *nlp;
 547         ndmp_notify_connected_request req;
 548 
 549         if (!(session = (ndmpd_session_t *)ndmp_get_client_data(connection)))
 550                 return;
 551         if ((nlp = ndmp_get_nlp(session)) == NULL)
 552                 return;
 553 
 554         NDMP_LOG(LOG_DEBUG, "ver: %u",
 555             session->ns_protocol_version);
 556 
 557         /* Send the SHUTDOWN message before closing the connection. */
 558         req.reason = NDMP_SHUTDOWN;
 559         req.protocol_version = session->ns_protocol_version;
 560         req.text_reason = "Connection closed by server.";
 561 
 562         if (ndmp_send_request(connection, NDMP_NOTIFY_CONNECTION_STATUS,
 563             NDMP_NO_ERR, (void *) &req, 0) < 0) {
 564                 NDMP_LOG(LOG_NOTICE, "Sending connection shutdown notify");
 565                 return;
 566         }
 567 
 568         (void) mutex_lock(&nlp->nlp_mtx);
 569         ndmp_close(connection);
 570         session->ns_eof = TRUE;
 571         (void) cond_broadcast(&nlp->nlp_cv);
 572         (void) mutex_unlock(&nlp->nlp_mtx);
 573 }
 574 
 575 /*
 576  * ************************************************************************
 577  * NDMP V4 HANDLERS
 578  * ************************************************************************
 579  */
 580 
 581 /*
 582  * ************************************************************************
 583  * LOCALS
 584  * ************************************************************************
 585  */
 586 
 587 /*
 588  * create_md5_digest
 589  *
 590  * This function uses the MD5 message-digest algorithm described
 591  * in RFC1321 to authenticate the client using a shared secret (password).
 592  * The message used to compute the MD5 digest is a concatenation of password,
 593  * null padding, the 64 byte fixed length challenge and a repeat of the
 594  * password. The length of the null padding is chosen to result in a 128 byte
 595  * fixed length message. The lengh of the padding can be computed as
 596  * 64 - 2*(length of the password). The client digest is computed using the
 597  * server challenge from the NDMP_CONFIG_GET_AUTH_ATTR reply.
 598  *
 599  * Parameters:
 600  *   digest (output) - 16 bytes MD5 digest
 601  *   passwd (input) - user password
 602  *   challenge (input) - 64 bytes server challenge
 603  *
 604  * Returns:
 605  *   void
 606  */
 607 static void
 608 create_md5_digest(unsigned char *digest, char *passwd, unsigned char *challenge)
 609 {
 610         char buf[130];
 611         char *p = &buf[0];
 612         int len, i;
 613         MD5_CTX md;
 614         char *pwd;
 615 
 616         *p = 0;
 617         pwd = passwd;
 618         if ((len = strlen(pwd)) > MD5_PASS_LIMIT)
 619                 len = MD5_PASS_LIMIT;
 620         (void) memcpy(p, pwd, len);
 621         p += len;
 622 
 623         for (i = 0; i < MD5_CHALLENGE_SIZE - 2 * len; i++)
 624                 *p++ = 0;
 625 
 626         (void) memcpy(p, challenge, MD5_CHALLENGE_SIZE);
 627         p += MD5_CHALLENGE_SIZE;
 628         (void) strlcpy(p, pwd, MD5_PASS_LIMIT);
 629 
 630         MD5Init(&md);
 631         MD5Update(&md, buf, 128);
 632         MD5Final(digest, &md);
 633 }
 634 
 635 /*
 636  * ndmp_connect_list_find
 637  *
 638  * Find the element in the active connection list.
 639  *
 640  * Parameters:
 641  *   connection (input) - connection handler.
 642  *
 643  * Returns:
 644  *   NULL - error
 645  *   connection list element pointer
 646  */
 647 static struct conn_list *
 648 ndmp_connect_list_find(ndmp_connection_t *connection)
 649 {
 650         struct conn_list *clp;
 651 
 652         NDMP_LOG(LOG_DEBUG, "connection: 0x%p",
 653             connection);
 654 
 655         LIST_FOREACH(clp, &cl_head, cl_q) {
 656                 if (clp->cl_conn == connection) {
 657                         (void) mutex_unlock(&cl_mutex);
 658                         return (clp);
 659                 }
 660         }
 661         return (NULL);
 662 }
 663 
 664 /*
 665  * ndmpconnect_list_add
 666  *
 667  * Add the new connection to the list of the active connections.
 668  *
 669  * Parameters:
 670  *   connection (input) - connection handler.
 671  *   id (input/output) - pointer to connection id.
 672  *
 673  * Returns:
 674  *   0 - success
 675  *  -1 - error
 676  */
 677 int
 678 ndmp_connect_list_add(ndmp_connection_t *connection, int *id)
 679 {
 680         struct conn_list *clp;
 681 
 682         if (connection == NULL) {
 683                 NDMP_LOG(LOG_DEBUG, "Invalid argument");
 684                 return (-1);
 685         }
 686 
 687         if ((clp = ndmp_malloc(sizeof (struct conn_list))) == NULL)
 688                 return (-1);
 689 
 690         clp->cl_conn = connection;
 691         clp->cl_id = *id;
 692 
 693         (void) mutex_lock(&cl_mutex);
 694         LIST_INSERT_HEAD(&cl_head, clp, cl_q);
 695         (*id)++;
 696         (void) mutex_unlock(&cl_mutex);
 697 
 698         return (0);
 699 }
 700 
 701 /*
 702  * ndmp_connect_list_del
 703  *
 704  * Delete the specified connection from the list.
 705  *
 706  * Parameters:
 707  *   connection (input) - connection handler.
 708  *
 709  * Returns:
 710  *   0 - success
 711  *  -1 - error
 712  */
 713 int
 714 ndmp_connect_list_del(ndmp_connection_t *connection)
 715 {
 716         struct conn_list *clp;
 717 
 718         (void) mutex_lock(&cl_mutex);
 719         if (!(clp = ndmp_connect_list_find(connection))) {
 720                 (void) mutex_unlock(&cl_mutex);
 721                 NDMP_LOG(LOG_DEBUG, "connection not found");
 722                 return (-1);
 723         }
 724 
 725         LIST_REMOVE(clp, cl_q);
 726         (void) mutex_unlock(&cl_mutex);
 727         free(clp);
 728 
 729         return (0);
 730 }
 731 
 732 
 733 /*
 734  * ndmpconnect_list_find_id
 735  *
 736  * Find the element specified by its id in the list of active connections.
 737  *
 738  * Parameters:
 739  *   id (input) - connection id.
 740  *
 741  * Returns:
 742  *   NULL - error
 743  *   connection list element pointer
 744  */
 745 static struct conn_list *
 746 ndmp_connect_list_find_id(int id)
 747 {
 748         struct conn_list *clp;
 749 
 750         NDMP_LOG(LOG_DEBUG, "id: %d", id);
 751 
 752         (void) mutex_lock(&cl_mutex);
 753         LIST_FOREACH(clp, &cl_head, cl_q) {
 754                 if (clp->cl_id == id) {
 755                         (void) mutex_unlock(&cl_mutex);
 756                         return (clp);
 757                 }
 758         }
 759 
 760         (void) mutex_unlock(&cl_mutex);
 761         return (NULL);
 762 }
 763 
 764 /*
 765  * Get common fields of the active connection.
 766  */
 767 static void
 768 ndmp_connect_get_conn(struct conn_list *clp, ndmp_door_ctx_t *enc_ctx)
 769 {
 770         int port;
 771         struct in_addr addr;
 772         char cl_addr[NDMP_CL_ADDR_LEN];
 773         ndmpd_session_t *session;
 774 
 775         if (!(session = (ndmpd_session_t *)ndmp_get_client_data(clp->cl_conn)))
 776                 return;
 777 
 778         ndmp_door_put_int32(enc_ctx, clp->cl_id);
 779         ndmp_door_put_int32(enc_ctx, session->ns_protocol_version);
 780         ndmp_door_put_int32(enc_ctx, clp->cl_conn->conn_authorized);
 781         ndmp_door_put_int32(enc_ctx, session->ns_eof);
 782         if (tcp_get_peer(clp->cl_conn->conn_sock, &(addr.s_addr), &port) != -1)
 783                 (void) snprintf(cl_addr, NDMP_CL_ADDR_LEN, "%s:%d",
 784                     (char *)inet_ntoa(addr), port);
 785         else
 786                 cl_addr[0] = '\0';
 787         ndmp_door_put_string(enc_ctx, cl_addr);
 788 }
 789 
 790 /*
 791  * Get the connection SCSI info.
 792  */
 793 static void
 794 ndmp_connect_get_scsi_v2(ndmpd_session_t *session, ndmp_door_ctx_t *enc_ctx)
 795 {
 796         ndmp_door_put_int32(enc_ctx, session->ns_scsi.sd_is_open);
 797         ndmp_door_put_string(enc_ctx, session->ns_scsi.sd_adapter_name);
 798         ndmp_door_put_int32(enc_ctx, session->ns_scsi.sd_valid_target_set);
 799         if (session->ns_scsi.sd_valid_target_set) {
 800                 ndmp_door_put_int32(enc_ctx, session->ns_scsi.sd_sid);
 801                 ndmp_door_put_int32(enc_ctx, session->ns_scsi.sd_lun);
 802         }
 803 }
 804 
 805 /*
 806  * Get the connection tape info.
 807  */
 808 static void
 809 ndmp_connect_get_tape_v2(ndmpd_session_t *session, ndmp_door_ctx_t *enc_ctx)
 810 {
 811         char dev_name[NDMP_TAPE_DEV_NAME];
 812 
 813         ndmp_door_put_int32(enc_ctx, session->ns_tape.td_fd);
 814         if (session->ns_tape.td_fd != -1) {
 815                 ndmp_door_put_uint64(enc_ctx, session->ns_tape.td_record_count);
 816                 ndmp_door_put_int32(enc_ctx, session->ns_tape.td_mode);
 817                 (void) snprintf(dev_name, NDMP_TAPE_DEV_NAME, "%st%02x%x",
 818                     session->ns_tape.td_adapter_name, session->ns_tape.td_sid,
 819                     session->ns_tape.td_lun);
 820                 ndmp_door_put_string(enc_ctx, dev_name);
 821                 ndmp_door_put_string(enc_ctx, session->ns_tape.td_adapter_name);
 822                 ndmp_door_put_int32(enc_ctx, session->ns_tape.td_sid);
 823                 ndmp_door_put_int32(enc_ctx, session->ns_tape.td_lun);
 824         }
 825 }
 826 
 827 /*
 828  * Get the connection mover info.
 829  */
 830 static void
 831 ndmp_connect_get_mover_v2(ndmpd_session_t *session, ndmp_door_ctx_t *enc_ctx)
 832 {
 833         ndmp_door_put_int32(enc_ctx, session->ns_mover.md_state);
 834         ndmp_door_put_int32(enc_ctx, session->ns_mover.md_mode);
 835         ndmp_door_put_int32(enc_ctx, session->ns_mover.md_pause_reason);
 836         ndmp_door_put_int32(enc_ctx, session->ns_mover.md_halt_reason);
 837         ndmp_door_put_uint64(enc_ctx, session->ns_mover.md_record_size);
 838         ndmp_door_put_uint64(enc_ctx, session->ns_mover.md_record_num);
 839         ndmp_door_put_uint64(enc_ctx, session->ns_mover.md_position);
 840         ndmp_door_put_uint64(enc_ctx, session->ns_mover.md_window_offset);
 841         ndmp_door_put_uint64(enc_ctx, session->ns_mover.md_window_length);
 842         ndmp_door_put_int32(enc_ctx, session->ns_mover.md_sock);
 843 }
 844 
 845 /*
 846  * Get the connection common data info.
 847  */
 848 static void
 849 ndmp_connect_get_data_common(ndmpd_session_t *session, ndmp_door_ctx_t *enc_ctx)
 850 {
 851         int i;
 852         ndmp_pval *ep;
 853         int len;
 854 
 855         ndmp_door_put_int32(enc_ctx, session->ns_data.dd_operation);
 856         ndmp_door_put_int32(enc_ctx, session->ns_data.dd_state);
 857         ndmp_door_put_int32(enc_ctx, session->ns_data.dd_halt_reason);
 858         ndmp_door_put_int32(enc_ctx, session->ns_data.dd_sock);
 859         ndmp_door_put_int32(enc_ctx, session->ns_data.dd_mover.addr_type);
 860         ndmp_door_put_int32(enc_ctx, session->ns_data.dd_abort);
 861         ndmp_door_put_uint64(enc_ctx, session->ns_data.dd_read_offset);
 862         ndmp_door_put_uint64(enc_ctx, session->ns_data.dd_read_length);
 863         ndmp_door_put_uint64(enc_ctx, session->ns_data.dd_data_size);
 864         /* verify data.env has as much data as in session->ns_data.dd_env_len */
 865         len = 0;
 866         ep = session->ns_data.dd_env;
 867         for (i = 0; ep && i < session->ns_data.dd_env_len; i++, ep++)
 868                 len++;
 869 
 870         /* put the len */
 871         (void) mutex_lock(&session->ns_lock);
 872         ndmp_door_put_uint64(enc_ctx, len);
 873         ep = session->ns_data.dd_env;
 874         for (i = 0; i < len; i++, ep++) {
 875                 ndmp_door_put_string(enc_ctx, ep->name);
 876                 ndmp_door_put_string(enc_ctx, ep->value);
 877         }
 878         (void) mutex_unlock(&session->ns_lock);
 879 }
 880 
 881 /*
 882  * Get the connection data info.
 883  */
 884 static void
 885 ndmp_connect_get_data_v2(ndmpd_session_t *session, ndmp_door_ctx_t *enc_ctx)
 886 {
 887         int i;
 888         ndmp_name *np;
 889         char tcp_addr[NDMP_TCP_ADDR_SIZE];
 890 
 891         ndmp_connect_get_data_common(session, enc_ctx);
 892 
 893         switch (session->ns_data.dd_mover.addr_type) {
 894         case NDMP_ADDR_LOCAL:
 895                 (void) snprintf(tcp_addr, NDMP_TCP_ADDR_SIZE, "%s", "Local");
 896                 ndmp_door_put_string(enc_ctx, tcp_addr);
 897                 break;
 898         case NDMP_ADDR_TCP:
 899                 (void) snprintf(tcp_addr, NDMP_TCP_ADDR_SIZE, "%s:%d",
 900                     (char *)inet_ntoa(IN_ADDR(
 901                     session->ns_data.dd_mover.ndmp_mover_addr_u.addr.ip_addr)),
 902                     session->ns_data.dd_mover.ndmp_mover_addr_u.addr.port);
 903                 ndmp_door_put_string(enc_ctx, tcp_addr);
 904                 break;
 905         default:
 906                 (void) snprintf(tcp_addr, NDMP_TCP_ADDR_SIZE, "%s", "Unknown");
 907                 ndmp_door_put_string(enc_ctx, tcp_addr);
 908         }
 909 
 910         ndmp_door_put_uint64(enc_ctx, session->ns_data.dd_nlist_len);
 911         np = session->ns_data.dd_nlist;
 912         for (i = 0; np && i < (int)session->ns_data.dd_nlist_len; i++, np++) {
 913                 ndmp_door_put_string(enc_ctx, np->name);
 914                 ndmp_door_put_string(enc_ctx, np->dest);
 915         }
 916 }
 917 
 918 /*
 919  * Get V2 connection info.
 920  */
 921 static void
 922 ndmp_connect_get_v2(ndmp_connection_t *connection, ndmp_door_ctx_t *enc_ctx)
 923 {
 924         ndmpd_session_t *session;
 925 
 926         if ((session = (ndmpd_session_t *)ndmp_get_client_data(connection))) {
 927                 ndmp_connect_get_scsi_v2(session, enc_ctx);
 928                 ndmp_connect_get_tape_v2(session, enc_ctx);
 929                 ndmp_connect_get_mover_v2(session, enc_ctx);
 930                 ndmp_connect_get_data_v2(session, enc_ctx);
 931         }
 932 }
 933 
 934 /*
 935  * Get the V3 connection mover info.
 936  */
 937 static void
 938 ndmp_connect_get_mover_v3(ndmpd_session_t *session, ndmp_door_ctx_t *enc_ctx)
 939 {
 940         char tcp_addr[NDMP_TCP_ADDR_SIZE];
 941 
 942         /* get all the V2 mover data first */
 943         ndmp_connect_get_mover_v2(session, enc_ctx);
 944 
 945         /* get the V3 mover data now */
 946         ndmp_door_put_int32(enc_ctx, session->ns_mover.md_listen_sock);
 947         ndmp_door_put_int32(enc_ctx, session->ns_mover.md_data_addr.addr_type);
 948         tcp_addr[0] = '\0';
 949         (void) snprintf(tcp_addr, NDMP_TCP_ADDR_SIZE, "%s:%d",
 950             (char *)
 951             inet_ntoa(IN_ADDR(session->ns_mover.md_data_addr.tcp_ip_v3)),
 952             (int)session->ns_mover.md_data_addr.tcp_port_v3);
 953         ndmp_door_put_string(enc_ctx, tcp_addr);
 954 }
 955 
 956 /*
 957  * Get the connection data info.
 958  */
 959 static void
 960 ndmp_connect_get_data_v3(ndmpd_session_t *session, ndmp_door_ctx_t *enc_ctx)
 961 {
 962         ulong_t i;
 963         mem_ndmp_name_v3_t *np;
 964         char tcp_addr[NDMP_TCP_ADDR_SIZE];
 965 
 966         ndmp_connect_get_data_common(session, enc_ctx);
 967 
 968         (void) snprintf(tcp_addr, NDMP_TCP_ADDR_SIZE, "%s:%d",
 969             (char *)inet_ntoa(IN_ADDR(session->ns_data.dd_data_addr.tcp_ip_v3)),
 970             (int)session->ns_data.dd_data_addr.tcp_port_v3);
 971         ndmp_door_put_string(enc_ctx, tcp_addr);
 972         ndmp_door_put_int32(enc_ctx, session->ns_data.dd_listen_sock);
 973         ndmp_door_put_uint64(enc_ctx,
 974             session->ns_data.dd_module.dm_stats.ms_bytes_processed);
 975         ndmp_door_put_uint64(enc_ctx, session->ns_data.dd_nlist_len);
 976         np = session->ns_data.dd_nlist_v3;
 977         for (i = 0; np && i < (int)session->ns_data.dd_nlist_len; i++, np++) {
 978                 ndmp_door_put_string(enc_ctx, np->nm3_opath);
 979                 ndmp_door_put_string(enc_ctx, np->nm3_dpath);
 980                 ndmp_door_put_uint64(enc_ctx, np->nm3_node);
 981                 ndmp_door_put_uint64(enc_ctx, np->nm3_fh_info);
 982         }
 983 }
 984 
 985 /*
 986  * Get V3 connection info.
 987  */
 988 static void
 989 ndmp_connect_get_v3(ndmp_connection_t *connection, ndmp_door_ctx_t *enc_ctx)
 990 {
 991         ndmpd_session_t *session;
 992 
 993         if ((session = (ndmpd_session_t *)ndmp_get_client_data(connection))) {
 994                 ndmp_connect_get_scsi_v2(session, enc_ctx);
 995                 ndmp_connect_get_tape_v2(session, enc_ctx);
 996                 ndmp_connect_get_mover_v3(session, enc_ctx);
 997                 ndmp_connect_get_data_v3(session, enc_ctx);
 998         }
 999 }
1000 
1001 /*
1002  * Get the list of all active sessions to the clients.  For each version,
1003  * call the appropriate get function.
1004  */
1005 static void
1006 connection_get(struct conn_list *clp, ndmp_door_ctx_t *enc_ctx)
1007 {
1008         ndmpd_session_t *session;
1009 
1010         session = (ndmpd_session_t *)ndmp_get_client_data(clp->cl_conn);
1011         if (!session) {
1012                 ndmp_door_put_int32(enc_ctx, NDMP_SESSION_NODATA);
1013                 return;
1014         }
1015         ndmp_door_put_int32(enc_ctx, NDMP_SESSION_DATA);
1016 
1017         switch (session->ns_protocol_version) {
1018         case NDMPV2:
1019                 ndmp_connect_get_conn(clp, enc_ctx);
1020                 ndmp_connect_get_v2(clp->cl_conn, enc_ctx);
1021                 break;
1022         case NDMPV3:
1023         case NDMPV4:
1024                 ndmp_connect_get_conn(clp, enc_ctx);
1025                 ndmp_connect_get_v3(clp->cl_conn, enc_ctx);
1026                 break;
1027         default:
1028                 NDMP_LOG(LOG_DEBUG,
1029                     "Invalid session (0x%p) version 0x%x", session,
1030                     session->ns_protocol_version);
1031         }
1032 }
1033 
1034 /*
1035  * ndmpd_connect_kill
1036  *
1037  * Kill the connection based on its version.
1038  *
1039  * Parameters:
1040  *   connection (input) - connection handler.
1041  *
1042  * Returns:
1043  *   0 - success
1044  *  -1 - error
1045  */
1046 int
1047 ndmpd_connect_kill(ndmp_connection_t *connection)
1048 {
1049         ndmpd_session_t *session;
1050 
1051         if (!(session = (ndmpd_session_t *)ndmp_get_client_data(connection)))
1052                 return (-1);
1053 
1054         switch (session->ns_protocol_version) {
1055         case NDMPV2:
1056                 ndmpd_connect_close_v2(connection, (void *)NULL);
1057                 break;
1058         case NDMPV3:
1059         case NDMPV4:
1060                 ndmpd_connect_close_v3(connection, (void *)NULL);
1061                 break;
1062         default:
1063                 NDMP_LOG(LOG_DEBUG,
1064                     "Invalid session (0x%p) version 0x%x", session,
1065                     session->ns_protocol_version);
1066         }
1067 
1068         return (0);
1069 }
1070 
1071 /*
1072  * Get the list of all active sessions to the clients.
1073  */
1074 void
1075 ndmp_connect_list_get(ndmp_door_ctx_t *enc_ctx)
1076 {
1077         int n;
1078         struct conn_list *clp;
1079 
1080         n = 0;
1081         (void) mutex_lock(&cl_mutex);
1082         LIST_FOREACH(clp, &cl_head, cl_q) {
1083                 n++;
1084         }
1085         /* write number of connections */
1086         ndmp_door_put_int32(enc_ctx, n);
1087         n = 0;
1088         LIST_FOREACH(clp, &cl_head, cl_q) {
1089                 connection_get(clp, enc_ctx);
1090                 n++;
1091         }
1092         (void) mutex_unlock(&cl_mutex);
1093 }
1094 
1095 /*
1096  * ndmpd_connect_kill_id
1097  *
1098  * Find a connection by its id and kill it.
1099  *
1100  * Parameters:
1101  *   id (input) - connection id.
1102  *
1103  * Returns:
1104  *   0 - success
1105  *  -1 - error
1106  */
1107 int
1108 ndmpd_connect_kill_id(int id)
1109 {
1110         struct conn_list *clp;
1111 
1112         if (!(clp = ndmp_connect_list_find_id(id)))
1113                 return (-1);
1114 
1115         return (ndmpd_connect_kill(clp->cl_conn));
1116 }
1117 
1118 /* Get the devices info */
1119 void
1120 ndmpd_get_devs(ndmp_door_ctx_t *enc_ctx)
1121 {
1122         int i, n;
1123         sasd_drive_t *sd;
1124         scsi_link_t *slink;
1125 
1126         if ((n = sasd_dev_count()) == 0) {
1127                 ndmp_door_put_int32(enc_ctx, n);
1128                 NDMP_LOG(LOG_DEBUG, "No device attached.");
1129                 return;
1130         }
1131         ndmp_door_put_int32(enc_ctx, n);
1132 
1133         for (i = 0; i < n; i++) {
1134                 sd = sasd_drive(i);
1135                 slink = sasd_dev_slink(i);
1136 
1137                 ndmp_door_put_int32(enc_ctx, slink->sl_type);
1138                 ndmp_door_put_string(enc_ctx, sd->sd_name);
1139                 ndmp_door_put_int32(enc_ctx, slink->sl_lun);
1140                 ndmp_door_put_int32(enc_ctx, slink->sl_sid);
1141                 ndmp_door_put_string(enc_ctx, sd->sd_vendor);
1142                 ndmp_door_put_string(enc_ctx, sd->sd_id);
1143                 ndmp_door_put_string(enc_ctx, sd->sd_rev);
1144                 ndmp_door_put_string(enc_ctx, sd->sd_serial);
1145                 ndmp_door_put_string(enc_ctx, sd->sd_wwn);
1146         }
1147 }
1148 
1149 /*
1150  * ndmpd_connect_auth_text
1151  *
1152  * Checks text authorization.
1153  *
1154  * Parameters:
1155  *   auth_id (input) - user name
1156  *   auth_password(input) - password
1157  *
1158  * Returns:
1159  *   NDMP_NO_ERR: on success
1160  *   Other NDMP_ error: invalid user name and password
1161  */
1162 int
1163 ndmpd_connect_auth_text(char *uname, char *auth_id, char *auth_password)
1164 {
1165         char *passwd, *dec_passwd;
1166         int rv;
1167 
1168         if (strcmp(uname, auth_id) != 0) {
1169                 rv = NDMP_NOT_AUTHORIZED_ERR;
1170         } else {
1171                 passwd = ndmpd_get_prop(NDMP_CLEARTEXT_PASSWORD);
1172                 if (!passwd || !*passwd) {
1173                         rv = NDMP_NOT_AUTHORIZED_ERR;
1174                 } else {
1175                         dec_passwd = ndmp_base64_decode(passwd);
1176                         if (dec_passwd == NULL || *dec_passwd == 0)
1177                                 rv = NDMP_NOT_AUTHORIZED_ERR;
1178                         else if (strcmp(auth_password, dec_passwd) != 0)
1179                                 rv = NDMP_NOT_AUTHORIZED_ERR;
1180                         else
1181                                 rv = NDMP_NO_ERR;
1182 
1183                         free(dec_passwd);
1184                 }
1185         }
1186 
1187         if (rv == NDMP_NO_ERR) {
1188                 NDMP_LOG(LOG_DEBUG, "Authorization granted.");
1189         } else {
1190                 NDMP_LOG(LOG_ERR, "Authorization denied.");
1191         }
1192 
1193         return (rv);
1194 }
1195 
1196 
1197 /*
1198  * ndmpd_connect_auth_md5
1199  *
1200  * Checks MD5 authorization.
1201  *
1202  * Parameters:
1203  *   auth_id (input) - user name
1204  *   auth_digest(input) - MD5 digest
1205  *      This is a 16 bytes digest info which is a MD5 transform of 128 bytes
1206  *      message (password + padding + server challenge + password). Server
1207  *      challenge is a 64 bytes random string per NDMP session sent out to the
1208  *      client on demand (See NDMP_CONFIG_GET_AUTH_ATTR command).
1209  *
1210  * Returns:
1211  *   NDMP_NO_ERR: on success
1212  *   Other NDMP_ error: invalid user name and password
1213  */
1214 int
1215 ndmpd_connect_auth_md5(char *uname, char *auth_id, char *auth_digest,
1216     unsigned char *auth_challenge)
1217 {
1218         char *passwd, *dec_passwd;
1219         unsigned char digest[16];
1220         int rv;
1221 
1222         if (strcmp(uname, auth_id) != 0) {
1223                 rv = NDMP_NOT_AUTHORIZED_ERR;
1224         } else {
1225                 passwd = ndmpd_get_prop(NDMP_CRAM_MD5_PASSWORD);
1226                 if (passwd == NULL || *passwd == 0) {
1227                         rv = NDMP_NOT_AUTHORIZED_ERR;
1228                 } else {
1229                         dec_passwd = ndmp_base64_decode(passwd);
1230 
1231                         if (dec_passwd == NULL || *dec_passwd == 0) {
1232                                 rv = NDMP_NOT_AUTHORIZED_ERR;
1233                         } else {
1234                                 create_md5_digest(digest, dec_passwd,
1235                                     auth_challenge);
1236                                 if (memcmp(digest, auth_digest,
1237                                     sizeof (digest)) != 0) {
1238                                         rv = NDMP_NOT_AUTHORIZED_ERR;
1239                                 } else {
1240                                         rv = NDMP_NO_ERR;
1241                                 }
1242                         }
1243                         free(dec_passwd);
1244                 }
1245         }
1246 
1247         if (rv == NDMP_NO_ERR) {
1248                 NDMP_LOG(LOG_DEBUG, "Authorization granted.");
1249         } else {
1250                 NDMP_LOG(LOG_ERR, "Authorization denied.");
1251         }
1252 
1253         return (rv);
1254 }