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

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

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