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