Imported Upstream version 1.17
[platform/upstream/krb5.git] / src / kadmin / server / misc.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
4  *
5  */
6
7 #include    <k5-int.h>
8 #include    <kdb.h>
9 #include    <kadm5/server_internal.h>
10 #include    "misc.h"
11 #include    "auth.h"
12 #include    "net-server.h"
13 kadm5_ret_t
14 schpw_util_wrapper(void *server_handle,
15                    krb5_principal client,
16                    krb5_principal target,
17                    krb5_boolean initial_flag,
18                    char *new_pw, char **ret_pw,
19                    char *msg_ret, unsigned int msg_len)
20 {
21     kadm5_ret_t                 ret;
22     kadm5_server_handle_t       handle = server_handle;
23
24     /*
25      * If no target is explicitly provided, then the target principal
26      * is the client principal.
27      */
28     if (target == NULL)
29         target = client;
30
31     /* If the client is changing its own password, require it to use an initial
32      * ticket, and enforce the policy min_life. */
33     if (krb5_principal_compare(handle->context, client, target)) {
34         if (!initial_flag) {
35             strlcpy(msg_ret, "Ticket must be derived from a password",
36                     msg_len);
37             return KADM5_AUTH_INITIAL;
38         }
39
40         ret = check_min_life(server_handle, target, msg_ret, msg_len);
41         if (ret != 0)
42             return ret;
43     }
44
45     if (auth(handle->context, OP_CPW, client, target,
46              NULL, NULL, NULL, NULL, 0)) {
47         ret = kadm5_chpass_principal_util(server_handle,
48                                           target,
49                                           new_pw, ret_pw,
50                                           msg_ret, msg_len);
51     } else {
52         ret = KADM5_AUTH_CHANGEPW;
53         strlcpy(msg_ret, "Unauthorized request", msg_len);
54     }
55
56     return ret;
57 }
58
59 kadm5_ret_t
60 check_min_life(void *server_handle, krb5_principal principal,
61                char *msg_ret, unsigned int msg_len)
62 {
63     krb5_timestamp              now;
64     kadm5_ret_t                 ret;
65     kadm5_policy_ent_rec        pol;
66     kadm5_principal_ent_rec     princ;
67     kadm5_server_handle_t       handle = server_handle;
68
69     if (msg_ret != NULL)
70         *msg_ret = '\0';
71
72     ret = krb5_timeofday(handle->context, &now);
73     if (ret)
74         return ret;
75
76     ret = kadm5_get_principal(handle->lhandle, principal,
77                               &princ, KADM5_PRINCIPAL_NORMAL_MASK);
78     if(ret)
79         return ret;
80     if(princ.aux_attributes & KADM5_POLICY) {
81         /* Look up the policy.  If it doesn't exist, treat this principal as if
82          * it had no policy. */
83         if((ret=kadm5_get_policy(handle->lhandle,
84                                  princ.policy, &pol)) != KADM5_OK) {
85             (void) kadm5_free_principal_ent(handle->lhandle, &princ);
86             return (ret == KADM5_UNK_POLICY) ? 0 : ret;
87         }
88         if(ts_delta(now, princ.last_pwd_change) < pol.pw_min_life &&
89            !(princ.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
90             if (msg_ret != NULL) {
91                 time_t until;
92                 char *time_string, *ptr;
93                 const char *errstr;
94
95                 until = princ.last_pwd_change + pol.pw_min_life;
96
97                 time_string = ctime(&until);
98                 if (time_string == NULL)
99                     time_string = "(error)";
100                 errstr = error_message(CHPASS_UTIL_PASSWORD_TOO_SOON);
101
102                 if (strlen(errstr) + strlen(time_string) < msg_len) {
103                     if (*(ptr = &time_string[strlen(time_string)-1]) == '\n')
104                         *ptr = '\0';
105                     snprintf(msg_ret, msg_len, errstr, time_string);
106                 }
107             }
108
109             (void) kadm5_free_policy_ent(handle->lhandle, &pol);
110             (void) kadm5_free_principal_ent(handle->lhandle, &princ);
111             return KADM5_PASS_TOOSOON;
112         }
113
114         ret = kadm5_free_policy_ent(handle->lhandle, &pol);
115         if (ret) {
116             (void) kadm5_free_principal_ent(handle->lhandle, &princ);
117             return ret;
118         }
119     }
120
121     return kadm5_free_principal_ent(handle->lhandle, &princ);
122 }
123
124 #define MAXPRINCLEN 125
125
126 void
127 trunc_name(size_t *len, char **dots)
128 {
129     *dots = *len > MAXPRINCLEN ? "..." : "";
130     *len = *len > MAXPRINCLEN ? MAXPRINCLEN : *len;
131 }
132
133 krb5_error_code
134 make_toolong_error (void *handle, krb5_data **out)
135 {
136     krb5_error errpkt;
137     krb5_error_code retval;
138     krb5_data *scratch;
139     kadm5_server_handle_t server_handle = (kadm5_server_handle_t)handle;
140
141     retval = krb5_us_timeofday(server_handle->context, &errpkt.stime, &errpkt.susec);
142     if (retval)
143         return retval;
144     errpkt.error = KRB_ERR_FIELD_TOOLONG;
145     retval = krb5_build_principal(server_handle->context, &errpkt.server,
146                                   strlen(server_handle->params.realm),
147                                   server_handle->params.realm,
148                                   "kadmin", "changepw", NULL);
149     if (retval)
150         return retval;
151     errpkt.client = NULL;
152     errpkt.cusec = 0;
153     errpkt.ctime = 0;
154     errpkt.text.length = 0;
155     errpkt.text.data = 0;
156     errpkt.e_data.length = 0;
157     errpkt.e_data.data = 0;
158     scratch = malloc(sizeof(*scratch));
159     if (scratch == NULL)
160         return ENOMEM;
161     retval = krb5_mk_error(server_handle->context, &errpkt, scratch);
162     if (retval) {
163         free(scratch);
164         return retval;
165     }
166
167     *out = scratch;
168     return 0;
169 }
170
171 krb5_context get_context(void *handle)
172 {
173     kadm5_server_handle_t server_handle = (kadm5_server_handle_t)handle;
174     return server_handle->context;
175 }