defd690d37f1e5aff6feb187456c233c1fccaaaf
[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;
106     struct afsconf_cell celldata;
107     char localcell[MAXCELLCHARS + 1];
108     struct rx_securityClass *sc;
109     struct ktc_encryptionKey k;
110     int i;
111     rxkad_level l;
112     code = _GetCellInfo(cell->name, &celldata);
113     if (code != 0) {
114         goto try_anon;
115     }
116
117     code = krb5_init_context(&context); /* see aklog.c main() */
118     if (code != 0) {
119         goto try_anon;
120     }
121
122     if (cell->realm == NULL) {
123         realm = NULL;
124         code = krb5_get_host_realm(context, celldata.hostName[0], &realms);
125
126         if (code == 0) {
127             strlcpy(localcell, realms[0], sizeof(localcell));
128             krb5_free_host_realm(context, realms);
129             realm = localcell;
130         }
131     } else {
132         realm = cell->realm;
133         strlcpy(localcell, realm, MAXCELLCHARS + 1);
134     }
135     if (realm)
136         if (realm == NULL) {
137             for (i = 0; (i < MAXCELLCHARS && cell->name[i]); i++) {
138                 if (isalpha(cell->name[i]))
139                     localcell[i] = toupper(cell->name[i]);
140                 else
141                     localcell[i] = cell->name[i];
142             }
143             localcell[i] = '\0';
144             realm = localcell;
145         }
146     cc = NULL;
147     code = krb5_cc_default(context, &cc);
148
149     memset(&match, 0, sizeof(match));
150     Z_enctype(Z_credskey(&match)) = ENCTYPE_DES_CBC_CRC;
151
152     if (code == 0)
153         code = krb5_cc_get_principal(context, cc, &match.client);
154     if (code == 0)
155         code = krb5_build_principal(context, &match.server,
156                                     strlen(realm), realm,
157                                     "afs", cell->name, NULL);
158
159     if (code != 0) {
160         krb5_free_cred_contents(context, &match);
161         if (cc)
162             krb5_cc_close(context, cc);
163         krb5_free_context(context);
164         goto try_anon;
165     }
166
167     code = krb5_get_credentials(context, 0, cc, &match, &cred);
168     if (code != 0) {
169         krb5_free_principal(context, match.server);
170         match.server = NULL;
171
172         code = krb5_build_principal(context, &match.server,
173                                     strlen(realm), realm, "afs", (void *)NULL);
174         if (code == 0)
175             code = krb5_get_credentials(context, 0, cc, &match, &cred);
176         if (code != 0) {
177             krb5_free_cred_contents(context, &match);
178             if (cc)
179                 krb5_cc_close(context, cc);
180             krb5_free_context(context);
181             goto try_anon;
182         }
183     }
184
185     if (insecure)
186         l = rxkad_clear;
187     else
188         l = rxkad_crypt;
189     memcpy(&k.data, Z_keydata(Z_credskey(cred)), 8);
190     sc = (struct rx_securityClass *)rxkad_NewClientSecurityObject
191         (l, &k, RXKAD_TKT_TYPE_KERBEROS_V5,
192          cred->ticket.length, cred->ticket.data);
193     krb5_free_creds(context, cred);
194     krb5_free_cred_contents(context, &match);
195     if (cc)
196         krb5_cc_close(context, cc);
197     krb5_free_context(context);
198     cell->security = sc;
199     cell->scindex = 2;
200     return 0;
201
202     try_anon:
203     if (try_anonymous)
204         return _GetNullSecurityObject(cell);
205     else
206         return code;
207 }
208
209 int
210 _GetVLservers(struct afscp_cell *cell)
211 {
212     struct rx_connection *conns[MAXHOSTSPERCELL + 1];
213     int i;
214     int code;
215     struct afsconf_cell celldata;
216
217     code = _GetCellInfo(cell->name, &celldata);
218     if (code != 0) {
219         return code;
220     }
221
222     for (i = 0; i < celldata.numServers; i++) {
223         conns[i] = rx_NewConnection(celldata.hostAddr[i].sin_addr.s_addr,
224                                     htons(AFSCONF_VLDBPORT),
225                                     USER_SERVICE_ID, cell->security,
226                                     cell->scindex);
227     }
228     conns[i] = 0;
229     return ubik_ClientInit(conns, &cell->vlservers);
230 }