Merge from vendor branch GPERF:
[dragonfly.git] / crypto / heimdal-0.6.3 / admin / get.c
1 /*
2  * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden). 
4  * All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met: 
9  *
10  * 1. Redistributions of source code must retain the above copyright 
11  *    notice, this list of conditions and the following disclaimer. 
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright 
14  *    notice, this list of conditions and the following disclaimer in the 
15  *    documentation and/or other materials provided with the distribution. 
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors 
18  *    may be used to endorse or promote products derived from this software 
19  *    without specific prior written permission. 
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
31  * SUCH DAMAGE. 
32  */
33
34 #include "ktutil_locl.h"
35
36 RCSID("$Id: get.c,v 1.22.2.1 2004/06/21 10:55:46 lha Exp $");
37
38 static void*
39 open_kadmin_connection(char *principal,
40                        const char *realm, 
41                        char *admin_server, 
42                        int server_port)
43 {
44     static kadm5_config_params conf;
45     krb5_error_code ret;
46     void *kadm_handle;
47     memset(&conf, 0, sizeof(conf));
48
49     if(realm) {
50         conf.realm = (char*)realm;
51         conf.mask |= KADM5_CONFIG_REALM;
52     }
53     
54     if (admin_server) {
55         conf.admin_server = admin_server;
56         conf.mask |= KADM5_CONFIG_ADMIN_SERVER;
57     }
58
59     if (server_port) {
60         conf.kadmind_port = htons(server_port);
61         conf.mask |= KADM5_CONFIG_KADMIND_PORT;
62     }
63
64     /* should get realm from each principal, instead of doing
65        everything with the same (local) realm */
66
67     ret = kadm5_init_with_password_ctx(context, 
68                                        principal,
69                                        NULL,
70                                        KADM5_ADMIN_SERVICE,
71                                        &conf, 0, 0, 
72                                        &kadm_handle);
73     if(ret) {
74         krb5_warn(context, ret, "kadm5_init_with_password");
75         return NULL;
76     }
77     return kadm_handle;
78 }
79
80 int
81 kt_get(int argc, char **argv)
82 {
83     krb5_error_code ret = 0;
84     krb5_keytab keytab;
85     void *kadm_handle = NULL;
86     char *principal = NULL;
87     char *realm = NULL;
88     char *admin_server = NULL;
89     int server_port = 0;
90     int help_flag = 0;
91     int optind = 0;
92     struct getarg_strings etype_strs = {0, NULL};
93     krb5_enctype *etypes = NULL;
94     size_t netypes = 0;
95     
96     struct getargs args[] = {
97         { "principal",  'p',    arg_string,   NULL, 
98           "admin principal", "principal" 
99         },
100         { "enctypes",   'e',    arg_strings,    NULL,
101           "encryption types to use", "enctypes" },
102         { "realm",      'r',    arg_string,   NULL, 
103           "realm to use", "realm" 
104         },
105         { "admin-server",       'a',    arg_string, NULL,
106           "server to contact", "host" 
107         },
108         { "server-port",        's',    arg_integer, NULL,
109           "port to contact", "port number" 
110         },
111         { "help",               'h',    arg_flag,    NULL }
112     };
113     int i = 0, j;
114
115     args[i++].value = &principal;
116     args[i++].value = &etype_strs;
117     args[i++].value = &realm;
118     args[i++].value = &admin_server;
119     args[i++].value = &server_port;
120     args[i++].value = &help_flag;
121
122     if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optind)
123        || help_flag) {
124         arg_printusage(args, sizeof(args) / sizeof(args[0]), 
125                        "ktutil get", "principal...");
126         return 1;
127     }
128     if(optind == argc) {
129         krb5_warnx(context, "no principals specified");
130         arg_printusage(args, sizeof(args) / sizeof(args[0]), 
131                        "ktutil get", "principal...");
132         return 1;
133     }
134     
135     if((keytab = ktutil_open_keytab()) == NULL)
136         return 1;
137
138     if(realm)
139         krb5_set_default_realm(context, realm);
140
141     if (etype_strs.num_strings) {
142         int i;
143
144         etypes = malloc (etype_strs.num_strings * sizeof(*etypes));
145         if (etypes == NULL) {
146             krb5_warnx(context, "malloc failed");
147             goto out;
148         }
149         netypes = etype_strs.num_strings;
150         for(i = 0; i < netypes; i++) {
151             ret = krb5_string_to_enctype(context, 
152                                          etype_strs.strings[i], 
153                                          &etypes[i]);
154             if(ret) {
155                 krb5_warnx(context, "unrecognized enctype: %s",
156                            etype_strs.strings[i]);
157                 goto out;
158             }
159         }
160     }
161
162     
163     for(i = optind; i < argc; i++){
164         krb5_principal princ_ent;
165         kadm5_principal_ent_rec princ;
166         int mask = 0;
167         krb5_keyblock *keys;
168         int n_keys;
169         int created = 0;
170         krb5_keytab_entry entry;
171
172         ret = krb5_parse_name(context, argv[i], &princ_ent);
173         if (ret) {
174             krb5_warn(context, ret, "can't parse principal %s", argv[i]);
175             continue;
176         }
177         memset(&princ, 0, sizeof(princ));
178         princ.principal = princ_ent;
179         mask |= KADM5_PRINCIPAL;
180         princ.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
181         mask |= KADM5_ATTRIBUTES;
182         princ.princ_expire_time = 0;
183         mask |= KADM5_PRINC_EXPIRE_TIME;
184
185         if(kadm_handle == NULL) {
186             const char *r;
187             if(realm != NULL)
188                 r = realm;
189             else
190                 r = krb5_principal_get_realm(context, princ_ent);
191             kadm_handle = open_kadmin_connection(principal, 
192                                                  r, 
193                                                  admin_server, 
194                                                  server_port);
195             if(kadm_handle == NULL) {
196                 break;
197             }
198         }
199         
200         ret = kadm5_create_principal(kadm_handle, &princ, mask, "x");
201         if(ret == 0)
202             created++;
203         else if(ret != KADM5_DUP) {
204             krb5_warn(context, ret, "kadm5_create_principal(%s)", argv[i]);
205             krb5_free_principal(context, princ_ent);
206             continue;
207         }
208         ret = kadm5_randkey_principal(kadm_handle, princ_ent, &keys, &n_keys);
209         if (ret) {
210             krb5_warn(context, ret, "kadm5_randkey_principal(%s)", argv[i]);
211             krb5_free_principal(context, princ_ent);
212             continue;
213         }
214         
215         ret = kadm5_get_principal(kadm_handle, princ_ent, &princ, 
216                               KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES);
217         if (ret) {
218             krb5_warn(context, ret, "kadm5_get_principal(%s)", argv[i]);
219             for (j = 0; j < n_keys; j++)
220                 krb5_free_keyblock_contents(context, &keys[j]);
221             krb5_free_principal(context, princ_ent);
222             continue;
223         }
224         princ.attributes &= (~KRB5_KDB_DISALLOW_ALL_TIX);
225         mask = KADM5_ATTRIBUTES;
226         if(created) {
227             princ.kvno = 1;
228             mask |= KADM5_KVNO;
229         }
230         ret = kadm5_modify_principal(kadm_handle, &princ, mask);
231         if (ret) {
232             krb5_warn(context, ret, "kadm5_modify_principal(%s)", argv[i]);
233             for (j = 0; j < n_keys; j++)
234                 krb5_free_keyblock_contents(context, &keys[j]);
235             krb5_free_principal(context, princ_ent);
236             continue;
237         }
238         for(j = 0; j < n_keys; j++) {
239             int do_add = TRUE;
240
241             if (netypes) {
242                 int i;
243
244                 do_add = FALSE;
245                 for (i = 0; i < netypes; ++i)
246                     if (keys[j].keytype == etypes[i]) {
247                         do_add = TRUE;
248                         break;
249                     }
250             }
251             if (do_add) {
252                 entry.principal = princ_ent;
253                 entry.vno = princ.kvno;
254                 entry.keyblock = keys[j];
255                 entry.timestamp = time (NULL);
256                 ret = krb5_kt_add_entry(context, keytab, &entry);
257                 if (ret)
258                     krb5_warn(context, ret, "krb5_kt_add_entry");
259             }
260             krb5_free_keyblock_contents(context, &keys[j]);
261         }
262         
263         kadm5_free_principal_ent(kadm_handle, &princ);
264         krb5_free_principal(context, princ_ent);
265     }
266  out:
267     free_getarg_strings(&etype_strs);
268     free(etypes);
269     if (kadm_handle)
270         kadm5_destroy(kadm_handle);
271     krb5_kt_close(context, keytab);
272     return ret != 0;
273 }