Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / servers / exchange / lib / e2k-kerberos.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /* Copyright (C) 2004 Novell, Inc.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of version 2 of the GNU Lesser General Public
7  * License as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <ctype.h>
25 #include <glib.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "e2k-kerberos.h"
31 #include <krb5.h>
32
33 static krb5_context
34 e2k_kerberos_context_new (const char *domain)
35 {
36         krb5_context ctx;
37         char *realm;
38
39         if (krb5_init_context (&ctx) != 0)
40                 return NULL;
41
42         realm = g_ascii_strup (domain, strlen (domain));
43         krb5_set_default_realm (ctx, realm);
44         g_free (realm);
45
46         return ctx;
47 }
48
49 static E2kKerberosResult
50 krb5_result_to_e2k_kerberos_result (int result)
51 {
52         switch (result) {
53         case 0:
54                 return E2K_KERBEROS_OK;
55
56         case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
57                 return E2K_KERBEROS_USER_UNKNOWN;
58
59         case KRB5KRB_AP_ERR_BAD_INTEGRITY:
60         case KRB5KDC_ERR_PREAUTH_FAILED:
61                 return E2K_KERBEROS_PASSWORD_INCORRECT;
62
63         case KRB5KDC_ERR_KEY_EXP:
64                 return E2K_KERBEROS_PASSWORD_EXPIRED;
65
66         case KRB5_KDC_UNREACH:
67                 return E2K_KERBEROS_KDC_UNREACHABLE;
68
69         case KRB5KRB_AP_ERR_SKEW:
70                 return E2K_KERBEROS_TIME_SKEW;
71
72         default:
73                 g_warning ("Unexpected kerberos error %d", result);
74                 return E2K_KERBEROS_FAILED;
75         }
76 }
77
78 static E2kKerberosResult
79 get_init_cred (krb5_context ctx, const char *usr_name, const char *passwd,
80                const char *in_tkt_service, krb5_creds *cred)
81 {
82         krb5_principal principal;
83         krb5_get_init_creds_opt opt;
84         krb5_error_code result;
85
86         result = krb5_parse_name (ctx, usr_name, &principal);
87         if (result)
88                 return E2K_KERBEROS_USER_UNKNOWN;
89
90         krb5_get_init_creds_opt_init (&opt);
91         krb5_get_init_creds_opt_set_tkt_life (&opt, 5*60);
92         krb5_get_init_creds_opt_set_renew_life (&opt, 0);
93         krb5_get_init_creds_opt_set_forwardable (&opt, 0);
94         krb5_get_init_creds_opt_set_proxiable (&opt, 0);
95
96         result = krb5_get_init_creds_password (ctx, cred, principal, passwd,
97                                                NULL, NULL, 0,
98                                                in_tkt_service, &opt);
99         krb5_free_principal (ctx, principal);
100
101         return krb5_result_to_e2k_kerberos_result (result);
102 }
103
104 /**
105  * e2k_kerberos_change_password
106  * @user: username
107  * @domain: Windows (2000) domain name
108  * @old_password: currrent password
109  * @new_password: password to be changed to
110  *
111  * Changes the password for the given user
112  *
113  * Return value: an #E2kKerberosResult
114  **/
115 E2kKerberosResult
116 e2k_kerberos_change_password (const char *user, const char *domain,
117                               const char *old_password, const char *new_password)
118 {
119         krb5_context ctx;
120         krb5_creds creds;
121         krb5_data res_code_string, res_string;
122         E2kKerberosResult result;
123         int res_code;
124
125         ctx = e2k_kerberos_context_new (domain);
126         if (!ctx)
127                 return E2K_KERBEROS_FAILED;
128
129         result = get_init_cred (ctx, user, old_password,
130                                 "kadmin/changepw", &creds);
131         if (result != E2K_KERBEROS_OK) {
132                 krb5_free_context (ctx);
133                 return result;
134         }
135
136         result = krb5_change_password (ctx, &creds, (char *)new_password,
137                                        &res_code, &res_code_string, &res_string);
138         krb5_free_cred_contents (ctx, &creds);
139         krb5_free_data_contents (ctx, &res_code_string);
140         krb5_free_data_contents (ctx, &res_string);
141         krb5_free_context (ctx);
142
143         if (result != 0)
144                 return krb5_result_to_e2k_kerberos_result (result);
145         else if (res_code != 0)
146                 return E2K_KERBEROS_FAILED;
147         else
148                 return E2K_KERBEROS_OK;
149 }
150
151 /**
152  * e2k_kerberos_check_password:
153  * @user: username
154  * @domain: Windows (2000) domain name
155  * @password: current password
156  *
157  * Checks if the password is valid, invalid, or expired
158  *
159  * Return value: %E2K_KERBEROS_OK, %E2K_KERBEROS_USER_UNKNOWN,
160  * %E2K_KERBEROS_PASSWORD_INCORRECT, %E2K_KERBEROS_PASSWORD_EXPIRED,
161  * or %E2K_KERBEROS_FAILED (for unknown errors)
162  **/
163 E2kKerberosResult
164 e2k_kerberos_check_password (const char *user, const char *domain,
165                              const char *password)
166 {
167         krb5_context ctx;
168         krb5_creds creds;
169         E2kKerberosResult result;
170
171         ctx = e2k_kerberos_context_new (domain);
172         if (!ctx)
173                 return E2K_KERBEROS_FAILED;
174
175         result = get_init_cred (ctx, user, password, NULL, &creds);
176
177         krb5_free_context (ctx);
178         if (result == E2K_KERBEROS_OK)
179                 krb5_free_cred_contents (ctx, &creds);
180
181         return result;
182 }