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