s4:remove "util_ldb" submodule and integrate the three gendb_* calls in "dsdb/common...
[kamenim/samba.git] / source4 / auth / credentials / credentials_secrets.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    User credentials handling (as regards on-disk files)
5
6    Copyright (C) Jelmer Vernooij 2005
7    Copyright (C) Tim Potter 2001
8    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "lib/events/events.h"
26 #include "lib/ldb/include/ldb.h"
27 #include "librpc/gen_ndr/samr.h" /* for struct samrPassword */
28 #include "param/secrets.h"
29 #include "system/filesys.h"
30 #include "auth/credentials/credentials.h"
31 #include "auth/credentials/credentials_krb5.h"
32 #include "auth/kerberos/kerberos_util.h"
33 #include "param/param.h"
34 #include "lib/events/events.h"
35 #include "dsdb/samdb/samdb.h"
36
37 /**
38  * Fill in credentials for the machine trust account, from the secrets database.
39  * 
40  * @param cred Credentials structure to fill in
41  * @retval NTSTATUS error detailing any failure
42  */
43 _PUBLIC_ NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred, 
44                                               struct loadparm_context *lp_ctx,
45                                               struct ldb_context *ldb,
46                                               const char *base,
47                                               const char *filter, 
48                                               char **error_string)
49 {
50         TALLOC_CTX *mem_ctx;
51         
52         int ldb_ret;
53         struct ldb_message *msg;
54         
55         const char *machine_account;
56         const char *password;
57         const char *old_password;
58         const char *domain;
59         const char *realm;
60         enum netr_SchannelType sct;
61         const char *salt_principal;
62         char *keytab;
63         const struct ldb_val *whenChanged;
64
65         /* ok, we are going to get it now, don't recurse back here */
66         cred->machine_account_pending = false;
67
68         /* some other parts of the system will key off this */
69         cred->machine_account = true;
70
71         mem_ctx = talloc_named(cred, 0, "cli_credentials fetch machine password");
72
73         if (!ldb) {
74                 /* Local secrets are stored in secrets.ldb */
75                 ldb = secrets_db_connect(mem_ctx, lp_ctx);
76                 if (!ldb) {
77                         /* set anonymous as the fallback, if the machine account won't work */
78                         cli_credentials_set_anonymous(cred);
79                         *error_string = talloc_strdup(cred, "Could not open secrets.ldb");
80                         talloc_free(mem_ctx);
81                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
82                 }
83         }
84
85         ldb_ret = dsdb_search_one(ldb, mem_ctx, &msg,
86                                   ldb_dn_new(mem_ctx, ldb, base),
87                                   LDB_SCOPE_SUBTREE,
88                                   NULL, 0, "%s", filter);
89
90         if (ldb_ret != LDB_SUCCESS) {
91                 *error_string = talloc_asprintf(cred, "Could not find entry to match filter: '%s' base: '%s': %s: %s\n",
92                                                 filter, base ? base : "",
93                                                 ldb_strerror(ldb_ret), ldb_errstring(ldb));
94                 /* set anonymous as the fallback, if the machine account won't work */
95                 cli_credentials_set_anonymous(cred);
96                 talloc_free(mem_ctx);
97                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
98         }
99
100         password = ldb_msg_find_attr_as_string(msg, "secret", NULL);
101         old_password = ldb_msg_find_attr_as_string(msg, "priorSecret", NULL);
102
103         machine_account = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
104
105         if (!machine_account) {
106                 machine_account = ldb_msg_find_attr_as_string(msg, "servicePrincipalName", NULL);
107                 
108                 if (!machine_account) {
109                         const char *ldap_bind_dn = ldb_msg_find_attr_as_string(msg, "ldapBindDn", NULL);
110                         if (!ldap_bind_dn) {
111                                 *error_string = talloc_asprintf(cred, 
112                                                                 "Could not find 'samAccountName', "
113                                                                 "'servicePrincipalName' or "
114                                                                 "'ldapBindDn' in secrets record: %s",
115                                                                 ldb_dn_get_linearized(msg->dn));
116                                 /* set anonymous as the fallback, if the machine account won't work */
117                                 cli_credentials_set_anonymous(cred);
118                                 talloc_free(mem_ctx);
119                                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
120                         } else {
121                                 /* store bind dn in credentials */
122                                 cli_credentials_set_bind_dn(cred, ldap_bind_dn);
123                         }
124                 }
125         }
126
127         salt_principal = ldb_msg_find_attr_as_string(msg, "saltPrincipal", NULL);
128         cli_credentials_set_salt_principal(cred, salt_principal);
129         
130         sct = ldb_msg_find_attr_as_int(msg, "secureChannelType", 0);
131         if (sct) { 
132                 cli_credentials_set_secure_channel_type(cred, sct);
133         }
134         
135         if (!password) {
136                 const struct ldb_val *nt_password_hash = ldb_msg_find_ldb_val(msg, "unicodePwd");
137                 struct samr_Password hash;
138                 ZERO_STRUCT(hash);
139                 if (nt_password_hash) {
140                         memcpy(hash.hash, nt_password_hash->data, 
141                                MIN(nt_password_hash->length, sizeof(hash.hash)));
142                 
143                         cli_credentials_set_nt_hash(cred, &hash, CRED_SPECIFIED);
144                 } else {
145                         cli_credentials_set_password(cred, NULL, CRED_SPECIFIED);
146                 }
147         } else {
148                 cli_credentials_set_password(cred, password, CRED_SPECIFIED);
149         }
150
151         
152         domain = ldb_msg_find_attr_as_string(msg, "flatname", NULL);
153         if (domain) {
154                 cli_credentials_set_domain(cred, domain, CRED_SPECIFIED);
155         }
156
157         realm = ldb_msg_find_attr_as_string(msg, "realm", NULL);
158         if (realm) {
159                 cli_credentials_set_realm(cred, realm, CRED_SPECIFIED);
160         }
161
162         if (machine_account) {
163                 cli_credentials_set_username(cred, machine_account, CRED_SPECIFIED);
164         }
165
166         cli_credentials_set_kvno(cred, ldb_msg_find_attr_as_int(msg, "msDS-KeyVersionNumber", 0));
167
168         whenChanged = ldb_msg_find_ldb_val(msg, "whenChanged");
169         if (whenChanged) {
170                 time_t lct;
171                 if (ldb_val_to_time(whenChanged, &lct) == LDB_SUCCESS) {
172                         cli_credentials_set_password_last_changed_time(cred, lct);
173                 }
174         }
175         
176         /* If there was an external keytab specified by reference in
177          * the LDB, then use this.  Otherwise we will make one up
178          * (chewing CPU time) from the password */
179         keytab = keytab_name_from_msg(cred, ldb, msg);
180         if (keytab) {
181                 cli_credentials_set_keytab_name(cred, lp_ctx, keytab, CRED_SPECIFIED);
182                 talloc_free(keytab);
183         }
184         talloc_free(mem_ctx);
185         
186         return NT_STATUS_OK;
187 }
188
189 /**
190  * Fill in credentials for the machine trust account, from the secrets database.
191  * 
192  * @param cred Credentials structure to fill in
193  * @retval NTSTATUS error detailing any failure
194  */
195 _PUBLIC_ NTSTATUS cli_credentials_set_machine_account(struct cli_credentials *cred,
196                                                       struct loadparm_context *lp_ctx)
197 {
198         NTSTATUS status;
199         char *filter;
200         char *error_string;
201         /* Bleh, nasty recursion issues: We are setting a machine
202          * account here, so we don't want the 'pending' flag around
203          * any more */
204         cred->machine_account_pending = false;
205         filter = talloc_asprintf(cred, SECRETS_PRIMARY_DOMAIN_FILTER, 
206                                  cli_credentials_get_domain(cred));
207         status = cli_credentials_set_secrets(cred, lp_ctx, NULL,
208                                              SECRETS_PRIMARY_DOMAIN_DN,
209                                              filter, &error_string);
210         if (!NT_STATUS_IS_OK(status)) {
211                 DEBUG(1, ("Could not find machine account in secrets database: %s: %s", nt_errstr(status), error_string));
212                 talloc_free(error_string);
213         }
214         return status;
215 }
216
217 /**
218  * Fill in credentials for the machine trust account, from the secrets database.
219  * 
220  * @param cred Credentials structure to fill in
221  * @retval NTSTATUS error detailing any failure
222  */
223 NTSTATUS cli_credentials_set_krbtgt(struct cli_credentials *cred,
224                                     struct loadparm_context *lp_ctx)
225 {
226         NTSTATUS status;
227         char *filter;
228         char *error_string;
229         /* Bleh, nasty recursion issues: We are setting a machine
230          * account here, so we don't want the 'pending' flag around
231          * any more */
232         cred->machine_account_pending = false;
233         filter = talloc_asprintf(cred, SECRETS_KRBTGT_SEARCH,
234                                        cli_credentials_get_realm(cred),
235                                        cli_credentials_get_domain(cred));
236         status = cli_credentials_set_secrets(cred, lp_ctx, NULL,
237                                              SECRETS_PRINCIPALS_DN,
238                                              filter, &error_string);
239         if (!NT_STATUS_IS_OK(status)) {
240                 DEBUG(1, ("Could not find krbtgt (master Kerberos) account in secrets database: %s: %s", nt_errstr(status), error_string));
241                 talloc_free(error_string);
242         }
243         return status;
244 }
245
246 /**
247  * Fill in credentials for a particular prinicpal, from the secrets database.
248  * 
249  * @param cred Credentials structure to fill in
250  * @retval NTSTATUS error detailing any failure
251  */
252 _PUBLIC_ NTSTATUS cli_credentials_set_stored_principal(struct cli_credentials *cred,
253                                               struct loadparm_context *lp_ctx,
254                                               const char *serviceprincipal)
255 {
256         NTSTATUS status;
257         char *filter;
258         char *error_string;
259         /* Bleh, nasty recursion issues: We are setting a machine
260          * account here, so we don't want the 'pending' flag around
261          * any more */
262         cred->machine_account_pending = false;
263         filter = talloc_asprintf(cred, SECRETS_PRINCIPAL_SEARCH,
264                                  cli_credentials_get_realm(cred),
265                                  cli_credentials_get_domain(cred),
266                                  serviceprincipal);
267         status = cli_credentials_set_secrets(cred, lp_ctx, NULL,
268                                              SECRETS_PRINCIPALS_DN, filter,
269                                              &error_string);
270         if (!NT_STATUS_IS_OK(status)) {
271                 DEBUG(1, ("Could not find %s principal in secrets database: %s: %s", serviceprincipal, nt_errstr(status), error_string));
272         }
273         return status;
274 }
275
276 /**
277  * Ask that when required, the credentials system will be filled with
278  * machine trust account, from the secrets database.
279  * 
280  * @param cred Credentials structure to fill in
281  * @note This function is used to call the above function after, rather 
282  *       than during, popt processing.
283  *
284  */
285 _PUBLIC_ void cli_credentials_set_machine_account_pending(struct cli_credentials *cred,
286                                                  struct loadparm_context *lp_ctx)
287 {
288         cred->machine_account_pending = true;
289         cred->machine_account_pending_lp_ctx = lp_ctx;
290 }
291
292