Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/lib/krb5/changepw.c
34878 views
1
/*
2
* Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
3
* (Royal Institute of Technology, Stockholm, Sweden).
4
* All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
*
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
*
13
* 2. Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in the
15
* documentation and/or other materials provided with the distribution.
16
*
17
* 3. Neither the name of the Institute nor the names of its contributors
18
* may be used to endorse or promote products derived from this software
19
* without specific prior written permission.
20
*
21
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31
* SUCH DAMAGE.
32
*/
33
34
#include "krb5_locl.h"
35
36
#undef __attribute__
37
#define __attribute__(X)
38
39
40
static void
41
str2data (krb5_data *d,
42
const char *fmt,
43
...) __attribute__ ((format (printf, 2, 3)));
44
45
static void
46
str2data (krb5_data *d,
47
const char *fmt,
48
...)
49
{
50
va_list args;
51
char *str;
52
53
va_start(args, fmt);
54
d->length = vasprintf (&str, fmt, args);
55
va_end(args);
56
d->data = str;
57
}
58
59
/*
60
* Change password protocol defined by
61
* draft-ietf-cat-kerb-chg-password-02.txt
62
*
63
* Share the response part of the protocol with MS set password
64
* (RFC3244)
65
*/
66
67
static krb5_error_code
68
chgpw_send_request (krb5_context context,
69
krb5_auth_context *auth_context,
70
krb5_creds *creds,
71
krb5_principal targprinc,
72
int is_stream,
73
rk_socket_t sock,
74
const char *passwd,
75
const char *host)
76
{
77
krb5_error_code ret;
78
krb5_data ap_req_data;
79
krb5_data krb_priv_data;
80
krb5_data passwd_data;
81
size_t len;
82
u_char header[6];
83
struct iovec iov[3];
84
struct msghdr msghdr;
85
86
if (is_stream)
87
return KRB5_KPASSWD_MALFORMED;
88
89
if (targprinc &&
90
krb5_principal_compare(context, creds->client, targprinc) != TRUE)
91
return KRB5_KPASSWD_MALFORMED;
92
93
krb5_data_zero (&ap_req_data);
94
95
ret = krb5_mk_req_extended (context,
96
auth_context,
97
AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
98
NULL, /* in_data */
99
creds,
100
&ap_req_data);
101
if (ret)
102
return ret;
103
104
passwd_data.data = rk_UNCONST(passwd);
105
passwd_data.length = strlen(passwd);
106
107
krb5_data_zero (&krb_priv_data);
108
109
ret = krb5_mk_priv (context,
110
*auth_context,
111
&passwd_data,
112
&krb_priv_data,
113
NULL);
114
if (ret)
115
goto out2;
116
117
len = 6 + ap_req_data.length + krb_priv_data.length;
118
header[0] = (len >> 8) & 0xFF;
119
header[1] = (len >> 0) & 0xFF;
120
header[2] = 0;
121
header[3] = 1;
122
header[4] = (ap_req_data.length >> 8) & 0xFF;
123
header[5] = (ap_req_data.length >> 0) & 0xFF;
124
125
memset(&msghdr, 0, sizeof(msghdr));
126
msghdr.msg_name = NULL;
127
msghdr.msg_namelen = 0;
128
msghdr.msg_iov = iov;
129
msghdr.msg_iovlen = sizeof(iov)/sizeof(*iov);
130
#if 0
131
msghdr.msg_control = NULL;
132
msghdr.msg_controllen = 0;
133
#endif
134
135
iov[0].iov_base = (void*)header;
136
iov[0].iov_len = 6;
137
iov[1].iov_base = ap_req_data.data;
138
iov[1].iov_len = ap_req_data.length;
139
iov[2].iov_base = krb_priv_data.data;
140
iov[2].iov_len = krb_priv_data.length;
141
142
if (rk_IS_SOCKET_ERROR( sendmsg (sock, &msghdr, 0) )) {
143
ret = rk_SOCK_ERRNO;
144
krb5_set_error_message(context, ret, "sendmsg %s: %s",
145
host, strerror(ret));
146
}
147
148
krb5_data_free (&krb_priv_data);
149
out2:
150
krb5_data_free (&ap_req_data);
151
return ret;
152
}
153
154
/*
155
* Set password protocol as defined by RFC3244 --
156
* Microsoft Windows 2000 Kerberos Change Password and Set Password Protocols
157
*/
158
159
static krb5_error_code
160
setpw_send_request (krb5_context context,
161
krb5_auth_context *auth_context,
162
krb5_creds *creds,
163
krb5_principal targprinc,
164
int is_stream,
165
rk_socket_t sock,
166
const char *passwd,
167
const char *host)
168
{
169
krb5_error_code ret;
170
krb5_data ap_req_data;
171
krb5_data krb_priv_data;
172
krb5_data pwd_data;
173
ChangePasswdDataMS chpw;
174
size_t len = 0;
175
u_char header[4 + 6];
176
u_char *p;
177
struct iovec iov[3];
178
struct msghdr msghdr;
179
180
krb5_data_zero (&ap_req_data);
181
182
ret = krb5_mk_req_extended (context,
183
auth_context,
184
AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
185
NULL, /* in_data */
186
creds,
187
&ap_req_data);
188
if (ret)
189
return ret;
190
191
chpw.newpasswd.length = strlen(passwd);
192
chpw.newpasswd.data = rk_UNCONST(passwd);
193
if (targprinc) {
194
chpw.targname = &targprinc->name;
195
chpw.targrealm = &targprinc->realm;
196
} else {
197
chpw.targname = NULL;
198
chpw.targrealm = NULL;
199
}
200
201
ASN1_MALLOC_ENCODE(ChangePasswdDataMS, pwd_data.data, pwd_data.length,
202
&chpw, &len, ret);
203
if (ret) {
204
krb5_data_free (&ap_req_data);
205
return ret;
206
}
207
208
if(pwd_data.length != len)
209
krb5_abortx(context, "internal error in ASN.1 encoder");
210
211
ret = krb5_mk_priv (context,
212
*auth_context,
213
&pwd_data,
214
&krb_priv_data,
215
NULL);
216
if (ret)
217
goto out2;
218
219
len = 6 + ap_req_data.length + krb_priv_data.length;
220
p = header;
221
if (is_stream) {
222
_krb5_put_int(p, len, 4);
223
p += 4;
224
}
225
*p++ = (len >> 8) & 0xFF;
226
*p++ = (len >> 0) & 0xFF;
227
*p++ = 0xff;
228
*p++ = 0x80;
229
*p++ = (ap_req_data.length >> 8) & 0xFF;
230
*p = (ap_req_data.length >> 0) & 0xFF;
231
232
memset(&msghdr, 0, sizeof(msghdr));
233
msghdr.msg_name = NULL;
234
msghdr.msg_namelen = 0;
235
msghdr.msg_iov = iov;
236
msghdr.msg_iovlen = sizeof(iov)/sizeof(*iov);
237
#if 0
238
msghdr.msg_control = NULL;
239
msghdr.msg_controllen = 0;
240
#endif
241
242
iov[0].iov_base = (void*)header;
243
if (is_stream)
244
iov[0].iov_len = 10;
245
else
246
iov[0].iov_len = 6;
247
iov[1].iov_base = ap_req_data.data;
248
iov[1].iov_len = ap_req_data.length;
249
iov[2].iov_base = krb_priv_data.data;
250
iov[2].iov_len = krb_priv_data.length;
251
252
if (rk_IS_SOCKET_ERROR( sendmsg (sock, &msghdr, 0) )) {
253
ret = rk_SOCK_ERRNO;
254
krb5_set_error_message(context, ret, "sendmsg %s: %s",
255
host, strerror(ret));
256
}
257
258
krb5_data_free (&krb_priv_data);
259
out2:
260
krb5_data_free (&ap_req_data);
261
krb5_data_free (&pwd_data);
262
return ret;
263
}
264
265
static krb5_error_code
266
process_reply (krb5_context context,
267
krb5_auth_context auth_context,
268
int is_stream,
269
rk_socket_t sock,
270
int *result_code,
271
krb5_data *result_code_string,
272
krb5_data *result_string,
273
const char *host)
274
{
275
krb5_error_code ret;
276
u_char reply[1024 * 3];
277
size_t len;
278
uint16_t pkt_len, pkt_ver;
279
krb5_data ap_rep_data;
280
int save_errno;
281
282
len = 0;
283
if (is_stream) {
284
while (len < sizeof(reply)) {
285
unsigned long size;
286
287
ret = recvfrom (sock, reply + len, sizeof(reply) - len,
288
0, NULL, NULL);
289
if (rk_IS_SOCKET_ERROR(ret)) {
290
save_errno = rk_SOCK_ERRNO;
291
krb5_set_error_message(context, save_errno,
292
"recvfrom %s: %s",
293
host, strerror(save_errno));
294
return save_errno;
295
} else if (ret == 0) {
296
krb5_set_error_message(context, 1,"recvfrom timeout %s", host);
297
return 1;
298
}
299
len += ret;
300
if (len < 4)
301
continue;
302
_krb5_get_int(reply, &size, 4);
303
if (size + 4 < len)
304
continue;
305
memmove(reply, reply + 4, size);
306
len = size;
307
break;
308
}
309
if (len == sizeof(reply)) {
310
krb5_set_error_message(context, ENOMEM,
311
N_("Message too large from %s", "host"),
312
host);
313
return ENOMEM;
314
}
315
} else {
316
ret = recvfrom (sock, reply, sizeof(reply), 0, NULL, NULL);
317
if (rk_IS_SOCKET_ERROR(ret)) {
318
save_errno = rk_SOCK_ERRNO;
319
krb5_set_error_message(context, save_errno,
320
"recvfrom %s: %s",
321
host, strerror(save_errno));
322
return save_errno;
323
}
324
len = ret;
325
}
326
327
if (len < 6) {
328
str2data (result_string, "server %s sent to too short message "
329
"(%zu bytes)", host, len);
330
*result_code = KRB5_KPASSWD_MALFORMED;
331
return 0;
332
}
333
334
pkt_len = (reply[0] << 8) | (reply[1]);
335
pkt_ver = (reply[2] << 8) | (reply[3]);
336
337
if ((pkt_len != len) || (reply[1] == 0x7e || reply[1] == 0x5e)) {
338
KRB_ERROR error;
339
size_t size;
340
u_char *p;
341
342
memset(&error, 0, sizeof(error));
343
344
ret = decode_KRB_ERROR(reply, len, &error, &size);
345
if (ret)
346
return ret;
347
348
if (error.e_data->length < 2) {
349
str2data(result_string, "server %s sent too short "
350
"e_data to print anything usable", host);
351
free_KRB_ERROR(&error);
352
*result_code = KRB5_KPASSWD_MALFORMED;
353
return 0;
354
}
355
356
p = error.e_data->data;
357
*result_code = (p[0] << 8) | p[1];
358
if (error.e_data->length == 2)
359
str2data(result_string, "server only sent error code");
360
else
361
krb5_data_copy (result_string,
362
p + 2,
363
error.e_data->length - 2);
364
free_KRB_ERROR(&error);
365
return 0;
366
}
367
368
if (pkt_len != len) {
369
str2data (result_string, "client: wrong len in reply");
370
*result_code = KRB5_KPASSWD_MALFORMED;
371
return 0;
372
}
373
if (pkt_ver != KRB5_KPASSWD_VERS_CHANGEPW) {
374
str2data (result_string,
375
"client: wrong version number (%d)", pkt_ver);
376
*result_code = KRB5_KPASSWD_MALFORMED;
377
return 0;
378
}
379
380
ap_rep_data.data = reply + 6;
381
ap_rep_data.length = (reply[4] << 8) | (reply[5]);
382
383
if (reply + len < (u_char *)ap_rep_data.data + ap_rep_data.length) {
384
str2data (result_string, "client: wrong AP len in reply");
385
*result_code = KRB5_KPASSWD_MALFORMED;
386
return 0;
387
}
388
389
if (ap_rep_data.length) {
390
krb5_ap_rep_enc_part *ap_rep;
391
krb5_data priv_data;
392
u_char *p;
393
394
priv_data.data = (u_char*)ap_rep_data.data + ap_rep_data.length;
395
priv_data.length = len - ap_rep_data.length - 6;
396
397
ret = krb5_rd_rep (context,
398
auth_context,
399
&ap_rep_data,
400
&ap_rep);
401
if (ret)
402
return ret;
403
404
krb5_free_ap_rep_enc_part (context, ap_rep);
405
406
ret = krb5_rd_priv (context,
407
auth_context,
408
&priv_data,
409
result_code_string,
410
NULL);
411
if (ret) {
412
krb5_data_free (result_code_string);
413
return ret;
414
}
415
416
if (result_code_string->length < 2) {
417
*result_code = KRB5_KPASSWD_MALFORMED;
418
str2data (result_string,
419
"client: bad length in result");
420
return 0;
421
}
422
423
p = result_code_string->data;
424
425
*result_code = (p[0] << 8) | p[1];
426
krb5_data_copy (result_string,
427
(unsigned char*)result_code_string->data + 2,
428
result_code_string->length - 2);
429
return 0;
430
} else {
431
KRB_ERROR error;
432
size_t size;
433
u_char *p;
434
435
ret = decode_KRB_ERROR(reply + 6, len - 6, &error, &size);
436
if (ret) {
437
return ret;
438
}
439
if (error.e_data->length < 2) {
440
krb5_warnx (context, "too short e_data to print anything usable");
441
return 1; /* XXX */
442
}
443
444
p = error.e_data->data;
445
*result_code = (p[0] << 8) | p[1];
446
krb5_data_copy (result_string,
447
p + 2,
448
error.e_data->length - 2);
449
return 0;
450
}
451
}
452
453
454
/*
455
* change the password using the credentials in `creds' (for the
456
* principal indicated in them) to `newpw', storing the result of
457
* the operation in `result_*' and an error code or 0.
458
*/
459
460
typedef krb5_error_code (*kpwd_send_request) (krb5_context,
461
krb5_auth_context *,
462
krb5_creds *,
463
krb5_principal,
464
int,
465
rk_socket_t,
466
const char *,
467
const char *);
468
typedef krb5_error_code (*kpwd_process_reply) (krb5_context,
469
krb5_auth_context,
470
int,
471
rk_socket_t,
472
int *,
473
krb5_data *,
474
krb5_data *,
475
const char *);
476
477
static struct kpwd_proc {
478
const char *name;
479
int flags;
480
#define SUPPORT_TCP 1
481
#define SUPPORT_UDP 2
482
kpwd_send_request send_req;
483
kpwd_process_reply process_rep;
484
} procs[] = {
485
{
486
"MS set password",
487
SUPPORT_TCP|SUPPORT_UDP,
488
setpw_send_request,
489
process_reply
490
},
491
{
492
"change password",
493
SUPPORT_UDP,
494
chgpw_send_request,
495
process_reply
496
},
497
{ NULL, 0, NULL, NULL }
498
};
499
500
/*
501
*
502
*/
503
504
static krb5_error_code
505
change_password_loop (krb5_context context,
506
krb5_creds *creds,
507
krb5_principal targprinc,
508
const char *newpw,
509
int *result_code,
510
krb5_data *result_code_string,
511
krb5_data *result_string,
512
struct kpwd_proc *proc)
513
{
514
krb5_error_code ret;
515
krb5_auth_context auth_context = NULL;
516
krb5_krbhst_handle handle = NULL;
517
krb5_krbhst_info *hi;
518
rk_socket_t sock;
519
unsigned int i;
520
int done = 0;
521
krb5_realm realm;
522
523
if (targprinc)
524
realm = targprinc->realm;
525
else
526
realm = creds->client->realm;
527
528
ret = krb5_auth_con_init (context, &auth_context);
529
if (ret)
530
return ret;
531
532
krb5_auth_con_setflags (context, auth_context,
533
KRB5_AUTH_CONTEXT_DO_SEQUENCE);
534
535
ret = krb5_krbhst_init (context, realm, KRB5_KRBHST_CHANGEPW, &handle);
536
if (ret)
537
goto out;
538
539
while (!done && (ret = krb5_krbhst_next(context, handle, &hi)) == 0) {
540
struct addrinfo *ai, *a;
541
int is_stream;
542
543
switch (hi->proto) {
544
case KRB5_KRBHST_UDP:
545
if ((proc->flags & SUPPORT_UDP) == 0)
546
continue;
547
is_stream = 0;
548
break;
549
case KRB5_KRBHST_TCP:
550
if ((proc->flags & SUPPORT_TCP) == 0)
551
continue;
552
is_stream = 1;
553
break;
554
default:
555
continue;
556
}
557
558
ret = krb5_krbhst_get_addrinfo(context, hi, &ai);
559
if (ret)
560
continue;
561
562
for (a = ai; !done && a != NULL; a = a->ai_next) {
563
int replied = 0;
564
565
sock = socket (a->ai_family, a->ai_socktype | SOCK_CLOEXEC, a->ai_protocol);
566
if (rk_IS_BAD_SOCKET(sock))
567
continue;
568
rk_cloexec(sock);
569
570
ret = connect(sock, a->ai_addr, a->ai_addrlen);
571
if (rk_IS_SOCKET_ERROR(ret)) {
572
rk_closesocket (sock);
573
goto out;
574
}
575
576
ret = krb5_auth_con_genaddrs (context, auth_context, sock,
577
KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR);
578
if (ret) {
579
rk_closesocket (sock);
580
goto out;
581
}
582
583
for (i = 0; !done && i < 5; ++i) {
584
fd_set fdset;
585
struct timeval tv;
586
587
if (!replied) {
588
replied = 0;
589
590
ret = (*proc->send_req) (context,
591
&auth_context,
592
creds,
593
targprinc,
594
is_stream,
595
sock,
596
newpw,
597
hi->hostname);
598
if (ret) {
599
rk_closesocket(sock);
600
goto out;
601
}
602
}
603
604
#ifndef NO_LIMIT_FD_SETSIZE
605
if (sock >= FD_SETSIZE) {
606
ret = ERANGE;
607
krb5_set_error_message(context, ret,
608
"fd %d too large", sock);
609
rk_closesocket (sock);
610
goto out;
611
}
612
#endif
613
614
FD_ZERO(&fdset);
615
FD_SET(sock, &fdset);
616
tv.tv_usec = 0;
617
tv.tv_sec = 1 + (1 << i);
618
619
ret = select (sock + 1, &fdset, NULL, NULL, &tv);
620
if (rk_IS_SOCKET_ERROR(ret) && rk_SOCK_ERRNO != EINTR) {
621
rk_closesocket(sock);
622
goto out;
623
}
624
if (ret == 1) {
625
ret = (*proc->process_rep) (context,
626
auth_context,
627
is_stream,
628
sock,
629
result_code,
630
result_code_string,
631
result_string,
632
hi->hostname);
633
if (ret == 0)
634
done = 1;
635
else if (i > 0 && ret == KRB5KRB_AP_ERR_MUT_FAIL)
636
replied = 1;
637
} else {
638
ret = KRB5_KDC_UNREACH;
639
}
640
}
641
rk_closesocket (sock);
642
}
643
}
644
645
out:
646
krb5_krbhst_free (context, handle);
647
krb5_auth_con_free (context, auth_context);
648
649
if (ret == KRB5_KDC_UNREACH) {
650
krb5_set_error_message(context,
651
ret,
652
N_("Unable to reach any changepw server "
653
" in realm %s", "realm"), realm);
654
*result_code = KRB5_KPASSWD_HARDERROR;
655
}
656
return ret;
657
}
658
659
#ifndef HEIMDAL_SMALLER
660
661
static struct kpwd_proc *
662
find_chpw_proto(const char *name)
663
{
664
struct kpwd_proc *p;
665
for (p = procs; p->name != NULL; p++) {
666
if (strcmp(p->name, name) == 0)
667
return p;
668
}
669
return NULL;
670
}
671
672
/**
673
* Deprecated: krb5_change_password() is deprecated, use krb5_set_password().
674
*
675
* @param context a Keberos context
676
* @param creds
677
* @param newpw
678
* @param result_code
679
* @param result_code_string
680
* @param result_string
681
*
682
* @return On sucess password is changed.
683
684
* @ingroup @krb5_deprecated
685
*/
686
687
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
688
krb5_change_password (krb5_context context,
689
krb5_creds *creds,
690
const char *newpw,
691
int *result_code,
692
krb5_data *result_code_string,
693
krb5_data *result_string)
694
KRB5_DEPRECATED_FUNCTION("Use X instead")
695
{
696
struct kpwd_proc *p = find_chpw_proto("change password");
697
698
*result_code = KRB5_KPASSWD_MALFORMED;
699
result_code_string->data = result_string->data = NULL;
700
result_code_string->length = result_string->length = 0;
701
702
if (p == NULL)
703
return KRB5_KPASSWD_MALFORMED;
704
705
return change_password_loop(context, creds, NULL, newpw,
706
result_code, result_code_string,
707
result_string, p);
708
}
709
#endif /* HEIMDAL_SMALLER */
710
711
/**
712
* Change password using creds.
713
*
714
* @param context a Keberos context
715
* @param creds The initial kadmin/passwd for the principal or an admin principal
716
* @param newpw The new password to set
717
* @param targprinc if unset, the default principal is used.
718
* @param result_code Result code, KRB5_KPASSWD_SUCCESS is when password is changed.
719
* @param result_code_string binary message from the server, contains
720
* at least the result_code.
721
* @param result_string A message from the kpasswd service or the
722
* library in human printable form. The string is NUL terminated.
723
*
724
* @return On sucess and *result_code is KRB5_KPASSWD_SUCCESS, the password is changed.
725
726
* @ingroup @krb5
727
*/
728
729
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
730
krb5_set_password(krb5_context context,
731
krb5_creds *creds,
732
const char *newpw,
733
krb5_principal targprinc,
734
int *result_code,
735
krb5_data *result_code_string,
736
krb5_data *result_string)
737
{
738
krb5_principal principal = NULL;
739
krb5_error_code ret = 0;
740
int i;
741
742
*result_code = KRB5_KPASSWD_MALFORMED;
743
krb5_data_zero(result_code_string);
744
krb5_data_zero(result_string);
745
746
if (targprinc == NULL) {
747
ret = krb5_get_default_principal(context, &principal);
748
if (ret)
749
return ret;
750
} else
751
principal = targprinc;
752
753
for (i = 0; procs[i].name != NULL; i++) {
754
*result_code = 0;
755
ret = change_password_loop(context, creds, principal, newpw,
756
result_code, result_code_string,
757
result_string,
758
&procs[i]);
759
if (ret == 0 && *result_code == 0)
760
break;
761
}
762
763
if (targprinc == NULL)
764
krb5_free_principal(context, principal);
765
return ret;
766
}
767
768
/*
769
*
770
*/
771
772
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
773
krb5_set_password_using_ccache(krb5_context context,
774
krb5_ccache ccache,
775
const char *newpw,
776
krb5_principal targprinc,
777
int *result_code,
778
krb5_data *result_code_string,
779
krb5_data *result_string)
780
{
781
krb5_creds creds, *credsp;
782
krb5_error_code ret;
783
krb5_principal principal = NULL;
784
785
*result_code = KRB5_KPASSWD_MALFORMED;
786
result_code_string->data = result_string->data = NULL;
787
result_code_string->length = result_string->length = 0;
788
789
memset(&creds, 0, sizeof(creds));
790
791
if (targprinc == NULL) {
792
ret = krb5_cc_get_principal(context, ccache, &principal);
793
if (ret)
794
return ret;
795
} else
796
principal = targprinc;
797
798
ret = krb5_make_principal(context, &creds.server,
799
krb5_principal_get_realm(context, principal),
800
"kadmin", "changepw", NULL);
801
if (ret)
802
goto out;
803
804
ret = krb5_cc_get_principal(context, ccache, &creds.client);
805
if (ret) {
806
krb5_free_principal(context, creds.server);
807
goto out;
808
}
809
810
ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp);
811
krb5_free_principal(context, creds.server);
812
krb5_free_principal(context, creds.client);
813
if (ret)
814
goto out;
815
816
ret = krb5_set_password(context,
817
credsp,
818
newpw,
819
principal,
820
result_code,
821
result_code_string,
822
result_string);
823
824
krb5_free_creds(context, credsp);
825
826
return ret;
827
out:
828
if (targprinc == NULL)
829
krb5_free_principal(context, principal);
830
return ret;
831
}
832
833
/*
834
*
835
*/
836
837
KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
838
krb5_passwd_result_to_string (krb5_context context,
839
int result)
840
{
841
static const char *strings[] = {
842
"Success",
843
"Malformed",
844
"Hard error",
845
"Auth error",
846
"Soft error" ,
847
"Access denied",
848
"Bad version",
849
"Initial flag needed"
850
};
851
852
if (result < 0 || result > KRB5_KPASSWD_INITIAL_FLAG_NEEDED)
853
return "unknown result code";
854
else
855
return strings[result];
856
}
857
858