84be5e864b93eb81f031b61b82c0d51afad1171f
[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 /* takes server in host byte order */
250 struct afscp_server *
251 afscp_ServerById(struct afscp_cell *thecell, afsUUID * u)
252 {
253     /* impliment uniquifiers? */
254     int i, code;
255     struct afscp_server **newlist;
256     struct afscp_server **newall;
257     struct afscp_server *ret = NULL;
258     afsUUID tmp;
259     bulkaddrs addrs;
260     struct ListAddrByAttributes attrs;
261     afs_int32 nentries, uniq;
262     char s[512];
263     afsUUID_to_string(u, s, 511);
264     afs_dprintf(("GetServerByID %s\n", s));
265
266     for (i = 0; i < thecell->nservers; i++) {
267         if (afs_uuid_equal(&thecell->fsservers[i]->id, u)) {
268             return thecell->fsservers[i];
269         }
270     }
271
272     if (thecell->nservers >= thecell->srvsalloced) {
273         if (thecell->srvsalloced)
274             thecell->srvsalloced = thecell->srvsalloced * 2;
275         else
276             thecell->srvsalloced = 4;
277         newlist = realloc(thecell->fsservers,
278                           thecell->srvsalloced *
279                           sizeof(struct afscp_server *));
280         if (newlist == NULL) {
281             return NULL;
282         }
283         thecell->fsservers = newlist;
284     }
285     ret = malloc(sizeof(struct afscp_server));
286     if (ret == NULL) {
287         return NULL;
288     }
289     memset(ret, 0, sizeof(struct afscp_server));
290     thecell->fsservers[thecell->nservers] = ret;
291     memmove(&ret->id, u, sizeof(afsUUID));
292     ret->cell = thecell->id;
293     memset(&tmp, 0, sizeof(tmp));
294     memset(&addrs, 0, sizeof(addrs));
295     memset(&attrs, 0, sizeof(attrs));
296     attrs.Mask = VLADDR_UUID;
297     memmove(&attrs.uuid, u, sizeof(afsUUID));
298
299     code = ubik_VL_GetAddrsU(thecell->vlservers, 0, &attrs, &tmp,
300                              &uniq, &nentries, &addrs);
301     if (code != 0) {
302         return NULL;
303     }
304     if (nentries > AFS_MAXHOSTS) {
305         nentries = AFS_MAXHOSTS;
306         /* XXX I don't want to do *that* much dynamic allocation */
307         abort();
308     }
309
310     ret->naddrs = nentries;
311     for (i = 0; i < nentries; i++) {
312         ret->addrs[i] = htonl(addrs.bulkaddrs_val[i]);
313         ret->conns[i] = rx_NewConnection(ret->addrs[i],
314                                          htons(AFSCONF_FILEPORT),
315                                          1, thecell->security,
316                                          thecell->scindex);
317     }
318     _xdr_free(_xdr_bulkaddrs, &addrs);
319     thecell->nservers++;
320
321     if (afscp_nservers >= afscp_srvsalloced) {
322         if (afscp_srvsalloced)
323             afscp_srvsalloced = afscp_srvsalloced * 2;
324         else
325             afscp_srvsalloced = 4;
326         newall = realloc(allservers,
327                          afscp_srvsalloced * sizeof(struct afscp_server *));
328         if (newall == NULL) {
329             return ret;
330         }
331         allservers = newall;
332     }
333     ret->index = afscp_nservers;
334     allservers[afscp_nservers++] = ret;
335     return ret;
336 }
337
338 /* takes server in host byte order */
339 struct afscp_server *
340 afscp_ServerByAddr(struct afscp_cell *thecell, afs_uint32 addr)
341 {
342     /* implement uniquifiers? */
343     int i, j;
344     struct afscp_server **newlist;
345     struct afscp_server **newall;
346     struct afscp_server *ret = NULL;
347     afsUUID uuid;
348     bulkaddrs addrs;
349     struct ListAddrByAttributes attrs;
350     afs_int32 nentries, code, uniq;
351
352     if (thecell == NULL)
353         return ret;             /* cannot continue without thecell */
354
355     for (i = 0; i < thecell->nservers; i++) {
356         ret = thecell->fsservers[i];
357         for (j = 0; j < ret->naddrs; j++)
358             if (ret->addrs[j] == htonl(addr)) {
359                 return ret;
360             }
361     }
362
363     if (thecell->nservers >= thecell->srvsalloced) {
364         if (thecell->srvsalloced)
365             thecell->srvsalloced = thecell->srvsalloced * 2;
366         else
367             thecell->srvsalloced = 4;
368         newlist = realloc(thecell->fsservers,
369                           thecell->srvsalloced * sizeof(struct afscp_server));
370         if (newlist == NULL) {
371             return NULL;
372         }
373         thecell->fsservers = newlist;
374     }
375     ret = malloc(sizeof(struct afscp_server));
376     if (ret == NULL) {
377         return NULL;
378     }
379     memset(ret, 0, sizeof(struct afscp_server));
380     thecell->fsservers[thecell->nservers] = ret;
381     ret->cell = thecell->id;
382     memset(&uuid, 0, sizeof(uuid));
383     memset(&addrs, 0, sizeof(addrs));
384     memset(&attrs, 0, sizeof(attrs));
385     attrs.Mask = VLADDR_IPADDR;
386     attrs.ipaddr = addr;
387
388     code = ubik_VL_GetAddrsU(thecell->vlservers, 0, &attrs, &uuid,
389                              &uniq, &nentries, &addrs);
390     if (code != 0) {
391         memset(&ret->id, 0, sizeof(uuid));
392         ret->naddrs = 1;
393         ret->addrs[0] = htonl(addr);
394         ret->conns[0] = rx_NewConnection(ret->addrs[0],
395                                          htons(AFSCONF_FILEPORT),
396                                          1, thecell->security,
397                                          thecell->scindex);
398     } else {
399         char s[512];
400
401         afsUUID_to_string(&uuid, s, 511);
402         afs_dprintf(("GetServerByAddr 0x%x -> uuid %s\n", addr, s));
403
404         if (nentries > AFS_MAXHOSTS) {
405             nentries = AFS_MAXHOSTS;
406             /* XXX I don't want to do *that* much dynamic allocation */
407             abort();
408         }
409         memmove(&ret->id, &uuid, sizeof(afsUUID));
410
411         ret->naddrs = nentries;
412         for (i = 0; i < nentries; i++) {
413             ret->addrs[i] = htonl(addrs.bulkaddrs_val[i]);
414             ret->conns[i] = rx_NewConnection(ret->addrs[i],
415                                              htons(AFSCONF_FILEPORT),
416                                              1, thecell->security,
417                                              thecell->scindex);
418         }
419         _xdr_free(_xdr_bulkaddrs, &addrs);
420     }
421
422     thecell->nservers++;
423     if (afscp_nservers >= afscp_srvsalloced) {
424         if (afscp_srvsalloced)
425             afscp_srvsalloced = afscp_srvsalloced * 2;
426         else
427             afscp_srvsalloced = 4;
428         newall = realloc(allservers,
429                          afscp_srvsalloced * sizeof(struct afscp_server *));
430         if (newall == NULL) {
431             return ret;
432         }
433         allservers = newall;
434     }
435     ret->index = afscp_nservers;
436     allservers[afscp_nservers++] = ret;
437     return ret;
438 }
439
440 /* takes server in host byte order */
441 struct afscp_server *
442 afscp_AnyServerByAddr(afs_uint32 addr)
443 {
444     /* implement uniquifiers? */
445     int i, j;
446     struct afscp_server *ret = NULL;
447
448     if (allservers == NULL)
449         return ret;
450     for (i = 0; i < afscp_nservers; i++) {
451         ret = allservers[i];
452         for (j = 0; j < ret->naddrs; j++)
453             if (ret->addrs[j] == htonl(addr)) {
454                 return ret;
455             }
456     }
457     return NULL;
458 }
459
460 /* takes server in host byte order */
461 struct afscp_server *
462 afscp_ServerByIndex(int i)
463 {
464     if (i >= afscp_nservers || i < 0)
465         return NULL;
466     return allservers[i];
467 }
468
469 struct rx_connection *
470 afscp_ServerConnection(const struct afscp_server *srv, int i)
471 {
472     if (srv == NULL || srv->conns == NULL)
473         return NULL;
474     if (i >= srv->naddrs || i < 0)
475         return NULL;
476     return srv->conns[i];
477 }