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