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