r9554: Do a quick once-over to make the ethereal auto-generated parser code a
[ira/wip.git] / source4 / lib / samba3 / secrets.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Copyright (C) Andrew Tridgell 1992-2001
4    Copyright (C) Andrew Bartlett      2002
5    Copyright (C) Rafal Szczesniak     2002
6    Copyright (C) Tim Potter           2001
7    Copyright (C) Jelmer Vernooij          2005
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 /* the Samba secrets database stores any generated, private information
25    such as the local SID and machine trust password */
26
27 #define SECRETS_DOMAIN_SID "SECRETS/SID"
28 #define SECRETS_DOMAIN_GUID "SECRETS/DOMGUID"
29 #define SECRETS_LDAP_BIND_PW "SECRETS/LDAP_BIND_PW"
30 #define SECRETS_MACHINE_ACCT_PASS "SECRETS/$MACHINE.ACC"
31 #define SECRETS_DOMTRUST_ACCT_PASS "SECRETS/$DOMTRUST.ACC"
32 #define SECRETS_MACHINE_PASSWORD "SECRETS/MACHINE_PASSWORD"
33 #define SECRETS_MACHINE_LAST_CHANGE_TIME "SECRETS/MACHINE_LAST_CHANGE_TIME"
34 #define SECRETS_MACHINE_SEC_CHANNEL_TYPE "SECRETS/MACHINE_SEC_CHANNEL_TYPE"
35 #define SECRETS_AFS_KEYFILE "SECRETS/AFS_KEYFILE"
36 #define SECRETS_AUTH_USER      "SECRETS/AUTH_USER"
37 #define SECRETS_AUTH_DOMAIN      "SECRETS/AUTH_DOMAIN"
38 #define SECRETS_AUTH_PASSWORD  "SECRETS/AUTH_PASSWORD"
39
40
41 #include "includes.h"
42 #include "tdb.h"
43 #include "system/filesys.h"
44 #include "librpc/gen_ndr/ndr_security.h"
45
46 /* structure for storing machine account password
47    (ie. when samba server is member of a domain */
48 struct machine_acct_pass {
49         uint8_t hash[16];
50         time_t mod_time;
51 };
52
53 #define SECRETS_AFS_MAXKEYS 8
54
55 struct afs_key {
56         uint32_t kvno;
57         char key[8];
58 };
59
60 static TDB_CONTEXT *secrets_open(const char *fname)
61 {
62         TDB_CONTEXT *tdb = tdb_open(fname, 0, TDB_DEFAULT, O_RDONLY, 0600);
63
64         if (!tdb) {
65                 DEBUG(0,("Failed to open %s\n", fname));
66                 return NULL;
67         }
68
69         return tdb;
70 }
71
72 /* read a entry from the secrets database - the caller must free the result
73    if size is non-null then the size of the entry is put in there
74  */
75 static void *secrets_fetch(TDB_CONTEXT *tdb, const char *key, size_t *size)
76 {
77         TDB_DATA kbuf, dbuf;
78         
79         kbuf.dptr = strdup(key);
80         kbuf.dsize = strlen(key);
81         dbuf = tdb_fetch(tdb, kbuf);
82         if (size)
83                 *size = dbuf.dsize;
84         free(kbuf.dptr);
85         return dbuf.dptr;
86 }
87
88 static BOOL secrets_fetch_domain_sid(TDB_CONTEXT *tdb, const char *domain, struct dom_sid *sid)
89 {
90         struct dom_sid *dyn_sid;
91         char *key;
92         size_t size;
93
94         asprintf(&key, "%s/%s", SECRETS_DOMAIN_SID, domain);
95         strupper_m(key);
96         dyn_sid = (struct dom_sid *)secrets_fetch(tdb, key, &size);
97         SAFE_FREE(key);
98
99         if (dyn_sid == NULL)
100                 return False;
101
102         if (size != sizeof(struct dom_sid))
103         { 
104                 SAFE_FREE(dyn_sid);
105                 return False;
106         }
107
108         *sid = *dyn_sid;
109         SAFE_FREE(dyn_sid);
110         return True;
111 }
112
113 static BOOL secrets_fetch_domain_guid(TDB_CONTEXT *tdb, const char *domain, struct GUID *guid)
114 {
115         struct GUID *dyn_guid;
116         char *key;
117         size_t size;
118
119         asprintf(&key, "%s/%s", SECRETS_DOMAIN_GUID, domain);
120         strupper_m(key);
121         dyn_guid = (struct GUID *)secrets_fetch(tdb, key, &size);
122
123         if (!dyn_guid) {
124                 return False;
125         }
126
127         if (size != sizeof(struct GUID))
128         { 
129                 DEBUG(1,("GUID size %d is wrong!\n", (int)size));
130                 SAFE_FREE(dyn_guid);
131                 return False;
132         }
133
134         *guid = *dyn_guid;
135         SAFE_FREE(dyn_guid);
136         return True;
137 }
138
139 /**
140  * Form a key for fetching the machine trust account password
141  *
142  * @param domain domain name
143  *
144  * @return stored password's key
145  **/
146 static char *trust_keystr(const char *domain)
147 {
148         char *keystr;
149
150         asprintf(&keystr, "%s/%s", SECRETS_MACHINE_ACCT_PASS, domain);
151         strupper_m(keystr);
152
153         return keystr;
154 }
155
156 /**
157  * Form a key for fetching a trusted domain password
158  *
159  * @param domain trusted domain name
160  *
161  * @return stored password's key
162  **/
163 static char *trustdom_keystr(const char *domain)
164 {
165         char *keystr;
166
167         asprintf(&keystr, "%s/%s", SECRETS_DOMTRUST_ACCT_PASS, domain);
168         strupper_m(keystr);
169                 
170         return keystr;
171 }
172
173 /************************************************************************
174  Routine to get the trust account password for a domain.
175  The user of this function must have locked the trust password file using
176  the above secrets_lock_trust_account_password().
177 ************************************************************************/
178
179 static BOOL secrets_fetch_trust_account_password(TDB_CONTEXT *tdb, 
180                                           const char *domain, uint8_t ret_pwd[16],
181                                           time_t *pass_last_set_time,
182                                           uint32_t *channel)
183 {
184         struct machine_acct_pass *pass;
185         char *plaintext;
186         size_t size;
187
188         plaintext = secrets_fetch_machine_password(tdb, domain, pass_last_set_time, 
189                                                    channel);
190         if (plaintext) {
191                 DEBUG(4,("Using cleartext machine password\n"));
192                 E_md4hash(plaintext, ret_pwd);
193                 SAFE_FREE(plaintext);
194                 return True;
195         }
196
197         if (!(pass = secrets_fetch(tdb, trust_keystr(domain), &size))) {
198                 DEBUG(5, ("secrets_fetch failed!\n"));
199                 return False;
200         }
201         
202         if (size != sizeof(*pass)) {
203                 DEBUG(0, ("secrets were of incorrect size!\n"));
204                 return False;
205         }
206
207         if (pass_last_set_time) *pass_last_set_time = pass->mod_time;
208         memcpy(ret_pwd, pass->hash, 16);
209         SAFE_FREE(pass);
210
211         if (channel) 
212                 *channel = get_default_sec_channel();
213
214         return True;
215 }
216
217 /************************************************************************
218  Routine to get account password to trusted domain
219 ************************************************************************/
220
221 static BOOL secrets_fetch_trusted_domain_password(TDB_CONTEXT *tdb, const char *domain, char** pwd, struct dom_sid **sid, time_t *pass_last_set_time)
222 {
223         struct trusted_dom_pass pass;
224         size_t size;
225         
226         /* unpacking structures */
227         char* pass_buf;
228         int pass_len = 0;
229
230         ZERO_STRUCT(pass);
231
232         /* fetching trusted domain password structure */
233         if (!(pass_buf = secrets_fetch(tdb, trustdom_keystr(domain), &size))) {
234                 DEBUG(5, ("secrets_fetch failed!\n"));
235                 return False;
236         }
237
238         /* unpack trusted domain password */
239         pass_len = tdb_trusted_dom_pass_unpack(pass_buf, size, &pass);
240         SAFE_FREE(pass_buf);
241
242         if (pass_len != size) {
243                 DEBUG(5, ("Invalid secrets size. Unpacked data doesn't match trusted_dom_pass structure.\n"));
244                 return False;
245         }
246                         
247         /* the trust's password */      
248         if (pwd) {
249                 *pwd = strdup(pass.pass);
250                 if (!*pwd) {
251                         return False;
252                 }
253         }
254
255         /* last change time */
256         if (pass_last_set_time) *pass_last_set_time = pass.mod_time;
257
258         /* domain sid */
259         
260         *sid = dom_sid_dup(tdb, &pass.domain_sid);
261                 
262         return True;
263 }
264
265 /************************************************************************
266  Routine to fetch the plaintext machine account password for a realm
267 the password is assumed to be a null terminated ascii string
268 ************************************************************************/
269 static char *secrets_fetch_machine_password(TDB_CONTEXT *tdb, const char *domain, 
270                                      time_t *pass_last_set_time,
271                                      uint32_t *channel)
272 {
273         char *key = NULL;
274         char *ret;
275         asprintf(&key, "%s/%s", SECRETS_MACHINE_PASSWORD, domain);
276         strupper_m(key);
277         ret = (char *)secrets_fetch(tdb, key, NULL);
278         SAFE_FREE(key);
279         
280         if (pass_last_set_time) {
281                 size_t size;
282                 uint32_t *last_set_time;
283                 asprintf(&key, "%s/%s", SECRETS_MACHINE_LAST_CHANGE_TIME, domain);
284                 strupper_m(key);
285                 last_set_time = secrets_fetch(tdb, key, &size);
286                 if (last_set_time) {
287                         *pass_last_set_time = IVAL(last_set_time,0);
288                         SAFE_FREE(last_set_time);
289                 } else {
290                         *pass_last_set_time = 0;
291                 }
292                 SAFE_FREE(key);
293         }
294         
295         if (channel) {
296                 size_t size;
297                 uint32_t *channel_type;
298                 asprintf(&key, "%s/%s", SECRETS_MACHINE_SEC_CHANNEL_TYPE, domain);
299                 strupper_m(key);
300                 channel_type = secrets_fetch(tdb, key, &size);
301                 if (channel_type) {
302                         *channel = IVAL(channel_type,0);
303                         SAFE_FREE(channel_type);
304                 } else {
305                         *channel = get_default_sec_channel();
306                 }
307                 SAFE_FREE(key);
308         }
309         
310         return ret;
311 }
312
313 /*******************************************************************
314  find the ldap password
315 ******************************************************************/
316 static BOOL fetch_ldap_pw(TDB_CONTEXT *tdb, const char *dn, char** pw)
317 {
318         char *key = NULL;
319         size_t size;
320         
321         if (asprintf(&key, "%s/%s", SECRETS_LDAP_BIND_PW, dn) < 0) {
322                 DEBUG(0, ("fetch_ldap_pw: asprintf failed!\n"));
323         }
324         
325         *pw=secrets_fetch(tdb, key, &size);
326         SAFE_FREE(key);
327
328         if (!size) {
329                 return False;
330         }
331         
332         return True;
333 }
334
335
336 /**
337  * Get trusted domains info from secrets.tdb.
338  *
339  * The linked list is allocated on the supplied talloc context, caller gets to destroy
340  * when done.
341  *
342  * @param ctx Allocation context
343  * @param enum_ctx Starting index, eg. we can start fetching at third
344  *        or sixth trusted domain entry. Zero is the first index.
345  *        Value it is set to is the enum context for the next enumeration.
346  * @param num_domains Number of domain entries to fetch at one call
347  * @param domains Pointer to array of trusted domain structs to be filled up
348  *
349  * @return nt status code of rpc response
350  **/ 
351
352 static NTSTATUS secrets_get_trusted_domains(TDB_CONTEXT *tdb, TALLOC_CTX* ctx, int* enum_ctx, unsigned int max_num_domains,
353                                      int *num_domains, struct samba3_trustdom ***domains)
354 {
355         TDB_LIST_NODE *keys, *k;
356         struct samba3_trustdom *dom = NULL;
357         char *pattern;
358         unsigned int start_idx;
359         uint32_t idx = 0;
360         size_t size, packed_size = 0;
361         fstring dom_name;
362         char *packed_pass;
363         struct trusted_dom_pass *pass = talloc(ctx, struct trusted_dom_pass);
364         NTSTATUS status;
365
366         if (!secrets_init()) return NT_STATUS_ACCESS_DENIED;
367         
368         if (!pass) {
369                 DEBUG(0, ("talloc_zero failed!\n"));
370                 return NT_STATUS_NO_MEMORY;
371         }
372                                 
373         *num_domains = 0;
374         start_idx = *enum_ctx;
375
376         /* generate searching pattern */
377         if (!(pattern = talloc_asprintf(ctx, "%s/*", SECRETS_DOMTRUST_ACCT_PASS))) {
378                 DEBUG(0, ("secrets_get_trusted_domains: talloc_asprintf() failed!\n"));
379                 return NT_STATUS_NO_MEMORY;
380         }
381
382         DEBUG(5, ("secrets_get_trusted_domains: looking for %d domains, starting at index %d\n", 
383                   max_num_domains, *enum_ctx));
384
385         *domains = talloc_zero_array(ctx, struct samba3_trustdom *, max_num_domains);
386
387         /* fetching trusted domains' data and collecting them in a list */
388         keys = tdb_search_keys(tdb, pattern);
389
390         /* 
391          * if there's no keys returned ie. no trusted domain,
392          * return "no more entries" code
393          */
394         status = NT_STATUS_NO_MORE_ENTRIES;
395
396         /* searching for keys in secrets db -- way to go ... */
397         for (k = keys; k; k = k->next) {
398                 char *secrets_key;
399                 
400                 /* important: ensure null-termination of the key string */
401                 secrets_key = strndup(k->node_key.dptr, k->node_key.dsize);
402                 if (!secrets_key) {
403                         DEBUG(0, ("strndup failed!\n"));
404                         return NT_STATUS_NO_MEMORY;
405                 }
406
407                 packed_pass = secrets_fetch(tdb, secrets_key, &size);
408                 packed_size = tdb_trusted_dom_pass_unpack(packed_pass, size, pass);
409                 /* packed representation isn't needed anymore */
410                 SAFE_FREE(packed_pass);
411                 
412                 if (size != packed_size) {
413                         DEBUG(2, ("Secrets record %s is invalid!\n", secrets_key));
414                         continue;
415                 }
416                 
417                 pull_ucs2_fstring(dom_name, pass->uni_name);
418                 DEBUG(18, ("Fetched secret record num %d.\nDomain name: %s, SID: %s\n",
419                            idx, dom_name, sid_string_static(&pass->domain_sid)));
420
421                 SAFE_FREE(secrets_key);
422
423                 if (idx >= start_idx && idx < start_idx + max_num_domains) {
424                         dom = talloc(ctx, struct samba3_trustdom);
425                         if (!dom) {
426                                 /* free returned tdb record */
427                                 return NT_STATUS_NO_MEMORY;
428                         }
429                         
430                         /* copy domain sid */
431                         SMB_ASSERT(sizeof(dom->sid) == sizeof(pass->domain_sid));
432                         memcpy(&(dom->sid), &(pass->domain_sid), sizeof(dom->sid));
433                         
434                         /* copy unicode domain name */
435                         dom->name = talloc_memdup(ctx, pass->uni_name,
436                                                   (strlen_w(pass->uni_name) + 1) * sizeof(smb_ucs2_t));
437                         
438                         (*domains)[idx - start_idx] = dom;
439                         
440                         DEBUG(18, ("Secret record is in required range.\n \
441                                    start_idx = %d, max_num_domains = %d. Added to returned array.\n",
442                                    start_idx, max_num_domains));
443
444                         *enum_ctx = idx + 1;
445                         (*num_domains)++;
446                 
447                         /* set proper status code to return */
448                         if (k->next) {
449                                 /* there are yet some entries to enumerate */
450                                 status = STATUS_MORE_ENTRIES;
451                         } else {
452                                 /* this is the last entry in the whole enumeration */
453                                 status = NT_STATUS_OK;
454                         }
455                 } else {
456                         DEBUG(18, ("Secret is outside the required range.\n \
457                                    start_idx = %d, max_num_domains = %d. Not added to returned array\n",
458                                    start_idx, max_num_domains));
459                 }
460                 
461                 idx++;          
462         }
463         
464         DEBUG(5, ("secrets_get_trusted_domains: got %d domains\n", *num_domains));
465
466         /* free the results of searching the keys */
467         tdb_search_list_free(keys);
468
469         return status;
470 }
471
472 /*******************************************************************************
473  Fetch the current (highest) AFS key from secrets.tdb
474 *******************************************************************************/
475 static BOOL secrets_fetch_afs_key(TDB_CONTEXT *tdb, const char *cell, struct afs_key *result)
476 {
477         fstring key;
478         struct afs_keyfile *keyfile;
479         size_t size;
480         uint32_t i;
481
482         slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_AFS_KEYFILE, cell);
483
484         keyfile = (struct afs_keyfile *)secrets_fetch(tdb, key, &size);
485
486         if (keyfile == NULL)
487                 return False;
488
489         if (size != sizeof(struct afs_keyfile)) {
490                 SAFE_FREE(keyfile);
491                 return False;
492         }
493
494         i = ntohl(keyfile->nkeys);
495
496         if (i > SECRETS_AFS_MAXKEYS) {
497                 SAFE_FREE(keyfile);
498                 return False;
499         }
500
501         *result = keyfile->entry[i-1];
502
503         result->kvno = ntohl(result->kvno);
504
505         return True;
506 }
507
508 /******************************************************************************
509   When kerberos is not available, choose between anonymous or
510   authenticated connections.  
511
512   We need to use an authenticated connection if DCs have the
513   RestrictAnonymous registry entry set > 0, or the "Additional
514   restrictions for anonymous connections" set in the win2k Local
515   Security Policy.
516
517   Caller to free() result in domain, username, password
518 *******************************************************************************/
519 static void secrets_fetch_ipc_userpass(TDB_CONTEXT *tdb, char **username, char **domain, char **password)
520 {
521         *username = secrets_fetch(tdb, SECRETS_AUTH_USER, NULL);
522         *domain = secrets_fetch(tdb, SECRETS_AUTH_DOMAIN, NULL);
523         *password = secrets_fetch(tdb, SECRETS_AUTH_PASSWORD, NULL);
524         
525         if (*username && **username) {
526
527                 if (!*domain || !**domain)
528                         *domain = smb_xstrdup(lp_workgroup());
529                 
530                 if (!*password || !**password)
531                         *password = smb_xstrdup("");
532
533                 DEBUG(3, ("IPC$ connections done by user %s\\%s\n", 
534                           *domain, *username));
535
536         } else {
537                 DEBUG(3, ("IPC$ connections done anonymously\n"));
538                 *username = smb_xstrdup("");
539                 *domain = smb_xstrdup("");
540                 *password = smb_xstrdup("");
541         }
542 }