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