9c58f1424ba0afa356c5c9fed1b7cfe5cc3b650e
[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 <sys/socket.h>
28 #include <netinet/in.h>
29 #include <stdlib.h>
30 #include <ctype.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <errno.h>
34
35 #include <afs/param.h>
36 #include <afs/cellconfig.h>
37 #ifndef AFSCONF_CLIENTNAME
38 #include <afs/dirpath.h>
39 #define AFSCONF_CLIENTNAME AFSDIR_CLIENT_ETC_DIRPATH
40 #endif
41
42 #include <ubik.h>
43 #include <rx/rxkad.h>
44 #include <rx/rx_null.h>
45
46 #include <krb5.h>
47
48 #include "afscp.h"
49 #include "afscp_internal.h"
50
51 #define HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE
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 int _rx_InitRandomPort(void) {
66   int sock;
67   unsigned int port;
68   struct sockaddr_in sin;
69
70   sock=socket(PF_INET, SOCK_DGRAM, 0);
71   if (sock == -1)
72     return errno;
73   sin.sin_family=AF_INET;
74   sin.sin_addr.s_addr=INADDR_ANY;
75   sin.sin_port=0;
76   if (bind(sock, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) < 0)
77     return errno;
78
79   port=sizeof(struct sockaddr_in);
80   if (getsockname(sock, (struct sockaddr *)&sin, &port) < 0)
81     return errno;
82   port=sin.sin_port;
83   close(sock);
84   return rx_Init(port);
85
86 }
87
88 static int insecure;
89
90 int afscp_Insecure(void) {
91   insecure=1;
92   return 0;
93 }
94 static struct afsconf_dir *confdir;
95
96 static int _GetCellInfo(char *cell, struct afsconf_cell *celldata) {
97
98   if (!confdir)
99     confdir=afsconf_Open(AFSCONF_CLIENTNAME);
100   if (!confdir)
101     return AFSCONF_NODB;
102   return afsconf_GetCellInfo(confdir, cell, AFSCONF_VLDBSERVICE, celldata);
103 }
104
105 int _GetSecurityObject(struct afs_cell *cell) {
106   int code;
107   krb5_context context;
108   krb5_creds match;
109   krb5_creds *cred;
110   krb5_ccache cc;
111   char **realms,*realm;
112   struct afsconf_cell celldata;
113   char localcell[MAXCELLCHARS];
114   struct rx_securityClass *sc;
115   struct ktc_encryptionKey k;
116   int i;
117   rxkad_level l;
118
119   code=_GetCellInfo(cell->name, &celldata);
120   if (code)
121     return code;
122
123   code=krb5_init_context(&context);
124   if (code)
125     return code;
126   realm=NULL;
127   code=krb5_get_host_realm(context, celldata.hostName[0], &realms);
128   if (!code) {
129     strcpy(localcell,realms[0]);
130     krb5_free_host_realm(context,realms);
131     realm=localcell;
132   }
133   if (!realm) {
134     for (i=0; (i < MAXCELLCHARS && cell->name[i]); i++) {
135       if (isalpha(cell->name[i]))
136         localcell[i]=toupper(cell->name[i]);
137       else
138         localcell[i]=cell->name[i];
139     }
140     localcell[i]='\0';
141     realm=localcell;
142   }
143   cc=NULL;
144   code=krb5_cc_default(context, &cc);
145
146   memset(&match, 0, sizeof(match));
147   Z_enctype(Z_credskey(&match))=ENCTYPE_DES_CBC_CRC;
148
149   if (!code)
150     code=krb5_cc_get_principal(context, cc, &match.client);
151   if (!code)
152       code=krb5_build_principal(context, &match.server,
153                                 strlen(realm), realm,
154                                 "afs", cell->name, NULL);
155
156   if (code) {
157     krb5_free_cred_contents(context, &match);
158     if (cc)
159       krb5_cc_close(context, cc);
160     krb5_free_context(context);
161     return code;
162   }
163
164   code = krb5_get_credentials(context, 0, cc, &match, &cred);
165   if (code) {
166     krb5_free_principal(context, match.server);
167     match.server=NULL;
168     code=krb5_build_principal(context, &match.server,
169                               strlen(realm), realm,
170                               "afs", NULL); /* afs@cell instead? */
171     if (!code)
172       code = krb5_get_credentials(context, 0, cc, &match, &cred);
173     if (code) {
174       krb5_free_cred_contents(context, &match);
175       if (cc)
176         krb5_cc_close(context, cc);
177       krb5_free_context(context);
178       return code;
179     }
180   }
181
182   if (insecure)
183     l=rxkad_clear;
184   else
185     l=rxkad_crypt;
186   memcpy(&k.data, Z_keydata(Z_credskey(cred)), 8);
187   sc = (struct rx_securityClass *)rxkad_NewClientSecurityObject
188     (l, &k, RXKAD_TKT_TYPE_KERBEROS_V5,
189      cred->ticket.length, cred->ticket.data);
190   krb5_free_creds(context, cred);
191   krb5_free_cred_contents(context, &match);
192   if (cc)
193     krb5_cc_close(context, cc);
194   krb5_free_context(context);
195   cell->security=sc;
196   cell->scindex=2;
197   return 0;
198 }
199 int _GetVLservers(struct afs_cell *cell) {
200   struct rx_connection *conns[MAXHOSTSPERCELL+1];
201   int i;
202   int code;
203   struct afsconf_cell celldata;
204
205   code=_GetCellInfo(cell->name, &celldata);
206   if (code)
207     return code;
208
209   for (i=0; i < celldata.numServers; i++) {
210     conns[i] = rx_NewConnection(celldata.hostAddr[i].sin_addr.s_addr,
211                                 htons(AFSCONF_VLDBPORT),
212                                 USER_SERVICE_ID, cell->security,
213                                 cell->scindex);
214   }
215   conns[i]=0;
216   return ubik_ClientInit(conns, &cell->vlservers);
217 }