afscp: avoid null dereference in _GetSecurityObject error case
[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         } else
143             goto try_anon;
144     } else {
145         realm = cell->realm;
146         strlcpy(localcell, realm, MAXCELLCHARS + 1);
147     }
148     if (realm)
149         if (realm == NULL) {
150             for (i = 0; (i < MAXCELLCHARS && cell->name[i]); i++) {
151                 if (isalpha(cell->name[i]))
152                     localcell[i] = toupper(cell->name[i]);
153                 else
154                     localcell[i] = cell->name[i];
155             }
156             localcell[i] = '\0';
157             realm = localcell;
158         }
159     cc = NULL;
160     code = krb5_cc_default(context, &cc);
161
162     memset(&match, 0, sizeof(match));
163     Z_enctype(Z_credskey(&match)) = ENCTYPE_DES_CBC_CRC;
164
165     if (code == 0)
166         code = krb5_cc_get_principal(context, cc, &match.client);
167     if (code == 0)
168         code = krb5_build_principal(context, &match.server,
169                                     strlen(realm), realm,
170                                     "afs", cell->name, NULL);
171
172     if (code != 0) {
173         krb5_free_cred_contents(context, &match);
174         if (cc)
175             krb5_cc_close(context, cc);
176         krb5_free_context(context);
177         goto try_anon;
178     }
179
180     code = krb5_get_credentials(context, 0, cc, &match, &cred);
181     if (code != 0) {
182         krb5_free_principal(context, match.server);
183         match.server = NULL;
184
185         code = krb5_build_principal(context, &match.server,
186                                     strlen(realm), realm, "afs", (void *)NULL);
187         if (code == 0)
188             code = krb5_get_credentials(context, 0, cc, &match, &cred);
189         if (code != 0) {
190             krb5_free_cred_contents(context, &match);
191             if (cc)
192                 krb5_cc_close(context, cc);
193             krb5_free_context(context);
194             goto try_anon;
195         }
196     }
197
198     if (insecure)
199         l = rxkad_clear;
200     else
201         l = rxkad_crypt;
202     memcpy(&k.data, Z_keydata(Z_credskey(cred)), 8);
203     sc = (struct rx_securityClass *)rxkad_NewClientSecurityObject
204         (l, &k, RXKAD_TKT_TYPE_KERBEROS_V5,
205          cred->ticket.length, cred->ticket.data);
206     krb5_free_creds(context, cred);
207     krb5_free_cred_contents(context, &match);
208     if (cc)
209         krb5_cc_close(context, cc);
210     krb5_free_context(context);
211     cell->security = sc;
212     cell->scindex = 2;
213     return 0;
214
215     try_anon:
216 #endif /* HAVE_KERBEROS */
217     if (try_anonymous)
218         return _GetNullSecurityObject(cell);
219     else
220         return code;
221 }
222
223 int
224 _GetVLservers(struct afscp_cell *cell)
225 {
226     struct rx_connection *conns[MAXHOSTSPERCELL + 1];
227     int i;
228     int code;
229     struct afsconf_cell celldata;
230
231     code = _GetCellInfo(cell->name, &celldata);
232     if (code != 0) {
233         return code;
234     }
235
236     for (i = 0; i < celldata.numServers; i++) {
237         conns[i] = rx_NewConnection(celldata.hostAddr[i].sin_addr.s_addr,
238                                     htons(AFSCONF_VLDBPORT),
239                                     USER_SERVICE_ID, cell->security,
240                                     cell->scindex);
241     }
242     conns[i] = 0;
243     return ubik_ClientInit(conns, &cell->vlservers);
244 }