libafscp fixes
[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 /* takes server in host byte order */
338 struct afscp_server *
339 afscp_ServerByAddr(struct afscp_cell *thecell, afs_uint32 addr)
340 {
341     /* implement uniquifiers? */
342     int i, j;
343     struct afscp_server **newlist;
344     struct afscp_server **newall;
345     struct afscp_server *ret = NULL;
346     afsUUID uuid;
347     bulkaddrs addrs;
348     struct ListAddrByAttributes attrs;
349     afs_int32 nentries, code, uniq;
350
351     if (thecell == NULL)
352         return ret;             /* cannot continue without thecell */
353
354     for (i = 0; i < thecell->nservers; i++) {
355         ret = thecell->fsservers[i];
356         for (j = 0; j < ret->naddrs; j++)
357             if (ret->addrs[j] == htonl(addr)) {
358                 return ret;
359             }
360     }
361
362     if (thecell->nservers >= thecell->srvsalloced) {
363         if (thecell->srvsalloced)
364             thecell->srvsalloced = thecell->srvsalloced * 2;
365         else
366             thecell->srvsalloced = 4;
367         newlist = realloc(thecell->fsservers,
368                           thecell->srvsalloced * sizeof(struct afscp_server));
369         if (newlist == NULL) {
370             return NULL;
371         }
372         thecell->fsservers = newlist;
373     }
374     ret = malloc(sizeof(struct afscp_server));
375     if (ret == NULL) {
376         return NULL;
377     }
378     memset(ret, 0, sizeof(struct afscp_server));
379     thecell->fsservers[thecell->nservers] = ret;
380     ret->cell = thecell->id;
381     memset(&uuid, 0, sizeof(uuid));
382     memset(&addrs, 0, sizeof(addrs));
383     memset(&attrs, 0, sizeof(attrs));
384     attrs.Mask = VLADDR_IPADDR;
385     attrs.ipaddr = addr;
386
387     code = ubik_VL_GetAddrsU(thecell->vlservers, 0, &attrs, &uuid,
388                              &uniq, &nentries, &addrs);
389     if (code != 0) {
390         memset(&ret->id, 0, sizeof(uuid));
391         ret->naddrs = 1;
392         ret->addrs[0] = htonl(addr);
393         ret->conns[0] = rx_NewConnection(ret->addrs[0],
394                                          htons(AFSCONF_FILEPORT),
395                                          1, thecell->security,
396                                          thecell->scindex);
397     } else {
398         char s[512];
399
400         afsUUID_to_string(&uuid, s, 511);
401         afs_dprintf(("GetServerByAddr 0x%x -> uuid %s\n", addr, s));
402
403         if (nentries > AFS_MAXHOSTS) {
404             nentries = AFS_MAXHOSTS;
405             /* XXX I don't want to do *that* much dynamic allocation */
406             abort();
407         }
408         memmove(&ret->id, &uuid, sizeof(afsUUID));
409
410         ret->naddrs = nentries;
411         for (i = 0; i < nentries; i++) {
412             ret->addrs[i] = htonl(addrs.bulkaddrs_val[i]);
413             ret->conns[i] = rx_NewConnection(ret->addrs[i],
414                                              htons(AFSCONF_FILEPORT),
415                                              1, thecell->security,
416                                              thecell->scindex);
417         }
418         _xdr_free(_xdr_bulkaddrs, &addrs);
419     }
420
421     thecell->nservers++;
422     if (afscp_nservers >= afscp_srvsalloced) {
423         if (afscp_srvsalloced)
424             afscp_srvsalloced = afscp_srvsalloced * 2;
425         else
426             afscp_srvsalloced = 4;
427         newall = realloc(allservers,
428                          afscp_srvsalloced * sizeof(struct afscp_server *));
429         if (newall == NULL) {
430             return ret;
431         }
432         allservers = newall;
433     }
434     ret->index = afscp_nservers;
435     allservers[afscp_nservers++] = ret;
436     return ret;
437 }
438
439 /* takes server in host byte order */
440 struct afscp_server *
441 afscp_AnyServerByAddr(afs_uint32 addr)
442 {
443     /* implement uniquifiers? */
444     int i, j;
445     struct afscp_server *ret = NULL;
446
447     if (allservers == NULL)
448         return ret;
449     for (i = 0; i < afscp_nservers; i++) {
450         ret = allservers[i];
451         for (j = 0; j < ret->naddrs; j++)
452             if (ret->addrs[j] == htonl(addr)) {
453                 return ret;
454             }
455     }
456     return NULL;
457 }
458
459 struct afscp_server *
460 afscp_ServerByIndex(int i)
461 {
462     if (i >= afscp_nservers || i < 0)
463         return NULL;
464     return allservers[i];
465 }
466
467 struct rx_connection *
468 afscp_ServerConnection(const struct afscp_server *srv, int i)
469 {
470     if (srv == NULL || srv->conns == NULL)
471         return NULL;
472     if (i >= srv->naddrs || i < 0)
473         return NULL;
474     return srv->conns[i];
475 }