Disable deprecated warnings for krb5 routines
[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 # define KERBEROS_APPLE_DEPRECATED(x)
43 # include <krb5.h>
44 #endif
45 #include "afscp.h"
46 #include "afscp_internal.h"
47
48 static int afscp_ncells = 0, afscp_cellsalloced = 0;
49 static struct afscp_cell *allcells = NULL;
50 static int afscp_nservers = 0, afscp_srvsalloced = 0;
51 static struct afscp_server **allservers = NULL;
52 static char *defcell = NULL;
53 static char *defrealm = NULL;
54 int afscp_errno = 0;
55
56 void
57 afscp_FreeAllCells(void)
58 {
59     int i;
60
61     if (allcells == NULL)
62         return;
63
64     for (i = 0; i < afscp_ncells; i++) {
65         if (allcells[i].realm != NULL)
66             free(allcells[i].realm);
67         if (allcells[i].fsservers != NULL)
68             free(allcells[i].fsservers);
69     }
70
71     free(allcells);
72     allcells = NULL;
73     afscp_ncells = 0;
74     afscp_cellsalloced = 0;
75 }
76
77 void
78 afscp_FreeAllServers(void)
79 {
80     if (allservers == NULL)
81         return;
82     free(allservers);
83     allservers = NULL;
84     afscp_nservers = 0;
85     afscp_srvsalloced = 0;
86 }
87
88 struct afscp_cell *
89 afscp_CellById(int id)
90 {
91     if (id >= afscp_ncells || id < 0)
92         return NULL;
93     return &allcells[id];
94 }
95
96 struct afscp_cell *
97 afscp_CellByName(const char *cellname, const char *realmname)
98 {
99     int i;
100     struct afscp_cell *newlist, *thecell;
101
102     if (cellname == NULL) {
103         return NULL;
104     }
105     for (i = 0; i < afscp_ncells; i++) {
106         if (strcmp(allcells[i].name, cellname) == 0) {
107             return &allcells[i];
108         }
109     }
110     if (afscp_ncells >= afscp_cellsalloced) {
111         if (afscp_cellsalloced)
112             afscp_cellsalloced = afscp_cellsalloced * 2;
113         else
114             afscp_cellsalloced = 4;
115         newlist =
116             realloc(allcells, afscp_cellsalloced * sizeof(struct afscp_cell));
117         if (newlist == NULL) {
118             return NULL;
119         }
120         allcells = newlist;
121     }
122     thecell = &allcells[afscp_ncells];
123     memset(thecell, 0, sizeof(struct afscp_cell));
124     strlcpy(thecell->name, cellname, sizeof(thecell->name));
125     if (realmname != NULL) {
126         thecell->realm = strdup(realmname);
127     } else {
128         thecell->realm = NULL;
129     }
130     if (_GetSecurityObject(thecell)) {
131         return NULL;
132     }
133     if (_GetVLservers(thecell)) {
134         RXS_Close(thecell->security);
135         return NULL;
136     }
137     thecell->id = afscp_ncells++;
138     return thecell;
139 }
140
141 struct afscp_cell *
142 afscp_DefaultCell(void)
143 {
144     struct afsconf_dir *dir;
145     char localcell[MAXCELLCHARS + 1];
146     int code;
147
148     if (defcell) {
149         return afscp_CellByName(defcell, defrealm);
150     }
151
152     dir = afsconf_Open(AFSCONF_CLIENTNAME);
153     if (dir == NULL) {
154         afscp_errno = AFSCONF_NODB;
155         return NULL;
156     }
157     code = afsconf_GetLocalCell(dir, localcell, MAXCELLCHARS);
158     if (code != 0) {
159         afscp_errno = code;
160         return NULL;
161     }
162     afsconf_Close(dir);
163     return afscp_CellByName(localcell, defrealm);
164 }
165
166 int
167 afscp_SetDefaultRealm(const char *realmname)
168 {
169     char *newdefrealm;
170
171 #ifdef HAVE_KERBEROS
172     /* krb5_error_code k5ec; */
173     krb5_context k5con;
174     int code;
175
176     if (realmname == NULL) {
177         if (defrealm != NULL)
178             free(defrealm);
179         defrealm = NULL;
180         return 0;
181     }
182
183     code = krb5_init_context(&k5con);   /* see aklog.c main() */
184     if (code != 0) {
185         return -1;
186     }
187     /* k5ec = */
188     krb5_set_default_realm(k5con, realmname);
189     /* if (k5ec != KRB5KDC_ERR_NONE) {
190      * com_err("libafscp", k5ec, "k5ec = %d (compared to KRB5KDC_ERR_NONE = %d)", k5ec, KRB5KDC_ERR_NONE);
191      * return -1;
192      * } */
193     /* krb5_set_default_realm() is returning 0 on success, not KRB5KDC_ERR_NONE */
194 #endif /* HAVE_KERBEROS */
195
196     newdefrealm = strdup(realmname);
197     if (newdefrealm == NULL) {
198         return -1;
199     }
200     if (defrealm != NULL)
201         free(defrealm);
202     defrealm = newdefrealm;
203     return 0;
204 }
205
206 int
207 afscp_SetDefaultCell(const char *cellname)
208 {
209     struct afscp_cell *this;
210     char *newdefcell;
211     if (cellname == NULL) {
212         if (defcell != NULL)
213             free(defcell);
214         defcell = NULL;
215         return 0;
216     }
217
218     this = afscp_CellByName(cellname, defrealm);
219     if (this == NULL) {
220         return -1;
221     }
222     newdefcell = strdup(cellname);
223     if (newdefcell == NULL) {
224         return -1;
225     }
226     if (defcell != NULL)
227         free(defcell);
228     defcell = newdefcell;
229     return 0;
230 }
231
232 int
233 afscp_CellId(struct afscp_cell *cell)
234 {
235     if (cell == NULL)
236         return -1;
237     return cell->id;
238 }
239
240 static void
241 _xdr_free(bool_t(*fn) (XDR * xdrs, void *obj), void *obj)
242 {
243     XDR xdrs;
244     xdrs.x_op = XDR_FREE;
245     fn(&xdrs, obj);
246 }
247
248 static bool_t
249 _xdr_bulkaddrs(XDR * xdrs, void *objp)
250 {
251     return xdr_bulkaddrs(xdrs, objp);
252 }
253
254 /* takes server in host byte order */
255 struct afscp_server *
256 afscp_ServerById(struct afscp_cell *thecell, afsUUID * u)
257 {
258     /* impliment uniquifiers? */
259     int i, code;
260     struct afscp_server **newlist;
261     struct afscp_server **newall;
262     struct afscp_server *ret = NULL;
263     afsUUID tmp;
264     bulkaddrs addrs;
265     struct ListAddrByAttributes attrs;
266     afs_int32 nentries, uniq;
267     char s[512];
268     afsUUID_to_string(u, s, 511);
269     afs_dprintf(("GetServerByID %s\n", s));
270
271     for (i = 0; i < thecell->nservers; i++) {
272         if (afs_uuid_equal(&thecell->fsservers[i]->id, u)) {
273             return thecell->fsservers[i];
274         }
275     }
276
277     if (thecell->nservers >= thecell->srvsalloced) {
278         if (thecell->srvsalloced)
279             thecell->srvsalloced = thecell->srvsalloced * 2;
280         else
281             thecell->srvsalloced = 4;
282         newlist = realloc(thecell->fsservers,
283                           thecell->srvsalloced *
284                           sizeof(struct afscp_server *));
285         if (newlist == NULL) {
286             return NULL;
287         }
288         thecell->fsservers = newlist;
289     }
290     ret = calloc(1, sizeof(struct afscp_server));
291     if (ret == NULL) {
292         return NULL;
293     }
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
374                               * sizeof(struct afscp_server *));
375         if (newlist == NULL) {
376             return NULL;
377         }
378         thecell->fsservers = newlist;
379     }
380     ret = calloc(1, sizeof(struct afscp_server));
381     if (ret == NULL) {
382         return NULL;
383     }
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 }