xref: /freebsd/crypto/krb5/src/lib/kadm5/srv/svr_policy.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
4  *
5  * $Header$
6  */
7 
8 #include        <sys/types.h>
9 #include        <kadm5/admin.h>
10 #include        "server_internal.h"
11 #include        <stdlib.h>
12 #include        <string.h>
13 #include        <errno.h>
14 
15 #define MIN_PW_HISTORY  1
16 #define MIN_PW_CLASSES  1
17 #define MAX_PW_CLASSES  5
18 #define MIN_PW_LENGTH   1
19 
20 /* Validate allowed_keysalts. */
21 static kadm5_ret_t
validate_allowed_keysalts(const char * allowed_keysalts)22 validate_allowed_keysalts(const char *allowed_keysalts)
23 {
24     kadm5_ret_t ret;
25     krb5_key_salt_tuple *ks_tuple = NULL;
26     krb5_int32 n_ks_tuple = 0;
27 
28     if (strchr(allowed_keysalts, '\t') != NULL)
29         return KADM5_BAD_KEYSALTS;
30     ret = krb5_string_to_keysalts(allowed_keysalts, ",", NULL, 0,
31                                   &ks_tuple, &n_ks_tuple);
32     free(ks_tuple);
33     if (ret == EINVAL)
34         return KADM5_BAD_KEYSALTS;
35     return ret;
36 }
37 
38 /*
39  * Function: kadm5_create_policy
40  *
41  * Purpose: Create Policies in the policy DB.
42  *
43  * Arguments:
44  *      entry   (input) The policy entry to be written out to the DB.
45  *      mask    (input) Specifies which fields in entry are to ge written out
46  *                      and which get default values.
47  *      <return value> 0 if successful otherwise an error code is returned.
48  *
49  * Requires:
50  *      Entry must be a valid principal entry, and mask have a valid value.
51  *
52  * Effects:
53  *      Writes the data to the database, and does a database sync if
54  *      successful.
55  *
56  */
57 
58 kadm5_ret_t
kadm5_create_policy(void * server_handle,kadm5_policy_ent_t entry,long mask)59 kadm5_create_policy(void *server_handle, kadm5_policy_ent_t entry, long mask)
60 {
61     kadm5_server_handle_t handle = server_handle;
62     osa_policy_ent_rec  pent, *check_pol;
63     int                 ret;
64     char                *p;
65 
66     CHECK_HANDLE(server_handle);
67 
68     krb5_clear_error_message(handle->context);
69 
70     if ((entry == (kadm5_policy_ent_t) NULL) || (entry->policy == NULL))
71         return EINVAL;
72     if(strlen(entry->policy) == 0)
73         return KADM5_BAD_POLICY;
74     if (!(mask & KADM5_POLICY) || (mask & ~ALL_POLICY_MASK))
75         return KADM5_BAD_MASK;
76     if ((mask & KADM5_POLICY_ALLOWED_KEYSALTS) &&
77         entry->allowed_keysalts != NULL) {
78         ret = validate_allowed_keysalts(entry->allowed_keysalts);
79         if (ret)
80             return ret;
81     }
82 
83     ret = krb5_db_get_policy(handle->context, entry->policy, &check_pol);
84     if (!ret) {
85         krb5_db_free_policy(handle->context, check_pol);
86         return KADM5_DUP;
87     } else if (ret != KRB5_KDB_NOENTRY) {
88         return ret;
89     }
90 
91     memset(&pent, 0, sizeof(pent));
92     pent.name = entry->policy;
93     p = entry->policy;
94     while(*p != '\0') {
95         if(*p < ' ' || *p > '~')
96             return KADM5_BAD_POLICY;
97         else
98             p++;
99     }
100     if (!(mask & KADM5_PW_MAX_LIFE))
101         pent.pw_max_life = 0;
102     else
103         pent.pw_max_life = entry->pw_max_life;
104     if (!(mask & KADM5_PW_MIN_LIFE))
105         pent.pw_min_life = 0;
106     else {
107         if((mask & KADM5_PW_MAX_LIFE)) {
108             if(entry->pw_min_life > entry->pw_max_life && entry->pw_max_life != 0)
109                 return KADM5_BAD_MIN_PASS_LIFE;
110         }
111         pent.pw_min_life = entry->pw_min_life;
112     }
113     if (!(mask & KADM5_PW_MIN_LENGTH))
114         pent.pw_min_length = MIN_PW_LENGTH;
115     else {
116         if(entry->pw_min_length < MIN_PW_LENGTH)
117             return KADM5_BAD_LENGTH;
118         pent.pw_min_length = entry->pw_min_length;
119     }
120     if (!(mask & KADM5_PW_MIN_CLASSES))
121         pent.pw_min_classes = MIN_PW_CLASSES;
122     else {
123         if(entry->pw_min_classes > MAX_PW_CLASSES || entry->pw_min_classes < MIN_PW_CLASSES)
124             return KADM5_BAD_CLASS;
125         pent.pw_min_classes = entry->pw_min_classes;
126     }
127     if (!(mask & KADM5_PW_HISTORY_NUM))
128         pent.pw_history_num = MIN_PW_HISTORY;
129     else {
130         if(entry->pw_history_num < MIN_PW_HISTORY)
131             return KADM5_BAD_HISTORY;
132         else
133             pent.pw_history_num = entry->pw_history_num;
134     }
135 
136     if (handle->api_version >= KADM5_API_VERSION_4) {
137         if (!(mask & KADM5_POLICY_ATTRIBUTES))
138             pent.attributes = 0;
139         else
140             pent.attributes = entry->attributes;
141         if (!(mask & KADM5_POLICY_MAX_LIFE))
142             pent.max_life = 0;
143         else
144             pent.max_life = entry->max_life;
145         if (!(mask & KADM5_POLICY_MAX_RLIFE))
146             pent.max_renewable_life = 0;
147         else
148             pent.max_renewable_life = entry->max_renewable_life;
149         if (!(mask & KADM5_POLICY_ALLOWED_KEYSALTS))
150             pent.allowed_keysalts = 0;
151         else
152             pent.allowed_keysalts = entry->allowed_keysalts;
153         if (!(mask & KADM5_POLICY_TL_DATA)) {
154             pent.n_tl_data = 0;
155             pent.tl_data = NULL;
156         } else {
157             pent.n_tl_data = entry->n_tl_data;
158             pent.tl_data = entry->tl_data;
159         }
160     }
161     if (handle->api_version >= KADM5_API_VERSION_3) {
162         if (!(mask & KADM5_PW_MAX_FAILURE))
163             pent.pw_max_fail = 0;
164         else
165             pent.pw_max_fail = entry->pw_max_fail;
166         if (!(mask & KADM5_PW_FAILURE_COUNT_INTERVAL))
167             pent.pw_failcnt_interval = 0;
168         else
169             pent.pw_failcnt_interval = entry->pw_failcnt_interval;
170         if (!(mask & KADM5_PW_LOCKOUT_DURATION))
171             pent.pw_lockout_duration = 0;
172         else
173             pent.pw_lockout_duration = entry->pw_lockout_duration;
174     }
175 
176     if ((ret = krb5_db_create_policy(handle->context, &pent)))
177         return ret;
178     else
179         return KADM5_OK;
180 }
181 
182 kadm5_ret_t
kadm5_delete_policy(void * server_handle,kadm5_policy_t name)183 kadm5_delete_policy(void *server_handle, kadm5_policy_t name)
184 {
185     kadm5_server_handle_t handle = server_handle;
186     osa_policy_ent_t            entry;
187     int                         ret;
188 
189     CHECK_HANDLE(server_handle);
190 
191     krb5_clear_error_message(handle->context);
192 
193     if(name == (kadm5_policy_t) NULL)
194         return EINVAL;
195     if(strlen(name) == 0)
196         return KADM5_BAD_POLICY;
197     ret = krb5_db_get_policy(handle->context, name, &entry);
198     if (ret == KRB5_KDB_NOENTRY)
199         return KADM5_UNK_POLICY;
200     else if (ret)
201         return ret;
202 
203     krb5_db_free_policy(handle->context, entry);
204     ret = krb5_db_delete_policy(handle->context, name);
205     if (ret == KRB5_KDB_POLICY_REF)
206         ret = KADM5_POLICY_REF;
207     return (ret == 0) ? KADM5_OK : ret;
208 }
209 
210 /* Allocate and form a TL data list of a desired size. */
211 static int
alloc_tl_data(krb5_int16 n_tl_data,krb5_tl_data ** tldp)212 alloc_tl_data(krb5_int16 n_tl_data, krb5_tl_data **tldp)
213 {
214     krb5_tl_data **tlp = tldp;
215     int i;
216 
217     for (i = 0; i < n_tl_data; i++) {
218         *tlp = calloc(1, sizeof(krb5_tl_data));
219         if (*tlp == NULL)
220             return ENOMEM; /* caller cleans up */
221         memset(*tlp, 0, sizeof(krb5_tl_data));
222         tlp = &((*tlp)->tl_data_next);
223     }
224 
225     return 0;
226 }
227 
228 static kadm5_ret_t
copy_tl_data(krb5_int16 n_tl_data,krb5_tl_data * tl_data,krb5_tl_data ** out)229 copy_tl_data(krb5_int16 n_tl_data, krb5_tl_data *tl_data,
230              krb5_tl_data **out)
231 {
232     kadm5_ret_t ret;
233     krb5_tl_data *tl, *tl_new;
234 
235     if ((ret = alloc_tl_data(n_tl_data, out)))
236         return ret; /* caller cleans up */
237 
238     tl = tl_data;
239     tl_new = *out;
240     for (; tl; tl = tl->tl_data_next, tl_new = tl_new->tl_data_next) {
241         tl_new->tl_data_contents = malloc(tl->tl_data_length);
242         if (tl_new->tl_data_contents == NULL)
243             return ENOMEM;
244         memcpy(tl_new->tl_data_contents, tl->tl_data_contents,
245                tl->tl_data_length);
246         tl_new->tl_data_type = tl->tl_data_type;
247         tl_new->tl_data_length = tl->tl_data_length;
248     }
249 
250     return 0;
251 }
252 
253 kadm5_ret_t
kadm5_modify_policy(void * server_handle,kadm5_policy_ent_t entry,long mask)254 kadm5_modify_policy(void *server_handle, kadm5_policy_ent_t entry, long mask)
255 {
256     kadm5_server_handle_t    handle = server_handle;
257     krb5_tl_data            *tl;
258     osa_policy_ent_t         p;
259     int                      ret;
260 
261     CHECK_HANDLE(server_handle);
262 
263     krb5_clear_error_message(handle->context);
264 
265     if((entry == (kadm5_policy_ent_t) NULL) || (entry->policy == NULL))
266         return EINVAL;
267     if(strlen(entry->policy) == 0)
268         return KADM5_BAD_POLICY;
269     if ((mask & KADM5_POLICY) || (mask & ~ALL_POLICY_MASK))
270         return KADM5_BAD_MASK;
271     if ((mask & KADM5_POLICY_ALLOWED_KEYSALTS) &&
272         entry->allowed_keysalts != NULL) {
273         ret = validate_allowed_keysalts(entry->allowed_keysalts);
274         if (ret)
275             return ret;
276     }
277     if ((mask & KADM5_POLICY_TL_DATA)) {
278         tl = entry->tl_data;
279         while (tl != NULL) {
280             if (tl->tl_data_type < 256)
281                 return KADM5_BAD_TL_TYPE;
282             tl = tl->tl_data_next;
283         }
284     }
285 
286     ret = krb5_db_get_policy(handle->context, entry->policy, &p);
287     if (ret == KRB5_KDB_NOENTRY)
288         return KADM5_UNK_POLICY;
289     else if (ret)
290         return ret;
291 
292     if ((mask & KADM5_PW_MAX_LIFE))
293         p->pw_max_life = entry->pw_max_life;
294     if ((mask & KADM5_PW_MIN_LIFE)) {
295         if(entry->pw_min_life > p->pw_max_life && p->pw_max_life != 0)  {
296             krb5_db_free_policy(handle->context, p);
297             return KADM5_BAD_MIN_PASS_LIFE;
298         }
299         p->pw_min_life = entry->pw_min_life;
300     }
301     if ((mask & KADM5_PW_MIN_LENGTH)) {
302         if(entry->pw_min_length < MIN_PW_LENGTH) {
303             krb5_db_free_policy(handle->context, p);
304             return KADM5_BAD_LENGTH;
305         }
306         p->pw_min_length = entry->pw_min_length;
307     }
308     if ((mask & KADM5_PW_MIN_CLASSES)) {
309         if(entry->pw_min_classes > MAX_PW_CLASSES ||
310            entry->pw_min_classes < MIN_PW_CLASSES) {
311             krb5_db_free_policy(handle->context, p);
312             return KADM5_BAD_CLASS;
313         }
314         p->pw_min_classes = entry->pw_min_classes;
315     }
316     if ((mask & KADM5_PW_HISTORY_NUM)) {
317         if(entry->pw_history_num < MIN_PW_HISTORY) {
318             krb5_db_free_policy(handle->context, p);
319             return KADM5_BAD_HISTORY;
320         }
321         p->pw_history_num = entry->pw_history_num;
322     }
323     if (handle->api_version >= KADM5_API_VERSION_3) {
324         if ((mask & KADM5_PW_MAX_FAILURE))
325             p->pw_max_fail = entry->pw_max_fail;
326         if ((mask & KADM5_PW_FAILURE_COUNT_INTERVAL))
327             p->pw_failcnt_interval = entry->pw_failcnt_interval;
328         if ((mask & KADM5_PW_LOCKOUT_DURATION))
329             p->pw_lockout_duration = entry->pw_lockout_duration;
330     }
331     if (handle->api_version >= KADM5_API_VERSION_4) {
332         if ((mask & KADM5_POLICY_ATTRIBUTES))
333             p->attributes = entry->attributes;
334         if ((mask & KADM5_POLICY_MAX_LIFE))
335             p->max_life = entry->max_life;
336         if ((mask & KADM5_POLICY_MAX_RLIFE))
337             p->max_renewable_life = entry->max_renewable_life;
338         if ((mask & KADM5_POLICY_ALLOWED_KEYSALTS)) {
339             free(p->allowed_keysalts);
340             p->allowed_keysalts = NULL;
341             if (entry->allowed_keysalts != NULL) {
342                 p->allowed_keysalts = strdup(entry->allowed_keysalts);
343                 if (p->allowed_keysalts == NULL) {
344                     ret = ENOMEM;
345                     goto cleanup;
346                 }
347             }
348         }
349         if ((mask & KADM5_POLICY_TL_DATA)) {
350             for (tl = entry->tl_data; tl != NULL; tl = tl->tl_data_next) {
351                 ret = krb5_db_update_tl_data(handle->context, &p->n_tl_data,
352                                              &p->tl_data, tl);
353                 if (ret)
354                     goto cleanup;
355             }
356         }
357     }
358     ret = krb5_db_put_policy(handle->context, p);
359 
360 cleanup:
361     krb5_db_free_policy(handle->context, p);
362     return ret;
363 }
364 
365 kadm5_ret_t
kadm5_get_policy(void * server_handle,kadm5_policy_t name,kadm5_policy_ent_t entry)366 kadm5_get_policy(void *server_handle, kadm5_policy_t name,
367                  kadm5_policy_ent_t entry)
368 {
369     osa_policy_ent_t            t;
370     kadm5_ret_t                 ret;
371     kadm5_server_handle_t handle = server_handle;
372 
373     memset(entry, 0, sizeof(*entry));
374 
375     CHECK_HANDLE(server_handle);
376 
377     krb5_clear_error_message(handle->context);
378 
379     if (name == (kadm5_policy_t) NULL)
380         return EINVAL;
381     if(strlen(name) == 0)
382         return KADM5_BAD_POLICY;
383     ret = krb5_db_get_policy(handle->context, name, &t);
384     if (ret == KRB5_KDB_NOENTRY)
385         return KADM5_UNK_POLICY;
386     else if (ret)
387         return ret;
388 
389     if ((entry->policy = strdup(t->name)) == NULL) {
390         ret = ENOMEM;
391         goto cleanup;
392     }
393     entry->pw_min_life = t->pw_min_life;
394     entry->pw_max_life = t->pw_max_life;
395     entry->pw_min_length = t->pw_min_length;
396     entry->pw_min_classes = t->pw_min_classes;
397     entry->pw_history_num = t->pw_history_num;
398     if (handle->api_version >= KADM5_API_VERSION_3) {
399         entry->pw_max_fail = t->pw_max_fail;
400         entry->pw_failcnt_interval = t->pw_failcnt_interval;
401         entry->pw_lockout_duration = t->pw_lockout_duration;
402     }
403     if (handle->api_version >= KADM5_API_VERSION_4) {
404         entry->attributes = t->attributes;
405         entry->max_life = t->max_life;
406         entry->max_renewable_life = t->max_renewable_life;
407         if (t->allowed_keysalts) {
408             entry->allowed_keysalts = strdup(t->allowed_keysalts);
409             if (!entry->allowed_keysalts) {
410                 ret = ENOMEM;
411                 goto cleanup;
412             }
413         }
414         ret = copy_tl_data(t->n_tl_data, t->tl_data, &entry->tl_data);
415         if (ret)
416             goto cleanup;
417         entry->n_tl_data = t->n_tl_data;
418     }
419 
420     ret = 0;
421 
422 cleanup:
423     if (ret)
424         kadm5_free_policy_ent(handle, entry);
425     krb5_db_free_policy(handle->context, t);
426     return ret;
427 }
428