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