Annotation of embedaddon/istgt/src/istgt_lu_ctl.c, revision 1.1.1.2

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

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