added nsupdate-gss
[tridge/junkcode.git] / kverify.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <unistd.h>
4 #include <fcntl.h>
5 #include <sys/stat.h>
6 #include <krb5.h>
7
8 #define DEBUG(l, x) printf x
9 #define NT_STATUS_LOGON_FAILURE -1
10 #define NT_STATUS_NO_MEMORY -1
11 #define NT_STATUS_OK 0
12
13 /****************************************************************************
14 load a file into memory from a fd.
15 ****************************************************************************/ 
16
17 char *fd_load(int fd, size_t *size)
18 {
19         struct stat sbuf;
20         char *p;
21
22         if (fstat(fd, &sbuf) != 0) return NULL;
23
24         p = (char *)malloc(sbuf.st_size+1);
25         if (!p) return NULL;
26
27         if (read(fd, p, sbuf.st_size) != sbuf.st_size) {
28                 free(p);
29                 return NULL;
30         }
31         p[sbuf.st_size] = 0;
32
33         if (size) *size = sbuf.st_size;
34
35         return p;
36 }
37
38 /****************************************************************************
39 load a file into memory
40 ****************************************************************************/
41 char *file_load(const char *fname, size_t *size)
42 {
43         int fd;
44         char *p;
45
46         if (!fname || !*fname) return NULL;
47         
48         fd = open(fname,O_RDONLY);
49         if (fd == -1) return NULL;
50
51         p = fd_load(fd, size);
52
53         close(fd);
54
55         return p;
56 }
57
58 /*
59   verify an incoming ticket and parse out the principal name and 
60   authorization_data if available 
61 */
62 static int verify_ticket(const char *ticket, size_t tsize, char *password_s)
63 {
64         krb5_context context;
65         krb5_auth_context auth_context = NULL;
66         krb5_keytab keytab = NULL;
67         krb5_data packet;
68         krb5_ticket *tkt = NULL;
69         krb5_data salt;
70         krb5_encrypt_block eblock;
71         int ret, i;
72         krb5_keyblock * key;
73         krb5_principal host_princ;
74         char *host_princ_s;
75         char *myname = "blu";
76         char *realm = "FLAGSHIP.DOT-NET";
77         krb5_data password;
78         krb5_enctype *enctypes = NULL;
79
80         password.data = password_s;
81         password.length = strlen(password_s);
82
83         ret = krb5_init_context(&context);
84         if (ret) {
85                 DEBUG(1,("krb5_init_context failed (%s)\n", error_message(ret)));
86                 return -1;
87         }
88
89         ret = krb5_set_default_realm(context, realm);
90         if (ret) {
91                 DEBUG(1,("krb5_set_default_realm failed (%s)\n", error_message(ret)));
92                 return -1;
93         }
94
95         /* this whole process is far more complex than I would
96            like. We have to go through all this to allow us to store
97            the secret internally, instead of using /etc/krb5.keytab */
98         ret = krb5_auth_con_init(context, &auth_context);
99         if (ret) {
100                 DEBUG(1,("krb5_auth_con_init failed (%s)\n", error_message(ret)));
101                 return -1;
102         }
103
104         asprintf(&host_princ_s, "HOST/%s@%s", myname, realm);
105         ret = krb5_parse_name(context, host_princ_s, &host_princ);
106         if (ret) {
107                 DEBUG(1,("krb5_parse_name(%s) failed (%s)\n", host_princ_s, error_message(ret)));
108                 return -1;
109         }
110
111         ret = krb5_principal2salt(context, host_princ, &salt);
112         if (ret) {
113                 DEBUG(1,("krb5_principal2salt failed (%s)\n", error_message(ret)));
114                 return NT_STATUS_LOGON_FAILURE;
115         }
116     
117         if (!(key = (krb5_keyblock *)malloc(sizeof(*key)))) {
118                 return NT_STATUS_NO_MEMORY;
119         }
120
121         if ((ret = krb5_get_permitted_enctypes(context, &enctypes))) {
122                 DEBUG(1,("krb5_get_permitted_enctypes failed (%s)\n", 
123                          error_message(ret)));
124                 return NT_STATUS_LOGON_FAILURE;
125         }
126
127         for (i=0;enctypes[i];i++) {
128                 krb5_use_enctype(context, &eblock, enctypes[i]);
129
130                 ret = krb5_string_to_key(context, &eblock, key, &password, &salt);
131                 if (ret) {
132                         continue;
133                 }
134
135                 krb5_auth_con_setuseruserkey(context, auth_context, key);
136
137                 packet.length = tsize;
138                 packet.data = (krb5_pointer)ticket;
139
140                 if (!(ret = krb5_rd_req(context, &auth_context, &packet, 
141                                        NULL, keytab, NULL, &tkt))) {
142                         krb5_free_ktypes(context, enctypes);
143                         return NT_STATUS_OK;
144                 }
145         }
146
147         DEBUG(1,("krb5_rd_req failed (%s)\n", 
148                  error_message(ret)));
149
150         krb5_free_ktypes(context, enctypes);
151
152         return NT_STATUS_LOGON_FAILURE;
153 }
154
155
156 int main(int argc, char *argv[])
157 {
158         char *tfile = argv[1];
159         char *pass = argv[2];
160         char *ticket;
161         size_t tsize;
162
163         ticket = file_load(tfile, &tsize);
164         if (!ticket) {
165                 perror(tfile);
166                 exit(1);
167         }
168         
169         return verify_ticket(ticket, tsize, pass);
170 }