Build libafscp when we lack kerberos
[openafs.git] / src / libafscp / afscp_util.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 <ctype.h>
33 #include <afs/cellconfig.h>
34 #ifndef AFSCONF_CLIENTNAME
35 #include <afs/dirpath.h>
36 #define AFSCONF_CLIENTNAME AFSDIR_CLIENT_ETC_DIRPATH
37 #endif
38 #include <ubik.h>
39 #include <rx/rx_null.h>
40 #include <rx/rxkad.h>
41 #ifdef HAVE_KERBEROS
42 # include <krb5.h>
43 #endif
44 #include "afscp.h"
45 #include "afscp_internal.h"
46
47 #ifdef HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE
48 #define Z_keydata(keyblock)     ((keyblock)->contents)
49 #define Z_keylen(keyblock)      ((keyblock)->length)
50 #define Z_credskey(creds)       (&(creds)->keyblock)
51 #define Z_enctype(keyblock)     ((keyblock)->enctype)
52 #else
53 #define Z_keydata(keyblock)     ((keyblock)->keyvalue.data)
54 #define Z_keylen(keyblock)      ((keyblock)->keyvalue.length)
55 #define Z_credskey(creds)       (&(creds)->session)
56 #define Z_enctype(keyblock)     ((keyblock)->keytype)
57 #endif
58
59 static int insecure = 0;
60 static int try_anonymous = 0;
61
62 int
63 afscp_Insecure(void)
64 {
65     insecure = 1;
66     return 0;
67 }
68
69 int
70 afscp_AnonymousAuth(int state)
71 {
72     try_anonymous = state;
73     return 0;
74 }
75
76 static struct afsconf_dir *confdir;
77
78 static int
79 _GetCellInfo(char *cell, struct afsconf_cell *celldata)
80 {
81     int code;
82     if (confdir == NULL)
83         confdir = afsconf_Open(AFSCONF_CLIENTNAME);
84     if (confdir == NULL) {
85         return AFSCONF_NODB;
86     }
87     code = afsconf_GetCellInfo(confdir, cell, AFSCONF_VLDBSERVICE, celldata);
88     return code;
89 }
90
91 static int
92 _GetNullSecurityObject(struct afscp_cell *cell)
93 {
94     cell->security = (struct rx_securityClass *)rxnull_NewClientSecurityObject();
95     cell->scindex = RX_SECIDX_NULL;
96     return 0;
97 }
98
99 int
100 _GetSecurityObject(struct afscp_cell *cell)
101 {
102     int code = ENOENT;
103 #ifdef HAVE_KERBEROS
104     krb5_context context;
105     krb5_creds match;
106     krb5_creds *cred;
107     krb5_ccache cc;
108     char **realms, *realm;
109     struct afsconf_cell celldata;
110     char localcell[MAXCELLCHARS + 1];
111     struct rx_securityClass *sc;
112     struct ktc_encryptionKey k;
113     int i;
114     rxkad_level l;
115     code = _GetCellInfo(cell->name, &celldata);
116     if (code != 0) {
117         goto try_anon;
118     }
119
120     code = krb5_init_context(&context); /* see aklog.c main() */
121     if (code != 0) {
122         goto try_anon;
123     }
124
125     if (cell->realm == NULL) {
126         realm = NULL;
127         code = krb5_get_host_realm(context, celldata.hostName[0], &realms);
128
129         if (code == 0) {
130             strlcpy(localcell, realms[0], sizeof(localcell));
131             krb5_free_host_realm(context, realms);
132             realm = localcell;
133         }
134     } else {
135         realm = cell->realm;
136         strlcpy(localcell, realm, MAXCELLCHARS + 1);
137     }
138     if (realm)
139         if (realm == NULL) {
140             for (i = 0; (i < MAXCELLCHARS && cell->name[i]); i++) {
141                 if (isalpha(cell->name[i]))
142                     localcell[i] = toupper(cell->name[i]);
143                 else
144                     localcell[i] = cell->name[i];
145             }
146             localcell[i] = '\0';
147             realm = localcell;
148         }
149     cc = NULL;
150     code = krb5_cc_default(context, &cc);
151
152     memset(&match, 0, sizeof(match));
153     Z_enctype(Z_credskey(&match)) = ENCTYPE_DES_CBC_CRC;
154
155     if (code == 0)
156         code = krb5_cc_get_principal(context, cc, &match.client);
157     if (code == 0)
158         code = krb5_build_principal(context, &match.server,
159                                     strlen(realm), realm,
160                                     "afs", cell->name, NULL);
161
162     if (code != 0) {
163         krb5_free_cred_contents(context, &match);
164         if (cc)
165             krb5_cc_close(context, cc);
166         krb5_free_context(context);
167         goto try_anon;
168     }
169
170     code = krb5_get_credentials(context, 0, cc, &match, &cred);
171     if (code != 0) {
172         krb5_free_principal(context, match.server);
173         match.server = NULL;
174
175         code = krb5_build_principal(context, &match.server,
176                                     strlen(realm), realm, "afs", (void *)NULL);
177         if (code == 0)
178             code = krb5_get_credentials(context, 0, cc, &match, &cred);
179         if (code != 0) {
180             krb5_free_cred_contents(context, &match);
181             if (cc)
182                 krb5_cc_close(context, cc);
183             krb5_free_context(context);
184             goto try_anon;
185         }
186     }
187
188     if (insecure)
189         l = rxkad_clear;
190     else
191         l = rxkad_crypt;
192     memcpy(&k.data, Z_keydata(Z_credskey(cred)), 8);
193     sc = (struct rx_securityClass *)rxkad_NewClientSecurityObject
194         (l, &k, RXKAD_TKT_TYPE_KERBEROS_V5,
195          cred->ticket.length, cred->ticket.data);
196     krb5_free_creds(context, cred);
197     krb5_free_cred_contents(context, &match);
198     if (cc)
199         krb5_cc_close(context, cc);
200     krb5_free_context(context);
201     cell->security = sc;
202     cell->scindex = 2;
203     return 0;
204
205     try_anon:
206 #endif /* HAVE_KERBEROS */
207     if (try_anonymous)
208         return _GetNullSecurityObject(cell);
209     else
210         return code;
211 }
212
213 int
214 _GetVLservers(struct afscp_cell *cell)
215 {
216     struct rx_connection *conns[MAXHOSTSPERCELL + 1];
217     int i;
218     int code;
219     struct afsconf_cell celldata;
220
221     code = _GetCellInfo(cell->name, &celldata);
222     if (code != 0) {
223         return code;
224     }
225
226     for (i = 0; i < celldata.numServers; i++) {
227         conns[i] = rx_NewConnection(celldata.hostAddr[i].sin_addr.s_addr,
228                                     htons(AFSCONF_VLDBPORT),
229                                     USER_SERVICE_ID, cell->security,
230                                     cell->scindex);
231     }
232     conns[i] = 0;
233     return ubik_ClientInit(conns, &cell->vlservers);
234 }