Annotation of embedaddon/istgt/src/istgtcontrol.c, revision 1.1.1.3

1.1       misho       1: /*
1.1.1.2   misho       2:  * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
1.1       misho       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>
1.1.1.3 ! misho      43: #include <syslog.h>
1.1       misho      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: 
1.1.1.2   misho      53: #if !defined(__GNUC__)
                     54: #undef __attribute__
                     55: #define __attribute__(x)
                     56: #endif
                     57: 
1.1       misho      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: 
1.1.1.2   misho     127: static void fatal(const char *format, ...) __attribute__((__noreturn__, __format__(__printf__, 1, 2)));
                    128: 
1.1       misho     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,
1.1.1.2   misho     159:            uctl->recvtmp, uctl->recvtmpsize,
                    160:            &uctl->recvtmpidx, &uctl->recvtmpcnt,
                    161:            uctl->timeout);
1.1       misho     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: 
1.1.1.2   misho     188: static int uctl_snprintf(UCTL_Ptr uctl, const char *format, ...) __attribute__((__format__(__printf__, 2, 3)));
                    189: 
1.1       misho     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
1.1.1.2   misho     217: is_err_req_auth(UCTL_Ptr uctl __attribute__((__unused__)), char *s)
1.1       misho     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
1.1.1.2   misho     230: is_err_chap_seq(UCTL_Ptr uctl __attribute__((__unused__)), char *s)
1.1       misho     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",
1.1.1.2   misho     361:            uctl->iqn, uctl->lun);
1.1       misho     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",
1.1.1.2   misho     397:            uctl->iqn, uctl->lun);
1.1       misho     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\" "
1.1.1.2   misho     481:            "\"%s\" \"%s\" \"%s\"\n",
                    482:            uctl->iqn, uctl->lun, uctl->mtype,
                    483:            uctl->mflags, uctl->mfile, uctl->msize);
1.1       misho     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",
1.1.1.2   misho     519:            uctl->iqn, uctl->lun);
1.1       misho     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",
1.1.1.2   misho     632:            uctl->auth.user,
                    633:            uctl->auth.secret,
                    634:            uctl->auth.muser,
                    635:            uctl->auth.msecret);
1.1       misho     636: #endif /* TRACE_UCTL */
                    637: 
                    638:        /* send algorithm CHAP_A */
                    639:        uctl_snprintf(uctl, "AUTH CHAP_A %d\n",
1.1.1.2   misho     640:            algorithm);
1.1       misho     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,
1.1.1.2   misho     675:            UCTL_CHAP_CHALLENGE_LEN,
                    676:            chap_c);
1.1       misho     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,
1.1.1.2   misho     693:            strlen(uctl->auth.secret));
1.1       misho     694:        /* followed by Challenge Value */
                    695:        istgt_md5update(&md5ctx, uctl->auth.chap_challenge,
1.1.1.2   misho     696:            uctl->auth.chap_challenge_len);
1.1       misho     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,
1.1.1.2   misho     704:            uctlmd5, ISTGT_MD5DIGEST_LEN);
1.1       misho     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,
1.1.1.2   misho     717:                    uctl->auth.chap_mchallenge_len);
1.1       misho     718: 
                    719:                istgt_bin2hex(workp, worksize,
1.1.1.2   misho     720:                    uctl->auth.chap_mchallenge,
                    721:                    uctl->auth.chap_mchallenge_len);
1.1       misho     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",
1.1.1.2   misho     728:                    uctl->auth.user, hexmd5,
                    729:                    (int) uctl->auth.chap_mid[0], hexchallenge);
1.1       misho     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,
1.1.1.2   misho     776:                    strlen(uctl->auth.msecret));
1.1       misho     777:                /* followed by Challenge Value */
                    778:                istgt_md5update(&md5ctx, uctl->auth.chap_mchallenge,
1.1.1.2   misho     779:                    uctl->auth.chap_mchallenge_len);
1.1       misho     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",
1.1.1.2   misho     805:                    uctl->auth.user, hexmd5);
1.1       misho     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;
1.1.1.3 ! misho     997:                        } else if (strcasecmp(val, "None") == 0) {
        !           998:                                uctl->req_auth = 0;
        !           999:                                uctl->req_auth_mutual = 0;
1.1       misho    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",
1.1.1.2   misho    1015:                    uctl->req_auth ? "CHAP" : "",
                   1016:                    uctl->req_auth_mutual ? "Mutual" : "");
1.1       misho    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",
1.1.1.2   misho    1035:            user, secret, muser, msecret);
1.1       misho    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)",
1.1.1.2   misho    1110:            ISTGT_VERSION, ISTGT_EXTRA_VERSION);
1.1       misho    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);
1.1.1.2   misho    1136:                        if (l < 0 || l > 0x3fff) {
1.1       misho    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
1.1.1.2   misho    1157:                            || strcasecmp(optarg, "Mutual CHAP") == 0
                   1158:                            || strcasecmp(optarg, "CHAP Mutual") == 0) {
1.1       misho    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",
1.1.1.2   misho    1189:                            ISTGT_VERSION, ISTGT_EXTRA_VERSION);
1.1       misho    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: 
1.1.1.3 ! misho    1215:        istgtcontrol_open_log();
        !          1216: 
1.1       misho    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 */
1.1.1.3 ! misho    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:        }
1.1       misho    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",
1.1.1.2   misho    1316:            uctl->req_auth_auto, uctl->req_auth, uctl->req_auth_mutual);
1.1       misho    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",
1.1.1.2   misho    1354:                    NULLP(uctl->mfile), NULLP(uctl->mflags), NULLP(uctl->msize));
1.1       misho    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);
1.1.1.3 ! misho    1457:        istgtcontrol_close_log();
1.1       misho    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>