File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / istgt / src / istgtcontrol.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jul 21 23:49:22 2013 UTC (10 years, 11 months ago) by misho
Branches: istgt, MAIN
CVS tags: v20121028, HEAD
20121028

    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 "build.h"
   33: 
   34: #include <stdint.h>
   35: #include <inttypes.h>
   36: 
   37: #include <stdarg.h>
   38: #include <signal.h>
   39: #include <stdio.h>
   40: #include <stdlib.h>
   41: #include <string.h>
   42: #include <unistd.h>
   43: #include <syslog.h>
   44: #include <sys/types.h>
   45: 
   46: #include "istgt.h"
   47: #include "istgt_ver.h"
   48: #include "istgt_conf.h"
   49: #include "istgt_sock.h"
   50: #include "istgt_misc.h"
   51: #include "istgt_md5.h"
   52: 
   53: #if !defined(__GNUC__)
   54: #undef __attribute__
   55: #define __attribute__(x)
   56: #endif
   57: 
   58: //#define TRACE_UCTL
   59: 
   60: #define DEFAULT_UCTL_CONFIG BUILD_ETC_ISTGT "/istgtcontrol.conf"
   61: #define DEFAULT_UCTL_TIMEOUT 60
   62: #define DEFAULT_UCTL_PORT 3261
   63: #define DEFAULT_UCTL_HOST "localhost"
   64: #define DEFAULT_UCTL_LUN 0
   65: #define DEFAULT_UCTL_MTYPE "-"
   66: #define DEFAULT_UCTL_MFLAGS "ro"
   67: #define DEFAULT_UCTL_MSIZE "auto"
   68: 
   69: #define MAX_LINEBUF 4096
   70: #define UCTL_CHAP_CHALLENGE_LEN 1024
   71: 
   72: typedef struct istgt_uctl_auth_t {
   73: 	char *user;
   74: 	char *secret;
   75: 	char *muser;
   76: 	char *msecret;
   77: 
   78: 	uint8_t chap_id[1];
   79: 	uint8_t chap_mid[1];
   80: 	int chap_challenge_len;
   81: 	uint8_t chap_challenge[UCTL_CHAP_CHALLENGE_LEN];
   82: 	int chap_mchallenge_len;
   83: 	uint8_t chap_mchallenge[UCTL_CHAP_CHALLENGE_LEN];
   84: } UCTL_AUTH;
   85: 
   86: typedef struct istgt_uctl_t {
   87: 	CONFIG *config;
   88: 
   89: 	char *host;
   90: 	int port;
   91: 
   92: 	int sock;
   93: 	char *iqn;
   94: 	int lun;
   95: 	char *mflags;
   96: 	char *mfile;
   97: 	char *msize;
   98: 	char *mtype;
   99: 
  100: 	int family;
  101: 	char caddr[MAX_ADDRBUF];
  102: 	char saddr[MAX_ADDRBUF];
  103: 
  104: 	UCTL_AUTH auth;
  105: 
  106: 	int timeout;
  107: 	int req_auth_auto;
  108: 	int req_auth;
  109: 	int req_auth_mutual;
  110: 
  111: 	int recvtmpsize;
  112: 	int recvtmpcnt;
  113: 	int recvtmpidx;
  114: 	int recvbufsize;
  115: 	int sendbufsize;
  116: 	int worksize;
  117: 	char recvtmp[MAX_LINEBUF];
  118: 	char recvbuf[MAX_LINEBUF];
  119: 	char sendbuf[MAX_LINEBUF];
  120: 	char work[MAX_LINEBUF];
  121: 	char *cmd;
  122: 	char *arg;
  123: } UCTL;
  124: typedef UCTL *UCTL_Ptr;
  125: 
  126: 
  127: static void fatal(const char *format, ...) __attribute__((__noreturn__, __format__(__printf__, 1, 2)));
  128: 
  129: static void
  130: fatal(const char *format, ...)
  131: {
  132: 	va_list ap;
  133: 
  134: 	va_start(ap, format);
  135: 	vfprintf(stderr, format, ap);
  136: 	va_end(ap);
  137: 	exit(EXIT_FAILURE);
  138: }
  139: 
  140: typedef enum {
  141: 	UCTL_CMD_OK = 0,
  142: 	UCTL_CMD_ERR = 1,
  143: 	UCTL_CMD_EOF = 2,
  144: 	UCTL_CMD_QUIT = 3,
  145: 	UCTL_CMD_DISCON = 4,
  146: 	UCTL_CMD_REQAUTH = 5,
  147: 	UCTL_CMD_CHAPSEQ = 6,
  148: } UCTL_CMD_STATUS;
  149: 
  150: //#define ARGS_DELIM " \t\r\n"
  151: #define ARGS_DELIM " \t"
  152: 
  153: static int
  154: uctl_readline(UCTL_Ptr uctl)
  155: {
  156: 	ssize_t total;
  157: 
  158: 	total = istgt_readline_socket(uctl->sock, uctl->recvbuf, uctl->recvbufsize,
  159: 	    uctl->recvtmp, uctl->recvtmpsize,
  160: 	    &uctl->recvtmpidx, &uctl->recvtmpcnt,
  161: 	    uctl->timeout);
  162: 	if (total < 0) {
  163: 		return UCTL_CMD_DISCON;
  164: 	}
  165: 	if (total == 0) {
  166: 		return UCTL_CMD_EOF;
  167: 	}
  168: 	return UCTL_CMD_OK;
  169: }
  170: 
  171: static int
  172: uctl_writeline(UCTL_Ptr uctl)
  173: {
  174: 	ssize_t total;
  175: 	ssize_t expect;
  176: 
  177: 	expect = strlen(uctl->sendbuf);
  178: 	total = istgt_writeline_socket(uctl->sock, uctl->sendbuf, uctl->timeout);
  179: 	if (total < 0) {
  180: 		return UCTL_CMD_DISCON;
  181: 	}
  182: 	if (total != expect) {
  183: 		return UCTL_CMD_ERR;
  184: 	}
  185: 	return UCTL_CMD_OK;
  186: }
  187: 
  188: static int uctl_snprintf(UCTL_Ptr uctl, const char *format, ...) __attribute__((__format__(__printf__, 2, 3)));
  189: 
  190: static int
  191: uctl_snprintf(UCTL_Ptr uctl, const char *format, ...)
  192: {
  193: 	va_list ap;
  194: 	int rc;
  195: 
  196: 	va_start(ap, format);
  197: 	rc = vsnprintf(uctl->sendbuf, uctl->sendbufsize, format, ap);
  198: 	va_end(ap);
  199: 	return rc;
  200: }
  201: 
  202: static char *
  203: get_banner(UCTL_Ptr uctl)
  204: {
  205: 	char *banner;
  206: 	int rc;
  207: 
  208: 	rc = uctl_readline(uctl);
  209: 	if (rc != UCTL_CMD_OK) {
  210: 		return NULL;
  211: 	}
  212: 	banner = xstrdup(trim_string(uctl->recvbuf));
  213: 	return banner;
  214: }
  215: 
  216: static int
  217: is_err_req_auth(UCTL_Ptr uctl __attribute__((__unused__)), char *s)
  218: {
  219: 	const char *req_auth_string = "auth required";
  220: 
  221: #ifdef TRACE_UCTL
  222: 	printf("S=%s, Q=%s\n", s, req_auth_string);
  223: #endif /* TRCAE_UCTL */
  224: 	if (strncasecmp(s, req_auth_string, strlen(req_auth_string)) == 0)
  225: 		return 1;
  226: 	return 0;
  227: }
  228: 
  229: static int
  230: is_err_chap_seq(UCTL_Ptr uctl __attribute__((__unused__)), char *s)
  231: {
  232: 	const char *chap_seq_string = "CHAP sequence error";
  233: 
  234: #ifdef TRACE_UCTL
  235: 	printf("S=%s, Q=%s\n", s, chap_seq_string);
  236: #endif /* TRCAE_UCTL */
  237: 	if (strncasecmp(s, chap_seq_string, strlen(chap_seq_string)) == 0)
  238: 		return 1;
  239: 	return 0;
  240: }
  241: 
  242: static int
  243: exec_quit(UCTL_Ptr uctl)
  244: {
  245: 	const char *delim = ARGS_DELIM;
  246: 	char *arg;
  247: 	char *result;
  248: 	int rc;
  249: 
  250: 	/* send command */
  251: 	uctl_snprintf(uctl, "QUIT\n");
  252: 	rc = uctl_writeline(uctl);
  253: 	if (rc != UCTL_CMD_OK) {
  254: 		return rc;
  255: 	}
  256: 
  257: 	/* receive result */
  258: 	rc = uctl_readline(uctl);
  259: 	if (rc != UCTL_CMD_OK) {
  260: 		return rc;
  261: 	}
  262: 	arg = trim_string(uctl->recvbuf);
  263: 	result = strsepq(&arg, delim);
  264: 	strupr(result);
  265: 	if (strcmp(result, "OK") != 0) {
  266: 		if (is_err_req_auth(uctl, arg))
  267: 			return UCTL_CMD_REQAUTH;
  268: 		fprintf(stderr, "ERROR %s\n", arg);
  269: 		return UCTL_CMD_ERR;
  270: 	}
  271: 	return UCTL_CMD_OK;
  272: }
  273: 
  274: static int
  275: exec_noop(UCTL_Ptr uctl)
  276: {
  277: 	const char *delim = ARGS_DELIM;
  278: 	char *arg;
  279: 	char *result;
  280: 	int rc;
  281: 
  282: 	/* send command */
  283: 	uctl_snprintf(uctl, "NOOP\n");
  284: 	rc = uctl_writeline(uctl);
  285: 	if (rc != UCTL_CMD_OK) {
  286: 		return rc;
  287: 	}
  288: 
  289: 	/* receive result */
  290: 	rc = uctl_readline(uctl);
  291: 	if (rc != UCTL_CMD_OK) {
  292: 		return rc;
  293: 	}
  294: 	arg = trim_string(uctl->recvbuf);
  295: 	result = strsepq(&arg, delim);
  296: 	strupr(result);
  297: 	if (strcmp(result, "OK") != 0) {
  298: 		if (is_err_req_auth(uctl, arg))
  299: 			return UCTL_CMD_REQAUTH;
  300: 		fprintf(stderr, "ERROR %s\n", arg);
  301: 		return UCTL_CMD_ERR;
  302: 	}
  303: 	return UCTL_CMD_OK;
  304: }
  305: 
  306: static int
  307: exec_version(UCTL_Ptr uctl)
  308: {
  309: 	const char *delim = ARGS_DELIM;
  310: 	char *arg;
  311: 	char *result;
  312: 	char *version;
  313: 	char *extver;
  314: 	int rc;
  315: 
  316: 	/* send command */
  317: 	uctl_snprintf(uctl, "VERSION\n");
  318: 	rc = uctl_writeline(uctl);
  319: 	if (rc != UCTL_CMD_OK) {
  320: 		return rc;
  321: 	}
  322: 
  323: 	/* receive result */
  324: 	while (1) {
  325: 		rc = uctl_readline(uctl);
  326: 		if (rc != UCTL_CMD_OK) {
  327: 			return rc;
  328: 		}
  329: 		arg = trim_string(uctl->recvbuf);
  330: 		result = strsepq(&arg, delim);
  331: 		strupr(result);
  332: 		if (strcmp(result, uctl->cmd) != 0) {
  333: 			break;
  334: 		}
  335: 		version = strsepq(&arg, delim);
  336: 		extver = strsepq(&arg, delim);
  337: 		printf("target version %s %s\n", version, extver);
  338: 	}
  339: 	if (strcmp(result, "OK") != 0) {
  340: 		if (is_err_req_auth(uctl, arg))
  341: 			return UCTL_CMD_REQAUTH;
  342: 		fprintf(stderr, "ERROR %s\n", arg);
  343: 		return UCTL_CMD_ERR;
  344: 	}
  345: 	return UCTL_CMD_OK;
  346: }
  347: 
  348: static int
  349: exec_unload(UCTL_Ptr uctl)
  350: {
  351: 	const char *delim = ARGS_DELIM;
  352: 	char *arg;
  353: 	char *result;
  354: 	int rc;
  355: 
  356: 	/* send command */
  357: 	if (uctl->iqn == NULL || uctl->lun < 0) {
  358: 		return UCTL_CMD_ERR;
  359: 	}
  360: 	uctl_snprintf(uctl, "UNLOAD \"%s\" %d\n",
  361: 	    uctl->iqn, uctl->lun);
  362: 	rc = uctl_writeline(uctl);
  363: 	if (rc != UCTL_CMD_OK) {
  364: 		return rc;
  365: 	}
  366: 
  367: 	/* receive result */
  368: 	rc = uctl_readline(uctl);
  369: 	if (rc != UCTL_CMD_OK) {
  370: 		return rc;
  371: 	}
  372: 	arg = trim_string(uctl->recvbuf);
  373: 	result = strsepq(&arg, delim);
  374: 	strupr(result);
  375: 	if (strcmp(result, "OK") != 0) {
  376: 		if (is_err_req_auth(uctl, arg))
  377: 			return UCTL_CMD_REQAUTH;
  378: 		fprintf(stderr, "ERROR %s\n", arg);
  379: 		return UCTL_CMD_ERR;
  380: 	}
  381: 	return UCTL_CMD_OK;
  382: }
  383: 
  384: static int
  385: exec_load(UCTL_Ptr uctl)
  386: {
  387: 	const char *delim = ARGS_DELIM;
  388: 	char *arg;
  389: 	char *result;
  390: 	int rc;
  391: 
  392: 	/* send command */
  393: 	if (uctl->iqn == NULL || uctl->lun < 0) {
  394: 		return UCTL_CMD_ERR;
  395: 	}
  396: 	uctl_snprintf(uctl, "LOAD \"%s\" %d\n",
  397: 	    uctl->iqn, uctl->lun);
  398: 	rc = uctl_writeline(uctl);
  399: 	if (rc != UCTL_CMD_OK) {
  400: 		return rc;
  401: 	}
  402: 
  403: 	/* receive result */
  404: 	rc = uctl_readline(uctl);
  405: 	if (rc != UCTL_CMD_OK) {
  406: 		return rc;
  407: 	}
  408: 	arg = trim_string(uctl->recvbuf);
  409: 	result = strsepq(&arg, delim);
  410: 	strupr(result);
  411: 	if (strcmp(result, "OK") != 0) {
  412: 		if (is_err_req_auth(uctl, arg))
  413: 			return UCTL_CMD_REQAUTH;
  414: 		fprintf(stderr, "ERROR %s\n", arg);
  415: 		return UCTL_CMD_ERR;
  416: 	}
  417: 	return UCTL_CMD_OK;
  418: }
  419: 
  420: static int
  421: exec_list(UCTL_Ptr uctl)
  422: {
  423: 	const char *delim = ARGS_DELIM;
  424: 	char *arg;
  425: 	char *result;
  426: 	char *target;
  427: 	int rc;
  428: 
  429: 	/* send command */
  430: 	if (uctl->iqn != NULL) {
  431: 		uctl_snprintf(uctl, "LIST \"%s\"\n", uctl->iqn);
  432: 	} else {
  433: 		uctl_snprintf(uctl, "LIST\n");
  434: 	}
  435: 	rc = uctl_writeline(uctl);
  436: 	if (rc != UCTL_CMD_OK) {
  437: 		return rc;
  438: 	}
  439: 
  440: 	/* receive result */
  441: 	while (1) {
  442: 		rc = uctl_readline(uctl);
  443: 		if (rc != UCTL_CMD_OK) {
  444: 			return rc;
  445: 		}
  446: 		arg = trim_string(uctl->recvbuf);
  447: 		result = strsepq(&arg, delim);
  448: 		strupr(result);
  449: 		if (strcmp(result, uctl->cmd) != 0)
  450: 			break;
  451: 		if (uctl->iqn != NULL) {
  452: 			printf("%s\n", arg);
  453: 		} else {
  454: 			target = strsepq(&arg, delim);
  455: 			printf("%s\n", target);
  456: 		}
  457: 	}
  458: 	if (strcmp(result, "OK") != 0) {
  459: 		if (is_err_req_auth(uctl, arg))
  460: 			return UCTL_CMD_REQAUTH;
  461: 		fprintf(stderr, "ERROR %s\n", arg);
  462: 		return UCTL_CMD_ERR;
  463: 	}
  464: 	return UCTL_CMD_OK;
  465: }
  466: 
  467: static int
  468: exec_change(UCTL_Ptr uctl)
  469: {
  470: 	const char *delim = ARGS_DELIM;
  471: 	char *arg;
  472: 	char *result;
  473: 	int rc;
  474: 
  475: 	/* send command */
  476: 	if (uctl->iqn == NULL || uctl->mfile == NULL || uctl->mtype == NULL
  477: 		|| uctl->mflags == NULL || uctl->msize == NULL) {
  478: 		return UCTL_CMD_ERR;
  479: 	}
  480: 	uctl_snprintf(uctl, "CHANGE \"%s\" %d \"%s\" "
  481: 	    "\"%s\" \"%s\" \"%s\"\n",
  482: 	    uctl->iqn, uctl->lun, uctl->mtype,
  483: 	    uctl->mflags, uctl->mfile, uctl->msize);
  484: 	rc = uctl_writeline(uctl);
  485: 	if (rc != UCTL_CMD_OK) {
  486: 		return rc;
  487: 	}
  488: 
  489: 	/* receive result */
  490: 	rc = uctl_readline(uctl);
  491: 	if (rc != UCTL_CMD_OK) {
  492: 		return rc;
  493: 	}
  494: 	arg = trim_string(uctl->recvbuf);
  495: 	result = strsepq(&arg, delim);
  496: 	strupr(result);
  497: 	if (strcmp(result, "OK") != 0) {
  498: 		if (is_err_req_auth(uctl, arg))
  499: 			return UCTL_CMD_REQAUTH;
  500: 		fprintf(stderr, "ERROR %s\n", arg);
  501: 		return UCTL_CMD_ERR;
  502: 	}
  503: 	return UCTL_CMD_OK;
  504: }
  505: 
  506: static int
  507: exec_reset(UCTL_Ptr uctl)
  508: {
  509: 	const char *delim = ARGS_DELIM;
  510: 	char *arg;
  511: 	char *result;
  512: 	int rc;
  513: 
  514: 	/* send command */
  515: 	if (uctl->iqn == NULL || uctl->lun < 0) {
  516: 		return UCTL_CMD_ERR;
  517: 	}
  518: 	uctl_snprintf(uctl, "RESET \"%s\" %d\n",
  519: 	    uctl->iqn, uctl->lun);
  520: 	rc = uctl_writeline(uctl);
  521: 	if (rc != UCTL_CMD_OK) {
  522: 		return rc;
  523: 	}
  524: 
  525: 	/* receive result */
  526: 	rc = uctl_readline(uctl);
  527: 	if (rc != UCTL_CMD_OK) {
  528: 		return rc;
  529: 	}
  530: 	arg = trim_string(uctl->recvbuf);
  531: 	result = strsepq(&arg, delim);
  532: 	strupr(result);
  533: 	if (strcmp(result, "OK") != 0) {
  534: 		if (is_err_req_auth(uctl, arg))
  535: 			return UCTL_CMD_REQAUTH;
  536: 		fprintf(stderr, "ERROR %s\n", arg);
  537: 		return UCTL_CMD_ERR;
  538: 	}
  539: 	return UCTL_CMD_OK;
  540: }
  541: 
  542: static int
  543: exec_info(UCTL_Ptr uctl)
  544: {
  545: 	const char *delim = ARGS_DELIM;
  546: 	char *arg;
  547: 	char *result;
  548: 	int rc;
  549: 
  550: 	/* send command */
  551: 	if (uctl->iqn != NULL) {
  552: 		uctl_snprintf(uctl, "INFO \"%s\"\n", uctl->iqn);
  553: 	} else {
  554: 		uctl_snprintf(uctl, "INFO\n");
  555: 	}
  556: 	rc = uctl_writeline(uctl);
  557: 	if (rc != UCTL_CMD_OK) {
  558: 		return rc;
  559: 	}
  560: 
  561: 	/* receive result */
  562: 	while (1) {
  563: 		rc = uctl_readline(uctl);
  564: 		if (rc != UCTL_CMD_OK) {
  565: 			return rc;
  566: 		}
  567: 		arg = trim_string(uctl->recvbuf);
  568: 		result = strsepq(&arg, delim);
  569: 		strupr(result);
  570: 		if (strcmp(result, uctl->cmd) != 0)
  571: 			break;
  572: 		if (uctl->iqn != NULL) {
  573: 			printf("%s\n", arg);
  574: 		} else {
  575: 			printf("%s\n", arg);
  576: 		}
  577: 	}
  578: 	if (strcmp(result, "OK") != 0) {
  579: 		if (is_err_req_auth(uctl, arg))
  580: 			return UCTL_CMD_REQAUTH;
  581: 		fprintf(stderr, "ERROR %s\n", arg);
  582: 		return UCTL_CMD_ERR;
  583: 	}
  584: 	return UCTL_CMD_OK;
  585: }
  586: 
  587: typedef struct exec_table_t
  588: {
  589: 	const char *name;
  590: 	int (*func) (UCTL_Ptr uctl);
  591: 	int req_argc;
  592: 	int req_target;
  593: } EXEC_TABLE;
  594: 
  595: static EXEC_TABLE exec_table[] = 
  596: {
  597: 	{ "QUIT",    exec_quit,     0, 0 },
  598: 	{ "NOOP",    exec_noop,     0, 0 },
  599: 	{ "VERSION", exec_version,  0, 0 },
  600: 	{ "LIST",    exec_list,     0, 0 },
  601: 	{ "UNLOAD",  exec_unload,   0, 1 },
  602: 	{ "LOAD",    exec_load,     0, 1 },
  603: 	{ "CHANGE",  exec_change,   1, 1 },
  604: 	{ "RESET",   exec_reset,    0, 1 },
  605: 	{ "INFO",    exec_info,     0, 0 },
  606: 	{ NULL,      NULL,          0, 0 },
  607: };
  608: 
  609: static int
  610: do_auth(UCTL_Ptr uctl)
  611: {
  612: 	uint8_t uctlmd5[ISTGT_MD5DIGEST_LEN];
  613: 	uint8_t resmd5[ISTGT_MD5DIGEST_LEN];
  614: 	ISTGT_MD5CTX md5ctx;
  615: 	const char *delim = ARGS_DELIM;
  616: 	char *arg;
  617: 	char *result;
  618: 	char *label;
  619: 	char *chap_i;
  620: 	char *chap_c;
  621: 	char *chap_n;
  622: 	char *chap_r;
  623: 	char *hexmd5;
  624: 	char *hexchallenge;
  625: 	char *workp;
  626: 	int worksize;
  627: 	int algorithm = 5; /* CHAP with MD5 */
  628: 	int rc;
  629: 
  630: #ifdef TRACE_UCTL
  631: 	printf("do_auth: user=%s, secret=%s, muser=%s, msecret=%s\n",
  632: 	    uctl->auth.user,
  633: 	    uctl->auth.secret,
  634: 	    uctl->auth.muser,
  635: 	    uctl->auth.msecret);
  636: #endif /* TRACE_UCTL */
  637: 
  638: 	/* send algorithm CHAP_A */
  639: 	uctl_snprintf(uctl, "AUTH CHAP_A %d\n",
  640: 	    algorithm);
  641: 	rc = uctl_writeline(uctl);
  642: 	if (rc != UCTL_CMD_OK) {
  643: 		return rc;
  644: 	}
  645: 
  646: 	/* receive CHAP_IC */
  647: 	rc = uctl_readline(uctl);
  648: 	if (rc != UCTL_CMD_OK) {
  649: 		return rc;
  650: 	}
  651: 	arg = trim_string(uctl->recvbuf);
  652: 	result = strsepq(&arg, delim);
  653: 	strupr(result);
  654: 	if (strcmp(result, "AUTH") != 0) {
  655: 		fprintf(stderr, "ERROR %s\n", arg);
  656: 		return UCTL_CMD_ERR;
  657: 	}
  658: 
  659: 	label = strsepq(&arg, delim);
  660: 	chap_i = strsepq(&arg, delim);
  661: 	chap_c = strsepq(&arg, delim);
  662: 	if (label == NULL || chap_i == NULL || chap_c == NULL) {
  663: 		fprintf(stderr, "CHAP sequence error\n");
  664: 		return UCTL_CMD_ERR;
  665: 	}
  666: 	if (strcasecmp(label, "CHAP_IC") != 0) {
  667: 		fprintf(stderr, "CHAP sequence error\n");
  668: 		return UCTL_CMD_ERR;
  669: 	}
  670: 
  671: 	/* Identifier */
  672: 	uctl->auth.chap_id[0] = (uint8_t) strtol(chap_i, NULL, 10);
  673: 	/* Challenge Value */
  674: 	rc = istgt_hex2bin(uctl->auth.chap_challenge,
  675: 	    UCTL_CHAP_CHALLENGE_LEN,
  676: 	    chap_c);
  677: 	if (rc < 0) {
  678: 		fprintf(stderr, "challenge format error\n");
  679: 		return UCTL_CMD_ERR;
  680: 	}
  681: 	uctl->auth.chap_challenge_len = rc;
  682: 
  683: 	if (uctl->auth.user == NULL || uctl->auth.secret == NULL) {
  684: 		fprintf(stderr, "ERROR auth user or secret is missing\n");
  685: 		return UCTL_CMD_ERR;
  686: 	}
  687: 
  688: 	istgt_md5init(&md5ctx);
  689: 	/* Identifier */
  690: 	istgt_md5update(&md5ctx, uctl->auth.chap_id, 1);
  691: 	/* followed by secret */
  692: 	istgt_md5update(&md5ctx, uctl->auth.secret,
  693: 	    strlen(uctl->auth.secret));
  694: 	/* followed by Challenge Value */
  695: 	istgt_md5update(&md5ctx, uctl->auth.chap_challenge,
  696: 	    uctl->auth.chap_challenge_len);
  697: 	/* uctlmd5 is Response Value */
  698: 	istgt_md5final(uctlmd5, &md5ctx);
  699: 
  700: 	workp = uctl->work;
  701: 	worksize = uctl->worksize;
  702: 
  703: 	istgt_bin2hex(workp, worksize,
  704: 	    uctlmd5, ISTGT_MD5DIGEST_LEN);
  705: 	hexmd5 = workp;
  706: 	worksize -= strlen(hexmd5) + 1;
  707: 	workp += strlen(hexmd5) + 1;
  708: 
  709: 	/* mutual CHAP? */
  710: 	if (uctl->req_auth_mutual) {
  711: 		/* Identifier is one octet */
  712: 		istgt_gen_random(uctl->auth.chap_mid, 1);
  713: 		/* Challenge Value is a variable stream of octets */
  714: 		/* (binary length MUST not exceed 1024 bytes) */
  715: 		uctl->auth.chap_mchallenge_len = UCTL_CHAP_CHALLENGE_LEN;
  716: 		istgt_gen_random(uctl->auth.chap_mchallenge,
  717: 		    uctl->auth.chap_mchallenge_len);
  718: 
  719: 		istgt_bin2hex(workp, worksize,
  720: 		    uctl->auth.chap_mchallenge,
  721: 		    uctl->auth.chap_mchallenge_len);
  722: 		hexchallenge = workp;
  723: 		worksize -= strlen(hexchallenge) + 1;
  724: 		workp += strlen(hexchallenge) + 1;
  725: 
  726: 		/* send CHAP_NR with CHAP_IC */
  727: 		uctl_snprintf(uctl, "AUTH CHAP_NR %s %s %d %s\n",
  728: 		    uctl->auth.user, hexmd5,
  729: 		    (int) uctl->auth.chap_mid[0], hexchallenge);
  730: 		rc = uctl_writeline(uctl);
  731: 		if (rc != UCTL_CMD_OK) {
  732: 			return rc;
  733: 		}
  734: 
  735: 		/* receive CHAP_NR */
  736: 		rc = uctl_readline(uctl);
  737: 		if (rc != UCTL_CMD_OK) {
  738: 			return rc;
  739: 		}
  740: 		arg = trim_string(uctl->recvbuf);
  741: 		result = strsepq(&arg, delim);
  742: 		strupr(result);
  743: 		if (strcmp(result, "AUTH") != 0) {
  744: 			fprintf(stderr, "ERROR %s\n", arg);
  745: 			return UCTL_CMD_ERR;
  746: 		}
  747: 
  748: 		label = strsepq(&arg, delim);
  749: 		chap_n = strsepq(&arg, delim);
  750: 		chap_r = strsepq(&arg, delim);
  751: 		if (label == NULL || chap_n == NULL || chap_r == NULL) {
  752: 			fprintf(stderr, "CHAP sequence error\n");
  753: 			return UCTL_CMD_ERR;
  754: 		}
  755: 		if (strcasecmp(label, "CHAP_NR") != 0) {
  756: 			fprintf(stderr, "CHAP sequence error\n");
  757: 			return UCTL_CMD_ERR;
  758: 		}
  759: 
  760: 		rc = istgt_hex2bin(resmd5, ISTGT_MD5DIGEST_LEN, chap_r);
  761: 		if (rc < 0 || rc != ISTGT_MD5DIGEST_LEN) {
  762: 			fprintf(stderr, "response format error\n");
  763: 			return UCTL_CMD_ERR;
  764: 		}
  765: 
  766: 		if (uctl->auth.muser == NULL || uctl->auth.msecret == NULL) {
  767: 			fprintf(stderr, "ERROR auth user or secret is missing\n");
  768: 			return UCTL_CMD_ERR;
  769: 		}
  770: 
  771: 		istgt_md5init(&md5ctx);
  772: 		/* Identifier */
  773: 		istgt_md5update(&md5ctx, uctl->auth.chap_mid, 1);
  774: 		/* followed by secret */
  775: 		istgt_md5update(&md5ctx, uctl->auth.msecret,
  776: 		    strlen(uctl->auth.msecret));
  777: 		/* followed by Challenge Value */
  778: 		istgt_md5update(&md5ctx, uctl->auth.chap_mchallenge,
  779: 		    uctl->auth.chap_mchallenge_len);
  780: 		/* uctlmd5 is expecting Response Value */
  781: 		istgt_md5final(uctlmd5, &md5ctx);
  782: 
  783: 		/* compare MD5 digest */
  784: 		if (memcmp(uctlmd5, resmd5, ISTGT_MD5DIGEST_LEN) != 0) {
  785: 			/* not match */
  786: 			fprintf(stderr, "ERROR auth user or secret is missing\n");
  787: 			/* discard result line */
  788: 			if (rc != UCTL_CMD_OK) {
  789: 				return rc;
  790: 			}
  791: 			arg = trim_string(uctl->recvbuf);
  792: 			result = strsepq(&arg, delim);
  793: 			strupr(result);
  794: 			if (strcmp(result, "OK") != 0) {
  795: 				fprintf(stderr, "ERROR %s\n", arg);
  796: 				return UCTL_CMD_ERR;
  797: 			}
  798: 			/* final with ERR */
  799: 			return UCTL_CMD_ERR;
  800: 		}
  801: 	} else {
  802: 		/* not mutual */
  803: 		/* send CHAP_NR */
  804: 		uctl_snprintf(uctl, "AUTH CHAP_NR %s %s\n",
  805: 		    uctl->auth.user, hexmd5);
  806: 		rc = uctl_writeline(uctl);
  807: 		if (rc != UCTL_CMD_OK) {
  808: 			return rc;
  809: 		}
  810: 	}
  811: 
  812: 	/* receive result */
  813: 	rc = uctl_readline(uctl);
  814: 	if (rc != UCTL_CMD_OK) {
  815: 		return rc;
  816: 	}
  817: 	arg = trim_string(uctl->recvbuf);
  818: 	result = strsepq(&arg, delim);
  819: 	strupr(result);
  820: 	if (strcmp(result, "OK") != 0) {
  821: 		if (is_err_chap_seq(uctl, arg))
  822: 			return UCTL_CMD_CHAPSEQ;
  823: 		fprintf(stderr, "ERROR %s\n", arg);
  824: 		return UCTL_CMD_ERR;
  825: 	}
  826: 	return UCTL_CMD_OK;
  827: }
  828: 
  829: static char *
  830: uctl_get_nmval(CF_SECTION *sp, const char *key, int idx1, int idx2)
  831: {
  832: 	CF_ITEM *ip;
  833: 	CF_VALUE *vp;
  834: 	int i;
  835: 
  836: 	ip = istgt_find_cf_nitem(sp, key, idx1);
  837: 	if (ip == NULL)
  838: 		return NULL;
  839: 	vp = ip->val;
  840: 	if (vp == NULL)
  841: 		return NULL;
  842: 	for (i = 0; vp != NULL; vp = vp->next) {
  843: 		if (i == idx2)
  844: 			return vp->value;
  845: 		i++;
  846: 	}
  847: 	return NULL;
  848: }
  849: 
  850: static char *
  851: uctl_get_nval(CF_SECTION *sp, const char *key, int idx)
  852: {
  853: 	CF_ITEM *ip;
  854: 	CF_VALUE *vp;
  855: 
  856: 	ip = istgt_find_cf_nitem(sp, key, idx);
  857: 	if (ip == NULL)
  858: 		return NULL;
  859: 	vp = ip->val;
  860: 	if (vp == NULL)
  861: 		return NULL;
  862: 	return vp->value;
  863: }
  864: 
  865: static char *
  866: uctl_get_val(CF_SECTION *sp, const char *key)
  867: {
  868: 	return uctl_get_nval(sp, key, 0);
  869: }
  870: 
  871: static int
  872: uctl_get_nintval(CF_SECTION *sp, const char *key, int idx)
  873: {
  874: 	const char *v;
  875: 	int value;
  876: 
  877: 	v = uctl_get_nval(sp, key, idx);
  878: 	if (v == NULL)
  879: 		return -1;
  880: 	value = (int)strtol(v, NULL, 10);
  881: 	return value;
  882: }
  883: 
  884: static int
  885: uctl_get_intval(CF_SECTION *sp, const char *key)
  886: {
  887: 	return uctl_get_nintval(sp, key, 0);
  888: }
  889: 
  890: static int
  891: uctl_init(UCTL_Ptr uctl)
  892: {
  893: 	CF_SECTION *sp;
  894: 	const char *val;
  895: 	const char *user, *muser;
  896: 	const char *secret, *msecret;
  897: 	int timeout;
  898: 	int port;
  899: 	int lun;
  900: 	int i;
  901: 
  902: 	sp = istgt_find_cf_section(uctl->config, "Global");
  903: 	if (sp == NULL) {
  904: 		fprintf(stderr, "find_cf_section failed()\n");
  905: 		return -1;
  906: 	}
  907: 
  908: 	val = uctl_get_val(sp, "Comment");
  909: 	if (val != NULL) {
  910: 		/* nothing */
  911: #ifdef TRACE_UCTL
  912: 		printf("Comment %s\n", val);
  913: #endif /* TRACE_UCTL */
  914: 	}
  915: 
  916: 	val = uctl_get_val(sp, "Host");
  917: 	if (val == NULL) {
  918: 		val = DEFAULT_UCTL_HOST;
  919: 	}
  920: 	uctl->host = xstrdup(val);
  921: #ifdef TRACE_UCTL
  922: 	printf("Host %s\n", uctl->host);
  923: #endif /* TRACE_UCTL */
  924: 
  925: 	port = uctl_get_intval(sp, "Port");
  926: 	if (port < 0) {
  927: 		port = DEFAULT_UCTL_PORT;
  928: 	}
  929: 	uctl->port = port;
  930: #ifdef TRACE_UCTL
  931: 	printf("Port %d\n", uctl->port);
  932: #endif /* TRACE_UCTL */
  933: 
  934: 	val = uctl_get_val(sp, "TargetName");
  935: 	if (val == NULL) {
  936: 		val = NULL;
  937: 	}
  938: 	uctl->iqn = xstrdup(val);
  939: #ifdef TRACE_UCTL
  940: 	printf("TargetName %s\n", uctl->iqn);
  941: #endif /* TRACE_UCTL */
  942: 
  943: 	lun = uctl_get_intval(sp, "Lun");
  944: 	if (lun < 0) {
  945: 		lun = DEFAULT_UCTL_LUN;
  946: 	}
  947: 	uctl->lun = lun;
  948: #ifdef TRACE_UCTL
  949: 	printf("Lun %d\n", uctl->lun);
  950: #endif /* TRACE_UCTL */
  951: 
  952: 	val = uctl_get_val(sp, "Flags");
  953: 	if (val == NULL) {
  954: 		val = DEFAULT_UCTL_MFLAGS;
  955: 	}
  956: 	uctl->mflags = xstrdup(val);
  957: #ifdef TRACE_UCTL
  958: 	printf("Flags %s\n", uctl->mflags);
  959: #endif /* TRACE_UCTL */
  960: 
  961: 	val = uctl_get_val(sp, "Size");
  962: 	if (val == NULL) {
  963: 		val = DEFAULT_UCTL_MSIZE;
  964: 	}
  965: 	uctl->msize = xstrdup(val);
  966: #ifdef TRACE_UCTL
  967: 	printf("Size %s\n", uctl->msize);
  968: #endif /* TRACE_UCTL */
  969: 
  970: 	timeout = uctl_get_intval(sp, "Timeout");
  971: 	if (timeout < 0) {
  972: 		timeout = DEFAULT_UCTL_TIMEOUT;
  973: 	}
  974: 	uctl->timeout = timeout;
  975: #ifdef TRACE_UCTL
  976: 	printf("Timeout %d\n", uctl->timeout);
  977: #endif /* TRACE_UCTL */
  978: 
  979: 	val = uctl_get_val(sp, "AuthMethod");
  980: 	if (val == NULL) {
  981: 		uctl->req_auth_auto = 0;
  982: 		uctl->req_auth = 0;
  983: 	} else {
  984: 		uctl->req_auth_auto = 0;
  985: 		for (i = 0; ; i++) {
  986: 			val = uctl_get_nmval(sp, "AuthMethod", 0, i);
  987: 			if (val == NULL)
  988: 				break;
  989: 			if (strcasecmp(val, "CHAP") == 0) {
  990: 				uctl->req_auth = 1;
  991: 			} else if (strcasecmp(val, "Mutual") == 0) {
  992: 				uctl->req_auth_mutual = 1;
  993: 			} else if (strcasecmp(val, "Auto") == 0) {
  994: 				uctl->req_auth_auto = 1;
  995: 				uctl->req_auth = 0;
  996: 				uctl->req_auth_mutual = 0;
  997: 			} else if (strcasecmp(val, "None") == 0) {
  998: 				uctl->req_auth = 0;
  999: 				uctl->req_auth_mutual = 0;
 1000: 			} else {
 1001: 				fprintf(stderr, "unknown auth\n");
 1002: 				return -1;
 1003: 			}
 1004: 		}
 1005: 		if (uctl->req_auth_mutual && !uctl->req_auth) {
 1006: 			fprintf(stderr, "Mutual but not CHAP\n");
 1007: 			return -1;
 1008: 		}
 1009: 	}
 1010: #ifdef TRACE_UCTL
 1011: 	if (uctl->req_auth == 0) {
 1012: 		printf("AuthMethod Auto\n");
 1013: 	} else {
 1014: 		printf("AuthMethod %s %s\n",
 1015: 		    uctl->req_auth ? "CHAP" : "",
 1016: 		    uctl->req_auth_mutual ? "Mutual" : "");
 1017: 	}
 1018: #endif /* TRACE_UCTL */
 1019: 
 1020: 	val = uctl_get_nval(sp, "Auth", 0);
 1021: 	if (val == NULL) {
 1022: 		user = secret = muser = msecret = NULL;
 1023: 	} else {
 1024: 		user = uctl_get_nmval(sp, "Auth", 0, 0);
 1025: 		secret = uctl_get_nmval(sp, "Auth", 0, 1);
 1026: 		muser = uctl_get_nmval(sp, "Auth", 0, 2);
 1027: 		msecret = uctl_get_nmval(sp, "Auth", 0, 3);
 1028: 	}
 1029: 	uctl->auth.user = xstrdup(user);
 1030: 	uctl->auth.secret = xstrdup(secret);
 1031: 	uctl->auth.muser = xstrdup(muser);
 1032: 	uctl->auth.msecret = xstrdup(msecret);
 1033: #ifdef TRACE_UCTL
 1034: 	printf("user=%s, secret=%s, muser=%s, msecret=%s\n",
 1035: 	    user, secret, muser, msecret);
 1036: #endif /* TRACE_UCTL */
 1037: 
 1038: 	return 0;
 1039: }
 1040: 
 1041: static void
 1042: usage(void)
 1043: {
 1044: 	printf("istgtcotrol [options] <command> [<file>]\n");
 1045: 	printf("options:\n");
 1046: 	printf("default may be changed by configuration file\n");
 1047: 	printf(" -c config  config file (default %s)\n", DEFAULT_UCTL_CONFIG);
 1048: 	printf(" -h host    target host name or IP (default %s)\n", DEFAULT_UCTL_HOST);
 1049: 	printf(" -p port    port number (default %d)\n", DEFAULT_UCTL_PORT);
 1050: 	printf(" -t target  target iqn\n");
 1051: 	printf(" -l lun     target lun (default %d)\n", DEFAULT_UCTL_LUN);
 1052: 	printf(" -f flags   media flags (default %s)\n", DEFAULT_UCTL_MFLAGS);
 1053: 	printf(" -s size    media size (default %s)\n", DEFAULT_UCTL_MSIZE);
 1054: 	printf(" -q         quiet mode\n");
 1055: 	printf(" -v         verbose mode\n");
 1056: 	printf(" -A method  authentication method (CHAP/Mutual CHAP/Auto)\n");
 1057: 	printf(" -U user    auth user\n");
 1058: 	printf(" -S secret  auth secret\n");
 1059: 	printf(" -M muser   mutual auth user\n");
 1060: 	printf(" -R msecret mutual auth secret\n");
 1061: 	printf(" -H         show this usage\n");
 1062: 	printf(" -V         show version\n");
 1063: 	printf("command:\n");
 1064: 	printf(" noop       no operation\n");
 1065: 	printf(" version    show target version\n");
 1066: 	printf(" list       list all or specified target\n");
 1067: 	printf(" load       load media to specified unit\n");
 1068: 	printf(" unload     unload media from specified unit\n");
 1069: 	printf(" change     change media with <file> at specified unit\n");
 1070: 	printf(" reset      reset specified lun of target\n");
 1071: 	printf(" info       show connections of target\n");
 1072: }
 1073: 
 1074: int
 1075: main(int argc, char *argv[])
 1076: {
 1077: 	const char *config_file = DEFAULT_UCTL_CONFIG;
 1078: 	CONFIG *config;
 1079: 	UCTL xuctl, *uctl;
 1080: 	struct sigaction sigact, sigoldact;
 1081: 	int (*func) (UCTL_Ptr);
 1082: 	int port = -1;
 1083: 	int lun = -1;
 1084: 	const char *host = NULL;
 1085: 	const char *mflags = NULL;
 1086: 	const char *mfile = NULL;
 1087: 	const char *msize = NULL;
 1088: 	const char *mtype = DEFAULT_UCTL_MTYPE;
 1089: 	char *target = NULL;
 1090: 	char *user = NULL;
 1091: 	char *secret = NULL;
 1092: 	char *muser = NULL;
 1093: 	char *msecret = NULL;
 1094: 	char *cmd;
 1095: 	char *banner;
 1096: 	long l;
 1097: 	int exec_result;
 1098: 	int req_argc;
 1099: 	int req_target;
 1100: 	int quiet = 0;
 1101: 	int verbose = 0;
 1102: 	int req_auth = -1;
 1103: 	int ch;
 1104: 	int sock;
 1105: 	int rc;
 1106: 	int i;
 1107: 
 1108: #ifdef HAVE_SETPROCTITLE
 1109: 	setproctitle("version %s (%s)",
 1110: 	    ISTGT_VERSION, ISTGT_EXTRA_VERSION);
 1111: #endif
 1112: 
 1113: 	memset(&xuctl, 0, sizeof xuctl);
 1114: 	uctl = &xuctl;
 1115: 
 1116: 	while ((ch = getopt(argc, argv, "c:h:p:t:l:f:s:qvA:U:S:M:R:VH")) != -1) {
 1117: 		switch (ch) {
 1118: 		case 'c':
 1119: 			config_file = optarg;
 1120: 			break;
 1121: 		case 'h':
 1122: 			host = optarg;
 1123: 			break;
 1124: 		case 'p':
 1125: 			l = strtol(optarg, NULL, 10);
 1126: 			if (l < 0 || l > 65535) {
 1127: 				fatal("invalid port %s\n", optarg);
 1128: 			}
 1129: 			port = (int) l;
 1130: 			break;
 1131: 		case 't':
 1132: 			target = optarg;
 1133: 			break;
 1134: 		case 'l':
 1135: 			l = strtol(optarg, NULL, 10);
 1136: 			if (l < 0 || l > 0x3fff) {
 1137: 				fatal("invalid lun %s\n", optarg);
 1138: 			}
 1139: 			lun = (int) l;
 1140: 			break;
 1141: 		case 'f':
 1142: 			mflags = optarg;
 1143: 			break;
 1144: 		case 's':
 1145: 			msize = optarg;
 1146: 			break;
 1147: 		case 'q':
 1148: 			quiet = 1;
 1149: 			break;
 1150: 		case 'v':
 1151: 			verbose = 1;
 1152: 			break;
 1153: 		case 'A':
 1154: 			if (strcasecmp(optarg, "CHAP") == 0) {
 1155: 				req_auth = 1;
 1156: 			} else if (strcasecmp(optarg, "Mutual") == 0
 1157: 			    || strcasecmp(optarg, "Mutual CHAP") == 0
 1158: 			    || strcasecmp(optarg, "CHAP Mutual") == 0) {
 1159: 				req_auth = 2;
 1160: 			} else if (strcasecmp(optarg, "Auto") == 0) {
 1161: 				req_auth = 0;
 1162: 			} else {
 1163: 				usage();
 1164: 				exit(EXIT_SUCCESS);
 1165: 			}
 1166: 			break;
 1167: 		case 'U':
 1168: 			user = optarg;
 1169: 			break;
 1170: 		case 'S':
 1171: 			secret = optarg;
 1172: #ifndef HAVE_SETPROCTITLE
 1173: 			secret = xstrdup(optarg);
 1174: 			memset(optarg, 'x', strlen(optarg));
 1175: #endif
 1176: 			break;
 1177: 		case 'M':
 1178: 			muser = optarg;
 1179: 			break;
 1180: 		case 'R':
 1181: 			msecret = optarg;
 1182: #ifndef HAVE_SETPROCTITLE
 1183: 			msecret = xstrdup(optarg);
 1184: 			memset(optarg, 'x', strlen(optarg));
 1185: #endif
 1186: 			break;
 1187: 		case 'V':
 1188: 			printf("istgtcontrol version %s (%s)\n",
 1189: 			    ISTGT_VERSION, ISTGT_EXTRA_VERSION);
 1190: 			exit(EXIT_SUCCESS);
 1191: 		case 'H':
 1192: 		default:
 1193: 			usage();
 1194: 			exit(EXIT_SUCCESS);
 1195: 		}
 1196: 	}
 1197: 	argc -= optind;
 1198: 	argv += optind;
 1199: 
 1200: 	/* read config files */
 1201: 	config = istgt_allocate_config();
 1202: 	rc = istgt_read_config(config, config_file);
 1203: 	if (rc < 0) {
 1204: 		fprintf(stderr, "config error\n");
 1205: 		exit(EXIT_FAILURE);
 1206: 	}
 1207: 	if (config->section == NULL) {
 1208: 		fprintf(stderr, "empty config\n");
 1209: 		istgt_free_config(config);
 1210: 		exit(EXIT_FAILURE);
 1211: 	}
 1212: 	uctl->config = config;
 1213: 	//istgt_print_config(config);
 1214: 
 1215: 	istgtcontrol_open_log();
 1216: 
 1217: 	/* take specified command */
 1218: 	if (argc < 1) {
 1219: 	error_usage_return:
 1220: 		istgt_free_config(config);
 1221: 		usage();
 1222: 		exit(EXIT_FAILURE);
 1223: 	}
 1224: 	cmd = strupr(xstrdup(argv[0]));
 1225: 	argc--;
 1226: 	argv++;
 1227: 
 1228: 	/* get function pointer and parameters for specified command */
 1229: 	func = NULL;
 1230: 	req_argc = -1;
 1231: 	req_target = -1;
 1232: 	for (i = 0; exec_table[i].name != NULL; i++) {
 1233: 		if (cmd[0] == exec_table[i].name[0]
 1234: 			&& strcmp(cmd, exec_table[i].name) == 0) {
 1235: 			func = exec_table[i].func;
 1236: 			req_argc = exec_table[i].req_argc;
 1237: 			req_target = exec_table[i].req_target;
 1238: 			break;
 1239: 		}
 1240: 	}
 1241: 	if (func == NULL) {
 1242: 		istgt_free_config(config);
 1243: 		fatal("unknown command %s\n", cmd);
 1244: 	}
 1245: 
 1246: 	/* patrameter check */
 1247: 	if (argc < req_argc) {
 1248: 		goto error_usage_return;
 1249: 	}
 1250: #if 0
 1251: 	if (req_target) {
 1252: 		if (target == NULL) {
 1253: 			goto error_usage_return;
 1254: 		}
 1255: 	}
 1256: #endif
 1257: 
 1258: 	/* take args */
 1259: 	if (strcmp(cmd, "CHANGE") == 0) {
 1260: 		/* change require file */
 1261: 		mfile = argv[0];
 1262: 	}
 1263: 
 1264: 	/* build parameters */
 1265: 	rc = uctl_init(uctl);
 1266: 	if (rc < 0) {
 1267: 		fprintf(stderr, "uctl_init() failed\n");
 1268: 		istgt_free_config(config);
 1269: 		exit(EXIT_FAILURE);
 1270: 	}
 1271: 	uctl->recvtmpcnt = 0;
 1272: 	uctl->recvtmpidx = 0;
 1273: 	uctl->recvtmpsize = sizeof uctl->recvtmp;
 1274: 	uctl->recvbufsize = sizeof uctl->recvbuf;
 1275: 	uctl->sendbufsize = sizeof uctl->sendbuf;
 1276: 	uctl->worksize = sizeof uctl->work;
 1277: 
 1278: 	/* override by command line */
 1279: 	if (user != NULL) {
 1280: 		xfree(uctl->auth.user);
 1281: 		uctl->auth.user = xstrdup(user);
 1282: 	}
 1283: 	if (secret != NULL) {
 1284: 		xfree(uctl->auth.secret);
 1285: 		uctl->auth.secret = xstrdup(secret);
 1286: 	}
 1287: 	if (muser != NULL) {
 1288: 		xfree(uctl->auth.muser);
 1289: 		uctl->auth.muser = xstrdup(muser);
 1290: 	}
 1291: 	if (msecret != NULL) {
 1292: 		xfree(uctl->auth.msecret);
 1293: 		uctl->auth.msecret = xstrdup(msecret);
 1294: 	}
 1295: 	if (req_target) {
 1296: 		if (uctl->iqn == NULL
 1297: 			&& target == NULL) {
 1298: 			goto error_usage_return;
 1299: 		}
 1300: 	}
 1301: 	if (req_auth >= 0) {
 1302: 		uctl->req_auth_auto = 1;
 1303: 		uctl->req_auth = 0;
 1304: 		uctl->req_auth_mutual = 0;
 1305: 		if (req_auth > 1) {
 1306: 			uctl->req_auth_auto = 0;
 1307: 			uctl->req_auth = 1;
 1308: 			uctl->req_auth_mutual = 1;
 1309: 		} else if (req_auth > 0) {
 1310: 			uctl->req_auth_auto = 0;
 1311: 			uctl->req_auth = 1;
 1312: 		}
 1313: 	}
 1314: #ifdef TRACE_UCTL
 1315: 	printf("auto=%d, auth=%d, mutual=%d\n",
 1316: 	    uctl->req_auth_auto, uctl->req_auth, uctl->req_auth_mutual);
 1317: #endif /* TRACE_UCTL */
 1318: 
 1319: 	if (host != NULL) {
 1320: 		xfree(uctl->host);
 1321: 		uctl->host = xstrdup(host);
 1322: 	}
 1323: 	if (port >= 0) {
 1324: 		uctl->port = port;
 1325: 	}
 1326: 	if (target != NULL) {
 1327: 		xfree(uctl->iqn);
 1328: 		if (strcasecmp(target, "ALL") == 0) {
 1329: 			uctl->iqn = NULL;
 1330: 		} else {
 1331: 			uctl->iqn = escape_string(target);
 1332: 		}
 1333: 	}
 1334: 	if (lun >= 0) {
 1335: 		uctl->lun = lun;
 1336: 	}
 1337: 	if (mflags != NULL) {
 1338: 		xfree(uctl->mflags);
 1339: 		uctl->mflags = escape_string(mflags);
 1340: 	}
 1341: 	uctl->mfile = escape_string(mfile);
 1342: 	if (msize != NULL) {
 1343: 		xfree(uctl->msize);
 1344: 		uctl->msize = escape_string(msize);
 1345: 	}
 1346: 	uctl->mtype = escape_string(mtype);
 1347: 	uctl->cmd = escape_string(cmd);
 1348: 
 1349: 	/* show setting */
 1350: #define NULLP(S) ((S) == NULL ? "NULL" : (S))
 1351: 	if (verbose) {
 1352: 		printf("iqn=%s, lun=%d\n", NULLP(uctl->iqn), uctl->lun);
 1353: 		printf("media file=%s, flags=%s, size=%s\n",
 1354: 		    NULLP(uctl->mfile), NULLP(uctl->mflags), NULLP(uctl->msize));
 1355: 	}
 1356: 
 1357: 	/* set signals */
 1358: 	memset(&sigact, 0, sizeof sigact);
 1359: 	memset(&sigoldact, 0, sizeof sigoldact);
 1360: 	sigact.sa_handler = SIG_IGN;
 1361: 	sigemptyset(&sigact.sa_mask);
 1362: 	if (sigaction(SIGPIPE, &sigact, &sigoldact) != 0) {
 1363: 		istgt_free_config(config);
 1364: 		fatal("sigaction() failed");
 1365: 	}
 1366: 
 1367: 	/* connect to target */
 1368: 	if (verbose) {
 1369: 		printf("connect to %s:%d\n", uctl->host, uctl->port);
 1370: 	}
 1371: 	sock = istgt_connect(uctl->host, uctl->port);
 1372: 	if (sock < 0) {
 1373: 		istgt_free_config(config);
 1374: 		fatal("istgt_connect(%s:%d) failed\n", uctl->host, uctl->port);
 1375: 	}
 1376: 	uctl->sock = sock;
 1377: 
 1378: 	/* get target banner (ready to send) */
 1379: 	banner = get_banner(uctl);
 1380: 	if (banner == NULL) {
 1381: 		close(uctl->sock);
 1382: 		istgt_free_config(config);
 1383: 		fatal("get_banner() failed\n");
 1384: 	}
 1385: 	if (verbose) {
 1386: 		printf("target banner \"%s\"\n", banner);
 1387: 	}
 1388: 
 1389: 	/* authentication */
 1390:  retry_auth:
 1391: 	if (uctl->req_auth) {
 1392: 		rc = do_auth(uctl);
 1393: 		if (rc != UCTL_CMD_OK) {
 1394: 			if (rc == UCTL_CMD_REQAUTH
 1395: 				|| rc == UCTL_CMD_CHAPSEQ) {
 1396: 			retry_auth_auto:
 1397: 				/* Auth negotiation */
 1398: 				if (uctl->req_auth == 0) {
 1399: #ifdef TRCAE_UCTL
 1400: 					printf("Auto negotiation CHAP\n");
 1401: #endif /* TRCAE_UCTL */
 1402: 					uctl->req_auth = 1;
 1403: 					goto retry_auth;
 1404: 				} else if (uctl->req_auth_mutual == 0) {
 1405: #ifdef TRCAE_UCTL
 1406: 					printf("Auto negotiation Mutual CHAP\n");
 1407: #endif /* TRCAE_UCTL */
 1408: 					uctl->req_auth_mutual = 1;
 1409: 					goto retry_auth;
 1410: 				}
 1411: 			}
 1412: 			if (!quiet) {
 1413: 				printf("AUTH failed\n");
 1414: 			}
 1415: 			exec_result = rc;
 1416: 			goto disconnect;
 1417: 		}
 1418: 	}
 1419: 
 1420: 	/* send specified command */
 1421: 	rc = func(uctl);
 1422: 	exec_result = rc;
 1423: 	if (rc != UCTL_CMD_OK) {
 1424: 		if (rc == UCTL_CMD_REQAUTH
 1425: 			|| rc == UCTL_CMD_CHAPSEQ) {
 1426: 			goto retry_auth_auto;
 1427: 		}
 1428: 		if (!quiet) {
 1429: 			printf("ABORT %s command\n", uctl->cmd);
 1430: 		}
 1431: 	} else {
 1432: 		if (!quiet) {
 1433: 			printf("DONE %s command\n", uctl->cmd);
 1434: 		}
 1435: 	}
 1436: 
 1437: 	/* disconnect from target */
 1438:  disconnect:
 1439: 	rc = exec_quit(uctl);
 1440: 	if (rc != UCTL_CMD_OK) {
 1441: 		fprintf(stderr, "QUIT failed\n");
 1442: 		/* error but continue */
 1443: 	}
 1444: 
 1445: 	/* cleanup */
 1446: 	close(sock);
 1447: 	xfree(uctl->host);
 1448: 	xfree(uctl->iqn);
 1449: 	xfree(uctl->mflags);
 1450: 	xfree(uctl->mfile);
 1451: 	xfree(uctl->msize);
 1452: 	xfree(uctl->mtype);
 1453: 	xfree(uctl->cmd);
 1454: 	xfree(banner);
 1455: 	xfree(cmd);
 1456: 	istgt_free_config(config);
 1457: 	istgtcontrol_close_log();
 1458: 
 1459: 	/* return value as execution result */
 1460: 	if (exec_result != UCTL_CMD_OK) {
 1461: 		exit(EXIT_FAILURE);
 1462: 	}
 1463: 	return EXIT_SUCCESS;
 1464: }

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