Home | History | Annotate | Download | only in iscsitgtd
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include <stdio.h>
     30 #include <strings.h>
     31 #include <sys/types.h>
     32 #include <stdlib.h>
     33 #include <unistd.h>
     34 #include <syslog.h>
     35 #include <sys/iscsi_protocol.h>
     36 #include <arpa/inet.h>
     37 #include <iscsitgt_impl.h>
     38 #include "queue.h"
     39 #include "iscsi_conn.h"
     40 #include "iscsi_sess.h"
     41 #include "iscsi_login.h"
     42 #include "iscsi_provider_impl.h"
     43 #include "utility.h"
     44 #include "target.h"
     45 #include "isns_client.h"
     46 
     47 typedef enum auth_action {
     48 	LOGIN_NO_AUTH,
     49 	LOGIN_AUTH,
     50 	LOGIN_DROP
     51 } auth_action_t;
     52 
     53 /*
     54  * Forward declarations
     55  */
     56 static iscsi_login_rsp_hdr_t *make_login_response(iscsi_conn_t *c,
     57     iscsi_login_hdr_t *lhp);
     58 static void send_login_reject(iscsi_conn_t *c, iscsi_login_hdr_t *lhp,
     59     int err_code);
     60 static Boolean_t check_for_valid_I_T(iscsi_conn_t *c);
     61 static auth_action_t login_set_auth(iscsi_sess_t *s);
     62 
     63 /*
     64  * iscsi_null_callback - This callback may be used under certain
     65  * conditions when authenticating a target, but I'm not sure what
     66  * we need to do here.
     67  */
     68 /* ARGSUSED */
     69 static void
     70 iscsi_null_callback(void *user_handle, void *message_handle, int auth_status)
     71 {
     72 }
     73 
     74 /*
     75  * iscsi_find_key_value -
     76  */
     77 static int
     78 iscsi_find_key_value(char *param, char *ihp, char *pdu_end,
     79     char **value_start, char **value_end)
     80 {
     81 	char *str = param;
     82 	char *text = ihp;
     83 	char *value = NULL;
     84 
     85 	if (value_start)
     86 		*value_start = NULL;
     87 	if (value_end)
     88 		*value_end = NULL;
     89 
     90 	/*
     91 	 * make sure they contain the same bytes
     92 	 */
     93 	while (*str) {
     94 		if (text >= pdu_end) {
     95 			return (0);
     96 		}
     97 		if (*text == '\0') {
     98 			return (0);
     99 		}
    100 		if (*str != *text) {
    101 			return (0);
    102 		}
    103 		str++;
    104 		text++;
    105 	}
    106 
    107 	if ((text >= pdu_end) ||
    108 	    (*text == '\0') ||
    109 	    (*text != ISCSI_TEXT_SEPARATOR)) {
    110 		return (0);
    111 	}
    112 
    113 	/*
    114 	 * find the value
    115 	 */
    116 	value = text + 1;
    117 
    118 	/*
    119 	 * find the end of the value
    120 	 */
    121 	while ((text < pdu_end) && (*text))
    122 		text++;
    123 
    124 	if (value_start)
    125 		*value_start = value;
    126 	if (value_end)
    127 		*value_end = text;
    128 
    129 	return (1);
    130 }
    131 
    132 Boolean_t
    133 iscsi_handle_login_pkt(iscsi_conn_t *c)
    134 {
    135 	iscsi_login_hdr_t	lh;
    136 	iscsi_login_rsp_hdr_t	*rsp		= NULL;
    137 	Boolean_t		rval		= False;
    138 	IscsiAuthClient		*auth_client	= NULL;
    139 	char			*text		= NULL;
    140 	char			*end		= NULL;
    141 	char			*text_rsp	= NULL;
    142 	char			debug[128];
    143 	int			debug_status	= 0;
    144 	int			errcode		= 0;
    145 	int			text_length	= 0;
    146 	int			keytype		= 0;
    147 	int			transit		= 0;
    148 	int			rc		= 0;
    149 	auth_action_t		auth_action	= LOGIN_DROP;
    150 	tgt_node_t		*tnode		= NULL;
    151 
    152 	if (read(c->c_fd, &lh, sizeof (lh)) != sizeof (lh)) {
    153 		queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log,
    154 		    "Header to small");
    155 		return (False);
    156 	}
    157 
    158 	if ((lh.opcode & ISCSI_OPCODE_MASK) != ISCSI_OP_LOGIN_CMD) {
    159 		(void) snprintf(debug, sizeof (debug),
    160 		    "CON%x  Wrong OP code for state (Got 0x%x, Expected 0x%x)",
    161 		    c->c_num, lh.opcode, ISCSI_OP_LOGIN_CMD);
    162 		queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug);
    163 		send_login_reject(c, &lh,
    164 		    (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) |
    165 		    ISCSI_LOGIN_STATUS_INVALID_REQUEST);
    166 		conn_state(c, T7);
    167 		return (True);
    168 	}
    169 
    170 	if (ISCSI_LOGIN_COMMAND_ENABLED()) {
    171 		uiscsiproto_t info;
    172 		char nil = '\0';
    173 
    174 		info.uip_target_addr = &c->c_target_sockaddr;
    175 		info.uip_initiator_addr = &c->c_initiator_sockaddr;
    176 
    177 		info.uip_target = &nil;
    178 		info.uip_initiator = &nil;
    179 		info.uip_lun = 0;
    180 
    181 		info.uip_itt = lh.itt;
    182 		info.uip_ttt = ISCSI_RSVD_TASK_TAG;
    183 
    184 		info.uip_cmdsn = ntohl(lh.cmdsn);
    185 		info.uip_statsn = ntohl(lh.expstatsn);
    186 		info.uip_datasn = 0;
    187 
    188 		info.uip_datalen = ntoh24(lh.dlength);
    189 		info.uip_flags = lh.flags;
    190 
    191 		ISCSI_LOGIN_COMMAND(&info);
    192 	}
    193 
    194 	if ((rval = session_alloc(c, lh.isid)) == False) {
    195 		conn_state(c, T7);
    196 		return (True);
    197 	}
    198 
    199 	connection_parameters_default(c);
    200 
    201 	c->c_cid	= ntohl(lh.cid);
    202 	c->c_statsn	= ntohl(lh.expstatsn);
    203 
    204 	(void) pthread_mutex_lock(&c->c_sess->s_mutex);
    205 	c->c_sess->s_cmdsn	= ntohl(lh.cmdsn);
    206 	c->c_sess->s_seencmdsn	= ntohl(lh.cmdsn);
    207 	(void) pthread_mutex_unlock(&c->c_sess->s_mutex);
    208 
    209 	/*
    210 	 * Is this a new session or an attempt to add a connection to
    211 	 * an existing session.
    212 	 */
    213 	if (ntohs(lh.tsid) != 0) {
    214 
    215 		/* Multiple connections per session not handled right now */
    216 		conn_state(c, T7);
    217 		return (True);
    218 	}
    219 
    220 	if ((rsp = make_login_response(c, &lh)) == NULL) {
    221 		(void) snprintf(debug, sizeof (debug),
    222 		    "CON%x  Failed make_login_response", c->c_num);
    223 		queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug);
    224 		return (False);
    225 	}
    226 	/* default is ISCSI_FLAG_LOGIN_TRANSIT, not good for login */
    227 	rsp->flags = 0;
    228 
    229 	if ((rsp->active_version < lh.min_version) ||
    230 	    (rsp->active_version > lh.max_version)) {
    231 		(void) snprintf(debug, sizeof (debug),
    232 		    "CON%x  Version: Active %d, min %d, max %d", c->c_num,
    233 		    rsp->active_version, lh.min_version, lh.max_version);
    234 		send_login_reject(c, &lh,
    235 		    (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) |
    236 		    ISCSI_LOGIN_STATUS_NO_VERSION);
    237 		queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug);
    238 		conn_state(c, T7);
    239 		free(rsp);
    240 		return (True);
    241 	}
    242 
    243 	if (lh.flags & ISCSI_FLAG_LOGIN_CONTINUE) {
    244 		(void) snprintf(debug, sizeof (debug),
    245 		    "CON%x  Continuation pkt", c->c_num);
    246 		queue_str(c->c_mgmtq, Q_CONN_LOGIN, msg_log, debug);
    247 	}
    248 
    249 	auth_client =
    250 	    (c->c_sess->sess_auth.auth_buffers &&
    251 	    c->c_sess->sess_auth.num_auth_buffers) ?
    252 	    (IscsiAuthClient *) c->c_sess->sess_auth.auth_buffers[0].address :
    253 	    NULL;
    254 
    255 	if (c->auth_text != NULL)
    256 		free(c->auth_text);
    257 	c->auth_text_length = 0;
    258 
    259 	transit = lh.flags & ISCSI_FLAG_LOGIN_TRANSIT;
    260 
    261 	switch (ISCSI_LOGIN_CURRENT_STAGE(lh.flags)) {
    262 	case ISCSI_SECURITY_NEGOTIATION_STAGE:
    263 
    264 		/*
    265 		 * Grab the parameters and create the response
    266 		 * text.
    267 		 */
    268 		rval = parse_text(c, ntoh24(lh.dlength),
    269 		    &text_rsp, &text_length, &errcode);
    270 		if (rval == False) {
    271 			send_login_reject(c, &lh, errcode);
    272 			(void) snprintf(debug, sizeof (debug),
    273 			    "CON%x  SecurityNegotiation: parse_text"
    274 			    " failed", c->c_num);
    275 			queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug);
    276 			conn_state(c, T7);
    277 			break;
    278 		}
    279 
    280 		if ((rval = check_for_valid_I_T(c)) == False) {
    281 			send_login_reject(c, &lh,
    282 			    (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) |
    283 			    ISCSI_LOGIN_STATUS_INIT_ERR);
    284 			(void) snprintf(debug, sizeof (debug),
    285 			    "CON%x  SecurityNegotiation: invalid I "
    286 			    "or T", c->c_num);
    287 			queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug);
    288 			conn_state(c, T7);
    289 			break;
    290 		}
    291 
    292 		auth_action = login_set_auth(c->c_sess);
    293 
    294 		if (auth_action == LOGIN_NO_AUTH) {
    295 			rsp->flags |= ISCSI_FLAG_LOGIN_TRANSIT;
    296 			rsp->flags |= ISCSI_OP_PARMS_NEGOTIATION_STAGE;
    297 			rval = add_text(&text_rsp, &text_length, "AuthMethod",
    298 			    "None");
    299 			if (rval == False) {
    300 				send_login_reject(c, &lh,
    301 				    (ISCSI_STATUS_CLASS_TARGET_ERR << 8) |
    302 				    ISCSI_LOGIN_STATUS_TARGET_ERROR);
    303 				(void) snprintf(debug, sizeof (debug),
    304 				    "CON%x Norm: Failed to add AuthMethod=None",
    305 				    c->c_num);
    306 				queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log,
    307 				    debug);
    308 				conn_state(c, T7);
    309 			}
    310 			break;
    311 		}
    312 
    313 		if (auth_action == LOGIN_DROP) {
    314 			send_login_reject(c, &lh,
    315 			    (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) |
    316 			    ISCSI_LOGIN_STATUS_TGT_FORBIDDEN);
    317 			(void) snprintf(debug, sizeof (debug),
    318 			    "CON%x  SecurityNegotiation: access denied",
    319 			    c->c_num);
    320 			queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug);
    321 			conn_state(c, T7);
    322 			rval = False;
    323 			break;
    324 		}
    325 
    326 		if (iscsiAuthClientRecvBegin(auth_client) !=
    327 		    iscsiAuthStatusNoError) {
    328 			(void) snprintf(debug, sizeof (debug), "CON%x  "
    329 			    "login failed - authentication receive failed",
    330 			    c->c_num);
    331 			queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug);
    332 			break;
    333 		}
    334 
    335 		if (iscsiAuthClientRecvTransitBit(auth_client,
    336 		    transit) != iscsiAuthStatusNoError) {
    337 			(void) snprintf(debug, sizeof (debug),
    338 			    "iscsi connection(%u) login failed - "
    339 			    "authentication transmit failed", c->c_num);
    340 			queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug);
    341 			break;
    342 		}
    343 
    344 		/*
    345 		 * scan the text data
    346 		 */
    347 		text = c->auth_text;
    348 		end = text + c->auth_text_length;
    349 more_text:
    350 		while (text && (text < end)) {
    351 			char *value = NULL;
    352 			char *value_end = NULL;
    353 			keytype = iscsiAuthKeyTypeNone;
    354 
    355 			/*
    356 			 * skip any NULs separating each text key=value pair
    357 			 */
    358 			while ((text < end) && (*text == '\0')) {
    359 				text++;
    360 			}
    361 			if (text >= end) {
    362 				break;
    363 			}
    364 
    365 			while (iscsiAuthClientGetNextKeyType(&keytype) ==
    366 			    iscsiAuthStatusNoError) {
    367 				char *key =
    368 				    (char *)iscsiAuthClientGetKeyName(keytype);
    369 				if ((key) &&
    370 				    (iscsi_find_key_value(key, text, end,
    371 				    &value, &value_end))) {
    372 					(void) snprintf(debug, sizeof (debug),
    373 					    "%s=%s", key, value);
    374 					queue_str(c->c_mgmtq, Q_CONN_ERRS,
    375 					    msg_log, debug);
    376 					if (iscsiAuthClientRecvKeyValue(
    377 					    auth_client, keytype, value)
    378 					    != iscsiAuthStatusNoError) {
    379 						(void) snprintf(debug,
    380 						    sizeof (debug),
    381 						    "iscsi connection(%u) login"
    382 						    "failed - can't accept "
    383 						    "%s in security stage",
    384 						    c->c_num, text);
    385 						queue_str(c->c_mgmtq,
    386 						    Q_CONN_ERRS,
    387 						    msg_log, debug);
    388 					}
    389 					text = value_end;
    390 					goto more_text;
    391 				}
    392 			}
    393 		}
    394 
    395 		switch (iscsiAuthClientRecvEnd(auth_client, iscsi_null_callback,
    396 		    (void *)c->c_sess, NULL)) {
    397 		case iscsiAuthStatusContinue:
    398 			/*
    399 			 * continue sending PDUs
    400 			 */
    401 			break;
    402 
    403 		case iscsiAuthStatusPass:
    404 			c->c_auth_pass = 1;
    405 			break;
    406 
    407 		case iscsiAuthStatusInProgress:
    408 			/*
    409 			 * this should only occur if we were authenticating the
    410 			 * target, which we don't do yet, so treat this as an
    411 			 * error.
    412 			 */
    413 		case iscsiAuthStatusNoError:
    414 			/*
    415 			 * treat this as an error, since we should get a
    416 			 * different code
    417 			 */
    418 		case iscsiAuthStatusError:
    419 		case iscsiAuthStatusFail:
    420 		default:
    421 			debug_status = 0;
    422 
    423 			(void) iscsiAuthClientGetDebugStatus(auth_client,
    424 			    &debug_status);
    425 			(void) snprintf(debug, sizeof (debug),
    426 			    "iscsi connection(%u) authentication failed (%s)",
    427 			    c->c_num, iscsiAuthClientDebugStatusToText(
    428 			    debug_status));
    429 			queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug);
    430 
    431 			send_login_reject(c, &lh,
    432 			    (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) |
    433 			    ISCSI_LOGIN_STATUS_AUTH_FAILED);
    434 			conn_state(c, T7);
    435 			rval = False;
    436 			break;
    437 		}
    438 
    439 		if (rval == False)
    440 			break;
    441 
    442 		keytype = iscsiAuthKeyTypeNone;
    443 		rc = iscsiAuthClientSendTransitBit(auth_client, &transit);
    444 
    445 		/*
    446 		 * see if we're ready for a stage change
    447 		 */
    448 		if (rc == iscsiAuthStatusNoError) {
    449 			if (transit) {
    450 				rsp->flags = lh.flags;
    451 			}
    452 
    453 		} else {
    454 			send_login_reject(c, &lh,
    455 			    (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) |
    456 			    ISCSI_LOGIN_STATUS_AUTH_FAILED);
    457 			(void) snprintf(debug, sizeof (debug),
    458 			    "CON%x  SecurityNegotiation: wants", c->c_num);
    459 			queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug);
    460 			conn_state(c, T7);
    461 			rval = False;
    462 		}
    463 
    464 		/*
    465 		 * enumerate all the keys the auth code might want to send
    466 		 */
    467 		while (iscsiAuthClientGetNextKeyType(&keytype) ==
    468 		    iscsiAuthStatusNoError) {
    469 			int present = 0;
    470 			char *key = (char *)iscsiAuthClientGetKeyName(keytype);
    471 			int key_length = key ? strlen(key) : 0;
    472 			int pdu_length = ntoh24(rsp->dlength);
    473 			char *auth_value = NULL;
    474 			unsigned int max_length = ISCSI_DEFAULT_MAX_XMIT_SEG_LEN
    475 			    - (pdu_length + key_length + 1); /* FIXME: check */
    476 
    477 			/*
    478 			 * add the key/value pairs the auth code wants to
    479 			 * send directly to the PDU, since they could in
    480 			 * theory be large.
    481 			 */
    482 			if ((auth_value = (char *)malloc(max_length)) ==
    483 			    NULL) {
    484 				send_login_reject(c, &lh,
    485 				    (ISCSI_STATUS_CLASS_TARGET_ERR << 8) |
    486 				    ISCSI_LOGIN_STATUS_TARGET_ERROR);
    487 
    488 				(void) snprintf(debug, sizeof (debug),
    489 				    "CON%x Norm: Failed alloc auth_key %S=%s",
    490 				    c->c_num, key, auth_value);
    491 				queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log,
    492 				    debug);
    493 				conn_state(c, T7);
    494 				rval = False;
    495 				break;
    496 			}
    497 			rc = iscsiAuthClientSendKeyValue(auth_client, keytype,
    498 			    &present, auth_value, max_length);
    499 			if ((rc == iscsiAuthStatusNoError) && present) {
    500 				(void) snprintf(debug, sizeof (debug),
    501 				    "key:%s, auth_value:%s\n", key, auth_value);
    502 				queue_str(c->c_mgmtq, Q_CONN_LOGIN, msg_log,
    503 				    debug);
    504 
    505 				rval = add_text(&text_rsp, &text_length,
    506 				    key, auth_value);
    507 				if (rval == False) {
    508 					send_login_reject(c, &lh,
    509 					    (ISCSI_STATUS_CLASS_TARGET_ERR <<
    510 					    8) |
    511 					    ISCSI_LOGIN_STATUS_TARGET_ERROR);
    512 					(void) snprintf(debug, sizeof (debug),
    513 					    "CON%x Norm: Failed to add %S=%s",
    514 					    c->c_num, key, auth_value);
    515 					queue_str(c->c_mgmtq, Q_CONN_ERRS,
    516 					    msg_log, debug);
    517 					conn_state(c, T7);
    518 				}
    519 			}
    520 			if (auth_value != NULL)
    521 				free(auth_value);
    522 		}
    523 
    524 		break;
    525 
    526 	case ISCSI_OP_PARMS_NEGOTIATION_STAGE:
    527 
    528 		/*
    529 		 * Gather up the parameters sent across and build a response
    530 		 * based on any selection required.
    531 		 */
    532 		if ((rval = parse_text(c, ntoh24(lh.dlength), &text_rsp,
    533 		    &text_length, &errcode)) == False) {
    534 
    535 			send_login_reject(c, &lh, errcode);
    536 			(void) snprintf(debug, sizeof (debug),
    537 			    "CON%x  Norm: parse_text failed", c->c_num);
    538 			queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug);
    539 			conn_state(c, T7);
    540 			break;
    541 		}
    542 
    543 		/*
    544 		 * If the connection hasn't passed authentication and
    545 		 * it's a normal session see if this connection MUST
    546 		 * have gone through authentication first. If the
    547 		 * initiator has a CHAP secret stored that means we
    548 		 * want to validate.
    549 		 */
    550 		if ((c->c_auth_pass == 0) &&
    551 		    (c->c_sess->s_type == SessionNormal)) {
    552 			if ((tnode = find_target_node(c->c_sess->s_t_name)) ==
    553 			    NULL) {
    554 				send_login_reject(c, &lh,
    555 				    (ISCSI_STATUS_CLASS_TARGET_ERR << 8) |
    556 				    ISCSI_LOGIN_STATUS_TARGET_ERROR);
    557 				(void) snprintf(debug, sizeof (debug),
    558 				    "CON%x  No target node in login",
    559 				    c->c_num);
    560 				queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log,
    561 				    debug);
    562 				conn_state(c, T7);
    563 			}
    564 
    565 			/*
    566 			 * check_access will return True if the initiator
    567 			 * is required to use CHAP authentication. So if
    568 			 * true and we're here it means that the initiator
    569 			 * is trying to skip the authentication step.
    570 			 */
    571 			if (check_access(tnode, c->c_sess->s_i_name, True) ==
    572 			    False) {
    573 				send_login_reject(c, &lh,
    574 				    (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) |
    575 				    ISCSI_LOGIN_STATUS_AUTH_FAILED);
    576 				(void) snprintf(debug, sizeof (debug),
    577 				    "CON%x  Authentication required for %s",
    578 				    c->c_num, c->c_sess->s_i_name);
    579 				queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log,
    580 				    debug);
    581 				conn_state(c, T7);
    582 			}
    583 		}
    584 
    585 		if ((rval = check_for_valid_I_T(c)) == False) {
    586 			send_login_reject(c, &lh,
    587 			    (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) |
    588 			    ISCSI_LOGIN_STATUS_INIT_ERR);
    589 
    590 			(void) snprintf(debug, sizeof (debug),
    591 			    "CON%x  Norm: bad I or T", c->c_num);
    592 			queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug);
    593 			conn_state(c, T7);
    594 			break;
    595 		}
    596 
    597 		/*
    598 		 * We accept transition and stage information as is
    599 		 * and echo it back because at this point there's no need
    600 		 * to send a parameter to the Initiator and expect a
    601 		 * reply.
    602 		 */
    603 		rsp->flags = lh.flags;
    604 
    605 		break;
    606 
    607 	case ISCSI_FULL_FEATURE_PHASE:
    608 		/* can't jump directly to full feature phase */
    609 		(void) snprintf(debug, sizeof (debug),
    610 		    "CON%x  Protocol error: wrong stage", c->c_num);
    611 		queue_str(c->c_mgmtq, Q_CONN_ERRS, msg_log, debug);
    612 		send_login_reject(c, &lh,
    613 		    (ISCSI_STATUS_CLASS_INITIATOR_ERR << 8) |
    614 		    ISCSI_LOGIN_STATUS_INIT_ERR);
    615 		conn_state(c, T7);
    616 		rval = False;
    617 		break;
    618 
    619 	default:
    620 		/* just drop the connection since we don't know what's up */
    621 		rval = False;
    622 		break;
    623 	}
    624 
    625 	hton24(rsp->dlength, text_length);
    626 	if ((rval == True) && (session_validate(c->c_sess) == True)) {
    627 
    628 		if (ISCSI_LOGIN_RESPONSE_ENABLED()) {
    629 			uiscsiproto_t info;
    630 			char nil = '\0';
    631 
    632 			info.uip_target_addr = &c->c_target_sockaddr;
    633 			info.uip_initiator_addr = &c->c_initiator_sockaddr;
    634 
    635 			info.uip_target = &nil;
    636 			info.uip_initiator = c->c_sess->s_i_name;
    637 			info.uip_lun = 0;
    638 
    639 			info.uip_itt = rsp->itt;
    640 			info.uip_ttt = ISCSI_RSVD_TASK_TAG;
    641 
    642 			info.uip_cmdsn = ntohl(rsp->expcmdsn);
    643 			info.uip_statsn = ntohl(rsp->statsn);
    644 			info.uip_datasn = 0;
    645 
    646 			info.uip_datalen = text_length;
    647 			info.uip_flags = rsp->flags;
    648 
    649 			ISCSI_LOGIN_RESPONSE(&info);
    650 		}
    651 
    652 		send_iscsi_pkt(c, (iscsi_hdr_t *)rsp, text_rsp);
    653 
    654 		if ((lh.flags & ISCSI_FLAG_LOGIN_TRANSIT) &&
    655 		    (ISCSI_LOGIN_NEXT_STAGE(lh.flags) ==
    656 		    ISCSI_FULL_FEATURE_PHASE)) {
    657 
    658 			conn_state(c, T5);
    659 
    660 			/*
    661 			 * At this point we've completed the negotiation
    662 			 * of all login parameters. Now we need to perform
    663 			 * some quick boundary checks and then send a couple
    664 			 * pieces of information to STE for it's use.
    665 			 */
    666 			c->c_max_burst_len = MIN(c->c_max_burst_len,
    667 			    c->c_max_recv_data);
    668 		}
    669 	}
    670 
    671 	if (text_rsp != NULL)
    672 		free(text_rsp);
    673 	if (rsp != NULL)
    674 		free(rsp);
    675 
    676 	return (rval);
    677 }
    678 
    679 /*
    680  * check_for_valid_I_T -- check to see if we have valid names
    681  *
    682  * This routine checks to see if we have received a valid InitiatorName
    683  * and TargetName which is the bare minimum which an Initiator must send
    684  * across during the login phase.
    685  */
    686 static Boolean_t
    687 check_for_valid_I_T(iscsi_conn_t *c)
    688 {
    689 	iscsi_sess_t	*s = c->c_sess;
    690 	if (s->s_type == SessionDiscovery)
    691 		return (s->s_i_name == NULL || strlen(s->s_i_name) == 0) ?
    692 		    False : True;
    693 	else
    694 		return (s->s_t_name == NULL || strlen(s->s_t_name) == 0) ||
    695 		    (s->s_i_name == NULL || strlen(s->s_i_name) == 0) ?
    696 		    False : True;
    697 }
    698 
    699 static iscsi_login_rsp_hdr_t *
    700 make_login_response(iscsi_conn_t *c, iscsi_login_hdr_t *lhp)
    701 {
    702 	iscsi_login_rsp_hdr_t	*r;
    703 
    704 	if (lhp->tsid != 0)
    705 		/* don't except existing sessions for now */
    706 		return (NULL);
    707 
    708 	r = (iscsi_login_rsp_hdr_t *)calloc(sizeof (*r), sizeof (char));
    709 	if (r == NULL)
    710 		return (NULL);
    711 
    712 	bcopy(lhp->isid, r->isid, 6); /* 6 is defined by protocol */
    713 	r->opcode		= ISCSI_OP_LOGIN_RSP;
    714 	r->flags		= ISCSI_FLAG_LOGIN_TRANSIT;
    715 	r->max_version		= ISCSI_MAX_VERSION;
    716 	r->active_version	= ISCSI_MIN_VERSION;
    717 	r->itt			= lhp->itt;
    718 
    719 	/*
    720 	 * As per section 10.13.3 of iSCSI RFC (3720), For a new session,
    721 	 * the target MUST generate a non-zero TSIH and ONLY return it
    722 	 * in the Login Final-Response
    723 	 */
    724 	if ((lhp->flags & ISCSI_FLAG_LOGIN_TRANSIT) &&
    725 	    (ISCSI_LOGIN_NEXT_STAGE(lhp->flags) ==
    726 	    ISCSI_FULL_FEATURE_PHASE))
    727 		/*
    728 		 * If this is the final Login Response, send the target
    729 		 * calculated TSIH
    730 		 */
    731 		r->tsid		= htons(c->c_sess->s_tsid);
    732 	else
    733 		/*
    734 		 * If this is not the final Login Response, send the TSIH value
    735 		 * provided by the initiator.
    736 		 */
    737 		r->tsid		= lhp->tsid;
    738 
    739 	(void) pthread_mutex_lock(&c->c_mutex);
    740 	r->statsn		= htonl(c->c_statsn++);
    741 	(void) pthread_mutex_unlock(&c->c_mutex);
    742 	if (c->c_sess != NULL) {
    743 		(void) pthread_mutex_lock(&c->c_sess->s_mutex);
    744 		/* ---- cmdsn is not advanced during login ---- */
    745 		r->expcmdsn	= htonl(c->c_sess->s_seencmdsn);
    746 		r->maxcmdsn	= htonl(CMD_MAXOUTSTANDING +
    747 		    c->c_sess->s_seencmdsn);
    748 		(void) pthread_mutex_unlock(&c->c_sess->s_mutex);
    749 	}
    750 
    751 	return (r);
    752 }
    753 
    754 static void
    755 send_login_reject(iscsi_conn_t *c, iscsi_login_hdr_t *lhp, int err_code)
    756 {
    757 	iscsi_login_rsp_hdr_t	*r;
    758 
    759 	if ((r = make_login_response(c, lhp)) == NULL)
    760 		return;
    761 
    762 	r->status_class = (err_code >> 8) & 0xff;
    763 	r->status_detail = err_code & 0xff;
    764 
    765 	if (ISCSI_LOGIN_RESPONSE_ENABLED()) {
    766 		uiscsiproto_t info;
    767 		char nil = '\0';
    768 
    769 		info.uip_target_addr = &c->c_target_sockaddr;
    770 		info.uip_initiator_addr = &c->c_initiator_sockaddr;
    771 
    772 		info.uip_target = &nil;
    773 		info.uip_initiator = &nil;
    774 		info.uip_lun = 0;
    775 
    776 		info.uip_itt = r->itt;
    777 		info.uip_ttt = ISCSI_RSVD_TASK_TAG;
    778 
    779 		info.uip_cmdsn = ntohl(r->expcmdsn);
    780 		info.uip_statsn = ntohl(r->statsn);
    781 		info.uip_datasn = 0;
    782 
    783 		info.uip_datalen = ntoh24(r->dlength);
    784 		info.uip_flags = r->flags;
    785 
    786 		ISCSI_LOGIN_RESPONSE(&info);
    787 	}
    788 
    789 	(void) write(c->c_fd, r, sizeof (*r));
    790 	free(r);
    791 }
    792 
    793 static auth_action_t
    794 login_set_auth(iscsi_sess_t *s)
    795 {
    796 	tgt_node_t *xnInitiator = NULL;
    797 	tgt_node_t *xnTarget = NULL;
    798 	tgt_node_t *xnAcl = NULL;
    799 	char *szIniAlias = NULL;
    800 	char *szIscsiName = NULL;
    801 	char *szChapName = NULL;
    802 	char *szChapSecret = NULL;
    803 	char *possible = NULL;
    804 	iscsi_auth_t *sess_auth = &(s->sess_auth);
    805 	int comp = 0;
    806 	int username_len = 0;
    807 
    808 	bzero(sess_auth->username_in, sizeof (sess_auth->username_in));
    809 	bzero(sess_auth->password_in, sizeof (sess_auth->password_in));
    810 	sess_auth->password_length_in = 0;
    811 
    812 	/* Load alias, iscsi-name, chap-name, chap-secret from config file */
    813 	while ((xnInitiator = tgt_node_next_child(main_config, XML_ELEMENT_INIT,
    814 	    xnInitiator)) != NULL) {
    815 
    816 		(void) tgt_find_value_str(xnInitiator, XML_ELEMENT_INIT,
    817 		    &szIniAlias);
    818 
    819 		if (tgt_find_value_str(xnInitiator, XML_ELEMENT_INAME,
    820 		    &szIscsiName) == True) {
    821 
    822 			comp = strcmp(s->s_i_name, szIscsiName);
    823 			free(szIscsiName);
    824 			szIscsiName = NULL;
    825 
    826 			if (comp == 0) {
    827 
    828 				if (tgt_find_value_str(xnInitiator,
    829 				    XML_ELEMENT_CHAPNAME,
    830 				    &szChapName) == True) {
    831 					/*CSTYLED*/
    832 					(void) strcpy(
    833 					    (char *)sess_auth->username_in,
    834 					    szChapName);
    835 					username_len = strlen(szChapName);
    836 					free(szChapName);
    837 				}
    838 
    839 				if (tgt_find_value_str(xnInitiator,
    840 				    XML_ELEMENT_CHAPSECRET,
    841 				    &szChapSecret) == True) {
    842 					/*CSTYLED*/
    843 					(void) strcpy(
    844 					    (char *)sess_auth->password_in,
    845 					    szChapSecret);
    846 					sess_auth->password_length_in =
    847 					    strlen(szChapSecret);
    848 					free(szChapSecret);
    849 				}
    850 				break;
    851 			}
    852 		}
    853 	}
    854 
    855 	if (s->s_type == SessionDiscovery) {
    856 		return (LOGIN_NO_AUTH);
    857 	}
    858 
    859 	if (s->s_t_name == NULL) {
    860 		/*
    861 		 * Should not happen for non-discovery session
    862 		 */
    863 		return (LOGIN_DROP);
    864 	}
    865 
    866 	/*
    867 	 * If iSNS enabled set LOGIN_AUTH
    868 	 */
    869 	if (isns_enabled() == True) {
    870 		if (username_len == 0)
    871 			return (LOGIN_NO_AUTH);
    872 		return (LOGIN_AUTH);
    873 	}
    874 
    875 	/*
    876 	 * If no acc_list for current target
    877 	 *    If no CHAP secret for the initiator, transit.
    878 	 *    If CHAP secret exists for the initiator, it must be authed.
    879 	 * If acc_list exists for the target, and
    880 	 * If the initiator not in the list, drop it.
    881 	 * If the initiator in the list, and
    882 	 * If no CHAP name for the initiator, transit.
    883 	 * If a CHAP name exists for the initiator, it must be authed.
    884 	 */
    885 
    886 	while ((xnTarget = tgt_node_next_child(targets_config, XML_ELEMENT_TARG,
    887 	    xnTarget)) != NULL) {
    888 
    889 		if ((tgt_find_value_str(xnTarget, XML_ELEMENT_INAME,
    890 		    &szIscsiName) == False) || (szIscsiName == NULL)) {
    891 			return (LOGIN_DROP);
    892 		}
    893 
    894 		comp = strcmp(szIscsiName, s->s_t_name);
    895 		free(szIscsiName);
    896 		szIscsiName = NULL;
    897 
    898 		if (comp == 0) {
    899 
    900 			if ((xnAcl = tgt_node_next(xnTarget,
    901 			    XML_ELEMENT_ACLLIST, 0)) == NULL) {
    902 				/*
    903 				 * No acl_list found, return auth or no auth
    904 				 */
    905 				if (username_len == 0)
    906 					return (LOGIN_NO_AUTH);
    907 				return (LOGIN_AUTH);
    908 			}
    909 
    910 			/*
    911 			 * This target has an access_list. Now compare
    912 			 * those entries against the initiator who started
    913 			 * this session.
    914 			 */
    915 			xnInitiator = NULL;
    916 			while ((xnInitiator = tgt_node_next(xnAcl,
    917 			    XML_ELEMENT_INIT, xnInitiator)) != NULL) {
    918 
    919 				if ((tgt_find_value_str(xnInitiator,
    920 				    XML_ELEMENT_INIT, &possible) == False) ||
    921 				    (possible == NULL))
    922 					continue;
    923 
    924 				if (strcmp(szIniAlias, possible) == 0) {
    925 					/*
    926 					 * Found the initiator in acl-list,
    927 					 * authentication needed
    928 					 */
    929 					free(possible);
    930 					if (username_len == 0)
    931 						return (LOGIN_NO_AUTH);
    932 					else
    933 						return (LOGIN_AUTH);
    934 				}
    935 
    936 				free(possible);
    937 				possible = NULL;
    938 			}
    939 			/*
    940 			 * Acl-list exists, while the initiator is not found in
    941 			 * the list, we should drop the connection
    942 			 */
    943 			return (LOGIN_DROP);
    944 		}
    945 	}
    946 
    947 	/* False means Need authentication */
    948 	return (LOGIN_AUTH);
    949 }
    950