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