01a00c3dfcd0121f1501a90a2ba19f31c49d3797
[garming/samba-autobuild/.git] / source4 / auth / credentials / credentials.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    User credentials handling
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 "librpc/gen_ndr/ndr_samr.h" /* for struct samrPassword */
27 #include "auth/gensec/gensec.h"
28 #include "libcli/auth/libcli_auth.h"
29
30 /**
31  * Create a new credentials structure
32  * @param mem_ctx TALLOC_CTX parent for credentials structure 
33  */
34 struct cli_credentials *cli_credentials_init(TALLOC_CTX *mem_ctx) 
35 {
36         struct cli_credentials *cred = talloc(mem_ctx, struct cli_credentials);
37         if (!cred) {
38                 return cred;
39         }
40
41         cred->netlogon_creds = NULL;
42         cred->machine_account_pending = False;
43         cred->workstation_obtained = CRED_UNINITIALISED;
44         cred->username_obtained = CRED_UNINITIALISED;
45         cred->password_obtained = CRED_UNINITIALISED;
46         cred->domain_obtained = CRED_UNINITIALISED;
47         cred->realm_obtained = CRED_UNINITIALISED;
48         cred->ccache_obtained = CRED_UNINITIALISED;
49         cred->client_gss_creds_obtained = CRED_UNINITIALISED;
50         cred->server_gss_creds_obtained = CRED_UNINITIALISED;
51         cred->keytab_obtained = CRED_UNINITIALISED;
52         cred->principal_obtained = CRED_UNINITIALISED;
53
54         cred->old_password = NULL;
55         cred->smb_krb5_context = NULL;
56         cred->salt_principal = NULL;
57         cred->machine_account = False;
58
59         cred->bind_dn = NULL;
60
61         cli_credentials_set_kerberos_state(cred, CRED_AUTO_USE_KERBEROS);
62
63         return cred;
64 }
65
66 void cli_credentials_set_kerberos_state(struct cli_credentials *creds, 
67                                         enum credentials_use_kerberos use_kerberos)
68 {
69         creds->use_kerberos = use_kerberos;
70 }
71
72 enum credentials_use_kerberos cli_credentials_get_kerberos_state(struct cli_credentials *creds)
73 {
74         return creds->use_kerberos;
75 }
76
77
78 /**
79  * Obtain the username for this credentials context.
80  * @param cred credentials context
81  * @retval The username set on this context.
82  * @note Return value will never be NULL except by programmer error.
83  */
84 const char *cli_credentials_get_username(struct cli_credentials *cred)
85 {
86         if (cred->machine_account_pending) {
87                 cli_credentials_set_machine_account(cred);
88         }
89
90         if (cred->username_obtained == CRED_CALLBACK) {
91                 cred->username = cred->username_cb(cred);
92                 cred->username_obtained = CRED_SPECIFIED;
93         }
94
95         return cred->username;
96 }
97
98 BOOL cli_credentials_set_username(struct cli_credentials *cred, 
99                                   const char *val, enum credentials_obtained obtained)
100 {
101         if (obtained >= cred->username_obtained) {
102                 cred->username = talloc_strdup(cred, val);
103                 cred->username_obtained = obtained;
104                 return True;
105         }
106
107         return False;
108 }
109
110 BOOL cli_credentials_set_username_callback(struct cli_credentials *cred,
111                                   const char *(*username_cb) (struct cli_credentials *))
112 {
113         if (cred->username_obtained < CRED_CALLBACK) {
114                 cred->username_cb = username_cb;
115                 cred->username_obtained = CRED_CALLBACK;
116                 return True;
117         }
118
119         return False;
120 }
121
122 BOOL cli_credentials_set_bind_dn(struct cli_credentials *cred, 
123                                  const char *bind_dn)
124 {
125         cred->bind_dn = talloc_strdup(cred, bind_dn);
126         return True;
127 }
128
129 /**
130  * Obtain the BIND DN for this credentials context.
131  * @param cred credentials context
132  * @retval The username set on this context.
133  * @note Return value will be NULL if not specified explictly
134  */
135 const char *cli_credentials_get_bind_dn(struct cli_credentials *cred)
136 {
137         return cred->bind_dn;
138 }
139
140
141 /**
142  * Obtain the client principal for this credentials context.
143  * @param cred credentials context
144  * @retval The username set on this context.
145  * @note Return value will never be NULL except by programmer error.
146  */
147 const char *cli_credentials_get_principal(struct cli_credentials *cred, TALLOC_CTX *mem_ctx)
148 {
149         if (cred->machine_account_pending) {
150                 cli_credentials_set_machine_account(cred);
151         }
152
153         if (cred->principal_obtained == CRED_CALLBACK) {
154                 cred->principal = cred->principal_cb(cred);
155                 cred->principal_obtained = CRED_SPECIFIED;
156         }
157
158         if (cred->principal_obtained < cred->username_obtained) {
159                 if (cred->domain_obtained > cred->realm_obtained) {
160                         return talloc_asprintf(mem_ctx, "%s@%s", 
161                                                cli_credentials_get_username(cred),
162                                                cli_credentials_get_domain(cred));
163                 } else {
164                         return talloc_asprintf(mem_ctx, "%s@%s", 
165                                                cli_credentials_get_username(cred),
166                                                cli_credentials_get_realm(cred));
167                 }
168         }
169         return talloc_reference(mem_ctx, cred->principal);
170 }
171
172 BOOL cli_credentials_set_principal(struct cli_credentials *cred, 
173                                    const char *val, 
174                                    enum credentials_obtained obtained)
175 {
176         if (obtained >= cred->principal_obtained) {
177                 cred->principal = talloc_strdup(cred, val);
178                 cred->principal_obtained = obtained;
179                 return True;
180         }
181
182         return False;
183 }
184
185 /* Set a callback to get the principal.  This could be a popup dialog,
186  * a terminal prompt or similar.  */
187
188 BOOL cli_credentials_set_principal_callback(struct cli_credentials *cred,
189                                   const char *(*principal_cb) (struct cli_credentials *))
190 {
191         if (cred->principal_obtained < CRED_CALLBACK) {
192                 cred->principal_cb = principal_cb;
193                 cred->principal_obtained = CRED_CALLBACK;
194                 return True;
195         }
196
197         return False;
198 }
199
200 /* Some of our tools are 'anonymous by default'.  This is a single
201  * function to determine if authentication has been explicitly
202  * requested */
203
204 BOOL cli_credentials_authentication_requested(struct cli_credentials *cred) 
205 {
206         if (cred->bind_dn) {
207                 return True;
208         }
209
210         if (cred->machine_account_pending) {
211                 cli_credentials_set_machine_account(cred);
212         }
213
214         if (cred->principal_obtained >= CRED_SPECIFIED) {
215                 return True;
216         }
217         if (cred->username_obtained >= CRED_SPECIFIED) {
218                 return True;
219         }
220         return False;
221 }
222
223 /**
224  * Obtain the password for this credentials context.
225  * @param cred credentials context
226  * @retval If set, the cleartext password, otherwise NULL
227  */
228 const char *cli_credentials_get_password(struct cli_credentials *cred)
229 {
230         if (cred->machine_account_pending) {
231                 cli_credentials_set_machine_account(cred);
232         }
233
234         if (cred->password_obtained == CRED_CALLBACK) {
235                 cred->password = cred->password_cb(cred);
236                 cred->password_obtained = CRED_SPECIFIED;
237         }
238
239         return cred->password;
240 }
241
242 /* Set a password on the credentials context, including an indication
243  * of 'how' the password was obtained */
244
245 BOOL cli_credentials_set_password(struct cli_credentials *cred, 
246                                   const char *val, 
247                                   enum credentials_obtained obtained)
248 {
249         if (obtained >= cred->password_obtained) {
250                 cred->password = talloc_strdup(cred, val);
251                 cred->password_obtained = obtained;
252
253                 cred->nt_hash = NULL;
254                 return True;
255         }
256
257         return False;
258 }
259
260 BOOL cli_credentials_set_password_callback(struct cli_credentials *cred,
261                                            const char *(*password_cb) (struct cli_credentials *))
262 {
263         if (cred->password_obtained < CRED_CALLBACK) {
264                 cred->password_cb = password_cb;
265                 cred->password_obtained = CRED_CALLBACK;
266                 return True;
267         }
268
269         return False;
270 }
271
272 /**
273  * Obtain the 'old' password for this credentials context (used for join accounts).
274  * @param cred credentials context
275  * @retval If set, the cleartext password, otherwise NULL
276  */
277 const char *cli_credentials_get_old_password(struct cli_credentials *cred)
278 {
279         if (cred->machine_account_pending) {
280                 cli_credentials_set_machine_account(cred);
281         }
282
283         return cred->old_password;
284 }
285
286 BOOL cli_credentials_set_old_password(struct cli_credentials *cred, 
287                                       const char *val, 
288                                       enum credentials_obtained obtained)
289 {
290         cred->old_password = talloc_strdup(cred, val);
291         return True;
292 }
293
294 /**
295  * Obtain the password, in the form MD4(unicode(password)) for this credentials context.
296  *
297  * Sometimes we only have this much of the password, while the rest of
298  * the time this call avoids calling E_md4hash themselves.
299  *
300  * @param cred credentials context
301  * @retval If set, the cleartext password, otherwise NULL
302  */
303 const struct samr_Password *cli_credentials_get_nt_hash(struct cli_credentials *cred, 
304                                                         TALLOC_CTX *mem_ctx)
305 {
306         const char *password = cli_credentials_get_password(cred);
307
308         if (password) {
309                 struct samr_Password *nt_hash = talloc(mem_ctx, struct samr_Password);
310                 if (!nt_hash) {
311                         return NULL;
312                 }
313                 
314                 E_md4hash(password, nt_hash->hash);    
315
316                 return nt_hash;
317         } else {
318                 return cred->nt_hash;
319         }
320 }
321
322 BOOL cli_credentials_set_nt_hash(struct cli_credentials *cred,
323                                  const struct samr_Password *nt_hash, 
324                                  enum credentials_obtained obtained)
325 {
326         if (obtained >= cred->password_obtained) {
327                 cli_credentials_set_password(cred, NULL, obtained);
328                 cred->nt_hash = talloc(cred, struct samr_Password);
329                 *cred->nt_hash = *nt_hash;
330                 return True;
331         }
332
333         return False;
334 }
335
336 /**
337  * Obtain the 'short' or 'NetBIOS' domain for this credentials context.
338  * @param cred credentials context
339  * @retval The domain set on this context. 
340  * @note Return value will never be NULL except by programmer error.
341  */
342 const char *cli_credentials_get_domain(struct cli_credentials *cred)
343 {
344         if (cred->machine_account_pending) {
345                 cli_credentials_set_machine_account(cred);
346         }
347
348         if (cred->domain_obtained == CRED_CALLBACK) {
349                 cred->domain = cred->domain_cb(cred);
350                 cred->domain_obtained = CRED_SPECIFIED;
351         }
352
353         return cred->domain;
354 }
355
356
357 BOOL cli_credentials_set_domain(struct cli_credentials *cred, 
358                                 const char *val, 
359                                 enum credentials_obtained obtained)
360 {
361         if (obtained >= cred->domain_obtained) {
362                 /* it is important that the domain be in upper case,
363                  * particularly for the sensitive NTLMv2
364                  * calculations */
365                 cred->domain = strupper_talloc(cred, val);
366                 cred->domain_obtained = obtained;
367                 return True;
368         }
369
370         return False;
371 }
372
373 BOOL cli_credentials_set_domain_callback(struct cli_credentials *cred,
374                                          const char *(*domain_cb) (struct cli_credentials *))
375 {
376         if (cred->domain_obtained < CRED_CALLBACK) {
377                 cred->domain_cb = domain_cb;
378                 cred->domain_obtained = CRED_CALLBACK;
379                 return True;
380         }
381
382         return False;
383 }
384
385 /**
386  * Obtain the Kerberos realm for this credentials context.
387  * @param cred credentials context
388  * @retval The realm set on this context. 
389  * @note Return value will never be NULL except by programmer error.
390  */
391 const char *cli_credentials_get_realm(struct cli_credentials *cred)
392 {       
393         if (cred->machine_account_pending) {
394                 cli_credentials_set_machine_account(cred);
395         }
396
397         if (cred->realm_obtained == CRED_CALLBACK) {
398                 cred->realm = cred->realm_cb(cred);
399                 cred->realm_obtained = CRED_SPECIFIED;
400         }
401
402         return cred->realm;
403 }
404
405 /**
406  * Set the realm for this credentials context, and force it to
407  * uppercase for the sainity of our local kerberos libraries 
408  */
409 BOOL cli_credentials_set_realm(struct cli_credentials *cred, 
410                                const char *val, 
411                                enum credentials_obtained obtained)
412 {
413         if (obtained >= cred->realm_obtained) {
414                 cred->realm = strupper_talloc(cred, val);
415                 cred->realm_obtained = obtained;
416                 return True;
417         }
418
419         return False;
420 }
421
422 BOOL cli_credentials_set_realm_callback(struct cli_credentials *cred,
423                                         const char *(*realm_cb) (struct cli_credentials *))
424 {
425         if (cred->realm_obtained < CRED_CALLBACK) {
426                 cred->realm_cb = realm_cb;
427                 cred->realm_obtained = CRED_CALLBACK;
428                 return True;
429         }
430
431         return False;
432 }
433
434 /**
435  * Obtain the 'short' or 'NetBIOS' workstation name for this credentials context.
436  *
437  * @param cred credentials context
438  * @retval The workstation name set on this context. 
439  * @note Return value will never be NULL except by programmer error.
440  */
441 const char *cli_credentials_get_workstation(struct cli_credentials *cred)
442 {
443         if (cred->workstation_obtained == CRED_CALLBACK) {
444                 cred->workstation = cred->workstation_cb(cred);
445                 cred->workstation_obtained = CRED_SPECIFIED;
446         }
447
448         return cred->workstation;
449 }
450
451 BOOL cli_credentials_set_workstation(struct cli_credentials *cred, 
452                                      const char *val, 
453                                      enum credentials_obtained obtained)
454 {
455         if (obtained >= cred->workstation_obtained) {
456                 cred->workstation = talloc_strdup(cred, val);
457                 cred->workstation_obtained = obtained;
458                 return True;
459         }
460
461         return False;
462 }
463
464 BOOL cli_credentials_set_workstation_callback(struct cli_credentials *cred,
465                                               const char *(*workstation_cb) (struct cli_credentials *))
466 {
467         if (cred->workstation_obtained < CRED_CALLBACK) {
468                 cred->workstation_cb = workstation_cb;
469                 cred->workstation_obtained = CRED_CALLBACK;
470                 return True;
471         }
472
473         return False;
474 }
475
476 /**
477  * Given a string, typically obtained from a -U argument, parse it into domain, username, realm and password fields
478  *
479  * The format accepted is [domain\\]user[%password] or user[@realm][%password]
480  *
481  * @param credentials Credentials structure on which to set the password
482  * @param data the string containing the username, password etc
483  * @param obtained This enum describes how 'specified' this password is
484  */
485
486 void cli_credentials_parse_string(struct cli_credentials *credentials, const char *data, enum credentials_obtained obtained)
487 {
488         char *uname, *p;
489
490         if (strcmp("%",data) == 0) {
491                 cli_credentials_set_anonymous(credentials);
492                 return;
493         }
494
495         uname = talloc_strdup(credentials, data); 
496         if ((p = strchr_m(uname,'%'))) {
497                 *p = 0;
498                 cli_credentials_set_password(credentials, p+1, obtained);
499         }
500
501         if ((p = strchr_m(uname,'@'))) {
502                 cli_credentials_set_principal(credentials, uname, obtained);
503                 *p = 0;
504                 cli_credentials_set_realm(credentials, p+1, obtained);
505                 return;
506         } else if ((p = strchr_m(uname,'\\')) || (p = strchr_m(uname, '/'))) {
507                 *p = 0;
508                 cli_credentials_set_domain(credentials, uname, obtained);
509                 uname = p+1;
510         }
511         cli_credentials_set_username(credentials, uname, obtained);
512 }
513
514 /**
515  * Specifies default values for domain, workstation and realm
516  * from the smb.conf configuration file
517  *
518  * @param cred Credentials structure to fill in
519  */
520 void cli_credentials_set_conf(struct cli_credentials *cred)
521 {
522         cli_credentials_set_username(cred, "", CRED_UNINITIALISED);
523         cli_credentials_set_domain(cred, lp_workgroup(), CRED_UNINITIALISED);
524         cli_credentials_set_workstation(cred, lp_netbios_name(), CRED_UNINITIALISED);
525         cli_credentials_set_realm(cred, lp_realm(), CRED_UNINITIALISED);
526 }
527
528 /**
529  * Guess defaults for credentials from environment variables, 
530  * and from the configuration file
531  * 
532  * @param cred Credentials structure to fill in
533  */
534 void cli_credentials_guess(struct cli_credentials *cred)
535 {
536         char *p;
537
538         cli_credentials_set_conf(cred);
539         
540         if (getenv("LOGNAME")) {
541                 cli_credentials_set_username(cred, getenv("LOGNAME"), CRED_GUESS_ENV);
542         }
543
544         if (getenv("USER")) {
545                 cli_credentials_parse_string(cred, getenv("USER"), CRED_GUESS_ENV);
546                 if ((p = strchr_m(getenv("USER"),'%'))) {
547                         memset(p,0,strlen(cred->password));
548                 }
549         }
550
551         if (getenv("DOMAIN")) {
552                 cli_credentials_set_domain(cred, getenv("DOMAIN"), CRED_GUESS_ENV);
553         }
554
555         if (getenv("PASSWD")) {
556                 cli_credentials_set_password(cred, getenv("PASSWD"), CRED_GUESS_ENV);
557         }
558
559         if (getenv("PASSWD_FD")) {
560                 cli_credentials_parse_password_fd(cred, atoi(getenv("PASSWD_FD")), CRED_GUESS_FILE);
561         }
562         
563         if (getenv("PASSWD_FILE")) {
564                 cli_credentials_parse_password_file(cred, getenv("PASSWD_FILE"), CRED_GUESS_FILE);
565         }
566
567         cli_credentials_set_ccache(cred, NULL, CRED_GUESS_FILE);
568 }
569
570 /**
571  * Attach NETLOGON credentials for use with SCHANNEL
572  */
573
574 void cli_credentials_set_netlogon_creds(struct cli_credentials *cred, 
575                                         struct creds_CredentialState *netlogon_creds)
576 {
577         cred->netlogon_creds = talloc_reference(cred, netlogon_creds);
578 }
579
580 /**
581  * Return attached NETLOGON credentials 
582  */
583
584 struct creds_CredentialState *cli_credentials_get_netlogon_creds(struct cli_credentials *cred)
585 {
586         return cred->netlogon_creds;
587 }
588
589 /** 
590  * Set NETLOGON secure channel type
591  */
592
593 void cli_credentials_set_secure_channel_type(struct cli_credentials *cred,
594                                              enum netr_SchannelType secure_channel_type)
595 {
596         cred->secure_channel_type = secure_channel_type;
597 }
598
599 /**
600  * Return NETLOGON secure chanel type
601  */
602
603 enum netr_SchannelType cli_credentials_get_secure_channel_type(struct cli_credentials *cred)
604 {
605         return cred->secure_channel_type;
606 }
607
608 /**
609  * Fill in a credentials structure as the anonymous user
610  */
611 void cli_credentials_set_anonymous(struct cli_credentials *cred) 
612 {
613         cli_credentials_set_username(cred, "", CRED_SPECIFIED);
614         cli_credentials_set_domain(cred, "", CRED_SPECIFIED);
615         cli_credentials_set_password(cred, NULL, CRED_SPECIFIED);
616 }
617
618 /**
619  * Describe a credentials context as anonymous or authenticated
620  * @retval True if anonymous, False if a username is specified
621  */
622
623 BOOL cli_credentials_is_anonymous(struct cli_credentials *cred)
624 {
625         const char *username;
626         
627         if (cred->machine_account_pending) {
628                 cli_credentials_set_machine_account(cred);
629         }
630
631         username = cli_credentials_get_username(cred);
632         
633         /* Yes, it is deliberate that we die if we have a NULL pointer
634          * here - anonymous is "", not NULL, which is 'never specified,
635          * never guessed', ie programmer bug */
636         if (!username[0]) {
637                 return True;
638         }
639
640         return False;
641 }