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

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

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