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