Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / libafscp / afscp_util.c
1 /* AUTORIGHTS
2 Copyright (C) 2003 - 2010 Chaskiel Grundman
3 Copyright (c) 2011 Your Filesystem Inc.
4 Copyright (c) 2012 Sine Nomine Associates
5 All rights reserved
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions and the following disclaimer in the
16 documentation and/or other materials provided with the distribution.
17
18 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 #include <afsconfig.h>
30 #include <afs/param.h>
31
32 #include <roken.h>
33
34 #include <ctype.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 <ubik.h>
41 #include <rx/rx_null.h>
42 #include <rx/rxkad.h>
43 #ifdef HAVE_KERBEROS
44 # define KERBEROS_APPLE_DEPRECATED(x)
45 # include <krb5.h>
46 #endif
47 #include "afscp.h"
48 #include "afscp_internal.h"
49
50 #define HC_DEPRECATED
51 #include <hcrypto/des.h>
52
53 #ifdef HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE
54 #define Z_keydata(keyblock) ((keyblock)->contents)
55 #define Z_keylen(keyblock) ((keyblock)->length)
56 #define Z_credskey(creds) (&(creds)->keyblock)
57 #define Z_enctype(keyblock) ((keyblock)->enctype)
58 #else
59 #define Z_keydata(keyblock) ((keyblock)->keyvalue.data)
60 #define Z_keylen(keyblock) ((keyblock)->keyvalue.length)
61 #define Z_credskey(creds) (&(creds)->session)
62 #define Z_enctype(keyblock) ((keyblock)->keytype)
63 #endif
64
65 static int insecure = 0;
66 static int try_anonymous = 0;
67 static char authas_name[256];
68 static char authas_inst[256];
69
70 int
71 afscp_Insecure(void)
72 {
73 insecure = 1;
74 return 0;
75 }
76
77 int
78 afscp_AnonymousAuth(int state)
79 {
80 try_anonymous = state;
81 return 0;
82 }
83
84 /**
85 * Connect to all servers using authenticated connections, using the local
86 * KeyFile to appear as an arbitrary user.
87 *
88 * @param[in] aname The pts username to impersonate
89 *
90 * @note aname is krb4-based name, not a krb5 principal. So for example, you
91 * probably want to give "user.admin" instead of "user/admin".
92 *
93 * @return operation status
94 * @retval 0 success
95 */
96 int
97 afscp_LocalAuthAs(const char *aname)
98 {
99 const char *ainst = strchr(aname, '.');
100 size_t namelen, instlen;
101
102 if (ainst) {
103 namelen = ainst - aname;
104 ainst++;
105 instlen = strlen(ainst);
106 } else {
107 namelen = strlen(aname);
108 ainst = "";
109 instlen = 0;
110 }
111
112 if (namelen+1 > sizeof(authas_name) || instlen+1 > sizeof(authas_inst)) {
113 return EINVAL;
114 }
115 strncpy(authas_name, aname, namelen);
116 strncpy(authas_inst, ainst, instlen);
117 return 0;
118 }
119
120 static struct afsconf_dir *confdir;
121
122 void
123 afscp_SetConfDir(char *confDir)
124 {
125 if (confdir != NULL)
126 afsconf_Close(confdir);
127
128 confdir = afsconf_Open(confDir);
129 }
130
131 static int
132 _GetCellInfo(char *cell, struct afsconf_cell *celldata)
133 {
134 int code;
135 if (confdir == NULL)
136 confdir = afsconf_Open(AFSCONF_CLIENTNAME);
137 if (confdir == NULL) {
138 return AFSCONF_NODB;
139 }
140 code = afsconf_GetCellInfo(confdir, cell, AFSCONF_VLDBSERVICE, celldata);
141 return code;
142 }
143
144 static int
145 _GetNullSecurityObject(struct afscp_cell *cell)
146 {
147 cell->security = (struct rx_securityClass *)rxnull_NewClientSecurityObject();
148 cell->scindex = RX_SECIDX_NULL;
149 return 0;
150 }
151
152 static int
153 _GetLocalSecurityObject(struct afscp_cell *cell,
154 char *aname, char *ainst)
155 {
156 int code = 0;
157 char tbuffer[256];
158 struct ktc_encryptionKey key, session;
159 struct rx_securityClass *tc;
160 afs_int32 kvno;
161 afs_int32 ticketLen;
162 rxkad_level lev;
163 struct afsconf_dir *tdir;
164
165 tdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
166 if (!tdir) {
167 code = AFSCONF_FAILURE;
168 goto done;
169 }
170
171 code = afsconf_GetLatestKey(tdir, &kvno, &key);
172 if (code) {
173 goto done;
174 }
175
176 DES_init_random_number_generator((DES_cblock *)&key);
177 code = DES_new_random_key((DES_cblock *)&session);
178 if (code) {
179 goto done;
180 }
181
182 ticketLen = sizeof(tbuffer);
183 memset(tbuffer, 0, sizeof(tbuffer));
184 code = tkt_MakeTicket(tbuffer, &ticketLen, &key, aname, ainst, "", 0,
185 0xffffffff, &session, 0, "afs", "");
186 if (code) {
187 goto done;
188 }
189
190 if (insecure) {
191 lev = rxkad_clear;
192 } else {
193 lev = rxkad_crypt;
194 }
195
196 tc = (struct rx_securityClass *)
197 rxkad_NewClientSecurityObject(lev, &session, kvno, ticketLen,
198 tbuffer);
199 if (!tc) {
200 code = RXKADBADKEY;
201 goto done;
202 }
203
204 cell->security = tc;
205 cell->scindex = 2;
206
207 done:
208 if (tdir) {
209 afsconf_Close(tdir);
210 }
211 return code;
212 }
213
214 int
215 _GetSecurityObject(struct afscp_cell *cell)
216 {
217 int code = ENOENT;
218 #ifdef HAVE_KERBEROS
219 krb5_context context;
220 krb5_creds match;
221 krb5_creds *cred;
222 krb5_ccache cc;
223 char **realms, *realm;
224 struct afsconf_cell celldata;
225 char localcell[MAXCELLCHARS + 1];
226 struct rx_securityClass *sc;
227 struct ktc_encryptionKey k;
228 int i;
229 rxkad_level l;
230 code = _GetCellInfo(cell->name, &celldata);
231 if (code != 0) {
232 goto try_anon;
233 }
234
235 if (authas_name[0]) {
236 code = _GetLocalSecurityObject(cell, authas_name, authas_inst);
237 if (code == 0) {
238 return 0;
239 }
240 }
241
242 code = krb5_init_context(&context); /* see aklog.c main() */
243 if (code != 0) {
244 goto try_anon;
245 }
246
247 if (cell->realm == NULL) {
248 realm = NULL;
249 code = krb5_get_host_realm(context, celldata.hostName[0], &realms);
250
251 if (code == 0) {
252 strlcpy(localcell, realms[0], sizeof(localcell));
253 krb5_free_host_realm(context, realms);
254 realm = localcell;
255 } else
256 goto try_anon;
257 } else {
258 realm = cell->realm;
259 strlcpy(localcell, realm, MAXCELLCHARS + 1);
260 }
261 if (realm)
262 if (realm == NULL) {
263 for (i = 0; (i < MAXCELLCHARS && cell->name[i]); i++) {
264 if (isalpha(cell->name[i]))
265 localcell[i] = toupper(cell->name[i]);
266 else
267 localcell[i] = cell->name[i];
268 }
269 localcell[i] = '\0';
270 realm = localcell;
271 }
272 cc = NULL;
273 code = krb5_cc_default(context, &cc);
274
275 memset(&match, 0, sizeof(match));
276 Z_enctype(Z_credskey(&match)) = ENCTYPE_DES_CBC_CRC;
277
278 if (code == 0)
279 code = krb5_cc_get_principal(context, cc, &match.client);
280 if (code == 0)
281 code = krb5_build_principal(context, &match.server,
282 strlen(realm), realm,
283 "afs", cell->name, NULL);
284
285 if (code != 0) {
286 krb5_free_cred_contents(context, &match);
287 if (cc)
288 krb5_cc_close(context, cc);
289 krb5_free_context(context);
290 goto try_anon;
291 }
292
293 code = krb5_get_credentials(context, 0, cc, &match, &cred);
294 if (code != 0) {
295 krb5_free_principal(context, match.server);
296 match.server = NULL;
297
298 code = krb5_build_principal(context, &match.server,
299 strlen(realm), realm, "afs", NULL);
300 if (code == 0)
301 code = krb5_get_credentials(context, 0, cc, &match, &cred);
302 if (code != 0) {
303 krb5_free_cred_contents(context, &match);
304 if (cc)
305 krb5_cc_close(context, cc);
306 krb5_free_context(context);
307 goto try_anon;
308 }
309 }
310
311 if (insecure)
312 l = rxkad_clear;
313 else
314 l = rxkad_crypt;
315 memcpy(&k.data, Z_keydata(Z_credskey(cred)), 8);
316 sc = (struct rx_securityClass *)rxkad_NewClientSecurityObject
317 (l, &k, RXKAD_TKT_TYPE_KERBEROS_V5,
318 cred->ticket.length, cred->ticket.data);
319 krb5_free_creds(context, cred);
320 krb5_free_cred_contents(context, &match);
321 if (cc)
322 krb5_cc_close(context, cc);
323 krb5_free_context(context);
324 cell->security = sc;
325 cell->scindex = 2;
326 return 0;
327
328 try_anon:
329 #endif /* HAVE_KERBEROS */
330 if (try_anonymous)
331 return _GetNullSecurityObject(cell);
332 else
333 return code;
334 }
335
336 int
337 _GetVLservers(struct afscp_cell *cell)
338 {
339 struct rx_connection *conns[MAXHOSTSPERCELL + 1];
340 int i;
341 int code;
342 struct afsconf_cell celldata;
343
344 code = _GetCellInfo(cell->name, &celldata);
345 if (code != 0) {
346 return code;
347 }
348
349 for (i = 0; i < celldata.numServers; i++) {
350 conns[i] = rx_NewConnection(celldata.hostAddr[i].sin_addr.s_addr,
351 htons(AFSCONF_VLDBPORT),
352 USER_SERVICE_ID, cell->security,
353 cell->scindex);
354 }
355 conns[i] = 0;
356 return ubik_ClientInit(conns, &cell->vlservers);
357 }