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