File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / istgt / src / istgt_lu_ctl.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:13:23 2012 UTC (11 years, 9 months ago) by misho
Branches: istgt, MAIN
CVS tags: v20121028, v20120901, HEAD
dhcp 4.1 r7

    1: /*
    2:  * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
    3:  * All rights reserved.
    4:  *
    5:  * Redistribution and use in source and binary forms, with or without
    6:  * modification, are permitted provided that the following conditions
    7:  * are met:
    8:  * 1. Redistributions of source code must retain the above copyright
    9:  *    notice, this list of conditions and the following disclaimer.
   10:  * 2. Redistributions in binary form must reproduce the above copyright
   11:  *    notice, this list of conditions and the following disclaimer in the
   12:  *    documentation and/or other materials provided with the distribution.
   13:  *
   14:  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17:  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
   18:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24:  * SUCH DAMAGE.
   25:  *
   26:  */
   27: 
   28: #ifdef HAVE_CONFIG_H
   29: #include "config.h"
   30: #endif
   31: 
   32: #include <inttypes.h>
   33: #include <stdint.h>
   34: 
   35: #include <stdarg.h>
   36: #include <stdio.h>
   37: #include <stdlib.h>
   38: #include <string.h>
   39: #include <pthread.h>
   40: #ifdef HAVE_PTHREAD_NP_H
   41: #include <pthread_np.h>
   42: #endif
   43: #include <unistd.h>
   44: #include <sys/param.h>
   45: 
   46: #include "istgt.h"
   47: #include "istgt_ver.h"
   48: #include "istgt_log.h"
   49: #include "istgt_sock.h"
   50: #include "istgt_misc.h"
   51: #include "istgt_md5.h"
   52: #include "istgt_lu.h"
   53: #include "istgt_iscsi.h"
   54: #include "istgt_proto.h"
   55: 
   56: #if !defined(__GNUC__)
   57: #undef __attribute__
   58: #define __attribute__(x)
   59: #endif
   60: 
   61: #define TIMEOUT_RW 60
   62: #define MAX_LINEBUF 4096
   63: 
   64: typedef struct istgt_uctl_t {
   65: 	int id;
   66: 
   67: 	ISTGT_Ptr istgt;
   68: 	PORTAL portal;
   69: 	int sock;
   70: 	pthread_t thread;
   71: 
   72: 	int family;
   73: 	char caddr[MAX_ADDRBUF];
   74: 	char saddr[MAX_ADDRBUF];
   75: 
   76: 	ISTGT_CHAP_AUTH auth;
   77: 	int authenticated;
   78: 
   79: 	int timeout;
   80: 	int auth_group;
   81: 	int no_auth;
   82: 	int req_auth;
   83: 	int req_mutual;
   84: 
   85: 	char *mediadirectory;
   86: 
   87: 	int recvtmpsize;
   88: 	int recvtmpcnt;
   89: 	int recvtmpidx;
   90: 	int recvbufsize;
   91: 	int sendbufsize;
   92: 	int worksize;
   93: 	char recvtmp[MAX_LINEBUF];
   94: 	char recvbuf[MAX_LINEBUF];
   95: 	char sendbuf[MAX_LINEBUF];
   96: 	char work[MAX_LINEBUF];
   97: 	char *cmd;
   98: 	char *arg;
   99: } UCTL;
  100: typedef UCTL *UCTL_Ptr;
  101: 
  102: typedef enum {
  103: 	UCTL_CMD_OK = 0,
  104: 	UCTL_CMD_ERR = 1,
  105: 	UCTL_CMD_EOF = 2,
  106: 	UCTL_CMD_QUIT = 3,
  107: 	UCTL_CMD_DISCON = 4,
  108: } UCTL_CMD_STATUS;
  109: 
  110: #define ARGS_DELIM " \t"
  111: 
  112: static int
  113: istgt_uctl_readline(UCTL_Ptr uctl)
  114: {
  115: 	ssize_t total;
  116: 
  117: 	total = istgt_readline_socket(uctl->sock, uctl->recvbuf, uctl->recvbufsize,
  118: 	    uctl->recvtmp, uctl->recvtmpsize,
  119: 	    &uctl->recvtmpidx, &uctl->recvtmpcnt,
  120: 	    uctl->timeout);
  121: 	if (total < 0) {
  122: 		return UCTL_CMD_DISCON;
  123: 	}
  124: 	if (total == 0) {
  125: 		return UCTL_CMD_EOF;
  126: 	}
  127: 	return UCTL_CMD_OK;
  128: }
  129: 
  130: static int
  131: istgt_uctl_writeline(UCTL_Ptr uctl)
  132: {
  133: 	ssize_t total;
  134: 	ssize_t expect;
  135: 
  136: 	expect = strlen(uctl->sendbuf);
  137: 	total = istgt_writeline_socket(uctl->sock, uctl->sendbuf, uctl->timeout);
  138: 	if (total < 0) {
  139: 		return UCTL_CMD_DISCON;
  140: 	}
  141: 	if (total != expect) {
  142: 		return UCTL_CMD_ERR;
  143: 	}
  144: 	return UCTL_CMD_OK;
  145: }
  146: 
  147: static int istgt_uctl_snprintf(UCTL_Ptr uctl, const char *format, ...) __attribute__((__format__(__printf__, 2, 3)));
  148: 
  149: static int
  150: istgt_uctl_snprintf(UCTL_Ptr uctl, const char *format, ...)
  151: {
  152: 	va_list ap;
  153: 	int rc;
  154: 
  155: 	va_start(ap, format);
  156: 	rc = vsnprintf(uctl->sendbuf, uctl->sendbufsize, format, ap);
  157: 	va_end(ap);
  158: 	return rc;
  159: }
  160: 
  161: static int
  162: istgt_uctl_get_media_present(ISTGT_LU_Ptr lu, int lun)
  163: {
  164: 	int rc;
  165: 
  166: 	switch (lu->type) {
  167: 	case ISTGT_LU_TYPE_DVD:
  168: 		MTX_LOCK(&lu->mutex);
  169: 		rc = istgt_lu_dvd_media_present(lu->lun[lun].spec);
  170: 		MTX_UNLOCK(&lu->mutex);
  171: 		break;
  172: 	case ISTGT_LU_TYPE_TAPE:
  173: 		MTX_LOCK(&lu->mutex);
  174: 		rc = istgt_lu_tape_media_present(lu->lun[lun].spec);
  175: 		MTX_UNLOCK(&lu->mutex);
  176: 		break;
  177: 	default:
  178: 		rc = 0;
  179: 	}
  180: 	return rc;
  181: }
  182: 
  183: static int
  184: istgt_uctl_get_media_lock(ISTGT_LU_Ptr lu, int lun)
  185: {
  186: 	int rc;
  187: 
  188: 	switch (lu->type) {
  189: 	case ISTGT_LU_TYPE_DVD:
  190: 		MTX_LOCK(&lu->mutex);
  191: 		rc = istgt_lu_dvd_media_lock(lu->lun[lun].spec);
  192: 		MTX_UNLOCK(&lu->mutex);
  193: 		break;
  194: 	case ISTGT_LU_TYPE_TAPE:
  195: 		MTX_LOCK(&lu->mutex);
  196: 		rc = istgt_lu_tape_media_lock(lu->lun[lun].spec);
  197: 		MTX_UNLOCK(&lu->mutex);
  198: 		break;
  199: 	default:
  200: 		rc = 0;
  201: 	}
  202: 	return rc;
  203: }
  204: 
  205: static int
  206: istgt_uctl_get_authinfo(UCTL_Ptr uctl, const char *authuser)
  207: {
  208: 	char *authfile = NULL;
  209: 	int ag_tag;
  210: 	int rc;
  211: 
  212: 	ag_tag = uctl->auth_group;
  213: 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "ag_tag=%d\n", ag_tag);
  214: 
  215: 	MTX_LOCK(&uctl->istgt->mutex);
  216: 	authfile = xstrdup(uctl->istgt->authfile);
  217: 	MTX_UNLOCK(&uctl->istgt->mutex);
  218: 
  219: 	rc = istgt_chap_get_authinfo(&uctl->auth, authfile, authuser, ag_tag);
  220: 	if (rc < 0) {
  221: 		ISTGT_ERRLOG("chap_get_authinfo() failed\n");
  222: 		xfree(authfile);
  223: 		return -1;
  224: 	}
  225: 	xfree(authfile);
  226: 	return 0;
  227: }
  228: 
  229: static int
  230: istgt_uctl_cmd_auth(UCTL_Ptr uctl)
  231: {
  232: 	const char *delim = ARGS_DELIM;
  233: 	char *arg;
  234: 	char *label;
  235: 	char *chap_a;
  236: 	char *chap_i;
  237: 	char *chap_c;
  238: 	char *chap_n;
  239: 	char *chap_r;
  240: 	int rc;
  241: 
  242: 	arg = uctl->arg;
  243: 	label = strsepq(&arg, delim);
  244: 
  245: 	if (label == NULL) {
  246: 		istgt_uctl_snprintf(uctl, "ERR invalid parameters\n");
  247: 		rc = istgt_uctl_writeline(uctl);
  248: 		if (rc != UCTL_CMD_OK) {
  249: 			return rc;
  250: 		}
  251: 		return UCTL_CMD_ERR;
  252: 	}
  253: 
  254: 	if (strcasecmp(label, "CHAP_A") == 0) {
  255: 		if (uctl->auth.chap_phase != ISTGT_CHAP_PHASE_WAIT_A) {
  256: 			istgt_uctl_snprintf(uctl, "ERR CHAP sequence error\n");
  257: 		error_return:
  258: 			uctl->auth.chap_phase = ISTGT_CHAP_PHASE_WAIT_A;
  259: 			rc = istgt_uctl_writeline(uctl);
  260: 			if (rc != UCTL_CMD_OK) {
  261: 				return rc;
  262: 			}
  263: 			return UCTL_CMD_ERR;
  264: 		}
  265: 
  266: 		chap_a = strsepq(&arg, delim);
  267: 		if (chap_a == NULL  || strcasecmp(chap_a, "5") != 0) {
  268: 			istgt_uctl_snprintf(uctl, "ERR invalid algorithm\n");
  269: 			goto error_return;
  270: 		}
  271: 
  272: 		/* Identifier is one octet */
  273: 		istgt_gen_random(uctl->auth.chap_id, 1);
  274: 		/* Challenge Value is a variable stream of octets */
  275: 		/* (binary length MUST not exceed 1024 bytes) */
  276: 		uctl->auth.chap_challenge_len = ISTGT_CHAP_CHALLENGE_LEN;
  277: 		istgt_gen_random(uctl->auth.chap_challenge,
  278: 		    uctl->auth.chap_challenge_len);
  279: 
  280: 		istgt_bin2hex(uctl->work, uctl->worksize,
  281: 		    uctl->auth.chap_challenge,
  282: 		    uctl->auth.chap_challenge_len);
  283: 
  284: 		istgt_uctl_snprintf(uctl, "%s CHAP_IC %d %s\n",
  285: 		    uctl->cmd, (int) uctl->auth.chap_id[0],
  286: 		    uctl->work);
  287: 		
  288: 		rc = istgt_uctl_writeline(uctl);
  289: 		if (rc != UCTL_CMD_OK) {
  290: 			return rc;
  291: 		}
  292: 		uctl->auth.chap_phase = ISTGT_CHAP_PHASE_WAIT_NR;
  293: 		/* 3-way handshake */
  294: 		return UCTL_CMD_OK;
  295: 	} else if (strcasecmp(label, "CHAP_NR") == 0) {
  296: 		uint8_t resmd5[ISTGT_MD5DIGEST_LEN];
  297: 		uint8_t tgtmd5[ISTGT_MD5DIGEST_LEN];
  298: 		ISTGT_MD5CTX md5ctx;
  299: 
  300: 		if (uctl->auth.chap_phase != ISTGT_CHAP_PHASE_WAIT_NR) {
  301: 			istgt_uctl_snprintf(uctl, "ERR CHAP sequence error\n");
  302: 			goto error_return;
  303: 		}
  304: 
  305: 		chap_n = strsepq(&arg, delim);
  306: 		chap_r = strsepq(&arg, delim);
  307: 		if (chap_n == NULL || chap_r == NULL) {
  308: 			istgt_uctl_snprintf(uctl, "ERR no response\n");
  309: 			goto error_return;
  310: 		}
  311: 		//ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "N=%s, R=%s\n", chap_n, chap_r);
  312: 
  313: 		rc = istgt_hex2bin(resmd5, ISTGT_MD5DIGEST_LEN, chap_r);
  314: 		if (rc < 0 || rc != ISTGT_MD5DIGEST_LEN) {
  315: 			istgt_uctl_snprintf(uctl, "ERR response format error\n");
  316: 			goto error_return;
  317: 		}
  318: 
  319: 		rc = istgt_uctl_get_authinfo(uctl, chap_n);
  320: 		if (rc < 0) {
  321: 			ISTGT_ERRLOG("auth failed (user %.64s)\n", chap_n);
  322: 			istgt_uctl_snprintf(uctl, "ERR auth user or secret is missing\n");
  323: 			goto error_return;
  324: 		}
  325: 		if (uctl->auth.user == NULL || uctl->auth.secret == NULL) {
  326: 			ISTGT_ERRLOG("auth failed (user %.64s)\n", chap_n);
  327: 			istgt_uctl_snprintf(uctl, "ERR auth user or secret is missing\n");
  328: 			goto error_return;
  329: 		}
  330: 
  331: 		istgt_md5init(&md5ctx);
  332: 		/* Identifier */
  333: 		istgt_md5update(&md5ctx, uctl->auth.chap_id, 1);
  334: 		/* followed by secret */
  335: 		istgt_md5update(&md5ctx, uctl->auth.secret,
  336: 		    strlen(uctl->auth.secret));
  337: 		/* followed by Challenge Value */
  338: 		istgt_md5update(&md5ctx, uctl->auth.chap_challenge,
  339: 		    uctl->auth.chap_challenge_len);
  340: 		/* tgtmd5 is expecting Response Value */
  341: 		istgt_md5final(tgtmd5, &md5ctx);
  342: 
  343: 		/* compare MD5 digest */
  344: 		if (memcmp(tgtmd5, resmd5, ISTGT_MD5DIGEST_LEN) != 0) {
  345: 			/* not match */
  346: 			ISTGT_ERRLOG("auth failed (user %.64s)\n", chap_n);
  347: 			istgt_uctl_snprintf(uctl, "ERR auth user or secret is missing\n");
  348: 			goto error_return;
  349: 		}
  350: 		/* OK client's secret */
  351: 		uctl->authenticated = 1;
  352: 
  353: 		/* mutual CHAP? */
  354: 		chap_i = strsepq(&arg, delim);
  355: 		chap_c = strsepq(&arg, delim);
  356: 		if (chap_i != NULL && chap_c != NULL) {
  357: 			/* Identifier */
  358: 			uctl->auth.chap_mid[0] = (uint8_t) strtol(chap_i, NULL, 10);
  359: 			/* Challenge Value */
  360: 			rc = istgt_hex2bin(uctl->auth.chap_mchallenge,
  361: 			    ISTGT_CHAP_CHALLENGE_LEN, chap_c);
  362: 			if (rc < 0) {
  363: 				istgt_uctl_snprintf(uctl, "ERR challenge format error\n");
  364: 				goto error_return;
  365: 			}
  366: 			uctl->auth.chap_mchallenge_len = rc;
  367: 
  368: 			if (uctl->auth.muser == NULL || uctl->auth.msecret == NULL) {
  369: 				ISTGT_ERRLOG("auth failed (user %.64s)\n", chap_n);
  370: 				istgt_uctl_snprintf(uctl,
  371: 				    "ERR auth user or secret is missing\n");
  372: 				goto error_return;
  373: 			}
  374: 
  375: 			istgt_md5init(&md5ctx);
  376: 			/* Identifier */
  377: 			istgt_md5update(&md5ctx, uctl->auth.chap_mid, 1);
  378: 			/* followed by secret */
  379: 			istgt_md5update(&md5ctx, uctl->auth.msecret,
  380: 			    strlen(uctl->auth.msecret));
  381: 			/* followed by Challenge Value */
  382: 			istgt_md5update(&md5ctx, uctl->auth.chap_mchallenge,
  383: 			    uctl->auth.chap_mchallenge_len);
  384: 			/* tgtmd5 is Response Value */
  385: 			istgt_md5final(tgtmd5, &md5ctx);
  386: 
  387: 			istgt_bin2hex(uctl->work, uctl->worksize,
  388: 			    tgtmd5, ISTGT_MD5DIGEST_LEN);
  389: 
  390: 			/* send NR for mutual CHAP */
  391: 			istgt_uctl_snprintf(uctl, "%s CHAP_NR \"%s\" %s\n",
  392: 			    uctl->cmd,
  393: 			    uctl->auth.muser,
  394: 			    uctl->work);
  395: 			rc = istgt_uctl_writeline(uctl);
  396: 			if (rc != UCTL_CMD_OK) {
  397: 				return rc;
  398: 			}
  399: 		} else {
  400: 			/* not mutual */
  401: 			if (uctl->req_mutual) {
  402: 				ISTGT_ERRLOG("required mutual CHAP\n");
  403: 				istgt_uctl_snprintf(uctl, "ERR CHAP sequence error\n");
  404: 				goto error_return;
  405: 			}
  406: 		}
  407: 
  408: 		uctl->auth.chap_phase = ISTGT_CHAP_PHASE_END;
  409: 	} else {
  410: 		istgt_uctl_snprintf(uctl, "ERR CHAP sequence error\n");
  411: 		goto error_return;
  412: 	}
  413: 
  414: 	/* auth succeeded (but mutual may fail) */
  415: 	istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd);
  416: 	rc = istgt_uctl_writeline(uctl);
  417: 	if (rc != UCTL_CMD_OK) {
  418: 		return rc;
  419: 	}
  420: 	return UCTL_CMD_OK;
  421: }
  422: 
  423: static int
  424: istgt_uctl_cmd_quit(UCTL_Ptr uctl)
  425: {
  426: 	int rc;
  427: 
  428: 	istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd);
  429: 	rc = istgt_uctl_writeline(uctl);
  430: 	if (rc != UCTL_CMD_OK) {
  431: 		return rc;
  432: 	}
  433: 	return UCTL_CMD_QUIT;
  434: }
  435: 
  436: static int
  437: istgt_uctl_cmd_noop(UCTL_Ptr uctl)
  438: {
  439: 	int rc;
  440: 
  441: 	istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd);
  442: 	rc = istgt_uctl_writeline(uctl);
  443: 	if (rc != UCTL_CMD_OK) {
  444: 		return rc;
  445: 	}
  446: 	return UCTL_CMD_OK;
  447: }
  448: 
  449: static int
  450: istgt_uctl_cmd_version(UCTL_Ptr uctl)
  451: {
  452: 	int rc;
  453: 
  454: 	istgt_uctl_snprintf(uctl, "%s %s (%s)\n", uctl->cmd,
  455: 	    ISTGT_VERSION, ISTGT_EXTRA_VERSION);
  456: 	rc = istgt_uctl_writeline(uctl);
  457: 	if (rc != UCTL_CMD_OK) {
  458: 		return rc;
  459: 	}
  460: 
  461: 	/* version succeeded */
  462: 	istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd);
  463: 	rc = istgt_uctl_writeline(uctl);
  464: 	if (rc != UCTL_CMD_OK) {
  465: 		return rc;
  466: 	}
  467: 	return UCTL_CMD_OK;
  468: }
  469: 
  470: static int
  471: istgt_uctl_cmd_list(UCTL_Ptr uctl)
  472: {
  473: 	ISTGT_LU_Ptr lu;
  474: 	ISTGT_LU_LUN_Ptr llp;
  475: 	const char *delim = ARGS_DELIM;
  476: 	char *arg;
  477: 	char *iqn;
  478: 	char *lun;
  479: 	char *mflags;
  480: 	char *mfile;
  481: 	char *msize;
  482: 	char *mtype;
  483: 	char *workp;
  484: 	int lun_i;
  485: 	int worksize;
  486: 	int present;
  487: 	int lock;
  488: 	int rc;
  489: 	int i;
  490: 
  491: 	arg = uctl->arg;
  492: 	iqn = strsepq(&arg, delim);
  493: 	lun = strsepq(&arg, delim);
  494: 
  495: 	if (arg != NULL) {
  496: 		istgt_uctl_snprintf(uctl, "ERR invalid parameters\n");
  497: 		rc = istgt_uctl_writeline(uctl);
  498: 		if (rc != UCTL_CMD_OK) {
  499: 			return rc;
  500: 		}
  501: 		return UCTL_CMD_ERR;
  502: 	}
  503: 
  504: 	if (iqn == NULL) {
  505: 		/* all targets */
  506: 		MTX_LOCK(&uctl->istgt->mutex);
  507: 		for (i = 0; i < MAX_LOGICAL_UNIT; i++) {
  508: 			lu = uctl->istgt->logical_unit[i];
  509: 			if (lu == NULL)
  510: 				continue;
  511: 			istgt_uctl_snprintf(uctl, "%s %s\n", uctl->cmd, lu->name);
  512: 			rc = istgt_uctl_writeline(uctl);
  513: 			if (rc != UCTL_CMD_OK) {
  514: 				MTX_UNLOCK(&uctl->istgt->mutex);
  515: 				return rc;
  516: 			}
  517: 		}
  518: 		MTX_UNLOCK(&uctl->istgt->mutex);
  519: 	} else {
  520: 		/* specified target */
  521: 		MTX_LOCK(&uctl->istgt->mutex);
  522: 		if (lun == NULL) {
  523: 			lun_i = 0;
  524: 		} else {
  525: 			lun_i = (int) strtol(lun, NULL, 10);
  526: 		}
  527: 		lu = istgt_lu_find_target(uctl->istgt, iqn);
  528: 		if (lu == NULL) {
  529: 			MTX_UNLOCK(&uctl->istgt->mutex);
  530: 			istgt_uctl_snprintf(uctl, "ERR no target\n");
  531: 		error_return:
  532: 			rc = istgt_uctl_writeline(uctl);
  533: 			if (rc != UCTL_CMD_OK) {
  534: 				return rc;
  535: 			}
  536: 			return UCTL_CMD_ERR;
  537: 		}
  538: 		if (lun_i < 0 || lun_i >= lu->maxlun) {
  539: 			MTX_UNLOCK(&uctl->istgt->mutex);
  540: 			istgt_uctl_snprintf(uctl, "ERR no target\n");
  541: 			goto error_return;
  542: 		}
  543: 		llp = &lu->lun[lun_i];
  544: 
  545: 		worksize = uctl->worksize;
  546: 		workp = uctl->work;
  547: 
  548: 		switch (llp->type) {
  549: 		case ISTGT_LU_LUN_TYPE_REMOVABLE:
  550: 			mflags = istgt_lu_get_media_flags_string(llp->u.removable.flags,
  551: 			    workp, worksize);
  552: 			worksize -= strlen(mflags) + 1;
  553: 			workp += strlen(mflags) + 1;
  554: 			present = istgt_uctl_get_media_present(lu, lun_i);
  555: 			lock = istgt_uctl_get_media_lock(lu, lun_i);
  556: 			mfile = llp->u.removable.file;
  557: 			if (llp->u.removable.flags & ISTGT_LU_FLAG_MEDIA_AUTOSIZE) {
  558: 				snprintf(workp, worksize, "auto");
  559: 			} else {
  560: 				snprintf(workp, worksize, "%"PRIu64,
  561: 				    llp->u.removable.size);
  562: 			}
  563: 			msize = workp;
  564: 			worksize -= strlen(msize) + 1;
  565: 			workp += strlen(msize) + 1;
  566: 			snprintf(workp, worksize, "-");
  567: 			mtype = workp;
  568: 			worksize -= strlen(msize) + 1;
  569: 			workp += strlen(msize) + 1;
  570: 
  571: 			istgt_uctl_snprintf(uctl, "%s lun%u %s %s %s %s %s \"%s\" %s\n",
  572: 			    uctl->cmd, lun_i,
  573: 			    "removable",
  574: 			    (present ? "present" : "absent"),
  575: 			    (lock ? "lock" : "unlock"),
  576: 			    mtype, mflags, mfile, msize);
  577: 			rc = istgt_uctl_writeline(uctl);
  578: 			break;
  579: 		case ISTGT_LU_LUN_TYPE_STORAGE:
  580: 			mfile = llp->u.storage.file;
  581: 			snprintf(workp, worksize, "%"PRIu64,
  582: 			    llp->u.storage.size);
  583: 			msize = workp;
  584: 			worksize -= strlen(msize) + 1;
  585: 			workp += strlen(msize) + 1;
  586: 
  587: 			istgt_uctl_snprintf(uctl, "%s lun%u %s \"%s\" %s\n",
  588: 			    uctl->cmd, lun_i,
  589: 			    "storage",
  590: 			    mfile, msize);
  591: 			rc = istgt_uctl_writeline(uctl);
  592: 			break;
  593: 		case ISTGT_LU_LUN_TYPE_DEVICE:
  594: 			mfile = llp->u.device.file;
  595: 
  596: 			istgt_uctl_snprintf(uctl, "%s lun%u %s \"%s\"\n",
  597: 			    uctl->cmd, lun_i,
  598: 			    "device",
  599: 			    mfile);
  600: 			rc = istgt_uctl_writeline(uctl);
  601: 			break;
  602: 		case ISTGT_LU_LUN_TYPE_SLOT:
  603: 		default:
  604: 			MTX_UNLOCK(&uctl->istgt->mutex);
  605: 			istgt_uctl_snprintf(uctl, "ERR unsupport LUN type\n");
  606: 			goto error_return;
  607: 		}
  608: 
  609: 		if (rc != UCTL_CMD_OK) {
  610: 			MTX_UNLOCK(&uctl->istgt->mutex);
  611: 			return rc;
  612: 		}
  613: 		MTX_UNLOCK(&uctl->istgt->mutex);
  614: 	}
  615: 
  616: 	/* list succeeded */
  617: 	istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd);
  618: 	rc = istgt_uctl_writeline(uctl);
  619: 	if (rc != UCTL_CMD_OK) {
  620: 		return rc;
  621: 	}
  622: 	return UCTL_CMD_OK;
  623: }
  624: 
  625: static int
  626: istgt_uctl_cmd_unload(UCTL_Ptr uctl)
  627: {
  628: 	ISTGT_LU_Ptr lu;
  629: 	ISTGT_LU_LUN_Ptr llp;
  630: 	const char *delim = ARGS_DELIM;
  631: 	char *arg;
  632: 	char *iqn;
  633: 	char *lun;
  634: 	int lun_i;
  635: 	int rc;
  636: 
  637: 	arg = uctl->arg;
  638: 	iqn = strsepq(&arg, delim);
  639: 	lun = strsepq(&arg, delim);
  640: 
  641: 	if (iqn == NULL || arg != NULL) {
  642: 		istgt_uctl_snprintf(uctl, "ERR invalid parameters\n");
  643: 		rc = istgt_uctl_writeline(uctl);
  644: 		if (rc != UCTL_CMD_OK) {
  645: 			return rc;
  646: 		}
  647: 		return UCTL_CMD_ERR;
  648: 	}
  649: 
  650: 	if (lun == NULL) {
  651: 		lun_i = 0;
  652: 	} else {
  653: 		lun_i = (int) strtol(lun, NULL, 10);
  654: 	}
  655: 	lu = istgt_lu_find_target(uctl->istgt, iqn);
  656: 	if (lu == NULL) {
  657: 		istgt_uctl_snprintf(uctl, "ERR no target\n");
  658: 	error_return:
  659: 		rc = istgt_uctl_writeline(uctl);
  660: 		if (rc != UCTL_CMD_OK) {
  661: 			return rc;
  662: 		}
  663: 		return UCTL_CMD_ERR;
  664: 	}
  665: 	if (lun_i < 0 || lun_i >= lu->maxlun) {
  666: 		istgt_uctl_snprintf(uctl, "ERR no target\n");
  667: 		goto error_return;
  668: 	}
  669: 	llp = &lu->lun[lun_i];
  670: 	if (llp->type != ISTGT_LU_LUN_TYPE_REMOVABLE) {
  671: 		istgt_uctl_snprintf(uctl, "ERR not removable\n");
  672: 		goto error_return;
  673: 	}
  674: 
  675: 	/* unload media from lun */
  676: 	switch (lu->type) {
  677: 	case ISTGT_LU_TYPE_DVD:
  678: 		MTX_LOCK(&lu->mutex);
  679: 		rc = istgt_lu_dvd_unload_media(lu->lun[lun_i].spec);
  680: 		MTX_UNLOCK(&lu->mutex);
  681: 		break;
  682: 	case ISTGT_LU_TYPE_TAPE:
  683: 		MTX_LOCK(&lu->mutex);
  684: 		rc = istgt_lu_tape_unload_media(lu->lun[lun_i].spec);
  685: 		MTX_UNLOCK(&lu->mutex);
  686: 		break;
  687: 	default:
  688: 		rc = -1;
  689: 	}
  690: 
  691: 	if (rc < 0) {
  692: 		istgt_uctl_snprintf(uctl, "ERR unload\n");
  693: 		rc = istgt_uctl_writeline(uctl);
  694: 		if (rc != UCTL_CMD_OK) {
  695: 			return rc;
  696: 		}
  697: 		return UCTL_CMD_ERR;
  698: 	}
  699: 
  700: 	/* logging event */
  701: 	ISTGT_NOTICELOG("Media Unload %s lun%d from %s\n",
  702: 	    iqn, lun_i, uctl->caddr);
  703: 
  704: 	/* unload succeeded */
  705: 	istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd);
  706: 	rc = istgt_uctl_writeline(uctl);
  707: 	if (rc != UCTL_CMD_OK) {
  708: 		return rc;
  709: 	}
  710: 	return UCTL_CMD_OK;
  711: }
  712: 
  713: static int
  714: istgt_uctl_cmd_load(UCTL_Ptr uctl)
  715: {
  716: 	ISTGT_LU_Ptr lu;
  717: 	ISTGT_LU_LUN_Ptr llp;
  718: 	const char *delim = ARGS_DELIM;
  719: 	char *arg;
  720: 	char *iqn;
  721: 	char *lun;
  722: 	int lun_i;
  723: 	int rc;
  724: 
  725: 	arg = uctl->arg;
  726: 	iqn = strsepq(&arg, delim);
  727: 	lun = strsepq(&arg, delim);
  728: 
  729: 	if (iqn == NULL || arg != NULL) {
  730: 		istgt_uctl_snprintf(uctl, "ERR invalid parameters\n");
  731: 		rc = istgt_uctl_writeline(uctl);
  732: 		if (rc != UCTL_CMD_OK) {
  733: 			return rc;
  734: 		}
  735: 		return UCTL_CMD_ERR;
  736: 	}
  737: 
  738: 	if (lun == NULL) {
  739: 		lun_i = 0;
  740: 	} else {
  741: 		lun_i = (int) strtol(lun, NULL, 10);
  742: 	}
  743: 	lu = istgt_lu_find_target(uctl->istgt, iqn);
  744: 	if (lu == NULL) {
  745: 		istgt_uctl_snprintf(uctl, "ERR no target\n");
  746: 	error_return:
  747: 		rc = istgt_uctl_writeline(uctl);
  748: 		if (rc != UCTL_CMD_OK) {
  749: 			return rc;
  750: 		}
  751: 		return UCTL_CMD_ERR;
  752: 	}
  753: 	if (lun_i < 0 || lun_i >= lu->maxlun) {
  754: 		istgt_uctl_snprintf(uctl, "ERR no target\n");
  755: 		goto error_return;
  756: 	}
  757: 	llp = &lu->lun[lun_i];
  758: 	if (llp->type != ISTGT_LU_LUN_TYPE_REMOVABLE) {
  759: 		istgt_uctl_snprintf(uctl, "ERR not removable\n");
  760: 		goto error_return;
  761: 	}
  762: 
  763: 	/* load media to lun */
  764: 	switch (lu->type) {
  765: 	case ISTGT_LU_TYPE_DVD:
  766: 		MTX_LOCK(&lu->mutex);
  767: 		rc = istgt_lu_dvd_load_media(lu->lun[lun_i].spec);
  768: 		MTX_UNLOCK(&lu->mutex);
  769: 		break;
  770: 	case ISTGT_LU_TYPE_TAPE:
  771: 		MTX_LOCK(&lu->mutex);
  772: 		rc = istgt_lu_tape_load_media(lu->lun[lun_i].spec);
  773: 		MTX_UNLOCK(&lu->mutex);
  774: 		break;
  775: 	default:
  776: 		rc = -1;
  777: 	}
  778: 
  779: 	if (rc < 0) {
  780: 		istgt_uctl_snprintf(uctl, "ERR load\n");
  781: 		rc = istgt_uctl_writeline(uctl);
  782: 		if (rc != UCTL_CMD_OK) {
  783: 			return rc;
  784: 		}
  785: 		return UCTL_CMD_ERR;
  786: 	}
  787: 
  788: 	/* logging event */
  789: 	ISTGT_NOTICELOG("Media Load %s lun%d from %s\n",
  790: 	    iqn, lun_i, uctl->caddr);
  791: 
  792: 	/* load succeeded */
  793: 	istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd);
  794: 	rc = istgt_uctl_writeline(uctl);
  795: 	if (rc != UCTL_CMD_OK) {
  796: 		return rc;
  797: 	}
  798: 	return UCTL_CMD_OK;
  799: }
  800: 
  801: static int
  802: istgt_uctl_cmd_change(UCTL_Ptr uctl)
  803: {
  804: 	ISTGT_LU_Ptr lu;
  805: 	ISTGT_LU_LUN_Ptr llp;
  806: 	const char *delim = ARGS_DELIM;
  807: 	char empty_flags[] = "ro";
  808: 	char empty_size[] = "0";
  809: 	char *arg;
  810: 	char *iqn;
  811: 	char *lun;
  812: 	char *type;
  813: 	char *flags;
  814: 	char *file;
  815: 	char *size;
  816: 	char *safedir;
  817: 	char *fullpath;
  818: 	char *abspath;
  819: 	int lun_i;
  820: 	int len;
  821: 	int rc;
  822: 
  823: 	arg = uctl->arg;
  824: 	iqn = strsepq(&arg, delim);
  825: 	lun = strsepq(&arg, delim);
  826: 
  827: 	type = strsepq(&arg, delim);
  828: 	flags = strsepq(&arg, delim);
  829: 	file = strsepq(&arg, delim);
  830: 	size = strsepq(&arg, delim);
  831: 
  832: 	if (iqn == NULL || lun == NULL || type == NULL || flags == NULL
  833: 	    || file == NULL || size == NULL || arg != NULL) {
  834: 		istgt_uctl_snprintf(uctl, "ERR invalid parameters\n");
  835: 		rc = istgt_uctl_writeline(uctl);
  836: 		if (rc != UCTL_CMD_OK) {
  837: 			return rc;
  838: 		}
  839: 		return UCTL_CMD_ERR;
  840: 	}
  841: 
  842: 	if (lun == NULL) {
  843: 		lun_i = 0;
  844: 	} else {
  845: 		lun_i = (int) strtol(lun, NULL, 10);
  846: 	}
  847: 	lu = istgt_lu_find_target(uctl->istgt, iqn);
  848: 	if (lu == NULL) {
  849: 		istgt_uctl_snprintf(uctl, "ERR no target\n");
  850: 	error_return:
  851: 		rc = istgt_uctl_writeline(uctl);
  852: 		if (rc != UCTL_CMD_OK) {
  853: 			return rc;
  854: 		}
  855: 		return UCTL_CMD_ERR;
  856: 	}
  857: 	if (lun_i < 0 || lun_i >= lu->maxlun) {
  858: 		istgt_uctl_snprintf(uctl, "ERR no target\n");
  859: 		goto error_return;
  860: 	}
  861: 	llp = &lu->lun[lun_i];
  862: 	if (llp->type != ISTGT_LU_LUN_TYPE_REMOVABLE) {
  863: 		istgt_uctl_snprintf(uctl, "ERR not removable\n");
  864: 		goto error_return;
  865: 	}
  866: 
  867: 	/* make safe directory (start '/', end '/') */
  868: 	len = 1 + strlen(uctl->mediadirectory) + 1 + 1;
  869: 	safedir = xmalloc(len);
  870: 	if (uctl->mediadirectory[0] != '/') {
  871: 		ISTGT_WARNLOG("MediaDirectory is not starting with '/'\n");
  872: 		snprintf(safedir, len, "/%s", uctl->mediadirectory);
  873: 	} else {
  874: 		snprintf(safedir, len, "%s", uctl->mediadirectory);
  875: 	}
  876: 	if (strlen(safedir) > 1 && safedir[strlen(safedir) - 1] != '/') {
  877: 		safedir[strlen(safedir) + 1] = '\0';
  878: 		safedir[strlen(safedir)] = '/';
  879: 	}
  880: 
  881: 	/* check abspath in mediadirectory? */
  882: 	len = strlen(safedir) + strlen(file) + 1;
  883: 	fullpath = xmalloc(len);
  884: 	if (file[0] != '/') {
  885: 		snprintf(fullpath, len, "%s%s", safedir, file);
  886: 	} else {
  887: 		snprintf(fullpath, len, "%s", file);
  888: 	}
  889: #ifdef PATH_MAX
  890: 	abspath = xmalloc(len + PATH_MAX);
  891: 	file = realpath(fullpath, abspath);
  892: #else
  893: /*
  894: 	{
  895: 		long path_max;
  896: 		path_max = pathconf(fullpath, _PC_PATH_MAX);
  897: 		if (path_max != -1L) {
  898: 			abspath = xmalloc(path_max);
  899: 			file = realpath(fullpath, abspath);
  900: 		}
  901: 	}
  902: */
  903: 	file = abspath = realpath(fullpath, NULL);
  904: #endif /* PATH_MAX */
  905: 	if (file == NULL) {
  906: 		ISTGT_ERRLOG("realpath(%s) failed\n", fullpath);
  907: 	internal_error:
  908: 		xfree(safedir);
  909: 		xfree(fullpath);
  910: 		xfree(abspath);
  911: 		istgt_uctl_snprintf(uctl, "ERR %s internal error\n", uctl->cmd);
  912: 		rc = istgt_uctl_writeline(uctl);
  913: 		if (rc != UCTL_CMD_OK) {
  914: 			return rc;
  915: 		}
  916: 		return UCTL_CMD_ERR;
  917: 	}
  918: 	if (strcasecmp(file, "/dev/null") == 0) {
  919: 		/* OK, empty slot */
  920: 		flags = empty_flags;
  921: 		size = empty_size;
  922: 	} else if (strncasecmp(file, safedir, strlen(safedir)) != 0) {
  923: 		ISTGT_ERRLOG("Realpath(%s) is not within MediaDirectory(%s)\n",
  924: 		    file, safedir);
  925: 		goto internal_error;
  926: 	}
  927: 
  928: 	/* unload and load media from lun */
  929: 	switch (lu->type) {
  930: 	case ISTGT_LU_TYPE_DVD:
  931: 		MTX_LOCK(&lu->mutex);
  932: 		rc = istgt_lu_dvd_change_media(lu->lun[lun_i].spec,
  933: 		    type, flags, file, size);
  934: 		MTX_UNLOCK(&lu->mutex);
  935: 		break;
  936: 	case ISTGT_LU_TYPE_TAPE:
  937: 		MTX_LOCK(&lu->mutex);
  938: 		rc = istgt_lu_tape_change_media(lu->lun[lun_i].spec,
  939: 		    type, flags, file, size);
  940: 		MTX_UNLOCK(&lu->mutex);
  941: 		break;
  942: 	default:
  943: 		rc = -1;
  944: 	}
  945: 
  946: 	if (rc < 0) {
  947: 		xfree(safedir);
  948: 		xfree(fullpath);
  949: 		xfree(abspath);
  950: 		istgt_uctl_snprintf(uctl, "ERR change\n");
  951: 		rc = istgt_uctl_writeline(uctl);
  952: 		if (rc != UCTL_CMD_OK) {
  953: 			return rc;
  954: 		}
  955: 		return UCTL_CMD_ERR;
  956: 	}
  957: 
  958: 	/* logging event */
  959: 	ISTGT_NOTICELOG("Media Change \"%s %s %s %s\" on %s lun%d from %s\n",
  960: 	    type, flags, file, size, iqn, lun_i, uctl->caddr);
  961: 
  962: 	xfree(safedir);
  963: 	xfree(fullpath);
  964: 	xfree(abspath);
  965: 
  966: 	/* change succeeded */
  967: 	istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd);
  968: 	rc = istgt_uctl_writeline(uctl);
  969: 	if (rc != UCTL_CMD_OK) {
  970: 		return rc;
  971: 	}
  972: 	return UCTL_CMD_OK;
  973: }
  974: 
  975: static int
  976: istgt_uctl_cmd_reset(UCTL_Ptr uctl)
  977: {
  978: 	ISTGT_LU_Ptr lu;
  979: 	ISTGT_LU_LUN_Ptr llp;
  980: 	const char *delim = ARGS_DELIM;
  981: 	char *arg;
  982: 	char *iqn;
  983: 	char *lun;
  984: 	int lun_i;
  985: 	int rc;
  986: 
  987: 	arg = uctl->arg;
  988: 	iqn = strsepq(&arg, delim);
  989: 	lun = strsepq(&arg, delim);
  990: 
  991: 	if (iqn == NULL || arg != NULL) {
  992: 		istgt_uctl_snprintf(uctl, "ERR invalid parameters\n");
  993: 		rc = istgt_uctl_writeline(uctl);
  994: 		if (rc != UCTL_CMD_OK) {
  995: 			return rc;
  996: 		}
  997: 		return UCTL_CMD_ERR;
  998: 	}
  999: 
 1000: 	if (lun == NULL) {
 1001: 		lun_i = 0;
 1002: 	} else {
 1003: 		lun_i = (int) strtol(lun, NULL, 10);
 1004: 	}
 1005: 	lu = istgt_lu_find_target(uctl->istgt, iqn);
 1006: 	if (lu == NULL) {
 1007: 		istgt_uctl_snprintf(uctl, "ERR no target\n");
 1008: 	error_return:
 1009: 		rc = istgt_uctl_writeline(uctl);
 1010: 		if (rc != UCTL_CMD_OK) {
 1011: 			return rc;
 1012: 		}
 1013: 		return UCTL_CMD_ERR;
 1014: 	}
 1015: 	if (lun_i < 0 || lun_i >= lu->maxlun) {
 1016: 		istgt_uctl_snprintf(uctl, "ERR no target\n");
 1017: 		goto error_return;
 1018: 	}
 1019: 	llp = &lu->lun[lun_i];
 1020: 	if (llp->type == ISTGT_LU_LUN_TYPE_NONE) {
 1021: 		istgt_uctl_snprintf(uctl, "ERR no LUN\n");
 1022: 		goto error_return;
 1023: 	}
 1024: 
 1025: 	/* reset lun */
 1026: 	switch (lu->type) {
 1027: 	case ISTGT_LU_TYPE_DISK:
 1028: 		MTX_LOCK(&lu->mutex);
 1029: 		rc = istgt_lu_disk_reset(lu, lun_i);
 1030: 		MTX_UNLOCK(&lu->mutex);
 1031: 		break;
 1032: 	case ISTGT_LU_TYPE_DVD:
 1033: 		MTX_LOCK(&lu->mutex);
 1034: 		rc = istgt_lu_dvd_reset(lu, lun_i);
 1035: 		MTX_UNLOCK(&lu->mutex);
 1036: 		break;
 1037: 	case ISTGT_LU_TYPE_TAPE:
 1038: 		MTX_LOCK(&lu->mutex);
 1039: 		rc = istgt_lu_tape_reset(lu, lun_i);
 1040: 		MTX_UNLOCK(&lu->mutex);
 1041: 		break;
 1042: 	case ISTGT_LU_TYPE_NONE:
 1043: 	case ISTGT_LU_TYPE_PASS:
 1044: 		rc = -1;
 1045: 		break;
 1046: 	default:
 1047: 		rc = -1;
 1048: 	}
 1049: 
 1050: 	if (rc < 0) {
 1051: 		istgt_uctl_snprintf(uctl, "ERR reset\n");
 1052: 		rc = istgt_uctl_writeline(uctl);
 1053: 		if (rc != UCTL_CMD_OK) {
 1054: 			return rc;
 1055: 		}
 1056: 		return UCTL_CMD_ERR;
 1057: 	}
 1058: 
 1059: 	/* logging event */
 1060: 	ISTGT_NOTICELOG("Unit Reset %s lun%d from %s\n",
 1061: 	    iqn, lun_i, uctl->caddr);
 1062: 
 1063: 	/* reset succeeded */
 1064: 	istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd);
 1065: 	rc = istgt_uctl_writeline(uctl);
 1066: 	if (rc != UCTL_CMD_OK) {
 1067: 		return rc;
 1068: 	}
 1069: 	return UCTL_CMD_OK;
 1070: }
 1071: 
 1072: static int
 1073: istgt_uctl_cmd_info(UCTL_Ptr uctl)
 1074: {
 1075: 	ISTGT_LU_Ptr lu;
 1076: 	CONN_Ptr conn;
 1077: 	SESS_Ptr sess;
 1078: 	const char *delim = ARGS_DELIM;
 1079: 	char *arg;
 1080: 	char *iqn;
 1081: 	int ncount;
 1082: 	int rc;
 1083: 	int i, j, k;
 1084: 
 1085: 	arg = uctl->arg;
 1086: 	iqn = strsepq(&arg, delim);
 1087: 
 1088: 	if (arg != NULL) {
 1089: 		istgt_uctl_snprintf(uctl, "ERR invalid parameters\n");
 1090: 		rc = istgt_uctl_writeline(uctl);
 1091: 		if (rc != UCTL_CMD_OK) {
 1092: 			return rc;
 1093: 		}
 1094: 		return UCTL_CMD_ERR;
 1095: 	}
 1096: 
 1097: 	ncount = 0;
 1098: 	MTX_LOCK(&uctl->istgt->mutex);
 1099: 	for (i = 0; i < MAX_LOGICAL_UNIT; i++) {
 1100: 		lu = uctl->istgt->logical_unit[i];
 1101: 		if (lu == NULL)
 1102: 			continue;
 1103: 		if (iqn != NULL && strcasecmp(iqn, lu->name) != 0)
 1104: 			continue;
 1105: 
 1106: 		istgt_lock_gconns();
 1107: 		MTX_LOCK(&lu->mutex);
 1108: 		for (j = 1; j < MAX_LU_TSIH; j++) {
 1109: 			if (lu->tsih[j].initiator_port != NULL
 1110: 				&& lu->tsih[j].tsih != 0) {
 1111: 				conn = istgt_find_conn(lu->tsih[j].initiator_port,
 1112: 				    lu->name, lu->tsih[j].tsih);
 1113: 				if (conn == NULL || conn->sess == NULL)
 1114: 					continue;
 1115: 
 1116: 				sess = conn->sess;
 1117: 				MTX_LOCK(&sess->mutex);
 1118: 				for (k = 0; k < sess->connections; k++) {
 1119: 					conn = sess->conns[k];
 1120: 					if (conn == NULL)
 1121: 						continue;
 1122: 
 1123: 					istgt_uctl_snprintf(uctl, "%s Login from %s (%s) on %s LU%d"
 1124: 					    " (%s:%s,%d), ISID=%"PRIx64", TSIH=%u,"
 1125: 					    " CID=%u, HeaderDigest=%s, DataDigest=%s,"
 1126: 					    " MaxConnections=%u,"
 1127: 					    " FirstBurstLength=%u, MaxBurstLength=%u,"
 1128: 					    " MaxRecvDataSegmentLength=%u,"
 1129: 					    " InitialR2T=%s, ImmediateData=%s\n",
 1130: 					    uctl->cmd,
 1131: 					    conn->initiator_name,
 1132: 					    conn->initiator_addr,
 1133: 					    conn->target_name, lu->num,
 1134: 					    conn->portal.host, conn->portal.port,
 1135: 					    conn->portal.tag,
 1136: 					    conn->sess->isid, conn->sess->tsih,
 1137: 					    conn->cid,
 1138: 					    (conn->header_digest ? "on" : "off"),
 1139: 					    (conn->data_digest ? "on" : "off"),
 1140: 					    conn->sess->MaxConnections,
 1141: 					    conn->sess->FirstBurstLength,
 1142: 					    conn->sess->MaxBurstLength,
 1143: 					    conn->MaxRecvDataSegmentLength,
 1144: 					    (conn->sess->initial_r2t ? "Yes" : "No"),
 1145: 					    (conn->sess->immediate_data ? "Yes" : "No"));
 1146: 					rc = istgt_uctl_writeline(uctl);
 1147: 					if (rc != UCTL_CMD_OK) {
 1148: 						MTX_UNLOCK(&sess->mutex);
 1149: 						MTX_UNLOCK(&lu->mutex);
 1150: 						istgt_unlock_gconns();
 1151: 						MTX_UNLOCK(&uctl->istgt->mutex);
 1152: 						return rc;
 1153: 					}
 1154: 					ncount++;
 1155: 				}
 1156: 				MTX_UNLOCK(&sess->mutex);
 1157: 			}
 1158: 		}
 1159: 		MTX_UNLOCK(&lu->mutex);
 1160: 		istgt_unlock_gconns();
 1161: 	}
 1162: 	MTX_UNLOCK(&uctl->istgt->mutex);
 1163: 	if (ncount == 0) {
 1164: 		istgt_uctl_snprintf(uctl, "%s no login\n", uctl->cmd);
 1165: 		rc = istgt_uctl_writeline(uctl);
 1166: 		if (rc != UCTL_CMD_OK) {
 1167: 			return rc;
 1168: 		}
 1169: 	}
 1170: 
 1171: 	/* info succeeded */
 1172: 	istgt_uctl_snprintf(uctl, "OK %s\n", uctl->cmd);
 1173: 	rc = istgt_uctl_writeline(uctl);
 1174: 	if (rc != UCTL_CMD_OK) {
 1175: 		return rc;
 1176: 	}
 1177: 	return UCTL_CMD_OK;
 1178: }
 1179: 
 1180: 
 1181: typedef struct istgt_uctl_cmd_table_t
 1182: {
 1183: 	const char *name;
 1184: 	int (*func) (UCTL_Ptr uctl);
 1185: } ISTGT_UCTL_CMD_TABLE;
 1186: 
 1187: static ISTGT_UCTL_CMD_TABLE istgt_uctl_cmd_table[] = 
 1188: {
 1189: 	{ "AUTH",    istgt_uctl_cmd_auth },
 1190: 	{ "QUIT",    istgt_uctl_cmd_quit },
 1191: 	{ "NOOP",    istgt_uctl_cmd_noop },
 1192: 	{ "VERSION", istgt_uctl_cmd_version },
 1193: 	{ "LIST",    istgt_uctl_cmd_list },
 1194: 	{ "UNLOAD",  istgt_uctl_cmd_unload },
 1195: 	{ "LOAD",    istgt_uctl_cmd_load },
 1196: 	{ "CHANGE",  istgt_uctl_cmd_change },
 1197: 	{ "RESET",   istgt_uctl_cmd_reset },
 1198: 	{ "INFO",    istgt_uctl_cmd_info },
 1199: 	{ NULL,      NULL },
 1200: };
 1201: 
 1202: static int
 1203: istgt_uctl_cmd_execute(UCTL_Ptr uctl)
 1204: {
 1205: 	int (*func) (UCTL_Ptr);
 1206: 	const char *delim = ARGS_DELIM;
 1207: 	char *arg;
 1208: 	char *cmd;
 1209: 	int rc;
 1210: 	int i;
 1211: 
 1212: 	arg = trim_string(uctl->recvbuf);
 1213: 	cmd = strsepq(&arg, delim);
 1214: 	uctl->arg = arg;
 1215: 	uctl->cmd = strupr(cmd);
 1216: 
 1217: 	func = NULL;
 1218: 	for (i = 0; istgt_uctl_cmd_table[i].name != NULL; i++) {
 1219: 		if (cmd[0] == istgt_uctl_cmd_table[i].name[0]
 1220: 		    && strcmp(cmd, istgt_uctl_cmd_table[i].name) == 0) {
 1221: 			func = istgt_uctl_cmd_table[i].func;
 1222: 			break;
 1223: 		}
 1224: 	}
 1225: 	if (func == NULL) {
 1226: 		istgt_uctl_snprintf(uctl, "ERR unknown command\n");
 1227: 		rc = istgt_uctl_writeline(uctl);
 1228: 		if (rc != UCTL_CMD_OK) {
 1229: 			return UCTL_CMD_DISCON;
 1230: 		}
 1231: 		return UCTL_CMD_ERR;
 1232: 	}
 1233: 
 1234: 	if (uctl->no_auth
 1235: 	    && (strcasecmp(cmd, "AUTH") == 0)) {
 1236: 		istgt_uctl_snprintf(uctl, "ERR auth not required\n");
 1237: 		rc = istgt_uctl_writeline(uctl);
 1238: 		if (rc != UCTL_CMD_OK) {
 1239: 			return UCTL_CMD_DISCON;
 1240: 		}
 1241: 		return UCTL_CMD_ERR;
 1242: 	}
 1243: 	if (uctl->req_auth && uctl->authenticated == 0
 1244: 	    && !(strcasecmp(cmd, "QUIT") == 0
 1245: 		|| strcasecmp(cmd, "AUTH") == 0)) {
 1246: 		istgt_uctl_snprintf(uctl, "ERR auth required\n");
 1247: 		rc = istgt_uctl_writeline(uctl);
 1248: 		if (rc != UCTL_CMD_OK) {
 1249: 			return UCTL_CMD_DISCON;
 1250: 		}
 1251: 		return UCTL_CMD_ERR;
 1252: 	}
 1253: 
 1254: 	rc = func(uctl);
 1255: 	return rc;
 1256: }
 1257: 
 1258: static void istgt_free_uctl(UCTL_Ptr uctl);
 1259: 
 1260: static void *
 1261: uctlworker(void *arg)
 1262: {
 1263: 	UCTL_Ptr uctl = (UCTL_Ptr) arg;
 1264: 	int rc;
 1265: 
 1266: 	ISTGT_TRACELOG(ISTGT_TRACE_NET, "connect to %s:%s,%d\n",
 1267: 	    uctl->portal.host, uctl->portal.port, uctl->portal.tag);
 1268: 
 1269: 	istgt_uctl_snprintf(uctl, "iSCSI Target Controller version %s (%s)"
 1270: 	    " on %s from %s\n",
 1271: 	    ISTGT_VERSION, ISTGT_EXTRA_VERSION,
 1272: 	    uctl->saddr, uctl->caddr);
 1273: 	rc = istgt_uctl_writeline(uctl);
 1274: 	if (rc != UCTL_CMD_OK) {
 1275: 		ISTGT_ERRLOG("uctl_writeline() failed\n");
 1276: 		return NULL;
 1277: 	}
 1278: 
 1279: 	while (1) {
 1280: 		if (istgt_get_state(uctl->istgt) != ISTGT_STATE_RUNNING) {
 1281: 			break;
 1282: 		}
 1283: 
 1284: 		/* read from socket */
 1285: 		rc = istgt_uctl_readline(uctl);
 1286: 		if (rc == UCTL_CMD_EOF) {
 1287: 			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "uctl_readline() EOF\n");
 1288: 			break;
 1289: 		}
 1290: 		if (rc != UCTL_CMD_OK) {
 1291: 			ISTGT_ERRLOG("uctl_readline() failed\n");
 1292: 			break;
 1293: 		}
 1294: 		/* execute command */
 1295: 		rc = istgt_uctl_cmd_execute(uctl);
 1296: 		if (rc == UCTL_CMD_QUIT) {
 1297: 			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "receive QUIT\n");
 1298: 			break;
 1299: 		}
 1300: 		if (rc == UCTL_CMD_DISCON) {
 1301: 			ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "request disconnect\n");
 1302: 			break;
 1303: 		}
 1304: 	}
 1305: 
 1306: 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "exiting ctlworker\n");
 1307: 
 1308: 	close(uctl->sock);
 1309: 	uctl->sock = -1;
 1310: 	istgt_free_uctl(uctl);
 1311: 	return NULL;
 1312: }
 1313: 
 1314: static void
 1315: istgt_free_uctl(UCTL_Ptr uctl)
 1316: {
 1317: 	if (uctl == NULL)
 1318: 		return;
 1319: 	xfree(uctl->mediadirectory);
 1320: 	xfree(uctl->portal.label);
 1321: 	xfree(uctl->portal.host);
 1322: 	xfree(uctl->portal.port);
 1323: 	xfree(uctl->auth.user);
 1324: 	xfree(uctl->auth.secret);
 1325: 	xfree(uctl->auth.muser);
 1326: 	xfree(uctl->auth.msecret);
 1327: 	xfree(uctl);
 1328: }
 1329: 
 1330: int
 1331: istgt_create_uctl(ISTGT_Ptr istgt, PORTAL_Ptr portal, int sock, struct sockaddr *sa, socklen_t salen __attribute__((__unused__)))
 1332: {
 1333: 	char buf[MAX_TMPBUF];
 1334: 	UCTL_Ptr uctl;
 1335: 	int rc;
 1336: 	int i;
 1337: 
 1338: 	uctl = xmalloc(sizeof *uctl);
 1339: 	memset(uctl, 0, sizeof *uctl);
 1340: 
 1341: 	uctl->istgt = istgt;
 1342: 	MTX_LOCK(&istgt->mutex);
 1343: 	uctl->auth_group = istgt->uctl_auth_group;
 1344: 	uctl->no_auth = istgt->no_uctl_auth;
 1345: 	uctl->req_auth = istgt->req_uctl_auth;
 1346: 	uctl->req_mutual = istgt->req_uctl_auth_mutual;
 1347: 	uctl->mediadirectory = xstrdup(istgt->mediadirectory);
 1348: 	MTX_UNLOCK(&istgt->mutex);
 1349: 
 1350: 	uctl->portal.label = xstrdup(portal->label);
 1351: 	uctl->portal.host = xstrdup(portal->host);
 1352: 	uctl->portal.port = xstrdup(portal->port);
 1353: 	uctl->portal.tag = portal->tag;
 1354: 	uctl->portal.sock = -1;
 1355: 	uctl->sock = sock;
 1356: 
 1357: 	uctl->timeout = TIMEOUT_RW;
 1358: 	uctl->auth.chap_phase = ISTGT_CHAP_PHASE_WAIT_A;
 1359: 	uctl->auth.user = NULL;
 1360: 	uctl->auth.secret = NULL;
 1361: 	uctl->auth.muser = NULL;
 1362: 	uctl->auth.msecret = NULL;
 1363: 	uctl->authenticated = 0;
 1364: 
 1365: 	uctl->recvtmpcnt = 0;
 1366: 	uctl->recvtmpidx = 0;
 1367: 	uctl->recvtmpsize = sizeof uctl->recvtmp;
 1368: 	uctl->recvbufsize = sizeof uctl->recvbuf;
 1369: 	uctl->sendbufsize = sizeof uctl->sendbuf;
 1370: 	uctl->worksize = sizeof uctl->work;
 1371: 
 1372: 	memset(uctl->caddr, 0, sizeof uctl->caddr);
 1373: 	memset(uctl->saddr, 0, sizeof uctl->saddr);
 1374: 
 1375: 	switch (sa->sa_family) {
 1376: 	case AF_INET6:
 1377: 		uctl->family = AF_INET6;
 1378: 		rc = istgt_getaddr(sock, uctl->saddr, sizeof uctl->saddr,
 1379: 		    uctl->caddr, sizeof uctl->caddr);
 1380: 		if (rc < 0) {
 1381: 			ISTGT_ERRLOG("istgt_getaddr() failed\n");
 1382: 			goto error_return;
 1383: 		}
 1384: 		break;
 1385: 	case AF_INET:
 1386: 		uctl->family = AF_INET;
 1387: 		rc = istgt_getaddr(sock, uctl->saddr, sizeof uctl->saddr,
 1388: 		    uctl->caddr, sizeof uctl->caddr);
 1389: 		if (rc < 0) {
 1390: 			ISTGT_ERRLOG("istgt_getaddr() failed\n");
 1391: 			goto error_return;
 1392: 		}
 1393: 		break;
 1394: 	default:
 1395: 		ISTGT_ERRLOG("unsupported family\n");
 1396: 		goto error_return;
 1397: 	}
 1398: 
 1399: 	if (istgt->nuctl_netmasks != 0) {
 1400: 		rc = -1;
 1401: 		for (i = 0; i < istgt->nuctl_netmasks; i++) {
 1402: 			rc = istgt_lu_allow_netmask(istgt->uctl_netmasks[i], uctl->caddr);
 1403: 			if (rc > 0) {
 1404: 				/* OK netmask */
 1405: 				break;
 1406: 			}
 1407: 		}
 1408: 		if (rc <= 0) {
 1409: 			ISTGT_WARNLOG("UCTL access denied from %s to (%s:%s)\n",
 1410: 			    uctl->caddr, uctl->portal.host, uctl->portal.port);
 1411: 			goto error_return;
 1412: 		}
 1413: 	}
 1414: 
 1415: 	printf("sock=%d, addr=%s, peer=%s\n",
 1416: 	    sock, uctl->saddr,
 1417: 	    uctl->caddr);
 1418: 
 1419: 	/* wildcard? */
 1420: 	if (strcasecmp(uctl->portal.host, "[::]") == 0
 1421: 	    || strcasecmp(uctl->portal.host, "[*]") == 0) {
 1422: 		if (uctl->family != AF_INET6) {
 1423: 			ISTGT_ERRLOG("address family error\n");
 1424: 			goto error_return;
 1425: 		}
 1426: 		snprintf(buf, sizeof buf, "[%s]", uctl->caddr);
 1427: 		xfree(uctl->portal.host);
 1428: 		uctl->portal.host = xstrdup(buf);
 1429: 	} else if (strcasecmp(uctl->portal.host, "0.0.0.0") == 0
 1430: 	    || strcasecmp(uctl->portal.host, "*") == 0) {
 1431: 		if (uctl->family != AF_INET) {
 1432: 			ISTGT_ERRLOG("address family error\n");
 1433: 			goto error_return;
 1434: 		}
 1435: 		snprintf(buf, sizeof buf, "%s", uctl->caddr);
 1436: 		xfree(uctl->portal.host);
 1437: 		uctl->portal.host = xstrdup(buf);
 1438: 	}
 1439: 
 1440: 	/* set timeout msec. */
 1441: 	rc = istgt_set_recvtimeout(uctl->sock, uctl->timeout * 1000);
 1442: 	if (rc != 0) {
 1443: 		ISTGT_ERRLOG("istgt_set_recvtimeo() failed\n");
 1444: 		goto error_return;
 1445: 	}
 1446: 	rc = istgt_set_sendtimeout(uctl->sock, uctl->timeout * 1000);
 1447: 	if (rc != 0) {
 1448: 		ISTGT_ERRLOG("istgt_set_sendtimeo() failed\n");
 1449: 		goto error_return;
 1450: 	}
 1451: 
 1452: 	/* create new thread */
 1453: #ifdef ISTGT_STACKSIZE
 1454: 	rc = pthread_create(&uctl->thread, &istgt->attr, &uctlworker, (void *)uctl);
 1455: #else
 1456: 	rc = pthread_create(&uctl->thread, NULL, &uctlworker, (void *)uctl);
 1457: #endif
 1458: 	if (rc != 0) {
 1459: 		ISTGT_ERRLOG("pthread_create() failed\n");
 1460: 	error_return:
 1461: 		xfree(uctl->portal.label);
 1462: 		xfree(uctl->portal.host);
 1463: 		xfree(uctl->portal.port);
 1464: 		xfree(uctl);
 1465: 		return -1;
 1466: 	}
 1467: 	rc = pthread_detach(uctl->thread);
 1468: 	if (rc != 0) {
 1469: 		ISTGT_ERRLOG("pthread_detach() failed\n");
 1470: 		goto error_return;
 1471: 	}
 1472: #ifdef HAVE_PTHREAD_SET_NAME_NP
 1473: 	pthread_set_name_np(uctl->thread, "uctlthread");
 1474: #endif
 1475: 
 1476: 	return 0;
 1477: }
 1478: 
 1479: int
 1480: istgt_uctl_init(ISTGT_Ptr istgt)
 1481: {
 1482: 	CF_SECTION *sp;
 1483: 	const char *val;
 1484: 	const char *ag_tag;
 1485: 	int alloc_len;
 1486: 	int ag_tag_i;
 1487: 	int masks;
 1488: 	int i;
 1489: 
 1490: 	ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_init_uctl_section\n");
 1491: 
 1492: 	sp = istgt_find_cf_section(istgt->config, "UnitControl");
 1493: 	if (sp == NULL) {
 1494: 		ISTGT_ERRLOG("find_cf_section failed()\n");
 1495: 		return -1;
 1496: 	}
 1497: 
 1498: 	val = istgt_get_val(sp, "Comment");
 1499: 	if (val != NULL) {
 1500: 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Comment %s\n", val);
 1501: 	}
 1502: 
 1503: 	for (i = 0; ; i++) {
 1504: 		val = istgt_get_nval(sp, "Netmask", i);
 1505: 		if (val == NULL)
 1506: 			break;
 1507: 	}
 1508: 	masks = i;
 1509: 	if (masks > MAX_NETMASK) {
 1510: 		ISTGT_ERRLOG("%d > MAX_NETMASK\n", masks);
 1511: 		return -1;
 1512: 	}
 1513: 	istgt->nuctl_netmasks = masks;
 1514: 	alloc_len = sizeof (char *) * masks;
 1515: 	istgt->uctl_netmasks = xmalloc(alloc_len);
 1516: 	for (i = 0; i < masks; i++) {
 1517: 		val = istgt_get_nval(sp, "Netmask", i);
 1518: 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "Netmask %s\n", val);
 1519: 		istgt->uctl_netmasks[i] = xstrdup(val);
 1520: 	}
 1521: 
 1522: 	val = istgt_get_val(sp, "AuthMethod");
 1523: 	if (val == NULL) {
 1524: 		istgt->no_uctl_auth = 0;
 1525: 		istgt->req_uctl_auth = 0;
 1526: 	} else {
 1527: 		istgt->no_uctl_auth = 0;
 1528: 		for (i = 0; ; i++) {
 1529: 			val = istgt_get_nmval(sp, "AuthMethod", 0, i);
 1530: 			if (val == NULL)
 1531: 				break;
 1532: 			if (strcasecmp(val, "CHAP") == 0) {
 1533: 				istgt->req_uctl_auth = 1;
 1534: 			} else if (strcasecmp(val, "Mutual") == 0) {
 1535: 				istgt->req_uctl_auth_mutual = 1;
 1536: 			} else if (strcasecmp(val, "Auto") == 0) {
 1537: 				istgt->req_uctl_auth = 0;
 1538: 				istgt->req_uctl_auth_mutual = 0;
 1539: 			} else if (strcasecmp(val, "None") == 0) {
 1540: 				istgt->no_uctl_auth = 1;
 1541: 				istgt->req_uctl_auth = 0;
 1542: 				istgt->req_uctl_auth_mutual = 0;
 1543: 			} else {
 1544: 				ISTGT_ERRLOG("unknown auth\n");
 1545: 				return -1;
 1546: 			}
 1547: 		}
 1548: 	}
 1549: 	if (istgt->no_uctl_auth == 0) {
 1550: 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthMethod None\n");
 1551: 	} else if (istgt->req_uctl_auth == 0) {
 1552: 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthMethod Auto\n");
 1553: 	} else {
 1554: 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthMethod %s %s\n",
 1555: 		    istgt->req_uctl_auth ? "CHAP" : "",
 1556: 		    istgt->req_uctl_auth_mutual ? "Mutual" : "");
 1557: 	}
 1558: 
 1559: 	val = istgt_get_val(sp, "AuthGroup");
 1560: 	if (val == NULL) {
 1561: 		istgt->uctl_auth_group = 0;
 1562: 	} else {
 1563: 		ag_tag = val;
 1564: 		if (strcasecmp(ag_tag, "None") == 0) {
 1565: 			ag_tag_i = 0;
 1566: 		} else {
 1567: 			if (strncasecmp(ag_tag, "AuthGroup",
 1568: 				strlen("AuthGroup")) != 0
 1569: 			    || sscanf(ag_tag, "%*[^0-9]%d", &ag_tag_i) != 1) {
 1570: 				ISTGT_ERRLOG("auth group error\n");
 1571: 				return -1;
 1572: 			}
 1573: 			if (ag_tag_i == 0) {
 1574: 				ISTGT_ERRLOG("invalid auth group %d\n", ag_tag_i);
 1575: 				return -1;
 1576: 			}
 1577: 		}
 1578: 		istgt->uctl_auth_group = ag_tag_i;
 1579: 	}
 1580: 	if (istgt->uctl_auth_group == 0) {
 1581: 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthGroup None\n");
 1582: 	} else {
 1583: 		ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "AuthGroup AuthGroup%d\n",
 1584: 		    istgt->uctl_auth_group);
 1585: 	}
 1586: 
 1587: 	return 0;
 1588: }
 1589: 
 1590: int
 1591: istgt_uctl_shutdown(ISTGT_Ptr istgt)
 1592: {
 1593: 	int i;
 1594: 
 1595: 	for (i = 0; i < istgt->nuctl_netmasks; i++) {
 1596: 		xfree(istgt->uctl_netmasks[i]);
 1597: 	}
 1598: 	xfree(istgt->uctl_netmasks);
 1599: 	return 0;
 1600: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>