cb96a6b69db04a28807bfacb81c5aab18d39747e
[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 void
79 afscp_SetConfDir(char *confDir)
80 {
81     if (confdir != NULL)
82         afsconf_Close(confdir);
83
84     confdir = afsconf_Open(confDir);
85 }
86
87 static int
88 _GetCellInfo(char *cell, struct afsconf_cell *celldata)
89 {
90     int code;
91     if (confdir == NULL)
92         confdir = afsconf_Open(AFSCONF_CLIENTNAME);
93     if (confdir == NULL) {
94         return AFSCONF_NODB;
95     }
96     code = afsconf_GetCellInfo(confdir, cell, AFSCONF_VLDBSERVICE, celldata);
97     return code;
98 }
99
100 static int
101 _GetNullSecurityObject(struct afscp_cell *cell)
102 {
103     cell->security = (struct rx_securityClass *)rxnull_NewClientSecurityObject();
104     cell->scindex = RX_SECIDX_NULL;
105     return 0;
106 }
107
108 int
109 _GetSecurityObject(struct afscp_cell *cell)
110 {
111     int code = ENOENT;
112 #ifdef HAVE_KERBEROS
113     krb5_context context;
114     krb5_creds match;
115     krb5_creds *cred;
116     krb5_ccache cc;
117     char **realms, *realm;
118     struct afsconf_cell celldata;
119     char localcell[MAXCELLCHARS + 1];
120     struct rx_securityClass *sc;
121     struct ktc_encryptionKey k;
122     int i;
123     rxkad_level l;
124     code = _GetCellInfo(cell->name, &celldata);
125     if (code != 0) {
126         goto try_anon;
127     }
128
129     code = krb5_init_context(&context); /* see aklog.c main() */
130     if (code != 0) {
131         goto try_anon;
132     }
133
134     if (cell->realm == NULL) {
135         realm = NULL;
136         code = krb5_get_host_realm(context, celldata.hostName[0], &realms);
137
138         if (code == 0) {
139             strlcpy(localcell, realms[0], sizeof(localcell));
140             krb5_free_host_realm(context, realms);
141             realm = localcell;
142         }
143     } else {
144         realm = cell->realm;
145         strlcpy(localcell, realm, MAXCELLCHARS + 1);
146     }
147     if (realm)
148         if (realm == NULL) {
149             for (i = 0; (i < MAXCELLCHARS && cell->name[i]); i++) {
150                 if (isalpha(cell->name[i]))
151                     localcell[i] = toupper(cell->name[i]);
152                 else
153                     localcell[i] = cell->name[i];
154             }
155             localcell[i] = '\0';
156             realm = localcell;
157         }
158     cc = NULL;
159     code = krb5_cc_default(context, &cc);
160
161     memset(&match, 0, sizeof(match));
162     Z_enctype(Z_credskey(&match)) = ENCTYPE_DES_CBC_CRC;
163
164     if (code == 0)
165         code = krb5_cc_get_principal(context, cc, &match.client);
166     if (code == 0)
167         code = krb5_build_principal(context, &match.server,
168                                     strlen(realm), realm,
169                                     "afs", cell->name, NULL);
170
171     if (code != 0) {
172         krb5_free_cred_contents(context, &match);
173         if (cc)
174             krb5_cc_close(context, cc);
175         krb5_free_context(context);
176         goto try_anon;
177     }
178
179     code = krb5_get_credentials(context, 0, cc, &match, &cred);
180     if (code != 0) {
181         krb5_free_principal(context, match.server);
182         match.server = NULL;
183
184         code = krb5_build_principal(context, &match.server,
185                                     strlen(realm), realm, "afs", (void *)NULL);
186         if (code == 0)
187             code = krb5_get_credentials(context, 0, cc, &match, &cred);
188         if (code != 0) {
189             krb5_free_cred_contents(context, &match);
190             if (cc)
191                 krb5_cc_close(context, cc);
192             krb5_free_context(context);
193             goto try_anon;
194         }
195     }
196
197     if (insecure)
198         l = rxkad_clear;
199     else
200         l = rxkad_crypt;
201     memcpy(&k.data, Z_keydata(Z_credskey(cred)), 8);
202     sc = (struct rx_securityClass *)rxkad_NewClientSecurityObject
203         (l, &k, RXKAD_TKT_TYPE_KERBEROS_V5,
204          cred->ticket.length, cred->ticket.data);
205     krb5_free_creds(context, cred);
206     krb5_free_cred_contents(context, &match);
207     if (cc)
208         krb5_cc_close(context, cc);
209     krb5_free_context(context);
210     cell->security = sc;
211     cell->scindex = 2;
212     return 0;
213
214     try_anon:
215 #endif /* HAVE_KERBEROS */
216     if (try_anonymous)
217         return _GetNullSecurityObject(cell);
218     else
219         return code;
220 }
221
222 int
223 _GetVLservers(struct afscp_cell *cell)
224 {
225     struct rx_connection *conns[MAXHOSTSPERCELL + 1];
226     int i;
227     int code;
228     struct afsconf_cell celldata;
229
230     code = _GetCellInfo(cell->name, &celldata);
231     if (code != 0) {
232         return code;
233     }
234
235     for (i = 0; i < celldata.numServers; i++) {
236         conns[i] = rx_NewConnection(celldata.hostAddr[i].sin_addr.s_addr,
237                                     htons(AFSCONF_VLDBPORT),
238                                     USER_SERVICE_ID, cell->security,
239                                     cell->scindex);
240     }
241     conns[i] = 0;
242     return ubik_ClientInit(conns, &cell->vlservers);
243 }