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