54a8a6ffe8bbc5ddbae0106b98a79f80991a2dc5
[kai/samba.git] / source / libsmb / clikrb5.c
1 /* 
2    Unix SMB/CIFS implementation.
3    simple kerberos5 routines for active directory
4    Copyright (C) Andrew Tridgell 2001
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 #ifdef HAVE_KRB5
24 /*
25   we can't use krb5_mk_req because w2k wants the service to be in a particular format
26 */
27 static krb5_error_code krb5_mk_req2(krb5_context context, 
28                                     krb5_auth_context *auth_context, 
29                                     const krb5_flags ap_req_options,
30                                     const char *principal,
31                                     krb5_ccache ccache, 
32                                     krb5_data *outbuf)
33 {
34         krb5_error_code           retval;
35         krb5_principal    server;
36         krb5_creds              * credsp;
37         krb5_creds                creds;
38         krb5_data in_data;
39         
40         retval = krb5_parse_name(context, principal, &server);
41         if (retval) {
42                 DEBUG(1,("Failed to parse principal %s\n", principal));
43                 return retval;
44         }
45         
46         /* obtain ticket & session key */
47         memset((char *)&creds, 0, sizeof(creds));
48         if ((retval = krb5_copy_principal(context, server, &creds.server))) {
49                 DEBUG(1,("krb5_copy_principal failed (%s)\n", 
50                          error_message(retval)));
51                 goto cleanup_princ;
52         }
53         
54         if ((retval = krb5_cc_get_principal(context, ccache, &creds.client))) {
55                 DEBUG(1,("krb5_cc_get_principal failed (%s)\n", 
56                          error_message(retval)));
57                 goto cleanup_creds;
58         }
59
60         if ((retval = krb5_get_credentials(context, 0,
61                                            ccache, &creds, &credsp))) {
62                 DEBUG(1,("krb5_get_credentials failed for %s (%s)\n", 
63                          principal, error_message(retval)));
64                 goto cleanup_creds;
65         }
66
67         /* cope with the ticket being in the future due to clock skew */
68         if ((unsigned)credsp->times.starttime > time(NULL)) {
69                 time_t t = time(NULL);
70                 int time_offset = (unsigned)credsp->times.starttime - t;
71                 DEBUG(4,("Advancing clock by %d seconds to cope with clock skew\n", time_offset));
72                 krb5_set_real_time(context, t + time_offset + 1, 0);
73         }
74
75         in_data.length = 0;
76         retval = krb5_mk_req_extended(context, auth_context, ap_req_options, 
77                                       &in_data, credsp, outbuf);
78         if (retval) {
79                 DEBUG(1,("krb5_mk_req_extended failed (%s)\n", 
80                          error_message(retval)));
81         }
82         
83         krb5_free_creds(context, credsp);
84
85 cleanup_creds:
86         krb5_free_cred_contents(context, &creds);
87
88 cleanup_princ:
89         krb5_free_principal(context, server);
90
91         return retval;
92 }
93
94 /*
95   get a kerberos5 ticket for the given service 
96 */
97 DATA_BLOB krb5_get_ticket(char *principal, time_t time_offset)
98 {
99         krb5_error_code retval;
100         krb5_data packet;
101         krb5_ccache ccdef;
102         krb5_context context;
103         krb5_auth_context auth_context = NULL;
104         DATA_BLOB ret;
105         krb5_enctype enc_types[] = {
106 #ifdef ENCTYPE_ARCFOUR_HMAC
107                 ENCTYPE_ARCFOUR_HMAC, 
108 #endif
109                                     ENCTYPE_DES_CBC_MD5, 
110                                     ENCTYPE_NULL};
111
112         retval = krb5_init_context(&context);
113         if (retval) {
114                 DEBUG(1,("krb5_init_context failed (%s)\n", 
115                          error_message(retval)));
116                 goto failed;
117         }
118
119         if (time_offset != 0) {
120                 krb5_set_real_time(context, time(NULL) + time_offset, 0);
121         }
122
123         if ((retval = krb5_cc_default(context, &ccdef))) {
124                 DEBUG(1,("krb5_cc_default failed (%s)\n",
125                          error_message(retval)));
126                 goto failed;
127         }
128
129         if ((retval = krb5_set_default_tgs_ktypes(context, enc_types))) {
130                 DEBUG(1,("krb5_set_default_tgs_ktypes failed (%s)\n",
131                          error_message(retval)));
132                 goto failed;
133         }
134
135         if ((retval = krb5_mk_req2(context, 
136                                    &auth_context, 
137                                    0, 
138                                    principal,
139                                    ccdef, &packet))) {
140                 goto failed;
141         }
142
143         ret = data_blob(packet.data, packet.length);
144 /* Hmm, heimdal dooesn't have this - what's the correct call? */
145 /*      krb5_free_data_contents(context, &packet); */
146         krb5_free_context(context);
147         return ret;
148
149 failed:
150         if ( context )
151                 krb5_free_context(context);
152                 
153         return data_blob(NULL, 0);
154 }
155
156
157 #else /* HAVE_KRB5 */
158  /* this saves a few linking headaches */
159  DATA_BLOB krb5_get_ticket(char *principal, time_t time_offset)
160  {
161          DEBUG(0,("NO KERBEROS SUPPORT\n"));
162          return data_blob(NULL, 0);
163  }
164 #endif