remove gcc34
[dragonfly.git] / crypto / heimdal-0.6.3 / lib / krb5 / changepw.c
1 /*
2  * Copyright (c) 1997 - 2003 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 RCSID("$Id: changepw.c,v 1.38.2.1 2004/06/21 08:38:10 lha Exp $");
37
38 static void
39 str2data (krb5_data *d,
40           const char *fmt,
41           ...) __attribute__ ((format (printf, 2, 3)));
42
43 static void
44 str2data (krb5_data *d,
45           const char *fmt,
46           ...)
47 {
48     va_list args;
49
50     va_start(args, fmt);
51     d->length = vasprintf ((char **)&d->data, fmt, args);
52     va_end(args);
53 }
54
55 /*
56  * Change password protocol defined by
57  * draft-ietf-cat-kerb-chg-password-02.txt
58  * 
59  * Share the response part of the protocol with MS set password
60  * (RFC3244)
61  */
62
63 static krb5_error_code
64 chgpw_send_request (krb5_context context,
65                     krb5_auth_context *auth_context,
66                     krb5_creds *creds,
67                     krb5_principal targprinc,
68                     int is_stream,
69                     int sock,
70                     char *passwd,
71                     const char *host)
72 {
73     krb5_error_code ret;
74     krb5_data ap_req_data;
75     krb5_data krb_priv_data;
76     krb5_data passwd_data;
77     size_t len;
78     u_char header[6];
79     u_char *p;
80     struct iovec iov[3];
81     struct msghdr msghdr;
82
83     if (is_stream)
84         return KRB5_KPASSWD_MALFORMED;
85
86     if (targprinc &&
87         krb5_principal_compare(context, creds->client, targprinc) != TRUE)
88         return KRB5_KPASSWD_MALFORMED;
89
90     krb5_data_zero (&ap_req_data);
91
92     ret = krb5_mk_req_extended (context,
93                                 auth_context,
94                                 AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
95                                 NULL, /* in_data */
96                                 creds,
97                                 &ap_req_data);
98     if (ret)
99         return ret;
100
101     passwd_data.data   = passwd;
102     passwd_data.length = strlen(passwd);
103
104     krb5_data_zero (&krb_priv_data);
105
106     ret = krb5_mk_priv (context,
107                         *auth_context,
108                         &passwd_data,
109                         &krb_priv_data,
110                         NULL);
111     if (ret)
112         goto out2;
113
114     len = 6 + ap_req_data.length + krb_priv_data.length;
115     p = header;
116     *p++ = (len >> 8) & 0xFF;
117     *p++ = (len >> 0) & 0xFF;
118     *p++ = 0;
119     *p++ = 1;
120     *p++ = (ap_req_data.length >> 8) & 0xFF;
121     *p++ = (ap_req_data.length >> 0) & 0xFF;
122
123     memset(&msghdr, 0, sizeof(msghdr));
124     msghdr.msg_name       = NULL;
125     msghdr.msg_namelen    = 0;
126     msghdr.msg_iov        = iov;
127     msghdr.msg_iovlen     = sizeof(iov)/sizeof(*iov);
128 #if 0
129     msghdr.msg_control    = NULL;
130     msghdr.msg_controllen = 0;
131 #endif
132
133     iov[0].iov_base    = (void*)header;
134     iov[0].iov_len     = 6;
135     iov[1].iov_base    = ap_req_data.data;
136     iov[1].iov_len     = ap_req_data.length;
137     iov[2].iov_base    = krb_priv_data.data;
138     iov[2].iov_len     = krb_priv_data.length;
139
140     if (sendmsg (sock, &msghdr, 0) < 0) {
141         ret = errno;
142         krb5_set_error_string(context, "sendmsg %s: %s", host, strerror(ret));
143     }
144
145     krb5_data_free (&krb_priv_data);
146 out2:
147     krb5_data_free (&ap_req_data);
148     return ret;
149 }
150
151 /*
152  * Set password protocol as defined by RFC3244 --
153  * Microsoft Windows 2000 Kerberos Change Password and Set Password Protocols
154  */
155
156 static krb5_error_code
157 setpw_send_request (krb5_context context,
158                     krb5_auth_context *auth_context,
159                     krb5_creds *creds,
160                     krb5_principal targprinc,
161                     int is_stream,
162                     int sock,
163                     char *passwd,
164                     const char *host)
165 {
166     krb5_error_code ret;
167     krb5_data ap_req_data;
168     krb5_data krb_priv_data;
169     krb5_data pwd_data;
170     ChangePasswdDataMS chpw;
171     size_t len;
172     u_char header[4 + 6];
173     u_char *p;
174     struct iovec iov[3];
175     struct msghdr msghdr;
176
177     krb5_data_zero (&ap_req_data);
178
179     ret = krb5_mk_req_extended (context,
180                                 auth_context,
181                                 AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY,
182                                 NULL, /* in_data */
183                                 creds,
184                                 &ap_req_data);
185     if (ret)
186         return ret;
187
188     chpw.newpasswd.length = strlen(passwd);
189     chpw.newpasswd.data = passwd;
190     if (targprinc) {
191         chpw.targname = &targprinc->name;
192         chpw.targrealm = &targprinc->realm;
193     } else {
194         chpw.targname = NULL;
195         chpw.targrealm = NULL;
196     }
197         
198     ASN1_MALLOC_ENCODE(ChangePasswdDataMS, pwd_data.data, pwd_data.length,
199                        &chpw, &len, ret);
200     if (ret) {
201         krb5_data_free (&ap_req_data);
202         return ret;
203     }
204
205     if(pwd_data.length != len)
206         krb5_abortx(context, "internal error in ASN.1 encoder");
207
208     ret = krb5_mk_priv (context,
209                         *auth_context,
210                         &pwd_data,
211                         &krb_priv_data,
212                         NULL);
213     if (ret)
214         goto out2;
215
216     len = 6 + ap_req_data.length + krb_priv_data.length;
217     p = header;
218     if (is_stream) {
219         _krb5_put_int(p, len, 4);
220         p += 4;
221     }
222     *p++ = (len >> 8) & 0xFF;
223     *p++ = (len >> 0) & 0xFF;
224     *p++ = 0xff;
225     *p++ = 0x80;
226     *p++ = (ap_req_data.length >> 8) & 0xFF;
227     *p++ = (ap_req_data.length >> 0) & 0xFF;
228
229     memset(&msghdr, 0, sizeof(msghdr));
230     msghdr.msg_name       = NULL;
231     msghdr.msg_namelen    = 0;
232     msghdr.msg_iov        = iov;
233     msghdr.msg_iovlen     = sizeof(iov)/sizeof(*iov);
234 #if 0
235     msghdr.msg_control    = NULL;
236     msghdr.msg_controllen = 0;
237 #endif
238
239     iov[0].iov_base    = (void*)header;
240     if (is_stream)
241         iov[0].iov_len     = 10;
242     else
243         iov[0].iov_len     = 6;
244     iov[1].iov_base    = ap_req_data.data;
245     iov[1].iov_len     = ap_req_data.length;
246     iov[2].iov_base    = krb_priv_data.data;
247     iov[2].iov_len     = krb_priv_data.length;
248
249     if (sendmsg (sock, &msghdr, 0) < 0) {
250         ret = errno;
251         krb5_set_error_string(context, "sendmsg %s: %s", host, strerror(ret));
252     }
253
254     krb5_data_free (&krb_priv_data);
255 out2:
256     krb5_data_free (&ap_req_data);
257     krb5_data_free (&pwd_data);
258     return ret;
259 }
260
261 static krb5_error_code
262 process_reply (krb5_context context,
263                krb5_auth_context auth_context,
264                int is_stream,
265                int sock,
266                int *result_code,
267                krb5_data *result_code_string,
268                krb5_data *result_string,
269                const char *host)
270 {
271     krb5_error_code ret;
272     u_char reply[1024 * 3];
273     ssize_t len;
274     u_int16_t pkt_len, pkt_ver;
275     krb5_data ap_rep_data;
276     int save_errno;
277
278     len = 0;
279     if (is_stream) {
280         while (len < sizeof(reply)) {
281             unsigned long size;
282
283             ret = recvfrom (sock, reply + len, sizeof(reply) - len, 
284                             0, NULL, NULL);
285             if (ret < 0) {
286                 save_errno = errno;
287                 krb5_set_error_string(context, "recvfrom %s: %s",
288                                       host, strerror(save_errno));
289                 return save_errno;
290             } else if (ret == 0) {
291                 krb5_set_error_string(context, "recvfrom timeout %s", host);
292                 return 1;
293             }
294             len += ret;
295             if (len < 4)
296                 continue;
297             _krb5_get_int(reply, &size, 4);
298             if (size + 4 < len)
299                 continue;
300             memmove(reply, reply + 4, size);            
301             len = size;
302             break;
303         }
304         if (len == sizeof(reply)) {
305             krb5_set_error_string(context, "message too large from %s",
306                                   host);
307             return ENOMEM;
308         }
309     } else {
310         ret = recvfrom (sock, reply, sizeof(reply), 0, NULL, NULL);
311         if (ret < 0) {
312             save_errno = errno;
313             krb5_set_error_string(context, "recvfrom %s: %s",
314                                   host, strerror(save_errno));
315             return save_errno;
316         }
317         len = ret;
318     }
319
320     if (len < 6) {
321         str2data (result_string, "server %s sent to too short message "
322                   "(%d bytes)", host, len);
323         *result_code = KRB5_KPASSWD_MALFORMED;
324         return 0;
325     }
326
327     pkt_len = (reply[0] << 8) | (reply[1]);
328     pkt_ver = (reply[2] << 8) | (reply[3]);
329
330     if ((pkt_len != len) || (reply[1] == 0x7e || reply[1] == 0x5e)) {
331         KRB_ERROR error;
332         size_t size;
333         u_char *p;
334
335         memset(&error, 0, sizeof(error));
336
337         ret = decode_KRB_ERROR(reply, len, &error, &size);
338         if (ret)
339             return ret;
340
341         if (error.e_data->length < 2) {
342             str2data(result_string, "server %s sent too short "
343                      "e_data to print anything usable", host);
344             free_KRB_ERROR(&error);
345             *result_code = KRB5_KPASSWD_MALFORMED;
346             return 0;
347         }
348
349         p = error.e_data->data;
350         *result_code = (p[0] << 8) | p[1];
351         if (error.e_data->length == 2)
352             str2data(result_string, "server only sent error code");
353         else 
354             krb5_data_copy (result_string,
355                             p + 2,
356                             error.e_data->length - 2);
357         free_KRB_ERROR(&error);
358         return 0;
359     }
360
361     if (pkt_len != len) {
362         str2data (result_string, "client: wrong len in reply");
363         *result_code = KRB5_KPASSWD_MALFORMED;
364         return 0;
365     }
366     if (pkt_ver != KRB5_KPASSWD_VERS_CHANGEPW) {
367         str2data (result_string,
368                   "client: wrong version number (%d)", pkt_ver);
369         *result_code = KRB5_KPASSWD_MALFORMED;
370         return 0;
371     }
372
373     ap_rep_data.data = reply + 6;
374     ap_rep_data.length  = (reply[4] << 8) | (reply[5]);
375   
376     if (reply + len < (u_char *)ap_rep_data.data + ap_rep_data.length) {
377         str2data (result_string, "client: wrong AP len in reply");
378         *result_code = KRB5_KPASSWD_MALFORMED;
379         return 0;
380     }
381
382     if (ap_rep_data.length) {
383         krb5_ap_rep_enc_part *ap_rep;
384         krb5_data priv_data;
385         u_char *p;
386
387         priv_data.data   = (u_char*)ap_rep_data.data + ap_rep_data.length;
388         priv_data.length = len - ap_rep_data.length - 6;
389
390         ret = krb5_rd_rep (context,
391                            auth_context,
392                            &ap_rep_data,
393                            &ap_rep);
394         if (ret)
395             return ret;
396
397         krb5_free_ap_rep_enc_part (context, ap_rep);
398
399         ret = krb5_rd_priv (context,
400                             auth_context,
401                             &priv_data,
402                             result_code_string,
403                             NULL);
404         if (ret) {
405             krb5_data_free (result_code_string);
406             return ret;
407         }
408
409         if (result_code_string->length < 2) {
410             *result_code = KRB5_KPASSWD_MALFORMED;
411             str2data (result_string,
412                       "client: bad length in result");
413             return 0;
414         }
415
416         p = result_code_string->data;
417       
418         *result_code = (p[0] << 8) | p[1];
419         krb5_data_copy (result_string,
420                         (unsigned char*)result_code_string->data + 2,
421                         result_code_string->length - 2);
422         return 0;
423     } else {
424         KRB_ERROR error;
425         size_t size;
426         u_char *p;
427       
428         ret = decode_KRB_ERROR(reply + 6, len - 6, &error, &size);
429         if (ret) {
430             return ret;
431         }
432         if (error.e_data->length < 2) {
433             krb5_warnx (context, "too short e_data to print anything usable");
434             return 1;           /* XXX */
435         }
436
437         p = error.e_data->data;
438         *result_code = (p[0] << 8) | p[1];
439         krb5_data_copy (result_string,
440                         p + 2,
441                         error.e_data->length - 2);
442         return 0;
443     }
444 }
445
446
447 /*
448  * change the password using the credentials in `creds' (for the
449  * principal indicated in them) to `newpw', storing the result of
450  * the operation in `result_*' and an error code or 0.
451  */
452
453 typedef krb5_error_code (*kpwd_send_request) (krb5_context,
454                                               krb5_auth_context *,
455                                               krb5_creds *,
456                                               krb5_principal,
457                                               int,
458                                               int,
459                                               char *,
460                                               const char *);
461 typedef krb5_error_code (*kpwd_process_reply) (krb5_context,
462                                                krb5_auth_context,
463                                                int,
464                                                int,
465                                                int *,
466                                                krb5_data *,
467                                                krb5_data *,
468                                                const char *);
469
470 struct kpwd_proc {
471     const char *name;
472     int flags;
473 #define SUPPORT_TCP     1
474 #define SUPPORT_UDP     2
475     kpwd_send_request send_req;
476     kpwd_process_reply process_rep;
477 } procs[] = {
478     {
479         "MS set password", 
480         SUPPORT_TCP|SUPPORT_UDP,
481         setpw_send_request, 
482         process_reply
483     },
484     {
485         "change password",
486         SUPPORT_UDP,
487         chgpw_send_request,
488         process_reply
489     },
490     { NULL }
491 };
492
493 static struct kpwd_proc *
494 find_chpw_proto(const char *name)
495 {
496     struct kpwd_proc *p;
497     for (p = procs; p->name != NULL; p++) {
498         if (strcmp(p->name, name) == 0)
499             return p;
500     }
501     return NULL;
502 }
503
504 /*
505  *
506  */
507
508 static krb5_error_code
509 change_password_loop (krb5_context      context,
510                       krb5_creds        *creds,
511                       krb5_principal    targprinc,
512                       char              *newpw,
513                       int               *result_code,
514                       krb5_data         *result_code_string,
515                       krb5_data         *result_string,
516                       struct kpwd_proc  *proc)
517 {
518     krb5_error_code ret;
519     krb5_auth_context auth_context = NULL;
520     krb5_krbhst_handle handle = NULL;
521     krb5_krbhst_info *hi;
522     int sock;
523     int i;
524     int done = 0;
525     krb5_realm realm = creds->client->realm;
526
527     ret = krb5_auth_con_init (context, &auth_context);
528     if (ret)
529         return ret;
530
531     krb5_auth_con_setflags (context, auth_context,
532                             KRB5_AUTH_CONTEXT_DO_SEQUENCE);
533
534     ret = krb5_krbhst_init (context, realm, KRB5_KRBHST_CHANGEPW, &handle);
535     if (ret)
536         goto out;
537
538     while (!done && (ret = krb5_krbhst_next(context, handle, &hi)) == 0) {
539         struct addrinfo *ai, *a;
540         int is_stream;
541
542         switch (hi->proto) {
543         case KRB5_KRBHST_UDP:
544             if ((proc->flags & SUPPORT_UDP) == 0)
545                 continue;
546             is_stream = 0;
547             break;
548         case KRB5_KRBHST_TCP:
549             if ((proc->flags & SUPPORT_TCP) == 0)
550                 continue;
551             is_stream = 1;
552             break;
553         default:
554             continue;
555         }
556
557         ret = krb5_krbhst_get_addrinfo(context, hi, &ai);
558         if (ret)
559             continue;
560
561         for (a = ai; !done && a != NULL; a = a->ai_next) {
562             int replied = 0;
563
564             sock = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
565             if (sock < 0)
566                 continue;
567
568             ret = connect(sock, a->ai_addr, a->ai_addrlen);
569             if (ret < 0) {
570                 close (sock);
571                 goto out;
572             }
573
574             ret = krb5_auth_con_genaddrs (context, auth_context, sock,
575                                           KRB5_AUTH_CONTEXT_GENERATE_LOCAL_ADDR);
576             if (ret) {
577                 close (sock);
578                 goto out;
579             }
580
581             for (i = 0; !done && i < 5; ++i) {
582                 fd_set fdset;
583                 struct timeval tv;
584
585                 if (!replied) {
586                     replied = 0;
587                     
588                     ret = (*proc->send_req) (context,
589                                              &auth_context,
590                                              creds,
591                                              targprinc,
592                                              is_stream,
593                                              sock,
594                                              newpw,
595                                              hi->hostname);
596                     if (ret) {
597                         close(sock);
598                         goto out;
599                     }
600                 }
601             
602                 if (sock >= FD_SETSIZE) {
603                     krb5_set_error_string(context, "fd %d too large", sock);
604                     ret = ERANGE;
605                     close (sock);
606                     goto out;
607                 }
608
609                 FD_ZERO(&fdset);
610                 FD_SET(sock, &fdset);
611                 tv.tv_usec = 0;
612                 tv.tv_sec  = 1 + (1 << i);
613
614                 ret = select (sock + 1, &fdset, NULL, NULL, &tv);
615                 if (ret < 0 && errno != EINTR) {
616                     close(sock);
617                     goto out;
618                 }
619                 if (ret == 1) {
620                     ret = (*proc->process_rep) (context,
621                                                 auth_context,
622                                                 is_stream,
623                                                 sock,
624                                                 result_code,
625                                                 result_code_string,
626                                                 result_string,
627                                                 hi->hostname);
628                     if (ret == 0)
629                         done = 1;
630                     else if (i > 0 && ret == KRB5KRB_AP_ERR_MUT_FAIL)
631                         replied = 1;
632                 } else {
633                     ret = KRB5_KDC_UNREACH;
634                 }
635             }
636             close (sock);
637         }
638     }
639
640  out:
641     krb5_krbhst_free (context, handle);
642     krb5_auth_con_free (context, auth_context);
643     if (done)
644         return 0;
645     else {
646         if (ret == KRB5_KDC_UNREACH)
647             krb5_set_error_string(context,
648                                   "unable to reach any changepw server "
649                                   " in realm %s", realm);
650         return ret;
651     }
652 }
653
654
655 /*
656  * change the password using the credentials in `creds' (for the
657  * principal indicated in them) to `newpw', storing the result of
658  * the operation in `result_*' and an error code or 0.
659  */
660
661 krb5_error_code
662 krb5_change_password (krb5_context      context,
663                       krb5_creds        *creds,
664                       char              *newpw,
665                       int               *result_code,
666                       krb5_data         *result_code_string,
667                       krb5_data         *result_string)
668 {
669     struct kpwd_proc *p = find_chpw_proto("change password");
670
671     *result_code = KRB5_KPASSWD_MALFORMED;
672     result_code_string->data = result_string->data = NULL;
673     result_code_string->length = result_string->length = 0;
674
675     if (p == NULL)
676         return KRB5_KPASSWD_MALFORMED;
677
678     return change_password_loop(context, creds, NULL, newpw, 
679                                 result_code, result_code_string, 
680                                 result_string, p);
681 }
682
683 /*
684  *
685  */
686
687 krb5_error_code
688 krb5_set_password(krb5_context context,
689                   krb5_creds *creds,
690                   char *newpw,
691                   krb5_principal targprinc,
692                   int *result_code,
693                   krb5_data *result_code_string,
694                   krb5_data *result_string)
695 {
696     krb5_principal principal = NULL;
697     krb5_error_code ret = 0;
698     int i;
699
700     *result_code = KRB5_KPASSWD_MALFORMED;
701     result_code_string->data = result_string->data = NULL;
702     result_code_string->length = result_string->length = 0;
703
704     if (targprinc == NULL) {
705         ret = krb5_get_default_principal(context, &principal);
706         if (ret)
707             return ret;
708     } else
709         principal = targprinc;
710
711     for (i = 0; procs[i].name != NULL; i++) {
712         *result_code = 0;
713         ret = change_password_loop(context, creds, targprinc, newpw, 
714                                    result_code, result_code_string, 
715                                    result_string, 
716                                    &procs[i]);
717         if (ret == 0 && *result_code == 0)
718             break;
719     }
720
721     if (targprinc == NULL)
722         krb5_free_principal(context, principal);
723     return ret;
724 }
725
726 /*
727  *
728  */
729
730 krb5_error_code
731 krb5_set_password_using_ccache(krb5_context context,
732                                krb5_ccache ccache,
733                                char *newpw,
734                                krb5_principal targprinc,
735                                int *result_code,
736                                krb5_data *result_code_string,
737                                krb5_data *result_string)
738 {
739     krb5_creds creds, *credsp;
740     krb5_error_code ret;
741     krb5_principal principal = NULL;
742
743     *result_code = KRB5_KPASSWD_MALFORMED;
744     result_code_string->data = result_string->data = NULL;
745     result_code_string->length = result_string->length = 0;
746
747     memset(&creds, 0, sizeof(creds));
748
749     if (targprinc == NULL) {
750         ret = krb5_cc_get_principal(context, ccache, &principal);
751         if (ret)
752             return ret;
753     } else
754         principal = targprinc;
755
756     ret = krb5_make_principal(context, &creds.server, 
757                               krb5_principal_get_realm(context, principal),
758                               "kadmin", "changepw", NULL);
759     if (ret)
760         goto out;
761
762     ret = krb5_cc_get_principal(context, ccache, &creds.client);
763     if (ret) {
764         krb5_free_principal(context, creds.server);
765         goto out;
766     }
767
768     ret = krb5_get_credentials(context, 0, ccache, &creds, &credsp);
769     krb5_free_principal(context, creds.server);
770     krb5_free_principal(context, creds.client);
771     if (ret)
772         goto out;
773
774     ret = krb5_set_password(context,
775                             credsp,
776                             newpw,
777                             principal,
778                             result_code,
779                             result_code_string,
780                             result_string);
781
782     krb5_free_creds(context, credsp); 
783
784     return ret;
785  out:
786     if (targprinc == NULL)
787         krb5_free_principal(context, principal);
788     return ret;
789 }
790
791 /*
792  *
793  */
794
795 const char*
796 krb5_passwd_result_to_string (krb5_context context,
797                               int result)
798 {
799     static const char *strings[] = {
800         "Success",
801         "Malformed",
802         "Hard error",
803         "Auth error",
804         "Soft error" ,
805         "Access denied",
806         "Bad version",
807         "Initial flag needed"
808     };
809
810     if (result < 0 || result > KRB5_KPASSWD_INITIAL_FLAG_NEEDED)
811         return "unknown result code";
812     else
813         return strings[result];
814 }