Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / libafscp / afscp_server.c
1 /* AUTORIGHTS
2 Copyright (C) 2003 - 2010 Chaskiel Grundman
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
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 #include <afsconfig.h>
28 #include <afs/param.h>
29
30 #include <roken.h>
31
32 #include <afs/vlserver.h>
33 #include <afs/vldbint.h>
34 #include <afs/volint.h>
35 #include <afs/cellconfig.h>
36 #ifndef AFSCONF_CLIENTNAME
37 #include <afs/dirpath.h>
38 #define AFSCONF_CLIENTNAME AFSDIR_CLIENT_ETC_DIRPATH
39 #endif
40 #include <rx/rx.h>
41 #ifdef HAVE_KERBEROS
42 # define KERBEROS_APPLE_DEPRECATED(x)
43 # include <krb5.h>
44 #endif
45 #include "afscp.h"
46 #include "afscp_internal.h"
47
48 static int afscp_ncells = 0, afscp_cellsalloced = 0;
49 static struct afscp_cell *allcells = NULL;
50 static int afscp_nservers = 0, afscp_srvsalloced = 0;
51 static struct afscp_server **allservers = NULL;
52 static char *defcell = NULL;
53 static char *defrealm = NULL;
54 int afscp_errno = 0;
55
56 void
57 afscp_FreeAllCells(void)
58 {
59 int i;
60
61 if (allcells == NULL)
62 return;
63
64 for (i = 0; i < afscp_ncells; i++) {
65 if (allcells[i].realm != NULL)
66 free(allcells[i].realm);
67 if (allcells[i].fsservers != NULL)
68 free(allcells[i].fsservers);
69 }
70
71 free(allcells);
72 allcells = NULL;
73 afscp_ncells = 0;
74 afscp_cellsalloced = 0;
75 }
76
77 void
78 afscp_FreeAllServers(void)
79 {
80 if (allservers == NULL)
81 return;
82 free(allservers);
83 allservers = NULL;
84 afscp_nservers = 0;
85 afscp_srvsalloced = 0;
86 }
87
88 struct afscp_cell *
89 afscp_CellById(int id)
90 {
91 if (id >= afscp_ncells || id < 0)
92 return NULL;
93 return &allcells[id];
94 }
95
96 struct afscp_cell *
97 afscp_CellByName(const char *cellname, const char *realmname)
98 {
99 int i;
100 struct afscp_cell *newlist, *thecell;
101
102 if (cellname == NULL) {
103 return NULL;
104 }
105 for (i = 0; i < afscp_ncells; i++) {
106 if (strcmp(allcells[i].name, cellname) == 0) {
107 return &allcells[i];
108 }
109 }
110 if (afscp_ncells >= afscp_cellsalloced) {
111 if (afscp_cellsalloced)
112 afscp_cellsalloced = afscp_cellsalloced * 2;
113 else
114 afscp_cellsalloced = 4;
115 newlist =
116 realloc(allcells, afscp_cellsalloced * sizeof(struct afscp_cell));
117 if (newlist == NULL) {
118 return NULL;
119 }
120 allcells = newlist;
121 }
122 thecell = &allcells[afscp_ncells];
123 memset(thecell, 0, sizeof(struct afscp_cell));
124 strlcpy(thecell->name, cellname, sizeof(thecell->name));
125 if (realmname != NULL) {
126 thecell->realm = strdup(realmname);
127 } else {
128 thecell->realm = NULL;
129 }
130 if (_GetSecurityObject(thecell)) {
131 return NULL;
132 }
133 if (_GetVLservers(thecell)) {
134 RXS_Close(thecell->security);
135 return NULL;
136 }
137 thecell->id = afscp_ncells++;
138 return thecell;
139 }
140
141 struct afscp_cell *
142 afscp_DefaultCell(void)
143 {
144 struct afsconf_dir *dir;
145 char localcell[MAXCELLCHARS + 1];
146 int code;
147
148 if (defcell) {
149 return afscp_CellByName(defcell, defrealm);
150 }
151
152 dir = afsconf_Open(AFSCONF_CLIENTNAME);
153 if (dir == NULL) {
154 afscp_errno = AFSCONF_NODB;
155 return NULL;
156 }
157 code = afsconf_GetLocalCell(dir, localcell, MAXCELLCHARS);
158 if (code != 0) {
159 afscp_errno = code;
160 return NULL;
161 }
162 afsconf_Close(dir);
163 return afscp_CellByName(localcell, defrealm);
164 }
165
166 int
167 afscp_SetDefaultRealm(const char *realmname)
168 {
169 char *newdefrealm;
170
171 #ifdef HAVE_KERBEROS
172 /* krb5_error_code k5ec; */
173 krb5_context k5con;
174 int code;
175
176 if (realmname == NULL) {
177 if (defrealm != NULL)
178 free(defrealm);
179 defrealm = NULL;
180 return 0;
181 }
182
183 code = krb5_init_context(&k5con); /* see aklog.c main() */
184 if (code != 0) {
185 return -1;
186 }
187 /* k5ec = */
188 krb5_set_default_realm(k5con, realmname);
189 /* if (k5ec != KRB5KDC_ERR_NONE) {
190 * com_err("libafscp", k5ec, "k5ec = %d (compared to KRB5KDC_ERR_NONE = %d)", k5ec, KRB5KDC_ERR_NONE);
191 * return -1;
192 * } */
193 /* krb5_set_default_realm() is returning 0 on success, not KRB5KDC_ERR_NONE */
194 #endif /* HAVE_KERBEROS */
195
196 newdefrealm = strdup(realmname);
197 if (newdefrealm == NULL) {
198 return -1;
199 }
200 if (defrealm != NULL)
201 free(defrealm);
202 defrealm = newdefrealm;
203 return 0;
204 }
205
206 int
207 afscp_SetDefaultCell(const char *cellname)
208 {
209 struct afscp_cell *this;
210 char *newdefcell;
211 if (cellname == NULL) {
212 if (defcell != NULL)
213 free(defcell);
214 defcell = NULL;
215 return 0;
216 }
217
218 this = afscp_CellByName(cellname, defrealm);
219 if (this == NULL) {
220 return -1;
221 }
222 newdefcell = strdup(cellname);
223 if (newdefcell == NULL) {
224 return -1;
225 }
226 if (defcell != NULL)
227 free(defcell);
228 defcell = newdefcell;
229 return 0;
230 }
231
232 int
233 afscp_CellId(struct afscp_cell *cell)
234 {
235 if (cell == NULL)
236 return -1;
237 return cell->id;
238 }
239
240 static void
241 _xdr_free(bool_t(*fn) (XDR * xdrs, void *obj), void *obj)
242 {
243 XDR xdrs;
244 xdrs.x_op = XDR_FREE;
245 fn(&xdrs, obj);
246 }
247
248 static bool_t
249 _xdr_bulkaddrs(XDR * xdrs, void *objp)
250 {
251 return xdr_bulkaddrs(xdrs, objp);
252 }
253
254 /* takes server in host byte order */
255 struct afscp_server *
256 afscp_ServerById(struct afscp_cell *thecell, afsUUID * u)
257 {
258 /* impliment uniquifiers? */
259 int i, code;
260 struct afscp_server **newlist;
261 struct afscp_server **newall;
262 struct afscp_server *ret = NULL;
263 afsUUID tmp;
264 bulkaddrs addrs;
265 struct ListAddrByAttributes attrs;
266 afs_int32 nentries, uniq;
267 char s[512];
268 afsUUID_to_string(u, s, 511);
269 afs_dprintf(("GetServerByID %s\n", s));
270
271 for (i = 0; i < thecell->nservers; i++) {
272 if (afs_uuid_equal(&thecell->fsservers[i]->id, u)) {
273 return thecell->fsservers[i];
274 }
275 }
276
277 if (thecell->nservers >= thecell->srvsalloced) {
278 if (thecell->srvsalloced)
279 thecell->srvsalloced = thecell->srvsalloced * 2;
280 else
281 thecell->srvsalloced = 4;
282 newlist = realloc(thecell->fsservers,
283 thecell->srvsalloced *
284 sizeof(struct afscp_server *));
285 if (newlist == NULL) {
286 return NULL;
287 }
288 thecell->fsservers = newlist;
289 }
290 ret = calloc(1, sizeof(struct afscp_server));
291 if (ret == NULL) {
292 return NULL;
293 }
294 thecell->fsservers[thecell->nservers] = ret;
295 memmove(&ret->id, u, sizeof(afsUUID));
296 ret->cell = thecell->id;
297 memset(&tmp, 0, sizeof(tmp));
298 memset(&addrs, 0, sizeof(addrs));
299 memset(&attrs, 0, sizeof(attrs));
300 attrs.Mask = VLADDR_UUID;
301 memmove(&attrs.uuid, u, sizeof(afsUUID));
302
303 code = ubik_VL_GetAddrsU(thecell->vlservers, 0, &attrs, &tmp,
304 &uniq, &nentries, &addrs);
305 if (code != 0) {
306 return NULL;
307 }
308 if (nentries > AFS_MAXHOSTS) {
309 nentries = AFS_MAXHOSTS;
310 /* XXX I don't want to do *that* much dynamic allocation */
311 abort();
312 }
313
314 ret->naddrs = nentries;
315 for (i = 0; i < nentries; i++) {
316 ret->addrs[i] = htonl(addrs.bulkaddrs_val[i]);
317 ret->conns[i] = rx_NewConnection(ret->addrs[i],
318 htons(AFSCONF_FILEPORT),
319 1, thecell->security,
320 thecell->scindex);
321 }
322 _xdr_free(_xdr_bulkaddrs, &addrs);
323 thecell->nservers++;
324
325 if (afscp_nservers >= afscp_srvsalloced) {
326 if (afscp_srvsalloced)
327 afscp_srvsalloced = afscp_srvsalloced * 2;
328 else
329 afscp_srvsalloced = 4;
330 newall = realloc(allservers,
331 afscp_srvsalloced * sizeof(struct afscp_server *));
332 if (newall == NULL) {
333 return ret;
334 }
335 allservers = newall;
336 }
337 ret->index = afscp_nservers;
338 allservers[afscp_nservers++] = ret;
339 return ret;
340 }
341
342 /* takes server in host byte order */
343 struct afscp_server *
344 afscp_ServerByAddr(struct afscp_cell *thecell, afs_uint32 addr)
345 {
346 /* implement uniquifiers? */
347 int i, j;
348 struct afscp_server **newlist;
349 struct afscp_server **newall;
350 struct afscp_server *ret = NULL;
351 afsUUID uuid;
352 bulkaddrs addrs;
353 struct ListAddrByAttributes attrs;
354 afs_int32 nentries, code, uniq;
355
356 if (thecell == NULL)
357 return ret; /* cannot continue without thecell */
358
359 for (i = 0; i < thecell->nservers; i++) {
360 ret = thecell->fsservers[i];
361 for (j = 0; j < ret->naddrs; j++)
362 if (ret->addrs[j] == htonl(addr)) {
363 return ret;
364 }
365 }
366
367 if (thecell->nservers >= thecell->srvsalloced) {
368 if (thecell->srvsalloced)
369 thecell->srvsalloced = thecell->srvsalloced * 2;
370 else
371 thecell->srvsalloced = 4;
372 newlist = realloc(thecell->fsservers,
373 thecell->srvsalloced
374 * sizeof(struct afscp_server *));
375 if (newlist == NULL) {
376 return NULL;
377 }
378 thecell->fsservers = newlist;
379 }
380 ret = calloc(1, sizeof(struct afscp_server));
381 if (ret == NULL) {
382 return NULL;
383 }
384 thecell->fsservers[thecell->nservers] = ret;
385 ret->cell = thecell->id;
386 memset(&uuid, 0, sizeof(uuid));
387 memset(&addrs, 0, sizeof(addrs));
388 memset(&attrs, 0, sizeof(attrs));
389 attrs.Mask = VLADDR_IPADDR;
390 attrs.ipaddr = addr;
391
392 code = ubik_VL_GetAddrsU(thecell->vlservers, 0, &attrs, &uuid,
393 &uniq, &nentries, &addrs);
394 if (code != 0) {
395 memset(&ret->id, 0, sizeof(uuid));
396 ret->naddrs = 1;
397 ret->addrs[0] = htonl(addr);
398 ret->conns[0] = rx_NewConnection(ret->addrs[0],
399 htons(AFSCONF_FILEPORT),
400 1, thecell->security,
401 thecell->scindex);
402 } else {
403 char s[512];
404
405 afsUUID_to_string(&uuid, s, 511);
406 afs_dprintf(("GetServerByAddr 0x%x -> uuid %s\n", addr, s));
407
408 if (nentries > AFS_MAXHOSTS) {
409 nentries = AFS_MAXHOSTS;
410 /* XXX I don't want to do *that* much dynamic allocation */
411 abort();
412 }
413 memmove(&ret->id, &uuid, sizeof(afsUUID));
414
415 ret->naddrs = nentries;
416 for (i = 0; i < nentries; i++) {
417 ret->addrs[i] = htonl(addrs.bulkaddrs_val[i]);
418 ret->conns[i] = rx_NewConnection(ret->addrs[i],
419 htons(AFSCONF_FILEPORT),
420 1, thecell->security,
421 thecell->scindex);
422 }
423 _xdr_free(_xdr_bulkaddrs, &addrs);
424 }
425
426 thecell->nservers++;
427 if (afscp_nservers >= afscp_srvsalloced) {
428 if (afscp_srvsalloced)
429 afscp_srvsalloced = afscp_srvsalloced * 2;
430 else
431 afscp_srvsalloced = 4;
432 newall = realloc(allservers,
433 afscp_srvsalloced * sizeof(struct afscp_server *));
434 if (newall == NULL) {
435 return ret;
436 }
437 allservers = newall;
438 }
439 ret->index = afscp_nservers;
440 allservers[afscp_nservers++] = ret;
441 return ret;
442 }
443
444 /* takes server in host byte order */
445 struct afscp_server *
446 afscp_AnyServerByAddr(afs_uint32 addr)
447 {
448 /* implement uniquifiers? */
449 int i, j;
450 struct afscp_server *ret = NULL;
451
452 if (allservers == NULL)
453 return ret;
454 for (i = 0; i < afscp_nservers; i++) {
455 ret = allservers[i];
456 for (j = 0; j < ret->naddrs; j++)
457 if (ret->addrs[j] == htonl(addr)) {
458 return ret;
459 }
460 }
461 return NULL;
462 }
463
464 /* takes server in host byte order */
465 struct afscp_server *
466 afscp_ServerByIndex(int i)
467 {
468 if (i >= afscp_nservers || i < 0)
469 return NULL;
470 return allservers[i];
471 }
472
473 struct rx_connection *
474 afscp_ServerConnection(const struct afscp_server *srv, int i)
475 {
476 if (srv == NULL)
477 return NULL;
478 if (i >= srv->naddrs || i < 0)
479 return NULL;
480 return srv->conns[i];
481 }