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
61static int ndmpd_connect_auth_text(char *uname, char *auth_id,
62    char *auth_password);
63static int ndmpd_connect_auth_md5(char *uname, char *auth_id, char *auth_digest,
64    unsigned char *auth_challenge);
65static struct conn_list *ndmp_connect_list_find(ndmp_connection_t *connection);
66static void create_md5_digest(unsigned char *digest, char *passwd,
67    unsigned char *challenge);
68static struct conn_list *ndmp_connect_list_find_id(int id);
69
70/* routines for connection info */
71void ndmp_connect_list_get(ndmp_door_ctx_t *enc_ctx);
72static void connection_get(struct conn_list *clp, ndmp_door_ctx_t *enc_ctx);
73static void ndmp_connect_get_conn(struct conn_list *clp,
74    ndmp_door_ctx_t *enc_ctx);
75static void ndmp_connect_get_v2(ndmp_connection_t *connection,
76    ndmp_door_ctx_t *enc_ctx);
77static void ndmp_connect_get_scsi_v2(ndmpd_session_t *session,
78    ndmp_door_ctx_t *enc_ctx);
79static void ndmp_connect_get_tape_v2(ndmpd_session_t *session,
80    ndmp_door_ctx_t *enc_ctx);
81static void ndmp_connect_get_mover_v2(ndmpd_session_t *session,
82    ndmp_door_ctx_t *enc_ctx);
83static void ndmp_connect_get_data_v2(ndmpd_session_t *session,
84    ndmp_door_ctx_t *enc_ctx);
85static void ndmp_connect_get_v3(ndmp_connection_t *connection,
86    ndmp_door_ctx_t *enc_ctx);
87static void ndmp_connect_get_mover_v3(ndmpd_session_t *session,
88    ndmp_door_ctx_t *enc_ctx);
89static void ndmp_connect_get_data_v3(ndmpd_session_t *session,
90    ndmp_door_ctx_t *enc_ctx);
91void 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 */
101struct conn_list {
102	LIST_ENTRY(conn_list) cl_q;
103	int cl_id;
104	ndmp_connection_t *cl_conn;
105};
106LIST_HEAD(cl_head, conn_list);
107
108/*
109 * Head of the active connections.
110 */
111static struct cl_head cl_head;
112
113mutex_t cl_mutex = DEFAULTMUTEX;
114
115
116/*
117 * Set this variable to non-zero to print verbose information.
118 */
119int 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
141void
142ndmpd_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 */
189void
190ndmpd_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 */
352void
353ndmpd_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*/
404void
405ndmpd_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 */
433void
434ndmpd_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*/
542void
543ndmpd_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 */
607static void
608create_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 */
647static struct conn_list *
648ndmp_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 */
677int
678ndmp_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 */
713int
714ndmp_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 */
745static struct conn_list *
746ndmp_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 */
767static void
768ndmp_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 */
793static void
794ndmp_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 */
808static void
809ndmp_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 */
830static void
831ndmp_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 */
848static void
849ndmp_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 */
884static void
885ndmp_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 */
921static void
922ndmp_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 */
937static void
938ndmp_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 */
959static void
960ndmp_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 */
988static void
989ndmp_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 */
1005static void
1006connection_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 */
1046int
1047ndmpd_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 */
1074void
1075ndmp_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 */
1107int
1108ndmpd_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 */
1119void
1120ndmpd_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 */
1162int
1163ndmpd_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 */
1214int
1215ndmpd_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