1 /*
2 
3 Copyright 1994, 1998  The Open Group
4 
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10 
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
21 
22 Except as contained in this notice, the name of The Open Group shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
25 from The Open Group.
26 
27 */
28 
29 /*
30  * xdm - display manager daemon
31  * Author:  Stephen Gildea, The Open Group
32  */
33 
34 /*
35  * krb5auth
36  *
37  * generate Kerberos Version 5 authorization records
38  */
39 
40 #include "dm.h"
41 #include "dm_error.h"
42 
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <krb5/krb5.h>
46 #include <krb5/kdb.h>			/* for TGTNAME */
47 
48 /*ARGSUSED*/
49 void
Krb5InitAuth(unsigned short name_len,char * name)50 Krb5InitAuth (unsigned short name_len, char *name)
51 {
52     krb5_init_ets();		/* initialize error_message() tables */
53 }
54 
55 /*
56  * Returns malloc'ed string that is the credentials cache name.
57  * name should be freed by caller.
58  */
59 char *
Krb5CCacheName(char * dname)60 Krb5CCacheName(char *dname)
61 {
62     char *name;
63     char *tmpdir;
64 
65     tmpdir = getenv("TMPDIR");
66     if (!tmpdir)
67 	tmpdir = "/tmp";
68     name = malloc(strlen(tmpdir) + strlen(dname) + 20);
69     if (!name)
70 	return NULL;
71     sprintf(name, "FILE:%s/K5C", tmpdir);
72     CleanUpFileName(dname, name+strlen(name), strlen(dname)+1);
73     return name;
74 }
75 
76 krb5_error_code
Krb5DisplayCCache(char * dname,krb5_ccache * ccache_return)77 Krb5DisplayCCache(char *dname, krb5_ccache *ccache_return)
78 {
79     krb5_error_code code;
80     char *name;
81 
82     name = Krb5CCacheName(dname);
83     if (!name)
84 	return ENOMEM;
85     Debug("resolving Kerberos cache %s\n", name);
86     code = krb5_cc_resolve(name, ccache_return);
87     free(name);
88     return code;
89 }
90 
91 Xauth *
Krb5GetAuthFor(unsigned short namelen,char * name,char * dname)92 Krb5GetAuthFor(unsigned short namelen, char *name, char *dname)
93 {
94     Xauth   *new;
95     char *filename;
96     struct stat statbuf;
97 
98     new = malloc (sizeof *new);
99     if (!new)
100 	return (Xauth *) 0;
101     new->family = FamilyWild;
102     new->address_length = 0;
103     new->address = 0;
104     new->number_length = 0;
105     new->number = 0;
106 
107     if (dname)
108     {
109 	filename = Krb5CCacheName(dname);
110 	new->data = malloc (3 + strlen(filename) + 1);
111 	if (!new->data)
112 	{
113 	    free (filename);
114 	    free (new);
115 	    return (Xauth *) 0;
116 	}
117 	strcpy(new->data, "UU:");
118 	strcat(new->data, filename);
119 	free (filename);
120 	new->data_length = strlen(new->data);
121     }
122     else
123     {
124 	new->data = NULL;
125 	new->data_length = 0;
126     }
127 
128     new->name = malloc (namelen);
129     if (!new->name)
130     {
131 	free (new->data);
132 	free (new);
133 	return (Xauth *) 0;
134     }
135     memmove( new->name, name, namelen);
136     new->name_length = namelen;
137     return new;
138 }
139 
140 Xauth *
Krb5GetAuth(unsigned short namelen,char * name)141 Krb5GetAuth (unsigned short namelen, char *name)
142 {
143     return Krb5GetAuthFor(namelen, name, NULL);
144 }
145 
146 int preauth_search_list[] = {
147 	0,
148 	KRB5_PADATA_ENC_TIMESTAMP,
149 	-1
150 	};
151 
152 /*
153  * Krb5Init - lifted from kinit.c
154  * Get TGT.
155  * Returns 0 if successful, 1 if not.
156  */
157 int
Krb5Init(char * name,char * passwd,struct display * d)158 Krb5Init(
159     char *name,
160     char *passwd,
161     struct display *d)		/* k5_ccache filled in if successful */
162 {
163     krb5_ccache ccache;
164     krb5_error_code code;
165     krb5_principal me;
166     krb5_creds my_creds;
167     krb5_principal server;
168     krb5_address **my_addresses;
169     krb5_timestamp now;
170     int	i;
171 
172     if (code = Krb5DisplayCCache(d->name, &ccache)) {
173 	LogError("%s while getting Krb5 ccache for \"%s\"\n",
174 		 error_message(code), d->name);
175 	return 1;
176     }
177 
178     if (code = krb5_parse_name (name, &me)) {
179 	 LogError("%s while parsing Krb5 name \"%s\"\n",
180 		  error_message(code), name);
181 	 return 1;
182     }
183 
184     code = krb5_cc_initialize (ccache, me);
185     if (code != 0) {
186 	LogError("%s while initializing Krb5 cache \"%s\"\n",
187 		 error_message(code), krb5_cc_default_name());
188 	return 1;
189     }
190 
191     memset((char *)&my_creds, 0, sizeof(my_creds));
192 
193     my_creds.client = me;
194 
195     if (code = krb5_build_principal_ext(&server,
196 					krb5_princ_realm(me)->length,
197 					krb5_princ_realm(me)->data,
198 					6, "krbtgt",
199 					krb5_princ_realm(me)->length,
200 					krb5_princ_realm(me)->data,
201 					0)) {
202 	LogError("%s while building Krb5 TGT server name\n",
203 		 error_message(code));
204 	return 1;
205     }
206 
207     my_creds.server = server;
208 
209     code = krb5_os_localaddr(&my_addresses);
210     if (code != 0) {
211 	LogError("%s while getting my address for Krb5\n",
212 		 error_message(code));
213 	return 1;
214     }
215     if (code = krb5_timeofday(&now)) {
216 	LogError("%s while getting time of day for Krb5\n",
217 		 error_message(code));
218 	return 1;
219     }
220     my_creds.times.starttime = 0;	/* start timer when request
221 					   gets to KDC */
222     my_creds.times.endtime = now + 60*60*8; /* 8 hours */
223     my_creds.times.renew_till = 0;
224 
225     for (i = 0; preauth_search_list[i] >= 0; i++) {
226 	code = krb5_get_in_tkt_with_password(0, my_addresses,
227 					     preauth_search_list[i],
228 					     ETYPE_DES_CBC_CRC,
229 					     KEYTYPE_DES,
230 					     passwd,
231 					     ccache,
232 					     &my_creds, 0);
233 	if (code != KRB5KDC_PREAUTH_FAILED &&
234 	    code != KRB5KRB_ERR_GENERIC)
235 	    break;
236     }
237 
238     krb5_free_principal(server);
239     krb5_free_addresses(my_addresses);
240 
241     if (code) {
242 	char *my_name = NULL;
243 	int code2 = krb5_unparse_name(me, &my_name);
244 	if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
245 	    LogError ("password incorrect for Krb5 principal \"%s\"\n",
246 		      code2 ? name : my_name);
247 	}
248 	else
249 	    LogError("%s while getting initial Krb5 credentials for \"%s\"\n",
250 		     error_message(code), code2 ? name : my_name);
251 	free (my_name);
252 	return 1;
253     }
254     krb5_cc_close(ccache);
255     return 0;
256 }
257