libafscp: code cleanup
[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 #include <krb5.h>
42 #include "afscp.h"
43 #include "afscp_internal.h"
44
45 static int afscp_ncells = 0, afscp_cellsalloced = 0;
46 static struct afscp_cell *allcells = NULL;
47 static int afscp_nservers = 0, afscp_srvsalloced = 0;
48 static struct afscp_server **allservers = NULL;
49 static char *defcell = NULL;
50 static char *defrealm = NULL;
51 int afscp_errno = 0;
52
53 void
54 afscp_FreeAllCells(void)
55 {
56     int i;
57
58     if (allcells == NULL)
59         return;
60
61     for (i = 0; i < afscp_ncells; i++) {
62         if (allcells[i].realm != NULL)
63             free(allcells[i].realm);
64         if (allcells[i].fsservers != NULL)
65             free(allcells[i].fsservers);
66     }
67
68     free(allcells);
69     allcells = NULL;
70     afscp_ncells = 0;
71     afscp_cellsalloced = 0;
72 }
73
74 void
75 afscp_FreeAllServers(void)
76 {
77     if (allservers == NULL)
78         return;
79     free(allservers);
80     allservers = NULL;
81     afscp_nservers = 0;
82     afscp_srvsalloced = 0;
83 }
84
85 struct afscp_cell *
86 afscp_CellById(int id)
87 {
88     if (id >= afscp_ncells || id < 0)
89         return NULL;
90     return &allcells[id];
91 }
92
93 struct afscp_cell *
94 afscp_CellByName(const char *cellname, const char *realmname)
95 {
96     int i;
97     struct afscp_cell *newlist, *thecell;
98
99     if (cellname == NULL) {
100         return NULL;
101     }
102     for (i = 0; i < afscp_ncells; i++) {
103         if (strcmp(allcells[i].name, cellname) == 0) {
104             return &allcells[i];
105         }
106     }
107     if (afscp_ncells >= afscp_cellsalloced) {
108         if (afscp_cellsalloced)
109             afscp_cellsalloced = afscp_cellsalloced * 2;
110         else
111             afscp_cellsalloced = 4;
112         newlist =
113             realloc(allcells, afscp_cellsalloced * sizeof(struct afscp_cell));
114         if (newlist == NULL) {
115             return NULL;
116         }
117         allcells = newlist;
118     }
119     thecell = &allcells[afscp_ncells];
120     memset(thecell, 0, sizeof(struct afscp_cell));
121     strlcpy(thecell->name, cellname, sizeof(thecell->name));
122     if (realmname != NULL) {
123         thecell->realm = malloc(strlen(realmname) + 1);
124         memset(thecell->realm, 0, strlen(realmname) + 1);
125         strlcpy(thecell->realm, realmname, strlen(realmname) + 1);
126     } else {
127         thecell->realm = NULL;
128     }
129     if (_GetSecurityObject(thecell)) {
130         return NULL;
131     }
132     if (_GetVLservers(thecell)) {
133         RXS_Close(thecell->security);
134         return NULL;
135     }
136     thecell->id = afscp_ncells++;
137     return thecell;
138 }
139
140 struct afscp_cell *
141 afscp_DefaultCell(void)
142 {
143     struct afsconf_dir *dir;
144     char localcell[MAXCELLCHARS + 1];
145     int code;
146
147     if (defcell) {
148         return afscp_CellByName(defcell, defrealm);
149     }
150
151     dir = afsconf_Open(AFSCONF_CLIENTNAME);
152     if (dir == NULL) {
153         afscp_errno = AFSCONF_NODB;
154         return NULL;
155     }
156     code = afsconf_GetLocalCell(dir, localcell, MAXCELLCHARS);
157     if (code != 0) {
158         afscp_errno = code;
159         return NULL;
160     }
161     afsconf_Close(dir);
162     return afscp_CellByName(localcell, defrealm);
163 }
164
165 int
166 afscp_SetDefaultRealm(const char *realmname)
167 {
168     /* krb5_error_code k5ec; */
169     krb5_context k5con;
170     char *newdefrealm;
171     int code;
172
173     if (realmname == NULL) {
174         if (defrealm != NULL)
175             free(defrealm);
176         defrealm = NULL;
177         return 0;
178     }
179
180     code = krb5_init_context(&k5con);   /* see aklog.c main() */
181     if (code != 0) {
182         return -1;
183     }
184     /* k5ec = */
185     krb5_set_default_realm(k5con, realmname);
186     /* if (k5ec != KRB5KDC_ERR_NONE) {
187      * com_err("libafscp", k5ec, "k5ec = %d (compared to KRB5KDC_ERR_NONE = %d)", k5ec, KRB5KDC_ERR_NONE);
188      * return -1;
189      * } */
190     /* krb5_set_default_realm() is returning 0 on success, not KRB5KDC_ERR_NONE */
191     newdefrealm = strdup(realmname);
192     if (newdefrealm == NULL) {
193         return -1;
194     }
195     if (defrealm != NULL)
196         free(defrealm);
197     defrealm = newdefrealm;
198     return 0;
199 }
200
201 int
202 afscp_SetDefaultCell(const char *cellname)
203 {
204     struct afscp_cell *this;
205     char *newdefcell;
206     if (cellname == NULL) {
207         if (defcell != NULL)
208             free(defcell);
209         defcell = NULL;
210         return 0;
211     }
212
213     this = afscp_CellByName(cellname, defrealm);
214     if (this == NULL) {
215         return -1;
216     }
217     newdefcell = strdup(cellname);
218     if (newdefcell == NULL) {
219         return -1;
220     }
221     if (defcell != NULL)
222         free(defcell);
223     defcell = newdefcell;
224     return 0;
225 }
226
227 int
228 afscp_CellId(struct afscp_cell *cell)
229 {
230     if (cell == NULL)
231         return -1;
232     return cell->id;
233 }
234
235 static void
236 _xdr_free(bool_t(*fn) (XDR * xdrs, void *obj), void *obj)
237 {
238     XDR xdrs;
239     xdrs.x_op = XDR_FREE;
240     fn(&xdrs, obj);
241 }
242
243 static bool_t
244 _xdr_bulkaddrs(XDR * xdrs, void *objp)
245 {
246     return xdr_bulkaddrs(xdrs, objp);
247 }
248
249 struct afscp_server *
250 afscp_ServerById(struct afscp_cell *thecell, afsUUID * u)
251 {
252     /* impliment uniquifiers? */
253     int i, code;
254     struct afscp_server **newlist;
255     struct afscp_server **newall;
256     struct afscp_server *ret = NULL;
257     afsUUID tmp;
258     bulkaddrs addrs;
259     struct ListAddrByAttributes attrs;
260     afs_int32 nentries, uniq;
261     char s[512];
262     afsUUID_to_string(u, s, 511);
263     afs_dprintf(("GetServerByID %s\n", s));
264
265     for (i = 0; i < thecell->nservers; i++) {
266         if (afs_uuid_equal(&thecell->fsservers[i]->id, u)) {
267             return thecell->fsservers[i];
268         }
269     }
270
271     if (thecell->nservers >= thecell->srvsalloced) {
272         if (thecell->srvsalloced)
273             thecell->srvsalloced = thecell->srvsalloced * 2;
274         else
275             thecell->srvsalloced = 4;
276         newlist = realloc(thecell->fsservers,
277                           thecell->srvsalloced *
278                           sizeof(struct afscp_server *));
279         if (newlist == NULL) {
280             return NULL;
281         }
282         thecell->fsservers = newlist;
283     }
284     ret = malloc(sizeof(struct afscp_server));
285     if (ret == NULL) {
286         return NULL;
287     }
288     memset(ret, 0, sizeof(struct afscp_server));
289     thecell->fsservers[thecell->nservers] = ret;
290     memmove(&ret->id, u, sizeof(afsUUID));
291     ret->cell = thecell->id;
292     memset(&tmp, 0, sizeof(tmp));
293     memset(&addrs, 0, sizeof(addrs));
294     memset(&attrs, 0, sizeof(attrs));
295     attrs.Mask = VLADDR_UUID;
296     memmove(&attrs.uuid, u, sizeof(afsUUID));
297
298     code = ubik_VL_GetAddrsU(thecell->vlservers, 0, &attrs, &tmp,
299                              &uniq, &nentries, &addrs);
300     if (code != 0) {
301         return NULL;
302     }
303     if (nentries > AFS_MAXHOSTS) {
304         nentries = AFS_MAXHOSTS;
305         /* XXX I don't want to do *that* much dynamic allocation */
306         abort();
307     }
308
309     ret->naddrs = nentries;
310     for (i = 0; i < nentries; i++) {
311         ret->addrs[i] = htonl(addrs.bulkaddrs_val[i]);
312         ret->conns[i] = rx_NewConnection(ret->addrs[i],
313                                          htons(AFSCONF_FILEPORT),
314                                          1, thecell->security,
315                                          thecell->scindex);
316     }
317     _xdr_free(_xdr_bulkaddrs, &addrs);
318     thecell->nservers++;
319
320     if (afscp_nservers >= afscp_srvsalloced) {
321         if (afscp_srvsalloced)
322             afscp_srvsalloced = afscp_srvsalloced * 2;
323         else
324             afscp_srvsalloced = 4;
325         newall = realloc(allservers,
326                          afscp_srvsalloced * sizeof(struct afscp_server *));
327         if (newall == NULL) {
328             return ret;
329         }
330         allservers = newall;
331     }
332     ret->index = afscp_nservers;
333     allservers[afscp_nservers++] = ret;
334     return ret;
335 }
336
337 struct afscp_server *
338 afscp_ServerByAddr(struct afscp_cell *thecell, afs_uint32 addr)
339 {
340     /* implement uniquifiers? */
341     int i, j;
342     struct afscp_server **newlist;
343     struct afscp_server **newall;
344     struct afscp_server *ret = NULL;
345     afsUUID uuid;
346     bulkaddrs addrs;
347     struct ListAddrByAttributes attrs;
348     afs_int32 nentries, code, uniq;
349
350     if (thecell == NULL)
351         return ret;             /* cannot continue without thecell */
352
353     for (i = 0; i < thecell->nservers; i++) {
354         ret = thecell->fsservers[i];
355         for (j = 0; j < ret->naddrs; j++)
356             if (ret->addrs[j] == htonl(addr)) {
357                 return ret;
358             }
359     }
360
361     if (thecell->nservers >= thecell->srvsalloced) {
362         if (thecell->srvsalloced)
363             thecell->srvsalloced = thecell->srvsalloced * 2;
364         else
365             thecell->srvsalloced = 4;
366         newlist = realloc(thecell->fsservers,
367                           thecell->srvsalloced * sizeof(struct afscp_server));
368         if (newlist == NULL) {
369             return NULL;
370         }
371         thecell->fsservers = newlist;
372     }
373     ret = malloc(sizeof(struct afscp_server));
374     if (ret == NULL) {
375         return NULL;
376     }
377     memset(ret, 0, sizeof(struct afscp_server));
378     thecell->fsservers[thecell->nservers] = ret;
379     ret->cell = thecell->id;
380     memset(&uuid, 0, sizeof(uuid));
381     memset(&addrs, 0, sizeof(addrs));
382     memset(&attrs, 0, sizeof(attrs));
383     attrs.Mask = VLADDR_IPADDR;
384     attrs.ipaddr = addr;
385
386     code = ubik_VL_GetAddrsU(thecell->vlservers, 0, &attrs, &uuid,
387                              &uniq, &nentries, &addrs);
388     if (code != 0) {
389         memset(&ret->id, 0, sizeof(uuid));
390         ret->naddrs = 1;
391         ret->addrs[0] = htonl(addr);
392         ret->conns[0] = rx_NewConnection(ret->addrs[0],
393                                          htons(AFSCONF_FILEPORT),
394                                          1, thecell->security,
395                                          thecell->scindex);
396     } else {
397         char s[512];
398
399         afsUUID_to_string(&uuid, s, 511);
400         afs_dprintf(("GetServerByAddr 0x%x -> uuid %s\n", addr, s));
401
402         if (nentries > AFS_MAXHOSTS) {
403             nentries = AFS_MAXHOSTS;
404             /* XXX I don't want to do *that* much dynamic allocation */
405             abort();
406         }
407         memmove(&ret->id, &uuid, sizeof(afsUUID));
408
409         ret->naddrs = nentries;
410         for (i = 0; i < nentries; i++) {
411             ret->addrs[i] = htonl(addrs.bulkaddrs_val[i]);
412             ret->conns[i] = rx_NewConnection(ret->addrs[i],
413                                              htons(AFSCONF_FILEPORT),
414                                              1, thecell->security,
415                                              thecell->scindex);
416         }
417         _xdr_free(_xdr_bulkaddrs, &addrs);
418     }
419
420     thecell->nservers++;
421     if (afscp_nservers >= afscp_srvsalloced) {
422         if (afscp_srvsalloced)
423             afscp_srvsalloced = afscp_srvsalloced * 2;
424         else
425             afscp_srvsalloced = 4;
426         newall = realloc(allservers,
427                          afscp_srvsalloced * sizeof(struct afscp_server *));
428         if (newall == NULL) {
429             return ret;
430         }
431         allservers = newall;
432     }
433     ret->index = afscp_nservers;
434     allservers[afscp_nservers++] = ret;
435     return ret;
436 }
437
438 struct afscp_server *
439 afscp_AnyServerByAddr(afs_uint32 addr)
440 {
441     /* implement uniquifiers? */
442     int i, j;
443     struct afscp_server *ret = NULL;
444
445     if (allservers == NULL)
446         return ret;
447     for (i = 0; i < afscp_nservers; i++) {
448         ret = allservers[i];
449         for (j = 0; j < ret->naddrs; j++)
450             if (ret->addrs[j] == htonl(addr)) {
451                 return ret;
452             }
453     }
454     return NULL;
455 }
456
457 struct afscp_server *
458 afscp_ServerByIndex(int i)
459 {
460     if (i >= afscp_nservers || i < 0)
461         return NULL;
462     return allservers[i];
463 }
464
465 struct rx_connection *
466 afscp_ServerConnection(const struct afscp_server *srv, int i)
467 {
468     if (srv == NULL || srv->conns == NULL)
469         return NULL;
470     if (i >= srv->naddrs || i < 0)
471         return NULL;
472     return srv->conns[i];
473 }