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 "smbd/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
,
56 if (!NT_STATUS_IS_OK(status
)) {
57 ok
= kpasswd_make_error_reply(mem_ctx
,
58 KRB5_KPASSWD_ACCESSDENIED
,
62 *error_string
= "Failed to create reply";
63 return KRB5_KPASSWD_HARDERROR
;
65 /* We want to send an an authenticated packet. */
69 ok
= kpasswd_make_pwchange_reply(mem_ctx
,
75 *error_string
= "Failed to create reply";
76 return KRB5_KPASSWD_HARDERROR
;
82 static krb5_error_code
kpasswd_set_password(struct kdc_server
*kdc
,
84 struct auth_session_info
*session_info
,
85 DATA_BLOB
*decoded_data
,
86 DATA_BLOB
*kpasswd_reply
,
87 const char **error_string
)
89 krb5_context context
= kdc
->smb_krb5_context
->krb5_context
;
91 krb5_principal target_principal
;
92 ChangePasswdDataMS chpw
= {};
94 DATA_BLOB password
= data_blob_null
;
95 enum samPwdChangeReason reject_reason
= SAM_PWD_CHANGE_NO_ERROR
;
96 struct samr_DomInfo1
*dominfo
= NULL
;
97 char *target_principal_string
= NULL
;
98 bool is_service_principal
= false;
102 code
= decode_ChangePasswdDataMS(decoded_data
->data
,
103 decoded_data
->length
,
107 DBG_WARNING("decode_ChangePasswdDataMS failed\n");
108 ok
= kpasswd_make_error_reply(mem_ctx
,
109 KRB5_KPASSWD_MALFORMED
,
110 "Failed to decode packet",
113 *error_string
= "Failed to create reply";
114 return KRB5_KPASSWD_HARDERROR
;
119 ok
= convert_string_talloc_handle(mem_ctx
,
120 lpcfg_iconv_handle(kdc
->task
->lp_ctx
),
123 (const char *)chpw
.newpasswd
.data
,
124 chpw
.newpasswd
.length
,
125 (void **)&password
.data
,
128 free_ChangePasswdDataMS(&chpw
);
129 DBG_WARNING("String conversion failed\n");
130 *error_string
= "String conversion failed";
131 return KRB5_KPASSWD_HARDERROR
;
134 if ((chpw
.targname
!= NULL
&& chpw
.targrealm
== NULL
) ||
135 (chpw
.targname
== NULL
&& chpw
.targrealm
!= NULL
)) {
136 free_ChangePasswdDataMS(&chpw
);
137 ok
= kpasswd_make_error_reply(mem_ctx
,
138 KRB5_KPASSWD_MALFORMED
,
139 "Realm and principal must be "
140 "both present, or neither present",
143 *error_string
= "Failed to create reply";
144 return KRB5_KPASSWD_HARDERROR
;
149 if (chpw
.targname
!= NULL
&& chpw
.targrealm
!= NULL
) {
150 code
= krb5_build_principal_ext(context
,
152 strlen(*chpw
.targrealm
),
156 free_ChangePasswdDataMS(&chpw
);
157 return kpasswd_make_error_reply(mem_ctx
,
158 KRB5_KPASSWD_MALFORMED
,
159 "Failed to parse principal",
162 code
= copy_PrincipalName(chpw
.targname
,
163 &target_principal
->name
);
165 free_ChangePasswdDataMS(&chpw
);
166 krb5_free_principal(context
, target_principal
);
167 return kpasswd_make_error_reply(mem_ctx
,
168 KRB5_KPASSWD_MALFORMED
,
169 "Failed to parse principal",
173 free_ChangePasswdDataMS(&chpw
);
174 return kpasswd_change_password(kdc
,
181 free_ChangePasswdDataMS(&chpw
);
183 if (target_principal
->name
.name_string
.len
>= 2) {
184 is_service_principal
= true;
186 code
= krb5_unparse_name_short(context
,
188 &target_principal_string
);
190 code
= krb5_unparse_name(context
,
192 &target_principal_string
);
194 krb5_free_principal(context
, target_principal
);
196 ok
= kpasswd_make_error_reply(mem_ctx
,
197 KRB5_KPASSWD_MALFORMED
,
198 "Failed to parse principal",
201 *error_string
= "Failed to create reply";
202 return KRB5_KPASSWD_HARDERROR
;
206 status
= kpasswd_samdb_set_password(mem_ctx
,
207 kdc
->task
->event_ctx
,
210 is_service_principal
,
211 target_principal_string
,
215 if (!NT_STATUS_IS_OK(status
)) {
216 DBG_ERR("kpasswd_samdb_set_password failed - %s\n",
220 ok
= kpasswd_make_pwchange_reply(mem_ctx
,
226 *error_string
= "Failed to create reply";
227 return KRB5_KPASSWD_HARDERROR
;
233 krb5_error_code
kpasswd_handle_request(struct kdc_server
*kdc
,
235 struct gensec_security
*gensec_security
,
237 DATA_BLOB
*decoded_data
,
238 DATA_BLOB
*kpasswd_reply
,
239 const char **error_string
)
241 struct auth_session_info
*session_info
;
244 status
= gensec_session_info(gensec_security
,
247 if (!NT_STATUS_IS_OK(status
)) {
248 *error_string
= talloc_asprintf(mem_ctx
,
249 "gensec_session_info failed - %s",
251 return KRB5_KPASSWD_HARDERROR
;
255 case KRB5_KPASSWD_VERS_CHANGEPW
: {
256 DATA_BLOB password
= data_blob_null
;
259 ok
= convert_string_talloc_handle(mem_ctx
,
260 lpcfg_iconv_handle(kdc
->task
->lp_ctx
),
263 (const char *)decoded_data
->data
,
264 decoded_data
->length
,
265 (void **)&password
.data
,
268 *error_string
= "String conversion failed!";
269 DBG_WARNING("%s\n", *error_string
);
270 return KRB5_KPASSWD_HARDERROR
;
273 return kpasswd_change_password(kdc
,
280 case KRB5_KPASSWD_VERS_SETPW
: {
281 return kpasswd_set_password(kdc
,
289 *error_string
= talloc_asprintf(mem_ctx
,
290 "Protocol version %u not supported",
292 return KRB5_KPASSWD_BAD_VERSION
;