]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - crypto/heimdal/lib/kadm5/init_c.c
This commit was generated by cvs2svn to compensate for changes in r56067,
[FreeBSD/FreeBSD.git] / crypto / heimdal / lib / kadm5 / init_c.c
1 /*
2  * Copyright (c) 1997, 1998, 1999 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 "kadm5_locl.h"
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <netdb.h>
39
40 RCSID("$Id: init_c.c,v 1.34 1999/12/20 14:05:49 assar Exp $");
41
42 static void
43 set_funcs(kadm5_client_context *c)
44 {
45 #define SET(C, F) (C)->funcs.F = kadm5 ## _c_ ## F
46     SET(c, chpass_principal);
47     SET(c, chpass_principal);
48     SET(c, create_principal);
49     SET(c, delete_principal);
50     SET(c, destroy);
51     SET(c, flush);
52     SET(c, get_principal);
53     SET(c, get_principals);
54     SET(c, get_privs);
55     SET(c, modify_principal);
56     SET(c, randkey_principal);
57     SET(c, rename_principal);
58 }
59
60 kadm5_ret_t
61 _kadm5_c_init_context(kadm5_client_context **ctx, 
62                       kadm5_config_params *params,
63                       krb5_context context)
64 {
65     krb5_error_code ret;
66     char *colon;
67
68     *ctx = malloc(sizeof(**ctx));
69     if(*ctx == NULL)
70         return ENOMEM;
71     memset(*ctx, 0, sizeof(**ctx));
72     krb5_add_et_list (context, initialize_kadm5_error_table_r);
73     set_funcs(*ctx);
74     (*ctx)->context = context;
75     if(params->mask & KADM5_CONFIG_REALM)
76         (*ctx)->realm = strdup(params->realm);
77     else
78         krb5_get_default_realm((*ctx)->context, &(*ctx)->realm);
79     if(params->mask & KADM5_CONFIG_ADMIN_SERVER)
80         (*ctx)->admin_server = strdup(params->admin_server);
81     else {
82         char **hostlist;
83
84         ret = krb5_get_krb_admin_hst (context, &(*ctx)->realm, &hostlist);
85         if (ret)
86             return ret;
87         (*ctx)->admin_server = strdup(*hostlist);
88         krb5_free_krbhst (context, hostlist);
89     }
90
91     if ((*ctx)->admin_server == NULL)
92         return ENOMEM;
93     colon = strchr ((*ctx)->admin_server, ':');
94     if (colon != NULL)
95         *colon++ = '\0';
96
97     (*ctx)->kadmind_port = 0;
98
99     if(params->mask & KADM5_CONFIG_KADMIND_PORT)
100         (*ctx)->kadmind_port = params->kadmind_port;
101     else if (colon != NULL) {
102         char *end;
103
104         (*ctx)->kadmind_port = htons(strtol (colon, &end, 0));
105     }
106     if ((*ctx)->kadmind_port == 0)
107         (*ctx)->kadmind_port = krb5_getportbyname (context, "kerberos-adm", 
108                                                    "tcp", 749);
109     return 0;
110 }
111
112 static krb5_error_code
113 get_kadm_ticket(krb5_context context,
114                 krb5_ccache id,
115                 krb5_principal client,
116                 const char *server_name)
117 {
118     krb5_error_code ret;
119     krb5_creds in, *out;
120     
121     memset(&in, 0, sizeof(in));
122     in.client = client;
123     ret = krb5_parse_name(context, server_name, &in.server);
124     if(ret) 
125         return ret;
126     ret = krb5_get_credentials(context, 0, id, &in, &out);
127     if(ret == 0)
128         krb5_free_creds(context, out);
129     krb5_free_principal(context, in.server);
130     return ret;
131 }
132
133 static krb5_error_code
134 get_new_cache(krb5_context context,
135               krb5_principal client,
136               const char *password,
137               krb5_prompter_fct prompter,
138               const char *keytab,
139               const char *server_name,
140               krb5_ccache *ret_cache)
141 {
142     krb5_error_code ret;
143     krb5_creds cred;
144     krb5_get_init_creds_opt opt;
145     krb5_ccache id;
146     
147     krb5_get_init_creds_opt_init (&opt);
148     if(password == NULL && prompter == NULL) {
149         krb5_keytab kt;
150         if(keytab == NULL)
151             ret = krb5_kt_default(context, &kt);
152         else
153             ret = krb5_kt_resolve(context, keytab, &kt);
154         if(ret) 
155             return ret;
156         ret = krb5_get_init_creds_keytab (context,
157                                           &cred,
158                                           client,
159                                           kt,
160                                           0,
161                                           server_name,
162                                           &opt);
163         krb5_kt_close(context, kt);
164     } else {
165         ret = krb5_get_init_creds_password (context,
166                                             &cred,
167                                             client,
168                                             password,
169                                             prompter,
170                                             NULL,
171                                             0,
172                                             server_name,
173                                             &opt);
174     }
175     switch(ret){
176     case 0:
177         break;
178     case KRB5_LIBOS_PWDINTR:    /* don't print anything if it was just C-c:ed */
179     case KRB5KRB_AP_ERR_BAD_INTEGRITY:
180     case KRB5KRB_AP_ERR_MODIFIED:
181         return KADM5_BAD_PASSWORD;
182     default:
183         return ret;
184     }
185     ret = krb5_cc_gen_new(context, &krb5_mcc_ops, &id);
186     if(ret)
187         return ret;
188     ret = krb5_cc_initialize (context, id, cred.client);
189     if (ret)
190         return ret;
191     ret = krb5_cc_store_cred (context, id, &cred);
192     if (ret)
193         return ret;
194     krb5_free_creds_contents (context, &cred);
195     *ret_cache = id;
196     return 0;
197 }
198
199 static krb5_error_code
200 get_cred_cache(krb5_context context,
201                const char *client_name,
202                const char *server_name,
203                const char *password,
204                krb5_prompter_fct prompter,
205                const char *keytab,
206                krb5_ccache ccache,
207                krb5_ccache *ret_cache)
208 {
209     krb5_error_code ret;
210     krb5_ccache id = NULL;
211     krb5_principal default_client = NULL, client = NULL;
212     
213     /* treat empty password as NULL */
214     if(password && *password == '\0')
215         password = NULL;
216     if(server_name == NULL)
217         server_name = KADM5_ADMIN_SERVICE;
218     
219     if(client_name != NULL) {
220         ret = krb5_parse_name(context, client_name, &client);
221         if(ret) 
222             return ret;
223     }
224
225     if(password != NULL || prompter != NULL) {
226         /* get principal from default cache, ok if this doesn't work */
227         ret = krb5_cc_default(context, &id);
228         if(ret == 0) {
229             ret = krb5_cc_get_principal(context, id, &default_client);
230             if(ret) {
231                 krb5_cc_close(context, id);
232                 id = NULL;
233             }
234         }
235         
236         if(client == NULL)
237             client = default_client;
238         if(client == NULL) {
239             const char *user;
240
241             user = get_default_username ();
242
243             if(user == NULL)
244                 return KADM5_FAILURE;
245             ret = krb5_make_principal(context, &client, 
246                                       NULL, user, "admin", NULL);
247             if(ret)
248                 return ret;
249         }
250         if(client != default_client) {
251             krb5_free_principal(context, default_client);
252             default_client = NULL;
253             if (id != NULL) {
254                 krb5_cc_close(context, id);
255                 id = NULL;
256             }
257         }
258     } else if(ccache != NULL)
259         id = ccache;
260     
261
262     if(id && (default_client == NULL || 
263               krb5_principal_compare(context, client, default_client))) {
264         ret = get_kadm_ticket(context, id, client, server_name);
265         if(ret == 0) {
266             *ret_cache = id;
267             krb5_free_principal(context, default_client);
268             if (default_client != client)
269                 krb5_free_principal(context, client);
270             return 0;
271         }
272         if(ccache != NULL)
273             /* couldn't get ticket from cache */
274             return -1;
275     }
276     /* get creds via AS request */
277     if(id)
278         krb5_cc_close(context, id);
279     if (client != default_client)
280         krb5_free_principal(context, default_client);
281
282     ret = get_new_cache(context, client, password, prompter, keytab, 
283                         server_name, ret_cache);
284     krb5_free_principal(context, client);
285     return ret;
286 }
287
288 static kadm5_ret_t 
289 kadm5_c_init_with_context(krb5_context context,
290                           const char *client_name, 
291                           const char *password,
292                           krb5_prompter_fct prompter,
293                           const char *keytab,
294                           krb5_ccache ccache,
295                           const char *service_name,
296                           kadm5_config_params *realm_params,
297                           unsigned long struct_version,
298                           unsigned long api_version,
299                           void **server_handle)
300 {
301     kadm5_ret_t ret;
302     kadm5_client_context *ctx;
303     krb5_principal server;
304     krb5_ccache cc;
305     int s;
306     struct addrinfo *ai, *a;
307     struct addrinfo hints;
308     int error;
309     char portstr[NI_MAXSERV];
310     char *hostname, *slash;
311
312     memset (&hints, 0, sizeof(hints));
313     hints.ai_socktype = SOCK_STREAM;
314     hints.ai_protocol = IPPROTO_TCP;
315
316     ret = _kadm5_c_init_context(&ctx, realm_params, context);
317     if(ret)
318         return ret;
319
320     snprintf (portstr, sizeof(portstr), "%u", ntohs(ctx->kadmind_port));
321
322     hostname = ctx->admin_server;
323     slash = strchr (hostname, '/');
324     if (slash != NULL)
325         hostname = slash + 1;
326
327     error = getaddrinfo (hostname, portstr, &hints, &ai);
328     if (error) 
329         return KADM5_BAD_SERVER_NAME;
330     
331     for (a = ai; a != NULL; a = a->ai_next) {
332         s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
333         if (s < 0)
334             continue;
335         if (connect (s, a->ai_addr, a->ai_addrlen) < 0) {
336             krb5_warn (context, errno, "connect(%s)", hostname);
337             close (s);
338             continue;
339         }
340         break;
341     }
342     if (a == NULL) {
343         freeaddrinfo (ai);
344         krb5_warnx (context, "failed to contact %s", hostname);
345         return KADM5_FAILURE;
346     }
347     ret = get_cred_cache(context, client_name, service_name, 
348                          password, prompter, keytab, ccache, &cc);
349     
350     if(ret) {
351         freeaddrinfo (ai);
352         close(s);
353         return ret;
354     }
355     ret = krb5_parse_name(context, KADM5_ADMIN_SERVICE, &server);
356     if(ret) {
357         freeaddrinfo (ai);
358         if(ccache == NULL)
359             krb5_cc_close(context, cc);
360         close(s);
361         return ret;
362     }
363     ctx->ac = NULL;
364
365     ret = krb5_sendauth(context, &ctx->ac, &s, 
366                         KADMIN_APPL_VERSION, NULL, 
367                         server, AP_OPTS_MUTUAL_REQUIRED, 
368                         NULL, NULL, cc, NULL, NULL, NULL);
369     if(ret == 0) {
370         krb5_data params, enc_data;
371         ret = _kadm5_marshal_params(context, realm_params, &params);
372         
373         ret = krb5_mk_priv(context,
374                            ctx->ac,
375                            &params,
376                            &enc_data,
377                            NULL);
378
379         ret = krb5_write_message(context, &s, &enc_data);
380         
381         krb5_data_free(&params);
382         krb5_data_free(&enc_data);
383     } else if(ret == KRB5_SENDAUTH_BADAPPLVERS) {
384         close(s);
385
386         s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
387         if (s < 0) {
388             freeaddrinfo (ai);
389             return errno;
390         }
391         if (connect (s, a->ai_addr, a->ai_addrlen) < 0) {
392             close (s);
393             freeaddrinfo (ai);
394             return errno;
395         }
396         freeaddrinfo (ai);
397
398         ret = krb5_sendauth(context, &ctx->ac, &s, 
399                             KADMIN_OLD_APPL_VERSION, NULL, 
400                             server, AP_OPTS_MUTUAL_REQUIRED, 
401                             NULL, NULL, cc, NULL, NULL, NULL);
402     }
403     freeaddrinfo (ai);
404     if(ret) {
405         close(s);
406         return ret;
407     }
408     
409     krb5_free_principal(context, server);
410     if(ccache == NULL)
411         krb5_cc_close(context, cc);
412     if(ret) {
413         close(s);
414         return ret;
415     }
416     ctx->sock = s;
417     *server_handle = ctx;
418     return 0;
419 }
420
421 static kadm5_ret_t 
422 init_context(const char *client_name, 
423              const char *password,
424              krb5_prompter_fct prompter,
425              const char *keytab,
426              krb5_ccache ccache,
427              const char *service_name,
428              kadm5_config_params *realm_params,
429              unsigned long struct_version,
430              unsigned long api_version,
431              void **server_handle)
432 {
433     krb5_context context;
434     kadm5_ret_t ret;
435     kadm5_server_context *ctx;
436     
437     krb5_init_context(&context);
438     ret = kadm5_c_init_with_context(context,
439                                     client_name,
440                                     password,
441                                     prompter,
442                                     keytab,
443                                     ccache,
444                                     service_name,
445                                     realm_params,
446                                     struct_version,
447                                     api_version,
448                                     server_handle);
449     if(ret){
450         krb5_free_context(context);
451         return ret;
452     }
453     ctx = *server_handle;
454     ctx->my_context = 1;
455     return 0;
456 }
457
458 kadm5_ret_t 
459 kadm5_c_init_with_password_ctx(krb5_context context,
460                                const char *client_name, 
461                                const char *password,
462                                const char *service_name,
463                                kadm5_config_params *realm_params,
464                                unsigned long struct_version,
465                                unsigned long api_version,
466                                void **server_handle)
467 {
468     return kadm5_c_init_with_context(context,
469                                      client_name,
470                                      password,
471                                      krb5_prompter_posix,
472                                      NULL,
473                                      NULL,
474                                      service_name,
475                                      realm_params,
476                                      struct_version,
477                                      api_version,
478                                      server_handle);
479 }
480
481 kadm5_ret_t 
482 kadm5_c_init_with_password(const char *client_name, 
483                            const char *password,
484                            const char *service_name,
485                            kadm5_config_params *realm_params,
486                            unsigned long struct_version,
487                            unsigned long api_version,
488                            void **server_handle)
489 {
490     return init_context(client_name, 
491                         password, 
492                         krb5_prompter_posix,
493                         NULL,
494                         NULL,
495                         service_name, 
496                         realm_params, 
497                         struct_version, 
498                         api_version, 
499                         server_handle);
500 }
501
502 kadm5_ret_t 
503 kadm5_c_init_with_skey_ctx(krb5_context context,
504                            const char *client_name, 
505                            const char *keytab,
506                            const char *service_name,
507                            kadm5_config_params *realm_params,
508                            unsigned long struct_version,
509                            unsigned long api_version,
510                            void **server_handle)
511 {
512     return kadm5_c_init_with_context(context,
513                                      client_name,
514                                      NULL,
515                                      NULL,
516                                      keytab,
517                                      NULL,
518                                      service_name,
519                                      realm_params,
520                                      struct_version,
521                                      api_version,
522                                      server_handle);
523 }
524
525
526 kadm5_ret_t 
527 kadm5_c_init_with_skey(const char *client_name, 
528                      const char *keytab,
529                      const char *service_name,
530                      kadm5_config_params *realm_params,
531                      unsigned long struct_version,
532                      unsigned long api_version,
533                      void **server_handle)
534 {
535     return init_context(client_name, 
536                         NULL,
537                         NULL,
538                         keytab,
539                         NULL,
540                         service_name, 
541                         realm_params, 
542                         struct_version, 
543                         api_version, 
544                         server_handle);
545 }
546
547 kadm5_ret_t 
548 kadm5_c_init_with_creds_ctx(krb5_context context,
549                             const char *client_name,
550                             krb5_ccache ccache,
551                             const char *service_name,
552                             kadm5_config_params *realm_params,
553                             unsigned long struct_version,
554                             unsigned long api_version,
555                             void **server_handle)
556 {
557     return kadm5_c_init_with_context(context,
558                                      client_name,
559                                      NULL,
560                                      NULL,
561                                      NULL,
562                                      ccache,
563                                      service_name,
564                                      realm_params,
565                                      struct_version,
566                                      api_version,
567                                      server_handle);
568 }
569
570 kadm5_ret_t 
571 kadm5_c_init_with_creds(const char *client_name,
572                         krb5_ccache ccache,
573                         const char *service_name,
574                         kadm5_config_params *realm_params,
575                         unsigned long struct_version,
576                         unsigned long api_version,
577                         void **server_handle)
578 {
579     return init_context(client_name, 
580                         NULL,
581                         NULL,
582                         NULL,
583                         ccache,
584                         service_name, 
585                         realm_params, 
586                         struct_version, 
587                         api_version, 
588                         server_handle);
589 }
590
591 #if 0
592 kadm5_ret_t 
593 kadm5_init(char *client_name, char *pass,
594            char *service_name,
595            kadm5_config_params *realm_params,
596            unsigned long struct_version,
597            unsigned long api_version,
598            void **server_handle)
599 {
600 }
601 #endif
602