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
ndmpd_connect_open_v2(ndmp_connection_t * connection,void * body)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
ndmpd_connect_client_auth_v2(ndmp_connection_t * connection,void * body)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
ndmpd_connect_server_auth_v2(ndmp_connection_t * connection,void * body)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
ndmpd_connect_close_v2(ndmp_connection_t * connection,void * body)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
ndmpd_connect_client_auth_v3(ndmp_connection_t * connection,void * body)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
ndmpd_connect_close_v3(ndmp_connection_t * connection,void * body)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
create_md5_digest(unsigned char * digest,char * passwd,unsigned char * challenge)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 *
ndmp_connect_list_find(ndmp_connection_t * connection)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
ndmp_connect_list_add(ndmp_connection_t * connection,int * id)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
ndmp_connect_list_del(ndmp_connection_t * connection)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 *
ndmp_connect_list_find_id(int id)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
ndmp_connect_get_conn(struct conn_list * clp,ndmp_door_ctx_t * enc_ctx)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
ndmp_connect_get_scsi_v2(ndmpd_session_t * session,ndmp_door_ctx_t * enc_ctx)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
ndmp_connect_get_tape_v2(ndmpd_session_t * session,ndmp_door_ctx_t * enc_ctx)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
ndmp_connect_get_mover_v2(ndmpd_session_t * session,ndmp_door_ctx_t * enc_ctx)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
ndmp_connect_get_data_common(ndmpd_session_t * session,ndmp_door_ctx_t * enc_ctx)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
ndmp_connect_get_data_v2(ndmpd_session_t * session,ndmp_door_ctx_t * enc_ctx)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
ndmp_connect_get_v2(ndmp_connection_t * connection,ndmp_door_ctx_t * enc_ctx)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
ndmp_connect_get_mover_v3(ndmpd_session_t * session,ndmp_door_ctx_t * enc_ctx)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
ndmp_connect_get_data_v3(ndmpd_session_t * session,ndmp_door_ctx_t * enc_ctx)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
ndmp_connect_get_v3(ndmp_connection_t * connection,ndmp_door_ctx_t * enc_ctx)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
connection_get(struct conn_list * clp,ndmp_door_ctx_t * enc_ctx)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
ndmpd_connect_kill(ndmp_connection_t * connection)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
ndmp_connect_list_get(ndmp_door_ctx_t * enc_ctx)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
ndmpd_connect_kill_id(int id)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
ndmpd_get_devs(ndmp_door_ctx_t * enc_ctx)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
ndmpd_connect_auth_text(char * uname,char * auth_id,char * auth_password)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
ndmpd_connect_auth_md5(char * uname,char * auth_id,char * auth_digest,unsigned char * auth_challenge)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 }
1255