~smb/ubuntu/oneiric/iscsitarget/proposed

« back to all changes in this revision

Viewing changes to .pc/debian-changes-1.4.20.2-5/usr/target.c

  • Committer: Stefan Bader
  • Date: 2011-06-29 11:04:54 UTC
  • mfrom: (2.1.13 experimental)
  • Revision ID: stefan.bader@canonical.com-20110629110454-zgjumob6217p3p1a
* Resynchronise with Debian experimental. Remaining changes:
  - If module unloading fails after stopping ietd, report it but still
    exit zero since this doesn't justify causing package operations to
    fail.
  - Install README.initiators and README.mcs.
* Sync to 1.4.20 branch. This is equivalent of 1.4.20.3 and includes all
  commits up till revision 1.4.20@453
* Add linux-headers packages to Suggests (Closes: #628428)
* Sync to 1.4.20 branch. This is equivalent of 1.4.20.3 and includes all
  commits up till revision 1.4.20@445
  (Closes: #618682, #622318, #610309)
* Last upload was incorrect. Really upload to unstable now
* Upload to unstable
* NIPQUAD definition has been removed in kernel 2.6.36,
  adjust kernel/conn.c accordingly so iscsitarget compiles
  against kernel 2.6.36. (Closes: #604641)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * target.c - ietd target handling
 
3
 *
 
4
 * Copyright (C) 2002-2003 Ardis Technolgies <roman at ardistech dot com>
 
5
 * Copyright (C) 2004-2010 VMware, Inc. All Rights Reserved.
 
6
 * Copyright (C) 2007-2010 Ross Walker <rswwalker at gmail dot com>
 
7
 *
 
8
 * This file is part of iSCSI Enterprise Target software.
 
9
 *
 
10
 * Released under the terms of the GNU GPL v2.0.
 
11
 *
 
12
 * This program is free software; you can redistribute it and/or
 
13
 * modify it under the terms of the GNU General Public License as
 
14
 * published by the Free Software Foundation; either version 2 of the
 
15
 * License, or (at your option) any later version.
 
16
 *
 
17
 * This program is distributed in the hope that it will be useful, but
 
18
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
20
 * General Public License for more details.
 
21
 *
 
22
 * You should have received a copy of the GNU General Public License
 
23
 * along with this program; if not, write to the Free Software
 
24
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 
25
 * 02110-1301 USA
 
26
 */
 
27
 
 
28
#include <ctype.h>
 
29
#include <dirent.h>
 
30
#include <errno.h>
 
31
#include <stdio.h>
 
32
#include <stdlib.h>
 
33
#include <string.h>
 
34
#include <netdb.h>
 
35
#include <ifaddrs.h>
 
36
#include <arpa/inet.h>
 
37
#include <netinet/in.h>
 
38
#include <sys/poll.h>
 
39
#include <sys/socket.h>
 
40
#include <sys/stat.h>
 
41
#include <sys/types.h>
 
42
 
 
43
#include "iscsid.h"
 
44
 
 
45
struct __qelem targets_list = LIST_HEAD_INIT(targets_list);
 
46
 
 
47
extern struct pollfd poll_array[POLL_MAX];
 
48
 
 
49
static int is_addr_loopback(char *addr)
 
50
{
 
51
        struct in_addr ia;
 
52
        struct in6_addr ia6;
 
53
 
 
54
        if (inet_pton(AF_INET, addr, &ia) == 1)
 
55
                return !strncmp(addr, "127.", 4);
 
56
 
 
57
        if (inet_pton(AF_INET6, addr, &ia6) == 1)
 
58
                return IN6_IS_ADDR_LOOPBACK(&ia6);
 
59
 
 
60
        return 0;
 
61
}
 
62
 
 
63
static int is_addr_unspecified(char *addr)
 
64
{
 
65
        struct in_addr ia;
 
66
        struct in6_addr ia6;
 
67
 
 
68
        if (inet_pton(AF_INET, addr, &ia) == 1)
 
69
                return (ia.s_addr == 0);
 
70
 
 
71
        if (inet_pton(AF_INET6, addr, &ia6) == 1)
 
72
                return IN6_IS_ADDR_UNSPECIFIED(&ia6);
 
73
 
 
74
        return 0;
 
75
}
 
76
 
 
77
static void target_print_addr(struct connection *conn, char *addr, int family)
 
78
{
 
79
        char taddr[NI_MAXHOST + NI_MAXSERV + 5];
 
80
 
 
81
        snprintf(taddr, sizeof(taddr),
 
82
                (family == AF_INET) ? "%s:%d,1" : "[%s]:%d,1",
 
83
                                                        addr, server_port);
 
84
 
 
85
        text_key_add(conn, "TargetAddress", taddr);
 
86
}
 
87
 
 
88
void target_list_build_ifaddrs(struct connection *conn, u32 tid, char *addr,
 
89
                                                                int family)
 
90
{
 
91
        struct ifaddrs *ifaddr, *ifa;
 
92
        char if_addr[NI_MAXHOST];
 
93
 
 
94
        getifaddrs(&ifaddr);
 
95
 
 
96
        for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
 
97
                if (!ifa->ifa_addr)
 
98
                        continue;
 
99
 
 
100
                int sa_family = ifa->ifa_addr->sa_family;
 
101
 
 
102
                if (sa_family == family) {
 
103
                        if (getnameinfo(ifa->ifa_addr, (family == AF_INET) ?
 
104
                                                sizeof(struct sockaddr_in) :
 
105
                                                sizeof(struct sockaddr_in6),
 
106
                                                if_addr, sizeof(if_addr),
 
107
                                                NULL, 0, NI_NUMERICHOST))
 
108
                                continue;
 
109
 
 
110
                        if (strcmp(addr, if_addr) && !is_addr_loopback(if_addr)
 
111
                                && cops->target_allow(tid, ifa->ifa_addr))
 
112
                                target_print_addr(conn, if_addr, family);
 
113
                }
 
114
        }
 
115
 
 
116
        freeifaddrs(ifaddr);
 
117
}
 
118
 
 
119
void target_list_build(struct connection *conn, char *name)
 
120
{
 
121
        struct target *target;
 
122
        struct sockaddr_storage ss1, ss2;
 
123
        socklen_t slen = sizeof(struct sockaddr_storage);
 
124
        char addr1[NI_MAXHOST], addr2[NI_MAXHOST];
 
125
        int ret, family, i;
 
126
 
 
127
        if (getsockname(conn->fd, (struct sockaddr *) &ss1, &slen)) {
 
128
                log_error("getsockname failed: %m");
 
129
                return;
 
130
        }
 
131
 
 
132
        ret = getnameinfo((struct sockaddr *) &ss1, slen, addr1,
 
133
                                sizeof(addr1), NULL, 0, NI_NUMERICHOST);
 
134
        if (ret) {
 
135
                log_error("getnameinfo failed: %s",
 
136
                        (ret == EAI_SYSTEM) ? strerror(errno) :
 
137
                                                        gai_strerror(ret));
 
138
                return;
 
139
        }
 
140
 
 
141
        family = ss1.ss_family;
 
142
 
 
143
        list_for_each_entry(target, &targets_list, tlist) {
 
144
                if (name && strcmp(target->name, name))
 
145
                        continue;
 
146
 
 
147
                if (!isns_scn_allow(target->tid, conn->initiator)
 
148
                        || !cops->initiator_allow(target->tid, conn->fd,
 
149
                                                        conn->initiator)
 
150
                        || !cops->target_allow(target->tid,
 
151
                                                (struct sockaddr *) &ss1))
 
152
                        continue;
 
153
 
 
154
                text_key_add(conn, "TargetName", target->name);
 
155
 
 
156
                target_print_addr(conn, addr1, family);
 
157
 
 
158
                for (i = 0; i < LISTEN_MAX && poll_array[i].fd; i++) {
 
159
                        slen = sizeof(struct sockaddr_storage);
 
160
 
 
161
                        if (getsockname(poll_array[i].fd,
 
162
                                        (struct sockaddr *) &ss2, &slen))
 
163
                                continue;
 
164
 
 
165
                        if (getnameinfo((struct sockaddr *) &ss2, slen, addr2,
 
166
                                sizeof(addr2), NULL, 0, NI_NUMERICHOST))
 
167
                                continue;
 
168
 
 
169
                        if (ss2.ss_family != family)
 
170
                                continue;
 
171
 
 
172
                        if (is_addr_unspecified(addr2))
 
173
                                target_list_build_ifaddrs(conn, target->tid,
 
174
                                                                addr1, family);
 
175
                        else if (strcmp(addr1, addr2)
 
176
                                && !is_addr_loopback(addr2)
 
177
                                && cops->target_allow(target->tid,
 
178
                                                (struct sockaddr *) &ss2))
 
179
                                target_print_addr(conn, addr2, family);
 
180
                }
 
181
        }
 
182
}
 
183
 
 
184
struct target* target_find_by_name(const char *name)
 
185
{
 
186
        struct target *target;
 
187
 
 
188
        list_for_each_entry(target, &targets_list, tlist) {
 
189
                if (!strcasecmp(target->name, name))
 
190
                        return target;
 
191
        }
 
192
 
 
193
        return NULL;
 
194
}
 
195
 
 
196
struct target* target_find_by_id(u32 tid)
 
197
{
 
198
        struct target *target;
 
199
 
 
200
        list_for_each_entry(target, &targets_list, tlist) {
 
201
                if (target->tid == tid)
 
202
                        return target;
 
203
        }
 
204
 
 
205
        return NULL;
 
206
}
 
207
 
 
208
static void all_accounts_del(u32 tid, int dir)
 
209
{
 
210
        char name[ISCSI_NAME_LEN], pass[ISCSI_NAME_LEN];
 
211
 
 
212
        memset(name, 0, sizeof(name));
 
213
 
 
214
        for (;cops->account_query(tid, dir, name, pass) != -ENOENT;
 
215
                memset(name, 0, sizeof(name))) {
 
216
                cops->account_del(tid, dir, name);
 
217
        }
 
218
 
 
219
}
 
220
 
 
221
int target_del(u32 tid)
 
222
{
 
223
        struct target *target = target_find_by_id(tid);
 
224
        int err;
 
225
 
 
226
        if (!target)
 
227
                return -ENOENT;
 
228
 
 
229
        if (!list_empty(&target->sessions_list)) {
 
230
                log_warning("%s: target %u still has sessions\n", __FUNCTION__,
 
231
                          tid);
 
232
                return -EBUSY;
 
233
        }
 
234
 
 
235
        err = ki->target_destroy(tid);
 
236
        if (err < 0) {
 
237
                log_error("unable to delete target %u: %d", tid, errno);
 
238
                return err;
 
239
        }
 
240
 
 
241
        remque(&target->tlist);
 
242
 
 
243
        all_accounts_del(tid, AUTH_DIR_INCOMING);
 
244
        all_accounts_del(tid, AUTH_DIR_OUTGOING);
 
245
 
 
246
        isns_target_deregister(target->name);
 
247
        free(target);
 
248
 
 
249
        return 0;
 
250
}
 
251
 
 
252
int target_add(u32 *tid, char *name)
 
253
{
 
254
        struct target *target;
 
255
        int err;
 
256
 
 
257
        if (!name)
 
258
                return -EINVAL;
 
259
 
 
260
        if (!(target = malloc(sizeof(*target))))
 
261
                return -ENOMEM;
 
262
 
 
263
        memset(target, 0, sizeof(*target));
 
264
        memcpy(target->name, name, sizeof(target->name) - 1);
 
265
 
 
266
        err = ki->target_create(tid, name);
 
267
        if (err < 0) {
 
268
                log_warning("unable create target %u: %d\n", *tid, errno);
 
269
                goto out;
 
270
        }
 
271
 
 
272
        INIT_LIST_HEAD(&target->tlist);
 
273
        INIT_LIST_HEAD(&target->sessions_list);
 
274
        INIT_LIST_HEAD(&target->isns_head);
 
275
        target->tid = *tid;
 
276
        insque(&target->tlist, &targets_list);
 
277
 
 
278
        isns_target_register(name);
 
279
 
 
280
        log_debug(1, "created target %s", name);
 
281
 
 
282
        return 0;
 
283
out:
 
284
        free(target);
 
285
        return err;
 
286
}
 
287
 
 
288
int target_redirected(struct target *target, struct connection *conn, struct sockaddr *sa)
 
289
{
 
290
        char tmp[NI_MAXHOST + 1];
 
291
        char addr[NI_MAXHOST + 3];
 
292
        char redirect[NI_MAXHOST + NI_MAXSERV + 4];
 
293
        char *p;
 
294
 
 
295
        if (!strlen(target->redirect.addr))
 
296
                return 0;
 
297
 
 
298
        if (getnameinfo(sa, (sa->sa_family == AF_INET) ?
 
299
                                        sizeof(struct sockaddr_in) :
 
300
                                        sizeof(struct sockaddr_in6),
 
301
                                        tmp, sizeof(tmp), NULL, 0,
 
302
                                        NI_NUMERICHOST))
 
303
                return 0;
 
304
 
 
305
        if ((p = strrchr(tmp, '%')))
 
306
                *p = '\0';
 
307
 
 
308
        if (sa->sa_family == AF_INET6)
 
309
                snprintf(addr, sizeof(addr), "[%s]", tmp);
 
310
        else
 
311
                snprintf(addr, sizeof(addr), "%s", tmp);
 
312
 
 
313
        snprintf(redirect, sizeof(redirect), "%s:%s", target->redirect.addr,
 
314
                strlen(target->redirect.port) ? target->redirect.port : "3260");
 
315
 
 
316
        if (strcmp(target->redirect.addr, addr)) {
 
317
                text_key_add(conn, "TargetAddress", redirect);
 
318
                return 1;
 
319
        }
 
320
 
 
321
        return 0;
 
322
}