dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / ndmpd / ndmp / ndmpd_connect.c
blob63370a2993859ef473ae55c9747ab1209affbbb1
1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /*
7 * BSD 3 Clause License
9 * Copyright (c) 2007, The Storage Networking Industry Association.
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.
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.
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.
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.
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. */
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>
61 static int ndmpd_connect_auth_text(char *uname, char *auth_id,
62 char *auth_password);
63 static int ndmpd_connect_auth_md5(char *uname, char *auth_id, char *auth_digest,
64 unsigned char *auth_challenge);
65 static struct conn_list *ndmp_connect_list_find(ndmp_connection_t *connection);
66 static void create_md5_digest(unsigned char *digest, char *passwd,
67 unsigned char *challenge);
68 static struct conn_list *ndmp_connect_list_find_id(int id);
70 /* routines for connection info */
71 void ndmp_connect_list_get(ndmp_door_ctx_t *enc_ctx);
72 static void connection_get(struct conn_list *clp, ndmp_door_ctx_t *enc_ctx);
73 static void ndmp_connect_get_conn(struct conn_list *clp,
74 ndmp_door_ctx_t *enc_ctx);
75 static void ndmp_connect_get_v2(ndmp_connection_t *connection,
76 ndmp_door_ctx_t *enc_ctx);
77 static void ndmp_connect_get_scsi_v2(ndmpd_session_t *session,
78 ndmp_door_ctx_t *enc_ctx);
79 static void ndmp_connect_get_tape_v2(ndmpd_session_t *session,
80 ndmp_door_ctx_t *enc_ctx);
81 static void ndmp_connect_get_mover_v2(ndmpd_session_t *session,
82 ndmp_door_ctx_t *enc_ctx);
83 static void ndmp_connect_get_data_v2(ndmpd_session_t *session,
84 ndmp_door_ctx_t *enc_ctx);
85 static void ndmp_connect_get_v3(ndmp_connection_t *connection,
86 ndmp_door_ctx_t *enc_ctx);
87 static void ndmp_connect_get_mover_v3(ndmpd_session_t *session,
88 ndmp_door_ctx_t *enc_ctx);
89 static void ndmp_connect_get_data_v3(ndmpd_session_t *session,
90 ndmp_door_ctx_t *enc_ctx);
91 void ndmpd_get_devs(ndmp_door_ctx_t *enc_ctx);
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 */
99 * List of active connections.
101 struct conn_list {
102 LIST_ENTRY(conn_list) cl_q;
103 int cl_id;
104 ndmp_connection_t *cl_conn;
106 LIST_HEAD(cl_head, conn_list);
109 * Head of the active connections.
111 static struct cl_head cl_head;
113 mutex_t cl_mutex = DEFAULTMUTEX;
117 * Set this variable to non-zero to print verbose information.
119 int ndmp_connect_print_verbose = 0;
123 * ************************************************************************
124 * NDMP V2 HANDLERS
125 * ************************************************************************
129 * ndmpd_connect_open_v2
131 * This handler sets the protocol version to be used on the connection.
133 * Parameters:
134 * connection (input) - connection handle.
135 * body (input) - request message body.
137 * Returns:
138 * void
141 void
142 ndmpd_connect_open_v2(ndmp_connection_t *connection, void *body)
144 ndmp_connect_open_request *request = (ndmp_connect_open_request *)body;
145 ndmp_connect_open_reply reply;
146 ndmpd_session_t *session;
148 reply.error = NDMP_NO_ERR;
150 if (!(session = (ndmpd_session_t *)ndmp_get_client_data(connection)))
151 return;
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;
159 ndmp_send_reply(connection, (void *) &reply,
160 "sending connect_open reply");
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.
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;
178 * ndmpd_connect_client_auth_v2
180 * This handler authorizes the NDMP connection.
182 * Parameters:
183 * connection (input) - connection handle.
184 * msginfo (input) - request message.
186 * Returns:
187 * void
189 void
190 ndmpd_connect_client_auth_v2(ndmp_connection_t *connection, void *body)
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;
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")));
208 reply.error = NDMP_NO_ERR;
210 switch (request->auth_data.auth_type) {
211 case NDMP_AUTH_NONE:
213 * Allow no authorization for development.
214 * Comment the following for a non-secure production server.
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;
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;
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;
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);
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.");
269 ndmpd_audit_connect(connection, reply.error ?
270 ADT_FAIL_PAM + PAM_AUTH_ERR : 0);
272 free(dec_passwd);
273 break;
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;
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);
304 session = ndmp_get_client_data(connection);
305 create_md5_digest(md5_digest, dec_passwd,
306 session->ns_challenge);
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");
320 ndmpd_audit_connect(connection, reply.error ?
321 ADT_FAIL_PAM + PAM_AUTH_ERR : 0);
323 free(dec_passwd);
324 break;
326 default:
327 reply.error = NDMP_ILLEGAL_ARGS_ERR;
330 if (reply.error == NDMP_NO_ERR)
331 ndmp_set_authorized(connection, TRUE);
332 else
333 ndmp_set_authorized(connection, FALSE);
335 ndmp_send_reply(connection, (void *) &reply,
336 "sending ndmp_connect_client_auth reply");
341 * ndmpd_connect_server_auth_v2
343 * This handler authenticates the server to the client.
345 * Parameters:
346 * connection (input) - connection handle.
347 * msginfo (input) - request message.
349 * Returns:
350 * void
352 void
353 ndmpd_connect_server_auth_v2(ndmp_connection_t *connection, void *body)
355 ndmp_connect_server_auth_request *request;
356 ndmp_connect_server_auth_reply reply;
358 request = (ndmp_connect_server_auth_request *)body;
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")));
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;
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;
378 case NDMP_AUTH_MD5:
379 reply.error = NDMP_ILLEGAL_ARGS_ERR;
380 break;
382 default:
383 reply.error = NDMP_ILLEGAL_ARGS_ERR;
386 ndmp_send_reply(connection, (void *) &reply,
387 "sending ndmp_connect_auth reply");
392 * ndmpd_connect_close_v2
394 * This handler closes the connection.
396 * Parameters:
397 * connection (input) - connection handle.
398 * msginfo (input) - request message.
400 * Returns:
401 * void
403 /*ARGSUSED*/
404 void
405 ndmpd_connect_close_v2(ndmp_connection_t *connection, void *body)
407 ndmpd_session_t *session;
409 if ((session = (ndmpd_session_t *)ndmp_get_client_data(connection))) {
410 (void) ndmp_close(connection);
411 session->ns_eof = TRUE;
416 * ************************************************************************
417 * NDMP V3 HANDLERS
418 * ************************************************************************
422 * ndmpd_connect_client_auth_v3
424 * This handler authorizes the NDMP connection.
426 * Parameters:
427 * connection (input) - connection handle.
428 * msginfo (input) - request message.
430 * Returns:
431 * void
433 void
434 ndmpd_connect_client_auth_v3(ndmp_connection_t *connection, void *body)
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;
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");
451 reply.error = NDMP_NO_ERR;
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;
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;
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;
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;
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;
505 default:
506 type = "unknown";
507 reply.error = NDMP_ILLEGAL_ARGS_ERR;
508 ndmpd_audit_connect(connection, EINVAL);
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)));
523 ndmp_send_reply(connection, (void *) &reply,
524 "sending ndmp_connect_auth reply");
529 * ndmpd_connect_close_v3
531 * Close the connection to the DMA.
532 * Send the SHUTDOWN message before closing the socket connection to the DMA.
534 * Parameters:
535 * connection (input) - connection handle.
536 * msginfo (input) - request message.
538 * Returns:
539 * void
541 /*ARGSUSED*/
542 void
543 ndmpd_connect_close_v3(ndmp_connection_t *connection, void *body)
545 ndmpd_session_t *session;
546 ndmp_lbr_params_t *nlp;
547 ndmp_notify_connected_request req;
549 if (!(session = (ndmpd_session_t *)ndmp_get_client_data(connection)))
550 return;
551 if ((nlp = ndmp_get_nlp(session)) == NULL)
552 return;
554 NDMP_LOG(LOG_DEBUG, "ver: %u",
555 session->ns_protocol_version);
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.";
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;
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);
576 * ************************************************************************
577 * NDMP V4 HANDLERS
578 * ************************************************************************
582 * ************************************************************************
583 * LOCALS
584 * ************************************************************************
588 * create_md5_digest
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.
599 * Parameters:
600 * digest (output) - 16 bytes MD5 digest
601 * passwd (input) - user password
602 * challenge (input) - 64 bytes server challenge
604 * Returns:
605 * void
607 static void
608 create_md5_digest(unsigned char *digest, char *passwd, unsigned char *challenge)
610 char buf[130];
611 char *p = &buf[0];
612 int len, i;
613 MD5_CTX md;
614 char *pwd;
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;
623 for (i = 0; i < MD5_CHALLENGE_SIZE - 2 * len; i++)
624 *p++ = 0;
626 (void) memcpy(p, challenge, MD5_CHALLENGE_SIZE);
627 p += MD5_CHALLENGE_SIZE;
628 (void) strlcpy(p, pwd, MD5_PASS_LIMIT);
630 MD5Init(&md);
631 MD5Update(&md, buf, 128);
632 MD5Final(digest, &md);
636 * ndmp_connect_list_find
638 * Find the element in the active connection list.
640 * Parameters:
641 * connection (input) - connection handler.
643 * Returns:
644 * NULL - error
645 * connection list element pointer
647 static struct conn_list *
648 ndmp_connect_list_find(ndmp_connection_t *connection)
650 struct conn_list *clp;
652 NDMP_LOG(LOG_DEBUG, "connection: 0x%p",
653 connection);
655 LIST_FOREACH(clp, &cl_head, cl_q) {
656 if (clp->cl_conn == connection) {
657 (void) mutex_unlock(&cl_mutex);
658 return (clp);
661 return (NULL);
665 * ndmpconnect_list_add
667 * Add the new connection to the list of the active connections.
669 * Parameters:
670 * connection (input) - connection handler.
671 * id (input/output) - pointer to connection id.
673 * Returns:
674 * 0 - success
675 * -1 - error
678 ndmp_connect_list_add(ndmp_connection_t *connection, int *id)
680 struct conn_list *clp;
682 if (connection == NULL) {
683 NDMP_LOG(LOG_DEBUG, "Invalid argument");
684 return (-1);
687 if ((clp = ndmp_malloc(sizeof (struct conn_list))) == NULL)
688 return (-1);
690 clp->cl_conn = connection;
691 clp->cl_id = *id;
693 (void) mutex_lock(&cl_mutex);
694 LIST_INSERT_HEAD(&cl_head, clp, cl_q);
695 (*id)++;
696 (void) mutex_unlock(&cl_mutex);
698 return (0);
702 * ndmp_connect_list_del
704 * Delete the specified connection from the list.
706 * Parameters:
707 * connection (input) - connection handler.
709 * Returns:
710 * 0 - success
711 * -1 - error
714 ndmp_connect_list_del(ndmp_connection_t *connection)
716 struct conn_list *clp;
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);
725 LIST_REMOVE(clp, cl_q);
726 (void) mutex_unlock(&cl_mutex);
727 free(clp);
729 return (0);
734 * ndmpconnect_list_find_id
736 * Find the element specified by its id in the list of active connections.
738 * Parameters:
739 * id (input) - connection id.
741 * Returns:
742 * NULL - error
743 * connection list element pointer
745 static struct conn_list *
746 ndmp_connect_list_find_id(int id)
748 struct conn_list *clp;
750 NDMP_LOG(LOG_DEBUG, "id: %d", id);
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);
760 (void) mutex_unlock(&cl_mutex);
761 return (NULL);
765 * Get common fields of the active connection.
767 static void
768 ndmp_connect_get_conn(struct conn_list *clp, ndmp_door_ctx_t *enc_ctx)
770 int port;
771 struct in_addr addr;
772 char cl_addr[NDMP_CL_ADDR_LEN];
773 ndmpd_session_t *session;
775 if (!(session = (ndmpd_session_t *)ndmp_get_client_data(clp->cl_conn)))
776 return;
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);
791 * Get the connection SCSI info.
793 static void
794 ndmp_connect_get_scsi_v2(ndmpd_session_t *session, ndmp_door_ctx_t *enc_ctx)
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);
806 * Get the connection tape info.
808 static void
809 ndmp_connect_get_tape_v2(ndmpd_session_t *session, ndmp_door_ctx_t *enc_ctx)
811 char dev_name[NDMP_TAPE_DEV_NAME];
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);
828 * Get the connection mover info.
830 static void
831 ndmp_connect_get_mover_v2(ndmpd_session_t *session, ndmp_door_ctx_t *enc_ctx)
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);
846 * Get the connection common data info.
848 static void
849 ndmp_connect_get_data_common(ndmpd_session_t *session, ndmp_door_ctx_t *enc_ctx)
851 int i;
852 ndmp_pval *ep;
853 int len;
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++;
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);
878 (void) mutex_unlock(&session->ns_lock);
882 * Get the connection data info.
884 static void
885 ndmp_connect_get_data_v2(ndmpd_session_t *session, ndmp_door_ctx_t *enc_ctx)
887 int i;
888 ndmp_name *np;
889 char tcp_addr[NDMP_TCP_ADDR_SIZE];
891 ndmp_connect_get_data_common(session, enc_ctx);
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);
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);
919 * Get V2 connection info.
921 static void
922 ndmp_connect_get_v2(ndmp_connection_t *connection, ndmp_door_ctx_t *enc_ctx)
924 ndmpd_session_t *session;
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);
935 * Get the V3 connection mover info.
937 static void
938 ndmp_connect_get_mover_v3(ndmpd_session_t *session, ndmp_door_ctx_t *enc_ctx)
940 char tcp_addr[NDMP_TCP_ADDR_SIZE];
942 /* get all the V2 mover data first */
943 ndmp_connect_get_mover_v2(session, enc_ctx);
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);
957 * Get the connection data info.
959 static void
960 ndmp_connect_get_data_v3(ndmpd_session_t *session, ndmp_door_ctx_t *enc_ctx)
962 ulong_t i;
963 mem_ndmp_name_v3_t *np;
964 char tcp_addr[NDMP_TCP_ADDR_SIZE];
966 ndmp_connect_get_data_common(session, enc_ctx);
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);
986 * Get V3 connection info.
988 static void
989 ndmp_connect_get_v3(ndmp_connection_t *connection, ndmp_door_ctx_t *enc_ctx)
991 ndmpd_session_t *session;
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);
1002 * Get the list of all active sessions to the clients. For each version,
1003 * call the appropriate get function.
1005 static void
1006 connection_get(struct conn_list *clp, ndmp_door_ctx_t *enc_ctx)
1008 ndmpd_session_t *session;
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;
1015 ndmp_door_put_int32(enc_ctx, NDMP_SESSION_DATA);
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);
1035 * ndmpd_connect_kill
1037 * Kill the connection based on its version.
1039 * Parameters:
1040 * connection (input) - connection handler.
1042 * Returns:
1043 * 0 - success
1044 * -1 - error
1047 ndmpd_connect_kill(ndmp_connection_t *connection)
1049 ndmpd_session_t *session;
1051 if (!(session = (ndmpd_session_t *)ndmp_get_client_data(connection)))
1052 return (-1);
1054 switch (session->ns_protocol_version) {
1055 case NDMPV2:
1056 ndmpd_connect_close_v2(connection, NULL);
1057 break;
1058 case NDMPV3:
1059 case NDMPV4:
1060 ndmpd_connect_close_v3(connection, NULL);
1061 break;
1062 default:
1063 NDMP_LOG(LOG_DEBUG,
1064 "Invalid session (0x%p) version 0x%x", session,
1065 session->ns_protocol_version);
1068 return (0);
1072 * Get the list of all active sessions to the clients.
1074 void
1075 ndmp_connect_list_get(ndmp_door_ctx_t *enc_ctx)
1077 int n;
1078 struct conn_list *clp;
1080 n = 0;
1081 (void) mutex_lock(&cl_mutex);
1082 LIST_FOREACH(clp, &cl_head, cl_q) {
1083 n++;
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++;
1092 (void) mutex_unlock(&cl_mutex);
1096 * ndmpd_connect_kill_id
1098 * Find a connection by its id and kill it.
1100 * Parameters:
1101 * id (input) - connection id.
1103 * Returns:
1104 * 0 - success
1105 * -1 - error
1108 ndmpd_connect_kill_id(int id)
1110 struct conn_list *clp;
1112 if (!(clp = ndmp_connect_list_find_id(id)))
1113 return (-1);
1115 return (ndmpd_connect_kill(clp->cl_conn));
1118 /* Get the devices info */
1119 void
1120 ndmpd_get_devs(ndmp_door_ctx_t *enc_ctx)
1122 int i, n;
1123 sasd_drive_t *sd;
1124 scsi_link_t *slink;
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;
1131 ndmp_door_put_int32(enc_ctx, n);
1133 for (i = 0; i < n; i++) {
1134 sd = sasd_drive(i);
1135 slink = sasd_dev_slink(i);
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);
1150 * ndmpd_connect_auth_text
1152 * Checks text authorization.
1154 * Parameters:
1155 * auth_id (input) - user name
1156 * auth_password(input) - password
1158 * Returns:
1159 * NDMP_NO_ERR: on success
1160 * Other NDMP_ error: invalid user name and password
1163 ndmpd_connect_auth_text(char *uname, char *auth_id, char *auth_password)
1165 char *passwd, *dec_passwd;
1166 int rv;
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;
1183 free(dec_passwd);
1187 if (rv == NDMP_NO_ERR) {
1188 NDMP_LOG(LOG_DEBUG, "Authorization granted.");
1189 } else {
1190 NDMP_LOG(LOG_ERR, "Authorization denied.");
1193 return (rv);
1198 * ndmpd_connect_auth_md5
1200 * Checks MD5 authorization.
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).
1210 * Returns:
1211 * NDMP_NO_ERR: on success
1212 * Other NDMP_ error: invalid user name and password
1215 ndmpd_connect_auth_md5(char *uname, char *auth_id, char *auth_digest,
1216 unsigned char *auth_challenge)
1218 char *passwd, *dec_passwd;
1219 unsigned char digest[16];
1220 int rv;
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);
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;
1243 free(dec_passwd);
1247 if (rv == NDMP_NO_ERR) {
1248 NDMP_LOG(LOG_DEBUG, "Authorization granted.");
1249 } else {
1250 NDMP_LOG(LOG_ERR, "Authorization denied.");
1253 return (rv);