root/source4/auth/credentials/credentials_files.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cli_credentials_parse_password_fd
  2. cli_credentials_parse_password_file
  3. cli_credentials_parse_file
  4. cli_credentials_set_secrets
  5. cli_credentials_set_machine_account
  6. cli_credentials_set_krbtgt
  7. cli_credentials_set_stored_principal
  8. cli_credentials_set_machine_account_pending

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

/* [<][>][^][v][top][bottom][index][help] */