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