r14363: Remove credentials.h from the global includes.
[garming/samba-autobuild/.git] / source4 / auth / credentials / credentials_files.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 2 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, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "lib/ldb/include/ldb.h"
27 #include "librpc/gen_ndr/ndr_samr.h" /* for struct samrPassword */
28 #include "passdb/secrets.h"
29 #include "system/filesys.h"
30 #include "db_wrap.h"
31 #include "auth/credentials/credentials.h"
32
33 /**
34  * Read a file descriptor, and parse it for a password (eg from a file or stdin)
35  *
36  * @param credentials Credentials structure on which to set the password
37  * @param fd open file descriptor to read the password from 
38  * @param obtained This enum describes how 'specified' this password is
39  */
40
41 BOOL cli_credentials_parse_password_fd(struct cli_credentials *credentials, 
42                                        int fd, enum credentials_obtained obtained)
43 {
44         char *p;
45         char pass[128];
46
47         for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */
48                 p && p - pass < sizeof(pass);) {
49                 switch (read(fd, p, 1)) {
50                 case 1:
51                         if (*p != '\n' && *p != '\0') {
52                                 *++p = '\0'; /* advance p, and null-terminate pass */
53                                 break;
54                         }
55                 case 0:
56                         if (p - pass) {
57                                 *p = '\0'; /* null-terminate it, just in case... */
58                                 p = NULL; /* then force the loop condition to become false */
59                                 break;
60                         } else {
61                                 fprintf(stderr, "Error reading password from file descriptor %d: %s\n", fd, "empty password\n");
62                                 return False;
63                         }
64
65                 default:
66                         fprintf(stderr, "Error reading password from file descriptor %d: %s\n",
67                                         fd, strerror(errno));
68                         return False;
69                 }
70         }
71
72         cli_credentials_set_password(credentials, pass, obtained);
73         return True;
74 }
75
76 /**
77  * Read a named file, and parse it for a password
78  *
79  * @param credentials Credentials structure on which to set the password
80  * @param file a named file to read the password from 
81  * @param obtained This enum describes how 'specified' this password is
82  */
83
84 BOOL cli_credentials_parse_password_file(struct cli_credentials *credentials, const char *file, enum credentials_obtained obtained)
85 {
86         int fd = open(file, O_RDONLY, 0);
87         BOOL ret;
88
89         if (fd < 0) {
90                 fprintf(stderr, "Error opening PASSWD_FILE %s: %s\n",
91                                 file, strerror(errno));
92                 return False;
93         }
94
95         ret = cli_credentials_parse_password_fd(credentials, fd, obtained);
96
97         close(fd);
98         
99         return ret;
100 }
101
102 /**
103  * Read a named file, and parse it for username, domain, realm and password
104  *
105  * @param credentials Credentials structure on which to set the password
106  * @param file a named file to read the details from 
107  * @param obtained This enum describes how 'specified' this password is
108  */
109
110 BOOL cli_credentials_parse_file(struct cli_credentials *cred, const char *file, enum credentials_obtained obtained) 
111 {
112         uint16_t len = 0;
113         char *ptr, *val, *param;
114         char **lines;
115         int i, numlines;
116
117         lines = file_lines_load(file, &numlines, NULL);
118
119         if (lines == NULL)
120         {
121                 /* fail if we can't open the credentials file */
122                 d_printf("ERROR: Unable to open credentials file!\n");
123                 return False;
124         }
125
126         for (i = 0; i < numlines; i++) {
127                 len = strlen(lines[i]);
128
129                 if (len == 0)
130                         continue;
131
132                 /* break up the line into parameter & value.
133                  * will need to eat a little whitespace possibly */
134                 param = lines[i];
135                 if (!(ptr = strchr_m (lines[i], '=')))
136                         continue;
137
138                 val = ptr+1;
139                 *ptr = '\0';
140
141                 /* eat leading white space */
142                 while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
143                         val++;
144
145                 if (strwicmp("password", param) == 0) {
146                         cli_credentials_set_password(cred, val, obtained);
147                 } else if (strwicmp("username", param) == 0) {
148                         cli_credentials_set_username(cred, val, obtained);
149                 } else if (strwicmp("domain", param) == 0) {
150                         cli_credentials_set_domain(cred, val, obtained);
151                 } else if (strwicmp("realm", param) == 0) {
152                         cli_credentials_set_realm(cred, val, obtained);
153                 }
154                 memset(lines[i], 0, len);
155         }
156
157         talloc_free(lines);
158
159         return True;
160 }
161
162
163 /**
164  * Fill in credentials for the machine trust account, from the secrets database.
165  * 
166  * @param cred Credentials structure to fill in
167  * @retval NTSTATUS error detailing any failure
168  */
169 NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred, 
170                                      const char *base,
171                                      const char *filter)
172 {
173         TALLOC_CTX *mem_ctx;
174         
175         struct ldb_context *ldb;
176         int ldb_ret;
177         struct ldb_message **msgs;
178         const char *attrs[] = {
179                 "secret",
180                 "priorSecret",
181                 "samAccountName",
182                 "flatname",
183                 "realm",
184                 "secureChannelType",
185                 "ntPwdHash",
186                 "msDS-KeyVersionNumber",
187                 "saltPrincipal",
188                 "privateKeytab",
189                 "krb5Keytab",
190                 NULL
191         };
192         
193         const char *machine_account;
194         const char *password;
195         const char *old_password;
196         const char *domain;
197         const char *realm;
198         enum netr_SchannelType sct;
199         const char *salt_principal;
200         const char *keytab;
201         
202         /* ok, we are going to get it now, don't recurse back here */
203         cred->machine_account_pending = False;
204
205         /* some other parts of the system will key off this */
206         cred->machine_account = True;
207
208         mem_ctx = talloc_named(cred, 0, "cli_credentials fetch machine password");
209
210         /* Local secrets are stored in secrets.ldb */
211         ldb = secrets_db_connect(mem_ctx);
212         if (!ldb) {
213                 /* set anonymous as the fallback, if the machine account won't work */
214                 cli_credentials_set_anonymous(cred);
215                 DEBUG(1, ("Could not open secrets.ldb\n"));
216                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
217         }
218
219         /* search for the secret record */
220         ldb_ret = gendb_search(ldb,
221                                mem_ctx, ldb_dn_explode(mem_ctx, base), 
222                                &msgs, attrs,
223                                "%s", filter);
224         if (ldb_ret == 0) {
225                 DEBUG(1, ("Could not find entry to match filter: %s\n",
226                           filter));
227                 /* set anonymous as the fallback, if the machine account won't work */
228                 cli_credentials_set_anonymous(cred);
229                 talloc_free(mem_ctx);
230                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
231         } else if (ldb_ret != 1) {
232                 DEBUG(1, ("Found more than one (%d) entry to match filter: %s\n",
233                           ldb_ret, filter));
234                 /* set anonymous as the fallback, if the machine account won't work */
235                 cli_credentials_set_anonymous(cred);
236                 talloc_free(mem_ctx);
237                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
238         }
239         
240         password = ldb_msg_find_string(msgs[0], "secret", NULL);
241         old_password = ldb_msg_find_string(msgs[0], "priorSecret", NULL);
242
243         machine_account = ldb_msg_find_string(msgs[0], "samAccountName", NULL);
244
245         if (!machine_account) {
246                 DEBUG(1, ("Could not find 'samAccountName' in join record to domain: %s\n",
247                           cli_credentials_get_domain(cred)));
248                 /* set anonymous as the fallback, if the machine account won't work */
249                 cli_credentials_set_anonymous(cred);
250                 talloc_free(mem_ctx);
251                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
252         }
253
254         salt_principal = ldb_msg_find_string(msgs[0], "saltPrincipal", NULL);
255         cli_credentials_set_salt_principal(cred, salt_principal);
256         
257         sct = ldb_msg_find_int(msgs[0], "secureChannelType", 0);
258         if (sct) { 
259                 cli_credentials_set_secure_channel_type(cred, sct);
260         }
261         
262         if (!password) {
263                 const struct ldb_val *nt_password_hash = ldb_msg_find_ldb_val(msgs[0], "ntPwdHash");
264                 struct samr_Password hash;
265                 ZERO_STRUCT(hash);
266                 if (nt_password_hash) {
267                         memcpy(hash.hash, nt_password_hash->data, 
268                                MIN(nt_password_hash->length, sizeof(hash.hash)));
269                 
270                         cli_credentials_set_nt_hash(cred, &hash, CRED_SPECIFIED);
271                 } else {
272                         cli_credentials_set_password(cred, NULL, CRED_SPECIFIED);
273                 }
274         } else {
275                 cli_credentials_set_password(cred, password, CRED_SPECIFIED);
276         }
277
278         
279         domain = ldb_msg_find_string(msgs[0], "flatname", NULL);
280         if (domain) {
281                 cli_credentials_set_domain(cred, domain, CRED_SPECIFIED);
282         }
283
284         realm = ldb_msg_find_string(msgs[0], "realm", NULL);
285         if (realm) {
286                 cli_credentials_set_realm(cred, realm, CRED_SPECIFIED);
287         }
288
289         cli_credentials_set_username(cred, machine_account, CRED_SPECIFIED);
290
291         cli_credentials_set_kvno(cred, ldb_msg_find_int(msgs[0], "msDS-KeyVersionNumber", 0));
292
293         /* If there was an external keytab specified by reference in
294          * the LDB, then use this.  Otherwise we will make one up
295          * (chewing CPU time) from the password */
296         keytab = ldb_msg_find_string(msgs[0], "krb5Keytab", NULL);
297         if (keytab) {
298                 cli_credentials_set_keytab_name(cred, keytab, CRED_SPECIFIED);
299         } else {
300                 keytab = ldb_msg_find_string(msgs[0], "privateKeytab", NULL);
301                 if (keytab) {
302                         keytab = talloc_asprintf(mem_ctx, "FILE:%s", private_path(mem_ctx, keytab));
303                         if (keytab) {
304                                 cli_credentials_set_keytab_name(cred, keytab, CRED_SPECIFIED);
305                         }
306                 }
307         }
308         talloc_free(mem_ctx);
309         
310         return NT_STATUS_OK;
311 }
312
313 /**
314  * Fill in credentials for the machine trust account, from the secrets database.
315  * 
316  * @param cred Credentials structure to fill in
317  * @retval NTSTATUS error detailing any failure
318  */
319 NTSTATUS cli_credentials_set_machine_account(struct cli_credentials *cred)
320 {
321         char *filter;
322         /* Bleh, nasty recursion issues: We are setting a machine
323          * account here, so we don't want the 'pending' flag around
324          * any more */
325         cred->machine_account_pending = False;
326         filter = talloc_asprintf(cred, SECRETS_PRIMARY_DOMAIN_FILTER, 
327                                        cli_credentials_get_domain(cred));
328         return cli_credentials_set_secrets(cred, SECRETS_PRIMARY_DOMAIN_DN,
329                                            filter);
330 }
331
332 /**
333  * Fill in credentials for the machine trust account, from the secrets database.
334  * 
335  * @param cred Credentials structure to fill in
336  * @retval NTSTATUS error detailing any failure
337  */
338 NTSTATUS cli_credentials_set_krbtgt(struct cli_credentials *cred)
339 {
340         char *filter;
341         /* Bleh, nasty recursion issues: We are setting a machine
342          * account here, so we don't want the 'pending' flag around
343          * any more */
344         cred->machine_account_pending = False;
345         filter = talloc_asprintf(cred, SECRETS_KRBTGT_SEARCH,
346                                        cli_credentials_get_realm(cred),
347                                        cli_credentials_get_domain(cred));
348         return cli_credentials_set_secrets(cred, SECRETS_PRINCIPALS_DN,
349                                            filter);
350 }
351
352 /**
353  * Fill in credentials for the machine trust account, from the secrets database.
354  * 
355  * @param cred Credentials structure to fill in
356  * @retval NTSTATUS error detailing any failure
357  */
358 NTSTATUS cli_credentials_set_stored_principal(struct cli_credentials *cred,
359                                               const char *serviceprincipal)
360 {
361         char *filter;
362         /* Bleh, nasty recursion issues: We are setting a machine
363          * account here, so we don't want the 'pending' flag around
364          * any more */
365         cred->machine_account_pending = False;
366         filter = talloc_asprintf(cred, SECRETS_PRINCIPAL_SEARCH,
367                                  cli_credentials_get_realm(cred),
368                                  cli_credentials_get_domain(cred),
369                                  serviceprincipal);
370         return cli_credentials_set_secrets(cred, SECRETS_PRINCIPALS_DN,
371                                            filter);
372 }
373
374 /**
375  * Ask that when required, the credentials system will be filled with
376  * machine trust account, from the secrets database.
377  * 
378  * @param cred Credentials structure to fill in
379  * @note This function is used to call the above function after, rather 
380  *       than during, popt processing.
381  *
382  */
383 void cli_credentials_set_machine_account_pending(struct cli_credentials *cred)
384 {
385         cred->machine_account_pending = True;
386 }
387
388
389 NTSTATUS cli_credentials_update_all_keytabs(TALLOC_CTX *parent_ctx)
390 {
391         TALLOC_CTX *mem_ctx;
392         int ldb_ret;
393         struct ldb_context *ldb;
394         struct ldb_message **msgs;
395         const char *attrs[] = { NULL };
396         struct cli_credentials *creds;
397         const char *filter;
398         NTSTATUS status;
399         int i, ret;
400
401         mem_ctx = talloc_new(parent_ctx);
402         if (!mem_ctx) {
403                 return NT_STATUS_NO_MEMORY;
404         }
405
406         /* Local secrets are stored in secrets.ldb */
407         ldb = secrets_db_connect(mem_ctx);
408         if (!ldb) {
409                 DEBUG(1, ("Could not open secrets.ldb\n"));
410                 talloc_free(mem_ctx);
411                 return NT_STATUS_ACCESS_DENIED;
412         }
413
414         /* search for the secret record, but only of things we can
415          * actually update */
416         ldb_ret = gendb_search(ldb,
417                                mem_ctx, NULL,
418                                &msgs, attrs,
419                                "(&(objectClass=kerberosSecret)(|(secret=*)(ntPwdHash=*)))");
420         if (ldb_ret == -1) {
421                 DEBUG(1, ("Error looking for kerberos type secrets to push into a keytab:: %s", ldb_errstring(ldb)));
422                 talloc_free(mem_ctx);
423                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
424         }
425
426         for (i=0; i < ldb_ret; i++) {
427                 /* Make a credentials structure from it */
428                 creds = cli_credentials_init(mem_ctx);
429                 if (!creds) {
430                         DEBUG(1, ("cli_credentials_init failed!"));
431                         talloc_free(mem_ctx);
432                         return NT_STATUS_NO_MEMORY;
433                 }
434                 cli_credentials_set_conf(creds);
435                 filter = talloc_asprintf(mem_ctx, "dn=%s", ldb_dn_linearize(mem_ctx, msgs[i]->dn));
436                 status = cli_credentials_set_secrets(creds, NULL, filter);
437                 if (!NT_STATUS_IS_OK(status)) {
438                         DEBUG(1, ("Failed to read secrets for keytab update for %s\n", 
439                                   filter));
440                         continue;
441                 } 
442                 ret = cli_credentials_update_keytab(creds);
443                 if (ret != 0) {
444                         DEBUG(1, ("Failed to update keytab for %s\n", 
445                                   filter));
446                         continue;
447                 }
448         }
449         return NT_STATUS_OK;
450 }
451