Annotation of embedaddon/istgt/src/istgtcontrol.c, revision 1.1.1.3
1.1 misho 1: /*
1.1.1.2 misho 2: * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
1.1 misho 3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: *
14: * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17: * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24: * SUCH DAMAGE.
25: *
26: */
27:
28: #ifdef HAVE_CONFIG_H
29: #include "config.h"
30: #endif
31:
32: #include "build.h"
33:
34: #include <stdint.h>
35: #include <inttypes.h>
36:
37: #include <stdarg.h>
38: #include <signal.h>
39: #include <stdio.h>
40: #include <stdlib.h>
41: #include <string.h>
42: #include <unistd.h>
1.1.1.3 ! misho 43: #include <syslog.h>
1.1 misho 44: #include <sys/types.h>
45:
46: #include "istgt.h"
47: #include "istgt_ver.h"
48: #include "istgt_conf.h"
49: #include "istgt_sock.h"
50: #include "istgt_misc.h"
51: #include "istgt_md5.h"
52:
1.1.1.2 misho 53: #if !defined(__GNUC__)
54: #undef __attribute__
55: #define __attribute__(x)
56: #endif
57:
1.1 misho 58: //#define TRACE_UCTL
59:
60: #define DEFAULT_UCTL_CONFIG BUILD_ETC_ISTGT "/istgtcontrol.conf"
61: #define DEFAULT_UCTL_TIMEOUT 60
62: #define DEFAULT_UCTL_PORT 3261
63: #define DEFAULT_UCTL_HOST "localhost"
64: #define DEFAULT_UCTL_LUN 0
65: #define DEFAULT_UCTL_MTYPE "-"
66: #define DEFAULT_UCTL_MFLAGS "ro"
67: #define DEFAULT_UCTL_MSIZE "auto"
68:
69: #define MAX_LINEBUF 4096
70: #define UCTL_CHAP_CHALLENGE_LEN 1024
71:
72: typedef struct istgt_uctl_auth_t {
73: char *user;
74: char *secret;
75: char *muser;
76: char *msecret;
77:
78: uint8_t chap_id[1];
79: uint8_t chap_mid[1];
80: int chap_challenge_len;
81: uint8_t chap_challenge[UCTL_CHAP_CHALLENGE_LEN];
82: int chap_mchallenge_len;
83: uint8_t chap_mchallenge[UCTL_CHAP_CHALLENGE_LEN];
84: } UCTL_AUTH;
85:
86: typedef struct istgt_uctl_t {
87: CONFIG *config;
88:
89: char *host;
90: int port;
91:
92: int sock;
93: char *iqn;
94: int lun;
95: char *mflags;
96: char *mfile;
97: char *msize;
98: char *mtype;
99:
100: int family;
101: char caddr[MAX_ADDRBUF];
102: char saddr[MAX_ADDRBUF];
103:
104: UCTL_AUTH auth;
105:
106: int timeout;
107: int req_auth_auto;
108: int req_auth;
109: int req_auth_mutual;
110:
111: int recvtmpsize;
112: int recvtmpcnt;
113: int recvtmpidx;
114: int recvbufsize;
115: int sendbufsize;
116: int worksize;
117: char recvtmp[MAX_LINEBUF];
118: char recvbuf[MAX_LINEBUF];
119: char sendbuf[MAX_LINEBUF];
120: char work[MAX_LINEBUF];
121: char *cmd;
122: char *arg;
123: } UCTL;
124: typedef UCTL *UCTL_Ptr;
125:
126:
1.1.1.2 misho 127: static void fatal(const char *format, ...) __attribute__((__noreturn__, __format__(__printf__, 1, 2)));
128:
1.1 misho 129: static void
130: fatal(const char *format, ...)
131: {
132: va_list ap;
133:
134: va_start(ap, format);
135: vfprintf(stderr, format, ap);
136: va_end(ap);
137: exit(EXIT_FAILURE);
138: }
139:
140: typedef enum {
141: UCTL_CMD_OK = 0,
142: UCTL_CMD_ERR = 1,
143: UCTL_CMD_EOF = 2,
144: UCTL_CMD_QUIT = 3,
145: UCTL_CMD_DISCON = 4,
146: UCTL_CMD_REQAUTH = 5,
147: UCTL_CMD_CHAPSEQ = 6,
148: } UCTL_CMD_STATUS;
149:
150: //#define ARGS_DELIM " \t\r\n"
151: #define ARGS_DELIM " \t"
152:
153: static int
154: uctl_readline(UCTL_Ptr uctl)
155: {
156: ssize_t total;
157:
158: total = istgt_readline_socket(uctl->sock, uctl->recvbuf, uctl->recvbufsize,
1.1.1.2 misho 159: uctl->recvtmp, uctl->recvtmpsize,
160: &uctl->recvtmpidx, &uctl->recvtmpcnt,
161: uctl->timeout);
1.1 misho 162: if (total < 0) {
163: return UCTL_CMD_DISCON;
164: }
165: if (total == 0) {
166: return UCTL_CMD_EOF;
167: }
168: return UCTL_CMD_OK;
169: }
170:
171: static int
172: uctl_writeline(UCTL_Ptr uctl)
173: {
174: ssize_t total;
175: ssize_t expect;
176:
177: expect = strlen(uctl->sendbuf);
178: total = istgt_writeline_socket(uctl->sock, uctl->sendbuf, uctl->timeout);
179: if (total < 0) {
180: return UCTL_CMD_DISCON;
181: }
182: if (total != expect) {
183: return UCTL_CMD_ERR;
184: }
185: return UCTL_CMD_OK;
186: }
187:
1.1.1.2 misho 188: static int uctl_snprintf(UCTL_Ptr uctl, const char *format, ...) __attribute__((__format__(__printf__, 2, 3)));
189:
1.1 misho 190: static int
191: uctl_snprintf(UCTL_Ptr uctl, const char *format, ...)
192: {
193: va_list ap;
194: int rc;
195:
196: va_start(ap, format);
197: rc = vsnprintf(uctl->sendbuf, uctl->sendbufsize, format, ap);
198: va_end(ap);
199: return rc;
200: }
201:
202: static char *
203: get_banner(UCTL_Ptr uctl)
204: {
205: char *banner;
206: int rc;
207:
208: rc = uctl_readline(uctl);
209: if (rc != UCTL_CMD_OK) {
210: return NULL;
211: }
212: banner = xstrdup(trim_string(uctl->recvbuf));
213: return banner;
214: }
215:
216: static int
1.1.1.2 misho 217: is_err_req_auth(UCTL_Ptr uctl __attribute__((__unused__)), char *s)
1.1 misho 218: {
219: const char *req_auth_string = "auth required";
220:
221: #ifdef TRACE_UCTL
222: printf("S=%s, Q=%s\n", s, req_auth_string);
223: #endif /* TRCAE_UCTL */
224: if (strncasecmp(s, req_auth_string, strlen(req_auth_string)) == 0)
225: return 1;
226: return 0;
227: }
228:
229: static int
1.1.1.2 misho 230: is_err_chap_seq(UCTL_Ptr uctl __attribute__((__unused__)), char *s)
1.1 misho 231: {
232: const char *chap_seq_string = "CHAP sequence error";
233:
234: #ifdef TRACE_UCTL
235: printf("S=%s, Q=%s\n", s, chap_seq_string);
236: #endif /* TRCAE_UCTL */
237: if (strncasecmp(s, chap_seq_string, strlen(chap_seq_string)) == 0)
238: return 1;
239: return 0;
240: }
241:
242: static int
243: exec_quit(UCTL_Ptr uctl)
244: {
245: const char *delim = ARGS_DELIM;
246: char *arg;
247: char *result;
248: int rc;
249:
250: /* send command */
251: uctl_snprintf(uctl, "QUIT\n");
252: rc = uctl_writeline(uctl);
253: if (rc != UCTL_CMD_OK) {
254: return rc;
255: }
256:
257: /* receive result */
258: rc = uctl_readline(uctl);
259: if (rc != UCTL_CMD_OK) {
260: return rc;
261: }
262: arg = trim_string(uctl->recvbuf);
263: result = strsepq(&arg, delim);
264: strupr(result);
265: if (strcmp(result, "OK") != 0) {
266: if (is_err_req_auth(uctl, arg))
267: return UCTL_CMD_REQAUTH;
268: fprintf(stderr, "ERROR %s\n", arg);
269: return UCTL_CMD_ERR;
270: }
271: return UCTL_CMD_OK;
272: }
273:
274: static int
275: exec_noop(UCTL_Ptr uctl)
276: {
277: const char *delim = ARGS_DELIM;
278: char *arg;
279: char *result;
280: int rc;
281:
282: /* send command */
283: uctl_snprintf(uctl, "NOOP\n");
284: rc = uctl_writeline(uctl);
285: if (rc != UCTL_CMD_OK) {
286: return rc;
287: }
288:
289: /* receive result */
290: rc = uctl_readline(uctl);
291: if (rc != UCTL_CMD_OK) {
292: return rc;
293: }
294: arg = trim_string(uctl->recvbuf);
295: result = strsepq(&arg, delim);
296: strupr(result);
297: if (strcmp(result, "OK") != 0) {
298: if (is_err_req_auth(uctl, arg))
299: return UCTL_CMD_REQAUTH;
300: fprintf(stderr, "ERROR %s\n", arg);
301: return UCTL_CMD_ERR;
302: }
303: return UCTL_CMD_OK;
304: }
305:
306: static int
307: exec_version(UCTL_Ptr uctl)
308: {
309: const char *delim = ARGS_DELIM;
310: char *arg;
311: char *result;
312: char *version;
313: char *extver;
314: int rc;
315:
316: /* send command */
317: uctl_snprintf(uctl, "VERSION\n");
318: rc = uctl_writeline(uctl);
319: if (rc != UCTL_CMD_OK) {
320: return rc;
321: }
322:
323: /* receive result */
324: while (1) {
325: rc = uctl_readline(uctl);
326: if (rc != UCTL_CMD_OK) {
327: return rc;
328: }
329: arg = trim_string(uctl->recvbuf);
330: result = strsepq(&arg, delim);
331: strupr(result);
332: if (strcmp(result, uctl->cmd) != 0) {
333: break;
334: }
335: version = strsepq(&arg, delim);
336: extver = strsepq(&arg, delim);
337: printf("target version %s %s\n", version, extver);
338: }
339: if (strcmp(result, "OK") != 0) {
340: if (is_err_req_auth(uctl, arg))
341: return UCTL_CMD_REQAUTH;
342: fprintf(stderr, "ERROR %s\n", arg);
343: return UCTL_CMD_ERR;
344: }
345: return UCTL_CMD_OK;
346: }
347:
348: static int
349: exec_unload(UCTL_Ptr uctl)
350: {
351: const char *delim = ARGS_DELIM;
352: char *arg;
353: char *result;
354: int rc;
355:
356: /* send command */
357: if (uctl->iqn == NULL || uctl->lun < 0) {
358: return UCTL_CMD_ERR;
359: }
360: uctl_snprintf(uctl, "UNLOAD \"%s\" %d\n",
1.1.1.2 misho 361: uctl->iqn, uctl->lun);
1.1 misho 362: rc = uctl_writeline(uctl);
363: if (rc != UCTL_CMD_OK) {
364: return rc;
365: }
366:
367: /* receive result */
368: rc = uctl_readline(uctl);
369: if (rc != UCTL_CMD_OK) {
370: return rc;
371: }
372: arg = trim_string(uctl->recvbuf);
373: result = strsepq(&arg, delim);
374: strupr(result);
375: if (strcmp(result, "OK") != 0) {
376: if (is_err_req_auth(uctl, arg))
377: return UCTL_CMD_REQAUTH;
378: fprintf(stderr, "ERROR %s\n", arg);
379: return UCTL_CMD_ERR;
380: }
381: return UCTL_CMD_OK;
382: }
383:
384: static int
385: exec_load(UCTL_Ptr uctl)
386: {
387: const char *delim = ARGS_DELIM;
388: char *arg;
389: char *result;
390: int rc;
391:
392: /* send command */
393: if (uctl->iqn == NULL || uctl->lun < 0) {
394: return UCTL_CMD_ERR;
395: }
396: uctl_snprintf(uctl, "LOAD \"%s\" %d\n",
1.1.1.2 misho 397: uctl->iqn, uctl->lun);
1.1 misho 398: rc = uctl_writeline(uctl);
399: if (rc != UCTL_CMD_OK) {
400: return rc;
401: }
402:
403: /* receive result */
404: rc = uctl_readline(uctl);
405: if (rc != UCTL_CMD_OK) {
406: return rc;
407: }
408: arg = trim_string(uctl->recvbuf);
409: result = strsepq(&arg, delim);
410: strupr(result);
411: if (strcmp(result, "OK") != 0) {
412: if (is_err_req_auth(uctl, arg))
413: return UCTL_CMD_REQAUTH;
414: fprintf(stderr, "ERROR %s\n", arg);
415: return UCTL_CMD_ERR;
416: }
417: return UCTL_CMD_OK;
418: }
419:
420: static int
421: exec_list(UCTL_Ptr uctl)
422: {
423: const char *delim = ARGS_DELIM;
424: char *arg;
425: char *result;
426: char *target;
427: int rc;
428:
429: /* send command */
430: if (uctl->iqn != NULL) {
431: uctl_snprintf(uctl, "LIST \"%s\"\n", uctl->iqn);
432: } else {
433: uctl_snprintf(uctl, "LIST\n");
434: }
435: rc = uctl_writeline(uctl);
436: if (rc != UCTL_CMD_OK) {
437: return rc;
438: }
439:
440: /* receive result */
441: while (1) {
442: rc = uctl_readline(uctl);
443: if (rc != UCTL_CMD_OK) {
444: return rc;
445: }
446: arg = trim_string(uctl->recvbuf);
447: result = strsepq(&arg, delim);
448: strupr(result);
449: if (strcmp(result, uctl->cmd) != 0)
450: break;
451: if (uctl->iqn != NULL) {
452: printf("%s\n", arg);
453: } else {
454: target = strsepq(&arg, delim);
455: printf("%s\n", target);
456: }
457: }
458: if (strcmp(result, "OK") != 0) {
459: if (is_err_req_auth(uctl, arg))
460: return UCTL_CMD_REQAUTH;
461: fprintf(stderr, "ERROR %s\n", arg);
462: return UCTL_CMD_ERR;
463: }
464: return UCTL_CMD_OK;
465: }
466:
467: static int
468: exec_change(UCTL_Ptr uctl)
469: {
470: const char *delim = ARGS_DELIM;
471: char *arg;
472: char *result;
473: int rc;
474:
475: /* send command */
476: if (uctl->iqn == NULL || uctl->mfile == NULL || uctl->mtype == NULL
477: || uctl->mflags == NULL || uctl->msize == NULL) {
478: return UCTL_CMD_ERR;
479: }
480: uctl_snprintf(uctl, "CHANGE \"%s\" %d \"%s\" "
1.1.1.2 misho 481: "\"%s\" \"%s\" \"%s\"\n",
482: uctl->iqn, uctl->lun, uctl->mtype,
483: uctl->mflags, uctl->mfile, uctl->msize);
1.1 misho 484: rc = uctl_writeline(uctl);
485: if (rc != UCTL_CMD_OK) {
486: return rc;
487: }
488:
489: /* receive result */
490: rc = uctl_readline(uctl);
491: if (rc != UCTL_CMD_OK) {
492: return rc;
493: }
494: arg = trim_string(uctl->recvbuf);
495: result = strsepq(&arg, delim);
496: strupr(result);
497: if (strcmp(result, "OK") != 0) {
498: if (is_err_req_auth(uctl, arg))
499: return UCTL_CMD_REQAUTH;
500: fprintf(stderr, "ERROR %s\n", arg);
501: return UCTL_CMD_ERR;
502: }
503: return UCTL_CMD_OK;
504: }
505:
506: static int
507: exec_reset(UCTL_Ptr uctl)
508: {
509: const char *delim = ARGS_DELIM;
510: char *arg;
511: char *result;
512: int rc;
513:
514: /* send command */
515: if (uctl->iqn == NULL || uctl->lun < 0) {
516: return UCTL_CMD_ERR;
517: }
518: uctl_snprintf(uctl, "RESET \"%s\" %d\n",
1.1.1.2 misho 519: uctl->iqn, uctl->lun);
1.1 misho 520: rc = uctl_writeline(uctl);
521: if (rc != UCTL_CMD_OK) {
522: return rc;
523: }
524:
525: /* receive result */
526: rc = uctl_readline(uctl);
527: if (rc != UCTL_CMD_OK) {
528: return rc;
529: }
530: arg = trim_string(uctl->recvbuf);
531: result = strsepq(&arg, delim);
532: strupr(result);
533: if (strcmp(result, "OK") != 0) {
534: if (is_err_req_auth(uctl, arg))
535: return UCTL_CMD_REQAUTH;
536: fprintf(stderr, "ERROR %s\n", arg);
537: return UCTL_CMD_ERR;
538: }
539: return UCTL_CMD_OK;
540: }
541:
542: static int
543: exec_info(UCTL_Ptr uctl)
544: {
545: const char *delim = ARGS_DELIM;
546: char *arg;
547: char *result;
548: int rc;
549:
550: /* send command */
551: if (uctl->iqn != NULL) {
552: uctl_snprintf(uctl, "INFO \"%s\"\n", uctl->iqn);
553: } else {
554: uctl_snprintf(uctl, "INFO\n");
555: }
556: rc = uctl_writeline(uctl);
557: if (rc != UCTL_CMD_OK) {
558: return rc;
559: }
560:
561: /* receive result */
562: while (1) {
563: rc = uctl_readline(uctl);
564: if (rc != UCTL_CMD_OK) {
565: return rc;
566: }
567: arg = trim_string(uctl->recvbuf);
568: result = strsepq(&arg, delim);
569: strupr(result);
570: if (strcmp(result, uctl->cmd) != 0)
571: break;
572: if (uctl->iqn != NULL) {
573: printf("%s\n", arg);
574: } else {
575: printf("%s\n", arg);
576: }
577: }
578: if (strcmp(result, "OK") != 0) {
579: if (is_err_req_auth(uctl, arg))
580: return UCTL_CMD_REQAUTH;
581: fprintf(stderr, "ERROR %s\n", arg);
582: return UCTL_CMD_ERR;
583: }
584: return UCTL_CMD_OK;
585: }
586:
587: typedef struct exec_table_t
588: {
589: const char *name;
590: int (*func) (UCTL_Ptr uctl);
591: int req_argc;
592: int req_target;
593: } EXEC_TABLE;
594:
595: static EXEC_TABLE exec_table[] =
596: {
597: { "QUIT", exec_quit, 0, 0 },
598: { "NOOP", exec_noop, 0, 0 },
599: { "VERSION", exec_version, 0, 0 },
600: { "LIST", exec_list, 0, 0 },
601: { "UNLOAD", exec_unload, 0, 1 },
602: { "LOAD", exec_load, 0, 1 },
603: { "CHANGE", exec_change, 1, 1 },
604: { "RESET", exec_reset, 0, 1 },
605: { "INFO", exec_info, 0, 0 },
606: { NULL, NULL, 0, 0 },
607: };
608:
609: static int
610: do_auth(UCTL_Ptr uctl)
611: {
612: uint8_t uctlmd5[ISTGT_MD5DIGEST_LEN];
613: uint8_t resmd5[ISTGT_MD5DIGEST_LEN];
614: ISTGT_MD5CTX md5ctx;
615: const char *delim = ARGS_DELIM;
616: char *arg;
617: char *result;
618: char *label;
619: char *chap_i;
620: char *chap_c;
621: char *chap_n;
622: char *chap_r;
623: char *hexmd5;
624: char *hexchallenge;
625: char *workp;
626: int worksize;
627: int algorithm = 5; /* CHAP with MD5 */
628: int rc;
629:
630: #ifdef TRACE_UCTL
631: printf("do_auth: user=%s, secret=%s, muser=%s, msecret=%s\n",
1.1.1.2 misho 632: uctl->auth.user,
633: uctl->auth.secret,
634: uctl->auth.muser,
635: uctl->auth.msecret);
1.1 misho 636: #endif /* TRACE_UCTL */
637:
638: /* send algorithm CHAP_A */
639: uctl_snprintf(uctl, "AUTH CHAP_A %d\n",
1.1.1.2 misho 640: algorithm);
1.1 misho 641: rc = uctl_writeline(uctl);
642: if (rc != UCTL_CMD_OK) {
643: return rc;
644: }
645:
646: /* receive CHAP_IC */
647: rc = uctl_readline(uctl);
648: if (rc != UCTL_CMD_OK) {
649: return rc;
650: }
651: arg = trim_string(uctl->recvbuf);
652: result = strsepq(&arg, delim);
653: strupr(result);
654: if (strcmp(result, "AUTH") != 0) {
655: fprintf(stderr, "ERROR %s\n", arg);
656: return UCTL_CMD_ERR;
657: }
658:
659: label = strsepq(&arg, delim);
660: chap_i = strsepq(&arg, delim);
661: chap_c = strsepq(&arg, delim);
662: if (label == NULL || chap_i == NULL || chap_c == NULL) {
663: fprintf(stderr, "CHAP sequence error\n");
664: return UCTL_CMD_ERR;
665: }
666: if (strcasecmp(label, "CHAP_IC") != 0) {
667: fprintf(stderr, "CHAP sequence error\n");
668: return UCTL_CMD_ERR;
669: }
670:
671: /* Identifier */
672: uctl->auth.chap_id[0] = (uint8_t) strtol(chap_i, NULL, 10);
673: /* Challenge Value */
674: rc = istgt_hex2bin(uctl->auth.chap_challenge,
1.1.1.2 misho 675: UCTL_CHAP_CHALLENGE_LEN,
676: chap_c);
1.1 misho 677: if (rc < 0) {
678: fprintf(stderr, "challenge format error\n");
679: return UCTL_CMD_ERR;
680: }
681: uctl->auth.chap_challenge_len = rc;
682:
683: if (uctl->auth.user == NULL || uctl->auth.secret == NULL) {
684: fprintf(stderr, "ERROR auth user or secret is missing\n");
685: return UCTL_CMD_ERR;
686: }
687:
688: istgt_md5init(&md5ctx);
689: /* Identifier */
690: istgt_md5update(&md5ctx, uctl->auth.chap_id, 1);
691: /* followed by secret */
692: istgt_md5update(&md5ctx, uctl->auth.secret,
1.1.1.2 misho 693: strlen(uctl->auth.secret));
1.1 misho 694: /* followed by Challenge Value */
695: istgt_md5update(&md5ctx, uctl->auth.chap_challenge,
1.1.1.2 misho 696: uctl->auth.chap_challenge_len);
1.1 misho 697: /* uctlmd5 is Response Value */
698: istgt_md5final(uctlmd5, &md5ctx);
699:
700: workp = uctl->work;
701: worksize = uctl->worksize;
702:
703: istgt_bin2hex(workp, worksize,
1.1.1.2 misho 704: uctlmd5, ISTGT_MD5DIGEST_LEN);
1.1 misho 705: hexmd5 = workp;
706: worksize -= strlen(hexmd5) + 1;
707: workp += strlen(hexmd5) + 1;
708:
709: /* mutual CHAP? */
710: if (uctl->req_auth_mutual) {
711: /* Identifier is one octet */
712: istgt_gen_random(uctl->auth.chap_mid, 1);
713: /* Challenge Value is a variable stream of octets */
714: /* (binary length MUST not exceed 1024 bytes) */
715: uctl->auth.chap_mchallenge_len = UCTL_CHAP_CHALLENGE_LEN;
716: istgt_gen_random(uctl->auth.chap_mchallenge,
1.1.1.2 misho 717: uctl->auth.chap_mchallenge_len);
1.1 misho 718:
719: istgt_bin2hex(workp, worksize,
1.1.1.2 misho 720: uctl->auth.chap_mchallenge,
721: uctl->auth.chap_mchallenge_len);
1.1 misho 722: hexchallenge = workp;
723: worksize -= strlen(hexchallenge) + 1;
724: workp += strlen(hexchallenge) + 1;
725:
726: /* send CHAP_NR with CHAP_IC */
727: uctl_snprintf(uctl, "AUTH CHAP_NR %s %s %d %s\n",
1.1.1.2 misho 728: uctl->auth.user, hexmd5,
729: (int) uctl->auth.chap_mid[0], hexchallenge);
1.1 misho 730: rc = uctl_writeline(uctl);
731: if (rc != UCTL_CMD_OK) {
732: return rc;
733: }
734:
735: /* receive CHAP_NR */
736: rc = uctl_readline(uctl);
737: if (rc != UCTL_CMD_OK) {
738: return rc;
739: }
740: arg = trim_string(uctl->recvbuf);
741: result = strsepq(&arg, delim);
742: strupr(result);
743: if (strcmp(result, "AUTH") != 0) {
744: fprintf(stderr, "ERROR %s\n", arg);
745: return UCTL_CMD_ERR;
746: }
747:
748: label = strsepq(&arg, delim);
749: chap_n = strsepq(&arg, delim);
750: chap_r = strsepq(&arg, delim);
751: if (label == NULL || chap_n == NULL || chap_r == NULL) {
752: fprintf(stderr, "CHAP sequence error\n");
753: return UCTL_CMD_ERR;
754: }
755: if (strcasecmp(label, "CHAP_NR") != 0) {
756: fprintf(stderr, "CHAP sequence error\n");
757: return UCTL_CMD_ERR;
758: }
759:
760: rc = istgt_hex2bin(resmd5, ISTGT_MD5DIGEST_LEN, chap_r);
761: if (rc < 0 || rc != ISTGT_MD5DIGEST_LEN) {
762: fprintf(stderr, "response format error\n");
763: return UCTL_CMD_ERR;
764: }
765:
766: if (uctl->auth.muser == NULL || uctl->auth.msecret == NULL) {
767: fprintf(stderr, "ERROR auth user or secret is missing\n");
768: return UCTL_CMD_ERR;
769: }
770:
771: istgt_md5init(&md5ctx);
772: /* Identifier */
773: istgt_md5update(&md5ctx, uctl->auth.chap_mid, 1);
774: /* followed by secret */
775: istgt_md5update(&md5ctx, uctl->auth.msecret,
1.1.1.2 misho 776: strlen(uctl->auth.msecret));
1.1 misho 777: /* followed by Challenge Value */
778: istgt_md5update(&md5ctx, uctl->auth.chap_mchallenge,
1.1.1.2 misho 779: uctl->auth.chap_mchallenge_len);
1.1 misho 780: /* uctlmd5 is expecting Response Value */
781: istgt_md5final(uctlmd5, &md5ctx);
782:
783: /* compare MD5 digest */
784: if (memcmp(uctlmd5, resmd5, ISTGT_MD5DIGEST_LEN) != 0) {
785: /* not match */
786: fprintf(stderr, "ERROR auth user or secret is missing\n");
787: /* discard result line */
788: if (rc != UCTL_CMD_OK) {
789: return rc;
790: }
791: arg = trim_string(uctl->recvbuf);
792: result = strsepq(&arg, delim);
793: strupr(result);
794: if (strcmp(result, "OK") != 0) {
795: fprintf(stderr, "ERROR %s\n", arg);
796: return UCTL_CMD_ERR;
797: }
798: /* final with ERR */
799: return UCTL_CMD_ERR;
800: }
801: } else {
802: /* not mutual */
803: /* send CHAP_NR */
804: uctl_snprintf(uctl, "AUTH CHAP_NR %s %s\n",
1.1.1.2 misho 805: uctl->auth.user, hexmd5);
1.1 misho 806: rc = uctl_writeline(uctl);
807: if (rc != UCTL_CMD_OK) {
808: return rc;
809: }
810: }
811:
812: /* receive result */
813: rc = uctl_readline(uctl);
814: if (rc != UCTL_CMD_OK) {
815: return rc;
816: }
817: arg = trim_string(uctl->recvbuf);
818: result = strsepq(&arg, delim);
819: strupr(result);
820: if (strcmp(result, "OK") != 0) {
821: if (is_err_chap_seq(uctl, arg))
822: return UCTL_CMD_CHAPSEQ;
823: fprintf(stderr, "ERROR %s\n", arg);
824: return UCTL_CMD_ERR;
825: }
826: return UCTL_CMD_OK;
827: }
828:
829: static char *
830: uctl_get_nmval(CF_SECTION *sp, const char *key, int idx1, int idx2)
831: {
832: CF_ITEM *ip;
833: CF_VALUE *vp;
834: int i;
835:
836: ip = istgt_find_cf_nitem(sp, key, idx1);
837: if (ip == NULL)
838: return NULL;
839: vp = ip->val;
840: if (vp == NULL)
841: return NULL;
842: for (i = 0; vp != NULL; vp = vp->next) {
843: if (i == idx2)
844: return vp->value;
845: i++;
846: }
847: return NULL;
848: }
849:
850: static char *
851: uctl_get_nval(CF_SECTION *sp, const char *key, int idx)
852: {
853: CF_ITEM *ip;
854: CF_VALUE *vp;
855:
856: ip = istgt_find_cf_nitem(sp, key, idx);
857: if (ip == NULL)
858: return NULL;
859: vp = ip->val;
860: if (vp == NULL)
861: return NULL;
862: return vp->value;
863: }
864:
865: static char *
866: uctl_get_val(CF_SECTION *sp, const char *key)
867: {
868: return uctl_get_nval(sp, key, 0);
869: }
870:
871: static int
872: uctl_get_nintval(CF_SECTION *sp, const char *key, int idx)
873: {
874: const char *v;
875: int value;
876:
877: v = uctl_get_nval(sp, key, idx);
878: if (v == NULL)
879: return -1;
880: value = (int)strtol(v, NULL, 10);
881: return value;
882: }
883:
884: static int
885: uctl_get_intval(CF_SECTION *sp, const char *key)
886: {
887: return uctl_get_nintval(sp, key, 0);
888: }
889:
890: static int
891: uctl_init(UCTL_Ptr uctl)
892: {
893: CF_SECTION *sp;
894: const char *val;
895: const char *user, *muser;
896: const char *secret, *msecret;
897: int timeout;
898: int port;
899: int lun;
900: int i;
901:
902: sp = istgt_find_cf_section(uctl->config, "Global");
903: if (sp == NULL) {
904: fprintf(stderr, "find_cf_section failed()\n");
905: return -1;
906: }
907:
908: val = uctl_get_val(sp, "Comment");
909: if (val != NULL) {
910: /* nothing */
911: #ifdef TRACE_UCTL
912: printf("Comment %s\n", val);
913: #endif /* TRACE_UCTL */
914: }
915:
916: val = uctl_get_val(sp, "Host");
917: if (val == NULL) {
918: val = DEFAULT_UCTL_HOST;
919: }
920: uctl->host = xstrdup(val);
921: #ifdef TRACE_UCTL
922: printf("Host %s\n", uctl->host);
923: #endif /* TRACE_UCTL */
924:
925: port = uctl_get_intval(sp, "Port");
926: if (port < 0) {
927: port = DEFAULT_UCTL_PORT;
928: }
929: uctl->port = port;
930: #ifdef TRACE_UCTL
931: printf("Port %d\n", uctl->port);
932: #endif /* TRACE_UCTL */
933:
934: val = uctl_get_val(sp, "TargetName");
935: if (val == NULL) {
936: val = NULL;
937: }
938: uctl->iqn = xstrdup(val);
939: #ifdef TRACE_UCTL
940: printf("TargetName %s\n", uctl->iqn);
941: #endif /* TRACE_UCTL */
942:
943: lun = uctl_get_intval(sp, "Lun");
944: if (lun < 0) {
945: lun = DEFAULT_UCTL_LUN;
946: }
947: uctl->lun = lun;
948: #ifdef TRACE_UCTL
949: printf("Lun %d\n", uctl->lun);
950: #endif /* TRACE_UCTL */
951:
952: val = uctl_get_val(sp, "Flags");
953: if (val == NULL) {
954: val = DEFAULT_UCTL_MFLAGS;
955: }
956: uctl->mflags = xstrdup(val);
957: #ifdef TRACE_UCTL
958: printf("Flags %s\n", uctl->mflags);
959: #endif /* TRACE_UCTL */
960:
961: val = uctl_get_val(sp, "Size");
962: if (val == NULL) {
963: val = DEFAULT_UCTL_MSIZE;
964: }
965: uctl->msize = xstrdup(val);
966: #ifdef TRACE_UCTL
967: printf("Size %s\n", uctl->msize);
968: #endif /* TRACE_UCTL */
969:
970: timeout = uctl_get_intval(sp, "Timeout");
971: if (timeout < 0) {
972: timeout = DEFAULT_UCTL_TIMEOUT;
973: }
974: uctl->timeout = timeout;
975: #ifdef TRACE_UCTL
976: printf("Timeout %d\n", uctl->timeout);
977: #endif /* TRACE_UCTL */
978:
979: val = uctl_get_val(sp, "AuthMethod");
980: if (val == NULL) {
981: uctl->req_auth_auto = 0;
982: uctl->req_auth = 0;
983: } else {
984: uctl->req_auth_auto = 0;
985: for (i = 0; ; i++) {
986: val = uctl_get_nmval(sp, "AuthMethod", 0, i);
987: if (val == NULL)
988: break;
989: if (strcasecmp(val, "CHAP") == 0) {
990: uctl->req_auth = 1;
991: } else if (strcasecmp(val, "Mutual") == 0) {
992: uctl->req_auth_mutual = 1;
993: } else if (strcasecmp(val, "Auto") == 0) {
994: uctl->req_auth_auto = 1;
995: uctl->req_auth = 0;
996: uctl->req_auth_mutual = 0;
1.1.1.3 ! misho 997: } else if (strcasecmp(val, "None") == 0) {
! 998: uctl->req_auth = 0;
! 999: uctl->req_auth_mutual = 0;
1.1 misho 1000: } else {
1001: fprintf(stderr, "unknown auth\n");
1002: return -1;
1003: }
1004: }
1005: if (uctl->req_auth_mutual && !uctl->req_auth) {
1006: fprintf(stderr, "Mutual but not CHAP\n");
1007: return -1;
1008: }
1009: }
1010: #ifdef TRACE_UCTL
1011: if (uctl->req_auth == 0) {
1012: printf("AuthMethod Auto\n");
1013: } else {
1014: printf("AuthMethod %s %s\n",
1.1.1.2 misho 1015: uctl->req_auth ? "CHAP" : "",
1016: uctl->req_auth_mutual ? "Mutual" : "");
1.1 misho 1017: }
1018: #endif /* TRACE_UCTL */
1019:
1020: val = uctl_get_nval(sp, "Auth", 0);
1021: if (val == NULL) {
1022: user = secret = muser = msecret = NULL;
1023: } else {
1024: user = uctl_get_nmval(sp, "Auth", 0, 0);
1025: secret = uctl_get_nmval(sp, "Auth", 0, 1);
1026: muser = uctl_get_nmval(sp, "Auth", 0, 2);
1027: msecret = uctl_get_nmval(sp, "Auth", 0, 3);
1028: }
1029: uctl->auth.user = xstrdup(user);
1030: uctl->auth.secret = xstrdup(secret);
1031: uctl->auth.muser = xstrdup(muser);
1032: uctl->auth.msecret = xstrdup(msecret);
1033: #ifdef TRACE_UCTL
1034: printf("user=%s, secret=%s, muser=%s, msecret=%s\n",
1.1.1.2 misho 1035: user, secret, muser, msecret);
1.1 misho 1036: #endif /* TRACE_UCTL */
1037:
1038: return 0;
1039: }
1040:
1041: static void
1042: usage(void)
1043: {
1044: printf("istgtcotrol [options] <command> [<file>]\n");
1045: printf("options:\n");
1046: printf("default may be changed by configuration file\n");
1047: printf(" -c config config file (default %s)\n", DEFAULT_UCTL_CONFIG);
1048: printf(" -h host target host name or IP (default %s)\n", DEFAULT_UCTL_HOST);
1049: printf(" -p port port number (default %d)\n", DEFAULT_UCTL_PORT);
1050: printf(" -t target target iqn\n");
1051: printf(" -l lun target lun (default %d)\n", DEFAULT_UCTL_LUN);
1052: printf(" -f flags media flags (default %s)\n", DEFAULT_UCTL_MFLAGS);
1053: printf(" -s size media size (default %s)\n", DEFAULT_UCTL_MSIZE);
1054: printf(" -q quiet mode\n");
1055: printf(" -v verbose mode\n");
1056: printf(" -A method authentication method (CHAP/Mutual CHAP/Auto)\n");
1057: printf(" -U user auth user\n");
1058: printf(" -S secret auth secret\n");
1059: printf(" -M muser mutual auth user\n");
1060: printf(" -R msecret mutual auth secret\n");
1061: printf(" -H show this usage\n");
1062: printf(" -V show version\n");
1063: printf("command:\n");
1064: printf(" noop no operation\n");
1065: printf(" version show target version\n");
1066: printf(" list list all or specified target\n");
1067: printf(" load load media to specified unit\n");
1068: printf(" unload unload media from specified unit\n");
1069: printf(" change change media with <file> at specified unit\n");
1070: printf(" reset reset specified lun of target\n");
1071: printf(" info show connections of target\n");
1072: }
1073:
1074: int
1075: main(int argc, char *argv[])
1076: {
1077: const char *config_file = DEFAULT_UCTL_CONFIG;
1078: CONFIG *config;
1079: UCTL xuctl, *uctl;
1080: struct sigaction sigact, sigoldact;
1081: int (*func) (UCTL_Ptr);
1082: int port = -1;
1083: int lun = -1;
1084: const char *host = NULL;
1085: const char *mflags = NULL;
1086: const char *mfile = NULL;
1087: const char *msize = NULL;
1088: const char *mtype = DEFAULT_UCTL_MTYPE;
1089: char *target = NULL;
1090: char *user = NULL;
1091: char *secret = NULL;
1092: char *muser = NULL;
1093: char *msecret = NULL;
1094: char *cmd;
1095: char *banner;
1096: long l;
1097: int exec_result;
1098: int req_argc;
1099: int req_target;
1100: int quiet = 0;
1101: int verbose = 0;
1102: int req_auth = -1;
1103: int ch;
1104: int sock;
1105: int rc;
1106: int i;
1107:
1108: #ifdef HAVE_SETPROCTITLE
1109: setproctitle("version %s (%s)",
1.1.1.2 misho 1110: ISTGT_VERSION, ISTGT_EXTRA_VERSION);
1.1 misho 1111: #endif
1112:
1113: memset(&xuctl, 0, sizeof xuctl);
1114: uctl = &xuctl;
1115:
1116: while ((ch = getopt(argc, argv, "c:h:p:t:l:f:s:qvA:U:S:M:R:VH")) != -1) {
1117: switch (ch) {
1118: case 'c':
1119: config_file = optarg;
1120: break;
1121: case 'h':
1122: host = optarg;
1123: break;
1124: case 'p':
1125: l = strtol(optarg, NULL, 10);
1126: if (l < 0 || l > 65535) {
1127: fatal("invalid port %s\n", optarg);
1128: }
1129: port = (int) l;
1130: break;
1131: case 't':
1132: target = optarg;
1133: break;
1134: case 'l':
1135: l = strtol(optarg, NULL, 10);
1.1.1.2 misho 1136: if (l < 0 || l > 0x3fff) {
1.1 misho 1137: fatal("invalid lun %s\n", optarg);
1138: }
1139: lun = (int) l;
1140: break;
1141: case 'f':
1142: mflags = optarg;
1143: break;
1144: case 's':
1145: msize = optarg;
1146: break;
1147: case 'q':
1148: quiet = 1;
1149: break;
1150: case 'v':
1151: verbose = 1;
1152: break;
1153: case 'A':
1154: if (strcasecmp(optarg, "CHAP") == 0) {
1155: req_auth = 1;
1156: } else if (strcasecmp(optarg, "Mutual") == 0
1.1.1.2 misho 1157: || strcasecmp(optarg, "Mutual CHAP") == 0
1158: || strcasecmp(optarg, "CHAP Mutual") == 0) {
1.1 misho 1159: req_auth = 2;
1160: } else if (strcasecmp(optarg, "Auto") == 0) {
1161: req_auth = 0;
1162: } else {
1163: usage();
1164: exit(EXIT_SUCCESS);
1165: }
1166: break;
1167: case 'U':
1168: user = optarg;
1169: break;
1170: case 'S':
1171: secret = optarg;
1172: #ifndef HAVE_SETPROCTITLE
1173: secret = xstrdup(optarg);
1174: memset(optarg, 'x', strlen(optarg));
1175: #endif
1176: break;
1177: case 'M':
1178: muser = optarg;
1179: break;
1180: case 'R':
1181: msecret = optarg;
1182: #ifndef HAVE_SETPROCTITLE
1183: msecret = xstrdup(optarg);
1184: memset(optarg, 'x', strlen(optarg));
1185: #endif
1186: break;
1187: case 'V':
1188: printf("istgtcontrol version %s (%s)\n",
1.1.1.2 misho 1189: ISTGT_VERSION, ISTGT_EXTRA_VERSION);
1.1 misho 1190: exit(EXIT_SUCCESS);
1191: case 'H':
1192: default:
1193: usage();
1194: exit(EXIT_SUCCESS);
1195: }
1196: }
1197: argc -= optind;
1198: argv += optind;
1199:
1200: /* read config files */
1201: config = istgt_allocate_config();
1202: rc = istgt_read_config(config, config_file);
1203: if (rc < 0) {
1204: fprintf(stderr, "config error\n");
1205: exit(EXIT_FAILURE);
1206: }
1207: if (config->section == NULL) {
1208: fprintf(stderr, "empty config\n");
1209: istgt_free_config(config);
1210: exit(EXIT_FAILURE);
1211: }
1212: uctl->config = config;
1213: //istgt_print_config(config);
1214:
1.1.1.3 ! misho 1215: istgtcontrol_open_log();
! 1216:
1.1 misho 1217: /* take specified command */
1218: if (argc < 1) {
1219: error_usage_return:
1220: istgt_free_config(config);
1221: usage();
1222: exit(EXIT_FAILURE);
1223: }
1224: cmd = strupr(xstrdup(argv[0]));
1225: argc--;
1226: argv++;
1227:
1228: /* get function pointer and parameters for specified command */
1229: func = NULL;
1230: req_argc = -1;
1231: req_target = -1;
1232: for (i = 0; exec_table[i].name != NULL; i++) {
1233: if (cmd[0] == exec_table[i].name[0]
1234: && strcmp(cmd, exec_table[i].name) == 0) {
1235: func = exec_table[i].func;
1236: req_argc = exec_table[i].req_argc;
1237: req_target = exec_table[i].req_target;
1238: break;
1239: }
1240: }
1241: if (func == NULL) {
1242: istgt_free_config(config);
1243: fatal("unknown command %s\n", cmd);
1244: }
1245:
1246: /* patrameter check */
1247: if (argc < req_argc) {
1248: goto error_usage_return;
1249: }
1250: #if 0
1251: if (req_target) {
1252: if (target == NULL) {
1253: goto error_usage_return;
1254: }
1255: }
1256: #endif
1257:
1258: /* take args */
1259: if (strcmp(cmd, "CHANGE") == 0) {
1260: /* change require file */
1261: mfile = argv[0];
1262: }
1263:
1264: /* build parameters */
1.1.1.3 ! misho 1265: rc = uctl_init(uctl);
! 1266: if (rc < 0) {
! 1267: fprintf(stderr, "uctl_init() failed\n");
! 1268: istgt_free_config(config);
! 1269: exit(EXIT_FAILURE);
! 1270: }
1.1 misho 1271: uctl->recvtmpcnt = 0;
1272: uctl->recvtmpidx = 0;
1273: uctl->recvtmpsize = sizeof uctl->recvtmp;
1274: uctl->recvbufsize = sizeof uctl->recvbuf;
1275: uctl->sendbufsize = sizeof uctl->sendbuf;
1276: uctl->worksize = sizeof uctl->work;
1277:
1278: /* override by command line */
1279: if (user != NULL) {
1280: xfree(uctl->auth.user);
1281: uctl->auth.user = xstrdup(user);
1282: }
1283: if (secret != NULL) {
1284: xfree(uctl->auth.secret);
1285: uctl->auth.secret = xstrdup(secret);
1286: }
1287: if (muser != NULL) {
1288: xfree(uctl->auth.muser);
1289: uctl->auth.muser = xstrdup(muser);
1290: }
1291: if (msecret != NULL) {
1292: xfree(uctl->auth.msecret);
1293: uctl->auth.msecret = xstrdup(msecret);
1294: }
1295: if (req_target) {
1296: if (uctl->iqn == NULL
1297: && target == NULL) {
1298: goto error_usage_return;
1299: }
1300: }
1301: if (req_auth >= 0) {
1302: uctl->req_auth_auto = 1;
1303: uctl->req_auth = 0;
1304: uctl->req_auth_mutual = 0;
1305: if (req_auth > 1) {
1306: uctl->req_auth_auto = 0;
1307: uctl->req_auth = 1;
1308: uctl->req_auth_mutual = 1;
1309: } else if (req_auth > 0) {
1310: uctl->req_auth_auto = 0;
1311: uctl->req_auth = 1;
1312: }
1313: }
1314: #ifdef TRACE_UCTL
1315: printf("auto=%d, auth=%d, mutual=%d\n",
1.1.1.2 misho 1316: uctl->req_auth_auto, uctl->req_auth, uctl->req_auth_mutual);
1.1 misho 1317: #endif /* TRACE_UCTL */
1318:
1319: if (host != NULL) {
1320: xfree(uctl->host);
1321: uctl->host = xstrdup(host);
1322: }
1323: if (port >= 0) {
1324: uctl->port = port;
1325: }
1326: if (target != NULL) {
1327: xfree(uctl->iqn);
1328: if (strcasecmp(target, "ALL") == 0) {
1329: uctl->iqn = NULL;
1330: } else {
1331: uctl->iqn = escape_string(target);
1332: }
1333: }
1334: if (lun >= 0) {
1335: uctl->lun = lun;
1336: }
1337: if (mflags != NULL) {
1338: xfree(uctl->mflags);
1339: uctl->mflags = escape_string(mflags);
1340: }
1341: uctl->mfile = escape_string(mfile);
1342: if (msize != NULL) {
1343: xfree(uctl->msize);
1344: uctl->msize = escape_string(msize);
1345: }
1346: uctl->mtype = escape_string(mtype);
1347: uctl->cmd = escape_string(cmd);
1348:
1349: /* show setting */
1350: #define NULLP(S) ((S) == NULL ? "NULL" : (S))
1351: if (verbose) {
1352: printf("iqn=%s, lun=%d\n", NULLP(uctl->iqn), uctl->lun);
1353: printf("media file=%s, flags=%s, size=%s\n",
1.1.1.2 misho 1354: NULLP(uctl->mfile), NULLP(uctl->mflags), NULLP(uctl->msize));
1.1 misho 1355: }
1356:
1357: /* set signals */
1358: memset(&sigact, 0, sizeof sigact);
1359: memset(&sigoldact, 0, sizeof sigoldact);
1360: sigact.sa_handler = SIG_IGN;
1361: sigemptyset(&sigact.sa_mask);
1362: if (sigaction(SIGPIPE, &sigact, &sigoldact) != 0) {
1363: istgt_free_config(config);
1364: fatal("sigaction() failed");
1365: }
1366:
1367: /* connect to target */
1368: if (verbose) {
1369: printf("connect to %s:%d\n", uctl->host, uctl->port);
1370: }
1371: sock = istgt_connect(uctl->host, uctl->port);
1372: if (sock < 0) {
1373: istgt_free_config(config);
1374: fatal("istgt_connect(%s:%d) failed\n", uctl->host, uctl->port);
1375: }
1376: uctl->sock = sock;
1377:
1378: /* get target banner (ready to send) */
1379: banner = get_banner(uctl);
1380: if (banner == NULL) {
1381: close(uctl->sock);
1382: istgt_free_config(config);
1383: fatal("get_banner() failed\n");
1384: }
1385: if (verbose) {
1386: printf("target banner \"%s\"\n", banner);
1387: }
1388:
1389: /* authentication */
1390: retry_auth:
1391: if (uctl->req_auth) {
1392: rc = do_auth(uctl);
1393: if (rc != UCTL_CMD_OK) {
1394: if (rc == UCTL_CMD_REQAUTH
1395: || rc == UCTL_CMD_CHAPSEQ) {
1396: retry_auth_auto:
1397: /* Auth negotiation */
1398: if (uctl->req_auth == 0) {
1399: #ifdef TRCAE_UCTL
1400: printf("Auto negotiation CHAP\n");
1401: #endif /* TRCAE_UCTL */
1402: uctl->req_auth = 1;
1403: goto retry_auth;
1404: } else if (uctl->req_auth_mutual == 0) {
1405: #ifdef TRCAE_UCTL
1406: printf("Auto negotiation Mutual CHAP\n");
1407: #endif /* TRCAE_UCTL */
1408: uctl->req_auth_mutual = 1;
1409: goto retry_auth;
1410: }
1411: }
1412: if (!quiet) {
1413: printf("AUTH failed\n");
1414: }
1415: exec_result = rc;
1416: goto disconnect;
1417: }
1418: }
1419:
1420: /* send specified command */
1421: rc = func(uctl);
1422: exec_result = rc;
1423: if (rc != UCTL_CMD_OK) {
1424: if (rc == UCTL_CMD_REQAUTH
1425: || rc == UCTL_CMD_CHAPSEQ) {
1426: goto retry_auth_auto;
1427: }
1428: if (!quiet) {
1429: printf("ABORT %s command\n", uctl->cmd);
1430: }
1431: } else {
1432: if (!quiet) {
1433: printf("DONE %s command\n", uctl->cmd);
1434: }
1435: }
1436:
1437: /* disconnect from target */
1438: disconnect:
1439: rc = exec_quit(uctl);
1440: if (rc != UCTL_CMD_OK) {
1441: fprintf(stderr, "QUIT failed\n");
1442: /* error but continue */
1443: }
1444:
1445: /* cleanup */
1446: close(sock);
1447: xfree(uctl->host);
1448: xfree(uctl->iqn);
1449: xfree(uctl->mflags);
1450: xfree(uctl->mfile);
1451: xfree(uctl->msize);
1452: xfree(uctl->mtype);
1453: xfree(uctl->cmd);
1454: xfree(banner);
1455: xfree(cmd);
1456: istgt_free_config(config);
1.1.1.3 ! misho 1457: istgtcontrol_close_log();
1.1 misho 1458:
1459: /* return value as execution result */
1460: if (exec_result != UCTL_CMD_OK) {
1461: exit(EXIT_FAILURE);
1462: }
1463: return EXIT_SUCCESS;
1464: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>