passdb: Use dom_sid_str_buf
[amitay/samba.git] / source4 / kdc / kpasswd-service-heimdal.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Samba kpasswd implementation
5
6    Copyright (c) 2016      Andreas Schneider <asn@samba.org>
7
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.
12
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.
17
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/>.
20 */
21
22 #include "includes.h"
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"
31
32 static krb5_error_code kpasswd_change_password(struct kdc_server *kdc,
33                                                TALLOC_CTX *mem_ctx,
34                                                struct auth_session_info *session_info,
35                                                DATA_BLOB *password,
36                                                DATA_BLOB *kpasswd_reply,
37                                                const char **error_string)
38 {
39         NTSTATUS status;
40         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
41         enum samPwdChangeReason reject_reason;
42         const char *reject_string = NULL;
43         struct samr_DomInfo1 *dominfo;
44         bool ok;
45
46         status = samdb_kpasswd_change_password(mem_ctx,
47                                                kdc->task->lp_ctx,
48                                                kdc->task->event_ctx,
49                                                kdc->samdb,
50                                                session_info,
51                                                password,
52                                                &reject_reason,
53                                                &dominfo,
54                                                &reject_string,
55                                                &result);
56         if (!NT_STATUS_IS_OK(status)) {
57                 ok = kpasswd_make_error_reply(mem_ctx,
58                                               KRB5_KPASSWD_ACCESSDENIED,
59                                               reject_string,
60                                               kpasswd_reply);
61                 if (!ok) {
62                         *error_string = "Failed to create reply";
63                         return KRB5_KPASSWD_HARDERROR;
64                 }
65                 /* We want to send an an authenticated packet. */
66                 return 0;
67         }
68
69         ok = kpasswd_make_pwchange_reply(mem_ctx,
70                                          result,
71                                          reject_reason,
72                                          dominfo,
73                                          kpasswd_reply);
74         if (!ok) {
75                 *error_string = "Failed to create reply";
76                 return KRB5_KPASSWD_HARDERROR;
77         }
78
79         return 0;
80 }
81
82 static krb5_error_code kpasswd_set_password(struct kdc_server *kdc,
83                                             TALLOC_CTX *mem_ctx,
84                                             struct auth_session_info *session_info,
85                                             DATA_BLOB *decoded_data,
86                                             DATA_BLOB *kpasswd_reply,
87                                             const char **error_string)
88 {
89         krb5_context context = kdc->smb_krb5_context->krb5_context;
90         krb5_error_code code;
91         krb5_principal target_principal;
92         ChangePasswdDataMS chpw = {};
93         size_t chpw_len = 0;
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;
99         NTSTATUS status;
100         bool ok;
101
102         code = decode_ChangePasswdDataMS(decoded_data->data,
103                                          decoded_data->length,
104                                          &chpw,
105                                          &chpw_len);
106         if (code != 0) {
107                 DBG_WARNING("decode_ChangePasswdDataMS failed\n");
108                 ok = kpasswd_make_error_reply(mem_ctx,
109                                               KRB5_KPASSWD_MALFORMED,
110                                               "Failed to decode packet",
111                                               kpasswd_reply);
112                 if (!ok) {
113                         *error_string = "Failed to create reply";
114                         return KRB5_KPASSWD_HARDERROR;
115                 }
116                 return 0;
117         }
118
119         ok = convert_string_talloc_handle(mem_ctx,
120                                           lpcfg_iconv_handle(kdc->task->lp_ctx),
121                                           CH_UTF8,
122                                           CH_UTF16,
123                                           (const char *)chpw.newpasswd.data,
124                                           chpw.newpasswd.length,
125                                           (void **)&password.data,
126                                           &password.length);
127         if (!ok) {
128                 free_ChangePasswdDataMS(&chpw);
129                 DBG_WARNING("String conversion failed\n");
130                 *error_string = "String conversion failed";
131                 return KRB5_KPASSWD_HARDERROR;
132         }
133
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",
141                                               kpasswd_reply);
142                 if (!ok) {
143                         *error_string = "Failed to create reply";
144                         return KRB5_KPASSWD_HARDERROR;
145                 }
146                 return 0;
147         }
148
149         if (chpw.targname != NULL && chpw.targrealm != NULL) {
150                 code = krb5_build_principal_ext(context,
151                                                &target_principal,
152                                                strlen(*chpw.targrealm),
153                                                *chpw.targrealm,
154                                                0);
155                 if (code != 0) {
156                         free_ChangePasswdDataMS(&chpw);
157                         return kpasswd_make_error_reply(mem_ctx,
158                                                         KRB5_KPASSWD_MALFORMED,
159                                                         "Failed to parse principal",
160                                                         kpasswd_reply);
161                 }
162                 code = copy_PrincipalName(chpw.targname,
163                                           &target_principal->name);
164                 if (code != 0) {
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",
170                                                         kpasswd_reply);
171                 }
172         } else {
173                 free_ChangePasswdDataMS(&chpw);
174                 return kpasswd_change_password(kdc,
175                                                mem_ctx,
176                                                session_info,
177                                                &password,
178                                                kpasswd_reply,
179                                                error_string);
180         }
181         free_ChangePasswdDataMS(&chpw);
182
183         if (target_principal->name.name_string.len >= 2) {
184                 is_service_principal = true;
185
186                 code = krb5_unparse_name_short(context,
187                                                target_principal,
188                                                &target_principal_string);
189         } else {
190                 code = krb5_unparse_name(context,
191                                          target_principal,
192                                          &target_principal_string);
193         }
194         krb5_free_principal(context, target_principal);
195         if (code != 0) {
196                 ok = kpasswd_make_error_reply(mem_ctx,
197                                               KRB5_KPASSWD_MALFORMED,
198                                               "Failed to parse principal",
199                                               kpasswd_reply);
200                 if (!ok) {
201                         *error_string = "Failed to create reply";
202                         return KRB5_KPASSWD_HARDERROR;
203                 }
204         }
205
206         status = kpasswd_samdb_set_password(mem_ctx,
207                                             kdc->task->event_ctx,
208                                             kdc->task->lp_ctx,
209                                             session_info,
210                                             is_service_principal,
211                                             target_principal_string,
212                                             &password,
213                                             &reject_reason,
214                                             &dominfo);
215         if (!NT_STATUS_IS_OK(status)) {
216                 DBG_ERR("kpasswd_samdb_set_password failed - %s\n",
217                         nt_errstr(status));
218         }
219
220         ok = kpasswd_make_pwchange_reply(mem_ctx,
221                                          status,
222                                          reject_reason,
223                                          dominfo,
224                                          kpasswd_reply);
225         if (!ok) {
226                 *error_string = "Failed to create reply";
227                 return KRB5_KPASSWD_HARDERROR;
228         }
229
230         return 0;
231 }
232
233 krb5_error_code kpasswd_handle_request(struct kdc_server *kdc,
234                                        TALLOC_CTX *mem_ctx,
235                                        struct gensec_security *gensec_security,
236                                        uint16_t verno,
237                                        DATA_BLOB *decoded_data,
238                                        DATA_BLOB *kpasswd_reply,
239                                        const char **error_string)
240 {
241         struct auth_session_info *session_info;
242         NTSTATUS status;
243
244         status = gensec_session_info(gensec_security,
245                                      mem_ctx,
246                                      &session_info);
247         if (!NT_STATUS_IS_OK(status)) {
248                 *error_string = talloc_asprintf(mem_ctx,
249                                                 "gensec_session_info failed - %s",
250                                                 nt_errstr(status));
251                 return KRB5_KPASSWD_HARDERROR;
252         }
253
254         switch(verno) {
255         case KRB5_KPASSWD_VERS_CHANGEPW: {
256                 DATA_BLOB password = data_blob_null;
257                 bool ok;
258
259                 ok = convert_string_talloc_handle(mem_ctx,
260                                                   lpcfg_iconv_handle(kdc->task->lp_ctx),
261                                                   CH_UTF8,
262                                                   CH_UTF16,
263                                                   (const char *)decoded_data->data,
264                                                   decoded_data->length,
265                                                   (void **)&password.data,
266                                                   &password.length);
267                 if (!ok) {
268                         *error_string = "String conversion failed!";
269                         DBG_WARNING("%s\n", *error_string);
270                         return KRB5_KPASSWD_HARDERROR;
271                 }
272
273                 return kpasswd_change_password(kdc,
274                                                mem_ctx,
275                                                session_info,
276                                                &password,
277                                                kpasswd_reply,
278                                                error_string);
279         }
280         case KRB5_KPASSWD_VERS_SETPW: {
281                 return kpasswd_set_password(kdc,
282                                             mem_ctx,
283                                             session_info,
284                                             decoded_data,
285                                             kpasswd_reply,
286                                             error_string);
287         }
288         default:
289                 *error_string = talloc_asprintf(mem_ctx,
290                                                 "Protocol version %u not supported",
291                                                 verno);
292                 return KRB5_KPASSWD_BAD_VERSION;
293         }
294
295         return 0;
296 }