1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
4  *
5  * $Id$
6  * $Source$
7  */
8 /*
9  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
10  * Use is subject to license terms.
11  */
12 
13 #include "k5-int.h"
14 #include <com_err.h>
15 #include <kadm5/admin.h>
16 #include <krb5.h>
17 #include <kdb_log.h>
18 #include "server_internal.h"
19 #include "osconf.h"
20 #include "iprop_hdr.h"
21 
22 /*
23  * Function check_handle
24  *
25  * Purpose: Check a server handle and return a com_err code if it is
26  * invalid or 0 if it is valid.
27  *
28  * Arguments:
29  *
30  *      handle          The server handle.
31  */
32 
check_handle(void * handle)33 static int check_handle(void *handle)
34 {
35     CHECK_HANDLE(handle);
36     return 0;
37 }
38 
dup_db_args(kadm5_server_handle_t handle,char ** db_args)39 static int dup_db_args(kadm5_server_handle_t handle, char **db_args)
40 {
41     int count  = 0;
42     int ret = 0;
43 
44     for (count=0; db_args && db_args[count]; count++);
45     if (count == 0) {
46         handle->db_args = NULL;
47         goto clean_n_exit;
48     }
49 
50     handle->db_args = calloc(sizeof(char*), count+1);
51     if (handle->db_args == NULL) {
52         ret=ENOMEM;
53         goto clean_n_exit;
54     }
55 
56     for (count=0; db_args[count]; count++) {
57         handle->db_args[count] = strdup(db_args[count]);
58         if (handle->db_args[count] == NULL) {
59             ret = ENOMEM;
60             goto clean_n_exit;
61         }
62     }
63 
64 clean_n_exit:
65     if (ret && handle->db_args) {
66         for (count=0; handle->db_args[count]; count++)
67             free(handle->db_args[count]);
68 
69         free(handle->db_args), handle->db_args = NULL;
70     }
71 
72     return ret;
73 }
74 
free_db_args(kadm5_server_handle_t handle)75 static void free_db_args(kadm5_server_handle_t handle)
76 {
77     int count;
78 
79     if (handle->db_args) {
80         for (count=0; handle->db_args[count]; count++)
81             free(handle->db_args[count]);
82 
83         free(handle->db_args), handle->db_args = NULL;
84     }
85 }
86 
kadm5_init_with_password(krb5_context context,char * client_name,char * pass,char * service_name,kadm5_config_params * params,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)87 kadm5_ret_t kadm5_init_with_password(krb5_context context, char *client_name,
88                                      char *pass, char *service_name,
89                                      kadm5_config_params *params,
90                                      krb5_ui_4 struct_version,
91                                      krb5_ui_4 api_version,
92                                      char **db_args,
93                                      void **server_handle)
94 {
95     return kadm5_init(context, client_name, pass, service_name, params,
96                       struct_version, api_version, db_args,
97                       server_handle);
98 }
99 
kadm5_init_anonymous(krb5_context context,char * client_name,char * service_name,kadm5_config_params * params,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)100 kadm5_ret_t kadm5_init_anonymous(krb5_context context, char *client_name,
101                                  char *service_name,
102                                  kadm5_config_params *params,
103                                  krb5_ui_4 struct_version,
104                                  krb5_ui_4 api_version,
105                                  char **db_args,
106                                  void **server_handle)
107 {
108     return kadm5_init(context, client_name, NULL, service_name, params,
109                       struct_version, api_version, db_args,
110                       server_handle);
111 }
112 
kadm5_init_with_creds(krb5_context context,char * client_name,krb5_ccache ccache,char * service_name,kadm5_config_params * params,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)113 kadm5_ret_t kadm5_init_with_creds(krb5_context context,
114                                   char *client_name,
115                                   krb5_ccache ccache,
116                                   char *service_name,
117                                   kadm5_config_params *params,
118                                   krb5_ui_4 struct_version,
119                                   krb5_ui_4 api_version,
120                                   char **db_args,
121                                   void **server_handle)
122 {
123     /*
124      * A program calling init_with_creds *never* expects to prompt
125      * the user.  If this is KADM5_API_VERSION_2 and MKEY_FROM_KBD is
126      * non-zero, return an error.
127      */
128     if (params && (params->mask & KADM5_CONFIG_MKEY_FROM_KBD) &&
129         params->mkey_from_kbd)
130         return KADM5_BAD_SERVER_PARAMS;
131     return kadm5_init(context, client_name, NULL, service_name, params,
132                       struct_version, api_version, db_args,
133                       server_handle);
134 }
135 
136 
kadm5_init_with_skey(krb5_context context,char * client_name,char * keytab,char * service_name,kadm5_config_params * params,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)137 kadm5_ret_t kadm5_init_with_skey(krb5_context context, char *client_name,
138                                  char *keytab, char *service_name,
139                                  kadm5_config_params *params,
140                                  krb5_ui_4 struct_version,
141                                  krb5_ui_4 api_version,
142                                  char **db_args,
143                                  void **server_handle)
144 {
145     /*
146      * A program calling init_with_skey *never* expects to prompt the
147      * user.  If this is KADM5_API_VERSION_2 and MKEY_FROM_KBD is
148      * non-zero, return an error.
149      */
150     if (params && (params->mask & KADM5_CONFIG_MKEY_FROM_KBD) &&
151         params->mkey_from_kbd)
152         return KADM5_BAD_SERVER_PARAMS;
153     return kadm5_init(context, client_name, NULL, service_name, params,
154                       struct_version, api_version, db_args,
155                       server_handle);
156 }
157 
kadm5_init(krb5_context context,char * client_name,char * pass,char * service_name,kadm5_config_params * params_in,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)158 kadm5_ret_t kadm5_init(krb5_context context, char *client_name, char *pass,
159                        char *service_name,
160                        kadm5_config_params *params_in,
161                        krb5_ui_4 struct_version,
162                        krb5_ui_4 api_version,
163                        char **db_args,
164                        void **server_handle)
165 {
166     int ret;
167     kadm5_server_handle_t handle;
168     kadm5_config_params params_local; /* for v1 compat */
169 
170     if (! server_handle)
171         return EINVAL;
172 
173     if (! client_name)
174         return EINVAL;
175 
176     if (! (handle = (kadm5_server_handle_t) malloc(sizeof *handle)))
177         return ENOMEM;
178     memset(handle, 0, sizeof(*handle));
179 
180     ret = dup_db_args(handle, db_args);
181     if (ret) {
182         free(handle);
183         return ret;
184     }
185 
186     handle->context = context;
187 
188     initialize_ovk_error_table();
189     initialize_ovku_error_table();
190 
191     handle->magic_number = KADM5_SERVER_HANDLE_MAGIC;
192     handle->struct_version = struct_version;
193     handle->api_version = api_version;
194 
195     /*
196      * Verify the version numbers before proceeding; we can't use
197      * CHECK_HANDLE because not all fields are set yet.
198      */
199     GENERIC_CHECK_HANDLE(handle, KADM5_OLD_SERVER_API_VERSION,
200                          KADM5_NEW_SERVER_API_VERSION);
201 
202     /*
203      * Acquire relevant profile entries.  Merge values
204      * in params_in with values from profile, based on
205      * params_in->mask.
206      */
207     memset(&params_local, 0, sizeof(params_local));
208 
209     ret = kadm5_get_config_params(handle->context, 1, params_in,
210                                   &handle->params);
211     if (ret) {
212         free_db_args(handle);
213         free(handle);
214         return(ret);
215     }
216 
217 #define REQUIRED_PARAMS (KADM5_CONFIG_REALM | KADM5_CONFIG_DBNAME |     \
218                          KADM5_CONFIG_ENCTYPE |                         \
219                          KADM5_CONFIG_FLAGS |                           \
220                          KADM5_CONFIG_MAX_LIFE | KADM5_CONFIG_MAX_RLIFE | \
221                          KADM5_CONFIG_EXPIRATION | KADM5_CONFIG_ENCTYPES)
222 
223 #define IPROP_REQUIRED_PARAMS                   \
224     (KADM5_CONFIG_IPROP_ENABLED |               \
225      KADM5_CONFIG_IPROP_LOGFILE |               \
226      KADM5_CONFIG_IPROP_PORT)
227 
228     if ((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
229         kadm5_free_config_params(handle->context, &handle->params);
230         free_db_args(handle);
231         free(handle);
232         return KADM5_MISSING_CONF_PARAMS;
233     }
234     if ((handle->params.mask & KADM5_CONFIG_IPROP_ENABLED) == KADM5_CONFIG_IPROP_ENABLED
235         && handle->params.iprop_enabled) {
236         if ((handle->params.mask & IPROP_REQUIRED_PARAMS) != IPROP_REQUIRED_PARAMS) {
237             kadm5_free_config_params(handle->context, &handle->params);
238             free_db_args(handle);
239             free(handle);
240             return KADM5_MISSING_CONF_PARAMS;
241         }
242     }
243 
244     ret = krb5_set_default_realm(handle->context, handle->params.realm);
245     if (ret) {
246         kadm5_free_config_params(handle->context, &handle->params);
247         free_db_args(handle);
248         free(handle);
249         return ret;
250     }
251 
252     ret = krb5_db_open(handle->context, db_args,
253                        KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN);
254     if (ret) {
255         kadm5_free_config_params(handle->context, &handle->params);
256         free_db_args(handle);
257         free(handle);
258         return(ret);
259     }
260 
261     if ((ret = krb5_parse_name(handle->context, client_name,
262                                &handle->current_caller))) {
263         kadm5_free_config_params(handle->context, &handle->params);
264         krb5_db_fini(handle->context);
265         free_db_args(handle);
266         free(handle);
267         return ret;
268     }
269 
270     if (! (handle->lhandle = malloc(sizeof(*handle)))) {
271         kadm5_free_config_params(handle->context, &handle->params);
272         krb5_db_fini(handle->context);
273         free_db_args(handle);
274         free(handle);
275         return ENOMEM;
276     }
277     *handle->lhandle = *handle;
278     handle->lhandle->api_version = KADM5_API_VERSION_4;
279     handle->lhandle->struct_version = KADM5_STRUCT_VERSION;
280     handle->lhandle->lhandle = handle->lhandle;
281 
282     /* can't check the handle until current_caller is set */
283     ret = check_handle((void *) handle);
284     if (ret) {
285         kadm5_free_config_params(handle->context, &handle->params);
286         free_db_args(handle);
287         free(handle);
288         return ret;
289     }
290 
291     ret = kdb_init_master(handle, handle->params.realm,
292                           (handle->params.mask & KADM5_CONFIG_MKEY_FROM_KBD)
293                           && handle->params.mkey_from_kbd);
294     if (ret) {
295         kadm5_free_config_params(handle->context, &handle->params);
296         krb5_db_fini(handle->context);
297         free_db_args(handle);
298         free(handle);
299         return ret;
300     }
301 
302     ret = kdb_init_hist(handle, handle->params.realm);
303     if (ret) {
304         kadm5_free_config_params(handle->context, &handle->params);
305         krb5_db_fini(handle->context);
306         free_db_args(handle);
307         free(handle);
308         return ret;
309     }
310 
311     ret = k5_kadm5_hook_load(context,&handle->hook_handles);
312     if (ret) {
313         kadm5_free_config_params(handle->context, &handle->params);
314         krb5_db_fini(handle->context);
315         krb5_free_principal(handle->context, handle->current_caller);
316         free_db_args(handle);
317         free(handle);
318         return ret;
319     }
320 
321     ret = init_pwqual(handle);
322     if (ret) {
323         kadm5_free_config_params(handle->context, &handle->params);
324         k5_kadm5_hook_free_handles(context, handle->hook_handles);
325         krb5_db_fini(handle->context);
326         krb5_free_principal(handle->context, handle->current_caller);
327         free_db_args(handle);
328         free(handle);
329         return ret;
330     }
331 
332     *server_handle = (void *) handle;
333 
334     return KADM5_OK;
335 }
336 
kadm5_destroy(void * server_handle)337 kadm5_ret_t kadm5_destroy(void *server_handle)
338 {
339     kadm5_server_handle_t handle = server_handle;
340 
341     CHECK_HANDLE(server_handle);
342 
343     destroy_pwqual(handle);
344 
345     k5_kadm5_hook_free_handles(handle->context, handle->hook_handles);
346     ulog_fini(handle->context);
347     krb5_db_fini(handle->context);
348     krb5_free_principal(handle->context, handle->current_caller);
349     kadm5_free_config_params(handle->context, &handle->params);
350     handle->magic_number = 0;
351     free(handle->lhandle);
352     free_db_args(handle);
353     free(handle);
354 
355     return KADM5_OK;
356 }
357 
kadm5_lock(void * server_handle)358 kadm5_ret_t kadm5_lock(void *server_handle)
359 {
360     kadm5_server_handle_t handle = server_handle;
361     kadm5_ret_t ret;
362 
363     CHECK_HANDLE(server_handle);
364     ret = krb5_db_lock(handle->context, KRB5_DB_LOCKMODE_EXCLUSIVE);
365     if (ret)
366         return ret;
367 
368     return KADM5_OK;
369 }
370 
kadm5_unlock(void * server_handle)371 kadm5_ret_t kadm5_unlock(void *server_handle)
372 {
373     kadm5_server_handle_t handle = server_handle;
374     kadm5_ret_t ret;
375 
376     CHECK_HANDLE(server_handle);
377     ret = krb5_db_unlock(handle->context);
378     if (ret)
379         return ret;
380 
381     return KADM5_OK;
382 }
383 
kadm5_flush(void * server_handle)384 kadm5_ret_t kadm5_flush(void *server_handle)
385 {
386     kadm5_server_handle_t handle = server_handle;
387     kadm5_ret_t ret;
388 
389     CHECK_HANDLE(server_handle);
390 
391     if ((ret = krb5_db_fini(handle->context)) ||
392         (ret = krb5_db_open(handle->context, handle->db_args,
393                             KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN))) {
394         (void) kadm5_destroy(server_handle);
395         return ret;
396     }
397     return KADM5_OK;
398 }
399 
_kadm5_check_handle(void * handle)400 int _kadm5_check_handle(void *handle)
401 {
402     CHECK_HANDLE(handle);
403     return 0;
404 }
405 
406 #include "gssapiP_krb5.h"
kadm5_init_krb5_context(krb5_context * ctx)407 krb5_error_code kadm5_init_krb5_context (krb5_context *ctx)
408 {
409     static int first_time = 1;
410     if (first_time) {
411         krb5_error_code err;
412         err = krb5_gss_use_kdc_context();
413         if (err)
414             return err;
415         first_time = 0;
416     }
417     return krb5int_init_context_kdc(ctx);
418 }
419 
420 krb5_error_code
kadm5_init_iprop(void * handle,char ** db_args)421 kadm5_init_iprop(void *handle, char **db_args)
422 {
423     kadm5_server_handle_t iprop_h;
424     krb5_error_code retval;
425 
426     iprop_h = handle;
427     if (iprop_h->params.iprop_enabled) {
428         ulog_set_role(iprop_h->context, IPROP_PRIMARY);
429         retval = ulog_map(iprop_h->context, iprop_h->params.iprop_logfile,
430                           iprop_h->params.iprop_ulogsize);
431         if (retval)
432             return (retval);
433     }
434     return (0);
435 }
436