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