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
60static int ndmpd_connect_auth_text(char *uname, char *auth_id,
61    char *auth_password);
62static int ndmpd_connect_auth_md5(char *uname, char *auth_id, char *auth_digest,
63    unsigned char *auth_challenge);
64static struct conn_list *ndmp_connect_list_find(ndmp_connection_t *connection);
65static void create_md5_digest(unsigned char *digest, char *passwd,
66    unsigned char *challenge);
67static struct conn_list *ndmp_connect_list_find_id(int id);
68
69/* routines for connection info */
70void ndmp_connect_list_get(ndmp_door_ctx_t *enc_ctx);
71static void connection_get(struct conn_list *clp, ndmp_door_ctx_t *enc_ctx);
72static void ndmp_connect_get_conn(struct conn_list *clp,
73    ndmp_door_ctx_t *enc_ctx);
74static void ndmp_connect_get_v2(ndmp_connection_t *connection,
75    ndmp_door_ctx_t *enc_ctx);
76static void ndmp_connect_get_scsi_v2(ndmpd_session_t *session,
77    ndmp_door_ctx_t *enc_ctx);
78static void ndmp_connect_get_tape_v2(ndmpd_session_t *session,
79    ndmp_door_ctx_t *enc_ctx);
80static void ndmp_connect_get_mover_v2(ndmpd_session_t *session,
81    ndmp_door_ctx_t *enc_ctx);
82static void ndmp_connect_get_data_v2(ndmpd_session_t *session,
83    ndmp_door_ctx_t *enc_ctx);
84static void ndmp_connect_get_v3(ndmp_connection_t *connection,
85    ndmp_door_ctx_t *enc_ctx);
86static void ndmp_connect_get_mover_v3(ndmpd_session_t *session,
87    ndmp_door_ctx_t *enc_ctx);
88static void ndmp_connect_get_data_v3(ndmpd_session_t *session,
89    ndmp_door_ctx_t *enc_ctx);
90void 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 */
100struct conn_list {
101	LIST_ENTRY(conn_list) cl_q;
102	int cl_id;
103	ndmp_connection_t *cl_conn;
104};
105LIST_HEAD(cl_head, conn_list);
106
107/*
108 * Head of the active connections.
109 */
110static struct cl_head cl_head;
111
112mutex_t cl_mutex = DEFAULTMUTEX;
113
114
115/*
116 * Set this variable to non-zero to print verbose information.
117 */
118int 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
140void
141ndmpd_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 */
188void
189ndmpd_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 */
351void
352ndmpd_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*/
403void
404ndmpd_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 */
432void
433ndmpd_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*/
541void
542ndmpd_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 */
600static void
601create_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 */
640static struct conn_list *
641ndmp_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 */
670int
671ndmp_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 */
706int
707ndmp_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 */
738static struct conn_list *
739ndmp_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 */
760static void
761ndmp_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 */
786static void
787ndmp_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 */
801static void
802ndmp_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 */
823static void
824ndmp_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 */
841static void
842ndmp_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 */
877static void
878ndmp_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 */
914static void
915ndmp_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 */
930static void
931ndmp_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 */
952static void
953ndmp_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 */
981static void
982ndmp_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 */
998static void
999connection_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 */
1039int
1040ndmpd_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 */
1071void
1072ndmp_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 */
1104int
1105ndmpd_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 */
1116void
1117ndmpd_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 */
1159int
1160ndmpd_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 */
1211int
1212ndmpd_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