2 Unix SMB/CIFS implementation.
4 Samba kpasswd implementation
6 Copyright (c) 2016 Andreas Schneider <asn@samba.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "samba/service_task.h"
24 #include "param/param.h"
25 #include "auth/auth.h"
26 #include "auth/gensec/gensec.h"
27 #include "kdc/kdc-server.h"
28 #include "kdc/kpasswd_glue.h"
29 #include "kdc/kpasswd-service.h"
30 #include "kdc/kpasswd-helper.h"
32 static krb5_error_code
kpasswd_change_password(struct kdc_server
*kdc
,
34 struct auth_session_info
*session_info
,
36 DATA_BLOB
*kpasswd_reply
,
37 const char **error_string
)
40 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
41 enum samPwdChangeReason reject_reason
;
42 const char *reject_string
= NULL
;
43 struct samr_DomInfo1
*dominfo
;
46 status
= samdb_kpasswd_change_password(mem_ctx
,
55 if (!NT_STATUS_IS_OK(status
)) {
56 ok
= kpasswd_make_error_reply(mem_ctx
,
57 KRB5_KPASSWD_ACCESSDENIED
,
61 *error_string
= "Failed to create reply";
62 return KRB5_KPASSWD_HARDERROR
;
64 /* We want to send an an authenticated packet. */
68 ok
= kpasswd_make_pwchange_reply(mem_ctx
,
74 *error_string
= "Failed to create reply";
75 return KRB5_KPASSWD_HARDERROR
;
81 static krb5_error_code
kpasswd_set_password(struct kdc_server
*kdc
,
83 struct auth_session_info
*session_info
,
84 DATA_BLOB
*decoded_data
,
85 DATA_BLOB
*kpasswd_reply
,
86 const char **error_string
)
88 krb5_context context
= kdc
->smb_krb5_context
->krb5_context
;
90 krb5_principal target_principal
;
91 ChangePasswdDataMS chpw
= {};
93 DATA_BLOB password
= data_blob_null
;
94 enum samPwdChangeReason reject_reason
= SAM_PWD_CHANGE_NO_ERROR
;
95 struct samr_DomInfo1
*dominfo
= NULL
;
96 char *target_principal_string
= NULL
;
97 bool is_service_principal
= false;
101 code
= decode_ChangePasswdDataMS(decoded_data
->data
,
102 decoded_data
->length
,
106 DBG_WARNING("decode_ChangePasswdDataMS failed\n");
107 ok
= kpasswd_make_error_reply(mem_ctx
,
108 KRB5_KPASSWD_MALFORMED
,
109 "Failed to decode packet",
112 *error_string
= "Failed to create reply";
113 return KRB5_KPASSWD_HARDERROR
;
118 ok
= convert_string_talloc_handle(mem_ctx
,
119 lpcfg_iconv_handle(kdc
->task
->lp_ctx
),
122 (const char *)chpw
.newpasswd
.data
,
123 chpw
.newpasswd
.length
,
124 (void **)&password
.data
,
127 free_ChangePasswdDataMS(&chpw
);
128 DBG_WARNING("String conversion failed\n");
129 *error_string
= "String conversion failed";
130 return KRB5_KPASSWD_HARDERROR
;
133 if ((chpw
.targname
!= NULL
&& chpw
.targrealm
== NULL
) ||
134 (chpw
.targname
== NULL
&& chpw
.targrealm
!= NULL
)) {
135 free_ChangePasswdDataMS(&chpw
);
136 ok
= kpasswd_make_error_reply(mem_ctx
,
137 KRB5_KPASSWD_MALFORMED
,
138 "Realm and principal must be "
139 "both present, or neither present",
142 *error_string
= "Failed to create reply";
143 return KRB5_KPASSWD_HARDERROR
;
148 if (chpw
.targname
!= NULL
&& chpw
.targrealm
!= NULL
) {
149 code
= krb5_build_principal_ext(context
,
151 strlen(*chpw
.targrealm
),
155 free_ChangePasswdDataMS(&chpw
);
156 return kpasswd_make_error_reply(mem_ctx
,
157 KRB5_KPASSWD_MALFORMED
,
158 "Failed to parse principal",
161 code
= copy_PrincipalName(chpw
.targname
,
162 &target_principal
->name
);
164 free_ChangePasswdDataMS(&chpw
);
165 krb5_free_principal(context
, target_principal
);
166 return kpasswd_make_error_reply(mem_ctx
,
167 KRB5_KPASSWD_MALFORMED
,
168 "Failed to parse principal",
172 free_ChangePasswdDataMS(&chpw
);
173 return kpasswd_change_password(kdc
,
180 free_ChangePasswdDataMS(&chpw
);
182 if (target_principal
->name
.name_string
.len
>= 2) {
183 is_service_principal
= true;
185 code
= krb5_unparse_name_short(context
,
187 &target_principal_string
);
189 code
= krb5_unparse_name(context
,
191 &target_principal_string
);
193 krb5_free_principal(context
, target_principal
);
195 ok
= kpasswd_make_error_reply(mem_ctx
,
196 KRB5_KPASSWD_MALFORMED
,
197 "Failed to parse principal",
200 *error_string
= "Failed to create reply";
201 return KRB5_KPASSWD_HARDERROR
;
205 status
= kpasswd_samdb_set_password(mem_ctx
,
206 kdc
->task
->event_ctx
,
209 is_service_principal
,
210 target_principal_string
,
214 if (!NT_STATUS_IS_OK(status
)) {
215 DBG_ERR("kpasswd_samdb_set_password failed - %s\n",
219 ok
= kpasswd_make_pwchange_reply(mem_ctx
,
225 *error_string
= "Failed to create reply";
226 return KRB5_KPASSWD_HARDERROR
;
232 krb5_error_code
kpasswd_handle_request(struct kdc_server
*kdc
,
234 struct gensec_security
*gensec_security
,
236 DATA_BLOB
*decoded_data
,
237 DATA_BLOB
*kpasswd_reply
,
238 const char **error_string
)
240 struct auth_session_info
*session_info
;
243 status
= gensec_session_info(gensec_security
,
246 if (!NT_STATUS_IS_OK(status
)) {
247 *error_string
= talloc_asprintf(mem_ctx
,
248 "gensec_session_info failed - %s",
250 return KRB5_KPASSWD_HARDERROR
;
254 case KRB5_KPASSWD_VERS_CHANGEPW
: {
255 DATA_BLOB password
= data_blob_null
;
258 ok
= convert_string_talloc_handle(mem_ctx
,
259 lpcfg_iconv_handle(kdc
->task
->lp_ctx
),
262 (const char *)decoded_data
->data
,
263 decoded_data
->length
,
264 (void **)&password
.data
,
267 *error_string
= "String conversion failed!";
268 DBG_WARNING("%s\n", *error_string
);
269 return KRB5_KPASSWD_HARDERROR
;
272 return kpasswd_change_password(kdc
,
279 case KRB5_KPASSWD_VERS_SETPW
: {
280 return kpasswd_set_password(kdc
,
288 *error_string
= talloc_asprintf(mem_ctx
,
289 "Protocol version %u not supported",
291 return KRB5_KPASSWD_BAD_VERSION
;