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