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